Skip to content

Commit 4b62afc

Browse files
authored
[X86][CodeGen] Support flags copy lowering for CCMP/CTEST (llvm#91849)
``` %1:gr64 = COPY $eflags OP1 may update eflags $eflags = COPY %1 OP2 may use eflags ``` To use eflags as input at 4th instruction, we need to use SETcc to preserve the eflags before 2, and update the source condition of OP2 according to value in GPR %1. In this patch, we support CCMP/CTEST as OP2.
1 parent 778826f commit 4b62afc

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

llvm/lib/Target/X86/X86FlagsCopyLowering.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ class X86FlagsCopyLoweringPass : public MachineFunctionPass {
124124
MachineBasicBlock::iterator TestPos,
125125
const DebugLoc &TestLoc, MachineInstr &SetCCI,
126126
MachineOperand &FlagUse, CondRegArray &CondRegs);
127+
void rewriteCCMP(MachineBasicBlock &TestMBB,
128+
MachineBasicBlock::iterator TestPos, const DebugLoc &TestLoc,
129+
MachineInstr &CMovI, MachineOperand &FlagUse,
130+
CondRegArray &CondRegs);
127131
};
128132

129133
} // end anonymous namespace
@@ -613,6 +617,9 @@ bool X86FlagsCopyLoweringPass::runOnMachineFunction(MachineFunction &MF) {
613617
rewriteFCMov(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
614618
} else if (X86::getCondFromSETCC(MI) != X86::COND_INVALID) {
615619
rewriteSetCC(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
620+
} else if (X86::getCondFromCCMP(MI) != X86::COND_INVALID) {
621+
rewriteCCMP(*TestMBB, TestPos, TestLoc, MI, *FlagUse, CondRegs);
622+
FlagsKilled = true;
616623
} else if (MI.getOpcode() == TargetOpcode::COPY) {
617624
rewriteCopy(MI, *FlagUse, CopyDefI);
618625
} else {
@@ -970,3 +977,29 @@ void X86FlagsCopyLoweringPass::rewriteSetCC(MachineBasicBlock &TestMBB,
970977

971978
SetCCI.eraseFromParent();
972979
}
980+
981+
void X86FlagsCopyLoweringPass::rewriteCCMP(MachineBasicBlock &TestMBB,
982+
MachineBasicBlock::iterator TestPos,
983+
const DebugLoc &TestLoc,
984+
MachineInstr &CCMPI,
985+
MachineOperand &FlagUse,
986+
CondRegArray &CondRegs) {
987+
// First get the register containing this specific condition.
988+
X86::CondCode Cond = X86::getCondFromCCMP(CCMPI);
989+
unsigned CondReg;
990+
bool Inverted;
991+
std::tie(CondReg, Inverted) =
992+
getCondOrInverseInReg(TestMBB, TestPos, TestLoc, Cond, CondRegs);
993+
994+
MachineBasicBlock &MBB = *CCMPI.getParent();
995+
996+
// Insert a direct test of the saved register.
997+
insertTest(MBB, CCMPI.getIterator(), CCMPI.getDebugLoc(), CondReg);
998+
999+
// Rewrite the CCMP/CTEST to use the !ZF flag from the test, and then kill its
1000+
// use of the flags afterward.
1001+
CCMPI.getOperand(CCMPI.getDesc().getNumOperands() - 1)
1002+
.setImm(Inverted ? X86::COND_E : X86::COND_NE);
1003+
FlagUse.setIsKill(true);
1004+
LLVM_DEBUG(dbgs() << " fixed ccmp/ctest: "; CCMPI.dump());
1005+
}

llvm/lib/Target/X86/X86InstrInfo.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3121,7 +3121,8 @@ bool X86InstrInfo::hasCommutePreference(MachineInstr &MI, bool &Commute) const {
31213121
int X86::getCondSrcNoFromDesc(const MCInstrDesc &MCID) {
31223122
unsigned Opcode = MCID.getOpcode();
31233123
if (!(X86::isJCC(Opcode) || X86::isSETCC(Opcode) || X86::isCMOVCC(Opcode) ||
3124-
X86::isCFCMOVCC(Opcode)))
3124+
X86::isCFCMOVCC(Opcode) || X86::isCCMPCC(Opcode) ||
3125+
X86::isCTESTCC(Opcode)))
31253126
return -1;
31263127
// Assume that condition code is always the last use operand.
31273128
unsigned NumUses = MCID.getNumOperands() - MCID.getNumDefs();
@@ -3157,6 +3158,12 @@ X86::CondCode X86::getCondFromCFCMov(const MachineInstr &MI) {
31573158
: X86::COND_INVALID;
31583159
}
31593160

3161+
X86::CondCode X86::getCondFromCCMP(const MachineInstr &MI) {
3162+
return X86::isCCMPCC(MI.getOpcode()) || X86::isCTESTCC(MI.getOpcode())
3163+
? X86::getCondFromMI(MI)
3164+
: X86::COND_INVALID;
3165+
}
3166+
31603167
/// Return the inverse of the specified condition,
31613168
/// e.g. turning COND_E to COND_NE.
31623169
X86::CondCode X86::GetOppositeBranchCondition(X86::CondCode CC) {

llvm/lib/Target/X86/X86InstrInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ CondCode getCondFromCMov(const MachineInstr &MI);
7171
// Turn CFCMOV instruction into condition code.
7272
CondCode getCondFromCFCMov(const MachineInstr &MI);
7373

74+
// Turn CCMP instruction into condition code.
75+
CondCode getCondFromCCMP(const MachineInstr &MI);
76+
7477
/// GetOppositeBranchCondition - Return the inverse of the specified cond,
7578
/// e.g. turning COND_E to COND_NE.
7679
CondCode GetOppositeBranchCondition(CondCode CC);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
2+
# RUN: llc -mtriple=x86_64 -run-pass x86-flags-copy-lowering -verify-machineinstrs -o - %s | FileCheck %s
3+
# Lower various interesting copy patterns of EFLAGS without using LAHF/SAHF.
4+
5+
...
6+
---
7+
name: test_ccmp
8+
body: |
9+
bb.0:
10+
liveins: $edi
11+
12+
; CHECK-LABEL: name: test_ccmp
13+
; CHECK: liveins: $edi
14+
; CHECK-NEXT: {{ $}}
15+
; CHECK-NEXT: MUL32r $edi, implicit-def $eax, implicit-def dead $edx, implicit-def $eflags, implicit $eax
16+
; CHECK-NEXT: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 1, implicit $eflags
17+
; CHECK-NEXT: [[ADD32rr:%[0-9]+]]:gr32 = ADD32rr $edi, $edi, implicit-def $eflags
18+
; CHECK-NEXT: TEST8rr [[SETCCr]], [[SETCCr]], implicit-def $eflags
19+
; CHECK-NEXT: CCMP32rr [[ADD32rr]], [[ADD32rr]], 0, 5, implicit-def $eflags, implicit killed $eflags
20+
; CHECK-NEXT: RET 0, $al
21+
MUL32r $edi, implicit-def $eax, implicit-def dead $edx, implicit-def $eflags, implicit $eax
22+
%1:gr64 = COPY $eflags
23+
%2:gr32 = ADD32rr $edi, $edi, implicit-def $eflags
24+
$eflags = COPY %1
25+
CCMP32rr %2, %2, 0, 1, implicit-def $eflags, implicit $eflags
26+
RET 0, $al
27+
28+
...
29+
---
30+
name: test_ctest
31+
body: |
32+
bb.0:
33+
liveins: $edi
34+
35+
; CHECK-LABEL: name: test_ctest
36+
; CHECK: liveins: $edi
37+
; CHECK-NEXT: {{ $}}
38+
; CHECK-NEXT: MUL32r $edi, implicit-def $eax, implicit-def dead $edx, implicit-def $eflags, implicit $eax
39+
; CHECK-NEXT: [[SETCCr:%[0-9]+]]:gr8 = SETCCr 1, implicit $eflags
40+
; CHECK-NEXT: [[ADD32rr:%[0-9]+]]:gr32 = ADD32rr $edi, $edi, implicit-def $eflags
41+
; CHECK-NEXT: TEST8rr [[SETCCr]], [[SETCCr]], implicit-def $eflags
42+
; CHECK-NEXT: CTEST32rr [[ADD32rr]], [[ADD32rr]], 0, 5, implicit-def $eflags, implicit killed $eflags
43+
; CHECK-NEXT: RET 0, $al
44+
MUL32r $edi, implicit-def $eax, implicit-def dead $edx, implicit-def $eflags, implicit $eax
45+
%1:gr64 = COPY $eflags
46+
%2:gr32 = ADD32rr $edi, $edi, implicit-def $eflags
47+
$eflags = COPY %1
48+
CTEST32rr %2, %2, 0, 1, implicit-def $eflags, implicit $eflags
49+
RET 0, $al
50+
51+
...

0 commit comments

Comments
 (0)