[llvm] [AArch64] Extend SBC combine to handle CSET HI (PR #192708)

Ricardo Jesus via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 21 07:13:16 PDT 2026


================
@@ -129,27 +129,188 @@ define i32 @test_sext_add(i32 %a, i32 %b, i32 %x, i32 %y) {
   ret i32 %res
 }
 
-; FIXME: This case could be supported with reversed operands to the CMP.
 define i32 @test_ugt(i32 %a, i32 %b, i32 %x, i32 %y) {
 ; CHECK-SD-LABEL: test_ugt:
 ; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    cmp w1, w0
+; CHECK-SD-NEXT:    sbc w0, w2, w3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: test_ugt:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp w0, w1
+; CHECK-GI-NEXT:    sub w9, w2, w3
+; CHECK-GI-NEXT:    cset w8, hi
+; CHECK-GI-NEXT:    sub w0, w9, w8
+; CHECK-GI-NEXT:    ret
+  %cc = icmp ugt i32 %a, %b
+  %carry = zext i1 %cc to i32
+  %sub = sub i32 %x, %y
+  %res = sub i32 %sub, %carry
+  ret i32 %res
+}
+
+define i64 @test_ugt_mixed_i32_i64(i32 %a, i32 %b, i64 %x, i64 %y) {
+; CHECK-SD-LABEL: test_ugt_mixed_i32_i64:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    cmp w1, w0
+; CHECK-SD-NEXT:    sbc x0, x2, x3
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: test_ugt_mixed_i32_i64:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp w0, w1
+; CHECK-GI-NEXT:    sub x9, x2, x3
+; CHECK-GI-NEXT:    cset w8, hi
+; CHECK-GI-NEXT:    sub x0, x9, x8
+; CHECK-GI-NEXT:    ret
+  %cc = icmp ugt i32 %a, %b
+  %carry = zext i1 %cc to i64
+  %sub = sub i64 %x, %y
+  %res = sub i64 %sub, %carry
+  ret i64 %res
+}
+
+define i32 @test_ugt_multi_use_flags(i32 %a, i32 %b, i32 %x, i32 %y, i32 %z) {
+; CHECK-SD-LABEL: test_ugt_multi_use_flags:
+; CHECK-SD:       // %bb.0:
 ; CHECK-SD-NEXT:    cmp w0, w1
 ; CHECK-SD-NEXT:    sub w8, w2, w3
 ; CHECK-SD-NEXT:    cset w9, hi
-; CHECK-SD-NEXT:    sub w0, w8, w9
+; CHECK-SD-NEXT:    cmp w0, w1
+; CHECK-SD-NEXT:    sub w8, w8, w9
+; CHECK-SD-NEXT:    csel w0, w8, w4, eq
 ; CHECK-SD-NEXT:    ret
 ;
-; CHECK-GI-LABEL: test_ugt:
+; CHECK-GI-LABEL: test_ugt_multi_use_flags:
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    cmp w0, w1
 ; CHECK-GI-NEXT:    sub w9, w2, w3
 ; CHECK-GI-NEXT:    cset w8, hi
-; CHECK-GI-NEXT:    sub w0, w9, w8
+; CHECK-GI-NEXT:    sub w8, w9, w8
+; CHECK-GI-NEXT:    csel w0, w8, w4, eq
 ; CHECK-GI-NEXT:    ret
   %cc = icmp ugt i32 %a, %b
   %carry = zext i1 %cc to i32
   %sub = sub i32 %x, %y
   %res = sub i32 %sub, %carry
+  %cc2 = icmp eq i32 %a, %b
+  %sel = select i1 %cc2, i32 %res, i32 %z
+  ret i32 %sel
+}
+
+define i32 @test_ugt_42(i32 %a, i32 %x, i32 %y) {
+; CHECK-SD-LABEL: test_ugt_42:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    mov w8, #42 // =0x2a
+; CHECK-SD-NEXT:    cmp w8, w0
+; CHECK-SD-NEXT:    sbc w0, w1, w2
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: test_ugt_42:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp w0, #42
+; CHECK-GI-NEXT:    sub w9, w1, w2
+; CHECK-GI-NEXT:    cset w8, hi
+; CHECK-GI-NEXT:    sub w0, w9, w8
+; CHECK-GI-NEXT:    ret
+  %cc = icmp ugt i32 %a, 42
+  %carry = zext i1 %cc to i32
+  %sub = sub i32 %x, %y
+  %res = sub i32 %sub, %carry
+  ret i32 %res
+}
+
+define i32 @test_only_borrow_ugt_42(i32 %a, i32 %x) {
+; CHECK-LABEL: test_only_borrow_ugt_42:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    cmp w0, #42
+; CHECK-NEXT:    cset w8, hi
+; CHECK-NEXT:    sub w0, w1, w8
+; CHECK-NEXT:    ret
+  %cc = icmp ugt i32 %a, 42
+  %carry = zext i1 %cc to i32
+  %res = sub i32 %x, %carry
+  ret i32 %res
+}
+
+define i32 @test_only_borrow_ugt_42_combine(i32 %a, i32 %x) {
+; CHECK-LABEL: test_only_borrow_ugt_42_combine:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    cmp w0, #42
+; CHECK-NEXT:    cset w8, hi
+; CHECK-NEXT:    sub w0, w1, w8
+; CHECK-NEXT:    ret
+  %cc = icmp ugt i32 %a, 42
+  %carry = zext i1 %cc to i32
+  %res = sub i32 %x, %carry
+  ret i32 %res
+}
----------------
rj-jesus wrote:

Could you please update this test to include a sub with the same operands as the icmp? This test was meant to ensure we don't increase code size by swapping operands when the compare and a sub can be combined to a single instruction. For example:
```
define i32 @test_only_borrow_ugt_42_combine(i32 %a, i32 %x) {
  %cc = icmp ugt i32 %a, 42
  %carry = zext i1 %cc to i32
  %res = sub i32 %x, %carry
  %sub42 = sub i32 %a, 42
  call void @use(i32 %sub42)
  ret i32 %res
}
```

https://github.com/llvm/llvm-project/pull/192708


More information about the llvm-commits mailing list