summaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r--lib/ExecutionEngine/ExecutionEngine.cpp321
-rw-r--r--lib/ExecutionEngine/ExecutionEngineBindings.cpp25
-rw-r--r--lib/ExecutionEngine/Interpreter/Execution.cpp188
-rw-r--r--lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp108
-rw-r--r--lib/ExecutionEngine/Interpreter/Interpreter.cpp4
-rw-r--r--lib/ExecutionEngine/Interpreter/Interpreter.h18
-rw-r--r--lib/ExecutionEngine/JIT/CMakeLists.txt2
-rw-r--r--lib/ExecutionEngine/JIT/Intercept.cpp11
-rw-r--r--lib/ExecutionEngine/JIT/JIT.cpp172
-rw-r--r--lib/ExecutionEngine/JIT/JIT.h47
-rw-r--r--lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp208
-rw-r--r--lib/ExecutionEngine/JIT/JITDebugRegisterer.h116
-rw-r--r--lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp182
-rw-r--r--lib/ExecutionEngine/JIT/JITDwarfEmitter.h4
-rw-r--r--lib/ExecutionEngine/JIT/JITEmitter.cpp292
-rw-r--r--lib/ExecutionEngine/JIT/JITMemoryManager.cpp387
-rw-r--r--lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp5
-rw-r--r--lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp178
-rw-r--r--lib/ExecutionEngine/JIT/TargetSelect.cpp85
19 files changed, 1658 insertions, 695 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp
index a80513f..053d960 100644
--- a/lib/ExecutionEngine/ExecutionEngine.cpp
+++ b/lib/ExecutionEngine/ExecutionEngine.cpp
@@ -13,16 +13,19 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "jit"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Config/alloca.h"
-#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/ValueHandle.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/System/Host.h"
#include "llvm/Target/TargetData.h"
@@ -33,12 +36,19 @@ using namespace llvm;
STATISTIC(NumInitBytes, "Number of bytes of global vars initialized");
STATISTIC(NumGlobals , "Number of global vars initialized");
-ExecutionEngine::EECtorFn ExecutionEngine::JITCtor = 0;
-ExecutionEngine::EECtorFn ExecutionEngine::InterpCtor = 0;
+ExecutionEngine *(*ExecutionEngine::JITCtor)(ModuleProvider *MP,
+ std::string *ErrorStr,
+ JITMemoryManager *JMM,
+ CodeGenOpt::Level OptLevel,
+ bool GVsWithCode) = 0;
+ExecutionEngine *(*ExecutionEngine::InterpCtor)(ModuleProvider *MP,
+ std::string *ErrorStr) = 0;
ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0;
-ExecutionEngine::ExecutionEngine(ModuleProvider *P) : LazyFunctionCreator(0) {
+ExecutionEngine::ExecutionEngine(ModuleProvider *P)
+ : EEState(*this),
+ LazyFunctionCreator(0) {
LazyCompilationDisabled = false;
GVCompilationDisabled = false;
SymbolSearchingDisabled = false;
@@ -105,6 +115,22 @@ Function *ExecutionEngine::FindFunctionNamed(const char *FnName) {
}
+void *ExecutionEngineState::RemoveMapping(
+ const MutexGuard &, const GlobalValue *ToUnmap) {
+ std::map<MapUpdatingCVH, void *>::iterator I =
+ GlobalAddressMap.find(getVH(ToUnmap));
+ void *OldVal;
+ if (I == GlobalAddressMap.end())
+ OldVal = 0;
+ else {
+ OldVal = I->second;
+ GlobalAddressMap.erase(I);
+ }
+
+ GlobalAddressReverseMap.erase(OldVal);
+ return OldVal;
+}
+
/// addGlobalMapping - Tell the execution engine that the specified global is
/// at the specified location. This is used internally as functions are JIT'd
/// and as global variables are laid out in memory. It can and should also be
@@ -113,14 +139,16 @@ Function *ExecutionEngine::FindFunctionNamed(const char *FnName) {
void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
MutexGuard locked(lock);
- DOUT << "JIT: Map \'" << GV->getNameStart() << "\' to [" << Addr << "]\n";
- void *&CurVal = state.getGlobalAddressMap(locked)[GV];
+ DEBUG(errs() << "JIT: Map \'" << GV->getName()
+ << "\' to [" << Addr << "]\n";);
+ void *&CurVal = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
CurVal = Addr;
// If we are using the reverse mapping, add it too
- if (!state.getGlobalAddressReverseMap(locked).empty()) {
- const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
+ if (!EEState.getGlobalAddressReverseMap(locked).empty()) {
+ AssertingVH<const GlobalValue> &V =
+ EEState.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV;
}
@@ -131,8 +159,8 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
void ExecutionEngine::clearAllGlobalMappings() {
MutexGuard locked(lock);
- state.getGlobalAddressMap(locked).clear();
- state.getGlobalAddressReverseMap(locked).clear();
+ EEState.getGlobalAddressMap(locked).clear();
+ EEState.getGlobalAddressReverseMap(locked).clear();
}
/// clearGlobalMappingsFromModule - Clear all global mappings that came from a
@@ -141,13 +169,11 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
MutexGuard locked(lock);
for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) {
- state.getGlobalAddressMap(locked).erase(FI);
- state.getGlobalAddressReverseMap(locked).erase(FI);
+ EEState.RemoveMapping(locked, FI);
}
for (Module::global_iterator GI = M->global_begin(), GE = M->global_end();
GI != GE; ++GI) {
- state.getGlobalAddressMap(locked).erase(GI);
- state.getGlobalAddressReverseMap(locked).erase(GI);
+ EEState.RemoveMapping(locked, GI);
}
}
@@ -157,34 +183,25 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
MutexGuard locked(lock);
- std::map<const GlobalValue*, void *> &Map = state.getGlobalAddressMap(locked);
+ std::map<ExecutionEngineState::MapUpdatingCVH, void *> &Map =
+ EEState.getGlobalAddressMap(locked);
// Deleting from the mapping?
if (Addr == 0) {
- std::map<const GlobalValue*, void *>::iterator I = Map.find(GV);
- void *OldVal;
- if (I == Map.end())
- OldVal = 0;
- else {
- OldVal = I->second;
- Map.erase(I);
- }
-
- if (!state.getGlobalAddressReverseMap(locked).empty())
- state.getGlobalAddressReverseMap(locked).erase(Addr);
- return OldVal;
+ return EEState.RemoveMapping(locked, GV);
}
- void *&CurVal = Map[GV];
+ void *&CurVal = Map[EEState.getVH(GV)];
void *OldVal = CurVal;
- if (CurVal && !state.getGlobalAddressReverseMap(locked).empty())
- state.getGlobalAddressReverseMap(locked).erase(CurVal);
+ if (CurVal && !EEState.getGlobalAddressReverseMap(locked).empty())
+ EEState.getGlobalAddressReverseMap(locked).erase(CurVal);
CurVal = Addr;
// If we are using the reverse mapping, add it too
- if (!state.getGlobalAddressReverseMap(locked).empty()) {
- const GlobalValue *&V = state.getGlobalAddressReverseMap(locked)[Addr];
+ if (!EEState.getGlobalAddressReverseMap(locked).empty()) {
+ AssertingVH<const GlobalValue> &V =
+ EEState.getGlobalAddressReverseMap(locked)[Addr];
assert((V == 0 || GV == 0) && "GlobalMapping already established!");
V = GV;
}
@@ -197,9 +214,9 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) {
MutexGuard locked(lock);
- std::map<const GlobalValue*, void*>::iterator I =
- state.getGlobalAddressMap(locked).find(GV);
- return I != state.getGlobalAddressMap(locked).end() ? I->second : 0;
+ std::map<ExecutionEngineState::MapUpdatingCVH, void*>::iterator I =
+ EEState.getGlobalAddressMap(locked).find(EEState.getVH(GV));
+ return I != EEState.getGlobalAddressMap(locked).end() ? I->second : 0;
}
/// getGlobalValueAtAddress - Return the LLVM global value object that starts
@@ -209,34 +226,34 @@ const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
MutexGuard locked(lock);
// If we haven't computed the reverse mapping yet, do so first.
- if (state.getGlobalAddressReverseMap(locked).empty()) {
- for (std::map<const GlobalValue*, void *>::iterator
- I = state.getGlobalAddressMap(locked).begin(),
- E = state.getGlobalAddressMap(locked).end(); I != E; ++I)
- state.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second,
+ if (EEState.getGlobalAddressReverseMap(locked).empty()) {
+ for (std::map<ExecutionEngineState::MapUpdatingCVH, void *>::iterator
+ I = EEState.getGlobalAddressMap(locked).begin(),
+ E = EEState.getGlobalAddressMap(locked).end(); I != E; ++I)
+ EEState.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second,
I->first));
}
- std::map<void *, const GlobalValue*>::iterator I =
- state.getGlobalAddressReverseMap(locked).find(Addr);
- return I != state.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
+ std::map<void *, AssertingVH<const GlobalValue> >::iterator I =
+ EEState.getGlobalAddressReverseMap(locked).find(Addr);
+ return I != EEState.getGlobalAddressReverseMap(locked).end() ? I->second : 0;
}
// CreateArgv - Turn a vector of strings into a nice argv style array of
// pointers to null terminated strings.
//
-static void *CreateArgv(ExecutionEngine *EE,
+static void *CreateArgv(LLVMContext &C, ExecutionEngine *EE,
const std::vector<std::string> &InputArgv) {
unsigned PtrSize = EE->getTargetData()->getPointerSize();
char *Result = new char[(InputArgv.size()+1)*PtrSize];
- DOUT << "JIT: ARGV = " << (void*)Result << "\n";
- const Type *SBytePtr = PointerType::getUnqual(Type::Int8Ty);
+ DEBUG(errs() << "JIT: ARGV = " << (void*)Result << "\n");
+ const Type *SBytePtr = Type::getInt8PtrTy(C);
for (unsigned i = 0; i != InputArgv.size(); ++i) {
unsigned Size = InputArgv[i].size()+1;
char *Dest = new char[Size];
- DOUT << "JIT: ARGV[" << i << "] = " << (void*)Dest << "\n";
+ DEBUG(errs() << "JIT: ARGV[" << i << "] = " << (void*)Dest << "\n");
std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest);
Dest[Size-1] = 0;
@@ -257,7 +274,8 @@ static void *CreateArgv(ExecutionEngine *EE,
/// runStaticConstructorsDestructors - This method is used to execute all of
/// the static constructors or destructors for a module, depending on the
/// value of isDtors.
-void ExecutionEngine::runStaticConstructorsDestructors(Module *module, bool isDtors) {
+void ExecutionEngine::runStaticConstructorsDestructors(Module *module,
+ bool isDtors) {
const char *Name = isDtors ? "llvm.global_dtors" : "llvm.global_ctors";
// Execute global ctors/dtors for each module in the program.
@@ -327,49 +345,47 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn,
unsigned NumArgs = Fn->getFunctionType()->getNumParams();
const FunctionType *FTy = Fn->getFunctionType();
const Type* PPInt8Ty =
- PointerType::getUnqual(PointerType::getUnqual(Type::Int8Ty));
+ PointerType::getUnqual(PointerType::getUnqual(
+ Type::getInt8Ty(Fn->getContext())));
switch (NumArgs) {
case 3:
if (FTy->getParamType(2) != PPInt8Ty) {
- cerr << "Invalid type for third argument of main() supplied\n";
- abort();
+ llvm_report_error("Invalid type for third argument of main() supplied");
}
// FALLS THROUGH
case 2:
if (FTy->getParamType(1) != PPInt8Ty) {
- cerr << "Invalid type for second argument of main() supplied\n";
- abort();
+ llvm_report_error("Invalid type for second argument of main() supplied");
}
// FALLS THROUGH
case 1:
- if (FTy->getParamType(0) != Type::Int32Ty) {
- cerr << "Invalid type for first argument of main() supplied\n";
- abort();
+ if (FTy->getParamType(0) != Type::getInt32Ty(Fn->getContext())) {
+ llvm_report_error("Invalid type for first argument of main() supplied");
}
// FALLS THROUGH
case 0:
if (!isa<IntegerType>(FTy->getReturnType()) &&
- FTy->getReturnType() != Type::VoidTy) {
- cerr << "Invalid return type of main() supplied\n";
- abort();
+ FTy->getReturnType() != Type::getVoidTy(FTy->getContext())) {
+ llvm_report_error("Invalid return type of main() supplied");
}
break;
default:
- cerr << "Invalid number of arguments of main() supplied\n";
- abort();
+ llvm_report_error("Invalid number of arguments of main() supplied");
}
if (NumArgs) {
GVArgs.push_back(GVArgc); // Arg #0 = argc.
if (NumArgs > 1) {
- GVArgs.push_back(PTOGV(CreateArgv(this, argv))); // Arg #1 = argv.
+ // Arg #1 = argv.
+ GVArgs.push_back(PTOGV(CreateArgv(Fn->getContext(), this, argv)));
assert(!isTargetNullPtr(this, GVTOP(GVArgs[1])) &&
"argv[0] was null after CreateArgv");
if (NumArgs > 2) {
std::vector<std::string> EnvVars;
for (unsigned i = 0; envp[i]; ++i)
EnvVars.push_back(envp[i]);
- GVArgs.push_back(PTOGV(CreateArgv(this, EnvVars))); // Arg #2 = envp.
+ // Arg #2 = envp.
+ GVArgs.push_back(PTOGV(CreateArgv(Fn->getContext(), this, EnvVars)));
}
}
}
@@ -383,27 +399,73 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn,
ExecutionEngine *ExecutionEngine::create(ModuleProvider *MP,
bool ForceInterpreter,
std::string *ErrorStr,
- CodeGenOpt::Level OptLevel) {
- ExecutionEngine *EE = 0;
+ CodeGenOpt::Level OptLevel,
+ bool GVsWithCode) {
+ return EngineBuilder(MP)
+ .setEngineKind(ForceInterpreter
+ ? EngineKind::Interpreter
+ : EngineKind::JIT)
+ .setErrorStr(ErrorStr)
+ .setOptLevel(OptLevel)
+ .setAllocateGVsWithCode(GVsWithCode)
+ .create();
+}
+ExecutionEngine *ExecutionEngine::create(Module *M) {
+ return EngineBuilder(M).create();
+}
+
+/// EngineBuilder - Overloaded constructor that automatically creates an
+/// ExistingModuleProvider for an existing module.
+EngineBuilder::EngineBuilder(Module *m) : MP(new ExistingModuleProvider(m)) {
+ InitEngine();
+}
+
+ExecutionEngine *EngineBuilder::create() {
// Make sure we can resolve symbols in the program as well. The zero arg
// to the function tells DynamicLibrary to load the program, not a library.
if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr))
return 0;
- // Unless the interpreter was explicitly selected, try making a JIT.
- if (!ForceInterpreter && JITCtor)
- EE = JITCtor(MP, ErrorStr, OptLevel);
+ // If the user specified a memory manager but didn't specify which engine to
+ // create, we assume they only want the JIT, and we fail if they only want
+ // the interpreter.
+ if (JMM) {
+ if (WhichEngine & EngineKind::JIT)
+ WhichEngine = EngineKind::JIT;
+ else {
+ if (ErrorStr)
+ *ErrorStr = "Cannot create an interpreter with a memory manager.";
+ return 0;
+ }
+ }
- // If we can't make a JIT, make an interpreter instead.
- if (EE == 0 && InterpCtor)
- EE = InterpCtor(MP, ErrorStr, OptLevel);
+ // Unless the interpreter was explicitly selected or the JIT is not linked,
+ // try making a JIT.
+ if (WhichEngine & EngineKind::JIT) {
+ if (ExecutionEngine::JITCtor) {
+ ExecutionEngine *EE =
+ ExecutionEngine::JITCtor(MP, ErrorStr, JMM, OptLevel,
+ AllocateGVsWithCode);
+ if (EE) return EE;
+ }
+ }
- return EE;
-}
+ // If we can't make a JIT and we didn't request one specifically, try making
+ // an interpreter instead.
+ if (WhichEngine & EngineKind::Interpreter) {
+ if (ExecutionEngine::InterpCtor)
+ return ExecutionEngine::InterpCtor(MP, ErrorStr);
+ if (ErrorStr)
+ *ErrorStr = "Interpreter has not been linked in.";
+ return 0;
+ }
-ExecutionEngine *ExecutionEngine::create(Module *M) {
- return create(new ExistingModuleProvider(M));
+ if ((WhichEngine & EngineKind::JIT) && ExecutionEngine::JITCtor == 0) {
+ if (ErrorStr)
+ *ErrorStr = "JIT has not been linked in.";
+ }
+ return 0;
}
/// getPointerToGlobal - This returns the address of the specified global
@@ -414,7 +476,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
return getPointerToFunction(F);
MutexGuard locked(lock);
- void *p = state.getGlobalAddressMap(locked)[GV];
+ void *p = EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
if (p)
return p;
@@ -423,8 +485,8 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
const_cast<GlobalVariable *>(dyn_cast<GlobalVariable>(GV)))
EmitGlobalVariable(GVar);
else
- assert(0 && "Global hasn't had an address allocated yet!");
- return state.getGlobalAddressMap(locked)[GV];
+ llvm_unreachable("Global hasn't had an address allocated yet!");
+ return EEState.getGlobalAddressMap(locked)[EEState.getVH(GV)];
}
/// This function converts a Constant* into a GenericValue. The interesting
@@ -482,11 +544,11 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
}
case Instruction::UIToFP: {
GenericValue GV = getConstantValue(Op0);
- if (CE->getType() == Type::FloatTy)
+ if (CE->getType()->isFloatTy())
GV.FloatVal = float(GV.IntVal.roundToDouble());
- else if (CE->getType() == Type::DoubleTy)
+ else if (CE->getType()->isDoubleTy())
GV.DoubleVal = GV.IntVal.roundToDouble();
- else if (CE->getType() == Type::X86_FP80Ty) {
+ else if (CE->getType()->isX86_FP80Ty()) {
const uint64_t zero[] = {0, 0};
APFloat apf = APFloat(APInt(80, 2, zero));
(void)apf.convertFromAPInt(GV.IntVal,
@@ -498,11 +560,11 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
}
case Instruction::SIToFP: {
GenericValue GV = getConstantValue(Op0);
- if (CE->getType() == Type::FloatTy)
+ if (CE->getType()->isFloatTy())
GV.FloatVal = float(GV.IntVal.signedRoundToDouble());
- else if (CE->getType() == Type::DoubleTy)
+ else if (CE->getType()->isDoubleTy())
GV.DoubleVal = GV.IntVal.signedRoundToDouble();
- else if (CE->getType() == Type::X86_FP80Ty) {
+ else if (CE->getType()->isX86_FP80Ty()) {
const uint64_t zero[] = { 0, 0};
APFloat apf = APFloat(APInt(80, 2, zero));
(void)apf.convertFromAPInt(GV.IntVal,
@@ -516,11 +578,11 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
case Instruction::FPToSI: {
GenericValue GV = getConstantValue(Op0);
uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth();
- if (Op0->getType() == Type::FloatTy)
+ if (Op0->getType()->isFloatTy())
GV.IntVal = APIntOps::RoundFloatToAPInt(GV.FloatVal, BitWidth);
- else if (Op0->getType() == Type::DoubleTy)
+ else if (Op0->getType()->isDoubleTy())
GV.IntVal = APIntOps::RoundDoubleToAPInt(GV.DoubleVal, BitWidth);
- else if (Op0->getType() == Type::X86_FP80Ty) {
+ else if (Op0->getType()->isX86_FP80Ty()) {
APFloat apf = APFloat(GV.IntVal);
uint64_t v;
bool ignored;
@@ -550,20 +612,22 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
GenericValue GV = getConstantValue(Op0);
const Type* DestTy = CE->getType();
switch (Op0->getType()->getTypeID()) {
- default: assert(0 && "Invalid bitcast operand");
+ default: llvm_unreachable("Invalid bitcast operand");
case Type::IntegerTyID:
assert(DestTy->isFloatingPoint() && "invalid bitcast");
- if (DestTy == Type::FloatTy)
+ if (DestTy->isFloatTy())
GV.FloatVal = GV.IntVal.bitsToFloat();
- else if (DestTy == Type::DoubleTy)
+ else if (DestTy->isDoubleTy())
GV.DoubleVal = GV.IntVal.bitsToDouble();
break;
case Type::FloatTyID:
- assert(DestTy == Type::Int32Ty && "Invalid bitcast");
+ assert(DestTy == Type::getInt32Ty(DestTy->getContext()) &&
+ "Invalid bitcast");
GV.IntVal.floatToBits(GV.FloatVal);
break;
case Type::DoubleTyID:
- assert(DestTy == Type::Int64Ty && "Invalid bitcast");
+ assert(DestTy == Type::getInt64Ty(DestTy->getContext()) &&
+ "Invalid bitcast");
GV.IntVal.doubleToBits(GV.DoubleVal);
break;
case Type::PointerTyID:
@@ -589,10 +653,10 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
GenericValue RHS = getConstantValue(CE->getOperand(1));
GenericValue GV;
switch (CE->getOperand(0)->getType()->getTypeID()) {
- default: assert(0 && "Bad add type!"); abort();
+ default: llvm_unreachable("Bad add type!");
case Type::IntegerTyID:
switch (CE->getOpcode()) {
- default: assert(0 && "Invalid integer opcode");
+ default: llvm_unreachable("Invalid integer opcode");
case Instruction::Add: GV.IntVal = LHS.IntVal + RHS.IntVal; break;
case Instruction::Sub: GV.IntVal = LHS.IntVal - RHS.IntVal; break;
case Instruction::Mul: GV.IntVal = LHS.IntVal * RHS.IntVal; break;
@@ -607,7 +671,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
break;
case Type::FloatTyID:
switch (CE->getOpcode()) {
- default: assert(0 && "Invalid float opcode"); abort();
+ default: llvm_unreachable("Invalid float opcode");
case Instruction::FAdd:
GV.FloatVal = LHS.FloatVal + RHS.FloatVal; break;
case Instruction::FSub:
@@ -622,7 +686,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
break;
case Type::DoubleTyID:
switch (CE->getOpcode()) {
- default: assert(0 && "Invalid double opcode"); abort();
+ default: llvm_unreachable("Invalid double opcode");
case Instruction::FAdd:
GV.DoubleVal = LHS.DoubleVal + RHS.DoubleVal; break;
case Instruction::FSub:
@@ -640,7 +704,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
case Type::FP128TyID: {
APFloat apfLHS = APFloat(LHS.IntVal);
switch (CE->getOpcode()) {
- default: assert(0 && "Invalid long double opcode"); abort();
+ default: llvm_unreachable("Invalid long double opcode");llvm_unreachable(0);
case Instruction::FAdd:
apfLHS.add(APFloat(RHS.IntVal), APFloat::rmNearestTiesToEven);
GV.IntVal = apfLHS.bitcastToAPInt();
@@ -670,8 +734,10 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
default:
break;
}
- cerr << "ConstantExpr not handled: " << *CE << "\n";
- abort();
+ std::string msg;
+ raw_string_ostream Msg(msg);
+ Msg << "ConstantExpr not handled: " << *CE;
+ llvm_report_error(Msg.str());
}
GenericValue Result;
@@ -698,11 +764,13 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
else if (const GlobalVariable* GV = dyn_cast<GlobalVariable>(C))
Result = PTOGV(getOrEmitGlobalVariable(const_cast<GlobalVariable*>(GV)));
else
- assert(0 && "Unknown constant pointer type!");
+ llvm_unreachable("Unknown constant pointer type!");
break;
default:
- cerr << "ERROR: Constant unimplemented for type: " << *C->getType() << "\n";
- abort();
+ std::string msg;
+ raw_string_ostream Msg(msg);
+ Msg << "ERROR: Constant unimplemented for type: " << *C->getType();
+ llvm_report_error(Msg.str());
}
return Result;
}
@@ -762,7 +830,7 @@ void ExecutionEngine::StoreValueToMemory(const GenericValue &Val,
*((PointerTy*)Ptr) = Val.PointerVal;
break;
default:
- cerr << "Cannot store value of type " << *Ty << "!\n";
+ errs() << "Cannot store value of type " << *Ty << "!\n";
}
if (sys::isLittleEndianHost() != getTargetData()->isLittleEndian())
@@ -803,15 +871,6 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
const Type *Ty) {
const unsigned LoadBytes = getTargetData()->getTypeStoreSize(Ty);
- if (sys::isLittleEndianHost() != getTargetData()->isLittleEndian()) {
- // Host and target are different endian - reverse copy the stored
- // bytes into a buffer, and load from that.
- uint8_t *Src = (uint8_t*)Ptr;
- uint8_t *Buf = (uint8_t*)alloca(LoadBytes);
- std::reverse_copy(Src, Src + LoadBytes, Buf);
- Ptr = (GenericValue*)Buf;
- }
-
switch (Ty->getTypeID()) {
case Type::IntegerTyID:
// An APInt with all words initially zero.
@@ -836,8 +895,10 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
break;
}
default:
- cerr << "Cannot load value of type " << *Ty << "!\n";
- abort();
+ std::string msg;
+ raw_string_ostream Msg(msg);
+ Msg << "Cannot load value of type " << *Ty << "!";
+ llvm_report_error(Msg.str());
}
}
@@ -845,7 +906,7 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
// specified memory location...
//
void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) {
- DOUT << "JIT: Initializing " << Addr << " ";
+ DEBUG(errs() << "JIT: Initializing " << Addr << " ");
DEBUG(Init->dump());
if (isa<UndefValue>(Init)) {
return;
@@ -876,8 +937,8 @@ void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) {
return;
}
- cerr << "Bad Type: " << *Init->getType() << "\n";
- assert(0 && "Unknown constant type to initialize memory with!");
+ errs() << "Bad Type: " << *Init->getType() << "\n";
+ llvm_unreachable("Unknown constant type to initialize memory with!");
}
/// EmitGlobals - Emit all of the global variables to memory, storing their
@@ -950,12 +1011,11 @@ void ExecutionEngine::emitGlobals() {
// External variable reference. Try to use the dynamic loader to
// get a pointer to it.
if (void *SymAddr =
- sys::DynamicLibrary::SearchForAddressOfSymbol(I->getName().c_str()))
+ sys::DynamicLibrary::SearchForAddressOfSymbol(I->getName()))
addGlobalMapping(I, SymAddr);
else {
- cerr << "Could not resolve external global address: "
- << I->getName() << "\n";
- abort();
+ llvm_report_error("Could not resolve external global address: "
+ +I->getName());
}
}
}
@@ -1011,3 +1071,18 @@ void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) {
NumInitBytes += (unsigned)GVSize;
++NumGlobals;
}
+
+ExecutionEngineState::MapUpdatingCVH::MapUpdatingCVH(
+ ExecutionEngineState &EES, const GlobalValue *GV)
+ : CallbackVH(const_cast<GlobalValue*>(GV)), EES(EES) {}
+
+void ExecutionEngineState::MapUpdatingCVH::deleted() {
+ MutexGuard locked(EES.EE.lock);
+ EES.RemoveMapping(locked, *this); // Destroys *this.
+}
+
+void ExecutionEngineState::MapUpdatingCVH::allUsesReplacedWith(
+ Value *new_value) {
+ assert(false && "The ExecutionEngine doesn't know how to handle a"
+ " RAUW on a value it has a global mapping for.");
+}
diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
index 401a226..5901cd7 100644
--- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp
+++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
@@ -15,6 +15,7 @@
#include "llvm-c/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstring>
using namespace llvm;
@@ -45,8 +46,7 @@ LLVMGenericValueRef LLVMCreateGenericValueOfFloat(LLVMTypeRef TyRef, double N) {
GenVal->DoubleVal = N;
break;
default:
- assert(0 && "LLVMGenericValueToFloat supports only float and double.");
- break;
+ llvm_unreachable("LLVMGenericValueToFloat supports only float and double.");
}
return wrap(GenVal);
}
@@ -75,7 +75,7 @@ double LLVMGenericValueToFloat(LLVMTypeRef TyRef, LLVMGenericValueRef GenVal) {
case Type::DoubleTyID:
return unwrap(GenVal)->DoubleVal;
default:
- assert(0 && "LLVMGenericValueToFloat supports only float and double.");
+ llvm_unreachable("LLVMGenericValueToFloat supports only float and double.");
break;
}
return 0; // Not reached
@@ -91,7 +91,10 @@ int LLVMCreateExecutionEngine(LLVMExecutionEngineRef *OutEE,
LLVMModuleProviderRef MP,
char **OutError) {
std::string Error;
- if (ExecutionEngine *EE = ExecutionEngine::create(unwrap(MP), false, &Error)){
+ EngineBuilder builder(unwrap(MP));
+ builder.setEngineKind(EngineKind::Either)
+ .setErrorStr(&Error);
+ if (ExecutionEngine *EE = builder.create()){
*OutEE = wrap(EE);
return 0;
}
@@ -103,8 +106,10 @@ int LLVMCreateInterpreter(LLVMExecutionEngineRef *OutInterp,
LLVMModuleProviderRef MP,
char **OutError) {
std::string Error;
- if (ExecutionEngine *Interp =
- ExecutionEngine::create(unwrap(MP), true, &Error)) {
+ EngineBuilder builder(unwrap(MP));
+ builder.setEngineKind(EngineKind::Interpreter)
+ .setErrorStr(&Error);
+ if (ExecutionEngine *Interp = builder.create()) {
*OutInterp = wrap(Interp);
return 0;
}
@@ -117,9 +122,11 @@ int LLVMCreateJITCompiler(LLVMExecutionEngineRef *OutJIT,
unsigned OptLevel,
char **OutError) {
std::string Error;
- if (ExecutionEngine *JIT =
- ExecutionEngine::create(unwrap(MP), false, &Error,
- (CodeGenOpt::Level)OptLevel)) {
+ EngineBuilder builder(unwrap(MP));
+ builder.setEngineKind(EngineKind::JIT)
+ .setErrorStr(&Error)
+ .setOptLevel((CodeGenOpt::Level)OptLevel);
+ if (ExecutionEngine *JIT = builder.create()) {
*OutJIT = wrap(JIT);
return 0;
}
diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp
index bb3f64e..f8c775e 100644
--- a/lib/ExecutionEngine/Interpreter/Execution.cpp
+++ b/lib/ExecutionEngine/Interpreter/Execution.cpp
@@ -22,10 +22,10 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
#include <cmath>
-#include <cstring>
using namespace llvm;
STATISTIC(NumDynamicInsts, "Number of dynamic instructions executed");
@@ -37,15 +37,6 @@ static cl::opt<bool> PrintVolatile("interpreter-print-volatile", cl::Hidden,
// Various Helper Functions
//===----------------------------------------------------------------------===//
-static inline uint64_t doSignExtension(uint64_t Val, const IntegerType* ITy) {
- // Determine if the value is signed or not
- bool isSigned = (Val & (1 << (ITy->getBitWidth()-1))) != 0;
- // If its signed, extend the sign bits
- if (isSigned)
- Val |= ~ITy->getBitMask();
- return Val;
-}
-
static void SetValue(Value *V, GenericValue Val, ExecutionContext &SF) {
SF.Values[V] = Val;
}
@@ -65,8 +56,8 @@ static void executeFAddInst(GenericValue &Dest, GenericValue Src1,
IMPLEMENT_BINARY_OPERATOR(+, Float);
IMPLEMENT_BINARY_OPERATOR(+, Double);
default:
- cerr << "Unhandled type for FAdd instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FAdd instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
}
@@ -76,8 +67,8 @@ static void executeFSubInst(GenericValue &Dest, GenericValue Src1,
IMPLEMENT_BINARY_OPERATOR(-, Float);
IMPLEMENT_BINARY_OPERATOR(-, Double);
default:
- cerr << "Unhandled type for FSub instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FSub instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
}
@@ -87,8 +78,8 @@ static void executeFMulInst(GenericValue &Dest, GenericValue Src1,
IMPLEMENT_BINARY_OPERATOR(*, Float);
IMPLEMENT_BINARY_OPERATOR(*, Double);
default:
- cerr << "Unhandled type for FMul instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FMul instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
}
@@ -98,8 +89,8 @@ static void executeFDivInst(GenericValue &Dest, GenericValue Src1,
IMPLEMENT_BINARY_OPERATOR(/, Float);
IMPLEMENT_BINARY_OPERATOR(/, Double);
default:
- cerr << "Unhandled type for FDiv instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FDiv instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
}
@@ -113,8 +104,8 @@ static void executeFRemInst(GenericValue &Dest, GenericValue Src1,
Dest.DoubleVal = fmod(Src1.DoubleVal, Src2.DoubleVal);
break;
default:
- cerr << "Unhandled type for Rem instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for Rem instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
}
@@ -140,8 +131,8 @@ static GenericValue executeICMP_EQ(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(eq,Ty);
IMPLEMENT_POINTER_ICMP(==);
default:
- cerr << "Unhandled type for ICMP_EQ predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_EQ predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -153,8 +144,8 @@ static GenericValue executeICMP_NE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(ne,Ty);
IMPLEMENT_POINTER_ICMP(!=);
default:
- cerr << "Unhandled type for ICMP_NE predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_NE predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -166,8 +157,8 @@ static GenericValue executeICMP_ULT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(ult,Ty);
IMPLEMENT_POINTER_ICMP(<);
default:
- cerr << "Unhandled type for ICMP_ULT predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_ULT predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -179,8 +170,8 @@ static GenericValue executeICMP_SLT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(slt,Ty);
IMPLEMENT_POINTER_ICMP(<);
default:
- cerr << "Unhandled type for ICMP_SLT predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_SLT predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -192,8 +183,8 @@ static GenericValue executeICMP_UGT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(ugt,Ty);
IMPLEMENT_POINTER_ICMP(>);
default:
- cerr << "Unhandled type for ICMP_UGT predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_UGT predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -205,8 +196,8 @@ static GenericValue executeICMP_SGT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(sgt,Ty);
IMPLEMENT_POINTER_ICMP(>);
default:
- cerr << "Unhandled type for ICMP_SGT predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_SGT predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -218,8 +209,8 @@ static GenericValue executeICMP_ULE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(ule,Ty);
IMPLEMENT_POINTER_ICMP(<=);
default:
- cerr << "Unhandled type for ICMP_ULE predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_ULE predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -231,8 +222,8 @@ static GenericValue executeICMP_SLE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(sle,Ty);
IMPLEMENT_POINTER_ICMP(<=);
default:
- cerr << "Unhandled type for ICMP_SLE predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_SLE predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -244,8 +235,8 @@ static GenericValue executeICMP_UGE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(uge,Ty);
IMPLEMENT_POINTER_ICMP(>=);
default:
- cerr << "Unhandled type for ICMP_UGE predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_UGE predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -257,8 +248,8 @@ static GenericValue executeICMP_SGE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_INTEGER_ICMP(sge,Ty);
IMPLEMENT_POINTER_ICMP(>=);
default:
- cerr << "Unhandled type for ICMP_SGE predicate: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for ICMP_SGE predicate: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -282,8 +273,8 @@ void Interpreter::visitICmpInst(ICmpInst &I) {
case ICmpInst::ICMP_UGE: R = executeICMP_UGE(Src1, Src2, Ty); break;
case ICmpInst::ICMP_SGE: R = executeICMP_SGE(Src1, Src2, Ty); break;
default:
- cerr << "Don't know how to handle this ICmp predicate!\n-->" << I;
- abort();
+ errs() << "Don't know how to handle this ICmp predicate!\n-->" << I;
+ llvm_unreachable(0);
}
SetValue(&I, R, SF);
@@ -301,8 +292,8 @@ static GenericValue executeFCMP_OEQ(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(==, Float);
IMPLEMENT_FCMP(==, Double);
default:
- cerr << "Unhandled type for FCmp EQ instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp EQ instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -315,8 +306,8 @@ static GenericValue executeFCMP_ONE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(!=, Double);
default:
- cerr << "Unhandled type for FCmp NE instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp NE instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -328,8 +319,8 @@ static GenericValue executeFCMP_OLE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(<=, Float);
IMPLEMENT_FCMP(<=, Double);
default:
- cerr << "Unhandled type for FCmp LE instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp LE instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -341,8 +332,8 @@ static GenericValue executeFCMP_OGE(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(>=, Float);
IMPLEMENT_FCMP(>=, Double);
default:
- cerr << "Unhandled type for FCmp GE instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp GE instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -354,8 +345,8 @@ static GenericValue executeFCMP_OLT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(<, Float);
IMPLEMENT_FCMP(<, Double);
default:
- cerr << "Unhandled type for FCmp LT instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp LT instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
@@ -367,14 +358,14 @@ static GenericValue executeFCMP_OGT(GenericValue Src1, GenericValue Src2,
IMPLEMENT_FCMP(>, Float);
IMPLEMENT_FCMP(>, Double);
default:
- cerr << "Unhandled type for FCmp GT instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled type for FCmp GT instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
return Dest;
}
#define IMPLEMENT_UNORDERED(TY, X,Y) \
- if (TY == Type::FloatTy) { \
+ if (TY->isFloatTy()) { \
if (X.FloatVal != X.FloatVal || Y.FloatVal != Y.FloatVal) { \
Dest.IntVal = APInt(1,true); \
return Dest; \
@@ -430,7 +421,7 @@ static GenericValue executeFCMP_UGT(GenericValue Src1, GenericValue Src2,
static GenericValue executeFCMP_ORD(GenericValue Src1, GenericValue Src2,
const Type *Ty) {
GenericValue Dest;
- if (Ty == Type::FloatTy)
+ if (Ty->isFloatTy())
Dest.IntVal = APInt(1,(Src1.FloatVal == Src1.FloatVal &&
Src2.FloatVal == Src2.FloatVal));
else
@@ -442,7 +433,7 @@ static GenericValue executeFCMP_ORD(GenericValue Src1, GenericValue Src2,
static GenericValue executeFCMP_UNO(GenericValue Src1, GenericValue Src2,
const Type *Ty) {
GenericValue Dest;
- if (Ty == Type::FloatTy)
+ if (Ty->isFloatTy())
Dest.IntVal = APInt(1,(Src1.FloatVal != Src1.FloatVal ||
Src2.FloatVal != Src2.FloatVal));
else
@@ -476,8 +467,8 @@ void Interpreter::visitFCmpInst(FCmpInst &I) {
case FCmpInst::FCMP_UGE: R = executeFCMP_UGE(Src1, Src2, Ty); break;
case FCmpInst::FCMP_OGE: R = executeFCMP_OGE(Src1, Src2, Ty); break;
default:
- cerr << "Don't know how to handle this FCmp predicate!\n-->" << I;
- abort();
+ errs() << "Don't know how to handle this FCmp predicate!\n-->" << I;
+ llvm_unreachable(0);
}
SetValue(&I, R, SF);
@@ -522,8 +513,8 @@ static GenericValue executeCmpInst(unsigned predicate, GenericValue Src1,
return Result;
}
default:
- cerr << "Unhandled Cmp predicate\n";
- abort();
+ errs() << "Unhandled Cmp predicate\n";
+ llvm_unreachable(0);
}
}
@@ -551,8 +542,8 @@ void Interpreter::visitBinaryOperator(BinaryOperator &I) {
case Instruction::Or: R.IntVal = Src1.IntVal | Src2.IntVal; break;
case Instruction::Xor: R.IntVal = Src1.IntVal ^ Src2.IntVal; break;
default:
- cerr << "Don't know how to handle this binary operator!\n-->" << I;
- abort();
+ errs() << "Don't know how to handle this binary operator!\n-->" << I;
+ llvm_unreachable(0);
}
SetValue(&I, R, SF);
@@ -610,7 +601,8 @@ void Interpreter::popStackAndReturnValueToCaller (const Type *RetTy,
// fill in the return value...
ExecutionContext &CallingSF = ECStack.back();
if (Instruction *I = CallingSF.Caller.getInstruction()) {
- if (CallingSF.Caller.getType() != Type::VoidTy) // Save result...
+ // Save result...
+ if (CallingSF.Caller.getType() != Type::getVoidTy(RetTy->getContext()))
SetValue(I, Result, CallingSF);
if (InvokeInst *II = dyn_cast<InvokeInst> (I))
SwitchToNewBasicBlock (II->getNormalDest (), CallingSF);
@@ -621,7 +613,7 @@ void Interpreter::popStackAndReturnValueToCaller (const Type *RetTy,
void Interpreter::visitReturnInst(ReturnInst &I) {
ExecutionContext &SF = ECStack.back();
- const Type *RetTy = Type::VoidTy;
+ const Type *RetTy = Type::getVoidTy(I.getContext());
GenericValue Result;
// Save away the return value... (if we are not 'ret void')
@@ -639,7 +631,7 @@ void Interpreter::visitUnwindInst(UnwindInst &I) {
do {
ECStack.pop_back ();
if (ECStack.empty ())
- abort ();
+ llvm_report_error("Empty stack during unwind!");
Inst = ECStack.back ().Caller.getInstruction ();
} while (!(Inst && isa<InvokeInst> (Inst)));
@@ -652,8 +644,7 @@ void Interpreter::visitUnwindInst(UnwindInst &I) {
}
void Interpreter::visitUnreachableInst(UnreachableInst &I) {
- cerr << "ERROR: Program executed an 'unreachable' instruction!\n";
- abort();
+ llvm_report_error("Program executed an 'unreachable' instruction!");
}
void Interpreter::visitBranchInst(BranchInst &I) {
@@ -746,9 +737,9 @@ void Interpreter::visitAllocationInst(AllocationInst &I) {
// Allocate enough memory to hold the type...
void *Memory = malloc(MemToAlloc);
- DOUT << "Allocated Type: " << *Ty << " (" << TypeSize << " bytes) x "
- << NumElements << " (Total: " << MemToAlloc << ") at "
- << uintptr_t(Memory) << '\n';
+ DEBUG(errs() << "Allocated Type: " << *Ty << " (" << TypeSize << " bytes) x "
+ << NumElements << " (Total: " << MemToAlloc << ") at "
+ << uintptr_t(Memory) << '\n');
GenericValue Result = PTOGV(Memory);
assert(Result.PointerVal != 0 && "Null pointer returned by malloc!");
@@ -804,7 +795,7 @@ GenericValue Interpreter::executeGEPOperation(Value *Ptr, gep_type_iterator I,
GenericValue Result;
Result.PointerVal = ((char*)getOperandValue(Ptr, SF).PointerVal) + Total;
- DOUT << "GEP Index " << Total << " bytes.\n";
+ DEBUG(errs() << "GEP Index " << Total << " bytes.\n");
return Result;
}
@@ -822,7 +813,7 @@ void Interpreter::visitLoadInst(LoadInst &I) {
LoadValueFromMemory(Result, Ptr, I.getType());
SetValue(&I, Result, SF);
if (I.isVolatile() && PrintVolatile)
- cerr << "Volatile load " << I;
+ errs() << "Volatile load " << I;
}
void Interpreter::visitStoreInst(StoreInst &I) {
@@ -832,7 +823,7 @@ void Interpreter::visitStoreInst(StoreInst &I) {
StoreValueToMemory(Val, (GenericValue *)GVTOP(SRC),
I.getOperand(0)->getType());
if (I.isVolatile() && PrintVolatile)
- cerr << "Volatile store: " << I;
+ errs() << "Volatile store: " << I;
}
//===----------------------------------------------------------------------===//
@@ -979,7 +970,7 @@ GenericValue Interpreter::executeZExtInst(Value *SrcVal, const Type *DstTy,
GenericValue Interpreter::executeFPTruncInst(Value *SrcVal, const Type *DstTy,
ExecutionContext &SF) {
GenericValue Dest, Src = getOperandValue(SrcVal, SF);
- assert(SrcVal->getType() == Type::DoubleTy && DstTy == Type::FloatTy &&
+ assert(SrcVal->getType()->isDoubleTy() && DstTy->isFloatTy() &&
"Invalid FPTrunc instruction");
Dest.FloatVal = (float) Src.DoubleVal;
return Dest;
@@ -988,7 +979,7 @@ GenericValue Interpreter::executeFPTruncInst(Value *SrcVal, const Type *DstTy,
GenericValue Interpreter::executeFPExtInst(Value *SrcVal, const Type *DstTy,
ExecutionContext &SF) {
GenericValue Dest, Src = getOperandValue(SrcVal, SF);
- assert(SrcVal->getType() == Type::FloatTy && DstTy == Type::DoubleTy &&
+ assert(SrcVal->getType()->isFloatTy() && DstTy->isDoubleTy() &&
"Invalid FPTrunc instruction");
Dest.DoubleVal = (double) Src.FloatVal;
return Dest;
@@ -1079,28 +1070,28 @@ GenericValue Interpreter::executeBitCastInst(Value *SrcVal, const Type *DstTy,
assert(isa<PointerType>(SrcTy) && "Invalid BitCast");
Dest.PointerVal = Src.PointerVal;
} else if (DstTy->isInteger()) {
- if (SrcTy == Type::FloatTy) {
+ if (SrcTy->isFloatTy()) {
Dest.IntVal.zext(sizeof(Src.FloatVal) * CHAR_BIT);
Dest.IntVal.floatToBits(Src.FloatVal);
- } else if (SrcTy == Type::DoubleTy) {
+ } else if (SrcTy->isDoubleTy()) {
Dest.IntVal.zext(sizeof(Src.DoubleVal) * CHAR_BIT);
Dest.IntVal.doubleToBits(Src.DoubleVal);
} else if (SrcTy->isInteger()) {
Dest.IntVal = Src.IntVal;
} else
- assert(0 && "Invalid BitCast");
- } else if (DstTy == Type::FloatTy) {
+ llvm_unreachable("Invalid BitCast");
+ } else if (DstTy->isFloatTy()) {
if (SrcTy->isInteger())
Dest.FloatVal = Src.IntVal.bitsToFloat();
else
Dest.FloatVal = Src.FloatVal;
- } else if (DstTy == Type::DoubleTy) {
+ } else if (DstTy->isDoubleTy()) {
if (SrcTy->isInteger())
Dest.DoubleVal = Src.IntVal.bitsToDouble();
else
Dest.DoubleVal = Src.DoubleVal;
} else
- assert(0 && "Invalid Bitcast");
+ llvm_unreachable("Invalid Bitcast");
return Dest;
}
@@ -1184,8 +1175,8 @@ void Interpreter::visitVAArgInst(VAArgInst &I) {
IMPLEMENT_VAARG(Float);
IMPLEMENT_VAARG(Double);
default:
- cerr << "Unhandled dest type for vaarg instruction: " << *Ty << "\n";
- abort();
+ errs() << "Unhandled dest type for vaarg instruction: " << *Ty << "\n";
+ llvm_unreachable(0);
}
// Set the Value of this Instruction.
@@ -1271,8 +1262,8 @@ GenericValue Interpreter::getConstantExprValue (ConstantExpr *CE,
Dest.IntVal = Op0.IntVal.ashr(Op1.IntVal.getZExtValue());
break;
default:
- cerr << "Unhandled ConstantExpr: " << *CE << "\n";
- abort();
+ errs() << "Unhandled ConstantExpr: " << *CE << "\n";
+ llvm_unreachable(0);
return GenericValue();
}
return Dest;
@@ -1344,30 +1335,29 @@ void Interpreter::run() {
// Track the number of dynamic instructions executed.
++NumDynamicInsts;
- DOUT << "About to interpret: " << I;
+ DEBUG(errs() << "About to interpret: " << I);
visit(I); // Dispatch to one of the visit* methods...
#if 0
// This is not safe, as visiting the instruction could lower it and free I.
-#ifndef NDEBUG
+DEBUG(
if (!isa<CallInst>(I) && !isa<InvokeInst>(I) &&
I.getType() != Type::VoidTy) {
- DOUT << " --> ";
+ errs() << " --> ";
const GenericValue &Val = SF.Values[&I];
switch (I.getType()->getTypeID()) {
- default: assert(0 && "Invalid GenericValue Type");
- case Type::VoidTyID: DOUT << "void"; break;
- case Type::FloatTyID: DOUT << "float " << Val.FloatVal; break;
- case Type::DoubleTyID: DOUT << "double " << Val.DoubleVal; break;
- case Type::PointerTyID: DOUT << "void* " << intptr_t(Val.PointerVal);
+ default: llvm_unreachable("Invalid GenericValue Type");
+ case Type::VoidTyID: errs() << "void"; break;
+ case Type::FloatTyID: errs() << "float " << Val.FloatVal; break;
+ case Type::DoubleTyID: errs() << "double " << Val.DoubleVal; break;
+ case Type::PointerTyID: errs() << "void* " << intptr_t(Val.PointerVal);
break;
case Type::IntegerTyID:
- DOUT << "i" << Val.IntVal.getBitWidth() << " "
- << Val.IntVal.toStringUnsigned(10)
- << " (0x" << Val.IntVal.toStringUnsigned(16) << ")\n";
+ errs() << "i" << Val.IntVal.getBitWidth() << " "
+ << Val.IntVal.toStringUnsigned(10)
+ << " (0x" << Val.IntVal.toStringUnsigned(16) << ")\n";
break;
}
- }
-#endif
+ });
#endif
}
}
diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
index b8525a3..8c45a36 100644
--- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
+++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
@@ -23,7 +23,7 @@
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Config/config.h" // Detect libffi
-#include "llvm/Support/Streams.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/ManagedStatic.h"
@@ -54,7 +54,7 @@ static ManagedStatic<std::map<const Function *, ExFunc> > ExportedFunctions;
static std::map<std::string, ExFunc> FuncNames;
#ifdef USE_LIBFFI
-typedef void (*RawFunc)(void);
+typedef void (*RawFunc)();
static ManagedStatic<std::map<const Function *, RawFunc> > RawFunctions;
#endif
@@ -95,15 +95,15 @@ static ExFunc lookupFunction(const Function *F) {
const FunctionType *FT = F->getFunctionType();
for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i)
ExtName += getTypeID(FT->getContainedType(i));
- ExtName += "_" + F->getName();
+ ExtName + "_" + F->getNameStr();
- sys::ScopedLock Writer(&*FunctionsLock);
+ sys::ScopedLock Writer(*FunctionsLock);
ExFunc FnPtr = FuncNames[ExtName];
if (FnPtr == 0)
- FnPtr = FuncNames["lle_X_"+F->getName()];
+ FnPtr = FuncNames["lle_X_" + F->getNameStr()];
if (FnPtr == 0) // Try calling a generic function... if it exists...
- FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol(
- ("lle_X_"+F->getName()).c_str());
+ FnPtr = (ExFunc)(intptr_t)
+ sys::DynamicLibrary::SearchForAddressOfSymbol("lle_X_"+F->getNameStr());
if (FnPtr != 0)
ExportedFunctions->insert(std::make_pair(F, FnPtr)); // Cache for later
return FnPtr;
@@ -126,8 +126,7 @@ static ffi_type *ffiTypeFor(const Type *Ty) {
default: break;
}
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
- cerr << "Type could not be mapped for use with libffi.\n";
- abort();
+ llvm_report_error("Type could not be mapped for use with libffi.");
return NULL;
}
@@ -175,8 +174,7 @@ static void *ffiValueFor(const Type *Ty, const GenericValue &AV,
default: break;
}
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
- cerr << "Type value could not be mapped for use with libffi.\n";
- abort();
+ llvm_report_error("Type value could not be mapped for use with libffi.");
return NULL;
}
@@ -190,9 +188,8 @@ static bool ffiInvoke(RawFunc Fn, Function *F,
// TODO: We don't have type information about the remaining arguments, because
// this information is never passed into ExecutionEngine::runFunction().
if (ArgVals.size() > NumArgs && F->isVarArg()) {
- cerr << "Calling external var arg function '" << F->getName()
- << "' is not supported by the Interpreter.\n";
- abort();
+ llvm_report_error("Calling external var arg function '" + F->getName()
+ + "' is not supported by the Interpreter.");
}
unsigned ArgBytes = 0;
@@ -206,9 +203,10 @@ static bool ffiInvoke(RawFunc Fn, Function *F,
ArgBytes += TD->getTypeStoreSize(ArgTy);
}
- uint8_t *ArgData = (uint8_t*) alloca(ArgBytes);
- uint8_t *ArgDataPtr = ArgData;
- std::vector<void*> values(NumArgs);
+ SmallVector<uint8_t, 128> ArgData;
+ ArgData.resize(ArgBytes);
+ uint8_t *ArgDataPtr = ArgData.data();
+ SmallVector<void*, 16> values(NumArgs);
for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
A != E; ++A) {
const unsigned ArgNo = A->getArgNo();
@@ -221,22 +219,22 @@ static bool ffiInvoke(RawFunc Fn, Function *F,
ffi_type *rtype = ffiTypeFor(RetTy);
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, &args[0]) == FFI_OK) {
- void *ret = NULL;
+ SmallVector<uint8_t, 128> ret;
if (RetTy->getTypeID() != Type::VoidTyID)
- ret = alloca(TD->getTypeStoreSize(RetTy));
- ffi_call(&cif, Fn, ret, &values[0]);
+ ret.resize(TD->getTypeStoreSize(RetTy));
+ ffi_call(&cif, Fn, ret.data(), values.data());
switch (RetTy->getTypeID()) {
case Type::IntegerTyID:
switch (cast<IntegerType>(RetTy)->getBitWidth()) {
- case 8: Result.IntVal = APInt(8 , *(int8_t *) ret); break;
- case 16: Result.IntVal = APInt(16, *(int16_t*) ret); break;
- case 32: Result.IntVal = APInt(32, *(int32_t*) ret); break;
- case 64: Result.IntVal = APInt(64, *(int64_t*) ret); break;
+ case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break;
+ case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break;
+ case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break;
+ case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break;
}
break;
- case Type::FloatTyID: Result.FloatVal = *(float *) ret; break;
- case Type::DoubleTyID: Result.DoubleVal = *(double*) ret; break;
- case Type::PointerTyID: Result.PointerVal = *(void **) ret; break;
+ case Type::FloatTyID: Result.FloatVal = *(float *) ret.data(); break;
+ case Type::DoubleTyID: Result.DoubleVal = *(double*) ret.data(); break;
+ case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break;
default: break;
}
return true;
@@ -272,7 +270,7 @@ GenericValue Interpreter::callExternalFunction(Function *F,
} else {
RawFn = RF->second;
}
-
+
FunctionsLock->release();
GenericValue Result;
@@ -280,10 +278,12 @@ GenericValue Interpreter::callExternalFunction(Function *F,
return Result;
#endif // USE_LIBFFI
- cerr << "Tried to execute an unknown external function: "
- << F->getType()->getDescription() << " " << F->getName() << "\n";
- if (F->getName() != "__main")
- abort();
+ if (F->getName() == "__main")
+ errs() << "Tried to execute an unknown external function: "
+ << F->getType()->getDescription() << " __main\n";
+ else
+ llvm_report_error("Tried to execute an unknown external function: " +
+ F->getType()->getDescription() + " " +F->getName());
return GenericValue();
}
@@ -291,6 +291,12 @@ GenericValue Interpreter::callExternalFunction(Function *F,
//===----------------------------------------------------------------------===//
// Functions "exported" to the running application...
//
+
+// Visual Studio warns about returning GenericValue in extern "C" linkage
+#ifdef _MSC_VER
+ #pragma warning(disable : 4190)
+#endif
+
extern "C" { // Don't add C++ manglings to llvm mangling :)
// void atexit(Function*)
@@ -313,6 +319,8 @@ GenericValue lle_X_exit(const FunctionType *FT,
// void abort(void)
GenericValue lle_X_abort(const FunctionType *FT,
const std::vector<GenericValue> &Args) {
+ //FIXME: should we report or raise here?
+ //llvm_report_error("Interpreted program raised SIGABRT");
raise (SIGABRT);
return GenericValue();
}
@@ -327,7 +335,7 @@ GenericValue lle_X_sprintf(const FunctionType *FT,
// printf should return # chars printed. This is completely incorrect, but
// close enough for now.
- GenericValue GV;
+ GenericValue GV;
GV.IntVal = APInt(32, strlen(FmtStr));
while (1) {
switch (*FmtStr) {
@@ -385,7 +393,8 @@ GenericValue lle_X_sprintf(const FunctionType *FT,
sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
case 's':
sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
- default: cerr << "<unknown printf code '" << *FmtStr << "'!>";
+ default:
+ errs() << "<unknown printf code '" << *FmtStr << "'!>";
ArgNo++; break;
}
strcpy(OutputBuffer, Buffer);
@@ -406,11 +415,12 @@ GenericValue lle_X_printf(const FunctionType *FT,
NewArgs.push_back(PTOGV((void*)&Buffer[0]));
NewArgs.insert(NewArgs.end(), Args.begin(), Args.end());
GenericValue GV = lle_X_sprintf(FT, NewArgs);
- cout << Buffer;
+ outs() << Buffer;
return GV;
}
-static void ByteswapSCANFResults(const char *Fmt, void *Arg0, void *Arg1,
+static void ByteswapSCANFResults(LLVMContext &C,
+ const char *Fmt, void *Arg0, void *Arg1,
void *Arg2, void *Arg3, void *Arg4, void *Arg5,
void *Arg6, void *Arg7, void *Arg8) {
void *Args[] = { Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, 0 };
@@ -450,26 +460,26 @@ static void ByteswapSCANFResults(const char *Fmt, void *Arg0, void *Arg1,
case 'i': case 'o': case 'u': case 'x': case 'X': case 'n': case 'p':
case 'd':
if (Long || LongLong) {
- Size = 8; Ty = Type::Int64Ty;
+ Size = 8; Ty = Type::getInt64Ty(C);
} else if (Half) {
- Size = 4; Ty = Type::Int16Ty;
+ Size = 4; Ty = Type::getInt16Ty(C);
} else {
- Size = 4; Ty = Type::Int32Ty;
+ Size = 4; Ty = Type::getInt32Ty(C);
}
break;
case 'e': case 'g': case 'E':
case 'f':
if (Long || LongLong) {
- Size = 8; Ty = Type::DoubleTy;
+ Size = 8; Ty = Type::getDoubleTy(C);
} else {
- Size = 4; Ty = Type::FloatTy;
+ Size = 4; Ty = Type::getFloatTy(C);
}
break;
case 's': case 'c': case '[': // No byteswap needed
Size = 1;
- Ty = Type::Int8Ty;
+ Ty = Type::getInt8Ty(C);
break;
default: break;
@@ -498,7 +508,8 @@ GenericValue lle_X_sscanf(const FunctionType *FT,
GenericValue GV;
GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
Args[5], Args[6], Args[7], Args[8], Args[9]));
- ByteswapSCANFResults(Args[1], Args[2], Args[3], Args[4],
+ ByteswapSCANFResults(FT->getContext(),
+ Args[1], Args[2], Args[3], Args[4],
Args[5], Args[6], Args[7], Args[8], Args[9], 0);
return GV;
}
@@ -515,7 +526,8 @@ GenericValue lle_X_scanf(const FunctionType *FT,
GenericValue GV;
GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],
Args[5], Args[6], Args[7], Args[8], Args[9]));
- ByteswapSCANFResults(Args[0], Args[1], Args[2], Args[3], Args[4],
+ ByteswapSCANFResults(FT->getContext(),
+ Args[0], Args[1], Args[2], Args[3], Args[4],
Args[5], Args[6], Args[7], Args[8], Args[9]);
return GV;
}
@@ -537,9 +549,14 @@ GenericValue lle_X_fprintf(const FunctionType *FT,
} // End extern "C"
+// Done with externals; turn the warning back on
+#ifdef _MSC_VER
+ #pragma warning(default: 4190)
+#endif
+
void Interpreter::initializeExternalFunctions() {
- sys::ScopedLock Writer(&*FunctionsLock);
+ sys::ScopedLock Writer(*FunctionsLock);
FuncNames["lle_X_atexit"] = lle_X_atexit;
FuncNames["lle_X_exit"] = lle_X_exit;
FuncNames["lle_X_abort"] = lle_X_abort;
@@ -550,4 +567,3 @@ void Interpreter::initializeExternalFunctions() {
FuncNames["lle_X_scanf"] = lle_X_scanf;
FuncNames["lle_X_fprintf"] = lle_X_fprintf;
}
-
diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.cpp b/lib/ExecutionEngine/Interpreter/Interpreter.cpp
index d7f38ef5..9be6a92 100644
--- a/lib/ExecutionEngine/Interpreter/Interpreter.cpp
+++ b/lib/ExecutionEngine/Interpreter/Interpreter.cpp
@@ -33,8 +33,7 @@ extern "C" void LLVMLinkInInterpreter() { }
/// create - Create a new interpreter object. This can never fail.
///
-ExecutionEngine *Interpreter::create(ModuleProvider *MP, std::string* ErrStr,
- CodeGenOpt::Level OptLevel /*unused*/) {
+ExecutionEngine *Interpreter::create(ModuleProvider *MP, std::string* ErrStr) {
// Tell this ModuleProvide to materialize and release the module
if (!MP->materializeModule(ErrStr))
// We got an error, just return 0
@@ -98,4 +97,3 @@ Interpreter::runFunction(Function *F,
return ExitValue;
}
-
diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h
index 6b13c90..e026287 100644
--- a/lib/ExecutionEngine/Interpreter/Interpreter.h
+++ b/lib/ExecutionEngine/Interpreter/Interpreter.h
@@ -17,11 +17,12 @@
#include "llvm/Function.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
-#include "llvm/Support/InstVisitor.h"
-#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/DataTypes.h"
-
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/InstVisitor.h"
+#include "llvm/Support/raw_ostream.h"
namespace llvm {
class IntrinsicLowering;
@@ -107,8 +108,7 @@ public:
/// create - Create an interpreter ExecutionEngine. This can never fail.
///
- static ExecutionEngine *create(ModuleProvider *M, std::string *ErrorStr = 0,
- CodeGenOpt::Level = CodeGenOpt::Default);
+ static ExecutionEngine *create(ModuleProvider *M, std::string *ErrorStr = 0);
/// run - Start execution with the specified function and arguments.
///
@@ -144,7 +144,9 @@ public:
void visitLoadInst(LoadInst &I);
void visitStoreInst(StoreInst &I);
void visitGetElementPtrInst(GetElementPtrInst &I);
- void visitPHINode(PHINode &PN) { assert(0 && "PHI nodes already handled!"); }
+ void visitPHINode(PHINode &PN) {
+ llvm_unreachable("PHI nodes already handled!");
+ }
void visitTruncInst(TruncInst &I);
void visitZExtInst(ZExtInst &I);
void visitSExtInst(SExtInst &I);
@@ -172,8 +174,8 @@ public:
void visitVAArgInst(VAArgInst &I);
void visitInstruction(Instruction &I) {
- cerr << I;
- assert(0 && "Instruction not interpretable yet!");
+ errs() << I;
+ llvm_unreachable("Instruction not interpretable yet!");
}
GenericValue callExternalFunction(Function *F,
diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt
index bf915f7..41b3b4e 100644
--- a/lib/ExecutionEngine/JIT/CMakeLists.txt
+++ b/lib/ExecutionEngine/JIT/CMakeLists.txt
@@ -4,9 +4,11 @@ add_definitions(-DENABLE_X86_JIT)
add_llvm_library(LLVMJIT
Intercept.cpp
JIT.cpp
+ JITDebugRegisterer.cpp
JITDwarfEmitter.cpp
JITEmitter.cpp
JITMemoryManager.cpp
MacOSJITEventListener.cpp
+ OProfileJITEventListener.cpp
TargetSelect.cpp
)
diff --git a/lib/ExecutionEngine/JIT/Intercept.cpp b/lib/ExecutionEngine/JIT/Intercept.cpp
index 3dcc462..c00b60a 100644
--- a/lib/ExecutionEngine/JIT/Intercept.cpp
+++ b/lib/ExecutionEngine/JIT/Intercept.cpp
@@ -16,7 +16,7 @@
//===----------------------------------------------------------------------===//
#include "JIT.h"
-#include "llvm/Support/Streams.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Config/config.h"
using namespace llvm;
@@ -56,6 +56,7 @@ static void runAtExitHandlers() {
* linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
* available as an exported symbol, so we have to add it explicitly.
*/
+namespace {
class StatSymbols {
public:
StatSymbols() {
@@ -72,6 +73,7 @@ public:
sys::DynamicLibrary::AddSymbol("mknod", (void*)(intptr_t)mknod);
}
};
+}
static StatSymbols initStatSymbols;
#endif // __linux__
@@ -82,7 +84,7 @@ static void jit_exit(int Status) {
}
// jit_atexit - Used to intercept the "atexit" library call.
-static int jit_atexit(void (*Fn)(void)) {
+static int jit_atexit(void (*Fn)()) {
AtExitHandlers.push_back(Fn); // Take note of atexit handler...
return 0; // Always successful
}
@@ -140,9 +142,8 @@ void *JIT::getPointerToNamedFunction(const std::string &Name,
return RP;
if (AbortOnFailure) {
- cerr << "ERROR: Program used external function '" << Name
- << "' which could not be resolved!\n";
- abort();
+ llvm_report_error("Program used external function '"+Name+
+ "' which could not be resolved!");
}
return 0;
}
diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp
index 1d8312f..b2a268b 100644
--- a/lib/ExecutionEngine/JIT/JIT.cpp
+++ b/lib/ExecutionEngine/JIT/JIT.cpp
@@ -27,6 +27,7 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetJITInfo.h"
#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Config/config.h"
@@ -196,25 +197,44 @@ void DarwinRegisterFrame(void* FrameBegin) {
ExecutionEngine *ExecutionEngine::createJIT(ModuleProvider *MP,
std::string *ErrorStr,
JITMemoryManager *JMM,
- CodeGenOpt::Level OptLevel) {
- ExecutionEngine *EE = JIT::createJIT(MP, ErrorStr, JMM, OptLevel);
- if (!EE) return 0;
-
+ CodeGenOpt::Level OptLevel,
+ bool GVsWithCode) {
+ return JIT::createJIT(MP, ErrorStr, JMM, OptLevel, GVsWithCode);
+}
+
+ExecutionEngine *JIT::createJIT(ModuleProvider *MP,
+ std::string *ErrorStr,
+ JITMemoryManager *JMM,
+ CodeGenOpt::Level OptLevel,
+ bool GVsWithCode) {
// Make sure we can resolve symbols in the program as well. The zero arg
// to the function tells DynamicLibrary to load the program, not a library.
- sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr);
- return EE;
+ if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr))
+ return 0;
+
+ // Pick a target either via -march or by guessing the native arch.
+ TargetMachine *TM = JIT::selectTarget(MP, ErrorStr);
+ if (!TM || (ErrorStr && ErrorStr->length() > 0)) return 0;
+
+ // If the target supports JIT code generation, create a the JIT.
+ if (TargetJITInfo *TJ = TM->getJITInfo()) {
+ return new JIT(MP, *TM, *TJ, JMM, OptLevel, GVsWithCode);
+ } else {
+ if (ErrorStr)
+ *ErrorStr = "target does not support JIT code generation";
+ return 0;
+ }
}
JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji,
- JITMemoryManager *JMM, CodeGenOpt::Level OptLevel)
- : ExecutionEngine(MP), TM(tm), TJI(tji) {
+ JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, bool GVsWithCode)
+ : ExecutionEngine(MP), TM(tm), TJI(tji), AllocateGVsWithCode(GVsWithCode) {
setTargetData(TM.getTargetData());
jitstate = new JITState(MP);
// Initialize JCE
- JCE = createEmitter(*this, JMM);
+ JCE = createEmitter(*this, JMM, TM);
// Add target data
MutexGuard locked(lock);
@@ -224,8 +244,7 @@ JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji,
// Turn the machine code intermediate representation into bytes in memory that
// may be executed.
if (TM.addPassesToEmitMachineCode(PM, *JCE, OptLevel)) {
- cerr << "Target does not support machine code emission!\n";
- abort();
+ llvm_report_error("Target does not support machine code emission!");
}
// Register routine for informing unwinding runtime about new EH frames
@@ -273,8 +292,7 @@ void JIT::addModuleProvider(ModuleProvider *MP) {
// Turn the machine code intermediate representation into bytes in memory
// that may be executed.
if (TM.addPassesToEmitMachineCode(PM, *JCE, CodeGenOpt::Default)) {
- cerr << "Target does not support machine code emission!\n";
- abort();
+ llvm_report_error("Target does not support machine code emission!");
}
// Initialize passes.
@@ -306,8 +324,7 @@ Module *JIT::removeModuleProvider(ModuleProvider *MP, std::string *E) {
// Turn the machine code intermediate representation into bytes in memory
// that may be executed.
if (TM.addPassesToEmitMachineCode(PM, *JCE, CodeGenOpt::Default)) {
- cerr << "Target does not support machine code emission!\n";
- abort();
+ llvm_report_error("Target does not support machine code emission!");
}
// Initialize passes.
@@ -338,8 +355,7 @@ void JIT::deleteModuleProvider(ModuleProvider *MP, std::string *E) {
// Turn the machine code intermediate representation into bytes in memory
// that may be executed.
if (TM.addPassesToEmitMachineCode(PM, *JCE, CodeGenOpt::Default)) {
- cerr << "Target does not support machine code emission!\n";
- abort();
+ llvm_report_error("Target does not support machine code emission!");
}
// Initialize passes.
@@ -366,10 +382,11 @@ GenericValue JIT::runFunction(Function *F,
// Handle some common cases first. These cases correspond to common `main'
// prototypes.
- if (RetTy == Type::Int32Ty || RetTy == Type::VoidTy) {
+ if (RetTy == Type::getInt32Ty(F->getContext()) ||
+ RetTy == Type::getVoidTy(F->getContext())) {
switch (ArgValues.size()) {
case 3:
- if (FTy->getParamType(0) == Type::Int32Ty &&
+ if (FTy->getParamType(0) == Type::getInt32Ty(F->getContext()) &&
isa<PointerType>(FTy->getParamType(1)) &&
isa<PointerType>(FTy->getParamType(2))) {
int (*PF)(int, char **, const char **) =
@@ -384,7 +401,7 @@ GenericValue JIT::runFunction(Function *F,
}
break;
case 2:
- if (FTy->getParamType(0) == Type::Int32Ty &&
+ if (FTy->getParamType(0) == Type::getInt32Ty(F->getContext()) &&
isa<PointerType>(FTy->getParamType(1))) {
int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr;
@@ -397,7 +414,7 @@ GenericValue JIT::runFunction(Function *F,
break;
case 1:
if (FTy->getNumParams() == 1 &&
- FTy->getParamType(0) == Type::Int32Ty) {
+ FTy->getParamType(0) == Type::getInt32Ty(F->getContext())) {
GenericValue rv;
int (*PF)(int) = (int(*)(int))(intptr_t)FPtr;
rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue()));
@@ -411,7 +428,7 @@ GenericValue JIT::runFunction(Function *F,
if (ArgValues.empty()) {
GenericValue rv;
switch (RetTy->getTypeID()) {
- default: assert(0 && "Unknown return type for function call!");
+ default: llvm_unreachable("Unknown return type for function call!");
case Type::IntegerTyID: {
unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth();
if (BitWidth == 1)
@@ -425,7 +442,7 @@ GenericValue JIT::runFunction(Function *F,
else if (BitWidth <= 64)
rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)());
else
- assert(0 && "Integer types > 64 bits not supported");
+ llvm_unreachable("Integer types > 64 bits not supported");
return rv;
}
case Type::VoidTyID:
@@ -440,7 +457,7 @@ GenericValue JIT::runFunction(Function *F,
case Type::X86_FP80TyID:
case Type::FP128TyID:
case Type::PPC_FP128TyID:
- assert(0 && "long double not supported yet");
+ llvm_unreachable("long double not supported yet");
return rv;
case Type::PointerTyID:
return PTOGV(((void*(*)())(intptr_t)FPtr)());
@@ -458,7 +475,7 @@ GenericValue JIT::runFunction(Function *F,
F->getParent());
// Insert a basic block.
- BasicBlock *StubBB = BasicBlock::Create("", Stub);
+ BasicBlock *StubBB = BasicBlock::Create(F->getContext(), "", Stub);
// Convert all of the GenericValue arguments over to constants. Note that we
// currently don't support varargs.
@@ -468,28 +485,31 @@ GenericValue JIT::runFunction(Function *F,
const Type *ArgTy = FTy->getParamType(i);
const GenericValue &AV = ArgValues[i];
switch (ArgTy->getTypeID()) {
- default: assert(0 && "Unknown argument type for function call!");
+ default: llvm_unreachable("Unknown argument type for function call!");
case Type::IntegerTyID:
- C = ConstantInt::get(AV.IntVal);
+ C = ConstantInt::get(F->getContext(), AV.IntVal);
break;
case Type::FloatTyID:
- C = ConstantFP::get(APFloat(AV.FloatVal));
+ C = ConstantFP::get(F->getContext(), APFloat(AV.FloatVal));
break;
case Type::DoubleTyID:
- C = ConstantFP::get(APFloat(AV.DoubleVal));
+ C = ConstantFP::get(F->getContext(), APFloat(AV.DoubleVal));
break;
case Type::PPC_FP128TyID:
case Type::X86_FP80TyID:
case Type::FP128TyID:
- C = ConstantFP::get(APFloat(AV.IntVal));
+ C = ConstantFP::get(F->getContext(), APFloat(AV.IntVal));
break;
case Type::PointerTyID:
void *ArgPtr = GVTOP(AV);
if (sizeof(void*) == 4)
- C = ConstantInt::get(Type::Int32Ty, (int)(intptr_t)ArgPtr);
+ C = ConstantInt::get(Type::getInt32Ty(F->getContext()),
+ (int)(intptr_t)ArgPtr);
else
- C = ConstantInt::get(Type::Int64Ty, (intptr_t)ArgPtr);
- C = ConstantExpr::getIntToPtr(C, ArgTy); // Cast the integer to pointer
+ C = ConstantInt::get(Type::getInt64Ty(F->getContext()),
+ (intptr_t)ArgPtr);
+ // Cast the integer to pointer
+ C = ConstantExpr::getIntToPtr(C, ArgTy);
break;
}
Args.push_back(C);
@@ -499,10 +519,11 @@ GenericValue JIT::runFunction(Function *F,
"", StubBB);
TheCall->setCallingConv(F->getCallingConv());
TheCall->setTailCall();
- if (TheCall->getType() != Type::VoidTy)
- ReturnInst::Create(TheCall, StubBB); // Return result of the call.
+ if (TheCall->getType() != Type::getVoidTy(F->getContext()))
+ // Return result of the call.
+ ReturnInst::Create(F->getContext(), TheCall, StubBB);
else
- ReturnInst::Create(StubBB); // Just return void.
+ ReturnInst::Create(F->getContext(), StubBB); // Just return void.
// Finally, return the value returned by our nullary stub function.
return runFunction(Stub, std::vector<GenericValue>());
@@ -629,9 +650,8 @@ void *JIT::getPointerToFunction(Function *F) {
std::string ErrorMsg;
if (MP->materializeFunction(F, &ErrorMsg)) {
- cerr << "Error reading function '" << F->getName()
- << "' from bitcode file: " << ErrorMsg << "\n";
- abort();
+ llvm_report_error("Error reading function '" + F->getName()+
+ "' from bitcode file: " + ErrorMsg);
}
// Now retry to get the address.
@@ -669,45 +689,18 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
if (GV->getName() == "__dso_handle")
return (void*)&__dso_handle;
#endif
- Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(GV->getName().c_str());
+ Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(GV->getName());
if (Ptr == 0 && !areDlsymStubsEnabled()) {
- cerr << "Could not resolve external global address: "
- << GV->getName() << "\n";
- abort();
+ llvm_report_error("Could not resolve external global address: "
+ +GV->getName());
}
addGlobalMapping(GV, Ptr);
} else {
- // GlobalVariable's which are not "constant" will cause trouble in a server
- // situation. It's returned in the same block of memory as code which may
- // not be writable.
- if (isGVCompilationDisabled() && !GV->isConstant()) {
- cerr << "Compilation of non-internal GlobalValue is disabled!\n";
- abort();
- }
// If the global hasn't been emitted to memory yet, allocate space and
- // emit it into memory. It goes in the same array as the generated
- // code, jump tables, etc.
- const Type *GlobalType = GV->getType()->getElementType();
- size_t S = getTargetData()->getTypeAllocSize(GlobalType);
- size_t A = getTargetData()->getPreferredAlignment(GV);
- if (GV->isThreadLocal()) {
- MutexGuard locked(lock);
- Ptr = TJI.allocateThreadLocalMemory(S);
- } else if (TJI.allocateSeparateGVMemory()) {
- if (A <= 8) {
- Ptr = malloc(S);
- } else {
- // Allocate S+A bytes of memory, then use an aligned pointer within that
- // space.
- Ptr = malloc(S+A);
- unsigned MisAligned = ((intptr_t)Ptr & (A-1));
- Ptr = (char*)Ptr + (MisAligned ? (A-MisAligned) : 0);
- }
- } else {
- Ptr = JCE->allocateSpace(S, A);
- }
+ // emit it into memory.
+ Ptr = getMemoryForGV(GV);
addGlobalMapping(GV, Ptr);
- EmitGlobalVariable(GV);
+ EmitGlobalVariable(GV); // Initialize the variable.
}
return Ptr;
}
@@ -742,14 +735,41 @@ void *JIT::recompileAndRelinkFunction(Function *F) {
/// on the target.
///
char* JIT::getMemoryForGV(const GlobalVariable* GV) {
- const Type *ElTy = GV->getType()->getElementType();
- size_t GVSize = (size_t)getTargetData()->getTypeAllocSize(ElTy);
+ char *Ptr;
+
+ // GlobalVariable's which are not "constant" will cause trouble in a server
+ // situation. It's returned in the same block of memory as code which may
+ // not be writable.
+ if (isGVCompilationDisabled() && !GV->isConstant()) {
+ llvm_report_error("Compilation of non-internal GlobalValue is disabled!");
+ }
+
+ // Some applications require globals and code to live together, so they may
+ // be allocated into the same buffer, but in general globals are allocated
+ // through the memory manager which puts them near the code but not in the
+ // same buffer.
+ const Type *GlobalType = GV->getType()->getElementType();
+ size_t S = getTargetData()->getTypeAllocSize(GlobalType);
+ size_t A = getTargetData()->getPreferredAlignment(GV);
if (GV->isThreadLocal()) {
MutexGuard locked(lock);
- return TJI.allocateThreadLocalMemory(GVSize);
+ Ptr = TJI.allocateThreadLocalMemory(S);
+ } else if (TJI.allocateSeparateGVMemory()) {
+ if (A <= 8) {
+ Ptr = (char*)malloc(S);
+ } else {
+ // Allocate S+A bytes of memory, then use an aligned pointer within that
+ // space.
+ Ptr = (char*)malloc(S+A);
+ unsigned MisAligned = ((intptr_t)Ptr & (A-1));
+ Ptr = Ptr + (MisAligned ? (A-MisAligned) : 0);
+ }
+ } else if (AllocateGVsWithCode) {
+ Ptr = (char*)JCE->allocateSpace(S, A);
} else {
- return new char[GVSize];
+ Ptr = (char*)JCE->allocateGlobal(S, A);
}
+ return Ptr;
}
void JIT::addPendingFunction(Function *F) {
diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h
index 66417a7..525cc84 100644
--- a/lib/ExecutionEngine/JIT/JIT.h
+++ b/lib/ExecutionEngine/JIT/JIT.h
@@ -16,11 +16,12 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/PassManager.h"
+#include "llvm/Support/ValueHandle.h"
namespace llvm {
class Function;
-class JITEvent_EmittedFunctionDetails;
+struct JITEvent_EmittedFunctionDetails;
class MachineCodeEmitter;
class MachineCodeInfo;
class TargetJITInfo;
@@ -33,7 +34,7 @@ private:
/// PendingFunctions - Functions which have not been code generated yet, but
/// were called from a function being code generated.
- std::vector<Function*> PendingFunctions;
+ std::vector<AssertingVH<Function> > PendingFunctions;
public:
explicit JITState(ModuleProvider *MP) : PM(MP), MP(MP) {}
@@ -43,7 +44,7 @@ public:
}
ModuleProvider *getMP() const { return MP; }
- std::vector<Function*> &getPendingFunctions(const MutexGuard &L) {
+ std::vector<AssertingVH<Function> > &getPendingFunctions(const MutexGuard &L){
return PendingFunctions;
}
};
@@ -55,10 +56,16 @@ class JIT : public ExecutionEngine {
JITCodeEmitter *JCE; // JCE object
std::vector<JITEventListener*> EventListeners;
+ /// AllocateGVsWithCode - Some applications require that global variables and
+ /// code be allocated into the same region of memory, in which case this flag
+ /// should be set to true. Doing so breaks freeMachineCodeForFunction.
+ bool AllocateGVsWithCode;
+
JITState *jitstate;
- JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji,
- JITMemoryManager *JMM, CodeGenOpt::Level OptLevel);
+ JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji,
+ JITMemoryManager *JMM, CodeGenOpt::Level OptLevel,
+ bool AllocateGVsWithCode);
public:
~JIT();
@@ -73,10 +80,13 @@ public:
/// create - Create an return a new JIT compiler if there is one available
/// for the current target. Otherwise, return null.
///
- static ExecutionEngine *create(ModuleProvider *MP, std::string *Err,
+ static ExecutionEngine *create(ModuleProvider *MP,
+ std::string *Err,
+ JITMemoryManager *JMM,
CodeGenOpt::Level OptLevel =
- CodeGenOpt::Default) {
- return createJIT(MP, Err, 0, OptLevel);
+ CodeGenOpt::Default,
+ bool GVsWithCode = true) {
+ return ExecutionEngine::createJIT(MP, Err, JMM, OptLevel, GVsWithCode);
}
virtual void addModuleProvider(ModuleProvider *MP);
@@ -145,16 +155,22 @@ public:
/// addPendingFunction - while jitting non-lazily, a called but non-codegen'd
/// function was encountered. Add it to a pending list to be processed after
/// the current function.
- ///
+ ///
void addPendingFunction(Function *F);
-
+
/// getCodeEmitter - Return the code emitter this JIT is emitting into.
+ ///
JITCodeEmitter *getCodeEmitter() const { return JCE; }
-
- static ExecutionEngine *createJIT(ModuleProvider *MP, std::string *Err,
- JITMemoryManager *JMM,
- CodeGenOpt::Level OptLevel);
+ /// selectTarget - Pick a target either via -march or by guessing the native
+ /// arch. Add any CPU features specified via -mcpu or -mattr.
+ static TargetMachine *selectTarget(ModuleProvider *MP, std::string *Err);
+
+ static ExecutionEngine *createJIT(ModuleProvider *MP,
+ std::string *ErrorStr,
+ JITMemoryManager *JMM,
+ CodeGenOpt::Level OptLevel,
+ bool GVsWithCode);
// Run the JIT on F and return information about the generated code
void runJITOnFunction(Function *F, MachineCodeInfo *MCI = 0);
@@ -170,7 +186,8 @@ public:
void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
private:
- static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM);
+ static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM,
+ TargetMachine &tm);
void runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked);
void updateFunctionStub(Function *F);
void updateDlsymStubTable();
diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
new file mode 100644
index 0000000..fa64010
--- /dev/null
+++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
@@ -0,0 +1,208 @@
+//===-- JITDebugRegisterer.cpp - Register debug symbols for JIT -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a JITDebugRegisterer object that is used by the JIT to
+// register debug info with debuggers like GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JITDebugRegisterer.h"
+#include "../../CodeGen/ELF.h"
+#include "../../CodeGen/ELFWriter.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Mutex.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ // Debuggers puts a breakpoint in this function.
+ void DISABLE_INLINE __jit_debug_register_code() { }
+
+ // We put information about the JITed function in this global, which the
+ // debugger reads. Make sure to specify the version statically, because the
+ // debugger checks the version before we can set it during runtime.
+ struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+}
+
+namespace {
+
+ /// JITDebugLock - Used to serialize all code registration events, since they
+ /// modify global variables.
+ sys::Mutex JITDebugLock;
+
+}
+
+JITDebugRegisterer::JITDebugRegisterer(TargetMachine &tm) : TM(tm), FnMap() { }
+
+JITDebugRegisterer::~JITDebugRegisterer() {
+ // Free all ELF memory.
+ for (RegisteredFunctionsMap::iterator I = FnMap.begin(), E = FnMap.end();
+ I != E; ++I) {
+ // Call the private method that doesn't update the map so our iterator
+ // doesn't break.
+ UnregisterFunctionInternal(I);
+ }
+ FnMap.clear();
+}
+
+std::string JITDebugRegisterer::MakeELF(const Function *F, DebugInfo &I) {
+ // Stack allocate an empty module with an empty LLVMContext for the ELFWriter
+ // API. We don't use the real module because then the ELFWriter would write
+ // out unnecessary GlobalValues during finalization.
+ LLVMContext Context;
+ Module M("", Context);
+
+ // Make a buffer for the ELF in memory.
+ std::string Buffer;
+ raw_string_ostream O(Buffer);
+ ELFWriter EW(O, TM);
+ EW.doInitialization(M);
+
+ // Copy the binary into the .text section. This isn't necessary, but it's
+ // useful to be able to disassemble the ELF by hand.
+ ELFSection &Text = EW.getTextSection((Function *)F);
+ Text.Addr = (uint64_t)I.FnStart;
+ // TODO: We could eliminate this copy if we somehow used a pointer/size pair
+ // instead of a vector.
+ Text.getData().assign(I.FnStart, I.FnEnd);
+
+ // Copy the exception handling call frame information into the .eh_frame
+ // section. This allows GDB to get a good stack trace, particularly on
+ // linux x86_64. Mark this as a PROGBITS section that needs to be loaded
+ // into memory at runtime.
+ ELFSection &EH = EW.getSection(".eh_frame", ELFSection::SHT_PROGBITS,
+ ELFSection::SHF_ALLOC);
+ // Pointers in the DWARF EH info are all relative to the EH frame start,
+ // which is stored here.
+ EH.Addr = (uint64_t)I.EhStart;
+ // TODO: We could eliminate this copy if we somehow used a pointer/size pair
+ // instead of a vector.
+ EH.getData().assign(I.EhStart, I.EhEnd);
+
+ // Add this single function to the symbol table, so the debugger prints the
+ // name instead of '???'. We give the symbol default global visibility.
+ ELFSym *FnSym = ELFSym::getGV(F,
+ ELFSym::STB_GLOBAL,
+ ELFSym::STT_FUNC,
+ ELFSym::STV_DEFAULT);
+ FnSym->SectionIdx = Text.SectionIdx;
+ FnSym->Size = I.FnEnd - I.FnStart;
+ FnSym->Value = 0; // Offset from start of section.
+ EW.SymbolList.push_back(FnSym);
+
+ EW.doFinalization(M);
+ O.flush();
+
+ // When trying to debug why GDB isn't getting the debug info right, it's
+ // awfully helpful to write the object file to disk so that it can be
+ // inspected with readelf and objdump.
+ if (JITEmitDebugInfoToDisk) {
+ std::string Filename;
+ raw_string_ostream O2(Filename);
+ O2 << "/tmp/llvm_function_" << I.FnStart << "_" << F->getNameStr() << ".o";
+ O2.flush();
+ std::string Errors;
+ raw_fd_ostream O3(Filename.c_str(), Errors);
+ O3 << Buffer;
+ O3.close();
+ }
+
+ return Buffer;
+}
+
+void JITDebugRegisterer::RegisterFunction(const Function *F, DebugInfo &I) {
+ // TODO: Support non-ELF platforms.
+ if (!TM.getELFWriterInfo())
+ return;
+
+ std::string Buffer = MakeELF(F, I);
+
+ jit_code_entry *JITCodeEntry = new jit_code_entry();
+ JITCodeEntry->symfile_addr = Buffer.c_str();
+ JITCodeEntry->symfile_size = Buffer.size();
+
+ // Add a mapping from F to the entry and buffer, so we can delete this
+ // info later.
+ FnMap[F] = std::make_pair<std::string, jit_code_entry*>(Buffer, JITCodeEntry);
+
+ // Acquire the lock and do the registration.
+ {
+ MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+
+ // Insert this entry at the head of the list.
+ JITCodeEntry->prev_entry = NULL;
+ jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
+ JITCodeEntry->next_entry = NextEntry;
+ if (NextEntry != NULL) {
+ NextEntry->prev_entry = JITCodeEntry;
+ }
+ __jit_debug_descriptor.first_entry = JITCodeEntry;
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+ }
+}
+
+void JITDebugRegisterer::UnregisterFunctionInternal(
+ RegisteredFunctionsMap::iterator I) {
+ jit_code_entry *JITCodeEntry = I->second.second;
+
+ // Acquire the lock and do the unregistration.
+ {
+ MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+
+ // Remove the jit_code_entry from the linked list.
+ jit_code_entry *PrevEntry = JITCodeEntry->prev_entry;
+ jit_code_entry *NextEntry = JITCodeEntry->next_entry;
+ if (NextEntry) {
+ NextEntry->prev_entry = PrevEntry;
+ }
+ if (PrevEntry) {
+ PrevEntry->next_entry = NextEntry;
+ } else {
+ assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
+ __jit_debug_descriptor.first_entry = NextEntry;
+ }
+
+ // Tell GDB which entry we removed, and unregister the code.
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+ }
+
+ // Free the ELF file in memory.
+ std::string &Buffer = I->second.first;
+ Buffer.clear();
+}
+
+void JITDebugRegisterer::UnregisterFunction(const Function *F) {
+ // TODO: Support non-ELF platforms.
+ if (!TM.getELFWriterInfo())
+ return;
+
+ RegisteredFunctionsMap::iterator I = FnMap.find(F);
+ if (I == FnMap.end()) return;
+ UnregisterFunctionInternal(I);
+ FnMap.erase(I);
+}
+
+} // end namespace llvm
diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h
new file mode 100644
index 0000000..dce506b
--- /dev/null
+++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h
@@ -0,0 +1,116 @@
+//===-- JITDebugRegisterer.h - Register debug symbols for JIT -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a JITDebugRegisterer object that is used by the JIT to
+// register debug info with debuggers like GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H
+#define LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/DataTypes.h"
+#include <string>
+
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+ } jit_actions_t;
+
+ struct jit_code_entry {
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+ };
+
+ struct jit_descriptor {
+ uint32_t version;
+ // This should be jit_actions_t, but we want to be specific about the
+ // bit-width.
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+ };
+
+}
+
+namespace llvm {
+
+class ELFSection;
+class Function;
+class TargetMachine;
+
+
+/// This class encapsulates information we want to send to the debugger.
+///
+struct DebugInfo {
+ uint8_t *FnStart;
+ uint8_t *FnEnd;
+ uint8_t *EhStart;
+ uint8_t *EhEnd;
+
+ DebugInfo() : FnStart(0), FnEnd(0), EhStart(0), EhEnd(0) {}
+};
+
+typedef DenseMap< const Function*, std::pair<std::string, jit_code_entry*> >
+ RegisteredFunctionsMap;
+
+/// This class registers debug info for JITed code with an attached debugger.
+/// Without proper debug info, GDB can't do things like source level debugging
+/// or even produce a proper stack trace on linux-x86_64. To use this class,
+/// whenever a function is JITed, create a DebugInfo struct and pass it to the
+/// RegisterFunction method. The method will then do whatever is necessary to
+/// inform the debugger about the JITed function.
+class JITDebugRegisterer {
+
+ TargetMachine &TM;
+
+ /// FnMap - A map of functions that have been registered to the associated
+ /// temporary files. Used for cleanup.
+ RegisteredFunctionsMap FnMap;
+
+ /// MakeELF - Builds the ELF file in memory and returns a std::string that
+ /// contains the ELF.
+ std::string MakeELF(const Function *F, DebugInfo &I);
+
+public:
+ JITDebugRegisterer(TargetMachine &tm);
+
+ /// ~JITDebugRegisterer - Unregisters all code and frees symbol files.
+ ///
+ ~JITDebugRegisterer();
+
+ /// RegisterFunction - Register debug info for the given function with an
+ /// attached debugger. Clients must call UnregisterFunction on all
+ /// registered functions before deleting them to free the associated symbol
+ /// file and unregister it from the debugger.
+ void RegisterFunction(const Function *F, DebugInfo &I);
+
+ /// UnregisterFunction - Unregister the debug info for the given function
+ /// from the debugger and free associated memory.
+ void UnregisterFunction(const Function *F);
+
+private:
+ /// UnregisterFunctionInternal - Unregister the debug info for the given
+ /// function from the debugger and delete any temporary files. The private
+ /// version of this method does not remove the function from FnMap so that it
+ /// can be called while iterating over FnMap.
+ void UnregisterFunctionInternal(RegisteredFunctionsMap::iterator I);
+
+};
+
+} // end namespace llvm
+
+#endif // LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H
diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp
index e101ef3..f2b28ad 100644
--- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp
+++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp
@@ -21,25 +21,27 @@
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
-#include "llvm/Target/TargetAsmInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
-
using namespace llvm;
-JITDwarfEmitter::JITDwarfEmitter(JIT& theJit) : Jit(theJit) {}
+JITDwarfEmitter::JITDwarfEmitter(JIT& theJit) : MMI(0), Jit(theJit) {}
unsigned char* JITDwarfEmitter::EmitDwarfTable(MachineFunction& F,
JITCodeEmitter& jce,
unsigned char* StartFunction,
- unsigned char* EndFunction) {
+ unsigned char* EndFunction,
+ unsigned char* &EHFramePtr) {
+ assert(MMI && "MachineModuleInfo not registered!");
+
const TargetMachine& TM = F.getTarget();
TD = TM.getTargetData();
- needsIndirectEncoding = TM.getTargetAsmInfo()->getNeedsIndirectEncoding();
stackGrowthDirection = TM.getFrameInfo()->getStackGrowthDirection();
RI = TM.getRegisterInfo();
JCE = &jce;
@@ -48,14 +50,13 @@ unsigned char* JITDwarfEmitter::EmitDwarfTable(MachineFunction& F,
EndFunction);
unsigned char* Result = 0;
- unsigned char* EHFramePtr = 0;
const std::vector<Function *> Personalities = MMI->getPersonalities();
EHFramePtr = EmitCommonEHFrame(Personalities[MMI->getPersonalityIndex()]);
Result = EmitEHFrame(Personalities[MMI->getPersonalityIndex()], EHFramePtr,
StartFunction, EndFunction, ExceptionTable);
-
+
return Result;
}
@@ -106,11 +107,9 @@ JITDwarfEmitter::EmitFrameMoves(intptr_t BaseLabelPtr,
JCE->emitULEB128Bytes(RI->getDwarfRegNum(Src.getReg(), true));
}
- int Offset = -Src.getOffset();
-
- JCE->emitULEB128Bytes(Offset);
+ JCE->emitULEB128Bytes(-Src.getOffset());
} else {
- assert(0 && "Machine move no supported yet.");
+ llvm_unreachable("Machine move not supported yet.");
}
} else if (Src.isReg() &&
Src.getReg() == MachineLocation::VirtualFP) {
@@ -118,7 +117,7 @@ JITDwarfEmitter::EmitFrameMoves(intptr_t BaseLabelPtr,
JCE->emitByte(dwarf::DW_CFA_def_cfa_register);
JCE->emitULEB128Bytes(RI->getDwarfRegNum(Dst.getReg(), true));
} else {
- assert(0 && "Machine move no supported yet.");
+ llvm_unreachable("Machine move not supported yet.");
}
} else {
unsigned Reg = RI->getDwarfRegNum(Src.getReg(), true);
@@ -209,6 +208,8 @@ struct CallSiteEntry {
unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
unsigned char* StartFunction,
unsigned char* EndFunction) const {
+ assert(MMI && "MachineModuleInfo not registered!");
+
// Map all labels and get rid of any dead landing pads.
MMI->TidyLandingPads();
@@ -241,7 +242,7 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
for(std::vector<unsigned>::const_iterator I = FilterIds.begin(),
E = FilterIds.end(); I != E; ++I) {
FilterOffsets.push_back(Offset);
- Offset -= TargetAsmInfo::getULEB128Size(*I);
+ Offset -= MCAsmInfo::getULEB128Size(*I);
}
// Compute the actions table and gather the first action index for each
@@ -266,10 +267,10 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size();
assert(Actions.size());
PrevAction = &Actions.back();
- SizeAction = TargetAsmInfo::getSLEB128Size(PrevAction->NextAction) +
- TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
+ SizeAction = MCAsmInfo::getSLEB128Size(PrevAction->NextAction) +
+ MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
for (unsigned j = NumShared; j != SizePrevIds; ++j) {
- SizeAction -= TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
+ SizeAction -= MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
SizeAction += -PrevAction->NextAction;
PrevAction = PrevAction->Previous;
}
@@ -280,10 +281,10 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
int TypeID = TypeIds[I];
assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
- unsigned SizeTypeID = TargetAsmInfo::getSLEB128Size(ValueForTypeID);
+ unsigned SizeTypeID = MCAsmInfo::getSLEB128Size(ValueForTypeID);
int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
- SizeAction = SizeTypeID + TargetAsmInfo::getSLEB128Size(NextAction);
+ SizeAction = SizeTypeID + MCAsmInfo::getSLEB128Size(NextAction);
SizeSiteActions += SizeAction;
ActionEntry Action = {ValueForTypeID, NextAction, PrevAction};
@@ -386,29 +387,19 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
sizeof(int32_t) + // Site length.
sizeof(int32_t)); // Landing pad.
for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
- SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action);
+ SizeSites += MCAsmInfo::getULEB128Size(CallSites[i].Action);
unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize();
unsigned TypeOffset = sizeof(int8_t) + // Call site format
// Call-site table length
- TargetAsmInfo::getULEB128Size(SizeSites) +
+ MCAsmInfo::getULEB128Size(SizeSites) +
SizeSites + SizeActions + SizeTypes;
- unsigned TotalSize = sizeof(int8_t) + // LPStart format
- sizeof(int8_t) + // TType format
- TargetAsmInfo::getULEB128Size(TypeOffset) + // TType base offset
- TypeOffset;
-
- unsigned SizeAlign = (4 - TotalSize) & 3;
-
// Begin the exception table.
- JCE->emitAlignment(4);
- for (unsigned i = 0; i != SizeAlign; ++i) {
- JCE->emitByte(0);
- // Asm->EOL("Padding");
- }
-
+ JCE->emitAlignmentWithFill(4, 0);
+ // Asm->EOL("Padding");
+
unsigned char* DwarfExceptionTable = (unsigned char*)JCE->getCurrentPCValue();
// Emit the header.
@@ -475,11 +466,10 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
GlobalVariable *GV = TypeInfos[M - 1];
if (GV) {
- if (TD->getPointerSize() == sizeof(int32_t)) {
+ if (TD->getPointerSize() == sizeof(int32_t))
JCE->emitInt32((intptr_t)Jit.getOrEmitGlobalVariable(GV));
- } else {
+ else
JCE->emitInt64((intptr_t)Jit.getOrEmitGlobalVariable(GV));
- }
} else {
if (TD->getPointerSize() == sizeof(int32_t))
JCE->emitInt32(0);
@@ -495,8 +485,8 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
JCE->emitULEB128Bytes(TypeID);
//Asm->EOL("Filter TypeInfo index");
}
-
- JCE->emitAlignment(4);
+
+ JCE->emitAlignmentWithFill(4, 0);
return DwarfExceptionTable;
}
@@ -517,7 +507,7 @@ JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const {
JCE->emitULEB128Bytes(1);
JCE->emitSLEB128Bytes(stackGrowth);
JCE->emitByte(RI->getDwarfRegNum(RI->getRARegister(), true));
-
+
if (Personality) {
// Augmentation Size: 3 small ULEBs of one byte each, and the personality
// function which size is PointerSize.
@@ -533,10 +523,9 @@ JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const {
JCE->emitByte(dwarf::DW_EH_PE_sdata8);
JCE->emitInt64(((intptr_t)Jit.getPointerToGlobal(Personality)));
}
-
+
JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
-
} else {
JCE->emitULEB128Bytes(1);
JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
@@ -545,11 +534,12 @@ JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const {
std::vector<MachineMove> Moves;
RI->getInitialFrameState(Moves);
EmitFrameMoves(0, Moves);
- JCE->emitAlignment(PointerSize);
-
- JCE->emitInt32At((uintptr_t*)StartCommonPtr,
- (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() -
- FrameCommonBeginPtr));
+
+ JCE->emitAlignmentWithFill(PointerSize, dwarf::DW_CFA_nop);
+
+ JCE->emitInt32At((uintptr_t*)StartCommonPtr,
+ (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() -
+ FrameCommonBeginPtr));
return StartCommonPtr;
}
@@ -574,13 +564,19 @@ JITDwarfEmitter::EmitEHFrame(const Function* Personality,
// If there is a personality and landing pads then point to the language
// specific data area in the exception table.
- if (MMI->getPersonalityIndex()) {
- JCE->emitULEB128Bytes(4);
+ if (Personality) {
+ JCE->emitULEB128Bytes(PointerSize == 4 ? 4 : 8);
- if (!MMI->getLandingPads().empty()) {
- JCE->emitInt32(ExceptionTable - (unsigned char*)JCE->getCurrentPCValue());
+ if (PointerSize == 4) {
+ if (!MMI->getLandingPads().empty())
+ JCE->emitInt32(ExceptionTable-(unsigned char*)JCE->getCurrentPCValue());
+ else
+ JCE->emitInt32((int)0);
} else {
- JCE->emitInt32((int)0);
+ if (!MMI->getLandingPads().empty())
+ JCE->emitInt64(ExceptionTable-(unsigned char*)JCE->getCurrentPCValue());
+ else
+ JCE->emitInt64((int)0);
}
} else {
JCE->emitULEB128Bytes(0);
@@ -589,14 +585,14 @@ JITDwarfEmitter::EmitEHFrame(const Function* Personality,
// Indicate locations of function specific callee saved registers in
// frame.
EmitFrameMoves((intptr_t)StartFunction, MMI->getFrameMoves());
-
- JCE->emitAlignment(PointerSize);
-
+
+ JCE->emitAlignmentWithFill(PointerSize, dwarf::DW_CFA_nop);
+
// Indicate the size of the table
- JCE->emitInt32At((uintptr_t*)StartEHPtr,
- (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() -
- StartEHPtr));
-
+ JCE->emitInt32At((uintptr_t*)StartEHPtr,
+ (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() -
+ StartEHPtr));
+
// Double zeroes for the unwind runtime
if (PointerSize == 8) {
JCE->emitInt64(0);
@@ -605,7 +601,6 @@ JITDwarfEmitter::EmitEHFrame(const Function* Personality,
JCE->emitInt32(0);
JCE->emitInt32(0);
}
-
return StartEHPtr;
}
@@ -616,7 +611,6 @@ unsigned JITDwarfEmitter::GetDwarfTableSizeInBytes(MachineFunction& F,
unsigned char* EndFunction) {
const TargetMachine& TM = F.getTarget();
TD = TM.getTargetData();
- needsIndirectEncoding = TM.getTargetAsmInfo()->getNeedsIndirectEncoding();
stackGrowthDirection = TM.getFrameInfo()->getStackGrowthDirection();
RI = TM.getRegisterInfo();
JCE = &jce;
@@ -630,7 +624,7 @@ unsigned JITDwarfEmitter::GetDwarfTableSizeInBytes(MachineFunction& F,
FinalSize += GetEHFrameSizeInBytes(Personalities[MMI->getPersonalityIndex()],
StartFunction);
-
+
return FinalSize;
}
@@ -653,11 +647,11 @@ JITDwarfEmitter::GetEHFrameSizeInBytes(const Function* Personality,
FinalSize += 3 * PointerSize;
// If there is a personality and landing pads then point to the language
// specific data area in the exception table.
- if (MMI->getPersonalityIndex()) {
- FinalSize += TargetAsmInfo::getULEB128Size(4);
+ if (Personality) {
+ FinalSize += MCAsmInfo::getULEB128Size(4);
FinalSize += PointerSize;
} else {
- FinalSize += TargetAsmInfo::getULEB128Size(0);
+ FinalSize += MCAsmInfo::getULEB128Size(0);
}
// Indicate locations of function specific callee saved registers in
@@ -685,24 +679,24 @@ unsigned JITDwarfEmitter::GetCommonEHFrameSizeInBytes(const Function* Personalit
FinalSize += 4;
FinalSize += 1;
FinalSize += Personality ? 5 : 3; // "zPLR" or "zR"
- FinalSize += TargetAsmInfo::getULEB128Size(1);
- FinalSize += TargetAsmInfo::getSLEB128Size(stackGrowth);
+ FinalSize += MCAsmInfo::getULEB128Size(1);
+ FinalSize += MCAsmInfo::getSLEB128Size(stackGrowth);
FinalSize += 1;
if (Personality) {
- FinalSize += TargetAsmInfo::getULEB128Size(7);
+ FinalSize += MCAsmInfo::getULEB128Size(7);
// Encoding
FinalSize+= 1;
//Personality
FinalSize += PointerSize;
- FinalSize += TargetAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
- FinalSize += TargetAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
+ FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
+ FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
} else {
- FinalSize += TargetAsmInfo::getULEB128Size(1);
- FinalSize += TargetAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
+ FinalSize += MCAsmInfo::getULEB128Size(1);
+ FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel);
}
std::vector<MachineMove> Moves;
@@ -754,23 +748,23 @@ JITDwarfEmitter::GetFrameMovesSizeInBytes(intptr_t BaseLabelPtr,
} else {
++FinalSize;
unsigned RegNum = RI->getDwarfRegNum(Src.getReg(), true);
- FinalSize += TargetAsmInfo::getULEB128Size(RegNum);
+ FinalSize += MCAsmInfo::getULEB128Size(RegNum);
}
int Offset = -Src.getOffset();
- FinalSize += TargetAsmInfo::getULEB128Size(Offset);
+ FinalSize += MCAsmInfo::getULEB128Size(Offset);
} else {
- assert(0 && "Machine move no supported yet.");
+ llvm_unreachable("Machine move no supported yet.");
}
} else if (Src.isReg() &&
Src.getReg() == MachineLocation::VirtualFP) {
if (Dst.isReg()) {
++FinalSize;
unsigned RegNum = RI->getDwarfRegNum(Dst.getReg(), true);
- FinalSize += TargetAsmInfo::getULEB128Size(RegNum);
+ FinalSize += MCAsmInfo::getULEB128Size(RegNum);
} else {
- assert(0 && "Machine move no supported yet.");
+ llvm_unreachable("Machine move no supported yet.");
}
} else {
unsigned Reg = RI->getDwarfRegNum(Src.getReg(), true);
@@ -778,15 +772,15 @@ JITDwarfEmitter::GetFrameMovesSizeInBytes(intptr_t BaseLabelPtr,
if (Offset < 0) {
++FinalSize;
- FinalSize += TargetAsmInfo::getULEB128Size(Reg);
- FinalSize += TargetAsmInfo::getSLEB128Size(Offset);
+ FinalSize += MCAsmInfo::getULEB128Size(Reg);
+ FinalSize += MCAsmInfo::getSLEB128Size(Offset);
} else if (Reg < 64) {
++FinalSize;
- FinalSize += TargetAsmInfo::getULEB128Size(Offset);
+ FinalSize += MCAsmInfo::getULEB128Size(Offset);
} else {
++FinalSize;
- FinalSize += TargetAsmInfo::getULEB128Size(Reg);
- FinalSize += TargetAsmInfo::getULEB128Size(Offset);
+ FinalSize += MCAsmInfo::getULEB128Size(Reg);
+ FinalSize += MCAsmInfo::getULEB128Size(Offset);
}
}
}
@@ -829,7 +823,7 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
for(std::vector<unsigned>::const_iterator I = FilterIds.begin(),
E = FilterIds.end(); I != E; ++I) {
FilterOffsets.push_back(Offset);
- Offset -= TargetAsmInfo::getULEB128Size(*I);
+ Offset -= MCAsmInfo::getULEB128Size(*I);
}
// Compute the actions table and gather the first action index for each
@@ -854,10 +848,10 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size();
assert(Actions.size());
PrevAction = &Actions.back();
- SizeAction = TargetAsmInfo::getSLEB128Size(PrevAction->NextAction) +
- TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
+ SizeAction = MCAsmInfo::getSLEB128Size(PrevAction->NextAction) +
+ MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
for (unsigned j = NumShared; j != SizePrevIds; ++j) {
- SizeAction -= TargetAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
+ SizeAction -= MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
SizeAction += -PrevAction->NextAction;
PrevAction = PrevAction->Previous;
}
@@ -868,10 +862,10 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
int TypeID = TypeIds[I];
assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
- unsigned SizeTypeID = TargetAsmInfo::getSLEB128Size(ValueForTypeID);
+ unsigned SizeTypeID = MCAsmInfo::getSLEB128Size(ValueForTypeID);
int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
- SizeAction = SizeTypeID + TargetAsmInfo::getSLEB128Size(NextAction);
+ SizeAction = SizeTypeID + MCAsmInfo::getSLEB128Size(NextAction);
SizeSiteActions += SizeAction;
ActionEntry Action = {ValueForTypeID, NextAction, PrevAction};
@@ -974,18 +968,18 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
sizeof(int32_t) + // Site length.
sizeof(int32_t)); // Landing pad.
for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
- SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action);
+ SizeSites += MCAsmInfo::getULEB128Size(CallSites[i].Action);
unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize();
unsigned TypeOffset = sizeof(int8_t) + // Call site format
// Call-site table length
- TargetAsmInfo::getULEB128Size(SizeSites) +
+ MCAsmInfo::getULEB128Size(SizeSites) +
SizeSites + SizeActions + SizeTypes;
unsigned TotalSize = sizeof(int8_t) + // LPStart format
sizeof(int8_t) + // TType format
- TargetAsmInfo::getULEB128Size(TypeOffset) + // TType base offset
+ MCAsmInfo::getULEB128Size(TypeOffset) + // TType base offset
TypeOffset;
unsigned SizeAlign = (4 - TotalSize) & 3;
@@ -1023,7 +1017,7 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
// Asm->EOL("Landing pad");
FinalSize += PointerSize;
- FinalSize += TargetAsmInfo::getULEB128Size(S.Action);
+ FinalSize += MCAsmInfo::getULEB128Size(S.Action);
// Asm->EOL("Action");
}
@@ -1032,9 +1026,9 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
ActionEntry &Action = Actions[I];
//Asm->EOL("TypeInfo index");
- FinalSize += TargetAsmInfo::getSLEB128Size(Action.ValueForTypeID);
+ FinalSize += MCAsmInfo::getSLEB128Size(Action.ValueForTypeID);
//Asm->EOL("Next action");
- FinalSize += TargetAsmInfo::getSLEB128Size(Action.NextAction);
+ FinalSize += MCAsmInfo::getSLEB128Size(Action.NextAction);
}
// Emit the type ids.
@@ -1046,7 +1040,7 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const {
// Emit the filter typeids.
for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) {
unsigned TypeID = FilterIds[j];
- FinalSize += TargetAsmInfo::getULEB128Size(TypeID);
+ FinalSize += MCAsmInfo::getULEB128Size(TypeID);
//Asm->EOL("Filter TypeInfo index");
}
diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h
index 9120ed4..e627550 100644
--- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h
+++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h
@@ -32,7 +32,6 @@ class JITDwarfEmitter {
const TargetRegisterInfo* RI;
MachineModuleInfo* MMI;
JIT& Jit;
- bool needsIndirectEncoding;
bool stackGrowthDirection;
unsigned char* EmitExceptionTable(MachineFunction* MF,
@@ -68,7 +67,8 @@ public:
unsigned char* EmitDwarfTable(MachineFunction& F,
JITCodeEmitter& JCE,
unsigned char* StartFunction,
- unsigned char* EndFunction);
+ unsigned char* EndFunction,
+ unsigned char* &EHFramePtr);
unsigned GetDwarfTableSizeInBytes(MachineFunction& F,
diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp
index 8fe7ab8..eacd9f9 100644
--- a/lib/ExecutionEngine/JIT/JITEmitter.cpp
+++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp
@@ -14,7 +14,9 @@
#define DEBUG_TYPE "jit"
#include "JIT.h"
+#include "JITDebugRegisterer.h"
#include "JITDwarfEmitter.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
@@ -33,8 +35,10 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Disassembler.h"
#include "llvm/System/Memory.h"
#include "llvm/Target/TargetInstrInfo.h"
@@ -49,6 +53,7 @@ using namespace llvm;
STATISTIC(NumBytes, "Number of bytes of machine code compiled");
STATISTIC(NumRelos, "Number of relocations applied");
+STATISTIC(NumRetries, "Number of retries with more memory");
static JIT *TheJIT = 0;
@@ -59,7 +64,7 @@ namespace {
class JITResolverState {
public:
typedef std::map<AssertingVH<Function>, void*> FunctionToStubMapTy;
- typedef std::map<void*, Function*> StubToFunctionMapTy;
+ typedef std::map<void*, AssertingVH<Function> > StubToFunctionMapTy;
typedef std::map<AssertingVH<GlobalValue>, void*> GlobalToIndirectSymMapTy;
private:
/// FunctionToStubMap - Keep track of the stub created for a particular
@@ -193,9 +198,9 @@ void *JITResolver::getFunctionStub(Function *F) {
// Call the lazy resolver function unless we are JIT'ing non-lazily, in which
// case we must resolve the symbol now.
- void *Actual = TheJIT->isLazyCompilationDisabled()
+ void *Actual = TheJIT->isLazyCompilationDisabled()
? (void *)0 : (void *)(intptr_t)LazyResolverFn;
-
+
// If this is an external declaration, attempt to resolve the address now
// to place in the stub.
if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode()) {
@@ -220,20 +225,20 @@ void *JITResolver::getFunctionStub(Function *F) {
TheJIT->updateGlobalMapping(F, Stub);
}
- DOUT << "JIT: Stub emitted at [" << Stub << "] for function '"
- << F->getName() << "'\n";
+ DEBUG(errs() << "JIT: Stub emitted at [" << Stub << "] for function '"
+ << F->getName() << "'\n");
// Finally, keep track of the stub-to-Function mapping so that the
// JITCompilerFn knows which function to compile!
state.getStubToFunctionMap(locked)[Stub] = F;
-
+
// If we are JIT'ing non-lazily but need to call a function that does not
// exist yet, add it to the JIT's work list so that we can fill in the stub
// address later.
if (!Actual && TheJIT->isLazyCompilationDisabled())
if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode())
TheJIT->addPendingFunction(F);
-
+
return Stub;
}
@@ -250,8 +255,8 @@ void *JITResolver::getGlobalValueIndirectSym(GlobalValue *GV, void *GVAddress) {
IndirectSym = TheJIT->getJITInfo().emitGlobalValueIndirectSym(GV, GVAddress,
*TheJIT->getCodeEmitter());
- DOUT << "JIT: Indirect symbol emitted at [" << IndirectSym << "] for GV '"
- << GV->getName() << "'\n";
+ DEBUG(errs() << "JIT: Indirect symbol emitted at [" << IndirectSym
+ << "] for GV '" << GV->getName() << "'\n");
return IndirectSym;
}
@@ -266,8 +271,8 @@ void *JITResolver::getExternalFunctionStub(void *FnAddr) {
Stub = TheJIT->getJITInfo().emitFunctionStub(0, FnAddr,
*TheJIT->getCodeEmitter());
- DOUT << "JIT: Stub emitted at [" << Stub
- << "] for external function at '" << FnAddr << "'\n";
+ DEBUG(errs() << "JIT: Stub emitted at [" << Stub
+ << "] for external function at '" << FnAddr << "'\n");
return Stub;
}
@@ -276,7 +281,8 @@ unsigned JITResolver::getGOTIndexForAddr(void* addr) {
if (!idx) {
idx = ++nextGOTIndex;
revGOTMap[addr] = idx;
- DOUT << "JIT: Adding GOT entry " << idx << " for addr [" << addr << "]\n";
+ DEBUG(errs() << "JIT: Adding GOT entry " << idx << " for addr ["
+ << addr << "]\n");
}
return idx;
}
@@ -373,9 +379,8 @@ void *JITResolver::JITCompilerFn(void *Stub) {
// If lazy compilation is disabled, emit a useful error message and abort.
if (TheJIT->isLazyCompilationDisabled()) {
- cerr << "LLVM JIT requested to do lazy compilation of function '"
- << F->getName() << "' when lazy compiles are disabled!\n";
- abort();
+ llvm_report_error("LLVM JIT requested to do lazy compilation of function '"
+ + F->getName() + "' when lazy compiles are disabled!");
}
// We might like to remove the stub from the StubToFunction map.
@@ -385,9 +390,9 @@ void *JITResolver::JITCompilerFn(void *Stub) {
// it needs to call.
//JR.state.getStubToFunctionMap(locked).erase(I);
- DOUT << "JIT: Lazily resolving function '" << F->getName()
- << "' In stub ptr = " << Stub << " actual ptr = "
- << ActualPtr << "\n";
+ DEBUG(errs() << "JIT: Lazily resolving function '" << F->getName()
+ << "' In stub ptr = " << Stub << " actual ptr = "
+ << ActualPtr << "\n");
Result = TheJIT->getPointerToFunction(F);
}
@@ -424,6 +429,12 @@ namespace {
// save BufferBegin/BufferEnd/CurBufferPtr here.
uint8_t *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr;
+ // When reattempting to JIT a function after running out of space, we store
+ // the estimated size of the function we're trying to JIT here, so we can
+ // ask the memory manager for at least this much space. When we
+ // successfully emit the function, we reset this back to zero.
+ uintptr_t SizeEstimate;
+
/// Relocations - These are the relocations that the function needs, as
/// emitted.
std::vector<MachineRelocation> Relocations;
@@ -455,9 +466,12 @@ namespace {
/// Resolver - This contains info about the currently resolved functions.
JITResolver Resolver;
-
+
/// DE - The dwarf emitter for the jit.
- JITDwarfEmitter *DE;
+ OwningPtr<JITDwarfEmitter> DE;
+
+ /// DR - The debug registerer for the jit.
+ OwningPtr<JITDebugRegisterer> DR;
/// LabelLocations - This vector is a mapping from Label ID's to their
/// address.
@@ -472,7 +486,12 @@ namespace {
// CurFn - The llvm function being emitted. Only valid during
// finishFunction().
const Function *CurFn;
-
+
+ /// Information about emitted code, which is passed to the
+ /// JITEventListeners. This is reset in startFunction and used in
+ /// finishFunction.
+ JITEvent_EmittedFunctionDetails EmissionDetails;
+
// CurFnStubUses - For a given Function, a vector of stubs that it
// references. This facilitates the JIT detecting that a stub is no
// longer used, so that it may be deallocated.
@@ -487,19 +506,26 @@ namespace {
// in the JITResolver's ExternalFnToStubMap.
StringMap<void *> ExtFnStubs;
+ DebugLocTuple PrevDLT;
+
public:
- JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0) {
+ JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM)
+ : SizeEstimate(0), Resolver(jit), MMI(0), CurFn(0) {
MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
if (jit.getJITInfo().needsGOT()) {
MemMgr->AllocateGOT();
- DOUT << "JIT is managing a GOT\n";
+ DEBUG(errs() << "JIT is managing a GOT\n");
}
- if (ExceptionHandling) DE = new JITDwarfEmitter(jit);
+ if (DwarfExceptionHandling || JITEmitDebugInfo) {
+ DE.reset(new JITDwarfEmitter(jit));
+ }
+ if (JITEmitDebugInfo) {
+ DR.reset(new JITDebugRegisterer(TM));
+ }
}
~JITEmitter() {
delete MemMgr;
- if (ExceptionHandling) delete DE;
}
/// classof - Methods for support type inquiry through isa, cast, and
@@ -527,6 +553,11 @@ namespace {
/// allocate a new one of the given size.
virtual void *allocateSpace(uintptr_t Size, unsigned Alignment);
+ /// allocateGlobal - Allocate memory for a global. Unlike allocateSpace,
+ /// this method does not allocate memory in the current output buffer,
+ /// because a global may live longer than the current function.
+ virtual void *allocateGlobal(uintptr_t Size, unsigned Alignment);
+
virtual void addRelocation(const MachineRelocation &MR) {
Relocations.push_back(MR);
}
@@ -535,8 +566,8 @@ namespace {
if (MBBLocations.size() <= (unsigned)MBB->getNumber())
MBBLocations.resize((MBB->getNumber()+1)*2);
MBBLocations[MBB->getNumber()] = getCurrentPCValue();
- DOUT << "JIT: Emitting BB" << MBB->getNumber() << " at ["
- << (void*) getCurrentPCValue() << "]\n";
+ DEBUG(errs() << "JIT: Emitting BB" << MBB->getNumber() << " at ["
+ << (void*) getCurrentPCValue() << "]\n");
}
virtual uintptr_t getConstantPoolEntryAddress(unsigned Entry) const;
@@ -548,9 +579,14 @@ namespace {
return MBBLocations[MBB->getNumber()];
}
+ /// retryWithMoreMemory - Log a retry and deallocate all memory for the
+ /// given function. Increase the minimum allocation size so that we get
+ /// more memory next time.
+ void retryWithMoreMemory(MachineFunction &F);
+
/// deallocateMemForFunction - Deallocate all memory for the specified
/// function body.
- void deallocateMemForFunction(Function *F);
+ void deallocateMemForFunction(const Function *F);
/// AddStubToCurrentFunction - Mark the current function being JIT'd as
/// using the stub at the specified address. Allows
@@ -561,6 +597,8 @@ namespace {
/// MachineRelocations that reference external functions by name.
const StringMap<void*> &getExternalFnStubs() const { return ExtFnStubs; }
+ virtual void processDebugLoc(DebugLoc DL, bool BeforePrintingInsn);
+
virtual void emitLabel(uint64_t LabelID) {
if (LabelLocations.size() <= LabelID)
LabelLocations.resize((LabelID+1)*2);
@@ -575,14 +613,14 @@ namespace {
virtual void setModuleInfo(MachineModuleInfo* Info) {
MMI = Info;
- if (ExceptionHandling) DE->setModuleInfo(Info);
+ if (DE.get()) DE->setModuleInfo(Info);
}
- void setMemoryExecutable(void) {
+ void setMemoryExecutable() {
MemMgr->setMemoryExecutable();
}
- JITMemoryManager *getMemMgr(void) const { return MemMgr; }
+ JITMemoryManager *getMemMgr() const { return MemMgr; }
private:
void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
@@ -606,7 +644,7 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
// If we have already compiled the function, return a pointer to its body.
Function *F = cast<Function>(V);
void *ResultPtr;
- if (!DoesntNeedStub && !TheJIT->isLazyCompilationDisabled()) {
+ if (!DoesntNeedStub) {
// Return the function stub if it's already created.
ResultPtr = Resolver.getFunctionStubIfAvailable(F);
if (ResultPtr)
@@ -658,11 +696,8 @@ void *JITEmitter::getPointerToGVIndirectSym(GlobalValue *V, void *Reference,
}
void JITEmitter::AddStubToCurrentFunction(void *StubAddr) {
- if (!TheJIT->areDlsymStubsEnabled())
- return;
-
assert(CurFn && "Stub added to current function, but current function is 0!");
-
+
SmallVectorImpl<void*> &StubsUsed = CurFnStubUses[CurFn];
StubsUsed.push_back(StubAddr);
@@ -670,6 +705,23 @@ void JITEmitter::AddStubToCurrentFunction(void *StubAddr) {
FnRefs.insert(CurFn);
}
+void JITEmitter::processDebugLoc(DebugLoc DL, bool BeforePrintingInsn) {
+ if (!DL.isUnknown()) {
+ DebugLocTuple CurDLT = EmissionDetails.MF->getDebugLocTuple(DL);
+
+ if (BeforePrintingInsn) {
+ if (CurDLT.Scope != 0 && PrevDLT != CurDLT) {
+ JITEvent_EmittedFunctionDetails::LineStart NextLine;
+ NextLine.Address = getCurrentPCValue();
+ NextLine.Loc = DL;
+ EmissionDetails.LineStarts.push_back(NextLine);
+ }
+
+ PrevDLT = CurDLT;
+ }
+ }
+}
+
static unsigned GetConstantPoolSizeInBytes(MachineConstantPool *MCP,
const TargetData *TD) {
const std::vector<MachineConstantPoolEntry> &Constants = MCP->getConstants();
@@ -713,7 +765,7 @@ unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV, unsigned Size) {
size_t GVSize = (size_t)TheJIT->getTargetData()->getTypeAllocSize(ElTy);
size_t GVAlign =
(size_t)TheJIT->getTargetData()->getPreferredAlignment(GV);
- DOUT << "JIT: Adding in size " << GVSize << " alignment " << GVAlign;
+ DEBUG(errs() << "JIT: Adding in size " << GVSize << " alignment " << GVAlign);
DEBUG(GV->dump());
// Assume code section ends with worst possible alignment, so first
// variable needs maximal padding.
@@ -772,8 +824,10 @@ unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant *C,
break;
}
default: {
- cerr << "ConstantExpr not handled: " << *CE << "\n";
- abort();
+ std::string msg;
+ raw_string_ostream Msg(msg);
+ Msg << "ConstantExpr not handled: " << *CE;
+ llvm_report_error(Msg.str());
}
}
}
@@ -839,7 +893,7 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
}
}
}
- DOUT << "JIT: About to look through initializers\n";
+ DEBUG(errs() << "JIT: About to look through initializers\n");
// Look for more globals that are referenced only from initializers.
// GVSet.end is computed each time because the set can grow as we go.
for (SmallPtrSet<const GlobalVariable *, 8>::iterator I = GVSet.begin();
@@ -853,14 +907,14 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
}
void JITEmitter::startFunction(MachineFunction &F) {
- DOUT << "JIT: Starting CodeGen of Function "
- << F.getFunction()->getName() << "\n";
+ DEBUG(errs() << "JIT: Starting CodeGen of Function "
+ << F.getFunction()->getName() << "\n");
uintptr_t ActualSize = 0;
// Set the memory writable, if it's not already
MemMgr->setMemoryWritable();
if (MemMgr->NeedsExactSize()) {
- DOUT << "JIT: ExactSize\n";
+ DEBUG(errs() << "JIT: ExactSize\n");
const TargetInstrInfo* TII = F.getTarget().getInstrInfo();
MachineJumpTableInfo *MJTI = F.getJumpTableInfo();
MachineConstantPool *MCP = F.getConstantPool();
@@ -887,12 +941,15 @@ void JITEmitter::startFunction(MachineFunction &F) {
// Add the function size
ActualSize += TII->GetFunctionSizeInBytes(F);
- DOUT << "JIT: ActualSize before globals " << ActualSize << "\n";
+ DEBUG(errs() << "JIT: ActualSize before globals " << ActualSize << "\n");
// Add the size of the globals that will be allocated after this function.
// These are all the ones referenced from this function that were not
// previously allocated.
ActualSize += GetSizeOfGlobalsInBytes(F);
- DOUT << "JIT: ActualSize after globals " << ActualSize << "\n";
+ DEBUG(errs() << "JIT: ActualSize after globals " << ActualSize << "\n");
+ } else if (SizeEstimate > 0) {
+ // SizeEstimate will be non-zero on reallocation attempts.
+ ActualSize = SizeEstimate;
}
BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(),
@@ -910,17 +967,22 @@ void JITEmitter::startFunction(MachineFunction &F) {
TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr);
MBBLocations.clear();
+
+ EmissionDetails.MF = &F;
+ EmissionDetails.LineStarts.clear();
}
bool JITEmitter::finishFunction(MachineFunction &F) {
if (CurBufferPtr == BufferEnd) {
- // FIXME: Allocate more space, then try again.
- cerr << "JIT: Ran out of space for generated machine code!\n";
- abort();
+ // We must call endFunctionBody before retrying, because
+ // deallocateMemForFunction requires it.
+ MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
+ retryWithMoreMemory(F);
+ return true;
}
-
+
emitJumpTableInfo(F.getJumpTableInfo());
-
+
// FnStart is the start of the text, not the start of the constant pool and
// other per-function data.
uint8_t *FnStart =
@@ -941,8 +1003,8 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
if (MR.isExternalSymbol()) {
ResultPtr = TheJIT->getPointerToNamedFunction(MR.getExternalSymbol(),
false);
- DOUT << "JIT: Map \'" << MR.getExternalSymbol() << "\' to ["
- << ResultPtr << "]\n";
+ DEBUG(errs() << "JIT: Map \'" << MR.getExternalSymbol() << "\' to ["
+ << ResultPtr << "]\n");
// If the target REALLY wants a stub for this function, emit it now.
if (!MR.doesntNeedStub()) {
@@ -983,9 +1045,9 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
unsigned idx = Resolver.getGOTIndexForAddr(ResultPtr);
MR.setGOTIndex(idx);
if (((void**)MemMgr->getGOTBase())[idx] != ResultPtr) {
- DOUT << "JIT: GOT was out of date for " << ResultPtr
- << " pointing at " << ((void**)MemMgr->getGOTBase())[idx]
- << "\n";
+ DEBUG(errs() << "JIT: GOT was out of date for " << ResultPtr
+ << " pointing at " << ((void**)MemMgr->getGOTBase())[idx]
+ << "\n");
((void**)MemMgr->getGOTBase())[idx] = ResultPtr;
}
}
@@ -1000,8 +1062,9 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
if (MemMgr->isManagingGOT()) {
unsigned idx = Resolver.getGOTIndexForAddr((void*)BufferBegin);
if (((void**)MemMgr->getGOTBase())[idx] != (void*)BufferBegin) {
- DOUT << "JIT: GOT was out of date for " << (void*)BufferBegin
- << " pointing at " << ((void**)MemMgr->getGOTBase())[idx] << "\n";
+ DEBUG(errs() << "JIT: GOT was out of date for " << (void*)BufferBegin
+ << " pointing at " << ((void**)MemMgr->getGOTBase())[idx]
+ << "\n");
((void**)MemMgr->getGOTBase())[idx] = (void*)BufferBegin;
}
}
@@ -1011,9 +1074,12 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
if (CurBufferPtr == BufferEnd) {
- // FIXME: Allocate more space, then try again.
- cerr << "JIT: Ran out of space for generated machine code!\n";
- abort();
+ retryWithMoreMemory(F);
+ return true;
+ } else {
+ // Now that we've succeeded in emitting the function, reset the
+ // SizeEstimate back down to zero.
+ SizeEstimate = 0;
}
BufferBegin = CurBufferPtr = 0;
@@ -1022,14 +1088,13 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
// Invalidate the icache if necessary.
sys::Memory::InvalidateInstructionCache(FnStart, FnEnd-FnStart);
- JITEvent_EmittedFunctionDetails Details;
TheJIT->NotifyFunctionEmitted(*F.getFunction(), FnStart, FnEnd-FnStart,
- Details);
+ EmissionDetails);
- DOUT << "JIT: Finished CodeGen of [" << (void*)FnStart
- << "] Function: " << F.getFunction()->getName()
- << ": " << (FnEnd-FnStart) << " bytes of text, "
- << Relocations.size() << " relocations\n";
+ DEBUG(errs() << "JIT: Finished CodeGen of [" << (void*)FnStart
+ << "] Function: " << F.getFunction()->getName()
+ << ": " << (FnEnd-FnStart) << " bytes of text, "
+ << Relocations.size() << " relocations\n");
Relocations.clear();
ConstPoolAddresses.clear();
@@ -1037,45 +1102,42 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
// Mark code region readable and executable if it's not so already.
MemMgr->setMemoryExecutable();
-#ifndef NDEBUG
- {
+ DEBUG(
if (sys::hasDisassembler()) {
- DOUT << "JIT: Disassembled code:\n";
- DOUT << sys::disassembleBuffer(FnStart, FnEnd-FnStart, (uintptr_t)FnStart);
+ errs() << "JIT: Disassembled code:\n";
+ errs() << sys::disassembleBuffer(FnStart, FnEnd-FnStart,
+ (uintptr_t)FnStart);
} else {
- DOUT << "JIT: Binary code:\n";
- DOUT << std::hex;
+ errs() << "JIT: Binary code:\n";
uint8_t* q = FnStart;
for (int i = 0; q < FnEnd; q += 4, ++i) {
if (i == 4)
i = 0;
if (i == 0)
- DOUT << "JIT: " << std::setw(8) << std::setfill('0')
- << (long)(q - FnStart) << ": ";
+ errs() << "JIT: " << (long)(q - FnStart) << ": ";
bool Done = false;
for (int j = 3; j >= 0; --j) {
if (q + j >= FnEnd)
Done = true;
else
- DOUT << std::setw(2) << std::setfill('0') << (unsigned short)q[j];
+ errs() << (unsigned short)q[j];
}
if (Done)
break;
- DOUT << ' ';
+ errs() << ' ';
if (i == 3)
- DOUT << '\n';
+ errs() << '\n';
}
- DOUT << std::dec;
- DOUT<< '\n';
+ errs()<< '\n';
}
- }
-#endif
- if (ExceptionHandling) {
+ );
+
+ if (DwarfExceptionHandling || JITEmitDebugInfo) {
uintptr_t ActualSize = 0;
SavedBufferBegin = BufferBegin;
SavedBufferEnd = BufferEnd;
SavedCurBufferPtr = CurBufferPtr;
-
+
if (MemMgr->NeedsExactSize()) {
ActualSize = DE->GetDwarfTableSizeInBytes(F, *this, FnStart, FnEnd);
}
@@ -1083,14 +1145,28 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(),
ActualSize);
BufferEnd = BufferBegin+ActualSize;
- uint8_t* FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd);
+ uint8_t *EhStart;
+ uint8_t *FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd,
+ EhStart);
MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr,
FrameRegister);
+ uint8_t *EhEnd = CurBufferPtr;
BufferBegin = SavedBufferBegin;
BufferEnd = SavedBufferEnd;
CurBufferPtr = SavedCurBufferPtr;
- TheJIT->RegisterTable(FrameRegister);
+ if (DwarfExceptionHandling) {
+ TheJIT->RegisterTable(FrameRegister);
+ }
+
+ if (JITEmitDebugInfo) {
+ DebugInfo I;
+ I.FnStart = FnStart;
+ I.FnEnd = FnEnd;
+ I.EhStart = EhStart;
+ I.EhEnd = EhEnd;
+ DR->RegisterFunction(F.getFunction(), I);
+ }
}
if (MMI)
@@ -1099,11 +1175,28 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
return false;
}
+void JITEmitter::retryWithMoreMemory(MachineFunction &F) {
+ DEBUG(errs() << "JIT: Ran out of space for native code. Reattempting.\n");
+ Relocations.clear(); // Clear the old relocations or we'll reapply them.
+ ConstPoolAddresses.clear();
+ ++NumRetries;
+ deallocateMemForFunction(F.getFunction());
+ // Try again with at least twice as much free space.
+ SizeEstimate = (uintptr_t)(2 * (BufferEnd - BufferBegin));
+}
+
/// deallocateMemForFunction - Deallocate all memory for the specified
/// function body. Also drop any references the function has to stubs.
-void JITEmitter::deallocateMemForFunction(Function *F) {
+void JITEmitter::deallocateMemForFunction(const Function *F) {
MemMgr->deallocateMemForFunction(F);
+ // TODO: Do we need to unregister exception handling information from libgcc
+ // here?
+
+ if (JITEmitDebugInfo) {
+ DR->UnregisterFunction(F);
+ }
+
// If the function did not reference any stubs, return.
if (CurFnStubUses.find(F) == CurFnStubUses.end())
return;
@@ -1125,7 +1218,7 @@ void JITEmitter::deallocateMemForFunction(Function *F) {
// in the JITResolver. Were there a memory manager deallocateStub routine,
// we could call that at this point too.
if (FnRefs.empty()) {
- DOUT << "\nJIT: Invalidated Stub at [" << Stub << "]\n";
+ DEBUG(errs() << "\nJIT: Invalidated Stub at [" << Stub << "]\n");
StubFnRefs.erase(Stub);
// Invalidate the stub. If it is a GV stub, update the JIT's global
@@ -1161,6 +1254,11 @@ void* JITEmitter::allocateSpace(uintptr_t Size, unsigned Alignment) {
return CurBufferPtr;
}
+void* JITEmitter::allocateGlobal(uintptr_t Size, unsigned Alignment) {
+ // Delegate this call through the memory manager.
+ return MemMgr->allocateGlobal(Size, Alignment);
+}
+
void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
if (TheJIT->getJITInfo().hasCustomConstantPool())
return;
@@ -1175,8 +1273,8 @@ void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
if (ConstantPoolBase == 0) return; // Buffer overflow.
- DOUT << "JIT: Emitted constant pool at [" << ConstantPoolBase
- << "] (size: " << Size << ", alignment: " << Align << ")\n";
+ DEBUG(errs() << "JIT: Emitted constant pool at [" << ConstantPoolBase
+ << "] (size: " << Size << ", alignment: " << Align << ")\n");
// Initialize the memory for all of the constant pool entries.
unsigned Offset = 0;
@@ -1189,13 +1287,12 @@ void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
ConstPoolAddresses.push_back(CAddr);
if (CPE.isMachineConstantPoolEntry()) {
// FIXME: add support to lower machine constant pool values into bytes!
- cerr << "Initialize memory with machine specific constant pool entry"
- << " has not been implemented!\n";
- abort();
+ llvm_report_error("Initialize memory with machine specific constant pool"
+ "entry has not been implemented!");
}
TheJIT->InitializeMemory(CPE.Val.ConstVal, (void*)CAddr);
- DOUT << "JIT: CP" << i << " at [0x"
- << std::hex << CAddr << std::dec << "]\n";
+ DEBUG(errs() << "JIT: CP" << i << " at [0x";
+ errs().write_hex(CAddr) << "]\n");
const Type *Ty = CPE.Val.ConstVal->getType();
Offset += TheJIT->getTargetData()->getTypeAllocSize(Ty);
@@ -1322,8 +1419,9 @@ uintptr_t JITEmitter::getJumpTableEntryAddress(unsigned Index) const {
// Public interface to this file
//===----------------------------------------------------------------------===//
-JITCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM) {
- return new JITEmitter(jit, JMM);
+JITCodeEmitter *JIT::createEmitter(JIT &jit, JITMemoryManager *JMM,
+ TargetMachine &tm) {
+ return new JITEmitter(jit, JMM, tm);
}
// getPointerToNamedFunction - This function is used as a global wrapper to
@@ -1396,7 +1494,7 @@ void JIT::updateDlsymStubTable() {
SmallVector<unsigned, 8> Offsets;
for (unsigned i = 0; i != GVs.size(); ++i) {
Offsets.push_back(offset);
- offset += GVs[i]->getName().length() + 1;
+ offset += GVs[i]->getName().size() + 1;
}
for (StringMapConstIterator<void*> i = ExtFns.begin(), e = ExtFns.end();
i != e; ++i) {
diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
index 70ccdcc..474843f 100644
--- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
+++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
@@ -11,9 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/GlobalValue.h"
+#define DEBUG_TYPE "jit"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Memory.h"
#include <map>
#include <vector>
@@ -24,6 +31,7 @@
#include <cstring>
using namespace llvm;
+STATISTIC(NumSlabs, "Number of slabs of memory allocated by the JIT");
JITMemoryManager::~JITMemoryManager() {}
@@ -140,7 +148,7 @@ FreeRangeHeader *FreeRangeHeader::AllocateBlock() {
/// FreeRangeHeader to allocate from.
FreeRangeHeader *MemoryRangeHeader::FreeBlock(FreeRangeHeader *FreeList) {
MemoryRangeHeader *FollowingBlock = &getBlockAfter();
- assert(ThisAllocated && "This block is already allocated!");
+ assert(ThisAllocated && "This block is already free!");
assert(FollowingBlock->PrevAllocated && "Flags out of sync!");
FreeRangeHeader *FreeListToReturn = FreeList;
@@ -243,67 +251,160 @@ TrimAllocationToSize(FreeRangeHeader *FreeList, uint64_t NewSize) {
// Memory Block Implementation.
//===----------------------------------------------------------------------===//
-namespace {
+namespace {
+
+ class DefaultJITMemoryManager;
+
+ class JITSlabAllocator : public SlabAllocator {
+ DefaultJITMemoryManager &JMM;
+ public:
+ JITSlabAllocator(DefaultJITMemoryManager &jmm) : JMM(jmm) { }
+ virtual ~JITSlabAllocator() { }
+ virtual MemSlab *Allocate(size_t Size);
+ virtual void Deallocate(MemSlab *Slab);
+ };
+
/// DefaultJITMemoryManager - Manage memory for the JIT code generation.
/// This splits a large block of MAP_NORESERVE'd memory into two
/// sections, one for function stubs, one for the functions themselves. We
/// have to do this because we may need to emit a function stub while in the
/// middle of emitting a function, and we don't know how large the function we
/// are emitting is.
- class VISIBILITY_HIDDEN DefaultJITMemoryManager : public JITMemoryManager {
- std::vector<sys::MemoryBlock> Blocks; // Memory blocks allocated by the JIT
- FreeRangeHeader *FreeMemoryList; // Circular list of free blocks.
-
+ class DefaultJITMemoryManager : public JITMemoryManager {
+
+ // Whether to poison freed memory.
+ bool PoisonMemory;
+
+ /// LastSlab - This points to the last slab allocated and is used as the
+ /// NearBlock parameter to AllocateRWX so that we can attempt to lay out all
+ /// stubs, data, and code contiguously in memory. In general, however, this
+ /// is not possible because the NearBlock parameter is ignored on Windows
+ /// platforms and even on Unix it works on a best-effort pasis.
+ sys::MemoryBlock LastSlab;
+
+ // Memory slabs allocated by the JIT. We refer to them as slabs so we don't
+ // confuse them with the blocks of memory descibed above.
+ std::vector<sys::MemoryBlock> CodeSlabs;
+ JITSlabAllocator BumpSlabAllocator;
+ BumpPtrAllocator StubAllocator;
+ BumpPtrAllocator DataAllocator;
+
+ // Circular list of free blocks.
+ FreeRangeHeader *FreeMemoryList;
+
// When emitting code into a memory block, this is the block.
MemoryRangeHeader *CurBlock;
-
- uint8_t *CurStubPtr, *StubBase;
+
uint8_t *GOTBase; // Target Specific reserved memory
void *DlsymTable; // Stub external symbol information
- // Centralize memory block allocation.
- sys::MemoryBlock getNewMemoryBlock(unsigned size);
-
std::map<const Function*, MemoryRangeHeader*> FunctionBlocks;
std::map<const Function*, MemoryRangeHeader*> TableBlocks;
public:
DefaultJITMemoryManager();
~DefaultJITMemoryManager();
+ /// allocateNewSlab - Allocates a new MemoryBlock and remembers it as the
+ /// last slab it allocated, so that subsequent allocations follow it.
+ sys::MemoryBlock allocateNewSlab(size_t size);
+
+ /// DefaultCodeSlabSize - When we have to go map more memory, we allocate at
+ /// least this much unless more is requested.
+ static const size_t DefaultCodeSlabSize;
+
+ /// DefaultSlabSize - Allocate data into slabs of this size unless we get
+ /// an allocation above SizeThreshold.
+ static const size_t DefaultSlabSize;
+
+ /// DefaultSizeThreshold - For any allocation larger than this threshold, we
+ /// should allocate a separate slab.
+ static const size_t DefaultSizeThreshold;
+
void AllocateGOT();
void SetDlsymTable(void *);
-
- uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
- unsigned Alignment);
-
+
+ // Testing methods.
+ virtual bool CheckInvariants(std::string &ErrorStr);
+ size_t GetDefaultCodeSlabSize() { return DefaultCodeSlabSize; }
+ size_t GetDefaultDataSlabSize() { return DefaultSlabSize; }
+ size_t GetDefaultStubSlabSize() { return DefaultSlabSize; }
+ unsigned GetNumCodeSlabs() { return CodeSlabs.size(); }
+ unsigned GetNumDataSlabs() { return DataAllocator.GetNumSlabs(); }
+ unsigned GetNumStubSlabs() { return StubAllocator.GetNumSlabs(); }
+
/// startFunctionBody - When a function starts, allocate a block of free
/// executable memory, returning a pointer to it and its actual size.
uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) {
-
+
FreeRangeHeader* candidateBlock = FreeMemoryList;
FreeRangeHeader* head = FreeMemoryList;
FreeRangeHeader* iter = head->Next;
uintptr_t largest = candidateBlock->BlockSize;
-
+
// Search for the largest free block
while (iter != head) {
- if (iter->BlockSize > largest) {
- largest = iter->BlockSize;
- candidateBlock = iter;
- }
- iter = iter->Next;
+ if (iter->BlockSize > largest) {
+ largest = iter->BlockSize;
+ candidateBlock = iter;
+ }
+ iter = iter->Next;
}
+
+ largest = largest - sizeof(MemoryRangeHeader);
+ // If this block isn't big enough for the allocation desired, allocate
+ // another block of memory and add it to the free list.
+ if (largest < ActualSize ||
+ largest <= FreeRangeHeader::getMinBlockSize()) {
+ DEBUG(errs() << "JIT: Allocating another slab of memory for function.");
+ candidateBlock = allocateNewCodeSlab((size_t)ActualSize);
+ }
+
// Select this candidate block for allocation
CurBlock = candidateBlock;
// Allocate the entire memory block.
FreeMemoryList = candidateBlock->AllocateBlock();
- ActualSize = CurBlock->BlockSize-sizeof(MemoryRangeHeader);
- return (uint8_t *)(CurBlock+1);
+ ActualSize = CurBlock->BlockSize - sizeof(MemoryRangeHeader);
+ return (uint8_t *)(CurBlock + 1);
}
-
+
+ /// allocateNewCodeSlab - Helper method to allocate a new slab of code
+ /// memory from the OS and add it to the free list. Returns the new
+ /// FreeRangeHeader at the base of the slab.
+ FreeRangeHeader *allocateNewCodeSlab(size_t MinSize) {
+ // If the user needs at least MinSize free memory, then we account for
+ // two MemoryRangeHeaders: the one in the user's block, and the one at the
+ // end of the slab.
+ size_t PaddedMin = MinSize + 2 * sizeof(MemoryRangeHeader);
+ size_t SlabSize = std::max(DefaultCodeSlabSize, PaddedMin);
+ sys::MemoryBlock B = allocateNewSlab(SlabSize);
+ CodeSlabs.push_back(B);
+ char *MemBase = (char*)(B.base());
+
+ // Put a tiny allocated block at the end of the memory chunk, so when
+ // FreeBlock calls getBlockAfter it doesn't fall off the end.
+ MemoryRangeHeader *EndBlock =
+ (MemoryRangeHeader*)(MemBase + B.size()) - 1;
+ EndBlock->ThisAllocated = 1;
+ EndBlock->PrevAllocated = 0;
+ EndBlock->BlockSize = sizeof(MemoryRangeHeader);
+
+ // Start out with a vast new block of free memory.
+ FreeRangeHeader *NewBlock = (FreeRangeHeader*)MemBase;
+ NewBlock->ThisAllocated = 0;
+ // Make sure getFreeBlockBefore doesn't look into unmapped memory.
+ NewBlock->PrevAllocated = 1;
+ NewBlock->BlockSize = (uintptr_t)EndBlock - (uintptr_t)NewBlock;
+ NewBlock->SetEndOfBlockSizeMarker();
+ NewBlock->AddToFreeList(FreeMemoryList);
+
+ assert(NewBlock->BlockSize - sizeof(MemoryRangeHeader) >= MinSize &&
+ "The block was too small!");
+ return NewBlock;
+ }
+
/// endFunctionBody - The function F is now allocated, and takes the memory
/// in the range [FunctionStart,FunctionEnd).
void endFunctionBody(const Function *F, uint8_t *FunctionStart,
@@ -319,12 +420,13 @@ namespace {
FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
}
- /// allocateSpace - Allocate a memory block of the given size.
+ /// allocateSpace - Allocate a memory block of the given size. This method
+ /// cannot be called between calls to startFunctionBody and endFunctionBody.
uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
CurBlock = FreeMemoryList;
FreeMemoryList = FreeMemoryList->AllocateBlock();
- uint8_t *result = (uint8_t *)CurBlock+1;
+ uint8_t *result = (uint8_t *)(CurBlock + 1);
if (Alignment == 0) Alignment = 1;
result = (uint8_t*)(((intptr_t)result+Alignment-1) &
@@ -336,6 +438,17 @@ namespace {
return result;
}
+ /// allocateStub - Allocate memory for a function stub.
+ uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
+ unsigned Alignment) {
+ return (uint8_t*)StubAllocator.Allocate(StubSize, Alignment);
+ }
+
+ /// allocateGlobal - Allocate memory for a global.
+ uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
+ return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
+ }
+
/// startExceptionTable - Use startFunctionBody to allocate memory for the
/// function's exception table.
uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) {
@@ -375,12 +488,12 @@ namespace {
// Find the block that is allocated for this function.
MemoryRangeHeader *MemRange = I->second;
assert(MemRange->ThisAllocated && "Block isn't allocated!");
-
+
// Fill the buffer with garbage!
-#ifndef NDEBUG
- memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
-#endif
-
+ if (PoisonMemory) {
+ memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
+ }
+
// Free the memory.
FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
@@ -393,12 +506,12 @@ namespace {
// Find the block that is allocated for this function.
MemRange = I->second;
assert(MemRange->ThisAllocated && "Block isn't allocated!");
-
+
// Fill the buffer with garbage!
-#ifndef NDEBUG
- memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
-#endif
-
+ if (PoisonMemory) {
+ memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
+ }
+
// Free the memory.
FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
@@ -408,36 +521,57 @@ namespace {
/// setMemoryWritable - When code generation is in progress,
/// the code pages may need permissions changed.
- void setMemoryWritable(void)
+ void setMemoryWritable()
{
- for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
- sys::Memory::setWritable(Blocks[i]);
+ for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
+ sys::Memory::setWritable(CodeSlabs[i]);
}
/// setMemoryExecutable - When code generation is done and we're ready to
/// start execution, the code pages may need permissions changed.
- void setMemoryExecutable(void)
+ void setMemoryExecutable()
{
- for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
- sys::Memory::setExecutable(Blocks[i]);
+ for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
+ sys::Memory::setExecutable(CodeSlabs[i]);
+ }
+
+ /// setPoisonMemory - Controls whether we write garbage over freed memory.
+ ///
+ void setPoisonMemory(bool poison) {
+ PoisonMemory = poison;
}
};
}
-DefaultJITMemoryManager::DefaultJITMemoryManager() {
- // Allocate a 16M block of memory for functions.
-#if defined(__APPLE__) && defined(__arm__)
- sys::MemoryBlock MemBlock = getNewMemoryBlock(4 << 20);
+MemSlab *JITSlabAllocator::Allocate(size_t Size) {
+ sys::MemoryBlock B = JMM.allocateNewSlab(Size);
+ MemSlab *Slab = (MemSlab*)B.base();
+ Slab->Size = B.size();
+ Slab->NextPtr = 0;
+ return Slab;
+}
+
+void JITSlabAllocator::Deallocate(MemSlab *Slab) {
+ sys::MemoryBlock B(Slab, Slab->Size);
+ sys::Memory::ReleaseRWX(B);
+}
+
+DefaultJITMemoryManager::DefaultJITMemoryManager()
+ :
+#ifdef NDEBUG
+ PoisonMemory(false),
#else
- sys::MemoryBlock MemBlock = getNewMemoryBlock(16 << 20);
+ PoisonMemory(true),
#endif
+ LastSlab(0, 0),
+ BumpSlabAllocator(*this),
+ StubAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator),
+ DataAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator) {
- uint8_t *MemBase = static_cast<uint8_t*>(MemBlock.base());
+ // Allocate space for code.
+ sys::MemoryBlock MemBlock = allocateNewSlab(DefaultCodeSlabSize);
+ CodeSlabs.push_back(MemBlock);
+ uint8_t *MemBase = (uint8_t*)MemBlock.base();
- // Allocate stubs backwards from the base, allocate functions forward
- // from the base.
- StubBase = MemBase;
- CurStubPtr = MemBase + 512*1024; // Use 512k for stubs, working backwards.
-
// We set up the memory chunk with 4 mem regions, like this:
// [ START
// [ Free #0 ] -> Large space to allocate functions from.
@@ -453,7 +587,7 @@ DefaultJITMemoryManager::DefaultJITMemoryManager() {
MemoryRangeHeader *Mem3 = (MemoryRangeHeader*)(MemBase+MemBlock.size())-1;
Mem3->ThisAllocated = 1;
Mem3->PrevAllocated = 0;
- Mem3->BlockSize = 0;
+ Mem3->BlockSize = sizeof(MemoryRangeHeader);
/// Add a tiny free region so that the free list always has one entry.
FreeRangeHeader *Mem2 =
@@ -469,12 +603,12 @@ DefaultJITMemoryManager::DefaultJITMemoryManager() {
MemoryRangeHeader *Mem1 = (MemoryRangeHeader*)Mem2-1;
Mem1->ThisAllocated = 1;
Mem1->PrevAllocated = 0;
- Mem1->BlockSize = (char*)Mem2 - (char*)Mem1;
+ Mem1->BlockSize = sizeof(MemoryRangeHeader);
// Add a FreeRangeHeader to the start of the function body region, indicating
// that the space is free. Mark the previous block allocated so we never look
// at it.
- FreeRangeHeader *Mem0 = (FreeRangeHeader*)CurStubPtr;
+ FreeRangeHeader *Mem0 = (FreeRangeHeader*)MemBase;
Mem0->ThisAllocated = 0;
Mem0->PrevAllocated = 1;
Mem0->BlockSize = (char*)Mem1-(char*)Mem0;
@@ -499,43 +633,128 @@ void DefaultJITMemoryManager::SetDlsymTable(void *ptr) {
}
DefaultJITMemoryManager::~DefaultJITMemoryManager() {
- for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
- sys::Memory::ReleaseRWX(Blocks[i]);
-
- delete[] GOTBase;
- Blocks.clear();
-}
+ for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
+ sys::Memory::ReleaseRWX(CodeSlabs[i]);
-uint8_t *DefaultJITMemoryManager::allocateStub(const GlobalValue* F,
- unsigned StubSize,
- unsigned Alignment) {
- CurStubPtr -= StubSize;
- CurStubPtr = (uint8_t*)(((intptr_t)CurStubPtr) &
- ~(intptr_t)(Alignment-1));
- if (CurStubPtr < StubBase) {
- // FIXME: allocate a new block
- fprintf(stderr, "JIT ran out of memory for function stubs!\n");
- abort();
- }
- return CurStubPtr;
+ delete[] GOTBase;
}
-sys::MemoryBlock DefaultJITMemoryManager::getNewMemoryBlock(unsigned size) {
+sys::MemoryBlock DefaultJITMemoryManager::allocateNewSlab(size_t size) {
// Allocate a new block close to the last one.
- const sys::MemoryBlock *BOld = Blocks.empty() ? 0 : &Blocks.front();
std::string ErrMsg;
- sys::MemoryBlock B = sys::Memory::AllocateRWX(size, BOld, &ErrMsg);
+ sys::MemoryBlock *LastSlabPtr = LastSlab.base() ? &LastSlab : 0;
+ sys::MemoryBlock B = sys::Memory::AllocateRWX(size, LastSlabPtr, &ErrMsg);
if (B.base() == 0) {
- fprintf(stderr,
- "Allocation failed when allocating new memory in the JIT\n%s\n",
- ErrMsg.c_str());
- abort();
+ llvm_report_error("Allocation failed when allocating new memory in the"
+ " JIT\n" + ErrMsg);
+ }
+ LastSlab = B;
+ ++NumSlabs;
+ // Initialize the slab to garbage when debugging.
+ if (PoisonMemory) {
+ memset(B.base(), 0xCD, B.size());
}
- Blocks.push_back(B);
return B;
}
+/// CheckInvariants - For testing only. Return "" if all internal invariants
+/// are preserved, and a helpful error message otherwise. For free and
+/// allocated blocks, make sure that adding BlockSize gives a valid block.
+/// For free blocks, make sure they're in the free list and that their end of
+/// block size marker is correct. This function should return an error before
+/// accessing bad memory. This function is defined here instead of in
+/// JITMemoryManagerTest.cpp so that we don't have to expose all of the
+/// implementation details of DefaultJITMemoryManager.
+bool DefaultJITMemoryManager::CheckInvariants(std::string &ErrorStr) {
+ raw_string_ostream Err(ErrorStr);
+
+ // Construct a the set of FreeRangeHeader pointers so we can query it
+ // efficiently.
+ llvm::SmallPtrSet<MemoryRangeHeader*, 16> FreeHdrSet;
+ FreeRangeHeader* FreeHead = FreeMemoryList;
+ FreeRangeHeader* FreeRange = FreeHead;
+
+ do {
+ // Check that the free range pointer is in the blocks we've allocated.
+ bool Found = false;
+ for (std::vector<sys::MemoryBlock>::iterator I = CodeSlabs.begin(),
+ E = CodeSlabs.end(); I != E && !Found; ++I) {
+ char *Start = (char*)I->base();
+ char *End = Start + I->size();
+ Found = (Start <= (char*)FreeRange && (char*)FreeRange < End);
+ }
+ if (!Found) {
+ Err << "Corrupt free list; points to " << FreeRange;
+ return false;
+ }
+
+ if (FreeRange->Next->Prev != FreeRange) {
+ Err << "Next and Prev pointers do not match.";
+ return false;
+ }
+
+ // Otherwise, add it to the set.
+ FreeHdrSet.insert(FreeRange);
+ FreeRange = FreeRange->Next;
+ } while (FreeRange != FreeHead);
+
+ // Go over each block, and look at each MemoryRangeHeader.
+ for (std::vector<sys::MemoryBlock>::iterator I = CodeSlabs.begin(),
+ E = CodeSlabs.end(); I != E; ++I) {
+ char *Start = (char*)I->base();
+ char *End = Start + I->size();
+
+ // Check each memory range.
+ for (MemoryRangeHeader *Hdr = (MemoryRangeHeader*)Start, *LastHdr = NULL;
+ Start <= (char*)Hdr && (char*)Hdr < End;
+ Hdr = &Hdr->getBlockAfter()) {
+ if (Hdr->ThisAllocated == 0) {
+ // Check that this range is in the free list.
+ if (!FreeHdrSet.count(Hdr)) {
+ Err << "Found free header at " << Hdr << " that is not in free list.";
+ return false;
+ }
+
+ // Now make sure the size marker at the end of the block is correct.
+ uintptr_t *Marker = ((uintptr_t*)&Hdr->getBlockAfter()) - 1;
+ if (!(Start <= (char*)Marker && (char*)Marker < End)) {
+ Err << "Block size in header points out of current MemoryBlock.";
+ return false;
+ }
+ if (Hdr->BlockSize != *Marker) {
+ Err << "End of block size marker (" << *Marker << ") "
+ << "and BlockSize (" << Hdr->BlockSize << ") don't match.";
+ return false;
+ }
+ }
+
+ if (LastHdr && LastHdr->ThisAllocated != Hdr->PrevAllocated) {
+ Err << "Hdr->PrevAllocated (" << Hdr->PrevAllocated << ") != "
+ << "LastHdr->ThisAllocated (" << LastHdr->ThisAllocated << ")";
+ return false;
+ } else if (!LastHdr && !Hdr->PrevAllocated) {
+ Err << "The first header should have PrevAllocated true.";
+ return false;
+ }
+
+ // Remember the last header.
+ LastHdr = Hdr;
+ }
+ }
+
+ // All invariants are preserved.
+ return true;
+}
JITMemoryManager *JITMemoryManager::CreateDefaultMemManager() {
return new DefaultJITMemoryManager();
}
+
+// Allocate memory for code in 512K slabs.
+const size_t DefaultJITMemoryManager::DefaultCodeSlabSize = 512 * 1024;
+
+// Allocate globals and stubs in slabs of 64K. (probably 16 pages)
+const size_t DefaultJITMemoryManager::DefaultSlabSize = 64 * 1024;
+
+// Waste at most 16K at the end of each bump slab. (probably 4 pages)
+const size_t DefaultJITMemoryManager::DefaultSizeThreshold = 16 * 1024;
diff --git a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp
index 3b8b84c..53585b8 100644
--- a/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp
+++ b/lib/ExecutionEngine/JIT/MacOSJITEventListener.cpp
@@ -84,8 +84,7 @@ JITEventListener *createMacOSJITEventListener() {
void MacOSJITEventListener::NotifyFunctionEmitted(
const Function &F, void *FnStart, size_t FnSize,
const EmittedFunctionDetails &) {
- const char *const FnName = F.getNameStart();
- assert(FnName != 0 && FnStart != 0 && "Bad symbol to add");
+ assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
JITSymbolTable **SymTabPtrPtr = 0;
SymTabPtrPtr = &__jitSymbolTable;
@@ -120,7 +119,7 @@ void MacOSJITEventListener::NotifyFunctionEmitted(
// Otherwise, we have enough space, just tack it onto the end of the array.
JITSymbolEntry &Entry = SymTabPtr->Symbols[SymTabPtr->NumSymbols];
- Entry.FnName = strdup(FnName);
+ Entry.FnName = strdup(F.getName().data());
Entry.FnStart = FnStart;
Entry.FnSize = FnSize;
++SymTabPtr->NumSymbols;
diff --git a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp
new file mode 100644
index 0000000..69398be
--- /dev/null
+++ b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp
@@ -0,0 +1,178 @@
+//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a JITEventListener object that calls into OProfile to tell
+// it about JITted functions. For now, we only record function names and sizes,
+// but eventually we'll also record line number information.
+//
+// See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
+// definition of the interface we're using.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "oprofile-jit-event-listener"
+#include "llvm/Function.h"
+#include "llvm/Analysis/DebugInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Errno.h"
+#include "llvm/Config/config.h"
+#include <stddef.h>
+using namespace llvm;
+
+#if USE_OPROFILE
+
+#include <opagent.h>
+
+namespace {
+
+class OProfileJITEventListener : public JITEventListener {
+ op_agent_t Agent;
+public:
+ OProfileJITEventListener();
+ ~OProfileJITEventListener();
+
+ virtual void NotifyFunctionEmitted(const Function &F,
+ void *FnStart, size_t FnSize,
+ const EmittedFunctionDetails &Details);
+ virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr);
+};
+
+OProfileJITEventListener::OProfileJITEventListener()
+ : Agent(op_open_agent()) {
+ if (Agent == NULL) {
+ const std::string err_str = sys::StrError();
+ DEBUG(errs() << "Failed to connect to OProfile agent: " << err_str << "\n");
+ } else {
+ DEBUG(errs() << "Connected to OProfile agent.\n");
+ }
+}
+
+OProfileJITEventListener::~OProfileJITEventListener() {
+ if (Agent != NULL) {
+ if (op_close_agent(Agent) == -1) {
+ const std::string err_str = sys::StrError();
+ DEBUG(errs() << "Failed to disconnect from OProfile agent: "
+ << err_str << "\n");
+ } else {
+ DEBUG(errs() << "Disconnected from OProfile agent.\n");
+ }
+ }
+}
+
+class FilenameCache {
+ // Holds the filename of each CompileUnit, so that we can pass the
+ // pointer into oprofile. These char*s are freed in the destructor.
+ DenseMap<MDNode*, char*> Filenames;
+
+ public:
+ const char *getFilename(MDNode *CompileUnit) {
+ char *&Filename = Filenames[CompileUnit];
+ if (Filename == NULL) {
+ DICompileUnit CU(CompileUnit);
+ Filename = strdup(CU.getFilename());
+ }
+ return Filename;
+ }
+ ~FilenameCache() {
+ for (DenseMap<MDNode*, char*>::iterator
+ I = Filenames.begin(), E = Filenames.end(); I != E; ++I) {
+ free(I->second);
+ }
+ }
+};
+
+static debug_line_info LineStartToOProfileFormat(
+ const MachineFunction &MF, FilenameCache &Filenames,
+ uintptr_t Address, DebugLoc Loc) {
+ debug_line_info Result;
+ Result.vma = Address;
+ const DebugLocTuple &tuple = MF.getDebugLocTuple(Loc);
+ Result.lineno = tuple.Line;
+ Result.filename = Filenames.getFilename(tuple.CompileUnit);
+ DEBUG(errs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
+ << Result.filename << ":" << Result.lineno << "\n");
+ return Result;
+}
+
+// Adds the just-emitted function to the symbol table.
+void OProfileJITEventListener::NotifyFunctionEmitted(
+ const Function &F, void *FnStart, size_t FnSize,
+ const EmittedFunctionDetails &Details) {
+ assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
+ if (op_write_native_code(Agent, F.getName().data(),
+ reinterpret_cast<uint64_t>(FnStart),
+ FnStart, FnSize) == -1) {
+ DEBUG(errs() << "Failed to tell OProfile about native function "
+ << F.getName() << " at ["
+ << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
+ return;
+ }
+
+ // Now we convert the line number information from the address/DebugLoc format
+ // in Details to the address/filename/lineno format that OProfile expects.
+ // OProfile 0.9.4 (and maybe later versions) has a bug that causes it to
+ // ignore line numbers for addresses above 4G.
+ FilenameCache Filenames;
+ std::vector<debug_line_info> LineInfo;
+ LineInfo.reserve(1 + Details.LineStarts.size());
+ if (!Details.MF->getDefaultDebugLoc().isUnknown()) {
+ LineInfo.push_back(LineStartToOProfileFormat(
+ *Details.MF, Filenames,
+ reinterpret_cast<uintptr_t>(FnStart),
+ Details.MF->getDefaultDebugLoc()));
+ }
+ for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
+ I = Details.LineStarts.begin(), E = Details.LineStarts.end();
+ I != E; ++I) {
+ LineInfo.push_back(LineStartToOProfileFormat(
+ *Details.MF, Filenames, I->Address, I->Loc));
+ }
+ if (!LineInfo.empty()) {
+ if (op_write_debug_line_info(Agent, FnStart,
+ LineInfo.size(), &*LineInfo.begin()) == -1) {
+ DEBUG(errs()
+ << "Failed to tell OProfile about line numbers for native function "
+ << F.getName() << " at ["
+ << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
+ }
+ }
+}
+
+// Removes the to-be-deleted function from the symbol table.
+void OProfileJITEventListener::NotifyFreeingMachineCode(
+ const Function &F, void *FnStart) {
+ assert(FnStart && "Invalid function pointer");
+ if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) {
+ DEBUG(errs() << "Failed to tell OProfile about unload of native function "
+ << F.getName() << " at " << FnStart << "\n");
+ }
+}
+
+} // anonymous namespace.
+
+namespace llvm {
+JITEventListener *createOProfileJITEventListener() {
+ return new OProfileJITEventListener;
+}
+}
+
+#else // USE_OPROFILE
+
+namespace llvm {
+// By defining this to return NULL, we can let clients call it unconditionally,
+// even if they haven't configured with the OProfile libraries.
+JITEventListener *createOProfileJITEventListener() {
+ return NULL;
+}
+} // namespace llvm
+
+#endif // USE_OPROFILE
diff --git a/lib/ExecutionEngine/JIT/TargetSelect.cpp b/lib/ExecutionEngine/JIT/TargetSelect.cpp
index 0f20819..8bed33b 100644
--- a/lib/ExecutionEngine/JIT/TargetSelect.cpp
+++ b/lib/ExecutionEngine/JIT/TargetSelect.cpp
@@ -7,24 +7,27 @@
//
//===----------------------------------------------------------------------===//
//
-// This just asks the TargetMachineRegistry for the appropriate JIT to use, and
-// allows the user to specify a specific one on the commandline with -march=x.
+// This just asks the TargetRegistry for the appropriate JIT to use, and allows
+// the user to specify a specific one on the commandline with -march=x. Clients
+// should initialize targets prior to calling createJIT.
//
//===----------------------------------------------------------------------===//
#include "JIT.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
-#include "llvm/Support/RegistryParser.h"
-#include "llvm/Support/Streams.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Target/TargetRegistry.h"
using namespace llvm;
-static cl::opt<const TargetMachineRegistry::entry*, false,
- RegistryParser<TargetMachine> >
-MArch("march", cl::desc("Architecture to generate assembly for:"));
+static cl::opt<std::string>
+MArch("march",
+ cl::desc("Architecture to generate assembly for (see --version)"));
static cl::opt<std::string>
MCPU("mcpu",
@@ -38,25 +41,51 @@ MAttrs("mattr",
cl::desc("Target specific attributes (-mattr=help for details)"),
cl::value_desc("a1,+a2,-a3,..."));
-/// createInternal - Create an return a new JIT compiler if there is one
-/// available for the current target. Otherwise, return null.
-///
-ExecutionEngine *JIT::createJIT(ModuleProvider *MP, std::string *ErrorStr,
- JITMemoryManager *JMM,
- CodeGenOpt::Level OptLevel) {
- const TargetMachineRegistry::entry *TheArch = MArch;
- if (TheArch == 0) {
+/// selectTarget - Pick a target either via -march or by guessing the native
+/// arch. Add any CPU features specified via -mcpu or -mattr.
+TargetMachine *JIT::selectTarget(ModuleProvider *MP, std::string *ErrorStr) {
+ Module &Mod = *MP->getModule();
+
+ Triple TheTriple(Mod.getTargetTriple());
+ if (TheTriple.getTriple().empty())
+ TheTriple.setTriple(sys::getHostTriple());
+
+ // Adjust the triple to match what the user requested.
+ const Target *TheTarget = 0;
+ if (!MArch.empty()) {
+ for (TargetRegistry::iterator it = TargetRegistry::begin(),
+ ie = TargetRegistry::end(); it != ie; ++it) {
+ if (MArch == it->getName()) {
+ TheTarget = &*it;
+ break;
+ }
+ }
+
+ if (!TheTarget) {
+ *ErrorStr = "No available targets are compatible with this -march, "
+ "see -version for the available targets.\n";
+ return 0;
+ }
+
+ // Adjust the triple to match (if known), otherwise stick with the
+ // module/host triple.
+ Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
+ if (Type != Triple::UnknownArch)
+ TheTriple.setArch(Type);
+ } else {
std::string Error;
- TheArch = TargetMachineRegistry::getClosestTargetForJIT(Error);
- if (TheArch == 0) {
+ TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
+ if (TheTarget == 0) {
if (ErrorStr)
*ErrorStr = Error;
return 0;
}
- } else if (TheArch->JITMatchQualityFn() == 0) {
- cerr << "WARNING: This target JIT is not designed for the host you are"
- << " running. If bad things happen, please choose a different "
- << "-march switch.\n";
+ }
+
+ if (!TheTarget->hasJIT()) {
+ errs() << "WARNING: This target JIT is not designed for the host you are"
+ << " running. If bad things happen, please choose a different "
+ << "-march switch.\n";
}
// Package up features to be passed to target/subtarget
@@ -70,14 +99,8 @@ ExecutionEngine *JIT::createJIT(ModuleProvider *MP, std::string *ErrorStr,
}
// Allocate a target...
- TargetMachine *Target = TheArch->CtorFn(*MP->getModule(), FeaturesStr);
+ TargetMachine *Target =
+ TheTarget->createTargetMachine(TheTriple.getTriple(), FeaturesStr);
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, JMM, OptLevel);
-
- if (ErrorStr)
- *ErrorStr = "target does not support JIT code generation";
- return 0;
+ return Target;
}
OpenPOWER on IntegriCloud