Skip to content

Commit

Permalink
[SYCL] Enable C++11 attribute spelling for clang loop_unroll attrib…
Browse files Browse the repository at this point in the history
…ute (#670)

Signed-off-by: Viktoria Maksimova <viktoria.maksimova@intel.com>
  • Loading branch information
vmaksimo authored and bader committed Sep 27, 2019
1 parent 5b0952c commit 2f1e243
Show file tree
Hide file tree
Showing 12 changed files with 239 additions and 50 deletions.
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,24 @@ def OpenCLUnrollHint : InheritableAttr {
let Documentation = [OpenCLUnrollHintDocs];
}

def LoopUnrollHint : InheritableAttr {
let Spellings = [CXX11<"clang","loop_unroll">];
let Args = [UnsignedArgument<"UnrollHint">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let AdditionalMembers = [{
static const char *getName() {
return "loop_unroll";
}
std::string getDiagnosticName() const {
std::string Value = "";
if (getUnrollHint())
Value = "(" + std::to_string(getUnrollHint()) + ")";
return "[[clang::loop_unroll" + Value + "]]";
}
}];
let Documentation = [LoopUnrollHintDocs];
}

def IntelReqdSubGroupSize: InheritableAttr {
let Spellings = [GNU<"intel_reqd_sub_group_size">, CXX11<"cl", "intel_reqd_sub_group_size">];
let Args = [UnsignedArgument<"SubGroupSize">];
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3056,6 +3056,16 @@ s6.11.5 for details.
}];
}

def LoopUnrollHintDocs : Documentation {
let Category = DocCatStmt;
let Content = [{
Loop unrolling optimization hint can be specified with CXX11 attribute
``[[clang::loop_unroll]]``. The attribute is placed immediately before a for,
while, do-while, or c++11 range-based for loop. This attribute can be
used to specify full unrolling or partial unrolling by a specified amount.
}];
}

def IntelReqdSubGroupSizeDocs : Documentation {
let Category = DocCatStmt;
let Content = [{
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1242,10 +1242,11 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
"force_cuda_host_device begin">;
} // end of Parse Issue category.

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

let CategoryName = "Modules Issue" in {
def err_unexpected_module_decl : Error<
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,16 @@ def err_attribute_argument_not_power_of_two : Error<
"%0 attribute argument must be a constant power of two greater than zero">;
def err_intel_fpga_memory_arg_invalid : Error<
"%0 attribute requires either no argument or one of: %1">;
def err_intel_fpga_loop_attr_duplication : Error<
"duplicate Intel FPGA loop attribute '%0'">;
def err_intel_fpga_merge_dir_invalid : Error<
"merge direction must be 'depth' or 'width'">;
def err_intel_fpga_reg_limitations : Error <
"Illegal %select{argument of type %1 |field in argument}0 to __builtin_intel_fpga_reg.">;
def illegal_type_declared_here : Note<
"Field with illegal type declared here">;
def err_sycl_loop_attr_duplication : Error<
"duplicate %select{unroll|Intel FPGA}0 loop attribute '%1'">;
def err_loop_unroll_compatibility : Error<
"incompatible loop unroll instructions: '%0' and '%1'">;

// C99 variable-length arrays
def ext_vla : Extension<"variable length arrays are a C99 feature">,
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2554,13 +2554,13 @@ class Parser : public CodeCompletionHandler {
/// \return false if error happens.
bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs);

/// Parses intelfpga:: loop attributes if the language is SYCL
bool MaybeParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
if (getLangOpts().SYCLIsDevice)
return ParseIntelFPGALoopAttributes(Attrs);
/// Parses intelfpga:: and clang:: loop attributes if the language is SYCL
bool MaybeParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
if (getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)
return ParseSYCLLoopAttributes(Attrs);
return true;
}
bool ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs);
bool ParseSYCLLoopAttributes(ParsedAttributes &Attrs);

void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
VersionTuple ParseVersionTuple(SourceRange &Range);
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/CodeGen/CGLoopInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,23 +625,25 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
const OpenCLUnrollHintAttr *OpenCLHint =
dyn_cast<OpenCLUnrollHintAttr>(Attr);
const LoopUnrollHintAttr *UnrollHint = dyn_cast<LoopUnrollHintAttr>(Attr);

// Skip non loop hint attributes
if (!LH && !OpenCLHint) {
if (!LH && !OpenCLHint && !UnrollHint) {
continue;
}

LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
unsigned ValueInt = 1;
// Translate opencl_unroll_hint attribute argument to
// equivalent LoopHintAttr enums.
// Translate opencl_unroll_hint and clang::unroll attribute
// argument to equivalent LoopHintAttr enums.
// OpenCL v2.0 s6.11.5:
// 0 - enable unroll (no argument).
// 1 - disable unroll.
// other positive integer n - unroll by n.
if (OpenCLHint) {
ValueInt = OpenCLHint->getUnrollHint();
if (OpenCLHint || UnrollHint) {
ValueInt = OpenCLHint ? OpenCLHint->getUnrollHint()
: UnrollHint->getUnrollHint();
if (ValueInt == 0) {
State = LoopHintAttr::Enable;
} else if (ValueInt != 1) {
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs) ||
!MaybeParseIntelFPGALoopAttributes(Attrs))
!MaybeParseSYCLLoopAttributes(Attrs))
return StmtError();

StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
Expand Down Expand Up @@ -2396,19 +2396,22 @@ bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
return true;
}

bool Parser::ParseIntelFPGALoopAttributes(ParsedAttributes &Attrs) {
bool Parser::ParseSYCLLoopAttributes(ParsedAttributes &Attrs) {
MaybeParseCXX11Attributes(Attrs);

if (Attrs.empty())
return true;

if (Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAIVDep &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAII &&
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency)
Attrs.begin()->getKind() != ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency &&
Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint)
return true;

bool IsIntelFPGAAttribute = (Attrs.begin()->getKind() != ParsedAttr::AT_LoopUnrollHint);

if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
Diag(Tok, diag::err_intel_fpga_loop_attrs_on_non_loop);
Diag(Tok, diag::err_loop_attr_on_non_loop) << IsIntelFPGAAttribute;
return false;
}
return true;
Expand Down
82 changes: 56 additions & 26 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,42 +332,69 @@ CheckForIncompatibleAttributes(Sema &S,
}
}


template <typename FPGALoopAttrT> static void
CheckForDuplicationFPGALoopAttribute(Sema &S,
const SmallVectorImpl<const Attr *>
&Attrs, SourceRange Range) {
const FPGALoopAttrT *LoopFPGAAttr = nullptr;
template <typename LoopAttrT>
static void CheckForDuplicationSYCLLoopAttribute(
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range,
bool isIntelFPGAAttr = true) {
const LoopAttrT *LoopAttr = nullptr;

for (const auto *I : Attrs) {
if (LoopFPGAAttr) {
if (isa<FPGALoopAttrT>(I)) {
if (LoopAttr) {
if (isa<LoopAttrT>(I)) {
SourceLocation Loc = Range.getBegin();
// Cannot specify same type of attribute twice.
S.Diag(Loc, diag::err_intel_fpga_loop_attr_duplication)
<< LoopFPGAAttr->getName();
S.Diag(Loc, diag::err_sycl_loop_attr_duplication)
<< isIntelFPGAAttr << LoopAttr->getName();
}
}
if (isa<FPGALoopAttrT>(I))
LoopFPGAAttr = cast<FPGALoopAttrT>(I);
if (isa<LoopAttrT>(I))
LoopAttr = cast<LoopAttrT>(I);
}
}

static void
CheckForIncompatibleFPGALoopAttributes(Sema &S,
const SmallVectorImpl<const Attr *>
&Attrs, SourceRange Range) {
CheckForDuplicationFPGALoopAttribute<SYCLIntelFPGAIVDepAttr>(S, Attrs, Range);
CheckForDuplicationFPGALoopAttribute<SYCLIntelFPGAIIAttr>(S, Attrs, Range);
CheckForDuplicationFPGALoopAttribute<
SYCLIntelFPGAMaxConcurrencyAttr>(S, Attrs, Range);
static void CheckForIncompatibleSYCLLoopAttributes(
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range) {
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAIVDepAttr>(S, Attrs, Range);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAIIAttr>(S, Attrs, Range);
CheckForDuplicationSYCLLoopAttribute<SYCLIntelFPGAMaxConcurrencyAttr>(
S, Attrs, Range);
CheckForDuplicationSYCLLoopAttribute<LoopUnrollHintAttr>(S, Attrs, Range,
false);
}

void CheckForIncompatibleUnrollHintAttributes(
Sema &S, const SmallVectorImpl<const Attr *> &Attrs, SourceRange Range) {

// This check is entered after it was analyzed that there are no duplicating
// pragmas and loop attributes. So, let's perform check that there are no
// conflicting pragma unroll and unroll attribute for the loop.
const LoopUnrollHintAttr *AttrUnroll = nullptr;
const LoopHintAttr *PragmaUnroll = nullptr;
for (const auto *I : Attrs) {
if (auto *LH = dyn_cast<LoopUnrollHintAttr>(I))
AttrUnroll = LH;
if (auto *LH = dyn_cast<LoopHintAttr>(I)) {
LoopHintAttr::OptionType Opt = LH->getOption();
if (Opt == LoopHintAttr::Unroll || Opt == LoopHintAttr::UnrollCount)
PragmaUnroll = LH;
}
}

if (AttrUnroll && PragmaUnroll) {
PrintingPolicy Policy(S.Context.getLangOpts());
SourceLocation Loc = Range.getBegin();
S.Diag(Loc, diag::err_loop_unroll_compatibility)
<< PragmaUnroll->getDiagnosticName(Policy)
<< AttrUnroll->getDiagnosticName();
}
}

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

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

return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
return LoopUnrollAttrT::CreateImplicit(S.Context, UnrollFactor);
}

static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
Expand All @@ -424,7 +451,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
case ParsedAttr::AT_SYCLIntelFPGAMaxConcurrency:
return handleIntelFPGALoopAttr<SYCLIntelFPGAMaxConcurrencyAttr>(S, St, A);
case ParsedAttr::AT_OpenCLUnrollHint:
return handleOpenCLUnrollHint(S, St, A, Range);
return handleLoopUnrollHint<OpenCLUnrollHintAttr>(S, St, A, Range);
case ParsedAttr::AT_LoopUnrollHint:
return handleLoopUnrollHint<LoopUnrollHintAttr>(S, St, A, Range);
case ParsedAttr::AT_Suppress:
return handleSuppressAttr(S, St, A, Range);
default:
Expand All @@ -446,7 +475,8 @@ StmtResult Sema::ProcessStmtAttributes(Stmt *S,
}

CheckForIncompatibleAttributes(*this, Attrs);
CheckForIncompatibleFPGALoopAttributes(*this, Attrs, Range);
CheckForIncompatibleSYCLLoopAttributes(*this, Attrs, Range);
CheckForIncompatibleUnrollHintAttributes(*this, Attrs, Range);

if (Attrs.empty())
return S;
Expand Down
42 changes: 42 additions & 0 deletions clang/test/CodeGenSYCL/loop_unroll.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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

// CHECK: br label %for.cond, !llvm.loop ![[COUNT:[0-9]+]]
// CHECK: br label %while.cond, !llvm.loop ![[DISABLE:[0-9]+]]
// CHECK: br i1 %{{.*}}, label %do.body, label %do.end, !llvm.loop ![[ENABLE:[0-9]+]]

// CHECK: ![[COUNT]] = distinct !{![[COUNT]], ![[COUNT_A:[0-9]+]]}
// CHECK-NEXT: ![[COUNT_A]] = !{!"llvm.loop.unroll.count", i32 8}
void count() {
[[clang::loop_unroll(8)]]
for (int i = 0; i < 1000; ++i);
}

// CHECK: ![[DISABLE]] = distinct !{![[DISABLE]], ![[DISABLE_A:[0-9]+]]}
// CHECK-NEXT: ![[DISABLE_A]] = !{!"llvm.loop.unroll.disable"}
void disable() {
int i = 1000;
[[clang::loop_unroll(1)]]
while (i--);
}

// CHECK: ![[ENABLE]] = distinct !{![[ENABLE]], ![[ENABLE_A:[0-9]+]]}
// CHECK-NEXT: ![[ENABLE_A]] = !{!"llvm.loop.unroll.enable"}
void enable() {
int i = 1000;
[[clang::loop_unroll]]
do {} while (i--);
}

template <typename name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
kernelFunc();
}

int main() {
kernel_single_task<class kernel_function>([]() {
count();
disable();
enable();
});
return 0;
}
22 changes: 22 additions & 0 deletions clang/test/CodeGenSYCL/loop_unroll_host.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %clangxx -c -S -emit-llvm %s -o - | FileCheck %s
// CHECK: br label %{{.*}}, !llvm.loop ![[COUNT:[0-9]+]]
// CHECK: br label %{{.*}}, !llvm.loop ![[DISABLE:[0-9]+]]
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[ENABLE:[0-9]+]]

int main() {
// CHECK: ![[COUNT]] = distinct !{![[COUNT]], ![[COUNT_A:[0-9]+]]}
// CHECK-NEXT: ![[COUNT_A]] = !{!"llvm.loop.unroll.count", i32 4}
[[clang::loop_unroll(4)]]
for (int i = 0; i < 100; ++i);
// CHECK: ![[DISABLE]] = distinct !{![[DISABLE]], ![[DISABLE_A:[0-9]+]]}
// CHECK-NEXT: ![[DISABLE_A]] = !{!"llvm.loop.unroll.disable"}
int i = 1000;
[[clang::loop_unroll(1)]]
while (i--);
// CHECK: ![[ENABLE]] = distinct !{![[ENABLE]], ![[ENABLE_A:[0-9]+]]}
// CHECK-NEXT: ![[ENABLE_A]] = !{!"llvm.loop.unroll.enable"}
i = 1000;
[[clang::loop_unroll]]
do {} while (i--);
return 0;
}
8 changes: 4 additions & 4 deletions clang/test/SemaSYCL/intel-fpga-loops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

// Test for Intel FPGA loop attributes applied not to a loop
void foo() {
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intelfpga::ivdep]] int a[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intelfpga::ivdep(2)]] int b[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intelfpga::ii(2)]] int c[10];
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while or do statements}}
// expected-error@+1 {{intelfpga loop attributes must be applied to for, while, or do statements}}
[[intelfpga::max_concurrency(2)]] int d[10];
}

Expand Down
Loading

0 comments on commit 2f1e243

Please sign in to comment.