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 /// 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"
40 #include "llvm/IR/PatternMatch.h"
43 using namespace PatternMatch;
45 #define DEBUG_TYPE "wasm-fastisel"
49 class WebAssemblyFastISel final : public FastISel {
50 // All possible address modes.
53 typedef enum { RegBase, FrameIndexBase } BaseKind;
64 const GlobalValue *GV;
67 // Innocuous defaults for our address.
68 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; }
69 void setKind(BaseKind K) {
70 assert(!isSet() && "Can't change kind with non-zero base");
73 BaseKind getKind() const { return Kind; }
74 bool isRegBase() const { return Kind == RegBase; }
75 bool isFIBase() const { return Kind == FrameIndexBase; }
76 void setReg(unsigned Reg) {
77 assert(isRegBase() && "Invalid base register access!");
78 assert(Base.Reg == 0 && "Overwriting non-zero register");
81 unsigned getReg() const {
82 assert(isRegBase() && "Invalid base register access!");
85 void setFI(unsigned FI) {
86 assert(isFIBase() && "Invalid base frame index access!");
87 assert(Base.FI == 0 && "Overwriting non-zero frame index");
90 unsigned getFI() const {
91 assert(isFIBase() && "Invalid base frame index access!");
95 void setOffset(int64_t Offset_) {
96 assert(Offset_ >= 0 && "Offsets must be non-negative");
99 int64_t getOffset() const { return Offset; }
100 void setGlobalValue(const GlobalValue *G) { GV = G; }
101 const GlobalValue *getGlobalValue() const { return GV; }
104 return Base.Reg != 0;
111 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
112 /// right decision when generating code for different targets.
113 const WebAssemblySubtarget *Subtarget;
114 LLVMContext *Context;
117 // Utility helper routines
118 MVT::SimpleValueType getSimpleType(Type *Ty) {
119 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
120 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
121 : MVT::INVALID_SIMPLE_VALUE_TYPE;
123 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
141 if (Subtarget->hasSIMD128())
146 if (Subtarget->hasUnimplementedSIMD128())
152 return MVT::INVALID_SIMPLE_VALUE_TYPE;
154 bool computeAddress(const Value *Obj, Address &Addr);
155 void materializeLoadStoreOperands(Address &Addr);
156 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
157 MachineMemOperand *MMO);
158 unsigned maskI1Value(unsigned Reg, const Value *V);
159 unsigned getRegForI1Value(const Value *V, bool &Not);
160 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
161 MVT::SimpleValueType From);
162 unsigned signExtendToI32(unsigned Reg, const Value *V,
163 MVT::SimpleValueType From);
164 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
165 MVT::SimpleValueType To);
166 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
167 MVT::SimpleValueType To);
168 unsigned getRegForUnsignedValue(const Value *V);
169 unsigned getRegForSignedValue(const Value *V);
170 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
171 unsigned notValue(unsigned Reg);
172 unsigned copyValue(unsigned Reg);
174 // Backend specific FastISel code.
175 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
176 unsigned fastMaterializeConstant(const Constant *C) override;
177 bool fastLowerArguments() override;
179 // Selection routines.
180 bool selectCall(const Instruction *I);
181 bool selectSelect(const Instruction *I);
182 bool selectTrunc(const Instruction *I);
183 bool selectZExt(const Instruction *I);
184 bool selectSExt(const Instruction *I);
185 bool selectICmp(const Instruction *I);
186 bool selectFCmp(const Instruction *I);
187 bool selectBitCast(const Instruction *I);
188 bool selectLoad(const Instruction *I);
189 bool selectStore(const Instruction *I);
190 bool selectBr(const Instruction *I);
191 bool selectRet(const Instruction *I);
192 bool selectUnreachable(const Instruction *I);
195 // Backend specific FastISel code.
196 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
197 const TargetLibraryInfo *LibInfo)
198 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
199 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
200 Context = &FuncInfo.Fn->getContext();
203 bool fastSelectInstruction(const Instruction *I) override;
205 #include "WebAssemblyGenFastISel.inc"
208 } // end anonymous namespace
210 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
212 const User *U = nullptr;
213 unsigned Opcode = Instruction::UserOp1;
214 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
215 // Don't walk into other basic blocks unless the object is an alloca from
216 // another block, otherwise it may not have a virtual register assigned.
217 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
218 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
219 Opcode = I->getOpcode();
222 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
223 Opcode = C->getOpcode();
227 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
228 if (Ty->getAddressSpace() > 255)
229 // Fast instruction selection doesn't support the special
233 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
234 if (Addr.getGlobalValue())
236 Addr.setGlobalValue(GV);
243 case Instruction::BitCast: {
244 // Look through bitcasts.
245 return computeAddress(U->getOperand(0), Addr);
247 case Instruction::IntToPtr: {
248 // Look past no-op inttoptrs.
249 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
250 TLI.getPointerTy(DL))
251 return computeAddress(U->getOperand(0), Addr);
254 case Instruction::PtrToInt: {
255 // Look past no-op ptrtoints.
256 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
257 return computeAddress(U->getOperand(0), Addr);
260 case Instruction::GetElementPtr: {
261 Address SavedAddr = Addr;
262 uint64_t TmpOffset = Addr.getOffset();
263 // Non-inbounds geps can wrap; wasm's offsets can't.
264 if (!cast<GEPOperator>(U)->isInBounds())
265 goto unsupported_gep;
266 // Iterate through the GEP folding the constants into offsets where
268 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
270 const Value *Op = GTI.getOperand();
271 if (StructType *STy = GTI.getStructTypeOrNull()) {
272 const StructLayout *SL = DL.getStructLayout(STy);
273 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
274 TmpOffset += SL->getElementOffset(Idx);
276 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
278 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
279 // Constant-offset addressing.
280 TmpOffset += CI->getSExtValue() * S;
283 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
284 // An unscaled add of a register. Set it as the new base.
285 unsigned Reg = getRegForValue(Op);
291 if (canFoldAddIntoGEP(U, Op)) {
292 // A compatible add with a constant operand. Fold the constant.
294 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
295 TmpOffset += CI->getSExtValue() * S;
296 // Iterate on the other operand.
297 Op = cast<AddOperator>(Op)->getOperand(0);
301 goto unsupported_gep;
305 // Don't fold in negative offsets.
306 if (int64_t(TmpOffset) >= 0) {
307 // Try to grab the base operand now.
308 Addr.setOffset(TmpOffset);
309 if (computeAddress(U->getOperand(0), Addr))
312 // We failed, restore everything and try the other options.
317 case Instruction::Alloca: {
318 const AllocaInst *AI = cast<AllocaInst>(Obj);
319 DenseMap<const AllocaInst *, int>::iterator SI =
320 FuncInfo.StaticAllocaMap.find(AI);
321 if (SI != FuncInfo.StaticAllocaMap.end()) {
325 Addr.setKind(Address::FrameIndexBase);
326 Addr.setFI(SI->second);
331 case Instruction::Add: {
332 // Adds of constants are common and easy enough.
333 const Value *LHS = U->getOperand(0);
334 const Value *RHS = U->getOperand(1);
336 if (isa<ConstantInt>(LHS))
339 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
340 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
341 if (int64_t(TmpOffset) >= 0) {
342 Addr.setOffset(TmpOffset);
343 return computeAddress(LHS, Addr);
347 Address Backup = Addr;
348 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
354 case Instruction::Sub: {
355 // Subs of constants are common and easy enough.
356 const Value *LHS = U->getOperand(0);
357 const Value *RHS = U->getOperand(1);
359 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
360 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
361 if (TmpOffset >= 0) {
362 Addr.setOffset(TmpOffset);
363 return computeAddress(LHS, Addr);
372 unsigned Reg = getRegForValue(Obj);
376 return Addr.getReg() != 0;
379 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
380 if (Addr.isRegBase()) {
381 unsigned Reg = Addr.getReg();
383 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
384 : &WebAssembly::I32RegClass);
385 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
386 : WebAssembly::CONST_I32;
387 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
394 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
395 const MachineInstrBuilder &MIB,
396 MachineMemOperand *MMO) {
397 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
398 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
401 if (const GlobalValue *GV = Addr.getGlobalValue())
402 MIB.addGlobalAddress(GV, Addr.getOffset());
404 MIB.addImm(Addr.getOffset());
406 if (Addr.isRegBase())
407 MIB.addReg(Addr.getReg());
409 MIB.addFrameIndex(Addr.getFI());
411 MIB.addMemOperand(MMO);
414 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
415 return zeroExtendToI32(Reg, V, MVT::i1);
418 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
419 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
420 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
421 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
422 Not = ICmp->isTrueWhenEqual();
423 return getRegForValue(ICmp->getOperand(0));
427 if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) {
429 return getRegForValue(NotV);
433 unsigned Reg = getRegForValue(V);
436 return maskI1Value(Reg, V);
439 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
440 MVT::SimpleValueType From) {
446 // If the value is naturally an i1, we don't need to mask it. We only know
447 // if a value is naturally an i1 if it is definitely lowered by FastISel,
448 // not a DAG ISel fallback.
449 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
450 return copyValue(Reg);
456 return copyValue(Reg);
461 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
463 TII.get(WebAssembly::CONST_I32), Imm)
464 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
466 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
467 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
468 TII.get(WebAssembly::AND_I32), Result)
475 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
476 MVT::SimpleValueType From) {
486 return copyValue(Reg);
491 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
493 TII.get(WebAssembly::CONST_I32), Imm)
494 .addImm(32 - MVT(From).getSizeInBits());
496 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
497 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
498 TII.get(WebAssembly::SHL_I32), Left)
502 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
503 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
504 TII.get(WebAssembly::SHR_S_I32), Right)
511 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
512 MVT::SimpleValueType From,
513 MVT::SimpleValueType To) {
514 if (To == MVT::i64) {
515 if (From == MVT::i64)
516 return copyValue(Reg);
518 Reg = zeroExtendToI32(Reg, V, From);
520 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
521 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
522 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
527 return zeroExtendToI32(Reg, V, From);
530 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
531 MVT::SimpleValueType From,
532 MVT::SimpleValueType To) {
533 if (To == MVT::i64) {
534 if (From == MVT::i64)
535 return copyValue(Reg);
537 Reg = signExtendToI32(Reg, V, From);
539 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
540 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
541 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
546 return signExtendToI32(Reg, V, From);
549 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
550 MVT::SimpleValueType From = getSimpleType(V->getType());
551 MVT::SimpleValueType To = getLegalType(From);
552 unsigned VReg = getRegForValue(V);
555 return zeroExtend(VReg, V, From, To);
558 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
559 MVT::SimpleValueType From = getSimpleType(V->getType());
560 MVT::SimpleValueType To = getLegalType(From);
561 unsigned VReg = getRegForValue(V);
564 return signExtend(VReg, V, From, To);
567 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
569 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
572 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
573 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
575 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
576 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
577 TII.get(WebAssembly::EQZ_I32), NotReg)
582 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
583 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
584 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
590 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
591 DenseMap<const AllocaInst *, int>::iterator SI =
592 FuncInfo.StaticAllocaMap.find(AI);
594 if (SI != FuncInfo.StaticAllocaMap.end()) {
596 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
597 : &WebAssembly::I32RegClass);
599 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
600 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
601 .addFrameIndex(SI->second);
608 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
609 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
611 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
612 : &WebAssembly::I32RegClass);
613 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
614 : WebAssembly::CONST_I32;
615 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
616 .addGlobalAddress(GV);
620 // Let target-independent code handle it.
624 bool WebAssemblyFastISel::fastLowerArguments() {
625 if (!FuncInfo.CanLowerReturn)
628 const Function *F = FuncInfo.Fn;
633 for (auto const &Arg : F->args()) {
634 const AttributeList &Attrs = F->getAttributes();
635 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
636 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
637 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
638 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
639 Attrs.hasParamAttribute(i, Attribute::Nest))
642 Type *ArgTy = Arg.getType();
643 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
645 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
649 const TargetRegisterClass *RC;
650 switch (getSimpleType(ArgTy)) {
655 Opc = WebAssembly::ARGUMENT_i32;
656 RC = &WebAssembly::I32RegClass;
659 Opc = WebAssembly::ARGUMENT_i64;
660 RC = &WebAssembly::I64RegClass;
663 Opc = WebAssembly::ARGUMENT_f32;
664 RC = &WebAssembly::F32RegClass;
667 Opc = WebAssembly::ARGUMENT_f64;
668 RC = &WebAssembly::F64RegClass;
671 Opc = WebAssembly::ARGUMENT_v16i8;
672 RC = &WebAssembly::V128RegClass;
675 Opc = WebAssembly::ARGUMENT_v8i16;
676 RC = &WebAssembly::V128RegClass;
679 Opc = WebAssembly::ARGUMENT_v4i32;
680 RC = &WebAssembly::V128RegClass;
683 Opc = WebAssembly::ARGUMENT_v2i64;
684 RC = &WebAssembly::V128RegClass;
687 Opc = WebAssembly::ARGUMENT_v4f32;
688 RC = &WebAssembly::V128RegClass;
691 Opc = WebAssembly::ARGUMENT_v2f64;
692 RC = &WebAssembly::V128RegClass;
695 Opc = WebAssembly::ARGUMENT_ExceptRef;
696 RC = &WebAssembly::EXCEPT_REFRegClass;
701 unsigned ResultReg = createResultReg(RC);
702 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
704 updateValueMap(&Arg, ResultReg);
709 MRI.addLiveIn(WebAssembly::ARGUMENTS);
711 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
712 for (auto const &Arg : F->args()) {
713 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
714 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
715 MFI->clearParamsAndResults();
718 MFI->addParam(ArgTy);
721 if (!F->getReturnType()->isVoidTy()) {
722 MVT::SimpleValueType RetTy =
723 getLegalType(getSimpleType(F->getReturnType()));
724 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
725 MFI->clearParamsAndResults();
728 MFI->addResult(RetTy);
734 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
735 const CallInst *Call = cast<CallInst>(I);
737 if (Call->isMustTailCall() || Call->isInlineAsm() ||
738 Call->getFunctionType()->isVarArg())
741 Function *Func = Call->getCalledFunction();
742 if (Func && Func->isIntrinsic())
745 bool IsDirect = Func != nullptr;
746 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
749 FunctionType *FuncTy = Call->getFunctionType();
751 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
754 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
756 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
759 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
765 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
766 ResultReg = createResultReg(&WebAssembly::I32RegClass);
769 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
770 ResultReg = createResultReg(&WebAssembly::I64RegClass);
773 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
774 ResultReg = createResultReg(&WebAssembly::F32RegClass);
777 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
778 ResultReg = createResultReg(&WebAssembly::F64RegClass);
781 Opc = IsDirect ? WebAssembly::CALL_v16i8
782 : WebAssembly::PCALL_INDIRECT_v16i8;
783 ResultReg = createResultReg(&WebAssembly::V128RegClass);
786 Opc = IsDirect ? WebAssembly::CALL_v8i16
787 : WebAssembly::PCALL_INDIRECT_v8i16;
788 ResultReg = createResultReg(&WebAssembly::V128RegClass);
791 Opc = IsDirect ? WebAssembly::CALL_v4i32
792 : WebAssembly::PCALL_INDIRECT_v4i32;
793 ResultReg = createResultReg(&WebAssembly::V128RegClass);
796 Opc = IsDirect ? WebAssembly::CALL_v2i64
797 : WebAssembly::PCALL_INDIRECT_v2i64;
798 ResultReg = createResultReg(&WebAssembly::V128RegClass);
801 Opc = IsDirect ? WebAssembly::CALL_v4f32
802 : WebAssembly::PCALL_INDIRECT_v4f32;
803 ResultReg = createResultReg(&WebAssembly::V128RegClass);
806 Opc = IsDirect ? WebAssembly::CALL_v2f64
807 : WebAssembly::PCALL_INDIRECT_v2f64;
808 ResultReg = createResultReg(&WebAssembly::V128RegClass);
811 Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
812 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
813 ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass);
820 SmallVector<unsigned, 8> Args;
821 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
822 Value *V = Call->getArgOperand(i);
823 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
824 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
827 const AttributeList &Attrs = Call->getAttributes();
828 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
829 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
830 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
831 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
832 Attrs.hasParamAttribute(i, Attribute::Nest))
837 if (Attrs.hasParamAttribute(i, Attribute::SExt))
838 Reg = getRegForSignedValue(V);
839 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
840 Reg = getRegForUnsignedValue(V);
842 Reg = getRegForValue(V);
850 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
853 MIB.addReg(ResultReg, RegState::Define);
856 MIB.addGlobalAddress(Func);
858 unsigned Reg = getRegForValue(Call->getCalledValue());
864 for (unsigned ArgReg : Args)
868 updateValueMap(Call, ResultReg);
872 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
873 const SelectInst *Select = cast<SelectInst>(I);
876 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
880 unsigned TrueReg = getRegForValue(Select->getTrueValue());
884 unsigned FalseReg = getRegForValue(Select->getFalseValue());
889 std::swap(TrueReg, FalseReg);
892 const TargetRegisterClass *RC;
893 switch (getSimpleType(Select->getType())) {
898 Opc = WebAssembly::SELECT_I32;
899 RC = &WebAssembly::I32RegClass;
902 Opc = WebAssembly::SELECT_I64;
903 RC = &WebAssembly::I64RegClass;
906 Opc = WebAssembly::SELECT_F32;
907 RC = &WebAssembly::F32RegClass;
910 Opc = WebAssembly::SELECT_F64;
911 RC = &WebAssembly::F64RegClass;
914 Opc = WebAssembly::SELECT_EXCEPT_REF;
915 RC = &WebAssembly::EXCEPT_REFRegClass;
921 unsigned ResultReg = createResultReg(RC);
922 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
927 updateValueMap(Select, ResultReg);
931 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
932 const TruncInst *Trunc = cast<TruncInst>(I);
934 unsigned Reg = getRegForValue(Trunc->getOperand(0));
938 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
939 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
940 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
941 TII.get(WebAssembly::I32_WRAP_I64), Result)
946 updateValueMap(Trunc, Reg);
950 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
951 const ZExtInst *ZExt = cast<ZExtInst>(I);
953 const Value *Op = ZExt->getOperand(0);
954 MVT::SimpleValueType From = getSimpleType(Op->getType());
955 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
956 unsigned In = getRegForValue(Op);
959 unsigned Reg = zeroExtend(In, Op, From, To);
963 updateValueMap(ZExt, Reg);
967 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
968 const SExtInst *SExt = cast<SExtInst>(I);
970 const Value *Op = SExt->getOperand(0);
971 MVT::SimpleValueType From = getSimpleType(Op->getType());
972 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
973 unsigned In = getRegForValue(Op);
976 unsigned Reg = signExtend(In, Op, From, To);
980 updateValueMap(SExt, Reg);
984 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
985 const ICmpInst *ICmp = cast<ICmpInst>(I);
987 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
989 bool isSigned = false;
990 switch (ICmp->getPredicate()) {
991 case ICmpInst::ICMP_EQ:
992 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
994 case ICmpInst::ICMP_NE:
995 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
997 case ICmpInst::ICMP_UGT:
998 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1000 case ICmpInst::ICMP_UGE:
1001 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1003 case ICmpInst::ICMP_ULT:
1004 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1006 case ICmpInst::ICMP_ULE:
1007 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1009 case ICmpInst::ICMP_SGT:
1010 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1013 case ICmpInst::ICMP_SGE:
1014 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1017 case ICmpInst::ICMP_SLT:
1018 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1021 case ICmpInst::ICMP_SLE:
1022 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1029 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
1033 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
1037 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1038 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1041 updateValueMap(ICmp, ResultReg);
1045 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1046 const FCmpInst *FCmp = cast<FCmpInst>(I);
1048 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1052 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1056 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1059 switch (FCmp->getPredicate()) {
1060 case FCmpInst::FCMP_OEQ:
1061 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1063 case FCmpInst::FCMP_UNE:
1064 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1066 case FCmpInst::FCMP_OGT:
1067 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1069 case FCmpInst::FCMP_OGE:
1070 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1072 case FCmpInst::FCMP_OLT:
1073 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1075 case FCmpInst::FCMP_OLE:
1076 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1078 case FCmpInst::FCMP_UGT:
1079 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1082 case FCmpInst::FCMP_UGE:
1083 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1086 case FCmpInst::FCMP_ULT:
1087 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1090 case FCmpInst::FCMP_ULE:
1091 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1098 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1099 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1104 ResultReg = notValue(ResultReg);
1106 updateValueMap(FCmp, ResultReg);
1110 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1111 // Target-independent code can handle this, except it doesn't set the dead
1112 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1113 // to satisfy code that expects this of isBitcast() instructions.
1114 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1115 EVT RetVT = TLI.getValueType(DL, I->getType());
1116 if (!VT.isSimple() || !RetVT.isSimple())
1119 unsigned In = getRegForValue(I->getOperand(0));
1125 updateValueMap(I, In);
1129 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1130 In, I->getOperand(0)->hasOneUse());
1133 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1135 assert(Iter->isBitcast());
1136 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1137 updateValueMap(I, Reg);
1141 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1142 const LoadInst *Load = cast<LoadInst>(I);
1143 if (Load->isAtomic())
1145 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1149 if (!computeAddress(Load->getPointerOperand(), Addr))
1152 // TODO: Fold a following sign-/zero-extend into the load instruction.
1155 const TargetRegisterClass *RC;
1156 switch (getSimpleType(Load->getType())) {
1159 Opc = WebAssembly::LOAD8_U_I32;
1160 RC = &WebAssembly::I32RegClass;
1163 Opc = WebAssembly::LOAD16_U_I32;
1164 RC = &WebAssembly::I32RegClass;
1167 Opc = WebAssembly::LOAD_I32;
1168 RC = &WebAssembly::I32RegClass;
1171 Opc = WebAssembly::LOAD_I64;
1172 RC = &WebAssembly::I64RegClass;
1175 Opc = WebAssembly::LOAD_F32;
1176 RC = &WebAssembly::F32RegClass;
1179 Opc = WebAssembly::LOAD_F64;
1180 RC = &WebAssembly::F64RegClass;
1186 materializeLoadStoreOperands(Addr);
1188 unsigned ResultReg = createResultReg(RC);
1189 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1192 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1194 updateValueMap(Load, ResultReg);
1198 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1199 const StoreInst *Store = cast<StoreInst>(I);
1200 if (Store->isAtomic())
1202 if (!Subtarget->hasSIMD128() &&
1203 Store->getValueOperand()->getType()->isVectorTy())
1207 if (!computeAddress(Store->getPointerOperand(), Addr))
1211 bool VTIsi1 = false;
1212 switch (getSimpleType(Store->getValueOperand()->getType())) {
1217 Opc = WebAssembly::STORE8_I32;
1220 Opc = WebAssembly::STORE16_I32;
1223 Opc = WebAssembly::STORE_I32;
1226 Opc = WebAssembly::STORE_I64;
1229 Opc = WebAssembly::STORE_F32;
1232 Opc = WebAssembly::STORE_F64;
1238 materializeLoadStoreOperands(Addr);
1240 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1244 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1246 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1248 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1250 MIB.addReg(ValueReg);
1254 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1255 const BranchInst *Br = cast<BranchInst>(I);
1256 if (Br->isUnconditional()) {
1257 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1258 fastEmitBranch(MSucc, Br->getDebugLoc());
1262 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1263 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1266 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1270 unsigned Opc = WebAssembly::BR_IF;
1272 Opc = WebAssembly::BR_UNLESS;
1274 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1278 finishCondBranch(Br->getParent(), TBB, FBB);
1282 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1283 if (!FuncInfo.CanLowerReturn)
1286 const ReturnInst *Ret = cast<ReturnInst>(I);
1288 if (Ret->getNumOperands() == 0) {
1289 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1290 TII.get(WebAssembly::RETURN_VOID));
1294 Value *RV = Ret->getOperand(0);
1295 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1299 switch (getSimpleType(RV->getType())) {
1304 Opc = WebAssembly::RETURN_I32;
1307 Opc = WebAssembly::RETURN_I64;
1310 Opc = WebAssembly::RETURN_F32;
1313 Opc = WebAssembly::RETURN_F64;
1316 Opc = WebAssembly::RETURN_v16i8;
1319 Opc = WebAssembly::RETURN_v8i16;
1322 Opc = WebAssembly::RETURN_v4i32;
1325 Opc = WebAssembly::RETURN_v2i64;
1328 Opc = WebAssembly::RETURN_v4f32;
1331 Opc = WebAssembly::RETURN_v2f64;
1333 case MVT::ExceptRef:
1334 Opc = WebAssembly::RETURN_EXCEPT_REF;
1341 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1342 Reg = getRegForSignedValue(RV);
1343 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1344 Reg = getRegForUnsignedValue(RV);
1346 Reg = getRegForValue(RV);
1351 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1355 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1356 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1357 TII.get(WebAssembly::UNREACHABLE));
1361 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1362 switch (I->getOpcode()) {
1363 case Instruction::Call:
1367 case Instruction::Select:
1368 return selectSelect(I);
1369 case Instruction::Trunc:
1370 return selectTrunc(I);
1371 case Instruction::ZExt:
1372 return selectZExt(I);
1373 case Instruction::SExt:
1374 return selectSExt(I);
1375 case Instruction::ICmp:
1376 return selectICmp(I);
1377 case Instruction::FCmp:
1378 return selectFCmp(I);
1379 case Instruction::BitCast:
1380 return selectBitCast(I);
1381 case Instruction::Load:
1382 return selectLoad(I);
1383 case Instruction::Store:
1384 return selectStore(I);
1385 case Instruction::Br:
1387 case Instruction::Ret:
1388 return selectRet(I);
1389 case Instruction::Unreachable:
1390 return selectUnreachable(I);
1395 // Fall back to target-independent instruction selection.
1396 return selectOperator(I, I->getOpcode());
1399 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1400 const TargetLibraryInfo *LibInfo) {
1401 return new WebAssemblyFastISel(FuncInfo, LibInfo);