[LLVMdev] Newbie JITter

Antony Blakey antony.blakey at gmail.com
Wed Nov 7 18:10:10 PST 2007


Hi,
    I'm experimenting with using LLVM to generate dynamic FFI bridges  
in VisualWorks Smalltalk. LLVM is an amazing thing! I'm going from  
dynamically generated assembler source to machine code, and I have  
that all working, copied from the llc tool and the JIT example. I  
have two questions:

1. What optimization passes, if any, should I run on the module  
before I pass it to the ExecutionEngine.
2. Do I need to retain the Module/ExistingModuleProvider, once I've  
built the ExecutionEngine and have a Function object. Or is there  
some simpler way to store/call the native code block?

An unrelated question: I want to dump the native assembler form of  
the code generated by the JIT. Currently I dump it using some code I  
adapted from llc, but that's not actually showing what the JIT is  
generating. How can I dump the JIT generated code, as native  
assembler? It's a debugging requirement only.

My test code is as follows, much of which is to do with generating  
the native assembler output.

#include "llvm/Module.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/System/Signals.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include <iostream>
using namespace llvm;

int main() {
	sys::PrintStackTraceOnErrorSignal();
	
	const char* assembler =
"@.LC0 = internal constant [19 x i8] c\"cooking with gas!\\0A\\00 
\"     ; [11 x i8]*\n"
"\n"
"declare i32 @puts(i8 *)                                          ;  
i32(i8 *)* \n"
"\n"
"define i32 @main() {                                             ;  
i32()* \n"
"        ; Convert [19 x i8 ]* to i8 *...\n"
"        %cast210 = getelementptr [19 x i8]* @.LC0, i64 0, i64 0 ; i8  
*\n"
"        call i32 @puts(i8 * %cast210)                            ;  
i32\n"
"        ret i32 0\n"
"};\n";
	
	int exitCode = 0;
	try {
		ParseError ParseErr;
		Module* M = ParseAssemblyString(assembler, new Module("test"),  
&ParseErr);
		if (!M) {
			cerr << "parse error: " << ParseErr.getMessage() << "\n";
			return 1;
		}
		
		std::cout << "\nWe just constructed this LLVM module:\n\n" << *M;
		
		std::string MArchErr;
		const TargetMachineRegistry::entry* MArch =  
TargetMachineRegistry::getClosestStaticTargetForModule(*M, MArchErr);
		if (MArch == 0) {
			std::cerr << "error auto-selecting target for module '" <<  
MArchErr << "'.\n";
			return 1;
		}
		
		TargetMachine* target = MArch->CtorFn(*M, "");
		assert(target && "Could not allocate target machine!");
		
		FunctionPassManager Passes(new ExistingModuleProvider(M));
		Passes.add(new TargetData(*target->getTargetData()));
		
		Passes.add(createVerifierPass());
		
		switch (target->addPassesToEmitFile(Passes, std::cout,  
TargetMachine::AssemblyFile, false)) {
			default:
				assert(0 && "Invalid file model!");
				return 1;
			case FileModel::MachOFile:
			case FileModel::ElfFile:
			case FileModel::Error:
				std::cerr << "target does not support generation of this file  
type!\n";
				return 1;
			case FileModel::AsmFile:
				break;
		}
		
		MachineCodeEmitter *MCE = 0;
		if (target->addPassesToEmitFileFinish(Passes, MCE, false)) {
			std::cerr << "target does not support generation of this file type! 
\n";
			return 1;
		}
		
		std::cout << "\nWhich has this machine code form:";
		
		Passes.doInitialization();
		
		for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
			if (!I->isDeclaration())
				Passes.run(*I);
		
		Passes.doFinalization();
		
		ExistingModuleProvider* MP = new ExistingModuleProvider(M);
		ExecutionEngine* EE = ExecutionEngine::create(MP, false);
		
		Function *MainFunction = M->getFunction("main");
		if (!MainFunction) {
			std::cerr << "'main' function not found in module.\n";
			return -1;
		}
		
		std::cout << "\n\nRunning main: " << std::flush;
		
		// Call the function with no arguments:
		std::vector<GenericValue> noargs;
		GenericValue gv = EE->runFunction(MainFunction, noargs);
		
		// Import result of execution:
		std::cout << "Result: " << gv.IntVal.toStringUnsigned(10) << "\n";
		
	} catch (const std::string& msg) {
		cerr << "exception: " << msg << "\n";
		exitCode = 1;
	} catch (...) {
		cerr << "exception: Unexpected unknown exception occurred.\n";
		exitCode = 1;
	}
	
	return exitCode;
}

Thanks,

Antony Blakey
--------------------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

Plurality is not to be assumed without necessity
   -- William of Ockham (ca. 1285-1349)





More information about the llvm-dev mailing list