1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
(** Copyright 2025-2026, Victoria Ostrovskaya & Danil Usoltsev *)

(** SPDX-License-Identifier: LGPL-3.0-or-later *)

open Llvm

module Llvm_backend = struct
  type instr =
    | Add of llvalue * llvalue * string
    | Sub of llvalue * llvalue * string
    | Mul of llvalue * llvalue * string
    | Sdiv of llvalue * llvalue * string
    | Neg of llvalue * string
    | Icmp of Icmp.t * llvalue * llvalue * string
    | And of llvalue * llvalue * string
    | Or of llvalue * llvalue * string
    | Not of llvalue * string
    | Load of lltype * llvalue * string
    | Store of llvalue * llvalue
    | Alloca of lltype * string
    | Call of lltype * llvalue * llvalue array * string
    | Ret of llvalue option
    | Br of llbasicblock
    | CondBr of llvalue * llbasicblock * llbasicblock
    | Phi of (llvalue * llbasicblock) list * string
    | Bitcast of llvalue * lltype * string
    | PtrToInt of llvalue * lltype * string
    | IntToPtr of llvalue * lltype * string

  let emit builder = function
    | Add (left, right, name) -> Some (build_add left right name builder)
    | Sub (left, right, name) -> Some (build_sub left right name builder)
    | Mul (left, right, name) -> Some (build_mul left right name builder)
    | Sdiv (left, right, name) -> Some (build_sdiv left right name builder)
    | Neg (operand, name) -> Some (build_neg operand name builder)
    | Icmp (cond, left, right, name) -> Some (build_icmp cond left right name builder)
    | And (left, right, name) -> Some (build_and left right name builder)
    | Or (left, right, name) -> Some (build_or left right name builder)
    | Not (operand, name) -> Some (build_not operand name builder)
    | Load (load_ty, ptr_value, name) -> Some (build_load load_ty ptr_value name builder)
    | Store (value, ptr_value) ->
      let (_ : Llvm.llvalue) = build_store value ptr_value builder in
      None
    | Alloca (alloca_ty, name) -> Some (build_alloca alloca_ty name builder)
    | Call (ft, callee, args, name) -> Some (build_call ft callee args name builder)
    | Ret None ->
      let (_ : Llvm.llvalue) = build_ret_void builder in
      None
    | Ret (Some ret_value) ->
      let (_ : Llvm.llvalue) = build_ret ret_value builder in
      None
    | Br block ->
      let (_ : Llvm.llvalue) = build_br block builder in
      None
    | CondBr (cond, then_bb, else_bb) ->
      let (_ : Llvm.llvalue) = build_cond_br cond then_bb else_bb builder in
      None
    | Phi (incoming, name) -> Some (build_phi incoming name builder)
    | Bitcast (operand, dest_ty, name) ->
      Some (build_bitcast operand dest_ty name builder)
    | PtrToInt (operand, dest_ty, name) ->
      Some (build_ptrtoint operand dest_ty name builder)
    | IntToPtr (operand, dest_ty, name) ->
      Some (build_inttoptr operand dest_ty name builder)
  ;;

  let add builder left right name = emit builder (Add (left, right, name))
  let sub builder left right name = emit builder (Sub (left, right, name))
  let mul builder left right name = emit builder (Mul (left, right, name))
  let sdiv builder left right name = emit builder (Sdiv (left, right, name))
  let neg builder operand name = emit builder (Neg (operand, name))
  let icmp builder cond left right name = emit builder (Icmp (cond, left, right, name))
  let and_ builder left right name = emit builder (And (left, right, name))
  let or_ builder left right name = emit builder (Or (left, right, name))
  let not builder operand name = emit builder (Not (operand, name))
  let load builder load_ty ptr_value name = emit builder (Load (load_ty, ptr_value, name))
  let alloca builder alloca_ty name = emit builder (Alloca (alloca_ty, name))
  let call builder ft callee args name = emit builder (Call (ft, callee, args, name))
  let phi builder incoming name = emit builder (Phi (incoming, name))

  let bitcast builder operand dest_ty name =
    emit builder (Bitcast (operand, dest_ty, name))
  ;;

  let ptrtoint builder operand dest_ty name =
    emit builder (PtrToInt (operand, dest_ty, name))
  ;;

  let inttoptr builder operand dest_ty name =
    emit builder (IntToPtr (operand, dest_ty, name))
  ;;

  let store builder value ptr_value =
    let (_ : Llvm.llvalue option) = emit builder (Store (value, ptr_value)) in
    ()
  ;;

  let ret_void builder =
    let (_ : Llvm.llvalue option) = emit builder (Ret None) in
    ()
  ;;

  let ret builder ret_value =
    let (_ : Llvm.llvalue option) = emit builder (Ret (Some ret_value)) in
    ()
  ;;

  let br builder block =
    let (_ : Llvm.llvalue option) = emit builder (Br block) in
    ()
  ;;

  let cond_br builder cond then_bb else_bb =
    let (_ : Llvm.llvalue option) = emit builder (CondBr (cond, then_bb, else_bb)) in
    ()
  ;;
end