mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
It is almost the same as the unsigned_lt builtin op, but it is
implemented as "0 =< Index, Index < Range" just for Java.
This is the first step of the bootstrapping process; the second step
will add a declaration for private_builtin.in_range.
compiler/builtin_ops.m:
As above.
compiler/llds_out_data.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_cs_data.m:
compiler/mlds_to_java_data.m:
Implement the new operation.
compiler/code_util.m:
compiler/llds.m:
compiler/ml_global_data.m:
compiler/mlds_dump.m:
compiler/opt_debug.m:
Conform to the change above.
compiler/options.m:
Add a way to test whether the installed compiler supports this new op.
tests/warnings/help_text.err_exp:
Expect the new option name.
1827 lines
76 KiB
Mathematica
1827 lines
76 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: llds.m.
|
|
% Main authors: conway, fjh.
|
|
%
|
|
% LLDS - The Low-Level Data Structure.
|
|
%
|
|
% This module defines the LLDS data structure itself.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ll_backend.llds.
|
|
:- interface.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module backend_libs.rtti.
|
|
:- import_module hlds.
|
|
:- import_module hlds.code_model.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module libs.
|
|
:- import_module libs.trace_params.
|
|
:- import_module ll_backend.layout.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_data_pragma.
|
|
:- import_module parse_tree.prog_foreign.
|
|
:- import_module parse_tree.prog_type.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module counter.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
:- import_module term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The type `c_file' is the actual LLDS.
|
|
|
|
:- type c_file
|
|
---> c_file(
|
|
cfile_modulename :: module_name,
|
|
cfile_foreign_decl_codes :: list(foreign_decl_code),
|
|
cfile_foreign_body_codes :: list(foreign_body_code),
|
|
cfile_foreign_export_defns :: list(foreign_export_defn),
|
|
cfile_vars :: list(tabling_info_struct),
|
|
cfile_scalar_common_data :: list(scalar_common_data_array),
|
|
cfile_vector_common_data :: list(vector_common_data_array),
|
|
cfile_rtti_data :: list(rtti_data),
|
|
cfile_ptis :: list(rval),
|
|
cfile_hlds_var_nums :: list(int),
|
|
cfile_short_locns :: list(int),
|
|
cfile_long_locns :: list(int),
|
|
cfile_user_event_var_nums :: list(maybe(int)),
|
|
cfile_user_events :: list(user_event_data),
|
|
cfile_no_var_label_layouts :: list(label_layout_no_vars),
|
|
cfile_svar_label_layouts :: list(label_layout_short_vars),
|
|
cfile_lvar_label_layouts :: list(label_layout_long_vars),
|
|
cfile_i_label_to_layout_map :: map(label, layout_slot_name),
|
|
cfile_p_label_to_layout_map :: map(label, data_id),
|
|
cfile_call_sites :: list(call_site_static_data),
|
|
cfile_coverage_points :: list(coverage_point_info),
|
|
cfile_proc_statics :: list(proc_layout_proc_static),
|
|
cfile_proc_head_var_nums :: list(int),
|
|
cfile_proc_var_names :: list(int),
|
|
cfile_proc_body_bytecodes :: list(int),
|
|
cfile_ts_string_table :: list(string),
|
|
cfile_table_io_entries :: list(table_io_entry_data),
|
|
cfile_table_io_entry_map :: map(pred_proc_id,
|
|
layout_slot_name),
|
|
cfile_proc_event_layouts :: list(layout_slot_name),
|
|
cfile_exec_traces :: list(proc_layout_exec_trace),
|
|
cfile_proc_layouts :: list(proc_layout_data),
|
|
cfile_module_layout_data :: list(module_layout_data),
|
|
cfile_closure_layout_data :: list(closure_proc_id_data),
|
|
cfile_alloc_sites :: list(alloc_site_info),
|
|
cfile_alloc_site_map :: map(alloc_site_id,
|
|
layout_slot_name),
|
|
cfile_code :: list(comp_gen_c_module),
|
|
cfile_user_init_c_names :: list(string),
|
|
cfile_user_final_c_names :: list(string),
|
|
cfile_complexity :: list(complexity_proc_info)
|
|
).
|
|
|
|
% Global variables generated by the compiler.
|
|
:- type tabling_info_struct
|
|
---> tabling_info_struct(
|
|
% The id of the procedure whose table this structure is.
|
|
tis_proc_label :: proc_label,
|
|
tis_eval_method :: tabled_eval_method,
|
|
|
|
tis_num_inputs :: int,
|
|
tis_num_outputs :: int,
|
|
tis_input_steps :: list(table_step_desc),
|
|
tis_maybe_output_steps :: maybe(list(table_step_desc)),
|
|
|
|
% Pseudo-typeinfos for headvars.
|
|
tis_ptis :: rval,
|
|
% Where to fill the ptis in from.
|
|
tis_type_params :: rval,
|
|
|
|
tis_size_limit :: maybe(int),
|
|
tis_stats :: table_attr_statistics
|
|
).
|
|
|
|
:- type typed_rval
|
|
---> typed_rval(rval, llds_type).
|
|
|
|
:- func typed_rvals_project_rvals(list(typed_rval)) = list(rval).
|
|
:- func typed_rvals_project_types(list(typed_rval)) = list(llds_type).
|
|
|
|
:- pred build_typed_rvals(list(rval)::in, list(llds_type)::in,
|
|
list(typed_rval)::out) is det.
|
|
|
|
:- type common_cell_type
|
|
---> plain_type(list(llds_type))
|
|
% The type is a structure with one field for each one
|
|
% of the cell's arguments.
|
|
; grouped_args_type(assoc_list(llds_type, int)).
|
|
% The type is a structure with one field for each group
|
|
% of the cell's arguments, with each group containing
|
|
% at least two elements of the same llds_type.
|
|
|
|
:- type common_cell_value
|
|
---> plain_value(list(typed_rval))
|
|
; grouped_args_value(list(common_cell_arg_group)).
|
|
|
|
:- type common_cell_arg_group
|
|
---> common_cell_grouped_args(
|
|
% The shared type of the fields in the group.
|
|
llds_type,
|
|
|
|
% The number of fields in the group. This will contain
|
|
% the length of the list in the third argument, but computed
|
|
% only once. It ought to be more than one; if a field cannot be
|
|
% grouped with neighbouring values of the same type, it should
|
|
% be stored as an ungrouped arg.
|
|
int,
|
|
|
|
% The field values themselves.
|
|
list(rval)
|
|
)
|
|
; common_cell_ungrouped_arg(
|
|
llds_type, % The type of the field.
|
|
rval % The field value.
|
|
).
|
|
|
|
:- type type_num
|
|
---> type_num(int).
|
|
|
|
:- type scalar_common_data_array
|
|
---> scalar_common_data_array(
|
|
% The type of the elements of the array.
|
|
scda_rval_types :: common_cell_type,
|
|
|
|
% The type number.
|
|
scda_type_num :: type_num,
|
|
|
|
% The array elements, starting at offset 0.
|
|
scda_values :: list(common_cell_value)
|
|
).
|
|
|
|
:- type vector_common_data_array
|
|
---> vector_common_data_array(
|
|
% The type of the elements of the array.
|
|
vcda_rval_types :: common_cell_type,
|
|
% The type number.
|
|
vcda_type_num :: type_num,
|
|
|
|
% The number of this vector, among all the vector cells
|
|
% with this type for the elements.
|
|
vcda_vector_num :: int,
|
|
|
|
% The array elements, starting at offset 0.
|
|
vcda_values :: list(common_cell_value)
|
|
).
|
|
|
|
% This maps the integer that identifies a constant structure
|
|
% (the key of a const_struct in const_struct_db ^ csdb_structs)
|
|
% to the rval representing the const_struct.
|
|
%
|
|
:- type const_struct_map == map(int, typed_rval).
|
|
|
|
:- type comp_gen_c_module
|
|
---> comp_gen_c_module(
|
|
% The name of this C module.
|
|
cgcm_name :: string,
|
|
|
|
% The code.
|
|
cgcm_procs :: list(c_procedure)
|
|
).
|
|
|
|
:- type c_procedure
|
|
---> c_procedure(
|
|
% The predicate or function's user-facing identity.
|
|
cproc_p_or_f :: pred_or_func,
|
|
cproc_name :: string,
|
|
cproc_user_arity :: user_arity,
|
|
|
|
% The pred_proc_id of this code.
|
|
cproc_id :: pred_proc_id,
|
|
|
|
% Proc_label of this procedure.
|
|
cproc_proc_label :: proc_label,
|
|
|
|
% The code model of the procedure.
|
|
cproc_code_model :: code_model,
|
|
|
|
cproc_eff_trace_level :: eff_trace_level,
|
|
|
|
% The code for this procedure.
|
|
cproc_code :: list(instruction),
|
|
|
|
% Source for new label numbers.
|
|
cproc_label_nums :: counter,
|
|
|
|
% The compiler is allowed to perform optimizations on this
|
|
% c_procedure that could alter RTTI information (e.g. the set
|
|
% of variables live at a label) only if this field is set
|
|
% to `may_alter_rtti'.
|
|
cproc_may_alter_rtti :: may_alter_rtti,
|
|
|
|
cproc_c_global_vars :: set(string)
|
|
).
|
|
|
|
:- type may_alter_rtti
|
|
---> may_alter_rtti
|
|
; must_not_alter_rtti.
|
|
|
|
:- type llds_proc_id == int.
|
|
|
|
% We build up instructions as trees and then flatten the tree to a list.
|
|
%
|
|
:- type llds_code == cord(instruction).
|
|
|
|
:- type instruction
|
|
---> llds_instr(
|
|
llds_inst :: instr,
|
|
llds_comment :: string
|
|
).
|
|
|
|
:- type maybe_auto_comments
|
|
---> no_auto_comments
|
|
; auto_comments.
|
|
|
|
:- 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 allow_lco
|
|
---> do_not_allow_lco
|
|
; allow_lco.
|
|
|
|
:- type call_model
|
|
---> call_model_det(allow_lco)
|
|
; call_model_semidet(allow_lco)
|
|
; call_model_nondet(nondet_tail_call).
|
|
|
|
% The type 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(Lval, Rval):
|
|
% Assign Rval to the location specified by Lval.
|
|
|
|
; keep_assign(lval, rval)
|
|
% As assign, but this operation cannot be optimized away or
|
|
% the target replaced by a temp register, even if the target
|
|
% *appears* to be unused by the following code.
|
|
|
|
; llcall(code_addr, code_addr, list(liveinfo), term.context,
|
|
maybe(forward_goal_path), call_model)
|
|
% llcall(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 id 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 says
|
|
% whether tail recursion elimination may be applied to the call.
|
|
% For model_non calls, this depends on whether there are any other
|
|
% stack frames on top of the stack frame of this procedure on the
|
|
% nondet stack. For model_det and model_semi calls, this depends on
|
|
% whether there is some other code, executing in parallel with this
|
|
% context, that uses the current stack frame.
|
|
%
|
|
% The ll prefix on call is to avoid the use of the call keyword
|
|
% and to distinguish this function symbol from a similar one
|
|
% in the MLDS.
|
|
|
|
; mkframe(nondet_frame_info, maybe(code_addr))
|
|
% mkframe(NondetFrameInfo, MaybeAddr) 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).
|
|
% If MaybeAddr = yes(CodeAddr), then CodeAddr is the code address
|
|
% to branch to when trying to generate the next solution from this
|
|
% choice point. If MaybeAddr = no, then the field of the choice
|
|
% point that contains this information is not filled in by mkframe;
|
|
% it is up to the code following to do so.
|
|
|
|
; label(label)
|
|
% Defines a label that can be used as the target of calls, gotos,
|
|
% etc. If the comment associated with the instruction ends with
|
|
% "nofulljump", then gotos ending at this label will not be
|
|
% replaced by the code starting at this label.
|
|
|
|
; goto(code_addr)
|
|
% Branch to the specified address. Note that jumps to do_fail,
|
|
% do_redo, etc can get optimized into invocations of the macros
|
|
% fail(), redo(), etc.
|
|
|
|
; computed_goto(rval, maybe(int), list(maybe(label)))
|
|
% Evaluate the 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. A label that isn't there implicitly means
|
|
% "not reached".
|
|
%
|
|
% The code that constructs this instructions should set the
|
|
% second argument to contain
|
|
%
|
|
% - either yes(MaxIndex), if the maximum possible value of
|
|
% the rval argument is known at compile time (and is MaxIndex),
|
|
% - or no, if this maximum value is not known at compile time.
|
|
%
|
|
% The info in this field is used to check the validity of an
|
|
% optimization performed on computed_gotos by peeohole.m.
|
|
|
|
; arbitrary_c_code(proc_affects_liveness, c_code_live_lvals, string)
|
|
% 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.
|
|
|
|
; save_maxfr(lval)
|
|
% Save the current value of maxfr to the given lval. In most
|
|
% grades, this does a straightforward copy, but in grades in which
|
|
% stacks can be reallocated, it saves the offset of maxfr from the
|
|
% start of the nondet stack.
|
|
|
|
; restore_maxfr(lval)
|
|
% Restore maxfr from the saved copy in the given lval. Assumes the
|
|
% lval was saved with save_maxfr.
|
|
|
|
; incr_hp(lval, maybe(ptag), maybe(int), rval, maybe(alloc_site_id),
|
|
may_use_atomic_alloc, maybe(rval), llds_reuse)
|
|
% incr_hp(Target, MaybeTag, MaybeOffset, SizeRval, MaybeAllocId,
|
|
% MayUseAtomicAlloc, MaybeRegionId, MaybeReuse)
|
|
%
|
|
% Get a memory block of a size given by SizeRval and put its
|
|
% address in Target, possibly after incrementing it by Offset words
|
|
% (if MaybeOffset = yes(Offset)) and/or after tagging it with Tag
|
|
% (if MaybeTag = yes(Tag)).
|
|
% If MaybeAllocId = yes(AllocId) then AllocId identifies the
|
|
% allocation site, for use in memory profiling.
|
|
% MayUseAtomicAlloc says whether we can use the atomic variants
|
|
% of the Boehm gc allocator calls. If MaybeRegionId =
|
|
% yes(RegionId), then the block should be allocated in the region
|
|
% identified by RegionId (i.e. in the region whose header RegionId
|
|
% points to). If MaybeReuse = llds_reuse(ReuseRval,
|
|
% MaybeFlagLval), then we should try to reuse the cell ReuseRval
|
|
% for the block. If MaybeFlagLval = yes(FlagLval) then FlagLval
|
|
% needs to be set to true or false indicate whether reuse was
|
|
% really possible.
|
|
|
|
; 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.
|
|
|
|
; push_region_frame(region_stack_id, embedded_stack_frame_id)
|
|
% push_region_frame(RegionStackId, EmbeddedStackId)
|
|
%
|
|
% Set the stack pointer of the region stack identified by
|
|
% RegionStackId to point to the group of stack slots identified
|
|
% by EmbeddedStackId (which specifies the new top embedded
|
|
% stack frame on that stack) *after* saving the old value of the
|
|
% stack pointer in the fixed slot reserved for this purpose in
|
|
% the new frame.
|
|
%
|
|
% The instruction will also fill in whatever other fixed slots
|
|
% of the new stack frame may be filled in at this time.
|
|
|
|
; region_fill_frame(region_fill_frame_op, embedded_stack_frame_id,
|
|
rval, lval, lval)
|
|
% region_fill_frame(FillOp, EmbeddedStackId,
|
|
% RegionId, NumLval, AddrLval)
|
|
%
|
|
% EmbeddedStackId should match the parameter of the
|
|
% push_region_frame instruction that created the embedded stack
|
|
% frame to which this instruction refers. RegionId should
|
|
% identify a region (i.e. it should point to the region header).
|
|
%
|
|
% If the condition appropriate to FillOp is true, then this
|
|
% instruction will
|
|
%
|
|
% (a) increment NumLval by one, and
|
|
% (b) store the aspects of the region relevant to FillOp
|
|
% in one or more consecutive memory locations starting at
|
|
% AddrRval, after which it will increment AddrRval
|
|
% by the number of words this uses.
|
|
%
|
|
% If the condition is false, the instruction will do nothing.
|
|
%
|
|
% The size of the frame must be big enough that the sequence of
|
|
% region_fill_frame operations executed on it don't overflow.
|
|
%
|
|
% At the end of the sequence, NumLval will be stored back into
|
|
% a fixed slot in the embedded frame using a region_set_fixed_slot
|
|
% instruction.
|
|
|
|
; region_set_fixed_slot(region_set_fixed_op, embedded_stack_frame_id,
|
|
rval)
|
|
% region_set_fixed_op(SetOp, EmbeddedStackId, Value)
|
|
%
|
|
% Given an embedded stack frame identified by EmbeddedStackId,
|
|
% set the fixed field of this frame identified by SetOp to Value.
|
|
|
|
; use_and_maybe_pop_region_frame(region_use_frame_op,
|
|
embedded_stack_frame_id)
|
|
% use_and_maybe_pop_region_frame(UseOp, EmbeddedStackId)
|
|
%
|
|
% For some values of UseOp, this instruction uses the contents of
|
|
% the frame identified by EmbeddedStackId (including values saved
|
|
% by region_set_fixed_op instructions) to operate on the values
|
|
% recorded in the frame by region_fill_frame instructions.
|
|
%
|
|
% For some other values of UseOp, this instruction logically pops
|
|
% the embedded stack off its stack. (The Mercury stacks are
|
|
% untouched.)
|
|
%
|
|
% For yet other values of UseOp, it does both.
|
|
|
|
; 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 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, stack_incr_kind)
|
|
% Increment the det stack pointer. The string is the name of the
|
|
% procedure, for use in collecting statistics about stack frame
|
|
% sizes.
|
|
|
|
; decr_sp(int)
|
|
% Decrement the det stack pointer.
|
|
|
|
; decr_sp_and_return(int)
|
|
% Pick up the return address from its slot in the stack frame,
|
|
% decrement the det stack pointer, and jump to the return address.
|
|
|
|
; foreign_proc_code(
|
|
fproc_decls :: list(foreign_proc_decl),
|
|
fproc_components :: list(foreign_proc_component),
|
|
fproc_may_call_merc :: proc_may_call_mercury,
|
|
fproc_fix_nolayout :: maybe(label),
|
|
fproc_fix_layout :: maybe(label),
|
|
fproc_fix_onlylayout :: maybe(label),
|
|
fproc_nofix :: maybe(label),
|
|
fproc_hash_def_label :: maybe(label),
|
|
fproc_stack_slot_ref :: maybe_refers_to_llds_stack,
|
|
fproc_maybe_dupl :: proc_may_duplicate
|
|
)
|
|
% foreign_proc_code(Decls, Components. MayCallMercury,
|
|
% FixNoLayout, FixLayout, FixOnlyLayout, NoFix, HashDef,
|
|
% StackSlotRef, MayBeDupl)
|
|
%
|
|
% Decls says what local variable declarations are required for
|
|
% 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 source program
|
|
% and generated by the compiler. These components can be sequenced
|
|
% in various ways. This flexibility is needed for nondet
|
|
% foreign_procs, which need different copies of several components
|
|
% for different paths through the code.
|
|
%
|
|
% MayCallMercury says whether the user C code components
|
|
% may call Mercury; certain optimizations can be performed
|
|
% across foreign_proc_code instructions that cannot call Mercury.
|
|
%
|
|
% Some components in some foreign_proc_code 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 FixNoLayout, FixLayout or FixOnlyLayout
|
|
% fields.
|
|
%
|
|
% FixNoLayout 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. FixLayout and FixOnlyLayout may give
|
|
% the names of labels whose names are fixed because they *do*
|
|
% have an associated label layout structure. The label in FixLayout
|
|
% may appear in C code; the label in FixOnlyLayout 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 NoFix field
|
|
% 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 foreign_proc_fail_to components).
|
|
%
|
|
% If HashDef is yes, then when the code generator generates C code
|
|
% for this foreign_proc, it should surround it with code that
|
|
% #defines the symbol MR_HASH_DEF_LABEL_LAYOUT to the address of
|
|
% the label layout structure of the given label. We use this
|
|
% mechanism to pass such addresses to the debugger because when
|
|
% the LLDS code is generated, we do not yet know what the address
|
|
% will be (even in C source form), since the slots in the arrays
|
|
% of label layout structures have not yet been allocated.
|
|
%
|
|
% If we are generating code for a target language other than C,
|
|
% HashDef will always be no.
|
|
%
|
|
% StackSlotRef says whether the contents of the foreign_proc
|
|
% C code can refer to stack slots. User-written shouldn't refer
|
|
% to stack slots, the question is whether any compiler-generated
|
|
% C code does.
|
|
%
|
|
% MayBeDupl says whether this instruction may be duplicated
|
|
% by jump optimization.
|
|
|
|
; init_sync_term(lval, int, int)
|
|
% Initialize a synchronization term, which is a continuous number
|
|
% of slots on the detstack. The first argument contains the base
|
|
% address of the synchronization term. The second argument
|
|
% indicates how many branches we expect to join at the end of the
|
|
% parallel conjunction. The third argument is an index into the
|
|
% threadscope string table. The string that it refers to
|
|
% identifies this parallel conjunction within the source code.
|
|
% (See the documentation in par_conj_gen.m and
|
|
% runtime/mercury_context.{c,h} for further information about
|
|
% synchronisation terms.)
|
|
|
|
; fork_new_child(lval, label)
|
|
% Create a new spark. fork(SyncTerm, Child) creates spark, to begin
|
|
% execution at Child, where SyncTerm contains the base address of
|
|
% the synchronisation term. Control continues at the next
|
|
% instruction.
|
|
|
|
; join_and_continue(lval, label)
|
|
% Signal that this thread of execution has finished in the current
|
|
% parallel conjunct. For details of how we at the end of a parallel
|
|
% conjunct see runtime/mercury_context.{c,h}.
|
|
% The synchronisation term is specified by the given lval.
|
|
% The label gives the address of the code following the parallel
|
|
% conjunction.
|
|
|
|
; lc_create_loop_control(int, lval)
|
|
% Create a loop control structure with the given number of slots,
|
|
% and put its address in the given lval.
|
|
|
|
; lc_wait_free_slot(rval, lval, label)
|
|
% Given an rval that holds the address of a loop control structure,
|
|
% return the index of a free slot in that structure, waiting for
|
|
% one to become free if necessary. The label acts as a resumption
|
|
% point if the context suspends. It will be both defined and used
|
|
% in the C code generated for this instruction, and should not
|
|
% be referred to from anywhere else.
|
|
|
|
; lc_spawn_off(rval, rval, label)
|
|
% Spawn off an independent computation whose execution starts
|
|
% at the given label and which will terminate by executing
|
|
% a join_and_terminate_lc instruction. The first rval should
|
|
% hold the address of the loop control structure that controls
|
|
% the spawned-off computation, and the second should hold
|
|
% the index of the slot occupied by that computation.
|
|
%
|
|
% After spawning off that computation, the original thread
|
|
% will just fall through.
|
|
|
|
; lc_join_and_terminate(rval, rval).
|
|
% Terminate the current context, which was spawned off by a
|
|
% spawn_off instruction. The first rval gives the address of
|
|
% the loop control structure, and the second is the index of
|
|
% this goal's slot in it. These two rvals should be exactly
|
|
% the same as the two rval arguments in the original lc_spawn_off
|
|
% instruction.
|
|
|
|
:- inst instr_llcall for instr/0
|
|
---> llcall(ground, ground, ground, ground, ground, ground).
|
|
:- inst instr_goto for instr/0
|
|
---> goto(ground).
|
|
:- inst instr_if_val for instr/0
|
|
---> if_val(ground, ground).
|
|
:- inst instr_foreign_proc_code for instr/0
|
|
---> foreign_proc_code(ground, ground, ground, ground, ground,
|
|
ground, ground, ground, ground, ground).
|
|
|
|
:- type alloc_site_id
|
|
---> alloc_site_id(alloc_site_info).
|
|
|
|
:- type stack_incr_kind
|
|
---> stack_incr_leaf % The incr_sp creates the stack frame
|
|
% of a leaf procedure.
|
|
; stack_incr_nonleaf. % The incr_sp creates the stack frame
|
|
% of a nonleaf procedure.
|
|
|
|
:- type nondet_frame_info
|
|
---> temp_frame(
|
|
temp_frame_type
|
|
)
|
|
; ordinary_frame(
|
|
string, % Name of the predicate.
|
|
int % Number of framevar slots.
|
|
).
|
|
|
|
:- 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.
|
|
|
|
:- type llds_reuse
|
|
---> no_llds_reuse
|
|
; llds_reuse(
|
|
rval, % The cell to reuse.
|
|
maybe(lval) % An optional lval to set to indicate
|
|
% whether cell reuse was actually possible.
|
|
).
|
|
|
|
% A foreign_proc_decl holds the information needed for the declaration
|
|
% of a local variable in a block of C code emitted for a foreign_proc_code
|
|
% instruction.
|
|
%
|
|
:- type foreign_proc_decl
|
|
---> foreign_proc_arg_decl(
|
|
% This local variable corresponds to a procedure arg.
|
|
mer_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.
|
|
).
|
|
|
|
% A foreign_proc_component holds one component of a foreign_proc_code
|
|
% instruction.
|
|
%
|
|
:- type foreign_proc_component
|
|
---> foreign_proc_inputs(list(foreign_proc_input))
|
|
; foreign_proc_outputs(list(foreign_proc_output))
|
|
; foreign_proc_user_code(maybe(prog_context), proc_affects_liveness,
|
|
string)
|
|
; foreign_proc_raw_code(can_branch_away, proc_affects_liveness,
|
|
c_code_live_lvals, string)
|
|
; foreign_proc_fail_to(label)
|
|
; foreign_proc_alloc_id(alloc_site_id)
|
|
; foreign_proc_noop.
|
|
|
|
:- type can_branch_away
|
|
---> can_branch_away
|
|
; cannot_branch_away.
|
|
|
|
% A foreign_proc_input represents the code that initializes one
|
|
% of the input variables for a foreign_proc_code instruction.
|
|
%
|
|
:- type foreign_proc_input
|
|
---> foreign_proc_input(
|
|
% The name of the foreign language variable.
|
|
in_foreign_lang_var_name :: string,
|
|
|
|
% The type of the Mercury variable being passed.
|
|
in_var_type :: mer_type,
|
|
|
|
% Whether in_var_type is a dummy type.
|
|
in_var_type_is_dummy :: is_dummy_type,
|
|
|
|
% The type of the argument in original foreign_proc procedure.
|
|
% If the foreign_proc was inlined in some other procedure,
|
|
% then the in_var_type can be an instance of in_original_type;
|
|
% otherwise, the two should be the same.
|
|
in_original_type :: mer_type,
|
|
|
|
% The value being passed.
|
|
in_arg_value :: rval,
|
|
|
|
% If in_original_type is a foreign type, info about
|
|
% that foreign type.
|
|
in_maybe_foreign_type :: maybe(foreign_proc_type),
|
|
|
|
in_box_policy :: box_policy
|
|
).
|
|
|
|
% A foreign_proc_output represents the code that stores one of
|
|
% of the outputs for a foreign_proc_code instruction.
|
|
%
|
|
:- type foreign_proc_output
|
|
---> foreign_proc_output(
|
|
% The place where the foreign_proc should put this output.
|
|
out_arg_dest :: lval,
|
|
|
|
% The type of the Mercury variable being passed.
|
|
out_var_type :: mer_type,
|
|
|
|
% Whether out_var_type is a dummy type.
|
|
out_var_type_is_dummy :: is_dummy_type,
|
|
|
|
% The type of the argument in original foreign_proc procedure;
|
|
% see in_original_type above.
|
|
out_original_type :: mer_type,
|
|
|
|
% The name of the foreign language variable.
|
|
out_var_name :: string,
|
|
|
|
% If in_original_type is a foreign type, info about
|
|
% that foreign type.
|
|
out_maybe_foreign_type :: maybe(foreign_proc_type),
|
|
|
|
out_box_policy :: box_policy
|
|
).
|
|
|
|
:- type foreign_proc_type
|
|
---> foreign_proc_type(
|
|
string, % The C type name.
|
|
foreign_type_assertions
|
|
% The assertions on the foreign_type
|
|
% declarations that the C type name came from.
|
|
).
|
|
|
|
:- type add_trail_ops
|
|
---> add_trail_ops
|
|
; do_not_add_trail_ops.
|
|
|
|
:- type add_region_ops
|
|
---> add_region_ops
|
|
; do_not_add_region_ops.
|
|
|
|
% See runtime/mercury_trail.h.
|
|
:- type reset_trail_reason
|
|
---> reset_reason_undo
|
|
; reset_reason_commit
|
|
; reset_reason_solve
|
|
; reset_reason_exception
|
|
; reset_reason_retry
|
|
; reset_reason_gc.
|
|
|
|
% See runtime/mercury_region.h
|
|
% XXX The documentation is not there yet, but should be there soon.
|
|
:- type region_stack_id
|
|
---> region_stack_ite
|
|
; region_stack_disj
|
|
; region_stack_commit.
|
|
|
|
:- type region_fill_frame_op
|
|
---> region_fill_ite_protect
|
|
; region_fill_ite_snapshot(removed_at_start_of_else)
|
|
; region_fill_semi_disj_protect
|
|
; region_fill_disj_snapshot
|
|
; region_fill_commit.
|
|
|
|
:- type removed_at_start_of_else
|
|
---> removed_at_start_of_else
|
|
; not_removed_at_start_of_else.
|
|
|
|
:- type region_set_fixed_op
|
|
---> region_set_ite_num_protects
|
|
; region_set_ite_num_snapshots
|
|
; region_set_disj_num_protects
|
|
; region_set_disj_num_snapshots
|
|
; region_set_commit_num_entries.
|
|
|
|
:- type region_use_frame_op
|
|
---> region_ite_then(region_ite_kind) % uses; pop only if semi
|
|
; region_ite_else(region_ite_kind) % uses and pops
|
|
; region_ite_nondet_cond_fail % pops
|
|
; region_disj_later % uses
|
|
; region_disj_last % uses and pops
|
|
; region_disj_nonlast_semi_commit % uses and pops
|
|
; region_commit_success % uses and pops
|
|
; region_commit_failure. % only pops
|
|
|
|
:- type region_ite_kind
|
|
---> region_ite_semidet_cond
|
|
; region_ite_nondet_cond.
|
|
|
|
:- type embedded_stack_frame_id
|
|
---> embedded_stack_frame_id(
|
|
% The embedded stack frame consists of the lvals
|
|
%
|
|
% stack_slot_num_to_lval(StackId, FirstSlot)
|
|
% to
|
|
% stack_slot_num_to_lval(StackId, LastSlot)
|
|
%
|
|
% with FirstSlot < LastSlot.
|
|
|
|
main_stack, % StackId
|
|
int, % FirstSlot
|
|
int % LastSlot
|
|
).
|
|
|
|
% first_nonfixed_embedded_slot_addr(EmbeddedStackId, FixedSize):
|
|
%
|
|
% Return the address of the lowest-address non-fixed slot in the given
|
|
% embedded stack frame.
|
|
%
|
|
:- func first_nonfixed_embedded_slot_addr(embedded_stack_frame_id, int) = rval.
|
|
|
|
% 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 native garbage collector.
|
|
%
|
|
:- type liveinfo
|
|
---> live_lvalue(
|
|
% What location does this lifeinfo structure refer to?
|
|
layout_locn,
|
|
|
|
% What is the type of this live value?
|
|
live_value_type,
|
|
|
|
% 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.
|
|
map(tvar, set(layout_locn))
|
|
).
|
|
|
|
% For an explanation of this type, see the comment on
|
|
% stack_layout.represent_locn.
|
|
%
|
|
:- type layout_locn
|
|
---> locn_direct(lval)
|
|
; locn_indirect(lval, int).
|
|
|
|
% live_value_type describes the different sorts of data that
|
|
% can be considered live.
|
|
%
|
|
:- type live_value_type
|
|
---> live_value_succip % A stored succip.
|
|
; live_value_curfr % A stored curfr.
|
|
; live_value_maxfr % A stored maxfr.
|
|
; live_value_redoip % A stored redoip.
|
|
; live_value_redofr % A stored redofr.
|
|
; live_value_hp % A stored heap pointer.
|
|
; live_value_trail_ptr % A stored trail pointer.
|
|
; live_value_ticket % A stored ticket.
|
|
; live_value_region_ite
|
|
; live_value_region_disj
|
|
; live_value_region_commit
|
|
|
|
; live_value_var(prog_var, string, mer_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).
|
|
|
|
; live_value_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 variables.
|
|
%
|
|
% At the moment, the LLDS only handles ground insts. When this changes,
|
|
% the argument type of partial will have to be changed, and the code
|
|
% that sets this field in live_value_var will have some actual work to do.
|
|
%
|
|
:- type llds_inst
|
|
---> llds_inst_better_be_ground.
|
|
|
|
:- func stack_slot_to_lval(stack_slot) = lval.
|
|
:- func key_stack_slot_to_lval(_, stack_slot) = lval.
|
|
|
|
:- type lval_or_any_reg
|
|
---> loa_lval(lval)
|
|
; loa_any_reg.
|
|
|
|
:- func abs_locn_to_lval_or_any_reg(abs_locn) = lval_or_any_reg.
|
|
|
|
:- func abs_locn_to_lval(abs_locn) = lval.
|
|
|
|
:- func key_abs_locn_to_lval(_, abs_locn) = lval.
|
|
|
|
:- type main_stack
|
|
---> det_stack
|
|
; nondet_stack.
|
|
|
|
% Return the id of the stack on which procedures with the given code model
|
|
% have their stack frames.
|
|
%
|
|
:- func code_model_to_main_stack(code_model) = main_stack.
|
|
|
|
% stack_slot_num_to_lval(StackId, N):
|
|
%
|
|
% Return an lval for slot N in a stack frame on StackId.
|
|
%
|
|
:- func stack_slot_num_to_lval(main_stack, int) = lval.
|
|
|
|
% stack_slot_num_to_lval(StackId, N):
|
|
%
|
|
% Return an rval for the address of slot N in a stack frame on StackId.
|
|
%
|
|
:- func stack_slot_num_to_lval_ref(main_stack, int) = rval.
|
|
|
|
% 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
|
|
% the 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 pointing to the top of det stack.
|
|
|
|
; parent_sp
|
|
% Virtual machine register pointing to the top of the det stack.
|
|
% This is only set at the beginning of a parallel conjunction (and
|
|
% restored afterwards). Parallel conjuncts which refer to stack
|
|
% slots use this register instead of sp, as they could be running
|
|
% in a different context, where sp would be pointing into a
|
|
% different 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 use_local_vars.m.
|
|
% 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.
|
|
|
|
; parent_stackvar(int)
|
|
% A det stack slot. The number is the offset relative to the
|
|
% value of `parent_sp'. These are used only in the code
|
|
% of parallel conjuncts. 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.
|
|
|
|
; double_stackvar(double_stack_type, int)
|
|
% Two consecutive stack slots for storing a double-precision float.
|
|
% The number is the offset relative to one of the stack pointers
|
|
% and represents the lower-numbered of two consecutive slots.
|
|
% As our stacks grow upward, they are addressed relative to the
|
|
% stack pointer at the top, so the higher-numbered slot has the
|
|
% lower address, and must be aligned for the target architecture.
|
|
%
|
|
% - stackvar(Slot), stackvar(Slot + 1)
|
|
% - parent_stackvar(Slot), parent_stackvar(Slot + 1)
|
|
|
|
; succip_slot(rval)
|
|
% The succip slot of the specified nondet stack frame; holds the
|
|
% code address to jump to on successful exit from this nondet
|
|
% procedure.
|
|
|
|
; succfr_slot(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.
|
|
|
|
; redoip_slot(rval)
|
|
% The redoip slot of the specified nondet stack frame; holds the
|
|
% code address to jump to on failure.
|
|
|
|
; redofr_slot(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.
|
|
|
|
; prevfr_slot(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(ptag), rval, rval)
|
|
% field(MaybePtag, Address, FieldNum) selects one 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 MaybePtag is yes,
|
|
% its argument gives the value of the primary tag to be subtracted
|
|
% from Address; if it is no, the primary tag bits will have to be
|
|
% masked off. The value of the primary 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.
|
|
|
|
; global_var_ref(c_global_var_ref)
|
|
% A reference to the value of the C global variable with the given
|
|
% name. At least for now, the global variable's type must be
|
|
% MR_Word.
|
|
|
|
% 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.
|
|
|
|
:- type double_stack_type
|
|
---> double_stackvar
|
|
; double_parent_stackvar.
|
|
|
|
% 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.
|
|
|
|
; mkword(ptag, rval)
|
|
% Given a pointer and a ptag, mkword returns a tagged pointer.
|
|
|
|
; mkword_hole(ptag)
|
|
% Make a tagged pointer to an address which is not yet known.
|
|
|
|
; const(rval_const)
|
|
|
|
; cast(llds_type, rval)
|
|
|
|
; 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 mem_ref
|
|
---> stackvar_ref(rval)
|
|
% Stack slot number.
|
|
|
|
; framevar_ref(rval)
|
|
% Stack slot number.
|
|
|
|
; heap_ref(rval, maybe(ptag), rval).
|
|
% The cell pointer, the ptag to subtract (if unknown, all the
|
|
% primary tag bits must be masked off), and the field number.
|
|
|
|
:- type c_global_var_ref
|
|
---> env_var_ref(string).
|
|
|
|
:- type rval_const
|
|
---> llconst_true
|
|
; llconst_false
|
|
|
|
; llconst_int(int)
|
|
; llconst_uint(uint)
|
|
|
|
; llconst_int8(int8)
|
|
; llconst_uint8(uint8)
|
|
|
|
; llconst_int16(int16)
|
|
; llconst_uint16(uint16)
|
|
|
|
; llconst_int32(int32)
|
|
; llconst_uint32(uint32)
|
|
|
|
; llconst_int64(int64)
|
|
; llconst_uint64(uint64)
|
|
|
|
; llconst_foreign(string, llds_type)
|
|
% A constant in the target language.
|
|
% It may be a #defined constant in C which is why
|
|
% it is represented as string.
|
|
|
|
; llconst_float(float)
|
|
|
|
; llconst_string(string)
|
|
% A string constant that may not contain NULL characters,
|
|
% but for which the compiler will emit a NULL character
|
|
% at the end.
|
|
; llconst_multi_string(list(string))
|
|
% A sequence of zero or more of the above kind of string constants,
|
|
% for which the compiler will emit a NULL character after
|
|
% each and every one. There will thus be a NULL character
|
|
% between consecutive strings in the list, as well as at the end.
|
|
|
|
% As mentioned in the top-of-module comment in library/string.m,
|
|
% the strings in both kinds of constants may contain code unit
|
|
% sequences that are invalid according to the rules of the encoding
|
|
% (UTF-8 or UTF-16) used by the platform that the compiler is
|
|
% running on. This may happen accidentally, due to a string
|
|
% read in from a file not being vetted, but it can also happen
|
|
% deliberately: the trie method of implementing switches on strings
|
|
% sometimes constructs strings from code unit sequences *even when*
|
|
% it is known that those sequences may contain some but not all
|
|
% of the code units belonging to a single code point.
|
|
|
|
; llconst_code_addr(code_addr)
|
|
; llconst_data_addr(data_id)
|
|
; llconst_data_addr_word_offset(data_id, int).
|
|
% The second version of llconst_data_addr specifies that the
|
|
% effective address should be the given number of words *past*
|
|
% the start of the given data_id.
|
|
|
|
% A data_id is an lval representing the given variable or array slot.
|
|
% Most references to the data_ref will want to take the address of this
|
|
% lval (by sticking a & in front of it), but in a few situations we need
|
|
% to be able to refer to the lval itself. One of those situations is when
|
|
% we are defining the variable. Another is when the variable is an array,
|
|
% and its name is implicitly taken by the C compiler as the address of the
|
|
% first element.
|
|
%
|
|
:- type data_id
|
|
---> rtti_data_id(rtti_id)
|
|
% The global variable holding the RTTI structure identified
|
|
% by the rtti_id.
|
|
|
|
; proc_tabling_data_id(proc_label, proc_tabling_struct_id)
|
|
% The tabling structure of the kind identified by the
|
|
% proc_tabling_struct_id for the procedure given by the
|
|
% proc_label.
|
|
|
|
; scalar_common_data_id(type_num, int)
|
|
% scalar_common_ref(TypeNum, CellNum) is the slot at index CellNum
|
|
% in the array of scalar cells of type TypeNum.
|
|
|
|
; vector_common_data_id(type_num, int)
|
|
% vector_common_ref(TypeNum, CellNum) is the sequence of slots
|
|
% starting at index CellNum in the array of vector cells of
|
|
% type TypeNum.
|
|
|
|
; layout_id(layout_name)
|
|
% The global variable holding the layout structure identified
|
|
% by the layout_name.
|
|
|
|
; layout_slot_id(layout_slot_id_kind, pred_proc_id).
|
|
% The slot reserved for the given pred_proc_id in the array
|
|
% identified by the layout_slot_id_kind.
|
|
|
|
:- type layout_slot_id_kind
|
|
---> table_io_entry_id.
|
|
|
|
% There are two kinds of labels: entry labels and internal labels.
|
|
% Entry labels are the entry points of procedures; internal labels are not.
|
|
%
|
|
% We have three ways of referring to entry labels. One way is valid from
|
|
% everywhere in the program (external). Another way is valid only from
|
|
% within the C file that defines the procedure (local). The last is valid
|
|
% only from within the BEGIN_MODULE/END_MODULE pair that contains the
|
|
% procedure definition. The more specialized the reference, the faster
|
|
% jumping to the label may be, though the implementations of adjacent
|
|
% entry_label_types may be identical in some grades.
|
|
%
|
|
% It is valid to declare a label using one entry_label_type and to
|
|
% refer to it using a more specialized entry_label_type.
|
|
|
|
:- type entry_label_type
|
|
---> entry_label_c_local
|
|
% proc entry; internal to a C module
|
|
; entry_label_local
|
|
% proc entry; internal to a Mercury module
|
|
; entry_label_exported.
|
|
% proc entry; exported from a Mercury module
|
|
|
|
:- type label
|
|
---> internal_label(int, proc_label)
|
|
; entry_label(entry_label_type, proc_label).
|
|
|
|
:- type code_addr
|
|
---> code_label(label)
|
|
% A label defined in this Mercury module.
|
|
|
|
; code_imported_proc(proc_label)
|
|
% A label for a procedure from another Mercury module.
|
|
|
|
; code_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(ho_call_variant)
|
|
; do_call_class_method(ho_call_variant)
|
|
|
|
; do_not_reached.
|
|
% We should never jump to this address.
|
|
|
|
:- type ho_call_variant
|
|
---> generic
|
|
% This calls for the use of one of do_call_closure_compact and
|
|
% do_call_class_method_compact which works for any number of
|
|
% visible input arguments.
|
|
|
|
; specialized_known(int).
|
|
% If the integer is N, this calls for the use of do_call_closure_N
|
|
% or do_call_class_method_N. These are specialized to assume N
|
|
% visible regular register input arguments, and zero visible float
|
|
% register input arguments.
|
|
|
|
% Each function symbol of this type corresponds to one of the C types
|
|
% {int,uint}_least{8,16,32}.
|
|
%
|
|
% Values of these types are intended for use in static data declarations,
|
|
% not for data that gets stored in registers, stack slots etc.
|
|
:- type int_least_type
|
|
---> int_least8
|
|
; uint_least8
|
|
; int_least16
|
|
; uint_least16
|
|
; int_least32
|
|
; uint_least32.
|
|
|
|
% 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
|
|
---> lt_bool
|
|
% A boolean value represented using the C type `MR_Integer'.
|
|
|
|
; lt_int_least(int_least_type)
|
|
% As documented above.
|
|
|
|
; lt_int(int_type)
|
|
% 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).
|
|
% Something whose C type is `MR_Unsigned' (the unsigned equivalent
|
|
% of `MR_Integer').
|
|
|
|
; lt_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').
|
|
|
|
; lt_string
|
|
% A Mercury string; represented in C as a value of type
|
|
% `MR_String'.
|
|
|
|
; lt_data_ptr
|
|
% A pointer to data; represented in C as a value of C type
|
|
% `MR_Word *'.
|
|
|
|
; lt_code_ptr
|
|
% A pointer to code; represented in C as a value of C type
|
|
% `MR_Code *'.
|
|
|
|
; lt_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).
|
|
|
|
:- type cell_arg
|
|
---> cell_arg_full_word(rval, completeness)
|
|
% Fill a single word field of a cell with the given rval, which
|
|
% could hold a single constructor argument, or multiple constructor
|
|
% arguments if they are packed. If the second argument is
|
|
% `incomplete' it means that the rval covers multiple constructor
|
|
% arguments but some of the arguments are not instantiated.
|
|
|
|
; cell_arg_double_word(rval)
|
|
% Fill two words of a cell with the given rval, which must be a
|
|
% double precision float.
|
|
|
|
; cell_arg_skip_one_word
|
|
; cell_arg_skip_two_words
|
|
% Leave one or two words of a cell unfilled.
|
|
|
|
; cell_arg_take_addr_one_word(prog_var, maybe(rval))
|
|
; cell_arg_take_addr_two_words(prog_var, maybe({rval, rval})).
|
|
% Take the address of a one- or two-word field.
|
|
% If the second argument is `yes(Rval/Rvals)',
|
|
% then set the field to Rval/Rvals beforehand.
|
|
|
|
:- type completeness
|
|
---> complete
|
|
; incomplete.
|
|
|
|
:- func region_stack_id_to_string(region_stack_id) = string.
|
|
|
|
:- pred break_up_local_label(label::in, proc_label::out, int::out) is det.
|
|
|
|
% Given a non-var lval, figure out its type.
|
|
%
|
|
:- pred lval_type(lval::in, llds_type::out) is det.
|
|
|
|
% Given a non-var rval, figure out its type.
|
|
%
|
|
:- pred rval_type(rval::in, llds_type::out) is det.
|
|
|
|
% Given a constant, figure out its type.
|
|
%
|
|
:- pred const_type(rval_const::in, llds_type::out) is det.
|
|
|
|
% Given a unary operator, figure out its return type.
|
|
%
|
|
:- pred unop_return_type(unary_op::in, llds_type::out) is det.
|
|
|
|
% Given a unary operator, figure out the type of its argument.
|
|
%
|
|
:- pred unop_arg_type(unary_op::in, llds_type::out) is det.
|
|
|
|
% Given a binary operator, figure out its return type.
|
|
%
|
|
:- pred binop_return_type(binary_op::in, llds_type::out) is det.
|
|
|
|
% Given a register, figure out its type.
|
|
%
|
|
:- pred register_type(reg_type::in, llds_type::out) is det.
|
|
|
|
:- func get_proc_label(label) = proc_label.
|
|
|
|
:- func get_defining_module_name(proc_label) = module_name.
|
|
|
|
:- type have_non_local_gotos
|
|
---> have_non_local_gotos
|
|
; do_not_have_non_local_gotos.
|
|
|
|
:- type have_asm_labels
|
|
---> have_asm_labels
|
|
; do_not_have_asm_labels.
|
|
|
|
:- type have_unboxed_floats
|
|
---> have_unboxed_floats
|
|
; do_not_have_unboxed_floats.
|
|
|
|
:- type use_float_registers
|
|
---> use_float_registers
|
|
; do_not_use_float_registers.
|
|
|
|
:- type have_unboxed_int64s
|
|
---> have_unboxed_int64s
|
|
; do_not_have_unboxed_int64s.
|
|
|
|
:- type have_static_ground_cells
|
|
---> have_static_ground_cells
|
|
; do_not_have_static_ground_cells.
|
|
|
|
:- type have_static_ground_floats
|
|
---> have_static_ground_floats
|
|
; do_not_have_static_ground_floats.
|
|
|
|
:- type have_static_ground_int64s
|
|
---> have_static_ground_int64s
|
|
; do_not_have_static_ground_int64s.
|
|
|
|
:- type have_static_code_addresses
|
|
---> have_static_code_addresses
|
|
; do_not_have_static_code_addresses.
|
|
|
|
:- type exprn_opts
|
|
---> exprn_opts(
|
|
non_local_gotos :: have_non_local_gotos,
|
|
asm_labels :: have_asm_labels,
|
|
unboxed_floats :: have_unboxed_floats,
|
|
float_registers :: use_float_registers,
|
|
det_stack_float_width :: stack_slot_width,
|
|
unboxed_int64s :: have_unboxed_int64s,
|
|
static_ground_cells :: have_static_ground_cells,
|
|
static_ground_floats :: have_static_ground_floats,
|
|
static_ground_int64s :: have_static_ground_int64s,
|
|
static_code_addresses :: have_static_code_addresses
|
|
).
|
|
|
|
:- func get_nonlocal_gotos(exprn_opts) = have_non_local_gotos.
|
|
:- func get_asm_labels(exprn_opts) = have_asm_labels.
|
|
:- func get_unboxed_floats(exprn_opts) = have_unboxed_floats.
|
|
:- func get_float_registers(exprn_opts) = use_float_registers.
|
|
:- func get_det_stack_float_width(exprn_opts) = stack_slot_width.
|
|
:- func get_unboxed_int64s(exprn_opts) = have_unboxed_int64s.
|
|
:- func get_static_ground_cells(exprn_opts) = have_static_ground_cells.
|
|
:- func get_static_ground_floats(exprn_opts) = have_static_ground_floats.
|
|
:- func get_static_ground_int64s(exprn_opts) = have_static_ground_int64s.
|
|
:- func get_static_code_addresses(exprn_opts) = have_static_code_addresses.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
:- import_module require.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
typed_rvals_project_rvals([]) = [].
|
|
typed_rvals_project_rvals([typed_rval(Rval, _Type) | TypedRvals]) =
|
|
[Rval | typed_rvals_project_rvals(TypedRvals)].
|
|
|
|
typed_rvals_project_types([]) = [].
|
|
typed_rvals_project_types([typed_rval(_Rval, Type) | TypedRvals]) =
|
|
[Type | typed_rvals_project_types(TypedRvals)].
|
|
|
|
build_typed_rvals([], [], []).
|
|
build_typed_rvals([_|_], [], _) :-
|
|
unexpected($pred, "length mismatch").
|
|
build_typed_rvals([], [_|_], _) :-
|
|
unexpected($pred, "length mismatch").
|
|
build_typed_rvals([Rval | Rvals], [Type | Types], [TypedRval | TypedRvals]) :-
|
|
TypedRval = typed_rval(Rval, Type),
|
|
build_typed_rvals(Rvals, Types, TypedRvals).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
first_nonfixed_embedded_slot_addr(EmbeddedStackId, FixedSize) = Rval :-
|
|
EmbeddedStackId = embedded_stack_frame_id(MainStackId,
|
|
_FirstSlot, LastSlot),
|
|
% LastSlot has the lowest address; FirstSlot has the highest address.
|
|
% The fixed slots are at the lowest addresses.
|
|
% XXX Quan: we may need a +1 here.
|
|
LowestAddrNonfixedSlot = LastSlot - FixedSize,
|
|
Rval = stack_slot_num_to_lval_ref(MainStackId, LowestAddrNonfixedSlot).
|
|
|
|
stack_slot_to_lval(Slot) = Lval :-
|
|
(
|
|
Slot = det_slot(N, Width),
|
|
(
|
|
Width = single_width,
|
|
Lval = stackvar(N)
|
|
;
|
|
Width = double_width,
|
|
Lval = double_stackvar(double_stackvar, N)
|
|
)
|
|
;
|
|
Slot = parent_det_slot(N, Width),
|
|
(
|
|
Width = single_width,
|
|
Lval = parent_stackvar(N)
|
|
;
|
|
Width = double_width,
|
|
Lval = double_stackvar(double_parent_stackvar, N)
|
|
)
|
|
;
|
|
Slot = nondet_slot(N),
|
|
Lval = framevar(N)
|
|
).
|
|
|
|
key_stack_slot_to_lval(_, Slot) =
|
|
stack_slot_to_lval(Slot).
|
|
|
|
abs_locn_to_lval_or_any_reg(any_reg) = loa_any_reg.
|
|
abs_locn_to_lval_or_any_reg(abs_reg(Type, N)) = loa_lval(reg(Type, N)).
|
|
abs_locn_to_lval_or_any_reg(abs_stackvar(N, Width)) =
|
|
loa_lval(stack_slot_to_lval(det_slot(N, Width))).
|
|
abs_locn_to_lval_or_any_reg(abs_parent_stackvar(N, Width)) =
|
|
loa_lval(stack_slot_to_lval(parent_det_slot(N, Width))).
|
|
abs_locn_to_lval_or_any_reg(abs_framevar(N)) =
|
|
loa_lval(stack_slot_to_lval(nondet_slot(N))).
|
|
|
|
abs_locn_to_lval(any_reg) = _ :-
|
|
unexpected($pred, "any_reg").
|
|
abs_locn_to_lval(abs_reg(Type, N)) = reg(Type, N).
|
|
abs_locn_to_lval(abs_stackvar(N, Width)) =
|
|
stack_slot_to_lval(det_slot(N, Width)).
|
|
abs_locn_to_lval(abs_parent_stackvar(N, Width)) =
|
|
stack_slot_to_lval(parent_det_slot(N, Width)).
|
|
abs_locn_to_lval(abs_framevar(N)) =
|
|
stack_slot_to_lval(nondet_slot(N)).
|
|
|
|
key_abs_locn_to_lval(_, AbsLocn) =
|
|
abs_locn_to_lval(AbsLocn).
|
|
|
|
code_model_to_main_stack(model_det) = det_stack.
|
|
code_model_to_main_stack(model_semi) = det_stack.
|
|
code_model_to_main_stack(model_non) = nondet_stack.
|
|
|
|
stack_slot_num_to_lval(det_stack, SlotNum) = stackvar(SlotNum).
|
|
stack_slot_num_to_lval(nondet_stack, SlotNum) = framevar(SlotNum).
|
|
|
|
stack_slot_num_to_lval_ref(det_stack, SlotNum) =
|
|
mem_addr(stackvar_ref(const(llconst_int(SlotNum)))).
|
|
stack_slot_num_to_lval_ref(nondet_stack, SlotNum) =
|
|
mem_addr(framevar_ref(const(llconst_int(SlotNum)))).
|
|
|
|
region_stack_id_to_string(region_stack_ite) = "region_ite_stack".
|
|
region_stack_id_to_string(region_stack_disj) = "region_disj_stack".
|
|
region_stack_id_to_string(region_stack_commit) = "region_commit_stack".
|
|
|
|
break_up_local_label(Label, ProcLabel, LabelNum) :-
|
|
(
|
|
Label = internal_label(LabelNum, ProcLabel)
|
|
;
|
|
Label = entry_label(_, _),
|
|
unexpected($pred, "entry label")
|
|
).
|
|
|
|
lval_type(reg(RegType, _), Type) :-
|
|
register_type(RegType, Type).
|
|
lval_type(succip, lt_code_ptr).
|
|
lval_type(maxfr, lt_data_ptr).
|
|
lval_type(curfr, lt_data_ptr).
|
|
lval_type(hp, lt_data_ptr).
|
|
lval_type(sp, lt_data_ptr).
|
|
lval_type(parent_sp, lt_data_ptr).
|
|
lval_type(temp(RegType, _), Type) :-
|
|
register_type(RegType, Type).
|
|
lval_type(stackvar(_), lt_word).
|
|
lval_type(parent_stackvar(_), lt_word).
|
|
lval_type(framevar(_), lt_word).
|
|
lval_type(double_stackvar(_, _), lt_float).
|
|
lval_type(succip_slot(_), lt_code_ptr).
|
|
lval_type(redoip_slot(_), lt_code_ptr).
|
|
lval_type(redofr_slot(_), lt_data_ptr).
|
|
lval_type(succfr_slot(_), lt_data_ptr).
|
|
lval_type(prevfr_slot(_), lt_data_ptr).
|
|
lval_type(field(_, _, _), lt_word).
|
|
lval_type(lvar(_), _) :-
|
|
unexpected($pred, "lvar").
|
|
lval_type(mem_ref(_), lt_word).
|
|
lval_type(global_var_ref(_), lt_word).
|
|
|
|
rval_type(lval(Lval), Type) :-
|
|
lval_type(Lval, Type).
|
|
rval_type(var(_), _) :-
|
|
unexpected($pred, "var").
|
|
%
|
|
% Note that mkword and data_addr consts must be of type data_ptr,
|
|
% not of type word, to ensure that static consts containing them
|
|
% get type `const MR_Word *', not type `MR_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 is only the reverse direction we need to avoid.
|
|
%
|
|
rval_type(mkword(_, _), lt_data_ptr).
|
|
rval_type(mkword_hole(_), lt_data_ptr).
|
|
rval_type(const(Const), Type) :-
|
|
const_type(Const, Type).
|
|
rval_type(cast(Type, _), Type).
|
|
rval_type(unop(UnOp, _), Type) :-
|
|
unop_return_type(UnOp, Type).
|
|
rval_type(binop(BinOp, _, _), Type) :-
|
|
binop_return_type(BinOp, Type).
|
|
rval_type(mem_addr(_), lt_data_ptr).
|
|
|
|
const_type(llconst_true, lt_bool).
|
|
const_type(llconst_false, lt_bool).
|
|
const_type(llconst_int(_), lt_int(int_type_int)).
|
|
const_type(llconst_uint(_), lt_int(int_type_uint)).
|
|
const_type(llconst_int8(_), lt_int(int_type_int8)).
|
|
const_type(llconst_uint8(_), lt_int(int_type_uint8)).
|
|
const_type(llconst_int16(_), lt_int(int_type_int16)).
|
|
const_type(llconst_uint16(_), lt_int(int_type_uint16)).
|
|
const_type(llconst_int32(_), lt_int(int_type_int32)).
|
|
const_type(llconst_uint32(_), lt_int(int_type_uint32)).
|
|
const_type(llconst_int64(_), lt_int(int_type_int64)).
|
|
const_type(llconst_uint64(_), lt_int(int_type_uint64)).
|
|
const_type(llconst_foreign(_, Type), Type).
|
|
const_type(llconst_float(_), lt_float).
|
|
const_type(llconst_string(_), lt_string).
|
|
const_type(llconst_multi_string(_), lt_string).
|
|
const_type(llconst_code_addr(_), lt_code_ptr).
|
|
const_type(llconst_data_addr(_), lt_data_ptr).
|
|
const_type(llconst_data_addr_word_offset(_, _), lt_data_ptr).
|
|
|
|
unop_return_type(tag, lt_word).
|
|
unop_return_type(strip_tag, lt_word).
|
|
unop_return_type(mkbody, lt_word).
|
|
unop_return_type(unmkbody, lt_word).
|
|
unop_return_type(bitwise_complement(IntType), lt_int(IntType)).
|
|
unop_return_type(logical_not, lt_bool).
|
|
unop_return_type(hash_string, lt_int(int_type_int)).
|
|
unop_return_type(hash_string2, lt_int(int_type_int)).
|
|
unop_return_type(hash_string3, lt_int(int_type_int)).
|
|
unop_return_type(hash_string4, lt_int(int_type_int)).
|
|
unop_return_type(hash_string5, lt_int(int_type_int)).
|
|
unop_return_type(hash_string6, lt_int(int_type_int)).
|
|
unop_return_type(dword_float_get_word0, lt_word).
|
|
unop_return_type(dword_float_get_word1, lt_word).
|
|
unop_return_type(dword_int64_get_word0, lt_word).
|
|
unop_return_type(dword_int64_get_word1, lt_word).
|
|
unop_return_type(dword_uint64_get_word0, lt_word).
|
|
unop_return_type(dword_uint64_get_word1, lt_word).
|
|
|
|
unop_arg_type(tag, lt_word).
|
|
unop_arg_type(strip_tag, lt_word).
|
|
unop_arg_type(mkbody, lt_word).
|
|
unop_arg_type(unmkbody, lt_word).
|
|
unop_arg_type(bitwise_complement(IntType), lt_int(IntType)).
|
|
unop_arg_type(logical_not, lt_bool).
|
|
unop_arg_type(hash_string, lt_string).
|
|
unop_arg_type(hash_string2, lt_string).
|
|
unop_arg_type(hash_string3, lt_string).
|
|
unop_arg_type(hash_string4, lt_string).
|
|
unop_arg_type(hash_string5, lt_string).
|
|
unop_arg_type(hash_string6, lt_string).
|
|
unop_arg_type(dword_float_get_word0, lt_float).
|
|
unop_arg_type(dword_float_get_word1, lt_float).
|
|
unop_arg_type(dword_int64_get_word0, lt_int(int_type_int64)).
|
|
unop_arg_type(dword_int64_get_word1, lt_int(int_type_int64)).
|
|
unop_arg_type(dword_uint64_get_word0, lt_int(int_type_uint64)).
|
|
unop_arg_type(dword_uint64_get_word1, lt_int(int_type_uint64)).
|
|
|
|
binop_return_type(int_arith(IntType, _), lt_int(IntType)).
|
|
binop_return_type(unchecked_left_shift(IntType, _), lt_int(IntType)).
|
|
binop_return_type(unchecked_right_shift(IntType, _), lt_int(IntType)).
|
|
binop_return_type(bitwise_and(IntType), lt_int(IntType)).
|
|
binop_return_type(bitwise_or(IntType), lt_int(IntType)).
|
|
binop_return_type(bitwise_xor(IntType), lt_int(IntType)).
|
|
binop_return_type(logical_and, lt_bool).
|
|
binop_return_type(logical_or, lt_bool).
|
|
binop_return_type(int_cmp(_, _), lt_bool).
|
|
binop_return_type(array_index(_Type), lt_word).
|
|
binop_return_type(string_unsafe_index_code_unit, lt_int(int_type_int)).
|
|
binop_return_type(offset_str_eq(_, _), lt_bool).
|
|
binop_return_type(str_cmp(_), lt_bool).
|
|
binop_return_type(str_nzp, lt_int(int_type_int)).
|
|
binop_return_type(int_as_uint_cmp(_), lt_bool).
|
|
binop_return_type(in_range, lt_bool).
|
|
binop_return_type(float_arith(_), lt_float).
|
|
binop_return_type(float_cmp(_), lt_bool).
|
|
binop_return_type(float_from_dword, lt_float).
|
|
binop_return_type(int64_from_dword, lt_int(int_type_int64)).
|
|
binop_return_type(uint64_from_dword, lt_int(int_type_uint64)).
|
|
binop_return_type(body, lt_word).
|
|
binop_return_type(pointer_equal_conservative, lt_bool).
|
|
|
|
register_type(reg_r, lt_word).
|
|
register_type(reg_f, lt_float).
|
|
|
|
get_proc_label(entry_label(_, ProcLabel)) = ProcLabel.
|
|
get_proc_label(internal_label(_, ProcLabel)) = ProcLabel.
|
|
|
|
get_defining_module_name(ordinary_proc_label(ModuleName, _, _, _, _, _))
|
|
= ModuleName.
|
|
get_defining_module_name(special_proc_label(ModuleName, _, _, _, _, _))
|
|
= ModuleName.
|
|
|
|
get_nonlocal_gotos(ExprnOpts) = ExprnOpts ^ non_local_gotos.
|
|
get_asm_labels(ExprnOpts) = ExprnOpts ^ asm_labels.
|
|
get_unboxed_floats(ExprnOpts) = ExprnOpts ^ unboxed_floats.
|
|
get_float_registers(ExprnOpts) = ExprnOpts ^ float_registers.
|
|
get_det_stack_float_width(ExprnOpts) = ExprnOpts ^ det_stack_float_width.
|
|
get_unboxed_int64s(ExprnOpts) = ExprnOpts ^ unboxed_int64s.
|
|
get_static_ground_cells(ExprnOpts) = ExprnOpts ^ static_ground_cells.
|
|
get_static_ground_floats(ExprnOpts) = ExprnOpts ^ static_ground_floats.
|
|
get_static_ground_int64s(ExprnOpts) = ExprnOpts ^ static_ground_int64s.
|
|
get_static_code_addresses(ExprnOpts) = ExprnOpts ^ static_code_addresses.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module ll_backend.llds.
|
|
%-----------------------------------------------------------------------------%
|