2015-06-30 07:51:55 +08:00
|
|
|
//=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-06-30 07:51:55 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
2018-05-01 23:54:18 +08:00
|
|
|
/// This file implements the WebAssemblyTargetLowering class.
|
2015-06-30 07:51:55 +08:00
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "WebAssemblyISelLowering.h"
|
|
|
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
|
|
|
#include "WebAssemblyMachineFunctionInfo.h"
|
|
|
|
#include "WebAssemblySubtarget.h"
|
|
|
|
#include "WebAssemblyTargetMachine.h"
|
|
|
|
#include "llvm/CodeGen/Analysis.h"
|
2015-08-25 06:16:48 +08:00
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
2017-11-28 09:13:40 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2015-09-17 00:51:30 +08:00
|
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
Reland "[WebAssembly] LSDA info generation"
Summary:
This adds support for LSDA (exception table) generation for wasm EH.
Wasm EH mostly follows the structure of Itanium-style exception tables,
with one exception: a call site table entry in wasm EH corresponds to
not a call site but a landing pad.
In wasm EH, the VM is responsible for stack unwinding. After an
exception occurs and the stack is unwound, the control flow is
transferred to wasm 'catch' instruction by the VM, after which the
personality function is called from the compiler-generated code. (Refer
to WasmEHPrepare pass for more information on this part.)
This patch:
- Changes wasm.landingpad.index intrinsic to take a token argument, to
make this 1:1 match with a catchpad instruction
- Stores landingpad index info and catch type info MachineFunction in
before instruction selection
- Lowers wasm.lsda intrinsic to an MCSymbol pointing to the start of an
exception table
- Adds WasmException class with overridden methods for table generation
- Adds support for LSDA section in Wasm object writer
Reviewers: dschuff, sbc100, rnk
Subscribers: mgorny, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D52748
llvm-svn: 345345
2018-10-26 07:55:10 +08:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2015-06-30 07:51:55 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
2018-11-14 10:46:21 +08:00
|
|
|
#include "llvm/CodeGen/WasmEHFuncInfo.h"
|
2016-01-28 21:19:47 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
2015-07-23 05:28:15 +08:00
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2015-06-30 07:51:55 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "wasm-lower"
|
|
|
|
|
|
|
|
WebAssemblyTargetLowering::WebAssemblyTargetLowering(
|
|
|
|
const TargetMachine &TM, const WebAssemblySubtarget &STI)
|
2015-07-03 05:36:25 +08:00
|
|
|
: TargetLowering(TM), Subtarget(&STI) {
|
2015-08-25 06:16:48 +08:00
|
|
|
auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
|
|
|
|
|
2015-08-13 01:53:29 +08:00
|
|
|
// Booleans always contain 0 or 1.
|
|
|
|
setBooleanContents(ZeroOrOneBooleanContent);
|
2018-10-20 09:35:23 +08:00
|
|
|
// Except in SIMD vectors
|
|
|
|
setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
|
2015-07-03 05:36:25 +08:00
|
|
|
// WebAssembly does not produce floating-point exceptions on normal floating
|
|
|
|
// point operations.
|
|
|
|
setHasFloatingPointExceptions(false);
|
2015-07-08 06:38:06 +08:00
|
|
|
// We don't know the microarchitecture here, so just reduce register pressure.
|
|
|
|
setSchedulingPreference(Sched::RegPressure);
|
2015-07-23 05:28:15 +08:00
|
|
|
// Tell ISel that we have a stack pointer.
|
|
|
|
setStackPointerRegisterToSaveRestore(
|
|
|
|
Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
|
|
|
|
// Set up the register classes.
|
2015-09-26 09:09:44 +08:00
|
|
|
addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
|
|
|
|
addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
|
|
|
|
addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
|
|
|
|
addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
|
2016-08-03 07:16:09 +08:00
|
|
|
if (Subtarget->hasSIMD128()) {
|
|
|
|
addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
|
|
|
|
addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
|
|
|
|
addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
|
|
|
|
addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
|
2019-01-26 09:25:37 +08:00
|
|
|
}
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128()) {
|
|
|
|
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
|
|
|
|
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
|
2016-08-03 07:16:09 +08:00
|
|
|
}
|
2015-07-23 05:28:15 +08:00
|
|
|
// Compute derived properties from the register classes.
|
|
|
|
computeRegisterProperties(Subtarget->getRegisterInfo());
|
|
|
|
|
2015-08-25 06:16:48 +08:00
|
|
|
setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
|
2015-11-26 00:44:29 +08:00
|
|
|
setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
|
2015-09-17 00:51:30 +08:00
|
|
|
setOperationAction(ISD::JumpTable, MVTPtr, Custom);
|
2016-02-13 06:56:03 +08:00
|
|
|
setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
|
|
|
|
setOperationAction(ISD::BRIND, MVT::Other, Custom);
|
2015-08-25 06:16:48 +08:00
|
|
|
|
2015-12-05 07:22:35 +08:00
|
|
|
// Take the default expansion for va_arg, va_copy, and va_end. There is no
|
|
|
|
// default action for va_start, so we do that custom.
|
|
|
|
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
|
|
|
|
2018-09-13 01:56:00 +08:00
|
|
|
for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
|
2015-08-12 05:02:46 +08:00
|
|
|
// Don't expand the floating-point types to constant pools.
|
|
|
|
setOperationAction(ISD::ConstantFP, T, Legal);
|
|
|
|
// Expand floating-point comparisons.
|
|
|
|
for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
|
|
|
|
ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
|
|
|
|
setCondCodeAction(CC, T, Expand);
|
2015-08-21 06:57:13 +08:00
|
|
|
// Expand floating-point library function operators.
|
2018-09-05 09:27:38 +08:00
|
|
|
for (auto Op :
|
|
|
|
{ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
|
2015-08-21 06:57:13 +08:00
|
|
|
setOperationAction(Op, T, Expand);
|
2015-08-25 02:23:13 +08:00
|
|
|
// Note supported floating-point library function operators that otherwise
|
|
|
|
// default to expand.
|
2015-11-30 06:32:02 +08:00
|
|
|
for (auto Op :
|
|
|
|
{ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
|
2015-08-25 02:23:13 +08:00
|
|
|
setOperationAction(Op, T, Legal);
|
[NFC] Rename minnan and maxnan to minimum and maximum
Summary:
Changes all uses of minnan/maxnan to minimum/maximum
globally. These names emphasize that the semantic difference between
these operations is more than just NaN-propagation.
Reviewers: arsenm, aheejin, dschuff, javed.absar
Subscribers: jholewinski, sdardis, wdng, sbc100, jgravelle-google, jrtc27, atanasyan, llvm-commits
Differential Revision: https://reviews.llvm.org/D53112
llvm-svn: 345218
2018-10-25 06:49:55 +08:00
|
|
|
// Support minimum and maximum, which otherwise default to expand.
|
|
|
|
setOperationAction(ISD::FMINIMUM, T, Legal);
|
|
|
|
setOperationAction(ISD::FMAXIMUM, T, Legal);
|
2017-02-23 00:28:00 +08:00
|
|
|
// WebAssembly currently has no builtin f16 support.
|
|
|
|
setOperationAction(ISD::FP16_TO_FP, T, Expand);
|
|
|
|
setOperationAction(ISD::FP_TO_FP16, T, Expand);
|
|
|
|
setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
|
|
|
|
setTruncStoreAction(T, MVT::f16, Expand);
|
2015-08-12 05:02:46 +08:00
|
|
|
}
|
2015-08-21 06:57:13 +08:00
|
|
|
|
2018-11-30 06:01:01 +08:00
|
|
|
// Expand unavailable integer operations.
|
|
|
|
for (auto Op :
|
|
|
|
{ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
|
|
|
|
ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
|
|
|
|
ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
|
2019-01-26 09:25:37 +08:00
|
|
|
for (auto T : {MVT::i32, MVT::i64})
|
2015-08-21 06:57:13 +08:00
|
|
|
setOperationAction(Op, T, Expand);
|
2019-01-26 09:25:37 +08:00
|
|
|
if (Subtarget->hasSIMD128())
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
|
2018-11-30 06:01:01 +08:00
|
|
|
setOperationAction(Op, T, Expand);
|
2019-01-26 09:25:37 +08:00
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
setOperationAction(Op, MVT::v2i64, Expand);
|
2015-08-21 06:57:13 +08:00
|
|
|
}
|
|
|
|
|
2019-01-26 09:25:37 +08:00
|
|
|
// SIMD-specific configuration
|
2018-09-08 05:54:46 +08:00
|
|
|
if (Subtarget->hasSIMD128()) {
|
2019-01-26 09:25:37 +08:00
|
|
|
// Support saturating add for i8x16 and i16x8
|
|
|
|
for (auto Op : {ISD::SADDSAT, ISD::UADDSAT})
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16})
|
|
|
|
setOperationAction(Op, T, Legal);
|
|
|
|
|
2019-01-30 10:23:29 +08:00
|
|
|
// Custom lower BUILD_VECTORs to minimize number of replace_lanes
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, T, Custom);
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
for (auto T : {MVT::v2i64, MVT::v2f64})
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, T, Custom);
|
|
|
|
|
2019-01-26 09:25:37 +08:00
|
|
|
// We have custom shuffle lowering to expose the shuffle mask
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
|
2018-09-08 05:54:46 +08:00
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
|
2019-01-26 09:25:37 +08:00
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
for (auto T: {MVT::v2i64, MVT::v2f64})
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
|
2018-09-08 05:54:46 +08:00
|
|
|
|
2019-01-26 09:25:37 +08:00
|
|
|
// Custom lowering since wasm shifts must have a scalar shift amount
|
|
|
|
for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL}) {
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
|
2018-11-02 08:39:57 +08:00
|
|
|
setOperationAction(Op, T, Custom);
|
2019-01-26 09:25:37 +08:00
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
2018-11-02 08:39:57 +08:00
|
|
|
setOperationAction(Op, MVT::v2i64, Custom);
|
2019-01-26 09:25:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Custom lower lane accesses to expand out variable indices
|
|
|
|
for (auto Op : {ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT}) {
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
|
|
|
|
setOperationAction(Op, T, Custom);
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
for (auto T : {MVT::v2i64, MVT::v2f64})
|
|
|
|
setOperationAction(Op, T, Custom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// There is no i64x2.mul instruction
|
|
|
|
setOperationAction(ISD::MUL, MVT::v2i64, Expand);
|
2018-10-20 09:31:18 +08:00
|
|
|
|
2019-01-26 09:25:37 +08:00
|
|
|
// There are no vector select instructions
|
2018-11-09 09:38:44 +08:00
|
|
|
for (auto Op : {ISD::VSELECT, ISD::SELECT_CC, ISD::SELECT}) {
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
|
|
|
|
setOperationAction(Op, T, Expand);
|
2019-01-11 06:32:11 +08:00
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
2018-11-09 09:38:44 +08:00
|
|
|
for (auto T : {MVT::v2i64, MVT::v2f64})
|
|
|
|
setOperationAction(Op, T, Expand);
|
|
|
|
}
|
2018-11-01 08:01:02 +08:00
|
|
|
|
2019-03-02 11:32:25 +08:00
|
|
|
// Expand integer operations supported for scalars but not SIMD
|
|
|
|
for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP, ISD::SDIV, ISD::UDIV,
|
|
|
|
ISD::SREM, ISD::UREM, ISD::ROTL, ISD::ROTR}) {
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
|
|
|
|
setOperationAction(Op, T, Expand);
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
setOperationAction(Op, MVT::v2i64, Expand);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expand float operations supported for scalars but not SIMD
|
|
|
|
for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
|
|
|
|
ISD::FCOPYSIGN}) {
|
|
|
|
setOperationAction(Op, MVT::v4f32, Expand);
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128())
|
|
|
|
setOperationAction(Op, MVT::v2f64, Expand);
|
|
|
|
}
|
|
|
|
|
2019-01-26 09:25:37 +08:00
|
|
|
// Expand additional SIMD ops that V8 hasn't implemented yet
|
|
|
|
if (!Subtarget->hasUnimplementedSIMD128()) {
|
|
|
|
setOperationAction(ISD::FSQRT, MVT::v4f32, Expand);
|
|
|
|
setOperationAction(ISD::FDIV, MVT::v4f32, Expand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-21 06:57:13 +08:00
|
|
|
// As a special case, these operators use the type to mean the type to
|
|
|
|
// sign-extend from.
|
2017-09-13 08:29:06 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
2018-01-20 01:16:24 +08:00
|
|
|
if (!Subtarget->hasSignExt()) {
|
2019-01-11 06:32:11 +08:00
|
|
|
// Sign extends are legal only when extending a vector extract
|
|
|
|
auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
|
2017-09-13 08:29:06 +08:00
|
|
|
for (auto T : {MVT::i8, MVT::i16, MVT::i32})
|
2019-01-11 06:32:11 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action);
|
2017-09-13 08:29:06 +08:00
|
|
|
}
|
2018-10-20 09:35:23 +08:00
|
|
|
for (auto T : MVT::integer_vector_valuetypes())
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
|
2015-08-21 06:57:13 +08:00
|
|
|
|
|
|
|
// Dynamic stack allocation: use the default expansion.
|
|
|
|
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
2015-08-25 06:31:52 +08:00
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
|
2015-09-01 06:24:11 +08:00
|
|
|
|
2015-12-12 07:49:46 +08:00
|
|
|
setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
|
2016-02-17 02:18:36 +08:00
|
|
|
setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
|
2015-12-12 07:49:46 +08:00
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
// Expand these forms; we pattern-match the forms that we can handle in isel.
|
|
|
|
for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
|
|
|
|
for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
|
|
|
|
setOperationAction(Op, T, Expand);
|
|
|
|
|
|
|
|
// We have custom switch handling.
|
|
|
|
setOperationAction(ISD::BR_JT, MVT::Other, Custom);
|
|
|
|
|
2015-09-01 06:24:11 +08:00
|
|
|
// WebAssembly doesn't have:
|
|
|
|
// - Floating-point extending loads.
|
|
|
|
// - Floating-point truncating stores.
|
|
|
|
// - i1 extending loads.
|
2018-10-25 09:46:07 +08:00
|
|
|
// - extending/truncating SIMD loads/stores
|
2015-12-10 10:07:53 +08:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
|
2015-09-01 06:24:11 +08:00
|
|
|
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
|
|
|
|
for (auto T : MVT::integer_valuetypes())
|
|
|
|
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
|
|
|
|
setLoadExtAction(Ext, T, MVT::i1, Promote);
|
2018-10-25 09:46:07 +08:00
|
|
|
if (Subtarget->hasSIMD128()) {
|
|
|
|
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
|
|
|
|
MVT::v2f64}) {
|
|
|
|
for (auto MemT : MVT::vector_valuetypes()) {
|
|
|
|
if (MVT(T) != MemT) {
|
|
|
|
setTruncStoreAction(T, MemT, Expand);
|
|
|
|
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
|
|
|
|
setLoadExtAction(Ext, T, MemT, Expand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-10 08:30:57 +08:00
|
|
|
|
2019-01-29 07:44:31 +08:00
|
|
|
// Don't do anything clever with build_pairs
|
|
|
|
setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
|
|
|
|
|
2015-11-10 08:30:57 +08:00
|
|
|
// Trap lowers to wasm unreachable
|
|
|
|
setOperationAction(ISD::TRAP, MVT::Other, Legal);
|
2017-08-31 02:07:45 +08:00
|
|
|
|
[WebAssembly] Support instruction selection for catching exceptions
Summary:
This lowers exception catching-related instructions:
1. Lowers `wasm.catch` intrinsic to `catch` instruction
2. Removes `catchpad` and `cleanuppad` instructions; they are not
necessary after isel phase. (`MachineBasicBlock::isEHFuncletEntry()` or
`MachineBasicBlock::isEHPad()` can be used instead.)
3. Lowers `catchret` and `cleanupret` instructions to pseudo `catchret`
and `cleanupret` instructions in isel, which will be replaced with other
instructions in `WebAssemblyExceptionPrepare` pass.
4. Adds 'WebAssemblyExceptionPrepare` pass, which is for running various
transformation for EH. Currently this pass only replaces `catchret` and
`cleanupret` instructions into appropriate wasm instructions to make
this patch successfully run until the end.
Currently this does not handle lowering of intrinsics related to LSDA
info generation (`wasm.landingpad.index` and `wasm.lsda`), because they
cannot be tested without implementing `EHStreamer`'s wasm-specific
handlers. They are marked as TODO, which is needed to make isel pass.
Also this does not generate `try` and `end_try` markers yet, which will
be handled in later patches.
This patch is based on the first wasm EH proposal.
(https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md)
Reviewers: dschuff, majnemer
Subscribers: jfb, sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D44090
llvm-svn: 333705
2018-06-01 06:25:54 +08:00
|
|
|
// Exception handling intrinsics
|
|
|
|
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
|
2018-11-14 10:46:21 +08:00
|
|
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
|
[WebAssembly] Support instruction selection for catching exceptions
Summary:
This lowers exception catching-related instructions:
1. Lowers `wasm.catch` intrinsic to `catch` instruction
2. Removes `catchpad` and `cleanuppad` instructions; they are not
necessary after isel phase. (`MachineBasicBlock::isEHFuncletEntry()` or
`MachineBasicBlock::isEHPad()` can be used instead.)
3. Lowers `catchret` and `cleanupret` instructions to pseudo `catchret`
and `cleanupret` instructions in isel, which will be replaced with other
instructions in `WebAssemblyExceptionPrepare` pass.
4. Adds 'WebAssemblyExceptionPrepare` pass, which is for running various
transformation for EH. Currently this pass only replaces `catchret` and
`cleanupret` instructions into appropriate wasm instructions to make
this patch successfully run until the end.
Currently this does not handle lowering of intrinsics related to LSDA
info generation (`wasm.landingpad.index` and `wasm.lsda`), because they
cannot be tested without implementing `EHStreamer`'s wasm-specific
handlers. They are marked as TODO, which is needed to make isel pass.
Also this does not generate `try` and `end_try` markers yet, which will
be handled in later patches.
This patch is based on the first wasm EH proposal.
(https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md)
Reviewers: dschuff, majnemer
Subscribers: jfb, sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D44090
llvm-svn: 333705
2018-06-01 06:25:54 +08:00
|
|
|
|
2017-08-31 02:07:45 +08:00
|
|
|
setMaxAtomicSizeInBitsSupported(64);
|
2019-02-05 08:49:55 +08:00
|
|
|
|
|
|
|
if (Subtarget->hasBulkMemory()) {
|
2019-02-14 06:25:18 +08:00
|
|
|
// Use memory.copy and friends over multiple loads and stores
|
2019-02-05 08:49:55 +08:00
|
|
|
MaxStoresPerMemcpy = 1;
|
|
|
|
MaxStoresPerMemcpyOptSize = 1;
|
2019-02-06 04:57:40 +08:00
|
|
|
MaxStoresPerMemmove = 1;
|
|
|
|
MaxStoresPerMemmoveOptSize = 1;
|
2019-02-14 06:25:18 +08:00
|
|
|
MaxStoresPerMemset = 1;
|
|
|
|
MaxStoresPerMemsetOptSize = 1;
|
2019-02-05 08:49:55 +08:00
|
|
|
}
|
2015-07-03 05:36:25 +08:00
|
|
|
}
|
2015-06-30 07:51:55 +08:00
|
|
|
|
2018-08-07 08:22:22 +08:00
|
|
|
TargetLowering::AtomicExpansionKind
|
|
|
|
WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
|
|
|
|
// We have wasm instructions for these
|
|
|
|
switch (AI->getOperation()) {
|
|
|
|
case AtomicRMWInst::Add:
|
|
|
|
case AtomicRMWInst::Sub:
|
|
|
|
case AtomicRMWInst::And:
|
|
|
|
case AtomicRMWInst::Or:
|
|
|
|
case AtomicRMWInst::Xor:
|
|
|
|
case AtomicRMWInst::Xchg:
|
|
|
|
return AtomicExpansionKind::None;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return AtomicExpansionKind::CmpXChg;
|
|
|
|
}
|
|
|
|
|
2015-08-25 02:44:37 +08:00
|
|
|
FastISel *WebAssemblyTargetLowering::createFastISel(
|
|
|
|
FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
|
|
|
|
return WebAssembly::createFastISel(FuncInfo, LibInfo);
|
|
|
|
}
|
|
|
|
|
2015-11-30 06:32:02 +08:00
|
|
|
MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
|
2015-08-03 08:00:11 +08:00
|
|
|
EVT VT) const {
|
2015-12-10 08:26:26 +08:00
|
|
|
unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
|
2018-09-05 09:27:38 +08:00
|
|
|
if (BitWidth > 1 && BitWidth < 8)
|
|
|
|
BitWidth = 8;
|
2015-12-17 07:25:51 +08:00
|
|
|
|
|
|
|
if (BitWidth > 64) {
|
2016-05-14 10:15:47 +08:00
|
|
|
// The shift will be lowered to a libcall, and compiler-rt libcalls expect
|
|
|
|
// the count to be an i32.
|
|
|
|
BitWidth = 32;
|
2015-12-17 07:25:51 +08:00
|
|
|
assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
|
2016-05-14 10:15:47 +08:00
|
|
|
"32-bit shift counts ought to be enough for anyone");
|
2015-12-17 07:25:51 +08:00
|
|
|
}
|
|
|
|
|
2015-12-10 08:26:26 +08:00
|
|
|
MVT Result = MVT::getIntegerVT(BitWidth);
|
|
|
|
assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
|
|
|
|
"Unable to represent scalar shift amount type");
|
|
|
|
return Result;
|
2015-08-03 08:00:11 +08:00
|
|
|
}
|
|
|
|
|
2017-11-28 09:13:40 +08:00
|
|
|
// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
|
|
|
|
// undefined result on invalid/overflow, to the WebAssembly opcode, which
|
|
|
|
// traps on invalid/overflow.
|
2018-09-05 09:27:38 +08:00
|
|
|
static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
|
|
|
|
MachineBasicBlock *BB,
|
|
|
|
const TargetInstrInfo &TII,
|
|
|
|
bool IsUnsigned, bool Int64,
|
|
|
|
bool Float64, unsigned LoweredOpcode) {
|
2017-11-28 09:13:40 +08:00
|
|
|
MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
|
|
|
|
|
|
|
|
unsigned OutReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned InReg = MI.getOperand(1).getReg();
|
|
|
|
|
|
|
|
unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
|
|
|
|
unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
|
|
|
|
unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
|
2017-11-30 04:20:11 +08:00
|
|
|
unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
|
2017-11-28 09:13:40 +08:00
|
|
|
unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
|
2017-11-30 04:20:11 +08:00
|
|
|
unsigned Eqz = WebAssembly::EQZ_I32;
|
|
|
|
unsigned And = WebAssembly::AND_I32;
|
2017-11-28 09:13:40 +08:00
|
|
|
int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
|
|
|
|
int64_t Substitute = IsUnsigned ? 0 : Limit;
|
|
|
|
double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
|
2017-12-16 07:52:06 +08:00
|
|
|
auto &Context = BB->getParent()->getFunction().getContext();
|
2017-11-28 09:13:40 +08:00
|
|
|
Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
|
|
|
|
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
const BasicBlock *LLVMBB = BB->getBasicBlock();
|
2017-11-28 09:13:40 +08:00
|
|
|
MachineFunction *F = BB->getParent();
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
|
|
|
|
MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
|
|
|
|
MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
|
2017-11-28 09:13:40 +08:00
|
|
|
|
|
|
|
MachineFunction::iterator It = ++BB->getIterator();
|
|
|
|
F->insert(It, FalseMBB);
|
|
|
|
F->insert(It, TrueMBB);
|
|
|
|
F->insert(It, DoneMBB);
|
|
|
|
|
|
|
|
// Transfer the remainder of BB and its successor edges to DoneMBB.
|
2019-03-06 05:05:09 +08:00
|
|
|
DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
|
2017-11-28 09:13:40 +08:00
|
|
|
DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
|
|
|
|
|
|
|
|
BB->addSuccessor(TrueMBB);
|
|
|
|
BB->addSuccessor(FalseMBB);
|
|
|
|
TrueMBB->addSuccessor(DoneMBB);
|
|
|
|
FalseMBB->addSuccessor(DoneMBB);
|
|
|
|
|
2017-11-30 04:20:11 +08:00
|
|
|
unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
|
2017-11-28 09:13:40 +08:00
|
|
|
Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
|
|
|
|
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
|
2017-11-30 04:20:11 +08:00
|
|
|
CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
|
|
EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
|
|
FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
|
|
|
|
TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
|
2017-11-28 09:13:40 +08:00
|
|
|
|
|
|
|
MI.eraseFromParent();
|
2017-11-30 04:20:11 +08:00
|
|
|
// For signed numbers, we can do a single comparison to determine whether
|
|
|
|
// fabs(x) is within range.
|
2017-11-28 09:13:40 +08:00
|
|
|
if (IsUnsigned) {
|
|
|
|
Tmp0 = InReg;
|
|
|
|
} else {
|
2018-09-05 09:27:38 +08:00
|
|
|
BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
|
2017-11-28 09:13:40 +08:00
|
|
|
}
|
|
|
|
BuildMI(BB, DL, TII.get(FConst), Tmp1)
|
|
|
|
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
|
2018-09-05 09:27:38 +08:00
|
|
|
BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
|
2017-11-30 04:20:11 +08:00
|
|
|
|
|
|
|
// For unsigned numbers, we have to do a separate comparison with zero.
|
|
|
|
if (IsUnsigned) {
|
|
|
|
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
|
2018-09-05 09:27:38 +08:00
|
|
|
unsigned SecondCmpReg =
|
|
|
|
MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
2017-11-30 04:20:11 +08:00
|
|
|
unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
|
|
BuildMI(BB, DL, TII.get(FConst), Tmp1)
|
|
|
|
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
|
2018-09-05 09:27:38 +08:00
|
|
|
BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
|
|
|
|
BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
|
2017-11-30 04:20:11 +08:00
|
|
|
CmpReg = AndReg;
|
|
|
|
}
|
|
|
|
|
2018-09-05 09:27:38 +08:00
|
|
|
BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
|
2017-11-30 04:20:11 +08:00
|
|
|
|
|
|
|
// Create the CFG diamond to select between doing the conversion or using
|
|
|
|
// the substitute value.
|
2018-09-05 09:27:38 +08:00
|
|
|
BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
|
|
|
|
BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
|
|
|
|
BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
|
|
|
|
BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
|
2017-11-28 09:13:40 +08:00
|
|
|
BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
|
2017-11-30 04:20:11 +08:00
|
|
|
.addReg(FalseReg)
|
2017-11-28 09:13:40 +08:00
|
|
|
.addMBB(FalseMBB)
|
2017-11-30 04:20:11 +08:00
|
|
|
.addReg(TrueReg)
|
2017-11-28 09:13:40 +08:00
|
|
|
.addMBB(TrueMBB);
|
|
|
|
|
|
|
|
return DoneMBB;
|
|
|
|
}
|
|
|
|
|
2018-09-05 09:27:38 +08:00
|
|
|
MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
|
|
|
|
MachineInstr &MI, MachineBasicBlock *BB) const {
|
2017-11-28 09:13:40 +08:00
|
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
|
|
DebugLoc DL = MI.getDebugLoc();
|
|
|
|
|
|
|
|
switch (MI.getOpcode()) {
|
2018-09-05 09:27:38 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("Unexpected instr type to insert");
|
2017-11-28 09:13:40 +08:00
|
|
|
case WebAssembly::FP_TO_SINT_I32_F32:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, false, false, false,
|
|
|
|
WebAssembly::I32_TRUNC_S_F32);
|
|
|
|
case WebAssembly::FP_TO_UINT_I32_F32:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, true, false, false,
|
|
|
|
WebAssembly::I32_TRUNC_U_F32);
|
|
|
|
case WebAssembly::FP_TO_SINT_I64_F32:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, false, true, false,
|
|
|
|
WebAssembly::I64_TRUNC_S_F32);
|
|
|
|
case WebAssembly::FP_TO_UINT_I64_F32:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, true, true, false,
|
|
|
|
WebAssembly::I64_TRUNC_U_F32);
|
|
|
|
case WebAssembly::FP_TO_SINT_I32_F64:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, false, false, true,
|
|
|
|
WebAssembly::I32_TRUNC_S_F64);
|
|
|
|
case WebAssembly::FP_TO_UINT_I32_F64:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, true, false, true,
|
|
|
|
WebAssembly::I32_TRUNC_U_F64);
|
|
|
|
case WebAssembly::FP_TO_SINT_I64_F64:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, false, true, true,
|
|
|
|
WebAssembly::I64_TRUNC_S_F64);
|
|
|
|
case WebAssembly::FP_TO_UINT_I64_F64:
|
|
|
|
return LowerFPToInt(MI, DL, BB, TII, true, true, true,
|
|
|
|
WebAssembly::I64_TRUNC_U_F64);
|
2018-09-05 09:27:38 +08:00
|
|
|
llvm_unreachable("Unexpected instruction to emit with custom inserter");
|
2017-11-28 09:13:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-05 09:27:38 +08:00
|
|
|
const char *
|
|
|
|
WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
2015-08-12 04:13:18 +08:00
|
|
|
switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
|
2018-09-05 09:27:38 +08:00
|
|
|
case WebAssemblyISD::FIRST_NUMBER:
|
|
|
|
break;
|
|
|
|
#define HANDLE_NODETYPE(NODE) \
|
|
|
|
case WebAssemblyISD::NODE: \
|
2015-08-25 06:16:48 +08:00
|
|
|
return "WebAssemblyISD::" #NODE;
|
|
|
|
#include "WebAssemblyISD.def"
|
|
|
|
#undef HANDLE_NODETYPE
|
2015-08-12 04:13:18 +08:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-13 09:42:29 +08:00
|
|
|
std::pair<unsigned, const TargetRegisterClass *>
|
|
|
|
WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
|
|
|
|
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
|
|
|
|
// First, see if this is a constraint that directly corresponds to a
|
|
|
|
// WebAssembly register class.
|
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
2018-09-05 09:27:38 +08:00
|
|
|
case 'r':
|
|
|
|
assert(VT != MVT::iPTR && "Pointer MVT not expected here");
|
|
|
|
if (Subtarget->hasSIMD128() && VT.isVector()) {
|
|
|
|
if (VT.getSizeInBits() == 128)
|
|
|
|
return std::make_pair(0U, &WebAssembly::V128RegClass);
|
|
|
|
}
|
|
|
|
if (VT.isInteger() && !VT.isVector()) {
|
|
|
|
if (VT.getSizeInBits() <= 32)
|
|
|
|
return std::make_pair(0U, &WebAssembly::I32RegClass);
|
|
|
|
if (VT.getSizeInBits() <= 64)
|
|
|
|
return std::make_pair(0U, &WebAssembly::I64RegClass);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2015-11-13 09:42:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
|
|
|
|
}
|
|
|
|
|
2015-11-20 07:04:59 +08:00
|
|
|
bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
|
|
|
|
// Assume ctz is a relatively cheap operation.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
|
|
|
|
// Assume clz is a relatively cheap operation.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-16 06:01:29 +08:00
|
|
|
bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
|
|
|
|
const AddrMode &AM,
|
2018-09-05 09:27:38 +08:00
|
|
|
Type *Ty, unsigned AS,
|
2017-07-21 19:59:37 +08:00
|
|
|
Instruction *I) const {
|
2015-12-16 06:01:29 +08:00
|
|
|
// WebAssembly offsets are added as unsigned without wrapping. The
|
|
|
|
// isLegalAddressingMode gives us no way to determine if wrapping could be
|
|
|
|
// happening, so we approximate this by accepting only non-negative offsets.
|
2018-09-05 09:27:38 +08:00
|
|
|
if (AM.BaseOffs < 0)
|
|
|
|
return false;
|
2015-12-16 06:01:29 +08:00
|
|
|
|
|
|
|
// WebAssembly has no scale register operands.
|
2018-09-05 09:27:38 +08:00
|
|
|
if (AM.Scale != 0)
|
|
|
|
return false;
|
2015-12-16 06:01:29 +08:00
|
|
|
|
|
|
|
// Everything else is legal.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-26 11:39:31 +08:00
|
|
|
bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
|
2016-02-12 04:57:09 +08:00
|
|
|
EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast) const {
|
2016-01-26 11:39:31 +08:00
|
|
|
// WebAssembly supports unaligned accesses, though it should be declared
|
|
|
|
// with the p2align attribute on loads and stores which do so, and there
|
|
|
|
// may be a performance impact. We tell LLVM they're "fast" because
|
2016-01-26 22:55:17 +08:00
|
|
|
// for the kinds of things that LLVM uses this for (merging adjacent stores
|
2016-01-26 11:39:31 +08:00
|
|
|
// of constants, etc.), WebAssembly implementations will either want the
|
|
|
|
// unaligned access or they'll split anyway.
|
2018-09-05 09:27:38 +08:00
|
|
|
if (Fast)
|
|
|
|
*Fast = true;
|
2016-01-26 11:39:31 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-22 00:57:19 +08:00
|
|
|
bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
|
|
|
|
AttributeList Attr) const {
|
2016-05-18 22:29:42 +08:00
|
|
|
// The current thinking is that wasm engines will perform this optimization,
|
|
|
|
// so we can save on code size.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-29 01:27:09 +08:00
|
|
|
EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
|
|
|
|
LLVMContext &C,
|
|
|
|
EVT VT) const {
|
|
|
|
if (VT.isVector())
|
|
|
|
return VT.changeVectorElementTypeToInteger();
|
|
|
|
|
|
|
|
return TargetLowering::getSetCCResultType(DL, C, VT);
|
|
|
|
}
|
|
|
|
|
2018-08-03 05:44:24 +08:00
|
|
|
bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
|
|
|
|
const CallInst &I,
|
|
|
|
MachineFunction &MF,
|
|
|
|
unsigned Intrinsic) const {
|
|
|
|
switch (Intrinsic) {
|
|
|
|
case Intrinsic::wasm_atomic_notify:
|
|
|
|
Info.opc = ISD::INTRINSIC_W_CHAIN;
|
|
|
|
Info.memVT = MVT::i32;
|
|
|
|
Info.ptrVal = I.getArgOperand(0);
|
|
|
|
Info.offset = 0;
|
|
|
|
Info.align = 4;
|
|
|
|
// atomic.notify instruction does not really load the memory specified with
|
|
|
|
// this argument, but MachineMemOperand should either be load or store, so
|
|
|
|
// we set this to a load.
|
|
|
|
// FIXME Volatile isn't really correct, but currently all LLVM atomic
|
|
|
|
// instructions are treated as volatiles in the backend, so we should be
|
|
|
|
// consistent. The same applies for wasm_atomic_wait intrinsics too.
|
|
|
|
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
|
|
|
|
return true;
|
|
|
|
case Intrinsic::wasm_atomic_wait_i32:
|
|
|
|
Info.opc = ISD::INTRINSIC_W_CHAIN;
|
|
|
|
Info.memVT = MVT::i32;
|
|
|
|
Info.ptrVal = I.getArgOperand(0);
|
|
|
|
Info.offset = 0;
|
|
|
|
Info.align = 4;
|
|
|
|
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
|
|
|
|
return true;
|
|
|
|
case Intrinsic::wasm_atomic_wait_i64:
|
|
|
|
Info.opc = ISD::INTRINSIC_W_CHAIN;
|
|
|
|
Info.memVT = MVT::i64;
|
|
|
|
Info.ptrVal = I.getArgOperand(0);
|
|
|
|
Info.offset = 0;
|
|
|
|
Info.align = 8;
|
|
|
|
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// WebAssembly Lowering private implementation.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Lowering Code
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
|
2015-07-23 05:28:15 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
DAG.getContext()->diagnose(
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
|
2015-07-23 05:28:15 +08:00
|
|
|
}
|
|
|
|
|
2015-12-05 01:16:07 +08:00
|
|
|
// Test whether the given calling convention is supported.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
static bool callingConvSupported(CallingConv::ID CallConv) {
|
2015-12-05 01:16:07 +08:00
|
|
|
// We currently support the language-independent target-independent
|
2015-12-05 02:27:03 +08:00
|
|
|
// conventions. We don't yet have a way to annotate calls with properties like
|
|
|
|
// "cold", and we don't have any call-clobbered registers, so these are mostly
|
|
|
|
// all handled the same.
|
2015-12-05 01:18:32 +08:00
|
|
|
return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
|
2015-12-05 02:27:03 +08:00
|
|
|
CallConv == CallingConv::Cold ||
|
|
|
|
CallConv == CallingConv::PreserveMost ||
|
|
|
|
CallConv == CallingConv::PreserveAll ||
|
|
|
|
CallConv == CallingConv::CXX_FAST_TLS;
|
2015-12-05 01:16:07 +08:00
|
|
|
}
|
|
|
|
|
2018-09-05 09:27:38 +08:00
|
|
|
SDValue
|
|
|
|
WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2015-08-25 05:59:51 +08:00
|
|
|
SelectionDAG &DAG = CLI.DAG;
|
|
|
|
SDLoc DL = CLI.DL;
|
|
|
|
SDValue Chain = CLI.Chain;
|
|
|
|
SDValue Callee = CLI.Callee;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2016-02-11 04:14:15 +08:00
|
|
|
auto Layout = MF.getDataLayout();
|
2015-08-25 05:59:51 +08:00
|
|
|
|
|
|
|
CallingConv::ID CallConv = CLI.CallConv;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
if (!callingConvSupported(CallConv))
|
2015-10-03 04:54:23 +08:00
|
|
|
fail(DL, DAG,
|
|
|
|
"WebAssembly doesn't support language-specific or target-specific "
|
|
|
|
"calling conventions yet");
|
2015-08-25 05:59:51 +08:00
|
|
|
if (CLI.IsPatchPoint)
|
|
|
|
fail(DL, DAG, "WebAssembly doesn't support patch point yet");
|
|
|
|
|
2015-10-03 04:54:23 +08:00
|
|
|
// WebAssembly doesn't currently support explicit tail calls. If they are
|
|
|
|
// required, fail. Otherwise, just disable them.
|
|
|
|
if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
|
|
|
|
MF.getTarget().Options.GuaranteedTailCallOpt) ||
|
2017-07-27 03:15:29 +08:00
|
|
|
(CLI.CS && CLI.CS.isMustTailCall()))
|
2015-10-03 04:54:23 +08:00
|
|
|
fail(DL, DAG, "WebAssembly doesn't support tail call yet");
|
|
|
|
CLI.IsTailCall = false;
|
|
|
|
|
2015-08-25 05:59:51 +08:00
|
|
|
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
|
2015-09-09 09:52:45 +08:00
|
|
|
if (Ins.size() > 1)
|
|
|
|
fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
|
|
|
|
|
2015-12-05 01:12:52 +08:00
|
|
|
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
|
2016-01-28 05:17:39 +08:00
|
|
|
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
|
2018-06-26 11:18:38 +08:00
|
|
|
unsigned NumFixedArgs = 0;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
for (unsigned I = 0; I < Outs.size(); ++I) {
|
|
|
|
const ISD::OutputArg &Out = Outs[I];
|
|
|
|
SDValue &OutVal = OutVals[I];
|
2015-12-10 08:22:40 +08:00
|
|
|
if (Out.Flags.isNest())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (Out.Flags.isInAlloca())
|
2015-12-10 08:22:40 +08:00
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (Out.Flags.isInConsecutiveRegs())
|
2015-12-10 08:22:40 +08:00
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (Out.Flags.isInConsecutiveRegsLast())
|
2015-12-10 08:22:40 +08:00
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
|
2016-02-13 05:30:18 +08:00
|
|
|
if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
|
2016-07-29 02:40:00 +08:00
|
|
|
auto &MFI = MF.getFrameInfo();
|
|
|
|
int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
|
|
|
|
Out.Flags.getByValAlign(),
|
|
|
|
/*isSS=*/false);
|
2016-01-28 05:17:39 +08:00
|
|
|
SDValue SizeNode =
|
|
|
|
DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
|
2016-02-11 04:14:15 +08:00
|
|
|
SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
|
2016-01-28 05:17:39 +08:00
|
|
|
Chain = DAG.getMemcpy(
|
|
|
|
Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
|
2016-02-17 09:43:37 +08:00
|
|
|
/*isVolatile*/ false, /*AlwaysInline=*/false,
|
2016-01-28 05:17:39 +08:00
|
|
|
/*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
|
|
|
|
OutVal = FINode;
|
|
|
|
}
|
2018-06-26 11:18:38 +08:00
|
|
|
// Count the number of fixed args *after* legalization.
|
|
|
|
NumFixedArgs += Out.IsFixed;
|
2015-12-05 01:12:52 +08:00
|
|
|
}
|
|
|
|
|
2015-08-25 05:59:51 +08:00
|
|
|
bool IsVarArg = CLI.IsVarArg;
|
2016-02-11 04:14:15 +08:00
|
|
|
auto PtrVT = getPointerTy(Layout);
|
2015-09-09 09:52:45 +08:00
|
|
|
|
2015-08-25 05:59:51 +08:00
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
|
|
|
|
|
2015-12-05 07:22:35 +08:00
|
|
|
if (IsVarArg) {
|
2016-02-11 03:51:04 +08:00
|
|
|
// Outgoing non-fixed arguments are placed in a buffer. First
|
|
|
|
// compute their offsets and the total amount of buffer space needed.
|
2019-02-26 13:20:19 +08:00
|
|
|
for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
|
|
|
|
const ISD::OutputArg &Out = Outs[I];
|
|
|
|
SDValue &Arg = OutVals[I];
|
2015-12-05 07:22:35 +08:00
|
|
|
EVT VT = Arg.getValueType();
|
|
|
|
assert(VT != MVT::iPTR && "Legalized args should be concrete");
|
|
|
|
Type *Ty = VT.getTypeForEVT(*DAG.getContext());
|
2019-02-26 13:20:19 +08:00
|
|
|
unsigned Align = std::max(Out.Flags.getOrigAlign(),
|
|
|
|
Layout.getABITypeAlignment(Ty));
|
2016-02-11 04:14:15 +08:00
|
|
|
unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty),
|
2019-02-26 13:20:19 +08:00
|
|
|
Align);
|
2015-12-05 07:22:35 +08:00
|
|
|
CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
|
|
|
|
Offset, VT.getSimpleVT(),
|
|
|
|
CCValAssign::Full));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
|
|
|
|
|
2016-02-11 03:51:04 +08:00
|
|
|
SDValue FINode;
|
|
|
|
if (IsVarArg && NumBytes) {
|
2015-12-05 07:22:35 +08:00
|
|
|
// For non-fixed arguments, next emit stores to store the argument values
|
2016-02-11 03:51:04 +08:00
|
|
|
// to the stack buffer at the offsets computed above.
|
2016-07-29 02:40:00 +08:00
|
|
|
int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
|
|
|
|
Layout.getStackAlignment(),
|
|
|
|
/*isSS=*/false);
|
2015-12-05 07:22:35 +08:00
|
|
|
unsigned ValNo = 0;
|
|
|
|
SmallVector<SDValue, 8> Chains;
|
|
|
|
for (SDValue Arg :
|
|
|
|
make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
|
|
|
|
assert(ArgLocs[ValNo].getValNo() == ValNo &&
|
|
|
|
"ArgLocs should remain in order and only hold varargs args");
|
|
|
|
unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
|
2016-02-11 04:14:15 +08:00
|
|
|
FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
|
2016-02-11 03:51:04 +08:00
|
|
|
SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
|
2015-12-05 07:22:35 +08:00
|
|
|
DAG.getConstant(Offset, DL, PtrVT));
|
2018-09-05 09:27:38 +08:00
|
|
|
Chains.push_back(
|
|
|
|
DAG.getStore(Chain, DL, Arg, Add,
|
|
|
|
MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
|
2015-12-05 07:22:35 +08:00
|
|
|
}
|
|
|
|
if (!Chains.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
|
2016-02-11 03:51:04 +08:00
|
|
|
} else if (IsVarArg) {
|
|
|
|
FINode = DAG.getIntPtrConstant(0, DL);
|
2015-12-05 07:22:35 +08:00
|
|
|
}
|
|
|
|
|
2019-03-27 03:46:15 +08:00
|
|
|
if (Callee->getOpcode() == ISD::GlobalAddress) {
|
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call
|
|
|
|
// is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
|
|
|
|
// doesn't at MO_GOT which is not needed for direct calls.
|
|
|
|
GlobalAddressSDNode* GA = cast<GlobalAddressSDNode>(Callee);
|
|
|
|
Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
|
|
|
|
getPointerTy(DAG.getDataLayout()),
|
|
|
|
GA->getOffset());
|
|
|
|
Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
|
|
|
|
getPointerTy(DAG.getDataLayout()), Callee);
|
|
|
|
}
|
|
|
|
|
2015-12-05 07:22:35 +08:00
|
|
|
// Compute the operands for the CALLn node.
|
2015-08-25 05:59:51 +08:00
|
|
|
SmallVector<SDValue, 16> Ops;
|
|
|
|
Ops.push_back(Chain);
|
2015-08-25 06:16:48 +08:00
|
|
|
Ops.push_back(Callee);
|
2015-12-05 07:22:35 +08:00
|
|
|
|
|
|
|
// Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
|
|
|
|
// isn't reliable.
|
|
|
|
Ops.append(OutVals.begin(),
|
|
|
|
IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
|
2016-02-11 03:51:04 +08:00
|
|
|
// Add a pointer to the vararg buffer.
|
2018-09-05 09:27:38 +08:00
|
|
|
if (IsVarArg)
|
|
|
|
Ops.push_back(FINode);
|
2015-08-25 05:59:51 +08:00
|
|
|
|
2016-02-11 03:51:04 +08:00
|
|
|
SmallVector<EVT, 8> InTys;
|
2015-12-05 01:12:52 +08:00
|
|
|
for (const auto &In : Ins) {
|
2015-12-10 08:22:40 +08:00
|
|
|
assert(!In.Flags.isByVal() && "byval is not valid for return values");
|
|
|
|
assert(!In.Flags.isNest() && "nest is not valid for return values");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (In.Flags.isInAlloca())
|
2015-12-10 08:22:40 +08:00
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (In.Flags.isInConsecutiveRegs())
|
2015-12-10 08:22:40 +08:00
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
|
2015-12-05 01:12:52 +08:00
|
|
|
if (In.Flags.isInConsecutiveRegsLast())
|
2015-12-16 06:01:29 +08:00
|
|
|
fail(DL, DAG,
|
|
|
|
"WebAssembly hasn't implemented cons regs last return values");
|
2015-12-05 01:12:52 +08:00
|
|
|
// Ignore In.getOrigAlign() because all our arguments are passed in
|
|
|
|
// registers.
|
2016-02-11 03:51:04 +08:00
|
|
|
InTys.push_back(In.VT);
|
2015-12-05 01:12:52 +08:00
|
|
|
}
|
2016-02-11 03:51:04 +08:00
|
|
|
InTys.push_back(MVT::Other);
|
|
|
|
SDVTList InTyList = DAG.getVTList(InTys);
|
2015-09-10 00:13:47 +08:00
|
|
|
SDValue Res =
|
|
|
|
DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
|
2016-02-11 03:51:04 +08:00
|
|
|
DL, InTyList, Ops);
|
2015-08-25 06:16:48 +08:00
|
|
|
if (Ins.empty()) {
|
|
|
|
Chain = Res;
|
|
|
|
} else {
|
|
|
|
InVals.push_back(Res);
|
|
|
|
Chain = Res.getValue(1);
|
|
|
|
}
|
2015-08-25 05:59:51 +08:00
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
2015-07-23 05:28:15 +08:00
|
|
|
bool WebAssemblyTargetLowering::CanLowerReturn(
|
2015-11-30 06:32:02 +08:00
|
|
|
CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
LLVMContext & /*Context*/) const {
|
2015-07-23 05:28:15 +08:00
|
|
|
// WebAssembly can't currently handle returning tuples.
|
|
|
|
return Outs.size() <= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue WebAssemblyTargetLowering::LowerReturn(
|
2015-12-05 07:22:35 +08:00
|
|
|
SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
|
2015-07-23 05:28:15 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
2016-06-12 23:39:02 +08:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
|
2015-07-23 05:28:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
if (!callingConvSupported(CallConv))
|
2015-07-23 05:28:15 +08:00
|
|
|
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
|
|
|
|
|
2015-08-01 01:53:38 +08:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
|
|
RetOps.append(OutVals.begin(), OutVals.end());
|
2015-08-01 05:04:18 +08:00
|
|
|
Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
|
2015-07-23 05:28:15 +08:00
|
|
|
|
2015-11-11 09:33:02 +08:00
|
|
|
// Record the number and types of the return values.
|
|
|
|
for (const ISD::OutputArg &Out : Outs) {
|
2015-12-03 07:40:03 +08:00
|
|
|
assert(!Out.Flags.isByVal() && "byval is not valid for return values");
|
|
|
|
assert(!Out.Flags.isNest() && "nest is not valid for return values");
|
2015-12-05 07:22:35 +08:00
|
|
|
assert(Out.IsFixed && "non-fixed return value is not valid");
|
2015-11-11 09:33:02 +08:00
|
|
|
if (Out.Flags.isInAlloca())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
|
|
|
|
if (Out.Flags.isInConsecutiveRegs())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
|
|
|
|
if (Out.Flags.isInConsecutiveRegsLast())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
|
|
|
|
}
|
|
|
|
|
2015-07-23 05:28:15 +08:00
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue WebAssemblyTargetLowering::LowerFormalArguments(
|
2016-02-11 03:51:04 +08:00
|
|
|
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
2016-06-12 23:39:02 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
|
|
|
|
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
if (!callingConvSupported(CallConv))
|
2015-07-23 05:28:15 +08:00
|
|
|
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
|
|
|
|
|
2016-10-07 06:29:32 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
|
|
|
|
|
2015-11-26 03:36:19 +08:00
|
|
|
// Set up the incoming ARGUMENTS value, which serves to represent the liveness
|
|
|
|
// of the incoming values before they're represented by virtual registers.
|
|
|
|
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
|
|
|
|
|
2015-08-01 01:53:38 +08:00
|
|
|
for (const ISD::InputArg &In : Ins) {
|
|
|
|
if (In.Flags.isInAlloca())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
|
|
|
|
if (In.Flags.isNest())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
|
|
|
|
if (In.Flags.isInConsecutiveRegs())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
|
|
|
|
if (In.Flags.isInConsecutiveRegsLast())
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
|
2015-11-26 02:13:18 +08:00
|
|
|
// Ignore In.getOrigAlign() because all our arguments are passed in
|
|
|
|
// registers.
|
2018-09-05 09:27:38 +08:00
|
|
|
InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
|
|
|
|
DAG.getTargetConstant(InVals.size(),
|
|
|
|
DL, MVT::i32))
|
|
|
|
: DAG.getUNDEF(In.VT));
|
2015-11-11 09:33:02 +08:00
|
|
|
|
|
|
|
// Record the number and types of arguments.
|
2016-02-11 03:51:04 +08:00
|
|
|
MFI->addParam(In.VT);
|
2015-08-01 01:53:38 +08:00
|
|
|
}
|
2015-07-23 05:28:15 +08:00
|
|
|
|
2016-02-11 03:51:04 +08:00
|
|
|
// Varargs are copied into a buffer allocated by the caller, and a pointer to
|
|
|
|
// the buffer is passed as an argument.
|
|
|
|
if (IsVarArg) {
|
|
|
|
MVT PtrVT = getPointerTy(MF.getDataLayout());
|
|
|
|
unsigned VarargVreg =
|
|
|
|
MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
|
|
|
|
MFI->setVarargBufferVreg(VarargVreg);
|
|
|
|
Chain = DAG.getCopyToReg(
|
|
|
|
Chain, DL, VarargVreg,
|
|
|
|
DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
|
|
|
|
DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
|
|
|
|
MFI->addParam(PtrVT);
|
|
|
|
}
|
2015-12-05 07:22:35 +08:00
|
|
|
|
2018-10-04 06:22:48 +08:00
|
|
|
// Record the number and types of arguments and results.
|
2016-10-07 06:29:32 +08:00
|
|
|
SmallVector<MVT, 4> Params;
|
|
|
|
SmallVector<MVT, 4> Results;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
computeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
|
2018-10-04 06:22:48 +08:00
|
|
|
DAG.getTarget(), Params, Results);
|
2016-10-07 06:29:32 +08:00
|
|
|
for (MVT VT : Results)
|
|
|
|
MFI->addResult(VT);
|
2018-10-04 06:22:48 +08:00
|
|
|
// TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
|
|
|
|
// the param logic here with ComputeSignatureVTs
|
|
|
|
assert(MFI->getParams().size() == Params.size() &&
|
|
|
|
std::equal(MFI->getParams().begin(), MFI->getParams().end(),
|
|
|
|
Params.begin()));
|
2016-10-07 06:29:32 +08:00
|
|
|
|
2015-07-23 05:28:15 +08:00
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2015-08-25 06:16:48 +08:00
|
|
|
// Custom lowering hooks.
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-08-25 06:16:48 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2016-02-13 06:56:03 +08:00
|
|
|
SDLoc DL(Op);
|
2015-08-25 06:16:48 +08:00
|
|
|
switch (Op.getOpcode()) {
|
2018-09-05 09:27:38 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("unimplemented operation lowering");
|
|
|
|
return SDValue();
|
|
|
|
case ISD::FrameIndex:
|
|
|
|
return LowerFrameIndex(Op, DAG);
|
|
|
|
case ISD::GlobalAddress:
|
|
|
|
return LowerGlobalAddress(Op, DAG);
|
|
|
|
case ISD::ExternalSymbol:
|
|
|
|
return LowerExternalSymbol(Op, DAG);
|
|
|
|
case ISD::JumpTable:
|
|
|
|
return LowerJumpTable(Op, DAG);
|
|
|
|
case ISD::BR_JT:
|
|
|
|
return LowerBR_JT(Op, DAG);
|
|
|
|
case ISD::VASTART:
|
|
|
|
return LowerVASTART(Op, DAG);
|
|
|
|
case ISD::BlockAddress:
|
|
|
|
case ISD::BRIND:
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
|
|
|
|
return SDValue();
|
|
|
|
case ISD::RETURNADDR: // Probably nothing meaningful can be returned here.
|
|
|
|
fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address");
|
|
|
|
return SDValue();
|
|
|
|
case ISD::FRAMEADDR:
|
|
|
|
return LowerFRAMEADDR(Op, DAG);
|
|
|
|
case ISD::CopyToReg:
|
|
|
|
return LowerCopyToReg(Op, DAG);
|
2018-11-02 08:06:56 +08:00
|
|
|
case ISD::EXTRACT_VECTOR_ELT:
|
|
|
|
case ISD::INSERT_VECTOR_ELT:
|
|
|
|
return LowerAccessVectorElement(Op, DAG);
|
2018-11-14 10:46:21 +08:00
|
|
|
case ISD::INTRINSIC_VOID:
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
case ISD::INTRINSIC_WO_CHAIN:
|
|
|
|
case ISD::INTRINSIC_W_CHAIN:
|
|
|
|
return LowerIntrinsic(Op, DAG);
|
2019-01-11 06:32:11 +08:00
|
|
|
case ISD::SIGN_EXTEND_INREG:
|
|
|
|
return LowerSIGN_EXTEND_INREG(Op, DAG);
|
2019-01-30 10:23:29 +08:00
|
|
|
case ISD::BUILD_VECTOR:
|
|
|
|
return LowerBUILD_VECTOR(Op, DAG);
|
2018-09-08 05:54:46 +08:00
|
|
|
case ISD::VECTOR_SHUFFLE:
|
|
|
|
return LowerVECTOR_SHUFFLE(Op, DAG);
|
2018-10-20 09:31:18 +08:00
|
|
|
case ISD::SHL:
|
|
|
|
case ISD::SRA:
|
|
|
|
case ISD::SRL:
|
|
|
|
return LowerShift(Op, DAG);
|
2015-08-25 06:16:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-17 02:18:36 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue Src = Op.getOperand(2);
|
|
|
|
if (isa<FrameIndexSDNode>(Src.getNode())) {
|
|
|
|
// CopyToReg nodes don't support FrameIndex operands. Other targets select
|
|
|
|
// the FI to some LEA-like instruction, but since we don't have that, we
|
|
|
|
// need to insert some kind of instruction that can take an FI operand and
|
|
|
|
// produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
|
2019-01-08 14:25:55 +08:00
|
|
|
// local.copy between Op and its FI operand.
|
2016-02-21 07:09:44 +08:00
|
|
|
SDValue Chain = Op.getOperand(0);
|
2016-02-17 02:18:36 +08:00
|
|
|
SDLoc DL(Op);
|
2016-02-21 07:09:44 +08:00
|
|
|
unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
|
2016-02-17 02:18:36 +08:00
|
|
|
EVT VT = Src.getValueType();
|
2018-09-05 09:27:38 +08:00
|
|
|
SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
|
|
|
|
: WebAssembly::COPY_I64,
|
|
|
|
DL, VT, Src),
|
|
|
|
0);
|
2016-02-21 07:09:44 +08:00
|
|
|
return Op.getNode()->getNumValues() == 1
|
|
|
|
? DAG.getCopyToReg(Chain, DL, Reg, Copy)
|
2018-09-05 09:27:38 +08:00
|
|
|
: DAG.getCopyToReg(Chain, DL, Reg, Copy,
|
|
|
|
Op.getNumOperands() == 4 ? Op.getOperand(3)
|
|
|
|
: SDValue());
|
2016-02-17 02:18:36 +08:00
|
|
|
}
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2015-12-12 07:49:46 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
int FI = cast<FrameIndexSDNode>(Op)->getIndex();
|
|
|
|
return DAG.getTargetFrameIndex(FI, Op.getValueType());
|
|
|
|
}
|
|
|
|
|
2016-02-17 07:48:04 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
// Non-zero depths are not supported by WebAssembly currently. Use the
|
|
|
|
// legalizer's default expansion, which is to return 0 (what this function is
|
|
|
|
// documented to do).
|
2016-02-17 08:14:03 +08:00
|
|
|
if (Op.getConstantOperandVal(0) > 0)
|
2016-02-17 07:48:04 +08:00
|
|
|
return SDValue();
|
|
|
|
|
2016-07-29 02:40:00 +08:00
|
|
|
DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
|
2016-02-17 07:48:04 +08:00
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
unsigned FP =
|
|
|
|
Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
|
|
|
|
return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
|
|
|
|
}
|
|
|
|
|
2015-08-25 06:16:48 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
|
|
|
const auto *GA = cast<GlobalAddressSDNode>(Op);
|
|
|
|
EVT VT = Op.getValueType();
|
2016-01-12 07:38:05 +08:00
|
|
|
assert(GA->getTargetFlags() == 0 &&
|
|
|
|
"Unexpected target flags on generic GlobalAddressSDNode");
|
2015-08-25 06:16:48 +08:00
|
|
|
if (GA->getAddressSpace() != 0)
|
|
|
|
fail(DL, DAG, "WebAssembly only expects the 0 address space");
|
2019-03-27 03:46:15 +08:00
|
|
|
|
2019-04-03 08:17:29 +08:00
|
|
|
unsigned OperandFlags = 0;
|
2019-03-27 03:46:15 +08:00
|
|
|
if (isPositionIndependent()) {
|
|
|
|
const GlobalValue *GV = GA->getGlobal();
|
|
|
|
if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) {
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MVT PtrVT = getPointerTy(MF.getDataLayout());
|
|
|
|
const char *BaseName;
|
2019-04-05 01:43:50 +08:00
|
|
|
if (GV->getValueType()->isFunctionTy()) {
|
2019-03-27 03:46:15 +08:00
|
|
|
BaseName = MF.createExternalSymbolName("__table_base");
|
2019-04-05 01:43:50 +08:00
|
|
|
OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
|
|
|
|
}
|
|
|
|
else {
|
2019-03-27 03:46:15 +08:00
|
|
|
BaseName = MF.createExternalSymbolName("__memory_base");
|
2019-04-05 01:43:50 +08:00
|
|
|
OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
|
|
|
|
}
|
2019-03-27 03:46:15 +08:00
|
|
|
SDValue BaseAddr =
|
|
|
|
DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
|
|
|
|
DAG.getTargetExternalSymbol(BaseName, PtrVT));
|
|
|
|
|
|
|
|
SDValue SymAddr = DAG.getNode(
|
|
|
|
WebAssemblyISD::WrapperPIC, DL, VT,
|
2019-04-05 01:43:50 +08:00
|
|
|
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
|
|
|
|
OperandFlags));
|
2019-03-27 03:46:15 +08:00
|
|
|
|
|
|
|
return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
|
|
|
|
} else {
|
2019-04-03 08:17:29 +08:00
|
|
|
OperandFlags = WebAssemblyII::MO_GOT;
|
2019-03-27 03:46:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
|
|
|
|
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
|
2019-04-03 08:17:29 +08:00
|
|
|
GA->getOffset(), OperandFlags));
|
2015-08-25 06:16:48 +08:00
|
|
|
}
|
|
|
|
|
2018-09-05 09:27:38 +08:00
|
|
|
SDValue
|
|
|
|
WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2015-11-26 00:44:29 +08:00
|
|
|
SDLoc DL(Op);
|
|
|
|
const auto *ES = cast<ExternalSymbolSDNode>(Op);
|
|
|
|
EVT VT = Op.getValueType();
|
2016-01-12 07:38:05 +08:00
|
|
|
assert(ES->getTargetFlags() == 0 &&
|
|
|
|
"Unexpected target flags on generic ExternalSymbolSDNode");
|
2019-04-03 08:17:29 +08:00
|
|
|
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
|
|
|
|
DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
|
2015-11-26 00:44:29 +08:00
|
|
|
}
|
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
// There's no need for a Wrapper node because we always incorporate a jump
|
2016-03-08 11:18:12 +08:00
|
|
|
// table operand into a BR_TABLE instruction, rather than ever
|
2015-11-20 11:02:49 +08:00
|
|
|
// materializing it in a register.
|
2015-09-17 00:51:30 +08:00
|
|
|
const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
|
|
|
|
return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
|
|
|
|
JT->getTargetFlags());
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
|
|
|
|
SDValue Index = Op.getOperand(2);
|
|
|
|
assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
|
|
|
|
|
|
|
|
SmallVector<SDValue, 8> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Index);
|
|
|
|
|
|
|
|
MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
|
|
|
|
const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
|
|
|
|
|
2016-03-08 11:18:12 +08:00
|
|
|
// Add an operand for each case.
|
2018-09-05 09:27:38 +08:00
|
|
|
for (auto MBB : MBBs)
|
|
|
|
Ops.push_back(DAG.getBasicBlock(MBB));
|
2016-03-08 11:18:12 +08:00
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
// TODO: For now, we just pick something arbitrary for a default case for now.
|
|
|
|
// We really want to sniff out the guard and put in the real default case (and
|
|
|
|
// delete the guard).
|
|
|
|
Ops.push_back(DAG.getBasicBlock(MBBs[0]));
|
|
|
|
|
2016-03-08 11:18:12 +08:00
|
|
|
return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
|
2015-09-17 00:51:30 +08:00
|
|
|
}
|
|
|
|
|
2015-12-05 07:22:35 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
|
|
|
EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
|
|
|
|
|
2016-02-11 03:51:04 +08:00
|
|
|
auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
|
2015-12-05 07:22:35 +08:00
|
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
2016-02-11 03:51:04 +08:00
|
|
|
|
|
|
|
SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
|
|
|
|
MFI->getVarargBufferVreg(), PtrVT);
|
|
|
|
return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
|
2016-07-16 03:35:43 +08:00
|
|
|
MachinePointerInfo(SV), 0);
|
2015-12-05 07:22:35 +08:00
|
|
|
}
|
|
|
|
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
unsigned IntNo;
|
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
case ISD::INTRINSIC_VOID:
|
|
|
|
case ISD::INTRINSIC_W_CHAIN:
|
|
|
|
IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
|
|
|
|
break;
|
|
|
|
case ISD::INTRINSIC_WO_CHAIN:
|
|
|
|
IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Invalid intrinsic");
|
|
|
|
}
|
[WebAssembly] Support instruction selection for catching exceptions
Summary:
This lowers exception catching-related instructions:
1. Lowers `wasm.catch` intrinsic to `catch` instruction
2. Removes `catchpad` and `cleanuppad` instructions; they are not
necessary after isel phase. (`MachineBasicBlock::isEHFuncletEntry()` or
`MachineBasicBlock::isEHPad()` can be used instead.)
3. Lowers `catchret` and `cleanupret` instructions to pseudo `catchret`
and `cleanupret` instructions in isel, which will be replaced with other
instructions in `WebAssemblyExceptionPrepare` pass.
4. Adds 'WebAssemblyExceptionPrepare` pass, which is for running various
transformation for EH. Currently this pass only replaces `catchret` and
`cleanupret` instructions into appropriate wasm instructions to make
this patch successfully run until the end.
Currently this does not handle lowering of intrinsics related to LSDA
info generation (`wasm.landingpad.index` and `wasm.lsda`), because they
cannot be tested without implementing `EHStreamer`'s wasm-specific
handlers. They are marked as TODO, which is needed to make isel pass.
Also this does not generate `try` and `end_try` markers yet, which will
be handled in later patches.
This patch is based on the first wasm EH proposal.
(https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md)
Reviewers: dschuff, majnemer
Subscribers: jfb, sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D44090
llvm-svn: 333705
2018-06-01 06:25:54 +08:00
|
|
|
SDLoc DL(Op);
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
|
[WebAssembly] Support instruction selection for catching exceptions
Summary:
This lowers exception catching-related instructions:
1. Lowers `wasm.catch` intrinsic to `catch` instruction
2. Removes `catchpad` and `cleanuppad` instructions; they are not
necessary after isel phase. (`MachineBasicBlock::isEHFuncletEntry()` or
`MachineBasicBlock::isEHPad()` can be used instead.)
3. Lowers `catchret` and `cleanupret` instructions to pseudo `catchret`
and `cleanupret` instructions in isel, which will be replaced with other
instructions in `WebAssemblyExceptionPrepare` pass.
4. Adds 'WebAssemblyExceptionPrepare` pass, which is for running various
transformation for EH. Currently this pass only replaces `catchret` and
`cleanupret` instructions into appropriate wasm instructions to make
this patch successfully run until the end.
Currently this does not handle lowering of intrinsics related to LSDA
info generation (`wasm.landingpad.index` and `wasm.lsda`), because they
cannot be tested without implementing `EHStreamer`'s wasm-specific
handlers. They are marked as TODO, which is needed to make isel pass.
Also this does not generate `try` and `end_try` markers yet, which will
be handled in later patches.
This patch is based on the first wasm EH proposal.
(https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md)
Reviewers: dschuff, majnemer
Subscribers: jfb, sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D44090
llvm-svn: 333705
2018-06-01 06:25:54 +08:00
|
|
|
switch (IntNo) {
|
|
|
|
default:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
return SDValue(); // Don't custom lower most intrinsics.
|
2018-10-04 07:02:23 +08:00
|
|
|
|
Reland "[WebAssembly] LSDA info generation"
Summary:
This adds support for LSDA (exception table) generation for wasm EH.
Wasm EH mostly follows the structure of Itanium-style exception tables,
with one exception: a call site table entry in wasm EH corresponds to
not a call site but a landing pad.
In wasm EH, the VM is responsible for stack unwinding. After an
exception occurs and the stack is unwound, the control flow is
transferred to wasm 'catch' instruction by the VM, after which the
personality function is called from the compiler-generated code. (Refer
to WasmEHPrepare pass for more information on this part.)
This patch:
- Changes wasm.landingpad.index intrinsic to take a token argument, to
make this 1:1 match with a catchpad instruction
- Stores landingpad index info and catch type info MachineFunction in
before instruction selection
- Lowers wasm.lsda intrinsic to an MCSymbol pointing to the start of an
exception table
- Adds WasmException class with overridden methods for table generation
- Adds support for LSDA section in Wasm object writer
Reviewers: dschuff, sbc100, rnk
Subscribers: mgorny, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D52748
llvm-svn: 345345
2018-10-26 07:55:10 +08:00
|
|
|
case Intrinsic::wasm_lsda: {
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
|
|
|
|
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
|
|
|
|
auto &Context = MF.getMMI().getContext();
|
|
|
|
MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
|
|
|
|
Twine(MF.getFunctionNumber()));
|
|
|
|
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
|
|
|
|
DAG.getMCSymbol(S, PtrVT));
|
|
|
|
}
|
2018-11-14 10:46:21 +08:00
|
|
|
|
|
|
|
case Intrinsic::wasm_throw: {
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
// We only support C++ exceptions for now
|
2018-11-14 10:46:21 +08:00
|
|
|
int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
if (Tag != CPP_EXCEPTION)
|
2018-11-14 10:46:21 +08:00
|
|
|
llvm_unreachable("Invalid tag!");
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
|
|
|
|
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
|
|
|
|
const char *SymName = MF.createExternalSymbolName("__cpp_exception");
|
2019-04-03 08:17:29 +08:00
|
|
|
SDValue SymNode = DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
|
|
|
|
DAG.getTargetExternalSymbol(SymName, PtrVT));
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
return DAG.getNode(WebAssemblyISD::THROW, DL,
|
|
|
|
MVT::Other, // outchain type
|
|
|
|
{
|
|
|
|
Op.getOperand(0), // inchain
|
|
|
|
SymNode, // exception symbol
|
|
|
|
Op.getOperand(3) // thrown value
|
|
|
|
});
|
2018-11-14 10:46:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 06:32:11 +08:00
|
|
|
SDValue
|
|
|
|
WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
// If sign extension operations are disabled, allow sext_inreg only if operand
|
|
|
|
// is a vector extract. SIMD does not depend on sign extension operations, but
|
|
|
|
// allowing sext_inreg in this context lets us have simple patterns to select
|
|
|
|
// extract_lane_s instructions. Expanding sext_inreg everywhere would be
|
|
|
|
// simpler in this file, but would necessitate large and brittle patterns to
|
|
|
|
// undo the expansion and select extract_lane_s instructions.
|
|
|
|
assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
|
|
|
|
if (Op.getOperand(0).getOpcode() == ISD::EXTRACT_VECTOR_ELT)
|
|
|
|
return Op;
|
|
|
|
// Otherwise expand
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2019-01-30 10:23:29 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
|
|
|
const EVT VecT = Op.getValueType();
|
|
|
|
const EVT LaneT = Op.getOperand(0).getValueType();
|
|
|
|
const size_t Lanes = Op.getNumOperands();
|
|
|
|
auto IsConstant = [](const SDValue &V) {
|
|
|
|
return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Find the most common operand, which is approximately the best to splat
|
|
|
|
using Entry = std::pair<SDValue, size_t>;
|
|
|
|
SmallVector<Entry, 16> ValueCounts;
|
|
|
|
size_t NumConst = 0, NumDynamic = 0;
|
|
|
|
for (const SDValue &Lane : Op->op_values()) {
|
|
|
|
if (Lane.isUndef()) {
|
|
|
|
continue;
|
|
|
|
} else if (IsConstant(Lane)) {
|
|
|
|
NumConst++;
|
|
|
|
} else {
|
|
|
|
NumDynamic++;
|
|
|
|
}
|
|
|
|
auto CountIt = std::find_if(ValueCounts.begin(), ValueCounts.end(),
|
|
|
|
[&Lane](Entry A) { return A.first == Lane; });
|
|
|
|
if (CountIt == ValueCounts.end()) {
|
|
|
|
ValueCounts.emplace_back(Lane, 1);
|
|
|
|
} else {
|
|
|
|
CountIt->second++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto CommonIt =
|
|
|
|
std::max_element(ValueCounts.begin(), ValueCounts.end(),
|
|
|
|
[](Entry A, Entry B) { return A.second < B.second; });
|
|
|
|
assert(CommonIt != ValueCounts.end() && "Unexpected all-undef build_vector");
|
|
|
|
SDValue SplatValue = CommonIt->first;
|
|
|
|
size_t NumCommon = CommonIt->second;
|
|
|
|
|
|
|
|
// If v128.const is available, consider using it instead of a splat
|
|
|
|
if (Subtarget->hasUnimplementedSIMD128()) {
|
|
|
|
// {i32,i64,f32,f64}.const opcode, and value
|
|
|
|
const size_t ConstBytes = 1 + std::max(size_t(4), 16 / Lanes);
|
|
|
|
// SIMD prefix and opcode
|
|
|
|
const size_t SplatBytes = 2;
|
|
|
|
const size_t SplatConstBytes = SplatBytes + ConstBytes;
|
|
|
|
// SIMD prefix, opcode, and lane index
|
|
|
|
const size_t ReplaceBytes = 3;
|
|
|
|
const size_t ReplaceConstBytes = ReplaceBytes + ConstBytes;
|
|
|
|
// SIMD prefix, v128.const opcode, and 128-bit value
|
|
|
|
const size_t VecConstBytes = 18;
|
|
|
|
// Initial v128.const and a replace_lane for each non-const operand
|
|
|
|
const size_t ConstInitBytes = VecConstBytes + NumDynamic * ReplaceBytes;
|
|
|
|
// Initial splat and all necessary replace_lanes
|
|
|
|
const size_t SplatInitBytes =
|
|
|
|
IsConstant(SplatValue)
|
|
|
|
// Initial constant splat
|
|
|
|
? (SplatConstBytes +
|
|
|
|
// Constant replace_lanes
|
|
|
|
(NumConst - NumCommon) * ReplaceConstBytes +
|
|
|
|
// Dynamic replace_lanes
|
|
|
|
(NumDynamic * ReplaceBytes))
|
|
|
|
// Initial dynamic splat
|
|
|
|
: (SplatBytes +
|
|
|
|
// Constant replace_lanes
|
|
|
|
(NumConst * ReplaceConstBytes) +
|
|
|
|
// Dynamic replace_lanes
|
|
|
|
(NumDynamic - NumCommon) * ReplaceBytes);
|
|
|
|
if (ConstInitBytes < SplatInitBytes) {
|
|
|
|
// Create build_vector that will lower to initial v128.const
|
|
|
|
SmallVector<SDValue, 16> ConstLanes;
|
|
|
|
for (const SDValue &Lane : Op->op_values()) {
|
|
|
|
if (IsConstant(Lane)) {
|
|
|
|
ConstLanes.push_back(Lane);
|
|
|
|
} else if (LaneT.isFloatingPoint()) {
|
|
|
|
ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
|
|
|
|
} else {
|
|
|
|
ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SDValue Result = DAG.getBuildVector(VecT, DL, ConstLanes);
|
|
|
|
// Add replace_lane instructions for non-const lanes
|
|
|
|
for (size_t I = 0; I < Lanes; ++I) {
|
|
|
|
const SDValue &Lane = Op->getOperand(I);
|
|
|
|
if (!Lane.isUndef() && !IsConstant(Lane))
|
|
|
|
Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
|
|
|
|
DAG.getConstant(I, DL, MVT::i32));
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Use a splat for the initial vector
|
|
|
|
SDValue Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
|
|
|
|
// Add replace_lane instructions for other values
|
|
|
|
for (size_t I = 0; I < Lanes; ++I) {
|
|
|
|
const SDValue &Lane = Op->getOperand(I);
|
|
|
|
if (Lane != SplatValue)
|
|
|
|
Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
|
|
|
|
DAG.getConstant(I, DL, MVT::i32));
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-09-08 05:54:46 +08:00
|
|
|
SDValue
|
|
|
|
WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
|
|
|
ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
|
|
|
|
MVT VecType = Op.getOperand(0).getSimpleValueType();
|
|
|
|
assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
|
|
|
|
size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
|
|
|
|
|
|
|
|
// Space for two vector args and sixteen mask indices
|
|
|
|
SDValue Ops[18];
|
|
|
|
size_t OpIdx = 0;
|
|
|
|
Ops[OpIdx++] = Op.getOperand(0);
|
|
|
|
Ops[OpIdx++] = Op.getOperand(1);
|
|
|
|
|
|
|
|
// Expand mask indices to byte indices and materialize them as operands
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
for (int M : Mask) {
|
2018-09-08 05:54:46 +08:00
|
|
|
for (size_t J = 0; J < LaneBytes; ++J) {
|
2018-10-20 03:08:06 +08:00
|
|
|
// Lower undefs (represented by -1 in mask) to zero
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
uint64_t ByteIndex = M == -1 ? 0 : (uint64_t)M * LaneBytes + J;
|
2018-10-20 03:08:06 +08:00
|
|
|
Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
|
2018-09-08 05:54:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-25 07:27:40 +08:00
|
|
|
return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
|
2018-09-08 05:54:46 +08:00
|
|
|
}
|
|
|
|
|
2018-11-02 08:06:56 +08:00
|
|
|
SDValue
|
|
|
|
WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
// Allow constant lane indices, expand variable lane indices
|
|
|
|
SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
|
|
|
|
if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef())
|
|
|
|
return Op;
|
|
|
|
else
|
|
|
|
// Perform default expansion
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG) {
|
2019-01-15 10:16:03 +08:00
|
|
|
EVT LaneT = Op.getSimpleValueType().getVectorElementType();
|
|
|
|
// 32-bit and 64-bit unrolled shifts will have proper semantics
|
|
|
|
if (LaneT.bitsGE(MVT::i32))
|
|
|
|
return DAG.UnrollVectorOp(Op.getNode());
|
|
|
|
// Otherwise mask the shift value to get proper semantics from 32-bit shift
|
|
|
|
SDLoc DL(Op);
|
|
|
|
SDValue ShiftVal = Op.getOperand(1);
|
|
|
|
uint64_t MaskVal = LaneT.getSizeInBits() - 1;
|
|
|
|
SDValue MaskedShiftVal = DAG.getNode(
|
|
|
|
ISD::AND, // mask opcode
|
|
|
|
DL, ShiftVal.getValueType(), // masked value type
|
|
|
|
ShiftVal, // original shift value operand
|
|
|
|
DAG.getConstant(MaskVal, DL, ShiftVal.getValueType()) // mask operand
|
|
|
|
);
|
|
|
|
|
|
|
|
return DAG.UnrollVectorOp(
|
|
|
|
DAG.getNode(Op.getOpcode(), // original shift opcode
|
|
|
|
DL, Op.getValueType(), // original return type
|
|
|
|
Op.getOperand(0), // original vector operand,
|
|
|
|
MaskedShiftVal // new masked shift value operand
|
|
|
|
)
|
|
|
|
.getNode());
|
|
|
|
}
|
|
|
|
|
2018-10-20 09:31:18 +08:00
|
|
|
SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc DL(Op);
|
2018-11-02 08:39:57 +08:00
|
|
|
|
|
|
|
// Only manually lower vector shifts
|
|
|
|
assert(Op.getSimpleValueType().isVector());
|
|
|
|
|
2019-03-02 01:43:55 +08:00
|
|
|
// Expand all vector shifts until V8 fixes its implementation
|
|
|
|
// TODO: remove this once V8 is fixed
|
|
|
|
if (!Subtarget->hasUnimplementedSIMD128())
|
|
|
|
return unrollVectorShift(Op, DAG);
|
|
|
|
|
2018-11-02 08:39:57 +08:00
|
|
|
// Unroll non-splat vector shifts
|
|
|
|
BuildVectorSDNode *ShiftVec;
|
|
|
|
SDValue SplatVal;
|
|
|
|
if (!(ShiftVec = dyn_cast<BuildVectorSDNode>(Op.getOperand(1).getNode())) ||
|
|
|
|
!(SplatVal = ShiftVec->getSplatValue()))
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
return unrollVectorShift(Op, DAG);
|
2018-11-02 08:39:57 +08:00
|
|
|
|
|
|
|
// All splats except i64x2 const splats are handled by patterns
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
auto *SplatConst = dyn_cast<ConstantSDNode>(SplatVal);
|
2018-11-02 08:39:57 +08:00
|
|
|
if (!SplatConst || Op.getSimpleValueType() != MVT::v2i64)
|
2018-10-20 09:31:18 +08:00
|
|
|
return Op;
|
2018-11-02 08:39:57 +08:00
|
|
|
|
|
|
|
// i64x2 const splats are custom lowered to avoid unnecessary wraps
|
2018-10-20 09:31:18 +08:00
|
|
|
unsigned Opcode;
|
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
case ISD::SHL:
|
|
|
|
Opcode = WebAssemblyISD::VEC_SHL;
|
|
|
|
break;
|
|
|
|
case ISD::SRA:
|
|
|
|
Opcode = WebAssemblyISD::VEC_SHR_S;
|
|
|
|
break;
|
|
|
|
case ISD::SRL:
|
|
|
|
Opcode = WebAssemblyISD::VEC_SHR_U;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unexpected opcode");
|
|
|
|
}
|
2018-11-02 08:39:57 +08:00
|
|
|
APInt Shift = SplatConst->getAPIntValue().zextOrTrunc(32);
|
2018-10-20 09:31:18 +08:00
|
|
|
return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0),
|
2018-11-02 08:39:57 +08:00
|
|
|
DAG.getConstant(Shift, DL, MVT::i32));
|
2018-10-20 09:31:18 +08:00
|
|
|
}
|
|
|
|
|
2015-06-30 07:51:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// WebAssembly Optimization Hooks
|
|
|
|
//===----------------------------------------------------------------------===//
|