Skip to content

Commit e2c7ee0

Browse files
committed
X86InstrInfo: Support immediates that are +1/-1 different in optimizeCompareInstr
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 97a1570 commit e2c7ee0

File tree

5 files changed

+349
-18
lines changed

5 files changed

+349
-18
lines changed

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 71 additions & 9 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
}
@@ -4417,7 +4429,7 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
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,9 +4482,59 @@ 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.

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

llvm/test/CodeGen/X86/optimize-compare.mir

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,219 @@ body: |
379379
CMP64ri32 %0, 24, implicit-def $eflags
380380
$cl = SETCCr 3, implicit $eflags
381381
...
382+
---
383+
name: opt_redundant_flags_adjusted_imm_0
384+
body: |
385+
bb.0:
386+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_0
387+
; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
388+
; CHECK-NEXT: CMP64ri8 [[COPY]], 1, implicit-def $eflags
389+
; CHECK-NEXT: $cl = SETCCr 4, implicit $eflags
390+
; CHECK-NEXT: $bl = SETCCr 15, implicit $eflags
391+
; CHECK-NEXT: $bl = SETCCr 7, implicit $eflags
392+
; CHECK-NEXT: $bl = SETCCr 14, implicit $eflags
393+
; CHECK-NEXT: $bl = SETCCr 6, implicit $eflags
394+
%0:gr64 = COPY $rsi
395+
; CMP+SETCC %0 == 1
396+
CMP64ri8 %0, 1, implicit-def $eflags
397+
$cl = SETCCr 4, implicit $eflags
398+
; CMP+SETCC %0 >= 2; CMP can be removed.
399+
CMP64ri8 %0, 2, implicit-def $eflags
400+
; %0 >=s 2 --> %0 >s 1
401+
$bl = SETCCr 13, implicit $eflags
402+
; %0 >=u 2 --> %0 >u 1
403+
$bl = SETCCr 3, implicit $eflags
404+
; %0 <s 2 --> %0 <=s 1
405+
$bl = SETCCr 12, implicit $eflags
406+
; %0 <u 2 --> %0 <=u 1
407+
$bl = SETCCr 2, implicit $eflags
408+
...
409+
---
410+
name: opt_redundant_flags_adjusted_imm_1
411+
body: |
412+
bb.0:
413+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_1
414+
; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
415+
; CHECK-NEXT: CMP64ri8 [[COPY]], 42, implicit-def $eflags
416+
; CHECK-NEXT: $cl = SETCCr 5, implicit $eflags
417+
; CHECK-NEXT: $bl = SETCCr 13, implicit $eflags
418+
; CHECK-NEXT: $bl = SETCCr 3, implicit $eflags
419+
; CHECK-NEXT: $bl = SETCCr 12, implicit $eflags
420+
; CHECK-NEXT: $bl = SETCCr 2, implicit $eflags
421+
%0:gr64 = COPY $rsi
422+
; CMP+SETCC %0 != 42
423+
CMP64ri8 %0, 42, implicit-def $eflags
424+
$cl = SETCCr 5, implicit $eflags
425+
; CMP+SETCC %0 >= 2; CMP can be removed.
426+
CMP64ri8 %0, 41, implicit-def $eflags
427+
; %0 >s 41 --> %0 >=s 42
428+
$bl = SETCCr 15, implicit $eflags
429+
; %0 >u 41 --> %0 >=u 42
430+
$bl = SETCCr 7, implicit $eflags
431+
; %0 <=s 41 --> %0 <s 42
432+
$bl = SETCCr 14, implicit $eflags
433+
; %0 <=u 41 --> %0 <u 42
434+
$bl = SETCCr 6, implicit $eflags
435+
...
436+
---
437+
name: opt_redundant_flags_adjusted_imm_test_cmp
438+
body: |
439+
bb.0:
440+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_test_cmp
441+
; CHECK: [[COPY:%[0-9]+]]:gr8 = COPY $bl
442+
; CHECK-NEXT: TEST8rr [[COPY]], [[COPY]], implicit-def $eflags
443+
; CHECK-NEXT: $cl = SETCCr 14, implicit $eflags
444+
; CHECK-NEXT: $cl = SETCCr 7, implicit $eflags
445+
; CHECK-NEXT: $cl = SETCCr 12, implicit $eflags
446+
%0:gr8 = COPY $bl
447+
TEST8rr %0, %0, implicit-def $eflags
448+
; SET %0 <=s 0
449+
$cl = SETCCr 14, implicit $eflags
450+
; CMP should be removed (%0 >=u 1)
451+
CMP8ri %0, 1, implicit-def $eflags
452+
$cl = SETCCr 3, implicit $eflags
453+
454+
; CMP should be removed (%0 <=s -1)
455+
CMP8ri %0, -1, implicit-def $eflags
456+
$cl = SETCCr 14, implicit $eflags
457+
...
458+
---
459+
name: opt_redundant_flags_adjusted_imm_cmp_test
460+
body: |
461+
bb.0:
462+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_cmp_test
463+
; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
464+
; CHECK-NEXT: CMP64ri32 [[COPY]], 1, implicit-def $eflags
465+
; CHECK-NEXT: $cl = SETCCr 13, implicit $eflags
466+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr64 = COPY $edi
467+
; CHECK-NEXT: CMP64ri32 [[COPY1]], -1, implicit-def $eflags
468+
; CHECK-NEXT: $cl = SETCCr 14, implicit $eflags
469+
%0:gr64 = COPY $rsi
470+
CMP64ri32 %0, 1, implicit-def $eflags
471+
; TEST should be removed
472+
TEST64rr %0, %0, implicit-def $eflags
473+
$cl = SETCCr 15, implicit $eflags
474+
475+
%1:gr64 = COPY $edi
476+
CMP64ri32 %1, -1, implicit-def $eflags
477+
; TEST should be removed
478+
TEST64rr %1, %1, implicit-def $eflags
479+
$cl = SETCCr 12, implicit $eflags
480+
...
481+
---
482+
name: opt_redundant_flags_adjusted_imm_noopt_0
483+
body: |
484+
bb.0:
485+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_noopt_0
486+
; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
487+
; CHECK-NEXT: CMP64ri8 [[COPY]], 42, implicit-def $eflags
488+
; CHECK-NEXT: $cl = SETCCr 4, implicit $eflags
489+
; CHECK-NEXT: CMP64ri8 [[COPY]], 41, implicit-def $eflags
490+
; CHECK-NEXT: $bl = SETCCr 4, implicit $eflags
491+
%0:gr64 = COPY $rsi
492+
; CMP+SETCC %0 <s 1
493+
CMP64ri8 %0, 42, implicit-def $eflags
494+
$cl = SETCCr 4, implicit $eflags
495+
; CMP should not be removed.
496+
CMP64ri8 %0, 41, implicit-def $eflags
497+
; %0 == 41
498+
$bl = SETCCr 4, implicit $eflags
499+
...
500+
---
501+
name: opt_redundant_flags_adjusted_imm_noopt_1
502+
body: |
503+
bb.0:
504+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_noopt_1
505+
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $esi
506+
; CHECK-NEXT: CMP32ri [[COPY]], 2147483647, implicit-def $eflags
507+
; CHECK-NEXT: CMP32ri [[COPY]], -2147483648, implicit-def $eflags
508+
; CHECK-NEXT: $bl = SETCCr 12, implicit $eflags
509+
; CHECK-NEXT: CMP32ri [[COPY]], 4294967295, implicit-def $eflags
510+
; CHECK-NEXT: CMP32ri [[COPY]], -2147483648, implicit-def $eflags
511+
; CHECK-NEXT: $bl = SETCCr 12, implicit $eflags
512+
; CHECK-NEXT: CMP32ri [[COPY]], 2147483647, implicit-def $eflags
513+
; CHECK-NEXT: CMP32ri [[COPY]], -2147483648, implicit-def $eflags
514+
; CHECK-NEXT: $bl = SETCCr 13, implicit $eflags
515+
; CHECK-NEXT: CMP32ri [[COPY]], 4294967295, implicit-def $eflags
516+
; CHECK-NEXT: CMP32ri [[COPY]], 0, implicit-def $eflags
517+
; CHECK-NEXT: $bl = SETCCr 2, implicit $eflags
518+
; CHECK-NEXT: CMP32ri [[COPY]], 4294967295, implicit-def $eflags
519+
; CHECK-NEXT: CMP32ri [[COPY]], 0, implicit-def $eflags
520+
; CHECK-NEXT: $bl = SETCCr 3, implicit $eflags
521+
%0:gr32 = COPY $esi
522+
; CMP+SETCC %0 == INT32_MAX
523+
CMP32ri %0, 2147483647, implicit-def $eflags
524+
; CMP should not be removed.
525+
CMP32ri %0, -2147483648, implicit-def $eflags
526+
; %0 <s INT32_MIN
527+
$bl = SETCCr 12, implicit $eflags
528+
529+
CMP32ri %0, 4294967295, implicit-def $eflags
530+
; CMP should not be removed.
531+
CMP32ri %0, -2147483648, implicit-def $eflags
532+
$bl = SETCCr 12, implicit $eflags
533+
534+
CMP32ri %0, 2147483647, implicit-def $eflags
535+
; CMP should not be removed.
536+
CMP32ri %0, -2147483648, implicit-def $eflags
537+
$bl = SETCCr 13, implicit $eflags
538+
539+
CMP32ri %0, 4294967295, implicit-def $eflags
540+
; should not be removed
541+
CMP32ri %0, 0, implicit-def $eflags
542+
$bl = SETCCr 2, implicit $eflags
543+
544+
CMP32ri %0, 4294967295, implicit-def $eflags
545+
; should not be removed
546+
CMP32ri %0, 0, implicit-def $eflags
547+
$bl = SETCCr 3, implicit $eflags
548+
...
549+
---
550+
name: opt_redundant_flags_adjusted_imm_noopt_2
551+
body: |
552+
bb.0:
553+
; CHECK-LABEL: name: opt_redundant_flags_adjusted_imm_noopt_2
554+
; CHECK: [[COPY:%[0-9]+]]:gr16 = COPY $cx
555+
; CHECK-NEXT: CMP16ri [[COPY]], -32768, implicit-def $eflags
556+
; CHECK-NEXT: CMP16ri [[COPY]], 32767, implicit-def $eflags
557+
; CHECK-NEXT: $bl = SETCCr 15, implicit $eflags
558+
; CHECK-NEXT: CMP16ri [[COPY]], 65535, implicit-def $eflags
559+
; CHECK-NEXT: CMP16ri [[COPY]], 32767, implicit-def $eflags
560+
; CHECK-NEXT: $bl = SETCCr 15, implicit $eflags
561+
; CHECK-NEXT: CMP16ri [[COPY]], -32768, implicit-def $eflags
562+
; CHECK-NEXT: CMP16ri [[COPY]], 32767, implicit-def $eflags
563+
; CHECK-NEXT: $bl = SETCCr 14, implicit $eflags
564+
; CHECK-NEXT: CMP16ri [[COPY]], 0, implicit-def $eflags
565+
; CHECK-NEXT: CMP16ri [[COPY]], 65535, implicit-def $eflags
566+
; CHECK-NEXT: $bl = SETCCr 4, implicit $eflags
567+
; CHECK-NEXT: CMP16ri [[COPY]], 0, implicit-def $eflags
568+
; CHECK-NEXT: CMP16ri [[COPY]], 65535, implicit-def $eflags
569+
; CHECK-NEXT: $bl = SETCCr 6, implicit $eflags
570+
%0:gr16 = COPY $cx
571+
; CMP+SETCC %0 == INT16_MIN
572+
CMP16ri %0, -32768, implicit-def $eflags
573+
; CMP should not be removed.
574+
CMP16ri %0, 32767, implicit-def $eflags
575+
; %0 >s INT16_MAX
576+
$bl = SETCCr 15, implicit $eflags
577+
578+
CMP16ri %0, 65535, implicit-def $eflags
579+
; CMP should not be removed.
580+
CMP16ri %0, 32767, implicit-def $eflags
581+
$bl = SETCCr 15, implicit $eflags
582+
583+
CMP16ri %0, -32768, implicit-def $eflags
584+
; CMP should not be removed.
585+
CMP16ri %0, 32767, implicit-def $eflags
586+
$bl = SETCCr 14, implicit $eflags
587+
588+
CMP16ri %0, 0, implicit-def $eflags
589+
; should not be removed
590+
CMP16ri %0, 65535, implicit-def $eflags
591+
$bl = SETCCr 4, implicit $eflags
592+
593+
CMP16ri %0, 0, implicit-def $eflags
594+
; should not be removed
595+
CMP16ri %0, 65535, implicit-def $eflags
596+
$bl = SETCCr 6, implicit $eflags
597+
...

0 commit comments

Comments
 (0)