2015-07-17 10 views
5

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:

  1. È corretto? Posso persino fare ciò che voglio, cioè condividere un puntatore C++ non elaborato con il codice JIT?
  2. 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.

+0

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 –

+0

Non penso che sia abbastanza simile. Sembra che tu stia chiamando una funzione dal codice JIT.Voglio solo incrementare un puntatore dal codice JIT. –

+0

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ù. –

risposta

1

Dopo aver suonato in giro un sacco di più con lcc (e usando un codice migliore C++ per alimentare in esso), ce l'ho a lavorare:

llvm::Value* pointerToPointer(void *ptr, llvm::BasicBlock *block) { 
    using namespace llvm; 
    LLVMContext &ctx = block->getContext(); 
    ConstantInt *const ptrAsInt = 
     ConstantInt::get(IntegerType::get(ctx, 64), (uint64_t)ptr); 
    PointerType *const Int8Ptr_type = Type::getInt8PtrTy(ctx); 
    PointerType *const Int8PtrPtr_type = PointerType::getUnqual(Int8Ptr_type); 
    return new IntToPtrInst(ptrAsInt, Int8PtrPtr_type, "pptr", block); 
} 

void pointerInc(llvm::Value *pptr, llvm::ConstantInt *sizeof_T, 
       llvm::BasicBlock *block) { 
    using namespace llvm; 
    LLVMContext &ctx = block->getContext(); 

    LoadInst *const ptr = new LoadInst(pptr, "ptr", block); 
    ptr->setAlignment(sizeof(void*)); 

    GetElementPtrInst *const inc = 
     GetElementPtrInst::Create(ptr, sizeof_T, "inc", block); 

    StoreInst *const store = new StoreInst(inc, pptr, block); 
    store->setAlignment(sizeof(void*)); 
} 

template<typename T> 
inline void pointerInc(T **pptr, llvm::BasicBlock *block) { 
    using namespace llvm; 
    LLVMContext &ctx = block->getContext(); 
    ConstantInt *const sizeof_T = ConstantInt::get(
     IntegerType::get(ctx, 64), (uint64_t)sizeof(T) 
    ); 
    pointerInc(pointerToPointer(pptr, block), sizeof_T, block); 
} 

Tuttavia, il programma viene eseguito con successo solo quando la funzione è JIT'd chiamato attraverso:

vector<GenericValue> noargs; 
exec->runFunction(func, noargs); 

Utilizzando uno o getFunctionAddress()getPointerToFunction() discariche nucleo. Non ho ancora una risposta.