45using namespace PatternMatch;
47#define DEBUG_TYPE "wasm-fastisel"
51class WebAssemblyFastISel final :
public FastISel {
55 using BaseKind =
enum { RegBase, FrameIndexBase };
58 BaseKind Kind = RegBase;
65 bool IsBaseSet =
false;
73 Address() {
Base.Reg = 0; }
74 void setKind(BaseKind K) {
75 assert(!isSet() &&
"Can't change kind with non-zero base");
78 BaseKind getKind()
const {
return Kind; }
79 bool isRegBase()
const {
return Kind == RegBase; }
80 bool isFIBase()
const {
return Kind == FrameIndexBase; }
81 void setReg(
unsigned Reg) {
82 assert(isRegBase() &&
"Invalid base register access!");
83 assert(!IsBaseSet &&
"Base cannot be reset");
88 assert(isRegBase() &&
"Invalid base register access!");
91 void setFI(
unsigned FI) {
92 assert(isFIBase() &&
"Invalid base frame index access!");
93 assert(!IsBaseSet &&
"Base cannot be reset");
97 unsigned getFI()
const {
98 assert(isFIBase() &&
"Invalid base frame index access!");
102 void setOffset(int64_t NewOffset) {
103 assert(NewOffset >= 0 &&
"Offsets must be non-negative");
106 int64_t
getOffset()
const {
return Offset; }
108 const GlobalValue *getGlobalValue()
const {
return GV; }
109 bool isSet()
const {
return IsBaseSet; }
120 EVT VT = TLI.getValueType(
DL, Ty,
true);
156 bool computeAddress(
const Value *Obj, Address &
Addr);
157 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);
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.MBBMap[
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: {
340 if (isa<ConstantInt>(LHS))
343 if (
const auto *CI = dyn_cast<ConstantInt>(RHS)) {
344 uint64_t TmpOffset =
Addr.getOffset() + CI->getSExtValue();
345 if (int64_t(TmpOffset) >= 0) {
346 Addr.setOffset(TmpOffset);
347 return computeAddress(LHS,
Addr);
352 if (computeAddress(LHS,
Addr) && computeAddress(RHS,
Addr))
358 case Instruction::Sub: {
363 if (
const auto *CI = dyn_cast<ConstantInt>(RHS)) {
364 int64_t TmpOffset =
Addr.getOffset() - CI->getSExtValue();
365 if (TmpOffset >= 0) {
366 Addr.setOffset(TmpOffset);
367 return computeAddress(LHS,
Addr);
380 return Addr.getReg() != 0;
383void WebAssemblyFastISel::materializeLoadStoreOperands(Address &
Addr) {
384 if (
Addr.isRegBase()) {
387 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
388 : &WebAssembly::I32RegClass);
389 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
390 : WebAssembly::CONST_I32;
391 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), Reg)
398void WebAssemblyFastISel::addLoadStoreOperands(
const Address &
Addr,
410 if (
Addr.isRegBase())
418unsigned WebAssemblyFastISel::maskI1Value(
unsigned Reg,
const Value *V) {
419 return zeroExtendToI32(Reg, V, MVT::i1);
422unsigned WebAssemblyFastISel::getRegForI1Value(
const Value *V,
425 if (
const auto *ICmp = dyn_cast<ICmpInst>(V))
426 if (
const ConstantInt *
C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
427 if (ICmp->isEquality() &&
C->isZero() &&
C->getType()->isIntegerTy(32) &&
428 ICmp->getParent() == BB) {
429 Not = ICmp->isTrueWhenEqual();
430 return getRegForValue(ICmp->getOperand(0));
437 return maskI1Value(Reg, V);
440unsigned WebAssemblyFastISel::zeroExtendToI32(
unsigned Reg,
const Value *V,
450 if (V !=
nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
451 return copyValue(Reg);
457 return copyValue(Reg);
462 Register Imm = createResultReg(&WebAssembly::I32RegClass);
463 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
464 TII.get(WebAssembly::CONST_I32), Imm)
468 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
469 TII.get(WebAssembly::AND_I32), Result)
476unsigned WebAssemblyFastISel::signExtendToI32(
unsigned Reg,
const Value *V,
487 return copyValue(Reg);
492 Register Imm = createResultReg(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
494 TII.get(WebAssembly::CONST_I32), Imm)
497 Register Left = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
499 TII.get(WebAssembly::SHL_I32),
Left)
504 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
505 TII.get(WebAssembly::SHR_S_I32),
Right)
512unsigned WebAssemblyFastISel::zeroExtend(
unsigned Reg,
const Value *V,
515 if (To == MVT::i64) {
516 if (
From == MVT::i64)
517 return copyValue(Reg);
519 Reg = zeroExtendToI32(Reg, V,
From);
522 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
523 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
529 return zeroExtendToI32(Reg, V,
From);
534unsigned WebAssemblyFastISel::signExtend(
unsigned Reg,
const Value *V,
537 if (To == MVT::i64) {
538 if (
From == MVT::i64)
539 return copyValue(Reg);
541 Reg = signExtendToI32(Reg, V,
From);
544 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
545 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
551 return signExtendToI32(Reg, V,
From);
556unsigned WebAssemblyFastISel::getRegForUnsignedValue(
const Value *V) {
564 return zeroExtend(VReg, V,
From, To);
567unsigned WebAssemblyFastISel::getRegForSignedValue(
const Value *V) {
575 return signExtend(VReg, V,
From, To);
578unsigned WebAssemblyFastISel::getRegForPromotedValue(
const Value *V,
580 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(
V);
583unsigned WebAssemblyFastISel::notValue(
unsigned Reg) {
584 assert(
MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
586 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
587 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
588 TII.get(WebAssembly::EQZ_I32), NotReg)
593unsigned WebAssemblyFastISel::copyValue(
unsigned Reg) {
594 Register ResultReg = createResultReg(
MRI.getRegClass(Reg));
595 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::COPY),
601unsigned WebAssemblyFastISel::fastMaterializeAlloca(
const AllocaInst *AI) {
603 FuncInfo.StaticAllocaMap.find(AI);
605 if (SI != FuncInfo.StaticAllocaMap.end()) {
607 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
608 : &WebAssembly::I32RegClass);
610 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
611 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
619unsigned WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
621 if (TLI.isPositionIndependent())
623 if (GV->isThreadLocal())
626 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
627 : &WebAssembly::I32RegClass);
628 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
629 : WebAssembly::CONST_I32;
630 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
639bool WebAssemblyFastISel::fastLowerArguments() {
640 if (!FuncInfo.CanLowerReturn)
651 for (
auto const &Arg :
F->args()) {
653 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
654 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
655 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
656 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
657 Attrs.hasParamAttr(
I, Attribute::Nest))
660 Type *ArgTy = Arg.getType();
663 if (!Subtarget->hasSIMD128() && ArgTy->
isVectorTy())
668 switch (getSimpleType(ArgTy)) {
673 Opc = WebAssembly::ARGUMENT_i32;
674 RC = &WebAssembly::I32RegClass;
677 Opc = WebAssembly::ARGUMENT_i64;
678 RC = &WebAssembly::I64RegClass;
681 Opc = WebAssembly::ARGUMENT_f32;
682 RC = &WebAssembly::F32RegClass;
685 Opc = WebAssembly::ARGUMENT_f64;
686 RC = &WebAssembly::F64RegClass;
689 Opc = WebAssembly::ARGUMENT_v16i8;
690 RC = &WebAssembly::V128RegClass;
693 Opc = WebAssembly::ARGUMENT_v8i16;
694 RC = &WebAssembly::V128RegClass;
697 Opc = WebAssembly::ARGUMENT_v4i32;
698 RC = &WebAssembly::V128RegClass;
701 Opc = WebAssembly::ARGUMENT_v2i64;
702 RC = &WebAssembly::V128RegClass;
705 Opc = WebAssembly::ARGUMENT_v4f32;
706 RC = &WebAssembly::V128RegClass;
709 Opc = WebAssembly::ARGUMENT_v2f64;
710 RC = &WebAssembly::V128RegClass;
713 Opc = WebAssembly::ARGUMENT_funcref;
714 RC = &WebAssembly::FUNCREFRegClass;
717 Opc = WebAssembly::ARGUMENT_externref;
718 RC = &WebAssembly::EXTERNREFRegClass;
723 Register ResultReg = createResultReg(RC);
724 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
726 updateValueMap(&Arg, ResultReg);
731 MRI.addLiveIn(WebAssembly::ARGUMENTS);
734 for (
auto const &Arg :
F->args()) {
737 MFI->clearParamsAndResults();
740 MFI->addParam(ArgTy);
743 if (!
F->getReturnType()->isVoidTy()) {
745 getLegalType(getSimpleType(
F->getReturnType()));
747 MFI->clearParamsAndResults();
750 MFI->addResult(
RetTy);
756bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
757 const auto *
Call = cast<CallInst>(
I);
760 if (
Call->isMustTailCall() ||
Call->isInlineAsm() ||
761 Call->getFunctionType()->isVarArg())
765 if (Func &&
Func->isIntrinsic())
771 bool IsDirect =
Func !=
nullptr;
772 if (!IsDirect && isa<ConstantExpr>(
Call->getCalledOperand()))
776 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
777 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
780 if (!Subtarget->hasSIMD128() &&
Call->getType()->isVectorTy())
789 ResultReg = createResultReg(&WebAssembly::I32RegClass);
792 ResultReg = createResultReg(&WebAssembly::I64RegClass);
795 ResultReg = createResultReg(&WebAssembly::F32RegClass);
798 ResultReg = createResultReg(&WebAssembly::F64RegClass);
801 ResultReg = createResultReg(&WebAssembly::V128RegClass);
804 ResultReg = createResultReg(&WebAssembly::V128RegClass);
807 ResultReg = createResultReg(&WebAssembly::V128RegClass);
810 ResultReg = createResultReg(&WebAssembly::V128RegClass);
813 ResultReg = createResultReg(&WebAssembly::V128RegClass);
816 ResultReg = createResultReg(&WebAssembly::V128RegClass);
819 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
822 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
830 for (
unsigned I = 0, E =
Call->arg_size();
I < E; ++
I) {
837 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
838 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
839 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
840 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
841 Attrs.hasParamAttr(
I, Attribute::Nest))
846 if (
Call->paramHasAttr(
I, Attribute::SExt))
847 Reg = getRegForSignedValue(V);
848 else if (
Call->paramHasAttr(
I, Attribute::ZExt))
849 Reg = getRegForUnsignedValue(V);
851 Reg = getRegForValue(V);
859 unsigned CalleeReg = 0;
861 CalleeReg = getRegForValue(
Call->getCalledOperand());
866 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc));
878 MF->getMMI().getContext(), Subtarget);
879 if (Subtarget->hasReferenceTypes()) {
892 if (Subtarget->hasAddr64()) {
893 auto Wrap =
BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), MIMD,
894 TII.get(WebAssembly::I32_WRAP_I64));
895 Register Reg32 = createResultReg(&WebAssembly::I32RegClass);
897 Wrap.addReg(CalleeReg);
902 for (
unsigned ArgReg : Args)
909 updateValueMap(Call, ResultReg);
913bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
914 const auto *
Select = cast<SelectInst>(
I);
918 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
935 switch (getSimpleType(
Select->getType())) {
940 Opc = WebAssembly::SELECT_I32;
941 RC = &WebAssembly::I32RegClass;
944 Opc = WebAssembly::SELECT_I64;
945 RC = &WebAssembly::I64RegClass;
948 Opc = WebAssembly::SELECT_F32;
949 RC = &WebAssembly::F32RegClass;
952 Opc = WebAssembly::SELECT_F64;
953 RC = &WebAssembly::F64RegClass;
956 Opc = WebAssembly::SELECT_FUNCREF;
957 RC = &WebAssembly::FUNCREFRegClass;
960 Opc = WebAssembly::SELECT_EXTERNREF;
961 RC = &WebAssembly::EXTERNREFRegClass;
967 Register ResultReg = createResultReg(RC);
968 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
973 updateValueMap(
Select, ResultReg);
977bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
978 const auto *Trunc = cast<TruncInst>(
I);
980 Register Reg = getRegForValue(Trunc->getOperand(0));
984 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
986 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
987 TII.get(WebAssembly::I32_WRAP_I64), Result)
992 updateValueMap(Trunc, Reg);
996bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
997 const auto *ZExt = cast<ZExtInst>(
I);
999 const Value *
Op = ZExt->getOperand(0);
1005 unsigned Reg = zeroExtend(In,
Op,
From, To);
1009 updateValueMap(ZExt, Reg);
1013bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1014 const auto *SExt = cast<SExtInst>(
I);
1016 const Value *
Op = SExt->getOperand(0);
1022 unsigned Reg = signExtend(In,
Op,
From, To);
1026 updateValueMap(SExt, Reg);
1030bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1031 const auto *ICmp = cast<ICmpInst>(
I);
1033 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1035 bool IsSigned =
false;
1036 switch (ICmp->getPredicate()) {
1037 case ICmpInst::ICMP_EQ:
1038 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1040 case ICmpInst::ICMP_NE:
1041 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1043 case ICmpInst::ICMP_UGT:
1044 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1046 case ICmpInst::ICMP_UGE:
1047 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1049 case ICmpInst::ICMP_ULT:
1050 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1052 case ICmpInst::ICMP_ULE:
1053 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1055 case ICmpInst::ICMP_SGT:
1056 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1059 case ICmpInst::ICMP_SGE:
1060 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1063 case ICmpInst::ICMP_SLT:
1064 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1067 case ICmpInst::ICMP_SLE:
1068 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1075 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1079 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1083 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1084 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
1087 updateValueMap(ICmp, ResultReg);
1091bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1092 const auto *FCmp = cast<FCmpInst>(
I);
1094 Register LHS = getRegForValue(FCmp->getOperand(0));
1098 Register RHS = getRegForValue(FCmp->getOperand(1));
1102 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1105 switch (FCmp->getPredicate()) {
1106 case FCmpInst::FCMP_OEQ:
1107 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1109 case FCmpInst::FCMP_UNE:
1110 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1112 case FCmpInst::FCMP_OGT:
1113 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1115 case FCmpInst::FCMP_OGE:
1116 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1118 case FCmpInst::FCMP_OLT:
1119 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1121 case FCmpInst::FCMP_OLE:
1122 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1124 case FCmpInst::FCMP_UGT:
1125 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1128 case FCmpInst::FCMP_UGE:
1129 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1132 case FCmpInst::FCMP_ULT:
1133 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1136 case FCmpInst::FCMP_ULE:
1137 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1144 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1145 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc), ResultReg)
1150 ResultReg = notValue(ResultReg);
1152 updateValueMap(FCmp, ResultReg);
1156bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1160 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1161 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1171 updateValueMap(
I, In);
1181 assert(Iter->isBitcast());
1183 updateValueMap(
I, Reg);
1187bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1188 const auto *
Load = cast<LoadInst>(
I);
1189 if (
Load->isAtomic())
1193 if (!Subtarget->hasSIMD128() &&
Load->getType()->isVectorTy())
1197 if (!computeAddress(
Load->getPointerOperand(),
Addr))
1204 bool A64 = Subtarget->hasAddr64();
1205 switch (getSimpleType(
Load->getType())) {
1208 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1209 RC = &WebAssembly::I32RegClass;
1212 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1213 RC = &WebAssembly::I32RegClass;
1216 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1217 RC = &WebAssembly::I32RegClass;
1220 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1221 RC = &WebAssembly::I64RegClass;
1224 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1225 RC = &WebAssembly::F32RegClass;
1228 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1229 RC = &WebAssembly::F64RegClass;
1235 materializeLoadStoreOperands(
Addr);
1237 Register ResultReg = createResultReg(RC);
1238 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc),
1241 addLoadStoreOperands(
Addr, MIB, createMachineMemOperandFor(Load));
1243 updateValueMap(Load, ResultReg);
1247bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1248 const auto *
Store = cast<StoreInst>(
I);
1249 if (
Store->isAtomic())
1253 if (!Subtarget->hasSIMD128() &&
1254 Store->getValueOperand()->getType()->isVectorTy())
1258 if (!computeAddress(
Store->getPointerOperand(),
Addr))
1262 bool VTIsi1 =
false;
1263 bool A64 = Subtarget->hasAddr64();
1264 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1269 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1272 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1275 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1278 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1281 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1284 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1290 materializeLoadStoreOperands(
Addr);
1292 Register ValueReg = getRegForValue(
Store->getValueOperand());
1296 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1298 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc));
1300 addLoadStoreOperands(
Addr, MIB, createMachineMemOperandFor(Store));
1306bool WebAssemblyFastISel::selectBr(
const Instruction *
I) {
1307 const auto *Br = cast<BranchInst>(
I);
1308 if (Br->isUnconditional()) {
1310 fastEmitBranch(MSucc, Br->getDebugLoc());
1318 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1322 unsigned Opc = WebAssembly::BR_IF;
1324 Opc = WebAssembly::BR_UNLESS;
1326 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(Opc))
1330 finishCondBranch(Br->getParent(),
TBB, FBB);
1334bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1335 if (!FuncInfo.CanLowerReturn)
1338 const auto *
Ret = cast<ReturnInst>(
I);
1340 if (
Ret->getNumOperands() == 0) {
1341 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1342 TII.get(WebAssembly::RETURN));
1347 if (
Ret->getNumOperands() > 1)
1354 switch (getSimpleType(RV->
getType())) {
1369 case MVT::externref:
1376 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1377 Reg = getRegForSignedValue(RV);
1378 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1379 Reg = getRegForUnsignedValue(RV);
1381 Reg = getRegForValue(RV);
1386 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1387 TII.get(WebAssembly::RETURN))
1392bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1393 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1394 TII.get(WebAssembly::UNREACHABLE));
1398bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1399 switch (
I->getOpcode()) {
1400 case Instruction::Call:
1404 case Instruction::Select:
1405 return selectSelect(
I);
1406 case Instruction::Trunc:
1407 return selectTrunc(
I);
1408 case Instruction::ZExt:
1409 return selectZExt(
I);
1410 case Instruction::SExt:
1411 return selectSExt(
I);
1412 case Instruction::ICmp:
1413 return selectICmp(
I);
1414 case Instruction::FCmp:
1415 return selectFCmp(
I);
1416 case Instruction::BitCast:
1417 return selectBitCast(
I);
1418 case Instruction::Load:
1419 return selectLoad(
I);
1420 case Instruction::Store:
1421 return selectStore(
I);
1422 case Instruction::Br:
1424 case Instruction::Ret:
1425 return selectRet(
I);
1426 case Instruction::Unreachable:
1427 return selectUnreachable(
I);
1433 return selectOperator(
I,
I->getOpcode());
1438 return new WebAssemblyFastISel(FuncInfo, LibInfo);
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu AMDGPU Register Bank Select
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 declares the WebAssembly-specific subclass of TargetMachine.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
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
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.
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.