English version
Accueil     À propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Browse thread
Compiler bug with bigarray
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2009-11-05 (02:01)
From: Goswin von Brederlow <goswin-v-b@w...>
Subject: Compiler bug with bigarray

I just finished adding a (int, int31_elt) Bigarray.kind for 4 byte
taged integers independent of the architecture to Bigarray. While
testing it I noticed that the generated assembler consists of this:

open Bigarray
let get_foo (a : (int, int31_elt, c_layout) Array1.t) x = Array1.unsafe_get a x
let get_bar (a : (int, int, c_layout) Array1.t) x = Array1.unsafe_get a x

0000000000404aa0 <camlTest__get_foo_127>:
  404aa0:       48 d1 fb                sar    %rbx
  404aa3:       48 8b 40 08             mov    0x8(%rax),%rax
  404aa7:       48 63 04 98             movslq (%rax,%rbx,4),%rax
  404aab:       48 d1 e0                shl    %rax
  404aae:       48 83 c8 01             or     $0x1,%rax
  404ab2:       c3                      retq   
  404ab3:       66 66 66 66 2e 0f 1f    nopw   %cs:0x0(%rax,%rax,1)
  404aba:       84 00 00 00 00 00 

0000000000404ac0 <camlTest__get_bar_130>:
  404ac0:       48 83 ec 08             sub    $0x8,%rsp
  404ac4:       48 89 c7                mov    %rax,%rdi
  404ac7:       48 89 de                mov    %rbx,%rsi
  404aca:       48 8b 05 bf af 21 00    mov    0x21afbf(%rip),%rax        # 61fa90 <_DYNAMIC+0x790>
  404ad1:       e8 7a 27 01 00          callq  417250 <caml_c_call>
  404ad6:       48 83 c4 08             add    $0x8,%rsp
  404ada:       c3                      retq   
  404adb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

As you can see in get_foo the compiler optimizes and inlines the
memory access directly. In get_bar on the other hand this optimization
fails and the generic bigarray get function is invoked as caml_c_call.

Looking at my patch for int31 I could not figure out any difference
that would explain this behaviour of the compiler. So I added a few
Printf.printf to see what the compiler does.

In the (int, int31) case the compiler ends up in cmmgen.ml: transl in the
case for

      | (Pbigarrayref(unsafe, num_dims, elt_kind, layout), arg1 ::
argl) ->
          let elt =
            bigarray_get unsafe elt_kind layout
              (transl arg1) (List.map transl argl) dbg in
          begin match elt_kind with
          | Pbigarray_int31 -> Printf.printf "Pbigarray_int31\n"; force_tag_int elt
          | Pbigarray_caml_int -> Printf.printf "Pbigarray_caml_int\n"; force_tag_int elt

In the (int, int) case the compiler never reaches that point. Instead
it ends up in cmmgen.ml: simplif_primitive

let simplif_primitive p =
  match p with
  | Pbigarrayref(unsafe, n, Pbigarray_unknown, layout) ->
      Printf.printf "caml_ba_get_ for Pbigarray_unknown\n";
      Pccall (default_prim ("caml_ba_get_" ^ string_of_int n))

So something is horribly wrong here. This should contain

   Pbigarrayref(unsafe, n, Pbigarray_caml_int, layout)

Somewhere during compilation the wrong Pbigarrayref gets created for
an (int, int, c_layout) Bigarray.Array1.t. It is created as unknown /
polymorphic ('a, 'b, 'c) Bigarray.Array1.t. The knowledge that it is
(int, int, c_layout) Bigarray.Array1.t is lost or never added to the
type and I am at a loss where that type is created at all. I tried
adding some more Printf.printf lines in places where Pbigarrayref gets
created but none of them get triggered.

So does anyone know where the Pbigarrayref gets created during
compilation and why it remains Pbigarray_unknown? The same problem
arises for Pbigarray_int32, Pbigarray_int64 and Pbigarray_native_int.
All three of which look like they should get optimized on 64bit or at
least keep their type information.


PS: This is debians ocaml 3.11.1-3