diff --git a/include/llvm/Target/TargetAsmInfo.h b/include/llvm/Target/TargetAsmInfo.h index 9b5ba4819cb..3b16ef1645f 100644 --- a/include/llvm/Target/TargetAsmInfo.h +++ b/include/llvm/Target/TargetAsmInfo.h @@ -29,8 +29,22 @@ namespace llvm { }; } + namespace SectionKind { + enum Kind { + Text, ///< Text section + Data, ///< Data section + BSS, ///< BSS section + ROData, ///< Readonly data section + RODataMergeStr, ///< Readonly data section (mergeable strings) + RODataMergeConst, ///< Readonly data section (mergeable constants) + ThreadData, ///< Initialized TLS data objects + ThreadBSS ///< Uninitialized TLS data objects + }; + } + class TargetMachine; class CallInst; + class GlobalValue; /// TargetAsmInfo - This class is intended to be used as a base class for asm /// properties and features specific to the target. @@ -427,7 +441,11 @@ namespace llvm { /// if the symbol can be relocated. virtual unsigned PreferredEHDataFormat(DwarfEncoding::Target Reason, bool Global) const; - + + /// SectionKindForGlobal - This hook allows the target to select proper + /// section kind used for global emission. + SectionKind::Kind SectionKindForGlobal(const GlobalValue *GV) const; + // Accessors. // const char *getTextSection() const { @@ -642,7 +660,7 @@ namespace llvm { } const char *getDwarfSectionOffsetDirective() const { return DwarfSectionOffsetDirective; - } + } const char *getDwarfAbbrevSection() const { return DwarfAbbrevSection; } diff --git a/lib/Target/TargetAsmInfo.cpp b/lib/Target/TargetAsmInfo.cpp index 67f0cfa5be8..2adad3d7baa 100644 --- a/lib/Target/TargetAsmInfo.cpp +++ b/lib/Target/TargetAsmInfo.cpp @@ -12,7 +12,13 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Constants.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Type.h" #include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Support/Dwarf.h" #include #include @@ -142,3 +148,46 @@ unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason, return dwarf::DW_EH_PE_absptr; } +static bool isSuitableForBSS(const GlobalVariable *GV) { + if (!GV->hasInitializer()) + return true; + + // Leave constant zeros in readonly constant sections, so they can be shared + Constant *C = GV->getInitializer(); + return (C->isNullValue() && !GV->isConstant() && !NoZerosInBSS); +} + +SectionKind::Kind +TargetAsmInfo::SectionKindForGlobal(const GlobalValue *GV) const { + // Early exit - functions should be always in text sections. + if (isa(GV)) + return SectionKind::Text; + + const GlobalVariable* GVar = dyn_cast(GV); + bool isThreadLocal = GVar->isThreadLocal(); + assert(GVar && "Invalid global value for section selection"); + + SectionKind::Kind kind; + if (isSuitableForBSS(GVar)) { + // Variable can be easily put to BSS section. + return (isThreadLocal ? SectionKind::ThreadBSS : SectionKind::BSS); + } else if (GVar->isConstant() && !isThreadLocal) { + // Now we know, that varible has initializer and it is constant. We need to + // check its initializer to decide, which section to output it into. Also + // note, there is no thread-local r/o section. + Constant *C = GVar->getInitializer(); + if (C->ContainsRelocations()) + kind = SectionKind::ROData; + else { + const ConstantArray *CVA = dyn_cast(C); + // Check, if initializer is a null-terminated string + if (CVA && CVA->isCString()) + kind = SectionKind::RODataMergeStr; + else + kind = SectionKind::RODataMergeConst; + } + } + + // Variable is not constant or thread-local - emit to generic data section. + return (isThreadLocal ? SectionKind::ThreadData : SectionKind::Data); +}