Skip to content

Commit 7d493dd

Browse files
MrSidimsbader
authored andcommitted
[SYCL][FPGA] Add io_pipe_id attribute
This attirubte is applicabale to pipe storage decl. It's expected to be used only in SYCL headers to distinguish I/O pipes from ordinar pipes and from each other. Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 29d9cc2 commit 7d493dd

File tree

8 files changed

+190
-1
lines changed

8 files changed

+190
-1
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,15 @@ def SYCLFPGAPipe : TypeAttr {
18231823
let Documentation = [SYCLFPGAPipeDocs];
18241824
}
18251825

1826+
def SYCLIntelPipeIO : Attr {
1827+
let Spellings = [GNU<"io_pipe_id">];
1828+
let Args = [ExprArgument<"ID">];
1829+
let LangOpts = [SYCLIsDevice, SYCLIsHost];
1830+
let Subjects = SubjectList<[Var]>;
1831+
let Documentation = [SYCLIntelPipeIOAttrDocs];
1832+
let PragmaAttributeSupport = 0;
1833+
}
1834+
18261835
// Variadic integral arguments.
18271836
def IntelFPGABankBits : Attr {
18281837
let Spellings = [CXX11<"intelfpga", "bank_bits">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,20 @@ write only. Expected to be used only in SYCL headers.
20332033
}];
20342034
}
20352035

2036+
def SYCLIntelPipeIOAttrDocs : Documentation {
2037+
let Category = DocCatVariable;
2038+
let Heading = "IO pipe ID";
2039+
let Content = [{
2040+
Add I/O attribute to SYCL pipe declaration to declare a special I/O pipe to
2041+
interface with input or output features of an FPGA. These features might include
2042+
network interfaces, PCIe, cameras, or other data capture or processing devices
2043+
or protocols.
2044+
2045+
The io_pipe_id(id) attribute specifies the I/O feature of an accelerator board
2046+
with which a pipe interfaces. The id argument is the name of the I/O interface.
2047+
}];
2048+
}
2049+
20362050
def SYCLIntelFPGAIVDepAttrDocs : Documentation {
20372051
let Category = DocCatVariable;
20382052
let Heading = "ivdep";

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9708,6 +9708,10 @@ class Sema final {
97089708
void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
97099709
Expr *Min, Expr *Max);
97109710

9711+
/// addSYCLIntelPipeIOAttr - Adds a pipe I/O attribute to a particular
9712+
/// declaration.
9713+
void addSYCLIntelPipeIOAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ID);
9714+
97119715
bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
97129716

97139717
//===--------------------------------------------------------------------===//

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,6 +3479,32 @@ bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
34793479
return true;
34803480
}
34813481

3482+
static void maybeEmitPipeStorageMetadata(const VarDecl *D,
3483+
llvm::GlobalVariable *GV,
3484+
CodeGenModule &CGM) {
3485+
// TODO: Applicable only on pipe storages. Currently they are defined
3486+
// as structures inside of SYCL headers. Add a check for pipe_storage_t
3487+
// when it ready.
3488+
QualType PipeTy = D->getType();
3489+
if (!PipeTy->isStructureType())
3490+
return;
3491+
3492+
if (auto *IOAttr = D->getAttr<SYCLIntelPipeIOAttr>()) {
3493+
llvm::APSInt ID(32);
3494+
llvm::LLVMContext &Context = CGM.getLLVMContext();
3495+
bool IsValid =
3496+
IOAttr->getID()->isIntegerConstantExpr(ID, D->getASTContext());
3497+
assert(IsValid && "Not an integer constant expression");
3498+
(void)IsValid;
3499+
3500+
llvm::Metadata *AttrMDArgs[] = {
3501+
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
3502+
llvm::Type::getInt32Ty(Context), ID.getSExtValue()))};
3503+
GV->setMetadata(IOAttr->getSpelling(),
3504+
llvm::MDNode::get(Context, AttrMDArgs));
3505+
}
3506+
}
3507+
34823508
/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
34833509
/// create and return an llvm GlobalVariable with the specified type. If there
34843510
/// is something in the module with the specified name, return it potentially
@@ -3668,6 +3694,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
36683694
: (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
36693695
assert(getContext().getTargetAddressSpace(ExpectedAS) ==
36703696
Ty->getPointerAddressSpace());
3697+
3698+
if (LangOpts.SYCLIsDevice)
3699+
maybeEmitPipeStorageMetadata(D, GV, *this);
3700+
36713701
if (AddrSpace != ExpectedAS)
36723702
return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
36733703
ExpectedAS, Ty);
@@ -4319,6 +4349,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
43194349
if (CGDebugInfo *DI = getModuleDebugInfo())
43204350
if (getCodeGenOpts().hasReducedDebugInfo())
43214351
DI->EmitGlobalVariable(GV, D);
4352+
4353+
if (LangOpts.SYCLIsDevice)
4354+
maybeEmitPipeStorageMetadata(D, GV, *this);
43224355
}
43234356

43244357
void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) {

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5516,6 +5516,47 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
55165516
PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
55175517
}
55185518

5519+
void Sema::addSYCLIntelPipeIOAttr(Decl *D, const AttributeCommonInfo &Attr,
5520+
Expr *E) {
5521+
VarDecl *VD = cast<VarDecl>(D);
5522+
QualType Ty = VD->getType();
5523+
// TODO: Applicable only on pipe storages. Currently they are defined
5524+
// as structures inside of SYCL headers. Add a check for pipe_storage_t
5525+
// when it is ready.
5526+
if (!Ty->isStructureType()) {
5527+
Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type_str)
5528+
<< Attr.getAttrName() << "SYCL pipe storage declaration";
5529+
return;
5530+
}
5531+
5532+
if (!E->isInstantiationDependent()) {
5533+
llvm::APSInt ArgVal(32);
5534+
if (!E->isIntegerConstantExpr(ArgVal, getASTContext())) {
5535+
Diag(E->getExprLoc(), diag::err_attribute_argument_type)
5536+
<< Attr.getAttrName() << AANT_ArgumentIntegerConstant
5537+
<< E->getSourceRange();
5538+
return;
5539+
}
5540+
int32_t ArgInt = ArgVal.getSExtValue();
5541+
if (ArgInt < 0) {
5542+
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
5543+
<< Attr.getAttrName() << /*non-negative*/ 1;
5544+
return;
5545+
}
5546+
}
5547+
5548+
D->addAttr(::new (Context) SYCLIntelPipeIOAttr(Context, Attr, E));
5549+
}
5550+
5551+
static void handleSYCLIntelPipeIOAttr(Sema &S, Decl *D,
5552+
const ParsedAttr &Attr) {
5553+
if (D->isInvalidDecl())
5554+
return;
5555+
5556+
Expr *E = Attr.getArgAsExpr(0);
5557+
S.addSYCLIntelPipeIOAttr(D, Attr, E);
5558+
}
5559+
55195560
static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
55205561
if (AliasName.startswith("__arm_"))
55215562
AliasName = AliasName.substr(6);
@@ -8040,6 +8081,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
80408081
case ParsedAttr::AT_IntelFPGABankBits:
80418082
handleIntelFPGABankBitsAttr(S, D, AL);
80428083
break;
8084+
case ParsedAttr::AT_SYCLIntelPipeIO:
8085+
handleSYCLIntelPipeIOAttr(S, D, AL);
8086+
break;
80438087

80448088
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters:
80458089
handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL);

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,17 @@ static void instantiateIntelFPGABankBitsAttr(
553553
S.AddIntelFPGABankBitsAttr(New, *Attr, Args.data(), Args.size());
554554
}
555555

556+
static void instantiateSYCLIntelPipeIOAttr(
557+
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
558+
const SYCLIntelPipeIOAttr *Attr, Decl *New) {
559+
// The ID expression is a constant expression.
560+
EnterExpressionEvaluationContext Unevaluated(
561+
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
562+
ExprResult Result = S.SubstExpr(Attr->getID(), TemplateArgs);
563+
if (!Result.isInvalid())
564+
S.addSYCLIntelPipeIOAttr(New, *Attr, Result.getAs<Expr>());
565+
}
566+
556567
void Sema::InstantiateAttrsForDecl(
557568
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
558569
Decl *New, LateInstantiatedAttrVec *LateAttrs,
@@ -686,6 +697,10 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
686697
instantiateIntelFPGABankBitsAttr(*this, TemplateArgs, IntelFPGABankBits,
687698
New);
688699
}
700+
if (const auto *SYCLIntelPipeIO = dyn_cast<SYCLIntelPipeIOAttr>(TmplAttr)) {
701+
instantiateSYCLIntelPipeIOAttr(*this, TemplateArgs, SYCLIntelPipeIO, New);
702+
continue;
703+
}
689704

690705
// Existing DLL attribute on the instantiation takes precedence.
691706
if (TmplAttr->getKind() == attr::DLLExport ||

clang/test/CodeGenSYCL/fpga_pipes.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,39 @@ RPipeTy RPipeCreator();
1111
template <typename PipeTy>
1212
void foo(PipeTy Pipe) {}
1313

14+
struct PipeStorageTy {
15+
int Size;
16+
};
17+
18+
// CHECK: @{{.*}}Storage = {{.*}} !io_pipe_id ![[ID0:[0-9]+]]
19+
constexpr PipeStorageTy
20+
Storage __attribute__((io_pipe_id(1))) = {1};
21+
22+
// CHECK: @{{.*}}TempStorage{{.*}} = {{.*}} !io_pipe_id ![[ID1:[0-9]+]]
23+
template <int N>
24+
constexpr PipeStorageTy
25+
TempStorage __attribute__((io_pipe_id(N))) = {2};
26+
27+
void boo(PipeStorageTy PipeStorage);
28+
29+
template <int ID>
30+
struct ethernet_pipe {
31+
static constexpr int id = ID;
32+
};
33+
34+
// CHECK: @{{.*}}PipeStorage{{.*}} = {{.*}} !io_pipe_id ![[ID2:[0-9]+]]
35+
template <typename name>
36+
class pipe {
37+
public:
38+
static void read() {
39+
boo(PipeStorage);
40+
}
41+
42+
private:
43+
static constexpr PipeStorageTy
44+
PipeStorage __attribute__((io_pipe_id(name::id))) = {3};
45+
};
46+
1447
template <typename name, typename Func>
1548
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
1649
kernelFunc();
@@ -24,7 +57,12 @@ int main() {
2457
RPipeTy rpipe = RPipeCreator();
2558
foo<WPipeTy>(wpipe);
2659
foo<RPipeTy>(rpipe);
60+
boo(Storage);
61+
boo(TempStorage<2>);
62+
pipe<ethernet_pipe<42>>::read();
2763
});
2864
return 0;
2965
}
30-
66+
// CHECK: ![[ID0]] = !{i32 1}
67+
// CHECK: ![[ID1]] = !{i32 2}
68+
// CHECK: ![[ID2]] = !{i32 42}

clang/test/SemaSYCL/fpga_pipes.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,35 @@ using type4 = __attribute__((pipe(0))) const int;
1414

1515
// expected-error@+1{{'pipe' attribute takes one argument}}
1616
using type5 = __attribute__((pipe)) const int;
17+
18+
struct pipe_storage {};
19+
20+
// no error expected
21+
const pipe_storage Storage1 __attribute__((io_pipe_id(1)));
22+
23+
// expected-error@+1{{'io_pipe_id' attribute requires a non-negative integral compile time constant expression}}
24+
const pipe_storage Storage2 __attribute__((io_pipe_id(-11)));
25+
26+
// expected-error@+1{{'io_pipe_id' attribute requires an integer constant}}
27+
const pipe_storage Storage3 __attribute__((io_pipe_id("abc")));
28+
29+
// expected-error@+1{{'io_pipe_id' attribute only applies to SYCL pipe storage declaration}}
30+
int Storage4 __attribute__((io_pipe_id(5)));
31+
32+
// expected-error@+2{{'io_pipe_id' attribute requires a non-negative integral compile time constant expression}}
33+
template <int N>
34+
pipe_storage Storage5 __attribute__((io_pipe_id(N)));
35+
36+
template <typename name, typename Func>
37+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
38+
kernelFunc();
39+
}
40+
41+
void foo(pipe_storage PS) {}
42+
43+
int main() {
44+
// no error expected
45+
foo(Storage5<2>);
46+
// expected-note@+1{{in instantiation of variable template specialization 'Storage5' requested here}}
47+
foo(Storage5<-1>);
48+
}

0 commit comments

Comments
 (0)