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
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)

open Bos
open Syntax

(* TODO: refactor to re-use code in Cmd_c.ml *)
let c_files_location = List.map Fpath.v Share.Sites.c_files

let find location file : Fpath.t Result.t =
  let* l =
    list_map
      (fun dir ->
        let filename = Fpath.append dir file in
        match OS.File.exists filename with
        | Ok true -> Ok (Some filename)
        | Ok false -> Ok None
        | Error (`Msg msg) -> Error (`Msg msg) )
      location
  in
  let rec loop = function
    | [] -> Error (`Msg (Fmt.str "can't find file %a" Fpath.pp file))
    | None :: tl -> loop tl
    | Some file :: _tl -> Ok file
  in
  loop l

let compile ~includes ~opt_lvl debug (files : Fpath.t list) : Fpath.t Result.t =
  let* clangpp_bin = OS.Cmd.resolve @@ Cmd.v "clang++" in
  let opt_lvl = Fmt.str "-O%s" opt_lvl in

  let includes = Cmd.of_list ~slip:"-I" (List.map Cmd.p includes) in

  let clang_cmd : Cmd.t =
    Cmd.(
      clangpp_bin % "-Wno-everything" % opt_lvl % "-emit-llvm"
      % "--target=wasm32" % "-m32" % "-c" %% includes
      %% Cmd.of_list (List.map Cmd.p files) )
  in

  let* () =
    match OS.Cmd.run clang_cmd with
    | Ok _ as v -> v
    | Error (`Msg e) ->
      Error
        (`Msg
           (Fmt.str "clang++ failed: %s"
              ( if debug then e
                else "run with --debug to get the full error message" ) ) )
  in

  let* llc_bin = OS.Cmd.resolve @@ Cmd.v "llc" in

  let files_bc =
    Cmd.of_list @@ List.map (fun file -> Cmd.p Fpath.(file -+ ".bc")) files
  in

  let llc_cmd : Cmd.t =
    Cmd.(
      llc_bin
      %
      (* TODO: configure this ? *)
      "-O0" % "-march=wasm32" % "-filetype=obj" %% files_bc )
  in

  let* () =
    match OS.Cmd.run llc_cmd with
    | Ok _ as v -> v
    | Error (`Msg e) ->
      Error
        (`Msg
           (Fmt.str "llc failed: %s"
              ( if debug then e
                else "run with --debug to get the full error message" ) ) )
  in
  let* wasmld_bin = OS.Cmd.resolve @@ Cmd.v "wasm-ld" in

  let files_o =
    Cmd.of_list @@ List.map (fun file -> Cmd.p Fpath.(file -+ ".o")) files
  in

  let out = Fpath.v "a.out.wasm" in

  let* binc = find c_files_location (Fpath.v "libc.wasm") in
  let wasmld_cmd : Cmd.t =
    Cmd.(
      wasmld_bin % "-z" % "stack-size=8388608" % "--export=main"
      % "--entry=main" %% files_o % p binc % "-o" % p out )
  in

  let* () =
    match OS.Cmd.run wasmld_cmd with
    | Ok _ as v -> v
    | Error (`Msg e) ->
      Error
        (`Msg
           (Fmt.str "wasm-ld failed: %s"
              ( if debug then e
                else "run with --debug to get the full error message" ) ) )
  in

  Ok out

let cmd ~debug ~arch:_ ~workers ~opt_lvl ~includes ~files ~profiling ~unsafe
  ~optimize ~no_stop_at_failure ~no_value ~no_assert_failure_expression_printing
  ~deterministic_result_order ~fail_mode ~concolic ~solver ~profile :
  unit Result.t =
  let includes = c_files_location @ includes in
  let* modul = compile ~includes ~opt_lvl debug files in
  let files = [ modul ] in
  (if concolic then Cmd_conc.cmd else Cmd_sym.cmd)
    ~profiling ~debug ~unsafe ~rac:false ~srac:false ~optimize ~workers
    ~no_stop_at_failure ~no_value ~no_assert_failure_expression_printing
    ~deterministic_result_order ~fail_mode ~workspace:(Fpath.v "owi-out")
    ~solver ~files ~profile