diff options
| -rw-r--r-- | llvm/test/Transforms/Attributor/align.ll (renamed from llvm/test/Transforms/FunctionAttrs/align.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/callbacks.ll (renamed from llvm/test/Transforms/FunctionAttrs/callbacks.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/dereferenceable-1.ll (renamed from llvm/test/Transforms/FunctionAttrs/dereferenceable.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/dereferenceable-2.ll | 356 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/heap_to_stack.ll (renamed from llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/internal-noalias.ll (renamed from llvm/test/Transforms/FunctionAttrs/internal-noalias.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/liveness.ll (renamed from llvm/test/Transforms/FunctionAttrs/liveness.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/misc.ll (renamed from llvm/test/Transforms/FunctionAttrs/misc.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/new_attributes.ll (renamed from llvm/test/Transforms/FunctionAttrs/new_attributes.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/noalias.ll (renamed from llvm/test/Transforms/FunctionAttrs/noalias_returned.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nocapture-1.ll | 346 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nocapture-2.ll (renamed from llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nofree.ll | 243 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nonnull.ll | 817 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/norecurse.ll | 147 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/noreturn.ll (renamed from llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/noreturn_async.ll (renamed from llvm/test/Transforms/FunctionAttrs/noreturn_async.ll) | 2 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/noreturn_sync.ll (renamed from llvm/test/Transforms/FunctionAttrs/noreturn_sync.ll) | 2 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nosync.ll (renamed from llvm/test/Transforms/FunctionAttrs/nosync.ll) | 37 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/nounwind.ll | 98 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll (renamed from llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/readattrs.ll | 145 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/returned.ll | 812 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/value-simplify.ll (renamed from llvm/test/Transforms/FunctionAttrs/value-simplify.ll) | 0 | ||||
| -rw-r--r-- | llvm/test/Transforms/Attributor/willreturn.ll (renamed from llvm/test/Transforms/FunctionAttrs/willreturn.ll) | 71 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/arg_returned.ll | 158 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/nocapture.ll | 72 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll | 69 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/nonnull.ll | 259 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/norecurse.ll | 121 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/nounwind.ll | 13 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/readattrs.ll | 36 | ||||
| -rw-r--r-- | llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll | 28 |
33 files changed, 3081 insertions, 751 deletions
diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/Attributor/align.ll index a5bf91915ba..a5bf91915ba 100644 --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll diff --git a/llvm/test/Transforms/FunctionAttrs/callbacks.ll b/llvm/test/Transforms/Attributor/callbacks.ll index f79d81c3969..f79d81c3969 100644 --- a/llvm/test/Transforms/FunctionAttrs/callbacks.ll +++ b/llvm/test/Transforms/Attributor/callbacks.ll diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll index 951b5047747..951b5047747 100644 --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/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 00000000000..b3c0440f930 --- /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_different_sizes(double* %arg1, i8* %arg2) { +; ATTRIBUTOR-LABEL: @bitcast_different_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 @different_size1(i32* %arg) { +; ATTRIBUTOR-LABEL: @different_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 @different_size2(i32* %arg) { +; ATTRIBUTOR-LABEL: @different_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 index 1f7be75ef16..1f7be75ef16 100644 --- a/llvm/test/Transforms/FunctionAttrs/heap_to_stack.ll +++ b/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 index fd6e17bc77f..fd6e17bc77f 100644 --- a/llvm/test/Transforms/FunctionAttrs/internal-noalias.ll +++ b/llvm/test/Transforms/Attributor/internal-noalias.ll diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll index 4fea57ff921..4fea57ff921 100644 --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ b/llvm/test/Transforms/Attributor/liveness.ll diff --git a/llvm/test/Transforms/FunctionAttrs/misc.ll b/llvm/test/Transforms/Attributor/misc.ll index 7b9e25809d9..7b9e25809d9 100644 --- a/llvm/test/Transforms/FunctionAttrs/misc.ll +++ b/llvm/test/Transforms/Attributor/misc.ll diff --git a/llvm/test/Transforms/FunctionAttrs/new_attributes.ll b/llvm/test/Transforms/Attributor/new_attributes.ll index 6e87cffeb02..6e87cffeb02 100644 --- a/llvm/test/Transforms/FunctionAttrs/new_attributes.ll +++ b/llvm/test/Transforms/Attributor/new_attributes.ll diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/Attributor/noalias.ll index 587727dc311..587727dc311 100644 --- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ b/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 00000000000..abb148d883e --- /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 + +@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! +} + +@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 +} + +@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 +} + +@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 index 79075268ed4..79075268ed4 100644 --- a/llvm/test/Transforms/FunctionAttrs/arg_nocapture.ll +++ b/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 00000000000..d06a0ea1e9b --- /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 00000000000..260f04c2737 --- /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 00000000000..25f7fdee5f1 --- /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 index 2b15e0780df..2b15e0780df 100644 --- a/llvm/test/Transforms/FunctionAttrs/fn_noreturn.ll +++ b/llvm/test/Transforms/Attributor/noreturn.ll diff --git a/llvm/test/Transforms/FunctionAttrs/noreturn_async.ll b/llvm/test/Transforms/Attributor/noreturn_async.ll index 3d2dd9f47da..7c00a5a0b5c 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 index b5a70e76271..4e6f13737a7 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 index abb40cf2669..cd01a0caa58 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 00000000000..e569095c8d4 --- /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 index 72d062b7616..72d062b7616 100644 --- a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll +++ b/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 00000000000..9c148ef160b --- /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 + +@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 00000000000..85ab69a0d99 --- /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 +} + +@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 index 4e765cc233f..4e765cc233f 100644 --- a/llvm/test/Transforms/FunctionAttrs/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll index 8f7e46837c1..90fef48b2a9 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 5572c0124a0..0adf91cd9aa 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 -} - -@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 a78af104167..25759cffe13 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 1c007ee11b4..8ac037e5cd8 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 42923cee770..128a2bdbe50 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 de5d35d6342..b780bb7b718 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 ed7576c970b..6d5e3a2ea5b 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 dc1fbf652f9..b11b3edcebf 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 b6b699fac85..e707b88b54a 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_different_sizes(double* %arg1, i8* %arg2) { ; CHECK-LABEL: @bitcast_different_sizes(double* %arg1, i8* %arg2) -; ATTRIBUTOR-LABEL: @bitcast_different_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_different_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 @different_size1(i32* %arg) { ; CHECK-LABEL: @different_size1(i32* %arg) -; ATTRIBUTOR-LABEL: @different_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 @different_size1(i32* %arg) { define void @different_size2(i32* %arg) { ; CHECK-LABEL: @different_size2(i32* %arg) -; ATTRIBUTOR-LABEL: @different_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 |

