Skip to content

Commit

Permalink
[X86] Resolve FIXME: Copy kill flag for eflags
Browse files Browse the repository at this point in the history
We now mark the last eflags usage as kill if the def was also kill.
  • Loading branch information
AreaZR committed Mar 3, 2024
1 parent 03f150b commit a1d3891
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 39 deletions.
15 changes: 10 additions & 5 deletions llvm/lib/CodeGen/MachineCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,10 @@ MachineCombiner::getDepth(SmallVectorImpl<MachineInstr *> &InsInstrs,
assert(DefInstr &&
"There must be a definition for a new virtual register");
DepthOp = InstrDepth[II->second];
int DefIdx = DefInstr->findRegisterDefOperandIdx(MO.getReg());
int UseIdx = InstrPtr->findRegisterUseOperandIdx(MO.getReg());
int DefIdx =
DefInstr->findRegisterDefOperandIdx(MO.getReg(), false, false, TRI);
int UseIdx =
InstrPtr->findRegisterUseOperandIdx(MO.getReg(), false, TRI);
LatencyOp = TSchedModel.computeOperandLatency(DefInstr, DefIdx,
InstrPtr, UseIdx);
} else {
Expand All @@ -244,8 +246,11 @@ MachineCombiner::getDepth(SmallVectorImpl<MachineInstr *> &InsInstrs,
DepthOp = BlockTrace.getInstrCycles(*DefInstr).Depth;
if (!isTransientMI(DefInstr))
LatencyOp = TSchedModel.computeOperandLatency(
DefInstr, DefInstr->findRegisterDefOperandIdx(MO.getReg()),
InstrPtr, InstrPtr->findRegisterUseOperandIdx(MO.getReg()));
DefInstr,
DefInstr->findRegisterDefOperandIdx(MO.getReg(), false, false,
TRI),
InstrPtr,
InstrPtr->findRegisterUseOperandIdx(MO.getReg(), false, TRI));
}
}
IDepth = std::max(IDepth, DepthOp + LatencyOp);
Expand Down Expand Up @@ -284,7 +289,7 @@ unsigned MachineCombiner::getLatency(MachineInstr *Root, MachineInstr *NewRoot,
if (UseMO && BlockTrace.isDepInTrace(*Root, *UseMO)) {
LatencyOp = TSchedModel.computeOperandLatency(
NewRoot, NewRoot->findRegisterDefOperandIdx(MO.getReg()), UseMO,
UseMO->findRegisterUseOperandIdx(MO.getReg()));
UseMO->findRegisterUseOperandIdx(MO.getReg(), false, TRI));
} else {
LatencyOp = TSchedModel.computeInstrLatency(NewRoot);
}
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/CodeGen/ModuloSchedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1673,7 +1673,9 @@ void PeelingModuloScheduleExpander::moveStageBetweenBlocks(
// we don't need the phi anymore.
if (getStage(Def) == Stage) {
Register PhiReg = MI.getOperand(0).getReg();
assert(Def->findRegisterDefOperandIdx(MI.getOperand(1).getReg()) != -1);
assert(Def->findRegisterDefOperandIdx(MI.getOperand(1).getReg(), false,
false,
MRI.getTargetRegisterInfo()) != -1);
MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
MI.getOperand(0).setReg(PhiReg);
PhiToDelete.push_back(&MI);
Expand Down Expand Up @@ -1899,7 +1901,8 @@ Register
PeelingModuloScheduleExpander::getEquivalentRegisterIn(Register Reg,
MachineBasicBlock *BB) {
MachineInstr *MI = MRI.getUniqueVRegDef(Reg);
unsigned OpIdx = MI->findRegisterDefOperandIdx(Reg);
unsigned OpIdx = MI->findRegisterDefOperandIdx(Reg, false, false,
MRI.getTargetRegisterInfo());
return BlockMIs[{BB, CanonicalMIs[MI]}]->getOperand(OpIdx).getReg();
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/PeepholeOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,7 @@ bool PeepholeOptimizer::findTargetRecurrence(
return false;

MachineInstr &MI = *(MRI->use_instr_nodbg_begin(Reg));
unsigned Idx = MI.findRegisterUseOperandIdx(Reg);
unsigned Idx = MI.findRegisterUseOperandIdx(Reg, false, TRI);

// Only interested in recurrences whose instructions have only one def, which
// is a virtual register.
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/RegisterCoalescer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ bool RegisterCoalescer::adjustCopiesBackFrom(const CoalescerPair &CP,

// If the source instruction was killing the source register before the
// merge, unset the isKill marker given the live range has been extended.
int UIdx = ValSEndInst->findRegisterUseOperandIdx(IntB.reg(), true);
int UIdx = ValSEndInst->findRegisterUseOperandIdx(IntB.reg(), true, TRI);
if (UIdx != -1) {
ValSEndInst->getOperand(UIdx).setIsKill(false);
}
Expand Down Expand Up @@ -848,7 +848,7 @@ RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
return { false, false };
// If DefMI is a two-address instruction then commuting it will change the
// destination register.
int DefIdx = DefMI->findRegisterDefOperandIdx(IntA.reg());
int DefIdx = DefMI->findRegisterDefOperandIdx(IntA.reg(), false, TRI);
assert(DefIdx != -1);
unsigned UseOpIdx;
if (!DefMI->isRegTiedToUseOperand(DefIdx, &UseOpIdx))
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1355,8 +1355,10 @@ tryInstructionTransform(MachineBasicBlock::iterator &mi,
<< "2addr: NEW INST: " << *NewMIs[1]);

// Transform the instruction, now that it no longer has a load.
unsigned NewDstIdx = NewMIs[1]->findRegisterDefOperandIdx(regA);
unsigned NewSrcIdx = NewMIs[1]->findRegisterUseOperandIdx(regB);
unsigned NewDstIdx =
NewMIs[1]->findRegisterDefOperandIdx(regA, false, TRI);
unsigned NewSrcIdx =
NewMIs[1]->findRegisterUseOperandIdx(regB, false, TRI);
MachineBasicBlock::iterator NewMI = NewMIs[1];
bool TransformResult =
tryInstructionTransform(NewMI, mi, NewSrcIdx, NewDstIdx, Dist, true);
Expand Down
49 changes: 40 additions & 9 deletions llvm/lib/Target/X86/X86FlagsCopyLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,31 @@ static X86::CondCode getCondFromFCMOV(unsigned Opcode) {
}
}

static bool checkEFLAGSLive(MachineInstr *MI) {
if (MI->killsRegister(X86::EFLAGS))
return false;

// The EFLAGS operand of MI might be missing a kill marker.
// Figure out whether EFLAGS operand should LIVE after MI instruction.
MachineBasicBlock *BB = MI->getParent();
MachineBasicBlock::iterator ItrMI = MI;

// Scan forward through BB for a use/def of EFLAGS.
for (auto I = std::next(ItrMI), E = BB->end(); I != E; ++I) {
if (I->readsRegister(X86::EFLAGS))
return true;
if (I->definesRegister(X86::EFLAGS))
return false;
}

// We hit the end of the block, check whether EFLAGS is live into a successor.
for (MachineBasicBlock *Succ : BB->successors())
if (Succ->isLiveIn(X86::EFLAGS))
return true;

return false;
}

bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName()
<< " **********\n");
Expand Down Expand Up @@ -442,7 +467,8 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
llvm::reverse(llvm::make_range(Begin, End)), [&](MachineInstr &MI) {
// Flag any instruction (other than the copy we are
// currently rewriting) that defs EFLAGS.
return &MI != CopyI && MI.findRegisterDefOperand(X86::EFLAGS);
return &MI != CopyI &&
MI.findRegisterDefOperand(X86::EFLAGS, false, false, TRI);
});
};
auto HasEFLAGSClobberPath = [&](MachineBasicBlock *BeginMBB,
Expand Down Expand Up @@ -500,7 +526,7 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
auto DefIt = llvm::find_if(
llvm::reverse(llvm::make_range(TestMBB->instr_begin(), TestPos)),
[&](MachineInstr &MI) {
return MI.findRegisterDefOperand(X86::EFLAGS);
return MI.findRegisterDefOperand(X86::EFLAGS, false, false, TRI);
});
if (DefIt.base() != TestMBB->instr_begin()) {
dbgs() << " Using EFLAGS defined by: ";
Expand Down Expand Up @@ -562,9 +588,10 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
break;
}

MachineOperand *FlagUse = MI.findRegisterUseOperand(X86::EFLAGS);
MachineOperand *FlagUse =
MI.findRegisterUseOperand(X86::EFLAGS, false, TRI);
if (!FlagUse) {
if (MI.findRegisterDefOperand(X86::EFLAGS)) {
if (MI.findRegisterDefOperand(X86::EFLAGS, false, false, TRI)) {
// If EFLAGS are defined, it's as-if they were killed. We can stop
// scanning here.
//
Expand Down Expand Up @@ -614,7 +641,7 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
rewriteCopy(MI, *FlagUse, CopyDefI);
} else {
// We assume all other instructions that use flags also def them.
assert(MI.findRegisterDefOperand(X86::EFLAGS) &&
assert(MI.findRegisterDefOperand(X86::EFLAGS, false, false, TRI) &&
"Expected a def of EFLAGS for this instruction!");

// NB!!! Several arithmetic instructions only *partially* update
Expand Down Expand Up @@ -683,6 +710,8 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
// Now rewrite the jumps that use the flags. These we handle specially
// because if there are multiple jumps in a single basic block we'll have
// to do surgery on the CFG.
bool CopyDefIsKill = !checkEFLAGSLive(&CopyDefI);
MachineOperand *LastEflagsUse = nullptr;
MachineBasicBlock *LastJmpMBB = nullptr;
for (MachineInstr *JmpI : JmpIs) {
// Past the first jump within a basic block we need to split the blocks
Expand All @@ -693,10 +722,12 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
LastJmpMBB = JmpI->getParent();

rewriteCondJmp(*TestMBB, TestPos, TestLoc, *JmpI, CondRegs);
if (CopyDefIsKill && JmpI->readsRegister(X86::EFLAGS))
LastEflagsUse = JmpI->findRegisterUseOperand(X86::EFLAGS, false, TRI);
}

// FIXME: Mark the last use of EFLAGS before the copy's def as a kill if
// the copy's def operand is itself a kill.
if (LastEflagsUse && CopyDefIsKill)
LastEflagsUse->setIsKill(true);
}

#ifndef NDEBUG
Expand Down Expand Up @@ -733,7 +764,7 @@ CondRegArray X86FlagsCopyLoweringPass::collectCondsInRegs(

// Stop scanning when we see the first definition of the EFLAGS as prior to
// this we would potentially capture the wrong flag state.
if (MI.findRegisterDefOperand(X86::EFLAGS))
if (MI.findRegisterDefOperand(X86::EFLAGS, false, false, TRI))
break;
}
return CondRegs;
Expand Down Expand Up @@ -911,7 +942,7 @@ void X86FlagsCopyLoweringPass::rewriteCondJmp(
// Rewrite the jump to use the !ZF flag from the test, and kill its use of
// flags afterward.
JmpI.getOperand(1).setImm(Inverted ? X86::COND_E : X86::COND_NE);
JmpI.findRegisterUseOperand(X86::EFLAGS)->setIsKill(true);
JmpI.findRegisterUseOperand(X86::EFLAGS, false, TRI)->setIsKill(true);
LLVM_DEBUG(dbgs() << " fixed jCC: "; JmpI.dump());
}

Expand Down
39 changes: 25 additions & 14 deletions llvm/lib/Target/X86/X86InstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3711,7 +3711,8 @@ bool X86InstrInfo::analyzeBranchImpl(

// In practice we should never have an undef eflags operand, if we do
// abort here as we are not prepared to preserve the flag.
if (I->findRegisterUseOperand(X86::EFLAGS)->isUndef())
if (I->findRegisterUseOperand(X86::EFLAGS, false, &getRegisterInfo())
->isUndef())
return true;

// Working from the bottom, handle the first conditional branch.
Expand Down Expand Up @@ -5455,7 +5456,8 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
}

// Make sure Sub instruction defines EFLAGS and mark the def live.
MachineOperand *FlagDef = Sub->findRegisterDefOperand(X86::EFLAGS);
MachineOperand *FlagDef = Sub->findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());
assert(FlagDef && "Unable to locate a def EFLAGS operand");
FlagDef->setIsDead(false);

Expand Down Expand Up @@ -5608,7 +5610,8 @@ bool X86InstrInfo::foldImmediateImpl(MachineInstr &UseMI, MachineInstr *DefMI,
return false;
}

if (UseMI.findRegisterUseOperand(Reg)->getSubReg())
if (UseMI.findRegisterUseOperand(Reg, false, MRI->getTargetRegisterInfo())
->getSubReg())
return false;
// Immediate has larger code size than register. So avoid folding the
// immediate if it has more than 1 use and we are optimizing for size.
Expand Down Expand Up @@ -5655,7 +5658,7 @@ bool X86InstrInfo::foldImmediateImpl(MachineInstr &UseMI, MachineInstr *DefMI,
if (!MakeChange)
return true;
UseMI.setDesc(get(X86::MOV32r0));
UseMI.removeOperand(UseMI.findRegisterUseOperandIdx(Reg));
UseMI.removeOperand(UseMI.findRegisterUseOperandIdx(Reg, false, TRI));
UseMI.addOperand(MachineOperand::CreateReg(X86::EFLAGS, /*isDef=*/true,
/*isImp=*/true,
/*isKill=*/false,
Expand All @@ -5677,17 +5680,18 @@ bool X86InstrInfo::foldImmediateImpl(MachineInstr &UseMI, MachineInstr *DefMI,
NewOpc == X86::SBB64ri32 || NewOpc == X86::SBB32ri ||
NewOpc == X86::SUB64ri32_ND || NewOpc == X86::SUB32ri_ND ||
NewOpc == X86::SBB64ri32_ND || NewOpc == X86::SBB32ri_ND) &&
UseMI.findRegisterUseOperandIdx(Reg) != 2)
UseMI.findRegisterUseOperandIdx(Reg, false, &getRegisterInfo()) != 2)
return false;
// For CMP instructions the immediate can only be at index 1.
if ((NewOpc == X86::CMP64ri32 || NewOpc == X86::CMP32ri) &&
UseMI.findRegisterUseOperandIdx(Reg) != 1)
UseMI.findRegisterUseOperandIdx(Reg, false, &getRegisterInfo()) != 1)
return false;

using namespace X86;
if (isSHL(Opc) || isSHR(Opc) || isSAR(Opc) || isROL(Opc) || isROR(Opc) ||
isRCL(Opc) || isRCR(Opc)) {
unsigned RegIdx = UseMI.findRegisterUseOperandIdx(Reg);
unsigned RegIdx =
UseMI.findRegisterUseOperandIdx(Reg, false, &getRegisterInfo());
if (RegIdx < 2)
return false;
if (!isInt<8>(ImmVal))
Expand Down Expand Up @@ -5716,8 +5720,10 @@ bool X86InstrInfo::foldImmediateImpl(MachineInstr &UseMI, MachineInstr *DefMI,
// ==>
// %100 = COPY %101
UseMI.setDesc(get(TargetOpcode::COPY));
UseMI.removeOperand(UseMI.findRegisterUseOperandIdx(Reg));
UseMI.removeOperand(UseMI.findRegisterDefOperandIdx(X86::EFLAGS));
UseMI.removeOperand(
UseMI.findRegisterUseOperandIdx(Reg, false, &getRegisterInfo()));
UseMI.removeOperand(UseMI.findRegisterDefOperandIdx(
X86::EFLAGS, false, false, &getRegisterInfo()));
UseMI.untieRegOperand(0);
UseMI.clearFlag(MachineInstr::MIFlag::NoSWrap);
UseMI.clearFlag(MachineInstr::MIFlag::NoUWrap);
Expand Down Expand Up @@ -9516,7 +9522,8 @@ bool X86InstrInfo::hasReassociableOperands(const MachineInstr &Inst,
// not change anything because rearranging the operands could affect other
// instructions that depend on the exact status flags (zero, sign, etc.)
// that are set by using these particular operands with this operation.
const MachineOperand *FlagDef = Inst.findRegisterDefOperand(X86::EFLAGS);
const MachineOperand *FlagDef = Inst.findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());
assert((Inst.getNumDefs() == 1 || FlagDef) && "Implicit def isn't flags?");
if (FlagDef && !FlagDef->isDead())
return false;
Expand Down Expand Up @@ -10038,8 +10045,10 @@ void X86InstrInfo::setSpecialOperandAttr(MachineInstr &OldMI1,
MachineInstr &NewMI1,
MachineInstr &NewMI2) const {
// Integer instructions may define an implicit EFLAGS dest register operand.
MachineOperand *OldFlagDef1 = OldMI1.findRegisterDefOperand(X86::EFLAGS);
MachineOperand *OldFlagDef2 = OldMI2.findRegisterDefOperand(X86::EFLAGS);
MachineOperand *OldFlagDef1 = OldMI1.findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());
MachineOperand *OldFlagDef2 = OldMI2.findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());

assert(!OldFlagDef1 == !OldFlagDef2 &&
"Unexpected instruction type for reassociation");
Expand All @@ -10050,8 +10059,10 @@ void X86InstrInfo::setSpecialOperandAttr(MachineInstr &OldMI1,
assert(OldFlagDef1->isDead() && OldFlagDef2->isDead() &&
"Must have dead EFLAGS operand in reassociable instruction");

MachineOperand *NewFlagDef1 = NewMI1.findRegisterDefOperand(X86::EFLAGS);
MachineOperand *NewFlagDef2 = NewMI2.findRegisterDefOperand(X86::EFLAGS);
MachineOperand *NewFlagDef1 = NewMI1.findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());
MachineOperand *NewFlagDef2 = NewMI2.findRegisterDefOperand(
X86::EFLAGS, false, false, &getRegisterInfo());

assert(NewFlagDef1 && NewFlagDef2 &&
"Unexpected operand in reassociable instruction");
Expand Down
10 changes: 6 additions & 4 deletions llvm/lib/Target/X86/X86SpeculativeLoadHardening.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ bool X86SpeculativeLoadHardeningPass::runOnMachineFunction(
PredStateSubReg);
++NumInstsInserted;
MachineOperand *ZeroEFLAGSDefOp =
ZeroI->findRegisterDefOperand(X86::EFLAGS);
ZeroI->findRegisterDefOperand(X86::EFLAGS, false, false, TRI);
assert(ZeroEFLAGSDefOp && ZeroEFLAGSDefOp->isImplicit() &&
"Must have an implicit def of EFLAGS!");
ZeroEFLAGSDefOp->setIsDead(true);
Expand Down Expand Up @@ -762,7 +762,8 @@ X86SpeculativeLoadHardeningPass::tracePredStateThroughCFG(
// If this is the last cmov and the EFLAGS weren't originally
// live-in, mark them as killed.
if (!LiveEFLAGS && Cond == Conds.back())
CMovI->findRegisterUseOperand(X86::EFLAGS)->setIsKill(true);
CMovI->findRegisterUseOperand(X86::EFLAGS, false, TRI)
->setIsKill(true);

++NumInstsInserted;
LLVM_DEBUG(dbgs() << " Inserting cmov: "; CMovI->dump();
Expand Down Expand Up @@ -1185,7 +1186,7 @@ X86SpeculativeLoadHardeningPass::tracePredStateThroughIndirectBranches(
.addReg(PS->InitialReg)
.addReg(PS->PoisonReg)
.addImm(X86::COND_NE);
CMovI->findRegisterUseOperand(X86::EFLAGS)->setIsKill(true);
CMovI->findRegisterUseOperand(X86::EFLAGS, false, TRI)->setIsKill(true);
++NumInstsInserted;
LLVM_DEBUG(dbgs() << " Inserting cmov: "; CMovI->dump(); dbgs() << "\n");
CMovs.push_back(&*CMovI);
Expand Down Expand Up @@ -1213,7 +1214,8 @@ static bool isEFLAGSLive(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
// Check if EFLAGS are alive by seeing if there is a def of them or they
// live-in, and then seeing if that def is in turn used.
for (MachineInstr &MI : llvm::reverse(llvm::make_range(MBB.begin(), I))) {
if (MachineOperand *DefOp = MI.findRegisterDefOperand(X86::EFLAGS)) {
if (MachineOperand *DefOp =
MI.findRegisterDefOperand(X86::EFLAGS, false, false, &TRI)) {
// If the def is dead, then EFLAGS is not live.
if (DefOp->isDead())
return false;
Expand Down

0 comments on commit a1d3891

Please sign in to comment.