Newer
Older
//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines target asm properties related what form asm statements
// should take.
//
//===----------------------------------------------------------------------===//
Anton Korobeynikov
committed
#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"
Anton Korobeynikov
committed
#include "llvm/Target/TargetOptions.h"
Anton Korobeynikov
committed
#include "llvm/Support/Dwarf.h"
using namespace llvm;
TargetAsmInfo::TargetAsmInfo() :
TextSection("\t.text"),
DataSection("\t.data"),
BSSSection("\t.bss"),
Lauro Ramos Venancio
committed
TLSDataSection("\t.section .tdata,\"awT\",@progbits"),
TLSBSSSection("\t.section .tbss,\"awT\",@nobits"),
NonexecutableStackDirective(0),
MaxInstLength(4),
SeparatorChar(';'),
CommentString("#"),
GlobalPrefix(""),
PrivateGlobalPrefix("."),
Chris Lattner
committed
JumpTableSpecialLabelPrefix(0),
GlobalVarAddrPrefix(""),
GlobalVarAddrSuffix(""),
FunctionAddrPrefix(""),
FunctionAddrSuffix(""),
PersonalityPrefix(""),
PersonalitySuffix(""),
Bill Wendling
committed
NeedsIndirectEncoding(false),
InlineAsmStart("#APP"),
InlineAsmEnd("#NO_APP"),
StringConstantPrefix(".str"),
ZeroDirective("\t.zero\t"),
ZeroDirectiveSuffix(0),
AsciiDirective("\t.ascii\t"),
AscizDirective("\t.asciz\t"),
Data8bitsDirective("\t.byte\t"),
Data16bitsDirective("\t.short\t"),
Data32bitsDirective("\t.long\t"),
Data64bitsDirective("\t.quad\t"),
AlignDirective("\t.align\t"),
AlignmentIsInBytes(true),
TextAlignFillValue(0),
SwitchToSectionDirective("\t.section\t"),
TextSectionStartSuffix(""),
DataSectionStartSuffix(""),
SectionEndDirectiveSuffix(0),
ConstantPoolSection("\t.section .rodata"),
JumpTableDataSection("\t.section .rodata"),
Andrew Lenharth
committed
JumpTableDirective(0),
StaticCtorsSection("\t.section .ctors,\"aw\",@progbits"),
StaticDtorsSection("\t.section .dtors,\"aw\",@progbits"),
FourByteConstantSection(0),
EightByteConstantSection(0),
SixteenByteConstantSection(0),
GlobalDirective("\t.globl\t"),
SetDirective(0),
LCOMMDirective(0),
COMMDirective("\t.comm\t"),
COMMDirectiveTakesAlignment(true),
HasDotTypeDotSizeDirective(true),
UsedDirective(0),
WeakDefDirective(0),
HiddenDirective("\t.hidden\t"),
ProtectedDirective("\t.protected\t"),
AbsoluteDebugSectionOffsets(false),
AbsoluteEHSectionOffsets(false),
HasDotLocAndDotFile(false),
SupportsDebugInformation(false),
DwarfRequiresFrameSection(true),
SupportsWeakOmittedEHFrame(true),
DwarfSectionOffsetDirective(0),
DwarfAbbrevSection(".debug_abbrev"),
DwarfInfoSection(".debug_info"),
DwarfLineSection(".debug_line"),
DwarfFrameSection(".debug_frame"),
DwarfPubNamesSection(".debug_pubnames"),
DwarfPubTypesSection(".debug_pubtypes"),
DwarfStrSection(".debug_str"),
DwarfLocSection(".debug_loc"),
DwarfARangesSection(".debug_aranges"),
DwarfRangesSection(".debug_ranges"),
DwarfMacInfoSection(".debug_macinfo"),
DwarfEHFrameSection(".eh_frame"),
DwarfExceptionSection(".gcc_except_table"),
AsmTransCBE(0) {
TargetAsmInfo::~TargetAsmInfo() {
}
/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorChar or newline) do not
/// count as an instruction.
/// Any other non-whitespace text is considered an instruction, with
/// multiple instructions separated by SeparatorChar or newlines.
/// Variable-length instructions are not handled here; this function
/// may be overloaded in the target code to do that.
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
// Count the number of instructions in the asm.
bool atInsnStart = true;
unsigned Length = 0;
for (; *Str; ++Str) {
if (*Str == '\n' || *Str == SeparatorChar)
atInsnStart = true;
if (atInsnStart && !isspace(*Str)) {
Length += MaxInstLength;
atInsnStart = false;
}
if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
atInsnStart = false;
unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
Anton Korobeynikov
committed
bool Global) const {
return dwarf::DW_EH_PE_absptr;
}
Anton Korobeynikov
committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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<Function>(GV))
return SectionKind::Text;
const GlobalVariable* GVar = dyn_cast<GlobalVariable>(GV);
bool isThreadLocal = GVar->isThreadLocal();
assert(GVar && "Invalid global value for section selection");
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())
Anton Korobeynikov
committed
else {
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
// Check, if initializer is a null-terminated string
if (CVA && CVA->isCString())
Anton Korobeynikov
committed
else
Anton Korobeynikov
committed
}
}
// Variable is not constant or thread-local - emit to generic data section.
return (isThreadLocal ? SectionKind::ThreadData : SectionKind::Data);
}
unsigned
TargetAsmInfo::SectionFlagsForGlobal(const GlobalValue *GV,
Anton Korobeynikov
committed
const char* Name) const {
unsigned Flags = SectionFlags::None;
// Decode flags from global itself.
if (GV) {
Anton Korobeynikov
committed
SectionKind::Kind Kind = SectionKindForGlobal(GV);
switch (Kind) {
case SectionKind::Text:
Anton Korobeynikov
committed
Flags |= SectionFlags::Code;
break;
case SectionKind::ThreadData:
Anton Korobeynikov
committed
Flags |= SectionFlags::TLS;
// FALLS THROUGH
case SectionKind::Data:
Anton Korobeynikov
committed
Flags |= SectionFlags::Writeable;
break;
case SectionKind::ThreadBSS:
Anton Korobeynikov
committed
Flags |= SectionFlags::TLS;
// FALLS THROUGH
case SectionKind::BSS:
Anton Korobeynikov
committed
Flags |= SectionFlags::BSS;
break;
case SectionKind::ROData:
// No additional flags here
break;
case SectionKind::RODataMergeStr:
Anton Korobeynikov
committed
Flags |= SectionFlags::Strings;
// FALLS THROUGH
case SectionKind::RODataMergeConst:
Anton Korobeynikov
committed
Flags |= SectionFlags::Mergeable;
break;
default:
assert(0 && "Unexpected section kind!");
}
Anton Korobeynikov
committed
Flags |= SectionFlags::Linkonce;
}
// Add flags from sections, if any.
Anton Korobeynikov
committed
Flags |= SectionFlags::Named;
// Some lame default implementation based on some magic section names.
if (strncmp(Name, ".gnu.linkonce.b.", 16) == 0 ||
strncmp(Name, ".llvm.linkonce.b.", 17) == 0)
Flags |= SectionFlags::BSS;
else if (strcmp(Name, ".tdata") == 0 ||
strncmp(Name, ".tdata.", 7) == 0 ||
strncmp(Name, ".gnu.linkonce.td.", 17) == 0 ||
strncmp(Name, ".llvm.linkonce.td.", 18) == 0)
Flags |= SectionFlags::TLS;
else if (strcmp(Name, ".tbss") == 0 ||
strncmp(Name, ".tbss.", 6) == 0 ||
strncmp(Name, ".gnu.linkonce.tb.", 17) == 0 ||
strncmp(Name, ".llvm.linkonce.tb.", 18) == 0)
Flags |= SectionFlags::BSS | SectionFlags::TLS;
Anton Korobeynikov
committed
return Flags;
Anton Korobeynikov
committed
std::string
TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
Anton Korobeynikov
committed
unsigned Flags = SectionFlagsForGlobal(GV, GV->getSection().c_str());
std::string Name;
// FIXME: Should we use some hashing based on section name and just check
// flags?
// Select section name
if (GV->hasSection()) {
// Honour section already set, if any
Name = GV->getSection();
} else {
// Use default section depending on the 'type' of global
Name = SelectSectionForGlobal(GV);
}
Anton Korobeynikov
committed
// If section is named we need to switch into it via special '.section'
// directive and also append funky flags. Otherwise - section name is just
// some magic assembler directive.
if (Flags & SectionFlags::Named)
Name = getSwitchToSectionDirective() + Name + PrintSectionFlags(Flags);
Anton Korobeynikov
committed
return Name;
}
// Lame default implementation. Calculate the section name for global.
std::string
TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV) const {
Anton Korobeynikov
committed
SectionKind::Kind Kind = SectionKindForGlobal(GV);
Anton Korobeynikov
committed
return UniqueSectionForGlobal(GV, Kind);
Anton Korobeynikov
committed
if (Kind == SectionKind::Text)
return getTextSection();
Anton Korobeynikov
committed
else if (Kind == SectionKind::BSS && getBSSSection())
return getBSSSection();
else if (getReadOnlySection() &&
Anton Korobeynikov
committed
(Kind == SectionKind::ROData ||
Kind == SectionKind::RODataMergeConst ||
Kind == SectionKind::RODataMergeStr))
return getReadOnlySection();
}
return getDataSection();
}
std::string
TargetAsmInfo::UniqueSectionForGlobal(const GlobalValue* GV,
Anton Korobeynikov
committed
SectionKind::Kind Kind) const {
switch (Kind) {
return ".gnu.linkonce.t." + GV->getName();
return ".gnu.linkonce.d." + GV->getName();
return ".gnu.linkonce.b." + GV->getName();
case SectionKind::ROData:
case SectionKind::RODataMergeConst:
case SectionKind::RODataMergeStr:
return ".gnu.linkonce.r." + GV->getName();
return ".gnu.linkonce.td." + GV->getName();
return ".gnu.linkonce.tb." + GV->getName();
default:
assert(0 && "Unknown section kind");
}
}