diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index d2c7b69986267..2309cb91fb6ac 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1419,6 +1419,22 @@ def IntelFPGALocalOrStaticVar : SubsetSubjecthasLocalStorage())}], "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", diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 087c4f13494bb..1e179836fc5c5 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -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)"; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index f0216dbbc494a..26c150f515f41 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3531,6 +3531,10 @@ void CodeGenModule::generateIntelFPGAAnnotation( } Out << '}'; } + if (D->hasAttr()) + Out << "{pump:1}"; + if (D->hasAttr()) + Out << "{pump:2}"; if (const auto *BWA = D->getAttr()) { llvm::APSInt BWAInt = BWA->getValue()->EvaluateKnownConstInt(getContext()); Out << '{' << BWA->getSpelling() << ':' << BWAInt << '}'; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b520424e27e49..2fc6f35ab7785 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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 +static void handleIntelFPGAPumpAttr(Sema &S, Decl *D, const ParsedAttr &Attr) { + + checkForDuplicateAttribute(S, D, Attr); + if (checkAttrMutualExclusion(S, D, Attr)) + return; + + if (checkAttrMutualExclusion(S, D, Attr)) + return; + + if (!D->hasAttr()) + D->addAttr(IntelFPGAMemoryAttr::CreateImplicit( + S.Context, IntelFPGAMemoryAttr::Default)); + + handleSimpleAttribute(S, D, Attr); +} + /// Handle the __memory__ attribute. /// This is incompatible with the __register__ attribute. static void handleIntelFPGAMemoryAttr(Sema &S, Decl *D, @@ -5057,6 +5077,10 @@ static bool checkIntelFPGARegisterAttrCompatibility(Sema &S, Decl *D, if (!MA->isImplicit() && checkAttrMutualExclusion(S, D, Attr)) InCompat = true; + if (checkAttrMutualExclusion(S, D, Attr)) + InCompat = true; + if (checkAttrMutualExclusion(S, D, Attr)) + InCompat = true; if (checkAttrMutualExclusion(S, D, Attr)) InCompat = true; if (checkAttrMutualExclusion(S, D, Attr)) @@ -7459,6 +7483,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, break; // Intel FPGA specific attributes + case ParsedAttr::AT_IntelFPGADoublePump: + handleIntelFPGAPumpAttr( + S, D, AL); + break; + case ParsedAttr::AT_IntelFPGASinglePump: + handleIntelFPGAPumpAttr( + S, D, AL); + break; case ParsedAttr::AT_IntelFPGAMemory: handleIntelFPGAMemoryAttr(S, D, AL); break; diff --git a/clang/test/CodeGenSYCL/intel-fpga-local.cpp b/clang/test/CodeGenSYCL/intel-fpga-local.cpp index a814ccf0548a5..0c78989249f37 100644 --- a/clang/test/CodeGenSYCL/intel-fpga-local.cpp +++ b/clang/test/CodeGenSYCL/intel-fpga-local.cpp @@ -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} @@ -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() { @@ -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() { @@ -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 @@ -104,4 +124,4 @@ int main() { baz(); }); return 0; -} \ No newline at end of file +} diff --git a/clang/test/SemaSYCL/intel-fpga-local.cpp b/clang/test/SemaSYCL/intel-fpga-local.cpp index 2fd12ee751fd6..0a0d7539cbd91 100644 --- a/clang/test/SemaSYCL/intel-fpga-local.cpp +++ b/clang/test/SemaSYCL/intel-fpga-local.cpp @@ -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__)) @@ -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 @@ -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__)) @@ -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]; @@ -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