I'm trying to pass an array as a parameter and use this array in another function with a Toy lang like C.
My code run and compile well when I compiler the following code
int at_index(int a[], int index) {
return 0;
}
int main() {
int a[10];
int tmp;
tmp = at_index(a, 0);
print(tmp);
return 0;
}
My compiler generates the following IR
; ModuleID = 'MicrocC-module'
source_filename = "MicrocC-module"
declare void @print(i32)
declare i32 @getint()
define i32 @at_index(i32* %0, i32 %1) {
entry:
%a = alloca i32*
store i32* %0, i32** %a
%index = alloca i32
store i32 %1, i32* %index
ret i32 0
}
define i32 @main() {
entry:
%a = alloca [10 x i32]
%tmp = alloca i32
%a1 = getelementptr inbounds [10 x i32], [10 x i32]* %a, i32 0, i32 0
%0 = call i32 @at_index(i32* %a1, i32 0)
store i32 %0, i32* %tmp
%tmp2 = load i32, i32* %tmp
call void @print(i32 %tmp2)
ret i32 0
}
But if I try to use the array an in the function I receive a core dump from the compiler, my demo to have core dump is
int at_index(int a[], int index) {
a[0] = 0;
return 0;
}
int main() {
int a[10];
int tmp;
tmp = at_index(a, 0);
print(tmp);
return 0;
}
I start to debug the code but I'm not able to find the error, and maybe my access in the array from the code is wrong.
My general code to access in position to an array is to call the following LLVM API with Ocaml
I receive from the AST a node with the access operation as variable and the index and I call the following API.
Llvm.build_in_bounds_gep variable [0, index] "access" llvm_builder
with the result of this call, I make all the operation on the variable, but I'm thinking that the case of the function body when the array is as a parameter, my variable is a pointer and for this reason, I receive the error, but this is my idea and it is where I'm stuck, any idea? there is some additional operation to do to access in an array where it is a parameter?
Update
The portion of code where I'm generating the function call are.
The rules to generate the alloc and store inside the function declaration
let rec translate_stm_to_llvm_ir llvm_builder stm_def =
match stm_def.node with
| Ast.Dec(tipe, id) ->
begin
logger#debug "Declaration stm processing for type %s" (Ast.show_typ tipe);
match tipe with
| Ast.TypArray(arr_tipe, size) ->
begin
let llvm_arr = gen_array_type (to_llvm_type arr_tipe) size in
let llvm_val = Llvm.build_alloca llvm_arr id llvm_builder in
(>->) id llvm_val false
end
| _ ->
begin
logger#trace "Literal variable build with LLVM";
let all_llvm = Llvm.build_alloca (to_llvm_type tipe) id llvm_builder in
(>->) id all_llvm false
end
end
How during the function call I translate the parameter, eg: Create a pointer for the int array[] and a value for a[i]
and translate_fun_exp_to_llvm exp llvm_builder =
match exp.node with
| Assign(variable, exp) ->
begin
logger#trace "*Assign stm* translating ...";
let llvm_var = translate_acc_var variable llvm_builder in
let exp_to_assign = translate_exp_to_llvm exp llvm_builder in
let _ = Llvm.build_store exp_to_assign llvm_var llvm_builder in
Llvm.build_load llvm_var "" llvm_builder
end
| Access(access) ->
begin
match access.node with
| Ast.AccVar(id) ->
begin
logger#error "Access on var inside a function call";
try
let acc_var = (<-<) id in
let type_var = Llvm.type_of acc_var in
let name_var = Llvm.value_name acc_var in
match (Llvm.string_of_lltype type_var) with
| "i32*" | "i8*" | "i1*" ->
logger#error "lvalue in function call";
Llvm.build_load acc_var name_var llvm_builder
| _ ->
begin
logger#trace "Access to first element of the array";
let first_pos = Llvm.const_int gen_int_type 0 in
Llvm.build_in_bounds_gep acc_var (Array.of_list [first_pos; first_pos]) name_var llvm_builder
end
with Not_found -> failwith "Variable not found"
end
| _ ->
begin
let acc_var = translate_acc_var access llvm_builder in
Llvm.build_load acc_var "" llvm_builder
How I translate the access variable in the function
and translate_acc_var acc_def llvm_builder =
match acc_def.node with
| Ast.AccVar(id) ->
begin
logger#trace "Access variable with id %s ...." id;
try (<-<) id
with Not_found -> failwith "Variable not found"
end
| AccIndex(acc, index) ->
begin
let variable = translate_acc_var acc llvm_builder in
let index_exp = translate_exp_to_llvm index llvm_builder in
let zeros_pos = Llvm.const_int gen_int_type 0 in
Llvm.build_in_bounds_gep variable (Array.of_list([zeros_pos; index_exp])) "" llvm_builder
end
| AccDeref (expr) as node->
begin
logger#debug "* *%s * Translating ..." (show_access_node node);
let llval = translate_exp_to_llvm expr llvm_builder in
let val_name = Llvm.value_name llval in
let type_val = Llvm.type_of llval in
Llvm.build_ptrtoint llval type_val val_name llvm_builder
end
| _ -> failwith "Access var not implemented"
Where the AST is formed with the following rules
type typ =
| TypInt (* Type int *)
| TypBool (* Type bool *)
| TypChar (* Type char *)
| TypArray of typ * int option (* Array type *)
| TypPoint of typ (* Pointer type *)
| TypVoid (* Type void *)
[@@deriving show]
and expr = expr_node annotated_node
and expr_node =
| Access of access (* x or *p or a[e] *)
| Assign of access * expr (* x=e or *p=e or a[e]=e *)
| Addr of access (* &x or &*p or &a[e] *)
| ILiteral of int (* Integer literal *)
| CLiteral of char (* Char literal *)
| BLiteral of bool (* Bool literal *)
| UnaryOp of uop * expr (* Unary primitive operator *)
| BinaryOp of binop * expr * expr (* Binary primitive operator *)
| Call of identifier * expr list (* Function call f(...) *)
[@@deriving show]
and access = access_node annotated_node
and access_node =
| AccVar of identifier (* Variable access x *)
| AccDeref of expr (* Pointer dereferencing *p *)
| AccIndex of access * expr (* Array indexing a[e] *)
[@@deriving show]
With an introduction of a logger, I get the last value before to call the getelementptr inbounds
The value that I have at the moment are
[0.042 Trace CodeGen ] Variable -> %2 = load i32*, i32** %a
[0.042 Trace CodeGen ] index -> %3 = load i32, i32* %index
variablerefer to thealloca, the result ofloading theallocaor something else (such as%0for example)? Same question forindex. And then I'm assuming you're using the GEP as an operand tostore?LLVM_ENABLE_ASSERTIONSto true.