Skip to content

Commit 2f1e243

Browse files
vmaksimobader
authored andcommitted
[SYCL] Enable C++11 attribute spelling for clang loop_unroll attribute (#670)
Signed-off-by: Viktoria Maksimova <[email protected]>
1 parent 5b0952c commit 2f1e243

File tree

12 files changed

+239
-50
lines changed

12 files changed

+239
-50
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,24 @@ def OpenCLUnrollHint : InheritableAttr {
11031103
let Documentation = [OpenCLUnrollHintDocs];
11041104
}
11051105

1106+
def LoopUnrollHint : InheritableAttr {
1107+
let Spellings = [CXX11<"clang","loop_unroll">];
1108+
let Args = [UnsignedArgument<"UnrollHint">];
1109+
let LangOpts = [SYCLIsDevice, SYCLIsHost];
1110+
let AdditionalMembers = [{
1111+
static const char *getName() {
1112+
return "loop_unroll";
1113+
}
1114+
std::string getDiagnosticName() const {
1115+
std::string Value = "";
1116+
if (getUnrollHint())
1117+
Value = "(" + std::to_string(getUnrollHint()) + ")";
1118+
return "[[clang::loop_unroll" + Value + "]]";
1119+
}
1120+
}];
1121+
let Documentation = [LoopUnrollHintDocs];
1122+
}
1123+
11061124
def IntelReqdSubGroupSize: InheritableAttr {
11071125
let Spellings = [GNU<"intel_reqd_sub_group_size">, CXX11<"cl", "intel_reqd_sub_group_size">];
11081126
let Args = [UnsignedArgument<"SubGroupSize">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3056,6 +3056,16 @@ s6.11.5 for details.
30563056
}];
30573057
}
30583058

3059+
def LoopUnrollHintDocs : Documentation {
3060+
let Category = DocCatStmt;
3061+
let Content = [{
3062+
Loop unrolling optimization hint can be specified with CXX11 attribute
3063+
``[[clang::loop_unroll]]``. The attribute is placed immediately before a for,
3064+
while, do-while, or c++11 range-based for loop. This attribute can be
3065+
used to specify full unrolling or partial unrolling by a specified amount.
3066+
}];
3067+
}
3068+
30593069
def IntelReqdSubGroupSizeDocs : Documentation {
30603070
let Category = DocCatStmt;
30613071
let Content = [{

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,10 +1242,11 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
12421242
"force_cuda_host_device begin">;
12431243
} // end of Parse Issue category.
12441244

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

12501251
let CategoryName = "Modules Issue" in {
12511252
def err_unexpected_module_decl : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,16 @@ def err_attribute_argument_not_power_of_two : Error<
127127
"%0 attribute argument must be a constant power of two greater than zero">;
128128
def err_intel_fpga_memory_arg_invalid : Error<
129129
"%0 attribute requires either no argument or one of: %1">;
130-
def err_intel_fpga_loop_attr_duplication : Error<
131-
"duplicate Intel FPGA loop attribute '%0'">;
132130
def err_intel_fpga_merge_dir_invalid : Error<
133131
"merge direction must be 'depth' or 'width'">;
134132
def err_intel_fpga_reg_limitations : Error <
135133
"Illegal %select{argument of type %1 |field in argument}0 to __builtin_intel_fpga_reg.">;
136134
def illegal_type_declared_here : Note<
137135
"Field with illegal type declared here">;
136+
def err_sycl_loop_attr_duplication : Error<
137+
"duplicate %select{unroll|Intel FPGA}0 loop attribute '%1'">;
138+
def err_loop_unroll_compatibility : Error<
139+
"incompatible loop unroll instructions: '%0' and '%1'">;
138140

139141
// C99 variable-length arrays
140142
def ext_vla : Extension<"variable length arrays are a C99 feature">,

clang/include/clang/Parse/Parser.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,13 +2554,13 @@ class Parser : public CodeCompletionHandler {
25542554
/// \return false if error happens.
25552555
bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs);
25562556

2557-
/// Parses intelfpga:: loop attributes if the language is SYCL
2558-
bool MaybeParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
2559-
if (getLangOpts().SYCLIsDevice)
2560-
return ParseIntelFPGALoopAttributes(Attrs);
2557+
/// Parses intelfpga:: and clang:: loop attributes if the language is SYCL
2558+
bool MaybeParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
2559+
if (getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)
2560+
return ParseSYCLLoopAttributes(Attrs);
25612561
return true;
25622562
}
2563-
bool ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs);
2563+
bool ParseSYCLLoopAttributes(ParsedAttributes &Attrs);
25642564

25652565
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
25662566
VersionTuple ParseVersionTuple(SourceRange &Range);

clang/lib/CodeGen/CGLoopInfo.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,23 +625,25 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
625625
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
626626
const OpenCLUnrollHintAttr *OpenCLHint =
627627
dyn_cast<OpenCLUnrollHintAttr>(Attr);
628+
const LoopUnrollHintAttr *UnrollHint = dyn_cast<LoopUnrollHintAttr>(Attr);
628629

629630
// Skip non loop hint attributes
630-
if (!LH && !OpenCLHint) {
631+
if (!LH && !OpenCLHint && !UnrollHint) {
631632
continue;
632633
}
633634

634635
LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
635636
LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
636637
unsigned ValueInt = 1;
637-
// Translate opencl_unroll_hint attribute argument to
638-
// equivalent LoopHintAttr enums.
638+
// Translate opencl_unroll_hint and clang::unroll attribute
639+
// argument to equivalent LoopHintAttr enums.
639640
// OpenCL v2.0 s6.11.5:
640641
// 0 - enable unroll (no argument).
641642
// 1 - disable unroll.
642643
// other positive integer n - unroll by n.
643-
if (OpenCLHint) {
644-
ValueInt = OpenCLHint->getUnrollHint();
644+
if (OpenCLHint || UnrollHint) {
645+
ValueInt = OpenCLHint ? OpenCLHint->getUnrollHint()
646+
: UnrollHint->getUnrollHint();
645647
if (ValueInt == 0) {
646648
State = LoopHintAttr::Enable;
647649
} else if (ValueInt != 1) {

clang/lib/Parse/ParseStmt.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
101101
ParsedAttributesWithRange Attrs(AttrFactory);
102102
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
103103
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs) ||
104-
!MaybeParseIntelFPGALoopAttributes(Attrs))
104+
!MaybeParseSYCLLoopAttributes(Attrs))
105105
return StmtError();
106106

107107
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
@@ -2396,19 +2396,22 @@ bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
23962396
return true;
23972397
}
23982398

2399-
bool Parser::ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
2399+
bool Parser::ParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
24002400
MaybeParseCXX11Attributes(Attrs);
24012401

24022402
if (Attrs.empty())
24032403
return true;
24042404

24052405
if (Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAIVDep &&
24062406
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAII &&
2407-
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency)
2407+
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency &&
2408+
Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint)
24082409
return true;
24092410

2411+
bool IsIntelFPGAAttribute = (Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint);
2412+
24102413
if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
2411-
Diag(Tok, diag::err_intel_fpga_loop_attrs_on_non_loop);
2414+
Diag(Tok, diag::err_loop_attr_on_non_loop) << IsIntelFPGAAttribute;
24122415
return false;
24132416
}
24142417
return true;

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -332,42 +332,69 @@ CheckForIncompatibleAttributes(Sema &S,
332332
}
333333
}
334334

335-
336-
template <typename FPGALoopAttrT> static void
337-
CheckForDuplicationFPGALoopAttribute(Sema &S,
338-
const SmallVectorImpl<const Attr *>
339-
&Attrs, SourceRange Range) {
340-
const FPGALoopAttrT *LoopFPGAAttr = nullptr;
335+
template <typename LoopAttrT>
336+
static void CheckForDuplicationSYCLLoopAttribute(
337+
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range,
338+
bool isIntelFPGAAttr = true) {
339+
const LoopAttrT *LoopAttr = nullptr;
341340

342341
for (const auto *I : Attrs) {
343-
if (LoopFPGAAttr) {
344-
if (isa<FPGALoopAttrT>(I)) {
342+
if (LoopAttr) {
343+
if (isa<LoopAttrT>(I)) {
345344
SourceLocation Loc = Range.getBegin();
346345
// Cannot specify same type of attribute twice.
347-
S.Diag(Loc, diag::err_intel_fpga_loop_attr_duplication)
348-
<< LoopFPGAAttr->getName();
346+
S.Diag(Loc, diag::err_sycl_loop_attr_duplication)
347+
<< isIntelFPGAAttr << LoopAttr->getName();
349348
}
350349
}
351-
if (isa<FPGALoopAttrT>(I))
352-
LoopFPGAAttr = cast<FPGALoopAttrT>(I);
350+
if (isa<LoopAttrT>(I))
351+
LoopAttr = cast<LoopAttrT>(I);
353352
}
354353
}
355354

356-
static void
357-
CheckForIncompatibleFPGALoopAttributes(Sema &S,
358-
const SmallVectorImpl<const Attr *>
359-
&Attrs, SourceRange Range) {
360-
CheckForDuplicationFPGALoopAttribute<SYCLIntelFPGAIVDepAttr>(S, Attrs, Range);
361-
CheckForDuplicationFPGALoopAttribute<SYCLIntelFPGAIIAttr>(S, Attrs, Range);
362-
CheckForDuplicationFPGALoopAttribute<
363-
SYCLIntelFPGAMaxConcurrencyAttr>(S, Attrs, Range);
355+
static void CheckForIncompatibleSYCLLoopAttributes(
356+
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range) {
357+
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAIVDepAttr>(S, Attrs, Range);
358+
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAIIAttr>(S, Attrs, Range);
359+
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAMaxConcurrencyAttr>(
360+
S, Attrs, Range);
361+
CheckForDuplicationSYCLLoopAttribute<LoopUnrollHintAttr>(S, Attrs, Range,
362+
false);
363+
}
364+
365+
void CheckForIncompatibleUnrollHintAttributes(
366+
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range) {
367+
368+
// This check is entered after it was analyzed that there are no duplicating
369+
// pragmas and loop attributes. So, let's perform check that there are no
370+
// conflicting pragma unroll and unroll attribute for the loop.
371+
const LoopUnrollHintAttr *AttrUnroll = nullptr;
372+
const LoopHintAttr *PragmaUnroll = nullptr;
373+
for (const auto *I : Attrs) {
374+
if (auto *LH = dyn_cast<LoopUnrollHintAttr>(I))
375+
AttrUnroll = LH;
376+
if (auto *LH = dyn_cast<LoopHintAttr>(I)) {
377+
LoopHintAttr::OptionType Opt = LH->getOption();
378+
if (Opt == LoopHintAttr::Unroll || Opt == LoopHintAttr::UnrollCount)
379+
PragmaUnroll = LH;
380+
}
381+
}
382+
383+
if (AttrUnroll && PragmaUnroll) {
384+
PrintingPolicy Policy(S.Context.getLangOpts());
385+
SourceLocation Loc = Range.getBegin();
386+
S.Diag(Loc, diag::err_loop_unroll_compatibility)
387+
<< PragmaUnroll->getDiagnosticName(Policy)
388+
<< AttrUnroll->getDiagnosticName();
389+
}
364390
}
365391

366-
static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
367-
SourceRange Range) {
392+
template <typename LoopUnrollAttrT>
393+
static Attr *handleLoopUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
394+
SourceRange Range) {
368395
// Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's
369396
// useful for OpenCL 1.x too and doesn't require HW support.
370-
// opencl_unroll_hint can have 0 arguments (compiler
397+
// opencl_unroll_hint or clang::unroll can have 0 arguments (compiler
371398
// determines unrolling factor) or 1 argument (the unroll factor provided
372399
// by the user).
373400

@@ -401,7 +428,7 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
401428
UnrollFactor = Val;
402429
}
403430

404-
return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
431+
return LoopUnrollAttrT::CreateImplicit(S.Context, UnrollFactor);
405432
}
406433

407434
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -424,7 +451,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
424451
case ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency:
425452
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxConcurrencyAttr>(S, St, A);
426453
case ParsedAttr::AT_OpenCLUnrollHint:
427-
return handleOpenCLUnrollHint(S, St, A, Range);
454+
return handleLoopUnrollHint<OpenCLUnrollHintAttr>(S, St, A, Range);
455+
case ParsedAttr::AT_LoopUnrollHint:
456+
return handleLoopUnrollHint<LoopUnrollHintAttr>(S, St, A, Range);
428457
case ParsedAttr::AT_Suppress:
429458
return handleSuppressAttr(S, St, A, Range);
430459
default:
@@ -446,7 +475,8 @@ StmtResult Sema::ProcessStmtAttributes(Stmt *S,
446475
}
447476

448477
CheckForIncompatibleAttributes(*this, Attrs);
449-
CheckForIncompatibleFPGALoopAttributes(*this, Attrs, Range);
478+
CheckForIncompatibleSYCLLoopAttributes(*this, Attrs, Range);
479+
CheckForIncompatibleUnrollHintAttributes(*this, Attrs, Range);
450480

451481
if (Attrs.empty())
452482
return S;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -x c++ -triple spir64-unknown-linux-sycldevice -std=c++11 -disable-llvm-passes -fsycl-is-device -emit-llvm %s -o - | FileCheck %s
2+
3+
// CHECK: br label %for.cond, !llvm.loop ![[COUNT:[0-9]+]]
4+
// CHECK: br label %while.cond, !llvm.loop ![[DISABLE:[0-9]+]]
5+
// CHECK: br i1 %{{.*}}, label %do.body, label %do.end, !llvm.loop ![[ENABLE:[0-9]+]]
6+
7+
// CHECK: ![[COUNT]] = distinct !{![[COUNT]], ![[COUNT_A:[0-9]+]]}
8+
// CHECK-NEXT: ![[COUNT_A]] = !{!"llvm.loop.unroll.count", i32 8}
9+
void count() {
10+
[[clang::loop_unroll(8)]]
11+
for (int i = 0; i < 1000; ++i);
12+
}
13+
14+
// CHECK: ![[DISABLE]] = distinct !{![[DISABLE]], ![[DISABLE_A:[0-9]+]]}
15+
// CHECK-NEXT: ![[DISABLE_A]] = !{!"llvm.loop.unroll.disable"}
16+
void disable() {
17+
int i = 1000;
18+
[[clang::loop_unroll(1)]]
19+
while (i--);
20+
}
21+
22+
// CHECK: ![[ENABLE]] = distinct !{![[ENABLE]], ![[ENABLE_A:[0-9]+]]}
23+
// CHECK-NEXT: ![[ENABLE_A]] = !{!"llvm.loop.unroll.enable"}
24+
void enable() {
25+
int i = 1000;
26+
[[clang::loop_unroll]]
27+
do {} while (i--);
28+
}
29+
30+
template <typename name, typename Func>
31+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
32+
kernelFunc();
33+
}
34+
35+
int main() {
36+
kernel_single_task<class kernel_function>([]() {
37+
count();
38+
disable();
39+
enable();
40+
});
41+
return 0;
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clangxx -c -S -emit-llvm %s -o - | FileCheck %s
2+
// CHECK: br label %{{.*}}, !llvm.loop ![[COUNT:[0-9]+]]
3+
// CHECK: br label %{{.*}}, !llvm.loop ![[DISABLE:[0-9]+]]
4+
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[ENABLE:[0-9]+]]
5+
6+
int main() {
7+
// CHECK: ![[COUNT]] = distinct !{![[COUNT]], ![[COUNT_A:[0-9]+]]}
8+
// CHECK-NEXT: ![[COUNT_A]] = !{!"llvm.loop.unroll.count", i32 4}
9+
[[clang::loop_unroll(4)]]
10+
for (int i = 0; i < 100; ++i);
11+
// CHECK: ![[DISABLE]] = distinct !{![[DISABLE]], ![[DISABLE_A:[0-9]+]]}
12+
// CHECK-NEXT: ![[DISABLE_A]] = !{!"llvm.loop.unroll.disable"}
13+
int i = 1000;
14+
[[clang::loop_unroll(1)]]
15+
while (i--);
16+
// CHECK: ![[ENABLE]] = distinct !{![[ENABLE]], ![[ENABLE_A:[0-9]+]]}
17+
// CHECK-NEXT: ![[ENABLE_A]] = !{!"llvm.loop.unroll.enable"}
18+
i = 1000;
19+
[[clang::loop_unroll]]
20+
do {} while (i--);
21+
return 0;
22+
}

clang/test/SemaSYCL/intel-fpga-loops.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
// Test for Intel FPGA loop attributes applied not to a loop
44
void foo() {
5-
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
5+
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
66
[[intelfpga::ivdep]] int a[10];
7-
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
7+
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
88
[[intelfpga::ivdep(2)]] int b[10];
9-
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
9+
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
1010
[[intelfpga::ii(2)]] int c[10];
11-
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
11+
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
1212
[[intelfpga::max_concurrency(2)]] int d[10];
1313
}
1414

0 commit comments

Comments
 (0)