[LLVMdev] Newbie JITter

Evan Cheng
Fri, 09 Nov 2007 08:20:36 -0000

On Nov 7, 2007, at 6:10 PM, Antony Blakey wrote:

> 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.

The default JIt driver, lli, runs everything. Code generation are
almost the same whether you do dynamic compilation or static
compilation (except for relocation-model / code-model used). You can
pick and choose what passes to run if compile time is a concern. You
can use

> 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?

I don't think it's safe to free Module early if you are using lazy
compilation. If that's disabled, I suppose it's safe to delete Module
once all references are resolved and relocated. Chris, can you confirm?

Don't understand your last question.

>
> 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.

I think there is disassembly capability built-in. See JITEmitter.cpp

Evan

>
> 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)
>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev