Skip to content

[SYCL] Enable FPGA max_concurrency memory attribute #80

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 4 commits into from
Apr 22, 2019
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
24 changes: 24 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,14 @@ def Mode : Attr {
let PragmaAttributeSupport = 0;
}

def IntelFPGALocalNonConstVar : SubsetSubject<Var,
[{S->hasLocalStorage() &&
S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::ParmVar &&
S->getKind() != Decl::NonTypeTemplateParm &&
!S->getType().isConstQualified()}],
"local non-const variables">;

def IntelFPGAConstVar : SubsetSubject<Var,
[{S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::ParmVar &&
Expand Down Expand Up @@ -1474,6 +1482,22 @@ def IntelFPGANumBanks : Attr {
}];
}

def IntelFPGAMaxConcurrency : InheritableAttr {
let Spellings = [GNU<"max_concurrency">, CXX11<"intelfpga","max_concurrency">];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps intelfpga would be clearer if written intel_fpga.
Are these attributes defined to be compatible with some other tools or are just brand new attributes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these attributes defined to be compatible with some other tools or are just brand new attributes?

You can already use them, for example, in Intel® FPGA SDK for OpenCL™ 19.1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. With the "intelfpga::" namespace?
But honestly I have no problem about having Intel extension harder to use or unclear. ;-)

let Args = [ExprArgument<"Value">];
let LangOpts = [SYCL];
let Subjects = SubjectList<[IntelFPGALocalNonConstVar, Field], ErrorDiag>;
let Documentation = [IntelFPGAMaxConcurrencyAttrDocs];
let AdditionalMembers = [{
static unsigned getMinValue() {
return 0;
}
static unsigned getMaxValue() {
return 1024*1024;
}
}];
}

def Naked : InheritableAttr {
let Spellings = [GCC<"naked">, Declspec<"naked">];
let Subjects = SubjectList<[Function]>;
Expand Down
19 changes: 15 additions & 4 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1670,7 +1670,7 @@ as ``-mlong-calls`` and ``-mno-long-calls``.

def IntelFPGAMemoryAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "memory (IntelFGPA)";
let Heading = "memory (IntelFPGA)";
let Content = [{
This attribute may be attached to a variable or struct member declaration and
instructs the backend to implement the variable or struct member in memory
Expand All @@ -1681,7 +1681,7 @@ it indicates what type of memory to use.

def IntelFPGARegisterAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "register (IntelFGPA)";
let Heading = "register (IntelFPGA)";
let Content = [{
This attribute may be attached to a variable or struct member declaration and
instructs the backend to promote the variable or struct member to register(s)
Expand All @@ -1691,7 +1691,7 @@ if possible.

def IntelFPGABankWidthAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "bankwidth (IntelFGPA)";
let Heading = "bankwidth (IntelFPGA)";
let Content = [{
This attribute may be attached to a variable or struct member declaration and
instructs the backend to implement the variable or struct member in a memory
Expand All @@ -1701,14 +1701,25 @@ with banks that are N bytes wide.

def IntelFPGANumBanksAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "numbanks (IntelFGPA)";
let Heading = "numbanks (IntelFPGA)";
let Content = [{
This attribute may be attached to a variable or struct member declaration and
instructs the backend to implement the variable or struct member in a memory
with N banks.
}];
}

def IntelFPGAMaxConcurrencyAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "max_concurrency (IntelFPGA)";
let Content = [{
This attribute may be attached to a variable or struct member declaration and
instructs the backend to replicate the memory generated for the variable or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memory generated might be unclear for people not familiar with FPGA.
But I do not now what to have instead. memory synthesized?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memory generated might be unclear for people not familiar with FPGA.
But I do not now what to have instead. memory synthesized?

I agree.

struct member sufficiently to enable the specified number of simultaneous
threads or loop iterations.
}];
}

def RISCVInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (RISCV)";
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8755,6 +8755,9 @@ class Sema {
bool checkRangedIntegralArgument(Expr *E, const AttrType *TmpAttr,
ExprResult &Result);
template <typename AttrType>
void AddOneConstantValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex);
template <typename AttrType>
void AddOneConstantPowerTwoValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex);

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3535,6 +3535,10 @@ void CodeGenModule::generateIntelFPGAAnnotation(
llvm::APSInt BWAInt = BWA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << BWA->getSpelling() << ':' << BWAInt << '}';
}
if (const auto *MCA = D->getAttr<IntelFPGAMaxConcurrencyAttr>()) {
llvm::APSInt MCAInt = MCA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << MCA->getSpelling() << ':' << MCAInt << '}';
}
if (const auto *NBA = D->getAttr<IntelFPGANumBanksAttr>()) {
llvm::APSInt BWAInt = NBA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << NBA->getSpelling() << ':' << BWAInt << '}';
Expand Down
38 changes: 38 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3781,6 +3781,28 @@ bool Sema::checkRangedIntegralArgument(Expr *E, const AttrType *TmpAttr,
return false;
}

template <typename AttrType>
void Sema::AddOneConstantValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex) {
AttrType TmpAttr(AttrRange, Context, E, SpellingListIndex);

if (!E->isValueDependent()) {
ExprResult ICE;
if (checkRangedIntegralArgument<AttrType>(E, &TmpAttr, ICE))
return;
E = ICE.get();
}

if (IntelFPGAMaxConcurrencyAttr::classof(&TmpAttr)) {
if (!D->hasAttr<IntelFPGAMemoryAttr>())
D->addAttr(IntelFPGAMemoryAttr::CreateImplicit(
Context, IntelFPGAMemoryAttr::Default));
}

D->addAttr(::new (Context)
AttrType(AttrRange, Context, E, SpellingListIndex));
}

template <typename AttrType>
void Sema::AddOneConstantPowerTwoValueAttr(SourceRange AttrRange, Decl *D,
Expr *E,
Expand Down Expand Up @@ -5037,6 +5059,8 @@ static bool checkIntelFPGARegisterAttrCompatibility(Sema &S, Decl *D,
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGABankWidthAttr>(S, D, Attr))
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGAMaxConcurrencyAttr>(S, D, Attr))
InCompat = true;
if (auto *NBA = D->getAttr<IntelFPGANumBanksAttr>())
if (!NBA->isImplicit() &&
checkAttrMutualExclusion<IntelFPGANumBanksAttr>(S, D, Attr))
Expand Down Expand Up @@ -5074,6 +5098,17 @@ static void handleOneConstantPowerTwoValueAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex());
}

static void handleIntelFPGAMaxConcurrencyAttr(Sema &S, Decl *D,
const ParsedAttr &Attr) {
checkForDuplicateAttribute<IntelFPGAMaxConcurrencyAttr>(S, D, Attr);
if (checkAttrMutualExclusion<IntelFPGARegisterAttr>(S, D, Attr))
return;

S.AddOneConstantValueAttr<IntelFPGAMaxConcurrencyAttr>(
Attr.getRange(), D, Attr.getArgAsExpr(0),
Attr.getAttributeSpellingListIndex());
}

static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParamIdx ArgCount;

Expand Down Expand Up @@ -7436,6 +7471,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_IntelFPGANumBanks:
handleOneConstantPowerTwoValueAttr<IntelFPGANumBanksAttr>(S, D, AL);
break;
case ParsedAttr::AT_IntelFPGAMaxConcurrency:
handleIntelFPGAMaxConcurrencyAttr(S, D, AL);
break;

case ParsedAttr::AT_AnyX86NoCallerSavedRegisters:
handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL);
Expand Down
23 changes: 17 additions & 6 deletions clang/test/CodeGenSYCL/intel-fpga-local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
//CHECK: [[ANN2:@.str[\.]*[0-9]*]] = {{.*}}{register:1}
//CHECK: [[ANN3:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}
//CHECK: [[ANN4:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{bankwidth:4}
//CHECK: [[ANN5:@.str[\.]*[0-9]*]] = {{.*}}{memory:BLOCK_RAM}
//CHECK: [[ANN6:@.str[\.]*[0-9]*]] = {{.*}}{memory:MLAB}
//CHECK: [[ANN7:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{bankwidth:8}
//CHECK: [[ANN5:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{max_concurrency:8}
//CHECK: [[ANN6:@.str[\.]*[0-9]*]] = {{.*}}{memory:BLOCK_RAM}
//CHECK: [[ANN7:@.str[\.]*[0-9]*]] = {{.*}}{memory:MLAB}
//CHECK: [[ANN8:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{bankwidth:8}
//CHECK: [[ANN9:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{max_concurrency:4}

void foo() {
//CHECK: %[[VAR_ONE:[0-9]+]] = bitcast{{.*}}var_one
Expand All @@ -32,6 +34,7 @@ struct foo_two {
int __attribute__((register)) f2;
int __attribute__((__memory__)) f3;
int __attribute__((__bankwidth__(4))) f4;
int __attribute__((max_concurrency(8))) f5;
};

void bar() {
Expand All @@ -52,6 +55,10 @@ void bar() {
//CHECK: %[[CAST:.*]] = bitcast{{.*}}%[[FIELD4]]
//CHECK: call i8* @llvm.ptr.annotation.p0i8{{.*}}%[[CAST]]{{.*}}[[ANN4]]
s1.f4 = 0;
//CHECK: %[[FIELD5:.*]] = getelementptr inbounds %struct.foo_two{{.*}}
//CHECK: %[[CAST:.*]] = bitcast{{.*}}%[[FIELD5]]
//CHECK: call i8* @llvm.ptr.annotation.p0i8{{.*}}%[[CAST]]{{.*}}[[ANN5]]
s1.f5 = 0;
}

void baz() {
Expand All @@ -69,16 +76,20 @@ void baz() {
int v_three [[intelfpga::memory]];
//CHECK: %[[V_FOUR:[0-9]+]] = bitcast{{.*}}v_four
//CHECK: %[[V_FOUR1:v_four[0-9]+]] = bitcast{{.*}}v_four
//CHECK: llvm.var.annotation{{.*}}%[[V_FOUR1]],{{.*}}[[ANN5]]
//CHECK: llvm.var.annotation{{.*}}%[[V_FOUR1]],{{.*}}[[ANN6]]
int v_four [[intelfpga::memory("BLOCK_RAM")]];
//CHECK: %[[V_FIVE:[0-9]+]] = bitcast{{.*}}v_five
//CHECK: %[[V_FIVE1:v_five[0-9]+]] = bitcast{{.*}}v_five
//CHECK: llvm.var.annotation{{.*}}%[[V_FIVE1]],{{.*}}[[ANN6]]
//CHECK: llvm.var.annotation{{.*}}%[[V_FIVE1]],{{.*}}[[ANN7]]
int v_five [[intelfpga::memory("MLAB")]];
//CHECK: %[[V_SIX:[0-9]+]] = bitcast{{.*}}v_six
//CHECK: %[[V_SIX1:v_six[0-9]+]] = bitcast{{.*}}v_six
//CHECK: llvm.var.annotation{{.*}}%[[V_SIX1]],{{.*}}[[ANN7]]
//CHECK: llvm.var.annotation{{.*}}%[[V_SIX1]],{{.*}}[[ANN8]]
int v_six [[intelfpga::bankwidth(8)]];
//CHECK: %[[V_SEVEN:[0-9]+]] = bitcast{{.*}}v_seven
//CHECK: %[[V_SEVEN1:v_seven[0-9]+]] = bitcast{{.*}}v_seven
//CHECK: llvm.var.annotation{{.*}}%[[V_SEVEN1]],{{.*}}[[ANN9]]
int v_seven [[intelfpga::max_concurrency(4)]];
}

template <typename name, typename Func>
Expand Down
84 changes: 79 additions & 5 deletions clang/test/SemaSYCL/intel-fpga-local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,22 @@ void foo1()
//CHECK: IntelFPGANumBanksAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}4{{$}}
__attribute__((__numbanks__(4))) unsigned int v_six2[32];
[[intelfpga::numbanks(4)]] unsigned int v_six2[32];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clearer, indeed!


//CHECK: VarDecl{{.*}}v_seven
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGAMaxConcurrencyAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}4{{$}}
__attribute__((max_concurrency(4)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a little bit scared about naming conflicts with thousands of top-level attributes landing from many vendors...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. We'll think on how to solve this for C-style attributes.

unsigned int v_seven[64];

//CHECK: VarDecl{{.*}}v_seven2
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGAMaxConcurrencyAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}8{{$}}
[[intelfpga::max_concurrency(8)]] unsigned int v_seven2[64];

int __attribute__((__register__)) A;
int __attribute__((__numbanks__(4), __bankwidth__(16))) E;
Expand All @@ -77,6 +92,12 @@ void foo1()
//expected-note@-2 {{conflicting attribute is here}}
unsigned int reg_six[64];

//expected-error@+2{{attributes are not compatible}}
__attribute__((__register__))
__attribute__((__max_concurrency__(16)))
//expected-note@-2 {{conflicting attribute is here}}
unsigned int reg_six_two[64];

//expected-error@+2{{attributes are not compatible}}
__attribute__((__register__))
__attribute__((__numbanks__(8)))
Expand Down Expand Up @@ -117,7 +138,7 @@ void foo1()
__attribute__((__bankwidth__(3)))
unsigned int bw_three[64];

//expected-error@+1{{requires integer constant between 1 and 1048576}}
//expected-error@+1{{'bankwidth' attribute requires integer constant between 1 and 1048576 inclusive}}
__attribute__((__bankwidth__(-4)))
unsigned int bw_four[64];

Expand All @@ -131,10 +152,43 @@ void foo1()
__attribute__((__bankwidth__(4,8)))
unsigned int bw_six[64];

//expected-error@+1{{requires integer constant between 1 and 1048576}}
//expected-error@+1{{'bankwidth' attribute requires integer constant between 1 and 1048576 inclusive}}
__attribute__((__bankwidth__(0)))
unsigned int bw_seven[64];

// max_concurrency
//expected-error@+2{{attributes are not compatible}}
__attribute__((__max_concurrency__(16)))
__attribute__((__register__))
//expected-note@-2 {{conflicting attribute is here}}
unsigned int mc_one[64];

//CHECK: VarDecl{{.*}}mc_two
//CHECK: IntelFPGAMaxConcurrencyAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}8{{$}}
//CHECK: IntelFPGAMaxConcurrencyAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}16{{$}}
//expected-warning@+2{{is already applied}}
__attribute__((__max_concurrency__(8)))
__attribute__((__max_concurrency__(16)))
unsigned int mc_two[64];

//expected-error@+1{{'max_concurrency' attribute requires integer constant between 0 and 1048576 inclusive}}
__attribute__((__max_concurrency__(-4)))
unsigned int mc_four[64];

int i_max_concurrency = 32; // expected-note {{declared here}}
//expected-error@+1{{expression is not an integral constant expression}}
__attribute__((__max_concurrency__(i_max_concurrency)))
//expected-note@-1{{read of non-const variable 'i_max_concurrency' is not allowed in a constant expression}}
unsigned int mc_five[64];

//expected-error@+1{{'__max_concurrency__' attribute takes one argument}}
__attribute__((__max_concurrency__(4,8)))
unsigned int mc_six[64];

// numbanks
//expected-error@+2{{attributes are not compatible}}
__attribute__((__numbanks__(16)))
Expand All @@ -158,7 +212,7 @@ void foo1()
__attribute__((__numbanks__(15)))
unsigned int nb_three[64];

//expected-error@+1{{requires integer constant between 1 and 1048576}}
//expected-error@+1{{attribute requires integer constant between 1 and 1048576 inclusive}}
__attribute__((__numbanks__(-4)))
unsigned int nb_four[64];

Expand All @@ -172,11 +226,24 @@ void foo1()
__attribute__((__numbanks__(4,8)))
unsigned int nb_six[64];

//expected-error@+1{{requires integer constant between 1 and 1048576}}
//expected-error@+1{{'numbanks' attribute requires integer constant between 1 and 1048576 inclusive}}
__attribute__((__numbanks__(0)))
unsigned int nb_seven[64];
}

//expected-error@+1{{attribute only applies to local non-const variables and non-static data members}}
__attribute__((__max_concurrency__(8)))
__constant unsigned int ext_two[64] = { 1, 2, 3 };

void other2()
{
//expected-error@+1{{attribute only applies to local non-const variables and non-static data members}}
__attribute__((__max_concurrency__(8))) const int ext_six[64] = { 0, 1 };
}

//expected-error@+1{{attribute only applies to local non-const variables and non-static data members}}
void other3(__attribute__((__max_concurrency__(8))) int pfoo) {}

struct foo {
//CHECK: FieldDecl{{.*}}v_two
//CHECK: IntelFPGAMemoryAttr
Expand Down Expand Up @@ -207,6 +274,13 @@ struct foo {
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}8{{$}}
__attribute__((__numbanks__(8))) unsigned int v_six[64];

//CHECK: FieldDecl{{.*}}v_seven
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGAMaxConcurrencyAttr
//CHECK-NEXT: ConstantExpr
//CHECK-NEXT: IntegerLiteral{{.*}}4{{$}}
__attribute__((__max_concurrency__(4))) unsigned int v_seven[64];
};

template <typename name, typename Func>
Expand Down