diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4fb4fb4a0744a..d2c7b69986267 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1387,6 +1387,14 @@ def Mode : Attr { let PragmaAttributeSupport = 0; } +def IntelFPGALocalNonConstVar : SubsetSubjecthasLocalStorage() && + S->getKind() != Decl::ImplicitParam && + S->getKind() != Decl::ParmVar && + S->getKind() != Decl::NonTypeTemplateParm && + !S->getType().isConstQualified()}], + "local non-const variables">; + def IntelFPGAConstVar : SubsetSubjectgetKind() != Decl::ImplicitParam && S->getKind() != Decl::ParmVar && @@ -1474,6 +1482,22 @@ def IntelFPGANumBanks : Attr { }]; } +def IntelFPGAMaxConcurrency : InheritableAttr { + let Spellings = [GNU<"max_concurrency">, CXX11<"intelfpga","max_concurrency">]; + 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]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index b38462b53ad40..087c4f13494bb 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -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 @@ -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) @@ -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 @@ -1701,7 +1701,7 @@ 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 @@ -1709,6 +1709,17 @@ 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 +struct member sufficiently to enable the specified number of simultaneous +threads or loop iterations. + }]; +} + def RISCVInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (RISCV)"; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b4288f487bfc6..87b2a8d58a4ea 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8755,6 +8755,9 @@ class Sema { bool checkRangedIntegralArgument(Expr *E, const AttrType *TmpAttr, ExprResult &Result); template + void AddOneConstantValueAttr(SourceRange AttrRange, Decl *D, Expr *E, + unsigned SpellingListIndex); + template void AddOneConstantPowerTwoValueAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned SpellingListIndex); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d2bc525f22b8a..f0216dbbc494a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3535,6 +3535,10 @@ void CodeGenModule::generateIntelFPGAAnnotation( llvm::APSInt BWAInt = BWA->getValue()->EvaluateKnownConstInt(getContext()); Out << '{' << BWA->getSpelling() << ':' << BWAInt << '}'; } + if (const auto *MCA = D->getAttr()) { + llvm::APSInt MCAInt = MCA->getValue()->EvaluateKnownConstInt(getContext()); + Out << '{' << MCA->getSpelling() << ':' << MCAInt << '}'; + } if (const auto *NBA = D->getAttr()) { llvm::APSInt BWAInt = NBA->getValue()->EvaluateKnownConstInt(getContext()); Out << '{' << NBA->getSpelling() << ':' << BWAInt << '}'; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 6814f1c7e38b8..b520424e27e49 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3781,6 +3781,28 @@ bool Sema::checkRangedIntegralArgument(Expr *E, const AttrType *TmpAttr, return false; } +template +void Sema::AddOneConstantValueAttr(SourceRange AttrRange, Decl *D, Expr *E, + unsigned SpellingListIndex) { + AttrType TmpAttr(AttrRange, Context, E, SpellingListIndex); + + if (!E->isValueDependent()) { + ExprResult ICE; + if (checkRangedIntegralArgument(E, &TmpAttr, ICE)) + return; + E = ICE.get(); + } + + if (IntelFPGAMaxConcurrencyAttr::classof(&TmpAttr)) { + if (!D->hasAttr()) + D->addAttr(IntelFPGAMemoryAttr::CreateImplicit( + Context, IntelFPGAMemoryAttr::Default)); + } + + D->addAttr(::new (Context) + AttrType(AttrRange, Context, E, SpellingListIndex)); +} + template void Sema::AddOneConstantPowerTwoValueAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -5037,6 +5059,8 @@ static bool checkIntelFPGARegisterAttrCompatibility(Sema &S, Decl *D, InCompat = true; if (checkAttrMutualExclusion(S, D, Attr)) InCompat = true; + if (checkAttrMutualExclusion(S, D, Attr)) + InCompat = true; if (auto *NBA = D->getAttr()) if (!NBA->isImplicit() && checkAttrMutualExclusion(S, D, Attr)) @@ -5074,6 +5098,17 @@ static void handleOneConstantPowerTwoValueAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex()); } +static void handleIntelFPGAMaxConcurrencyAttr(Sema &S, Decl *D, + const ParsedAttr &Attr) { + checkForDuplicateAttribute(S, D, Attr); + if (checkAttrMutualExclusion(S, D, Attr)) + return; + + S.AddOneConstantValueAttr( + Attr.getRange(), D, Attr.getArgAsExpr(0), + Attr.getAttributeSpellingListIndex()); +} + static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamIdx ArgCount; @@ -7436,6 +7471,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_IntelFPGANumBanks: handleOneConstantPowerTwoValueAttr(S, D, AL); break; + case ParsedAttr::AT_IntelFPGAMaxConcurrency: + handleIntelFPGAMaxConcurrencyAttr(S, D, AL); + break; case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: handleSimpleAttribute(S, D, AL); diff --git a/clang/test/CodeGenSYCL/intel-fpga-local.cpp b/clang/test/CodeGenSYCL/intel-fpga-local.cpp index 9d6c624e07a08..a814ccf0548a5 100644 --- a/clang/test/CodeGenSYCL/intel-fpga-local.cpp +++ b/clang/test/CodeGenSYCL/intel-fpga-local.cpp @@ -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 @@ -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() { @@ -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() { @@ -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 diff --git a/clang/test/SemaSYCL/intel-fpga-local.cpp b/clang/test/SemaSYCL/intel-fpga-local.cpp index 29ad19aabbe43..2fd12ee751fd6 100644 --- a/clang/test/SemaSYCL/intel-fpga-local.cpp +++ b/clang/test/SemaSYCL/intel-fpga-local.cpp @@ -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]; + + //CHECK: VarDecl{{.*}}v_seven + //CHECK: IntelFPGAMemoryAttr{{.*}}Implicit + //CHECK: IntelFPGAMaxConcurrencyAttr + //CHECK-NEXT: ConstantExpr + //CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + __attribute__((max_concurrency(4))) + 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; @@ -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))) @@ -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]; @@ -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))) @@ -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]; @@ -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 @@ -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