mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 00:11:00 +00:00
Update llvm-mc / MCAsmStreamer to print the instruction using the actual target
specific printer (this only works on x86, for now). - This makes it possible to do some correctness checking of the parsing and matching, since we can compare the results of 'as' on the original input, to those of 'as' on the output from llvm-mc. - In theory, we could now have an easy ATT -> Intel syntax converter. :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78986 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
575327b77e
commit
c22e0b2443
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user