[llvm] [SwitchLowering] Support merging 0 and power-of-2 case. (PR #139736)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun May 25 04:02:41 PDT 2025


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/139736

>From 53277f29549126e1afd7e091948d80f8df669133 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 27 Mar 2025 21:25:57 +0000
Subject: [PATCH 1/2] Add test case

---
 .../AArch64/switch-cases-to-branch-and.ll     | 595 ++++++++++++++++++
 1 file changed, 595 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll

diff --git a/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
new file mode 100644
index 0000000000000..04d4ce8493e1b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
@@ -0,0 +1,595 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -O3 -mtriple=arm64-apple-macosx -o - %s | FileCheck %s
+
+define i32 @switch_with_matching_dests_0_and_pow2_3_cases(i8 %v) {
+; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:  LBB0_1: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ands w10, w0, #0xff
+; CHECK-NEXT:    b.eq LBB0_6
+; CHECK-NEXT:  ; %bb.2: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT:    cmp w10, #32
+; CHECK-NEXT:    b.eq LBB0_6
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT:    cmp w10, #124
+; CHECK-NEXT:    b.eq LBB0_7
+; CHECK-NEXT:  ; %bb.4: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.ne LBB0_1
+; CHECK-NEXT:  ; %bb.5:
+; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:  LBB0_6: ; %common.ret
+; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB0_7: ; %e2
+; CHECK-NEXT:    mov w0, #30 ; =0x1e
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i8 %v, label %loop.latch [
+  i8 32, label %e1
+  i8 0, label %e1
+  i8 124, label %e2
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %c = icmp eq i32 %iv.next, 100
+  br i1 %c, label %e1, label %loop.header
+
+e1:
+  ret i32 20
+
+e2:
+  ret i32 30
+}
+
+define i32 @switch_with_matching_dests_0_and_pow2_3_cases_swapped(i8 %v) {
+; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases_swapped:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:  LBB1_1: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ands w10, w0, #0xff
+; CHECK-NEXT:    b.eq LBB1_6
+; CHECK-NEXT:  ; %bb.2: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
+; CHECK-NEXT:    cmp w10, #32
+; CHECK-NEXT:    b.eq LBB1_6
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
+; CHECK-NEXT:    cmp w10, #124
+; CHECK-NEXT:    b.eq LBB1_7
+; CHECK-NEXT:  ; %bb.4: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.ne LBB1_1
+; CHECK-NEXT:  ; %bb.5:
+; CHECK-NEXT:    mov w8, #10 ; =0xa
+; CHECK-NEXT:  LBB1_6: ; %common.ret
+; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB1_7: ; %e2
+; CHECK-NEXT:    mov w0, #30 ; =0x1e
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i8 %v, label %loop.latch [
+  i8 0, label %e1
+  i8 32, label %e1
+  i8 124, label %e2
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %c = icmp eq i32 %iv.next, 100
+  br i1 %c, label %e0, label %loop.header
+
+e0:
+  ret i32 10
+
+e1:
+  ret i32 20
+
+e2:
+  ret i32 30
+}
+
+define i32 @switch_with_matching_dests_0_and_pow2_3_cases_with_phi(i8 %v, i1 %c) {
+; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases_with_phi:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    tbz w1, #0, LBB2_8
+; CHECK-NEXT:  ; %bb.1: ; %loop.header.preheader
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:  LBB2_2: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ands w10, w0, #0xff
+; CHECK-NEXT:    b.eq LBB2_7
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
+; CHECK-NEXT:    cmp w10, #32
+; CHECK-NEXT:    b.eq LBB2_7
+; CHECK-NEXT:  ; %bb.4: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
+; CHECK-NEXT:    cmp w10, #124
+; CHECK-NEXT:    b.eq LBB2_9
+; CHECK-NEXT:  ; %bb.5: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.ne LBB2_2
+; CHECK-NEXT:  ; %bb.6:
+; CHECK-NEXT:    mov w8, #10 ; =0xa
+; CHECK-NEXT:  LBB2_7: ; %common.ret
+; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB2_8:
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB2_9: ; %e2
+; CHECK-NEXT:    mov w0, #30 ; =0x1e
+; CHECK-NEXT:    ret
+entry:
+  br i1 %c, label %then, label %e1
+
+then:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %then], [ %iv.next, %loop.latch ]
+  switch i8 %v, label %loop.latch [
+  i8 32, label %e1
+  i8 0, label %e1
+  i8 124, label %e2
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, 100
+  br i1 %ec, label %e0, label %loop.header
+
+e0:
+  ret i32 10
+
+e1:
+  %p = phi i32 [ 0, %entry ], [ 20, %loop.header ], [ 20, %loop.header ]
+  ret i32 %p
+
+e2:
+  ret i32 30
+}
+
+define i32 @switch_with_matching_dests_0_and_pow2_3_cases_all_different_succs(i8 %v) {
+; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases_all_different_succs:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w8, #100 ; =0x64
+; CHECK-NEXT:  LBB3_1: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ands w9, w0, #0xff
+; CHECK-NEXT:    b.eq LBB3_6
+; CHECK-NEXT:  ; %bb.2: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB3_1 Depth=1
+; CHECK-NEXT:    cmp w9, #32
+; CHECK-NEXT:    b.eq LBB3_8
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB3_1 Depth=1
+; CHECK-NEXT:    cmp w9, #124
+; CHECK-NEXT:    b.eq LBB3_7
+; CHECK-NEXT:  ; %bb.4: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB3_1 Depth=1
+; CHECK-NEXT:    subs w8, w8, #1
+; CHECK-NEXT:    b.ne LBB3_1
+; CHECK-NEXT:  ; %bb.5:
+; CHECK-NEXT:    mov w0, #10 ; =0xa
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB3_6: ; %e2
+; CHECK-NEXT:    mov w0, #30 ; =0x1e
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB3_7: ; %e3
+; CHECK-NEXT:    mov w0, #40 ; =0x28
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB3_8:
+; CHECK-NEXT:    mov w0, #20 ; =0x14
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i8 %v, label %loop.latch [
+  i8 32, label %e1
+  i8 0, label %e2
+  i8 124, label %e3
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, 100
+  br i1 %ec, label %e0, label %loop.header
+
+e0:
+  ret i32 10
+
+e1:
+  ret i32 20
+
+e2:
+  ret i32 30
+
+e3:
+  ret i32 40
+}
+
+define i32 @switch_in_loop_with_matching_dests_0_and_pow2_3_cases(ptr %start) {
+; CHECK-LABEL: switch_in_loop_with_matching_dests_0_and_pow2_3_cases:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    add x8, x0, #1
+; CHECK-NEXT:  LBB4_1: ; %loop
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w9, [x8], #1
+; CHECK-NEXT:    cbz w9, LBB4_4
+; CHECK-NEXT:  ; %bb.2: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB4_1 Depth=1
+; CHECK-NEXT:    cmp w9, #124
+; CHECK-NEXT:    b.eq LBB4_5
+; CHECK-NEXT:  ; %bb.3: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB4_1 Depth=1
+; CHECK-NEXT:    cmp w9, #32
+; CHECK-NEXT:    b.ne LBB4_1
+; CHECK-NEXT:  LBB4_4: ; %e1
+; CHECK-NEXT:    mov w0, #-1 ; =0xffffffff
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB4_5: ; %e2.loopexit
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+entry:
+  br label %loop
+
+loop:
+  %p = phi ptr [ %start, %entry ], [ %4, %loop ]
+  %4 = getelementptr inbounds nuw i8, ptr %p, i64 1
+  %l = load i8, ptr %4, align 1
+  switch i8 %l, label %loop [
+  i8 32, label %e1
+  i8 0, label %e1
+  i8 124, label %e2
+  ]
+
+e1:
+  br label %e2
+
+e2:
+  %8 = phi i32 [ -1, %e1 ], [ 0, %loop ]
+  ret i32 %8
+}
+
+define i32 @switch_in_loop_with_matching_dests_0_and_pow2_4_cases(ptr %start) {
+; CHECK-LABEL: switch_in_loop_with_matching_dests_0_and_pow2_4_cases:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov x10, #32769 ; =0x8001
+; CHECK-NEXT:    mov w8, #1 ; =0x1
+; CHECK-NEXT:    add x9, x0, #1
+; CHECK-NEXT:    movk x10, #1, lsl #32
+; CHECK-NEXT:    b LBB5_2
+; CHECK-NEXT:  LBB5_1: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB5_2 Depth=1
+; CHECK-NEXT:    cmp w11, #124
+; CHECK-NEXT:    b.eq LBB5_5
+; CHECK-NEXT:  LBB5_2: ; %loop
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w11, [x9], #1
+; CHECK-NEXT:    cmp w11, #32
+; CHECK-NEXT:    b.hi LBB5_1
+; CHECK-NEXT:  ; %bb.3: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB5_2 Depth=1
+; CHECK-NEXT:    lsl x12, x8, x11
+; CHECK-NEXT:    tst x12, x10
+; CHECK-NEXT:    b.eq LBB5_1
+; CHECK-NEXT:  ; %bb.4: ; %e1
+; CHECK-NEXT:    mov w0, #-1 ; =0xffffffff
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB5_5: ; %e2.loopexit
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+entry:
+  br label %loop
+
+loop:
+  %p = phi ptr [ %start, %entry ], [ %4, %loop ]
+  %4 = getelementptr inbounds nuw i8, ptr %p, i64 1
+  %l = load i8, ptr %4, align 1
+  switch i8 %l, label %loop [
+  i8 0, label %e1
+  i8 15, label %e1
+  i8 32, label %e1
+  i8 124, label %e2
+  ]
+
+e1:
+  br label %e2
+
+e2:
+  %8 = phi i32 [ -1, %e1 ], [ 0, %loop ]
+  ret i32 %8
+}
+
+define i32 @switch_in_loop_with_matching_dests_0_and_non_pow2(ptr %start) {
+; CHECK-LABEL: switch_in_loop_with_matching_dests_0_and_non_pow2:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    add x8, x0, #1
+; CHECK-NEXT:  LBB6_1: ; %loop
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldrb w9, [x8], #1
+; CHECK-NEXT:    cmp w9, #35
+; CHECK-NEXT:    b.eq LBB6_4
+; CHECK-NEXT:  ; %bb.2: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB6_1 Depth=1
+; CHECK-NEXT:    cmp w9, #33
+; CHECK-NEXT:    b.eq LBB6_5
+; CHECK-NEXT:  ; %bb.3: ; %loop
+; CHECK-NEXT:    ; in Loop: Header=BB6_1 Depth=1
+; CHECK-NEXT:    cbnz w9, LBB6_1
+; CHECK-NEXT:  LBB6_4: ; %common.ret.loopexit
+; CHECK-NEXT:    mov w0, #-1 ; =0xffffffff
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB6_5: ; %e2
+; CHECK-NEXT:    mov w0, #10 ; =0xa
+; CHECK-NEXT:    ret
+entry:
+  br label %loop
+
+loop:
+  %p = phi ptr [ %start, %entry ], [ %4, %loop ]
+  %4 = getelementptr inbounds nuw i8, ptr %p, i64 1
+  %l = load i8, ptr %4, align 1
+  switch i8 %l, label %loop [
+  i8 0, label %e1
+  i8 35, label %e1
+  i8 33, label %e2
+  ]
+
+e1:
+  ret i32 -1
+
+e2:
+  ret i32 10
+}
+
+define void @test_successor_with_loop_phi(ptr %A, ptr %B) {
+; CHECK-LABEL: test_successor_with_loop_phi:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:  LBB7_1: ; %loop
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    ldr w8, [x0]
+; CHECK-NEXT:    str wzr, [x0]
+; CHECK-NEXT:    mov x0, x1
+; CHECK-NEXT:    orr w8, w8, #0x4
+; CHECK-NEXT:    cmp w8, #4
+; CHECK-NEXT:    b.eq LBB7_1
+; CHECK-NEXT:  ; %bb.2: ; %exit
+; CHECK-NEXT:    ret
+entry:
+  br label %loop
+
+loop:
+  %p = phi ptr [ %A, %entry ], [ %B , %loop ], [ %B, %loop ]
+  %l = load i32, ptr %p
+  store i32 0, ptr %p
+  switch i32 %l, label %exit [
+  i32 4, label %loop
+  i32 0, label %loop
+  ]
+
+exit:
+  ret void
+}
+
+define i64 @consecutive_match_both(ptr %p, i32 %param) {
+; CHECK-LABEL: consecutive_match_both:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w8, #1 ; =0x1
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w10, #249 ; =0xf9
+; CHECK-NEXT:    lsl w8, w8, w1
+; CHECK-NEXT:    b LBB8_2
+; CHECK-NEXT:  LBB8_1: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB8_2 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.eq LBB8_5
+; CHECK-NEXT:  LBB8_2: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    cmp w1, #7
+; CHECK-NEXT:    b.hi LBB8_1
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB8_2 Depth=1
+; CHECK-NEXT:    tst w8, w10
+; CHECK-NEXT:    b.eq LBB8_1
+; CHECK-NEXT:  ; %bb.4: ; %e0
+; CHECK-NEXT:    mov x0, xzr
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB8_5:
+; CHECK-NEXT:    mov x0, #-42 ; =0xffffffffffffffd6
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i32 %param, label %loop.latch [
+  i32 7, label %e0
+  i32 6, label %e0
+  i32 5, label %e0
+  i32 4, label %e0
+  i32 3, label %e0
+  i32 0, label %e0
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, 100
+  br i1 %ec, label %e1, label %loop.header
+
+e0:
+  %m = getelementptr i8, ptr %p, i64 20
+  br label %e1
+
+e1:
+  %res = phi i64 [ 0, %e0 ], [ -42, %loop.latch ]
+  ret i64 %res
+}
+
+define i64 @consecutive_match_before(ptr %p, i32 %param) {
+; CHECK-LABEL: consecutive_match_before:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w8, #1 ; =0x1
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w10, #25 ; =0x19
+; CHECK-NEXT:    lsl w8, w8, w1
+; CHECK-NEXT:    b LBB9_2
+; CHECK-NEXT:  LBB9_1: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB9_2 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.eq LBB9_5
+; CHECK-NEXT:  LBB9_2: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    cmp w1, #4
+; CHECK-NEXT:    b.hi LBB9_1
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB9_2 Depth=1
+; CHECK-NEXT:    tst w8, w10
+; CHECK-NEXT:    b.eq LBB9_1
+; CHECK-NEXT:  ; %bb.4: ; %e0
+; CHECK-NEXT:    mov x0, xzr
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB9_5:
+; CHECK-NEXT:    mov x0, #-42 ; =0xffffffffffffffd6
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i32 %param, label %loop.latch [
+  i32 4, label %e0
+  i32 3, label %e0
+  i32 0, label %e0
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, 100
+  br i1 %ec, label %e1, label %loop.header
+
+e0:
+  %m = getelementptr i8, ptr %p, i64 20
+  br label %e1
+
+e1:
+  %res = phi i64 [ 0, %e0 ], [ -42, %loop.latch ]
+  ret i64 %res
+}
+
+define i64 @consecutive_match_after(ptr %p, i32 %param) {
+; CHECK-LABEL: consecutive_match_after:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    mov w8, #1 ; =0x1
+; CHECK-NEXT:    mov w9, #100 ; =0x64
+; CHECK-NEXT:    mov w10, #49 ; =0x31
+; CHECK-NEXT:    lsl w8, w8, w1
+; CHECK-NEXT:    b LBB10_2
+; CHECK-NEXT:  LBB10_1: ; %loop.latch
+; CHECK-NEXT:    ; in Loop: Header=BB10_2 Depth=1
+; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    b.eq LBB10_5
+; CHECK-NEXT:  LBB10_2: ; %loop.header
+; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    cmp w1, #5
+; CHECK-NEXT:    b.hi LBB10_1
+; CHECK-NEXT:  ; %bb.3: ; %loop.header
+; CHECK-NEXT:    ; in Loop: Header=BB10_2 Depth=1
+; CHECK-NEXT:    tst w8, w10
+; CHECK-NEXT:    b.eq LBB10_1
+; CHECK-NEXT:  ; %bb.4: ; %e0
+; CHECK-NEXT:    mov x0, xzr
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB10_5:
+; CHECK-NEXT:    mov x0, #-42 ; =0xffffffffffffffd6
+; CHECK-NEXT:    ret
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
+  switch i32 %param, label %loop.latch [
+  i32 5, label %e0
+  i32 4, label %e0
+  i32 0, label %e0
+  ]
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, 100
+  br i1 %ec, label %e1, label %loop.header
+
+e0:
+  %m = getelementptr i8, ptr %p, i64 20
+  br label %e1
+
+e1:
+  %res = phi i64 [ 0, %e0 ], [ -42, %loop.latch ]
+  ret i64 %res
+}
+
+define void @merge_with_stores(ptr %A, i16 %v) {
+; CHECK-LABEL: merge_with_stores:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    and w8, w1, #0xffff
+; CHECK-NEXT:    sub w9, w8, #10
+; CHECK-NEXT:    cmp w9, #2
+; CHECK-NEXT:    b.lo LBB11_4
+; CHECK-NEXT:  ; %bb.1: ; %entry
+; CHECK-NEXT:    cbz w8, LBB11_5
+; CHECK-NEXT:  ; %bb.2: ; %entry
+; CHECK-NEXT:    cmp w8, #2
+; CHECK-NEXT:    b.eq LBB11_5
+; CHECK-NEXT:  ; %bb.3: ; %default.dst
+; CHECK-NEXT:    strh wzr, [x0]
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB11_4: ; %other.dst
+; CHECK-NEXT:    mov w8, #1 ; =0x1
+; CHECK-NEXT:    strh w8, [x0, #36]
+; CHECK-NEXT:  LBB11_5: ; %pow2.dst
+; CHECK-NEXT:    ret
+entry:
+  switch i16 %v, label %default.dst [
+    i16 10, label %other.dst
+    i16 0, label %pow2.dst
+    i16 2, label %pow2.dst
+    i16 11, label %other.dst
+  ]
+
+default.dst:
+  store i16 0, ptr %A, align 8
+  br label %pow2.dst
+
+other.dst:
+  %gep = getelementptr i8, ptr %A, i64 36
+  store i16 1, ptr %gep, align 8
+  br label %pow2.dst
+
+pow2.dst:
+  ret void
+}

>From 9c5fe8e3953188b592f88c80a1ad20d57fb466da Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 13 May 2025 15:02:30 +0100
Subject: [PATCH 2/2] [SwitchLowering] Support merging 0 and power-of-2 case.

---
 .../llvm/CodeGen/GlobalISel/IRTranslator.h    |  14 +-
 .../llvm/CodeGen/SwitchLoweringUtils.h        |   5 +-
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |  23 ++--
 .../SelectionDAG/SelectionDAGBuilder.cpp      |  16 ++-
 llvm/lib/CodeGen/SwitchLoweringUtils.cpp      |  34 +++++
 .../AArch64/switch-cases-to-branch-and.ll     | 128 ++++++++----------
 6 files changed, 127 insertions(+), 93 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 6fd05c8fddd5f..b1ae8171ce2d2 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -405,13 +405,13 @@ class IRTranslator : public MachineFunctionPass {
       BranchProbability UnhandledProbs, SwitchCG::CaseClusterIt I,
       MachineBasicBlock *Fallthrough, bool FallthroughUnreachable);
 
-  bool lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I, Value *Cond,
-                                MachineBasicBlock *Fallthrough,
-                                bool FallthroughUnreachable,
-                                BranchProbability UnhandledProbs,
-                                MachineBasicBlock *CurMBB,
-                                MachineIRBuilder &MIB,
-                                MachineBasicBlock *SwitchMBB);
+  bool lowerSwitchAndOrRangeWorkItem(SwitchCG::CaseClusterIt I, Value *Cond,
+                                     MachineBasicBlock *Fallthrough,
+                                     bool FallthroughUnreachable,
+                                     BranchProbability UnhandledProbs,
+                                     MachineBasicBlock *CurMBB,
+                                     MachineIRBuilder &MIB,
+                                     MachineBasicBlock *SwitchMBB);
 
   bool lowerBitTestWorkItem(
       SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
diff --git a/llvm/include/llvm/CodeGen/SwitchLoweringUtils.h b/llvm/include/llvm/CodeGen/SwitchLoweringUtils.h
index 9f1d6f7b4f952..6b7cb8d9ce45a 100644
--- a/llvm/include/llvm/CodeGen/SwitchLoweringUtils.h
+++ b/llvm/include/llvm/CodeGen/SwitchLoweringUtils.h
@@ -35,7 +35,8 @@ enum CaseClusterKind {
   /// A cluster of cases suitable for jump table lowering.
   CC_JumpTable,
   /// A cluster of cases suitable for bit test lowering.
-  CC_BitTests
+  CC_BitTests,
+  CC_And
 };
 
 /// A cluster of case labels.
@@ -141,6 +142,8 @@ struct CaseBlock {
   BranchProbability TrueProb, FalseProb;
   bool IsUnpredictable;
 
+  bool EmitAnd = false;
+
   // Constructor for SelectionDAG.
   CaseBlock(ISD::CondCode cc, const Value *cmplhs, const Value *cmprhs,
             const Value *cmpmiddle, MachineBasicBlock *truebb,
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index fe5dcd14d8804..eb07a730ac8d5 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -1059,18 +1059,15 @@ bool IRTranslator::lowerJumpTableWorkItem(SwitchCG::SwitchWorkListItem W,
   }
   return true;
 }
-bool IRTranslator::lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I,
-                                            Value *Cond,
-                                            MachineBasicBlock *Fallthrough,
-                                            bool FallthroughUnreachable,
-                                            BranchProbability UnhandledProbs,
-                                            MachineBasicBlock *CurMBB,
-                                            MachineIRBuilder &MIB,
-                                            MachineBasicBlock *SwitchMBB) {
+bool IRTranslator::lowerSwitchAndOrRangeWorkItem(
+    SwitchCG::CaseClusterIt I, Value *Cond, MachineBasicBlock *Fallthrough,
+    bool FallthroughUnreachable, BranchProbability UnhandledProbs,
+    MachineBasicBlock *CurMBB, MachineIRBuilder &MIB,
+    MachineBasicBlock *SwitchMBB) {
   using namespace SwitchCG;
   const Value *RHS, *LHS, *MHS;
   CmpInst::Predicate Pred;
-  if (I->Low == I->High) {
+  if (I->Low == I->High || I->Kind == CC_And) {
     // Check Cond == I->Low.
     Pred = CmpInst::ICMP_EQ;
     LHS = Cond;
@@ -1088,6 +1085,7 @@ bool IRTranslator::lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I,
   // The false probability is the sum of all unhandled cases.
   CaseBlock CB(Pred, FallthroughUnreachable, LHS, RHS, MHS, I->MBB, Fallthrough,
                CurMBB, MIB.getDebugLoc(), I->Prob, UnhandledProbs);
+  CB.EmitAnd = I->Kind == CC_And;
 
   emitSwitchCase(CB, SwitchMBB, MIB);
   return true;
@@ -1327,10 +1325,11 @@ bool IRTranslator::lowerSwitchWorkItem(SwitchCG::SwitchWorkListItem W,
       }
       break;
     }
+    case CC_And:
     case CC_Range: {
-      if (!lowerSwitchRangeWorkItem(I, Cond, Fallthrough,
-                                    FallthroughUnreachable, UnhandledProbs,
-                                    CurMBB, MIB, SwitchMBB)) {
+      if (!lowerSwitchAndOrRangeWorkItem(I, Cond, Fallthrough,
+                                         FallthroughUnreachable, UnhandledProbs,
+                                         CurMBB, MIB, SwitchMBB)) {
         LLVM_DEBUG(dbgs() << "Failed to lower switch range");
         return false;
       }
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 434484b671bf2..9da2eaaae30c5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2857,7 +2857,17 @@ void SelectionDAGBuilder::visitSwitchCase(CaseBlock &CB,
   EVT MemVT = TLI.getMemValueType(DAG.getDataLayout(), CB.CmpLHS->getType());
 
   // Build the setcc now.
-  if (!CB.CmpMHS) {
+  if (CB.EmitAnd) {
+    SDLoc dl = getCurSDLoc();
+
+    const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+    EVT VT = TLI.getValueType(DAG.getDataLayout(), CB.CmpRHS->getType(), true);
+    SDValue C = DAG.getConstant(*cast<ConstantInt>(CB.CmpRHS), dl, VT);
+    SDValue Zero = DAG.getConstant(0, dl, VT);
+    SDValue CondLHS = getValue(CB.CmpLHS);
+    SDValue And = DAG.getNode(ISD::AND, dl, C.getValueType(), CondLHS, C);
+    Cond = DAG.getSetCC(dl, MVT::i1, And, Zero, ISD::SETEQ);
+  } else if (!CB.CmpMHS) {
     // Fold "(X == true)" to X and "(X == false)" to !X to
     // handle common cases produced by branch lowering.
     if (CB.CmpRHS == ConstantInt::getTrue(*DAG.getContext()) &&
@@ -12232,10 +12242,11 @@ void SelectionDAGBuilder::lowerWorkItem(SwitchWorkListItem W, Value *Cond,
         }
         break;
       }
+      case CC_And:
       case CC_Range: {
         const Value *RHS, *LHS, *MHS;
         ISD::CondCode CC;
-        if (I->Low == I->High) {
+        if (I->Low == I->High || I->Kind == CC_And) {
           // Check Cond == I->Low.
           CC = ISD::SETEQ;
           LHS = Cond;
@@ -12257,6 +12268,7 @@ void SelectionDAGBuilder::lowerWorkItem(SwitchWorkListItem W, Value *Cond,
         CaseBlock CB(CC, LHS, RHS, MHS, I->MBB, Fallthrough, CurMBB,
                      getCurSDLoc(), I->Prob, UnhandledProbs);
 
+        CB.EmitAnd = I->Kind == CC_And;
         if (CurMBB == SwitchMBB)
           visitSwitchCase(CB, SwitchMBB);
         else
diff --git a/llvm/lib/CodeGen/SwitchLoweringUtils.cpp b/llvm/lib/CodeGen/SwitchLoweringUtils.cpp
index 038c499fe236e..11122f120eddc 100644
--- a/llvm/lib/CodeGen/SwitchLoweringUtils.cpp
+++ b/llvm/lib/CodeGen/SwitchLoweringUtils.cpp
@@ -362,6 +362,40 @@ void SwitchCG::SwitchLowering::findBitTestClusters(CaseClusterVector &Clusters,
     }
   }
   Clusters.resize(DstIndex);
+
+  unsigned ZeroIdx = -1;
+  for (const auto &[Idx, C] : enumerate(Clusters)) {
+    if (C.Kind != CC_Range || C.Low != C.High)
+      continue;
+    if (C.Low->isZero()) {
+      ZeroIdx = Idx;
+      break;
+    }
+  }
+
+  if (ZeroIdx == -1u)
+    return;
+
+  unsigned Pow2Idx = -1;
+  for (const auto &[Idx, C] : enumerate(Clusters)) {
+    if (C.Kind != CC_Range || C.Low != C.High || C.MBB != Clusters[ZeroIdx].MBB)
+      continue;
+    if (C.Low->getValue().isPowerOf2()) {
+      Pow2Idx = Idx;
+      break;
+    }
+  }
+
+  if (Pow2Idx == -1u)
+    return;
+
+  APInt Pow2 = Clusters[Pow2Idx].Low->getValue();
+  APInt NewC = (Pow2 + 1) * -1;
+  Clusters[ZeroIdx].Low = ConstantInt::get(SI->getContext(), NewC);
+  Clusters[ZeroIdx].High = ConstantInt::get(SI->getContext(), NewC);
+  Clusters[ZeroIdx].Kind = CC_And;
+  Clusters[ZeroIdx].Prob += Clusters[Pow2Idx].Prob;
+  Clusters.erase(Clusters.begin() + Pow2Idx);
 }
 
 bool SwitchCG::SwitchLowering::buildBitTests(CaseClusterVector &Clusters,
diff --git a/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
index 04d4ce8493e1b..b6f3da072ec63 100644
--- a/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
+++ b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
@@ -4,30 +4,25 @@
 define i32 @switch_with_matching_dests_0_and_pow2_3_cases(i8 %v) {
 ; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases:
 ; CHECK:       ; %bb.0: ; %entry
-; CHECK-NEXT:    mov w9, #100 ; =0x64
-; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:    mov w8, #100 ; =0x64
+; CHECK-NEXT:    mov w9, #223 ; =0xdf
 ; CHECK-NEXT:  LBB0_1: ; %loop.header
 ; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ands w10, w0, #0xff
-; CHECK-NEXT:    b.eq LBB0_6
+; CHECK-NEXT:    tst w0, w9
+; CHECK-NEXT:    b.eq LBB0_4
 ; CHECK-NEXT:  ; %bb.2: ; %loop.header
 ; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
-; CHECK-NEXT:    cmp w10, #32
-; CHECK-NEXT:    b.eq LBB0_6
-; CHECK-NEXT:  ; %bb.3: ; %loop.header
-; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT:    and w10, w0, #0xff
 ; CHECK-NEXT:    cmp w10, #124
-; CHECK-NEXT:    b.eq LBB0_7
-; CHECK-NEXT:  ; %bb.4: ; %loop.latch
+; CHECK-NEXT:    b.eq LBB0_5
+; CHECK-NEXT:  ; %bb.3: ; %loop.latch
 ; CHECK-NEXT:    ; in Loop: Header=BB0_1 Depth=1
-; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    subs w8, w8, #1
 ; CHECK-NEXT:    b.ne LBB0_1
-; CHECK-NEXT:  ; %bb.5:
-; CHECK-NEXT:    mov w8, #20 ; =0x14
-; CHECK-NEXT:  LBB0_6: ; %common.ret
-; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:  LBB0_4:
+; CHECK-NEXT:    mov w0, #20 ; =0x14
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB0_7: ; %e2
+; CHECK-NEXT:  LBB0_5: ; %e2
 ; CHECK-NEXT:    mov w0, #30 ; =0x1e
 ; CHECK-NEXT:    ret
 entry:
@@ -56,30 +51,28 @@ e2:
 define i32 @switch_with_matching_dests_0_and_pow2_3_cases_swapped(i8 %v) {
 ; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases_swapped:
 ; CHECK:       ; %bb.0: ; %entry
-; CHECK-NEXT:    mov w9, #100 ; =0x64
-; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:    mov w8, #100 ; =0x64
+; CHECK-NEXT:    mov w9, #223 ; =0xdf
 ; CHECK-NEXT:  LBB1_1: ; %loop.header
 ; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ands w10, w0, #0xff
-; CHECK-NEXT:    b.eq LBB1_6
+; CHECK-NEXT:    tst w0, w9
+; CHECK-NEXT:    b.eq LBB1_5
 ; CHECK-NEXT:  ; %bb.2: ; %loop.header
 ; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
-; CHECK-NEXT:    cmp w10, #32
-; CHECK-NEXT:    b.eq LBB1_6
-; CHECK-NEXT:  ; %bb.3: ; %loop.header
-; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
+; CHECK-NEXT:    and w10, w0, #0xff
 ; CHECK-NEXT:    cmp w10, #124
-; CHECK-NEXT:    b.eq LBB1_7
-; CHECK-NEXT:  ; %bb.4: ; %loop.latch
+; CHECK-NEXT:    b.eq LBB1_6
+; CHECK-NEXT:  ; %bb.3: ; %loop.latch
 ; CHECK-NEXT:    ; in Loop: Header=BB1_1 Depth=1
-; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    subs w8, w8, #1
 ; CHECK-NEXT:    b.ne LBB1_1
-; CHECK-NEXT:  ; %bb.5:
-; CHECK-NEXT:    mov w8, #10 ; =0xa
-; CHECK-NEXT:  LBB1_6: ; %common.ret
-; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:  ; %bb.4:
+; CHECK-NEXT:    mov w0, #10 ; =0xa
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB1_7: ; %e2
+; CHECK-NEXT:  LBB1_5:
+; CHECK-NEXT:    mov w0, #20 ; =0x14
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB1_6: ; %e2
 ; CHECK-NEXT:    mov w0, #30 ; =0x1e
 ; CHECK-NEXT:    ret
 entry:
@@ -111,35 +104,33 @@ e2:
 define i32 @switch_with_matching_dests_0_and_pow2_3_cases_with_phi(i8 %v, i1 %c) {
 ; CHECK-LABEL: switch_with_matching_dests_0_and_pow2_3_cases_with_phi:
 ; CHECK:       ; %bb.0: ; %entry
-; CHECK-NEXT:    tbz w1, #0, LBB2_8
+; CHECK-NEXT:    tbz w1, #0, LBB2_6
 ; CHECK-NEXT:  ; %bb.1: ; %loop.header.preheader
-; CHECK-NEXT:    mov w9, #100 ; =0x64
-; CHECK-NEXT:    mov w8, #20 ; =0x14
+; CHECK-NEXT:    mov w8, #100 ; =0x64
+; CHECK-NEXT:    mov w9, #223 ; =0xdf
 ; CHECK-NEXT:  LBB2_2: ; %loop.header
 ; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    ands w10, w0, #0xff
+; CHECK-NEXT:    tst w0, w9
 ; CHECK-NEXT:    b.eq LBB2_7
 ; CHECK-NEXT:  ; %bb.3: ; %loop.header
 ; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
-; CHECK-NEXT:    cmp w10, #32
-; CHECK-NEXT:    b.eq LBB2_7
-; CHECK-NEXT:  ; %bb.4: ; %loop.header
-; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
+; CHECK-NEXT:    and w10, w0, #0xff
 ; CHECK-NEXT:    cmp w10, #124
-; CHECK-NEXT:    b.eq LBB2_9
-; CHECK-NEXT:  ; %bb.5: ; %loop.latch
+; CHECK-NEXT:    b.eq LBB2_8
+; CHECK-NEXT:  ; %bb.4: ; %loop.latch
 ; CHECK-NEXT:    ; in Loop: Header=BB2_2 Depth=1
-; CHECK-NEXT:    subs w9, w9, #1
+; CHECK-NEXT:    subs w8, w8, #1
 ; CHECK-NEXT:    b.ne LBB2_2
-; CHECK-NEXT:  ; %bb.6:
-; CHECK-NEXT:    mov w8, #10 ; =0xa
-; CHECK-NEXT:  LBB2_7: ; %common.ret
-; CHECK-NEXT:    mov w0, w8
+; CHECK-NEXT:  ; %bb.5:
+; CHECK-NEXT:    mov w0, #10 ; =0xa
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB2_8:
+; CHECK-NEXT:  LBB2_6:
 ; CHECK-NEXT:    mov w0, wzr
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB2_9: ; %e2
+; CHECK-NEXT:  LBB2_7:
+; CHECK-NEXT:    mov w0, #20 ; =0x14
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB2_8: ; %e2
 ; CHECK-NEXT:    mov w0, #30 ; =0x1e
 ; CHECK-NEXT:    ret
 entry:
@@ -240,21 +231,18 @@ define i32 @switch_in_loop_with_matching_dests_0_and_pow2_3_cases(ptr %start) {
 ; CHECK-NEXT:  LBB4_1: ; %loop
 ; CHECK-NEXT:    ; =>This Inner Loop Header: Depth=1
 ; CHECK-NEXT:    ldrb w9, [x8], #1
-; CHECK-NEXT:    cbz w9, LBB4_4
+; CHECK-NEXT:    tst w9, #0xffffffdf
+; CHECK-NEXT:    b.eq LBB4_4
 ; CHECK-NEXT:  ; %bb.2: ; %loop
 ; CHECK-NEXT:    ; in Loop: Header=BB4_1 Depth=1
 ; CHECK-NEXT:    cmp w9, #124
-; CHECK-NEXT:    b.eq LBB4_5
-; CHECK-NEXT:  ; %bb.3: ; %loop
-; CHECK-NEXT:    ; in Loop: Header=BB4_1 Depth=1
-; CHECK-NEXT:    cmp w9, #32
 ; CHECK-NEXT:    b.ne LBB4_1
+; CHECK-NEXT:  ; %bb.3: ; %e2.loopexit
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
 ; CHECK-NEXT:  LBB4_4: ; %e1
 ; CHECK-NEXT:    mov w0, #-1 ; =0xffffffff
 ; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB4_5: ; %e2.loopexit
-; CHECK-NEXT:    mov w0, wzr
-; CHECK-NEXT:    ret
 entry:
   br label %loop
 
@@ -376,8 +364,7 @@ define void @test_successor_with_loop_phi(ptr %A, ptr %B) {
 ; CHECK-NEXT:    ldr w8, [x0]
 ; CHECK-NEXT:    str wzr, [x0]
 ; CHECK-NEXT:    mov x0, x1
-; CHECK-NEXT:    orr w8, w8, #0x4
-; CHECK-NEXT:    cmp w8, #4
+; CHECK-NEXT:    tst w8, #0xfffffffb
 ; CHECK-NEXT:    b.eq LBB7_1
 ; CHECK-NEXT:  ; %bb.2: ; %exit
 ; CHECK-NEXT:    ret
@@ -556,22 +543,21 @@ e1:
 define void @merge_with_stores(ptr %A, i16 %v) {
 ; CHECK-LABEL: merge_with_stores:
 ; CHECK:       ; %bb.0: ; %entry
-; CHECK-NEXT:    and w8, w1, #0xffff
-; CHECK-NEXT:    sub w9, w8, #10
-; CHECK-NEXT:    cmp w9, #2
-; CHECK-NEXT:    b.lo LBB11_4
+; CHECK-NEXT:    mov w8, #65533 ; =0xfffd
+; CHECK-NEXT:    tst w1, w8
+; CHECK-NEXT:    b.eq LBB11_3
 ; CHECK-NEXT:  ; %bb.1: ; %entry
-; CHECK-NEXT:    cbz w8, LBB11_5
-; CHECK-NEXT:  ; %bb.2: ; %entry
+; CHECK-NEXT:    and w8, w1, #0xffff
+; CHECK-NEXT:    sub w8, w8, #10
 ; CHECK-NEXT:    cmp w8, #2
-; CHECK-NEXT:    b.eq LBB11_5
-; CHECK-NEXT:  ; %bb.3: ; %default.dst
-; CHECK-NEXT:    strh wzr, [x0]
-; CHECK-NEXT:    ret
-; CHECK-NEXT:  LBB11_4: ; %other.dst
+; CHECK-NEXT:    b.hs LBB11_4
+; CHECK-NEXT:  ; %bb.2: ; %other.dst
 ; CHECK-NEXT:    mov w8, #1 ; =0x1
 ; CHECK-NEXT:    strh w8, [x0, #36]
-; CHECK-NEXT:  LBB11_5: ; %pow2.dst
+; CHECK-NEXT:  LBB11_3: ; %pow2.dst
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  LBB11_4: ; %default.dst
+; CHECK-NEXT:    strh wzr, [x0]
 ; CHECK-NEXT:    ret
 entry:
   switch i16 %v, label %default.dst [



More information about the llvm-commits mailing list