Alexis Engelke 6813f8f037
[IR] Don't store switch case values as operands
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
2025-12-11 18:38:39 +01:00

77 lines
2.3 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s
define i32 @nodedup(i1 %c, i16 %v) {
; CHECK-LABEL: define i32 @nodedup(
; CHECK-SAME: i1 [[C:%.*]], i16 [[V:%.*]]) {
; CHECK-NEXT: br i1 [[C]], label %[[B1:.*]], label %[[B2:.*]]
; CHECK: [[B1]]:
; CHECK-NEXT: switch i16 [[V]], label %[[RET2:.*]] [
; CHECK-NEXT: i16 1962, label %[[COMMON_RET:.*]]
; CHECK-NEXT: i16 2000, label %[[COMMON_RET]]
; CHECK-NEXT: i16 1963, label %[[COMMON_RET]]
; CHECK-NEXT: ]
; CHECK: [[B2]]:
; CHECK-NEXT: switch i16 [[V]], label %[[RET2]] [
; CHECK-NEXT: i16 2766, label %[[COMMON_RET]]
; CHECK-NEXT: i16 2798, label %[[COMMON_RET]]
; CHECK-NEXT: i16 2767, label %[[COMMON_RET]]
; CHECK-NEXT: ]
; CHECK: [[COMMON_RET]]:
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 3, %[[RET2]] ], [ 1, %[[B2]] ], [ 1, %[[B2]] ], [ 1, %[[B2]] ], [ 1, %[[B1]] ], [ 1, %[[B1]] ], [ 1, %[[B1]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
; CHECK: [[RET2]]:
; CHECK-NEXT: br label %[[COMMON_RET]]
;
br i1 %c, label %b1, label %b2
b1:
switch i16 %v, label %ret2 [
i16 1962, label %ret1
i16 2000, label %ret1
i16 1963, label %ret1
]
b2:
switch i16 %v, label %ret2 [
i16 2766, label %ret1
i16 2798, label %ret1
i16 2767, label %ret1
]
ret1:
ret i32 1
ret2:
ret i32 3
}
define i32 @dedup(i1 %c, i16 %v) {
; CHECK-LABEL: define i32 @dedup(
; CHECK-SAME: i1 [[C:%.*]], i16 [[V:%.*]]) {
; CHECK-NEXT: switch i16 [[V]], label %[[RET2:.*]] [
; CHECK-NEXT: i16 2766, label %[[COMMON_RET:.*]]
; CHECK-NEXT: i16 2798, label %[[COMMON_RET]]
; CHECK-NEXT: i16 2767, label %[[COMMON_RET]]
; CHECK-NEXT: ]
; CHECK: [[COMMON_RET]]:
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 3, %[[RET2]] ], [ 1, [[TMP0:%.*]] ], [ 1, [[TMP0]] ], [ 1, [[TMP0]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
; CHECK: [[RET2]]:
; CHECK-NEXT: br label %[[COMMON_RET]]
;
br i1 %c, label %b1, label %b2
b1:
switch i16 %v, label %ret2 [
i16 2766, label %ret1
i16 2798, label %ret1
i16 2767, label %ret1
]
b2:
switch i16 %v, label %ret2 [
i16 2766, label %ret1
i16 2798, label %ret1
i16 2767, label %ret1
]
ret1:
ret i32 1
ret2:
ret i32 3
}