From 1bd711969ce910a6e63f24f617ce87b02afd448a Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 16 Oct 2014 20:52:46 +0000 Subject: [PATCH] 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219960 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 25 +++++++++++++++++++++++++ include/clang/Sema/Sema.h | 23 ----------------------- lib/CodeGen/CodeGenModule.cpp | 7 +++++++ lib/Parse/ParsePragma.cpp | 27 ++++++++++++++------------- lib/Sema/SemaAttr.cpp | 20 ++++++++++---------- lib/Sema/SemaDecl.cpp | 10 ++++++---- test/CodeGen/sections.c | 10 ++++++++++ 7 files changed, 72 insertions(+), 50 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 78155443d3..d2157d34a5 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -2328,6 +2328,31 @@ private: std::unique_ptr AllParents; std::unique_ptr 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 SectionInfos; }; /// \brief Utility function for constructing a nullary selector. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4cd4c57c33..f4579c2c3f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 SectionInfos; bool UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *TheDecl); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 7d8c34d199..78a2631a36 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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()) { + 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. diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 7f19abf89e..8c3fb7a569 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -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( + ASTContext::PragmaSectionFlag Flag = + llvm::StringSwitch( 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(); diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index f92bb68d20..76297977ea 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -363,15 +363,15 @@ void Sema::PragmaStack::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; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 65eafd5a3c..6f20c6a9f7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(); } @@ -9403,15 +9405,15 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isThisDeclarationADefinition() && ActiveTemplateInstantiations.empty()) { PragmaStack *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() && Stack->CurrentValue) var->addAttr( diff --git a/test/CodeGen/sections.c b/test/CodeGen/sections.c index 8d93fed480..4c59881b73 100644 --- a/test/CodeGen/sections.c +++ b/test/CodeGen/sections.c @@ -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" -- 2.40.0