1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
17 //===----------------------------------------------------------------------===//
19 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20 #include "WebAssembly.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"
42 #define DEBUG_TYPE "wasm-fastisel"
46 class WebAssemblyFastISel final : public FastISel {
47 // All possible address modes.
50 typedef enum { RegBase, FrameIndexBase } BaseKind;
61 const GlobalValue *GV;
64 // Innocuous defaults for our address.
65 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
66 void setKind(BaseKind K) {
67 assert(!isSet() && "Can't change kind with non-zero base");
70 BaseKind getKind() const { return Kind; }
71 bool isRegBase() const { return Kind == RegBase; }
72 bool isFIBase() const { return Kind == FrameIndexBase; }
73 void setReg(unsigned Reg) {
74 assert(isRegBase() && "Invalid base register access!");
75 assert(Base.Reg == 0 && "Overwriting non-zero register");
78 unsigned getReg() const {
79 assert(isRegBase() && "Invalid base register access!");
82 void setFI(unsigned FI) {
83 assert(isFIBase() && "Invalid base frame index access!");
84 assert(Base.FI == 0 && "Overwriting non-zero frame index");
87 unsigned getFI() const {
88 assert(isFIBase() && "Invalid base frame index access!");
92 void setOffset(int64_t Offset_) {
93 assert(Offset_ >= 0 && "Offsets must be non-negative");
96 int64_t getOffset() const { return Offset; }
97 void setGlobalValue(const GlobalValue *G) { GV = G; }
98 const GlobalValue *getGlobalValue() const { return GV; }
101 return Base.Reg != 0;
108 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
109 /// right decision when generating code for different targets.
110 const WebAssemblySubtarget *Subtarget;
111 LLVMContext *Context;
114 // Utility helper routines
115 MVT::SimpleValueType getSimpleType(Type *Ty) {
116 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
117 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
118 MVT::INVALID_SIMPLE_VALUE_TYPE;
120 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
137 if (Subtarget->hasSIMD128())
143 return MVT::INVALID_SIMPLE_VALUE_TYPE;
145 bool computeAddress(const Value *Obj, Address &Addr);
146 void materializeLoadStoreOperands(Address &Addr);
147 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
148 MachineMemOperand *MMO);
149 unsigned maskI1Value(unsigned Reg, const Value *V);
150 unsigned getRegForI1Value(const Value *V, bool &Not);
151 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
152 MVT::SimpleValueType From);
153 unsigned signExtendToI32(unsigned Reg, const Value *V,
154 MVT::SimpleValueType From);
155 unsigned zeroExtend(unsigned Reg, const Value *V,
156 MVT::SimpleValueType From,
157 MVT::SimpleValueType To);
158 unsigned signExtend(unsigned Reg, const Value *V,
159 MVT::SimpleValueType From,
160 MVT::SimpleValueType To);
161 unsigned getRegForUnsignedValue(const Value *V);
162 unsigned getRegForSignedValue(const Value *V);
163 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
164 unsigned notValue(unsigned Reg);
165 unsigned copyValue(unsigned Reg);
167 // Backend specific FastISel code.
168 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
169 unsigned fastMaterializeConstant(const Constant *C) override;
170 bool fastLowerArguments() override;
172 // Selection routines.
173 bool selectCall(const Instruction *I);
174 bool selectSelect(const Instruction *I);
175 bool selectTrunc(const Instruction *I);
176 bool selectZExt(const Instruction *I);
177 bool selectSExt(const Instruction *I);
178 bool selectICmp(const Instruction *I);
179 bool selectFCmp(const Instruction *I);
180 bool selectBitCast(const Instruction *I);
181 bool selectLoad(const Instruction *I);
182 bool selectStore(const Instruction *I);
183 bool selectBr(const Instruction *I);
184 bool selectRet(const Instruction *I);
185 bool selectUnreachable(const Instruction *I);
188 // Backend specific FastISel code.
189 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
190 const TargetLibraryInfo *LibInfo)
191 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
192 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
193 Context = &FuncInfo.Fn->getContext();
196 bool fastSelectInstruction(const Instruction *I) override;
198 #include "WebAssemblyGenFastISel.inc"
201 } // end anonymous namespace
203 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
205 const User *U = nullptr;
206 unsigned Opcode = Instruction::UserOp1;
207 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
208 // Don't walk into other basic blocks unless the object is an alloca from
209 // another block, otherwise it may not have a virtual register assigned.
210 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
211 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
212 Opcode = I->getOpcode();
215 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
216 Opcode = C->getOpcode();
220 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
221 if (Ty->getAddressSpace() > 255)
222 // Fast instruction selection doesn't support the special
226 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
227 if (Addr.getGlobalValue())
229 Addr.setGlobalValue(GV);
236 case Instruction::BitCast: {
237 // Look through bitcasts.
238 return computeAddress(U->getOperand(0), Addr);
240 case Instruction::IntToPtr: {
241 // Look past no-op inttoptrs.
242 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
243 TLI.getPointerTy(DL))
244 return computeAddress(U->getOperand(0), Addr);
247 case Instruction::PtrToInt: {
248 // Look past no-op ptrtoints.
249 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
250 return computeAddress(U->getOperand(0), Addr);
253 case Instruction::GetElementPtr: {
254 Address SavedAddr = Addr;
255 uint64_t TmpOffset = Addr.getOffset();
256 // Non-inbounds geps can wrap; wasm's offsets can't.
257 if (!cast<GEPOperator>(U)->isInBounds())
258 goto unsupported_gep;
259 // Iterate through the GEP folding the constants into offsets where
261 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
263 const Value *Op = GTI.getOperand();
264 if (StructType *STy = GTI.getStructTypeOrNull()) {
265 const StructLayout *SL = DL.getStructLayout(STy);
266 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
267 TmpOffset += SL->getElementOffset(Idx);
269 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
271 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
272 // Constant-offset addressing.
273 TmpOffset += CI->getSExtValue() * S;
276 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
277 // An unscaled add of a register. Set it as the new base.
278 Addr.setReg(getRegForValue(Op));
281 if (canFoldAddIntoGEP(U, Op)) {
282 // A compatible add with a constant operand. Fold the constant.
284 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
285 TmpOffset += CI->getSExtValue() * S;
286 // Iterate on the other operand.
287 Op = cast<AddOperator>(Op)->getOperand(0);
291 goto unsupported_gep;
295 // Don't fold in negative offsets.
296 if (int64_t(TmpOffset) >= 0) {
297 // Try to grab the base operand now.
298 Addr.setOffset(TmpOffset);
299 if (computeAddress(U->getOperand(0), Addr))
302 // We failed, restore everything and try the other options.
307 case Instruction::Alloca: {
308 const AllocaInst *AI = cast<AllocaInst>(Obj);
309 DenseMap<const AllocaInst *, int>::iterator SI =
310 FuncInfo.StaticAllocaMap.find(AI);
311 if (SI != FuncInfo.StaticAllocaMap.end()) {
315 Addr.setKind(Address::FrameIndexBase);
316 Addr.setFI(SI->second);
321 case Instruction::Add: {
322 // Adds of constants are common and easy enough.
323 const Value *LHS = U->getOperand(0);
324 const Value *RHS = U->getOperand(1);
326 if (isa<ConstantInt>(LHS))
329 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
330 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
331 if (int64_t(TmpOffset) >= 0) {
332 Addr.setOffset(TmpOffset);
333 return computeAddress(LHS, Addr);
337 Address Backup = Addr;
338 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
344 case Instruction::Sub: {
345 // Subs of constants are common and easy enough.
346 const Value *LHS = U->getOperand(0);
347 const Value *RHS = U->getOperand(1);
349 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
350 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
351 if (TmpOffset >= 0) {
352 Addr.setOffset(TmpOffset);
353 return computeAddress(LHS, Addr);
362 Addr.setReg(getRegForValue(Obj));
363 return Addr.getReg() != 0;
366 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
367 if (Addr.isRegBase()) {
368 unsigned Reg = Addr.getReg();
370 Reg = createResultReg(Subtarget->hasAddr64() ?
371 &WebAssembly::I64RegClass :
372 &WebAssembly::I32RegClass);
373 unsigned Opc = Subtarget->hasAddr64() ?
374 WebAssembly::CONST_I64 :
375 WebAssembly::CONST_I32;
376 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
383 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
384 const MachineInstrBuilder &MIB,
385 MachineMemOperand *MMO) {
386 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
387 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
390 if (const GlobalValue *GV = Addr.getGlobalValue())
391 MIB.addGlobalAddress(GV, Addr.getOffset());
393 MIB.addImm(Addr.getOffset());
395 if (Addr.isRegBase())
396 MIB.addReg(Addr.getReg());
398 MIB.addFrameIndex(Addr.getFI());
400 MIB.addMemOperand(MMO);
403 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
404 return zeroExtendToI32(Reg, V, MVT::i1);
407 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
408 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
409 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
410 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
411 Not = ICmp->isTrueWhenEqual();
412 return getRegForValue(ICmp->getOperand(0));
415 if (BinaryOperator::isNot(V)) {
417 return getRegForValue(BinaryOperator::getNotArgument(V));
421 return maskI1Value(getRegForValue(V), V);
424 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
425 MVT::SimpleValueType From) {
431 // If the value is naturally an i1, we don't need to mask it.
432 // TODO: Recursively examine selects, phis, and, or, xor, constants.
433 if (From == MVT::i1 && V != nullptr) {
434 if (isa<CmpInst>(V) ||
435 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
436 return copyValue(Reg);
442 return copyValue(Reg);
447 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
448 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
449 TII.get(WebAssembly::CONST_I32), Imm)
450 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
452 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
453 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
454 TII.get(WebAssembly::AND_I32), Result)
461 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
462 MVT::SimpleValueType From) {
472 return copyValue(Reg);
477 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
478 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
479 TII.get(WebAssembly::CONST_I32), Imm)
480 .addImm(32 - MVT(From).getSizeInBits());
482 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
483 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
484 TII.get(WebAssembly::SHL_I32), Left)
488 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
489 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
490 TII.get(WebAssembly::SHR_S_I32), Right)
497 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
498 MVT::SimpleValueType From,
499 MVT::SimpleValueType To) {
500 if (To == MVT::i64) {
501 if (From == MVT::i64)
502 return copyValue(Reg);
504 Reg = zeroExtendToI32(Reg, V, From);
506 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
507 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
508 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
513 return zeroExtendToI32(Reg, V, From);
516 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
517 MVT::SimpleValueType From,
518 MVT::SimpleValueType To) {
519 if (To == MVT::i64) {
520 if (From == MVT::i64)
521 return copyValue(Reg);
523 Reg = signExtendToI32(Reg, V, From);
525 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
526 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
527 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
532 return signExtendToI32(Reg, V, From);
535 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
536 MVT::SimpleValueType From = getSimpleType(V->getType());
537 MVT::SimpleValueType To = getLegalType(From);
538 return zeroExtend(getRegForValue(V), V, From, To);
541 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
542 MVT::SimpleValueType From = getSimpleType(V->getType());
543 MVT::SimpleValueType To = getLegalType(From);
544 return zeroExtend(getRegForValue(V), V, From, To);
547 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
549 return IsSigned ? getRegForSignedValue(V) :
550 getRegForUnsignedValue(V);
553 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
554 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
556 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
557 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
558 TII.get(WebAssembly::EQZ_I32), NotReg)
563 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
564 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
565 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
566 TII.get(WebAssembly::COPY), ResultReg)
571 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
572 DenseMap<const AllocaInst *, int>::iterator SI =
573 FuncInfo.StaticAllocaMap.find(AI);
575 if (SI != FuncInfo.StaticAllocaMap.end()) {
576 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
577 &WebAssembly::I64RegClass :
578 &WebAssembly::I32RegClass);
579 unsigned Opc = Subtarget->hasAddr64() ?
580 WebAssembly::COPY_I64 :
581 WebAssembly::COPY_I32;
582 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
583 .addFrameIndex(SI->second);
590 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
591 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
592 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
593 &WebAssembly::I64RegClass :
594 &WebAssembly::I32RegClass);
595 unsigned Opc = Subtarget->hasAddr64() ?
596 WebAssembly::CONST_I64 :
597 WebAssembly::CONST_I32;
598 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
599 .addGlobalAddress(GV);
603 // Let target-independent code handle it.
607 bool WebAssemblyFastISel::fastLowerArguments() {
608 if (!FuncInfo.CanLowerReturn)
611 const Function *F = FuncInfo.Fn;
616 for (auto const &Arg : F->args()) {
617 const AttributeList &Attrs = F->getAttributes();
618 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
619 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
620 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
621 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
622 Attrs.hasParamAttribute(i, Attribute::Nest))
625 Type *ArgTy = Arg.getType();
626 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
628 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
632 const TargetRegisterClass *RC;
633 switch (getSimpleType(ArgTy)) {
638 Opc = WebAssembly::ARGUMENT_I32;
639 RC = &WebAssembly::I32RegClass;
642 Opc = WebAssembly::ARGUMENT_I64;
643 RC = &WebAssembly::I64RegClass;
646 Opc = WebAssembly::ARGUMENT_F32;
647 RC = &WebAssembly::F32RegClass;
650 Opc = WebAssembly::ARGUMENT_F64;
651 RC = &WebAssembly::F64RegClass;
654 Opc = WebAssembly::ARGUMENT_v16i8;
655 RC = &WebAssembly::V128RegClass;
658 Opc = WebAssembly::ARGUMENT_v8i16;
659 RC = &WebAssembly::V128RegClass;
662 Opc = WebAssembly::ARGUMENT_v4i32;
663 RC = &WebAssembly::V128RegClass;
666 Opc = WebAssembly::ARGUMENT_v4f32;
667 RC = &WebAssembly::V128RegClass;
672 unsigned ResultReg = createResultReg(RC);
673 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
675 updateValueMap(&Arg, ResultReg);
680 MRI.addLiveIn(WebAssembly::ARGUMENTS);
682 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
683 for (auto const &Arg : F->args())
684 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
686 if (!F->getReturnType()->isVoidTy())
687 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
692 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
693 const CallInst *Call = cast<CallInst>(I);
695 if (Call->isMustTailCall() || Call->isInlineAsm() ||
696 Call->getFunctionType()->isVarArg())
699 Function *Func = Call->getCalledFunction();
700 if (Func && Func->isIntrinsic())
703 FunctionType *FuncTy = Call->getFunctionType();
705 bool IsDirect = Func != nullptr;
706 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
709 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
711 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
714 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
720 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
721 ResultReg = createResultReg(&WebAssembly::I32RegClass);
724 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
725 ResultReg = createResultReg(&WebAssembly::I64RegClass);
728 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
729 ResultReg = createResultReg(&WebAssembly::F32RegClass);
732 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
733 ResultReg = createResultReg(&WebAssembly::F64RegClass);
737 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
738 ResultReg = createResultReg(&WebAssembly::V128RegClass);
742 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
743 ResultReg = createResultReg(&WebAssembly::V128RegClass);
747 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
748 ResultReg = createResultReg(&WebAssembly::V128RegClass);
752 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
753 ResultReg = createResultReg(&WebAssembly::V128RegClass);
760 SmallVector<unsigned, 8> Args;
761 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
762 Value *V = Call->getArgOperand(i);
763 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
764 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
767 const AttributeList &Attrs = Call->getAttributes();
768 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
769 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
770 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
771 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
772 Attrs.hasParamAttribute(i, Attribute::Nest))
777 if (Attrs.hasParamAttribute(i, Attribute::SExt))
778 Reg = getRegForSignedValue(V);
779 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
780 Reg = getRegForUnsignedValue(V);
782 Reg = getRegForValue(V);
790 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
793 MIB.addReg(ResultReg, RegState::Define);
796 MIB.addGlobalAddress(Func);
798 MIB.addReg(getRegForValue(Call->getCalledValue()));
800 for (unsigned ArgReg : Args)
804 updateValueMap(Call, ResultReg);
808 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
809 const SelectInst *Select = cast<SelectInst>(I);
812 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
816 unsigned TrueReg = getRegForValue(Select->getTrueValue());
820 unsigned FalseReg = getRegForValue(Select->getFalseValue());
825 std::swap(TrueReg, FalseReg);
828 const TargetRegisterClass *RC;
829 switch (getSimpleType(Select->getType())) {
834 Opc = WebAssembly::SELECT_I32;
835 RC = &WebAssembly::I32RegClass;
838 Opc = WebAssembly::SELECT_I64;
839 RC = &WebAssembly::I64RegClass;
842 Opc = WebAssembly::SELECT_F32;
843 RC = &WebAssembly::F32RegClass;
846 Opc = WebAssembly::SELECT_F64;
847 RC = &WebAssembly::F64RegClass;
853 unsigned ResultReg = createResultReg(RC);
854 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
859 updateValueMap(Select, ResultReg);
863 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
864 const TruncInst *Trunc = cast<TruncInst>(I);
866 unsigned Reg = getRegForValue(Trunc->getOperand(0));
870 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
871 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
872 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
873 TII.get(WebAssembly::I32_WRAP_I64), Result)
878 updateValueMap(Trunc, Reg);
882 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
883 const ZExtInst *ZExt = cast<ZExtInst>(I);
885 const Value *Op = ZExt->getOperand(0);
886 MVT::SimpleValueType From = getSimpleType(Op->getType());
887 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
888 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
892 updateValueMap(ZExt, Reg);
896 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
897 const SExtInst *SExt = cast<SExtInst>(I);
899 const Value *Op = SExt->getOperand(0);
900 MVT::SimpleValueType From = getSimpleType(Op->getType());
901 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
902 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
906 updateValueMap(SExt, Reg);
910 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
911 const ICmpInst *ICmp = cast<ICmpInst>(I);
913 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
915 bool isSigned = false;
916 switch (ICmp->getPredicate()) {
917 case ICmpInst::ICMP_EQ:
918 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
920 case ICmpInst::ICMP_NE:
921 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
923 case ICmpInst::ICMP_UGT:
924 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
926 case ICmpInst::ICMP_UGE:
927 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
929 case ICmpInst::ICMP_ULT:
930 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
932 case ICmpInst::ICMP_ULE:
933 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
935 case ICmpInst::ICMP_SGT:
936 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
939 case ICmpInst::ICMP_SGE:
940 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
943 case ICmpInst::ICMP_SLT:
944 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
947 case ICmpInst::ICMP_SLE:
948 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
951 default: return false;
954 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
958 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
962 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
963 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
966 updateValueMap(ICmp, ResultReg);
970 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
971 const FCmpInst *FCmp = cast<FCmpInst>(I);
973 unsigned LHS = getRegForValue(FCmp->getOperand(0));
977 unsigned RHS = getRegForValue(FCmp->getOperand(1));
981 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
984 switch (FCmp->getPredicate()) {
985 case FCmpInst::FCMP_OEQ:
986 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
988 case FCmpInst::FCMP_UNE:
989 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
991 case FCmpInst::FCMP_OGT:
992 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
994 case FCmpInst::FCMP_OGE:
995 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
997 case FCmpInst::FCMP_OLT:
998 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1000 case FCmpInst::FCMP_OLE:
1001 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1003 case FCmpInst::FCMP_UGT:
1004 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1007 case FCmpInst::FCMP_UGE:
1008 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1011 case FCmpInst::FCMP_ULT:
1012 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1015 case FCmpInst::FCMP_ULE:
1016 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1023 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1024 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1029 ResultReg = notValue(ResultReg);
1031 updateValueMap(FCmp, ResultReg);
1035 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1036 // Target-independent code can handle this, except it doesn't set the dead
1037 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1038 // to satisfy code that expects this of isBitcast() instructions.
1039 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1040 EVT RetVT = TLI.getValueType(DL, I->getType());
1041 if (!VT.isSimple() || !RetVT.isSimple())
1046 updateValueMap(I, getRegForValue(I->getOperand(0)));
1050 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1051 getRegForValue(I->getOperand(0)),
1052 I->getOperand(0)->hasOneUse());
1055 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1057 assert(Iter->isBitcast());
1058 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1059 updateValueMap(I, Reg);
1063 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1064 const LoadInst *Load = cast<LoadInst>(I);
1065 if (Load->isAtomic())
1067 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1071 if (!computeAddress(Load->getPointerOperand(), Addr))
1074 // TODO: Fold a following sign-/zero-extend into the load instruction.
1077 const TargetRegisterClass *RC;
1078 switch (getSimpleType(Load->getType())) {
1081 Opc = WebAssembly::LOAD8_U_I32;
1082 RC = &WebAssembly::I32RegClass;
1085 Opc = WebAssembly::LOAD16_U_I32;
1086 RC = &WebAssembly::I32RegClass;
1089 Opc = WebAssembly::LOAD_I32;
1090 RC = &WebAssembly::I32RegClass;
1093 Opc = WebAssembly::LOAD_I64;
1094 RC = &WebAssembly::I64RegClass;
1097 Opc = WebAssembly::LOAD_F32;
1098 RC = &WebAssembly::F32RegClass;
1101 Opc = WebAssembly::LOAD_F64;
1102 RC = &WebAssembly::F64RegClass;
1108 materializeLoadStoreOperands(Addr);
1110 unsigned ResultReg = createResultReg(RC);
1111 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1114 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1116 updateValueMap(Load, ResultReg);
1120 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1121 const StoreInst *Store = cast<StoreInst>(I);
1122 if (Store->isAtomic())
1124 if (!Subtarget->hasSIMD128() &&
1125 Store->getValueOperand()->getType()->isVectorTy())
1129 if (!computeAddress(Store->getPointerOperand(), Addr))
1133 bool VTIsi1 = false;
1134 switch (getSimpleType(Store->getValueOperand()->getType())) {
1138 Opc = WebAssembly::STORE8_I32;
1141 Opc = WebAssembly::STORE16_I32;
1144 Opc = WebAssembly::STORE_I32;
1147 Opc = WebAssembly::STORE_I64;
1150 Opc = WebAssembly::STORE_F32;
1153 Opc = WebAssembly::STORE_F64;
1155 default: return false;
1158 materializeLoadStoreOperands(Addr);
1160 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1164 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1166 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1168 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1170 MIB.addReg(ValueReg);
1174 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1175 const BranchInst *Br = cast<BranchInst>(I);
1176 if (Br->isUnconditional()) {
1177 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1178 fastEmitBranch(MSucc, Br->getDebugLoc());
1182 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1183 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1186 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1190 unsigned Opc = WebAssembly::BR_IF;
1192 Opc = WebAssembly::BR_UNLESS;
1194 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1198 finishCondBranch(Br->getParent(), TBB, FBB);
1202 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1203 if (!FuncInfo.CanLowerReturn)
1206 const ReturnInst *Ret = cast<ReturnInst>(I);
1208 if (Ret->getNumOperands() == 0) {
1209 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1210 TII.get(WebAssembly::RETURN_VOID));
1214 Value *RV = Ret->getOperand(0);
1215 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1219 switch (getSimpleType(RV->getType())) {
1220 case MVT::i1: case MVT::i8:
1221 case MVT::i16: case MVT::i32:
1222 Opc = WebAssembly::RETURN_I32;
1225 Opc = WebAssembly::RETURN_I64;
1228 Opc = WebAssembly::RETURN_F32;
1231 Opc = WebAssembly::RETURN_F64;
1234 Opc = WebAssembly::RETURN_v16i8;
1237 Opc = WebAssembly::RETURN_v8i16;
1240 Opc = WebAssembly::RETURN_v4i32;
1243 Opc = WebAssembly::RETURN_v4f32;
1245 default: return false;
1249 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1250 Reg = getRegForSignedValue(RV);
1251 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1252 Reg = getRegForUnsignedValue(RV);
1254 Reg = getRegForValue(RV);
1259 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1263 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1264 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1265 TII.get(WebAssembly::UNREACHABLE));
1269 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1270 switch (I->getOpcode()) {
1271 case Instruction::Call:
1275 case Instruction::Select: return selectSelect(I);
1276 case Instruction::Trunc: return selectTrunc(I);
1277 case Instruction::ZExt: return selectZExt(I);
1278 case Instruction::SExt: return selectSExt(I);
1279 case Instruction::ICmp: return selectICmp(I);
1280 case Instruction::FCmp: return selectFCmp(I);
1281 case Instruction::BitCast: return selectBitCast(I);
1282 case Instruction::Load: return selectLoad(I);
1283 case Instruction::Store: return selectStore(I);
1284 case Instruction::Br: return selectBr(I);
1285 case Instruction::Ret: return selectRet(I);
1286 case Instruction::Unreachable: return selectUnreachable(I);
1290 // Fall back to target-independent instruction selection.
1291 return selectOperator(I, I->getOpcode());
1294 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1295 const TargetLibraryInfo *LibInfo) {
1296 return new WebAssemblyFastISel(FuncInfo, LibInfo);