add .o file writing for inline asm in llc. Here's a silly

demo:

$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
	abc incl    %eax
	^
LLVM ERROR: Error parsing inline asm

Only problem seems to be that the parser finalizes OutStreamer 
at the end of the first inline asm, which isn't what we want.
For example:

$ cat asm.c
int foo(int X) {
 __asm__ ("incl    %0" : "+r" (X));
 return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
	subq	$8, %rsp
	movl	%edi, (%rsp)
	movl	%edi, %eax
	## InlineAsm Start
	incl    %eax
	## InlineAsm End
	movl	%eax, (%rsp)
	movl	%eax, 4(%rsp)
	addq	$8, %rsp
	ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000	subq	$0x08,%rsp
0000000000000004	movl	%edi,(%rsp)
0000000000000007	movl	%edi,%eax
0000000000000009	incl	%eax
$ 

don't stop at inc!

llvm-svn: 100491
This commit is contained in:
Chris Lattner 2010-04-05 23:11:24 +00:00
parent bdc3f34150
commit 8900ef1931
2 changed files with 35 additions and 3 deletions

View File

@ -18,9 +18,16 @@
#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCParser/AsmParser.h"
#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace llvm; using namespace llvm;
@ -28,6 +35,11 @@ using namespace llvm;
void AsmPrinter::EmitInlineAsm(StringRef Str) const { void AsmPrinter::EmitInlineAsm(StringRef Str) const {
assert(!Str.empty() && "Can't emit empty inline asm block"); assert(!Str.empty() && "Can't emit empty inline asm block");
// Remember if the buffer is nul terminated or not so we can avoid a copy.
bool isNullTerminated = Str.back() == 0;
if (isNullTerminated)
Str = Str.substr(0, Str.size()-1);
// If the output streamer is actually a .s file, just emit the blob textually. // If the output streamer is actually a .s file, just emit the blob textually.
// This is useful in case the asm parser doesn't handle something but the // This is useful in case the asm parser doesn't handle something but the
// system assembler does. // system assembler does.
@ -36,7 +48,27 @@ void AsmPrinter::EmitInlineAsm(StringRef Str) const {
return; return;
} }
errs() << "Inline asm not supported by this streamer!\n"; SourceMgr SrcMgr;
MemoryBuffer *Buffer;
if (isNullTerminated)
Buffer = MemoryBuffer::getMemBuffer(Str, "<inline asm>");
else
Buffer = MemoryBuffer::getMemBufferCopy(Str, "<inline asm>");
// Tell SrcMgr about this buffer, it takes ownership of the buffer.
SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
AsmParser Parser(SrcMgr, OutContext, OutStreamer, *MAI);
OwningPtr<TargetAsmParser> TAP(TM.getTarget().createAsmParser(Parser));
if (!TAP)
llvm_report_error("Inline asm not supported by this streamer because"
" we don't have an asm parser for this target\n");
Parser.setTargetParser(*TAP.get());
// Don't implicitly switch to the text section before the asm.
int Res = Parser.Run(/*NoInitialTextSection*/ true);
if (Res)
llvm_report_error("Error parsing inline asm\n");
} }
@ -249,8 +281,7 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const {
} }
} }
} }
OS << "\n"; OS << '\n' << (char)0; // null terminate string.
EmitInlineAsm(OS.str()); EmitInlineAsm(OS.str());
// Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't

View File

@ -214,6 +214,7 @@ int main(int argc, char **argv) {
// Initialize targets first, so that --version shows registered targets. // Initialize targets first, so that --version shows registered targets.
InitializeAllTargets(); InitializeAllTargets();
InitializeAllAsmPrinters(); InitializeAllAsmPrinters();
InitializeAllAsmParsers();
cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");