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);
1290 return WebAssembly::INSTRUCTION_LIST_END;
1291 case WebAssembly::I32_EXTEND8_S_I32:
1292 Opc = A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1294 case WebAssembly::I32_EXTEND16_S_I32:
1295 Opc = A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1297 case WebAssembly::I64_EXTEND8_S_I64:
1298 Opc = A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1300 case WebAssembly::I64_EXTEND16_S_I64:
1301 Opc = A64 ? WebAssembly::LOAD16_S_I64_A64 : WebAssembly::LOAD16_S_I64_A32;
1303 case WebAssembly::I64_EXTEND32_S_I64:
1304 case WebAssembly::I64_EXTEND_S_I32:
1305 Opc = A64 ? WebAssembly::LOAD32_S_I64_A64 : WebAssembly::LOAD32_S_I64_A32;
1316 bool IsConstant =
false;
1317 for (
unsigned I = 1;
I <= 2; ++
I) {
1320 if (
DefMI && (
DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1321 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1322 Mask =
DefMI->getOperand(1).getImm();
1329 return WebAssembly::INSTRUCTION_LIST_END;
1333 return WebAssembly::INSTRUCTION_LIST_END;
1335 if (
MI->getOpcode() == WebAssembly::AND_I32) {
1337 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1339 return A64 ? WebAssembly::LOAD16_U_I32_A64
1340 : WebAssembly::LOAD16_U_I32_A32;
1341 }
else if (
MI->getOpcode() == WebAssembly::AND_I64) {
1343 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1345 return A64 ? WebAssembly::LOAD16_U_I64_A64
1346 : WebAssembly::LOAD16_U_I64_A32;
1348 return A64 ? WebAssembly::LOAD32_U_I64_A64
1349 : WebAssembly::LOAD32_U_I64_A32;
1352 return WebAssembly::INSTRUCTION_LIST_END;
1357 switch (
MI->getOpcode()) {
1358 case WebAssembly::I32_EXTEND8_S_I32:
1359 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:
1365 case WebAssembly::AND_I32:
1366 case WebAssembly::AND_I64:
1369 return WebAssembly::INSTRUCTION_LIST_END;
1383 unsigned Opc =
MI->getOpcode();
1384 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1385 if (
Opc != WebAssembly::SHL_I32)
1388 Register DestReg =
MI->getOperand(0).getReg();
1394 if (UserOpc != WebAssembly::SHR_S_I32)
1402 Register ShlAmtReg =
MI->getOperand(2).getReg();
1407 return MI &&
MI->getOpcode() == WebAssembly::CONST_I32 &&
1408 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1410 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1414 NewOpc = A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1417 A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1422bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1423 const LoadInst *LI) {
1425 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1427 MachineInstr *UserMI =
nullptr;
1430 WebAssembly::INSTRUCTION_LIST_END) {
1431 ResultReg =
MI->getOperand(0).getReg();
1433 WebAssembly::INSTRUCTION_LIST_END) {
1439 if (!
emitLoad(ResultReg, NewOpc, LI))
1444 removeDeadCode(UserIter, std::next(UserIter));
1448 removeDeadCode(Iter, std::next(Iter));
1452bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1454 if (
Load->isAtomic())
1464 const TargetRegisterClass *RC;
1466 switch (getSimpleType(
Load->getType())) {
1469 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1470 RC = &WebAssembly::I32RegClass;
1473 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1474 RC = &WebAssembly::I32RegClass;
1477 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1478 RC = &WebAssembly::I32RegClass;
1481 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1482 RC = &WebAssembly::I64RegClass;
1485 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1486 RC = &WebAssembly::F32RegClass;
1489 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1490 RC = &WebAssembly::F64RegClass;
1496 Register ResultReg = createResultReg(RC);
1500 updateValueMap(Load, ResultReg);
1504bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1506 if (
Store->isAtomic())
1511 Store->getValueOperand()->getType()->isVectorTy())
1515 if (!computeAddress(
Store->getPointerOperand(), Addr))
1519 bool VTIsi1 =
false;
1521 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1526 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1529 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1532 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1535 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1538 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1541 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1547 materializeLoadStoreOperands(Addr);
1549 Register ValueReg = getRegForValue(
Store->getValueOperand());
1553 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1555 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1557 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1563bool WebAssemblyFastISel::selectCondBr(
const Instruction *
I) {
1566 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1567 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1570 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1574 unsigned Opc = WebAssembly::BR_IF;
1576 Opc = WebAssembly::BR_UNLESS;
1578 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1582 finishCondBranch(Br->getParent(),
TBB, FBB);
1586bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1587 if (!FuncInfo.CanLowerReturn)
1592 if (Ret->getNumOperands() == 0) {
1593 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1594 TII.get(WebAssembly::RETURN));
1599 if (Ret->getNumOperands() > 1)
1602 Value *RV = Ret->getOperand(0);
1606 switch (getSimpleType(RV->
getType())) {
1621 case MVT::externref:
1629 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1630 Reg = getRegForSignedValue(RV);
1631 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1632 Reg = getRegForUnsignedValue(RV);
1634 Reg = getRegForValue(RV);
1639 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1644bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1645 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1646 TII.get(WebAssembly::UNREACHABLE));
1650bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1651 switch (
I->getOpcode()) {
1652 case Instruction::Call:
1656 case Instruction::Select:
1657 return selectSelect(
I);
1658 case Instruction::Trunc:
1659 return selectTrunc(
I);
1660 case Instruction::ZExt:
1661 return selectZExt(
I);
1662 case Instruction::SExt:
1663 return selectSExt(
I);
1664 case Instruction::ICmp:
1665 return selectICmp(
I);
1666 case Instruction::FCmp:
1667 return selectFCmp(
I);
1668 case Instruction::BitCast:
1669 return selectBitCast(
I);
1670 case Instruction::Load:
1671 return selectLoad(
I);
1672 case Instruction::Store:
1673 return selectStore(
I);
1674 case Instruction::CondBr:
1675 return selectCondBr(
I);
1676 case Instruction::Ret:
1677 return selectRet(
I);
1678 case Instruction::Unreachable:
1679 return selectUnreachable(
I);
1685 return selectOperator(
I,
I->getOpcode());
1692 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 unsigned getZExtLoadOpcodeFromAnd(MachineInstr *MI, MachineRegisterInfo &MRI, const LoadInst *LI, bool A64)
static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI)
Matches a sign-extension pattern (shl + shr_s) to fold it into a signed load.
static unsigned getSExtLoadOpcode(unsigned Opc, bool A64)
static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI, const LoadInst *LI, bool A64)
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
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.