Skip to content

[SYCL] Remove a parsing error and make it a semantic error #3158

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 4 commits into from
Feb 5, 2021
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
34 changes: 26 additions & 8 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1383,8 +1383,10 @@ def OpenCLUnrollHint : InheritableAttr {
let Documentation = [OpenCLUnrollHintDocs];
}

def LoopUnrollHint : InheritableAttr {
def LoopUnrollHint : StmtAttr {
let Spellings = [CXX11<"clang","loop_unroll">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"UnrollHintExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
Expand Down Expand Up @@ -1802,9 +1804,11 @@ def Mode : Attr {
let PragmaAttributeSupport = 0;
}

def SYCLIntelFPGAIVDep : Attr {
def SYCLIntelFPGAIVDep : StmtAttr {
let Spellings = [CXX11<"intelfpga","ivdep">,
CXX11<"intel","ivdep">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [
ExprArgument<"SafelenExpr">, ExprArgument<"ArrayExpr">,
UnsignedArgument<"SafelenValue">
Expand Down Expand Up @@ -1850,58 +1854,72 @@ def SYCLIntelFPGAInitiationInterval : StmtAttr {
let Spellings = [CXX11<"intelfpga","ii">,
CXX11<"intel","ii">,
CXX11<"intel", "initiation_interval">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"IntervalExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGAInitiationIntervalAttrDocs];
}

def SYCLIntelFPGAMaxConcurrency : Attr {
def SYCLIntelFPGAMaxConcurrency : StmtAttr {
let Spellings = [CXX11<"intelfpga","max_concurrency">,
CXX11<"intel","max_concurrency">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"NThreadsExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGAMaxConcurrencyAttrDocs];
}

def SYCLIntelFPGALoopCoalesce : Attr {
def SYCLIntelFPGALoopCoalesce : StmtAttr {
let Spellings = [CXX11<"intelfpga","loop_coalesce">,
CXX11<"intel","loop_coalesce">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"NExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGALoopCoalesceAttrDocs];
}

def SYCLIntelFPGADisableLoopPipelining : Attr {
def SYCLIntelFPGADisableLoopPipelining : StmtAttr {
let Spellings = [CXX11<"intelfpga","disable_loop_pipelining">,
CXX11<"intel","disable_loop_pipelining">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGADisableLoopPipeliningAttrDocs];
}

def SYCLIntelFPGAMaxInterleaving : Attr {
def SYCLIntelFPGAMaxInterleaving : StmtAttr {
let Spellings = [CXX11<"intelfpga","max_interleaving">,
CXX11<"intel","max_interleaving">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"NExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGAMaxInterleavingAttrDocs];
}

def SYCLIntelFPGASpeculatedIterations : Attr {
def SYCLIntelFPGASpeculatedIterations : StmtAttr {
let Spellings = [CXX11<"intelfpga","speculated_iterations">,
CXX11<"intel","speculated_iterations">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let Args = [ExprArgument<"NExpr">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGASpeculatedIterationsAttrDocs];
}

def SYCLIntelFPGANofusion : Attr {
def SYCLIntelFPGANofusion : StmtAttr {
let Spellings = [CXX11<"intel","nofusion">];
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
ErrorDiag, "'for', 'while', and 'do' statements">;
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let HasCustomTypeTransform = 1;
let Documentation = [SYCLIntelFPGANofusionAttrDocs];
Expand Down
6 changes: 0 additions & 6 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1433,12 +1433,6 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
"force_cuda_host_device begin">;
} // end of Parse Issue category.

// SYCL loop pragmas and attributes support
// * Intel FPGA attribute ivdep, ii, max_concurrency support
// * clang::loop_unroll attribute support
def err_loop_attr_on_non_loop : Error<
"%select{clang|intelfpga}0 loop attributes must be applied to for, while, or do statements">;

let CategoryName = "Modules Issue" in {
def err_unexpected_module_decl : Error<
"module declaration can only appear at the top level">;
Expand Down
8 changes: 0 additions & 8 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2767,14 +2767,6 @@ class Parser : public CodeCompletionHandler {
/// \return false if error happens.
bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs);

/// Parses intelfpga:: and clang:: loop attributes if the language is SYCL
bool MaybeParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
if (getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)
return ParseSYCLLoopAttributes(Attrs);
return true;
}
bool ParseSYCLLoopAttributes(ParsedAttributes &Attrs);

void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
VersionTuple ParseVersionTuple(SourceRange &Range);
void ParseAvailabilityAttribute(IdentifierInfo &Availability,
Expand Down
32 changes: 1 addition & 31 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,

ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs) ||
!MaybeParseSYCLLoopAttributes(Attrs))
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
return StmtError();

StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
Expand Down Expand Up @@ -2565,32 +2564,3 @@ bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
}
return true;
}

bool Parser::ParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
MaybeParseCXX11Attributes(Attrs);

if (Attrs.empty())
return true;

if (Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAIVDep &&
Attrs.begin()->getKind() !=
ParsedAttr::AT_SYCLIntelFPGAInitiationInterval &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGALoopCoalesce &&
Attrs.begin()->getKind() !=
ParsedAttr::AT_SYCLIntelFPGADisableLoopPipelining &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving &&
Attrs.begin()->getKind() !=
ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations &&
Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGANofusion)
return true;

bool IsIntelFPGAAttribute = (Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint);

if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
Diag(Tok, diag::err_loop_attr_on_non_loop) << IsIntelFPGAAttribute;
return false;
}
return true;
}
64 changes: 50 additions & 14 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,16 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
}

template <typename FPGALoopAttrT>
static Attr *handleIntelFPGALoopAttr(Sema &S, const ParsedAttr &A) {
static Attr *handleIntelFPGALoopAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
if(S.LangOpts.SYCLIsHost)
return nullptr;

if (!isa<ForStmt, CXXForRangeStmt, DoStmt, WhileStmt>(St)) {
S.Diag(A.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< A << "'for', 'while', and 'do' statements";
return nullptr;
}

unsigned NumArgs = A.getNumArgs();
if (NumArgs > 1) {
S.Diag(A.getLoc(), diag::warn_attribute_too_many_arguments) << A << 1;
Expand All @@ -104,10 +110,16 @@ static Attr *handleIntelFPGALoopAttr(Sema &S, const ParsedAttr &A) {

template <>
Attr *handleIntelFPGALoopAttr<SYCLIntelFPGADisableLoopPipeliningAttr>(
Sema &S, const ParsedAttr &A) {
Sema &S, Stmt *St, const ParsedAttr &A) {
if (S.LangOpts.SYCLIsHost)
return nullptr;

if (!isa<ForStmt, CXXForRangeStmt, DoStmt, WhileStmt>(St)) {
S.Diag(A.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< A << "'for', 'while', and 'do' statements";
return nullptr;
}

unsigned NumArgs = A.getNumArgs();
if (NumArgs > 0) {
S.Diag(A.getLoc(), diag::warn_attribute_too_many_arguments) << A << 0;
Expand Down Expand Up @@ -270,7 +282,13 @@ CheckRedundantSYCLIntelFPGAIVDepAttrs(Sema &S, ArrayRef<const Attr *> Attrs) {
}
}

static Attr *handleIntelFPGAIVDepAttr(Sema &S, const ParsedAttr &A) {
static Attr *handleIntelFPGAIVDepAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
if (!isa<ForStmt, CXXForRangeStmt, DoStmt, WhileStmt>(St)) {
S.Diag(A.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< A << "'for', 'while', and 'do' statements";
return nullptr;
}

unsigned NumArgs = A.getNumArgs();
if (NumArgs > 2) {
S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A << 2;
Expand All @@ -284,10 +302,17 @@ static Attr *handleIntelFPGAIVDepAttr(Sema &S, const ParsedAttr &A) {
NumArgs == 2 ? A.getArgAsExpr(1) : nullptr);
}

static Attr *handleIntelFPGANofusionAttr(Sema &S, const ParsedAttr &A) {
static Attr *handleIntelFPGANofusionAttr(Sema &S, Stmt *St,
const ParsedAttr &A) {
if (S.LangOpts.SYCLIsHost)
return nullptr;

if (!isa<ForStmt, CXXForRangeStmt, DoStmt, WhileStmt>(St)) {
S.Diag(A.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< A << "'for', 'while', and 'do' statements";
return nullptr;
}

unsigned NumArgs = A.getNumArgs();
if (NumArgs > 0) {
S.Diag(A.getLoc(), diag::warn_attribute_too_many_arguments) << A << 0;
Expand Down Expand Up @@ -751,8 +776,17 @@ static Attr *handleLoopUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
Expr *E = NumArgs ? A.getArgAsExpr(0) : nullptr;
if (A.getParsedKind() == ParsedAttr::AT_OpenCLUnrollHint)
return S.BuildOpenCLLoopUnrollHintAttr(A, E);
else if (A.getParsedKind() == ParsedAttr::AT_LoopUnrollHint)
else if (A.getParsedKind() == ParsedAttr::AT_LoopUnrollHint) {
// FIXME: this should be hoisted up to the top level, but can't be placed
// there until the opencl attribute has its parsing error converted into a
// semantic error. See: Parser::ParseOpenCLUnrollHintAttribute().
if (!isa<ForStmt, CXXForRangeStmt, DoStmt, WhileStmt>(St)) {
S.Diag(A.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< A << "'for', 'while', and 'do' statements";
return nullptr;
}
return S.BuildLoopUnrollHintAttr(A, E);
}

return nullptr;
}
Expand All @@ -771,20 +805,22 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
case ParsedAttr::AT_LoopHint:
return handleLoopHintAttr(S, St, A, Range);
case ParsedAttr::AT_SYCLIntelFPGAIVDep:
return handleIntelFPGAIVDepAttr(S, A);
return handleIntelFPGAIVDepAttr(S, St, A);
case ParsedAttr::AT_SYCLIntelFPGAInitiationInterval:
return handleIntelFPGALoopAttr<SYCLIntelFPGAInitiationIntervalAttr>(S, A);
return handleIntelFPGALoopAttr<SYCLIntelFPGAInitiationIntervalAttr>(S, St,
A);
case ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency:
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxConcurrencyAttr>(S, A);
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxConcurrencyAttr>(S, St, A);
case ParsedAttr::AT_SYCLIntelFPGALoopCoalesce:
return handleIntelFPGALoopAttr<SYCLIntelFPGALoopCoalesceAttr>(S, A);
return handleIntelFPGALoopAttr<SYCLIntelFPGALoopCoalesceAttr>(S, St, A);
case ParsedAttr::AT_SYCLIntelFPGADisableLoopPipelining:
return handleIntelFPGALoopAttr<SYCLIntelFPGADisableLoopPipeliningAttr>(S,
A);
return handleIntelFPGALoopAttr<SYCLIntelFPGADisableLoopPipeliningAttr>(
S, St, A);
case ParsedAttr::AT_SYCLIntelFPGAMaxInterleaving:
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxInterleavingAttr>(S, A);
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxInterleavingAttr>(S, St, A);
case ParsedAttr::AT_SYCLIntelFPGASpeculatedIterations:
return handleIntelFPGALoopAttr<SYCLIntelFPGASpeculatedIterationsAttr>(S, A);
return handleIntelFPGALoopAttr<SYCLIntelFPGASpeculatedIterationsAttr>(S, St,
A);
case ParsedAttr::AT_OpenCLUnrollHint:
case ParsedAttr::AT_LoopUnrollHint:
return handleLoopUnrollHint(S, St, A, Range);
Expand All @@ -797,7 +833,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
case ParsedAttr::AT_Unlikely:
return handleUnlikely(S, St, A, Range);
case ParsedAttr::AT_SYCLIntelFPGANofusion:
return handleIntelFPGANofusionAttr(S, A);
return handleIntelFPGANofusionAttr(S, St, A);
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
Expand Down
36 changes: 19 additions & 17 deletions clang/test/SemaSYCL/intel-fpga-loops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,21 @@

// Test for Intel FPGA loop attributes applied not to a loop
void foo() {
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'ivdep' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::ivdep]] int a[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intel::ivdep(2)]] int b[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'initiation_interval' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::initiation_interval(2)]] int c[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'max_concurrency' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::max_concurrency(2)]] int d[10];

int arr[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intel::ivdep(arr)]] int e[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intel::ivdep(arr, 2)]] int f[10];

// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'disable_loop_pipelining' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::disable_loop_pipelining]] int g[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'loop_coalesce' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::loop_coalesce(2)]] int h[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'max_interleaving' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::max_interleaving(4)]] int i[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'speculated_iterations' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::speculated_iterations(6)]] int j[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'nofusion' attribute only applies to 'for', 'while', and 'do' statements}}
[[intel::nofusion]] int k[10];
}

Expand Down Expand Up @@ -426,3 +417,14 @@ int main() {
});
return 0;
}

void parse_order_error() {
// We had a bug where we would only look at the first attribute in the group
// when trying to determine whether to diagnose the loop attributes on an
// incorrect subject. Test that we properly catch this situation.
[[clang::nomerge, intel::max_concurrency(1)]] // expected-error {{'max_concurrency' attribute only applies to 'for', 'while', and 'do' statements}}
if (1) { parse_order_error(); } // Recursive call silences unrelated diagnostic about nomerge.

[[clang::nomerge, intel::max_concurrency(1)]] // OK
while (1) { parse_order_error(); } // Recursive call silences unrelated diagnostic about nomerge.
}
2 changes: 1 addition & 1 deletion clang/test/SemaSYCL/loop_unroll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ void bar() {
}

void foo() {
// expected-error@+1 {{clang loop attributes must be applied to for, while, or do statements}}
// expected-error@+1 {{'loop_unroll' attribute only applies to 'for', 'while', and 'do' statements}}
[[clang::loop_unroll(8)]] int a[10];

// expected-error@+1 {{'loop_unroll' attribute takes no more than 1 argument}}
Expand Down
14 changes: 13 additions & 1 deletion clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3526,6 +3526,9 @@ static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) {
}

static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
// FIXME: this function only diagnoses declaration attributes and lacks
// reasonable support for statement attributes.

// If the attribute does not contain a Subjects definition, then use the
// default appertainsTo logic.
if (Attr.isValueUnset("Subjects"))
Expand Down Expand Up @@ -3557,7 +3560,16 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
// because it requires the subject to be of a specific type, and were that
// information inlined here, it would not support an attribute with multiple
// custom subjects.
if ((*I)->isSubClassOf("SubsetSubject")) {
//
// If the subject is a statement rather than a declaration node, use 'true'
// as the test so that statement nodes can be mixed with declaration nodes
// for attributes which appertain to both statements and declarations. If
// all of the nodes are statement nodes (so the diagnostic predicate is
// trivially true), this will diagnose the use of the attribute on any
// declaration, which is reasonable.
if ((*I)->isSubClassOf("StmtNode")) {
OS << "true";
} else if ((*I)->isSubClassOf("SubsetSubject")) {
OS << "!" << functionNameForCustomAppertainsTo(**I) << "(D)";
} else {
OS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
Expand Down