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)
494 .
addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
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);
585 if (From != MVT::i32) {
586 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
587 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
591 Result = createResultReg(&WebAssembly::I64RegClass);
596 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
597 TII.get(WebAssembly::I64_EXTEND8_S_I64), Result)
601 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
602 TII.get(WebAssembly::I64_EXTEND16_S_I64), Result)
606 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
607 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
614 Reg = signExtendToI32(
Reg, V, From);
616 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
617 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
625 return signExtendToI32(
Reg, V, From);
630unsigned WebAssemblyFastISel::getRegForUnsignedValue(
const Value *V) {
638 return zeroExtend(VReg, V, From, To);
641unsigned WebAssemblyFastISel::getRegForSignedValue(
const Value *V) {
649 return signExtend(VReg, V, From, To);
652unsigned WebAssemblyFastISel::getRegForPromotedValue(
const Value *V,
654 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(
V);
657unsigned WebAssemblyFastISel::notValue(
unsigned Reg) {
658 assert(MRI.getRegClass(
Reg) == &WebAssembly::I32RegClass);
660 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
661 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::EQZ_I32),
667unsigned WebAssemblyFastISel::copyValue(
unsigned Reg) {
668 Register ResultReg = createResultReg(MRI.getRegClass(
Reg));
669 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::COPY),
675Register WebAssemblyFastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
676 auto SI = FuncInfo.StaticAllocaMap.find(AI);
678 if (SI != FuncInfo.StaticAllocaMap.end()) {
680 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
681 : &WebAssembly::I32RegClass);
683 Subtarget->
hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
684 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
692Register WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
694 if (TLI.isPositionIndependent())
696 if (GV->isThreadLocal())
699 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
700 : &WebAssembly::I32RegClass);
701 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
702 : WebAssembly::CONST_I32;
703 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
712bool WebAssemblyFastISel::fastLowerArguments() {
713 if (!FuncInfo.CanLowerReturn)
720 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
724 for (
auto const &Arg :
F->args()) {
725 const AttributeList &
Attrs =
F->getAttributes();
726 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
727 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
728 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
729 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
730 Attrs.hasParamAttr(
I, Attribute::Nest))
733 Type *ArgTy = Arg.getType();
740 const TargetRegisterClass *RC;
741 switch (getSimpleType(ArgTy)) {
746 Opc = WebAssembly::ARGUMENT_i32;
747 RC = &WebAssembly::I32RegClass;
750 Opc = WebAssembly::ARGUMENT_i64;
751 RC = &WebAssembly::I64RegClass;
754 Opc = WebAssembly::ARGUMENT_f32;
755 RC = &WebAssembly::F32RegClass;
758 Opc = WebAssembly::ARGUMENT_f64;
759 RC = &WebAssembly::F64RegClass;
762 Opc = WebAssembly::ARGUMENT_v16i8;
763 RC = &WebAssembly::V128RegClass;
766 Opc = WebAssembly::ARGUMENT_v8i16;
767 RC = &WebAssembly::V128RegClass;
770 Opc = WebAssembly::ARGUMENT_v4i32;
771 RC = &WebAssembly::V128RegClass;
774 Opc = WebAssembly::ARGUMENT_v2i64;
775 RC = &WebAssembly::V128RegClass;
778 Opc = WebAssembly::ARGUMENT_v4f32;
779 RC = &WebAssembly::V128RegClass;
782 Opc = WebAssembly::ARGUMENT_v2f64;
783 RC = &WebAssembly::V128RegClass;
786 Opc = WebAssembly::ARGUMENT_funcref;
787 RC = &WebAssembly::FUNCREFRegClass;
790 Opc = WebAssembly::ARGUMENT_externref;
791 RC = &WebAssembly::EXTERNREFRegClass;
794 Opc = WebAssembly::ARGUMENT_exnref;
795 RC = &WebAssembly::EXNREFRegClass;
800 Register ResultReg = createResultReg(RC);
801 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
803 updateValueMap(&Arg, ResultReg);
808 MRI.addLiveIn(WebAssembly::ARGUMENTS);
810 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
811 for (
auto const &Arg :
F->args()) {
814 MFI->clearParamsAndResults();
817 MFI->addParam(ArgTy);
820 if (!
F->getReturnType()->isVoidTy()) {
822 getLegalType(getSimpleType(
F->getReturnType()));
824 MFI->clearParamsAndResults();
827 MFI->addResult(RetTy);
833bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
838 WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_DEFAULT)
847 if (Func &&
Func->isIntrinsic())
853 bool IsDirect =
Func !=
nullptr;
858 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
859 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
871 ResultReg = createResultReg(&WebAssembly::I32RegClass);
874 ResultReg = createResultReg(&WebAssembly::I64RegClass);
877 ResultReg = createResultReg(&WebAssembly::F32RegClass);
880 ResultReg = createResultReg(&WebAssembly::F64RegClass);
883 ResultReg = createResultReg(&WebAssembly::V128RegClass);
886 ResultReg = createResultReg(&WebAssembly::V128RegClass);
889 ResultReg = createResultReg(&WebAssembly::V128RegClass);
892 ResultReg = createResultReg(&WebAssembly::V128RegClass);
895 ResultReg = createResultReg(&WebAssembly::V128RegClass);
898 ResultReg = createResultReg(&WebAssembly::V128RegClass);
901 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
904 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
907 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
914 SmallVector<unsigned, 8>
Args;
922 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
923 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
924 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
925 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
926 Attrs.hasParamAttr(
I, Attribute::Nest))
932 Reg = getRegForSignedValue(V);
934 Reg = getRegForUnsignedValue(V);
936 Reg = getRegForValue(V);
944 unsigned CalleeReg = 0;
951 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
954 MIB.
addReg(ResultReg, RegState::Define);
963 MF->getContext(), Subtarget);
975 for (
unsigned ArgReg : Args)
982 updateValueMap(
Call, ResultReg);
988bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
993 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
1009 const TargetRegisterClass *RC;
1010 switch (getSimpleType(
Select->getType())) {
1015 Opc = WebAssembly::SELECT_I32;
1016 RC = &WebAssembly::I32RegClass;
1019 Opc = WebAssembly::SELECT_I64;
1020 RC = &WebAssembly::I64RegClass;
1023 Opc = WebAssembly::SELECT_F32;
1024 RC = &WebAssembly::F32RegClass;
1027 Opc = WebAssembly::SELECT_F64;
1028 RC = &WebAssembly::F64RegClass;
1031 Opc = WebAssembly::SELECT_FUNCREF;
1032 RC = &WebAssembly::FUNCREFRegClass;
1034 case MVT::externref:
1035 Opc = WebAssembly::SELECT_EXTERNREF;
1036 RC = &WebAssembly::EXTERNREFRegClass;
1039 Opc = WebAssembly::SELECT_EXNREF;
1040 RC = &WebAssembly::EXNREFRegClass;
1046 Register ResultReg = createResultReg(RC);
1047 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1052 updateValueMap(
Select, ResultReg);
1056bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
1059 const Value *
Op = Trunc->getOperand(0);
1067 if (From == MVT::i64) {
1069 return copyValue(
Reg);
1071 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1073 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1074 TII.get(WebAssembly::I32_WRAP_I64), Result)
1080 if (From == MVT::i32)
1081 return copyValue(
Reg);
1086 unsigned Reg = Truncate(In);
1090 updateValueMap(Trunc,
Reg);
1094bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
1097 const Value *
Op = ZExt->getOperand(0);
1103 unsigned Reg = zeroExtend(In,
Op, From, To);
1107 updateValueMap(ZExt,
Reg);
1111bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1114 const Value *
Op = SExt->getOperand(0);
1120 unsigned Reg = signExtend(In,
Op, From, To);
1124 updateValueMap(SExt,
Reg);
1128bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1131 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1133 bool IsSigned =
false;
1134 switch (ICmp->getPredicate()) {
1135 case ICmpInst::ICMP_EQ:
1136 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1138 case ICmpInst::ICMP_NE:
1139 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1141 case ICmpInst::ICMP_UGT:
1142 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1144 case ICmpInst::ICMP_UGE:
1145 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1147 case ICmpInst::ICMP_ULT:
1148 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1150 case ICmpInst::ICMP_ULE:
1151 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1153 case ICmpInst::ICMP_SGT:
1154 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1157 case ICmpInst::ICMP_SGE:
1158 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1161 case ICmpInst::ICMP_SLT:
1162 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1165 case ICmpInst::ICMP_SLE:
1166 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1173 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1177 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1181 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1182 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1185 updateValueMap(ICmp, ResultReg);
1189bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1192 Register LHS = getRegForValue(FCmp->getOperand(0));
1196 Register RHS = getRegForValue(FCmp->getOperand(1));
1200 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1203 switch (FCmp->getPredicate()) {
1204 case FCmpInst::FCMP_OEQ:
1205 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1207 case FCmpInst::FCMP_UNE:
1208 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1210 case FCmpInst::FCMP_OGT:
1211 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1213 case FCmpInst::FCMP_OGE:
1214 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1216 case FCmpInst::FCMP_OLT:
1217 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1219 case FCmpInst::FCMP_OLE:
1220 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1222 case FCmpInst::FCMP_UGT:
1223 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1226 case FCmpInst::FCMP_UGE:
1227 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1230 case FCmpInst::FCMP_ULT:
1231 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1234 case FCmpInst::FCMP_ULE:
1235 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1242 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1243 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1248 ResultReg = notValue(ResultReg);
1250 updateValueMap(FCmp, ResultReg);
1254bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1258 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1259 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1269 updateValueMap(
I, In);
1279 assert(Iter->isBitcast());
1281 updateValueMap(
I,
Reg);
1289 return WebAssembly::INSTRUCTION_LIST_END;
1291 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1293 return A64 ? WebAssembly::LOAD16_S_I64_A64
1294 : WebAssembly::LOAD16_S_I64_A32;
1296 return A64 ? WebAssembly::LOAD32_S_I64_A64
1297 : WebAssembly::LOAD32_S_I64_A32;
1303 return WebAssembly::INSTRUCTION_LIST_END;
1305 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1307 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1315 return WebAssembly::INSTRUCTION_LIST_END;
1317 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1319 return A64 ? WebAssembly::LOAD16_U_I64_A64
1320 : WebAssembly::LOAD16_U_I64_A32;
1322 return A64 ? WebAssembly::LOAD32_U_I64_A64
1323 : WebAssembly::LOAD32_U_I64_A32;
1329 return WebAssembly::INSTRUCTION_LIST_END;
1331 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1333 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1341 case WebAssembly::I32_EXTEND8_S_I32:
1342 case WebAssembly::I32_EXTEND16_S_I32:
1343 case WebAssembly::I64_EXTEND8_S_I64:
1344 case WebAssembly::I64_EXTEND16_S_I64:
1345 case WebAssembly::I64_EXTEND32_S_I64:
1346 case WebAssembly::I64_EXTEND_S_I32:
1355 case WebAssembly::I32_EXTEND8_S_I32:
1356 case WebAssembly::I32_EXTEND16_S_I32:
1358 case WebAssembly::I64_EXTEND8_S_I64:
1359 case WebAssembly::I64_EXTEND16_S_I64:
1360 case WebAssembly::I64_EXTEND32_S_I64:
1361 case WebAssembly::I64_EXTEND_S_I32:
1368 unsigned Opc =
MI->getOpcode();
1375 return WebAssembly::INSTRUCTION_LIST_END;
1381 unsigned NarrowOpc) {
1388 case WebAssembly::I64_EXTEND_U_I32:
1389 OuterUserMI = UserMI;
1391 case WebAssembly::I64_EXTEND_S_I32:
1392 OuterUserMI = UserMI;
1410 unsigned Opc =
MI->getOpcode();
1411 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1412 if (
Opc != WebAssembly::SHL_I32)
1415 Register DestReg =
MI->getOperand(0).getReg();
1421 if (UserOpc != WebAssembly::SHR_S_I32)
1429 Register ShlAmtReg =
MI->getOperand(2).getReg();
1434 return MI &&
MI->getOpcode() == WebAssembly::CONST_I32 &&
1435 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1437 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1442 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1443 return WebAssembly::INSTRUCTION_LIST_END;
1446 OuterUserMI, NarrowOpc);
1454 if (
MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1455 return WebAssembly::INSTRUCTION_LIST_END;
1458 Register DestReg =
MI->getOperand(0).getReg();
1460 return WebAssembly::INSTRUCTION_LIST_END;
1465 return WebAssembly::INSTRUCTION_LIST_END;
1466 case WebAssembly::I64_EXTEND8_S_I64:
1468 return WebAssembly::INSTRUCTION_LIST_END;
1470 case WebAssembly::I64_EXTEND16_S_I64:
1472 return WebAssembly::INSTRUCTION_LIST_END;
1480 if (
MI->getOpcode() != WebAssembly::COPY)
1481 return WebAssembly::INSTRUCTION_LIST_END;
1485 return WebAssembly::INSTRUCTION_LIST_END;
1487 Register CopyDst =
MI->getOperand(0).getReg();
1489 return WebAssembly::INSTRUCTION_LIST_END;
1494 return WebAssembly::INSTRUCTION_LIST_END;
1495 case WebAssembly::I64_EXTEND_U_I32:
1497 case WebAssembly::I64_EXTEND_S_I32:
1505 if (
MI->getOpcode() != WebAssembly::AND_I32 &&
1506 MI->getOpcode() != WebAssembly::AND_I64)
1507 return WebAssembly::INSTRUCTION_LIST_END;
1510 bool IsConstant =
false;
1511 for (
unsigned I = 1;
I <= 2; ++
I) {
1514 if (
DefMI && (
DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1515 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1516 Mask =
DefMI->getOperand(1).getImm();
1523 return WebAssembly::INSTRUCTION_LIST_END;
1527 return WebAssembly::INSTRUCTION_LIST_END;
1529 if (
MI->getOpcode() == WebAssembly::AND_I64)
1533 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1534 return WebAssembly::INSTRUCTION_LIST_END;
1537 OuterUserMI, NarrowOpc);
1540bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1541 const LoadInst *LI) {
1543 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1545 MachineInstr *UserMI =
nullptr;
1546 MachineInstr *OuterUserMI =
nullptr;
1547 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1549 WebAssembly::INSTRUCTION_LIST_END) {
1551 }
else if ((NewOpc =
1553 WebAssembly::INSTRUCTION_LIST_END) {
1556 WebAssembly::INSTRUCTION_LIST_END) {
1558 :
MI->getOperand(0).getReg();
1560 WebAssembly::INSTRUCTION_LIST_END) {
1561 ResultReg =
MI->getOperand(0).getReg();
1562 }
else if ((NewOpc =
1564 WebAssembly::INSTRUCTION_LIST_END) {
1571 if (!
emitLoad(ResultReg, NewOpc, LI))
1576 removeDeadCode(OuterIter, std::next(OuterIter));
1581 removeDeadCode(UserIter, std::next(UserIter));
1585 removeDeadCode(Iter, std::next(Iter));
1589bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1591 if (
Load->isAtomic())
1601 const TargetRegisterClass *RC;
1603 switch (getSimpleType(
Load->getType())) {
1606 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1607 RC = &WebAssembly::I32RegClass;
1610 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1611 RC = &WebAssembly::I32RegClass;
1614 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1615 RC = &WebAssembly::I32RegClass;
1618 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1619 RC = &WebAssembly::I64RegClass;
1622 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1623 RC = &WebAssembly::F32RegClass;
1626 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1627 RC = &WebAssembly::F64RegClass;
1633 Register ResultReg = createResultReg(RC);
1637 updateValueMap(Load, ResultReg);
1641bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1643 if (
Store->isAtomic())
1648 Store->getValueOperand()->getType()->isVectorTy())
1652 if (!computeAddress(
Store->getPointerOperand(), Addr))
1656 bool VTIsi1 =
false;
1658 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1663 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1666 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1669 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1672 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1675 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1678 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1684 materializeLoadStoreOperands(Addr);
1686 Register ValueReg = getRegForValue(
Store->getValueOperand());
1690 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1692 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1694 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1700bool WebAssemblyFastISel::selectCondBr(
const Instruction *
I) {
1703 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1704 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1707 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1711 unsigned Opc = WebAssembly::BR_IF;
1713 Opc = WebAssembly::BR_UNLESS;
1715 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1719 finishCondBranch(Br->getParent(),
TBB, FBB);
1723bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1724 if (!FuncInfo.CanLowerReturn)
1729 if (Ret->getNumOperands() == 0) {
1730 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1731 TII.get(WebAssembly::RETURN));
1736 if (Ret->getNumOperands() > 1)
1739 Value *RV = Ret->getOperand(0);
1743 switch (getSimpleType(RV->
getType())) {
1758 case MVT::externref:
1766 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1767 Reg = getRegForSignedValue(RV);
1768 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1769 Reg = getRegForUnsignedValue(RV);
1771 Reg = getRegForValue(RV);
1776 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1781bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1782 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1783 TII.get(WebAssembly::UNREACHABLE));
1787bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1788 switch (
I->getOpcode()) {
1789 case Instruction::Call:
1793 case Instruction::Select:
1794 return selectSelect(
I);
1795 case Instruction::Trunc:
1796 return selectTrunc(
I);
1797 case Instruction::ZExt:
1798 return selectZExt(
I);
1799 case Instruction::SExt:
1800 return selectSExt(
I);
1801 case Instruction::ICmp:
1802 return selectICmp(
I);
1803 case Instruction::FCmp:
1804 return selectFCmp(
I);
1805 case Instruction::BitCast:
1806 return selectBitCast(
I);
1807 case Instruction::Load:
1808 return selectLoad(
I);
1809 case Instruction::Store:
1810 return selectStore(
I);
1811 case Instruction::CondBr:
1812 return selectCondBr(
I);
1813 case Instruction::Ret:
1814 return selectRet(
I);
1815 case Instruction::Unreachable:
1816 return selectUnreachable(
I);
1822 return selectOperator(
I,
I->getOpcode());
1829 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< 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 type parsing utility functions.
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.
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 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.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
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.
@ C
The default llvm calling convention, compatible with C.
Not(const Pred &P) -> Not< Pred >
bool isDefaultAddressSpace(unsigned AS)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
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.
FunctionAddr VTableAddr Value
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)
gep_type_iterator gep_type_end(const User *GEP)
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.
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.