[llvm] 9655203 - [Attributor] Copy or port test cases related to Attributor to` Attributor` test folder
Hideto Ueno via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 2 07:37:33 PST 2019
Author: Hideto Ueno
Date: 2019-12-02T15:36:29Z
New Revision: 96552036e307f7b0dd6477583c3fdb7de17e8aac
URL: https://github.com/llvm/llvm-project/commit/96552036e307f7b0dd6477583c3fdb7de17e8aac
DIFF: https://github.com/llvm/llvm-project/commit/96552036e307f7b0dd6477583c3fdb7de17e8aac.diff
LOG: [Attributor] Copy or port test cases related to Attributor to` Attributor` test folder
Summary:
This patch moves the test cases related to Attributor to `Transforms/Attributor` folder.
We have used `Transforms/FunctionAttrs` as the primary folder for Attributor test but we need to change testing way now.
For the test cases which I think functionattrs doesn't infer anything something like (willreturn, nosync, value-simplify, h2s ..etc), I moved them with the command `git mv`.
For the test cases in which functoinattrs and attributor are tested, I copied the test to the folder and remove the check only used by functoinattrs.
Reviewers: jdoerfert, sstefan1
Reviewed By: jdoerfert
Subscribers: jfb, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70843
Added:
llvm/test/Transforms/Attributor/align.ll
llvm/test/Transforms/Attributor/callbacks.ll
llvm/test/Transforms/Attributor/dereferenceable-1.ll
llvm/test/Transforms/Attributor/dereferenceable-2.ll
llvm/test/Transforms/Attributor/heap_to_stack.ll
llvm/test/Transforms/Attributor/internal-noalias.ll
llvm/test/Transforms/Attributor/liveness.ll
llvm/test/Transforms/Attributor/misc.ll
llvm/test/Transforms/Attributor/new_attributes.ll
llvm/test/Transforms/Attributor/noalias.ll
llvm/test/Transforms/Attributor/nocapture-1.ll
llvm/test/Transforms/Attributor/nocapture-2.ll
llvm/test/Transforms/Attributor/nofree.ll
llvm/test/Transforms/Attributor/nonnull.ll
llvm/test/Transforms/Attributor/norecurse.ll
llvm/test/Transforms/Attributor/noreturn.ll
llvm/test/Transforms/Attributor/noreturn_async.ll
llvm/test/Transforms/Attributor/noreturn_sync.ll
llvm/test/Transforms/Attributor/nosync.ll
llvm/test/Transforms/Attributor/nounwind.ll
llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
llvm/test/Transforms/Attributor/readattrs.ll
llvm/test/Transforms/Attributor/returned.ll
llvm/test/Transforms/Attributor/value-simplify.ll
llvm/test/Transforms/Attributor/willreturn.ll
Modified:
llvm/test/Transforms/FunctionAttrs/arg_returned.ll
llvm/test/Transforms/FunctionAttrs/nocapture.ll
llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
llvm/test/Transforms/FunctionAttrs/nonnull.ll
llvm/test/Transforms/FunctionAttrs/norecurse.ll
llvm/test/Transforms/FunctionAttrs/nounwind.ll
llvm/test/Transforms/FunctionAttrs/readattrs.ll
llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll
Removed:
llvm/test/Transforms/FunctionAttrs/align.ll
llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
llvm/test/Transforms/FunctionAttrs/callbacks.ll
llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll
llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll
llvm/test/Transforms/FunctionAttrs/internal-noalias.ll
llvm/test/Transforms/FunctionAttrs/liveness.ll
llvm/test/Transforms/FunctionAttrs/misc.ll
llvm/test/Transforms/FunctionAttrs/new_attributes.ll
llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
llvm/test/Transforms/FunctionAttrs/noreturn_async.ll
llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll
llvm/test/Transforms/FunctionAttrs/nosync.ll
llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
llvm/test/Transforms/FunctionAttrs/value-simplify.ll
llvm/test/Transforms/FunctionAttrs/willreturn.ll
################################################################################
diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/Attributor/align.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/align.ll
rename to llvm/test/Transforms/Attributor/align.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/callbacks.ll b/llvm/test/Transforms/Attributor/callbacks.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/callbacks.ll
rename to llvm/test/Transforms/Attributor/callbacks.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
rename to llvm/test/Transforms/Attributor/dereferenceable-1.ll
diff --git a/llvm/test/Transforms/Attributor/dereferenceable-2.ll b/llvm/test/Transforms/Attributor/dereferenceable-2.ll
new file mode 100644
index 000000000000..b3c0440f930f
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/dereferenceable-2.ll
@@ -0,0 +1,356 @@
+; RUN: opt < %s -attributor --attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR
+; Copied from Transforms/InferFunctionAttrs/dereferenceable.ll
+
+; Determine dereference-ability before unused loads get deleted:
+; https://bugs.llvm.org/show_bug.cgi?id=21780
+
+define <4 x double> @PR21780(double* %ptr) {
+; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
+
+ ; GEP of index 0 is simplified away.
+ %arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1
+ %arrayidx2 = getelementptr inbounds double, double* %ptr, i64 2
+ %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
+
+ %t0 = load double, double* %ptr, align 8
+ %t1 = load double, double* %arrayidx1, align 8
+ %t2 = load double, double* %arrayidx2, align 8
+ %t3 = load double, double* %arrayidx3, align 8
+
+ %vecinit0 = insertelement <4 x double> undef, double %t0, i32 0
+ %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1
+ %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2
+ %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3
+ %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
+ ret <4 x double> %shuffle
+}
+
+
+define double @PR21780_only_access3_with_inbounds(double* %ptr) {
+; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
+
+ %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
+ %t3 = load double, double* %arrayidx3, align 8
+ ret double %t3
+}
+
+define double @PR21780_only_access3_without_inbounds(double* %ptr) {
+; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture nofree readonly align 8 %ptr)
+ %arrayidx3 = getelementptr double, double* %ptr, i64 3
+ %t3 = load double, double* %arrayidx3, align 8
+ ret double %t3
+}
+
+define double @PR21780_without_inbounds(double* %ptr) {
+; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
+
+ %arrayidx1 = getelementptr double, double* %ptr, i64 1
+ %arrayidx2 = getelementptr double, double* %ptr, i64 2
+ %arrayidx3 = getelementptr double, double* %ptr, i64 3
+
+ %t0 = load double, double* %ptr, align 8
+ %t1 = load double, double* %arrayidx1, align 8
+ %t2 = load double, double* %arrayidx2, align 8
+ %t3 = load double, double* %arrayidx3, align 8
+
+ ret double %t3
+}
+
+; Unsimplified, but still valid. Also, throw in some bogus arguments.
+
+define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
+; ATTRIBUTOR-LABEL: @gep0(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull writeonly dereferenceable(1) %other, i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr)
+ %arrayidx0 = getelementptr i8, i8* %ptr, i64 0
+ %arrayidx1 = getelementptr i8, i8* %ptr, i64 1
+ %arrayidx2 = getelementptr i8, i8* %ptr, i64 2
+ %t0 = load i8, i8* %arrayidx0
+ %t1 = load i8, i8* %arrayidx1
+ %t2 = load i8, i8* %arrayidx2
+ store i8 %t2, i8* %other
+ ret void
+}
+
+; Order of accesses does not change computation.
+; Multiple arguments may be dereferenceable.
+
+define void @ordering(i8* %ptr1, i32* %ptr2) {
+; ATTRIBUTOR-LABEL: @ordering(i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr1, i32* nocapture nofree nonnull readonly dereferenceable(8) %ptr2)
+ %a20 = getelementptr i32, i32* %ptr2, i64 0
+ %a12 = getelementptr i8, i8* %ptr1, i64 2
+ %t12 = load i8, i8* %a12
+ %a11 = getelementptr i8, i8* %ptr1, i64 1
+ %t20 = load i32, i32* %a20
+ %a10 = getelementptr i8, i8* %ptr1, i64 0
+ %t10 = load i8, i8* %a10
+ %t11 = load i8, i8* %a11
+ %a21 = getelementptr i32, i32* %ptr2, i64 1
+ %t21 = load i32, i32* %a21
+ ret void
+}
+
+; Not in entry block.
+
+define void @not_entry_but_guaranteed_to_execute(i8* %ptr) {
+; ATTRIBUTOR-LABEL: @not_entry_but_guaranteed_to_execute(i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr)
+entry:
+ br label %exit
+exit:
+ %arrayidx0 = getelementptr i8, i8* %ptr, i64 0
+ %arrayidx1 = getelementptr i8, i8* %ptr, i64 1
+ %arrayidx2 = getelementptr i8, i8* %ptr, i64 2
+ %t0 = load i8, i8* %arrayidx0
+ %t1 = load i8, i8* %arrayidx1
+ %t2 = load i8, i8* %arrayidx2
+ ret void
+}
+
+; Not in entry block and not guaranteed to execute.
+
+define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) {
+; ATTRIBUTOR-LABEL: @not_entry_not_guaranteed_to_execute(i8* nocapture nofree readonly %ptr, i1 %cond)
+entry:
+ br i1 %cond, label %loads, label %exit
+loads:
+ %arrayidx0 = getelementptr i8, i8* %ptr, i64 0
+ %arrayidx1 = getelementptr i8, i8* %ptr, i64 1
+ %arrayidx2 = getelementptr i8, i8* %ptr, i64 2
+ %t0 = load i8, i8* %arrayidx0
+ %t1 = load i8, i8* %arrayidx1
+ %t2 = load i8, i8* %arrayidx2
+ ret void
+exit:
+ ret void
+}
+
+; The last load may not execute, so derefenceable bytes only covers the 1st two loads.
+
+define void @partial_in_entry(i16* %ptr, i1 %cond) {
+; ATTRIBUTOR-LABEL: @partial_in_entry(i16* nocapture nofree nonnull readonly dereferenceable(4) %ptr, i1 %cond)
+entry:
+ %arrayidx0 = getelementptr i16, i16* %ptr, i64 0
+ %arrayidx1 = getelementptr i16, i16* %ptr, i64 1
+ %arrayidx2 = getelementptr i16, i16* %ptr, i64 2
+ %t0 = load i16, i16* %arrayidx0
+ %t1 = load i16, i16* %arrayidx1
+ br i1 %cond, label %loads, label %exit
+loads:
+ %t2 = load i16, i16* %arrayidx2
+ ret void
+exit:
+ ret void
+}
+
+; The volatile load can't be used to prove a non-volatile access is allowed.
+; The 2nd and 3rd loads may never execute.
+
+define void @volatile_is_not_dereferenceable(i16* %ptr) {
+; ATTRIBUTOR-LABEL: @volatile_is_not_dereferenceable(i16* nofree %ptr)
+ %arrayidx0 = getelementptr i16, i16* %ptr, i64 0
+ %arrayidx1 = getelementptr i16, i16* %ptr, i64 1
+ %arrayidx2 = getelementptr i16, i16* %ptr, i64 2
+ %t0 = load volatile i16, i16* %arrayidx0
+ %t1 = load i16, i16* %arrayidx1
+ %t2 = load i16, i16* %arrayidx2
+ ret void
+}
+
+; TODO: We should allow inference for atomic (but not volatile) ops.
+
+define void @atomic_is_alright(i16* %ptr) {
+; ATTRIBUTOR-LABEL: @atomic_is_alright(i16* nocapture nofree nonnull readonly align 2 dereferenceable(6) %ptr)
+ %arrayidx0 = getelementptr i16, i16* %ptr, i64 0
+ %arrayidx1 = getelementptr i16, i16* %ptr, i64 1
+ %arrayidx2 = getelementptr i16, i16* %ptr, i64 2
+ %t0 = load atomic i16, i16* %arrayidx0 unordered, align 2
+ %t1 = load i16, i16* %arrayidx1
+ %t2 = load i16, i16* %arrayidx2
+ ret void
+}
+
+declare void @may_not_return()
+
+define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
+; ATTRIBUTOR-LABEL: @not_guaranteed_to_transfer_execution(i16* nocapture nonnull readonly dereferenceable(2) %ptr)
+ %arrayidx0 = getelementptr i16, i16* %ptr, i64 0
+ %arrayidx1 = getelementptr i16, i16* %ptr, i64 1
+ %arrayidx2 = getelementptr i16, i16* %ptr, i64 2
+ %t0 = load i16, i16* %arrayidx0
+ call void @may_not_return()
+ %t1 = load i16, i16* %arrayidx1
+ %t2 = load i16, i16* %arrayidx2
+ ret void
+}
+
+; We must have consecutive accesses.
+
+define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
+; ATTRIBUTOR-LABEL: @variable_gep_index(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull readonly dereferenceable(1) %ptr, i64 %variable_index)
+ %arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index
+ %arrayidx2 = getelementptr i8, i8* %ptr, i64 2
+ %t0 = load i8, i8* %ptr
+ %t1 = load i8, i8* %arrayidx1
+ %t2 = load i8, i8* %arrayidx2
+ ret void
+}
+
+; Deal with >1 GEP index.
+
+define void @multi_index_gep(<4 x i8>* %ptr) {
+; FIXME: %ptr should be dereferenceable(4)
+; ATTRIBUTOR-LABEL: @multi_index_gep(<4 x i8>* nocapture nofree nonnull readonly dereferenceable(1) %ptr)
+ %arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0
+ %t0 = load i8, i8* %arrayidx00
+ ret void
+}
+
+; Could round weird bitwidths down?
+
+define void @not_byte_multiple(i9* %ptr) {
+; ATTRIBUTOR-LABEL: @not_byte_multiple(i9* nocapture nofree nonnull readonly dereferenceable(2) %ptr)
+ %arrayidx0 = getelementptr i9, i9* %ptr, i64 0
+ %t0 = load i9, i9* %arrayidx0
+ ret void
+}
+
+; Missing direct access from the pointer.
+
+define void @no_pointer_deref(i16* %ptr) {
+; ATTRIBUTOR-LABEL: @no_pointer_deref(i16* nocapture nofree readonly %ptr)
+ %arrayidx1 = getelementptr i16, i16* %ptr, i64 1
+ %arrayidx2 = getelementptr i16, i16* %ptr, i64 2
+ %t1 = load i16, i16* %arrayidx1
+ %t2 = load i16, i16* %arrayidx2
+ ret void
+}
+
+; Out-of-order is ok, but missing access concludes dereferenceable range.
+
+define void @non_consecutive(i32* %ptr) {
+; ATTRIBUTOR-LABEL: @non_consecutive(i32* nocapture nofree nonnull readonly dereferenceable(8) %ptr)
+ %arrayidx1 = getelementptr i32, i32* %ptr, i64 1
+ %arrayidx0 = getelementptr i32, i32* %ptr, i64 0
+ %arrayidx3 = getelementptr i32, i32* %ptr, i64 3
+ %t1 = load i32, i32* %arrayidx1
+ %t0 = load i32, i32* %arrayidx0
+ %t3 = load i32, i32* %arrayidx3
+ ret void
+}
+
+; Improve on existing dereferenceable attribute.
+
+define void @more_bytes(i32* dereferenceable(8) %ptr) {
+; ATTRIBUTOR-LABEL: @more_bytes(i32* nocapture nofree nonnull readonly dereferenceable(16) %ptr)
+ %arrayidx3 = getelementptr i32, i32* %ptr, i64 3
+ %arrayidx1 = getelementptr i32, i32* %ptr, i64 1
+ %arrayidx0 = getelementptr i32, i32* %ptr, i64 0
+ %arrayidx2 = getelementptr i32, i32* %ptr, i64 2
+ %t3 = load i32, i32* %arrayidx3
+ %t1 = load i32, i32* %arrayidx1
+ %t2 = load i32, i32* %arrayidx2
+ %t0 = load i32, i32* %arrayidx0
+ ret void
+}
+
+; Improve on existing dereferenceable_or_null attribute.
+
+define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
+; ATTRIBUTOR-LABEL: @more_bytes_and_not_null(i32* nocapture nofree nonnull readonly dereferenceable(16) %ptr)
+ %arrayidx3 = getelementptr i32, i32* %ptr, i64 3
+ %arrayidx1 = getelementptr i32, i32* %ptr, i64 1
+ %arrayidx0 = getelementptr i32, i32* %ptr, i64 0
+ %arrayidx2 = getelementptr i32, i32* %ptr, i64 2
+ %t3 = load i32, i32* %arrayidx3
+ %t1 = load i32, i32* %arrayidx1
+ %t2 = load i32, i32* %arrayidx2
+ %t0 = load i32, i32* %arrayidx0
+ ret void
+}
+
+; But don't pessimize existing dereferenceable attribute.
+
+define void @better_bytes(i32* dereferenceable(100) %ptr) {
+; ATTRIBUTOR-LABEL: @better_bytes(i32* nocapture nofree nonnull readonly dereferenceable(100) %ptr)
+ %arrayidx3 = getelementptr i32, i32* %ptr, i64 3
+ %arrayidx1 = getelementptr i32, i32* %ptr, i64 1
+ %arrayidx0 = getelementptr i32, i32* %ptr, i64 0
+ %arrayidx2 = getelementptr i32, i32* %ptr, i64 2
+ %t3 = load i32, i32* %arrayidx3
+ %t1 = load i32, i32* %arrayidx1
+ %t2 = load i32, i32* %arrayidx2
+ %t0 = load i32, i32* %arrayidx0
+ ret void
+}
+
+define void @bitcast(i32* %arg) {
+; ATTRIBUTOR-LABEL: @bitcast(i32* nocapture nofree nonnull readonly dereferenceable(8) %arg)
+ %ptr = bitcast i32* %arg to float*
+ %arrayidx0 = getelementptr float, float* %ptr, i64 0
+ %arrayidx1 = getelementptr float, float* %ptr, i64 1
+ %t0 = load float, float* %arrayidx0
+ %t1 = load float, float* %arrayidx1
+ ret void
+}
+
+define void @bitcast_
diff erent_sizes(double* %arg1, i8* %arg2) {
+; ATTRIBUTOR-LABEL: @bitcast_
diff erent_sizes(double* nocapture nofree nonnull readonly dereferenceable(12) %arg1, i8* nocapture nofree nonnull readonly dereferenceable(16) %arg2)
+ %ptr1 = bitcast double* %arg1 to float*
+ %a10 = getelementptr float, float* %ptr1, i64 0
+ %a11 = getelementptr float, float* %ptr1, i64 1
+ %a12 = getelementptr float, float* %ptr1, i64 2
+ %ld10 = load float, float* %a10
+ %ld11 = load float, float* %a11
+ %ld12 = load float, float* %a12
+
+ %ptr2 = bitcast i8* %arg2 to i64*
+ %a20 = getelementptr i64, i64* %ptr2, i64 0
+ %a21 = getelementptr i64, i64* %ptr2, i64 1
+ %ld20 = load i64, i64* %a20
+ %ld21 = load i64, i64* %a21
+ ret void
+}
+
+define void @negative_offset(i32* %arg) {
+; ATTRIBUTOR-LABEL: @negative_offset(i32* nocapture nofree nonnull readonly dereferenceable(4) %arg)
+ %ptr = bitcast i32* %arg to float*
+ %arrayidx0 = getelementptr float, float* %ptr, i64 0
+ %arrayidx1 = getelementptr float, float* %ptr, i64 -1
+ %t0 = load float, float* %arrayidx0
+ %t1 = load float, float* %arrayidx1
+ ret void
+}
+
+define void @stores(i32* %arg) {
+; ATTRIBUTOR-LABEL: @stores(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
+ %ptr = bitcast i32* %arg to float*
+ %arrayidx0 = getelementptr float, float* %ptr, i64 0
+ %arrayidx1 = getelementptr float, float* %ptr, i64 1
+ store float 1.0, float* %arrayidx0
+ store float 2.0, float* %arrayidx1
+ ret void
+}
+
+define void @load_store(i32* %arg) {
+; ATTRIBUTOR-LABEL: @load_store(i32* nocapture nofree nonnull dereferenceable(8) %arg)
+ %ptr = bitcast i32* %arg to float*
+ %arrayidx0 = getelementptr float, float* %ptr, i64 0
+ %arrayidx1 = getelementptr float, float* %ptr, i64 1
+ %t1 = load float, float* %arrayidx0
+ store float 2.0, float* %arrayidx1
+ ret void
+}
+
+define void @
diff erent_size1(i32* %arg) {
+; ATTRIBUTOR-LABEL: @
diff erent_size1(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
+ %arg-cast = bitcast i32* %arg to double*
+ store double 0.000000e+00, double* %arg-cast
+ store i32 0, i32* %arg
+ ret void
+}
+
+define void @
diff erent_size2(i32* %arg) {
+; ATTRIBUTOR-LABEL: @
diff erent_size2(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
+ store i32 0, i32* %arg
+ %arg-cast = bitcast i32* %arg to double*
+ store double 0.000000e+00, double* %arg-cast
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll
rename to llvm/test/Transforms/Attributor/heap_to_stack.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/internal-noalias.ll
rename to llvm/test/Transforms/Attributor/internal-noalias.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/liveness.ll
rename to llvm/test/Transforms/Attributor/liveness.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/misc.ll b/llvm/test/Transforms/Attributor/misc.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/misc.ll
rename to llvm/test/Transforms/Attributor/misc.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/new_attributes.ll b/llvm/test/Transforms/Attributor/new_attributes.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/new_attributes.ll
rename to llvm/test/Transforms/Attributor/new_attributes.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/Attributor/noalias.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
rename to llvm/test/Transforms/Attributor/noalias.ll
diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll
new file mode 100644
index 000000000000..abb148d883ed
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nocapture-1.ll
@@ -0,0 +1,346 @@
+; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
+; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
+; Copied from Transforms/FunctoinAttrs/nocapture.ll
+
+ at g = global i32* null ; <i32**> [#uses=1]
+
+; ATTRIBUTOR: define i32* @c1(i32* nofree readnone returned "no-capture-maybe-returned" %q)
+define i32* @c1(i32* %q) {
+ ret i32* %q
+}
+
+; ATTRIBUTOR: define void @c2(i32* nofree writeonly %q)
+; It would also be acceptable to mark %q as readnone. Update @c3 too.
+define void @c2(i32* %q) {
+ store i32* %q, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define void @c3(i32* nofree writeonly %q)
+define void @c3(i32* %q) {
+ call void @c2(i32* %q)
+ ret void
+}
+
+; ATTRIBUTOR: define i1 @c4(i32* nofree readnone %q, i32 %bitno)
+define i1 @c4(i32* %q, i32 %bitno) {
+ %tmp = ptrtoint i32* %q to i32
+ %tmp2 = lshr i32 %tmp, %bitno
+ %bit = trunc i32 %tmp2 to i1
+ br i1 %bit, label %l1, label %l0
+l0:
+ ret i1 0 ; escaping value not caught by def-use chaining.
+l1:
+ ret i1 1 ; escaping value not caught by def-use chaining.
+}
+
+; c4b is c4 but without the escaping part
+; ATTRIBUTOR: define i1 @c4b(i32* nocapture nofree readnone %q, i32 %bitno)
+define i1 @c4b(i32* %q, i32 %bitno) {
+ %tmp = ptrtoint i32* %q to i32
+ %tmp2 = lshr i32 %tmp, %bitno
+ %bit = trunc i32 %tmp2 to i1
+ br i1 %bit, label %l1, label %l0
+l0:
+ ret i1 0 ; not escaping!
+l1:
+ ret i1 0 ; not escaping!
+}
+
+ at lookup_table = global [2 x i1] [ i1 0, i1 1 ]
+
+; ATTRIBUTOR: define i1 @c5(i32* nofree readonly %q, i32 %bitno)
+define i1 @c5(i32* %q, i32 %bitno) {
+ %tmp = ptrtoint i32* %q to i32
+ %tmp2 = lshr i32 %tmp, %bitno
+ %bit = and i32 %tmp2, 1
+ ; subtle escape mechanism follows
+ %lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
+ %val = load i1, i1* %lookup
+ ret i1 %val
+}
+
+declare void @throw_if_bit_set(i8*, i8) readonly
+
+; ATTRIBUTOR: define i1 @c6(i8* readonly %q, i8 %bit)
+define i1 @c6(i8* %q, i8 %bit) personality i32 (...)* @__gxx_personality_v0 {
+ invoke void @throw_if_bit_set(i8* %q, i8 %bit)
+ to label %ret0 unwind label %ret1
+ret0:
+ ret i1 0
+ret1:
+ %exn = landingpad {i8*, i32}
+ cleanup
+ ret i1 1
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
+ %tmp = ptrtoint i32* %q to i32
+ %tmp2 = lshr i32 %tmp, %bitno
+ %bit = and i32 %tmp2, 1
+ %lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
+ ret i1* %lookup
+}
+
+; ATTRIBUTOR: define i1 @c7(i32* nofree readonly %q, i32 %bitno)
+define i1 @c7(i32* %q, i32 %bitno) {
+ %ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
+ %val = load i1, i1* %ptr
+ ret i1 %val
+}
+
+
+; ATTRIBUTOR: define i32 @nc1(i32* nofree %q, i32* nocapture nofree %p, i1 %b)
+define i32 @nc1(i32* %q, i32* %p, i1 %b) {
+e:
+ br label %l
+l:
+ %x = phi i32* [ %p, %e ]
+ %y = phi i32* [ %q, %e ]
+ %tmp = bitcast i32* %x to i32* ; <i32*> [#uses=2]
+ %tmp2 = select i1 %b, i32* %tmp, i32* %y
+ %val = load i32, i32* %tmp2 ; <i32> [#uses=1]
+ store i32 0, i32* %tmp
+ store i32* %y, i32** @g
+ ret i32 %val
+}
+
+; ATTRIBUTOR: define i32 @nc1_addrspace(i32* nofree %q, i32 addrspace(1)* nocapture nofree %p, i1 %b)
+define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) {
+e:
+ br label %l
+l:
+ %x = phi i32 addrspace(1)* [ %p, %e ]
+ %y = phi i32* [ %q, %e ]
+ %tmp = addrspacecast i32 addrspace(1)* %x to i32* ; <i32*> [#uses=2]
+ %tmp2 = select i1 %b, i32* %tmp, i32* %y
+ %val = load i32, i32* %tmp2 ; <i32> [#uses=1]
+ store i32 0, i32* %tmp
+ store i32* %y, i32** @g
+ ret i32 %val
+}
+
+; ATTRIBUTOR: define void @nc2(i32* nocapture nofree %p, i32* nofree %q)
+define void @nc2(i32* %p, i32* %q) {
+ %1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
+ ret void
+}
+
+
+; ATTRIBUTOR: define void @nc3(void ()* nocapture nofree nonnull %p)
+define void @nc3(void ()* %p) {
+ call void %p()
+ ret void
+}
+
+declare void @external(i8*) readonly nounwind
+; ATTRIBUTOR: define void @nc4(i8* nocapture readonly %p)
+define void @nc4(i8* %p) {
+ call void @external(i8* %p)
+ ret void
+}
+
+; ATTRIBUTOR: define void @nc5(void (i8*)* nocapture nofree nonnull %f, i8* nocapture %p)
+define void @nc5(void (i8*)* %f, i8* %p) {
+ call void %f(i8* %p) readonly nounwind
+ call void %f(i8* nocapture %p)
+ ret void
+}
+
+; ATTRIBUTOR: define void @test1_1(i8* nocapture nofree readnone %x1_1, i8* nocapture nofree readnone %y1_1, i1 %c)
+; It would be acceptable to add readnone to %y1_1 and %y1_2.
+define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
+ call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c)
+ store i32* null, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define i8* @test1_2(i8* nocapture nofree readnone %x1_2, i8* nofree readnone returned "no-capture-maybe-returned" %y1_2, i1 %c)
+define i8* @test1_2(i8* %x1_2, i8* %y1_2, i1 %c) {
+ br i1 %c, label %t, label %f
+t:
+ call void @test1_1(i8* %x1_2, i8* %y1_2, i1 %c)
+ store i32* null, i32** @g
+ br label %f
+f:
+ ret i8* %y1_2
+}
+
+; ATTRIBUTOR: define void @test2(i8* nocapture nofree readnone %x2)
+define void @test2(i8* %x2) {
+ call void @test2(i8* %x2)
+ store i32* null, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define void @test3(i8* nocapture nofree readnone %x3, i8* nocapture nofree readnone %y3, i8* nocapture nofree readnone %z3)
+define void @test3(i8* %x3, i8* %y3, i8* %z3) {
+ call void @test3(i8* %z3, i8* %y3, i8* %x3)
+ store i32* null, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define void @test4_1(i8* nocapture nofree readnone %x4_1, i1 %c)
+define void @test4_1(i8* %x4_1, i1 %c) {
+ call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1, i1 %c)
+ store i32* null, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define i8* @test4_2(i8* nocapture nofree readnone %x4_2, i8* nofree readnone returned "no-capture-maybe-returned" %y4_2, i8* nocapture nofree readnone %z4_2, i1 %c)
+define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2, i1 %c) {
+ br i1 %c, label %t, label %f
+t:
+ call void @test4_1(i8* null, i1 %c)
+ store i32* null, i32** @g
+ br label %f
+f:
+ ret i8* %y4_2
+}
+
+declare i8* @test5_1(i8* %x5_1)
+
+; ATTRIBUTOR: define void @test5_2(i8* %x5_2)
+define void @test5_2(i8* %x5_2) {
+ call i8* @test5_1(i8* %x5_2)
+ store i32* null, i32** @g
+ ret void
+}
+
+declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...)
+
+; ATTRIBUTOR: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
+define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) {
+ call void (i8*, i8*, ...) @test6_1(i8* %x6_2, i8* %y6_2, i8* %z6_2)
+ store i32* null, i32** @g
+ ret void
+}
+
+; ATTRIBUTOR: define void @test_cmpxchg(i32* nocapture nofree nonnull dereferenceable(4) %p)
+define void @test_cmpxchg(i32* %p) {
+ cmpxchg i32* %p, i32 0, i32 1 acquire monotonic
+ ret void
+}
+
+; ATTRIBUTOR: define void @test_cmpxchg_ptr(i32** nocapture nofree nonnull dereferenceable(8) %p, i32* nofree %q)
+define void @test_cmpxchg_ptr(i32** %p, i32* %q) {
+ cmpxchg i32** %p, i32* null, i32* %q acquire monotonic
+ ret void
+}
+
+; ATTRIBUTOR: define void @test_atomicrmw(i32* nocapture nofree nonnull dereferenceable(4) %p)
+define void @test_atomicrmw(i32* %p) {
+ atomicrmw add i32* %p, i32 1 seq_cst
+ ret void
+}
+
+; ATTRIBUTOR: define void @test_volatile(i32* nofree align 4 %x)
+define void @test_volatile(i32* %x) {
+entry:
+ %gep = getelementptr i32, i32* %x, i64 1
+ store volatile i32 0, i32* %gep, align 4
+ ret void
+}
+
+; ATTRIBUTOR: nocaptureLaunder(i8* nocapture %p)
+define void @nocaptureLaunder(i8* %p) {
+entry:
+ %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
+ store i8 42, i8* %b
+ ret void
+}
+
+ at g2 = global i8* null
+; ATTRIBUTOR: define void @captureLaunder(i8* %p)
+define void @captureLaunder(i8* %p) {
+ %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
+ store i8* %b, i8** @g2
+ ret void
+}
+
+; ATTRIBUTOR: @nocaptureStrip(i8* nocapture writeonly %p)
+define void @nocaptureStrip(i8* %p) {
+entry:
+ %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
+ store i8 42, i8* %b
+ ret void
+}
+
+ at g3 = global i8* null
+; ATTRIBUTOR: define void @captureStrip(i8* writeonly %p)
+define void @captureStrip(i8* %p) {
+ %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
+ store i8* %b, i8** @g3
+ ret void
+}
+
+; ATTRIBUTOR: define i1 @captureICmp(i32* nofree readnone %x)
+define i1 @captureICmp(i32* %x) {
+ %1 = icmp eq i32* %x, null
+ ret i1 %1
+}
+
+; ATTRIBUTOR: define i1 @captureICmpRev(i32* nofree readnone %x)
+define i1 @captureICmpRev(i32* %x) {
+ %1 = icmp eq i32* null, %x
+ ret i1 %1
+}
+
+; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture nofree nonnull readnone %x)
+define i1 @nocaptureInboundsGEPICmp(i32* %x) {
+ %1 = getelementptr inbounds i32, i32* %x, i32 5
+ %2 = bitcast i32* %1 to i8*
+ %3 = icmp eq i8* %2, null
+ ret i1 %3
+}
+
+; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture nofree nonnull readnone %x)
+define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
+ %1 = getelementptr inbounds i32, i32* %x, i32 5
+ %2 = bitcast i32* %1 to i8*
+ %3 = icmp eq i8* null, %2
+ ret i1 %3
+}
+
+; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture nofree readnone dereferenceable_or_null(4) %x)
+define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) {
+ %1 = bitcast i32* %x to i8*
+ %2 = icmp eq i8* %1, null
+ ret i1 %2
+}
+
+; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* nofree readnone dereferenceable_or_null(4) %x)
+define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
+ %1 = bitcast i32* %x to i8*
+ %2 = icmp eq i8* %1, null
+ ret i1 %2
+}
+
+declare void @unknown(i8*)
+define void @test_callsite() {
+entry:
+; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm.
+; ATTRIBUTOR: call void @unknown(i8* noalias null)
+ call void @unknown(i8* null)
+ ret void
+}
+
+declare i8* @unknownpi8pi8(i8*,i8* returned)
+define i8* @test_returned1(i8* %A, i8* returned %B) nounwind readonly {
+; ATTRIBUTOR: define i8* @test_returned1(i8* nocapture readonly %A, i8* readonly returned %B)
+entry:
+ %p = call i8* @unknownpi8pi8(i8* %A, i8* %B)
+ ret i8* %p
+}
+
+define i8* @test_returned2(i8* %A, i8* %B) {
+; ATTRIBUTOR: define i8* @test_returned2(i8* nocapture readonly %A, i8* readonly returned %B)
+entry:
+ %p = call i8* @unknownpi8pi8(i8* %A, i8* %B) nounwind readonly
+ ret i8* %p
+}
+
+declare i8* @llvm.launder.invariant.group.p0i8(i8*)
+declare i8* @llvm.strip.invariant.group.p0i8(i8*)
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll b/llvm/test/Transforms/Attributor/nocapture-2.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll
rename to llvm/test/Transforms/Attributor/nocapture-2.ll
diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll
new file mode 100644
index 000000000000..d06a0ea1e9b0
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofree.ll
@@ -0,0 +1,243 @@
+; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
+; Copied from Transforms/FunctoinAttrs/nofree-attributor.ll
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Test cases specifically designed for the "nofree" function attribute.
+; We use FIXME's to indicate problems and missing attributes.
+
+; Free functions
+declare void @free(i8* nocapture) local_unnamed_addr #1
+declare noalias i8* @realloc(i8* nocapture, i64) local_unnamed_addr #0
+declare void @_ZdaPv(i8*) local_unnamed_addr #2
+
+
+; TEST 1 (positive case)
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @only_return()
+define void @only_return() #0 {
+ ret void
+}
+
+
+; TEST 2 (negative case)
+; Only free
+; void only_free(char* p) {
+; free(p);
+; }
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr #1
+define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
+ tail call void @free(i8* %0) #1
+ ret void
+}
+
+
+; TEST 3 (negative case)
+; Free occurs in same scc.
+; void free_in_scc1(char*p){
+; free_in_scc2(p);
+; }
+; void free_in_scc2(char*p){
+; free_in_scc1(p);
+; free(p);
+; }
+
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT :define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
+define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
+ tail call void @free_in_scc2(i8* %0) #1
+ ret void
+}
+
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
+define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
+ %cmp = icmp eq i8* %0, null
+ br i1 %cmp, label %rec, label %call
+call:
+ tail call void @free(i8* %0) #1
+ br label %end
+rec:
+ tail call void @free_in_scc1(i8* %0)
+ br label %end
+end:
+ ret void
+}
+
+
+; TEST 4 (positive case)
+; Free doesn't occur.
+; void mutual_recursion1(){
+; mutual_recursion2();
+; }
+; void mutual_recursion2(){
+; mutual_recursion1();
+; }
+
+
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
+define void @mutual_recursion1() #0 {
+ call void @mutual_recursion2()
+ ret void
+}
+
+; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
+define void @mutual_recursion2() #0 {
+ call void @mutual_recursion1()
+ ret void
+}
+
+
+; TEST 5
+; C++ delete operation (negative case)
+; void delete_op (char p[]){
+; delete [] p;
+; }
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #1
+define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
+ %2 = icmp eq i8* %0, null
+ br i1 %2, label %4, label %3
+
+; <label>:3: ; preds = %1
+ tail call void @_ZdaPv(i8* nonnull %0) #2
+ br label %4
+
+; <label>:4: ; preds = %3, %1
+ ret void
+}
+
+
+; TEST 6 (negative case)
+; Call realloc
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
+define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
+ %ret = tail call i8* @realloc(i8* %0, i64 %1) #2
+ ret i8* %ret
+}
+
+
+; TEST 7 (positive case)
+; Call function declaration with "nofree"
+
+
+; ATTRIBUTOR: Function Attrs: nofree noinline nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: declare void @nofree_function()
+declare void @nofree_function() nofree readnone #0
+
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @call_nofree_function()
+define void @call_nofree_function() #0 {
+ tail call void @nofree_function()
+ ret void
+}
+
+; TEST 8 (negative case)
+; Call function declaration without "nofree"
+
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NEXT: declare void @maybe_free()
+declare void @maybe_free() #0
+
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @call_maybe_free()
+define void @call_maybe_free() #0 {
+ tail call void @maybe_free()
+ ret void
+}
+
+
+; TEST 9 (negative case)
+; Call both of above functions
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @call_both()
+define void @call_both() #0 {
+ tail call void @maybe_free()
+ tail call void @nofree_function()
+ ret void
+}
+
+
+; TEST 10 (positive case)
+; Call intrinsic function
+; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
+; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
+declare float @llvm.floor.f32(float)
+
+; FIXME: missing nofree
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
+
+define void @call_floor(float %a) #0 {
+ tail call float @llvm.floor.f32(float %a)
+ ret void
+}
+
+; TEST 11 (positive case)
+; Check propagation.
+
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @f1()
+define void @f1() #0 {
+ tail call void @nofree_function()
+ ret void
+}
+
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define void @f2()
+define void @f2() #0 {
+ tail call void @f1()
+ ret void
+}
+
+; TEST 12 NoFree argument - positive.
+; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %a)
+define double @test12(double* nocapture readonly %a) {
+entry:
+ %0 = load double, double* %a, align 8
+ %call = tail call double @cos(double %0) #2
+ ret double %call
+}
+
+declare double @cos(double) nobuiltin nounwind nofree
+
+; FIXME: %a should be nofree.
+; TEST 13 NoFree argument - positive.
+; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly align 8 dereferenceable(8) %a)
+define noalias i32* @test13(i64* nocapture readonly %a) {
+entry:
+ %0 = load i64, i64* %a, align 8
+ %call = tail call noalias i8* @malloc(i64 %0) #2
+ %1 = bitcast i8* %call to i32*
+ ret i32* %1
+}
+
+; ATTRIBUTOR: define void @test14(i8* nocapture %0, i8* nocapture nofree readnone %1)
+define void @test14(i8* nocapture %0, i8* nocapture %1) {
+ tail call void @free(i8* %0) #1
+ ret void
+}
+
+declare noalias i8* @malloc(i64)
+
+attributes #0 = { nounwind uwtable noinline }
+attributes #1 = { nounwind }
+attributes #2 = { nobuiltin nounwind }
diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
new file mode 100644
index 000000000000..260f04c27379
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -0,0 +1,817 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_OPM
+; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_NPM
+; Copied from Transforms/FunctoinAttrs/nonnull.ll
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare nonnull i8* @ret_nonnull()
+
+; Return a pointer trivially nonnull (call return attribute)
+define i8* @test1() {
+; ATTRIBUTOR: define nonnull i8* @test1
+ %ret = call i8* @ret_nonnull()
+ ret i8* %ret
+}
+
+; Return a pointer trivially nonnull (argument attribute)
+define i8* @test2(i8* nonnull %p) {
+; ATTRIBUTOR: define nonnull i8* @test2
+ ret i8* %p
+}
+
+; Given an SCC where one of the functions can not be marked nonnull,
+; can we still mark the other one which is trivially nonnull
+define i8* @scc_binder(i1 %c) {
+; ATTRIBUTOR: define noalias i8* @scc_binder
+ br i1 %c, label %rec, label %end
+rec:
+ call i8* @test3(i1 %c)
+ br label %end
+end:
+ ret i8* null
+}
+
+define i8* @test3(i1 %c) {
+; ATTRIBUTOR: define nonnull i8* @test3
+ call i8* @scc_binder(i1 %c)
+ %ret = call i8* @ret_nonnull()
+ ret i8* %ret
+}
+
+; Given a mutual recursive set of functions, we can mark them
+; nonnull if neither can ever return null. (In this case, they
+; just never return period.)
+define i8* @test4_helper() {
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4_helper
+ %ret = call i8* @test4()
+ ret i8* %ret
+}
+
+define i8* @test4() {
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4
+ %ret = call i8* @test4_helper()
+ ret i8* %ret
+}
+
+; Given a mutual recursive set of functions which *can* return null
+; make sure we haven't marked them as nonnull.
+define i8* @test5_helper(i1 %c) {
+; ATTRIBUTOR: define noalias i8* @test5_helper
+ br i1 %c, label %rec, label %end
+rec:
+ %ret = call i8* @test5(i1 %c)
+ br label %end
+end:
+ ret i8* null
+}
+
+define i8* @test5(i1 %c) {
+; ATTRIBUTOR: define noalias i8* @test5
+ %ret = call i8* @test5_helper(i1 %c)
+ ret i8* %ret
+}
+
+; Local analysis, but going through a self recursive phi
+; ATTRIBUTOR: Function Attrs: noreturn
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test6a()
+define i8* @test6a() {
+entry:
+ %ret = call i8* @ret_nonnull()
+ br label %loop
+loop:
+ %phi = phi i8* [%ret, %entry], [%phi, %loop]
+ br i1 undef, label %loop, label %exit
+exit:
+ ret i8* %phi
+}
+
+; ATTRIBUTOR: define nonnull i8* @test6b(i1 %c)
+define i8* @test6b(i1 %c) {
+entry:
+ %ret = call i8* @ret_nonnull()
+ br label %loop
+loop:
+ %phi = phi i8* [%ret, %entry], [%phi, %loop]
+ br i1 %c, label %loop, label %exit
+exit:
+ ret i8* %phi
+}
+
+; ATTRIBUTOR: define i8* @test7
+define i8* @test7(i8* %a) {
+ %b = getelementptr inbounds i8, i8* %a, i64 0
+ ret i8* %b
+}
+
+; ATTRIBUTOR: define nonnull i8* @test8
+define i8* @test8(i8* %a) {
+ %b = getelementptr inbounds i8, i8* %a, i64 1
+ ret i8* %b
+}
+
+; ATTRIBUTOR: define i8* @test9
+define i8* @test9(i8* %a, i64 %n) {
+ %b = getelementptr inbounds i8, i8* %a, i64 %n
+ ret i8* %b
+}
+
+declare void @llvm.assume(i1)
+; FIXME: missing nonnull
+; ATTRIBUTOR: define i8* @test10
+define i8* @test10(i8* %a, i64 %n) {
+ %cmp = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %cmp)
+ %b = getelementptr inbounds i8, i8* %a, i64 %n
+ ret i8* %b
+}
+
+; TEST 11
+; char* test11(char *p) {
+; return p? p: nonnull();
+; }
+; FIXME: missing nonnull
+; ATTRIBUTOR: define i8* @test11
+define i8* @test11(i8*) local_unnamed_addr {
+ %2 = icmp eq i8* %0, null
+ br i1 %2, label %3, label %5
+
+; <label>:3: ; preds = %1
+ %4 = tail call i8* @ret_nonnull()
+ br label %5
+
+; <label>:5: ; preds = %3, %1
+ %6 = phi i8* [ %4, %3 ], [ %0, %1 ]
+ ret i8* %6
+}
+
+; TEST 12
+; Simple CallSite Test
+declare void @test12_helper(i8*)
+define void @test12(i8* nonnull %a) {
+; ATTRIBUTOR: define void @test12(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: tail call void @test12_helper(i8* nonnull %a)
+ tail call void @test12_helper(i8* %a)
+ ret void
+}
+
+; TEST 13
+; Simple Argument Tests
+declare i8* @unknown()
+define void @test13_helper() {
+ %nonnullptr = tail call i8* @ret_nonnull()
+ %maybenullptr = tail call i8* @unknown()
+ tail call void @test13(i8* %nonnullptr, i8* %nonnullptr, i8* %maybenullptr)
+ tail call void @test13(i8* %nonnullptr, i8* %maybenullptr, i8* %nonnullptr)
+ ret void
+}
+define internal void @test13(i8* %a, i8* %b, i8* %c) {
+; ATTRIBUTOR: define internal void @test13(i8* nocapture nofree nonnull readnone %a, i8* nocapture nofree readnone %b, i8* nocapture nofree readnone %c)
+ ret void
+}
+
+declare nonnull i8* @nonnull()
+
+; TEST 14
+; Complex propagation
+; Argument of f1, f2, f3 can be marked with nonnull.
+
+; * Argument
+; 1. In f1:bb6, %arg can be marked with nonnull because of the comparison in bb1
+; 2. Because f2 is internal function, f2(i32* %arg) -> @f2(i32* nonnull %arg)
+; 3. In f1:bb4 %tmp5 is nonnull and f3 is internal function.
+; Then, f3(i32* %arg) -> @f3(i32* nonnull %arg)
+; 4. We get nonnull in whole f1 call sites so f1(i32* %arg) -> @f1(i32* nonnull %arg)
+
+
+define internal i32* @f1(i32* %arg) {
+; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg)
+; ATTRIBUTOR: define internal nonnull i32* @f1(i32* nofree readonly %arg)
+
+bb:
+ %tmp = icmp eq i32* %arg, null
+ br i1 %tmp, label %bb9, label %bb1
+
+bb1: ; preds = %bb
+ %tmp2 = load i32, i32* %arg, align 4
+ %tmp3 = icmp eq i32 %tmp2, 0
+ br i1 %tmp3, label %bb6, label %bb4
+
+bb4: ; preds = %bb1
+ %tmp5 = getelementptr inbounds i32, i32* %arg, i64 1
+; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* nofree nonnull %tmp5)
+ %tmp5b = tail call i32* @f3(i32* %tmp5)
+ %tmp5c = getelementptr inbounds i32, i32* %tmp5b, i64 -1
+ br label %bb9
+
+bb6: ; preds = %bb1
+; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg)
+; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree %arg)
+ %tmp7 = tail call i32* @f2(i32* %arg)
+ ret i32* %tmp7
+
+bb9: ; preds = %bb4, %bb
+ %tmp10 = phi i32* [ %tmp5c, %bb4 ], [ inttoptr (i64 4 to i32*), %bb ]
+ ret i32* %tmp10
+}
+
+define internal i32* @f2(i32* %arg) {
+; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg)
+; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree readonly %arg)
+bb:
+
+; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
+; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* nofree %arg)
+ %tmp = tail call i32* @f1(i32* %arg)
+ ret i32* %tmp
+}
+
+define dso_local noalias i32* @f3(i32* %arg) {
+; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg)
+; ATTRIBUTOR: define dso_local noalias nonnull i32* @f3(i32* nofree readonly %arg)
+bb:
+; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
+; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* nofree %arg)
+ %tmp = call i32* @f1(i32* %arg)
+ ret i32* %tmp
+}
+
+; TEST 15
+define void @f15(i8* %arg) {
+; ATTRIBUTOR: tail call void @use1(i8* nonnull dereferenceable(4) %arg)
+
+ tail call void @use1(i8* dereferenceable(4) %arg)
+ ret void
+}
+
+declare void @fun0() #1
+declare void @fun1(i8*) #1
+declare void @fun2(i8*, i8*) #1
+declare void @fun3(i8*, i8*, i8*) #1
+; TEST 16 simple path test
+; if(..)
+; fun2(nonnull %a, nonnull %b)
+; else
+; fun2(nonnull %a, %b)
+; We can say that %a is nonnull but %b is not.
+define void @f16(i8* %a, i8 * %b, i8 %c) {
+; FIXME: missing nonnull on %a
+; ATTRIBUTOR: define void @f16(i8* %a, i8* %b, i8 %c)
+ %cmp = icmp eq i8 %c, 0
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ tail call void @fun2(i8* nonnull %a, i8* nonnull %b)
+ ret void
+if.else:
+ tail call void @fun2(i8* nonnull %a, i8* %b)
+ ret void
+}
+; TEST 17 explore child BB test
+; if(..)
+; ... (willreturn & nounwind)
+; else
+; ... (willreturn & nounwind)
+; fun1(nonnull %a)
+; We can say that %a is nonnull
+define void @f17(i8* %a, i8 %c) {
+; ATTRIBUTOR: define void @f17(i8* nonnull %a, i8 %c)
+ %cmp = icmp eq i8 %c, 0
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ tail call void @fun0()
+ br label %cont
+if.else:
+ tail call void @fun0()
+ br label %cont
+cont:
+ tail call void @fun1(i8* nonnull %a)
+ ret void
+}
+; TEST 18 More complex test
+; if(..)
+; ... (willreturn & nounwind)
+; else
+; ... (willreturn & nounwind)
+; if(..)
+; ... (willreturn & nounwind)
+; else
+; ... (willreturn & nounwind)
+; fun1(nonnull %a)
+
+define void @f18(i8* %a, i8* %b, i8 %c) {
+; ATTRIBUTOR: define void @f18(i8* nonnull %a, i8* %b, i8 %c)
+ %cmp1 = icmp eq i8 %c, 0
+ br i1 %cmp1, label %if.then, label %if.else
+if.then:
+ tail call void @fun0()
+ br label %cont
+if.else:
+ tail call void @fun0()
+ br label %cont
+cont:
+ %cmp2 = icmp eq i8 %c, 1
+ br i1 %cmp2, label %cont.then, label %cont.else
+cont.then:
+ tail call void @fun1(i8* nonnull %b)
+ br label %cont2
+cont.else:
+ tail call void @fun0()
+ br label %cont2
+cont2:
+ tail call void @fun1(i8* nonnull %a)
+ ret void
+}
+
+; TEST 19: Loop
+
+define void @f19(i8* %a, i8* %b, i8 %c) {
+; FIXME: missing nonnull on %b
+; ATTRIBUTOR: define void @f19(i8* %a, i8* %b, i8 %c)
+ br label %loop.header
+loop.header:
+ %cmp2 = icmp eq i8 %c, 0
+ br i1 %cmp2, label %loop.body, label %loop.exit
+loop.body:
+ tail call void @fun1(i8* nonnull %b)
+ tail call void @fun1(i8* nonnull %a)
+ br label %loop.header
+loop.exit:
+ tail call void @fun1(i8* nonnull %b)
+ ret void
+}
+
+; Test propagation of nonnull callsite args back to caller.
+
+declare void @use1(i8* %x)
+declare void @use2(i8* %x, i8* %y);
+declare void @use3(i8* %x, i8* %y, i8* %z);
+
+declare void @use1nonnull(i8* nonnull %x);
+declare void @use2nonnull(i8* nonnull %x, i8* nonnull %y);
+declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
+
+declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor
+
+; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute.
+
+define void @parent1(i8* %a, i8* %b, i8* %c) {
+; ATTRIBUTOR-LABEL: @parent1(i8* %a, i8* %b, i8* %c)
+; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
+; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
+; ATTRIBUTOR-NEXT: ret void
+ call void @use3(i8* %c, i8* %a, i8* %b)
+ call void @use3nonnull(i8* %b, i8* %c, i8* %a)
+ ret void
+}
+
+; Extend non-null to parent for all arguments.
+
+define void @parent2(i8* %a, i8* %b, i8* %c) {
+
+; ATTRIBUTOR-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c)
+; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
+; ATTRIBUTOR-NEXT: call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b)
+
+; ATTRIBUTOR-NEXT: ret void
+ call void @use3nonnull(i8* %b, i8* %c, i8* %a)
+ call void @use3(i8* %c, i8* %a, i8* %b)
+ ret void
+}
+
+; Extend non-null to parent for 1st argument.
+
+define void @parent3(i8* %a, i8* %b, i8* %c) {
+
+; ATTRIBUTOR-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c)
+; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %b, i8* nonnull %a)
+
+; ATTRIBUTOR-NEXT: ret void
+
+ call void @use1nonnull(i8* %a)
+ call void @use3(i8* %c, i8* %b, i8* %a)
+ ret void
+}
+
+; Extend non-null to parent for last 2 arguments.
+
+define void @parent4(i8* %a, i8* %b, i8* %c) {
+; CHECK-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
+; CHECK-NEXT: call void @use2nonnull(i8* %c, i8* %b)
+; CHECK-NEXT: call void @use2(i8* %a, i8* %c)
+; CHECK-NEXT: call void @use1(i8* %b)
+
+; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
+; ATTRIBUTOR-NEXT: call void @use2nonnull(i8* nonnull %c, i8* nonnull %b)
+; ATTRIBUTOR-NEXT: call void @use2(i8* %a, i8* nonnull %c)
+; ATTRIBUTOR-NEXT: call void @use1(i8* nonnull %b)
+
+; ATTRIBUTOR: ret void
+
+ call void @use2nonnull(i8* %c, i8* %b)
+ call void @use2(i8* %a, i8* %c)
+ call void @use1(i8* %b)
+ ret void
+}
+
+; The callsite must execute in order for the attribute to transfer to the parent.
+; It appears benign to extend non-null to the parent in this case, but we can't do that
+; because it would incorrectly propagate the wrong information to its callers.
+
+define void @parent5(i8* %a, i1 %a_is_notnull) {
+; ATTRIBUTOR: @parent5(i8* %a, i1 %a_is_notnull)
+; ATTRIBUTOR-NEXT: br i1 %a_is_notnull, label %t, label %f
+; ATTRIBUTOR: t:
+; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: ret void
+; ATTRIBUTOR: f:
+; ATTRIBUTOR-NEXT: ret void
+
+ br i1 %a_is_notnull, label %t, label %f
+t:
+ call void @use1nonnull(i8* %a)
+ ret void
+f:
+ ret void
+}
+
+; The callsite must execute in order for the attribute to transfer to the parent.
+; The volatile load can't trap, so we can guarantee that we'll get to the call.
+
+define i8 @parent6(i8* %a, i8* %b) {
+; ATTRIBUTOR-LABEL: @parent6(i8* nonnull %a, i8* %b)
+; ATTRIBUTOR-NEXT: [[C:%.*]] = load volatile i8, i8* %b
+; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: ret i8 [[C]]
+
+ %c = load volatile i8, i8* %b
+ call void @use1nonnull(i8* %a)
+ ret i8 %c
+}
+
+; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent.
+
+define i8 @parent7(i8* %a) {
+
+
+; ATTRIBUTOR-LABEL: @parent7(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* nonnull %a)
+; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
+
+; ATTRIBUTOR-NEXT: ret i8 [[RET]]
+
+ %ret = call i8 @use1safecall(i8* %a)
+ call void @use1nonnull(i8* %a)
+ ret i8 %ret
+}
+
+; Make sure that an invoke works similarly to a call.
+
+declare i32 @esfp(...)
+
+define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){
+; ATTRIBUTOR-LABEL: @parent8(i8* nonnull %a, i8* nocapture nofree readnone %bogus1, i8* nonnull %b)
+; ATTRIBUTOR-NEXT: entry:
+; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b)
+; ATTRIBUTOR-NEXT: to label %cont unwind label %exc
+; ATTRIBUTOR: cont:
+; ATTRIBUTOR-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null
+; ATTRIBUTOR-NEXT: ret i1 [[NULL_CHECK]]
+; ATTRIBUTOR: exc:
+; ATTRIBUTOR-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
+; ATTRIBUTOR-NEXT: filter [0 x i8*] zeroinitializer
+; ATTRIBUTOR-NEXT: unreachable
+
+entry:
+ invoke void @use2nonnull(i8* %a, i8* %b)
+ to label %cont unwind label %exc
+
+cont:
+ %null_check = icmp eq i8* %b, null
+ ret i1 %null_check
+
+exc:
+ %lp = landingpad { i8*, i32 }
+ filter [0 x i8*] zeroinitializer
+ unreachable
+}
+
+; ATTRIBUTOR: define nonnull i32* @gep1(
+define i32* @gep1(i32* %p) {
+ %q = getelementptr inbounds i32, i32* %p, i32 1
+ ret i32* %q
+}
+
+define i32* @gep1_no_null_opt(i32* %p) #0 {
+; Should't be able to derive nonnull based on gep.
+; ATTRIBUTOR: define i32* @gep1_no_null_opt(
+ %q = getelementptr inbounds i32, i32* %p, i32 1
+ ret i32* %q
+}
+
+; ATTRIBUTOR: define i32 addrspace(3)* @gep2(
+define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
+ %q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1
+ ret i32 addrspace(3)* %q
+}
+
+; FIXME: We should propagate dereferenceable here but *not* nonnull
+; ATTRIBUTOR: define dereferenceable_or_null(4) i32 addrspace(3)* @as(i32 addrspace(3)* nofree readnone returned dereferenceable(4) dereferenceable_or_null(4) %p)
+define i32 addrspace(3)* @as(i32 addrspace(3)* dereferenceable(4) %p) {
+ ret i32 addrspace(3)* %p
+}
+
+; ATTRIBUTOR: define internal nonnull i32* @g2()
+define internal i32* @g2() {
+ ret i32* inttoptr (i64 4 to i32*)
+}
+
+define i32* @g1() {
+ %c = call i32* @g2()
+ ret i32* %c
+}
+
+declare void @use_i32_ptr(i32*) readnone nounwind
+; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a)
+define internal void @called_by_weak(i32* %a) {
+ call void @use_i32_ptr(i32* %a)
+ ret void
+}
+
+; Check we do not annotate the function interface of this weak function.
+; ATTRIBUTOR: define weak_odr void @weak_caller(i32* nonnull %a)
+define weak_odr void @weak_caller(i32* nonnull %a) {
+ call void @called_by_weak(i32* %a)
+ ret void
+}
+
+; Expect nonnull
+; ATTRIBUTOR: define internal void @control(i32* nocapture nonnull readnone align 16 dereferenceable(8) %a)
+define internal void @control(i32* dereferenceable(4) %a) {
+ call void @use_i32_ptr(i32* %a)
+ ret void
+}
+; Avoid nonnull as we do not touch naked functions
+; ATTRIBUTOR: define internal void @naked(i32* dereferenceable(4) %a)
+define internal void @naked(i32* dereferenceable(4) %a) naked {
+ call void @use_i32_ptr(i32* %a)
+ ret void
+}
+; Avoid nonnull as we do not touch optnone
+; ATTRIBUTOR: define internal void @optnone(i32* dereferenceable(4) %a)
+define internal void @optnone(i32* dereferenceable(4) %a) optnone noinline {
+ call void @use_i32_ptr(i32* %a)
+ ret void
+}
+define void @make_live(i32* nonnull dereferenceable(8) %a) {
+ call void @naked(i32* nonnull dereferenceable(8) align 16 %a)
+ call void @control(i32* nonnull dereferenceable(8) align 16 %a)
+ call void @optnone(i32* nonnull dereferenceable(8) align 16 %a)
+ ret void
+}
+
+;int f(int *u, int n){
+; for(int i = 0;i<n;i++){
+; h(u);
+; }
+; return g(nonnull u);
+;}
+declare void @h(i32*) willreturn nounwind
+declare i32 @g(i32*) willreturn nounwind
+define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) {
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1
+; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
+; ATTRIBUTOR-NEXT: en:
+; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
+; ATTRIBUTOR: ex:
+; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
+; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
+; ATTRIBUTOR: hd:
+; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
+; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]])
+; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
+; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
+; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
+;
+en:
+ %tmp3 = icmp eq i32 %b, 0
+ br i1 %tmp3, label %ex, label %hd
+
+ex:
+ %tmp5 = tail call i32 @g(i32* nonnull %a)
+ ret i32 %tmp5
+
+hd:
+ %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+ tail call void @h(i32* %a)
+ %tmp8 = add nuw i32 %tmp7, 1
+ %tmp9 = icmp eq i32 %tmp8, %b
+ br i1 %tmp9, label %ex, label %hd
+}
+
+define i32 @nonnull_exec_ctx_1b(i32* %a, i32 %b) {
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b
+; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
+; ATTRIBUTOR-NEXT: en:
+; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
+; ATTRIBUTOR: ex:
+; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
+; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
+; ATTRIBUTOR: hd:
+; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
+; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]])
+; ATTRIBUTOR-NEXT: br label [[HD2]]
+; ATTRIBUTOR: hd2:
+; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
+; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
+; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
+;
+en:
+ %tmp3 = icmp eq i32 %b, 0
+ br i1 %tmp3, label %ex, label %hd
+
+ex:
+ %tmp5 = tail call i32 @g(i32* nonnull %a)
+ ret i32 %tmp5
+
+hd:
+ %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ]
+ tail call void @h(i32* %a)
+ br label %hd2
+
+hd2:
+ %tmp8 = add nuw i32 %tmp7, 1
+ %tmp9 = icmp eq i32 %tmp8, %b
+ br i1 %tmp9, label %ex, label %hd
+}
+
+define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) willreturn nounwind {
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2
+; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
+; ATTRIBUTOR-NEXT: en:
+; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
+; ATTRIBUTOR: ex:
+; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
+; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
+; ATTRIBUTOR: hd:
+; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
+; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]])
+; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
+; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
+; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
+;
+en:
+ %tmp3 = icmp eq i32 %b, 0
+ br i1 %tmp3, label %ex, label %hd
+
+ex:
+ %tmp5 = tail call i32 @g(i32* nonnull %a)
+ ret i32 %tmp5
+
+hd:
+ %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
+ tail call void @h(i32* %a)
+ %tmp8 = add nuw i32 %tmp7, 1
+ %tmp9 = icmp eq i32 %tmp8, %b
+ br i1 %tmp9, label %ex, label %hd
+}
+
+define i32 @nonnull_exec_ctx_2b(i32* %a, i32 %b) willreturn nounwind {
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b
+; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
+; ATTRIBUTOR-NEXT: en:
+; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
+; ATTRIBUTOR: ex:
+; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
+; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
+; ATTRIBUTOR: hd:
+; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
+; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]])
+; ATTRIBUTOR-NEXT: br label [[HD2]]
+; ATTRIBUTOR: hd2:
+; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
+; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
+; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
+;
+en:
+ %tmp3 = icmp eq i32 %b, 0
+ br i1 %tmp3, label %ex, label %hd
+
+ex:
+ %tmp5 = tail call i32 @g(i32* nonnull %a)
+ ret i32 %tmp5
+
+hd:
+ %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ]
+ tail call void @h(i32* %a)
+ br label %hd2
+
+hd2:
+ %tmp8 = add nuw i32 %tmp7, 1
+ %tmp9 = icmp eq i32 %tmp8, %b
+ br i1 %tmp9, label %ex, label %hd
+}
+
+; Original from PR43833
+declare void @sink(i32*)
+
+; FIXME: the sink argument should be marked nonnull as in @PR43833_simple.
+define void @PR43833(i32* %0, i32 %1) {
+; ATTRIBUTOR-LABEL: @PR43833(
+; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1:%.*]], 1
+; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
+; ATTRIBUTOR: 4:
+; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
+; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
+; ATTRIBUTOR-NEXT: br label [[TMP8:%.*]]
+; ATTRIBUTOR: 7:
+; ATTRIBUTOR-NEXT: ret void
+; ATTRIBUTOR: 8:
+; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
+; ATTRIBUTOR-NEXT: tail call void @sink(i32* [[TMP6]])
+; ATTRIBUTOR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
+; ATTRIBUTOR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
+; ATTRIBUTOR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
+;
+ %3 = icmp sgt i32 %1, 1
+ br i1 %3, label %4, label %7
+
+4: ; preds = %2
+ %5 = zext i32 %1 to i64
+ %6 = getelementptr inbounds i32, i32* %0, i64 %5
+ br label %8
+
+7: ; preds = %8, %2
+ ret void
+
+8: ; preds = %8, %4
+ %9 = phi i32 [ 1, %4 ], [ %10, %8 ]
+ tail call void @sink(i32* %6)
+ %10 = add nuw nsw i32 %9, 1
+ %11 = icmp eq i32 %10, %1
+ br i1 %11, label %7, label %8
+}
+
+; Adjusted from PR43833
+define void @PR43833_simple(i32* %0, i32 %1) {
+; ATTRIBUTOR_OPM-LABEL: @PR43833_simple(
+; ATTRIBUTOR_OPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
+; ATTRIBUTOR_OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
+; ATTRIBUTOR_OPM: 4:
+; ATTRIBUTOR_OPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
+; ATTRIBUTOR_OPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
+; ATTRIBUTOR_OPM-NEXT: br label [[TMP8:%.*]]
+; ATTRIBUTOR_OPM: 7:
+; ATTRIBUTOR_OPM-NEXT: ret void
+; ATTRIBUTOR_OPM: 8:
+; ATTRIBUTOR_OPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
+; ATTRIBUTOR_OPM-NEXT: tail call void @sink(i32* [[TMP6]])
+; ATTRIBUTOR_OPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
+; ATTRIBUTOR_OPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
+; ATTRIBUTOR_OPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
+;
+; ATTRIBUTOR_NPM-LABEL: @PR43833_simple(
+; ATTRIBUTOR_NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
+; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
+; ATTRIBUTOR_NPM: 4:
+; ATTRIBUTOR_NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
+; ATTRIBUTOR_NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
+; ATTRIBUTOR_NPM-NEXT: br label [[TMP8:%.*]]
+; ATTRIBUTOR_NPM: 7:
+; ATTRIBUTOR_NPM-NEXT: ret void
+; ATTRIBUTOR_NPM: 8:
+; ATTRIBUTOR_NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
+; ATTRIBUTOR_NPM-NEXT: tail call void @sink(i32* [[TMP6]])
+; ATTRIBUTOR_NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
+; ATTRIBUTOR_NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
+; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
+;
+ %3 = icmp ne i32 %1, 0
+ br i1 %3, label %4, label %7
+
+4: ; preds = %2
+ %5 = zext i32 %1 to i64
+ %6 = getelementptr inbounds i32, i32* %0, i64 %5
+ br label %8
+
+7: ; preds = %8, %2
+ ret void
+
+8: ; preds = %8, %4
+ %9 = phi i32 [ 1, %4 ], [ %10, %8 ]
+ tail call void @sink(i32* %6)
+ %10 = add nuw nsw i32 %9, 1
+ %11 = icmp eq i32 %10, %1
+ br i1 %11, label %7, label %8
+}
+
+attributes #0 = { "null-pointer-is-valid"="true" }
+attributes #1 = { nounwind willreturn}
diff --git a/llvm/test/Transforms/Attributor/norecurse.ll b/llvm/test/Transforms/Attributor/norecurse.ll
new file mode 100644
index 000000000000..25f7fdee5f13
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/norecurse.ll
@@ -0,0 +1,147 @@
+; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
+; Copied from Transforms/FunctoinAttrs/norecurse.ll
+
+; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; ATTRIBUTOR-NEXT: define i32 @leaf()
+define i32 @leaf() {
+ ret i32 1
+}
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-SAME: readnone
+; ATTRIBUTOR-NOT: norecurse
+; ATTRIBUTOR-NEXT: define i32 @self_rec()
+define i32 @self_rec() {
+ %a = call i32 @self_rec()
+ ret i32 4
+}
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-SAME: readnone
+; ATTRIBUTOR-NOT: norecurse
+; ATTRIBUTOR-NEXT: define i32 @indirect_rec()
+define i32 @indirect_rec() {
+ %a = call i32 @indirect_rec2()
+ ret i32 %a
+}
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-SAME: readnone
+; ATTRIBUTOR-NOT: norecurse
+; ATTRIBUTOR-NEXT: define i32 @indirect_rec2()
+define i32 @indirect_rec2() {
+ %a = call i32 @indirect_rec()
+ ret i32 %a
+}
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-SAME: readnone
+; ATTRIBUTOR-NOT: norecurse
+; ATTRIBUTOR-NEXT: define i32 @extern()
+define i32 @extern() {
+ %a = call i32 @k()
+ ret i32 %a
+}
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-NEXT: declare i32 @k()
+declare i32 @k() readnone
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-NOT: norecurse
+; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture writeonly %dest, i8* nocapture readonly %src, i32 %len)
+define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
+ ret void
+}
+
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
+
+; ATTRIBUTOR: Function Attrs
+; FIXME: missing "norecurse"
+; ATTRIBUTOR-SAME: nosync readnone
+define internal i32 @called_by_norecurse() {
+ %a = call i32 @k()
+ ret i32 %a
+}
+; ATTRIBUTOR: Function Attrs
+; ATTRIBUTOR-NEXT: define void @m()
+define void @m() norecurse {
+ %a = call i32 @called_by_norecurse()
+ ret void
+}
+
+; ATTRIBUTOR: Function Attrs
+; FIXME: missing "norecurse"
+; ATTRIBUTOR-SAME: nosync
+define internal i32 @called_by_norecurse_indirectly() {
+ %a = call i32 @k()
+ ret i32 %a
+}
+define internal void @o() {
+ %a = call i32 @called_by_norecurse_indirectly()
+ ret void
+}
+define void @p() norecurse {
+ call void @o()
+ ret void
+}
+
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
+; ATTRIBUTOR-NEXT: define void @f(i32 %x)
+define void @f(i32 %x) {
+entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ %tobool = icmp ne i32 %0, 0
+ br i1 %tobool, label %if.then, label %if.end
+
+if.then:
+ call void @g() norecurse
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; ATTRIBUTOR: define void @g()
+define void @g() norecurse {
+entry:
+ call void @f(i32 0)
+ ret void
+}
+
+; ATTRIBUTOR-NOT: Function Attrs
+; ATTRIBUTOR: define linkonce_odr i32 @leaf_redefinable()
+define linkonce_odr i32 @leaf_redefinable() {
+ ret i32 1
+}
+
+; Call through a function pointer
+; ATTRIBUTOR-NOT: Function Attrs
+; ATTRIBUTOR: define i32 @eval_func1(i32 (i32)* nocapture nofree nonnull %0, i32 %1)
+define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
+ %3 = tail call i32 %0(i32 %1) #2
+ ret i32 %3
+}
+
+; ATTRIBUTOR-NOT: Function Attrs
+; ATTRIBUTOR: define i32 @eval_func2(i32 (i32)* nocapture nofree %0, i32 %1)
+define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{
+ %3 = tail call i32 %0(i32 %1) #2
+ ret i32 %3
+}
+
+declare void @unknown()
+; Call an unknown function in a dead block.
+; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; ATTRIBUTOR: define i32 @call_unknown_in_dead_block()
+define i32 @call_unknown_in_dead_block() local_unnamed_addr {
+ ret i32 0
+Dead:
+ tail call void @unknown()
+ ret i32 1
+}
+
diff --git a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll b/llvm/test/Transforms/Attributor/noreturn.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll
rename to llvm/test/Transforms/Attributor/noreturn.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll b/llvm/test/Transforms/Attributor/noreturn_async.ll
similarity index 96%
rename from llvm/test/Transforms/FunctionAttrs/noreturn_async.ll
rename to llvm/test/Transforms/Attributor/noreturn_async.ll
index 3d2dd9f47da6..7c00a5a0b5cb 100644
--- a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll
+++ b/llvm/test/Transforms/Attributor/noreturn_async.ll
@@ -1,4 +1,4 @@
-; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
+; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
;
; This file is the same as noreturn_sync.ll but with a personality which
; indicates that the exception handler *can* catch asynchronous exceptions. As
diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll b/llvm/test/Transforms/Attributor/noreturn_sync.ll
similarity index 96%
rename from llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll
rename to llvm/test/Transforms/Attributor/noreturn_sync.ll
index b5a70e762716..4e6f13737a7e 100644
--- a/llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll
+++ b/llvm/test/Transforms/Attributor/noreturn_sync.ll
@@ -1,4 +1,4 @@
-; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
+; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
;
; This file is the same as noreturn_async.ll but with a personality which
; indicates that the exception handler *cannot* catch asynchronous exceptions.
diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll
similarity index 82%
rename from llvm/test/Transforms/FunctionAttrs/nosync.ll
rename to llvm/test/Transforms/Attributor/nosync.ll
index abb40cf26697..cd01a0caa58d 100644
--- a/llvm/test/Transforms/FunctionAttrs/nosync.ll
+++ b/llvm/test/Transforms/Attributor/nosync.ll
@@ -1,4 +1,3 @@
-; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -25,8 +24,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
%struct.ST = type { i32, double, %struct.RT }
-; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
-; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* nofree nonnull readnone "no-capture-maybe-returned" %s)
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
@@ -42,8 +39,6 @@ entry:
; return n;
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0)
define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
@@ -58,8 +53,6 @@ define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtabl
; atomic_load_explicit(num, memory_order_relaxed);
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0)
define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
@@ -74,8 +67,6 @@ define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
; return n;
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0)
@@ -90,8 +81,6 @@ define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable
; atomic_store_explicit(num, 10, memory_order_release);
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define void @load_release(i32* nocapture %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture nofree writeonly align 4 %0)
@@ -102,8 +91,6 @@ define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
; TEST 6 - negative volatile, relaxed atomic
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture nofree writeonly align 4 %0)
@@ -118,8 +105,6 @@ define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable
; *num = 14;
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define void @volatile_store(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @volatile_store(i32* nofree align 4 %0)
@@ -135,8 +120,6 @@ define void @volatile_store(i32* %0) norecurse nounwind uwtable {
; return n;
; }
-; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
-; FNATTR-NEXT: define i32 @volatile_load(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* nofree align 4 %0)
@@ -147,14 +130,10 @@ define i32 @volatile_load(i32* %0) norecurse nounwind uwtable {
; TEST 9
-; FNATTR: Function Attrs: noinline nosync nounwind uwtable
-; FNATTR-NEXT: declare void @nosync_function()
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @nosync_function()
declare void @nosync_function() noinline nounwind uwtable nosync
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NEXT: define void @call_nosync_function()
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
; ATTRIBUTOR-next: define void @call_nosync_function()
define void @call_nosync_function() nounwind uwtable noinline {
@@ -164,14 +143,10 @@ define void @call_nosync_function() nounwind uwtable noinline {
; TEST 10 - negative, should not deduce nosync
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NEXT: declare void @might_sync()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @might_sync()
declare void @might_sync() noinline nounwind uwtable
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NEXT: define void @call_might_sync()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @call_might_sync()
@@ -183,8 +158,6 @@ define void @call_might_sync() nounwind uwtable noinline {
; TEST 11 - positive, should deduce nosync
; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
-; FNATTR: Function Attrs: nofree noinline nounwind uwtable
-; FNATTR-NEXT: define i32 @scc1(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture nofree readnone %0)
define i32 @scc1(i32* %0) noinline nounwind uwtable {
@@ -193,8 +166,6 @@ define i32 @scc1(i32* %0) noinline nounwind uwtable {
ret i32 %val;
}
-; FNATTR: Function Attrs: nofree noinline nounwind uwtable
-; FNATTR-NEXT: define void @scc2(i32* %0)
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture nofree readnone %0)
define void @scc2(i32* %0) noinline nounwind uwtable {
@@ -221,8 +192,6 @@ define void @scc2(i32* %0) noinline nounwind uwtable {
%"struct.std::atomic" = type { %"struct.std::__atomic_base" }
%"struct.std::__atomic_base" = type { i8 }
-; FNATTR: Function Attrs: nofree norecurse nounwind
-; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR: define void @foo1(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1)
@@ -234,8 +203,6 @@ define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
ret void
}
-; FNATTR: Function Attrs: nofree norecurse nounwind
-; FNATTR-NEXT: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR: define void @bar(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1)
define void @bar(i32* %0, %"struct.std::atomic"* %1) {
@@ -254,8 +221,6 @@ define void @bar(i32* %0, %"struct.std::atomic"* %1) {
}
; TEST 13 - Fence syncscope("singlethread") seq_cst
-; FNATTR: Function Attrs: nofree norecurse nounwind
-; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn
; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1)
@@ -267,8 +232,6 @@ define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
ret void
}
-; FNATTR: Function Attrs: nofree norecurse nounwind
-; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1)
define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
diff --git a/llvm/test/Transforms/Attributor/nounwind.ll b/llvm/test/Transforms/Attributor/nounwind.ll
new file mode 100644
index 000000000000..e569095c8d41
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nounwind.ll
@@ -0,0 +1,98 @@
+; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S | FileCheck %s --check-prefix=ATTRIBUTOR
+; Copied from Transforms/FunctoinAttrs/nounwind.ll
+
+; TEST 1
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
+; ATTRIBUTOR-NEXT: define i32 @foo1()
+define i32 @foo1() {
+ ret i32 1
+}
+
+; TEST 2
+; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
+; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
+define i32 @scc1_foo() {
+ %1 = call i32 @scc1_bar()
+ ret i32 1
+}
+
+
+; TEST 3
+; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
+; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
+define i32 @scc1_bar() {
+ %1 = call i32 @scc1_foo()
+ ret i32 1
+}
+
+declare i32 @non_nounwind()
+
+; TEST 4
+; ATTRIBUTOR: define void @call_non_nounwind() {
+define void @call_non_nounwind(){
+ tail call i32 @non_nounwind()
+ ret void
+}
+
+; TEST 5 - throw
+; int maybe_throw(bool canThrow) {
+; if (canThrow)
+; throw;
+; else
+; return -1;
+; }
+
+; ATTRIBUTOR: define i32 @maybe_throw(i1 zeroext %0)
+define i32 @maybe_throw(i1 zeroext %0) {
+ br i1 %0, label %2, label %3
+
+2: ; preds = %1
+ tail call void @__cxa_rethrow() #1
+ unreachable
+
+3: ; preds = %1
+ ret i32 -1
+}
+
+declare void @__cxa_rethrow()
+
+; TEST 6 - catch
+; int catch_thing() {
+; try {
+; int a = doThing(true);
+; }
+; catch(...) { return -1; }
+; return 1;
+; }
+
+; ATTRIBUTOR: define i32 @catch_thing()
+define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+ invoke void @__cxa_rethrow() #1
+ to label %1 unwind label %2
+
+1: ; preds = %0
+ unreachable
+
+2: ; preds = %0
+ %3 = landingpad { i8*, i32 }
+ catch i8* null
+ %4 = extractvalue { i8*, i32 } %3, 0
+ %5 = tail call i8* @__cxa_begin_catch(i8* %4) #2
+ tail call void @__cxa_end_catch()
+ ret i32 -1
+}
+
+define i32 @catch_thing_user() {
+; ATTRIBUTOR: define i32 @catch_thing_user
+; ATTRIBUTOR-NEXT: %catch_thing_call = call
+; ATTRIBUTOR-NEXT: ret i32 -1
+ %catch_thing_call = call i32 @catch_thing()
+ ret i32 %catch_thing_call
+}
+
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
diff --git a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
rename to llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll
new file mode 100644
index 000000000000..9c148ef160bf
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/readattrs.ll
@@ -0,0 +1,145 @@
+; RUN: opt < %s -attributor -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=ATTRIBUTOR
+; RUN: opt < %s -aa-pipeline=basic-aa -passes='attributor' -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=ATTRIBUTOR
+; Copied from Transforms/FunctionAttrs/readattrs.ll
+
+ at x = global i32 0
+
+declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...)
+
+; NOTE: readonly for %y1_2 would be OK here but not for the similar situation in test13.
+;
+; ATTRIBUTOR: define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2)
+define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
+ call void (i8*, i8*, ...) @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2)
+ store i32 0, i32* @x
+ ret void
+}
+
+; ATTRIBUTOR: define i8* @test2(i8* nofree readnone returned %p)
+define i8* @test2(i8* %p) {
+ store i32 0, i32* @x
+ ret i8* %p
+}
+
+; ATTRIBUTOR: define i1 @test3(i8* nofree readnone %p, i8* nofree readnone %q)
+define i1 @test3(i8* %p, i8* %q) {
+ %A = icmp ult i8* %p, %q
+ ret i1 %A
+}
+
+declare void @test4_1(i8* nocapture) readonly
+
+; ATTRIBUTOR: define void @test4_2(i8* nocapture readonly %p)
+define void @test4_2(i8* %p) {
+ call void @test4_1(i8* %p)
+ ret void
+}
+
+; ATTRIBUTOR: define void @test5(i8** nocapture nofree nonnull writeonly dereferenceable(8) %p, i8* nofree writeonly %q)
+; Missed optz'n: we could make %q readnone, but don't break test6!
+define void @test5(i8** %p, i8* %q) {
+ store i8* %q, i8** %p
+ ret void
+}
+
+declare void @test6_1()
+; ATTRIBUTOR: define void @test6_2(i8** nocapture nonnull writeonly dereferenceable(8) %p, i8* %q)
+; This is not a missed optz'n.
+define void @test6_2(i8** %p, i8* %q) {
+ store i8* %q, i8** %p
+ call void @test6_1()
+ ret void
+}
+
+; ATTRIBUTOR: define void @test7_1(i32* inalloca nocapture nofree writeonly %a)
+; inalloca parameters are always considered written
+define void @test7_1(i32* inalloca %a) {
+ ret void
+}
+
+; ATTRIBUTOR: define i32* @test8_1(i32* nofree readnone returned %p)
+define i32* @test8_1(i32* %p) {
+entry:
+ ret i32* %p
+}
+
+; ATTRIBUTOR: define void @test8_2(i32* nocapture nofree writeonly %p)
+define void @test8_2(i32* %p) {
+entry:
+ %call = call i32* @test8_1(i32* %p)
+ store i32 10, i32* %call, align 4
+ ret void
+}
+
+; ATTRIBUTOR: declare void @llvm.masked.scatter
+declare void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*>, i32, <4 x i1>)
+
+; ATTRIBUTOR-NOT: readnone
+; ATTRIBUTOR-NOT: readonly
+; ATTRIBUTOR: define void @test9
+define void @test9(<4 x i32*> %ptrs, <4 x i32>%val) {
+ call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
+ ret void
+}
+
+; ATTRIBUTOR: declare <4 x i32> @llvm.masked.gather
+declare <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*>, i32, <4 x i1>, <4 x i32>)
+; ATTRIBUTOR: readonly
+; ATTRIBUTOR: define <4 x i32> @test10
+define <4 x i32> @test10(<4 x i32*> %ptrs) {
+ %res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
+ ret <4 x i32> %res
+}
+
+; ATTRIBUTOR: declare <4 x i32> @test11_1
+declare <4 x i32> @test11_1(<4 x i32*>) argmemonly nounwind readonly
+; ATTRIBUTOR: readonly
+; ATTRIBUTOR-NOT: readnone
+; ATTRIBUTOR: define <4 x i32> @test11_2
+define <4 x i32> @test11_2(<4 x i32*> %ptrs) {
+ %res = call <4 x i32> @test11_1(<4 x i32*> %ptrs)
+ ret <4 x i32> %res
+}
+
+declare <4 x i32> @test12_1(<4 x i32*>) argmemonly nounwind
+; ATTRIBUTOR-NOT: readnone
+; ATTRIBUTOR: define <4 x i32> @test12_2
+define <4 x i32> @test12_2(<4 x i32*> %ptrs) {
+ %res = call <4 x i32> @test12_1(<4 x i32*> %ptrs)
+ ret <4 x i32> %res
+}
+
+; ATTRIBUTOR: define i32 @volatile_load(
+; ATTRIBUTOR-NOT: readonly
+; ATTRIBUTOR: ret
+define i32 @volatile_load(i32* %p) {
+ %load = load volatile i32, i32* %p
+ ret i32 %load
+}
+
+declare void @escape_readnone_ptr(i8** %addr, i8* readnone %ptr)
+declare void @escape_readonly_ptr(i8** %addr, i8* readonly %ptr)
+
+; The argument pointer %escaped_then_written cannot be marked readnone/only even
+; though the only direct use, in @escape_readnone_ptr/@escape_readonly_ptr,
+; is marked as readnone/only. However, the functions can write the pointer into
+; %addr, causing the store to write to %escaped_then_written.
+;
+;
+; ATTRIBUTOR: define void @unsound_readnone(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
+; ATTRIBUTOR: define void @unsound_readonly(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
+define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) {
+ %addr = alloca i8*
+ call void @escape_readnone_ptr(i8** %addr, i8* %escaped_then_written)
+ %addr.ld = load i8*, i8** %addr
+ store i8 0, i8* %addr.ld
+ ret void
+}
+
+define void @unsound_readonly(i8* %ignored, i8* %escaped_then_written) {
+ %addr = alloca i8*
+ call void @escape_readonly_ptr(i8** %addr, i8* %escaped_then_written)
+ %addr.ld = load i8*, i8** %addr
+ store i8 0, i8* %addr.ld
+ ret void
+}
diff --git a/llvm/test/Transforms/Attributor/returned.ll b/llvm/test/Transforms/Attributor/returned.ll
new file mode 100644
index 000000000000..85ab69a0d99a
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/returned.ll
@@ -0,0 +1,812 @@
+; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
+; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -functionattrs -S < %s | FileCheck %s --check-prefix=BOTH
+;
+; Copied from Transforms/FunctoinAttrs/read_write_returned_arguments_scc.ll
+;
+; Test cases specifically designed for the "returned" argument attribute.
+; We use FIXME's to indicate problems and missing attributes.
+;
+
+; TEST SCC test returning an integer value argument
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define i32 @sink_r0(i32 returned %r)
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
+;
+;
+; ATTRIBUTOR: define i32 @sink_r0(i32 returned %r)
+; ATTRIBUTOR: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
+; ATTRIBUTOR: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
+; ATTRIBUTOR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
+;
+; int scc_r1(int a, int b, int r);
+; int scc_r2(int a, int b, int r);
+;
+; __attribute__((noinline)) int sink_r0(int r) {
+; return r;
+; }
+;
+; __attribute__((noinline)) int scc_r1(int a, int r, int b) {
+; return scc_r2(r, a, sink_r0(r));
+; }
+;
+; __attribute__((noinline)) int scc_r2(int a, int b, int r) {
+; if (a > b)
+; return scc_r2(b, a, sink_r0(r));
+; if (a < b)
+; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r2(a, b, r)), scc_r1(a, b, r));
+; return a == b ? r : scc_r2(a, b, r);
+; }
+; __attribute__((noinline)) int scc_rX(int a, int b, int r) {
+; if (a > b)
+; return scc_r2(b, a, sink_r0(r));
+; if (a < b) // V Diff to scc_r2
+; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r1(a, b, r)), scc_r1(a, b, r));
+; return a == b ? r : scc_r2(a, b, r);
+; }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @sink_r0(i32 %r) #0 {
+entry:
+ ret i32 %r
+}
+
+define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 {
+entry:
+ %call = call i32 @sink_r0(i32 %r)
+ %call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call)
+ ret i32 %call1
+}
+
+define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 {
+entry:
+ %cmp = icmp sgt i32 %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %call = call i32 @sink_r0(i32 %r)
+ %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
+ br label %return
+
+if.end: ; preds = %entry
+ %cmp2 = icmp slt i32 %a, %b
+ br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3: ; preds = %if.end
+ %call4 = call i32 @sink_r0(i32 %b)
+ %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+ %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
+ %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
+ %call8 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+ %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
+ %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+ %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
+ br label %return
+
+if.end12: ; preds = %if.end
+ %cmp13 = icmp eq i32 %a, %b
+ br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true: ; preds = %if.end12
+ br label %cond.end
+
+cond.false: ; preds = %if.end12
+ %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+ br label %cond.end
+
+cond.end: ; preds = %cond.false, %cond.true
+ %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
+ br label %return
+
+return: ; preds = %cond.end, %if.then3, %if.then
+ %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+ ret i32 %retval.0
+}
+
+define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 {
+entry:
+ %cmp = icmp sgt i32 %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %call = call i32 @sink_r0(i32 %r)
+ %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call)
+ br label %return
+
+if.end: ; preds = %entry
+ %cmp2 = icmp slt i32 %a, %b
+ br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3: ; preds = %if.end
+ %call4 = call i32 @sink_r0(i32 %b)
+ %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+ %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r)
+ %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r)
+ %call8 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+ %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8)
+ %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r)
+ %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10)
+ br label %return
+
+if.end12: ; preds = %if.end
+ %cmp13 = icmp eq i32 %a, %b
+ br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true: ; preds = %if.end12
+ br label %cond.end
+
+cond.false: ; preds = %if.end12
+ %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r)
+ br label %cond.end
+
+cond.end: ; preds = %cond.false, %cond.true
+ %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ]
+ br label %return
+
+return: ; preds = %cond.end, %if.then3, %if.then
+ %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+ ret i32 %retval.0
+}
+
+
+; TEST SCC test returning a pointer value argument
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* nofree readnone returned "no-capture-maybe-returned" %r)
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* nofree readnone %a, double* nofree readnone returned %r, double* nocapture nofree readnone %b)
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* nofree readnone %a, double* nofree readnone %b, double* nofree readnone returned %r)
+;
+; double* ptr_scc_r1(double* a, double* b, double* r);
+; double* ptr_scc_r2(double* a, double* b, double* r);
+;
+; __attribute__((noinline)) double* ptr_sink_r0(double* r) {
+; return r;
+; }
+;
+; __attribute__((noinline)) double* ptr_scc_r1(double* a, double* r, double* b) {
+; return ptr_scc_r2(r, a, ptr_sink_r0(r));
+; }
+;
+; __attribute__((noinline)) double* ptr_scc_r2(double* a, double* b, double* r) {
+; if (a > b)
+; return ptr_scc_r2(b, a, ptr_sink_r0(r));
+; if (a < b)
+; return ptr_scc_r1(ptr_sink_r0(b), ptr_scc_r2(ptr_scc_r1(a, b, r), ptr_scc_r1(a, ptr_scc_r2(r, r, r), r), ptr_scc_r2(a, b, r)), ptr_scc_r1(a, b, r));
+; return a == b ? r : ptr_scc_r2(a, b, r);
+; }
+define double* @ptr_sink_r0(double* %r) #0 {
+entry:
+ ret double* %r
+}
+
+define double* @ptr_scc_r1(double* %a, double* %r, double* %b) #0 {
+entry:
+ %call = call double* @ptr_sink_r0(double* %r)
+ %call1 = call double* @ptr_scc_r2(double* %r, double* %a, double* %call)
+ ret double* %call1
+}
+
+define double* @ptr_scc_r2(double* %a, double* %b, double* %r) #0 {
+entry:
+ %cmp = icmp ugt double* %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %call = call double* @ptr_sink_r0(double* %r)
+ %call1 = call double* @ptr_scc_r2(double* %b, double* %a, double* %call)
+ br label %return
+
+if.end: ; preds = %entry
+ %cmp2 = icmp ult double* %a, %b
+ br i1 %cmp2, label %if.then3, label %if.end12
+
+if.then3: ; preds = %if.end
+ %call4 = call double* @ptr_sink_r0(double* %b)
+ %call5 = call double* @ptr_scc_r1(double* %a, double* %b, double* %r)
+ %call6 = call double* @ptr_scc_r2(double* %r, double* %r, double* %r)
+ %call7 = call double* @ptr_scc_r1(double* %a, double* %call6, double* %r)
+ %call8 = call double* @ptr_scc_r2(double* %a, double* %b, double* %r)
+ %call9 = call double* @ptr_scc_r2(double* %call5, double* %call7, double* %call8)
+ %call10 = call double* @ptr_scc_r1(double* %a, double* %b, double* %r)
+ %call11 = call double* @ptr_scc_r1(double* %call4, double* %call9, double* %call10)
+ br label %return
+
+if.end12: ; preds = %if.end
+ %cmp13 = icmp eq double* %a, %b
+ br i1 %cmp13, label %cond.true, label %cond.false
+
+cond.true: ; preds = %if.end12
+ br label %cond.end
+
+cond.false: ; preds = %if.end12
+ %call14 = call double* @ptr_scc_r2(double* %a, double* %b, double* %r)
+ br label %cond.end
+
+cond.end: ; preds = %cond.false, %cond.true
+ %cond = phi double* [ %r, %cond.true ], [ %call14, %cond.false ]
+ br label %return
+
+return: ; preds = %cond.end, %if.then3, %if.then
+ %retval.0 = phi double* [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ]
+ ret double* %retval.0
+}
+
+
+; TEST a no-return singleton SCC
+;
+; int* rt0(int *a) {
+; return *a ? a : rt0(a);
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable
+; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a)
+define i32* @rt0(i32* %a) #0 {
+entry:
+ %v = load i32, i32* %a, align 4
+ %tobool = icmp ne i32 %v, 0
+ %call = call i32* @rt0(i32* %a)
+ %sel = select i1 %tobool, i32* %a, i32* %call
+ ret i32* %sel
+}
+
+; TEST a no-return singleton SCC
+;
+; int* rt1(int *a) {
+; return *a ? undef : rt1(a);
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable
+; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a)
+define i32* @rt1(i32* %a) #0 {
+entry:
+ %v = load i32, i32* %a, align 4
+ %tobool = icmp ne i32 %v, 0
+ %call = call i32* @rt1(i32* %a)
+ %sel = select i1 %tobool, i32* undef, i32* %call
+ ret i32* %sel
+}
+
+; TEST another SCC test
+;
+; BOTH: define i32* @rt2_helper(i32* nofree readnone returned %a)
+; BOTH: define i32* @rt2(i32* nofree readnone %a, i32* nofree readnone "no-capture-maybe-returned" %b)
+define i32* @rt2_helper(i32* %a) #0 {
+entry:
+ %call = call i32* @rt2(i32* %a, i32* %a)
+ ret i32* %call
+}
+
+define i32* @rt2(i32* %a, i32 *%b) #0 {
+entry:
+ %cmp = icmp eq i32* %a, null
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %call = call i32* @rt2_helper(i32* %a)
+ br label %if.end
+
+if.end:
+ %sel = phi i32* [ %b, %entry], [%call, %if.then]
+ ret i32* %sel
+}
+
+; TEST another SCC test
+;
+; BOTH: define i32* @rt3_helper(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
+; BOTH: define i32* @rt3(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
+define i32* @rt3_helper(i32* %a, i32* %b) #0 {
+entry:
+ %call = call i32* @rt3(i32* %a, i32* %b)
+ ret i32* %call
+}
+
+define i32* @rt3(i32* %a, i32 *%b) #0 {
+entry:
+ %cmp = icmp eq i32* %a, null
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %call = call i32* @rt3_helper(i32* %a, i32* %b)
+ br label %if.end
+
+if.end:
+ %sel = phi i32* [ %b, %entry], [%call, %if.then]
+ ret i32* %sel
+}
+
+; TEST address taken function with call to an external functions
+;
+; void unknown_fn(void *);
+;
+; int* calls_unknown_fn(int *r) {
+; unknown_fn(&calls_unknown_fn);
+; return r;
+; }
+;
+; BOTH: declare void @unknown_fn(i32* (i32*)*)
+;
+; BOTH: Function Attrs: noinline nounwind uwtable
+; BOTH-NEXT: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
+; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
+declare void @unknown_fn(i32* (i32*)*) #0
+
+define i32* @calls_unknown_fn(i32* %r) #0 {
+ tail call void @unknown_fn(i32* (i32*)* nonnull @calls_unknown_fn)
+ ret i32* %r
+}
+
+
+; TEST call to a function that might be redifined at link time
+;
+; int *maybe_redefined_fn(int *r) {
+; return r;
+; }
+;
+; int *calls_maybe_redefined_fn(int *r) {
+; maybe_redefined_fn(r);
+; return r;
+; }
+;
+; Verify the maybe-redefined function is not annotated:
+;
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
+;
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn(i32* returned %r)
+;
+; BOTH: Function Attrs: noinline nounwind uwtable
+; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
+;
+; BOTH: Function Attrs: noinline nounwind uwtable
+; BOTH-NEXT: define i32* @calls_maybe_redefined_fn(i32* returned %r)
+define linkonce_odr i32* @maybe_redefined_fn(i32* %r) #0 {
+entry:
+ ret i32* %r
+}
+
+define i32* @calls_maybe_redefined_fn(i32* %r) #0 {
+entry:
+ %call = call i32* @maybe_redefined_fn(i32* %r)
+ ret i32* %r
+}
+
+; TEST return call to a function that might be redifined at link time
+;
+; int *maybe_redefined_fn2(int *r) {
+; return r;
+; }
+;
+; int *calls_maybe_redefined_fn2(int *r) {
+; return maybe_redefined_fn2(r);
+; }
+;
+; Verify the maybe-redefined function is not annotated:
+;
+; BOTH: Function Attrs: noinline nounwind uwtable
+; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn2(i32* %r)
+; BOTH: Function Attrs: noinline nounwind uwtable
+; BOTH-NEXT: define i32* @calls_maybe_redefined_fn2(i32* %r)
+;
+; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn2(i32* %r)
+define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) #0 {
+entry:
+ ret i32* %r
+}
+
+define i32* @calls_maybe_redefined_fn2(i32* %r) #0 {
+entry:
+ %call = call i32* @maybe_redefined_fn2(i32* %r)
+ ret i32* %call
+}
+
+
+; TEST returned argument goes through select and phi
+;
+; double select_and_phi(double b) {
+; double x = b;
+; if (b > 0)
+; x = b;
+; return b == 0? b : x;
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double @select_and_phi(double returned %b)
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
+define double @select_and_phi(double %b) #0 {
+entry:
+ %cmp = fcmp ogt double %b, 0.000000e+00
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ %phi = phi double [ %b, %if.then ], [ %b, %entry ]
+ %cmp1 = fcmp oeq double %b, 0.000000e+00
+ %sel = select i1 %cmp1, double %b, double %phi
+ ret double %sel
+}
+
+
+; TEST returned argument goes through recursion, select, and phi
+;
+; double recursion_select_and_phi(int a, double b) {
+; double x = b;
+; if (a-- > 0)
+; x = recursion_select_and_phi(a, b);
+; return b == 0? b : x;
+; }
+;
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
+define double @recursion_select_and_phi(i32 %a, double %b) #0 {
+entry:
+ %dec = add nsw i32 %a, -1
+ %cmp = icmp sgt i32 %a, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %call = call double @recursion_select_and_phi(i32 %dec, double %b)
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ %phi = phi double [ %call, %if.then ], [ %b, %entry ]
+ %cmp1 = fcmp oeq double %b, 0.000000e+00
+ %sel = select i1 %cmp1, double %b, double %phi
+ ret double %sel
+}
+
+
+; TEST returned argument goes through bitcasts
+;
+; double* bitcast(int* b) {
+; return (double*)b;
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
+define double* @bitcast(i32* %b) #0 {
+entry:
+ %bc0 = bitcast i32* %b to double*
+ ret double* %bc0
+}
+
+
+; TEST returned argument goes through select and phi interleaved with bitcasts
+;
+; double* bitcasts_select_and_phi(int* b) {
+; double* x = b;
+; if (b == 0)
+; x = b;
+; return b != 0 ? b : x;
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
+define double* @bitcasts_select_and_phi(i32* %b) #0 {
+entry:
+ %bc0 = bitcast i32* %b to double*
+ %cmp = icmp eq double* %bc0, null
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %bc1 = bitcast i32* %b to double*
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ %phi = phi double* [ %bc1, %if.then ], [ %bc0, %entry ]
+ %bc2 = bitcast double* %phi to i8*
+ %bc3 = bitcast i32* %b to i8*
+ %cmp2 = icmp ne double* %bc0, null
+ %sel = select i1 %cmp2, i8* %bc2, i8* %bc3
+ %bc4 = bitcast i8* %sel to double*
+ ret double* %bc4
+}
+
+
+; TEST return argument or argument or undef
+;
+; double* ret_arg_arg_undef(int* b) {
+; if (b == 0)
+; return (double*)b;
+; if (b == 0)
+; return (double*)b;
+; /* return undef */
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
+define double* @ret_arg_arg_undef(i32* %b) #0 {
+entry:
+ %bc0 = bitcast i32* %b to double*
+ %cmp = icmp eq double* %bc0, null
+ br i1 %cmp, label %ret_arg0, label %if.end
+
+ret_arg0:
+ %bc1 = bitcast i32* %b to double*
+ ret double* %bc1
+
+if.end:
+ br i1 %cmp, label %ret_arg1, label %ret_undef
+
+ret_arg1:
+ ret double* %bc0
+
+ret_undef:
+ ret double *undef
+}
+
+
+; TEST return undef or argument or argument
+;
+; double* ret_undef_arg_arg(int* b) {
+; if (b == 0)
+; return (double*)b;
+; if (b == 0)
+; return (double*)b;
+; /* return undef */
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
+;
+;
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
+define double* @ret_undef_arg_arg(i32* %b) #0 {
+entry:
+ %bc0 = bitcast i32* %b to double*
+ %cmp = icmp eq double* %bc0, null
+ br i1 %cmp, label %ret_undef, label %if.end
+
+ret_undef:
+ ret double *undef
+
+if.end:
+ br i1 %cmp, label %ret_arg0, label %ret_arg1
+
+ret_arg0:
+ ret double* %bc0
+
+ret_arg1:
+ %bc1 = bitcast i32* %b to double*
+ ret double* %bc1
+}
+
+
+; TEST return undef or argument or undef
+;
+; double* ret_undef_arg_undef(int* b) {
+; if (b == 0)
+; /* return undef */
+; if (b == 0)
+; return (double*)b;
+; /* return undef */
+; }
+;
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
+; BOTH-NEXT: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
+;
+; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
+define double* @ret_undef_arg_undef(i32* %b) #0 {
+entry:
+ %bc0 = bitcast i32* %b to double*
+ %cmp = icmp eq double* %bc0, null
+ br i1 %cmp, label %ret_undef0, label %if.end
+
+ret_undef0:
+ ret double *undef
+
+if.end:
+ br i1 %cmp, label %ret_arg, label %ret_undef1
+
+ret_arg:
+ ret double* %bc0
+
+ret_undef1:
+ ret double *undef
+}
+
+; TEST return argument or unknown call result
+;
+; int* ret_arg_or_unknown(int* b) {
+; if (b == 0)
+; return b;
+; return unknown();
+; }
+;
+; Verify we do not assume b is returned
+;
+; ATTRIBUTOR: define i32* @ret_arg_or_unknown(i32* %b)
+; ATTRIBUTOR: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
+; BOTH: define i32* @ret_arg_or_unknown(i32* %b)
+; BOTH: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
+declare i32* @unknown(i32*)
+
+define i32* @ret_arg_or_unknown(i32* %b) #0 {
+entry:
+ %cmp = icmp eq i32* %b, null
+ br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+ ret i32* %b
+
+ret_unknown:
+ %call = call i32* @unknown(i32* %b)
+ ret i32* %call
+}
+
+define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 {
+entry:
+ %cmp = icmp eq i32* %b, null
+ br i1 %cmp, label %ret_arg, label %ret_unknown
+
+ret_arg:
+ br label %r
+
+ret_unknown:
+ %call = call i32* @unknown(i32* %b)
+ br label %r
+
+r:
+ %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ]
+ ret i32* %phi
+}
+
+; TEST inconsistent IR in dead code.
+;
+; ATTRIBUTOR: define i32 @deadblockcall1(i32 returned %A)
+; ATTRIBUTOR: define i32 @deadblockcall2(i32 returned %A)
+; ATTRIBUTOR: define i32 @deadblockphi1(i32 returned %A)
+; ATTRIBUTOR: define i32 @deadblockphi2(i32 returned %A)
+; BOTH: define i32 @deadblockcall1(i32 returned %A)
+; BOTH: define i32 @deadblockcall2(i32 returned %A)
+; BOTH: define i32 @deadblockphi1(i32 returned %A)
+; BOTH: define i32 @deadblockphi2(i32 returned %A)
+define i32 @deadblockcall1(i32 %A) #0 {
+entry:
+ ret i32 %A
+unreachableblock:
+ %B = call i32 @deadblockcall1(i32 %B)
+ ret i32 %B
+}
+
+declare i32 @deadblockcall_helper(i32 returned %A);
+
+define i32 @deadblockcall2(i32 %A) #0 {
+entry:
+ ret i32 %A
+unreachableblock1:
+ %B = call i32 @deadblockcall_helper(i32 %B)
+ ret i32 %B
+unreachableblock2:
+ %C = call i32 @deadblockcall1(i32 %C)
+ ret i32 %C
+}
+
+define i32 @deadblockphi1(i32 %A) #0 {
+entry:
+ br label %r
+unreachableblock1:
+ %B = call i32 @deadblockcall_helper(i32 %B)
+ ret i32 %B
+unreachableblock2:
+ %C = call i32 @deadblockcall1(i32 %C)
+ br label %r
+r:
+ %PHI = phi i32 [%A, %entry], [%C, %unreachableblock2]
+ ret i32 %PHI
+}
+
+define i32 @deadblockphi2(i32 %A) #0 {
+entry:
+ br label %r
+unreachableblock1:
+ %B = call i32 @deadblockcall_helper(i32 %B)
+ br label %unreachableblock3
+unreachableblock2:
+ %C = call i32 @deadblockcall1(i32 %C)
+ br label %unreachableblock3
+unreachableblock3:
+ %PHI1 = phi i32 [%B, %unreachableblock1], [%C, %unreachableblock2]
+ br label %r
+r:
+ %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
+ ret i32 %PHI2
+}
+
+declare void @noreturn() noreturn;
+
+define i32 @deadblockphi3(i32 %A, i1 %c) #0 {
+entry:
+ br i1 %c, label %r, label %unreachablecall
+unreachablecall:
+ call void @noreturn();
+ %B = call i32 @deadblockcall_helper(i32 0)
+ br label %unreachableblock3
+unreachableblock2:
+ %C = call i32 @deadblockcall1(i32 %C)
+ br label %unreachableblock3
+unreachableblock3:
+ %PHI1 = phi i32 [%B, %unreachablecall], [%C, %unreachableblock2]
+ br label %r
+r:
+ %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3]
+ ret i32 %PHI2
+}
+
+define weak_odr i32 @non_exact_0() {
+ ret i32 0
+}
+define weak_odr i32 @non_exact_1(i32 %a) {
+ ret i32 %a
+}
+define weak_odr i32 @non_exact_2(i32 returned %a) {
+ ret i32 %a
+}
+define weak_odr i32* @non_exact_3(i32* align 32 returned %a) {
+ ret i32* %a
+}
+define i32 @exact(i32* %a) {
+ %c0 = call i32 @non_exact_0()
+ %c1 = call i32 @non_exact_1(i32 1)
+ %c2 = call i32 @non_exact_2(i32 2)
+ %c3 = call i32* @non_exact_3(i32* %a)
+; We can use the information of the weak function non_exact_3 because it was
+; given to us and not derived (the alignment of the returned argument).
+; ATTRIBUTOR: %c4 = load i32, i32* %c3, align 32
+ %c4 = load i32, i32* %c3
+; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
+; ATTRIBUTOR: %add1 = add i32 %c0, %c1
+; ATTRIBUTOR: %add2 = add i32 %add1, %c2
+; ATTRIBUTOR: %add3 = add i32 %add2, %c4
+ %add1 = add i32 %c0, %c1
+ %add2 = add i32 %add1, %c2
+ %add3 = add i32 %add2, %c4
+ ret i32 %add3
+}
+
+ at G = external global i8
+define i32* @ret_const() #0 {
+ %bc = bitcast i8* @G to i32*
+ ret i32* %bc
+}
+define i32* @use_const() #0 {
+ %c = call i32* @ret_const()
+ ; ATTRIBUTOR: ret i32* bitcast (i8* @G to i32*)
+ ret i32* %c
+}
+define i32* @dont_use_const() #0 {
+ %c = musttail call i32* @ret_const()
+ ; ATTRIBUTOR: ret i32* %c
+ ret i32* %c
+}
+
+attributes #0 = { noinline nounwind uwtable }
diff --git a/llvm/test/Transforms/FunctionAttrs/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
similarity index 100%
rename from llvm/test/Transforms/FunctionAttrs/value-simplify.ll
rename to llvm/test/Transforms/Attributor/value-simplify.ll
diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll
similarity index 78%
rename from llvm/test/Transforms/FunctionAttrs/willreturn.ll
rename to llvm/test/Transforms/Attributor/willreturn.ll
index 8f7e46837c1e..90fef48b2a90 100644
--- a/llvm/test/Transforms/FunctionAttrs/willreturn.ll
+++ b/llvm/test/Transforms/Attributor/willreturn.ll
@@ -1,4 +1,3 @@
-; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
@@ -9,8 +8,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; TEST 1 (positive case)
-; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
-; FNATTR-NEXT: define void @only_return()
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define void @only_return()
define void @only_return() #0 {
@@ -25,8 +22,6 @@ define void @only_return() #0 {
; return n<=1? n : fib(n-1) + fib(n-2);
; }
-; FNATTR: Function Attrs: noinline nounwind readnone uwtable
-; FNATTR-NEXT: define i32 @fib(i32 %0)
; FIXME: missing willreturn
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr
@@ -56,9 +51,6 @@ define i32 @fib(i32 %0) local_unnamed_addr #0 {
; }
; fact_maybe_not(-1) doesn't stop.
-; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
@@ -93,8 +85,6 @@ define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
; }
; FIXME: missing willreturn
-; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
-; FNATTR-NEXT: define i32 @fact_loop(i32 %0)
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr
define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
@@ -123,9 +113,6 @@ define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
; mutual_recursion1();
; }
-; FNATTR: Function Attrs: noinline nounwind readnone uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @mutual_recursion1(i1 %c)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
@@ -139,9 +126,6 @@ end:
}
-; FNATTR: Function Attrs: noinline nounwind readnone uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @mutual_recursion2(i1 %c)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
@@ -153,15 +137,10 @@ define void @mutual_recursion2(i1 %c) #0 {
; TEST 5 (negative case)
; call exit/abort (has noreturn attribute)
-; FNATTR: Function Attrs: noreturn
-; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noreturn
; ATTRIBUTOR-NEXT: declare void @exit(i32) local_unnamed_add
declare void @exit(i32 %0) local_unnamed_addr noreturn
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @only_exit()
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr
@@ -180,9 +159,6 @@ define void @only_exit() local_unnamed_addr #0 {
; }
; return;
; }
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
@@ -210,14 +186,10 @@ define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_
; TEST 6 (positive case)
; Call intrinsic function
; FIXME: missing willreturn
-; FNATTRS: Function Attrs: noinline readnone speculatable
-; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
declare float @llvm.floor.f32(float)
-; FNATTRS: Function Attrs: noinline nounwind readnone uwtable
-; FNATTRS-NEXT: define void @call_floor(float %a)
; FIXME: missing willreturn
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
@@ -230,17 +202,11 @@ define void @call_floor(float %a) #0 {
; TEST 7 (negative case)
; Call function declaration without willreturn
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: declare void @maybe_noreturn()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: declare void @maybe_noreturn()
declare void @maybe_noreturn() #0
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @call_maybe_noreturn()
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_maybe_noreturn()
@@ -253,14 +219,10 @@ define void @call_maybe_noreturn() #0 {
; TEST 8 (positive case)
; Check propagation.
-; FNATTR: Function Attrs: norecurse willreturn
-; FNATTR-NEXT: declare void @will_return()
; ATTRIBUTOR: Function Attrs: norecurse willreturn
; ATTRIBUTOR-NEXT: declare void @will_return()
declare void @will_return() willreturn norecurse
-; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
-; FNATTR-NEXT: define void @f1()
; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @f1()
define void @f1() #0 {
@@ -268,8 +230,6 @@ define void @f1() #0 {
ret void
}
-; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
-; FNATTR-NEXT: define void @f2()
; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @f2()
define void @f2() #0 {
@@ -281,9 +241,6 @@ define void @f2() #0 {
; TEST 9 (negative case)
; call willreturn function in endless loop.
-; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @call_will_return_but_has_loop()
; ATTRIBUTOR: Function Attrs: noinline norecurse noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop()
@@ -300,14 +257,10 @@ label2:
; TEST 10 (positive case)
; invoke a function with willreturn
-; FNATTR: Function Attrs: noinline uwtable willreturn
-; FNATTR-NEXT: declare i1 @maybe_raise_exception()
; ATTRIBUTOR: Function Attrs: noinline uwtable willreturn
; ATTRIBUTOR-NEXT: declare i1 @maybe_raise_exception()
declare i1 @maybe_raise_exception() #1 willreturn
-; FNATTR: Function Attrs: nounwind
-; FNATTR-NEXT: define void @invoke_test()
; ATTRIBUTOR: Function Attrs: nounwind willreturn
; ATTRIBUTOR-NEXT: define void @invoke_test()
define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 {
@@ -335,8 +288,6 @@ declare i32 @__gxx_personality_v0(...)
; }
; FIXME: missing willreturn
-; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
-; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture nofree readonly %0)
define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
@@ -367,9 +318,6 @@ define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
; }
; return ans;
; }
-; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture nofree readonly %2, i32 %3) local_unnamed_addr
@@ -406,8 +354,6 @@ define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2,
; FIXME: missing willreturn
-; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
-; FNATTR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1)
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture nofree readonly %1) local_unnamed_addr
@@ -437,8 +383,6 @@ define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
; TEST 14 (positive case)
; multiple return
-; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
-; FNATTR-NEXT: define i32 @multiple_return(i32 %a)
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a)
define i32 @multiple_return(i32 %a) #0 {
@@ -455,8 +399,6 @@ f:
; unreachable exit
; 15.1 (positive case)
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NEXT: define void @unreachable_exit_positive1()
; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_positive1()
define void @unreachable_exit_positive1() #0 {
@@ -469,8 +411,6 @@ unreachable_label:
}
; FIXME: missing willreturn
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
@@ -497,9 +437,6 @@ unreachable_label:
;15.2
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @unreachable_exit_negative1()
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1()
@@ -512,9 +449,6 @@ unreachable_label:
unreachable
}
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @unreachable_exit_negative2()
; ATTRIBUTOR: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
@@ -531,15 +465,10 @@ unreachable_label:
unreachable
}
-; FNATTR: Function Attrs: noreturn nounwind
-; FNATTR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
; ATTRIBUTOR: Function Attrs: noreturn nounwind
; ATTRIBUTOR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
declare void @llvm.eh.sjlj.longjmp(i8*)
-; FNATTR: Function Attrs: noinline nounwind uwtable
-; FNATTR-NOT: willreturn
-; FNATTR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #3 {
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
index 5572c0124a07..0adf91cd9aa1 100644
--- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
+++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
@@ -1,6 +1,4 @@
; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
-; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
-; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -functionattrs -S < %s | FileCheck %s --check-prefix=BOTH
;
; Test cases specifically designed for the "returned" argument attribute.
; We use FIXME's to indicate problems and missing attributes.
@@ -8,24 +6,12 @@
; TEST SCC test returning an integer value argument
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define i32 @sink_r0(i32 returned %r)
-; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
-; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
-; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
;
; FNATTR: define i32 @sink_r0(i32 returned %r)
; FNATTR: define i32 @scc_r1(i32 %a, i32 %r, i32 %b)
; FNATTR: define i32 @scc_r2(i32 %a, i32 %b, i32 %r)
; FNATTR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
;
-; ATTRIBUTOR: define i32 @sink_r0(i32 returned %r)
-; ATTRIBUTOR: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
-; ATTRIBUTOR: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
-; ATTRIBUTOR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
;
; int scc_r1(int a, int b, int r);
; int scc_r2(int a, int b, int r);
@@ -163,12 +149,6 @@ return: ; preds = %cond.end, %if.then3
; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b)
; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* nofree readnone returned "no-capture-maybe-returned" %r)
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* nofree readnone %a, double* nofree readnone returned %r, double* nocapture nofree readnone %b)
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* nofree readnone %a, double* nofree readnone %b, double* nofree readnone returned %r)
;
; double* ptr_scc_r1(double* a, double* b, double* r);
; double* ptr_scc_r2(double* a, double* b, double* r);
@@ -253,8 +233,6 @@ return: ; preds = %cond.end, %if.then3
; }
;
; FNATTR: define i32* @rt0(i32* readonly %a)
-; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable
-; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a)
define i32* @rt0(i32* %a) #0 {
entry:
%v = load i32, i32* %a, align 4
@@ -271,8 +249,6 @@ entry:
; }
;
; FNATTR: define noalias i32* @rt1(i32* nocapture readonly %a)
-; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readonly uwtable
-; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %a)
define i32* @rt1(i32* %a) #0 {
entry:
%v = load i32, i32* %a, align 4
@@ -286,8 +262,6 @@ entry:
;
; FNATTR: define i32* @rt2_helper(i32* %a)
; FNATTR: define i32* @rt2(i32* readnone %a, i32* readnone %b)
-; BOTH: define i32* @rt2_helper(i32* nofree readnone returned %a)
-; BOTH: define i32* @rt2(i32* nofree readnone %a, i32* nofree readnone "no-capture-maybe-returned" %b)
define i32* @rt2_helper(i32* %a) #0 {
entry:
%call = call i32* @rt2(i32* %a, i32* %a)
@@ -312,8 +286,6 @@ if.end:
;
; FNATTR: define i32* @rt3_helper(i32* %a, i32* %b)
; FNATTR: define i32* @rt3(i32* readnone %a, i32* readnone %b)
-; BOTH: define i32* @rt3_helper(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
-; BOTH: define i32* @rt3(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
define i32* @rt3_helper(i32* %a, i32* %b) #0 {
entry:
%call = call i32* @rt3(i32* %a, i32* %b)
@@ -343,12 +315,8 @@ if.end:
; return r;
; }
;
-; BOTH: declare void @unknown_fn(i32* (i32*)*)
;
-; BOTH: Function Attrs: noinline nounwind uwtable
-; BOTH-NEXT: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
; FNATTR: define i32* @calls_unknown_fn(i32* readnone returned %r)
-; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* readnone returned "no-capture-maybe-returned" %r)
declare void @unknown_fn(i32* (i32*)*) #0
define i32* @calls_unknown_fn(i32* %r) #0 {
@@ -357,41 +325,6 @@ define i32* @calls_unknown_fn(i32* %r) #0 {
}
-; TEST call to a function that might be redifined at link time
-;
-; int *maybe_redefined_fn(int *r) {
-; return r;
-; }
-;
-; int *calls_maybe_redefined_fn(int *r) {
-; maybe_redefined_fn(r);
-; return r;
-; }
-;
-; Verify the maybe-redefined function is not annotated:
-;
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
-;
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn(i32* returned %r)
-;
-; BOTH: Function Attrs: noinline nounwind uwtable
-; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
-;
-; BOTH: Function Attrs: noinline nounwind uwtable
-; BOTH-NEXT: define i32* @calls_maybe_redefined_fn(i32* returned %r)
-define linkonce_odr i32* @maybe_redefined_fn(i32* %r) #0 {
-entry:
- ret i32* %r
-}
-
-define i32* @calls_maybe_redefined_fn(i32* %r) #0 {
-entry:
- %call = call i32* @maybe_redefined_fn(i32* %r)
- ret i32* %r
-}
-
; TEST return call to a function that might be redifined at link time
;
; int *maybe_redefined_fn2(int *r) {
@@ -404,13 +337,8 @@ entry:
;
; Verify the maybe-redefined function is not annotated:
;
-; BOTH: Function Attrs: noinline nounwind uwtable
-; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn2(i32* %r)
-; BOTH: Function Attrs: noinline nounwind uwtable
-; BOTH-NEXT: define i32* @calls_maybe_redefined_fn2(i32* %r)
;
; FNATTR: define i32* @calls_maybe_redefined_fn2(i32* %r)
-; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn2(i32* %r)
define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) #0 {
entry:
ret i32* %r
@@ -432,12 +360,8 @@ entry:
; return b == 0? b : x;
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double @select_and_phi(double returned %b)
;
; FNATTR: define double @select_and_phi(double %b)
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
define double @select_and_phi(double %b) #0 {
entry:
%cmp = fcmp ogt double %b, 0.000000e+00
@@ -463,13 +387,9 @@ if.end: ; preds = %if.then, %entry
; return b == 0? b : x;
; }
;
-; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
;
; FNATTR: define double @recursion_select_and_phi(i32 %a, double %b)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
define double @recursion_select_and_phi(i32 %a, double %b) #0 {
entry:
%dec = add nsw i32 %a, -1
@@ -494,13 +414,9 @@ if.end: ; preds = %if.then, %entry
; return (double*)b;
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
;
; FNATTR: define double* @bitcast(i32* readnone %b)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
define double* @bitcast(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
@@ -517,13 +433,9 @@ entry:
; return b != 0 ? b : x;
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
;
; FNATTR: define double* @bitcasts_select_and_phi(i32* readnone %b)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
define double* @bitcasts_select_and_phi(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
@@ -555,13 +467,9 @@ if.end: ; preds = %if.then, %entry
; /* return undef */
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
;
; FNATTR: define double* @ret_arg_arg_undef(i32* readnone %b)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
define double* @ret_arg_arg_undef(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
@@ -593,13 +501,9 @@ ret_undef:
; /* return undef */
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
;
; FNATTR: define double* @ret_undef_arg_arg(i32* readnone %b)
;
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
define double* @ret_undef_arg_arg(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
@@ -631,11 +535,8 @@ ret_arg1:
; /* return undef */
; }
;
-; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
-; BOTH-NEXT: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
;
; FNATTR: define double* @ret_undef_arg_undef(i32* readnone %b)
-; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
define double* @ret_undef_arg_undef(i32* %b) #0 {
entry:
%bc0 = bitcast i32* %b to double*
@@ -667,10 +568,6 @@ ret_undef1:
;
; FNATTR: define i32* @ret_arg_or_unknown(i32* %b)
; FNATTR: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
-; ATTRIBUTOR: define i32* @ret_arg_or_unknown(i32* %b)
-; ATTRIBUTOR: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
-; BOTH: define i32* @ret_arg_or_unknown(i32* %b)
-; BOTH: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
declare i32* @unknown(i32*)
define i32* @ret_arg_or_unknown(i32* %b) #0 {
@@ -709,14 +606,6 @@ r:
; FNATTR: define i32 @deadblockcall2(i32 %A)
; FNATTR: define i32 @deadblockphi1(i32 %A)
; FNATTR: define i32 @deadblockphi2(i32 %A)
-; ATTRIBUTOR: define i32 @deadblockcall1(i32 returned %A)
-; ATTRIBUTOR: define i32 @deadblockcall2(i32 returned %A)
-; ATTRIBUTOR: define i32 @deadblockphi1(i32 returned %A)
-; ATTRIBUTOR: define i32 @deadblockphi2(i32 returned %A)
-; BOTH: define i32 @deadblockcall1(i32 returned %A)
-; BOTH: define i32 @deadblockcall2(i32 returned %A)
-; BOTH: define i32 @deadblockphi1(i32 returned %A)
-; BOTH: define i32 @deadblockphi2(i32 returned %A)
define i32 @deadblockcall1(i32 %A) #0 {
entry:
ret i32 %A
@@ -789,51 +678,4 @@ r:
ret i32 %PHI2
}
-define weak_odr i32 @non_exact_0() {
- ret i32 0
-}
-define weak_odr i32 @non_exact_1(i32 %a) {
- ret i32 %a
-}
-define weak_odr i32 @non_exact_2(i32 returned %a) {
- ret i32 %a
-}
-define weak_odr i32* @non_exact_3(i32* align 32 returned %a) {
- ret i32* %a
-}
-define i32 @exact(i32* %a) {
- %c0 = call i32 @non_exact_0()
- %c1 = call i32 @non_exact_1(i32 1)
- %c2 = call i32 @non_exact_2(i32 2)
- %c3 = call i32* @non_exact_3(i32* %a)
-; We can use the information of the weak function non_exact_3 because it was
-; given to us and not derived (the alignment of the returned argument).
-; ATTRIBUTOR: %c4 = load i32, i32* %c3, align 32
- %c4 = load i32, i32* %c3
-; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
-; ATTRIBUTOR: %add1 = add i32 %c0, %c1
-; ATTRIBUTOR: %add2 = add i32 %add1, %c2
-; ATTRIBUTOR: %add3 = add i32 %add2, %c4
- %add1 = add i32 %c0, %c1
- %add2 = add i32 %add1, %c2
- %add3 = add i32 %add2, %c4
- ret i32 %add3
-}
-
- at G = external global i8
-define i32* @ret_const() #0 {
- %bc = bitcast i8* @G to i32*
- ret i32* %bc
-}
-define i32* @use_const() #0 {
- %c = call i32* @ret_const()
- ; ATTRIBUTOR: ret i32* bitcast (i8* @G to i32*)
- ret i32* %c
-}
-define i32* @dont_use_const() #0 {
- %c = musttail call i32* @ret_const()
- ; ATTRIBUTOR: ret i32* %c
- ret i32* %c
-}
-
attributes #0 = { noinline nounwind uwtable }
diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
index a78af1041672..25759cffe13f 100644
--- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -1,18 +1,14 @@
-; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER
-; RUN: opt -passes=function-attrs -S < %s | FileCheck %s --check-prefixes=FNATTR,EITHER
-; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER
-; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,EITHER
+; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefixes=FNATTR
+; RUN: opt -passes=function-attrs -S < %s | FileCheck %s --check-prefixes=FNATTR
@g = global i32* null ; <i32**> [#uses=1]
; FNATTR: define i32* @c1(i32* readnone returned %q)
-; ATTRIBUTOR: define i32* @c1(i32* nofree readnone returned "no-capture-maybe-returned" %q)
define i32* @c1(i32* %q) {
ret i32* %q
}
; FNATTR: define void @c2(i32* %q)
-; ATTRIBUTOR: define void @c2(i32* nofree writeonly %q)
; It would also be acceptable to mark %q as readnone. Update @c3 too.
define void @c2(i32* %q) {
store i32* %q, i32** @g
@@ -20,14 +16,12 @@ define void @c2(i32* %q) {
}
; FNATTR: define void @c3(i32* %q)
-; ATTRIBUTOR: define void @c3(i32* nofree writeonly %q)
define void @c3(i32* %q) {
call void @c2(i32* %q)
ret void
}
; FNATTR: define i1 @c4(i32* %q, i32 %bitno)
-; ATTRIBUTOR: define i1 @c4(i32* nofree readnone %q, i32 %bitno)
define i1 @c4(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
@@ -41,7 +35,6 @@ l1:
; c4b is c4 but without the escaping part
; FNATTR: define i1 @c4b(i32* %q, i32 %bitno)
-; ATTRIBUTOR: define i1 @c4b(i32* nocapture nofree readnone %q, i32 %bitno)
define i1 @c4b(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
@@ -56,7 +49,6 @@ l1:
@lookup_table = global [2 x i1] [ i1 0, i1 1 ]
; FNATTR: define i1 @c5(i32* %q, i32 %bitno)
-; ATTRIBUTOR: define i1 @c5(i32* nofree readonly %q, i32 %bitno)
define i1 @c5(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
@@ -69,7 +61,7 @@ define i1 @c5(i32* %q, i32 %bitno) {
declare void @throw_if_bit_set(i8*, i8) readonly
-; EITHER: define i1 @c6(i8* readonly %q, i8 %bit)
+; FNATTR: define i1 @c6(i8* readonly %q, i8 %bit)
define i1 @c6(i8* %q, i8 %bit) personality i32 (...)* @__gxx_personality_v0 {
invoke void @throw_if_bit_set(i8* %q, i8 %bit)
to label %ret0 unwind label %ret1
@@ -92,7 +84,6 @@ define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
}
; FNATTR: define i1 @c7(i32* readonly %q, i32 %bitno)
-; ATTRIBUTOR: define i1 @c7(i32* nofree readonly %q, i32 %bitno)
define i1 @c7(i32* %q, i32 %bitno) {
%ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
%val = load i1, i1* %ptr
@@ -101,7 +92,6 @@ define i1 @c7(i32* %q, i32 %bitno) {
; FNATTR: define i32 @nc1(i32* %q, i32* nocapture %p, i1 %b)
-; ATTRIBUTOR: define i32 @nc1(i32* nofree %q, i32* nocapture nofree %p, i1 %b)
define i32 @nc1(i32* %q, i32* %p, i1 %b) {
e:
br label %l
@@ -117,7 +107,6 @@ l:
}
; FNATTR: define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* nocapture %p, i1 %b)
-; ATTRIBUTOR: define i32 @nc1_addrspace(i32* nofree %q, i32 addrspace(1)* nocapture nofree %p, i1 %b)
define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) {
e:
br label %l
@@ -133,7 +122,6 @@ l:
}
; FNATTR: define void @nc2(i32* nocapture %p, i32* %q)
-; ATTRIBUTOR: define void @nc2(i32* nocapture nofree %p, i32* nofree %q)
define void @nc2(i32* %p, i32* %q) {
%1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
ret void
@@ -141,21 +129,19 @@ define void @nc2(i32* %p, i32* %q) {
; FNATTR: define void @nc3(void ()* nocapture %p)
-; ATTRIBUTOR: define void @nc3(void ()* nocapture nofree nonnull %p)
define void @nc3(void ()* %p) {
call void %p()
ret void
}
declare void @external(i8*) readonly nounwind
-; EITHER: define void @nc4(i8* nocapture readonly %p)
+; FNATTR: define void @nc4(i8* nocapture readonly %p)
define void @nc4(i8* %p) {
call void @external(i8* %p)
ret void
}
; FNATTR: define void @nc5(void (i8*)* nocapture %f, i8* nocapture %p)
-; ATTRIBUTOR: define void @nc5(void (i8*)* nocapture nofree nonnull %f, i8* nocapture %p)
define void @nc5(void (i8*)* %f, i8* %p) {
call void %f(i8* %p) readonly nounwind
call void %f(i8* nocapture %p)
@@ -163,7 +149,6 @@ define void @nc5(void (i8*)* %f, i8* %p) {
}
; FNATTR: define void @test1_1(i8* nocapture readnone %x1_1, i8* %y1_1, i1 %c)
-; ATTRIBUTOR: define void @test1_1(i8* nocapture nofree readnone %x1_1, i8* nocapture nofree readnone %y1_1, i1 %c)
; It would be acceptable to add readnone to %y1_1 and %y1_2.
define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c)
@@ -172,7 +157,6 @@ define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
}
; FNATTR: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2, i1 %c)
-; ATTRIBUTOR: define i8* @test1_2(i8* nocapture nofree readnone %x1_2, i8* nofree readnone returned "no-capture-maybe-returned" %y1_2, i1 %c)
define i8* @test1_2(i8* %x1_2, i8* %y1_2, i1 %c) {
br i1 %c, label %t, label %f
t:
@@ -184,7 +168,6 @@ f:
}
; FNATTR: define void @test2(i8* nocapture readnone %x2)
-; ATTRIBUTOR: define void @test2(i8* nocapture nofree readnone %x2)
define void @test2(i8* %x2) {
call void @test2(i8* %x2)
store i32* null, i32** @g
@@ -192,7 +175,6 @@ define void @test2(i8* %x2) {
}
; FNATTR: define void @test3(i8* nocapture readnone %x3, i8* nocapture readnone %y3, i8* nocapture readnone %z3)
-; ATTRIBUTOR: define void @test3(i8* nocapture nofree readnone %x3, i8* nocapture nofree readnone %y3, i8* nocapture nofree readnone %z3)
define void @test3(i8* %x3, i8* %y3, i8* %z3) {
call void @test3(i8* %z3, i8* %y3, i8* %x3)
store i32* null, i32** @g
@@ -200,7 +182,6 @@ define void @test3(i8* %x3, i8* %y3, i8* %z3) {
}
; FNATTR: define void @test4_1(i8* %x4_1, i1 %c)
-; ATTRIBUTOR: define void @test4_1(i8* nocapture nofree readnone %x4_1, i1 %c)
define void @test4_1(i8* %x4_1, i1 %c) {
call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1, i1 %c)
store i32* null, i32** @g
@@ -208,7 +189,6 @@ define void @test4_1(i8* %x4_1, i1 %c) {
}
; FNATTR: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2, i1 %c)
-; ATTRIBUTOR: define i8* @test4_2(i8* nocapture nofree readnone %x4_2, i8* nofree readnone returned "no-capture-maybe-returned" %y4_2, i8* nocapture nofree readnone %z4_2, i1 %c)
define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2, i1 %c) {
br i1 %c, label %t, label %f
t:
@@ -221,7 +201,7 @@ f:
declare i8* @test5_1(i8* %x5_1)
-; EITHER: define void @test5_2(i8* %x5_2)
+; FNATTR: define void @test5_2(i8* %x5_2)
define void @test5_2(i8* %x5_2) {
call i8* @test5_1(i8* %x5_2)
store i32* null, i32** @g
@@ -230,7 +210,7 @@ define void @test5_2(i8* %x5_2) {
declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...)
-; EITHER: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
+; FNATTR: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) {
call void (i8*, i8*, ...) @test6_1(i8* %x6_2, i8* %y6_2, i8* %z6_2)
store i32* null, i32** @g
@@ -238,28 +218,24 @@ define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) {
}
; FNATTR: define void @test_cmpxchg(i32* nocapture %p)
-; ATTRIBUTOR: define void @test_cmpxchg(i32* nocapture nofree nonnull dereferenceable(4) %p)
define void @test_cmpxchg(i32* %p) {
cmpxchg i32* %p, i32 0, i32 1 acquire monotonic
ret void
}
; FNATTR: define void @test_cmpxchg_ptr(i32** nocapture %p, i32* %q)
-; ATTRIBUTOR: define void @test_cmpxchg_ptr(i32** nocapture nofree nonnull dereferenceable(8) %p, i32* nofree %q)
define void @test_cmpxchg_ptr(i32** %p, i32* %q) {
cmpxchg i32** %p, i32* null, i32* %q acquire monotonic
ret void
}
; FNATTR: define void @test_atomicrmw(i32* nocapture %p)
-; ATTRIBUTOR: define void @test_atomicrmw(i32* nocapture nofree nonnull dereferenceable(4) %p)
define void @test_atomicrmw(i32* %p) {
atomicrmw add i32* %p, i32 1 seq_cst
ret void
}
; FNATTR: define void @test_volatile(i32* %x)
-; ATTRIBUTOR: define void @test_volatile(i32* nofree align 4 %x)
define void @test_volatile(i32* %x) {
entry:
%gep = getelementptr i32, i32* %x, i64 1
@@ -267,7 +243,7 @@ entry:
ret void
}
-; EITHER: nocaptureLaunder(i8* nocapture %p)
+; FNATTR: nocaptureLaunder(i8* nocapture %p)
define void @nocaptureLaunder(i8* %p) {
entry:
%b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
@@ -276,7 +252,7 @@ entry:
}
@g2 = global i8* null
-; EITHER: define void @captureLaunder(i8* %p)
+; FNATTR: define void @captureLaunder(i8* %p)
define void @captureLaunder(i8* %p) {
%b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
store i8* %b, i8** @g2
@@ -284,7 +260,6 @@ define void @captureLaunder(i8* %p) {
}
; FNATTR: @nocaptureStrip(i8* nocapture %p)
-; ATTRIBUTOR: @nocaptureStrip(i8* nocapture writeonly %p)
define void @nocaptureStrip(i8* %p) {
entry:
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
@@ -294,7 +269,6 @@ entry:
@g3 = global i8* null
; FNATTR: define void @captureStrip(i8* %p)
-; ATTRIBUTOR: define void @captureStrip(i8* writeonly %p)
define void @captureStrip(i8* %p) {
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
store i8* %b, i8** @g3
@@ -302,21 +276,18 @@ define void @captureStrip(i8* %p) {
}
; FNATTR: define i1 @captureICmp(i32* readnone %x)
-; ATTRIBUTOR: define i1 @captureICmp(i32* nofree readnone %x)
define i1 @captureICmp(i32* %x) {
%1 = icmp eq i32* %x, null
ret i1 %1
}
; FNATTR: define i1 @captureICmpRev(i32* readnone %x)
-; ATTRIBUTOR: define i1 @captureICmpRev(i32* nofree readnone %x)
define i1 @captureICmpRev(i32* %x) {
%1 = icmp eq i32* null, %x
ret i1 %1
}
; FNATTR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x)
-; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture nofree nonnull readnone %x)
define i1 @nocaptureInboundsGEPICmp(i32* %x) {
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
@@ -325,7 +296,6 @@ define i1 @nocaptureInboundsGEPICmp(i32* %x) {
}
; FNATTR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture readnone %x)
-; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture nofree nonnull readnone %x)
define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
@@ -334,7 +304,6 @@ define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
}
; FNATTR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x)
-; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture nofree readnone dereferenceable_or_null(4) %x)
define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) {
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1, null
@@ -342,36 +311,11 @@ define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x
}
; FNATTR: define i1 @captureDereferenceableOrNullICmp(i32* readnone dereferenceable_or_null(4) %x)
-; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* nofree readnone dereferenceable_or_null(4) %x)
define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1, null
ret i1 %2
}
-declare void @unknown(i8*)
-define void @test_callsite() {
-entry:
-; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm.
-; ATTRIBUTOR: call void @unknown(i8* noalias null)
- call void @unknown(i8* null)
- ret void
-}
-
-declare i8* @unknownpi8pi8(i8*,i8* returned)
-define i8* @test_returned1(i8* %A, i8* returned %B) nounwind readonly {
-; ATTRIBUTOR: define i8* @test_returned1(i8* nocapture readonly %A, i8* readonly returned %B)
-entry:
- %p = call i8* @unknownpi8pi8(i8* %A, i8* %B)
- ret i8* %p
-}
-
-define i8* @test_returned2(i8* %A, i8* %B) {
-; ATTRIBUTOR: define i8* @test_returned2(i8* nocapture readonly %A, i8* readonly returned %B)
-entry:
- %p = call i8* @unknownpi8pi8(i8* %A, i8* %B) nounwind readonly
- ret i8* %p
-}
-
declare i8* @llvm.launder.invariant.group.p0i8(i8*)
declare i8* @llvm.strip.invariant.group.p0i8(i8*)
diff --git a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
index 1c007ee11b41..8ac037e5cd8d 100644
--- a/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll
@@ -1,5 +1,4 @@
; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s --check-prefix=FNATTR
-; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -15,8 +14,6 @@ declare void @_ZdaPv(i8*) local_unnamed_addr #2
; TEST 1 (positive case)
; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
; FNATTR-NEXT: define void @only_return()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @only_return()
define void @only_return() #0 {
ret void
}
@@ -30,9 +27,6 @@ define void @only_return() #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr #1
define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
tail call void @free(i8* %0) #1
ret void
@@ -52,9 +46,6 @@ define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT :define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
tail call void @free_in_scc2(i8* %0) #1
ret void
@@ -63,9 +54,6 @@ define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
%cmp = icmp eq i8* %0, null
br i1 %cmp, label %rec, label %call
@@ -92,8 +80,6 @@ end:
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion1()
-; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
define void @mutual_recursion1() #0 {
call void @mutual_recursion2()
ret void
@@ -101,8 +87,6 @@ define void @mutual_recursion1() #0 {
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @mutual_recursion2()
-; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
define void @mutual_recursion2() #0 {
call void @mutual_recursion1()
ret void
@@ -117,9 +101,6 @@ define void @mutual_recursion2() #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #1
define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
%2 = icmp eq i8* %0, null
br i1 %2, label %4, label %3
@@ -137,9 +118,6 @@ define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
; Call realloc
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
%ret = tail call i8* @realloc(i8* %0, i64 %1) #2
ret i8* %ret
@@ -152,14 +130,10 @@ define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0
; FNATTR: Function Attrs: nofree noinline nounwind readnone uwtable
; FNATTR-NEXT: declare void @nofree_function()
-; ATTRIBUTOR: Function Attrs: nofree noinline nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: declare void @nofree_function()
declare void @nofree_function() nofree readnone #0
; FNATTR: Function Attrs: noinline nounwind readnone uwtable
; FNATTR-NEXT: define void @call_nofree_function()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @call_nofree_function()
define void @call_nofree_function() #0 {
tail call void @nofree_function()
ret void
@@ -169,16 +143,11 @@ define void @call_nofree_function() #0 {
; Call function declaration without "nofree"
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NEXT: declare void @maybe_free()
declare void @maybe_free() #0
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR: define void @call_maybe_free()
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT: define void @call_maybe_free()
define void @call_maybe_free() #0 {
tail call void @maybe_free()
ret void
@@ -190,9 +159,6 @@ define void @call_maybe_free() #0 {
; FNATTR: Function Attrs: noinline nounwind uwtable
; FNATTR-NEXT: define void @call_both()
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
-; ATTRIBUTOR-NOT: nofree
-; ATTRIBUTOR-NEXT: define void @call_both()
define void @call_both() #0 {
tail call void @maybe_free()
tail call void @nofree_function()
@@ -204,15 +170,11 @@ define void @call_both() #0 {
; Call intrinsic function
; FNATTRS: Function Attrs: noinline readnone speculatable
; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
-; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
-; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
declare float @llvm.floor.f32(float)
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @call_floor(float %a)
; FIXME: missing nofree
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
define void @call_floor(float %a) #0 {
tail call float @llvm.floor.f32(float %a)
@@ -224,8 +186,6 @@ define void @call_floor(float %a) #0 {
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @f1()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @f1()
define void @f1() #0 {
tail call void @nofree_function()
ret void
@@ -233,40 +193,11 @@ define void @f1() #0 {
; FNATTRS: Function Attrs: noinline nounwind uwtable
; FNATTRS-NEXT: define void @f2()
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
-; ATTRIBUTOR-NEXT: define void @f2()
define void @f2() #0 {
tail call void @f1()
ret void
}
-; TEST 12 NoFree argument - positive.
-; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %a)
-define double @test12(double* nocapture readonly %a) {
-entry:
- %0 = load double, double* %a, align 8
- %call = tail call double @cos(double %0) #2
- ret double %call
-}
-
-declare double @cos(double) nobuiltin nounwind nofree
-
-; FIXME: %a should be nofree.
-; TEST 13 NoFree argument - positive.
-; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly align 8 dereferenceable(8) %a)
-define noalias i32* @test13(i64* nocapture readonly %a) {
-entry:
- %0 = load i64, i64* %a, align 8
- %call = tail call noalias i8* @malloc(i64 %0) #2
- %1 = bitcast i8* %call to i32*
- ret i32* %1
-}
-
-; ATTRIBUTOR: define void @test14(i8* nocapture %0, i8* nocapture nofree readnone %1)
-define void @test14(i8* nocapture %0, i8* nocapture %1) {
- tail call void @free(i8* %0) #1
- ret void
-}
declare noalias i8* @malloc(i64)
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index 42923cee7708..128a2bdbe50c 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -1,8 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=BOTH,FNATTR,OLD
-; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=BOTH,FNATTR,OLD
-; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=BOTH,OLD,ATTRIBUTOR,ATTRIBUTOR_OPM
-; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=BOTH,ATTRIBUTOR,ATTRIBUTOR_NPM
+; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=FNATTR
+; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=FNATTR
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -10,14 +8,14 @@ declare nonnull i8* @ret_nonnull()
; Return a pointer trivially nonnull (call return attribute)
define i8* @test1() {
-; BOTH: define nonnull i8* @test1
+; FNATTR: define nonnull i8* @test1
%ret = call i8* @ret_nonnull()
ret i8* %ret
}
; Return a pointer trivially nonnull (argument attribute)
define i8* @test2(i8* nonnull %p) {
-; BOTH: define nonnull i8* @test2
+; FNATTR: define nonnull i8* @test2
ret i8* %p
}
@@ -25,7 +23,6 @@ define i8* @test2(i8* nonnull %p) {
; can we still mark the other one which is trivially nonnull
define i8* @scc_binder(i1 %c) {
; FNATTR: define i8* @scc_binder
-; ATTRIBUTOR: define noalias i8* @scc_binder
br i1 %c, label %rec, label %end
rec:
call i8* @test3(i1 %c)
@@ -35,7 +32,7 @@ end:
}
define i8* @test3(i1 %c) {
-; BOTH: define nonnull i8* @test3
+; FNATTR: define nonnull i8* @test3
call i8* @scc_binder(i1 %c)
%ret = call i8* @ret_nonnull()
ret i8* %ret
@@ -46,14 +43,12 @@ define i8* @test3(i1 %c) {
; just never return period.)
define i8* @test4_helper() {
; FNATTR: define noalias nonnull i8* @test4_helper
-; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4_helper
%ret = call i8* @test4()
ret i8* %ret
}
define i8* @test4() {
; FNATTR: define noalias nonnull i8* @test4
-; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4
%ret = call i8* @test4_helper()
ret i8* %ret
}
@@ -62,7 +57,6 @@ define i8* @test4() {
; make sure we haven't marked them as nonnull.
define i8* @test5_helper(i1 %c) {
; FNATTR: define noalias i8* @test5_helper
-; ATTRIBUTOR: define noalias i8* @test5_helper
br i1 %c, label %rec, label %end
rec:
%ret = call i8* @test5(i1 %c)
@@ -73,14 +67,11 @@ end:
define i8* @test5(i1 %c) {
; FNATTR: define noalias i8* @test5
-; ATTRIBUTOR: define noalias i8* @test5
%ret = call i8* @test5_helper(i1 %c)
ret i8* %ret
}
; Local analysis, but going through a self recursive phi
-; ATTRIBUTOR: Function Attrs: noreturn
-; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test6a()
define i8* @test6a() {
entry:
%ret = call i8* @ret_nonnull()
@@ -92,7 +83,6 @@ exit:
ret i8* %phi
}
-; ATTRIBUTOR: define nonnull i8* @test6b(i1 %c)
define i8* @test6b(i1 %c) {
entry:
%ret = call i8* @ret_nonnull()
@@ -104,19 +94,19 @@ exit:
ret i8* %phi
}
-; BOTH: define i8* @test7
+; FNATTR: define i8* @test7
define i8* @test7(i8* %a) {
%b = getelementptr inbounds i8, i8* %a, i64 0
ret i8* %b
}
-; BOTH: define nonnull i8* @test8
+; FNATTR: define nonnull i8* @test8
define i8* @test8(i8* %a) {
%b = getelementptr inbounds i8, i8* %a, i64 1
ret i8* %b
}
-; BOTH: define i8* @test9
+; FNATTR: define i8* @test9
define i8* @test9(i8* %a, i64 %n) {
%b = getelementptr inbounds i8, i8* %a, i64 %n
ret i8* %b
@@ -125,7 +115,6 @@ define i8* @test9(i8* %a, i64 %n) {
declare void @llvm.assume(i1)
; FNATTR: define i8* @test10
; FIXME: missing nonnull
-; ATTRIBUTOR: define i8* @test10
define i8* @test10(i8* %a, i64 %n) {
%cmp = icmp ne i64 %n, 0
call void @llvm.assume(i1 %cmp)
@@ -139,7 +128,6 @@ define i8* @test10(i8* %a, i64 %n) {
; }
; FNATTR: define i8* @test11
; FIXME: missing nonnull
-; ATTRIBUTOR: define i8* @test11
define i8* @test11(i8*) local_unnamed_addr {
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@@ -157,8 +145,6 @@ define i8* @test11(i8*) local_unnamed_addr {
; Simple CallSite Test
declare void @test12_helper(i8*)
define void @test12(i8* nonnull %a) {
-; ATTRIBUTOR: define void @test12(i8* nonnull %a)
-; ATTRIBUTOR-NEXT: tail call void @test12_helper(i8* nonnull %a)
tail call void @test12_helper(i8* %a)
ret void
}
@@ -174,7 +160,6 @@ define void @test13_helper() {
ret void
}
define internal void @test13(i8* %a, i8* %b, i8* %c) {
-; ATTRIBUTOR: define internal void @test13(i8* nocapture nofree nonnull readnone %a, i8* nocapture nofree readnone %b, i8* nocapture nofree readnone %c)
ret void
}
@@ -194,7 +179,6 @@ declare nonnull i8* @nonnull()
define internal i32* @f1(i32* %arg) {
; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg)
-; ATTRIBUTOR: define internal nonnull i32* @f1(i32* nofree readonly %arg)
bb:
%tmp = icmp eq i32* %arg, null
@@ -207,14 +191,12 @@ bb1: ; preds = %bb
bb4: ; preds = %bb1
%tmp5 = getelementptr inbounds i32, i32* %arg, i64 1
-; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* nofree nonnull %tmp5)
%tmp5b = tail call i32* @f3(i32* %tmp5)
%tmp5c = getelementptr inbounds i32, i32* %tmp5b, i64 -1
br label %bb9
bb6: ; preds = %bb1
; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg)
-; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree %arg)
%tmp7 = tail call i32* @f2(i32* %arg)
ret i32* %tmp7
@@ -225,28 +207,23 @@ bb9: ; preds = %bb4, %bb
define internal i32* @f2(i32* %arg) {
; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg)
-; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree readonly %arg)
bb:
; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
-; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* nofree %arg)
%tmp = tail call i32* @f1(i32* %arg)
ret i32* %tmp
}
define dso_local noalias i32* @f3(i32* %arg) {
; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg)
-; ATTRIBUTOR: define dso_local noalias nonnull i32* @f3(i32* nofree readonly %arg)
bb:
; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg)
-; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* nofree %arg)
%tmp = call i32* @f1(i32* %arg)
ret i32* %tmp
}
; TEST 15
define void @f15(i8* %arg) {
-; ATTRIBUTOR: tail call void @use1(i8* nonnull dereferenceable(4) %arg)
tail call void @use1(i8* dereferenceable(4) %arg)
ret void
@@ -264,7 +241,6 @@ declare void @fun3(i8*, i8*, i8*) #1
; We can say that %a is nonnull but %b is not.
define void @f16(i8* %a, i8 * %b, i8 %c) {
; FIXME: missing nonnull on %a
-; ATTRIBUTOR: define void @f16(i8* %a, i8* %b, i8 %c)
%cmp = icmp eq i8 %c, 0
br i1 %cmp, label %if.then, label %if.else
if.then:
@@ -282,7 +258,6 @@ if.else:
; fun1(nonnull %a)
; We can say that %a is nonnull
define void @f17(i8* %a, i8 %c) {
-; ATTRIBUTOR: define void @f17(i8* nonnull %a, i8 %c)
%cmp = icmp eq i8 %c, 0
br i1 %cmp, label %if.then, label %if.else
if.then:
@@ -307,7 +282,6 @@ cont:
; fun1(nonnull %a)
define void @f18(i8* %a, i8* %b, i8 %c) {
-; ATTRIBUTOR: define void @f18(i8* nonnull %a, i8* %b, i8 %c)
%cmp1 = icmp eq i8 %c, 0
br i1 %cmp1, label %if.then, label %if.else
if.then:
@@ -334,7 +308,6 @@ cont2:
define void @f19(i8* %a, i8* %b, i8 %c) {
; FIXME: missing nonnull on %b
-; ATTRIBUTOR: define void @f19(i8* %a, i8* %b, i8 %c)
br label %loop.header
loop.header:
%cmp2 = icmp eq i8 %c, 0
@@ -363,11 +336,10 @@ declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantee
; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute.
define void @parent1(i8* %a, i8* %b, i8* %c) {
-; BOTH-LABEL: @parent1(i8* %a, i8* %b, i8* %c)
-; BOTH-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
+; FNATTR-LABEL: @parent1(i8* %a, i8* %b, i8* %c)
+; FNATTR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
; FNATTR-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a)
-; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
-; BOTH-NEXT: ret void
+; FNATTR-NEXT: ret void
call void @use3(i8* %c, i8* %a, i8* %b)
call void @use3nonnull(i8* %b, i8* %c, i8* %a)
ret void
@@ -380,11 +352,8 @@ define void @parent2(i8* %a, i8* %b, i8* %c) {
; FNATTR-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a)
; FNATTR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
-; ATTRIBUTOR-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c)
-; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a)
-; ATTRIBUTOR-NEXT: call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b)
-; BOTH-NEXT: ret void
+; FNATTR-NEXT: ret void
call void @use3nonnull(i8* %b, i8* %c, i8* %a)
call void @use3(i8* %c, i8* %a, i8* %b)
ret void
@@ -397,11 +366,8 @@ define void @parent3(i8* %a, i8* %b, i8* %c) {
; FNATTR-NEXT: call void @use1nonnull(i8* %a)
; FNATTR-NEXT: call void @use3(i8* %c, i8* %b, i8* %a)
-; ATTRIBUTOR-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c)
-; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
-; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %b, i8* nonnull %a)
-; BOTH-NEXT: ret void
+; FNATTR-NEXT: ret void
call void @use1nonnull(i8* %a)
call void @use3(i8* %c, i8* %b, i8* %a)
@@ -416,12 +382,8 @@ define void @parent4(i8* %a, i8* %b, i8* %c) {
; CHECK-NEXT: call void @use2(i8* %a, i8* %c)
; CHECK-NEXT: call void @use1(i8* %b)
-; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
-; ATTRIBUTOR-NEXT: call void @use2nonnull(i8* nonnull %c, i8* nonnull %b)
-; ATTRIBUTOR-NEXT: call void @use2(i8* %a, i8* nonnull %c)
-; ATTRIBUTOR-NEXT: call void @use1(i8* nonnull %b)
-; BOTH: ret void
+; FNATTR: ret void
call void @use2nonnull(i8* %c, i8* %b)
call void @use2(i8* %a, i8* %c)
@@ -434,14 +396,13 @@ define void @parent4(i8* %a, i8* %b, i8* %c) {
; because it would incorrectly propagate the wrong information to its callers.
define void @parent5(i8* %a, i1 %a_is_notnull) {
-; BOTH: @parent5(i8* %a, i1 %a_is_notnull)
-; BOTH-NEXT: br i1 %a_is_notnull, label %t, label %f
-; BOTH: t:
+; FNATTR: @parent5(i8* %a, i1 %a_is_notnull)
+; FNATTR-NEXT: br i1 %a_is_notnull, label %t, label %f
+; FNATTR: t:
; FNATTR-NEXT: call void @use1nonnull(i8* %a)
-; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
-; BOTH-NEXT: ret void
-; BOTH: f:
-; BOTH-NEXT: ret void
+; FNATTR-NEXT: ret void
+; FNATTR: f:
+; FNATTR-NEXT: ret void
br i1 %a_is_notnull, label %t, label %f
t:
@@ -456,11 +417,9 @@ f:
define i8 @parent6(i8* %a, i8* %b) {
; FNATTR-LABEL: @parent6(i8* nonnull %a, i8* %b)
-; ATTRIBUTOR-LABEL: @parent6(i8* nonnull %a, i8* %b)
-; BOTH-NEXT: [[C:%.*]] = load volatile i8, i8* %b
+; FNATTR-NEXT: [[C:%.*]] = load volatile i8, i8* %b
; FNATTR-NEXT: call void @use1nonnull(i8* %a)
-; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
-; BOTH-NEXT: ret i8 [[C]]
+; FNATTR-NEXT: ret i8 [[C]]
%c = load volatile i8, i8* %b
call void @use1nonnull(i8* %a)
@@ -475,11 +434,8 @@ define i8 @parent7(i8* %a) {
; FNATTR-NEXT: call void @use1nonnull(i8* %a)
-; ATTRIBUTOR-LABEL: @parent7(i8* nonnull %a)
-; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* nonnull %a)
-; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a)
-; BOTH-NEXT: ret i8 [[RET]]
+; FNATTR-NEXT: ret i8 [[RET]]
%ret = call i8 @use1safecall(i8* %a)
call void @use1nonnull(i8* %a)
@@ -492,18 +448,16 @@ declare i32 @esfp(...)
define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){
; FNATTR-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b)
-; ATTRIBUTOR-LABEL: @parent8(i8* nonnull %a, i8* nocapture nofree readnone %bogus1, i8* nonnull %b)
-; BOTH-NEXT: entry:
+; FNATTR-NEXT: entry:
; FNATTR-NEXT: invoke void @use2nonnull(i8* %a, i8* %b)
-; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b)
-; BOTH-NEXT: to label %cont unwind label %exc
-; BOTH: cont:
-; BOTH-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null
-; BOTH-NEXT: ret i1 [[NULL_CHECK]]
-; BOTH: exc:
-; BOTH-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
-; BOTH-NEXT: filter [0 x i8*] zeroinitializer
-; BOTH-NEXT: unreachable
+; FNATTR-NEXT: to label %cont unwind label %exc
+; FNATTR: cont:
+; FNATTR-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null
+; FNATTR-NEXT: ret i1 [[NULL_CHECK]]
+; FNATTR: exc:
+; FNATTR-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
+; FNATTR-NEXT: filter [0 x i8*] zeroinitializer
+; FNATTR-NEXT: unreachable
entry:
invoke void @use2nonnull(i8* %a, i8* %b)
@@ -519,7 +473,7 @@ exc:
unreachable
}
-; BOTH: define nonnull i32* @gep1(
+; FNATTR: define nonnull i32* @gep1(
define i32* @gep1(i32* %p) {
%q = getelementptr inbounds i32, i32* %p, i32 1
ret i32* %q
@@ -527,12 +481,12 @@ define i32* @gep1(i32* %p) {
define i32* @gep1_no_null_opt(i32* %p) #0 {
; Should't be able to derive nonnull based on gep.
-; BOTH: define i32* @gep1_no_null_opt(
+; FNATTR: define i32* @gep1_no_null_opt(
%q = getelementptr inbounds i32, i32* %p, i32 1
ret i32* %q
}
-; BOTH: define i32 addrspace(3)* @gep2(
+; FNATTR: define i32 addrspace(3)* @gep2(
define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
%q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1
ret i32 addrspace(3)* %q
@@ -540,12 +494,11 @@ define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
; FNATTR: define i32 addrspace(3)* @as(i32 addrspace(3)* readnone returned dereferenceable(4) %p)
; FIXME: We should propagate dereferenceable here but *not* nonnull
-; ATTRIBUTOR: define dereferenceable_or_null(4) i32 addrspace(3)* @as(i32 addrspace(3)* nofree readnone returned dereferenceable(4) dereferenceable_or_null(4) %p)
define i32 addrspace(3)* @as(i32 addrspace(3)* dereferenceable(4) %p) {
ret i32 addrspace(3)* %p
}
-; BOTH: define internal nonnull i32* @g2()
+; FNATTR: define internal nonnull i32* @g2()
define internal i32* @g2() {
ret i32* inttoptr (i64 4 to i32*)
}
@@ -556,33 +509,28 @@ define i32* @g1() {
}
declare void @use_i32_ptr(i32*) readnone nounwind
-; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a)
define internal void @called_by_weak(i32* %a) {
call void @use_i32_ptr(i32* %a)
ret void
}
; Check we do not annotate the function interface of this weak function.
-; ATTRIBUTOR: define weak_odr void @weak_caller(i32* nonnull %a)
define weak_odr void @weak_caller(i32* nonnull %a) {
call void @called_by_weak(i32* %a)
ret void
}
; Expect nonnull
-; ATTRIBUTOR: define internal void @control(i32* nocapture nonnull readnone align 16 dereferenceable(8) %a)
define internal void @control(i32* dereferenceable(4) %a) {
call void @use_i32_ptr(i32* %a)
ret void
}
; Avoid nonnull as we do not touch naked functions
-; ATTRIBUTOR: define internal void @naked(i32* dereferenceable(4) %a)
define internal void @naked(i32* dereferenceable(4) %a) naked {
call void @use_i32_ptr(i32* %a)
ret void
}
; Avoid nonnull as we do not touch optnone
-; ATTRIBUTOR: define internal void @optnone(i32* dereferenceable(4) %a)
define internal void @optnone(i32* dereferenceable(4) %a) optnone noinline {
call void @use_i32_ptr(i32* %a)
ret void
@@ -618,20 +566,6 @@ define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) {
; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1
-; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
-; ATTRIBUTOR-NEXT: en:
-; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
-; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
-; ATTRIBUTOR: ex:
-; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
-; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
-; ATTRIBUTOR: hd:
-; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
-; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]])
-; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
-; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
-; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
en:
%tmp3 = icmp eq i32 %b, 0
@@ -667,22 +601,6 @@ define i32 @nonnull_exec_ctx_1b(i32* %a, i32 %b) {
; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b
-; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
-; ATTRIBUTOR-NEXT: en:
-; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
-; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
-; ATTRIBUTOR: ex:
-; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
-; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
-; ATTRIBUTOR: hd:
-; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
-; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]])
-; ATTRIBUTOR-NEXT: br label [[HD2]]
-; ATTRIBUTOR: hd2:
-; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
-; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
-; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
en:
%tmp3 = icmp eq i32 %b, 0
@@ -719,20 +637,6 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) willreturn nounwind {
; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2
-; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
-; ATTRIBUTOR-NEXT: en:
-; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
-; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
-; ATTRIBUTOR: ex:
-; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
-; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
-; ATTRIBUTOR: hd:
-; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
-; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]])
-; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
-; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
-; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
en:
%tmp3 = icmp eq i32 %b, 0
@@ -768,22 +672,6 @@ define i32 @nonnull_exec_ctx_2b(i32* %a, i32 %b) willreturn nounwind {
; FNATTR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
; FNATTR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
-; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b
-; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]])
-; ATTRIBUTOR-NEXT: en:
-; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B:%.*]], 0
-; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
-; ATTRIBUTOR: ex:
-; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A:%.*]])
-; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
-; ATTRIBUTOR: hd:
-; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
-; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]])
-; ATTRIBUTOR-NEXT: br label [[HD2]]
-; ATTRIBUTOR: hd2:
-; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
-; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
-; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
;
en:
%tmp3 = icmp eq i32 %b, 0
@@ -809,21 +697,21 @@ declare void @sink(i32*)
; FIXME: the sink argument should be marked nonnull as in @PR43833_simple.
define void @PR43833(i32* %0, i32 %1) {
-; BOTH-LABEL: @PR43833(
-; BOTH-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1:%.*]], 1
-; BOTH-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
-; BOTH: 4:
-; BOTH-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
-; BOTH-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
-; BOTH-NEXT: br label [[TMP8:%.*]]
-; BOTH: 7:
-; BOTH-NEXT: ret void
-; BOTH: 8:
-; BOTH-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
-; BOTH-NEXT: tail call void @sink(i32* [[TMP6]])
-; BOTH-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
-; BOTH-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
-; BOTH-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
+; FNATTR-LABEL: @PR43833(
+; FNATTR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1:%.*]], 1
+; FNATTR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
+; FNATTR: 4:
+; FNATTR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
+; FNATTR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
+; FNATTR-NEXT: br label [[TMP8:%.*]]
+; FNATTR: 7:
+; FNATTR-NEXT: ret void
+; FNATTR: 8:
+; FNATTR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
+; FNATTR-NEXT: tail call void @sink(i32* [[TMP6]])
+; FNATTR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
+; FNATTR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
+; FNATTR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
;
%3 = icmp sgt i32 %1, 1
br i1 %3, label %4, label %7
@@ -846,37 +734,22 @@ define void @PR43833(i32* %0, i32 %1) {
; Adjusted from PR43833
define void @PR43833_simple(i32* %0, i32 %1) {
-; OLD-LABEL: @PR43833_simple(
-; OLD-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
-; OLD-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
-; OLD: 4:
-; OLD-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
-; OLD-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
-; OLD-NEXT: br label [[TMP8:%.*]]
-; OLD: 7:
-; OLD-NEXT: ret void
-; OLD: 8:
-; OLD-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
-; OLD-NEXT: tail call void @sink(i32* [[TMP6]])
-; OLD-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
-; OLD-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
-; OLD-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
+; FNATTR-LABEL: @PR43833_simple(
+; FNATTR-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
+; FNATTR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
+; FNATTR: 4:
+; FNATTR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
+; FNATTR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
+; FNATTR-NEXT: br label [[TMP8:%.*]]
+; FNATTR: 7:
+; FNATTR-NEXT: ret void
+; FNATTR: 8:
+; FNATTR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
+; FNATTR-NEXT: tail call void @sink(i32* [[TMP6]])
+; FNATTR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
+; FNATTR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
+; FNATTR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
;
-; ATTRIBUTOR_NPM-LABEL: @PR43833_simple(
-; ATTRIBUTOR_NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1:%.*]], 0
-; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
-; ATTRIBUTOR_NPM: 4:
-; ATTRIBUTOR_NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
-; ATTRIBUTOR_NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP5]]
-; ATTRIBUTOR_NPM-NEXT: br label [[TMP8:%.*]]
-; ATTRIBUTOR_NPM: 7:
-; ATTRIBUTOR_NPM-NEXT: ret void
-; ATTRIBUTOR_NPM: 8:
-; ATTRIBUTOR_NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
-; ATTRIBUTOR_NPM-NEXT: tail call void @sink(i32* [[TMP6]])
-; ATTRIBUTOR_NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
-; ATTRIBUTOR_NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
-; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
;
%3 = icmp ne i32 %1, 0
br i1 %3, label %4, label %7
diff --git a/llvm/test/Transforms/FunctionAttrs/norecurse.ll b/llvm/test/Transforms/FunctionAttrs/norecurse.ll
index de5d35d63429..b780bb7b7189 100644
--- a/llvm/test/Transforms/FunctionAttrs/norecurse.ll
+++ b/llvm/test/Transforms/FunctionAttrs/norecurse.ll
@@ -1,88 +1,83 @@
-; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s --check-prefixes=CHECK,BOTH
-; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-functionattrs' -S | FileCheck %s --check-prefixes=CHECK,BOTH
-; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,BOTH
+; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s
+; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs),rpo-functionattrs' -S | FileCheck %s
; CHECK: Function Attrs
; CHECK-SAME: norecurse nounwind readnone
-; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; BOTH-NEXT: define i32 @leaf()
+; CHECK-NEXT: define i32 @leaf()
define i32 @leaf() {
ret i32 1
}
-; BOTH: Function Attrs
-; BOTH-SAME: readnone
-; BOTH-NOT: norecurse
-; BOTH-NEXT: define i32 @self_rec()
+; CHECK: Function Attrs
+; CHECK-SAME: readnone
+; CHECK-NOT: norecurse
+; CHECK-NEXT: define i32 @self_rec()
define i32 @self_rec() {
%a = call i32 @self_rec()
ret i32 4
}
-; BOTH: Function Attrs
-; BOTH-SAME: readnone
-; BOTH-NOT: norecurse
-; BOTH-NEXT: define i32 @indirect_rec()
+; CHECK: Function Attrs
+; CHECK-SAME: readnone
+; CHECK-NOT: norecurse
+; CHECK-NEXT: define i32 @indirect_rec()
define i32 @indirect_rec() {
%a = call i32 @indirect_rec2()
ret i32 %a
}
-; BOTH: Function Attrs
-; BOTH-SAME: readnone
-; BOTH-NOT: norecurse
-; BOTH-NEXT: define i32 @indirect_rec2()
+; CHECK: Function Attrs
+; CHECK-SAME: readnone
+; CHECK-NOT: norecurse
+; CHECK-NEXT: define i32 @indirect_rec2()
define i32 @indirect_rec2() {
%a = call i32 @indirect_rec()
ret i32 %a
}
-; BOTH: Function Attrs
-; BOTH-SAME: readnone
-; BOTH-NOT: norecurse
-; BOTH-NEXT: define i32 @extern()
+; CHECK: Function Attrs
+; CHECK-SAME: readnone
+; CHECK-NOT: norecurse
+; CHECK-NEXT: define i32 @extern()
define i32 @extern() {
%a = call i32 @k()
ret i32 %a
}
-; BOTH: Function Attrs
-; BOTH-NEXT: declare i32 @k()
+; CHECK: Function Attrs
+; CHECK-NEXT: declare i32 @k()
declare i32 @k() readnone
-; BOTH: Function Attrs
+; CHECK: Function Attrs
; CHECK-SAME: nounwind
-; BOTH-NOT: norecurse
+; CHECK-NOT: norecurse
; CHECK-NEXT: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len)
-; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture writeonly %dest, i8* nocapture readonly %src, i32 %len)
define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
ret void
}
-; BOTH: Function Attrs
-; BOTH-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32
+; CHECK: Function Attrs
+; CHECK-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
-; BOTH: Function Attrs
+; CHECK: Function Attrs
; CHECK-SAME: norecurse readnone
; FIXME: missing "norecurse"
-; ATTRIBUTOR-SAME: nosync readnone
; CHECK-NEXT: define internal i32 @called_by_norecurse()
define internal i32 @called_by_norecurse() {
%a = call i32 @k()
ret i32 %a
}
-; BOTH: Function Attrs
-; BOTH-NEXT: define void @m()
+; CHECK: Function Attrs
+; CHECK-NEXT: define void @m()
define void @m() norecurse {
%a = call i32 @called_by_norecurse()
ret void
}
-; BOTH: Function Attrs
+; CHECK: Function Attrs
; CHECK-SAME: norecurse readnone
; FIXME: missing "norecurse"
-; ATTRIBUTOR-SAME: nosync
; CHECK-NEXT: define internal i32 @called_by_norecurse_indirectly()
define internal i32 @called_by_norecurse_indirectly() {
%a = call i32 @k()
@@ -96,61 +91,3 @@ define void @p() norecurse {
call void @o()
ret void
}
-
-; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
-; ATTRIBUTOR-NEXT: define void @f(i32 %x)
-define void @f(i32 %x) {
-entry:
- %x.addr = alloca i32, align 4
- store i32 %x, i32* %x.addr, align 4
- %0 = load i32, i32* %x.addr, align 4
- %tobool = icmp ne i32 %0, 0
- br i1 %tobool, label %if.then, label %if.end
-
-if.then:
- call void @g() norecurse
- br label %if.end
-
-if.end:
- ret void
-}
-
-; BOTH: define void @g()
-define void @g() norecurse {
-entry:
- call void @f(i32 0)
- ret void
-}
-
-; ATTRIBUTOR-NOT: Function Attrs
-; ATTRIBUTOR: define linkonce_odr i32 @leaf_redefinable()
-define linkonce_odr i32 @leaf_redefinable() {
- ret i32 1
-}
-
-; Call through a function pointer
-; ATTRIBUTOR-NOT: Function Attrs
-; ATTRIBUTOR: define i32 @eval_func1(i32 (i32)* nocapture nofree nonnull %0, i32 %1)
-define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
- %3 = tail call i32 %0(i32 %1) #2
- ret i32 %3
-}
-
-; ATTRIBUTOR-NOT: Function Attrs
-; ATTRIBUTOR: define i32 @eval_func2(i32 (i32)* nocapture nofree %0, i32 %1)
-define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{
- %3 = tail call i32 %0(i32 %1) #2
- ret i32 %3
-}
-
-declare void @unknown()
-; Call an unknown function in a dead block.
-; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; ATTRIBUTOR: define i32 @call_unknown_in_dead_block()
-define i32 @call_unknown_in_dead_block() local_unnamed_addr {
- ret i32 0
-Dead:
- tail call void @unknown()
- ret i32 1
-}
-
diff --git a/llvm/test/Transforms/FunctionAttrs/nounwind.ll b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
index ed7576c970bf..6d5e3a2ea5b2 100644
--- a/llvm/test/Transforms/FunctionAttrs/nounwind.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
@@ -1,11 +1,8 @@
; RUN: opt < %s -functionattrs -S | FileCheck %s
-; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S | FileCheck %s --check-prefix=ATTRIBUTOR
; TEST 1
; CHECK: Function Attrs: norecurse nounwind readnone
; CHECK-NEXT: define i32 @foo1()
-; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
-; ATTRIBUTOR-NEXT: define i32 @foo1()
define i32 @foo1() {
ret i32 1
}
@@ -13,8 +10,6 @@ define i32 @foo1() {
; TEST 2
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: define i32 @scc1_foo()
-; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
-; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
define i32 @scc1_foo() {
%1 = call i32 @scc1_bar()
ret i32 1
@@ -24,8 +19,6 @@ define i32 @scc1_foo() {
; TEST 3
; CHECK: Function Attrs: nounwind readnone
; CHECK-NEXT: define i32 @scc1_bar()
-; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
-; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
define i32 @scc1_bar() {
%1 = call i32 @scc1_foo()
ret i32 1
@@ -36,7 +29,6 @@ declare i32 @non_nounwind()
; TEST 4
; CHECK: define void @call_non_nounwind() {
-; ATTRIBUTOR: define void @call_non_nounwind() {
define void @call_non_nounwind(){
tail call i32 @non_nounwind()
ret void
@@ -51,7 +43,6 @@ define void @call_non_nounwind(){
; }
; CHECK: define i32 @maybe_throw(i1 zeroext %0)
-; ATTRIBUTOR: define i32 @maybe_throw(i1 zeroext %0)
define i32 @maybe_throw(i1 zeroext %0) {
br i1 %0, label %2, label %3
@@ -75,7 +66,6 @@ declare void @__cxa_rethrow()
; }
; CHECK: define i32 @catch_thing()
-; ATTRIBUTOR: define i32 @catch_thing()
define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
invoke void @__cxa_rethrow() #1
to label %1 unwind label %2
@@ -93,9 +83,6 @@ define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality
}
define i32 @catch_thing_user() {
-; ATTRIBUTOR: define i32 @catch_thing_user
-; ATTRIBUTOR-NEXT: %catch_thing_call = call
-; ATTRIBUTOR-NEXT: ret i32 -1
%catch_thing_call = call i32 @catch_thing()
ret i32 %catch_thing_call
}
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
index dc1fbf652f9e..b11b3edcebfc 100644
--- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -1,7 +1,5 @@
-; RUN: opt < %s -functionattrs -S | FileCheck %s --check-prefixes=CHECK,FNATTR
-; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s --check-prefixes=CHECK,FNATTR
-; RUN: opt < %s -attributor -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
-; RUN: opt < %s -aa-pipeline=basic-aa -passes='attributor' -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
+; RUN: opt < %s -functionattrs -S | FileCheck %s
+; RUN: opt < %s -aa-pipeline=basic-aa -passes='cgscc(function-attrs)' -S | FileCheck %s
@x = global i32 0
@@ -9,23 +7,20 @@ declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...)
; NOTE: readonly for %y1_2 would be OK here but not for the similar situation in test13.
;
-; FNATTR: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2)
-; ATTRIBUTOR: define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2)
+; CHECK: define void @test1_2(i8* %x1_2, i8* readonly %y1_2, i8* %z1_2)
define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
call void (i8*, i8*, ...) @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2)
store i32 0, i32* @x
ret void
}
-; FNATTR: define i8* @test2(i8* readnone returned %p)
-; ATTRIBUTOR: define i8* @test2(i8* nofree readnone returned %p)
+; CHECK: define i8* @test2(i8* readnone returned %p)
define i8* @test2(i8* %p) {
store i32 0, i32* @x
ret i8* %p
}
-; FNATTR: define i1 @test3(i8* readnone %p, i8* readnone %q)
-; ATTRIBUTOR: define i1 @test3(i8* nofree readnone %p, i8* nofree readnone %q)
+; CHECK: define i1 @test3(i8* readnone %p, i8* readnone %q)
define i1 @test3(i8* %p, i8* %q) {
%A = icmp ult i8* %p, %q
ret i1 %A
@@ -39,8 +34,7 @@ define void @test4_2(i8* %p) {
ret void
}
-; FNATTR: define void @test5(i8** nocapture %p, i8* %q)
-; ATTRIBUTOR: define void @test5(i8** nocapture nofree nonnull writeonly dereferenceable(8) %p, i8* nofree writeonly %q)
+; CHECK: define void @test5(i8** nocapture %p, i8* %q)
; Missed optz'n: we could make %q readnone, but don't break test6!
define void @test5(i8** %p, i8* %q) {
store i8* %q, i8** %p
@@ -48,8 +42,7 @@ define void @test5(i8** %p, i8* %q) {
}
declare void @test6_1()
-; FNATTR: define void @test6_2(i8** nocapture %p, i8* %q)
-; ATTRIBUTOR: define void @test6_2(i8** nocapture nonnull writeonly dereferenceable(8) %p, i8* %q)
+; CHECK: define void @test6_2(i8** nocapture %p, i8* %q)
; This is not a missed optz'n.
define void @test6_2(i8** %p, i8* %q) {
store i8* %q, i8** %p
@@ -57,22 +50,19 @@ define void @test6_2(i8** %p, i8* %q) {
ret void
}
-; FNATTR: define void @test7_1(i32* inalloca nocapture %a)
-; ATTRIBUTOR: define void @test7_1(i32* inalloca nocapture nofree writeonly %a)
+; CHECK: define void @test7_1(i32* inalloca nocapture %a)
; inalloca parameters are always considered written
define void @test7_1(i32* inalloca %a) {
ret void
}
-; FNATTR: define i32* @test8_1(i32* readnone returned %p)
-; ATTRIBUTOR: define i32* @test8_1(i32* nofree readnone returned %p)
+; CHECK: define i32* @test8_1(i32* readnone returned %p)
define i32* @test8_1(i32* %p) {
entry:
ret i32* %p
}
-; FNATTR: define void @test8_2(i32* %p)
-; ATTRIBUTOR: define void @test8_2(i32* nocapture nofree writeonly %p)
+; CHECK: define void @test8_2(i32* %p)
define void @test8_2(i32* %p) {
entry:
%call = call i32* @test8_1(i32* %p)
@@ -136,11 +126,9 @@ declare void @escape_readonly_ptr(i8** %addr, i8* readonly %ptr)
;
; FIXME: This test currently exposes a bug in functionattrs!
;
-; FNATTR: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* readnone %escaped_then_written)
-; FNATTR: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* readonly %escaped_then_written)
+; CHECK: define void @unsound_readnone(i8* nocapture readnone %ignored, i8* readnone %escaped_then_written)
+; CHECK: define void @unsound_readonly(i8* nocapture readnone %ignored, i8* readonly %escaped_then_written)
;
-; ATTRIBUTOR: define void @unsound_readnone(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
-; ATTRIBUTOR: define void @unsound_readonly(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) {
%addr = alloca i8*
call void @escape_readnone_ptr(i8** %addr, i8* %escaped_then_written)
diff --git a/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll
index b6b699fac85e..e707b88b54ac 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll
@@ -1,5 +1,4 @@
; RUN: opt < %s -inferattrs -S | FileCheck %s
-; RUN: opt < %s -attributor --attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR
@@ -8,7 +7,6 @@
define <4 x double> @PR21780(double* %ptr) {
; CHECK-LABEL: @PR21780(double* %ptr)
-; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
; GEP of index 0 is simplified away.
%arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1
@@ -31,7 +29,6 @@ define <4 x double> @PR21780(double* %ptr) {
define double @PR21780_only_access3_with_inbounds(double* %ptr) {
; CHECK-LABEL: @PR21780_only_access3_with_inbounds(double* %ptr)
-; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
%arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
%t3 = load double, double* %arrayidx3, align 8
@@ -40,7 +37,6 @@ define double @PR21780_only_access3_with_inbounds(double* %ptr) {
define double @PR21780_only_access3_without_inbounds(double* %ptr) {
; CHECK-LABEL: @PR21780_only_access3_without_inbounds(double* %ptr)
-; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture nofree readonly align 8 %ptr)
%arrayidx3 = getelementptr double, double* %ptr, i64 3
%t3 = load double, double* %arrayidx3, align 8
ret double %t3
@@ -48,7 +44,6 @@ define double @PR21780_only_access3_without_inbounds(double* %ptr) {
define double @PR21780_without_inbounds(double* %ptr) {
; CHECK-LABEL: @PR21780_without_inbounds(double* %ptr)
-; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
%arrayidx1 = getelementptr double, double* %ptr, i64 1
%arrayidx2 = getelementptr double, double* %ptr, i64 2
@@ -66,7 +61,6 @@ define double @PR21780_without_inbounds(double* %ptr) {
define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
; CHECK-LABEL: @gep0(i8* %unused, i8* %other, i8* %ptr)
-; ATTRIBUTOR-LABEL: @gep0(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull writeonly dereferenceable(1) %other, i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr)
%arrayidx0 = getelementptr i8, i8* %ptr, i64 0
%arrayidx1 = getelementptr i8, i8* %ptr, i64 1
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
@@ -82,7 +76,6 @@ define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
define void @ordering(i8* %ptr1, i32* %ptr2) {
; CHECK-LABEL: @ordering(i8* %ptr1, i32* %ptr2)
-; ATTRIBUTOR-LABEL: @ordering(i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr1, i32* nocapture nofree nonnull readonly dereferenceable(8) %ptr2)
%a20 = getelementptr i32, i32* %ptr2, i64 0
%a12 = getelementptr i8, i8* %ptr1, i64 2
%t12 = load i8, i8* %a12
@@ -100,7 +93,6 @@ define void @ordering(i8* %ptr1, i32* %ptr2) {
define void @not_entry_but_guaranteed_to_execute(i8* %ptr) {
; CHECK-LABEL: @not_entry_but_guaranteed_to_execute(i8* %ptr)
-; ATTRIBUTOR-LABEL: @not_entry_but_guaranteed_to_execute(i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr)
entry:
br label %exit
exit:
@@ -117,7 +109,6 @@ exit:
define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) {
; CHECK-LABEL: @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond)
-; ATTRIBUTOR-LABEL: @not_entry_not_guaranteed_to_execute(i8* nocapture nofree readonly %ptr, i1 %cond)
entry:
br i1 %cond, label %loads, label %exit
loads:
@@ -136,7 +127,6 @@ exit:
define void @partial_in_entry(i16* %ptr, i1 %cond) {
; CHECK-LABEL: @partial_in_entry(i16* %ptr, i1 %cond)
-; ATTRIBUTOR-LABEL: @partial_in_entry(i16* nocapture nofree nonnull readonly dereferenceable(4) %ptr, i1 %cond)
entry:
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
@@ -156,7 +146,6 @@ exit:
define void @volatile_is_not_dereferenceable(i16* %ptr) {
; CHECK-LABEL: @volatile_is_not_dereferenceable(i16* %ptr)
-; ATTRIBUTOR-LABEL: @volatile_is_not_dereferenceable(i16* nofree %ptr)
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@@ -170,7 +159,6 @@ define void @volatile_is_not_dereferenceable(i16* %ptr) {
define void @atomic_is_alright(i16* %ptr) {
; CHECK-LABEL: @atomic_is_alright(i16* %ptr)
-; ATTRIBUTOR-LABEL: @atomic_is_alright(i16* nocapture nofree nonnull readonly align 2 dereferenceable(6) %ptr)
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@@ -184,7 +172,6 @@ declare void @may_not_return()
define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
; CHECK-LABEL: @not_guaranteed_to_transfer_execution(i16* %ptr)
-; ATTRIBUTOR-LABEL: @not_guaranteed_to_transfer_execution(i16* nocapture nonnull readonly dereferenceable(2) %ptr)
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@@ -199,7 +186,6 @@ define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
; CHECK-LABEL: @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index)
-; ATTRIBUTOR-LABEL: @variable_gep_index(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull readonly dereferenceable(1) %ptr, i64 %variable_index)
%arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
%t0 = load i8, i8* %ptr
@@ -213,7 +199,6 @@ define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
define void @multi_index_gep(<4 x i8>* %ptr) {
; CHECK-LABEL: @multi_index_gep(<4 x i8>* %ptr)
; FIXME: %ptr should be dereferenceable(4)
-; ATTRIBUTOR-LABEL: @multi_index_gep(<4 x i8>* nocapture nofree nonnull readonly dereferenceable(1) %ptr)
%arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0
%t0 = load i8, i8* %arrayidx00
ret void
@@ -223,7 +208,6 @@ define void @multi_index_gep(<4 x i8>* %ptr) {
define void @not_byte_multiple(i9* %ptr) {
; CHECK-LABEL: @not_byte_multiple(i9* %ptr)
-; ATTRIBUTOR-LABEL: @not_byte_multiple(i9* nocapture nofree nonnull readonly dereferenceable(2) %ptr)
%arrayidx0 = getelementptr i9, i9* %ptr, i64 0
%t0 = load i9, i9* %arrayidx0
ret void
@@ -233,7 +217,6 @@ define void @not_byte_multiple(i9* %ptr) {
define void @no_pointer_deref(i16* %ptr) {
; CHECK-LABEL: @no_pointer_deref(i16* %ptr)
-; ATTRIBUTOR-LABEL: @no_pointer_deref(i16* nocapture nofree readonly %ptr)
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
%t1 = load i16, i16* %arrayidx1
@@ -245,7 +228,6 @@ define void @no_pointer_deref(i16* %ptr) {
define void @non_consecutive(i32* %ptr) {
; CHECK-LABEL: @non_consecutive(i32* %ptr)
-; ATTRIBUTOR-LABEL: @non_consecutive(i32* nocapture nofree nonnull readonly dereferenceable(8) %ptr)
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
@@ -259,7 +241,6 @@ define void @non_consecutive(i32* %ptr) {
define void @more_bytes(i32* dereferenceable(8) %ptr) {
; CHECK-LABEL: @more_bytes(i32* dereferenceable(8) %ptr)
-; ATTRIBUTOR-LABEL: @more_bytes(i32* nocapture nofree nonnull readonly dereferenceable(16) %ptr)
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@@ -275,7 +256,6 @@ define void @more_bytes(i32* dereferenceable(8) %ptr) {
define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
; CHECK-LABEL: @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr)
-; ATTRIBUTOR-LABEL: @more_bytes_and_not_null(i32* nocapture nofree nonnull readonly dereferenceable(16) %ptr)
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@@ -291,7 +271,6 @@ define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
define void @better_bytes(i32* dereferenceable(100) %ptr) {
; CHECK-LABEL: @better_bytes(i32* dereferenceable(100) %ptr)
-; ATTRIBUTOR-LABEL: @better_bytes(i32* nocapture nofree nonnull readonly dereferenceable(100) %ptr)
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@@ -305,7 +284,6 @@ define void @better_bytes(i32* dereferenceable(100) %ptr) {
define void @bitcast(i32* %arg) {
; CHECK-LABEL: @bitcast(i32* %arg)
-; ATTRIBUTOR-LABEL: @bitcast(i32* nocapture nofree nonnull readonly dereferenceable(8) %arg)
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@@ -316,7 +294,6 @@ define void @bitcast(i32* %arg) {
define void @bitcast_
diff erent_sizes(double* %arg1, i8* %arg2) {
; CHECK-LABEL: @bitcast_
diff erent_sizes(double* %arg1, i8* %arg2)
-; ATTRIBUTOR-LABEL: @bitcast_
diff erent_sizes(double* nocapture nofree nonnull readonly dereferenceable(12) %arg1, i8* nocapture nofree nonnull readonly dereferenceable(16) %arg2)
%ptr1 = bitcast double* %arg1 to float*
%a10 = getelementptr float, float* %ptr1, i64 0
%a11 = getelementptr float, float* %ptr1, i64 1
@@ -335,7 +312,6 @@ define void @bitcast_
diff erent_sizes(double* %arg1, i8* %arg2) {
define void @negative_offset(i32* %arg) {
; CHECK-LABEL: @negative_offset(i32* %arg)
-; ATTRIBUTOR-LABEL: @negative_offset(i32* nocapture nofree nonnull readonly dereferenceable(4) %arg)
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 -1
@@ -346,7 +322,6 @@ define void @negative_offset(i32* %arg) {
define void @stores(i32* %arg) {
; CHECK-LABEL: @stores(i32* %arg)
-; ATTRIBUTOR-LABEL: @stores(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@@ -357,7 +332,6 @@ define void @stores(i32* %arg) {
define void @load_store(i32* %arg) {
; CHECK-LABEL: @load_store(i32* %arg)
-; ATTRIBUTOR-LABEL: @load_store(i32* nocapture nofree nonnull dereferenceable(8) %arg)
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@@ -368,7 +342,6 @@ define void @load_store(i32* %arg) {
define void @
diff erent_size1(i32* %arg) {
; CHECK-LABEL: @
diff erent_size1(i32* %arg)
-; ATTRIBUTOR-LABEL: @
diff erent_size1(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
%arg-cast = bitcast i32* %arg to double*
store double 0.000000e+00, double* %arg-cast
store i32 0, i32* %arg
@@ -377,7 +350,6 @@ define void @
diff erent_size1(i32* %arg) {
define void @
diff erent_size2(i32* %arg) {
; CHECK-LABEL: @
diff erent_size2(i32* %arg)
-; ATTRIBUTOR-LABEL: @
diff erent_size2(i32* nocapture nofree nonnull writeonly dereferenceable(8) %arg)
store i32 0, i32* %arg
%arg-cast = bitcast i32* %arg to double*
store double 0.000000e+00, double* %arg-cast
More information about the llvm-commits
mailing list