Skip to content

Commit 3378926

Browse files
MrSidimsromanovvlad
authored andcommitted
[SYCL] Initial support of Intel FPGA loop attributes
Following attributes are being supported: intelfpga::ivdep(Safelen) Applies to a loop. Safelen is a positive integer. If no additional arguments are provided, it indicates that the backend may assume that the loop carries no dependences. If a safelen is provided then the backend may assume that all loop carried dependences have a dependence distance of at least that length. Metadata generated: No safelen provided: "llvm.loop.ivdep.enable" Safelen provided: "llvm.loop.ivdep.safelen", i32 Safelen intelfpga::ii(Interval) Applies to a loop. Indicates that the loop should be pipelined with an initiation interval. Interval must be a positive integer. Cannot be applied multiple times to the same loop. Metadata generated: "llvm.loop.ii", i32 Interval intefpga::max_concurrency(NThreads) Applies to a loop. Indicates that the loop should allow no more than NThreads or iterations to execute it simultaneously. NThreads must be a positive integer. Cannot be applied multiple times to the same loop. Metadata generated: "llvm.loop.max_concurrency", i32 NThreads Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 4ad0398 commit 3378926

File tree

11 files changed

+472
-3
lines changed

11 files changed

+472
-3
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,42 @@ def Mode : Attr {
13871387
let PragmaAttributeSupport = 0;
13881388
}
13891389

1390+
def IntelFPGAIVDep : Attr {
1391+
let Spellings = [CXX11<"intelfpga","ivdep">];
1392+
let Args = [IntArgument<"Safelen">];
1393+
let LangOpts = [SYCL];
1394+
let AdditionalMembers = [{
1395+
static const char *getName() {
1396+
return "ivdep";
1397+
}
1398+
}];
1399+
let Documentation = [IntelFPGAIVDepAttrDocs];
1400+
}
1401+
1402+
def IntelFPGAII : Attr {
1403+
let Spellings = [CXX11<"intelfpga","ii">];
1404+
let Args = [IntArgument<"Interval">];
1405+
let LangOpts = [SYCL];
1406+
let AdditionalMembers = [{
1407+
static const char *getName() {
1408+
return "ii";
1409+
}
1410+
}];
1411+
let Documentation = [IntelFPGAIIAttrDocs];
1412+
}
1413+
1414+
def IntelFPGAMaxConcurrency : Attr {
1415+
let Spellings = [CXX11<"intelfpga","max_concurrency">];
1416+
let Args = [IntArgument<"NThreads">];
1417+
let LangOpts = [SYCL];
1418+
let AdditionalMembers = [{
1419+
static const char *getName() {
1420+
return "max_concurrency";
1421+
}
1422+
}];
1423+
let Documentation = [IntelFPGAMaxConcurrencyAttrDocs];
1424+
}
1425+
13901426
def IntelFPGALocalNonConstVar : SubsetSubject<Var,
13911427
[{S->hasLocalStorage() &&
13921428
S->getKind() != Decl::ImplicitParam &&

clang/include/clang/Basic/AttrDocs.td

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,37 @@ threads or loop iterations.
17401740
}];
17411741
}
17421742

1743+
def IntelFPGAIVDepAttrDocs : Documentation {
1744+
let Category = DocCatVariable;
1745+
let Heading = "ivdep";
1746+
let Content = [{
1747+
This attribute applies to a loop. If no additional arguments are provided, it
1748+
indicates that the backend may assume that the loop carries no dependences.
1749+
If a safelen is provided then the backend may assume that all loop carried
1750+
dependences have a dependence distance of at least that length.
1751+
}];
1752+
}
1753+
1754+
def IntelFPGAIIAttrDocs : Documentation {
1755+
let Category = DocCatVariable;
1756+
let Heading = "ii";
1757+
let Content = [{
1758+
This attribute applies to a loop. Indicates that the loop should be pipelined
1759+
with an initiation interval of N. N must be a positive integer. Cannot be
1760+
applied multiple times to the same loop.
1761+
}];
1762+
}
1763+
1764+
def IntelFPGAMaxConcurrencyAttrDocs : Documentation {
1765+
let Category = DocCatVariable;
1766+
let Heading = "max_concurrency";
1767+
let Content = [{
1768+
This attribute applies to a loop. Indicates that the loop should allow no more
1769+
than N threads or iterations to execute it simultaneously. N must be a positive
1770+
integer. Cannot be applied multiple times to the same loop.
1771+
}];
1772+
}
1773+
17431774
def RISCVInterruptDocs : Documentation {
17441775
let Category = DocCatFunction;
17451776
let Heading = "interrupt (RISCV)";

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,11 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
12181218
"force_cuda_host_device begin">;
12191219
} // end of Parse Issue category.
12201220

1221+
// Intel FPGA pragmas and attributes support
1222+
// Attribute ivdep, ii, max_concurrency support
1223+
def err_intel_fpga_loop_attrs_on_non_loop : Error<
1224+
"intelfpga loop attributes must be applied to for, while or do statements">;
1225+
12211226
let CategoryName = "Modules Issue" in {
12221227
def err_unexpected_module_decl : Error<
12231228
"module declaration can only appear at the top level">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def err_attribute_argument_not_power_of_two : Error<
128128
"%0 attribute argument must be a constant power of two greater than zero">;
129129
def err_intel_fpga_memory_arg_invalid : Error<
130130
"%0 attribute requires either no argument or one of: %1">;
131+
def err_intel_fpga_loop_attr_duplication : Error<
132+
"duplicate Intel FPGA loop attribute '%0'">;
131133

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

clang/include/clang/Parse/Parser.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2519,8 +2519,16 @@ class Parser : public CodeCompletionHandler {
25192519
/// Parses opencl_unroll_hint attribute.
25202520
/// \return false if error happens.
25212521
bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs);
2522-
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
25232522

2523+
/// Parses intelfpga:: loop attributes if the language is SYCL
2524+
bool MaybeParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
2525+
if (getLangOpts().SYCLIsDevice)
2526+
return ParseIntelFPGALoopAttributes(Attrs);
2527+
return true;
2528+
}
2529+
bool ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs);
2530+
2531+
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
25242532
VersionTuple ParseVersionTuple(SourceRange &Range);
25252533
void ParseAvailabilityAttribute(IdentifierInfo &Availability,
25262534
SourceLocation AvailabilityLoc,

clang/lib/CodeGen/CGLoopInfo.cpp

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
2323
const llvm::DebugLoc &EndLoc, MDNode *&AccGroup) {
2424

2525
if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
26-
Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
26+
Attrs.InterleaveCount == 0 && Attrs.IVDepEnable == false &&
27+
Attrs.IVDepSafelen == 0 && Attrs.IInterval == 0 &&
28+
Attrs.MaxConcurrencyNThreads == 0 && Attrs.UnrollCount == 0 &&
2729
Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
2830
Attrs.PipelineInitiationInterval == 0 &&
2931
Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
@@ -63,6 +65,37 @@ static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
6365
Args.push_back(MDNode::get(Ctx, Vals));
6466
}
6567

68+
// Setting ivdep attribute
69+
if (Attrs.IVDepEnable) {
70+
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.ivdep.enable")};
71+
Args.push_back(MDNode::get(Ctx, Vals));
72+
}
73+
74+
// Setting ivdep attribute with safelen
75+
if (Attrs.IVDepSafelen > 0) {
76+
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.ivdep.safelen"),
77+
ConstantAsMetadata::get(ConstantInt::get(
78+
llvm::Type::getInt32Ty(Ctx), Attrs.IVDepSafelen))};
79+
Args.push_back(MDNode::get(Ctx, Vals));
80+
}
81+
82+
// Setting ii attribute with an initiation interval
83+
if (Attrs.IInterval > 0) {
84+
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.ii"),
85+
ConstantAsMetadata::get(ConstantInt::get(
86+
llvm::Type::getInt32Ty(Ctx), Attrs.IInterval))};
87+
Args.push_back(MDNode::get(Ctx, Vals));
88+
}
89+
90+
// Setting max_concurrency attribute with number of threads
91+
if (Attrs.MaxConcurrencyNThreads > 0) {
92+
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.max_concurrency"),
93+
ConstantAsMetadata::get(ConstantInt::get(
94+
llvm::Type::getInt32Ty(Ctx),
95+
Attrs.MaxConcurrencyNThreads))};
96+
Args.push_back(MDNode::get(Ctx, Vals));
97+
}
98+
6699
// Setting unroll.count
67100
if (Attrs.UnrollCount > 0) {
68101
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"),
@@ -152,6 +185,8 @@ static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
152185

153186
LoopAttributes::LoopAttributes(bool IsParallel)
154187
: IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
188+
IVDepEnable(false), IVDepSafelen(0), IInterval(0),
189+
MaxConcurrencyNThreads(0),
155190
UnrollEnable(LoopAttributes::Unspecified),
156191
UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
157192
InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
@@ -161,6 +196,10 @@ LoopAttributes::LoopAttributes(bool IsParallel)
161196
void LoopAttributes::clear() {
162197
IsParallel = false;
163198
VectorizeWidth = 0;
199+
IVDepEnable = false;
200+
IVDepSafelen = 0;
201+
IInterval = 0;
202+
MaxConcurrencyNThreads = 0;
164203
InterleaveCount = 0;
165204
UnrollCount = 0;
166205
UnrollAndJamCount = 0;
@@ -358,6 +397,49 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
358397
}
359398
}
360399

400+
// Translate intelfpga loop attributes' arguments to equivalent Attr enums.
401+
// It's being handled separately from LoopHintAttrs not to support
402+
// legacy GNU attributes and pragma styles.
403+
//
404+
// For attribute ivdep:
405+
// 0 - 'llvm.loop.ivdep.enable' metadata will be emitted
406+
// n - 'llvm.loop.ivdep.safelen, i32 n' metadata will be emitted
407+
// For attribute ii:
408+
// n - 'llvm.loop.ii, i32 n' metadata will be emitted
409+
// For attribute max_concurrency:
410+
// n - 'llvm.loop.max_concurrency, i32 n' metadata will be emitted
411+
for (const auto *Attr : Attrs) {
412+
const IntelFPGAIVDepAttr *IntelFPGAIVDep =
413+
dyn_cast<IntelFPGAIVDepAttr>(Attr);
414+
const IntelFPGAIIAttr *IntelFPGAII =
415+
dyn_cast<IntelFPGAIIAttr>(Attr);
416+
const IntelFPGAMaxConcurrencyAttr *IntelFPGAMaxConcurrency =
417+
dyn_cast<IntelFPGAMaxConcurrencyAttr>(Attr);
418+
419+
if (!IntelFPGAIVDep && !IntelFPGAII && !IntelFPGAMaxConcurrency)
420+
continue;
421+
422+
if (IntelFPGAIVDep) {
423+
unsigned ValueInt = IntelFPGAIVDep->getSafelen();
424+
if (ValueInt == 0)
425+
setIVDepEnable();
426+
else if (ValueInt > 1)
427+
setIVDepSafelen(ValueInt);
428+
}
429+
430+
if (IntelFPGAII) {
431+
unsigned ValueInt = IntelFPGAII->getInterval();
432+
if (ValueInt > 1)
433+
setIInterval(ValueInt);
434+
}
435+
436+
if (IntelFPGAMaxConcurrency) {
437+
unsigned ValueInt = IntelFPGAMaxConcurrency->getNThreads();
438+
if (ValueInt > 1)
439+
setMaxConcurrencyNThreads(ValueInt);
440+
}
441+
}
442+
361443
/// Stage the attributes.
362444
push(Header, StartLoc, EndLoc);
363445
}

clang/lib/CodeGen/CGLoopInfo.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ struct LoopAttributes {
5757
/// Value for llvm.loop.interleave.count metadata.
5858
unsigned InterleaveCount;
5959

60+
/// Value for llvm.loop.ivdep.enable metadata.
61+
bool IVDepEnable;
62+
63+
/// Value for llvm.loop.ivdep.safelen metadata.
64+
unsigned IVDepSafelen;
65+
66+
/// Value for llvm.loop.ii metadata.
67+
unsigned IInterval;
68+
69+
/// Value for llvm.loop.max_concurrency metadata.
70+
unsigned MaxConcurrencyNThreads;
71+
6072
/// llvm.unroll.
6173
unsigned UnrollCount;
6274

@@ -170,6 +182,20 @@ class LoopInfoStack {
170182
/// Set the interleave count for the next loop pushed.
171183
void setInterleaveCount(unsigned C) { StagedAttrs.InterleaveCount = C; }
172184

185+
/// Set flag of ivdep for the next loop pushed.
186+
void setIVDepEnable() { StagedAttrs.IVDepEnable = true; }
187+
188+
/// Set value of safelen count for the next loop pushed.
189+
void setIVDepSafelen(unsigned C) { StagedAttrs.IVDepSafelen = C; }
190+
191+
/// Set value of an initiation interval for the next loop pushed.
192+
void setIInterval(unsigned C) { StagedAttrs.IInterval = C; }
193+
194+
/// Set value of threads for the next loop pushed.
195+
void setMaxConcurrencyNThreads(unsigned C) {
196+
StagedAttrs.MaxConcurrencyNThreads = C;
197+
}
198+
173199
/// Set the unroll count for the next loop pushed.
174200
void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; }
175201

clang/lib/Parse/ParseStmt.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
100100

101101
ParsedAttributesWithRange Attrs(AttrFactory);
102102
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
103-
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
103+
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs) ||
104+
!MaybeParseIntelFPGALoopAttributes(Attrs))
104105
return StmtError();
105106

106107
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
@@ -2370,3 +2371,21 @@ bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
23702371
}
23712372
return true;
23722373
}
2374+
2375+
bool Parser::ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
2376+
MaybeParseCXX11Attributes(Attrs);
2377+
2378+
if (Attrs.empty())
2379+
return true;
2380+
2381+
if (Attrs.begin()->getKind() != ParsedAttr::AT_IntelFPGAIVDep &&
2382+
Attrs.begin()->getKind() != ParsedAttr::AT_IntelFPGAII &&
2383+
Attrs.begin()->getKind() != ParsedAttr::AT_IntelFPGAMaxConcurrency)
2384+
return true;
2385+
2386+
if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
2387+
Diag(Tok, diag::err_intel_fpga_loop_attrs_on_non_loop);
2388+
return false;
2389+
}
2390+
return true;
2391+
}

0 commit comments

Comments
 (0)