[llvm] [ARM][AArch64] Allow the CSE to take into consideration uses of the carry and overflow flags in ARM and AArch64 (PR #150803)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 26 16:10:49 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/150803
>From 581cc64748b557ba1c921495fea4ef1e2d3fc0ce Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 26 Jul 2025 18:01:24 -0400
Subject: [PATCH 1/3] [ARM][AArch64] Allow the CSE to take into consideration
uses of the carry and overflow flags in ARM and AArch64
On both of these platforms, we know that the cmp will not stomp on these flags and overwrite them if doing so would be poison, or in ANDS case, it will always have the V flag cleared during an ANDS.
---
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 23 +++++++++++++--
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 30 ++++++++++++++++++--
2 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 8685d7a04ac9c..be4ed2911c05a 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -1884,6 +1884,10 @@ static bool isSUBSRegImm(unsigned Opcode) {
return Opcode == AArch64::SUBSWri || Opcode == AArch64::SUBSXri;
}
+static bool isANDSRegImm(unsigned Opcode) {
+ return Opcode == AArch64::ANDSWri || Opcode == AArch64::ANDSXri;
+}
+
/// Check if CmpInstr can be substituted by MI.
///
/// CmpInstr can be substituted:
@@ -1904,7 +1908,8 @@ static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr,
assert(sForm(MI) != AArch64::INSTRUCTION_LIST_END);
const unsigned CmpOpcode = CmpInstr.getOpcode();
- if (!isADDSRegImm(CmpOpcode) && !isSUBSRegImm(CmpOpcode))
+ if (!isADDSRegImm(CmpOpcode) && !isSUBSRegImm(CmpOpcode) &&
+ !isANDSRegImm(CmpOpcode))
return false;
assert((CmpInstr.getOperand(2).isImm() &&
@@ -1912,7 +1917,17 @@ static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr,
"Caller guarantees that CmpInstr compares with constant 0");
std::optional<UsedNZCV> NZVCUsed = examineCFlagsUse(MI, CmpInstr, TRI);
- if (!NZVCUsed || NZVCUsed->C)
+ if (!NZVCUsed)
+ return false;
+
+ // CmpInstr is either 'ADDS %vreg, 0' or 'SUBS %vreg, 0', and MI is either
+ // '%vreg = add ...' or '%vreg = sub ...'.
+ // Condition flag C is used to indicate unsigned overflow.
+ // 1) MI and CmpInstr set N and C to the same value if Cmp is an adds
+ // 2) ADDS x, 0, always sets C to 0.
+ // In practice we should not really get here, as an unsigned comparison with 0
+ // should have been optimized out anyway, but just in case.
+ if (NZVCUsed->C && !isADDSRegImm(CmpOpcode))
return false;
// CmpInstr is either 'ADDS %vreg, 0' or 'SUBS %vreg, 0', and MI is either
@@ -1921,7 +1936,9 @@ static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr,
// 1) MI and CmpInstr set N and V to the same value.
// 2) If MI is add/sub with no-signed-wrap, it produces a poison value when
// signed overflow occurs, so CmpInstr could still be simplified away.
- if (NZVCUsed->V && !MI.getFlag(MachineInstr::NoSWrap))
+ // 3) ANDS also always sets V to 0.
+ if (NZVCUsed->V && !MI.getFlag(MachineInstr::NoSWrap) &&
+ !isANDSRegImm(CmpOpcode))
return false;
AccessKind AccessToCheck = AK_Write;
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 50217c3a047df..44bf8012ae0a7 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -3087,17 +3087,41 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
case ARMCC::AL: // none
// CPSR can be used multiple times, we should continue.
break;
+ default:
case ARMCC::HS: // C
case ARMCC::LO: // C
- case ARMCC::VS: // V
- case ARMCC::VC: // V
case ARMCC::HI: // C Z
case ARMCC::LS: // C Z
+ // The instruction uses the C bit which is not safe.
+ return false;
+ case ARMCC::VS: // V
+ case ARMCC::VC: // V
case ARMCC::GE: // N V
case ARMCC::LT: // N V
case ARMCC::GT: // Z N V
case ARMCC::LE: // Z N V
- // The instruction uses the V bit or C bit which is not safe.
+ // We MAY be able to do this if signed overflow is
+ // poison.
+
+ if (I->getFlag(MachineInstr::NoSWrap)) {
+ // Only adds and subs can set the V bit.
+
+ unsigned Opc = I->getOpcode();
+ bool IsSub = Opc == ARM::SUBrr || Opc == ARM::t2SUBrr ||
+ Opc == ARM::SUBri || Opc == ARM::t2SUBri ||
+ Opc == ARM::tSUBrr || Opc == ARM::tSUBi3 ||
+ Opc == ARM::tSUBi8;
+
+ bool IsAdd = Opc == ARM::ADDrr || Opc == ARM::t2ADDrr ||
+ Opc == ARM::ADDri || Opc == ARM::t2ADDri ||
+ Opc == ARM::tADDrr || Opc == ARM::tADDi3 ||
+ Opc == ARM::tADDi8;
+
+ if (IsSub || IsAdd)
+ break;
+ }
+
+ // The instruction uses the V bit which is not safe.
return false;
}
}
>From c6a2669b62deb770cbb5325a6fb4110bfb2189ca Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 26 Jul 2025 19:04:22 -0400
Subject: [PATCH 2/3] Update aarch64-icmp-opt.ll
---
llvm/test/CodeGen/AArch64/aarch64-icmp-opt.ll | 104 ++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/aarch64-icmp-opt.ll b/llvm/test/CodeGen/AArch64/aarch64-icmp-opt.ll
index c24ef372a5907..57ef72959a21a 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-icmp-opt.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-icmp-opt.ll
@@ -110,7 +110,111 @@ define i32 @add_i32(i32 %0, i32 %1) {
ret i32 %10
}
+define i64 @and_i64(i64 %0, i64 %1) {
+; CHECK-LABEL: and_i64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ands x0, x1, x0
+; CHECK-NEXT: b.le .LBB4_2
+; CHECK-NEXT: // %bb.1:
+; CHECK-NEXT: b _Z2f4l
+; CHECK-NEXT: .LBB4_2:
+; CHECK-NEXT: b _Z2f3l
+ %3 = and i64 %1, %0
+ %4 = icmp slt i64 %3, 1
+ br i1 %4, label %5, label %7
+
+5:
+ %6 = tail call i64 @_Z2f3l(i64 %3)
+ br label %9
+
+7:
+ %8 = tail call i64 @_Z2f4l(i64 %3)
+ br label %9
+
+9:
+ %10 = phi i64 [ %6, %5 ], [ %8, %7 ]
+ ret i64 %10
+}
+define i32 @and_i32(i32 %0, i32 %1) {
+; CHECK-LABEL: and_i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ands w0, w1, w0
+; CHECK-NEXT: b.le .LBB5_2
+; CHECK-NEXT: // %bb.1:
+; CHECK-NEXT: b _Z2f4l
+; CHECK-NEXT: .LBB5_2:
+; CHECK-NEXT: b _Z2f3l
+ %3 = and i32 %1, %0
+ %4 = icmp slt i32 %3, 1
+ br i1 %4, label %5, label %7
+
+5:
+ %6 = tail call i32 @_Z2f3l(i32 %3)
+ br label %9
+
+7:
+ %8 = tail call i32 @_Z2f4l(i32 %3)
+ br label %9
+
+9:
+ %10 = phi i32 [ %6, %5 ], [ %8, %7 ]
+ ret i32 %10
+}
+
+define i64 @and_i64_freeze(i64 %0, i64 %1) {
+; CHECK-LABEL: and_i64_freeze:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ands x0, x1, x0
+; CHECK-NEXT: b.le .LBB6_2
+; CHECK-NEXT: // %bb.1:
+; CHECK-NEXT: b _Z2f4l
+; CHECK-NEXT: .LBB6_2:
+; CHECK-NEXT: b _Z2f3l
+ %3 = and i64 %1, %0
+ %freeze = freeze i64 %3
+ %4 = icmp slt i64 %3, 1
+ br i1 %4, label %5, label %7
+
+5:
+ %6 = tail call i64 @_Z2f3l(i64 %freeze)
+ br label %9
+
+7:
+ %8 = tail call i64 @_Z2f4l(i64 %freeze)
+ br label %9
+
+9:
+ %10 = phi i64 [ %6, %5 ], [ %8, %7 ]
+ ret i64 %10
+}
+
+define i32 @and_i32_freeze(i32 %0, i32 %1) {
+; CHECK-LABEL: and_i32_freeze:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ands w0, w1, w0
+; CHECK-NEXT: b.le .LBB7_2
+; CHECK-NEXT: // %bb.1:
+; CHECK-NEXT: b _Z2f4l
+; CHECK-NEXT: .LBB7_2:
+; CHECK-NEXT: b _Z2f3l
+ %3 = and i32 %1, %0
+ %freeze = freeze i32 %3
+ %4 = icmp slt i32 %freeze, 1
+ br i1 %4, label %5, label %7
+
+5:
+ %6 = tail call i32 @_Z2f3l(i32 %freeze)
+ br label %9
+
+7:
+ %8 = tail call i32 @_Z2f4l(i32 %freeze)
+ br label %9
+
+9:
+ %10 = phi i32 [ %6, %5 ], [ %8, %7 ]
+ ret i32 %10
+}
declare i32 @_Z2f1i(i32)
declare i32 @_Z2f2i(i32)
>From be309cf324116f1faa3f0b6760a0436b50cfd5b3 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 26 Jul 2025 19:04:29 -0400
Subject: [PATCH 3/3] Update ARMBaseInstrInfo.cpp
---
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 44bf8012ae0a7..e48703b1285e8 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -3087,7 +3087,6 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
case ARMCC::AL: // none
// CPSR can be used multiple times, we should continue.
break;
- default:
case ARMCC::HS: // C
case ARMCC::LO: // C
case ARMCC::HI: // C Z
@@ -3100,12 +3099,12 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
case ARMCC::LT: // N V
case ARMCC::GT: // Z N V
case ARMCC::LE: // Z N V
- // We MAY be able to do this if signed overflow is
- // poison.
+ {
+ // We MAY be able to do this if signed overflow is
+ // poison.
if (I->getFlag(MachineInstr::NoSWrap)) {
// Only adds and subs can set the V bit.
-
unsigned Opc = I->getOpcode();
bool IsSub = Opc == ARM::SUBrr || Opc == ARM::t2SUBrr ||
Opc == ARM::SUBri || Opc == ARM::t2SUBri ||
@@ -3124,6 +3123,7 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
// The instruction uses the V bit which is not safe.
return false;
}
+ }
}
}
}
More information about the llvm-commits
mailing list