38#include "llvm/IR/IntrinsicsWebAssembly.h"
43#define DEBUG_TYPE "wasm-fastisel"
47class WebAssemblyFastISel final :
public FastISel {
51 enum BaseKind { 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");
104 const GlobalValue *getGlobalValue()
const {
return GV; }
105 bool isSet()
const {
return IsBaseSet; }
116 EVT VT = TLI.getValueType(
DL, Ty,
true);
156 bool computeAddress(
const Value *Obj, Address &Addr);
157 void materializeLoadStoreOperands(Address &Addr);
161 unsigned maskI1Value(
unsigned Reg,
const Value *V);
162 unsigned getRegForI1Value(
const Value *V,
const BasicBlock *BB,
bool &Not);
163 unsigned zeroExtendToI32(
unsigned Reg,
const Value *V,
165 unsigned signExtendToI32(
unsigned Reg,
const Value *V,
171 unsigned getRegForUnsignedValue(
const Value *V);
172 unsigned getRegForSignedValue(
const Value *V);
173 unsigned getRegForPromotedValue(
const Value *V,
bool IsSigned);
174 unsigned notValue(
unsigned Reg);
175 unsigned copyValue(
unsigned Reg);
180 bool fastLowerArguments()
override;
202 :
FastISel(FuncInfo, LibInfo, LibcallLowering,
208 bool fastSelectInstruction(
const Instruction *
I)
override;
212#include "WebAssemblyGenFastISel.inc"
217bool WebAssemblyFastISel::computeAddress(
const Value *Obj, Address &Addr) {
218 const User *
U =
nullptr;
219 unsigned Opcode = Instruction::UserOp1;
223 if (FuncInfo.StaticAllocaMap.count(
static_cast<const AllocaInst *
>(Obj)) ||
224 FuncInfo.getMBB(
I->getParent()) == FuncInfo.MBB) {
225 Opcode =
I->getOpcode();
229 Opcode =
C->getOpcode();
234 if (Ty->getAddressSpace() > 255)
240 if (TLI.isPositionIndependent())
242 if (Addr.getGlobalValue())
244 if (GV->isThreadLocal())
246 Addr.setGlobalValue(GV);
253 case Instruction::BitCast: {
255 return computeAddress(
U->getOperand(0), Addr);
257 case Instruction::IntToPtr: {
259 if (TLI.getValueType(
DL,
U->getOperand(0)->getType()) ==
260 TLI.getPointerTy(
DL))
261 return computeAddress(
U->getOperand(0), Addr);
264 case Instruction::PtrToInt: {
266 if (TLI.getValueType(
DL,
U->getType()) == TLI.getPointerTy(
DL))
267 return computeAddress(
U->getOperand(0), Addr);
270 case Instruction::GetElementPtr: {
272 uint64_t TmpOffset = Addr.getOffset();
275 goto unsupported_gep;
280 const Value *
Op = GTI.getOperand();
281 if (StructType *STy = GTI.getStructTypeOrNull()) {
282 const StructLayout *SL =
DL.getStructLayout(STy);
286 uint64_t S = GTI.getSequentialElementStride(
DL);
290 TmpOffset += CI->getSExtValue() * S;
293 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
301 if (canFoldAddIntoGEP(U,
Op)) {
304 TmpOffset += CI->getSExtValue() * S;
310 goto unsupported_gep;
315 if (int64_t(TmpOffset) >= 0) {
317 Addr.setOffset(TmpOffset);
318 if (computeAddress(
U->getOperand(0), Addr))
326 case Instruction::Alloca: {
328 auto SI = 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 auto SI = FuncInfo.StaticAllocaMap.find(AI);
679 if (SI != FuncInfo.StaticAllocaMap.end()) {
681 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
682 : &WebAssembly::I32RegClass);
684 Subtarget->
hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
685 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
693Register WebAssemblyFastISel::fastMaterializeConstant(
const Constant *
C) {
695 if (TLI.isPositionIndependent())
697 if (GV->isThreadLocal())
700 createResultReg(Subtarget->
hasAddr64() ? &WebAssembly::I64RegClass
701 : &WebAssembly::I32RegClass);
702 unsigned Opc = Subtarget->
hasAddr64() ? WebAssembly::CONST_I64
703 : WebAssembly::CONST_I32;
704 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
713bool WebAssemblyFastISel::fastLowerArguments() {
714 if (!FuncInfo.CanLowerReturn)
721 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
725 for (
auto const &Arg :
F->args()) {
726 const AttributeList &
Attrs =
F->getAttributes();
727 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
728 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
729 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
730 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
731 Attrs.hasParamAttr(
I, Attribute::Nest))
734 Type *ArgTy = Arg.getType();
741 const TargetRegisterClass *RC;
742 switch (getSimpleType(ArgTy)) {
747 Opc = WebAssembly::ARGUMENT_i32;
748 RC = &WebAssembly::I32RegClass;
751 Opc = WebAssembly::ARGUMENT_i64;
752 RC = &WebAssembly::I64RegClass;
755 Opc = WebAssembly::ARGUMENT_f32;
756 RC = &WebAssembly::F32RegClass;
759 Opc = WebAssembly::ARGUMENT_f64;
760 RC = &WebAssembly::F64RegClass;
763 Opc = WebAssembly::ARGUMENT_v16i8;
764 RC = &WebAssembly::V128RegClass;
767 Opc = WebAssembly::ARGUMENT_v8i16;
768 RC = &WebAssembly::V128RegClass;
771 Opc = WebAssembly::ARGUMENT_v4i32;
772 RC = &WebAssembly::V128RegClass;
775 Opc = WebAssembly::ARGUMENT_v2i64;
776 RC = &WebAssembly::V128RegClass;
779 Opc = WebAssembly::ARGUMENT_v4f32;
780 RC = &WebAssembly::V128RegClass;
783 Opc = WebAssembly::ARGUMENT_v2f64;
784 RC = &WebAssembly::V128RegClass;
787 Opc = WebAssembly::ARGUMENT_funcref;
788 RC = &WebAssembly::FUNCREFRegClass;
791 Opc = WebAssembly::ARGUMENT_externref;
792 RC = &WebAssembly::EXTERNREFRegClass;
795 Opc = WebAssembly::ARGUMENT_exnref;
796 RC = &WebAssembly::EXNREFRegClass;
801 Register ResultReg = createResultReg(RC);
802 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
804 updateValueMap(&Arg, ResultReg);
809 MRI.addLiveIn(WebAssembly::ARGUMENTS);
811 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
812 for (
auto const &Arg :
F->args()) {
815 MFI->clearParamsAndResults();
818 MFI->addParam(ArgTy);
821 if (!
F->getReturnType()->isVoidTy()) {
823 getLegalType(getSimpleType(
F->getReturnType()));
825 MFI->clearParamsAndResults();
828 MFI->addResult(RetTy);
834bool WebAssemblyFastISel::selectCall(
const Instruction *
I) {
843 if (Func &&
Func->isIntrinsic())
849 bool IsDirect =
Func !=
nullptr;
854 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
855 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
867 ResultReg = createResultReg(&WebAssembly::I32RegClass);
870 ResultReg = createResultReg(&WebAssembly::I64RegClass);
873 ResultReg = createResultReg(&WebAssembly::F32RegClass);
876 ResultReg = createResultReg(&WebAssembly::F64RegClass);
879 ResultReg = createResultReg(&WebAssembly::V128RegClass);
882 ResultReg = createResultReg(&WebAssembly::V128RegClass);
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
894 ResultReg = createResultReg(&WebAssembly::V128RegClass);
897 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
900 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
903 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
910 SmallVector<unsigned, 8>
Args;
918 if (
Attrs.hasParamAttr(
I, Attribute::ByVal) ||
919 Attrs.hasParamAttr(
I, Attribute::SwiftSelf) ||
920 Attrs.hasParamAttr(
I, Attribute::SwiftError) ||
921 Attrs.hasParamAttr(
I, Attribute::InAlloca) ||
922 Attrs.hasParamAttr(
I, Attribute::Nest))
928 Reg = getRegForSignedValue(V);
930 Reg = getRegForUnsignedValue(V);
932 Reg = getRegForValue(V);
940 unsigned CalleeReg = 0;
947 const Value *FuncrefArg =
nullptr;
949 if (Conv->getIntrinsicID() == Intrinsic::wasm_funcref_to_ptr)
950 FuncrefArg = Conv->getArgOperand(0);
952 const bool IsFuncrefCall = FuncrefArg !=
nullptr;
953 MCSymbolWasm *Table =
nullptr;
956 if (!IsFuncrefCall) {
967 CalleeReg = getRegForValue(FuncrefArg);
969 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
970 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
971 TII.get(WebAssembly::CONST_I32), ZeroReg)
973 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
974 TII.get(WebAssembly::TABLE_SET_FUNCREF))
979 CalleeReg = createResultReg(&WebAssembly::I32RegClass);
980 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
981 TII.get(WebAssembly::CONST_I32), CalleeReg)
986 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
989 MIB.
addReg(ResultReg, RegState::Define);
1007 for (
unsigned ArgReg : Args)
1013 if (IsFuncrefCall) {
1015 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
1016 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1017 TII.get(WebAssembly::CONST_I32), ZeroReg)
1019 unsigned NullReg = createResultReg(&WebAssembly::FUNCREFRegClass);
1020 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1021 TII.get(WebAssembly::REF_NULL_FUNCREF), NullReg);
1022 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1023 TII.get(WebAssembly::TABLE_SET_FUNCREF))
1030 updateValueMap(
Call, ResultReg);
1036bool WebAssemblyFastISel::selectSelect(
const Instruction *
I) {
1041 getRegForI1Value(
Select->getCondition(),
I->getParent(), Not);
1057 const TargetRegisterClass *RC;
1058 switch (getSimpleType(
Select->getType())) {
1063 Opc = WebAssembly::SELECT_I32;
1064 RC = &WebAssembly::I32RegClass;
1067 Opc = WebAssembly::SELECT_I64;
1068 RC = &WebAssembly::I64RegClass;
1071 Opc = WebAssembly::SELECT_F32;
1072 RC = &WebAssembly::F32RegClass;
1075 Opc = WebAssembly::SELECT_F64;
1076 RC = &WebAssembly::F64RegClass;
1079 Opc = WebAssembly::SELECT_FUNCREF;
1080 RC = &WebAssembly::FUNCREFRegClass;
1082 case MVT::externref:
1083 Opc = WebAssembly::SELECT_EXTERNREF;
1084 RC = &WebAssembly::EXTERNREFRegClass;
1087 Opc = WebAssembly::SELECT_EXNREF;
1088 RC = &WebAssembly::EXNREFRegClass;
1094 Register ResultReg = createResultReg(RC);
1095 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1100 updateValueMap(
Select, ResultReg);
1104bool WebAssemblyFastISel::selectTrunc(
const Instruction *
I) {
1107 const Value *
Op = Trunc->getOperand(0);
1115 if (From == MVT::i64) {
1117 return copyValue(
Reg);
1119 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1121 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1122 TII.get(WebAssembly::I32_WRAP_I64), Result)
1128 if (From == MVT::i32)
1129 return copyValue(
Reg);
1134 unsigned Reg = Truncate(In);
1138 updateValueMap(Trunc,
Reg);
1142bool WebAssemblyFastISel::selectZExt(
const Instruction *
I) {
1145 const Value *
Op = ZExt->getOperand(0);
1151 unsigned Reg = zeroExtend(In,
Op, From, To);
1155 updateValueMap(ZExt,
Reg);
1159bool WebAssemblyFastISel::selectSExt(
const Instruction *
I) {
1162 const Value *
Op = SExt->getOperand(0);
1168 unsigned Reg = signExtend(In,
Op, From, To);
1172 updateValueMap(SExt,
Reg);
1176bool WebAssemblyFastISel::selectICmp(
const Instruction *
I) {
1179 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1181 bool IsSigned =
false;
1182 switch (ICmp->getPredicate()) {
1183 case ICmpInst::ICMP_EQ:
1184 Opc =
I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1186 case ICmpInst::ICMP_NE:
1187 Opc =
I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1189 case ICmpInst::ICMP_UGT:
1190 Opc =
I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1192 case ICmpInst::ICMP_UGE:
1193 Opc =
I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1195 case ICmpInst::ICMP_ULT:
1196 Opc =
I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1198 case ICmpInst::ICMP_ULE:
1199 Opc =
I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1201 case ICmpInst::ICMP_SGT:
1202 Opc =
I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1205 case ICmpInst::ICMP_SGE:
1206 Opc =
I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1209 case ICmpInst::ICMP_SLT:
1210 Opc =
I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1213 case ICmpInst::ICMP_SLE:
1214 Opc =
I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1221 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1225 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1229 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1230 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1233 updateValueMap(ICmp, ResultReg);
1237bool WebAssemblyFastISel::selectFCmp(
const Instruction *
I) {
1240 Register LHS = getRegForValue(FCmp->getOperand(0));
1244 Register RHS = getRegForValue(FCmp->getOperand(1));
1248 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1251 switch (FCmp->getPredicate()) {
1252 case FCmpInst::FCMP_OEQ:
1253 Opc =
F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1255 case FCmpInst::FCMP_UNE:
1256 Opc =
F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1258 case FCmpInst::FCMP_OGT:
1259 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1261 case FCmpInst::FCMP_OGE:
1262 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1264 case FCmpInst::FCMP_OLT:
1265 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1267 case FCmpInst::FCMP_OLE:
1268 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1270 case FCmpInst::FCMP_UGT:
1271 Opc =
F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1274 case FCmpInst::FCMP_UGE:
1275 Opc =
F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1278 case FCmpInst::FCMP_ULT:
1279 Opc =
F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1282 case FCmpInst::FCMP_ULE:
1283 Opc =
F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1290 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1291 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc), ResultReg)
1296 ResultReg = notValue(ResultReg);
1298 updateValueMap(FCmp, ResultReg);
1302bool WebAssemblyFastISel::selectBitCast(
const Instruction *
I) {
1306 EVT VT = TLI.getValueType(
DL,
I->getOperand(0)->getType());
1307 EVT RetVT = TLI.getValueType(
DL,
I->getType());
1317 updateValueMap(
I, In);
1327 assert(Iter->isBitcast());
1329 updateValueMap(
I,
Reg);
1337 return WebAssembly::INSTRUCTION_LIST_END;
1339 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1341 return A64 ? WebAssembly::LOAD16_S_I64_A64
1342 : WebAssembly::LOAD16_S_I64_A32;
1344 return A64 ? WebAssembly::LOAD32_S_I64_A64
1345 : WebAssembly::LOAD32_S_I64_A32;
1351 return WebAssembly::INSTRUCTION_LIST_END;
1353 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1355 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1363 return WebAssembly::INSTRUCTION_LIST_END;
1365 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1367 return A64 ? WebAssembly::LOAD16_U_I64_A64
1368 : WebAssembly::LOAD16_U_I64_A32;
1370 return A64 ? WebAssembly::LOAD32_U_I64_A64
1371 : WebAssembly::LOAD32_U_I64_A32;
1377 return WebAssembly::INSTRUCTION_LIST_END;
1379 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1381 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1389 case WebAssembly::I32_EXTEND8_S_I32:
1390 case WebAssembly::I32_EXTEND16_S_I32:
1391 case WebAssembly::I64_EXTEND8_S_I64:
1392 case WebAssembly::I64_EXTEND16_S_I64:
1393 case WebAssembly::I64_EXTEND32_S_I64:
1394 case WebAssembly::I64_EXTEND_S_I32:
1403 case WebAssembly::I32_EXTEND8_S_I32:
1404 case WebAssembly::I32_EXTEND16_S_I32:
1406 case WebAssembly::I64_EXTEND8_S_I64:
1407 case WebAssembly::I64_EXTEND16_S_I64:
1408 case WebAssembly::I64_EXTEND32_S_I64:
1409 case WebAssembly::I64_EXTEND_S_I32:
1416 unsigned Opc =
MI->getOpcode();
1423 return WebAssembly::INSTRUCTION_LIST_END;
1429 unsigned NarrowOpc) {
1436 case WebAssembly::I64_EXTEND_U_I32:
1437 OuterUserMI = UserMI;
1439 case WebAssembly::I64_EXTEND_S_I32:
1440 OuterUserMI = UserMI;
1458 unsigned Opc =
MI->getOpcode();
1459 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1460 if (
Opc != WebAssembly::SHL_I32)
1463 Register DestReg =
MI->getOperand(0).getReg();
1469 if (UserOpc != WebAssembly::SHR_S_I32)
1477 Register ShlAmtReg =
MI->getOperand(2).getReg();
1482 return MI &&
MI->getOpcode() == WebAssembly::CONST_I32 &&
1483 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1485 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1490 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1491 return WebAssembly::INSTRUCTION_LIST_END;
1494 OuterUserMI, NarrowOpc);
1502 if (
MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1503 return WebAssembly::INSTRUCTION_LIST_END;
1506 Register DestReg =
MI->getOperand(0).getReg();
1508 return WebAssembly::INSTRUCTION_LIST_END;
1513 return WebAssembly::INSTRUCTION_LIST_END;
1514 case WebAssembly::I64_EXTEND8_S_I64:
1516 return WebAssembly::INSTRUCTION_LIST_END;
1518 case WebAssembly::I64_EXTEND16_S_I64:
1520 return WebAssembly::INSTRUCTION_LIST_END;
1528 if (
MI->getOpcode() != WebAssembly::COPY)
1529 return WebAssembly::INSTRUCTION_LIST_END;
1533 return WebAssembly::INSTRUCTION_LIST_END;
1535 Register CopyDst =
MI->getOperand(0).getReg();
1537 return WebAssembly::INSTRUCTION_LIST_END;
1542 return WebAssembly::INSTRUCTION_LIST_END;
1543 case WebAssembly::I64_EXTEND_U_I32:
1545 case WebAssembly::I64_EXTEND_S_I32:
1553 if (
MI->getOpcode() != WebAssembly::AND_I32 &&
1554 MI->getOpcode() != WebAssembly::AND_I64)
1555 return WebAssembly::INSTRUCTION_LIST_END;
1558 bool IsConstant =
false;
1559 for (
unsigned I = 1;
I <= 2; ++
I) {
1562 if (
DefMI && (
DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1563 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1564 Mask =
DefMI->getOperand(1).getImm();
1571 return WebAssembly::INSTRUCTION_LIST_END;
1575 return WebAssembly::INSTRUCTION_LIST_END;
1577 if (
MI->getOpcode() == WebAssembly::AND_I64)
1581 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1582 return WebAssembly::INSTRUCTION_LIST_END;
1585 OuterUserMI, NarrowOpc);
1588bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *
MI,
unsigned OpNo,
1589 const LoadInst *LI) {
1591 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1593 MachineInstr *UserMI =
nullptr;
1594 MachineInstr *OuterUserMI =
nullptr;
1595 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1597 WebAssembly::INSTRUCTION_LIST_END) {
1599 }
else if ((NewOpc =
1601 WebAssembly::INSTRUCTION_LIST_END) {
1604 WebAssembly::INSTRUCTION_LIST_END) {
1606 :
MI->getOperand(0).getReg();
1608 WebAssembly::INSTRUCTION_LIST_END) {
1609 ResultReg =
MI->getOperand(0).getReg();
1610 }
else if ((NewOpc =
1612 WebAssembly::INSTRUCTION_LIST_END) {
1619 if (!
emitLoad(ResultReg, NewOpc, LI))
1624 removeDeadCode(OuterIter, std::next(OuterIter));
1629 removeDeadCode(UserIter, std::next(UserIter));
1633 removeDeadCode(Iter, std::next(Iter));
1637bool WebAssemblyFastISel::selectLoad(
const Instruction *
I) {
1639 if (
Load->isAtomic())
1649 const TargetRegisterClass *RC;
1651 switch (getSimpleType(
Load->getType())) {
1654 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1655 RC = &WebAssembly::I32RegClass;
1658 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1659 RC = &WebAssembly::I32RegClass;
1662 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1663 RC = &WebAssembly::I32RegClass;
1666 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1667 RC = &WebAssembly::I64RegClass;
1670 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1671 RC = &WebAssembly::F32RegClass;
1674 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1675 RC = &WebAssembly::F64RegClass;
1681 Register ResultReg = createResultReg(RC);
1685 updateValueMap(Load, ResultReg);
1689bool WebAssemblyFastISel::selectStore(
const Instruction *
I) {
1691 if (
Store->isAtomic())
1696 Store->getValueOperand()->getType()->isVectorTy())
1700 if (!computeAddress(
Store->getPointerOperand(), Addr))
1704 bool VTIsi1 =
false;
1706 switch (getSimpleType(
Store->getValueOperand()->getType())) {
1711 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1714 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1717 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1720 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1723 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1726 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1732 materializeLoadStoreOperands(Addr);
1734 Register ValueReg = getRegForValue(
Store->getValueOperand());
1738 ValueReg = maskI1Value(ValueReg,
Store->getValueOperand());
1740 auto MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc));
1742 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1748bool WebAssemblyFastISel::selectCondBr(
const Instruction *
I) {
1751 MachineBasicBlock *
TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1752 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1755 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1759 unsigned Opc = WebAssembly::BR_IF;
1761 Opc = WebAssembly::BR_UNLESS;
1763 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(
Opc))
1767 finishCondBranch(Br->getParent(),
TBB, FBB);
1771bool WebAssemblyFastISel::selectRet(
const Instruction *
I) {
1772 if (!FuncInfo.CanLowerReturn)
1777 if (Ret->getNumOperands() == 0) {
1778 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1779 TII.get(WebAssembly::RETURN));
1784 if (Ret->getNumOperands() > 1)
1787 Value *RV = Ret->getOperand(0);
1791 switch (getSimpleType(RV->
getType())) {
1806 case MVT::externref:
1814 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1815 Reg = getRegForSignedValue(RV);
1816 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1817 Reg = getRegForUnsignedValue(RV);
1819 Reg = getRegForValue(RV);
1824 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
TII.get(WebAssembly::RETURN))
1829bool WebAssemblyFastISel::selectUnreachable(
const Instruction *
I) {
1830 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1831 TII.get(WebAssembly::UNREACHABLE));
1835bool WebAssemblyFastISel::fastSelectInstruction(
const Instruction *
I) {
1836 switch (
I->getOpcode()) {
1837 case Instruction::Call:
1841 case Instruction::Select:
1842 return selectSelect(
I);
1843 case Instruction::Trunc:
1844 return selectTrunc(
I);
1845 case Instruction::ZExt:
1846 return selectZExt(
I);
1847 case Instruction::SExt:
1848 return selectSExt(
I);
1849 case Instruction::ICmp:
1850 return selectICmp(
I);
1851 case Instruction::FCmp:
1852 return selectFCmp(
I);
1853 case Instruction::BitCast:
1854 return selectBitCast(
I);
1855 case Instruction::Load:
1856 return selectLoad(
I);
1857 case Instruction::Store:
1858 return selectStore(
I);
1859 case Instruction::CondBr:
1860 return selectCondBr(
I);
1861 case Instruction::Ret:
1862 return selectRet(
I);
1863 case Instruction::Unreachable:
1864 return selectUnreachable(
I);
1870 return selectOperator(
I,
I->getOpcode());
1877 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
MachineInstrBuilder MachineInstrBuilder & DefMI
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the FastISel class.
const HexagonInstrInfo * TII
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
static bool isFoldableSExtOpcode(unsigned Opc)
static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static bool isI64SExtResult(unsigned Opc)
static unsigned matchFoldableCopyToI64Ext(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
static unsigned matchFoldableSExtFromPromotedI32(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI)
static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI, MachineInstr *&OuterUserMI)
Matches a sign-extension pattern (shl + shr_s) to fold it into a signed load.
static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI, unsigned NarrowOpc)
static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI, const LoadInst *LI, bool A64)
static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
an instruction to allocate memory on the stack
LLVM Basic Block Representation.
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
LLVM_ABI bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
bool isMustTailCall() const
This is an important base class in LLVM.
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
This is an important class for using LLVM in a threaded context.
Tracks which library functions to use for a particular subtarget.
An instruction for reading from memory.
@ INVALID_SIMPLE_VALUE_TYPE
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
Wrapper class representing virtual and physical registers.
TypeSize getElementOffset(unsigned Idx) const
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
bool isArrayTy() const
True if this is an instance of ArrayType.
bool isStructTy() const
True if this is an instance of StructType.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasCallIndirectOverlong() const
bool hasReferenceTypes() const
bool hasExceptionHandling() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
Not(const Pred &P) -> Not< Pred >
bool isDefaultAddressSpace(unsigned AS)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
MCSymbolWasm * getOrCreateFuncrefCallTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __funcref_call_table, for use in funcref calls when lowered to table.set + call_indirect.
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.