Skip to content

Commit

Permalink
[SYCL] Enable FPGA memory attributes
Browse files Browse the repository at this point in the history
This patch introduces the following FPGA memory attributes:
* register
* memory
* numbanks
* bankwidth

Signed-off-by: Vladimir Lazarev <vladimir.lazarev@intel.com>
Signed-off-by: Viktoria Maksimova <viktoria.maksimova@intel.com>
  • Loading branch information
vmaksimo authored and vladimirlaz committed Mar 22, 2019
1 parent 0738099 commit fbffaab
Show file tree
Hide file tree
Showing 13 changed files with 733 additions and 0 deletions.
87 changes: 87 additions & 0 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -1387,6 +1387,93 @@ def Mode : Attr {
let PragmaAttributeSupport = 0;
}

def IntelFPGAConstVar : SubsetSubject<Var,
[{S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::ParmVar &&
S->getKind() != Decl::NonTypeTemplateParm &&
(S->getType().isConstQualified() ||
S->getType().getAddressSpace() ==
LangAS::opencl_constant)}],
"constant variables">;

def IntelFPGALocalStaticSlaveMemVar : SubsetSubject<Var,
[{S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::NonTypeTemplateParm &&
(S->getStorageClass() == SC_Static ||
S->hasLocalStorage())}],
"local variables, static variables, slave memory arguments">;

def IntelFPGALocalOrStaticVar : SubsetSubject<Var,
[{S->getKind() != Decl::ImplicitParam &&
S->getKind() != Decl::ParmVar &&
S->getKind() != Decl::NonTypeTemplateParm &&
(S->getStorageClass() == SC_Static ||
S->hasLocalStorage())}],
"local variables, static variables">;

def IntelFPGAMemory : Attr {
let Spellings = [GNU<"memory">, CXX11<"intelfpga", "memory">];
let Args = [EnumArgument<"Kind", "MemoryKind",
["MLAB", "BLOCK_RAM", ""],
["MLAB", "BlockRAM", "Default"], 1>];
let AdditionalMembers = [{
static void generateValidStrings(SmallString<256> &Str) {
auto Last = BlockRAM;
for (int I = 0; I <= Last; ++I) {
Str += ConvertMemoryKindToStr(static_cast<MemoryKind>(I));
if (I != Last) Str += " ";
}
}
}];
let Subjects = SubjectList<[IntelFPGAConstVar, IntelFPGALocalStaticSlaveMemVar,
Field], ErrorDiag>;
let LangOpts = [SYCL];
let Documentation = [IntelFPGAMemoryAttrDocs];
}

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

// One integral argument.
def IntelFPGABankWidth : Attr {
let Spellings = [GNU<"bankwidth">, CXX11<"intelfpga","bankwidth">];
let Args = [ExprArgument<"Value">];
let Subjects = SubjectList<[IntelFPGAConstVar, IntelFPGALocalStaticSlaveMemVar,
Field], ErrorDiag>;
let LangOpts = [SYCL];
let Documentation = [IntelFPGABankWidthAttrDocs];
let AdditionalMembers = [{
static unsigned getMinValue() {
return 1;
}
static unsigned getMaxValue() {
return 1024*1024;
}
}];
}

def IntelFPGANumBanks : Attr {
let Spellings = [GNU<"numbanks">, CXX11<"intelfpga","numbanks">];
let Args = [ExprArgument<"Value">];
let Subjects = SubjectList<[IntelFPGAConstVar, IntelFPGALocalStaticSlaveMemVar,
Field], ErrorDiag>;
let LangOpts = [SYCL];
let Documentation = [IntelFPGANumBanksAttrDocs];
let AdditionalMembers = [{
static unsigned getMinValue() {
return 1;
}
static unsigned getMaxValue() {
return 1024*1024;
}
}];
}

def Naked : InheritableAttr {
let Spellings = [GCC<"naked">, Declspec<"naked">];
let Subjects = SubjectList<[Function]>;
Expand Down
41 changes: 41 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Expand Up @@ -1668,6 +1668,47 @@ as ``-mlong-calls`` and ``-mno-long-calls``.
}];
}

def IntelFPGAMemoryAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "memory (IntelFGPA)";
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
rather than promoting to register(s). If the optional parameter is specified
it indicates what type of memory to use.
}];
}

def IntelFPGARegisterAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "register (IntelFGPA)";
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)
if possible.
}];
}

def IntelFPGABankWidthAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "bankwidth (IntelFGPA)";
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 banks that are N bytes wide.
}];
}

def IntelFPGANumBanksAttrDocs : Documentation {
let Category = DocCatVariable;
let Heading = "numbanks (IntelFGPA)";
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 RISCVInterruptDocs : Documentation {
let Category = DocCatFunction;
let Heading = "interrupt (RISCV)";
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -123,6 +123,12 @@ def warn_double_const_requires_fp64 : Warning<
def err_half_const_requires_fp16 : Error<
"half precision constant requires cl_khr_fp16">;

// Intel FPGA extensions
def err_attribute_argument_not_power_of_two : Error<
"%0 attribute argument must be a constant power of two greater than zero">;
def err_intel_fpga_memory_arg_invalid : Error<
"%0 attribute requires either no argument or one of: %1">;

// C99 variable-length arrays
def ext_vla : Extension<"variable length arrays are a C99 feature">,
InGroup<VLAExtension>;
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -8751,6 +8751,13 @@ class Sema {
/// attribute to be added (usually because of a pragma).
void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc);

template <typename AttrType>
bool checkRangedIntegralArgument(Expr *E, const AttrType *TmpAttr,
ExprResult &Result);
template <typename AttrType>
void AddOneConstantPowerTwoValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex);

/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
unsigned SpellingListIndex, bool IsPackExpansion);
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Expand Up @@ -1607,6 +1607,18 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
(void)DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder);
}

// Emit Intel FPGA attribute annotation for a local variable.
if (getLangOpts().SYCLIsDevice) {
SmallString<256> AnnotStr;
CGM.generateIntelFPGAAnnotation(&D, AnnotStr);
if (!AnnotStr.empty()) {
llvm::Value *V = address.getPointer();
EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation),
Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()),
AnnotStr, D.getLocation());
}
}

if (D.hasAttr<AnnotateAttr>() && HaveInsertPoint())
EmitVarAnnotations(&D, address.getPointer());

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Expand Up @@ -3958,6 +3958,14 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
if (field->hasAttr<AnnotateAttr>())
addr = EmitFieldAnnotations(field, addr);

// Emit attribute annotation for a field.
if (getLangOpts().SYCLIsDevice) {
SmallString<256> AnnotStr;
CGM.generateIntelFPGAAnnotation(field, AnnotStr);
if (!AnnotStr.empty())
addr = EmitIntelFPGAFieldAnnotations(field, addr, AnnotStr);
}

LValue LV = MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
LV.getQuals().addCVRQualifiers(RecordCVR);

Expand Down
17 changes: 17 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Expand Up @@ -2293,6 +2293,23 @@ Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
return Address(V, Addr.getAlignment());
}

Address CodeGenFunction::EmitIntelFPGAFieldAnnotations(const FieldDecl *D,
Address Addr,
StringRef AnnotStr) {
llvm::Value *V = Addr.getPointer();
llvm::Type *VTy = V->getType();
llvm::Function *F =
CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, CGM.Int8PtrTy);
// FIXME Always emit the cast inst so we can differentiate between
// annotation on the first field of a struct and annotation on the struct
// itself.
if (VTy != CGM.Int8PtrTy)
V = Builder.CreateBitCast(V, CGM.Int8PtrTy);
V = EmitAnnotationCall(F, V, AnnotStr, D->getLocation());
V = Builder.CreateBitCast(V, VTy);
return Address(V, Addr.getAlignment());
}

CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { }

CodeGenFunction::SanitizerScope::SanitizerScope(CodeGenFunction *CGF)
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Expand Up @@ -4009,6 +4009,10 @@ class CodeGenFunction : public CodeGenTypeCache {
/// annotation result.
Address EmitFieldAnnotations(const FieldDecl *D, Address V);

/// Emit Intel FPGA field annotations for the given field and value. Returns
/// the annotation result.
Address EmitIntelFPGAFieldAnnotations(const FieldDecl *D, Address V,
StringRef AnnotStr);
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
Expand Down
64 changes: 64 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -3512,6 +3512,55 @@ void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
}

void CodeGenModule::generateIntelFPGAAnnotation(
const Decl *D, llvm::SmallString<256> &AnnotStr) {
llvm::raw_svector_ostream Out(AnnotStr);
if (D->hasAttr<IntelFPGARegisterAttr>())
Out << "{register:1}";
if (auto const *MA = D->getAttr<IntelFPGAMemoryAttr>()) {
IntelFPGAMemoryAttr::MemoryKind Kind = MA->getKind();
Out << "{memory:";
switch (Kind) {
case IntelFPGAMemoryAttr::MLAB:
case IntelFPGAMemoryAttr::BlockRAM:
Out << IntelFPGAMemoryAttr::ConvertMemoryKindToStr(Kind);
break;
case IntelFPGAMemoryAttr::Default:
Out << "DEFAULT";
break;
}
Out << '}';
}
if (const auto *BWA = D->getAttr<IntelFPGABankWidthAttr>()) {
llvm::APSInt BWAInt = BWA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << BWA->getSpelling() << ':' << BWAInt << '}';
}
if (const auto *NBA = D->getAttr<IntelFPGANumBanksAttr>()) {
llvm::APSInt BWAInt = NBA->getValue()->EvaluateKnownConstInt(getContext());
Out << '{' << NBA->getSpelling() << ':' << BWAInt << '}';
}
}

void CodeGenModule::addGlobalIntelFPGAAnnotation(const VarDecl *VD,
llvm::GlobalValue *GV) {
SmallString<256> AnnotStr;
generateIntelFPGAAnnotation(VD, AnnotStr);
if (!AnnotStr.empty()) {
// Get the globals for file name, annotation, and the line number.
llvm::Constant *AnnoGV = EmitAnnotationString(AnnotStr),
*UnitGV = EmitAnnotationUnit(VD->getLocation()),
*LineNoCst = EmitAnnotationLineNo(VD->getLocation());

llvm::Constant *C =
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, Int8PtrTy);
// Create the ConstantStruct for the global annotation.
llvm::Constant *Fields[4] = {
C, llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy),
llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), LineNoCst};
Annotations.push_back(llvm::ConstantStruct::getAnon(Fields));
}
}

/// Pass IsTentative as true if you want to create a tentative definition.
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
bool IsTentative) {
Expand Down Expand Up @@ -3638,6 +3687,21 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (D->hasAttr<AnnotateAttr>())
AddGlobalAnnotations(D, GV);

// Emit Intel FPGA attribute annotation for a file-scope static variable.
if (getLangOpts().SYCLIsDevice)
addGlobalIntelFPGAAnnotation(D, GV);

if (D->getType().isRestrictQualified()) {
llvm::LLVMContext &Context = getLLVMContext();

// Common metadata nodes.
llvm::NamedMDNode *GlobalsRestrict =
getModule().getOrInsertNamedMetadata("globals.restrict");
llvm::Metadata *Args[] = {llvm::ValueAsMetadata::get(GV)};
llvm::MDNode *Node = llvm::MDNode::get(Context, Args);
GlobalsRestrict->addOperand(Node);
}

// Set the llvm linkage type as appropriate.
llvm::GlobalValue::LinkageTypes Linkage =
getLLVMLinkageVarDefinition(D, GV->isConstant());
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Expand Up @@ -976,6 +976,10 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::FunctionType *FnType = nullptr, bool DontDefer = false,
ForDefinition_t IsForDefinition = NotForDefinition);

void generateIntelFPGAAnnotation(const Decl *D,
llvm::SmallString<256> &AnnotStr);
void addGlobalIntelFPGAAnnotation(const VarDecl *VD, llvm::GlobalValue *GV);

/// Given a builtin id for a function like "__builtin_fabsf", return a
/// Function* for "fabsf".
llvm::Constant *getBuiltinLibFunction(const FunctionDecl *FD,
Expand Down

0 comments on commit fbffaab

Please sign in to comment.