blob: 70720e0c32c23e5a63f52952e6e056d602c3b9a9 [file] [log] [blame]
Dan Gohman10e730a2015-06-29 23:51:55 +00001//=- 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
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// This file implements the WebAssemblyTargetLowering class.
Dan Gohman10e730a2015-06-29 23:51:55 +000012///
13//===----------------------------------------------------------------------===//
14
15#include "WebAssemblyISelLowering.h"
16#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17#include "WebAssemblyMachineFunctionInfo.h"
18#include "WebAssemblySubtarget.h"
19#include "WebAssemblyTargetMachine.h"
Dan Gohman10e730a2015-06-29 23:51:55 +000020#include "llvm/CodeGen/Analysis.h"
JF Bastienaf111db2015-08-24 22:16:48 +000021#include "llvm/CodeGen/CallingConvLower.h"
Dan Gohmancdd48b82017-11-28 01:13:40 +000022#include "llvm/CodeGen/MachineInstrBuilder.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000023#include "llvm/CodeGen/MachineJumpTableInfo.h"
Heejin Ahn24faf852018-10-25 23:55:10 +000024#include "llvm/CodeGen/MachineModuleInfo.h"
Dan Gohman10e730a2015-06-29 23:51:55 +000025#include "llvm/CodeGen/MachineRegisterInfo.h"
26#include "llvm/CodeGen/SelectionDAG.h"
Oliver Stannard02fa1c82016-01-28 13:19:47 +000027#include "llvm/IR/DiagnosticInfo.h"
JF Bastienb9073fb2015-07-22 21:28:15 +000028#include "llvm/IR/DiagnosticPrinter.h"
Dan Gohman10e730a2015-06-29 23:51:55 +000029#include "llvm/IR/Function.h"
30#include "llvm/IR/Intrinsics.h"
Dan Gohman10e730a2015-06-29 23:51:55 +000031#include "llvm/Support/Debug.h"
32#include "llvm/Support/ErrorHandling.h"
33#include "llvm/Support/raw_ostream.h"
34#include "llvm/Target/TargetOptions.h"
35using namespace llvm;
36
37#define DEBUG_TYPE "wasm-lower"
38
Heejin Ahn5831e9c2018-08-09 23:58:51 +000039// Emit proposed instructions that may not have been implemented in engines
40cl::opt<bool> EnableUnimplementedWasmSIMDInstrs(
41 "wasm-enable-unimplemented-simd",
42 cl::desc("Emit potentially-unimplemented WebAssembly SIMD instructions"),
43 cl::init(false));
44
Dan Gohman10e730a2015-06-29 23:51:55 +000045WebAssemblyTargetLowering::WebAssemblyTargetLowering(
46 const TargetMachine &TM, const WebAssemblySubtarget &STI)
Dan Gohmanbfaf7e12015-07-02 21:36:25 +000047 : TargetLowering(TM), Subtarget(&STI) {
JF Bastienaf111db2015-08-24 22:16:48 +000048 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
49
JF Bastien71d29ac2015-08-12 17:53:29 +000050 // Booleans always contain 0 or 1.
51 setBooleanContents(ZeroOrOneBooleanContent);
Thomas Lively5ea17d42018-10-20 01:35:23 +000052 // Except in SIMD vectors
53 setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
Dan Gohmanbfaf7e12015-07-02 21:36:25 +000054 // WebAssembly does not produce floating-point exceptions on normal floating
55 // point operations.
56 setHasFloatingPointExceptions(false);
Dan Gohman489abd72015-07-07 22:38:06 +000057 // We don't know the microarchitecture here, so just reduce register pressure.
58 setSchedulingPreference(Sched::RegPressure);
JF Bastienb9073fb2015-07-22 21:28:15 +000059 // Tell ISel that we have a stack pointer.
60 setStackPointerRegisterToSaveRestore(
61 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
62 // Set up the register classes.
Dan Gohmand0bf9812015-09-26 01:09:44 +000063 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
64 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
65 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
66 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
Derek Schuff39bf39f2016-08-02 23:16:09 +000067 if (Subtarget->hasSIMD128()) {
68 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
69 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
70 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
71 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
Heejin Ahn5831e9c2018-08-09 23:58:51 +000072 if (EnableUnimplementedWasmSIMDInstrs) {
73 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
74 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
75 }
Derek Schuff39bf39f2016-08-02 23:16:09 +000076 }
JF Bastienb9073fb2015-07-22 21:28:15 +000077 // Compute derived properties from the register classes.
78 computeRegisterProperties(Subtarget->getRegisterInfo());
79
JF Bastienaf111db2015-08-24 22:16:48 +000080 setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
Dan Gohman2c8fe6a2015-11-25 16:44:29 +000081 setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
Dan Gohman950a13c2015-09-16 16:51:30 +000082 setOperationAction(ISD::JumpTable, MVTPtr, Custom);
Derek Schuff51699a82016-02-12 22:56:03 +000083 setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
84 setOperationAction(ISD::BRIND, MVT::Other, Custom);
JF Bastienaf111db2015-08-24 22:16:48 +000085
Dan Gohman35bfb242015-12-04 23:22:35 +000086 // Take the default expansion for va_arg, va_copy, and va_end. There is no
87 // default action for va_start, so we do that custom.
88 setOperationAction(ISD::VASTART, MVT::Other, Custom);
89 setOperationAction(ISD::VAARG, MVT::Other, Expand);
90 setOperationAction(ISD::VACOPY, MVT::Other, Expand);
91 setOperationAction(ISD::VAEND, MVT::Other, Expand);
92
Thomas Livelyebd4c902018-09-12 17:56:00 +000093 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
JF Bastienda06bce2015-08-11 21:02:46 +000094 // Don't expand the floating-point types to constant pools.
95 setOperationAction(ISD::ConstantFP, T, Legal);
96 // Expand floating-point comparisons.
97 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
98 ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
99 setCondCodeAction(CC, T, Expand);
Dan Gohman32907a62015-08-20 22:57:13 +0000100 // Expand floating-point library function operators.
Heejin Ahnf208f632018-09-05 01:27:38 +0000101 for (auto Op :
102 {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
Dan Gohman32907a62015-08-20 22:57:13 +0000103 setOperationAction(Op, T, Expand);
Dan Gohman896e53f2015-08-24 18:23:13 +0000104 // Note supported floating-point library function operators that otherwise
105 // default to expand.
Dan Gohman7a6b9822015-11-29 22:32:02 +0000106 for (auto Op :
107 {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
Dan Gohman896e53f2015-08-24 18:23:13 +0000108 setOperationAction(Op, T, Legal);
Thomas Lively30f1d692018-10-24 22:49:55 +0000109 // Support minimum and maximum, which otherwise default to expand.
110 setOperationAction(ISD::FMINIMUM, T, Legal);
111 setOperationAction(ISD::FMAXIMUM, T, Legal);
Dan Gohmana63e8eb2017-02-22 16:28:00 +0000112 // WebAssembly currently has no builtin f16 support.
113 setOperationAction(ISD::FP16_TO_FP, T, Expand);
114 setOperationAction(ISD::FP_TO_FP16, T, Expand);
115 setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
116 setTruncStoreAction(T, MVT::f16, Expand);
JF Bastienda06bce2015-08-11 21:02:46 +0000117 }
Dan Gohman32907a62015-08-20 22:57:13 +0000118
Thomas Lively0aad98f2018-10-25 19:06:13 +0000119 // Support saturating add for i8x16 and i16x8
120 if (Subtarget->hasSIMD128())
121 for (auto T : {MVT::v16i8, MVT::v8i16})
122 for (auto Op : {ISD::SADDSAT, ISD::UADDSAT})
123 setOperationAction(Op, T, Legal);
124
Dan Gohman32907a62015-08-20 22:57:13 +0000125 for (auto T : {MVT::i32, MVT::i64}) {
126 // Expand unavailable integer operations.
Dan Gohman7a6b9822015-11-29 22:32:02 +0000127 for (auto Op :
Heejin Ahnf208f632018-09-05 01:27:38 +0000128 {ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
129 ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
130 ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
Dan Gohman32907a62015-08-20 22:57:13 +0000131 setOperationAction(Op, T, Expand);
132 }
133 }
134
Thomas Lively2ee686d2018-08-22 23:06:27 +0000135 // There is no i64x2.mul instruction
136 setOperationAction(ISD::MUL, MVT::v2i64, Expand);
137
Thomas Livelya0d25812018-09-07 21:54:46 +0000138 // We have custom shuffle lowering to expose the shuffle mask
139 if (Subtarget->hasSIMD128()) {
140 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) {
141 setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
142 }
143 if (EnableUnimplementedWasmSIMDInstrs) {
144 setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i64, Custom);
145 setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f64, Custom);
146 }
147 }
148
Thomas Lively55735d52018-10-20 01:31:18 +0000149 // Custom lowering to avoid having to emit a wrap for 2xi64 constant shifts
150 if (Subtarget->hasSIMD128() && EnableUnimplementedWasmSIMDInstrs)
151 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
152 setOperationAction(Op, MVT::v2i64, Custom);
153
Thomas Livelyd4891a12018-11-01 00:01:02 +0000154 // There is no select instruction for vectors
155 if (Subtarget->hasSIMD128()) {
156 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
157 setOperationAction(ISD::VSELECT, T, Expand);
158 if (EnableUnimplementedWasmSIMDInstrs)
159 for (auto T : {MVT::v2i64, MVT::v2f64})
160 setOperationAction(ISD::VSELECT, T, Expand);
161 }
162
Dan Gohman32907a62015-08-20 22:57:13 +0000163 // As a special case, these operators use the type to mean the type to
164 // sign-extend from.
Derek Schuffa519fe52017-09-13 00:29:06 +0000165 setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
Dan Gohman5d2b9352018-01-19 17:16:24 +0000166 if (!Subtarget->hasSignExt()) {
Derek Schuffa519fe52017-09-13 00:29:06 +0000167 for (auto T : {MVT::i8, MVT::i16, MVT::i32})
168 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
169 }
Thomas Lively5ea17d42018-10-20 01:35:23 +0000170 for (auto T : MVT::integer_vector_valuetypes())
171 setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
Dan Gohman32907a62015-08-20 22:57:13 +0000172
173 // Dynamic stack allocation: use the default expansion.
174 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
175 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
Dan Gohman2683a552015-08-24 22:31:52 +0000176 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
JF Bastien73ff6af2015-08-31 22:24:11 +0000177
Derek Schuff9769deb2015-12-11 23:49:46 +0000178 setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
Derek Schuffaadc89c2016-02-16 18:18:36 +0000179 setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
Derek Schuff9769deb2015-12-11 23:49:46 +0000180
Dan Gohman950a13c2015-09-16 16:51:30 +0000181 // Expand these forms; we pattern-match the forms that we can handle in isel.
182 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
183 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
184 setOperationAction(Op, T, Expand);
185
186 // We have custom switch handling.
187 setOperationAction(ISD::BR_JT, MVT::Other, Custom);
188
JF Bastien73ff6af2015-08-31 22:24:11 +0000189 // WebAssembly doesn't have:
190 // - Floating-point extending loads.
191 // - Floating-point truncating stores.
192 // - i1 extending loads.
Thomas Lively325c9c52018-10-25 01:46:07 +0000193 // - extending/truncating SIMD loads/stores
Dan Gohman60bddf12015-12-10 02:07:53 +0000194 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
JF Bastien73ff6af2015-08-31 22:24:11 +0000195 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
196 for (auto T : MVT::integer_valuetypes())
197 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
198 setLoadExtAction(Ext, T, MVT::i1, Promote);
Thomas Lively325c9c52018-10-25 01:46:07 +0000199 if (Subtarget->hasSIMD128()) {
200 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
201 MVT::v2f64}) {
202 for (auto MemT : MVT::vector_valuetypes()) {
203 if (MVT(T) != MemT) {
204 setTruncStoreAction(T, MemT, Expand);
205 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
206 setLoadExtAction(Ext, T, MemT, Expand);
207 }
208 }
209 }
210 }
Derek Schuffffa143c2015-11-10 00:30:57 +0000211
212 // Trap lowers to wasm unreachable
213 setOperationAction(ISD::TRAP, MVT::Other, Legal);
Derek Schuff18ba1922017-08-30 18:07:45 +0000214
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000215 // Exception handling intrinsics
216 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
217
Derek Schuff18ba1922017-08-30 18:07:45 +0000218 setMaxAtomicSizeInBitsSupported(64);
Dan Gohmanbfaf7e12015-07-02 21:36:25 +0000219}
Dan Gohman10e730a2015-06-29 23:51:55 +0000220
Heejin Ahne8653bb2018-08-07 00:22:22 +0000221TargetLowering::AtomicExpansionKind
222WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
223 // We have wasm instructions for these
224 switch (AI->getOperation()) {
225 case AtomicRMWInst::Add:
226 case AtomicRMWInst::Sub:
227 case AtomicRMWInst::And:
228 case AtomicRMWInst::Or:
229 case AtomicRMWInst::Xor:
230 case AtomicRMWInst::Xchg:
231 return AtomicExpansionKind::None;
232 default:
233 break;
234 }
235 return AtomicExpansionKind::CmpXChg;
236}
237
Dan Gohman7b634842015-08-24 18:44:37 +0000238FastISel *WebAssemblyTargetLowering::createFastISel(
239 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
240 return WebAssembly::createFastISel(FuncInfo, LibInfo);
241}
242
JF Bastienaf111db2015-08-24 22:16:48 +0000243bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
Dan Gohman7a6b9822015-11-29 22:32:02 +0000244 const GlobalAddressSDNode * /*GA*/) const {
Dan Gohmana4b710a2015-12-06 19:33:32 +0000245 // All offsets can be folded.
246 return true;
JF Bastienaf111db2015-08-24 22:16:48 +0000247}
248
Dan Gohman7a6b9822015-11-29 22:32:02 +0000249MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
JF Bastienfda53372015-08-03 00:00:11 +0000250 EVT VT) const {
Dan Gohmana8483752015-12-10 00:26:26 +0000251 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
Heejin Ahnf208f632018-09-05 01:27:38 +0000252 if (BitWidth > 1 && BitWidth < 8)
253 BitWidth = 8;
Dan Gohman41729532015-12-16 23:25:51 +0000254
255 if (BitWidth > 64) {
Dan Gohmana01e8bd2016-05-14 02:15:47 +0000256 // The shift will be lowered to a libcall, and compiler-rt libcalls expect
257 // the count to be an i32.
258 BitWidth = 32;
Dan Gohman41729532015-12-16 23:25:51 +0000259 assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
Dan Gohmana01e8bd2016-05-14 02:15:47 +0000260 "32-bit shift counts ought to be enough for anyone");
Dan Gohman41729532015-12-16 23:25:51 +0000261 }
262
Dan Gohmana8483752015-12-10 00:26:26 +0000263 MVT Result = MVT::getIntegerVT(BitWidth);
264 assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
265 "Unable to represent scalar shift amount type");
266 return Result;
JF Bastienfda53372015-08-03 00:00:11 +0000267}
268
Dan Gohmancdd48b82017-11-28 01:13:40 +0000269// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
270// undefined result on invalid/overflow, to the WebAssembly opcode, which
271// traps on invalid/overflow.
Heejin Ahnf208f632018-09-05 01:27:38 +0000272static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
273 MachineBasicBlock *BB,
274 const TargetInstrInfo &TII,
275 bool IsUnsigned, bool Int64,
276 bool Float64, unsigned LoweredOpcode) {
Dan Gohmancdd48b82017-11-28 01:13:40 +0000277 MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
278
279 unsigned OutReg = MI.getOperand(0).getReg();
280 unsigned InReg = MI.getOperand(1).getReg();
281
282 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
283 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
284 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
Dan Gohman580c1022017-11-29 20:20:11 +0000285 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
Dan Gohmancdd48b82017-11-28 01:13:40 +0000286 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
Dan Gohman580c1022017-11-29 20:20:11 +0000287 unsigned Eqz = WebAssembly::EQZ_I32;
288 unsigned And = WebAssembly::AND_I32;
Dan Gohmancdd48b82017-11-28 01:13:40 +0000289 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
290 int64_t Substitute = IsUnsigned ? 0 : Limit;
291 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
David Blaikie21109242017-12-15 23:52:06 +0000292 auto &Context = BB->getParent()->getFunction().getContext();
Dan Gohmancdd48b82017-11-28 01:13:40 +0000293 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
294
295 const BasicBlock *LLVM_BB = BB->getBasicBlock();
296 MachineFunction *F = BB->getParent();
297 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVM_BB);
298 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
299 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVM_BB);
300
301 MachineFunction::iterator It = ++BB->getIterator();
302 F->insert(It, FalseMBB);
303 F->insert(It, TrueMBB);
304 F->insert(It, DoneMBB);
305
306 // Transfer the remainder of BB and its successor edges to DoneMBB.
307 DoneMBB->splice(DoneMBB->begin(), BB,
Heejin Ahnf208f632018-09-05 01:27:38 +0000308 std::next(MachineBasicBlock::iterator(MI)), BB->end());
Dan Gohmancdd48b82017-11-28 01:13:40 +0000309 DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
310
311 BB->addSuccessor(TrueMBB);
312 BB->addSuccessor(FalseMBB);
313 TrueMBB->addSuccessor(DoneMBB);
314 FalseMBB->addSuccessor(DoneMBB);
315
Dan Gohman580c1022017-11-29 20:20:11 +0000316 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
Dan Gohmancdd48b82017-11-28 01:13:40 +0000317 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
318 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
Dan Gohman580c1022017-11-29 20:20:11 +0000319 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
320 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
321 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
322 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
Dan Gohmancdd48b82017-11-28 01:13:40 +0000323
324 MI.eraseFromParent();
Dan Gohman580c1022017-11-29 20:20:11 +0000325 // For signed numbers, we can do a single comparison to determine whether
326 // fabs(x) is within range.
Dan Gohmancdd48b82017-11-28 01:13:40 +0000327 if (IsUnsigned) {
328 Tmp0 = InReg;
329 } else {
Heejin Ahnf208f632018-09-05 01:27:38 +0000330 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
Dan Gohmancdd48b82017-11-28 01:13:40 +0000331 }
332 BuildMI(BB, DL, TII.get(FConst), Tmp1)
333 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
Heejin Ahnf208f632018-09-05 01:27:38 +0000334 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
Dan Gohman580c1022017-11-29 20:20:11 +0000335
336 // For unsigned numbers, we have to do a separate comparison with zero.
337 if (IsUnsigned) {
338 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
Heejin Ahnf208f632018-09-05 01:27:38 +0000339 unsigned SecondCmpReg =
340 MRI.createVirtualRegister(&WebAssembly::I32RegClass);
Dan Gohman580c1022017-11-29 20:20:11 +0000341 unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
342 BuildMI(BB, DL, TII.get(FConst), Tmp1)
343 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
Heejin Ahnf208f632018-09-05 01:27:38 +0000344 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
345 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
Dan Gohman580c1022017-11-29 20:20:11 +0000346 CmpReg = AndReg;
347 }
348
Heejin Ahnf208f632018-09-05 01:27:38 +0000349 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
Dan Gohman580c1022017-11-29 20:20:11 +0000350
351 // Create the CFG diamond to select between doing the conversion or using
352 // the substitute value.
Heejin Ahnf208f632018-09-05 01:27:38 +0000353 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
354 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
355 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
356 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
Dan Gohmancdd48b82017-11-28 01:13:40 +0000357 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
Dan Gohman580c1022017-11-29 20:20:11 +0000358 .addReg(FalseReg)
Dan Gohmancdd48b82017-11-28 01:13:40 +0000359 .addMBB(FalseMBB)
Dan Gohman580c1022017-11-29 20:20:11 +0000360 .addReg(TrueReg)
Dan Gohmancdd48b82017-11-28 01:13:40 +0000361 .addMBB(TrueMBB);
362
363 return DoneMBB;
364}
365
Heejin Ahnf208f632018-09-05 01:27:38 +0000366MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
367 MachineInstr &MI, MachineBasicBlock *BB) const {
Dan Gohmancdd48b82017-11-28 01:13:40 +0000368 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
369 DebugLoc DL = MI.getDebugLoc();
370
371 switch (MI.getOpcode()) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000372 default:
373 llvm_unreachable("Unexpected instr type to insert");
Dan Gohmancdd48b82017-11-28 01:13:40 +0000374 case WebAssembly::FP_TO_SINT_I32_F32:
375 return LowerFPToInt(MI, DL, BB, TII, false, false, false,
376 WebAssembly::I32_TRUNC_S_F32);
377 case WebAssembly::FP_TO_UINT_I32_F32:
378 return LowerFPToInt(MI, DL, BB, TII, true, false, false,
379 WebAssembly::I32_TRUNC_U_F32);
380 case WebAssembly::FP_TO_SINT_I64_F32:
381 return LowerFPToInt(MI, DL, BB, TII, false, true, false,
382 WebAssembly::I64_TRUNC_S_F32);
383 case WebAssembly::FP_TO_UINT_I64_F32:
384 return LowerFPToInt(MI, DL, BB, TII, true, true, false,
385 WebAssembly::I64_TRUNC_U_F32);
386 case WebAssembly::FP_TO_SINT_I32_F64:
387 return LowerFPToInt(MI, DL, BB, TII, false, false, true,
388 WebAssembly::I32_TRUNC_S_F64);
389 case WebAssembly::FP_TO_UINT_I32_F64:
390 return LowerFPToInt(MI, DL, BB, TII, true, false, true,
391 WebAssembly::I32_TRUNC_U_F64);
392 case WebAssembly::FP_TO_SINT_I64_F64:
393 return LowerFPToInt(MI, DL, BB, TII, false, true, true,
394 WebAssembly::I64_TRUNC_S_F64);
395 case WebAssembly::FP_TO_UINT_I64_F64:
396 return LowerFPToInt(MI, DL, BB, TII, true, true, true,
397 WebAssembly::I64_TRUNC_U_F64);
Heejin Ahnf208f632018-09-05 01:27:38 +0000398 llvm_unreachable("Unexpected instruction to emit with custom inserter");
Dan Gohmancdd48b82017-11-28 01:13:40 +0000399 }
400}
401
Heejin Ahnf208f632018-09-05 01:27:38 +0000402const char *
403WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
JF Bastien480c8402015-08-11 20:13:18 +0000404 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000405 case WebAssemblyISD::FIRST_NUMBER:
406 break;
407#define HANDLE_NODETYPE(NODE) \
408 case WebAssemblyISD::NODE: \
JF Bastienaf111db2015-08-24 22:16:48 +0000409 return "WebAssemblyISD::" #NODE;
410#include "WebAssemblyISD.def"
411#undef HANDLE_NODETYPE
JF Bastien480c8402015-08-11 20:13:18 +0000412 }
413 return nullptr;
414}
415
Dan Gohmanf19ed562015-11-13 01:42:29 +0000416std::pair<unsigned, const TargetRegisterClass *>
417WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
418 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
419 // First, see if this is a constraint that directly corresponds to a
420 // WebAssembly register class.
421 if (Constraint.size() == 1) {
422 switch (Constraint[0]) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000423 case 'r':
424 assert(VT != MVT::iPTR && "Pointer MVT not expected here");
425 if (Subtarget->hasSIMD128() && VT.isVector()) {
426 if (VT.getSizeInBits() == 128)
427 return std::make_pair(0U, &WebAssembly::V128RegClass);
428 }
429 if (VT.isInteger() && !VT.isVector()) {
430 if (VT.getSizeInBits() <= 32)
431 return std::make_pair(0U, &WebAssembly::I32RegClass);
432 if (VT.getSizeInBits() <= 64)
433 return std::make_pair(0U, &WebAssembly::I64RegClass);
434 }
435 break;
436 default:
437 break;
Dan Gohmanf19ed562015-11-13 01:42:29 +0000438 }
439 }
440
441 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
442}
443
Dan Gohman3192ddf2015-11-19 23:04:59 +0000444bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
445 // Assume ctz is a relatively cheap operation.
446 return true;
447}
448
449bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
450 // Assume clz is a relatively cheap operation.
451 return true;
452}
453
Dan Gohman4b9d7912015-12-15 22:01:29 +0000454bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
455 const AddrMode &AM,
Heejin Ahnf208f632018-09-05 01:27:38 +0000456 Type *Ty, unsigned AS,
Jonas Paulsson024e3192017-07-21 11:59:37 +0000457 Instruction *I) const {
Dan Gohman4b9d7912015-12-15 22:01:29 +0000458 // WebAssembly offsets are added as unsigned without wrapping. The
459 // isLegalAddressingMode gives us no way to determine if wrapping could be
460 // happening, so we approximate this by accepting only non-negative offsets.
Heejin Ahnf208f632018-09-05 01:27:38 +0000461 if (AM.BaseOffs < 0)
462 return false;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000463
464 // WebAssembly has no scale register operands.
Heejin Ahnf208f632018-09-05 01:27:38 +0000465 if (AM.Scale != 0)
466 return false;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000467
468 // Everything else is legal.
469 return true;
470}
471
Dan Gohmanbb372242016-01-26 03:39:31 +0000472bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
Derek Schuff3f063292016-02-11 20:57:09 +0000473 EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast) const {
Dan Gohmanbb372242016-01-26 03:39:31 +0000474 // WebAssembly supports unaligned accesses, though it should be declared
475 // with the p2align attribute on loads and stores which do so, and there
476 // may be a performance impact. We tell LLVM they're "fast" because
Dan Gohmanfb619e92016-01-26 14:55:17 +0000477 // for the kinds of things that LLVM uses this for (merging adjacent stores
Dan Gohmanbb372242016-01-26 03:39:31 +0000478 // of constants, etc.), WebAssembly implementations will either want the
479 // unaligned access or they'll split anyway.
Heejin Ahnf208f632018-09-05 01:27:38 +0000480 if (Fast)
481 *Fast = true;
Dan Gohmanbb372242016-01-26 03:39:31 +0000482 return true;
483}
484
Reid Klecknerb5180542017-03-21 16:57:19 +0000485bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
486 AttributeList Attr) const {
Dan Gohmanb4c3c382016-05-18 14:29:42 +0000487 // The current thinking is that wasm engines will perform this optimization,
488 // so we can save on code size.
489 return true;
490}
491
Simon Pilgrim99f70162018-06-28 17:27:09 +0000492EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
493 LLVMContext &C,
494 EVT VT) const {
495 if (VT.isVector())
496 return VT.changeVectorElementTypeToInteger();
497
498 return TargetLowering::getSetCCResultType(DL, C, VT);
499}
500
Heejin Ahn4128cb02018-08-02 21:44:24 +0000501bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
502 const CallInst &I,
503 MachineFunction &MF,
504 unsigned Intrinsic) const {
505 switch (Intrinsic) {
506 case Intrinsic::wasm_atomic_notify:
507 Info.opc = ISD::INTRINSIC_W_CHAIN;
508 Info.memVT = MVT::i32;
509 Info.ptrVal = I.getArgOperand(0);
510 Info.offset = 0;
511 Info.align = 4;
512 // atomic.notify instruction does not really load the memory specified with
513 // this argument, but MachineMemOperand should either be load or store, so
514 // we set this to a load.
515 // FIXME Volatile isn't really correct, but currently all LLVM atomic
516 // instructions are treated as volatiles in the backend, so we should be
517 // consistent. The same applies for wasm_atomic_wait intrinsics too.
518 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
519 return true;
520 case Intrinsic::wasm_atomic_wait_i32:
521 Info.opc = ISD::INTRINSIC_W_CHAIN;
522 Info.memVT = MVT::i32;
523 Info.ptrVal = I.getArgOperand(0);
524 Info.offset = 0;
525 Info.align = 4;
526 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
527 return true;
528 case Intrinsic::wasm_atomic_wait_i64:
529 Info.opc = ISD::INTRINSIC_W_CHAIN;
530 Info.memVT = MVT::i64;
531 Info.ptrVal = I.getArgOperand(0);
532 Info.offset = 0;
533 Info.align = 8;
534 Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
535 return true;
536 default:
537 return false;
538 }
539}
540
Dan Gohman10e730a2015-06-29 23:51:55 +0000541//===----------------------------------------------------------------------===//
542// WebAssembly Lowering private implementation.
543//===----------------------------------------------------------------------===//
544
545//===----------------------------------------------------------------------===//
546// Lowering Code
547//===----------------------------------------------------------------------===//
548
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000549static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *msg) {
JF Bastienb9073fb2015-07-22 21:28:15 +0000550 MachineFunction &MF = DAG.getMachineFunction();
551 DAG.getContext()->diagnose(
David Blaikie21109242017-12-15 23:52:06 +0000552 DiagnosticInfoUnsupported(MF.getFunction(), msg, DL.getDebugLoc()));
JF Bastienb9073fb2015-07-22 21:28:15 +0000553}
554
Dan Gohman85dbdda2015-12-04 17:16:07 +0000555// Test whether the given calling convention is supported.
Dan Gohmana3f5ce52015-12-04 17:18:32 +0000556static bool CallingConvSupported(CallingConv::ID CallConv) {
Dan Gohman85dbdda2015-12-04 17:16:07 +0000557 // We currently support the language-independent target-independent
Dan Gohman1ce2b1a2015-12-04 18:27:03 +0000558 // conventions. We don't yet have a way to annotate calls with properties like
559 // "cold", and we don't have any call-clobbered registers, so these are mostly
560 // all handled the same.
Dan Gohmana3f5ce52015-12-04 17:18:32 +0000561 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
Dan Gohman1ce2b1a2015-12-04 18:27:03 +0000562 CallConv == CallingConv::Cold ||
563 CallConv == CallingConv::PreserveMost ||
564 CallConv == CallingConv::PreserveAll ||
565 CallConv == CallingConv::CXX_FAST_TLS;
Dan Gohman85dbdda2015-12-04 17:16:07 +0000566}
567
Heejin Ahnf208f632018-09-05 01:27:38 +0000568SDValue
569WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
570 SmallVectorImpl<SDValue> &InVals) const {
JF Bastiend8a9d662015-08-24 21:59:51 +0000571 SelectionDAG &DAG = CLI.DAG;
572 SDLoc DL = CLI.DL;
573 SDValue Chain = CLI.Chain;
574 SDValue Callee = CLI.Callee;
575 MachineFunction &MF = DAG.getMachineFunction();
Derek Schuff992d83f2016-02-10 20:14:15 +0000576 auto Layout = MF.getDataLayout();
JF Bastiend8a9d662015-08-24 21:59:51 +0000577
578 CallingConv::ID CallConv = CLI.CallConv;
Dan Gohman85dbdda2015-12-04 17:16:07 +0000579 if (!CallingConvSupported(CallConv))
Dan Gohman9cc692b2015-10-02 20:54:23 +0000580 fail(DL, DAG,
581 "WebAssembly doesn't support language-specific or target-specific "
582 "calling conventions yet");
JF Bastiend8a9d662015-08-24 21:59:51 +0000583 if (CLI.IsPatchPoint)
584 fail(DL, DAG, "WebAssembly doesn't support patch point yet");
585
Dan Gohman9cc692b2015-10-02 20:54:23 +0000586 // WebAssembly doesn't currently support explicit tail calls. If they are
587 // required, fail. Otherwise, just disable them.
588 if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
589 MF.getTarget().Options.GuaranteedTailCallOpt) ||
Peter Collingbourne081ffe22017-07-26 19:15:29 +0000590 (CLI.CS && CLI.CS.isMustTailCall()))
Dan Gohman9cc692b2015-10-02 20:54:23 +0000591 fail(DL, DAG, "WebAssembly doesn't support tail call yet");
592 CLI.IsTailCall = false;
593
JF Bastiend8a9d662015-08-24 21:59:51 +0000594 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
Dan Gohmane590b332015-09-09 01:52:45 +0000595 if (Ins.size() > 1)
596 fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
597
Dan Gohman2d822e72015-12-04 17:12:52 +0000598 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
Derek Schuff4dd67782016-01-27 21:17:39 +0000599 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
Dan Gohman910ba332018-06-26 03:18:38 +0000600 unsigned NumFixedArgs = 0;
Derek Schuff4dd67782016-01-27 21:17:39 +0000601 for (unsigned i = 0; i < Outs.size(); ++i) {
602 const ISD::OutputArg &Out = Outs[i];
603 SDValue &OutVal = OutVals[i];
Dan Gohman7935fa32015-12-10 00:22:40 +0000604 if (Out.Flags.isNest())
605 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
Dan Gohman2d822e72015-12-04 17:12:52 +0000606 if (Out.Flags.isInAlloca())
Dan Gohman7935fa32015-12-10 00:22:40 +0000607 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
Dan Gohman2d822e72015-12-04 17:12:52 +0000608 if (Out.Flags.isInConsecutiveRegs())
Dan Gohman7935fa32015-12-10 00:22:40 +0000609 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
Dan Gohman2d822e72015-12-04 17:12:52 +0000610 if (Out.Flags.isInConsecutiveRegsLast())
Dan Gohman7935fa32015-12-10 00:22:40 +0000611 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
Dan Gohmana6771b32016-02-12 21:30:18 +0000612 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
Matthias Braun941a7052016-07-28 18:40:00 +0000613 auto &MFI = MF.getFrameInfo();
614 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
615 Out.Flags.getByValAlign(),
616 /*isSS=*/false);
Derek Schuff4dd67782016-01-27 21:17:39 +0000617 SDValue SizeNode =
618 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
Derek Schuff992d83f2016-02-10 20:14:15 +0000619 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
Derek Schuff4dd67782016-01-27 21:17:39 +0000620 Chain = DAG.getMemcpy(
621 Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
Dan Gohman476ffce2016-02-17 01:43:37 +0000622 /*isVolatile*/ false, /*AlwaysInline=*/false,
Derek Schuff4dd67782016-01-27 21:17:39 +0000623 /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
624 OutVal = FINode;
625 }
Dan Gohman910ba332018-06-26 03:18:38 +0000626 // Count the number of fixed args *after* legalization.
627 NumFixedArgs += Out.IsFixed;
Dan Gohman2d822e72015-12-04 17:12:52 +0000628 }
629
JF Bastiend8a9d662015-08-24 21:59:51 +0000630 bool IsVarArg = CLI.IsVarArg;
Derek Schuff992d83f2016-02-10 20:14:15 +0000631 auto PtrVT = getPointerTy(Layout);
Dan Gohmane590b332015-09-09 01:52:45 +0000632
JF Bastiend8a9d662015-08-24 21:59:51 +0000633 // Analyze operands of the call, assigning locations to each operand.
634 SmallVector<CCValAssign, 16> ArgLocs;
635 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
JF Bastiend8a9d662015-08-24 21:59:51 +0000636
Dan Gohman35bfb242015-12-04 23:22:35 +0000637 if (IsVarArg) {
Derek Schuff27501e22016-02-10 19:51:04 +0000638 // Outgoing non-fixed arguments are placed in a buffer. First
639 // compute their offsets and the total amount of buffer space needed.
Dan Gohman35bfb242015-12-04 23:22:35 +0000640 for (SDValue Arg :
641 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
642 EVT VT = Arg.getValueType();
643 assert(VT != MVT::iPTR && "Legalized args should be concrete");
644 Type *Ty = VT.getTypeForEVT(*DAG.getContext());
Derek Schuff992d83f2016-02-10 20:14:15 +0000645 unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty),
646 Layout.getABITypeAlignment(Ty));
Dan Gohman35bfb242015-12-04 23:22:35 +0000647 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
648 Offset, VT.getSimpleVT(),
649 CCValAssign::Full));
650 }
651 }
652
653 unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
654
Derek Schuff27501e22016-02-10 19:51:04 +0000655 SDValue FINode;
656 if (IsVarArg && NumBytes) {
Dan Gohman35bfb242015-12-04 23:22:35 +0000657 // For non-fixed arguments, next emit stores to store the argument values
Derek Schuff27501e22016-02-10 19:51:04 +0000658 // to the stack buffer at the offsets computed above.
Matthias Braun941a7052016-07-28 18:40:00 +0000659 int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
660 Layout.getStackAlignment(),
661 /*isSS=*/false);
Dan Gohman35bfb242015-12-04 23:22:35 +0000662 unsigned ValNo = 0;
663 SmallVector<SDValue, 8> Chains;
664 for (SDValue Arg :
665 make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
666 assert(ArgLocs[ValNo].getValNo() == ValNo &&
667 "ArgLocs should remain in order and only hold varargs args");
668 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
Derek Schuff992d83f2016-02-10 20:14:15 +0000669 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
Derek Schuff27501e22016-02-10 19:51:04 +0000670 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
Dan Gohman35bfb242015-12-04 23:22:35 +0000671 DAG.getConstant(Offset, DL, PtrVT));
Heejin Ahnf208f632018-09-05 01:27:38 +0000672 Chains.push_back(
673 DAG.getStore(Chain, DL, Arg, Add,
674 MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
Dan Gohman35bfb242015-12-04 23:22:35 +0000675 }
676 if (!Chains.empty())
677 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
Derek Schuff27501e22016-02-10 19:51:04 +0000678 } else if (IsVarArg) {
679 FINode = DAG.getIntPtrConstant(0, DL);
Dan Gohman35bfb242015-12-04 23:22:35 +0000680 }
681
682 // Compute the operands for the CALLn node.
JF Bastiend8a9d662015-08-24 21:59:51 +0000683 SmallVector<SDValue, 16> Ops;
684 Ops.push_back(Chain);
JF Bastienaf111db2015-08-24 22:16:48 +0000685 Ops.push_back(Callee);
Dan Gohman35bfb242015-12-04 23:22:35 +0000686
687 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
688 // isn't reliable.
689 Ops.append(OutVals.begin(),
690 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
Derek Schuff27501e22016-02-10 19:51:04 +0000691 // Add a pointer to the vararg buffer.
Heejin Ahnf208f632018-09-05 01:27:38 +0000692 if (IsVarArg)
693 Ops.push_back(FINode);
JF Bastiend8a9d662015-08-24 21:59:51 +0000694
Derek Schuff27501e22016-02-10 19:51:04 +0000695 SmallVector<EVT, 8> InTys;
Dan Gohman2d822e72015-12-04 17:12:52 +0000696 for (const auto &In : Ins) {
Dan Gohman7935fa32015-12-10 00:22:40 +0000697 assert(!In.Flags.isByVal() && "byval is not valid for return values");
698 assert(!In.Flags.isNest() && "nest is not valid for return values");
Dan Gohman2d822e72015-12-04 17:12:52 +0000699 if (In.Flags.isInAlloca())
Dan Gohman7935fa32015-12-10 00:22:40 +0000700 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
Dan Gohman2d822e72015-12-04 17:12:52 +0000701 if (In.Flags.isInConsecutiveRegs())
Dan Gohman7935fa32015-12-10 00:22:40 +0000702 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
Dan Gohman2d822e72015-12-04 17:12:52 +0000703 if (In.Flags.isInConsecutiveRegsLast())
Dan Gohman4b9d7912015-12-15 22:01:29 +0000704 fail(DL, DAG,
705 "WebAssembly hasn't implemented cons regs last return values");
Dan Gohman2d822e72015-12-04 17:12:52 +0000706 // Ignore In.getOrigAlign() because all our arguments are passed in
707 // registers.
Derek Schuff27501e22016-02-10 19:51:04 +0000708 InTys.push_back(In.VT);
Dan Gohman2d822e72015-12-04 17:12:52 +0000709 }
Derek Schuff27501e22016-02-10 19:51:04 +0000710 InTys.push_back(MVT::Other);
711 SDVTList InTyList = DAG.getVTList(InTys);
Dan Gohmanf71abef2015-09-09 16:13:47 +0000712 SDValue Res =
713 DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
Derek Schuff27501e22016-02-10 19:51:04 +0000714 DL, InTyList, Ops);
JF Bastienaf111db2015-08-24 22:16:48 +0000715 if (Ins.empty()) {
716 Chain = Res;
717 } else {
718 InVals.push_back(Res);
719 Chain = Res.getValue(1);
720 }
JF Bastiend8a9d662015-08-24 21:59:51 +0000721
JF Bastiend8a9d662015-08-24 21:59:51 +0000722 return Chain;
723}
724
JF Bastienb9073fb2015-07-22 21:28:15 +0000725bool WebAssemblyTargetLowering::CanLowerReturn(
Dan Gohman7a6b9822015-11-29 22:32:02 +0000726 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
727 const SmallVectorImpl<ISD::OutputArg> &Outs,
728 LLVMContext & /*Context*/) const {
JF Bastienb9073fb2015-07-22 21:28:15 +0000729 // WebAssembly can't currently handle returning tuples.
730 return Outs.size() <= 1;
731}
732
733SDValue WebAssemblyTargetLowering::LowerReturn(
Dan Gohman35bfb242015-12-04 23:22:35 +0000734 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
JF Bastienb9073fb2015-07-22 21:28:15 +0000735 const SmallVectorImpl<ISD::OutputArg> &Outs,
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000736 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
JF Bastienb9073fb2015-07-22 21:28:15 +0000737 SelectionDAG &DAG) const {
JF Bastienb9073fb2015-07-22 21:28:15 +0000738 assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
Dan Gohman85dbdda2015-12-04 17:16:07 +0000739 if (!CallingConvSupported(CallConv))
JF Bastienb9073fb2015-07-22 21:28:15 +0000740 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
741
JF Bastien600aee92015-07-31 17:53:38 +0000742 SmallVector<SDValue, 4> RetOps(1, Chain);
743 RetOps.append(OutVals.begin(), OutVals.end());
JF Bastien4a2d5602015-07-31 21:04:18 +0000744 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
JF Bastienb9073fb2015-07-22 21:28:15 +0000745
Dan Gohman754cd112015-11-11 01:33:02 +0000746 // Record the number and types of the return values.
747 for (const ISD::OutputArg &Out : Outs) {
Dan Gohmanac132e92015-12-02 23:40:03 +0000748 assert(!Out.Flags.isByVal() && "byval is not valid for return values");
749 assert(!Out.Flags.isNest() && "nest is not valid for return values");
Dan Gohman35bfb242015-12-04 23:22:35 +0000750 assert(Out.IsFixed && "non-fixed return value is not valid");
Dan Gohman754cd112015-11-11 01:33:02 +0000751 if (Out.Flags.isInAlloca())
752 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
Dan Gohman754cd112015-11-11 01:33:02 +0000753 if (Out.Flags.isInConsecutiveRegs())
754 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
755 if (Out.Flags.isInConsecutiveRegsLast())
756 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
Dan Gohman754cd112015-11-11 01:33:02 +0000757 }
758
JF Bastienb9073fb2015-07-22 21:28:15 +0000759 return Chain;
760}
761
762SDValue WebAssemblyTargetLowering::LowerFormalArguments(
Derek Schuff27501e22016-02-10 19:51:04 +0000763 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000764 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
765 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
Dan Gohman85dbdda2015-12-04 17:16:07 +0000766 if (!CallingConvSupported(CallConv))
JF Bastienb9073fb2015-07-22 21:28:15 +0000767 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
JF Bastienb9073fb2015-07-22 21:28:15 +0000768
Dan Gohman2726b882016-10-06 22:29:32 +0000769 MachineFunction &MF = DAG.getMachineFunction();
770 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
771
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000772 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
773 // of the incoming values before they're represented by virtual registers.
774 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
775
JF Bastien600aee92015-07-31 17:53:38 +0000776 for (const ISD::InputArg &In : Ins) {
JF Bastien600aee92015-07-31 17:53:38 +0000777 if (In.Flags.isInAlloca())
778 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
779 if (In.Flags.isNest())
780 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
JF Bastien600aee92015-07-31 17:53:38 +0000781 if (In.Flags.isInConsecutiveRegs())
782 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
783 if (In.Flags.isInConsecutiveRegsLast())
784 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
Dan Gohman9c54d3b2015-11-25 18:13:18 +0000785 // Ignore In.getOrigAlign() because all our arguments are passed in
786 // registers.
Heejin Ahnf208f632018-09-05 01:27:38 +0000787 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
788 DAG.getTargetConstant(InVals.size(),
789 DL, MVT::i32))
790 : DAG.getUNDEF(In.VT));
Dan Gohman754cd112015-11-11 01:33:02 +0000791
792 // Record the number and types of arguments.
Derek Schuff27501e22016-02-10 19:51:04 +0000793 MFI->addParam(In.VT);
JF Bastien600aee92015-07-31 17:53:38 +0000794 }
JF Bastienb9073fb2015-07-22 21:28:15 +0000795
Derek Schuff27501e22016-02-10 19:51:04 +0000796 // Varargs are copied into a buffer allocated by the caller, and a pointer to
797 // the buffer is passed as an argument.
798 if (IsVarArg) {
799 MVT PtrVT = getPointerTy(MF.getDataLayout());
800 unsigned VarargVreg =
801 MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
802 MFI->setVarargBufferVreg(VarargVreg);
803 Chain = DAG.getCopyToReg(
804 Chain, DL, VarargVreg,
805 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
806 DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
807 MFI->addParam(PtrVT);
808 }
Dan Gohman35bfb242015-12-04 23:22:35 +0000809
Derek Schuff77a7a382018-10-03 22:22:48 +0000810 // Record the number and types of arguments and results.
Dan Gohman2726b882016-10-06 22:29:32 +0000811 SmallVector<MVT, 4> Params;
812 SmallVector<MVT, 4> Results;
Derek Schuff77a7a382018-10-03 22:22:48 +0000813 ComputeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
814 DAG.getTarget(), Params, Results);
Dan Gohman2726b882016-10-06 22:29:32 +0000815 for (MVT VT : Results)
816 MFI->addResult(VT);
Derek Schuff77a7a382018-10-03 22:22:48 +0000817 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
818 // the param logic here with ComputeSignatureVTs
819 assert(MFI->getParams().size() == Params.size() &&
820 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
821 Params.begin()));
Dan Gohman2726b882016-10-06 22:29:32 +0000822
JF Bastienb9073fb2015-07-22 21:28:15 +0000823 return Chain;
824}
825
Dan Gohman10e730a2015-06-29 23:51:55 +0000826//===----------------------------------------------------------------------===//
JF Bastienaf111db2015-08-24 22:16:48 +0000827// Custom lowering hooks.
Dan Gohman10e730a2015-06-29 23:51:55 +0000828//===----------------------------------------------------------------------===//
829
JF Bastienaf111db2015-08-24 22:16:48 +0000830SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
831 SelectionDAG &DAG) const {
Derek Schuff51699a82016-02-12 22:56:03 +0000832 SDLoc DL(Op);
JF Bastienaf111db2015-08-24 22:16:48 +0000833 switch (Op.getOpcode()) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000834 default:
835 llvm_unreachable("unimplemented operation lowering");
836 return SDValue();
837 case ISD::FrameIndex:
838 return LowerFrameIndex(Op, DAG);
839 case ISD::GlobalAddress:
840 return LowerGlobalAddress(Op, DAG);
841 case ISD::ExternalSymbol:
842 return LowerExternalSymbol(Op, DAG);
843 case ISD::JumpTable:
844 return LowerJumpTable(Op, DAG);
845 case ISD::BR_JT:
846 return LowerBR_JT(Op, DAG);
847 case ISD::VASTART:
848 return LowerVASTART(Op, DAG);
849 case ISD::BlockAddress:
850 case ISD::BRIND:
851 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
852 return SDValue();
853 case ISD::RETURNADDR: // Probably nothing meaningful can be returned here.
854 fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address");
855 return SDValue();
856 case ISD::FRAMEADDR:
857 return LowerFRAMEADDR(Op, DAG);
858 case ISD::CopyToReg:
859 return LowerCopyToReg(Op, DAG);
860 case ISD::INTRINSIC_WO_CHAIN:
861 return LowerINTRINSIC_WO_CHAIN(Op, DAG);
Thomas Livelya0d25812018-09-07 21:54:46 +0000862 case ISD::VECTOR_SHUFFLE:
863 return LowerVECTOR_SHUFFLE(Op, DAG);
Thomas Lively55735d52018-10-20 01:31:18 +0000864 case ISD::SHL:
865 case ISD::SRA:
866 case ISD::SRL:
867 return LowerShift(Op, DAG);
JF Bastienaf111db2015-08-24 22:16:48 +0000868 }
869}
870
Derek Schuffaadc89c2016-02-16 18:18:36 +0000871SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
872 SelectionDAG &DAG) const {
873 SDValue Src = Op.getOperand(2);
874 if (isa<FrameIndexSDNode>(Src.getNode())) {
875 // CopyToReg nodes don't support FrameIndex operands. Other targets select
876 // the FI to some LEA-like instruction, but since we don't have that, we
877 // need to insert some kind of instruction that can take an FI operand and
878 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
879 // copy_local between Op and its FI operand.
Dan Gohman02c08712016-02-20 23:09:44 +0000880 SDValue Chain = Op.getOperand(0);
Derek Schuffaadc89c2016-02-16 18:18:36 +0000881 SDLoc DL(Op);
Dan Gohman02c08712016-02-20 23:09:44 +0000882 unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
Derek Schuffaadc89c2016-02-16 18:18:36 +0000883 EVT VT = Src.getValueType();
Heejin Ahnf208f632018-09-05 01:27:38 +0000884 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
885 : WebAssembly::COPY_I64,
886 DL, VT, Src),
887 0);
Dan Gohman02c08712016-02-20 23:09:44 +0000888 return Op.getNode()->getNumValues() == 1
889 ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
Heejin Ahnf208f632018-09-05 01:27:38 +0000890 : DAG.getCopyToReg(Chain, DL, Reg, Copy,
891 Op.getNumOperands() == 4 ? Op.getOperand(3)
892 : SDValue());
Derek Schuffaadc89c2016-02-16 18:18:36 +0000893 }
894 return SDValue();
895}
896
Derek Schuff9769deb2015-12-11 23:49:46 +0000897SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
898 SelectionDAG &DAG) const {
899 int FI = cast<FrameIndexSDNode>(Op)->getIndex();
900 return DAG.getTargetFrameIndex(FI, Op.getValueType());
901}
902
Dan Gohman94c65662016-02-16 23:48:04 +0000903SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
904 SelectionDAG &DAG) const {
905 // Non-zero depths are not supported by WebAssembly currently. Use the
906 // legalizer's default expansion, which is to return 0 (what this function is
907 // documented to do).
Dan Gohman1d547bf2016-02-17 00:14:03 +0000908 if (Op.getConstantOperandVal(0) > 0)
Dan Gohman94c65662016-02-16 23:48:04 +0000909 return SDValue();
910
Matthias Braun941a7052016-07-28 18:40:00 +0000911 DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
Dan Gohman94c65662016-02-16 23:48:04 +0000912 EVT VT = Op.getValueType();
913 unsigned FP =
914 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
915 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
916}
917
JF Bastienaf111db2015-08-24 22:16:48 +0000918SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
919 SelectionDAG &DAG) const {
920 SDLoc DL(Op);
921 const auto *GA = cast<GlobalAddressSDNode>(Op);
922 EVT VT = Op.getValueType();
Dan Gohman26c67652016-01-11 23:38:05 +0000923 assert(GA->getTargetFlags() == 0 &&
924 "Unexpected target flags on generic GlobalAddressSDNode");
JF Bastienaf111db2015-08-24 22:16:48 +0000925 if (GA->getAddressSpace() != 0)
926 fail(DL, DAG, "WebAssembly only expects the 0 address space");
Dan Gohman4b9d7912015-12-15 22:01:29 +0000927 return DAG.getNode(
928 WebAssemblyISD::Wrapper, DL, VT,
929 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
JF Bastienaf111db2015-08-24 22:16:48 +0000930}
931
Heejin Ahnf208f632018-09-05 01:27:38 +0000932SDValue
933WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
934 SelectionDAG &DAG) const {
Dan Gohman2c8fe6a2015-11-25 16:44:29 +0000935 SDLoc DL(Op);
936 const auto *ES = cast<ExternalSymbolSDNode>(Op);
937 EVT VT = Op.getValueType();
Dan Gohman26c67652016-01-11 23:38:05 +0000938 assert(ES->getTargetFlags() == 0 &&
939 "Unexpected target flags on generic ExternalSymbolSDNode");
940 // Set the TargetFlags to 0x1 which indicates that this is a "function"
941 // symbol rather than a data symbol. We do this unconditionally even though
942 // we don't know anything about the symbol other than its name, because all
943 // external symbols used in target-independent SelectionDAG code are for
944 // functions.
Heejin Ahnf208f632018-09-05 01:27:38 +0000945 return DAG.getNode(
946 WebAssemblyISD::Wrapper, DL, VT,
947 DAG.getTargetExternalSymbol(ES->getSymbol(), VT,
948 WebAssemblyII::MO_SYMBOL_FUNCTION));
Dan Gohman2c8fe6a2015-11-25 16:44:29 +0000949}
950
Dan Gohman950a13c2015-09-16 16:51:30 +0000951SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
952 SelectionDAG &DAG) const {
953 // There's no need for a Wrapper node because we always incorporate a jump
Dan Gohman14026062016-03-08 03:18:12 +0000954 // table operand into a BR_TABLE instruction, rather than ever
Dan Gohmanbb7ce8e2015-11-20 03:02:49 +0000955 // materializing it in a register.
Dan Gohman950a13c2015-09-16 16:51:30 +0000956 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
957 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
958 JT->getTargetFlags());
959}
960
961SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
962 SelectionDAG &DAG) const {
963 SDLoc DL(Op);
964 SDValue Chain = Op.getOperand(0);
965 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
966 SDValue Index = Op.getOperand(2);
967 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
968
969 SmallVector<SDValue, 8> Ops;
970 Ops.push_back(Chain);
971 Ops.push_back(Index);
972
973 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
974 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
975
Dan Gohman14026062016-03-08 03:18:12 +0000976 // Add an operand for each case.
Heejin Ahnf208f632018-09-05 01:27:38 +0000977 for (auto MBB : MBBs)
978 Ops.push_back(DAG.getBasicBlock(MBB));
Dan Gohman14026062016-03-08 03:18:12 +0000979
Dan Gohman950a13c2015-09-16 16:51:30 +0000980 // TODO: For now, we just pick something arbitrary for a default case for now.
981 // We really want to sniff out the guard and put in the real default case (and
982 // delete the guard).
983 Ops.push_back(DAG.getBasicBlock(MBBs[0]));
984
Dan Gohman14026062016-03-08 03:18:12 +0000985 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
Dan Gohman950a13c2015-09-16 16:51:30 +0000986}
987
Dan Gohman35bfb242015-12-04 23:22:35 +0000988SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
989 SelectionDAG &DAG) const {
990 SDLoc DL(Op);
991 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
992
Derek Schuff27501e22016-02-10 19:51:04 +0000993 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
Dan Gohman35bfb242015-12-04 23:22:35 +0000994 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
Derek Schuff27501e22016-02-10 19:51:04 +0000995
996 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
997 MFI->getVarargBufferVreg(), PtrVT);
998 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
Derek Schuff1a946e42016-07-15 19:35:43 +0000999 MachinePointerInfo(SV), 0);
Dan Gohman35bfb242015-12-04 23:22:35 +00001000}
1001
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +00001002SDValue
1003WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
1004 SelectionDAG &DAG) const {
1005 unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
1006 SDLoc DL(Op);
1007 switch (IntNo) {
1008 default:
1009 return {}; // Don't custom lower most intrinsics.
Thomas Lively5d461c92018-10-03 23:02:23 +00001010
Heejin Ahn24faf852018-10-25 23:55:10 +00001011 case Intrinsic::wasm_lsda: {
1012 MachineFunction &MF = DAG.getMachineFunction();
1013 EVT VT = Op.getValueType();
1014 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
1015 MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
1016 auto &Context = MF.getMMI().getContext();
1017 MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
1018 Twine(MF.getFunctionNumber()));
1019 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1020 DAG.getMCSymbol(S, PtrVT));
1021 }
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +00001022 }
1023}
1024
Thomas Livelya0d25812018-09-07 21:54:46 +00001025SDValue
1026WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
1027 SelectionDAG &DAG) const {
1028 SDLoc DL(Op);
1029 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
1030 MVT VecType = Op.getOperand(0).getSimpleValueType();
1031 assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
1032 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
1033
1034 // Space for two vector args and sixteen mask indices
1035 SDValue Ops[18];
1036 size_t OpIdx = 0;
1037 Ops[OpIdx++] = Op.getOperand(0);
1038 Ops[OpIdx++] = Op.getOperand(1);
1039
1040 // Expand mask indices to byte indices and materialize them as operands
1041 for (size_t I = 0, Lanes = Mask.size(); I < Lanes; ++I) {
1042 for (size_t J = 0; J < LaneBytes; ++J) {
Thomas Lively11a332d02018-10-19 19:08:06 +00001043 // Lower undefs (represented by -1 in mask) to zero
1044 uint64_t ByteIndex =
1045 Mask[I] == -1 ? 0 : (uint64_t)Mask[I] * LaneBytes + J;
1046 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
Thomas Livelya0d25812018-09-07 21:54:46 +00001047 }
1048 }
1049
Thomas Livelyed951342018-10-24 23:27:40 +00001050 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
Thomas Livelya0d25812018-09-07 21:54:46 +00001051}
1052
Thomas Lively55735d52018-10-20 01:31:18 +00001053SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
1054 SelectionDAG &DAG) const {
1055 SDLoc DL(Op);
1056 auto *ShiftVec = dyn_cast<BuildVectorSDNode>(Op.getOperand(1).getNode());
1057 APInt SplatValue, SplatUndef;
1058 unsigned SplatBitSize;
1059 bool HasAnyUndefs;
1060 if (!ShiftVec || !ShiftVec->isConstantSplat(SplatValue, SplatUndef,
1061 SplatBitSize, HasAnyUndefs))
1062 return Op;
1063 unsigned Opcode;
1064 switch (Op.getOpcode()) {
1065 case ISD::SHL:
1066 Opcode = WebAssemblyISD::VEC_SHL;
1067 break;
1068 case ISD::SRA:
1069 Opcode = WebAssemblyISD::VEC_SHR_S;
1070 break;
1071 case ISD::SRL:
1072 Opcode = WebAssemblyISD::VEC_SHR_U;
1073 break;
1074 default:
1075 llvm_unreachable("unexpected opcode");
1076 return Op;
1077 }
1078 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0),
1079 DAG.getConstant(SplatValue.trunc(32), DL, MVT::i32));
1080}
1081
Dan Gohman10e730a2015-06-29 23:51:55 +00001082//===----------------------------------------------------------------------===//
1083// WebAssembly Optimization Hooks
1084//===----------------------------------------------------------------------===//