diff --git a/include/llvm/MC/MCAtom.h b/include/llvm/MC/MCAtom.h index b0c97ec41da..f91a96f7c29 100644 --- a/include/llvm/MC/MCAtom.h +++ b/include/llvm/MC/MCAtom.h @@ -17,6 +17,8 @@ namespace llvm { public: MCAtom(MCSection *_Section) : Section(_Section) {} + + MCSection *getSection() { return Section; } }; } // end namespace llvm diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index 78943fc056e..3ccc4daa767 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -113,7 +113,7 @@ namespace llvm { /// allocator supports it). /// @return The allocated memory. Could be NULL. inline void *operator new(size_t Bytes, llvm::MCContext &C, - size_t Alignment) throw () { + size_t Alignment = 16) throw () { return C.Allocate(Bytes, Alignment); } /// @brief Placement delete companion to the new above. diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index 236f0687e74..341f7f01514 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -19,6 +19,8 @@ namespace llvm { public: MCSection(const char *_Name) : Name(_Name) {} + + const std::string &getName() const { return Name; } }; } // end namespace llvm diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index f2b94b94570..9374529ff43 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -84,7 +84,7 @@ namespace llvm { // the symbol and make the printer smart enough to add the right symbols? // This should work as long as the order of attributes in the file doesn't // matter. - virtual void EmitSymbolAttribute(MCSymbol *Symbol, + virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) = 0; /// EmitBytes - Emit @param Length bytes starting at @param Data into the @@ -116,7 +116,7 @@ namespace llvm { /// createAsmStreamer - Create a machine code streamer which will print out /// assembly for the native target, suitable for compiling with a native /// assembler. - inline MCStreamer *createAsmStreamer(MCContext &Ctx, raw_ostream &OS) { return 0; } + MCStreamer *createAsmStreamer(MCContext &Ctx, raw_ostream &OS); // FIXME: These two may end up getting rolled into a single // createObjectStreamer interface, which implements the assembler backend, and diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index 66215b17b4a..085f765caf8 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -23,6 +23,10 @@ namespace llvm { public: MCSymbol(MCAtom *_Atom, const char *_Name, bool _IsTemporary) : Atom(_Atom), Name(_Name), IsTemporary(_IsTemporary) {} + + MCAtom *getAtom() { return Atom; } + + const std::string &getName() { return Name; } }; } // end namespace llvm diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp new file mode 100644 index 00000000000..1956c2e77bd --- /dev/null +++ b/lib/MC/MCAsmStreamer.cpp @@ -0,0 +1,143 @@ +//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" + +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + + class MCAsmStreamer : public MCStreamer { + raw_ostream &OS; + + MCSection *CurSection; + + public: + MCAsmStreamer(MCContext &Context, raw_ostream &_OS) + : MCStreamer(Context), OS(_OS) {} + ~MCAsmStreamer() {} + + /// @name MCStreamer Interface + /// @{ + + virtual void SwitchSection(MCSection *Section); + + virtual void EmitLabel(MCSymbol *Symbol); + + virtual void EmitAssignment(MCSymbol *Symbol, const MCValue &Value, + bool MakeAbsolute = false); + + virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); + + virtual void EmitBytes(const char *Data, unsigned Length); + + virtual void EmitValue(const MCValue &Value, unsigned Size); + + virtual void EmitInstruction(const MCInst &Inst); + + virtual void Finish(); + + /// @} + }; + +} + +/// Allow printing values directly to a raw_ostream. +inline raw_ostream &operator<<(raw_ostream &os, const MCValue &Value) { + if (Value.getSymA()) { + os << Value.getSymA()->getName(); + if (Value.getSymB()) + os << " - " << Value.getSymB()->getName(); + if (Value.getCst()) + os << " + " << Value.getCst(); + } else { + assert(!Value.getSymB() && "Invalid machine code value!"); + os << Value.getCst(); + } + + return os; +} + +void MCAsmStreamer::SwitchSection(MCSection *Section) { + if (Section != CurSection) { + CurSection = Section; + + // FIXME: Really we would like the segment, flags, etc. to be separate + // values instead of embedded in the name. Not all assemblers understand all + // this stuff though. + OS << ".section " << Section->getName() << "\n"; + } +} + +void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { + // FIXME: We need to enforce that we aren't printing atoms which are more + // complicated than the assembler understands. + assert(Symbol->getAtom()->getSection() == CurSection && + "The label for a symbol must match its section!"); + OS << Symbol->getName() << ":\n"; +} + +void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCValue &Value, + bool MakeAbsolute) { + if (MakeAbsolute) { + OS << ".set " << Symbol->getName() << ", " << Value << '\n'; + } else { + OS << Symbol->getName() << " = " << Value << '\n'; + } +} + +void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + SymbolAttr Attribute) { + switch (Attribute) { + case Global: OS << ".globl"; break; + case Weak: OS << ".weak"; break; + case PrivateExtern: OS << ".private_extern"; break; + } + + OS << ' ' << Symbol->getName() << '\n'; +} + +void MCAsmStreamer::EmitBytes(const char *Data, unsigned Length) { + for (unsigned i = 0; i != Length; ++i) { + OS << ".byte " << (unsigned) Data[i] << '\n'; + } +} + +void MCAsmStreamer::EmitValue(const MCValue &Value, unsigned Size) { + // Need target hooks to know how to print this. + switch (Size) { + default: + assert(0 && "Invalid size for machine code value!"); + case 1: OS << ".byte"; break; + case 2: OS << ".hword"; break; + case 4: OS << ".long"; break; + case 8: OS << ".quad"; break; + } + + OS << ' ' << Value << '\n'; +} + +void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { + // FIXME: Implement. + OS << "# FIXME: Implement instruction printing!\n"; +} + +void MCAsmStreamer::Finish() { + OS.flush(); +} + +MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS) { + return new MCAsmStreamer(Context, OS); +} diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index be805232e4d..cad0d569902 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -26,13 +26,13 @@ MCSection *MCContext::GetSection(const char *Name) { MCSection *&Entry = Sections[Name]; if (!Entry) - Entry = new (this) MCSection(Name); + Entry = new (*this) MCSection(Name); return Entry; } MCAtom *MCContext::CreateAtom(MCSection *Section) { - return new (this) MCAtom(Section); + return new (*this) MCAtom(Section); } MCSymbol *MCContext::CreateSymbol(MCAtom *Atom, const char *Name) { @@ -41,18 +41,18 @@ MCSymbol *MCContext::CreateSymbol(MCAtom *Atom, const char *Name) { // Create and bind the symbol, and ensure that names are unique. MCSymbol *&Entry = Symbols[Name]; assert(!Entry && "Duplicate symbol definition!"); - return Entry = new (this) MCSymbol(Atom, Name, false); + return Entry = new (*this) MCSymbol(Atom, Name, false); } MCSymbol *MCContext::CreateTemporarySymbol(MCAtom *Atom, const char *Name) { // If unnamed, just create a symbol. if (Name[0] == '\0') - new (this) MCSymbol(Atom, "", true); + new (*this) MCSymbol(Atom, "", true); // Otherwise create as usual. MCSymbol *&Entry = Symbols[Name]; assert(!Entry && "Duplicate symbol definition!"); - return Entry = new (this) MCSymbol(Atom, Name, true); + return Entry = new (*this) MCSymbol(Atom, Name, true); } MCSymbol *MCContext::LookupSymbol(const char *Name) const { diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp new file mode 100644 index 00000000000..a634f33ad34 --- /dev/null +++ b/lib/MC/MCStreamer.cpp @@ -0,0 +1,18 @@ +//===- lib/MC/MCStreamer.cpp - Streaming Machine Code Output --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context) { +} + +MCStreamer::~MCStreamer() { +} diff --git a/unittests/MC/AsmStreamerTest.cpp b/unittests/MC/AsmStreamerTest.cpp new file mode 100644 index 00000000000..80cd4560859 --- /dev/null +++ b/unittests/MC/AsmStreamerTest.cpp @@ -0,0 +1,52 @@ +//===- AsmStreamerTest.cpp - Triple unit tests ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + +// Helper class. +class StringAsmStreamer { + std::string Str; + raw_string_ostream OS; + MCContext Context; + MCStreamer *Streamer; + +public: + StringAsmStreamer() : OS(Str), Streamer(createAsmStreamer(Context, OS)) {} + ~StringAsmStreamer() { + delete Streamer; + } + + MCContext &getContext() { return Context; } + MCStreamer &getStreamer() { return *Streamer; } + + const std::string &getString() { + Streamer->Finish(); + return Str; + } +}; + +TEST(AsmStreamer, EmptyOutput) { + StringAsmStreamer S; + EXPECT_EQ(S.getString(), ""); +} + +TEST(AsmStreamer, Sections) { + StringAsmStreamer S; + MCSection *Sec0 = S.getContext().GetSection("foo"); + S.getStreamer().SwitchSection(Sec0); + EXPECT_EQ(S.getString(), ".section foo\n"); +} + +} diff --git a/unittests/MC/Makefile b/unittests/MC/Makefile new file mode 100644 index 00000000000..410d3869cd5 --- /dev/null +++ b/unittests/MC/Makefile @@ -0,0 +1,15 @@ +##===- unittests/MC/Makefile -------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = MC +LINK_COMPONENTS := core support mc + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Makefile b/unittests/Makefile index 1ff54111026..04d12e01ad7 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -16,7 +16,7 @@ BUILD_ARCHIVE = 1 CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include/ CPP.Flags += -Wno-variadic-macros -PARALLEL_DIRS = ADT Support VMCore +PARALLEL_DIRS = ADT Support VMCore MC include $(LEVEL)/Makefile.common