Voglio che la maggior parte del mio programma sia un programma C++ ordinariamente compilato. Detto programma utilizza un blocco di memoria contigua per una pila. La cima della pila è mantenuta da un puntatore ordinario.Condivisione di un puntatore C++ con codice JIT LLVM
Voglio condividere quel puntatore con il codice generato tramite JV LLVM. Ad esempio, dato:
llvm::InitializeNativeTarget();
llvm::LLVMContext ctx;
std::unique_ptr<llvm::Module> uptr_module = llvm::make_unique<llvm::Module>("lt", ctx);
llvm::Module *const module = uptr_module.get();
int *const stack = new int[100];
int *top = stack; // I want this pointer to be shared with JIT'd code
llvm::Function *const func = llvm::cast<llvm::Function>(
module->getOrInsertFunction("func", llvm::Type::getVoidTy(ctx), (llvm::Type*)0)
);
llvm::BasicBlock *const block = llvm::BasicBlock::Create(ctx, "entry", func);
pointerInc(&top, block); // Increment the pointer in JIT'd code
llvm::ReturnInst::Create(ctx, block);
llvm::verifyFunction(*func, &llvm::outs());
llvm::verifyModule(*module, &llvm::outs());
module->dump();
llvm::EngineBuilder eb(std::move(uptr_module));
llvm::ExecutionEngine *const exec = eb.create();
assert(exec);
void *const func_ptr = exec->getPointerToFunction(func);
assert(func_ptr);
typedef void (*PFv_v)();
(*(PFv_v)func_ptr)(); // Call JIT'd function
dove pointerInc()
inserirà codice JIT'd nella corrente BasicBlock
per incrementare top
. Il codice è pointerInc()
:
// Convert a raw C++ pointer into an LLVM Constant*.
template<typename T>
inline llvm::Value* ptrToValue(T **pptr, llvm::LLVMContext &ctx) {
return return llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), (uint64_t)pptr);
}
void pointerInc(llvm::Constant *pptrAsInt64, llvm::ConstantInt *sizeof_T,
llvm::BasicBlock *block) {
llvm::LLVMContext &ctx = block->getContext();
llvm::Constant *const intToPtr8 = llvm::ConstantExpr::getIntToPtr(
pptrAsInt64, llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(ctx))
);
llvm::GetElementPtrInst *const inc =
llvm::GetElementPtrInst::Create(intToPtr8, sizeof_T, "inc", block);
llvm::CastInst *const cast = llvm::CastInst::CreatePointerCast(
inc, llvm::Type::getInt64Ty(ctx), "cast", block
);
llvm::Constant *const intToPtr64 = llvm::ConstantExpr::getIntToPtr(
pptrAsInt64, llvm::PointerType::getUnqual(llvm::Type::getInt64Ty(ctx))
);
llvm::StoreInst *const store = new llvm::StoreInst(cast, intToPtr64, false, block);
store->setAlignment(8);
}
template<typename T>
inline void pointerInc(T **pptr, llvm::BasicBlock *block) {
llvm::LLVMContext &ctx = block->getContext();
llvm::ConstantInt *const sizeof_T =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(ctx), sizeof(T));
pointerInc(ptrToValue(pptr, ctx), sizeof_T, block);
}
Purtroppo, questo non funziona. È il corpo di (il più grande) pointerInc()
che è sbagliato. Il codice è in realtà derivato dal codice API LLVM C++ generato da llc
in un normale programma C++ che incrementa un puntatore.
Quando viene eseguito, il programma stampa:
&p = 140734551679784
--------------------
; ModuleID = 'lt'
define void @func() {
entry:
%inc = getelementptr i8* inttoptr (i64 140734551679784 to i8*), i64 4
%cast = ptrtoint i8* %inc to i64
store i64 %cast, i64* inttoptr (i64 140734551679784 to i64*), align 8
ret void
}
Segmentation fault: 11 (core dumped)
Ci sono due domande:
- È corretto? Posso persino fare ciò che voglio, cioè condividere un puntatore C++ non elaborato con il codice JIT?
- Perché si scarica il nucleo?
Anche se ho fatto la funzione JIT'd essere vuota, il codice ancora nucleo discariche alla linea che chiama la funzione. Il codice di installazione JIT di LLVM assomiglia a tutti gli esempi che ho visto, quindi non vedo nemmeno cosa c'è che non va.
Un piccolo aiuto?
Aggiornamento
Se cambio la linea deprecato:
void *const func_ptr = exec->getPointerToFunction(func);
alla nuova linea:
uint64_t const func_ptr = exec->getFunctionAddress("func");
poi func_ptr
è nullo.
Ho scritto qualcosa di simile qui: http://eli.thegreenplace.net/2015/calling-back-into-python-from-llvmlite-jited-code - utilizza i binding Python per LLVM, ma l'idea principale è lo stesso - rendere il codice JIT consapevole di qualcosa nel programma host –
Non penso che sia abbastanza simile. Sembra che tu stia chiamando una funzione dal codice JIT.Voglio solo incrementare un puntatore dal codice JIT. –
Si potrebbe chiedere su alcuni [LLVM-dev] (http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev) mailing list o su alcuni [canale IRC LLVM] (http://llvm.org/docs/# IRC). Potresti anche utilizzare qualche altra tecnologia: [GCCJIT] (https://gcc.gnu.org/onlinedocs/jit/), 'libjit',' asmjit' ecc; e potresti elencare il codice assembler prodotto per comprenderne di più. –