#include "llvm/Support/DataTypes.h"
namespace llvm {
+ class AsmPrinter;
class MCContext;
class MCValue;
class MCInst;
/// 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
#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"
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
}
-/// 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;
}
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=[";
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);
}
// 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.
.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
// 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
// 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)
#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"
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
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) {
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",
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;
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");