| // RUN: %clang_cc1 -fpass-by-value-is-noalias -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=WITH_NOALIAS %s |
| // RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s |
| |
| // A trivial struct large enough so it is not passed in registers on ARM64. |
| struct Foo { |
| int a; |
| int b; |
| int c; |
| int d; |
| int e; |
| int f; |
| }; |
| |
| // Make sure noalias is added to indirect arguments with trivially copyable types |
| // if -fpass-by-value-is-noalias is provided. |
| |
| // WITH_NOALIAS: define{{.*}} void @_Z4take3Foo(%struct.Foo* noalias %arg) |
| // NO_NOALIAS: define{{.*}} void @_Z4take3Foo(%struct.Foo* %arg) |
| void take(Foo arg) {} |
| |
| int G; |
| |
| // NonTrivial is not trivially-copyable, because it has a non-trivial copy |
| // constructor. |
| struct NonTrivial { |
| int a; |
| int b; |
| int c; |
| int d; |
| int e; |
| int f; |
| |
| NonTrivial(const NonTrivial &Other) { |
| a = G + 10 + Other.a; |
| } |
| }; |
| |
| // Make sure noalias is not added to indirect arguments that are not trivially |
| // copyable even if -fpass-by-value-is-noalias is provided. |
| |
| // WITH_NOALIAS: define{{.*}} void @_Z4take10NonTrivial(%struct.NonTrivial* %arg) |
| // NO_NOALIAS: define{{.*}} void @_Z4take10NonTrivial(%struct.NonTrivial* %arg) |
| void take(NonTrivial arg) {} |
| |
| // Escape examples. Pointers to the objects passed to take() may escape, depending on whether a temporary copy is created or not (e.g. due to NRVO). |
| struct A { |
| A(A **where) : data{"hello world 1"} { |
| *where = this; //Escaped pointer 1 (proposed UB?) |
| } |
| |
| A() : data{"hello world 2"} {} |
| |
| char data[32]; |
| }; |
| A *p; |
| |
| // WITH_NOALIAS: define{{.*}} void @_Z4take1A(%struct.A* noalias %arg) |
| // NO_NOALIAS: define{{.*}} void @_Z4take1A(%struct.A* %arg) |
| void take(A arg) {} |
| |
| // WITH_NOALIAS: define{{.*}} void @_Z7CreateAPP1A(%struct.A* noalias sret(%struct.A) align 1 %agg.result, %struct.A** %where) |
| // NO_NOALIAS: define{{.*}} void @_Z7CreateAPP1A(%struct.A* noalias sret(%struct.A) align 1 %agg.result, %struct.A** %where) |
| A CreateA(A **where) { |
| A justlikethis; |
| *where = &justlikethis; //Escaped pointer 2 (should also be UB, then) |
| return justlikethis; |
| } |
| |
| // elsewhere, perhaps compiled by a smarter compiler that doesn't make a copy here |
| void test() { |
| take({&p}); // 1 |
| take(CreateA(&p)); // 2 |
| } |