Skip to content
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
16 changes: 16 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,22 @@ def IntelFPGALocalOrStaticVar : SubsetSubject<Var,
S->hasLocalStorage())}],
"local variables, static variables">;

def IntelFPGADoublePump : Attr {
let Spellings = [GNU<"doublepump">, CXX11<"intelfpga", "doublepump">];
let Subjects = SubjectList<[IntelFPGAConstVar, IntelFPGALocalOrStaticVar,
Field], ErrorDiag>;
let LangOpts = [SYCL];
let Documentation = [IntelFPGADoublePumpAttrDocs];
}

def IntelFPGASinglePump : Attr {
let Spellings = [GNU<"singlepump">, CXX11<"intelfpga", "singlepump">];
let Subjects = SubjectList<[IntelFPGAConstVar, IntelFPGALocalOrStaticVar,
Field], ErrorDiag>;
let LangOpts = [SYCL];
let Documentation = [IntelFPGASinglePumpAttrDocs];
}

def IntelFPGAMemory : Attr {
let Spellings = [GNU<"memory">, CXX11<"intelfpga", "memory">];
let Args = [EnumArgument<"Kind", "MemoryKind",
Expand Down
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,26 @@ as ``-mlong-calls`` and ``-mno-long-calls``.
}];
}

def IntelFPGADoublePumpAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "doublepump (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
that is clocked at twice the rate of its accessors.
}];
}

def IntelFPGASinglePumpAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "singlepump (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
that is clocked at the same rate as its accessors.
}];
}

def IntelFPGAMemoryAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "memory (IntelFPGA)";
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 @@ -3531,6 +3531,10 @@ void CodeGenModule::generateIntelFPGAAnnotation(
}
Out << '}';
}
if (D->hasAttr<IntelFPGASinglePumpAttr>())
Out << "{pump:1}";
if (D->hasAttr<IntelFPGADoublePumpAttr>())
Out << "{pump:2}";
if (const auto *BWA = D->getAttr<IntelFPGABankWidthAttr>()) {
llvm::APSInt BWAInt = BWA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << BWA->getSpelling() << ':' << BWAInt << '}';
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5013,6 +5013,26 @@ static bool checkForDuplicateAttribute(Sema &S, Decl *D,
return false;
}

/// Handle the __doublepump__ and __singlepump__ attributes.
/// One but not both can be specified
/// Both are incompatible with the __register__ attribute.
template <typename AttrType, typename IncompatAttrType>
static void handleIntelFPGAPumpAttr(Sema &S, Decl *D, const ParsedAttr &Attr) {

checkForDuplicateAttribute<AttrType>(S, D, Attr);
if (checkAttrMutualExclusion<IncompatAttrType>(S, D, Attr))
return;

if (checkAttrMutualExclusion<IntelFPGARegisterAttr>(S, D, Attr))
return;

if (!D->hasAttr<IntelFPGAMemoryAttr>())
D->addAttr(IntelFPGAMemoryAttr::CreateImplicit(
S.Context, IntelFPGAMemoryAttr::Default));

handleSimpleAttribute<AttrType>(S, D, Attr);
}

/// Handle the __memory__ attribute.
/// This is incompatible with the __register__ attribute.
static void handleIntelFPGAMemoryAttr(Sema &S, Decl *D,
Expand Down Expand Up @@ -5057,6 +5077,10 @@ static bool checkIntelFPGARegisterAttrCompatibility(Sema &S, Decl *D,
if (!MA->isImplicit() &&
checkAttrMutualExclusion<IntelFPGAMemoryAttr>(S, D, Attr))
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGADoublePumpAttr>(S, D, Attr))
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGASinglePumpAttr>(S, D, Attr))
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGABankWidthAttr>(S, D, Attr))
InCompat = true;
if (checkAttrMutualExclusion<IntelFPGAMaxConcurrencyAttr>(S, D, Attr))
Expand Down Expand Up @@ -7459,6 +7483,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
break;

// Intel FPGA specific attributes
case ParsedAttr::AT_IntelFPGADoublePump:
handleIntelFPGAPumpAttr<IntelFPGADoublePumpAttr, IntelFPGASinglePumpAttr>(
S, D, AL);
break;
case ParsedAttr::AT_IntelFPGASinglePump:
handleIntelFPGAPumpAttr<IntelFPGASinglePumpAttr, IntelFPGADoublePumpAttr>(
S, D, AL);
break;
case ParsedAttr::AT_IntelFPGAMemory:
handleIntelFPGAMemoryAttr(S, D, AL);
break;
Expand Down
22 changes: 21 additions & 1 deletion clang/test/CodeGenSYCL/intel-fpga-local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
//CHECK: [[ANN3:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}
//CHECK: [[ANN4:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{bankwidth:4}
//CHECK: [[ANN5:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{max_concurrency:8}
//CHECK: [[ANN10:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{pump:1}
//CHECK: [[ANN11:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{pump:2}
//CHECK: [[ANN6:@.str[\.]*[0-9]*]] = {{.*}}{memory:BLOCK_RAM}
//CHECK: [[ANN7:@.str[\.]*[0-9]*]] = {{.*}}{memory:MLAB}
//CHECK: [[ANN8:@.str[\.]*[0-9]*]] = {{.*}}{memory:DEFAULT}{bankwidth:8}
Expand Down Expand Up @@ -35,6 +37,8 @@ struct foo_two {
int __attribute__((__memory__)) f3;
int __attribute__((__bankwidth__(4))) f4;
int __attribute__((max_concurrency(8))) f5;
int __attribute__((singlepump)) f6;
int __attribute__((doublepump)) f7;
};

void bar() {
Expand All @@ -59,6 +63,14 @@ void bar() {
//CHECK: %[[CAST:.*]] = bitcast{{.*}}%[[FIELD5]]
//CHECK: call i8* @llvm.ptr.annotation.p0i8{{.*}}%[[CAST]]{{.*}}[[ANN5]]
s1.f5 = 0;
//CHECK: %[[FIELD6:.*]] = getelementptr inbounds %struct.foo_two{{.*}}
//CHECK: %[[CAST:.*]] = bitcast{{.*}}%[[FIELD6]]
//CHECK: call i8* @llvm.ptr.annotation.p0i8{{.*}}%[[CAST]]{{.*}}[[ANN10]]
s1.f6 = 0;
//CHECK: %[[FIELD7:.*]] = getelementptr inbounds %struct.foo_two{{.*}}
//CHECK: %[[CAST:.*]] = bitcast{{.*}}%[[FIELD7]]
//CHECK: call i8* @llvm.ptr.annotation.p0i8{{.*}}%[[CAST]]{{.*}}[[ANN11]]
s1.f7 = 0;
}

void baz() {
Expand Down Expand Up @@ -90,6 +102,14 @@ void baz() {
//CHECK: %[[V_SEVEN1:v_seven[0-9]+]] = bitcast{{.*}}v_seven
//CHECK: llvm.var.annotation{{.*}}%[[V_SEVEN1]],{{.*}}[[ANN9]]
int v_seven [[intelfpga::max_concurrency(4)]];
//CHECK: %[[V_EIGHT:[0-9]+]] = bitcast{{.*}}v_eight
//CHECK: %[[V_EIGHT1:v_eight[0-9]+]] = bitcast{{.*}}v_eight
//CHECK: llvm.var.annotation{{.*}}%[[V_EIGHT1]],{{.*}}[[ANN10]]
int v_eight [[intelfpga::singlepump]];
//CHECK: %[[V_NINE:[0-9]+]] = bitcast{{.*}}v_nine
//CHECK: %[[V_NINE1:v_nine[0-9]+]] = bitcast{{.*}}v_nine
//CHECK: llvm.var.annotation{{.*}}%[[V_NINE1]],{{.*}}[[ANN11]]
int v_nine [[intelfpga::doublepump]];
}

template <typename name, typename Func>
Expand All @@ -104,4 +124,4 @@ int main() {
baz();
});
return 0;
}
}
101 changes: 101 additions & 0 deletions clang/test/SemaSYCL/intel-fpga-local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
//CHECK: FunctionDecl{{.*}}foo1
void foo1()
{
//CHECK: VarDecl{{.*}}v_one
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGADoublePumpAttr
__attribute__((__doublepump__))
unsigned int v_one[64];

//CHECK: VarDecl{{.*}}v_one2
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGADoublePumpAttr
[[intelfpga::doublepump]] unsigned int v_one2[64];

//CHECK: VarDecl{{.*}}v_two
//CHECK: IntelFPGAMemoryAttr
__attribute__((__memory__))
Expand All @@ -25,6 +36,17 @@ void foo1()
//CHECK: IntelFPGARegisterAttr
[[intelfpga::register]] unsigned int v_three2[32];

//CHECK: VarDecl{{.*}}v_four
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGASinglePumpAttr
__attribute__((__singlepump__))
unsigned int v_four[64];

//CHECK: VarDecl{{.*}}v_four2
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGASinglePumpAttr
[[intelfpga::singlepump]] unsigned int v_four2[64];

//CHECK: VarDecl{{.*}}v_five
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGABankWidthAttr
Expand Down Expand Up @@ -70,16 +92,79 @@ void foo1()
//CHECK-NEXT: IntegerLiteral{{.*}}8{{$}}
[[intelfpga::max_concurrency(8)]] unsigned int v_seven2[64];

//CHECK: VarDecl{{.*}}v_fourteen
//CHECK: IntelFPGADoublePumpAttr
//CHECK: IntelFPGAMemoryAttr{{.*}}MLAB{{$}}
__attribute__((__doublepump__))
__attribute__((__memory__("MLAB")))
unsigned int v_fourteen[64];

//CHECK: VarDecl{{.*}}v_fifteen
//CHECK: IntelFPGAMemoryAttr{{.*}}MLAB{{$}}
//CHECK: IntelFPGADoublePumpAttr
__attribute__((__memory__("MLAB")))
__attribute__((__doublepump__))
unsigned int v_fifteen[64];

int __attribute__((__register__)) A;
int __attribute__((__numbanks__(4), __bankwidth__(16), __singlepump__)) B;
int __attribute__((__numbanks__(4), __bankwidth__(16), __doublepump__)) C;
int __attribute__((__numbanks__(4), __bankwidth__(16))) E;

// diagnostics

// **doublepump
//expected-error@+2{{attributes are not compatible}}
__attribute__((__doublepump__))
__attribute__((__singlepump__))
//expected-note@-2 {{conflicting attribute is here}}
unsigned int dp_one[64];

//expected-warning@+2{{attribute 'doublepump' is already applied}}
__attribute__((doublepump))
__attribute__((__doublepump__))
unsigned int dp_two[64];

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

// **singlepump
//expected-error@+1{{attributes are not compatible}}
__attribute__((__singlepump__,__doublepump__))
//expected-note@-1 {{conflicting attribute is here}}
unsigned int sp_one[64];

//expected-warning@+2{{attribute 'singlepump' is already applied}}
__attribute__((singlepump))
__attribute__((__singlepump__))
unsigned int sp_two[64];

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

// **register
//expected-warning@+1{{attribute 'register' is already applied}}
__attribute__((register)) __attribute__((__register__))
unsigned int reg_one[64];

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

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

//expected-error@+2{{attributes are not compatible}}
__attribute__((__register__))
__attribute__((__memory__))
Expand Down Expand Up @@ -245,6 +330,11 @@ void other2()
void other3(__attribute__((__max_concurrency__(8))) int pfoo) {}

struct foo {
//CHECK: FieldDecl{{.*}}v_one
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGADoublePumpAttr
__attribute__((__doublepump__)) unsigned int v_one[64];

//CHECK: FieldDecl{{.*}}v_two
//CHECK: IntelFPGAMemoryAttr
__attribute__((__memory__)) unsigned int v_two[64];
Expand All @@ -257,10 +347,21 @@ struct foo {
//CHECK: IntelFPGAMemoryAttr{{.*}}BlockRAM{{$}}
__attribute__((__memory__("BLOCK_RAM"))) unsigned int v_two_B[64];

//CHECK: FieldDecl{{.*}}v_two_C
//CHECK: IntelFPGAMemoryAttr{{.*}}BlockRAM{{$}}
//CHECK: IntelFPGADoublePumpAttr
__attribute__((__memory__("BLOCK_RAM")))
__attribute__((doublepump)) unsigned int v_two_C[64];

//CHECK: FieldDecl{{.*}}v_three
//CHECK: IntelFPGARegisterAttr
__attribute__((__register__)) unsigned int v_three[64];

//CHECK: FieldDecl{{.*}}v_four
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGASinglePumpAttr
__attribute__((__singlepump__)) unsigned int v_four[64];

//CHECK: FieldDecl{{.*}}v_five
//CHECK: IntelFPGAMemoryAttr{{.*}}Implicit
//CHECK: IntelFPGABankWidthAttr
Expand Down