HI,
I am (still) trying to create a REPL for a simple language
The approach I’ve sort of stumbled on is creating a module for each new REPL input, and linking the previous module into the new one. This works fine for functions, and global variables are persisted, but but when referenced it seems their values are set to 0, even if the previously executed module changed their value.
here is the function that creates a new module in between REPL invocations:
typedef struct {
LLVMContextRef context;
LLVMModuleRef module;
LLVMBuilderRef builder;
LLVMExecutionEngineRef engine;
SymbolTable *symbol_table;
LLVMPassManagerRef pass_manager;
char *module_path;
} Context;
int reinit_lang_ctx(Context *ctx) {
LLVMModuleRef newModule =
LLVMModuleCreateWithNameInContext(inst_name("ylc"), ctx->context);
char *error = NULL;
if (LLVMCreateJITCompilerForModule(&ctx->engine, newModule, 2, &error) != 0) {
fprintf(stderr, "Failed to create execution engine: %s\n", error);
LLVMDisposeMessage(error);
return 1;
}
LLVMModuleRef oldModule = ctx->module;
ctx->module = newModule;
LLVMValueRef global = LLVMGetFirstGlobal(oldModule);
while (global != NULL) {
const char *name = LLVMGetValueName(global);
SymbolValue sym;
if(table_lookup(ctx->symbol_table, name, &sym) == 0 && sym.type == TYPE_GLOBAL_VARIABLE) {
// find old global variables and copy their values to new ones??
}
global = LLVMGetNextGlobal(global);
}
// link symbols in old module into new module
LLVMLinkModules2(ctx->module, oldModule);
init_symbol_table(ctx->symbol_table);
return 0;
}
and here is what the generated IR looks like
first after evaluating a file
type Point = struct (
double x,
double y,
)
let printf = extern fn (str fmt, ...) int
let Point p = (
x = 2.0,
y = 1.0,
)
p.x = 3.0
printf("point x: %f\n", p.x)
printf("point y: %f\n", p.y)
IR:
; ModuleID = 'ylc1'
source_filename = "examples/structs.ylc"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
%Point = type <{ double, double }>
@p = global %Point zeroinitializer
@"point x: %f\0A" = private unnamed_addr constant [13 x i8] c"point x: %f\0A\00", align 1
@"point y: %f\0A" = private unnamed_addr constant [13 x i8] c"point y: %f\0A\00", align 1
define void @main() {
entry:
store %Point <{ double 2.000000e+00, double 1.000000e+00 }>, ptr @p, align 1
store double 3.000000e+00, ptr @p, align 8
%get_member_val = load double, ptr @p, align 8
%call2 = call ptr (ptr, ...) @printf(ptr @"point x: %f\0A", double %get_member_val)
%get_member_val1 = load double, ptr getelementptr inbounds (double, ptr @p, i32 1), align 8
%call3 = call ptr (ptr, ...) @printf(ptr @"point y: %f\0A", double %get_member_val1)
ret void
}
declare ptr @printf(ptr %0, ...)
after that I reinit the ctx (creating a new module & linking the old one) and then accept the repl input
p.x
; ModuleID = 'ylc4'
source_filename = "ylc4"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
%Point = type <{ double, double }>
@p = global %Point zeroinitializer
@"point x: %f\0A" = private unnamed_addr constant [13 x i8] c"point x: %f\0A\00", align 1
@"point y: %f\0A" = private unnamed_addr constant [13 x i8] c"point y: %f\0A\00", align 1
define void @main() {
entry:
store %Point <{ double 2.000000e+00, double 1.000000e+00 }>, ptr @p, align 1
store double 3.000000e+00, ptr @p, align 8
%get_member_val = load double, ptr @p, align 8
%call2 = call ptr (ptr, ...) @printf(ptr @"point x: %f\0A", double %get_member_val)
%get_member_val1 = load double, ptr getelementptr inbounds (double, ptr @p, i32 1), align 8
%call3 = call ptr (ptr, ...) @printf(ptr @"point y: %f\0A", double %get_member_val1)
ret void
}
declare ptr @printf(ptr %0, ...)
define void @main.1() {
entry:
%get_member_val = load double, ptr @p, align 8
ret void
}
that evaluation (@main.1()) yields the value 0.0000 rather than 3.000 as set in @main()
can anyone give me some pointers to what I might be doing wrong?
llvm v 16.0.6 & using LLVM C API