Line data Source code
1 : //=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// This file implements the WebAssemblyTargetLowering class.
12 : ///
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "WebAssemblyISelLowering.h"
16 : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17 : #include "WebAssemblyMachineFunctionInfo.h"
18 : #include "WebAssemblySubtarget.h"
19 : #include "WebAssemblyTargetMachine.h"
20 : #include "llvm/CodeGen/Analysis.h"
21 : #include "llvm/CodeGen/CallingConvLower.h"
22 : #include "llvm/CodeGen/MachineInstrBuilder.h"
23 : #include "llvm/CodeGen/MachineJumpTableInfo.h"
24 : #include "llvm/CodeGen/MachineRegisterInfo.h"
25 : #include "llvm/CodeGen/SelectionDAG.h"
26 : #include "llvm/IR/DiagnosticInfo.h"
27 : #include "llvm/IR/DiagnosticPrinter.h"
28 : #include "llvm/IR/Function.h"
29 : #include "llvm/IR/Intrinsics.h"
30 : #include "llvm/Support/Debug.h"
31 : #include "llvm/Support/ErrorHandling.h"
32 : #include "llvm/Support/raw_ostream.h"
33 : #include "llvm/Target/TargetOptions.h"
34 : using namespace llvm;
35 :
36 : #define DEBUG_TYPE "wasm-lower"
37 :
38 : // Emit proposed instructions that may not have been implemented in engines
39 : cl::opt<bool> EnableUnimplementedWasmSIMDInstrs(
40 : "wasm-enable-unimplemented-simd",
41 : cl::desc("Emit potentially-unimplemented WebAssembly SIMD instructions"),
42 : cl::init(false));
43 :
44 293 : WebAssemblyTargetLowering::WebAssemblyTargetLowering(
45 293 : const TargetMachine &TM, const WebAssemblySubtarget &STI)
46 293 : : TargetLowering(TM), Subtarget(&STI) {
47 293 : auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
48 :
49 : // Booleans always contain 0 or 1.
50 : setBooleanContents(ZeroOrOneBooleanContent);
51 : // WebAssembly does not produce floating-point exceptions on normal floating
52 : // point operations.
53 : setHasFloatingPointExceptions(false);
54 : // We don't know the microarchitecture here, so just reduce register pressure.
55 : setSchedulingPreference(Sched::RegPressure);
56 : // Tell ISel that we have a stack pointer.
57 293 : setStackPointerRegisterToSaveRestore(
58 293 : Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
59 : // Set up the register classes.
60 : addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
61 : addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
62 : addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
63 : addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
64 293 : if (Subtarget->hasSIMD128()) {
65 : addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
66 : addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
67 : addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
68 : addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
69 23 : if (EnableUnimplementedWasmSIMDInstrs) {
70 : addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
71 : addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
72 : }
73 : }
74 : // Compute derived properties from the register classes.
75 586 : computeRegisterProperties(Subtarget->getRegisterInfo());
76 :
77 : setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
78 : setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
79 : setOperationAction(ISD::JumpTable, MVTPtr, Custom);
80 : setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
81 : setOperationAction(ISD::BRIND, MVT::Other, Custom);
82 :
83 : // Take the default expansion for va_arg, va_copy, and va_end. There is no
84 : // default action for va_start, so we do that custom.
85 : setOperationAction(ISD::VASTART, MVT::Other, Custom);
86 : setOperationAction(ISD::VAARG, MVT::Other, Expand);
87 : setOperationAction(ISD::VACOPY, MVT::Other, Expand);
88 : setOperationAction(ISD::VAEND, MVT::Other, Expand);
89 :
90 1465 : for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
91 : // Don't expand the floating-point types to constant pools.
92 1172 : setOperationAction(ISD::ConstantFP, T, Legal);
93 : // Expand floating-point comparisons.
94 18752 : for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
95 10548 : ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
96 : setCondCodeAction(CC, T, Expand);
97 : // Expand floating-point library function operators.
98 14064 : for (auto Op :
99 8204 : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
100 : setOperationAction(Op, T, Expand);
101 : // Note supported floating-point library function operators that otherwise
102 : // default to expand.
103 11720 : for (auto Op :
104 7032 : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
105 : setOperationAction(Op, T, Legal);
106 : // Support minnan and maxnan, which otherwise default to expand.
107 : setOperationAction(ISD::FMINNAN, T, Legal);
108 : setOperationAction(ISD::FMAXNAN, T, Legal);
109 : // WebAssembly currently has no builtin f16 support.
110 : setOperationAction(ISD::FP16_TO_FP, T, Expand);
111 : setOperationAction(ISD::FP_TO_FP16, T, Expand);
112 : setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
113 : setTruncStoreAction(T, MVT::f16, Expand);
114 : }
115 :
116 879 : for (auto T : {MVT::i32, MVT::i64}) {
117 : // Expand unavailable integer operations.
118 16408 : for (auto Op :
119 : {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
120 : ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
121 8790 : ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
122 : setOperationAction(Op, T, Expand);
123 : }
124 : }
125 :
126 : // There is no i64x2.mul instruction
127 : setOperationAction(ISD::MUL, MVT::v2i64, Expand);
128 :
129 : // We have custom shuffle lowering to expose the shuffle mask
130 293 : if (Subtarget->hasSIMD128()) {
131 115 : for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) {
132 : setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
133 : }
134 23 : if (EnableUnimplementedWasmSIMDInstrs) {
135 : setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i64, Custom);
136 : setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f64, Custom);
137 : }
138 : }
139 :
140 : // As a special case, these operators use the type to mean the type to
141 : // sign-extend from.
142 : setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
143 293 : if (!Subtarget->hasSignExt()) {
144 1068 : for (auto T : {MVT::i8, MVT::i16, MVT::i32})
145 : setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
146 : }
147 :
148 : // Dynamic stack allocation: use the default expansion.
149 : setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
150 : setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
151 : setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
152 :
153 : setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
154 : setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
155 :
156 : // Expand these forms; we pattern-match the forms that we can handle in isel.
157 1465 : for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
158 3516 : for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
159 : setOperationAction(Op, T, Expand);
160 :
161 : // We have custom switch handling.
162 : setOperationAction(ISD::BR_JT, MVT::Other, Custom);
163 :
164 : // WebAssembly doesn't have:
165 : // - Floating-point extending loads.
166 : // - Floating-point truncating stores.
167 : // - i1 extending loads.
168 : setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
169 : setTruncStoreAction(MVT::f64, MVT::f32, Expand);
170 2051 : for (auto T : MVT::integer_valuetypes())
171 7032 : for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
172 : setLoadExtAction(Ext, T, MVT::i1, Promote);
173 :
174 : // Trap lowers to wasm unreachable
175 : setOperationAction(ISD::TRAP, MVT::Other, Legal);
176 :
177 : // Exception handling intrinsics
178 : setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
179 :
180 : setMaxAtomicSizeInBitsSupported(64);
181 293 : }
182 :
183 : TargetLowering::AtomicExpansionKind
184 260 : WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
185 : // We have wasm instructions for these
186 : switch (AI->getOperation()) {
187 : case AtomicRMWInst::Add:
188 : case AtomicRMWInst::Sub:
189 : case AtomicRMWInst::And:
190 : case AtomicRMWInst::Or:
191 : case AtomicRMWInst::Xor:
192 : case AtomicRMWInst::Xchg:
193 : return AtomicExpansionKind::None;
194 : default:
195 : break;
196 : }
197 : return AtomicExpansionKind::CmpXChg;
198 : }
199 :
200 478 : FastISel *WebAssemblyTargetLowering::createFastISel(
201 : FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
202 478 : return WebAssembly::createFastISel(FuncInfo, LibInfo);
203 : }
204 :
205 228 : bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
206 : const GlobalAddressSDNode * /*GA*/) const {
207 : // All offsets can be folded.
208 228 : return true;
209 : }
210 :
211 2011 : MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
212 : EVT VT) const {
213 2011 : unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
214 2011 : if (BitWidth > 1 && BitWidth < 8)
215 : BitWidth = 8;
216 :
217 2010 : if (BitWidth > 64) {
218 : // The shift will be lowered to a libcall, and compiler-rt libcalls expect
219 : // the count to be an i32.
220 : BitWidth = 32;
221 : assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
222 : "32-bit shift counts ought to be enough for anyone");
223 : }
224 :
225 2011 : MVT Result = MVT::getIntegerVT(BitWidth);
226 : assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
227 : "Unable to represent scalar shift amount type");
228 2011 : return Result;
229 : }
230 :
231 : // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
232 : // undefined result on invalid/overflow, to the WebAssembly opcode, which
233 : // traps on invalid/overflow.
234 24 : static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
235 : MachineBasicBlock *BB,
236 : const TargetInstrInfo &TII,
237 : bool IsUnsigned, bool Int64,
238 : bool Float64, unsigned LoweredOpcode) {
239 24 : MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
240 :
241 24 : unsigned OutReg = MI.getOperand(0).getReg();
242 24 : unsigned InReg = MI.getOperand(1).getReg();
243 :
244 24 : unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
245 24 : unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
246 24 : unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
247 24 : unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
248 24 : unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
249 : unsigned Eqz = WebAssembly::EQZ_I32;
250 : unsigned And = WebAssembly::AND_I32;
251 24 : int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
252 24 : int64_t Substitute = IsUnsigned ? 0 : Limit;
253 24 : double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
254 24 : auto &Context = BB->getParent()->getFunction().getContext();
255 24 : Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
256 :
257 24 : const BasicBlock *LLVM_BB = BB->getBasicBlock();
258 24 : MachineFunction *F = BB->getParent();
259 24 : MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVM_BB);
260 24 : MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
261 24 : MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVM_BB);
262 :
263 24 : MachineFunction::iterator It = ++BB->getIterator();
264 : F->insert(It, FalseMBB);
265 : F->insert(It, TrueMBB);
266 : F->insert(It, DoneMBB);
267 :
268 : // Transfer the remainder of BB and its successor edges to DoneMBB.
269 24 : DoneMBB->splice(DoneMBB->begin(), BB,
270 : std::next(MachineBasicBlock::iterator(MI)), BB->end());
271 24 : DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
272 :
273 24 : BB->addSuccessor(TrueMBB);
274 24 : BB->addSuccessor(FalseMBB);
275 24 : TrueMBB->addSuccessor(DoneMBB);
276 24 : FalseMBB->addSuccessor(DoneMBB);
277 :
278 : unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
279 24 : Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
280 24 : Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
281 24 : CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
282 24 : EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
283 24 : FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
284 24 : TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
285 :
286 24 : MI.eraseFromParent();
287 : // For signed numbers, we can do a single comparison to determine whether
288 : // fabs(x) is within range.
289 24 : if (IsUnsigned) {
290 : Tmp0 = InReg;
291 : } else {
292 12 : BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
293 : }
294 24 : BuildMI(BB, DL, TII.get(FConst), Tmp1)
295 24 : .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
296 24 : BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
297 :
298 : // For unsigned numbers, we have to do a separate comparison with zero.
299 24 : if (IsUnsigned) {
300 12 : Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
301 : unsigned SecondCmpReg =
302 12 : MRI.createVirtualRegister(&WebAssembly::I32RegClass);
303 12 : unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
304 12 : BuildMI(BB, DL, TII.get(FConst), Tmp1)
305 12 : .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
306 12 : BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
307 12 : BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
308 : CmpReg = AndReg;
309 : }
310 :
311 24 : BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
312 :
313 : // Create the CFG diamond to select between doing the conversion or using
314 : // the substitute value.
315 24 : BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
316 24 : BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
317 24 : BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
318 24 : BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
319 48 : BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
320 24 : .addReg(FalseReg)
321 : .addMBB(FalseMBB)
322 24 : .addReg(TrueReg)
323 : .addMBB(TrueMBB);
324 :
325 24 : return DoneMBB;
326 : }
327 :
328 24 : MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
329 : MachineInstr &MI, MachineBasicBlock *BB) const {
330 24 : const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
331 : DebugLoc DL = MI.getDebugLoc();
332 :
333 48 : switch (MI.getOpcode()) {
334 0 : default:
335 0 : llvm_unreachable("Unexpected instr type to insert");
336 : case WebAssembly::FP_TO_SINT_I32_F32:
337 10 : return LowerFPToInt(MI, DL, BB, TII, false, false, false,
338 : WebAssembly::I32_TRUNC_S_F32);
339 : case WebAssembly::FP_TO_UINT_I32_F32:
340 10 : return LowerFPToInt(MI, DL, BB, TII, true, false, false,
341 : WebAssembly::I32_TRUNC_U_F32);
342 : case WebAssembly::FP_TO_SINT_I64_F32:
343 2 : return LowerFPToInt(MI, DL, BB, TII, false, true, false,
344 : WebAssembly::I64_TRUNC_S_F32);
345 : case WebAssembly::FP_TO_UINT_I64_F32:
346 2 : return LowerFPToInt(MI, DL, BB, TII, true, true, false,
347 : WebAssembly::I64_TRUNC_U_F32);
348 : case WebAssembly::FP_TO_SINT_I32_F64:
349 2 : return LowerFPToInt(MI, DL, BB, TII, false, false, true,
350 : WebAssembly::I32_TRUNC_S_F64);
351 : case WebAssembly::FP_TO_UINT_I32_F64:
352 2 : return LowerFPToInt(MI, DL, BB, TII, true, false, true,
353 : WebAssembly::I32_TRUNC_U_F64);
354 : case WebAssembly::FP_TO_SINT_I64_F64:
355 10 : return LowerFPToInt(MI, DL, BB, TII, false, true, true,
356 : WebAssembly::I64_TRUNC_S_F64);
357 : case WebAssembly::FP_TO_UINT_I64_F64:
358 10 : return LowerFPToInt(MI, DL, BB, TII, true, true, true,
359 : WebAssembly::I64_TRUNC_U_F64);
360 : llvm_unreachable("Unexpected instruction to emit with custom inserter");
361 : }
362 : }
363 :
364 : const char *
365 4 : WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
366 4 : switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
367 : case WebAssemblyISD::FIRST_NUMBER:
368 : break;
369 : #define HANDLE_NODETYPE(NODE) \
370 : case WebAssemblyISD::NODE: \
371 : return "WebAssemblyISD::" #NODE;
372 : #include "WebAssemblyISD.def"
373 : #undef HANDLE_NODETYPE
374 : }
375 0 : return nullptr;
376 : }
377 :
378 : std::pair<unsigned, const TargetRegisterClass *>
379 28 : WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
380 : const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
381 : // First, see if this is a constraint that directly corresponds to a
382 : // WebAssembly register class.
383 28 : if (Constraint.size() == 1) {
384 28 : switch (Constraint[0]) {
385 14 : case 'r':
386 : assert(VT != MVT::iPTR && "Pointer MVT not expected here");
387 14 : if (Subtarget->hasSIMD128() && VT.isVector()) {
388 0 : if (VT.getSizeInBits() == 128)
389 0 : return std::make_pair(0U, &WebAssembly::V128RegClass);
390 : }
391 28 : if (VT.isInteger() && !VT.isVector()) {
392 14 : if (VT.getSizeInBits() <= 32)
393 12 : return std::make_pair(0U, &WebAssembly::I32RegClass);
394 2 : if (VT.getSizeInBits() <= 64)
395 2 : return std::make_pair(0U, &WebAssembly::I64RegClass);
396 : }
397 : break;
398 : default:
399 : break;
400 : }
401 : }
402 :
403 14 : return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
404 : }
405 :
406 3 : bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
407 : // Assume ctz is a relatively cheap operation.
408 3 : return true;
409 : }
410 :
411 3 : bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
412 : // Assume clz is a relatively cheap operation.
413 3 : return true;
414 : }
415 :
416 2313 : bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
417 : const AddrMode &AM,
418 : Type *Ty, unsigned AS,
419 : Instruction *I) const {
420 : // WebAssembly offsets are added as unsigned without wrapping. The
421 : // isLegalAddressingMode gives us no way to determine if wrapping could be
422 : // happening, so we approximate this by accepting only non-negative offsets.
423 2313 : if (AM.BaseOffs < 0)
424 : return false;
425 :
426 : // WebAssembly has no scale register operands.
427 2235 : if (AM.Scale != 0)
428 184 : return false;
429 :
430 : // Everything else is legal.
431 : return true;
432 : }
433 :
434 74 : bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
435 : EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast) const {
436 : // WebAssembly supports unaligned accesses, though it should be declared
437 : // with the p2align attribute on loads and stores which do so, and there
438 : // may be a performance impact. We tell LLVM they're "fast" because
439 : // for the kinds of things that LLVM uses this for (merging adjacent stores
440 : // of constants, etc.), WebAssembly implementations will either want the
441 : // unaligned access or they'll split anyway.
442 74 : if (Fast)
443 3 : *Fast = true;
444 74 : return true;
445 : }
446 :
447 25 : bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
448 : AttributeList Attr) const {
449 : // The current thinking is that wasm engines will perform this optimization,
450 : // so we can save on code size.
451 25 : return true;
452 : }
453 :
454 1890 : EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
455 : LLVMContext &C,
456 : EVT VT) const {
457 1890 : if (VT.isVector())
458 116 : return VT.changeVectorElementTypeToInteger();
459 :
460 1774 : return TargetLowering::getSetCCResultType(DL, C, VT);
461 : }
462 :
463 105 : bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
464 : const CallInst &I,
465 : MachineFunction &MF,
466 : unsigned Intrinsic) const {
467 105 : switch (Intrinsic) {
468 8 : case Intrinsic::wasm_atomic_notify:
469 8 : Info.opc = ISD::INTRINSIC_W_CHAIN;
470 8 : Info.memVT = MVT::i32;
471 8 : Info.ptrVal = I.getArgOperand(0);
472 8 : Info.offset = 0;
473 8 : Info.align = 4;
474 : // atomic.notify instruction does not really load the memory specified with
475 : // this argument, but MachineMemOperand should either be load or store, so
476 : // we set this to a load.
477 : // FIXME Volatile isn't really correct, but currently all LLVM atomic
478 : // instructions are treated as volatiles in the backend, so we should be
479 : // consistent. The same applies for wasm_atomic_wait intrinsics too.
480 8 : Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
481 8 : return true;
482 8 : case Intrinsic::wasm_atomic_wait_i32:
483 8 : Info.opc = ISD::INTRINSIC_W_CHAIN;
484 8 : Info.memVT = MVT::i32;
485 8 : Info.ptrVal = I.getArgOperand(0);
486 8 : Info.offset = 0;
487 8 : Info.align = 4;
488 8 : Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
489 8 : return true;
490 6 : case Intrinsic::wasm_atomic_wait_i64:
491 6 : Info.opc = ISD::INTRINSIC_W_CHAIN;
492 6 : Info.memVT = MVT::i64;
493 6 : Info.ptrVal = I.getArgOperand(0);
494 6 : Info.offset = 0;
495 6 : Info.align = 8;
496 6 : Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
497 6 : return true;
498 : default:
499 : return false;
500 : }
501 : }
502 :
503 : //===----------------------------------------------------------------------===//
504 : // WebAssembly Lowering private implementation.
505 : //===----------------------------------------------------------------------===//
506 :
507 : //===----------------------------------------------------------------------===//
508 : // Lowering Code
509 : //===----------------------------------------------------------------------===//
510 :
511 1 : static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *msg) {
512 1 : MachineFunction &MF = DAG.getMachineFunction();
513 2 : DAG.getContext()->diagnose(
514 2 : DiagnosticInfoUnsupported(MF.getFunction(), msg, DL.getDebugLoc()));
515 1 : }
516 :
517 : // Test whether the given calling convention is supported.
518 : static bool CallingConvSupported(CallingConv::ID CallConv) {
519 : // We currently support the language-independent target-independent
520 : // conventions. We don't yet have a way to annotate calls with properties like
521 : // "cold", and we don't have any call-clobbered registers, so these are mostly
522 : // all handled the same.
523 5781 : return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
524 2 : CallConv == CallingConv::Cold ||
525 1 : CallConv == CallingConv::PreserveMost ||
526 5781 : CallConv == CallingConv::PreserveAll ||
527 0 : CallConv == CallingConv::CXX_FAST_TLS;
528 : }
529 :
530 : SDValue
531 520 : WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
532 : SmallVectorImpl<SDValue> &InVals) const {
533 520 : SelectionDAG &DAG = CLI.DAG;
534 : SDLoc DL = CLI.DL;
535 520 : SDValue Chain = CLI.Chain;
536 520 : SDValue Callee = CLI.Callee;
537 520 : MachineFunction &MF = DAG.getMachineFunction();
538 1040 : auto Layout = MF.getDataLayout();
539 :
540 520 : CallingConv::ID CallConv = CLI.CallConv;
541 : if (!CallingConvSupported(CallConv))
542 0 : fail(DL, DAG,
543 : "WebAssembly doesn't support language-specific or target-specific "
544 : "calling conventions yet");
545 520 : if (CLI.IsPatchPoint)
546 0 : fail(DL, DAG, "WebAssembly doesn't support patch point yet");
547 :
548 : // WebAssembly doesn't currently support explicit tail calls. If they are
549 : // required, fail. Otherwise, just disable them.
550 1 : if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
551 521 : MF.getTarget().Options.GuaranteedTailCallOpt) ||
552 : (CLI.CS && CLI.CS.isMustTailCall()))
553 0 : fail(DL, DAG, "WebAssembly doesn't support tail call yet");
554 520 : CLI.IsTailCall = false;
555 :
556 : SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
557 520 : if (Ins.size() > 1)
558 0 : fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
559 :
560 : SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
561 : SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
562 : unsigned NumFixedArgs = 0;
563 1253 : for (unsigned i = 0; i < Outs.size(); ++i) {
564 : const ISD::OutputArg &Out = Outs[i];
565 : SDValue &OutVal = OutVals[i];
566 733 : if (Out.Flags.isNest())
567 0 : fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
568 733 : if (Out.Flags.isInAlloca())
569 0 : fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
570 733 : if (Out.Flags.isInConsecutiveRegs())
571 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
572 733 : if (Out.Flags.isInConsecutiveRegsLast())
573 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
574 733 : if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
575 8 : auto &MFI = MF.getFrameInfo();
576 8 : int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
577 : Out.Flags.getByValAlign(),
578 : /*isSS=*/false);
579 : SDValue SizeNode =
580 8 : DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
581 8 : SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
582 8 : Chain = DAG.getMemcpy(
583 : Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
584 : /*isVolatile*/ false, /*AlwaysInline=*/false,
585 8 : /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
586 8 : OutVal = FINode;
587 : }
588 : // Count the number of fixed args *after* legalization.
589 733 : NumFixedArgs += Out.IsFixed;
590 : }
591 :
592 520 : bool IsVarArg = CLI.IsVarArg;
593 : auto PtrVT = getPointerTy(Layout);
594 :
595 : // Analyze operands of the call, assigning locations to each operand.
596 : SmallVector<CCValAssign, 16> ArgLocs;
597 1040 : CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
598 :
599 520 : if (IsVarArg) {
600 : // Outgoing non-fixed arguments are placed in a buffer. First
601 : // compute their offsets and the total amount of buffer space needed.
602 13 : for (SDValue Arg :
603 24 : make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
604 13 : EVT VT = Arg.getValueType();
605 : assert(VT != MVT::iPTR && "Legalized args should be concrete");
606 13 : Type *Ty = VT.getTypeForEVT(*DAG.getContext());
607 13 : unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty),
608 : Layout.getABITypeAlignment(Ty));
609 13 : CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
610 : Offset, VT.getSimpleVT(),
611 13 : CCValAssign::Full));
612 : }
613 : }
614 :
615 520 : unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
616 :
617 520 : SDValue FINode;
618 520 : if (IsVarArg && NumBytes) {
619 : // For non-fixed arguments, next emit stores to store the argument values
620 : // to the stack buffer at the offsets computed above.
621 8 : int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
622 : Layout.getStackAlignment(),
623 : /*isSS=*/false);
624 : unsigned ValNo = 0;
625 : SmallVector<SDValue, 8> Chains;
626 26 : for (SDValue Arg :
627 21 : make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
628 : assert(ArgLocs[ValNo].getValNo() == ValNo &&
629 : "ArgLocs should remain in order and only hold varargs args");
630 26 : unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
631 13 : FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
632 : SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
633 13 : DAG.getConstant(Offset, DL, PtrVT));
634 13 : Chains.push_back(
635 13 : DAG.getStore(Chain, DL, Arg, Add,
636 26 : MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
637 : }
638 8 : if (!Chains.empty())
639 8 : Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
640 512 : } else if (IsVarArg) {
641 3 : FINode = DAG.getIntPtrConstant(0, DL);
642 : }
643 :
644 : // Compute the operands for the CALLn node.
645 : SmallVector<SDValue, 16> Ops;
646 520 : Ops.push_back(Chain);
647 520 : Ops.push_back(Callee);
648 :
649 : // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
650 : // isn't reliable.
651 1040 : Ops.append(OutVals.begin(),
652 11 : IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
653 : // Add a pointer to the vararg buffer.
654 520 : if (IsVarArg)
655 11 : Ops.push_back(FINode);
656 :
657 : SmallVector<EVT, 8> InTys;
658 730 : for (const auto &In : Ins) {
659 : assert(!In.Flags.isByVal() && "byval is not valid for return values");
660 : assert(!In.Flags.isNest() && "nest is not valid for return values");
661 210 : if (In.Flags.isInAlloca())
662 0 : fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
663 210 : if (In.Flags.isInConsecutiveRegs())
664 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
665 210 : if (In.Flags.isInConsecutiveRegsLast())
666 0 : fail(DL, DAG,
667 : "WebAssembly hasn't implemented cons regs last return values");
668 : // Ignore In.getOrigAlign() because all our arguments are passed in
669 : // registers.
670 210 : InTys.push_back(In.VT);
671 : }
672 520 : InTys.push_back(MVT::Other);
673 520 : SDVTList InTyList = DAG.getVTList(InTys);
674 : SDValue Res =
675 520 : DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
676 730 : DL, InTyList, Ops);
677 520 : if (Ins.empty()) {
678 310 : Chain = Res;
679 : } else {
680 210 : InVals.push_back(Res);
681 210 : Chain = Res.getValue(1);
682 : }
683 :
684 520 : return Chain;
685 : }
686 :
687 3515 : bool WebAssemblyTargetLowering::CanLowerReturn(
688 : CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
689 : const SmallVectorImpl<ISD::OutputArg> &Outs,
690 : LLVMContext & /*Context*/) const {
691 : // WebAssembly can't currently handle returning tuples.
692 3515 : return Outs.size() <= 1;
693 : }
694 :
695 2633 : SDValue WebAssemblyTargetLowering::LowerReturn(
696 : SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
697 : const SmallVectorImpl<ISD::OutputArg> &Outs,
698 : const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
699 : SelectionDAG &DAG) const {
700 : assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
701 : if (!CallingConvSupported(CallConv))
702 0 : fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
703 :
704 : SmallVector<SDValue, 4> RetOps(1, Chain);
705 2633 : RetOps.append(OutVals.begin(), OutVals.end());
706 2633 : Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
707 :
708 : // Record the number and types of the return values.
709 4195 : for (const ISD::OutputArg &Out : Outs) {
710 : assert(!Out.Flags.isByVal() && "byval is not valid for return values");
711 : assert(!Out.Flags.isNest() && "nest is not valid for return values");
712 : assert(Out.IsFixed && "non-fixed return value is not valid");
713 1562 : if (Out.Flags.isInAlloca())
714 0 : fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
715 1562 : if (Out.Flags.isInConsecutiveRegs())
716 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
717 1562 : if (Out.Flags.isInConsecutiveRegsLast())
718 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
719 : }
720 :
721 2633 : return Chain;
722 : }
723 :
724 2628 : SDValue WebAssemblyTargetLowering::LowerFormalArguments(
725 : SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
726 : const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
727 : SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
728 : if (!CallingConvSupported(CallConv))
729 0 : fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
730 :
731 2628 : MachineFunction &MF = DAG.getMachineFunction();
732 : auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
733 :
734 : // Set up the incoming ARGUMENTS value, which serves to represent the liveness
735 : // of the incoming values before they're represented by virtual registers.
736 2628 : MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
737 :
738 9356 : for (const ISD::InputArg &In : Ins) {
739 6728 : if (In.Flags.isInAlloca())
740 0 : fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
741 6728 : if (In.Flags.isNest())
742 0 : fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
743 6728 : if (In.Flags.isInConsecutiveRegs())
744 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
745 6728 : if (In.Flags.isInConsecutiveRegsLast())
746 0 : fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
747 : // Ignore In.getOrigAlign() because all our arguments are passed in
748 : // registers.
749 13456 : InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
750 : DAG.getTargetConstant(InVals.size(),
751 6647 : DL, MVT::i32))
752 6809 : : DAG.getUNDEF(In.VT));
753 :
754 : // Record the number and types of arguments.
755 6728 : MFI->addParam(In.VT);
756 : }
757 :
758 : // Varargs are copied into a buffer allocated by the caller, and a pointer to
759 : // the buffer is passed as an argument.
760 2628 : if (IsVarArg) {
761 6 : MVT PtrVT = getPointerTy(MF.getDataLayout());
762 : unsigned VarargVreg =
763 12 : MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
764 : MFI->setVarargBufferVreg(VarargVreg);
765 6 : Chain = DAG.getCopyToReg(
766 : Chain, DL, VarargVreg,
767 : DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
768 6 : DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
769 6 : MFI->addParam(PtrVT);
770 : }
771 :
772 : // Record the number and types of arguments and results.
773 : SmallVector<MVT, 4> Params;
774 : SmallVector<MVT, 4> Results;
775 5256 : ComputeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
776 : DAG.getTarget(), Params, Results);
777 4196 : for (MVT VT : Results)
778 1568 : MFI->addResult(VT);
779 : // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
780 : // the param logic here with ComputeSignatureVTs
781 : assert(MFI->getParams().size() == Params.size() &&
782 : std::equal(MFI->getParams().begin(), MFI->getParams().end(),
783 : Params.begin()));
784 :
785 2628 : return Chain;
786 : }
787 :
788 : //===----------------------------------------------------------------------===//
789 : // Custom lowering hooks.
790 : //===----------------------------------------------------------------------===//
791 :
792 4950 : SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
793 : SelectionDAG &DAG) const {
794 : SDLoc DL(Op);
795 4950 : switch (Op.getOpcode()) {
796 0 : default:
797 0 : llvm_unreachable("unimplemented operation lowering");
798 : return SDValue();
799 176 : case ISD::FrameIndex:
800 176 : return LowerFrameIndex(Op, DAG);
801 746 : case ISD::GlobalAddress:
802 746 : return LowerGlobalAddress(Op, DAG);
803 57 : case ISD::ExternalSymbol:
804 57 : return LowerExternalSymbol(Op, DAG);
805 0 : case ISD::JumpTable:
806 0 : return LowerJumpTable(Op, DAG);
807 2 : case ISD::BR_JT:
808 2 : return LowerBR_JT(Op, DAG);
809 2 : case ISD::VASTART:
810 2 : return LowerVASTART(Op, DAG);
811 0 : case ISD::BlockAddress:
812 : case ISD::BRIND:
813 0 : fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
814 0 : return SDValue();
815 1 : case ISD::RETURNADDR: // Probably nothing meaningful can be returned here.
816 1 : fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address");
817 1 : return SDValue();
818 4 : case ISD::FRAMEADDR:
819 4 : return LowerFRAMEADDR(Op, DAG);
820 3828 : case ISD::CopyToReg:
821 3828 : return LowerCopyToReg(Op, DAG);
822 124 : case ISD::INTRINSIC_WO_CHAIN:
823 124 : return LowerINTRINSIC_WO_CHAIN(Op, DAG);
824 10 : case ISD::VECTOR_SHUFFLE:
825 10 : return LowerVECTOR_SHUFFLE(Op, DAG);
826 : }
827 : }
828 :
829 3828 : SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
830 : SelectionDAG &DAG) const {
831 3828 : SDValue Src = Op.getOperand(2);
832 : if (isa<FrameIndexSDNode>(Src.getNode())) {
833 : // CopyToReg nodes don't support FrameIndex operands. Other targets select
834 : // the FI to some LEA-like instruction, but since we don't have that, we
835 : // need to insert some kind of instruction that can take an FI operand and
836 : // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
837 : // copy_local between Op and its FI operand.
838 2 : SDValue Chain = Op.getOperand(0);
839 : SDLoc DL(Op);
840 2 : unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
841 2 : EVT VT = Src.getValueType();
842 2 : SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
843 : : WebAssembly::COPY_I64,
844 : DL, VT, Src),
845 : 0);
846 2 : return Op.getNode()->getNumValues() == 1
847 1 : ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
848 : : DAG.getCopyToReg(Chain, DL, Reg, Copy,
849 : Op.getNumOperands() == 4 ? Op.getOperand(3)
850 2 : : SDValue());
851 : }
852 3826 : return SDValue();
853 : }
854 :
855 176 : SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
856 : SelectionDAG &DAG) const {
857 176 : int FI = cast<FrameIndexSDNode>(Op)->getIndex();
858 176 : return DAG.getTargetFrameIndex(FI, Op.getValueType());
859 : }
860 :
861 4 : SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
862 : SelectionDAG &DAG) const {
863 : // Non-zero depths are not supported by WebAssembly currently. Use the
864 : // legalizer's default expansion, which is to return 0 (what this function is
865 : // documented to do).
866 4 : if (Op.getConstantOperandVal(0) > 0)
867 1 : return SDValue();
868 :
869 3 : DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
870 3 : EVT VT = Op.getValueType();
871 : unsigned FP =
872 6 : Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
873 6 : return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
874 : }
875 :
876 746 : SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
877 : SelectionDAG &DAG) const {
878 : SDLoc DL(Op);
879 : const auto *GA = cast<GlobalAddressSDNode>(Op);
880 746 : EVT VT = Op.getValueType();
881 : assert(GA->getTargetFlags() == 0 &&
882 : "Unexpected target flags on generic GlobalAddressSDNode");
883 746 : if (GA->getAddressSpace() != 0)
884 0 : fail(DL, DAG, "WebAssembly only expects the 0 address space");
885 : return DAG.getNode(
886 : WebAssemblyISD::Wrapper, DL, VT,
887 746 : DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
888 : }
889 :
890 : SDValue
891 57 : WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
892 : SelectionDAG &DAG) const {
893 : SDLoc DL(Op);
894 : const auto *ES = cast<ExternalSymbolSDNode>(Op);
895 57 : EVT VT = Op.getValueType();
896 : assert(ES->getTargetFlags() == 0 &&
897 : "Unexpected target flags on generic ExternalSymbolSDNode");
898 : // Set the TargetFlags to 0x1 which indicates that this is a "function"
899 : // symbol rather than a data symbol. We do this unconditionally even though
900 : // we don't know anything about the symbol other than its name, because all
901 : // external symbols used in target-independent SelectionDAG code are for
902 : // functions.
903 : return DAG.getNode(
904 : WebAssemblyISD::Wrapper, DL, VT,
905 : DAG.getTargetExternalSymbol(ES->getSymbol(), VT,
906 57 : WebAssemblyII::MO_SYMBOL_FUNCTION));
907 : }
908 :
909 0 : SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
910 : SelectionDAG &DAG) const {
911 : // There's no need for a Wrapper node because we always incorporate a jump
912 : // table operand into a BR_TABLE instruction, rather than ever
913 : // materializing it in a register.
914 : const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
915 : return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
916 0 : JT->getTargetFlags());
917 : }
918 :
919 2 : SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
920 : SelectionDAG &DAG) const {
921 : SDLoc DL(Op);
922 2 : SDValue Chain = Op.getOperand(0);
923 : const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
924 2 : SDValue Index = Op.getOperand(2);
925 : assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
926 :
927 : SmallVector<SDValue, 8> Ops;
928 2 : Ops.push_back(Chain);
929 2 : Ops.push_back(Index);
930 :
931 2 : MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
932 2 : const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
933 :
934 : // Add an operand for each case.
935 50 : for (auto MBB : MBBs)
936 48 : Ops.push_back(DAG.getBasicBlock(MBB));
937 :
938 : // TODO: For now, we just pick something arbitrary for a default case for now.
939 : // We really want to sniff out the guard and put in the real default case (and
940 : // delete the guard).
941 2 : Ops.push_back(DAG.getBasicBlock(MBBs[0]));
942 :
943 2 : return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
944 : }
945 :
946 2 : SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
947 : SelectionDAG &DAG) const {
948 : SDLoc DL(Op);
949 2 : EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
950 :
951 2 : auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
952 2 : const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
953 :
954 : SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
955 4 : MFI->getVarargBufferVreg(), PtrVT);
956 : return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
957 2 : MachinePointerInfo(SV), 0);
958 : }
959 :
960 : SDValue
961 124 : WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
962 : SelectionDAG &DAG) const {
963 248 : unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
964 : SDLoc DL(Op);
965 124 : switch (IntNo) {
966 120 : default:
967 120 : return {}; // Don't custom lower most intrinsics.
968 :
969 4 : case Intrinsic::wasm_lsda:
970 : // TODO For now, just return 0 not to crash
971 4 : return DAG.getConstant(0, DL, Op.getValueType());
972 : }
973 : }
974 :
975 : SDValue
976 10 : WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
977 : SelectionDAG &DAG) const {
978 : SDLoc DL(Op);
979 10 : ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
980 10 : MVT VecType = Op.getOperand(0).getSimpleValueType();
981 : assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
982 10 : size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
983 :
984 : // Space for two vector args and sixteen mask indices
985 10 : SDValue Ops[18];
986 : size_t OpIdx = 0;
987 10 : Ops[OpIdx++] = Op.getOperand(0);
988 10 : Ops[OpIdx++] = Op.getOperand(1);
989 :
990 : // Expand mask indices to byte indices and materialize them as operands
991 78 : for (size_t I = 0, Lanes = Mask.size(); I < Lanes; ++I) {
992 228 : for (size_t J = 0; J < LaneBytes; ++J) {
993 160 : Ops[OpIdx++] =
994 320 : DAG.getConstant((uint64_t)Mask[I] * LaneBytes + J, DL, MVT::i32);
995 : }
996 : }
997 :
998 10 : return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, MVT::v16i8, Ops);
999 : }
1000 :
1001 : //===----------------------------------------------------------------------===//
1002 : // WebAssembly Optimization Hooks
1003 : //===----------------------------------------------------------------------===//
|