Johannes Doerfert 84bf0da34d
[Attributor][FIX] Ensure to always translate call site arguments (#107323)
When we propagate call site arguments we always need to translate them,
this is important as we ended up picking the function argument for a
recurisve call not the call site argument. `@recBad` and `@recGood` in
`returned.ll` show the problem as they used to transform them the same
way. The restructuring cleans the code up and helps derive more
"returned" arguments and better information in the presence of recursive
calls. The "dropped" attributes are simply dropped because we do not
query them anymore, not because we cannot derive them.
2024-09-05 13:37:21 -07:00

1787 lines
69 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; FIXME: CGSCC is not looking at callees and calleers even though it could be allowed.
define i32 @test0(ptr %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define {{[^@]+}}@test0
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]]
; CHECK-NEXT: ret i32 [[A]]
;
%a = load i32, ptr %p, !range !0
ret i32 %a
}
define i32 @test0-range-check(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@test0-range-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[A:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3:[0-9]+]], !range [[RNG0]]
; TUNIT-NEXT: ret i32 [[A]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@test0-range-check
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: [[A:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5:[0-9]+]]
; CGSCC-NEXT: ret i32 [[A]]
;
%a = tail call i32 @test0(ptr %p)
ret i32 %a
}
declare void @use3-dummy(i1, i1, i1)
define void @use3(i1, i1, i1) {
; CHECK-LABEL: define {{[^@]+}}@use3
; CHECK-SAME: (i1 [[TMP0:%.*]], i1 [[TMP1:%.*]], i1 [[TMP2:%.*]]) {
; CHECK-NEXT: tail call void @use3-dummy(i1 [[TMP0]], i1 [[TMP1]], i1 [[TMP2]])
; CHECK-NEXT: ret void
;
tail call void @use3-dummy(i1 %0, i1 %1, i1 %2)
ret void
}
; TEST0 icmp test
define void @test0-icmp-check(ptr %p){
; ret = [0, 10)
; TUNIT-LABEL: define {{[^@]+}}@test0-icmp-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) {
; TUNIT-NEXT: [[RET:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
; TUNIT-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_EQ_6:%.*]] = icmp eq i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_EQ_1]], i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 [[CMP_EQ_6]])
; TUNIT-NEXT: [[CMP_NE_1:%.*]] = icmp ne i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_NE_6:%.*]] = icmp ne i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_NE_1]], i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 [[CMP_NE_6]])
; TUNIT-NEXT: [[CMP_UGT_1:%.*]] = icmp ugt i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_UGT_2:%.*]] = icmp ugt i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_UGT_1]], i1 [[CMP_UGT_2]], i1 [[CMP_UGT_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 noundef false)
; TUNIT-NEXT: [[CMP_UGE_1:%.*]] = icmp uge i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_UGE_6:%.*]] = icmp uge i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_UGE_1]], i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 noundef true, i1 [[CMP_UGE_6]])
; TUNIT-NEXT: [[CMP_SGT_1:%.*]] = icmp sgt i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_SGT_2:%.*]] = icmp sgt i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_SGT_6:%.*]] = icmp sgt i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_SGT_1]], i1 [[CMP_SGT_2]], i1 [[CMP_SGT_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 [[CMP_SGT_6]])
; TUNIT-NEXT: [[CMP_GTE_1:%.*]] = icmp sge i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_GTE_5:%.*]] = icmp sge i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_GTE_6:%.*]] = icmp sge i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_GTE_1]], i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 [[CMP_GTE_5]], i1 [[CMP_GTE_6]])
; TUNIT-NEXT: [[CMP_SLT_1:%.*]] = icmp slt i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_SLT_5:%.*]] = icmp slt i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_SLT_6:%.*]] = icmp slt i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_SLT_1]], i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 [[CMP_SLT_5]], i1 [[CMP_SLT_6]])
; TUNIT-NEXT: [[CMP_LTE_1:%.*]] = icmp sle i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_LTE_2:%.*]] = icmp sle i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; TUNIT-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; TUNIT-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; TUNIT-NEXT: [[CMP_LTE_6:%.*]] = icmp sle i32 [[RET]], -1
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_LTE_1]], i1 [[CMP_LTE_2]], i1 [[CMP_LTE_3]])
; TUNIT-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 [[CMP_LTE_6]])
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@test0-icmp-check
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) {
; CGSCC-NEXT: [[RET:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5]]
; CGSCC-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_EQ_6:%.*]] = icmp eq i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_EQ_1]], i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 [[CMP_EQ_6]])
; CGSCC-NEXT: [[CMP_NE_1:%.*]] = icmp ne i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_NE_6:%.*]] = icmp ne i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_NE_1]], i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 [[CMP_NE_6]])
; CGSCC-NEXT: [[CMP_UGT_1:%.*]] = icmp ugt i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_UGT_2:%.*]] = icmp ugt i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_UGT_1]], i1 [[CMP_UGT_2]], i1 [[CMP_UGT_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 noundef false)
; CGSCC-NEXT: [[CMP_UGE_1:%.*]] = icmp uge i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_UGE_6:%.*]] = icmp uge i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_UGE_1]], i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 noundef true, i1 [[CMP_UGE_6]])
; CGSCC-NEXT: [[CMP_SGT_1:%.*]] = icmp sgt i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_SGT_2:%.*]] = icmp sgt i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_SGT_6:%.*]] = icmp sgt i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_SGT_1]], i1 [[CMP_SGT_2]], i1 [[CMP_SGT_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 [[CMP_SGT_6]])
; CGSCC-NEXT: [[CMP_GTE_1:%.*]] = icmp sge i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_GTE_5:%.*]] = icmp sge i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_GTE_6:%.*]] = icmp sge i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_GTE_1]], i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 [[CMP_GTE_5]], i1 [[CMP_GTE_6]])
; CGSCC-NEXT: [[CMP_SLT_1:%.*]] = icmp slt i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_SLT_5:%.*]] = icmp slt i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_SLT_6:%.*]] = icmp slt i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_SLT_1]], i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 [[CMP_SLT_5]], i1 [[CMP_SLT_6]])
; CGSCC-NEXT: [[CMP_LTE_1:%.*]] = icmp sle i32 [[RET]], 10
; CGSCC-NEXT: [[CMP_LTE_2:%.*]] = icmp sle i32 [[RET]], 9
; CGSCC-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; CGSCC-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; CGSCC-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; CGSCC-NEXT: [[CMP_LTE_6:%.*]] = icmp sle i32 [[RET]], -1
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_LTE_1]], i1 [[CMP_LTE_2]], i1 [[CMP_LTE_3]])
; CGSCC-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 [[CMP_LTE_6]])
; CGSCC-NEXT: ret void
;
%ret = tail call i32 @test0(ptr %p)
; ret = [0, 10), eq
%cmp-eq-1 = icmp eq i32 %ret, 10
%cmp-eq-2 = icmp eq i32 %ret, 9
%cmp-eq-3 = icmp eq i32 %ret, 8
%cmp-eq-4 = icmp eq i32 %ret, 1
%cmp-eq-5 = icmp eq i32 %ret, 0
%cmp-eq-6 = icmp eq i32 %ret, -1
tail call void @use3(i1 %cmp-eq-1, i1 %cmp-eq-2, i1 %cmp-eq-3)
tail call void @use3(i1 %cmp-eq-4, i1 %cmp-eq-5, i1 %cmp-eq-6)
; ret = [0, 10), ne
%cmp-ne-1 = icmp ne i32 %ret, 10
%cmp-ne-2 = icmp ne i32 %ret, 9
%cmp-ne-3 = icmp ne i32 %ret, 8
%cmp-ne-4 = icmp ne i32 %ret, 1
%cmp-ne-5 = icmp ne i32 %ret, 0
%cmp-ne-6 = icmp ne i32 %ret, -1
tail call void @use3(i1 %cmp-ne-1, i1 %cmp-ne-2, i1 %cmp-ne-3)
tail call void @use3(i1 %cmp-ne-4, i1 %cmp-ne-5, i1 %cmp-ne-6)
; ret = [0, 10), ugt
%cmp-ugt-1 = icmp ugt i32 %ret, 10
%cmp-ugt-2 = icmp ugt i32 %ret, 9
%cmp-ugt-3 = icmp ugt i32 %ret, 8
%cmp-ugt-4 = icmp ugt i32 %ret, 1
%cmp-ugt-5 = icmp ugt i32 %ret, 0
%cmp-ugt-6 = icmp ugt i32 %ret, -1
tail call void @use3(i1 %cmp-ugt-1, i1 %cmp-ugt-2, i1 %cmp-ugt-3)
tail call void @use3(i1 %cmp-ugt-4, i1 %cmp-ugt-5, i1 %cmp-ugt-6)
; ret = [0, 10), uge
%cmp-uge-1 = icmp uge i32 %ret, 10
%cmp-uge-2 = icmp uge i32 %ret, 9
%cmp-uge-3 = icmp uge i32 %ret, 8
%cmp-uge-4 = icmp uge i32 %ret, 1
%cmp-uge-5 = icmp uge i32 %ret, 0
%cmp-uge-6 = icmp uge i32 %ret, -1
tail call void @use3(i1 %cmp-uge-1, i1 %cmp-uge-2, i1 %cmp-uge-3)
tail call void @use3(i1 %cmp-uge-4, i1 %cmp-uge-5, i1 %cmp-uge-6)
; ret = [0, 10), sgt
%cmp-sgt-1 = icmp sgt i32 %ret, 10
%cmp-sgt-2 = icmp sgt i32 %ret, 9
%cmp-sgt-3 = icmp sgt i32 %ret, 8
%cmp-sgt-4 = icmp sgt i32 %ret, 1
%cmp-sgt-5 = icmp sgt i32 %ret, 0
%cmp-sgt-6 = icmp sgt i32 %ret, -1
tail call void @use3(i1 %cmp-sgt-1, i1 %cmp-sgt-2, i1 %cmp-sgt-3)
tail call void @use3(i1 %cmp-sgt-4, i1 %cmp-sgt-5, i1 %cmp-sgt-6)
; ret = [0, 10), sge
%cmp-gte-1 = icmp sge i32 %ret, 10
%cmp-gte-2 = icmp sge i32 %ret, 9
%cmp-gte-3 = icmp sge i32 %ret, 8
%cmp-gte-4 = icmp sge i32 %ret, 1
%cmp-gte-5 = icmp sge i32 %ret, 0
%cmp-gte-6 = icmp sge i32 %ret, -1
tail call void @use3(i1 %cmp-gte-1, i1 %cmp-gte-2, i1 %cmp-gte-3)
tail call void @use3(i1 %cmp-gte-4, i1 %cmp-gte-5, i1 %cmp-gte-6)
; ret = [0, 10), slt
%cmp-slt-1 = icmp slt i32 %ret, 10
%cmp-slt-2 = icmp slt i32 %ret, 9
%cmp-slt-3 = icmp slt i32 %ret, 8
%cmp-slt-4 = icmp slt i32 %ret, 1
%cmp-slt-5 = icmp slt i32 %ret, 0
%cmp-slt-6 = icmp slt i32 %ret, -1
tail call void @use3(i1 %cmp-slt-1, i1 %cmp-slt-2, i1 %cmp-slt-3)
tail call void @use3(i1 %cmp-slt-4, i1 %cmp-slt-5, i1 %cmp-slt-6)
; ret = [0, 10), sle
%cmp-lte-1 = icmp sle i32 %ret, 10
%cmp-lte-2 = icmp sle i32 %ret, 9
%cmp-lte-3 = icmp sle i32 %ret, 8
%cmp-lte-4 = icmp sle i32 %ret, 1
%cmp-lte-5 = icmp sle i32 %ret, 0
%cmp-lte-6 = icmp sle i32 %ret, -1
tail call void @use3(i1 %cmp-lte-1, i1 %cmp-lte-2, i1 %cmp-lte-3)
tail call void @use3(i1 %cmp-lte-4, i1 %cmp-lte-5, i1 %cmp-lte-6)
ret void
}
define i32 @test1(ptr %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define {{[^@]+}}@test1
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[LOAD_10_100:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1:![0-9]+]]
; CHECK-NEXT: [[ADD_10_THEN_20_110:%.*]] = add i32 [[LOAD_10_100]], 10
; CHECK-NEXT: [[MUL_10_THEN_200_1091:%.*]] = mul i32 [[ADD_10_THEN_20_110]], 10
; CHECK-NEXT: ret i32 [[MUL_10_THEN_200_1091]]
;
%load-10-100 = load i32, ptr %p, !range !1
%add-10-then-20-110 = add i32 %load-10-100, 10
%mul-10-then-200-1091 = mul i32 %add-10-then-20-110, 10
ret i32 %mul-10-then-200-1091
}
define i1 @test1-check(ptr %p) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@test1-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[RES:%.*]] = tail call i32 @test1(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]], !range [[RNG2:![0-9]+]]
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; TUNIT-NEXT: ret i1 [[CMP]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@test1-check
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: [[RES:%.*]] = tail call i32 @test1(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5]]
; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; CGSCC-NEXT: ret i1 [[CMP]]
;
%res = tail call i32 @test1(ptr %p)
%cmp = icmp eq i32 %res, 500
ret i1 %cmp
}
; TEST2
; int test2(int *p) { return *p == 0 ? 4 : 3; }
; int test2_check(int *p) {
; int call = test2(p);
; if (call == 5) {
; // dead block
; return 2;
; } else {
; return 3;
; }
; }
define i32 @test2(ptr %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define {{[^@]+}}@test2
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 4, i32 3
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%0 = load i32, ptr %p, align 4
%tobool = icmp eq i32 %0, 0
%cond = select i1 %tobool, i32 4, i32 3
ret i32 %cond
}
define i32 @test2_check(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@test2_check
; TUNIT-SAME: (ptr nocapture nofree readnone align 4 [[P:%.*]]) #[[ATTR1:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: br label [[IF_THEN:%.*]]
; TUNIT: if.then:
; TUNIT-NEXT: br label [[RETURN:%.*]]
; TUNIT: if.end:
; TUNIT-NEXT: unreachable
; TUNIT: return:
; TUNIT-NEXT: ret i32 2
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@test2_check
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = tail call i32 @test2(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5]]
; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 5
; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CGSCC: if.then:
; CGSCC-NEXT: br label [[RETURN:%.*]]
; CGSCC: if.end:
; CGSCC-NEXT: br label [[RETURN]]
; CGSCC: return:
; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 2, [[IF_THEN]] ], [ 3, [[IF_END]] ]
; CGSCC-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%call = tail call i32 @test2(ptr %p)
%cmp = icmp slt i32 %call, 5
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
br label %return
if.end: ; preds = %entry
br label %return
return: ; preds = %if.end, %if.then
%retval.0 = phi i32 [ 2, %if.then ], [ 3, %if.end ]
ret i32 %retval.0
}
; TEST 3 SECV test
; void unkown();
; int r1(unsigned int u){
; int sum = 0;
; for(int i = 0; i<100;i++){
; sum += i;
; }
; // sum = 50 * 49 / 2
; if(sum > 10000){
; // dead block
; return 20;
; }else {
; return 10;
; }
; }
; void f1(int u){
; if(r1(u) > 15){
; // deadblock
; unkown();
; }else {
; return;
; }
; }
declare dso_local void @unkown()
define internal i32 @r1(i32) local_unnamed_addr {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@r1
; TUNIT-SAME: () local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: br label [[TMP4:%.*]]
; TUNIT: 1:
; TUNIT-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP7:%.*]], 10000
; TUNIT-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[F:%.*]]
; TUNIT: 3:
; TUNIT-NEXT: ret i32 20
; TUNIT: f:
; TUNIT-NEXT: ret i32 10
; TUNIT: 4:
; TUNIT-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP8:%.*]], [[TMP4]] ]
; TUNIT-NEXT: [[TMP6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP7]], [[TMP4]] ]
; TUNIT-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP5]], [[TMP6]]
; TUNIT-NEXT: [[TMP8]] = add nuw nsw i32 [[TMP5]], 1
; TUNIT-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 100
; TUNIT-NEXT: br i1 [[TMP9]], label [[TMP1:%.*]], label [[TMP4]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@r1
; CGSCC-SAME: () local_unnamed_addr #[[ATTR2:[0-9]+]] {
; CGSCC-NEXT: br label [[TMP4:%.*]]
; CGSCC: 1:
; CGSCC-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP7:%.*]], 10000
; CGSCC-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[F:%.*]]
; CGSCC: 3:
; CGSCC-NEXT: ret i32 20
; CGSCC: f:
; CGSCC-NEXT: ret i32 10
; CGSCC: 4:
; CGSCC-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP8:%.*]], [[TMP4]] ]
; CGSCC-NEXT: [[TMP6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP7]], [[TMP4]] ]
; CGSCC-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP5]], [[TMP6]]
; CGSCC-NEXT: [[TMP8]] = add nuw nsw i32 [[TMP5]], 1
; CGSCC-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 100
; CGSCC-NEXT: br i1 [[TMP9]], label [[TMP1:%.*]], label [[TMP4]]
;
br label %5
2: ; preds = %5
%3 = icmp sgt i32 %8, 10000
br i1 %3, label %4, label %f
4:
ret i32 20
f:
ret i32 10
5: ; preds = %5, %1
%6 = phi i32 [ 0, %1 ], [ %9, %5 ]
%7 = phi i32 [ 0, %1 ], [ %8, %5 ]
%8 = add nuw nsw i32 %6, %7
%9 = add nuw nsw i32 %6, 1
%10 = icmp eq i32 %9, 100
br i1 %10, label %2, label %5
}
define void @f1(i32){
; TUNIT-LABEL: define {{[^@]+}}@f1
; TUNIT-SAME: (i32 [[TMP0:%.*]]) {
; TUNIT-NEXT: [[TMP2:%.*]] = tail call i32 @r1() #[[ATTR4:[0-9]+]]
; TUNIT-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; TUNIT-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; TUNIT: 4:
; TUNIT-NEXT: tail call void @unkown()
; TUNIT-NEXT: br label [[TMP5]]
; TUNIT: 5:
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@f1
; CGSCC-SAME: (i32 [[TMP0:%.*]]) {
; CGSCC-NEXT: [[TMP2:%.*]] = tail call i32 @r1() #[[ATTR6:[0-9]+]]
; CGSCC-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; CGSCC-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; CGSCC: 4:
; CGSCC-NEXT: tail call void @unkown()
; CGSCC-NEXT: br label [[TMP5]]
; CGSCC: 5:
; CGSCC-NEXT: ret void
;
%2 = tail call i32 @r1(i32 %0)
%3 = icmp sgt i32 %2, 15
br i1 %3, label %4, label %5
4: ; preds = %1
tail call void @unkown()
br label %5
5: ; preds = %1, %4
ret void
}
; TEST4 LVI test
; f1
; int test4-f1(int u){
; if(u>=0) {
; return u;
; }else{
; return 0;
; }
; }
define dso_local i32 @test4-f1(i32 %u) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@test4-f1
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[U]], -1
; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[RETURN:%.*]]
; TUNIT: if.then:
; TUNIT-NEXT: br label [[RETURN]]
; TUNIT: return:
; TUNIT-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[U]], [[IF_THEN]] ], [ 0, [[ENTRY:%.*]] ]
; TUNIT-NEXT: ret i32 [[RETVAL_0]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@test4-f1
; CGSCC-SAME: (i32 [[U:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[U]], -1
; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[RETURN:%.*]]
; CGSCC: if.then:
; CGSCC-NEXT: br label [[RETURN]]
; CGSCC: return:
; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[U]], [[IF_THEN]] ], [ 0, [[ENTRY:%.*]] ]
; CGSCC-NEXT: ret i32 [[RETVAL_0]]
;
; FIXME: RETVAL_0 >= 0
entry:
%cmp = icmp sgt i32 %u, -1
br i1 %cmp, label %if.then, label %return
if.then: ; preds = %entry
br label %return
return: ; preds = %entry, %if.then
%retval.0 = phi i32 [ %u, %if.then ], [ 0, %entry ]
ret i32 %retval.0
}
define dso_local i32 @test4-g1(i32 %u) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@test4-g1
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CALL:%.*]] = tail call i32 @test4-f1(i32 [[U]]) #[[ATTR4]]
; TUNIT-NEXT: ret i32 [[CALL]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@test4-g1
; CGSCC-SAME: (i32 [[U:%.*]]) #[[ATTR3:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = tail call i32 @test4-f1(i32 [[U]]) #[[ATTR7:[0-9]+]]
; CGSCC-NEXT: ret i32 [[CALL]]
;
; FIXME: %call should have range [0, inf]
entry:
%call = tail call i32 @test4-f1(i32 %u)
ret i32 %call
}
; f2
; int test4-f1(int u){
; if(u>-1) {
; return u+1;
; }else{
; return 1;
; }
; }
define dso_local i32 @test4-f2(i32 %u) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@test4-f2
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[U]], -1
; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; TUNIT: if.then:
; TUNIT-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[U]], 1
; TUNIT-NEXT: br label [[RETURN:%.*]]
; TUNIT: if.else:
; TUNIT-NEXT: br label [[RETURN]]
; TUNIT: return:
; TUNIT-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[ADD]], [[IF_THEN]] ], [ 1, [[IF_ELSE]] ]
; TUNIT-NEXT: ret i32 [[RETVAL_0]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@test4-f2
; CGSCC-SAME: (i32 [[U:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[U]], -1
; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CGSCC: if.then:
; CGSCC-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[U]], 1
; CGSCC-NEXT: br label [[RETURN:%.*]]
; CGSCC: if.else:
; CGSCC-NEXT: br label [[RETURN]]
; CGSCC: return:
; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[ADD]], [[IF_THEN]] ], [ 1, [[IF_ELSE]] ]
; CGSCC-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%cmp = icmp sgt i32 %u, -1
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %entry
%add = add nuw nsw i32 %u, 1
br label %return
if.else: ; preds = %entry
br label %return
return: ; preds = %if.else, %if.then
%retval.0 = phi i32 [ %add, %if.then ], [ 1, %if.else ]
ret i32 %retval.0
}
define dso_local i32 @test4-g2(i32 %u) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@test4-g2
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #[[ATTR4]], !range [[RNG3:![0-9]+]]
; TUNIT-NEXT: ret i32 [[CALL]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@test4-g2
; CGSCC-SAME: (i32 [[U:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #[[ATTR7]]
; CGSCC-NEXT: ret i32 [[CALL]]
;
entry:
%call = tail call i32 @test4-f2(i32 %u)
ret i32 %call
}
define dso_local i32 @test-5() {
; TUNIT-LABEL: define {{[^@]+}}@test-5() {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CALL:%.*]] = call i32 @rec(i32 noundef 0)
; TUNIT-NEXT: ret i32 [[CALL]]
;
; CGSCC-LABEL: define {{[^@]+}}@test-5() {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = call noundef i32 @rec(i32 noundef 0)
; CGSCC-NEXT: ret i32 [[CALL]]
;
entry:
%call = call i32 @rec(i32 0)
ret i32 %call
}
define internal i32 @rec(i32 %depth) {
; CHECK-LABEL: define {{[^@]+}}@rec
; CHECK-SAME: (i32 [[DEPTH:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo(i32 [[DEPTH]])
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[CALL]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[DEPTH]], 10
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END3:%.*]]
; CHECK: if.then1:
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[DEPTH]], 1
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @rec(i32 [[ADD]])
; CHECK-NEXT: br label [[IF_END3]]
; CHECK: if.end3:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ 1, [[IF_END3]] ]
; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%call = call i32 @foo(i32 %depth)
%tobool = icmp ne i32 %call, 0
br i1 %tobool, label %if.then, label %if.end
if.then: ; preds = %entry
br label %return
if.end: ; preds = %entry
%cmp = icmp slt i32 %depth, 10
br i1 %cmp, label %if.then1, label %if.end3
if.then1: ; preds = %if.end
%add = add nsw i32 %depth, 1
%call2 = call i32 @rec(i32 %add)
br label %if.end3
if.end3: ; preds = %if.then1, %if.end
br label %return
return: ; preds = %if.end3, %if.then
%retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.end3 ]
ret i32 %retval.0
}
declare dso_local i32 @foo(i32)
; Examples taken from https://llvm.discourse.group/t/impossible-condition-optimization/461/1
;
; The important part is that we return a constant (false)
;
; {
; FIXME: All but the return is not needed anymore
define dso_local zeroext i1 @phi(i32 %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@phi
; TUNIT-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: bb:
; TUNIT-NEXT: [[TMP:%.*]] = icmp sgt i32 [[ARG]], 5
; TUNIT-NEXT: br i1 [[TMP]], label [[BB1:%.*]], label [[BB2:%.*]]
; TUNIT: bb1:
; TUNIT-NEXT: br label [[BB3:%.*]]
; TUNIT: bb2:
; TUNIT-NEXT: br label [[BB3]]
; TUNIT: bb3:
; TUNIT-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[ARG]], 10
; TUNIT-NEXT: br i1 [[TMP4]], label [[BB5:%.*]], label [[BB7:%.*]]
; TUNIT: bb5:
; TUNIT-NEXT: br label [[BB9:%.*]]
; TUNIT: bb7:
; TUNIT-NEXT: br label [[BB9]]
; TUNIT: bb9:
; TUNIT-NEXT: br label [[BB12:%.*]]
; TUNIT: bb11:
; TUNIT-NEXT: unreachable
; TUNIT: bb12:
; TUNIT-NEXT: br label [[BB13:%.*]]
; TUNIT: bb13:
; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@phi
; CGSCC-SAME: (i32 [[ARG:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: bb:
; CGSCC-NEXT: [[TMP:%.*]] = icmp sgt i32 [[ARG]], 5
; CGSCC-NEXT: br i1 [[TMP]], label [[BB1:%.*]], label [[BB2:%.*]]
; CGSCC: bb1:
; CGSCC-NEXT: br label [[BB3:%.*]]
; CGSCC: bb2:
; CGSCC-NEXT: br label [[BB3]]
; CGSCC: bb3:
; CGSCC-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[ARG]], 10
; CGSCC-NEXT: br i1 [[TMP4]], label [[BB5:%.*]], label [[BB7:%.*]]
; CGSCC: bb5:
; CGSCC-NEXT: br label [[BB9:%.*]]
; CGSCC: bb7:
; CGSCC-NEXT: br label [[BB9]]
; CGSCC: bb9:
; CGSCC-NEXT: br label [[BB12:%.*]]
; CGSCC: bb11:
; CGSCC-NEXT: unreachable
; CGSCC: bb12:
; CGSCC-NEXT: br label [[BB13:%.*]]
; CGSCC: bb13:
; CGSCC-NEXT: ret i1 false
;
bb:
%tmp = icmp sgt i32 %arg, 5
br i1 %tmp, label %bb1, label %bb2
bb1: ; preds = %bb
br label %bb3
bb2: ; preds = %bb
br label %bb3
bb3: ; preds = %bb2, %bb1
%.02 = phi i32 [ 1, %bb1 ], [ 2, %bb2 ]
%tmp4 = icmp sgt i32 %arg, 10
br i1 %tmp4, label %bb5, label %bb7
bb5: ; preds = %bb3
%tmp6 = add nsw i32 %.02, 1
br label %bb9
bb7: ; preds = %bb3
%tmp8 = add nsw i32 %.02, 2
br label %bb9
bb9: ; preds = %bb7, %bb5
%.01 = phi i32 [ %tmp6, %bb5 ], [ %tmp8, %bb7 ]
%tmp10 = icmp eq i32 %.01, 5
br i1 %tmp10, label %bb11, label %bb12
bb11: ; preds = %bb9
br label %bb13
bb12: ; preds = %bb9
br label %bb13
bb13: ; preds = %bb12, %bb11
%.0 = phi i1 [ true, %bb11 ], [ false, %bb12 ]
ret i1 %.0
}
define dso_local i1 @select(i32 %a) local_unnamed_addr #0 {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@select
; TUNIT-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@select
; CGSCC-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i1 false
;
entry:
%cmp = icmp sgt i32 %a, 5
%. = select i1 %cmp, i32 1, i32 2
%cmp1 = icmp sgt i32 %a, 10
%y.0.v = select i1 %cmp1, i32 1, i32 2
%y.0 = add nuw nsw i32 %., %y.0.v
%cmp6 = icmp eq i32 %y.0, 5
ret i1 %cmp6
}
define dso_local i32 @select_zext(i32 %a) local_unnamed_addr #0 {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@select_zext
; TUNIT-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: ret i32 0
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@select_zext
; CGSCC-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i32 0
;
entry:
%cmp = icmp sgt i32 %a, 5
%. = select i1 %cmp, i32 1, i32 2
%cmp1 = icmp sgt i32 %a, 10
%y.0.v = select i1 %cmp1, i32 1, i32 2
%y.0 = add nuw nsw i32 %., %y.0.v
%cmp6 = icmp eq i32 %y.0, 5
%.13 = zext i1 %cmp6 to i32
ret i32 %.13
}
define dso_local i64 @select_int2ptr_bitcast_ptr2int(i32 %a) local_unnamed_addr #0 {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@select_int2ptr_bitcast_ptr2int
; TUNIT-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
; TUNIT-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
; TUNIT-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
; TUNIT-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
; TUNIT-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
; TUNIT-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
; TUNIT-NEXT: [[I2P:%.*]] = inttoptr i1 [[CMP6]] to ptr
; TUNIT-NEXT: [[P2I:%.*]] = ptrtoint ptr [[I2P]] to i64
; TUNIT-NEXT: ret i64 [[P2I]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@select_int2ptr_bitcast_ptr2int
; CGSCC-SAME: (i32 [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 5
; CGSCC-NEXT: [[DOT:%.*]] = select i1 [[CMP]], i32 1, i32 2
; CGSCC-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 10
; CGSCC-NEXT: [[Y_0_V:%.*]] = select i1 [[CMP1]], i32 1, i32 2
; CGSCC-NEXT: [[Y_0:%.*]] = add nuw nsw i32 [[DOT]], [[Y_0_V]]
; CGSCC-NEXT: [[CMP6:%.*]] = icmp eq i32 [[Y_0]], 5
; CGSCC-NEXT: [[I2P:%.*]] = inttoptr i1 [[CMP6]] to ptr
; CGSCC-NEXT: [[P2I:%.*]] = ptrtoint ptr [[I2P]] to i64
; CGSCC-NEXT: ret i64 [[P2I]]
;
entry:
%cmp = icmp sgt i32 %a, 5
%. = select i1 %cmp, i32 1, i32 2
%cmp1 = icmp sgt i32 %a, 10
%y.0.v = select i1 %cmp1, i32 1, i32 2
%y.0 = add nuw nsw i32 %., %y.0.v
%cmp6 = icmp eq i32 %y.0, 5
%i2p = inttoptr i1 %cmp6 to ptr
%p2i = ptrtoint ptr %i2p to i64
ret i64 %p2i
}
; }
define i1 @f_fcmp(float %a, float %b) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@f_fcmp
; TUNIT-SAME: (float [[A:%.*]], float [[B:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R:%.*]] = fcmp uge float [[A]], [[B]]
; TUNIT-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; TUNIT-NEXT: ret i1 [[S]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@f_fcmp
; CGSCC-SAME: (float [[A:%.*]], float [[B:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[R:%.*]] = fcmp uge float [[A]], [[B]]
; CGSCC-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; CGSCC-NEXT: ret i1 [[S]]
;
%r = fcmp uge float %a, %b
%s = select i1 %r, i1 %r, i1 0
ret i1 %s
}
define i1 @d_fcmp(double %a, double %b) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@d_fcmp
; TUNIT-SAME: (double [[A:%.*]], double [[B:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R:%.*]] = fcmp oeq double [[A]], [[B]]
; TUNIT-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; TUNIT-NEXT: ret i1 [[S]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@d_fcmp
; CGSCC-SAME: (double [[A:%.*]], double [[B:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[R:%.*]] = fcmp oeq double [[A]], [[B]]
; CGSCC-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; CGSCC-NEXT: ret i1 [[S]]
;
%r = fcmp oeq double %a, %b
%s = select i1 %r, i1 %r, i1 0
ret i1 %s
}
define i1 @dp_icmp(ptr %a, ptr %b) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@dp_icmp
; TUNIT-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone [[B:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R:%.*]] = icmp sge ptr [[A]], [[B]]
; TUNIT-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; TUNIT-NEXT: ret i1 [[S]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@dp_icmp
; CGSCC-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone [[B:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[R:%.*]] = icmp sge ptr [[A]], [[B]]
; CGSCC-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; CGSCC-NEXT: ret i1 [[S]]
;
%r = icmp sge ptr %a, %b
%s = select i1 %r, i1 %r, i1 0
ret i1 %s
}
define i1 @ip_icmp(ptr %a, ptr %b) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ip_icmp
; TUNIT-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone [[B:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R:%.*]] = icmp ult ptr [[A]], [[B]]
; TUNIT-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; TUNIT-NEXT: ret i1 [[S]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ip_icmp
; CGSCC-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone [[B:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[R:%.*]] = icmp ult ptr [[A]], [[B]]
; CGSCC-NEXT: [[S:%.*]] = select i1 [[R]], i1 [[R]], i1 false
; CGSCC-NEXT: ret i1 [[S]]
;
%r = icmp ult ptr %a, %b
%s = select i1 %r, i1 %r, i1 0
ret i1 %s
}
define i1 @fcmp_caller(float %fa, float %fb, double %da, double %db, ptr %dpa, ptr %dpb, ptr %ipa, ptr %ipb) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@fcmp_caller
; TUNIT-SAME: (float [[FA:%.*]], float [[FB:%.*]], double [[DA:%.*]], double [[DB:%.*]], ptr nofree readnone [[DPA:%.*]], ptr nofree readnone [[DPB:%.*]], ptr nofree readnone [[IPA:%.*]], ptr nofree readnone [[IPB:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R1:%.*]] = call i1 @f_fcmp(float [[FA]], float [[FB]]) #[[ATTR4]]
; TUNIT-NEXT: [[R2:%.*]] = call i1 @d_fcmp(double [[DA]], double [[DB]]) #[[ATTR4]]
; TUNIT-NEXT: [[R3:%.*]] = call i1 @dp_icmp(ptr noalias nofree readnone [[DPA]], ptr noalias nofree readnone [[DPB]]) #[[ATTR4]]
; TUNIT-NEXT: [[R4:%.*]] = call i1 @ip_icmp(ptr noalias nofree readnone [[IPA]], ptr noalias nofree readnone [[IPB]]) #[[ATTR4]]
; TUNIT-NEXT: [[O1:%.*]] = or i1 [[R1]], [[R2]]
; TUNIT-NEXT: [[O2:%.*]] = or i1 [[R3]], [[R4]]
; TUNIT-NEXT: [[O3:%.*]] = or i1 [[O1]], [[O2]]
; TUNIT-NEXT: ret i1 [[O3]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@fcmp_caller
; CGSCC-SAME: (float [[FA:%.*]], float [[FB:%.*]], double [[DA:%.*]], double [[DB:%.*]], ptr nofree readnone [[DPA:%.*]], ptr nofree readnone [[DPB:%.*]], ptr nofree readnone [[IPA:%.*]], ptr nofree readnone [[IPB:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[R1:%.*]] = call i1 @f_fcmp(float [[FA]], float [[FB]]) #[[ATTR7]]
; CGSCC-NEXT: [[R2:%.*]] = call i1 @d_fcmp(double [[DA]], double [[DB]]) #[[ATTR7]]
; CGSCC-NEXT: [[R3:%.*]] = call i1 @dp_icmp(ptr noalias nofree readnone [[DPA]], ptr noalias nofree readnone [[DPB]]) #[[ATTR7]]
; CGSCC-NEXT: [[R4:%.*]] = call i1 @ip_icmp(ptr noalias nofree readnone [[IPA]], ptr noalias nofree readnone [[IPB]]) #[[ATTR7]]
; CGSCC-NEXT: [[O1:%.*]] = or i1 [[R1]], [[R2]]
; CGSCC-NEXT: [[O2:%.*]] = or i1 [[R3]], [[R4]]
; CGSCC-NEXT: [[O3:%.*]] = or i1 [[O1]], [[O2]]
; CGSCC-NEXT: ret i1 [[O3]]
;
%r1 = call i1 @f_fcmp(float %fa, float %fb)
%r2 = call i1 @d_fcmp(double %da, double %db)
%r3 = call i1 @dp_icmp(ptr %dpa, ptr %dpb)
%r4 = call i1 @ip_icmp(ptr %ipa, ptr %ipb)
%o1 = or i1 %r1, %r2
%o2 = or i1 %r3, %r4
%o3 = or i1 %o1, %o2
ret i1 %o3
}
define i8 @ret_two() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ret_two
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i8 2
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ret_two
; CGSCC-SAME: () #[[ATTR2]] {
; CGSCC-NEXT: ret i8 2
;
ret i8 2
}
define i8 @ret_undef() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ret_undef
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i8 undef
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ret_undef
; CGSCC-SAME: () #[[ATTR2]] {
; CGSCC-NEXT: ret i8 undef
;
ret i8 undef
}
; Verify we collapse undef to a value and return something non-undef here.
define i8 @undef_collapse_1() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@undef_collapse_1
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i8 0
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@undef_collapse_1
; CGSCC-SAME: () #[[ATTR3]] {
; CGSCC-NEXT: [[C:%.*]] = call i8 @ret_undef() #[[ATTR7]]
; CGSCC-NEXT: [[S:%.*]] = shl i8 [[C]], 2
; CGSCC-NEXT: ret i8 [[S]]
;
%c = call i8 @ret_undef()
%s = shl i8 %c, 2
ret i8 %s
}
; Verify we collapse undef to a value and return something non-undef here.
define i8 @undef_collapse_2() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@undef_collapse_2
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i8 0
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@undef_collapse_2
; CGSCC-SAME: () #[[ATTR3]] {
; CGSCC-NEXT: [[C:%.*]] = call i8 @ret_two() #[[ATTR7]]
; CGSCC-NEXT: [[S:%.*]] = shl i8 undef, [[C]]
; CGSCC-NEXT: ret i8 [[S]]
;
%c = call i8 @ret_two()
%s = shl i8 undef, %c
ret i8 %s
}
define i8 @undef_collapse_caller() {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@undef_collapse_caller
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i8 0
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@undef_collapse_caller
; CGSCC-SAME: () #[[ATTR3]] {
; CGSCC-NEXT: [[C1:%.*]] = call i8 @undef_collapse_1() #[[ATTR7]]
; CGSCC-NEXT: [[C2:%.*]] = call i8 @undef_collapse_2() #[[ATTR7]]
; CGSCC-NEXT: [[A:%.*]] = add i8 [[C1]], [[C2]]
; CGSCC-NEXT: ret i8 [[A]]
;
%c1 = call i8 @undef_collapse_1()
%c2 = call i8 @undef_collapse_2()
%a = add i8 %c1, %c2
ret i8 %a
}
define i32 @ret1or2(i1 %c) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ret1or2
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[S:%.*]] = select i1 [[C]], i32 1, i32 2
; TUNIT-NEXT: ret i32 [[S]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ret1or2
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[S:%.*]] = select i1 [[C]], i32 1, i32 2
; CGSCC-NEXT: ret i32 [[S]]
;
%s = select i1 %c, i32 1, i32 2
ret i32 %s
}
define i1 @callee_range_1(i1 %c1, i1 %c2, i1 %c3) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@callee_range_1
; TUNIT-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #[[ATTR4]]
; TUNIT-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #[[ATTR4]]
; TUNIT-NEXT: [[INDIRECTION:%.*]] = select i1 [[C3]], i32 [[R1]], i32 [[R2]]
; TUNIT-NEXT: [[A:%.*]] = add i32 [[R1]], [[INDIRECTION]]
; TUNIT-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 4
; TUNIT-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; TUNIT-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; TUNIT-NEXT: ret i1 [[F]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@callee_range_1
; CGSCC-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #[[ATTR7]]
; CGSCC-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #[[ATTR7]]
; CGSCC-NEXT: [[INDIRECTION:%.*]] = select i1 [[C3]], i32 [[R1]], i32 [[R2]]
; CGSCC-NEXT: [[A:%.*]] = add i32 [[R1]], [[INDIRECTION]]
; CGSCC-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 4
; CGSCC-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC-NEXT: ret i1 [[F]]
;
%r1 = call i32 @ret1or2(i1 %c1)
%r2 = call i32 @ret1or2(i1 %c2)
%indirection = select i1 %c3, i32 %r1, i32 %r2
%a = add i32 %r1, %indirection
%i1 = icmp sle i32 %a, 4
%i2 = icmp sge i32 %a, 2
%f = and i1 %i1, %i2
ret i1 %f
}
define i1 @callee_range_2(i1 %c1, i1 %c2) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@callee_range_2
; TUNIT-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #[[ATTR4]]
; TUNIT-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #[[ATTR4]]
; TUNIT-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; TUNIT-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; TUNIT-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; TUNIT-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; TUNIT-NEXT: ret i1 [[F]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@callee_range_2
; CGSCC-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #[[ATTR7]]
; CGSCC-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #[[ATTR7]]
; CGSCC-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; CGSCC-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; CGSCC-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC-NEXT: ret i1 [[F]]
;
%r1 = call i32 @ret1or2(i1 %c1)
%r2 = call i32 @ret1or2(i1 %c2)
%a = add i32 %r1, %r2
%i1 = icmp sle i32 %a, 3
%i2 = icmp sge i32 %a, 2
%f = and i1 %i1, %i2
ret i1 %f
}
define i32 @ret100() {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ret100
; TUNIT-SAME: () #[[ATTR1]] {
; TUNIT-NEXT: ret i32 100
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ret100
; CGSCC-SAME: () #[[ATTR2]] {
; CGSCC-NEXT: ret i32 100
;
ret i32 100
}
define i1 @ctx_adjustment(i32 %V) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@ctx_adjustment
; TUNIT-SAME: (i32 [[V:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; TUNIT-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; TUNIT: if.true:
; TUNIT-NEXT: br label [[END:%.*]]
; TUNIT: if.false:
; TUNIT-NEXT: br label [[END]]
; TUNIT: end:
; TUNIT-NEXT: [[PHI:%.*]] = phi i32 [ [[V]], [[IF_TRUE]] ], [ 100, [[IF_FALSE]] ]
; TUNIT-NEXT: [[C2:%.*]] = icmp sge i32 [[PHI]], 100
; TUNIT-NEXT: ret i1 [[C2]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@ctx_adjustment
; CGSCC-SAME: (i32 [[V:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; CGSCC-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CGSCC: if.true:
; CGSCC-NEXT: br label [[END:%.*]]
; CGSCC: if.false:
; CGSCC-NEXT: [[CALL:%.*]] = call i32 @ret100() #[[ATTR7]]
; CGSCC-NEXT: br label [[END]]
; CGSCC: end:
; CGSCC-NEXT: [[PHI:%.*]] = phi i32 [ [[V]], [[IF_TRUE]] ], [ [[CALL]], [[IF_FALSE]] ]
; CGSCC-NEXT: [[C2:%.*]] = icmp sge i32 [[PHI]], 100
; CGSCC-NEXT: ret i1 [[C2]]
;
%c1 = icmp sge i32 %V, 100
br i1 %c1, label %if.true, label %if.false
if.true:
br label %end
if.false:
%call = call i32 @ret100()
br label %end
end:
%phi = phi i32 [ %V, %if.true ], [ %call, %if.false ]
%c2 = icmp sge i32 %phi, 100
ret i1 %c2
}
define i32 @func(i1 %c) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@func
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[RET:%.*]] = select i1 [[C]], i32 0, i32 1
; TUNIT-NEXT: ret i32 [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@func
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[RET:%.*]] = select i1 [[C]], i32 0, i32 1
; CGSCC-NEXT: ret i32 [[RET]]
;
%ret = select i1 %c, i32 0, i32 1
ret i32 %ret
}
define i32 @simplify_callsite_argument(i1 %d) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@simplify_callsite_argument
; TUNIT-SAME: (i1 [[D:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[C:%.*]] = select i1 [[D]], i1 true, i1 false
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: [[RET1:%.*]] = call i32 @func(i1 noundef [[C]]) #[[ATTR4]]
; TUNIT-NEXT: ret i32 [[RET1]]
; TUNIT: f:
; TUNIT-NEXT: [[RET2:%.*]] = call i32 @func(i1 noundef false) #[[ATTR4]]
; TUNIT-NEXT: ret i32 [[RET2]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@simplify_callsite_argument
; CGSCC-SAME: (i1 [[D:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[C:%.*]] = select i1 [[D]], i1 true, i1 false
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: t:
; CGSCC-NEXT: [[RET1:%.*]] = call noundef i32 @func(i1 noundef [[C]]) #[[ATTR7]]
; CGSCC-NEXT: ret i32 [[RET1]]
; CGSCC: f:
; CGSCC-NEXT: [[RET2:%.*]] = call noundef i32 @func(i1 noundef false) #[[ATTR7]]
; CGSCC-NEXT: ret i32 [[RET2]]
;
%c = select i1 %d, i1 true, i1 false
br i1 %c, label %t, label %f
t:
%ret1 = call i32 @func(i1 %c)
ret i32 %ret1
f:
%ret2 = call i32 @func(i1 false)
ret i32 %ret2
}
define internal i32 @less_than_65536(i32 %arg) {
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@less_than_65536
; CGSCC-SAME: (i32 [[ARG:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[SHRINKED:%.*]] = udiv i32 [[ARG]], 65536
; CGSCC-NEXT: ret i32 [[SHRINKED]]
;
%shrinked = udiv i32 %arg, 65536
ret i32 %shrinked
}
define internal i1 @is_less_than_65536(i32 %arg) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@is_less_than_65536
; CGSCC-SAME: (i32 [[ARG:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp ult i32 [[ARG]], 65536
; CGSCC-NEXT: ret i1 [[CMP]]
;
%cmp = icmp ult i32 %arg, 65536
ret i1 %cmp
}
define i1 @check_divided_range(i32 %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@check_divided_range
; TUNIT-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: ret i1 true
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@check_divided_range
; CGSCC-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @less_than_65536(i32 noundef 0) #[[ATTR7]]
; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @less_than_65536(i32 [[ARG]]) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE1:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET1]]) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE2:%.*]] = call i1 @is_less_than_65536(i32 [[CSRET2]]) #[[ATTR7]]
; CGSCC-NEXT: [[RET:%.*]] = and i1 [[TRUE1]], [[TRUE2]]
; CGSCC-NEXT: ret i1 [[RET]]
;
%csret1 = call i32 @less_than_65536(i32 0)
%csret2 = call i32 @less_than_65536(i32 %arg)
%true1 = call i1 @is_less_than_65536(i32 %csret1)
%true2 = call i1 @is_less_than_65536(i32 %csret2)
%ret = and i1 %true1, %true2
ret i1 %ret
}
define internal i32 @cast_and_return(i1 %c) {
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@cast_and_return
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[C]] to i32
; CGSCC-NEXT: ret i32 [[RET]]
;
%ret = zext i1 %c to i32
ret i32 %ret
}
define internal i1 @is_less_than_3(i32 %c) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@is_less_than_3
; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 3
; CGSCC-NEXT: ret i1 [[CMP]]
;
%cmp = icmp slt i32 %c, 3
ret i1 %cmp
}
define i1 @check_casted_range(i1 %c) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@check_casted_range
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: ret i1 true
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@check_casted_range
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @cast_and_return(i1 noundef true) #[[ATTR7]]
; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @cast_and_return(i1 [[C]]) #[[ATTR7]]
; CGSCC-NEXT: [[ADD:%.*]] = add i32 [[CSRET1]], [[CSRET2]]
; CGSCC-NEXT: [[RET:%.*]] = call i1 @is_less_than_3(i32 [[ADD]]) #[[ATTR7]]
; CGSCC-NEXT: ret i1 [[RET]]
;
%csret1 = call i32 @cast_and_return(i1 true)
%csret2 = call i32 @cast_and_return(i1 %c)
%add = add i32 %csret1, %csret2
%ret = call i1 @is_less_than_3(i32 %add)
ret i1 %ret
}
define internal i32 @less_than_100_1(i32 %c) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@less_than_100_1
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
; CGSCC-NEXT: i32 0, label [[ONZERO:%.*]]
; CGSCC-NEXT: i32 1, label [[ONONE:%.*]]
; CGSCC-NEXT: i32 2, label [[ONTWO:%.*]]
; CGSCC-NEXT: i32 3, label [[ONTHREE:%.*]]
; CGSCC-NEXT: i32 4, label [[ONFOUR:%.*]]
; CGSCC-NEXT: i32 5, label [[ONFIVE:%.*]]
; CGSCC-NEXT: i32 6, label [[ONSIX:%.*]]
; CGSCC-NEXT: ]
; CGSCC: onzero:
; CGSCC-NEXT: ret i32 0
; CGSCC: onone:
; CGSCC-NEXT: ret i32 1
; CGSCC: ontwo:
; CGSCC-NEXT: ret i32 2
; CGSCC: onthree:
; CGSCC-NEXT: ret i32 3
; CGSCC: onfour:
; CGSCC-NEXT: ret i32 4
; CGSCC: onfive:
; CGSCC-NEXT: ret i32 5
; CGSCC: onsix:
; CGSCC-NEXT: ret i32 6
; CGSCC: otherwise:
; CGSCC-NEXT: ret i32 99
;
switch i32 %c, label %otherwise [ i32 0, label %onzero
i32 1, label %onone
i32 2, label %ontwo
i32 3, label %onthree
i32 4, label %onfour
i32 5, label %onfive
i32 6, label %onsix]
onzero:
ret i32 0
onone:
ret i32 1
ontwo:
ret i32 2
onthree:
ret i32 3
onfour:
ret i32 4
onfive:
ret i32 5
onsix:
ret i32 6
otherwise:
ret i32 99
}
define internal i1 @is_less_than_100_1(i32 %c) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@is_less_than_100_1
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 100
; CGSCC-NEXT: ret i1 [[CMP]]
;
%cmp = icmp slt i32 %c, 100
ret i1 %cmp
}
define i1 @propagate_range1(i32 %c){
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@propagate_range1
; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: ret i1 true
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@propagate_range1
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[CSRET:%.*]] = call i32 @less_than_100_1(i32 noundef [[C]]) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE:%.*]] = call i1 @is_less_than_100_1(i32 noundef [[CSRET]]) #[[ATTR7]]
; CGSCC-NEXT: ret i1 [[TRUE]]
;
%csret = call i32 @less_than_100_1(i32 %c)
%true = call i1 @is_less_than_100_1(i32 %csret)
ret i1 %true
}
define internal i32 @less_than_100_2(i32 %c) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@less_than_100_2
; TUNIT-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
; TUNIT-NEXT: i32 0, label [[ONZERO:%.*]]
; TUNIT-NEXT: i32 1, label [[ONONE:%.*]]
; TUNIT-NEXT: i32 2, label [[ONTWO:%.*]]
; TUNIT-NEXT: i32 3, label [[ONTHREE:%.*]]
; TUNIT-NEXT: i32 4, label [[ONFOUR:%.*]]
; TUNIT-NEXT: i32 5, label [[ONFIVE:%.*]]
; TUNIT-NEXT: i32 6, label [[ONSIX:%.*]]
; TUNIT-NEXT: ]
; TUNIT: onzero:
; TUNIT-NEXT: ret i32 0
; TUNIT: onone:
; TUNIT-NEXT: ret i32 1
; TUNIT: ontwo:
; TUNIT-NEXT: ret i32 2
; TUNIT: onthree:
; TUNIT-NEXT: ret i32 3
; TUNIT: onfour:
; TUNIT-NEXT: ret i32 4
; TUNIT: onfive:
; TUNIT-NEXT: ret i32 5
; TUNIT: onsix:
; TUNIT-NEXT: ret i32 6
; TUNIT: otherwise:
; TUNIT-NEXT: ret i32 99
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@less_than_100_2
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [
; CGSCC-NEXT: i32 0, label [[ONZERO:%.*]]
; CGSCC-NEXT: i32 1, label [[ONONE:%.*]]
; CGSCC-NEXT: i32 2, label [[ONTWO:%.*]]
; CGSCC-NEXT: i32 3, label [[ONTHREE:%.*]]
; CGSCC-NEXT: i32 4, label [[ONFOUR:%.*]]
; CGSCC-NEXT: i32 5, label [[ONFIVE:%.*]]
; CGSCC-NEXT: i32 6, label [[ONSIX:%.*]]
; CGSCC-NEXT: ]
; CGSCC: onzero:
; CGSCC-NEXT: ret i32 0
; CGSCC: onone:
; CGSCC-NEXT: ret i32 1
; CGSCC: ontwo:
; CGSCC-NEXT: ret i32 2
; CGSCC: onthree:
; CGSCC-NEXT: ret i32 3
; CGSCC: onfour:
; CGSCC-NEXT: ret i32 4
; CGSCC: onfive:
; CGSCC-NEXT: ret i32 5
; CGSCC: onsix:
; CGSCC-NEXT: ret i32 6
; CGSCC: otherwise:
; CGSCC-NEXT: ret i32 99
;
switch i32 %c, label %otherwise [ i32 0, label %onzero
i32 1, label %onone
i32 2, label %ontwo
i32 3, label %onthree
i32 4, label %onfour
i32 5, label %onfive
i32 6, label %onsix]
onzero:
ret i32 0
onone:
ret i32 1
ontwo:
ret i32 2
onthree:
ret i32 3
onfour:
ret i32 4
onfive:
ret i32 5
onsix:
ret i32 6
otherwise:
ret i32 99
}
define internal i1 @is_less_than_100_2(i32 %c) {
;
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@is_less_than_100_2
; TUNIT-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 100
; TUNIT-NEXT: ret i1 [[CMP]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@is_less_than_100_2
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 100
; CGSCC-NEXT: ret i1 [[CMP]]
;
%cmp = icmp slt i32 %c, 100
ret i1 %cmp
}
define i1 @propagate_range2(i32 %c) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@propagate_range2
; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[CSRET1:%.*]] = call noundef i32 @less_than_100_2(i32 noundef 0) #[[ATTR4]]
; TUNIT-NEXT: [[TRUE1:%.*]] = call i1 @is_less_than_100_2(i32 noundef [[CSRET1]]) #[[ATTR4]]
; TUNIT-NEXT: [[CSRET2:%.*]] = call noundef i32 @less_than_100_2(i32 noundef [[C]]) #[[ATTR4]]
; TUNIT-NEXT: [[TRUE2:%.*]] = call i1 @is_less_than_100_2(i32 noundef [[CSRET2]]) #[[ATTR4]]
; TUNIT-NEXT: [[TRUE:%.*]] = and i1 [[TRUE1]], [[TRUE2]]
; TUNIT-NEXT: ret i1 [[TRUE]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@propagate_range2
; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @less_than_100_2(i32 noundef 0) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE1:%.*]] = call i1 @is_less_than_100_2(i32 noundef [[CSRET1]]) #[[ATTR7]]
; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @less_than_100_2(i32 noundef [[C]]) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE2:%.*]] = call i1 @is_less_than_100_2(i32 noundef [[CSRET2]]) #[[ATTR7]]
; CGSCC-NEXT: [[TRUE:%.*]] = and i1 [[TRUE1]], [[TRUE2]]
; CGSCC-NEXT: ret i1 [[TRUE]]
;
%csret1 = call i32 @less_than_100_2(i32 0)
%true1 = call i1 @is_less_than_100_2(i32 %csret1)
%csret2 = call i32 @less_than_100_2(i32 %c)
%true2 = call i1 @is_less_than_100_2(i32 %csret2)
%true = and i1 %true1, %true2
ret i1 %true
}
define internal i1 @non_zero(i8 %v) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@non_zero
; TUNIT-SAME: (i8 [[V:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: [[R:%.*]] = icmp ne i8 [[V]], 0
; TUNIT-NEXT: ret i1 [[R]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@non_zero
; CGSCC-SAME: (i8 [[V:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: ret i1 true
;
%r = icmp ne i8 %v, 0
ret i1 %r
}
; Avoid range metadata for %l below
define i1 @context(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@context
; TUNIT-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1) [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; TUNIT-NEXT: [[C:%.*]] = icmp slt i8 0, [[L]]
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) #[[ATTR4]]
; TUNIT-NEXT: ret i1 [[R]]
; TUNIT: f:
; TUNIT-NEXT: ret i1 false
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@context
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly dereferenceable(1) [[P:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: [[L:%.*]] = load i8, ptr [[P]], align 1
; CGSCC-NEXT: [[C:%.*]] = icmp slt i8 0, [[L]]
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: t:
; CGSCC-NEXT: [[R:%.*]] = call noundef i1 @non_zero(i8 [[L]]) #[[ATTR7]]
; CGSCC-NEXT: ret i1 [[R]]
; CGSCC: f:
; CGSCC-NEXT: ret i1 false
;
%l = load i8, ptr %p
%c = icmp slt i8 0, %l
br i1 %c, label %t, label %f
t:
%r = call i1 @non_zero(i8 %l)
ret i1 %r
f:
ret i1 false
}
define void @spam(ptr %arg, ptr %arg1) {
; CHECK-LABEL: define {{[^@]+}}@spam
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[ARG:%.*]], ptr nocapture nofree readnone [[ARG1:%.*]]) {
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr [[ARG]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP]], 4
; CHECK-NEXT: br i1 [[TMP2]], label [[BB3:%.*]], label [[BB4:%.*]]
; CHECK: bb3:
; CHECK-NEXT: call fastcc void @wobble(i32 signext [[TMP]])
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: bb4:
; CHECK-NEXT: call void @ham(i32 [[TMP]])
; CHECK-NEXT: br label [[BB5]]
; CHECK: bb5:
; CHECK-NEXT: ret void
;
bb:
%tmp = load i32, ptr %arg, align 8
%tmp2 = icmp ult i32 %tmp, 4
br i1 %tmp2, label %bb3, label %bb4
bb3: ; preds = %bb
call fastcc void @wobble(i32 signext %tmp)
br label %bb5
bb4: ; preds = %bb
call void @ham(i32 %tmp)
br label %bb5
bb5: ; preds = %bb4, %bb3
ret void
}
define internal fastcc void @wobble(i32 signext %arg) {
; CHECK-LABEL: define {{[^@]+}}@wobble
; CHECK-SAME: (i32 signext [[ARG:%.*]]) {
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = icmp ult i32 [[ARG]], 2
; CHECK-NEXT: br i1 [[TMP]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: call void @barney(i32 noundef signext 32, i32 noundef signext 0)
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb2:
; CHECK-NEXT: br label [[BB3]]
; CHECK: bb3:
; CHECK-NEXT: ret void
;
bb:
%tmp = icmp ult i32 %arg, 2
br i1 %tmp, label %bb1, label %bb2
bb1: ; preds = %bb
call void @barney(i32 signext 32, i32 signext 0)
br label %bb3
bb2: ; preds = %bb
br label %bb3
bb3: ; preds = %bb2, %bb1
ret void
}
define i1 @loop_1(i32 %N) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none)
; TUNIT-LABEL: define {{[^@]+}}@loop_1
; TUNIT-SAME: (i32 [[N:%.*]]) #[[ATTR2:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: br label [[HEADER:%.*]]
; TUNIT: header:
; TUNIT-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[AND:%.*]], [[HEADER]] ]
; TUNIT-NEXT: [[INC:%.*]] = add i32 [[I]], 1
; TUNIT-NEXT: [[AND]] = and i32 [[INC]], 9999
; TUNIT-NEXT: [[CMP:%.*]] = icmp ne i32 [[N]], [[AND]]
; TUNIT-NEXT: br i1 [[CMP]], label [[HEADER]], label [[EXIT:%.*]]
; TUNIT: exit:
; TUNIT-NEXT: [[R:%.*]] = icmp sle i32 [[I]], 5
; TUNIT-NEXT: ret i1 [[R]]
;
; CGSCC: Function Attrs: nofree norecurse nosync nounwind memory(none)
; CGSCC-LABEL: define {{[^@]+}}@loop_1
; CGSCC-SAME: (i32 [[N:%.*]]) #[[ATTR4:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: br label [[HEADER:%.*]]
; CGSCC: header:
; CGSCC-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[AND:%.*]], [[HEADER]] ]
; CGSCC-NEXT: [[INC:%.*]] = add i32 [[I]], 1
; CGSCC-NEXT: [[AND]] = and i32 [[INC]], 9999
; CGSCC-NEXT: [[CMP:%.*]] = icmp ne i32 [[N]], [[AND]]
; CGSCC-NEXT: br i1 [[CMP]], label [[HEADER]], label [[EXIT:%.*]]
; CGSCC: exit:
; CGSCC-NEXT: [[R:%.*]] = icmp sle i32 [[I]], 5
; CGSCC-NEXT: ret i1 [[R]]
;
entry:
br label %header
header:
%i = phi i32 [0, %entry], [%and, %header]
%inc = add i32 %i, 1
%and = and i32 %inc, 9999
%cmp = icmp ne i32 %N, %and
br i1 %cmp, label %header, label %exit
exit:
%r = icmp sle i32 %i, 5
ret i1 %r
}
declare void @ham(i32)
declare void @barney(i32 signext, i32 signext)
!0 = !{i32 0, i32 10}
!1 = !{i32 10, i32 100}
;.
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind memory(none) }
; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn memory(read) }
; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn memory(none) }
;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR4]] = { nofree norecurse nosync nounwind memory(none) }
; CGSCC: attributes #[[ATTR5]] = { nofree willreturn memory(read) }
; CGSCC: attributes #[[ATTR6]] = { nofree willreturn }
; CGSCC: attributes #[[ATTR7]] = { nofree nosync willreturn }
;.
; TUNIT: [[RNG0]] = !{i32 0, i32 10}
; TUNIT: [[RNG1]] = !{i32 10, i32 100}
; TUNIT: [[RNG2]] = !{i32 200, i32 1091}
; TUNIT: [[RNG3]] = !{i32 1, i32 -2147483648}
;.
; CGSCC: [[RNG0]] = !{i32 0, i32 10}
; CGSCC: [[RNG1]] = !{i32 10, i32 100}
;.