aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/main
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/hipe/main
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/hipe/main')
-rw-r--r--lib/hipe/main/Makefile117
-rw-r--r--lib/hipe/main/hipe.app.src222
-rw-r--r--lib/hipe/main/hipe.appup.src19
-rw-r--r--lib/hipe/main/hipe.erl1555
-rw-r--r--lib/hipe/main/hipe.hrl.src322
-rw-r--r--lib/hipe/main/hipe_main.erl549
6 files changed, 2784 insertions, 0 deletions
diff --git a/lib/hipe/main/Makefile b/lib/hipe/main/Makefile
new file mode 100644
index 0000000000..0ac522b1b2
--- /dev/null
+++ b/lib/hipe/main/Makefile
@@ -0,0 +1,117 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+ifndef EBIN
+EBIN = ../ebin
+endif
+
+ifndef DOCS
+DOCS = ../doc
+endif
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(HIPE_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+ifdef HIPE_ENABLED
+HIPE_MODULES = hipe
+else
+HIPE_MODULES =
+endif
+MODULES = hipe_main $(HIPE_MODULES)
+
+## hipe.hrl is automatically generated from hipe.hrl.src -- see below
+HRL_FILES= hipe.hrl
+ERL_FILES= $(MODULES:%=%.erl)
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
+DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
+
+APP_FILE= hipe.app
+APP_SRC= $(APP_FILE).src
+APP_TARGET= $(EBIN)/$(APP_FILE)
+
+APPUP_FILE= hipe.appup
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+include ../native.mk
+
+ERL_COMPILE_FLAGS += +nowarn_shadow_vars +warn_missing_spec +warn_untyped_record
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+hipe.hrl: ../vsn.mk hipe.hrl.src
+ sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
+
+$(EBIN)/hipe.beam: hipe.hrl ../../compiler/src/beam_disasm.hrl
+$(EBIN)/hipe_main.beam: hipe.hrl ../icode/hipe_icode.hrl #../rtl/hipe_rtl.hrl
+
+debug opt: $(TARGET_FILES)
+
+docs: $(DOC_FILES)
+
+clean:
+ rm -f $(TARGET_FILES) $(DOC_FILES) $(HRL_FILES)
+ rm -f core
+
+$(DOCS)/%.html:%.erl
+ erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DATA) ../vsn.mk $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELSYSDIR)/main
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/main
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+
+release_docs_spec:
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
new file mode 100644
index 0000000000..e5d6d1e540
--- /dev/null
+++ b/lib/hipe/main/hipe.app.src
@@ -0,0 +1,222 @@
+%% This is an -*- erlang -*- file.
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+{application, hipe,
+ [{description, "HiPE Native Code Compiler, version %VSN%"},
+ {vsn, "%VSN%"},
+ {modules, [cerl_cconv,
+ cerl_closurean,
+ cerl_hipeify,
+ cerl_hybrid_transform,
+ cerl_lib,
+ cerl_messagean,
+ cerl_pmatch,
+ cerl_prettypr,
+ cerl_to_icode,
+ cerl_typean,
+ erl_bif_types,
+ erl_types,
+ hipe,
+ hipe_adj_list,
+ hipe_amd64_assemble,
+ hipe_amd64_defuse,
+ hipe_amd64_encode,
+ hipe_amd64_frame,
+ hipe_amd64_liveness,
+ hipe_amd64_main,
+ hipe_amd64_pp,
+ hipe_amd64_ra,
+ hipe_amd64_ra_finalise,
+ hipe_amd64_ra_ls,
+ hipe_amd64_ra_naive,
+ hipe_amd64_ra_postconditions,
+ hipe_amd64_ra_sse2_postconditions,
+ hipe_amd64_ra_x87_ls,
+ hipe_amd64_registers,
+ hipe_amd64_specific,
+ hipe_amd64_specific_sse2,
+ hipe_amd64_specific_x87,
+ hipe_amd64_spill_restore,
+ hipe_amd64_x87,
+ hipe_arm,
+ hipe_arm_assemble,
+ hipe_arm_cfg,
+ hipe_arm_defuse,
+ hipe_arm_encode,
+ hipe_arm_finalise,
+ hipe_arm_frame,
+ hipe_arm_liveness_gpr,
+ hipe_arm_main,
+ hipe_arm_pp,
+ hipe_arm_ra,
+ hipe_arm_ra_finalise,
+ hipe_arm_ra_ls,
+ hipe_arm_ra_naive,
+ hipe_arm_ra_postconditions,
+ hipe_arm_registers,
+ hipe_arm_specific,
+ hipe_bb,
+ hipe_beam_to_icode,
+ hipe_ceach,
+ hipe_coalescing_regalloc,
+ hipe_consttab,
+ hipe_data_pp,
+ hipe_digraph,
+ hipe_dominators,
+ hipe_dot,
+ hipe_gen_cfg,
+ hipe_gensym,
+ hipe_graph_coloring_regalloc,
+ hipe_icode,
+ hipe_icode2rtl,
+ hipe_icode_bincomp,
+ hipe_icode_callgraph,
+ hipe_icode_cfg,
+ hipe_icode_coordinator,
+ hipe_icode_ebb,
+ hipe_icode_exceptions,
+ hipe_icode_fp,
+ hipe_icode_heap_test,
+ hipe_icode_inline_bifs,
+ hipe_icode_instruction_counter,
+ hipe_icode_liveness,
+ hipe_icode_mulret,
+ hipe_icode_pp,
+ hipe_icode_primops,
+ hipe_icode_range,
+ hipe_icode_ssa,
+ hipe_icode_ssa_const_prop,
+ hipe_icode_ssa_copy_prop,
+ hipe_icode_ssa_struct_reuse,
+ hipe_icode_split_arith,
+ hipe_icode_type,
+ hipe_ig,
+ hipe_ig_moves,
+ hipe_jit,
+ hipe_ls_regalloc,
+ hipe_main,
+ hipe_moves,
+ hipe_node_sets,
+ hipe_optimistic_regalloc,
+ hipe_pack_constants,
+ hipe_ppc,
+ hipe_ppc_assemble,
+ hipe_ppc_cfg,
+ hipe_ppc_defuse,
+ hipe_ppc_encode,
+ hipe_ppc_finalise,
+ hipe_ppc_frame,
+ hipe_ppc_liveness_all,
+ hipe_ppc_liveness_fpr,
+ hipe_ppc_liveness_gpr,
+ hipe_ppc_main,
+ hipe_ppc_pp,
+ hipe_ppc_ra,
+ hipe_ppc_ra_finalise,
+ hipe_ppc_ra_ls,
+ hipe_ppc_ra_naive,
+ hipe_ppc_ra_postconditions,
+ hipe_ppc_ra_postconditions_fp,
+ hipe_ppc_registers,
+ hipe_ppc_specific,
+ hipe_ppc_specific_fp,
+ hipe_profile,
+ hipe_reg_worklists,
+ hipe_regalloc_loop,
+ hipe_rtl,
+ hipe_rtl_arch,
+ hipe_rtl_arith_32,
+ hipe_rtl_arith_64,
+ hipe_rtl_binary,
+ hipe_rtl_binary_match,
+ hipe_rtl_binary_construct,
+ hipe_rtl_cfg,
+ hipe_rtl_cleanup_const,
+ hipe_rtl_exceptions,
+ hipe_rtl_lcm,
+ hipe_rtl_liveness,
+ hipe_rtl_mk_switch,
+ hipe_rtl_primops,
+ hipe_rtl_ssa,
+ hipe_rtl_ssa_const_prop,
+ hipe_rtl_ssa_avail_expr,
+ hipe_rtl_ssapre,
+ hipe_rtl_symbolic,
+ hipe_rtl_to_amd64,
+ hipe_rtl_to_arm,
+ hipe_rtl_to_ppc,
+ hipe_rtl_to_sparc,
+ hipe_rtl_to_x86,
+ hipe_rtl_varmap,
+ hipe_sdi,
+ hipe_sparc,
+ hipe_sparc_assemble,
+ hipe_sparc_cfg,
+ hipe_sparc_defuse,
+ hipe_sparc_encode,
+ hipe_sparc_finalise,
+ hipe_sparc_frame,
+ hipe_sparc_liveness_all,
+ hipe_sparc_liveness_fpr,
+ hipe_sparc_liveness_gpr,
+ hipe_sparc_main,
+ hipe_sparc_pp,
+ hipe_sparc_ra,
+ hipe_sparc_ra_finalise,
+ hipe_sparc_ra_ls,
+ hipe_sparc_ra_naive,
+ hipe_sparc_ra_postconditions,
+ hipe_sparc_ra_postconditions_fp,
+ hipe_sparc_registers,
+ hipe_sparc_specific,
+ hipe_sparc_specific_fp,
+ hipe_spillcost,
+ hipe_spillmin,
+ hipe_spillmin_color,
+ hipe_spillmin_scan,
+ hipe_tagscheme,
+ hipe_temp_map,
+ hipe_timing,
+ hipe_tool,
+ hipe_vectors,
+ hipe_x86,
+ hipe_x86_assemble,
+ hipe_x86_cfg,
+ hipe_x86_defuse,
+ hipe_x86_encode,
+ hipe_x86_frame,
+ hipe_x86_liveness,
+ hipe_x86_main,
+ hipe_x86_postpass,
+ hipe_x86_pp,
+ hipe_x86_ra,
+ hipe_x86_ra_finalise,
+ hipe_x86_ra_ls,
+ hipe_x86_ra_naive,
+ hipe_x86_ra_postconditions,
+ hipe_x86_ra_x87_ls,
+ hipe_x86_registers,
+ hipe_x86_specific,
+ hipe_x86_specific_x87,
+ hipe_x86_spill_restore,
+ hipe_x86_x87]},
+ {registered,[]},
+ {applications, [kernel,stdlib]},
+ {env, []}]}.
diff --git a/lib/hipe/main/hipe.appup.src b/lib/hipe/main/hipe.appup.src
new file mode 100644
index 0000000000..1d5a0d93f5
--- /dev/null
+++ b/lib/hipe/main/hipe.appup.src
@@ -0,0 +1,19 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+{"%VSN%",[],[]}.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
new file mode 100644
index 0000000000..ed722fecba
--- /dev/null
+++ b/lib/hipe/main/hipe.erl
@@ -0,0 +1,1555 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% ====================================================================
+%% Copyright (c) 1998 by Erik Johansson. All Rights Reserved
+%% ====================================================================
+%% Filename : hipe.erl
+%% Module : hipe
+%% Purpose :
+%% Notes :
+%% History : * 1998-01-28 Erik Johansson ([email protected]): Created.
+%% CVS : $Id$
+%% ====================================================================
+%% @doc This is the direct interface to the HiPE compiler.
+%%
+%% <h3>Normal use</h3>
+%%
+%% <p>The normal way to native-compile an Erlang module using HiPE is to
+%% include the atom <code>native</code> in the Erlang compiler options,
+%% as in:
+%%
+%% <pre> 1> c(my_module, [native]).</pre></p>
+%%
+%% <p>Options to the HiPE compiler are then passed as follows:
+%%
+%% <pre> 1> c(my_module, [native,{hipe,Options}]).</pre></p>
+%%
+%% <p>For on-line help in the Erlang shell, call <a
+%% href="#help-0"><code>hipe:help()</code></a>. Details on HiPE compiler
+%% options are given by <a
+%% href="#help_options-0"><code>hipe:help_options()</code></a>.</p>
+%%
+%% <h3>Using the direct interface - for advanced users only</h3>
+%%
+%% To compile a module or a specific function to native code and
+%% automatically load the code into memory, call <a
+%% href="#c-1"><code>hipe:c(Module)</code></a> or <a
+%% href="#c-2"><code>hipe:c(Module, Options)</code></a>. Note that all
+%% options are specific to the HiPE compiler. See the <a
+%% href="#index">function index</a> for other compiler functions.
+%%
+%% <h3>Main Options</h3>
+%%
+%% Options are processed in the order they appear in the list; an
+%% early option will shadow a later one.
+%% <dl>
+%% <dt><code>o0, 'O0', o1, 'O1', o2, 'O2', o3, 'O3'</code></dt>
+%% <dd>Set optimization level (default 2).</dd>
+%%
+%% <dt><code>load</code></dt>
+%% <dd>Automatically load the code into memory after compiling.</dd>
+%%
+%% <dt><code>time</code></dt>
+%% <dd>Reports the compilation times for the different stages
+%% of the compiler. Call <a
+%% href="#help_option-1"><code>hipe:help_option(time)</code></a> for
+%% details.</dd>
+%%
+%% <dt><code>{timeout, Time}</code></dt>
+%% <dd>Sets the time the compiler is allowed to use for the
+%% compilation. <code>Time</code> is time in ms or the atom
+%% <code>infinity</code> (the default).</dd>
+%%
+%% <dt><code>verbose</code></dt>
+%% <dd>Make the HiPE compiler output information about what it is
+%% being done.</dd>
+%% </dl>
+%%
+%% <h3>Advanced Options</h3>
+%%
+%% Note: You can also specify <code>{Option, false}</code> to turn a
+%% particular option off, or <code>{Option, true}</code> to force it on.
+%% Boolean-valued (<code>true</code>/<code>false</code>) options also
+%% have negative-form aliases, e.g. <code>no_load</code> = <code>{load,
+%% false}</code>.
+%%
+%% <p><dl>
+%% <dt><code>debug</code></dt>
+%% <dd>Outputs internal debugging information during
+%% compilation.</dd>
+%%
+%% <dt><code>icode_ssa_copy_prop</code></dt>
+%% <dd>Performs copy propagation on the SSA form on the Icode
+%% level.</dd>
+%%
+%% <dt><code>icode_ssa_const_prop</code></dt>
+%% <dd>Performs sparse conditional constant propagation on the SSA
+%% form on the Icode level.</dd>
+%%
+%% <dt><code>icode_ssa_struct_reuse</code></dt>
+%% <dd>Tries to factor out identical tuple and list constructions
+%% on the Icode level.</dd>
+%%
+%% <dt><code>icode_type</code></dt>
+%% <dd>Simplifies the code by employing type analysis and propagation
+%% on the Icode level.</dd>
+%%
+%% <dt><code>icode_range</code></dt>
+%% <dd>Performs integer range analysis on the Icode level.</dd>
+%%
+%% <dt><code>pp_all</code></dt>
+%% <dd>Equivalent to <code>[pp_beam, pp_icode, pp_rtl,
+%% pp_native]</code>.</dd>
+%%
+%% <dt><code>pp_asm</code></dt>
+%% <dd>Prints the assembly listing with addresses and bytecode.
+%% Currently available for x86 only.</dd>
+%%
+%% <dt><code>pp_beam, {pp_beam, {file, File}}</code></dt>
+%% <dd>Display the input Beam code to stdout or file.</dd>
+%%
+%% <dt><code>pp_icode, {pp_icode, {file, File}},
+%% {pp_icode, {only, Functions}}</code></dt>
+%% <dd>Pretty-print Icode intermediate code to stdout or file.</dd>
+%%
+%% <dt><code>pp_native, {pp_native, {file, File}},
+%% {pp_native, {only, Functions}}</code></dt>
+%% <dd>Pretty-print native code to stdout or file.</dd>
+%%
+%% <dt><code>pp_opt_icode, {pp_opt_icode, {file, File}},
+%% {pp_opt_icode, {only, Functions}}</code></dt>
+%% <dd>Pretty-print optimized Icode to stdout or file.</dd>
+%%
+%% <dt><code>pp_rtl, {pp_rtl, {file, File}},
+%% {pp_rtl, {only, Functions}}</code></dt>
+%% <dd>Pretty-print RTL intermediate code to stdout or file.</dd>
+%%
+%% <dt><code>regalloc</code></dt>
+%% <dd>Select register allocation algorithm. Used as
+%% <code>{regalloc, Method}</code>.
+%%
+%% <p><code>Method</code> is one of the following:
+%% <ul>
+%% <li><code>naive</code>: spills everything (for debugging and
+%% testing only).</li>
+%% <li><code>linear_scan</code>: fast compilation; not so good if
+%% only few registers available.</li>
+%% <li><code>graph_color</code>: slower, but gives better
+%% performance.</li>
+%% <li><code>coalescing</code>: tries hard to use registers; can be
+%% very slow, but typically results in code with best performance.</li>
+%% </ul></p></dd>
+%%
+%% <dt><code>remove_comments</code></dt>
+%% <dd>Remove comments from intermediate code.</dd>
+%%
+%% <dt><code>rtl_ssa_const_prop</code></dt>
+%% <dd>Performs sparse conditional constant propagation on the SSA
+%% form on the RTL level. </dd>
+%%
+%% <dt><code>rtl_lcm</code></dt>
+%% <dd>Lazy Code Motion on RTL.</dd>
+%%
+%% <dt><code>rtl_ssapre</code></dt>
+%% <dd>Lazy Partial Redundancy Elimination on RTL (SSA level).</dd>
+%%
+%% <dt><code>use_indexing</code></dt>
+%% <dd>Use indexing for multiple-choice branch selection.</dd>
+%%
+%% <dt><code>use_callgraph</code></dt>
+%% <dd>Use a static call graph for determining the order in which
+%% the functions of a module should be compiled (in reversed
+%% topological sort order).</dd>
+%% </dl></p>
+%%
+%% <h3>Debugging Options</h3>
+%% (May require that some modules have been
+%% compiled with the <code>DEBUG</code> flag.)
+%% <dl>
+%% <dt><code>rtl_show_translation</code></dt>
+%% <dd>Prints each step in the translation from Icode to RTL</dd>
+%% </dl>
+%%
+%% @end
+%% ====================================================================
+
+-module(hipe).
+
+-export([c/1,
+ c/2,
+ f/1,
+ f/2,
+ compile/1,
+ compile/2,
+ compile/4,
+ compile_core/4,
+ file/1,
+ file/2,
+ load/1,
+ help/0,
+ help_hiper/0,
+ help_options/0,
+ help_option/1,
+ help_debug_options/0,
+ version/0]).
+
+-ifndef(DEBUG).
+-define(DEBUG,true).
+-endif.
+
+-include("hipe.hrl").
+-include("../../compiler/src/beam_disasm.hrl").
+
+%%-------------------------------------------------------------------
+%% Basic type declaration for exported functions of the 'hipe' module
+%%-------------------------------------------------------------------
+
+-type mod() :: atom().
+-type c_unit() :: mod() | mfa().
+-type f_unit() :: mod() | binary().
+-type ret_rtl() :: [_].
+-type c_ret() :: {'ok', c_unit()} | {'error', term()} |
+ {'ok', c_unit(), ret_rtl()}. %% The last for debugging only
+-type compile_file() :: atom() | string() | binary().
+-type compile_ret() :: {hipe_architecture(), binary()} | list().
+
+%%-------------------------------------------------------------------
+
+-define(COMPILE_DEFAULTS, [o2]).
+-define(DEFAULT_TIMEOUT, infinity).
+
+%%-------------------------------------------------------------------
+
+%% @spec load(Mod) -> {module, Mod} | {error, Reason}
+%% Mod = mod()
+%% Reason = term()
+%%
+%% @doc Like load/2, but tries to locate a BEAM file automatically.
+%%
+%% @see load/2
+
+-spec load(Mod) -> {'module', Mod} | {'error', term()}
+ when is_subtype(Mod, mod()).
+
+load(Mod) ->
+ load(Mod, beam_file(Mod)).
+
+%% @spec load(Mod, BeamFileName) -> {module, Mod} | {error, Reason}
+%% Mod = mod()
+%% Reason = term()
+%% BeamFileName = string()
+%% filename() = term()
+%%
+%% @type mod() = atom(). A module name.
+%%
+%% @doc User interface for loading code into memory. The code can be
+%% given as a native code binary or as the file name of a BEAM file
+%% which should contain a native-code chunk. If only the module name is
+%% given (see <code>load/1</code>), the BEAM file is located
+%% automatically.
+%%
+%% @see load/1
+
+-spec load(Mod, string()) -> {'module', Mod} | {'error', term()}
+ when is_subtype(Mod, mod()).
+
+load(Mod, BeamFileName) when is_list(BeamFileName) ->
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ case beam_lib:chunks(BeamFileName, [ChunkName]) of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> do_load(Mod, Bin, Bin);
+ Error -> {error, Error}
+ end.
+
+%% @spec c(Name) -> {ok, Name} | {error, Reason}
+%% Name = mod() | mfa()
+%% Reason = term()
+%%
+%% @equiv c(Name, [])
+
+-spec c(c_unit()) -> c_ret().
+
+c(Name) ->
+ c(Name, []).
+
+%% @spec c(Name, options()) -> {ok, Name} | {error, Reason}
+%% Name = mod() | mfa()
+%% options() = [option()]
+%% option() = term()
+%% Reason = term()
+%%
+%% @type mfa() = {M::mod(),F::fun(),A::arity()}.
+%% A fully qualified function name.
+%%
+%% @type fun() = atom(). A function identifier.
+%%
+%% @type arity() = integer(). A function arity; always nonnegative.
+%%
+%% @doc User-friendly native code compiler interface. Reads BEAM code
+%% from the corresponding "Module<code>.beam</code>" file in the system
+%% path, and compiles either a single function or the whole module to
+%% native code. By default, the compiled code is loaded directly. See
+%% above for documentation of options.
+%%
+%% @see c/1
+%% @see c/3
+%% @see f/2
+%% @see compile/2
+
+-spec c(c_unit(), comp_options()) -> c_ret().
+
+c(Name, Options) ->
+ c(Name, beam_file(Name), Options).
+
+%% @spec c(Name, File, options()) -> {ok, Name} | {error, Reason}
+%% Name = mod() | mfa()
+%% File = filename() | binary()
+%% Reason = term()
+%%
+%% @doc Like <code>c/2</code>, but reads BEAM code from the specified
+%% <code>File</code>.
+%%
+%% @see c/2
+%% @see f/2
+
+c(Name, File, Opts) ->
+ %% No server if only one function is compiled
+ Opts1 = user_compile_opts(Opts),
+ case compile(Name, File, Opts1) of
+ {ok, Res} ->
+ case proplists:get_bool(to_rtl, Opts1) of
+ true -> {ok, Name, Res};
+ false -> {ok, Name}
+ end;
+ Other ->
+ Other
+ end.
+
+%% @spec f(File) -> {ok, Name} | {error, Reason}
+%% File = filename() | binary()
+%% Name = mod()
+%% Reason = term()
+%%
+%% @equiv f(File, [])
+
+-spec f(f_unit()) -> {'ok', mod()} | {'error', term()}.
+
+f(File) ->
+ f(File, []).
+
+%% @spec f(File, options()) -> {ok, Name} | {error, Reason}
+%% File = filename() | binary()
+%% Name = mod()
+%% Reason = term()
+%%
+%% @doc Like <code>c/3</code>, but takes the module name from the
+%% specified <code>File</code>. This always compiles the whole module;
+%% there is no possibility to compile just a single function.
+%%
+%% @see c/3
+
+-spec f(f_unit(), comp_options()) -> {'ok', mod()} | {'error', term()}.
+
+f(File, Opts) ->
+ case file(File, user_compile_opts(Opts)) of
+ {ok, Name, _} ->
+ {ok, Name};
+ Other ->
+ Other
+ end.
+
+-define(USER_DEFAULTS, [load]).
+
+user_compile_opts(Opts) ->
+ Opts ++ ?USER_DEFAULTS.
+
+
+%% @spec compile(Name) -> {ok, {Target,Binary}} | {error, Reason}
+%% Name = mod() | mfa()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @equiv compile(Name, [])
+
+-spec compile(c_unit()) -> {'ok', compile_ret()} | {'error', term()}.
+
+compile(Name) ->
+ compile(Name, []).
+
+%% @spec compile(Name, options()) -> {ok, {Target,Binary}} | {error, Reason}
+%% Name = mod() | mfa()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @doc Direct compiler interface, for advanced use. This just compiles
+%% the named function or module, reading BEAM code from the
+%% corresponding "Module<code>.beam</code>" file in the system path.
+%% Returns <code>{ok, Binary}</code> if successful, or <code>{error,
+%% Reason}</code> otherwise. By default, it does <em>not</em> load the
+%% binary to memory (the <code>load</code> option can be used to
+%% activate automatic loading). <code>File</code> can be either a file
+%% name or a binary containing the BEAM code for the module.
+%%
+%% @see c/2
+%% @see compile/1
+%% @see compile/3
+%% @see file/2
+%% @see load/2
+
+-spec compile(c_unit(), comp_options()) -> {'ok', compile_ret()} | {'error', _}.
+
+compile(Name, Options) ->
+ compile(Name, beam_file(Name), Options).
+
+-spec beam_file(mod() | mfa()) -> string().
+
+beam_file({M,F,A}) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
+ beam_file(M);
+beam_file(Module) when is_atom(Module) ->
+ case code:which(Module) of
+ non_existing ->
+ ?error_msg("Cannot find ~w.beam file.",[Module]),
+ ?EXIT({cant_find_beam_file,Module});
+ File -> % string()
+ File
+ end.
+
+%% @spec compile(Name, File, options()) ->
+%% {ok, {Target, Binary}} | {error, Reason}
+%% Name = mod() | mfa()
+%% File = filename() | binary()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @doc Like <code>compile/2</code>, but reads BEAM code from the
+%% specified <code>File</code>.
+%%
+%% @see compile/2
+
+-spec compile(c_unit(), compile_file(), comp_options()) ->
+ {'ok', compile_ret()} | {'error', term()}.
+
+compile(Name, File, Opts0) ->
+ Opts1 = expand_kt2(Opts0),
+ Opts =
+ case Name of
+ {_Mod, _Fun, _Arity} ->
+ [no_concurrent_comp|Opts1];
+ _ ->
+ Opts1
+ end,
+ case proplists:get_value(core, Opts) of
+ true when is_binary(File) ->
+ ?error_msg("Cannot get Core Erlang code from BEAM binary.",[]),
+ ?EXIT({cant_compile_core_from_binary});
+ true ->
+ case filename:find_src(filename:rootname(File, ".beam")) of
+ {error, _} ->
+ ?error_msg("Cannot find source code for ~p.",[File]),
+ ?EXIT({cant_find_source_code});
+ {Source, CompOpts} ->
+ CoreOpts = [X || X = {core_transform, _} <- Opts],
+ %%io:format("Using: ~w\n", [CoreOpts]),
+ case compile:file(Source, CoreOpts ++ [to_core, binary|CompOpts]) of
+ {ok, _, Core} ->
+ compile_core(Name, Core, File, Opts);
+ Error ->
+ ?error_msg("Error compiling ~p:\n~p.",[File, Error]),
+ ?EXIT({cant_compile_source_code})
+ end
+ end;
+ {src_file, Source} ->
+ CoreOpts1 = [X || X = {core_transform, _} <- Opts],
+ CoreOpts2 = [report_errors, to_core, binary, {i,"../include"}|CoreOpts1],
+ %% io:format("Using: ~w\n", [CoreOpts2]),
+ case compile:file(Source, CoreOpts2) of
+ {ok, _, Core} ->
+ compile_core(Name, Core, File, Opts);
+ Error ->
+ ?error_msg("Error compiling ~p:\n~p\n",[Source, Error]),
+ ?EXIT({cant_compile_source_code, Error})
+ end;
+ Other when Other =:= false; Other =:= undefined ->
+ NewOpts =
+ case proplists:get_value(use_callgraph, Opts) of
+ No when No =:= false; No =:= undefined -> Opts;
+ _ ->
+ case Name of
+ {_M,_F,_A} ->
+ %% There is no point in using the callgraph or concurrent_comp
+ %% when analyzing just one function.
+ [no_use_callgraph, no_concurrent_comp|Opts];
+ _ -> Opts
+ end
+ end,
+ DisasmFun = fun (_) -> disasm(File) end,
+ IcodeFun = fun (Code, Opts_) ->
+ get_beam_icode(Name, Code, File, Opts_)
+ end,
+ run_compiler(Name, DisasmFun, IcodeFun, NewOpts)
+ end.
+
+-spec compile_core(mod(), _, compile_file(), comp_options()) ->
+ {'ok', compile_ret()} | {'error', term()}.
+
+compile_core(Name, Core0, File, Opts) ->
+ Core = cerl:from_records(Core0),
+ Core1 = case (erlang:system_info(heap_type) =:= hybrid)
+ andalso proplists:get_bool(hybrid, Opts) of
+ true -> cerl_hybrid_transform:transform(Core, Opts);
+ false -> Core
+ end,
+ compile(Name, Core1, File, Opts).
+
+%% @spec compile(Name, Core, File, options()) ->
+%% {ok, {Target, Binary}} | {error, Reason}
+%% Name = mod()
+%% Core = coreErlang() | []
+%% File = filename() | binary()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @doc Like <code>compile/3</code>, but unless <code>Core</code> is
+%% <code>[]</code>, low-level code is generated from the given Core
+%% Erlang code instead of from the BEAM code.
+%%
+%% <p>Note that only whole modules can be compiled with this
+%% function.</p>
+%%
+%% @see compile/3
+
+-spec compile(mod(), _, compile_file(), comp_options()) ->
+ {'ok', compile_ret()} | {'error', term()}.
+
+compile(Name, [], File, Opts) ->
+ compile(Name, File, Opts);
+compile(Name, Core, File, Opts) when is_atom(Name) ->
+ DisasmFun = fun (_) -> {false, []} end,
+ IcodeFun = fun (_, Opts) ->
+ get_core_icode(Name, Core, File, Opts)
+ end,
+ run_compiler(Name, DisasmFun, IcodeFun, Opts).
+
+%% @spec file(File) -> {ok, Name, {Target, Binary}} | {error, Reason}
+%% File = filename() | binary()
+%% Name = mod() | mfa()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @equiv file(File, [])
+
+-spec file(Mod) -> {'ok', Mod, compile_ret()} | {'error', term()}
+ when is_subtype(Mod, mod()).
+
+file(File) ->
+ file(File, []).
+
+%% @spec file(File, options()) -> {ok, Name, {Target,Binary}} | {error, Reason}
+%% File = filename()
+%% Name = mod() | mfa()
+%% Binary = binary()
+%% Reason = term()
+%%
+%% @doc Like <code>compile/2</code>, but takes the module name from the
+%% specified <code>File</code>. Returns both the name and the final
+%% binary if successful.
+%%
+%% @see file/1
+%% @see compile/2
+
+-spec file(Mod, comp_options()) -> {'ok', Mod, compile_ret()}
+ | {'error', term()}
+ when is_subtype(Mod, mod()).
+file(File, Options) when is_atom(File) ->
+ case beam_lib:info(File) of
+ L when is_list(L) ->
+ {module, Mod} = lists:keyfind(module, 1, L),
+ case compile(Mod, File, Options) of
+ {ok, CompRet} ->
+ {ok, Mod, CompRet};
+ Other ->
+ Other
+ end;
+ Error ->
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------------
+%% The rest are internal functions:
+%%-----------------------------------------------------------------------
+
+%% @doc
+%% Get BEAM code from `.beam' files or directly from binaries.
+%% File is either a file name or a binary containing the BEAM code.
+
+disasm(File) ->
+ case beam_disasm:file(File) of
+ #beam_file{labeled_exports = LabeledExports,
+ compile_info = CompInfo,
+ code = BeamCode} ->
+ {options, CompOpts} = lists:keyfind(options, 1, CompInfo),
+ HCompOpts = case lists:keyfind(hipe, 1, CompOpts) of
+ {hipe, L} when is_list(L) -> L;
+ {hipe, X} -> [X];
+ _ -> []
+ end,
+ Exports = fix_beam_exports(LabeledExports),
+ {{BeamCode, Exports}, HCompOpts};
+ {error, _Mod, Error} ->
+ io:format("~s\n", [beam_lib:format_error(Error)]),
+ ?EXIT(no_beam_code)
+ end.
+
+fix_beam_exports(BeamExports) ->
+ fix_beam_exports(BeamExports, []).
+
+fix_beam_exports([{F,A,_}|BeamExports], Exports) ->
+ fix_beam_exports(BeamExports, [{F,A} | Exports]);
+fix_beam_exports([], Exports) ->
+ Exports.
+
+get_beam_icode({M,_F,_A} = MFA, {BeamCode, Exports}, _File, Options) ->
+ ?option_time({ok, Icode} =
+ (catch {ok, hipe_beam_to_icode:mfa(BeamCode, MFA, Options)}),
+ "BEAM-to-Icode", Options),
+ {{M, Exports, Icode}, false};
+get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->
+ ?option_time({ok, Icode} =
+ (catch {ok, hipe_beam_to_icode:module(BeamCode, Options)}),
+ "BEAM-to-Icode", Options),
+ BeamBin = get_beam_code(File),
+ {{Mod, Exports, Icode}, BeamBin}.
+
+get_core_icode(Mod, Core, File, Options) ->
+ ?option_time({ok, Icode} =
+ (catch {ok, cerl_to_icode:module(Core, Options)}),
+ "BEAM-to-Icode", Options),
+ NeedBeamCode = not proplists:get_bool(load, Options),
+ BeamBin =
+ case NeedBeamCode of
+ true -> [];
+ false -> get_beam_code(File)
+ end,
+ Exports = [cerl:var_name(V) || V <- cerl:module_exports(Core)],
+ {{Mod, Exports, Icode}, BeamBin}.
+
+get_beam_code(Bin) when is_binary(Bin) -> Bin;
+get_beam_code(FileName) ->
+ case erl_prim_loader:get_file(FileName) of
+ {ok,Bin,_} ->
+ Bin;
+ error ->
+ ?EXIT(no_beam_file)
+ end.
+
+
+%% ---------------------------------------------------------------------
+%% All compilations go through this function. Note that it receives only
+%% "basic" options. Name is just used for verbosity. The DisasmFun and
+%% IcodeFun only collect the Icode; most of the real work is done in the
+%% 'finalize' function.
+
+run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->
+ Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),
+ ?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),
+ ?option_start_time("Compile", Opts),
+ Res = run_compiler_1(DisasmFun, IcodeFun, Opts),
+ ?option_stop_time("Compile", Opts),
+ Res.
+
+run_compiler_1(DisasmFun, IcodeFun, Options) ->
+ Parent = self(),
+ {trap_exit,TrapExit} = process_info(Parent, trap_exit),
+ %% Spawn a compilation process CompProc. In case this process gets
+ %% killed, the trap_exit flag is restored to that of the Parent process.
+ process_flag(trap_exit, true),
+ CompProc = spawn_link(fun () ->
+ %% Compiler process
+ set_architecture(Options),
+ pre_init(Options),
+ %% The full option expansion is not done
+ %% until the DisasmFun returns.
+ {Code, CompOpts} = DisasmFun(Options),
+ Opts = expand_options(Options ++ CompOpts),
+ check_options(Opts),
+ ?when_option(verbose, Options,
+ ?debug_msg("Options: ~p.\n",[Opts])),
+ init(Opts),
+ {Icode, WholeModule} = IcodeFun(Code, Opts),
+ CompRes = compile_finish(Icode, WholeModule, Opts),
+ compiler_return(CompRes, Parent)
+ end),
+ Timeout = case proplists:get_value(timeout, Options) of
+ N when is_integer(N), N >= 0 -> N;
+ undefined -> ?DEFAULT_TIMEOUT;
+ infinity -> infinity;
+ Other ->
+ ?WARNING_MSG("Bad timeout value: ~P\n"
+ "Using default timeout limit.\n",
+ [Other, 5]),
+ ?DEFAULT_TIMEOUT
+ end,
+ receive
+ {'EXIT', CompProc, normal} -> ok;
+ {'EXIT', CompProc, Reason} -> exit(Reason)
+ after Timeout ->
+ %% Kill the compilation process
+ exit(CompProc, kill),
+ receive {'EXIT', CompProc, _} -> ok end,
+ flush(),
+ ?error_msg("ERROR: Compilation timed out.\n",[]),
+ exit(timed_out)
+ end,
+ Result = receive {CompProc, Res} -> Res end,
+ process_flag(trap_exit, TrapExit),
+ Result.
+
+flush() ->
+ receive
+ _ -> flush()
+ after 0 ->
+ ok
+ end.
+
+compiler_return(Res, Client) ->
+ Client ! {self(), Res}.
+
+compile_finish({Mod, Exports, Icode}, WholeModule, Options) ->
+ Res = finalize(Icode, Mod, Exports, WholeModule, Options),
+ post(Res, Icode, Options).
+
+
+%% -------------------------------------------------------------------------
+%% finalize/5
+%% compiles, assembles, and optionally loads a list of `{MFA, Icode}' pairs,
+%% and returns `{ok, {TargetArch, Binary}}' or `{error, Reason, Stack}'.
+
+finalize(OrigList, Mod, Exports, WholeModule, Opts) ->
+ List = icode_multret(OrigList, Mod, Opts, Exports),
+ {T1Compile,_} = erlang:statistics(runtime),
+ CompiledCode =
+ case proplists:get_value(use_callgraph, Opts) of
+ true ->
+ %% Compiling the functions bottom-up by using a call graph
+ CallGraph = hipe_icode_callgraph:construct(List),
+ OrdList = hipe_icode_callgraph:to_list(CallGraph),
+ finalize_fun(OrdList, Exports, Opts);
+ _ ->
+ %% Compiling the functions bottom-up by reversing the list
+ OrdList = lists:reverse(List),
+ finalize_fun(OrdList, Exports, Opts)
+ end,
+ {T2Compile,_} = erlang:statistics(runtime),
+ ?when_option(verbose, Opts,
+ ?debug_msg("Compiled ~p in ~.2f s\n",
+ [Mod,(T2Compile-T1Compile)/1000])),
+ case proplists:get_bool(to_rtl, Opts) of
+ true ->
+ {ok, CompiledCode};
+ false ->
+ Closures =
+ [MFA || {MFA, Icode} <- List,
+ hipe_icode:icode_is_closure(Icode)],
+ {T1,_} = erlang:statistics(runtime),
+ ?when_option(verbose, Opts, ?debug_msg("Assembling ~w",[Mod])),
+ try assemble(CompiledCode, Closures, Exports, Opts) of
+ Bin ->
+ {T2,_} = erlang:statistics(runtime),
+ ?when_option(verbose, Opts,
+ ?debug_untagged_msg(" in ~.2f s\n",
+ [(T2-T1)/1000])),
+ {module,Mod} = maybe_load(Mod, Bin, WholeModule, Opts),
+ TargetArch = get(hipe_target_arch),
+ {ok, {TargetArch,Bin}}
+ catch
+ error:Error ->
+ {error,Error,erlang:get_stacktrace()}
+ end
+ end.
+
+finalize_fun(MfaIcodeList, Exports, Opts) ->
+ case proplists:get_value(concurrent_comp, Opts) of
+ FalseVal when (FalseVal =:= undefined) orelse (FalseVal =:= false) ->
+ [finalize_fun_sequential(MFAIcode, Opts, #comp_servers{})
+ || {_MFA, _Icode} = MFAIcode <- MfaIcodeList];
+ TrueVal when (TrueVal =:= true) or (TrueVal =:= debug) ->
+ finalize_fun_concurrent(MfaIcodeList, Exports, Opts)
+ end.
+
+finalize_fun_concurrent(MfaIcodeList, Exports, Opts) ->
+ Self = self(),
+ case MfaIcodeList of
+ [{{M,_,_},_}|_] ->
+ CallGraph = hipe_icode_callgraph:construct_callgraph(MfaIcodeList),
+ Closures = [{MFA, true} || {MFA, Icode} <- MfaIcodeList,
+ hipe_icode:icode_is_closure(Icode)],
+ Exported = [{{M, F, A}, false} || {F, A} <- Exports],
+ NonEscaping = [MFA || {{_M, F, A} = MFA, Icode} <- MfaIcodeList,
+ not lists:member({F, A}, Exports),
+ not hipe_icode:icode_is_closure(Icode)],
+ Escaping = Closures ++ Exported,
+ TypeServerFun =
+ fun() ->
+ hipe_icode_coordinator:coordinate(CallGraph, Escaping,
+ NonEscaping, hipe_icode_type)
+ end,
+ TypeServer = spawn_link(TypeServerFun),
+ PPServerFun =
+ fun() ->
+ pp_server_start(Opts)
+ end,
+ PPServer = spawn_link(PPServerFun),
+ RangeServerFun =
+ fun() ->
+ hipe_icode_coordinator:coordinate(CallGraph, Escaping,
+ NonEscaping, hipe_icode_range)
+ end,
+ RangeServer = spawn_link(RangeServerFun),
+ Servers = #comp_servers{pp_server = PPServer,
+ range = RangeServer,
+ type = TypeServer},
+ CompFuns =
+ [fun() ->
+ set_architecture(Opts),
+ pre_init(Opts),
+ init(Opts),
+ Self ! finalize_fun_sequential(IcodeFun, Opts, Servers)
+ end || IcodeFun <- MfaIcodeList],
+ lists:foreach(fun (F) -> spawn_link(F) end, CompFuns),
+ Final = [receive Res when element(1, Res) =:= MFA -> Res end
+ || {MFA, _} <- MfaIcodeList],
+ lists:foreach(fun (Pid) -> stop_and_wait(Pid) end,
+ [PPServer, TypeServer, RangeServer]),
+ Final;
+ [] ->
+ []
+ end.
+
+stop_and_wait(Pid) ->
+ Pid ! {stop, self()},
+ receive
+ _ -> ok
+ end.
+
+finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
+ {T1, _} = erlang:statistics(runtime),
+ ?when_option(verbose, Opts, ?debug_msg("Compiling ~w~n", [MFA])),
+ try hipe_main:compile_icode(MFA, Icode, Opts, Servers) of
+ {native, _Platform, {unprofiled, Code}} ->
+ {T2, _} = erlang:statistics(runtime),
+ ?when_option(verbose, Opts,
+ ?debug_msg("Compiled ~w in ~.2f s\n", [MFA,(T2-T1)/1000])),
+ {MFA, Code};
+ {rtl, LinearRtl} ->
+ {MFA, LinearRtl}
+ catch
+ error:Error ->
+ ?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
+ ErrorInfo = {Error, erlang:get_stacktrace()},
+ ?error_msg("ERROR: ~p~n", [ErrorInfo]),
+ ?EXIT(ErrorInfo)
+ end.
+
+pp_server_start(Opts) ->
+ set_architecture(Opts),
+ garbage_collect(),
+ pp_server().
+
+pp_server() ->
+ receive
+ {print, Fun} ->
+ Fun(), pp_server();
+ {stop, Pid} ->
+ Pid ! {done, self()};
+ _ ->
+ pp_server()
+ end.
+
+icode_multret(List, Mod, Opts, Exports) ->
+ case proplists:get_bool(icode_multret, Opts) of
+ true ->
+ hipe_icode_mulret:mult_ret(List, Mod, Opts, Exports);
+ false ->
+ List
+ end.
+
+maybe_load(Mod, Bin, WholeModule, Opts) ->
+ case proplists:get_bool(load, Opts) of
+ false ->
+ {module, Mod};
+ true ->
+ ?when_option(verbose, Opts, ?debug_msg("Loading/linking\n", [])),
+ do_load(Mod, Bin, WholeModule)
+ end.
+
+do_load(Mod, Bin, WholeModule) ->
+ HostArch = get(hipe_host_arch),
+ TargetArch = get(hipe_target_arch),
+ %% Make sure we can do the load.
+ if HostArch =/= TargetArch ->
+ ?EXIT({host_and_target_arch_differ, HostArch, TargetArch});
+ true -> ok
+ end,
+ case WholeModule of
+ false ->
+ %% In this case, the emulated code for the module must be loaded.
+ {module, Mod} = code:ensure_loaded(Mod),
+ code:load_native_partial(Mod, Bin);
+ BinCode when is_binary(BinCode) ->
+ case code:is_sticky(Mod) of
+ true ->
+ %% We unpack and repack the Beam binary as a workaround to
+ %% ensure that it is not compressed.
+ {ok, _, Chunks} = beam_lib:all_chunks(WholeModule),
+ {ok, Beam} = beam_lib:build_module(Chunks),
+ %% Don't purge or register sticky mods; just load native.
+ code:load_native_sticky(Mod, Bin, Beam);
+ false ->
+ %% Normal loading of a whole module
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ {ok, _, Chunks0} = beam_lib:all_chunks(WholeModule),
+ Chunks = [{ChunkName, Bin}|lists:keydelete(ChunkName, 1, Chunks0)],
+ {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
+ code:load_binary(Mod, code:which(Mod), BeamPlusNative)
+ end
+ end.
+
+assemble(CompiledCode, Closures, Exports, Options) ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ powerpc ->
+ hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ arm ->
+ hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ x86 ->
+ hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ amd64 ->
+ hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ Arch ->
+ ?EXIT({executing_on_an_unsupported_architecture, Arch})
+ end.
+
+%% --------------------------------------------------------------------
+
+%% Initialise host and target architectures. Target defaults to host,
+%% but can be overridden by passing an option {target, Target}.
+
+set_architecture(Options) ->
+ put(hipe_host_arch, erlang:system_info(hipe_architecture)),
+ put(hipe_target_arch,
+ proplists:get_value(target, Options, get(hipe_host_arch))),
+ ok.
+
+%% This sets up some globally accessed stuff that are needed by the
+%% compiler process before it even gets the full list of options.
+%% Therefore, this expands the current set of options for local use.
+
+pre_init(Opts) ->
+ Options = expand_options(Opts),
+ %% Initialise some counters used for measurements and benchmarking. If
+ %% the option 'measure_regalloc' is given the compilation will return
+ %% a keylist with the counter values.
+ put(hipe_time,
+ case proplists:get_value(time, Options, false) of
+ true -> [hipe, hipe_main];
+ OptTime -> OptTime
+ end),
+ lists:foreach(fun (T) -> ?set_hipe_timer_val(T, 0) end, hipe_timers()),
+ lists:foreach(fun (Counter) ->
+ case Counter of
+ {CounterName, InitVal} -> put(CounterName, InitVal);
+ CounterName -> put(CounterName, 0)
+ end
+ end,
+ proplists:get_value(counters, Options, [])),
+ put(hipe_debug, proplists:get_bool(debug, Options)),
+ put(hipe_inline_fp, proplists:get_bool(inline_fp, Options)),
+ ok.
+
+%% Prepare the compiler process by setting up variables which are
+%% accessed globally. Options have been fully expanded at ths point.
+
+init(_Options) ->
+ put(callersavetime, 0),
+ put(totalspill, {0,0}),
+ put(spilledtemps, 0),
+ put(pre_ra_instrs, 0),
+ put(post_ra_instrs, 0),
+ put(pre_ra_temps, 0),
+ put(post_ra_temps, 0),
+ put(noregs, 0),
+ put(bbs, 0),
+ ok.
+
+%% --------------------------------------------------------------------
+
+post(Res, Icode, Options) ->
+ TimerVals =
+ case proplists:get_value(timers, Options) of
+ Timers when is_list(Timers) ->
+ [{Timer, ?get_hipe_timer_val(Timer)} || Timer <- Timers];
+ _ -> []
+ end,
+ CounterVals =
+ case proplists:get_value(counters, Options) of
+ Counters when is_list(Counters) ->
+ [case Counter of
+ {CounterName, _InitVal} -> {CounterName, get(CounterName)};
+ CounterName -> {CounterName, get(CounterName)}
+ end
+ || Counter <- Counters];
+ _ -> []
+ end,
+ Measures =
+ case proplists:get_bool(measure_regalloc, Options) of
+ true ->
+ get(); % return whole process dictionary list (simplest way...)
+ false -> []
+ end,
+ Info = TimerVals ++ CounterVals ++ Measures,
+ case proplists:get_bool(get_called_modules, Options) of
+ true ->
+ CalledMods = hipe_icode_callgraph:get_called_modules(Icode),
+ case Info of
+ [] ->
+ {Res, {called_modules, CalledMods}};
+ _ ->
+ {Res, {info, Info}, {called_modules, CalledMods}}
+ end;
+ false ->
+ case Info of
+ [] ->
+ Res;
+ _ ->
+ {Res, {info, Info}}
+ end
+ end.
+
+%% --------------------------------------------------------------------
+
+%% @doc Returns the current HiPE version as a string().
+-spec version() -> string().
+
+version() ->
+ ?VERSION_STRING().
+
+%% --------------------------------------------------------------------
+%% D O C U M E N T A T I O N - H E L P
+%% --------------------------------------------------------------------
+
+%% @doc Prints on-line documentation to the standard output.
+-spec help() -> 'ok'.
+
+help() ->
+ M =
+ "The HiPE Compiler (Version " ++ ?VERSION_STRING() ++ ")\n" ++
+ "\n" ++
+ " The normal way to native-compile Erlang code using HiPE is to\n" ++
+ " include `native' in the Erlang compiler options, as in:\n" ++
+ " 1> c(my_module, [native]).\n" ++
+ " Options to the HiPE compiler must then be passed as follows:\n" ++
+ " 1> c(my_module, [native,{hipe,Options}]).\n" ++
+ " Use `help_options()' for details.\n" ++
+ "\n" ++
+ " Utility functions:\n" ++
+ " help()\n" ++
+ " Prints this message.\n" ++
+ " help_options()\n" ++
+ " Prints a description of options recognized by the\n" ++
+ " HiPE compiler.\n" ++
+ " help_option(Option)\n" ++
+ " Prints a description of that option.\n" ++
+ " help_debug_options()\n" ++
+ " Prints a description of debug options.\n" ++
+ " version() ->\n" ++
+ " Returns the HiPE version as a string'.\n" ++
+ "\n" ++
+ " For HiPE developers only:\n" ++
+ " Use `help_hiper()' for information about HiPE's low-level interface\n",
+ io:put_chars(M),
+ ok.
+
+-spec help_hiper() -> 'ok'.
+
+help_hiper() ->
+ M =
+ " This interface is supposed to be used by HiPE-developers only!\n" ++
+ " Note that all options are specific to the HiPE compiler.\n" ++
+ " c(Name,Options)\n" ++
+ " Compiles the module or function Name and loads it\n" ++
+ " to memory. Name is an atom or a tuple {M,F,A}.\n" ++
+ " c(Name)\n" ++
+ " As above, but using only default options.\n" ++
+ " f(File,Options)\n" ++
+ " As c(Name,File,Options), but taking the module name\n" ++
+ " from File.\n" ++
+ " f(File)\n" ++
+ " As above, but using only default options.\n" ++
+ " compile(Name,Options)\n" ++
+ " Compiles the module or function Name to a binary.\n" ++
+ " By default, this does not load to memory.\n" ++
+ " compile(Name)\n" ++
+ " As above, but using only default options.\n" ++
+ " file(File,Options)\n" ++
+ " As compile(Name,File,Options), but taking the\n" ++
+ " module name from File.\n" ++
+ " file(File)\n" ++
+ " As above, but using only default options.\n" ++
+ " load(Module)\n" ++
+ " Loads the named module into memory.\n",
+ io:put_chars(M),
+ ok.
+
+%% TODO: it should be possible to specify the target somehow when asking
+%% for available options. Right now, you only see host machine options.
+
+%% @doc Prints documentation about options to the standard output.
+-spec help_options() -> 'ok'.
+
+help_options() ->
+ set_architecture([]), %% needed for target-specific option expansion
+ O1 = expand_options([o1]),
+ O2 = expand_options([o2]),
+ O3 = expand_options([o3]),
+ io:format("HiPE Compiler Options\n" ++
+ " Boolean-valued options generally have corresponding " ++
+ "aliases `no_...',\n" ++
+ " and can also be specified as `{Option, true}' " ++
+ "or `{Option, false}.\n\n" ++
+ " General boolean options:\n" ++
+ " ~p.\n\n" ++
+ " Non-boolean options:\n" ++
+ " o#, where 0 =< # =< 3:\n" ++
+ " Select optimization level (the default is 2).\n\n" ++
+ " Further options can be found below; " ++
+ "use `hipe:help_option(Name)' for details.\n\n" ++
+ " Aliases:\n" ++
+ " pp_all = ~p,\n" ++
+ " pp_sparc = pp_native,\n" ++
+ " pp_x86 = pp_native,\n" ++
+ " pp_amd64 = pp_native,\n" ++
+ " pp_ppc = pp_native,\n" ++
+ " o0,\n" ++
+ " o1 = ~p,\n" ++
+ " o2 = ~p ++ o1,\n" ++
+ " o3 = ~p ++ o2.\n",
+ [ordsets:from_list([verbose, debug, time, load, pp_beam,
+ pp_icode, pp_rtl, pp_native, pp_asm,
+ timeout]),
+ expand_options([pp_all]),
+ O1 -- [o1],
+ (O2 -- O1) -- [o2],
+ (O3 -- O2) -- [o3]]),
+ ok.
+
+%% Documentation of the individual options.
+%% If you add an option, please add help-text here.
+
+-spec option_text(atom()) -> string().
+
+option_text('O') ->
+ "Specify optimization level. Used as o1, o2, o3.\n" ++
+ " At the moment levels 0 - 3 are implemented.\n" ++
+ " Aliases: 'O1', 'O2', O3'.";
+option_text(caller_save_spill_restore) ->
+ "Activates caller save register spills and restores";
+option_text(debug) ->
+ "Outputs internal debugging information during compilation";
+option_text(icode_range) ->
+ "Performs integer range analysis on the Icode level";
+option_text(icode_ssa_check) ->
+ "Checks whether Icode is on SSA form or not\n";
+option_text(icode_ssa_copy_prop) ->
+ "Performs copy propagation on Icode SSA";
+option_text(icode_ssa_const_prop) ->
+ "Performs sparse conditional constant propagation on Icode SSA";
+option_text(icode_ssa_struct_reuse) ->
+ "Factors out common tuple and list constructions on Icode SSA";
+option_text(icode_type) ->
+ "Performs type analysis on the Icode level" ++
+ "and then simplifies the code based on the results of this analysis";
+option_text(load) ->
+ "Automatically load the produced native code into memory";
+option_text(peephole) ->
+ "Enables peephole optimizations";
+option_text(pmatch) ->
+ "Enables pattern matching compilation when compiling from Core; " ++
+ "has no effect when compiling from BEAM bytecode";
+option_text(pp_asm) ->
+ "Displays assembly listing with addresses and bytecode\n" ++
+ "Currently available for x86 only";
+option_text(pp_beam) ->
+ "Display the input BEAM code";
+option_text(pp_icode) ->
+ "Display the intermediate HiPE-ICode";
+option_text(pp_rtl) ->
+ "Display the intermediate HiPE-RTL code";
+option_text(pp_rtl_lcm) ->
+ "Display the intermediate HiPE-RTL lazy code motion sets";
+option_text(pp_rtl_ssapre) ->
+ "Display the intermediate HiPE-RTL A-SSAPRE sets";
+option_text(pp_native) ->
+ "Display the generated (back-end specific) native code";
+option_text(regalloc) ->
+ "Select register allocation algorithm. Used as {regalloc, METHOD}.\n" ++
+ " Currently available methods:\n" ++
+ " naive - spills everything (for debugging and testing)\n" ++
+ " linear_scan - fast; not so good if few registers available\n" ++
+ " graph_color - slow, but gives OK performance\n" ++
+ " coalescing - slower, tries hard to use registers\n" ++
+ " optimistic - another variant of a coalescing allocator";
+option_text(remove_comments) ->
+ "Strip comments from intermediate code";
+option_text(rtl_ssa) ->
+ "Perform SSA conversion on the RTL level -- default starting at O2";
+option_text(rtl_ssa_const_prop) ->
+ "Performs sparse conditional constant propagation on RTL SSA";
+option_text(rtl_lcm) ->
+ "Perform Lazy Code Motion on RTL";
+option_text(rtl_ssapre) ->
+ "Perform A-SSAPRE on RTL";
+option_text(time) ->
+ "Reports the compilation times for the different stages\n" ++
+ "of the compiler.\n" ++
+ " {time, Module} reports timings for the module Module.\n" ++
+ " {time, [M1, M2, M3]} reports timings for the specified modules.\n" ++
+ " {time, all} reports timings all modules.\n" ++
+ " time reports timings for the main module.\n";
+option_text(timeout) ->
+ "Specify compilation time limit in ms. Used as {timeout, LIMIT}.\n" ++
+ " The limit must be a non-negative integer or the atom 'infinity'.\n" ++
+ " The current default limit is 15 minutes (900000 ms).";
+option_text(use_indexing) ->
+ "Use indexing for multiple-choice branch selection.";
+option_text(use_callgraph) ->
+ "Compile the functions in a module according to a reversed topological " ++
+ "sorted order to gain more information when using a persistent lookup " ++
+ "table for storing intra-modular type information.";
+option_text(verbose) ->
+ "Output information about what is being done";
+option_text(Opt) when is_atom(Opt) ->
+ "".
+
+%% @doc Prints documentation about a specific option to the standard output.
+-spec help_option(comp_option()) -> 'ok'.
+
+help_option(Opt) ->
+ set_architecture([]), %% needed for target-specific option expansion
+ case expand_options([Opt]) of
+ [Opt] ->
+ Name = if is_atom(Opt) -> Opt;
+ tuple_size(Opt) =:= 2 -> element(1, Opt)
+ end,
+ case option_text(Name) of
+ "" ->
+ case lists:member(Name, opt_keys()) of
+ true ->
+ io:format("~w - Sorry, this option is not documented yet.\n",
+ [Name]);
+ _ ->
+ io:format("Unknown option ~p.\n", [Name])
+ end;
+ Txt ->
+ io:fwrite("~w - ~s\n", [Name, Txt])
+ end;
+ Opts ->
+ io:fwrite("This is an alias for: ~p.\n", [Opts])
+ end,
+ ok.
+
+%% @doc Prints documentation about debugging options to the standard
+%% output.
+-spec help_debug_options() -> 'ok'.
+
+help_debug_options() ->
+ io:format("HiPE compiler debug options:\n" ++
+ " Might require that some modules have been compiled " ++
+ "with the debug flag.\n" ++
+ " rtl_show_translation - Prints each step in the\n" ++
+ " translation from Icode to RTL\n",
+ []),
+ ok.
+
+hipe_timers() ->
+ [time_ra].
+
+%% ____________________________________________________________________
+%%
+%% Option expansion
+
+%% These are currently in use, but not documented:
+%%
+%% count_instrs:
+%% icode_type:
+%% icode_range:
+%% {ls_order, Order}:
+%% {regalloc, Algorithm}:
+%% remove_comments
+%% timeregalloc:
+%% timers
+%% use_indexing
+
+%% Valid option keys. (Don't list aliases or negations - the check is
+%% done after the options have been expanded to normal form.)
+
+opt_keys() ->
+ [
+ binary_opt,
+ bitlevel_binaries,
+ caller_save_spill_restore,
+ concurrent_comp,
+ core,
+ core_transform,
+ counters,
+ count_instrs,
+ count_spills,
+ count_temps,
+ debug,
+ get_called_modules,
+ split_arith,
+ split_arith_unsafe,
+ icode_inline_bifs,
+ icode_ssa_check,
+ icode_ssa_copy_prop,
+ icode_ssa_const_prop,
+ icode_ssa_struct_reuse,
+ icode_type,
+ icode_range,
+ icode_multret,
+ inline_fp,
+ ls_order,
+ load,
+ measure_regalloc,
+ peephole,
+ pmatch,
+ pp_asm,
+ pp_beam,
+ pp_icode,
+ pp_icode_ssa,
+ pp_icode_split_arith,
+ pp_opt_icode,
+ pp_range_icode,
+ pp_typed_icode,
+ pp_icode_liveness,
+ pp_native,
+ pp_rtl,
+ pp_rtl_liveness,
+ pp_rtl_ssa,
+ pp_rtl_lcm,
+ pp_rtl_ssapre,
+ pp_rtl_linear,
+ regalloc,
+ remove_comments,
+ rtl_ssa,
+ rtl_ssa_const_prop,
+ rtl_lcm,
+ rtl_ssapre,
+ rtl_show_translation,
+ spillmin_color,
+ target,
+ time,
+ timeout,
+ timeregalloc,
+ timers,
+ to_rtl,
+ use_indexing,
+ use_inline_atom_search,
+ use_callgraph,
+ use_clusters,
+ use_jumptable,
+ verbose,
+ %% verbose_spills,
+ x87].
+
+%% Definitions:
+
+o1_opts() ->
+ Common = [inline_fp, pmatch, peephole],
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ Common;
+ powerpc ->
+ Common;
+ arm ->
+ Common -- [inline_fp]; % Pointless optimising for absent hardware
+ x86 ->
+ [x87 | Common]; % XXX: Temporary until x86 has sse2
+ amd64 ->
+ Common;
+ Arch ->
+ ?EXIT({executing_on_an_unsupported_architecture,Arch})
+ end.
+
+o2_opts() ->
+ Common = [icode_ssa_const_prop, icode_ssa_copy_prop, % icode_ssa_struct_reuse,
+ icode_type, icode_inline_bifs, rtl_lcm,
+ rtl_ssa, rtl_ssa_const_prop,
+ spillmin_color, use_indexing, remove_comments,
+ concurrent_comp, binary_opt | o1_opts()],
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ Common;
+ powerpc ->
+ Common;
+ arm ->
+ Common;
+ x86 ->
+ Common;
+ % [rtl_ssapre | Common];
+ amd64 ->
+ [icode_range | Common]; % range analysis is effective on 64 bits
+ Arch ->
+ ?EXIT({executing_on_an_unsupported_architecture,Arch})
+ end.
+
+o3_opts() ->
+ Common = [icode_range, {regalloc,coalescing} | o2_opts()],
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ Common;
+ powerpc ->
+ Common;
+ arm ->
+ Common;
+ x86 ->
+ Common;
+ amd64 ->
+ Common;
+ Arch ->
+ ?EXIT({executing_on_an_unsupported_architecture,Arch})
+ end.
+
+%% Note that in general, the normal form for options should be positive.
+%% This is a good programming convention, so that tests in the code say
+%% "if 'x' ..." instead of "if not 'no_x' ...".
+
+opt_negations() ->
+ [{no_binary_opt, binary_opt},
+ {no_bitlevel_binaries, bitlevel_binaries},
+ {no_core, core},
+ {no_debug, debug},
+ {no_get_called_modules, get_called_modules},
+ {no_split_arith, split_arith},
+ {no_concurrent_comp, concurrent_comp},
+ {no_icode_inline_bifs, icode_inline_bifs},
+ {no_icode_range, icode_range},
+ {no_icode_split_arith, icode_split_arith},
+ {no_icode_ssa_check, icode_ssa_check},
+ {no_icode_ssa_copy_prop, icode_ssa_copy_prop},
+ {no_icode_ssa_const_prop, icode_ssa_const_prop},
+ {no_icode_ssa_struct_reuse, icode_ssa_struct_reuse},
+ {no_icode_type, icode_type},
+ {no_inline_fp, inline_fp},
+ {no_load, load},
+ {no_peephole, peephole},
+ {no_pmatch, pmatch},
+ {no_pp_beam, pp_beam},
+ {no_pp_icode, pp_icode},
+ {no_pp_icode_ssa, pp_icode_ssa},
+ {no_pp_opt_icode, pp_opt_icode},
+ {no_pp_typed_icode, pp_typed_icode},
+ {no_pp_rtl, pp_rtl},
+ {no_pp_native, pp_native},
+ {no_pp_rtl_lcm, pp_rtl_lcm},
+ {no_pp_rtl_ssapre, pp_rtl_ssapre},
+ {no_remove_comments, remove_comments},
+ {no_rtl_ssa, rtl_ssa},
+ {no_rtl_ssa_const_prop, rtl_ssa_const_prop},
+ {no_rtl_lcm, rtl_lcm},
+ {no_rtl_ssapre, rtl_ssapre},
+ {no_rtl_show_translation, rtl_show_translation},
+ {no_time, time},
+ {no_use_callgraph, use_callgraph},
+ {no_use_clusters, use_clusters},
+ {no_use_inline_atom_search, use_inline_atom_search},
+ {no_use_indexing, use_indexing}].
+
+%% Don't use negative forms in right-hand sides of aliases and expansions!
+%% We only expand negations once, before the other expansions are done.
+
+opt_aliases() ->
+ [{'O0', o0},
+ {'O1', o1},
+ {'O2', o2},
+ {'O3', o3},
+ {pp_sparc, pp_native},
+ {pp_x86, pp_native},
+ {pp_amd64, pp_native},
+ {pp_ppc, pp_native}].
+
+opt_basic_expansions() ->
+ [{pp_all, [pp_beam, pp_icode, pp_rtl, pp_native]}].
+
+opt_expansions() ->
+ [{o1, o1_opts()},
+ {o2, o2_opts()},
+ {o3, o3_opts()},
+ {x87, [x87, inline_fp]},
+ {inline_fp, case get(hipe_target_arch) of %% XXX: Temporary until x86
+ x86 -> [x87, inline_fp]; %% has sse2
+ _ -> [inline_fp] end}].
+
+%% This expands "basic" options, which may be tested early and cannot be
+%% in conflict with options found in the source code.
+
+-spec expand_basic_options(comp_options()) -> comp_options().
+
+expand_basic_options(Opts) ->
+ proplists:normalize(Opts, [{negations, opt_negations()},
+ {aliases, opt_aliases()},
+ {expand, opt_basic_expansions()}]).
+
+-spec expand_kt2(comp_options()) -> comp_options().
+
+expand_kt2(Opts) ->
+ proplists:normalize(Opts, [{expand, [{kt2_type,
+ [{use_callgraph, fixpoint}, core,
+ {core_transform, cerl_typean}]}]}]).
+
+%% Note that set_architecture/1 must be called first, and that the given
+%% list should contain the total set of options, since things like 'o2'
+%% are expanded here. Basic expansions are processed here also, since
+%% this function is called from the help functions.
+
+-spec expand_options(comp_options()) -> comp_options().
+
+expand_options(Opts) ->
+ proplists:normalize(Opts, [{negations, opt_negations()},
+ {aliases, opt_aliases()},
+ {expand, opt_basic_expansions()},
+ {expand, opt_expansions()}]).
+
+-spec check_options(comp_options()) -> 'ok'.
+
+check_options(Opts) ->
+ Keys = ordsets:from_list(opt_keys()),
+ Used = ordsets:from_list(proplists:get_keys(Opts)),
+ case ordsets:subtract(Used, Keys) of
+ [] ->
+ ok;
+ L ->
+ ?WARNING_MSG("Unknown options: ~p.\n", [L]),
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
new file mode 100644
index 0000000000..a1fbeda9cf
--- /dev/null
+++ b/lib/hipe/main/hipe.hrl.src
@@ -0,0 +1,322 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Filename : hipe.hrl (automatically generated by hipe.hrl.src)
+%% Purpose : Defines some useful macros for debugging and error
+%% reporting.
+%%
+%% History : * 2000-11-03 Erik Johansson ([email protected]): Created.
+%% ====================================================================
+%%
+%% Defines:
+%% msg/2 - Works like io:format but prepends
+%% ?MSGTAG to the message.
+%% If LOGGING is defined then error_logger is used,
+%% or rather its substitute in code_server.
+%% untagged_msg/2 - Like msg/2 but without the tag.
+%% WARNING_MSG/2 - Prints a tagged warning.
+%% error_msg/2 - Logs a tagged error.
+%% debug_msg/2 - Prints a tagged msg if DEBUG is defined.
+%% IF_DEBUG(A,B) - Executes A if DEBUG is defined B otherwise.
+%% IF_DEBUG(Lvl,A,B) - Executes A if DEBUG is defined to a value >= Lvl
+%% otherwise B is executed.
+%% EXIT - Exits with added module and line info.
+%% ASSERT - Exits if the expresion does not evaluate to true.
+%% VERBOSE_ASSSERT - A message is printed even when an asertion is true.
+%% TIME_STMNT(Stmnt, String, FreeVar)
+%% - Times the statemnet Stmnt if TIMING is on.
+%% The execution time is bound to FreeVar.
+%% String is printed after the execution
+%% followed by the execution time in seconds and
+%% a newline.
+%%
+%% Flags:
+%% DEBUG - Turns on debugging. (Can be defined to a integer
+%% value to determine the level of debugging)
+%% VERBOSE - More info is printed...
+%% HIPE_LOGGING - Turn on logging of messages with erl_logger.
+%% DO_ASSERT - Turn on Assertions.
+%% TIMING - Turn on timing.
+%% HIPE_INSTRUMENT_COMPILER - Turn on instrumentation of the compiler.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(VERSION_STRING(),"%VSN%").
+-define(MSGTAG, "<HiPE (v " ++ ?VERSION_STRING() ++ ")> ").
+
+%%
+%% Define the message macros with or without logging,
+%% depending on the value of the HIPE_LOGGING flag.
+%%
+
+-ifdef(HIPE_LOGGING).
+-define(msg(Msg, Args),
+ code_server:info_msg(?MSGTAG ++ Msg, Args)).
+-define(untagged_msg(Msg, Args),
+ code_server:info_msg(Msg, Args)).
+-else.
+-define(msg(Msg, Args),
+ io:format(?MSGTAG ++ Msg, Args)).
+-define(untagged_msg(Msg, Args),
+ io:format(Msg, Args)).
+-endif.
+
+%%
+%% Define error and warning messages.
+%%
+-define(error_msg(Msg, Args),
+ code_server:error_msg(?MSGTAG ++
+ "Error: [~s:~w]: " ++ Msg,
+ [?MODULE,?LINE|Args])).
+-define(WARNING_MSG(Msg, Args),
+ ?msg("Warning: [~s:~w]: " ++ Msg, [?MODULE,?LINE|Args])).
+
+%%
+%% Define the macros that are dependent on the debug flag.
+%%
+
+-ifdef(DEBUG).
+-define(debug_msg(Msg,Data), ?msg(Msg,Data)).
+-define(debug_untagged_msg(Msg,Data), ?untagged_msg(Msg,Data)).
+-define(IF_DEBUG(DebugAction,NoDebugAction), DebugAction).
+-define(IF_DEBUG_LEVEL(Level,DebugAction,NoDebugAction),
+ if (Level =< ?DEBUG) -> DebugAction; true -> NoDebugAction end).
+-else.
+-define(debug_msg(Msg,Data), no_debug).
+-define(debug_untagged_msg(Msg,Data), no_debug).
+-define(IF_DEBUG(DebugAction,NoDebugAction), NoDebugAction).
+-define(IF_DEBUG_LEVEL(Level,DebugAction,NoDebugAction), NoDebugAction).
+-endif.
+
+%%
+%% Define the exit macro
+%%
+-ifdef(VERBOSE).
+-define(EXIT(Reason), erlang:error({?MODULE,?LINE,Reason})).
+-else.
+-define(EXIT(Reason),
+ ?msg("EXITED with reason ~w @~w:~w\n", [Reason,?MODULE,?LINE]),
+ erlang:error({?MODULE,?LINE,Reason})).
+-endif.
+
+%%
+%% Assertions.
+%%
+-ifdef(DO_ASSERT).
+-define(VERBOSE_ASSERT(X),
+ case X of
+ true ->
+ io:format("Assertion ok ~w ~w\n",[?MODULE,?LINE]),
+ true;
+ __ASSVAL_R ->
+ io:format("Assertion failed ~w ~w: ~p\n",
+ [?MODULE,?LINE, __ASSVAL_R]),
+ ?EXIT(assertion_failed)
+ end).
+-define(ASSERT(X),
+ case X of
+ true -> true;
+ _ -> ?EXIT(assertion_failed)
+ end).
+-else.
+-define(ASSERT(X),true).
+-define(VERBOSE_ASSERT(X),true).
+-endif.
+
+
+%% Use this to display info, save stuff and so on.
+%% Vars cannot be exported from __Action
+-define(when_option(__Opt,__Opts,__Action),
+ case proplists:get_bool(__Opt,__Opts) of
+ true -> __Action;
+ false -> ok
+ end).
+
+%% Timing macros
+
+-ifdef(TIMING).
+-define(TIME_STMNT(STMNT,Msg,Timer),
+ Timer = hipe_timing:start_timer(),
+ STMNT,
+ ?untagged_msg(Msg ++ "~.2f s\n",[hipe_timing:stop_timer(Timer)/1000])).
+-else.
+-define(TIME_STMNT(STMNT,Msg,Timer),STMNT).
+-endif.
+
+-define(start_timer(Text), hipe_timing:start(Text, ?MODULE)).
+-define(stop_timer(Text), hipe_timing:stop(Text, ?MODULE)).
+-define(start_hipe_timer(Timer), hipe_timing:start_hipe_timer(Timer)).
+-define(stop_hipe_timer(Timer), hipe_timing:stop_hipe_timer(Timer)).
+-define(get_hipe_timer_val(Timer), get(Timer)).
+-define(set_hipe_timer_val(Timer, Val), put(Timer, Val)).
+-define(option_time(Stmnt, Text, Options),
+ if true -> ?when_option(time, Options, ?start_timer(Text)),
+ fun(R) ->
+ ?when_option(time, Options, ?stop_timer(Text)),
+ R
+ end(Stmnt)end).
+
+-define(option_start_time(Text,Options),
+ ?when_option(time, Options, ?start_timer(Text))).
+
+-define(option_stop_time(Text,Options),
+ ?when_option(time, Options, ?stop_timer(Text))).
+
+-define(opt_start_timer(Text),
+ hipe_timing:start_optional_timer(Text,?MODULE)).
+-define(opt_stop_timer(Text),
+ hipe_timing:stop_optional_timer(Text,?MODULE)).
+
+%%
+%% Turn on instrumentation of the compiler.
+%%
+-ifdef(HIPE_INSTRUMENT_COMPILER).
+
+-define(count_pre_ra_instructions(Options, NoInstrs),
+ ?when_option(count_instrs, Options,
+ put(pre_ra_instrs,
+ get(pre_ra_instrs)+ NoInstrs))).
+-define(count_post_ra_instructions(Options, NoInstrs),
+ ?when_option(count_instrs, Options,
+ put(post_ra_instrs,
+ get(post_ra_instrs)+ NoInstrs))).
+
+-define(start_time_regalloc(Options),
+ ?when_option(timeregalloc, Options,
+ put(regalloctime1,erlang:statistics(runtime)))).
+-define(stop_time_regalloc(Options),
+ ?when_option(timeregalloc, Options,
+ put(regalloctime,
+ get(regalloctime) +
+ (element(1,erlang:statistics(runtime))
+ -element(1,get(regalloctime1)))))).
+-define(start_time_caller_saves(Options),
+ ?when_option(timeregalloc, Options,
+ put(callersavetime1,erlang:statistics(runtime)))).
+-define(stop_time_caller_saves(Options),
+ ?when_option(timeregalloc, Options,
+ put(callersavetime,
+ get(callersavetime) +
+ (element(1,erlang:statistics(runtime))
+ -element(1,get(callersavetime1)))))).
+
+-define(count_pre_ra_temps(Options, NoTemps),
+ ?when_option(count_temps, Options,
+ put(pre_ra_temps,
+ get(pre_ra_temps)+ NoTemps))).
+-define(count_post_ra_temps(Options, NoTemps),
+ ?when_option(count_temps, Options,
+ put(post_ra_temps,
+ get(post_ra_temps)+ NoTemps))).
+
+-define(inc_counter(Counter, Val),
+ case get(Counter) of
+ undefined -> true;
+ _ -> put(Counter, Val + get(Counter))
+ end).
+
+-define(cons_counter(Counter, Val),
+ case get(Counter) of
+ undefined -> true;
+ _ -> put(Counter, [Val|get(Counter)])
+ end).
+
+-define(update_counter(Counter, Val, Op),
+ case get(Counter) of
+ undefined -> true;
+ _ -> put(Counter, get(Counter) Op Val)
+ end).
+
+-define(start_ra_instrumentation(Options, NoInstrs, NoTemps),
+ begin
+ ?count_pre_ra_instructions(Options, NoInstrs),
+ ?count_pre_ra_temps(Options, NoTemps),
+ case get(counter_mem_temps) of
+ undefined -> true;
+ _ -> put(counter_mfa_mem_temps,[])
+ end,
+ ?start_time_regalloc(Options)
+ end).
+-define(stop_ra_instrumentation(Options, NoInstrs, NoTemps),
+ begin
+ ?stop_time_regalloc(Options),
+ ?count_post_ra_instructions(Options, NoInstrs),
+ ?cons_counter(counter_mem_temps, get(counter_mfa_mem_temps)),
+ ?cons_counter(ra_all_iterations_counter, get(ra_iteration_counter)),
+ put(ra_iteration_counter,0),
+ ?count_post_ra_temps(Options, NoTemps)
+ end).
+
+-define(add_spills(Options, NoSpills),
+ ?when_option(count_spills, Options,
+ put(spilledtemps, get(spilledtemps) + NoSpills))).
+
+-define(optional_start_timer(Timer, Options),
+ case lists:member(Timer, proplists:get_value(timers,Options++[{timers,[]}])) of
+ true -> ?start_hipe_timer(Timer);
+ false -> true
+ end).
+-define(optional_stop_timer(Timer, Options),
+ case lists:member(Timer, proplists:get_value(timers,Options++[{timers,[]}])) of
+ true -> ?stop_hipe_timer(Timer);
+ false -> true
+ end).
+
+-else. %% HIPE_INSTRUMENT_COMPILER
+
+-define(count_pre_ra_instructions(Options, NoInstrs), no_instrumentation).
+-define(count_post_ra_instructions(Options, NoInstrs),no_instrumentation).
+-define(start_time_regalloc(Options), no_instrumentation).
+-define(stop_time_regalloc(Options), no_instrumentation).
+-define(start_time_caller_saves(Options), no_instrumentation).
+-define(stop_time_caller_saves(Options), no_instrumentation).
+-define(count_pre_ra_temps(Options, NoTemps), no_instrumentation).
+-define(count_post_ra_temps(Options, NoTemps), no_instrumentation).
+-define(start_ra_instrumentation(Options, NoInstrs, NoTemps),no_instrumentation).
+-define(stop_ra_instrumentation(Options, NoInstrs, NoTemps),no_instrumentation).
+-define(add_spills(Options, NoSpills), no_instrumentation).
+-define(optional_start_timer(Options, Timer), no_instrumentation).
+-define(optional_stop_timer(Options, Timer), no_instrumentation).
+-define(inc_counter(Counter, Val), no_instrumentation).
+-define(update_counter(Counter, Val, Op), no_instrumentation).
+-define(cons_counter(Counter, Val), no_instrumentation).
+
+-endif. %% HIPE_INSTRUMENT_COMPILER
+
+%%----------------------------------------------------------------------------
+%% Records defined in the hipe module used in other parts of the compiler
+%%----------------------------------------------------------------------------
+
+-record(comp_servers, {pp_server :: pid(), range :: pid(), type :: pid()}).
+
+%%----------------------------------------------------------------------------
+%% Basic types of the 'hipe' application used in other parts of the system
+%%----------------------------------------------------------------------------
+
+-type comp_option() :: atom() | {atom(), atom()}.
+-type comp_options() :: [comp_option()].
+
+-type hipe_architecture() ::
+ 'amd64' | 'arm' | 'powerpc' | 'ppc64' | 'ultrasparc' | 'x86'.
+
+-type hipe_map() :: [{non_neg_integer(),
+ 'unknown' | {'reg' | 'fp_reg' | 'spill',
+ non_neg_integer()}}].
+-type hipe_temp_map() :: tuple().
+-type hipe_spill_map() :: [{non_neg_integer(), {'spill',non_neg_integer()}}].
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
new file mode 100644
index 0000000000..fe9bc83fd2
--- /dev/null
+++ b/lib/hipe/main/hipe_main.erl
@@ -0,0 +1,549 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% @doc This is the HiPE compiler's main "loop".
+%%
+%% <h3>Purpose</h3>
+%%
+%% <p> This module provides code which compiles a single Erlang
+%% function, represented as linear ICode all the way down to a linear
+%% native code representation (which depends on the 'hipe_target_arch'
+%% global variable). </p>
+%%
+%% @end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%=====================================================================
+
+-module(hipe_main).
+-export([compile_icode/4]).
+
+%%=====================================================================
+
+-ifndef(DEBUG).
+-define(DEBUG,1).
+-endif.
+
+-define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
+
+-include("hipe.hrl").
+-include("../icode/hipe_icode.hrl").
+%%-include("../rtl/hipe_rtl.hrl").
+
+%%=====================================================================
+
+-type comp_icode_ret() :: {'native',hipe_architecture(),{'unprofiled',_}}
+ | {'rtl',tuple()}.
+
+%%=====================================================================
+
+%% @spec compile_icode(MFA::mfa(),
+%% LinearIcode::#icode{},
+%% CompilerOptions::comp_options(),
+%% CompServers::#comp_servers()) ->
+%% {native,Platform,{unprofiled,NativeCode}} | {rtl,RTLCode}
+%%
+%% @doc Compiles the Icode (in linear form) of a single MFA down to
+%% native code for the platform of the target architecture.
+%% CompilerOptions influence the steps of this compilation process.
+%%
+%% <p> In particular, the compiler option '<code>to_rtl</code>' stops
+%% compilation after translation to RTL (in which case RTL code is
+%% generated). The compiler options must have already been expanded
+%% (cf. `<a href="hipe.html">hipe:expand_options</a>'). </p>
+
+-spec compile_icode(mfa(), #icode{}, comp_options(), #comp_servers{}) ->
+ comp_icode_ret().
+
+compile_icode(MFA, LinearIcode, Options, Servers) ->
+ compile_icode(MFA, LinearIcode, Options, Servers, get(hipe_debug)).
+
+%%--------------------------------------------------------------------
+%%
+%% The following constraints apply to the passes on Icode:
+%%
+%% 1. The no_comment pass must be done on linear form;
+%%
+%% 2. linear_to_cfg, which turns linear form into a CFG, must be
+%% performed before any of the passes on CFG form;
+%%
+%% 3. handle_exceptions must be performed before icode_ssa;
+%%
+%% 4. split_arith should be performed after icode_ssa for
+%% effectiveness reasons (and perhaps to work at all);
+%%
+%% 5. remove_trivial_bbs should be performed last to tidy up the CFG.
+%%
+%%---------------------------------------------------------------------
+
+compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
+ %% Set up gensym with the right ranges for this function.
+ {LMin,LMax} = hipe_icode:icode_label_range(LinearIcode0),
+ hipe_gensym:set_label_range(icode, LMin, LMax+1),
+ {VMin,VMax} = hipe_icode:icode_var_range(LinearIcode0),
+ hipe_gensym:set_var_range(icode, VMin, VMax+1),
+ %%hipe_icode_pp:pp(LinearIcode0),
+ ?opt_start_timer("Icode"),
+ LinearIcode1 = icode_no_comment(LinearIcode0, Options),
+ IcodeCfg0 = icode_linear_to_cfg(LinearIcode1, Options),
+ %%hipe_icode_cfg:pp(IcodeCfg1),
+ IcodeCfg1 = icode_handle_exceptions(IcodeCfg0, MFA, Options),
+ IcodeCfg3 = icode_inline_bifs(IcodeCfg1, Options),
+ pp(IcodeCfg3, MFA, icode, pp_icode, Options, Servers),
+ IcodeCfg4 = icode_ssa(IcodeCfg3, MFA, Options, Servers),
+ IcodeCfg5 = icode_split_arith(IcodeCfg4, MFA, Options),
+ pp(IcodeCfg5, MFA, icode, pp_icode_split_arith, Options, Servers),
+ IcodeCfg6 = icode_heap_test(IcodeCfg5, Options),
+ IcodeCfg7 = icode_remove_trivial_bbs(IcodeCfg6, Options),
+ pp(IcodeCfg7, MFA, icode, pp_opt_icode, Options, Servers),
+ pp(IcodeCfg7, MFA, icode_liveness, pp_icode_liveness, Options, Servers),
+ FinalIcode = hipe_icode_cfg:cfg_to_linear(IcodeCfg7),
+ ?opt_stop_timer("Icode"),
+ LinearRTL = ?option_time(icode_to_rtl(MFA,FinalIcode,Options, Servers),
+ "RTL", Options),
+ case proplists:get_bool(to_rtl, Options) of
+ false ->
+ rtl_to_native(MFA, LinearRTL, Options, DebugState);
+ true ->
+ put(hipe_debug, DebugState),
+ {rtl, LinearRTL}
+ end.
+
+%%----------------------------------------------------------------
+%%
+%% Icode passes
+%%
+%%----------------------------------------------------------------
+
+icode_no_comment(LinearIcode, Options) ->
+ case proplists:get_bool(remove_comments, Options) of
+ true ->
+ ?option_time(hipe_icode:strip_comments(LinearIcode),
+ "Icode remove comments", Options);
+ _ ->
+ LinearIcode
+ end.
+
+icode_linear_to_cfg(LinearIcode, Options) ->
+ ?option_time(hipe_icode_cfg:linear_to_cfg(LinearIcode),
+ "transform linear Icode to CFG", Options).
+
+icode_ssa_binary_pass(IcodeSSA, Options) ->
+ case proplists:get_bool(binary_opt, Options) of
+ true ->
+ ?option_time(hipe_icode_bincomp:cfg(IcodeSSA),
+ "Icode binary pass", Options);
+ false ->
+ IcodeSSA
+ end.
+
+icode_handle_exceptions(IcodeCfg, MFA, Options) ->
+ debug("Icode fix catches: ~w~n", [MFA], Options),
+ ?option_time(hipe_icode_exceptions:fix_catches(IcodeCfg),
+ "Icode fix catches", Options).
+
+icode_inline_bifs(IcodeCfg, Options) ->
+ case proplists:get_bool(icode_inline_bifs, Options) of
+ true ->
+ ?option_time(hipe_icode_inline_bifs:cfg(IcodeCfg),
+ "Icode inline bifs", Options);
+ false ->
+ IcodeCfg
+ end.
+
+%%---------------------------------------------------------------------
+
+icode_split_arith(IcodeCfg, MFA, Options) ->
+ case proplists:get_bool(split_arith, Options) orelse
+ proplists:get_bool(split_arith_unsafe, Options) of
+ true ->
+ ?option_time(hipe_icode_split_arith:cfg(IcodeCfg, MFA, Options),
+ "Icode split arith", Options);
+ false ->
+ IcodeCfg
+ end.
+
+icode_heap_test(IcodeCfg, Options) ->
+ ?option_time(hipe_icode_heap_test:cfg(IcodeCfg),
+ "Icode heap_test", Options).
+
+icode_remove_trivial_bbs(IcodeCfg, Options) ->
+ ?option_time(hipe_icode_cfg:remove_trivial_bbs(IcodeCfg),
+ "Icode trivial BB removal", Options).
+
+pp(Cfg, MFA, Level, PrintOption, Options, Servers) ->
+ perform_io(pp_fun(Cfg, MFA, get_pp_module(Level),
+ proplists:get_value(PrintOption, Options)),
+ Servers#comp_servers.pp_server).
+
+pp_fun(Cfg, MFA, PP, PrintOptionValue) ->
+ case PrintOptionValue of
+ true ->
+ fun() -> PP:pp(Cfg) end;
+ {only, Lst} when is_list(Lst) ->
+ case lists:member(MFA, Lst) of
+ true ->
+ fun() -> PP:pp(Cfg) end;
+ false ->
+ no_fun
+ end;
+ {only, MFA} ->
+ fun() -> PP:pp(Cfg) end;
+ {file, FileName} ->
+ fun() ->
+ {ok, File} = file:open(FileName, [write,append]),
+ PP:pp(File, Cfg),
+ file:close(File)
+ end;
+ _ ->
+ no_fun
+ end.
+
+get_pp_module(icode) -> hipe_icode_cfg;
+get_pp_module(rtl) -> hipe_rtl_cfg;
+get_pp_module(rtl_linear) -> hipe_rtl;
+get_pp_module(icode_liveness) -> hipe_icode_liveness;
+get_pp_module(rtl_liveness) -> hipe_rtl_liveness.
+
+perform_io(no_fun, _) -> ok;
+perform_io(Fun,PPServer) when is_pid(PPServer) ->
+ PPServer ! {print,Fun};
+perform_io(Fun, undefined) ->
+ Fun().
+
+
+%%--------------------------------------------------------------------
+%%
+%% Icode passes on SSA form. The following constraints are applicable:
+%%
+%% 1. ssa_convert must be first and ssa_unconvert last
+%%
+%% 2. ssa_dead_code must be run after the other passes
+%%
+%% 3. The present order was chosen to maximize effectiveness as
+%% ssa_const_prop might make ssa_type_info more effective
+%%
+%% 4. ssa_check could be put in between all passes to make sure that
+%% they preserve SSA-ness
+%%
+%%---------------------------------------------------------------------
+
+icode_ssa(IcodeCfg0, MFA, Options, Servers) ->
+ ?opt_start_timer("Icode SSA passes"),
+ IcodeSSA0 = icode_ssa_convert(IcodeCfg0, Options),
+ pp(IcodeSSA0, MFA, icode, pp_icode_ssa, Options, Servers),
+ IcodeSSA1 = icode_ssa_const_prop(IcodeSSA0, Options),
+ IcodeSSA2 = icode_ssa_dead_code_elimination(IcodeSSA1, Options),
+ IcodeSSA3 = icode_ssa_copy_prop(IcodeSSA2, Options),
+ IcodeSSA3a = icode_ssa_binary_pass(IcodeSSA3, Options),
+ IcodeSSA4 = icode_ssa_type(IcodeSSA3a, MFA, Options, Servers),
+ IcodeSSA5 = icode_ssa_dead_code_elimination(IcodeSSA4, Options),
+ IcodeSSA6 = icode_ssa_struct_reuse(IcodeSSA5, Options),
+ icode_ssa_check(IcodeSSA6, Options), %% just for sanity
+ pp(IcodeSSA6, MFA, icode, pp_icode_ssa, Options, Servers),
+ IcodeCfg = icode_ssa_unconvert(IcodeSSA6, Options),
+ ?opt_stop_timer("Icode SSA passes"),
+ IcodeCfg.
+
+icode_ssa_type(IcodeSSA, MFA, Options, Servers) ->
+ case proplists:get_value(icode_type, Options) of
+ false -> IcodeSSA;
+ undefined -> IcodeSSA;
+ true ->
+ AnnIcode1 = icode_ssa_type_info(IcodeSSA, MFA, Options, Servers),
+ pp(AnnIcode1, MFA, icode, pp_typed_icode, Options, Servers),
+ AnnIcode2 =
+ case proplists:get_bool(inline_fp, Options) of
+ true -> hipe_icode_fp:cfg(AnnIcode1);
+ false -> AnnIcode1
+ end,
+ AnnIcode3 = icode_range_analysis(AnnIcode2, MFA, Options, Servers),
+ pp(AnnIcode3, MFA, icode, pp_range_icode, Options, Servers),
+ hipe_icode_type:unannotate_cfg(AnnIcode3)
+ end.
+
+icode_ssa_convert(IcodeCfg, Options) ->
+ ?option_time(hipe_icode_ssa:convert(IcodeCfg),
+ "Icode SSA conversion", Options).
+
+icode_ssa_const_prop(IcodeSSA, Options) ->
+ case proplists:get_bool(icode_ssa_const_prop, Options) of
+ true ->
+ ?option_time(Tmp=hipe_icode_ssa_const_prop:propagate(IcodeSSA),
+ "Icode SSA sparse conditional constant propagation", Options),
+ ?option_time(hipe_icode_ssa:remove_dead_code(Tmp),
+ "Icode SSA dead code elimination pass 1", Options);
+ false ->
+ IcodeSSA
+ end.
+
+icode_ssa_copy_prop(IcodeSSA, Options) ->
+ case proplists:get_bool(icode_ssa_copy_prop, Options) of
+ true ->
+ ?option_time(hipe_icode_ssa_copy_prop:cfg(IcodeSSA),
+ "Icode SSA copy propagation", Options);
+ false ->
+ IcodeSSA
+ end.
+
+icode_ssa_struct_reuse(IcodeSSA, Options) ->
+ case proplists:get_value(icode_ssa_struct_reuse, Options) of
+ true ->
+ ?option_time(hipe_icode_ssa_struct_reuse:struct_reuse(IcodeSSA),
+ "Icode SSA structure reuse", Options);
+ _ ->
+ IcodeSSA
+ end.
+
+icode_ssa_type_info(IcodeSSA, MFA, Options, Servers) ->
+ ?option_time(hipe_icode_type:cfg(IcodeSSA, MFA, Options, Servers),
+ "Icode SSA type info", Options).
+
+icode_range_analysis(IcodeSSA, MFA, Options, Servers) ->
+ case proplists:get_bool(icode_range, Options) of
+ true ->
+ ?option_time(hipe_icode_range:cfg(IcodeSSA, MFA, Options, Servers),
+ "Icode SSA integer range analysis", Options);
+ false ->
+ IcodeSSA
+ end.
+
+icode_ssa_dead_code_elimination(IcodeSSA, Options) ->
+ IcodeSSA1 = ?option_time(hipe_icode_ssa:remove_dead_code(IcodeSSA),
+ "Icode SSA dead code elimination pass 2",
+ Options),
+ hipe_icode_cfg:remove_unreachable_code(IcodeSSA1).
+
+icode_ssa_check(IcodeSSA, Options) ->
+ ?when_option(icode_ssa_check, Options,
+ ?option_time(hipe_icode_ssa:check(IcodeSSA),
+ "Icode check for SSA-ness", Options)).
+
+icode_ssa_unconvert(IcodeSSA, Options) ->
+ ?option_time(hipe_icode_ssa:unconvert(IcodeSSA),
+ "Icode SSA unconversion", Options).
+
+
+%%=====================================================================
+%%
+%% @spec icode_to_rtl(MFA::mfa(), Icode, options()) -> Linear_RTL_code
+%% @end
+%%=====================================================================
+
+%%---------------------------------------------------------------------
+%%
+%% The passes on RTL are as follows:
+%%
+%% 1. The translation to RTL, in particular the way exceptions are
+%% currently handled in RTL, introduces some unreachable code.
+%% Therefore, unreachable code is removed early on followed by a
+%% pass that removes trivial basic blocks so as to have smaller
+%% code to play with.
+%%
+%% 2. Code is then converted to SSA so as to perform as many
+%% optimizations as possible in this pass.
+%% Currently, the following optimizations are performed on SSA:
+%% - sparse conditional constant propagation (controlled by an option)
+%% - dead code elimination
+%% - detection of available exceptions
+%% - partial redundancy elimination (controlled by an option)
+%% Finally, code is converted back to non-SSA form.
+%%
+%% 3. rtl_symbolic expands some symbolic instructions.
+%%
+%% 4. rtl_lcm performs a lazy code motion on RTL.
+%%
+%%----------------------------------------------------------------------
+
+icode_to_rtl(MFA, Icode, Options, Servers) ->
+ debug("ICODE -> RTL: ~w, ~w~n", [MFA, hash(Icode)], Options),
+ LinearRTL = translate_to_rtl(Icode, Options),
+ pp(LinearRTL, MFA, rtl_linear, pp_rtl_linear, Options, Servers),
+ RtlCfg = initialize_rtl_cfg(LinearRTL, Options),
+ %% hipe_rtl_cfg:pp(RtlCfg),
+ RtlCfg0 = hipe_rtl_cfg:remove_unreachable_code(RtlCfg),
+ RtlCfg1 = hipe_rtl_cfg:remove_trivial_bbs(RtlCfg0),
+ %% hipe_rtl_cfg:pp(RtlCfg1),
+ RtlCfg2 = rtl_ssa(RtlCfg1, Options),
+ RtlCfg3 = rtl_symbolic(RtlCfg2, Options),
+ %% hipe_rtl_cfg:pp(RtlCfg3),
+ pp(RtlCfg3, MFA, rtl_liveness, pp_rtl_liveness, Options, Servers),
+ RtlCfg4 = rtl_lcm(RtlCfg3, Options),
+ pp(RtlCfg4, MFA, rtl, pp_rtl, Options, Servers),
+ LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg4),
+ LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
+ %% hipe_rtl:pp(standard_io, LinearRTL2),
+ LinearRTL2.
+
+translate_to_rtl(Icode, Options) ->
+ %% GC tests should have been added in the conversion to Icode.
+ ?option_time(hipe_icode2rtl:translate(Icode, Options),
+ "translate", Options).
+
+initialize_rtl_cfg(LinearRTL, Options) ->
+ ?option_time(hipe_rtl_cfg:init(LinearRTL), "to cfg", Options).
+
+rtl_symbolic(RtlCfg, Options) ->
+ ?option_time(hipe_rtl_symbolic:expand(RtlCfg),
+ "Expansion of symbolic instructions", Options).
+
+%%----------------------------------------------------------------------
+%%
+%% RTL passes on SSA form. The following constraints are applicable:
+%%
+%% 1. ssa_convert must be first and ssa_unconvert last.
+%%
+%% 2. dead_code_elimination should be performed after conditional
+%% constant propagation in order to cleanup dead code that might
+%% be created by that pass.
+%%
+%% 3. avail_expr ... (PER ADD THIS)
+%%
+%% 4. rtl_ssapre performs A-SSAPRE and has to be done after all other
+%% optimizations.
+%%
+%% 5. ssa_check could be put in between all passes to make sure that
+%% they preserve SSA-ness.
+%%
+%%----------------------------------------------------------------------
+
+rtl_ssa(RtlCfg0, Options) ->
+ case proplists:get_bool(rtl_ssa, Options) of
+ true ->
+ ?opt_start_timer("RTL SSA passes"),
+ RtlSSA0 = rtl_ssa_convert(RtlCfg0, Options),
+ RtlSSA1 = rtl_ssa_const_prop(RtlSSA0, Options),
+ %% RtlSSA1a = rtl_ssa_copy_prop(RtlSSA1, Options),
+ RtlSSA2 = rtl_ssa_dead_code_elimination(RtlSSA1, Options),
+ RtlSSA3 = rtl_ssa_avail_expr(RtlSSA2, Options),
+ RtlSSA4 = rtl_ssapre(RtlSSA3, Options),
+ %% rtl_ssa_check(RtlSSA4, Options), %% just for sanity
+ RtlCfg = rtl_ssa_unconvert(RtlSSA4, Options),
+ case proplists:get_bool(pp_rtl_ssa, Options) of
+ true ->
+ io:format("%%------------- After SSA un-conversion -----------\n"),
+ hipe_rtl_cfg:pp(RtlCfg);
+ false ->
+ ok
+ end,
+ ?opt_stop_timer("RTL SSA passes"),
+ RtlCfg;
+ false ->
+ RtlCfg0
+ end.
+
+rtl_ssa_convert(RtlCfg, Options) ->
+ case proplists:get_bool(pp_rtl_ssa, Options) of
+ true ->
+ io:format("%%------------- Before SSA conversion --------------\n"),
+ hipe_rtl_cfg:pp(RtlCfg),
+ io:format("%%------------- After SSA conversion --------------\n"),
+ RtlCfgSSA = hipe_rtl_ssa:convert(RtlCfg),
+ hipe_rtl_cfg:pp(RtlCfgSSA),
+ io:format("%%------------- SSA check warnings below -----------\n"),
+ hipe_rtl_ssa:check(RtlCfgSSA),
+ RtlCfgSSA;
+ false ->
+ ?option_time(hipe_rtl_ssa:convert(RtlCfg),
+ "RTL SSA conversion", Options)
+ end.
+
+rtl_ssa_const_prop(RtlCfgSSA, Options) ->
+ case proplists:get_bool(rtl_ssa_const_prop, Options) of
+ true ->
+ ?option_time(hipe_rtl_ssa_const_prop:propagate(RtlCfgSSA),
+ "RTL SSA sparse conditional constant propagation", Options);
+ false ->
+ RtlCfgSSA
+ end.
+
+rtl_ssa_dead_code_elimination(RtlCfgSSA, Options) ->
+ ?option_time(hipe_rtl_ssa:remove_dead_code(RtlCfgSSA),
+ "RTL SSA dead code elimination", Options).
+
+rtl_ssa_avail_expr(RtlCfgSSA, Options) ->
+ ?option_time(hipe_rtl_ssa_avail_expr:cfg(RtlCfgSSA),
+ "RTL SSA heap optimizations", Options).
+
+%%---------------------------------------------------------------------
+
+rtl_ssapre(RtlCfg, Options) ->
+ case proplists:get_bool(rtl_ssapre, Options) of
+ true ->
+ ?opt_start_timer("Partial Redundancy Elimination (A-SSAPRE)"),
+ NewRtlCfg = hipe_rtl_ssapre:rtl_ssapre(RtlCfg, Options),
+ ?opt_stop_timer("Partial Redundancy Elimination (A-SSAPRE)"),
+ NewRtlCfg;
+ false ->
+ RtlCfg
+ end.
+
+%%---------------------------------------------------------------------
+
+rtl_ssa_unconvert(RtlCfgSSA, Options) ->
+ ?option_time(hipe_rtl_ssa:unconvert(RtlCfgSSA),
+ "RTL SSA un-convert", Options).
+
+%%---------------------------------------------------------------------
+
+rtl_lcm(RtlCfg, Options) ->
+ case proplists:get_bool(rtl_lcm, Options) of
+ true ->
+ ?opt_start_timer("RTL lazy code motion"),
+ %% ?option_time(hipe_rtl_lcm:rtl_lcm(RtlCfg, Options),
+ %% "RTL lazy code motion", Options);
+ RtlCfg1 = hipe_rtl_lcm:rtl_lcm(RtlCfg, Options),
+ ?opt_stop_timer("RTL lazy code motion"),
+ RtlCfg1;
+ false ->
+ RtlCfg
+ end.
+
+%%=====================================================================
+%% Translation to native code takes place in the corresponding back-end
+%%=====================================================================
+
+rtl_to_native(MFA, LinearRTL, Options, DebugState) ->
+ ?opt_start_timer("Native code"),
+ LinearNativeCode =
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_main:rtl_to_sparc(MFA, LinearRTL, Options);
+ powerpc ->
+ hipe_ppc_main:rtl_to_ppc(MFA, LinearRTL, Options);
+ arm ->
+ hipe_arm_main:rtl_to_arm(MFA, LinearRTL, Options);
+ x86 ->
+ hipe_x86_main:rtl_to_x86(MFA, LinearRTL, Options);
+ amd64 ->
+ hipe_amd64_main:rtl_to_amd64(MFA, LinearRTL, Options)
+ end,
+ ?opt_stop_timer("Native code"),
+ put(hipe_debug, DebugState),
+ LinearNativeCode.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Debugging stuff ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+debug(Text, Args, Options) ->
+ ?when_option(debug, Options, ?msg(Text,Args)).
+
+hash(X) ->
+ erlang:phash(X, 16#7f3f5f1).