Move lowerGlobal() from target-specific code to emitGlobal() in generic code.
Emitting the global initializers is mostly the same across
each architecture (same filling, alignment, etc.). The only difference
is in assembler-directive quirks. E.g., on ARM for ".align N" N is
the exponent for a power of 2, while on x86 N is the actual number
of bytes. To avoid target-specific directives, use .p2align which
is always a power of 2. Similarly, use % instead of @. Either one
may be a comment character for *some* architecture, but for the
architectures we care about % is not a comment character while @
is sometimes (ARM).
Usually MIPS uses ".space N" for ".zero", but the assembler seems
to accept ".zero" so don't change that for now.
May need to adjust .long in the future too.
.word for AArch64 and .4byte for MIPS?
Potentially we can refactor the lowerGlobals() dispatcher
(ELF vs ASM vs IASM). The only thing target-specific about that
is *probably* just the relocation type.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1188603002.
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index aefad00..4bb035a 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -20,6 +20,7 @@
#include "assembler_mips32.h"
#include "IceCfg.h" // setError()
#include "IceCfgNode.h"
+#include "IceGlobalInits.h"
#include "IceOperand.h"
#include "IceRegAlloc.h"
#include "IceTargetLowering.h"
@@ -445,6 +446,89 @@
TargetDataLowering::~TargetDataLowering() {}
+void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
+ if (!ALLOW_DUMP)
+ return;
+
+ // If external and not initialized, this must be a cross test.
+ // Don't generate a declaration for such cases.
+ bool IsExternal = Var.isExternal() || Ctx->getFlags().getDisableInternal();
+ if (IsExternal && !Var.hasInitializer())
+ return;
+
+ Ostream &Str = Ctx->getStrEmit();
+ const VariableDeclaration::InitializerListType &Initializers =
+ Var.getInitializers();
+ bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
+ bool IsConstant = Var.getIsConstant();
+ uint32_t Align = Var.getAlignment();
+ SizeT Size = Var.getNumBytes();
+ IceString MangledName = Var.mangleName(Ctx);
+ IceString SectionSuffix = "";
+ if (Ctx->getFlags().getDataSections())
+ SectionSuffix = "." + MangledName;
+
+ Str << "\t.type\t" << MangledName << ",%object\n";
+
+ if (IsConstant)
+ Str << "\t.section\t.rodata" << SectionSuffix << ",\"a\",%progbits\n";
+ else if (HasNonzeroInitializer)
+ Str << "\t.section\t.data" << SectionSuffix << ",\"aw\",%progbits\n";
+ else
+ Str << "\t.section\t.bss" << SectionSuffix << ",\"aw\",%nobits\n";
+
+ if (IsExternal)
+ Str << "\t.globl\t" << MangledName << "\n";
+
+ if (Align > 1) {
+ assert(llvm::isPowerOf2_32(Align));
+ // Use the .p2align directive, since the .align N directive can either
+ // interpret N as bytes, or power of 2 bytes, depending on the target.
+ Str << "\t.p2align\t" << llvm::Log2_32(Align) << "\n";
+ }
+
+ Str << MangledName << ":\n";
+
+ if (HasNonzeroInitializer) {
+ for (VariableDeclaration::Initializer *Init : Initializers) {
+ switch (Init->getKind()) {
+ case VariableDeclaration::Initializer::DataInitializerKind: {
+ const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(Init)
+ ->getContents();
+ for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
+ Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
+ }
+ break;
+ }
+ case VariableDeclaration::Initializer::ZeroInitializerKind:
+ Str << "\t.zero\t" << Init->getNumBytes() << "\n";
+ break;
+ case VariableDeclaration::Initializer::RelocInitializerKind: {
+ const auto Reloc =
+ llvm::cast<VariableDeclaration::RelocInitializer>(Init);
+ Str << "\t" << getEmit32Directive() << "\t";
+ Str << Reloc->getDeclaration()->mangleName(Ctx);
+ if (RelocOffsetT Offset = Reloc->getOffset()) {
+ if (Offset >= 0 || (Offset == INT32_MIN))
+ Str << " + " << Offset;
+ else
+ Str << " - " << -Offset;
+ }
+ Str << "\n";
+ break;
+ }
+ }
+ }
+ } else
+ // NOTE: for non-constant zero initializers, this is BSS (no bits),
+ // so an ELF writer would not write to the file, and only track
+ // virtual offsets, but the .s writer still needs this .zero and
+ // cannot simply use the .size to advance offsets.
+ Str << "\t.zero\t" << Size << "\n";
+
+ Str << "\t.size\t" << MangledName << ", " << Size << "\n";
+}
+
std::unique_ptr<TargetHeaderLowering>
TargetHeaderLowering::createLowering(GlobalContext *Ctx) {
TargetArch Target = Ctx->getFlags().getTargetArch();