Why can I execute an LLVM function in my module once, and then a second time the function is NULL?

I’m working on a repl for a simple language using the LLVM C API.
So far I’m able to generate IR for an expression and execute it,
but if I do that again the function cannot be found

here is a simplified version of my ‘runner’ code:

#include "lang_runner.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>

#include "codegen.h"
#include "llvm_backend.h"
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Transforms/Scalar.h>
#include <llvm-c/Transforms/Utils.h>

int run_value(LLVMExecutionEngineRef engine, LLVMValueRef value) {
  if (value == NULL) {
    fprintf(stderr, "Unable to codegen for node\n");
    return 1;
  }

  // Dump IR.
  LLVMDumpValue(value);

  void *fp = LLVMGetPointerToGlobal(engine, value);
  double (*FP)() = (double (*)())(intptr_t)fp;

  if (FP) {
    fprintf(stderr, "Evaluted to %f\n", FP());
    return 0;
  } else {
    fprintf(stderr, "Could not find function pointer");
    return 1;
  }
}

int LLVMRuntime(int repl, char *path) {
  LLVMModuleRef module = LLVMModuleCreateWithName("ylc");
  LLVMBuilderRef builder = LLVMCreateBuilder();
  LLVMExecutionEngineRef engine;

  LLVMInitializeNativeTarget();
  LLVMLinkInMCJIT();
  LLVMInitializeNativeAsmPrinter();
  LLVMInitializeNativeAsmParser();

  char *msg;
  if (LLVMCreateExecutionEngineForModule(&engine, module, &msg) == 1) {
    fprintf(stderr, "%s\n", msg);
    LLVMDisposeMessage(msg);
    return 1;
  }

  char *input = malloc(sizeof(char) * INPUT_BUFSIZE);
  for (;;) {

    repl_input(input, INPUT_BUFSIZE, "> ");
    AST *ast = parse(input);
    print_ast(*ast, 0);
    printf("\n");
    LLVMValueRef value = codegen(ast, module, builder);
    run_value(engine, value);

    free_ast(ast);
  }

  // Dump entire module.
  LLVMDumpModule(module);

  LLVMDisposeBuilder(builder);
  LLVMDisposeModule(module);
  return 0;
}

and this is the function that generates the IR for the ‘top-level’ expression:

#include "codegen.h"
#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h>
#include <llvm-c/Types.h>
#include <stdio.h>
#include <stdlib.h>

static int counter = 0;
static LLVMValueRef codegen_main(AST *ast, LLVMModuleRef module,
                                 LLVMBuilderRef builder) {

  LLVMTypeRef funcType = LLVMFunctionType(LLVMDoubleType(), NULL, 0, 0);

  // Create function.
  char name[10];
  snprintf(name, sizeof(name), "main_%d", counter);
  counter++;

  LLVMValueRef func = LLVMAddFunction(module, name, funcType);
  LLVMSetLinkage(func, LLVMExternalLinkage);

  // Create basic block.
  LLVMBasicBlockRef block = LLVMAppendBasicBlock(func, name);
  LLVMPositionBuilderAtEnd(builder, block);

  // Generate body.
  LLVMValueRef body = codegen(ast->data.AST_MAIN.body, module, builder);

  if (body == NULL) {
    printf("delete func??");
    LLVMDeleteFunction(func);
    return NULL;
  }

  // Insert body as return vale.
  LLVMBuildRet(builder, body);

  // Verify function.
  if (LLVMVerifyFunction(func, LLVMPrintMessageAction) == 1) {
    fprintf(stderr, "Invalid function");
    LLVMDeleteFunction(func);
    return NULL;
  }

  return func;
}

and this is the output when I try to execute more than one expression with the dumped IR and comments:

> ./build/lang # call the repl executable
> -1.23 # prompt + input for the repl
main: # printed representation of my ast
 statements: 
  (-1.230000 )
define double @main_0() { # IR dump
main_0:
  ret double 0xBFF3AE1480000000
}
Evaluted to -1.230000 # works the first time
> -2.3 # second input
main: # ast dump
 statements: 
  (-2.300000 )
define double @main_1() { # IR dump
main_1:
  ret double 0xC002666660000000
}
Could not find function pointer # execution failed

I’m still quite new to LLVM and I’m struggling to understand how to ‘reuse’ the module & execution engine I’ve set up

here is a link to my repository: GitHub - crawdaddie/ylc at llvm-codegen-be

please let me know if this question needs more clarification or info

In case anyone stumbles across a similar issue:

I’ve managed to solve this by creating a new module for each new input of my repl, and cloning the previous module into it:

int init_lang_ctx(Context *ctx) {
  LLVMContextRef context = LLVMGetGlobalContext();
  LLVMModuleRef module = LLVMModuleCreateWithNameInContext("ylc", context);
  LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
  LLVMExecutionEngineRef engine;

  LLVMPassManagerRef pass_manager =
      LLVMCreateFunctionPassManagerForModule(module);

  LLVMAddPromoteMemoryToRegisterPass(pass_manager);
  // LLVMAddInstructionCombiningPass(pass_manager);
  LLVMAddReassociatePass(pass_manager);
  LLVMAddGVNPass(pass_manager);
  LLVMAddCFGSimplificationPass(pass_manager);
  LLVMAddTailCallEliminationPass(pass_manager);

  LLVMInitializeFunctionPassManager(pass_manager);

  char *error = NULL;
  if (LLVMCreateJITCompilerForModule(&engine, module, 2, &error) != 0) {
    fprintf(stderr, "Failed to create execution engine: %s\n", error);
    LLVMDisposeMessage(error);
    return 1;
  }

  ctx->context = context;
  ctx->builder = builder;
  ctx->engine = engine;
  ctx->module = module;
  ctx->pass_manager = pass_manager;
  return 0;
}

int reinit_lang_ctx(Context *ctx) {
  LLVMModuleRef newModule = LLVMCloneModule(ctx->module);
  // LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx->context);
  LLVMExecutionEngineRef engine;

  char *error = NULL;
  if (LLVMCreateJITCompilerForModule(&engine, newModule, 2, &error) != 0) {
    fprintf(stderr, "Failed to create execution engine: %s\n", error);
    LLVMDisposeMessage(error);
    return 1;
  }

  LLVMDisposeModule(ctx->module);
  ctx->module = newModule;
  // ctx->builder = builder;
  ctx->engine = engine;

  init_symbol_table(ctx->symbol_table);
  return 0;
}

init_lang_ctx sets up my llvm context & other values that I pass along to my codegen functions,
reinit_lang_ctx reuses the llvm context but creates a new module & clones the previous one into it.

I’m very curious if this is the proper way to achieve repl-like behaviour and persist functions & variables across repl iterations