Улучшение лямбда-кода OCaml генерирует для утверждений

Я хотел бы улучшить лямбда-код, сгенерированный для конструкции "assert" OCaml 3.12.1. Вот пример:

let f x =
    assert (x = 4);
    assert (2 + x = 6);
    assert (x - x = 0);
    exit x

Файл longfilename.ml, приведенный выше, является представителем больших модулей OCaml, для которых я хотел бы улучшить генерацию лямбда-кода. Он компилируется в:

$ ocamlopt -S longfilename.ml
$ cat longfilename.s
...
    .data
    .quad   3072
_camlLongfilename__2:
    .quad   L100007
    .quad   9
    .quad   9
    .quad   2300
L100007: .L100007:
    .ascii  "longfilename.ml"
    .byte   0
    .data
    .quad   3072
_camlLongfilename__3:
    .quad   L100006
    .quad   7
    .quad   9
    .quad   2300
L100006: .L100006:
    .ascii  "longfilename.ml"
    .byte   0
    .data
    .quad   3072
_camlLongfilename__4:
    .quad   L100005
    .quad   5
    .quad   9
    .quad   2300
L100005: .L100005:
    .ascii  "longfilename.ml"
    .byte   0
...

Вышеупомянутое ужасно избыточно. Имя исходного файла, из которого может исходить каждое утверждение, дублируется. Похоже, что виновником является bytecomp/translcore.ml:

let assert_failed loc =
  (* [Location.get_pos_info] is too expensive *)
  let fname = match loc.Location.loc_start.Lexing.pos_fname with
              | "" -> !Location.input_name
              | x -> x
  in
  let pos = loc.Location.loc_start in
  let line = pos.Lexing.pos_lnum in
  let char = pos.Lexing.pos_cnum - pos.Lexing.pos_bol in
  Lprim(Praise, [Lprim(Pmakeblock(0, Immutable),
          [transl_path Predef.path_assert_failure;
           Lconst(Const_block(0,
              [Const_base(Const_string fname);
               Const_base(Const_int line);
               Const_base(Const_int char)]))])])
;;

На первый взгляд, похоже, этого было бы достаточно, чтобы дать имя Const_base(Const_string fname), а для хранения и повторного использования хэш-таблицу времени компиляции. Для внутримодульной оптимизации, изменения просто могут быть управляемы (пока хэш-таблица reset в каждом блоке компиляции).

Я немного из глубины здесь, особенно "reset на каждой компиляции единица ". Любой намек?

Ответ 1

В компиляторе OCaml уже существует механизм для обмена некоторыми константами: см. asmcomp/compilenv.ml и его использование, в частности значения structured_constants, в asmcomp/cmmgen.ml. Я не знаком с этим кодом, поэтому не знаю, почему ваш конкретный вариант использования не является общим, но похоже, что существует разница между лямбда-кодом, Const_base (Const_string foo) и Const_immstring foo; более поздние являются общими, и, возможно, первые не являются.

Я не знаю, что подразумеваемая семантика для immstring. Кажется, он используется компилятором для компиляции меток метода (bytecomp/translclass.ml), но не подвергается языку ввода.

(Я подозреваю, что это различие состоит в том, что строки изменяемы, поэтому совместное использование видимых пользователем строк будет наблюдаемым и изменяет поведение программ. Но строковые константы уже сняты лямбда, так что пользователи уже могут наблюдать семантически несогласованный обмен. видимые строки, вероятно, все еще будут отвергнуты как разрыв совместимости.)

Рассматривая, как эти непосредственные строки обрабатываются постоянным испускающим кодом (asmcomp/cmmgen.ml:emit_constant), они представляются как обычные строки, поэтому, возможно, вы можете просто исправить компилятор, чтобы использовать immstring в assert_failed и все будет работать.

[EDIT BY OP]

Изменение Const_base (Const_string fname) на Const_immstring fname, хотя и немного несовместимо, позволяет OCaml скомпилировать себя, скомпилировать Frama-C, а новый Frama-C передает свои регрессионные тесты. В исходном примере эффект следующий: это был желаемый результат:

$ cat longfilename.s 
...
    .data
    .quad   3072
_camlLongfilename__2:
    .quad   L100005
    .quad   9
    .quad   9
    .data
    .quad   3072
_camlLongfilename__3:
    .quad   L100005
    .quad   7
    .quad   9
    .data
    .quad   3072
_camlLongfilename__4:
    .quad   L100005
    .quad   5
    .quad   9
    .quad   2300
L100005: .L100005:
    .ascii  "longfilename.ml"
    .byte   0