Skip to content

Commit 847a680

Browse files
committed
X86InstrInfo: Support immediates that are +1/-1 different in optimizeCompareInstr
This is a re-commit of e2c7ee0 which was reverted in a2a58d9. This includes a fix to consistently check for EFLAGS being live-out. See phabricator review. Original Summary: This extends `optimizeCompareInstr` to re-use previous comparison results if the previous comparison was with an immediate that was 1 bigger or smaller. Example: CMP x, 13 ... CMP x, 12 ; can be removed if we change the SETg SETg ... ; x > 12 changed to `SETge` (x >= 13) removing CMP Motivation: This often happens because SelectionDAG canonicalization tends to add/subtract 1 often when optimizing for fallthrough blocks. Example for `x > C` the fallthrough optimization switches true/false blocks with `!(x > C)` --> `x <= C` and canonicalization turns this into `x < C + 1`. Differential Revision: https://reviews.llvm.org/D110867
1 parent 870fc84 commit 847a680

File tree

5 files changed

+443
-24
lines changed

5 files changed

+443
-24
lines changed

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,8 +4014,8 @@ bool X86InstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
40144014
bool X86InstrInfo::isRedundantFlagInstr(const MachineInstr &FlagI,
40154015
Register SrcReg, Register SrcReg2,
40164016
int64_t ImmMask, int64_t ImmValue,
4017-
const MachineInstr &OI,
4018-
bool *IsSwapped) const {
4017+
const MachineInstr &OI, bool *IsSwapped,
4018+
int64_t *ImmDelta) const {
40194019
switch (OI.getOpcode()) {
40204020
case X86::CMP64rr:
40214021
case X86::CMP32rr:
@@ -4066,10 +4066,21 @@ bool X86InstrInfo::isRedundantFlagInstr(const MachineInstr &FlagI,
40664066
int64_t OIMask;
40674067
int64_t OIValue;
40684068
if (analyzeCompare(OI, OISrcReg, OISrcReg2, OIMask, OIValue) &&
4069-
SrcReg == OISrcReg && ImmMask == OIMask && OIValue == ImmValue) {
4070-
assert(SrcReg2 == X86::NoRegister && OISrcReg2 == X86::NoRegister &&
4071-
"should not have 2nd register");
4072-
return true;
4069+
SrcReg == OISrcReg && ImmMask == OIMask) {
4070+
if (OIValue == ImmValue) {
4071+
*ImmDelta = 0;
4072+
return true;
4073+
} else if (static_cast<uint64_t>(ImmValue) ==
4074+
static_cast<uint64_t>(OIValue) - 1) {
4075+
*ImmDelta = -1;
4076+
return true;
4077+
} else if (static_cast<uint64_t>(ImmValue) ==
4078+
static_cast<uint64_t>(OIValue) + 1) {
4079+
*ImmDelta = 1;
4080+
return true;
4081+
} else {
4082+
return false;
4083+
}
40734084
}
40744085
}
40754086
return FlagI.isIdenticalTo(OI);
@@ -4319,6 +4330,7 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
43194330
bool ShouldUpdateCC = false;
43204331
bool IsSwapped = false;
43214332
X86::CondCode NewCC = X86::COND_INVALID;
4333+
int64_t ImmDelta = 0;
43224334

43234335
// Search backward from CmpInstr for the next instruction defining EFLAGS.
43244336
const TargetRegisterInfo *TRI = &getRegisterInfo();
@@ -4365,7 +4377,7 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
43654377
// ... // EFLAGS not changed
43664378
// cmp x, y // <-- can be removed
43674379
if (isRedundantFlagInstr(CmpInstr, SrcReg, SrcReg2, CmpMask, CmpValue,
4368-
Inst, &IsSwapped)) {
4380+
Inst, &IsSwapped, &ImmDelta)) {
43694381
Sub = &Inst;
43704382
break;
43714383
}
@@ -4399,7 +4411,7 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
43994411
// It is safe to remove CmpInstr if EFLAGS is redefined or killed.
44004412
// If we are done with the basic block, we need to check whether EFLAGS is
44014413
// live-out.
4402-
bool IsSafe = false;
4414+
bool FlagsMayLiveOut = true;
44034415
SmallVector<std::pair<MachineInstr*, X86::CondCode>, 4> OpsToUpdate;
44044416
MachineBasicBlock::iterator AfterCmpInstr =
44054417
std::next(MachineBasicBlock::iterator(CmpInstr));
@@ -4409,15 +4421,15 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
44094421
// We should check the usage if this instruction uses and updates EFLAGS.
44104422
if (!UseEFLAGS && ModifyEFLAGS) {
44114423
// It is safe to remove CmpInstr if EFLAGS is updated again.
4412-
IsSafe = true;
4424+
FlagsMayLiveOut = false;
44134425
break;
44144426
}
44154427
if (!UseEFLAGS && !ModifyEFLAGS)
44164428
continue;
44174429

44184430
// EFLAGS is used by this instruction.
44194431
X86::CondCode OldCC = X86::COND_INVALID;
4420-
if (MI || IsSwapped) {
4432+
if (MI || IsSwapped || ImmDelta != 0) {
44214433
// We decode the condition code from opcode.
44224434
if (Instr.isBranch())
44234435
OldCC = X86::getCondFromBranch(Instr);
@@ -4470,24 +4482,74 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
44704482
// We swap the condition code and synthesize the new opcode.
44714483
ReplacementCC = getSwappedCondition(OldCC);
44724484
if (ReplacementCC == X86::COND_INVALID) return false;
4485+
ShouldUpdateCC = true;
4486+
} else if (ImmDelta != 0) {
4487+
unsigned BitWidth = TRI->getRegSizeInBits(*MRI->getRegClass(SrcReg));
4488+
// Shift amount for min/max constants to adjust for 8/16/32 instruction
4489+
// sizes.
4490+
switch (OldCC) {
4491+
case X86::COND_L: // x <s (C + 1) --> x <=s C
4492+
if (ImmDelta != 1 || APInt::getSignedMinValue(BitWidth) == CmpValue)
4493+
return false;
4494+
ReplacementCC = X86::COND_LE;
4495+
break;
4496+
case X86::COND_B: // x <u (C + 1) --> x <=u C
4497+
if (ImmDelta != 1 || CmpValue == 0)
4498+
return false;
4499+
ReplacementCC = X86::COND_BE;
4500+
break;
4501+
case X86::COND_GE: // x >=s (C + 1) --> x >s C
4502+
if (ImmDelta != 1 || APInt::getSignedMinValue(BitWidth) == CmpValue)
4503+
return false;
4504+
ReplacementCC = X86::COND_G;
4505+
break;
4506+
case X86::COND_AE: // x >=u (C + 1) --> x >u C
4507+
if (ImmDelta != 1 || CmpValue == 0)
4508+
return false;
4509+
ReplacementCC = X86::COND_A;
4510+
break;
4511+
case X86::COND_G: // x >s (C - 1) --> x >=s C
4512+
if (ImmDelta != -1 || APInt::getSignedMaxValue(BitWidth) == CmpValue)
4513+
return false;
4514+
ReplacementCC = X86::COND_GE;
4515+
break;
4516+
case X86::COND_A: // x >u (C - 1) --> x >=u C
4517+
if (ImmDelta != -1 || APInt::getMaxValue(BitWidth) == CmpValue)
4518+
return false;
4519+
ReplacementCC = X86::COND_AE;
4520+
break;
4521+
case X86::COND_LE: // x <=s (C - 1) --> x <s C
4522+
if (ImmDelta != -1 || APInt::getSignedMaxValue(BitWidth) == CmpValue)
4523+
return false;
4524+
ReplacementCC = X86::COND_L;
4525+
break;
4526+
case X86::COND_BE: // x <=u (C - 1) --> x <u C
4527+
if (ImmDelta != -1 || APInt::getMaxValue(BitWidth) == CmpValue)
4528+
return false;
4529+
ReplacementCC = X86::COND_B;
4530+
break;
4531+
default:
4532+
return false;
4533+
}
4534+
ShouldUpdateCC = true;
44734535
}
44744536

4475-
if ((ShouldUpdateCC || IsSwapped) && ReplacementCC != OldCC) {
4537+
if (ShouldUpdateCC && ReplacementCC != OldCC) {
44764538
// Push the MachineInstr to OpsToUpdate.
44774539
// If it is safe to remove CmpInstr, the condition code of these
44784540
// instructions will be modified.
44794541
OpsToUpdate.push_back(std::make_pair(&Instr, ReplacementCC));
44804542
}
44814543
if (ModifyEFLAGS || Instr.killsRegister(X86::EFLAGS, TRI)) {
44824544
// It is safe to remove CmpInstr if EFLAGS is updated again or killed.
4483-
IsSafe = true;
4545+
FlagsMayLiveOut = false;
44844546
break;
44854547
}
44864548
}
44874549

4488-
// If EFLAGS is not killed nor re-defined, we should check whether it is
4489-
// live-out. If it is live-out, do not optimize.
4490-
if ((MI || IsSwapped) && !IsSafe) {
4550+
// If we have to update users but EFLAGS is live-out abort, since we cannot
4551+
// easily find all of the users.
4552+
if (ShouldUpdateCC && FlagsMayLiveOut) {
44914553
for (MachineBasicBlock *Successor : CmpMBB.successors())
44924554
if (Successor->isLiveIn(X86::EFLAGS))
44934555
return false;

llvm/lib/Target/X86/X86InstrInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,8 @@ class X86InstrInfo final : public X86GenInstrInfo {
640640
/// CMP %1, %2 and %3 = SUB %2, %1 ; IsSwapped=true
641641
bool isRedundantFlagInstr(const MachineInstr &FlagI, Register SrcReg,
642642
Register SrcReg2, int64_t ImmMask, int64_t ImmValue,
643-
const MachineInstr &OI, bool *IsSwapped) const;
643+
const MachineInstr &OI, bool *IsSwapped,
644+
int64_t *ImmDelta) const;
644645
};
645646

646647
} // namespace llvm

0 commit comments

Comments
 (0)