aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/GlobalISel/LegalizerHelper.cpp')
-rw-r--r--lib/CodeGen/GlobalISel/LegalizerHelper.cpp646
1 files changed, 374 insertions, 272 deletions
diff --git a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index a3b43c92a7fc..87086af121b7 100644
--- a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -26,6 +26,7 @@
#define DEBUG_TYPE "legalizer"
using namespace llvm;
+using namespace LegalizeActions;
LegalizerHelper::LegalizerHelper(MachineFunction &MF)
: MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()) {
@@ -34,34 +35,34 @@ LegalizerHelper::LegalizerHelper(MachineFunction &MF)
LegalizerHelper::LegalizeResult
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
- DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
+ LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
- auto Action = LI.getAction(MI, MRI);
- switch (std::get<0>(Action)) {
- case LegalizerInfo::Legal:
- DEBUG(dbgs() << ".. Already legal\n");
+ auto Step = LI.getAction(MI, MRI);
+ switch (Step.Action) {
+ case Legal:
+ LLVM_DEBUG(dbgs() << ".. Already legal\n");
return AlreadyLegal;
- case LegalizerInfo::Libcall:
- DEBUG(dbgs() << ".. Convert to libcall\n");
+ case Libcall:
+ LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
return libcall(MI);
- case LegalizerInfo::NarrowScalar:
- DEBUG(dbgs() << ".. Narrow scalar\n");
- return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action));
- case LegalizerInfo::WidenScalar:
- DEBUG(dbgs() << ".. Widen scalar\n");
- return widenScalar(MI, std::get<1>(Action), std::get<2>(Action));
- case LegalizerInfo::Lower:
- DEBUG(dbgs() << ".. Lower\n");
- return lower(MI, std::get<1>(Action), std::get<2>(Action));
- case LegalizerInfo::FewerElements:
- DEBUG(dbgs() << ".. Reduce number of elements\n");
- return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action));
- case LegalizerInfo::Custom:
- DEBUG(dbgs() << ".. Custom legalization\n");
+ case NarrowScalar:
+ LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
+ return narrowScalar(MI, Step.TypeIdx, Step.NewType);
+ case WidenScalar:
+ LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
+ return widenScalar(MI, Step.TypeIdx, Step.NewType);
+ case Lower:
+ LLVM_DEBUG(dbgs() << ".. Lower\n");
+ return lower(MI, Step.TypeIdx, Step.NewType);
+ case FewerElements:
+ LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
+ return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
+ case Custom:
+ LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized
: UnableToLegalize;
default:
- DEBUG(dbgs() << ".. Unable to legalize\n");
+ LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
return UnableToLegalize;
}
}
@@ -103,6 +104,9 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
return Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32;
case TargetOpcode::G_FPOW:
return Size == 64 ? RTLIB::POW_F64 : RTLIB::POW_F32;
+ case TargetOpcode::G_FMA:
+ assert((Size == 32 || Size == 64) && "Unsupported size");
+ return Size == 64 ? RTLIB::FMA_F64 : RTLIB::FMA_F32;
}
llvm_unreachable("Unknown libcall function");
}
@@ -123,13 +127,47 @@ llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
return LegalizerHelper::Legalized;
}
+// Useful for libcalls where all operands have the same type.
static LegalizerHelper::LegalizeResult
simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,
Type *OpType) {
auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
+
+ SmallVector<CallLowering::ArgInfo, 3> Args;
+ for (unsigned i = 1; i < MI.getNumOperands(); i++)
+ Args.push_back({MI.getOperand(i).getReg(), OpType});
return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), OpType},
- {{MI.getOperand(1).getReg(), OpType},
- {MI.getOperand(2).getReg(), OpType}});
+ Args);
+}
+
+static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
+ Type *FromType) {
+ auto ToMVT = MVT::getVT(ToType);
+ auto FromMVT = MVT::getVT(FromType);
+
+ switch (Opcode) {
+ case TargetOpcode::G_FPEXT:
+ return RTLIB::getFPEXT(FromMVT, ToMVT);
+ case TargetOpcode::G_FPTRUNC:
+ return RTLIB::getFPROUND(FromMVT, ToMVT);
+ case TargetOpcode::G_FPTOSI:
+ return RTLIB::getFPTOSINT(FromMVT, ToMVT);
+ case TargetOpcode::G_FPTOUI:
+ return RTLIB::getFPTOUINT(FromMVT, ToMVT);
+ case TargetOpcode::G_SITOFP:
+ return RTLIB::getSINTTOFP(FromMVT, ToMVT);
+ case TargetOpcode::G_UITOFP:
+ return RTLIB::getUINTTOFP(FromMVT, ToMVT);
+ }
+ llvm_unreachable("Unsupported libcall function");
+}
+
+static LegalizerHelper::LegalizeResult
+conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,
+ Type *FromType) {
+ RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
+ return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ToType},
+ {{MI.getOperand(1).getReg(), FromType}});
}
LegalizerHelper::LegalizeResult
@@ -157,6 +195,7 @@ LegalizerHelper::libcall(MachineInstr &MI) {
case TargetOpcode::G_FSUB:
case TargetOpcode::G_FMUL:
case TargetOpcode::G_FDIV:
+ case TargetOpcode::G_FMA:
case TargetOpcode::G_FPOW:
case TargetOpcode::G_FREM: {
Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx);
@@ -165,6 +204,59 @@ LegalizerHelper::libcall(MachineInstr &MI) {
return Status;
break;
}
+ case TargetOpcode::G_FPEXT: {
+ // FIXME: Support other floating point types (half, fp128 etc)
+ unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
+ unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (ToSize != 64 || FromSize != 32)
+ return UnableToLegalize;
+ LegalizeResult Status = conversionLibcall(
+ MI, MIRBuilder, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx));
+ if (Status != Legalized)
+ return Status;
+ break;
+ }
+ case TargetOpcode::G_FPTRUNC: {
+ // FIXME: Support other floating point types (half, fp128 etc)
+ unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
+ unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (ToSize != 32 || FromSize != 64)
+ return UnableToLegalize;
+ LegalizeResult Status = conversionLibcall(
+ MI, MIRBuilder, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx));
+ if (Status != Legalized)
+ return Status;
+ break;
+ }
+ case TargetOpcode::G_FPTOSI:
+ case TargetOpcode::G_FPTOUI: {
+ // FIXME: Support other types
+ unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
+ unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (ToSize != 32 || (FromSize != 32 && FromSize != 64))
+ return UnableToLegalize;
+ LegalizeResult Status = conversionLibcall(
+ MI, MIRBuilder, Type::getInt32Ty(Ctx),
+ FromSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx));
+ if (Status != Legalized)
+ return Status;
+ break;
+ }
+ case TargetOpcode::G_SITOFP:
+ case TargetOpcode::G_UITOFP: {
+ // FIXME: Support other types
+ unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
+ unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ if (FromSize != 32 || (ToSize != 32 && ToSize != 64))
+ return UnableToLegalize;
+ LegalizeResult Status = conversionLibcall(
+ MI, MIRBuilder,
+ ToSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx),
+ Type::getInt32Ty(Ctx));
+ if (Status != Legalized)
+ return Status;
+ break;
+ }
}
MI.eraseFromParent();
@@ -180,8 +272,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
MIRBuilder.setInstr(MI);
- int64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
- int64_t NarrowSize = NarrowTy.getSizeInBits();
+ uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
+ uint64_t NarrowSize = NarrowTy.getSizeInBits();
switch (MI.getOpcode()) {
default:
@@ -194,11 +286,9 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
int NumParts = SizeOp0 / NarrowSize;
SmallVector<unsigned, 2> DstRegs;
- for (int i = 0; i < NumParts; ++i) {
- unsigned Dst = MRI.createGenericVirtualRegister(NarrowTy);
- MIRBuilder.buildUndef(Dst);
- DstRegs.push_back(Dst);
- }
+ for (int i = 0; i < NumParts; ++i)
+ DstRegs.push_back(
+ MIRBuilder.buildUndef(NarrowTy)->getOperand(0).getReg());
MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
MI.eraseFromParent();
return Legalized;
@@ -249,8 +339,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
unsigned OpReg = MI.getOperand(0).getReg();
- int64_t OpStart = MI.getOperand(2).getImm();
- int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
+ uint64_t OpStart = MI.getOperand(2).getImm();
+ uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
for (int i = 0; i < NumParts; ++i) {
unsigned SrcStart = i * NarrowSize;
@@ -265,7 +355,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
// OpSegStart is where this destination segment would start in OpReg if it
// extended infinitely in both directions.
- int64_t ExtractOffset, SegSize;
+ int64_t ExtractOffset;
+ uint64_t SegSize;
if (OpStart < SrcStart) {
ExtractOffset = 0;
SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
@@ -301,8 +392,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
unsigned OpReg = MI.getOperand(2).getReg();
- int64_t OpStart = MI.getOperand(3).getImm();
- int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
+ uint64_t OpStart = MI.getOperand(3).getImm();
+ uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
for (int i = 0; i < NumParts; ++i) {
unsigned DstStart = i * NarrowSize;
@@ -319,7 +410,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
// OpSegStart is where this destination segment would start in OpReg if it
// extended infinitely in both directions.
- int64_t ExtractOffset, InsertOffset, SegSize;
+ int64_t ExtractOffset, InsertOffset;
+ uint64_t SegSize;
if (OpStart < DstStart) {
InsertOffset = 0;
ExtractOffset = DstStart - OpStart;
@@ -353,6 +445,14 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
// NarrowSize.
if (SizeOp0 % NarrowSize != 0)
return UnableToLegalize;
+
+ const auto &MMO = **MI.memoperands_begin();
+ // This implementation doesn't work for atomics. Give up instead of doing
+ // something invalid.
+ if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
+ MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
+ return UnableToLegalize;
+
int NumParts = SizeOp0 / NarrowSize;
LLT OffsetTy = LLT::scalar(
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
@@ -363,12 +463,16 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
unsigned SrcReg = 0;
unsigned Adjustment = i * NarrowSize / 8;
+ MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
+ MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
+ NarrowSize / 8, i == 0 ? MMO.getAlignment() : NarrowSize / 8,
+ MMO.getAAInfo(), MMO.getRanges(), MMO.getSyncScopeID(),
+ MMO.getOrdering(), MMO.getFailureOrdering());
+
MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy,
Adjustment);
- // TODO: This is conservatively correct, but we probably want to split the
- // memory operands in the future.
- MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin());
+ MIRBuilder.buildLoad(DstReg, SrcReg, *SplitMMO);
DstRegs.push_back(DstReg);
}
@@ -382,6 +486,14 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
// NarrowSize.
if (SizeOp0 % NarrowSize != 0)
return UnableToLegalize;
+
+ const auto &MMO = **MI.memoperands_begin();
+ // This implementation doesn't work for atomics. Give up instead of doing
+ // something invalid.
+ if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
+ MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
+ return UnableToLegalize;
+
int NumParts = SizeOp0 / NarrowSize;
LLT OffsetTy = LLT::scalar(
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
@@ -393,12 +505,16 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
unsigned DstReg = 0;
unsigned Adjustment = i * NarrowSize / 8;
+ MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
+ MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
+ NarrowSize / 8, i == 0 ? MMO.getAlignment() : NarrowSize / 8,
+ MMO.getAAInfo(), MMO.getRanges(), MMO.getSyncScopeID(),
+ MMO.getOrdering(), MMO.getFailureOrdering());
+
MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy,
Adjustment);
- // TODO: This is conservatively correct, but we probably want to split the
- // memory operands in the future.
- MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin());
+ MIRBuilder.buildStore(SrcRegs[i], DstReg, *SplitMMO);
}
MI.eraseFromParent();
return Legalized;
@@ -475,6 +591,22 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
}
}
+void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy,
+ unsigned OpIdx, unsigned ExtOpcode) {
+ MachineOperand &MO = MI.getOperand(OpIdx);
+ auto ExtB = MIRBuilder.buildInstr(ExtOpcode, WideTy, MO.getReg());
+ MO.setReg(ExtB->getOperand(0).getReg());
+}
+
+void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,
+ unsigned OpIdx, unsigned TruncOpcode) {
+ MachineOperand &MO = MI.getOperand(OpIdx);
+ unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
+ MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
+ MIRBuilder.buildInstr(TruncOpcode, MO.getReg(), DstExt);
+ MO.setReg(DstExt);
+}
+
LegalizerHelper::LegalizeResult
LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
MIRBuilder.setInstr(MI);
@@ -482,286 +614,201 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
switch (MI.getOpcode()) {
default:
return UnableToLegalize;
+
case TargetOpcode::G_ADD:
case TargetOpcode::G_AND:
case TargetOpcode::G_MUL:
case TargetOpcode::G_OR:
case TargetOpcode::G_XOR:
case TargetOpcode::G_SUB:
- case TargetOpcode::G_SHL: {
// Perform operation at larger width (any extension is fine here, high bits
// don't affect the result) and then truncate the result back to the
// original type.
- unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
- unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg());
- MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg());
-
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(MI.getOpcode())
- .addDef(DstExt)
- .addUse(Src1Ext)
- .addUse(Src2Ext);
-
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
+
+ case TargetOpcode::G_SHL:
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
+ // The "number of bits to shift" operand must preserve its value as an
+ // unsigned integer:
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
+ return Legalized;
+
case TargetOpcode::G_SDIV:
- case TargetOpcode::G_UDIV:
case TargetOpcode::G_SREM:
- case TargetOpcode::G_UREM:
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
+ return Legalized;
+
case TargetOpcode::G_ASHR:
- case TargetOpcode::G_LSHR: {
- unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV ||
- MI.getOpcode() == TargetOpcode::G_SREM ||
- MI.getOpcode() == TargetOpcode::G_ASHR
- ? TargetOpcode::G_SEXT
- : TargetOpcode::G_ZEXT;
-
- unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse(
- MI.getOperand(1).getReg());
-
- unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse(
- MI.getOperand(2).getReg());
-
- unsigned ResExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(MI.getOpcode())
- .addDef(ResExt)
- .addUse(LHSExt)
- .addUse(RHSExt);
-
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt);
- MI.eraseFromParent();
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
+ // The "number of bits to shift" operand must preserve its value as an
+ // unsigned integer:
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
- case TargetOpcode::G_SELECT: {
+
+ case TargetOpcode::G_UDIV:
+ case TargetOpcode::G_UREM:
+ case TargetOpcode::G_LSHR:
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
+ return Legalized;
+
+ case TargetOpcode::G_SELECT:
if (TypeIdx != 0)
return UnableToLegalize;
-
// Perform operation at larger width (any extension is fine here, high bits
// don't affect the result) and then truncate the result back to the
// original type.
- unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
- unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(2).getReg());
- MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(3).getReg());
-
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(TargetOpcode::G_SELECT)
- .addDef(DstExt)
- .addReg(MI.getOperand(1).getReg())
- .addUse(Src1Ext)
- .addUse(Src2Ext);
-
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
+ widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
+
case TargetOpcode::G_FPTOSI:
- case TargetOpcode::G_FPTOUI: {
+ case TargetOpcode::G_FPTOUI:
if (TypeIdx != 0)
return UnableToLegalize;
-
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(MI.getOpcode())
- .addDef(DstExt)
- .addUse(MI.getOperand(1).getReg());
-
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
+
case TargetOpcode::G_SITOFP:
- case TargetOpcode::G_UITOFP: {
if (TypeIdx != 1)
return UnableToLegalize;
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
+ MIRBuilder.recordInsertion(&MI);
+ return Legalized;
- unsigned Src = MI.getOperand(1).getReg();
- unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
-
- if (MI.getOpcode() == TargetOpcode::G_SITOFP) {
- MIRBuilder.buildSExt(SrcExt, Src);
- } else {
- assert(MI.getOpcode() == TargetOpcode::G_UITOFP && "Unexpected conv op");
- MIRBuilder.buildZExt(SrcExt, Src);
- }
-
- MIRBuilder.buildInstr(MI.getOpcode())
- .addDef(MI.getOperand(0).getReg())
- .addUse(SrcExt);
-
- MI.eraseFromParent();
+ case TargetOpcode::G_UITOFP:
+ if (TypeIdx != 1)
+ return UnableToLegalize;
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
- case TargetOpcode::G_INSERT: {
+
+ case TargetOpcode::G_INSERT:
if (TypeIdx != 0)
return UnableToLegalize;
-
- unsigned Src = MI.getOperand(1).getReg();
- unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildAnyExt(SrcExt, Src);
-
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(),
- MI.getOperand(3).getImm());
- for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) {
- MIB.addReg(MI.getOperand(OpNum).getReg());
- MIB.addImm(MI.getOperand(OpNum + 1).getImm());
- }
-
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
- case TargetOpcode::G_LOAD: {
- assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
- WideTy.getSizeInBits() &&
- "illegal to increase number of bytes loaded");
-
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(),
- **MI.memoperands_begin());
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+
+ case TargetOpcode::G_LOAD:
+ // For some types like i24, we might try to widen to i32. To properly handle
+ // this we should be using a dedicated extending load, until then avoid
+ // trying to legalize.
+ if (alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) !=
+ WideTy.getSizeInBits())
+ return UnableToLegalize;
+ LLVM_FALLTHROUGH;
+ case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_ZEXTLOAD:
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
+
case TargetOpcode::G_STORE: {
if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(1) ||
WideTy != LLT::scalar(8))
return UnableToLegalize;
- auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
- auto Content = TLI.getBooleanContents(false, false);
-
- unsigned ExtOp = TargetOpcode::G_ANYEXT;
- if (Content == TargetLoweringBase::ZeroOrOneBooleanContent)
- ExtOp = TargetOpcode::G_ZEXT;
- else if (Content == TargetLoweringBase::ZeroOrNegativeOneBooleanContent)
- ExtOp = TargetOpcode::G_SEXT;
- else
- ExtOp = TargetOpcode::G_ANYEXT;
-
- unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildInstr(ExtOp).addDef(SrcExt).addUse(
- MI.getOperand(0).getReg());
- MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(),
- **MI.memoperands_begin());
- MI.eraseFromParent();
+ widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ZEXT);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
}
case TargetOpcode::G_CONSTANT: {
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm());
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ MachineOperand &SrcMO = MI.getOperand(1);
+ LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
+ const APInt &Val = SrcMO.getCImm()->getValue().sext(WideTy.getSizeInBits());
+ SrcMO.setCImm(ConstantInt::get(Ctx, Val));
+
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
}
case TargetOpcode::G_FCONSTANT: {
- unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm());
- MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt);
- MI.eraseFromParent();
+ MachineOperand &SrcMO = MI.getOperand(1);
+ LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
+ APFloat Val = SrcMO.getFPImm()->getValueAPF();
+ bool LosesInfo;
+ switch (WideTy.getSizeInBits()) {
+ case 32:
+ Val.convert(APFloat::IEEEsingle(), APFloat::rmTowardZero, &LosesInfo);
+ break;
+ case 64:
+ Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &LosesInfo);
+ break;
+ default:
+ llvm_unreachable("Unhandled fp widen type");
+ }
+ SrcMO.setFPImm(ConstantFP::get(Ctx, Val));
+
+ widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
}
- case TargetOpcode::G_BRCOND: {
- unsigned TstExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg());
- MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB());
- MI.eraseFromParent();
+ case TargetOpcode::G_BRCOND:
+ widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
- case TargetOpcode::G_FCMP: {
- unsigned Op0Ext, Op1Ext, DstReg;
- unsigned Cmp1 = MI.getOperand(2).getReg();
- unsigned Cmp2 = MI.getOperand(3).getReg();
- if (TypeIdx == 0) {
- Op0Ext = Cmp1;
- Op1Ext = Cmp2;
- DstReg = MRI.createGenericVirtualRegister(WideTy);
- } else {
- Op0Ext = MRI.createGenericVirtualRegister(WideTy);
- Op1Ext = MRI.createGenericVirtualRegister(WideTy);
- DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op0Ext, Cmp1);
- MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op1Ext, Cmp2);
- }
- MIRBuilder.buildFCmp(
- static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
- DstReg, Op0Ext, Op1Ext);
+
+ case TargetOpcode::G_FCMP:
if (TypeIdx == 0)
- MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(),
- DstReg);
- MI.eraseFromParent();
- return Legalized;
- }
- case TargetOpcode::G_ICMP: {
- bool IsSigned = CmpInst::isSigned(
- static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
- unsigned Cmp1 = MI.getOperand(2).getReg();
- unsigned Cmp2 = MI.getOperand(3).getReg();
- unsigned Op0Ext, Op1Ext, DstReg;
- if (TypeIdx == 0) {
- Op0Ext = Cmp1;
- Op1Ext = Cmp2;
- DstReg = MRI.createGenericVirtualRegister(WideTy);
- } else {
- Op0Ext = MRI.createGenericVirtualRegister(WideTy);
- Op1Ext = MRI.createGenericVirtualRegister(WideTy);
- DstReg = MI.getOperand(0).getReg();
- if (IsSigned) {
- MIRBuilder.buildSExt(Op0Ext, Cmp1);
- MIRBuilder.buildSExt(Op1Ext, Cmp2);
- } else {
- MIRBuilder.buildZExt(Op0Ext, Cmp1);
- MIRBuilder.buildZExt(Op1Ext, Cmp2);
- }
+ widenScalarDst(MI, WideTy);
+ else {
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
+ widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);
}
- MIRBuilder.buildICmp(
- static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
- DstReg, Op0Ext, Op1Ext);
+ MIRBuilder.recordInsertion(&MI);
+ return Legalized;
+
+ case TargetOpcode::G_ICMP:
if (TypeIdx == 0)
- MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(),
- DstReg);
- MI.eraseFromParent();
+ widenScalarDst(MI, WideTy);
+ else {
+ unsigned ExtOpcode = CmpInst::isSigned(static_cast<CmpInst::Predicate>(
+ MI.getOperand(1).getPredicate()))
+ ? TargetOpcode::G_SEXT
+ : TargetOpcode::G_ZEXT;
+ widenScalarSrc(MI, WideTy, 2, ExtOpcode);
+ widenScalarSrc(MI, WideTy, 3, ExtOpcode);
+ }
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
- case TargetOpcode::G_GEP: {
+
+ case TargetOpcode::G_GEP:
assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
- unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy);
- MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg());
- MI.getOperand(2).setReg(OffsetExt);
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
- }
+
case TargetOpcode::G_PHI: {
assert(TypeIdx == 0 && "Expecting only Idx 0");
- auto getExtendedReg = [&](unsigned Reg, MachineBasicBlock &MBB) {
- auto FirstTermIt = MBB.getFirstTerminator();
- MIRBuilder.setInsertPt(MBB, FirstTermIt);
- MachineInstr *DefMI = MRI.getVRegDef(Reg);
- MachineInstrBuilder MIB;
- if (DefMI->getOpcode() == TargetOpcode::G_TRUNC)
- MIB = MIRBuilder.buildAnyExtOrTrunc(WideTy,
- DefMI->getOperand(1).getReg());
- else
- MIB = MIRBuilder.buildAnyExt(WideTy, Reg);
- return MIB->getOperand(0).getReg();
- };
- auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, WideTy);
- for (auto OpIt = MI.operands_begin() + 1, OpE = MI.operands_end();
- OpIt != OpE;) {
- unsigned Reg = OpIt++->getReg();
- MachineBasicBlock *OpMBB = OpIt++->getMBB();
- MIB.addReg(getExtendedReg(Reg, *OpMBB));
- MIB.addMBB(OpMBB);
+
+ for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
+ MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
+ MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
+ widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
}
- auto *MBB = MI.getParent();
- MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI());
- MIRBuilder.buildTrunc(MI.getOperand(0).getReg(),
- MIB->getOperand(0).getReg());
- MI.eraseFromParent();
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
+ widenScalarDst(MI, WideTy);
+ MIRBuilder.recordInsertion(&MI);
return Legalized;
}
}
@@ -813,7 +860,21 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
unsigned Zero = MRI.createGenericVirtualRegister(Ty);
MIRBuilder.buildConstant(Zero, 0);
- MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
+
+ // For *signed* multiply, overflow is detected by checking:
+ // (hi != (lo >> bitwidth-1))
+ if (Opcode == TargetOpcode::G_SMULH) {
+ unsigned Shifted = MRI.createGenericVirtualRegister(Ty);
+ unsigned ShiftAmt = MRI.createGenericVirtualRegister(Ty);
+ MIRBuilder.buildConstant(ShiftAmt, Ty.getSizeInBits() - 1);
+ MIRBuilder.buildInstr(TargetOpcode::G_ASHR)
+ .addDef(Shifted)
+ .addUse(Res)
+ .addUse(ShiftAmt);
+ MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
+ } else {
+ MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
+ }
MI.eraseFromParent();
return Legalized;
}
@@ -843,11 +904,10 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
}
ConstantFP &ZeroForNegation =
*cast<ConstantFP>(ConstantFP::getZeroValueForNegation(ZeroTy));
- unsigned Zero = MRI.createGenericVirtualRegister(Ty);
- MIRBuilder.buildFConstant(Zero, ZeroForNegation);
+ auto Zero = MIRBuilder.buildFConstant(Ty, ZeroForNegation);
MIRBuilder.buildInstr(TargetOpcode::G_FSUB)
.addDef(Res)
- .addUse(Zero)
+ .addUse(Zero->getOperand(0).getReg())
.addUse(MI.getOperand(1).getReg());
MI.eraseFromParent();
return Legalized;
@@ -856,7 +916,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
// Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
// First, check if G_FNEG is marked as Lower. If so, we may
// end up with an infinite loop as G_FSUB is used to legalize G_FNEG.
- if (LI.getAction({G_FNEG, Ty}).first == LegalizerInfo::Lower)
+ if (LI.getAction({G_FNEG, {Ty}}).Action == Lower)
return UnableToLegalize;
unsigned Res = MI.getOperand(0).getReg();
unsigned LHS = MI.getOperand(1).getReg();
@@ -882,6 +942,48 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
MI.eraseFromParent();
return Legalized;
}
+ case TargetOpcode::G_LOAD:
+ case TargetOpcode::G_SEXTLOAD:
+ case TargetOpcode::G_ZEXTLOAD: {
+ // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned PtrReg = MI.getOperand(1).getReg();
+ LLT DstTy = MRI.getType(DstReg);
+ auto &MMO = **MI.memoperands_begin();
+
+ if (DstTy.getSizeInBits() == MMO.getSize() /* in bytes */ * 8) {
+ // In the case of G_LOAD, this was a non-extending load already and we're
+ // about to lower to the same instruction.
+ if (MI.getOpcode() == TargetOpcode::G_LOAD)
+ return UnableToLegalize;
+ MIRBuilder.buildLoad(DstReg, PtrReg, MMO);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+
+ if (DstTy.isScalar()) {
+ unsigned TmpReg = MRI.createGenericVirtualRegister(
+ LLT::scalar(MMO.getSize() /* in bytes */ * 8));
+ MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
+ switch (MI.getOpcode()) {
+ default:
+ llvm_unreachable("Unexpected opcode");
+ case TargetOpcode::G_LOAD:
+ MIRBuilder.buildAnyExt(DstReg, TmpReg);
+ break;
+ case TargetOpcode::G_SEXTLOAD:
+ MIRBuilder.buildSExt(DstReg, TmpReg);
+ break;
+ case TargetOpcode::G_ZEXTLOAD:
+ MIRBuilder.buildZExt(DstReg, TmpReg);
+ break;
+ }
+ MI.eraseFromParent();
+ return Legalized;
+ }
+
+ return UnableToLegalize;
+ }
}
}