[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