Llvm 生成 IR 分段错误(core dumped)

时间:2021-01-19 00:21:34

标签: llvm llvm-ir

我试图传递一个数组作为参数,并在另一个函数中使用这个数组,并使用像 C 这样的玩具语言。

当我编译以下代码时,我的代码运行和编译良好

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;
}

我的编译器生成以下 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
}

但是如果我尝试在函数中使用数组 an 我会收到来自编译器的核心转储,我的核心转储演示是

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;
}

我开始调试代码但我找不到错误,也许我从代码中访问数组是错误的。

我访问数组的一般代码是使用 Ocaml 调用以下 LLVM API

我从 AST 收到一个节点,其变量为 access operationindex 为我调用以下 API。

Llvm.build_in_bounds_gep variable [0, index] "access" llvm_builder

有了这个调用的结果,我对变量进行了所有操作,但我认为函数体的情况,当数组作为参数时,我的变量是一个指针,因此,我收到错误,但这是我的想法,这是我卡住的地方,有什么想法吗?需要做一些额外的操作来访问作为参数的数组吗?

更新

我生成函数调用的代码部分是。

在函数声明中生成分配和存储的规则

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

在函数调用期间我如何翻译参数,例如:为 int array[] 创建一个指针并为 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

我如何翻译函数中的访问变量

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"

AST 的形成方式如下

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]

随着记录器的引入,我在调用 getelementptr inbounds

之前获得了最后一个值

我现在的价值是

[0.042  Trace      CodeGen              ] Variable ->   %2 = load i32*, i32** %a
[0.042  Trace      CodeGen              ] index ->   %3 = load i32, i32* %index

1 个答案:

答案 0 :(得分:2)

查看您的代码,它看起来像 variable 指的是 %aalloca 类型为 i32**,而 index 指的是 %indexalloca 类型的 %i32。这引入了两个问题:

  1. GEP 只是地址计算 - 它不会取消引用任何内容。因此,您不能使用它来通过这样的双指针。您需要先使用 alloca 取消引用 load,然后在 GEP 中使用加载结果。然后,您还应该删除 0,因为在 load 之后只有一个指针,只需要一个索引。
  2. GEP 中的索引必须是整数,而不是指向整数的指针。同样,您需要load 索引并使用 GEP 中的加载结果。