2010-03-13 17 views
15

Probablemente es algo básico porque estoy empezando a aprender LLVM ..LLVM JIT segfaults. ¿Qué estoy haciendo mal?

Lo siguiente crea una función factorial y trata de git y ejecutarla (sé que el func generado es correcto porque pude compilar estáticamente y ejecutalo). Pero consigo fallo de segmentación después de la ejecución de la función (en EE-> runFunction (THEF, Args))

#include "llvm/Module.h" 
#include "llvm/Function.h" 
#include "llvm/PassManager.h" 
#include "llvm/CallingConv.h" 
#include "llvm/Analysis/Verifier.h" 
#include "llvm/Assembly/PrintModulePass.h" 
#include "llvm/Support/IRBuilder.h" 
#include "llvm/Support/raw_ostream.h" 
#include "llvm/ExecutionEngine/JIT.h" 
#include "llvm/ExecutionEngine/GenericValue.h" 


using namespace llvm; 


Module* makeLLVMModule() { 
    // Module Construction 
    LLVMContext& ctx = getGlobalContext(); 
    Module* mod = new Module("test", ctx); 
    Constant* c = mod->getOrInsertFunction("fact64", 
    /*ret type*/       IntegerType::get(ctx,64), 
             IntegerType::get(ctx,64), 
    /*varargs terminated with null*/  NULL); 

    Function* fact64 = cast<Function>(c); 
    fact64->setCallingConv(CallingConv::C); 
    /* Arg names */ 
    Function::arg_iterator args = fact64->arg_begin(); 
    Value* x = args++; 
    x->setName("x"); 


    /* Body */ 
    BasicBlock* block = BasicBlock::Create(ctx, "entry", fact64); 
    BasicBlock* xLessThan2Block= BasicBlock::Create(ctx, "xlst2_block", fact64); 
    BasicBlock* elseBlock = BasicBlock::Create(ctx, "else_block", fact64); 
    IRBuilder<> builder(block); 

    Value *One = ConstantInt::get(Type::getInt64Ty(ctx), 1); 
    Value *Two = ConstantInt::get(Type::getInt64Ty(ctx), 2); 

    Value* xLessThan2 = builder.CreateICmpULT(x, Two, "tmp"); 
//builder.CreateCondBr(xLessThan2, xLessThan2Block, cond_false_2); 
    builder.CreateCondBr(xLessThan2, xLessThan2Block, elseBlock); 


    /* Recursion */ 
    builder.SetInsertPoint(elseBlock); 
    Value* xMinus1 = builder.CreateSub(x, One, "tmp"); 
    std::vector<Value*> args1; 
    args1.push_back(xMinus1); 
    Value* recur_1 = builder.CreateCall(fact64, args1.begin(), args1.end(), "tmp"); 
    Value* retVal = builder.CreateBinOp(Instruction::Mul, x, recur_1, "tmp"); 
    builder.CreateRet(retVal); 

    /* x<2 */ 
    builder.SetInsertPoint(xLessThan2Block); 
    builder.CreateRet(One); 
    return mod; 
} 

int main(int argc, char**argv) { 
    long long x; 
    if(argc > 1) 
    x = atol(argv[1]); 
    else 
    x = 4; 

    Module* Mod = makeLLVMModule(); 

    verifyModule(*Mod, PrintMessageAction); 
    PassManager PM; 
    PM.add(createPrintModulePass(&outs())); 
    PM.run(*Mod); 

    // Now we going to create JIT 
    ExecutionEngine *EE = EngineBuilder(Mod).create(); 
    // Call the function with argument x: 
    std::vector<GenericValue> Args(1); 
    Args[0].IntVal = APInt(64, x); 
    Function* TheF = cast<Function>(Mod->getFunction("fact64")) ; 

    /* The following CRASHES.. */ 
    GenericValue GV = EE->runFunction(TheF, Args); 
    outs() << "Result: " << GV.IntVal << "\n"; 
    delete Mod; 
    return 0; 
} 

Editar: La forma correcta para permitir JIT (véase la respuesta aceptada a continuación):

1.#include "llvm/ExecutionEngine/Jit.h"` 

2.InitializeNativeTarget(); 

Respuesta

10

Me apuesto a que el puntero es nulo ExecutionEngine .... Usted se echa en falta una llamada a InitializeNativeTarget, de la documentación dice:

InitializeNativeTarget - El programa principal debe llamar a esta función para inicializar el objetivo nativo correspondiente al anfitrión. Esto es útil para las aplicaciones JIT para garantizar que el destino se vincule correctamente.

Puesto que no hay compilador JIT disponibles sin llamar InitializeNativeTarget, ModuleBuilder selecciona el intérprete (si está disponible). Probablemente no sea lo que querías. Es posible que desee look at my previous post on this subject.

+1

Gracias. Información muy útil. ¿Esto significa que para usar JIT y NO el intérprete debería incluir ExecutionEngine/JIT.h INSTEAD of llvm/ExecutionEngine/Interpreter.h? – GabiMe

+1

Sí, si desea el JIT, incluya JIT.h y asegúrese de llamar a InitializeNativeTarget() antes de crear un ExecutionEngine. También puede llamar a EngineBuilder.setEngineKind (EngineKind :: JIT) antes de llamar a .create() para asegurarse de obtener un JIT. –

+0

Ojalá pudiera votar más esto. Pasé aproximadamente una hora cazando este problema. Supongo que necesito aprender a RTFM un poco mejor. :) ¡Gracias de nuevo! – HVS

1
#include "llvm/ExecutionEngine/Interpreter.h" 
+0

¿Alguna idea de por qué incluir esto lo resuelve? – tstenner

+0

Sí. Buena pregunta. Por qué ? – GabiMe

2

la inclusión de esa cabecera (llvm/ExecutionEngine/Interpreter.h) fuerza una inicialización estática del JIT. No es la mejor decisión de diseño, pero al menos funciona.

Cuestiones relacionadas