Skip to content

Commit 92aadf3

Browse files
authored
[SYCL][FPGA] Add support for new attribute for loop pipelining (#6254)
This patch adds support for new FPGA attribute called [[intel::fpga_pipeline(N)]] that takes a Boolean parameter. N can be a template parameter or constexpr. If the user didn't provide a parameter, the default value of N would be 1, which implies enable pipelining. This attribute can be applied to loops. Example syntax: // will disable loop pipelining [[intel::fpga_pipeline(0)]] for (int i = 0; i<N; ++i) {...} LLVM IR: When applied on a loop, the LLVM IR should be attached to llvm.loop metadata: !{!"llvm.loop.intel.pipelining.enable", i32 N} The value of the !"llvm.loop.intel.pipelining.enable" metadata is an i32 value that corresponds to the boolean parameter N. A value of 0 is used for not pipelining the loop. A value of 1 is used for pipelining the loop. If the parameter is not given, value of N will be the default value 1, which implies we will pipeline the loop, and the IR will look like !{!"llvm.loop.intel.pipelining.enable", i32 1} Error Message: We should emit an error when [[intel::initiation_interval(k)]] and [[intel::fpga_pipeline(0)]] are used together: "error: initiation_interval and fpga_pipeline(0) attributes are not compatible" We should emit an error when [[intel::max_concurrency(k)]] and [[intel::fpga_pipeline(0)]] are used together: "error: max_concurrency and fpga_pipeline(0) attributes are not compatible" Note: this basically performs very similar functionalities as [[intel::disable_loop_pipelining]], the plan is to deprecate disable_loop_pipelining in future releases and use [[intel::fpga_pipeline(n)]] instead. Signed-off-by: Soumi Manna <soumi.manna@intel.com>
1 parent 7a2f44b commit 92aadf3

File tree

11 files changed

+374
-39
lines changed

11 files changed

+374
-39
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,6 +2308,23 @@ def : MutualExclusions<[SYCLIntelFPGAIVDep,
23082308
def : MutualExclusions<[SYCLIntelFPGAMaxConcurrency,
23092309
SYCLIntelFPGADisableLoopPipelining]>;
23102310

2311+
def SYCLIntelFPGAPipeline : InheritableAttr {
2312+
let Spellings = [CXX11<"intel","fpga_pipeline">];
2313+
let Args = [ExprArgument<"Value", /*optional*/1>];
2314+
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
2315+
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
2316+
ErrorDiag, "'for', 'while', and 'do' statements">;
2317+
let Documentation = [SYCLIntelFPGAPipelineAttrDocs];
2318+
let IsStmtDependent = 1;
2319+
}
2320+
2321+
def : MutualExclusions<[SYCLIntelFPGAInitiationInterval,
2322+
SYCLIntelFPGAPipeline]>;
2323+
def : MutualExclusions<[SYCLIntelFPGAIVDep,
2324+
SYCLIntelFPGAPipeline]>;
2325+
def : MutualExclusions<[SYCLIntelFPGAMaxConcurrency,
2326+
SYCLIntelFPGAPipeline]>;
2327+
23112328
def SYCLIntelFPGALoopCount : StmtAttr {
23122329
let Spellings = [CXX11<"intel", "loop_count_min">,
23132330
CXX11<"intel", "loop_count_max">,
@@ -2340,6 +2357,9 @@ def SYCLIntelFPGAMaxInterleaving : StmtAttr {
23402357
def : MutualExclusions<[SYCLIntelFPGADisableLoopPipelining,
23412358
SYCLIntelFPGAMaxInterleaving]>;
23422359

2360+
def : MutualExclusions<[SYCLIntelFPGAPipeline,
2361+
SYCLIntelFPGAMaxInterleaving]>;
2362+
23432363
def SYCLIntelFPGASpeculatedIterations : StmtAttr {
23442364
let Spellings = [CXX11<"intel", "speculated_iterations">];
23452365
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
@@ -2352,6 +2372,9 @@ def SYCLIntelFPGASpeculatedIterations : StmtAttr {
23522372
def : MutualExclusions<[SYCLIntelFPGADisableLoopPipelining,
23532373
SYCLIntelFPGASpeculatedIterations]>;
23542374

2375+
def : MutualExclusions<[SYCLIntelFPGAPipeline,
2376+
SYCLIntelFPGASpeculatedIterations]>;
2377+
23552378
def SYCLIntelFPGANofusion : StmtAttr {
23562379
let Spellings = [CXX11<"intel","nofusion">];
23572380
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],

clang/include/clang/Basic/AttrDocs.td

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,6 +3291,9 @@ function, or in conjunction with ``max_interleaving``,
32913291
``speculated_iterations``, ``max_concurrency``, ``initiation_interval``,
32923292
or ``ivdep``.
32933293

3294+
The ``[[intel::disable_loop_pipelining]]`` attribute spelling is a deprecated
3295+
synonym for ``[[[intel::fpga_pipeline]]`` and will be removed in the future.
3296+
32943297
.. code-block:: c++
32953298

32963299
void foo() {
@@ -3303,6 +3306,58 @@ or ``ivdep``.
33033306
}];
33043307
}
33053308

3309+
def SYCLIntelFPGAPipelineAttrDocs : Documentation {
3310+
let Category = DocCatVariable;
3311+
let Heading = "intel::fpga_pipeline";
3312+
let Content = [{
3313+
The ``intel::fpga_pipeline(N)`` attribute applies to a loop and it allows users
3314+
to disable or enable pipelining iterations of a loop. The attribute optionally
3315+
accepts an integer constant expression that is converted to `bool`. A `true`
3316+
value enables pipelining while a `false` value disables pipelining. The
3317+
optional argument defaults to `true`. This attribute cannot be applied to a
3318+
loop in conjunction with the ``max_interleaving``, ``speculated_iterations``,
3319+
``max_concurrency``, ``initiation_interval``, or ``ivdep`` attributes.
3320+
3321+
.. code-block:: c++
3322+
3323+
// Disable loop pipelining
3324+
void bar() {
3325+
int a[10];
3326+
[[[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i) a[i] = 0;
3327+
}
3328+
3329+
// Enable loop pipelining
3330+
void foo() {
3331+
int var = 0;
3332+
[[intel::fpga_pipeline(1)]] for (int i = 0; i < 10; ++i) var++;
3333+
}
3334+
3335+
void Array(int *array, size_t n) {
3336+
// identical to [[intel::fpga_pipeline(1)]]
3337+
[[intel::fpga_pipeline]] for (int i = 0; i < n; ++i) array[i] = 0;
3338+
}
3339+
3340+
void count () {
3341+
int a1[10], int i = 0;
3342+
[[intel::fpga_pipeline(1)]] while (i < 10) {
3343+
a1[i] += 3;
3344+
}
3345+
3346+
void check() {
3347+
int a = 10;
3348+
[[intel::fpga_pipeline(1)]] do {
3349+
a = a + 1;
3350+
} while (a < 20);
3351+
}
3352+
3353+
template<int A>
3354+
void func() {
3355+
[[intel::fpga_pipeline(A)]] for(;;) { }
3356+
}
3357+
3358+
}];
3359+
}
3360+
33063361
def SYCLIntelFPGALoopCountAttrDocs : Documentation {
33073362
let Category = DocCatVariable;
33083363
let Heading = "intel::loop_count_min, intel::loop_count_max, intel::loop_count_avg, intel::loop_count";

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,6 +2277,9 @@ class Sema final {
22772277
SYCLIntelFPGALoopCoalesceAttr *
22782278
BuildSYCLIntelFPGALoopCoalesceAttr(const AttributeCommonInfo &CI, Expr *E);
22792279

2280+
SYCLIntelFPGAPipelineAttr *
2281+
BuildSYCLIntelFPGAPipelineAttr(const AttributeCommonInfo &CI, Expr *E);
2282+
22802283
bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
22812284

22822285
bool CheckFunctionReturnType(QualType T, SourceLocation Loc);

clang/lib/CodeGen/CGLoopInfo.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,14 @@ MDNode *LoopInfo::createMetadata(
611611
llvm::Type::getInt32Ty(Ctx), VC.second))};
612612
LoopProperties.push_back(MDNode::get(Ctx, Vals));
613613
}
614+
615+
for (auto &FP : Attrs.SYCLIntelFPGAPipeline) {
616+
Metadata *Vals[] = {MDString::get(Ctx, FP.first),
617+
ConstantAsMetadata::get(ConstantInt::get(
618+
llvm::Type::getInt32Ty(Ctx), FP.second))};
619+
LoopProperties.push_back(MDNode::get(Ctx, Vals));
620+
}
621+
614622
LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(),
615623
AdditionalLoopProperties.end());
616624
return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms);
@@ -654,6 +662,7 @@ void LoopAttributes::clear() {
654662
PipelineDisabled = false;
655663
PipelineInitiationInterval = 0;
656664
SYCLNofusionEnable = false;
665+
SYCLIntelFPGAPipeline.clear();
657666
MustProgress = false;
658667
}
659668

@@ -687,7 +696,8 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
687696
Attrs.UnrollEnable == LoopAttributes::Unspecified &&
688697
Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
689698
Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
690-
Attrs.SYCLNofusionEnable == false && !EndLoc && !Attrs.MustProgress)
699+
Attrs.SYCLNofusionEnable == false &&
700+
Attrs.SYCLIntelFPGAPipeline.empty() && !EndLoc && !Attrs.MustProgress)
691701
return;
692702

693703
TempLoopID = MDNode::getTemporary(Header->getContext(), None);
@@ -1011,6 +1021,8 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
10111021
// emitted
10121022
// For attribute nofusion:
10131023
// 'llvm.loop.fusion.disable' metadata will be emitted
1024+
// For attribute fpga_pipeline:
1025+
// n - 'llvm.loop.intel.pipelining.enable, i32 n' metadata will be emitted
10141026
for (const auto *A : Attrs) {
10151027
if (const auto *IntelFPGAIVDep = dyn_cast<SYCLIntelFPGAIVDepAttr>(A))
10161028
addSYCLIVDepInfo(Header->getContext(), IntelFPGAIVDep->getSafelenValue(),
@@ -1075,6 +1087,15 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
10751087

10761088
if (isa<SYCLIntelFPGANofusionAttr>(A))
10771089
setSYCLNofusionEnable();
1090+
1091+
if (const auto *IntelFPGAPipeline =
1092+
dyn_cast<SYCLIntelFPGAPipelineAttr>(A)) {
1093+
const auto *CE = cast<ConstantExpr>(IntelFPGAPipeline->getValue());
1094+
Optional<llvm::APSInt> ArgVal = CE->getResultAsAPSInt();
1095+
unsigned int Value = ArgVal->getBoolValue() ? 1 : 0;
1096+
const char *Var = "llvm.loop.intel.pipelining.enable";
1097+
setSYCLIntelFPGAPipeline(Var, Value);
1098+
}
10781099
}
10791100

10801101
setMustProgress(MustProgress);

clang/lib/CodeGen/CGLoopInfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ struct LoopAttributes {
152152
/// Flag for llvm.loop.fusion.disable metatdata.
153153
bool SYCLNofusionEnable;
154154

155+
/// Value for fpga_pipeline variant and metadata.
156+
llvm::SmallVector<std::pair<const char *, unsigned int>, 2>
157+
SYCLIntelFPGAPipeline;
158+
155159
/// Value for whether the loop is required to make progress.
156160
bool MustProgress;
157161
};
@@ -407,6 +411,11 @@ class LoopInfoStack {
407411
/// Set flag of nofusion for the next loop pushed.
408412
void setSYCLNofusionEnable() { StagedAttrs.SYCLNofusionEnable = true; }
409413

414+
/// Set variant and value of fpga_pipeline for the next loop pushed.
415+
void setSYCLIntelFPGAPipeline(const char *Var, unsigned int Value) {
416+
StagedAttrs.SYCLIntelFPGAPipeline.push_back({Var, Value});
417+
}
418+
410419
/// Set no progress for the next loop pushed.
411420
void setMustProgress(bool P) { StagedAttrs.MustProgress = P; }
412421

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ void Sema::CheckDeprecatedSYCLAttributeSpelling(const ParsedAttr &A,
364364
Diag(A.getLoc(), diag::ext_sycl_2020_attr_spelling) << A;
365365
return;
366366
}
367+
368+
// Deprecate [[intel::disable_loop_pipelining]] attribute spelling in favor
369+
// of the SYCL FPGA attribute spelling [[intel::fpga_pipeline]].
370+
if (A.hasScope() && A.getScopeName()->isStr("intel") &&
371+
A.getAttrName()->isStr("disable_loop_pipelining")) {
372+
DiagnoseDeprecatedAttribute(A, "intel", "fpga_pipeline");
373+
return;
374+
}
367375
}
368376

369377
/// Check if IdxExpr is a valid parameter index for a function or

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,33 @@ static Attr *handleSYCLIntelFPGADisableLoopPipeliningAttr(Sema &S, Stmt *,
219219
return new (S.Context) SYCLIntelFPGADisableLoopPipeliningAttr(S.Context, A);
220220
}
221221

222+
// Handle [[intel:fpga_pipeline]] attribute.
223+
static Attr *handleSYCLIntelFPGAPipelineAttr(Sema &S, Stmt *,
224+
const ParsedAttr &A) {
225+
// If no attribute argument is specified, set to default value '1'.
226+
Expr *E = A.isArgExpr(0)
227+
? A.getArgAsExpr(0)
228+
: IntegerLiteral::Create(S.Context, llvm::APInt(32, 1),
229+
S.Context.IntTy, A.getLoc());
230+
231+
return S.BuildSYCLIntelFPGAPipelineAttr(A, E);
232+
}
233+
234+
SYCLIntelFPGAPipelineAttr *
235+
Sema::BuildSYCLIntelFPGAPipelineAttr(const AttributeCommonInfo &A, Expr *E) {
236+
237+
if (!E->isValueDependent()) {
238+
// Check if the expression is not value dependent.
239+
llvm::APSInt ArgVal;
240+
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
241+
if (Res.isInvalid())
242+
return nullptr;
243+
E = Res.get();
244+
}
245+
246+
return new (Context) SYCLIntelFPGAPipelineAttr(Context, A, E);
247+
}
248+
222249
static bool checkSYCLIntelFPGAIVDepSafeLen(Sema &S, llvm::APSInt &Value,
223250
Expr *E) {
224251
if (!Value.isStrictlyPositive())
@@ -821,6 +848,7 @@ static void CheckForIncompatibleSYCLLoopAttributes(
821848
CheckForDuplicationSYCLLoopAttribute<LoopUnrollHintAttr>(S, Attrs, false);
822849
CheckRedundantSYCLIntelFPGAIVDepAttrs(S, Attrs);
823850
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGANofusionAttr>(S, Attrs);
851+
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAPipelineAttr>(S, Attrs);
824852
}
825853

826854
void CheckForIncompatibleUnrollHintAttributes(
@@ -966,6 +994,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
966994
return handleUnlikely(S, St, A, Range);
967995
case ParsedAttr::AT_SYCLIntelFPGANofusion:
968996
return handleIntelFPGANofusionAttr(S, St, A);
997+
case ParsedAttr::AT_SYCLIntelFPGAPipeline:
998+
return handleSYCLIntelFPGAPipelineAttr(S, St, A);
969999
default:
9701000
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
9711001
// declaration attribute is not written on a statement, but this code is

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,8 @@ namespace {
11101110
const SYCLIntelFPGASpeculatedIterationsAttr *SI);
11111111
const SYCLIntelFPGALoopCountAttr *
11121112
TransformSYCLIntelFPGALoopCountAttr(const SYCLIntelFPGALoopCountAttr *SI);
1113+
const SYCLIntelFPGAPipelineAttr *
1114+
TransformSYCLIntelFPGAPipelineAttr(const SYCLIntelFPGAPipelineAttr *SI);
11131115

11141116
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
11151117
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -1601,6 +1603,13 @@ const LoopUnrollHintAttr *TemplateInstantiator::TransformLoopUnrollHintAttr(
16011603
return getSema().BuildLoopUnrollHintAttr(*LU, TransformedExpr);
16021604
}
16031605

1606+
const SYCLIntelFPGAPipelineAttr *
1607+
TemplateInstantiator::TransformSYCLIntelFPGAPipelineAttr(
1608+
const SYCLIntelFPGAPipelineAttr *PA) {
1609+
Expr *TransformedExpr = getDerived().TransformExpr(PA->getValue()).get();
1610+
return getSema().BuildSYCLIntelFPGAPipelineAttr(*PA, TransformedExpr);
1611+
}
1612+
16041613
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
16051614
NonTypeTemplateParmDecl *parm,
16061615
SourceLocation loc,

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
// CHECK: br label %for.cond2, !llvm.loop ![[MD_LCA_1:[0-9]+]]
2121
// CHECK: br label %for.cond13, !llvm.loop ![[MD_LCA_2:[0-9]+]]
2222
// CHECK: br label %for.cond24, !llvm.loop ![[MD_LCA_3:[0-9]+]]
23+
// CHECK: br label %for.cond, !llvm.loop ![[MD_FP:[0-9]+]]
24+
// CHECK: br label %for.cond2, !llvm.loop ![[MD_FP_1:[0-9]+]]
25+
// CHECK: br label %for.cond13, !llvm.loop ![[MD_FP_2:[0-9]+]]
26+
// CHECK: br label %for.cond24, !llvm.loop ![[MD_FP_3:[0-9]+]]
27+
// CHECK: br label %while.cond, !llvm.loop ![[MD_FP_4:[0-9]+]]
28+
// CHECK: br i1 %cmp38, label %do.body, label %do.end, !llvm.loop ![[MD_FP_5:[0-9]+]]
29+
// CHECK: br label %for.cond40, !llvm.loop ![[MD_FP_6:[0-9]+]]
30+
// CHECK: br label %while.cond47, !llvm.loop ![[MD_FP_7:[0-9]+]]
2331

2432
void disable_loop_pipelining() {
2533
int a[10];
@@ -126,6 +134,7 @@ void speculated_iterations() {
126134
a[i] = 0;
127135
}
128136

137+
// Add CodeGen tests for FPGA loop attribute: [[intel::fpga_pipeline()]].
129138
template <int A>
130139
void loop_count_control() {
131140
int a[10];
@@ -150,6 +159,48 @@ void loop_count_control() {
150159
a[i] = 0;
151160
}
152161

162+
// Add CodeGen tests for Loop attribute: [[intel::fpga_pipeline()]].
163+
template <int A>
164+
void fpga_pipeline() {
165+
int a[10];
166+
// CHECK: ![[MD_FP]] = distinct !{![[MD_FP]], ![[MP]], ![[MD_fpga_pipeline:[0-9]+]]}
167+
// CHECK-NEXT: ![[MD_fpga_pipeline]] = !{!"llvm.loop.intel.pipelining.enable", i32 1}
168+
[[intel::fpga_pipeline(A)]] for (int i = 0; i != 10; ++i)
169+
a[i] = 0;
170+
171+
// CHECK: ![[MD_FP_1]] = distinct !{![[MD_FP_1]], ![[MP]], ![[MD_fpga_pipeline]]}
172+
[[intel::fpga_pipeline(1)]] for (int i = 0; i != 10; ++i)
173+
a[i] = 0;
174+
175+
// CHECK: ![[MD_FP_2]] = distinct !{![[MD_FP_2]], ![[MP]], ![[MD_fpga_pipeline]]}
176+
[[intel::fpga_pipeline]] for (int i = 0; i != 10; ++i)
177+
a[i] = 0;
178+
179+
// CHECK: ![[MD_FP_3]] = distinct !{![[MD_FP_3]], ![[MP]], ![[MD_dlp]]}
180+
[[intel::fpga_pipeline(0)]] for (int i = 0; i != 10; ++i)
181+
a[i] = 0;
182+
183+
// CHECK: ![[MD_FP_4]] = distinct !{![[MD_FP_4]], ![[MP]], ![[MD_fpga_pipeline]]}
184+
int j = 0;
185+
[[intel::fpga_pipeline]] while (j < 10) {
186+
a[j] += 3;
187+
}
188+
189+
// CHECK: ![[MD_FP_5]] = distinct !{![[MD_FP_5]], ![[MP]], ![[MD_fpga_pipeline]]}
190+
int b = 10;
191+
[[intel::fpga_pipeline(1)]] do {
192+
b = b + 1;
193+
} while (b < 20);
194+
195+
// CHECK: ![[MD_FP_6]] = distinct !{![[MD_FP_6]], ![[MD_fpga_pipeline]]}
196+
int c[] = {0, 1, 2, 3, 4, 5};
197+
[[intel::fpga_pipeline(A)]] for (int n : c) { n *= 2; }
198+
199+
// CHECK: ![[MD_FP_7]] = distinct !{![[MD_FP_7]], ![[MP]], ![[MD_fpga_pipeline]]}
200+
int k = 0;
201+
[[intel::fpga_pipeline(-1)]] while (k < 20) { a[k] += 2; }
202+
}
203+
153204
template <typename name, typename Func>
154205
__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) {
155206
kernelFunc();
@@ -165,6 +216,7 @@ int main() {
165216
max_interleaving<3, 0>();
166217
speculated_iterations<4, 0>();
167218
loop_count_control<12>();
219+
fpga_pipeline<1>();
168220
});
169221
return 0;
170222
}

0 commit comments

Comments
 (0)