1 // 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
2 // RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s
3 
4 // A trivial struct large enough so it is not passed in registers on ARM64.
5 struct Foo {
6   int a;
7   int b;
8   int c;
9   int d;
10   int e;
11   int f;
12 };
13 
14 // Make sure noalias is added to indirect arguments with trivially copyable types
15 // if -fpass-by-value-is-noalias is provided.
16 
17 // WITH_NOALIAS: define{{.*}} void @_Z4take3Foo(%struct.Foo* noalias %arg)
18 // NO_NOALIAS: define{{.*}} void @_Z4take3Foo(%struct.Foo* %arg)
take(Foo arg)19 void take(Foo arg) {}
20 
21 int G;
22 
23 // NonTrivial is not trivially-copyable, because it has a non-trivial copy
24 // constructor.
25 struct NonTrivial {
26   int a;
27   int b;
28   int c;
29   int d;
30   int e;
31   int f;
32 
NonTrivialNonTrivial33   NonTrivial(const NonTrivial &Other) {
34     a = G + 10 + Other.a;
35   }
36 };
37 
38 // Make sure noalias is not added to indirect arguments that are not trivially
39 // copyable even if -fpass-by-value-is-noalias is provided.
40 
41 // WITH_NOALIAS: define{{.*}} void @_Z4take10NonTrivial(%struct.NonTrivial* %arg)
42 // NO_NOALIAS:   define{{.*}} void @_Z4take10NonTrivial(%struct.NonTrivial* %arg)
take(NonTrivial arg)43 void take(NonTrivial arg) {}
44 
45 // 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).
46 struct A {
AA47   A(A **where) : data{"hello world 1"} {
48     *where = this; //Escaped pointer 1 (proposed UB?)
49   }
50 
AA51   A() : data{"hello world 2"} {}
52 
53   char data[32];
54 };
55 A *p;
56 
57 // WITH_NOALIAS: define{{.*}} void @_Z4take1A(%struct.A* noalias %arg)
58 // NO_NOALIAS: define{{.*}} void @_Z4take1A(%struct.A* %arg)
take(A arg)59 void take(A arg) {}
60 
61 // WITH_NOALIAS: define{{.*}} void @_Z7CreateAPP1A(%struct.A* noalias sret(%struct.A) align 1 %agg.result, %struct.A** %where)
62 // NO_NOALIAS: define{{.*}} void @_Z7CreateAPP1A(%struct.A* noalias sret(%struct.A) align 1 %agg.result, %struct.A** %where)
CreateA(A ** where)63 A CreateA(A **where) {
64   A justlikethis;
65   *where = &justlikethis; //Escaped pointer 2 (should also be UB, then)
66   return justlikethis;
67 }
68 
69 // elsewhere, perhaps compiled by a smarter compiler that doesn't make a copy here
test()70 void test() {
71   take({&p});        // 1
72   take(CreateA(&p)); // 2
73 }
74