Exposing the noduplicate attribute within Clang, which marks functions so that the optimizer does not duplicate code.

Patch thanks to Marcello Maggioni!

llvm-svn: 201941
This commit is contained in:
Aaron Ballman 2014-02-22 16:59:24 +00:00
parent 9d2c15eff7
commit 7c19ab17c7
8 changed files with 128 additions and 1 deletions

View File

@ -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
===================

View File

@ -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]>;

View File

@ -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.
}];
}
}

View File

@ -1052,6 +1052,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
if (TargetDecl->hasAttr<NoReturnAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
if (TargetDecl->hasAttr<NoDuplicateAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();

View File

@ -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<NoDuplicateAttr>()) {
B.addAttribute(llvm::Attribute::NoDuplicate);
} else if (D->hasAttr<NoInlineAttr>()) {
B.addAttribute(llvm::Attribute::NoInline);
} else if ((D->hasAttr<AlwaysInlineAttr>() ||

View File

@ -4237,6 +4237,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttribute<PureAttr>(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<NoDuplicateAttr>(S, D, Attr); break;
case AttributeList::AT_NoInline:
handleSimpleAttribute<NoInlineAttr>(S, D, Attr); break;
case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg.

View File

@ -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{{.*}} }

View File

@ -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}}