diff --git a/clang/docs/AttributeReference.rst b/clang/docs/AttributeReference.rst index 1d41cb32cf6d..84b5440ac30d 100644 --- a/clang/docs/AttributeReference.rst +++ b/clang/docs/AttributeReference.rst @@ -558,6 +558,50 @@ caveats to this use of name mangling: Query for this feature with ``__has_extension(attribute_overloadable)``. +noduplicate +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "__declspec", "Keyword" + + "X","X","","" + +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated +or not as a result of optimizations. This is required for the implementation +of functions with certain special requirements, like the OpenCL "barrier", +function that, depending on the hardware, might require to be run concurrently +by all the threads that are currently executing in lockstep on the hardware. +For example this attribute applied on the function "nodupfunc" +avoids that this code: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimization into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the barrier call is duplicated and sunk into the two branches of the condition. Variable Attributes =================== diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 148de472063f..9c28d631d236 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -803,6 +803,12 @@ def NoDebug : InheritableAttr { let Documentation = [Undocumented]; } +def NoDuplicate : InheritableAttr { + let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoDuplicateDocs]; +} + def NoInline : InheritableAttr { let Spellings = [GCC<"noinline">, Declspec<"noinline">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index c0f0fbcea13c..ebe4bb9abb2e 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -299,6 +299,49 @@ Query for this feature with ``__has_attribute(objc_method_family)``. }]; } +def NoDuplicateDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated +or not as a result of optimizations. This is required for the implementation +of functions with certain special requirements, like the OpenCL "barrier", +function that, depending on the hardware, might require to be run concurrently +by all the threads that are currently executing in lockstep on the hardware. +For example this attribute applied on the function "nodupfunc" +avoids that this code: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimization into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the barrier call is duplicated and sunk into the two branches of the condition. + }]; +} + def ObjCRequiresSuperDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -842,4 +885,4 @@ Clang implements two kinds of checks with this attribute. the corresponding arguments are annotated. If the arguments are incorrect, the caller of ``foo`` will receive a warning. }]; -} \ No newline at end of file +} diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a9caa88706a8..a21e4783b60b 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1052,6 +1052,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs(); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index bbf5a730f07d..e6798e49a85a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -631,6 +631,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, // Naked implies noinline: we should not be inlining such functions. B.addAttribute(llvm::Attribute::Naked); B.addAttribute(llvm::Attribute::NoInline); + } else if (D->hasAttr()) { + B.addAttribute(llvm::Attribute::NoDuplicate); } else if (D->hasAttr()) { B.addAttribute(llvm::Attribute::NoInline); } else if ((D->hasAttr() || diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 29e4bb7b3e26..1de06af775d5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4237,6 +4237,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_Cleanup: handleCleanupAttr (S, D, Attr); break; case AttributeList::AT_NoDebug: handleNoDebugAttr (S, D, Attr); break; + case AttributeList::AT_NoDuplicate: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_NoInline: handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. diff --git a/clang/test/CodeGen/noduplicate-cxx11-test.cpp b/clang/test/CodeGen/noduplicate-cxx11-test.cpp new file mode 100644 index 000000000000..01278632bffb --- /dev/null +++ b/clang/test/CodeGen/noduplicate-cxx11-test.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple=i686-pc-unknown -std=c++11 %s -emit-llvm -o - | FileCheck %s + +// This was a problem in Sema, but only shows up as noinline missing +// in CodeGen. + +// CHECK: define i32 @_Z15noduplicatedfuni(i32 %a) [[NI:#[0-9]+]] + +int noduplicatedfun [[clang::noduplicate]] (int a) { + + return a+1; + +} + +int main() { + + return noduplicatedfun(5); + +} + +// CHECK: attributes [[NI]] = { noduplicate nounwind{{.*}} } diff --git a/clang/test/Sema/attr-noduplicate.c b/clang/test/Sema/attr-noduplicate.c new file mode 100644 index 000000000000..2a77de50c038 --- /dev/null +++ b/clang/test/Sema/attr-noduplicate.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +int a __attribute__((noduplicate)); // expected-warning {{'noduplicate' attribute only applies to functions}} + +void t1() __attribute__((noduplicate)); + +void t2() __attribute__((noduplicate(2))); // expected-error {{'noduplicate' attribute takes no arguments}} +