37#include "llvm/IR/IntrinsicsWebAssembly.h"
42#define DEBUG_TYPE "wasm-fastisel"
46class WebAssemblyFastISel final :
public FastISel {
50 enum BaseKind { RegBase, FrameIndexBase };
53 BaseKind Kind = RegBase;
60 bool IsBaseSet =
false;
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(!IsBaseSet &&
"Base cannot be reset");
83 assert(isRegBase() &&
"Invalid base register access!");
86 void setFI(
unsigned FI) {
87 assert(isFIBase() &&
"Invalid base frame index access!");
88 assert(!IsBaseSet &&
"Base cannot be reset");
92 unsigned getFI()
const {
93 assert(isFIBase() &&
"Invalid base frame index access!");
97 void setOffset(int64_t NewOffset) {
98 assert(NewOffset >= 0 &&
"Offsets must be non-negative");
103 const GlobalValue *getGlobalValue()
const {
return GV; }
104 bool isSet()
const {
return IsBaseSet; }
115 EVT VT = TLI.getValueType(
DL, Ty,
true);
155 bool computeAddress(
const Value *Obj, Address &Addr);
156 void materializeLoadStoreOperands(Address &Addr);
160 unsigned maskI1Value(
unsigned Reg,
const Value *V);
161 unsigned getRegForI1Value(
const Value *V,
const BasicBlock *BB,
bool &Not);
162 unsigned zeroExtendToI32(
unsigned Reg,
const Value *V,
164 unsigned signExtendToI32(
unsigned Reg,
const Value *V,
170 unsigned getRegForUnsignedValue(
const Value *V);
171 unsigned getRegForSignedValue(
const Value *V);
172 unsigned getRegForPromotedValue(
const Value *V,
bool IsSigned);
173 unsigned notValue(
unsigned Reg);
174 unsigned copyValue(
unsigned Reg);
179 bool fastLowerArguments()
override;
201 :
FastISel(FuncInfo, LibInfo, LibcallLowering,
207 bool fastSelectInstruction(
const Instruction *
I)
override;
211#include "WebAssemblyGenFastISel.inc"
216bool WebAssemblyFastISel::computeAddress(
const Value *Obj, Address &Addr) {
217 const User *
U =
nullptr;
218 unsigned Opcode = Instruction::UserOp1;
222 if (FuncInfo.StaticAllocaMap.count(
static_cast<const AllocaInst *
>(Obj)) ||
223 FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
224 Opcode =
I->getOpcode();
228 Opcode =
C->getOpcode();
233 if (Ty->getAddressSpace() > 255)
239 if (TLI.isPositionIndependent())
241 if (Addr.getGlobalValue())
243 if (GV->isThreadLocal())
245 Addr.setGlobalValue(GV);
252 case Instruction::BitCast: {
254 return computeAddress(
U->getOperand(0), Addr);
256 case Instruction::IntToPtr: {
258 if (TLI.getValueType(
DL,
U->getOperand(0)->getType()) ==
259 TLI.getPointerTy(
DL))
260 return computeAddress(
U->getOperand(0), Addr);
263 case Instruction::PtrToInt: {
265 if (TLI.getValueType(
DL,
U->getType()) == TLI.getPointerTy(
DL))
266 return computeAddress(
U->getOperand(0), Addr);
269 case Instruction::GetElementPtr: {
271 uint64_t TmpOffset = Addr.getOffset();
274 goto unsupported_gep;
279 const Value *
Op = GTI.getOperand();
280 if (StructType *STy = GTI.getStructTypeOrNull()) {
281 const StructLayout *SL =
DL.getStructLayout(STy);
285 uint64_t S = GTI.getSequentialElementStride(
DL);
289 TmpOffset += CI->getSExtValue() * S;
292 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
300 if (canFoldAddIntoGEP(U,
Op)) {
303 TmpOffset += CI->getSExtValue() * S;
309 goto unsupported_gep;
314 if (int64_t(TmpOffset) >= 0) {
316 Addr.setOffset(TmpOffset);
317 if (computeAddress(
U->getOperand(0), Addr))
325 case Instruction::Alloca: {
327 auto SI = FuncInfo.StaticAllocaMap.find(AI);
328 if (SI != FuncInfo.StaticAllocaMap.end()) {
332 Addr.setKind(Address::FrameIndexBase);
333 Addr.setFI(
SI->second);
338 case Instruction::Add: {
342 if (!OFBinOp->hasNoUnsignedWrap())
353 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
354 if (int64_t(TmpOffset) >= 0) {
355 Addr.setOffset(TmpOffset);
356 return computeAddress(
LHS, Addr);
361 if (computeAddress(
LHS, Addr) && computeAddress(
RHS, Addr))
367 case Instruction::Sub: {
371 if (!OFBinOp->hasNoUnsignedWrap())
379 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
380 if (TmpOffset >= 0) {
381 Addr.setOffset(TmpOffset);
382 return computeAddress(
LHS, Addr);
395 return Addr.getReg() != 0;
398void WebAssemblyFastISel::materializeLoadStoreOperands(
Address &Addr) {
399 if (Addr.isRegBase()) {
400 unsigned Reg = Addr.getReg();
402 Reg = createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
403 : &WebAssembly::I32RegClass);
404 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
405 : WebAssembly::CONST_I32;
413void WebAssemblyFastISel::addLoadStoreOperands(
const Address &Addr,
414 const MachineInstrBuilder &MIB,
415 MachineMemOperand *MMO) {
420 if (
const GlobalValue *GV = Addr.getGlobalValue())
423 MIB.
addImm(Addr.getOffset());
425 if (Addr.isRegBase())
426 MIB.
addReg(Addr.getReg());
433bool WebAssemblyFastISel::emitLoad(
Register ResultReg,
unsigned Opc,
434 const LoadInst *
Load) {
436 if (!computeAddress(
Load->getPointerOperand(), Addr))
439 materializeLoadStoreOperands(Addr);
441 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg);
442 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(
Load));
447unsigned WebAssemblyFastISel::maskI1Value(
unsigned Reg,
const Value *V) {
448 return zeroExtendToI32(
Reg, V, MVT::i1);
451unsigned WebAssemblyFastISel::getRegForI1Value(
const Value *V,
452 const BasicBlock *BB,
456 if (ICmp->isEquality() &&
C->isZero() &&
C->getType()->isIntegerTy(32) &&
457 ICmp->getParent() == BB) {
458 Not = ICmp->isTrueWhenEqual();
459 return getRegForValue(ICmp->getOperand(0));
466 return maskI1Value(
Reg, V);
469unsigned WebAssemblyFastISel::zeroExtendToI32(
unsigned Reg,
const Value *V,
480 return copyValue(
Reg);
486 return copyValue(
Reg);
491 Register Imm = createResultReg(&WebAssembly::I32RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
493 TII.get(WebAssembly::CONST_I32),
Imm)
497 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::AND_I32),
505unsigned WebAssemblyFastISel::signExtendToI32(
unsigned Reg,
const Value *V,
516 return copyValue(
Reg);
522 if (From == MVT::i8 || From == MVT::i16) {
524 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
525 TII.get(From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
526 : WebAssembly::I32_EXTEND8_S_I32),
533 Register Imm = createResultReg(&WebAssembly::I32RegClass);
534 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
535 TII.get(WebAssembly::CONST_I32),
Imm)
536 .
addImm(32 - MVT(From).getSizeInBits());
538 Register Left = createResultReg(&WebAssembly::I32RegClass);
539 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::SHL_I32),
545 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
546 TII.get(WebAssembly::SHR_S_I32),
Right)
553unsigned WebAssemblyFastISel::zeroExtend(
unsigned Reg,
const Value *V,
556 if (To == MVT::i64) {
557 if (From == MVT::i64)
558 return copyValue(
Reg);
560 Reg = zeroExtendToI32(
Reg, V, From);
563 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
564 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
570 return zeroExtendToI32(
Reg, V, From);
575unsigned WebAssemblyFastISel::signExtend(
unsigned Reg,
const Value *V,
578 if (To == MVT::i64) {
579 if (From == MVT::i64)
580 return copyValue(
Reg);
588 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
589 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
593 Result = createResultReg(&WebAssembly::I64RegClass);
595 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
596 TII.get(From == MVT::i8 ? WebAssembly::I64_EXTEND8_S_I64
597 : WebAssembly::I64_EXTEND16_S_I64),
603 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
604 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
612 Reg = signExtendToI32(
Reg, V, From);
616 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
617 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
623 return signExtendToI32(
Reg, V, From);
628unsigned WebAssemblyFastISel::getRegForUnsignedValue(
const Value *V) {
636 return zeroExtend(VReg, V, From, To);
639unsigned WebAssemblyFastISel::getRegForSignedValue(
const Value *V) {
647 return signExtend(VReg, V, From, To);
650unsigned WebAssemblyFastISel::getRegForPromotedValue(
const Value *V,
652 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(
V);
655unsigned WebAssemblyFastISel::notValue(
unsigned Reg) {
656 assert(MRI.getRegClass(
Reg) == &WebAssembly::I32RegClass);
658 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
659 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::EQZ_I32),
665unsigned WebAssemblyFastISel::copyValue(
unsigned Reg) {
666 Register ResultReg = createResultReg(MRI.getRegClass(
Reg));
667 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::COPY),
673Register WebAssemblyFastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
674 auto SI = FuncInfo.StaticAllocaMap.find(AI);
676 if (SI != FuncInfo.StaticAllocaMap.end()) {
678 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
679 : &WebAssembly::I32RegClass);
681 Subtarget->
hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
682 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
690Register WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
692 if (TLI.isPositionIndependent())
694 if (GV->isThreadLocal())
697 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
698 : &WebAssembly::I32RegClass);
699 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
700 : WebAssembly::CONST_I32;
701 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
710bool WebAssemblyFastISel::fastLowerArguments() {
711 if (!FuncInfo.CanLowerReturn)
718 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
722 for (
auto const &Arg :
F->args()) {
723 const AttributeList &
Attrs =
F->getAttributes();
724 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
725 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
726 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
727 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
728 Attrs.hasParamAttr(
I, Attribute::Nest))
731 Type *ArgTy = Arg.getType();
739 switch (getSimpleType(ArgTy)) {
744 Opc = WebAssembly::ARGUMENT_i32;
745 RC = &WebAssembly::I32RegClass;
748 Opc = WebAssembly::ARGUMENT_i64;
749 RC = &WebAssembly::I64RegClass;
752 Opc = WebAssembly::ARGUMENT_f32;
753 RC = &WebAssembly::F32RegClass;
756 Opc = WebAssembly::ARGUMENT_f64;
757 RC = &WebAssembly::F64RegClass;
760 Opc = WebAssembly::ARGUMENT_v16i8;
761 RC = &WebAssembly::V128RegClass;
764 Opc = WebAssembly::ARGUMENT_v8i16;
765 RC = &WebAssembly::V128RegClass;
768 Opc = WebAssembly::ARGUMENT_v4i32;
769 RC = &WebAssembly::V128RegClass;
772 Opc = WebAssembly::ARGUMENT_v2i64;
773 RC = &WebAssembly::V128RegClass;
776 Opc = WebAssembly::ARGUMENT_v4f32;
777 RC = &WebAssembly::V128RegClass;
780 Opc = WebAssembly::ARGUMENT_v2f64;
781 RC = &WebAssembly::V128RegClass;
784 Opc = WebAssembly::ARGUMENT_funcref;
785 RC = &WebAssembly::FUNCREFRegClass;
788 Opc = WebAssembly::ARGUMENT_externref;
789 RC = &WebAssembly::EXTERNREFRegClass;
792 Opc = WebAssembly::ARGUMENT_exnref;
793 RC = &WebAssembly::EXNREFRegClass;
798 Register ResultReg = createResultReg(RC);
799 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
801 updateValueMap(&Arg, ResultReg);
806 MRI.addLiveIn(WebAssembly::ARGUMENTS);
808 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
809 for (
auto const &Arg :
F->args()) {
812 MFI->clearParamsAndResults();
815 MFI->addParam(ArgTy);
818 if (!
F->getReturnType()->isVoidTy()) {
820 getLegalType(getSimpleType(
F->getReturnType()));
822 MFI->clearParamsAndResults();
825 MFI->addResult(RetTy);
831bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
840 if (Func &&
Func->isIntrinsic())
846 bool IsDirect =
Func !=
nullptr;
851 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
852 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
864 ResultReg = createResultReg(&WebAssembly::I32RegClass);
867 ResultReg = createResultReg(&WebAssembly::I64RegClass);
870 ResultReg = createResultReg(&WebAssembly::F32RegClass);
873 ResultReg = createResultReg(&WebAssembly::F64RegClass);
876 ResultReg = createResultReg(&WebAssembly::V128RegClass);
879 ResultReg = createResultReg(&WebAssembly::V128RegClass);
882 ResultReg = createResultReg(&WebAssembly::V128RegClass);
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
894 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
897 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
900 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
907 SmallVector<unsigned, 8>
Args;
915 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
916 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
917 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
918 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
919 Attrs.hasParamAttr(
I, Attribute::Nest))
925 Reg = getRegForSignedValue(V);
927 Reg = getRegForUnsignedValue(V);
929 Reg = getRegForValue(V);
937 unsigned CalleeReg = 0;
944 const Value *FuncrefArg =
nullptr;
946 if (Conv->getIntrinsicID() == Intrinsic::wasm_funcref_to_ptr)
947 FuncrefArg = Conv->getArgOperand(0);
949 const bool IsFuncrefCall = FuncrefArg !=
nullptr;
950 MCSymbolWasm *
Table =
nullptr;
953 if (!IsFuncrefCall) {
955 Table = WebAssembly::getOrCreateFunctionTableSymbol(MF->getContext(),
962 Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(MF->getContext(),
964 CalleeReg = getRegForValue(FuncrefArg);
966 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
967 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
968 TII.get(WebAssembly::CONST_I32), ZeroReg)
970 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
971 TII.get(WebAssembly::TABLE_SET_FUNCREF))
976 CalleeReg = createResultReg(&WebAssembly::I32RegClass);
977 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
978 TII.get(WebAssembly::CONST_I32), CalleeReg)
983 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
986 MIB.
addReg(ResultReg, RegState::Define);
1004 for (
unsigned ArgReg : Args)
1010 if (IsFuncrefCall) {
1012 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
1013 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1014 TII.get(WebAssembly::CONST_I32), ZeroReg)
1016 unsigned NullReg = createResultReg(&WebAssembly::FUNCREFRegClass);
1017 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1018 TII.get(WebAssembly::REF_NULL_FUNCREF), NullReg);
1019 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1020 TII.get(WebAssembly::TABLE_SET_FUNCREF))
1027 updateValueMap(
Call, ResultReg);
1033bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
1038 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
1055 switch (getSimpleType(
Select->getType())) {
1060 Opc = WebAssembly::SELECT_I32;
1061 RC = &WebAssembly::I32RegClass;
1064 Opc = WebAssembly::SELECT_I64;
1065 RC = &WebAssembly::I64RegClass;
1068 Opc = WebAssembly::SELECT_F32;
1069 RC = &WebAssembly::F32RegClass;
1072 Opc = WebAssembly::SELECT_F64;
1073 RC = &WebAssembly::F64RegClass;
1076 Opc = WebAssembly::SELECT_FUNCREF;
1077 RC = &WebAssembly::FUNCREFRegClass;
1079 case MVT::externref:
1080 Opc = WebAssembly::SELECT_EXTERNREF;
1081 RC = &WebAssembly::EXTERNREFRegClass;
1084 Opc = WebAssembly::SELECT_EXNREF;
1085 RC = &WebAssembly::EXNREFRegClass;
1091 Register ResultReg = createResultReg(RC);
1092 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1097 updateValueMap(
Select, ResultReg);
1101bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
1104 const Value *
Op = Trunc->getOperand(0);
1112 if (From == MVT::i64) {
1114 return copyValue(
Reg);
1116 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1118 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1119 TII.get(WebAssembly::I32_WRAP_I64), Result)
1125 if (From == MVT::i32)
1126 return copyValue(
Reg);
1131 unsigned Reg = Truncate(In);
1135 updateValueMap(Trunc,
Reg);
1139bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
1142 const Value *
Op = ZExt->getOperand(0);
1148 unsigned Reg = zeroExtend(In,
Op, From, To);
1152 updateValueMap(ZExt,
Reg);
1156bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1159 const Value *
Op = SExt->getOperand(0);
1165 unsigned Reg = signExtend(In,
Op, From, To);
1169 updateValueMap(SExt,
Reg);
1173bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1176 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1178 bool IsSigned =
false;
1179 switch (ICmp->getPredicate()) {
1180 case ICmpInst::ICMP_EQ:
1181 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1183 case ICmpInst::ICMP_NE:
1184 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1186 case ICmpInst::ICMP_UGT:
1187 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1189 case ICmpInst::ICMP_UGE:
1190 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1192 case ICmpInst::ICMP_ULT:
1193 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1195 case ICmpInst::ICMP_ULE:
1196 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1198 case ICmpInst::ICMP_SGT:
1199 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1202 case ICmpInst::ICMP_SGE:
1203 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1206 case ICmpInst::ICMP_SLT:
1207 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1210 case ICmpInst::ICMP_SLE:
1211 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1218 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1222 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1226 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1227 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1230 updateValueMap(ICmp, ResultReg);
1234bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1237 Register LHS = getRegForValue(FCmp->getOperand(0));
1241 Register RHS = getRegForValue(FCmp->getOperand(1));
1245 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1248 switch (FCmp->getPredicate()) {
1249 case FCmpInst::FCMP_OEQ:
1250 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1252 case FCmpInst::FCMP_UNE:
1253 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1255 case FCmpInst::FCMP_OGT:
1256 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1258 case FCmpInst::FCMP_OGE:
1259 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1261 case FCmpInst::FCMP_OLT:
1262 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1264 case FCmpInst::FCMP_OLE:
1265 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1267 case FCmpInst::FCMP_UGT:
1268 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1271 case FCmpInst::FCMP_UGE:
1272 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1275 case FCmpInst::FCMP_ULT:
1276 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1279 case FCmpInst::FCMP_ULE:
1280 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1287 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1288 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1293 ResultReg = notValue(ResultReg);
1295 updateValueMap(FCmp, ResultReg);
1299bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1303 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1304 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1314 updateValueMap(
I, In);
1324 assert(Iter->isBitcast());
1326 updateValueMap(
I,
Reg);
1334 return WebAssembly::INSTRUCTION_LIST_END;
1336 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1338 return A64 ? WebAssembly::LOAD16_S_I64_A64
1339 : WebAssembly::LOAD16_S_I64_A32;
1341 return A64 ? WebAssembly::LOAD32_S_I64_A64
1342 : WebAssembly::LOAD32_S_I64_A32;
1348 return WebAssembly::INSTRUCTION_LIST_END;
1350 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1352 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1360 return WebAssembly::INSTRUCTION_LIST_END;
1362 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1364 return A64 ? WebAssembly::LOAD16_U_I64_A64
1365 : WebAssembly::LOAD16_U_I64_A32;
1367 return A64 ? WebAssembly::LOAD32_U_I64_A64
1368 : WebAssembly::LOAD32_U_I64_A32;
1374 return WebAssembly::INSTRUCTION_LIST_END;
1376 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1378 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1386 case WebAssembly::I32_EXTEND8_S_I32:
1387 case WebAssembly::I32_EXTEND16_S_I32:
1388 case WebAssembly::I64_EXTEND8_S_I64:
1389 case WebAssembly::I64_EXTEND16_S_I64:
1390 case WebAssembly::I64_EXTEND32_S_I64:
1391 case WebAssembly::I64_EXTEND_S_I32:
1400 case WebAssembly::I32_EXTEND8_S_I32:
1401 case WebAssembly::I32_EXTEND16_S_I32:
1403 case WebAssembly::I64_EXTEND8_S_I64:
1404 case WebAssembly::I64_EXTEND16_S_I64:
1405 case WebAssembly::I64_EXTEND32_S_I64:
1406 case WebAssembly::I64_EXTEND_S_I32:
1413 unsigned Opc =
MI->getOpcode();
1420 return WebAssembly::INSTRUCTION_LIST_END;
1426 unsigned NarrowOpc) {
1433 case WebAssembly::I64_EXTEND_U_I32:
1434 OuterUserMI = UserMI;
1436 case WebAssembly::I64_EXTEND_S_I32:
1437 OuterUserMI = UserMI;
1455 unsigned Opc =
MI->getOpcode();
1456 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1457 if (
Opc != WebAssembly::SHL_I32)
1460 Register DestReg =
MI->getOperand(0).getReg();
1466 if (UserOpc != WebAssembly::SHR_S_I32)
1474 Register ShlAmtReg =
MI->getOperand(2).getReg();
1479 return MI &&
MI->getOpcode() == WebAssembly::CONST_I32 &&
1480 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1482 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1487 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1488 return WebAssembly::INSTRUCTION_LIST_END;
1491 OuterUserMI, NarrowOpc);
1499 if (
MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1500 return WebAssembly::INSTRUCTION_LIST_END;
1503 Register DestReg =
MI->getOperand(0).getReg();
1505 return WebAssembly::INSTRUCTION_LIST_END;
1510 return WebAssembly::INSTRUCTION_LIST_END;
1511 case WebAssembly::I64_EXTEND8_S_I64:
1513 return WebAssembly::INSTRUCTION_LIST_END;
1515 case WebAssembly::I64_EXTEND16_S_I64:
1517 return WebAssembly::INSTRUCTION_LIST_END;
1525 if (
MI->getOpcode() != WebAssembly::COPY)
1526 return WebAssembly::INSTRUCTION_LIST_END;
1530 return WebAssembly::INSTRUCTION_LIST_END;
1532 Register CopyDst =
MI->getOperand(0).getReg();
1534 return WebAssembly::INSTRUCTION_LIST_END;
1539 return WebAssembly::INSTRUCTION_LIST_END;
1540 case WebAssembly::I64_EXTEND_U_I32:
1542 case WebAssembly::I64_EXTEND_S_I32:
1550 if (
MI->getOpcode() != WebAssembly::AND_I32 &&
1551 MI->getOpcode() != WebAssembly::AND_I64)
1552 return WebAssembly::INSTRUCTION_LIST_END;
1555 bool IsConstant =
false;
1556 for (
unsigned I = 1;
I <= 2; ++
I) {
1559 if (
DefMI && (
DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1560 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1561 Mask =
DefMI->getOperand(1).getImm();
1568 return WebAssembly::INSTRUCTION_LIST_END;
1572 return WebAssembly::INSTRUCTION_LIST_END;
1574 if (
MI->getOpcode() == WebAssembly::AND_I64)
1578 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1579 return WebAssembly::INSTRUCTION_LIST_END;
1582 OuterUserMI, NarrowOpc);
1585bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1586 const LoadInst *LI) {
1588 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1590 MachineInstr *UserMI =
nullptr;
1591 MachineInstr *OuterUserMI =
nullptr;
1592 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1594 WebAssembly::INSTRUCTION_LIST_END) {
1596 }
else if ((NewOpc =
1598 WebAssembly::INSTRUCTION_LIST_END) {
1601 WebAssembly::INSTRUCTION_LIST_END) {
1603 :
MI->getOperand(0).getReg();
1605 WebAssembly::INSTRUCTION_LIST_END) {
1606 ResultReg =
MI->getOperand(0).getReg();
1607 }
else if ((NewOpc =
1609 WebAssembly::INSTRUCTION_LIST_END) {
1616 if (!
emitLoad(ResultReg, NewOpc, LI))
1621 removeDeadCode(OuterIter, std::next(OuterIter));
1626 removeDeadCode(UserIter, std::next(UserIter));
1630 removeDeadCode(Iter, std::next(Iter));
1634bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1636 if (
Load->isAtomic())
1638 if (!WebAssembly::isDefaultAddressSpace(
Load->getPointerAddressSpace()))
1648 switch (getSimpleType(
Load->getType())) {
1651 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1652 RC = &WebAssembly::I32RegClass;
1655 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1656 RC = &WebAssembly::I32RegClass;
1659 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1660 RC = &WebAssembly::I32RegClass;
1663 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1664 RC = &WebAssembly::I64RegClass;
1667 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1668 RC = &WebAssembly::F32RegClass;
1671 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1672 RC = &WebAssembly::F64RegClass;
1678 Register ResultReg = createResultReg(RC);
1682 updateValueMap(
Load, ResultReg);
1686bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1688 if (
Store->isAtomic())
1690 if (!WebAssembly::isDefaultAddressSpace(
Store->getPointerAddressSpace()))
1693 Store->getValueOperand()->getType()->isVectorTy())
1697 if (!computeAddress(
Store->getPointerOperand(), Addr))
1701 bool VTIsi1 =
false;
1703 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1708 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1711 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1714 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1717 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1720 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1723 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1729 materializeLoadStoreOperands(Addr);
1731 Register ValueReg = getRegForValue(
Store->getValueOperand());
1735 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1737 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1739 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(
Store));
1745bool WebAssemblyFastISel::selectCondBr(
const Instruction *
I) {
1748 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1749 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1752 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1756 unsigned Opc = WebAssembly::BR_IF;
1758 Opc = WebAssembly::BR_UNLESS;
1760 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1764 finishCondBranch(Br->getParent(),
TBB, FBB);
1768bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1769 if (!FuncInfo.CanLowerReturn)
1774 if (Ret->getNumOperands() == 0) {
1775 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1776 TII.get(WebAssembly::RETURN));
1781 if (Ret->getNumOperands() > 1)
1784 Value *RV = Ret->getOperand(0);
1788 switch (getSimpleType(RV->
getType())) {
1803 case MVT::externref:
1811 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1812 Reg = getRegForSignedValue(RV);
1813 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1814 Reg = getRegForUnsignedValue(RV);
1816 Reg = getRegForValue(RV);
1821 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1826bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1827 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1828 TII.get(WebAssembly::UNREACHABLE));
1832bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1833 switch (
I->getOpcode()) {
1834 case Instruction::Call:
1838 case Instruction::Select:
1839 return selectSelect(
I);
1840 case Instruction::Trunc:
1841 return selectTrunc(
I);
1842 case Instruction::ZExt:
1843 return selectZExt(
I);
1844 case Instruction::SExt:
1845 return selectSExt(
I);
1846 case Instruction::ICmp:
1847 return selectICmp(
I);
1848 case Instruction::FCmp:
1849 return selectFCmp(
I);
1850 case Instruction::BitCast:
1851 return selectBitCast(
I);
1852 case Instruction::Load:
1853 return selectLoad(
I);
1854 case Instruction::Store:
1855 return selectStore(
I);
1856 case Instruction::CondBr:
1857 return selectCondBr(
I);
1858 case Instruction::Ret:
1859 return selectRet(
I);
1860 case Instruction::Unreachable:
1861 return selectUnreachable(
I);
1867 return selectOperator(
I,
I->getOpcode());
1874 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
MachineInstrBuilder MachineInstrBuilder & DefMI
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the FastISel class.
const HexagonInstrInfo * TII
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
static bool isFoldableSExtOpcode(unsigned Opc)
static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static bool isI64SExtResult(unsigned Opc)
static unsigned matchFoldableCopyToI64Ext(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
static unsigned matchFoldableSExtFromPromotedI32(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI)
static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI, MachineInstr *&OuterUserMI)
Matches a sign-extension pattern (shl + shr_s) to fold it into a signed load.
static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI, unsigned NarrowOpc)
static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI, const LoadInst *LI, bool A64)
static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific utility functions.
an instruction to allocate memory on the stack
LLVM Basic Block Representation.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
LLVM_ABI bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
bool isMustTailCall() const
This is an important base class in LLVM.
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
This is an important class for using LLVM in a threaded context.
Tracks which library functions to use for a particular subtarget or function.
An instruction for reading from memory.
@ INVALID_SIMPLE_VALUE_TYPE
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
Wrapper class representing virtual and physical registers.
TypeSize getElementOffset(unsigned Idx) const
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
bool isStructTy() const
True if this is an instance of StructType.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasCallIndirectOverlong() const
bool hasReferenceTypes() const
bool hasExceptionHandling() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
Not(const Pred &P) -> Not< Pred >
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo, const LibcallLoweringInfo *libcallLowering)
@ User
could "use" a pointer
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void diagnoseDontCall(const CallInst &CI)
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
gep_type_iterator gep_type_end(const User *GEP)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
generic_gep_type_iterator<> gep_type_iterator
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
gep_type_iterator gep_type_begin(const User *GEP)
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
MCRegisterClass TargetRegisterClass
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.