Skip to content

Commit 90fa5bb

Browse files
[SYCL][FPGA]Implementation of max_reinvocation_delay loop attribute (#6623)
Add support for max_reinvocation_delay FPGA loop attribute, used for specifying the maximum number of cycles allowed between loop invocations.
1 parent 51b7969 commit 90fa5bb

File tree

9 files changed

+193
-1
lines changed

9 files changed

+193
-1
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,6 +2384,18 @@ def SYCLIntelFPGANofusion : StmtAttr {
23842384
let Documentation = [SYCLIntelFPGANofusionAttrDocs];
23852385
}
23862386

2387+
def SYCLIntelFPGAMaxReinvocationDelay : StmtAttr {
2388+
let Spellings = [CXX11<"intel", "max_reinvocation_delay">];
2389+
let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
2390+
ErrorDiag, "'for', 'while', and 'do' statements">;
2391+
let Args = [ExprArgument<"NExpr">];
2392+
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
2393+
let IsStmtDependent = 1;
2394+
let Documentation = [SYCLIntelFPGAMaxReinvocationDelayAttrDocs];
2395+
}
2396+
def : MutualExclusions<[SYCLIntelFPGADisableLoopPipelining,
2397+
SYCLIntelFPGAMaxReinvocationDelay]>;
2398+
23872399
def IntelFPGALocalNonConstVar : SubsetSubject<Var,
23882400
[{S->hasLocalStorage() &&
23892401
S->getKind() != Decl::ImplicitParam &&

clang/include/clang/Basic/AttrDocs.td

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3314,7 +3314,7 @@ disables pipelining of the loop or function data path, causing the loop
33143314
or function to be executed serially. Cannot be used on the same loop or
33153315
function, or in conjunction with ``max_interleaving``,
33163316
``speculated_iterations``, ``max_concurrency``, ``initiation_interval``,
3317-
or ``ivdep``.
3317+
``ivdep``, or ``max_reinvocation_delay``.
33183318

33193319
.. code-block:: c++
33203320

@@ -3447,6 +3447,31 @@ loop should not be fused with any adjacent loop.
34473447
}];
34483448
}
34493449

3450+
def SYCLIntelFPGAMaxReinvocationDelayAttrDocs : Documentation {
3451+
let Category = DocCatVariable;
3452+
let Heading = "intel::max_reinvocation_delay";
3453+
let Content = [{
3454+
This attribute applies to a loop. Specifies the maximum number of cycles allowed
3455+
on the delay between the launch of the last iteration of a loop invocation and
3456+
the launch of the first iteration of a new loop invocation. Parameter N is
3457+
mandatory, and is a positive integer. Cannot be used on the same loop in
3458+
conjunction with disable_loop_pipelining.
3459+
3460+
.. code-block:: c++
3461+
3462+
void foo() {
3463+
int var = 0;
3464+
[[intel::max_reinvocation_delay(1)]]
3465+
for (int i = 0; sycl::log10((float)(x)) < 10; i++) var++;
3466+
}
3467+
3468+
template<int N>
3469+
void bar() {
3470+
[[intel::max_reinvocation_delay(N)]] for(;;) { }
3471+
}
3472+
}];
3473+
}
3474+
34503475
def SYCLIntelLoopFuseDocs : Documentation {
34513476
let Category = DocCatFunction;
34523477
let Heading = "loop_fuse, loop_fuse_independent";

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,6 +2287,9 @@ class Sema final {
22872287
Expr *E);
22882288
SYCLIntelFPGALoopCoalesceAttr *
22892289
BuildSYCLIntelFPGALoopCoalesceAttr(const AttributeCommonInfo &CI, Expr *E);
2290+
SYCLIntelFPGAMaxReinvocationDelayAttr *
2291+
BuildSYCLIntelFPGAMaxReinvocationDelayAttr(const AttributeCommonInfo &CI,
2292+
Expr *E);
22902293

22912294
bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
22922295

clang/lib/CodeGen/CGLoopInfo.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,15 @@ MDNode *LoopInfo::createMetadata(
611611
llvm::Type::getInt32Ty(Ctx), VC.second))};
612612
LoopProperties.push_back(MDNode::get(Ctx, Vals));
613613
}
614+
615+
if (Attrs.SYCLMaxReinvocationDelayNCycles) {
616+
Metadata *Vals[] = {
617+
MDString::get(Ctx, "llvm.loop.intel.max_reinvocation_delay.count"),
618+
ConstantAsMetadata::get(
619+
ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
620+
*Attrs.SYCLMaxReinvocationDelayNCycles))};
621+
LoopProperties.push_back(MDNode::get(Ctx, Vals));
622+
}
614623

615624
LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(),
616625
AdditionalLoopProperties.end());
@@ -645,6 +654,7 @@ void LoopAttributes::clear() {
645654
SYCLMaxInterleavingNInvocations.reset();
646655
SYCLSpeculatedIterationsNIterations.reset();
647656
SYCLIntelFPGAVariantCount.clear();
657+
SYCLMaxReinvocationDelayNCycles.reset();
648658
UnrollCount = 0;
649659
UnrollAndJamCount = 0;
650660
VectorizeEnable = LoopAttributes::Unspecified;
@@ -681,6 +691,7 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
681691
!Attrs.SYCLMaxInterleavingNInvocations &&
682692
!Attrs.SYCLSpeculatedIterationsNIterations &&
683693
Attrs.SYCLIntelFPGAVariantCount.empty() && Attrs.UnrollCount == 0 &&
694+
!Attrs.SYCLMaxReinvocationDelayNCycles &&
684695
Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
685696
Attrs.PipelineInitiationInterval == 0 &&
686697
Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified &&
@@ -1012,6 +1023,9 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
10121023
// emitted
10131024
// For attribute nofusion:
10141025
// 'llvm.loop.fusion.disable' metadata will be emitted
1026+
// For attribute max_reinvocation_delay:
1027+
// n - 'llvm.loop.intel.max_reinvocation_delay.count, i32 n' metadata will be
1028+
// emitted
10151029
for (const auto *A : Attrs) {
10161030
if (const auto *IntelFPGAIVDep = dyn_cast<SYCLIntelFPGAIVDepAttr>(A))
10171031
addSYCLIVDepInfo(Header->getContext(), IntelFPGAIVDep->getSafelenValue(),
@@ -1076,6 +1090,14 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
10761090

10771091
if (isa<SYCLIntelFPGANofusionAttr>(A))
10781092
setSYCLNofusionEnable();
1093+
1094+
if (const auto *IntelFPGAMaxReinvocationDelay =
1095+
dyn_cast<SYCLIntelFPGAMaxReinvocationDelayAttr>(A)) {
1096+
const auto *CE = cast<ConstantExpr>(
1097+
IntelFPGAMaxReinvocationDelay->getNExpr());
1098+
llvm::APSInt ArgVal = CE->getResultAsAPSInt();
1099+
setSYCLMaxReinvocationDelayNCycles(ArgVal.getSExtValue());
1100+
}
10791101
}
10801102

10811103
setMustProgress(MustProgress);

clang/lib/CodeGen/CGLoopInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ struct LoopAttributes {
134134
/// Value for llvm.loop.intel.speculated.iterations.count metadata.
135135
llvm::Optional<unsigned> SYCLSpeculatedIterationsNIterations;
136136

137+
// Value for llvm.loop.intel.max_reinvocation_delay metadata.
138+
llvm::Optional<unsigned> SYCLMaxReinvocationDelayNCycles;
139+
137140
/// llvm.unroll.
138141
unsigned UnrollCount;
139142

@@ -410,6 +413,11 @@ class LoopInfoStack {
410413
/// Set no progress for the next loop pushed.
411414
void setMustProgress(bool P) { StagedAttrs.MustProgress = P; }
412415

416+
/// Set value of max reinvocation delay for the next loop pushed.
417+
void setSYCLMaxReinvocationDelayNCycles(unsigned C) {
418+
StagedAttrs.SYCLMaxReinvocationDelayNCycles = C;
419+
}
420+
413421
private:
414422
/// Returns true if there is LoopInfo on the stack.
415423
bool hasInfo() const { return !Active.empty(); }

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,35 @@ static Attr *handleIntelFPGANofusionAttr(Sema &S, Stmt *St,
451451
return new (S.Context) SYCLIntelFPGANofusionAttr(S.Context, A);
452452
}
453453

454+
SYCLIntelFPGAMaxReinvocationDelayAttr *
455+
Sema::BuildSYCLIntelFPGAMaxReinvocationDelayAttr(const AttributeCommonInfo &CI,
456+
Expr *E) {
457+
if (!E->isValueDependent()) {
458+
llvm::APSInt ArgVal;
459+
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
460+
if (Res.isInvalid())
461+
return nullptr;
462+
E = Res.get();
463+
464+
// This attribute requires a strictly positive value.
465+
if (ArgVal <= 0) {
466+
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
467+
<< CI << /*positive*/ 0;
468+
return nullptr;
469+
}
470+
}
471+
472+
return new (Context) SYCLIntelFPGAMaxReinvocationDelayAttr(Context, CI, E);
473+
}
474+
475+
static Attr * handleSYCLIntelFPGAMaxReinvocationDelayAttr(Sema &S, Stmt *St,
476+
const ParsedAttr &A) {
477+
S.CheckDeprecatedSYCLAttributeSpelling(A);
478+
479+
Expr *E = A.getArgAsExpr(0);
480+
return S.BuildSYCLIntelFPGAMaxReinvocationDelayAttr(A, E);
481+
}
482+
454483
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
455484
SourceRange) {
456485
IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
@@ -828,6 +857,8 @@ static void CheckForIncompatibleSYCLLoopAttributes(
828857
CheckForDuplicationSYCLLoopAttribute<LoopUnrollHintAttr>(S, Attrs, false);
829858
CheckRedundantSYCLIntelFPGAIVDepAttrs(S, Attrs);
830859
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGANofusionAttr>(S, Attrs);
860+
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAMaxReinvocationDelayAttr>(
861+
S, Attrs);
831862
}
832863

833864
void CheckForIncompatibleUnrollHintAttributes(
@@ -973,6 +1004,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
9731004
return handleUnlikely(S, St, A, Range);
9741005
case ParsedAttr::AT_SYCLIntelFPGANofusion:
9751006
return handleIntelFPGANofusionAttr(S, St, A);
1007+
case ParsedAttr::AT_SYCLIntelFPGAMaxReinvocationDelay:
1008+
return handleSYCLIntelFPGAMaxReinvocationDelayAttr(S, St, A);
9761009
default:
9771010
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
9781011
// declaration attribute is not written on a statement, but this code is

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,9 @@ namespace {
11121112
const SYCLIntelFPGASpeculatedIterationsAttr *SI);
11131113
const SYCLIntelFPGALoopCountAttr *
11141114
TransformSYCLIntelFPGALoopCountAttr(const SYCLIntelFPGALoopCountAttr *SI);
1115+
const SYCLIntelFPGAMaxReinvocationDelayAttr *
1116+
TransformSYCLIntelFPGAMaxReinvocationDelayAttr(
1117+
const SYCLIntelFPGAMaxReinvocationDelayAttr *MRD);
11151118

11161119
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
11171120
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -1603,6 +1606,14 @@ const LoopUnrollHintAttr *TemplateInstantiator::TransformLoopUnrollHintAttr(
16031606
return getSema().BuildLoopUnrollHintAttr(*LU, TransformedExpr);
16041607
}
16051608

1609+
const SYCLIntelFPGAMaxReinvocationDelayAttr *
1610+
TemplateInstantiator::TransformSYCLIntelFPGAMaxReinvocationDelayAttr(
1611+
const SYCLIntelFPGAMaxReinvocationDelayAttr *MRD) {
1612+
Expr *TransformedExpr = getDerived().TransformExpr(MRD->getNExpr()).get();
1613+
return getSema().BuildSYCLIntelFPGAMaxReinvocationDelayAttr(*MRD,
1614+
TransformedExpr);
1615+
}
1616+
16061617
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
16071618
NonTypeTemplateParmDecl *parm,
16081619
SourceLocation loc,

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
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_MRD:[0-9]+]]
24+
// CHECK: br label %for.cond2, !llvm.loop ![[MD_MRD_2:[0-9]+]]
25+
// CHECK: br label %for.cond13, !llvm.loop ![[MD_MRD_3:[0-9]+]]
2326

2427
void disable_loop_pipelining() {
2528
int a[10];
@@ -151,6 +154,23 @@ void loop_count_control() {
151154
a[i] = 0;
152155
}
153156

157+
template <int A, int B>
158+
void max_reinvocation_delay() {
159+
int a[10];
160+
// CHECK: ![[MD_MRD]] = distinct !{![[MD_MRD]], ![[MP]], ![[MD_max_reinvocation_delay:[0-9]+]]}
161+
// CHECK-NEXT: ![[MD_max_reinvocation_delay]] = !{!"llvm.loop.intel.max_reinvocation_delay.count", i32 3}
162+
[[intel::max_reinvocation_delay(A)]] for (int i = 0; i != 10; ++i)
163+
a[i] = 0;
164+
// CHECK: ![[MD_MRD_2]] = distinct !{![[MD_MRD_2]], ![[MP]], ![[MD_max_reinvocation_delay_2:[0-9]+]]}
165+
// CHECK-NEXT: ![[MD_max_reinvocation_delay_2]] = !{!"llvm.loop.intel.max_reinvocation_delay.count", i32 5}
166+
[[intel::max_reinvocation_delay(5)]] for (int i = 0; i != 10; ++i)
167+
a[i] = 0;
168+
// CHECK: ![[MD_MRD_3]] = distinct !{![[MD_MRD_3]], ![[MP]], ![[MD_max_reinvocation_delay_3:[0-9]+]]}
169+
// CHECK-NEXT: ![[MD_max_reinvocation_delay_3]] = !{!"llvm.loop.intel.max_reinvocation_delay.count", i32 1}
170+
[[intel::max_reinvocation_delay(B)]] for (int i = 0; i != 10; ++i)
171+
a[i] = 0;
172+
}
173+
154174
template <typename name, typename Func>
155175
__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) {
156176
kernelFunc();
@@ -166,6 +186,7 @@ int main() {
166186
max_interleaving<3, 0>();
167187
speculated_iterations<4, 0>();
168188
loop_count_control<12>();
189+
max_reinvocation_delay<3, 1>();
169190
});
170191
return 0;
171192
}

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ void foo() {
2626
[[intel::loop_count_avg(6)]] int l[10];
2727
// expected-error@+1{{'loop_count' attribute cannot be applied to a declaration}}
2828
[[intel::loop_count(8)]] int m[10];
29+
// expected-error@+1 {{'max_reinvocation_delay' attribute cannot be applied to a declaration}}
30+
[[intel::max_reinvocation_delay(1)]] int n[10];
2931
}
3032

3133
// Test for deprecated spelling of Intel FPGA loop attributes
@@ -122,6 +124,9 @@ void boo() {
122124
// expected-error@+1 {{'loop_count' attribute takes one argument}}
123125
[[intel::loop_count(6, 9)]] for (int i = 0; i != 10; ++i)
124126
a[i] = 0;
127+
// expected-error@+1 {{'max_reinvocation_delay' attribute takes one argument}}
128+
[[intel::max_reinvocation_delay(5, 2)]] for (int i = 0; i != 10; ++i)
129+
a[i] = 0;
125130
}
126131

127132
// Test for incorrect argument value for Intel FPGA loop attributes
@@ -216,6 +221,12 @@ void goo() {
216221
// expected-error@+1 {{'loop_count' attribute requires a non-negative integral compile time constant expression}}
217222
[[intel::loop_count(-1)]] for (int i = 0; i != 10; ++i)
218223
a[i] = 0;
224+
// expected-error@+1 {{'max_reinvocation_delay' attribute requires a positive integral compile time constant expression}}
225+
[[intel::max_reinvocation_delay(0)]] for (int i = 0; i != 10; ++i)
226+
a[i] = 0;
227+
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[8]'}}
228+
[[intel::max_reinvocation_delay("test123")]] for (int i = 0; i != 10; ++i)
229+
a[i] = 0;
219230
}
220231

221232
// Test for Intel FPGA loop attributes duplication
@@ -334,6 +345,11 @@ void zoo() {
334345
// expected-error@+1{{duplicate Intel FPGA loop attribute 'loop_count'}}
335346
[[intel::loop_count(2)]] for (int i = 0; i != 10; ++i)
336347
a[i] = 0;
348+
349+
[[intel::max_reinvocation_delay(1)]]
350+
// expected-error@+1{{duplicate Intel FPGA loop attribute 'max_reinvocation_delay'}}
351+
[[intel::max_reinvocation_delay(1)]] for (int i = 0; i != 10; ++i)
352+
a[i] = 0;
337353
}
338354

339355
// Test for Intel FPGA loop attributes compatibility
@@ -374,6 +390,10 @@ void loop_attrs_compatibility() {
374390
a[i] = 0;
375391
[[intel::loop_count(8)]] for (int i = 0; i != 10; ++i)
376392
a[i] = 0;
393+
// expected-error@+2 {{'disable_loop_pipelining' and 'max_reinvocation_delay' attributes are not compatible}}
394+
// expected-note@+1 {{conflicting attribute is here}}
395+
[[intel::max_reinvocation_delay(1)]] [[intel::disable_loop_pipelining]] for (int i = 0; i != 10; ++i)
396+
a[i] = 0;
377397
}
378398

379399
template<int A, int B, int C>
@@ -534,6 +554,19 @@ void loop_count_control_dependent() {
534554
a[i] = 0;
535555
}
536556

557+
template <int A, int B, int C>
558+
void max_reinvocation_delay_dependent() {
559+
int a[10];
560+
// expected-error@+1 {{'max_reinvocation_delay' attribute requires a positive integral compile time constant expression}}
561+
[[intel::max_reinvocation_delay(C)]] for (int i = 0; i != 10; ++i)
562+
a[i] = 0;
563+
564+
// expected-error@+2 {{duplicate Intel FPGA loop attribute 'max_reinvocation_delay'}}
565+
[[intel::max_reinvocation_delay(A)]]
566+
[[intel::max_reinvocation_delay(B)]] for (int i = 0; i != 10; ++i)
567+
a[i] = 0;
568+
}
569+
537570
void check_max_concurrency_expression() {
538571
int a[10];
539572
// Test that checks expression is not a constant expression.
@@ -630,6 +663,22 @@ void check_loop_count_expression() {
630663
a[i] = 0;
631664
}
632665

666+
void check_max_reinvocation_delay_expression() {
667+
int a[10];
668+
// Test that checks expression is not a constant expression.
669+
// expected-note@+1{{declared here}}
670+
int foo;
671+
// expected-error@+2{{expression is not an integral constant expression}}
672+
// expected-note@+1{{read of non-const variable 'foo' is not allowed in a constant expression}}
673+
[[intel::max_reinvocation_delay(foo + 1)]] for (int i = 0; i != 10; ++i)
674+
a[i] = 0;
675+
676+
// Test that checks expression is a constant expression.
677+
constexpr int bar = 0;
678+
[[intel::max_reinvocation_delay(bar + 2)]] for (int i = 0; i != 10; ++i) // OK
679+
a[i] = 0;
680+
}
681+
633682
// Test that checks wrong template instantiation and ensures that the type
634683
// is checked properly when instantiating from the template definition.
635684
struct S {};
@@ -671,6 +720,12 @@ void check_loop_attr_template_instantiation() {
671720
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}}
672721
[[intel::loop_count(Ty{})]] for (int i = 0; i != 10; ++i)
673722
a[i] = 0;
723+
724+
// expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'S'}}
725+
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}}
726+
[[intel::max_reinvocation_delay(Ty{})]] for (int i = 0; i != 10; ++i)
727+
a[i] = 0;
728+
674729
}
675730

676731
int main() {
@@ -693,12 +748,14 @@ int main() {
693748
speculated_iterations_dependent<1, 8, -3, 0>(); // expected-note{{in instantiation of function template specialization 'speculated_iterations_dependent<1, 8, -3, 0>' requested here}}
694749
loop_coalesce_dependent<-1, 4, 0>(); // expected-note{{in instantiation of function template specialization 'loop_coalesce_dependent<-1, 4, 0>' requested here}}
695750
loop_count_control_dependent<3, 2, -1>(); // expected-note{{in instantiation of function template specialization 'loop_count_control_dependent<3, 2, -1>' requested here}}
751+
max_reinvocation_delay_dependent<1, 3, 0>(); // expected-note{{in instantiation of function template specialization 'max_reinvocation_delay_dependent<1, 3, 0>' requested here}}
696752
check_max_concurrency_expression();
697753
check_max_interleaving_expression();
698754
check_speculated_iterations_expression();
699755
check_loop_coalesce_expression();
700756
check_initiation_interval_expression();
701757
check_loop_count_expression();
758+
check_max_reinvocation_delay_expression();
702759
check_loop_attr_template_instantiation<S>(); //expected-note{{in instantiation of function template specialization 'check_loop_attr_template_instantiation<S>' requested here}}
703760
check_loop_attr_template_instantiation<float>(); //expected-note{{in instantiation of function template specialization 'check_loop_attr_template_instantiation<float>' requested here}}
704761
});

0 commit comments

Comments
 (0)