MS Compat: mark globals emitted in read-only sections const

They cannot be written to, so marking them const makes sense and may improve
optimisation.

As a side-effect, SectionInfos has to be moved from Sema to ASTContext.

It also fixes this problem, that occurs when compiling ATL:

  warning LNK4254: section 'ATL' (C0000040) merged into '.rdata' (40000040) with different attributes

The ATL headers are putting variables in a special section that's marked
read-only. However, Clang currently can't model that read-onlyness in the IR.
But, by making the variables const, the section does become read-only, and
the linker warning is avoided.

Differential Revision: http://reviews.llvm.org/D5812

llvm-svn: 219960
This commit is contained in:
Hans Wennborg
2014-10-16 20:52:46 +00:00
parent 933bead97d
commit 899ded9cdf
7 changed files with 72 additions and 50 deletions

View File

@@ -2328,6 +2328,31 @@ private:
std::unique_ptr<ParentMap> AllParents;
std::unique_ptr<VTableContextBase> VTContext;
public:
enum PragmaSectionFlag : unsigned {
PSF_None = 0,
PSF_Read = 0x1,
PSF_Write = 0x2,
PSF_Execute = 0x4,
PSF_Implicit = 0x8,
PSF_Invalid = 0x80000000U,
};
struct SectionInfo {
DeclaratorDecl *Decl;
SourceLocation PragmaSectionLocation;
int SectionFlags;
SectionInfo() {}
SectionInfo(DeclaratorDecl *Decl,
SourceLocation PragmaSectionLocation,
int SectionFlags)
: Decl(Decl),
PragmaSectionLocation(PragmaSectionLocation),
SectionFlags(SectionFlags) {}
};
llvm::StringMap<SectionInfo> SectionInfos;
};
/// \brief Utility function for constructing a nullary selector.

View File

@@ -7218,29 +7218,6 @@ public:
PSK_CodeSeg,
};
enum PragmaSectionFlag : unsigned {
PSF_None = 0,
PSF_Read = 0x1,
PSF_Write = 0x2,
PSF_Execute = 0x4,
PSF_Implicit = 0x8,
PSF_Invalid = 0x80000000U,
};
struct SectionInfo {
DeclaratorDecl *Decl;
SourceLocation PragmaSectionLocation;
int SectionFlags;
SectionInfo() {}
SectionInfo(DeclaratorDecl *Decl,
SourceLocation PragmaSectionLocation,
int SectionFlags)
: Decl(Decl),
PragmaSectionLocation(PragmaSectionLocation),
SectionFlags(SectionFlags) {}
};
llvm::StringMap<SectionInfo> SectionInfos;
bool UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *TheDecl);

View File

@@ -1931,6 +1931,13 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
isTypeConstant(D->getType(), true));
// If it is in a read-only section, mark it 'constant'.
if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
const ASTContext::SectionInfo &SI = Context.SectionInfos[SA->getName()];
if ((SI.SectionFlags & ASTContext::PSF_Write) == 0)
GV->setConstant(true);
}
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
// Set the llvm linkage type as appropriate.

View File

@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -539,20 +540,20 @@ bool Parser::HandlePragmaMSSection(StringRef PragmaName,
<< PragmaName;
return false;
}
Sema::PragmaSectionFlag Flag =
llvm::StringSwitch<Sema::PragmaSectionFlag>(
ASTContext::PragmaSectionFlag Flag =
llvm::StringSwitch<ASTContext::PragmaSectionFlag>(
Tok.getIdentifierInfo()->getName())
.Case("read", Sema::PSF_Read)
.Case("write", Sema::PSF_Write)
.Case("execute", Sema::PSF_Execute)
.Case("shared", Sema::PSF_Invalid)
.Case("nopage", Sema::PSF_Invalid)
.Case("nocache", Sema::PSF_Invalid)
.Case("discard", Sema::PSF_Invalid)
.Case("remove", Sema::PSF_Invalid)
.Default(Sema::PSF_None);
if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
PP.Diag(PragmaLocation, Flag == Sema::PSF_None
.Case("read", ASTContext::PSF_Read)
.Case("write", ASTContext::PSF_Write)
.Case("execute", ASTContext::PSF_Execute)
.Case("shared", ASTContext::PSF_Invalid)
.Case("nopage", ASTContext::PSF_Invalid)
.Case("nocache", ASTContext::PSF_Invalid)
.Case("discard", ASTContext::PSF_Invalid)
.Case("remove", ASTContext::PSF_Invalid)
.Default(ASTContext::PSF_None);
if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) {
PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None
? diag::warn_pragma_invalid_specific_action
: diag::warn_pragma_unsupported_action)
<< PragmaName << Tok.getIdentifierInfo()->getName();

View File

@@ -363,15 +363,15 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *Decl) {
auto Section = SectionInfos.find(SectionName);
if (Section == SectionInfos.end()) {
SectionInfos[SectionName] =
SectionInfo(Decl, SourceLocation(), SectionFlags);
auto Section = Context.SectionInfos.find(SectionName);
if (Section == Context.SectionInfos.end()) {
Context.SectionInfos[SectionName] =
ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags);
return false;
}
// A pre-declared section takes precedence w/o diagnostic.
if (Section->second.SectionFlags == SectionFlags ||
!(Section->second.SectionFlags & PSF_Implicit))
!(Section->second.SectionFlags & ASTContext::PSF_Implicit))
return false;
auto OtherDecl = Section->second.Decl;
Diag(Decl->getLocation(), diag::err_section_conflict)
@@ -390,11 +390,11 @@ bool Sema::UnifySection(StringRef SectionName,
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
SourceLocation PragmaSectionLocation) {
auto Section = SectionInfos.find(SectionName);
if (Section != SectionInfos.end()) {
auto Section = Context.SectionInfos.find(SectionName);
if (Section != Context.SectionInfos.end()) {
if (Section->second.SectionFlags == SectionFlags)
return false;
if (!(Section->second.SectionFlags & PSF_Implicit)) {
if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) {
Diag(PragmaSectionLocation, diag::err_section_conflict)
<< "this" << "a prior #pragma section";
Diag(Section->second.PragmaSectionLocation,
@@ -402,8 +402,8 @@ bool Sema::UnifySection(StringRef SectionName,
return true;
}
}
SectionInfos[SectionName] =
SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
Context.SectionInfos[SectionName] =
ASTContext::SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
return false;
}

View File

@@ -7334,7 +7334,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
CodeSegStack.CurrentValue->getString(),
CodeSegStack.CurrentPragmaLocation));
if (UnifySection(CodeSegStack.CurrentValue->getString(),
PSF_Implicit | PSF_Execute | PSF_Read, NewFD))
ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
ASTContext::PSF_Read,
NewFD))
NewFD->dropAttr<SectionAttr>();
}
@@ -9403,15 +9405,15 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isThisDeclarationADefinition() &&
ActiveTemplateInstantiations.empty()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
int SectionFlags = PSF_Implicit | PSF_Read;
int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
if (var->getType().isConstQualified())
Stack = &ConstSegStack;
else if (!var->getInit()) {
Stack = &BSSSegStack;
SectionFlags |= PSF_Write;
SectionFlags |= ASTContext::PSF_Write;
} else {
Stack = &DataSegStack;
SectionFlags |= PSF_Write;
SectionFlags |= ASTContext::PSF_Write;
}
if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
var->addAttr(

View File

@@ -31,6 +31,14 @@ int i;
int TEST1;
#pragma bss_seg(pop)
int TEST2;
#pragma section("read_flag_section", read)
// Even though they are not declared const, these become constant since they are
// in a read-only section.
__declspec(allocate("read_flag_section")) int unreferenced = 0;
extern __declspec(allocate("read_flag_section")) int referenced = 42;
int *user() { return &referenced; }
#ifdef __cplusplus
}
#endif
@@ -47,5 +55,7 @@ int TEST2;
//CHECK: @i = global i32 0
//CHECK: @TEST1 = global i32 0
//CHECK: @TEST2 = global i32 0, section ".bss1"
//CHECK: @unreferenced = constant i32 0, section "read_flag_section"
//CHECK: @referenced = constant i32 42, section "read_flag_section"
//CHECK: define void @g()
//CHECK: define void @h() {{.*}} section ".my_code"