; 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
}