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 DenseMap<const AllocaInst *, int>::iterator
SI =
328 FuncInfo.StaticAllocaMap.find(AI);
329 if (SI != FuncInfo.StaticAllocaMap.end()) {
333 Addr.setKind(Address::FrameIndexBase);
334 Addr.setFI(
SI->second);
339 case Instruction::Add: {
343 if (!OFBinOp->hasNoUnsignedWrap())
354 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
355 if (int64_t(TmpOffset) >= 0) {
356 Addr.setOffset(TmpOffset);
357 return computeAddress(
LHS, Addr);
362 if (computeAddress(
LHS, Addr) && computeAddress(
RHS, Addr))
368 case Instruction::Sub: {
372 if (!OFBinOp->hasNoUnsignedWrap())
380 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
381 if (TmpOffset >= 0) {
382 Addr.setOffset(TmpOffset);
383 return computeAddress(
LHS, Addr);
396 return Addr.getReg() != 0;
399void WebAssemblyFastISel::materializeLoadStoreOperands(
Address &Addr) {
400 if (Addr.isRegBase()) {
401 unsigned Reg = Addr.getReg();
403 Reg = createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
404 : &WebAssembly::I32RegClass);
405 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
406 : WebAssembly::CONST_I32;
414void WebAssemblyFastISel::addLoadStoreOperands(
const Address &Addr,
415 const MachineInstrBuilder &MIB,
416 MachineMemOperand *MMO) {
421 if (
const GlobalValue *GV = Addr.getGlobalValue())
424 MIB.
addImm(Addr.getOffset());
426 if (Addr.isRegBase())
427 MIB.
addReg(Addr.getReg());
434bool WebAssemblyFastISel::emitLoad(
Register ResultReg,
unsigned Opc,
435 const LoadInst *Load) {
437 if (!computeAddress(
Load->getPointerOperand(), Addr))
440 materializeLoadStoreOperands(Addr);
442 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg);
443 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
448unsigned WebAssemblyFastISel::maskI1Value(
unsigned Reg,
const Value *V) {
449 return zeroExtendToI32(
Reg, V, MVT::i1);
452unsigned WebAssemblyFastISel::getRegForI1Value(
const Value *V,
453 const BasicBlock *BB,
457 if (ICmp->isEquality() &&
C->isZero() &&
C->getType()->isIntegerTy(32) &&
458 ICmp->getParent() == BB) {
459 Not = ICmp->isTrueWhenEqual();
460 return getRegForValue(ICmp->getOperand(0));
467 return maskI1Value(
Reg, V);
470unsigned WebAssemblyFastISel::zeroExtendToI32(
unsigned Reg,
const Value *V,
481 return copyValue(
Reg);
487 return copyValue(
Reg);
492 Register Imm = createResultReg(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
494 TII.get(WebAssembly::CONST_I32), Imm)
495 .
addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::AND_I32),
506unsigned WebAssemblyFastISel::signExtendToI32(
unsigned Reg,
const Value *V,
517 return copyValue(
Reg);
523 if (From == MVT::i8 || From == MVT::i16) {
525 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
526 TII.get(From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
527 : WebAssembly::I32_EXTEND8_S_I32),
534 Register Imm = createResultReg(&WebAssembly::I32RegClass);
535 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
536 TII.get(WebAssembly::CONST_I32), Imm)
537 .
addImm(32 - MVT(From).getSizeInBits());
539 Register Left = createResultReg(&WebAssembly::I32RegClass);
540 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::SHL_I32),
546 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
547 TII.get(WebAssembly::SHR_S_I32),
Right)
554unsigned WebAssemblyFastISel::zeroExtend(
unsigned Reg,
const Value *V,
557 if (To == MVT::i64) {
558 if (From == MVT::i64)
559 return copyValue(
Reg);
561 Reg = zeroExtendToI32(
Reg, V, From);
564 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
565 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
571 return zeroExtendToI32(
Reg, V, From);
576unsigned WebAssemblyFastISel::signExtend(
unsigned Reg,
const Value *V,
579 if (To == MVT::i64) {
580 if (From == MVT::i64)
581 return copyValue(
Reg);
586 if (From != MVT::i32) {
587 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
588 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
592 Result = createResultReg(&WebAssembly::I64RegClass);
597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
598 TII.get(WebAssembly::I64_EXTEND8_S_I64), Result)
602 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
603 TII.get(WebAssembly::I64_EXTEND16_S_I64), Result)
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
608 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
615 Reg = signExtendToI32(
Reg, V, From);
617 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
618 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
626 return signExtendToI32(
Reg, V, From);
631unsigned WebAssemblyFastISel::getRegForUnsignedValue(
const Value *V) {
639 return zeroExtend(VReg, V, From, To);
642unsigned WebAssemblyFastISel::getRegForSignedValue(
const Value *V) {
650 return signExtend(VReg, V, From, To);
653unsigned WebAssemblyFastISel::getRegForPromotedValue(
const Value *V,
655 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(
V);
658unsigned WebAssemblyFastISel::notValue(
unsigned Reg) {
659 assert(MRI.getRegClass(
Reg) == &WebAssembly::I32RegClass);
661 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
662 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::EQZ_I32),
668unsigned WebAssemblyFastISel::copyValue(
unsigned Reg) {
669 Register ResultReg = createResultReg(MRI.getRegClass(
Reg));
670 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::COPY),
676Register WebAssemblyFastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
677 DenseMap<const AllocaInst *, int>::iterator
SI =
678 FuncInfo.StaticAllocaMap.find(AI);
680 if (SI != FuncInfo.StaticAllocaMap.end()) {
682 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
683 : &WebAssembly::I32RegClass);
685 Subtarget->
hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
686 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
694Register WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
696 if (TLI.isPositionIndependent())
698 if (GV->isThreadLocal())
701 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
702 : &WebAssembly::I32RegClass);
703 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
704 : WebAssembly::CONST_I32;
705 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
714bool WebAssemblyFastISel::fastLowerArguments() {
715 if (!FuncInfo.CanLowerReturn)
722 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
726 for (
auto const &Arg :
F->args()) {
727 const AttributeList &
Attrs =
F->getAttributes();
728 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
729 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
730 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
731 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
732 Attrs.hasParamAttr(
I, Attribute::Nest))
735 Type *ArgTy = Arg.getType();
742 const TargetRegisterClass *RC;
743 switch (getSimpleType(ArgTy)) {
748 Opc = WebAssembly::ARGUMENT_i32;
749 RC = &WebAssembly::I32RegClass;
752 Opc = WebAssembly::ARGUMENT_i64;
753 RC = &WebAssembly::I64RegClass;
756 Opc = WebAssembly::ARGUMENT_f32;
757 RC = &WebAssembly::F32RegClass;
760 Opc = WebAssembly::ARGUMENT_f64;
761 RC = &WebAssembly::F64RegClass;
764 Opc = WebAssembly::ARGUMENT_v16i8;
765 RC = &WebAssembly::V128RegClass;
768 Opc = WebAssembly::ARGUMENT_v8i16;
769 RC = &WebAssembly::V128RegClass;
772 Opc = WebAssembly::ARGUMENT_v4i32;
773 RC = &WebAssembly::V128RegClass;
776 Opc = WebAssembly::ARGUMENT_v2i64;
777 RC = &WebAssembly::V128RegClass;
780 Opc = WebAssembly::ARGUMENT_v4f32;
781 RC = &WebAssembly::V128RegClass;
784 Opc = WebAssembly::ARGUMENT_v2f64;
785 RC = &WebAssembly::V128RegClass;
788 Opc = WebAssembly::ARGUMENT_funcref;
789 RC = &WebAssembly::FUNCREFRegClass;
792 Opc = WebAssembly::ARGUMENT_externref;
793 RC = &WebAssembly::EXTERNREFRegClass;
796 Opc = WebAssembly::ARGUMENT_exnref;
797 RC = &WebAssembly::EXNREFRegClass;
802 Register ResultReg = createResultReg(RC);
803 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
805 updateValueMap(&Arg, ResultReg);
810 MRI.addLiveIn(WebAssembly::ARGUMENTS);
812 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
813 for (
auto const &Arg :
F->args()) {
816 MFI->clearParamsAndResults();
819 MFI->addParam(ArgTy);
822 if (!
F->getReturnType()->isVoidTy()) {
824 getLegalType(getSimpleType(
F->getReturnType()));
826 MFI->clearParamsAndResults();
829 MFI->addResult(RetTy);
835bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
840 WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_DEFAULT)
849 if (Func &&
Func->isIntrinsic())
855 bool IsDirect =
Func !=
nullptr;
860 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
861 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
873 ResultReg = createResultReg(&WebAssembly::I32RegClass);
876 ResultReg = createResultReg(&WebAssembly::I64RegClass);
879 ResultReg = createResultReg(&WebAssembly::F32RegClass);
882 ResultReg = createResultReg(&WebAssembly::F64RegClass);
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
894 ResultReg = createResultReg(&WebAssembly::V128RegClass);
897 ResultReg = createResultReg(&WebAssembly::V128RegClass);
900 ResultReg = createResultReg(&WebAssembly::V128RegClass);
903 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
906 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
909 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
916 SmallVector<unsigned, 8>
Args;
924 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
925 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
926 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
927 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
928 Attrs.hasParamAttr(
I, Attribute::Nest))
934 Reg = getRegForSignedValue(V);
936 Reg = getRegForUnsignedValue(V);
938 Reg = getRegForValue(V);
946 unsigned CalleeReg = 0;
953 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
956 MIB.
addReg(ResultReg, RegState::Define);
965 MF->getContext(), Subtarget);
977 for (
unsigned ArgReg : Args)
984 updateValueMap(
Call, ResultReg);
990bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
995 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
1011 const TargetRegisterClass *RC;
1012 switch (getSimpleType(
Select->getType())) {
1017 Opc = WebAssembly::SELECT_I32;
1018 RC = &WebAssembly::I32RegClass;
1021 Opc = WebAssembly::SELECT_I64;
1022 RC = &WebAssembly::I64RegClass;
1025 Opc = WebAssembly::SELECT_F32;
1026 RC = &WebAssembly::F32RegClass;
1029 Opc = WebAssembly::SELECT_F64;
1030 RC = &WebAssembly::F64RegClass;
1033 Opc = WebAssembly::SELECT_FUNCREF;
1034 RC = &WebAssembly::FUNCREFRegClass;
1036 case MVT::externref:
1037 Opc = WebAssembly::SELECT_EXTERNREF;
1038 RC = &WebAssembly::EXTERNREFRegClass;
1041 Opc = WebAssembly::SELECT_EXNREF;
1042 RC = &WebAssembly::EXNREFRegClass;
1048 Register ResultReg = createResultReg(RC);
1049 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1054 updateValueMap(
Select, ResultReg);
1058bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
1061 const Value *
Op = Trunc->getOperand(0);
1069 if (From == MVT::i64) {
1071 return copyValue(
Reg);
1073 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1075 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1076 TII.get(WebAssembly::I32_WRAP_I64), Result)
1082 if (From == MVT::i32)
1083 return copyValue(
Reg);
1088 unsigned Reg = Truncate(In);
1092 updateValueMap(Trunc,
Reg);
1096bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
1099 const Value *
Op = ZExt->getOperand(0);
1105 unsigned Reg = zeroExtend(In,
Op, From, To);
1109 updateValueMap(ZExt,
Reg);
1113bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1116 const Value *
Op = SExt->getOperand(0);
1122 unsigned Reg = signExtend(In,
Op, From, To);
1126 updateValueMap(SExt,
Reg);
1130bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1133 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1135 bool IsSigned =
false;
1136 switch (ICmp->getPredicate()) {
1137 case ICmpInst::ICMP_EQ:
1138 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1140 case ICmpInst::ICMP_NE:
1141 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1143 case ICmpInst::ICMP_UGT:
1144 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1146 case ICmpInst::ICMP_UGE:
1147 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1149 case ICmpInst::ICMP_ULT:
1150 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1152 case ICmpInst::ICMP_ULE:
1153 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1155 case ICmpInst::ICMP_SGT:
1156 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1159 case ICmpInst::ICMP_SGE:
1160 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1163 case ICmpInst::ICMP_SLT:
1164 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1167 case ICmpInst::ICMP_SLE:
1168 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1175 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1179 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1183 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1184 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1187 updateValueMap(ICmp, ResultReg);
1191bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1194 Register LHS = getRegForValue(FCmp->getOperand(0));
1198 Register RHS = getRegForValue(FCmp->getOperand(1));
1202 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1205 switch (FCmp->getPredicate()) {
1206 case FCmpInst::FCMP_OEQ:
1207 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1209 case FCmpInst::FCMP_UNE:
1210 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1212 case FCmpInst::FCMP_OGT:
1213 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1215 case FCmpInst::FCMP_OGE:
1216 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1218 case FCmpInst::FCMP_OLT:
1219 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1221 case FCmpInst::FCMP_OLE:
1222 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1224 case FCmpInst::FCMP_UGT:
1225 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1228 case FCmpInst::FCMP_UGE:
1229 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1232 case FCmpInst::FCMP_ULT:
1233 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1236 case FCmpInst::FCMP_ULE:
1237 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1244 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1245 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1250 ResultReg = notValue(ResultReg);
1252 updateValueMap(FCmp, ResultReg);
1256bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1260 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1261 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1271 updateValueMap(
I, In);
1281 assert(Iter->isBitcast());
1283 updateValueMap(
I,
Reg);
1291 return WebAssembly::INSTRUCTION_LIST_END;
1293 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1295 return A64 ? WebAssembly::LOAD16_S_I64_A64
1296 : WebAssembly::LOAD16_S_I64_A32;
1298 return A64 ? WebAssembly::LOAD32_S_I64_A64
1299 : WebAssembly::LOAD32_S_I64_A32;
1305 return WebAssembly::INSTRUCTION_LIST_END;
1307 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1309 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1317 return WebAssembly::INSTRUCTION_LIST_END;
1319 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1321 return A64 ? WebAssembly::LOAD16_U_I64_A64
1322 : WebAssembly::LOAD16_U_I64_A32;
1324 return A64 ? WebAssembly::LOAD32_U_I64_A64
1325 : WebAssembly::LOAD32_U_I64_A32;
1331 return WebAssembly::INSTRUCTION_LIST_END;
1333 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1335 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1343 case WebAssembly::I32_EXTEND8_S_I32:
1344 case WebAssembly::I32_EXTEND16_S_I32:
1345 case WebAssembly::I64_EXTEND8_S_I64:
1346 case WebAssembly::I64_EXTEND16_S_I64:
1347 case WebAssembly::I64_EXTEND32_S_I64:
1348 case WebAssembly::I64_EXTEND_S_I32:
1357 case WebAssembly::I32_EXTEND8_S_I32:
1358 case WebAssembly::I32_EXTEND16_S_I32:
1360 case WebAssembly::I64_EXTEND8_S_I64:
1361 case WebAssembly::I64_EXTEND16_S_I64:
1362 case WebAssembly::I64_EXTEND32_S_I64:
1363 case WebAssembly::I64_EXTEND_S_I32:
1370 unsigned Opc =
MI->getOpcode();
1377 return WebAssembly::INSTRUCTION_LIST_END;
1383 unsigned NarrowOpc) {
1390 case WebAssembly::I64_EXTEND_U_I32:
1391 OuterUserMI = UserMI;
1393 case WebAssembly::I64_EXTEND_S_I32:
1394 OuterUserMI = UserMI;
1412 unsigned Opc =
MI->getOpcode();
1413 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1414 if (
Opc != WebAssembly::SHL_I32)
1417 Register DestReg =
MI->getOperand(0).getReg();
1423 if (UserOpc != WebAssembly::SHR_S_I32)
1431 Register ShlAmtReg =
MI->getOperand(2).getReg();
1436 return MI &&
MI->getOpcode() == WebAssembly::CONST_I32 &&
1437 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1439 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1444 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1445 return WebAssembly::INSTRUCTION_LIST_END;
1448 OuterUserMI, NarrowOpc);
1456 if (
MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1457 return WebAssembly::INSTRUCTION_LIST_END;
1460 Register DestReg =
MI->getOperand(0).getReg();
1462 return WebAssembly::INSTRUCTION_LIST_END;
1467 return WebAssembly::INSTRUCTION_LIST_END;
1468 case WebAssembly::I64_EXTEND8_S_I64:
1470 return WebAssembly::INSTRUCTION_LIST_END;
1472 case WebAssembly::I64_EXTEND16_S_I64:
1474 return WebAssembly::INSTRUCTION_LIST_END;
1482 if (
MI->getOpcode() != WebAssembly::COPY)
1483 return WebAssembly::INSTRUCTION_LIST_END;
1487 return WebAssembly::INSTRUCTION_LIST_END;
1489 Register CopyDst =
MI->getOperand(0).getReg();
1491 return WebAssembly::INSTRUCTION_LIST_END;
1496 return WebAssembly::INSTRUCTION_LIST_END;
1497 case WebAssembly::I64_EXTEND_U_I32:
1499 case WebAssembly::I64_EXTEND_S_I32:
1507 if (
MI->getOpcode() != WebAssembly::AND_I32 &&
1508 MI->getOpcode() != WebAssembly::AND_I64)
1509 return WebAssembly::INSTRUCTION_LIST_END;
1512 bool IsConstant =
false;
1513 for (
unsigned I = 1;
I <= 2; ++
I) {
1516 if (
DefMI && (
DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1517 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1518 Mask =
DefMI->getOperand(1).getImm();
1525 return WebAssembly::INSTRUCTION_LIST_END;
1529 return WebAssembly::INSTRUCTION_LIST_END;
1531 if (
MI->getOpcode() == WebAssembly::AND_I64)
1535 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1536 return WebAssembly::INSTRUCTION_LIST_END;
1539 OuterUserMI, NarrowOpc);
1542bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1543 const LoadInst *LI) {
1545 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1547 MachineInstr *UserMI =
nullptr;
1548 MachineInstr *OuterUserMI =
nullptr;
1549 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1551 WebAssembly::INSTRUCTION_LIST_END) {
1553 }
else if ((NewOpc =
1555 WebAssembly::INSTRUCTION_LIST_END) {
1558 WebAssembly::INSTRUCTION_LIST_END) {
1560 :
MI->getOperand(0).getReg();
1562 WebAssembly::INSTRUCTION_LIST_END) {
1563 ResultReg =
MI->getOperand(0).getReg();
1564 }
else if ((NewOpc =
1566 WebAssembly::INSTRUCTION_LIST_END) {
1573 if (!
emitLoad(ResultReg, NewOpc, LI))
1578 removeDeadCode(OuterIter, std::next(OuterIter));
1583 removeDeadCode(UserIter, std::next(UserIter));
1587 removeDeadCode(Iter, std::next(Iter));
1591bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1593 if (
Load->isAtomic())
1603 const TargetRegisterClass *RC;
1605 switch (getSimpleType(
Load->getType())) {
1608 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1609 RC = &WebAssembly::I32RegClass;
1612 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1613 RC = &WebAssembly::I32RegClass;
1616 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1617 RC = &WebAssembly::I32RegClass;
1620 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1621 RC = &WebAssembly::I64RegClass;
1624 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1625 RC = &WebAssembly::F32RegClass;
1628 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1629 RC = &WebAssembly::F64RegClass;
1635 Register ResultReg = createResultReg(RC);
1639 updateValueMap(Load, ResultReg);
1643bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1645 if (
Store->isAtomic())
1650 Store->getValueOperand()->getType()->isVectorTy())
1654 if (!computeAddress(
Store->getPointerOperand(), Addr))
1658 bool VTIsi1 =
false;
1660 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1665 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1668 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1671 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1674 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1677 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1680 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1686 materializeLoadStoreOperands(Addr);
1688 Register ValueReg = getRegForValue(
Store->getValueOperand());
1692 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1694 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1696 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1702bool WebAssemblyFastISel::selectCondBr(
const Instruction *
I) {
1705 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1706 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1709 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1713 unsigned Opc = WebAssembly::BR_IF;
1715 Opc = WebAssembly::BR_UNLESS;
1717 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1721 finishCondBranch(Br->getParent(),
TBB, FBB);
1725bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1726 if (!FuncInfo.CanLowerReturn)
1731 if (Ret->getNumOperands() == 0) {
1732 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1733 TII.get(WebAssembly::RETURN));
1738 if (Ret->getNumOperands() > 1)
1741 Value *RV = Ret->getOperand(0);
1745 switch (getSimpleType(RV->
getType())) {
1760 case MVT::externref:
1768 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1769 Reg = getRegForSignedValue(RV);
1770 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1771 Reg = getRegForUnsignedValue(RV);
1773 Reg = getRegForValue(RV);
1778 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1783bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1784 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1785 TII.get(WebAssembly::UNREACHABLE));
1789bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1790 switch (
I->getOpcode()) {
1791 case Instruction::Call:
1795 case Instruction::Select:
1796 return selectSelect(
I);
1797 case Instruction::Trunc:
1798 return selectTrunc(
I);
1799 case Instruction::ZExt:
1800 return selectZExt(
I);
1801 case Instruction::SExt:
1802 return selectSExt(
I);
1803 case Instruction::ICmp:
1804 return selectICmp(
I);
1805 case Instruction::FCmp:
1806 return selectFCmp(
I);
1807 case Instruction::BitCast:
1808 return selectBitCast(
I);
1809 case Instruction::Load:
1810 return selectLoad(
I);
1811 case Instruction::Store:
1812 return selectStore(
I);
1813 case Instruction::CondBr:
1814 return selectCondBr(
I);
1815 case Instruction::Ret:
1816 return selectRet(
I);
1817 case Instruction::Unreachable:
1818 return selectUnreachable(
I);
1824 return selectOperator(
I,
I->getOpcode());
1831 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.