-; RUN: opt -inline -S < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
+; RUN: opt -inline -S < %s | FileCheck --check-prefixes=CHECK,NO_ASSUME %s
+; RUN: opt -inline -S --enable-knowledge-retention < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
; The callee guarantees that the pointer argument is nonnull and dereferenceable.
; That information should transfer to the caller.
define i32 @callee(i32* dereferenceable(32) %t1) {
-; CHECK-LABEL: @callee(i32* dereferenceable(32) %t1)
-; CHECK-NEXT: [[T2:%.*]] = load i32, i32* %t1
+; CHECK-LABEL: define {{[^@]+}}@callee
+; CHECK-SAME: (i32* dereferenceable(32) [[T1:%.*]])
+; CHECK-NEXT: [[T2:%.*]] = load i32, i32* [[T1]]
; CHECK-NEXT: ret i32 [[T2]]
;
%t2 = load i32, i32* %t1
; The caller argument could be known nonnull and dereferenceable(32).
define i32 @caller1(i32* %t1) {
-; CHECK-LABEL: @caller1(i32* %t1)
-; CHECK-NEXT: [[T2_I:%.*]] = load i32, i32* %t1
-; CHECK-NEXT: ret i32 [[T2_I]]
+; NO_ASSUME-LABEL: define {{[^@]+}}@caller1
+; NO_ASSUME-SAME: (i32* [[T1:%.*]])
+; NO_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; NO_ASSUME-NEXT: ret i32 [[T2_I]]
+;
+; USE_ASSUME-LABEL: define {{[^@]+}}@caller1
+; USE_ASSUME-SAME: (i32* [[T1:%.*]])
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[T1]], i64 32) ]
+; USE_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; USE_ASSUME-NEXT: ret i32 [[T2_I]]
;
%t2 = tail call i32 @callee(i32* dereferenceable(32) %t1)
ret i32 %t2
; The dereferenceable amount could be increased.
define i32 @caller2(i32* dereferenceable(31) %t1) {
-; CHECK-LABEL: @caller2(i32* dereferenceable(31) %t1)
-; CHECK-NEXT: [[T2_I:%.*]] = load i32, i32* %t1
-; CHECK-NEXT: ret i32 [[T2_I]]
+; NO_ASSUME-LABEL: define {{[^@]+}}@caller2
+; NO_ASSUME-SAME: (i32* dereferenceable(31) [[T1:%.*]])
+; NO_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; NO_ASSUME-NEXT: ret i32 [[T2_I]]
+;
+; USE_ASSUME-LABEL: define {{[^@]+}}@caller2
+; USE_ASSUME-SAME: (i32* dereferenceable(31) [[T1:%.*]])
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[T1]], i64 32) ]
+; USE_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; USE_ASSUME-NEXT: ret i32 [[T2_I]]
;
%t2 = tail call i32 @callee(i32* dereferenceable(32) %t1)
ret i32 %t2
; Make sure that we don't propagate a smaller dereferenceable amount.
define i32 @caller3(i32* dereferenceable(33) %t1) {
-; CHECK-LABEL: @caller3(i32* dereferenceable(33) %t1)
-; CHECK-NEXT: [[T2_I:%.*]] = load i32, i32* %t1
-; CHECK-NEXT: ret i32 [[T2_I]]
+; NO_ASSUME-LABEL: define {{[^@]+}}@caller3
+; NO_ASSUME-SAME: (i32* dereferenceable(33) [[T1:%.*]])
+; NO_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; NO_ASSUME-NEXT: ret i32 [[T2_I]]
+;
+; USE_ASSUME-LABEL: define {{[^@]+}}@caller3
+; USE_ASSUME-SAME: (i32* dereferenceable(33) [[T1:%.*]])
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[T1]], i64 32) ]
+; USE_ASSUME-NEXT: [[T2_I:%.*]] = load i32, i32* [[T1]]
+; USE_ASSUME-NEXT: ret i32 [[T2_I]]
;
%t2 = tail call i32 @callee(i32* dereferenceable(32) %t1)
ret i32 %t2
-; RUN: opt -inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
+; RUN: opt -inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
+; RUN: opt -inline -enable-noalias-to-md-conversion --enable-knowledge-retention -S < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @hello(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+; CHECK-LABEL: define {{[^@]+}}@hello
+; CHECK-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
+; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX]], align 4
+; CHECK-NEXT: ret void
+;
+; ASSUME-LABEL: @hello(
+; ASSUME-NEXT: entry:
+; ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C:%.*]], align 4
+; ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 5
+; ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX]], align 4
+; ASSUME-NEXT: ret void
entry:
%0 = load float, float* %c, align 4
%arrayidx = getelementptr inbounds float, float* %a, i64 5
}
define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+; NO_ASSUME-LABEL: define {{[^@]+}}@foo
+; NO_ASSUME-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
+; NO_ASSUME-NEXT: entry:
+; NO_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
+; NO_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
+; NO_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
+; NO_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
+; NO_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; NO_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
+; NO_ASSUME-NEXT: ret void
+;
+; USE_ASSUME-LABEL: define {{[^@]+}}@foo
+; USE_ASSUME-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
+; USE_ASSUME-NEXT: entry:
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
+; USE_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
+; USE_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
+; USE_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
+; USE_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
+; USE_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; USE_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
+; USE_ASSUME-NEXT: ret void
+;
entry:
tail call void @hello(float* %a, float* %c)
%0 = load float, float* %c, align 4
ret void
}
-; CHECK: define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
-; CHECK: entry:
-; CHECK: %0 = load float, float* %c, align 4, !alias.scope !0, !noalias !3
-; CHECK: %arrayidx.i = getelementptr inbounds float, float* %a, i64 5
-; CHECK: store float %0, float* %arrayidx.i, align 4, !alias.scope !3, !noalias !0
-; CHECK: %1 = load float, float* %c, align 4
-; CHECK: %arrayidx = getelementptr inbounds float, float* %a, i64 7
-; CHECK: store float %1, float* %arrayidx, align 4
-; CHECK: ret void
-; CHECK: }
-
define void @hello2(float* noalias nocapture %a, float* noalias nocapture %b, float* nocapture readonly %c) #0 {
+; CHECK-LABEL: define {{[^@]+}}@hello2
+; CHECK-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
+; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX]], align 4
+; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
+; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX1]], align 4
+; CHECK-NEXT: ret void
+;
entry:
%0 = load float, float* %c, align 4
%arrayidx = getelementptr inbounds float, float* %a, i64 6
; Check that when hello() is inlined into foo(), and then foo() is inlined into
; foo2(), the noalias scopes are properly concatenated.
define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+; NO_ASSUME-LABEL: define {{[^@]+}}@foo2
+; NO_ASSUME-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
+; NO_ASSUME-NEXT: entry:
+; NO_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !5, !noalias !10
+; NO_ASSUME-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
+; NO_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !10, !noalias !5
+; NO_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !13, !noalias !14
+; NO_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; NO_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !14, !noalias !13
+; NO_ASSUME-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !15
+; NO_ASSUME-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
+; NO_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !19, !noalias !20
+; NO_ASSUME-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
+; NO_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !20, !noalias !19
+; NO_ASSUME-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4
+; NO_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; NO_ASSUME-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4
+; NO_ASSUME-NEXT: ret void
+;
+; USE_ASSUME-LABEL: define {{[^@]+}}@foo2
+; USE_ASSUME-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
+; USE_ASSUME-NEXT: entry:
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) #2 [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ], !noalias !5
+; USE_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !9, !noalias !12
+; USE_ASSUME-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
+; USE_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !12, !noalias !9
+; USE_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !14, !noalias !15
+; USE_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; USE_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !15, !noalias !14
+; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[B]]), "nocapture"(float* [[A]]), "nocapture"(float* [[B]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
+; USE_ASSUME-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !16
+; USE_ASSUME-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
+; USE_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !20, !noalias !21
+; USE_ASSUME-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
+; USE_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !21, !noalias !20
+; USE_ASSUME-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4
+; USE_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
+; USE_ASSUME-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4
+; USE_ASSUME-NEXT: ret void
+;
entry:
tail call void @foo(float* %a, float* %c)
tail call void @hello2(float* %a, float* %b, float* %c)
ret void
}
-; CHECK: define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
-; CHECK: entry:
-; CHECK: %0 = load float, float* %c, align 4, !alias.scope !5, !noalias !10
-; CHECK: %arrayidx.i.i = getelementptr inbounds float, float* %a, i64 5
-; CHECK: store float %0, float* %arrayidx.i.i, align 4, !alias.scope !10, !noalias !5
-; CHECK: %1 = load float, float* %c, align 4, !alias.scope !13, !noalias !14
-; CHECK: %arrayidx.i = getelementptr inbounds float, float* %a, i64 7
-; CHECK: store float %1, float* %arrayidx.i, align 4, !alias.scope !14, !noalias !13
-; CHECK: %2 = load float, float* %c, align 4, !noalias !15
-; CHECK: %arrayidx.i1 = getelementptr inbounds float, float* %a, i64 6
-; CHECK: store float %2, float* %arrayidx.i1, align 4, !alias.scope !19, !noalias !20
-; CHECK: %arrayidx1.i = getelementptr inbounds float, float* %b, i64 8
-; CHECK: store float %2, float* %arrayidx1.i, align 4, !alias.scope !20, !noalias !19
-; CHECK: %3 = load float, float* %c, align 4
-; CHECK: %arrayidx = getelementptr inbounds float, float* %a, i64 7
-; CHECK: store float %3, float* %arrayidx, align 4
-; CHECK: ret void
-; CHECK: }
-
-; CHECK: !0 = !{!1}
-; CHECK: !1 = distinct !{!1, !2, !"hello: %c"}
-; CHECK: !2 = distinct !{!2, !"hello"}
-; CHECK: !3 = !{!4}
-; CHECK: !4 = distinct !{!4, !2, !"hello: %a"}
-; CHECK: !5 = !{!6, !8}
-; CHECK: !6 = distinct !{!6, !7, !"hello: %c"}
-; CHECK: !7 = distinct !{!7, !"hello"}
-; CHECK: !8 = distinct !{!8, !9, !"foo: %c"}
-; CHECK: !9 = distinct !{!9, !"foo"}
-; CHECK: !10 = !{!11, !12}
-; CHECK: !11 = distinct !{!11, !7, !"hello: %a"}
-; CHECK: !12 = distinct !{!12, !9, !"foo: %a"}
-; CHECK: !13 = !{!8}
-; CHECK: !14 = !{!12}
-; CHECK: !15 = !{!16, !18}
-; CHECK: !16 = distinct !{!16, !17, !"hello2: %a"}
-; CHECK: !17 = distinct !{!17, !"hello2"}
-; CHECK: !18 = distinct !{!18, !17, !"hello2: %b"}
-; CHECK: !19 = !{!16}
-; CHECK: !20 = !{!18}
+; NO_ASSUME: !0 = !{!1}
+; NO_ASSUME: !1 = distinct !{!1, !2, !"hello: %c"}
+; NO_ASSUME: !2 = distinct !{!2, !"hello"}
+; NO_ASSUME: !3 = !{!4}
+; NO_ASSUME: !4 = distinct !{!4, !2, !"hello: %a"}
+; NO_ASSUME: !5 = !{!6, !8}
+; NO_ASSUME: !6 = distinct !{!6, !7, !"hello: %c"}
+; NO_ASSUME: !7 = distinct !{!7, !"hello"}
+; NO_ASSUME: !8 = distinct !{!8, !9, !"foo: %c"}
+; NO_ASSUME: !9 = distinct !{!9, !"foo"}
+; NO_ASSUME: !10 = !{!11, !12}
+; NO_ASSUME: !11 = distinct !{!11, !7, !"hello: %a"}
+; NO_ASSUME: !12 = distinct !{!12, !9, !"foo: %a"}
+; NO_ASSUME: !13 = !{!8}
+; NO_ASSUME: !14 = !{!12}
+; NO_ASSUME: !15 = !{!16, !18}
+; NO_ASSUME: !16 = distinct !{!16, !17, !"hello2: %a"}
+; NO_ASSUME: !17 = distinct !{!17, !"hello2"}
+; NO_ASSUME: !18 = distinct !{!18, !17, !"hello2: %b"}
+; NO_ASSUME: !19 = !{!16}
+; NO_ASSUME: !20 = !{!18}
attributes #0 = { nounwind uwtable }