[llvm] [ARM] Special case scmp 0 (PR #207428)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 3 09:43:44 PDT 2026
https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/207428
We can use cmp instead of subs for scmp 0, and we can do shifts for scmp 0 too.
>From 95f74ef513d7f5cc9ed3a3262bc09e78f0c3b234 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Fri, 3 Jul 2026 12:39:47 -0400
Subject: [PATCH 1/2] [ARM] Precommit tests for scmp/ucmp with 0. NFC.
---
llvm/test/CodeGen/ARM/scmp.ll | 287 +++++++++++++++++++++++++++++++++-
llvm/test/CodeGen/ARM/ucmp.ll | 198 ++++++++++++++++++++++-
2 files changed, 483 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/scmp.ll b/llvm/test/CodeGen/ARM/scmp.ll
index 9189aee6aaf43..168a3f90be33c 100644
--- a/llvm/test/CodeGen/ARM/scmp.ll
+++ b/llvm/test/CodeGen/ARM/scmp.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=armv7-unknown-eabi %s -o - | FileCheck %s
-
+; RUN: llc -mtriple=thumbv6m-unknown-eabi %s -o - | FileCheck %s --check-prefix=THUMB
define i8 @scmp_8_8(i8 signext %x, i8 signext %y) nounwind {
; CHECK-LABEL: scmp_8_8:
; CHECK: @ %bb.0:
@@ -8,6 +8,26 @@ define i8 @scmp_8_8(i8 signext %x, i8 signext %y) nounwind {
; CHECK-NEXT: movwgt r0, #1
; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_8_8:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: cmp r0, r1
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: bge .LBB0_3
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ble .LBB0_4
+; THUMB-NEXT: .LBB0_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
+; THUMB-NEXT: .LBB0_3:
+; THUMB-NEXT: mov r0, r3
+; THUMB-NEXT: bgt .LBB0_2
+; THUMB-NEXT: .LBB0_4:
+; THUMB-NEXT: mov r2, r3
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.scmp(i8 %x, i8 %y)
ret i8 %1
}
@@ -19,6 +39,26 @@ define i8 @scmp_8_16(i16 signext %x, i16 signext %y) nounwind {
; CHECK-NEXT: movwgt r0, #1
; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_8_16:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: cmp r0, r1
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: bge .LBB1_3
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ble .LBB1_4
+; THUMB-NEXT: .LBB1_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
+; THUMB-NEXT: .LBB1_3:
+; THUMB-NEXT: mov r0, r3
+; THUMB-NEXT: bgt .LBB1_2
+; THUMB-NEXT: .LBB1_4:
+; THUMB-NEXT: mov r2, r3
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.scmp(i16 %x, i16 %y)
ret i8 %1
}
@@ -30,6 +70,26 @@ define i8 @scmp_8_32(i32 %x, i32 %y) nounwind {
; CHECK-NEXT: movwgt r0, #1
; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_8_32:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: cmp r0, r1
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: bge .LBB2_3
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ble .LBB2_4
+; THUMB-NEXT: .LBB2_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
+; THUMB-NEXT: .LBB2_3:
+; THUMB-NEXT: mov r0, r3
+; THUMB-NEXT: bgt .LBB2_2
+; THUMB-NEXT: .LBB2_4:
+; THUMB-NEXT: mov r2, r3
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.scmp(i32 %x, i32 %y)
ret i8 %1
}
@@ -49,6 +109,29 @@ define i8 @scmp_8_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: movwlt r12, #1
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: scmp_8_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blt .LBB3_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB3_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blt .LBB3_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB3_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i8 @llvm.scmp(i64 %x, i64 %y)
ret i8 %1
}
@@ -76,6 +159,50 @@ define i8 @scmp_8_128(i128 %x, i128 %y) nounwind {
; CHECK-NEXT: movwlt r5, #1
; CHECK-NEXT: sub r0, r5, r7
; CHECK-NEXT: pop {r4, r5, r6, r7, r11, pc}
+;
+; THUMB-LABEL: scmp_8_128:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, r7, lr}
+; THUMB-NEXT: push {r4, r5, r6, r7, lr}
+; THUMB-NEXT: .pad #20
+; THUMB-NEXT: sub sp, #20
+; THUMB-NEXT: str r3, [sp, #16] @ 4-byte Spill
+; THUMB-NEXT: movs r3, #1
+; THUMB-NEXT: str r3, [sp] @ 4-byte Spill
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: str r3, [sp, #12] @ 4-byte Spill
+; THUMB-NEXT: ldr r6, [sp, #52]
+; THUMB-NEXT: add r7, sp, #40
+; THUMB-NEXT: ldm r7, {r3, r5, r7}
+; THUMB-NEXT: subs r4, r0, r3
+; THUMB-NEXT: str r1, [sp, #4] @ 4-byte Spill
+; THUMB-NEXT: mov r4, r1
+; THUMB-NEXT: ldr r1, [sp] @ 4-byte Reload
+; THUMB-NEXT: sbcs r4, r5
+; THUMB-NEXT: str r2, [sp, #8] @ 4-byte Spill
+; THUMB-NEXT: mov r4, r2
+; THUMB-NEXT: sbcs r4, r7
+; THUMB-NEXT: ldr r4, [sp, #16] @ 4-byte Reload
+; THUMB-NEXT: sbcs r4, r6
+; THUMB-NEXT: mov r2, r1
+; THUMB-NEXT: blt .LBB4_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ldr r2, [sp, #12] @ 4-byte Reload
+; THUMB-NEXT: .LBB4_2:
+; THUMB-NEXT: subs r0, r3, r0
+; THUMB-NEXT: ldr r0, [sp, #4] @ 4-byte Reload
+; THUMB-NEXT: sbcs r5, r0
+; THUMB-NEXT: ldr r0, [sp, #8] @ 4-byte Reload
+; THUMB-NEXT: sbcs r7, r0
+; THUMB-NEXT: ldr r0, [sp, #16] @ 4-byte Reload
+; THUMB-NEXT: sbcs r6, r0
+; THUMB-NEXT: blt .LBB4_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: ldr r1, [sp, #12] @ 4-byte Reload
+; THUMB-NEXT: .LBB4_4:
+; THUMB-NEXT: subs r0, r1, r2
+; THUMB-NEXT: add sp, #20
+; THUMB-NEXT: pop {r4, r5, r6, r7, pc}
%1 = call i8 @llvm.scmp(i128 %x, i128 %y)
ret i8 %1
}
@@ -87,6 +214,26 @@ define i32 @scmp_32_32(i32 %x, i32 %y) nounwind {
; CHECK-NEXT: movwgt r0, #1
; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_32_32:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: cmp r0, r1
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: bge .LBB5_3
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ble .LBB5_4
+; THUMB-NEXT: .LBB5_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
+; THUMB-NEXT: .LBB5_3:
+; THUMB-NEXT: mov r0, r3
+; THUMB-NEXT: bgt .LBB5_2
+; THUMB-NEXT: .LBB5_4:
+; THUMB-NEXT: mov r2, r3
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
%1 = call i32 @llvm.scmp(i32 %x, i32 %y)
ret i32 %1
}
@@ -98,6 +245,26 @@ define i32 @scmp_neg(i32 %x, i32 %y) nounwind {
; CHECK-NEXT: movwgt r0, #1
; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_neg:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: cmn r0, r1
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: bge .LBB6_3
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ble .LBB6_4
+; THUMB-NEXT: .LBB6_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
+; THUMB-NEXT: .LBB6_3:
+; THUMB-NEXT: mov r0, r3
+; THUMB-NEXT: bgt .LBB6_2
+; THUMB-NEXT: .LBB6_4:
+; THUMB-NEXT: mov r2, r3
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: bx lr
%yy = sub nsw i32 0, %y
%1 = call i32 @llvm.scmp(i32 %x, i32 %yy)
ret i32 %1
@@ -118,6 +285,29 @@ define i32 @scmp_32_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: movwlt r12, #1
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: scmp_32_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blt .LBB7_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB7_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blt .LBB7_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB7_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i32 @llvm.scmp(i64 %x, i64 %y)
ret i32 %1
}
@@ -138,6 +328,101 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: asr r1, r0, #31
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: scmp_64_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blt .LBB8_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB8_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blt .LBB8_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB8_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: asrs r1, r0, #31
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i64 @llvm.scmp(i64 %x, i64 %y)
ret i64 %1
}
+
+define i32 @scmp_32_32_zero(i32 %x) nounwind {
+; CHECK-LABEL: scmp_32_32_zero:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: mov r1, #0
+; CHECK-NEXT: cmp r0, #0
+; CHECK-NEXT: movwgt r1, #1
+; CHECK-NEXT: mvnlt r1, #0
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_32_32_zero:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: asrs r1, r0, #31
+; THUMB-NEXT: rsbs r0, r0, #0
+; THUMB-NEXT: lsrs r0, r0, #31
+; THUMB-NEXT: orrs r0, r1
+; THUMB-NEXT: bx lr
+ %1 = call i32 @llvm.scmp(i32 %x, i32 0)
+ ret i32 %1
+}
+
+define i8 @scmp_8_32_zero(i32 %x) nounwind {
+; CHECK-LABEL: scmp_8_32_zero:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: mov r1, #0
+; CHECK-NEXT: cmp r0, #0
+; CHECK-NEXT: movwgt r1, #1
+; CHECK-NEXT: mvnlt r1, #0
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_8_32_zero:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: asrs r1, r0, #31
+; THUMB-NEXT: rsbs r0, r0, #0
+; THUMB-NEXT: lsrs r0, r0, #31
+; THUMB-NEXT: orrs r0, r1
+; THUMB-NEXT: bx lr
+ %1 = call i8 @llvm.scmp(i32 %x, i32 0)
+ ret i8 %1
+}
+
+define i64 @scmp_64_64_zero(i64 %x) nounwind {
+; CHECK-LABEL: scmp_64_64_zero:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: rsbs r0, r0, #0
+; CHECK-NEXT: mov r2, #0
+; CHECK-NEXT: rscs r0, r1, #0
+; CHECK-NEXT: movwlt r2, #1
+; CHECK-NEXT: sub r0, r2, r1, lsr #31
+; CHECK-NEXT: asr r1, r0, #31
+; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: scmp_64_64_zero:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r2, #0
+; THUMB-NEXT: rsbs r0, r0, #0
+; THUMB-NEXT: mov r0, r2
+; THUMB-NEXT: sbcs r0, r1
+; THUMB-NEXT: bge .LBB11_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: movs r2, #1
+; THUMB-NEXT: .LBB11_2:
+; THUMB-NEXT: lsrs r0, r1, #31
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: asrs r1, r0, #31
+; THUMB-NEXT: bx lr
+ %1 = call i64 @llvm.scmp(i64 %x, i64 0)
+ ret i64 %1
+}
diff --git a/llvm/test/CodeGen/ARM/ucmp.ll b/llvm/test/CodeGen/ARM/ucmp.ll
index bb0201454d1ea..6cafe778e9a31 100644
--- a/llvm/test/CodeGen/ARM/ucmp.ll
+++ b/llvm/test/CodeGen/ARM/ucmp.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=armv7-unknown-eabi %s -o - | FileCheck %s
-
+; RUN: llc -mtriple=thumbv6m-unknown-eabi %s -o - | FileCheck %s --check-prefix=THUMB
define i8 @ucmp_8_8(i8 zeroext %x, i8 zeroext %y) nounwind {
; CHECK-LABEL: ucmp_8_8:
; CHECK: @ %bb.0:
@@ -8,6 +8,15 @@ define i8 @ucmp_8_8(i8 zeroext %x, i8 zeroext %y) nounwind {
; CHECK-NEXT: movwhi r0, #1
; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_8_8:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: subs r2, r0, r1
+; THUMB-NEXT: sbcs r2, r2
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r2, r1
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.ucmp(i8 %x, i8 %y)
ret i8 %1
}
@@ -19,6 +28,15 @@ define i8 @ucmp_8_16(i16 zeroext %x, i16 zeroext %y) nounwind {
; CHECK-NEXT: movwhi r0, #1
; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_8_16:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: subs r2, r0, r1
+; THUMB-NEXT: sbcs r2, r2
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r2, r1
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.ucmp(i16 %x, i16 %y)
ret i8 %1
}
@@ -30,6 +48,15 @@ define i8 @ucmp_8_32(i32 %x, i32 %y) nounwind {
; CHECK-NEXT: movwhi r0, #1
; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_8_32:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: subs r2, r0, r1
+; THUMB-NEXT: sbcs r2, r2
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r2, r1
+; THUMB-NEXT: bx lr
%1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
ret i8 %1
}
@@ -49,6 +76,29 @@ define i8 @ucmp_8_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: movwlo r12, #1
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: ucmp_8_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blo .LBB3_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB3_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blo .LBB3_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB3_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i8 @llvm.ucmp(i64 %x, i64 %y)
ret i8 %1
}
@@ -76,6 +126,50 @@ define i8 @ucmp_8_128(i128 %x, i128 %y) nounwind {
; CHECK-NEXT: movwlo r5, #1
; CHECK-NEXT: sub r0, r5, r7
; CHECK-NEXT: pop {r4, r5, r6, r7, r11, pc}
+;
+; THUMB-LABEL: ucmp_8_128:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, r7, lr}
+; THUMB-NEXT: push {r4, r5, r6, r7, lr}
+; THUMB-NEXT: .pad #20
+; THUMB-NEXT: sub sp, #20
+; THUMB-NEXT: str r3, [sp, #16] @ 4-byte Spill
+; THUMB-NEXT: movs r3, #1
+; THUMB-NEXT: str r3, [sp] @ 4-byte Spill
+; THUMB-NEXT: movs r3, #0
+; THUMB-NEXT: str r3, [sp, #12] @ 4-byte Spill
+; THUMB-NEXT: ldr r6, [sp, #52]
+; THUMB-NEXT: add r7, sp, #40
+; THUMB-NEXT: ldm r7, {r3, r5, r7}
+; THUMB-NEXT: subs r4, r0, r3
+; THUMB-NEXT: str r1, [sp, #4] @ 4-byte Spill
+; THUMB-NEXT: mov r4, r1
+; THUMB-NEXT: ldr r1, [sp] @ 4-byte Reload
+; THUMB-NEXT: sbcs r4, r5
+; THUMB-NEXT: str r2, [sp, #8] @ 4-byte Spill
+; THUMB-NEXT: mov r4, r2
+; THUMB-NEXT: sbcs r4, r7
+; THUMB-NEXT: ldr r4, [sp, #16] @ 4-byte Reload
+; THUMB-NEXT: sbcs r4, r6
+; THUMB-NEXT: mov r2, r1
+; THUMB-NEXT: blo .LBB4_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: ldr r2, [sp, #12] @ 4-byte Reload
+; THUMB-NEXT: .LBB4_2:
+; THUMB-NEXT: subs r0, r3, r0
+; THUMB-NEXT: ldr r0, [sp, #4] @ 4-byte Reload
+; THUMB-NEXT: sbcs r5, r0
+; THUMB-NEXT: ldr r0, [sp, #8] @ 4-byte Reload
+; THUMB-NEXT: sbcs r7, r0
+; THUMB-NEXT: ldr r0, [sp, #16] @ 4-byte Reload
+; THUMB-NEXT: sbcs r6, r0
+; THUMB-NEXT: blo .LBB4_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: ldr r1, [sp, #12] @ 4-byte Reload
+; THUMB-NEXT: .LBB4_4:
+; THUMB-NEXT: subs r0, r1, r2
+; THUMB-NEXT: add sp, #20
+; THUMB-NEXT: pop {r4, r5, r6, r7, pc}
%1 = call i8 @llvm.ucmp(i128 %x, i128 %y)
ret i8 %1
}
@@ -87,6 +181,15 @@ define i32 @ucmp_32_32(i32 %x, i32 %y) nounwind {
; CHECK-NEXT: movwhi r0, #1
; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_32_32:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: subs r2, r0, r1
+; THUMB-NEXT: sbcs r2, r2
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r2, r1
+; THUMB-NEXT: bx lr
%1 = call i32 @llvm.ucmp(i32 %x, i32 %y)
ret i32 %1
}
@@ -106,6 +209,29 @@ define i32 @ucmp_32_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: movwlo r12, #1
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: ucmp_32_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blo .LBB6_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB6_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blo .LBB6_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB6_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i32 @llvm.ucmp(i64 %x, i64 %y)
ret i32 %1
}
@@ -126,6 +252,76 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
; CHECK-NEXT: sub r0, r12, lr
; CHECK-NEXT: asr r1, r0, #31
; CHECK-NEXT: pop {r11, pc}
+;
+; THUMB-LABEL: ucmp_64_64:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: .save {r4, r5, r6, lr}
+; THUMB-NEXT: push {r4, r5, r6, lr}
+; THUMB-NEXT: movs r4, #1
+; THUMB-NEXT: movs r5, #0
+; THUMB-NEXT: subs r6, r0, r2
+; THUMB-NEXT: mov r6, r1
+; THUMB-NEXT: sbcs r6, r3
+; THUMB-NEXT: mov r6, r4
+; THUMB-NEXT: blo .LBB7_2
+; THUMB-NEXT: @ %bb.1:
+; THUMB-NEXT: mov r6, r5
+; THUMB-NEXT: .LBB7_2:
+; THUMB-NEXT: subs r0, r2, r0
+; THUMB-NEXT: sbcs r3, r1
+; THUMB-NEXT: blo .LBB7_4
+; THUMB-NEXT: @ %bb.3:
+; THUMB-NEXT: mov r4, r5
+; THUMB-NEXT: .LBB7_4:
+; THUMB-NEXT: subs r0, r4, r6
+; THUMB-NEXT: asrs r1, r0, #31
+; THUMB-NEXT: pop {r4, r5, r6, pc}
%1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
ret i64 %1
}
+
+define i32 @ucmp_32_32_zero(i32 %x) nounwind {
+; CHECK-LABEL: ucmp_32_32_zero:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: mov r1, #0
+; CHECK-NEXT: cmp r0, #0
+; CHECK-NEXT: movwhi r1, #1
+; CHECK-NEXT: mvnlo r1, #0
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_32_32_zero:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r1, #0
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r0, #0
+; THUMB-NEXT: sbcs r0, r0
+; THUMB-NEXT: subs r0, r0, r1
+; THUMB-NEXT: bx lr
+ %1 = call i32 @llvm.ucmp(i32 %x, i32 0)
+ ret i32 %1
+}
+
+define i8 @ucmp_8_32_zero(i32 %x) nounwind {
+; CHECK-LABEL: ucmp_8_32_zero:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: mov r1, #0
+; CHECK-NEXT: cmp r0, #0
+; CHECK-NEXT: movwhi r1, #1
+; CHECK-NEXT: mvnlo r1, #0
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: bx lr
+;
+; THUMB-LABEL: ucmp_8_32_zero:
+; THUMB: @ %bb.0:
+; THUMB-NEXT: movs r1, #0
+; THUMB-NEXT: cmp r1, r0
+; THUMB-NEXT: sbcs r1, r1
+; THUMB-NEXT: subs r0, r0, #0
+; THUMB-NEXT: sbcs r0, r0
+; THUMB-NEXT: subs r0, r0, r1
+; THUMB-NEXT: bx lr
+ %1 = call i8 @llvm.ucmp(i32 %x, i32 0)
+ ret i8 %1
+}
>From c7c63f82b9f3a0ea201a7715c0f1d3688533cc77 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Fri, 3 Jul 2026 11:27:06 -0400
Subject: [PATCH 2/2] [ARM] Special case scmp 0
We can use cmp instead of subs for scmp 0, and we can do shifts for scmp 0 too.
---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 84 ++++++++++++-------------
llvm/test/CodeGen/ARM/scmp.ll | 12 ++--
llvm/test/CodeGen/ARM/ucmp.ll | 12 ++--
3 files changed, 49 insertions(+), 59 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 577e97e736c25..b155bb2742110 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -592,11 +592,10 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_,
setOperationAction(ISD::BSWAP, VT, Expand);
}
- if (!Subtarget->isThumb1Only() && !Subtarget->hasV8_1MMainlineOps())
+ if (!Subtarget->hasV8_1MMainlineOps()) {
setOperationAction(ISD::SCMP, MVT::i32, Custom);
-
- if (!Subtarget->hasV8_1MMainlineOps())
setOperationAction(ISD::UCMP, MVT::i32, Custom);
+ }
if (!Subtarget->isThumb1Only())
setOperationAction(ISD::ABS, MVT::i32, Custom);
@@ -10388,10 +10387,25 @@ SDValue ARMTargetLowering::LowerCMP(SDValue Op, SelectionDAG &DAG) const {
// Final subtraction: Sbc1Result - Sbc2Result (no flags needed)
SDValue Result =
DAG.getNode(ISD::SUB, dl, MVT::i32, Sbc1Result, Sbc2Result);
- if (Op.getValueType() != MVT::i32)
- Result = DAG.getSExtOrTrunc(Result, dl, Op.getValueType());
+ return DAG.getSExtOrTrunc(Result, dl, Op.getValueType());
+ }
- return Result;
+ // Optimize scmp with 0 using (x ashr 31) | (-x shr 31)
+ if (Subtarget->isThumb1Only()) {
+ if (!isNullConstant(RHS))
+ return SDValue();
+
+ // Freeze?
+ LHS = DAG.getFreeze(LHS);
+ EVT VT = LHS.getValueType();
+ unsigned BitWidth = VT.getScalarSizeInBits();
+ SDValue ShiftAmount = DAG.getShiftAmountConstant(BitWidth - 1, VT, dl);
+ SDValue SignShift = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmount);
+ SDValue NegX =
+ DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, dl, VT), LHS);
+ SDValue LshrNeg = DAG.getNode(ISD::SRL, dl, VT, NegX, ShiftAmount);
+ SDValue Res = DAG.getNode(ISD::OR, dl, VT, SignShift, LshrNeg);
+ return DAG.getSExtOrTrunc(Res, dl, Op.getValueType());
}
// For the ARM assembly pattern:
@@ -10404,42 +10418,29 @@ SDValue ARMTargetLowering::LowerCMP(SDValue Op, SelectionDAG &DAG) const {
// Optimization: if RHS is a subtraction against 0, use ADDC instead of SUBC
unsigned Opcode = ARMISD::SUBC;
- // Check if RHS is a subtraction against 0: (0 - X)
- if (RHS.getOpcode() == ISD::SUB) {
- SDValue SubLHS = RHS.getOperand(0);
- SDValue SubRHS = RHS.getOperand(1);
-
- // Check if it's 0 - X
- if (isNullConstant(SubLHS)) {
- bool CanUseAdd = false;
- if (IsSigned) {
- // For SCMP: only if X is known to never be INT_MIN (to avoid overflow)
- if (RHS->getFlags().hasNoSignedWrap() || !DAG.computeKnownBits(SubRHS)
- .getSignedMinValue()
- .isMinSignedValue()) {
- CanUseAdd = true;
- }
- } else {
- // For UCMP: only if X is known to never be zero
- if (DAG.isKnownNeverZero(SubRHS)) {
- CanUseAdd = true;
- }
- }
-
- if (CanUseAdd) {
- Opcode = ARMISD::ADDC;
- RHS = SubRHS; // Replace RHS with X, so we do LHS + X instead of
- // LHS - (0 - X)
- }
- }
+ ISD::CondCode CC = IsSigned ? ISD::SETGT : ISD::SETUGT;
+ if (isCMN(RHS, CC, DAG)) {
+ Opcode = ARMISD::ADDC;
+ RHS = RHS.getOperand(1); // Replace RHS with X, so we do LHS + X instead of
+ // LHS - (0 - X)
}
- // Generate the operation with flags
- SDValue OpWithFlags =
- DAG.getNode(Opcode, dl, DAG.getVTList(MVT::i32, FlagsVT), LHS, RHS);
+ // isCMN should not return true for 0
+ bool isCmp = isNullConstant(RHS);
+ assert((Opcode != ARMISD::ADDC || !isCmp) && "isCMN should not return true for 0");
- SDValue OpResult = OpWithFlags.getValue(0);
- SDValue Flags = OpWithFlags.getValue(1);
+ // Generate the operation with flags
+ SDValue OpResult;
+ SDValue Flags;
+ if (isCmp) {
+ OpResult = LHS;
+ Flags = DAG.getNode(ARMISD::CMP, dl, FlagsVT, LHS, RHS);
+ } else {
+ SDValue OpWithFlags =
+ DAG.getNode(Opcode, dl, DAG.getVTList(MVT::i32, FlagsVT), LHS, RHS);
+ OpResult = OpWithFlags.getValue(0);
+ Flags = OpWithFlags.getValue(1);
+ }
// Constants for conditional moves
SDValue One = DAG.getConstant(1, dl, MVT::i32);
@@ -10459,10 +10460,7 @@ SDValue ARMTargetLowering::LowerCMP(SDValue Op, SelectionDAG &DAG) const {
SDValue Result2 = DAG.getNode(ARMISD::CMOV, dl, MVT::i32, Result1, MinusOne,
LTCondValue, Flags);
- if (Op.getValueType() != MVT::i32)
- Result2 = DAG.getSExtOrTrunc(Result2, dl, Op.getValueType());
-
- return Result2;
+ return DAG.getSExtOrTrunc(Result2, dl, Op.getValueType());
}
SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
diff --git a/llvm/test/CodeGen/ARM/scmp.ll b/llvm/test/CodeGen/ARM/scmp.ll
index 168a3f90be33c..da748d3966fd5 100644
--- a/llvm/test/CodeGen/ARM/scmp.ll
+++ b/llvm/test/CodeGen/ARM/scmp.ll
@@ -359,11 +359,9 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
define i32 @scmp_32_32_zero(i32 %x) nounwind {
; CHECK-LABEL: scmp_32_32_zero:
; CHECK: @ %bb.0:
-; CHECK-NEXT: mov r1, #0
; CHECK-NEXT: cmp r0, #0
-; CHECK-NEXT: movwgt r1, #1
-; CHECK-NEXT: mvnlt r1, #0
-; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: movwgt r0, #1
+; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
;
; THUMB-LABEL: scmp_32_32_zero:
@@ -380,11 +378,9 @@ define i32 @scmp_32_32_zero(i32 %x) nounwind {
define i8 @scmp_8_32_zero(i32 %x) nounwind {
; CHECK-LABEL: scmp_8_32_zero:
; CHECK: @ %bb.0:
-; CHECK-NEXT: mov r1, #0
; CHECK-NEXT: cmp r0, #0
-; CHECK-NEXT: movwgt r1, #1
-; CHECK-NEXT: mvnlt r1, #0
-; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: movwgt r0, #1
+; CHECK-NEXT: mvnlt r0, #0
; CHECK-NEXT: bx lr
;
; THUMB-LABEL: scmp_8_32_zero:
diff --git a/llvm/test/CodeGen/ARM/ucmp.ll b/llvm/test/CodeGen/ARM/ucmp.ll
index 6cafe778e9a31..1ff22c2c5ca18 100644
--- a/llvm/test/CodeGen/ARM/ucmp.ll
+++ b/llvm/test/CodeGen/ARM/ucmp.ll
@@ -283,11 +283,9 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
define i32 @ucmp_32_32_zero(i32 %x) nounwind {
; CHECK-LABEL: ucmp_32_32_zero:
; CHECK: @ %bb.0:
-; CHECK-NEXT: mov r1, #0
; CHECK-NEXT: cmp r0, #0
-; CHECK-NEXT: movwhi r1, #1
-; CHECK-NEXT: mvnlo r1, #0
-; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: movwhi r0, #1
+; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
;
; THUMB-LABEL: ucmp_32_32_zero:
@@ -306,11 +304,9 @@ define i32 @ucmp_32_32_zero(i32 %x) nounwind {
define i8 @ucmp_8_32_zero(i32 %x) nounwind {
; CHECK-LABEL: ucmp_8_32_zero:
; CHECK: @ %bb.0:
-; CHECK-NEXT: mov r1, #0
; CHECK-NEXT: cmp r0, #0
-; CHECK-NEXT: movwhi r1, #1
-; CHECK-NEXT: mvnlo r1, #0
-; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: movwhi r0, #1
+; CHECK-NEXT: mvnlo r0, #0
; CHECK-NEXT: bx lr
;
; THUMB-LABEL: ucmp_8_32_zero:
More information about the llvm-commits
mailing list