SwitchInst case values must be ConstantInt, which have no use list. Therefore it is not necessary to store these as Use, instead store them more efficiently as a simple array of pointers after the uses, similar to how PHINode stores basic blocks. After this change, the successors of all terminators are stored consecutively in the operand list. This is preparatory work for improving the performance of successor access. Add new C API functions so that switch case values remain accessible from bindings for other languages. While this could also be achieved by merely changing the order of operands (i.e., first all successors, then all constants), doing so would increase the asymptotic runtime of addCase from O(1) to O(n) (i.e., adding n cases would be O(n^2)), because it would need to shift all constants by one slot. Having null/invalid operands is also a bad idea and would cause much more breakage. Pull Request: https://github.com/llvm/llvm-project/pull/170984
80 lines
1.6 KiB
LLVM
80 lines
1.6 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
|
|
|
|
define internal i32 @fn1(i32 %a) {
|
|
; CHECK-LABEL: @fn1(
|
|
; CHECK-NEXT: switch i32 [[A:%.*]], label [[B1:%.*]] [
|
|
; CHECK-NEXT: i32 1, label [[B2:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[B3:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: b1:
|
|
; CHECK-NEXT: ret i32 1
|
|
; CHECK: b2:
|
|
; CHECK-NEXT: ret i32 2
|
|
; CHECK: b3:
|
|
; CHECK-NEXT: ret i32 3
|
|
;
|
|
switch i32 %a, label %b1 [
|
|
i32 1, label %b2
|
|
i32 2, label %b3
|
|
]
|
|
b1:
|
|
ret i32 1
|
|
b2:
|
|
ret i32 2
|
|
b3:
|
|
ret i32 3
|
|
}
|
|
|
|
define internal i32 @fn2(i32 %a) {
|
|
switch i32 %a, label %b1 [
|
|
i32 1, label %b2
|
|
i32 2, label %b3
|
|
]
|
|
b1:
|
|
ret i32 1
|
|
b2:
|
|
ret i32 2
|
|
b3:
|
|
ret i32 3
|
|
}
|
|
|
|
; Different switch case value, don't merge.
|
|
define internal i32 @fn3(i32 %a) {
|
|
; CHECK-LABEL: @fn3(
|
|
; CHECK-NEXT: switch i32 [[A:%.*]], label [[B1:%.*]] [
|
|
; CHECK-NEXT: i32 1000, label [[B2:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[B3:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: b1:
|
|
; CHECK-NEXT: ret i32 1
|
|
; CHECK: b2:
|
|
; CHECK-NEXT: ret i32 2
|
|
; CHECK: b3:
|
|
; CHECK-NEXT: ret i32 3
|
|
;
|
|
switch i32 %a, label %b1 [
|
|
i32 1000, label %b2
|
|
i32 2, label %b3
|
|
]
|
|
b1:
|
|
ret i32 1
|
|
b2:
|
|
ret i32 2
|
|
b3:
|
|
ret i32 3
|
|
}
|
|
|
|
define void @caller(i32 %a) {
|
|
; CHECK-LABEL: @caller(
|
|
; CHECK-NEXT: [[R1:%.*]] = call i32 @fn1(i32 [[A:%.*]])
|
|
; CHECK-NEXT: [[R2:%.*]] = call i32 @fn1(i32 [[A]])
|
|
; CHECK-NEXT: [[R3:%.*]] = call i32 @fn3(i32 [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%r1 = call i32 @fn1(i32 %a)
|
|
%r2 = call i32 @fn2(i32 %a)
|
|
%r3 = call i32 @fn3(i32 %a)
|
|
ret void
|
|
}
|