Skip to content

Commit 4e6835d

Browse files
authored
[AArch64] Use ccmn to compare negative immediates between -1 and -31 (#95825)
Because ccmn is like a + b, it works when using cmp but with values that when negated are in the range of 1 through 31
1 parent a9efcbf commit 4e6835d

File tree

4 files changed

+29
-7
lines changed

4 files changed

+29
-7
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,12 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
35193519
RHS = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, RHS);
35203520
}
35213521
Opcode = AArch64ISD::FCCMP;
3522+
} else if (ConstantSDNode *Const = dyn_cast<ConstantSDNode>(RHS)) {
3523+
APInt Imm = Const->getAPIntValue();
3524+
if (Imm.isNegative() && Imm.sgt(-32)) {
3525+
Opcode = AArch64ISD::CCMN;
3526+
RHS = DAG.getConstant(Imm.abs(), DL, Const->getValueType(0));
3527+
}
35223528
} else if (RHS.getOpcode() == ISD::SUB) {
35233529
SDValue SubOp0 = RHS.getOperand(0);
35243530
if (isNullConstant(SubOp0) && (CC == ISD::SETEQ || CC == ISD::SETNE)) {

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4667,18 +4667,19 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
46674667
Register LHS, Register RHS, CmpInst::Predicate CC,
46684668
AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC,
46694669
MachineIRBuilder &MIB) const {
4670-
// TODO: emit CMN as an optimization.
46714670
auto &MRI = *MIB.getMRI();
46724671
LLT OpTy = MRI.getType(LHS);
46734672
unsigned CCmpOpc;
46744673
std::optional<ValueAndVReg> C;
46754674
if (CmpInst::isIntPredicate(CC)) {
46764675
assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
46774676
C = getIConstantVRegValWithLookThrough(RHS, MRI);
4678-
if (C && C->Value.ult(32))
4677+
if (!C || C->Value.sgt(31) || C->Value.slt(-31))
4678+
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4679+
else if (C->Value.ule(31))
46794680
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
46804681
else
4681-
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4682+
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
46824683
} else {
46834684
assert(OpTy.getSizeInBits() == 16 || OpTy.getSizeInBits() == 32 ||
46844685
OpTy.getSizeInBits() == 64);
@@ -4703,6 +4704,8 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
47034704
MIB.buildInstr(CCmpOpc, {}, {LHS});
47044705
if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
47054706
CCmp.addImm(C->Value.getZExtValue());
4707+
else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4708+
CCmp.addImm(C->Value.abs().getZExtValue());
47064709
else
47074710
CCmp.addReg(RHS);
47084711
CCmp.addImm(NZCV).addImm(Predicate);

llvm/test/CodeGen/AArch64/arm64-ccmp.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,10 +706,9 @@ define i32 @select_noccmp3(i32 %v0, i32 %v1, i32 %v2) {
706706
; GISEL: ; %bb.0:
707707
; GISEL-NEXT: mov w8, #99 ; =0x63
708708
; GISEL-NEXT: sub w9, w0, #45
709-
; GISEL-NEXT: mov w10, #-23 ; =0xffffffe9
710709
; GISEL-NEXT: cmp w0, #77
711710
; GISEL-NEXT: ccmp w0, w8, #4, ne
712-
; GISEL-NEXT: ccmp w9, w10, #2, eq
711+
; GISEL-NEXT: ccmn w9, #23, #2, eq
713712
; GISEL-NEXT: ccmp w0, #14, #0, lo
714713
; GISEL-NEXT: csel w0, w1, w2, hs
715714
; GISEL-NEXT: ret

llvm/test/CodeGen/AArch64/cmp-chains.ll

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,5 +242,19 @@ define i32 @true_or3(i32 %0, i32 %1, i32 %2) {
242242
%9 = zext i1 %8 to i32
243243
ret i32 %9
244244
}
245-
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
246-
; CHECK: {{.*}}
245+
246+
; (b > -3 && a < c)
247+
define i32 @neg_range_int(i32 %a, i32 %b, i32 %c) {
248+
; CHECK-LABEL: neg_range_int:
249+
; CHECK: // %bb.0:
250+
; CHECK-NEXT: cmp w0, w2
251+
; CHECK-NEXT: ccmn w1, #3, #4, lt
252+
; CHECK-NEXT: csel w0, w1, w0, gt
253+
; CHECK-NEXT: ret
254+
%cmp = icmp sgt i32 %b, -3
255+
%cmp1 = icmp slt i32 %a, %c
256+
%or.cond = and i1 %cmp, %cmp1
257+
%retval.0 = select i1 %or.cond, i32 %b, i32 %a
258+
ret i32 %retval.0
259+
}
260+

0 commit comments

Comments
 (0)