Generate the GEP with the index type that InstCombine will cast it to but use the knowledge that the index is unsigned.
243 lines
8.4 KiB
LLVM
243 lines
8.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -passes=simplifycfg --switch-to-lookup -S < %s | FileCheck %s
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
|
|
declare i1 @foo()
|
|
|
|
; https://alive2.llvm.org/ce/z/tuxLhJ
|
|
define i1 @switch_lookup_with_small_i1(i64 %x) {
|
|
; CHECK-LABEL: @switch_lookup_with_small_i1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i64 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i64 [[AND]] to i16
|
|
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i16 [[SWITCH_CAST]], 1
|
|
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i16 1030, [[SWITCH_SHIFTAMT]]
|
|
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i16 [[SWITCH_DOWNSHIFT]] to i1
|
|
; CHECK-NEXT: ret i1 [[SWITCH_MASKED]]
|
|
;
|
|
entry:
|
|
%and = and i64 %x, 15
|
|
switch i64 %and, label %default [
|
|
i64 10, label %lor.end
|
|
i64 1, label %lor.end
|
|
i64 2, label %lor.end
|
|
]
|
|
|
|
default: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %entry, %entry, %entry, %default
|
|
%0 = phi i1 [ true, %entry ], [ false, %default ], [ true, %entry ], [ true, %entry ]
|
|
ret i1 %0
|
|
}
|
|
|
|
; https://godbolt.org/z/sjbjorKon
|
|
define i8 @switch_lookup_with_small_i8(i64 %x) {
|
|
; CHECK-LABEL: @switch_lookup_with_small_i8(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[REM:%.*]] = urem i64 [[X:%.*]], 5
|
|
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i64 [[REM]] to i40
|
|
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i40 [[SWITCH_CAST]], 8
|
|
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i40 460303, [[SWITCH_SHIFTAMT]]
|
|
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i40 [[SWITCH_DOWNSHIFT]] to i8
|
|
; CHECK-NEXT: ret i8 [[SWITCH_MASKED]]
|
|
;
|
|
entry:
|
|
%rem = urem i64 %x, 5
|
|
switch i64 %rem, label %default [
|
|
i64 0, label %sw.bb0
|
|
i64 1, label %sw.bb1
|
|
i64 2, label %sw.bb2
|
|
]
|
|
|
|
sw.bb0: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
sw.bb1: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
sw.bb2: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
default: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
lor.end:
|
|
%0 = phi i8 [ 15, %sw.bb0 ], [ 6, %sw.bb1 ], [ 7, %sw.bb2 ], [ 0, %default ]
|
|
ret i8 %0
|
|
}
|
|
|
|
; Negative test: Table size would not fit the register.
|
|
define i8 @switch_lookup_with_small_i8_negative(i64 %x) {
|
|
; CHECK-LABEL: @switch_lookup_with_small_i8_negative(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[REM:%.*]] = urem i64 [[X:%.*]], 9
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[REM]], 3
|
|
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i64 [[REM]] to i24
|
|
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i24 [[SWITCH_CAST]], 8
|
|
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i24 460303, [[SWITCH_SHIFTAMT]]
|
|
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i24 [[SWITCH_DOWNSHIFT]] to i8
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i8 [[SWITCH_MASKED]], i8 0
|
|
; CHECK-NEXT: ret i8 [[TMP1]]
|
|
;
|
|
entry:
|
|
%rem = urem i64 %x, 9 ; 9 * 8 = 72 > 64, not fit the register
|
|
switch i64 %rem, label %default [
|
|
i64 0, label %sw.bb0
|
|
i64 1, label %sw.bb1
|
|
i64 2, label %sw.bb2
|
|
]
|
|
|
|
sw.bb0: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
sw.bb1: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
sw.bb2: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
default: ; preds = %entry
|
|
br label %lor.end
|
|
|
|
lor.end:
|
|
%0 = phi i8 [ 15, %sw.bb0 ], [ 6, %sw.bb1 ], [ 7, %sw.bb2 ], [ 0, %default ]
|
|
ret i8 %0
|
|
}
|
|
|
|
; Negative test: The default branch is unreachable, also it has no result.
|
|
define i1 @switch_lookup_with_small_i1_default_unreachable(i32 %x) {
|
|
; CHECK-LABEL: @switch_lookup_with_small_i1_default_unreachable(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
entry:
|
|
%and = and i32 %x, 15
|
|
switch i32 %and, label %default [
|
|
i32 4, label %phi.end
|
|
i32 2, label %phi.end
|
|
i32 10, label %phi.end
|
|
i32 9, label %phi.end
|
|
i32 1, label %sw.bb1.i
|
|
i32 3, label %sw.bb1.i
|
|
i32 5, label %sw.bb1.i
|
|
i32 0, label %sw.bb1.i
|
|
i32 6, label %sw.bb1.i
|
|
i32 7, label %sw.bb1.i
|
|
i32 8, label %sw.bb1.i
|
|
]
|
|
|
|
sw.bb1.i: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry
|
|
br label %phi.end
|
|
|
|
default: ; preds = %entry
|
|
unreachable
|
|
|
|
phi.end: ; preds = %sw.bb1.i, %entry, %entry, %entry, %entry
|
|
%retval = phi i1 [ false, %sw.bb1.i ], [ false, %entry ], [ false, %entry ], [ false, %entry ], [ false, %entry ]
|
|
ret i1 %retval
|
|
}
|
|
|
|
; Negative test: The result in default reachable, but its value is not const.
|
|
define i1 @switch_lookup_with_small_i1_default_nonconst(i64 %x) {
|
|
; CHECK-LABEL: @switch_lookup_with_small_i1_default_nonconst(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[AND:%.*]] = and i64 [[X:%.*]], 15
|
|
; CHECK-NEXT: switch i64 [[AND]], label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i64 10, label [[LOR_END:%.*]]
|
|
; CHECK-NEXT: i64 1, label [[LOR_END]]
|
|
; CHECK-NEXT: i64 2, label [[LOR_END]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: default:
|
|
; CHECK-NEXT: [[CALL:%.*]] = tail call i1 @foo()
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[CALL]], [[DEFAULT]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
|
|
; CHECK-NEXT: ret i1 [[TMP0]]
|
|
;
|
|
entry:
|
|
%and = and i64 %x, 15
|
|
switch i64 %and, label %default [
|
|
i64 10, label %lor.end
|
|
i64 1, label %lor.end
|
|
i64 2, label %lor.end
|
|
]
|
|
|
|
default: ; preds = %entry
|
|
%call = tail call i1 @foo()
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %entry, %entry, %entry, %default
|
|
%0 = phi i1 [ true, %entry ], [ %call, %default ], [ true, %entry ], [ true, %entry ]
|
|
ret i1 %0
|
|
}
|
|
|
|
; Negative test: The upper bound index of switch is swapped.
|
|
define void @switch_lookup_with_nonconst_range(i32 %x, i1 %cond) {
|
|
; CHECK-LABEL: @switch_lookup_with_nonconst_range(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_PREHEADER:%.*]]
|
|
; CHECK: for.preheader:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_PREHEADER]], label [[FOR_END:%.*]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[ADD]], 6
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[LOR_END:%.*]]
|
|
; CHECK: switch.lookup:
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[ADD]] to i64
|
|
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [6 x i32], ptr @switch.table.switch_lookup_with_nonconst_range, i64 0, i64 [[TMP1]]
|
|
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
|
|
; CHECK-NEXT: br label [[LOR_END]]
|
|
; CHECK: lor.end:
|
|
; CHECK-NEXT: [[RETVAL_0_I_I:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 1, [[FOR_END]] ]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %for.preheader
|
|
|
|
for.preheader: ; preds = %for.preheader, %entry
|
|
%add = add nuw i32 %x, 1 ; the UpperBound is unconfirmed
|
|
br i1 %cond, label %for.preheader, label %for.end
|
|
|
|
for.end: ; preds = %for.preheader
|
|
switch i32 %add, label %default [
|
|
i32 0, label %lor.end
|
|
i32 1, label %lor.end
|
|
i32 5, label %lor.end
|
|
]
|
|
|
|
default: ; preds = %for.end
|
|
br label %lor.end
|
|
|
|
lor.end: ; preds = %default, %for.end, %for.end, %for.end
|
|
%retval.0.i.i = phi i32 [ 1, %default ], [ 0, %for.end ], [ 0, %for.end ], [ 0, %for.end ]
|
|
ret void
|
|
}
|
|
|
|
define i1 @pr88607() {
|
|
; CHECK-LABEL: @pr88607(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[COND:%.*]] = select i1 false, i32 4, i32 1
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 false, i32 2, i32 [[COND]]
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
entry:
|
|
%cond = select i1 false, i32 4, i32 1
|
|
%spec.select = select i1 false, i32 2, i32 %cond
|
|
switch i32 %spec.select, label %lor.rhs [
|
|
i32 0, label %exit
|
|
i32 5, label %exit ; unreachable large case index
|
|
i32 1, label %exit
|
|
]
|
|
|
|
lor.rhs: ; preds = %entry
|
|
br label %exit
|
|
|
|
exit: ; preds = %lor.rhs, %entry, %entry, %entry, %entry
|
|
%res.ph = phi i1 [ false, %entry ], [ false, %lor.rhs ], [ false, %entry ], [ false, %entry ]
|
|
ret i1 %res.ph
|
|
}
|
|
|