1 //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements the WebAssemblyTargetLowering class.
12 //===----------------------------------------------------------------------===//
14 #include "WebAssemblyISelLowering.h"
15 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16 #include "WebAssemblyMachineFunctionInfo.h"
17 #include "WebAssemblySubtarget.h"
18 #include "WebAssemblyTargetMachine.h"
19 #include "llvm/CodeGen/Analysis.h"
20 #include "llvm/CodeGen/CallingConvLower.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineJumpTableInfo.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
25 #include "llvm/CodeGen/SelectionDAG.h"
26 #include "llvm/CodeGen/WasmEHFuncInfo.h"
27 #include "llvm/IR/DiagnosticInfo.h"
28 #include "llvm/IR/DiagnosticPrinter.h"
29 #include "llvm/IR/Function.h"
30 #include "llvm/IR/Intrinsics.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/Target/TargetOptions.h"
37 #define DEBUG_TYPE "wasm-lower"
39 WebAssemblyTargetLowering::WebAssemblyTargetLowering(
40 const TargetMachine
&TM
, const WebAssemblySubtarget
&STI
)
41 : TargetLowering(TM
), Subtarget(&STI
) {
42 auto MVTPtr
= Subtarget
->hasAddr64() ? MVT::i64
: MVT::i32
;
44 // Booleans always contain 0 or 1.
45 setBooleanContents(ZeroOrOneBooleanContent
);
46 // Except in SIMD vectors
47 setBooleanVectorContents(ZeroOrNegativeOneBooleanContent
);
48 // WebAssembly does not produce floating-point exceptions on normal floating
50 setHasFloatingPointExceptions(false);
51 // We don't know the microarchitecture here, so just reduce register pressure.
52 setSchedulingPreference(Sched::RegPressure
);
53 // Tell ISel that we have a stack pointer.
54 setStackPointerRegisterToSaveRestore(
55 Subtarget
->hasAddr64() ? WebAssembly::SP64
: WebAssembly::SP32
);
56 // Set up the register classes.
57 addRegisterClass(MVT::i32
, &WebAssembly::I32RegClass
);
58 addRegisterClass(MVT::i64
, &WebAssembly::I64RegClass
);
59 addRegisterClass(MVT::f32
, &WebAssembly::F32RegClass
);
60 addRegisterClass(MVT::f64
, &WebAssembly::F64RegClass
);
61 if (Subtarget
->hasSIMD128()) {
62 addRegisterClass(MVT::v16i8
, &WebAssembly::V128RegClass
);
63 addRegisterClass(MVT::v8i16
, &WebAssembly::V128RegClass
);
64 addRegisterClass(MVT::v4i32
, &WebAssembly::V128RegClass
);
65 addRegisterClass(MVT::v4f32
, &WebAssembly::V128RegClass
);
67 if (Subtarget
->hasUnimplementedSIMD128()) {
68 addRegisterClass(MVT::v2i64
, &WebAssembly::V128RegClass
);
69 addRegisterClass(MVT::v2f64
, &WebAssembly::V128RegClass
);
71 // Compute derived properties from the register classes.
72 computeRegisterProperties(Subtarget
->getRegisterInfo());
74 setOperationAction(ISD::GlobalAddress
, MVTPtr
, Custom
);
75 setOperationAction(ISD::ExternalSymbol
, MVTPtr
, Custom
);
76 setOperationAction(ISD::JumpTable
, MVTPtr
, Custom
);
77 setOperationAction(ISD::BlockAddress
, MVTPtr
, Custom
);
78 setOperationAction(ISD::BRIND
, MVT::Other
, Custom
);
80 // Take the default expansion for va_arg, va_copy, and va_end. There is no
81 // default action for va_start, so we do that custom.
82 setOperationAction(ISD::VASTART
, MVT::Other
, Custom
);
83 setOperationAction(ISD::VAARG
, MVT::Other
, Expand
);
84 setOperationAction(ISD::VACOPY
, MVT::Other
, Expand
);
85 setOperationAction(ISD::VAEND
, MVT::Other
, Expand
);
87 for (auto T
: {MVT::f32
, MVT::f64
, MVT::v4f32
, MVT::v2f64
}) {
88 // Don't expand the floating-point types to constant pools.
89 setOperationAction(ISD::ConstantFP
, T
, Legal
);
90 // Expand floating-point comparisons.
91 for (auto CC
: {ISD::SETO
, ISD::SETUO
, ISD::SETUEQ
, ISD::SETONE
,
92 ISD::SETULT
, ISD::SETULE
, ISD::SETUGT
, ISD::SETUGE
})
93 setCondCodeAction(CC
, T
, Expand
);
94 // Expand floating-point library function operators.
96 {ISD::FSIN
, ISD::FCOS
, ISD::FSINCOS
, ISD::FPOW
, ISD::FREM
, ISD::FMA
})
97 setOperationAction(Op
, T
, Expand
);
98 // Note supported floating-point library function operators that otherwise
101 {ISD::FCEIL
, ISD::FFLOOR
, ISD::FTRUNC
, ISD::FNEARBYINT
, ISD::FRINT
})
102 setOperationAction(Op
, T
, Legal
);
103 // Support minimum and maximum, which otherwise default to expand.
104 setOperationAction(ISD::FMINIMUM
, T
, Legal
);
105 setOperationAction(ISD::FMAXIMUM
, T
, Legal
);
106 // WebAssembly currently has no builtin f16 support.
107 setOperationAction(ISD::FP16_TO_FP
, T
, Expand
);
108 setOperationAction(ISD::FP_TO_FP16
, T
, Expand
);
109 setLoadExtAction(ISD::EXTLOAD
, T
, MVT::f16
, Expand
);
110 setTruncStoreAction(T
, MVT::f16
, Expand
);
113 // Expand unavailable integer operations.
115 {ISD::BSWAP
, ISD::SMUL_LOHI
, ISD::UMUL_LOHI
, ISD::MULHS
, ISD::MULHU
,
116 ISD::SDIVREM
, ISD::UDIVREM
, ISD::SHL_PARTS
, ISD::SRA_PARTS
,
117 ISD::SRL_PARTS
, ISD::ADDC
, ISD::ADDE
, ISD::SUBC
, ISD::SUBE
}) {
118 for (auto T
: {MVT::i32
, MVT::i64
})
119 setOperationAction(Op
, T
, Expand
);
120 if (Subtarget
->hasSIMD128())
121 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
})
122 setOperationAction(Op
, T
, Expand
);
123 if (Subtarget
->hasUnimplementedSIMD128())
124 setOperationAction(Op
, MVT::v2i64
, Expand
);
127 // SIMD-specific configuration
128 if (Subtarget
->hasSIMD128()) {
129 // Support saturating add for i8x16 and i16x8
130 for (auto Op
: {ISD::SADDSAT
, ISD::UADDSAT
})
131 for (auto T
: {MVT::v16i8
, MVT::v8i16
})
132 setOperationAction(Op
, T
, Legal
);
134 // Custom lower BUILD_VECTORs to minimize number of replace_lanes
135 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
, MVT::v4f32
})
136 setOperationAction(ISD::BUILD_VECTOR
, T
, Custom
);
137 if (Subtarget
->hasUnimplementedSIMD128())
138 for (auto T
: {MVT::v2i64
, MVT::v2f64
})
139 setOperationAction(ISD::BUILD_VECTOR
, T
, Custom
);
141 // We have custom shuffle lowering to expose the shuffle mask
142 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
, MVT::v4f32
})
143 setOperationAction(ISD::VECTOR_SHUFFLE
, T
, Custom
);
144 if (Subtarget
->hasUnimplementedSIMD128())
145 for (auto T
: {MVT::v2i64
, MVT::v2f64
})
146 setOperationAction(ISD::VECTOR_SHUFFLE
, T
, Custom
);
148 // Custom lowering since wasm shifts must have a scalar shift amount
149 for (auto Op
: {ISD::SHL
, ISD::SRA
, ISD::SRL
}) {
150 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
})
151 setOperationAction(Op
, T
, Custom
);
152 if (Subtarget
->hasUnimplementedSIMD128())
153 setOperationAction(Op
, MVT::v2i64
, Custom
);
156 // Custom lower lane accesses to expand out variable indices
157 for (auto Op
: {ISD::EXTRACT_VECTOR_ELT
, ISD::INSERT_VECTOR_ELT
}) {
158 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
, MVT::v4f32
})
159 setOperationAction(Op
, T
, Custom
);
160 if (Subtarget
->hasUnimplementedSIMD128())
161 for (auto T
: {MVT::v2i64
, MVT::v2f64
})
162 setOperationAction(Op
, T
, Custom
);
165 // There is no i64x2.mul instruction
166 setOperationAction(ISD::MUL
, MVT::v2i64
, Expand
);
168 // There are no vector select instructions
169 for (auto Op
: {ISD::VSELECT
, ISD::SELECT_CC
, ISD::SELECT
}) {
170 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
, MVT::v4f32
})
171 setOperationAction(Op
, T
, Expand
);
172 if (Subtarget
->hasUnimplementedSIMD128())
173 for (auto T
: {MVT::v2i64
, MVT::v2f64
})
174 setOperationAction(Op
, T
, Expand
);
177 // Expand additional SIMD ops that V8 hasn't implemented yet
178 if (!Subtarget
->hasUnimplementedSIMD128()) {
179 setOperationAction(ISD::FSQRT
, MVT::v4f32
, Expand
);
180 setOperationAction(ISD::FDIV
, MVT::v4f32
, Expand
);
184 // As a special case, these operators use the type to mean the type to
186 setOperationAction(ISD::SIGN_EXTEND_INREG
, MVT::i1
, Expand
);
187 if (!Subtarget
->hasSignExt()) {
188 // Sign extends are legal only when extending a vector extract
189 auto Action
= Subtarget
->hasSIMD128() ? Custom
: Expand
;
190 for (auto T
: {MVT::i8
, MVT::i16
, MVT::i32
})
191 setOperationAction(ISD::SIGN_EXTEND_INREG
, T
, Action
);
193 for (auto T
: MVT::integer_vector_valuetypes())
194 setOperationAction(ISD::SIGN_EXTEND_INREG
, T
, Expand
);
196 // Dynamic stack allocation: use the default expansion.
197 setOperationAction(ISD::STACKSAVE
, MVT::Other
, Expand
);
198 setOperationAction(ISD::STACKRESTORE
, MVT::Other
, Expand
);
199 setOperationAction(ISD::DYNAMIC_STACKALLOC
, MVTPtr
, Expand
);
201 setOperationAction(ISD::FrameIndex
, MVT::i32
, Custom
);
202 setOperationAction(ISD::CopyToReg
, MVT::Other
, Custom
);
204 // Expand these forms; we pattern-match the forms that we can handle in isel.
205 for (auto T
: {MVT::i32
, MVT::i64
, MVT::f32
, MVT::f64
})
206 for (auto Op
: {ISD::BR_CC
, ISD::SELECT_CC
})
207 setOperationAction(Op
, T
, Expand
);
209 // We have custom switch handling.
210 setOperationAction(ISD::BR_JT
, MVT::Other
, Custom
);
212 // WebAssembly doesn't have:
213 // - Floating-point extending loads.
214 // - Floating-point truncating stores.
215 // - i1 extending loads.
216 // - extending/truncating SIMD loads/stores
217 setLoadExtAction(ISD::EXTLOAD
, MVT::f64
, MVT::f32
, Expand
);
218 setTruncStoreAction(MVT::f64
, MVT::f32
, Expand
);
219 for (auto T
: MVT::integer_valuetypes())
220 for (auto Ext
: {ISD::EXTLOAD
, ISD::ZEXTLOAD
, ISD::SEXTLOAD
})
221 setLoadExtAction(Ext
, T
, MVT::i1
, Promote
);
222 if (Subtarget
->hasSIMD128()) {
223 for (auto T
: {MVT::v16i8
, MVT::v8i16
, MVT::v4i32
, MVT::v2i64
, MVT::v4f32
,
225 for (auto MemT
: MVT::vector_valuetypes()) {
226 if (MVT(T
) != MemT
) {
227 setTruncStoreAction(T
, MemT
, Expand
);
228 for (auto Ext
: {ISD::EXTLOAD
, ISD::ZEXTLOAD
, ISD::SEXTLOAD
})
229 setLoadExtAction(Ext
, T
, MemT
, Expand
);
235 // Don't do anything clever with build_pairs
236 setOperationAction(ISD::BUILD_PAIR
, MVT::i64
, Expand
);
238 // Trap lowers to wasm unreachable
239 setOperationAction(ISD::TRAP
, MVT::Other
, Legal
);
241 // Exception handling intrinsics
242 setOperationAction(ISD::INTRINSIC_WO_CHAIN
, MVT::Other
, Custom
);
243 setOperationAction(ISD::INTRINSIC_VOID
, MVT::Other
, Custom
);
245 setMaxAtomicSizeInBitsSupported(64);
247 if (Subtarget
->hasBulkMemory()) {
248 // Use memory.copy and friends over multiple loads and stores
249 MaxStoresPerMemcpy
= 1;
250 MaxStoresPerMemcpyOptSize
= 1;
251 MaxStoresPerMemmove
= 1;
252 MaxStoresPerMemmoveOptSize
= 1;
253 MaxStoresPerMemset
= 1;
254 MaxStoresPerMemsetOptSize
= 1;
258 TargetLowering::AtomicExpansionKind
259 WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst
*AI
) const {
260 // We have wasm instructions for these
261 switch (AI
->getOperation()) {
262 case AtomicRMWInst::Add
:
263 case AtomicRMWInst::Sub
:
264 case AtomicRMWInst::And
:
265 case AtomicRMWInst::Or
:
266 case AtomicRMWInst::Xor
:
267 case AtomicRMWInst::Xchg
:
268 return AtomicExpansionKind::None
;
272 return AtomicExpansionKind::CmpXChg
;
275 FastISel
*WebAssemblyTargetLowering::createFastISel(
276 FunctionLoweringInfo
&FuncInfo
, const TargetLibraryInfo
*LibInfo
) const {
277 return WebAssembly::createFastISel(FuncInfo
, LibInfo
);
280 bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
281 const GlobalAddressSDNode
* /*GA*/) const {
282 // All offsets can be folded.
286 MVT
WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout
& /*DL*/,
288 unsigned BitWidth
= NextPowerOf2(VT
.getSizeInBits() - 1);
289 if (BitWidth
> 1 && BitWidth
< 8)
293 // The shift will be lowered to a libcall, and compiler-rt libcalls expect
294 // the count to be an i32.
296 assert(BitWidth
>= Log2_32_Ceil(VT
.getSizeInBits()) &&
297 "32-bit shift counts ought to be enough for anyone");
300 MVT Result
= MVT::getIntegerVT(BitWidth
);
301 assert(Result
!= MVT::INVALID_SIMPLE_VALUE_TYPE
&&
302 "Unable to represent scalar shift amount type");
306 // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
307 // undefined result on invalid/overflow, to the WebAssembly opcode, which
308 // traps on invalid/overflow.
309 static MachineBasicBlock
*LowerFPToInt(MachineInstr
&MI
, DebugLoc DL
,
310 MachineBasicBlock
*BB
,
311 const TargetInstrInfo
&TII
,
312 bool IsUnsigned
, bool Int64
,
313 bool Float64
, unsigned LoweredOpcode
) {
314 MachineRegisterInfo
&MRI
= BB
->getParent()->getRegInfo();
316 unsigned OutReg
= MI
.getOperand(0).getReg();
317 unsigned InReg
= MI
.getOperand(1).getReg();
319 unsigned Abs
= Float64
? WebAssembly::ABS_F64
: WebAssembly::ABS_F32
;
320 unsigned FConst
= Float64
? WebAssembly::CONST_F64
: WebAssembly::CONST_F32
;
321 unsigned LT
= Float64
? WebAssembly::LT_F64
: WebAssembly::LT_F32
;
322 unsigned GE
= Float64
? WebAssembly::GE_F64
: WebAssembly::GE_F32
;
323 unsigned IConst
= Int64
? WebAssembly::CONST_I64
: WebAssembly::CONST_I32
;
324 unsigned Eqz
= WebAssembly::EQZ_I32
;
325 unsigned And
= WebAssembly::AND_I32
;
326 int64_t Limit
= Int64
? INT64_MIN
: INT32_MIN
;
327 int64_t Substitute
= IsUnsigned
? 0 : Limit
;
328 double CmpVal
= IsUnsigned
? -(double)Limit
* 2.0 : -(double)Limit
;
329 auto &Context
= BB
->getParent()->getFunction().getContext();
330 Type
*Ty
= Float64
? Type::getDoubleTy(Context
) : Type::getFloatTy(Context
);
332 const BasicBlock
*LLVMBB
= BB
->getBasicBlock();
333 MachineFunction
*F
= BB
->getParent();
334 MachineBasicBlock
*TrueMBB
= F
->CreateMachineBasicBlock(LLVMBB
);
335 MachineBasicBlock
*FalseMBB
= F
->CreateMachineBasicBlock(LLVMBB
);
336 MachineBasicBlock
*DoneMBB
= F
->CreateMachineBasicBlock(LLVMBB
);
338 MachineFunction::iterator It
= ++BB
->getIterator();
339 F
->insert(It
, FalseMBB
);
340 F
->insert(It
, TrueMBB
);
341 F
->insert(It
, DoneMBB
);
343 // Transfer the remainder of BB and its successor edges to DoneMBB.
344 DoneMBB
->splice(DoneMBB
->begin(), BB
,
345 std::next(MachineBasicBlock::iterator(MI
)), BB
->end());
346 DoneMBB
->transferSuccessorsAndUpdatePHIs(BB
);
348 BB
->addSuccessor(TrueMBB
);
349 BB
->addSuccessor(FalseMBB
);
350 TrueMBB
->addSuccessor(DoneMBB
);
351 FalseMBB
->addSuccessor(DoneMBB
);
353 unsigned Tmp0
, Tmp1
, CmpReg
, EqzReg
, FalseReg
, TrueReg
;
354 Tmp0
= MRI
.createVirtualRegister(MRI
.getRegClass(InReg
));
355 Tmp1
= MRI
.createVirtualRegister(MRI
.getRegClass(InReg
));
356 CmpReg
= MRI
.createVirtualRegister(&WebAssembly::I32RegClass
);
357 EqzReg
= MRI
.createVirtualRegister(&WebAssembly::I32RegClass
);
358 FalseReg
= MRI
.createVirtualRegister(MRI
.getRegClass(OutReg
));
359 TrueReg
= MRI
.createVirtualRegister(MRI
.getRegClass(OutReg
));
361 MI
.eraseFromParent();
362 // For signed numbers, we can do a single comparison to determine whether
363 // fabs(x) is within range.
367 BuildMI(BB
, DL
, TII
.get(Abs
), Tmp0
).addReg(InReg
);
369 BuildMI(BB
, DL
, TII
.get(FConst
), Tmp1
)
370 .addFPImm(cast
<ConstantFP
>(ConstantFP::get(Ty
, CmpVal
)));
371 BuildMI(BB
, DL
, TII
.get(LT
), CmpReg
).addReg(Tmp0
).addReg(Tmp1
);
373 // For unsigned numbers, we have to do a separate comparison with zero.
375 Tmp1
= MRI
.createVirtualRegister(MRI
.getRegClass(InReg
));
376 unsigned SecondCmpReg
=
377 MRI
.createVirtualRegister(&WebAssembly::I32RegClass
);
378 unsigned AndReg
= MRI
.createVirtualRegister(&WebAssembly::I32RegClass
);
379 BuildMI(BB
, DL
, TII
.get(FConst
), Tmp1
)
380 .addFPImm(cast
<ConstantFP
>(ConstantFP::get(Ty
, 0.0)));
381 BuildMI(BB
, DL
, TII
.get(GE
), SecondCmpReg
).addReg(Tmp0
).addReg(Tmp1
);
382 BuildMI(BB
, DL
, TII
.get(And
), AndReg
).addReg(CmpReg
).addReg(SecondCmpReg
);
386 BuildMI(BB
, DL
, TII
.get(Eqz
), EqzReg
).addReg(CmpReg
);
388 // Create the CFG diamond to select between doing the conversion or using
389 // the substitute value.
390 BuildMI(BB
, DL
, TII
.get(WebAssembly::BR_IF
)).addMBB(TrueMBB
).addReg(EqzReg
);
391 BuildMI(FalseMBB
, DL
, TII
.get(LoweredOpcode
), FalseReg
).addReg(InReg
);
392 BuildMI(FalseMBB
, DL
, TII
.get(WebAssembly::BR
)).addMBB(DoneMBB
);
393 BuildMI(TrueMBB
, DL
, TII
.get(IConst
), TrueReg
).addImm(Substitute
);
394 BuildMI(*DoneMBB
, DoneMBB
->begin(), DL
, TII
.get(TargetOpcode::PHI
), OutReg
)
403 MachineBasicBlock
*WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
404 MachineInstr
&MI
, MachineBasicBlock
*BB
) const {
405 const TargetInstrInfo
&TII
= *Subtarget
->getInstrInfo();
406 DebugLoc DL
= MI
.getDebugLoc();
408 switch (MI
.getOpcode()) {
410 llvm_unreachable("Unexpected instr type to insert");
411 case WebAssembly::FP_TO_SINT_I32_F32
:
412 return LowerFPToInt(MI
, DL
, BB
, TII
, false, false, false,
413 WebAssembly::I32_TRUNC_S_F32
);
414 case WebAssembly::FP_TO_UINT_I32_F32
:
415 return LowerFPToInt(MI
, DL
, BB
, TII
, true, false, false,
416 WebAssembly::I32_TRUNC_U_F32
);
417 case WebAssembly::FP_TO_SINT_I64_F32
:
418 return LowerFPToInt(MI
, DL
, BB
, TII
, false, true, false,
419 WebAssembly::I64_TRUNC_S_F32
);
420 case WebAssembly::FP_TO_UINT_I64_F32
:
421 return LowerFPToInt(MI
, DL
, BB
, TII
, true, true, false,
422 WebAssembly::I64_TRUNC_U_F32
);
423 case WebAssembly::FP_TO_SINT_I32_F64
:
424 return LowerFPToInt(MI
, DL
, BB
, TII
, false, false, true,
425 WebAssembly::I32_TRUNC_S_F64
);
426 case WebAssembly::FP_TO_UINT_I32_F64
:
427 return LowerFPToInt(MI
, DL
, BB
, TII
, true, false, true,
428 WebAssembly::I32_TRUNC_U_F64
);
429 case WebAssembly::FP_TO_SINT_I64_F64
:
430 return LowerFPToInt(MI
, DL
, BB
, TII
, false, true, true,
431 WebAssembly::I64_TRUNC_S_F64
);
432 case WebAssembly::FP_TO_UINT_I64_F64
:
433 return LowerFPToInt(MI
, DL
, BB
, TII
, true, true, true,
434 WebAssembly::I64_TRUNC_U_F64
);
435 llvm_unreachable("Unexpected instruction to emit with custom inserter");
440 WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode
) const {
441 switch (static_cast<WebAssemblyISD::NodeType
>(Opcode
)) {
442 case WebAssemblyISD::FIRST_NUMBER
:
444 #define HANDLE_NODETYPE(NODE) \
445 case WebAssemblyISD::NODE: \
446 return "WebAssemblyISD::" #NODE;
447 #include "WebAssemblyISD.def"
448 #undef HANDLE_NODETYPE
453 std::pair
<unsigned, const TargetRegisterClass
*>
454 WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
455 const TargetRegisterInfo
*TRI
, StringRef Constraint
, MVT VT
) const {
456 // First, see if this is a constraint that directly corresponds to a
457 // WebAssembly register class.
458 if (Constraint
.size() == 1) {
459 switch (Constraint
[0]) {
461 assert(VT
!= MVT::iPTR
&& "Pointer MVT not expected here");
462 if (Subtarget
->hasSIMD128() && VT
.isVector()) {
463 if (VT
.getSizeInBits() == 128)
464 return std::make_pair(0U, &WebAssembly::V128RegClass
);
466 if (VT
.isInteger() && !VT
.isVector()) {
467 if (VT
.getSizeInBits() <= 32)
468 return std::make_pair(0U, &WebAssembly::I32RegClass
);
469 if (VT
.getSizeInBits() <= 64)
470 return std::make_pair(0U, &WebAssembly::I64RegClass
);
478 return TargetLowering::getRegForInlineAsmConstraint(TRI
, Constraint
, VT
);
481 bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
482 // Assume ctz is a relatively cheap operation.
486 bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
487 // Assume clz is a relatively cheap operation.
491 bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout
&DL
,
493 Type
*Ty
, unsigned AS
,
494 Instruction
*I
) const {
495 // WebAssembly offsets are added as unsigned without wrapping. The
496 // isLegalAddressingMode gives us no way to determine if wrapping could be
497 // happening, so we approximate this by accepting only non-negative offsets.
501 // WebAssembly has no scale register operands.
505 // Everything else is legal.
509 bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
510 EVT
/*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast
) const {
511 // WebAssembly supports unaligned accesses, though it should be declared
512 // with the p2align attribute on loads and stores which do so, and there
513 // may be a performance impact. We tell LLVM they're "fast" because
514 // for the kinds of things that LLVM uses this for (merging adjacent stores
515 // of constants, etc.), WebAssembly implementations will either want the
516 // unaligned access or they'll split anyway.
522 bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT
,
523 AttributeList Attr
) const {
524 // The current thinking is that wasm engines will perform this optimization,
525 // so we can save on code size.
529 EVT
WebAssemblyTargetLowering::getSetCCResultType(const DataLayout
&DL
,
533 return VT
.changeVectorElementTypeToInteger();
535 return TargetLowering::getSetCCResultType(DL
, C
, VT
);
538 bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo
&Info
,
541 unsigned Intrinsic
) const {
543 case Intrinsic::wasm_atomic_notify
:
544 Info
.opc
= ISD::INTRINSIC_W_CHAIN
;
545 Info
.memVT
= MVT::i32
;
546 Info
.ptrVal
= I
.getArgOperand(0);
549 // atomic.notify instruction does not really load the memory specified with
550 // this argument, but MachineMemOperand should either be load or store, so
551 // we set this to a load.
552 // FIXME Volatile isn't really correct, but currently all LLVM atomic
553 // instructions are treated as volatiles in the backend, so we should be
554 // consistent. The same applies for wasm_atomic_wait intrinsics too.
555 Info
.flags
= MachineMemOperand::MOVolatile
| MachineMemOperand::MOLoad
;
557 case Intrinsic::wasm_atomic_wait_i32
:
558 Info
.opc
= ISD::INTRINSIC_W_CHAIN
;
559 Info
.memVT
= MVT::i32
;
560 Info
.ptrVal
= I
.getArgOperand(0);
563 Info
.flags
= MachineMemOperand::MOVolatile
| MachineMemOperand::MOLoad
;
565 case Intrinsic::wasm_atomic_wait_i64
:
566 Info
.opc
= ISD::INTRINSIC_W_CHAIN
;
567 Info
.memVT
= MVT::i64
;
568 Info
.ptrVal
= I
.getArgOperand(0);
571 Info
.flags
= MachineMemOperand::MOVolatile
| MachineMemOperand::MOLoad
;
578 //===----------------------------------------------------------------------===//
579 // WebAssembly Lowering private implementation.
580 //===----------------------------------------------------------------------===//
582 //===----------------------------------------------------------------------===//
584 //===----------------------------------------------------------------------===//
586 static void fail(const SDLoc
&DL
, SelectionDAG
&DAG
, const char *Msg
) {
587 MachineFunction
&MF
= DAG
.getMachineFunction();
588 DAG
.getContext()->diagnose(
589 DiagnosticInfoUnsupported(MF
.getFunction(), Msg
, DL
.getDebugLoc()));
592 // Test whether the given calling convention is supported.
593 static bool callingConvSupported(CallingConv::ID CallConv
) {
594 // We currently support the language-independent target-independent
595 // conventions. We don't yet have a way to annotate calls with properties like
596 // "cold", and we don't have any call-clobbered registers, so these are mostly
597 // all handled the same.
598 return CallConv
== CallingConv::C
|| CallConv
== CallingConv::Fast
||
599 CallConv
== CallingConv::Cold
||
600 CallConv
== CallingConv::PreserveMost
||
601 CallConv
== CallingConv::PreserveAll
||
602 CallConv
== CallingConv::CXX_FAST_TLS
;
606 WebAssemblyTargetLowering::LowerCall(CallLoweringInfo
&CLI
,
607 SmallVectorImpl
<SDValue
> &InVals
) const {
608 SelectionDAG
&DAG
= CLI
.DAG
;
610 SDValue Chain
= CLI
.Chain
;
611 SDValue Callee
= CLI
.Callee
;
612 MachineFunction
&MF
= DAG
.getMachineFunction();
613 auto Layout
= MF
.getDataLayout();
615 CallingConv::ID CallConv
= CLI
.CallConv
;
616 if (!callingConvSupported(CallConv
))
618 "WebAssembly doesn't support language-specific or target-specific "
619 "calling conventions yet");
620 if (CLI
.IsPatchPoint
)
621 fail(DL
, DAG
, "WebAssembly doesn't support patch point yet");
623 // WebAssembly doesn't currently support explicit tail calls. If they are
624 // required, fail. Otherwise, just disable them.
625 if ((CallConv
== CallingConv::Fast
&& CLI
.IsTailCall
&&
626 MF
.getTarget().Options
.GuaranteedTailCallOpt
) ||
627 (CLI
.CS
&& CLI
.CS
.isMustTailCall()))
628 fail(DL
, DAG
, "WebAssembly doesn't support tail call yet");
629 CLI
.IsTailCall
= false;
631 SmallVectorImpl
<ISD::InputArg
> &Ins
= CLI
.Ins
;
633 fail(DL
, DAG
, "WebAssembly doesn't support more than 1 returned value yet");
635 SmallVectorImpl
<ISD::OutputArg
> &Outs
= CLI
.Outs
;
636 SmallVectorImpl
<SDValue
> &OutVals
= CLI
.OutVals
;
637 unsigned NumFixedArgs
= 0;
638 for (unsigned I
= 0; I
< Outs
.size(); ++I
) {
639 const ISD::OutputArg
&Out
= Outs
[I
];
640 SDValue
&OutVal
= OutVals
[I
];
641 if (Out
.Flags
.isNest())
642 fail(DL
, DAG
, "WebAssembly hasn't implemented nest arguments");
643 if (Out
.Flags
.isInAlloca())
644 fail(DL
, DAG
, "WebAssembly hasn't implemented inalloca arguments");
645 if (Out
.Flags
.isInConsecutiveRegs())
646 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs arguments");
647 if (Out
.Flags
.isInConsecutiveRegsLast())
648 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs last arguments");
649 if (Out
.Flags
.isByVal() && Out
.Flags
.getByValSize() != 0) {
650 auto &MFI
= MF
.getFrameInfo();
651 int FI
= MFI
.CreateStackObject(Out
.Flags
.getByValSize(),
652 Out
.Flags
.getByValAlign(),
655 DAG
.getConstant(Out
.Flags
.getByValSize(), DL
, MVT::i32
);
656 SDValue FINode
= DAG
.getFrameIndex(FI
, getPointerTy(Layout
));
657 Chain
= DAG
.getMemcpy(
658 Chain
, DL
, FINode
, OutVal
, SizeNode
, Out
.Flags
.getByValAlign(),
659 /*isVolatile*/ false, /*AlwaysInline=*/false,
660 /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
663 // Count the number of fixed args *after* legalization.
664 NumFixedArgs
+= Out
.IsFixed
;
667 bool IsVarArg
= CLI
.IsVarArg
;
668 auto PtrVT
= getPointerTy(Layout
);
670 // Analyze operands of the call, assigning locations to each operand.
671 SmallVector
<CCValAssign
, 16> ArgLocs
;
672 CCState
CCInfo(CallConv
, IsVarArg
, MF
, ArgLocs
, *DAG
.getContext());
675 // Outgoing non-fixed arguments are placed in a buffer. First
676 // compute their offsets and the total amount of buffer space needed.
678 make_range(OutVals
.begin() + NumFixedArgs
, OutVals
.end())) {
679 EVT VT
= Arg
.getValueType();
680 assert(VT
!= MVT::iPTR
&& "Legalized args should be concrete");
681 Type
*Ty
= VT
.getTypeForEVT(*DAG
.getContext());
682 unsigned Offset
= CCInfo
.AllocateStack(Layout
.getTypeAllocSize(Ty
),
683 Layout
.getABITypeAlignment(Ty
));
684 CCInfo
.addLoc(CCValAssign::getMem(ArgLocs
.size(), VT
.getSimpleVT(),
685 Offset
, VT
.getSimpleVT(),
690 unsigned NumBytes
= CCInfo
.getAlignedCallFrameSize();
693 if (IsVarArg
&& NumBytes
) {
694 // For non-fixed arguments, next emit stores to store the argument values
695 // to the stack buffer at the offsets computed above.
696 int FI
= MF
.getFrameInfo().CreateStackObject(NumBytes
,
697 Layout
.getStackAlignment(),
700 SmallVector
<SDValue
, 8> Chains
;
702 make_range(OutVals
.begin() + NumFixedArgs
, OutVals
.end())) {
703 assert(ArgLocs
[ValNo
].getValNo() == ValNo
&&
704 "ArgLocs should remain in order and only hold varargs args");
705 unsigned Offset
= ArgLocs
[ValNo
++].getLocMemOffset();
706 FINode
= DAG
.getFrameIndex(FI
, getPointerTy(Layout
));
707 SDValue Add
= DAG
.getNode(ISD::ADD
, DL
, PtrVT
, FINode
,
708 DAG
.getConstant(Offset
, DL
, PtrVT
));
710 DAG
.getStore(Chain
, DL
, Arg
, Add
,
711 MachinePointerInfo::getFixedStack(MF
, FI
, Offset
), 0));
714 Chain
= DAG
.getNode(ISD::TokenFactor
, DL
, MVT::Other
, Chains
);
715 } else if (IsVarArg
) {
716 FINode
= DAG
.getIntPtrConstant(0, DL
);
719 // Compute the operands for the CALLn node.
720 SmallVector
<SDValue
, 16> Ops
;
721 Ops
.push_back(Chain
);
722 Ops
.push_back(Callee
);
724 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
726 Ops
.append(OutVals
.begin(),
727 IsVarArg
? OutVals
.begin() + NumFixedArgs
: OutVals
.end());
728 // Add a pointer to the vararg buffer.
730 Ops
.push_back(FINode
);
732 SmallVector
<EVT
, 8> InTys
;
733 for (const auto &In
: Ins
) {
734 assert(!In
.Flags
.isByVal() && "byval is not valid for return values");
735 assert(!In
.Flags
.isNest() && "nest is not valid for return values");
736 if (In
.Flags
.isInAlloca())
737 fail(DL
, DAG
, "WebAssembly hasn't implemented inalloca return values");
738 if (In
.Flags
.isInConsecutiveRegs())
739 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs return values");
740 if (In
.Flags
.isInConsecutiveRegsLast())
742 "WebAssembly hasn't implemented cons regs last return values");
743 // Ignore In.getOrigAlign() because all our arguments are passed in
745 InTys
.push_back(In
.VT
);
747 InTys
.push_back(MVT::Other
);
748 SDVTList InTyList
= DAG
.getVTList(InTys
);
750 DAG
.getNode(Ins
.empty() ? WebAssemblyISD::CALL0
: WebAssemblyISD::CALL1
,
755 InVals
.push_back(Res
);
756 Chain
= Res
.getValue(1);
762 bool WebAssemblyTargetLowering::CanLowerReturn(
763 CallingConv::ID
/*CallConv*/, MachineFunction
& /*MF*/, bool /*IsVarArg*/,
764 const SmallVectorImpl
<ISD::OutputArg
> &Outs
,
765 LLVMContext
& /*Context*/) const {
766 // WebAssembly can't currently handle returning tuples.
767 return Outs
.size() <= 1;
770 SDValue
WebAssemblyTargetLowering::LowerReturn(
771 SDValue Chain
, CallingConv::ID CallConv
, bool /*IsVarArg*/,
772 const SmallVectorImpl
<ISD::OutputArg
> &Outs
,
773 const SmallVectorImpl
<SDValue
> &OutVals
, const SDLoc
&DL
,
774 SelectionDAG
&DAG
) const {
775 assert(Outs
.size() <= 1 && "WebAssembly can only return up to one value");
776 if (!callingConvSupported(CallConv
))
777 fail(DL
, DAG
, "WebAssembly doesn't support non-C calling conventions");
779 SmallVector
<SDValue
, 4> RetOps(1, Chain
);
780 RetOps
.append(OutVals
.begin(), OutVals
.end());
781 Chain
= DAG
.getNode(WebAssemblyISD::RETURN
, DL
, MVT::Other
, RetOps
);
783 // Record the number and types of the return values.
784 for (const ISD::OutputArg
&Out
: Outs
) {
785 assert(!Out
.Flags
.isByVal() && "byval is not valid for return values");
786 assert(!Out
.Flags
.isNest() && "nest is not valid for return values");
787 assert(Out
.IsFixed
&& "non-fixed return value is not valid");
788 if (Out
.Flags
.isInAlloca())
789 fail(DL
, DAG
, "WebAssembly hasn't implemented inalloca results");
790 if (Out
.Flags
.isInConsecutiveRegs())
791 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs results");
792 if (Out
.Flags
.isInConsecutiveRegsLast())
793 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs last results");
799 SDValue
WebAssemblyTargetLowering::LowerFormalArguments(
800 SDValue Chain
, CallingConv::ID CallConv
, bool IsVarArg
,
801 const SmallVectorImpl
<ISD::InputArg
> &Ins
, const SDLoc
&DL
,
802 SelectionDAG
&DAG
, SmallVectorImpl
<SDValue
> &InVals
) const {
803 if (!callingConvSupported(CallConv
))
804 fail(DL
, DAG
, "WebAssembly doesn't support non-C calling conventions");
806 MachineFunction
&MF
= DAG
.getMachineFunction();
807 auto *MFI
= MF
.getInfo
<WebAssemblyFunctionInfo
>();
809 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
810 // of the incoming values before they're represented by virtual registers.
811 MF
.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS
);
813 for (const ISD::InputArg
&In
: Ins
) {
814 if (In
.Flags
.isInAlloca())
815 fail(DL
, DAG
, "WebAssembly hasn't implemented inalloca arguments");
816 if (In
.Flags
.isNest())
817 fail(DL
, DAG
, "WebAssembly hasn't implemented nest arguments");
818 if (In
.Flags
.isInConsecutiveRegs())
819 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs arguments");
820 if (In
.Flags
.isInConsecutiveRegsLast())
821 fail(DL
, DAG
, "WebAssembly hasn't implemented cons regs last arguments");
822 // Ignore In.getOrigAlign() because all our arguments are passed in
824 InVals
.push_back(In
.Used
? DAG
.getNode(WebAssemblyISD::ARGUMENT
, DL
, In
.VT
,
825 DAG
.getTargetConstant(InVals
.size(),
827 : DAG
.getUNDEF(In
.VT
));
829 // Record the number and types of arguments.
830 MFI
->addParam(In
.VT
);
833 // Varargs are copied into a buffer allocated by the caller, and a pointer to
834 // the buffer is passed as an argument.
836 MVT PtrVT
= getPointerTy(MF
.getDataLayout());
837 unsigned VarargVreg
=
838 MF
.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT
));
839 MFI
->setVarargBufferVreg(VarargVreg
);
840 Chain
= DAG
.getCopyToReg(
841 Chain
, DL
, VarargVreg
,
842 DAG
.getNode(WebAssemblyISD::ARGUMENT
, DL
, PtrVT
,
843 DAG
.getTargetConstant(Ins
.size(), DL
, MVT::i32
)));
844 MFI
->addParam(PtrVT
);
847 // Record the number and types of arguments and results.
848 SmallVector
<MVT
, 4> Params
;
849 SmallVector
<MVT
, 4> Results
;
850 computeSignatureVTs(MF
.getFunction().getFunctionType(), MF
.getFunction(),
851 DAG
.getTarget(), Params
, Results
);
852 for (MVT VT
: Results
)
854 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
855 // the param logic here with ComputeSignatureVTs
856 assert(MFI
->getParams().size() == Params
.size() &&
857 std::equal(MFI
->getParams().begin(), MFI
->getParams().end(),
863 //===----------------------------------------------------------------------===//
864 // Custom lowering hooks.
865 //===----------------------------------------------------------------------===//
867 SDValue
WebAssemblyTargetLowering::LowerOperation(SDValue Op
,
868 SelectionDAG
&DAG
) const {
870 switch (Op
.getOpcode()) {
872 llvm_unreachable("unimplemented operation lowering");
874 case ISD::FrameIndex
:
875 return LowerFrameIndex(Op
, DAG
);
876 case ISD::GlobalAddress
:
877 return LowerGlobalAddress(Op
, DAG
);
878 case ISD::ExternalSymbol
:
879 return LowerExternalSymbol(Op
, DAG
);
881 return LowerJumpTable(Op
, DAG
);
883 return LowerBR_JT(Op
, DAG
);
885 return LowerVASTART(Op
, DAG
);
886 case ISD::BlockAddress
:
888 fail(DL
, DAG
, "WebAssembly hasn't implemented computed gotos");
890 case ISD::RETURNADDR
: // Probably nothing meaningful can be returned here.
891 fail(DL
, DAG
, "WebAssembly hasn't implemented __builtin_return_address");
894 return LowerFRAMEADDR(Op
, DAG
);
896 return LowerCopyToReg(Op
, DAG
);
897 case ISD::EXTRACT_VECTOR_ELT
:
898 case ISD::INSERT_VECTOR_ELT
:
899 return LowerAccessVectorElement(Op
, DAG
);
900 case ISD::INTRINSIC_VOID
:
901 case ISD::INTRINSIC_WO_CHAIN
:
902 case ISD::INTRINSIC_W_CHAIN
:
903 return LowerIntrinsic(Op
, DAG
);
904 case ISD::SIGN_EXTEND_INREG
:
905 return LowerSIGN_EXTEND_INREG(Op
, DAG
);
906 case ISD::BUILD_VECTOR
:
907 return LowerBUILD_VECTOR(Op
, DAG
);
908 case ISD::VECTOR_SHUFFLE
:
909 return LowerVECTOR_SHUFFLE(Op
, DAG
);
913 return LowerShift(Op
, DAG
);
917 SDValue
WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op
,
918 SelectionDAG
&DAG
) const {
919 SDValue Src
= Op
.getOperand(2);
920 if (isa
<FrameIndexSDNode
>(Src
.getNode())) {
921 // CopyToReg nodes don't support FrameIndex operands. Other targets select
922 // the FI to some LEA-like instruction, but since we don't have that, we
923 // need to insert some kind of instruction that can take an FI operand and
924 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
925 // local.copy between Op and its FI operand.
926 SDValue Chain
= Op
.getOperand(0);
928 unsigned Reg
= cast
<RegisterSDNode
>(Op
.getOperand(1))->getReg();
929 EVT VT
= Src
.getValueType();
930 SDValue
Copy(DAG
.getMachineNode(VT
== MVT::i32
? WebAssembly::COPY_I32
931 : WebAssembly::COPY_I64
,
934 return Op
.getNode()->getNumValues() == 1
935 ? DAG
.getCopyToReg(Chain
, DL
, Reg
, Copy
)
936 : DAG
.getCopyToReg(Chain
, DL
, Reg
, Copy
,
937 Op
.getNumOperands() == 4 ? Op
.getOperand(3)
943 SDValue
WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op
,
944 SelectionDAG
&DAG
) const {
945 int FI
= cast
<FrameIndexSDNode
>(Op
)->getIndex();
946 return DAG
.getTargetFrameIndex(FI
, Op
.getValueType());
949 SDValue
WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op
,
950 SelectionDAG
&DAG
) const {
951 // Non-zero depths are not supported by WebAssembly currently. Use the
952 // legalizer's default expansion, which is to return 0 (what this function is
953 // documented to do).
954 if (Op
.getConstantOperandVal(0) > 0)
957 DAG
.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
958 EVT VT
= Op
.getValueType();
960 Subtarget
->getRegisterInfo()->getFrameRegister(DAG
.getMachineFunction());
961 return DAG
.getCopyFromReg(DAG
.getEntryNode(), SDLoc(Op
), FP
, VT
);
964 SDValue
WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op
,
965 SelectionDAG
&DAG
) const {
967 const auto *GA
= cast
<GlobalAddressSDNode
>(Op
);
968 EVT VT
= Op
.getValueType();
969 assert(GA
->getTargetFlags() == 0 &&
970 "Unexpected target flags on generic GlobalAddressSDNode");
971 if (GA
->getAddressSpace() != 0)
972 fail(DL
, DAG
, "WebAssembly only expects the 0 address space");
974 WebAssemblyISD::Wrapper
, DL
, VT
,
975 DAG
.getTargetGlobalAddress(GA
->getGlobal(), DL
, VT
, GA
->getOffset()));
979 WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op
,
980 SelectionDAG
&DAG
) const {
982 const auto *ES
= cast
<ExternalSymbolSDNode
>(Op
);
983 EVT VT
= Op
.getValueType();
984 assert(ES
->getTargetFlags() == 0 &&
985 "Unexpected target flags on generic ExternalSymbolSDNode");
986 // Set the TargetFlags to 0x1 which indicates that this is a "function"
987 // symbol rather than a data symbol. We do this unconditionally even though
988 // we don't know anything about the symbol other than its name, because all
989 // external symbols used in target-independent SelectionDAG code are for
992 WebAssemblyISD::Wrapper
, DL
, VT
,
993 DAG
.getTargetExternalSymbol(ES
->getSymbol(), VT
,
994 WebAssemblyII::MO_SYMBOL_FUNCTION
));
997 SDValue
WebAssemblyTargetLowering::LowerJumpTable(SDValue Op
,
998 SelectionDAG
&DAG
) const {
999 // There's no need for a Wrapper node because we always incorporate a jump
1000 // table operand into a BR_TABLE instruction, rather than ever
1001 // materializing it in a register.
1002 const JumpTableSDNode
*JT
= cast
<JumpTableSDNode
>(Op
);
1003 return DAG
.getTargetJumpTable(JT
->getIndex(), Op
.getValueType(),
1004 JT
->getTargetFlags());
1007 SDValue
WebAssemblyTargetLowering::LowerBR_JT(SDValue Op
,
1008 SelectionDAG
&DAG
) const {
1010 SDValue Chain
= Op
.getOperand(0);
1011 const auto *JT
= cast
<JumpTableSDNode
>(Op
.getOperand(1));
1012 SDValue Index
= Op
.getOperand(2);
1013 assert(JT
->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
1015 SmallVector
<SDValue
, 8> Ops
;
1016 Ops
.push_back(Chain
);
1017 Ops
.push_back(Index
);
1019 MachineJumpTableInfo
*MJTI
= DAG
.getMachineFunction().getJumpTableInfo();
1020 const auto &MBBs
= MJTI
->getJumpTables()[JT
->getIndex()].MBBs
;
1022 // Add an operand for each case.
1023 for (auto MBB
: MBBs
)
1024 Ops
.push_back(DAG
.getBasicBlock(MBB
));
1026 // TODO: For now, we just pick something arbitrary for a default case for now.
1027 // We really want to sniff out the guard and put in the real default case (and
1028 // delete the guard).
1029 Ops
.push_back(DAG
.getBasicBlock(MBBs
[0]));
1031 return DAG
.getNode(WebAssemblyISD::BR_TABLE
, DL
, MVT::Other
, Ops
);
1034 SDValue
WebAssemblyTargetLowering::LowerVASTART(SDValue Op
,
1035 SelectionDAG
&DAG
) const {
1037 EVT PtrVT
= getPointerTy(DAG
.getMachineFunction().getDataLayout());
1039 auto *MFI
= DAG
.getMachineFunction().getInfo
<WebAssemblyFunctionInfo
>();
1040 const Value
*SV
= cast
<SrcValueSDNode
>(Op
.getOperand(2))->getValue();
1042 SDValue ArgN
= DAG
.getCopyFromReg(DAG
.getEntryNode(), DL
,
1043 MFI
->getVarargBufferVreg(), PtrVT
);
1044 return DAG
.getStore(Op
.getOperand(0), DL
, ArgN
, Op
.getOperand(1),
1045 MachinePointerInfo(SV
), 0);
1048 SDValue
WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op
,
1049 SelectionDAG
&DAG
) const {
1050 MachineFunction
&MF
= DAG
.getMachineFunction();
1052 switch (Op
.getOpcode()) {
1053 case ISD::INTRINSIC_VOID
:
1054 case ISD::INTRINSIC_W_CHAIN
:
1055 IntNo
= cast
<ConstantSDNode
>(Op
.getOperand(1))->getZExtValue();
1057 case ISD::INTRINSIC_WO_CHAIN
:
1058 IntNo
= cast
<ConstantSDNode
>(Op
.getOperand(0))->getZExtValue();
1061 llvm_unreachable("Invalid intrinsic");
1067 return SDValue(); // Don't custom lower most intrinsics.
1069 case Intrinsic::wasm_lsda
: {
1070 EVT VT
= Op
.getValueType();
1071 const TargetLowering
&TLI
= DAG
.getTargetLoweringInfo();
1072 MVT PtrVT
= TLI
.getPointerTy(DAG
.getDataLayout());
1073 auto &Context
= MF
.getMMI().getContext();
1074 MCSymbol
*S
= Context
.getOrCreateSymbol(Twine("GCC_except_table") +
1075 Twine(MF
.getFunctionNumber()));
1076 return DAG
.getNode(WebAssemblyISD::Wrapper
, DL
, VT
,
1077 DAG
.getMCSymbol(S
, PtrVT
));
1080 case Intrinsic::wasm_throw
: {
1081 // We only support C++ exceptions for now
1082 int Tag
= cast
<ConstantSDNode
>(Op
.getOperand(2).getNode())->getZExtValue();
1083 if (Tag
!= CPP_EXCEPTION
)
1084 llvm_unreachable("Invalid tag!");
1085 const TargetLowering
&TLI
= DAG
.getTargetLoweringInfo();
1086 MVT PtrVT
= TLI
.getPointerTy(DAG
.getDataLayout());
1087 const char *SymName
= MF
.createExternalSymbolName("__cpp_exception");
1089 DAG
.getNode(WebAssemblyISD::Wrapper
, DL
, PtrVT
,
1090 DAG
.getTargetExternalSymbol(
1091 SymName
, PtrVT
, WebAssemblyII::MO_SYMBOL_EVENT
));
1092 return DAG
.getNode(WebAssemblyISD::THROW
, DL
,
1093 MVT::Other
, // outchain type
1095 Op
.getOperand(0), // inchain
1096 SymNode
, // exception symbol
1097 Op
.getOperand(3) // thrown value
1104 WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op
,
1105 SelectionDAG
&DAG
) const {
1106 // If sign extension operations are disabled, allow sext_inreg only if operand
1107 // is a vector extract. SIMD does not depend on sign extension operations, but
1108 // allowing sext_inreg in this context lets us have simple patterns to select
1109 // extract_lane_s instructions. Expanding sext_inreg everywhere would be
1110 // simpler in this file, but would necessitate large and brittle patterns to
1111 // undo the expansion and select extract_lane_s instructions.
1112 assert(!Subtarget
->hasSignExt() && Subtarget
->hasSIMD128());
1113 if (Op
.getOperand(0).getOpcode() == ISD::EXTRACT_VECTOR_ELT
)
1119 SDValue
WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op
,
1120 SelectionDAG
&DAG
) const {
1122 const EVT VecT
= Op
.getValueType();
1123 const EVT LaneT
= Op
.getOperand(0).getValueType();
1124 const size_t Lanes
= Op
.getNumOperands();
1125 auto IsConstant
= [](const SDValue
&V
) {
1126 return V
.getOpcode() == ISD::Constant
|| V
.getOpcode() == ISD::ConstantFP
;
1129 // Find the most common operand, which is approximately the best to splat
1130 using Entry
= std::pair
<SDValue
, size_t>;
1131 SmallVector
<Entry
, 16> ValueCounts
;
1132 size_t NumConst
= 0, NumDynamic
= 0;
1133 for (const SDValue
&Lane
: Op
->op_values()) {
1134 if (Lane
.isUndef()) {
1136 } else if (IsConstant(Lane
)) {
1141 auto CountIt
= std::find_if(ValueCounts
.begin(), ValueCounts
.end(),
1142 [&Lane
](Entry A
) { return A
.first
== Lane
; });
1143 if (CountIt
== ValueCounts
.end()) {
1144 ValueCounts
.emplace_back(Lane
, 1);
1150 std::max_element(ValueCounts
.begin(), ValueCounts
.end(),
1151 [](Entry A
, Entry B
) { return A
.second
< B
.second
; });
1152 assert(CommonIt
!= ValueCounts
.end() && "Unexpected all-undef build_vector");
1153 SDValue SplatValue
= CommonIt
->first
;
1154 size_t NumCommon
= CommonIt
->second
;
1156 // If v128.const is available, consider using it instead of a splat
1157 if (Subtarget
->hasUnimplementedSIMD128()) {
1158 // {i32,i64,f32,f64}.const opcode, and value
1159 const size_t ConstBytes
= 1 + std::max(size_t(4), 16 / Lanes
);
1160 // SIMD prefix and opcode
1161 const size_t SplatBytes
= 2;
1162 const size_t SplatConstBytes
= SplatBytes
+ ConstBytes
;
1163 // SIMD prefix, opcode, and lane index
1164 const size_t ReplaceBytes
= 3;
1165 const size_t ReplaceConstBytes
= ReplaceBytes
+ ConstBytes
;
1166 // SIMD prefix, v128.const opcode, and 128-bit value
1167 const size_t VecConstBytes
= 18;
1168 // Initial v128.const and a replace_lane for each non-const operand
1169 const size_t ConstInitBytes
= VecConstBytes
+ NumDynamic
* ReplaceBytes
;
1170 // Initial splat and all necessary replace_lanes
1171 const size_t SplatInitBytes
=
1172 IsConstant(SplatValue
)
1173 // Initial constant splat
1174 ? (SplatConstBytes
+
1175 // Constant replace_lanes
1176 (NumConst
- NumCommon
) * ReplaceConstBytes
+
1177 // Dynamic replace_lanes
1178 (NumDynamic
* ReplaceBytes
))
1179 // Initial dynamic splat
1181 // Constant replace_lanes
1182 (NumConst
* ReplaceConstBytes
) +
1183 // Dynamic replace_lanes
1184 (NumDynamic
- NumCommon
) * ReplaceBytes
);
1185 if (ConstInitBytes
< SplatInitBytes
) {
1186 // Create build_vector that will lower to initial v128.const
1187 SmallVector
<SDValue
, 16> ConstLanes
;
1188 for (const SDValue
&Lane
: Op
->op_values()) {
1189 if (IsConstant(Lane
)) {
1190 ConstLanes
.push_back(Lane
);
1191 } else if (LaneT
.isFloatingPoint()) {
1192 ConstLanes
.push_back(DAG
.getConstantFP(0, DL
, LaneT
));
1194 ConstLanes
.push_back(DAG
.getConstant(0, DL
, LaneT
));
1197 SDValue Result
= DAG
.getBuildVector(VecT
, DL
, ConstLanes
);
1198 // Add replace_lane instructions for non-const lanes
1199 for (size_t I
= 0; I
< Lanes
; ++I
) {
1200 const SDValue
&Lane
= Op
->getOperand(I
);
1201 if (!Lane
.isUndef() && !IsConstant(Lane
))
1202 Result
= DAG
.getNode(ISD::INSERT_VECTOR_ELT
, DL
, VecT
, Result
, Lane
,
1203 DAG
.getConstant(I
, DL
, MVT::i32
));
1208 // Use a splat for the initial vector
1209 SDValue Result
= DAG
.getSplatBuildVector(VecT
, DL
, SplatValue
);
1210 // Add replace_lane instructions for other values
1211 for (size_t I
= 0; I
< Lanes
; ++I
) {
1212 const SDValue
&Lane
= Op
->getOperand(I
);
1213 if (Lane
!= SplatValue
)
1214 Result
= DAG
.getNode(ISD::INSERT_VECTOR_ELT
, DL
, VecT
, Result
, Lane
,
1215 DAG
.getConstant(I
, DL
, MVT::i32
));
1221 WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op
,
1222 SelectionDAG
&DAG
) const {
1224 ArrayRef
<int> Mask
= cast
<ShuffleVectorSDNode
>(Op
.getNode())->getMask();
1225 MVT VecType
= Op
.getOperand(0).getSimpleValueType();
1226 assert(VecType
.is128BitVector() && "Unexpected shuffle vector type");
1227 size_t LaneBytes
= VecType
.getVectorElementType().getSizeInBits() / 8;
1229 // Space for two vector args and sixteen mask indices
1232 Ops
[OpIdx
++] = Op
.getOperand(0);
1233 Ops
[OpIdx
++] = Op
.getOperand(1);
1235 // Expand mask indices to byte indices and materialize them as operands
1236 for (int M
: Mask
) {
1237 for (size_t J
= 0; J
< LaneBytes
; ++J
) {
1238 // Lower undefs (represented by -1 in mask) to zero
1239 uint64_t ByteIndex
= M
== -1 ? 0 : (uint64_t)M
* LaneBytes
+ J
;
1240 Ops
[OpIdx
++] = DAG
.getConstant(ByteIndex
, DL
, MVT::i32
);
1244 return DAG
.getNode(WebAssemblyISD::SHUFFLE
, DL
, Op
.getValueType(), Ops
);
1248 WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op
,
1249 SelectionDAG
&DAG
) const {
1250 // Allow constant lane indices, expand variable lane indices
1251 SDNode
*IdxNode
= Op
.getOperand(Op
.getNumOperands() - 1).getNode();
1252 if (isa
<ConstantSDNode
>(IdxNode
) || IdxNode
->isUndef())
1255 // Perform default expansion
1259 static SDValue
unrollVectorShift(SDValue Op
, SelectionDAG
&DAG
) {
1260 EVT LaneT
= Op
.getSimpleValueType().getVectorElementType();
1261 // 32-bit and 64-bit unrolled shifts will have proper semantics
1262 if (LaneT
.bitsGE(MVT::i32
))
1263 return DAG
.UnrollVectorOp(Op
.getNode());
1264 // Otherwise mask the shift value to get proper semantics from 32-bit shift
1266 SDValue ShiftVal
= Op
.getOperand(1);
1267 uint64_t MaskVal
= LaneT
.getSizeInBits() - 1;
1268 SDValue MaskedShiftVal
= DAG
.getNode(
1269 ISD::AND
, // mask opcode
1270 DL
, ShiftVal
.getValueType(), // masked value type
1271 ShiftVal
, // original shift value operand
1272 DAG
.getConstant(MaskVal
, DL
, ShiftVal
.getValueType()) // mask operand
1275 return DAG
.UnrollVectorOp(
1276 DAG
.getNode(Op
.getOpcode(), // original shift opcode
1277 DL
, Op
.getValueType(), // original return type
1278 Op
.getOperand(0), // original vector operand,
1279 MaskedShiftVal
// new masked shift value operand
1284 SDValue
WebAssemblyTargetLowering::LowerShift(SDValue Op
,
1285 SelectionDAG
&DAG
) const {
1288 // Only manually lower vector shifts
1289 assert(Op
.getSimpleValueType().isVector());
1291 // Expand all vector shifts until V8 fixes its implementation
1292 // TODO: remove this once V8 is fixed
1293 if (!Subtarget
->hasUnimplementedSIMD128())
1294 return unrollVectorShift(Op
, DAG
);
1296 // Unroll non-splat vector shifts
1297 BuildVectorSDNode
*ShiftVec
;
1299 if (!(ShiftVec
= dyn_cast
<BuildVectorSDNode
>(Op
.getOperand(1).getNode())) ||
1300 !(SplatVal
= ShiftVec
->getSplatValue()))
1301 return unrollVectorShift(Op
, DAG
);
1303 // All splats except i64x2 const splats are handled by patterns
1304 auto *SplatConst
= dyn_cast
<ConstantSDNode
>(SplatVal
);
1305 if (!SplatConst
|| Op
.getSimpleValueType() != MVT::v2i64
)
1308 // i64x2 const splats are custom lowered to avoid unnecessary wraps
1310 switch (Op
.getOpcode()) {
1312 Opcode
= WebAssemblyISD::VEC_SHL
;
1315 Opcode
= WebAssemblyISD::VEC_SHR_S
;
1318 Opcode
= WebAssemblyISD::VEC_SHR_U
;
1321 llvm_unreachable("unexpected opcode");
1323 APInt Shift
= SplatConst
->getAPIntValue().zextOrTrunc(32);
1324 return DAG
.getNode(Opcode
, DL
, Op
.getValueType(), Op
.getOperand(0),
1325 DAG
.getConstant(Shift
, DL
, MVT::i32
));
1328 //===----------------------------------------------------------------------===//
1329 // WebAssembly Optimization Hooks
1330 //===----------------------------------------------------------------------===//