[llvm] [AArch64] Add final missing instructions to sForm (PR #167518)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 09:21:45 PDT 2026
https://github.com/mike-goutokuji updated https://github.com/llvm/llvm-project/pull/167518
>From d81b364d882e2ef94ea38a539a5eb104de85b104 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 11 Nov 2025 10:12:05 -0500
Subject: [PATCH 1/2] Pre-commit tests (NFC)
---
.../AArch64/peephole-substitute-cmp-adcs.mir | 294 ++++++++++++++++++
1 file changed, 294 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
diff --git a/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir b/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
new file mode 100644
index 0000000000000..a029fc6de37e4
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
@@ -0,0 +1,294 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64-unknown-linux -run-pass=peephole-opt -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=aarch64-unknown-linux -passes=peephole-opt %s -o - | FileCheck %s
+#
+# Exercise sForm-driven substituteCmpToZero for:
+# - ADCSXr / ADCSWr (carry chain + redundant ADDS*ri #0)
+# - SBCSXr / SBCSWr (borrow chain + redundant ADDS*ri #0)
+# - ADDWrs / ADDXrs / SUBWrs / SUBXrs (shifted reg without flags -> *S*rs;
+# redundant ADDS*ri #0 or SUBS*ri #0)
+
+---
+name: peephole_substitute_cmp_adcs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr64 }
+ - { id: 1, class: gpr64 }
+ - { id: 2, class: gpr64 }
+ - { id: 3, class: gpr64 }
+ - { id: 4, class: gpr64 }
+ - { id: 5, class: gpr64common }
+ - { id: 6, class: gpr32 }
+ - { id: 7, class: gpr64 }
+body: |
+ bb.0:
+ liveins: $x0, $x1, $x2, $x3
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_adcs
+ ; CHECK: liveins: $x0, $x1, $x2, $x3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr64 = COPY $x2
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr64 = COPY $x3
+ ; CHECK-NEXT: [[ADDSXrr:%[0-9]+]]:gpr64 = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
+ ; CHECK-NEXT: [[ADCSXr:%[0-9]+]]:gpr64common = ADCSXr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
+ ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[ADCSXr]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr64 = COPY $x0
+ %1:gpr64 = COPY $x1
+ %2:gpr64 = COPY $x2
+ %3:gpr64 = COPY $x3
+ %4:gpr64 = ADDSXrr %0, %1, implicit-def $nzcv
+ %5:gpr64common = ADCSXr %2, %3, implicit-def $nzcv, implicit $nzcv
+ dead %7:gpr64 = ADDSXri killed %5:gpr64common, 0, 0, implicit-def $nzcv
+ %6:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_adcswr
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32 }
+ - { id: 1, class: gpr32 }
+ - { id: 2, class: gpr32 }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr32 }
+ - { id: 5, class: gpr32common }
+ - { id: 6, class: gpr32 }
+ - { id: 7, class: gpr32 }
+body: |
+ bb.0:
+ liveins: $w0, $w1, $w2, $w3
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_adcswr
+ ; CHECK: liveins: $w0, $w1, $w2, $w3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr32 = COPY $w2
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr32 = COPY $w3
+ ; CHECK-NEXT: [[ADDSWrr:%[0-9]+]]:gpr32 = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
+ ; CHECK-NEXT: [[ADCSWr:%[0-9]+]]:gpr32common = ADCSWr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
+ ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[ADCSWr]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr32 = COPY $w0
+ %1:gpr32 = COPY $w1
+ %2:gpr32 = COPY $w2
+ %3:gpr32 = COPY $w3
+ %4:gpr32 = ADDSWrr %0, %1, implicit-def $nzcv
+ %5:gpr32common = ADCSWr %2, %3, implicit-def $nzcv, implicit $nzcv
+ dead %7:gpr32 = ADDSWri killed %5:gpr32common, 0, 0, implicit-def $nzcv
+ %6:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_sbcsxr
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr64 }
+ - { id: 1, class: gpr64 }
+ - { id: 2, class: gpr64 }
+ - { id: 3, class: gpr64 }
+ - { id: 4, class: gpr64 }
+ - { id: 5, class: gpr64common }
+ - { id: 6, class: gpr32 }
+ - { id: 7, class: gpr64 }
+body: |
+ bb.0:
+ liveins: $x0, $x1, $x2, $x3
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_sbcsxr
+ ; CHECK: liveins: $x0, $x1, $x2, $x3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr64 = COPY $x2
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr64 = COPY $x3
+ ; CHECK-NEXT: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
+ ; CHECK-NEXT: [[SBCSXr:%[0-9]+]]:gpr64common = SBCSXr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
+ ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[SBCSXr]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr64 = COPY $x0
+ %1:gpr64 = COPY $x1
+ %2:gpr64 = COPY $x2
+ %3:gpr64 = COPY $x3
+ %4:gpr64 = SUBSXrr %0, %1, implicit-def $nzcv
+ %5:gpr64common = SBCSXr %2, %3, implicit-def $nzcv, implicit $nzcv
+ dead %7:gpr64 = ADDSXri killed %5:gpr64common, 0, 0, implicit-def $nzcv
+ %6:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_addwrs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32 }
+ - { id: 1, class: gpr32 }
+ - { id: 2, class: gpr32common }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr32 }
+body: |
+ bb.0:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_addwrs
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
+ ; CHECK-NEXT: [[ADDWrs:%[0-9]+]]:gpr32common = ADDWrs [[COPY]], [[COPY1]], 0
+ ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[ADDWrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr32 = COPY $w0
+ %1:gpr32 = COPY $w1
+ %2:gpr32common = ADDWrs %0, %1, 0
+ dead %4:gpr32 = ADDSWri killed %2:gpr32common, 0, 0, implicit-def $nzcv
+ %3:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %3
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_addxrs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr64 }
+ - { id: 1, class: gpr64 }
+ - { id: 2, class: gpr64common }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr64 }
+body: |
+ bb.0:
+ liveins: $x0, $x1
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_addxrs
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+ ; CHECK-NEXT: [[ADDXrs:%[0-9]+]]:gpr64common = ADDXrs [[COPY]], [[COPY1]], 0
+ ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[ADDXrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr64 = COPY $x0
+ %1:gpr64 = COPY $x1
+ %2:gpr64common = ADDXrs %0, %1, 0
+ dead %4:gpr64 = ADDSXri killed %2:gpr64common, 0, 0, implicit-def $nzcv
+ %3:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %3
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_subwrs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32 }
+ - { id: 1, class: gpr32 }
+ - { id: 2, class: gpr32common }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr32 }
+body: |
+ bb.0:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_subwrs
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
+ ; CHECK-NEXT: [[SUBWrs:%[0-9]+]]:gpr32common = SUBWrs [[COPY]], [[COPY1]], 0
+ ; CHECK-NEXT: dead [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri killed [[SUBWrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr32 = COPY $w0
+ %1:gpr32 = COPY $w1
+ %2:gpr32common = SUBWrs %0, %1, 0
+ dead %4:gpr32 = SUBSWri killed %2:gpr32common, 0, 0, implicit-def $nzcv
+ %3:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %3
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_subxrs
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr64 }
+ - { id: 1, class: gpr64 }
+ - { id: 2, class: gpr64common }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr64 }
+body: |
+ bb.0:
+ liveins: $x0, $x1
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_subxrs
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+ ; CHECK-NEXT: [[SUBXrs:%[0-9]+]]:gpr64common = SUBXrs [[COPY]], [[COPY1]], 0
+ ; CHECK-NEXT: dead [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri killed [[SUBXrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr64 = COPY $x0
+ %1:gpr64 = COPY $x1
+ %2:gpr64common = SUBXrs %0, %1, 0
+ dead %4:gpr64 = SUBSXri killed %2:gpr64common, 0, 0, implicit-def $nzcv
+ %3:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %3
+ RET_ReallyLR implicit $w0
+...
+---
+name: peephole_substitute_cmp_sbcswr
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gpr32 }
+ - { id: 1, class: gpr32 }
+ - { id: 2, class: gpr32 }
+ - { id: 3, class: gpr32 }
+ - { id: 4, class: gpr32 }
+ - { id: 5, class: gpr32common }
+ - { id: 6, class: gpr32 }
+ - { id: 7, class: gpr32 }
+body: |
+ bb.0:
+ liveins: $w0, $w1, $w2, $w3
+
+ ; CHECK-LABEL: name: peephole_substitute_cmp_sbcswr
+ ; CHECK: liveins: $w0, $w1, $w2, $w3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr32 = COPY $w2
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr32 = COPY $w3
+ ; CHECK-NEXT: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
+ ; CHECK-NEXT: [[SBCSWr:%[0-9]+]]:gpr32common = SBCSWr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
+ ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[SBCSWr]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ ; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:gpr32 = COPY $w0
+ %1:gpr32 = COPY $w1
+ %2:gpr32 = COPY $w2
+ %3:gpr32 = COPY $w3
+ %4:gpr32 = SUBSWrr %0, %1, implicit-def $nzcv
+ %5:gpr32common = SBCSWr %2, %3, implicit-def $nzcv, implicit $nzcv
+ dead %7:gpr32 = ADDSWri killed %5:gpr32common, 0, 0, implicit-def $nzcv
+ %6:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
>From ef6be7ea83f569aa6e17c6299dfb0a0c9fed5fb1 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Mon, 20 Apr 2026 19:10:49 -0400
Subject: [PATCH 2/2] [AArch64] Add final missing instructions to sForm
Fix these inconsistencies.
---
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 38 +++++++++++++------
.../AArch64/peephole-substitute-cmp-adcs.mir | 16 ++------
2 files changed, 30 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 57ea2d2f2f992..d5d1e17216e63 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -2078,12 +2078,16 @@ static unsigned sForm(MachineInstr &Instr) {
case AArch64::ADDSXri:
case AArch64::ADDSWrx:
case AArch64::ADDSXrx:
+ case AArch64::ADDSWrs:
+ case AArch64::ADDSXrs:
case AArch64::SUBSWrr:
case AArch64::SUBSWri:
case AArch64::SUBSWrx:
+ case AArch64::SUBSWrs:
case AArch64::SUBSXrr:
case AArch64::SUBSXri:
case AArch64::SUBSXrx:
+ case AArch64::SUBSXrs:
case AArch64::ANDSWri:
case AArch64::ANDSWrr:
case AArch64::ANDSWrs:
@@ -2094,6 +2098,10 @@ static unsigned sForm(MachineInstr &Instr) {
case AArch64::BICSXrr:
case AArch64::BICSWrs:
case AArch64::BICSXrs:
+ case AArch64::ADCSWr:
+ case AArch64::ADCSXr:
+ case AArch64::SBCSWr:
+ case AArch64::SBCSXr:
return Instr.getOpcode();
case AArch64::ADDWrr:
@@ -2108,6 +2116,10 @@ static unsigned sForm(MachineInstr &Instr) {
return AArch64::ADDSWrx;
case AArch64::ADDXrx:
return AArch64::ADDSXrx;
+ case AArch64::ADDWrs:
+ return AArch64::ADDSWrs;
+ case AArch64::ADDXrs:
+ return AArch64::ADDSXrs;
case AArch64::ADCWr:
return AArch64::ADCSWr;
case AArch64::ADCXr:
@@ -2124,6 +2136,10 @@ static unsigned sForm(MachineInstr &Instr) {
return AArch64::SUBSWrx;
case AArch64::SUBXrx:
return AArch64::SUBSXrx;
+ case AArch64::SUBWrs:
+ return AArch64::SUBSWrs;
+ case AArch64::SUBXrs:
+ return AArch64::SUBSXrs;
case AArch64::SBCWr:
return AArch64::SBCSWr;
case AArch64::SBCXr:
@@ -2315,13 +2331,13 @@ static bool isANDOpcode(MachineInstr &MI) {
/// MI and CmpInstr
/// or if MI opcode is not the S form there must be neither defs of flags
/// nor uses of flags between MI and CmpInstr.
-/// - and, if C/V flags are not used after CmpInstr
-/// or if N flag is used but MI produces poison value if signed overflow
-/// occurs.
+/// - and, C is not used after CmpInstr; CmpInstr's C is from adds/subs #0 on
+/// SrcReg and can differ from MI (e.g. carry out of ADCS/SBCS).
+/// - and, V is not used after CmpInstr unless MI is AND/BIC (V cleared) or MI
+/// has NoSWrap (overflow is poison and the fold is still safe).
static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr,
const TargetRegisterInfo &TRI) {
- // NOTE this assertion guarantees that MI.getOpcode() is add or subtraction
- // that may or may not set flags.
+ // MI is an opcode sForm maps (add/sub/adc/sbc/and/bic and their S forms).
assert(sForm(MI) != AArch64::INSTRUCTION_LIST_END);
const unsigned CmpOpcode = CmpInstr.getOpcode();
@@ -2336,13 +2352,11 @@ static bool canInstrSubstituteCmpInstr(MachineInstr &MI, MachineInstr &CmpInstr,
if (!NZVCUsed || NZVCUsed->C)
return false;
- // CmpInstr is either 'ADDS %vreg, 0' or 'SUBS %vreg, 0', and MI is either
- // '%vreg = add ...' or '%vreg = sub ...'.
- // Condition flag V is used to indicate signed overflow.
- // 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.
- // Note that Ands and Bics instructions always clear the V flag.
+ // CmpInstr is ADDS/SUBS with immediate 0 on SrcReg (compare SrcReg to zero).
+ // After the fold, users see NZCV from MI (or its S form), not from CmpInstr.
+ // N/Z match CmpInstr for the value in SrcReg; C/V need not match in general
+ // (e.g. ADCS vs adds #0), so we require C unused after CmpInstr and gate V
+ // as below. NoSWrap makes signed overflow poison; AND/BIC clear V.
if (NZVCUsed->V && !MI.getFlag(MachineInstr::NoSWrap) && !isANDOpcode(MI))
return false;
diff --git a/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir b/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
index a029fc6de37e4..2a73446b201fb 100644
--- a/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
+++ b/llvm/test/CodeGen/AArch64/peephole-substitute-cmp-adcs.mir
@@ -33,7 +33,6 @@ body: |
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr64 = COPY $x3
; CHECK-NEXT: [[ADDSXrr:%[0-9]+]]:gpr64 = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK-NEXT: [[ADCSXr:%[0-9]+]]:gpr64common = ADCSXr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
- ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[ADCSXr]], 0, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -73,7 +72,6 @@ body: |
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr32 = COPY $w3
; CHECK-NEXT: [[ADDSWrr:%[0-9]+]]:gpr32 = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK-NEXT: [[ADCSWr:%[0-9]+]]:gpr32common = ADCSWr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
- ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[ADCSWr]], 0, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -113,7 +111,6 @@ body: |
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr64 = COPY $x3
; CHECK-NEXT: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK-NEXT: [[SBCSXr:%[0-9]+]]:gpr64common = SBCSXr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
- ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[SBCSXr]], 0, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -146,8 +143,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
- ; CHECK-NEXT: [[ADDWrs:%[0-9]+]]:gpr32common = ADDWrs [[COPY]], [[COPY1]], 0
- ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[ADDWrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[ADDSWrs:%[0-9]+]]:gpr32common = ADDSWrs [[COPY]], [[COPY1]], 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -177,8 +173,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
- ; CHECK-NEXT: [[ADDXrs:%[0-9]+]]:gpr64common = ADDXrs [[COPY]], [[COPY1]], 0
- ; CHECK-NEXT: dead [[ADDSXri:%[0-9]+]]:gpr64 = ADDSXri killed [[ADDXrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[ADDSXrs:%[0-9]+]]:gpr64common = ADDSXrs [[COPY]], [[COPY1]], 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -208,8 +203,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
- ; CHECK-NEXT: [[SUBWrs:%[0-9]+]]:gpr32common = SUBWrs [[COPY]], [[COPY1]], 0
- ; CHECK-NEXT: dead [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri killed [[SUBWrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[SUBSWrs:%[0-9]+]]:gpr32common = SUBSWrs [[COPY]], [[COPY1]], 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -239,8 +233,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
- ; CHECK-NEXT: [[SUBXrs:%[0-9]+]]:gpr64common = SUBXrs [[COPY]], [[COPY1]], 0
- ; CHECK-NEXT: dead [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri killed [[SUBXrs]], 0, 0, implicit-def $nzcv
+ ; CHECK-NEXT: [[SUBSXrs:%[0-9]+]]:gpr64common = SUBSXrs [[COPY]], [[COPY1]], 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -277,7 +270,6 @@ body: |
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr32 = COPY $w3
; CHECK-NEXT: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK-NEXT: [[SBCSWr:%[0-9]+]]:gpr32common = SBCSWr [[COPY2]], [[COPY3]], implicit-def $nzcv, implicit $nzcv
- ; CHECK-NEXT: dead [[ADDSWri:%[0-9]+]]:gpr32 = ADDSWri killed [[SBCSWr]], 0, 0, implicit-def $nzcv
; CHECK-NEXT: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
; CHECK-NEXT: $w0 = COPY [[CSINCWr]]
; CHECK-NEXT: RET_ReallyLR implicit $w0
More information about the llvm-commits
mailing list