eddyz87 updated this revision to Diff 533824.
eddyz87 added a comment.
Rebase, `nomerge` documentation updated.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D152986/new/
https://reviews.llvm.org/D152986
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/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/attr-nomerge.cpp
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/Parser/stmt-attributes.c
clang/test/Parser/stmt-attributes.cpp
clang/test/Parser/stmt-attributes.m
clang/test/Sema/attr-nomerge-ast.cpp
clang/test/Sema/attr-nomerge.cpp
Index: clang/test/Sema/attr-nomerge.cpp
===================================================================
--- clang/test/Sema/attr-nomerge.cpp
+++ clang/test/Sema/attr-nomerge.cpp
@@ -8,10 +8,14 @@
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 only applies to functions and statements}}
+ [[clang::nomerge]] label: bar(); // expected-error {{'nomerge' attribute only applies to functions, statements and variables}}
}
[[clang::nomerge]] int f();
-[[clang::nomerge]] static int i = f(); // expected-error {{'nomerge' attribute only applies to functions and statements}}
+[[clang::nomerge]] static int i = f(); // expected-warning {{'nomerge' attribute is ignored because 'i' is not a function pointer}}
+
+[[clang::nomerge]] void (*j)(void);
+
+struct [[clang::nomerge]] buz {}; // expected-error {{'nomerge' attribute only applies to functions, statements and variables}}
Index: clang/test/Sema/attr-nomerge-ast.cpp
===================================================================
--- clang/test/Sema/attr-nomerge-ast.cpp
+++ clang/test/Sema/attr-nomerge-ast.cpp
@@ -4,6 +4,7 @@
[[clang::nomerge]] void func();
void func();
[[clang::nomerge]] void func() {}
+[[clang::nomerge]] void (*var)(void);
// CHECK: FunctionDecl {{.*}} func 'void ()'
// CHECK-NEXT: NoMergeAttr
@@ -14,3 +15,6 @@
// CHECK-NEXT: FunctionDecl {{.*}} func 'void ()'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: NoMergeAttr
+
+// CHECK-NEXT: VarDecl {{.*}} var 'void (*)()'
+// CHECK-NEXT: NoMergeAttr
Index: clang/test/Parser/stmt-attributes.m
===================================================================
--- clang/test/Parser/stmt-attributes.m
+++ clang/test/Parser/stmt-attributes.m
@@ -19,7 +19,7 @@
@implementation Test
- (void)foo __attribute__((nomerge)) {
- // expected-error@-1 {{'nomerge' attribute only applies to functions and statements}}
+ // expected-error@-1 {{'nomerge' attribute only applies to functions, statements and variables}}
}
- (void)bar {
Index: clang/test/Parser/stmt-attributes.cpp
===================================================================
--- clang/test/Parser/stmt-attributes.cpp
+++ clang/test/Parser/stmt-attributes.cpp
@@ -6,7 +6,7 @@
template <typename T = void>
class __attribute__((nomerge)) A {
- // expected-error@-1 {{'nomerge' attribute only applies to functions and statements}}
+ // expected-error@-1 {{'nomerge' attribute only applies to functions, statements and variables}}
};
class B : public A<> {
Index: clang/test/Parser/stmt-attributes.c
===================================================================
--- clang/test/Parser/stmt-attributes.c
+++ clang/test/Parser/stmt-attributes.c
@@ -82,9 +82,11 @@
int x;
__attribute__((nomerge)) x = 10; // expected-warning {{'nomerge' attribute is ignored because there exists no call expression inside the statement}}
- __attribute__((nomerge)) label : bar(); // expected-error {{'nomerge' attribute only applies to functions and statements}}
+ __attribute__((nomerge)) label : bar(); // expected-error {{'nomerge' attribute only applies to functions, statements and variables}}
}
int f(void);
-__attribute__((nomerge)) static int i; // expected-error {{'nomerge' attribute only applies to functions and statements}}
+__attribute__((nomerge)) static int (*fptr)(void);
+__attribute__((nomerge)) static int i; // expected-warning {{'nomerge' attribute is ignored because 'i' is not a function pointer}}
+struct buz {} __attribute__((nomerge)); // expected-error {{'nomerge' attribute only applies to functions, statements and variables}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -104,7 +104,7 @@
// CHECK-NEXT: NoEscape (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: NoInline (SubjectMatchRule_function)
// CHECK-NEXT: NoInstrumentFunction (SubjectMatchRule_function, SubjectMatchRule_objc_method)
-// CHECK-NEXT: NoMerge (SubjectMatchRule_function)
+// CHECK-NEXT: NoMerge (SubjectMatchRule_function, SubjectMatchRule_variable)
// CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
// CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
// CHECK-NEXT: NoProfileFunction (SubjectMatchRule_function)
Index: clang/test/CodeGen/attr-nomerge.cpp
===================================================================
--- clang/test/CodeGen/attr-nomerge.cpp
+++ clang/test/CodeGen/attr-nomerge.cpp
@@ -16,12 +16,14 @@
bool bar();
[[clang::nomerge]] void f(bool, bool);
+[[clang::nomerge]] void (*fptr)(void);
void foo(int i, A *ap, B *bp) {
[[clang::nomerge]] bar();
[[clang::nomerge]] (i = 4, bar());
[[clang::nomerge]] (void)(bar());
f(bar(), bar());
+ fptr();
[[clang::nomerge]] [] { bar(); bar(); }(); // nomerge only applies to the anonymous function call
[[clang::nomerge]] for (bar(); bar(); bar()) {}
[[clang::nomerge]] { asm("nop"); }
@@ -66,6 +68,8 @@
// CHECK: call noundef zeroext i1 @_Z3barv(){{$}}
// CHECK: call noundef zeroext i1 @_Z3barv(){{$}}
// CHECK: call void @_Z1fbb({{.*}}) #[[ATTR0]]
+// CHECK: %[[FPTR:.*]] = load ptr, ptr @fptr
+// CHECK-NEXT: call void %[[FPTR]]() #[[ATTR0]]
// CHECK: call void @"_ZZ3fooiP1AP1BENK3$_0clEv"{{.*}} #[[ATTR0]]
// CHECK: call noundef zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK-LABEL: for.cond:
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8369,6 +8369,16 @@
D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
}
+static void handleNoMergeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ auto *VDecl = dyn_cast<VarDecl>(D);
+ if (VDecl && !VDecl->isFunctionPointerType()) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_ignored_non_function_pointer)
+ << AL << VDecl;
+ return;
+ }
+ D->addAttr(NoMergeAttr::Create(S.Context, AL));
+}
+
static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// The 'sycl_kernel' attribute applies only to function templates.
const auto *FD = cast<FunctionDecl>(D);
@@ -9249,6 +9259,9 @@
case ParsedAttr::AT_FunctionReturnThunks:
handleFunctionReturnThunksAttr(S, D, AL);
break;
+ case ParsedAttr::AT_NoMerge:
+ handleNoMergeAttr(S, D, AL);
+ break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -2341,6 +2341,9 @@
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
NBA = Fn->getAttr<NoBuiltinAttr>();
}
+ }
+
+ if (isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl)) {
// Only place nomerge attribute on call sites, never functions. This
// allows it to work on indirect virtual function calls.
if (AttrOnCallSite && TargetDecl->hasAttr<NoMergeAttr>())
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2981,6 +2981,10 @@
"statement">,
InGroup<IgnoredAttributes>;
+def warn_attribute_ignored_non_function_pointer: Warning<
+ "%0 attribute is ignored because %1 is not a function pointer">,
+ InGroup<IgnoredAttributes>;
+
def warn_function_attribute_ignored_in_stmt : Warning<
"attribute is ignored on this statement as it only applies to functions; "
"use '%0' on statements">,
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -547,9 +547,33 @@
stack traces less useful for debugging. This attribute gives the user control
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.
+``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 to such functions. For example:
+
+.. code-block:: c++
+
+ [[clang::nomerge]] void foo(int) {}
+
+ void bar(int x) {
+ auto *ptr = foo;
+ if (x) foo(1); else foo(2); // will not be merged
+ if (x) ptr(1); else ptr(2); // indirect call, can be merged
+ }
+
+``nomerge`` attribute can also be used for pointers to functions to
+prevent calls through such pointer from merging. In such case the
+effect applies only to a specific function pointer. For example:
+
+.. code-block:: c++
+
+ [[clang::nomerge]] void (*foo)(int);
+
+ void bar(int x) {
+ auto *ptr = foo;
+ if (x) foo(1); else foo(2); // will not be merged
+ if (x) ptr(1); else ptr(2); // 'ptr' has no 'nomerge' attribute, can be merged
+ }
}];
}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1482,9 +1482,8 @@
def NoMerge : DeclOrStmtAttr {
let Spellings = [Clang<"nomerge">];
let Documentation = [NoMergeDocs];
- let Subjects = SubjectList<[Function, Stmt], ErrorDiag,
- "functions and statements">;
- let SimpleHandler = 1;
+ let Subjects = SubjectList<[Function, Stmt, Var], ErrorDiag,
+ "functions, statements and variables">;
}
def MustTail : StmtAttr {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits