docs/runtime/compiler-ir.md
Enso IR, currently implemented in Scala, with base class
org.enso.compiler.core.IR, is created from the output of the native
parser. The IR is an immutable annotated AST subjected to
multiple passes. Every pass is a class implementing the
org.enso.compiler.pass.IRPass interface.
See Runtime roadmap - static analysis for future goals.
If org.enso.compiler.data.CompilerConfig#isLintingDisabled is false, various
additional linting compiler passes are enabled in org.enso.compiler.Passes.
Such passes usually generate warnings, for example, about an unused local
binding. In production (when running the engine from the language-server),
linting is disabled.
Automatic removal of unused imports can be enabled with
enso.compiler.RemoveUnusedImports system property. To remove unused imports
from the whole Standard.Base, run:
enso --no-compile-dependencies --no-ir-caches --vm.D enso.compiler.RemoveUnusedImports --compile distribution/lib/Standard/Base/0.0.0-dev/
Note that to properly dump module from standard library, it is recommended to run with --no-ir-caches.
The IR can be visualized using the enso.compiler.dumpIr system property. The
property value has format <module-name>[:<dump-level>], where module-name is
a substring of a module to dump and dump-level is an optional integer which
can be:
1 ... the default value.
2 ... Does not chain mini passes. By default, mini passes are chained into
a bigger mega pass. Use this if you want to see IR transformation done by all
mini passes.
IRs are dumped into the IGV tool in a similar way to how GraalVM graphs are dumped, which is documented in enso4igv.
When using the enso.compiler.dumpIr property, one has to add
--add-exports jdk.graal.compiler/jdk.graal.compiler.graphio=org.enso.runtime.compiler.dump.igv
to the JAVA_TOOL_OPTIONS env var, because the IGV dumper uses an internal
package of GraalVM JDK's module which is not exported by default.
Usage example:
$ env JAVA_TOOL_OPTIONS='--add-exports=jdk.graal.compiler/jdk.graal.compiler.graphio=org.enso.runtime.compiler.dump.igv -Denso.compiler.dumpIr=Vector' ./built-distribution/*/bin/enso --no-ir-caches --run tmp.enso
The IR graphs are dumped directly to IGV, if it is running, or to the ir-dumps
directory in the
BGV
format.
For a module, multiple graphs are dumped. Names of the graphs correspond to the names of the Compiler passes, as can be seen on the screenshot:
Opening the first graph for the Vector module is overwhelming, since it has
more than 3000 nodes:
However, nodes are structured in blocks. Blocks can be seen on the right side
in the Control Flow tool window.
Zoom into a particular block:
Control Flow tool window.Zoom to Selection button in the toolbar.
Below the tab, there are all the passes displayed as points (Phase toolbar). Hovering over a point shows the pass name:
Click-and-drag the mouse to select a region of passes. This will display the
difference in the graph between those passes. In the following screenshot, we
can see the difference between the very first pass, and MethodCalls pass:
Orange nodes represent those with changed properties.
Clicking on a single changed node, we can see that there is NEW_passData
property:
In this case, we can see that AliasMetadata.ChildScope passData was added to
that node between the selected passes.
In the following screenshot, we can see that the 8 Function$Lambda node was
removed (displayed in red) between passes 15: AliasAnalysis and
18: SuspendedArguments:
Nodes that were added are displayed in green.
Clicking on a single node, the points representing passes in the Phase toolbar change colors: