The code below has a superfluous ()
expression. Is this perhaps optimized away (i.e removed) by the OCaml compiler (ocamlopt.opt) ?
let () =
();
print_string "hello";
The code below has a superfluous ()
expression. Is this perhaps optimized away (i.e removed) by the OCaml compiler (ocamlopt.opt) ?
let () =
();
print_string "hello";
This is indeed optimised away by the compiler. You can see that by using some options to dump the intermediate representations used by the compiler:
$ ocamlopt -c -dcmm tmp/unit.ml -dlambda
(let (*match*/269 = (seq 0 (apply (field 41 (global Stdlib!)) "hello")))
(makeblock 0))
cmm:
(data)
(data global "camlUnit__gc_roots" "camlUnit__gc_roots": int 0)
(data int 768 global "camlUnit" "camlUnit":)
(data
int 2044
global "camlUnit__const_immstring_4"
"camlUnit__const_immstring_4":
string "hello"
skip 2
byte 2)
(function camlUnit__entry ()
(app{tmp/unit.ml:3,2-22;stdlib.ml:487,21-43} "camlStdlib__output_string_763"
(load_mut val "camlStdlib__Pccall_1851") "camlUnit__const_immstring_4"
unit)
1)
(data)
In this case you can see that in the lambda
representation, there is a the seq 0 (....)
, which correspond to the ();
in your example.
When you look at the cmm code generated for the entry point of the module (i.e. its initialisation code), you see:
(function camlUnit__entry ()
(app{tmp/unit.ml:3,2-22;stdlib.ml:487,21-43} "camlStdlib__output_string_763"
(load_mut val "camlStdlib__Pccall_1851") "camlUnit__const_immstring_4"
unit)
1)
Where the code directly calls the output_string
function from the stdlib (this is because the call to print_string
has been inlined, indeed, if you look at the definition of print_string
in the stdlib.ml
file from the compiler distribution, you see: let print_string s = output_string stdout s
). In any case, you can see that there is nothing before that call, which means the seq 0 (...)
from the lambda code has been optimized away.
The lambda representation I get using the same way seems to be different:
let () =
();
print_string "Hello";
The result is:
λ ~/Workspace/Demo/ ocamlopt -c -dcmm demo.ml -dlambda
(seq
(let
(*match*/269 = (seq 0 (apply (field_imm 41 (global Stdlib!)) "Hello")))
0)
0)
cmm:
(data)
(data int 768 global "camlDemo" "camlDemo":)
(data
global "camlDemo__gc_roots"
"camlDemo__gc_roots":
addr "camlDemo"
int 0)
(data int 2044 "camlDemo__1": string "Hello" skip 2 byte 2)
(function camlDemo__entry ()
(let
*match*/269
(seq []
(app{stdlib.ml:485,21-43} "camlStdlib__output_string_248"
(load_mut val (+a "camlStdlib" 304)) "camlDemo__1" val))
[])
1)
(data)
I am using ocaml5.0.0
compiler on linux
Interesting ! For the record, I used a 4.14.0
compiler for the above, I’ll look at what happens with a 5.0
compiler.
Note: it is much easier to read the intermediate representation of functions than of top-level expressions, so you should put the code you care about in a function. (If anything, you can grep the function name to find the right place.)
I suspect the difference is that one of them was compiled with flambda and not the other. The first one (from @zozozo) looks like it was compiled with flambda, while the second one (from @Muqiu-Han) looks like it was compiled without flambda.
I switched to 4.14.0 and got the same result, I think maybe it’s true as @vlaviron said, I didn’t compile with Flambda. But I use the same compile parameters as you:
λ ~/Workspace/Demo/ ocaml --version
The OCaml toplevel, version 4.14.0
λ ~/Workspace/Demo/ ocamlopt -c -dcmm demo.ml -dlambda
(seq
(let (*match*/268 = (seq 0 (apply (field 41 (global Stdlib!)) "Hello"))) 0)
0)
cmm:
(data)
(data int 768 global "camlDemo" "camlDemo":)
(data
global "camlDemo__gc_roots"
"camlDemo__gc_roots":
addr "camlDemo"
int 0)
(data int 2044 "camlDemo__1": string "Hello" skip 2 byte 2)
(function camlDemo__entry ()
(let
*match*/268
(seq []
(app{stdlib.ml:487,21-43} "camlStdlib__output_string_250"
(load_mut val (+a "camlStdlib" 304)) "camlDemo__1" val))
[])
1)
(data)
Yes, you are right! I need to install ocaml-option-flambda
to enable flambda compilation, otherwise -dlambda will not take effect, After I installed it for ocaml5.0.0, the result is the same as @zozozo!
λ ~/Workspace/Demo/ ocamlopt -c -dcmm demo.ml -dlambda
(let (*match*/270 = (seq 0 (apply (field_imm 41 (global Stdlib!)) "Hello")))
(makeblock 0))
cmm:
(data)
(data global "camlDemo__gc_roots" "camlDemo__gc_roots": int 0)
(data int 768 global "camlDemo" "camlDemo":)
(data
int 2044
global "camlDemo__const_immstring_4"
"camlDemo__const_immstring_4":
string "Hello"
skip 2
byte 2)
(function camlDemo__entry ()
(app{demo.ml:3,2-22;stdlib.ml:485,21-43} "camlStdlib__output_string_766"
(load_mut val "camlStdlib__Pccall_1834") "camlDemo__const_immstring_4"
unit)
1)
(data)
λ ~/Workspace/Demo/ ocamlopt --version
5.0.0
λ ~/Workspace/Demo/ opam install ocaml-option-flambda
[NOTE] Package ocaml-option-flambda is already installed (current version is 1).
Note that the superfluos ()
is also optimized away without Flambda, but the optimization takes place after the generation of C–, so it is not visible when using -dcmm
.
Cheers,
Nicolas
(-dlinear
for example shows the ()
gone away.)