Skip to content

Commit e6f868c

Browse files
koachandoac
andauthored
[Sparc] Optimize compare instruction (#167140)
If we need to compare the result of a computation with 0, we can sometimes replace the last instruction in the computation with one that sets the integer condition codes. We can then branch immediately based on the zero-flag instead of having to use an extra compare instruction (a SUBcc instruction). This is only possible if the result of the compare is not used anywhere else and that no other instruction modifies the integer condition codes between the time the result of the computation is defined and the time it is used. --------- Co-authored-by: Daniel Cederman <[email protected]>
1 parent 39774f9 commit e6f868c

File tree

10 files changed

+411
-26
lines changed

10 files changed

+411
-26
lines changed

llvm/lib/Target/Sparc/SparcInstrInfo.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,145 @@ unsigned SparcInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
641641
return get(Opcode).getSize();
642642
}
643643

644+
bool SparcInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
645+
Register &SrcReg2, int64_t &CmpMask,
646+
int64_t &CmpValue) const {
647+
Register DstReg;
648+
switch (MI.getOpcode()) {
649+
default:
650+
break;
651+
case SP::SUBCCri:
652+
DstReg = MI.getOperand(0).getReg();
653+
SrcReg = MI.getOperand(1).getReg();
654+
SrcReg2 = 0;
655+
CmpMask = ~0;
656+
CmpValue = MI.getOperand(2).getImm();
657+
return DstReg == SP::G0 && CmpValue == 0;
658+
case SP::SUBCCrr:
659+
DstReg = MI.getOperand(0).getReg();
660+
SrcReg = MI.getOperand(1).getReg();
661+
SrcReg2 = MI.getOperand(2).getReg();
662+
CmpMask = ~0;
663+
CmpValue = 0;
664+
return DstReg == SP::G0 && SrcReg2 == SP::G0;
665+
}
666+
667+
return false;
668+
}
669+
670+
bool SparcInstrInfo::optimizeCompareInstr(
671+
MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int64_t CmpMask,
672+
int64_t CmpValue, const MachineRegisterInfo *MRI) const {
673+
674+
// Get the unique definition of SrcReg.
675+
MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
676+
if (!MI)
677+
return false;
678+
679+
// Only optimize if defining and comparing instruction in same block.
680+
if (MI->getParent() != CmpInstr.getParent())
681+
return false;
682+
683+
unsigned NewOpcode;
684+
switch (MI->getOpcode()) {
685+
case SP::ANDNrr:
686+
NewOpcode = SP::ANDNCCrr;
687+
break;
688+
case SP::ANDNri:
689+
NewOpcode = SP::ANDNCCri;
690+
break;
691+
case SP::ANDrr:
692+
NewOpcode = SP::ANDCCrr;
693+
break;
694+
case SP::ANDri:
695+
NewOpcode = SP::ANDCCri;
696+
break;
697+
case SP::ORrr:
698+
NewOpcode = SP::ORCCrr;
699+
break;
700+
case SP::ORri:
701+
NewOpcode = SP::ORCCri;
702+
break;
703+
case SP::ORNCCrr:
704+
NewOpcode = SP::ORNCCrr;
705+
break;
706+
case SP::ORNri:
707+
NewOpcode = SP::ORNCCri;
708+
break;
709+
case SP::XORrr:
710+
NewOpcode = SP::XORCCrr;
711+
break;
712+
case SP::XNORri:
713+
NewOpcode = SP::XNORCCri;
714+
break;
715+
case SP::XNORrr:
716+
NewOpcode = SP::XNORCCrr;
717+
break;
718+
case SP::ADDrr:
719+
NewOpcode = SP::ADDCCrr;
720+
break;
721+
case SP::ADDri:
722+
NewOpcode = SP::ADDCCri;
723+
break;
724+
case SP::SUBrr:
725+
NewOpcode = SP::SUBCCrr;
726+
break;
727+
case SP::SUBri:
728+
NewOpcode = SP::SUBCCri;
729+
break;
730+
default:
731+
return false;
732+
}
733+
734+
bool IsICCModified = false;
735+
MachineBasicBlock::iterator I = MI;
736+
MachineBasicBlock::iterator C = CmpInstr;
737+
MachineBasicBlock::iterator E = CmpInstr.getParent()->end();
738+
const TargetRegisterInfo *TRI = &getRegisterInfo();
739+
740+
// If ICC is used or modified between MI and CmpInstr we cannot optimize.
741+
while (++I != C) {
742+
if (I->modifiesRegister(SP::ICC, TRI) || I->readsRegister(SP::ICC, TRI))
743+
return false;
744+
}
745+
746+
while (++I != E) {
747+
// Only allow conditionals on equality.
748+
if (I->readsRegister(SP::ICC, TRI)) {
749+
bool IsICCBranch = I->getOpcode() == SP::BCOND ||
750+
I->getOpcode() == SP::BPICC ||
751+
I->getOpcode() == SP::BPXCC;
752+
bool IsICCMove =
753+
I->getOpcode() == SP::MOVICCrr || I->getOpcode() == SP::MOVICCri ||
754+
I->getOpcode() == SP::MOVXCCrr || I->getOpcode() == SP::MOVXCCri;
755+
bool IsICCConditional = IsICCBranch || IsICCMove;
756+
if (!IsICCConditional ||
757+
(I->getOperand(IsICCBranch ? 1 : 3).getImm() != SPCC::ICC_E &&
758+
I->getOperand(IsICCBranch ? 1 : 3).getImm() != SPCC::ICC_NE))
759+
return false;
760+
} else if (I->modifiesRegister(SP::ICC, TRI)) {
761+
IsICCModified = true;
762+
break;
763+
}
764+
}
765+
766+
if (!IsICCModified) {
767+
MachineBasicBlock *MBB = CmpInstr.getParent();
768+
if (any_of(MBB->successors(),
769+
[](MachineBasicBlock *Succ) { return Succ->isLiveIn(SP::ICC); }))
770+
return false;
771+
}
772+
773+
if (MRI->hasOneNonDBGUse(SrcReg))
774+
MI->getOperand(0).setReg(SP::G0);
775+
776+
MI->setDesc(get(NewOpcode));
777+
MI->addRegisterDefined(SP::ICC);
778+
CmpInstr.eraseFromParent();
779+
780+
return true;
781+
}
782+
644783
bool SparcInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
645784
switch (MI.getOpcode()) {
646785
case TargetOpcode::LOAD_STACK_GUARD: {

llvm/lib/Target/Sparc/SparcInstrInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ class SparcInstrInfo : public SparcGenInstrInfo {
107107
/// instruction may be. This returns the maximum number of bytes.
108108
unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
109109

110+
bool analyzeCompare(const MachineInstr &MI, Register &SrcReg,
111+
Register &SrcReg2, int64_t &CmpMask,
112+
int64_t &CmpValue) const override;
113+
114+
bool optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
115+
Register SrcReg2, int64_t CmpMask, int64_t CmpValue,
116+
const MachineRegisterInfo *MRI) const override;
117+
110118
// Lower pseudo instructions after register allocation.
111119
bool expandPostRAPseudo(MachineInstr &MI) const override;
112120
};

llvm/lib/Target/Sparc/SparcInstrInfo.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, simm13Op>;
908908
let Uses = [ICC], Defs = [ICC] in
909909
defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, simm13Op>;
910910

911-
let Defs = [ICC], hasPostISelHook = true in
911+
let Defs = [ICC], hasPostISelHook = true, isCompare = 1 in
912912
defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, simm13Op>;
913913

914914
let Uses = [ICC] in

llvm/test/CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,15 @@ define i64 @atomicrmw_udec_wrap_i64(ptr %ptr, i64 %val) {
292292
; CHECK-NEXT: mov %g0, %l0
293293
; CHECK-NEXT: addcc %g3, -1, %o3
294294
; CHECK-NEXT: addxcc %g2, -1, %o2
295-
; CHECK-NEXT: or %g3, %g2, %l1
296-
; CHECK-NEXT: cmp %l1, 0
295+
; CHECK-NEXT: orcc %g3, %g2, %g0
297296
; CHECK-NEXT: move %icc, 1, %i5
298297
; CHECK-NEXT: cmp %g2, %i1
299298
; CHECK-NEXT: movgu %icc, 1, %g4
300299
; CHECK-NEXT: cmp %g3, %i2
301300
; CHECK-NEXT: movgu %icc, 1, %l0
302301
; CHECK-NEXT: cmp %g2, %i1
303302
; CHECK-NEXT: move %icc, %l0, %g4
304-
; CHECK-NEXT: or %i5, %g4, %i5
305-
; CHECK-NEXT: cmp %i5, 0
303+
; CHECK-NEXT: orcc %i5, %g4, %g0
306304
; CHECK-NEXT: movne %icc, %i1, %o2
307305
; CHECK-NEXT: movne %icc, %i2, %o3
308306
; CHECK-NEXT: std %g2, [%fp+-8]

llvm/test/CodeGen/SPARC/ctlz.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ define i64 @i64_nopoison(i64 %x) nounwind {
156156
; SPARC-LABEL: i64_nopoison:
157157
; SPARC: ! %bb.0:
158158
; SPARC-NEXT: save %sp, -96, %sp
159-
; SPARC-NEXT: or %i1, %i0, %i2
160-
; SPARC-NEXT: cmp %i2, 0
159+
; SPARC-NEXT: orcc %i1, %i0, %g0
161160
; SPARC-NEXT: be .LBB2_4
162161
; SPARC-NEXT: nop
163162
; SPARC-NEXT: ! %bb.1: ! %cond.false
@@ -182,8 +181,7 @@ define i64 @i64_nopoison(i64 %x) nounwind {
182181
; SPARC-POPC-LABEL: i64_nopoison:
183182
; SPARC-POPC: ! %bb.0:
184183
; SPARC-POPC-NEXT: save %sp, -96, %sp
185-
; SPARC-POPC-NEXT: or %i1, %i0, %i2
186-
; SPARC-POPC-NEXT: cmp %i2, 0
184+
; SPARC-POPC-NEXT: orcc %i1, %i0, %g0
187185
; SPARC-POPC-NEXT: be .LBB2_4
188186
; SPARC-POPC-NEXT: nop
189187
; SPARC-POPC-NEXT: ! %bb.1: ! %cond.false

llvm/test/CodeGen/SPARC/cttz.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,7 @@ define i32 @i32_poison(i32 %x) nounwind {
184184
define i64 @i64_nopoison(i64 %x) nounwind {
185185
; SPARC-LABEL: i64_nopoison:
186186
; SPARC: ! %bb.0:
187-
; SPARC-NEXT: or %o1, %o0, %o2
188-
; SPARC-NEXT: cmp %o2, 0
187+
; SPARC-NEXT: orcc %o1, %o0, %g0
189188
; SPARC-NEXT: be .LBB2_3
190189
; SPARC-NEXT: nop
191190
; SPARC-NEXT: ! %bb.1: ! %cond.false
@@ -219,8 +218,7 @@ define i64 @i64_nopoison(i64 %x) nounwind {
219218
;
220219
; SPARC-POPC-LABEL: i64_nopoison:
221220
; SPARC-POPC: ! %bb.0:
222-
; SPARC-POPC-NEXT: or %o1, %o0, %o2
223-
; SPARC-POPC-NEXT: cmp %o2, 0
221+
; SPARC-POPC-NEXT: orcc %o1, %o0, %g0
224222
; SPARC-POPC-NEXT: be .LBB2_3
225223
; SPARC-POPC-NEXT: nop
226224
; SPARC-POPC-NEXT: ! %bb.1: ! %cond.false

llvm/test/CodeGen/SPARC/fp128-select.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ define fp128 @f128_select_soft(fp128 %a, fp128 %b) #0 {
2222
; V9-NEXT: sllx %o3, 32, %o3
2323
; V9-NEXT: or %o3, %o2, %o2
2424
; V9-NEXT: xor %o1, %o2, %o1
25-
; V9-NEXT: or %o0, %o1, %o0
26-
; V9-NEXT: cmp %o0, 0
25+
; V9-NEXT: orcc %o0, %o1, %g0
2726
; V9-NEXT: bne %xcc, .LBB0_2
2827
; V9-NEXT: nop
2928
; V9-NEXT: ! %bb.1:

0 commit comments

Comments
 (0)