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;
1312bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1313 const LoadInst *LI) {
1317 WebAssembly::INSTRUCTION_LIST_END)
1320 Register ResultReg =
MI->getOperand(0).getReg();
1321 if (!
emitLoad(ResultReg, NewOpc, LI))
1325 removeDeadCode(Iter, std::next(Iter));
1329bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1331 if (
Load->isAtomic())
1341 const TargetRegisterClass *RC;
1343 switch (getSimpleType(
Load->getType())) {
1346 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1347 RC = &WebAssembly::I32RegClass;
1350 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1351 RC = &WebAssembly::I32RegClass;
1354 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1355 RC = &WebAssembly::I32RegClass;
1358 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1359 RC = &WebAssembly::I64RegClass;
1362 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1363 RC = &WebAssembly::F32RegClass;
1366 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1367 RC = &WebAssembly::F64RegClass;
1373 Register ResultReg = createResultReg(RC);
1377 updateValueMap(Load, ResultReg);
1381bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1383 if (
Store->isAtomic())
1388 Store->getValueOperand()->getType()->isVectorTy())
1392 if (!computeAddress(
Store->getPointerOperand(), Addr))
1396 bool VTIsi1 =
false;
1398 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1403 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1406 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1409 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1412 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1415 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1418 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1424 materializeLoadStoreOperands(Addr);
1426 Register ValueReg = getRegForValue(
Store->getValueOperand());
1430 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1432 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1434 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1440bool WebAssemblyFastISel::selectBr(
const Instruction *
I) {
1442 if (Br->isUnconditional()) {
1443 MachineBasicBlock *MSucc = FuncInfo.getMBB(Br->getSuccessor(0));
1444 fastEmitBranch(MSucc, Br->getDebugLoc());
1448 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1449 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1452 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1456 unsigned Opc = WebAssembly::BR_IF;
1458 Opc = WebAssembly::BR_UNLESS;
1460 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1464 finishCondBranch(Br->getParent(),
TBB, FBB);
1468bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1469 if (!FuncInfo.CanLowerReturn)
1474 if (Ret->getNumOperands() == 0) {
1475 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1476 TII.get(WebAssembly::RETURN));
1481 if (Ret->getNumOperands() > 1)
1484 Value *RV = Ret->getOperand(0);
1488 switch (getSimpleType(RV->
getType())) {
1503 case MVT::externref:
1511 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1512 Reg = getRegForSignedValue(RV);
1513 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1514 Reg = getRegForUnsignedValue(RV);
1516 Reg = getRegForValue(RV);
1521 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1526bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1527 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1528 TII.get(WebAssembly::UNREACHABLE));
1532bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1533 switch (
I->getOpcode()) {
1534 case Instruction::Call:
1538 case Instruction::Select:
1539 return selectSelect(
I);
1540 case Instruction::Trunc:
1541 return selectTrunc(
I);
1542 case Instruction::ZExt:
1543 return selectZExt(
I);
1544 case Instruction::SExt:
1545 return selectSExt(
I);
1546 case Instruction::ICmp:
1547 return selectICmp(
I);
1548 case Instruction::FCmp:
1549 return selectFCmp(
I);
1550 case Instruction::BitCast:
1551 return selectBitCast(
I);
1552 case Instruction::Load:
1553 return selectLoad(
I);
1554 case Instruction::Store:
1555 return selectStore(
I);
1556 case Instruction::Br:
1558 case Instruction::Ret:
1559 return selectRet(
I);
1560 case Instruction::Unreachable:
1561 return selectUnreachable(
I);
1567 return selectOperator(
I,
I->getOpcode());
1574 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
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 getSExtLoadOpcode(unsigned Opc, 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.
A description of a memory reference used in the backend.
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.
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 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)
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.