[llvm-commits] CVS: llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp Emitter.cpp Intercept.cpp JIT.cpp JIT.h VM.cpp VM.h
Chris Lattner
lattner at cs.uiuc.edu
Fri Dec 19 19:47:01 PST 2003
Changes in directory llvm/lib/ExecutionEngine/JIT:
TargetSelect.cpp added (r1.1)
Emitter.cpp updated: 1.36 -> 1.37
Intercept.cpp updated: 1.11 -> 1.12
JIT.cpp updated: 1.27 -> 1.28
JIT.h updated: 1.19 -> 1.20
VM.cpp (r1.17) removed
VM.h (r1.19) removed
---
Log message:
Cleanup the JIT as per PR176. This renames the VM class to JIT, and merges the
VM.cpp and JIT.cpp files into JIT.cpp. This also splits some nasty code out
into TargetSelect.cpp so that people hopefully won't notice it. :)
---
Diffs of the changes: (+217 -107)
Index: llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp
diff -c /dev/null llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp:1.1
*** /dev/null Fri Dec 19 19:46:37 2003
--- llvm/lib/ExecutionEngine/JIT/TargetSelect.cpp Fri Dec 19 19:46:27 2003
***************
*** 0 ****
--- 1,92 ----
+ //===-- TargetSelect.cpp - Target Chooser Code ----------------------------===//
+ //
+ // The LLVM Compiler Infrastructure
+ //
+ // This file was developed by the LLVM research group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // This file contains the hideously gross code that is currently used to select
+ // a particular TargetMachine for the JIT to use. This should obviously be
+ // improved in the future, probably by having the TargetMachines register
+ // themselves with the runtime, and then have them choose themselves if they
+ // match the current machine.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #include "JIT.h"
+ #include "llvm/Module.h"
+ #include "llvm/ModuleProvider.h"
+ #include "llvm/Target/TargetMachine.h"
+ #include "llvm/Target/TargetMachineImpls.h"
+ #include "Support/CommandLine.h"
+ using namespace llvm;
+
+ #if !defined(ENABLE_X86_JIT) && !defined(ENABLE_SPARC_JIT)
+ #define NO_JITS_ENABLED
+ #endif
+
+ namespace {
+ enum ArchName { x86, Sparc };
+
+ #ifndef NO_JITS_ENABLED
+ cl::opt<ArchName>
+ Arch("march", cl::desc("Architecture to JIT to:"), cl::Prefix,
+ cl::values(
+ #ifdef ENABLE_X86_JIT
+ clEnumVal(x86, " IA-32 (Pentium and above)"),
+ #endif
+ #ifdef ENABLE_SPARC_JIT
+ clEnumValN(Sparc, "sparc", " Sparc-V9"),
+ #endif
+ 0),
+ #if defined(ENABLE_X86_JIT)
+ cl::init(x86)
+ #elif defined(ENABLE_SPARC_JIT)
+ cl::init(Sparc)
+ #endif
+ );
+ #endif /* NO_JITS_ENABLED */
+ }
+
+ /// create - Create an return a new JIT compiler if there is one available
+ /// for the current target. Otherwise, return null.
+ ///
+ ExecutionEngine *JIT::create(ModuleProvider *MP) {
+ TargetMachine* (*TargetMachineAllocator)(const Module &) = 0;
+
+ // Allow a command-line switch to override what *should* be the default target
+ // machine for this platform. This allows for debugging a Sparc JIT on X86 --
+ // our X86 machines are much faster at recompiling LLVM and linking LLI.
+ #ifndef NO_JITS_ENABLED
+
+ switch (Arch) {
+ #ifdef ENABLE_X86_JIT
+ case x86:
+ TargetMachineAllocator = allocateX86TargetMachine;
+ break;
+ #endif
+ #ifdef ENABLE_SPARC_JIT
+ case Sparc:
+ TargetMachineAllocator = allocateSparcTargetMachine;
+ break;
+ #endif
+ default:
+ assert(0 && "-march flag not supported on this host!");
+ }
+ #else
+ return 0;
+ #endif
+
+ // Allocate a target...
+ TargetMachine *Target = TargetMachineAllocator(*MP->getModule());
+ assert(Target && "Could not allocate target machine!");
+
+ // If the target supports JIT code generation, return a new JIT now.
+ if (TargetJITInfo *TJ = Target->getJITInfo())
+ return new JIT(MP, *Target, *TJ);
+ return 0;
+ }
+
+
Index: llvm/lib/ExecutionEngine/JIT/Emitter.cpp
diff -u llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.36 llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.37
--- llvm/lib/ExecutionEngine/JIT/Emitter.cpp:1.36 Mon Dec 8 02:06:28 2003
+++ llvm/lib/ExecutionEngine/JIT/Emitter.cpp Fri Dec 19 19:46:27 2003
@@ -16,7 +16,7 @@
#ifndef _POSIX_MAPPED_FILES
#define _POSIX_MAPPED_FILES
#endif
-#include "VM.h"
+#include "JIT.h"
#include "llvm/Constant.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
@@ -31,7 +31,7 @@
namespace {
Statistic<> NumBytes("jit", "Number of bytes of machine code compiled");
- VM *TheVM = 0;
+ JIT *TheJIT = 0;
/// JITMemoryManager - Manage memory for the JIT code generation in a logical,
/// sane way. This splits a large block of MAP_NORESERVE'd memory into two
@@ -142,7 +142,7 @@
// constant pool.
std::vector<void*> ConstantPoolAddresses;
public:
- Emitter(VM &vm) { TheVM = &vm; }
+ Emitter(JIT &jit) { TheJIT = &jit; }
virtual void startFunction(MachineFunction &F);
virtual void finishFunction(MachineFunction &F);
@@ -166,13 +166,13 @@
};
}
-MachineCodeEmitter *VM::createEmitter(VM &V) {
- return new Emitter(V);
+MachineCodeEmitter *JIT::createEmitter(JIT &jit) {
+ return new Emitter(jit);
}
void Emitter::startFunction(MachineFunction &F) {
CurByte = CurBlock = MemMgr.startFunctionBody();
- TheVM->addGlobalMapping(F.getFunction(), CurBlock);
+ TheJIT->addGlobalMapping(F.getFunction(), CurBlock);
}
void Emitter::finishFunction(MachineFunction &F) {
@@ -197,8 +197,8 @@
unsigned TotalSize = 0;
for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
const Type *Ty = Constants[i]->getType();
- unsigned Size = TheVM->getTargetData().getTypeSize(Ty);
- unsigned Alignment = TheVM->getTargetData().getTypeAlignment(Ty);
+ unsigned Size = TheJIT->getTargetData().getTypeSize(Ty);
+ unsigned Alignment = TheJIT->getTargetData().getTypeAlignment(Ty);
// Make sure to take into account the alignment requirements of the type.
TotalSize = (TotalSize + Alignment-1) & ~(Alignment-1);
@@ -213,7 +213,7 @@
// Actually output all of the constants, and remember their addresses.
for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
void *Addr = Pool + ConstantOffset[i];
- TheVM->InitializeMemory(Constants[i], Addr);
+ TheJIT->InitializeMemory(Constants[i], Addr);
ConstantPoolAddresses.push_back(Addr);
}
}
@@ -248,10 +248,10 @@
uint64_t Emitter::getGlobalValueAddress(GlobalValue *V) {
// Try looking up the function to see if it is already compiled, if not return
// 0.
- return (intptr_t)TheVM->getPointerToGlobalIfAvailable(V);
+ return (intptr_t)TheJIT->getPointerToGlobalIfAvailable(V);
}
uint64_t Emitter::getGlobalValueAddress(const std::string &Name) {
- return (intptr_t)TheVM->getPointerToNamedFunction(Name);
+ return (intptr_t)TheJIT->getPointerToNamedFunction(Name);
}
// getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry
@@ -272,19 +272,19 @@
}
uint64_t Emitter::forceCompilationOf(Function *F) {
- return (intptr_t)TheVM->getPointerToFunction(F);
+ return (intptr_t)TheJIT->getPointerToFunction(F);
}
// getPointerToNamedFunction - This function is used as a global wrapper to
-// VM::getPointerToNamedFunction for the purpose of resolving symbols when
+// JIT::getPointerToNamedFunction for the purpose of resolving symbols when
// bugpoint is debugging the JIT. In that scenario, we are loading an .so and
// need to resolve function(s) that are being mis-codegenerated, so we need to
// resolve their addresses at runtime, and this is the way to do it.
extern "C" {
void *getPointerToNamedFunction(const char *Name) {
- Module &M = TheVM->getModule();
+ Module &M = TheJIT->getModule();
if (Function *F = M.getNamedFunction(Name))
- return TheVM->getPointerToFunction(F);
- return TheVM->getPointerToNamedFunction(Name);
+ return TheJIT->getPointerToFunction(F);
+ return TheJIT->getPointerToNamedFunction(Name);
}
}
Index: llvm/lib/ExecutionEngine/JIT/Intercept.cpp
diff -u llvm/lib/ExecutionEngine/JIT/Intercept.cpp:1.11 llvm/lib/ExecutionEngine/JIT/Intercept.cpp:1.12
--- llvm/lib/ExecutionEngine/JIT/Intercept.cpp:1.11 Mon Dec 8 02:06:28 2003
+++ llvm/lib/ExecutionEngine/JIT/Intercept.cpp Fri Dec 19 19:46:27 2003
@@ -15,7 +15,7 @@
//
//===----------------------------------------------------------------------===//
-#include "VM.h"
+#include "JIT.h"
#include "Support/DynamicLinker.h"
#include <iostream>
using namespace llvm;
@@ -28,7 +28,7 @@
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
-void VM::runAtExitHandlers() {
+void JIT::runAtExitHandlers() {
while (!AtExitHandlers.empty()) {
void (*Fn)() = AtExitHandlers.back();
AtExitHandlers.pop_back();
@@ -45,7 +45,7 @@
// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
- VM::runAtExitHandlers(); // Run atexit handlers...
+ JIT::runAtExitHandlers(); // Run atexit handlers...
exit(Status);
}
@@ -61,7 +61,7 @@
/// function by using the dynamic loader interface. As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
-void *VM::getPointerToNamedFunction(const std::string &Name) {
+void *JIT::getPointerToNamedFunction(const std::string &Name) {
// Check to see if this is one of the functions we want to intercept...
if (Name == "exit") return (void*)&jit_exit;
if (Name == "atexit") return (void*)&jit_atexit;
Index: llvm/lib/ExecutionEngine/JIT/JIT.cpp
diff -u llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.27 llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.28
--- llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.27 Fri Dec 19 19:22:19 2003
+++ llvm/lib/ExecutionEngine/JIT/JIT.cpp Fri Dec 19 19:46:27 2003
@@ -1,4 +1,4 @@
-//===-- JIT.cpp - LLVM Just-In-Time Compiler ------------------------------===//
+//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,102 +7,50 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the top-level support for creating a Just-In-Time
-// compiler for the current architecture.
+// This tool implements a just-in-time compiler for LLVM, allowing direct
+// execution of LLVM bytecode in an efficient manner.
//
//===----------------------------------------------------------------------===//
-#include "VM.h"
-#include "llvm/Module.h"
+#include "JIT.h"
+#include "llvm/Function.h"
#include "llvm/ModuleProvider.h"
+#include "llvm/CodeGen/MachineCodeEmitter.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetMachineImpls.h"
-#include "Support/CommandLine.h"
+#include "llvm/Target/TargetJITInfo.h"
using namespace llvm;
-#if !defined(ENABLE_X86_JIT) && !defined(ENABLE_SPARC_JIT)
-#define NO_JITS_ENABLED
-#endif
-
-namespace {
- enum ArchName { x86, Sparc };
-
-#ifndef NO_JITS_ENABLED
- cl::opt<ArchName>
- Arch("march", cl::desc("Architecture to JIT to:"), cl::Prefix,
- cl::values(
-#ifdef ENABLE_X86_JIT
- clEnumVal(x86, " IA-32 (Pentium and above)"),
-#endif
-#ifdef ENABLE_SPARC_JIT
- clEnumValN(Sparc, "sparc", " Sparc-V9"),
-#endif
- 0),
-#if defined(ENABLE_X86_JIT)
- cl::init(x86)
-#elif defined(ENABLE_SPARC_JIT)
- cl::init(Sparc)
-#endif
- );
-#endif /* NO_JITS_ENABLED */
-}
-
-/// create - Create an return a new JIT compiler if there is one available
-/// for the current target. Otherwise, return null.
-///
-ExecutionEngine *VM::create(ModuleProvider *MP) {
- TargetMachine* (*TargetMachineAllocator)(const Module &) = 0;
-
- // Allow a command-line switch to override what *should* be the default target
- // machine for this platform. This allows for debugging a Sparc JIT on X86 --
- // our X86 machines are much faster at recompiling LLVM and linking LLI.
-#ifndef NO_JITS_ENABLED
-
- switch (Arch) {
-#ifdef ENABLE_X86_JIT
- case x86:
- TargetMachineAllocator = allocateX86TargetMachine;
- break;
-#endif
-#ifdef ENABLE_SPARC_JIT
- case Sparc:
- TargetMachineAllocator = allocateSparcTargetMachine;
- break;
-#endif
- default:
- assert(0 && "-march flag not supported on this host!");
- }
-#else
- return 0;
-#endif
-
- // Allocate a target...
- TargetMachine *Target = TargetMachineAllocator(*MP->getModule());
- assert(Target && "Could not allocate target machine!");
-
- // If the target supports JIT code generation, return a new JIT now.
- if (TargetJITInfo *TJ = Target->getJITInfo())
- return new VM(MP, *Target, *TJ);
- return 0;
-}
-
-VM::VM(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
+JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
: ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
setTargetData(TM.getTargetData());
// Initialize MCE
MCE = createEmitter(*this);
- setupPassManager();
+ // Compile LLVM Code down to machine code in the intermediate representation
+ TJI.addPassesToJITCompile(PM);
+
+ // Turn the machine code intermediate representation into bytes in memory that
+ // may be executed.
+ if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
+ std::cerr << "lli: target '" << TM.getName()
+ << "' doesn't support machine code emission!\n";
+ abort();
+ }
emitGlobals();
}
+JIT::~JIT() {
+ delete MCE;
+ delete &TM;
+}
+
/// run - Start execution with the specified function and arguments.
///
-GenericValue VM::run(Function *F, const std::vector<GenericValue> &ArgValues)
-{
+GenericValue JIT::run(Function *F, const std::vector<GenericValue> &ArgValues) {
assert (F && "Function *F was null at entry to run()");
int (*PF)(int, char **, const char **) =
@@ -119,4 +67,75 @@
GenericValue rv;
rv.IntVal = ExitCode;
return rv;
+}
+
+/// runJITOnFunction - Run the FunctionPassManager full of
+/// just-in-time compilation passes on F, hopefully filling in
+/// GlobalAddress[F] with the address of F's machine code.
+///
+void JIT::runJITOnFunction(Function *F) {
+ static bool isAlreadyCodeGenerating = false;
+ assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
+
+ // JIT the function
+ isAlreadyCodeGenerating = true;
+ PM.run(*F);
+ isAlreadyCodeGenerating = false;
+}
+
+/// getPointerToFunction - This method is used to get the address of the
+/// specified function, compiling it if neccesary.
+///
+void *JIT::getPointerToFunction(Function *F) {
+ void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
+ if (Addr) return Addr;
+
+ // Make sure we read in the function if it exists in this Module
+ MP->materializeFunction(F);
+
+ if (F->isExternal())
+ return Addr = getPointerToNamedFunction(F->getName());
+
+ runJITOnFunction(F);
+ assert(Addr && "Code generation didn't add function to GlobalAddress table!");
+ return Addr;
+}
+
+// getPointerToFunctionOrStub - If the specified function has been
+// code-gen'd, return a pointer to the function. If not, compile it, or use
+// a stub to implement lazy compilation if available.
+//
+void *JIT::getPointerToFunctionOrStub(Function *F) {
+ // If we have already code generated the function, just return the address.
+ std::map<const GlobalValue*, void *>::iterator I = GlobalAddress.find(F);
+ if (I != GlobalAddress.end()) return I->second;
+
+ // If the target supports "stubs" for functions, get a stub now.
+ if (void *Ptr = TJI.getJITStubForFunction(F, *MCE))
+ return Ptr;
+
+ // Otherwise, if the target doesn't support it, just codegen the function.
+ return getPointerToFunction(F);
+}
+
+/// recompileAndRelinkFunction - This method is used to force a function
+/// which has already been compiled, to be compiled again, possibly
+/// after it has been modified. Then the entry to the old copy is overwritten
+/// with a branch to the new copy. If there was no old copy, this acts
+/// just like JIT::getPointerToFunction().
+///
+void *JIT::recompileAndRelinkFunction(Function *F) {
+ void *&Addr = GlobalAddress[F]; // Check if function already code gen'd
+
+ // If it's not already compiled (this is kind of weird) there is no
+ // reason to patch it up.
+ if (!Addr) { return getPointerToFunction (F); }
+
+ void *OldAddr = Addr;
+ Addr = 0;
+ MachineFunction::destruct(F);
+ runJITOnFunction(F);
+ assert(Addr && "Code generation didn't add function to GlobalAddress table!");
+ TJI.replaceMachineCodeForFunction(OldAddr, Addr);
+ return Addr;
}
Index: llvm/lib/ExecutionEngine/JIT/JIT.h
diff -u llvm/lib/ExecutionEngine/JIT/JIT.h:1.19 llvm/lib/ExecutionEngine/JIT/JIT.h:1.20
--- llvm/lib/ExecutionEngine/JIT/JIT.h:1.19 Fri Dec 19 19:22:19 2003
+++ llvm/lib/ExecutionEngine/JIT/JIT.h Fri Dec 19 19:46:27 2003
@@ -1,4 +1,4 @@
-//===-- VM.h - Definitions for Virtual Machine ------------------*- C++ -*-===//
+//===-- JIT.h - Class definition for the JIT --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the top-level Virtual Machine data structure.
+// This file defines the top-level JIT data structure.
//
//===----------------------------------------------------------------------===//
-#ifndef VM_H
-#define VM_H
+#ifndef JIT_H
+#define JIT_H
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
@@ -27,16 +27,16 @@
class TargetJITInfo;
class MachineCodeEmitter;
-class VM : public ExecutionEngine {
+class JIT : public ExecutionEngine {
TargetMachine &TM; // The current target we are compiling to
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
FunctionPassManager PM; // Passes to compile a function
MachineCodeEmitter *MCE; // MCE object
- VM(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
+ JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
public:
- ~VM();
+ ~JIT();
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
@@ -79,13 +79,12 @@
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
- /// just like VM::getPointerToFunction().
+ /// just like JIT::getPointerToFunction().
///
void *recompileAndRelinkFunction(Function *F);
private:
- static MachineCodeEmitter *createEmitter(VM &V);
- void setupPassManager();
+ static MachineCodeEmitter *createEmitter(JIT &J);
void runJITOnFunction (Function *F);
};
More information about the llvm-commits
mailing list