diff options
Diffstat (limited to 'lib/MC')
-rw-r--r-- | lib/MC/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/MC/MCAsmInfo.cpp | 17 | ||||
-rw-r--r-- | lib/MC/MCAsmInfoCOFF.cpp | 7 | ||||
-rw-r--r-- | lib/MC/MCAsmInfoDarwin.cpp | 17 | ||||
-rw-r--r-- | lib/MC/MCAsmParser.cpp | 18 | ||||
-rw-r--r-- | lib/MC/MCAsmStreamer.cpp | 352 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 2 | ||||
-rw-r--r-- | lib/MC/MCExpr.cpp | 29 | ||||
-rw-r--r-- | lib/MC/MCInst.cpp | 4 | ||||
-rw-r--r-- | lib/MC/MCMachOStreamer.cpp | 71 | ||||
-rw-r--r-- | lib/MC/MCNullStreamer.cpp | 12 | ||||
-rw-r--r-- | lib/MC/MCParser/AsmLexer.cpp | 320 | ||||
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 1781 | ||||
-rw-r--r-- | lib/MC/MCParser/CMakeLists.txt | 7 | ||||
-rw-r--r-- | lib/MC/MCParser/MCAsmLexer.cpp (renamed from lib/MC/MCAsmLexer.cpp) | 2 | ||||
-rw-r--r-- | lib/MC/MCParser/MCAsmParser.cpp | 35 | ||||
-rw-r--r-- | lib/MC/MCParser/Makefile | 16 | ||||
-rw-r--r-- | lib/MC/MCParser/TargetAsmParser.cpp (renamed from lib/MC/TargetAsmParser.cpp) | 0 | ||||
-rw-r--r-- | lib/MC/MCSectionELF.cpp | 12 | ||||
-rw-r--r-- | lib/MC/MCStreamer.cpp | 25 | ||||
-rw-r--r-- | lib/MC/MCSymbol.cpp | 77 | ||||
-rw-r--r-- | lib/MC/MCValue.cpp | 8 | ||||
-rw-r--r-- | lib/MC/Makefile | 2 |
23 files changed, 2557 insertions, 260 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 8a1a058..9ead33b 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -2,8 +2,6 @@ add_llvm_library(LLVMMC MCAsmInfo.cpp MCAsmInfoCOFF.cpp MCAsmInfoDarwin.cpp - MCAsmLexer.cpp - MCAsmParser.cpp MCAsmStreamer.cpp MCAssembler.cpp MCCodeEmitter.cpp @@ -20,5 +18,4 @@ add_llvm_library(LLVMMC MCStreamer.cpp MCSymbol.cpp MCValue.cpp - TargetAsmParser.cpp ) diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index 3e5c97d..547f904 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -19,8 +19,9 @@ using namespace llvm; MCAsmInfo::MCAsmInfo() { - ZeroFillDirective = 0; - NonexecutableStackDirective = 0; + HasSubsectionsViaSymbols = false; + HasMachoZeroFillDirective = false; + HasStaticCtorDtorReferenceInStaticMode = false; NeedsSet = false; MaxInstLength = 4; PCSymbol = "$"; @@ -36,7 +37,6 @@ MCAsmInfo::MCAsmInfo() { AllowQuotesInName = false; AllowNameToStartWithDigit = false; ZeroDirective = "\t.zero\t"; - ZeroDirectiveSuffix = 0; AsciiDirective = "\t.ascii\t"; AscizDirective = "\t.asciz\t"; Data8bitsDirective = "\t.byte\t"; @@ -52,17 +52,16 @@ MCAsmInfo::MCAsmInfo() { PICJumpTableDirective = 0; GlobalDirective = "\t.globl\t"; SetDirective = 0; - LCOMMDirective = 0; - COMMDirective = "\t.comm\t"; + HasLCOMMDirective = false; COMMDirectiveTakesAlignment = true; HasDotTypeDotSizeDirective = true; HasSingleParameterDotFile = true; - UsedDirective = 0; + HasNoDeadStrip = false; WeakRefDirective = 0; WeakDefDirective = 0; - // FIXME: These are ELFish - move to ELFMAI. - HiddenDirective = "\t.hidden\t"; - ProtectedDirective = "\t.protected\t"; + LinkOnceDirective = 0; + HiddenVisibilityAttr = MCSA_Hidden; + ProtectedVisibilityAttr = MCSA_Protected; AbsoluteDebugSectionOffsets = false; AbsoluteEHSectionOffsets = false; HasLEB128 = false; diff --git a/lib/MC/MCAsmInfoCOFF.cpp b/lib/MC/MCAsmInfoCOFF.cpp index 23b0dd7..e395acd 100644 --- a/lib/MC/MCAsmInfoCOFF.cpp +++ b/lib/MC/MCAsmInfoCOFF.cpp @@ -18,14 +18,17 @@ using namespace llvm; MCAsmInfoCOFF::MCAsmInfoCOFF() { GlobalPrefix = "_"; - LCOMMDirective = "\t.lcomm\t"; + HasLCOMMDirective = true; COMMDirectiveTakesAlignment = false; HasDotTypeDotSizeDirective = false; HasSingleParameterDotFile = false; - HiddenDirective = NULL; PrivateGlobalPrefix = "L"; // Prefix for private global symbols WeakRefDirective = "\t.weak\t"; + LinkOnceDirective = "\t.linkonce same_size\n"; SetDirective = "\t.set\t"; + + // Doesn't support visibility: + HiddenVisibilityAttr = ProtectedVisibilityAttr = MCSA_Invalid; // Set up DWARF directives HasLEB128 = true; // Target asm supports leb128 directives (little-endian) diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index d99120d..9902f50 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -24,6 +24,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { NeedsSet = true; AllowQuotesInName = true; HasSingleParameterDotFile = false; + HasSubsectionsViaSymbols = true; AlignmentIsInBytes = false; InlineAsmStart = " InlineAsm Start"; @@ -32,14 +33,20 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { // Directives: WeakDefDirective = "\t.weak_definition "; WeakRefDirective = "\t.weak_reference "; - HiddenDirective = "\t.private_extern "; - LCOMMDirective = "\t.lcomm\t"; ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. - ZeroFillDirective = "\t.zerofill\t"; // Uses .zerofill + HasMachoZeroFillDirective = true; // Uses .zerofill + HasStaticCtorDtorReferenceInStaticMode = true; SetDirective = "\t.set"; - ProtectedDirective = "\t.globl\t"; + + HiddenVisibilityAttr = MCSA_PrivateExtern; + // Doesn't support protected visibility. + ProtectedVisibilityAttr = MCSA_Global; + + HasDotTypeDotSizeDirective = false; - UsedDirective = "\t.no_dead_strip\t"; + HasNoDeadStrip = true; + // Note: Even though darwin has the .lcomm directive, it is just a synonym for + // zerofill, so we prefer to use .zerofill. // _foo.eh symbols are currently always exported so that the linker knows // about them. This is not necessary on 10.6 and later, but it diff --git a/lib/MC/MCAsmParser.cpp b/lib/MC/MCAsmParser.cpp deleted file mode 100644 index 2287e89..0000000 --- a/lib/MC/MCAsmParser.cpp +++ /dev/null @@ -1,18 +0,0 @@ -//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/MC/MCAsmParser.h" - -using namespace llvm; - -MCAsmParser::MCAsmParser() { -} - -MCAsmParser::~MCAsmParser() { -} diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index b6ebb1a..bf39239 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" -#include "llvm/ADT/SmallString.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -17,26 +16,68 @@ #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FormattedStream.h" using namespace llvm; namespace { class MCAsmStreamer : public MCStreamer { - raw_ostream &OS; + formatted_raw_ostream &OS; const MCAsmInfo &MAI; + bool IsLittleEndian, IsVerboseAsm; MCInstPrinter *InstPrinter; MCCodeEmitter *Emitter; + + SmallString<128> CommentToEmit; + raw_svector_ostream CommentStream; public: - MCAsmStreamer(MCContext &Context, raw_ostream &_OS, const MCAsmInfo &tai, - MCInstPrinter *_Printer, MCCodeEmitter *_Emitter) - : MCStreamer(Context), OS(_OS), MAI(tai), InstPrinter(_Printer), - Emitter(_Emitter) {} + MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, + const MCAsmInfo &mai, + bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer, + MCCodeEmitter *emitter) + : MCStreamer(Context), OS(os), MAI(mai), IsLittleEndian(isLittleEndian), + IsVerboseAsm(isVerboseAsm), InstPrinter(printer), Emitter(emitter), + CommentStream(CommentToEmit) {} ~MCAsmStreamer() {} + bool isLittleEndian() const { return IsLittleEndian; } + + + inline void EmitEOL() { + // If we don't have any comments, just emit a \n. + if (!IsVerboseAsm) { + OS << '\n'; + return; + } + EmitCommentsAndEOL(); + } + void EmitCommentsAndEOL(); + + /// AddComment - Add a comment that can be emitted to the generated .s + /// file if applicable as a QoI issue to make the output of the compiler + /// more readable. This only affects the MCAsmStreamer, and only when + /// verbose assembly output is enabled. + virtual void AddComment(const Twine &T); + + /// GetCommentOS - Return a raw_ostream that comments can be written to. + /// Unlike AddComment, you are required to terminate comments with \n if you + /// use this method. + virtual raw_ostream &GetCommentOS() { + if (!IsVerboseAsm) + return nulls(); // Discard comments unless in verbose asm mode. + return CommentStream; + } + + /// AddBlankLine - Emit a blank line to a .s file to pretty it up. + virtual void AddBlankLine() { + EmitEOL(); + } + /// @name MCStreamer Interface /// @{ @@ -44,23 +85,33 @@ public: virtual void EmitLabel(MCSymbol *Symbol); - virtual void EmitAssemblerFlag(AssemblerFlag Flag); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); - virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); - virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); + /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. + /// + /// @param Symbol - The common symbol to emit. + /// @param Size - The size of the common symbol. + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); - virtual void EmitBytes(StringRef Data); + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size); + virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); + virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace); + + virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue, + unsigned AddrSpace); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, @@ -78,6 +129,50 @@ public: } // end anonymous namespace. +/// AddComment - Add a comment that can be emitted to the generated .s +/// file if applicable as a QoI issue to make the output of the compiler +/// more readable. This only affects the MCAsmStreamer, and only when +/// verbose assembly output is enabled. +void MCAsmStreamer::AddComment(const Twine &T) { + if (!IsVerboseAsm) return; + + // Make sure that CommentStream is flushed. + CommentStream.flush(); + + T.toVector(CommentToEmit); + // Each comment goes on its own line. + CommentToEmit.push_back('\n'); + + // Tell the comment stream that the vector changed underneath it. + CommentStream.resync(); +} + +void MCAsmStreamer::EmitCommentsAndEOL() { + if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) { + OS << '\n'; + return; + } + + CommentStream.flush(); + StringRef Comments = CommentToEmit.str(); + + assert(Comments.back() == '\n' && + "Comment array not newline terminated"); + do { + // Emit a line of comments. + OS.PadToColumn(MAI.getCommentColumn()); + size_t Position = Comments.find('\n'); + OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n'; + + Comments = Comments.substr(Position+1); + } while (!Comments.empty()); + + CommentToEmit.clear(); + // Tell the comment stream that the vector changed underneath it. + CommentStream.resync(); +} + + static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { assert(Bytes && "Invalid size!"); return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); @@ -101,17 +196,17 @@ void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(CurSection && "Cannot emit before setting section!"); - Symbol->print(OS, &MAI); - OS << ":\n"; + OS << *Symbol << ":"; + EmitEOL(); Symbol->setSection(*CurSection); } -void MCAsmStreamer::EmitAssemblerFlag(AssemblerFlag Flag) { +void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { default: assert(0 && "Invalid flag!"); - case SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; + case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; } - OS << '\n'; + EmitEOL(); } void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { @@ -119,10 +214,8 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { assert((Symbol->isUndefined() || Symbol->isAbsolute()) && "Cannot define a symbol twice!"); - Symbol->print(OS, &MAI); - OS << " = "; - Value->print(OS, &MAI); - OS << '\n'; + OS << *Symbol << " = " << *Value; + EmitEOL(); // FIXME: Lift context changes into super class. // FIXME: Set associated section. @@ -130,41 +223,54 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { } void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, - SymbolAttr Attribute) { + MCSymbolAttr Attribute) { switch (Attribute) { - case Global: OS << ".globl"; break; - case Hidden: OS << ".hidden"; break; - case IndirectSymbol: OS << ".indirect_symbol"; break; - case Internal: OS << ".internal"; break; - case LazyReference: OS << ".lazy_reference"; break; - case NoDeadStrip: OS << ".no_dead_strip"; break; - case PrivateExtern: OS << ".private_extern"; break; - case Protected: OS << ".protected"; break; - case Reference: OS << ".reference"; break; - case Weak: OS << ".weak"; break; - case WeakDefinition: OS << ".weak_definition"; break; - case WeakReference: OS << ".weak_reference"; break; + case MCSA_Invalid: assert(0 && "Invalid symbol attribute"); + case MCSA_Global: OS << MAI.getGlobalDirective(); break; // .globl + case MCSA_Hidden: OS << ".hidden "; break; + case MCSA_IndirectSymbol: OS << ".indirect_symbol "; break; + case MCSA_Internal: OS << ".internal "; break; + case MCSA_LazyReference: OS << ".lazy_reference "; break; + case MCSA_Local: OS << ".local "; break; + case MCSA_NoDeadStrip: OS << ".no_dead_strip "; break; + case MCSA_PrivateExtern: OS << ".private_extern "; break; + case MCSA_Protected: OS << ".protected "; break; + case MCSA_Reference: OS << ".reference "; break; + case MCSA_Weak: OS << ".weak "; break; + case MCSA_WeakDefinition: OS << ".weak_definition "; break; + // .weak_reference + case MCSA_WeakReference: OS << MAI.getWeakRefDirective(); break; } - OS << ' '; - Symbol->print(OS, &MAI); - OS << '\n'; + OS << *Symbol; + EmitEOL(); } void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - OS << ".desc" << ' '; - Symbol->print(OS, &MAI); - OS << ',' << DescValue << '\n'; + OS << ".desc" << ' ' << *Symbol << ',' << DescValue; + EmitEOL(); } -void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, +void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { - OS << ".comm "; - Symbol->print(OS, &MAI); - OS << ',' << Size; - if (ByteAlignment != 0) - OS << ',' << Log2_32(ByteAlignment); - OS << '\n'; + OS << "\t.comm\t" << *Symbol << ',' << Size; + if (ByteAlignment != 0 && MAI.getCOMMDirectiveTakesAlignment()) { + if (MAI.getAlignmentIsInBytes()) + OS << ',' << ByteAlignment; + else + OS << ',' << Log2_32(ByteAlignment); + } + EmitEOL(); +} + +/// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. +/// +/// @param Symbol - The common symbol to emit. +/// @param Size - The size of the common symbol. +void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert(MAI.hasLCOMMDirective() && "Doesn't have .lcomm, can't emit it!"); + OS << "\t.lcomm\t" << *Symbol << ',' << Size; + EmitEOL(); } void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, @@ -177,36 +283,130 @@ void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); if (Symbol != NULL) { - OS << ','; - Symbol->print(OS, &MAI); - OS << ',' << Size; + OS << ',' << *Symbol << ',' << Size; if (ByteAlignment != 0) OS << ',' << Log2_32(ByteAlignment); } - OS << '\n'; + EmitEOL(); +} + +static inline char toOctal(int X) { return (X&7)+'0'; } + +void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + assert(CurSection && "Cannot emit contents before setting section!"); + if (Data.empty()) return; + + if (Data.size() == 1) { + OS << MAI.getData8bitsDirective(AddrSpace); + OS << (unsigned)(unsigned char)Data[0]; + EmitEOL(); + return; + } + + // If the data ends with 0 and the target supports .asciz, use it, otherwise + // use .ascii + if (MAI.getAscizDirective() && Data.back() == 0) { + OS << MAI.getAscizDirective(); + Data = Data.substr(0, Data.size()-1); + } else { + OS << MAI.getAsciiDirective(); + } + + OS << " \""; + for (unsigned i = 0, e = Data.size(); i != e; ++i) { + unsigned char C = Data[i]; + if (C == '"' || C == '\\') { + OS << '\\' << (char)C; + continue; + } + + if (isprint((unsigned char)C)) { + OS << (char)C; + continue; + } + + switch (C) { + case '\b': OS << "\\b"; break; + case '\f': OS << "\\f"; break; + case '\n': OS << "\\n"; break; + case '\r': OS << "\\r"; break; + case '\t': OS << "\\t"; break; + default: + OS << '\\'; + OS << toOctal(C >> 6); + OS << toOctal(C >> 3); + OS << toOctal(C >> 0); + break; + } + } + OS << '"'; + EmitEOL(); } -void MCAsmStreamer::EmitBytes(StringRef Data) { +/// EmitIntValue - Special case of EmitValue that avoids the client having +/// to pass in a MCExpr for constant integers. +void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, + unsigned AddrSpace) { assert(CurSection && "Cannot emit contents before setting section!"); - for (unsigned i = 0, e = Data.size(); i != e; ++i) - OS << ".byte " << (unsigned) (unsigned char) Data[i] << '\n'; + const char *Directive = 0; + switch (Size) { + default: break; + case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; + case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; + case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; + case 8: + Directive = MAI.getData64bitsDirective(AddrSpace); + // If the target doesn't support 64-bit data, emit as two 32-bit halves. + if (Directive) break; + if (isLittleEndian()) { + EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); + EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); + } else { + EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); + EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); + } + return; + } + + assert(Directive && "Invalid size for machine code value!"); + OS << Directive << truncateToSize(Value, Size); + EmitEOL(); } -void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size) { +void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { assert(CurSection && "Cannot emit contents before setting section!"); - // Need target hooks to know how to print this. + const char *Directive = 0; switch (Size) { - default: - llvm_unreachable("Invalid size for machine code value!"); - case 1: OS << ".byte"; break; - case 2: OS << ".short"; break; - case 4: OS << ".long"; break; - case 8: OS << ".quad"; break; + default: break; + case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; + case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; + case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; + case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break; } + + assert(Directive && "Invalid size for machine code value!"); + OS << Directive << *truncateToSize(Value, Size); + EmitEOL(); +} + +/// EmitFill - Emit NumBytes bytes worth of the value specified by +/// FillValue. This implements directives such as '.space'. +void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, + unsigned AddrSpace) { + if (NumBytes == 0) return; + + if (AddrSpace == 0) + if (const char *ZeroDirective = MAI.getZeroDirective()) { + OS << ZeroDirective << NumBytes; + if (FillValue != 0) + OS << ',' << (int)FillValue; + EmitEOL(); + return; + } - OS << ' '; - truncateToSize(Value, Size)->print(OS, &MAI); - OS << '\n'; + // Emit a byte at a time. + MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace); } void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, @@ -236,7 +436,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; } - OS << '\n'; + EmitEOL(); return; } @@ -254,15 +454,14 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ", " << truncateToSize(Value, ValueSize); if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; - OS << '\n'; + EmitEOL(); } void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { // FIXME: Verify that Offset is associated with the current section. - OS << ".org "; - Offset->print(OS, &MAI); - OS << ", " << (unsigned) Value << '\n'; + OS << ".org " << *Offset << ", " << (unsigned) Value; + EmitEOL(); } void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { @@ -271,7 +470,7 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { // If we have an AsmPrinter, use that to print. if (InstPrinter) { InstPrinter->printInst(&Inst); - OS << '\n'; + EmitEOL(); // Show the encoding if we have a code emitter. if (Emitter) { @@ -296,15 +495,18 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { // Otherwise fall back to a structural printing for now. Eventually we should // always have access to the target specific printer. Inst.print(OS, &MAI); - OS << '\n'; + EmitEOL(); } void MCAsmStreamer::Finish() { OS.flush(); } -MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS, - const MCAsmInfo &MAI, MCInstPrinter *IP, +MCStreamer *llvm::createAsmStreamer(MCContext &Context, + formatted_raw_ostream &OS, + const MCAsmInfo &MAI, bool isLittleEndian, + bool isVerboseAsm, MCInstPrinter *IP, MCCodeEmitter *CE) { - return new MCAsmStreamer(Context, OS, MAI, IP, CE); + return new MCAsmStreamer(Context, OS, MAI, isLittleEndian, isVerboseAsm, + IP, CE); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 1f5b6f1..f0f5a47 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -679,8 +679,6 @@ public: UndefinedSymbolData[i].SymbolData->setIndex(Index++); // The string table is padded to a multiple of 4. - // - // FIXME: Check to see if this varies per arch. while (StringTable.size() % 4) StringTable += '\x00'; } diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index a19ec19..1ee1b1b 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -15,7 +15,7 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; -void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { +void MCExpr::print(raw_ostream &OS) const { switch (getKind()) { case MCExpr::Constant: OS << cast<MCConstantExpr>(*this).getValue(); @@ -26,13 +26,10 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { // Parenthesize names that start with $ so that they don't look like // absolute names. - if (Sym.getName()[0] == '$') { - OS << '('; - Sym.print(OS, MAI); - OS << ')'; - } else { - Sym.print(OS, MAI); - } + if (Sym.getName()[0] == '$') + OS << '(' << Sym << ')'; + else + OS << Sym; return; } @@ -45,7 +42,7 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { case MCUnaryExpr::Not: OS << '~'; break; case MCUnaryExpr::Plus: OS << '+'; break; } - UE.getSubExpr()->print(OS, MAI); + OS << *UE.getSubExpr(); return; } @@ -54,11 +51,9 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { // Only print parens around the LHS if it is non-trivial. if (isa<MCConstantExpr>(BE.getLHS()) || isa<MCSymbolRefExpr>(BE.getLHS())) { - BE.getLHS()->print(OS, MAI); + OS << *BE.getLHS(); } else { - OS << '('; - BE.getLHS()->print(OS, MAI); - OS << ')'; + OS << '(' << *BE.getLHS() << ')'; } switch (BE.getOpcode()) { @@ -95,11 +90,9 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { // Only print parens around the LHS if it is non-trivial. if (isa<MCConstantExpr>(BE.getRHS()) || isa<MCSymbolRefExpr>(BE.getRHS())) { - BE.getRHS()->print(OS, MAI); + OS << *BE.getRHS(); } else { - OS << '('; - BE.getRHS()->print(OS, MAI); - OS << ')'; + OS << '(' << *BE.getRHS() << ')'; } return; } @@ -109,7 +102,7 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { } void MCExpr::dump() const { - print(dbgs(), 0); + print(dbgs()); dbgs() << '\n'; } diff --git a/lib/MC/MCInst.cpp b/lib/MC/MCInst.cpp index 7c7a644..0634c9f 100644 --- a/lib/MC/MCInst.cpp +++ b/lib/MC/MCInst.cpp @@ -23,9 +23,7 @@ void MCOperand::print(raw_ostream &OS, const MCAsmInfo *MAI) const { else if (isImm()) OS << "Imm:" << getImm(); else if (isExpr()) { - OS << "Expr:("; - getExpr()->print(OS, MAI); - OS << ")"; + OS << "Expr:(" << *getExpr() << ")"; } else OS << "UNDEFINED"; OS << ">"; diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 828b92a..e559c65 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -117,36 +117,26 @@ public: /// @{ virtual void SwitchSection(const MCSection *Section); - virtual void EmitLabel(MCSymbol *Symbol); - - virtual void EmitAssemblerFlag(AssemblerFlag Flag); - + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); - - virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); - + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); - - virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); - + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert(0 && "macho doesn't support this directive"); + } virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); - - virtual void EmitBytes(StringRef Data); - - virtual void EmitValue(const MCExpr *Value, unsigned Size); - + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); + virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); - virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0); - virtual void EmitInstruction(const MCInst &Inst); - virtual void Finish(); /// @} @@ -183,9 +173,9 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { Symbol->setSection(*CurSection); } -void MCMachOStreamer::EmitAssemblerFlag(AssemblerFlag Flag) { +void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { - case SubsectionsViaSymbols: + case MCAF_SubsectionsViaSymbols: Assembler.setSubsectionsViaSymbols(true); return; } @@ -204,10 +194,10 @@ void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { } void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, - SymbolAttr Attribute) { + MCSymbolAttr Attribute) { // Indirect symbols are handled differently, to match how 'as' handles // them. This makes writing matching .o files easier. - if (Attribute == MCStreamer::IndirectSymbol) { + if (Attribute == MCSA_IndirectSymbol) { // Note that we intentionally cannot use the symbol data here; this is // important for matching the string table that 'as' generates. IndirectSymbolData ISD; @@ -229,19 +219,21 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, // In the future it might be worth trying to make these operations more well // defined. switch (Attribute) { - case MCStreamer::IndirectSymbol: - case MCStreamer::Hidden: - case MCStreamer::Internal: - case MCStreamer::Protected: - case MCStreamer::Weak: + case MCSA_Invalid: + case MCSA_IndirectSymbol: + case MCSA_Hidden: + case MCSA_Internal: + case MCSA_Protected: + case MCSA_Weak: + case MCSA_Local: assert(0 && "Invalid symbol attribute for Mach-O!"); break; - case MCStreamer::Global: + case MCSA_Global: SD.setExternal(true); break; - case MCStreamer::LazyReference: + case MCSA_LazyReference: // FIXME: This requires -dynamic. SD.setFlags(SD.getFlags() | SF_NoDeadStrip); if (Symbol->isUndefined()) @@ -250,23 +242,23 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, // Since .reference sets the no dead strip bit, it is equivalent to // .no_dead_strip in practice. - case MCStreamer::Reference: - case MCStreamer::NoDeadStrip: + case MCSA_Reference: + case MCSA_NoDeadStrip: SD.setFlags(SD.getFlags() | SF_NoDeadStrip); break; - case MCStreamer::PrivateExtern: + case MCSA_PrivateExtern: SD.setExternal(true); SD.setPrivateExtern(true); break; - case MCStreamer::WeakReference: + case MCSA_WeakReference: // FIXME: This requires -dynamic. if (Symbol->isUndefined()) SD.setFlags(SD.getFlags() | SF_WeakReference); break; - case MCStreamer::WeakDefinition: + case MCSA_WeakDefinition: // FIXME: 'as' enforces that this is defined and global. The manual claims // it has to be in a coalesced section, but this isn't enforced. SD.setFlags(SD.getFlags() | SF_WeakDefinition); @@ -281,7 +273,7 @@ void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask); } -void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, +void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); @@ -315,14 +307,15 @@ void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, SectData.setAlignment(ByteAlignment); } -void MCMachOStreamer::EmitBytes(StringRef Data) { +void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); if (!DF) DF = new MCDataFragment(CurSectionData); DF->getContents().append(Data.begin(), Data.end()); } -void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size) { +void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { new MCFillFragment(*AddValueSymbols(Value), Size, 1, CurSectionData); } @@ -353,11 +346,13 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { if (!Emitter) llvm_unreachable("no code emitter available!"); + // FIXME: Emitting an instruction should cause S_ATTR_SOME_INSTRUCTIONS to + // be set for the current section. // FIXME: Relocations! SmallString<256> Code; raw_svector_ostream VecOS(Code); Emitter->EncodeInstruction(Inst, VecOS); - EmitBytes(VecOS.str()); + EmitBytes(VecOS.str(), 0); } void MCMachOStreamer::Finish() { diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index ddc4e69..7c219b3 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -31,23 +31,25 @@ namespace { virtual void EmitLabel(MCSymbol *Symbol) {} - virtual void EmitAssemblerFlag(AssemblerFlag Flag) {} + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) {} + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} - virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) {} - virtual void EmitBytes(StringRef Data) {} + virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} - virtual void EmitValue(const MCExpr *Value, unsigned Size) {} + virtual void EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) {} virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp new file mode 100644 index 0000000..482eefd --- /dev/null +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -0,0 +1,320 @@ +//===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the lexer for assembly files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/MC/MCAsmInfo.h" +#include <cerrno> +#include <cstdio> +#include <cstdlib> +using namespace llvm; + +AsmLexer::AsmLexer(const MCAsmInfo &_MAI) : MAI(_MAI) { + CurBuf = NULL; + CurPtr = NULL; + TokStart = 0; +} + +AsmLexer::~AsmLexer() { +} + +void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { + CurBuf = buf; + + if (ptr) + CurPtr = ptr; + else + CurPtr = CurBuf->getBufferStart(); + + TokStart = 0; +} + +SMLoc AsmLexer::getLoc() const { + return SMLoc::getFromPointer(TokStart); +} + +/// ReturnError - Set the error to the specified string at the specified +/// location. This is defined to always return AsmToken::Error. +AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { + SetError(SMLoc::getFromPointer(Loc), Msg); + + return AsmToken(AsmToken::Error, StringRef(Loc, 0)); +} + +int AsmLexer::getNextChar() { + char CurChar = *CurPtr++; + switch (CurChar) { + default: + return (unsigned char)CurChar; + case 0: + // A nul character in the stream is either the end of the current buffer or + // a random nul in the file. Disambiguate that here. + if (CurPtr-1 != CurBuf->getBufferEnd()) + return 0; // Just whitespace. + + // Otherwise, return end of file. + --CurPtr; // Another call to lex will return EOF again. + return EOF; + } +} + +/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* +AsmToken AsmLexer::LexIdentifier() { + while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' || + *CurPtr == '.' || *CurPtr == '@') + ++CurPtr; + return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); +} + +/// LexSlash: Slash: / +/// C-Style Comment: /* ... */ +AsmToken AsmLexer::LexSlash() { + switch (*CurPtr) { + case '*': break; // C style comment. + case '/': return ++CurPtr, LexLineComment(); + default: return AsmToken(AsmToken::Slash, StringRef(CurPtr, 1)); + } + + // C Style comment. + ++CurPtr; // skip the star. + while (1) { + int CurChar = getNextChar(); + switch (CurChar) { + case EOF: + return ReturnError(TokStart, "unterminated comment"); + case '*': + // End of the comment? + if (CurPtr[0] != '/') break; + + ++CurPtr; // End the */. + return LexToken(); + } + } +} + +/// LexLineComment: Comment: #[^\n]* +/// : //[^\n]* +AsmToken AsmLexer::LexLineComment() { + // FIXME: This is broken if we happen to a comment at the end of a file, which + // was .included, and which doesn't end with a newline. + int CurChar = getNextChar(); + while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF) + CurChar = getNextChar(); + + if (CurChar == EOF) + return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0)); + return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); +} + + +/// LexDigit: First character is [0-9]. +/// Local Label: [0-9][:] +/// Forward/Backward Label: [0-9][fb] +/// Binary integer: 0b[01]+ +/// Octal integer: 0[0-7]+ +/// Hex integer: 0x[0-9a-fA-F]+ +/// Decimal integer: [1-9][0-9]* +/// TODO: FP literal. +AsmToken AsmLexer::LexDigit() { + if (*CurPtr == ':') + return ReturnError(TokStart, "FIXME: local label not implemented"); + if (*CurPtr == 'f' || *CurPtr == 'b') + return ReturnError(TokStart, "FIXME: directional label not implemented"); + + // Decimal integer: [1-9][0-9]* + if (CurPtr[-1] != '0') { + while (isdigit(*CurPtr)) + ++CurPtr; + + StringRef Result(TokStart, CurPtr - TokStart); + + long long Value; + if (Result.getAsInteger(10, Value)) + return ReturnError(TokStart, "Invalid decimal number"); + return AsmToken(AsmToken::Integer, Result, Value); + } + + if (*CurPtr == 'b') { + ++CurPtr; + const char *NumStart = CurPtr; + while (CurPtr[0] == '0' || CurPtr[0] == '1') + ++CurPtr; + + // Requires at least one binary digit. + if (CurPtr == NumStart) + return ReturnError(TokStart, "Invalid binary number"); + + StringRef Result(TokStart, CurPtr - TokStart); + + long long Value; + if (Result.getAsInteger(2, Value)) + return ReturnError(TokStart, "Invalid binary number"); + + return AsmToken(AsmToken::Integer, Result, Value); + } + + if (*CurPtr == 'x') { + ++CurPtr; + const char *NumStart = CurPtr; + while (isxdigit(CurPtr[0])) + ++CurPtr; + + // Requires at least one hex digit. + if (CurPtr == NumStart) + return ReturnError(CurPtr-2, "Invalid hexadecimal number"); + + unsigned long long Result; + if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) + return ReturnError(TokStart, "Invalid hexadecimal number"); + + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + (int64_t)Result); + } + + // Must be an octal number, it starts with 0. + while (*CurPtr >= '0' && *CurPtr <= '7') + ++CurPtr; + + StringRef Result(TokStart, CurPtr - TokStart); + long long Value; + if (Result.getAsInteger(8, Value)) + return ReturnError(TokStart, "Invalid octal number"); + + return AsmToken(AsmToken::Integer, Result, Value); +} + +/// LexQuote: String: "..." +AsmToken AsmLexer::LexQuote() { + int CurChar = getNextChar(); + // TODO: does gas allow multiline string constants? + while (CurChar != '"') { + if (CurChar == '\\') { + // Allow \", etc. + CurChar = getNextChar(); + } + + if (CurChar == EOF) + return ReturnError(TokStart, "unterminated string constant"); + + CurChar = getNextChar(); + } + + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); +} + +StringRef AsmLexer::LexUntilEndOfStatement() { + TokStart = CurPtr; + + while (!isAtStartOfComment(*CurPtr) && // Start of line comment. + *CurPtr != ';' && // End of statement marker. + *CurPtr != '\n' && + *CurPtr != '\r' && + (*CurPtr != 0 || CurPtr != CurBuf->getBufferEnd())) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); +} + +bool AsmLexer::isAtStartOfComment(char Char) { + // FIXME: This won't work for multi-character comment indicators like "//". + return Char == *MAI.getCommentString(); +} + +AsmToken AsmLexer::LexToken() { + TokStart = CurPtr; + // This always consumes at least one character. + int CurChar = getNextChar(); + + if (isAtStartOfComment(CurChar)) + return LexLineComment(); + + switch (CurChar) { + default: + // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* + if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') + return LexIdentifier(); + + // Unknown character, emit an error. + return ReturnError(TokStart, "invalid character in input"); + case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); + case 0: + case ' ': + case '\t': + // Ignore whitespace. + return LexToken(); + case '\n': // FALL THROUGH. + case '\r': // FALL THROUGH. + case ';': return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); + case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); + case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); + case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); + case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); + case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); + case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); + case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); + case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); + case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); + case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); + case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); + case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); + case '=': + if (*CurPtr == '=') + return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); + case '|': + if (*CurPtr == '|') + return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); + case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); + case '&': + if (*CurPtr == '&') + return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); + case '!': + if (*CurPtr == '=') + return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); + case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); + case '/': return LexSlash(); + case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + case '"': return LexQuote(); + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return LexDigit(); + case '<': + switch (*CurPtr) { + case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + StringRef(TokStart, 2)); + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); + } + case '>': + switch (*CurPtr) { + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); + } + + // TODO: Quoted identifiers (objc methods etc) + // local labels: [0-9][:] + // Forward/backward labels: [0-9][fb] + // Integers, fp constants, character constants. + } +} diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp new file mode 100644 index 0000000..dd438b7 --- /dev/null +++ b/lib/MC/MCParser/AsmParser.cpp @@ -0,0 +1,1781 @@ +//===- AsmParser.cpp - Parser for Assembly Files --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the parser for assembly files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/AsmParser.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmParser.h" +using namespace llvm; + + +enum { DEFAULT_ADDRSPACE = 0 }; + +// Mach-O section uniquing. +// +// FIXME: Figure out where this should live, it should be shared by +// TargetLoweringObjectFile. +typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy; + +AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, + const MCAsmInfo &_MAI) + : Lexer(_MAI), Ctx(_Ctx), Out(_Out), SrcMgr(_SM), TargetParser(0), + CurBuffer(0), SectionUniquingMap(0) { + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + + // Debugging directives. + AddDirectiveHandler(".file", &AsmParser::ParseDirectiveFile); + AddDirectiveHandler(".line", &AsmParser::ParseDirectiveLine); + AddDirectiveHandler(".loc", &AsmParser::ParseDirectiveLoc); +} + + + +AsmParser::~AsmParser() { + // If we have the MachO uniquing map, free it. + delete (MachOUniqueMapTy*)SectionUniquingMap; +} + +const MCSection *AsmParser::getMachOSection(const StringRef &Segment, + const StringRef &Section, + unsigned TypeAndAttributes, + unsigned Reserved2, + SectionKind Kind) const { + // We unique sections by their segment/section pair. The returned section + // may not have the same flags as the requested section, if so this should be + // diagnosed by the client as an error. + + // Create the map if it doesn't already exist. + if (SectionUniquingMap == 0) + SectionUniquingMap = new MachOUniqueMapTy(); + MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)SectionUniquingMap; + + // Form the name to look up. + SmallString<64> Name; + Name += Segment; + Name.push_back(','); + Name += Section; + + // Do the lookup, if we have a hit, return it. + const MCSectionMachO *&Entry = Map[Name.str()]; + + // FIXME: This should validate the type and attributes. + if (Entry) return Entry; + + // Otherwise, return a new section. + return Entry = MCSectionMachO::Create(Segment, Section, TypeAndAttributes, + Reserved2, Kind, Ctx); +} + +void AsmParser::Warning(SMLoc L, const Twine &Msg) { + PrintMessage(L, Msg.str(), "warning"); +} + +bool AsmParser::Error(SMLoc L, const Twine &Msg) { + PrintMessage(L, Msg.str(), "error"); + return true; +} + +bool AsmParser::TokError(const char *Msg) { + PrintMessage(Lexer.getLoc(), Msg, "error"); + return true; +} + +void AsmParser::PrintMessage(SMLoc Loc, const std::string &Msg, + const char *Type) const { + SrcMgr.PrintMessage(Loc, Msg, Type); +} + +bool AsmParser::EnterIncludeFile(const std::string &Filename) { + int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc()); + if (NewBuf == -1) + return true; + + CurBuffer = NewBuf; + + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + + return false; +} + +const AsmToken &AsmParser::Lex() { + const AsmToken *tok = &Lexer.Lex(); + + if (tok->is(AsmToken::Eof)) { + // If this is the end of an included file, pop the parent file off the + // include stack. + SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); + if (ParentIncludeLoc != SMLoc()) { + CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), + ParentIncludeLoc.getPointer()); + tok = &Lexer.Lex(); + } + } + + if (tok->is(AsmToken::Error)) + PrintMessage(Lexer.getErrLoc(), Lexer.getErr(), "error"); + + return *tok; +} + +bool AsmParser::Run() { + // Create the initial section. + // + // FIXME: Support -n. + // FIXME: Target hook & command line option for initial section. + Out.SwitchSection(getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind())); + + + // Prime the lexer. + Lex(); + + bool HadError = false; + + AsmCond StartingCondState = TheCondState; + + // While we have input, parse each statement. + while (Lexer.isNot(AsmToken::Eof)) { + // Handle conditional assembly here before calling ParseStatement() + if (Lexer.getKind() == AsmToken::Identifier) { + // If we have an identifier, handle it as the key symbol. + AsmToken ID = getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal = ID.getString(); + + if (IDVal == ".if" || + IDVal == ".elseif" || + IDVal == ".else" || + IDVal == ".endif") { + if (!ParseConditionalAssemblyDirectives(IDVal, IDLoc)) + continue; + HadError = true; + EatToEndOfStatement(); + continue; + } + } + if (TheCondState.Ignore) { + EatToEndOfStatement(); + continue; + } + + if (!ParseStatement()) continue; + + // We had an error, remember it and recover by skipping to the next line. + HadError = true; + EatToEndOfStatement(); + } + + if (TheCondState.TheCond != StartingCondState.TheCond || + TheCondState.Ignore != StartingCondState.Ignore) + return TokError("unmatched .ifs or .elses"); + + if (!HadError) + Out.Finish(); + + return HadError; +} + +/// ParseConditionalAssemblyDirectives - parse the conditional assembly +/// directives +bool AsmParser::ParseConditionalAssemblyDirectives(StringRef Directive, + SMLoc DirectiveLoc) { + if (Directive == ".if") + return ParseDirectiveIf(DirectiveLoc); + if (Directive == ".elseif") + return ParseDirectiveElseIf(DirectiveLoc); + if (Directive == ".else") + return ParseDirectiveElse(DirectiveLoc); + if (Directive == ".endif") + return ParseDirectiveEndIf(DirectiveLoc); + return true; +} + +/// EatToEndOfStatement - Throw away the rest of the line for testing purposes. +void AsmParser::EatToEndOfStatement() { + while (Lexer.isNot(AsmToken::EndOfStatement) && + Lexer.isNot(AsmToken::Eof)) + Lex(); + + // Eat EOL. + if (Lexer.is(AsmToken::EndOfStatement)) + Lex(); +} + + +/// ParseParenExpr - Parse a paren expression and return it. +/// NOTE: This assumes the leading '(' has already been consumed. +/// +/// parenexpr ::= expr) +/// +bool AsmParser::ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { + if (ParseExpression(Res)) return true; + if (Lexer.isNot(AsmToken::RParen)) + return TokError("expected ')' in parentheses expression"); + EndLoc = Lexer.getLoc(); + Lex(); + return false; +} + +MCSymbol *AsmParser::CreateSymbol(StringRef Name) { + if (MCSymbol *S = Ctx.LookupSymbol(Name)) + return S; + + // If the label starts with L it is an assembler temporary label. + if (Name.startswith("L")) + return Ctx.CreateTemporarySymbol(Name); + + return Ctx.CreateSymbol(Name); +} + +/// ParsePrimaryExpr - Parse a primary expression and return it. +/// primaryexpr ::= (parenexpr +/// primaryexpr ::= symbol +/// primaryexpr ::= number +/// primaryexpr ::= ~,+,- primaryexpr +bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { + switch (Lexer.getKind()) { + default: + return TokError("unknown token in expression"); + case AsmToken::Exclaim: + Lex(); // Eat the operator. + if (ParsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreateLNot(Res, getContext()); + return false; + case AsmToken::String: + case AsmToken::Identifier: { + // This is a symbol reference. + MCSymbol *Sym = CreateSymbol(getTok().getIdentifier()); + EndLoc = Lexer.getLoc(); + Lex(); // Eat identifier. + + // If this is an absolute variable reference, substitute it now to preserve + // semantics in the face of reassignment. + if (Sym->getValue() && isa<MCConstantExpr>(Sym->getValue())) { + Res = Sym->getValue(); + return false; + } + + // Otherwise create a symbol ref. + Res = MCSymbolRefExpr::Create(Sym, getContext()); + return false; + } + case AsmToken::Integer: + Res = MCConstantExpr::Create(getTok().getIntVal(), getContext()); + EndLoc = Lexer.getLoc(); + Lex(); // Eat token. + return false; + case AsmToken::LParen: + Lex(); // Eat the '('. + return ParseParenExpr(Res, EndLoc); + case AsmToken::Minus: + Lex(); // Eat the operator. + if (ParsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreateMinus(Res, getContext()); + return false; + case AsmToken::Plus: + Lex(); // Eat the operator. + if (ParsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreatePlus(Res, getContext()); + return false; + case AsmToken::Tilde: + Lex(); // Eat the operator. + if (ParsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreateNot(Res, getContext()); + return false; + } +} + +bool AsmParser::ParseExpression(const MCExpr *&Res) { + SMLoc EndLoc; + return ParseExpression(Res, EndLoc); +} + +/// ParseExpression - Parse an expression and return it. +/// +/// expr ::= expr +,- expr -> lowest. +/// expr ::= expr |,^,&,! expr -> middle. +/// expr ::= expr *,/,%,<<,>> expr -> highest. +/// expr ::= primaryexpr +/// +bool AsmParser::ParseExpression(const MCExpr *&Res, SMLoc &EndLoc) { + Res = 0; + return ParsePrimaryExpr(Res, EndLoc) || + ParseBinOpRHS(1, Res, EndLoc); +} + +bool AsmParser::ParseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { + if (ParseParenExpr(Res, EndLoc)) + return true; + + return false; +} + +bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { + const MCExpr *Expr; + + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Expr)) + return true; + + if (!Expr->EvaluateAsAbsolute(Res)) + return Error(StartLoc, "expected absolute expression"); + + return false; +} + +static unsigned getBinOpPrecedence(AsmToken::TokenKind K, + MCBinaryExpr::Opcode &Kind) { + switch (K) { + default: + return 0; // not a binop. + + // Lowest Precedence: &&, || + case AsmToken::AmpAmp: + Kind = MCBinaryExpr::LAnd; + return 1; + case AsmToken::PipePipe: + Kind = MCBinaryExpr::LOr; + return 1; + + // Low Precedence: +, -, ==, !=, <>, <, <=, >, >= + case AsmToken::Plus: + Kind = MCBinaryExpr::Add; + return 2; + case AsmToken::Minus: + Kind = MCBinaryExpr::Sub; + return 2; + case AsmToken::EqualEqual: + Kind = MCBinaryExpr::EQ; + return 2; + case AsmToken::ExclaimEqual: + case AsmToken::LessGreater: + Kind = MCBinaryExpr::NE; + return 2; + case AsmToken::Less: + Kind = MCBinaryExpr::LT; + return 2; + case AsmToken::LessEqual: + Kind = MCBinaryExpr::LTE; + return 2; + case AsmToken::Greater: + Kind = MCBinaryExpr::GT; + return 2; + case AsmToken::GreaterEqual: + Kind = MCBinaryExpr::GTE; + return 2; + + // Intermediate Precedence: |, &, ^ + // + // FIXME: gas seems to support '!' as an infix operator? + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; + return 3; + case AsmToken::Caret: + Kind = MCBinaryExpr::Xor; + return 3; + case AsmToken::Amp: + Kind = MCBinaryExpr::And; + return 3; + + // Highest Precedence: *, /, %, <<, >> + case AsmToken::Star: + Kind = MCBinaryExpr::Mul; + return 4; + case AsmToken::Slash: + Kind = MCBinaryExpr::Div; + return 4; + case AsmToken::Percent: + Kind = MCBinaryExpr::Mod; + return 4; + case AsmToken::LessLess: + Kind = MCBinaryExpr::Shl; + return 4; + case AsmToken::GreaterGreater: + Kind = MCBinaryExpr::Shr; + return 4; + } +} + + +/// ParseBinOpRHS - Parse all binary operators with precedence >= 'Precedence'. +/// Res contains the LHS of the expression on input. +bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, + SMLoc &EndLoc) { + while (1) { + MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; + unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); + + // If the next token is lower precedence than we are allowed to eat, return + // successfully with what we ate already. + if (TokPrec < Precedence) + return false; + + Lex(); + + // Eat the next primary expression. + const MCExpr *RHS; + if (ParsePrimaryExpr(RHS, EndLoc)) return true; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + MCBinaryExpr::Opcode Dummy; + unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy); + if (TokPrec < NextTokPrec) { + if (ParseBinOpRHS(Precedence+1, RHS, EndLoc)) return true; + } + + // Merge LHS and RHS according to operator. + Res = MCBinaryExpr::Create(Kind, Res, RHS, getContext()); + } +} + + + + +/// ParseStatement: +/// ::= EndOfStatement +/// ::= Label* Directive ...Operands... EndOfStatement +/// ::= Label* Identifier OperandList* EndOfStatement +bool AsmParser::ParseStatement() { + if (Lexer.is(AsmToken::EndOfStatement)) { + Lex(); + return false; + } + + // Statements always start with an identifier. + AsmToken ID = getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal; + if (ParseIdentifier(IDVal)) + return TokError("unexpected token at start of statement"); + + // FIXME: Recurse on local labels? + + // See what kind of statement we have. + switch (Lexer.getKind()) { + case AsmToken::Colon: { + // identifier ':' -> Label. + Lex(); + + // Diagnose attempt to use a variable as a label. + // + // FIXME: Diagnostics. Note the location of the definition as a label. + // FIXME: This doesn't diagnose assignment to a symbol which has been + // implicitly marked as external. + MCSymbol *Sym = CreateSymbol(IDVal); + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // Emit the label. + Out.EmitLabel(Sym); + + return ParseStatement(); + } + + case AsmToken::Equal: + // identifier '=' ... -> assignment statement + Lex(); + + return ParseAssignment(IDVal); + + default: // Normal instruction or directive. + break; + } + + // Otherwise, we have a normal instruction or directive. + if (IDVal[0] == '.') { + // FIXME: This should be driven based on a hash lookup and callback. + if (IDVal == ".section") + return ParseDirectiveDarwinSection(); + if (IDVal == ".text") + // FIXME: This changes behavior based on the -static flag to the + // assembler. + return ParseDirectiveSectionSwitch("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + if (IDVal == ".const") + return ParseDirectiveSectionSwitch("__TEXT", "__const"); + if (IDVal == ".static_const") + return ParseDirectiveSectionSwitch("__TEXT", "__static_const"); + if (IDVal == ".cstring") + return ParseDirectiveSectionSwitch("__TEXT","__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".literal4") + return ParseDirectiveSectionSwitch("__TEXT", "__literal4", + MCSectionMachO::S_4BYTE_LITERALS, + 4); + if (IDVal == ".literal8") + return ParseDirectiveSectionSwitch("__TEXT", "__literal8", + MCSectionMachO::S_8BYTE_LITERALS, + 8); + if (IDVal == ".literal16") + return ParseDirectiveSectionSwitch("__TEXT","__literal16", + MCSectionMachO::S_16BYTE_LITERALS, + 16); + if (IDVal == ".constructor") + return ParseDirectiveSectionSwitch("__TEXT","__constructor"); + if (IDVal == ".destructor") + return ParseDirectiveSectionSwitch("__TEXT","__destructor"); + if (IDVal == ".fvmlib_init0") + return ParseDirectiveSectionSwitch("__TEXT","__fvmlib_init0"); + if (IDVal == ".fvmlib_init1") + return ParseDirectiveSectionSwitch("__TEXT","__fvmlib_init1"); + + // FIXME: The assembler manual claims that this has the self modify code + // flag, at least on x86-32, but that does not appear to be correct. + if (IDVal == ".symbol_stub") + return ParseDirectiveSectionSwitch("__TEXT","__symbol_stub", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + // FIXME: Different on PPC and ARM. + 0, 16); + // FIXME: PowerPC only? + if (IDVal == ".picsymbol_stub") + return ParseDirectiveSectionSwitch("__TEXT","__picsymbol_stub", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, 26); + if (IDVal == ".data") + return ParseDirectiveSectionSwitch("__DATA", "__data"); + if (IDVal == ".static_data") + return ParseDirectiveSectionSwitch("__DATA", "__static_data"); + + // FIXME: The section names of these two are misspelled in the assembler + // manual. + if (IDVal == ".non_lazy_symbol_pointer") + return ParseDirectiveSectionSwitch("__DATA", "__nl_symbol_ptr", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, + 4); + if (IDVal == ".lazy_symbol_pointer") + return ParseDirectiveSectionSwitch("__DATA", "__la_symbol_ptr", + MCSectionMachO::S_LAZY_SYMBOL_POINTERS, + 4); + + if (IDVal == ".dyld") + return ParseDirectiveSectionSwitch("__DATA", "__dyld"); + if (IDVal == ".mod_init_func") + return ParseDirectiveSectionSwitch("__DATA", "__mod_init_func", + MCSectionMachO::S_MOD_INIT_FUNC_POINTERS, + 4); + if (IDVal == ".mod_term_func") + return ParseDirectiveSectionSwitch("__DATA", "__mod_term_func", + MCSectionMachO::S_MOD_TERM_FUNC_POINTERS, + 4); + if (IDVal == ".const_data") + return ParseDirectiveSectionSwitch("__DATA", "__const"); + + + if (IDVal == ".objc_class") + return ParseDirectiveSectionSwitch("__OBJC", "__class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_meta_class") + return ParseDirectiveSectionSwitch("__OBJC", "__meta_class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cat_cls_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cat_cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cat_inst_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cat_inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_protocol") + return ParseDirectiveSectionSwitch("__OBJC", "__protocol", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_string_object") + return ParseDirectiveSectionSwitch("__OBJC", "__string_object", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cls_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_inst_meth") + return ParseDirectiveSectionSwitch("__OBJC", "__inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_cls_refs") + return ParseDirectiveSectionSwitch("__OBJC", "__cls_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, + 4); + if (IDVal == ".objc_message_refs") + return ParseDirectiveSectionSwitch("__OBJC", "__message_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, + 4); + if (IDVal == ".objc_symbols") + return ParseDirectiveSectionSwitch("__OBJC", "__symbols", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_category") + return ParseDirectiveSectionSwitch("__OBJC", "__category", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_class_vars") + return ParseDirectiveSectionSwitch("__OBJC", "__class_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_instance_vars") + return ParseDirectiveSectionSwitch("__OBJC", "__instance_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_module_info") + return ParseDirectiveSectionSwitch("__OBJC", "__module_info", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + if (IDVal == ".objc_class_names") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_meth_var_types") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_meth_var_names") + return ParseDirectiveSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + if (IDVal == ".objc_selector_strs") + return ParseDirectiveSectionSwitch("__OBJC", "__selector_strs", + MCSectionMachO::S_CSTRING_LITERALS); + + // Assembler features + if (IDVal == ".set") + return ParseDirectiveSet(); + + // Data directives + + if (IDVal == ".ascii") + return ParseDirectiveAscii(false); + if (IDVal == ".asciz") + return ParseDirectiveAscii(true); + + if (IDVal == ".byte") + return ParseDirectiveValue(1); + if (IDVal == ".short") + return ParseDirectiveValue(2); + if (IDVal == ".long") + return ParseDirectiveValue(4); + if (IDVal == ".quad") + return ParseDirectiveValue(8); + + // FIXME: Target hooks for IsPow2. + if (IDVal == ".align") + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); + if (IDVal == ".align32") + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (IDVal == ".balign") + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); + if (IDVal == ".balignw") + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); + if (IDVal == ".balignl") + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); + if (IDVal == ".p2align") + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); + if (IDVal == ".p2alignw") + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); + if (IDVal == ".p2alignl") + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + + if (IDVal == ".org") + return ParseDirectiveOrg(); + + if (IDVal == ".fill") + return ParseDirectiveFill(); + if (IDVal == ".space") + return ParseDirectiveSpace(); + + // Symbol attribute directives + + if (IDVal == ".globl" || IDVal == ".global") + return ParseDirectiveSymbolAttribute(MCSA_Global); + if (IDVal == ".hidden") + return ParseDirectiveSymbolAttribute(MCSA_Hidden); + if (IDVal == ".indirect_symbol") + return ParseDirectiveSymbolAttribute(MCSA_IndirectSymbol); + if (IDVal == ".internal") + return ParseDirectiveSymbolAttribute(MCSA_Internal); + if (IDVal == ".lazy_reference") + return ParseDirectiveSymbolAttribute(MCSA_LazyReference); + if (IDVal == ".no_dead_strip") + return ParseDirectiveSymbolAttribute(MCSA_NoDeadStrip); + if (IDVal == ".private_extern") + return ParseDirectiveSymbolAttribute(MCSA_PrivateExtern); + if (IDVal == ".protected") + return ParseDirectiveSymbolAttribute(MCSA_Protected); + if (IDVal == ".reference") + return ParseDirectiveSymbolAttribute(MCSA_Reference); + if (IDVal == ".weak") + return ParseDirectiveSymbolAttribute(MCSA_Weak); + if (IDVal == ".weak_definition") + return ParseDirectiveSymbolAttribute(MCSA_WeakDefinition); + if (IDVal == ".weak_reference") + return ParseDirectiveSymbolAttribute(MCSA_WeakReference); + + if (IDVal == ".comm") + return ParseDirectiveComm(/*IsLocal=*/false); + if (IDVal == ".lcomm") + return ParseDirectiveComm(/*IsLocal=*/true); + if (IDVal == ".zerofill") + return ParseDirectiveDarwinZerofill(); + if (IDVal == ".desc") + return ParseDirectiveDarwinSymbolDesc(); + if (IDVal == ".lsym") + return ParseDirectiveDarwinLsym(); + + if (IDVal == ".subsections_via_symbols") + return ParseDirectiveDarwinSubsectionsViaSymbols(); + if (IDVal == ".abort") + return ParseDirectiveAbort(); + if (IDVal == ".include") + return ParseDirectiveInclude(); + if (IDVal == ".dump") + return ParseDirectiveDarwinDumpOrLoad(IDLoc, /*IsDump=*/true); + if (IDVal == ".load") + return ParseDirectiveDarwinDumpOrLoad(IDLoc, /*IsLoad=*/false); + + // Look up the handler in the handler table, + bool(AsmParser::*Handler)(StringRef, SMLoc) = DirectiveMap[IDVal]; + if (Handler) + return (this->*Handler)(IDVal, IDLoc); + + // Target hook for parsing target specific directives. + if (!getTargetParser().ParseDirective(ID)) + return false; + + Warning(IDLoc, "ignoring directive for now"); + EatToEndOfStatement(); + return false; + } + + + SmallVector<MCParsedAsmOperand*, 8> ParsedOperands; + if (getTargetParser().ParseInstruction(IDVal, IDLoc, ParsedOperands)) + // FIXME: Leaking ParsedOperands on failure. + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + // FIXME: Leaking ParsedOperands on failure. + return TokError("unexpected token in argument list"); + + // Eat the end of statement marker. + Lex(); + + + MCInst Inst; + + bool MatchFail = getTargetParser().MatchInstruction(ParsedOperands, Inst); + + // Free any parsed operands. + for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) + delete ParsedOperands[i]; + + if (MatchFail) { + // FIXME: We should give nicer diagnostics about the exact failure. + Error(IDLoc, "unrecognized instruction"); + return true; + } + + // Instruction is good, process it. + Out.EmitInstruction(Inst); + + // Skip to end of line for now. + return false; +} + +bool AsmParser::ParseAssignment(const StringRef &Name) { + // FIXME: Use better location, we should use proper tokens. + SMLoc EqualLoc = Lexer.getLoc(); + + const MCExpr *Value; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in assignment"); + + // Eat the end of statement marker. + Lex(); + + // Validate that the LHS is allowed to be a variable (either it has not been + // used as a symbol, or it is an absolute symbol). + MCSymbol *Sym = getContext().LookupSymbol(Name); + if (Sym) { + // Diagnose assignment to a label. + // + // FIXME: Diagnostics. Note the location of the definition as a label. + // FIXME: Diagnose assignment to protected identifier (e.g., register name). + if (!Sym->isUndefined() && !Sym->isAbsolute()) + return Error(EqualLoc, "redefinition of '" + Name + "'"); + else if (!Sym->isVariable()) + return Error(EqualLoc, "invalid assignment to '" + Name + "'"); + else if (!isa<MCConstantExpr>(Sym->getValue())) + return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + + Name + "'"); + } else + Sym = CreateSymbol(Name); + + // FIXME: Handle '.'. + + // Do the assignment. + Out.EmitAssignment(Sym, Value); + + return false; +} + +/// ParseIdentifier: +/// ::= identifier +/// ::= string +bool AsmParser::ParseIdentifier(StringRef &Res) { + if (Lexer.isNot(AsmToken::Identifier) && + Lexer.isNot(AsmToken::String)) + return true; + + Res = getTok().getIdentifier(); + + Lex(); // Consume the identifier token. + + return false; +} + +/// ParseDirectiveSet: +/// ::= .set identifier ',' expression +bool AsmParser::ParseDirectiveSet() { + StringRef Name; + + if (ParseIdentifier(Name)) + return TokError("expected identifier after '.set' directive"); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.set'"); + Lex(); + + return ParseAssignment(Name); +} + +/// ParseDirectiveSection: +/// ::= .section identifier (',' identifier)* +/// FIXME: This should actually parse out the segment, section, attributes and +/// sizeof_stub fields. +bool AsmParser::ParseDirectiveDarwinSection() { + SMLoc Loc = Lexer.getLoc(); + + StringRef SectionName; + if (ParseIdentifier(SectionName)) + return Error(Loc, "expected identifier after '.section' directive"); + + // Verify there is a following comma. + if (!Lexer.is(AsmToken::Comma)) + return TokError("unexpected token in '.section' directive"); + + std::string SectionSpec = SectionName; + SectionSpec += ","; + + // Add all the tokens until the end of the line, ParseSectionSpecifier will + // handle this. + StringRef EOL = Lexer.LexUntilEndOfStatement(); + SectionSpec.append(EOL.begin(), EOL.end()); + + Lex(); + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.section' directive"); + Lex(); + + + StringRef Segment, Section; + unsigned TAA, StubSize; + std::string ErrorStr = + MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, + TAA, StubSize); + + if (!ErrorStr.empty()) + return Error(Loc, ErrorStr.c_str()); + + // FIXME: Arch specific. + Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, + SectionKind())); + return false; +} + +/// ParseDirectiveSectionSwitch - +bool AsmParser::ParseDirectiveSectionSwitch(const char *Segment, + const char *Section, + unsigned TAA, unsigned Align, + unsigned StubSize) { + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + // FIXME: Arch specific. + Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, + SectionKind())); + + // Set the implicit alignment, if any. + // + // FIXME: This isn't really what 'as' does; I think it just uses the implicit + // alignment on the section (e.g., if one manually inserts bytes into the + // section, then just issueing the section switch directive will not realign + // the section. However, this is arguably more reasonable behavior, and there + // is no good reason for someone to intentionally emit incorrectly sized + // values into the implicitly aligned sections. + if (Align) + Out.EmitValueToAlignment(Align, 0, 1, 0); + + return false; +} + +bool AsmParser::ParseEscapedString(std::string &Data) { + assert(Lexer.is(AsmToken::String) && "Unexpected current token!"); + + Data = ""; + StringRef Str = getTok().getStringContents(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (Str[i] != '\\') { + Data += Str[i]; + continue; + } + + // Recognize escaped characters. Note that this escape semantics currently + // loosely follows Darwin 'as'. Notably, it doesn't support hex escapes. + ++i; + if (i == e) + return TokError("unexpected backslash at end of string"); + + // Recognize octal sequences. + if ((unsigned) (Str[i] - '0') <= 7) { + // Consume up to three octal characters. + unsigned Value = Str[i] - '0'; + + if (i + 1 != e && ((unsigned) (Str[i + 1] - '0')) <= 7) { + ++i; + Value = Value * 8 + (Str[i] - '0'); + + if (i + 1 != e && ((unsigned) (Str[i + 1] - '0')) <= 7) { + ++i; + Value = Value * 8 + (Str[i] - '0'); + } + } + + if (Value > 255) + return TokError("invalid octal escape sequence (out of range)"); + + Data += (unsigned char) Value; + continue; + } + + // Otherwise recognize individual escapes. + switch (Str[i]) { + default: + // Just reject invalid escape sequences for now. + return TokError("invalid escape sequence (unrecognized character)"); + + case 'b': Data += '\b'; break; + case 'f': Data += '\f'; break; + case 'n': Data += '\n'; break; + case 'r': Data += '\r'; break; + case 't': Data += '\t'; break; + case '"': Data += '"'; break; + case '\\': Data += '\\'; break; + } + } + + return false; +} + +/// ParseDirectiveAscii: +/// ::= ( .ascii | .asciz ) [ "string" ( , "string" )* ] +bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { + for (;;) { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.ascii' or '.asciz' directive"); + + std::string Data; + if (ParseEscapedString(Data)) + return true; + + Out.EmitBytes(Data, DEFAULT_ADDRSPACE); + if (ZeroTerminated) + Out.EmitBytes(StringRef("\0", 1), DEFAULT_ADDRSPACE); + + Lex(); + + if (Lexer.is(AsmToken::EndOfStatement)) + break; + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.ascii' or '.asciz' directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// ParseDirectiveValue +/// ::= (.byte | .short | ... ) [ expression (, expression)* ] +bool AsmParser::ParseDirectiveValue(unsigned Size) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { + for (;;) { + const MCExpr *Value; + SMLoc ATTRIBUTE_UNUSED StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) + return true; + + Out.EmitValue(Value, Size, DEFAULT_ADDRSPACE); + + if (Lexer.is(AsmToken::EndOfStatement)) + break; + + // FIXME: Improve diagnostic. + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// ParseDirectiveSpace +/// ::= .space expression [ , expression ] +bool AsmParser::ParseDirectiveSpace() { + int64_t NumBytes; + if (ParseAbsoluteExpression(NumBytes)) + return true; + + int64_t FillExpr = 0; + bool HasFillExpr = false; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.space' directive"); + Lex(); + + if (ParseAbsoluteExpression(FillExpr)) + return true; + + HasFillExpr = true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.space' directive"); + } + + Lex(); + + if (NumBytes <= 0) + return TokError("invalid number of bytes in '.space' directive"); + + // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. + Out.EmitFill(NumBytes, FillExpr, DEFAULT_ADDRSPACE); + + return false; +} + +/// ParseDirectiveFill +/// ::= .fill expression , expression , expression +bool AsmParser::ParseDirectiveFill() { + int64_t NumValues; + if (ParseAbsoluteExpression(NumValues)) + return true; + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lex(); + + int64_t FillSize; + if (ParseAbsoluteExpression(FillSize)) + return true; + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lex(); + + int64_t FillExpr; + if (ParseAbsoluteExpression(FillExpr)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.fill' directive"); + + Lex(); + + if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8) + return TokError("invalid '.fill' size, expected 1, 2, 4, or 8"); + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + Out.EmitValue(MCConstantExpr::Create(FillExpr, getContext()), FillSize, + DEFAULT_ADDRSPACE); + + return false; +} + +/// ParseDirectiveOrg +/// ::= .org expression [ , expression ] +bool AsmParser::ParseDirectiveOrg() { + const MCExpr *Offset; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Offset)) + return true; + + // Parse optional fill expression. + int64_t FillExpr = 0; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.org' directive"); + Lex(); + + if (ParseAbsoluteExpression(FillExpr)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.org' directive"); + } + + Lex(); + + // FIXME: Only limited forms of relocatable expressions are accepted here, it + // has to be relative to the current section. + Out.EmitValueToOffset(Offset, FillExpr); + + return false; +} + +/// ParseDirectiveAlign +/// ::= {.align, ...} expression [ , expression [ , expression ]] +bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + SMLoc AlignmentLoc = Lexer.getLoc(); + int64_t Alignment; + if (ParseAbsoluteExpression(Alignment)) + return true; + + SMLoc MaxBytesLoc; + bool HasFillExpr = false; + int64_t FillExpr = 0; + int64_t MaxBytesToFill = 0; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + // The fill expression can be omitted while specifying a maximum number of + // alignment bytes, e.g: + // .align 3,,4 + if (Lexer.isNot(AsmToken::Comma)) { + HasFillExpr = true; + if (ParseAbsoluteExpression(FillExpr)) + return true; + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + MaxBytesLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(MaxBytesToFill)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + } + } + + Lex(); + + if (!HasFillExpr) { + // FIXME: Sometimes fill with nop. + FillExpr = 0; + } + + // Compute alignment in bytes. + if (IsPow2) { + // FIXME: Diagnose overflow. + if (Alignment >= 32) { + Error(AlignmentLoc, "invalid alignment value"); + Alignment = 31; + } + + Alignment = 1ULL << Alignment; + } + + // Diagnose non-sensical max bytes to align. + if (MaxBytesLoc.isValid()) { + if (MaxBytesToFill < 1) { + Error(MaxBytesLoc, "alignment directive can never be satisfied in this " + "many bytes, ignoring maximum bytes expression"); + MaxBytesToFill = 0; + } + + if (MaxBytesToFill >= Alignment) { + Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and " + "has no effect"); + MaxBytesToFill = 0; + } + } + + // FIXME: Target specific behavior about how the "extra" bytes are filled. + Out.EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); + + return false; +} + +/// ParseDirectiveSymbolAttribute +/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] +bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { + for (;;) { + StringRef Name; + + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = CreateSymbol(Name); + + Out.EmitSymbolAttribute(Sym, Attr); + + if (Lexer.is(AsmToken::EndOfStatement)) + break; + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// ParseDirectiveDarwinSymbolDesc +/// ::= .desc identifier , expression +bool AsmParser::ParseDirectiveDarwinSymbolDesc() { + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.desc' directive"); + Lex(); + + SMLoc DescLoc = Lexer.getLoc(); + int64_t DescValue; + if (ParseAbsoluteExpression(DescValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.desc' directive"); + + Lex(); + + // Set the n_desc field of this Symbol to this DescValue + Out.EmitSymbolDesc(Sym, DescValue); + + return false; +} + +/// ParseDirectiveComm +/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] +bool AsmParser::ParseDirectiveComm(bool IsLocal) { + SMLoc IDLoc = Lexer.getLoc(); + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Size; + SMLoc SizeLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (Lexer.is(AsmToken::Comma)) { + Lex(); + Pow2AlignmentLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Pow2Alignment)) + return true; + + // If this target takes alignments in bytes (not log) validate and convert. + if (Lexer.getMAI().getAlignmentIsInBytes()) { + if (!isPowerOf2_64(Pow2Alignment)) + return Error(Pow2AlignmentLoc, "alignment must be a power of 2"); + Pow2Alignment = Log2_64(Pow2Alignment); + } + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.comm' or '.lcomm' directive"); + + Lex(); + + // NOTE: a size of zero for a .comm should create a undefined symbol + // but a size of .lcomm creates a bss symbol of size zero. + if (Size < 0) + return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't " + "be less than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assember + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive " + "alignment, can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // '.lcomm' is equivalent to '.zerofill'. + // Create the Symbol as a common or local common with Size and Pow2Alignment + if (IsLocal) { + Out.EmitZerofill(getMachOSection("__DATA", "__bss", + MCSectionMachO::S_ZEROFILL, 0, + SectionKind()), + Sym, Size, 1 << Pow2Alignment); + return false; + } + + Out.EmitCommonSymbol(Sym, Size, 1 << Pow2Alignment); + return false; +} + +/// ParseDirectiveDarwinZerofill +/// ::= .zerofill segname , sectname [, identifier , size_expression [ +/// , align_expression ]] +bool AsmParser::ParseDirectiveDarwinZerofill() { + // FIXME: Handle quoted names here. + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected segment name after '.zerofill' directive"); + StringRef Segment = getTok().getString(); + Lex(); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected section name after comma in '.zerofill' " + "directive"); + StringRef Section = getTok().getString(); + Lex(); + + // If this is the end of the line all that was wanted was to create the + // the section but with no symbol. + if (Lexer.is(AsmToken::EndOfStatement)) { + // Create the zerofill section but no symbol + Out.EmitZerofill(getMachOSection(Segment, Section, + MCSectionMachO::S_ZEROFILL, 0, + SectionKind())); + return false; + } + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected identifier in directive"); + + // handle the identifier as the key symbol. + SMLoc IDLoc = Lexer.getLoc(); + MCSymbol *Sym = CreateSymbol(getTok().getString()); + Lex(); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Size; + SMLoc SizeLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (Lexer.is(AsmToken::Comma)) { + Lex(); + Pow2AlignmentLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zerofill' directive"); + + Lex(); + + if (Size < 0) + return Error(SizeLoc, "invalid '.zerofill' directive size, can't be less " + "than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assember + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.zerofill' directive alignment, " + "can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // Create the zerofill Symbol with Size and Pow2Alignment + // + // FIXME: Arch specific. + Out.EmitZerofill(getMachOSection(Segment, Section, + MCSectionMachO::S_ZEROFILL, 0, + SectionKind()), + Sym, Size, 1 << Pow2Alignment); + + return false; +} + +/// ParseDirectiveDarwinSubsectionsViaSymbols +/// ::= .subsections_via_symbols +bool AsmParser::ParseDirectiveDarwinSubsectionsViaSymbols() { + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.subsections_via_symbols' directive"); + + Lex(); + + Out.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + + return false; +} + +/// ParseDirectiveAbort +/// ::= .abort [ "abort_string" ] +bool AsmParser::ParseDirectiveAbort() { + // FIXME: Use loc from directive. + SMLoc Loc = Lexer.getLoc(); + + StringRef Str = ""; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.abort' directive"); + + Str = getTok().getString(); + + Lex(); + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.abort' directive"); + + Lex(); + + // FIXME: Handle here. + if (Str.empty()) + Error(Loc, ".abort detected. Assembly stopping."); + else + Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + + return false; +} + +/// ParseDirectiveLsym +/// ::= .lsym identifier , expression +bool AsmParser::ParseDirectiveDarwinLsym() { + StringRef Name; + if (ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = CreateSymbol(Name); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("unexpected token in '.lsym' directive"); + Lex(); + + const MCExpr *Value; + SMLoc StartLoc = Lexer.getLoc(); + if (ParseExpression(Value)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.lsym' directive"); + + Lex(); + + // We don't currently support this directive. + // + // FIXME: Diagnostic location! + (void) Sym; + return TokError("directive '.lsym' is unsupported"); +} + +/// ParseDirectiveInclude +/// ::= .include "filename" +bool AsmParser::ParseDirectiveInclude() { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.include' directive"); + + std::string Filename = getTok().getString(); + SMLoc IncludeLoc = Lexer.getLoc(); + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.include' directive"); + + // Strip the quotes. + Filename = Filename.substr(1, Filename.size()-2); + + // Attempt to switch the lexer to the included file before consuming the end + // of statement to avoid losing it when we switch. + if (EnterIncludeFile(Filename)) { + PrintMessage(IncludeLoc, + "Could not find include file '" + Filename + "'", + "error"); + return true; + } + + return false; +} + +/// ParseDirectiveDarwinDumpOrLoad +/// ::= ( .dump | .load ) "filename" +bool AsmParser::ParseDirectiveDarwinDumpOrLoad(SMLoc IDLoc, bool IsDump) { + if (Lexer.isNot(AsmToken::String)) + return TokError("expected string in '.dump' or '.load' directive"); + + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.dump' or '.load' directive"); + + Lex(); + + // FIXME: If/when .dump and .load are implemented they will be done in the + // the assembly parser and not have any need for an MCStreamer API. + if (IsDump) + Warning(IDLoc, "ignoring directive .dump for now"); + else + Warning(IDLoc, "ignoring directive .load for now"); + + return false; +} + +/// ParseDirectiveIf +/// ::= .if expression +bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { + // Consume the identifier that was the .if directive + Lex(); + + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + if(TheCondState.Ignore) { + EatToEndOfStatement(); + } + else { + int64_t ExprValue; + if (ParseAbsoluteExpression(ExprValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.if' directive"); + + Lex(); + + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveElseIf +/// ::= .elseif expression +bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { + if (TheCondState.TheCond != AsmCond::IfCond && + TheCondState.TheCond != AsmCond::ElseIfCond) + Error(DirectiveLoc, "Encountered a .elseif that doesn't follow a .if or " + " an .elseif"); + TheCondState.TheCond = AsmCond::ElseIfCond; + + // Consume the identifier that was the .elseif directive + Lex(); + + bool LastIgnoreState = false; + if (!TheCondStack.empty()) + LastIgnoreState = TheCondStack.back().Ignore; + if (LastIgnoreState || TheCondState.CondMet) { + TheCondState.Ignore = true; + EatToEndOfStatement(); + } + else { + int64_t ExprValue; + if (ParseAbsoluteExpression(ExprValue)) + return true; + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.elseif' directive"); + + Lex(); + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveElse +/// ::= .else +bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { + // Consume the identifier that was the .else directive + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.else' directive"); + + Lex(); + + if (TheCondState.TheCond != AsmCond::IfCond && + TheCondState.TheCond != AsmCond::ElseIfCond) + Error(DirectiveLoc, "Encountered a .else that doesn't follow a .if or an " + ".elseif"); + TheCondState.TheCond = AsmCond::ElseCond; + bool LastIgnoreState = false; + if (!TheCondStack.empty()) + LastIgnoreState = TheCondStack.back().Ignore; + if (LastIgnoreState || TheCondState.CondMet) + TheCondState.Ignore = true; + else + TheCondState.Ignore = false; + + return false; +} + +/// ParseDirectiveEndIf +/// ::= .endif +bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { + // Consume the identifier that was the .endif directive + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.endif' directive"); + + Lex(); + + if ((TheCondState.TheCond == AsmCond::NoCond) || + TheCondStack.empty()) + Error(DirectiveLoc, "Encountered a .endif that doesn't follow a .if or " + ".else"); + if (!TheCondStack.empty()) { + TheCondState = TheCondStack.back(); + TheCondStack.pop_back(); + } + + return false; +} + +/// ParseDirectiveFile +/// ::= .file [number] string +bool AsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { + // FIXME: I'm not sure what this is. + int64_t FileNumber = -1; + if (Lexer.is(AsmToken::Integer)) { + FileNumber = getTok().getIntVal(); + Lex(); + + if (FileNumber < 1) + return TokError("file number less than one"); + } + + if (Lexer.isNot(AsmToken::String)) + return TokError("unexpected token in '.file' directive"); + + StringRef ATTRIBUTE_UNUSED FileName = getTok().getString(); + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + // FIXME: Do something with the .file. + + return false; +} + +/// ParseDirectiveLine +/// ::= .line [number] +bool AsmParser::ParseDirectiveLine(StringRef, SMLoc DirectiveLoc) { + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.line' directive"); + + int64_t LineNumber = getTok().getIntVal(); + (void) LineNumber; + Lex(); + + // FIXME: Do something with the .line. + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + return false; +} + + +/// ParseDirectiveLoc +/// ::= .loc number [number [number]] +bool AsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + // FIXME: What are these fields? + int64_t FileNumber = getTok().getIntVal(); + (void) FileNumber; + // FIXME: Validate file. + + Lex(); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + int64_t Param2 = getTok().getIntVal(); + (void) Param2; + Lex(); + + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + + int64_t Param3 = getTok().getIntVal(); + (void) Param3; + Lex(); + + // FIXME: Do something with the .loc. + } + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + return false; +} + diff --git a/lib/MC/MCParser/CMakeLists.txt b/lib/MC/MCParser/CMakeLists.txt new file mode 100644 index 0000000..a5c0818 --- /dev/null +++ b/lib/MC/MCParser/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(LLVMMCParser + AsmLexer.cpp + AsmParser.cpp + MCAsmLexer.cpp + MCAsmParser.cpp + TargetAsmParser.cpp + ) diff --git a/lib/MC/MCAsmLexer.cpp b/lib/MC/MCParser/MCAsmLexer.cpp index 1e34ed6..e5b2955 100644 --- a/lib/MC/MCAsmLexer.cpp +++ b/lib/MC/MCParser/MCAsmLexer.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/Support/SourceMgr.h" using namespace llvm; diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp new file mode 100644 index 0000000..b8c2054 --- /dev/null +++ b/lib/MC/MCParser/MCAsmParser.cpp @@ -0,0 +1,35 @@ +//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/Support/SourceMgr.h" +using namespace llvm; + +MCAsmParser::MCAsmParser() { +} + +MCAsmParser::~MCAsmParser() { +} + +const AsmToken &MCAsmParser::getTok() { + return getLexer().getTok(); +} + +bool MCAsmParser::ParseExpression(const MCExpr *&Res) { + SMLoc L; + return ParseExpression(Res, L); +} + +/// getStartLoc - Get the location of the first token of this operand. +SMLoc MCParsedAsmOperand::getStartLoc() const { return SMLoc(); } +SMLoc MCParsedAsmOperand::getEndLoc() const { return SMLoc(); } + + diff --git a/lib/MC/MCParser/Makefile b/lib/MC/MCParser/Makefile new file mode 100644 index 0000000..e4eb483 --- /dev/null +++ b/lib/MC/MCParser/Makefile @@ -0,0 +1,16 @@ +##===- lib/MC/MCParser/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMMCParser +BUILD_ARCHIVE := 1 +CXXFLAGS = -fno-rtti + +include $(LEVEL)/Makefile.common + diff --git a/lib/MC/TargetAsmParser.cpp b/lib/MC/MCParser/TargetAsmParser.cpp index 05760c9..05760c9 100644 --- a/lib/MC/TargetAsmParser.cpp +++ b/lib/MC/MCParser/TargetAsmParser.cpp diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index 4d520ec..ebfe269 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -22,14 +22,12 @@ Create(StringRef Section, unsigned Type, unsigned Flags, // ShouldOmitSectionDirective - Decides whether a '.section' directive // should be printed before the section name -bool MCSectionELF::ShouldOmitSectionDirective(const char *Name, +bool MCSectionELF::ShouldOmitSectionDirective(StringRef Name, const MCAsmInfo &MAI) const { // FIXME: Does .section .bss/.data/.text work everywhere?? - if (strcmp(Name, ".text") == 0 || - strcmp(Name, ".data") == 0 || - (strcmp(Name, ".bss") == 0 && - !MAI.usesELFSectionDirectiveForBSS())) + if (Name == ".text" || Name == ".data" || + (Name == ".bss" && !MAI.usesELFSectionDirectiveForBSS())) return true; return false; @@ -46,7 +44,7 @@ bool MCSectionELF::ShouldPrintSectionType(unsigned Ty) const { void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { - if (ShouldOmitSectionDirective(SectionName.c_str(), MAI)) { + if (ShouldOmitSectionDirective(SectionName, MAI)) { OS << '\t' << getSectionName() << '\n'; return; } @@ -128,7 +126,7 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, // header index. bool MCSectionELF::HasCommonSymbols() const { - if (strncmp(SectionName.c_str(), ".gnu.linkonce.", 14) == 0) + if (StringRef(SectionName).startswith(".gnu.linkonce.")) return true; return false; diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 8a6dcda..15b3079 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -8,7 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" - +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context), CurSection(0) { @@ -16,3 +17,25 @@ MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context), CurSection(0) { MCStreamer::~MCStreamer() { } + +raw_ostream &MCStreamer::GetCommentOS() { + // By default, discard comments. + return nulls(); +} + + +/// EmitIntValue - Special case of EmitValue that avoids the client having to +/// pass in a MCExpr for constant integers. +void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, + unsigned AddrSpace) { + EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); +} + +/// EmitFill - Emit NumBytes bytes worth of the value specified by +/// FillValue. This implements directives such as '.space'. +void MCStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, + unsigned AddrSpace) { + const MCExpr *E = MCConstantExpr::Create(FillValue, getContext()); + for (uint64_t i = 0, e = NumBytes; i != e; ++i) + EmitValue(E, 1, AddrSpace); +} diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp index 265d06c..3fb1233 100644 --- a/lib/MC/MCSymbol.cpp +++ b/lib/MC/MCSymbol.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -26,24 +25,11 @@ static bool isAcceptableChar(char C) { return true; } -static char HexDigit(int V) { - return V < 10 ? V+'0' : V+'A'-10; -} - -static void MangleLetter(raw_ostream &OS, unsigned char C) { - OS << '_' << HexDigit(C >> 4) << HexDigit(C & 15) << '_'; -} - -/// NameNeedsEscaping - Return true if the identifier \arg Str needs quotes -/// for this assembler. -static bool NameNeedsEscaping(StringRef Str, const MCAsmInfo &MAI) { +/// NameNeedsQuoting - Return true if the identifier \arg Str needs quotes to be +/// syntactically correct. +static bool NameNeedsQuoting(StringRef Str) { assert(!Str.empty() && "Cannot create an empty MCSymbol"); - // If the first character is a number and the target does not allow this, we - // need quotes. - if (!MAI.doesAllowNameToStartWithDigit() && Str[0] >= '0' && Str[0] <= '9') - return true; - // If any of the characters in the string is an unacceptable character, force // quotes. for (unsigned i = 0, e = Str.size(); i != e; ++i) @@ -52,63 +38,18 @@ static bool NameNeedsEscaping(StringRef Str, const MCAsmInfo &MAI) { return false; } -/// printMangledName - Print the specified string in mangled form if it uses -/// any unusual characters. -void MCSymbol::printMangledName(StringRef Str, raw_ostream &OS, - const MCAsmInfo *MAI) { - // The first character is not allowed to be a number unless the target - // explicitly allows it. - if ((MAI == 0 || !MAI->doesAllowNameToStartWithDigit()) && - Str[0] >= '0' && Str[0] <= '9') { - MangleLetter(OS, Str[0]); - Str = Str.substr(1); - } - - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - if (!isAcceptableChar(Str[i])) - MangleLetter(OS, Str[i]); - else - OS << Str[i]; - } -} - -/// PrintMangledQuotedName - On systems that support quoted symbols, we still -/// have to escape some (obscure) characters like " and \n which would break the -/// assembler's lexing. -static void PrintMangledQuotedName(raw_ostream &OS, StringRef Str) { - OS << '"'; - - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - if (Str[i] == '"') - OS << "_QQ_"; - else if (Str[i] == '\n') - OS << "_NL_"; - else - OS << Str[i]; - } - OS << '"'; -} - - -void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const { - if (MAI == 0 || !NameNeedsEscaping(getName(), *MAI)) { +void MCSymbol::print(raw_ostream &OS) const { + // The name for this MCSymbol is required to be a valid target name. However, + // some targets support quoting names with funny characters. If the name + // contains a funny character, then print it quoted. + if (!NameNeedsQuoting(getName())) { OS << getName(); return; } - - // On systems that do not allow quoted names, print with mangling. - if (!MAI->doesAllowQuotesInName()) - return printMangledName(getName(), OS, MAI); - - // If the string contains a double quote or newline, we still have to mangle - // it. - if (getName().find('"') != std::string::npos || - getName().find('\n') != std::string::npos) - return PrintMangledQuotedName(OS, getName()); OS << '"' << getName() << '"'; } void MCSymbol::dump() const { - print(dbgs(), 0); + print(dbgs()); } diff --git a/lib/MC/MCValue.cpp b/lib/MC/MCValue.cpp index c1222ec..043a49d 100644 --- a/lib/MC/MCValue.cpp +++ b/lib/MC/MCValue.cpp @@ -19,12 +19,10 @@ void MCValue::print(raw_ostream &OS, const MCAsmInfo *MAI) const { return; } - getSymA()->print(OS, MAI); + OS << *getSymA(); - if (getSymB()) { - OS << " - "; - getSymB()->print(OS, MAI); - } + if (getSymB()) + OS << " - " << *getSymB(); if (getConstant()) OS << " + " << getConstant(); diff --git a/lib/MC/Makefile b/lib/MC/Makefile index 314a5b1..371776f 100644 --- a/lib/MC/Makefile +++ b/lib/MC/Makefile @@ -10,6 +10,8 @@ LEVEL = ../.. LIBRARYNAME = LLVMMC BUILD_ARCHIVE := 1 +PARALLEL_DIRS := MCParser +CXXFLAGS = -fno-rtti include $(LEVEL)/Makefile.common |