41using namespace PatternMatch;
43#define DEBUG_TYPE "wasm-fastisel"
47class WebAssemblyFastISel final :
public FastISel {
51 using BaseKind =
enum { RegBase, FrameIndexBase };
54 BaseKind Kind = RegBase;
61 bool IsBaseSet =
false;
70 void setKind(BaseKind K) {
71 assert(!isSet() &&
"Can't change kind with non-zero base");
74 BaseKind getKind()
const {
return Kind; }
75 bool isRegBase()
const {
return Kind == RegBase; }
76 bool isFIBase()
const {
return Kind == FrameIndexBase; }
77 void setReg(
unsigned Reg) {
78 assert(isRegBase() &&
"Invalid base register access!");
79 assert(!IsBaseSet &&
"Base cannot be reset");
84 assert(isRegBase() &&
"Invalid base register access!");
87 void setFI(
unsigned FI) {
88 assert(isFIBase() &&
"Invalid base frame index access!");
89 assert(!IsBaseSet &&
"Base cannot be reset");
93 unsigned getFI()
const {
94 assert(isFIBase() &&
"Invalid base frame index access!");
98 void setOffset(int64_t NewOffset) {
99 assert(NewOffset >= 0 &&
"Offsets must be non-negative");
102 int64_t
getOffset()
const {
return Offset; }
104 const GlobalValue *getGlobalValue()
const {
return GV; }
105 bool isSet()
const {
return IsBaseSet; }
116 EVT VT = TLI.getValueType(
DL, Ty,
true);
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);
200 :
FastISel(FuncInfo, LibInfo,
true) {
207#include "WebAssemblyGenFastISel.inc"
212bool WebAssemblyFastISel::computeAddress(
const Value *Obj, Address &
Addr) {
213 const User *
U =
nullptr;
214 unsigned Opcode = Instruction::UserOp1;
215 if (
const auto *
I = dyn_cast<Instruction>(Obj)) {
218 if (FuncInfo.StaticAllocaMap.count(
static_cast<const AllocaInst *
>(Obj)) ||
219 FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
220 Opcode =
I->getOpcode();
223 }
else if (
const auto *
C = dyn_cast<ConstantExpr>(Obj)) {
224 Opcode =
C->getOpcode();
228 if (
auto *Ty = dyn_cast<PointerType>(Obj->
getType()))
229 if (Ty->getAddressSpace() > 255)
234 if (
const auto *GV = dyn_cast<GlobalValue>(Obj)) {
235 if (TLI.isPositionIndependent())
237 if (
Addr.getGlobalValue())
239 if (GV->isThreadLocal())
241 Addr.setGlobalValue(GV);
248 case Instruction::BitCast: {
250 return computeAddress(
U->getOperand(0),
Addr);
252 case Instruction::IntToPtr: {
254 if (TLI.getValueType(
DL,
U->getOperand(0)->getType()) ==
255 TLI.getPointerTy(
DL))
256 return computeAddress(
U->getOperand(0),
Addr);
259 case Instruction::PtrToInt: {
261 if (TLI.getValueType(
DL,
U->getType()) == TLI.getPointerTy(
DL))
262 return computeAddress(
U->getOperand(0),
Addr);
265 case Instruction::GetElementPtr: {
269 if (!cast<GEPOperator>(U)->isInBounds())
270 goto unsupported_gep;
275 const Value *
Op = GTI.getOperand();
276 if (
StructType *STy = GTI.getStructTypeOrNull()) {
278 unsigned Idx = cast<ConstantInt>(
Op)->getZExtValue();
281 uint64_t S = GTI.getSequentialElementStride(
DL);
283 if (
const auto *CI = dyn_cast<ConstantInt>(
Op)) {
285 TmpOffset += CI->getSExtValue() * S;
288 if (S == 1 &&
Addr.isRegBase() &&
Addr.getReg() == 0) {
296 if (canFoldAddIntoGEP(U,
Op)) {
298 auto *CI = cast<ConstantInt>(cast<AddOperator>(
Op)->getOperand(1));
299 TmpOffset += CI->getSExtValue() * S;
301 Op = cast<AddOperator>(
Op)->getOperand(0);
305 goto unsupported_gep;
310 if (int64_t(TmpOffset) >= 0) {
312 Addr.setOffset(TmpOffset);
313 if (computeAddress(
U->getOperand(0),
Addr))
321 case Instruction::Alloca: {
322 const auto *AI = cast<AllocaInst>(Obj);
324 FuncInfo.StaticAllocaMap.find(AI);
325 if (SI != FuncInfo.StaticAllocaMap.end()) {
329 Addr.setKind(Address::FrameIndexBase);
335 case Instruction::Add: {
338 if (
auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
339 if (!OFBinOp->hasNoUnsignedWrap())
346 if (isa<ConstantInt>(LHS))
349 if (
const auto *CI = dyn_cast<ConstantInt>(RHS)) {
350 uint64_t TmpOffset =
Addr.getOffset() + CI->getSExtValue();
351 if (int64_t(TmpOffset) >= 0) {
352 Addr.setOffset(TmpOffset);
353 return computeAddress(LHS,
Addr);
358 if (computeAddress(LHS,
Addr) && computeAddress(RHS,
Addr))
364 case Instruction::Sub: {
367 if (
auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
368 if (!OFBinOp->hasNoUnsignedWrap())
375 if (
const auto *CI = dyn_cast<ConstantInt>(RHS)) {
376 int64_t TmpOffset =
Addr.getOffset() - CI->getSExtValue();
377 if (TmpOffset >= 0) {
378 Addr.setOffset(TmpOffset);
379 return computeAddress(LHS,
Addr);
392 return Addr.getReg() != 0;
395void WebAssemblyFastISel::materializeLoadStoreOperands(Address &
Addr) {
396 if (
Addr.isRegBase()) {
399 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
400 : &WebAssembly::I32RegClass);
401 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
402 : WebAssembly::CONST_I32;
403 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), Reg)
410void WebAssemblyFastISel::addLoadStoreOperands(
const Address &
Addr,
422 if (
Addr.isRegBase())
430unsigned WebAssemblyFastISel::maskI1Value(
unsigned Reg,
const Value *V) {
431 return zeroExtendToI32(Reg, V, MVT::i1);
434unsigned WebAssemblyFastISel::getRegForI1Value(
const Value *V,
437 if (
const auto *ICmp = dyn_cast<ICmpInst>(V))
438 if (
const ConstantInt *
C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
439 if (ICmp->isEquality() &&
C->isZero() &&
C->getType()->isIntegerTy(32) &&
440 ICmp->getParent() == BB) {
441 Not = ICmp->isTrueWhenEqual();
442 return getRegForValue(ICmp->getOperand(0));
449 return maskI1Value(Reg, V);
452unsigned WebAssemblyFastISel::zeroExtendToI32(
unsigned Reg,
const Value *V,
462 if (V !=
nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
463 return copyValue(Reg);
469 return copyValue(Reg);
474 Register Imm = createResultReg(&WebAssembly::I32RegClass);
475 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
476 TII.get(WebAssembly::CONST_I32), Imm)
480 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
481 TII.get(WebAssembly::AND_I32), Result)
488unsigned WebAssemblyFastISel::signExtendToI32(
unsigned Reg,
const Value *V,
499 return copyValue(Reg);
504 Register Imm = createResultReg(&WebAssembly::I32RegClass);
505 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
506 TII.get(WebAssembly::CONST_I32), Imm)
509 Register Left = createResultReg(&WebAssembly::I32RegClass);
510 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
511 TII.get(WebAssembly::SHL_I32),
Left)
516 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
517 TII.get(WebAssembly::SHR_S_I32),
Right)
524unsigned WebAssemblyFastISel::zeroExtend(
unsigned Reg,
const Value *V,
527 if (To == MVT::i64) {
528 if (
From == MVT::i64)
529 return copyValue(Reg);
531 Reg = zeroExtendToI32(Reg, V,
From);
534 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
535 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
541 return zeroExtendToI32(Reg, V,
From);
546unsigned WebAssemblyFastISel::signExtend(
unsigned Reg,
const Value *V,
549 if (To == MVT::i64) {
550 if (
From == MVT::i64)
551 return copyValue(Reg);
553 Reg = signExtendToI32(Reg, V,
From);
556 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
557 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
563 return signExtendToI32(Reg, V,
From);
568unsigned WebAssemblyFastISel::getRegForUnsignedValue(
const Value *V) {
576 return zeroExtend(VReg, V,
From, To);
579unsigned WebAssemblyFastISel::getRegForSignedValue(
const Value *V) {
587 return signExtend(VReg, V,
From, To);
590unsigned WebAssemblyFastISel::getRegForPromotedValue(
const Value *V,
592 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(
V);
595unsigned WebAssemblyFastISel::notValue(
unsigned Reg) {
596 assert(
MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
598 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
599 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
600 TII.get(WebAssembly::EQZ_I32), NotReg)
605unsigned WebAssemblyFastISel::copyValue(
unsigned Reg) {
606 Register ResultReg = createResultReg(
MRI.getRegClass(Reg));
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::COPY),
613unsigned WebAssemblyFastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
615 FuncInfo.StaticAllocaMap.find(AI);
617 if (SI != FuncInfo.StaticAllocaMap.end()) {
619 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
620 : &WebAssembly::I32RegClass);
622 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
623 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
631unsigned WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
633 if (TLI.isPositionIndependent())
635 if (GV->isThreadLocal())
638 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
639 : &WebAssembly::I32RegClass);
640 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
641 : WebAssembly::CONST_I32;
642 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
651bool WebAssemblyFastISel::fastLowerArguments() {
652 if (!FuncInfo.CanLowerReturn)
663 for (
auto const &Arg :
F->args()) {
665 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
666 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
667 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
668 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
669 Attrs.hasParamAttr(
I, Attribute::Nest))
672 Type *ArgTy = Arg.getType();
675 if (!Subtarget->hasSIMD128() && ArgTy->
isVectorTy())
680 switch (getSimpleType(ArgTy)) {
685 Opc = WebAssembly::ARGUMENT_i32;
686 RC = &WebAssembly::I32RegClass;
689 Opc = WebAssembly::ARGUMENT_i64;
690 RC = &WebAssembly::I64RegClass;
693 Opc = WebAssembly::ARGUMENT_f32;
694 RC = &WebAssembly::F32RegClass;
697 Opc = WebAssembly::ARGUMENT_f64;
698 RC = &WebAssembly::F64RegClass;
701 Opc = WebAssembly::ARGUMENT_v16i8;
702 RC = &WebAssembly::V128RegClass;
705 Opc = WebAssembly::ARGUMENT_v8i16;
706 RC = &WebAssembly::V128RegClass;
709 Opc = WebAssembly::ARGUMENT_v4i32;
710 RC = &WebAssembly::V128RegClass;
713 Opc = WebAssembly::ARGUMENT_v2i64;
714 RC = &WebAssembly::V128RegClass;
717 Opc = WebAssembly::ARGUMENT_v4f32;
718 RC = &WebAssembly::V128RegClass;
721 Opc = WebAssembly::ARGUMENT_v2f64;
722 RC = &WebAssembly::V128RegClass;
725 Opc = WebAssembly::ARGUMENT_funcref;
726 RC = &WebAssembly::FUNCREFRegClass;
729 Opc = WebAssembly::ARGUMENT_externref;
730 RC = &WebAssembly::EXTERNREFRegClass;
733 Opc = WebAssembly::ARGUMENT_exnref;
734 RC = &WebAssembly::EXNREFRegClass;
739 Register ResultReg = createResultReg(RC);
740 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
742 updateValueMap(&Arg, ResultReg);
747 MRI.addLiveIn(WebAssembly::ARGUMENTS);
750 for (
auto const &Arg :
F->args()) {
753 MFI->clearParamsAndResults();
756 MFI->addParam(ArgTy);
759 if (!
F->getReturnType()->isVoidTy()) {
761 getLegalType(getSimpleType(
F->getReturnType()));
763 MFI->clearParamsAndResults();
766 MFI->addResult(
RetTy);
772bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
773 const auto *
Call = cast<CallInst>(
I);
776 if (
Call->isMustTailCall() ||
Call->isInlineAsm() ||
777 Call->getFunctionType()->isVarArg())
781 if (Func &&
Func->isIntrinsic())
787 bool IsDirect =
Func !=
nullptr;
788 if (!IsDirect && isa<ConstantExpr>(
Call->getCalledOperand()))
792 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
793 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
796 if (!Subtarget->hasSIMD128() &&
Call->getType()->isVectorTy())
805 ResultReg = createResultReg(&WebAssembly::I32RegClass);
808 ResultReg = createResultReg(&WebAssembly::I64RegClass);
811 ResultReg = createResultReg(&WebAssembly::F32RegClass);
814 ResultReg = createResultReg(&WebAssembly::F64RegClass);
817 ResultReg = createResultReg(&WebAssembly::V128RegClass);
820 ResultReg = createResultReg(&WebAssembly::V128RegClass);
823 ResultReg = createResultReg(&WebAssembly::V128RegClass);
826 ResultReg = createResultReg(&WebAssembly::V128RegClass);
829 ResultReg = createResultReg(&WebAssembly::V128RegClass);
832 ResultReg = createResultReg(&WebAssembly::V128RegClass);
835 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
838 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
841 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
849 for (
unsigned I = 0, E =
Call->arg_size();
I < E; ++
I) {
856 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
857 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
858 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
859 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
860 Attrs.hasParamAttr(
I, Attribute::Nest))
865 if (
Call->paramHasAttr(
I, Attribute::SExt))
866 Reg = getRegForSignedValue(V);
867 else if (
Call->paramHasAttr(
I, Attribute::ZExt))
868 Reg = getRegForUnsignedValue(V);
870 Reg = getRegForValue(V);
878 unsigned CalleeReg = 0;
880 CalleeReg = getRegForValue(
Call->getCalledOperand());
885 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc));
897 MF->getContext(), Subtarget);
898 if (Subtarget->hasCallIndirectOverlong()) {
909 for (
unsigned ArgReg : Args)
916 updateValueMap(Call, ResultReg);
920bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
921 const auto *
Select = cast<SelectInst>(
I);
925 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
942 switch (getSimpleType(
Select->getType())) {
947 Opc = WebAssembly::SELECT_I32;
948 RC = &WebAssembly::I32RegClass;
951 Opc = WebAssembly::SELECT_I64;
952 RC = &WebAssembly::I64RegClass;
955 Opc = WebAssembly::SELECT_F32;
956 RC = &WebAssembly::F32RegClass;
959 Opc = WebAssembly::SELECT_F64;
960 RC = &WebAssembly::F64RegClass;
963 Opc = WebAssembly::SELECT_FUNCREF;
964 RC = &WebAssembly::FUNCREFRegClass;
967 Opc = WebAssembly::SELECT_EXTERNREF;
968 RC = &WebAssembly::EXTERNREFRegClass;
971 Opc = WebAssembly::SELECT_EXNREF;
972 RC = &WebAssembly::EXNREFRegClass;
978 Register ResultReg = createResultReg(RC);
979 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
984 updateValueMap(
Select, ResultReg);
988bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
989 const auto *Trunc = cast<TruncInst>(
I);
991 Register Reg = getRegForValue(Trunc->getOperand(0));
995 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
997 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
998 TII.get(WebAssembly::I32_WRAP_I64), Result)
1003 updateValueMap(Trunc, Reg);
1007bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
1008 const auto *ZExt = cast<ZExtInst>(
I);
1010 const Value *
Op = ZExt->getOperand(0);
1016 unsigned Reg = zeroExtend(In,
Op,
From, To);
1020 updateValueMap(ZExt, Reg);
1024bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1025 const auto *SExt = cast<SExtInst>(
I);
1027 const Value *
Op = SExt->getOperand(0);
1033 unsigned Reg = signExtend(In,
Op,
From, To);
1037 updateValueMap(SExt, Reg);
1041bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1042 const auto *ICmp = cast<ICmpInst>(
I);
1044 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1046 bool IsSigned =
false;
1047 switch (ICmp->getPredicate()) {
1048 case ICmpInst::ICMP_EQ:
1049 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1051 case ICmpInst::ICMP_NE:
1052 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1054 case ICmpInst::ICMP_UGT:
1055 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1057 case ICmpInst::ICMP_UGE:
1058 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1060 case ICmpInst::ICMP_ULT:
1061 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1063 case ICmpInst::ICMP_ULE:
1064 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1066 case ICmpInst::ICMP_SGT:
1067 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1070 case ICmpInst::ICMP_SGE:
1071 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1074 case ICmpInst::ICMP_SLT:
1075 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1078 case ICmpInst::ICMP_SLE:
1079 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1086 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1090 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1094 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1095 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
1098 updateValueMap(ICmp, ResultReg);
1102bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1103 const auto *FCmp = cast<FCmpInst>(
I);
1105 Register LHS = getRegForValue(FCmp->getOperand(0));
1109 Register RHS = getRegForValue(FCmp->getOperand(1));
1113 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1116 switch (FCmp->getPredicate()) {
1117 case FCmpInst::FCMP_OEQ:
1118 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1120 case FCmpInst::FCMP_UNE:
1121 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1123 case FCmpInst::FCMP_OGT:
1124 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1126 case FCmpInst::FCMP_OGE:
1127 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1129 case FCmpInst::FCMP_OLT:
1130 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1132 case FCmpInst::FCMP_OLE:
1133 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1135 case FCmpInst::FCMP_UGT:
1136 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1139 case FCmpInst::FCMP_UGE:
1140 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1143 case FCmpInst::FCMP_ULT:
1144 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1147 case FCmpInst::FCMP_ULE:
1148 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1155 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1156 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
1161 ResultReg = notValue(ResultReg);
1163 updateValueMap(FCmp, ResultReg);
1167bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1171 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1172 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1182 updateValueMap(
I, In);
1192 assert(Iter->isBitcast());
1194 updateValueMap(
I, Reg);
1198bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1199 const auto *
Load = cast<LoadInst>(
I);
1200 if (
Load->isAtomic())
1204 if (!Subtarget->hasSIMD128() &&
Load->getType()->isVectorTy())
1208 if (!computeAddress(
Load->getPointerOperand(),
Addr))
1215 bool A64 = Subtarget->hasAddr64();
1216 switch (getSimpleType(
Load->getType())) {
1219 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1220 RC = &WebAssembly::I32RegClass;
1223 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1224 RC = &WebAssembly::I32RegClass;
1227 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1228 RC = &WebAssembly::I32RegClass;
1231 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1232 RC = &WebAssembly::I64RegClass;
1235 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1236 RC = &WebAssembly::F32RegClass;
1239 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1240 RC = &WebAssembly::F64RegClass;
1246 materializeLoadStoreOperands(
Addr);
1248 Register ResultReg = createResultReg(RC);
1249 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc),
1252 addLoadStoreOperands(
Addr, MIB, createMachineMemOperandFor(Load));
1254 updateValueMap(Load, ResultReg);
1258bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1259 const auto *
Store = cast<StoreInst>(
I);
1260 if (
Store->isAtomic())
1264 if (!Subtarget->hasSIMD128() &&
1265 Store->getValueOperand()->getType()->isVectorTy())
1269 if (!computeAddress(
Store->getPointerOperand(),
Addr))
1273 bool VTIsi1 =
false;
1274 bool A64 = Subtarget->hasAddr64();
1275 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1280 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1283 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1286 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1289 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1292 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1295 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1301 materializeLoadStoreOperands(
Addr);
1303 Register ValueReg = getRegForValue(
Store->getValueOperand());
1307 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1309 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc));
1311 addLoadStoreOperands(
Addr, MIB, createMachineMemOperandFor(Store));
1317bool WebAssemblyFastISel::selectBr(
const Instruction *
I) {
1318 const auto *Br = cast<BranchInst>(
I);
1319 if (Br->isUnconditional()) {
1321 fastEmitBranch(MSucc, Br->getDebugLoc());
1329 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1333 unsigned Opc = WebAssembly::BR_IF;
1335 Opc = WebAssembly::BR_UNLESS;
1337 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc))
1341 finishCondBranch(Br->getParent(),
TBB, FBB);
1345bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1346 if (!FuncInfo.CanLowerReturn)
1349 const auto *
Ret = cast<ReturnInst>(
I);
1351 if (
Ret->getNumOperands() == 0) {
1352 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1353 TII.get(WebAssembly::RETURN));
1358 if (
Ret->getNumOperands() > 1)
1365 switch (getSimpleType(RV->
getType())) {
1380 case MVT::externref:
1388 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1389 Reg = getRegForSignedValue(RV);
1390 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1391 Reg = getRegForUnsignedValue(RV);
1393 Reg = getRegForValue(RV);
1398 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1399 TII.get(WebAssembly::RETURN))
1404bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1405 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1406 TII.get(WebAssembly::UNREACHABLE));
1410bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1411 switch (
I->getOpcode()) {
1412 case Instruction::Call:
1416 case Instruction::Select:
1417 return selectSelect(
I);
1418 case Instruction::Trunc:
1419 return selectTrunc(
I);
1420 case Instruction::ZExt:
1421 return selectZExt(
I);
1422 case Instruction::SExt:
1423 return selectSExt(
I);
1424 case Instruction::ICmp:
1425 return selectICmp(
I);
1426 case Instruction::FCmp:
1427 return selectFCmp(
I);
1428 case Instruction::BitCast:
1429 return selectBitCast(
I);
1430 case Instruction::Load:
1431 return selectLoad(
I);
1432 case Instruction::Store:
1433 return selectStore(
I);
1434 case Instruction::Br:
1436 case Instruction::Ret:
1437 return selectRet(
I);
1438 case Instruction::Unreachable:
1439 return selectUnreachable(
I);
1445 return selectOperator(
I,
I->getOpcode());
1450 return new WebAssemblyFastISel(FuncInfo, LibInfo);
unsigned const MachineRegisterInfo * MRI
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
BlockVerifier::State From
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
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 ...
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
This is the shared class of boolean and integer constants.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
virtual unsigned fastMaterializeConstant(const Constant *C)
Emit a constant in a register using target-specific logic, such as constant pool loads.
virtual bool fastLowerArguments()
This method is called by target-independent code to do target- specific argument lowering.
bool selectCall(const User *I)
virtual bool fastSelectInstruction(const Instruction *I)=0
This method is called by target-independent code when the normal FastISel process fails to select an ...
bool selectBitCast(const User *I)
virtual unsigned fastMaterializeAlloca(const AllocaInst *C)
Emit an alloca address in a register using target-specific logic.
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.
@ INVALID_SIMPLE_VALUE_TYPE
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
A description of a memory reference used in the backend.
Wrapper class representing virtual and physical registers.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
TypeSize getElementOffset(unsigned Idx) const
Class to represent struct types.
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.
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.
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
bool hasReferenceTypes() const
bool hasExceptionHandling() const
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ Swift
Calling convention for Swift.
@ C
The default llvm calling convention, compatible with C.
@ Define
Register definition.
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)
Reg
All possible values of the reg field in the ModR/M byte.
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
gep_type_iterator gep_type_end(const User *GEP)
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
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.