| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt < %s -passes=jump-table-to-switch -S | FileCheck %s | |
| @table1 = constant [4 x ptr] [ptr null, ptr @f0, ptr poison, ptr @f1] | |
| @table2 = constant [3 x ptr] [ptr null, ptr poison, ptr null] | |
| @table3 = constant [3 x ptr] [ptr null, ptr @f0, ptr null] | |
| @table4 = constant [3 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @g0, ptr addrspace(1) null] | |
| define i32 @f0() { | |
| ; CHECK-LABEL: define i32 @f0() { | |
| ; CHECK-NEXT: ret i32 10 | |
| ; | |
| ret i32 10 | |
| } | |
| define i32 @f1() { | |
| ; CHECK-LABEL: define i32 @f1() { | |
| ; CHECK-NEXT: ret i32 11 | |
| ; | |
| ret i32 11 | |
| } | |
| define i32 @g0() addrspace(1) { | |
| ; CHECK-LABEL: define i32 @g0() addrspace(1) { | |
| ; CHECK-NEXT: ret i32 20 | |
| ; | |
| ret i32 20 | |
| } | |
| define i32 @test_holes(i64 %i) { | |
| ; CHECK-LABEL: define i32 @test_holes( | |
| ; CHECK-SAME: i64 [[I:%.*]]) { | |
| ; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds [4 x ptr], ptr @table1, i64 0, i64 [[I]] | |
| ; CHECK-NEXT: [[F:%.*]] = load ptr, ptr [[P]], align 8 | |
| ; CHECK-NEXT: switch i64 [[I]], label %[[DEFAULT_SWITCH_CASE_UNREACHABLE:.*]] [ | |
| ; CHECK-NEXT: i64 1, label %[[CALL_1:.*]] | |
| ; CHECK-NEXT: i64 3, label %[[CALL_3:.*]] | |
| ; CHECK-NEXT: ], !prof [[PROF0:![0-9]+]] | |
| ; CHECK: [[DEFAULT_SWITCH_CASE_UNREACHABLE]]: | |
| ; CHECK-NEXT: unreachable | |
| ; CHECK: [[CALL_1]]: | |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @f0() | |
| ; CHECK-NEXT: br label %[[DOTTAIL:.*]] | |
| ; CHECK: [[CALL_3]]: | |
| ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @f1() | |
| ; CHECK-NEXT: br label %[[DOTTAIL]] | |
| ; CHECK: [[DOTTAIL]]: | |
| ; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP1]], %[[CALL_1]] ], [ [[TMP2]], %[[CALL_3]] ] | |
| ; CHECK-NEXT: ret i32 [[TMP3]] | |
| ; | |
| %p = getelementptr inbounds [4 x ptr], ptr @table1, i64 0, i64 %i | |
| %f = load ptr, ptr %p, align 8 | |
| %r = call i32 %f() | |
| ret i32 %r | |
| } | |
| define i32 @test_all_ubs(i64 %i) { | |
| ; CHECK-LABEL: define i32 @test_all_ubs( | |
| ; CHECK-SAME: i64 [[I:%.*]]) { | |
| ; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds [3 x ptr], ptr @table2, i64 0, i64 [[I]] | |
| ; CHECK-NEXT: [[F:%.*]] = load ptr, ptr [[P]], align 8 | |
| ; CHECK-NEXT: [[R:%.*]] = call i32 [[F]]() | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| %p = getelementptr inbounds [3 x ptr], ptr @table2, i64 0, i64 %i | |
| %f = load ptr, ptr %p, align 8 | |
| %r = call i32 %f() | |
| ret i32 %r | |
| } | |
| define i32 @test_valid_null(i64 %i) null_pointer_is_valid { | |
| ; CHECK-LABEL: define i32 @test_valid_null( | |
| ; CHECK-SAME: i64 [[I:%.*]]) #[[ATTR0:[0-9]+]] { | |
| ; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds [3 x ptr], ptr @table3, i64 0, i64 [[I]] | |
| ; CHECK-NEXT: [[F:%.*]] = load ptr, ptr [[P]], align 8 | |
| ; CHECK-NEXT: [[R:%.*]] = call i32 [[F]]() | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| %p = getelementptr inbounds [3 x ptr], ptr @table3, i64 0, i64 %i | |
| %f = load ptr, ptr %p, align 8 | |
| %r = call i32 %f() | |
| ret i32 %r | |
| } | |
| ; Null is a valid address in non-zero address spaces. | |
| define i32 @test_valid_null_addrspace(i64 %i) { | |
| ; CHECK-LABEL: define i32 @test_valid_null_addrspace( | |
| ; CHECK-SAME: i64 [[I:%.*]]) { | |
| ; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds [3 x ptr addrspace(1)], ptr @table4, i64 0, i64 [[I]] | |
| ; CHECK-NEXT: [[F:%.*]] = load ptr addrspace(1), ptr [[P]], align 8 | |
| ; CHECK-NEXT: [[R:%.*]] = call addrspace(1) i32 [[F]]() | |
| ; CHECK-NEXT: ret i32 [[R]] | |
| ; | |
| %p = getelementptr inbounds [3 x ptr addrspace(1)], ptr @table4, i64 0, i64 %i | |
| %f = load ptr addrspace(1), ptr %p, align 8 | |
| %r = call addrspace(1) i32 %f() | |
| ret i32 %r | |
| } | |
| ;. | |
| ; CHECK: [[PROF0]] = !{!"unknown", !"jump-table-to-switch"} | |
| ;. |