diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -395,6 +395,10 @@ /// Whether to not follow the AAPCS that enforce at least one read before storing to a volatile bitfield CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0) +/// Assume that by-value parameters do not alias any other values. +CODEGENOPT(PassByValueIsNoAlias, 1, 0) + + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4314,6 +4314,9 @@ def fcompatibility_qualified_id_block_param_type_checking : Flag<["-"], "fcompatibility-qualified-id-block-type-checking">, HelpText<"Allow using blocks with parameters of more specific type than " "the type system guarantees when a parameter is qualified id">; +def fpass_by_value_is_noalias: Flag<["-"], "fpass-by-value-is-noalias">, + HelpText<"Allows assuming by-value parameters do not alias any other value." + "Has no effect on non-trivially-copyable classes in C++.">, Group; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2201,6 +2201,13 @@ if (AI.getIndirectByVal()) Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); + if (CodeGenOpts.PassByValueIsNoAlias && + ParamType.isTriviallyCopyableType(getContext()) && + !ParamType.isObjCGCWeak()) + // When calling the function, the pointer passed in will be the only + // reference to the underlying object. Mark it accordingly. + Attrs.addAttribute(llvm::Attribute::NoAlias); + // TODO: We could add the byref attribute if not byval, but it would // require updating many testcases. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1453,6 +1453,8 @@ std::string(Args.getLastArgValue(OPT_fsymbol_partition_EQ)); Opts.ForceAAPCSBitfieldLoad = Args.hasArg(OPT_ForceAAPCSBitfieldLoad); + + Opts.PassByValueIsNoAlias = Args.hasArg(OPT_fpass_by_value_is_noalias); return Success; } diff --git a/clang/test/CodeGen/pass-by-value-noalias.c b/clang/test/CodeGen/pass-by-value-noalias.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/pass-by-value-noalias.c @@ -0,0 +1,16 @@ +// 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 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; +}; + +// WITH_NOALIAS: define void @take(%struct.Foo* noalias %arg) +// NO_NOALIAS: define void @take(%struct.Foo* %arg) +void take(struct Foo arg) {} diff --git a/clang/test/CodeGenCXX/pass-by-value-noalias.cpp b/clang/test/CodeGenCXX/pass-by-value-noalias.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/pass-by-value-noalias.cpp @@ -0,0 +1,43 @@ +// 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) {} diff --git a/clang/test/CodeGenObjC/pass-by-value-noalias.m b/clang/test/CodeGenObjC/pass-by-value-noalias.m new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenObjC/pass-by-value-noalias.m @@ -0,0 +1,21 @@ +// 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 +// 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 + +// A struct large enough so it is not passed in registers on ARM64. + +@interface Bar +@property char value; +@end + +struct Foo { + int a; + int b; + int c; + int d; + int e; + Bar *__weak f; +}; + +// WITH_NOALIAS: define void @take(%struct.Foo* noalias %arg) +// NO_NOALIAS: define void @take(%struct.Foo* %arg) +void take(struct Foo arg) {}