mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-20 00:15:27 +00:00
Estimated hours taken: 6 (+12 by fjh) Branches: main Read in the `.opt' files transitively, so that we get all the definitions of equivalence types. This is needed to support --high-level-data for the .NET / Java back-ends. compiler/options.m: Add an option `--read-opt-files-transitively' (on by default). compiler/intermod.m: Read in the `.opt' files transitively. compiler/modules.m: `mmake depend' now assumes the target code for a module depends on the `.opt', `.int' and `.int2' files for all transitively imported modules. compiler/make.dependencies.m: Handle the extra dependencies. compiler/make_hlds.m: Process `pragma termination_info' pragmas in pass 3, *after* we've handled default modes for functions. This avoids a problem where the compiler was reporting spurious errors for the `pragma termination_info' pragmas for functions, when the `.opt' file for that module was read in before the `.int' file. I'm not sure if this problem was introduced by the changes above or whether the changes above just exposed an existing problem. compiler/deep_profiling.m: compiler/llds.m: compiler/mercury_compile.m: compiler/modes.m: compiler/modules.m: compiler/term_pass2.m: Add module qualifiers to calls to `member' and `map'. These are needed now that the equivalence `:- type set(T) == list(T)' is exposed with inter-module optimization. NEWS: doc/user_guide.texi: Document the change. tests/invalid/Mmakefile: Avoid reporting errors when creating the `.opt' file for the `missing_parent_import' test case.
1342 lines
46 KiB
Mathematica
1342 lines
46 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-2002 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% LLDS - The Low-Level Data Structure.
|
|
|
|
% This module defines the LLDS data structure itself.
|
|
|
|
% Main authors: conway, fjh.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend__llds.
|
|
|
|
:- interface.
|
|
|
|
:- import_module parse_tree__prog_data, parse_tree__inst.
|
|
:- import_module hlds__hlds_pred, hlds__hlds_goal, hlds__hlds_data.
|
|
:- import_module backend_libs__foreign, backend_libs__code_model.
|
|
:- import_module backend_libs__rtti, backend_libs__builtin_ops.
|
|
:- import_module ll_backend__layout.
|
|
:- import_module libs__tree.
|
|
|
|
:- import_module bool, list, assoc_list, map, set, std_util, counter, term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% foreign_interface_info holds information used when generating
|
|
% code that uses the foreign language interface.
|
|
:- type foreign_interface_info
|
|
---> foreign_interface_info(
|
|
module_name,
|
|
% info about stuff imported from C:
|
|
foreign_decl_info,
|
|
foreign_import_module_info,
|
|
foreign_body_info,
|
|
% info about stuff exported to C:
|
|
foreign_export_decls,
|
|
foreign_export_defns
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- import_module ll_backend__continuation_info.
|
|
|
|
:- type global_data.
|
|
|
|
:- pred global_data_init(list(layout_data)::in, global_data::out) is det.
|
|
|
|
:- pred global_data_add_new_proc_var(global_data::in,
|
|
pred_proc_id::in, comp_gen_c_var::in, global_data::out) is det.
|
|
|
|
:- pred global_data_add_new_proc_layout(global_data::in,
|
|
pred_proc_id::in, proc_layout_info::in, global_data::out) is det.
|
|
|
|
:- pred global_data_update_proc_layout(global_data::in,
|
|
pred_proc_id::in, proc_layout_info::in, global_data::out) is det.
|
|
|
|
:- pred global_data_add_new_closure_layouts(global_data::in,
|
|
list(comp_gen_c_data)::in, global_data::out) is det.
|
|
|
|
:- pred global_data_add_new_non_common_static_datas(global_data::in,
|
|
list(comp_gen_c_data)::in, global_data::out) is det.
|
|
|
|
:- pred global_data_maybe_get_proc_layout(global_data::in, pred_proc_id::in,
|
|
proc_layout_info::out) is semidet.
|
|
|
|
:- pred global_data_get_proc_layout(global_data::in, pred_proc_id::in,
|
|
proc_layout_info::out) is det.
|
|
|
|
:- pred global_data_get_all_proc_vars(global_data::in,
|
|
list(comp_gen_c_var)::out) is det.
|
|
|
|
:- pred global_data_get_all_proc_layouts(global_data::in,
|
|
list(proc_layout_info)::out) is det.
|
|
|
|
:- pred global_data_get_all_closure_layouts(global_data::in,
|
|
list(comp_gen_c_data)::out) is det.
|
|
|
|
:- pred global_data_get_all_non_common_static_data(global_data::in,
|
|
list(comp_gen_c_data)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% The type `c_file' is the actual LLDS.
|
|
%
|
|
:- type c_file
|
|
---> c_file(
|
|
module_name,
|
|
foreign_decl_info,
|
|
list(user_foreign_code),
|
|
list(foreign_export),
|
|
list(comp_gen_c_var),
|
|
list(comp_gen_c_data),
|
|
list(comp_gen_c_module)
|
|
).
|
|
|
|
% Global variables generated by the compiler.
|
|
:- type comp_gen_c_var
|
|
---> tabling_pointer_var(
|
|
module_name, % The basename of this C file.
|
|
proc_label % The id of the procedure
|
|
% whose table this variable
|
|
% represents.
|
|
).
|
|
|
|
% Global data generated by the compiler. Usually readonly,
|
|
% with one exception: data containing code addresses must
|
|
% be initialized.
|
|
:- type comp_gen_c_data
|
|
---> comp_gen_c_data(
|
|
module_name, % The basename of this C file.
|
|
data_name, % A representation of the name
|
|
% of the variable; it will be
|
|
% qualified with the basename.
|
|
bool, % Should this item be exported
|
|
% from this Mercury module?
|
|
% XXX Actually this field is
|
|
% redundant; see linkage/2
|
|
% in llds_out.m.
|
|
list(maybe(rval)), % The arguments of the create.
|
|
create_arg_types, % May specify the types of the
|
|
% arguments of the create.
|
|
list(pred_proc_id) % The procedures referenced.
|
|
% Used by dead_proc_elim.
|
|
)
|
|
; rtti_data(
|
|
rtti_data
|
|
)
|
|
; layout_data(
|
|
layout_data
|
|
).
|
|
|
|
:- type comp_gen_c_module
|
|
---> comp_gen_c_module(
|
|
string, % the name of this C module
|
|
list(c_procedure) % code
|
|
).
|
|
|
|
:- type c_procedure
|
|
---> c_procedure(
|
|
string, % predicate name
|
|
int, % arity
|
|
pred_proc_id, % the pred_proc_id this code
|
|
list(instruction), % the code for this procedure
|
|
proc_label, % proc_label of this procedure
|
|
counter, % source for new label numbers
|
|
contains_reconstruction % value numbering needs
|
|
% to handle goals that
|
|
% perform structure reuse
|
|
% specially.
|
|
).
|
|
|
|
:- type contains_reconstruction
|
|
---> contains_reconstruction
|
|
; does_not_contain_reconstruction
|
|
.
|
|
|
|
:- type llds_proc_id == int.
|
|
|
|
% we build up instructions as trees and then flatten
|
|
% the tree to get a list.
|
|
:- type code_tree == tree(list(instruction)).
|
|
|
|
:- type instruction == pair(instr, string).
|
|
% instruction, comment
|
|
|
|
:- type nondet_tail_call
|
|
---> no_tail_call
|
|
% At the point of the call, the procedure has
|
|
% more alternatives.
|
|
%
|
|
% Under these conditions, the call cannot be
|
|
% transformed into a tail call.
|
|
; checked_tail_call
|
|
% At the point of the call, the procedure has
|
|
% no more alternatives, and curfr and maxfr
|
|
% are not guaranteed to be identical.
|
|
%
|
|
% Under these conditions, the call can be
|
|
% transformed into a tail call whenever its
|
|
% return address leads to the procedure
|
|
% epilogue AND curfr and maxfr are found
|
|
% to be identical at runtime.
|
|
; unchecked_tail_call.
|
|
% At the point of the call the procedure has no
|
|
% more alternatives, and curfr and maxfr are
|
|
% guaranteed to be identical.
|
|
%
|
|
% Under these conditions, the call can be
|
|
% transformed into a tail call whenever its
|
|
% return address leads to the procedure
|
|
% epilogue.
|
|
|
|
:- type call_model
|
|
---> det
|
|
; semidet
|
|
; nondet(nondet_tail_call).
|
|
|
|
% `instr' defines the various LLDS virtual machine instructions.
|
|
% Each instruction gets compiled to a simple piece of C code
|
|
% or a macro invocation.
|
|
:- type instr
|
|
---> comment(string)
|
|
% Insert a comment into the output code.
|
|
|
|
; livevals(set(lval))
|
|
% A list of which registers and stack locations
|
|
% are currently live.
|
|
|
|
; block(int, int, list(instruction))
|
|
% block(NumIntTemps, NumFloatTemps, Instrs):
|
|
% A list of instructions that make use of
|
|
% some local temporary variables.
|
|
|
|
; assign(lval, rval)
|
|
% assign(Location, Value):
|
|
% Assign the value specified by rval to the location
|
|
% specified by lval.
|
|
|
|
; call(code_addr, code_addr, list(liveinfo), term__context,
|
|
goal_path, call_model)
|
|
% call(Target, Continuation, _, _, _) is the same as
|
|
% succip = Continuation; goto(Target).
|
|
% The third argument is the live value info for the
|
|
% values live on return. The fourth argument gives
|
|
% the context of the call. The fifth gives the goal
|
|
% path of the call in the body of the procedure; it is
|
|
% meaningful only if execution tracing is enabled.
|
|
% The last gives the code model of the called
|
|
% procedure, and if it is model_non, says whether
|
|
% tail recursion elimination is potentially applicable
|
|
% to the call.
|
|
|
|
; mkframe(nondet_frame_info, code_addr)
|
|
% mkframe(NondetFrameInfo, CodeAddr) creates a nondet
|
|
% stack frame. NondetFrameInfo says whether the frame
|
|
% is an ordinary frame, containing the variables of a
|
|
% model_non procedure, or a temp frame used only for
|
|
% its redoip/redofr slots. If the former, it also
|
|
% gives the details of the size of the variable parts
|
|
% of the frame (temp frames have no variable sized
|
|
% parts). CodeAddr is the code address to branch to
|
|
% when trying to generate the next solution from this
|
|
% choice point.
|
|
|
|
; label(label)
|
|
% Defines a label that can be used as the
|
|
% target of calls, gotos, etc.
|
|
|
|
; goto(code_addr)
|
|
% goto(Target)
|
|
% Branch to the specified address.
|
|
% Note that jumps to do_fail, do_redo, etc., can get
|
|
% optimized into the invocations of macros
|
|
% fail(), redo(), etc..
|
|
|
|
; computed_goto(rval, list(label))
|
|
% Evaluate rval, which should be an integer,
|
|
% and jump to the (rval+1)th label in the list.
|
|
% e.g. computed_goto(2, [A, B, C, D])
|
|
% will branch to label C.
|
|
|
|
; c_code(string, c_code_live_lvals)
|
|
% Do whatever is specified by the string,
|
|
% which can be any piece of C code that
|
|
% does not have any non-local flow of control.
|
|
|
|
; if_val(rval, code_addr)
|
|
% If rval is true, then goto code_addr.
|
|
|
|
; incr_hp(lval, maybe(tag), rval, string)
|
|
% Get a memory block of a size given by an rval
|
|
% and put its address in the given lval,
|
|
% possibly after tagging it with a given tag.
|
|
% The string gives the name of the type constructor
|
|
% of the memory cell for use in memory profiling.
|
|
|
|
; mark_hp(lval)
|
|
% Tell the heap sub-system to store a marker
|
|
% (for later use in restore_hp/1 instructions)
|
|
% in the specified lval
|
|
|
|
; restore_hp(rval)
|
|
% The rval must be a marker as returned by mark_hp/1.
|
|
% The effect is to deallocate all the memory which
|
|
% was allocated since that call to mark_hp.
|
|
|
|
; free_heap(rval)
|
|
% Notify the garbage collector that the heap space
|
|
% associated with the top-level cell of the rval is
|
|
% no longer needed.
|
|
% `free' is useless but harmless without conservative
|
|
% garbage collection.
|
|
|
|
; store_ticket(lval)
|
|
% Allocate a new "ticket" and store it in the lval.
|
|
%
|
|
% Operational semantics:
|
|
% MR_ticket_counter = ++MR_ticket_high_water;
|
|
% lval = MR_trail_ptr;
|
|
|
|
; reset_ticket(rval, reset_trail_reason)
|
|
% The rval must specify a ticket allocated with
|
|
% `store_ticket' and not yet invalidated, pruned or
|
|
% deallocated.
|
|
% If reset_trail_reason is `undo', `exception', or
|
|
% `retry', restore any mutable global state to the
|
|
% state it was in when the ticket was obtained with
|
|
% store_ticket(); invalidates any tickets allocated
|
|
% after this one.
|
|
% If reset_trail_reason is `commit' or `solve', leave
|
|
% the state unchanged, just check that it is safe to
|
|
% commit to this solution (i.e. that there are no
|
|
% outstanding delayed goals -- this is the
|
|
% "floundering" check).
|
|
% Note that we do not discard trail entries after
|
|
% commits, because that would in general be unsafe.
|
|
%
|
|
% Any invalidated ticket which has not yet been
|
|
% backtracked over should be pruned with
|
|
% `prune_ticket' or `prune_tickets_to'.
|
|
% Any invalidated ticket which has been backtracked
|
|
% over is useless and should be deallocated with
|
|
% `discard_ticket'.
|
|
%
|
|
% Operational semantics:
|
|
% MR_untrail_to(rval, reset_trail_reason);
|
|
|
|
; prune_ticket
|
|
% Invalidates the most-recently allocated ticket.
|
|
%
|
|
% Operational semantics:
|
|
% --MR_ticket_counter;
|
|
|
|
; discard_ticket
|
|
% Deallocates the most-recently allocated ticket.
|
|
%
|
|
% Operational semantics:
|
|
% MR_ticket_high_water = --MR_ticket_counter;
|
|
|
|
; mark_ticket_stack(lval)
|
|
% Tell the trail sub-system to store a ticket counter
|
|
% (for later use in prune_tickets_to)
|
|
% in the specified lval.
|
|
%
|
|
% Operational semantics:
|
|
% lval = MR_ticket_counter;
|
|
|
|
; prune_tickets_to(rval)
|
|
% The rval must be a ticket counter obtained via
|
|
% `mark_ticket_stack' and not yet invalidated.
|
|
% Prunes any trail tickets allocated after
|
|
% the corresponding call to mark_ticket_stack.
|
|
% Invalidates any later ticket counters.
|
|
%
|
|
% Operational semantics:
|
|
% MR_ticket_counter = rval;
|
|
|
|
% ; discard_tickets_to(rval) % this is only used in
|
|
% the hand-written code in
|
|
% library/exception.m
|
|
% The rval must be a ticket counter obtained via
|
|
% `mark_ticket_stack' and not yet invalidated.
|
|
% Deallocates any trail tickets allocated after
|
|
% the corresponding call to mark_ticket_stack.
|
|
% Invalidates any later ticket counters.
|
|
%
|
|
% Operational semantics:
|
|
% MR_ticket_counter = rval;
|
|
% MR_ticket_high_water = MR_ticket_counter;
|
|
|
|
; incr_sp(int, string)
|
|
% Increment the det stack pointer. The string is
|
|
% the name of the procedure, for use in stack dumps.
|
|
% It is used only in grades in which stack dumps are
|
|
% enabled (i.e. not in grades where SPEED is defined).
|
|
|
|
; decr_sp(int)
|
|
% Decrement the det stack pointer.
|
|
|
|
; pragma_c(list(pragma_c_decl), list(pragma_c_component),
|
|
may_call_mercury, maybe(label), maybe(label),
|
|
maybe(label), maybe(label), bool)
|
|
% The first argument says what local variable
|
|
% declarations are required for the following
|
|
% components, which in turn can specify how
|
|
% the inputs should be placed in their variables,
|
|
% how the outputs should be picked up from their
|
|
% variables, and C code both from the program
|
|
% and the compiler. These components can be
|
|
% sequenced in various ways. This flexibility
|
|
% is needed for nondet pragma C codes, which
|
|
% need different copies of several components
|
|
% for different paths tthrough the code.
|
|
%
|
|
% The third argument says whether the user C code
|
|
% components may call Mercury; certain optimizations
|
|
% can be performed across pragma_c instructions that
|
|
% cannot call Mercury.
|
|
%
|
|
% Some components in some pragma_c instructions
|
|
% refer to a Mercury label. If they do, we must
|
|
% prevent the label from being optimized away.
|
|
% To make it known to labelopt, we mention it in
|
|
% the fourth, fifth or sixth arg. The fourth argument
|
|
% may give the name of a label whose name is fixed
|
|
% because it embedded in raw C code, and which does
|
|
% not have a layout structure. The fifth and sixth
|
|
% arguments may give the names of labels whose names
|
|
% are fixed because they do have an associated label
|
|
% layout structure. The label in the fifth argument
|
|
% may appear in C code; the label in the sixth argument
|
|
% may not (such a label may therefore may be deleted
|
|
% from the LLDS code if it is not referred to from
|
|
% anywhere else). The seventh argument may give the
|
|
% name of a label that can be changed (because it is
|
|
% not mentioned in C code and has no associated layout
|
|
% structure, being mentioned only in pragma_c_fail_to
|
|
% components).
|
|
%
|
|
% The last argument says whether the contents
|
|
% of the pragma C code can refer to stack slots.
|
|
% User-written shouldn't refer to stack slots,
|
|
% the question is whether the compiler-generated
|
|
% C code does.
|
|
|
|
; init_sync_term(lval, int)
|
|
% Initialize a synchronization term.
|
|
% the first arguement contains the lvalue into
|
|
% which we will store the synchronization term,
|
|
% and the second argument indicates how many
|
|
% branches we expect to join at the end of the
|
|
% parallel conjunction.
|
|
% (See the documentation in par_conj_gen.m and
|
|
% runtime/mercury_context.{c,h} for further
|
|
% information about synchronisation terms.)
|
|
|
|
; fork(label, label, int)
|
|
% Create a new context.
|
|
% fork(Child, Parent, NumSlots) creates a new thread
|
|
% which will start executing at Child. After spawning
|
|
% execution in the child, control branches to Parent.
|
|
% NumSlots is the number of stack slots that need to
|
|
% be copied to the child's stack (see comments in
|
|
% runtime/mercury_context.{h,c}).
|
|
|
|
; join_and_terminate(lval)
|
|
% Signal that this thread of execution has finished in
|
|
% the current parallel conjunction, then terminate it.
|
|
% The synchronisation term is specified by the
|
|
% given lval. (See the documentation in par_conj_gen.m
|
|
% and runtime/mercury_context.{c,h} for further
|
|
% information about synchronisation terms.)
|
|
|
|
; join_and_continue(lval, label)
|
|
% Signal that this thread of execution has finished
|
|
% in the current parallel conjunction, then branch to
|
|
% the given label. The synchronisation
|
|
% term is specified by the given lval.
|
|
.
|
|
|
|
:- type nondet_frame_info
|
|
---> temp_frame(
|
|
temp_frame_type
|
|
)
|
|
; ordinary_frame(
|
|
string, % Name of the predicate.
|
|
int, % Number of framevar slots.
|
|
maybe(pragma_c_struct) % If yes, the frame should
|
|
% also contain this struct
|
|
% (for use by a model_non
|
|
% pragma C code).
|
|
).
|
|
|
|
:- type c_code_live_lvals
|
|
---> no_live_lvals_info % There is no information available
|
|
% about the live lvals used in
|
|
% the c_code.
|
|
|
|
; live_lvals_info(
|
|
set(lval) % The set of lvals defined before the
|
|
% c_code that are live inside the
|
|
% c_code.
|
|
).
|
|
|
|
% Temporary frames on the nondet stack exist only to provide a failure
|
|
% environment, i.e. a place to store a redoip and a redofr. Accurate
|
|
% garbage collection and execution tracing need to know how to
|
|
% interpret the layout information associated with the label whose
|
|
% address is in the redoip slot. If the label is in a procedure that
|
|
% stores its variables on the nondet stack, the redofr slot will give
|
|
% the address of the relevant stack frame. If the label is in a
|
|
% procedure that stores its variables on the det stack, the temporary
|
|
% frame will contain an extra slot containing the address of the
|
|
% relevant frame on the det stack.
|
|
:- type temp_frame_type
|
|
---> det_stack_proc
|
|
; nondet_stack_proc.
|
|
|
|
% Procedures defined by nondet pragma C codes must have some way of
|
|
% preserving information after a success, so that when control
|
|
% backtracks to the procedure, the C code knows what to do.
|
|
% Our implementation saves this information in a C struct.
|
|
% Programmers must include the declaration of the fields of this
|
|
% C struct in the `pragma c_code' declaration itself.
|
|
% A pragma_c_struct holds information about this C struct.
|
|
:- type pragma_c_struct
|
|
---> pragma_c_struct(
|
|
string, % The name of the struct tag.
|
|
string, % The field declarations, supplied
|
|
% by the user in the `pragma c_code'
|
|
% declaration.
|
|
maybe(prog_context)
|
|
% Where the field declarations
|
|
% originally appeared.
|
|
).
|
|
|
|
% A pragma_c_decl holds the information needed for the declaration
|
|
% of a local variable in a block of C code emitted for a pragma_c
|
|
% instruction.
|
|
:- type pragma_c_decl
|
|
---> pragma_c_arg_decl(
|
|
% This local variable corresponds to a procedure arg.
|
|
type, % The Mercury type of the argument.
|
|
string, % The string which is used to describe the
|
|
% type in the C code.
|
|
string % The name of the local variable that
|
|
% will hold the value of that argument
|
|
% inside the C block.
|
|
)
|
|
; pragma_c_struct_ptr_decl(
|
|
% This local variable holds the address of the
|
|
% save struct.
|
|
string, % The name of the C struct tag of the save
|
|
% struct; the type of the local variable
|
|
% will be a pointer to a struct with this tag.
|
|
string % The name of the local variable.
|
|
).
|
|
|
|
% A pragma_c_component holds one component of a pragma_c instruction.
|
|
:- type pragma_c_component
|
|
---> pragma_c_inputs(list(pragma_c_input))
|
|
; pragma_c_outputs(list(pragma_c_output))
|
|
; pragma_c_user_code(maybe(prog_context), string)
|
|
; pragma_c_raw_code(string, c_code_live_lvals)
|
|
; pragma_c_fail_to(label)
|
|
; pragma_c_noop.
|
|
|
|
% A pragma_c_input represents the code that initializes one
|
|
% of the input variables for a pragma_c instruction.
|
|
:- type pragma_c_input
|
|
---> pragma_c_input(string, type, rval, maybe(string)).
|
|
% variable name, type, variable value,
|
|
% maybe C type if foreign type.
|
|
|
|
% A pragma_c_output represents the code that stores one of
|
|
% of the outputs for a pragma_c instruction.
|
|
:- type pragma_c_output
|
|
---> pragma_c_output(lval, type, string, maybe(string)).
|
|
% where to put the output val, type and name
|
|
% of variable containing the output val
|
|
% followed by maybe C type if foreign type.
|
|
|
|
% see runtime/mercury_trail.h
|
|
:- type reset_trail_reason
|
|
---> undo
|
|
; commit
|
|
; solve
|
|
; exception
|
|
; retry
|
|
; gc
|
|
.
|
|
|
|
% The kinds of events with which MR_trace may be called, either
|
|
% by compiler-generated code, or by code in the standard library
|
|
% referring to compiler-generated data structures.
|
|
:- type trace_port
|
|
---> call
|
|
; exit
|
|
; fail
|
|
; redo
|
|
; exception
|
|
; ite_cond
|
|
; ite_then
|
|
; ite_else
|
|
; neg_enter
|
|
; neg_success
|
|
; neg_failure
|
|
; switch
|
|
; disj
|
|
; nondet_pragma_first
|
|
; nondet_pragma_later.
|
|
|
|
% Each call instruction has a list of liveinfo, which stores
|
|
% information about which variables are live after the call
|
|
% (that is, on return). The information is intended for use by
|
|
% the non-conservative garbage collector.
|
|
:- type liveinfo
|
|
---> live_lvalue(
|
|
layout_locn,
|
|
% What location does this lifeinfo structure
|
|
% refer to?
|
|
live_value_type,
|
|
% What is the type of this live value?
|
|
map(tvar, set(layout_locn))
|
|
% For each tvar that is a parameter of the
|
|
% type of this value, give the set of
|
|
% locations where the type_info variable
|
|
% describing the actual type bound to the
|
|
% type parameter may be found.
|
|
%
|
|
% We record all the locations of the typeinfo,
|
|
% in case different paths of arriving a this
|
|
% program point leave the typeinfo in different
|
|
% sets of locations. However, there must be at
|
|
% least type_info location that is valid
|
|
% along all paths leading to this point.
|
|
).
|
|
|
|
% For an explanation of this type, see the comment on
|
|
% stack_layout__represent_locn.
|
|
:- type layout_locn
|
|
---> direct(lval)
|
|
; indirect(lval, int).
|
|
|
|
% live_value_type describes the different sorts of data that
|
|
% can be considered live.
|
|
:- type live_value_type
|
|
---> succip % A stored succip.
|
|
; curfr % A stored curfr.
|
|
; maxfr % A stored maxfr.
|
|
; redoip % A stored redoip.
|
|
; redofr % A stored redofr.
|
|
; hp % A stored heap pointer.
|
|
; trail_ptr % A stored trail pointer.
|
|
; ticket % A stored ticket.
|
|
; var(prog_var, string, type, llds_inst)
|
|
% A variable (the var number
|
|
% and name are for execution
|
|
% tracing; we have to store
|
|
% the name here because when
|
|
% we want to use the
|
|
% live_value_type, we won't
|
|
% have access to the varset).
|
|
; unwanted. % Something we don't need,
|
|
% or at least don't need
|
|
% information about.
|
|
|
|
% For recording information about the inst of a variable for use
|
|
% by the garbage collector or the debugger, we don't need to know
|
|
% what functors its parts are bound to, or which parts of it are
|
|
% unique; we just need to know which parts of it are bound.
|
|
% If we used the HLDS type inst to represent the instantiatedness
|
|
% in the LLDS, we would find that insts that the LLDS wants to treat
|
|
% as the same would compare as different. The live_value_types and
|
|
% var_infos containing them would compare as different as well,
|
|
% which can lead to a variable being listed more than once in
|
|
% a label's list of live variable.
|
|
%
|
|
% At the moment, the LLDS only handles ground insts. When this changes,
|
|
% the argument type of partial will have to be changed.
|
|
:- type llds_inst
|
|
---> ground
|
|
; partial((inst)).
|
|
|
|
% An lval represents a data location or register that can be used
|
|
% as the target of an assignment.
|
|
:- type lval --->
|
|
|
|
/* virtual machine registers */
|
|
|
|
reg(reg_type, int)
|
|
% One of the general-purpose virtual machine
|
|
% registers (either an int or float reg).
|
|
|
|
; succip % Virtual machine register holding the
|
|
% return address for det/semidet code.
|
|
|
|
; maxfr % Virtual machine register holding a pointer
|
|
% to the top of nondet stack.
|
|
|
|
; curfr % Virtual machine register holding a pointer
|
|
% to the current nondet stack frame.
|
|
|
|
; hp % Virtual machine register holding the heap
|
|
% pointer.
|
|
|
|
; sp % Virtual machine register point to the
|
|
% top of det stack.
|
|
|
|
; temp(reg_type, int)
|
|
% A local temporary register.
|
|
% These temporary registers are actually
|
|
% local variables declared in `block'
|
|
% instructions. They may only be
|
|
% used inside blocks. The code generator
|
|
% doesn't generate these; they are introduced
|
|
% by value numbering. The basic idea is
|
|
% to improve efficiency by using local
|
|
% variables that the C compiler may be
|
|
% able to allocate in a register rather than
|
|
% using stack slots.
|
|
|
|
/* values on the stack */
|
|
|
|
; stackvar(int) % A det stack slot. The number is the offset
|
|
% relative to the current value of `sp'.
|
|
% These are used in both det and semidet code.
|
|
% Stackvar slot numbers start at 1.
|
|
|
|
; framevar(int) % A nondet stack slot. The reference is
|
|
% relative to the current value of `curfr'.
|
|
% These are used in nondet code.
|
|
% Framevar slot numbers start at 1.
|
|
|
|
; succip(rval) % The succip slot of the specified
|
|
% nondet stack frame; holds the code address
|
|
% to jump to on successful exit from this
|
|
% nondet procedure.
|
|
|
|
; redoip(rval) % The redoip slot of the specified
|
|
% nondet stack frame; holds the code address
|
|
% to jump to on failure.
|
|
|
|
; redofr(rval) % the redofr slot of the specified
|
|
% nondet stack frame; holds the address of
|
|
% the frame that the curfr register should be
|
|
% set to when backtracking through the redoip
|
|
% slot.
|
|
|
|
; succfr(rval) % The succfr slot of the specified
|
|
% nondet stack frame; holds the address of
|
|
% caller's nondet stack frame. On successful
|
|
% exit from this nondet procedure, we will
|
|
% set curfr to this value.
|
|
|
|
; prevfr(rval) % The prevfr slot of the specified
|
|
% nondet stack frame; holds the address of
|
|
% the previous frame on the nondet stack.
|
|
|
|
/* values on the heap */
|
|
|
|
; field(maybe(tag), rval, rval)
|
|
% field(Tag, Address, FieldNum)
|
|
% selects a field of a compound term.
|
|
% Address is a tagged pointer to a cell
|
|
% on the heap; the offset into the cell
|
|
% is FieldNum words. If Tag is yes, the
|
|
% arg gives the value of the tag; if it is
|
|
% no, the tag bits will have to be masked off.
|
|
% The value of the tag should be given if
|
|
% it is known, since this will lead to
|
|
% faster code.
|
|
|
|
/* values somewhere in memory */
|
|
|
|
; mem_ref(rval) % A word in the heap, in the det stack or
|
|
% in the nondet stack. The rval should have
|
|
% originally come from a mem_addr rval.
|
|
|
|
/* pseudo-values */
|
|
|
|
; lvar(prog_var). % The location of the specified variable.
|
|
% `var' lvals are used during code generation,
|
|
% but should not be present in the LLDS at any
|
|
% stage after code generation.
|
|
|
|
% An rval is an expression that represents a value.
|
|
:- type rval
|
|
---> lval(lval)
|
|
% The value of an `lval' rval is just the value stored in
|
|
% the specified lval.
|
|
|
|
; var(prog_var)
|
|
% The value of a `var' rval is just the value of the
|
|
% specified variable.
|
|
% `var' rvals are used during code generation,
|
|
% but should not be present in the LLDS at any
|
|
% stage after code generation.
|
|
|
|
; create(tag, list(maybe(rval)), create_arg_types,
|
|
static_or_dynamic, int, string, maybe(rval))
|
|
% create(Tag, Arguments, MaybeArgTypes, StaticOrDynamic,
|
|
% LabelNumber, CellKind, CellToReuse):
|
|
% A `create' instruction is used during code generation
|
|
% for creating a term, either on the heap or
|
|
% (if the term is constant) as a static constant.
|
|
% After code generation, only constant term create() rvals
|
|
% should be present in the LLDS, others will get transformed
|
|
% to incr_hp(..., Tag, Size) plus assignments to the fields.
|
|
%
|
|
% MaybeArgTypes may explicitly give the C level types of
|
|
% the arguments, although usually these types will be implicit.
|
|
%
|
|
% StaticOrDynamic may say that the cell must be allocated
|
|
% dynamically on the heap, because the resulting data structure
|
|
% must be unique (e.g. if we're doing to do destructive update
|
|
% on it). It may say that the cell must be allocated
|
|
% statically, e.g. because the MaybeArgTypes includes
|
|
% explicitly specified types that differ in size from Word
|
|
% (the code generator cannot fill in such cells).
|
|
% Or it may say that this cell can be allocated either way,
|
|
% subject to other constraints (e.g. a cell cannot be allocated
|
|
% statically unless all of its components are statically
|
|
% allocated as well).
|
|
%
|
|
% The label number is needed for the case when
|
|
% we can construct the term at compile-time
|
|
% and just reference the label.
|
|
%
|
|
% The string argument gives the name of the type constructor
|
|
% of the function symbol of which this is a cell, for use
|
|
% in memory profiling.
|
|
%
|
|
% The maybe(rval) contains the location of a cell to reuse.
|
|
% This will always be `no' after code generation.
|
|
%
|
|
% For the time being, you must leave the argument types
|
|
% implicit if the cell is to be unique. This is because
|
|
% (a) the code generator assumes that each argument of a cell
|
|
% it creates on the heap is the same size as a Word; (b)
|
|
% this assumption may be incorrect with explicitly defined
|
|
% argument types.
|
|
|
|
; mkword(tag, rval)
|
|
% Given a pointer and a tag, mkword returns a tagged pointer.
|
|
|
|
; const(rval_const)
|
|
|
|
; unop(unary_op, rval)
|
|
|
|
; binop(binary_op, rval, rval)
|
|
|
|
; mem_addr(mem_ref).
|
|
% The address of a word in the heap, the det stack or
|
|
% the nondet stack.
|
|
|
|
:- type static_or_dynamic
|
|
---> must_be_static
|
|
; can_be_either
|
|
; must_be_dynamic.
|
|
|
|
% Values of this type specify the C types and therefore the sizes
|
|
% of the arguments of a create rval.
|
|
%
|
|
% If the type is given as yes(LldsType), then the type is the C type
|
|
% corresponding to LldsType. If the type is given as no, then the
|
|
% type is implicit; it is what llds_out__rval_type_as_arg says
|
|
% when given the actual argument.
|
|
:- type create_arg_types
|
|
---> uniform(maybe(llds_type)) % All the arguments have
|
|
% the given C type.
|
|
; initial(initial_arg_types, create_arg_types)
|
|
% Each element of the assoc
|
|
% list N - T specifies that
|
|
% the next N arguments have
|
|
% type T. The types of the
|
|
% remainder of the arguments
|
|
% are given by the recursive
|
|
% create_arg_types.
|
|
; none. % There ought to be no more
|
|
% arguments.
|
|
|
|
:- type initial_arg_types == assoc_list(int, maybe(llds_type)).
|
|
|
|
:- type mem_ref
|
|
---> stackvar_ref(int) % stack slot number
|
|
; framevar_ref(int) % stack slot number
|
|
; heap_ref(rval, int, int). % the cell pointer,
|
|
% the tag to subtract,
|
|
% and the field number
|
|
|
|
:- type rval_const
|
|
---> true
|
|
; false
|
|
; int_const(int)
|
|
; float_const(float)
|
|
; string_const(string)
|
|
; multi_string_const(int, string)
|
|
% a string containing embedded NULLs,
|
|
% whose real length is given by the integer,
|
|
% and not the location of the first NULL
|
|
; code_addr_const(code_addr)
|
|
; data_addr_const(data_addr)
|
|
; label_entry(label).
|
|
% the address of the label (uses MR_ENTRY macro).
|
|
|
|
:- type data_addr
|
|
---> data_addr(module_name, data_name)
|
|
% module name; which var
|
|
; rtti_addr(rtti_type_ctor, rtti_name)
|
|
% type id; which var
|
|
; layout_addr(layout_name).
|
|
|
|
:- type data_name
|
|
---> common(int)
|
|
; base_typeclass_info(class_id, string)
|
|
% class name & class arity, names and arities of the
|
|
% types
|
|
; tabling_pointer(proc_label)
|
|
% A variable that contains a pointer that points to
|
|
% the table used to implement memoization, loopcheck
|
|
% or minimal model semantics for the given procedure.
|
|
; deep_profiling_procedure_data(proc_label)
|
|
.
|
|
|
|
:- type reg_type
|
|
---> r % general-purpose (integer) regs
|
|
; f. % floating point regs
|
|
|
|
:- type label
|
|
---> local(int, proc_label) % not proc entry; internal to a
|
|
% procedure
|
|
; c_local(proc_label) % proc entry; internal to a C module
|
|
; local(proc_label) % proc entry; internal to a Mercury
|
|
% module
|
|
; exported(proc_label). % proc entry; exported from a Mercury
|
|
% module
|
|
|
|
:- type code_addr
|
|
---> label(label) % A label defined in this Mercury
|
|
% module.
|
|
; imported(proc_label) % A label from another Mercury module.
|
|
; succip % The address in the `succip'
|
|
% register.
|
|
; do_succeed(bool) % The bool is `yes' if there are any
|
|
% alternatives left. If the bool is
|
|
% `no', we do a succeed_discard()
|
|
% rather than a succeed().
|
|
; do_redo
|
|
; do_fail
|
|
|
|
; do_trace_redo_fail_shallow
|
|
; do_trace_redo_fail_deep
|
|
% Labels in the runtime, the code
|
|
% at which calls MR_trace with a
|
|
% REDO event and then fails. The
|
|
% shallow variety only does this
|
|
% if the from_full flag was set
|
|
% on entry to the given procedure.
|
|
; do_call_closure
|
|
; do_call_class_method
|
|
; do_det_aditi_call
|
|
; do_semidet_aditi_call
|
|
; do_nondet_aditi_call
|
|
; do_aditi_insert
|
|
; do_aditi_delete
|
|
; do_aditi_bulk_insert
|
|
; do_aditi_bulk_delete
|
|
; do_aditi_bulk_modify
|
|
; do_not_reached. % We should never jump to this address.
|
|
|
|
% A proc_label is a label used for the entry point to a procedure.
|
|
% The defining module is the module that provides the code for the
|
|
% predicate, the declaring module contains the `:- pred' declaration.
|
|
% When these are different, as for specialised versions of predicates
|
|
% from `.opt' files, the defining module's name is added as a
|
|
% qualifier to the label.
|
|
:- type proc_label
|
|
---> proc(
|
|
module_name, % defining module
|
|
pred_or_func,
|
|
module_name, % declaring module
|
|
string, % name
|
|
int, % arity
|
|
proc_id % mode number
|
|
)
|
|
|
|
; special_proc(
|
|
module_name, % defining module
|
|
string, % pred name
|
|
module_name, % type module
|
|
string, % type name
|
|
int, % type arity
|
|
proc_id % mode number
|
|
).
|
|
|
|
% A tag (used in mkword, create and field expressions
|
|
% and in incr_hp instructions) is a small integer.
|
|
:- type tag == int.
|
|
|
|
% We categorize the data types used in the LLDS into
|
|
% a small number of categories, for purposes such as
|
|
% choosing the right sort of register for a given value
|
|
% to avoid unnecessary boxing/unboxing of floats.
|
|
:- type llds_type
|
|
---> bool % A boolean value
|
|
% represented using the C type `MR_Integer'.
|
|
; int_least8 % A signed value that fits that contains
|
|
% at least eight bits, represented using the
|
|
% C type MR_int_least8_t. Intended for use in
|
|
% static data declarations, not for data
|
|
% that gets stored in registers, stack slots
|
|
% etc.
|
|
; uint_least8 % An unsigned version of int_least8,
|
|
% represented using the C type
|
|
% MR_uint_least8_t.
|
|
; int_least16 % A signed value that fits that contains
|
|
% at least sixteen bits, represented using the
|
|
% C type MR_int_least16_t. Intended for use in
|
|
% static data declarations, not for data
|
|
% that gets stored in registers, stack slots
|
|
% etc.
|
|
; uint_least16 % An unsigned version of int_least16,
|
|
% represented using the C type
|
|
% MR_uint_least16_t.
|
|
; int_least32 % A signed value that fits that contains
|
|
% at least 32 bits, represented using the
|
|
% C type MR_int_least32_t. Intended for use in
|
|
% static data declarations, not for data
|
|
% that gets stored in registers, stack slots
|
|
% etc.
|
|
; uint_least32 % An unsigned version of intleast_32,
|
|
% represented using the C type uint_least32_t.
|
|
; integer % A Mercury `int', represented in C as a
|
|
% value of type `MR_Integer' (which is
|
|
% a signed integral type of the same
|
|
% size as a pointer).
|
|
; unsigned % Something whose C type is `MR_Unsigned'
|
|
% (the unsigned equivalent of `MR_Integer').
|
|
; float % A Mercury `float', represented in C as a
|
|
% value of type `MR_Float' (which may be either
|
|
% `float' or `double', but is usually
|
|
% `double').
|
|
; string % A Mercury string; represented in C as a
|
|
% value of type `MR_String'.
|
|
; data_ptr % A pointer to data; represented in C
|
|
% as a value of C type `MR_Word *'.
|
|
; code_ptr % A pointer to code; represented in C
|
|
% as a value of C type `MR_Code *'.
|
|
; word. % Something that can be assigned to a value
|
|
% of C type `MR_Word', i.e., something whose
|
|
% size is a word but which may be either
|
|
% signed or unsigned
|
|
% (used for registers, stack slots, etc).
|
|
|
|
:- func llds__stack_slot_num_to_lval(code_model, int) = lval.
|
|
|
|
:- pred llds__wrap_rtti_data(rtti_data::in, comp_gen_c_data::out) is det.
|
|
|
|
% given a non-var rval, figure out its type
|
|
:- pred llds__rval_type(rval::in, llds_type::out) is det.
|
|
|
|
% given a non-var lval, figure out its type
|
|
:- pred llds__lval_type(lval::in, llds_type::out) is det.
|
|
|
|
% given a constant, figure out its type
|
|
:- pred llds__const_type(rval_const::in, llds_type::out) is det.
|
|
|
|
% given a unary operator, figure out its return type
|
|
:- pred llds__unop_return_type(unary_op::in, llds_type::out) is det.
|
|
|
|
% given a unary operator, figure out the type of its argument
|
|
:- pred llds__unop_arg_type(unary_op::in, llds_type::out) is det.
|
|
|
|
% given a binary operator, figure out its return type
|
|
:- pred llds__binop_return_type(binary_op::in, llds_type::out) is det.
|
|
|
|
% given a register, figure out its type
|
|
:- pred llds__register_type(reg_type::in, llds_type::out) is det.
|
|
|
|
% check whether the types of all argument are the same size as word
|
|
:- pred llds__all_args_are_word_size(create_arg_types::in, bool::out) is det.
|
|
|
|
% check whether an arg of the given type is the same size as word
|
|
% (floats may be bigger than a word, but if so, they are boxed)
|
|
:- pred llds__type_is_word_size_as_arg(llds_type::in, bool::out) is det.
|
|
|
|
:- func get_proc_label(label) = proc_label.
|
|
|
|
:- func get_defining_module_name(proc_label) = module_name.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module require.
|
|
|
|
llds__stack_slot_num_to_lval(CodeModel, SlotNum) =
|
|
(if CodeModel = model_non then
|
|
framevar(SlotNum)
|
|
else
|
|
stackvar(SlotNum)
|
|
).
|
|
|
|
llds__wrap_rtti_data(RttiData, rtti_data(RttiData)).
|
|
|
|
llds__lval_type(reg(RegType, _), Type) :-
|
|
llds__register_type(RegType, Type).
|
|
llds__lval_type(succip, code_ptr).
|
|
llds__lval_type(maxfr, data_ptr).
|
|
llds__lval_type(curfr, data_ptr).
|
|
llds__lval_type(hp, data_ptr).
|
|
llds__lval_type(sp, data_ptr).
|
|
llds__lval_type(temp(RegType, _), Type) :-
|
|
llds__register_type(RegType, Type).
|
|
llds__lval_type(stackvar(_), word).
|
|
llds__lval_type(framevar(_), word).
|
|
llds__lval_type(succip(_), code_ptr).
|
|
llds__lval_type(redoip(_), code_ptr).
|
|
llds__lval_type(redofr(_), data_ptr).
|
|
llds__lval_type(succfr(_), data_ptr).
|
|
llds__lval_type(prevfr(_), data_ptr).
|
|
llds__lval_type(field(_, _, _), word).
|
|
llds__lval_type(lvar(_), _) :-
|
|
error("lvar unexpected in llds__lval_type").
|
|
llds__lval_type(mem_ref(_), word).
|
|
|
|
llds__rval_type(lval(Lval), Type) :-
|
|
llds__lval_type(Lval, Type).
|
|
llds__rval_type(var(_), _) :-
|
|
error("var unexpected in llds__rval_type").
|
|
llds__rval_type(create(_, _, _, _, _, _, _), data_ptr).
|
|
%
|
|
% Note that create and mkword must both be of type data_ptr,
|
|
% not of type word, to ensure that static consts containing
|
|
% them get type `const Word *', not type `Word'; this is
|
|
% necessary because casts from pointer to int must not be used
|
|
% in the initializers for constant expressions -- if they are,
|
|
% then lcc barfs, and gcc generates bogus code on some systems,
|
|
% (e.g. IRIX with shared libs). If the second argument to mkword
|
|
% is an integer, not a pointer, then we will end up casting it
|
|
% to a pointer, but casts from integer to pointer are OK, it's
|
|
% only the reverse direction we need to avoid.
|
|
%
|
|
llds__rval_type(mkword(_, _), data_ptr).
|
|
llds__rval_type(const(Const), Type) :-
|
|
llds__const_type(Const, Type).
|
|
llds__rval_type(unop(UnOp, _), Type) :-
|
|
llds__unop_return_type(UnOp, Type).
|
|
llds__rval_type(binop(BinOp, _, _), Type) :-
|
|
llds__binop_return_type(BinOp, Type).
|
|
llds__rval_type(mem_addr(_), data_ptr).
|
|
|
|
llds__const_type(true, bool).
|
|
llds__const_type(false, bool).
|
|
llds__const_type(int_const(_), integer).
|
|
llds__const_type(float_const(_), float).
|
|
llds__const_type(string_const(_), string).
|
|
llds__const_type(multi_string_const(_, _), string).
|
|
llds__const_type(code_addr_const(_), code_ptr).
|
|
llds__const_type(data_addr_const(_), data_ptr).
|
|
llds__const_type(label_entry(_), code_ptr).
|
|
|
|
llds__unop_return_type(mktag, word).
|
|
llds__unop_return_type(tag, word).
|
|
llds__unop_return_type(unmktag, word).
|
|
llds__unop_return_type(strip_tag, word).
|
|
llds__unop_return_type(mkbody, word).
|
|
llds__unop_return_type(unmkbody, word).
|
|
llds__unop_return_type(hash_string, integer).
|
|
llds__unop_return_type(bitwise_complement, integer).
|
|
llds__unop_return_type(not, bool).
|
|
|
|
llds__unop_arg_type(mktag, word).
|
|
llds__unop_arg_type(tag, word).
|
|
llds__unop_arg_type(unmktag, word).
|
|
llds__unop_arg_type(strip_tag, word).
|
|
llds__unop_arg_type(mkbody, word).
|
|
llds__unop_arg_type(unmkbody, word).
|
|
llds__unop_arg_type(hash_string, word).
|
|
llds__unop_arg_type(bitwise_complement, integer).
|
|
llds__unop_arg_type(not, bool).
|
|
|
|
llds__binop_return_type((+), integer).
|
|
llds__binop_return_type((-), integer).
|
|
llds__binop_return_type((*), integer).
|
|
llds__binop_return_type((/), integer).
|
|
llds__binop_return_type((mod), integer).
|
|
llds__binop_return_type((<<), integer).
|
|
llds__binop_return_type((>>), integer).
|
|
llds__binop_return_type((&), integer).
|
|
llds__binop_return_type(('|'), integer).
|
|
llds__binop_return_type((^), integer).
|
|
llds__binop_return_type((and), bool).
|
|
llds__binop_return_type((or), bool).
|
|
llds__binop_return_type(eq, bool).
|
|
llds__binop_return_type(ne, bool).
|
|
llds__binop_return_type(array_index(_Type), word).
|
|
llds__binop_return_type(str_eq, bool).
|
|
llds__binop_return_type(str_ne, bool).
|
|
llds__binop_return_type(str_lt, bool).
|
|
llds__binop_return_type(str_gt, bool).
|
|
llds__binop_return_type(str_le, bool).
|
|
llds__binop_return_type(str_ge, bool).
|
|
llds__binop_return_type((<), bool).
|
|
llds__binop_return_type((>), bool).
|
|
llds__binop_return_type((<=), bool).
|
|
llds__binop_return_type((>=), bool).
|
|
llds__binop_return_type(unsigned_le, bool).
|
|
llds__binop_return_type(float_plus, float).
|
|
llds__binop_return_type(float_minus, float).
|
|
llds__binop_return_type(float_times, float).
|
|
llds__binop_return_type(float_divide, float).
|
|
llds__binop_return_type(float_eq, bool).
|
|
llds__binop_return_type(float_ne, bool).
|
|
llds__binop_return_type(float_lt, bool).
|
|
llds__binop_return_type(float_gt, bool).
|
|
llds__binop_return_type(float_le, bool).
|
|
llds__binop_return_type(float_ge, bool).
|
|
llds__binop_return_type(body, word).
|
|
|
|
llds__register_type(r, word).
|
|
llds__register_type(f, float).
|
|
|
|
llds__all_args_are_word_size(uniform(MaybeType), AllWordSize) :-
|
|
llds__maybe_type_is_word_size(MaybeType, AllWordSize).
|
|
llds__all_args_are_word_size(initial(Init, Rest), AllWordSize) :-
|
|
assoc_list__values(Init, MaybeTypes),
|
|
list__map(llds__maybe_type_is_word_size, MaybeTypes, InitWordSizes),
|
|
llds__all_args_are_word_size(Rest, RestWordSize),
|
|
bool__and_list([RestWordSize | InitWordSizes], AllWordSize).
|
|
llds__all_args_are_word_size(none, yes).
|
|
|
|
:- pred llds__maybe_type_is_word_size(maybe(llds_type)::in, bool::out) is det.
|
|
|
|
llds__maybe_type_is_word_size(no, yes).
|
|
llds__maybe_type_is_word_size(yes(Type), IsWordSize) :-
|
|
llds__type_is_word_size_as_arg(Type, IsWordSize).
|
|
|
|
llds__type_is_word_size_as_arg(int_least8, no).
|
|
llds__type_is_word_size_as_arg(uint_least8, no).
|
|
llds__type_is_word_size_as_arg(int_least16, no).
|
|
llds__type_is_word_size_as_arg(uint_least16, no).
|
|
llds__type_is_word_size_as_arg(int_least32, no).
|
|
llds__type_is_word_size_as_arg(uint_least32, no).
|
|
llds__type_is_word_size_as_arg(bool, yes).
|
|
llds__type_is_word_size_as_arg(integer, yes).
|
|
llds__type_is_word_size_as_arg(unsigned, yes).
|
|
llds__type_is_word_size_as_arg(float, yes).
|
|
llds__type_is_word_size_as_arg(string, yes).
|
|
llds__type_is_word_size_as_arg(data_ptr, yes).
|
|
llds__type_is_word_size_as_arg(code_ptr, yes).
|
|
llds__type_is_word_size_as_arg(word, yes).
|
|
|
|
get_proc_label(exported(ProcLabel)) = ProcLabel.
|
|
get_proc_label(local(ProcLabel)) = ProcLabel.
|
|
get_proc_label(c_local(ProcLabel)) = ProcLabel.
|
|
get_proc_label(local(_, ProcLabel)) = ProcLabel.
|
|
|
|
get_defining_module_name(proc(ModuleName, _, _, _, _, _)) = ModuleName.
|
|
get_defining_module_name(special_proc(ModuleName, _, _, _, _, _)) = ModuleName.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type proc_var_map == map(pred_proc_id, comp_gen_c_var).
|
|
:- type proc_layout_map == map(pred_proc_id, proc_layout_info).
|
|
|
|
:- type global_data
|
|
---> global_data(
|
|
proc_var_map :: proc_var_map,
|
|
% Information about the global
|
|
% variables defined by each
|
|
% procedure.
|
|
proc_layout_map :: proc_layout_map,
|
|
% Information about the
|
|
% layout structures defined
|
|
% by each procedure.
|
|
closure_layouts :: list(comp_gen_c_data),
|
|
% The list of all closure
|
|
% layouts generated in this
|
|
% module. While all closure
|
|
% layouts are different from
|
|
% all other comp_gen_c_datas,
|
|
% it is possible, although
|
|
% unlikely, for two closures
|
|
% to have the same layout.
|
|
non_common_data :: list(comp_gen_c_data)
|
|
% The list of global data
|
|
% structures that do not need
|
|
% to be checked by llds_common,
|
|
% because their construction
|
|
% ensures no overlaps.
|
|
).
|
|
|
|
:- func wrap_layout_data(layout_data) = comp_gen_c_data.
|
|
|
|
wrap_layout_data(LayoutData) = layout_data(LayoutData).
|
|
|
|
global_data_init(LayoutData, GlobalData) :-
|
|
map__init(EmptyDataMap),
|
|
map__init(EmptyLayoutMap),
|
|
NonCommon = list__map(wrap_layout_data, LayoutData),
|
|
GlobalData = global_data(EmptyDataMap, EmptyLayoutMap, [], NonCommon).
|
|
|
|
global_data_add_new_proc_var(GlobalData0, PredProcId, ProcVar, GlobalData) :-
|
|
ProcVarMap0 = GlobalData0 ^ proc_var_map,
|
|
map__det_insert(ProcVarMap0, PredProcId, ProcVar, ProcVarMap),
|
|
GlobalData = GlobalData0 ^ proc_var_map := ProcVarMap.
|
|
|
|
global_data_add_new_proc_layout(GlobalData0, PredProcId, ProcLayout,
|
|
GlobalData) :-
|
|
ProcLayoutMap0 = GlobalData0 ^ proc_layout_map,
|
|
map__det_insert(ProcLayoutMap0, PredProcId, ProcLayout, ProcLayoutMap),
|
|
GlobalData = GlobalData0 ^ proc_layout_map := ProcLayoutMap.
|
|
|
|
global_data_update_proc_layout(GlobalData0, PredProcId, ProcLayout,
|
|
GlobalData) :-
|
|
ProcLayoutMap0 = GlobalData0 ^ proc_layout_map,
|
|
map__det_update(ProcLayoutMap0, PredProcId, ProcLayout, ProcLayoutMap),
|
|
GlobalData = GlobalData0 ^ proc_layout_map := ProcLayoutMap.
|
|
|
|
global_data_add_new_closure_layouts(GlobalData0, NewClosureLayouts,
|
|
GlobalData) :-
|
|
ClosureLayouts0 = GlobalData0 ^ closure_layouts,
|
|
list__append(NewClosureLayouts, ClosureLayouts0, ClosureLayouts),
|
|
GlobalData = GlobalData0 ^ closure_layouts := ClosureLayouts.
|
|
|
|
global_data_add_new_non_common_static_datas(GlobalData0, NewNonCommonStatics,
|
|
GlobalData) :-
|
|
NonCommonStatics0 = GlobalData0 ^ non_common_data,
|
|
list__append(NewNonCommonStatics, NonCommonStatics0, NonCommonStatics),
|
|
GlobalData = GlobalData0 ^ non_common_data := NonCommonStatics.
|
|
|
|
global_data_maybe_get_proc_layout(GlobalData, PredProcId, ProcLayout) :-
|
|
ProcLayoutMap = GlobalData ^ proc_layout_map,
|
|
map__search(ProcLayoutMap, PredProcId, ProcLayout).
|
|
|
|
global_data_get_proc_layout(GlobalData, PredProcId, ProcLayout) :-
|
|
ProcLayoutMap = GlobalData ^ proc_layout_map,
|
|
map__lookup(ProcLayoutMap, PredProcId, ProcLayout).
|
|
|
|
global_data_get_all_proc_vars(GlobalData, ProcVars) :-
|
|
ProcVarMap = GlobalData ^ proc_var_map,
|
|
map__values(ProcVarMap, ProcVars).
|
|
|
|
global_data_get_all_proc_layouts(GlobalData, ProcLayouts) :-
|
|
ProcLayoutMap = GlobalData ^ proc_layout_map,
|
|
map__values(ProcLayoutMap, ProcLayouts).
|
|
|
|
global_data_get_all_closure_layouts(GlobalData, ClosureLayouts) :-
|
|
ClosureLayouts = GlobalData ^ closure_layouts.
|
|
|
|
global_data_get_all_non_common_static_data(GlobalData, NonCommonStatics) :-
|
|
NonCommonStatics = GlobalData ^ non_common_data.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|