; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes='simplifycfg' -simplifycfg-require-and-preserve-domtree=1 -S -mtriple=riscv64 < %s \ ; RUN: | FileCheck %s --check-prefixes=CHECK,RV64I ; RUN: opt -passes='simplifycfg' -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_MASKINDEX:%.*]] = trunc i32 [[TMP0]] to i8 ; RV64ZBB-NEXT: [[SWITCH_SHIFTED:%.*]] = lshr i8 121, [[SWITCH_MASKINDEX]] ; RV64ZBB-NEXT: [[SWITCH_LOBIT:%.*]] = trunc i8 [[SWITCH_SHIFTED]] to i1 ; RV64ZBB-NEXT: call void @llvm.assume(i1 [[SWITCH_LOBIT]]) ; 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 }