This transform has been restricted to legal types since https://reviews.llvm.org/rG65df808f6254617b9eee931d00e95d900610b660 in 2012. This is particularly restrictive on RISCV64 which only has i64 as a legal integer type. i32 is a very common type in code generated from C, but we won't form a lookup table with it. This also effects other common types like i8/i16 types on ARM, AArch64, RISCV, etc. This patch proposes to allow power of 2 types larger than 8 bit, if they will fit in the largest legal integer type in DataLayout. These types are common in C code so generally well handled in the backends. We could probably do this for other types like i24 and rely on alignment and padding to allow the backend to use a single wider load. This isn't my main concern right now and it will need more tests. We could also allow larger types up to some limit and let the backend split into multiple loads, but we need to define that limit. It's also not my main concern right now. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D107233
318 lines
9.3 KiB
LLVM
318 lines
9.3 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-to-lookup -S | FileCheck %s
|
|
; RUN: opt < %s -passes='simplifycfg<switch-to-lookup>' -S | FileCheck %s
|
|
|
|
target datalayout = "e-n32"
|
|
|
|
define i32 @test1(i32 %a) {
|
|
; CHECK-LABEL: @test1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97
|
|
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2
|
|
; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30
|
|
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], 4
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[SWITCH_LOOKUP:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table.test1, i32 0, i32 [[TMP4]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 97, label %one
|
|
i32 101, label %two
|
|
i32 105, label %three
|
|
i32 109, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
; Optimization shouldn't trigger; bitwidth > 64
|
|
define i128 @test2(i128 %a) {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: switch i128 [[A:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i128 97, label [[ONE:%.*]]
|
|
; CHECK-NEXT: i128 101, label [[TWO:%.*]]
|
|
; CHECK-NEXT: i128 105, label [[THREE:%.*]]
|
|
; CHECK-NEXT: i128 109, label [[THREE]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i128 [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i128 [[COMMON_RET_OP]]
|
|
; CHECK: one:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: two:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: three:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
switch i128 %a, label %def [
|
|
i128 97, label %one
|
|
i128 101, label %two
|
|
i128 105, label %three
|
|
i128 109, label %three
|
|
]
|
|
|
|
def:
|
|
ret i128 8867
|
|
|
|
one:
|
|
ret i128 11984
|
|
two:
|
|
ret i128 1143
|
|
three:
|
|
ret i128 99783
|
|
}
|
|
|
|
; Optimization shouldn't trigger; no holes present
|
|
define i32 @test3(i32 %a) {
|
|
; CHECK-LABEL: @test3(
|
|
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[A:%.*]], 97
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 3
|
|
; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_LOOKUP:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* @switch.table.test3, i32 0, i32 [[SWITCH_TABLEIDX]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 97, label %one
|
|
i32 98, label %two
|
|
i32 99, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
; Optimization shouldn't trigger; not an arithmetic progression
|
|
define i32 @test4(i32 %a) {
|
|
; CHECK-LABEL: @test4(
|
|
; CHECK-NEXT: switch i32 [[A:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i32 97, label [[ONE:%.*]]
|
|
; CHECK-NEXT: i32 102, label [[TWO:%.*]]
|
|
; CHECK-NEXT: i32 105, label [[THREE:%.*]]
|
|
; CHECK-NEXT: i32 109, label [[THREE]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: one:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: two:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: three:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 97, label %one
|
|
i32 102, label %two
|
|
i32 105, label %three
|
|
i32 109, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
; Optimization shouldn't trigger; not a power of two
|
|
define i32 @test5(i32 %a) {
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: switch i32 [[A:%.*]], label [[COMMON_RET:%.*]] [
|
|
; CHECK-NEXT: i32 97, label [[ONE:%.*]]
|
|
; CHECK-NEXT: i32 102, label [[TWO:%.*]]
|
|
; CHECK-NEXT: i32 107, label [[THREE:%.*]]
|
|
; CHECK-NEXT: i32 112, label [[THREE]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ 11984, [[ONE]] ], [ 1143, [[TWO]] ], [ 99783, [[THREE]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
; CHECK: one:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: two:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: three:
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 97, label %one
|
|
i32 102, label %two
|
|
i32 107, label %three
|
|
i32 112, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
define i32 @test6(i32 %a) optsize {
|
|
; CHECK-LABEL: @test6(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], -109
|
|
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2
|
|
; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30
|
|
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], 4
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[SWITCH_LOOKUP:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table.test6, i32 0, i32 [[TMP4]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 -97, label %one
|
|
i32 -101, label %two
|
|
i32 -105, label %three
|
|
i32 -109, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
define i8 @test7(i8 %a) optsize {
|
|
; CHECK-LABEL: @test7(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[A:%.*]], -36
|
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr i8 [[TMP0]], 2
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP0]], 6
|
|
; CHECK-NEXT: [[TMP3:%.*]] = or i8 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i8 [[TMP3]], 4
|
|
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i8 [[TMP3]] to i32
|
|
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul i32 [[SWITCH_CAST]], 8
|
|
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i32 -943228976, [[SWITCH_SHIFTAMT]]
|
|
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i32 [[SWITCH_DOWNSHIFT]] to i8
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = select i1 [[TMP4]], i8 [[SWITCH_MASKED]], i8 -93
|
|
; CHECK-NEXT: ret i8 [[COMMON_RET_OP]]
|
|
;
|
|
switch i8 %a, label %def [
|
|
i8 220, label %one
|
|
i8 224, label %two
|
|
i8 228, label %three
|
|
i8 232, label %three
|
|
]
|
|
|
|
def:
|
|
ret i8 8867
|
|
|
|
one:
|
|
ret i8 11984
|
|
two:
|
|
ret i8 1143
|
|
three:
|
|
ret i8 99783
|
|
}
|
|
|
|
define i32 @test8(i32 %a) optsize {
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 97
|
|
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 2
|
|
; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 30
|
|
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], 5
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[SWITCH_LOOKUP:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], [5 x i32]* @switch.table.test8, i32 0, i32 [[TMP4]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 97, label %one
|
|
i32 101, label %two
|
|
i32 105, label %three
|
|
i32 113, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|
|
define i32 @test9(i32 %a) {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], 6
|
|
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], 1
|
|
; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP1]], 31
|
|
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
|
|
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], 8
|
|
; CHECK-NEXT: br i1 [[TMP5]], label [[SWITCH_LOOKUP:%.*]], label [[COMMON_RET:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [8 x i32], [8 x i32]* @switch.table.test9, i32 0, i32 [[TMP4]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[COMMON_RET]]
|
|
; CHECK: common.ret:
|
|
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 8867, [[TMP0:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
|
|
;
|
|
switch i32 %a, label %def [
|
|
i32 18, label %one
|
|
i32 20, label %two
|
|
i32 6, label %three
|
|
i32 10, label %three
|
|
]
|
|
|
|
def:
|
|
ret i32 8867
|
|
|
|
one:
|
|
ret i32 11984
|
|
two:
|
|
ret i32 1143
|
|
three:
|
|
ret i32 99783
|
|
}
|
|
|