Skip to content

[SYCL][FPGA] Refactor statments attributes to align with community the way we handle conflicting vs duplicate values #12243

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 3 commits into from
Jan 10, 2024
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
56 changes: 50 additions & 6 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,50 @@ CheckForDuplicationSYCLLoopAttribute(Sema &S,
}
}

// Diagnose non-identical duplicates as a 'conflicting' loop attributes
// and suppress duplicate errors in cases where the two match for
// FPGA attributes: 'SYCLIntelMaxInterleavingAttr',
// 'SYCLIntelSpeculatedIterationsAttr', and
// 'SYCLIntelMaxReinvocationDelayAttr'.
template <typename LoopAttrT>
static void CheckForDuplicateAttrs(Sema &S, ArrayRef<const Attr *> Attrs) {
auto FindFunc = [](const Attr *A) { return isa<const LoopAttrT>(A); };
const auto *FirstItr = std::find_if(Attrs.begin(), Attrs.end(), FindFunc);

if (FirstItr == Attrs.end()) // no attributes found
return;

const auto *LastFoundItr = FirstItr;
std::optional<llvm::APSInt> FirstValue;

const auto *CAFA =
dyn_cast<ConstantExpr>(cast<LoopAttrT>(*FirstItr)->getNExpr());
// Return early if first expression is dependent (since we don't
// know what the effective size will be), and skip the loop entirely.
if (!CAFA)
return;

while (Attrs.end() != (LastFoundItr = std::find_if(LastFoundItr + 1,
Attrs.end(), FindFunc))) {
const auto *CASA =
dyn_cast<ConstantExpr>(cast<LoopAttrT>(*LastFoundItr)->getNExpr());
// If the value is dependent, we can not test anything.
if (!CASA)
return;
// Test the attribute values.
llvm::APSInt SecondValue = CASA->getResultAsAPSInt();
if (!FirstValue)
FirstValue = CAFA->getResultAsAPSInt();

if (FirstValue != SecondValue) {
S.Diag((*LastFoundItr)->getLocation(), diag::err_loop_attr_conflict)
<< *FirstItr;
S.Diag((*FirstItr)->getLocation(), diag::note_previous_attribute);
return;
}
}
}

static void CheckForIncompatibleSYCLLoopAttributes(
Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
CheckForDuplicationSYCLLoopAttribute<SYCLIntelInitiationIntervalAttr>(
Expand All @@ -973,16 +1017,13 @@ static void CheckForIncompatibleSYCLLoopAttributes(
CheckForDuplicationSYCLLoopAttribute<SYCLIntelLoopCoalesceAttr>(S, Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelDisableLoopPipeliningAttr>(
S, Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelMaxInterleavingAttr>(S,
Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelSpeculatedIterationsAttr>(
S, Attrs);
CheckForDuplicateAttrs<SYCLIntelMaxInterleavingAttr>(S, Attrs);
CheckForDuplicateAttrs<SYCLIntelSpeculatedIterationsAttr>(S, Attrs);
CheckForDuplicateSYCLIntelLoopCountAttrs(S, Attrs);
CheckForDuplicationSYCLLoopAttribute<LoopUnrollHintAttr>(S, Attrs, false);
CheckRedundantSYCLIntelIVDepAttrs(S, Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelNofusionAttr>(S, Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelMaxReinvocationDelayAttr>(
S, Attrs);
CheckForDuplicateAttrs<SYCLIntelMaxReinvocationDelayAttr>(S, Attrs);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelEnableLoopPipeliningAttr>(
S, Attrs);
}
Expand Down Expand Up @@ -1165,6 +1206,9 @@ void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,

bool Sema::CheckRebuiltAttributedStmtAttributes(ArrayRef<const Attr *> Attrs) {
CheckRedundantSYCLIntelIVDepAttrs(*this, Attrs);
CheckForDuplicateAttrs<SYCLIntelSpeculatedIterationsAttr>(*this, Attrs);
CheckForDuplicateAttrs<SYCLIntelMaxInterleavingAttr>(*this, Attrs);
CheckForDuplicateAttrs<SYCLIntelMaxReinvocationDelayAttr>(*this, Attrs);
return false;
}

Expand Down
45 changes: 34 additions & 11 deletions clang/test/SemaSYCL/intel-fpga-loops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,17 +285,24 @@ void zoo() {
[[intel::max_interleaving(1)]]
[[intel::loop_coalesce]] for (int i = 0; i != 10; ++i)
a[i] = 0;
[[intel::max_interleaving(1)]]
// expected-error@+2 {{duplicate Intel FPGA loop attribute 'max_interleaving'}}
[[intel::max_interleaving(1)]] // expected-note {{previous attribute is here}}
[[intel::max_interleaving(1)]] // OK.
// expected-error@+2 {{conflicting loop attribute 'max_interleaving'}}
[[intel::speculated_iterations(1)]]
[[intel::max_interleaving(0)]] for (int i = 0; i != 10; ++i)
a[i] = 0;
[[intel::speculated_iterations(1)]]
// expected-error@+2 {{duplicate Intel FPGA loop attribute 'speculated_iterations'}}
[[intel::speculated_iterations(1)]] // expected-note {{previous attribute is here}}
// expected-error@+2 {{conflicting loop attribute 'speculated_iterations'}}
[[intel::loop_coalesce]]
[[intel::speculated_iterations(2)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::speculated_iterations(1)]] // expected-note {{previous attribute is here}}
[[intel::speculated_iterations(1)]] // OK
// expected-error@+1 {{conflicting loop attribute 'speculated_iterations'}}
[[intel::speculated_iterations(2)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::ivdep]]
// expected-warning@+2 {{ignoring redundant Intel FPGA loop attribute 'ivdep': safelen INF >= safelen INF}}
// expected-note@-2 {{previous attribute is here}}
Expand Down Expand Up @@ -359,10 +366,15 @@ void zoo() {
a[i] = 0;

[[intel::max_reinvocation_delay(1)]]
// expected-error@+1{{duplicate Intel FPGA loop attribute 'max_reinvocation_delay'}}
[[intel::max_reinvocation_delay(1)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::max_reinvocation_delay(10)]] // expected-note {{previous attribute is here}}
[[intel::max_reinvocation_delay(10)]] // OK
// expected-error@+1 {{conflicting loop attribute 'max_reinvocation_delay'}}
[[intel::max_reinvocation_delay(20)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::enable_loop_pipelining]]
// expected-error@+1 {{duplicate Intel FPGA loop attribute 'enable_loop_pipelining'}}
[[intel::enable_loop_pipelining]] for (int i = 0; i != 10; ++i)
Expand Down Expand Up @@ -501,11 +513,14 @@ void max_interleaving_dependent() {
[[intel::max_interleaving(C)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

// expected-error@+2 {{duplicate Intel FPGA loop attribute 'max_interleaving'}}
[[intel::max_interleaving(C)]]
// expected-error@+2 {{conflicting loop attribute 'max_interleaving'}}
[[intel::max_interleaving(C)]] // expected-note {{previous attribute is here}}
[[intel::max_interleaving(D)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::max_interleaving(D)]]
[[intel::max_interleaving(D)]] for (int i = 0; i != 10; ++i)
a[i] = 0;
}

template <int A, int B, int C, int D>
Expand All @@ -515,14 +530,18 @@ void speculated_iterations_dependent() {
[[intel::speculated_iterations(C)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

// expected-error@+2 {{duplicate Intel FPGA loop attribute 'speculated_iterations'}}
[[intel::speculated_iterations(A)]]
// expected-error@+2 {{conflicting loop attribute 'speculated_iterations'}}
[[intel::speculated_iterations(A)]] // expected-note {{previous attribute is here}}
[[intel::speculated_iterations(B)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

// speculated_iterations attribute accepts value 0.
[[intel::speculated_iterations(D)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::speculated_iterations(B)]]
[[intel::speculated_iterations(B)]] for (int i = 0; i != 10; ++i)
a[i] = 0;
}

template <int A, int B, int C>
Expand Down Expand Up @@ -593,10 +612,14 @@ void max_reinvocation_delay_dependent() {
[[intel::max_reinvocation_delay(C)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

// expected-error@+2 {{duplicate Intel FPGA loop attribute 'max_reinvocation_delay'}}
[[intel::max_reinvocation_delay(A)]]
// expected-error@+2 {{conflicting loop attribute 'max_reinvocation_delay'}}
[[intel::max_reinvocation_delay(A)]] // expected-note {{previous attribute is here}}
[[intel::max_reinvocation_delay(B)]] for (int i = 0; i != 10; ++i)
a[i] = 0;

[[intel::max_reinvocation_delay(A)]]
[[intel::max_reinvocation_delay(A)]] for (int i = 0; i != 10; ++i)
a[i] = 0;
}

void check_max_concurrency_expression() {
Expand Down