fhahn created this revision. fhahn added reviewers: rjmccall, rsmith, hfinkel, jfb. Herald added subscribers: dang, dexonsmith. Herald added a project: clang. fhahn requested review of this revision.
After the recent discussion on cfe-dev 'Can indirect class parameters be noalias?' [1], it seems like using using noalias is problematic for current C++, but should be allowed for C-only code. This patch introduces a new option to let the user indicate that it is safe to mark indirect class parameters as noalias. Note that this also applies to external callers, e.g. it might not be safe to use this flag for C functions that are called by C++ functions. In targets that allocate indirect arguments in the called function, this enables more agressive optimizations with respect to memory operations and brings a ~1% - 2% codesize reduction for some programs. I am not sure about the best name for the option and description. I would appreciate any feedback. [1] : http://lists.llvm.org/pipermail/cfe-dev/2020-July/066353.html Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D85473 Files: clang/include/clang/Basic/LangOptions.def clang/include/clang/Driver/Options.td clang/lib/CodeGen/CGCall.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/test/CodeGen/pass-by-value-noalias.c Index: clang/test/CodeGen/pass-by-value-noalias.c =================================================================== --- /dev/null +++ clang/test/CodeGen/pass-by-value-noalias.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fpass-by-value-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 + +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) {} Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -3419,6 +3419,7 @@ Opts.PCHInstantiateTemplates = Args.hasArg(OPT_fpch_instantiate_templates); Opts.MatrixTypes = Args.hasArg(OPT_fenable_matrix); + Opts.PassByValueNoAlias = Args.hasArg(OPT_fpass_by_value_noalias); Opts.MaxTokens = getLastArgIntValue(Args, OPT_fmax_tokens_EQ, 0, Diags); Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2184,6 +2184,11 @@ if (AI.getIndirectByVal()) Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); + if (getLangOpts().PassByValueNoAlias) + // 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); + CharUnits Align = AI.getIndirectAlign(); // In a byval argument, it is important that the required Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -4284,6 +4284,10 @@ 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_noalias: Flag<["-"], "fpass-by-value-noalias">, + HelpText<"Allows assuming no references to passed by value escape before " + "transferring execution to the called function. Note that this " + "does not hold for C++">; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -368,6 +368,10 @@ LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type") +LANGOPT(PassByValueNoAlias, 1, 0, "Allows assuming no references to passed by " + "value escape before transferring execution " + "to the called function. Note that this does " + "not hold for C++") COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0")
Index: clang/test/CodeGen/pass-by-value-noalias.c =================================================================== --- /dev/null +++ clang/test/CodeGen/pass-by-value-noalias.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fpass-by-value-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 + +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) {} Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -3419,6 +3419,7 @@ Opts.PCHInstantiateTemplates = Args.hasArg(OPT_fpch_instantiate_templates); Opts.MatrixTypes = Args.hasArg(OPT_fenable_matrix); + Opts.PassByValueNoAlias = Args.hasArg(OPT_fpass_by_value_noalias); Opts.MaxTokens = getLastArgIntValue(Args, OPT_fmax_tokens_EQ, 0, Diags); Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2184,6 +2184,11 @@ if (AI.getIndirectByVal()) Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType)); + if (getLangOpts().PassByValueNoAlias) + // 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); + CharUnits Align = AI.getIndirectAlign(); // In a byval argument, it is important that the required Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -4284,6 +4284,10 @@ 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_noalias: Flag<["-"], "fpass-by-value-noalias">, + HelpText<"Allows assuming no references to passed by value escape before " + "transferring execution to the called function. Note that this " + "does not hold for C++">; // FIXME: Remove these entirely once functionality/tests have been excised. def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -368,6 +368,10 @@ LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type") +LANGOPT(PassByValueNoAlias, 1, 0, "Allows assuming no references to passed by " + "value escape before transferring execution " + "to the called function. Note that this does " + "not hold for C++") COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0")
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits