mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +00:00
Estimated hours taken: 0.5 Branches: main tools/subst: A simple tool for performing substitutions on the source files of the compiler. compiler/*.m: Change the names of the get predicates operating on module_infos to include "get" in the name, for uniformity. This was done mostly by the following sed script, with some manual cleanup afterwards to reduce excessive line lengths. s/module_info_types/module_info_get_type_table/ s/module_info_set_types/module_info_set_type_table/ s/module_info_insts/module_info_get_inst_table/ s/module_info_set_insts/module_info_set_inst_table/ s/module_info_modes/module_info_get_mode_table/ s/module_info_set_modes/module_info_set_mode_table/ s/module_info_ctors/module_info_get_cons_table/ s/module_info_set_ctors/module_info_set_cons_table/ s/module_info_classes/module_info_get_class_table/ s/module_info_set_classes/module_info_set_class_table/ s/module_info_instances/module_info_get_instance_table/ s/module_info_set_instances/module_info_set_instance_table/ s/module_info_superclasses/module_info_get_superclass_table/ s/module_info_set_superclasses/module_info_set_superclass_table/ s/module_info_assertion_table/module_info_get_assertion_table/ s/module_info_exclusive_table/module_info_get_exclusive_table/ s/module_info_ctor_field_table/module_info_get_ctor_field_table/ s/module_info_name/module_info_get_name/ s/module_info_globals/module_info_get_globals/ s/module_info_contains_foreign_types/module_info_get_contains_foreign_types/ s/module_info_num_errors/module_info_get_num_errors/ s/module_info_type_ctor_gen_infos/module_info_get_type_ctor_gen_infos/ s/module_info_stratified_preds/module_info_get_stratified_preds/ s/module_info_unused_arg_info/module_info_get_unused_arg_info/ s/module_info_exception_info/module_info_get_exception_info/ s/module_info_type_spec_info/module_info_get_type_spec_info/ s/module_info_no_tag_types/module_info_get_no_tag_types/ s/module_info_analysis_info/module_info_get_analysis_info/ s/module_info_aditi_top_down_procs/module_info_get_aditi_top_down_procs/
1496 lines
60 KiB
Mathematica
1496 lines
60 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2005 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% file: mode_util.m
|
|
% main author: fjh
|
|
|
|
% This module contains utility predicates for dealing with modes and insts.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds__mode_util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds__hlds_goal.
|
|
:- import_module hlds__hlds_module.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module hlds__instmap.
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% mode_get_insts returns the initial instantiatedness and the final
|
|
% instantiatedness for a given mode.
|
|
% Throw an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_get_insts(module_info::in, (mode)::in, (inst)::out, (inst)::out)
|
|
is det.
|
|
|
|
% A version of mode_get_insts that fails if the mode is undefined.
|
|
%
|
|
:- pred mode_get_insts_semidet(module_info::in, (mode)::in,
|
|
(inst)::out, (inst)::out) is semidet.
|
|
|
|
% A mode is considered input if the initial inst is bound.
|
|
% Throws an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_is_input(module_info::in, (mode)::in) is semidet.
|
|
|
|
% A mode is considered fully input if the initial inst is ground.
|
|
% Throws an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_is_fully_input(module_info::in, (mode)::in) is semidet.
|
|
|
|
% A mode is considered output if the initial inst is free and the
|
|
% final inst is bound.
|
|
% Throws an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_is_output(module_info::in, (mode)::in) is semidet.
|
|
|
|
% A mode is considered fully output if the initial inst is free and
|
|
% the final inst is ground.
|
|
% Throws an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_is_fully_output(module_info::in, (mode)::in) is semidet.
|
|
|
|
% A mode is considered unused if both initial and final insts are free.
|
|
% Throws an exception if the mode is undefined.
|
|
%
|
|
:- pred mode_is_unused(module_info::in, (mode)::in) is semidet.
|
|
|
|
% Succeeds iff the given mode is undefined.
|
|
%
|
|
:- pred mode_is_undefined(module_info::in, (mode)::in) is semidet.
|
|
|
|
% mode_to_arg_mode converts a mode (and corresponding type) to
|
|
% an arg_mode. A mode is a high-level notion, the normal
|
|
% Mercury language mode. An `arg_mode' is a low-level notion
|
|
% used for code generation, which indicates the argument
|
|
% passing convention (top_in, top_out, or top_unused) that
|
|
% corresponds to that mode. We need to know the type, not just
|
|
% the mode, because the argument passing convention can depend
|
|
% on the type's representation.
|
|
%
|
|
:- pred mode_to_arg_mode(module_info::in, (mode)::in, (type)::in,
|
|
arg_mode::out) is det.
|
|
|
|
:- pred modes_to_arg_modes(module_info::in, list(mode)::in, list(type)::in,
|
|
list(arg_mode)::out) is det.
|
|
|
|
:- func mode_get_initial_inst(module_info, (mode)) = (inst).
|
|
|
|
:- func mode_get_final_inst(module_info, (mode)) = (inst).
|
|
|
|
:- pred mode_list_get_initial_insts(module_info::in,
|
|
list(mode)::in, list(inst)::out) is det.
|
|
|
|
:- pred mode_list_get_final_insts(module_info::in,
|
|
list(mode)::in, list(inst)::out) is det.
|
|
|
|
:- pred modes_to_uni_modes(module_info::in, list(mode)::in, list(mode)::in,
|
|
list(uni_mode)::out) is det.
|
|
|
|
% Given a user-defined or compiler-defined inst name, lookup the
|
|
% corresponding inst in the inst table.
|
|
%
|
|
:- pred inst_lookup(module_info::in, inst_name::in, (inst)::out) is det.
|
|
|
|
% Use the instmap deltas for all the atomic sub-goals to recompute
|
|
% the instmap deltas for all the non-atomic sub-goals of a goal.
|
|
% Used to ensure that the instmap deltas remain valid after code has
|
|
% been re-arranged, e.g. by followcode. This also takes the
|
|
% module_info as input and output since it may need to insert new
|
|
% merge_insts into the merge_inst table. If the first argument is
|
|
% yes, the instmap_deltas for calls and deconstruction unifications
|
|
% are also recomputed.
|
|
%
|
|
:- pred recompute_instmap_delta_proc(bool::in, proc_info::in, proc_info::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
:- pred recompute_instmap_delta(bool::in, hlds_goal::in, hlds_goal::out,
|
|
vartypes::in, inst_varset::in, instmap::in, module_info::in,
|
|
module_info::out) is det.
|
|
|
|
% Given corresponding lists of types and modes, produce a new list
|
|
% of modes which includes the information provided by the
|
|
% corresponding types.
|
|
%
|
|
:- pred propagate_types_into_mode_list(module_info::in, list(type)::in,
|
|
list(mode)::in, list(mode)::out) is det.
|
|
|
|
% Given corresponding lists of types and insts and a substitution
|
|
% for the type variables in the type, produce a new list of insts
|
|
% which includes the information provided by the corresponding types.
|
|
%
|
|
:- pred propagate_types_into_inst_list(module_info::in, tsubst::in,
|
|
list(type)::in, list(inst)::in, list(inst)::out) is det.
|
|
|
|
% Convert a list of constructors to a list of bound_insts where the
|
|
% arguments are `ground'.
|
|
%
|
|
% NOTE: the list(bound_inst) is not sorted and may contain
|
|
% duplicates.
|
|
%
|
|
:- pred constructors_to_bound_insts(module_info::in, uniqueness::in,
|
|
list(constructor)::in, list(bound_inst)::out) is det.
|
|
|
|
% Convert a list of constructors to a list of bound_insts where the
|
|
% arguments are `any'.
|
|
%
|
|
% NOTE: the list(bound_inst) is not sorted and may contain
|
|
% duplicates.
|
|
%
|
|
:- pred constructors_to_bound_any_insts(module_info::in, uniqueness::in,
|
|
list(constructor)::in, list(bound_inst)::out) is det.
|
|
|
|
% Given the mode of a predicate, work out which arguments are live
|
|
% (might be used again by the caller of that predicate) and which
|
|
% are dead.
|
|
%
|
|
:- pred get_arg_lives(module_info::in, list(mode)::in, list(is_live)::out)
|
|
is det.
|
|
|
|
% Given the switched on variable and the instmaps before the switch
|
|
% and after a branch make sure that any information added by the
|
|
% functor test gets added to the instmap for the case.
|
|
%
|
|
:- pred fixup_switch_var(prog_var::in, instmap::in, instmap::in,
|
|
hlds_goal::in, hlds_goal::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred normalise_insts(module_info::in, list(type)::in,
|
|
list(inst)::in, list(inst)::out) is det.
|
|
|
|
:- pred normalise_inst(module_info::in, (type)::in, (inst)::in, (inst)::out)
|
|
is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Partition a list of arguments into inputs and others.
|
|
% Throws an exception if one of the modes is undefined.
|
|
%
|
|
:- pred partition_args(module_info::in, list(mode)::in, list(T)::in,
|
|
list(T)::out, list(T)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds__inst_match.
|
|
:- import_module check_hlds__inst_util.
|
|
:- import_module check_hlds__mode_info.
|
|
:- import_module check_hlds__type_util.
|
|
:- import_module hlds__hlds_data.
|
|
:- import_module mdbcomp__prim_data.
|
|
:- import_module parse_tree__error_util.
|
|
:- import_module parse_tree__prog_io.
|
|
:- import_module parse_tree__prog_mode.
|
|
:- import_module parse_tree__prog_util.
|
|
:- import_module parse_tree__prog_type.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module std_util.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
mode_get_initial_inst(ModuleInfo, Mode) = Inst :-
|
|
mode_get_insts(ModuleInfo, Mode, Inst, _).
|
|
|
|
mode_get_final_inst(ModuleInfo, Mode) = Inst :-
|
|
mode_get_insts(ModuleInfo, Mode, _, Inst).
|
|
|
|
mode_list_get_initial_insts(_ModuleInfo, [], []).
|
|
mode_list_get_initial_insts(ModuleInfo, [Mode | Modes], [Inst | Insts]) :-
|
|
mode_get_insts(ModuleInfo, Mode, Inst, _),
|
|
mode_list_get_initial_insts(ModuleInfo, Modes, Insts).
|
|
|
|
mode_list_get_final_insts(_ModuleInfo, [], []).
|
|
mode_list_get_final_insts(ModuleInfo, [Mode | Modes], [Inst | Insts]) :-
|
|
mode_get_insts(ModuleInfo, Mode, _, Inst),
|
|
mode_list_get_final_insts(ModuleInfo, Modes, Insts).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% A mode is considered an input mode if the top-level node is input.
|
|
%
|
|
mode_is_input(ModuleInfo, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, _FinalInst),
|
|
inst_is_bound(ModuleInfo, InitialInst).
|
|
|
|
% A mode is considered fully input if its initial inst is ground.
|
|
%
|
|
mode_is_fully_input(ModuleInfo, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, _FinalInst),
|
|
inst_is_ground(ModuleInfo, InitialInst).
|
|
|
|
% A mode is considered an output mode if the top-level node is output.
|
|
%
|
|
mode_is_output(ModuleInfo, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, FinalInst),
|
|
inst_is_free(ModuleInfo, InitialInst),
|
|
inst_is_bound(ModuleInfo, FinalInst).
|
|
|
|
% A mode is considered fully output if its initial inst is free
|
|
% and its final insts is ground.
|
|
%
|
|
mode_is_fully_output(ModuleInfo, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, FinalInst),
|
|
inst_is_free(ModuleInfo, InitialInst),
|
|
inst_is_ground(ModuleInfo, FinalInst).
|
|
|
|
% A mode is considered a unused mode if it is equivalent to free >> free.
|
|
%
|
|
mode_is_unused(ModuleInfo, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, FinalInst),
|
|
inst_is_free(ModuleInfo, InitialInst),
|
|
inst_is_free(ModuleInfo, FinalInst).
|
|
|
|
mode_is_undefined(ModuleInfo, Mode) :-
|
|
not mode_get_insts_semidet(ModuleInfo, Mode, _, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
modes_to_arg_modes(_ModuleInfo, [], [], []).
|
|
modes_to_arg_modes(_ModuleInfo, [], [_ | _], _) :-
|
|
unexpected(this_file, "modes_to_arg_modes: length mismatch").
|
|
modes_to_arg_modes(_ModuleInfo, [_ | _], [], _) :-
|
|
unexpected(this_file, "modes_to_arg_modes: length mismatch").
|
|
modes_to_arg_modes(ModuleInfo, [Mode | Modes], [Type | Types],
|
|
[ArgMode | ArgModes]) :-
|
|
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
|
|
modes_to_arg_modes(ModuleInfo, Modes, Types, ArgModes).
|
|
|
|
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode) :-
|
|
mode_to_arg_mode_2(ModuleInfo, Mode, Type, [], ArgMode).
|
|
|
|
:- pred mode_to_arg_mode_2(module_info::in, (mode)::in, (type)::in,
|
|
list(type_ctor)::in, arg_mode::out) is det.
|
|
|
|
mode_to_arg_mode_2(ModuleInfo, Mode, Type, ContainingTypes, ArgMode) :-
|
|
%
|
|
% We need to handle no_tag types (types which have exactly one constructor,
|
|
% and whose one constructor has exactly one argument) specially here,
|
|
% since for them an inst of bound(f(free)) is not really bound as far as
|
|
% code generation is concerned, since the f/1 will get optimized away.
|
|
%
|
|
(
|
|
% Is this a no_tag type?
|
|
type_is_no_tag_type(ModuleInfo, Type, FunctorName, ArgType),
|
|
% Avoid infinite recursion.
|
|
type_to_ctor_and_args(Type, TypeCtor, _TypeArgs),
|
|
\+ list__member(TypeCtor, ContainingTypes)
|
|
->
|
|
% The arg_mode will be determined by the mode and type of the
|
|
% functor's argument, so we figure out the mode and type of the
|
|
% argument, and then recurse.
|
|
%
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, FinalInst),
|
|
ConsId = cons(FunctorName, 1),
|
|
get_single_arg_inst(InitialInst, ModuleInfo, ConsId, InitialArgInst),
|
|
get_single_arg_inst(FinalInst, ModuleInfo, ConsId, FinalArgInst),
|
|
ModeOfArg = (InitialArgInst -> FinalArgInst),
|
|
mode_to_arg_mode_2(ModuleInfo, ModeOfArg, ArgType,
|
|
[TypeCtor | ContainingTypes], ArgMode)
|
|
;
|
|
base_mode_to_arg_mode(ModuleInfo, Mode, ArgMode)
|
|
).
|
|
|
|
:- pred base_mode_to_arg_mode(module_info::in, (mode)::in, arg_mode::out)
|
|
is det.
|
|
|
|
base_mode_to_arg_mode(ModuleInfo, Mode, ArgMode) :-
|
|
mode_get_insts(ModuleInfo, Mode, InitialInst, FinalInst),
|
|
( inst_is_bound(ModuleInfo, InitialInst) ->
|
|
ArgMode = top_in
|
|
; inst_is_bound(ModuleInfo, FinalInst) ->
|
|
ArgMode = top_out
|
|
;
|
|
ArgMode = top_unused
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% get_single_arg_inst(Inst, ConsId, Arity, ArgInsts):
|
|
% Given an inst `Inst', figure out what the inst of the argument would be,
|
|
% assuming that the functor is the one given by the specified ConsId,
|
|
% whose arity is 1.
|
|
%
|
|
:- pred get_single_arg_inst((inst)::in, module_info::in, cons_id::in,
|
|
(inst)::out) is det.
|
|
|
|
get_single_arg_inst(defined_inst(InstName), ModuleInfo, ConsId, ArgInst) :-
|
|
inst_lookup(ModuleInfo, InstName, Inst),
|
|
get_single_arg_inst(Inst, ModuleInfo, ConsId, ArgInst).
|
|
get_single_arg_inst(not_reached, _, _, not_reached).
|
|
get_single_arg_inst(ground(Uniq, _PredInst), _, _, ground(Uniq, none)).
|
|
get_single_arg_inst(bound(_Uniq, List), _, ConsId, ArgInst) :-
|
|
( get_single_arg_inst_2(List, ConsId, ArgInst0) ->
|
|
ArgInst = ArgInst0
|
|
;
|
|
% The code is unreachable.
|
|
ArgInst = not_reached
|
|
).
|
|
get_single_arg_inst(free, _, _, free).
|
|
get_single_arg_inst(free(_Type), _, _, free). % XXX loses type info
|
|
get_single_arg_inst(any(Uniq), _, _, any(Uniq)).
|
|
get_single_arg_inst(abstract_inst(_, _), _, _, _) :-
|
|
unexpected(this_file,
|
|
"get_single_arg_inst: abstract insts not supported").
|
|
get_single_arg_inst(inst_var(_), _, _, _) :-
|
|
unexpected(this_file, "get_single_arg_inst: inst_var").
|
|
get_single_arg_inst(constrained_inst_vars(_, Inst), ModuleInfo, ConsId,
|
|
ArgInst) :-
|
|
get_single_arg_inst(Inst, ModuleInfo, ConsId, ArgInst).
|
|
|
|
:- pred get_single_arg_inst_2(list(bound_inst)::in, cons_id::in, (inst)::out)
|
|
is semidet.
|
|
|
|
get_single_arg_inst_2([BoundInst | BoundInsts], ConsId, ArgInst) :-
|
|
( BoundInst = functor(ConsId, [ArgInst0]) ->
|
|
ArgInst = ArgInst0
|
|
;
|
|
get_single_arg_inst_2(BoundInsts, ConsId, ArgInst)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Given two lists of modes (inst mappings) of equal length, convert
|
|
% them into a single list of inst pair mappings.
|
|
%
|
|
modes_to_uni_modes(_ModuleInfo, [], [], []).
|
|
modes_to_uni_modes(_ModuleInfo, [], [_ | _], _) :-
|
|
unexpected(this_file, "modes_to_uni_modes: length mismatch").
|
|
modes_to_uni_modes(_ModuleInfo, [_ | _], [], _) :-
|
|
unexpected(this_file, "modes_to_uni_modes: length mismatch").
|
|
modes_to_uni_modes(ModuleInfo, [X | Xs], [Y | Ys], [A | As]) :-
|
|
mode_get_insts(ModuleInfo, X, InitialX, FinalX),
|
|
mode_get_insts(ModuleInfo, Y, InitialY, FinalY),
|
|
A = ((InitialX - InitialY) -> (FinalX - FinalY)),
|
|
modes_to_uni_modes(ModuleInfo, Xs, Ys, As).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
inst_lookup(ModuleInfo, InstName, Inst) :-
|
|
(
|
|
InstName = unify_inst(_, _, _, _),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_unify_insts(InstTable, UnifyInstTable),
|
|
map__lookup(UnifyInstTable, InstName, MaybeInst),
|
|
( MaybeInst = known(Inst0, _) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = merge_inst(A, B),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_merge_insts(InstTable, MergeInstTable),
|
|
map__lookup(MergeInstTable, A - B, MaybeInst),
|
|
( MaybeInst = known(Inst0) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = ground_inst(_, _, _, _),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_ground_insts(InstTable, GroundInstTable),
|
|
map__lookup(GroundInstTable, InstName, MaybeInst),
|
|
( MaybeInst = known(Inst0, _) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = any_inst(_, _, _, _),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_any_insts(InstTable, AnyInstTable),
|
|
map__lookup(AnyInstTable, InstName, MaybeInst),
|
|
( MaybeInst = known(Inst0, _) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = shared_inst(SharedInstName),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_shared_insts(InstTable, SharedInstTable),
|
|
map__lookup(SharedInstTable, SharedInstName, MaybeInst),
|
|
( MaybeInst = known(Inst0) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = mostly_uniq_inst(NondetLiveInstName),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_mostly_uniq_insts(InstTable,
|
|
NondetLiveInstTable),
|
|
map__lookup(NondetLiveInstTable, NondetLiveInstName, MaybeInst),
|
|
( MaybeInst = known(Inst0) ->
|
|
Inst = Inst0
|
|
;
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = user_inst(Name, Args),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_user_insts(InstTable, UserInstTable),
|
|
user_inst_table_get_inst_defns(UserInstTable, InstDefns),
|
|
list__length(Args, Arity),
|
|
( map__search(InstDefns, Name - Arity, InstDefn) ->
|
|
InstDefn = hlds_inst_defn(_VarSet, Params, InstBody, _C, _),
|
|
inst_lookup_subst_args(InstBody, Params, Name, Args, Inst)
|
|
;
|
|
Inst = abstract_inst(Name, Args)
|
|
)
|
|
;
|
|
InstName = typed_ground(Uniq, Type),
|
|
map__init(Subst),
|
|
propagate_type_into_inst(ModuleInfo, Subst, Type,
|
|
ground(Uniq, none), Inst)
|
|
;
|
|
InstName = typed_inst(Type, TypedInstName),
|
|
inst_lookup(ModuleInfo, TypedInstName, Inst0),
|
|
map__init(Subst),
|
|
propagate_type_into_inst(ModuleInfo, Subst, Type, Inst0, Inst)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Given corresponding lists of types and modes, produce a new
|
|
% list of modes which includes the information provided by the
|
|
% corresponding types.
|
|
%
|
|
propagate_types_into_mode_list(_, [], [], []).
|
|
propagate_types_into_mode_list(ModuleInfo, [Type | Types],
|
|
[Mode0 | Modes0], [Mode | Modes]) :-
|
|
propagate_type_into_mode(ModuleInfo, Type, Mode0, Mode),
|
|
propagate_types_into_mode_list(ModuleInfo, Types, Modes0, Modes).
|
|
propagate_types_into_mode_list(_, [], [_ | _], []) :-
|
|
unexpected(this_file, "propagate_types_into_mode_list: length mismatch").
|
|
propagate_types_into_mode_list(_, [_ | _], [], []) :-
|
|
unexpected(this_file, "propagate_types_into_mode_list: length mismatch").
|
|
|
|
propagate_types_into_inst_list(_, _, [], [], []).
|
|
propagate_types_into_inst_list(ModuleInfo, Subst, [Type | Types],
|
|
[Inst0 | Insts0], [Inst | Insts]) :-
|
|
propagate_type_into_inst(ModuleInfo, Subst, Type, Inst0, Inst),
|
|
propagate_types_into_inst_list(ModuleInfo, Subst, Types, Insts0, Insts).
|
|
propagate_types_into_inst_list(_, _, [], [_ | _], []) :-
|
|
unexpected(this_file, "propagate_types_into_inst_list: length mismatch").
|
|
propagate_types_into_inst_list(_, _, [_ | _], [], []) :-
|
|
unexpected(this_file, "propagate_types_into_inst_list: length mismatch").
|
|
|
|
% Given a type and a mode, produce a new mode that includes the
|
|
% information provided by the type.
|
|
%
|
|
:- pred propagate_type_into_mode(module_info::in, (type)::in,
|
|
(mode)::in, (mode)::out) is det.
|
|
|
|
propagate_type_into_mode(ModuleInfo, Type, Mode0, Mode) :-
|
|
mode_get_insts(ModuleInfo, Mode0, InitialInst0, FinalInst0),
|
|
map__init(Subst),
|
|
propagate_type_into_inst_lazily(ModuleInfo, Subst, Type,
|
|
InitialInst0, InitialInst),
|
|
propagate_type_into_inst_lazily(ModuleInfo, Subst, Type,
|
|
FinalInst0, FinalInst),
|
|
Mode = (InitialInst -> FinalInst).
|
|
|
|
% Given a type, an inst and a substitution for the type variables in
|
|
% the type, produce a new inst that includes the information
|
|
% provided by the type.
|
|
%
|
|
% There are three sorts of information added:
|
|
% 1. Module qualifiers.
|
|
% 2. The set of constructors in the type.
|
|
% 3. For higher-order function types
|
|
% (but not higher-order predicate types),
|
|
% the higher-order inst, i.e. the argument modes
|
|
% and the determinism.
|
|
%
|
|
% Currently #2 is not yet implemented, due to unsolved
|
|
% efficiency problems. (See the XXX's below.)
|
|
%
|
|
% There are two versions, an "eager" one and a "lazy" one. In
|
|
% general eager expansion is to be preferred, because the expansion
|
|
% is done just once, whereas with lazy expansion the work will be
|
|
% done N times.
|
|
% However, for recursive insts we must use lazy expansion (otherwise
|
|
% we would get infinite regress). Also, usually many of the
|
|
% imported procedures will not be called, so for the insts in
|
|
% imported mode declarations N is often zero.
|
|
%
|
|
:- pred propagate_type_into_inst(module_info::in, tsubst::in, (type)::in,
|
|
(inst)::in, (inst)::out) is det.
|
|
|
|
:- pred propagate_type_into_inst_lazily(module_info::in, tsubst::in,
|
|
(type)::in, (inst)::in, (inst)::out) is det.
|
|
|
|
% % XXX We ought to expand things eagerly here, using the commented
|
|
% % out code below. However, that causes efficiency problems,
|
|
% % so for the moment it is disabled.
|
|
% propagate_type_into_inst(Type, Subst, ModuleInfo, Inst0, Inst) :-
|
|
% apply_type_subst(Type0, Subst, Type),
|
|
% (
|
|
% type_constructors(Type, ModuleInfo, Constructors)
|
|
% ->
|
|
% propagate_ctor_info(Inst0, Type, Constructors, ModuleInfo, Inst)
|
|
% ;
|
|
% Inst = Inst0
|
|
% ).
|
|
|
|
propagate_type_into_inst(ModuleInfo, Subst, Type, Inst0, Inst) :-
|
|
propagate_ctor_info_lazily(ModuleInfo, Subst, Type, Inst0, Inst).
|
|
|
|
propagate_type_into_inst_lazily(ModuleInfo, Subst, Type, Inst0, Inst) :-
|
|
propagate_ctor_info_lazily(ModuleInfo, Subst, Type, Inst0, Inst).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred propagate_ctor_info(module_info::in, (type)::in,
|
|
list(constructor)::in, (inst)::in, (inst)::out) is det.
|
|
|
|
propagate_ctor_info(ModuleInfo, Type, Constructors, Inst0, Inst) :-
|
|
(
|
|
Inst0 = any(_Uniq),
|
|
Inst = Inst0 % XXX loses type info!
|
|
;
|
|
Inst0 = free,
|
|
% Inst = free(Type)
|
|
Inst = free % XXX temporary hack
|
|
;
|
|
Inst0 = free(_),
|
|
unexpected(this_file, "propagate_ctor_info: type info already present")
|
|
;
|
|
Inst0 = bound(Uniq, BoundInsts0),
|
|
propagate_ctor_info_2(ModuleInfo, Type, BoundInsts0, BoundInsts),
|
|
(
|
|
BoundInsts = [],
|
|
Inst = not_reached
|
|
;
|
|
BoundInsts = [_ | _],
|
|
% XXX do we need to sort the BoundInsts?
|
|
Inst = bound(Uniq, BoundInsts)
|
|
)
|
|
;
|
|
Inst0 = ground(Uniq, none),
|
|
( type_is_higher_order(Type, _Purity, function, _, ArgTypes) ->
|
|
default_higher_order_func_inst(ModuleInfo, ArgTypes,
|
|
HigherOrderInstInfo),
|
|
Inst = ground(Uniq, higher_order(HigherOrderInstInfo))
|
|
;
|
|
constructors_to_bound_insts(ModuleInfo, Uniq,
|
|
Constructors, BoundInsts0),
|
|
list__sort_and_remove_dups(BoundInsts0, BoundInsts),
|
|
Inst = bound(Uniq, BoundInsts)
|
|
)
|
|
;
|
|
Inst0 = ground(Uniq, higher_order(PredInstInfo0)),
|
|
PredInstInfo0 = pred_inst_info(PredOrFunc, Modes0, Det),
|
|
(
|
|
type_is_higher_order(Type, _Purity, PredOrFunc, _, ArgTypes),
|
|
list__same_length(ArgTypes, Modes0)
|
|
->
|
|
propagate_types_into_mode_list(ModuleInfo, ArgTypes, Modes0, Modes)
|
|
;
|
|
% The inst is not a valid inst for the type, so leave it alone.
|
|
% This can only happen if the user has made a mistake. A mode
|
|
% error should hopefully be reported if anything tries to match
|
|
% with the inst.
|
|
Modes = Modes0
|
|
),
|
|
PredInstInfo = pred_inst_info(PredOrFunc, Modes, Det),
|
|
Inst = ground(Uniq, higher_order(PredInstInfo))
|
|
;
|
|
Inst0 = not_reached,
|
|
Inst = Inst0
|
|
;
|
|
Inst0 = inst_var(_),
|
|
Inst = Inst0
|
|
;
|
|
Inst0 = constrained_inst_vars(V, SubInst0),
|
|
propagate_ctor_info(ModuleInfo, Type, Constructors, SubInst0, SubInst),
|
|
Inst = constrained_inst_vars(V, SubInst)
|
|
;
|
|
Inst0 = abstract_inst(_Name, _Args),
|
|
Inst = Inst0 % XXX loses info
|
|
;
|
|
Inst0 = defined_inst(InstName),
|
|
inst_lookup(ModuleInfo, InstName, NamedInst),
|
|
propagate_ctor_info(ModuleInfo, Type, Constructors, NamedInst, Inst)
|
|
).
|
|
|
|
:- pred propagate_ctor_info_lazily(module_info::in, tsubst::in, (type)::in,
|
|
(inst)::in, (inst)::out) is det.
|
|
|
|
propagate_ctor_info_lazily(ModuleInfo, Subst, Type0, Inst0, Inst) :-
|
|
(
|
|
Inst0 = any(_Uniq),
|
|
Inst = Inst0 % XXX loses type info!
|
|
;
|
|
Inst0 = free,
|
|
% Inst = free(Type0)
|
|
Inst = free % XXX temporary hack
|
|
;
|
|
Inst0 = free(_),
|
|
error("propagate_ctor_info_lazily: type info already present")
|
|
;
|
|
Inst0 = bound(Uniq, BoundInsts0),
|
|
apply_type_subst(Type0, Subst, Type),
|
|
propagate_ctor_info_2(ModuleInfo, Type, BoundInsts0, BoundInsts),
|
|
(
|
|
BoundInsts = [],
|
|
Inst = not_reached
|
|
;
|
|
BoundInsts = [_ | _],
|
|
% XXX Do we need to sort the BoundInsts?
|
|
Inst = bound(Uniq, BoundInsts)
|
|
)
|
|
;
|
|
Inst0 = ground(Uniq, none),
|
|
apply_type_subst(Type0, Subst, Type),
|
|
( type_is_higher_order(Type, _Purity, function, _, ArgTypes) ->
|
|
default_higher_order_func_inst(ModuleInfo, ArgTypes,
|
|
HigherOrderInstInfo),
|
|
Inst = ground(Uniq, higher_order(HigherOrderInstInfo))
|
|
;
|
|
% XXX The information added by this is not yet used, so it's
|
|
% disabled since it unnecessarily complicates the insts.
|
|
%
|
|
% Inst = defined_inst(typed_ground(Uniq, Type))
|
|
Inst = ground(Uniq, none)
|
|
)
|
|
;
|
|
Inst0 = ground(Uniq, higher_order(PredInstInfo0)),
|
|
PredInstInfo0 = pred_inst_info(PredOrFunc, Modes0, Det),
|
|
apply_type_subst(Type0, Subst, Type),
|
|
(
|
|
type_is_higher_order(Type, _Purity, PredOrFunc, _, ArgTypes),
|
|
list__same_length(ArgTypes, Modes0)
|
|
->
|
|
propagate_types_into_mode_list(ModuleInfo, ArgTypes, Modes0, Modes)
|
|
;
|
|
% The inst is not a valid inst for the type, so leave it alone.
|
|
% This can only happen if the user has made a mistake. A mode error
|
|
% should hopefully be reported if anything tries to match with the
|
|
% inst.
|
|
Modes = Modes0
|
|
),
|
|
PredInstInfo = pred_inst_info(PredOrFunc, Modes, Det),
|
|
Inst = ground(Uniq, higher_order(PredInstInfo))
|
|
;
|
|
Inst0 = not_reached,
|
|
Inst = Inst0
|
|
;
|
|
Inst0 = inst_var(_),
|
|
Inst = Inst0
|
|
;
|
|
Inst0 = constrained_inst_vars(V, SubInst0),
|
|
propagate_ctor_info_lazily(ModuleInfo, Subst, Type0,
|
|
SubInst0, SubInst),
|
|
Inst = constrained_inst_vars(V, SubInst)
|
|
;
|
|
Inst0 = abstract_inst(_Name, _Args),
|
|
Inst = Inst0 % XXX loses info
|
|
;
|
|
Inst0 = defined_inst(InstName0),
|
|
apply_type_subst(Type0, Subst, Type),
|
|
( InstName0 = typed_inst(_, _) ->
|
|
% If this happens, it means that we have already lazily propagated
|
|
% type info into this inst. We want to avoid creating insts of
|
|
% the form typed_inst(_, typed_inst(...)), because that would be
|
|
% unnecessary, and could cause efficiency problems or perhaps
|
|
% even infinite loops.
|
|
InstName = InstName0
|
|
;
|
|
InstName = typed_inst(Type, InstName0)
|
|
),
|
|
Inst = defined_inst(InstName)
|
|
).
|
|
|
|
%
|
|
% If the user does not explicitly specify a higher-order inst
|
|
% for a higher-order function type, it defaults to
|
|
% `func(in, in, ..., in) = out is det',
|
|
% i.e. all args input, return value output, and det.
|
|
% This applies recursively to the arguments and return
|
|
% value too.
|
|
%
|
|
:- pred default_higher_order_func_inst(module_info::in, list(type)::in,
|
|
pred_inst_info::out) is det.
|
|
|
|
default_higher_order_func_inst(ModuleInfo, PredArgTypes, PredInstInfo) :-
|
|
In = (ground(shared, none) -> ground(shared, none)),
|
|
Out = (free -> ground(shared, none)),
|
|
list__length(PredArgTypes, NumPredArgs),
|
|
NumFuncArgs = NumPredArgs - 1,
|
|
list__duplicate(NumFuncArgs, In, FuncArgModes),
|
|
FuncRetMode = Out,
|
|
list__append(FuncArgModes, [FuncRetMode], PredArgModes0),
|
|
propagate_types_into_mode_list(ModuleInfo, PredArgTypes,
|
|
PredArgModes0, PredArgModes),
|
|
PredInstInfo = pred_inst_info(function, PredArgModes, det).
|
|
|
|
constructors_to_bound_insts(ModuleInfo, Uniq, Constructors, BoundInsts) :-
|
|
constructors_to_bound_insts_2(ModuleInfo, Uniq,
|
|
Constructors, ground(Uniq, none), BoundInsts).
|
|
|
|
constructors_to_bound_any_insts(ModuleInfo, Uniq, Constructors, BoundInsts) :-
|
|
constructors_to_bound_insts_2(ModuleInfo, Uniq,
|
|
Constructors, any(Uniq), BoundInsts).
|
|
|
|
:- pred constructors_to_bound_insts_2(module_info::in, uniqueness::in,
|
|
list(constructor)::in, (inst)::in, list(bound_inst)::out) is det.
|
|
|
|
constructors_to_bound_insts_2(_, _, [], _, []).
|
|
constructors_to_bound_insts_2(ModuleInfo, Uniq, [Ctor | Ctors], ArgInst,
|
|
[BoundInst | BoundInsts]) :-
|
|
Ctor = ctor(_ExistQVars, _Constraints, Name, Args),
|
|
ctor_arg_list_to_inst_list(Args, ArgInst, Insts),
|
|
list__length(Insts, Arity),
|
|
BoundInst = functor(cons(Name, Arity), Insts),
|
|
constructors_to_bound_insts_2(ModuleInfo, Uniq, Ctors, ArgInst, BoundInsts).
|
|
|
|
:- pred ctor_arg_list_to_inst_list(list(constructor_arg)::in, (inst)::in,
|
|
list(inst)::out) is det.
|
|
|
|
ctor_arg_list_to_inst_list([], _, []).
|
|
ctor_arg_list_to_inst_list([_Name - _Type | Args], Inst, [Inst | Insts]) :-
|
|
ctor_arg_list_to_inst_list(Args, Inst, Insts).
|
|
|
|
:- pred propagate_ctor_info_2(module_info::in, (type)::in,
|
|
list(bound_inst)::in, list(bound_inst)::out) is det.
|
|
|
|
propagate_ctor_info_2(ModuleInfo, Type, BoundInsts0, BoundInsts) :-
|
|
(
|
|
type_is_tuple(Type, TupleArgTypes)
|
|
->
|
|
list__map(propagate_ctor_info_tuple(ModuleInfo, TupleArgTypes),
|
|
BoundInsts0, BoundInsts)
|
|
;
|
|
type_to_ctor_and_args(Type, TypeCtor, TypeArgs),
|
|
TypeCtor = qualified(TypeModule, _) - _,
|
|
module_info_get_type_table(ModuleInfo, TypeTable),
|
|
map__search(TypeTable, TypeCtor, TypeDefn),
|
|
hlds_data__get_type_defn_tparams(TypeDefn, TypeParams),
|
|
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
|
|
Constructors = TypeBody ^ du_type_ctors
|
|
->
|
|
map__from_corresponding_lists(TypeParams, TypeArgs, ArgSubst),
|
|
propagate_ctor_info_3(ModuleInfo, ArgSubst, TypeModule, Constructors,
|
|
BoundInsts0, BoundInsts1),
|
|
list__sort(BoundInsts1, BoundInsts)
|
|
;
|
|
% Builtin types don't need processing.
|
|
BoundInsts = BoundInsts0
|
|
).
|
|
|
|
:- pred propagate_ctor_info_tuple(module_info::in, list(type)::in,
|
|
bound_inst::in, bound_inst::out) is det.
|
|
|
|
propagate_ctor_info_tuple(ModuleInfo, TupleArgTypes, BoundInst0, BoundInst) :-
|
|
BoundInst0 = functor(Functor, ArgInsts0),
|
|
(
|
|
Functor = cons(unqualified("{}"), _),
|
|
list__length(ArgInsts0, ArgInstsLen),
|
|
list__length(TupleArgTypes, TupleArgTypesLen),
|
|
ArgInstsLen = TupleArgTypesLen
|
|
->
|
|
map__init(Subst),
|
|
propagate_types_into_inst_list(ModuleInfo, Subst, TupleArgTypes,
|
|
ArgInsts0, ArgInsts)
|
|
;
|
|
% The bound_inst's arity does not match the
|
|
% tuple's arity, so leave it alone. This can
|
|
% only happen in a user defined bound_inst.
|
|
% A mode error should be reported if anything
|
|
% tries to match with the inst.
|
|
ArgInsts = ArgInsts0
|
|
),
|
|
BoundInst = functor(Functor, ArgInsts).
|
|
|
|
:- pred propagate_ctor_info_3(module_info::in, tsubst::in,
|
|
module_name::in, list(constructor)::in,
|
|
list(bound_inst)::in, list(bound_inst)::out) is det.
|
|
|
|
propagate_ctor_info_3(_, _, _, _, [], []).
|
|
propagate_ctor_info_3(ModuleInfo, Subst, TypeModule, Constructors,
|
|
[BoundInst0 | BoundInsts0], [BoundInst | BoundInsts]) :-
|
|
BoundInst0 = functor(ConsId0, ArgInsts0),
|
|
( ConsId0 = cons(unqualified(Name), Ar) ->
|
|
ConsId = cons(qualified(TypeModule, Name), Ar)
|
|
;
|
|
ConsId = ConsId0
|
|
),
|
|
(
|
|
ConsId = cons(ConsName, Arity),
|
|
GetCons = (pred(Ctor::in) is semidet :-
|
|
Ctor = ctor(_, _, ConsName, CtorArgs),
|
|
list__length(CtorArgs, Arity)
|
|
),
|
|
list__filter(GetCons, Constructors, [Constructor])
|
|
->
|
|
Constructor = ctor(_ExistQVars, _Constraints, _Name, Args),
|
|
GetArgTypes = (pred(CtorArg::in, ArgType::out) is det :-
|
|
CtorArg = _ArgName - ArgType
|
|
),
|
|
list__map(GetArgTypes, Args, ArgTypes),
|
|
propagate_types_into_inst_list(ModuleInfo, Subst, ArgTypes,
|
|
ArgInsts0, ArgInsts),
|
|
BoundInst = functor(ConsId, ArgInsts)
|
|
;
|
|
% The cons_id is not a valid constructor for the type,
|
|
% so leave it alone. This can only happen in a user defined
|
|
% bound_inst. A mode error should be reported if anything
|
|
% tries to match with the inst.
|
|
BoundInst = functor(ConsId, ArgInsts0)
|
|
),
|
|
propagate_ctor_info_3(ModuleInfo, Subst, TypeModule,
|
|
Constructors, BoundInsts0, BoundInsts).
|
|
|
|
:- pred apply_type_subst((type)::in, tsubst::in, (type)::out) is det.
|
|
|
|
apply_type_subst(Type0, Subst, Type) :-
|
|
% optimize common case
|
|
( map__is_empty(Subst) ->
|
|
Type = Type0
|
|
;
|
|
apply_subst_to_type(Subst, Type0, Type)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred inst_lookup_subst_args(hlds_inst_body::in, list(inst_var)::in,
|
|
sym_name::in, list(inst)::in, (inst)::out) is det.
|
|
|
|
inst_lookup_subst_args(eqv_inst(Inst0), Params, _Name, Args, Inst) :-
|
|
inst_substitute_arg_list(Inst0, Params, Args, Inst).
|
|
inst_lookup_subst_args(abstract_inst, _Params, Name, Args,
|
|
abstract_inst(Name, Args)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% mode_get_insts returns the initial instantiatedness and
|
|
% the final instantiatedness for a given mode.
|
|
%
|
|
mode_get_insts_semidet(_ModuleInfo, (InitialInst -> FinalInst),
|
|
InitialInst, FinalInst).
|
|
mode_get_insts_semidet(ModuleInfo, user_defined_mode(Name, Args),
|
|
Initial, Final) :-
|
|
list__length(Args, Arity),
|
|
module_info_get_mode_table(ModuleInfo, Modes),
|
|
mode_table_get_mode_defns(Modes, ModeDefns),
|
|
map__search(ModeDefns, Name - Arity, HLDS_Mode),
|
|
HLDS_Mode = hlds_mode_defn(_VarSet, Params, ModeDefn, _Context, _Status),
|
|
ModeDefn = eqv_mode(Mode0),
|
|
mode_substitute_arg_list(Mode0, Params, Args, Mode),
|
|
mode_get_insts_semidet(ModuleInfo, Mode, Initial, Final).
|
|
|
|
mode_get_insts(ModuleInfo, Mode, InstA, InstB) :-
|
|
( mode_get_insts_semidet(ModuleInfo, Mode, InstA0, InstB0) ->
|
|
InstA = InstA0,
|
|
InstB = InstB0
|
|
;
|
|
unexpected(this_file, "mode_get_insts_semidet failed")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Use the instmap deltas for all the atomic sub-goals to recompute
|
|
% the instmap deltas for all the non-atomic sub-goals of a goal.
|
|
% Used to ensure that the instmap deltas remain valid after
|
|
% code has been re-arranged, e.g. by followcode.
|
|
% After common.m has been run, it may be necessary to recompute
|
|
% instmap deltas for atomic goals, since more outputs of calls
|
|
% and deconstructions may become non-local (XXX does this require
|
|
% rerunning mode analysis rather than just recompute_instmap_delta?).
|
|
%
|
|
recompute_instmap_delta_proc(RecomputeAtomic, !ProcInfo, !ModuleInfo) :-
|
|
proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap0),
|
|
proc_info_vartypes(!.ProcInfo, VarTypes),
|
|
proc_info_goal(!.ProcInfo, Goal0),
|
|
proc_info_inst_varset(!.ProcInfo, InstVarSet),
|
|
recompute_instmap_delta(RecomputeAtomic, Goal0, Goal,
|
|
VarTypes, InstVarSet, InstMap0, !ModuleInfo),
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
recompute_instmap_delta(RecomputeAtomic, Goal0, Goal, VarTypes, InstVarSet,
|
|
InstMap0, ModuleInfo0, ModuleInfo) :-
|
|
RI0 = recompute_info(ModuleInfo0, InstVarSet),
|
|
recompute_instmap_delta_1(RecomputeAtomic, Goal0, Goal, VarTypes,
|
|
InstMap0, _, RI0, RI),
|
|
ModuleInfo = RI ^ module_info.
|
|
|
|
:- pred recompute_instmap_delta_1(bool::in, hlds_goal::in, hlds_goal::out,
|
|
vartypes::in, instmap::in, instmap_delta::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_1(RecomputeAtomic, Goal0 - GoalInfo0, Goal - GoalInfo,
|
|
VarTypes, InstMap0, InstMapDelta, !RI) :-
|
|
(
|
|
RecomputeAtomic = no,
|
|
goal_is_atomic(Goal0),
|
|
Goal0 \= unify(_, lambda_goal(_,_,_,_,_,_,_,_,_), _, _, _)
|
|
% Lambda expressions always need to be processed.
|
|
->
|
|
Goal = Goal0,
|
|
GoalInfo1 = GoalInfo0
|
|
;
|
|
recompute_instmap_delta_2(RecomputeAtomic, Goal0, GoalInfo0,
|
|
Goal, VarTypes, InstMap0, InstMapDelta0, !RI),
|
|
goal_info_get_nonlocals(GoalInfo0, NonLocals),
|
|
instmap_delta_restrict(NonLocals, InstMapDelta0, InstMapDelta1),
|
|
goal_info_set_instmap_delta(InstMapDelta1, GoalInfo0, GoalInfo1)
|
|
),
|
|
|
|
% If the initial instmap is unreachable so is the final instmap.
|
|
( instmap__is_unreachable(InstMap0) ->
|
|
instmap_delta_init_unreachable(UnreachableInstMapDelta),
|
|
goal_info_set_instmap_delta(UnreachableInstMapDelta,
|
|
GoalInfo1, GoalInfo)
|
|
;
|
|
GoalInfo = GoalInfo1
|
|
),
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta).
|
|
|
|
:- type recompute_info
|
|
---> recompute_info(
|
|
module_info :: module_info,
|
|
inst_varset :: inst_varset
|
|
).
|
|
|
|
% update_module_info(P, R, RI0, RI) will call predicate P, passing it
|
|
% the module_info from RI0 and placing the output module_info in RI.
|
|
% The output of P's first argument is returned in R.
|
|
%
|
|
:- pred update_module_info(
|
|
pred(T, module_info, module_info)::in(pred(out, in, out) is det),
|
|
T::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
update_module_info(P, R, !RI) :-
|
|
ModuleInfo0 = !.RI ^ module_info,
|
|
P(R, ModuleInfo0, ModuleInfo),
|
|
!:RI = !.RI ^ module_info := ModuleInfo.
|
|
|
|
:- pred recompute_instmap_delta_2(bool::in, hlds_goal_expr::in,
|
|
hlds_goal_info::in, hlds_goal_expr::out, vartypes::in, instmap::in,
|
|
instmap_delta::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_2(Atomic, switch(Var, Det, Cases0), GoalInfo,
|
|
switch(Var, Det, Cases), VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
( goal_info_has_feature(GoalInfo, mode_check_clauses_goal) ->
|
|
Cases = Cases0,
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta)
|
|
;
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
recompute_instmap_delta_cases(Atomic, Var, Cases0, Cases,
|
|
VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
|
|
).
|
|
|
|
recompute_instmap_delta_2(Atomic, conj(Goals0), _, conj(Goals),
|
|
VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_conj(Atomic, Goals0, Goals,
|
|
VarTypes, InstMap, InstMapDelta, !RI).
|
|
|
|
recompute_instmap_delta_2(Atomic, par_conj(Goals0), GoalInfo,
|
|
par_conj(Goals), VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
|
|
VarTypes, InstMap, NonLocals, InstMapDelta, !RI).
|
|
|
|
recompute_instmap_delta_2(Atomic, disj(Goals0), GoalInfo, disj(Goals),
|
|
VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
( goal_info_has_feature(GoalInfo, mode_check_clauses_goal) ->
|
|
Goals = Goals0,
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta)
|
|
;
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
recompute_instmap_delta_disj(Atomic, Goals0, Goals,
|
|
VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
|
|
).
|
|
|
|
recompute_instmap_delta_2(Atomic, not(Goal0), _, not(Goal),
|
|
VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
instmap_delta_init_reachable(InstMapDelta),
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap, _,
|
|
!RI).
|
|
|
|
recompute_instmap_delta_2(Atomic, if_then_else(Vars, Cond0, Then0, Else0),
|
|
GoalInfo, if_then_else(Vars, Cond, Then, Else), VarTypes,
|
|
InstMap0, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_1(Atomic, Cond0, Cond, VarTypes, InstMap0,
|
|
InstMapDeltaCond, !RI),
|
|
instmap__apply_instmap_delta(InstMap0, InstMapDeltaCond, InstMapCond),
|
|
recompute_instmap_delta_1(Atomic, Then0, Then, VarTypes, InstMapCond,
|
|
InstMapDeltaThen, !RI),
|
|
recompute_instmap_delta_1(Atomic, Else0, Else, VarTypes, InstMap0,
|
|
InstMapDeltaElse, !RI),
|
|
instmap_delta_apply_instmap_delta(InstMapDeltaCond, InstMapDeltaThen,
|
|
test_size, InstMapDeltaCondThen),
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
update_module_info(
|
|
merge_instmap_delta(InstMap0, NonLocals,
|
|
VarTypes, InstMapDeltaElse, InstMapDeltaCondThen),
|
|
InstMapDelta, !RI).
|
|
|
|
recompute_instmap_delta_2(Atomic, scope(Reason, Goal0), _,
|
|
scope(Reason, Goal), VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap,
|
|
InstMapDelta, !RI).
|
|
|
|
recompute_instmap_delta_2(_, generic_call(Details, Vars, Modes, Detism), _,
|
|
generic_call(Details, Vars, Modes, Detism),
|
|
_VarTypes, _InstMap, InstMapDelta, !RI) :-
|
|
ModuleInfo = !.RI ^ module_info,
|
|
instmap_delta_from_mode_list(Vars, Modes, ModuleInfo, InstMapDelta).
|
|
|
|
recompute_instmap_delta_2(_, call(PredId, ProcId, Args, D, E, F), _,
|
|
call(PredId, ProcId, Args, D, E, F), VarTypes,
|
|
InstMap, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_call(PredId, ProcId,
|
|
Args, VarTypes, InstMap, InstMapDelta, !RI).
|
|
|
|
recompute_instmap_delta_2(Atomic, unify(LHS, RHS0, UniMode0, Uni, Context),
|
|
GoalInfo, unify(LHS, RHS, UniMode, Uni, Context), VarTypes,
|
|
InstMap0, InstMapDelta, !RI) :-
|
|
(
|
|
RHS0 = lambda_goal(Purity, PorF, EvalMethod, FixModes,
|
|
NonLocals, LambdaVars, Modes, Det, Goal0)
|
|
->
|
|
ModuleInfo0 = !.RI ^ module_info,
|
|
instmap__pre_lambda_update(ModuleInfo0, LambdaVars, Modes,
|
|
InstMap0, InstMap),
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes,
|
|
InstMap, _, !RI),
|
|
RHS = lambda_goal(Purity, PorF, EvalMethod, FixModes,
|
|
NonLocals, LambdaVars, Modes, Det, Goal)
|
|
;
|
|
RHS = RHS0
|
|
),
|
|
(
|
|
Atomic = yes,
|
|
recompute_instmap_delta_unify(Uni, UniMode0, UniMode,
|
|
GoalInfo, InstMap0, InstMapDelta, !.RI)
|
|
;
|
|
Atomic = no,
|
|
UniMode = UniMode0,
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta)
|
|
).
|
|
|
|
recompute_instmap_delta_2(_,
|
|
foreign_proc(A, PredId, ProcId, Args, ExtraArgs, F), GoalInfo,
|
|
foreign_proc(A, PredId, ProcId, Args, ExtraArgs, F),
|
|
VarTypes, InstMap, InstMapDelta, !RI) :-
|
|
ArgVars = list__map(foreign_arg_var, Args),
|
|
recompute_instmap_delta_call(PredId, ProcId,
|
|
ArgVars, VarTypes, InstMap, InstMapDelta0, !RI),
|
|
(
|
|
ExtraArgs = [],
|
|
InstMapDelta = InstMapDelta0
|
|
;
|
|
ExtraArgs = [_ | _],
|
|
goal_info_get_instmap_delta(GoalInfo, OldInstMapDelta),
|
|
ExtraArgVars = list__map(foreign_arg_var, ExtraArgs),
|
|
instmap_delta_restrict(set__list_to_set(ExtraArgVars),
|
|
OldInstMapDelta, ExtraArgsInstMapDelta),
|
|
instmap_delta_apply_instmap_delta(InstMapDelta0,
|
|
ExtraArgsInstMapDelta, large_base, InstMapDelta)
|
|
).
|
|
|
|
recompute_instmap_delta_2(_, shorthand(_), _, _, _, _, _, !RI) :-
|
|
% these should have been expanded out by now
|
|
unexpected(this_file,
|
|
"recompute_instmap_delta_2: unexpected shorthand").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred recompute_instmap_delta_conj(bool::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, vartypes::in, instmap::in, instmap_delta::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_conj(_, [], [], _, _, InstMapDelta, !RI) :-
|
|
instmap_delta_init_reachable(InstMapDelta).
|
|
recompute_instmap_delta_conj(Atomic, [Goal0 | Goals0], [Goal | Goals],
|
|
VarTypes, InstMap0, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap0,
|
|
InstMapDelta0, !RI),
|
|
instmap__apply_instmap_delta(InstMap0, InstMapDelta0, InstMap1),
|
|
recompute_instmap_delta_conj(Atomic, Goals0, Goals, VarTypes, InstMap1,
|
|
InstMapDelta1, !RI),
|
|
instmap_delta_apply_instmap_delta(InstMapDelta0, InstMapDelta1,
|
|
large_overlay, InstMapDelta).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred recompute_instmap_delta_par_conj(bool::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, vartypes::in, instmap::in, set(prog_var)::in,
|
|
instmap_delta::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_par_conj(_, [], [], _, _, _, InstMapDelta, !RI) :-
|
|
instmap_delta_init_unreachable(InstMapDelta).
|
|
recompute_instmap_delta_par_conj(Atomic, [Goal0], [Goal],
|
|
VarTypes, InstMap, _, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap,
|
|
InstMapDelta, !RI).
|
|
recompute_instmap_delta_par_conj(Atomic, [Goal0 | Goals0], [Goal | Goals],
|
|
VarTypes, InstMap, NonLocals, InstMapDelta, !RI) :-
|
|
Goals0 = [_ | _],
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal,
|
|
VarTypes, InstMap, InstMapDelta0, !RI),
|
|
recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
|
|
VarTypes, InstMap, NonLocals, InstMapDelta1, !RI),
|
|
update_module_info(unify_instmap_delta(InstMap, NonLocals,
|
|
InstMapDelta0, InstMapDelta1), InstMapDelta, !RI).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred recompute_instmap_delta_disj(bool::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, vartypes::in, instmap::in, set(prog_var)::in,
|
|
instmap_delta::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_disj(Atomic, Goals0, Goals, VarTypes, InstMap,
|
|
NonLocals, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_disj_2(Atomic, Goals0, Goals, VarTypes, InstMap,
|
|
NonLocals, InstMapDeltas, !RI),
|
|
(
|
|
InstMapDeltas = [],
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
;
|
|
InstMapDeltas = [_ | _],
|
|
update_module_info(
|
|
merge_instmap_deltas(InstMap, NonLocals, VarTypes, InstMapDeltas),
|
|
InstMapDelta, !RI)
|
|
).
|
|
|
|
:- pred recompute_instmap_delta_disj_2(bool::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out, vartypes::in, instmap::in, set(prog_var)::in,
|
|
list(instmap_delta)::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_disj_2(_Atomic, [], [],
|
|
_VarTypes, _InstMap, _NonLocals, [], !RI).
|
|
recompute_instmap_delta_disj_2(Atomic, [Goal0 | Goals0], [Goal | Goals],
|
|
VarTypes, InstMap, NonLocals, [InstMapDelta | InstMapDeltas], !RI) :-
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal,
|
|
VarTypes, InstMap, InstMapDelta, !RI),
|
|
recompute_instmap_delta_disj_2(Atomic, Goals0, Goals,
|
|
VarTypes, InstMap, NonLocals, InstMapDeltas, !RI).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred recompute_instmap_delta_cases(bool::in, prog_var::in, list(case)::in,
|
|
list(case)::out, vartypes::in, instmap::in, set(prog_var)::in,
|
|
instmap_delta::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_cases(Atomic, Var, Cases0, Cases, VarTypes,
|
|
InstMap0, NonLocals, InstMapDelta, !RI) :-
|
|
recompute_instmap_delta_cases_2(Atomic, Var, Cases0, Cases, VarTypes,
|
|
InstMap0, NonLocals, InstMapDeltas, !RI),
|
|
(
|
|
InstMapDeltas = [],
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
;
|
|
InstMapDeltas = [_ | _],
|
|
update_module_info(
|
|
merge_instmap_deltas(InstMap0, NonLocals, VarTypes, InstMapDeltas),
|
|
InstMapDelta, !RI)
|
|
).
|
|
|
|
:- pred recompute_instmap_delta_cases_2(bool::in, prog_var::in, list(case)::in,
|
|
list(case)::out, vartypes::in, instmap::in, set(prog_var)::in,
|
|
list(instmap_delta)::out, recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_cases_2(_Atomic, _Var, [], [],
|
|
_VarTypes, _InstMap, _NonLocals, [], !RI).
|
|
recompute_instmap_delta_cases_2(Atomic, Var, [Case0 | Cases0], [Case | Cases],
|
|
VarTypes, InstMap0, NonLocals, [InstMapDelta | InstMapDeltas], !RI) :-
|
|
Case0 = case(Functor, Goal0),
|
|
map__lookup(VarTypes, Var, Type),
|
|
update_module_info(instmap__bind_var_to_functor(Var, Type, Functor,
|
|
InstMap0), InstMap1, !RI),
|
|
recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap1,
|
|
InstMapDelta0, !RI),
|
|
update_module_info(instmap_delta_bind_var_to_functor(Var, Type,
|
|
Functor, InstMap0, InstMapDelta0), InstMapDelta, !RI),
|
|
Case = case(Functor, Goal),
|
|
recompute_instmap_delta_cases_2(Atomic, Var, Cases0, Cases,
|
|
VarTypes, InstMap0, NonLocals, InstMapDeltas, !RI).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred recompute_instmap_delta_call(pred_id::in, proc_id::in,
|
|
list(prog_var)::in, vartypes::in, instmap::in, instmap_delta::out,
|
|
recompute_info::in, recompute_info::out) is det.
|
|
|
|
recompute_instmap_delta_call(PredId, ProcId, Args, VarTypes, InstMap,
|
|
InstMapDelta, !RI) :-
|
|
ModuleInfo = !.RI ^ module_info,
|
|
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
|
|
proc_info_interface_determinism(ProcInfo, Detism),
|
|
( determinism_components(Detism, _, at_most_zero) ->
|
|
instmap_delta_init_unreachable(InstMapDelta)
|
|
;
|
|
proc_info_argmodes(ProcInfo, ArgModes0),
|
|
proc_info_inst_varset(ProcInfo, ProcInstVarSet),
|
|
InstVarSet = !.RI ^ inst_varset,
|
|
rename_apart_inst_vars(InstVarSet, ProcInstVarSet,
|
|
ArgModes0, ArgModes1),
|
|
mode_list_get_initial_insts(ModuleInfo, ArgModes1, InitialInsts),
|
|
|
|
% Compute the inst_var substitution from the initial insts
|
|
% of the called procedure and the insts of the argument variables.
|
|
map__init(InstVarSub0),
|
|
update_module_info(compute_inst_var_sub(Args, VarTypes, InstMap,
|
|
InitialInsts, InstVarSub0), InstVarSub, !RI),
|
|
|
|
% Apply the inst_var substitution to the argument modes.
|
|
mode_list_apply_substitution(ArgModes1, InstVarSub, ArgModes2),
|
|
|
|
% Calculate the final insts of the argument variables from their
|
|
% initial insts and the final insts of the called procedure
|
|
% (with inst_var substitutions applied).
|
|
update_module_info(
|
|
recompute_instmap_delta_call_2(Args, InstMap, ArgModes2),
|
|
ArgModes, !RI),
|
|
instmap_delta_from_mode_list(Args, ArgModes, ModuleInfo, InstMapDelta)
|
|
).
|
|
|
|
:- pred compute_inst_var_sub(list(prog_var)::in, vartypes::in, instmap::in,
|
|
list(inst)::in, inst_var_sub::in, inst_var_sub::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
compute_inst_var_sub([], _, _, [], !Sub, !ModuleInfo).
|
|
compute_inst_var_sub([_ | _], _, _, [], !Sub, !ModuleInfo) :-
|
|
unexpected(this_file, "compute_inst_var_sub").
|
|
compute_inst_var_sub([], _, _, [_ | _], !Sub, !ModuleInfo) :-
|
|
unexpected(this_file, "compute_inst_var_sub").
|
|
compute_inst_var_sub([Arg | Args], VarTypes, InstMap, [Inst | Insts],
|
|
!Sub, !ModuleInfo) :-
|
|
% This is similar to modecheck_var_has_inst.
|
|
SaveModuleInfo = !.ModuleInfo,
|
|
SaveSub = !.Sub,
|
|
( instmap__is_reachable(InstMap) ->
|
|
instmap__lookup_var(InstMap, Arg, ArgInst),
|
|
map__lookup(VarTypes, Arg, Type),
|
|
( inst_matches_initial(ArgInst, Inst, Type, !ModuleInfo, !Sub) ->
|
|
true
|
|
;
|
|
% error("compute_inst_var_sub: " ++
|
|
% ++ "inst_matches_initial failed")
|
|
% XXX We shouldn't ever get here, but unfortunately
|
|
% the mode system currently has several problems (most
|
|
% noticeably lack of alias tracking for unique modes)
|
|
% which mean inst_matches_initial can sometimes fail
|
|
% here.
|
|
!:ModuleInfo = SaveModuleInfo,
|
|
!:Sub = SaveSub
|
|
)
|
|
;
|
|
true
|
|
),
|
|
compute_inst_var_sub(Args, VarTypes, InstMap, Insts, !Sub, !ModuleInfo).
|
|
|
|
:- pred recompute_instmap_delta_call_2(list(prog_var)::in, instmap::in,
|
|
list(mode)::in, list(mode)::out, module_info::in, module_info::out)
|
|
is det.
|
|
|
|
recompute_instmap_delta_call_2([], _, [], [], !ModuleInfo).
|
|
recompute_instmap_delta_call_2([_ | _], _, [], _, !ModuleInfo) :-
|
|
unexpected(this_file, "recompute_instmap_delta_call_2").
|
|
recompute_instmap_delta_call_2([], _, [_ | _], _, !ModuleInfo) :-
|
|
unexpected(this_file, "recompute_instmap_delta_call_2").
|
|
recompute_instmap_delta_call_2([Arg | Args], InstMap, [Mode0 | Modes0],
|
|
[Mode | Modes], !ModuleInfo) :-
|
|
% This is similar to modecheck_set_var_inst.
|
|
( instmap__is_reachable(InstMap) ->
|
|
instmap__lookup_var(InstMap, Arg, ArgInst0),
|
|
mode_get_insts(!.ModuleInfo, Mode0, _, FinalInst),
|
|
(
|
|
abstractly_unify_inst(dead, ArgInst0, FinalInst,
|
|
fake_unify, UnifyInst, _, !ModuleInfo)
|
|
->
|
|
Mode = (ArgInst0 -> UnifyInst)
|
|
;
|
|
unexpected(this_file,
|
|
"recompute_instmap_delta_call_2: unify_inst failed")
|
|
)
|
|
;
|
|
Mode = (not_reached -> not_reached)
|
|
),
|
|
recompute_instmap_delta_call_2(Args, InstMap, Modes0, Modes,
|
|
!ModuleInfo).
|
|
|
|
:- pred recompute_instmap_delta_unify(unification::in, unify_mode::in,
|
|
unify_mode::out, hlds_goal_info::in, instmap::in, instmap_delta::out,
|
|
recompute_info::in) is det.
|
|
|
|
recompute_instmap_delta_unify(Uni, UniMode0, UniMode, GoalInfo,
|
|
InstMap, InstMapDelta, RI) :-
|
|
% Deconstructions are the only types of unifications that can require
|
|
% updating of the instmap_delta after simplify.m has been run.
|
|
ModuleInfo = RI ^ module_info,
|
|
(
|
|
Uni = deconstruct(Var, _ConsId, Vars, UniModes, _, _CanCGC)
|
|
->
|
|
% Get the final inst of the deconstructed var, which will be the same
|
|
% as in the old instmap.
|
|
%
|
|
goal_info_get_instmap_delta(GoalInfo, OldInstMapDelta),
|
|
instmap__lookup_var(InstMap, Var, InitialInst),
|
|
( instmap_delta_search_var(OldInstMapDelta, Var, FinalInst1) ->
|
|
% XXX we need to merge the information in InitialInst
|
|
% and FinalInst1. In puzzle_detism_bug, InitialInst
|
|
% has a var bound to one function symbol (james), while
|
|
% FinalInst1 has it bound to another (katherine).
|
|
% The correct final inst is thus `unreachable', but
|
|
% we don't return that.
|
|
FinalInst = FinalInst1
|
|
;
|
|
% It wasn't in the instmap_delta, so the inst didn't
|
|
% change.
|
|
FinalInst = InitialInst
|
|
),
|
|
UniModeToRhsMode = (pred(UMode::in, Mode::out) is det :-
|
|
UMode = ((_ - Inst0) -> (_ - Inst)),
|
|
Mode = (Inst0 -> Inst)
|
|
),
|
|
list__map(UniModeToRhsMode, UniModes, Modes),
|
|
instmap_delta_from_mode_list([Var | Vars],
|
|
[(InitialInst -> FinalInst) | Modes],
|
|
ModuleInfo, InstMapDelta),
|
|
UniMode = UniMode0
|
|
;
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
|
|
UniMode = UniMode0
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Arguments with final inst `clobbered' are dead, any
|
|
% others are assumed to be live.
|
|
%
|
|
get_arg_lives(_, [], []).
|
|
get_arg_lives(ModuleInfo, [Mode | Modes], [IsLive | IsLives]) :-
|
|
mode_get_insts(ModuleInfo, Mode, _InitialInst, FinalInst),
|
|
( inst_is_clobbered(ModuleInfo, FinalInst) ->
|
|
IsLive = dead
|
|
;
|
|
IsLive = live
|
|
),
|
|
get_arg_lives(ModuleInfo, Modes, IsLives).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
normalise_insts(_, [], [], []).
|
|
normalise_insts(_, [], [_ | _], _) :-
|
|
unexpected(this_file, "normalise_insts: length mismatch").
|
|
normalise_insts(_, [_ | _], [], _) :-
|
|
unexpected(this_file, "normalise_insts: length mismatch").
|
|
normalise_insts(ModuleInfo, [Type | Types],
|
|
[Inst0 | Insts0], [Inst | Insts]) :-
|
|
normalise_inst(ModuleInfo, Type, Inst0, Inst),
|
|
normalise_insts(ModuleInfo, Types, Insts0, Insts).
|
|
|
|
% This is a bit of a hack.
|
|
% The aim is to avoid non-termination due to the creation
|
|
% of ever-expanding insts.
|
|
% XXX should also normalise partially instantiated insts.
|
|
%
|
|
normalise_inst(ModuleInfo, Type, Inst0, NormalisedInst) :-
|
|
inst_expand(ModuleInfo, Inst0, Inst),
|
|
( Inst = bound(_, _) ->
|
|
(
|
|
inst_is_ground(ModuleInfo, Inst),
|
|
inst_is_unique(ModuleInfo, Inst),
|
|
% don't infer unique modes for introduced type_infos
|
|
% arguments, because that leads to an increase
|
|
% in the number of inferred modes without any benefit
|
|
\+ is_introduced_type_info_type(Type),
|
|
\+ inst_contains_nonstandard_func_mode(ModuleInfo, Inst)
|
|
->
|
|
NormalisedInst = ground(unique, none)
|
|
;
|
|
inst_is_ground(ModuleInfo, Inst),
|
|
inst_is_mostly_unique(ModuleInfo, Inst),
|
|
% don't infer unique modes for introduced type_infos
|
|
% arguments, because that leads to an increase
|
|
% in the number of inferred modes without any benefit
|
|
\+ is_introduced_type_info_type(Type),
|
|
\+ inst_contains_nonstandard_func_mode(ModuleInfo, Inst)
|
|
->
|
|
NormalisedInst = ground(mostly_unique, none)
|
|
;
|
|
inst_is_ground(ModuleInfo, Inst),
|
|
\+ inst_is_clobbered(ModuleInfo, Inst),
|
|
\+ inst_contains_nonstandard_func_mode(ModuleInfo, Inst)
|
|
->
|
|
NormalisedInst = ground(shared, none)
|
|
;
|
|
% XXX need to limit the potential size of insts
|
|
% here in order to avoid infinite loops in
|
|
% mode inference
|
|
NormalisedInst = Inst
|
|
)
|
|
;
|
|
NormalisedInst = Inst
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
fixup_switch_var(Var, InstMap0, InstMap, Goal0, Goal) :-
|
|
Goal0 = GoalExpr - GoalInfo0,
|
|
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta0),
|
|
instmap__lookup_var(InstMap0, Var, Inst0),
|
|
instmap__lookup_var(InstMap, Var, Inst),
|
|
( Inst = Inst0 ->
|
|
GoalInfo = GoalInfo0
|
|
;
|
|
instmap_delta_set(Var, Inst, InstMapDelta0, InstMapDelta),
|
|
goal_info_set_instmap_delta(InstMapDelta, GoalInfo0, GoalInfo)
|
|
),
|
|
Goal = GoalExpr - GoalInfo.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
partition_args(_, [], [_ | _], _, _) :-
|
|
unexpected(this_file, "partition_args").
|
|
partition_args(_, [_ | _], [], _, _) :-
|
|
unexpected(this_file, "partition_args").
|
|
partition_args(_, [], [], [], []).
|
|
partition_args(ModuleInfo, [ArgMode | ArgModes], [Arg | Args],
|
|
!:InputArgs, !:OutputArgs) :-
|
|
partition_args(ModuleInfo, ArgModes, Args, !:InputArgs, !:OutputArgs),
|
|
( mode_is_input(ModuleInfo, ArgMode) ->
|
|
!:InputArgs = [Arg | !.InputArgs]
|
|
;
|
|
!:OutputArgs = [Arg | !.OutputArgs]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "mode_util.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|