summaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp')
-rw-r--r--contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp479
1 files changed, 418 insertions, 61 deletions
diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 87086af121b7..b3fc94cdec60 100644
--- a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -15,24 +15,37 @@
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-
#define DEBUG_TYPE "legalizer"
using namespace llvm;
using namespace LegalizeActions;
-LegalizerHelper::LegalizerHelper(MachineFunction &MF)
- : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()) {
+LegalizerHelper::LegalizerHelper(MachineFunction &MF,
+ GISelChangeObserver &Observer,
+ MachineIRBuilder &Builder)
+ : MIRBuilder(Builder), MRI(MF.getRegInfo()),
+ LI(*MF.getSubtarget().getLegalizerInfo()), Observer(Observer) {
MIRBuilder.setMF(MF);
+ MIRBuilder.setChangeObserver(Observer);
}
+LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
+ GISelChangeObserver &Observer,
+ MachineIRBuilder &B)
+ : MIRBuilder(B), MRI(MF.getRegInfo()), LI(LI), Observer(Observer) {
+ MIRBuilder.setMF(MF);
+ MIRBuilder.setChangeObserver(Observer);
+}
LegalizerHelper::LegalizeResult
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
@@ -59,8 +72,8 @@ LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
case Custom:
LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
- return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized
- : UnableToLegalize;
+ return LI.legalizeCustom(MI, MRI, MIRBuilder, Observer) ? Legalized
+ : UnableToLegalize;
default:
LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
return UnableToLegalize;
@@ -77,17 +90,20 @@ void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
switch (Opcode) {
case TargetOpcode::G_SDIV:
- assert(Size == 32 && "Unsupported size");
- return RTLIB::SDIV_I32;
+ assert((Size == 32 || Size == 64) && "Unsupported size");
+ return Size == 64 ? RTLIB::SDIV_I64 : RTLIB::SDIV_I32;
case TargetOpcode::G_UDIV:
- assert(Size == 32 && "Unsupported size");
- return RTLIB::UDIV_I32;
+ assert((Size == 32 || Size == 64) && "Unsupported size");
+ return Size == 64 ? RTLIB::UDIV_I64 : RTLIB::UDIV_I32;
case TargetOpcode::G_SREM:
- assert(Size == 32 && "Unsupported size");
- return RTLIB::SREM_I32;
+ assert((Size == 32 || Size == 64) && "Unsupported size");
+ return Size == 64 ? RTLIB::SREM_I64 : RTLIB::SREM_I32;
case TargetOpcode::G_UREM:
+ assert((Size == 32 || Size == 64) && "Unsupported size");
+ return Size == 64 ? RTLIB::UREM_I64 : RTLIB::UREM_I32;
+ case TargetOpcode::G_CTLZ_ZERO_UNDEF:
assert(Size == 32 && "Unsupported size");
- return RTLIB::UREM_I32;
+ return RTLIB::CTLZ_I32;
case TargetOpcode::G_FADD:
assert((Size == 32 || Size == 64) && "Unsupported size");
return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32;
@@ -184,8 +200,9 @@ LegalizerHelper::libcall(MachineInstr &MI) {
case TargetOpcode::G_SDIV:
case TargetOpcode::G_UDIV:
case TargetOpcode::G_SREM:
- case TargetOpcode::G_UREM: {
- Type *HLTy = Type::getInt32Ty(Ctx);
+ case TargetOpcode::G_UREM:
+ case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
+ Type *HLTy = IntegerType::get(Ctx, Size);
auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy);
if (Status != Legalized)
return Status;
@@ -289,7 +306,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
for (int i = 0; i < NumParts; ++i)
DstRegs.push_back(
MIRBuilder.buildUndef(NarrowTy)->getOperand(0).getReg());
- MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
+
+ unsigned DstReg = MI.getOperand(0).getReg();
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -319,7 +341,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
CarryIn = CarryOut;
}
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildMerge(DstReg, DstRegs);
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -375,7 +400,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
DstRegs.push_back(SegReg);
}
- MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
+ unsigned DstReg = MI.getOperand(0).getReg();
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -436,7 +465,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
}
assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered");
- MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
+ unsigned DstReg = MI.getOperand(0).getReg();
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -462,12 +495,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
unsigned SrcReg = 0;
unsigned Adjustment = i * NarrowSize / 8;
+ unsigned Alignment = MinAlign(MMO.getAlignment(), Adjustment);
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());
+ NarrowSize / 8, Alignment, MMO.getAAInfo(), MMO.getRanges(),
+ MMO.getSyncScopeID(), MMO.getOrdering(), MMO.getFailureOrdering());
MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy,
Adjustment);
@@ -477,7 +510,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
DstRegs.push_back(DstReg);
}
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildMerge(DstReg, DstRegs);
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -504,12 +540,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
for (int i = 0; i < NumParts; ++i) {
unsigned DstReg = 0;
unsigned Adjustment = i * NarrowSize / 8;
+ unsigned Alignment = MinAlign(MMO.getAlignment(), Adjustment);
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());
+ NarrowSize / 8, Alignment, MMO.getAAInfo(), MMO.getRanges(),
+ MMO.getSyncScopeID(), MMO.getOrdering(), MMO.getFailureOrdering());
MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy,
Adjustment);
@@ -537,11 +573,16 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
DstRegs.push_back(DstReg);
}
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildMerge(DstReg, DstRegs);
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
- case TargetOpcode::G_OR: {
+ case TargetOpcode::G_AND:
+ case TargetOpcode::G_OR:
+ case TargetOpcode::G_XOR: {
// Legalize bitwise operation:
// A = BinOp<Ty> B, C
// into:
@@ -580,11 +621,15 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
// Do the operation on each small part.
for (int i = 0; i < NumParts; ++i)
- MIRBuilder.buildOr(DstRegs[i], SrcsReg1[i], SrcsReg2[i]);
+ MIRBuilder.buildInstr(MI.getOpcode(), {DstRegs[i]},
+ {SrcsReg1[i], SrcsReg2[i]});
// Gather the destination registers into the final destination.
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildMerge(DstReg, DstRegs);
+ if(MRI.getType(DstReg).isVector())
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+ else
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -594,7 +639,7 @@ 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());
+ auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO.getReg()});
MO.setReg(ExtB->getOperand(0).getReg());
}
@@ -603,7 +648,7 @@ void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,
MachineOperand &MO = MI.getOperand(OpIdx);
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
- MIRBuilder.buildInstr(TruncOpcode, MO.getReg(), DstExt);
+ MIRBuilder.buildInstr(TruncOpcode, {MO.getReg()}, {DstExt});
MO.setReg(DstExt);
}
@@ -614,6 +659,69 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
switch (MI.getOpcode()) {
default:
return UnableToLegalize;
+ case TargetOpcode::G_UADDO:
+ case TargetOpcode::G_USUBO: {
+ if (TypeIdx == 1)
+ return UnableToLegalize; // TODO
+ auto LHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, {WideTy},
+ {MI.getOperand(2).getReg()});
+ auto RHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, {WideTy},
+ {MI.getOperand(3).getReg()});
+ unsigned Opcode = MI.getOpcode() == TargetOpcode::G_UADDO
+ ? TargetOpcode::G_ADD
+ : TargetOpcode::G_SUB;
+ // Do the arithmetic in the larger type.
+ auto NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSZext, RHSZext});
+ LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
+ APInt Mask = APInt::getAllOnesValue(OrigTy.getSizeInBits());
+ auto AndOp = MIRBuilder.buildInstr(
+ TargetOpcode::G_AND, {WideTy},
+ {NewOp, MIRBuilder.buildConstant(WideTy, Mask.getZExtValue())});
+ // There is no overflow if the AndOp is the same as NewOp.
+ MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1).getReg(), NewOp,
+ AndOp);
+ // Now trunc the NewOp to the original result.
+ MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), NewOp);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ case TargetOpcode::G_CTTZ:
+ case TargetOpcode::G_CTTZ_ZERO_UNDEF:
+ case TargetOpcode::G_CTLZ:
+ case TargetOpcode::G_CTLZ_ZERO_UNDEF:
+ case TargetOpcode::G_CTPOP: {
+ // First ZEXT the input.
+ auto MIBSrc = MIRBuilder.buildZExt(WideTy, MI.getOperand(1).getReg());
+ LLT CurTy = MRI.getType(MI.getOperand(0).getReg());
+ if (MI.getOpcode() == TargetOpcode::G_CTTZ) {
+ // The count is the same in the larger type except if the original
+ // value was zero. This can be handled by setting the bit just off
+ // the top of the original type.
+ auto TopBit =
+ APInt::getOneBitSet(WideTy.getSizeInBits(), CurTy.getSizeInBits());
+ MIBSrc = MIRBuilder.buildInstr(
+ TargetOpcode::G_OR, {WideTy},
+ {MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit.getSExtValue())});
+ }
+ // Perform the operation at the larger size.
+ auto MIBNewOp = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy}, {MIBSrc});
+ // This is already the correct result for CTPOP and CTTZs
+ if (MI.getOpcode() == TargetOpcode::G_CTLZ ||
+ MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) {
+ // The correct result is NewOp - (Difference in widety and current ty).
+ unsigned SizeDiff = WideTy.getSizeInBits() - CurTy.getSizeInBits();
+ MIBNewOp = MIRBuilder.buildInstr(
+ TargetOpcode::G_SUB, {WideTy},
+ {MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff)});
+ }
+ auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
+ // Make the original instruction a trunc now, and update its source.
+ Observer.changingInstr(MI);
+ MI.setDesc(TII.get(TargetOpcode::G_TRUNC));
+ MI.getOperand(1).setReg(MIBNewOp->getOperand(0).getReg());
+ Observer.changedInstr(MI);
+ return Legalized;
+ }
case TargetOpcode::G_ADD:
case TargetOpcode::G_AND:
@@ -624,87 +732,100 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
// 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.
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_SHL:
+ Observer.changingInstr(MI);
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);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_SDIV:
case TargetOpcode::G_SREM:
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_ASHR:
+ Observer.changingInstr(MI);
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);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_UDIV:
case TargetOpcode::G_UREM:
case TargetOpcode::G_LSHR:
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(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.
- widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
- widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
- widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changingInstr(MI);
+ if (TypeIdx == 0) {
+ // 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.
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
+ widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
+ widenScalarDst(MI, WideTy);
+ } else {
+ // Explicit extension is required here since high bits affect the result.
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
+ }
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI:
if (TypeIdx != 0)
return UnableToLegalize;
+ Observer.changingInstr(MI);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_SITOFP:
if (TypeIdx != 1)
return UnableToLegalize;
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_UITOFP:
if (TypeIdx != 1)
return UnableToLegalize;
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_INSERT:
if (TypeIdx != 0)
return UnableToLegalize;
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_LOAD:
@@ -717,8 +838,9 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
LLVM_FALLTHROUGH;
case TargetOpcode::G_SEXTLOAD:
case TargetOpcode::G_ZEXTLOAD:
+ Observer.changingInstr(MI);
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_STORE: {
@@ -726,18 +848,20 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
WideTy != LLT::scalar(8))
return UnableToLegalize;
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ZEXT);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
}
case TargetOpcode::G_CONSTANT: {
MachineOperand &SrcMO = MI.getOperand(1);
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
const APInt &Val = SrcMO.getCImm()->getValue().sext(WideTy.getSizeInBits());
+ Observer.changingInstr(MI);
SrcMO.setCImm(ConstantInt::get(Ctx, Val));
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
}
case TargetOpcode::G_FCONSTANT: {
@@ -755,28 +879,38 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
default:
llvm_unreachable("Unhandled fp widen type");
}
+ Observer.changingInstr(MI);
SrcMO.setFPImm(ConstantFP::get(Ctx, Val));
widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
+ return Legalized;
+ }
+ case TargetOpcode::G_IMPLICIT_DEF: {
+ Observer.changingInstr(MI);
+ widenScalarDst(MI, WideTy);
+ Observer.changedInstr(MI);
return Legalized;
}
case TargetOpcode::G_BRCOND:
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_FCMP:
+ Observer.changingInstr(MI);
if (TypeIdx == 0)
widenScalarDst(MI, WideTy);
else {
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);
}
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_ICMP:
+ Observer.changingInstr(MI);
if (TypeIdx == 0)
widenScalarDst(MI, WideTy);
else {
@@ -787,18 +921,20 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
widenScalarSrc(MI, WideTy, 2, ExtOpcode);
widenScalarSrc(MI, WideTy, 3, ExtOpcode);
}
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_GEP:
assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
+ Observer.changingInstr(MI);
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_PHI: {
assert(TypeIdx == 0 && "Expecting only Idx 0");
+ Observer.changingInstr(MI);
for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
@@ -808,9 +944,25 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
MachineBasicBlock &MBB = *MI.getParent();
MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
widenScalarDst(MI, WideTy);
- MIRBuilder.recordInsertion(&MI);
+ Observer.changedInstr(MI);
return Legalized;
}
+ case TargetOpcode::G_EXTRACT_VECTOR_ELT:
+ if (TypeIdx != 2)
+ return UnableToLegalize;
+ Observer.changingInstr(MI);
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
+ Observer.changedInstr(MI);
+ return Legalized;
+
+ case TargetOpcode::G_FCEIL:
+ if (TypeIdx != 0)
+ return UnableToLegalize;
+ Observer.changingInstr(MI);
+ widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
+ widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
+ Observer.changedInstr(MI);
+ return Legalized;
}
}
@@ -984,6 +1136,30 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
return UnableToLegalize;
}
+ case TargetOpcode::G_CTLZ_ZERO_UNDEF:
+ case TargetOpcode::G_CTTZ_ZERO_UNDEF:
+ case TargetOpcode::G_CTLZ:
+ case TargetOpcode::G_CTTZ:
+ case TargetOpcode::G_CTPOP:
+ return lowerBitCount(MI, TypeIdx, Ty);
+ case G_UADDE: {
+ unsigned Res = MI.getOperand(0).getReg();
+ unsigned CarryOut = MI.getOperand(1).getReg();
+ unsigned LHS = MI.getOperand(2).getReg();
+ unsigned RHS = MI.getOperand(3).getReg();
+ unsigned CarryIn = MI.getOperand(4).getReg();
+
+ unsigned TmpRes = MRI.createGenericVirtualRegister(Ty);
+ unsigned ZExtCarryIn = MRI.createGenericVirtualRegister(Ty);
+
+ MIRBuilder.buildAdd(TmpRes, LHS, RHS);
+ MIRBuilder.buildZExt(ZExtCarryIn, CarryIn);
+ MIRBuilder.buildAdd(Res, TmpRes, ZExtCarryIn);
+ MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, Res, LHS);
+
+ MI.eraseFromParent();
+ return Legalized;
+ }
}
}
@@ -993,10 +1169,14 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
// FIXME: Don't know how to handle secondary types yet.
if (TypeIdx != 0)
return UnableToLegalize;
+
+ MIRBuilder.setInstr(MI);
switch (MI.getOpcode()) {
default:
return UnableToLegalize;
- case TargetOpcode::G_ADD: {
+ case TargetOpcode::G_IMPLICIT_DEF: {
+ SmallVector<unsigned, 2> DstRegs;
+
unsigned NarrowSize = NarrowTy.getSizeInBits();
unsigned DstReg = MI.getOperand(0).getReg();
unsigned Size = MRI.getType(DstReg).getSizeInBits();
@@ -1006,7 +1186,29 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
if (Size % NarrowSize != 0)
return UnableToLegalize;
- MIRBuilder.setInstr(MI);
+ for (int i = 0; i < NumParts; ++i) {
+ unsigned TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
+ MIRBuilder.buildUndef(TmpReg);
+ DstRegs.push_back(TmpReg);
+ }
+
+ if (NarrowTy.isVector())
+ MIRBuilder.buildConcatVectors(DstReg, DstRegs);
+ else
+ MIRBuilder.buildBuildVector(DstReg, DstRegs);
+
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ case TargetOpcode::G_ADD: {
+ unsigned NarrowSize = NarrowTy.getSizeInBits();
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned Size = MRI.getType(DstReg).getSizeInBits();
+ int NumParts = Size / NarrowSize;
+ // FIXME: Don't know how to handle the situation where the small vectors
+ // aren't all the same size yet.
+ if (Size % NarrowSize != 0)
+ return UnableToLegalize;
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
@@ -1018,9 +1220,164 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
DstRegs.push_back(DstReg);
}
- MIRBuilder.buildMerge(DstReg, DstRegs);
+ MIRBuilder.buildConcatVectors(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
+ case TargetOpcode::G_LOAD:
+ case TargetOpcode::G_STORE: {
+ bool IsLoad = MI.getOpcode() == TargetOpcode::G_LOAD;
+ unsigned ValReg = MI.getOperand(0).getReg();
+ unsigned AddrReg = MI.getOperand(1).getReg();
+ unsigned NarrowSize = NarrowTy.getSizeInBits();
+ unsigned Size = MRI.getType(ValReg).getSizeInBits();
+ unsigned NumParts = Size / NarrowSize;
+
+ SmallVector<unsigned, 8> NarrowRegs;
+ if (!IsLoad)
+ extractParts(ValReg, NarrowTy, NumParts, NarrowRegs);
+
+ const LLT OffsetTy =
+ LLT::scalar(MRI.getType(AddrReg).getScalarSizeInBits());
+ MachineFunction &MF = *MI.getMF();
+ MachineMemOperand *MMO = *MI.memoperands_begin();
+ for (unsigned Idx = 0; Idx < NumParts; ++Idx) {
+ unsigned Adjustment = Idx * NarrowTy.getSizeInBits() / 8;
+ unsigned Alignment = MinAlign(MMO->getAlignment(), Adjustment);
+ unsigned NewAddrReg = 0;
+ MIRBuilder.materializeGEP(NewAddrReg, AddrReg, OffsetTy, Adjustment);
+ MachineMemOperand &NewMMO = *MF.getMachineMemOperand(
+ MMO->getPointerInfo().getWithOffset(Adjustment), MMO->getFlags(),
+ NarrowTy.getSizeInBits() / 8, Alignment);
+ if (IsLoad) {
+ unsigned Dst = MRI.createGenericVirtualRegister(NarrowTy);
+ NarrowRegs.push_back(Dst);
+ MIRBuilder.buildLoad(Dst, NewAddrReg, NewMMO);
+ } else {
+ MIRBuilder.buildStore(NarrowRegs[Idx], NewAddrReg, NewMMO);
+ }
+ }
+ if (IsLoad) {
+ if (NarrowTy.isVector())
+ MIRBuilder.buildConcatVectors(ValReg, NarrowRegs);
+ else
+ MIRBuilder.buildBuildVector(ValReg, NarrowRegs);
+ }
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ }
+}
+
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
+ unsigned Opc = MI.getOpcode();
+ auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
+ auto isSupported = [this](const LegalityQuery &Q) {
+ auto QAction = LI.getAction(Q).Action;
+ return QAction == Legal || QAction == Libcall || QAction == Custom;
+ };
+ switch (Opc) {
+ default:
+ return UnableToLegalize;
+ case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
+ // This trivially expands to CTLZ.
+ Observer.changingInstr(MI);
+ MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
+ Observer.changedInstr(MI);
+ return Legalized;
+ }
+ case TargetOpcode::G_CTLZ: {
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned Len = Ty.getSizeInBits();
+ if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {Ty}})) {
+ // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
+ auto MIBCtlzZU = MIRBuilder.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF,
+ {Ty}, {SrcReg});
+ auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
+ auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
+ auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
+ SrcReg, MIBZero);
+ MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
+ MIBCtlzZU);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ // for now, we do this:
+ // NewLen = NextPowerOf2(Len);
+ // x = x | (x >> 1);
+ // x = x | (x >> 2);
+ // ...
+ // x = x | (x >>16);
+ // x = x | (x >>32); // for 64-bit input
+ // Upto NewLen/2
+ // return Len - popcount(x);
+ //
+ // Ref: "Hacker's Delight" by Henry Warren
+ unsigned Op = SrcReg;
+ unsigned NewLen = PowerOf2Ceil(Len);
+ for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
+ auto MIBShiftAmt = MIRBuilder.buildConstant(Ty, 1ULL << i);
+ auto MIBOp = MIRBuilder.buildInstr(
+ TargetOpcode::G_OR, {Ty},
+ {Op, MIRBuilder.buildInstr(TargetOpcode::G_LSHR, {Ty},
+ {Op, MIBShiftAmt})});
+ Op = MIBOp->getOperand(0).getReg();
+ }
+ auto MIBPop = MIRBuilder.buildInstr(TargetOpcode::G_CTPOP, {Ty}, {Op});
+ MIRBuilder.buildInstr(TargetOpcode::G_SUB, {MI.getOperand(0).getReg()},
+ {MIRBuilder.buildConstant(Ty, Len), MIBPop});
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ case TargetOpcode::G_CTTZ_ZERO_UNDEF: {
+ // This trivially expands to CTTZ.
+ Observer.changingInstr(MI);
+ MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
+ Observer.changedInstr(MI);
+ return Legalized;
+ }
+ case TargetOpcode::G_CTTZ: {
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned Len = Ty.getSizeInBits();
+ if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {Ty}})) {
+ // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
+ // zero.
+ auto MIBCttzZU = MIRBuilder.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF,
+ {Ty}, {SrcReg});
+ auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
+ auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
+ auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
+ SrcReg, MIBZero);
+ MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
+ MIBCttzZU);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ // for now, we use: { return popcount(~x & (x - 1)); }
+ // unless the target has ctlz but not ctpop, in which case we use:
+ // { return 32 - nlz(~x & (x-1)); }
+ // Ref: "Hacker's Delight" by Henry Warren
+ auto MIBCstNeg1 = MIRBuilder.buildConstant(Ty, -1);
+ auto MIBNot =
+ MIRBuilder.buildInstr(TargetOpcode::G_XOR, {Ty}, {SrcReg, MIBCstNeg1});
+ auto MIBTmp = MIRBuilder.buildInstr(
+ TargetOpcode::G_AND, {Ty},
+ {MIBNot, MIRBuilder.buildInstr(TargetOpcode::G_ADD, {Ty},
+ {SrcReg, MIBCstNeg1})});
+ if (!isSupported({TargetOpcode::G_CTPOP, {Ty}}) &&
+ isSupported({TargetOpcode::G_CTLZ, {Ty}})) {
+ auto MIBCstLen = MIRBuilder.buildConstant(Ty, Len);
+ MIRBuilder.buildInstr(
+ TargetOpcode::G_SUB, {MI.getOperand(0).getReg()},
+ {MIBCstLen,
+ MIRBuilder.buildInstr(TargetOpcode::G_CTLZ, {Ty}, {MIBTmp})});
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
+ MI.getOperand(1).setReg(MIBTmp->getOperand(0).getReg());
+ return Legalized;
+ }
}
}