zequanwu updated this revision to Diff 261698.
zequanwu marked 4 inline comments as done.
zequanwu added a comment.

Add Sema test.
Check if nomerge attribute has no arguments and statement contains call 
expressions.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79121/new/

https://reviews.llvm.org/D79121

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/test/CodeGen/attr-nomerge.cpp
  clang/test/Sema/attr-nomerge.cpp

Index: clang/test/Sema/attr-nomerge.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-nomerge.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+void bar();
+
+void foo() {
+  [[clang::nomerge]] bar();
+  [[clang::nomerge(1, 2)]] bar(); // expected-error {{'nomerge' attribute takes no arguments}}
+  int x;
+  [[clang::nomerge]] x = 10; // expected-warning {{nomerge attribute is ignored because there exists no call expression inside the statement}}
+}
Index: clang/test/CodeGen/attr-nomerge.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-nomerge.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -S -emit-llvm %s -o - | FileCheck %s
+
+bool bar();
+void f(bool, bool);
+
+void foo(int i) {
+  [[clang::nomerge]] bar();
+  [[clang::nomerge]] (i = 4, bar());
+  [[clang::nomerge]] (void)(bar());
+  [[clang::nomerge]] f(bar(), bar());
+  bar();
+}
+// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR:[0-9]+]]
+// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
+// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
+// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
+// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
+// CHECK: call void @_Z1fbb({{.*}}) #[[NOMERGEATTR]]
+// CHECK-NEXT: call zeroext i1 @_Z3barv()
+// CHECK: attributes #[[NOMERGEATTR]] = { nomerge }
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -169,6 +169,28 @@
 
   return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
 }
+static bool hasCallExpr(Stmt *S) {
+  if (S->getStmtClass() == Stmt::CallExprClass)
+    return true;
+  for (Stmt *SubStmt : S->children()) {
+    if (hasCallExpr(SubStmt))
+      return true;
+  }
+  return false;
+}
+
+static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+                               SourceRange Range) {
+  NoMergeAttr attribute(S.Context, A);
+  if (S.CheckAttrNoArgs(A))
+    return nullptr;
+  if (!hasCallExpr(St)) {
+    S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt)
+        << attribute.getSpelling();
+    return nullptr;
+  }
+  return ::new (S.Context) NoMergeAttr(S.Context, A);
+}
 
 static void
 CheckForIncompatibleAttributes(Sema &S,
@@ -335,6 +357,8 @@
     return handleOpenCLUnrollHint(S, St, A, Range);
   case ParsedAttr::AT_Suppress:
     return handleSuppressAttr(S, St, A, Range);
+  case ParsedAttr::AT_NoMerge:
+    return handleNoMergeAttr(S, St, A, Range);
   default:
     // if we're here, then we parsed a known attribute, but didn't recognize
     // it as a statement attribute => it is declaration attribute
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -574,6 +574,9 @@
     ~SanitizerScope();
   };
 
+  /// True if the current statement has nomerge attribute.
+  bool NoMerge = false;
+
   /// In C++, whether we are code generating a thunk.  This controls whether we
   /// should emit cleanups.
   bool CurFuncIsThunk = false;
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -608,7 +608,13 @@
 }
 
 void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
+  for (const auto *A: S.getAttrs())
+    if (A->getKind() == attr::NoMerge) {
+      NoMerge = true;
+      break;
+    }
   EmitStmt(S.getSubStmt(), S.getAttrs());
+  NoMerge = false;
 }
 
 void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -4523,6 +4523,12 @@
         Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
                            llvm::Attribute::StrictFP);
 
+  // Add call-site nomerge attribute if exists.
+  if (NoMerge)
+    Attrs =
+      Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
+                         llvm::Attribute::NoMerge);
+
   // Apply some call-site-specific attributes.
   // TODO: work this into building the attribute set.
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2751,6 +2751,9 @@
   InGroup<DiagGroup<"auto-var-id">>;
 
 // Attributes
+def warn_nomerge_attribute_ignored_in_stmt: Warning<
+  "%0 attribute is ignored because there exists no call expression inside the "
+  "statement">;
 def err_nsobject_attribute : Error<
   "'NSObject' attribute is for pointer types only">;
 def err_attributes_are_not_compatible : Error<
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -350,6 +350,20 @@
   }];
 }
 
+def NoMergeDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+If a statement is marked ``nomerge`` and contains call experessions, those call
+expressions inside the statement will not be merged during optimization. This 
+attribute can be used to prevent the optimizer from obscuring the source
+location of certain calls. For example, it will prevent tail merging otherwise
+identical code sequences that raise an exception or terminate the program. Tail
+merging normally reduces the precision of source location information, making
+stack traces less useful for debugging. This attribute gives the user control
+over the tradeoff between code size and debug information precision.
+  }];
+}
+
 def AssertCapabilityDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "assert_capability, assert_shared_capability";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1275,6 +1275,11 @@
   let Documentation = [FallthroughDocs];
 }
 
+def NoMerge : StmtAttr {
+  let Spellings = [Clang<"nomerge">];
+  let Documentation = [NoMergeDocs];
+}
+
 def FastCall : DeclOrTypeAttr {
   let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
                    Keyword<"_fastcall">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to