]> granicus.if.org Git - clang/commitdiff
Exposing the noduplicate attribute within Clang, which marks functions so that the...
authorAaron Ballman <aaron@aaronballman.com>
Sat, 22 Feb 2014 16:59:24 +0000 (16:59 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Sat, 22 Feb 2014 16:59:24 +0000 (16:59 +0000)
Patch thanks to Marcello Maggioni!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201941 91177308-0d34-0410-b5e6-96231b3b80d8

docs/AttributeReference.rst
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
lib/CodeGen/CGCall.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/noduplicate-cxx11-test.cpp [new file with mode: 0644]
test/Sema/attr-noduplicate.c [new file with mode: 0644]

index 1d41cb32cf6df40777721a4368327281eaa56631..84b5440ac30d871464405967db0fcb8a3846ed6c 100644 (file)
@@ -558,6 +558,50 @@ caveats to this use of name mangling:
 \r
 Query for this feature with ``__has_extension(attribute_overloadable)``.\r
 \r
+noduplicate\r
+-----------\r
+.. csv-table:: Supported Syntaxes\r
+   :header: "GNU", "C++11", "__declspec", "Keyword"\r
+\r
+   "X","X","",""\r
+\r
+The ``noduplicate`` attribute can be placed on function declarations to control\r
+whether function calls to this function can be duplicated \r
+or not as a result of optimizations. This is required for the implementation\r
+of functions with certain special requirements, like the OpenCL "barrier", \r
+function that, depending on the hardware, might require to be run concurrently\r
+by all the threads that are currently executing in lockstep on the hardware.\r
+For example this attribute applied on the function "nodupfunc" \r
+avoids that this code:\r
+\r
+.. code-block:: c\r
+\r
+  void nodupfunc() __attribute__((noduplicate));\r
+  // Setting it as a C++11 attribute is also valid\r
+  // void nodupfunc() [[clang::noduplicate]];\r
+  void foo();\r
+  void bar();\r
+\r
+  nodupfunc();\r
+  if (a > n) {\r
+    foo();\r
+  } else {\r
+    bar();\r
+  }\r
+\r
+gets possibly modified by some optimization into code similar to this:\r
+\r
+.. code-block:: c\r
+\r
+  if (a > n) {\r
+    nodupfunc();\r
+    foo();\r
+  } else {\r
+    nodupfunc();\r
+    bar();\r
+  }\r
+\r
+where the barrier call is duplicated and sunk into the two branches of the condition.\r
 \r
 Variable Attributes\r
 ===================\r
index 148de472063f00016a0a9a2f1345856cf5b20d11..9c28d631d2363bbef8d4e55585809f3d78b9e17a 100644 (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]>;
index c0f0fbcea13cf955cdf50f0d2fc441ccf822cb26..ebe4bb9abb2e6722052b5d6756540e311a1ab6ef 100644 (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.
   }];
-}
\ No newline at end of file
+}
index a9caa88706a82cd31adc7389a1959e9ea9eb4b0c..a21e4783b60b26376a2c3950c69e331ffda01e79 100644 (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>();
index bbf5a730f07dcf82b8966c7976c7905625b1995c..e6798e49a85ac97a1ee2e16b409aff86db4dd7e9 100644 (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>() ||
index 29e4bb7b3e26979ef669f273cffec7eac4cc37e5..1de06af775d5e4b4502473c48305824a6f80c70f 100644 (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.
diff --git a/test/CodeGen/noduplicate-cxx11-test.cpp b/test/CodeGen/noduplicate-cxx11-test.cpp
new file mode 100644 (file)
index 0000000..0127863
--- /dev/null
@@ -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/test/Sema/attr-noduplicate.c b/test/Sema/attr-noduplicate.c
new file mode 100644 (file)
index 0000000..2a77de5
--- /dev/null
@@ -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}}
+