[llvm-commits] CVS: llvm/lib/ExecutionEngine/JIT/JIT.cpp JIT.h JITEmitter.cpp
Reid Spencer
reid at x10sys.com
Tue Jul 12 08:52:08 PDT 2005
Changes in directory llvm/lib/ExecutionEngine/JIT:
JIT.cpp updated: 1.55 -> 1.56
JIT.h updated: 1.26 -> 1.27
JITEmitter.cpp updated: 1.67 -> 1.68
---
Log message:
For PR540: http://llvm.cs.uiuc.edu/PR540 :
This patch completes the changes for making lli thread-safe. Here's the list
of changes:
* The Support/ThreadSupport* files were removed and replaced with the
MutexGuard.h file since all ThreadSupport* declared was a Mutex Guard.
The implementation of MutexGuard.h is now based on sys::Mutex which hides
its implementation and makes it unnecessary to have the -NoSupport.h and
-PThreads.h versions of ThreadSupport.
* All places in ExecutionEngine that previously referred to "Mutex" now
refer to sys::Mutex
* All places in ExecutionEngine that previously referred to "MutexLocker"
now refer to MutexGuard (this is frivolous but I believe the technically
correct name for such a class is "Guard" not a "Locker").
These changes passed all of llvm-test. All we need now are some test cases
that actually use multiple threads.
---
Diffs of the changes: (+76 -27)
JIT.cpp | 20 ++++++++++++++------
JIT.h | 27 ++++++++++++++++++++++-----
JITEmitter.cpp | 56 ++++++++++++++++++++++++++++++++++++++++----------------
3 files changed, 76 insertions(+), 27 deletions(-)
Index: llvm/lib/ExecutionEngine/JIT/JIT.cpp
diff -u llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.55 llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.56
--- llvm/lib/ExecutionEngine/JIT/JIT.cpp:1.55 Fri May 6 01:48:54 2005
+++ llvm/lib/ExecutionEngine/JIT/JIT.cpp Tue Jul 12 10:51:55 2005
@@ -30,13 +30,15 @@
using namespace llvm;
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
- : ExecutionEngine(MP), TM(tm), TJI(tji), PM(MP) {
+ : ExecutionEngine(MP), TM(tm), TJI(tji), state(MP) {
setTargetData(TM.getTargetData());
// Initialize MCE
MCE = createEmitter(*this);
// Add target data
+ MutexGuard locked(lock);
+ FunctionPassManager& PM = state.getPM(locked);
PM.add(new TargetData(TM.getTargetData()));
// Compile LLVM Code down to machine code in the intermediate representation
@@ -216,18 +218,20 @@
void JIT::runJITOnFunction(Function *F) {
static bool isAlreadyCodeGenerating = false;
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
+
+ MutexGuard locked(lock);
// JIT the function
isAlreadyCodeGenerating = true;
- PM.run(*F);
+ state.getPM(locked).run(*F);
isAlreadyCodeGenerating = false;
// If the function referred to a global variable that had not yet been
// emitted, it allocates memory for the global, but doesn't emit it yet. Emit
// all of these globals now.
- while (!PendingGlobals.empty()) {
- const GlobalVariable *GV = PendingGlobals.back();
- PendingGlobals.pop_back();
+ while (!state.getPendingGlobals(locked).empty()) {
+ const GlobalVariable *GV = state.getPendingGlobals(locked).back();
+ state.getPendingGlobals(locked).pop_back();
EmitGlobalVariable(GV);
}
}
@@ -236,6 +240,8 @@
/// specified function, compiling it if neccesary.
///
void *JIT::getPointerToFunction(Function *F) {
+ MutexGuard locked(lock);
+
if (void *Addr = getPointerToGlobalIfAvailable(F))
return Addr; // Check if function already code gen'd
@@ -270,6 +276,8 @@
/// variable, possibly emitting it to memory if needed. This is used by the
/// Emitter.
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
+ MutexGuard locked(lock);
+
void *Ptr = getPointerToGlobalIfAvailable(GV);
if (Ptr) return Ptr;
@@ -287,7 +295,7 @@
// compilation.
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
Ptr = new char[(size_t)S];
- PendingGlobals.push_back(GV);
+ state.getPendingGlobals(locked).push_back(GV);
}
addGlobalMapping(GV, Ptr);
return Ptr;
Index: llvm/lib/ExecutionEngine/JIT/JIT.h
diff -u llvm/lib/ExecutionEngine/JIT/JIT.h:1.26 llvm/lib/ExecutionEngine/JIT/JIT.h:1.27
--- llvm/lib/ExecutionEngine/JIT/JIT.h:1.26 Thu Apr 21 17:45:04 2005
+++ llvm/lib/ExecutionEngine/JIT/JIT.h Tue Jul 12 10:51:55 2005
@@ -27,18 +27,35 @@
class TargetJITInfo;
class MachineCodeEmitter;
-class JIT : public ExecutionEngine {
- TargetMachine &TM; // The current target we are compiling to
- TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
-
+class JITState {
+private:
FunctionPassManager PM; // Passes to compile a function
- MachineCodeEmitter *MCE; // MCE object
/// PendingGlobals - Global variables which have had memory allocated for them
/// while a function was code generated, but which have not been initialized
/// yet.
std::vector<const GlobalVariable*> PendingGlobals;
+public:
+ JITState(ModuleProvider *MP) : PM(MP) {}
+
+ FunctionPassManager& getPM(const MutexGuard& locked) {
+ return PM;
+ }
+
+ std::vector<const GlobalVariable*>& getPendingGlobals(const MutexGuard& locked) {
+ return PendingGlobals;
+ }
+};
+
+
+class JIT : public ExecutionEngine {
+ TargetMachine &TM; // The current target we are compiling to
+ TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
+ MachineCodeEmitter *MCE; // MCE object
+
+ JITState state;
+
JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
public:
~JIT();
Index: llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp
diff -u llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp:1.67 llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp:1.68
--- llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp:1.67 Thu Apr 21 23:06:43 2005
+++ llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp Tue Jul 12 10:51:55 2005
@@ -120,6 +120,28 @@
// JIT lazy compilation code.
//
namespace {
+ class JITResolverState {
+ private:
+ /// FunctionToStubMap - Keep track of the stub created for a particular
+ /// function so that we can reuse them if necessary.
+ std::map<Function*, void*> FunctionToStubMap;
+
+ /// StubToFunctionMap - Keep track of the function that each stub
+ /// corresponds to.
+ std::map<void*, Function*> StubToFunctionMap;
+
+ public:
+ std::map<Function*, void*>& getFunctionToStubMap(const MutexGuard& locked) {
+ assert(locked.holds(TheJIT->lock));
+ return FunctionToStubMap;
+ }
+
+ std::map<void*, Function*>& getStubToFunctionMap(const MutexGuard& locked) {
+ assert(locked.holds(TheJIT->lock));
+ return StubToFunctionMap;
+ }
+ };
+
/// JITResolver - Keep track of, and resolve, call sites for functions that
/// have not yet been compiled.
class JITResolver {
@@ -130,13 +152,7 @@
/// rewrite instructions to use.
TargetJITInfo::LazyResolverFn LazyResolverFn;
- // FunctionToStubMap - Keep track of the stub created for a particular
- // function so that we can reuse them if necessary.
- std::map<Function*, void*> FunctionToStubMap;
-
- // StubToFunctionMap - Keep track of the function that each stub corresponds
- // to.
- std::map<void*, Function*> StubToFunctionMap;
+ JITResolverState state;
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
/// external functions.
@@ -159,8 +175,9 @@
/// instruction without the use of a stub, record the location of the use so
/// we know which function is being used at the location.
void *AddCallbackAtLocation(Function *F, void *Location) {
+ MutexGuard locked(TheJIT->lock);
/// Get the target-specific JIT resolver function.
- StubToFunctionMap[Location] = F;
+ state.getStubToFunctionMap(locked)[Location] = F;
return (void*)LazyResolverFn;
}
@@ -181,8 +198,10 @@
/// getFunctionStub - This returns a pointer to a function stub, creating
/// one on demand as needed.
void *JITResolver::getFunctionStub(Function *F) {
+ MutexGuard locked(TheJIT->lock);
+
// If we already have a stub for this function, recycle it.
- void *&Stub = FunctionToStubMap[F];
+ void *&Stub = state.getFunctionToStubMap(locked)[F];
if (Stub) return Stub;
// Call the lazy resolver function unless we already KNOW it is an external
@@ -207,7 +226,7 @@
// Finally, keep track of the stub-to-Function mapping so that the
// JITCompilerFn knows which function to compile!
- StubToFunctionMap[Stub] = F;
+ state.getStubToFunctionMap(locked)[Stub] = F;
return Stub;
}
@@ -231,16 +250,21 @@
void *JITResolver::JITCompilerFn(void *Stub) {
JITResolver &JR = getJITResolver();
+ MutexGuard locked(TheJIT->lock);
+
// The address given to us for the stub may not be exactly right, it might be
// a little bit after the stub. As such, use upper_bound to find it.
std::map<void*, Function*>::iterator I =
- JR.StubToFunctionMap.upper_bound(Stub);
- assert(I != JR.StubToFunctionMap.begin() && "This is not a known stub!");
+ JR.state.getStubToFunctionMap(locked).upper_bound(Stub);
+ assert(I != JR.state.getStubToFunctionMap(locked).begin() && "This is not a known stub!");
Function *F = (--I)->second;
- // The target function will rewrite the stub so that the compilation callback
- // function is no longer called from this stub.
- JR.StubToFunctionMap.erase(I);
+ // We might like to remove the stub from the StubToFunction map.
+ // We can't do that! Multiple threads could be stuck, waiting to acquire the
+ // lock above. As soon as the 1st function finishes compiling the function,
+ // the next one will be released, and needs to be able to find the function it needs
+ // to call.
+ //JR.state.getStubToFunctionMap(locked).erase(I);
DEBUG(std::cerr << "JIT: Lazily resolving function '" << F->getName()
<< "' In stub ptr = " << Stub << " actual ptr = "
@@ -249,7 +273,7 @@
void *Result = TheJIT->getPointerToFunction(F);
// We don't need to reuse this stub in the future, as F is now compiled.
- JR.FunctionToStubMap.erase(F);
+ JR.state.getFunctionToStubMap(locked).erase(F);
// FIXME: We could rewrite all references to this stub if we knew them.
return Result;
More information about the llvm-commits
mailing list