Skip to content

[Clang] __attribute__((assume)) refactor #84934

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1640,10 +1640,11 @@ def Unlikely : StmtAttr {
def : MutualExclusions<[Likely, Unlikely]>;

def CXXAssume : StmtAttr {
let Spellings = [CXX11<"", "assume", 202207>];
let Spellings = [CXX11<"", "assume", 202207>, Clang<"assume">];
let Subjects = SubjectList<[NullStmt], ErrorDiag, "empty statements">;
let Args = [ExprArgument<"Assumption">];
let Documentation = [CXXAssumeDocs];
let HasCustomParsing = 1;
}

def NoMerge : DeclOrStmtAttr {
Expand Down Expand Up @@ -4255,7 +4256,7 @@ def OMPDeclareVariant : InheritableAttr {
}

def OMPAssume : InheritableAttr {
let Spellings = [Clang<"assume">, CXX11<"omp", "assume">];
let Spellings = [CXX11<"omp", "assume">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let InheritEvenIfAlreadyPresent = 1;
let Documentation = [OMPAssumeDocs];
Expand Down
7 changes: 2 additions & 5 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -2027,9 +2027,6 @@ Different optimisers are likely to react differently to the presence of
this attribute; in some cases, adding ``assume`` may affect performance
negatively. It should be used with parsimony and care.

Note that `clang::assume` is a different attribute. Always write ``assume``
without a namespace if you intend to use the standard C++ attribute.

Example:

.. code-block:: c++
Expand Down Expand Up @@ -4740,7 +4737,7 @@ def OMPAssumeDocs : Documentation {
let Category = DocCatFunction;
let Heading = "assume";
let Content = [{
Clang supports the ``__attribute__((assume("assumption")))`` attribute to
Clang supports the ``[[omp::assume("assumption")]]`` attribute to
provide additional information to the optimizer. The string-literal, here
"assumption", will be attached to the function declaration such that later
analysis and optimization passes can assume the "assumption" to hold.
Expand All @@ -4752,7 +4749,7 @@ A function can have multiple assume attributes and they propagate from prior
declarations to later definitions. Multiple assumptions are aggregated into a
single comma separated string. Thus, one can provide multiple assumptions via
a comma separated string, i.a.,
``__attribute__((assume("assumption1,assumption2")))``.
``[[omp::assume("assumption1,assumption2")]]``.

While LLVM plugins might provide more assumption strings, the default LLVM
optimization passes are aware of the following assumptions:
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10239,9 +10239,6 @@ def err_fallthrough_attr_outside_switch : Error<
def err_fallthrough_attr_invalid_placement : Error<
"fallthrough annotation does not directly precede switch label">;

def err_assume_attr_args : Error<
"attribute '%0' requires a single expression argument">;

def warn_unreachable_default : Warning<
"default label in switch which covers all enumeration values">,
InGroup<CoveredSwitchDefault>, DefaultIgnore;
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2997,7 +2997,8 @@ class Parser : public CodeCompletionHandler {
bool ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
SourceLocation *EndLoc);
SourceLocation *EndLoc,
ParsedAttr::Form Form);

IdentifierInfo *TryParseCXX11AttributeIdentifier(
SourceLocation &Loc,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@ void Parser::ParseGNUAttributeArgs(
ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc,
Form);
return;
} else if (AttrKind == ParsedAttr::AT_CXXAssume) {
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
return;
}

// These may refer to the function arguments, but need to be parsed early to
Expand Down Expand Up @@ -720,6 +723,10 @@ unsigned Parser::ParseClangAttributeArgs(
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Form);
break;

case ParsedAttr::AT_CXXAssume:
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
break;
}
return !Attrs.empty() ? Attrs.begin()->getNumArgs() : 0;
}
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4560,7 +4560,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
SourceLocation *EndLoc) {
SourceLocation *EndLoc,
ParsedAttr::Form Form) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
Expand Down Expand Up @@ -4603,7 +4604,7 @@ bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
auto RParen = Tok.getLocation();
T.consumeClose();
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr,
SourceLocation(), &Assumption, 1, ParsedAttr::Form::CXX11());
SourceLocation(), &Assumption, 1, Form);

if (EndLoc)
*EndLoc = RParen;
Expand Down Expand Up @@ -4683,7 +4684,7 @@ bool Parser::ParseCXX11AttributeArgs(
ScopeName, ScopeLoc, Form);
// So does C++23's assume() attribute.
else if (!ScopeName && AttrName->isStr("assume")) {
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc))
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form))
return true;
NumArgs = 1;
} else
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,8 @@ bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
SourceRange Range) {
if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) {
Diag(A.getLoc(), diag::err_assume_attr_args) << A.getAttrName() << Range;
Diag(A.getLoc(), diag::err_attribute_wrong_number_arguments)
<< A.getAttrName() << 1 << Range;
return ExprError();
}

Expand All @@ -682,8 +683,11 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
Assumption = Res.get();
}

if (!getLangOpts().CPlusPlus23)
if (!getLangOpts().CPlusPlus23 &&
A.getSyntax() == AttributeCommonInfo::AS_CXX11) {
llvm::dbgs() << "Syntax: " << int(A.getSyntax()) << "\n";
Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range;
}

return Assumption;
}
Expand Down
58 changes: 0 additions & 58 deletions clang/test/CodeGen/assume_attr.c

This file was deleted.

48 changes: 24 additions & 24 deletions clang/test/CodeGenCXX/assume_attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,77 @@

/// foo: declarations only

__attribute__((assume("foo:before1"))) void foo();
[[omp::assume("foo:before1")]] void foo();

__attribute__((assume("foo:before2")))
__attribute__((assume("foo:before3"))) void
[[omp::assume("foo:before2")]]
[[omp::assume("foo:before3")]] void
foo();

/// baz: static function declarations and a definition

__attribute__((assume("baz:before1"))) static void baz();
[[omp::assume("baz:before1")]] static void baz();

__attribute__((assume("baz:before2")))
__attribute__((assume("baz:before3"))) static void
[[omp::assume("baz:before2")]]
[[omp::assume("baz:before3")]] static void
baz();

// Definition
__attribute__((assume("baz:def1,baz:def2"))) static void baz() { foo(); }
[[omp::assume("baz:def1,baz:def2")]] static void baz() { foo(); }

__attribute__((assume("baz:after"))) static void baz();
[[omp::assume("baz:after")]] static void baz();

/// bar: external function declarations and a definition

__attribute__((assume("bar:before1"))) void bar();
[[omp::assume("bar:before1")]] void bar();

__attribute__((assume("bar:before2")))
__attribute__((assume("bar:before3"))) void
[[omp::assume("bar:before2")]]
[[omp::assume("bar:before3")]] void
bar();

// Definition
__attribute__((assume("bar:def1,bar:def2"))) void bar() { baz(); }
[[omp::assume("bar:def1,bar:def2")]] void bar() { baz(); }

__attribute__((assume("bar:after"))) void bar();
[[omp::assume("bar:after")]] void bar();

/// back to foo

__attribute__((assume("foo:after"))) void foo();
[[omp::assume("foo:after")]] void foo();

/// class tests
class C {
__attribute__((assume("C:private_method"))) void private_method();
__attribute__((assume("C:private_static"))) static void private_static();
[[omp::assume("C:private_method")]] void private_method();
[[omp::assume("C:private_static")]] static void private_static();

public:
__attribute__((assume("C:public_method1"))) void public_method();
__attribute__((assume("C:public_static1"))) static void public_static();
[[omp::assume("C:public_method1")]] void public_method();
[[omp::assume("C:public_static1")]] static void public_static();
};

__attribute__((assume("C:public_method2"))) void C::public_method() {
[[omp::assume("C:public_method2")]] void C::public_method() {
private_method();
}

__attribute__((assume("C:public_static2"))) void C::public_static() {
[[omp::assume("C:public_static2")]] void C::public_static() {
private_static();
}

/// template tests
template <typename T>
__attribute__((assume("template_func<T>"))) void template_func() {}
[[omp::assume("template_func<T>")]] void template_func() {}

template <>
__attribute__((assume("template_func<float>"))) void template_func<float>() {}
[[omp::assume("template_func<float>")]] void template_func<float>() {}

template <>
void template_func<int>() {}

template <typename T>
struct S {
__attribute__((assume("S<T>::method"))) void method();
[[omp::assume("S<T>::method")]] void method();
};

template <>
__attribute__((assume("S<float>::method"))) void S<float>::method() {}
[[omp::assume("S<float>::method")]] void S<float>::method() {}

template <>
void S<int>::method() {}
Expand Down
80 changes: 40 additions & 40 deletions clang/test/OpenMP/assumes_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,46 +67,46 @@ int lambda_outer() {
}
#pragma omp end assumes

// AST: void foo() __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
// AST-NEXT: }
// AST-NEXT: class BAR {
// AST-NEXT: public:
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAR() {
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar1() {
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void bar2() {
// AST-NEXT: }
// AST-NEXT: };
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar() {
// AST-NEXT: BAR b;
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz();
// AST-NEXT: template <typename T> class BAZ {
// AST-NEXT: public:
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ<T>() {
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1() {
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2() {
// AST-NEXT: }
// AST-NEXT: };
// AST-NEXT: template<> class BAZ<float> {
// AST-NEXT: public:
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ() {
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1();
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2();
// AST-NEXT: };
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz() {
// AST-NEXT: BAZ<float> b;
// AST-NEXT: }
// AST-NEXT: __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) int lambda_outer() {
// AST-NEXT: auto lambda_inner = []() {
// AST-NEXT: return 42;
// AST-NEXT: };
// AST-NEXT: return lambda_inner();
// AST-NEXT: }
// AST{LITERAL}: void foo() [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: class BAR {
// AST-NEXT{LITERAL}: public:
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAR() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar1() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void bar2() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: };
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar() {
// AST-NEXT{LITERAL}: BAR b;
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz();
// AST-NEXT{LITERAL}: template <typename T> class BAZ {
// AST-NEXT{LITERAL}: public:
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ<T>() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: };
// AST-NEXT{LITERAL}: template<> class BAZ<float> {
// AST-NEXT{LITERAL}: public:
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ() {
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1();
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2();
// AST-NEXT{LITERAL}: };
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz() {
// AST-NEXT{LITERAL}: BAZ<float> b;
// AST-NEXT{LITERAL}: }
// AST-NEXT{LITERAL}: [[omp::assume("ompx_lambda_assumption")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] int lambda_outer() {
// AST-NEXT{LITERAL}: auto lambda_inner = []() {
// AST-NEXT{LITERAL}: return 42;
// AST-NEXT{LITERAL}: };
// AST-NEXT{LITERAL}: return lambda_inner();
// AST-NEXT{LITERAL}: }

#endif

Expand Down
Loading
Loading