llvm/llvm/test/Transforms/SimplifyCFG/RISCV/switch-of-powers-of-two.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes='simplifycfg<switch-to-lookup>' -simplifycfg-require-and-preserve-domtree=1 -S -mtriple=riscv64 < %s \
; RUN: | FileCheck %s --check-prefixes=CHECK,RV64I
; RUN: opt -passes='simplifycfg<switch-to-lookup>' -simplifycfg-require-and-preserve-domtree=1 -S -mtriple=riscv64 -mattr=+zbb < %s \
; RUN: | FileCheck %s --check-prefixes=CHECK,RV64ZBB

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

; Check that the range of switch of powers of two is reduced and switch itself is lowered to lookup-table.
define i32 @switch_of_powers(i32 %x) {
; RV64I-LABEL: @switch_of_powers(
; RV64I-NEXT:  entry:
; RV64I-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT_CASE:%.*]] [
; RV64I-NEXT:      i32 1, label [[RETURN:%.*]]
; RV64I-NEXT:      i32 8, label [[BB2:%.*]]
; RV64I-NEXT:      i32 16, label [[BB3:%.*]]
; RV64I-NEXT:      i32 32, label [[BB4:%.*]]
; RV64I-NEXT:      i32 64, label [[BB5:%.*]]
; RV64I-NEXT:    ]
; RV64I:       default_case:
; RV64I-NEXT:    unreachable
; RV64I:       bb2:
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       bb3:
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       bb4:
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       bb5:
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       return:
; RV64I-NEXT:    [[P:%.*]] = phi i32 [ 2, [[BB2]] ], [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ 3, [[ENTRY:%.*]] ]
; RV64I-NEXT:    ret i32 [[P]]
;
; RV64ZBB-LABEL: @switch_of_powers(
; RV64ZBB-NEXT:  entry:
; RV64ZBB-NEXT:    [[TMP0:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
; RV64ZBB-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.switch_of_powers, i32 0, i32 [[TMP0]]
; RV64ZBB-NEXT:    [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
; RV64ZBB-NEXT:    ret i32 [[SWITCH_LOAD]]
;
entry:
  switch i32 %x, label %default_case [
  i32 1,  label %bb1
  i32 8,  label %bb2
  i32 16, label %bb3
  i32 32, label %bb4
  i32 64, label %bb5
  ]


default_case: unreachable
bb1: br label %return
bb2: br label %return
bb3: br label %return
bb4: br label %return
bb5: br label %return

return:
  %p = phi i32 [ 3, %bb1 ], [ 2, %bb2 ], [ 1, %bb3 ], [ 0, %bb4 ], [ 42, %bb5 ]
  ret i32 %p
}

; Check that switch's of powers of two range is not reduced if default case is reachable
define i32 @switch_of_powers_reachable_default(i32 %x) {
; CHECK-LABEL: @switch_of_powers_reachable_default(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[X:%.*]], label [[RETURN:%.*]] [
; CHECK-NEXT:      i32 1, label [[BB1:%.*]]
; CHECK-NEXT:      i32 8, label [[BB2:%.*]]
; CHECK-NEXT:      i32 16, label [[BB3:%.*]]
; CHECK-NEXT:      i32 32, label [[BB4:%.*]]
; CHECK-NEXT:      i32 64, label [[BB5:%.*]]
; CHECK-NEXT:    ]
; CHECK:       bb1:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb2:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb4:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb5:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 3, [[BB1]] ], [ 2, [[BB2]] ], [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ -1, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i32 [[P]]
;
entry:
  switch i32 %x, label %default_case [
  i32 1,  label %bb1
  i32 8,  label %bb2
  i32 16, label %bb3
  i32 32, label %bb4
  i32 64, label %bb5
  ]


default_case: br label %return
bb1: br label %return
bb2: br label %return
bb3: br label %return
bb4: br label %return
bb5: br label %return

return:
  %p = phi i32 [ 3, %bb1 ], [ 2, %bb2 ], [ 1, %bb3 ], [ 0, %bb4 ], [ 42, %bb5 ], [-1, %default_case]
  ret i32 %p
}

; Check that switch with zero case is not considered as switch of powers of two
define i32 @switch_of_non_powers(i32 %x) {
; CHECK-LABEL: @switch_of_non_powers(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT_CASE:%.*]] [
; CHECK-NEXT:      i32 0, label [[RETURN:%.*]]
; CHECK-NEXT:      i32 1, label [[BB2:%.*]]
; CHECK-NEXT:      i32 16, label [[BB3:%.*]]
; CHECK-NEXT:      i32 32, label [[BB4:%.*]]
; CHECK-NEXT:      i32 64, label [[BB5:%.*]]
; CHECK-NEXT:    ]
; CHECK:       default_case:
; CHECK-NEXT:    unreachable
; CHECK:       bb2:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb4:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb5:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 2, [[BB2]] ], [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ 3, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i32 [[P]]
;
entry:
  switch i32 %x, label %default_case [
  i32 0,  label %bb1
  i32 1,  label %bb2
  i32 16, label %bb3
  i32 32, label %bb4
  i32 64, label %bb5
  ]


default_case: unreachable
bb1: br label %return
bb2: br label %return
bb3: br label %return
bb4: br label %return
bb5: br label %return

return:
  %p = phi i32 [ 3, %bb1 ], [ 2, %bb2 ], [ 1, %bb3 ], [ 0, %bb4 ], [ 42, %bb5 ]
  ret i32 %p
}

define i32 @unable_to_create_dense_switch(i32 %x) {
; CHECK-LABEL: @unable_to_create_dense_switch(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT_CASE:%.*]] [
; CHECK-NEXT:      i32 1, label [[RETURN:%.*]]
; CHECK-NEXT:      i32 2, label [[BB3:%.*]]
; CHECK-NEXT:      i32 4, label [[BB4:%.*]]
; CHECK-NEXT:      i32 4096, label [[BB5:%.*]]
; CHECK-NEXT:    ]
; CHECK:       default_case:
; CHECK-NEXT:    unreachable
; CHECK:       bb3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb4:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb5:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ 2, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i32 [[P]]
;
entry:
  switch i32 %x, label %default_case [
  i32 1,  label %bb2
  i32 2, label %bb3
  i32 4, label %bb4
  i32 4096, label %bb5
  ]


default_case: unreachable
bb1: br label %return
bb2: br label %return
bb3: br label %return
bb4: br label %return
bb5: br label %return

return:
  %p = phi i32 [ 3, %bb1 ], [ 2, %bb2 ], [ 1, %bb3 ], [ 0, %bb4 ], [ 42, %bb5 ]
  ret i32 %p
}

declare i32 @bar(i32)
define i32 @unable_to_generate_lookup_table(i32 %x, i32 %y) {
; RV64I-LABEL: @unable_to_generate_lookup_table(
; RV64I-NEXT:  entry:
; RV64I-NEXT:    switch i32 [[Y:%.*]], label [[DEFAULT_CASE:%.*]] [
; RV64I-NEXT:      i32 1, label [[BB2:%.*]]
; RV64I-NEXT:      i32 2, label [[BB3:%.*]]
; RV64I-NEXT:      i32 8, label [[BB4:%.*]]
; RV64I-NEXT:      i32 64, label [[BB5:%.*]]
; RV64I-NEXT:    ]
; RV64I:       default_case:
; RV64I-NEXT:    unreachable
; RV64I:       bb2:
; RV64I-NEXT:    [[XOR2:%.*]] = xor i32 [[X:%.*]], 48
; RV64I-NEXT:    [[CALL2:%.*]] = call i32 @bar(i32 [[XOR2]])
; RV64I-NEXT:    [[ADD2:%.*]] = sub i32 [[CALL2]], [[X]]
; RV64I-NEXT:    br label [[RETURN:%.*]]
; RV64I:       bb3:
; RV64I-NEXT:    [[XOR3:%.*]] = xor i32 [[X]], 96
; RV64I-NEXT:    [[CALL3:%.*]] = call i32 @bar(i32 [[XOR3]])
; RV64I-NEXT:    [[ADD3:%.*]] = add i32 [[CALL3]], [[X]]
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       bb4:
; RV64I-NEXT:    [[CALL4:%.*]] = call i32 @bar(i32 [[X]])
; RV64I-NEXT:    [[ADD4:%.*]] = add i32 [[CALL4]], [[X]]
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       bb5:
; RV64I-NEXT:    [[XOR5:%.*]] = xor i32 [[X]], 9
; RV64I-NEXT:    [[CALL5:%.*]] = call i32 @bar(i32 [[XOR5]])
; RV64I-NEXT:    [[ADD5:%.*]] = add i32 [[CALL5]], [[X]]
; RV64I-NEXT:    br label [[RETURN]]
; RV64I:       return:
; RV64I-NEXT:    [[P:%.*]] = phi i32 [ [[ADD2]], [[BB2]] ], [ [[ADD3]], [[BB3]] ], [ [[ADD4]], [[BB4]] ], [ [[ADD5]], [[BB5]] ]
; RV64I-NEXT:    ret i32 [[P]]
;
; RV64ZBB-LABEL: @unable_to_generate_lookup_table(
; RV64ZBB-NEXT:  entry:
; RV64ZBB-NEXT:    [[TMP0:%.*]] = call i32 @llvm.cttz.i32(i32 [[Y:%.*]], i1 true)
; RV64ZBB-NEXT:    switch i32 [[TMP0]], label [[DEFAULT_CASE:%.*]] [
; RV64ZBB-NEXT:      i32 0, label [[BB2:%.*]]
; RV64ZBB-NEXT:      i32 1, label [[BB3:%.*]]
; RV64ZBB-NEXT:      i32 3, label [[BB4:%.*]]
; RV64ZBB-NEXT:      i32 6, label [[BB5:%.*]]
; RV64ZBB-NEXT:    ]
; RV64ZBB:       default_case:
; RV64ZBB-NEXT:    unreachable
; RV64ZBB:       bb2:
; RV64ZBB-NEXT:    [[XOR2:%.*]] = xor i32 [[X:%.*]], 48
; RV64ZBB-NEXT:    [[CALL2:%.*]] = call i32 @bar(i32 [[XOR2]])
; RV64ZBB-NEXT:    [[ADD2:%.*]] = sub i32 [[CALL2]], [[X]]
; RV64ZBB-NEXT:    br label [[RETURN:%.*]]
; RV64ZBB:       bb3:
; RV64ZBB-NEXT:    [[XOR3:%.*]] = xor i32 [[X]], 96
; RV64ZBB-NEXT:    [[CALL3:%.*]] = call i32 @bar(i32 [[XOR3]])
; RV64ZBB-NEXT:    [[ADD3:%.*]] = add i32 [[CALL3]], [[X]]
; RV64ZBB-NEXT:    br label [[RETURN]]
; RV64ZBB:       bb4:
; RV64ZBB-NEXT:    [[CALL4:%.*]] = call i32 @bar(i32 [[X]])
; RV64ZBB-NEXT:    [[ADD4:%.*]] = add i32 [[CALL4]], [[X]]
; RV64ZBB-NEXT:    br label [[RETURN]]
; RV64ZBB:       bb5:
; RV64ZBB-NEXT:    [[XOR5:%.*]] = xor i32 [[X]], 9
; RV64ZBB-NEXT:    [[CALL5:%.*]] = call i32 @bar(i32 [[XOR5]])
; RV64ZBB-NEXT:    [[ADD5:%.*]] = add i32 [[CALL5]], [[X]]
; RV64ZBB-NEXT:    br label [[RETURN]]
; RV64ZBB:       return:
; RV64ZBB-NEXT:    [[P:%.*]] = phi i32 [ [[ADD2]], [[BB2]] ], [ [[ADD3]], [[BB3]] ], [ [[ADD4]], [[BB4]] ], [ [[ADD5]], [[BB5]] ]
; RV64ZBB-NEXT:    ret i32 [[P]]
;
entry:
  switch i32 %y, label %default_case [
  i32 1,  label %bb2
  i32 2, label %bb3
  i32 8, label %bb4
  i32 64, label %bb5
  ]


default_case: unreachable
bb1:
  %xor1 = xor i32 %x, 42
  %call1 = call i32 @bar(i32 %xor1)
  %add1 = add i32 %call1, %x
  br label %return
bb2:
  %xor2 = xor i32 %x, 48
  %call2 = call i32 @bar(i32 %xor2)
  %add2 = sub i32 %call2, %x
  br label %return
bb3:
  %xor3 = xor i32 %x, 96
  %call3 = call i32 @bar(i32 %xor3)
  %add3 = add i32 %call3, %x
  br label %return
bb4:
  %call4 = call i32 @bar(i32 %x)
  %add4 = add i32 %call4, %x
  br label %return
bb5:
  %xor5 = xor i32 %x, 9
  %call5 = call i32 @bar(i32 %xor5)
  %add5 = add i32 %call5, %x
  br label %return

return:
  %p = phi i32 [ %add1, %bb1 ], [ %add2, %bb2 ], [ %add3, %bb3 ], [ %add4, %bb4 ], [ %add5, %bb5 ]

  ret i32 %p
}

define i128 @switch_with_long_condition(i128 %x) {
; CHECK-LABEL: @switch_with_long_condition(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    switch i128 [[X:%.*]], label [[DEFAULT_CASE:%.*]] [
; CHECK-NEXT:      i128 1, label [[RETURN:%.*]]
; CHECK-NEXT:      i128 2, label [[BB3:%.*]]
; CHECK-NEXT:      i128 4, label [[BB4:%.*]]
; CHECK-NEXT:      i128 32, label [[BB5:%.*]]
; CHECK-NEXT:    ]
; CHECK:       default_case:
; CHECK-NEXT:    unreachable
; CHECK:       bb3:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb4:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       bb5:
; CHECK-NEXT:    br label [[RETURN]]
; CHECK:       return:
; CHECK-NEXT:    [[P:%.*]] = phi i128 [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ 2, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i128 [[P]]
;
entry:
  switch i128 %x, label %default_case [
  i128 1,  label %bb2
  i128 2, label %bb3
  i128 4, label %bb4
  i128 32, label %bb5
  ]


default_case: unreachable
bb1: br label %return
bb2: br label %return
bb3: br label %return
bb4: br label %return
bb5: br label %return

return:
  %p = phi i128 [ 3, %bb1 ], [ 2, %bb2 ], [ 1, %bb3 ], [ 0, %bb4 ], [ 42, %bb5 ]
  ret i128 %p
}