Skip to content

Commit

Permalink
Add support for __declspec(code_seg("segname"))
Browse files Browse the repository at this point in the history
This patch uses CodeSegAttr to represent __declspec(code_seg) rather than 
building on the existing support for #pragma code_seg.
The code_seg declspec is applied on functions and classes. This attribute 
enables the placement of code into separate named segments, including compiler-
generated codes and template instantiations.

For more information, please see the following:
https://msdn.microsoft.com/en-us/library/dn636922.aspx

This patch fixes the regression for the support for attribute ((section).
llvm-mirror/clang@746b78d

Patch by Soumi Manna (Manna)
Differential Revision: https://reviews.llvm.org/D48841

llvm-svn: 337420
  • Loading branch information
Erich Keane committed Jul 18, 2018
1 parent d4b82da commit 7963e8b
Show file tree
Hide file tree
Showing 15 changed files with 829 additions and 8 deletions.
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -1770,6 +1770,13 @@ def Section : InheritableAttr {
let Documentation = [SectionDocs];
}

def CodeSeg : InheritableAttr {
let Spellings = [Declspec<"code_seg">];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>;
let Documentation = [CodeSegDocs];
}

def PragmaClangBSSSection : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Expand Up @@ -306,6 +306,18 @@ An example of how to use ``alloc_size``
}];
}

def CodeSegDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``__declspec(code_seg)`` attribute enables the placement of code into separate
named segments that can be paged or locked in memory individually. This attribute
is used to control the placement of instantiated templates and compiler-generated
code. See the documentation for `__declspec(code_seg)`_ on MSDN.

.. _`__declspec(code_seg)`: http://msdn.microsoft.com/en-us/library/dn636922.aspx
}];
}

def AllocAlignDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
12 changes: 10 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -2668,11 +2668,19 @@ def err_only_annotate_after_access_spec : Error<
"access specifier can only have annotation attributes">;

def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
"argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">;
def warn_mismatched_section : Warning<
"section does not match previous declaration">, InGroup<Section>;
"%select{codeseg|section}0 does not match previous declaration">, InGroup<Section>;
def warn_attribute_section_on_redeclaration : Warning<
"section attribute is specified on redeclared variable">, InGroup<Section>;
def err_mismatched_code_seg_base : Error<
"derived class must specify the same code segment as its base classes">;
def err_mismatched_code_seg_override : Error<
"overriding virtual function must specify the same code segment as its overridden function">;
def err_conflicting_codeseg_attribute : Error<
"conflicting code segment specifiers">;
def warn_duplicate_codeseg_attribute : Warning<
"duplicate code segment specifiers">, InGroup<Section>;

def err_anonymous_property: Error<
"anonymous property is not supported">;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -1952,6 +1952,7 @@ class Sema {
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
Expand Down Expand Up @@ -2446,6 +2447,8 @@ class Sema {
int FirstArg, unsigned AttrSpellingListIndex);
SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
CodeSegAttr *mergeCodeSegAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
IdentifierInfo *Ident,
unsigned AttrSpellingListIndex);
Expand Down Expand Up @@ -5852,6 +5855,7 @@ class Sema {
/// ensure that referenceDLLExportedClassMethods is called some point later
/// when all outer classes of Class are complete.
void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class);

void referenceDLLExportedClassMethods();

Expand Down
12 changes: 8 additions & 4 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -1387,8 +1387,10 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
F->addAttributes(llvm::AttributeList::FunctionIndex, Attrs);
}
}

if (const SectionAttr *SA = D->getAttr<SectionAttr>())

if (const auto *CSA = D->getAttr<CodeSegAttr>())
GO->setSection(CSA->getName());
else if (const auto *SA = D->getAttr<SectionAttr>())
GO->setSection(SA->getName());
}

Expand Down Expand Up @@ -1485,8 +1487,10 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
setLinkageForGV(F, FD);
setGVProperties(F, FD);

if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
if (const auto *CSA = FD->getAttr<CodeSegAttr>())
F->setSection(CSA->getName());
else if (const auto *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());

if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by
Expand Down
79 changes: 79 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -2452,6 +2452,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
AttrSpellingListIndex);
else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr))
NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(),
AttrSpellingListIndex);
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
AttrSpellingListIndex,
Expand Down Expand Up @@ -2670,6 +2673,15 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}

// Redeclaration adds code-seg attribute.
const auto *NewCSA = New->getAttr<CodeSegAttr>();
if (NewCSA && !Old->hasAttr<CodeSegAttr>() &&
!NewCSA->isImplicit() && isa<CXXMethodDecl>(New)) {
Diag(New->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
Diag(Old->getLocation(), diag::note_previous_declaration);
}

if (!Old->hasAttrs())
return;

Expand Down Expand Up @@ -8723,6 +8735,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->dropAttr<SectionAttr>();
}

// Apply an implicit CodeSegAttr from class declspec or
// apply an implicit SectionAttr from #pragma code_seg if active.
if (!NewFD->hasAttr<CodeSegAttr>()) {
if (Attr *SAttr = getImplicitCodeSegOrSectionAttrForFunction(NewFD,
D.isFunctionDefinition())) {
NewFD->addAttr(SAttr);
}
}

// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);

Expand Down Expand Up @@ -9170,6 +9191,64 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return NewFD;
}

/// Return a CodeSegAttr from a containing class. The Microsoft docs say
/// when __declspec(code_seg) "is applied to a class, all member functions of
/// the class and nested classes -- this includes compiler-generated special
/// member functions -- are put in the specified segment."
/// The actual behavior is a little more complicated. The Microsoft compiler
/// won't check outer classes if there is an active value from #pragma code_seg.
/// The CodeSeg is always applied from the direct parent but only from outer
/// classes when the #pragma code_seg stack is empty. See:
/// https://reviews.llvm.org/D22931, the Microsoft feedback page is no longer
/// available since MS has removed the page.
static Attr *getImplicitCodeSegAttrFromClass(Sema &S, const FunctionDecl *FD) {
const auto *Method = dyn_cast<CXXMethodDecl>(FD);
if (!Method)
return nullptr;
const CXXRecordDecl *Parent = Method->getParent();
if (const auto *SAttr = Parent->getAttr<CodeSegAttr>()) {
Attr *NewAttr = SAttr->clone(S.getASTContext());
NewAttr->setImplicit(true);
return NewAttr;
}

// The Microsoft compiler won't check outer classes for the CodeSeg
// when the #pragma code_seg stack is active.
if (S.CodeSegStack.CurrentValue)
return nullptr;

while ((Parent = dyn_cast<CXXRecordDecl>(Parent->getParent()))) {
if (const auto *SAttr = Parent->getAttr<CodeSegAttr>()) {
Attr *NewAttr = SAttr->clone(S.getASTContext());
NewAttr->setImplicit(true);
return NewAttr;
}
}
return nullptr;
}

/// Returns an implicit CodeSegAttr if a __declspec(code_seg) is found on a
/// containing class. Otherwise it will return implicit SectionAttr if the
/// function is a definition and there is an active value on CodeSegStack
/// (from the current #pragma code-seg value).
///
/// \param FD Function being declared.
/// \param IsDefinition Whether it is a definition or just a declarartion.
/// \returns A CodeSegAttr or SectionAttr to apply to the function or
/// nullptr if no attribute should be added.
Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
bool IsDefinition) {
if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD))
return A;
if (!FD->hasAttr<SectionAttr>() && IsDefinition &&
CodeSegStack.CurrentValue) {
return SectionAttr::CreateImplicit(getASTContext(),
SectionAttr::Declspec_allocate,
CodeSegStack.CurrentValue->getString(),
CodeSegStack.CurrentPragmaLocation);
}
return nullptr;
}
/// Checks if the new declaration declared in dependent context must be
/// put in the same redeclaration chain as the specified declaration.
///
Expand Down
69 changes: 67 additions & 2 deletions clang/lib/Sema/SemaDeclAttr.cpp
Expand Up @@ -2825,10 +2825,18 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
StringRef Name,
unsigned AttrSpellingListIndex) {
// Explicit or partial specializations do not inherit
// the section attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (AttrSpellingListIndex == SectionAttr::Declspec_allocate &&
FD->isFunctionTemplateSpecialization())
return nullptr;
}
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
if (ExistingAttr->getName() == Name)
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section);
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 1 /*section*/;
Diag(Range.getBegin(), diag::note_previous_attribute);
return nullptr;
}
Expand All @@ -2839,7 +2847,8 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName);
if (!Error.empty()) {
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error;
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
<< 1 /*'section'*/;
return false;
}
return true;
Expand Down Expand Up @@ -2870,6 +2879,59 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}

static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) {
std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
if (!Error.empty()) {
S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
<< 0 /*'code-seg'*/;
return false;
}
return true;
}

CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range,
StringRef Name,
unsigned AttrSpellingListIndex) {
// Explicit or partial specializations do not inherit
// the code_seg attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isFunctionTemplateSpecialization())
return nullptr;
}
if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
if (ExistingAttr->getName() == Name)
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
Diag(Range.getBegin(), diag::note_previous_attribute);
return nullptr;
}
return ::new (Context) CodeSegAttr(Range, Context, Name,
AttrSpellingListIndex);
}

static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
return;
if (!checkCodeSegName(S, LiteralLoc, Str))
return;
if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
if (!ExistingAttr->isImplicit()) {
S.Diag(AL.getLoc(),
ExistingAttr->getName() == Str
? diag::warn_duplicate_codeseg_attribute
: diag::err_conflicting_codeseg_attribute);
return;
}
D->dropAttr<CodeSegAttr>();
}
if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str,
AL.getAttributeSpellingListIndex()))
D->addAttr(CSA);
}

// Check for things we'd like to warn about. Multiversioning issues are
// handled later in the process, once we know how many exist.
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
Expand Down Expand Up @@ -6120,6 +6182,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;
case ParsedAttr::AT_Target:
handleTargetAttr(S, D, AL);
break;
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Expand Up @@ -2243,6 +2243,19 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
CXXRecordDecl *CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");

// Microsoft docs say:
// "If a base-class has a code_seg attribute, derived classes must have the
// same attribute."
const auto *BaseCSA = CXXBaseDecl->getAttr<CodeSegAttr>();
const auto *DerivedCSA = Class->getAttr<CodeSegAttr>();
if ((DerivedCSA || BaseCSA) &&
(!BaseCSA || !DerivedCSA || BaseCSA->getName() != DerivedCSA->getName())) {
Diag(Class->getLocation(), diag::err_mismatched_code_seg_base);
Diag(CXXBaseDecl->getLocation(), diag::note_base_class_specified_here)
<< CXXBaseDecl;
return nullptr;
}

// A class which contains a flexible array member is not suitable for use as a
// base class:
// - If the layout determines that a base comes before another base,
Expand Down Expand Up @@ -5614,6 +5627,16 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S,
}
}

void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) {
// Mark any compiler-generated routines with the implicit code_seg attribute.
for (auto *Method : Class->methods()) {
if (Method->isUserProvided())
continue;
if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
Method->addAttr(A);
}
}

/// Check class-level dllimport/dllexport attribute.
void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
Attr *ClassAttr = getDLLAttr(Class);
Expand Down Expand Up @@ -6122,6 +6145,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}

checkClassLevelDLLAttribute(Record);
checkClassLevelCodeSegAttribute(Record);

bool ClangABICompat4 =
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
Expand Down Expand Up @@ -14589,6 +14613,16 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
}
}

// Virtual overrides must have the same code_seg.
const auto *OldCSA = Old->getAttr<CodeSegAttr>();
const auto *NewCSA = New->getAttr<CodeSegAttr>();
if ((NewCSA || OldCSA) &&
(!OldCSA || !NewCSA || NewCSA->getName() != OldCSA->getName())) {
Diag(New->getLocation(), diag::err_mismatched_code_seg_override);
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}

CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();

// If the calling conventions match, everything is fine
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaLambda.cpp
Expand Up @@ -913,6 +913,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// This represents the function body for the lambda function, check if we
// have to apply optnone due to a pragma.
AddRangeBasedOptnone(Method);

// code_seg attribute on lambda apply to the method.
if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
Method->addAttr(A);

// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);
Expand Down

0 comments on commit 7963e8b

Please sign in to comment.