Add nomerge function attribute to clang

This commit is contained in:
Zequan Wu 2020-05-08 11:36:34 -07:00
parent f96a7706d9
commit 307e853954
9 changed files with 125 additions and 0 deletions

View File

@ -1275,6 +1275,11 @@ def FallThrough : StmtAttr {
let Documentation = [FallthroughDocs];
}
def NoMerge : StmtAttr {
let Spellings = [Clang<"nomerge">];
let Documentation = [NoMergeDocs];
}
def FastCall : DeclOrTypeAttr {
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
Keyword<"_fastcall">];

View File

@ -350,6 +350,20 @@ that appears to be capable of returning to its caller.
}];
}
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";

View File

@ -2762,6 +2762,10 @@ def warn_auto_var_is_id : Warning<
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">,
InGroup<IgnoredAttributes>;
def err_nsobject_attribute : Error<
"'NSObject' attribute is for pointer types only">;
def err_attributes_are_not_compatible : Error<

View File

@ -4822,6 +4822,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
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);
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.

View File

@ -25,6 +25,7 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
@ -608,6 +609,13 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
}
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
bool nomerge = false;
for (const auto *A: S.getAttrs())
if (A->getKind() == attr::NoMerge) {
nomerge = true;
break;
}
SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
EmitStmt(S.getSubStmt(), S.getAttrs());
}

View File

@ -595,6 +595,9 @@ public:
/// region.
bool IsInPreservedAIRegion = false;
/// True if the current statement has nomerge attribute.
bool InNoMergeAttributedStmt = false;
const CodeGen::CGBlockInfo *BlockInfo = nullptr;
llvm::Value *BlockPointer = nullptr;

View File

@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
@ -170,6 +171,45 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
}
namespace {
class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> {
bool FoundCallExpr = false;
public:
typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited;
CallExprFinder(Sema &S, const Stmt* St) : Inherited(S.Context) {
Visit(St);
}
bool foundCallExpr() { return FoundCallExpr; }
void VisitCallExpr(const CallExpr *E) { FoundCallExpr = true; }
void Visit(const Stmt *St) {
if (!St) return;
ConstEvaluatedExprVisitor<CallExprFinder>::Visit(St);
}
};
} // namespace
static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
NoMergeAttr NMA(S.Context, A);
if (S.CheckAttrNoArgs(A))
return nullptr;
CallExprFinder CEF(S, St);
if (!CEF.foundCallExpr()) {
S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt)
<< NMA.getSpelling();
return nullptr;
}
return ::new (S.Context) NoMergeAttr(S.Context, A);
}
static void
CheckForIncompatibleAttributes(Sema &S,
const SmallVectorImpl<const Attr *> &Attrs) {
@ -335,6 +375,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
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

View File

@ -0,0 +1,26 @@
// 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());
[[clang::nomerge]] [] { bar(); bar(); }(); // nomerge only applies to the anonymous function call
[[clang::nomerge]] for (bar(); 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: 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 zeroext i1 @_Z3barv()
// CHECK: attributes #[[NOMERGEATTR]] = { nomerge }

View File

@ -0,0 +1,17 @@
// 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}}
[[clang::nomerge]] label: bar(); // expected-error {{'nomerge' attribute cannot be applied to a declaration}}
}
int f();
[[clang::nomerge]] static int i = f(); // expected-error {{'nomerge' attribute cannot be applied to a declaration}}