mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
Nuke the old JIT.
I am sure we will be finding bits and pieces of dead code for years to come, but this is a good start. Thanks to Lang Hames for making MCJIT a good replacement! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215111 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7ad7c75048
commit
875710a2fd
@ -1673,18 +1673,13 @@ $(ObjDir)/%GenAsmMatcher.inc.tmp : %.td $(ObjDir)/.dir $(LLVM_TBLGEN)
|
||||
$(TARGET:%=$(ObjDir)/%GenMCCodeEmitter.inc.tmp): \
|
||||
$(ObjDir)/%GenMCCodeEmitter.inc.tmp: %.td $(ObjDir)/.dir $(LLVM_TBLGEN)
|
||||
$(Echo) "Building $(<F) MC code emitter with tblgen"
|
||||
$(Verb) $(LLVMTableGen) -gen-emitter -mc-emitter -o $(call SYSPATH, $@) $<
|
||||
$(Verb) $(LLVMTableGen) -gen-emitter -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(TARGET:%=$(ObjDir)/%GenMCPseudoLowering.inc.tmp): \
|
||||
$(ObjDir)/%GenMCPseudoLowering.inc.tmp: %.td $(ObjDir)/.dir $(LLVM_TBLGEN)
|
||||
$(Echo) "Building $(<F) MC Pseudo instruction expander with tblgen"
|
||||
$(Verb) $(LLVMTableGen) -gen-pseudo-lowering -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(TARGET:%=$(ObjDir)/%GenCodeEmitter.inc.tmp): \
|
||||
$(ObjDir)/%GenCodeEmitter.inc.tmp: %.td $(ObjDir)/.dir $(LLVM_TBLGEN)
|
||||
$(Echo) "Building $(<F) code emitter with tblgen"
|
||||
$(Verb) $(LLVMTableGen) -gen-emitter -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(TARGET:%=$(ObjDir)/%GenDAGISel.inc.tmp): \
|
||||
$(ObjDir)/%GenDAGISel.inc.tmp : %.td $(ObjDir)/.dir $(LLVM_TBLGEN)
|
||||
$(Echo) "Building $(<F) DAG instruction selector implementation with tblgen"
|
||||
|
@ -78,8 +78,7 @@ returns the (currently, 32-bit unsigned) value of the instruction.
|
||||
**Output**: C++ code, implementing the target's CodeEmitter
|
||||
class by overriding the virtual functions as ``<Target>CodeEmitter::function()``.
|
||||
|
||||
**Usage**: Used to include directly at the end of ``<Target>CodeEmitter.cpp``, and
|
||||
with option `-mc-emitter` to be included in ``<Target>MCCodeEmitter.cpp``.
|
||||
**Usage**: Used to include directly at the end of ``<Target>MCCodeEmitter.cpp``.
|
||||
|
||||
RegisterInfo
|
||||
------------
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
#include "BrainF.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
BitWriter
|
||||
Core
|
||||
ExecutionEngine
|
||||
JIT
|
||||
MC
|
||||
Support
|
||||
nativecodegen
|
||||
|
@ -1964,10 +1964,8 @@ int main(int argc, char *argv[]) {
|
||||
// Build engine with JIT
|
||||
llvm::EngineBuilder factory(module);
|
||||
factory.setEngineKind(llvm::EngineKind::JIT);
|
||||
factory.setAllocateGVsWithCode(false);
|
||||
factory.setTargetOptions(Opts);
|
||||
factory.setMCJITMemoryManager(MemMgr);
|
||||
factory.setUseMCJIT(true);
|
||||
llvm::ExecutionEngine *executionEngine = factory.create();
|
||||
|
||||
{
|
||||
|
@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
Interpreter
|
||||
JIT
|
||||
MC
|
||||
Support
|
||||
nativecodegen
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
Interpreter
|
||||
JIT
|
||||
MC
|
||||
Support
|
||||
nativecodegen
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
@ -126,7 +125,6 @@ int main() {
|
||||
|
||||
// Import result of execution:
|
||||
outs() << "Result: " << gv.IntVal << "\n";
|
||||
EE->freeMachineCodeForFunction(FooF);
|
||||
delete EE;
|
||||
llvm_shutdown();
|
||||
return 0;
|
||||
|
@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
InstCombine
|
||||
JIT
|
||||
MC
|
||||
ScalarOpts
|
||||
Support
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
InstCombine
|
||||
JIT
|
||||
MC
|
||||
ScalarOpts
|
||||
Support
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
InstCombine
|
||||
JIT
|
||||
MC
|
||||
ScalarOpts
|
||||
Support
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
InstCombine
|
||||
JIT
|
||||
MC
|
||||
ScalarOpts
|
||||
Support
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -897,7 +897,6 @@ ExecutionEngine *MCJITHelper::compileModule(Module *M) {
|
||||
std::string ErrStr;
|
||||
ExecutionEngine *NewEngine = EngineBuilder(M)
|
||||
.setErrorStr(&ErrStr)
|
||||
.setUseMCJIT(true)
|
||||
.setMCJITMemoryManager(new HelpingMemoryManager(this))
|
||||
.create();
|
||||
if (!NewEngine) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
@ -52,10 +51,6 @@ namespace {
|
||||
cl::desc("Dump IR from modules to stderr on shutdown"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool> UseMCJIT(
|
||||
"use-mcjit", cl::desc("Use the MCJIT execution engine"),
|
||||
cl::init(true));
|
||||
|
||||
cl::opt<bool> EnableLazyCompilation(
|
||||
"enable-lazy-compilation", cl::desc("Enable lazy compilation when using the MCJIT engine"),
|
||||
cl::init(true));
|
||||
@ -792,96 +787,6 @@ public:
|
||||
virtual void dump();
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Helper class for JIT execution engine
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class JITHelper : public BaseHelper {
|
||||
public:
|
||||
JITHelper(LLVMContext &Context) {
|
||||
// Make the module, which holds all the code.
|
||||
if (!InputIR.empty()) {
|
||||
TheModule = parseInputIR(InputIR, Context);
|
||||
} else {
|
||||
TheModule = new Module("my cool jit", Context);
|
||||
}
|
||||
|
||||
// Create the JIT. This takes ownership of the module.
|
||||
std::string ErrStr;
|
||||
TheExecutionEngine = EngineBuilder(TheModule).setErrorStr(&ErrStr).create();
|
||||
if (!TheExecutionEngine) {
|
||||
fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
TheFPM = new FunctionPassManager(TheModule);
|
||||
|
||||
// Set up the optimizer pipeline. Start with registering info about how the
|
||||
// target lays out data structures.
|
||||
TheFPM->add(new DataLayout(*TheExecutionEngine->getDataLayout()));
|
||||
// Provide basic AliasAnalysis support for GVN.
|
||||
TheFPM->add(createBasicAliasAnalysisPass());
|
||||
// Promote allocas to registers.
|
||||
TheFPM->add(createPromoteMemoryToRegisterPass());
|
||||
// Do simple "peephole" optimizations and bit-twiddling optzns.
|
||||
TheFPM->add(createInstructionCombiningPass());
|
||||
// Reassociate expressions.
|
||||
TheFPM->add(createReassociatePass());
|
||||
// Eliminate Common SubExpressions.
|
||||
TheFPM->add(createGVNPass());
|
||||
// Simplify the control flow graph (deleting unreachable blocks, etc).
|
||||
TheFPM->add(createCFGSimplificationPass());
|
||||
|
||||
TheFPM->doInitialization();
|
||||
}
|
||||
|
||||
virtual ~JITHelper() {
|
||||
if (TheFPM)
|
||||
delete TheFPM;
|
||||
if (TheExecutionEngine)
|
||||
delete TheExecutionEngine;
|
||||
}
|
||||
|
||||
virtual Function *getFunction(const std::string FnName) {
|
||||
assert(TheModule);
|
||||
return TheModule->getFunction(FnName);
|
||||
}
|
||||
|
||||
virtual Module *getModuleForNewFunction() {
|
||||
assert(TheModule);
|
||||
return TheModule;
|
||||
}
|
||||
|
||||
virtual void *getPointerToFunction(Function* F) {
|
||||
assert(TheExecutionEngine);
|
||||
return TheExecutionEngine->getPointerToFunction(F);
|
||||
}
|
||||
|
||||
virtual void *getPointerToNamedFunction(const std::string &Name) {
|
||||
return TheExecutionEngine->getPointerToNamedFunction(Name);
|
||||
}
|
||||
|
||||
virtual void runFPM(Function &F) {
|
||||
assert(TheFPM);
|
||||
TheFPM->run(F);
|
||||
}
|
||||
|
||||
virtual void closeCurrentModule() {
|
||||
// This should never be called for JIT
|
||||
assert(false);
|
||||
}
|
||||
|
||||
virtual void dump() {
|
||||
assert(TheModule);
|
||||
TheModule->dump();
|
||||
}
|
||||
|
||||
private:
|
||||
Module *TheModule;
|
||||
ExecutionEngine *TheExecutionEngine;
|
||||
FunctionPassManager *TheFPM;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MCJIT helper class
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1034,7 +939,6 @@ ExecutionEngine *MCJITHelper::compileModule(Module *M) {
|
||||
std::string ErrStr;
|
||||
ExecutionEngine *EE = EngineBuilder(M)
|
||||
.setErrorStr(&ErrStr)
|
||||
.setUseMCJIT(true)
|
||||
.setMCJITMemoryManager(new HelpingMemoryManager(this))
|
||||
.create();
|
||||
if (!EE) {
|
||||
@ -1194,10 +1098,8 @@ Value *UnaryExprAST::Codegen() {
|
||||
Value *OperandV = Operand->Codegen();
|
||||
if (OperandV == 0) return 0;
|
||||
Function *F;
|
||||
if (UseMCJIT)
|
||||
F = TheHelper->getFunction(MakeLegalFunctionName(std::string("unary")+Opcode));
|
||||
else
|
||||
F = TheHelper->getFunction(std::string("unary")+Opcode);
|
||||
F = TheHelper->getFunction(
|
||||
MakeLegalFunctionName(std::string("unary") + Opcode));
|
||||
if (F == 0)
|
||||
return ErrorV("Unknown unary operator");
|
||||
|
||||
@ -1246,10 +1148,7 @@ Value *BinaryExprAST::Codegen() {
|
||||
// If it wasn't a builtin binary operator, it must be a user defined one. Emit
|
||||
// a call to it.
|
||||
Function *F;
|
||||
if (UseMCJIT)
|
||||
F = TheHelper->getFunction(MakeLegalFunctionName(std::string("binary")+Op));
|
||||
else
|
||||
F = TheHelper->getFunction(std::string("binary")+Op);
|
||||
F = TheHelper->getFunction(MakeLegalFunctionName(std::string("binary")+Op));
|
||||
assert(F && "binary operator not found!");
|
||||
|
||||
Value *Ops[] = { L, R };
|
||||
@ -1482,10 +1381,7 @@ Function *PrototypeAST::Codegen() {
|
||||
Doubles, false);
|
||||
|
||||
std::string FnName;
|
||||
if (UseMCJIT)
|
||||
FnName = MakeLegalFunctionName(Name);
|
||||
else
|
||||
FnName = Name;
|
||||
FnName = MakeLegalFunctionName(Name);
|
||||
|
||||
Module* M = TheHelper->getModuleForNewFunction();
|
||||
Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, M);
|
||||
@ -1560,10 +1456,6 @@ Function *FunctionAST::Codegen() {
|
||||
// Validate the generated code, checking for consistency.
|
||||
verifyFunction(*TheFunction);
|
||||
|
||||
// Optimize the function.
|
||||
if (!UseMCJIT)
|
||||
TheHelper->runFPM(*TheFunction);
|
||||
|
||||
return TheFunction;
|
||||
}
|
||||
|
||||
@ -1581,7 +1473,7 @@ Function *FunctionAST::Codegen() {
|
||||
|
||||
static void HandleDefinition() {
|
||||
if (FunctionAST *F = ParseDefinition()) {
|
||||
if (UseMCJIT && EnableLazyCompilation)
|
||||
if (EnableLazyCompilation)
|
||||
TheHelper->closeCurrentModule();
|
||||
Function *LF = F->Codegen();
|
||||
if (LF && VerboseOutput) {
|
||||
@ -1671,10 +1563,8 @@ double printlf() {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
InitializeNativeTarget();
|
||||
if (UseMCJIT) {
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
InitializeNativeTargetAsmParser();
|
||||
}
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
InitializeNativeTargetAsmParser();
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
@ -1690,10 +1580,7 @@ int main(int argc, char **argv) {
|
||||
BinopPrecedence['*'] = 40; // highest.
|
||||
|
||||
// Make the Helper, which holds all the code.
|
||||
if (UseMCJIT)
|
||||
TheHelper = new MCJITHelper(Context);
|
||||
else
|
||||
TheHelper = new JITHelper(Context);
|
||||
TheHelper = new MCJITHelper(Context);
|
||||
|
||||
// Prime the first token.
|
||||
if (!SuppressPrompts)
|
||||
|
@ -778,7 +778,6 @@ void *MCJITHelper::getPointerToFunction(Function* F) {
|
||||
std::string ErrStr;
|
||||
ExecutionEngine *NewEngine = EngineBuilder(OpenModule)
|
||||
.setErrorStr(&ErrStr)
|
||||
.setUseMCJIT(true)
|
||||
.setMCJITMemoryManager(new HelpingMemoryManager(this))
|
||||
.create();
|
||||
if (!NewEngine) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
@ -808,7 +808,6 @@ ExecutionEngine *MCJITHelper::compileModule(Module *M) {
|
||||
std::string ErrStr;
|
||||
ExecutionEngine *NewEngine = EngineBuilder(M)
|
||||
.setErrorStr(&ErrStr)
|
||||
.setUseMCJIT(true)
|
||||
.setMCJITMemoryManager(new HelpingMemoryManager(this))
|
||||
.create();
|
||||
if (!NewEngine) {
|
||||
|
@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
Interpreter
|
||||
JIT
|
||||
Support
|
||||
nativecodegen
|
||||
)
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
@ -1,344 +0,0 @@
|
||||
//===-- llvm/CodeGen/JITCodeEmitter.h - Code emission ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an abstract interface that is used by the machine code
|
||||
// emission framework to output the code. This allows machine code emission to
|
||||
// be separated from concerns such as resolution of call targets, and where the
|
||||
// machine code will be written (memory or disk, f.e.).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_JITCODEEMITTER_H
|
||||
#define LLVM_CODEGEN_JITCODEEMITTER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineConstantPool;
|
||||
class MachineJumpTableInfo;
|
||||
class MachineFunction;
|
||||
class MachineModuleInfo;
|
||||
class MachineRelocation;
|
||||
class Value;
|
||||
class GlobalValue;
|
||||
class Function;
|
||||
|
||||
/// JITCodeEmitter - This class defines two sorts of methods: those for
|
||||
/// emitting the actual bytes of machine code, and those for emitting auxiliary
|
||||
/// structures, such as jump tables, relocations, etc.
|
||||
///
|
||||
/// Emission of machine code is complicated by the fact that we don't (in
|
||||
/// general) know the size of the machine code that we're about to emit before
|
||||
/// we emit it. As such, we preallocate a certain amount of memory, and set the
|
||||
/// BufferBegin/BufferEnd pointers to the start and end of the buffer. As we
|
||||
/// emit machine instructions, we advance the CurBufferPtr to indicate the
|
||||
/// location of the next byte to emit. In the case of a buffer overflow (we
|
||||
/// need to emit more machine code than we have allocated space for), the
|
||||
/// CurBufferPtr will saturate to BufferEnd and ignore stores. Once the entire
|
||||
/// function has been emitted, the overflow condition is checked, and if it has
|
||||
/// occurred, more memory is allocated, and we reemit the code into it.
|
||||
///
|
||||
class JITCodeEmitter : public MachineCodeEmitter {
|
||||
void anchor() override;
|
||||
public:
|
||||
virtual ~JITCodeEmitter() {}
|
||||
|
||||
/// startFunction - This callback is invoked when the specified function is
|
||||
/// about to be code generated. This initializes the BufferBegin/End/Ptr
|
||||
/// fields.
|
||||
///
|
||||
void startFunction(MachineFunction &F) override = 0;
|
||||
|
||||
/// finishFunction - This callback is invoked when the specified function has
|
||||
/// finished code generation. If a buffer overflow has occurred, this method
|
||||
/// returns true (the callee is required to try again), otherwise it returns
|
||||
/// false.
|
||||
///
|
||||
bool finishFunction(MachineFunction &F) override = 0;
|
||||
|
||||
/// allocIndirectGV - Allocates and fills storage for an indirect
|
||||
/// GlobalValue, and returns the address.
|
||||
virtual void *allocIndirectGV(const GlobalValue *GV,
|
||||
const uint8_t *Buffer, size_t Size,
|
||||
unsigned Alignment) = 0;
|
||||
|
||||
/// emitByte - This callback is invoked when a byte needs to be written to the
|
||||
/// output stream.
|
||||
///
|
||||
void emitByte(uint8_t B) {
|
||||
if (CurBufferPtr != BufferEnd)
|
||||
*CurBufferPtr++ = B;
|
||||
}
|
||||
|
||||
/// emitWordLE - This callback is invoked when a 32-bit word needs to be
|
||||
/// written to the output stream in little-endian format.
|
||||
///
|
||||
void emitWordLE(uint32_t W) {
|
||||
if (4 <= BufferEnd-CurBufferPtr) {
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 0);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 8);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 16);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 24);
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitWordBE - This callback is invoked when a 32-bit word needs to be
|
||||
/// written to the output stream in big-endian format.
|
||||
///
|
||||
void emitWordBE(uint32_t W) {
|
||||
if (4 <= BufferEnd-CurBufferPtr) {
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 24);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 16);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 8);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 0);
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitDWordLE - This callback is invoked when a 64-bit word needs to be
|
||||
/// written to the output stream in little-endian format.
|
||||
///
|
||||
void emitDWordLE(uint64_t W) {
|
||||
if (8 <= BufferEnd-CurBufferPtr) {
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 0);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 8);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 16);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 24);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 32);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 40);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 48);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 56);
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitDWordBE - This callback is invoked when a 64-bit word needs to be
|
||||
/// written to the output stream in big-endian format.
|
||||
///
|
||||
void emitDWordBE(uint64_t W) {
|
||||
if (8 <= BufferEnd-CurBufferPtr) {
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 56);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 48);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 40);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 32);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 24);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 16);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 8);
|
||||
*CurBufferPtr++ = (uint8_t)(W >> 0);
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitAlignment - Move the CurBufferPtr pointer up to the specified
|
||||
/// alignment (saturated to BufferEnd of course).
|
||||
void emitAlignment(unsigned Alignment) {
|
||||
if (Alignment == 0) Alignment = 1;
|
||||
uint8_t *NewPtr = (uint8_t*)RoundUpToAlignment((uintptr_t)CurBufferPtr,
|
||||
Alignment);
|
||||
CurBufferPtr = std::min(NewPtr, BufferEnd);
|
||||
}
|
||||
|
||||
/// emitAlignmentWithFill - Similar to emitAlignment, except that the
|
||||
/// extra bytes are filled with the provided byte.
|
||||
void emitAlignmentWithFill(unsigned Alignment, uint8_t Fill) {
|
||||
if (Alignment == 0) Alignment = 1;
|
||||
uint8_t *NewPtr = (uint8_t*)RoundUpToAlignment((uintptr_t)CurBufferPtr,
|
||||
Alignment);
|
||||
// Fail if we don't have room.
|
||||
if (NewPtr > BufferEnd) {
|
||||
CurBufferPtr = BufferEnd;
|
||||
return;
|
||||
}
|
||||
while (CurBufferPtr < NewPtr) {
|
||||
*CurBufferPtr++ = Fill;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitULEB128Bytes - This callback is invoked when a ULEB128 needs to be
|
||||
/// written to the output stream.
|
||||
void emitULEB128Bytes(uint64_t Value, unsigned PadTo = 0) {
|
||||
do {
|
||||
uint8_t Byte = Value & 0x7f;
|
||||
Value >>= 7;
|
||||
if (Value || PadTo != 0) Byte |= 0x80;
|
||||
emitByte(Byte);
|
||||
} while (Value);
|
||||
|
||||
if (PadTo) {
|
||||
do {
|
||||
uint8_t Byte = (PadTo > 1) ? 0x80 : 0x0;
|
||||
emitByte(Byte);
|
||||
} while (--PadTo);
|
||||
}
|
||||
}
|
||||
|
||||
/// emitSLEB128Bytes - This callback is invoked when a SLEB128 needs to be
|
||||
/// written to the output stream.
|
||||
void emitSLEB128Bytes(int64_t Value) {
|
||||
int32_t Sign = Value >> (8 * sizeof(Value) - 1);
|
||||
bool IsMore;
|
||||
|
||||
do {
|
||||
uint8_t Byte = Value & 0x7f;
|
||||
Value >>= 7;
|
||||
IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
|
||||
if (IsMore) Byte |= 0x80;
|
||||
emitByte(Byte);
|
||||
} while (IsMore);
|
||||
}
|
||||
|
||||
/// emitString - This callback is invoked when a String needs to be
|
||||
/// written to the output stream.
|
||||
void emitString(const std::string &String) {
|
||||
for (size_t i = 0, N = String.size(); i < N; ++i) {
|
||||
uint8_t C = String[i];
|
||||
emitByte(C);
|
||||
}
|
||||
emitByte(0);
|
||||
}
|
||||
|
||||
/// emitInt32 - Emit a int32 directive.
|
||||
void emitInt32(uint32_t Value) {
|
||||
if (4 <= BufferEnd-CurBufferPtr) {
|
||||
*((uint32_t*)CurBufferPtr) = Value;
|
||||
CurBufferPtr += 4;
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitInt64 - Emit a int64 directive.
|
||||
void emitInt64(uint64_t Value) {
|
||||
if (8 <= BufferEnd-CurBufferPtr) {
|
||||
*((uint64_t*)CurBufferPtr) = Value;
|
||||
CurBufferPtr += 8;
|
||||
} else {
|
||||
CurBufferPtr = BufferEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// emitInt32At - Emit the Int32 Value in Addr.
|
||||
void emitInt32At(uintptr_t *Addr, uintptr_t Value) {
|
||||
if (Addr >= (uintptr_t*)BufferBegin && Addr < (uintptr_t*)BufferEnd)
|
||||
(*(uint32_t*)Addr) = (uint32_t)Value;
|
||||
}
|
||||
|
||||
/// emitInt64At - Emit the Int64 Value in Addr.
|
||||
void emitInt64At(uintptr_t *Addr, uintptr_t Value) {
|
||||
if (Addr >= (uintptr_t*)BufferBegin && Addr < (uintptr_t*)BufferEnd)
|
||||
(*(uint64_t*)Addr) = (uint64_t)Value;
|
||||
}
|
||||
|
||||
|
||||
/// emitLabel - Emits a label
|
||||
void emitLabel(MCSymbol *Label) override = 0;
|
||||
|
||||
/// allocateSpace - Allocate a block of space in the current output buffer,
|
||||
/// returning null (and setting conditions to indicate buffer overflow) on
|
||||
/// failure. Alignment is the alignment in bytes of the buffer desired.
|
||||
void *allocateSpace(uintptr_t Size, unsigned Alignment) override {
|
||||
emitAlignment(Alignment);
|
||||
void *Result;
|
||||
|
||||
// Check for buffer overflow.
|
||||
if (Size >= (uintptr_t)(BufferEnd-CurBufferPtr)) {
|
||||
CurBufferPtr = BufferEnd;
|
||||
Result = nullptr;
|
||||
} else {
|
||||
// Allocate the space.
|
||||
Result = CurBufferPtr;
|
||||
CurBufferPtr += Size;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// 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) = 0;
|
||||
|
||||
/// StartMachineBasicBlock - This should be called by the target when a new
|
||||
/// basic block is about to be emitted. This way the MCE knows where the
|
||||
/// start of the block is, and can implement getMachineBasicBlockAddress.
|
||||
void StartMachineBasicBlock(MachineBasicBlock *MBB) override = 0;
|
||||
|
||||
/// getCurrentPCValue - This returns the address that the next emitted byte
|
||||
/// will be output to.
|
||||
///
|
||||
uintptr_t getCurrentPCValue() const override {
|
||||
return (uintptr_t)CurBufferPtr;
|
||||
}
|
||||
|
||||
/// getCurrentPCOffset - Return the offset from the start of the emitted
|
||||
/// buffer that we are currently writing to.
|
||||
uintptr_t getCurrentPCOffset() const override {
|
||||
return CurBufferPtr-BufferBegin;
|
||||
}
|
||||
|
||||
/// earlyResolveAddresses - True if the code emitter can use symbol addresses
|
||||
/// during code emission time. The JIT is capable of doing this because it
|
||||
/// creates jump tables or constant pools in memory on the fly while the
|
||||
/// object code emitters rely on a linker to have real addresses and should
|
||||
/// use relocations instead.
|
||||
bool earlyResolveAddresses() const override { return true; }
|
||||
|
||||
/// addRelocation - Whenever a relocatable address is needed, it should be
|
||||
/// noted with this interface.
|
||||
void addRelocation(const MachineRelocation &MR) override = 0;
|
||||
|
||||
/// FIXME: These should all be handled with relocations!
|
||||
|
||||
/// getConstantPoolEntryAddress - Return the address of the 'Index' entry in
|
||||
/// the constant pool that was last emitted with the emitConstantPool method.
|
||||
///
|
||||
uintptr_t getConstantPoolEntryAddress(unsigned Index) const override = 0;
|
||||
|
||||
/// getJumpTableEntryAddress - Return the address of the jump table with index
|
||||
/// 'Index' in the function that last called initJumpTableInfo.
|
||||
///
|
||||
uintptr_t getJumpTableEntryAddress(unsigned Index) const override = 0;
|
||||
|
||||
/// getMachineBasicBlockAddress - Return the address of the specified
|
||||
/// MachineBasicBlock, only usable after the label for the MBB has been
|
||||
/// emitted.
|
||||
///
|
||||
uintptr_t
|
||||
getMachineBasicBlockAddress(MachineBasicBlock *MBB) const override = 0;
|
||||
|
||||
/// getLabelAddress - Return the address of the specified Label, only usable
|
||||
/// after the Label has been emitted.
|
||||
///
|
||||
uintptr_t getLabelAddress(MCSymbol *Label) const override = 0;
|
||||
|
||||
/// Specifies the MachineModuleInfo object. This is used for exception handling
|
||||
/// purposes.
|
||||
void setModuleInfo(MachineModuleInfo* Info) override = 0;
|
||||
|
||||
/// getLabelLocations - Return the label locations map of the label IDs to
|
||||
/// their address.
|
||||
virtual DenseMap<MCSymbol*, uintptr_t> *getLabelLocations() {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -141,12 +141,6 @@ protected:
|
||||
// To avoid having libexecutionengine depend on the JIT and interpreter
|
||||
// libraries, the execution engine implementations set these functions to ctor
|
||||
// pointers at startup time if they are linked in.
|
||||
static ExecutionEngine *(*JITCtor)(
|
||||
Module *M,
|
||||
std::string *ErrorStr,
|
||||
JITMemoryManager *JMM,
|
||||
bool GVsWithCode,
|
||||
TargetMachine *TM);
|
||||
static ExecutionEngine *(*MCJITCtor)(
|
||||
Module *M,
|
||||
std::string *ErrorStr,
|
||||
@ -335,13 +329,6 @@ public:
|
||||
/// getFunctionAddress instead.
|
||||
virtual void *getPointerToFunction(Function *F) = 0;
|
||||
|
||||
/// getPointerToBasicBlock - The different EE's represent basic blocks in
|
||||
/// different ways. Return the representation for a blockaddress of the
|
||||
/// specified block.
|
||||
///
|
||||
/// This function will not be implemented for the MCJIT execution engine.
|
||||
virtual void *getPointerToBasicBlock(BasicBlock *BB) = 0;
|
||||
|
||||
/// getPointerToFunctionOrStub - If the specified function has been
|
||||
/// code-gen'd, return a pointer to the function. If not, compile it, or use
|
||||
/// a stub to implement lazy compilation if available. See
|
||||
@ -389,18 +376,6 @@ public:
|
||||
|
||||
void InitializeMemory(const Constant *Init, void *Addr);
|
||||
|
||||
/// recompileAndRelinkFunction - This method is used to force a function which
|
||||
/// has already been compiled to be compiled again, possibly after it has been
|
||||
/// modified. Then the entry to the old copy is overwritten with a branch to
|
||||
/// the new copy. If there was no old copy, this acts just like
|
||||
/// VM::getPointerToFunction().
|
||||
virtual void *recompileAndRelinkFunction(Function *F) = 0;
|
||||
|
||||
/// freeMachineCodeForFunction - Release memory in the ExecutionEngine
|
||||
/// corresponding to the machine code emitted to execute this function, useful
|
||||
/// for garbage-collecting generated code.
|
||||
virtual void freeMachineCodeForFunction(Function *F) = 0;
|
||||
|
||||
/// getOrEmitGlobalVariable - Return the address of the specified global
|
||||
/// variable, possibly emitting it to memory if needed. This is used by the
|
||||
/// Emitter.
|
||||
@ -537,14 +512,12 @@ private:
|
||||
CodeGenOpt::Level OptLevel;
|
||||
RTDyldMemoryManager *MCJMM;
|
||||
JITMemoryManager *JMM;
|
||||
bool AllocateGVsWithCode;
|
||||
TargetOptions Options;
|
||||
Reloc::Model RelocModel;
|
||||
CodeModel::Model CMModel;
|
||||
std::string MArch;
|
||||
std::string MCPU;
|
||||
SmallVector<std::string, 4> MAttrs;
|
||||
bool UseMCJIT;
|
||||
bool VerifyModules;
|
||||
|
||||
/// InitEngine - Does the common initialization of default options.
|
||||
@ -626,18 +599,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// setAllocateGVsWithCode - Sets whether global values should be allocated
|
||||
/// into the same buffer as code. For most applications this should be set
|
||||
/// to false. Allocating globals with code breaks freeMachineCodeForFunction
|
||||
/// and is probably unsafe and bad for performance. However, we have clients
|
||||
/// who depend on this behavior, so we must support it. This option defaults
|
||||
/// to false so that users of the new API can safely use the new memory
|
||||
/// manager and free machine code.
|
||||
EngineBuilder &setAllocateGVsWithCode(bool a) {
|
||||
AllocateGVsWithCode = a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// setMArch - Override the architecture set by the Module's triple.
|
||||
EngineBuilder &setMArch(StringRef march) {
|
||||
MArch.assign(march.begin(), march.end());
|
||||
@ -650,13 +611,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// setUseMCJIT - Set whether the MC-JIT implementation should be used
|
||||
/// (experimental).
|
||||
EngineBuilder &setUseMCJIT(bool Value) {
|
||||
UseMCJIT = Value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// setVerifyModules - Set whether the JIT implementation should verify
|
||||
/// IR modules during compilation.
|
||||
EngineBuilder &setVerifyModules(bool Verify) {
|
||||
|
@ -1,38 +0,0 @@
|
||||
//===-- JIT.h - Abstract Execution Engine Interface -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file forces the JIT to link in on certain operating systems.
|
||||
// (Windows).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_JIT_H
|
||||
#define LLVM_EXECUTIONENGINE_JIT_H
|
||||
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include <cstdlib>
|
||||
|
||||
extern "C" void LLVMLinkInJIT();
|
||||
|
||||
namespace {
|
||||
struct ForceJITLinking {
|
||||
ForceJITLinking() {
|
||||
// We must reference JIT in such a way that compilers will not
|
||||
// delete it all as dead code, even with whole program optimization,
|
||||
// yet is effectively a NO-OP. As the compiler isn't smart enough
|
||||
// to know that getenv() never returns -1, this will do the job.
|
||||
if (std::getenv("bar") != (char*) -1)
|
||||
return;
|
||||
|
||||
LLVMLinkInJIT();
|
||||
}
|
||||
} ForceJITLinking;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,136 +0,0 @@
|
||||
//===- Target/TargetJITInfo.h - Target Information for JIT ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes an abstract interface used by the Just-In-Time code
|
||||
// generator to perform target-specific activities, such as emitting stubs. If
|
||||
// a TargetMachine supports JIT code generation, it should provide one of these
|
||||
// objects through the getJITInfo() method.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TARGET_TARGETJITINFO_H
|
||||
#define LLVM_TARGET_TARGETJITINFO_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class JITCodeEmitter;
|
||||
class MachineRelocation;
|
||||
|
||||
/// TargetJITInfo - Target specific information required by the Just-In-Time
|
||||
/// code generator.
|
||||
class TargetJITInfo {
|
||||
virtual void anchor();
|
||||
public:
|
||||
virtual ~TargetJITInfo() {}
|
||||
|
||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
||||
/// code.
|
||||
///
|
||||
virtual void replaceMachineCodeForFunction(void *Old, void *New) = 0;
|
||||
|
||||
/// emitGlobalValueIndirectSym - Use the specified JITCodeEmitter object
|
||||
/// to emit an indirect symbol which contains the address of the specified
|
||||
/// ptr.
|
||||
virtual void *emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr,
|
||||
JITCodeEmitter &JCE) {
|
||||
llvm_unreachable("This target doesn't implement "
|
||||
"emitGlobalValueIndirectSym!");
|
||||
}
|
||||
|
||||
/// Records the required size and alignment for a call stub in bytes.
|
||||
struct StubLayout {
|
||||
size_t Size;
|
||||
size_t Alignment;
|
||||
};
|
||||
/// Returns the maximum size and alignment for a call stub on this target.
|
||||
virtual StubLayout getStubLayout() {
|
||||
llvm_unreachable("This target doesn't implement getStubLayout!");
|
||||
}
|
||||
|
||||
/// emitFunctionStub - Use the specified JITCodeEmitter object to emit a
|
||||
/// small native function that simply calls the function at the specified
|
||||
/// address. The JITCodeEmitter must already have storage allocated for the
|
||||
/// stub. Return the address of the resultant function, which may have been
|
||||
/// aligned from the address the JCE was set up to emit at.
|
||||
virtual void *emitFunctionStub(const Function* F, void *Target,
|
||||
JITCodeEmitter &JCE) {
|
||||
llvm_unreachable("This target doesn't implement emitFunctionStub!");
|
||||
}
|
||||
|
||||
/// getPICJumpTableEntry - Returns the value of the jumptable entry for the
|
||||
/// specific basic block.
|
||||
virtual uintptr_t getPICJumpTableEntry(uintptr_t BB, uintptr_t JTBase) {
|
||||
llvm_unreachable("This target doesn't implement getPICJumpTableEntry!");
|
||||
}
|
||||
|
||||
/// LazyResolverFn - This typedef is used to represent the function that
|
||||
/// unresolved call points should invoke. This is a target specific
|
||||
/// function that knows how to walk the stack and find out which stub the
|
||||
/// call is coming from.
|
||||
typedef void (*LazyResolverFn)();
|
||||
|
||||
/// JITCompilerFn - This typedef is used to represent the JIT function that
|
||||
/// lazily compiles the function corresponding to a stub. The JIT keeps
|
||||
/// track of the mapping between stubs and LLVM Functions, the target
|
||||
/// provides the ability to figure out the address of a stub that is called
|
||||
/// by the LazyResolverFn.
|
||||
typedef void* (*JITCompilerFn)(void *);
|
||||
|
||||
/// getLazyResolverFunction - This method is used to initialize the JIT,
|
||||
/// giving the target the function that should be used to compile a
|
||||
/// function, and giving the JIT the target function used to do the lazy
|
||||
/// resolving.
|
||||
virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn) {
|
||||
llvm_unreachable("Not implemented for this target!");
|
||||
}
|
||||
|
||||
/// relocate - Before the JIT can run a block of code that has been emitted,
|
||||
/// it must rewrite the code to contain the actual addresses of any
|
||||
/// referenced global symbols.
|
||||
virtual void relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase) {
|
||||
assert(NumRelocs == 0 && "This target does not have relocations!");
|
||||
}
|
||||
|
||||
/// allocateThreadLocalMemory - Each target has its own way of
|
||||
/// handling thread local variables. This method returns a value only
|
||||
/// meaningful to the target.
|
||||
virtual char* allocateThreadLocalMemory(size_t size) {
|
||||
llvm_unreachable("This target does not implement thread local storage!");
|
||||
}
|
||||
|
||||
/// needsGOT - Allows a target to specify that it would like the
|
||||
/// JIT to manage a GOT for it.
|
||||
bool needsGOT() const { return useGOT; }
|
||||
|
||||
/// hasCustomConstantPool - Allows a target to specify that constant
|
||||
/// pool address resolution is handled by the target.
|
||||
virtual bool hasCustomConstantPool() const { return false; }
|
||||
|
||||
/// hasCustomJumpTables - Allows a target to specify that jumptables
|
||||
/// are emitted by the target.
|
||||
virtual bool hasCustomJumpTables() const { return false; }
|
||||
|
||||
/// allocateSeparateGVMemory - If true, globals should be placed in
|
||||
/// separately allocated heap memory rather than in the same
|
||||
/// code memory allocated by JITCodeEmitter.
|
||||
virtual bool allocateSeparateGVMemory() const { return false; }
|
||||
protected:
|
||||
bool useGOT;
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -828,11 +828,6 @@ public:
|
||||
return UseUnderscoreLongJmp;
|
||||
}
|
||||
|
||||
/// Return whether the target can generate code for jump tables.
|
||||
bool supportJumpTables() const {
|
||||
return SupportJumpTables;
|
||||
}
|
||||
|
||||
/// Return integer threshold on number of blocks to use jump tables rather
|
||||
/// than if sequence.
|
||||
int getMinimumJumpTableEntries() const {
|
||||
@ -1001,11 +996,6 @@ protected:
|
||||
UseUnderscoreLongJmp = Val;
|
||||
}
|
||||
|
||||
/// Indicate whether the target can generate code for jump tables.
|
||||
void setSupportJumpTables(bool Val) {
|
||||
SupportJumpTables = Val;
|
||||
}
|
||||
|
||||
/// Indicate the number of blocks to generate jump tables rather than if
|
||||
/// sequence.
|
||||
void setMinimumJumpTableEntries(int Val) {
|
||||
@ -1509,10 +1499,6 @@ private:
|
||||
/// Defaults to false.
|
||||
bool UseUnderscoreLongJmp;
|
||||
|
||||
/// Whether the target can generate code for jumptables. If it's not true,
|
||||
/// then each jumptable must be lowered into if-then-else's.
|
||||
bool SupportJumpTables;
|
||||
|
||||
/// Number of blocks threshold to use jump tables.
|
||||
int MinimumJumpTableEntries;
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
namespace llvm {
|
||||
|
||||
class InstrItineraryData;
|
||||
class JITCodeEmitter;
|
||||
class GlobalValue;
|
||||
class Mangler;
|
||||
class MCAsmInfo;
|
||||
@ -36,7 +35,6 @@ class DataLayout;
|
||||
class TargetLibraryInfo;
|
||||
class TargetFrameLowering;
|
||||
class TargetIntrinsicInfo;
|
||||
class TargetJITInfo;
|
||||
class TargetLowering;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
@ -101,10 +99,6 @@ public:
|
||||
virtual const TargetSubtargetInfo *getSubtargetImpl() const {
|
||||
return nullptr;
|
||||
}
|
||||
TargetSubtargetInfo *getSubtargetImpl() {
|
||||
const TargetMachine *TM = this;
|
||||
return const_cast<TargetSubtargetInfo *>(TM->getSubtargetImpl());
|
||||
}
|
||||
|
||||
/// getSubtarget - This method returns a pointer to the specified type of
|
||||
/// TargetSubtargetInfo. In debug builds, it verifies that the object being
|
||||
@ -201,18 +195,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to
|
||||
/// get machine code emitted. This uses a JITCodeEmitter object to handle
|
||||
/// actually outputting the machine code and resolving things like the address
|
||||
/// of functions. This method returns true if machine code emission is
|
||||
/// not supported.
|
||||
///
|
||||
virtual bool addPassesToEmitMachineCode(PassManagerBase &,
|
||||
JITCodeEmitter &,
|
||||
bool /*DisableVerify*/ = true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// addPassesToEmitMC - Add passes to the specified pass manager to get
|
||||
/// machine code emitted with the MCJIT. This method returns true if machine
|
||||
/// code is not supported. It fills the MCContext Ctx pointer which can be
|
||||
@ -259,15 +241,6 @@ public:
|
||||
AnalysisID StartAfter = nullptr,
|
||||
AnalysisID StopAfter = nullptr) override;
|
||||
|
||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to
|
||||
/// get machine code emitted. This uses a JITCodeEmitter object to handle
|
||||
/// actually outputting the machine code and resolving things like the address
|
||||
/// of functions. This method returns true if machine code emission is
|
||||
/// not supported.
|
||||
///
|
||||
bool addPassesToEmitMachineCode(PassManagerBase &PM, JITCodeEmitter &MCE,
|
||||
bool DisableVerify = true) override;
|
||||
|
||||
/// addPassesToEmitMC - Add passes to the specified pass manager to get
|
||||
/// machine code emitted with the MCJIT. This method returns true if machine
|
||||
/// code is not supported. It fills the MCContext Ctx pointer which can be
|
||||
@ -275,14 +248,6 @@ public:
|
||||
///
|
||||
bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
|
||||
raw_ostream &OS, bool DisableVerify = true) override;
|
||||
|
||||
/// addCodeEmitter - This pass should be overridden by the target to add a
|
||||
/// code emitter, if supported. If this is not supported, 'true' should be
|
||||
/// returned.
|
||||
virtual bool addCodeEmitter(PassManagerBase &,
|
||||
JITCodeEmitter &) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -26,7 +26,6 @@ class SDep;
|
||||
class SUnit;
|
||||
class TargetFrameLowering;
|
||||
class TargetInstrInfo;
|
||||
class TargetJITInfo;
|
||||
class TargetLowering;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
@ -79,11 +78,6 @@ public:
|
||||
///
|
||||
virtual const TargetRegisterInfo *getRegisterInfo() const { return nullptr; }
|
||||
|
||||
/// getJITInfo - If this target supports a JIT, return information for it,
|
||||
/// otherwise return null.
|
||||
///
|
||||
virtual TargetJITInfo *getJITInfo() { return nullptr; }
|
||||
|
||||
/// getInstrItineraryData - Returns instruction itinerary data for the target
|
||||
/// or specific subtarget.
|
||||
///
|
||||
|
@ -188,9 +188,8 @@ unsigned BasicTTI::getJumpBufSize() const {
|
||||
|
||||
bool BasicTTI::shouldBuildLookupTables() const {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
return TLI->supportJumpTables() &&
|
||||
(TLI->isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
TLI->isOperationLegalOrCustom(ISD::BRIND, MVT::Other));
|
||||
return TLI->isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
TLI->isOperationLegalOrCustom(ISD::BRIND, MVT::Other);
|
||||
}
|
||||
|
||||
bool BasicTTI::haveFastSqrt(Type *Ty) const {
|
||||
|
@ -27,7 +27,6 @@ add_llvm_library(LLVMCodeGen
|
||||
InlineSpiller.cpp
|
||||
InterferenceCache.cpp
|
||||
IntrinsicLowering.cpp
|
||||
JITCodeEmitter.cpp
|
||||
JumpInstrTables.cpp
|
||||
LLVMTargetMachine.cpp
|
||||
LatencyPriorityQueue.cpp
|
||||
|
@ -1,14 +0,0 @@
|
||||
//===-- llvm/CodeGen/JITCodeEmitter.cpp - Code emission --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void JITCodeEmitter::anchor() { }
|
@ -226,26 +226,6 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// addPassesToEmitMachineCode - Add passes to the specified pass manager to
|
||||
/// get machine code emitted. This uses a JITCodeEmitter object to handle
|
||||
/// actually outputting the machine code and resolving things like the address
|
||||
/// of functions. This method should return true if machine code emission is
|
||||
/// not supported.
|
||||
///
|
||||
bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM,
|
||||
JITCodeEmitter &JCE,
|
||||
bool DisableVerify) {
|
||||
// Add common CodeGen passes.
|
||||
MCContext *Context = addPassesToGenerateCode(this, PM, DisableVerify, nullptr,
|
||||
nullptr);
|
||||
if (!Context)
|
||||
return true;
|
||||
|
||||
addCodeEmitter(PM, JCE);
|
||||
|
||||
return false; // success!
|
||||
}
|
||||
|
||||
/// addPassesToEmitMC - Add passes to the specified pass manager to get
|
||||
/// machine code emitted with the MCJIT. This method returns true if machine
|
||||
/// code is not supported. It fills the MCContext Ctx pointer which can be
|
||||
|
@ -2228,9 +2228,8 @@ bool SelectionDAGBuilder::handleSmallSwitchRange(CaseRec& CR,
|
||||
}
|
||||
|
||||
static inline bool areJTsAllowed(const TargetLowering &TLI) {
|
||||
return TLI.supportJumpTables() &&
|
||||
(TLI.isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
TLI.isOperationLegalOrCustom(ISD::BRIND, MVT::Other));
|
||||
return TLI.isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
TLI.isOperationLegalOrCustom(ISD::BRIND, MVT::Other);
|
||||
}
|
||||
|
||||
static APInt ComputeRange(const APInt &First, const APInt &Last) {
|
||||
|
@ -719,7 +719,6 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm,
|
||||
PrefLoopAlignment = 0;
|
||||
MinStackArgumentAlignment = 1;
|
||||
InsertFencesForAtomic = false;
|
||||
SupportJumpTables = true;
|
||||
MinimumJumpTableEntries = 4;
|
||||
|
||||
InitLibcallNames(LibcallRoutineNames, Triple(TM.getTargetTriple()));
|
||||
|
@ -8,7 +8,6 @@ add_llvm_library(LLVMExecutionEngine
|
||||
)
|
||||
|
||||
add_subdirectory(Interpreter)
|
||||
add_subdirectory(JIT)
|
||||
add_subdirectory(MCJIT)
|
||||
add_subdirectory(RuntimeDyld)
|
||||
|
||||
|
@ -48,12 +48,6 @@ void ObjectCache::anchor() {}
|
||||
void ObjectBuffer::anchor() {}
|
||||
void ObjectBufferStream::anchor() {}
|
||||
|
||||
ExecutionEngine *(*ExecutionEngine::JITCtor)(
|
||||
Module *M,
|
||||
std::string *ErrorStr,
|
||||
JITMemoryManager *JMM,
|
||||
bool GVsWithCode,
|
||||
TargetMachine *TM) = nullptr;
|
||||
ExecutionEngine *(*ExecutionEngine::MCJITCtor)(
|
||||
Module *M,
|
||||
std::string *ErrorStr,
|
||||
@ -417,10 +411,8 @@ void EngineBuilder::InitEngine() {
|
||||
MCJMM = nullptr;
|
||||
JMM = nullptr;
|
||||
Options = TargetOptions();
|
||||
AllocateGVsWithCode = false;
|
||||
RelocModel = Reloc::Default;
|
||||
CMModel = CodeModel::JITDefault;
|
||||
UseMCJIT = false;
|
||||
|
||||
// IR module verification is enabled by default in debug builds, and disabled
|
||||
// by default in release builds.
|
||||
@ -453,14 +445,6 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (MCJMM && ! UseMCJIT) {
|
||||
if (ErrorStr)
|
||||
*ErrorStr =
|
||||
"Cannot create a legacy JIT with a runtime dyld memory "
|
||||
"manager.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Unless the interpreter was explicitly selected or the JIT is not linked,
|
||||
// try making a JIT.
|
||||
@ -473,12 +457,9 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) {
|
||||
}
|
||||
|
||||
ExecutionEngine *EE = nullptr;
|
||||
if (UseMCJIT && ExecutionEngine::MCJITCtor)
|
||||
if (ExecutionEngine::MCJITCtor)
|
||||
EE = ExecutionEngine::MCJITCtor(M, ErrorStr, MCJMM ? MCJMM : JMM,
|
||||
TheTM.release());
|
||||
else if (ExecutionEngine::JITCtor)
|
||||
EE = ExecutionEngine::JITCtor(M, ErrorStr, JMM,
|
||||
AllocateGVsWithCode, TheTM.release());
|
||||
|
||||
if (EE) {
|
||||
EE->setVerifyModules(VerifyModules);
|
||||
@ -496,8 +477,7 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((WhichEngine & EngineKind::JIT) && !ExecutionEngine::JITCtor &&
|
||||
!ExecutionEngine::MCJITCtor) {
|
||||
if ((WhichEngine & EngineKind::JIT) && !ExecutionEngine::MCJITCtor) {
|
||||
if (ErrorStr)
|
||||
*ErrorStr = "JIT has not been linked in.";
|
||||
}
|
||||
@ -843,9 +823,6 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
|
||||
Result = PTOGV(getPointerToFunctionOrStub(const_cast<Function*>(F)));
|
||||
else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C))
|
||||
Result = PTOGV(getOrEmitGlobalVariable(const_cast<GlobalVariable*>(GV)));
|
||||
else if (const BlockAddress *BA = dyn_cast<BlockAddress>(C))
|
||||
Result = PTOGV(getPointerToBasicBlock(const_cast<BasicBlock*>(
|
||||
BA->getBasicBlock())));
|
||||
else
|
||||
llvm_unreachable("Unknown constant pointer type!");
|
||||
break;
|
||||
|
@ -192,7 +192,6 @@ LLVMBool LLVMCreateMCJITCompilerForModule(
|
||||
EngineBuilder builder(unwrap(M));
|
||||
builder.setEngineKind(EngineKind::JIT)
|
||||
.setErrorStr(&Error)
|
||||
.setUseMCJIT(true)
|
||||
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
|
||||
.setCodeModel(unwrap(options.CodeModel))
|
||||
.setTargetOptions(targetOptions);
|
||||
@ -275,7 +274,6 @@ LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F,
|
||||
}
|
||||
|
||||
void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F) {
|
||||
unwrap(EE)->freeMachineCodeForFunction(unwrap<Function>(F));
|
||||
}
|
||||
|
||||
void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M){
|
||||
@ -314,7 +312,7 @@ LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name,
|
||||
|
||||
void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE,
|
||||
LLVMValueRef Fn) {
|
||||
return unwrap(EE)->recompileAndRelinkFunction(unwrap<Function>(Fn));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE) {
|
||||
|
@ -121,17 +121,6 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// recompileAndRelinkFunction - For the interpreter, functions are always
|
||||
/// up-to-date.
|
||||
///
|
||||
void *recompileAndRelinkFunction(Function *F) override {
|
||||
return getPointerToFunction(F);
|
||||
}
|
||||
|
||||
/// freeMachineCodeForFunction - The interpreter does not generate any code.
|
||||
///
|
||||
void freeMachineCodeForFunction(Function *F) override { }
|
||||
|
||||
// Methods used to execute code:
|
||||
// Place a call on the stack
|
||||
void callFunction(Function *F, const std::vector<GenericValue> &ArgVals);
|
||||
@ -213,7 +202,6 @@ private: // Helper functions
|
||||
void SwitchToNewBasicBlock(BasicBlock *Dest, ExecutionContext &SF);
|
||||
|
||||
void *getPointerToFunction(Function *F) override { return (void*)F; }
|
||||
void *getPointerToBasicBlock(BasicBlock *BB) override { return (void*)BB; }
|
||||
|
||||
void initializeExecutionEngine() { }
|
||||
void initializeExternalFunctions();
|
||||
|
@ -1,8 +0,0 @@
|
||||
# TODO: Support other architectures. See Makefile.
|
||||
add_definitions(-DENABLE_X86_JIT)
|
||||
|
||||
add_llvm_library(LLVMJIT
|
||||
JIT.cpp
|
||||
JITEmitter.cpp
|
||||
JITMemoryManager.cpp
|
||||
)
|
@ -1,696 +0,0 @@
|
||||
//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tool implements a just-in-time compiler for LLVM, allowing direct
|
||||
// execution of LLVM bitcode in an efficient manner.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "JIT.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/CodeGen/MachineCodeInfo.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/JITMemoryManager.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple gcc defaults to -fuse-cxa-atexit (i.e. calls __cxa_atexit instead
|
||||
// of atexit). It passes the address of linker generated symbol __dso_handle
|
||||
// to the function.
|
||||
// This configuration change happened at version 5330.
|
||||
# include <AvailabilityMacros.h>
|
||||
# if defined(MAC_OS_X_VERSION_10_4) && \
|
||||
((MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4) || \
|
||||
(MAC_OS_X_VERSION_MIN_REQUIRED == MAC_OS_X_VERSION_10_4 && \
|
||||
__APPLE_CC__ >= 5330))
|
||||
# ifndef HAVE___DSO_HANDLE
|
||||
# define HAVE___DSO_HANDLE 1
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE___DSO_HANDLE
|
||||
extern void *__dso_handle __attribute__ ((__visibility__ ("hidden")));
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
static struct RegisterJIT {
|
||||
RegisterJIT() { JIT::Register(); }
|
||||
} JITRegistrator;
|
||||
|
||||
}
|
||||
|
||||
extern "C" void LLVMLinkInJIT() {
|
||||
}
|
||||
|
||||
/// createJIT - This is the factory method for creating a JIT for the current
|
||||
/// machine, it does not fall back to the interpreter. This takes ownership
|
||||
/// of the module.
|
||||
ExecutionEngine *JIT::createJIT(Module *M,
|
||||
std::string *ErrorStr,
|
||||
JITMemoryManager *JMM,
|
||||
bool GVsWithCode,
|
||||
TargetMachine *TM) {
|
||||
// Try to register the program as a source of symbols to resolve against.
|
||||
//
|
||||
// FIXME: Don't do this here.
|
||||
sys::DynamicLibrary::LoadLibraryPermanently(nullptr, nullptr);
|
||||
|
||||
// If the target supports JIT code generation, create the JIT.
|
||||
if (TargetJITInfo *TJ = TM->getSubtargetImpl()->getJITInfo()) {
|
||||
return new JIT(M, *TM, *TJ, JMM, GVsWithCode);
|
||||
} else {
|
||||
if (ErrorStr)
|
||||
*ErrorStr = "target does not support JIT code generation";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// This class supports the global getPointerToNamedFunction(), which allows
|
||||
/// bugpoint or gdb users to search for a function by name without any context.
|
||||
class JitPool {
|
||||
SmallPtrSet<JIT*, 1> JITs; // Optimize for process containing just 1 JIT.
|
||||
mutable sys::Mutex Lock;
|
||||
public:
|
||||
void Add(JIT *jit) {
|
||||
MutexGuard guard(Lock);
|
||||
JITs.insert(jit);
|
||||
}
|
||||
void Remove(JIT *jit) {
|
||||
MutexGuard guard(Lock);
|
||||
JITs.erase(jit);
|
||||
}
|
||||
void *getPointerToNamedFunction(const char *Name) const {
|
||||
MutexGuard guard(Lock);
|
||||
assert(JITs.size() != 0 && "No Jit registered");
|
||||
//search function in every instance of JIT
|
||||
for (SmallPtrSet<JIT*, 1>::const_iterator Jit = JITs.begin(),
|
||||
end = JITs.end();
|
||||
Jit != end; ++Jit) {
|
||||
if (Function *F = (*Jit)->FindFunctionNamed(Name))
|
||||
return (*Jit)->getPointerToFunction(F);
|
||||
}
|
||||
// The function is not available : fallback on the first created (will
|
||||
// search in symbol of the current program/library)
|
||||
return (*JITs.begin())->getPointerToNamedFunction(Name);
|
||||
}
|
||||
};
|
||||
ManagedStatic<JitPool> AllJits;
|
||||
}
|
||||
extern "C" {
|
||||
// getPointerToNamedFunction - This function is used as a global wrapper to
|
||||
// JIT::getPointerToNamedFunction for the purpose of resolving symbols when
|
||||
// bugpoint is debugging the JIT. In that scenario, we are loading an .so and
|
||||
// need to resolve function(s) that are being mis-codegenerated, so we need to
|
||||
// resolve their addresses at runtime, and this is the way to do it.
|
||||
void *getPointerToNamedFunction(const char *Name) {
|
||||
return AllJits->getPointerToNamedFunction(Name);
|
||||
}
|
||||
}
|
||||
|
||||
JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
|
||||
JITMemoryManager *jmm, bool GVsWithCode)
|
||||
: ExecutionEngine(M), TM(tm), TJI(tji),
|
||||
JMM(jmm ? jmm : JITMemoryManager::CreateDefaultMemManager()),
|
||||
AllocateGVsWithCode(GVsWithCode), isAlreadyCodeGenerating(false) {
|
||||
setDataLayout(TM.getSubtargetImpl()->getDataLayout());
|
||||
|
||||
jitstate = new JITState(M);
|
||||
|
||||
// Initialize JCE
|
||||
JCE = createEmitter(*this, JMM, TM);
|
||||
|
||||
// Register in global list of all JITs.
|
||||
AllJits->Add(this);
|
||||
|
||||
// Add target data
|
||||
MutexGuard locked(lock);
|
||||
FunctionPassManager &PM = jitstate->getPM();
|
||||
M->setDataLayout(TM.getSubtargetImpl()->getDataLayout());
|
||||
PM.add(new DataLayoutPass(M));
|
||||
|
||||
// Turn the machine code intermediate representation into bytes in memory that
|
||||
// may be executed.
|
||||
if (TM.addPassesToEmitMachineCode(PM, *JCE, !getVerifyModules())) {
|
||||
report_fatal_error("Target does not support machine code emission!");
|
||||
}
|
||||
|
||||
// Initialize passes.
|
||||
PM.doInitialization();
|
||||
}
|
||||
|
||||
JIT::~JIT() {
|
||||
// Cleanup.
|
||||
AllJits->Remove(this);
|
||||
delete jitstate;
|
||||
delete JCE;
|
||||
// JMM is a ownership of JCE, so we no need delete JMM here.
|
||||
delete &TM;
|
||||
}
|
||||
|
||||
/// addModule - Add a new Module to the JIT. If we previously removed the last
|
||||
/// Module, we need re-initialize jitstate with a valid Module.
|
||||
void JIT::addModule(Module *M) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
if (Modules.empty()) {
|
||||
assert(!jitstate && "jitstate should be NULL if Modules vector is empty!");
|
||||
|
||||
jitstate = new JITState(M);
|
||||
|
||||
FunctionPassManager &PM = jitstate->getPM();
|
||||
M->setDataLayout(TM.getSubtargetImpl()->getDataLayout());
|
||||
PM.add(new DataLayoutPass(M));
|
||||
|
||||
// Turn the machine code intermediate representation into bytes in memory
|
||||
// that may be executed.
|
||||
if (TM.addPassesToEmitMachineCode(PM, *JCE, !getVerifyModules())) {
|
||||
report_fatal_error("Target does not support machine code emission!");
|
||||
}
|
||||
|
||||
// Initialize passes.
|
||||
PM.doInitialization();
|
||||
}
|
||||
|
||||
ExecutionEngine::addModule(M);
|
||||
}
|
||||
|
||||
/// removeModule - If we are removing the last Module, invalidate the jitstate
|
||||
/// since the PassManager it contains references a released Module.
|
||||
bool JIT::removeModule(Module *M) {
|
||||
bool result = ExecutionEngine::removeModule(M);
|
||||
|
||||
MutexGuard locked(lock);
|
||||
|
||||
if (jitstate && jitstate->getModule() == M) {
|
||||
delete jitstate;
|
||||
jitstate = nullptr;
|
||||
}
|
||||
|
||||
if (!jitstate && !Modules.empty()) {
|
||||
jitstate = new JITState(Modules[0]);
|
||||
|
||||
FunctionPassManager &PM = jitstate->getPM();
|
||||
M->setDataLayout(TM.getSubtargetImpl()->getDataLayout());
|
||||
PM.add(new DataLayoutPass(M));
|
||||
|
||||
// Turn the machine code intermediate representation into bytes in memory
|
||||
// that may be executed.
|
||||
if (TM.addPassesToEmitMachineCode(PM, *JCE, !getVerifyModules())) {
|
||||
report_fatal_error("Target does not support machine code emission!");
|
||||
}
|
||||
|
||||
// Initialize passes.
|
||||
PM.doInitialization();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// run - Start execution with the specified function and arguments.
|
||||
///
|
||||
GenericValue JIT::runFunction(Function *F,
|
||||
const std::vector<GenericValue> &ArgValues) {
|
||||
assert(F && "Function *F was null at entry to run()");
|
||||
|
||||
void *FPtr = getPointerToFunction(F);
|
||||
assert(FPtr && "Pointer to fn's code was null after getPointerToFunction");
|
||||
FunctionType *FTy = F->getFunctionType();
|
||||
Type *RetTy = FTy->getReturnType();
|
||||
|
||||
assert((FTy->getNumParams() == ArgValues.size() ||
|
||||
(FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) &&
|
||||
"Wrong number of arguments passed into function!");
|
||||
assert(FTy->getNumParams() == ArgValues.size() &&
|
||||
"This doesn't support passing arguments through varargs (yet)!");
|
||||
|
||||
// Handle some common cases first. These cases correspond to common `main'
|
||||
// prototypes.
|
||||
if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) {
|
||||
switch (ArgValues.size()) {
|
||||
case 3:
|
||||
if (FTy->getParamType(0)->isIntegerTy(32) &&
|
||||
FTy->getParamType(1)->isPointerTy() &&
|
||||
FTy->getParamType(2)->isPointerTy()) {
|
||||
int (*PF)(int, char **, const char **) =
|
||||
(int(*)(int, char **, const char **))(intptr_t)FPtr;
|
||||
|
||||
// Call the function.
|
||||
GenericValue rv;
|
||||
rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(),
|
||||
(char **)GVTOP(ArgValues[1]),
|
||||
(const char **)GVTOP(ArgValues[2])));
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (FTy->getParamType(0)->isIntegerTy(32) &&
|
||||
FTy->getParamType(1)->isPointerTy()) {
|
||||
int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr;
|
||||
|
||||
// Call the function.
|
||||
GenericValue rv;
|
||||
rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(),
|
||||
(char **)GVTOP(ArgValues[1])));
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (FTy->getParamType(0)->isIntegerTy(32)) {
|
||||
GenericValue rv;
|
||||
int (*PF)(int) = (int(*)(int))(intptr_t)FPtr;
|
||||
rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue()));
|
||||
return rv;
|
||||
}
|
||||
if (FTy->getParamType(0)->isPointerTy()) {
|
||||
GenericValue rv;
|
||||
int (*PF)(char *) = (int(*)(char *))(intptr_t)FPtr;
|
||||
rv.IntVal = APInt(32, PF((char*)GVTOP(ArgValues[0])));
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle cases where no arguments are passed first.
|
||||
if (ArgValues.empty()) {
|
||||
GenericValue rv;
|
||||
switch (RetTy->getTypeID()) {
|
||||
default: llvm_unreachable("Unknown return type for function call!");
|
||||
case Type::IntegerTyID: {
|
||||
unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth();
|
||||
if (BitWidth == 1)
|
||||
rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)());
|
||||
else if (BitWidth <= 8)
|
||||
rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)());
|
||||
else if (BitWidth <= 16)
|
||||
rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)());
|
||||
else if (BitWidth <= 32)
|
||||
rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)());
|
||||
else if (BitWidth <= 64)
|
||||
rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)());
|
||||
else
|
||||
llvm_unreachable("Integer types > 64 bits not supported");
|
||||
return rv;
|
||||
}
|
||||
case Type::VoidTyID:
|
||||
rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)());
|
||||
return rv;
|
||||
case Type::FloatTyID:
|
||||
rv.FloatVal = ((float(*)())(intptr_t)FPtr)();
|
||||
return rv;
|
||||
case Type::DoubleTyID:
|
||||
rv.DoubleVal = ((double(*)())(intptr_t)FPtr)();
|
||||
return rv;
|
||||
case Type::X86_FP80TyID:
|
||||
case Type::FP128TyID:
|
||||
case Type::PPC_FP128TyID:
|
||||
llvm_unreachable("long double not supported yet");
|
||||
case Type::PointerTyID:
|
||||
return PTOGV(((void*(*)())(intptr_t)FPtr)());
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, this is not one of our quick and easy cases. Because we don't have a
|
||||
// full FFI, we have to codegen a nullary stub function that just calls the
|
||||
// function we are interested in, passing in constants for all of the
|
||||
// arguments. Make this function and return.
|
||||
|
||||
// First, create the function.
|
||||
FunctionType *STy=FunctionType::get(RetTy, false);
|
||||
Function *Stub = Function::Create(STy, Function::InternalLinkage, "",
|
||||
F->getParent());
|
||||
|
||||
// Insert a basic block.
|
||||
BasicBlock *StubBB = BasicBlock::Create(F->getContext(), "", Stub);
|
||||
|
||||
// Convert all of the GenericValue arguments over to constants. Note that we
|
||||
// currently don't support varargs.
|
||||
SmallVector<Value*, 8> Args;
|
||||
for (unsigned i = 0, e = ArgValues.size(); i != e; ++i) {
|
||||
Constant *C = nullptr;
|
||||
Type *ArgTy = FTy->getParamType(i);
|
||||
const GenericValue &AV = ArgValues[i];
|
||||
switch (ArgTy->getTypeID()) {
|
||||
default: llvm_unreachable("Unknown argument type for function call!");
|
||||
case Type::IntegerTyID:
|
||||
C = ConstantInt::get(F->getContext(), AV.IntVal);
|
||||
break;
|
||||
case Type::FloatTyID:
|
||||
C = ConstantFP::get(F->getContext(), APFloat(AV.FloatVal));
|
||||
break;
|
||||
case Type::DoubleTyID:
|
||||
C = ConstantFP::get(F->getContext(), APFloat(AV.DoubleVal));
|
||||
break;
|
||||
case Type::PPC_FP128TyID:
|
||||
case Type::X86_FP80TyID:
|
||||
case Type::FP128TyID:
|
||||
C = ConstantFP::get(F->getContext(), APFloat(ArgTy->getFltSemantics(),
|
||||
AV.IntVal));
|
||||
break;
|
||||
case Type::PointerTyID:
|
||||
void *ArgPtr = GVTOP(AV);
|
||||
if (sizeof(void*) == 4)
|
||||
C = ConstantInt::get(Type::getInt32Ty(F->getContext()),
|
||||
(int)(intptr_t)ArgPtr);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
CallInst *TheCall = CallInst::Create(F, Args, "", StubBB);
|
||||
TheCall->setCallingConv(F->getCallingConv());
|
||||
TheCall->setTailCall();
|
||||
if (!TheCall->getType()->isVoidTy())
|
||||
// Return result of the call.
|
||||
ReturnInst::Create(F->getContext(), TheCall, StubBB);
|
||||
else
|
||||
ReturnInst::Create(F->getContext(), StubBB); // Just return void.
|
||||
|
||||
// Finally, call our nullary stub function.
|
||||
GenericValue Result = runFunction(Stub, std::vector<GenericValue>());
|
||||
// Erase it, since no other function can have a reference to it.
|
||||
Stub->eraseFromParent();
|
||||
// And return the result.
|
||||
return Result;
|
||||
}
|
||||
|
||||
void JIT::RegisterJITEventListener(JITEventListener *L) {
|
||||
if (!L)
|
||||
return;
|
||||
MutexGuard locked(lock);
|
||||
EventListeners.push_back(L);
|
||||
}
|
||||
void JIT::UnregisterJITEventListener(JITEventListener *L) {
|
||||
if (!L)
|
||||
return;
|
||||
MutexGuard locked(lock);
|
||||
std::vector<JITEventListener*>::reverse_iterator I=
|
||||
std::find(EventListeners.rbegin(), EventListeners.rend(), L);
|
||||
if (I != EventListeners.rend()) {
|
||||
std::swap(*I, EventListeners.back());
|
||||
EventListeners.pop_back();
|
||||
}
|
||||
}
|
||||
void JIT::NotifyFunctionEmitted(
|
||||
const Function &F,
|
||||
void *Code, size_t Size,
|
||||
const JITEvent_EmittedFunctionDetails &Details) {
|
||||
MutexGuard locked(lock);
|
||||
for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
|
||||
EventListeners[I]->NotifyFunctionEmitted(F, Code, Size, Details);
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::NotifyFreeingMachineCode(void *OldPtr) {
|
||||
MutexGuard locked(lock);
|
||||
for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
|
||||
EventListeners[I]->NotifyFreeingMachineCode(OldPtr);
|
||||
}
|
||||
}
|
||||
|
||||
/// runJITOnFunction - Run the FunctionPassManager full of
|
||||
/// just-in-time compilation passes on F, hopefully filling in
|
||||
/// GlobalAddress[F] with the address of F's machine code.
|
||||
///
|
||||
void JIT::runJITOnFunction(Function *F, MachineCodeInfo *MCI) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
class MCIListener : public JITEventListener {
|
||||
MachineCodeInfo *const MCI;
|
||||
public:
|
||||
MCIListener(MachineCodeInfo *mci) : MCI(mci) {}
|
||||
void NotifyFunctionEmitted(const Function &, void *Code, size_t Size,
|
||||
const EmittedFunctionDetails &) override {
|
||||
MCI->setAddress(Code);
|
||||
MCI->setSize(Size);
|
||||
}
|
||||
};
|
||||
MCIListener MCIL(MCI);
|
||||
if (MCI)
|
||||
RegisterJITEventListener(&MCIL);
|
||||
|
||||
runJITOnFunctionUnlocked(F);
|
||||
|
||||
if (MCI)
|
||||
UnregisterJITEventListener(&MCIL);
|
||||
}
|
||||
|
||||
void JIT::runJITOnFunctionUnlocked(Function *F) {
|
||||
assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");
|
||||
|
||||
jitTheFunctionUnlocked(F);
|
||||
|
||||
// If the function referred to another function that had not yet been
|
||||
// read from bitcode, and we are jitting non-lazily, emit it now.
|
||||
while (!jitstate->getPendingFunctions().empty()) {
|
||||
Function *PF = jitstate->getPendingFunctions().back();
|
||||
jitstate->getPendingFunctions().pop_back();
|
||||
|
||||
assert(!PF->hasAvailableExternallyLinkage() &&
|
||||
"Externally-defined function should not be in pending list.");
|
||||
|
||||
jitTheFunctionUnlocked(PF);
|
||||
|
||||
// Now that the function has been jitted, ask the JITEmitter to rewrite
|
||||
// the stub with real address of the function.
|
||||
updateFunctionStubUnlocked(PF);
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::jitTheFunctionUnlocked(Function *F) {
|
||||
isAlreadyCodeGenerating = true;
|
||||
jitstate->getPM().run(*F);
|
||||
isAlreadyCodeGenerating = false;
|
||||
|
||||
// clear basic block addresses after this function is done
|
||||
getBasicBlockAddressMap().clear();
|
||||
}
|
||||
|
||||
/// getPointerToFunction - This method is used to get the address of the
|
||||
/// specified function, compiling it if necessary.
|
||||
///
|
||||
void *JIT::getPointerToFunction(Function *F) {
|
||||
|
||||
if (void *Addr = getPointerToGlobalIfAvailable(F))
|
||||
return Addr; // Check if function already code gen'd
|
||||
|
||||
MutexGuard locked(lock);
|
||||
|
||||
// Now that this thread owns the lock, make sure we read in the function if it
|
||||
// exists in this Module.
|
||||
std::string ErrorMsg;
|
||||
if (F->Materialize(&ErrorMsg)) {
|
||||
report_fatal_error("Error reading function '" + F->getName()+
|
||||
"' from bitcode file: " + ErrorMsg);
|
||||
}
|
||||
|
||||
// ... and check if another thread has already code gen'd the function.
|
||||
if (void *Addr = getPointerToGlobalIfAvailable(F))
|
||||
return Addr;
|
||||
|
||||
if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
|
||||
bool AbortOnFailure = !F->hasExternalWeakLinkage();
|
||||
void *Addr = getPointerToNamedFunction(F->getName(), AbortOnFailure);
|
||||
addGlobalMapping(F, Addr);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
runJITOnFunctionUnlocked(F);
|
||||
|
||||
void *Addr = getPointerToGlobalIfAvailable(F);
|
||||
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void JIT::addPointerToBasicBlock(const BasicBlock *BB, void *Addr) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
BasicBlockAddressMapTy::iterator I =
|
||||
getBasicBlockAddressMap().find(BB);
|
||||
if (I == getBasicBlockAddressMap().end()) {
|
||||
getBasicBlockAddressMap()[BB] = Addr;
|
||||
} else {
|
||||
// ignore repeats: some BBs can be split into few MBBs?
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::clearPointerToBasicBlock(const BasicBlock *BB) {
|
||||
MutexGuard locked(lock);
|
||||
getBasicBlockAddressMap().erase(BB);
|
||||
}
|
||||
|
||||
void *JIT::getPointerToBasicBlock(BasicBlock *BB) {
|
||||
// make sure it's function is compiled by JIT
|
||||
(void)getPointerToFunction(BB->getParent());
|
||||
|
||||
// resolve basic block address
|
||||
MutexGuard locked(lock);
|
||||
|
||||
BasicBlockAddressMapTy::iterator I =
|
||||
getBasicBlockAddressMap().find(BB);
|
||||
if (I != getBasicBlockAddressMap().end()) {
|
||||
return I->second;
|
||||
} else {
|
||||
llvm_unreachable("JIT does not have BB address for address-of-label, was"
|
||||
" it eliminated by optimizer?");
|
||||
}
|
||||
}
|
||||
|
||||
void *JIT::getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure){
|
||||
if (!isSymbolSearchingDisabled()) {
|
||||
void *ptr = JMM->getPointerToNamedFunction(Name, false);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// If a LazyFunctionCreator is installed, use it to get/create the function.
|
||||
if (LazyFunctionCreator)
|
||||
if (void *RP = LazyFunctionCreator(Name))
|
||||
return RP;
|
||||
|
||||
if (AbortOnFailure) {
|
||||
report_fatal_error("Program used external function '"+Name+
|
||||
"' which could not be resolved!");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/// getOrEmitGlobalVariable - Return the address of the specified global
|
||||
/// variable, possibly emitting it to memory if needed. This is used by the
|
||||
/// Emitter.
|
||||
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
|
||||
MutexGuard locked(lock);
|
||||
|
||||
void *Ptr = getPointerToGlobalIfAvailable(GV);
|
||||
if (Ptr) return Ptr;
|
||||
|
||||
// If the global is external, just remember the address.
|
||||
if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) {
|
||||
#if HAVE___DSO_HANDLE
|
||||
if (GV->getName() == "__dso_handle")
|
||||
return (void*)&__dso_handle;
|
||||
#endif
|
||||
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(GV->getName());
|
||||
if (!Ptr) {
|
||||
report_fatal_error("Could not resolve external global address: "
|
||||
+GV->getName());
|
||||
}
|
||||
addGlobalMapping(GV, Ptr);
|
||||
} else {
|
||||
// If the global hasn't been emitted to memory yet, allocate space and
|
||||
// emit it into memory.
|
||||
Ptr = getMemoryForGV(GV);
|
||||
addGlobalMapping(GV, Ptr);
|
||||
EmitGlobalVariable(GV); // Initialize the variable.
|
||||
}
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
/// recompileAndRelinkFunction - This method is used to force a function
|
||||
/// which has already been compiled, to be compiled again, possibly
|
||||
/// after it has been modified. Then the entry to the old copy is overwritten
|
||||
/// with a branch to the new copy. If there was no old copy, this acts
|
||||
/// just like JIT::getPointerToFunction().
|
||||
///
|
||||
void *JIT::recompileAndRelinkFunction(Function *F) {
|
||||
void *OldAddr = getPointerToGlobalIfAvailable(F);
|
||||
|
||||
// If it's not already compiled there is no reason to patch it up.
|
||||
if (!OldAddr) return getPointerToFunction(F);
|
||||
|
||||
// Delete the old function mapping.
|
||||
addGlobalMapping(F, nullptr);
|
||||
|
||||
// Recodegen the function
|
||||
runJITOnFunction(F);
|
||||
|
||||
// Update state, forward the old function to the new function.
|
||||
void *Addr = getPointerToGlobalIfAvailable(F);
|
||||
assert(Addr && "Code generation didn't add function to GlobalAddress table!");
|
||||
TJI.replaceMachineCodeForFunction(OldAddr, Addr);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
/// getMemoryForGV - This method abstracts memory allocation of global
|
||||
/// variable so that the JIT can allocate thread local variables depending
|
||||
/// on the target.
|
||||
///
|
||||
char* JIT::getMemoryForGV(const GlobalVariable* GV) {
|
||||
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()) {
|
||||
report_fatal_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.
|
||||
Type *GlobalType = GV->getType()->getElementType();
|
||||
size_t S = getDataLayout()->getTypeAllocSize(GlobalType);
|
||||
size_t A = getDataLayout()->getPreferredAlignment(GV);
|
||||
if (GV->isThreadLocal()) {
|
||||
MutexGuard locked(lock);
|
||||
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 {
|
||||
Ptr = (char*)JCE->allocateGlobal(S, A);
|
||||
}
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
void JIT::addPendingFunction(Function *F) {
|
||||
MutexGuard locked(lock);
|
||||
jitstate->getPendingFunctions().push_back(F);
|
||||
}
|
||||
|
||||
|
||||
JITEventListener::~JITEventListener() {}
|
@ -1,214 +0,0 @@
|
||||
//===-- JIT.h - Class definition for the JIT --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the top-level JIT data structure.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef JIT_H
|
||||
#define JIT_H
|
||||
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
struct JITEvent_EmittedFunctionDetails;
|
||||
class MachineCodeEmitter;
|
||||
class MachineCodeInfo;
|
||||
class TargetJITInfo;
|
||||
class TargetMachine;
|
||||
|
||||
class JITState {
|
||||
private:
|
||||
FunctionPassManager PM; // Passes to compile a function
|
||||
Module *M; // Module used to create the PM
|
||||
|
||||
/// PendingFunctions - Functions which have not been code generated yet, but
|
||||
/// were called from a function being code generated.
|
||||
std::vector<AssertingVH<Function> > PendingFunctions;
|
||||
|
||||
public:
|
||||
explicit JITState(Module *M) : PM(M), M(M) {}
|
||||
|
||||
FunctionPassManager &getPM() {
|
||||
return PM;
|
||||
}
|
||||
|
||||
Module *getModule() const { return M; }
|
||||
std::vector<AssertingVH<Function> > &getPendingFunctions() {
|
||||
return PendingFunctions;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class JIT : public ExecutionEngine {
|
||||
/// types
|
||||
typedef ValueMap<const BasicBlock *, void *>
|
||||
BasicBlockAddressMapTy;
|
||||
/// data
|
||||
TargetMachine &TM; // The current target we are compiling to
|
||||
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
|
||||
JITCodeEmitter *JCE; // JCE object
|
||||
JITMemoryManager *JMM;
|
||||
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;
|
||||
|
||||
/// True while the JIT is generating code. Used to assert against recursive
|
||||
/// entry.
|
||||
bool isAlreadyCodeGenerating;
|
||||
|
||||
JITState *jitstate;
|
||||
|
||||
/// BasicBlockAddressMap - A mapping between LLVM basic blocks and their
|
||||
/// actualized version, only filled for basic blocks that have their address
|
||||
/// taken.
|
||||
BasicBlockAddressMapTy BasicBlockAddressMap;
|
||||
|
||||
|
||||
JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
|
||||
JITMemoryManager *JMM, bool AllocateGVsWithCode);
|
||||
public:
|
||||
~JIT();
|
||||
|
||||
static void Register() {
|
||||
JITCtor = createJIT;
|
||||
}
|
||||
|
||||
/// getJITInfo - Return the target JIT information structure.
|
||||
///
|
||||
TargetJITInfo &getJITInfo() const { return TJI; }
|
||||
|
||||
void addModule(Module *M) override;
|
||||
|
||||
/// removeModule - Remove a Module from the list of modules. Returns true if
|
||||
/// M is found.
|
||||
bool removeModule(Module *M) override;
|
||||
|
||||
/// runFunction - Start execution with the specified function and arguments.
|
||||
///
|
||||
GenericValue runFunction(Function *F,
|
||||
const std::vector<GenericValue> &ArgValues) override;
|
||||
|
||||
/// getPointerToNamedFunction - This method returns the address of the
|
||||
/// specified function by using the MemoryManager. As such it is only
|
||||
/// useful for resolving library symbols, not code generated symbols.
|
||||
///
|
||||
/// If AbortOnFailure is false and no function with the given name is
|
||||
/// found, this function silently returns a null pointer. Otherwise,
|
||||
/// it prints a message to stderr and aborts.
|
||||
///
|
||||
void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true) override;
|
||||
|
||||
// CompilationCallback - Invoked the first time that a call site is found,
|
||||
// which causes lazy compilation of the target function.
|
||||
//
|
||||
static void CompilationCallback();
|
||||
|
||||
/// getPointerToFunction - This returns the address of the specified function,
|
||||
/// compiling it if necessary.
|
||||
///
|
||||
void *getPointerToFunction(Function *F) override;
|
||||
|
||||
/// addPointerToBasicBlock - Adds address of the specific basic block.
|
||||
void addPointerToBasicBlock(const BasicBlock *BB, void *Addr);
|
||||
|
||||
/// clearPointerToBasicBlock - Removes address of specific basic block.
|
||||
void clearPointerToBasicBlock(const BasicBlock *BB);
|
||||
|
||||
/// getPointerToBasicBlock - This returns the address of the specified basic
|
||||
/// block, assuming function is compiled.
|
||||
void *getPointerToBasicBlock(BasicBlock *BB) override;
|
||||
|
||||
/// getOrEmitGlobalVariable - Return the address of the specified global
|
||||
/// variable, possibly emitting it to memory if needed. This is used by the
|
||||
/// Emitter.
|
||||
void *getOrEmitGlobalVariable(const GlobalVariable *GV) override;
|
||||
|
||||
/// getPointerToFunctionOrStub - If the specified function has been
|
||||
/// code-gen'd, return a pointer to the function. If not, compile it, or use
|
||||
/// a stub to implement lazy compilation if available.
|
||||
///
|
||||
void *getPointerToFunctionOrStub(Function *F) override;
|
||||
|
||||
/// recompileAndRelinkFunction - This method is used to force a function
|
||||
/// which has already been compiled, to be compiled again, possibly
|
||||
/// after it has been modified. Then the entry to the old copy is overwritten
|
||||
/// with a branch to the new copy. If there was no old copy, this acts
|
||||
/// just like JIT::getPointerToFunction().
|
||||
///
|
||||
void *recompileAndRelinkFunction(Function *F) override;
|
||||
|
||||
/// freeMachineCodeForFunction - deallocate memory used to code-generate this
|
||||
/// Function.
|
||||
///
|
||||
void freeMachineCodeForFunction(Function *F) override;
|
||||
|
||||
/// 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(Module *M,
|
||||
std::string *ErrorStr,
|
||||
JITMemoryManager *JMM,
|
||||
bool GVsWithCode,
|
||||
TargetMachine *TM);
|
||||
|
||||
// Run the JIT on F and return information about the generated code
|
||||
void runJITOnFunction(Function *F, MachineCodeInfo *MCI = nullptr) override;
|
||||
|
||||
void RegisterJITEventListener(JITEventListener *L) override;
|
||||
void UnregisterJITEventListener(JITEventListener *L) override;
|
||||
|
||||
TargetMachine *getTargetMachine() override { return &TM; }
|
||||
|
||||
/// These functions correspond to the methods on JITEventListener. They
|
||||
/// iterate over the registered listeners and call the corresponding method on
|
||||
/// each.
|
||||
void NotifyFunctionEmitted(
|
||||
const Function &F, void *Code, size_t Size,
|
||||
const JITEvent_EmittedFunctionDetails &Details);
|
||||
void NotifyFreeingMachineCode(void *OldPtr);
|
||||
|
||||
BasicBlockAddressMapTy &
|
||||
getBasicBlockAddressMap() {
|
||||
return BasicBlockAddressMap;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static JITCodeEmitter *createEmitter(JIT &J, JITMemoryManager *JMM,
|
||||
TargetMachine &tm);
|
||||
void runJITOnFunctionUnlocked(Function *F);
|
||||
void updateFunctionStubUnlocked(Function *F);
|
||||
void jitTheFunctionUnlocked(Function *F);
|
||||
|
||||
protected:
|
||||
|
||||
/// getMemoryforGV - Allocate memory for a global variable.
|
||||
char* getMemoryForGV(const GlobalVariable* GV) override;
|
||||
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
;===- ./lib/ExecutionEngine/JIT/LLVMBuild.txt ------------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = JIT
|
||||
parent = ExecutionEngine
|
||||
required_libraries = CodeGen Core ExecutionEngine Support
|
@ -1,38 +0,0 @@
|
||||
##===- lib/ExecutionEngine/JIT/Makefile --------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMJIT
|
||||
|
||||
# Get the $(ARCH) setting
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
# Enable the X86 JIT if compiling on X86
|
||||
ifeq ($(ARCH), x86)
|
||||
ENABLE_X86_JIT = 1
|
||||
endif
|
||||
|
||||
# This flag can also be used on the command line to force inclusion
|
||||
# of the X86 JIT on non-X86 hosts
|
||||
ifdef ENABLE_X86_JIT
|
||||
CPPFLAGS += -DENABLE_X86_JIT
|
||||
endif
|
||||
|
||||
# Enable the Sparc JIT if compiling on Sparc
|
||||
ifeq ($(ARCH), Sparc)
|
||||
ENABLE_SPARC_JIT = 1
|
||||
endif
|
||||
|
||||
# This flag can also be used on the command line to force inclusion
|
||||
# of the Sparc JIT on non-Sparc hosts
|
||||
ifdef ENABLE_SPARC_JIT
|
||||
CPPFLAGS += -DENABLE_SPARC_JIT
|
||||
endif
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -16,7 +16,7 @@
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = Interpreter JIT MCJIT RuntimeDyld IntelJITEvents OProfileJIT
|
||||
subdirectories = Interpreter MCJIT RuntimeDyld IntelJITEvents OProfileJIT
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
|
@ -1,4 +1,5 @@
|
||||
add_llvm_library(LLVMMCJIT
|
||||
JITMemoryManager.cpp
|
||||
MCJIT.cpp
|
||||
SectionMemoryManager.cpp
|
||||
)
|
||||
|
@ -247,10 +247,6 @@ void MCJIT::finalizeModule(Module *M) {
|
||||
finalizeLoadedModules();
|
||||
}
|
||||
|
||||
void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
|
||||
report_fatal_error("not yet implemented");
|
||||
}
|
||||
|
||||
uint64_t MCJIT::getExistingSymbolAddress(const std::string &Name) {
|
||||
Mangler Mang(TM->getSubtargetImpl()->getDataLayout());
|
||||
SmallString<128> FullName;
|
||||
@ -372,14 +368,6 @@ void *MCJIT::getPointerToFunction(Function *F) {
|
||||
return (void*)Dyld.getSymbolLoadAddress(Name);
|
||||
}
|
||||
|
||||
void *MCJIT::recompileAndRelinkFunction(Function *F) {
|
||||
report_fatal_error("not yet implemented");
|
||||
}
|
||||
|
||||
void MCJIT::freeMachineCodeForFunction(Function *F) {
|
||||
report_fatal_error("not yet implemented");
|
||||
}
|
||||
|
||||
void MCJIT::runStaticConstructorsDestructorsInModulePtrSet(
|
||||
bool isDtors, ModulePtrSet::iterator I, ModulePtrSet::iterator E) {
|
||||
for (; I != E; ++I) {
|
||||
@ -549,8 +537,7 @@ void MCJIT::UnregisterJITEventListener(JITEventListener *L) {
|
||||
if (!L)
|
||||
return;
|
||||
MutexGuard locked(lock);
|
||||
SmallVector<JITEventListener*, 2>::reverse_iterator I=
|
||||
std::find(EventListeners.rbegin(), EventListeners.rend(), L);
|
||||
auto I = std::find(EventListeners.rbegin(), EventListeners.rend(), L);
|
||||
if (I != EventListeners.rend()) {
|
||||
std::swap(*I, EventListeners.back());
|
||||
EventListeners.pop_back();
|
||||
@ -566,7 +553,8 @@ void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) {
|
||||
void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) {
|
||||
MutexGuard locked(lock);
|
||||
for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
|
||||
EventListeners[I]->NotifyFreeingObject(Obj);
|
||||
JITEventListener *L = EventListeners[I];
|
||||
L->NotifyFreeingObject(Obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ class MCJIT : public ExecutionEngine {
|
||||
MCContext *Ctx;
|
||||
LinkingMemoryManager MemMgr;
|
||||
RuntimeDyld Dyld;
|
||||
SmallVector<JITEventListener*, 2> EventListeners;
|
||||
std::vector<JITEventListener*> EventListeners;
|
||||
|
||||
OwningModuleContainer OwnedModules;
|
||||
|
||||
@ -275,14 +275,8 @@ public:
|
||||
/// \param isDtors - Run the destructors instead of constructors.
|
||||
void runStaticConstructorsDestructors(bool isDtors) override;
|
||||
|
||||
void *getPointerToBasicBlock(BasicBlock *BB) override;
|
||||
|
||||
void *getPointerToFunction(Function *F) override;
|
||||
|
||||
void *recompileAndRelinkFunction(Function *F) override;
|
||||
|
||||
void freeMachineCodeForFunction(Function *F) override;
|
||||
|
||||
GenericValue runFunction(Function *F,
|
||||
const std::vector<GenericValue> &ArgValues) override;
|
||||
|
||||
|
@ -30,7 +30,7 @@ TargetMachine *EngineBuilder::selectTarget() {
|
||||
|
||||
// MCJIT can generate code for remote targets, but the old JIT and Interpreter
|
||||
// must use the host architecture.
|
||||
if (UseMCJIT && WhichEngine != EngineKind::Interpreter && M)
|
||||
if (WhichEngine != EngineKind::Interpreter && M)
|
||||
TT.setTriple(M->getTargetTriple());
|
||||
|
||||
return selectTarget(TT, MArch, MCPU, MAttrs);
|
||||
@ -89,8 +89,7 @@ TargetMachine *EngineBuilder::selectTarget(const Triple &TargetTriple,
|
||||
}
|
||||
|
||||
// FIXME: non-iOS ARM FastISel is broken with MCJIT.
|
||||
if (UseMCJIT &&
|
||||
TheTriple.getArch() == Triple::arm &&
|
||||
if (TheTriple.getArch() == Triple::arm &&
|
||||
!TheTriple.isiOS() &&
|
||||
OptLevel == CodeGenOpt::None) {
|
||||
OptLevel = CodeGenOpt::Less;
|
||||
|
@ -2,7 +2,7 @@ set(LLVM_TARGET_DEFINITIONS AArch64.td)
|
||||
|
||||
tablegen(LLVM AArch64GenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM AArch64GenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM AArch64GenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM AArch64GenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM AArch64GenMCPseudoLowering.inc -gen-pseudo-lowering)
|
||||
tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
|
||||
|
@ -23,7 +23,6 @@ class ARMAsmPrinter;
|
||||
class ARMBaseTargetMachine;
|
||||
class FunctionPass;
|
||||
class ImmutablePass;
|
||||
class JITCodeEmitter;
|
||||
class MachineInstr;
|
||||
class MCInst;
|
||||
class TargetLowering;
|
||||
@ -31,10 +30,6 @@ class TargetMachine;
|
||||
|
||||
FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM,
|
||||
CodeGenOpt::Level OptLevel);
|
||||
|
||||
FunctionPass *createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM,
|
||||
JITCodeEmitter &JCE);
|
||||
|
||||
FunctionPass *createA15SDOptimizerPass();
|
||||
FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false);
|
||||
FunctionPass *createARMExpandPseudoPass();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
|
@ -1,344 +0,0 @@
|
||||
//===-- ARMJITInfo.cpp - Implement the JIT interfaces for the ARM target --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the JIT interfaces for the ARM target.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMJITInfo.h"
|
||||
#include "ARMConstantPoolValue.h"
|
||||
#include "ARMMachineFunctionInfo.h"
|
||||
#include "ARMRelocations.h"
|
||||
#include "MCTargetDesc/ARMBaseInfo.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdlib>
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
|
||||
void ARMJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
|
||||
report_fatal_error("ARMJITInfo::replaceMachineCodeForFunction");
|
||||
}
|
||||
|
||||
/// JITCompilerFunction - This contains the address of the JIT function used to
|
||||
/// compile a function lazily.
|
||||
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
|
||||
|
||||
// Get the ASMPREFIX for the current host. This is often '_'.
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
#define GETASMPREFIX2(X) #X
|
||||
#define GETASMPREFIX(X) GETASMPREFIX2(X)
|
||||
#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)
|
||||
|
||||
// CompilationCallback stub - We can't use a C function with inline assembly in
|
||||
// it, because the prolog/epilog inserted by GCC won't work for us. (We need
|
||||
// to preserve more context and manipulate the stack directly). Instead,
|
||||
// write our own wrapper, which does things our way, so we have complete
|
||||
// control over register saving and restoring.
|
||||
extern "C" {
|
||||
#if defined(__arm__)
|
||||
void ARMCompilationCallback();
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl " ASMPREFIX "ARMCompilationCallback\n"
|
||||
ASMPREFIX "ARMCompilationCallback:\n"
|
||||
// Save caller saved registers since they may contain stuff
|
||||
// for the real target function right now. We have to act as if this
|
||||
// whole compilation callback doesn't exist as far as the caller is
|
||||
// concerned, so we can't just preserve the callee saved regs.
|
||||
"stmdb sp!, {r0, r1, r2, r3, lr}\n"
|
||||
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
|
||||
"vstmdb sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
|
||||
#endif
|
||||
// The LR contains the address of the stub function on entry.
|
||||
// pass it as the argument to the C part of the callback
|
||||
"mov r0, lr\n"
|
||||
"sub sp, sp, #4\n"
|
||||
// Call the C portion of the callback
|
||||
"bl " ASMPREFIX "ARMCompilationCallbackC\n"
|
||||
"add sp, sp, #4\n"
|
||||
// Restoring the LR to the return address of the function that invoked
|
||||
// the stub and de-allocating the stack space for it requires us to
|
||||
// swap the two saved LR values on the stack, as they're backwards
|
||||
// for what we need since the pop instruction has a pre-determined
|
||||
// order for the registers.
|
||||
// +--------+
|
||||
// 0 | LR | Original return address
|
||||
// +--------+
|
||||
// 1 | LR | Stub address (start of stub)
|
||||
// 2-5 | R3..R0 | Saved registers (we need to preserve all regs)
|
||||
// 6-20 | D0..D7 | Saved VFP registers
|
||||
// +--------+
|
||||
//
|
||||
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
|
||||
// Restore VFP caller-saved registers.
|
||||
"vldmia sp!, {d0, d1, d2, d3, d4, d5, d6, d7}\n"
|
||||
#endif
|
||||
//
|
||||
// We need to exchange the values in slots 0 and 1 so we can
|
||||
// return to the address in slot 1 with the address in slot 0
|
||||
// restored to the LR.
|
||||
"ldr r0, [sp,#20]\n"
|
||||
"ldr r1, [sp,#16]\n"
|
||||
"str r1, [sp,#20]\n"
|
||||
"str r0, [sp,#16]\n"
|
||||
// Return to the (newly modified) stub to invoke the real function.
|
||||
// The above twiddling of the saved return addresses allows us to
|
||||
// deallocate everything, including the LR the stub saved, with two
|
||||
// updating load instructions.
|
||||
"ldmia sp!, {r0, r1, r2, r3, lr}\n"
|
||||
"ldr pc, [sp], #4\n"
|
||||
);
|
||||
#else // Not an ARM host
|
||||
void ARMCompilationCallback() {
|
||||
llvm_unreachable("Cannot call ARMCompilationCallback() on a non-ARM arch!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// ARMCompilationCallbackC - This is the target-specific function invoked
|
||||
/// by the function stub when we did not know the real target of a call.
|
||||
/// This function must locate the start of the stub or call site and pass
|
||||
/// it into the JIT compiler function.
|
||||
extern "C" void ARMCompilationCallbackC(intptr_t StubAddr) {
|
||||
// Get the address of the compiled code for this function.
|
||||
intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)StubAddr);
|
||||
|
||||
// Rewrite the call target... so that we don't end up here every time we
|
||||
// execute the call. We're replacing the first two instructions of the
|
||||
// stub with:
|
||||
// ldr pc, [pc,#-4]
|
||||
// <addr>
|
||||
if (!sys::Memory::setRangeWritable((void*)StubAddr, 8)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable");
|
||||
}
|
||||
*(intptr_t *)StubAddr = 0xe51ff004; // ldr pc, [pc, #-4]
|
||||
*(intptr_t *)(StubAddr+4) = NewVal;
|
||||
if (!sys::Memory::setRangeExecutable((void*)StubAddr, 8)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable");
|
||||
}
|
||||
}
|
||||
|
||||
TargetJITInfo::LazyResolverFn
|
||||
ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) {
|
||||
JITCompilerFunction = F;
|
||||
return ARMCompilationCallback;
|
||||
}
|
||||
|
||||
void *ARMJITInfo::emitGlobalValueIndirectSym(const GlobalValue *GV, void *Ptr,
|
||||
JITCodeEmitter &JCE) {
|
||||
uint8_t Buffer[4];
|
||||
uint8_t *Cur = Buffer;
|
||||
MachineCodeEmitter::emitWordLEInto(Cur, (intptr_t)Ptr);
|
||||
void *PtrAddr = JCE.allocIndirectGV(
|
||||
GV, Buffer, sizeof(Buffer), /*Alignment=*/4);
|
||||
addIndirectSymAddr(Ptr, (intptr_t)PtrAddr);
|
||||
return PtrAddr;
|
||||
}
|
||||
|
||||
TargetJITInfo::StubLayout ARMJITInfo::getStubLayout() {
|
||||
// The stub contains up to 3 4-byte instructions, aligned at 4 bytes, and a
|
||||
// 4-byte address. See emitFunctionStub for details.
|
||||
StubLayout Result = {16, 4};
|
||||
return Result;
|
||||
}
|
||||
|
||||
void *ARMJITInfo::emitFunctionStub(const Function* F, void *Fn,
|
||||
JITCodeEmitter &JCE) {
|
||||
void *Addr;
|
||||
// If this is just a call to an external function, emit a branch instead of a
|
||||
// call. The code is the same except for one bit of the last instruction.
|
||||
if (Fn != (void*)(intptr_t)ARMCompilationCallback) {
|
||||
// Branch to the corresponding function addr.
|
||||
if (IsPIC) {
|
||||
// The stub is 16-byte size and 4-aligned.
|
||||
intptr_t LazyPtr = getIndirectSymAddr(Fn);
|
||||
if (!LazyPtr) {
|
||||
// In PIC mode, the function stub is loading a lazy-ptr.
|
||||
LazyPtr= (intptr_t)emitGlobalValueIndirectSym((const GlobalValue*)F, Fn, JCE);
|
||||
DEBUG(if (F)
|
||||
errs() << "JIT: Indirect symbol emitted at [" << LazyPtr
|
||||
<< "] for GV '" << F->getName() << "'\n";
|
||||
else
|
||||
errs() << "JIT: Stub emitted at [" << LazyPtr
|
||||
<< "] for external function at '" << Fn << "'\n");
|
||||
}
|
||||
JCE.emitAlignment(4);
|
||||
Addr = (void*)JCE.getCurrentPCValue();
|
||||
if (!sys::Memory::setRangeWritable(Addr, 16)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable");
|
||||
}
|
||||
JCE.emitWordLE(0xe59fc004); // ldr ip, [pc, #+4]
|
||||
JCE.emitWordLE(0xe08fc00c); // L_func$scv: add ip, pc, ip
|
||||
JCE.emitWordLE(0xe59cf000); // ldr pc, [ip]
|
||||
JCE.emitWordLE(LazyPtr - (intptr_t(Addr)+4+8)); // func - (L_func$scv+8)
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 16);
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 16)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable");
|
||||
}
|
||||
} else {
|
||||
// The stub is 8-byte size and 4-aligned.
|
||||
JCE.emitAlignment(4);
|
||||
Addr = (void*)JCE.getCurrentPCValue();
|
||||
if (!sys::Memory::setRangeWritable(Addr, 8)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable");
|
||||
}
|
||||
JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4]
|
||||
JCE.emitWordLE((intptr_t)Fn); // addr of function
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 8);
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 8)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The compilation callback will overwrite the first two words of this
|
||||
// stub with indirect branch instructions targeting the compiled code.
|
||||
// This stub sets the return address to restart the stub, so that
|
||||
// the new branch will be invoked when we come back.
|
||||
//
|
||||
// Branch and link to the compilation callback.
|
||||
// The stub is 16-byte size and 4-byte aligned.
|
||||
JCE.emitAlignment(4);
|
||||
Addr = (void*)JCE.getCurrentPCValue();
|
||||
if (!sys::Memory::setRangeWritable(Addr, 16)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable");
|
||||
}
|
||||
// Save LR so the callback can determine which stub called it.
|
||||
// The compilation callback is responsible for popping this prior
|
||||
// to returning.
|
||||
JCE.emitWordLE(0xe92d4000); // push {lr}
|
||||
// Set the return address to go back to the start of this stub.
|
||||
JCE.emitWordLE(0xe24fe00c); // sub lr, pc, #12
|
||||
// Invoke the compilation callback.
|
||||
JCE.emitWordLE(0xe51ff004); // ldr pc, [pc, #-4]
|
||||
// The address of the compilation callback.
|
||||
JCE.emitWordLE((intptr_t)ARMCompilationCallback);
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 16);
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 16)) {
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable");
|
||||
}
|
||||
}
|
||||
|
||||
return Addr;
|
||||
}
|
||||
|
||||
intptr_t ARMJITInfo::resolveRelocDestAddr(MachineRelocation *MR) const {
|
||||
ARM::RelocationType RT = (ARM::RelocationType)MR->getRelocationType();
|
||||
switch (RT) {
|
||||
default:
|
||||
return (intptr_t)(MR->getResultPointer());
|
||||
case ARM::reloc_arm_pic_jt:
|
||||
// Destination address - jump table base.
|
||||
return (intptr_t)(MR->getResultPointer()) - MR->getConstantVal();
|
||||
case ARM::reloc_arm_jt_base:
|
||||
// Jump table base address.
|
||||
return getJumpTableBaseAddr(MR->getJumpTableIndex());
|
||||
case ARM::reloc_arm_cp_entry:
|
||||
case ARM::reloc_arm_vfp_cp_entry:
|
||||
// Constant pool entry address.
|
||||
return getConstantPoolEntryAddr(MR->getConstantPoolIndex());
|
||||
case ARM::reloc_arm_machine_cp_entry: {
|
||||
ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)MR->getConstantVal();
|
||||
assert((!ACPV->hasModifier() && !ACPV->mustAddCurrentAddress()) &&
|
||||
"Can't handle this machine constant pool entry yet!");
|
||||
intptr_t Addr = (intptr_t)(MR->getResultPointer());
|
||||
Addr -= getPCLabelAddr(ACPV->getLabelId()) + ACPV->getPCAdjustment();
|
||||
return Addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// relocate - Before the JIT can run a block of code that has been emitted,
|
||||
/// it must rewrite the code to contain the actual addresses of any
|
||||
/// referenced global symbols.
|
||||
void ARMJITInfo::relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase) {
|
||||
for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
|
||||
void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
|
||||
intptr_t ResultPtr = resolveRelocDestAddr(MR);
|
||||
switch ((ARM::RelocationType)MR->getRelocationType()) {
|
||||
case ARM::reloc_arm_cp_entry:
|
||||
case ARM::reloc_arm_vfp_cp_entry:
|
||||
case ARM::reloc_arm_relative: {
|
||||
// It is necessary to calculate the correct PC relative value. We
|
||||
// subtract the base addr from the target addr to form a byte offset.
|
||||
ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
|
||||
// If the result is positive, set bit U(23) to 1.
|
||||
if (ResultPtr >= 0)
|
||||
*((intptr_t*)RelocPos) |= 1 << ARMII::U_BitShift;
|
||||
else {
|
||||
// Otherwise, obtain the absolute value and set bit U(23) to 0.
|
||||
*((intptr_t*)RelocPos) &= ~(1 << ARMII::U_BitShift);
|
||||
ResultPtr = - ResultPtr;
|
||||
}
|
||||
// Set the immed value calculated.
|
||||
// VFP immediate offset is multiplied by 4.
|
||||
if (MR->getRelocationType() == ARM::reloc_arm_vfp_cp_entry)
|
||||
ResultPtr = ResultPtr >> 2;
|
||||
*((intptr_t*)RelocPos) |= ResultPtr;
|
||||
// Set register Rn to PC (which is register 15 on all architectures).
|
||||
// FIXME: This avoids the need for register info in the JIT class.
|
||||
*((intptr_t*)RelocPos) |= 15 << ARMII::RegRnShift;
|
||||
break;
|
||||
}
|
||||
case ARM::reloc_arm_pic_jt:
|
||||
case ARM::reloc_arm_machine_cp_entry:
|
||||
case ARM::reloc_arm_absolute: {
|
||||
// These addresses have already been resolved.
|
||||
*((intptr_t*)RelocPos) |= (intptr_t)ResultPtr;
|
||||
break;
|
||||
}
|
||||
case ARM::reloc_arm_branch: {
|
||||
// It is necessary to calculate the correct value of signed_immed_24
|
||||
// field. We subtract the base addr from the target addr to form a
|
||||
// byte offset, which must be inside the range -33554432 and +33554428.
|
||||
// Then, we set the signed_immed_24 field of the instruction to bits
|
||||
// [25:2] of the byte offset. More details ARM-ARM p. A4-11.
|
||||
ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
|
||||
ResultPtr = (ResultPtr & 0x03FFFFFC) >> 2;
|
||||
assert(ResultPtr >= -33554432 && ResultPtr <= 33554428);
|
||||
*((intptr_t*)RelocPos) |= ResultPtr;
|
||||
break;
|
||||
}
|
||||
case ARM::reloc_arm_jt_base: {
|
||||
// JT base - (instruction addr + 8)
|
||||
ResultPtr = ResultPtr - (intptr_t)RelocPos - 8;
|
||||
*((intptr_t*)RelocPos) |= ResultPtr;
|
||||
break;
|
||||
}
|
||||
case ARM::reloc_arm_movw: {
|
||||
ResultPtr = ResultPtr & 0xFFFF;
|
||||
*((intptr_t*)RelocPos) |= ResultPtr & 0xFFF;
|
||||
*((intptr_t*)RelocPos) |= ((ResultPtr >> 12) & 0xF) << 16;
|
||||
break;
|
||||
}
|
||||
case ARM::reloc_arm_movt: {
|
||||
ResultPtr = (ResultPtr >> 16) & 0xFFFF;
|
||||
*((intptr_t*)RelocPos) |= ResultPtr & 0xFFF;
|
||||
*((intptr_t*)RelocPos) |= ((ResultPtr >> 12) & 0xF) << 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ARMJITInfo::Initialize(const MachineFunction &MF, bool isPIC) {
|
||||
const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
|
||||
ConstPoolId2AddrMap.resize(AFI->getNumPICLabels());
|
||||
JumpTableId2AddrMap.resize(AFI->getNumJumpTables());
|
||||
IsPIC = isPIC;
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
//===-- ARMJITInfo.h - ARM implementation of the JIT interface -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the ARMJITInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMJITINFO_H
|
||||
#define ARMJITINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class ARMTargetMachine;
|
||||
|
||||
class ARMJITInfo : public TargetJITInfo {
|
||||
// ConstPoolId2AddrMap - A map from constant pool ids to the corresponding
|
||||
// CONSTPOOL_ENTRY addresses.
|
||||
SmallVector<intptr_t, 16> ConstPoolId2AddrMap;
|
||||
|
||||
// JumpTableId2AddrMap - A map from inline jumptable ids to the
|
||||
// corresponding inline jump table bases.
|
||||
SmallVector<intptr_t, 16> JumpTableId2AddrMap;
|
||||
|
||||
// PCLabelMap - A map from PC labels to addresses.
|
||||
DenseMap<unsigned, intptr_t> PCLabelMap;
|
||||
|
||||
// Sym2IndirectSymMap - A map from symbol (GlobalValue and ExternalSymbol)
|
||||
// addresses to their indirect symbol addresses.
|
||||
DenseMap<void*, intptr_t> Sym2IndirectSymMap;
|
||||
|
||||
// IsPIC - True if the relocation model is PIC. This is used to determine
|
||||
// how to codegen function stubs.
|
||||
bool IsPIC;
|
||||
|
||||
public:
|
||||
explicit ARMJITInfo() : IsPIC(false) { useGOT = false; }
|
||||
|
||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
||||
/// code.
|
||||
///
|
||||
void replaceMachineCodeForFunction(void *Old, void *New) override;
|
||||
|
||||
/// emitGlobalValueIndirectSym - Use the specified JITCodeEmitter object
|
||||
/// to emit an indirect symbol which contains the address of the specified
|
||||
/// ptr.
|
||||
void *emitGlobalValueIndirectSym(const GlobalValue* GV, void *ptr,
|
||||
JITCodeEmitter &JCE) override;
|
||||
|
||||
// getStubLayout - Returns the size and alignment of the largest call stub
|
||||
// on ARM.
|
||||
StubLayout getStubLayout() override;
|
||||
|
||||
/// emitFunctionStub - Use the specified JITCodeEmitter object to emit a
|
||||
/// small native function that simply calls the function at the specified
|
||||
/// address.
|
||||
void *emitFunctionStub(const Function* F, void *Fn,
|
||||
JITCodeEmitter &JCE) override;
|
||||
|
||||
/// getLazyResolverFunction - Expose the lazy resolver to the JIT.
|
||||
LazyResolverFn getLazyResolverFunction(JITCompilerFn) override;
|
||||
|
||||
/// relocate - Before the JIT can run a block of code that has been emitted,
|
||||
/// it must rewrite the code to contain the actual addresses of any
|
||||
/// referenced global symbols.
|
||||
void relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase) override;
|
||||
|
||||
/// hasCustomConstantPool - Allows a target to specify that constant
|
||||
/// pool address resolution is handled by the target.
|
||||
bool hasCustomConstantPool() const override { return true; }
|
||||
|
||||
/// hasCustomJumpTables - Allows a target to specify that jumptables
|
||||
/// are emitted by the target.
|
||||
bool hasCustomJumpTables() const override { return true; }
|
||||
|
||||
/// allocateSeparateGVMemory - If true, globals should be placed in
|
||||
/// separately allocated heap memory rather than in the same
|
||||
/// code memory allocated by JITCodeEmitter.
|
||||
bool allocateSeparateGVMemory() const override {
|
||||
#ifdef __APPLE__
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Initialize - Initialize internal stage for the function being JITted.
|
||||
/// Resize constant pool ids to CONSTPOOL_ENTRY addresses map; resize
|
||||
/// jump table ids to jump table bases map; remember if codegen relocation
|
||||
/// model is PIC.
|
||||
void Initialize(const MachineFunction &MF, bool isPIC);
|
||||
|
||||
/// getConstantPoolEntryAddr - The ARM target puts all constant
|
||||
/// pool entries into constant islands. This returns the address of the
|
||||
/// constant pool entry of the specified index.
|
||||
intptr_t getConstantPoolEntryAddr(unsigned CPI) const {
|
||||
assert(CPI < ConstPoolId2AddrMap.size());
|
||||
return ConstPoolId2AddrMap[CPI];
|
||||
}
|
||||
|
||||
/// addConstantPoolEntryAddr - Map a Constant Pool Index to the address
|
||||
/// where its associated value is stored. When relocations are processed,
|
||||
/// this value will be used to resolve references to the constant.
|
||||
void addConstantPoolEntryAddr(unsigned CPI, intptr_t Addr) {
|
||||
assert(CPI < ConstPoolId2AddrMap.size());
|
||||
ConstPoolId2AddrMap[CPI] = Addr;
|
||||
}
|
||||
|
||||
/// getJumpTableBaseAddr - The ARM target inline all jump tables within
|
||||
/// text section of the function. This returns the address of the base of
|
||||
/// the jump table of the specified index.
|
||||
intptr_t getJumpTableBaseAddr(unsigned JTI) const {
|
||||
assert(JTI < JumpTableId2AddrMap.size());
|
||||
return JumpTableId2AddrMap[JTI];
|
||||
}
|
||||
|
||||
/// addJumpTableBaseAddr - Map a jump table index to the address where
|
||||
/// the corresponding inline jump table is emitted. When relocations are
|
||||
/// processed, this value will be used to resolve references to the
|
||||
/// jump table.
|
||||
void addJumpTableBaseAddr(unsigned JTI, intptr_t Addr) {
|
||||
assert(JTI < JumpTableId2AddrMap.size());
|
||||
JumpTableId2AddrMap[JTI] = Addr;
|
||||
}
|
||||
|
||||
/// getPCLabelAddr - Retrieve the address of the PC label of the
|
||||
/// specified id.
|
||||
intptr_t getPCLabelAddr(unsigned Id) const {
|
||||
DenseMap<unsigned, intptr_t>::const_iterator I = PCLabelMap.find(Id);
|
||||
assert(I != PCLabelMap.end());
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// addPCLabelAddr - Remember the address of the specified PC label.
|
||||
void addPCLabelAddr(unsigned Id, intptr_t Addr) {
|
||||
PCLabelMap.insert(std::make_pair(Id, Addr));
|
||||
}
|
||||
|
||||
/// getIndirectSymAddr - Retrieve the address of the indirect symbol of the
|
||||
/// specified symbol located at address. Returns 0 if the indirect symbol
|
||||
/// has not been emitted.
|
||||
intptr_t getIndirectSymAddr(void *Addr) const {
|
||||
DenseMap<void*,intptr_t>::const_iterator I= Sym2IndirectSymMap.find(Addr);
|
||||
if (I != Sym2IndirectSymMap.end())
|
||||
return I->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// addIndirectSymAddr - Add a mapping from address of an emitted symbol to
|
||||
/// its indirect symbol address.
|
||||
void addIndirectSymAddr(void *SymAddr, intptr_t IndSymAddr) {
|
||||
Sym2IndirectSymMap.insert(std::make_pair(SymAddr, IndSymAddr));
|
||||
}
|
||||
|
||||
private:
|
||||
/// resolveRelocDestAddr - Resolve the resulting address of the relocation
|
||||
/// if it's not already solved. Constantpool entries must be resolved by
|
||||
/// ARM target.
|
||||
intptr_t resolveRelocDestAddr(MachineRelocation *MR) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -15,7 +15,6 @@
|
||||
#include "ARMFrameLowering.h"
|
||||
#include "ARMISelLowering.h"
|
||||
#include "ARMInstrInfo.h"
|
||||
#include "ARMJITInfo.h"
|
||||
#include "ARMSelectionDAGInfo.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "ARMMachineFunctionInfo.h"
|
||||
@ -158,7 +157,7 @@ ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &CPU,
|
||||
ARMProcClass(None), stackAlignment(4), CPUString(CPU), IsLittle(IsLittle),
|
||||
TargetTriple(TT), Options(Options), TargetABI(ARM_ABI_UNKNOWN),
|
||||
DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS))),
|
||||
TSInfo(DL), JITInfo(),
|
||||
TSInfo(DL),
|
||||
InstrInfo(isThumb1Only()
|
||||
? (ARMBaseInstrInfo *)new Thumb1InstrInfo(*this)
|
||||
: !isThumb()
|
||||
|
@ -18,13 +18,11 @@
|
||||
#include "ARMFrameLowering.h"
|
||||
#include "ARMISelLowering.h"
|
||||
#include "ARMInstrInfo.h"
|
||||
#include "ARMJITInfo.h"
|
||||
#include "ARMSelectionDAGInfo.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "Thumb1FrameLowering.h"
|
||||
#include "Thumb1InstrInfo.h"
|
||||
#include "Thumb2InstrInfo.h"
|
||||
#include "ARMJITInfo.h"
|
||||
#include "MCTargetDesc/ARMMCTargetDesc.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
@ -261,7 +259,6 @@ protected:
|
||||
const ARMSelectionDAGInfo *getSelectionDAGInfo() const override {
|
||||
return &TSInfo;
|
||||
}
|
||||
ARMJITInfo *getJITInfo() override { return &JITInfo; }
|
||||
const ARMBaseInstrInfo *getInstrInfo() const override {
|
||||
return InstrInfo.get();
|
||||
}
|
||||
@ -278,7 +275,6 @@ protected:
|
||||
private:
|
||||
const DataLayout DL;
|
||||
ARMSelectionDAGInfo TSInfo;
|
||||
ARMJITInfo JITInfo;
|
||||
// Either Thumb1InstrInfo or Thumb2InstrInfo.
|
||||
std::unique_ptr<ARMBaseInstrInfo> InstrInfo;
|
||||
ARMTargetLowering TLInfo;
|
||||
|
@ -244,10 +244,3 @@ bool ARMPassConfig::addPreEmitPass() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ARMBaseTargetMachine::addCodeEmitter(PassManagerBase &PM,
|
||||
JITCodeEmitter &JCE) {
|
||||
// Machine code emitter pass for ARM.
|
||||
PM.add(createARMJITCodeEmitterPass(*this, JCE));
|
||||
return false;
|
||||
}
|
||||
|
@ -39,8 +39,6 @@ public:
|
||||
|
||||
// Pass Pipeline Configuration
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
|
||||
bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &MCE) override;
|
||||
};
|
||||
|
||||
/// ARMTargetMachine - ARM target machine.
|
||||
|
@ -2,8 +2,7 @@ set(LLVM_TARGET_DEFINITIONS ARM.td)
|
||||
|
||||
tablegen(LLVM ARMGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM ARMGenCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM ARMGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM ARMGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM ARMGenMCPseudoLowering.inc -gen-pseudo-lowering)
|
||||
tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher)
|
||||
@ -19,7 +18,6 @@ add_llvm_target(ARMCodeGen
|
||||
ARMAsmPrinter.cpp
|
||||
ARMBaseInstrInfo.cpp
|
||||
ARMBaseRegisterInfo.cpp
|
||||
ARMCodeEmitter.cpp
|
||||
ARMConstantIslandPass.cpp
|
||||
ARMConstantPoolValue.cpp
|
||||
ARMExpandPseudoInsts.cpp
|
||||
@ -29,7 +27,6 @@ add_llvm_target(ARMCodeGen
|
||||
ARMISelDAGToDAG.cpp
|
||||
ARMISelLowering.cpp
|
||||
ARMInstrInfo.cpp
|
||||
ARMJITInfo.cpp
|
||||
ARMLoadStoreOptimizer.cpp
|
||||
ARMMCInstLower.cpp
|
||||
ARMMachineFunctionInfo.cpp
|
||||
|
@ -15,7 +15,7 @@ TARGET = ARM
|
||||
BUILT_SOURCES = ARMGenRegisterInfo.inc ARMGenInstrInfo.inc \
|
||||
ARMGenAsmWriter.inc ARMGenAsmMatcher.inc \
|
||||
ARMGenDAGISel.inc ARMGenSubtargetInfo.inc \
|
||||
ARMGenCodeEmitter.inc ARMGenCallingConv.inc \
|
||||
ARMGenCallingConv.inc \
|
||||
ARMGenFastISel.inc ARMGenMCCodeEmitter.inc \
|
||||
ARMGenMCPseudoLowering.inc ARMGenDisassemblerTables.inc
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
add_llvm_library(LLVMTarget
|
||||
Target.cpp
|
||||
TargetIntrinsicInfo.cpp
|
||||
TargetJITInfo.cpp
|
||||
TargetLibraryInfo.cpp
|
||||
TargetLoweringObjectFile.cpp
|
||||
TargetMachine.cpp
|
||||
|
@ -3,8 +3,7 @@ set(LLVM_TARGET_DEFINITIONS Mips.td)
|
||||
tablegen(LLVM MipsGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM MipsGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler)
|
||||
tablegen(LLVM MipsGenCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel)
|
||||
tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel)
|
||||
@ -24,11 +23,9 @@ add_llvm_target(MipsCodeGen
|
||||
Mips16RegisterInfo.cpp
|
||||
MipsAnalyzeImmediate.cpp
|
||||
MipsAsmPrinter.cpp
|
||||
MipsCodeEmitter.cpp
|
||||
MipsConstantIslandPass.cpp
|
||||
MipsDelaySlotFiller.cpp
|
||||
MipsFastISel.cpp
|
||||
MipsJITInfo.cpp
|
||||
MipsInstrInfo.cpp
|
||||
MipsISelDAGToDAG.cpp
|
||||
MipsISelLowering.cpp
|
||||
|
@ -13,7 +13,7 @@ TARGET = Mips
|
||||
|
||||
# Make sure that tblgen is run, first thing.
|
||||
BUILT_SOURCES = MipsGenRegisterInfo.inc MipsGenInstrInfo.inc \
|
||||
MipsGenAsmWriter.inc MipsGenFastISel.inc MipsGenCodeEmitter.inc \
|
||||
MipsGenAsmWriter.inc MipsGenFastISel.inc \
|
||||
MipsGenDAGISel.inc MipsGenCallingConv.inc \
|
||||
MipsGenSubtargetInfo.inc MipsGenMCCodeEmitter.inc \
|
||||
MipsGenDisassemblerTables.inc \
|
||||
|
@ -26,8 +26,6 @@ namespace llvm {
|
||||
FunctionPass *createMipsOptimizePICCallPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsJITCodeEmitterPass(MipsTargetMachine &TM,
|
||||
JITCodeEmitter &JCE);
|
||||
FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm);
|
||||
} // end namespace llvm;
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "Mips16ISelLowering.h"
|
||||
#include "MCTargetDesc/MipsBaseInfo.h"
|
||||
#include "Mips16HardFloatInfo.h"
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "MipsRegisterInfo.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
@ -1,483 +0,0 @@
|
||||
//===-- Mips/MipsCodeEmitter.cpp - Convert Mips Code to Machine Code ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the pass that transforms the Mips machine instructions
|
||||
// into relocatable machine code.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include "Mips.h"
|
||||
#include "MCTargetDesc/MipsBaseInfo.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsRelocations.h"
|
||||
#include "MipsSubtarget.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#ifndef NDEBUG
|
||||
#include <iomanip>
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
|
||||
STATISTIC(NumEmitted, "Number of machine instructions emitted");
|
||||
|
||||
namespace {
|
||||
|
||||
class MipsCodeEmitter : public MachineFunctionPass {
|
||||
MipsJITInfo *JTI;
|
||||
const MipsInstrInfo *II;
|
||||
const DataLayout *TD;
|
||||
const MipsSubtarget *Subtarget;
|
||||
TargetMachine &TM;
|
||||
JITCodeEmitter &MCE;
|
||||
const std::vector<MachineConstantPoolEntry> *MCPEs;
|
||||
const std::vector<MachineJumpTableEntry> *MJTEs;
|
||||
bool IsPIC;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<MachineModuleInfo> ();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
static char ID;
|
||||
|
||||
public:
|
||||
MipsCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce)
|
||||
: MachineFunctionPass(ID), JTI(nullptr), II(nullptr), TD(nullptr),
|
||||
TM(tm), MCE(mce), MCPEs(nullptr), MJTEs(nullptr),
|
||||
IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "Mips Machine Code Emitter";
|
||||
}
|
||||
|
||||
/// getBinaryCodeForInstr - This function, generated by the
|
||||
/// CodeEmitterGenerator using TableGen, produces the binary encoding for
|
||||
/// machine instructions.
|
||||
uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const;
|
||||
|
||||
void emitInstruction(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB);
|
||||
|
||||
private:
|
||||
|
||||
void emitWord(unsigned Word);
|
||||
|
||||
/// Routines that handle operands which add machine relocations which are
|
||||
/// fixed up by the relocation stage.
|
||||
void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
|
||||
bool MayNeedFarStub) const;
|
||||
void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const;
|
||||
void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const;
|
||||
void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const;
|
||||
void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const;
|
||||
|
||||
/// getMachineOpValue - Return binary encoding of operand. If the machine
|
||||
/// operand requires relocation, record the relocation and return zero.
|
||||
unsigned getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
unsigned getRelocation(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
unsigned getJumpTargetOpValue(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getJumpTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getBranchTargetOpValueMM(const MachineInstr &MI,
|
||||
unsigned OpNo) const;
|
||||
|
||||
unsigned getBranchTarget21OpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const;
|
||||
unsigned getBranchTarget26OpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const;
|
||||
unsigned getJumpOffset16OpValue(const MachineInstr &MI, unsigned OpNo) const;
|
||||
|
||||
unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getMemEncodingMMImm12(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getMSAMemEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getSizeExtEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getLSAImmEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getSimm19Lsl2Encoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getSimm18Lsl3Encoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
|
||||
/// Expand pseudo instructions with accumulator register operands.
|
||||
void expandACCInstr(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB, unsigned Opc) const;
|
||||
|
||||
void expandPseudoIndirectBranch(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB) const;
|
||||
|
||||
/// \brief Expand pseudo instruction. Return true if MI was expanded.
|
||||
bool expandPseudos(MachineBasicBlock::instr_iterator &MI,
|
||||
MachineBasicBlock &MBB) const;
|
||||
};
|
||||
}
|
||||
|
||||
char MipsCodeEmitter::ID = 0;
|
||||
|
||||
bool MipsCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
|
||||
MipsTargetMachine &Target = static_cast<MipsTargetMachine &>(
|
||||
const_cast<TargetMachine &>(MF.getTarget()));
|
||||
// Initialize the subtarget so that we can grab the subtarget dependent
|
||||
// variables from it.
|
||||
Subtarget = &TM.getSubtarget<MipsSubtarget>();
|
||||
JTI = Target.getSubtargetImpl()->getJITInfo();
|
||||
II = Subtarget->getInstrInfo();
|
||||
TD = Subtarget->getDataLayout();
|
||||
MCPEs = &MF.getConstantPool()->getConstants();
|
||||
MJTEs = nullptr;
|
||||
if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables();
|
||||
JTI->Initialize(MF, IsPIC, Subtarget->isLittle());
|
||||
MCE.setModuleInfo(&getAnalysis<MachineModuleInfo> ());
|
||||
|
||||
do {
|
||||
DEBUG(errs() << "JITTing function '"
|
||||
<< MF.getName() << "'\n");
|
||||
MCE.startFunction(MF);
|
||||
|
||||
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
|
||||
MBB != E; ++MBB){
|
||||
MCE.StartMachineBasicBlock(MBB);
|
||||
for (MachineBasicBlock::instr_iterator I = MBB->instr_begin(),
|
||||
E = MBB->instr_end(); I != E;)
|
||||
emitInstruction(*I++, *MBB);
|
||||
}
|
||||
} while (MCE.finishFunction(MF));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getRelocation(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
// NOTE: This relocations are for static.
|
||||
uint64_t TSFlags = MI.getDesc().TSFlags;
|
||||
uint64_t Form = TSFlags & MipsII::FormMask;
|
||||
if (Form == MipsII::FrmJ)
|
||||
return Mips::reloc_mips_26;
|
||||
if ((Form == MipsII::FrmI || Form == MipsII::FrmFI)
|
||||
&& MI.isBranch())
|
||||
return Mips::reloc_mips_pc16;
|
||||
if (Form == MipsII::FrmI && MI.getOpcode() == Mips::LUi)
|
||||
return Mips::reloc_mips_hi;
|
||||
return Mips::reloc_mips_lo;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getJumpTargetOpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
MachineOperand MO = MI.getOperand(OpNo);
|
||||
if (MO.isGlobal())
|
||||
emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true);
|
||||
else if (MO.isSymbol())
|
||||
emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO));
|
||||
else if (MO.isMBB())
|
||||
emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO));
|
||||
else
|
||||
llvm_unreachable("Unexpected jump target operand kind.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getJumpTargetOpValueMM(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getBranchTargetOpValueMM(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getBranchTarget21OpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getBranchTarget26OpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getJumpOffset16OpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
MachineOperand MO = MI.getOperand(OpNo);
|
||||
emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getMemEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
// Base register is encoded in bits 20-16, offset is encoded in bits 15-0.
|
||||
assert(MI.getOperand(OpNo).isReg());
|
||||
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo)) << 16;
|
||||
return (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getMemEncodingMMImm12(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getMSAMemEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getSizeExtEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
// size is encoded as size-1.
|
||||
return getMachineOpValue(MI, MI.getOperand(OpNo)) - 1;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getSizeInsEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
// size is encoded as pos+size-1.
|
||||
return getMachineOpValue(MI, MI.getOperand(OpNo-1)) +
|
||||
getMachineOpValue(MI, MI.getOperand(OpNo)) - 1;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getLSAImmEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getSimm18Lsl3Encoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MipsCodeEmitter::getSimm19Lsl2Encoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Unimplemented function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getMachineOpValue - Return binary encoding of operand. If the machine
|
||||
/// operand requires relocation, record the relocation and return zero.
|
||||
unsigned MipsCodeEmitter::getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
if (MO.isReg())
|
||||
return TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(
|
||||
MO.getReg());
|
||||
else if (MO.isImm())
|
||||
return static_cast<unsigned>(MO.getImm());
|
||||
else if (MO.isGlobal())
|
||||
emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true);
|
||||
else if (MO.isSymbol())
|
||||
emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO));
|
||||
else if (MO.isCPI())
|
||||
emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO));
|
||||
else if (MO.isJTI())
|
||||
emitJumpTableAddress(MO.getIndex(), getRelocation(MI, MO));
|
||||
else if (MO.isMBB())
|
||||
emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO));
|
||||
else
|
||||
llvm_unreachable("Unable to encode MachineOperand!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc,
|
||||
bool MayNeedFarStub) const {
|
||||
MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc,
|
||||
const_cast<GlobalValue *>(GV), 0,
|
||||
MayNeedFarStub));
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::
|
||||
emitExternalSymbolAddress(const char *ES, unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
|
||||
Reloc, ES, 0, 0));
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(),
|
||||
Reloc, CPI, 0, false));
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::
|
||||
emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(),
|
||||
Reloc, JTIndex, 0, false));
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB,
|
||||
unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(),
|
||||
Reloc, BB));
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::emitInstruction(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB) {
|
||||
DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << *MI);
|
||||
|
||||
// Expand pseudo instruction. Skip if MI was not expanded.
|
||||
if (((MI->getDesc().TSFlags & MipsII::FormMask) == MipsII::Pseudo) &&
|
||||
!expandPseudos(MI, MBB))
|
||||
return;
|
||||
|
||||
MCE.processDebugLoc(MI->getDebugLoc(), true);
|
||||
|
||||
emitWord(getBinaryCodeForInstr(*MI));
|
||||
++NumEmitted; // Keep track of the # of mi's emitted
|
||||
|
||||
MCE.processDebugLoc(MI->getDebugLoc(), false);
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::emitWord(unsigned Word) {
|
||||
DEBUG(errs() << " 0x";
|
||||
errs().write_hex(Word) << "\n");
|
||||
if (Subtarget->isLittle())
|
||||
MCE.emitWordLE(Word);
|
||||
else
|
||||
MCE.emitWordBE(Word);
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::expandACCInstr(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB,
|
||||
unsigned Opc) const {
|
||||
// Expand "pseudomult $ac0, $t0, $t1" to "mult $t0, $t1".
|
||||
BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Opc))
|
||||
.addReg(MI->getOperand(1).getReg()).addReg(MI->getOperand(2).getReg());
|
||||
}
|
||||
|
||||
void MipsCodeEmitter::expandPseudoIndirectBranch(
|
||||
MachineBasicBlock::instr_iterator MI, MachineBasicBlock &MBB) const {
|
||||
// This logic is duplicated from MipsAsmPrinter::emitPseudoIndirectBranch()
|
||||
bool HasLinkReg = false;
|
||||
unsigned Opcode = 0;
|
||||
|
||||
if (Subtarget->hasMips64r6()) {
|
||||
// MIPS64r6 should use (JALR64 ZERO_64, $rs)
|
||||
Opcode = Mips::JALR64;
|
||||
HasLinkReg = true;
|
||||
} else if (Subtarget->hasMips32r6()) {
|
||||
// MIPS32r6 should use (JALR ZERO, $rs)
|
||||
Opcode = Mips::JALR;
|
||||
HasLinkReg = true;
|
||||
} else if (Subtarget->inMicroMipsMode())
|
||||
// microMIPS should use (JR_MM $rs)
|
||||
Opcode = Mips::JR_MM;
|
||||
else {
|
||||
// Everything else should use (JR $rs)
|
||||
Opcode = Mips::JR;
|
||||
}
|
||||
|
||||
auto MIB = BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Opcode));
|
||||
|
||||
if (HasLinkReg) {
|
||||
unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
|
||||
MIB.addReg(ZeroReg);
|
||||
}
|
||||
|
||||
MIB.addReg(MI->getOperand(0).getReg());
|
||||
}
|
||||
|
||||
bool MipsCodeEmitter::expandPseudos(MachineBasicBlock::instr_iterator &MI,
|
||||
MachineBasicBlock &MBB) const {
|
||||
switch (MI->getOpcode()) {
|
||||
default:
|
||||
llvm_unreachable("Unhandled pseudo");
|
||||
return false;
|
||||
case Mips::NOP:
|
||||
BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::SLL), Mips::ZERO)
|
||||
.addReg(Mips::ZERO).addImm(0);
|
||||
break;
|
||||
case Mips::B:
|
||||
BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::BEQ)).addReg(Mips::ZERO)
|
||||
.addReg(Mips::ZERO).addOperand(MI->getOperand(0));
|
||||
break;
|
||||
case Mips::TRAP:
|
||||
BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::BREAK)).addImm(0)
|
||||
.addImm(0);
|
||||
break;
|
||||
case Mips::JALRPseudo:
|
||||
BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::JALR), Mips::RA)
|
||||
.addReg(MI->getOperand(0).getReg());
|
||||
break;
|
||||
case Mips::PseudoMULT:
|
||||
expandACCInstr(MI, MBB, Mips::MULT);
|
||||
break;
|
||||
case Mips::PseudoMULTu:
|
||||
expandACCInstr(MI, MBB, Mips::MULTu);
|
||||
break;
|
||||
case Mips::PseudoSDIV:
|
||||
expandACCInstr(MI, MBB, Mips::SDIV);
|
||||
break;
|
||||
case Mips::PseudoUDIV:
|
||||
expandACCInstr(MI, MBB, Mips::UDIV);
|
||||
break;
|
||||
case Mips::PseudoMADD:
|
||||
expandACCInstr(MI, MBB, Mips::MADD);
|
||||
break;
|
||||
case Mips::PseudoMADDU:
|
||||
expandACCInstr(MI, MBB, Mips::MADDU);
|
||||
break;
|
||||
case Mips::PseudoMSUB:
|
||||
expandACCInstr(MI, MBB, Mips::MSUB);
|
||||
break;
|
||||
case Mips::PseudoMSUBU:
|
||||
expandACCInstr(MI, MBB, Mips::MSUBU);
|
||||
break;
|
||||
case Mips::PseudoReturn:
|
||||
case Mips::PseudoReturn64:
|
||||
case Mips::PseudoIndirectBranch:
|
||||
case Mips::PseudoIndirectBranch64:
|
||||
expandPseudoIndirectBranch(MI, MBB);
|
||||
break;
|
||||
case TargetOpcode::CFI_INSTRUCTION:
|
||||
case TargetOpcode::IMPLICIT_DEF:
|
||||
case TargetOpcode::KILL:
|
||||
// Do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
(MI--)->eraseFromBundle();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// createMipsJITCodeEmitterPass - Return a pass that emits the collected Mips
|
||||
/// code to the specified MCE object.
|
||||
FunctionPass *llvm::createMipsJITCodeEmitterPass(MipsTargetMachine &TM,
|
||||
JITCodeEmitter &JCE) {
|
||||
return new MipsCodeEmitter(TM, JCE);
|
||||
}
|
||||
|
||||
#include "MipsGenCodeEmitter.inc"
|
@ -28,6 +28,7 @@
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
|
@ -1,286 +0,0 @@
|
||||
//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the JIT interfaces for the Mips target.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsJITInfo.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsRelocations.h"
|
||||
#include "MipsSubtarget.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdlib>
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
|
||||
|
||||
void MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
|
||||
unsigned NewAddr = (intptr_t)New;
|
||||
unsigned OldAddr = (intptr_t)Old;
|
||||
const unsigned NopInstr = 0x0;
|
||||
|
||||
// If the functions are in the same memory segment, insert PC-region branch.
|
||||
if ((NewAddr & 0xF0000000) == ((OldAddr + 4) & 0xF0000000)) {
|
||||
unsigned *OldInstruction = (unsigned *)Old;
|
||||
*OldInstruction = 0x08000000;
|
||||
unsigned JTargetAddr = NewAddr & 0x0FFFFFFC;
|
||||
|
||||
JTargetAddr >>= 2;
|
||||
*OldInstruction |= JTargetAddr;
|
||||
|
||||
// Insert a NOP.
|
||||
OldInstruction++;
|
||||
*OldInstruction = NopInstr;
|
||||
|
||||
sys::Memory::InvalidateInstructionCache(Old, 2 * 4);
|
||||
} else {
|
||||
// We need to clear hint bits from the instruction, in case it is 'jr ra'.
|
||||
const unsigned HintMask = 0xFFFFF83F, ReturnSequence = 0x03e00008;
|
||||
unsigned* CurrentInstr = (unsigned*)Old;
|
||||
unsigned CurrInstrHintClear = (*CurrentInstr) & HintMask;
|
||||
unsigned* NextInstr = CurrentInstr + 1;
|
||||
unsigned NextInstrHintClear = (*NextInstr) & HintMask;
|
||||
|
||||
// Do absolute jump if there are 2 or more instructions before return from
|
||||
// the old function.
|
||||
if ((CurrInstrHintClear != ReturnSequence) &&
|
||||
(NextInstrHintClear != ReturnSequence)) {
|
||||
const unsigned LuiT0Instr = 0x3c080000, AddiuT0Instr = 0x25080000;
|
||||
const unsigned JrT0Instr = 0x01000008;
|
||||
// lui t0, high 16 bit of the NewAddr
|
||||
(*(CurrentInstr++)) = LuiT0Instr | ((NewAddr & 0xffff0000) >> 16);
|
||||
// addiu t0, t0, low 16 bit of the NewAddr
|
||||
(*(CurrentInstr++)) = AddiuT0Instr | (NewAddr & 0x0000ffff);
|
||||
// jr t0
|
||||
(*(CurrentInstr++)) = JrT0Instr;
|
||||
(*CurrentInstr) = NopInstr;
|
||||
|
||||
sys::Memory::InvalidateInstructionCache(Old, 4 * 4);
|
||||
} else {
|
||||
// Unsupported case
|
||||
report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// JITCompilerFunction - This contains the address of the JIT function used to
|
||||
/// compile a function lazily.
|
||||
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
|
||||
|
||||
// Get the ASMPREFIX for the current host. This is often '_'.
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
#define GETASMPREFIX2(X) #X
|
||||
#define GETASMPREFIX(X) GETASMPREFIX2(X)
|
||||
#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)
|
||||
|
||||
// CompilationCallback stub - We can't use a C function with inline assembly in
|
||||
// it, because the prolog/epilog inserted by GCC won't work for us. Instead,
|
||||
// write our own wrapper, which does things our way, so we have complete control
|
||||
// over register saving and restoring. This code saves registers, calls
|
||||
// MipsCompilationCallbackC and restores registers.
|
||||
extern "C" {
|
||||
#if defined (__mips__)
|
||||
void MipsCompilationCallback();
|
||||
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl " ASMPREFIX "MipsCompilationCallback\n"
|
||||
ASMPREFIX "MipsCompilationCallback:\n"
|
||||
".ent " ASMPREFIX "MipsCompilationCallback\n"
|
||||
".frame $sp, 32, $ra\n"
|
||||
".set noreorder\n"
|
||||
".cpload $t9\n"
|
||||
|
||||
"addiu $sp, $sp, -64\n"
|
||||
".cprestore 16\n"
|
||||
|
||||
// Save argument registers a0, a1, a2, a3, f12, f14 since they may contain
|
||||
// stuff for the real target function right now. We have to act as if this
|
||||
// whole compilation callback doesn't exist as far as the caller is
|
||||
// concerned. We also need to save the ra register since it contains the
|
||||
// original return address, and t8 register since it contains the address
|
||||
// of the end of function stub.
|
||||
"sw $a0, 20($sp)\n"
|
||||
"sw $a1, 24($sp)\n"
|
||||
"sw $a2, 28($sp)\n"
|
||||
"sw $a3, 32($sp)\n"
|
||||
"sw $ra, 36($sp)\n"
|
||||
"sw $t8, 40($sp)\n"
|
||||
"sdc1 $f12, 48($sp)\n"
|
||||
"sdc1 $f14, 56($sp)\n"
|
||||
|
||||
// t8 points at the end of function stub. Pass the beginning of the stub
|
||||
// to the MipsCompilationCallbackC.
|
||||
"addiu $a0, $t8, -16\n"
|
||||
"jal " ASMPREFIX "MipsCompilationCallbackC\n"
|
||||
"nop\n"
|
||||
|
||||
// Restore registers.
|
||||
"lw $a0, 20($sp)\n"
|
||||
"lw $a1, 24($sp)\n"
|
||||
"lw $a2, 28($sp)\n"
|
||||
"lw $a3, 32($sp)\n"
|
||||
"lw $ra, 36($sp)\n"
|
||||
"lw $t8, 40($sp)\n"
|
||||
"ldc1 $f12, 48($sp)\n"
|
||||
"ldc1 $f14, 56($sp)\n"
|
||||
"addiu $sp, $sp, 64\n"
|
||||
|
||||
// Jump to the (newly modified) stub to invoke the real function.
|
||||
"addiu $t8, $t8, -16\n"
|
||||
"jr $t8\n"
|
||||
"nop\n"
|
||||
|
||||
".set reorder\n"
|
||||
".end " ASMPREFIX "MipsCompilationCallback\n"
|
||||
);
|
||||
#else // host != Mips
|
||||
void MipsCompilationCallback() {
|
||||
llvm_unreachable(
|
||||
"Cannot call MipsCompilationCallback() on a non-Mips arch!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// MipsCompilationCallbackC - This is the target-specific function invoked
|
||||
/// by the function stub when we did not know the real target of a call.
|
||||
/// This function must locate the start of the stub or call site and pass
|
||||
/// it into the JIT compiler function.
|
||||
extern "C" void MipsCompilationCallbackC(intptr_t StubAddr) {
|
||||
// Get the address of the compiled code for this function.
|
||||
intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
|
||||
|
||||
// Rewrite the function stub so that we don't end up here every time we
|
||||
// execute the call. We're replacing the first four instructions of the
|
||||
// stub with code that jumps to the compiled function:
|
||||
// lui $t9, %hi(NewVal)
|
||||
// addiu $t9, $t9, %lo(NewVal)
|
||||
// jr $t9
|
||||
// nop
|
||||
|
||||
int Hi = ((unsigned)NewVal & 0xffff0000) >> 16;
|
||||
if ((NewVal & 0x8000) != 0)
|
||||
Hi++;
|
||||
int Lo = (int)(NewVal & 0xffff);
|
||||
|
||||
*(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi;
|
||||
*(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo;
|
||||
*(intptr_t *)(StubAddr + 8) = 25 << 21 | 8;
|
||||
*(intptr_t *)(StubAddr + 12) = 0;
|
||||
|
||||
sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16);
|
||||
}
|
||||
|
||||
TargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction(
|
||||
JITCompilerFn F) {
|
||||
JITCompilerFunction = F;
|
||||
return MipsCompilationCallback;
|
||||
}
|
||||
|
||||
TargetJITInfo::StubLayout MipsJITInfo::getStubLayout() {
|
||||
// The stub contains 4 4-byte instructions, aligned at 4 bytes. See
|
||||
// emitFunctionStub for details.
|
||||
StubLayout Result = { 4*4, 4 };
|
||||
return Result;
|
||||
}
|
||||
|
||||
void *MipsJITInfo::emitFunctionStub(const Function *F, void *Fn,
|
||||
JITCodeEmitter &JCE) {
|
||||
JCE.emitAlignment(4);
|
||||
void *Addr = (void*) (JCE.getCurrentPCValue());
|
||||
if (!sys::Memory::setRangeWritable(Addr, 16))
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable.");
|
||||
|
||||
intptr_t EmittedAddr;
|
||||
if (Fn != (void*)(intptr_t)MipsCompilationCallback)
|
||||
EmittedAddr = (intptr_t)Fn;
|
||||
else
|
||||
EmittedAddr = (intptr_t)MipsCompilationCallback;
|
||||
|
||||
|
||||
int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16;
|
||||
if ((EmittedAddr & 0x8000) != 0)
|
||||
Hi++;
|
||||
int Lo = (int)(EmittedAddr & 0xffff);
|
||||
|
||||
// lui $t9, %hi(EmittedAddr)
|
||||
// addiu $t9, $t9, %lo(EmittedAddr)
|
||||
// jalr $t8, $t9
|
||||
// nop
|
||||
if (IsLittleEndian) {
|
||||
JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi);
|
||||
JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
|
||||
JCE.emitWordLE(25 << 21 | 24 << 11 | 9);
|
||||
JCE.emitWordLE(0);
|
||||
} else {
|
||||
JCE.emitWordBE(0xf << 26 | 25 << 16 | Hi);
|
||||
JCE.emitWordBE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
|
||||
JCE.emitWordBE(25 << 21 | 24 << 11 | 9);
|
||||
JCE.emitWordBE(0);
|
||||
}
|
||||
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 16);
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 16))
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable.");
|
||||
|
||||
return Addr;
|
||||
}
|
||||
|
||||
/// relocate - Before the JIT can run a block of code that has been emitted,
|
||||
/// it must rewrite the code to contain the actual addresses of any
|
||||
/// referenced global symbols.
|
||||
void MipsJITInfo::relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char *GOTBase) {
|
||||
for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
|
||||
|
||||
void *RelocPos = (char*) Function + MR->getMachineCodeOffset();
|
||||
intptr_t ResultPtr = (intptr_t) MR->getResultPointer();
|
||||
|
||||
switch ((Mips::RelocationType) MR->getRelocationType()) {
|
||||
case Mips::reloc_mips_pc16:
|
||||
ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff;
|
||||
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
|
||||
break;
|
||||
|
||||
case Mips::reloc_mips_26:
|
||||
ResultPtr = (ResultPtr & 0x0fffffff) >> 2;
|
||||
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
|
||||
break;
|
||||
|
||||
case Mips::reloc_mips_hi:
|
||||
ResultPtr = ResultPtr >> 16;
|
||||
if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) {
|
||||
ResultPtr += 1;
|
||||
}
|
||||
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
|
||||
break;
|
||||
|
||||
case Mips::reloc_mips_lo: {
|
||||
// Addend is needed for unaligned load/store instructions, where offset
|
||||
// for the second load/store in the expanded instruction sequence must
|
||||
// be modified by +1 or +3. Otherwise, Addend is 0.
|
||||
int Addend = *((unsigned*) RelocPos) & 0xffff;
|
||||
ResultPtr = (ResultPtr + Addend) & 0xffff;
|
||||
*((unsigned*) RelocPos) &= 0xffff0000;
|
||||
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
//===- MipsJITInfo.h - Mips Implementation of the JIT Interface -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the MipsJITInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MIPSJITINFO_H
|
||||
#define MIPSJITINFO_H
|
||||
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class MipsTargetMachine;
|
||||
|
||||
class MipsJITInfo : public TargetJITInfo {
|
||||
|
||||
bool IsPIC;
|
||||
bool IsLittleEndian;
|
||||
|
||||
public:
|
||||
explicit MipsJITInfo() :
|
||||
IsPIC(false), IsLittleEndian(true) {}
|
||||
|
||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
||||
/// code.
|
||||
///
|
||||
void replaceMachineCodeForFunction(void *Old, void *New) override;
|
||||
|
||||
// getStubLayout - Returns the size and alignment of the largest call stub
|
||||
// on Mips.
|
||||
StubLayout getStubLayout() override;
|
||||
|
||||
/// emitFunctionStub - Use the specified JITCodeEmitter object to emit a
|
||||
/// small native function that simply calls the function at the specified
|
||||
/// address.
|
||||
void *emitFunctionStub(const Function *F, void *Fn,
|
||||
JITCodeEmitter &JCE) override;
|
||||
|
||||
/// getLazyResolverFunction - Expose the lazy resolver to the JIT.
|
||||
LazyResolverFn getLazyResolverFunction(JITCompilerFn) override;
|
||||
|
||||
/// relocate - Before the JIT can run a block of code that has been emitted,
|
||||
/// it must rewrite the code to contain the actual addresses of any
|
||||
/// referenced global symbols.
|
||||
void relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char *GOTBase) override;
|
||||
|
||||
/// Initialize - Initialize internal stage for the function being JITted.
|
||||
void Initialize(const MachineFunction &MF, bool isPIC,
|
||||
bool isLittleEndian) {
|
||||
IsPIC = isPIC;
|
||||
IsLittleEndian = isLittleEndian;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#include "Mips.h"
|
||||
#include "MCTargetDesc/MipsBaseInfo.h"
|
||||
#include "MCTargetDesc/MipsMCNaCl.h"
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
@ -11,6 +11,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "MipsSEISelLowering.h"
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "MipsRegisterInfo.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
|
@ -115,7 +115,7 @@ MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU,
|
||||
HasDSPR2(false), AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16),
|
||||
HasMSA(false), TM(_TM), TargetTriple(TT),
|
||||
DL(computeDataLayout(initializeSubtargetDependencies(CPU, FS, TM))),
|
||||
TSInfo(DL), JITInfo(), InstrInfo(MipsInstrInfo::create(*this)),
|
||||
TSInfo(DL), InstrInfo(MipsInstrInfo::create(*this)),
|
||||
FrameLowering(MipsFrameLowering::create(*this)),
|
||||
TLInfo(MipsTargetLowering::create(*TM, *this)) {
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "MipsFrameLowering.h"
|
||||
#include "MipsISelLowering.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsJITInfo.h"
|
||||
#include "MipsSelectionDAGInfo.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/MC/MCInstrItineraries.h"
|
||||
@ -145,7 +144,6 @@ protected:
|
||||
|
||||
const DataLayout DL; // Calculates type size & alignment
|
||||
const MipsSelectionDAGInfo TSInfo;
|
||||
MipsJITInfo JITInfo;
|
||||
std::unique_ptr<const MipsInstrInfo> InstrInfo;
|
||||
std::unique_ptr<const MipsFrameLowering> FrameLowering;
|
||||
std::unique_ptr<const MipsTargetLowering> TLInfo;
|
||||
@ -272,7 +270,6 @@ public:
|
||||
void setHelperClassesMips16();
|
||||
void setHelperClassesMipsSE();
|
||||
|
||||
MipsJITInfo *getJITInfo() override { return &JITInfo; }
|
||||
const MipsSelectionDAGInfo *getSelectionDAGInfo() const override {
|
||||
return &TSInfo;
|
||||
}
|
||||
|
@ -189,10 +189,3 @@ bool MipsPassConfig::addPreEmitPass() {
|
||||
addPass(createMipsConstantIslandPass(TM));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MipsTargetMachine::addCodeEmitter(PassManagerBase &PM,
|
||||
JITCodeEmitter &JCE) {
|
||||
// Machine code emitter pass for Mips.
|
||||
PM.add(createMipsJITCodeEmitterPass(*this, JCE));
|
||||
return false;
|
||||
}
|
||||
|
@ -44,16 +44,12 @@ public:
|
||||
return Subtarget;
|
||||
return &DefaultSubtarget;
|
||||
}
|
||||
MipsSubtarget *getSubtargetImpl() {
|
||||
return static_cast<MipsSubtarget *>(TargetMachine::getSubtargetImpl());
|
||||
}
|
||||
|
||||
/// \brief Reset the subtarget for the Mips target.
|
||||
void resetSubtarget(MachineFunction *MF);
|
||||
|
||||
// Pass Pipeline Configuration
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE) override;
|
||||
};
|
||||
|
||||
/// MipsebTargetMachine - Mips32/64 big endian target machine.
|
||||
|
@ -43,12 +43,6 @@ public:
|
||||
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
|
||||
// Emission of machine code through JITCodeEmitter is not supported.
|
||||
bool addPassesToEmitMachineCode(PassManagerBase &, JITCodeEmitter &,
|
||||
bool = true) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Emission of machine code through MCJIT is not supported.
|
||||
bool addPassesToEmitMC(PassManagerBase &, MCContext *&, raw_ostream &,
|
||||
bool = true) override {
|
||||
|
@ -2,9 +2,8 @@ set(LLVM_TARGET_DEFINITIONS PPC.td)
|
||||
|
||||
tablegen(LLVM PPCGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM PPCGenAsmMatcher.inc -gen-asm-matcher)
|
||||
tablegen(LLVM PPCGenCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler)
|
||||
tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM PPCGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM PPCGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM PPCGenDAGISel.inc -gen-dag-isel)
|
||||
@ -16,7 +15,6 @@ add_public_tablegen_target(PowerPCCommonTableGen)
|
||||
add_llvm_target(PowerPCCodeGen
|
||||
PPCAsmPrinter.cpp
|
||||
PPCBranchSelector.cpp
|
||||
PPCCodeEmitter.cpp
|
||||
PPCCTRLoops.cpp
|
||||
PPCHazardRecognizers.cpp
|
||||
PPCInstrInfo.cpp
|
||||
@ -24,7 +22,6 @@ add_llvm_target(PowerPCCodeGen
|
||||
PPCISelLowering.cpp
|
||||
PPCFastISel.cpp
|
||||
PPCFrameLowering.cpp
|
||||
PPCJITInfo.cpp
|
||||
PPCMCInstLower.cpp
|
||||
PPCMachineFunctionInfo.cpp
|
||||
PPCRegisterInfo.cpp
|
||||
|
@ -13,7 +13,7 @@ TARGET = PPC
|
||||
|
||||
# Make sure that tblgen is run, first thing.
|
||||
BUILT_SOURCES = PPCGenRegisterInfo.inc PPCGenAsmMatcher.inc \
|
||||
PPCGenAsmWriter.inc PPCGenCodeEmitter.inc \
|
||||
PPCGenAsmWriter.inc \
|
||||
PPCGenInstrInfo.inc PPCGenDAGISel.inc \
|
||||
PPCGenSubtargetInfo.inc PPCGenCallingConv.inc \
|
||||
PPCGenMCCodeEmitter.inc PPCGenFastISel.inc \
|
||||
|
@ -26,7 +26,6 @@ namespace llvm {
|
||||
class PassRegistry;
|
||||
class FunctionPass;
|
||||
class ImmutablePass;
|
||||
class JITCodeEmitter;
|
||||
class MachineInstr;
|
||||
class AsmPrinter;
|
||||
class MCInst;
|
||||
@ -41,8 +40,6 @@ namespace llvm {
|
||||
FunctionPass *createPPCVSXFMAMutatePass();
|
||||
FunctionPass *createPPCBranchSelectionPass();
|
||||
FunctionPass *createPPCISelDag(PPCTargetMachine &TM);
|
||||
FunctionPass *createPPCJITCodeEmitterPass(PPCTargetMachine &TM,
|
||||
JITCodeEmitter &MCE);
|
||||
void LowerPPCMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
||||
AsmPrinter &AP, bool isDarwin);
|
||||
|
||||
|
@ -386,8 +386,7 @@ bool PPCCTRLoops::mightUseCTR(const Triple &TT, BasicBlock *BB) {
|
||||
return true;
|
||||
const TargetLowering *TLI = TM->getSubtargetImpl()->getTargetLowering();
|
||||
|
||||
if (TLI->supportJumpTables() &&
|
||||
SI->getNumCases()+1 >= (unsigned) TLI->getMinimumJumpTableEntries())
|
||||
if (SI->getNumCases() + 1 >= (unsigned)TLI->getMinimumJumpTableEntries())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,295 +0,0 @@
|
||||
//===-- PPCCodeEmitter.cpp - JIT Code Emitter for PowerPC -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PowerPC 32-bit CodeEmitter and associated machinery to
|
||||
// JIT-compile bitcode to native PowerPC.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PPC.h"
|
||||
#include "PPCRelocations.h"
|
||||
#include "PPCTargetMachine.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class PPCCodeEmitter : public MachineFunctionPass {
|
||||
TargetMachine &TM;
|
||||
JITCodeEmitter &MCE;
|
||||
MachineModuleInfo *MMI;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<MachineModuleInfo>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
static char ID;
|
||||
|
||||
/// MovePCtoLROffset - When/if we see a MovePCtoLR instruction, we record
|
||||
/// its address in the function into this pointer.
|
||||
void *MovePCtoLROffset;
|
||||
public:
|
||||
|
||||
PPCCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce)
|
||||
: MachineFunctionPass(ID), TM(tm), MCE(mce) {}
|
||||
|
||||
/// getBinaryCodeForInstr - This function, generated by the
|
||||
/// CodeEmitterGenerator using TableGen, produces the binary encoding for
|
||||
/// machine instructions.
|
||||
uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const;
|
||||
|
||||
|
||||
MachineRelocation GetRelocation(const MachineOperand &MO,
|
||||
unsigned RelocID) const;
|
||||
|
||||
/// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr
|
||||
unsigned getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
unsigned get_crbitm_encoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getDirectBrEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getCondBrEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getAbsDirectBrEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const;
|
||||
unsigned getAbsCondBrEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
|
||||
unsigned getImm16Encoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getMemRIEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getMemRIXEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getTLSRegEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
unsigned getTLSCallEncoding(const MachineInstr &MI, unsigned OpNo) const;
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "PowerPC Machine Code Emitter";
|
||||
}
|
||||
|
||||
/// runOnMachineFunction - emits the given MachineFunction to memory
|
||||
///
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
/// emitBasicBlock - emits the given MachineBasicBlock to memory
|
||||
///
|
||||
void emitBasicBlock(MachineBasicBlock &MBB);
|
||||
};
|
||||
}
|
||||
|
||||
char PPCCodeEmitter::ID = 0;
|
||||
|
||||
/// createPPCCodeEmitterPass - Return a pass that emits the collected PPC code
|
||||
/// to the specified MCE object.
|
||||
FunctionPass *llvm::createPPCJITCodeEmitterPass(PPCTargetMachine &TM,
|
||||
JITCodeEmitter &JCE) {
|
||||
return new PPCCodeEmitter(TM, JCE);
|
||||
}
|
||||
|
||||
bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
|
||||
assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
|
||||
MF.getTarget().getRelocationModel() != Reloc::Static) &&
|
||||
"JIT relocation model must be set to static or default!");
|
||||
|
||||
MMI = &getAnalysis<MachineModuleInfo>();
|
||||
MCE.setModuleInfo(MMI);
|
||||
do {
|
||||
MovePCtoLROffset = nullptr;
|
||||
MCE.startFunction(MF);
|
||||
for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB)
|
||||
emitBasicBlock(*BB);
|
||||
} while (MCE.finishFunction(MF));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) {
|
||||
MCE.StartMachineBasicBlock(&MBB);
|
||||
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){
|
||||
const MachineInstr &MI = *I;
|
||||
MCE.processDebugLoc(MI.getDebugLoc(), true);
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
MCE.emitWordBE(getBinaryCodeForInstr(MI));
|
||||
break;
|
||||
case TargetOpcode::CFI_INSTRUCTION:
|
||||
break;
|
||||
case TargetOpcode::EH_LABEL:
|
||||
MCE.emitLabel(MI.getOperand(0).getMCSymbol());
|
||||
break;
|
||||
case TargetOpcode::IMPLICIT_DEF:
|
||||
case TargetOpcode::KILL:
|
||||
break; // pseudo opcode, no side effects
|
||||
case PPC::MovePCtoLR:
|
||||
case PPC::MovePCtoLR8:
|
||||
assert(TM.getRelocationModel() == Reloc::PIC_);
|
||||
MovePCtoLROffset = (void*)MCE.getCurrentPCValue();
|
||||
MCE.emitWordBE(0x48000005); // bl 1
|
||||
break;
|
||||
}
|
||||
MCE.processDebugLoc(MI.getDebugLoc(), false);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::get_crbitm_encoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
assert((MI.getOpcode() == PPC::MTOCRF || MI.getOpcode() == PPC::MTOCRF8 ||
|
||||
MI.getOpcode() == PPC::MFOCRF || MI.getOpcode() == PPC::MFOCRF8) &&
|
||||
(MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7));
|
||||
return 0x80 >> TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(
|
||||
MO.getReg());
|
||||
}
|
||||
|
||||
MachineRelocation PPCCodeEmitter::GetRelocation(const MachineOperand &MO,
|
||||
unsigned RelocID) const {
|
||||
// If in PIC mode, we need to encode the negated address of the
|
||||
// 'movepctolr' into the unrelocated field. After relocation, we'll have
|
||||
// &gv-&movepctolr-4 in the imm field. Once &movepctolr is added to the imm
|
||||
// field, we get &gv. This doesn't happen for branch relocations, which are
|
||||
// always implicitly pc relative.
|
||||
intptr_t Cst = 0;
|
||||
if (TM.getRelocationModel() == Reloc::PIC_) {
|
||||
assert(MovePCtoLROffset && "MovePCtoLR not seen yet?");
|
||||
Cst = -(intptr_t)MovePCtoLROffset - 4;
|
||||
}
|
||||
|
||||
if (MO.isGlobal())
|
||||
return MachineRelocation::getGV(MCE.getCurrentPCOffset(), RelocID,
|
||||
const_cast<GlobalValue *>(MO.getGlobal()),
|
||||
Cst, isa<Function>(MO.getGlobal()));
|
||||
if (MO.isSymbol())
|
||||
return MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
|
||||
RelocID, MO.getSymbolName(), Cst);
|
||||
if (MO.isCPI())
|
||||
return MachineRelocation::getConstPool(MCE.getCurrentPCOffset(),
|
||||
RelocID, MO.getIndex(), Cst);
|
||||
|
||||
if (MO.isMBB())
|
||||
return MachineRelocation::getBB(MCE.getCurrentPCOffset(),
|
||||
RelocID, MO.getMBB());
|
||||
|
||||
assert(MO.isJTI());
|
||||
return MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(),
|
||||
RelocID, MO.getIndex(), Cst);
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getDirectBrEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO);
|
||||
|
||||
MCE.addRelocation(GetRelocation(MO, PPC::reloc_pcrel_bx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getCondBrEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
MCE.addRelocation(GetRelocation(MO, PPC::reloc_pcrel_bcx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getAbsDirectBrEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO);
|
||||
|
||||
llvm_unreachable("Absolute branch relocations unsupported on the old JIT.");
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getAbsCondBrEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("Absolute branch relocations unsupported on the old JIT.");
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getImm16Encoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO);
|
||||
|
||||
unsigned RelocID;
|
||||
switch (MO.getTargetFlags() & PPCII::MO_ACCESS_MASK) {
|
||||
default: llvm_unreachable("Unsupported target operand flags!");
|
||||
case PPCII::MO_LO: RelocID = PPC::reloc_absolute_low; break;
|
||||
case PPCII::MO_HA: RelocID = PPC::reloc_absolute_high; break;
|
||||
}
|
||||
|
||||
MCE.addRelocation(GetRelocation(MO, RelocID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getMemRIEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
// Encode (imm, reg) as a memri, which has the low 16-bits as the
|
||||
// displacement and the next 5 bits as the register #.
|
||||
assert(MI.getOperand(OpNo+1).isReg());
|
||||
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1)) << 16;
|
||||
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isImm())
|
||||
return (getMachineOpValue(MI, MO) & 0xFFFF) | RegBits;
|
||||
|
||||
// Add a fixup for the displacement field.
|
||||
MCE.addRelocation(GetRelocation(MO, PPC::reloc_absolute_low));
|
||||
return RegBits;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getMemRIXEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
// Encode (imm, reg) as a memrix, which has the low 14-bits as the
|
||||
// displacement and the next 5 bits as the register #.
|
||||
assert(MI.getOperand(OpNo+1).isReg());
|
||||
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1)) << 14;
|
||||
|
||||
const MachineOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isImm())
|
||||
return ((getMachineOpValue(MI, MO) >> 2) & 0x3FFF) | RegBits;
|
||||
|
||||
MCE.addRelocation(GetRelocation(MO, PPC::reloc_absolute_low_ix));
|
||||
return RegBits;
|
||||
}
|
||||
|
||||
|
||||
unsigned PPCCodeEmitter::getTLSRegEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("TLS not supported on the old JIT.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getTLSCallEncoding(const MachineInstr &MI,
|
||||
unsigned OpNo) const {
|
||||
llvm_unreachable("TLS not supported on the old JIT.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned PPCCodeEmitter::getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
|
||||
if (MO.isReg()) {
|
||||
// MTOCRF/MFOCRF should go through get_crbitm_encoding for the CR operand.
|
||||
// The GPR operand should come through here though.
|
||||
assert((MI.getOpcode() != PPC::MTOCRF && MI.getOpcode() != PPC::MTOCRF8 &&
|
||||
MI.getOpcode() != PPC::MFOCRF && MI.getOpcode() != PPC::MFOCRF8) ||
|
||||
MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7);
|
||||
return TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(
|
||||
MO.getReg());
|
||||
}
|
||||
|
||||
assert(MO.isImm() &&
|
||||
"Relocation required in an instruction that we cannot encode!");
|
||||
return MO.getImm();
|
||||
}
|
||||
|
||||
#include "PPCGenCodeEmitter.inc"
|
@ -684,11 +684,6 @@ PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM)
|
||||
if (Subtarget.isDarwin())
|
||||
setPrefFunctionAlignment(4);
|
||||
|
||||
if (isPPC64 && Subtarget.isJITCodeModel())
|
||||
// Temporary workaround for the inability of PPC64 JIT to handle jump
|
||||
// tables.
|
||||
setSupportJumpTables(false);
|
||||
|
||||
setInsertFencesForAtomic(true);
|
||||
|
||||
if (Subtarget.enableMachineScheduler())
|
||||
@ -3564,33 +3559,27 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag,
|
||||
}
|
||||
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
||||
// XXX Work around for http://llvm.org/bugs/show_bug.cgi?id=5201
|
||||
// Use indirect calls for ALL functions calls in JIT mode, since the
|
||||
// far-call stubs may be outside relocation limits for a BL instruction.
|
||||
if (!DAG.getTarget().getSubtarget<PPCSubtarget>().isJITCodeModel()) {
|
||||
unsigned OpFlags = 0;
|
||||
if ((DAG.getTarget().getRelocationModel() != Reloc::Static &&
|
||||
(Subtarget.getTargetTriple().isMacOSX() &&
|
||||
Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5)) &&
|
||||
(G->getGlobal()->isDeclaration() ||
|
||||
G->getGlobal()->isWeakForLinker())) ||
|
||||
(Subtarget.isTargetELF() && !isPPC64 &&
|
||||
!G->getGlobal()->hasLocalLinkage() &&
|
||||
DAG.getTarget().getRelocationModel() == Reloc::PIC_)) {
|
||||
// PC-relative references to external symbols should go through $stub,
|
||||
// unless we're building with the leopard linker or later, which
|
||||
// automatically synthesizes these stubs.
|
||||
OpFlags = PPCII::MO_PLT_OR_STUB;
|
||||
}
|
||||
|
||||
// If the callee is a GlobalAddress/ExternalSymbol node (quite common,
|
||||
// every direct call is) turn it into a TargetGlobalAddress /
|
||||
// TargetExternalSymbol node so that legalize doesn't hack it.
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl,
|
||||
Callee.getValueType(),
|
||||
0, OpFlags);
|
||||
needIndirectCall = false;
|
||||
unsigned OpFlags = 0;
|
||||
if ((DAG.getTarget().getRelocationModel() != Reloc::Static &&
|
||||
(Subtarget.getTargetTriple().isMacOSX() &&
|
||||
Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5)) &&
|
||||
(G->getGlobal()->isDeclaration() ||
|
||||
G->getGlobal()->isWeakForLinker())) ||
|
||||
(Subtarget.isTargetELF() && !isPPC64 &&
|
||||
!G->getGlobal()->hasLocalLinkage() &&
|
||||
DAG.getTarget().getRelocationModel() == Reloc::PIC_)) {
|
||||
// PC-relative references to external symbols should go through $stub,
|
||||
// unless we're building with the leopard linker or later, which
|
||||
// automatically synthesizes these stubs.
|
||||
OpFlags = PPCII::MO_PLT_OR_STUB;
|
||||
}
|
||||
|
||||
// If the callee is a GlobalAddress/ExternalSymbol node (quite common,
|
||||
// every direct call is) turn it into a TargetGlobalAddress /
|
||||
// TargetExternalSymbol node so that legalize doesn't hack it.
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl,
|
||||
Callee.getValueType(), 0, OpFlags);
|
||||
needIndirectCall = false;
|
||||
}
|
||||
|
||||
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
||||
|
@ -1,482 +0,0 @@
|
||||
//===-- PPCJITInfo.cpp - Implement the JIT interfaces for the PowerPC -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the JIT interfaces for the 32-bit PowerPC target.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "PPCJITInfo.h"
|
||||
#include "PPCRelocations.h"
|
||||
#include "PPCSubtarget.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
|
||||
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
|
||||
|
||||
PPCJITInfo::PPCJITInfo(PPCSubtarget &STI)
|
||||
: Subtarget(STI), is64Bit(STI.isPPC64()) {
|
||||
useGOT = 0;
|
||||
}
|
||||
|
||||
#define BUILD_ADDIS(RD,RS,IMM16) \
|
||||
((15 << 26) | ((RD) << 21) | ((RS) << 16) | ((IMM16) & 65535))
|
||||
#define BUILD_ORI(RD,RS,UIMM16) \
|
||||
((24 << 26) | ((RS) << 21) | ((RD) << 16) | ((UIMM16) & 65535))
|
||||
#define BUILD_ORIS(RD,RS,UIMM16) \
|
||||
((25 << 26) | ((RS) << 21) | ((RD) << 16) | ((UIMM16) & 65535))
|
||||
#define BUILD_RLDICR(RD,RS,SH,ME) \
|
||||
((30 << 26) | ((RS) << 21) | ((RD) << 16) | (((SH) & 31) << 11) | \
|
||||
(((ME) & 63) << 6) | (1 << 2) | ((((SH) >> 5) & 1) << 1))
|
||||
#define BUILD_MTSPR(RS,SPR) \
|
||||
((31 << 26) | ((RS) << 21) | ((SPR) << 16) | (467 << 1))
|
||||
#define BUILD_BCCTRx(BO,BI,LINK) \
|
||||
((19 << 26) | ((BO) << 21) | ((BI) << 16) | (528 << 1) | ((LINK) & 1))
|
||||
#define BUILD_B(TARGET, LINK) \
|
||||
((18 << 26) | (((TARGET) & 0x00FFFFFF) << 2) | ((LINK) & 1))
|
||||
|
||||
// Pseudo-ops
|
||||
#define BUILD_LIS(RD,IMM16) BUILD_ADDIS(RD,0,IMM16)
|
||||
#define BUILD_SLDI(RD,RS,IMM6) BUILD_RLDICR(RD,RS,IMM6,63-IMM6)
|
||||
#define BUILD_MTCTR(RS) BUILD_MTSPR(RS,9)
|
||||
#define BUILD_BCTR(LINK) BUILD_BCCTRx(20,0,LINK)
|
||||
|
||||
static void EmitBranchToAt(uint64_t At, uint64_t To, bool isCall, bool is64Bit){
|
||||
intptr_t Offset = ((intptr_t)To - (intptr_t)At) >> 2;
|
||||
unsigned *AtI = (unsigned*)(intptr_t)At;
|
||||
|
||||
if (Offset >= -(1 << 23) && Offset < (1 << 23)) { // In range?
|
||||
AtI[0] = BUILD_B(Offset, isCall); // b/bl target
|
||||
} else if (!is64Bit) {
|
||||
AtI[0] = BUILD_LIS(12, To >> 16); // lis r12, hi16(address)
|
||||
AtI[1] = BUILD_ORI(12, 12, To); // ori r12, r12, lo16(address)
|
||||
AtI[2] = BUILD_MTCTR(12); // mtctr r12
|
||||
AtI[3] = BUILD_BCTR(isCall); // bctr/bctrl
|
||||
} else {
|
||||
AtI[0] = BUILD_LIS(12, To >> 48); // lis r12, hi16(address)
|
||||
AtI[1] = BUILD_ORI(12, 12, To >> 32); // ori r12, r12, lo16(address)
|
||||
AtI[2] = BUILD_SLDI(12, 12, 32); // sldi r12, r12, 32
|
||||
AtI[3] = BUILD_ORIS(12, 12, To >> 16); // oris r12, r12, hi16(address)
|
||||
AtI[4] = BUILD_ORI(12, 12, To); // ori r12, r12, lo16(address)
|
||||
AtI[5] = BUILD_MTCTR(12); // mtctr r12
|
||||
AtI[6] = BUILD_BCTR(isCall); // bctr/bctrl
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void PPC32CompilationCallback();
|
||||
extern "C" void PPC64CompilationCallback();
|
||||
|
||||
// The first clause of the preprocessor directive looks wrong, but it is
|
||||
// necessary when compiling this code on non-PowerPC hosts.
|
||||
#if (!defined(__ppc__) && !defined(__powerpc__)) || defined(__powerpc64__) || defined(__ppc64__)
|
||||
void PPC32CompilationCallback() {
|
||||
llvm_unreachable("This is not a 32bit PowerPC, you can't execute this!");
|
||||
}
|
||||
#elif !defined(__ELF__)
|
||||
// CompilationCallback stub - We can't use a C function with inline assembly in
|
||||
// it, because we the prolog/epilog inserted by GCC won't work for us. Instead,
|
||||
// write our own wrapper, which does things our way, so we have complete control
|
||||
// over register saving and restoring.
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl _PPC32CompilationCallback\n"
|
||||
"_PPC32CompilationCallback:\n"
|
||||
// Make space for 8 ints r[3-10] and 13 doubles f[1-13] and the
|
||||
// FIXME: need to save v[0-19] for altivec?
|
||||
// FIXME: could shrink frame
|
||||
// Set up a proper stack frame
|
||||
// FIXME Layout
|
||||
// PowerPC32 ABI linkage - 24 bytes
|
||||
// parameters - 32 bytes
|
||||
// 13 double registers - 104 bytes
|
||||
// 8 int registers - 32 bytes
|
||||
"mflr r0\n"
|
||||
"stw r0, 8(r1)\n"
|
||||
"stwu r1, -208(r1)\n"
|
||||
// Save all int arg registers
|
||||
"stw r10, 204(r1)\n" "stw r9, 200(r1)\n"
|
||||
"stw r8, 196(r1)\n" "stw r7, 192(r1)\n"
|
||||
"stw r6, 188(r1)\n" "stw r5, 184(r1)\n"
|
||||
"stw r4, 180(r1)\n" "stw r3, 176(r1)\n"
|
||||
// Save all call-clobbered FP regs.
|
||||
"stfd f13, 168(r1)\n" "stfd f12, 160(r1)\n"
|
||||
"stfd f11, 152(r1)\n" "stfd f10, 144(r1)\n"
|
||||
"stfd f9, 136(r1)\n" "stfd f8, 128(r1)\n"
|
||||
"stfd f7, 120(r1)\n" "stfd f6, 112(r1)\n"
|
||||
"stfd f5, 104(r1)\n" "stfd f4, 96(r1)\n"
|
||||
"stfd f3, 88(r1)\n" "stfd f2, 80(r1)\n"
|
||||
"stfd f1, 72(r1)\n"
|
||||
// Arguments to Compilation Callback:
|
||||
// r3 - our lr (address of the call instruction in stub plus 4)
|
||||
// r4 - stub's lr (address of instruction that called the stub plus 4)
|
||||
// r5 - is64Bit - always 0.
|
||||
"mr r3, r0\n"
|
||||
"lwz r2, 208(r1)\n" // stub's frame
|
||||
"lwz r4, 8(r2)\n" // stub's lr
|
||||
"li r5, 0\n" // 0 == 32 bit
|
||||
"bl _LLVMPPCCompilationCallback\n"
|
||||
"mtctr r3\n"
|
||||
// Restore all int arg registers
|
||||
"lwz r10, 204(r1)\n" "lwz r9, 200(r1)\n"
|
||||
"lwz r8, 196(r1)\n" "lwz r7, 192(r1)\n"
|
||||
"lwz r6, 188(r1)\n" "lwz r5, 184(r1)\n"
|
||||
"lwz r4, 180(r1)\n" "lwz r3, 176(r1)\n"
|
||||
// Restore all FP arg registers
|
||||
"lfd f13, 168(r1)\n" "lfd f12, 160(r1)\n"
|
||||
"lfd f11, 152(r1)\n" "lfd f10, 144(r1)\n"
|
||||
"lfd f9, 136(r1)\n" "lfd f8, 128(r1)\n"
|
||||
"lfd f7, 120(r1)\n" "lfd f6, 112(r1)\n"
|
||||
"lfd f5, 104(r1)\n" "lfd f4, 96(r1)\n"
|
||||
"lfd f3, 88(r1)\n" "lfd f2, 80(r1)\n"
|
||||
"lfd f1, 72(r1)\n"
|
||||
// Pop 3 frames off the stack and branch to target
|
||||
"lwz r1, 208(r1)\n"
|
||||
"lwz r2, 8(r1)\n"
|
||||
"mtlr r2\n"
|
||||
"bctr\n"
|
||||
);
|
||||
|
||||
#else
|
||||
// ELF PPC 32 support
|
||||
|
||||
// CompilationCallback stub - We can't use a C function with inline assembly in
|
||||
// it, because we the prolog/epilog inserted by GCC won't work for us. Instead,
|
||||
// write our own wrapper, which does things our way, so we have complete control
|
||||
// over register saving and restoring.
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl PPC32CompilationCallback\n"
|
||||
"PPC32CompilationCallback:\n"
|
||||
// Make space for 8 ints r[3-10] and 8 doubles f[1-8] and the
|
||||
// FIXME: need to save v[0-19] for altivec?
|
||||
// FIXME: could shrink frame
|
||||
// Set up a proper stack frame
|
||||
// FIXME Layout
|
||||
// 8 double registers - 64 bytes
|
||||
// 8 int registers - 32 bytes
|
||||
"mflr 0\n"
|
||||
"stw 0, 4(1)\n"
|
||||
"stwu 1, -104(1)\n"
|
||||
// Save all int arg registers
|
||||
"stw 10, 100(1)\n" "stw 9, 96(1)\n"
|
||||
"stw 8, 92(1)\n" "stw 7, 88(1)\n"
|
||||
"stw 6, 84(1)\n" "stw 5, 80(1)\n"
|
||||
"stw 4, 76(1)\n" "stw 3, 72(1)\n"
|
||||
// Save all call-clobbered FP regs.
|
||||
"stfd 8, 64(1)\n"
|
||||
"stfd 7, 56(1)\n" "stfd 6, 48(1)\n"
|
||||
"stfd 5, 40(1)\n" "stfd 4, 32(1)\n"
|
||||
"stfd 3, 24(1)\n" "stfd 2, 16(1)\n"
|
||||
"stfd 1, 8(1)\n"
|
||||
// Arguments to Compilation Callback:
|
||||
// r3 - our lr (address of the call instruction in stub plus 4)
|
||||
// r4 - stub's lr (address of instruction that called the stub plus 4)
|
||||
// r5 - is64Bit - always 0.
|
||||
"mr 3, 0\n"
|
||||
"lwz 5, 104(1)\n" // stub's frame
|
||||
"lwz 4, 4(5)\n" // stub's lr
|
||||
"li 5, 0\n" // 0 == 32 bit
|
||||
"bl LLVMPPCCompilationCallback\n"
|
||||
"mtctr 3\n"
|
||||
// Restore all int arg registers
|
||||
"lwz 10, 100(1)\n" "lwz 9, 96(1)\n"
|
||||
"lwz 8, 92(1)\n" "lwz 7, 88(1)\n"
|
||||
"lwz 6, 84(1)\n" "lwz 5, 80(1)\n"
|
||||
"lwz 4, 76(1)\n" "lwz 3, 72(1)\n"
|
||||
// Restore all FP arg registers
|
||||
"lfd 8, 64(1)\n"
|
||||
"lfd 7, 56(1)\n" "lfd 6, 48(1)\n"
|
||||
"lfd 5, 40(1)\n" "lfd 4, 32(1)\n"
|
||||
"lfd 3, 24(1)\n" "lfd 2, 16(1)\n"
|
||||
"lfd 1, 8(1)\n"
|
||||
// Pop 3 frames off the stack and branch to target
|
||||
"lwz 1, 104(1)\n"
|
||||
"lwz 0, 4(1)\n"
|
||||
"mtlr 0\n"
|
||||
"bctr\n"
|
||||
);
|
||||
#endif
|
||||
|
||||
#if !defined(__powerpc64__) && !defined(__ppc64__)
|
||||
void PPC64CompilationCallback() {
|
||||
llvm_unreachable("This is not a 64bit PowerPC, you can't execute this!");
|
||||
}
|
||||
#else
|
||||
# ifdef __ELF__
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl PPC64CompilationCallback\n"
|
||||
#if _CALL_ELF == 2
|
||||
".type PPC64CompilationCallback,@function\n"
|
||||
"PPC64CompilationCallback:\n"
|
||||
#else
|
||||
".section \".opd\",\"aw\",@progbits\n"
|
||||
".align 3\n"
|
||||
"PPC64CompilationCallback:\n"
|
||||
".quad .L.PPC64CompilationCallback,.TOC.@tocbase,0\n"
|
||||
".size PPC64CompilationCallback,24\n"
|
||||
".previous\n"
|
||||
".align 4\n"
|
||||
".type PPC64CompilationCallback,@function\n"
|
||||
".L.PPC64CompilationCallback:\n"
|
||||
#endif
|
||||
# else
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl _PPC64CompilationCallback\n"
|
||||
"_PPC64CompilationCallback:\n"
|
||||
# endif
|
||||
// Make space for 8 ints r[3-10] and 13 doubles f[1-13] and the
|
||||
// FIXME: need to save v[0-19] for altivec?
|
||||
// Set up a proper stack frame
|
||||
// Layout
|
||||
// PowerPC64 ABI linkage - 48 bytes
|
||||
// parameters - 64 bytes
|
||||
// 13 double registers - 104 bytes
|
||||
// 8 int registers - 64 bytes
|
||||
"mflr 0\n"
|
||||
"std 0, 16(1)\n"
|
||||
"stdu 1, -280(1)\n"
|
||||
// Save all int arg registers
|
||||
"std 10, 272(1)\n" "std 9, 264(1)\n"
|
||||
"std 8, 256(1)\n" "std 7, 248(1)\n"
|
||||
"std 6, 240(1)\n" "std 5, 232(1)\n"
|
||||
"std 4, 224(1)\n" "std 3, 216(1)\n"
|
||||
// Save all call-clobbered FP regs.
|
||||
"stfd 13, 208(1)\n" "stfd 12, 200(1)\n"
|
||||
"stfd 11, 192(1)\n" "stfd 10, 184(1)\n"
|
||||
"stfd 9, 176(1)\n" "stfd 8, 168(1)\n"
|
||||
"stfd 7, 160(1)\n" "stfd 6, 152(1)\n"
|
||||
"stfd 5, 144(1)\n" "stfd 4, 136(1)\n"
|
||||
"stfd 3, 128(1)\n" "stfd 2, 120(1)\n"
|
||||
"stfd 1, 112(1)\n"
|
||||
// Arguments to Compilation Callback:
|
||||
// r3 - our lr (address of the call instruction in stub plus 4)
|
||||
// r4 - stub's lr (address of instruction that called the stub plus 4)
|
||||
// r5 - is64Bit - always 1.
|
||||
"mr 3, 0\n" // return address (still in r0)
|
||||
"ld 5, 280(1)\n" // stub's frame
|
||||
"ld 4, 16(5)\n" // stub's lr
|
||||
"li 5, 1\n" // 1 == 64 bit
|
||||
# ifdef __ELF__
|
||||
"bl LLVMPPCCompilationCallback\n"
|
||||
"nop\n"
|
||||
# else
|
||||
"bl _LLVMPPCCompilationCallback\n"
|
||||
# endif
|
||||
"mtctr 3\n"
|
||||
// Restore all int arg registers
|
||||
"ld 10, 272(1)\n" "ld 9, 264(1)\n"
|
||||
"ld 8, 256(1)\n" "ld 7, 248(1)\n"
|
||||
"ld 6, 240(1)\n" "ld 5, 232(1)\n"
|
||||
"ld 4, 224(1)\n" "ld 3, 216(1)\n"
|
||||
// Restore all FP arg registers
|
||||
"lfd 13, 208(1)\n" "lfd 12, 200(1)\n"
|
||||
"lfd 11, 192(1)\n" "lfd 10, 184(1)\n"
|
||||
"lfd 9, 176(1)\n" "lfd 8, 168(1)\n"
|
||||
"lfd 7, 160(1)\n" "lfd 6, 152(1)\n"
|
||||
"lfd 5, 144(1)\n" "lfd 4, 136(1)\n"
|
||||
"lfd 3, 128(1)\n" "lfd 2, 120(1)\n"
|
||||
"lfd 1, 112(1)\n"
|
||||
// Pop 3 frames off the stack and branch to target
|
||||
"ld 1, 280(1)\n"
|
||||
"ld 0, 16(1)\n"
|
||||
"mtlr 0\n"
|
||||
// XXX: any special TOC handling in the ELF case for JIT?
|
||||
"bctr\n"
|
||||
);
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
LLVM_LIBRARY_VISIBILITY void *
|
||||
LLVMPPCCompilationCallback(unsigned *StubCallAddrPlus4,
|
||||
unsigned *OrigCallAddrPlus4,
|
||||
bool is64Bit) {
|
||||
// Adjust the pointer to the address of the call instruction in the stub
|
||||
// emitted by emitFunctionStub, rather than the instruction after it.
|
||||
unsigned *StubCallAddr = StubCallAddrPlus4 - 1;
|
||||
unsigned *OrigCallAddr = OrigCallAddrPlus4 - 1;
|
||||
|
||||
void *Target = JITCompilerFunction(StubCallAddr);
|
||||
|
||||
// Check to see if *OrigCallAddr is a 'bl' instruction, and if we can rewrite
|
||||
// it to branch directly to the destination. If so, rewrite it so it does not
|
||||
// need to go through the stub anymore.
|
||||
unsigned OrigCallInst = *OrigCallAddr;
|
||||
if ((OrigCallInst >> 26) == 18) { // Direct call.
|
||||
intptr_t Offset = ((intptr_t)Target - (intptr_t)OrigCallAddr) >> 2;
|
||||
|
||||
if (Offset >= -(1 << 23) && Offset < (1 << 23)) { // In range?
|
||||
// Clear the original target out.
|
||||
OrigCallInst &= (63 << 26) | 3;
|
||||
// Fill in the new target.
|
||||
OrigCallInst |= (Offset & ((1 << 24)-1)) << 2;
|
||||
// Replace the call.
|
||||
*OrigCallAddr = OrigCallInst;
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that we are coming from a stub that was created with our
|
||||
// emitFunctionStub.
|
||||
if ((*StubCallAddr >> 26) == 18)
|
||||
StubCallAddr -= 3;
|
||||
else {
|
||||
assert((*StubCallAddr >> 26) == 19 && "Call in stub is not indirect!");
|
||||
StubCallAddr -= is64Bit ? 9 : 6;
|
||||
}
|
||||
|
||||
// Rewrite the stub with an unconditional branch to the target, for any users
|
||||
// who took the address of the stub.
|
||||
EmitBranchToAt((intptr_t)StubCallAddr, (intptr_t)Target, false, is64Bit);
|
||||
sys::Memory::InvalidateInstructionCache(StubCallAddr, 7*4);
|
||||
|
||||
// Put the address of the target function to call and the address to return to
|
||||
// after calling the target function in a place that is easy to get on the
|
||||
// stack after we restore all regs.
|
||||
return Target;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TargetJITInfo::LazyResolverFn
|
||||
PPCJITInfo::getLazyResolverFunction(JITCompilerFn Fn) {
|
||||
JITCompilerFunction = Fn;
|
||||
return is64Bit ? PPC64CompilationCallback : PPC32CompilationCallback;
|
||||
}
|
||||
|
||||
TargetJITInfo::StubLayout PPCJITInfo::getStubLayout() {
|
||||
// The stub contains up to 10 4-byte instructions, aligned at 4 bytes: 3
|
||||
// instructions to save the caller's address if this is a lazy-compilation
|
||||
// stub, plus a 1-, 4-, or 7-instruction sequence to load an arbitrary address
|
||||
// into a register and jump through it.
|
||||
StubLayout Result = {10*4, 4};
|
||||
return Result;
|
||||
}
|
||||
|
||||
#if (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
|
||||
defined(__APPLE__)
|
||||
extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
|
||||
#endif
|
||||
|
||||
void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn,
|
||||
JITCodeEmitter &JCE) {
|
||||
// If this is just a call to an external function, emit a branch instead of a
|
||||
// call. The code is the same except for one bit of the last instruction.
|
||||
if (Fn != (void*)(intptr_t)PPC32CompilationCallback &&
|
||||
Fn != (void*)(intptr_t)PPC64CompilationCallback) {
|
||||
void *Addr = (void*)JCE.getCurrentPCValue();
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
EmitBranchToAt((intptr_t)Addr, (intptr_t)Fn, false, is64Bit);
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 7*4);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void *Addr = (void*)JCE.getCurrentPCValue();
|
||||
if (is64Bit) {
|
||||
JCE.emitWordBE(0xf821ffb1); // stdu r1,-80(r1)
|
||||
JCE.emitWordBE(0x7d6802a6); // mflr r11
|
||||
JCE.emitWordBE(0xf9610060); // std r11, 96(r1)
|
||||
} else if (Subtarget.isDarwinABI()){
|
||||
JCE.emitWordBE(0x9421ffe0); // stwu r1,-32(r1)
|
||||
JCE.emitWordBE(0x7d6802a6); // mflr r11
|
||||
JCE.emitWordBE(0x91610028); // stw r11, 40(r1)
|
||||
} else {
|
||||
JCE.emitWordBE(0x9421ffe0); // stwu r1,-32(r1)
|
||||
JCE.emitWordBE(0x7d6802a6); // mflr r11
|
||||
JCE.emitWordBE(0x91610024); // stw r11, 36(r1)
|
||||
}
|
||||
intptr_t BranchAddr = (intptr_t)JCE.getCurrentPCValue();
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
JCE.emitWordBE(0);
|
||||
EmitBranchToAt(BranchAddr, (intptr_t)Fn, true, is64Bit);
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 10*4);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
|
||||
void PPCJITInfo::relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase) {
|
||||
for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
|
||||
unsigned *RelocPos = (unsigned*)Function + MR->getMachineCodeOffset()/4;
|
||||
intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
|
||||
switch ((PPC::RelocationType)MR->getRelocationType()) {
|
||||
default: llvm_unreachable("Unknown relocation type!");
|
||||
case PPC::reloc_pcrel_bx:
|
||||
// PC-relative relocation for b and bl instructions.
|
||||
ResultPtr = (ResultPtr-(intptr_t)RelocPos) >> 2;
|
||||
assert(ResultPtr >= -(1 << 23) && ResultPtr < (1 << 23) &&
|
||||
"Relocation out of range!");
|
||||
*RelocPos |= (ResultPtr & ((1 << 24)-1)) << 2;
|
||||
break;
|
||||
case PPC::reloc_pcrel_bcx:
|
||||
// PC-relative relocation for BLT,BLE,BEQ,BGE,BGT,BNE, or other
|
||||
// bcx instructions.
|
||||
ResultPtr = (ResultPtr-(intptr_t)RelocPos) >> 2;
|
||||
assert(ResultPtr >= -(1 << 13) && ResultPtr < (1 << 13) &&
|
||||
"Relocation out of range!");
|
||||
*RelocPos |= (ResultPtr & ((1 << 14)-1)) << 2;
|
||||
break;
|
||||
case PPC::reloc_absolute_high: // high bits of ref -> low 16 of instr
|
||||
case PPC::reloc_absolute_low: { // low bits of ref -> low 16 of instr
|
||||
ResultPtr += MR->getConstantVal();
|
||||
|
||||
// If this is a high-part access, get the high-part.
|
||||
if (MR->getRelocationType() == PPC::reloc_absolute_high) {
|
||||
// If the low part will have a carry (really a borrow) from the low
|
||||
// 16-bits into the high 16, add a bit to borrow from.
|
||||
if (((int)ResultPtr << 16) < 0)
|
||||
ResultPtr += 1 << 16;
|
||||
ResultPtr >>= 16;
|
||||
}
|
||||
|
||||
// Do the addition then mask, so the addition does not overflow the 16-bit
|
||||
// immediate section of the instruction.
|
||||
unsigned LowBits = (*RelocPos + ResultPtr) & 65535;
|
||||
unsigned HighBits = *RelocPos & ~65535;
|
||||
*RelocPos = LowBits | HighBits; // Slam into low 16-bits
|
||||
break;
|
||||
}
|
||||
case PPC::reloc_absolute_low_ix: { // low bits of ref -> low 14 of instr
|
||||
ResultPtr += MR->getConstantVal();
|
||||
// Do the addition then mask, so the addition does not overflow the 16-bit
|
||||
// immediate section of the instruction.
|
||||
unsigned LowBits = (*RelocPos + ResultPtr) & 0xFFFC;
|
||||
unsigned HighBits = *RelocPos & 0xFFFF0003;
|
||||
*RelocPos = LowBits | HighBits; // Slam into low 14-bits.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPCJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
|
||||
EmitBranchToAt((intptr_t)Old, (intptr_t)New, false, is64Bit);
|
||||
sys::Memory::InvalidateInstructionCache(Old, 7*4);
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
//===-- PPCJITInfo.h - PowerPC impl. of the JIT interface -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the PowerPC implementation of the TargetJITInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef POWERPC_JITINFO_H
|
||||
#define POWERPC_JITINFO_H
|
||||
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class PPCSubtarget;
|
||||
class PPCJITInfo : public TargetJITInfo {
|
||||
protected:
|
||||
PPCSubtarget &Subtarget;
|
||||
bool is64Bit;
|
||||
|
||||
public:
|
||||
PPCJITInfo(PPCSubtarget &STI);
|
||||
|
||||
StubLayout getStubLayout() override;
|
||||
void *emitFunctionStub(const Function *F, void *Fn,
|
||||
JITCodeEmitter &JCE) override;
|
||||
LazyResolverFn getLazyResolverFunction(JITCompilerFn) override;
|
||||
void relocate(void *Function, MachineRelocation *MR, unsigned NumRelocs,
|
||||
unsigned char *GOTBase) override;
|
||||
|
||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
||||
/// code.
|
||||
///
|
||||
void replaceMachineCodeForFunction(void *Old, void *New) override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -80,21 +80,9 @@ PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &CPU,
|
||||
: PPCGenSubtargetInfo(TT, CPU, FS), IsPPC64(is64Bit), TargetTriple(TT),
|
||||
OptLevel(OptLevel), TargetABI(PPC_ABI_UNKNOWN),
|
||||
FrameLowering(initializeSubtargetDependencies(CPU, FS)),
|
||||
DL(getDataLayoutString(*this)), InstrInfo(*this), JITInfo(*this),
|
||||
DL(getDataLayoutString(*this)), InstrInfo(*this),
|
||||
TLInfo(TM), TSInfo(&DL) {}
|
||||
|
||||
/// SetJITMode - This is called to inform the subtarget info that we are
|
||||
/// producing code for the JIT.
|
||||
void PPCSubtarget::SetJITMode() {
|
||||
// JIT mode doesn't want lazy resolver stubs, it knows exactly where
|
||||
// everything is. This matters for PPC64, which codegens in PIC mode without
|
||||
// stubs.
|
||||
HasLazyResolverStubs = false;
|
||||
|
||||
// Calls to external functions need to use indirect calls
|
||||
IsJITCodeModel = true;
|
||||
}
|
||||
|
||||
void PPCSubtarget::resetSubtargetFeatures(const MachineFunction *MF) {
|
||||
AttributeSet FnAttrs = MF->getFunction()->getAttributes();
|
||||
Attribute CPUAttr = FnAttrs.getAttribute(AttributeSet::FunctionIndex,
|
||||
@ -143,7 +131,6 @@ void PPCSubtarget::initializeEnvironment() {
|
||||
DeprecatedMFTB = false;
|
||||
DeprecatedDST = false;
|
||||
HasLazyResolverStubs = false;
|
||||
IsJITCodeModel = false;
|
||||
}
|
||||
|
||||
void PPCSubtarget::resetSubtargetFeatures(StringRef CPU, StringRef FS) {
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "PPCFrameLowering.h"
|
||||
#include "PPCInstrInfo.h"
|
||||
#include "PPCISelLowering.h"
|
||||
#include "PPCJITInfo.h"
|
||||
#include "PPCSelectionDAGInfo.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
@ -104,7 +103,6 @@ protected:
|
||||
bool DeprecatedMFTB;
|
||||
bool DeprecatedDST;
|
||||
bool HasLazyResolverStubs;
|
||||
bool IsJITCodeModel;
|
||||
bool IsLittleEndian;
|
||||
|
||||
/// TargetTriple - What processor and OS we're targeting.
|
||||
@ -122,7 +120,6 @@ protected:
|
||||
PPCFrameLowering FrameLowering;
|
||||
const DataLayout DL;
|
||||
PPCInstrInfo InstrInfo;
|
||||
PPCJITInfo JITInfo;
|
||||
PPCTargetLowering TLInfo;
|
||||
PPCSelectionDAGInfo TSInfo;
|
||||
|
||||
@ -138,10 +135,6 @@ public:
|
||||
/// subtarget options. Definition of function is auto generated by tblgen.
|
||||
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
|
||||
|
||||
/// SetJITMode - This is called to inform the subtarget info that we are
|
||||
/// producing code for the JIT.
|
||||
void SetJITMode();
|
||||
|
||||
/// getStackAlignment - Returns the minimum alignment known to hold of the
|
||||
/// stack frame on entry to the function and which must be maintained by every
|
||||
/// function for this subtarget.
|
||||
@ -162,7 +155,6 @@ public:
|
||||
}
|
||||
const DataLayout *getDataLayout() const override { return &DL; }
|
||||
const PPCInstrInfo *getInstrInfo() const override { return &InstrInfo; }
|
||||
PPCJITInfo *getJITInfo() override { return &JITInfo; }
|
||||
const PPCTargetLowering *getTargetLowering() const override {
|
||||
return &TLInfo;
|
||||
}
|
||||
@ -207,9 +199,6 @@ public:
|
||||
bool hasLazyResolverStub(const GlobalValue *GV,
|
||||
const TargetMachine &TM) const;
|
||||
|
||||
// isJITCodeModel - True if we're generating code for the JIT
|
||||
bool isJITCodeModel() const { return IsJITCodeModel; }
|
||||
|
||||
// isLittleEndian - True if generating little-endian code
|
||||
bool isLittleEndian() const { return IsLittleEndian; }
|
||||
|
||||
|
@ -148,18 +148,6 @@ bool PPCPassConfig::addPreEmitPass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PPCTargetMachine::addCodeEmitter(PassManagerBase &PM,
|
||||
JITCodeEmitter &JCE) {
|
||||
// Inform the subtarget that we are in JIT mode. FIXME: does this break macho
|
||||
// writing?
|
||||
Subtarget.SetJITMode();
|
||||
|
||||
// Machine code emitter pass for PowerPC.
|
||||
PM.add(createPPCJITCodeEmitterPass(*this, JCE));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PPCTargetMachine::addAnalysisPasses(PassManagerBase &PM) {
|
||||
// Add first the target-independent BasicTTI pass, then our PPC pass. This
|
||||
// allows the PPC pass to delegate to the target independent layer when
|
||||
|
@ -36,8 +36,6 @@ public:
|
||||
|
||||
// Pass Pipeline Configuration
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
bool addCodeEmitter(PassManagerBase &PM,
|
||||
JITCodeEmitter &JCE) override;
|
||||
|
||||
/// \brief Register PPC analysis passes with a pass manager.
|
||||
void addAnalysisPasses(PassManagerBase &PM) override;
|
||||
|
@ -6,7 +6,7 @@ tablegen(LLVM AMDGPUGenDAGISel.inc -gen-dag-isel)
|
||||
tablegen(LLVM AMDGPUGenCallingConv.inc -gen-callingconv)
|
||||
tablegen(LLVM AMDGPUGenSubtargetInfo.inc -gen-subtarget)
|
||||
tablegen(LLVM AMDGPUGenIntrinsics.inc -gen-tgt-intrinsic)
|
||||
tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM AMDGPUGenDFAPacketizer.inc -gen-dfa-packetizer)
|
||||
tablegen(LLVM AMDGPUGenAsmWriter.inc -gen-asm-writer)
|
||||
add_public_tablegen_target(AMDGPUCommonTableGen)
|
||||
|
@ -2,9 +2,8 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td)
|
||||
|
||||
tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler)
|
||||
tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
|
||||
tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter)
|
||||
tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
|
||||
tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
|
||||
tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
|
||||
@ -24,8 +23,6 @@ add_llvm_target(SparcCodeGen
|
||||
SparcSubtarget.cpp
|
||||
SparcTargetMachine.cpp
|
||||
SparcSelectionDAGInfo.cpp
|
||||
SparcJITInfo.cpp
|
||||
SparcCodeEmitter.cpp
|
||||
SparcMCInstLower.cpp
|
||||
SparcTargetObjectFile.cpp
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \
|
||||
SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \
|
||||
SparcGenDAGISel.inc SparcGenDisassemblerTables.inc \
|
||||
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
|
||||
SparcGenCodeEmitter.inc SparcGenMCCodeEmitter.inc
|
||||
SparcGenMCCodeEmitter.inc
|
||||
|
||||
DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc
|
||||
|
||||
|
@ -29,8 +29,6 @@ namespace llvm {
|
||||
|
||||
FunctionPass *createSparcISelDag(SparcTargetMachine &TM);
|
||||
FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM);
|
||||
FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM,
|
||||
JITCodeEmitter &JCE);
|
||||
|
||||
void LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
|
||||
MCInst &OutMI,
|
||||
|
@ -1,281 +0,0 @@
|
||||
//===-- Sparc/SparcCodeEmitter.cpp - Convert Sparc Code to Machine Code ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the pass that transforms the Sparc machine instructions
|
||||
// into relocatable machine code.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include "Sparc.h"
|
||||
#include "MCTargetDesc/SparcMCExpr.h"
|
||||
#include "SparcRelocations.h"
|
||||
#include "SparcTargetMachine.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
|
||||
STATISTIC(NumEmitted, "Number of machine instructions emitted");
|
||||
|
||||
namespace {
|
||||
|
||||
class SparcCodeEmitter : public MachineFunctionPass {
|
||||
SparcJITInfo *JTI;
|
||||
const SparcInstrInfo *II;
|
||||
const DataLayout *TD;
|
||||
const SparcSubtarget *Subtarget;
|
||||
TargetMachine &TM;
|
||||
JITCodeEmitter &MCE;
|
||||
const std::vector<MachineConstantPoolEntry> *MCPEs;
|
||||
bool IsPIC;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<MachineModuleInfo> ();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
static char ID;
|
||||
|
||||
public:
|
||||
SparcCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce)
|
||||
: MachineFunctionPass(ID), JTI(nullptr), II(nullptr), TD(nullptr),
|
||||
TM(tm), MCE(mce), MCPEs(nullptr),
|
||||
IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "Sparc Machine Code Emitter";
|
||||
}
|
||||
|
||||
/// getBinaryCodeForInstr - This function, generated by the
|
||||
/// CodeEmitterGenerator using TableGen, produces the binary encoding for
|
||||
/// machine instructions.
|
||||
uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const;
|
||||
|
||||
void emitInstruction(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB);
|
||||
|
||||
private:
|
||||
/// getMachineOpValue - Return binary encoding of operand. If the machine
|
||||
/// operand requires relocation, record the relocation and return zero.
|
||||
unsigned getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
unsigned getCallTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
unsigned getBranchTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
unsigned getBranchPredTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
unsigned getBranchOnRegTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
|
||||
void emitWord(unsigned Word);
|
||||
|
||||
unsigned getRelocation(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc) const;
|
||||
void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const;
|
||||
void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const;
|
||||
void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const;
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
char SparcCodeEmitter::ID = 0;
|
||||
|
||||
bool SparcCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
|
||||
SparcTargetMachine &Target = static_cast<SparcTargetMachine &>(
|
||||
const_cast<TargetMachine &>(MF.getTarget()));
|
||||
|
||||
JTI = Target.getSubtargetImpl()->getJITInfo();
|
||||
II = Target.getSubtargetImpl()->getInstrInfo();
|
||||
TD = Target.getSubtargetImpl()->getDataLayout();
|
||||
Subtarget = &TM.getSubtarget<SparcSubtarget>();
|
||||
MCPEs = &MF.getConstantPool()->getConstants();
|
||||
JTI->Initialize(MF, IsPIC);
|
||||
MCE.setModuleInfo(&getAnalysis<MachineModuleInfo> ());
|
||||
|
||||
do {
|
||||
DEBUG(errs() << "JITTing function '"
|
||||
<< MF.getName() << "'\n");
|
||||
MCE.startFunction(MF);
|
||||
|
||||
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
|
||||
MBB != E; ++MBB){
|
||||
MCE.StartMachineBasicBlock(MBB);
|
||||
for (MachineBasicBlock::instr_iterator I = MBB->instr_begin(),
|
||||
E = MBB->instr_end(); I != E;)
|
||||
emitInstruction(*I++, *MBB);
|
||||
}
|
||||
} while (MCE.finishFunction(MF));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::emitInstruction(MachineBasicBlock::instr_iterator MI,
|
||||
MachineBasicBlock &MBB) {
|
||||
DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << *MI);
|
||||
|
||||
MCE.processDebugLoc(MI->getDebugLoc(), true);
|
||||
|
||||
++NumEmitted;
|
||||
|
||||
switch (MI->getOpcode()) {
|
||||
default: {
|
||||
emitWord(getBinaryCodeForInstr(*MI));
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::INLINEASM: {
|
||||
// We allow inline assembler nodes with empty bodies - they can
|
||||
// implicitly define registers, which is ok for JIT.
|
||||
if (MI->getOperand(0).getSymbolName()[0]) {
|
||||
report_fatal_error("JIT does not support inline asm!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::CFI_INSTRUCTION:
|
||||
break;
|
||||
case TargetOpcode::EH_LABEL: {
|
||||
MCE.emitLabel(MI->getOperand(0).getMCSymbol());
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::IMPLICIT_DEF:
|
||||
case TargetOpcode::KILL: {
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
case SP::GETPCX: {
|
||||
report_fatal_error("JIT does not support pseudo instruction GETPCX yet!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MCE.processDebugLoc(MI->getDebugLoc(), false);
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::emitWord(unsigned Word) {
|
||||
DEBUG(errs() << " 0x";
|
||||
errs().write_hex(Word) << "\n");
|
||||
MCE.emitWordBE(Word);
|
||||
}
|
||||
|
||||
/// getMachineOpValue - Return binary encoding of operand. If the machine
|
||||
/// operand requires relocation, record the relocation and return zero.
|
||||
unsigned SparcCodeEmitter::getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
if (MO.isReg())
|
||||
return TM.getSubtargetImpl()->getRegisterInfo()->getEncodingValue(
|
||||
MO.getReg());
|
||||
else if (MO.isImm())
|
||||
return static_cast<unsigned>(MO.getImm());
|
||||
else if (MO.isGlobal())
|
||||
emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO));
|
||||
else if (MO.isSymbol())
|
||||
emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO));
|
||||
else if (MO.isCPI())
|
||||
emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO));
|
||||
else if (MO.isMBB())
|
||||
emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO));
|
||||
else
|
||||
llvm_unreachable("Unable to encode MachineOperand!");
|
||||
return 0;
|
||||
}
|
||||
unsigned SparcCodeEmitter::getCallTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getBranchPredTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getBranchOnRegTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
|
||||
unsigned TF = MO.getTargetFlags();
|
||||
switch (TF) {
|
||||
default:
|
||||
case SparcMCExpr::VK_Sparc_None: break;
|
||||
case SparcMCExpr::VK_Sparc_LO: return SP::reloc_sparc_lo;
|
||||
case SparcMCExpr::VK_Sparc_HI: return SP::reloc_sparc_hi;
|
||||
case SparcMCExpr::VK_Sparc_H44: return SP::reloc_sparc_h44;
|
||||
case SparcMCExpr::VK_Sparc_M44: return SP::reloc_sparc_m44;
|
||||
case SparcMCExpr::VK_Sparc_L44: return SP::reloc_sparc_l44;
|
||||
case SparcMCExpr::VK_Sparc_HH: return SP::reloc_sparc_hh;
|
||||
case SparcMCExpr::VK_Sparc_HM: return SP::reloc_sparc_hm;
|
||||
}
|
||||
|
||||
unsigned Opc = MI.getOpcode();
|
||||
switch (Opc) {
|
||||
default: break;
|
||||
case SP::CALL: return SP::reloc_sparc_pc30;
|
||||
case SP::BA:
|
||||
case SP::BCOND:
|
||||
case SP::FBCOND: return SP::reloc_sparc_pc22;
|
||||
case SP::BPXCC: return SP::reloc_sparc_pc19;
|
||||
}
|
||||
llvm_unreachable("unknown reloc!");
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::emitGlobalAddress(const GlobalValue *GV,
|
||||
unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc,
|
||||
const_cast<GlobalValue *>(GV), 0,
|
||||
true));
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::
|
||||
emitExternalSymbolAddress(const char *ES, unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
|
||||
Reloc, ES, 0, 0));
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::
|
||||
emitConstPoolAddress(unsigned CPI, unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(),
|
||||
Reloc, CPI, 0, false));
|
||||
}
|
||||
|
||||
void SparcCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB,
|
||||
unsigned Reloc) const {
|
||||
MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(),
|
||||
Reloc, BB));
|
||||
}
|
||||
|
||||
|
||||
/// createSparcJITCodeEmitterPass - Return a pass that emits the collected Sparc
|
||||
/// code to the specified MCE object.
|
||||
FunctionPass *llvm::createSparcJITCodeEmitterPass(SparcTargetMachine &TM,
|
||||
JITCodeEmitter &JCE) {
|
||||
return new SparcCodeEmitter(TM, JCE);
|
||||
}
|
||||
|
||||
#include "SparcGenCodeEmitter.inc"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user