From 7e4dcb1cc3e96c54bf8eb452ce3e824cbc6d4a0f Mon Sep 17 00:00:00 2001 From: Daniel Cederman Date: Fri, 24 Aug 2018 10:32:04 +0200 Subject: [PATCH 1/2] [Sparc] Optimize compare instruction 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. --- llvm/lib/Target/Sparc/SparcInstrInfo.cpp | 143 ++++++++++ llvm/lib/Target/Sparc/SparcInstrInfo.h | 8 + llvm/lib/Target/Sparc/SparcInstrInfo.td | 13 +- llvm/test/CodeGen/SPARC/2011-01-11-CC.ll | 6 +- .../CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll | 6 +- llvm/test/CodeGen/SPARC/ctlz.ll | 6 +- llvm/test/CodeGen/SPARC/cttz.ll | 6 +- llvm/test/CodeGen/SPARC/optcompare.ll | 250 ++++++++++++++++++ .../SPARC/smulo-128-legalisation-lowering.ll | 3 +- .../SPARC/umulo-128-legalisation-lowering.ll | 16 +- 10 files changed, 428 insertions(+), 29 deletions(-) create mode 100644 llvm/test/CodeGen/SPARC/optcompare.ll diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp index f66eb9dbee2dc..b2d6aa18732bc 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -640,6 +640,149 @@ unsigned SparcInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { return get(Opcode).getSize(); } +bool SparcInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg, + Register &SrcReg2, int64_t &CmpMask, + int64_t &CmpValue) const { + switch (MI.getOpcode()) { + default: + break; + case SP::CMPri: + SrcReg = MI.getOperand(0).getReg(); + SrcReg2 = 0; + CmpMask = ~0; + CmpValue = MI.getOperand(1).getImm(); + return (CmpValue == 0); + case SP::CMPrr: + SrcReg = MI.getOperand(0).getReg(); + SrcReg2 = MI.getOperand(1).getReg(); + CmpMask = ~0; + CmpValue = 0; + return SrcReg2 == SP::G0; + } + + return false; +} + +bool SparcInstrInfo::optimizeCompareInstr( + MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int64_t CmpMask, + int64_t CmpValue, const MachineRegisterInfo *MRI) const { + + // Get the unique definition of SrcReg. + MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg); + if (!MI) + return false; + + // Only optimize if defining and comparing instruction in same block. + if (MI->getParent() != CmpInstr.getParent()) + return false; + + unsigned newOpcode; + switch (MI->getOpcode()) { + case SP::ANDNrr: + newOpcode = SP::ANDNCCrr; + break; + case SP::ANDNri: + newOpcode = SP::ANDNCCri; + break; + case SP::ANDrr: + newOpcode = SP::ANDCCrr; + break; + case SP::ANDri: + newOpcode = SP::ANDCCri; + break; + case SP::ORrr: + newOpcode = SP::ORCCrr; + break; + case SP::ORri: + newOpcode = SP::ORCCri; + break; + case SP::ORNCCrr: + newOpcode = SP::ORNCCrr; + break; + case SP::ORNri: + newOpcode = SP::ORNCCri; + break; + case SP::XORrr: + newOpcode = SP::XORCCrr; + break; + case SP::XNORri: + newOpcode = SP::XNORCCri; + break; + case SP::XNORrr: + newOpcode = SP::XNORCCrr; + break; + case SP::ADDrr: + newOpcode = SP::ADDCCrr; + break; + case SP::ADDri: + newOpcode = SP::ADDCCri; + break; + case SP::SUBrr: + newOpcode = SP::SUBCCrr; + break; + case SP::SUBri: + newOpcode = SP::SUBCCri; + break; + default: + return false; + } + + bool isSafe = false; + bool isRegUsed = false; + MachineBasicBlock::iterator I = MI; + MachineBasicBlock::iterator C = CmpInstr; + MachineBasicBlock::iterator E = CmpInstr.getParent()->end(); + const TargetRegisterInfo *TRI = &getRegisterInfo(); + + // If ICC is used or modified between MI and CmpInstr we cannot optimize. + while (++I != C) { + if (I->modifiesRegister(SP::ICC, TRI) || I->readsRegister(SP::ICC, TRI)) + return false; + if (I->readsRegister(SrcReg, TRI)) + isRegUsed = true; + } + + while (++I != E) { + // Only allow conditionals on equality. + if (I->readsRegister(SP::ICC, TRI)) { + bool IsICCBranch = (I->getOpcode() == SP::BCOND) || + (I->getOpcode() == SP::BPICC) || + (I->getOpcode() == SP::BPXCC); + bool IsICCMove = (I->getOpcode() == SP::MOVICCrr) || + (I->getOpcode() == SP::MOVICCri) || + (I->getOpcode() == SP::MOVXCCrr) || + (I->getOpcode() == SP::MOVXCCri); + bool IsICCConditional = IsICCBranch || IsICCMove; + if (!IsICCConditional || + (I->getOperand(IsICCBranch ? 1 : 3).getImm() != SPCC::ICC_E && + I->getOperand(IsICCBranch ? 1 : 3).getImm() != SPCC::ICC_NE)) + return false; + } else if (I->modifiesRegister(SP::ICC, TRI)) { + isSafe = true; + break; + } + } + + if (!isSafe) { + MachineBasicBlock *MBB = CmpInstr.getParent(); + for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); + SI != SE; ++SI) + if ((*SI)->isLiveIn(SP::ICC)) + return false; + } + + // If the result is not needed use the %g0 register. + if (!isRegUsed && CmpInstr.getOperand(0).isKill()) + MI->getOperand(0).setReg(SP::G0); + + MI->setDesc(get(newOpcode)); + MI->addRegisterDefined(SP::ICC); + CmpInstr.eraseFromParent(); + + return true; +} + bool SparcInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { switch (MI.getOpcode()) { case TargetOpcode::LOAD_STACK_GUARD: { diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.h b/llvm/lib/Target/Sparc/SparcInstrInfo.h index 01d0204734943..dd0f9c7efebd4 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.h +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.h @@ -108,6 +108,14 @@ class SparcInstrInfo : public SparcGenInstrInfo { /// instruction may be. This returns the maximum number of bytes. unsigned getInstSizeInBytes(const MachineInstr &MI) const override; + bool analyzeCompare(const MachineInstr &MI, Register &SrcReg, + Register &SrcReg2, int64_t &CmpMask, + int64_t &CmpValue) const override; + + bool optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg, + Register SrcReg2, int64_t CmpMask, int64_t CmpValue, + const MachineRegisterInfo *MRI) const override; + // Lower pseudo instructions after register allocation. bool expandPostRAPseudo(MachineInstr &MI) const override; }; diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td index bc192c2d5f523..233dea63b80e6 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -914,8 +914,17 @@ let Defs = [ICC], hasPostISelHook = true in let Uses = [ICC] in defm SUBC : F3_12np <"subx", 0b001100>; -def : Pat<(SPcmpicc i32:$lhs, i32:$rhs), (SUBCCrr $lhs, $rhs)>; -def : Pat<(SPcmpicc i32:$lhs, (i32 simm13:$rhs)), (SUBCCri $lhs, imm:$rhs)>; +// cmp (from Section A.3) is a specialized alias for subcc +let Defs = [ICC], rd = 0, isCompare = 1 in { + def CMPrr : F3_1<2, 0b010100, + (outs), (ins IntRegs:$rs1, IntRegs:$rs2), + "cmp $rs1, $rs2", + [(SPcmpicc i32:$rs1, i32:$rs2)]>; + def CMPri : F3_2<2, 0b010100, + (outs), (ins IntRegs:$rs1, simm13Op:$simm13), + "cmp $rs1, $simm13", + [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>; +} // Section B.18 - Multiply Instructions, p. 113 let Defs = [Y] in { diff --git a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll index e05c47bfee766..9dffe0a3ce456 100644 --- a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll +++ b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll @@ -25,15 +25,13 @@ define i32 @test_addx(i64 %a, i64 %b, i64 %c) nounwind { ; V8-NEXT: retl ; V8-NEXT: nop ; V8-NEXT: .LBB0_4: ! %entry -; V8-NEXT: mov %g0, %o2 ; V8-NEXT: cmp %o3, %o5 ; V8-NEXT: bgu .LBB0_2 -; V8-NEXT: nop +; V8-NEXT: mov %g0, %o2 ; V8-NEXT: .LBB0_5: ! %entry -; V8-NEXT: mov %g0, %o0 ; V8-NEXT: cmp %o1, %o4 ; V8-NEXT: be .LBB0_3 -; V8-NEXT: nop +; V8-NEXT: mov %g0, %o0 ; V8-NEXT: .LBB0_6: ! %entry ; V8-NEXT: retl ; V8-NEXT: mov %o2, %o0 diff --git a/llvm/test/CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll b/llvm/test/CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll index d1f1c46d9b8b1..ac21cb2bf88de 100644 --- a/llvm/test/CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll +++ b/llvm/test/CodeGen/SPARC/atomicrmw-uinc-udec-wrap.ll @@ -292,8 +292,7 @@ define i64 @atomicrmw_udec_wrap_i64(ptr %ptr, i64 %val) { ; CHECK-NEXT: mov %g0, %l0 ; CHECK-NEXT: addcc %g3, -1, %o3 ; CHECK-NEXT: addxcc %g2, -1, %o2 -; CHECK-NEXT: or %g3, %g2, %l1 -; CHECK-NEXT: cmp %l1, 0 +; CHECK-NEXT: orcc %g3, %g2, %g0 ; CHECK-NEXT: move %icc, 1, %i5 ; CHECK-NEXT: cmp %g2, %i1 ; CHECK-NEXT: movgu %icc, 1, %g4 @@ -301,8 +300,7 @@ define i64 @atomicrmw_udec_wrap_i64(ptr %ptr, i64 %val) { ; CHECK-NEXT: movgu %icc, 1, %l0 ; CHECK-NEXT: cmp %g2, %i1 ; CHECK-NEXT: move %icc, %l0, %g4 -; CHECK-NEXT: or %i5, %g4, %i5 -; CHECK-NEXT: cmp %i5, 0 +; CHECK-NEXT: orcc %i5, %g4, %i5 ; CHECK-NEXT: movne %icc, %i1, %o2 ; CHECK-NEXT: movne %icc, %i2, %o3 ; CHECK-NEXT: std %g2, [%fp+-8] diff --git a/llvm/test/CodeGen/SPARC/ctlz.ll b/llvm/test/CodeGen/SPARC/ctlz.ll index f7dc309452b35..528b3c9a0b8e9 100644 --- a/llvm/test/CodeGen/SPARC/ctlz.ll +++ b/llvm/test/CodeGen/SPARC/ctlz.ll @@ -156,8 +156,7 @@ define i64 @i64_nopoison(i64 %x) nounwind { ; SPARC-LABEL: i64_nopoison: ; SPARC: ! %bb.0: ; SPARC-NEXT: save %sp, -96, %sp -; SPARC-NEXT: or %i1, %i0, %i2 -; SPARC-NEXT: cmp %i2, 0 +; SPARC-NEXT: orcc %i1, %i0, %g0 ; SPARC-NEXT: be .LBB2_4 ; SPARC-NEXT: nop ; SPARC-NEXT: ! %bb.1: ! %cond.false @@ -182,8 +181,7 @@ define i64 @i64_nopoison(i64 %x) nounwind { ; SPARC-POPC-LABEL: i64_nopoison: ; SPARC-POPC: ! %bb.0: ; SPARC-POPC-NEXT: save %sp, -96, %sp -; SPARC-POPC-NEXT: or %i1, %i0, %i2 -; SPARC-POPC-NEXT: cmp %i2, 0 +; SPARC-POPC-NEXT: orcc %i1, %i0, %g0 ; SPARC-POPC-NEXT: be .LBB2_4 ; SPARC-POPC-NEXT: nop ; SPARC-POPC-NEXT: ! %bb.1: ! %cond.false diff --git a/llvm/test/CodeGen/SPARC/cttz.ll b/llvm/test/CodeGen/SPARC/cttz.ll index 138f67dbf684a..49592fe4dac00 100644 --- a/llvm/test/CodeGen/SPARC/cttz.ll +++ b/llvm/test/CodeGen/SPARC/cttz.ll @@ -184,8 +184,7 @@ define i32 @i32_poison(i32 %x) nounwind { define i64 @i64_nopoison(i64 %x) nounwind { ; SPARC-LABEL: i64_nopoison: ; SPARC: ! %bb.0: -; SPARC-NEXT: or %o1, %o0, %o2 -; SPARC-NEXT: cmp %o2, 0 +; SPARC-NEXT: orcc %o1, %o0, %g0 ; SPARC-NEXT: be .LBB2_3 ; SPARC-NEXT: nop ; SPARC-NEXT: ! %bb.1: ! %cond.false @@ -219,8 +218,7 @@ define i64 @i64_nopoison(i64 %x) nounwind { ; ; SPARC-POPC-LABEL: i64_nopoison: ; SPARC-POPC: ! %bb.0: -; SPARC-POPC-NEXT: or %o1, %o0, %o2 -; SPARC-POPC-NEXT: cmp %o2, 0 +; SPARC-POPC-NEXT: orcc %o1, %o0, %g0 ; SPARC-POPC-NEXT: be .LBB2_3 ; SPARC-POPC-NEXT: nop ; SPARC-POPC-NEXT: ! %bb.1: ! %cond.false diff --git a/llvm/test/CodeGen/SPARC/optcompare.ll b/llvm/test/CodeGen/SPARC/optcompare.ll new file mode 100644 index 0000000000000..d05596da16f7e --- /dev/null +++ b/llvm/test/CodeGen/SPARC/optcompare.ll @@ -0,0 +1,250 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=sparc | FileCheck %s +; RUN: llc < %s -mtriple=sparcv9 | FileCheck %s -check-prefix=CHECK64 + +define i32 @test(i32 %a) #0 { +; CHECK-LABEL: test: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: andcc %o0, 1, %g0 +; CHECK-NEXT: bne .LBB0_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %if.end +; CHECK-NEXT: retl +; CHECK-NEXT: mov 2, %o0 +; CHECK-NEXT: .LBB0_2: ! %if.then +; CHECK-NEXT: retl +; CHECK-NEXT: mov 1, %o0 +; +; CHECK64-LABEL: test: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: andcc %o0, 1, %g0 +; CHECK64-NEXT: bne %icc, .LBB0_2 +; CHECK64-NEXT: nop +; CHECK64-NEXT: ! %bb.1: ! %if.end +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 2, %o0 +; CHECK64-NEXT: .LBB0_2: ! %if.then +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 1, %o0 +entry: + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: + ret i32 1 + +if.end: + ret i32 2 +} + +; Same as above, with select. +define i32 @test_select(i32 %a) #0 { +; CHECK-LABEL: test_select: +; CHECK: ! %bb.0: +; CHECK-NEXT: andcc %o0, 1, %g0 +; CHECK-NEXT: be .LBB1_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: +; CHECK-NEXT: retl +; CHECK-NEXT: mov 2, %o0 +; CHECK-NEXT: .LBB1_2: +; CHECK-NEXT: retl +; CHECK-NEXT: mov 1, %o0 +; +; CHECK64-LABEL: test_select: +; CHECK64: ! %bb.0: +; CHECK64-NEXT: andcc %o0, 1, %g0 +; CHECK64-NEXT: mov 2, %o0 +; CHECK64-NEXT: retl +; CHECK64-NEXT: move %icc, 1, %o0 + %and = and i32 %a, 1 + %tobool = icmp eq i32 %and, 0 + %ret = select i1 %tobool, i32 1, i32 2 + ret i32 %ret +} + + +; No instruction can be changed to set ICC +define i32 @no_candidate(i32 %a) #0 { +; CHECK-LABEL: no_candidate: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: cmp %o0, 0 +; CHECK-NEXT: be .LBB2_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %if.then +; CHECK-NEXT: retl +; CHECK-NEXT: mov 1, %o0 +; CHECK-NEXT: .LBB2_2: ! %if.end +; CHECK-NEXT: retl +; CHECK-NEXT: mov 2, %o0 +; +; CHECK64-LABEL: no_candidate: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: cmp %o0, 0 +; CHECK64-NEXT: be %icc, .LBB2_2 +; CHECK64-NEXT: nop +; CHECK64-NEXT: ! %bb.1: ! %if.then +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 1, %o0 +; CHECK64-NEXT: .LBB2_2: ! %if.end +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 2, %o0 +entry: + %tobool = icmp eq i32 %a, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: + ret i32 1 + +if.end: + ret i32 2 +} + +; Defining instruction and compare not in same block +define i32 @not_same_block(i32 %a) #0 { +; CHECK-LABEL: not_same_block: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: and %o0, 1, %o0 +; CHECK-NEXT: .LBB3_1: ! %if.then +; CHECK-NEXT: ! =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: cmp %o0, 0 +; CHECK-NEXT: bne .LBB3_1 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.2: ! %if.end +; CHECK-NEXT: retl +; CHECK-NEXT: mov 2, %o0 +; +; CHECK64-LABEL: not_same_block: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: and %o0, 1, %o0 +; CHECK64-NEXT: .LBB3_1: ! %if.then +; CHECK64-NEXT: ! =>This Inner Loop Header: Depth=1 +; CHECK64-NEXT: cmp %o0, 0 +; CHECK64-NEXT: bne %icc, .LBB3_1 +; CHECK64-NEXT: nop +; CHECK64-NEXT: ! %bb.2: ! %if.end +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 2, %o0 +entry: + %and = and i32 %a, 1 + br label %if.then + +if.then: + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %if.end, label %if.then + ret i32 1 + +if.end: + ret i32 2 +} + +; Compare instruction is not checking equality +define i32 @not_equality(i32 %a) #0 { +; CHECK-LABEL: not_equality: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: and %o0, 1, %o1 +; CHECK-NEXT: cmp %o1, 0 +; CHECK-NEXT: bl .LBB4_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %entry +; CHECK-NEXT: mov %o1, %o0 +; CHECK-NEXT: .LBB4_2: ! %entry +; CHECK-NEXT: retl +; CHECK-NEXT: nop +; +; CHECK64-LABEL: not_equality: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: and %o0, 1, %o1 +; CHECK64-NEXT: cmp %o1, 0 +; CHECK64-NEXT: movl %icc, %o0, %o1 +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov %o1, %o0 +entry: + %and = and i32 %a, 1 + %cmp = icmp slt i32 %and, 0 + %cond = select i1 %cmp, i32 %a, i32 %and + ret i32 %cond +} + +; Instruction that modifies ICC (call) between defining +; and compare instruction. +define i32 @call_between(i32 %a) #0 { +; CHECK-LABEL: call_between: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -96, %sp +; CHECK-NEXT: and %i0, 1, %i1 +; CHECK-NEXT: call not_equality +; CHECK-NEXT: mov %i1, %o0 +; CHECK-NEXT: cmp %i1, 0 +; CHECK-NEXT: be .LBB5_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %entry +; CHECK-NEXT: mov %i1, %i0 +; CHECK-NEXT: .LBB5_2: ! %entry +; CHECK-NEXT: ret +; CHECK-NEXT: restore +; +; CHECK64-LABEL: call_between: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: save %sp, -176, %sp +; CHECK64-NEXT: and %i0, 1, %i1 +; CHECK64-NEXT: call not_equality +; CHECK64-NEXT: mov %i1, %o0 +; CHECK64-NEXT: cmp %i1, 0 +; CHECK64-NEXT: move %icc, %i0, %i1 +; CHECK64-NEXT: ret +; CHECK64-NEXT: restore %g0, %i1, %o0 +entry: + %and = and i32 %a, 1 + call i32 @not_equality(i32 %and) + %cmp = icmp eq i32 %and, 0 + %cond = select i1 %cmp, i32 %a, i32 %and + ret i32 %cond +} + +; ICC is used in successor block. +define i32 @icc_live_out(i32 %a) #0 { +; CHECK-LABEL: icc_live_out: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: and %o0, 1, %o1 +; CHECK-NEXT: cmp %o1, 0 +; CHECK-NEXT: bne .LBB6_4 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %case1 +; CHECK-NEXT: be .LBB6_3 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.2: ! %case1 +; CHECK-NEXT: mov %o1, %o0 +; CHECK-NEXT: .LBB6_3: ! %case1 +; CHECK-NEXT: retl +; CHECK-NEXT: nop +; CHECK-NEXT: .LBB6_4: ! %case2 +; CHECK-NEXT: retl +; CHECK-NEXT: mov 2, %o0 +; +; CHECK64-LABEL: icc_live_out: +; CHECK64: ! %bb.0: ! %entry +; CHECK64-NEXT: mov %o0, %o1 +; CHECK64-NEXT: and %o0, 1, %o0 +; CHECK64-NEXT: cmp %o0, 0 +; CHECK64-NEXT: bne %icc, .LBB6_2 +; CHECK64-NEXT: nop +; CHECK64-NEXT: ! %bb.1: ! %case1 +; CHECK64-NEXT: retl +; CHECK64-NEXT: move %icc, %o1, %o0 +; CHECK64-NEXT: .LBB6_2: ! %case2 +; CHECK64-NEXT: retl +; CHECK64-NEXT: mov 2, %o0 +entry: + %and = and i32 %a, 1 + %cmp = icmp eq i32 %and, 0 + br i1 %cmp, label %case1, label %case2 +case1: + %cond = select i1 %cmp, i32 %a, i32 %and + ret i32 %cond +case2: + ret i32 2 +} + +attributes #0 = { nounwind } diff --git a/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll index 1e5ab7922de08..e0c7032b1d9d4 100644 --- a/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll +++ b/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll @@ -130,8 +130,7 @@ define { i128, i8 } @muloti_test(i128 %l, i128 %r) nounwind { ; SPARC-NEXT: xor %i0, %g4, %i0 ; SPARC-NEXT: xor %i5, %g4, %i4 ; SPARC-NEXT: or %i4, %i0, %i0 -; SPARC-NEXT: or %i0, %i1, %i0 -; SPARC-NEXT: cmp %i0, 0 +; SPARC-NEXT: orcc %i0, %i1, %g0 ; SPARC-NEXT: bne .LBB0_2 ; SPARC-NEXT: nop ; SPARC-NEXT: ! %bb.1: ! %start diff --git a/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll index 6d197c88bfecd..40e90d6bdd6af 100644 --- a/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll +++ b/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll @@ -116,32 +116,30 @@ define { i128, i8 } @muloti_test(i128 %l, i128 %r) nounwind { ; SPARC-NEXT: .LBB0_22: ! %start ; SPARC-NEXT: and %o4, %o3, %o2 ; SPARC-NEXT: cmp %l1, 0 -; SPARC-NEXT: and %o0, %l4, %l4 +; SPARC-NEXT: and %o0, %l4, %o0 ; SPARC-NEXT: bne .LBB0_24 ; SPARC-NEXT: mov %l3, %l1 ; SPARC-NEXT: ! %bb.23: ! %start ; SPARC-NEXT: mov %g0, %l1 ; SPARC-NEXT: .LBB0_24: ! %start -; SPARC-NEXT: or %o2, %o1, %o0 +; SPARC-NEXT: or %o2, %o1, %l4 ; SPARC-NEXT: cmp %l2, %l0 -; SPARC-NEXT: or %l4, %l6, %l4 +; SPARC-NEXT: or %o0, %l6, %l6 ; SPARC-NEXT: bcs .LBB0_26 ; SPARC-NEXT: mov %l3, %l0 ; SPARC-NEXT: ! %bb.25: ! %start ; SPARC-NEXT: mov %g0, %l0 ; SPARC-NEXT: .LBB0_26: ! %start -; SPARC-NEXT: or %o0, %l7, %l2 -; SPARC-NEXT: or %i5, %i4, %i4 -; SPARC-NEXT: cmp %i4, 0 -; SPARC-NEXT: or %l4, %l1, %l1 +; SPARC-NEXT: or %l4, %l7, %l2 +; SPARC-NEXT: orcc %i5, %i4, %g0 +; SPARC-NEXT: or %l6, %l1, %l1 ; SPARC-NEXT: bne .LBB0_28 ; SPARC-NEXT: mov %l3, %i4 ; SPARC-NEXT: ! %bb.27: ! %start ; SPARC-NEXT: mov %g0, %i4 ; SPARC-NEXT: .LBB0_28: ! %start ; SPARC-NEXT: or %l2, %g4, %i5 -; SPARC-NEXT: or %i1, %i0, %i0 -; SPARC-NEXT: cmp %i0, 0 +; SPARC-NEXT: orcc %i1, %i0, %g0 ; SPARC-NEXT: bne .LBB0_30 ; SPARC-NEXT: or %l1, %l0, %i0 ; SPARC-NEXT: ! %bb.29: ! %start From 19ed01ea21c178881d3237986f6edba6d15b26d8 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 9 Nov 2025 09:39:17 +0700 Subject: [PATCH 2/2] Apply suggestions --- llvm/lib/Target/Sparc/SparcInstrInfo.cpp | 21 ++++++++++++--------- llvm/lib/Target/Sparc/SparcInstrInfo.td | 15 +++------------ llvm/test/CodeGen/SPARC/2011-01-11-CC.ll | 6 ++++-- llvm/test/CodeGen/SPARC/fp128-select.ll | 3 +-- llvm/test/CodeGen/SPARC/optcompare.ll | 8 ++++---- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp index b2d6aa18732bc..24bebf9cf2097 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -643,21 +643,24 @@ unsigned SparcInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { bool SparcInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg, Register &SrcReg2, int64_t &CmpMask, int64_t &CmpValue) const { + Register DstReg; switch (MI.getOpcode()) { default: break; - case SP::CMPri: - SrcReg = MI.getOperand(0).getReg(); + case SP::SUBCCri: + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); SrcReg2 = 0; CmpMask = ~0; - CmpValue = MI.getOperand(1).getImm(); - return (CmpValue == 0); - case SP::CMPrr: - SrcReg = MI.getOperand(0).getReg(); - SrcReg2 = MI.getOperand(1).getReg(); + CmpValue = MI.getOperand(2).getImm(); + return (DstReg == SP::G0) && (CmpValue == 0); + case SP::SUBCCrr: + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + SrcReg2 = MI.getOperand(2).getReg(); CmpMask = ~0; CmpValue = 0; - return SrcReg2 == SP::G0; + return (DstReg == SP::G0) && (SrcReg2 == SP::G0); } return false; @@ -773,7 +776,7 @@ bool SparcInstrInfo::optimizeCompareInstr( } // If the result is not needed use the %g0 register. - if (!isRegUsed && CmpInstr.getOperand(0).isKill()) + if (!isRegUsed && CmpInstr.getOperand(1).isKill()) MI->getOperand(0).setReg(SP::G0); MI->setDesc(get(newOpcode)); diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td index 233dea63b80e6..f654f8b0671e4 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -908,23 +908,14 @@ defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, simm13Op>; let Uses = [ICC], Defs = [ICC] in defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, simm13Op>; -let Defs = [ICC], hasPostISelHook = true in +let Defs = [ICC], hasPostISelHook = true, isCompare = 1 in defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, simm13Op>; let Uses = [ICC] in defm SUBC : F3_12np <"subx", 0b001100>; -// cmp (from Section A.3) is a specialized alias for subcc -let Defs = [ICC], rd = 0, isCompare = 1 in { - def CMPrr : F3_1<2, 0b010100, - (outs), (ins IntRegs:$rs1, IntRegs:$rs2), - "cmp $rs1, $rs2", - [(SPcmpicc i32:$rs1, i32:$rs2)]>; - def CMPri : F3_2<2, 0b010100, - (outs), (ins IntRegs:$rs1, simm13Op:$simm13), - "cmp $rs1, $simm13", - [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>; -} +def : Pat<(SPcmpicc i32:$lhs, i32:$rhs), (SUBCCrr $lhs, $rhs)>; +def : Pat<(SPcmpicc i32:$lhs, (i32 simm13:$rhs)), (SUBCCri $lhs, imm:$rhs)>; // Section B.18 - Multiply Instructions, p. 113 let Defs = [Y] in { diff --git a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll index 9dffe0a3ce456..e05c47bfee766 100644 --- a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll +++ b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll @@ -25,13 +25,15 @@ define i32 @test_addx(i64 %a, i64 %b, i64 %c) nounwind { ; V8-NEXT: retl ; V8-NEXT: nop ; V8-NEXT: .LBB0_4: ! %entry +; V8-NEXT: mov %g0, %o2 ; V8-NEXT: cmp %o3, %o5 ; V8-NEXT: bgu .LBB0_2 -; V8-NEXT: mov %g0, %o2 +; V8-NEXT: nop ; V8-NEXT: .LBB0_5: ! %entry +; V8-NEXT: mov %g0, %o0 ; V8-NEXT: cmp %o1, %o4 ; V8-NEXT: be .LBB0_3 -; V8-NEXT: mov %g0, %o0 +; V8-NEXT: nop ; V8-NEXT: .LBB0_6: ! %entry ; V8-NEXT: retl ; V8-NEXT: mov %o2, %o0 diff --git a/llvm/test/CodeGen/SPARC/fp128-select.ll b/llvm/test/CodeGen/SPARC/fp128-select.ll index 72038e59b9fc8..2868896dd83b3 100644 --- a/llvm/test/CodeGen/SPARC/fp128-select.ll +++ b/llvm/test/CodeGen/SPARC/fp128-select.ll @@ -22,8 +22,7 @@ define fp128 @f128_select_soft(fp128 %a, fp128 %b) #0 { ; V9-NEXT: sllx %o3, 32, %o3 ; V9-NEXT: or %o3, %o2, %o2 ; V9-NEXT: xor %o1, %o2, %o1 -; V9-NEXT: or %o0, %o1, %o0 -; V9-NEXT: cmp %o0, 0 +; V9-NEXT: orcc %o0, %o1, %g0 ; V9-NEXT: bne %xcc, .LBB0_2 ; V9-NEXT: nop ; V9-NEXT: ! %bb.1: diff --git a/llvm/test/CodeGen/SPARC/optcompare.ll b/llvm/test/CodeGen/SPARC/optcompare.ll index d05596da16f7e..28588503caeaf 100644 --- a/llvm/test/CodeGen/SPARC/optcompare.ll +++ b/llvm/test/CodeGen/SPARC/optcompare.ll @@ -207,11 +207,11 @@ entry: define i32 @icc_live_out(i32 %a) #0 { ; CHECK-LABEL: icc_live_out: ; CHECK: ! %bb.0: ! %entry -; CHECK-NEXT: and %o0, 1, %o1 -; CHECK-NEXT: cmp %o1, 0 +; CHECK-NEXT: andcc %o0, 1, %o1 ; CHECK-NEXT: bne .LBB6_4 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.1: ! %case1 +; CHECK-NEXT: cmp %o1, 0 ; CHECK-NEXT: be .LBB6_3 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.2: ! %case1 @@ -226,11 +226,11 @@ define i32 @icc_live_out(i32 %a) #0 { ; CHECK64-LABEL: icc_live_out: ; CHECK64: ! %bb.0: ! %entry ; CHECK64-NEXT: mov %o0, %o1 -; CHECK64-NEXT: and %o0, 1, %o0 -; CHECK64-NEXT: cmp %o0, 0 +; CHECK64-NEXT: andcc %o0, 1, %o0 ; CHECK64-NEXT: bne %icc, .LBB6_2 ; CHECK64-NEXT: nop ; CHECK64-NEXT: ! %bb.1: ! %case1 +; CHECK64-NEXT: cmp %o0, 0 ; CHECK64-NEXT: retl ; CHECK64-NEXT: move %icc, %o1, %o0 ; CHECK64-NEXT: .LBB6_2: ! %case2