Skip to content

Commit 23b3574

Browse files
author
git apple-llvm automerger
committed
Merge commit '08dd9ccc53e0' from apple/stable/20200714 into swift/main
2 parents a81d496 + 08dd9cc commit 23b3574

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@ CODEGENOPT(KeepStaticConsts, 1, 0)
393393
/// Whether to not follow the AAPCS that enforce at least one read before storing to a volatile bitfield
394394
CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0)
395395

396+
/// Assume that by-value parameters do not alias any other values.
397+
CODEGENOPT(PassByValueIsNoAlias, 1, 0)
398+
399+
396400
#undef CODEGENOPT
397401
#undef ENUM_CODEGENOPT
398402
#undef VALUE_CODEGENOPT

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4339,6 +4339,9 @@ def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">,
43394339
def fcompatibility_qualified_id_block_param_type_checking : Flag<["-"], "fcompatibility-qualified-id-block-type-checking">,
43404340
HelpText<"Allow using blocks with parameters of more specific type than "
43414341
"the type system guarantees when a parameter is qualified id">;
4342+
def fpass_by_value_is_noalias: Flag<["-"], "fpass-by-value-is-noalias">,
4343+
HelpText<"Allows assuming by-value parameters do not alias any other value. "
4344+
"Has no effect on non-trivially-copyable classes in C++.">, Group<f_Group>;
43424345

43434346
// FIXME: Remove these entirely once functionality/tests have been excised.
43444347
def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>,

clang/lib/CodeGen/CGCall.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,13 @@ void CodeGenModule::ConstructAttributeList(
21922192
if (AI.getIndirectByVal())
21932193
Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType));
21942194

2195+
auto *Decl = ParamType->getAsRecordDecl();
2196+
if (CodeGenOpts.PassByValueIsNoAlias && Decl &&
2197+
Decl->getArgPassingRestrictions() == RecordDecl::APK_CanPassInRegs)
2198+
// When calling the function, the pointer passed in will be the only
2199+
// reference to the underlying object. Mark it accordingly.
2200+
Attrs.addAttribute(llvm::Attribute::NoAlias);
2201+
21952202
CharUnits Align = AI.getIndirectAlign();
21962203

21972204
// In a byval argument, it is important that the required

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
15391539
std::string(Args.getLastArgValue(OPT_fsymbol_partition_EQ));
15401540

15411541
Opts.ForceAAPCSBitfieldLoad = Args.hasArg(OPT_ForceAAPCSBitfieldLoad);
1542+
1543+
Opts.PassByValueIsNoAlias = Args.hasArg(OPT_fpass_by_value_is_noalias);
15421544
return Success;
15431545
}
15441546

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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 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+
// WITH_NOALIAS: define void @take(%struct.Foo* noalias %arg)
15+
// NO_NOALIAS: define void @take(%struct.Foo* %arg)
16+
void take(struct Foo arg) {}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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)
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+
33+
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)
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 {
47+
A(A **where) : data{"hello world 1"} {
48+
*where = this; //Escaped pointer 1 (proposed UB?)
49+
}
50+
51+
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)
59+
void take(A arg) {}
60+
61+
// WITH_NOALIAS: define void @_Z7CreateAPP1A(%struct.A* noalias sret align 1 %agg.result, %struct.A** %where)
62+
// NO_NOALIAS: define void @_Z7CreateAPP1A(%struct.A* noalias sret align 1 %agg.result, %struct.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
70+
void test() {
71+
take({&p}); // 1
72+
take(CreateA(&p)); // 2
73+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -fpass-by-value-is-noalias -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns -fobjc-runtime-has-weak -fobjc-arc -fobjc-dispatch-method=mixed %s -o - 2>&1 | FileCheck --check-prefix=WITH_NOALIAS %s
2+
// RUN: %clang_cc1 -triple arm64-apple-iphoneos -emit-llvm -disable-llvm-optzns -fobjc-runtime-has-weak -fobjc-arc -fobjc-dispatch-method=mixed %s -o - 2>&1 | FileCheck --check-prefix=NO_NOALIAS %s
3+
4+
@interface Bar
5+
@property char value;
6+
@end
7+
8+
// A struct large enough so it is not passed in registers on ARM64, but with a
9+
// weak reference, so noalias should not be added even with
10+
// -fpass-by-value-is-noalias.
11+
struct Foo {
12+
int a;
13+
int b;
14+
int c;
15+
int d;
16+
int e;
17+
Bar *__weak f;
18+
};
19+
20+
// WITH_NOALIAS: define void @take(%struct.Foo* %arg)
21+
// NO_NOALIAS: define void @take(%struct.Foo* %arg)
22+
void take(struct Foo arg) {}

0 commit comments

Comments
 (0)