Viewing generated assembly from OCaml source files

When trying to about the performance of my programs or the overhead of various design decisions (for example, choosing a immutable vs mutable representation of data), I often find that I don’t have a clear mental model of how compiler optimizations will affect the assembly will actually be generated.

While for small programs it would be fairly simple to manually run ocamlopt myself to verify my intuition, when I’m working on a larger project with several dependencies using dune, in order to compile the project, I would need the same flags that dune uses when building.

I’ve somewhat managed to achieve this with the hacky decompile script below (here with error-handling), but this is somewhat brittle.

Is there a more systematic and robust way of achieving this?

Note: I’ve tried passing the -S flag via link_flags in the dune file, but I think dune seems to delete the generated file automatically.

FILE=${1?File to be decompiled}

BASENAME=$(basename "${FILE%.*}")
DIRNAME=$(dirname "${FILE%.*}")
TARGETNAME="${DIRNAME}/${BASENAME}.s"

# run dune with verbose and copy last output
BUILD_COMMAND=$(dune clean && dune build --verbose 2>&1 | tail -n1)

# retrieve build directory from output
BUILD_DIR=$(echo $BUILD_COMMAND | grep ocamlopt | sed 's/.*(cd \(.*\) && .*/\1/')

ML_FILES=$(find . -type f -name '*.ml' | grep -v _build/default)
SORTED_ML_FILES=$(ocamldep -sort $ML_FILES)

# run ocamlopt with flags from dune, but set it up to output assembly file and only compile selected file
COMPILE_COMMAND=$(echo $BUILD_COMMAND | sed "s/.*:\(.*\))/\1 -S /")
eval "$COMPILE_COMMAND ${SORTED_ML_FILES})"

OUTPUT_FILE="$BUILD_DIR/$TARGETNAME"
cat  "$OUTPUT_FILE"
1 Like

I think this should work if you add the flag to (ocamlopt_flags ...) instead of (link_flags ...). The asm files will be generated inside the _build subdirectory (in the same place where the .cmx files are generated).

Cheers,
Nicolas

Alas, that was a mistake on my part, checking my dune files again, I meant ocamlopt_flags rather than link_flags. Even when passing the -S flag nothing seems to turn up.

For reference, here is a dune file I tried it out on:

(executable
 (name main)
 (libraries containers react)
 (ocamlopt_flags -S))

but the _build/default subdirectory only had the project files and the executable - no generated assembly files or any other intermediate files.

dune stores its compilation artifacts in specific subdirectories. For your example dune file this means you should look in _build/default/.main.eobjs/native. This directory will contain the .cmx files and also the assembly files if you are passing -S.

Cheers,
Nicolas

1 Like

Aha - the generated assembly files were indeed there - thanks!

I didn’t realize dune stores the build artifacts elsewhere, this is very useful.