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 "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"
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) { Kind = K; }
67 BaseKind getKind() const { return Kind; }
68 bool isRegBase() const { return Kind == RegBase; }
69 bool isFIBase() const { return Kind == FrameIndexBase; }
70 void setReg(unsigned Reg) {
71 assert(isRegBase() && "Invalid base register access!");
74 unsigned getReg() const {
75 assert(isRegBase() && "Invalid base register access!");
78 void setFI(unsigned FI) {
79 assert(isFIBase() && "Invalid base frame index access!");
82 unsigned getFI() const {
83 assert(isFIBase() && "Invalid base frame index access!");
87 void setOffset(int64_t Offset_) {
88 assert(Offset_ >= 0 && "Offsets must be non-negative");
91 int64_t getOffset() const { return Offset; }
92 void setGlobalValue(const GlobalValue *G) { GV = G; }
93 const GlobalValue *getGlobalValue() const { return GV; }
96 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
97 /// right decision when generating code for different targets.
98 const WebAssemblySubtarget *Subtarget;
102 // Utility helper routines
103 MVT::SimpleValueType getSimpleType(Type *Ty) {
104 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
105 return VT.isSimple() ? VT.getSimpleVT().SimpleTy :
106 MVT::INVALID_SIMPLE_VALUE_TYPE;
108 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
125 if (Subtarget->hasSIMD128())
131 return MVT::INVALID_SIMPLE_VALUE_TYPE;
133 bool computeAddress(const Value *Obj, Address &Addr);
134 void materializeLoadStoreOperands(Address &Addr);
135 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
136 MachineMemOperand *MMO);
137 unsigned maskI1Value(unsigned Reg, const Value *V);
138 unsigned getRegForI1Value(const Value *V, bool &Not);
139 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
140 MVT::SimpleValueType From);
141 unsigned signExtendToI32(unsigned Reg, const Value *V,
142 MVT::SimpleValueType From);
143 unsigned zeroExtend(unsigned Reg, const Value *V,
144 MVT::SimpleValueType From,
145 MVT::SimpleValueType To);
146 unsigned signExtend(unsigned Reg, const Value *V,
147 MVT::SimpleValueType From,
148 MVT::SimpleValueType To);
149 unsigned getRegForUnsignedValue(const Value *V);
150 unsigned getRegForSignedValue(const Value *V);
151 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
152 unsigned notValue(unsigned Reg);
153 unsigned copyValue(unsigned Reg);
155 // Backend specific FastISel code.
156 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
157 unsigned fastMaterializeConstant(const Constant *C) override;
158 bool fastLowerArguments() override;
160 // Selection routines.
161 bool selectCall(const Instruction *I);
162 bool selectSelect(const Instruction *I);
163 bool selectTrunc(const Instruction *I);
164 bool selectZExt(const Instruction *I);
165 bool selectSExt(const Instruction *I);
166 bool selectICmp(const Instruction *I);
167 bool selectFCmp(const Instruction *I);
168 bool selectBitCast(const Instruction *I);
169 bool selectLoad(const Instruction *I);
170 bool selectStore(const Instruction *I);
171 bool selectBr(const Instruction *I);
172 bool selectRet(const Instruction *I);
173 bool selectUnreachable(const Instruction *I);
176 // Backend specific FastISel code.
177 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
178 const TargetLibraryInfo *LibInfo)
179 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
180 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
181 Context = &FuncInfo.Fn->getContext();
184 bool fastSelectInstruction(const Instruction *I) override;
186 #include "WebAssemblyGenFastISel.inc"
189 } // end anonymous namespace
191 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
193 const User *U = nullptr;
194 unsigned Opcode = Instruction::UserOp1;
195 if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
196 // Don't walk into other basic blocks unless the object is an alloca from
197 // another block, otherwise it may not have a virtual register assigned.
198 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
199 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
200 Opcode = I->getOpcode();
203 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
204 Opcode = C->getOpcode();
208 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
209 if (Ty->getAddressSpace() > 255)
210 // Fast instruction selection doesn't support the special
214 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) {
215 if (Addr.getGlobalValue())
217 Addr.setGlobalValue(GV);
224 case Instruction::BitCast: {
225 // Look through bitcasts.
226 return computeAddress(U->getOperand(0), Addr);
228 case Instruction::IntToPtr: {
229 // Look past no-op inttoptrs.
230 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
231 TLI.getPointerTy(DL))
232 return computeAddress(U->getOperand(0), Addr);
235 case Instruction::PtrToInt: {
236 // Look past no-op ptrtoints.
237 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
238 return computeAddress(U->getOperand(0), Addr);
241 case Instruction::GetElementPtr: {
242 Address SavedAddr = Addr;
243 uint64_t TmpOffset = Addr.getOffset();
244 // Non-inbounds geps can wrap; wasm's offsets can't.
245 if (!cast<GEPOperator>(U)->isInBounds())
246 goto unsupported_gep;
247 // Iterate through the GEP folding the constants into offsets where
249 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
251 const Value *Op = GTI.getOperand();
252 if (StructType *STy = GTI.getStructTypeOrNull()) {
253 const StructLayout *SL = DL.getStructLayout(STy);
254 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
255 TmpOffset += SL->getElementOffset(Idx);
257 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
259 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
260 // Constant-offset addressing.
261 TmpOffset += CI->getSExtValue() * S;
264 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
265 // An unscaled add of a register. Set it as the new base.
266 Addr.setReg(getRegForValue(Op));
269 if (canFoldAddIntoGEP(U, Op)) {
270 // A compatible add with a constant operand. Fold the constant.
272 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
273 TmpOffset += CI->getSExtValue() * S;
274 // Iterate on the other operand.
275 Op = cast<AddOperator>(Op)->getOperand(0);
279 goto unsupported_gep;
283 // Don't fold in negative offsets.
284 if (int64_t(TmpOffset) >= 0) {
285 // Try to grab the base operand now.
286 Addr.setOffset(TmpOffset);
287 if (computeAddress(U->getOperand(0), Addr))
290 // We failed, restore everything and try the other options.
295 case Instruction::Alloca: {
296 const AllocaInst *AI = cast<AllocaInst>(Obj);
297 DenseMap<const AllocaInst *, int>::iterator SI =
298 FuncInfo.StaticAllocaMap.find(AI);
299 if (SI != FuncInfo.StaticAllocaMap.end()) {
300 Addr.setKind(Address::FrameIndexBase);
301 Addr.setFI(SI->second);
306 case Instruction::Add: {
307 // Adds of constants are common and easy enough.
308 const Value *LHS = U->getOperand(0);
309 const Value *RHS = U->getOperand(1);
311 if (isa<ConstantInt>(LHS))
314 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
315 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
316 if (int64_t(TmpOffset) >= 0) {
317 Addr.setOffset(TmpOffset);
318 return computeAddress(LHS, Addr);
322 Address Backup = Addr;
323 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
329 case Instruction::Sub: {
330 // Subs of constants are common and easy enough.
331 const Value *LHS = U->getOperand(0);
332 const Value *RHS = U->getOperand(1);
334 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
335 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
336 if (TmpOffset >= 0) {
337 Addr.setOffset(TmpOffset);
338 return computeAddress(LHS, Addr);
344 Addr.setReg(getRegForValue(Obj));
345 return Addr.getReg() != 0;
348 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
349 if (Addr.isRegBase()) {
350 unsigned Reg = Addr.getReg();
352 Reg = createResultReg(Subtarget->hasAddr64() ?
353 &WebAssembly::I64RegClass :
354 &WebAssembly::I32RegClass);
355 unsigned Opc = Subtarget->hasAddr64() ?
356 WebAssembly::CONST_I64 :
357 WebAssembly::CONST_I32;
358 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
365 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
366 const MachineInstrBuilder &MIB,
367 MachineMemOperand *MMO) {
368 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
369 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
372 if (const GlobalValue *GV = Addr.getGlobalValue())
373 MIB.addGlobalAddress(GV, Addr.getOffset());
375 MIB.addImm(Addr.getOffset());
377 if (Addr.isRegBase())
378 MIB.addReg(Addr.getReg());
380 MIB.addFrameIndex(Addr.getFI());
382 MIB.addMemOperand(MMO);
385 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
386 return zeroExtendToI32(Reg, V, MVT::i1);
389 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
390 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V))
391 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
392 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
393 Not = ICmp->isTrueWhenEqual();
394 return getRegForValue(ICmp->getOperand(0));
397 if (BinaryOperator::isNot(V)) {
399 return getRegForValue(BinaryOperator::getNotArgument(V));
403 return maskI1Value(getRegForValue(V), V);
406 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
407 MVT::SimpleValueType From) {
413 // If the value is naturally an i1, we don't need to mask it.
414 // TODO: Recursively examine selects, phis, and, or, xor, constants.
415 if (From == MVT::i1 && V != nullptr) {
416 if (isa<CmpInst>(V) ||
417 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
418 return copyValue(Reg);
424 return copyValue(Reg);
429 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
430 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
431 TII.get(WebAssembly::CONST_I32), Imm)
432 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
434 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
435 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
436 TII.get(WebAssembly::AND_I32), Result)
443 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
444 MVT::SimpleValueType From) {
454 return copyValue(Reg);
459 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
460 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
461 TII.get(WebAssembly::CONST_I32), Imm)
462 .addImm(32 - MVT(From).getSizeInBits());
464 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
465 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
466 TII.get(WebAssembly::SHL_I32), Left)
470 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
471 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
472 TII.get(WebAssembly::SHR_S_I32), Right)
479 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
480 MVT::SimpleValueType From,
481 MVT::SimpleValueType To) {
482 if (To == MVT::i64) {
483 if (From == MVT::i64)
484 return copyValue(Reg);
486 Reg = zeroExtendToI32(Reg, V, From);
488 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
489 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
490 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
495 return zeroExtendToI32(Reg, V, From);
498 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
499 MVT::SimpleValueType From,
500 MVT::SimpleValueType To) {
501 if (To == MVT::i64) {
502 if (From == MVT::i64)
503 return copyValue(Reg);
505 Reg = signExtendToI32(Reg, V, From);
507 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
508 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
509 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
514 return signExtendToI32(Reg, V, From);
517 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
518 MVT::SimpleValueType From = getSimpleType(V->getType());
519 MVT::SimpleValueType To = getLegalType(From);
520 return zeroExtend(getRegForValue(V), V, From, To);
523 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
524 MVT::SimpleValueType From = getSimpleType(V->getType());
525 MVT::SimpleValueType To = getLegalType(From);
526 return zeroExtend(getRegForValue(V), V, From, To);
529 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
531 return IsSigned ? getRegForSignedValue(V) :
532 getRegForUnsignedValue(V);
535 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
536 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
538 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
539 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
540 TII.get(WebAssembly::EQZ_I32), NotReg)
545 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
546 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
547 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
548 TII.get(WebAssembly::COPY), ResultReg)
553 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
554 DenseMap<const AllocaInst *, int>::iterator SI =
555 FuncInfo.StaticAllocaMap.find(AI);
557 if (SI != FuncInfo.StaticAllocaMap.end()) {
558 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
559 &WebAssembly::I64RegClass :
560 &WebAssembly::I32RegClass);
561 unsigned Opc = Subtarget->hasAddr64() ?
562 WebAssembly::COPY_I64 :
563 WebAssembly::COPY_I32;
564 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
565 .addFrameIndex(SI->second);
572 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
573 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
574 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ?
575 &WebAssembly::I64RegClass :
576 &WebAssembly::I32RegClass);
577 unsigned Opc = Subtarget->hasAddr64() ?
578 WebAssembly::CONST_I64 :
579 WebAssembly::CONST_I32;
580 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
581 .addGlobalAddress(GV);
585 // Let target-independent code handle it.
589 bool WebAssemblyFastISel::fastLowerArguments() {
590 if (!FuncInfo.CanLowerReturn)
593 const Function *F = FuncInfo.Fn;
598 for (auto const &Arg : F->args()) {
599 const AttributeList &Attrs = F->getAttributes();
600 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
601 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
602 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
603 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
604 Attrs.hasParamAttribute(i, Attribute::Nest))
607 Type *ArgTy = Arg.getType();
608 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
610 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
614 const TargetRegisterClass *RC;
615 switch (getSimpleType(ArgTy)) {
620 Opc = WebAssembly::ARGUMENT_I32;
621 RC = &WebAssembly::I32RegClass;
624 Opc = WebAssembly::ARGUMENT_I64;
625 RC = &WebAssembly::I64RegClass;
628 Opc = WebAssembly::ARGUMENT_F32;
629 RC = &WebAssembly::F32RegClass;
632 Opc = WebAssembly::ARGUMENT_F64;
633 RC = &WebAssembly::F64RegClass;
636 Opc = WebAssembly::ARGUMENT_v16i8;
637 RC = &WebAssembly::V128RegClass;
640 Opc = WebAssembly::ARGUMENT_v8i16;
641 RC = &WebAssembly::V128RegClass;
644 Opc = WebAssembly::ARGUMENT_v4i32;
645 RC = &WebAssembly::V128RegClass;
648 Opc = WebAssembly::ARGUMENT_v4f32;
649 RC = &WebAssembly::V128RegClass;
654 unsigned ResultReg = createResultReg(RC);
655 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
657 updateValueMap(&Arg, ResultReg);
662 MRI.addLiveIn(WebAssembly::ARGUMENTS);
664 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
665 for (auto const &Arg : F->args())
666 MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
668 if (!F->getReturnType()->isVoidTy())
669 MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
674 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
675 const CallInst *Call = cast<CallInst>(I);
677 if (Call->isMustTailCall() || Call->isInlineAsm() ||
678 Call->getFunctionType()->isVarArg())
681 Function *Func = Call->getCalledFunction();
682 if (Func && Func->isIntrinsic())
685 FunctionType *FuncTy = Call->getFunctionType();
687 bool IsDirect = Func != nullptr;
688 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
691 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
693 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
696 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
702 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
703 ResultReg = createResultReg(&WebAssembly::I32RegClass);
706 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
707 ResultReg = createResultReg(&WebAssembly::I64RegClass);
710 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
711 ResultReg = createResultReg(&WebAssembly::F32RegClass);
714 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
715 ResultReg = createResultReg(&WebAssembly::F64RegClass);
719 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
720 ResultReg = createResultReg(&WebAssembly::V128RegClass);
724 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
725 ResultReg = createResultReg(&WebAssembly::V128RegClass);
729 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
730 ResultReg = createResultReg(&WebAssembly::V128RegClass);
734 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
735 ResultReg = createResultReg(&WebAssembly::V128RegClass);
742 SmallVector<unsigned, 8> Args;
743 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) {
744 Value *V = Call->getArgOperand(i);
745 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
746 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
749 const AttributeList &Attrs = Call->getAttributes();
750 if (Attrs.hasParamAttribute(i, Attribute::ByVal) ||
751 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) ||
752 Attrs.hasParamAttribute(i, Attribute::SwiftError) ||
753 Attrs.hasParamAttribute(i, Attribute::InAlloca) ||
754 Attrs.hasParamAttribute(i, Attribute::Nest))
759 if (Attrs.hasParamAttribute(i, Attribute::SExt))
760 Reg = getRegForSignedValue(V);
761 else if (Attrs.hasParamAttribute(i, Attribute::ZExt))
762 Reg = getRegForUnsignedValue(V);
764 Reg = getRegForValue(V);
772 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
775 MIB.addReg(ResultReg, RegState::Define);
778 MIB.addGlobalAddress(Func);
780 MIB.addReg(getRegForValue(Call->getCalledValue()));
782 for (unsigned ArgReg : Args)
786 updateValueMap(Call, ResultReg);
790 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
791 const SelectInst *Select = cast<SelectInst>(I);
794 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
798 unsigned TrueReg = getRegForValue(Select->getTrueValue());
802 unsigned FalseReg = getRegForValue(Select->getFalseValue());
807 std::swap(TrueReg, FalseReg);
810 const TargetRegisterClass *RC;
811 switch (getSimpleType(Select->getType())) {
816 Opc = WebAssembly::SELECT_I32;
817 RC = &WebAssembly::I32RegClass;
820 Opc = WebAssembly::SELECT_I64;
821 RC = &WebAssembly::I64RegClass;
824 Opc = WebAssembly::SELECT_F32;
825 RC = &WebAssembly::F32RegClass;
828 Opc = WebAssembly::SELECT_F64;
829 RC = &WebAssembly::F64RegClass;
835 unsigned ResultReg = createResultReg(RC);
836 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
841 updateValueMap(Select, ResultReg);
845 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
846 const TruncInst *Trunc = cast<TruncInst>(I);
848 unsigned Reg = getRegForValue(Trunc->getOperand(0));
852 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
853 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
854 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
855 TII.get(WebAssembly::I32_WRAP_I64), Result)
860 updateValueMap(Trunc, Reg);
864 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
865 const ZExtInst *ZExt = cast<ZExtInst>(I);
867 const Value *Op = ZExt->getOperand(0);
868 MVT::SimpleValueType From = getSimpleType(Op->getType());
869 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
870 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To);
874 updateValueMap(ZExt, Reg);
878 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
879 const SExtInst *SExt = cast<SExtInst>(I);
881 const Value *Op = SExt->getOperand(0);
882 MVT::SimpleValueType From = getSimpleType(Op->getType());
883 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
884 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To);
888 updateValueMap(SExt, Reg);
892 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
893 const ICmpInst *ICmp = cast<ICmpInst>(I);
895 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
897 bool isSigned = false;
898 switch (ICmp->getPredicate()) {
899 case ICmpInst::ICMP_EQ:
900 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
902 case ICmpInst::ICMP_NE:
903 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
905 case ICmpInst::ICMP_UGT:
906 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
908 case ICmpInst::ICMP_UGE:
909 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
911 case ICmpInst::ICMP_ULT:
912 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
914 case ICmpInst::ICMP_ULE:
915 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
917 case ICmpInst::ICMP_SGT:
918 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
921 case ICmpInst::ICMP_SGE:
922 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
925 case ICmpInst::ICMP_SLT:
926 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
929 case ICmpInst::ICMP_SLE:
930 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
933 default: return false;
936 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned);
940 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned);
944 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
945 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
948 updateValueMap(ICmp, ResultReg);
952 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
953 const FCmpInst *FCmp = cast<FCmpInst>(I);
955 unsigned LHS = getRegForValue(FCmp->getOperand(0));
959 unsigned RHS = getRegForValue(FCmp->getOperand(1));
963 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
966 switch (FCmp->getPredicate()) {
967 case FCmpInst::FCMP_OEQ:
968 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
970 case FCmpInst::FCMP_UNE:
971 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
973 case FCmpInst::FCMP_OGT:
974 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
976 case FCmpInst::FCMP_OGE:
977 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
979 case FCmpInst::FCMP_OLT:
980 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
982 case FCmpInst::FCMP_OLE:
983 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
985 case FCmpInst::FCMP_UGT:
986 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
989 case FCmpInst::FCMP_UGE:
990 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
993 case FCmpInst::FCMP_ULT:
994 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
997 case FCmpInst::FCMP_ULE:
998 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1005 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1006 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1011 ResultReg = notValue(ResultReg);
1013 updateValueMap(FCmp, ResultReg);
1017 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1018 // Target-independent code can handle this, except it doesn't set the dead
1019 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1020 // to satisfy code that expects this of isBitcast() instructions.
1021 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1022 EVT RetVT = TLI.getValueType(DL, I->getType());
1023 if (!VT.isSimple() || !RetVT.isSimple())
1028 updateValueMap(I, getRegForValue(I->getOperand(0)));
1032 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1033 getRegForValue(I->getOperand(0)),
1034 I->getOperand(0)->hasOneUse());
1037 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1039 assert(Iter->isBitcast());
1040 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1041 updateValueMap(I, Reg);
1045 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1046 const LoadInst *Load = cast<LoadInst>(I);
1047 if (Load->isAtomic())
1049 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1053 if (!computeAddress(Load->getPointerOperand(), Addr))
1056 // TODO: Fold a following sign-/zero-extend into the load instruction.
1059 const TargetRegisterClass *RC;
1060 switch (getSimpleType(Load->getType())) {
1063 Opc = WebAssembly::LOAD8_U_I32;
1064 RC = &WebAssembly::I32RegClass;
1067 Opc = WebAssembly::LOAD16_U_I32;
1068 RC = &WebAssembly::I32RegClass;
1071 Opc = WebAssembly::LOAD_I32;
1072 RC = &WebAssembly::I32RegClass;
1075 Opc = WebAssembly::LOAD_I64;
1076 RC = &WebAssembly::I64RegClass;
1079 Opc = WebAssembly::LOAD_F32;
1080 RC = &WebAssembly::F32RegClass;
1083 Opc = WebAssembly::LOAD_F64;
1084 RC = &WebAssembly::F64RegClass;
1090 materializeLoadStoreOperands(Addr);
1092 unsigned ResultReg = createResultReg(RC);
1093 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1096 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1098 updateValueMap(Load, ResultReg);
1102 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1103 const StoreInst *Store = cast<StoreInst>(I);
1104 if (Store->isAtomic())
1106 if (!Subtarget->hasSIMD128() &&
1107 Store->getValueOperand()->getType()->isVectorTy())
1111 if (!computeAddress(Store->getPointerOperand(), Addr))
1115 bool VTIsi1 = false;
1116 switch (getSimpleType(Store->getValueOperand()->getType())) {
1120 Opc = WebAssembly::STORE8_I32;
1123 Opc = WebAssembly::STORE16_I32;
1126 Opc = WebAssembly::STORE_I32;
1129 Opc = WebAssembly::STORE_I64;
1132 Opc = WebAssembly::STORE_F32;
1135 Opc = WebAssembly::STORE_F64;
1137 default: return false;
1140 materializeLoadStoreOperands(Addr);
1142 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1146 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1148 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1150 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1152 MIB.addReg(ValueReg);
1156 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1157 const BranchInst *Br = cast<BranchInst>(I);
1158 if (Br->isUnconditional()) {
1159 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1160 fastEmitBranch(MSucc, Br->getDebugLoc());
1164 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1165 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1168 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1172 unsigned Opc = WebAssembly::BR_IF;
1174 Opc = WebAssembly::BR_UNLESS;
1176 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1180 finishCondBranch(Br->getParent(), TBB, FBB);
1184 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1185 if (!FuncInfo.CanLowerReturn)
1188 const ReturnInst *Ret = cast<ReturnInst>(I);
1190 if (Ret->getNumOperands() == 0) {
1191 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1192 TII.get(WebAssembly::RETURN_VOID));
1196 Value *RV = Ret->getOperand(0);
1197 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1201 switch (getSimpleType(RV->getType())) {
1202 case MVT::i1: case MVT::i8:
1203 case MVT::i16: case MVT::i32:
1204 Opc = WebAssembly::RETURN_I32;
1207 Opc = WebAssembly::RETURN_I64;
1210 Opc = WebAssembly::RETURN_F32;
1213 Opc = WebAssembly::RETURN_F64;
1216 Opc = WebAssembly::RETURN_v16i8;
1219 Opc = WebAssembly::RETURN_v8i16;
1222 Opc = WebAssembly::RETURN_v4i32;
1225 Opc = WebAssembly::RETURN_v4f32;
1227 default: return false;
1231 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1232 Reg = getRegForSignedValue(RV);
1233 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1234 Reg = getRegForUnsignedValue(RV);
1236 Reg = getRegForValue(RV);
1241 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1245 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1246 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1247 TII.get(WebAssembly::UNREACHABLE));
1251 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1252 switch (I->getOpcode()) {
1253 case Instruction::Call:
1257 case Instruction::Select: return selectSelect(I);
1258 case Instruction::Trunc: return selectTrunc(I);
1259 case Instruction::ZExt: return selectZExt(I);
1260 case Instruction::SExt: return selectSExt(I);
1261 case Instruction::ICmp: return selectICmp(I);
1262 case Instruction::FCmp: return selectFCmp(I);
1263 case Instruction::BitCast: return selectBitCast(I);
1264 case Instruction::Load: return selectLoad(I);
1265 case Instruction::Store: return selectStore(I);
1266 case Instruction::Br: return selectBr(I);
1267 case Instruction::Ret: return selectRet(I);
1268 case Instruction::Unreachable: return selectUnreachable(I);
1272 // Fall back to target-independent instruction selection.
1273 return selectOperator(I, I->getOpcode());
1276 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1277 const TargetLibraryInfo *LibInfo) {
1278 return new WebAssemblyFastISel(FuncInfo, LibInfo);