diff options
-rw-r--r-- | include/llvm/MC/MCStreamer.h | 6 | ||||
-rw-r--r-- | lib/MC/MCAsmStreamer.cpp | 64 | ||||
-rw-r--r-- | lib/Target/X86/AsmParser/X86AsmParser.cpp | 6 | ||||
-rw-r--r-- | test/MC/AsmParser/labels.s | 6 | ||||
-rw-r--r-- | test/MC/AsmParser/x86_instructions.s | 34 | ||||
-rw-r--r-- | test/MC/AsmParser/x86_operands.s | 64 | ||||
-rw-r--r-- | tools/llvm-mc/llvm-mc.cpp | 63 |
7 files changed, 133 insertions, 110 deletions
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 3f37bfe2a8..434288eb18 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -17,6 +17,7 @@ #include "llvm/Support/DataTypes.h" namespace llvm { + class AsmPrinter; class MCContext; class MCValue; class MCInst; @@ -228,7 +229,10 @@ namespace llvm { /// createAsmStreamer - Create a machine code streamer which will print out /// assembly for the native target, suitable for compiling with a native /// assembler. - MCStreamer *createAsmStreamer(MCContext &Ctx, raw_ostream &OS); + /// + /// \arg AP - If given, an AsmPrinter to use for printing instructions. + MCStreamer *createAsmStreamer(MCContext &Ctx, raw_ostream &OS, + AsmPrinter *AP = 0); // FIXME: These two may end up getting rolled into a single // createObjectStreamer interface, which implements the assembler backend, and diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 75390c695a..ac2aabdf8e 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -9,6 +9,7 @@ #include "llvm/MC/MCStreamer.h" +#include "llvm/CodeGen/AsmPrinter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSectionMachO.h" @@ -23,12 +24,14 @@ namespace { class MCAsmStreamer : public MCStreamer { raw_ostream &OS; + + AsmPrinter *Printer; MCSection *CurSection; public: - MCAsmStreamer(MCContext &Context, raw_ostream &_OS) - : MCStreamer(Context), OS(_OS), CurSection(0) {} + MCAsmStreamer(MCContext &Context, raw_ostream &_OS, AsmPrinter *_AsmPrinter) + : MCStreamer(Context), OS(_OS), Printer(_AsmPrinter), CurSection(0) {} ~MCAsmStreamer() {} /// @name MCStreamer Interface @@ -75,50 +78,16 @@ namespace { } -/// NeedsQuoting - Return true if the string \arg Str needs quoting, i.e., it -/// does not match [a-zA-Z_.][a-zA-Z0-9_.]*. -// -// FIXME: This could be more permissive, do we care? -static inline bool NeedsQuoting(const StringRef &Str) { - if (Str.empty()) - return true; - - // Check that first character is in [a-zA-Z_.]. - if (!((Str[0] >= 'a' && Str[0] <= 'z') || - (Str[0] >= 'A' && Str[0] <= 'Z') || - (Str[0] == '_' || Str[0] == '.'))) - return true; - - // Check subsequent characters are in [a-zA-Z0-9_.]. - for (unsigned i = 1, e = Str.size(); i != e; ++i) - if (!((Str[i] >= 'a' && Str[i] <= 'z') || - (Str[i] >= 'A' && Str[i] <= 'Z') || - (Str[i] >= '0' && Str[i] <= '9') || - (Str[i] == '_' || Str[i] == '.'))) - return true; - - return false; -} - /// Allow printing symbols directly to a raw_ostream with proper quoting. static inline raw_ostream &operator<<(raw_ostream &os, const MCSymbol *S) { - if (NeedsQuoting(S->getName())) - return os << '"' << S->getName() << '"'; - return os << S->getName(); + S->print(os); + + return os; } /// Allow printing values directly to a raw_ostream. static inline raw_ostream &operator<<(raw_ostream &os, const MCValue &Value) { - if (Value.getSymA()) { - os << Value.getSymA(); - if (Value.getSymB()) - os << " - " << Value.getSymB(); - if (Value.getConstant()) - os << " + " << Value.getConstant(); - } else { - assert(!Value.getSymB() && "Invalid machine code value!"); - os << Value.getConstant(); - } + Value.print(os); return os; } @@ -300,7 +269,15 @@ static raw_ostream &operator<<(raw_ostream &OS, const MCOperand &Op) { void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { assert(CurSection && "Cannot emit contents before setting section!"); - // FIXME: Implement proper printing. + + // If we have an AsmPrinter, use that to print. + if (Printer) { + Printer->printMCInst(&Inst); + return; + } + + // Otherwise fall back to a structural printing for now. Eventually we should + // always have access to the target specific printer. OS << "MCInst(" << "opcode=" << Inst.getOpcode() << ", " << "operands=["; @@ -316,6 +293,7 @@ void MCAsmStreamer::Finish() { OS.flush(); } -MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS) { - return new MCAsmStreamer(Context, OS); +MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS, + AsmPrinter *AP) { + return new MCAsmStreamer(Context, OS, AP); } diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 4643211867..5232beb9c3 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -422,10 +422,8 @@ bool X86ATTAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { // FIXME: We should give nicer diagnostics about the exact failure. - // FIXME: For now we just treat unrecognized instructions as "warnings". - Warning(Loc, "unrecognized instruction"); - - return false; + Error(Loc, "unrecognized instruction"); + return true; } // Force static initialization. diff --git a/test/MC/AsmParser/labels.s b/test/MC/AsmParser/labels.s index d4c80315a4..c9cb44eaf0 100644 --- a/test/MC/AsmParser/labels.s +++ b/test/MC/AsmParser/labels.s @@ -13,14 +13,14 @@ a: .text foo: -// CHECK: val:"a$b" +// CHECK: addl $24, "a$b"(%eax) addl $24, "a$b"(%eax) -// CHECK: val:"a$b" + 10 +// CHECK: addl $24, "a$b" + 10(%eax) addl $24, ("a$b" + 10)(%eax) // CHECK: "b$c" = 10 "b$c" = 10 -// CHECK: val:10 +// CHECK: addl $10, %eax addl "b$c", %eax diff --git a/test/MC/AsmParser/x86_instructions.s b/test/MC/AsmParser/x86_instructions.s index c5cb80585a..4c5b698d3f 100644 --- a/test/MC/AsmParser/x86_instructions.s +++ b/test/MC/AsmParser/x86_instructions.s @@ -1,58 +1,58 @@ // FIXME: Switch back to FileCheck once we print actual instructions -// RUN: llvm-mc -triple x86_64-unknown-unknown %s > %t +// RUN: llvm-mc -triple x86_64-unknown-unknown %s | FileCheck %s -// RUN: grep {MCInst(opcode=.*, operands=.reg:2, reg:0, reg:2.)} %t +// CHECK: subb %al, %al subb %al, %al -// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:24.)} %t +// CHECK: addl $24, %eax addl $24, %eax -// RUN: grep {MCInst(opcode=.*, operands=.reg:20, imm:1, reg:0, val:10, reg:0, reg:19.)} %t +// CHECK: movl %eax, 10(%ebp) movl %eax, 10(%ebp) -// RUN: grep {MCInst(opcode=.*, operands=.reg:20, imm:1, reg:21, val:10, reg:0, reg:19.)} %t +// CHECK: movl %eax, 10(%ebp,%ebx) movl %eax, 10(%ebp, %ebx) -// RUN: grep {MCInst(opcode=.*, operands=.reg:20, imm:4, reg:21, val:10, reg:0, reg:19.)} %t +// CHECK: movl %eax, 10(%ebp,%ebx,4) movl %eax, 10(%ebp, %ebx, 4) -// RUN: grep {MCInst(opcode=.*, operands=.reg:0, imm:4, reg:21, val:10, reg:0, reg:19.)} %t +// CHECK: movl %eax, 10(,%ebx,4) movl %eax, 10(, %ebx, 4) // FIXME: Check that this matches SUB32ri8 -// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:1.)} %t +// CHECK: subl $1, %eax subl $1, %eax // FIXME: Check that this matches SUB32ri8 -// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:-1.)} %t +// CHECK: subl $-1, %eax subl $-1, %eax // FIXME: Check that this matches SUB32ri -// RUN: grep {MCInst(opcode=.*, operands=.reg:19, reg:0, val:256.)} %t +// CHECK: subl $256, %eax subl $256, %eax // FIXME: Check that this matches XOR64ri8 -// RUN: grep {MCInst(opcode=.*, operands=.reg:80, reg:0, val:1.)} %t +// CHECK: xorq $1, %rax xorq $1, %rax // FIXME: Check that this matches XOR64ri32 -// RUN: grep {MCInst(opcode=.*, operands=.reg:80, reg:0, val:256.)} %t +// CHECK: xorq $256, %rax xorq $256, %rax // FIXME: Check that this matches SUB8rr -// RUN: grep {MCInst(opcode=.*, operands=.reg:5, reg:0, reg:2.)} %t +// CHECK: subb %al, %bl subb %al, %bl // FIXME: Check that this matches SUB16rr -// RUN: grep {MCInst(opcode=.*, operands=.reg:8, reg:0, reg:3.)} %t +// CHECK: subw %ax, %bx subw %ax, %bx // FIXME: Check that this matches SUB32rr -// RUN: grep {MCInst(opcode=.*, operands=.reg:21, reg:0, reg:19.)} %t +// CHECK: subl %eax, %ebx subl %eax, %ebx // FIXME: Check that this matches the correct instruction. -// RUN: grep {MCInst(opcode=.*, operands=.reg:80.)} %t +// CHECK: call *%rax call *%rax // FIXME: Check that this matches the correct instruction. -// RUN: grep {MCInst(opcode=.*, operands=.reg:21, reg:0, reg:19.)} %t +// CHECK: shldl %cl, %eax, %ebx shldl %cl, %eax, %ebx diff --git a/test/MC/AsmParser/x86_operands.s b/test/MC/AsmParser/x86_operands.s index c6f886b950..d6c16808cf 100644 --- a/test/MC/AsmParser/x86_operands.s +++ b/test/MC/AsmParser/x86_operands.s @@ -1,36 +1,58 @@ // FIXME: Actually test that we get the expected results. -// RUN: llvm-mc -triple i386-unknown-unknown %s > %t 2> %t2 +// RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s # Immediates - push $1 - push $(1+2) - push $a - push $1 + 2 +# CHECK: addl $1, %eax + addl $1, %eax +# CHECK: addl $3, %eax + addl $(1+2), %eax +# CHECK: addl $a, %eax + addl $a, %eax +# CHECK: addl $3, %eax + addl $1 + 2, %eax # Disambiguation - push 4+4 - push (4+4) - push (4+4)(%eax) - push 8(%eax) - push (%eax) - push (4+4)(,%eax) + + # FIXME: Add back when we can match this. + #addl $1, 4+4 + # FIXME: Add back when we can match this. + #addl $1, (4+4) +# CHECK: addl $1, 8(%eax) + addl $1, 4+4(%eax) +# CHECK: addl $1, 8(%eax) + addl $1, (4+4)(%eax) +# CHECK: addl $1, 8(%eax) + addl $1, 8(%eax) +# CHECK: addl $1, 0(%eax) + addl $1, (%eax) +# CHECK: addl $1, 8(,%eax) + addl $1, (4+4)(,%eax) # Indirect Memory Operands - push 1(%eax) - push 1(%eax,%ebx) - push 1(%eax,%ebx,) - push 1(%eax,%ebx,4) - push 1(,%ebx) - push 1(,%ebx,) - push 1(,%ebx,4) - push 1(,%ebx,(2+2)) +# CHECK: addl $1, 1(%eax) + addl $1, 1(%eax) +# CHECK: addl $1, 1(%eax,%ebx) + addl $1, 1(%eax,%ebx) +# CHECK: addl $1, 1(%eax,%ebx) + addl $1, 1(%eax,%ebx,) +# CHECK: addl $1, 1(%eax,%ebx,4) + addl $1, 1(%eax,%ebx,4) +# CHECK: addl $1, 1(,%ebx) + addl $1, 1(,%ebx) +# CHECK: addl $1, 1(,%ebx) + addl $1, 1(,%ebx,) +# CHECK: addl $1, 1(,%ebx,4) + addl $1, 1(,%ebx,4) +# CHECK: addl $1, 1(,%ebx,4) + addl $1, 1(,%ebx,(2+2)) # '*' +# CHECK: call a call a - call *a +# CHECK: call *%eax call *%eax - call 4(%eax) # FIXME: Warn or reject. +# CHECK: call *4(%eax) call *4(%eax) diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 465c312737..7c57f35699 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -16,7 +16,9 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/CodeGen/AsmPrinter.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" @@ -145,28 +147,21 @@ static int AsLexInput(const char *ProgName) { return Error; } -static TargetAsmParser *GetTargetAsmParser(const char *ProgName, - MCAsmParser &Parser) { +static const Target *GetTarget(const char *ProgName) { // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); - if (TheTarget == 0) { - errs() << ProgName << ": error: unable to get target for '" << TripleName - << "', see --version and --triple.\n"; - return 0; - } + if (TheTarget) + return TheTarget; - if (TargetAsmParser *TAP = TheTarget->createAsmParser(Parser)) - return TAP; - - errs() << ProgName - << ": error: this target does not support assembly parsing.\n"; + errs() << ProgName << ": error: unable to get target for '" << TripleName + << "', see --version and --triple.\n"; return 0; } -static raw_ostream *GetOutputStream() { +static formatted_raw_ostream *GetOutputStream() { if (OutputFilename == "" || OutputFilename == "-") - return &outs(); + return &fouts(); // Make sure that the Out file gets unlinked from the disk if we get a // SIGINT @@ -183,10 +178,14 @@ static raw_ostream *GetOutputStream() { return 0; } - return Out; + return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM); } static int AssembleInput(const char *ProgName) { + const Target *TheTarget = GetTarget(ProgName); + if (!TheTarget) + return 1; + std::string Error; MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, &Error); if (Buffer == 0) { @@ -208,10 +207,25 @@ static int AssembleInput(const char *ProgName) { SrcMgr.setIncludeDirs(IncludeDirs); MCContext Ctx; - raw_ostream *Out = GetOutputStream(); + formatted_raw_ostream *Out = GetOutputStream(); if (!Out) return 1; - OwningPtr<MCStreamer> Str(createAsmStreamer(Ctx, *Out)); + + // See if we can get an asm printer. + OwningPtr<AsmPrinter> AP(0); + + // FIXME: We shouldn't need to do this (and link in codegen). + OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(TripleName, "")); + const TargetAsmInfo *TAI = 0; + + if (TM) { + TAI = TheTarget->createAsmInfo(TripleName); + assert(TAI && "Unable to create target asm info!"); + + AP.reset(TheTarget->createAsmPrinter(*Out, *TM, TAI, true)); + } + + OwningPtr<MCStreamer> Str(createAsmStreamer(Ctx, *Out, AP.get())); // FIXME: Target hook & command line option for initial section. Str.get()->SwitchSection(MCSectionMachO::Create("__TEXT","__text", @@ -220,13 +234,17 @@ static int AssembleInput(const char *ProgName) { Ctx)); AsmParser Parser(SrcMgr, Ctx, *Str.get()); - OwningPtr<TargetAsmParser> TAP(GetTargetAsmParser(ProgName, Parser)); - if (!TAP) + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + if (!TAP) { + errs() << ProgName + << ": error: this target does not support assembly parsing.\n"; return 1; + } + Parser.setTargetParser(*TAP.get()); int Res = Parser.Run(); - if (Out != &outs()) + if (Out != &fouts()) delete Out; return Res; @@ -239,8 +257,11 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - // Initialize targets and assembly parsers. + // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); + // FIXME: We shouldn't need to initialize the Target(Machine)s. + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); |