zequanwu updated this revision to Diff 311062.
zequanwu marked an inline comment as done.
zequanwu added a comment.

Add docs.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92800

Files:
  clang/include/clang/AST/Attr.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/attr-nomerge.cpp
  clang/test/Sema/attr-nomerge.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp
  llvm/include/llvm/IR/Attributes.td

Index: llvm/include/llvm/IR/Attributes.td
===================================================================
--- llvm/include/llvm/IR/Attributes.td
+++ llvm/include/llvm/IR/Attributes.td
@@ -121,7 +121,7 @@
 /// Function is called early and/or often, so lazy binding isn't worthwhile.
 def NonLazyBind : EnumAttr<"nonlazybind">;
 
-/// Disable merging for call sites
+/// Disable merging for specified functions or call sites.
 def NoMerge : EnumAttr<"nomerge">;
 
 /// Pointer is known to be not null.
Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -2682,6 +2682,7 @@
   { "ATTR", "Attr" },
   { "TYPE_ATTR", "TypeAttr" },
   { "STMT_ATTR", "StmtAttr" },
+  { "DECL_OR_STMT_ATTR", "DeclOrStmtAttr" },
   { "INHERITABLE_ATTR", "InheritableAttr" },
   { "DECL_OR_TYPE_ATTR", "DeclOrTypeAttr" },
   { "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
@@ -3767,7 +3768,8 @@
     OS << (Attr.isSubClassOf("TypeAttr") ||
            Attr.isSubClassOf("DeclOrTypeAttr")) << ";\n";
     OS << "    IsStmt = ";
-    OS << Attr.isSubClassOf("StmtAttr") << ";\n";
+    OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr"))
+       << ";\n";
     OS << "    IsKnownToGCC = ";
     OS << IsKnownToGCC(Attr) << ";\n";
     OS << "    IsSupportedByPragmaAttribute = ";
Index: clang/test/Sema/attr-nomerge.cpp
===================================================================
--- clang/test/Sema/attr-nomerge.cpp
+++ clang/test/Sema/attr-nomerge.cpp
@@ -8,10 +8,10 @@
   int x;
   [[clang::nomerge]] x = 10; // expected-warning {{nomerge attribute is ignored because there exists no call expression inside the statement}}
 
-  [[clang::nomerge]] label: bar(); // expected-error {{'nomerge' attribute cannot be applied to a declaration}}
+  [[clang::nomerge]] label: bar(); // expected-warning {{'nomerge' attribute only applies to functions and methods}}
 
 }
 
-int f();
+[[clang::nomerge]] int f();
 
-[[clang::nomerge]] static int i = f(); // expected-error {{'nomerge' attribute cannot be applied to a declaration}}
+[[clang::nomerge]] static int i = f(); // expected-warning {{'nomerge' attribute only applies to functions and methods}}
Index: clang/test/CodeGen/attr-nomerge.cpp
===================================================================
--- clang/test/CodeGen/attr-nomerge.cpp
+++ clang/test/CodeGen/attr-nomerge.cpp
@@ -1,9 +1,23 @@
 // RUN: %clang_cc1 -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
 
-bool bar();
-void f(bool, bool);
+class A {
+public:
+  [[clang::nomerge]] A();
+  [[clang::nomerge]] ~A();
+  [[clang::nomerge]] void f();
+  [[clang::nomerge]] virtual void g();
+  [[clang::nomerge]] static void f1();
+};
 
-void foo(int i) {
+class B : public A {
+public:
+  void g() override;
+};
+
+[[clang::nomerge]] bool bar();
+[[clang::nomerge]] void f(bool, bool);
+
+void foo(int i, A *ap, B *bp) {
   [[clang::nomerge]] bar();
   [[clang::nomerge]] (i = 4, bar());
   [[clang::nomerge]] (void)(bar());
@@ -12,18 +26,48 @@
   [[clang::nomerge]] for (bar(); bar(); bar()) {}
   [[clang::nomerge]] { asm("nop"); }
   bar();
+
+  ap->g();
+  bp->g();
+
+  A a;
+  a.f();
+  a.g();
+  A::f1();
+
+  B b;
+  b.g();
 }
-// 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: call void @"_ZZ3fooiENK3$_0clEv"(%class.anon* {{[^,]*}} %ref.tmp) #[[NOMERGEATTR]]
-// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
-// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
-// CHECK: call zeroext i1 @_Z3barv() #[[NOMERGEATTR]]
-// CHECK: call void asm {{.*}} #[[NOMERGEATTR2:[0-9]+]]
-// CHECK: call zeroext i1 @_Z3barv()
-// CHECK: attributes #[[NOMERGEATTR]] = { nomerge }
-// CHECK: attributes #[[NOMERGEATTR2]] = { nomerge nounwind }
+
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call void @_Z1fbb({{.*}}){{$}}
+// CHECK: call void @"_ZZ3fooiP1AP1BENK3$_0clEv"{{.*}} #[[ATTR0:[0-9]+]]
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: call void asm sideeffect "nop"{{.*}} #[[ATTR1:[0-9]+]]
+// CHECK: call zeroext i1 @_Z3barv(){{$}}
+// CHECK: %[[AG:.*]] = load void (%class.A*)*, void (%class.A*)**
+// CHECK-NEXT: call void %[[AG]](%class.A* nonnull dereferenceable
+// CHECK: %[[BG:.*]] = load void (%class.B*)*, void (%class.B*)**
+// CHECK-NEXT: call void %[[BG]](%class.B* nonnull dereferenceable
+
+
+// CHECK-DAG: declare zeroext i1 @_Z3barv() #[[ATTR2:[0-9]+]]
+// CHECK-DAG: declare void @_Z1fbb(i1 zeroext, i1 zeroext) #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1AC1Ev{{.*}} #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1A1fEv{{.*}} #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1A1gEv{{.*}} #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1A2f1Ev{{.*}} #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1AC2Ev{{.*}} #[[ATTR2]]
+// CHECK-DAG: declare void @_ZN1AD1Ev{{.*}} #[[ATTR3:[0-9]+]]
+// CHECK-DAG: declare void @_ZN1AD2Ev{{.*}} #[[ATTR3]]
+
+// CHECK-DAG: attributes #[[ATTR0]] = {{{.*}}nomerge{{.*}}}
+// CHECK-DAG: attributes #[[ATTR1]] = {{{.*}}nomerge{{.*}}}
+// CHECK-DAG: attributes #[[ATTR2]] = {{{.*}}nomerge{{.*}}}
+// CHECK-DAG: attributes #[[ATTR3]] = {{{.*}}nomerge{{.*}}}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2182,6 +2182,16 @@
   D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
 }
 
+static void handleNoMergeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (!isFunctionOrMethod(D)) {
+    S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
+        << AL << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) NoMergeAttr(S.Context, AL));
+}
+
 template <typename AttrTy>
 static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
   // Handle the case where the attribute has a text message.
@@ -7743,6 +7753,9 @@
     handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D,
                                                                          AL);
     break;
+  case ParsedAttr::AT_NoMerge:
+    handleNoMergeAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_Visibility:
     handleVisibilityAttr(S, D, AL, false);
     break;
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1966,6 +1966,8 @@
           FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
         NBA = Fn->getAttr<NoBuiltinAttr>();
       }
+      if (!AttrOnCallSite && TargetDecl->hasAttr<NoMergeAttr>())
+        FuncAttrs.addAttribute(llvm::Attribute::NoMerge);
     }
 
     // 'const', 'pure' and 'noalias' attributed functions are also nounwind.
@@ -4873,11 +4875,13 @@
         Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
                            llvm::Attribute::StrictFP);
 
-  // Add call-site nomerge attribute if exists.
-  if (InNoMergeAttributedStmt)
-    Attrs =
-      Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
-                         llvm::Attribute::NoMerge);
+  // Add nomerge attribute to the call-site if the callee function doesn't have
+  // the attribute.
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
+    if (!FD->hasAttr<NoMergeAttr>() && InNoMergeAttributedStmt)
+      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/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -386,7 +386,11 @@
 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.
+over the tradeoff between code size and debug information precision. 
+
+``nomerge`` attribute can also be used as function attribute to prevent all 
+calls to the specified function from merging. It has no effect on indirect 
+calls.
   }];
 }
 
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -555,6 +555,9 @@
 /// A stmt attribute is not processed on a declaration or a type.
 class StmtAttr : Attr;
 
+/// A attribute is either a declaration attribute or a statement attribute.
+class DeclOrStmtAttr : Attr;
+
 /// An inheritable attribute is inherited by later redeclarations.
 class InheritableAttr : Attr {
   // Set to true if this attribute can be duplicated on a subject when inheriting
@@ -1312,7 +1315,7 @@
   let Documentation = [LikelihoodDocs];
 }
 
-def NoMerge : StmtAttr {
+def NoMerge : DeclOrStmtAttr {
   let Spellings = [Clang<"nomerge">];
   let Documentation = [NoMergeDocs];
 }
Index: clang/include/clang/AST/Attr.h
===================================================================
--- clang/include/clang/AST/Attr.h
+++ clang/include/clang/AST/Attr.h
@@ -137,6 +137,19 @@
   }
 };
 
+class DeclOrStmtAttr : public Attr {
+protected:
+  DeclOrStmtAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+                 attr::Kind AK, bool IsLateParsed)
+      : Attr(Context, CommonInfo, AK, IsLateParsed) {}
+
+public:
+  static bool classof(const Attr *A) {
+    return A->getKind() >= attr::FirstDeclOrStmtAttr &&
+           A->getKind() <= attr::LastDeclOrStmtAttr;
+  }
+};
+
 class InheritableAttr : public Attr {
 protected:
   InheritableAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to