1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[Attributor] Reuse the IPConstantProp tests for the Attributor

The Attributor can, to some degree, do what IPConstantProp does. We can
consequently use the corner cases already collected and tested for in
the IPConstantProp tests to improve Attributor test coverage.

This exposed various bugs fixed in previous Attributor patches.

Not all functionality of IPConstantProp is available in AAValueSimplify
and AAIsDead so some tests show that we cannot perform the expected
constant propagation.

Reviewers: fhahn, efriedma, mssimpso, davide

Subscribers: bollu, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D69748
This commit is contained in:
Johannes Doerfert 2019-11-01 23:37:04 -05:00
parent 3a938e8b27
commit de726cb6f1
24 changed files with 1442 additions and 0 deletions

View File

@ -0,0 +1,25 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt < %s -passes=attributor -S | FileCheck %s
; Should not propagate the result of a weak function.
; PR2411
define weak i32 @foo() nounwind {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 1
;
entry:
ret i32 1
}
define i32 @main() nounwind {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[R:%.*]] = call i32 @foo()
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%r = call i32 @foo( ) nounwind
ret i32 %r
}

View File

@ -0,0 +1,102 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; Don't constant-propagate byval pointers, since they are not pointers!
; PR5038
%struct.MYstr = type { i8, i32 }
@mystr = internal global %struct.MYstr zeroinitializer ; <%struct.MYstr*> [#uses=3]
define internal void @vfu1(%struct.MYstr* byval align 4 %u) nounwind {
; CHECK-LABEL: define {{[^@]+}}@vfu1
; CHECK-SAME: (%struct.MYstr* nocapture nofree nonnull writeonly byval align 8 dereferenceable(8) [[U:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* [[U]], i32 0, i32 1
; CHECK-NEXT: store i32 99, i32* [[TMP0]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 0
; CHECK-NEXT: store i8 97, i8* [[TMP1]], align 8
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: return:
; CHECK-NEXT: ret void
;
entry:
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
store i32 99, i32* %0, align 4
%1 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 0 ; <i8*> [#uses=1]
store i8 97, i8* %1, align 4
br label %return
return: ; preds = %entry
ret void
}
define internal i32 @vfu2(%struct.MYstr* byval align 4 %u) nounwind readonly {
; CHECK-LABEL: define {{[^@]+}}@vfu2
; CHECK-SAME: (%struct.MYstr* nocapture nofree nonnull readonly byval align 8 dereferenceable(8) [[U:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]]
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; CHECK-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; CHECK-NEXT: ret i32 [[TMP5]]
;
entry:
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
%1 = load i32, i32* %0
%2 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 0 ; <i8*> [#uses=1]
%3 = load i8, i8* %2
%4 = zext i8 %3 to i32
%5 = add i32 %4, %1
ret i32 %5
}
define i32 @unions() nounwind {
; CHECK-LABEL: define {{[^@]+}}@unions()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @vfu1(%struct.MYstr* nofree nonnull byval align 8 dereferenceable(8) @mystr)
; CHECK-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* nofree nonnull byval align 8 dereferenceable(8) @mystr)
; CHECK-NEXT: ret i32 [[RESULT]]
;
entry:
call void @vfu1(%struct.MYstr* byval align 4 @mystr) nounwind
%result = call i32 @vfu2(%struct.MYstr* byval align 4 @mystr) nounwind
ret i32 %result
}
define internal i32 @vfu2_v2(%struct.MYstr* byval align 4 %u) nounwind readonly {
; CHECK-LABEL: define {{[^@]+}}@vfu2_v2
; CHECK-SAME: (%struct.MYstr* nocapture nofree nonnull byval align 8 dereferenceable(8) [[U:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* %u, i32 0, i32 1
; CHECK-NEXT: store i32 99, i32* [[Z]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* %u, i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]]
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* %u, i32 0, i32 0
; CHECK-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; CHECK-NEXT: ret i32 [[TMP5]]
;
entry:
%z = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1
store i32 99, i32* %z, align 4
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
%1 = load i32, i32* %0
%2 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 0 ; <i8*> [#uses=1]
%3 = load i8, i8* %2
%4 = zext i8 %3 to i32
%5 = add i32 %4, %1
ret i32 %5
}
define i32 @unions_v2() nounwind {
; CHECK-LABEL: define {{[^@]+}}@unions_v2()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @vfu1(%struct.MYstr* nofree nonnull byval align 8 dereferenceable(8) @mystr)
; CHECK-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* nofree nonnull byval align 8 dereferenceable(8) @mystr)
; CHECK-NEXT: ret i32 [[RESULT]]
;
entry:
call void @vfu1(%struct.MYstr* byval align 4 @mystr) nounwind
%result = call i32 @vfu2_v2(%struct.MYstr* byval align 4 @mystr) nounwind
ret i32 %result
}

View File

@ -0,0 +1,34 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define i64 @fn2() {
; CHECK-LABEL: define {{[^@]+}}@fn2()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CONV:%.*]] = sext i32 undef to i64
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]])
; CHECK-NEXT: ret i64 [[CALL2]]
;
entry:
%conv = sext i32 undef to i64
%div = sdiv i64 8, %conv
%call2 = call i64 @fn1(i64 %div)
ret i64 %call2
}
define internal i64 @fn1(i64 %p1) {
; CHECK-LABEL: define {{[^@]+}}@fn1
; CHECK-SAME: (i64 returned [[P1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i64 [[P1]], 0
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[P1]], i64 [[P1]]
; CHECK-NEXT: ret i64 [[COND]]
;
entry:
%tobool = icmp ne i64 %p1, 0
%cond = select i1 %tobool, i64 %p1, i64 %p1
ret i64 %cond
}

View File

@ -0,0 +1,90 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @fn2(i32* %P) {
; CHECK-LABEL: define {{[^@]+}}@fn2
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: for.cond1:
; CHECK-NEXT: br i1 undef, label [[IF_END]], label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ], [ null, [[FOR_COND1]] ]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
; CHECK-NEXT: br label [[FOR_COND1]]
;
entry:
br label %if.end
for.cond1: ; preds = %if.end, %for.end
br i1 undef, label %if.end, label %if.end
if.end: ; preds = %lbl, %for.cond1
%e.2 = phi i32* [ undef, %entry ], [ null, %for.cond1 ], [ null, %for.cond1 ]
%0 = load i32, i32* %e.2, align 4
%call = call i32 @fn1(i32 %0)
store i32 %call, i32* %P
br label %for.cond1
}
define internal i32 @fn1(i32 %p1) {
; CHECK-LABEL: define {{[^@]+}}@fn1
; CHECK-SAME: (i32 returned [[P1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%tobool = icmp ne i32 %p1, 0
%cond = select i1 %tobool, i32 %p1, i32 %p1
ret i32 %cond
}
define void @fn_no_null_opt(i32* %P) #0 {
; CHECK-LABEL: define {{[^@]+}}@fn_no_null_opt
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: for.cond1:
; CHECK-NEXT: br i1 undef, label [[IF_END]], label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ], [ null, [[FOR_COND1]] ]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
; CHECK-NEXT: br label [[FOR_COND1]]
;
entry:
br label %if.end
for.cond1: ; preds = %if.end, %for.end
br i1 undef, label %if.end, label %if.end
if.end: ; preds = %lbl, %for.cond1
%e.2 = phi i32* [ undef, %entry ], [ null, %for.cond1 ], [ null, %for.cond1 ]
%0 = load i32, i32* %e.2, align 4
%call = call i32 @fn0(i32 %0)
store i32 %call, i32* %P
br label %for.cond1
}
define internal i32 @fn0(i32 %p1) {
; CHECK-LABEL: define {{[^@]+}}@fn0
; CHECK-SAME: (i32 returned [[P1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%tobool = icmp ne i32 %p1, 0
%cond = select i1 %tobool, i32 %p1, i32 %p1
ret i32 %cond
}
attributes #0 = { "null-pointer-is-valid"="true" }

View File

@ -0,0 +1,30 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
%struct.wobble = type { i32 }
%struct.zot = type { %struct.wobble, %struct.wobble, %struct.wobble }
declare dso_local fastcc float @bar(%struct.wobble* noalias, <8 x i32>) unnamed_addr
define %struct.zot @widget(<8 x i32> %arg) local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@widget
; CHECK-SAME: (<8 x i32> [[ARG:%.*]]) local_unnamed_addr
; CHECK-NEXT: bb:
; CHECK-NEXT: ret [[STRUCT_ZOT:%.*]] undef
;
bb:
ret %struct.zot undef
}
define void @baz(<8 x i32> %arg) local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@baz
; CHECK-SAME: (<8 x i32> [[ARG:%.*]]) local_unnamed_addr
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP1:%.*]] = extractvalue [[STRUCT_ZOT:%.*]] undef, 0, 0
; CHECK-NEXT: ret void
;
bb:
%tmp = call %struct.zot @widget(<8 x i32> %arg)
%tmp1 = extractvalue %struct.zot %tmp, 0, 0
ret void
}

View File

@ -0,0 +1,85 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; The original C source looked like this:
;
; long long a101, b101, e101;
; volatile long c101;
; int d101;
;
; static inline int bar(p1, p2)
; {
; return 0;
; }
;
; void foo(unsigned p1)
; {
; long long *f = &b101, *g = &e101;
; c101 = 0;
; (void)((*f |= a101) - (*g = bar(d101)));
; c101 = (*f |= a101 &= p1) == d101;
; }
;
; When compiled with Clang it gives a warning
; warning: too few arguments in call to 'bar'
;
; This ll reproducer has been reduced to only include tha call.
;
; Note that -lint will report this as UB, but it passes -verify.
; This test is just to verify that we do not crash/assert due to mismatch in
; argument count between the caller and callee.
define dso_local void @foo(i16 %a) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i16 [[A:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16)*)(i16 [[A]])
; CHECK-NEXT: ret void
;
%call = call i16 bitcast (i16 (i16, i16) * @bar to i16 (i16) *)(i16 %a)
ret void
}
define internal i16 @bar(i16 %p1, i16 %p2) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]])
; CHECK-NEXT: ret i16 0
;
ret i16 0
}
;-------------------------------------------------------------------------------
; Additional tests to verify that we still optimize when having a mismatch
; in argument count due to varargs (as long as all non-variadic arguments have
; been provided),
define dso_local i16 @vararg_tests(i16 %a) {
; CHECK-LABEL: define {{[^@]+}}@vararg_tests
; CHECK-SAME: (i16 [[A:%.*]])
; CHECK-NEXT: [[CALL1:%.*]] = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 [[A]])
; CHECK-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
; CHECK-NEXT: [[ADD:%.*]] = add i16 [[CALL1]], [[CALL2]]
; CHECK-NEXT: ret i16 [[ADD]]
;
%call1 = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 %a)
%call2 = call i16 bitcast (i16 (i16, i16, ...) * @vararg_no_prop to i16 (i16) *) (i16 7)
%add = add i16 %call1, %call2
ret i16 %add
}
define internal i16 @vararg_prop(i16 %p1, ...) {
; CHECK-LABEL: define {{[^@]+}}@vararg_prop
; CHECK-SAME: (i16 returned [[P1:%.*]], ...)
; CHECK-NEXT: ret i16 7
;
ret i16 %p1
}
define internal i16 @vararg_no_prop(i16 %p1, i16 %p2, ...) {
; CHECK-LABEL: define {{[^@]+}}@vararg_no_prop
; CHECK-SAME: (i16 returned [[P1:%.*]], i16 [[P2:%.*]], ...)
; CHECK-NEXT: ret i16 [[P1]]
;
ret i16 %p1
}

View File

@ -0,0 +1,25 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; This test is just to verify that we do not crash/assert due to mismatch in
; argument type between the caller and callee.
define dso_local void @foo(i16 %a) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i16 [[A:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16, i32)*)(i16 [[A]], i32 7)
; CHECK-NEXT: ret void
;
%call = call i16 bitcast (i16 (i16, i16) * @bar to i16 (i16, i32) *)(i16 %a, i32 7)
ret void
}
define internal i16 @bar(i16 %p1, i16 %p2) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i16 [[P1:%.*]], i16 returned [[P2:%.*]])
; CHECK-NEXT: ret i16 [[P2]]
;
ret i16 %p2
}

View File

@ -0,0 +1,34 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; See PR26774
define i32 @baz() {
; CHECK-LABEL: define {{[^@]+}}@baz()
; CHECK-NEXT: ret i32 10
;
ret i32 10
}
; We can const-prop @baz's return value *into* @foo, but cannot
; constprop @foo's return value into bar.
define linkonce_odr i32 @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: [[VAL:%.*]] = call i32 @baz()
; CHECK-NEXT: ret i32 10
;
%val = call i32 @baz()
ret i32 %val
}
define i32 @bar() {
; CHECK-LABEL: define {{[^@]+}}@bar()
; CHECK-NEXT: [[VAL:%.*]] = call i32 @foo()
; CHECK-NEXT: ret i32 [[VAL]]
;
%val = call i32 @foo()
ret i32 %val
}

View File

@ -0,0 +1,43 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='internalize,attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; PR5569
; IPSCCP should prove that the blocks are dead and delete them, and
; properly handle the dangling blockaddress constants.
; CHECK: @bar.l = internal constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]
@code = global [5 x i32] [i32 0, i32 0, i32 0, i32 0, i32 1], align 4 ; <[5 x i32]*> [#uses=0]
@bar.l = internal constant [2 x i8*] [i8* blockaddress(@bar, %lab0), i8* blockaddress(@bar, %end)] ; <[2 x i8*]*> [#uses=1]
define void @foo(i32 %x) nounwind readnone {
entry:
%b = alloca i32, align 4 ; <i32*> [#uses=1]
store volatile i32 -1, i32* %b
ret void
}
define void @bar(i32* nocapture %pc) nounwind readonly {
entry:
br label %indirectgoto
lab0: ; preds = %indirectgoto
%indvar.next = add i32 %indvar, 1 ; <i32> [#uses=1]
br label %indirectgoto
end: ; preds = %indirectgoto
ret void
indirectgoto: ; preds = %lab0, %entry
%indvar = phi i32 [ %indvar.next, %lab0 ], [ 0, %entry ] ; <i32> [#uses=2]
%pc.addr.0 = getelementptr i32, i32* %pc, i32 %indvar ; <i32*> [#uses=1]
%tmp1.pn = load i32, i32* %pc.addr.0 ; <i32> [#uses=1]
%indirect.goto.dest.in = getelementptr inbounds [2 x i8*], [2 x i8*]* @bar.l, i32 0, i32 %tmp1.pn ; <i8**> [#uses=1]
%indirect.goto.dest = load i8*, i8** %indirect.goto.dest.in ; <i8*> [#uses=1]
indirectbr i8* %indirect.goto.dest, [label %lab0, label %end]
}
define i32 @main() nounwind readnone {
entry:
ret i32 0
}

View File

@ -0,0 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 -disable-output < %s
define internal void @foo(i32 %X) {
call void @foo( i32 %X )
ret void
}

View File

@ -0,0 +1,78 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
target datalayout = "E-m:e-i64:64-n32:64"
target triple = "powerpc64-bgq-linux"
define void @test(i32 signext %n) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32 signext [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: unreachable
; CHECK: if.end:
; CHECK-NEXT: unreachable
; CHECK: if.then2:
; CHECK-NEXT: unreachable
; CHECK: if.end4:
; CHECK-NEXT: unreachable
; CHECK: if.then9:
; CHECK-NEXT: unreachable
; CHECK: if.then12:
; CHECK-NEXT: unreachable
; CHECK: if.else14:
; CHECK-NEXT: unreachable
; CHECK: do.body:
; CHECK-NEXT: unreachable
; CHECK: if.then33:
; CHECK-NEXT: unreachable
; CHECK: cond.false.i28:
; CHECK-NEXT: unreachable
; CHECK: _ZN5boost4math4signIgEEiRKT_.exit30:
; CHECK-NEXT: unreachable
;
entry:
br i1 undef, label %if.then, label %if.end
if.then: ; preds = %entry
ret void
if.end: ; preds = %entry
br i1 undef, label %if.then2, label %if.end4
if.then2: ; preds = %if.end
unreachable
if.end4: ; preds = %if.end
%sub.n = select i1 undef, i32 undef, i32 %n
switch i32 %sub.n, label %if.else14 [
i32 0, label %if.then9
i32 1, label %if.then12
]
if.then9: ; preds = %if.end4
unreachable
if.then12: ; preds = %if.end4
unreachable
if.else14: ; preds = %if.end4
br label %do.body
do.body: ; preds = %do.body, %if.else14
%scale.0 = phi ppc_fp128 [ 0xM3FF00000000000000000000000000000, %if.else14 ], [ %scale.0, %do.body ]
br i1 undef, label %do.body, label %if.then33
if.then33: ; preds = %do.body
br i1 undef, label %_ZN5boost4math4signIgEEiRKT_.exit30, label %cond.false.i28
cond.false.i28: ; preds = %if.then33
%0 = bitcast ppc_fp128 %scale.0 to i128
%tobool.i26 = icmp slt i128 %0, 0
br label %_ZN5boost4math4signIgEEiRKT_.exit30
_ZN5boost4math4signIgEEiRKT_.exit30: ; preds = %cond.false.i28, %if.then33
unreachable
}

View File

@ -0,0 +1,40 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
@_ZL6test1g = internal global i32 42, align 4
define void @_Z7test1f1v() nounwind {
; CHECK-LABEL: define {{[^@]+}}@_Z7test1f1v()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* @_ZL6test1g, align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: store i32 0, i32* @_ZL6test1g, align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%tmp = load i32, i32* @_ZL6test1g, align 4
%cmp = icmp eq i32 %tmp, 0
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
store i32 0, i32* @_ZL6test1g, align 4
br label %if.end
if.end: ; preds = %if.then, %entry
ret void
}
define i32 @_Z7test1f2v() nounwind {
; CHECK-LABEL: define {{[^@]+}}@_Z7test1f2v()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* @_ZL6test1g, align 4
; CHECK-NEXT: ret i32 [[TMP]]
;
entry:
%tmp = load i32, i32* @_ZL6test1g, align 4
ret i32 %tmp
}

View File

@ -0,0 +1,117 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
;
;
; /---------------------------------------|
; | /----------------------|----|
; | | /-----| |
; V V V | |
; void broker(int (*cb0)(int), int (*cb1)(int), int (*cb2)(int), int, int);
;
; static int cb0(int zero) {
; return zero;
; }
; static int cb1(int unknown) {
; return unknown;
; }
; static int cb2(int unknown) {
; cb0(0);
; return unknown;
; }
; static int cb3(int unknown) {
; return unknown;
; }
; static int cb4(int unknown) {
; return unknown;
; }
;
; void foo() {
; cb0(0);
; cb3(1);
; broker(cb0, cb1, cb0, 0, 1);
; broker(cb1, cb2, cb2, 0, 1);
; broker(cb3, cb2, cb3, 0, 1);
; broker(cb4, cb4, cb4, 0, 1);
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define internal i32 @cb0(i32 %zero) {
; CHECK-LABEL: define {{[^@]+}}@cb0
; CHECK-SAME: (i32 returned [[ZERO:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 0
;
entry:
ret i32 %zero
}
define internal i32 @cb1(i32 %unknown) {
; CHECK-LABEL: define {{[^@]+}}@cb1
; CHECK-SAME: (i32 returned [[UNKNOWN:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[UNKNOWN]]
;
entry:
ret i32 %unknown
}
define internal i32 @cb2(i32 %unknown) {
; CHECK-LABEL: define {{[^@]+}}@cb2
; CHECK-SAME: (i32 returned [[UNKNOWN:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @cb0(i32 0)
; CHECK-NEXT: ret i32 [[UNKNOWN]]
;
entry:
%call = call i32 @cb0(i32 0)
ret i32 %unknown
}
define internal i32 @cb3(i32 %unknown) {
; CHECK-LABEL: define {{[^@]+}}@cb3
; CHECK-SAME: (i32 returned [[UNKNOWN:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[UNKNOWN]]
;
entry:
ret i32 %unknown
}
define internal i32 @cb4(i32 %unknown) {
; CHECK-LABEL: define {{[^@]+}}@cb4
; CHECK-SAME: (i32 returned [[UNKNOWN:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[UNKNOWN]]
;
entry:
ret i32 %unknown
}
define void @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @cb0(i32 0)
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @cb3(i32 1)
; CHECK-NEXT: call void @broker(i32 (i32)* nonnull @cb0, i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb0, i32 0, i32 1)
; CHECK-NEXT: call void @broker(i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb2, i32 0, i32 1)
; CHECK-NEXT: call void @broker(i32 (i32)* nonnull @cb3, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb3, i32 0, i32 1)
; CHECK-NEXT: call void @broker(i32 (i32)* nonnull @cb4, i32 (i32)* nonnull @cb4, i32 (i32)* nonnull @cb4, i32 0, i32 1)
; CHECK-NEXT: ret void
;
entry:
%call = call i32 @cb0(i32 0)
%call1 = call i32 @cb3(i32 1)
call void @broker(i32 (i32)* nonnull @cb0, i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb0, i32 0, i32 1)
call void @broker(i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb2, i32 0, i32 1)
call void @broker(i32 (i32)* nonnull @cb3, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb3, i32 0, i32 1)
call void @broker(i32 (i32)* nonnull @cb4, i32 (i32)* nonnull @cb4, i32 (i32)* nonnull @cb4, i32 0, i32 1)
ret void
}
declare !callback !3 void @broker(i32 (i32)*, i32 (i32)*, i32 (i32)*, i32, i32)
!0 = !{i64 0, i64 3, i1 false}
!1 = !{i64 1, i64 4, i1 false}
!2 = !{i64 2, i64 3, i1 false}
!3 = !{!0, !2, !1}

View File

@ -0,0 +1,79 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
; PR36485
; musttail call result can't be replaced with a constant, unless the call can be removed
declare i32 @external()
define i8* @start(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@start
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
; CHECK-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 [[V]])
; CHECK-NEXT: ret i8* [[CA]]
; CHECK: false:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
; CHECK-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
; CHECK: c2_true:
; CHECK-NEXT: [[CA1:%.*]] = musttail call i8* @no_side_effects(i8 undef)
; CHECK-NEXT: ret i8* [[CA1]]
; CHECK: c2_false:
; CHECK-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 undef)
; CHECK-NEXT: ret i8* [[CA2]]
;
%c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false
true:
; FIXME: propagate the value information for %v
%ca = musttail call i8* @side_effects(i8 %v)
ret i8* %ca
false:
%c2 = icmp eq i8 %v, 1
br i1 %c2, label %c2_true, label %c2_false
c2_true:
%ca1 = musttail call i8* @no_side_effects(i8 %v)
; FIXME: zap this call
ret i8* %ca1
c2_false:
%ca2 = musttail call i8* @dont_zap_me(i8 %v)
ret i8* %ca2
}
define internal i8* @side_effects(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@side_effects
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @start(i8 [[V]])
; CHECK-NEXT: ret i8* [[CA]]
;
%i1 = call i32 @external()
; since this goes back to `start` the SCPP should be see that the return value
; is always `null`.
; The call can't be removed due to `external` call above, though.
%ca = musttail call i8* @start(i8 %v)
; Thus the result must be returned anyway
ret i8* %ca
}
define internal i8* @no_side_effects(i8 %v) readonly nounwind {
; CHECK-LABEL: define {{[^@]+}}@no_side_effects
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: ret i8* null
;
ret i8* null
}
define internal i8* @dont_zap_me(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@dont_zap_me
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: ret i8* null
;
%i1 = call i32 @external()
ret i8* null
}

View File

@ -0,0 +1,47 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.0.24215"
define i32 @dipsy(i32, i32) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@dipsy
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: BasicBlock0:
; CHECK-NEXT: call void asm "\0D\0Apushl %ebp\0D\0Amovl 8(%esp),%eax\0D\0Amovl 12(%esp), %ebp\0D\0Acalll *%eax\0D\0Apopl %ebp\0D\0Aretl\0D\0A", ""()
; CHECK-NEXT: ret i32 0
;
BasicBlock0:
call void asm "\0D\0Apushl %ebp\0D\0Amovl 8(%esp),%eax\0D\0Amovl 12(%esp), %ebp\0D\0Acalll *%eax\0D\0Apopl %ebp\0D\0Aretl\0D\0A", ""()
ret i32 0
}
define void @tinkywinky(i32, i32, i32) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@tinkywinky
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) local_unnamed_addr
; CHECK-NEXT: BasicBlock1:
; CHECK-NEXT: call void asm "\0D\0A movl 12(%esp), %ebp\0D\0A movl 4(%esp), %eax\0D\0A movl 8(%esp), %esp\0D\0A jmpl *%eax\0D\0A", ""()
; CHECK-NEXT: ret void
;
BasicBlock1:
call void asm "\0D\0A movl 12(%esp), %ebp\0D\0A movl 4(%esp), %eax\0D\0A movl 8(%esp), %esp\0D\0A jmpl *%eax\0D\0A", ""()
ret void
}
define void @patatino(i32, i32, i32) local_unnamed_addr #1 {
; CHECK-LABEL: define {{[^@]+}}@patatino
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) local_unnamed_addr
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @dipsy(i32 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: tail call void @tinkywinky(i32 [[TMP3]], i32 [[TMP2]], i32 [[TMP1]])
; CHECK-NEXT: ret void
;
bb:
%3 = tail call i32 @dipsy(i32 %0, i32 %1) #0
; Check that we don't accidentally propagate zero.
tail call void @tinkywinky(i32 %3, i32 %2, i32 %1) #0
ret void
}
attributes #0 = { naked }
attributes #1 = { "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" }

View File

@ -0,0 +1,132 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
;
; void bar(int, float, double);
;
; void foo(int N) {
; float p = 3;
; double q = 5;
; N = 7;
;
; #pragma omp parallel for firstprivate(q)
; for (int i = 2; i < N; i++) {
; bar(i, p, q);
; }
; }
;
; Verify the constant value of q is propagated into the outlined function.
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
%struct.ident_t = type { i32, i32, i32, i32, i8* }
@.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1
@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 514, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8
@1 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8
define dso_local void @foo(i32 %N) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[P:%.*]] = alloca float, align 4
; CHECK-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; CHECK-NEXT: store float 3.000000e+00, float* [[P]], align 4
; CHECK-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @1, i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* nonnull align 4 dereferenceable(4) [[N_ADDR]], float* nonnull align 4 dereferenceable(4) [[P]], i64 4617315517961601024)
; CHECK-NEXT: ret void
;
entry:
%N.addr = alloca i32, align 4
%p = alloca float, align 4
store i32 %N, i32* %N.addr, align 4
store float 3.000000e+00, float* %p, align 4
store i32 7, i32* %N.addr, align 4
call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @1, i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* nonnull %N.addr, float* nonnull %p, i64 4617315517961601024)
ret void
}
define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %N, float* dereferenceable(4) %p, i64 %q) {
entry:
%q.addr = alloca i64, align 8
%.omp.lb = alloca i32, align 4
%.omp.ub = alloca i32, align 4
%.omp.stride = alloca i32, align 4
%.omp.is_last = alloca i32, align 4
; CHECK: store i64 4617315517961601024, i64* %q.addr, align 8
store i64 %q, i64* %q.addr, align 8
%conv = bitcast i64* %q.addr to double*
%tmp = load i32, i32* %N, align 4
%sub3 = add nsw i32 %tmp, -3
%cmp = icmp sgt i32 %tmp, 2
br i1 %cmp, label %omp.precond.then, label %omp.precond.end
omp.precond.then: ; preds = %entry
store i32 0, i32* %.omp.lb, align 4
store i32 %sub3, i32* %.omp.ub, align 4
store i32 1, i32* %.omp.stride, align 4
store i32 0, i32* %.omp.is_last, align 4
%tmp5 = load i32, i32* %.global_tid., align 4
call void @__kmpc_for_static_init_4(%struct.ident_t* nonnull @0, i32 %tmp5, i32 34, i32* nonnull %.omp.is_last, i32* nonnull %.omp.lb, i32* nonnull %.omp.ub, i32* nonnull %.omp.stride, i32 1, i32 1)
%tmp6 = load i32, i32* %.omp.ub, align 4
%cmp6 = icmp sgt i32 %tmp6, %sub3
br i1 %cmp6, label %cond.true, label %cond.false
cond.true: ; preds = %omp.precond.then
br label %cond.end
cond.false: ; preds = %omp.precond.then
%tmp7 = load i32, i32* %.omp.ub, align 4
br label %cond.end
cond.end: ; preds = %cond.false, %cond.true
%cond = phi i32 [ %sub3, %cond.true ], [ %tmp7, %cond.false ]
store i32 %cond, i32* %.omp.ub, align 4
%tmp8 = load i32, i32* %.omp.lb, align 4
br label %omp.inner.for.cond
omp.inner.for.cond: ; preds = %omp.inner.for.inc, %cond.end
%.omp.iv.0 = phi i32 [ %tmp8, %cond.end ], [ %add11, %omp.inner.for.inc ]
%tmp9 = load i32, i32* %.omp.ub, align 4
%cmp8 = icmp sgt i32 %.omp.iv.0, %tmp9
br i1 %cmp8, label %omp.inner.for.cond.cleanup, label %omp.inner.for.body
omp.inner.for.cond.cleanup: ; preds = %omp.inner.for.cond
br label %omp.inner.for.end
omp.inner.for.body: ; preds = %omp.inner.for.cond
%add10 = add nsw i32 %.omp.iv.0, 2
%tmp10 = load float, float* %p, align 4
%tmp11 = load double, double* %conv, align 8
call void @bar(i32 %add10, float %tmp10, double %tmp11)
br label %omp.body.continue
omp.body.continue: ; preds = %omp.inner.for.body
br label %omp.inner.for.inc
omp.inner.for.inc: ; preds = %omp.body.continue
%add11 = add nsw i32 %.omp.iv.0, 1
br label %omp.inner.for.cond
omp.inner.for.end: ; preds = %omp.inner.for.cond.cleanup
br label %omp.loop.exit
omp.loop.exit: ; preds = %omp.inner.for.end
%tmp12 = load i32, i32* %.global_tid., align 4
call void @__kmpc_for_static_fini(%struct.ident_t* nonnull @0, i32 %tmp12)
br label %omp.precond.end
omp.precond.end: ; preds = %omp.loop.exit, %entry
ret void
}
declare dso_local void @__kmpc_for_static_init_4(%struct.ident_t*, i32, i32, i32*, i32*, i32*, i32*, i32, i32)
declare dso_local void @bar(i32, float, double)
declare dso_local void @__kmpc_for_static_fini(%struct.ident_t*, i32)
declare !callback !0 dso_local void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
!1 = !{i64 2, i64 -1, i64 -1, i1 true}
!0 = !{!1}

View File

@ -0,0 +1,65 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
;
; #include <pthread.h>
;
; void *GlobalVPtr;
;
; static void *foo(void *arg) { return arg; }
; static void *bar(void *arg) { return arg; }
;
; int main() {
; pthread_t thread;
; pthread_create(&thread, NULL, foo, NULL);
; pthread_create(&thread, NULL, bar, &GlobalVPtr);
; return 0;
; }
;
; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
; bar, respectively.
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
%union.pthread_attr_t = type { i64, [48 x i8] }
@GlobalVPtr = common dso_local global i8* null, align 8
define dso_local i32 @main() {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull [[THREAD]], %union.pthread_attr_t* null, i8* (i8*)* nonnull @foo, i8* noalias null)
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull [[THREAD]], %union.pthread_attr_t* null, i8* (i8*)* nonnull @bar, i8* nonnull align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT: ret i32 0
;
entry:
%thread = alloca i64, align 8
%call = call i32 @pthread_create(i64* nonnull %thread, %union.pthread_attr_t* null, i8* (i8*)* nonnull @foo, i8* null)
%call1 = call i32 @pthread_create(i64* nonnull %thread, %union.pthread_attr_t* null, i8* (i8*)* nonnull @bar, i8* bitcast (i8** @GlobalVPtr to i8*))
ret i32 0
}
declare !callback !0 dso_local i32 @pthread_create(i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*)
define internal i8* @foo(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i8* noalias nofree readnone returned [[ARG:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* null
;
entry:
ret i8* %arg
}
define internal i8* @bar(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
;
entry:
ret i8* %arg
}
!1 = !{i64 2, i64 3, i1 false}
!0 = !{!1}

View File

@ -0,0 +1,21 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; CHECK-NOT: %X
define internal i32 @foo(i32 %X) {
%Y = call i32 @foo( i32 %X ) ; <i32> [#uses=1]
%Z = add i32 %Y, 1 ; <i32> [#uses=1]
ret i32 %Z
}
define void @bar() {
; CHECK-LABEL: define {{[^@]+}}@bar()
; CHECK-NEXT: unreachable
; CHECK: .split:
; CHECK-NEXT: unreachable
;
call i32 @foo( i32 17 ) ; <i32>:1 [#uses=0]
ret void
}

View File

@ -0,0 +1,45 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; PR5596
; IPSCCP should propagate the 0 argument, eliminate the switch, and propagate
; the result.
; FIXME: Remove obsolete calls/instructions
define i32 @main() noreturn nounwind {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL2:%.*]] = tail call i32 @wwrite(i64 0)
; CHECK-NEXT: ret i32 123
;
entry:
%call2 = tail call i32 @wwrite(i64 0) nounwind
ret i32 %call2
}
define internal i32 @wwrite(i64 %i) nounwind readnone {
; CHECK-LABEL: define {{[^@]+}}@wwrite
; CHECK-SAME: (i64 [[I:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [
; CHECK-NEXT: i64 3, label [[RETURN:%.*]]
; CHECK-NEXT: i64 10, label [[RETURN]]
; CHECK-NEXT: ]
; CHECK: sw.default:
; CHECK-NEXT: ret i32 123
; CHECK: return:
; CHECK-NEXT: unreachable
;
entry:
switch i64 %i, label %sw.default [
i64 3, label %return
i64 10, label %return
]
sw.default:
ret i32 123
return:
ret i32 0
}

View File

@ -0,0 +1,96 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=9 < %s | FileCheck %s
;; This function returns its second argument on all return statements
define internal i32* @incdec(i1 %C, i32* %V) {
; CHECK-LABEL: define {{[^@]+}}@incdec
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nofree nonnull returned align 4 dereferenceable(4) [[V:%.*]])
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: [[X1:%.*]] = add i32 [[X]], 1
; CHECK-NEXT: store i32 [[X1]], i32* [[V]], align 4
; CHECK-NEXT: ret i32* [[V]]
; CHECK: F:
; CHECK-NEXT: [[X2:%.*]] = sub i32 [[X]], 1
; CHECK-NEXT: store i32 [[X2]], i32* [[V]], align 4
; CHECK-NEXT: ret i32* [[V]]
;
%X = load i32, i32* %V
br i1 %C, label %T, label %F
T: ; preds = %0
%X1 = add i32 %X, 1
store i32 %X1, i32* %V
ret i32* %V
F: ; preds = %0
%X2 = sub i32 %X, 1
store i32 %X2, i32* %V
ret i32* %V
}
;; This function returns its first argument as a part of a multiple return
;; value
define internal { i32, i32 } @foo(i32 %A, i32 %B) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]])
; CHECK-NEXT: [[X:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT: [[Y:%.*]] = insertvalue { i32, i32 } undef, i32 [[A]], 0
; CHECK-NEXT: [[Z:%.*]] = insertvalue { i32, i32 } [[Y]], i32 [[X]], 1
; CHECK-NEXT: ret { i32, i32 } [[Z]]
;
%X = add i32 %A, %B
%Y = insertvalue { i32, i32 } undef, i32 %A, 0
%Z = insertvalue { i32, i32 } %Y, i32 %X, 1
ret { i32, i32 } %Z
}
define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i1 [[C:%.*]]) #2 personality i32 (...)* @__gxx_personality_v0
; CHECK-NEXT: [[Q:%.*]] = alloca i32
; CHECK-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) [[Q]])
; CHECK-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2)
; CHECK-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
; CHECK-NEXT: [[S2:%.*]] = invoke { i32, i32 } @foo(i32 3, i32 4)
; CHECK-NEXT: to label [[OK:%.*]] unwind label [[LPAD:%.*]]
; CHECK: OK:
; CHECK-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
; CHECK-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]]
; CHECK-NEXT: store i32 [[Z]], i32* [[W]], align 4
; CHECK-NEXT: br label [[RET:%.*]]
; CHECK: LPAD:
; CHECK-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[RET]]
; CHECK: RET:
; CHECK-NEXT: ret void
;
%Q = alloca i32
;; Call incdec to see if %W is properly replaced by %Q
%W = call i32* @incdec(i1 %C, i32* %Q ) ; <i32> [#uses=1]
;; Call @foo twice, to prevent the arguments from propagating into the
;; function (so we can check the returned argument is properly
;; propagated per-caller).
%S1 = call { i32, i32 } @foo(i32 1, i32 2)
%X1 = extractvalue { i32, i32 } %S1, 0
%S2 = invoke { i32, i32 } @foo(i32 3, i32 4) to label %OK unwind label %LPAD
OK:
%X2 = extractvalue { i32, i32 } %S2, 0
;; Do some stuff with the returned values which we can grep for
%Z = add i32 %X1, %X2
store i32 %Z, i32* %W
br label %RET
LPAD:
%exn = landingpad {i8*, i32}
cleanup
br label %RET
RET:
ret void
}
declare i32 @__gxx_personality_v0(...)

View File

@ -0,0 +1,59 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; FIXME: icmp folding is missing
define internal i32 @foo(i1 %C) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: ret i32 52
; CHECK: F:
; CHECK-NEXT: ret i32 52
;
br i1 %C, label %T, label %F
T: ; preds = %0
ret i32 52
F: ; preds = %0
ret i32 52
}
define i1 @caller(i1 %C) {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: [[X:%.*]] = call i32 @foo(i1 [[C]])
; CHECK-NEXT: [[Y:%.*]] = icmp ne i32 52, 0
; CHECK-NEXT: ret i1 [[Y]]
;
%X = call i32 @foo( i1 %C ) ; <i32> [#uses=1]
%Y = icmp ne i32 %X, 0 ; <i1> [#uses=1]
ret i1 %Y
}
define i1 @invokecaller(i1 %C) personality i32 (...)* @__gxx_personality_v0 {
; CHECK-LABEL: define {{[^@]+}}@invokecaller
; CHECK-SAME: (i1 [[C:%.*]]) #0 personality i32 (...)* @__gxx_personality_v0
; CHECK-NEXT: [[X:%.*]] = call i32 @foo(i1 [[C]])
; CHECK-NEXT: br label [[OK:%.*]]
; CHECK: .i2c:
; CHECK-NEXT: unreachable
; CHECK: OK:
; CHECK-NEXT: [[Y:%.*]] = icmp ne i32 52, 0
; CHECK-NEXT: ret i1 [[Y]]
; CHECK: FAIL:
; CHECK-NEXT: unreachable
;
%X = invoke i32 @foo( i1 %C ) to label %OK unwind label %FAIL ; <i32> [#uses=1]
OK:
%Y = icmp ne i32 %X, 0 ; <i1> [#uses=1]
ret i1 %Y
FAIL:
%exn = landingpad {i8*, i32}
cleanup
ret i1 false
}
declare i32 @__gxx_personality_v0(...)

View File

@ -0,0 +1,69 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s
;; FIXME: support for extractvalue and insertvalue missing.
%0 = type { i32, i32 }
define internal %0 @foo(i1 %Q) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i1 [[Q:%.*]])
; CHECK-NEXT: br i1 [[Q]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: [[MRV:%.*]] = insertvalue [[TMP0:%.*]] undef, i32 21, 0
; CHECK-NEXT: [[MRV1:%.*]] = insertvalue [[TMP0]] %mrv, i32 22, 1
; CHECK-NEXT: ret [[TMP0]] %mrv1
; CHECK: F:
; CHECK-NEXT: [[MRV2:%.*]] = insertvalue [[TMP0]] undef, i32 21, 0
; CHECK-NEXT: [[MRV3:%.*]] = insertvalue [[TMP0]] %mrv2, i32 23, 1
; CHECK-NEXT: ret [[TMP0]] %mrv3
;
br i1 %Q, label %T, label %F
T: ; preds = %0
%mrv = insertvalue %0 undef, i32 21, 0
%mrv1 = insertvalue %0 %mrv, i32 22, 1
ret %0 %mrv1
F: ; preds = %0
%mrv2 = insertvalue %0 undef, i32 21, 0
%mrv3 = insertvalue %0 %mrv2, i32 23, 1
ret %0 %mrv3
}
define internal %0 @bar(i1 %Q) {
%A = insertvalue %0 undef, i32 21, 0
br i1 %Q, label %T, label %F
T: ; preds = %0
%B = insertvalue %0 %A, i32 22, 1
ret %0 %B
F: ; preds = %0
%C = insertvalue %0 %A, i32 23, 1
ret %0 %C
}
define %0 @caller(i1 %Q) {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i1 [[Q:%.*]])
; CHECK-NEXT: [[X:%.*]] = call [[TMP0:%.*]] @foo(i1 [[Q]])
; CHECK-NEXT: [[A:%.*]] = extractvalue [[TMP0]] %X, 0
; CHECK-NEXT: [[B:%.*]] = extractvalue [[TMP0]] %X, 1
; CHECK-NEXT: [[C:%.*]] = extractvalue [[TMP0]] undef, 0
; CHECK-NEXT: [[D:%.*]] = extractvalue [[TMP0]] undef, 1
; CHECK-NEXT: [[M:%.*]] = add i32 [[A]], [[C]]
; CHECK-NEXT: [[N:%.*]] = add i32 [[B]], [[D]]
; CHECK-NEXT: ret [[TMP0]] %X
;
%X = call %0 @foo(i1 %Q)
%A = extractvalue %0 %X, 0
%B = extractvalue %0 %X, 1
%Y = call %0 @bar(i1 %Q)
%C = extractvalue %0 %Y, 0
%D = extractvalue %0 %Y, 1
%M = add i32 %A, %C
;; Check that the second return values didn't get propagated
%N = add i32 %B, %D
ret %0 %X
}

View File

@ -0,0 +1,66 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
define internal i32 @testf(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@testf
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C]], label [[IF_COND:%.*]], label [[IF_END:%.*]]
; CHECK: if.cond:
; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[IF_END]]
; CHECK: if.then:
; CHECK-NEXT: unreachable
; CHECK: if.end:
; CHECK-NEXT: ret i32 10
;
entry:
br i1 %c, label %if.cond, label %if.end
if.cond:
br i1 undef, label %if.then, label %if.end
if.then: ; preds = %entry, %if.then
ret i32 11
if.end: ; preds = %if.then1, %entry
ret i32 10
}
define internal i32 @test1(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test1
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @testf(i1 [[C]])
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 10, 10
; CHECK-NEXT: br i1 [[RES]], label [[RET1:%.*]], label [[RET2:%.*]]
; CHECK: ret1:
; CHECK-NEXT: ret i32 99
; CHECK: ret2:
; CHECK-NEXT: ret i32 0
;
entry:
br label %if.then
if.then: ; preds = %entry, %if.then
%call = call i32 @testf(i1 %c)
%res = icmp eq i32 %call, 10
br i1 %res, label %ret1, label %ret2
ret1: ; preds = %if.then, %entry
ret i32 99
ret2: ; preds = %if.then, %entry
ret i32 0
}
define i32 @main(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@main
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: [[RES:%.*]] = call i32 @test1(i1 [[C]])
; CHECK-NEXT: ret i32 [[RES]]
;
%res = call i32 @test1(i1 %c)
ret i32 %res
}

View File

@ -0,0 +1,53 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
;
; #include <threads.h>
; thread_local int gtl = 0;
; int gsh = 0;
;
; static int callee(int *thread_local_ptr, int *shared_ptr) {
; return *thread_local_ptr + *shared_ptr;
; }
;
; void broker(int *, int (*callee)(int *, int *), int *);
;
; void caller() {
; broker(&gtl, callee, &gsh);
; }
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@gtl = dso_local thread_local global i32 0, align 4
@gsh = dso_local global i32 0, align 4
define internal i32 @callee(i32* %thread_local_ptr, i32* %shared_ptr) {
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[THREAD_LOCAL_PTR:%.*]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[SHARED_PTR:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[THREAD_LOCAL_PTR]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @gsh, align 4
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP]], [[TMP1]]
; CHECK-NEXT: ret i32 [[ADD]]
;
entry:
%tmp = load i32, i32* %thread_local_ptr, align 4
%tmp1 = load i32, i32* %shared_ptr, align 4
%add = add nsw i32 %tmp, %tmp1
ret i32 %add
}
define dso_local void @caller() {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @broker(i32* nonnull align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nonnull align 4 dereferenceable(4) @gsh)
; CHECK-NEXT: ret void
;
entry:
call void @broker(i32* nonnull @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nonnull @gsh)
ret void
}
declare !callback !0 dso_local void @broker(i32*, i32 (i32*, i32*)*, i32*)
!1 = !{i64 1, i64 0, i64 2, i1 false}
!0 = !{!1}