1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt < %s -passes=jump-table-to-switch -verify-dom-info -S | FileCheck %s 3; RUN: opt < %s -passes=jump-table-to-switch -jump-table-to-switch-size-threshold=0 -verify-dom-info -S | FileCheck %s --check-prefix=THRESHOLD-0 4 5@func_array = constant [2 x ptr] [ptr @func0, ptr @func1] 6 7define i32 @func0() { 8 ret i32 1 9} 10 11define i32 @func1() { 12 ret i32 2 13} 14 15define i32 @function_with_jump_table(i32 %index) { 16; CHECK-LABEL: define i32 @function_with_jump_table( 17; CHECK-SAME: i32 [[INDEX:%.*]]) { 18; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 19; CHECK-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 20; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [ 21; CHECK-NEXT: i32 0, label [[CALL_0:%.*]] 22; CHECK-NEXT: i32 1, label [[CALL_1:%.*]] 23; CHECK-NEXT: ] 24; CHECK: default.switch.case.unreachable: 25; CHECK-NEXT: unreachable 26; CHECK: call.0: 27; CHECK-NEXT: [[TMP1:%.*]] = call i32 @func0() 28; CHECK-NEXT: br label [[DOTTAIL:%.*]] 29; CHECK: call.1: 30; CHECK-NEXT: [[TMP2:%.*]] = call i32 @func1() 31; CHECK-NEXT: br label [[DOTTAIL]] 32; CHECK: .tail: 33; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ] 34; CHECK-NEXT: ret i32 [[TMP3]] 35; 36; THRESHOLD-0-LABEL: define i32 @function_with_jump_table( 37; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) { 38; THRESHOLD-0-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 39; THRESHOLD-0-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 40; THRESHOLD-0-NEXT: [[RESULT:%.*]] = call i32 [[FUNC_PTR]]() 41; THRESHOLD-0-NEXT: ret i32 [[RESULT]] 42; 43 %gep = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index 44 %func_ptr = load ptr, ptr %gep 45 %result = call i32 %func_ptr() 46 ret i32 %result 47} 48 49define i32 @basic_block_splitted_twice(i32 %index) { 50; CHECK-LABEL: define i32 @basic_block_splitted_twice( 51; CHECK-SAME: i32 [[INDEX:%.*]]) { 52; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 53; CHECK-NEXT: [[FUNC_PTR1:%.*]] = load ptr, ptr [[GEP1]], align 8 54; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [ 55; CHECK-NEXT: i32 0, label [[CALL_0:%.*]] 56; CHECK-NEXT: i32 1, label [[CALL_1:%.*]] 57; CHECK-NEXT: ] 58; CHECK: default.switch.case.unreachable: 59; CHECK-NEXT: unreachable 60; CHECK: call.0: 61; CHECK-NEXT: [[TMP1:%.*]] = call i32 @func0() 62; CHECK-NEXT: br label [[DOTTAIL:%.*]] 63; CHECK: call.1: 64; CHECK-NEXT: [[TMP2:%.*]] = call i32 @func1() 65; CHECK-NEXT: br label [[DOTTAIL]] 66; CHECK: .tail: 67; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ] 68; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 69; CHECK-NEXT: [[FUNC_PTR2:%.*]] = load ptr, ptr [[GEP2]], align 8 70; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE1:%.*]] [ 71; CHECK-NEXT: i32 0, label [[CALL_02:%.*]] 72; CHECK-NEXT: i32 1, label [[CALL_13:%.*]] 73; CHECK-NEXT: ] 74; CHECK: default.switch.case.unreachable1: 75; CHECK-NEXT: unreachable 76; CHECK: call.02: 77; CHECK-NEXT: [[TMP4:%.*]] = call i32 @func0() 78; CHECK-NEXT: br label [[DOTTAIL_TAIL:%.*]] 79; CHECK: call.13: 80; CHECK-NEXT: [[TMP5:%.*]] = call i32 @func1() 81; CHECK-NEXT: br label [[DOTTAIL_TAIL]] 82; CHECK: .tail.tail: 83; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP4]], [[CALL_02]] ], [ [[TMP5]], [[CALL_13]] ] 84; CHECK-NEXT: [[RESULT:%.*]] = add i32 [[TMP3]], [[TMP6]] 85; CHECK-NEXT: ret i32 [[RESULT]] 86; 87; THRESHOLD-0-LABEL: define i32 @basic_block_splitted_twice( 88; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) { 89; THRESHOLD-0-NEXT: [[GEP1:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 90; THRESHOLD-0-NEXT: [[FUNC_PTR1:%.*]] = load ptr, ptr [[GEP1]], align 8 91; THRESHOLD-0-NEXT: [[RESULT1:%.*]] = call i32 [[FUNC_PTR1]]() 92; THRESHOLD-0-NEXT: [[GEP2:%.*]] = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 [[INDEX]] 93; THRESHOLD-0-NEXT: [[FUNC_PTR2:%.*]] = load ptr, ptr [[GEP2]], align 8 94; THRESHOLD-0-NEXT: [[RESULT2:%.*]] = call i32 [[FUNC_PTR2]]() 95; THRESHOLD-0-NEXT: [[RESULT:%.*]] = add i32 [[RESULT1]], [[RESULT2]] 96; THRESHOLD-0-NEXT: ret i32 [[RESULT]] 97; 98 %gep1 = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index 99 %func_ptr1 = load ptr, ptr %gep1 100 %result1 = call i32 %func_ptr1() 101 %gep2 = getelementptr inbounds [2 x ptr], ptr @func_array, i32 0, i32 %index 102 %func_ptr2 = load ptr, ptr %gep2 103 %result2 = call i32 %func_ptr2() 104 %result = add i32 %result1, %result2 105 ret i32 %result 106} 107 108define void @void_func0() { 109 ret void 110} 111 112define void @void_func1() { 113 ret void 114} 115 116@void_func_array = constant [2 x ptr] [ptr @void_func0, ptr @void_func1] 117 118define void @void_function_with_jump_table(i32 %index) { 119; CHECK-LABEL: define void @void_function_with_jump_table( 120; CHECK-SAME: i32 [[INDEX:%.*]]) { 121; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]] 122; CHECK-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 123; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [ 124; CHECK-NEXT: i32 0, label [[CALL_0:%.*]] 125; CHECK-NEXT: i32 1, label [[CALL_1:%.*]] 126; CHECK-NEXT: ] 127; CHECK: default.switch.case.unreachable: 128; CHECK-NEXT: unreachable 129; CHECK: call.0: 130; CHECK-NEXT: call void @void_func0() 131; CHECK-NEXT: br label [[DOTTAIL:%.*]] 132; CHECK: call.1: 133; CHECK-NEXT: call void @void_func1() 134; CHECK-NEXT: br label [[DOTTAIL]] 135; CHECK: .tail: 136; CHECK-NEXT: ret void 137; 138; THRESHOLD-0-LABEL: define void @void_function_with_jump_table( 139; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) { 140; THRESHOLD-0-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]] 141; THRESHOLD-0-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 142; THRESHOLD-0-NEXT: call void [[FUNC_PTR]]() 143; THRESHOLD-0-NEXT: ret void 144; 145 %gep = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 %index 146 %func_ptr = load ptr, ptr %gep 147 call void %func_ptr() 148 ret void 149} 150 151define void @void_function_with_jump_table_and_call_site_attr(i32 %index) { 152; CHECK-LABEL: define void @void_function_with_jump_table_and_call_site_attr( 153; CHECK-SAME: i32 [[INDEX:%.*]]) { 154; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]] 155; CHECK-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 156; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [ 157; CHECK-NEXT: i32 0, label [[CALL_0:%.*]] 158; CHECK-NEXT: i32 1, label [[CALL_1:%.*]] 159; CHECK-NEXT: ] 160; CHECK: default.switch.case.unreachable: 161; CHECK-NEXT: unreachable 162; CHECK: call.0: 163; CHECK-NEXT: call void @void_func0() #[[ATTR0:[0-9]+]] 164; CHECK-NEXT: br label [[DOTTAIL:%.*]] 165; CHECK: call.1: 166; CHECK-NEXT: call void @void_func1() #[[ATTR0]] 167; CHECK-NEXT: br label [[DOTTAIL]] 168; CHECK: .tail: 169; CHECK-NEXT: ret void 170; 171; THRESHOLD-0-LABEL: define void @void_function_with_jump_table_and_call_site_attr( 172; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) { 173; THRESHOLD-0-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 [[INDEX]] 174; THRESHOLD-0-NEXT: [[FUNC_PTR:%.*]] = load ptr, ptr [[GEP]], align 8 175; THRESHOLD-0-NEXT: call void [[FUNC_PTR]]() #[[ATTR0:[0-9]+]] 176; THRESHOLD-0-NEXT: ret void 177; 178 %gep = getelementptr inbounds [2 x ptr], ptr @void_func_array, i32 0, i32 %index 179 %func_ptr = load ptr, ptr %gep 180 call void %func_ptr() nounwind 181 ret void 182} 183 184 185define i32 @func0_addrspace_42() addrspace(42) { 186 ret i32 1 187} 188 189define i32 @func1_addrspace_42() addrspace(42) { 190 ret i32 2 191} 192 193@func_array_addrspace_42 = addrspace(42) constant [2 x ptr addrspace(42)] [ptr addrspace(42) @func0_addrspace_42, ptr addrspace(42) @func1_addrspace_42] 194 195define i32 @function_with_jump_table_addrspace_42(i32 %index) addrspace(42) { 196; CHECK-LABEL: define i32 @function_with_jump_table_addrspace_42( 197; CHECK-SAME: i32 [[INDEX:%.*]]) addrspace(42) { 198; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 [[INDEX]] 199; CHECK-NEXT: [[FUNC_PTR:%.*]] = load ptr addrspace(42), ptr addrspace(42) [[GEP]], align 8 200; CHECK-NEXT: switch i32 [[INDEX]], label [[DEFAULT_SWITCH_CASE_UNREACHABLE:%.*]] [ 201; CHECK-NEXT: i32 0, label [[CALL_0:%.*]] 202; CHECK-NEXT: i32 1, label [[CALL_1:%.*]] 203; CHECK-NEXT: ] 204; CHECK: default.switch.case.unreachable: 205; CHECK-NEXT: unreachable 206; CHECK: call.0: 207; CHECK-NEXT: [[TMP1:%.*]] = call addrspace(42) i32 @func0_addrspace_42() 208; CHECK-NEXT: br label [[DOTTAIL:%.*]] 209; CHECK: call.1: 210; CHECK-NEXT: [[TMP2:%.*]] = call addrspace(42) i32 @func1_addrspace_42() 211; CHECK-NEXT: br label [[DOTTAIL]] 212; CHECK: .tail: 213; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP1]], [[CALL_0]] ], [ [[TMP2]], [[CALL_1]] ] 214; CHECK-NEXT: ret i32 [[TMP3]] 215; 216; THRESHOLD-0-LABEL: define i32 @function_with_jump_table_addrspace_42( 217; THRESHOLD-0-SAME: i32 [[INDEX:%.*]]) addrspace(42) { 218; THRESHOLD-0-NEXT: [[GEP:%.*]] = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 [[INDEX]] 219; THRESHOLD-0-NEXT: [[FUNC_PTR:%.*]] = load ptr addrspace(42), ptr addrspace(42) [[GEP]], align 8 220; THRESHOLD-0-NEXT: [[RESULT:%.*]] = call addrspace(42) i32 [[FUNC_PTR]]() 221; THRESHOLD-0-NEXT: ret i32 [[RESULT]] 222; 223 %gep = getelementptr inbounds [2 x ptr addrspace(42)], ptr addrspace(42) @func_array_addrspace_42, i32 0, i32 %index 224 %func_ptr = load ptr addrspace(42), ptr addrspace(42) %gep, align 8 225 %result = call addrspace(42) i32 %func_ptr() 226 ret i32 %result 227} 228 229