From 4e6835d4d980b0a1ea6a9de1c2e8360fd0810bba Mon Sep 17 00:00:00 2001 From: AtariDreams Date: Fri, 21 Jun 2024 10:48:04 -0400 Subject: [PATCH] [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 --- .../lib/Target/AArch64/AArch64ISelLowering.cpp | 6 ++++++ .../GISel/AArch64InstructionSelector.cpp | 9 ++++++--- llvm/test/CodeGen/AArch64/arm64-ccmp.ll | 3 +-- llvm/test/CodeGen/AArch64/cmp-chains.ll | 18 ++++++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 7f821715c910d8..0c834acacdca90 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3519,6 +3519,12 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS, RHS = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, RHS); } Opcode = AArch64ISD::FCCMP; + } else if (ConstantSDNode *Const = dyn_cast(RHS)) { + APInt Imm = Const->getAPIntValue(); + if (Imm.isNegative() && Imm.sgt(-32)) { + Opcode = AArch64ISD::CCMN; + RHS = DAG.getConstant(Imm.abs(), DL, Const->getValueType(0)); + } } else if (RHS.getOpcode() == ISD::SUB) { SDValue SubOp0 = RHS.getOperand(0); if (isNullConstant(SubOp0) && (CC == ISD::SETEQ || CC == ISD::SETNE)) { diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index d32007ec45fb65..0357a7206c478e 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -4667,7 +4667,6 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison( Register LHS, Register RHS, CmpInst::Predicate CC, AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC, MachineIRBuilder &MIB) const { - // TODO: emit CMN as an optimization. auto &MRI = *MIB.getMRI(); LLT OpTy = MRI.getType(LHS); unsigned CCmpOpc; @@ -4675,10 +4674,12 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison( if (CmpInst::isIntPredicate(CC)) { assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64); C = getIConstantVRegValWithLookThrough(RHS, MRI); - if (C && C->Value.ult(32)) + if (!C || C->Value.sgt(31) || C->Value.slt(-31)) + CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr; + else if (C->Value.ule(31)) CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi; else - CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr; + CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi; } else { assert(OpTy.getSizeInBits() == 16 || OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64); @@ -4703,6 +4704,8 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison( MIB.buildInstr(CCmpOpc, {}, {LHS}); if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi) CCmp.addImm(C->Value.getZExtValue()); + else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi) + CCmp.addImm(C->Value.abs().getZExtValue()); else CCmp.addReg(RHS); CCmp.addImm(NZCV).addImm(Predicate); diff --git a/llvm/test/CodeGen/AArch64/arm64-ccmp.ll b/llvm/test/CodeGen/AArch64/arm64-ccmp.ll index 5d3b2d3649e1b3..b6702bba1598c9 100644 --- a/llvm/test/CodeGen/AArch64/arm64-ccmp.ll +++ b/llvm/test/CodeGen/AArch64/arm64-ccmp.ll @@ -706,10 +706,9 @@ define i32 @select_noccmp3(i32 %v0, i32 %v1, i32 %v2) { ; GISEL: ; %bb.0: ; GISEL-NEXT: mov w8, #99 ; =0x63 ; GISEL-NEXT: sub w9, w0, #45 -; GISEL-NEXT: mov w10, #-23 ; =0xffffffe9 ; GISEL-NEXT: cmp w0, #77 ; GISEL-NEXT: ccmp w0, w8, #4, ne -; GISEL-NEXT: ccmp w9, w10, #2, eq +; GISEL-NEXT: ccmn w9, #23, #2, eq ; GISEL-NEXT: ccmp w0, #14, #0, lo ; GISEL-NEXT: csel w0, w1, w2, hs ; GISEL-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/cmp-chains.ll b/llvm/test/CodeGen/AArch64/cmp-chains.ll index 1d9f39e5185939..14cb0c82b1c039 100644 --- a/llvm/test/CodeGen/AArch64/cmp-chains.ll +++ b/llvm/test/CodeGen/AArch64/cmp-chains.ll @@ -242,5 +242,19 @@ define i32 @true_or3(i32 %0, i32 %1, i32 %2) { %9 = zext i1 %8 to i32 ret i32 %9 } -;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: -; CHECK: {{.*}} + +; (b > -3 && a < c) +define i32 @neg_range_int(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: neg_range_int: +; CHECK: // %bb.0: +; CHECK-NEXT: cmp w0, w2 +; CHECK-NEXT: ccmn w1, #3, #4, lt +; CHECK-NEXT: csel w0, w1, w0, gt +; CHECK-NEXT: ret + %cmp = icmp sgt i32 %b, -3 + %cmp1 = icmp slt i32 %a, %c + %or.cond = and i1 %cmp, %cmp1 + %retval.0 = select i1 %or.cond, i32 %b, i32 %a + ret i32 %retval.0 +} +