# backend-lowhalf-g.pkg
#
# From a compiletime perspective, this file is a generic
# generic that hooks everything together into
# a lowhalf code generator -- a complete compiler backend
# lower half.
#
# From a runtime perspective, this file is (generates) the
# heart of the back end, namely the driver code that
# accepts intermediate code from the backend upper half in
# machcode-controlflow-graph format and applies to it the requested
# compiler passes in the requested order.
#
# For a higher-level overview, see
#
# src/A.COMPILER-PASSES.OVERVIEW
#
#
#
#
#
# Runtime invocation of our (sole) entrypoint
#
# translate_nextcode_to_execode
#
# is from
#
#
src/lib/compiler/back/top/main/backend-tophalf-g.pkg#
# We do a smidgen of setup work and then pass the buck to
#
# f2x::translate_nextcode_to_execode
#
# in
#
#
src/lib/compiler/back/low/main/main/translate-nextcode-to-treecode-g.pkg#
# which does the bulk of the work of translating intermediate code
# from nextcode (upper half) format into
# machcode-controlflow-graph (lower half) format, and then passes the buck
# back to us via our
#
# translate_machcode_cccomponent_to_execode
#
# callback.
# Compiled by:
#
src/lib/compiler/core.sublib### "He is able who thinks he is able."
###
### -- Gautama Buddha (563-483 BCE)
# We are invoked from:
#
#
src/lib/compiler/back/low/main/intel32/backend-lowhalf-intel32-g.pkg#
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg#
src/lib/compiler/back/low/main/sparc32/backend-lowhalf-sparc32.pkgstipulate
package cos = compile_statistics; # compile_statistics is from
src/lib/compiler/front/basics/stats/compile-statistics.pkg package ds = deep_syntax; # deep_syntax is from
src/lib/compiler/front/typer-stuff/deep-syntax/deep-syntax.pkg package lbl = codelabel; # codelabel is from
src/lib/compiler/back/low/code/codelabel.pkg package lhn = lowhalf_notes; # lowhalf_notes is from
src/lib/compiler/back/low/code/lowhalf-notes.pkg package odg = oop_digraph; # oop_digraph is from
src/lib/graph/oop-digraph.pkg# package pcs = per_compile_stuff; # per_compile_stuff is from
src/lib/compiler/front/typer-stuff/main/per-compile-stuff.pkg package pp = standard_prettyprinter; # standard_prettyprinter is from
src/lib/prettyprint/big/src/standard-prettyprinter.pkg package cv = compiler_verbosity; # compiler_verbosity is from
src/lib/compiler/front/basics/main/compiler-verbosity.pkg Npp = pp::Npp; # Null_Or(pp::Prettyprinter)
herein
#
# Our compiletime generic invocations are once each from
# the various backend implementations:
#
#
src/lib/compiler/back/low/main/intel32/backend-lowhalf-intel32-g.pkg #
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg #
src/lib/compiler/back/low/main/sparc32/backend-lowhalf-sparc32.pkg #
generic package backend_lowhalf_g (
# ================= # machine_properties_intel32 is from
src/lib/compiler/back/low/main/intel32/machine-properties-intel32.pkg # # machine_properties_pwrpc32 is from
src/lib/compiler/back/low/main/pwrpc32/machine-properties-pwrpc32.pkg # # machine_properties_sparc32 is from
src/lib/compiler/back/low/main/sparc32/machine-properties-sparc32.pkg package mp: Machine_Properties; # Machine_Properties is from
src/lib/compiler/back/low/main/main/machine-properties.api # pwrpc32 uses: # treecode_extension_mythryl is from
src/lib/compiler/back/low/main/nextcode/treecode-extension-mythryl.pkg # treecode_extension_sparc32 is from
src/lib/compiler/back/low/main/sparc32/treecode-extension-sparc32.pkg # treecode_extension_intel32 is from
src/lib/compiler/back/low/main/intel32/treecode-extension-intel32.pkg package trx: Treecode_Extension_Mythryl; # Treecode_Extension_Mythryl is from
src/lib/compiler/back/low/main/nextcode/treecode-extension-mythryl.api # machcode_universals_pwrpc32 is from
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg # machcode_universals_sparc32 is from
src/lib/compiler/back/low/main/sparc32/backend-lowhalf-sparc32.pkg # machcode_universals_intel32 is from
src/lib/compiler/back/low/main/intel32/backend-lowhalf-intel32-g.pkg package mu: Machcode_Universals; # Machcode_Universals is from
src/lib/compiler/back/low/code/machcode-universals.api # platform_register_info_sparc32 is from
src/lib/compiler/back/low/main/sparc32/backend-lowhalf-sparc32.pkg # platform_register_info_pwrpw32 is from
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg # platform_register_info_intel32 is from
src/lib/compiler/back/low/main/intel32/backend-lowhalf-intel32-g.pkg package pri: Platform_Register_Info # Platform_Register_Info is from
src/lib/compiler/back/low/main/nextcode/platform-register-info.api where #
tcf::rgn == nextcode_ramregions # "rgn" == "region"
also tcf::lac == late_constant # late_constant is from
src/lib/compiler/back/low/main/nextcode/late-constant.pkg also tcf::trx == trx; # "trx" == "treecode_extension".
# "tcf" == "treecode_form".
package cpo: Client_Pseudo_Ops_Mythryl; # Client_Pseudo_Ops_Mythryl is from
src/lib/compiler/back/low/main/nextcode/client-pseudo-ops-mythryl.api package pop: Pseudo_Ops # Pseudo_Ops is from
src/lib/compiler/back/low/mcg/pseudo-op.api where # "pop" == "pseudo_ops".
tcf == pri::tcf # "tcf" == "treecode_form".
also cpo == cpo; # "cpo" == "client_pseudo_ops".
package t2m: Translate_Treecode_To_Machcode # Translate_Treecode_To_Machcode is from
src/lib/compiler/back/low/treecode/translate-treecode-to-machcode.api where # "t2m" == "translate_treecode_to_machcode".
mcf == mu::mcf # "mcf" == "machcode_form" (abstract machine code).
also tcs::tcf == pri::tcf # "tcf" == "treecode_form".
also tcs::cst::pop == pop; # "pop" == "pseudo_ops".
package ae: Machcode_Codebuffer_Pp # Machcode_Codebuffer_Pp is from
src/lib/compiler/back/low/emit/machcode-codebuffer-pp.api where
cst::pop == pop # "pop" == "pseudo_ops".
also mcf == t2m::mcf; # "mcf" == "machcode_form" (abstract machine code).
# Linearizing parallel copies:
#
package crm: Compile_Register_Moves # Compile_Register_Moves is from
src/lib/compiler/back/low/code/compile-register-moves.api where
mcf == ae::mcf; # "mcf" == "machcode_form" (abstract machine code).
package sja: Squash_Jumps_And_Write_Code_To_Code_Segment_Buffer # Squash_Jumps_And_Write_Code_To_Code_Segment_Buffer is from
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer.api where # "sja" == "squash_jumps_and...".
mcg == t2m::mcg; # "mcg" == "machcode_controlflow_graph".
package ra: Register_Allocator # Register_Allocator is from
src/lib/compiler/back/low/regor/register-allocator.api where # "ra" == "register_allocator" (regor).
mcg == sja::mcg; # "mcg" == "machcode_controlflow_graph".
package cal: Ccalls # Ccalls is from
src/lib/compiler/back/low/ccalls/ccalls.api where # Native C call generator.
tcf == pri::tcf; # "tcf" == "treecode_form".
package fuf: Free_Up_Framepointer_In_Machcode # Free_Up_Framepointer_In_Machcode is from
src/lib/compiler/back/low/omit-framepointer/free-up-framepointer-in-machcode.api where # "fuf" == "free_up_framepointer".
mcg == ra::mcg; # "mcg" == "machcode_controlflow_graph".
abi_variant: Null_Or( String );
)
: (weak) Backend_Lowhalf # Backend_Lowhalf is from
src/lib/compiler/back/low/main/main/backend-lowhalf.api {
# Export to client packages:
#
package ae = ae; # "ae" == "asm_emitter".
package mcg = sja::mcg; # "mcg" == "machcode_controlflow_graph".
package t2m = t2m; # "t2m" == "treecode_to_machcode".
package crm = crm; # "crm" == "compile_register_moves".
package mp = mp; # "mp" == "machine properties".
package mu = mu; # "mu" == "machcode_universals".
#
#
abi_variant = abi_variant;
stipulate
package mcf = mcg::mcf; # "mcf" == "machcode_form" (abstract machine code).
package rgk = mcf::rgk;
package tcs = t2m::tcs; # "tcs" == "treecode_stream".
herein
package pmc
=
print_machcode_controlflow_graph_g ( # print_machcode_controlflow_graph_g is from
src/lib/compiler/back/low/mcg/print-machcode-controlflow-graph-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package ae = ae; # "ae" == "asm_emitter".
);
package avu
=
machcode_controlflow_graph_viewer_g ( # machcode_controlflow_graph_viewer_g is from
src/lib/compiler/back/low/display/machcode-controlflow-graph-viewer-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package ae = ae; # "ae" == "asm_emitter".
#
package gv # "gv" == "graph_viewer".
=
graph_viewer_g ( # graph_viewer_g is from
src/lib/compiler/back/low/display/graph-viewer-g.pkg all_displays # all_displays is from
src/lib/compiler/back/low/display/all-displays.pkg );
);
package cmp # Generate instructions for parallel register moves.
= # "cmp" == "compile moves phase"
compile_register_moves_phase_g ( # compile_register_moves_phase_g is from
src/lib/compiler/back/low/mcg/compile-register-moves-phase-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package crm = crm; # "crm" == "compile_register_moves".
);
package glp # "glp" == "guess_machcode_loop_probabilities".
=
guess_machcode_loop_probabilities_g ( # guess_machcode_loop_probabilities_g is from
src/lib/compiler/back/low/frequencies/guess-machcode-loop-probabilities-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
);
package gef # "gef" == "guess execution frequencies"
=
guess_bblock_execution_frequencies_g ( # guess_bblock_execution_frequencies_g is from
src/lib/compiler/back/low/frequencies/guess-bblock-execution-frequencies-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
);
package bbo # "bbo" == "basic block ordering".
=
make_final_basic_block_order_list_g ( # make_final_basic_block_order_list_g is from
src/lib/compiler/back/low/block-placement/make-final-basic-block-order-list-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package mu = mu; # "mu" == "machcode_universals".
);
package cbp # "cbp" == "check block placement".
=
check_machcode_block_placement_g ( # check_machcode_block_placement_g is from
src/lib/compiler/back/low/block-placement/check-machcode-block-placement-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package mu = mu; # "mu" == "machcode_universals".
);
# After experimentation, some architecture-specific
# control may be needed for chain_escapes.
#
package fjj
=
forward_jumps_to_jumps_g ( # forward_jumps_to_jumps_g is from
src/lib/compiler/back/low/block-placement/forward-jumps-to-jumps-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package mu = mu; # "mu" == "machcode_universals".
#
chain_escapes = REF FALSE; # This looks like more icky thread-hostile mutable global state...?
reverse_direction = REF FALSE;
);
package ihc # Exported to client packages.
=
put_treecode_heapcleaner_calls_g ( # put_treecode_heapcleaner_calls_g is from
src/lib/compiler/back/low/main/nextcode/emit-treecode-heapcleaner-calls-g.pkg #
package pri = pri; # "pri" == "nextcode_registers".
package mp = mp; # "mp" == "machine_properties".
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package tcs = t2m::tcs; # "tcs" == "treecode_stream".
);
# This module is used to check for heapcleaner bugs.
# It is turned off by default. You can turn it on
# with the flag "check-gc", and turn on verbose debugging
# with "debug-check-gc".
#
package chc
=
check_heapcleaner_calls_g ( # check_heapcleaner_calls_g is from
src/lib/compiler/back/low/main/nextcode/check-heapcleaner-calls-g.pkg #
package ae = ae; # "ae" == "asm_emitter".
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package mu = mu; # "mu" == "machcode_universals".
package pri = pri; # "pri" == "nextcode_registers".
#
root_registers = ihc::heapcleaner_arg_registers;
);
show_graphical_view_of_machcode_controlflow_graph_after_block_placement
=
lowhalf_control::make_bool (
#
"show_graphical_view_of_machcode_controlflow_graph_after_block_placement",
"graphical view of mcg after block placement"
);
minimum_blocks_for_machcode_controlflow_graph_graphical_display
=
lowhalf_control::make_int (
#
"minimum_blocks_for_machcode_controlflow_graph_graphical_display",
"minimium threshold for size of graphical view"
);
fun replace_framepointer_uses_with_stackpointer_in_machcode_controlflow_graph # This is not an argument to generic.
#
(npp:Npp, cv: cv::Compiler_Verbosity) # Null_Or(pp::Prettyprinter)
#
(machcode_controlflow_graph as odg::DIGRAPH graph)
=
{ graph.graph_info -> mcg::GRAPH_INFO { notes, ... };
#
if (lhn::uses_virtual_framepointer.is_in *notes)
#
fuf::replace_framepointer_uses_with_stackpointer_in_machcode_controlflow_graph
{
virtual_framepointer => pri::virtual_framepointer,
machcode_controlflow_graph,
initial_fp_to_sp_delta => THE 0: Null_Or( one_word_int::Int )
};
machcode_controlflow_graph;
else
machcode_controlflow_graph;
fi;
};
fun guess_bblock_execution_frequencies (npp:Npp, cv: cv::Compiler_Verbosity) machcode_controlflow_graph
=
{ glp::guess_machcode_loop_probabilities machcode_controlflow_graph;
#
gef::guess_bblock_execution_frequencies machcode_controlflow_graph;
machcode_controlflow_graph;
};
Lowhalf_Phase
=
( String,
#
(pp::Npp, cv::Compiler_Verbosity)
-> mcg::Machcode_Controlflow_Graph
-> mcg::Machcode_Controlflow_Graph
);
fun phase x
=
cos::do_compiler_phase (cos::make_compiler_phase x);
fun make_phase (name, f)
=
(name, phase name f);
# On intel32 sja is defined in
src/lib/compiler/back/low/main/intel32/backend-lowhalf-intel32-g.pkg # in terms of squash_jumps_and_make_machinecode_bytevector_intel32_g
# squash_jumps_and_make_machinecode_bytevector_intel32_g is from
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-intel32-g.pkg # On pwrpc32 sja is defined in
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg # in terms of bacic_block_scheduler2_g
# squash_jumps_and_make_machinecode_bytevector_pwrpc32_g is from
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-pwrpc32-g.pkg # On sparc32 sja is defined in
src/lib/compiler/back/low/main/sparc32/backend-lowhalf-sparc32.pkg # in terms of squash_jumps_and_make_machinecode_bytevector_sparc32_g
# squash_jumps_and_make_machinecode_bytevector_sparc32_g is from
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-sparc32-g.pkg extract_all_code_and_data_from_acg = phase "lowhalf abstract_all_code_and_data_from_machcode_controlflow_graph" sja::extract_all_code_and_data_from_machcode_controlflow_graph;
make_final_basic_block_order_list = phase "lowhalf Block placement" bbo::make_final_basic_block_order_list;
forward_jumps_to_jumps = phase "lowhalf Jump chaining" fjj::forward_jomps_to_jumps;
guess_bblock_execution_frequencies = phase "lowhalf Compute frequencies" guess_bblock_execution_frequencies;
allocate_registers = phase "lowhalf register allocation" ra::allocate_registers;
omitfp = phase "lowhalf omit frame pointer" replace_framepointer_uses_with_stackpointer_in_machcode_controlflow_graph;
compile_register_moves = phase "lowhalf expand copies" cmp::compile_register_moves;
check_heapcleaner_calls = phase "lowhalf check heapcleaner calls" chc::check_heapcleaner_calls;
squash_jumps_and_write_all_machine_code_and_data_bytes_into_code_segment_buffer
=
phase "lowhalf squash_jumps_and_write_all_machine_code_and_data_bytes_into_code_segment_buffer"
sja::squash_jumps_and_write_all_machine_code_and_data_bytes_into_code_segment_buffer;
#
# We do not here directly invoke the squash_jumps_and_write_all_machine_code_and_data_bytes_into_code_segment_buffer
# phase; rather, it is exported per
# the Backend_Lowhalf_Core api in # Backend_Lowhalf_Core is from
src/lib/compiler/back/low/main/main/backend-lowhalf-core.api # the Backend_Lowhalf api and then # Backend_Lowhalf is from
src/lib/compiler/back/low/main/main/backend-lowhalf.api # called by backend*::harvest_code_segment
# -- for details see the comment in
#
# Squash_Jumps_And_Write_Code_To_Code_Segment_Buffer #
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer.api# ra_phase = ("allocate_registers", allocate_registers); # Never referenced, but required by
src/lib/compiler/back/low/main/main/backend-lowhalf-core.api optimizer_hook
=
REF [ ("check_heapcleaner_calls", check_heapcleaner_calls),
("guess_bblock_execution_frequencies", guess_bblock_execution_frequencies),
("allocate_registers", allocate_registers),
("omitfp", omitfp),
("compile register moves", compile_register_moves),
("check_heapcleaner_calls", check_heapcleaner_calls)
];
fun translate_machcode_cccomponent_to_execode # Callback invoked by
src/lib/compiler/back/low/main/main/translate-nextcode-to-treecode-g.pkg #
(per_compile_stuff: per_compile_stuff::Per_Compile_Stuff( ds::Declaration ))
#
(cluster: mcg::Machcode_Controlflow_Graph)
: Void
=
{
dump_blocks (run_phases (*optimizer_hook, cluster));
}
where
per_compile_stuff -> { prettyprinter_or_null => npp, compiler_verbosity => cv, ... };
case npp
#
NULL => ();
#
THE pp
=>
if cv.pprint_machcode_controlflow_graph
#
pp.txt "\n\n\n(Following printed by src/lib/compiler/back/low/main/main/backend-lowhalf-g.pkg.)\n";
pp.txt "\n\nMachcode_Controlflow_Graph form:\n";
pmc::maybe_prettyprint_machcode_controlflow_graph
npp
"Initial control flow graph"
cluster;
pp.flush ();
fi;
esac;
fun run_phases ([], cluster)
=>
cluster;
run_phases ((_, f) ! phases, cluster)
=>
run_phases (phases, f (npp, cv) cluster);
end;
fun dump_blocks machcode_controlflow_graph
=
{ my (machcode_controlflow_graph, bblocks) # 'bblocks' is final list of all basic blocks in selected concatenation order.
=
forward_jumps_to_jumps # If a jump just jumps to another jump, save an instruction by jumping directly to final destination.
#
(make_final_basic_block_order_list # Pick the basic block ordering that looks fastest -- jumps between consecutive bblocks in memory can be eliminated.
#
machcode_controlflow_graph
);
#
case npp
#
NULL => ();
#
THE pp
=>
if cv.pprint_machcode_controlflow_graph
pp.txt "\n\n\n(Following printed by src/lib/compiler/back/low/main/main/backend-lowhalf-g.pkg.)\n";
pp.txt "\n\nMachcode_Controlflow_Graph form:\n";
pmc::maybe_prettyprint_machcode_controlflow_graph
npp
"Final control flow graph"
machcode_controlflow_graph;
pp.flush ();
fi;
esac;
#
fun maybe_view_machcode_controlflow_graph ()
=
if (*show_graphical_view_of_machcode_controlflow_graph_after_block_placement
and length bblocks >= *minimum_blocks_for_machcode_controlflow_graph_graphical_display
)
avu::view_machcode_controlflow_graph machcode_controlflow_graph;
fi;
cbp::check_machcode_block_placement (machcode_controlflow_graph, bblocks);
maybe_view_machcode_controlflow_graph ();
extract_all_code_and_data_from_acg (npp, cv) (machcode_controlflow_graph, bblocks);
#
# The extracted code and data are stored in
# (respectively) the global variables # Gawds help us all.
#
# textseg_list
# dataseg_list
#
# in the relevant one of
#
#
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-intel32-g.pkg #
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-pwrpc32-g.pkg #
src/lib/compiler/back/low/jmp/squash-jumps-and-write-code-to-code-segment-buffer-sparc32-g.pkg };
end;
package f2x # "f2x" ==" (translate) "nextcode_to_execode".
=
translate_nextcode_to_treecode_g ( # translate_nextcode_to_treecode_g is from
src/lib/compiler/back/low/main/main/translate-nextcode-to-treecode-g.pkg #
package t2m = t2m; # "t2m" == "translate_treecode_to_machcode".
package mp = mp; # "mp" == "machine_properties".
package trx = trx; # "trx" == "treecode_extension".
package pri = pri; # "pri" == "nextcode_registers".
package cpo = cpo; # "cpo" == "client_pseudo_ops".
package pop = pop; # "pop" == "pseudo_ops".
package ihc = ihc; # "ihc" == "insert_treecode_heapcleaner_calls".
#
package mkg # "mkg" == "make_machcode_codebuffer".
=
make_machcode_codebuffer_g ( # make_machcode_codebuffer_g is from
src/lib/compiler/back/low/mcg/make-machcode-codebuffer-g.pkg #
package mcg = mcg; # "mcg" == "machcode_controlflow_graph".
package mu = mu; # "mu" == "machcode_universals".
package cst = t2m::tcs::cst; # "cst" == "codestream".
);
#
package cal = cal; # "cal" == "ccalls".
package rgk = rgk; # "rgk" == "registerkinds".
#
translate_machcode_cccomponent_to_execode
=
translate_machcode_cccomponent_to_execode;
);
translate_nextcode_to_execode'
=
phase "lowhalf translate_nextcode_to_execode" f2x::translate_nextcode_to_execode;
fun translate_nextcode_to_execode x
=
{ # First, initialize all hidden state: # Sheesh -- a Fortran programmer would blush. Imagine if this -wasn't- functional programming.
#
lbl::set_count_to_zero ();
ihc::clear__public_fn_heapcleaner_call_specs__private_fn_heapcleaner_call_specs__and__longjumps_to_heapcleaner_calls ();
sja::clear__textseg_list__and__dataseg_list ();
#
translate_nextcode_to_execode' x;
};
end;
};
end;