1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel 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 /// \brief This file defines the WebAssembly-specific support for the FastISel
12 /// class. Some of the target-specific code is generated by tablegen in the file
13 /// WebAssemblyGenFastISel.inc, which is #included here.
14 ///
15 /// TODO: kill flags
16 ///
17 //===----------------------------------------------------------------------===//
18
19 #include "WebAssembly.h"
20 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
21 #include "WebAssemblyMachineFunctionInfo.h"
22 #include "WebAssemblySubtarget.h"
23 #include "WebAssemblyTargetMachine.h"
24 #include "llvm/Analysis/BranchProbabilityInfo.h"
25 #include "llvm/CodeGen/FastISel.h"
26 #include "llvm/CodeGen/FunctionLoweringInfo.h"
27 #include "llvm/CodeGen/MachineConstantPool.h"
28 #include "llvm/CodeGen/MachineFrameInfo.h"
29 #include "llvm/CodeGen/MachineInstrBuilder.h"
30 #include "llvm/CodeGen/MachineRegisterInfo.h"
31 #include "llvm/IR/DataLayout.h"
32 #include "llvm/IR/DerivedTypes.h"
33 #include "llvm/IR/Function.h"
34 #include "llvm/IR/GetElementPtrTypeIterator.h"
35 #include "llvm/IR/GlobalAlias.h"
36 #include "llvm/IR/GlobalVariable.h"
37 #include "llvm/IR/Instructions.h"
38 #include "llvm/IR/IntrinsicInst.h"
39 #include "llvm/IR/Operator.h"
40 using namespace llvm;
41
42 #define DEBUG_TYPE "wasm-fastisel"
43
44 namespace {
45
46 class WebAssemblyFastISel final : public FastISel {
47 // All possible address modes.
48 class Address {
49 public:
50 typedef enum { RegBase, FrameIndexBase } BaseKind;
51
52 private:
53 BaseKind Kind;
54 union {
55 unsigned Reg;
56 int FI;
57 } Base;
58
59 int64_t Offset;
60
61 const GlobalValue *GV;
62
63 public:
64 // Innocuous defaults for our address.
Address()65 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
setKind(BaseKind K)66 void setKind(BaseKind K) { Kind = K; }
getKind() const67 BaseKind getKind() const { return Kind; }
isRegBase() const68 bool isRegBase() const { return Kind == RegBase; }
isFIBase() const69 bool isFIBase() const { return Kind == FrameIndexBase; }
setReg(unsigned Reg)70 void setReg(unsigned Reg) {
71 assert(isRegBase() && "Invalid base register access!");
72 Base.Reg = Reg;
73 }
getReg() const74 unsigned getReg() const {
75 assert(isRegBase() && "Invalid base register access!");
76 return Base.Reg;
77 }
setFI(unsigned FI)78 void setFI(unsigned FI) {
79 assert(isFIBase() && "Invalid base frame index access!");
80 Base.FI = FI;
81 }
getFI() const82 unsigned getFI() const {
83 assert(isFIBase() && "Invalid base frame index access!");
84 return Base.FI;
85 }
86
setOffset(int64_t Offset_)87 void setOffset(int64_t Offset_) { Offset = Offset_; }
getOffset() const88 int64_t getOffset() const { return Offset; }
setGlobalValue(const GlobalValue * G)89 void setGlobalValue(const GlobalValue *G) { GV = G; }
getGlobalValue() const90 const GlobalValue *getGlobalValue() const { return GV; }
91 };
92
93 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
94 /// right decision when generating code for different targets.
95 const WebAssemblySubtarget *Subtarget;
96 LLVMContext *Context;
97
98 private:
99 // Utility helper routines
getSimpleType(Type * Ty)100 MVT::SimpleValueType getSimpleType(Type *Ty) {
101 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
102 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
103 MVT::INVALID_SIMPLE_VALUE_TYPE;
104 }
getLegalType(MVT::SimpleValueType VT)105 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
106 switch (VT) {
107 case MVT::i1:
108 case MVT::i8:
109 case MVT::i16:
110 return MVT::i32;
111 case MVT::i32:
112 case MVT::i64:
113 case MVT::f32:
114 case MVT::f64:
115 return VT;
116 default:
117 break;
118 }
119 return MVT::INVALID_SIMPLE_VALUE_TYPE;
120 }
121 bool computeAddress(const Value *Obj, Address &Addr);
122 void materializeLoadStoreOperands(Address &Addr);
123 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
124 MachineMemOperand *MMO);
125 unsigned maskI1Value(unsigned Reg, const Value *V);
126 unsigned getRegForI1Value(const Value *V, bool &Not);
127 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
128 MVT::SimpleValueType From);
129 unsigned signExtendToI32(unsigned Reg, const Value *V,
130 MVT::SimpleValueType From);
131 unsigned zeroExtend(unsigned Reg, const Value *V,
132 MVT::SimpleValueType From,
133 MVT::SimpleValueType To);
134 unsigned signExtend(unsigned Reg, const Value *V,
135 MVT::SimpleValueType From,
136 MVT::SimpleValueType To);
137 unsigned getRegForUnsignedValue(const Value *V);
138 unsigned getRegForSignedValue(const Value *V);
139 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
140 unsigned notValue(unsigned Reg);
141 unsigned copyValue(unsigned Reg);
142
143 // Backend specific FastISel code.
144 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
145 unsigned fastMaterializeConstant(const Constant *C) override;
146 bool fastLowerArguments() override;
147
148 // Selection routines.
149 bool selectCall(const Instruction *I);
150 bool selectSelect(const Instruction *I);
151 bool selectTrunc(const Instruction *I);
152 bool selectZExt(const Instruction *I);
153 bool selectSExt(const Instruction *I);
154 bool selectICmp(const Instruction *I);
155 bool selectFCmp(const Instruction *I);
156 bool selectBitCast(const Instruction *I);
157 bool selectLoad(const Instruction *I);
158 bool selectStore(const Instruction *I);
159 bool selectBr(const Instruction *I);
160 bool selectRet(const Instruction *I);
161 bool selectUnreachable(const Instruction *I);
162
163 public:
164 // Backend specific FastISel code.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)165 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
166 const TargetLibraryInfo *LibInfo)
167 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
168 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
169 Context = &FuncInfo.Fn->getContext();
170 }
171
172 bool fastSelectInstruction(const Instruction *I) override;
173
174 #include "WebAssemblyGenFastISel.inc"
175 };
176
177 } // end anonymous namespace
178
computeAddress(const Value * Obj,Address & Addr)179 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
180
181 const User *U = nullptr;
182 unsigned Opcode = Instruction::UserOp1;
183 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
184 // Don't walk into other basic blocks unless the object is an alloca from
185 // another block, otherwise it may not have a virtual register assigned.
186 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
187 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
188 Opcode = I->getOpcode();
189 U = I;
190 }
191 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
192 Opcode = C->getOpcode();
193 U = C;
194 }
195
196 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
197 if (Ty->getAddressSpace() > 255)
198 // Fast instruction selection doesn't support the special
199 // address spaces.
200 return false;
201
202 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
203 if (Addr.getGlobalValue())
204 return false;
205 Addr.setGlobalValue(GV);
206 return true;
207 }
208
209 switch (Opcode) {
210 default:
211 break;
212 case Instruction::BitCast: {
213 // Look through bitcasts.
214 return computeAddress(U->getOperand(0), Addr);
215 }
216 case Instruction::IntToPtr: {
217 // Look past no-op inttoptrs.
218 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
219 TLI.getPointerTy(DL))
220 return computeAddress(U->getOperand(0), Addr);
221 break;
222 }
223 case Instruction::PtrToInt: {
224 // Look past no-op ptrtoints.
225 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
226 return computeAddress(U->getOperand(0), Addr);
227 break;
228 }
229 case Instruction::GetElementPtr: {
230 Address SavedAddr = Addr;
231 uint64_t TmpOffset = Addr.getOffset();
232 // Iterate through the GEP folding the constants into offsets where
233 // we can.
234 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
235 GTI != E; ++GTI) {
236 const Value *Op = GTI.getOperand();
237 if (StructType *STy = dyn_cast<StructType>(*GTI)) {
238 const StructLayout *SL = DL.getStructLayout(STy);
239 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
240 TmpOffset += SL->getElementOffset(Idx);
241 } else {
242 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
243 for (;;) {
244 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
245 // Constant-offset addressing.
246 TmpOffset += CI->getSExtValue() * S;
247 break;
248 }
249 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
250 // An unscaled add of a register. Set it as the new base.
251 Addr.setReg(getRegForValue(Op));
252 break;
253 }
254 if (canFoldAddIntoGEP(U, Op)) {
255 // A compatible add with a constant operand. Fold the constant.
256 ConstantInt *CI =
257 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
258 TmpOffset += CI->getSExtValue() * S;
259 // Iterate on the other operand.
260 Op = cast<AddOperator>(Op)->getOperand(0);
261 continue;
262 }
263 // Unsupported
264 goto unsupported_gep;
265 }
266 }
267 }
268 // Try to grab the base operand now.
269 Addr.setOffset(TmpOffset);
270 if (computeAddress(U->getOperand(0), Addr))
271 return true;
272 // We failed, restore everything and try the other options.
273 Addr = SavedAddr;
274 unsupported_gep:
275 break;
276 }
277 case Instruction::Alloca: {
278 const AllocaInst *AI = cast<AllocaInst>(Obj);
279 DenseMap<const AllocaInst *, int>::iterator SI =
280 FuncInfo.StaticAllocaMap.find(AI);
281 if (SI != FuncInfo.StaticAllocaMap.end()) {
282 Addr.setKind(Address::FrameIndexBase);
283 Addr.setFI(SI->second);
284 return true;
285 }
286 break;
287 }
288 case Instruction::Add: {
289 // Adds of constants are common and easy enough.
290 const Value *LHS = U->getOperand(0);
291 const Value *RHS = U->getOperand(1);
292
293 if (isa<ConstantInt>(LHS))
294 std::swap(LHS, RHS);
295
296 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
297 Addr.setOffset(Addr.getOffset() + CI->getSExtValue());
298 return computeAddress(LHS, Addr);
299 }
300
301 Address Backup = Addr;
302 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
303 return true;
304 Addr = Backup;
305
306 break;
307 }
308 case Instruction::Sub: {
309 // Subs of constants are common and easy enough.
310 const Value *LHS = U->getOperand(0);
311 const Value *RHS = U->getOperand(1);
312
313 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
314 Addr.setOffset(Addr.getOffset() - CI->getSExtValue());
315 return computeAddress(LHS, Addr);
316 }
317 break;
318 }
319 }
320 Addr.setReg(getRegForValue(Obj));
321 return Addr.getReg() != 0;
322 }
323
materializeLoadStoreOperands(Address & Addr)324 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
325 if (Addr.isRegBase()) {
326 unsigned Reg = Addr.getReg();
327 if (Reg == 0) {
328 Reg = createResultReg(Subtarget->hasAddr64() ?
329 &WebAssembly::I64RegClass :
330 &WebAssembly::I32RegClass);
331 unsigned Opc = Subtarget->hasAddr64() ?
332 WebAssembly::CONST_I64 :
333 WebAssembly::CONST_I32;
334 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
335 .addImm(0);
336 Addr.setReg(Reg);
337 }
338 }
339 }
340
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)341 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
342 const MachineInstrBuilder &MIB,
343 MachineMemOperand *MMO) {
344 if (const GlobalValue *GV = Addr.getGlobalValue())
345 MIB.addGlobalAddress(GV, Addr.getOffset());
346 else
347 MIB.addImm(Addr.getOffset());
348
349 if (Addr.isRegBase())
350 MIB.addReg(Addr.getReg());
351 else
352 MIB.addFrameIndex(Addr.getFI());
353
354 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
355 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
356 MIB.addImm(0);
357
358 MIB.addMemOperand(MMO);
359 }
360
maskI1Value(unsigned Reg,const Value * V)361 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
362 return zeroExtendToI32(Reg, V, MVT::i1);
363 }
364
getRegForI1Value(const Value * V,bool & Not)365 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
366 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
367 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
368 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
369 Not = ICmp->isTrueWhenEqual();
370 return getRegForValue(ICmp->getOperand(0));
371 }
372
373 if (BinaryOperator::isNot(V)) {
374 Not = true;
375 return getRegForValue(BinaryOperator::getNotArgument(V));
376 }
377
378 Not = false;
379 return maskI1Value(getRegForValue(V), V);
380 }
381
zeroExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)382 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
383 MVT::SimpleValueType From) {
384 switch (From) {
385 case MVT::i1:
386 // If the value is naturally an i1, we don't need to mask it.
387 // TODO: Recursively examine selects, phis, and, or, xor, constants.
388 if (From == MVT::i1 && V != nullptr) {
389 if (isa<CmpInst>(V) ||
390 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
391 return copyValue(Reg);
392 }
393 case MVT::i8:
394 case MVT::i16:
395 break;
396 case MVT::i32:
397 return copyValue(Reg);
398 default:
399 return 0;
400 }
401
402 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
403 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
404 TII.get(WebAssembly::CONST_I32), Imm)
405 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
406
407 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
408 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
409 TII.get(WebAssembly::AND_I32), Result)
410 .addReg(Reg)
411 .addReg(Imm);
412
413 return Result;
414 }
415
signExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)416 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
417 MVT::SimpleValueType From) {
418 switch (From) {
419 case MVT::i1:
420 case MVT::i8:
421 case MVT::i16:
422 break;
423 case MVT::i32:
424 return copyValue(Reg);
425 default:
426 return 0;
427 }
428
429 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
430 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
431 TII.get(WebAssembly::CONST_I32), Imm)
432 .addImm(32 - MVT(From).getSizeInBits());
433
434 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
435 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
436 TII.get(WebAssembly::SHL_I32), Left)
437 .addReg(Reg)
438 .addReg(Imm);
439
440 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
441 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
442 TII.get(WebAssembly::SHR_S_I32), Right)
443 .addReg(Left)
444 .addReg(Imm);
445
446 return Right;
447 }
448
zeroExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)449 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
450 MVT::SimpleValueType From,
451 MVT::SimpleValueType To) {
452 if (To == MVT::i64) {
453 if (From == MVT::i64)
454 return copyValue(Reg);
455
456 Reg = zeroExtendToI32(Reg, V, From);
457
458 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
459 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
460 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
461 .addReg(Reg);
462 return Result;
463 }
464
465 return zeroExtendToI32(Reg, V, From);
466 }
467
signExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)468 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
469 MVT::SimpleValueType From,
470 MVT::SimpleValueType To) {
471 if (To == MVT::i64) {
472 if (From == MVT::i64)
473 return copyValue(Reg);
474
475 Reg = signExtendToI32(Reg, V, From);
476
477 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
478 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
479 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
480 .addReg(Reg);
481 return Result;
482 }
483
484 return signExtendToI32(Reg, V, From);
485 }
486
getRegForUnsignedValue(const Value * V)487 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
488 MVT::SimpleValueType From = getSimpleType(V->getType());
489 MVT::SimpleValueType To = getLegalType(From);
490 return zeroExtend(getRegForValue(V), V, From, To);
491 }
492
getRegForSignedValue(const Value * V)493 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
494 MVT::SimpleValueType From = getSimpleType(V->getType());
495 MVT::SimpleValueType To = getLegalType(From);
496 return zeroExtend(getRegForValue(V), V, From, To);
497 }
498
getRegForPromotedValue(const Value * V,bool IsSigned)499 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
500 bool IsSigned) {
501 return IsSigned ? getRegForSignedValue(V) :
502 getRegForUnsignedValue(V);
503 }
504
notValue(unsigned Reg)505 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
506 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
507
508 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
509 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
510 TII.get(WebAssembly::EQZ_I32), NotReg)
511 .addReg(Reg);
512 return NotReg;
513 }
514
copyValue(unsigned Reg)515 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
516 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
517 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
518 TII.get(WebAssembly::COPY), ResultReg)
519 .addReg(Reg);
520 return ResultReg;
521 }
522
fastMaterializeAlloca(const AllocaInst * AI)523 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
524 DenseMap<const AllocaInst *, int>::iterator SI =
525 FuncInfo.StaticAllocaMap.find(AI);
526
527 if (SI != FuncInfo.StaticAllocaMap.end()) {
528 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
529 &WebAssembly::I64RegClass :
530 &WebAssembly::I32RegClass);
531 unsigned Opc = Subtarget->hasAddr64() ?
532 WebAssembly::COPY_LOCAL_I64 :
533 WebAssembly::COPY_LOCAL_I32;
534 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
535 .addFrameIndex(SI->second);
536 return ResultReg;
537 }
538
539 return 0;
540 }
541
fastMaterializeConstant(const Constant * C)542 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
543 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
544 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
545 &WebAssembly::I64RegClass :
546 &WebAssembly::I32RegClass);
547 unsigned Opc = Subtarget->hasAddr64() ?
548 WebAssembly::CONST_I64 :
549 WebAssembly::CONST_I32;
550 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
551 .addGlobalAddress(GV);
552 return ResultReg;
553 }
554
555 // Let target-independent code handle it.
556 return 0;
557 }
558
fastLowerArguments()559 bool WebAssemblyFastISel::fastLowerArguments() {
560 if (!FuncInfo.CanLowerReturn)
561 return false;
562
563 const Function *F = FuncInfo.Fn;
564 if (F->isVarArg())
565 return false;
566
567 unsigned i = 0;
568 for (auto const &Arg : F->args()) {
569 const AttributeSet &Attrs = F->getAttributes();
570 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
571 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
572 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
573 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
574 Attrs.hasAttribute(i+1, Attribute::Nest))
575 return false;
576
577 Type *ArgTy = Arg.getType();
578 if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
579 return false;
580
581 unsigned Opc;
582 const TargetRegisterClass *RC;
583 switch (getSimpleType(ArgTy)) {
584 case MVT::i1:
585 case MVT::i8:
586 case MVT::i16:
587 case MVT::i32:
588 Opc = WebAssembly::ARGUMENT_I32;
589 RC = &WebAssembly::I32RegClass;
590 break;
591 case MVT::i64:
592 Opc = WebAssembly::ARGUMENT_I64;
593 RC = &WebAssembly::I64RegClass;
594 break;
595 case MVT::f32:
596 Opc = WebAssembly::ARGUMENT_F32;
597 RC = &WebAssembly::F32RegClass;
598 break;
599 case MVT::f64:
600 Opc = WebAssembly::ARGUMENT_F64;
601 RC = &WebAssembly::F64RegClass;
602 break;
603 default:
604 return false;
605 }
606 unsigned ResultReg = createResultReg(RC);
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
608 .addImm(i);
609 updateValueMap(&Arg, ResultReg);
610
611 ++i;
612 }
613
614 MRI.addLiveIn(WebAssembly::ARGUMENTS);
615
616 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
617 for (auto const &Arg : F->args())
618 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
619
620 return true;
621 }
622
selectCall(const Instruction * I)623 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
624 const CallInst *Call = cast<CallInst>(I);
625
626 if (Call->isMustTailCall() || Call->isInlineAsm() ||
627 Call->getFunctionType()->isVarArg())
628 return false;
629
630 Function *Func = Call->getCalledFunction();
631 if (Func && Func->isIntrinsic())
632 return false;
633
634 FunctionType *FuncTy = Call->getFunctionType();
635 unsigned Opc;
636 bool IsDirect = Func != nullptr;
637 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
638 unsigned ResultReg;
639 if (IsVoid) {
640 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::CALL_INDIRECT_VOID;
641 } else {
642 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
643 switch (RetTy) {
644 case MVT::i1:
645 case MVT::i8:
646 case MVT::i16:
647 case MVT::i32:
648 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::CALL_INDIRECT_I32;
649 ResultReg = createResultReg(&WebAssembly::I32RegClass);
650 break;
651 case MVT::i64:
652 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::CALL_INDIRECT_I64;
653 ResultReg = createResultReg(&WebAssembly::I64RegClass);
654 break;
655 case MVT::f32:
656 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::CALL_INDIRECT_F32;
657 ResultReg = createResultReg(&WebAssembly::F32RegClass);
658 break;
659 case MVT::f64:
660 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::CALL_INDIRECT_F64;
661 ResultReg = createResultReg(&WebAssembly::F64RegClass);
662 break;
663 default:
664 return false;
665 }
666 }
667
668 SmallVector<unsigned, 8> Args;
669 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
670 Value *V = Call->getArgOperand(i);
671 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
672 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
673 return false;
674
675 const AttributeSet &Attrs = Call->getAttributes();
676 if (Attrs.hasAttribute(i+1, Attribute::ByVal) ||
677 Attrs.hasAttribute(i+1, Attribute::SwiftSelf) ||
678 Attrs.hasAttribute(i+1, Attribute::SwiftError) ||
679 Attrs.hasAttribute(i+1, Attribute::InAlloca) ||
680 Attrs.hasAttribute(i+1, Attribute::Nest))
681 return false;
682
683 unsigned Reg;
684
685 if (Attrs.hasAttribute(i+1, Attribute::SExt))
686 Reg = getRegForSignedValue(V);
687 else if (Attrs.hasAttribute(i+1, Attribute::ZExt))
688 Reg = getRegForUnsignedValue(V);
689 else
690 Reg = getRegForValue(V);
691
692 if (Reg == 0)
693 return false;
694
695 Args.push_back(Reg);
696 }
697
698 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
699
700 if (!IsVoid)
701 MIB.addReg(ResultReg, RegState::Define);
702
703 if (IsDirect)
704 MIB.addGlobalAddress(Func);
705 else
706 MIB.addReg(getRegForValue(Call->getCalledValue()));
707
708 for (unsigned ArgReg : Args)
709 MIB.addReg(ArgReg);
710
711 if (!IsVoid)
712 updateValueMap(Call, ResultReg);
713 return true;
714 }
715
selectSelect(const Instruction * I)716 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
717 const SelectInst *Select = cast<SelectInst>(I);
718
719 bool Not;
720 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
721 if (CondReg == 0)
722 return false;
723
724 unsigned TrueReg = getRegForValue(Select->getTrueValue());
725 if (TrueReg == 0)
726 return false;
727
728 unsigned FalseReg = getRegForValue(Select->getFalseValue());
729 if (FalseReg == 0)
730 return false;
731
732 if (Not)
733 std::swap(TrueReg, FalseReg);
734
735 unsigned Opc;
736 const TargetRegisterClass *RC;
737 switch (getSimpleType(Select->getType())) {
738 case MVT::i1:
739 case MVT::i8:
740 case MVT::i16:
741 case MVT::i32:
742 Opc = WebAssembly::SELECT_I32;
743 RC = &WebAssembly::I32RegClass;
744 break;
745 case MVT::i64:
746 Opc = WebAssembly::SELECT_I64;
747 RC = &WebAssembly::I64RegClass;
748 break;
749 case MVT::f32:
750 Opc = WebAssembly::SELECT_F32;
751 RC = &WebAssembly::F32RegClass;
752 break;
753 case MVT::f64:
754 Opc = WebAssembly::SELECT_F64;
755 RC = &WebAssembly::F64RegClass;
756 break;
757 default:
758 return false;
759 }
760
761 unsigned ResultReg = createResultReg(RC);
762 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
763 .addReg(TrueReg)
764 .addReg(FalseReg)
765 .addReg(CondReg);
766
767 updateValueMap(Select, ResultReg);
768 return true;
769 }
770
selectTrunc(const Instruction * I)771 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
772 const TruncInst *Trunc = cast<TruncInst>(I);
773
774 unsigned Reg = getRegForValue(Trunc->getOperand(0));
775 if (Reg == 0)
776 return false;
777
778 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
779 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
780 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
781 TII.get(WebAssembly::I32_WRAP_I64), Result)
782 .addReg(Reg);
783 Reg = Result;
784 }
785
786 updateValueMap(Trunc, Reg);
787 return true;
788 }
789
selectZExt(const Instruction * I)790 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
791 const ZExtInst *ZExt = cast<ZExtInst>(I);
792
793 const Value *Op = ZExt->getOperand(0);
794 MVT::SimpleValueType From = getSimpleType(Op->getType());
795 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
796 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
797 if (Reg == 0)
798 return false;
799
800 updateValueMap(ZExt, Reg);
801 return true;
802 }
803
selectSExt(const Instruction * I)804 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
805 const SExtInst *SExt = cast<SExtInst>(I);
806
807 const Value *Op = SExt->getOperand(0);
808 MVT::SimpleValueType From = getSimpleType(Op->getType());
809 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
810 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
811 if (Reg == 0)
812 return false;
813
814 updateValueMap(SExt, Reg);
815 return true;
816 }
817
selectICmp(const Instruction * I)818 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
819 const ICmpInst *ICmp = cast<ICmpInst>(I);
820
821 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
822 unsigned Opc;
823 bool isSigned = false;
824 switch (ICmp->getPredicate()) {
825 case ICmpInst::ICMP_EQ:
826 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
827 break;
828 case ICmpInst::ICMP_NE:
829 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
830 break;
831 case ICmpInst::ICMP_UGT:
832 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
833 break;
834 case ICmpInst::ICMP_UGE:
835 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
836 break;
837 case ICmpInst::ICMP_ULT:
838 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
839 break;
840 case ICmpInst::ICMP_ULE:
841 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
842 break;
843 case ICmpInst::ICMP_SGT:
844 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
845 isSigned = true;
846 break;
847 case ICmpInst::ICMP_SGE:
848 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
849 isSigned = true;
850 break;
851 case ICmpInst::ICMP_SLT:
852 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
853 isSigned = true;
854 break;
855 case ICmpInst::ICMP_SLE:
856 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
857 isSigned = true;
858 break;
859 default: return false;
860 }
861
862 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
863 if (LHS == 0)
864 return false;
865
866 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
867 if (RHS == 0)
868 return false;
869
870 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
871 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
872 .addReg(LHS)
873 .addReg(RHS);
874 updateValueMap(ICmp, ResultReg);
875 return true;
876 }
877
selectFCmp(const Instruction * I)878 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
879 const FCmpInst *FCmp = cast<FCmpInst>(I);
880
881 unsigned LHS = getRegForValue(FCmp->getOperand(0));
882 if (LHS == 0)
883 return false;
884
885 unsigned RHS = getRegForValue(FCmp->getOperand(1));
886 if (RHS == 0)
887 return false;
888
889 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
890 unsigned Opc;
891 bool Not = false;
892 switch (FCmp->getPredicate()) {
893 case FCmpInst::FCMP_OEQ:
894 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
895 break;
896 case FCmpInst::FCMP_UNE:
897 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
898 break;
899 case FCmpInst::FCMP_OGT:
900 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
901 break;
902 case FCmpInst::FCMP_OGE:
903 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
904 break;
905 case FCmpInst::FCMP_OLT:
906 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
907 break;
908 case FCmpInst::FCMP_OLE:
909 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
910 break;
911 case FCmpInst::FCMP_UGT:
912 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
913 Not = true;
914 break;
915 case FCmpInst::FCMP_UGE:
916 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
917 Not = true;
918 break;
919 case FCmpInst::FCMP_ULT:
920 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
921 Not = true;
922 break;
923 case FCmpInst::FCMP_ULE:
924 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
925 Not = true;
926 break;
927 default:
928 return false;
929 }
930
931 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
932 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
933 .addReg(LHS)
934 .addReg(RHS);
935
936 if (Not)
937 ResultReg = notValue(ResultReg);
938
939 updateValueMap(FCmp, ResultReg);
940 return true;
941 }
942
selectBitCast(const Instruction * I)943 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
944 // Target-independent code can handle this, except it doesn't set the dead
945 // flag on the ARGUMENTS clobber, so we have to do that manually in order
946 // to satisfy code that expects this of isBitcast() instructions.
947 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
948 EVT RetVT = TLI.getValueType(DL, I->getType());
949 if (!VT.isSimple() || !RetVT.isSimple())
950 return false;
951
952 if (VT == RetVT) {
953 // No-op bitcast.
954 updateValueMap(I, getRegForValue(I->getOperand(0)));
955 return true;
956 }
957
958 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
959 getRegForValue(I->getOperand(0)),
960 I->getOperand(0)->hasOneUse());
961 if (!Reg)
962 return false;
963 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
964 --Iter;
965 assert(Iter->isBitcast());
966 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
967 updateValueMap(I, Reg);
968 return true;
969 }
970
selectLoad(const Instruction * I)971 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
972 const LoadInst *Load = cast<LoadInst>(I);
973 if (Load->isAtomic())
974 return false;
975
976 Address Addr;
977 if (!computeAddress(Load->getPointerOperand(), Addr))
978 return false;
979
980 // TODO: Fold a following sign-/zero-extend into the load instruction.
981
982 unsigned Opc;
983 const TargetRegisterClass *RC;
984 switch (getSimpleType(Load->getType())) {
985 case MVT::i1:
986 case MVT::i8:
987 Opc = WebAssembly::LOAD8_U_I32;
988 RC = &WebAssembly::I32RegClass;
989 break;
990 case MVT::i16:
991 Opc = WebAssembly::LOAD16_U_I32;
992 RC = &WebAssembly::I32RegClass;
993 break;
994 case MVT::i32:
995 Opc = WebAssembly::LOAD_I32;
996 RC = &WebAssembly::I32RegClass;
997 break;
998 case MVT::i64:
999 Opc = WebAssembly::LOAD_I64;
1000 RC = &WebAssembly::I64RegClass;
1001 break;
1002 case MVT::f32:
1003 Opc = WebAssembly::LOAD_F32;
1004 RC = &WebAssembly::F32RegClass;
1005 break;
1006 case MVT::f64:
1007 Opc = WebAssembly::LOAD_F64;
1008 RC = &WebAssembly::F64RegClass;
1009 break;
1010 default:
1011 return false;
1012 }
1013
1014 materializeLoadStoreOperands(Addr);
1015
1016 unsigned ResultReg = createResultReg(RC);
1017 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1018 ResultReg);
1019
1020 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1021
1022 updateValueMap(Load, ResultReg);
1023 return true;
1024 }
1025
selectStore(const Instruction * I)1026 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1027 const StoreInst *Store = cast<StoreInst>(I);
1028 if (Store->isAtomic())
1029 return false;
1030
1031 Address Addr;
1032 if (!computeAddress(Store->getPointerOperand(), Addr))
1033 return false;
1034
1035 unsigned Opc;
1036 const TargetRegisterClass *RC;
1037 bool VTIsi1 = false;
1038 switch (getSimpleType(Store->getValueOperand()->getType())) {
1039 case MVT::i1:
1040 VTIsi1 = true;
1041 case MVT::i8:
1042 Opc = WebAssembly::STORE8_I32;
1043 RC = &WebAssembly::I32RegClass;
1044 break;
1045 case MVT::i16:
1046 Opc = WebAssembly::STORE16_I32;
1047 RC = &WebAssembly::I32RegClass;
1048 break;
1049 case MVT::i32:
1050 Opc = WebAssembly::STORE_I32;
1051 RC = &WebAssembly::I32RegClass;
1052 break;
1053 case MVT::i64:
1054 Opc = WebAssembly::STORE_I64;
1055 RC = &WebAssembly::I64RegClass;
1056 break;
1057 case MVT::f32:
1058 Opc = WebAssembly::STORE_F32;
1059 RC = &WebAssembly::F32RegClass;
1060 break;
1061 case MVT::f64:
1062 Opc = WebAssembly::STORE_F64;
1063 RC = &WebAssembly::F64RegClass;
1064 break;
1065 default: return false;
1066 }
1067
1068 materializeLoadStoreOperands(Addr);
1069
1070 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1071 if (VTIsi1)
1072 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1073
1074 unsigned ResultReg = createResultReg(RC);
1075 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1076 ResultReg);
1077
1078 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1079
1080 MIB.addReg(ValueReg);
1081 return true;
1082 }
1083
selectBr(const Instruction * I)1084 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1085 const BranchInst *Br = cast<BranchInst>(I);
1086 if (Br->isUnconditional()) {
1087 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1088 fastEmitBranch(MSucc, Br->getDebugLoc());
1089 return true;
1090 }
1091
1092 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1093 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1094
1095 bool Not;
1096 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1097
1098 unsigned Opc = WebAssembly::BR_IF;
1099 if (Not)
1100 Opc = WebAssembly::BR_UNLESS;
1101
1102 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1103 .addMBB(TBB)
1104 .addReg(CondReg);
1105
1106 finishCondBranch(Br->getParent(), TBB, FBB);
1107 return true;
1108 }
1109
selectRet(const Instruction * I)1110 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1111 if (!FuncInfo.CanLowerReturn)
1112 return false;
1113
1114 const ReturnInst *Ret = cast<ReturnInst>(I);
1115
1116 if (Ret->getNumOperands() == 0) {
1117 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1118 TII.get(WebAssembly::RETURN_VOID));
1119 return true;
1120 }
1121
1122 Value *RV = Ret->getOperand(0);
1123 unsigned Opc;
1124 switch (getSimpleType(RV->getType())) {
1125 case MVT::i1: case MVT::i8:
1126 case MVT::i16: case MVT::i32:
1127 Opc = WebAssembly::RETURN_I32;
1128 break;
1129 case MVT::i64:
1130 Opc = WebAssembly::RETURN_I64;
1131 break;
1132 case MVT::f32: Opc = WebAssembly::RETURN_F32; break;
1133 case MVT::f64: Opc = WebAssembly::RETURN_F64; break;
1134 default: return false;
1135 }
1136
1137 unsigned Reg;
1138 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1139 Reg = getRegForSignedValue(RV);
1140 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1141 Reg = getRegForUnsignedValue(RV);
1142 else
1143 Reg = getRegForValue(RV);
1144
1145 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1146 return true;
1147 }
1148
selectUnreachable(const Instruction * I)1149 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1150 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1151 TII.get(WebAssembly::UNREACHABLE));
1152 return true;
1153 }
1154
fastSelectInstruction(const Instruction * I)1155 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1156 switch (I->getOpcode()) {
1157 case Instruction::Call:
1158 if (selectCall(I))
1159 return true;
1160 break;
1161 case Instruction::Select: return selectSelect(I);
1162 case Instruction::Trunc: return selectTrunc(I);
1163 case Instruction::ZExt: return selectZExt(I);
1164 case Instruction::SExt: return selectSExt(I);
1165 case Instruction::ICmp: return selectICmp(I);
1166 case Instruction::FCmp: return selectFCmp(I);
1167 case Instruction::BitCast: return selectBitCast(I);
1168 case Instruction::Load: return selectLoad(I);
1169 case Instruction::Store: return selectStore(I);
1170 case Instruction::Br: return selectBr(I);
1171 case Instruction::Ret: return selectRet(I);
1172 case Instruction::Unreachable: return selectUnreachable(I);
1173 default: break;
1174 }
1175
1176 // Fall back to target-independent instruction selection.
1177 return selectOperator(I, I->getOpcode());
1178 }
1179
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)1180 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1181 const TargetLibraryInfo *LibInfo) {
1182 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1183 }
1184