Skip to content

Commit

Permalink
[CodeGen][NFC] Make TII::getMemOpBaseImmOfs return a base operand
Browse files Browse the repository at this point in the history
Currently, instructions doing memory accesses through a base operand that is
not a register can not be analyzed using `TII::getMemOpBaseRegImmOfs`.

This means that functions such as `TII::shouldClusterMemOps` will bail
out on instructions using an FI as a base instead of a register.

The goal of this patch is to refactor all this to return a base
operand instead of a base register.

Then in a separate patch, I will add FI support to the mem op clustering
in the MachineScheduler.

Differential Revision: https://reviews.llvm.org/D54846

llvm-svn: 347746
  • Loading branch information
francisvm committed Nov 28, 2018
1 parent dda6290 commit d7eebd6
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 170 deletions.
12 changes: 6 additions & 6 deletions llvm/include/llvm/CodeGen/TargetInstrInfo.h
Expand Up @@ -1136,11 +1136,11 @@ class TargetInstrInfo : public MCInstrInfo {
return false;
}

/// Get the base register and byte offset of an instruction that reads/writes
/// Get the base operand and byte offset of an instruction that reads/writes
/// memory.
virtual bool getMemOpBaseRegImmOfs(MachineInstr &MemOp, unsigned &BaseReg,
int64_t &Offset,
const TargetRegisterInfo *TRI) const {
virtual bool getMemOperandWithOffset(MachineInstr &MI,
MachineOperand *&BaseOp, int64_t &Offset,
const TargetRegisterInfo *TRI) const {
return false;
}

Expand All @@ -1164,8 +1164,8 @@ class TargetInstrInfo : public MCInstrInfo {
/// or
/// DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
/// to TargetPassConfig::createMachineScheduler() to have an effect.
virtual bool shouldClusterMemOps(MachineInstr &FirstLdSt, unsigned BaseReg1,
MachineInstr &SecondLdSt, unsigned BaseReg2,
virtual bool shouldClusterMemOps(MachineOperand &BaseOp1,
MachineOperand &BaseOp2,
unsigned NumLoads) const {
llvm_unreachable("target did not implement shouldClusterMemOps()");
}
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/CodeGen/ImplicitNullChecks.cpp
Expand Up @@ -360,10 +360,10 @@ ImplicitNullChecks::SuitabilityResult
ImplicitNullChecks::isSuitableMemoryOp(MachineInstr &MI, unsigned PointerReg,
ArrayRef<MachineInstr *> PrevInsts) {
int64_t Offset;
unsigned BaseReg;
MachineOperand *BaseOp;

if (!TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI) ||
BaseReg != PointerReg)
if (!TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI) ||
!BaseOp->isReg() || BaseOp->getReg() != PointerReg)
return SR_Unsuitable;

// We want the mem access to be issued at a sane offset from PointerReg,
Expand Down
28 changes: 17 additions & 11 deletions llvm/lib/CodeGen/MachinePipeliner.cpp
Expand Up @@ -1121,11 +1121,12 @@ void SwingSchedulerDAG::addLoopCarriedDependences(AliasAnalysis *AA) {
// First, perform the cheaper check that compares the base register.
// If they are the same and the load offset is less than the store
// offset, then mark the dependence as loop carried potentially.
unsigned BaseReg1, BaseReg2;
MachineOperand *BaseOp1, *BaseOp2;
int64_t Offset1, Offset2;
if (TII->getMemOpBaseRegImmOfs(LdMI, BaseReg1, Offset1, TRI) &&
TII->getMemOpBaseRegImmOfs(MI, BaseReg2, Offset2, TRI)) {
if (BaseReg1 == BaseReg2 && (int)Offset1 < (int)Offset2) {
if (TII->getMemOperandWithOffset(LdMI, BaseOp1, Offset1, TRI) &&
TII->getMemOperandWithOffset(MI, BaseOp2, Offset2, TRI)) {
if (BaseOp1->isIdenticalTo(*BaseOp2) &&
(int)Offset1 < (int)Offset2) {
assert(TII->areMemAccessesTriviallyDisjoint(LdMI, MI, AA) &&
"What happened to the chain edge?");
SDep Dep(Load, SDep::Barrier);
Expand Down Expand Up @@ -3246,11 +3247,16 @@ void SwingSchedulerDAG::addBranches(MBBVectorTy &PrologBBs,
/// during each iteration. Set Delta to the amount of the change.
bool SwingSchedulerDAG::computeDelta(MachineInstr &MI, unsigned &Delta) {
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
unsigned BaseReg;
MachineOperand *BaseOp;
int64_t Offset;
if (!TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI))
if (!TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI))
return false;

if (!BaseOp->isReg())
return false;

unsigned BaseReg = BaseOp->getReg();

MachineRegisterInfo &MRI = MF.getRegInfo();
// Check if there is a Phi. If so, get the definition in the loop.
MachineInstr *BaseDef = MRI.getVRegDef(BaseReg);
Expand Down Expand Up @@ -3653,19 +3659,19 @@ bool SwingSchedulerDAG::isLoopCarriedDep(SUnit *Source, const SDep &Dep,
if (!computeDelta(*SI, DeltaS) || !computeDelta(*DI, DeltaD))
return true;

unsigned BaseRegS, BaseRegD;
MachineOperand *BaseOpS, *BaseOpD;
int64_t OffsetS, OffsetD;
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
if (!TII->getMemOpBaseRegImmOfs(*SI, BaseRegS, OffsetS, TRI) ||
!TII->getMemOpBaseRegImmOfs(*DI, BaseRegD, OffsetD, TRI))
if (!TII->getMemOperandWithOffset(*SI, BaseOpS, OffsetS, TRI) ||
!TII->getMemOperandWithOffset(*DI, BaseOpD, OffsetD, TRI))
return true;

if (BaseRegS != BaseRegD)
if (!BaseOpS->isIdenticalTo(*BaseOpD))
return true;

// Check that the base register is incremented by a constant value for each
// iteration.
MachineInstr *Def = MRI.getVRegDef(BaseRegS);
MachineInstr *Def = MRI.getVRegDef(BaseOpS->getReg());
if (!Def || !Def->isPHI())
return true;
unsigned InitVal = 0;
Expand Down
22 changes: 11 additions & 11 deletions llvm/lib/CodeGen/MachineScheduler.cpp
Expand Up @@ -1483,15 +1483,15 @@ namespace {
class BaseMemOpClusterMutation : public ScheduleDAGMutation {
struct MemOpInfo {
SUnit *SU;
unsigned BaseReg;
MachineOperand *BaseOp;
int64_t Offset;

MemOpInfo(SUnit *su, unsigned reg, int64_t ofs)
: SU(su), BaseReg(reg), Offset(ofs) {}
MemOpInfo(SUnit *su, MachineOperand *Op, int64_t ofs)
: SU(su), BaseOp(Op), Offset(ofs) {}

bool operator<(const MemOpInfo&RHS) const {
return std::tie(BaseReg, Offset, SU->NodeNum) <
std::tie(RHS.BaseReg, RHS.Offset, RHS.SU->NodeNum);
bool operator<(const MemOpInfo &RHS) const {
return std::make_tuple(BaseOp->getReg(), Offset, SU->NodeNum) <
std::make_tuple(RHS.BaseOp->getReg(), RHS.Offset, RHS.SU->NodeNum);
}
};

Expand Down Expand Up @@ -1547,10 +1547,10 @@ void BaseMemOpClusterMutation::clusterNeighboringMemOps(
ArrayRef<SUnit *> MemOps, ScheduleDAGMI *DAG) {
SmallVector<MemOpInfo, 32> MemOpRecords;
for (SUnit *SU : MemOps) {
unsigned BaseReg;
MachineOperand *BaseOp;
int64_t Offset;
if (TII->getMemOpBaseRegImmOfs(*SU->getInstr(), BaseReg, Offset, TRI))
MemOpRecords.push_back(MemOpInfo(SU, BaseReg, Offset));
if (TII->getMemOperandWithOffset(*SU->getInstr(), BaseOp, Offset, TRI))
MemOpRecords.push_back(MemOpInfo(SU, BaseOp, Offset));
}
if (MemOpRecords.size() < 2)
return;
Expand All @@ -1560,8 +1560,8 @@ void BaseMemOpClusterMutation::clusterNeighboringMemOps(
for (unsigned Idx = 0, End = MemOpRecords.size(); Idx < (End - 1); ++Idx) {
SUnit *SUa = MemOpRecords[Idx].SU;
SUnit *SUb = MemOpRecords[Idx+1].SU;
if (TII->shouldClusterMemOps(*SUa->getInstr(), MemOpRecords[Idx].BaseReg,
*SUb->getInstr(), MemOpRecords[Idx+1].BaseReg,
if (TII->shouldClusterMemOps(*MemOpRecords[Idx].BaseOp,
*MemOpRecords[Idx + 1].BaseOp,
ClusterLength) &&
DAG->addEdge(SUb, SDep(SUa, SDep::Cluster))) {
LLVM_DEBUG(dbgs() << "Cluster ld/st SU(" << SUa->NodeNum << ") - SU("
Expand Down
9 changes: 6 additions & 3 deletions llvm/lib/CodeGen/MachineSink.cpp
Expand Up @@ -716,9 +716,12 @@ static bool SinkingPreventsImplicitNullCheck(MachineInstr &MI,
!PredBB->getTerminator()->getMetadata(LLVMContext::MD_make_implicit))
return false;

unsigned BaseReg;
MachineOperand *BaseOp;
int64_t Offset;
if (!TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI))
if (!TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI))
return false;

if (!BaseOp->isReg())
return false;

if (!(MI.mayLoad() && !MI.isPredicable()))
Expand All @@ -731,7 +734,7 @@ static bool SinkingPreventsImplicitNullCheck(MachineInstr &MI,
return MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
(MBP.Predicate == MachineBranchPredicate::PRED_NE ||
MBP.Predicate == MachineBranchPredicate::PRED_EQ) &&
MBP.LHS.getReg() == BaseReg;
MBP.LHS.getReg() == BaseOp->getReg();
}

/// Sink an instruction and its associated debug instructions. If the debug
Expand Down
81 changes: 49 additions & 32 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
Expand Up @@ -1135,7 +1135,7 @@ bool AArch64InstrInfo::isCoalescableExtInstr(const MachineInstr &MI,
bool AArch64InstrInfo::areMemAccessesTriviallyDisjoint(
MachineInstr &MIa, MachineInstr &MIb, AliasAnalysis *AA) const {
const TargetRegisterInfo *TRI = &getRegisterInfo();
unsigned BaseRegA = 0, BaseRegB = 0;
MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr;
int64_t OffsetA = 0, OffsetB = 0;
unsigned WidthA = 0, WidthB = 0;

Expand All @@ -1146,14 +1146,14 @@ bool AArch64InstrInfo::areMemAccessesTriviallyDisjoint(
MIa.hasOrderedMemoryRef() || MIb.hasOrderedMemoryRef())
return false;

// Retrieve the base register, offset from the base register and width. Width
// Retrieve the base register, offset from the base and width. Width
// is the size of memory that is being loaded/stored (e.g. 1, 2, 4, 8). If
// base registers are identical, and the offset of a lower memory access +
// the width doesn't overlap the offset of a higher memory access,
// then the memory accesses are different.
if (getMemOpBaseRegImmOfsWidth(MIa, BaseRegA, OffsetA, WidthA, TRI) &&
getMemOpBaseRegImmOfsWidth(MIb, BaseRegB, OffsetB, WidthB, TRI)) {
if (BaseRegA == BaseRegB) {
if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, WidthA, TRI) &&
getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, WidthB, TRI)) {
if (BaseOpA->isIdenticalTo(*BaseOpB)) {
int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
Expand Down Expand Up @@ -2042,10 +2042,13 @@ bool AArch64InstrInfo::isCandidateToMergeOrPair(MachineInstr &MI) const {

// Can't merge/pair if the instruction modifies the base register.
// e.g., ldr x0, [x0]
unsigned BaseReg = MI.getOperand(1).getReg();
const TargetRegisterInfo *TRI = &getRegisterInfo();
if (MI.modifiesRegister(BaseReg, TRI))
return false;
// This case will never occur with an FI base.
if (MI.getOperand(1).isReg()) {
unsigned BaseReg = MI.getOperand(1).getReg();
const TargetRegisterInfo *TRI = &getRegisterInfo();
if (MI.modifiesRegister(BaseReg, TRI))
return false;
}

// Check if this load/store has a hint to avoid pair formation.
// MachineMemOperands hints are set by the AArch64StorePairSuppress pass.
Expand All @@ -2068,16 +2071,17 @@ bool AArch64InstrInfo::isCandidateToMergeOrPair(MachineInstr &MI) const {
return true;
}

bool AArch64InstrInfo::getMemOpBaseRegImmOfs(
MachineInstr &LdSt, unsigned &BaseReg, int64_t &Offset,
const TargetRegisterInfo *TRI) const {
bool AArch64InstrInfo::getMemOperandWithOffset(MachineInstr &LdSt,
MachineOperand *&BaseOp,
int64_t &Offset,
const TargetRegisterInfo *TRI) const {
unsigned Width;
return getMemOpBaseRegImmOfsWidth(LdSt, BaseReg, Offset, Width, TRI);
return getMemOperandWithOffsetWidth(LdSt, BaseOp, Offset, Width, TRI);
}

bool AArch64InstrInfo::getMemOpBaseRegImmOfsWidth(
MachineInstr &LdSt, unsigned &BaseReg, int64_t &Offset, unsigned &Width,
const TargetRegisterInfo *TRI) const {
bool AArch64InstrInfo::getMemOperandWithOffsetWidth(
MachineInstr &LdSt, MachineOperand *&BaseOp, int64_t &Offset,
unsigned &Width, const TargetRegisterInfo *TRI) const {
assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
// Handle only loads/stores with base register followed by immediate offset.
if (LdSt.getNumExplicitOperands() == 3) {
Expand Down Expand Up @@ -2105,13 +2109,18 @@ bool AArch64InstrInfo::getMemOpBaseRegImmOfsWidth(
// multiplied by the scaling factor. Unscaled instructions have scaling factor
// set to 1.
if (LdSt.getNumExplicitOperands() == 3) {
BaseReg = LdSt.getOperand(1).getReg();
BaseOp = &LdSt.getOperand(1);
Offset = LdSt.getOperand(2).getImm() * Scale;
} else {
assert(LdSt.getNumExplicitOperands() == 4 && "invalid number of operands");
BaseReg = LdSt.getOperand(2).getReg();
BaseOp = &LdSt.getOperand(2);
Offset = LdSt.getOperand(3).getImm() * Scale;
}

assert(
BaseOp->isReg() &&
"getMemOperandWithOffset only supports base operands of type register.");

return true;
}

Expand Down Expand Up @@ -2322,13 +2331,19 @@ static bool canPairLdStOpc(unsigned FirstOpc, unsigned SecondOpc) {

/// Detect opportunities for ldp/stp formation.
///
/// Only called for LdSt for which getMemOpBaseRegImmOfs returns true.
bool AArch64InstrInfo::shouldClusterMemOps(MachineInstr &FirstLdSt,
unsigned BaseReg1,
MachineInstr &SecondLdSt,
unsigned BaseReg2,
/// Only called for LdSt for which getMemOperandWithOffset returns true.
bool AArch64InstrInfo::shouldClusterMemOps(MachineOperand &BaseOp1,
MachineOperand &BaseOp2,
unsigned NumLoads) const {
if (BaseReg1 != BaseReg2)
MachineInstr &FirstLdSt = *BaseOp1.getParent();
MachineInstr &SecondLdSt = *BaseOp2.getParent();
if (BaseOp1.getType() != BaseOp2.getType())
return false;

assert(BaseOp1.isReg() && "Only base registers are supported.");

// Check for base regs.
if (BaseOp1.isReg() && BaseOp1.getReg() != BaseOp2.getReg())
return false;

// Only cluster up to a single pair.
Expand Down Expand Up @@ -5402,19 +5417,20 @@ AArch64InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
// At this point, we have a stack instruction that we might need to fix
// up. We'll handle it if it's a load or store.
if (MI.mayLoadOrStore()) {
unsigned Base; // Filled with the base regiser of MI.
MachineOperand *Base; // Filled with the base operand of MI.
int64_t Offset; // Filled with the offset of MI.
unsigned DummyWidth;

// Does it allow us to offset the base register and is the base SP?
if (!getMemOpBaseRegImmOfsWidth(MI, Base, Offset, DummyWidth, &RI) ||
Base != AArch64::SP)
// Does it allow us to offset the base operand and is the base the
// register SP?
if (!getMemOperandWithOffset(MI, Base, Offset, &RI) ||
!Base->isReg() || Base->getReg() != AArch64::SP)
return outliner::InstrType::Illegal;

// Find the minimum/maximum offset for this instruction and check if
// fixing it up would be in range.
int64_t MinOffset, MaxOffset; // Unscaled offsets for the instruction.
unsigned Scale; // The scale to multiply the offsets by.
unsigned DummyWidth;
getMemOpInfo(MI.getOpcode(), Scale, DummyWidth, MinOffset, MaxOffset);

// TODO: We should really test what happens if an instruction overflows.
Expand All @@ -5439,13 +5455,14 @@ AArch64InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,

void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
for (MachineInstr &MI : MBB) {
unsigned Base, Width;
MachineOperand *Base;
unsigned Width;
int64_t Offset;

// Is this a load or store with an immediate offset with SP as the base?
if (!MI.mayLoadOrStore() ||
!getMemOpBaseRegImmOfsWidth(MI, Base, Offset, Width, &RI) ||
Base != AArch64::SP)
!getMemOperandWithOffsetWidth(MI, Base, Offset, Width, &RI) ||
(Base->isReg() && Base->getReg() != AArch64::SP))
continue;

// It is, so we have to fix it up.
Expand Down
15 changes: 7 additions & 8 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.h
Expand Up @@ -97,13 +97,13 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
/// Hint that pairing the given load or store is unprofitable.
static void suppressLdStPair(MachineInstr &MI);

bool getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg,
int64_t &Offset,
const TargetRegisterInfo *TRI) const override;
bool getMemOperandWithOffset(MachineInstr &MI, MachineOperand *&BaseOp,
int64_t &Offset,
const TargetRegisterInfo *TRI) const override;

bool getMemOpBaseRegImmOfsWidth(MachineInstr &LdSt, unsigned &BaseReg,
int64_t &Offset, unsigned &Width,
const TargetRegisterInfo *TRI) const;
bool getMemOperandWithOffsetWidth(MachineInstr &MI, MachineOperand *&BaseOp,
int64_t &Offset, unsigned &Width,
const TargetRegisterInfo *TRI) const;

/// Return the immediate offset of the base register in a load/store \p LdSt.
MachineOperand &getMemOpBaseRegImmOfsOffsetOperand(MachineInstr &LdSt) const;
Expand All @@ -115,8 +115,7 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
bool getMemOpInfo(unsigned Opcode, unsigned &Scale, unsigned &Width,
int64_t &MinOffset, int64_t &MaxOffset) const;

bool shouldClusterMemOps(MachineInstr &FirstLdSt, unsigned BaseReg1,
MachineInstr &SecondLdSt, unsigned BaseReg2,
bool shouldClusterMemOps(MachineOperand &BaseOp1, MachineOperand &BaseOp2,
unsigned NumLoads) const override;

void copyPhysRegTuple(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp
Expand Up @@ -148,9 +148,11 @@ bool AArch64StorePairSuppress::runOnMachineFunction(MachineFunction &MF) {
for (auto &MI : MBB) {
if (!isNarrowFPStore(MI))
continue;
unsigned BaseReg;
MachineOperand *BaseOp;
int64_t Offset;
if (TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI)) {
if (TII->getMemOperandWithOffset(MI, BaseOp, Offset, TRI) &&
BaseOp->isReg()) {
unsigned BaseReg = BaseOp->getReg();
if (PrevBaseReg == BaseReg) {
// If this block can take STPs, skip ahead to the next block.
if (!SuppressSTP && shouldAddSTPToBlock(MI.getParent()))
Expand Down

0 comments on commit d7eebd6

Please sign in to comment.