mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 13:23:53 +00:00
Estimated hours taken: 3 A bunch of cleanups: improve error messages, tidy up the code. Also, do some work towards supporting higher-order functions. type_util.m: Add new predicate type_is_higher_order/3 for checking whether a type is a higher-order type. This recognizes both higher-order predicate types and also higher-order function types. code_info.m, modes.m, polymorphism.m, shapes.m: Use type_is_higher_order/3. make_hlds.m: Fix another error message to do the right thing when reporting errors for functions. mercury_to_mercury: List `func' in the table of operators, so that it gets parenthesized correctly. modes.m, mode_errors.m: Improve the error message for attempted higher-order unifications: spit out some context, and if verbose_errors is enabled, spit out a long description.
2596 lines
87 KiB
Mathematica
2596 lines
87 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% file: code_info.m
|
|
%
|
|
% main author: conway.
|
|
%
|
|
% This file defines the code_info type and various operations on it.
|
|
%
|
|
% The code_info structure is a 'state' used by the code generator.
|
|
%
|
|
% The following assumptions are made about the state of the high-level
|
|
% data structure:
|
|
% o Variables can be stored in any number of distinct places.
|
|
% o Registers may contain a value corresponding to more than
|
|
% one variable.
|
|
% o Procedures are in superhomogeneous form. This means that
|
|
% construction unifications and builtins are not nested.
|
|
% o Evaluation of arguments in construction and deconstruction
|
|
% unifications is lazy. This means that arguments in a
|
|
% `don't care' mode are ignored, and that assignments
|
|
% are cached.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module code_info.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_pred, hlds_goal, llds.
|
|
:- import_module code_util, tree, globals, unify_proc.
|
|
:- import_module bool, set, std_util, assoc_list.
|
|
|
|
:- type code_info.
|
|
|
|
% Create a new code_info structure.
|
|
:- pred code_info__init(varset, liveness_info, call_info, bool, globals,
|
|
pred_id, proc_id, proc_info, code_model, instmap,
|
|
follow_vars, module_info, shape_table, code_info).
|
|
:- mode code_info__init(in, in, in, in, in, in, in, in, in, in, in, in, in, out)
|
|
is det.
|
|
|
|
% Generate the next local label in sequence.
|
|
:- pred code_info__get_next_label(label, code_info, code_info).
|
|
:- mode code_info__get_next_label(out, in, out) is det.
|
|
|
|
% Generate the next local label number in sequence.
|
|
:- pred code_info__get_next_label_number(int, code_info, code_info).
|
|
:- mode code_info__get_next_label_number(out, in, out) is det.
|
|
|
|
% Sets up call to code_info__make_entry_label_2.
|
|
:- pred code_info__make_entry_label(module_info, pred_id, proc_id, code_addr,
|
|
code_info, code_info).
|
|
:- mode code_info__make_entry_label(in, in, in, out, in, out) is det.
|
|
|
|
% Create a code address for which holds the address
|
|
% of the specified predicate.
|
|
:- pred code_info__make_entry_label_2(module_info, int, pred_id, proc_id,
|
|
pred_id, proc_id, code_addr).
|
|
:- mode code_info__make_entry_label_2(in, in, in, in, in, in, out) is det.
|
|
|
|
% Get the variables for the current procedure.
|
|
:- pred code_info__get_varset(varset, code_info, code_info).
|
|
:- mode code_info__get_varset(out, in, out) is det.
|
|
|
|
% Set the variables for the current procedure.
|
|
:- pred code_info__set_varset(varset, code_info, code_info).
|
|
:- mode code_info__set_varset(in, in, out) is det.
|
|
|
|
% Get the hlds mapping from variables to
|
|
% stack slots
|
|
:- pred code_info__get_call_info(call_info, code_info, code_info).
|
|
:- mode code_info__get_call_info(out, in, out) is det.
|
|
|
|
% Set the hlds mapping from variables to
|
|
% stack slots
|
|
:- pred code_info__set_call_info(call_info, code_info, code_info).
|
|
:- mode code_info__set_call_info(in, in, out) is det.
|
|
|
|
:- pred code_info__get_pred_id(pred_id, code_info, code_info).
|
|
:- mode code_info__get_pred_id(out, in, out) is det.
|
|
|
|
:- pred code_info__set_pred_id(pred_id, code_info, code_info).
|
|
:- mode code_info__set_pred_id(in, in, out) is det.
|
|
|
|
:- pred code_info__get_proc_id(proc_id, code_info, code_info).
|
|
:- mode code_info__get_proc_id(out, in, out) is det.
|
|
|
|
:- pred code_info__set_proc_id(proc_id, code_info, code_info).
|
|
:- mode code_info__set_proc_id(in, in, out) is det.
|
|
|
|
:- pred code_info__cache_expression(var, rval, code_info, code_info).
|
|
:- mode code_info__cache_expression(in, in, in, out) is det.
|
|
|
|
% Generate code to either setup the input arguments for a call
|
|
% (i.e. in the caller), or to setup the output arguments in the
|
|
% predicate epilog (i.e. in the callee).
|
|
|
|
:- type call_direction ---> caller ; callee.
|
|
|
|
:- pred code_info__setup_call(assoc_list(var, arg_info),
|
|
call_direction, code_tree, code_info, code_info).
|
|
:- mode code_info__setup_call(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__save_variable_on_stack(var, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__save_variable_on_stack(in, out, in, out) is det.
|
|
|
|
% Succeed if the given variable is live at the
|
|
% end of this goal.
|
|
:- pred code_info__variable_is_live(var, code_info, code_info).
|
|
:- mode code_info__variable_is_live(in, in, out) is semidet.
|
|
|
|
% Get the call argument info for a given mode
|
|
% of a given predicate
|
|
:- pred code_info__get_pred_proc_arginfo(pred_id, proc_id, list(arg_info),
|
|
code_info, code_info).
|
|
:- mode code_info__get_pred_proc_arginfo(in, in, out, in, out) is det.
|
|
|
|
% Get the call argument information for the
|
|
% current procedure
|
|
:- pred code_info__get_arginfo(list(arg_info), code_info, code_info).
|
|
:- mode code_info__get_arginfo(out, in, out) is det.
|
|
|
|
:- pred code_info__get_headvars(list(var), code_info, code_info).
|
|
:- mode code_info__get_headvars(out, in, out) is det.
|
|
|
|
:- pred code_info__cons_id_to_tag(var, cons_id, cons_tag,
|
|
code_info, code_info).
|
|
:- mode code_info__cons_id_to_tag(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__get_total_stackslot_count(int, code_info, code_info).
|
|
:- mode code_info__get_total_stackslot_count(out, in, out) is det.
|
|
|
|
:- pred code_info__clear_all_registers(code_info, code_info).
|
|
:- mode code_info__clear_all_registers(in, out) is det.
|
|
|
|
:- pred code_info__get_live_variables(list(var), code_info, code_info).
|
|
:- mode code_info__get_live_variables(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_forced_saves(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_forced_saves(out, in, out) is det.
|
|
|
|
:- pred code_info__grab_code_info(code_info, code_info, code_info).
|
|
:- mode code_info__grab_code_info(out, in, out) is det.
|
|
|
|
:- pred code_info__slap_code_info(code_info, code_info, code_info).
|
|
:- mode code_info__slap_code_info(in, in, out) is det.
|
|
|
|
:- pred code_info__get_proc_info(proc_info, code_info, code_info).
|
|
:- mode code_info__get_proc_info(out, in, out) is det.
|
|
|
|
:- pred code_info__get_succip_used(bool, code_info, code_info).
|
|
:- mode code_info__get_succip_used(out, in, out) is det.
|
|
|
|
:- pred code_info__set_succip_used(bool, code_info, code_info).
|
|
:- mode code_info__set_succip_used(in, in, out) is det.
|
|
|
|
:- pred code_info__remake_with_store_map(code_info, code_info).
|
|
:- mode code_info__remake_with_store_map(in, out) is det.
|
|
|
|
:- pred code_info__remake_with_call_info(code_info, code_info).
|
|
:- mode code_info__remake_with_call_info(in, out) is det.
|
|
|
|
:- pred code_info__update_liveness_info(delta_liveness, code_info, code_info).
|
|
:- mode code_info__update_liveness_info(in, in, out) is det.
|
|
|
|
:- pred code_info__update_deadness_info(delta_liveness, code_info, code_info).
|
|
:- mode code_info__update_deadness_info(in, in, out) is det.
|
|
|
|
:- pred code_info__set_var_location(var, lval, code_info, code_info).
|
|
:- mode code_info__set_var_location(in, in, in, out) is det.
|
|
|
|
:- pred code_info__produce_variable(var, code_tree, rval, code_info, code_info).
|
|
:- mode code_info__produce_variable(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__produce_variable_in_reg(var, code_tree, rval,
|
|
code_info, code_info).
|
|
:- mode code_info__produce_variable_in_reg(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__place_var(var, lval, code_tree, code_info, code_info).
|
|
:- mode code_info__place_var(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__make_vars_dead(set(var), code_info, code_info).
|
|
:- mode code_info__make_vars_dead(in, in, out) is det.
|
|
|
|
:- pred code_info__make_vars_live(set(var), code_info, code_info).
|
|
:- mode code_info__make_vars_live(in, in, out) is det.
|
|
|
|
:- pred code_info__get_liveness_info(liveness_info, code_info, code_info).
|
|
:- mode code_info__get_liveness_info(out, in, out) is det.
|
|
|
|
:- pred code_info__set_liveness_info(liveness_info, code_info, code_info).
|
|
:- mode code_info__set_liveness_info(in, in, out) is det.
|
|
|
|
:- pred code_info__acquire_reg(reg, code_info, code_info).
|
|
:- mode code_info__acquire_reg(out, in, out) is det.
|
|
|
|
:- pred code_info__release_reg(reg, code_info, code_info).
|
|
:- mode code_info__release_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__lock_reg(reg, code_info, code_info).
|
|
:- mode code_info__lock_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__unlock_reg(reg, code_info, code_info).
|
|
:- mode code_info__unlock_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__get_module_info(module_info, code_info, code_info).
|
|
:- mode code_info__get_module_info(out, in, out) is det.
|
|
|
|
:- pred code_info__get_shapes(shape_table, code_info, code_info).
|
|
:- mode code_info__get_shapes(out, in, out) is det.
|
|
|
|
:- pred code_info__set_shapes(shape_table, code_info, code_info).
|
|
:- mode code_info__set_shapes(in, in, out) is det.
|
|
|
|
:- type failure_cont
|
|
---> failure_cont(failure_continuation, maybe(label), failure_map).
|
|
% the maybe(label) is yes if we created a
|
|
% temporary frame and we need to restore
|
|
% curfr after a redo()
|
|
|
|
:- type failure_continuation
|
|
---> known(bool) % on failure we jump to a label
|
|
% the bool is `yes' if we are inside
|
|
% a nondet context
|
|
; unknown. % on failure we do a `redo()'
|
|
% NB. any piece of code that sets the current
|
|
% failure continuation to `unknown' had
|
|
% better save variables that are live (on
|
|
% redo) onto the stack.
|
|
|
|
:- type failure_map == assoc_list(map(var, set(rval)), code_addr).
|
|
% we assume that there are exactly two
|
|
% alternatives in the failure_map list;
|
|
% the first one is the entry point with variables
|
|
% potentially in registers and the second one in
|
|
% the list is the entry point with variables on the
|
|
% stack.
|
|
|
|
% push a new failure continuation onto the stack
|
|
|
|
:- pred code_info__make_known_failure_cont(set(var), bool, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__make_known_failure_cont(in, in, out, in, out) is det.
|
|
|
|
% We manufacture a failure cont when we start generating
|
|
% code for a proc because on the failure of a procedure
|
|
% we don't need to prepare for execution to resume in this
|
|
% procedure.
|
|
:- pred code_info__manufacture_failure_cont(bool, code_info, code_info).
|
|
:- mode code_info__manufacture_failure_cont(in, in, out) is det.
|
|
|
|
% pop the failure continuation stack
|
|
|
|
:- pred code_info__pop_failure_cont(code_info, code_info).
|
|
:- mode code_info__pop_failure_cont(in, out) is det.
|
|
|
|
% set the topmost failure cont to `unknown' (e.g. after
|
|
% a nondet call or after a disjunction).
|
|
|
|
:- pred code_info__unset_failure_cont(code_info, code_info).
|
|
:- mode code_info__unset_failure_cont(in, out) is det.
|
|
|
|
% lookup the value on the top of the failure continuation stack
|
|
|
|
:- pred code_info__failure_cont(failure_cont, code_info, code_info).
|
|
:- mode code_info__failure_cont(out, in, out) is det.
|
|
|
|
% generate some code to restore the current redoip, by looking
|
|
% at the top of the failure continuation stack.
|
|
|
|
:- pred code_info__restore_failure_cont(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_failure_cont(out, in, out) is det.
|
|
|
|
:- pred code_info__modify_failure_cont(code_tree, code_info, code_info).
|
|
:- mode code_info__modify_failure_cont(out, in, out) is det.
|
|
|
|
% do_soft_cut takes the lval where the address of the
|
|
% failure frame is stored, and it returns code to
|
|
% set the redoip of that frame to do_fail.
|
|
|
|
:- pred code_info__do_soft_cut(lval, code_tree, code_info, code_info).
|
|
:- mode code_info__do_soft_cut(in, out, in, out) is det.
|
|
|
|
:- pred code_info__stack_variable(int, lval, code_info, code_info).
|
|
:- mode code_info__stack_variable(in, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_nondet_saves(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_nondet_saves(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_failure(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_failure(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_under_failure(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_under_failure(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_test_and_fail(rval, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_test_and_fail(in, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_det_pre_commit(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_det_pre_commit(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_det_commit(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_det_commit(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_semi_pre_commit(label, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_semi_pre_commit(out, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_semi_commit(label, code_tree, code_info, code_info).
|
|
:- mode code_info__generate_semi_commit(in, out, in, out) is det.
|
|
|
|
:- pred code_info__save_maxfr(lval, code_tree, code_info, code_info).
|
|
:- mode code_info__save_maxfr(out, out, in, out) is det.
|
|
|
|
:- pred code_info__save_hp(code_tree, code_info, code_info).
|
|
:- mode code_info__save_hp(out, in, out) is det.
|
|
|
|
:- pred code_info__restore_hp(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_hp(out, in, out) is det.
|
|
|
|
:- pred code_info__save_ticket(code_tree, code_info, code_info).
|
|
:- mode code_info__save_ticket(out, in, out) is det.
|
|
|
|
:- pred code_info__restore_ticket(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_ticket(out, in, out) is det.
|
|
|
|
:- pred code_info__restore_ticket_and_pop(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_ticket_and_pop(out, in, out) is det.
|
|
|
|
:- pred code_info__discard_ticket(code_tree, code_info, code_info).
|
|
:- mode code_info__discard_ticket(out, in, out) is det.
|
|
|
|
:- pred code_info__save_redoip(code_tree, code_info, code_info).
|
|
:- mode code_info__save_redoip(out, in, out) is det.
|
|
|
|
:- pred code_info__restore_redoip(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_redoip(out, in, out) is det.
|
|
|
|
:- pred code_info__get_old_hp(code_tree, code_info, code_info).
|
|
:- mode code_info__get_old_hp(out, in, out) is det.
|
|
|
|
:- pred code_info__pop_stack(code_tree, code_info, code_info).
|
|
:- mode code_info__pop_stack(out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_save_hp(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_save_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_restore_hp(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_restore_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_get_old_hp(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_get_old_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_pop_stack(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_pop_stack(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_save_ticket(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_save_ticket(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_restore_ticket(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_restore_ticket(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_restore_ticket_and_pop(bool, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_restore_ticket_and_pop(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_discard_ticket(bool, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_discard_ticket(in, out, in, out) is det.
|
|
|
|
:- pred code_info__get_globals(globals, code_info, code_info).
|
|
:- mode code_info__get_globals(out, in, out) is det.
|
|
|
|
:- pred code_info__set_globals(globals, code_info, code_info).
|
|
:- mode code_info__set_globals(in, in, out) is det.
|
|
|
|
:- pred code_info__push_store_map(map(var, lval), code_info, code_info).
|
|
:- mode code_info__push_store_map(in, in, out) is det.
|
|
|
|
:- pred code_info__pop_store_map(code_info, code_info).
|
|
:- mode code_info__pop_store_map(in, out) is det.
|
|
|
|
:- pred code_info__current_store_map(map(var, lval), code_info, code_info).
|
|
:- mode code_info__current_store_map(out, in, out) is det.
|
|
|
|
:- pred code_info__variable_type(var, type, code_info, code_info).
|
|
:- mode code_info__variable_type(in, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_stack_livevals(set(var), set(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_stack_livevals(in, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_stack_livelvals(set(var), list(liveinfo),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_stack_livelvals(in, out, in, out) is det.
|
|
|
|
:- pred code_info__variable_to_string(var, string, code_info, code_info).
|
|
:- mode code_info__variable_to_string(in, out, in, out) is det.
|
|
|
|
:- pred code_info__apply_instmap_delta(instmap_delta, code_info, code_info).
|
|
:- mode code_info__apply_instmap_delta(in, in, out) is det.
|
|
|
|
:- pred code_info__get_instmap(instmap, code_info, code_info).
|
|
:- mode code_info__get_instmap(out, in, out) is det.
|
|
|
|
:- pred code_info__set_instmap(instmap, code_info, code_info).
|
|
:- mode code_info__set_instmap(in, in, out) is det.
|
|
|
|
:- pred code_info__get_nondet_lives(set(var), code_info, code_info).
|
|
:- mode code_info__get_nondet_lives(out, in, out) is det.
|
|
|
|
:- pred code_info__set_nondet_lives(set(var), code_info, code_info).
|
|
:- mode code_info__set_nondet_lives(in, in, out) is det.
|
|
|
|
:- pred code_info__can_generate_direct_branch(code_addr, code_info, code_info).
|
|
:- mode code_info__can_generate_direct_branch(out, in, out) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds_module, hlds_data.
|
|
:- import_module code_exprn, set, varset, term, stack, prog_io.
|
|
:- import_module type_util, mode_util, options, shapes.
|
|
:- import_module string, require, char, list, map, bimap, tree, int.
|
|
|
|
:- pred code_info__get_label_count(int, code_info, code_info).
|
|
:- mode code_info__get_label_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_label_count(int, code_info, code_info).
|
|
:- mode code_info__set_label_count(in, in, out) is det.
|
|
|
|
:- type junk ---> junk.
|
|
|
|
:- type code_info --->
|
|
code_info(
|
|
int, % The number of stack slots allocated.
|
|
% for storing variables.
|
|
% (Some extra stack slots are used
|
|
% for saving and restoring registers.)
|
|
int, % Counter for the local labels used
|
|
% by this procedure.
|
|
varset, % The variables in this procedure.
|
|
call_info, % The storage allocations for the
|
|
% live variables at the end of the
|
|
% current switch.
|
|
pred_id, % The label of the current predicate.
|
|
proc_id, % The label of the current procedure.
|
|
junk, % JUNK
|
|
% what is stored in each register.
|
|
exprn_info, % A map storing the information about
|
|
% the status of each variable.
|
|
proc_info, % The proc_info for the this procedure.
|
|
bool, % do we need to store succip?
|
|
fall_through, % The failure continuation stack
|
|
module_info, % The module_info structure - you just
|
|
% never know when you might need it.
|
|
% It should be read-only.
|
|
liveness_info, % Variables that are live
|
|
% after this goal
|
|
stack(map(var, lval)),
|
|
% Store Map - where to put things
|
|
code_model, % The model of the current procedure
|
|
instmap, % insts of variables
|
|
pair(int), % The current and maximum (respectively)
|
|
% number of extra temporary stackslots
|
|
% that have been pushed during the
|
|
% procedure
|
|
globals, % code generation options
|
|
stack(pair(lval, lval_or_ticket)),
|
|
% the locations in use on the stack
|
|
shape_table, % Table of shapes.
|
|
set(var), % Variables that are not quite live
|
|
% but are only nondet-live (so that
|
|
% we make sure we save them).
|
|
list(pair(lval, lval_or_ticket))
|
|
% A list of lvalues (ie curfr, maxfr
|
|
% and redoip) that get saved onto the
|
|
% det stack even though the current
|
|
% context is nondet. We need to store
|
|
% these for GC purposes.
|
|
).
|
|
|
|
:- type fall_through == stack(failure_cont).
|
|
|
|
:- type lval_or_ticket ---> ticket ; lval(lval).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__init(Varset, Liveness, CallInfo, SaveSuccip, Globals,
|
|
PredId, ProcId, ProcInfo, CodeModel, Requests,
|
|
_FollowVars, ModuleInfo, Shapes, C) :-
|
|
proc_info_headvars(ProcInfo, HeadVars),
|
|
proc_info_arg_info(ProcInfo, ArgInfos),
|
|
assoc_list__from_corresponding_lists(HeadVars, ArgInfos, Args),
|
|
code_info__build_input_arg_list(Args, ArgList),
|
|
globals__get_options(Globals, Options),
|
|
code_exprn__init_state(ArgList, Varset, Options, ExprnInfo),
|
|
stack__init(Continue),
|
|
stack__init(StoreMapStack0),
|
|
stack__init(PushedVals0),
|
|
map__init(StoreMap),
|
|
set__init(NondetLives),
|
|
stack__push(StoreMapStack0, StoreMap, StoreMapStack),
|
|
code_info__max_slot(CallInfo, SlotCount0),
|
|
(
|
|
CodeModel = model_non
|
|
->
|
|
SlotCount is SlotCount0 + 1
|
|
;
|
|
SlotCount = SlotCount0
|
|
),
|
|
C = code_info(
|
|
SlotCount,
|
|
0,
|
|
Varset,
|
|
CallInfo,
|
|
PredId,
|
|
ProcId,
|
|
junk,
|
|
ExprnInfo,
|
|
ProcInfo,
|
|
SaveSuccip,
|
|
Continue,
|
|
ModuleInfo,
|
|
Liveness,
|
|
StoreMapStack,
|
|
CodeModel,
|
|
Requests,
|
|
0 - 0,
|
|
Globals,
|
|
PushedVals0,
|
|
Shapes,
|
|
NondetLives,
|
|
[]
|
|
).
|
|
|
|
:- pred code_info__build_input_arg_list(assoc_list(var, arg_info),
|
|
assoc_list(var, rval)).
|
|
:- mode code_info__build_input_arg_list(in, out) is det.
|
|
|
|
code_info__build_input_arg_list([], []).
|
|
code_info__build_input_arg_list([V - Arg|Rest0], VarArgs) :-
|
|
Arg = arg_info(Loc, Mode),
|
|
(
|
|
Mode = top_in
|
|
->
|
|
code_util__arg_loc_to_register(Loc, Reg),
|
|
VarArgs = [V - lval(reg(Reg))|VarArgs0]
|
|
;
|
|
VarArgs = VarArgs0
|
|
),
|
|
code_info__build_input_arg_list(Rest0, VarArgs0).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__max_slot(call_info, int).
|
|
:- mode code_info__max_slot(in, out) is det.
|
|
|
|
code_info__max_slot(CallInfo, SlotCount) :-
|
|
map__values(CallInfo, CallList),
|
|
code_info__max_slot_2(CallList, 0, SlotCount).
|
|
|
|
:- pred code_info__max_slot_2(list(lval), int, int).
|
|
:- mode code_info__max_slot_2(in, in, out) is det.
|
|
|
|
code_info__max_slot_2([], Max, Max).
|
|
code_info__max_slot_2([L|Ls], Max0, Max) :-
|
|
(
|
|
L = stackvar(N)
|
|
->
|
|
int__max(N, Max0, Max1)
|
|
;
|
|
L = framevar(N)
|
|
->
|
|
int__max(N, Max0, Max1)
|
|
;
|
|
Max1 = Max0
|
|
),
|
|
code_info__max_slot_2(Ls, Max1, Max).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_next_label(Label) -->
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
code_info__get_next_label_number(N),
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ code_util__make_local_label(ModuleInfo, PredId, ProcId, N, Label) }.
|
|
|
|
code_info__get_next_label_number(N) -->
|
|
code_info__get_label_count(N0),
|
|
{ N is N0 + 1 },
|
|
code_info__set_label_count(N).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__make_entry_label(ModuleInfo, PredId, ProcId, PredAddress) -->
|
|
code_info__get_globals(Globals),
|
|
code_info__get_pred_id(CurPredId),
|
|
code_info__get_proc_id(CurProcId),
|
|
{
|
|
globals__lookup_int_option(Globals, procs_per_c_function, ProcsPerFunc),
|
|
code_info__make_entry_label_2(ModuleInfo, ProcsPerFunc, PredId,
|
|
ProcId, CurPredId, CurProcId, PredAddress)
|
|
}.
|
|
|
|
code_info__make_entry_label_2(ModuleInfo, ProcsPerFunc, PredId, ProcId,
|
|
CurPredId, CurProcId, PredAddress) :-
|
|
module_info_preds(ModuleInfo, Preds),
|
|
map__lookup(Preds, PredId, PredInfo),
|
|
(
|
|
( pred_info_is_imported(PredInfo)
|
|
; pred_info_is_pseudo_imported(PredInfo),
|
|
% only the (in, in) mode of unification is imported
|
|
ProcId = 0
|
|
; ProcsPerFunc \= 0,
|
|
\+ (PredId = CurPredId, ProcId = CurProcId)
|
|
)
|
|
->
|
|
code_util__make_proc_label(ModuleInfo,
|
|
PredId, ProcId, ProcLabel),
|
|
PredAddress = imported(ProcLabel)
|
|
;
|
|
code_util__make_local_entry_label(ModuleInfo,
|
|
PredId, ProcId, Label),
|
|
PredAddress = label(Label)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% XXX We could use the sanity checking mechanism...
|
|
code_info__clear_all_registers -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__clobber_regs([], Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__get_variable_slot(var, lval, code_info, code_info).
|
|
:- mode code_info__get_variable_slot(in, out, in, out) is det.
|
|
|
|
code_info__get_variable_slot(Var, Slot) -->
|
|
code_info__get_call_info(CallInfo),
|
|
{ map__lookup(CallInfo, Var, Slot) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Given a constructor id, and a variable (so that we can work out the
|
|
% type of the constructor), determine correct tag (representation)
|
|
% of that constructor.
|
|
|
|
:- code_info__cons_id_to_tag(_, X, _, _, _) when X. % NU-Prolog indexing.
|
|
|
|
code_info__cons_id_to_tag(_Var, int_const(X), int_constant(X)) --> [].
|
|
code_info__cons_id_to_tag(_Var, float_const(X), float_constant(X)) --> [].
|
|
code_info__cons_id_to_tag(_Var, string_const(X), string_constant(X)) --> [].
|
|
code_info__cons_id_to_tag(_Var, address_const(P,M), address_constant(P,M))
|
|
--> [].
|
|
code_info__cons_id_to_tag(_Var, pred_const(P,M), pred_closure_tag(P,M)) --> [].
|
|
code_info__cons_id_to_tag(Var, cons(Name, Arity), Tag) -->
|
|
%
|
|
% Lookup the type of the variable
|
|
%
|
|
code_info__variable_type(Var, Type),
|
|
(
|
|
% handle the `character' type specially
|
|
{ Type = term__functor(term__atom("character"), [], _) },
|
|
{ string__char_to_string(Char, Name) }
|
|
->
|
|
{ char__to_int(Char, CharCode) },
|
|
{ Tag = int_constant(CharCode) }
|
|
;
|
|
% handle higher-order pred types specially
|
|
{ type_is_higher_order(Type, _PredOrFunc, PredArgTypes) }
|
|
->
|
|
{ list__length(PredArgTypes, PredArity) },
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ module_info_get_predicate_table(ModuleInfo, PredicateTable) },
|
|
{ TotalArity is Arity + PredArity },
|
|
{
|
|
predicate_table_search_name_arity(PredicateTable,
|
|
Name, TotalArity, PredIds)
|
|
->
|
|
(
|
|
PredIds = [PredId]
|
|
->
|
|
predicate_table_get_preds(PredicateTable, Preds),
|
|
map__lookup(Preds, PredId, PredInfo),
|
|
pred_info_procedures(PredInfo, Procs),
|
|
map__keys(Procs, ProcIds),
|
|
(
|
|
ProcIds = [ProcId]
|
|
->
|
|
Tag = pred_closure_tag(PredId, ProcId)
|
|
;
|
|
error("sorry, not implemented: taking address of predicate with multiple modes")
|
|
)
|
|
;
|
|
% cons_id ought to include the module prefix, so
|
|
% that we could use predicate_table__search_m_n_a to
|
|
% prevent this from happening
|
|
string__append("code_info__cons_id_to_tag: ambiguous pred ", Name, Msg),
|
|
error(Msg)
|
|
)
|
|
;
|
|
% the type-checker should ensure that this never happens
|
|
error("code_info__cons_id_to_tag: invalid pred")
|
|
}
|
|
;
|
|
% Use the type to determine the type_id
|
|
{ type_to_type_id(Type, TypeId0, _) ->
|
|
TypeId = TypeId0
|
|
;
|
|
% the type-checker should ensure that this never happens
|
|
error("code_info__cons_id_to_tag: invalid type")
|
|
},
|
|
|
|
% Given the type_id, lookup up the constructor tag
|
|
% table for that type
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ module_info_types(ModuleInfo, TypeTable) },
|
|
{ map__lookup(TypeTable, TypeId, TypeDefn) },
|
|
{
|
|
TypeDefn = hlds__type_defn(_, _,
|
|
du_type(_, ConsTable0, _), _, _)
|
|
->
|
|
ConsTable = ConsTable0
|
|
;
|
|
% this should never happen
|
|
error(
|
|
"code_info__cons_id_to_tag: type is not d.u. type?"
|
|
)
|
|
},
|
|
% Finally look up the cons_id in the table
|
|
{ map__lookup(ConsTable, cons(Name, Arity), Tag) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_live_variables(VarList) -->
|
|
code_info__get_liveness_info(NormalLiveVars),
|
|
code_info__get_nondet_lives(NondetLiveVars),
|
|
{ set__union(NormalLiveVars, NondetLiveVars, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__variable_is_live(Var) -->
|
|
code_info__get_liveness_info(Liveness),
|
|
code_info__get_nondet_lives(Nondets),
|
|
(
|
|
{ set__member(Var, Liveness) }
|
|
;
|
|
{ set__member(Var, Nondets) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_pred_proc_arginfo(PredId, ProcId, ArgInfo) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ module_info_preds(ModuleInfo, Preds) },
|
|
{ map__lookup(Preds, PredId, PredInfo) },
|
|
{ pred_info_procedures(PredInfo, Procs) },
|
|
{ map__lookup(Procs, ProcId, ProcInfo) },
|
|
{ proc_info_arg_info(ProcInfo, ArgInfo) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__set_var_location(Var, Lval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__set_var_location(Var, Lval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__produce_variable(Var, Code, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__produce_var(Var, Rval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__produce_variable_in_reg(Var, Code, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__produce_var_in_reg(Var, Rval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__place_var(Var, Lval, Code) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(Var, Lval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__place_vars(assoc_list(var, set(rval)), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__place_vars(in, out, in, out) is det.
|
|
|
|
code_info__place_vars([], empty) --> [].
|
|
code_info__place_vars([V-Rs|RestList], Code) -->
|
|
(
|
|
{ set__to_sorted_list(Rs, RList) },
|
|
{ code_info__lval_member(L, RList) }
|
|
->
|
|
code_info__place_var(V, L, ThisCode)
|
|
;
|
|
{ ThisCode = empty }
|
|
),
|
|
code_info__place_vars(RestList, RestCode),
|
|
{ Code = tree(ThisCode, RestCode) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__lock_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__lock_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__unlock_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__unlock_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__acquire_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__acquire_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__release_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__release_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__cache_expression(Var, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__cache_exprn(Var, Rval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__setup_call([], _Direction, empty) --> [].
|
|
code_info__setup_call([V - arg_info(Loc,Mode)|Rest], Direction, Code) -->
|
|
(
|
|
{
|
|
Mode = top_in,
|
|
Direction = caller
|
|
;
|
|
Mode = top_out,
|
|
Direction = callee
|
|
}
|
|
->
|
|
{ code_util__arg_loc_to_register(Loc, Reg) },
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(V, reg(Reg), Code0, Exprn0, Exprn1) },
|
|
% We need to test that either the variable
|
|
% is live OR it occurs in the remaining arguments
|
|
% because of a bug in polymorphism.m which
|
|
% causes some compiler generated code to violate
|
|
% superhomogeneous form
|
|
(
|
|
code_info__variable_is_live(V)
|
|
->
|
|
{ IsLive = yes }
|
|
;
|
|
{ IsLive = no }
|
|
),
|
|
{
|
|
list__member(Vtmp - _, Rest),
|
|
V = Vtmp
|
|
->
|
|
Occurs = yes
|
|
;
|
|
Occurs = no
|
|
},
|
|
(
|
|
% We can't simply use a disj here
|
|
% because of bugs in modes/det_analysis
|
|
{ bool__or(Occurs, IsLive, yes) }
|
|
->
|
|
{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
|
|
code_info__set_exprn_info(Exprn2),
|
|
code_info__setup_call(Rest, Direction, Code1),
|
|
code_info__get_exprn_info(Exprn3),
|
|
{ code_exprn__unlock_reg(Reg, Exprn3, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
{ Code = tree(Code0, Code1) }
|
|
;
|
|
{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
|
|
{ code_exprn__var_becomes_dead(V, Exprn2, Exprn3) },
|
|
code_info__set_exprn_info(Exprn3),
|
|
code_info__setup_call(Rest, Direction, Code1),
|
|
code_info__get_exprn_info(Exprn4),
|
|
{ code_exprn__unlock_reg(Reg, Exprn4, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
{ Code = tree(Code0, Code1) }
|
|
)
|
|
;
|
|
code_info__setup_call(Rest, Direction, Code)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__save_variable_on_stack(Var, Code) -->
|
|
code_info__get_variable_slot(Var, Slot),
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(Var, Slot, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_arginfo(ArgInfo) -->
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
code_info__get_pred_proc_arginfo(PredId, ProcId, ArgInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_forced_saves(Code) -->
|
|
code_info__current_store_map(StoreMap),
|
|
code_info__get_call_info(CallInfo),
|
|
code_info__get_live_variables(Vars),
|
|
code_info__generate_forced_saves_2(Vars, StoreMap, CallInfo, Code).
|
|
|
|
:- pred code_info__generate_forced_saves_2(list(var), map(var, lval),
|
|
map(var, lval), code_tree, code_info, code_info).
|
|
:- mode code_info__generate_forced_saves_2(in, in, in, out, in, out) is det.
|
|
|
|
code_info__generate_forced_saves_2([], _Store, _Call, empty) --> [].
|
|
code_info__generate_forced_saves_2([V|Vs], Store, Call, Code) -->
|
|
(
|
|
{ map__search(Store, V, Lval) }
|
|
->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(V, Lval, Code0, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn)
|
|
;
|
|
{ map__search(Call, V, Lval) }
|
|
->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(V, Lval, Code0, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn)
|
|
;
|
|
{ error("code_info__generate_forced_saves: variable not found") }
|
|
),
|
|
code_info__generate_forced_saves_2(Vs, Store, Call, Code1),
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_nondet_saves(Code) -->
|
|
code_info__get_call_info(CallInfo),
|
|
{ map__to_assoc_list(CallInfo, CallList) },
|
|
code_info__generate_nondet_saves_2(CallList, Code).
|
|
|
|
:- pred code_info__generate_nondet_saves_2(assoc_list(var, lval), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_nondet_saves_2(in, out, in, out) is det.
|
|
|
|
code_info__generate_nondet_saves_2([], empty) --> [].
|
|
code_info__generate_nondet_saves_2([Var - StackThing|VarSlots], Code) -->
|
|
(
|
|
code_info__variable_is_live(Var)
|
|
->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(Var, StackThing, Code0,
|
|
Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn)
|
|
;
|
|
{ Code0 = empty }
|
|
),
|
|
{ Code = tree(Code0, Code1) },
|
|
code_info__generate_nondet_saves_2(VarSlots, Code1).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_headvars(HeadVars) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
{ module_info_preds(ModuleInfo, Preds) },
|
|
{ map__lookup(Preds, PredId, PredInfo) },
|
|
{ pred_info_procedures(PredInfo, Procs) },
|
|
{ map__lookup(Procs, ProcId, ProcInfo) },
|
|
{ proc_info_headvars(ProcInfo, HeadVars) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% code_info__remake_with_store_map rebuilds the register info and
|
|
% variable info data structures. It operates under the assumption
|
|
% that if a variable is live, it is stored somewhere. What is more,
|
|
% it assumes that if a variable is live, then there is a copy of it
|
|
% stored on the stack in the location given by the store map. This
|
|
% means that it only makes sense to call this predicate in situations
|
|
% such as the start of disjuncts where it only makes sense to have
|
|
% variables on the stack. (Note that disj_gen contains a piece of
|
|
% magic to use the register versions of variables if possible in the
|
|
% first disjunct).
|
|
|
|
code_info__remake_with_store_map -->
|
|
code_info__get_varset(Varset),
|
|
code_info__get_live_variables(VarList),
|
|
{ set__list_to_set(VarList, Vars) },
|
|
code_info__get_call_info(CallInfo),
|
|
code_info__current_store_map(StoreMap),
|
|
{ map__overlay(CallInfo, StoreMap, LvalMap0) },
|
|
{ map__select(LvalMap0, Vars, LvalMap) },
|
|
{ map__to_assoc_list(LvalMap, VarLvals0) },
|
|
{ code_info__fixup_lvallist(VarLvals0, VarLvals) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ code_exprn__init_state(VarLvals, Varset, Options, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% code_info__remake_with_call_info rebuilds the register info and the
|
|
% variable info structures. It operates under the assumption that if
|
|
% a variable is live, then it should be located in the storage indicated
|
|
% by the call info information. This is for use at the end of the branches
|
|
% in branched structures, where we need to ensure that variables are
|
|
% stored in consistient places.
|
|
|
|
code_info__remake_with_call_info -->
|
|
code_info__get_varset(Varset),
|
|
code_info__get_live_variables(VarList),
|
|
{ set__list_to_set(VarList, Vars) },
|
|
code_info__get_call_info(CallInfo),
|
|
{ map__select(CallInfo, Vars, LvalMap) },
|
|
{ map__to_assoc_list(LvalMap, VarLvals0) },
|
|
{ code_info__fixup_lvallist(VarLvals0, VarLvals) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ code_exprn__init_state(VarLvals, Varset, Options, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__fixup_lvallist(assoc_list(var, lval), assoc_list(var, rval)).
|
|
:- mode code_info__fixup_lvallist(in, out) is det.
|
|
|
|
code_info__fixup_lvallist([], []).
|
|
code_info__fixup_lvallist([V - L|Ls], [V - lval(L)|Rs]) :-
|
|
code_info__fixup_lvallist(Ls, Rs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__update_liveness_info(Births - _Deaths) -->
|
|
code_info__get_liveness_info(Liveness0),
|
|
{ set__union(Liveness0, Births, Liveness) },
|
|
code_info__set_liveness_info(Liveness).
|
|
|
|
code_info__update_deadness_info(_Births - Deaths) -->
|
|
code_info__get_liveness_info(Liveness0),
|
|
{ set__difference(Liveness0, Deaths, Liveness) },
|
|
code_info__set_liveness_info(Liveness).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__make_vars_dead(Vars0) -->
|
|
code_info__get_nondet_lives(NondetLives),
|
|
% Don't kill off nondet-live variables
|
|
{ set__difference(Vars0, NondetLives, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
code_info__make_vars_dead_2(VarList).
|
|
|
|
:- pred code_info__make_vars_dead_2(list(var), code_info, code_info).
|
|
:- mode code_info__make_vars_dead_2(in, in, out) is det.
|
|
|
|
code_info__make_vars_dead_2([]) --> [].
|
|
code_info__make_vars_dead_2([V|Vs]) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__var_becomes_dead(V, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
code_info__make_vars_dead_2(Vs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__make_vars_live(Vars) -->
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
code_info__make_vars_live_2(VarList).
|
|
|
|
:- pred code_info__make_vars_live_2(list(var), code_info, code_info).
|
|
:- mode code_info__make_vars_live_2(in, in, out) is det.
|
|
|
|
code_info__make_vars_live_2([]) --> [].
|
|
code_info__make_vars_live_2([V|Vs]) -->
|
|
(
|
|
code_info__current_store_map(Store),
|
|
{ map__search(Store, V, Lval0) }
|
|
->
|
|
{ Lval = Lval0 }
|
|
;
|
|
code_info__get_call_info(Call),
|
|
{ map__search(Call, V, Lval0) }
|
|
->
|
|
{ Lval = Lval0 }
|
|
;
|
|
code_info__get_varset(Varset),
|
|
{ varset__lookup_name(Varset, V, Name) },
|
|
{ string__append("I don't know where to put variable ",
|
|
Name, Msg) },
|
|
{ error(Msg) }
|
|
),
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__maybe_set_var_location(V, Lval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
code_info__make_vars_live_2(Vs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__maybe_save_hp(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__save_hp(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_restore_hp(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__restore_hp(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_get_old_hp(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__get_old_hp(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_pop_stack(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__pop_stack(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_save_ticket(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__save_ticket(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_restore_ticket(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__restore_ticket(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_restore_ticket_and_pop(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__restore_ticket_and_pop(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_discard_ticket(Maybe, Code) -->
|
|
( { Maybe = yes } ->
|
|
code_info__discard_ticket(Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__save_hp(Code) -->
|
|
code_info__push_temp(lval(hp), HpSlot),
|
|
{ Code = node([ mark_hp(HpSlot) - "Save heap pointer" ]) }.
|
|
|
|
code_info__restore_hp(Code) -->
|
|
code_info__pop_temp(Lval),
|
|
{ Code = node([ restore_hp(lval(Lval)) - "Restore heap pointer" ]) }.
|
|
|
|
code_info__get_old_hp(Code) -->
|
|
code_info__get_stack_top(Lval),
|
|
{ Code = node([ restore_hp(lval(Lval)) - "Reset heap pointer" ]) }.
|
|
|
|
code_info__save_ticket(Code) -->
|
|
code_info__push_temp(ticket, Lval),
|
|
{ Code = node([ store_ticket(Lval) - "Save ticket" ]) }.
|
|
|
|
code_info__restore_ticket(Code) -->
|
|
code_info__get_stack_top(Lval),
|
|
{ Code = node([ restore_ticket(lval(Lval)) - "Restore ticket" ]) }.
|
|
|
|
code_info__restore_ticket_and_pop(Code) -->
|
|
code_info__pop_temp(Lval),
|
|
{ Code = tree(
|
|
node([ restore_ticket(lval(Lval)) - "Restore ticket" ]),
|
|
node([ discard_ticket - "Restore ticket" ]) )
|
|
}.
|
|
|
|
code_info__discard_ticket(Code) -->
|
|
code_info__pop_temp(_),
|
|
{ Code = node([ discard_ticket - "Restore ticket" ]) }.
|
|
|
|
code_info__save_redoip(Code) -->
|
|
code_info__push_temp(lval(redoip(lval(maxfr))), RedoIpSlot),
|
|
{ Code = node([ assign(RedoIpSlot, lval(redoip(lval(maxfr))))
|
|
- "Save the redoip" ]) }.
|
|
|
|
code_info__save_maxfr(MaxfrSlot, Code) -->
|
|
code_info__push_temp(lval(maxfr), MaxfrSlot),
|
|
{ Code = node([ assign(MaxfrSlot, lval(maxfr))
|
|
- "Save maxfr" ]) }.
|
|
|
|
code_info__restore_redoip(Code) -->
|
|
code_info__pop_temp(Lval),
|
|
{ Code = node([ assign(redoip(lval(maxfr)), lval(Lval))
|
|
- "Restore the redoip" ]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__stack_variable(Num, Lval) -->
|
|
code_info__get_proc_model(CodeModel),
|
|
(
|
|
{ CodeModel = model_non }
|
|
->
|
|
{ Num1 is Num - 1 }, % framevars start at zero
|
|
{ Lval = framevar(Num1) }
|
|
;
|
|
{ Lval = stackvar(Num) } % stackvars start at one
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The det stack frame is organized as follows.
|
|
%
|
|
% ... unused ...
|
|
% sp ---> <first unused slot>
|
|
% <space for local var 1>
|
|
% ... local vars ...
|
|
% <space for local var n>
|
|
% <space for temporary reg save 1>
|
|
% ... temporary reg saves ...
|
|
% <space for temporary reg save n>
|
|
% <space for succip>
|
|
%
|
|
% The stack pointer points to the first free location at the
|
|
% top of the stack.
|
|
%
|
|
% `code_info__num_stackslots' counts the number of slots reserved
|
|
% for saving local variables.
|
|
%
|
|
% `code_info__max_push_count' counts the number of slots reserved
|
|
% for saving and restoring registers (hp, redoip, etc.)
|
|
%
|
|
% `code_info__succip_used' determines whether we need a slot to
|
|
% hold the succip.
|
|
%
|
|
% The variable part of the nondet stack is organized in the same way
|
|
% as the det stack (but the nondet stack also contains several other
|
|
% fixed fields.)
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Returns the total stackslot count, but not including space for
|
|
% succip.
|
|
code_info__get_total_stackslot_count(NumSlots) -->
|
|
code_info__get_stackslot_count(SlotsForVars),
|
|
code_info__get_max_push_count(SlotsForTemps),
|
|
{ NumSlots is SlotsForVars + SlotsForTemps }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% `push_temp' doesn't actually increment the stack pointer, it just
|
|
% increments the push count. The space will be allocated in the
|
|
% procedure prologue.
|
|
|
|
:- pred code_info__push_temp(lval_or_ticket, lval, code_info, code_info).
|
|
:- mode code_info__push_temp(in, out, in, out) is det.
|
|
|
|
code_info__push_temp(Item, StackVar) -->
|
|
code_info__get_push_count(Count0),
|
|
{ Count is Count0 + 1 },
|
|
code_info__set_push_count(Count),
|
|
code_info__get_stackslot_count(NumSlots),
|
|
{ Slot is Count + NumSlots },
|
|
code_info__stack_variable(Slot, StackVar),
|
|
code_info__get_pushed_values(VStack0),
|
|
{ stack__push(VStack0, StackVar - Item, VStack) },
|
|
code_info__set_pushed_values(VStack).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__add_commit_val(lval, lval, code_info, code_info).
|
|
:- mode code_info__add_commit_val(in, in, in, out) is det.
|
|
|
|
code_info__add_commit_val(Item, StackVar) -->
|
|
code_info__get_commit_vals(Stack0),
|
|
code_info__set_commit_vals([StackVar - lval(Item) | Stack0]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__rem_commit_val(code_info, code_info).
|
|
:- mode code_info__rem_commit_val(in, out) is det.
|
|
|
|
code_info__rem_commit_val -->
|
|
code_info__get_commit_vals(Stack0),
|
|
(
|
|
{ Stack0 = [_ | Stack] },
|
|
code_info__set_commit_vals(Stack)
|
|
;
|
|
{ Stack0 = [] },
|
|
{ error("code_info__rem_commit_val: Empty list") }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% `pop_stack' and `pop_temp' don't actually decrement the stack
|
|
% pointer, they just decrement the push count. The space will
|
|
% be deallocated in the procedure epilogue.
|
|
|
|
code_info__pop_stack(empty) -->
|
|
code_info__get_push_count(Count0),
|
|
{ Count is Count0 - 1 },
|
|
code_info__set_push_count(Count),
|
|
code_info__get_pushed_values(VStack0),
|
|
{ stack__pop_det(VStack0, _, VStack) },
|
|
code_info__set_pushed_values(VStack).
|
|
|
|
:- pred code_info__pop_temp(lval, code_info, code_info).
|
|
:- mode code_info__pop_temp(out, in, out) is det.
|
|
|
|
code_info__pop_temp(StackVar) -->
|
|
code_info__get_push_count(Count0),
|
|
{ Count is Count0 - 1 },
|
|
code_info__set_push_count(Count),
|
|
code_info__get_pushed_values(VStack0),
|
|
{ stack__pop_det(VStack0, _, VStack) },
|
|
code_info__set_pushed_values(VStack),
|
|
code_info__get_stackslot_count(NumSlots),
|
|
{ Slot is Count0 + NumSlots },
|
|
code_info__stack_variable(Slot, StackVar).
|
|
|
|
:- pred code_info__get_stack_top(lval, code_info, code_info).
|
|
:- mode code_info__get_stack_top(out, in, out) is det.
|
|
|
|
code_info__get_stack_top(StackVar) -->
|
|
code_info__get_push_count(Count),
|
|
code_info__get_stackslot_count(NumSlots),
|
|
{ Slot is Count + NumSlots },
|
|
code_info__stack_variable(Slot, StackVar).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_failure(Code) -->
|
|
code_info__grab_code_info(CodeInfo),
|
|
code_info__failure_cont(failure_cont(Cont, _MaybeRedoLab, FailureMap)),
|
|
(
|
|
{ Cont = known(_) },
|
|
(
|
|
code_info__pick_failure(FailureMap, FailureAddress0)
|
|
->
|
|
{ FailureAddress = FailureAddress0 },
|
|
{ PlaceCode = empty }
|
|
;
|
|
{ FailureMap = [Map - Addr|_] }
|
|
->
|
|
{ FailureAddress = Addr },
|
|
{ map__to_assoc_list(Map, AssocList) },
|
|
code_info__place_vars(AssocList, PlaceCode)
|
|
;
|
|
{error("code_info__generate_failure: no valid failmap")}
|
|
),
|
|
{ BranchCode = node([goto(FailureAddress) - "fail"]) },
|
|
{ Code = tree(PlaceCode, BranchCode) }
|
|
;
|
|
{ Cont = unknown },
|
|
{ Code = node([goto(do_redo) - "fail"]) }
|
|
),
|
|
code_info__slap_code_info(CodeInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_under_failure(Code) -->
|
|
code_info__grab_code_info(CodeInfo),
|
|
code_info__pop_failure_cont,
|
|
code_info__generate_failure(Code),
|
|
code_info__slap_code_info(CodeInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_test_and_fail(Rval0, Code) -->
|
|
code_info__failure_cont(failure_cont(Cont, _MaybeRedoLab, FailureMap)),
|
|
(
|
|
{ Cont = known(_) },
|
|
(
|
|
code_info__pick_failure(FailureMap, FailureAddress0)
|
|
->
|
|
% We branch away if the test *fails*
|
|
{ code_util__neg_rval(Rval0, Rval) },
|
|
{ Code = node([ if_val(Rval, FailureAddress0) -
|
|
"Test for failure" ]) }
|
|
;
|
|
{ FailureMap = [Map - Addr|_] }
|
|
->
|
|
{ FailureAddress = Addr },
|
|
{ map__to_assoc_list(Map, AssocList) },
|
|
code_info__get_next_label(SuccessLabel),
|
|
code_info__grab_code_info(CodeInfo),
|
|
code_info__place_vars(AssocList, PlaceCode),
|
|
code_info__slap_code_info(CodeInfo),
|
|
{ SuccessAddress = label(SuccessLabel) },
|
|
% We branch away if the test Succeeds
|
|
{ TestCode = node([ if_val(Rval0, SuccessAddress) -
|
|
"Test for failure" ]) },
|
|
{ FailCode = tree(PlaceCode, node([
|
|
goto(FailureAddress) - ""
|
|
])) },
|
|
{ Code = tree(tree(TestCode, FailCode), node([
|
|
label(SuccessLabel) - "success continuation"
|
|
])) }
|
|
;
|
|
{ error("code_info__generate_test_and_fail: no valid failmap") }
|
|
)
|
|
;
|
|
{ Cont = unknown },
|
|
{ FailureAddress = do_redo },
|
|
% We branch away if the test *fails*
|
|
{ code_util__neg_rval(Rval0, Rval) },
|
|
{ Code = node([ if_val(Rval, FailureAddress) -
|
|
"Test for failure" ]) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__can_generate_direct_branch(CodeAddr) -->
|
|
code_info__failure_cont(failure_cont(known(no), no, FailureMap)),
|
|
code_info__pick_failure(FailureMap, CodeAddr).
|
|
% { FailureMap = [Map - CodeAddr|_] },
|
|
% { map__is_empty(Map) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__pick_failure(assoc_list(map(var, set(rval)), code_addr),
|
|
code_addr, code_info, code_info).
|
|
:- mode code_info__pick_failure(in, out, in, out) is semidet.
|
|
|
|
code_info__pick_failure([], _CodeAddr) -->
|
|
{ fail }.
|
|
code_info__pick_failure([Map - Addr | Rest], CodeAddr) -->
|
|
{ map__keys(Map, KeyList) },
|
|
{ set__list_to_set(KeyList, Keys) },
|
|
code_info__variable_locations(Locations0),
|
|
{ map__select(Locations0, Keys, Locations) },
|
|
{ map__to_assoc_list(Locations, List) },
|
|
(
|
|
\+ (
|
|
{ list__member(Thingy, List) },
|
|
\+ (
|
|
{ Thingy = Var - Actual },
|
|
{ map__search(Map, Var, Rvals) },
|
|
{ set__subset(Rvals, Actual) }
|
|
)
|
|
)
|
|
->
|
|
{ CodeAddr = Addr }
|
|
;
|
|
code_info__pick_failure(Rest, CodeAddr)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__variable_locations(map(var, set(rval)),
|
|
code_info, code_info).
|
|
:- mode code_info__variable_locations(out, in, out) is det.
|
|
|
|
code_info__variable_locations(Locations) -->
|
|
code_info__get_exprn_info(Exprn),
|
|
{ code_exprn__get_varlocs(Exprn, Locations) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% `semi_pre_commit' and `semi_commit' should be generated as a pair
|
|
% surrounding a nondet goal.
|
|
% `generate_semi_pre_commit' returns a label (a failure cont label)
|
|
% which should be passed to `generate_semi_commit'.
|
|
% If the goal succeeds, the `commit' will cut any choice points
|
|
% generated in the goal.
|
|
|
|
code_info__generate_semi_pre_commit(RedoLab, PreCommit) -->
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
% the pushes and pops on the det stack below will cause
|
|
% problems for accurate garbage collection. Hence we
|
|
% make sure the commit vals are made live, so gc
|
|
% can figure out what is going on later.
|
|
{ PushCode = node([
|
|
incr_sp(3) -
|
|
"push space for curfr, maxfr, and redoip"
|
|
]) },
|
|
{ CurfrSlot = stackvar(1) },
|
|
{ MaxfrSlot = stackvar(2) },
|
|
{ RedoipSlot = stackvar(3) },
|
|
code_info__add_commit_val(curfr, CurfrSlot),
|
|
code_info__add_commit_val(maxfr, MaxfrSlot),
|
|
code_info__add_commit_val(redoip(lval(maxfr)), RedoipSlot)
|
|
;
|
|
{ PushCode = empty },
|
|
code_info__push_temp(lval(curfr), CurfrSlot),
|
|
code_info__push_temp(lval(maxfr), MaxfrSlot),
|
|
code_info__push_temp(lval(redoip(lval(maxfr))), RedoipSlot)
|
|
),
|
|
{ SaveCode = node([
|
|
assign(CurfrSlot, lval(curfr)) -
|
|
"Save current nondet frame pointer",
|
|
assign(MaxfrSlot, lval(maxfr)) -
|
|
"Save top of nondet stack",
|
|
assign(RedoipSlot, lval(redoip(lval(maxfr)))) -
|
|
"Save the top redoip"
|
|
]) },
|
|
code_info__failure_cont(failure_cont(_OrigCont, _MaybeRedo,
|
|
FailureMap0)),
|
|
code_info__relabel_failure_cont(FailureMap0, FailureMap),
|
|
code_info__push_failure_cont(failure_cont(known(yes), no, FailureMap)),
|
|
code_info__get_next_label(RedoLab),
|
|
{ HijackCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(address_const(label(RedoLab)))) -
|
|
"Hijack the failure cont"
|
|
]) },
|
|
{ PreCommit = tree(tree(PushCode, SaveCode), HijackCode) }.
|
|
|
|
code_info__generate_semi_commit(RedoLab, Commit) -->
|
|
code_info__get_next_label(SuccLabel),
|
|
{ GotoSuccLabel = node([
|
|
goto(label(SuccLabel)) - "Jump to success continuation"
|
|
]) },
|
|
{ SuccLabelCode = node([
|
|
label(SuccLabel) - "Success continuation"
|
|
]) },
|
|
{ RedoLabCode = node([
|
|
label(RedoLab) - "Failure (redo) continuation"
|
|
]) },
|
|
code_info__grab_code_info(CodeInfo0),
|
|
code_info__failure_cont(failure_cont(_OldCont, _MaybeRedo,
|
|
HFailureMap)),
|
|
code_info__generate_failure_continuation(HFailureMap, FailureContCode),
|
|
code_info__generate_under_failure(Fail),
|
|
code_info__slap_code_info(CodeInfo0),
|
|
code_info__pop_failure_cont,
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
{ PopCode = node([decr_sp(3) -
|
|
"pop redoip, maxfr & curfr"]) },
|
|
{ RedoipSlot = stackvar(3) },
|
|
{ MaxfrSlot = stackvar(2) },
|
|
{ CurfrSlot = stackvar(1) },
|
|
code_info__rem_commit_val,
|
|
code_info__rem_commit_val,
|
|
code_info__rem_commit_val
|
|
;
|
|
{ PopCode = empty },
|
|
code_info__pop_temp(RedoipSlot),
|
|
code_info__pop_temp(MaxfrSlot),
|
|
code_info__pop_temp(CurfrSlot)
|
|
),
|
|
{ RestoreMaxfr = node([
|
|
assign(maxfr, lval(MaxfrSlot)) -
|
|
"Prune away unwanted choice-points"
|
|
]) },
|
|
{ RestoreRedoip = node([
|
|
assign(redoip(lval(maxfr)), lval(RedoipSlot)) -
|
|
"Restore the top redoip"
|
|
]) },
|
|
{ RestoreCurfr = node([
|
|
assign(curfr, lval(CurfrSlot)) -
|
|
"Restore nondet frame pointer"
|
|
]) },
|
|
{ SuccessCode = tree(
|
|
RestoreMaxfr,
|
|
tree(tree(RestoreRedoip, RestoreCurfr), PopCode)
|
|
) },
|
|
{ FailCode = tree(
|
|
tree(tree(RedoLabCode, RestoreCurfr), FailureContCode),
|
|
tree(tree(RestoreRedoip, PopCode), Fail)
|
|
) },
|
|
{ Commit = tree(tree(SuccessCode, tree(GotoSuccLabel, FailCode)),
|
|
SuccLabelCode) }.
|
|
|
|
% `det_pre_commit' and `det_commit' should be generated as a pair
|
|
% surrounding a multidet goal.
|
|
% After the goal succeeds, the `commit' will cut any choice points
|
|
% generated in the goal.
|
|
|
|
code_info__generate_det_pre_commit(PreCommit) -->
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
% the pushes and pops on the det stack below will cause
|
|
% problems for accurate garbage collection. Hence we
|
|
% make sure the commit vals are made live, so gc
|
|
% can figure out what is going on later.
|
|
{ PushCode = node([
|
|
incr_sp(3) -
|
|
"push space for curfr, maxfr, and redoip"
|
|
]) },
|
|
{ CurfrSlot = stackvar(1) },
|
|
{ MaxfrSlot = stackvar(2) },
|
|
{ RedoipSlot = stackvar(3) },
|
|
code_info__add_commit_val(curfr, CurfrSlot),
|
|
code_info__add_commit_val(maxfr, MaxfrSlot),
|
|
code_info__add_commit_val(redoip(lval(maxfr)), RedoipSlot)
|
|
;
|
|
{ PushCode = empty },
|
|
code_info__push_temp(lval(curfr), CurfrSlot),
|
|
code_info__push_temp(lval(maxfr), MaxfrSlot),
|
|
code_info__push_temp(lval(redoip(lval(maxfr))), RedoipSlot)
|
|
),
|
|
{ SaveCode = node([
|
|
assign(CurfrSlot, lval(curfr)) -
|
|
"Save current nondet frame pointer",
|
|
assign(MaxfrSlot, lval(maxfr)) -
|
|
"Save top of nondet stack",
|
|
assign(RedoipSlot, lval(redoip(lval(maxfr)))) -
|
|
"Save the top redoip"
|
|
]) },
|
|
{ PreCommit = tree(PushCode, SaveCode) }.
|
|
|
|
code_info__generate_det_commit(Commit) -->
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
{ PopCode = node([decr_sp(3) -
|
|
"pop redoip, maxfr & curfr"]) },
|
|
{ RedoipSlot = stackvar(3) },
|
|
{ MaxfrSlot = stackvar(2) },
|
|
{ CurfrSlot = stackvar(1) },
|
|
code_info__rem_commit_val,
|
|
code_info__rem_commit_val,
|
|
code_info__rem_commit_val
|
|
;
|
|
{ PopCode = empty },
|
|
code_info__pop_temp(RedoipSlot),
|
|
code_info__pop_temp(MaxfrSlot),
|
|
code_info__pop_temp(CurfrSlot)
|
|
),
|
|
{ RestoreMaxfr = node([
|
|
assign(maxfr, lval(MaxfrSlot)) -
|
|
"Prune away unwanted choice-points"
|
|
]) },
|
|
{ RestoreRedoip = node([
|
|
assign(redoip(lval(maxfr)), lval(RedoipSlot)) -
|
|
"Restore the top redoip"
|
|
]) },
|
|
{ RestoreCurfr = node([
|
|
assign(curfr, lval(CurfrSlot)) -
|
|
"Restore nondet frame pointer"
|
|
]) },
|
|
{ Commit = tree( RestoreMaxfr,
|
|
tree(tree(RestoreRedoip, RestoreCurfr), PopCode)
|
|
) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__push_failure_cont(failure_cont, code_info, code_info).
|
|
:- mode code_info__push_failure_cont(in, in, out) is det.
|
|
|
|
code_info__push_failure_cont(Cont) -->
|
|
code_info__get_fall_through(Fall0),
|
|
{ stack__push(Fall0, Cont, Fall) },
|
|
code_info__set_fall_through(Fall).
|
|
|
|
code_info__pop_failure_cont -->
|
|
(
|
|
code_info__get_fall_through(Fall0),
|
|
{ stack__pop(Fall0, _, Fall) },
|
|
code_info__set_fall_through(Fall)
|
|
->
|
|
[]
|
|
;
|
|
{ error("code_info__pop_failure_cont: empty stack") }
|
|
).
|
|
|
|
code_info__failure_cont(Cont) -->
|
|
code_info__get_fall_through(Fall),
|
|
(
|
|
{ stack__top(Fall, Cont0) }
|
|
->
|
|
{ Cont = Cont0 }
|
|
;
|
|
{ error("code_info__failure_cont: no failure continuation") }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__manufacture_failure_cont(IsNondet) -->
|
|
{ map__init(Empty) },
|
|
(
|
|
{ IsNondet = no }
|
|
->
|
|
code_info__get_next_label(ContLab1),
|
|
code_info__get_next_label(ContLab2),
|
|
{ Address1 = label(ContLab1) },
|
|
{ Address2 = label(ContLab2) }
|
|
;
|
|
{ Address1 = do_fail },
|
|
{ Address2 = do_fail }
|
|
),
|
|
code_info__push_failure_cont(failure_cont(known(IsNondet),
|
|
no, [Empty - Address1, Empty - Address2])).
|
|
|
|
code_info__make_known_failure_cont(Vars, IsNondet, ModContCode) -->
|
|
code_info__get_next_label(ContLab),
|
|
code_info__get_next_label(StackLab),
|
|
(
|
|
{ IsNondet = no }
|
|
->
|
|
% In semidet continuations we don't use the redoip
|
|
{ HijackCode = empty },
|
|
{ MaybeRedoLab = no }
|
|
;
|
|
code_info__failure_cont(failure_cont(OrigCont, _, _)),
|
|
{ OrigCont = unknown }
|
|
->
|
|
% efficiency of this code could be improved
|
|
% ("mkframe()" is a bit of a sledge hammer)
|
|
code_info__get_next_label(RedoLab),
|
|
{ MaybeRedoLab = yes(RedoLab) },
|
|
{ HijackCode =
|
|
node([
|
|
mkframe("hijack", 1, label(RedoLab)) -
|
|
"create a temporary frame",
|
|
assign(curfr, lval(succfr(lval(maxfr)))) -
|
|
"restore curfr (which was clobbered by mkframe)"
|
|
])
|
|
}
|
|
;
|
|
{ MaybeRedoLab = no },
|
|
{ HijackCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(address_const(label(StackLab)))) -
|
|
"Set failure continuation"
|
|
]) }
|
|
),
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
code_info__produce_vars(VarList, RegMap, RegCode),
|
|
code_info__get_call_info(CallInfo),
|
|
{ map__select(CallInfo, Vars, StackMap0) },
|
|
{ map__to_assoc_list(StackMap0, StackList0) },
|
|
{ code_info__tweak_stacklist(StackList0, StackList) },
|
|
{ map__from_assoc_list(StackList, StackMap) },
|
|
{ ContMap = [RegMap-label(ContLab), StackMap-label(StackLab)] },
|
|
code_info__push_failure_cont(
|
|
failure_cont(known(IsNondet), MaybeRedoLab, ContMap)),
|
|
{ ModContCode = tree(RegCode, HijackCode) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__produce_vars(list(var), map(var, set(rval)), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__produce_vars(in, out, out, in, out) is det.
|
|
|
|
code_info__produce_vars([], Map, empty) -->
|
|
{ map__init(Map) }.
|
|
code_info__produce_vars([V|Vs], Map, Code) -->
|
|
code_info__produce_vars(Vs, Map0, Code0),
|
|
code_info__produce_variable_in_reg(V, Code1, Rval),
|
|
{ set__singleton_set(Rvals, Rval) },
|
|
{ map__set(Map0, V, Rvals, Map) },
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__tweak_stacklist(assoc_list(var, lval),
|
|
assoc_list(var, set(rval))).
|
|
:- mode code_info__tweak_stacklist(in, out) is det.
|
|
|
|
code_info__tweak_stacklist([], []).
|
|
code_info__tweak_stacklist([V-L|Rest0], [V-Rs|Rest]) :-
|
|
set__singleton_set(Rs, lval(L)),
|
|
code_info__tweak_stacklist(Rest0, Rest).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__unset_failure_cont -->
|
|
code_info__failure_cont(
|
|
failure_cont(_OrigCont, MaybeRedoLabel, FailureMap)),
|
|
code_info__pop_failure_cont,
|
|
code_info__push_failure_cont(
|
|
failure_cont(unknown, MaybeRedoLabel, FailureMap)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__relabel_failure_cont(failure_map, failure_map,
|
|
code_info, code_info).
|
|
:- mode code_info__relabel_failure_cont(in, out, in, out) is det.
|
|
|
|
code_info__relabel_failure_cont([], []) --> [].
|
|
code_info__relabel_failure_cont([Map - _|Rest0], [Map - L|Rest]) -->
|
|
code_info__get_next_label(L0),
|
|
{ L = label(L0) },
|
|
code_info__relabel_failure_cont(Rest0, Rest).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__modify_failure_cont(ModifyCode) -->
|
|
code_info__failure_cont(failure_cont(OldCont, MaybeRedo0, FailureMap)),
|
|
code_info__generate_failure_cont(FailureMap, FailureCode),
|
|
code_info__pop_failure_cont,
|
|
code_info__get_next_label(New0),
|
|
code_info__get_next_label(New1),
|
|
(
|
|
{ OldCont = unknown ; OldCont = known(yes) }
|
|
->
|
|
{ NewCont = known(yes) },
|
|
( { MaybeRedo0 = yes(_OldRedo) } ->
|
|
code_info__get_next_label(NewRedo),
|
|
{ MaybeRedo = yes(NewRedo) }
|
|
;
|
|
{ MaybeRedo = no }
|
|
),
|
|
{ ResetCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(address_const(label(New1)))) -
|
|
"modify failure cont"
|
|
]) }
|
|
;
|
|
{ error("code_info__modify_failure_cont: semidet context") }
|
|
% { NewCont = known(no) },
|
|
% { ResetCode = empty },
|
|
% { MaybeRedo = no }
|
|
),
|
|
(
|
|
{ FailureMap = [Map0 - _Lab0, Map1 - _Lab1] }
|
|
->
|
|
code_info__push_failure_cont(failure_cont(NewCont, MaybeRedo,
|
|
[Map0 - label(New0), Map1 - label(New1)]))
|
|
;
|
|
{ error("code_info__modify_failure_cont: bad failure map.") }
|
|
),
|
|
{ ModifyCode = tree(FailureCode, ResetCode) }.
|
|
|
|
% XXX rewrite this to fit on one screeen
|
|
code_info__restore_failure_cont(Code) -->
|
|
code_info__failure_cont(failure_cont(CurrentCont, _Redo1, FailureMap)),
|
|
code_info__generate_failure_cont(FailureMap, FailureCode),
|
|
code_info__pop_failure_cont,
|
|
% Fixup the redoip of the top frame if necessary
|
|
(
|
|
{ CurrentCont = known(no) }
|
|
->
|
|
{ RestoreCode = empty },
|
|
{ ResetCode = empty }
|
|
;
|
|
% { CurrentCont = known(yes) ; CurrentCont = unknown }
|
|
{ RestoreCode = empty },
|
|
code_info__failure_cont(failure_cont(NewCont, MaybeRedoLab,
|
|
NewFailureMap)),
|
|
(
|
|
{ NewCont = unknown },
|
|
{ ResetCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(address_const(do_fail))) -
|
|
"restore failure cont"
|
|
]) }
|
|
;
|
|
{ NewCont = known(NondetCont) },
|
|
(
|
|
{ NondetCont = no },
|
|
{ ResetCode = empty }
|
|
;
|
|
{ NondetCont = yes },
|
|
(
|
|
{ MaybeRedoLab = yes(RedoLab) }
|
|
->
|
|
{ NewRedoAddress = label(RedoLab) }
|
|
;
|
|
{ NewFailureMap = [_, _Map - Cont] }
|
|
->
|
|
{ NewRedoAddress = Cont }
|
|
;
|
|
{ error("code_info__restore_failure_cont: no valid failure-map") }
|
|
),
|
|
{ ResetCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(address_const(NewRedoAddress))) -
|
|
"restore failure cont"
|
|
]) }
|
|
)
|
|
)
|
|
),
|
|
{ Code = tree(FailureCode, tree(RestoreCode, ResetCode)) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__do_soft_cut(TheFrame, Code) -->
|
|
code_info__failure_cont(failure_cont(ContType, MaybeRedo, FailMap)),
|
|
(
|
|
{ ContType = known(_) },
|
|
(
|
|
{ MaybeRedo = yes(RedoLab) }
|
|
->
|
|
{ Address = label(RedoLab) }
|
|
;
|
|
{ FailMap = [_, _Places - StackLab] }
|
|
->
|
|
{ Address = StackLab }
|
|
;
|
|
{ error("code_info__do_soft_cut: invalid failmap") }
|
|
)
|
|
;
|
|
% If the newly uncovered cont is unknown then
|
|
% we must have created a new frame before the
|
|
% condition which we no longer need, so we
|
|
% set its redoip to do_fail.
|
|
{ ContType = unknown },
|
|
{ Address = do_fail }
|
|
),
|
|
{ Code = node([
|
|
assign(redoip(lval(TheFrame)), const(address_const(Address))) -
|
|
"prune away the `else' case of the if-then-else"
|
|
]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__generate_failure_cont(failure_map,
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__generate_failure_cont(in, out, in, out) is det.
|
|
|
|
code_info__generate_failure_cont(FailMap, Code) -->
|
|
code_info__failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(_CurrentCont, MaybeRedo, _FailureMap) },
|
|
|
|
% did we create a temp nondet frame?
|
|
% if so, we need to create a redo() continuation,
|
|
% which restores curfr before continuing
|
|
(
|
|
{ MaybeRedo = yes(RedoLab) }
|
|
->
|
|
{ FixCurFrCode =
|
|
node([
|
|
label(RedoLab) - "redo entry point",
|
|
assign(curfr, lval(succfr(lval(maxfr)))) -
|
|
"restore curfr"
|
|
])
|
|
}
|
|
;
|
|
{ FixCurFrCode = empty }
|
|
),
|
|
code_info__generate_failure_continuation(FailMap, Code0),
|
|
{ Code = tree(FixCurFrCode, Code0) }.
|
|
|
|
:- pred code_info__generate_failure_continuation(failure_map,
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__generate_failure_continuation(in, out, in, out) is det.
|
|
|
|
code_info__generate_failure_continuation([], _) -->
|
|
{ error("code_info__generate_failure_continuation: no mapping!") }.
|
|
code_info__generate_failure_continuation([C|Cs], Code) -->
|
|
{ C = Map0 - CodeAddr },
|
|
(
|
|
{ CodeAddr = label(Label0) }
|
|
->
|
|
{ Label = Label0 }
|
|
;
|
|
{ error("code_info__generate_failure_continuation: non-label!") }
|
|
),
|
|
(
|
|
{ Cs = [] },
|
|
{ Code = node([ label(Label) - "Failure Continuation" ]) },
|
|
code_info__set_var_locations(Map0)
|
|
;
|
|
{ Cs = [_|_] },
|
|
{ ThisCode = node([ label(Label) - "End of failure continuation" ]) },
|
|
code_info__generate_failure_cont_2(Cs, Map0, Map, RestCode),
|
|
code_info__set_var_locations(Map),
|
|
{ Code = tree(RestCode, ThisCode) }
|
|
).
|
|
|
|
:- pred code_info__generate_failure_cont_2(failure_map,
|
|
map(var, set(rval)), map(var, set(rval)), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_failure_cont_2(in, in, out, out, in, out) is det.
|
|
|
|
code_info__generate_failure_cont_2([], Map, Map, empty) --> [].
|
|
code_info__generate_failure_cont_2([C0|Cs], Map0, Map, Code) -->
|
|
{ C0 = ThisMap - CodeAddr0 },
|
|
(
|
|
{ CodeAddr0 = label(Label) },
|
|
{ map__to_assoc_list(ThisMap, VarLvalList) },
|
|
code_info__place_cont_vars(VarLvalList, Map0, Map1,
|
|
PlaceVarsCode),
|
|
{ ThisContCode = tree(
|
|
node([ label(Label) - "Part of the failure continuation" ]),
|
|
PlaceVarsCode
|
|
) }
|
|
;
|
|
{ CodeAddr0 = imported(_ProcLabel) },
|
|
{ error("what is imported/1 doing in a failure continuation?") }
|
|
;
|
|
{ CodeAddr0 = succip },
|
|
{ error("what is succip/0 doing in a failure continuation?") }
|
|
;
|
|
{ CodeAddr0 = do_succeed(_) },
|
|
{ error("what is do_succeed/1 doing in a failure continuation?") }
|
|
;
|
|
{ CodeAddr0 = do_redo },
|
|
{ ThisContCode = empty },
|
|
{ Map1 = Map0}
|
|
;
|
|
{ CodeAddr0 = do_fail },
|
|
{ ThisContCode = empty },
|
|
{ Map1 = Map0}
|
|
),
|
|
{ Code = tree(ThisContCode, RestCode) },
|
|
code_info__generate_failure_cont_2(Cs, Map1, Map, RestCode).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__place_cont_vars(assoc_list(var, set(rval)),
|
|
map(var, set(rval)), map(var, set(rval)),
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__place_cont_vars(in, in, out, out, in, out) is det.
|
|
|
|
code_info__place_cont_vars([], Map, Map, empty) --> [].
|
|
% Map0 has the places where each var may finally be stored,
|
|
% Map has the places where each var is actually stored.
|
|
code_info__place_cont_vars([Var - CurrSet | Rest], Map0, Map, Code) -->
|
|
{ map__lookup(Map0, Var, TargetSet) },
|
|
{ set__intersect(CurrSet, TargetSet, Rvals) },
|
|
(
|
|
{ set__empty(Rvals) }
|
|
->
|
|
{ set__to_sorted_list(CurrSet, CurrList) },
|
|
{ set__to_sorted_list(TargetSet, TargetList) },
|
|
(
|
|
% Should use cheapest, currently,
|
|
% just use first.
|
|
{ CurrList = [Source|_] },
|
|
{ code_info__lval_member(TargetLval, TargetList) }
|
|
->
|
|
{ ThisCode = node([
|
|
assign(TargetLval, Source) - ""
|
|
]) },
|
|
{ set__singleton_set(Rvals2, lval(TargetLval)) },
|
|
{ map__set(Map0, Var, Rvals2, Map1) }
|
|
;
|
|
{ list__member(Thing, TargetList) },
|
|
{ Thing = create(_, _, _) }
|
|
->
|
|
{ Map1 = Map0 },
|
|
{ ThisCode = empty }
|
|
;
|
|
{ list__member(Thing, TargetList) },
|
|
{ Thing = const(_) }
|
|
->
|
|
{ Map1 = Map0 },
|
|
{ ThisCode = empty }
|
|
;
|
|
{ error("code_info__place_cont_vars: No vars!") }
|
|
)
|
|
;
|
|
{ map__set(Map0, Var, Rvals, Map1) },
|
|
{ ThisCode = empty }
|
|
),
|
|
{ Code = tree(ThisCode, RestCode) },
|
|
code_info__place_cont_vars(Rest, Map1, Map, RestCode).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__lval_member(lval, list(rval)).
|
|
:- mode code_info__lval_member(out, in) is semidet.
|
|
|
|
code_info__lval_member(Lval, [X|Xs]) :-
|
|
(
|
|
X = lval(Lval0)
|
|
->
|
|
Lval = Lval0
|
|
;
|
|
code_info__lval_member(Lval, Xs)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__set_var_locations(map(var, set(rval)), code_info, code_info).
|
|
:- mode code_info__set_var_locations(in, in, out) is det.
|
|
|
|
code_info__set_var_locations(Map) -->
|
|
{ map__to_assoc_list(Map, List0) },
|
|
{ code_info__flatten_varlval_list(List0, List) },
|
|
code_info__get_varset(Varset),
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_options(Globals, Options) },
|
|
{ code_exprn__init_state(List, Varset, Options, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
:- pred code_info__flatten_varlval_list(assoc_list(var, set(rval)),
|
|
assoc_list(var, rval)).
|
|
:- mode code_info__flatten_varlval_list(in, out) is det.
|
|
|
|
code_info__flatten_varlval_list([], []).
|
|
code_info__flatten_varlval_list([V - Rvals | Rest0], All) :-
|
|
code_info__flatten_varlval_list(Rest0, Rest),
|
|
set__to_sorted_list(Rvals, RvalList),
|
|
code_info__flatten_varlval_list_2(RvalList, V, Rest1),
|
|
list__append(Rest1, Rest, All).
|
|
|
|
:- pred code_info__flatten_varlval_list_2(list(rval), var,
|
|
assoc_list(var, rval)).
|
|
:- mode code_info__flatten_varlval_list_2(in, in, out) is det.
|
|
|
|
code_info__flatten_varlval_list_2([], _V, []).
|
|
code_info__flatten_varlval_list_2([R|Rs], V, [V - R|Rest]) :-
|
|
code_info__flatten_varlval_list_2(Rs, V, Rest).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__push_store_map(Map) -->
|
|
code_info__get_store_map(Maps0),
|
|
{ stack__push(Maps0, Map, Maps) },
|
|
code_info__set_store_map(Maps).
|
|
|
|
code_info__pop_store_map -->
|
|
code_info__get_store_map(Maps0),
|
|
{ stack__pop_det(Maps0, _, Maps) },
|
|
code_info__set_store_map(Maps).
|
|
|
|
code_info__current_store_map(Map) -->
|
|
code_info__get_store_map(Maps0),
|
|
(
|
|
{ stack__top(Maps0, Map0) }
|
|
->
|
|
{ Map = Map0 }
|
|
;
|
|
{ error("No store map on stack") }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_stack_livevals(Args, LiveVals) -->
|
|
code_info__get_live_variables(LiveVars),
|
|
{ set__list_to_set(LiveVars, Vars0) },
|
|
{ set__difference(Vars0, Args, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
{ set__init(LiveVals0) },
|
|
code_info__generate_stack_livevals_2(VarList, LiveVals0, LiveVals1),
|
|
code_info__get_pushed_values(Pushed0),
|
|
code_info__get_commit_vals(CommitVals),
|
|
{ stack__push_list(Pushed0, CommitVals, Pushed) },
|
|
{ code_info__generate_stack_livevals_3(Pushed, LiveVals1, LiveVals) }.
|
|
|
|
:- pred code_info__generate_stack_livevals_2(list(var), set(lval), set(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_stack_livevals_2(in, in, out, in, out) is det.
|
|
|
|
code_info__generate_stack_livevals_2([], Vals, Vals) --> [].
|
|
code_info__generate_stack_livevals_2([V|Vs], Vals0, Vals) -->
|
|
code_info__get_variable_slot(V, Slot),
|
|
{ set__insert(Vals0, Slot, Vals1) },
|
|
code_info__generate_stack_livevals_2(Vs, Vals1, Vals).
|
|
|
|
:- pred code_info__generate_stack_livevals_3(stack(pair(lval, lval_or_ticket)),
|
|
set(lval), set(lval)).
|
|
:- mode code_info__generate_stack_livevals_3(in, in, out) is det.
|
|
|
|
code_info__generate_stack_livevals_3(Stack0, Vals0, Vals) :-
|
|
(
|
|
stack__pop(Stack0, Top - _, Stack1)
|
|
->
|
|
set__insert(Vals0, Top, Vals1),
|
|
code_info__generate_stack_livevals_3(Stack1, Vals1, Vals)
|
|
;
|
|
Vals = Vals0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__apply_instmap_delta(Delta) -->
|
|
code_info__get_instmap(InstMap0),
|
|
{ apply_instmap_delta(InstMap0, Delta, InstMap) },
|
|
code_info__set_instmap(InstMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_stack_livelvals(Args, LiveVals) -->
|
|
code_info__get_live_variables(LiveVars),
|
|
{ set__list_to_set(LiveVars, Vars0) },
|
|
{ set__difference(Vars0, Args, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
{ set__init(LiveVals0) },
|
|
code_info__generate_stack_livelvals_2(VarList, LiveVals0, LiveVals1),
|
|
{ set__to_sorted_list(LiveVals1, LiveVals2) },
|
|
code_info__livevals_to_livelvals(LiveVals2, LiveVals3),
|
|
code_info__get_pushed_values(Pushed0),
|
|
code_info__get_commit_vals(CommitVals),
|
|
{ stack__push_list(Pushed0, CommitVals, Pushed) },
|
|
{ code_info__generate_stack_livelvals_3(Pushed, LiveVals3, LiveVals) }.
|
|
|
|
:- pred code_info__generate_stack_livelvals_2(list(var),
|
|
set(pair(lval, var)),
|
|
set(pair(lval, var)),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_stack_livelvals_2(in, in, out, in, out) is det.
|
|
|
|
code_info__generate_stack_livelvals_2([], Vals, Vals) --> [].
|
|
code_info__generate_stack_livelvals_2([V|Vs], Vals0, Vals) -->
|
|
code_info__get_variable_slot(V, Slot),
|
|
{ set__insert(Vals0, Slot - V, Vals1) },
|
|
code_info__generate_stack_livelvals_2(Vs, Vals1, Vals).
|
|
|
|
:- pred code_info__generate_stack_livelvals_3(stack(pair(lval, lval_or_ticket)),
|
|
list(liveinfo), list(liveinfo)).
|
|
:- mode code_info__generate_stack_livelvals_3(in, in, out) is det.
|
|
|
|
code_info__generate_stack_livelvals_3(Stack0, LiveInfo0, LiveInfo) :-
|
|
(
|
|
stack__pop(Stack0, Top - StoredLval , Stack1)
|
|
->
|
|
code_info__get_shape_num(StoredLval, S_Num),
|
|
LiveInfo = [live_lvalue(Top, S_Num) | Lives],
|
|
code_info__generate_stack_livelvals_3(Stack1, LiveInfo0, Lives)
|
|
;
|
|
LiveInfo = LiveInfo0
|
|
).
|
|
|
|
:- pred code_info__get_shape_num(lval_or_ticket, shape_num).
|
|
:- mode code_info__get_shape_num(in, out) is det.
|
|
|
|
code_info__get_shape_num(lval(succip), succip).
|
|
code_info__get_shape_num(lval(hp), hp).
|
|
code_info__get_shape_num(lval(maxfr), maxfr).
|
|
code_info__get_shape_num(lval(curfr), curfr).
|
|
code_info__get_shape_num(lval(succfr(_)), succfr).
|
|
code_info__get_shape_num(lval(prevfr(_)), prevfr).
|
|
code_info__get_shape_num(lval(redoip(_)), redoip).
|
|
code_info__get_shape_num(lval(succip(_)), succip).
|
|
code_info__get_shape_num(lval(sp), sp).
|
|
code_info__get_shape_num(lval(lvar(_)), unwanted).
|
|
code_info__get_shape_num(lval(field(_, _, _)), unwanted).
|
|
code_info__get_shape_num(lval(temp(_)), unwanted).
|
|
code_info__get_shape_num(lval(reg(_)), unwanted).
|
|
code_info__get_shape_num(lval(stackvar(_)), unwanted).
|
|
code_info__get_shape_num(lval(framevar(_)), unwanted).
|
|
code_info__get_shape_num(ticket, ticket).
|
|
|
|
:- pred code_info__livevals_to_livelvals(list(pair(lval, var)), list(liveinfo),
|
|
code_info, code_info).
|
|
:- mode code_info__livevals_to_livelvals(in, out, in, out) is det.
|
|
|
|
code_info__livevals_to_livelvals([], [], C, C).
|
|
code_info__livevals_to_livelvals([L - V|Ls],
|
|
[live_lvalue(L, num(S_Num))|Lives]) -->
|
|
code_info__get_module_info(Module),
|
|
code_info__get_shapes(S_Tab0),
|
|
{ module_info_types(Module, Type_Table) },
|
|
code_info__variable_type(V, Type),
|
|
% We don't yet support partial insts when allocating
|
|
% shapes, so pass ground(shared, no) as a placeholder.
|
|
{ shapes__request_shape_number(Type - ground(shared, no), Type_Table,
|
|
S_Tab0, S_Tab1, S_Num) },
|
|
code_info__set_shapes(S_Tab1),
|
|
code_info__livevals_to_livelvals(Ls, Lives).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__variable_type(Var, Type) -->
|
|
code_info__get_proc_info(ProcInfo),
|
|
{ proc_info_vartypes(ProcInfo, VarTypes) },
|
|
{ map__lookup(VarTypes, Var, Type) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__get_stackslot_count(int, code_info, code_info).
|
|
:- mode code_info__get_stackslot_count(out, in, out) is det.
|
|
|
|
% :- pred code_info__get_registers(register_info, code_info, code_info).
|
|
% :- mode code_info__get_registers(out, in, out) is det.
|
|
%
|
|
% :- pred code_info__set_registers(register_info, code_info, code_info).
|
|
% :- mode code_info__set_registers(in, in, out) is det.
|
|
|
|
:- pred code_info__get_exprn_info(exprn_info, code_info, code_info).
|
|
:- mode code_info__get_exprn_info(out, in, out) is det.
|
|
|
|
:- pred code_info__set_exprn_info(exprn_info, code_info, code_info).
|
|
:- mode code_info__set_exprn_info(in, in, out) is det.
|
|
|
|
% Get the fall though point for failure
|
|
:- pred code_info__get_fall_through(fall_through, code_info, code_info).
|
|
:- mode code_info__get_fall_through(out, in, out) is det.
|
|
|
|
% Set the fall though point for failure
|
|
:- pred code_info__set_fall_through(fall_through, code_info, code_info).
|
|
:- mode code_info__set_fall_through(in, in, out) is det.
|
|
|
|
:- pred code_info__get_proc_model(code_model, code_info, code_info).
|
|
:- mode code_info__get_proc_model(out, in, out) is det.
|
|
|
|
:- pred code_info__get_push_count(int, code_info, code_info).
|
|
:- mode code_info__get_push_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_push_count(int, code_info, code_info).
|
|
:- mode code_info__set_push_count(in, in, out) is det.
|
|
|
|
:- pred code_info__get_max_push_count(int, code_info, code_info).
|
|
:- mode code_info__get_max_push_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_max_push_count(int, code_info, code_info).
|
|
:- mode code_info__set_max_push_count(in, in, out) is det.
|
|
|
|
:- pred code_info__get_store_map(stack(map(var, lval)), code_info, code_info).
|
|
:- mode code_info__get_store_map(out, in, out) is det.
|
|
|
|
:- pred code_info__set_store_map(stack(map(var, lval)), code_info, code_info).
|
|
:- mode code_info__set_store_map(in, in, out) is det.
|
|
|
|
:- pred code_info__get_pushed_values(stack(pair(lval, lval_or_ticket)),
|
|
code_info, code_info).
|
|
:- mode code_info__get_pushed_values(out, in, out) is det.
|
|
|
|
:- pred code_info__set_pushed_values(stack(pair(lval, lval_or_ticket)),
|
|
code_info, code_info).
|
|
:- mode code_info__set_pushed_values(in, in, out) is det.
|
|
|
|
:- pred code_info__get_commit_vals(list(pair(lval, lval_or_ticket)),
|
|
code_info, code_info).
|
|
:- mode code_info__get_commit_vals(out, in, out) is det.
|
|
|
|
:- pred code_info__set_commit_vals(list(pair(lval, lval_or_ticket)),
|
|
code_info, code_info).
|
|
:- mode code_info__set_commit_vals(in, in, out) is det.
|
|
|
|
code_info__get_stackslot_count(A, CI, CI) :-
|
|
CI = code_info(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
% code_info__set_stackslot_count(A, CI0, CI) :-
|
|
% CI0 = code_info(_, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
% T, U, V),
|
|
% CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
% T, U, V).
|
|
|
|
code_info__get_label_count(B, CI, CI) :-
|
|
CI = code_info(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_label_count(B, CI0, CI) :-
|
|
CI0 = code_info(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_varset(C, CI, CI) :-
|
|
CI = code_info(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_varset(C, CI0, CI) :-
|
|
CI0 = code_info(A, B, _, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_call_info(D, CI, CI) :-
|
|
CI = code_info(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_call_info(D, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, _, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_pred_id(E, CI, CI) :-
|
|
CI = code_info(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_pred_id(E, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, _, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_proc_id(F, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_proc_id(F, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
% code_info__get_registers(G, CI, CI) :-
|
|
% CI = code_info(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
% _, _, _).
|
|
|
|
% code_info__set_registers(G, CI0, CI) :-
|
|
% CI0 = code_info(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
% T, U, V),
|
|
% CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
% T, U, V).
|
|
|
|
code_info__get_exprn_info(H, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_exprn_info(H, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, _, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_proc_info(I, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_succip_used(J, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_succip_used(J, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_fall_through(K, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_fall_through(K, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, _, L, M, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_module_info(L, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
% It is a bad idea to allow the code generator to module_info
|
|
% in arbitrary ways.
|
|
% code_info__set_module_info(L, CI0, CI) :-
|
|
% CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, P, Q, R, S, T, U, V),
|
|
% CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V).
|
|
|
|
code_info__get_liveness_info(M, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_liveness_info(M, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_store_map(N, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_store_map(N, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, P, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_proc_model(O, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_instmap(P, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__set_instmap(P, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, _, Q, R, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_push_count(Q, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
Q - _, _, _, _, _, _).
|
|
|
|
code_info__get_max_push_count(QMax, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_ - QMax, _, _, _, _, _).
|
|
|
|
code_info__set_push_count(Q, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
|
|
_ - QMax0, R, S, T, U, V),
|
|
int__max(QMax0, Q, QMax),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
|
|
Q - QMax, R, S, T, U, V).
|
|
|
|
code_info__set_max_push_count(QMax, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
|
|
Q - _, R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
|
|
Q - QMax, R, S, T, U, V).
|
|
|
|
code_info__get_globals(R, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, R, _,
|
|
_, _, _).
|
|
|
|
code_info__set_globals(R, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, _, S,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_pushed_values(S, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, S,
|
|
_, _, _).
|
|
|
|
code_info__set_pushed_values(S, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, _,
|
|
T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_shapes(T, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
T, _, _).
|
|
|
|
code_info__set_shapes(T, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
_, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_nondet_lives(U, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, U, _).
|
|
|
|
code_info__set_nondet_lives(U, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, _, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
code_info__get_commit_vals(V, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, V).
|
|
|
|
code_info__set_commit_vals(V, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, _),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S,
|
|
T, U, V).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__grab_code_info(C, C, C).
|
|
|
|
code_info__slap_code_info(C0, C1, C) :-
|
|
code_info__get_label_count(L, C1, _),
|
|
code_info__set_label_count(L, C0, C2),
|
|
code_info__get_succip_used(S, C1, _),
|
|
code_info__set_succip_used(S, C2, C3),
|
|
code_info__get_store_map(F, C1, _),
|
|
code_info__set_store_map(F, C3, C4),
|
|
code_info__get_fall_through(J, C0, _),
|
|
code_info__set_fall_through(J, C4, C5),
|
|
code_info__get_max_push_count(PC, C1, _),
|
|
code_info__set_max_push_count(PC, C5, C).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__variable_to_string(Var, Name) -->
|
|
code_info__get_varset(Varset),
|
|
{ varset__lookup_name(Varset, Var, Name) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|