[m-dev.] for review: `possible' alias analysis stage
Nancy MAZUR
nancy at cs.mu.OZ.AU
Mon Feb 21 17:03:55 AEDT 2000
Hi,
here's the code.
waiting to be shot (can I be blindfolded, please?),
Nancy
===================================================================
estimated hours taken: 100
Added `possible' alias analysis stage (before unique modes analysis).
(definition: possible alias, as opposed to definite aliasing,
expresses whether two datastructures might be (partially) aliased
to one another at run-time.)
To switch analysis on: --infer-possible-aliases
To dump alias-information into the dump-hlds: --dump-hlds-options kulalias
(or --dump-hlds-options k )
The analysis considers only first order code, works on an
intermodular basis (i.e. generates and loads interface-files,
which I gave the extension "opt.ka"), and at this moment fails
on everything that cannot be handled:
- higher-order calls / typeclasses
- special calls (c-code, .. )
- calls to predicates of a module for which no interface-file
has been loaded (i.e. no non-local alias information available).
Near-future changes:
- instead of failing, handle special calls appropriately and
proceed (i.e. introduce `top' as abstract substitution);
- calls to predicates handling builtin-types could be
shortcutted in the sense that aliases cannot be created.
- abstract representations of the aliases are normalized
after each analysis of a procedure. This normalization
is now based solely on the type-information (and thus
tails of lists are mapped to lists), and ought to be
extended to take into account the instmaps of the variables
concerned.
Less near future changes:
- higher-order?
- abstract data-types?
===
compiler/handle_options.m
compiler/hlds_out.m
added option/handler to print alias information in hlds_dumps
(`kulalias' or `k')
compiler/options.m
compiler/mercury_compile.m
added option/handler to switch on alias analysis
(`infer-possible-aliases')
compiler/prog_data.m
compiler/prog_io_pragma.m
compiler/module_qual.m
compiler/modules.m
compiler/mercury_to_mercury.m
compiler/make_hlds.m
added new prog_data__pragma_type constructor: ka_alias_info/5
added new pragma-declaration: ka_alias_info/3
:- pragma ka_alias_info( <small pred declaration>,
vars( <list of headvars> ),
maybe( <printed alias-information> ) ).
This pragma-declaration is not intended to be
used directly by the programmer.
compiler/hlds_pred.m:
added new field in proc_info
===
new files: (ka = KUL-alias)
compiler/ka_alias_as.m : definition of the abstract substitution and
it's primitive operations
compiler/ka_run.m : main module for effectively running the analysis pass
compiler/ka_util.m : some extra types/procedures, mainly definition of
a fixpoint table.
Index: handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.88
diff -u -r1.88 handle_options.m
--- handle_options.m 2000/01/10 05:26:18 1.88
+++ handle_options.m 2000/02/08 00:15:19
@@ -854,9 +854,11 @@
:- pred convert_dump_alias(string, string).
:- mode convert_dump_alias(in, out) is semidet.
-convert_dump_alias("ALL", "abcdfgilmnprstuvCIMPTU").
-convert_dump_alias("all", "abcdfgilmnprstuvCMPT").
+convert_dump_alias("ALL", "abcdfgiklmnprstuvCIMPTU").
+convert_dump_alias("all", "abcdfgiklmnprstuvCMPT").
convert_dump_alias("codegen", "dfnprsu").
convert_dump_alias("vanessa", "ltuCIU").
convert_dump_alias("paths", "cP").
convert_dump_alias("petdr", "din").
+convert_dump_alias("kulalias", "k").
+
Index: hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.235
diff -u -r1.235 hlds_out.m
--- hlds_out.m 2000/01/13 06:15:45 1.235
+++ hlds_out.m 2000/02/08 01:07:04
@@ -244,6 +244,7 @@
:- import_module int, string, set, assoc_list, map, multi_map.
:- import_module require, getopt, std_util, term_io, varset.
+:- import_module ka_alias_as.
hlds_out__write_type_id(Name - Arity) -->
@@ -2840,6 +2841,7 @@
{ proc_info_typeinfo_varmap(Proc, TypeInfoMap) },
{ proc_info_typeclass_info_varmap(Proc, TypeClassInfoMap) },
{ proc_info_is_address_taken(Proc, IsAddressTaken) },
+ { proc_info_possible_aliases(Proc, MaybeAliases) },
{ Indent1 is Indent + 1 },
hlds_out__write_indent(Indent1),
@@ -2866,6 +2868,19 @@
;
[]
),
+
+ (
+ { string__contains_char(Verbose, 'k') }
+ ->
+ hlds_out__write_indent(Indent),
+ io__write_string("% Possible aliases: "),
+ ka_alias_as__print_maybe_possible_aliases(MaybeAliases,
+ Proc),
+ io__nl
+ ;
+ []
+ ),
+
hlds_out__write_indent(Indent),
hlds_out__write_var_types(Indent, VarSet, AppendVarnums,
Index: hlds_pred.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.70
diff -u -r1.70 hlds_pred.m
--- hlds_pred.m 2000/01/26 02:04:24 1.70
+++ hlds_pred.m 2000/02/08 00:19:31
@@ -16,6 +16,7 @@
:- import_module hlds_data, hlds_goal, hlds_module, llds, prog_data, instmap.
:- import_module globals, term_util.
:- import_module bool, list, set, map, std_util, term, varset.
+:- import_module ka_alias_as.
:- implementation.
@@ -1488,6 +1489,13 @@
:- pred proc_info_set_rl_exprn_id(proc_info, rl_exprn_id, proc_info).
:- mode proc_info_set_rl_exprn_id(in, in, out) is det.
+:- pred proc_info_possible_aliases(proc_info, maybe(ka_alias_as__alias_as)).
+:- mode proc_info_possible_aliases(in, out) is det.
+
+:- pred proc_info_set_possible_aliases(proc_info, alias_as, proc_info).
+:- mode proc_info_set_possible_aliases(in, in, out) is det.
+
+
% For a set of variables V, find all the type variables in the types
% of the variables in V, and return set of typeinfo variables for
% those type variables. (find all typeinfos for variables in V).
@@ -1595,13 +1603,17 @@
% must be considered as having its
% address taken, since it is possible
% that some other module may do so.
- maybe(rl_exprn_id)
+ maybe(rl_exprn_id),
% For predicates with an
% `aditi_top_down' marker, which are
% executed top-down on the Aditi side
% of the connection, we generate an RL
% expression, for which this is an
% identifier. See rl_update.m.
+ maybe(alias_as)
+ % `Possible' aliases annotations per
+ % procedure. This field is set by the
+ % KUL alias analysis (module ka_run).
).
% Some parts of the procedure aren't known yet. We initialize
@@ -1627,11 +1639,12 @@
map__init(TVarsMap),
map__init(TCVarsMap),
RLExprn = no,
+ ALIAS = no,
NewProc = procedure(
MaybeDet, BodyVarSet, BodyTypes, HeadVars, Modes, MaybeArgLives,
ClauseBody, MContext, StackSlots, InferredDet, CanProcess,
ArgInfo, InitialLiveness, TVarsMap, TCVarsMap, eval_normal,
- no, no, DeclaredModes, IsAddressTaken, RLExprn
+ no, no, DeclaredModes, IsAddressTaken, RLExprn, ALIAS
).
proc_info_set(DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
@@ -1639,11 +1652,12 @@
CanProcess, ArgInfo, Liveness, TVarMap, TCVarsMap, ArgSizes,
Termination, IsAddressTaken, ProcInfo) :-
RLExprn = no,
+ ALIAS = no,
ProcInfo = procedure(
DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
HeadLives, Goal, Context, StackSlots, InferredDetism,
CanProcess, ArgInfo, Liveness, TVarMap, TCVarsMap, eval_normal,
- ArgSizes, Termination, no, IsAddressTaken, RLExprn).
+ ArgSizes, Termination, no, IsAddressTaken, RLExprn, ALIAS ).
proc_info_create(VarSet, VarTypes, HeadVars, HeadModes, Detism, Goal,
Context, TVarMap, TCVarsMap, IsAddressTaken, ProcInfo) :-
@@ -1651,17 +1665,18 @@
set__init(Liveness),
MaybeHeadLives = no,
RLExprn = no,
+ ALIAS = no,
ProcInfo = procedure(yes(Detism), VarSet, VarTypes, HeadVars, HeadModes,
MaybeHeadLives, Goal, Context, StackSlots, Detism, yes, [],
Liveness, TVarMap, TCVarsMap, eval_normal, no, no, no,
- IsAddressTaken, RLExprn).
+ IsAddressTaken, RLExprn, ALIAS).
proc_info_set_body(ProcInfo0, VarSet, VarTypes, HeadVars, Goal,
TI_VarMap, TCI_VarMap, ProcInfo) :-
ProcInfo0 = procedure(A, _, _, _, E, F, _,
- H, I, J, K, L, M, _, _, P, Q, R, S, T, U),
+ H, I, J, K, L, M, _, _, P, Q, R, S, T, U, V),
ProcInfo = procedure(A, VarSet, VarTypes, HeadVars, E, F, Goal,
- H, I, J, K, L, M, TI_VarMap, TCI_VarMap, P, Q, R, S, T, U).
+ H, I, J, K, L, M, TI_VarMap, TCI_VarMap, P, Q, R, S, T, U, V).
proc_info_interface_determinism(ProcInfo, Determinism) :-
proc_info_declared_determinism(ProcInfo, MaybeDeterminism),
@@ -1719,87 +1734,91 @@
proc_info_declared_determinism(ProcInfo, A) :-
ProcInfo = procedure(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_varset(ProcInfo, B) :-
ProcInfo = procedure(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_vartypes(ProcInfo, C) :-
ProcInfo = procedure(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_headvars(ProcInfo, D) :-
ProcInfo = procedure(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_argmodes(ProcInfo, E) :-
ProcInfo = procedure(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_maybe_arglives(ProcInfo, F) :-
ProcInfo = procedure(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_goal(ProcInfo, G) :-
ProcInfo = procedure(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_context(ProcInfo, H) :-
ProcInfo = procedure(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_stack_slots(ProcInfo, I) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_inferred_determinism(ProcInfo, J) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_can_process(ProcInfo, K) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_arg_info(ProcInfo, L) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_liveness_info(ProcInfo, M) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_typeinfo_varmap(ProcInfo, N) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_typeclass_info_varmap(ProcInfo, O) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_eval_method(ProcInfo, P) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P,
- _, _, _, _, _).
+ _, _, _, _, _, _).
proc_info_get_maybe_arg_size_info(ProcInfo, Q) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- Q, _, _, _, _).
+ Q, _, _, _, _, _).
proc_info_get_maybe_termination_info(ProcInfo, R) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, R, _, _, _).
+ _, R, _, _, _, _).
proc_info_maybe_declared_argmodes(ProcInfo, S) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, S, _, _).
+ _, _, S, _, _, _).
proc_info_is_address_taken(ProcInfo, T) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, T, _).
+ _, _, _, T, _, _).
proc_info_get_rl_exprn_id(ProcInfo, U) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+ _, _, _, _, U, _).
+
+proc_info_possible_aliases(ProcInfo, V) :-
ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
- _, _, _, _, U).
+ _, _, _, _, _, V).
% :- type proc_info
% ---> procedure(
@@ -1869,105 +1888,112 @@
proc_info_set_varset(ProcInfo0, B, ProcInfo) :-
ProcInfo0 = procedure(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_vartypes(ProcInfo0, C, ProcInfo) :-
ProcInfo0 = procedure(A, B, _, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_headvars(ProcInfo0, D, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, _, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_argmodes(ProcInfo0, E, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, _, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_maybe_arglives(ProcInfo0, F, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_goal(ProcInfo0, G, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_stack_slots(ProcInfo0, I, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_inferred_determinism(ProcInfo0, J, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_can_process(ProcInfo0, K, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, _, L, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_arg_info(ProcInfo0, L, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_liveness_info(ProcInfo0, M, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_typeinfo_varmap(ProcInfo0, N, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_typeclass_info_varmap(ProcInfo0, O, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _,
- P, Q, R, S, T, U),
+ P, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_eval_method(ProcInfo0, P, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- _, Q, R, S, T, U),
+ _, Q, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_maybe_arg_size_info(ProcInfo0, Q, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, _, R, S, T, U),
+ P, _, R, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_maybe_termination_info(ProcInfo0, R, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, _, S, T, U),
+ P, Q, _, S, T, U, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, U).
+ P, Q, R, S, T, U, V).
proc_info_set_rl_exprn_id(ProcInfo0, U, ProcInfo) :-
ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, _),
+ P, Q, R, S, T, _, V),
ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
- P, Q, R, S, T, yes(U)).
+ P, Q, R, S, T, yes(U), V).
+
+proc_info_set_possible_aliases(ProcInfo0, V, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
+ P, Q, R, S, T, U, _),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
+ P, Q, R, S, T, U, yes(V)).
+
proc_info_get_typeinfo_vars_setwise(ProcInfo, Vars, TypeInfoVars) :-
set__to_sorted_list(Vars, VarList),
Index: make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.322
diff -u -r1.322 make_hlds.m
--- make_hlds.m 2000/01/25 04:09:47 1.322
+++ make_hlds.m 2000/02/14 03:34:37
@@ -63,6 +63,7 @@
:- import_module string, char, int, set, bintree, map, multi_map, require.
:- import_module bag, term, varset, getopt, assoc_list, term_io.
+:- import_module ka_alias_as.
parse_tree_to_hlds(module(Name, Items), MQInfo0, EqvMap, Module,
UndefTypes, UndefModes) -->
@@ -480,6 +481,11 @@
MaybeArgSizeInfo, MaybeTerminationInfo, Context,
Module0, Module)
;
+ { Pragma = ka_alias_info(_PredOrFunc, _SymName, _ModeList,
+ _HeadVars, _MaybeAliasInfo) },
+ % ignore ka_alias_info pragma's in .m files
+ { Module = Module0 }
+ ;
{ Pragma = terminates(Name, Arity) },
add_pred_marker(Module0, "terminates", Name, Arity,
ImportStatus, Context, terminates,
@@ -1352,6 +1358,7 @@
**** { module_info_incr_errors(Module0, Module) }
***/
).
+
%-----------------------------------------------------------------------------%
Index: mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.147
diff -u -r1.147 mercury_compile.m
--- mercury_compile.m 2000/01/10 00:43:44 1.147
+++ mercury_compile.m 2000/02/09 00:09:29
@@ -52,6 +52,7 @@
:- import_module mercury_to_mercury, mercury_to_goedel.
:- import_module dependency_graph, prog_util, rl_dump, rl_file.
:- import_module options, globals, passes_aux.
+:- import_module ka_run.
%-----------------------------------------------------------------------------%
@@ -906,7 +907,13 @@
mercury_compile__maybe_dump_hlds(HLDS9, "09", "determinism"),
!,
- mercury_compile__check_unique_modes(HLDS9, Verbose, Stats,
+ % check aliases
+ mercury_compile__possible_aliases(HLDS9, Verbose, Stats,
+ HLDS9b), !,
+ mercury_compile__maybe_dump_hlds(HLDS9b, "09b",
+ "possible_aliases"), !,
+
+ mercury_compile__check_unique_modes(HLDS9b, Verbose, Stats,
HLDS10, FoundUniqError), !,
mercury_compile__maybe_dump_hlds(HLDS10, "10", "unique_modes"),
!,
@@ -938,6 +945,7 @@
;
{ FoundError = yes }
)
+
),
{ HLDS20 = HLDS12 },
@@ -1468,6 +1476,27 @@
HLDS0, HLDS),
maybe_write_string(Verbose, "% done.\n"),
maybe_report_stats(Stats).
+
+:- pred mercury_compile__possible_aliases( module_info, bool, bool,
+ module_info, io__state,
+ io__state).
+:- mode mercury_compile__possible_aliases( in, in, in, out, di, uo) is det.
+
+mercury_compile__possible_aliases(HLDS0, Verbose, Stats, HLDS ) -->
+ globals__io_lookup_bool_option( infer_possible_aliases, InferAliases),
+ (
+ { InferAliases = yes }
+ ->
+ maybe_write_string(Verbose,
+ "% Annotating with possible aliases...\n"),
+ maybe_flush_output(Verbose),
+ ka_run__aliases_pass( HLDS0, HLDS ),
+ maybe_write_string(Verbose, "% done.\n"),
+ maybe_report_stats(Stats)
+ ;
+ { HLDS = HLDS0 }
+ ).
+
%-----------------------------------------------------------------------------%
Index: mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.166
diff -u -r1.166 mercury_to_mercury.m
--- mercury_to_mercury.m 2000/01/25 04:09:52 1.166
+++ mercury_to_mercury.m 2000/02/09 06:20:33
@@ -31,6 +31,9 @@
io__state, io__state).
:- mode convert_to_mercury(in, in, in, di, uo) is det.
+:- pred mercury_output_sym_name(sym_name, io__state, io__state).
+:- mode mercury_output_sym_name(in, di, uo) is det.
+
:- pred mercury_output_item(item, prog_context, io__state, io__state).
:- mode mercury_output_item(in, in, di, uo) is det.
@@ -415,6 +418,9 @@
PredName, ModeList, Context,
MaybeArgSizeInfo, MaybeTerminationInfo)
;
+ { Pragma = ka_alias_info(_,_,_,_,_) },
+ []
+ ;
{ Pragma = terminates(Pred, Arity) },
mercury_output_pragma_decl(Pred, Arity, predicate, "terminates")
;
@@ -2667,9 +2673,6 @@
% Use mercury_output_bracketed_sym_name when the sym_name has
% no arguments, otherwise use mercury_output_sym_name.
%
-
-:- pred mercury_output_sym_name(sym_name, io__state, io__state).
-:- mode mercury_output_sym_name(in, di, uo) is det.
mercury_output_sym_name(SymName) -->
mercury_output_sym_name(SymName, not_next_to_graphic_token).
Index: module_qual.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/module_qual.m,v
retrieving revision 1.53
diff -u -r1.53 module_qual.m
--- module_qual.m 2000/01/13 04:29:40 1.53
+++ module_qual.m 2000/02/09 06:58:13
@@ -946,6 +946,10 @@
termination_info(PredOrFunc, SymName, ModeList, Args, Term),
Info0, Info) -->
qualify_mode_list(ModeList0, ModeList, Info0, Info).
+qualify_pragma(ka_alias_info(PredOrFunc, SymName, ModeList0, Vars, MaybeAS),
+ ka_alias_info(PredOrFunc, SymName, ModeList, Vars, MaybeAS),
+ Info0, Info) -->
+ qualify_mode_list(ModeList0, ModeList, Info0, Info).
qualify_pragma(terminates(A, B), terminates(A, B), Info, Info) --> [].
qualify_pragma(does_not_terminate(A, B), does_not_terminate(A, B),
Info, Info) --> [].
Index: modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.115
diff -u -r1.115 modules.m
--- modules.m 2000/01/11 07:53:40 1.115
+++ modules.m 2000/02/09 07:00:27
@@ -910,6 +910,7 @@
pragma_allowed_in_interface(unused_args(_, _, _, _, _), no).
pragma_allowed_in_interface(type_spec(_, _, _, _, _, _, _), yes).
pragma_allowed_in_interface(termination_info(_, _, _, _, _), yes).
+pragma_allowed_in_interface(ka_alias_info(_, _, _, _, _), yes).
pragma_allowed_in_interface(terminates(_, _), yes).
pragma_allowed_in_interface(does_not_terminate(_, _), yes).
pragma_allowed_in_interface(check_termination(_, _), yes).
Index: options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.277
diff -u -r1.277 options.m
--- options.m 2000/01/10 00:43:45 1.277
+++ options.m 2000/02/08 00:17:08
@@ -121,6 +121,7 @@
; strict_sequential
; infer_types
; infer_modes
+ ; infer_possible_aliases
; infer_det
; infer_all
; type_inference_iteration_limit
@@ -493,6 +494,7 @@
fully_strict - bool(yes),
infer_types - bool(no),
infer_modes - bool(no),
+ infer_possible_aliases - bool(no),
infer_det - bool(yes),
infer_all - bool_special,
type_inference_iteration_limit - int(60),
@@ -863,6 +865,7 @@
long_option("infer-all", infer_all).
long_option("infer-types", infer_types).
long_option("infer-modes", infer_modes).
+long_option("infer-possible-aliases", infer_possible_aliases).
long_option("infer-determinism", infer_det).
long_option("infer-det", infer_det).
long_option("type-inference-iteration-limit",
Index: prog_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.52
diff -u -r1.52 prog_data.m
--- prog_data.m 2000/01/24 17:47:15 1.52
+++ prog_data.m 2000/02/09 04:01:01
@@ -24,6 +24,7 @@
:- import_module (inst).
:- import_module bool, list, assoc_list, map, varset, term, std_util.
+:- import_module ka_alias_as.
%-----------------------------------------------------------------------------%
@@ -248,6 +249,13 @@
% termination_info pragmas are used in opt and
% trans_opt files.
+ ; ka_alias_info(pred_or_func, sym_name, list(mode),
+ list(prog_var), maybe(alias_as))
+ % the list(mode) is the declared argmodes of the
+ % procedure.
+ % This pragma is used to define information about
+ % a predicates possible aliases set.
+ % These pragma's are used in opt.ka files
; terminates(sym_name, arity)
% Predname, Arity
Index: prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.21
diff -u -r1.21 prog_io_pragma.m
--- prog_io_pragma.m 1999/07/13 08:53:24 1.21
+++ prog_io_pragma.m 2000/02/09 07:48:46
@@ -25,6 +25,7 @@
:- import_module prog_io, prog_io_goal, prog_util.
:- import_module term_util, term_errors.
:- import_module int, map, string, std_util, bool, require.
+:- import_module ka_alias_as.
parse_pragma(ModuleName, VarSet, PragmaTerms, Result) :-
(
@@ -613,7 +614,48 @@
"syntax error in `:- pragma termination_info' declaration",
ErrorTerm)
).
-
+
+parse_pragma_type(ModuleName, "ka_alias_info", PragmaTerms, ErrorTerm,
+ _VarSet, Result) :-
+ (
+ PragmaTerms = [
+ PredAndModesTerm0,
+ HVsTerm,
+ AliasInformation
+ ],
+ parse_pred_or_func_and_arg_modes(yes(ModuleName), PredAndModesTerm0,
+ ErrorTerm, "`:- pragma ka_alias_info' declaration",
+ NameAndModesResult),
+ NameAndModesResult = ok(PredName - PredOrFunc, ModeList),
+
+ % variables
+ HVsTerm = term__functor(term__atom("vars"), ListHVTerm, _),
+ term__vars_list(ListHVTerm, HeadVarsGeneric),
+ list__map(term__coerce_var, HeadVarsGeneric, HeadVars),
+
+ % aliases
+
+ (
+ AliasInformation = term__functor(
+ term__atom("not_available"),_,_),
+ MaybeAliasInfo = no
+ ;
+ AliasInformation = term__functor(
+ term__atom("yes"), ReadAliases, _),
+ ka_alias_as__parse_read_aliases(ReadAliases, Alias_as),
+ MaybeAliasInfo = yes(Alias_as)
+ ),
+
+ Result0 = ok(pragma(ka_alias_info(PredOrFunc, PredName, ModeList,
+ HeadVars, MaybeAliasInfo)))
+ ->
+ Result = Result0
+ ;
+ Result = error(
+ "syntax error in `:- pragma ka_alias_info' declaration",
+ ErrorTerm)
+ ).
+
parse_pragma_type(ModuleName, "terminates", PragmaTerms,
ErrorTerm, _VarSet, Result) :-
parse_simple_pragma(ModuleName, "terminates",
-------
new file: ka_alias_as.m
%-----------------------------------------------------------------------------%
% Copyright (C) 1996-2000 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.
%-----------------------------------------------------------------------------%
% module ka_alias_as: defines the KUL alias abstract substitution
% main author: nancy
% notes:
% 1. internally at some point, this abstract substitution uses
% the notion of a `selector'. This concept corresponds to the
% `selector' used by bta. At some moment the code related to
% these selectors should be shared. This is not the case at this
% moment.
% 2. _partially instantiated datastructures_ : the day they'll be
% introduced, a couple of things will have to be changed.
:- module ka_alias_as.
:- interface.
%-------------------------------------------------------------------%
%-- import_module
:- import_module list, map.
:- import_module prog_data.
:- import_module hlds_goal.
:- import_module hlds_pred, hlds_module.
:- import_module instmap.
:- import_module io, std_util, term.
%-------------------------------------------------------------------%
%-- exported types
:- type alias_as.
%-------------------------------------------------------------------%
%-- exported predicates
:- pred init( alias_as::out ) is det.
:- pred is_bottom( alias_as::in ) is semidet.
% project alias abstract substitution on a list of variables.
:- pred project( list(prog_var), alias_as, alias_as).
:- mode project( in, in, out ) is det.
% rename abstract substitution according to a mapping
% of prog_vars (map (FROM_VARS, TO_VARS) ).
:- pred rename( map(prog_var, prog_var), alias_as, alias_as).
:- mode rename( in, in, out ) is det.
% returns true if both abstract substitutions are equal.
% needed for fixpoint
:- pred equal( alias_as, alias_as).
:- mode equal( in, in) is semidet.
% first abstract subst. is less than or equal to second
% abstract subst. (for fixpoint). (not used)
:- pred leq( alias_as, alias_as).
:- mode leq( in ,in ) is semidet.
% compute least upper bound.
:- pred least_upper_bound( alias_as, alias_as, alias_as).
:- mode least_upper_bound( in, in, out) is det.
% compute least upper bound of a list of abstract substitutions.
:- pred least_upper_bound_list( list(alias_as), alias_as).
:- mode least_upper_bound_list( in, out) is det.
% extend( NEW, OLD, RESULT).
% extend a given abstract substitution with new information.
:- pred extend( alias_as, alias_as, alias_as).
:- mode extend( in, in, out) is det.
% specialized extend for unifications
:- pred extend_unification( hlds_goal__unification, alias_as, alias_as).
:- mode extend_unification( in, in, out) is det.
% normalization of the representation based on the types of
% the variables (retreived from proc_info) and the instmaps.
:- pred normalize( hlds_pred__proc_info, module_info, instmap, alias_as, alias_as).
:- mode normalize( in, in, in, in, out ) is det.
% print-procedures:
% print_maybe_possible_aliases: routine used within
% hlds_dumps.
:- pred print_maybe_possible_aliases( maybe(alias_as), proc_info,
io__state, io__state).
:- mode print_maybe_possible_aliases( in, in, di, uo) is det.
% print_maybe_interface_aliases: routine for printing
% alias information in interface files.
:- pred print_maybe_interface_aliases( maybe(alias_as),
proc_info, io__state, io__state).
:- mode print_maybe_interface_aliases( in, in, di, uo) is det.
% reverse routine of print_maybe_interface_aliases.
:- pred parse_read_aliases(list(term(T)), alias_as).
:- mode parse_read_aliases(in,out) is det.
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
:- implementation.
:- import_module std_util.
:- import_module hlds_data.
:- import_module hlds_out.
:- import_module varset.
%-------------------------------------------------------------------%
%-- type definitions
:- type alias_as --->
real_as( list(alias) )
; bottom.
% where list(alias) contains no doubles!
% near future: alias_as should also include top(string),
% where string could be some sort of message.
:- type alias == pair(datastruct).
:- type datastruct ---> cel(prog_var,selector).
:- type selector == list(unit_sel).
:- type unit_sel ---> us( cons_id, index ).
:- type index == int.
%-------------------------------------------------------------------%
% init
init(bottom).
% is_bottom
is_bottom(bottom).
is_bottom(real_as([])).
% project
project( _Listvar, bottom, bottom).
project( Listvar, real_as(Aliases), ASout) :-
list__foldl( project_alias( Listvar ), Aliases, [], PAliases),
wrap(PAliases, ASout).
rename( _Mapvar, bottom, bottom).
rename( Mapvar, real_as(Aliases), ASout) :-
list__foldl( rename_alias( Mapvar ), Aliases, [], RAliases),
wrap(RAliases, ASout).
equal( bottom, bottom).
equal( real_as(LIST1), real_as(LIST2)):-
list__length(LIST1, L),
list__length(LIST2, L),
list__takewhile(alias_occurs_in(LIST2),LIST1,_, AfterList),
AfterList = [].
leq( bottom, _ ).
leq( real_as(LIST1), real_as(LIST2) ) :-
list__takewhile(alias_subsumed_by_list(LIST2),LIST1,_, AfterList),
AfterList = [].
least_upper_bound( A1, A2, RESULT) :-
(
A1 = real_as(LIST1),
A2 = real_as(LIST2)
->
alias_list_lub(LIST1,LIST2,Aliases),
wrap(Aliases, RESULT)
;
A1 = bottom
->
RESULT = A2
;
RESULT = A1
).
:- pred alias_list_lub(list(alias),list(alias),list(alias)).
:- mode alias_list_lub(in,in,out) is det.
alias_list_lub(LIST1,LIST2,Aliases):-
list__foldl(alias_add_subsuming,LIST1,LIST2,Aliases).
least_upper_bound_list( AS_LIST, AS ) :-
list__foldl(least_upper_bound, AS_LIST, bottom, AS).
extend( A1, A2, RESULT ):-
(
A1 = real_as(NEW),
A2 = real_as(OLD)
->
alias_altclosure(NEW,OLD,Aliases),
wrap(Aliases,RESULT)
;
A1 = bottom
->
RESULT = A2
;
RESULT = A1
).
extend_unification( Unif, ASin, ASout ):-
alias_from_unification( Unif, AUnif),
extend( AUnif, ASin, ASout).
normalize( ProcInfo, HLDS, _INSTMAP, ALIASin, ALIASout):-
normalize_with_type_information( ProcInfo, HLDS, ALIASin, ALIAS1),
remove_doubles( ALIAS1, ALIASout).
:- pred remove_doubles( alias_as, alias_as).
:- mode remove_doubles( in, out ) is det.
remove_doubles( AS0, AS ):-
(
AS0 = real_as( Aliases0 )
->
list__foldl( add_without_doubles, Aliases0, [], Aliases ),
wrap( Aliases, AS )
;
AS = AS0
).
:- pred add_without_doubles( alias, list(alias), list(alias) ).
:- mode add_without_doubles( in, in, out ) is det.
add_without_doubles( Alias, Aliases0, Aliases ) :-
(
alias_occurs_in(Aliases0, Alias)
->
Aliases = Aliases0
;
Aliases = [ Alias | Aliases0 ]
).
%-------------------------------------------------------------------%
% printing routines
%-------------------------------------------------------------------%
% MaybeAs = yes( Alias_as) -> print out Alias_as
% = no -> print "not available"
print_maybe_possible_aliases( MaybeAS, ProcInfo ) -->
(
{ MaybeAS = yes(AS) }
->
io__nl,
print_possible_aliases( AS, ProcInfo)
;
io__write_string(" not available.")
).
% print_possible_aliases( Abstract Substitution, Proc Info).
% print alias abstract substitution
:- pred print_possible_aliases( alias_as, proc_info, io__state, io__state).
:- mode print_possible_aliases( in, in, di, uo ) is det.
print_possible_aliases( AS, ProcInfo ) -->
(
{ AS = real_as(Aliases) }
->
io__write_list( Aliases, "", print_alias(ProcInfo,"% ", "\n")),
io__write_string("% -- end aliases")
;
io__write_string("% aliases = bottom")
).
% MaybeAs = yes(Alias_as) -> print `yes( printed Alias_as)'
% = no -> print `not_available'
print_maybe_interface_aliases( MaybeAS, ProcInfo ) -->
(
{ MaybeAS = yes(AS) }
->
io__write_string("yes("),
(
{ AS = real_as(Aliases) }
->
io__write_string("["),
io__write_list( Aliases, ",", print_alias(ProcInfo," ","")),
io__write_string("]")
;
io__write_string("bottom")
),
io__write_string(")")
;
io__write_string("not_available")
).
:- pred print_alias( proc_info, string, string, alias, io__state, io__state).
:- mode print_alias( in, in, in, in, di, uo) is det.
print_alias( ProcInfo, FrontString, EndString, ALIAS ) -->
{ ALIAS = D1 - D2 },
io__write_string( FrontString ),
io__write_string( "pair( " ),
print_datastructure( D1, ProcInfo ),
io__write_string(" , "),
print_datastructure( D2, ProcInfo ),
io__write_string(" ) "),
io__write_string( EndString ).
:- pred print_datastructure( datastruct, proc_info, io__state, io__state).
:- mode print_datastructure( in, in, di, uo) is det.
print_datastructure( D, ProcInfo) -->
{ D = cel( ProgVar, SEL ) },
{ proc_info_varset(ProcInfo, ProgVarset) },
{ varset__lookup_name( ProgVarset, ProgVar, ProgName ) },
io__write_string("cel("),
io__write_string( ProgName ),
io__write_string(", ["),
io__write_list( SEL, ",", print_unit_selector ),
io__write_string("])").
:- import_module mercury_to_mercury, string, prog_io.
:- pred print_unit_selector( unit_sel, io__state, io__state).
:- mode print_unit_selector( in, di, uo) is det.
print_unit_selector( us( CONS, INDEX ) ) -->
{ cons_id_arity( CONS, ARITY ) },
io__write_string( "sel("),
mercury_output_cons_id(CONS, needs_brackets),
io__write_string( "," ),
io__write_int( ARITY ),
io__write_string(","),
io__write_int(INDEX),
io__write_string(")").
%-------------------------------------------------------------------%
% parsing routines
%-------------------------------------------------------------------%
parse_read_aliases( LISTTERM ,AS ):-
(
% LISTTERM ought to have only one element
LISTTERM = [ OneITEM ]
->
(
OneITEM = term__functor( term__atom(CONS), TERMS, _ )
->
(
CONS = ".",
TERMS = [ ELEM , RESTTERMS ]
->
parse_alias_term( ELEM, RESTTERMS, Aliases),
wrap(Aliases, AS)
% AS = bottom
;
CONS = "bottom"
->
AS = bottom
;
string__append(
"(ka) parse_read_aliases: could not parse aliases, top cons: ", CONS, Msg),
error(Msg)
)
;
error("(ka) parse_read_aliases: term not a functor")
)
;
list__length( LISTTERM, L ),
string__int_to_string(L, LS),
string__append_list( ["(ka) parse_read_aliases: wrong number of arguments. yes/", LS,
" should be yes/1"], Msg),
error(Msg)
).
:- pred parse_alias_term( term(T), term(T),list(alias)).
:- mode parse_alias_term( in, in, out) is det.
parse_alias_term( First, Rest, Aliases) :-
parse_one_alias_term( First, Alias ),
(
Rest = term__functor( term__atom(CONS), Args, _ )
->
(
CONS = ".",
Args = [ Second, NewRest]
->
parse_alias_term(Second, NewRest, RestAliases),
Aliases = [ Alias | RestAliases ]
;
Aliases = [ Alias ]
)
;
error("(ka) parse_alias_term: term is not a functor")
).
:- pred parse_one_alias_term( term(T), alias).
:- mode parse_one_alias_term( in, out ) is det.
parse_one_alias_term( TERM , A ) :-
(
TERM = term__functor( term__atom(CONS), Args, _)
->
(
CONS = "pair"
->
(
Args = [ First, Second ]
->
parse_datastructure_term( First, D1 ),
parse_datastructure_term( Second, D2 ),
A = D1 - D2
;
list__length(Args, L),
string__int_to_string(L,LS),
string__append_list(
[ "(ka) parse_one_alias_term: ",
"wrong number of arguments. `-'/",
LS,"should be `-'/2"],Msg),
error(Msg)
)
;
term__det_term_to_type( TERM, TYPE),
varset__init(V),
mercury_type_to_string(V, TYPE, StringTerm),
string__append_list([
"(ka) parse_one_alias_term: ",
"wrong constructor. `",
StringTerm,
"' should be `pair'"],Msg),
error(Msg)
)
;
error("(ka) parse_one_alias_term: term is not a functor")
).
:- pred parse_datastructure_term( term(T), datastruct ).
:- mode parse_datastructure_term( in, out ) is det.
parse_datastructure_term( TERM, Data ):-
(
TERM = term__functor( term__atom( CONS ), Args, _ )
->
(
CONS = "cel"
->
(
Args = [ VarTerm, SelectorTerm ]
->
(
VarTerm = term__variable(VAR)
->
term__coerce_var(VAR, PROGVAR),
parse_selector_term(SelectorTerm, SELECTOR),
Data = cel(PROGVAR, SELECTOR)
;
error("(ka) parse_datastructure_term: wrong term. variable, should be functor")
)
;
list__length(Args, L),
string__int_to_string( L, LS),
string__append_list(["(ka) parse_datastructure_term: wrong number of arguments. cel/",LS,
"should be cel/2"],Msg),
error(Msg)
)
;
string__append_list(["(ka) parse_datastructure_term: wrong constructor. `",CONS,
"' should be `cel'"],Msg),
error(Msg)
)
;
error("(ka) parse_datastructure_term: term not a functor")
).
:- pred parse_selector_term( term(T), selector).
:- mode parse_selector_term(in,out) is det.
parse_selector_term( TERM, SEL ):-
(
TERM = term__functor( term__atom(CONS), Args, _)
->
(
CONS = ".",
Args = [ First , Rest ]
->
parse_unit_selector( First, US),
parse_selector_term( Rest, SELrest ),
SEL = [ US | SELrest ]
;
SEL = []
)
;
error("(ka) parse_selector_term: term not a functor")
).
:- pred parse_unit_selector( term(T), unit_sel).
:- mode parse_unit_selector( in, out) is det.
parse_unit_selector( TERM, US ):-
(
TERM = term__functor( term__atom(CONS), Args, _)
->
(
CONS = "sel",
Args = [ CONS_TERM, ARITY_TERM, POS_TERM ]
->
(
prog_io__sym_name_and_args( CONS_TERM, ConsID_SN, ConsID_ARGS ),
ConsID_ARGS = [],
ARITY_TERM = term__functor( term__integer( Arity ), _, _),
POS_TERM = term__functor( term__integer( Pos ), _, _ )
->
ConsID = cons( ConsID_SN, Arity ),
US = us( ConsID, Pos )
;
CONS_TERM = term__functor( term__integer( X ), _, _)
->
ConsID = int_const( X ),
US = us( ConsID, 0 )
;
CONS_TERM = term__functor( term__float( X ), _, _)
->
ConsID = float_const( X ),
US = us( ConsID, 0)
;
CONS_TERM = term__functor( term__string( S ), _, _)
->
ConsID = string_const( S ),
US = us( ConsID, 0 )
;
error("(ka) parse_unit_selector: unknown cons_id in unit selector")
)
;
error("(ka) parse_unit_selector: top constructor should be sel/3")
)
;
error("(ka) parse_unit_selector: term not a functor")
).
%-------------------------------------------------------------------%
%-- additional predicates
:- pred wrap( list(alias), alias_as).
:- mode wrap( in, out) is det.
wrap( LIST, AS) :-
(
LIST = []
->
AS = bottom
;
AS = real_as(LIST)
).
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
%-- alias predicates
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
:- pred project_alias( list(prog_var), alias,
list(alias), list(alias)).
:- mode project_alias( in, in, in, out) is det.
project_alias( LIST, Alias, LISTin, LISTout) :-
Alias = Data1 - Data2,
datastruct_get_var(Data1, Var1),
datastruct_get_var(Data2, Var2),
(
list__member(Var1, LIST),
list__member(Var2, LIST)
->
LISTout = [Alias | LISTin]
;
LISTout = LISTin
).
:- pred rename_alias( map(prog_var, prog_var), alias,
list(alias), list(alias)).
:- mode rename_alias( in, in, in, out) is det.
rename_alias( MAP, Alias, LISTin, LISTout) :-
Alias = Data1 - Data2,
datastruct_rename( MAP, Data1, RData1),
datastruct_rename( MAP, Data2, RData2),
RAlias = RData1 - RData2,
LISTout = [RAlias | LISTin].
:- pred alias_occurs_in( list(alias), alias).
:- mode alias_occurs_in( in, in ) is semidet.
alias_occurs_in( [A1 | R ], A2 ):-
(
alias_equal(A1,A2)
->
true
;
alias_occurs_in( R, A2 )
).
:- pred alias_equal( alias, alias ).
:- mode alias_equal( in, in ) is semidet.
alias_equal( A1, A2 ) :-
A1 = D1a - D1b,
A2 = D2a - D2b,
(
datastruct_equal(D1a,D2a),
datastruct_equal(D1b,D2b)
;
datastruct_equal(D1a,D2b),
datastruct_equal(D1b,D2a)
).
:- pred alias_subsumed_by_list( list(alias), alias ).
:- mode alias_subsumed_by_list( in, in) is semidet.
alias_subsumed_by_list( [A1 | R ] , A2 ) :-
(
alias_leq(A2,A1)
->
true
;
alias_subsumed_by_list( R, A2)
).
:- pred alias_leq( alias, alias).
:- mode alias_leq( in, in ) is semidet.
alias_leq( A1, A2 ) :-
A1 = D1a - D1b,
A2 = D2a - D2b,
(
datastruct_same_vars(D1a,D2a),
datastruct_same_vars(D1b,D2b)
->
datastruct_leq_selectors(D1a,D2a),
datastruct_leq_selectors(D1b,D2b)
;
(
datastruct_same_vars(D1a,D2b),
datastruct_same_vars(D1b,D2a)
->
datastruct_leq_selectors(D1a,D2b),
datastruct_leq_selectors(D1b,D2a)
;
fail
)
).
:- pred alias_add_subsuming(alias,list(alias),list(alias)).
:- mode alias_add_subsuming(in,in, out) is det.
alias_add_subsuming( ALIAS, [], [ALIAS]).
alias_add_subsuming( ALIAS, [ A | R ], RESULT ):-
(
alias_leq(ALIAS,A)
->
RESULT = [ A | R ]
;
alias_leq(A, ALIAS)
->
RESULT = [ ALIAS | R ]
;
alias_add_subsuming( ALIAS, R, TEMP),
RESULT = [ A | TEMP ]
).
% alias_altclosure( NEW, OLD, RESULT)
% computes the alternating closure of two lists of aliases.
% RESULT = NEW + OLD + path2(NEW,OLD) + path3(NEW,OLD).
% where path2(NEW,OLD) is: (a,b), such that (a,c) in NEW,
% and (c,b) in OLD
% where path3(NEW,OLD) is: (a,b), such that (a,c) in NEW,
% (c,d) in OLD,
% (d,b) in NEW
% taking into account termshifts.
:- pred alias_altclosure(list(alias),list(alias),list(alias)).
:- mode alias_altclosure(in,in,out) is det.
alias_altclosure( NEW, OLD, RESULT) :-
(
NEW = []
->
RESULT = OLD
;
OLD = []
->
RESULT = NEW
;
altclosure_path2_3(NEW,OLD,PATH2,PATH3),
list__foldl(alias_list_lub,[OLD,PATH2,PATH3],NEW,RESULT)
).
:- pred altclosure_path2_3(list(alias),list(alias),list(alias),list(alias)).
:- mode altclosure_path2_3(in,in,out,out) is det.
altclosure_path2_3(NEW,OLD,PATH2,PATH3):-
% not only this returns the path2 results,
% but these results are also such that:
% ALIAS = D1 - D2, where D1 is from NEW, en D2
% from OLD
% constructs paths from NEW to OLD
list__foldl(altclos_ordered_path(OLD),NEW,[],PATH2),
% constructs paths from PATH2 (NEW -> OLD) to NEW
list__foldl(altclos_ordered_path(NEW),PATH2,[],PATH3).
% altclos_ordered_path( to_aliases, from_alias, temporary result,
% new result).
:- pred altclos_ordered_path(list(alias),alias,list(alias),list(alias)).
:- mode altclos_ordered_path(in,in,in,out) is det.
altclos_ordered_path( TO_LIST, FROM_ALIAS, LISTin, LISTout) :-
list__filter_map(single_altclos(FROM_ALIAS),TO_LIST,NEW),
list__append(NEW,LISTin,LISTout).
% single_altclos( FROM_ALIAS, TO_ALIAS, RESULT_ALIAS).
% --> semidet!
:- pred single_altclos(alias,alias,alias).
:- mode single_altclos(in,in,out) is semidet.
single_altclos( FROM , TO , RESULT ) :-
FROM = DFa - DFb,
TO = DTa - DTb,
(
datastruct_same_vars(DFb,DTa)
->
single_directed_altclos(FROM, TO, RESULT)
;
datastruct_same_vars(DFa,DTa)
->
alias_switch(FROM,FROMsw),
single_directed_altclos(FROMsw,TO,RESULT)
;
datastruct_same_vars(DFb,DTb)
->
alias_switch(TO,TOsw),
single_directed_altclos(FROM,TOsw,RESULT)
;
datastruct_same_vars(DFa,DTb)
->
alias_switch(FROM,FROMsw),
alias_switch(TO,TOsw),
single_directed_altclos(FROMsw,TOsw,RESULT)
;
fail
).
% single_directed_altclos(FROM,TO, RESULT), with matching
% middle vars!
:- pred single_directed_altclos(alias,alias,alias).
:- mode single_directed_altclos(in,in,out) is semidet.
single_directed_altclos( FROM, TO, RESULT) :-
FROM = DFa - DFb,
TO = DTa - DTb,
datastruct_get_selector(DFb,SF),
datastruct_get_selector(DTa,ST),
(
selector_match(SF,ST,EXT1)
->
% SF.EXT1 = ST
datastruct_termshift(DFa,EXT1,DRa),
RESULT = DRa - DTb
;
selector_match(ST,SF,EXT2)
->
% ST.EXT1 = SF
datastruct_termshift(DTb,EXT2,DRb),
RESULT = DFa - DRb
;
fail
).
:- pred alias_from_unification(hlds_goal__unification, alias_as).
:- mode alias_from_unification(in, out) is det.
alias_from_unification( construct( VAR, CONS, ARGS, _, _, _, _ ), AS ) :-
list__foldl( alias_from_unif(VAR,CONS),ARGS, 1 - [], _N - R),
wrap(R, AS).
alias_from_unification(deconstruct( VAR, CONS, ARGS, _, _ ), AS) :-
list__foldl( alias_from_unif(VAR,CONS),ARGS, 1 - [], _N - R),
wrap(R, AS).
alias_from_unification(assign(VAR1,VAR2), AS):-
datastruct_create_top(VAR1,D1),
datastruct_create_top(VAR2,D2),
ALIAS = D1 - D2,
wrap( [ALIAS], AS).
alias_from_unification(simple_test(_A,_B), AS):-
init(AS).
alias_from_unification(complicated_unify(_,_,_), AS):-
% XXXX only if partially instantiated datastructures cannot
% exist.
init(AS).
:- import_module int.
:- pred alias_from_unif(prog_var, cons_id, prog_var,
pair(int, list(alias)),
pair(int, list(alias))).
:- mode alias_from_unif(in, in, in, in, out) is det.
alias_from_unif( VAR, CONS, ARG, N - LISTin, N1 - LISTout):-
datastruct_create( VAR, CONS, N, D1),
datastruct_create_top( ARG, D2 ),
ALIAS = D1 - D2,
N1 is N + 1,
LISTout = [ALIAS | LISTin].
% switch the order of the alias...
:- pred alias_switch(alias,alias).
:- mode alias_switch(in,out) is det.
alias_switch( D1 - D2, D2 - D1 ).
%-------------------------------------------------------------------%
% NORMALIZATION WITH TYPE INFORMATION
%-------------------------------------------------------------------%
:- import_module type_util, require.
:- pred normalize_with_type_information( proc_info, module_info,
alias_as, alias_as).
:- mode normalize_with_type_information( in, in, in, out) is det.
normalize_with_type_information( ProcInfo, HLDS, Alias0, Alias):-
(
Alias0 = real_as(Aliases0)
->
proc_info_vartypes( ProcInfo, VarTypes ),
list__map( normalize_wti_alias(VarTypes, HLDS),
Aliases0, Aliases),
wrap(Aliases, Alias)
;
Alias = Alias0
).
:- pred normalize_wti_alias( vartypes, module_info, alias, alias ).
:- mode normalize_wti_alias( in, in, in, out) is det.
normalize_wti_alias( VarTypes, HLDS, A0, A ):-
A0 = Da0 - Db0,
normalize_wti_datastruct( VarTypes, HLDS, Da0, Da),
normalize_wti_datastruct( VarTypes, HLDS, Db0, Db),
A = Da - Db.
:- pred normalize_wti_datastruct( vartypes, module_info, datastruct, datastruct ).
:- mode normalize_wti_datastruct( in, in, in, out) is det.
normalize_wti_datastruct( VarTypes, HLDS, D0, D ):-
D0 = cel( ProgVar, SEL0 ),
map__lookup(VarTypes, ProgVar, VarType),
(
type_util__is_introduced_type_info_type(VarType)
->
D = D0
;
normalize_wti_selector( VarType, HLDS, SEL0, SEL),
D = cel( ProgVar, SEL )
).
:- pred normalize_wti_selector( type, module_info, selector, selector).
:- mode normalize_wti_selector( in, in, in, out) is det.
normalize_wti_selector( VarType, HLDS, SEL0, SEL ):-
branch_map_init( B0 ),
selector_init( TOP ),
branch_map_insert( VarType, TOP, B0, B1 ),
normalize_wti_selector_2( VarType, HLDS, B1, TOP, SEL0, SEL).
:- pred normalize_wti_selector_2( type, module_info, branch_map,
selector, selector, selector).
:- mode normalize_wti_selector_2( in, in, in, in, in, out) is det.
normalize_wti_selector_2( VarType, HLDS, B0, Acc0, SEL0, SEL ):-
(
selector_top( SEL0 )
->
SEL = Acc0
;
selector_take_first_us( SEL0, US, SELR ),
US = us(CONS, INDEX),
type_util__classify_type( VarType, HLDS, Class ),
(
Class = user_type
->
true
;
error("(ka) ka_alias_as: not user type")
),
type_util__get_cons_id_arg_types(HLDS, VarType, CONS,
ArgTypes ),
(
list__index1(ArgTypes, INDEX, CType )
->
(
branch_map_search( B0, CType, BSel )
->
normalize_wti_selector_2( CType, HLDS,
B0, BSel, SELR, SEL )
;
selector_add_us( Acc0, US, Acc1 ),
branch_map_insert( CType, Acc1, B0, B1 ),
normalize_wti_selector_2( CType, HLDS,
B1, Acc1, SELR, SEL )
)
;
error("(ka) ka_alias_as: index not found")
)
).
%-------------------------------------------------------------------%
% BRANCH_MAP : copy/pasted from wimvh/bta_reduce.m
%-------------------------------------------------------------------%
:- import_module assoc_list.
:- type branch_map == assoc_list(type, selector).
:- pred branch_map_init(branch_map).
:- mode branch_map_init(out) is det.
:- pred branch_map_insert(type, selector, branch_map, branch_map).
:- mode branch_map_insert(in, in, in, out) is det.
:- pred branch_map_search(branch_map, type, selector).
:- mode branch_map_search(in, in, out) is semidet.
branch_map_init([]).
branch_map_insert(Type, SelPart, Map1, [(Type - SelPart) | Map1]).
branch_map_search([ (T1 - S1) | Ms ], T2, S):-
map__init(Empty),
% The two types are considered equal if they
% unify
% under an empty substitution
(
type_unify(T1, T2, [], Empty, Subst),
map__is_empty(Subst)
->
S = S1
;
branch_map_search(Ms, T2, S)
).
%-------------------------------------------------------------------%
%-- datastruct manipulations
:- pred datastruct_get_var(datastruct,prog_var).
:- mode datastruct_get_var(in,out) is det.
:- pred datastruct_get_selector(datastruct, selector).
:- mode datastruct_get_selector(in,out) is det.
datastruct_get_var(cel(VAR, _Sel), VAR).
datastruct_get_selector(cel(_Var, SEL), SEL).
:- pred datastruct_rename(map(prog_var,prog_var), datastruct, datastruct).
:- mode datastruct_rename(in, in ,out) is det.
datastruct_rename( MAP, DATAin, DATAout) :-
DATAin = cel(VAR, SEL),
map__lookup( MAP, VAR, RVAR),
DATAout = cel(RVAR, SEL).
:- pred datastruct_equal(datastruct, datastruct).
:- mode datastruct_equal(in,in) is semidet.
datastruct_equal( D1, D2 ):- D1 = D2.
:- pred datastruct_same_vars(datastruct,datastruct).
:- mode datastruct_same_vars(in,in) is semidet.
datastruct_same_vars(D1, D2):-
datastruct_get_var(D1,V),
datastruct_get_var(D2,V).
:- pred datastruct_leq_selectors(datastruct,datastruct).
:- mode datastruct_leq_selectors(in,in) is semidet.
datastruct_leq_selectors(D1,D2):-
(
D1 = D2
->
true
;
datastruct_get_selector(D1,S1),
datastruct_get_selector(D2,S2),
selector_leq(S1,S2)
).
:- pred datastruct_termshift(datastruct, selector, datastruct).
:- mode datastruct_termshift(in,in,out) is det.
datastruct_termshift(Din, S, Dout):-
Din = cel(V,Sin),
selector_termshift(Sin,S,Sout),
Dout = cel(V,Sout).
:- pred datastruct_create(prog_var, cons_id, int, datastruct).
:- mode datastruct_create(in,in,in,out) is det.
datastruct_create( V, CONS, INDEX, Dout) :-
unit_sel_create(CONS,INDEX, US),
SEL = [US],
Dout = cel(V,SEL).
:- pred datastruct_create_top(prog_var,datastruct).
:- mode datastruct_create_top(in,out) is det.
datastruct_create_top( V, Dout) :-
SEL = [],
Dout = cel(V, SEL).
%-------------------------------------------------------------------%
%-- selector manipulations
:- pred selector_init(selector::out) is det.
:- pred selector_top(selector::in) is semidet.
selector_init([]).
selector_top([]).
:- pred selector_take_first_us( selector, unit_sel, selector).
:- mode selector_take_first_us( in, out, out) is det.
selector_take_first_us( SEL0, US, SEL ):-
(
SEL0 = [ F | R ]
->
US = F, SEL = R
;
error("(ka) ka_alias_as: trying to split empty selector!")
).
:- pred selector_add_us( selector, unit_sel, selector).
:- mode selector_add_us( in, in, out) is det.
selector_add_us( S0, US, S ):-
list__append( S0, [US], S ).
:- pred unit_sel_create(cons_id, index, unit_sel).
:- mode unit_sel_create(in,in,out) is det.
unit_sel_create(CONS, INDEX, US):-
US = us( CONS, INDEX).
:- pred selector_leq(selector, selector).
:- mode selector_leq(in, in) is semidet.
selector_leq( S1, S2 ) :-
% XXXX dirty dirty dirty
% S1 is less than or equal (i.e., is subsumed by) S2,
% if S1 can be selected through S2 by appending extra
% unit-selectors to S2.
list__append(S2, _ , S1).
% selector_match(S1,S2,EXT) such that
% S1.EXT = S2
:- pred selector_match(selector,selector,selector).
:- mode selector_match(in,in,out) is semidet.
selector_match( S1, S2, EXT) :-
list__append(S1,EXT,S2).
:- pred selector_termshift(selector,selector,selector).
:- mode selector_termshift(in,in,out) is det.
selector_termshift(S1,S2,S):- list__append(S1,S2,S).
-------
new file: ka_util.m
%-----------------------------------------------------------------------------%
% Copyright (C) 1996-2000 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.
%-----------------------------------------------------------------------------%
% module ka_util: extra datastructures and predicates needed by the
% KUL aliasing pass
% main author: nancy
:- module ka_util.
:- interface.
%-------------------------------------------------------------------%
:- import_module list, map, bool.
:- import_module hlds_pred.
:- import_module ka_alias_as.
% table of alias substitutions needed for fixpoint computation.
:- type ka_fixpoint_table --->
ka_fixpoint(
int, % counts the runs
is_recursive, % default = no
is_stable, % default = yes
map( pred_proc_id, tabled_alias_as)
).
:- type tabled_alias_as --->
not_available ; available(alias_as).
:- type is_recursive == bool.
:- type is_stable == bool.
% initialize the table given the pred_proc_id's which will be
% handled in this fixpoint computation.
:- pred ka_fixpoint_table_init(list(pred_proc_id)::in, ka_fixpoint_table::out) is det.
% the datastructure keeps track of the number of fixpoint runs
% performed, this predicates adds one.
:- pred ka_fixpoint_table_new_run( ka_fixpoint_table::in, ka_fixpoint_table::out) is det.
% check whether all entries are stable. If so, one has reached
% a fixpoint
:- pred ka_fixpoint_table_all_stable( ka_fixpoint_table:: in ) is semidet.
% at the end of the analysis of one single pred_proc_id,
% the new exit alias information is stored. This might
% change the stability of the table.
% if the pred_proc_id is not in the table --> error
:- pred ka_fixpoint_table_new_as( pred_proc_id, alias_as,
ka_fixpoint_table, ka_fixpoint_table).
:- mode ka_fixpoint_table_new_as( in, in, in, out) is det.
% retreive the alias abstract substitution of a given
% pred_proc_id. If this information is not available,
% the general character of the fixpoint-table will be
% set to `recursive'
% if the pred_proc_id is not in the table --> fail
:- pred ka_fixpoint_table_get_as( pred_proc_id, alias_as,
ka_fixpoint_table, ka_fixpoint_table).
:- mode ka_fixpoint_table_get_as( in, out, in, out) is semidet.
% retreive alias_as information, without changing the
% table. To be used after fixpoint has been reached.
:- pred ka_fixpoint_table_get_final_as( pred_proc_id, alias_as,
ka_fixpoint_table).
:- mode ka_fixpoint_table_get_final_as( in, out, in) is det.
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
:- implementation.
:- import_module require,int.
ka_fixpoint_table_init( PRED_PROC_IDS, TABLE):-
map__init( Map0 ),
list__foldl( pred( PRED_PROC::in, Min::in, Mout::out) is det :-
( map__det_insert( Min, PRED_PROC, not_available, Mout )),
PRED_PROC_IDS,
Map0,
Map1 ),
TABLE = ka_fixpoint( 1, no, yes, Map1 ).
ka_fixpoint_table_new_run( Tin, Tout ) :-
Tin = ka_fixpoint( Runs, R, S, M),
Runs1 is Runs + 1,
Tout = ka_fixpoint( Runs1, R, S, M).
ka_fixpoint_table_all_stable( TABLE ) :-
TABLE = ka_fixpoint( _, R, S, _ ),
(
R = yes
->
S = yes
;
true
).
ka_fixpoint_table_new_as( PRED_PROC_ID, ALIAS_AS, Tin, Tout) :-
Tin = ka_fixpoint( Runs, R, _S, Min),
map__lookup( Min, PRED_PROC_ID, TabledASin),
(
TabledASin = available( SomeAS),
ka_alias_as__equal( SomeAS, ALIAS_AS )
->
Stability = yes,
TabledASout = TabledASin
;
Stability = no,
TabledASout = available( ALIAS_AS )
),
map__det_update( Min, PRED_PROC_ID, TabledASout, Mout),
Tout = ka_fixpoint( Runs, R, Stability, Mout).
ka_fixpoint_table_get_as( PRED_PROC_ID, ALIAS_AS, Tin, Tout) :-
Tin = ka_fixpoint( Runs, _R, S, M ),
map__search( M, PRED_PROC_ID, TabledAS), % can fail
(
TabledAS = available(AS)
->
ALIAS_AS = AS,
Rout = no,
Mout = M
;
ka_alias_as__init(ALIAS_AS),
NewTabled = available(ALIAS_AS),
% the alias_as in the table
% is also updated.
map__det_update( M, PRED_PROC_ID, NewTabled, Mout),
Rout = yes % fixpoint now recursive
),
Tout = ka_fixpoint( Runs, Rout, S, Mout ).
ka_fixpoint_table_get_final_as( PRED_PROC_ID, ALIAS_AS, T ):-
T = ka_fixpoint( _Runs, _R, _S, M ),
map__lookup( M, PRED_PROC_ID, TabledAS),
(
TabledAS = available(AS)
->
ALIAS_AS = AS
;
error("Internal error: ka_util__fixpoint_get_final_as")
).
-------
new file: ka_run.m
%-----------------------------------------------------------------------------%
% Copyright (C) 1996-2000 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.
%-----------------------------------------------------------------------------%
% module ka_run: implements the process of annotating each predicate, each
% procedure with KUL alias information
% main author: nancy
:- module ka_run.
:- interface.
%-------------------------------------------------------------------%
:- import_module io.
:- import_module hlds_module.
:- pred ka_run__aliases_pass( module_info, module_info, io__state, io__state).
:- mode ka_run__aliases_pass( in, out, di, uo) is det.
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
:- implementation.
:- import_module require.
:- import_module list, map.
:- import_module dependency_graph.
:- import_module instmap.
:- import_module hlds_pred, hlds_goal, prog_data.
:- import_module ka_util, ka_alias_as.
:- import_module std_util, string.
%-------------------------------------------------------------------%
ka_run__aliases_pass( HLDSin, HLDSout ) -->
% first load all interfaces.
ka_run__ensure_loaded_interfaces( HLDSin, HLDS0 ),
% strongly connected components needed
{ module_info_ensure_dependency_info( HLDS0, HLDS1) },
{ module_info_get_maybe_dependency_info( HLDS1, MaybeDepInfo) } ,
(
{ MaybeDepInfo = yes(DepInfo) }
->
{ hlds_dependency_info_get_dependency_ordering( DepInfo, DepOrdering ) },
% perform the analysis
{ run_with_dependencies( DepOrdering, HLDS1, HLDSout) },
% write out the results
ka_run__make_ka_interface( HLDSout )
;
{ error("(ka) ka_run module: no dependency info") }
).
:- pred run_with_dependencies( dependency_ordering, module_info,
module_info).
:- mode run_with_dependencies( in, in, out) is det.
run_with_dependencies( Deps, HLDSin, HLDSout) :-
list__foldl( run_with_dependency, Deps, HLDSin, HLDSout ).
:- pred run_with_dependency( list(pred_proc_id), module_info, module_info).
:- mode run_with_dependency( in, in, out ) is det.
run_with_dependency( SCC , HLDSin, HLDSout ) :-
(
% analysis ignores special predicates
some_are_special_preds(SCC, HLDSin)
->
HLDSout = HLDSin
;
% for each list of strongly connected components,
% perform a fixpoint computation.
ka_util__ka_fixpoint_table_init( SCC, FPtable0 ),
run_with_dependency_until_fixpoint( SCC, FPtable0,
HLDSin, HLDSout )
).
:- pred some_are_special_preds( list(pred_proc_id), module_info).
:- mode some_are_special_preds( in, in ) is semidet.
some_are_special_preds( SCC, HLDS ):-
module_info_get_special_pred_map( HLDS, MAP),
map__values( MAP, SpecPRED_IDS ),
list__takewhile( pred_id_in(SpecPRED_IDS), SCC,
_SCC_IN, SCC_NOT_IN ),
SCC_NOT_IN = [].
:- pred pred_id_in( list(pred_id), pred_proc_id ).
:- mode pred_id_in( in, in) is semidet.
pred_id_in( IDS, PRED_PROC_ID):-
PRED_PROC_ID = proc( PRED_ID, _),
list__member( PRED_ID, IDS ).
:- pred run_with_dependency_until_fixpoint( list(pred_proc_id),
ka_util__ka_fixpoint_table, module_info, module_info ).
:- mode run_with_dependency_until_fixpoint( in, in, in, out ) is det.
run_with_dependency_until_fixpoint( SCC, FPtable0, HLDSin, HLDSout ):-
list__foldl( analyse_pred_proc( HLDSin), SCC, FPtable0, FPtable),
(
ka_fixpoint_table_all_stable( FPtable )
->
list__foldl( update_alias_in_module_info(FPtable), SCC, HLDSin, HLDSout)
;
ka_util__ka_fixpoint_table_new_run(FPtable,FPtable1),
run_with_dependency_until_fixpoint( SCC, FPtable1, HLDSin, HLDSout )
).
%-------------------------------------------------------------------%
% THE KERNEL
%-------------------------------------------------------------------%
:- pred analyse_pred_proc( module_info, pred_proc_id, ka_fixpoint_table,
ka_fixpoint_table).
:- mode analyse_pred_proc( in, in, in, out) is det.
analyse_pred_proc( HLDS, PRED_PROC_ID , FPtable0, FPtable):-
module_info_pred_proc_info( HLDS, PRED_PROC_ID, _PredInfo, ProcInfo),
proc_info_goal( ProcInfo, Goal),
proc_info_headvars( ProcInfo, HeadVars),
Goal = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
instmap__init_reachable(InitIM),
instmap__apply_instmap_delta(InitIM, InstMapDelta, InstMap),
ka_alias_as__init(Alias0),
analyse_goal( HLDS, Goal, FPtable0, FPtable1, Alias0, Alias1 ),
ka_alias_as__project( HeadVars, Alias1, Alias2),
ka_alias_as__normalize( ProcInfo, HLDS, InstMap, Alias2, Alias ),
ka_fixpoint_table_new_as( PRED_PROC_ID, Alias, FPtable1, FPtable).
% analyse a given goal, with module_info and fixpoint table
% to lookup extra information, starting from an initial abstract
% substitution, and creating a new one. During this process,
% the fixpoint table might change (when recursive predicates are
% encountered).
:- pred analyse_goal( module_info, hlds_goal,
ka_fixpoint_table, ka_fixpoint_table,
alias_as, alias_as).
:- mode analyse_goal( in, in, in, out, in, out) is det.
analyse_goal( HLDS, Goal, FPtable0, FPtable, Alias0, Alias ) :-
Goal = GoalExpr - _GoalInfo ,
analyse_goal_expr( GoalExpr, HLDS, FPtable0, FPtable, Alias0, Alias).
:- pred analyse_goal_expr( hlds_goal_expr, module_info,
ka_fixpoint_table, ka_fixpoint_table,
alias_as, alias_as).
:- mode analyse_goal_expr( in, in, in, out, in, out) is det.
analyse_goal_expr( conj(Goals), HLDS , T0, T, A0, A) :-
list__foldl2( analyse_goal(HLDS), Goals, T0, T, A0, A).
analyse_goal_expr( call(PredID, ProcID, ARGS, _,_, _PName), HLDS, T0, T, A0, A):-
PRED_PROC_ID = proc(PredID, ProcID),
lookup_call_alias( PRED_PROC_ID, HLDS, T0, T, CallAlias),
rename_call_alias( PRED_PROC_ID, HLDS, ARGS, CallAlias, RenamedCallAlias),
ka_alias_as__extend( RenamedCallAlias, A0, A ).
analyse_goal_expr( generic_call(_,_,_,_), _HLDS , T, T, A, A):-
error("(ka) generic_call not handled") .
analyse_goal_expr( switch(_Var,_CF,Cases,_SM), HLDS, T0, T, A0, A ):-
list__map_foldl( analyse_case(HLDS, A0), Cases, SwitchAliases, T0, T),
ka_alias_as__least_upper_bound_list( SwitchAliases, A ).
:- pred analyse_case( module_info, alias_as, case, alias_as, ka_fixpoint_table,
ka_fixpoint_table ).
:- mode analyse_case( in, in, in, out, in, out ) is det.
analyse_case( HLDS, Alias0, CASE, Alias, T0, T ):-
CASE = case( _, Goal),
analyse_goal( HLDS, Goal, T0, T, Alias0, Alias).
analyse_goal_expr( unify(_,_,_,Unification,_), _, T, T, A0, A ):-
ka_alias_as__extend_unification( Unification, A0, A).
analyse_goal_expr( disj(Goals, _SM), HLDS, T0, T, A0, A ):-
list__map_foldl(
pred( Goal::in, Alias::out, FPT0::in, FPT::out) is det :-
( analyse_goal( HLDS, Goal, FPT0, FPT, A0, Alias)),
Goals,
DisjAliases,
T0, T ),
ka_alias_as__least_upper_bound_list( DisjAliases, A ).
analyse_goal_expr( not(Goal), HLDS , T0, T, A0, A ):-
analyse_goal( HLDS, Goal, T0, T, A0, A).
analyse_goal_expr( some(_Vars,_,_Goal), _ , T, T, A, A):-
error( "(ka) some goal not handled") .
analyse_goal_expr( if_then_else(_VARS, IF, THEN, ELSE, _SM), HLDS , T0, T, A0, A) :-
analyse_goal( HLDS, IF, T0, T1, A0, A1),
analyse_goal( HLDS, THEN, T1, T2, A1, A2),
analyse_goal( HLDS, ELSE, T2, T, A0, A3),
ka_alias_as__least_upper_bound( A2, A3, A).
analyse_goal_expr( pragma_c_code( _,_,_,_,_,_,_ ), _ , T, T, A, A) :-
error( "(ka) pragma_c_code not handled") .
analyse_goal_expr( par_conj( _Goals, _SM), _ , T, T, A, A) :-
error( "(ka) par_conj not handled") .
analyse_goal_expr( bi_implication( _G1, _G2), _ , T, T, A, A) :-
error( "(ka) bi_implication not handled") .
%-------------------------------------------------------------------%
% lookup the alias of the procedure with given pred_proc_id,
% look first in table, if this fails (then not in same SCC),
% look in module_info. If this fails, an error is produced.
% XXXX: near future: if the types used within an unknown
% call are all primitive types, aliases cannot be created
% anyway, and analysis could proceed. Not yet implemented.
:- pred lookup_call_alias( pred_proc_id, module_info, ka_fixpoint_table,
ka_fixpoint_table, alias_as ).
:- mode lookup_call_alias( in, in, in, out, out) is det.
lookup_call_alias( PRED_PROC_ID, HLDS, FPtable0, FPtable, Alias) :-
(
ka_fixpoint_table_get_as( PRED_PROC_ID, AL, FPtable0, FPtable1)
->
FPtable = FPtable1,
Alias = AL
;
module_info_pred_proc_info( HLDS, PRED_PROC_ID, PredInfo,
ProcInfo),
proc_info_possible_aliases(ProcInfo, MaybeAliases),
(
MaybeAliases = yes( SomeAL)
->
FPtable = FPtable0,
Alias = SomeAL
;
PRED_PROC_ID = proc(PRED_ID, PROC_ID),
pred_info_name(PredInfo, PNAME),
pred_id_to_int(PRED_ID, IPRED_ID),
proc_id_to_int(PROC_ID, IPROC_ID),
string__int_to_string(IPRED_ID, SPRED_ID),
string__int_to_string(IPROC_ID, SPROC_ID),
string__append_list(["(ka) lookup alias failed for ",PNAME,"(",SPRED_ID, ",", SPROC_ID, ")"], ErrMsg),
error(ErrMsg)
)
).
:- pred rename_call_alias( pred_proc_id, module_info, list(prog_var),
alias_as, alias_as).
:- mode rename_call_alias( in, in, in, in, out) is det.
rename_call_alias( PRED_PROC_ID, HLDS, ARGS, Ain, Aout ):-
module_info_pred_proc_info( HLDS, PRED_PROC_ID, _P, ProcInfo),
proc_info_headvars(ProcInfo, Headvars),
map__from_corresponding_lists(Headvars,ARGS,Dict),
ka_alias_as__rename( Dict, Ain, Aout ).
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
% easy stuff
% once the abstract alias substitution is computed for
% a procedure, one must simply update the proc-information
% of that procedure.
:- pred update_alias_in_module_info(ka_util__ka_fixpoint_table,
pred_proc_id, module_info,
module_info).
:- mode update_alias_in_module_info(in, in, in, out) is det.
update_alias_in_module_info( FPtable, PRED_PROC_ID, HLDSin, HLDSout) :-
module_info_pred_proc_info(HLDSin, PRED_PROC_ID, PredInfo, ProcInfo),
ka_fixpoint_table_get_final_as( PRED_PROC_ID, ALIAS_AS, FPtable),
proc_info_set_possible_aliases( ProcInfo, ALIAS_AS, NewProcInfo),
module_info_set_pred_proc_info(HLDSin, PRED_PROC_ID, PredInfo,
NewProcInfo, HLDSout).
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
% make the interface
:- import_module globals, modules, passes_aux, bool, options.
:- import_module varset.
:- import_module mercury_to_mercury.
% inspiration taken from termination.m
:- pred ka_run__make_ka_interface( module_info, io__state, io__state ).
:- mode ka_run__make_ka_interface( in, di, uo ) is det.
ka_run__make_ka_interface( HLDS ) -->
{ module_info_name( HLDS, ModuleName ) },
modules__module_name_to_file_name( ModuleName, ".opt.ka", bool__no, KaFileName),
globals__io_lookup_bool_option(verbose, Verbose),
maybe_write_string(Verbose, "% -> writing possible aliases to `"),
maybe_write_string(Verbose, KaFileName ),
maybe_write_string(Verbose, "'..."),
maybe_flush_output(Verbose),
io__open_output( KaFileName, KaFileRes ),
(
{ KaFileRes = ok(KaFile) },
io__set_output_stream( KaFile, OldStream ),
ka_run__make_ka_interface_2( HLDS ),
io__set_output_stream( OldStream, _ ),
io__close_output( KaFile ),
maybe_write_string(Verbose, " done.\n"),
maybe_flush_output(Verbose)
;
{ KaFileRes = error( IOError ) },
maybe_write_string(Verbose, " failed!\n"),
maybe_flush_output(Verbose),
{ io__error_message( IOError, IOErrorMsg ) },
io__write_strings(["Error opening file `",
KaFileName, "' for output: ", IOErrorMsg]),
io__set_exit_status(1)
).
:- pred ka_run__make_ka_interface_2( module_info,
io__state, io__state).
:- mode ka_run__make_ka_interface_2( in, di, uo) is det.
ka_run__make_ka_interface_2( HLDS ) -->
{ module_info_name( HLDS, ModuleName ) },
{ module_info_predids( HLDS, PredIds ) },
{ module_info_get_special_pred_map( HLDS, MAP ) },
{ map__values( MAP, SpecPredIds ) },
io__write_string(":- module "),
mercury_output_sym_name( ModuleName ),
io__write_string(".\n\n"),
io__write_string(":- interface. \n"),
list__foldl( make_ka_interface_pred(HLDS, SpecPredIds), PredIds ).
:- pred ka_run__make_ka_interface_pred(module_info, list(pred_id),pred_id,
io__state, io__state).
:- mode ka_run__make_ka_interface_pred( in, in, in, di ,uo) is det.
ka_run__make_ka_interface_pred( HLDS, SpecPredIds, PredId ) -->
{ module_info_pred_info( HLDS, PredId, PredInfo ) },
(
{ pred_info_is_exported( PredInfo ) }
->
(
{ list__member( PredId, SpecPredIds ) }
->
[]
;
{ pred_info_exported_procids( PredInfo , ProcIds ) } ,
{ pred_info_procedures( PredInfo, ProcTable ) },
list__foldl( make_ka_interface_pred_proc( PredInfo, ProcTable),
ProcIds )
)
;
[]
).
:- pred ka_run__make_ka_interface_pred_proc( pred_info, proc_table, proc_id,
io__state, io__state).
:- mode ka_run__make_ka_interface_pred_proc( in, in, in, di, uo) is det.
ka_run__make_ka_interface_pred_proc( PredInfo, ProcTable, ProcId) -->
io__write_string(":- pragma ka_alias_info("),
% write a simple predicate declaration
{ varset__init( InitVarSet ) },
{ pred_info_name( PredInfo, PredName ) },
{ pred_info_get_is_pred_or_func( PredInfo, PredOrFunc ) },
{ pred_info_module( PredInfo, ModuleName ) },
{ pred_info_context( PredInfo, Context ) },
{ SymName = qualified( ModuleName, PredName ) },
{ map__lookup( ProcTable, ProcId, ProcInfo ) },
{ proc_info_declared_argmodes( ProcInfo, Modes ) },
(
{ PredOrFunc = predicate },
mercury_output_pred_mode_subdecl( InitVarSet, SymName, Modes,
std_util__no, Context )
;
{ PredOrFunc = function },
{ pred_args_to_func_args( Modes, FuncModes, RetMode ) },
mercury_output_func_mode_subdecl( InitVarSet, SymName,
FuncModes, RetMode, std_util__no, Context )
),
io__write_string(", "),
% write headvars vars(HeadVar__1, ... HeadVar__n)
{ proc_info_varset(ProcInfo, ProgVarset) },
{ proc_info_headvars(ProcInfo, HeadVars) },
io__write_string("vars("),
mercury_output_vars(HeadVars, ProgVarset, no),
io__write_string(")"),
io__write_string(", "),
% write alias information
{ proc_info_possible_aliases(ProcInfo, MaybeAliases) },
ka_alias_as__print_maybe_interface_aliases( MaybeAliases, ProcInfo),
io__write_string(").\n").
%-------------------------------------------------------------------%
%-------------------------------------------------------------------%
% ensure loaded interfaces.
:- import_module term, set, prog_io, globals, prog_out, prog_io_util.
:- import_module hlds_out, assoc_list, mode_util.
% load interfaces of the imported modules.
% If some interface file appears to be unavailable, a warning
% is generated, and probably the code will fail at some later
% point.
:- pred ka_run__ensure_loaded_interfaces( module_info, module_info,
io__state, io__state).
:- mode ka_run__ensure_loaded_interfaces( in, out, di, uo) is det.
ka_run__ensure_loaded_interfaces( HLDS0, HLDS) -->
{ module_info_get_imported_module_specifiers( HLDS0, ModSpecs ) },
{ set__to_sorted_list( ModSpecs, LModSpecs ) },
list__foldl2( load_interface, LModSpecs, HLDS0, HLDS).
:- pred load_interface( module_specifier, module_info, module_info,
io__state, io__state).
:- mode load_interface( in, in, out, di, uo) is det.
load_interface( ModuleSpec, HLDS0, HLDS ) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
module_name_to_file_name( ModuleSpec, ".opt.ka", no, FileName ),
maybe_write_string(VeryVerbose, "% Reading `"),
maybe_write_string(VeryVerbose, FileName ),
maybe_write_string(VeryVerbose, "'... "),
maybe_flush_output(VeryVerbose),
prog_io__read_module( FileName, ModuleSpec, yes, Err, _ModuleName,
Msgs, Items),
(
{ Err = fatal }
->
maybe_write_string(VeryVerbose, "fatal error(s).\n")
;
{ Err = yes }
->
maybe_write_string(VeryVerbose, "parse_error(s).\n")
;
maybe_write_string(VeryVerbose, "successfull parse.\n")
),
prog_out__write_messages(Msgs),
(
{ Err = fatal }
->
maybe_write_string(VeryVerbose, "% Continuing... errors might occur later.\n")
;
{ Err = yes }
->
maybe_write_string(VeryVerbose, "% Continuing... errors might occur later.\n")
;
maybe_write_string(VeryVerbose, "% Cool!\n")
),
list__foldl2( add_item_from_opt_ka, Items, HLDS0, HLDS ).
:- pred add_item_from_opt_ka( item_and_context, module_info, module_info,
io__state, io__state ).
:- mode add_item_from_opt_ka( in, in, out, di, uo) is det.
add_item_from_opt_ka( Item - _Context, HLDS0, HLDS ) -->
(
{ Item = pragma(Pragma) }
->
add_pragma_item_from_opt_ka( Pragma , HLDS0, HLDS)
;
prog_io_util__report_warning(
"Only pragma ka_alias_info allowed in `.opt.ka' file.") ,
{ HLDS = HLDS0 }
).
:- pred add_pragma_item_from_opt_ka( pragma_type, module_info, module_info,
io__state, io__state).
:- mode add_pragma_item_from_opt_ka( in, in, out, di, uo) is det.
add_pragma_item_from_opt_ka( Pragma, HLDS0, HLDS) -->
(
{ Pragma = ka_alias_info( PredOrFunc, SymName, Modes,
HeadVars, MaybeAlias) }
->
add_pragma_possible_aliases_info( PredOrFunc, SymName, Modes,
HeadVars, MaybeAlias, HLDS0, HLDS)
;
prog_io_util__report_warning(
"Only pragma ka_alias_info allowed in `.opt.ka' file.") ,
{ HLDS = HLDS0 }
).
:- pred add_pragma_possible_aliases_info( pred_or_func, sym_name, list(mode),
list(var(T)), maybe(alias_as),
module_info, module_info,
io__state, io__state).
:- mode add_pragma_possible_aliases_info( in, in, in, in, in, in, out, di, uo)
is det.
add_pragma_possible_aliases_info(_, _, _, _, no, Module, Module) --> [].
add_pragma_possible_aliases_info(PredOrFunc,SymName, Modes,
HeadVars, yes(AliasAS),
Module0, Module) -->
{ module_info_get_predicate_table(Module0, Preds) },
{ list__length(Modes, Arity) },
(
{ predicate_table_search_pf_sym_arity( Preds,
PredOrFunc, SymName, Arity, PredIds) },
{ PredIds \= [] }
->
(
{ PredIds = [PredId] }
->
{ module_info_preds(Module0, PredTable0) },
{ map__lookup(PredTable0, PredId, PredInfo0) },
{ pred_info_procedures(PredInfo0, ProcTable0) },
{ map__to_assoc_list(ProcTable0, ProcList) },
(
{ get_procedure_matching_declmodes( ProcList,
Modes, Module0, ProcId) }
->
{ map__lookup(ProcTable0, ProcId, ProcInfo0) },
{ proc_info_headvars(ProcInfo0, ProcHeadVars) },
{ list__map( term__coerce_var, HeadVars, CHeadVars )},
{ map__from_corresponding_lists(CHeadVars,
ProcHeadVars, MapHeadVars) },
{ ka_alias_as__rename( MapHeadVars, AliasAS,
RenAliasAS) },
{ proc_info_set_possible_aliases( ProcInfo0,
RenAliasAS, ProcInfo ) },
{ map__det_update(ProcTable0, ProcId, ProcInfo,
ProcTable) },
{ pred_info_set_procedures(PredInfo0, ProcTable,
PredInfo) },
{ map__det_update(PredTable0, PredId, PredInfo,
PredTable) },
{ module_info_set_preds( Module0, PredTable, Module) }
;
% { module_info_incr_errors(Module0, Module) },
io__write_string(
"Error: `:- pragma ka_alias_info' "),
io__write_string(
"declaration for undeclared mode of "),
hlds_out__write_simple_call_id(PredOrFunc,
SymName/Arity),
io__write_string(".\n"),
{ Module = Module0 },
io__set_exit_status(1)
)
;
io__write_string("Error: ambiguous predicate name "),
hlds_out__write_simple_call_id(PredOrFunc, SymName/Arity),
io__write_string(" in `pragma ka_alias_info'.\n"),
{ Module = Module0 },
io__set_exit_status(1)
% { module_info_incr_errors(Module0, Module) }
)
;
io__write_string("Error: no corresponding predicate found "),
hlds_out__write_simple_call_id(PredOrFunc, SymName/Arity),
io__write_string(" in `pragma ka_alias_info'.\n"),
{ Module = Module0 },
io__set_exit_status(1)
% { module_info_incr_errors(Module0, Module) }
).
% Find the procedure with declared argmodes which match the ones
% we want. If there was no mode declaration, then use the inferred
% argmodes.
% Copy/pasted from make_hlds.m
:- pred get_procedure_matching_declmodes(assoc_list(proc_id, proc_info),
list(mode), module_info, proc_id).
:- mode get_procedure_matching_declmodes(in, in, in, out) is semidet.
get_procedure_matching_declmodes([P|Procs], Modes, ModuleInfo, OurProcId) :-
P = ProcId - ProcInfo,
proc_info_declared_argmodes(ProcInfo, ArgModes),
( mode_list_matches(Modes, ArgModes, ModuleInfo) ->
OurProcId = ProcId
;
get_procedure_matching_declmodes(Procs, Modes, ModuleInfo,
OurProcId)
).
:- pred mode_list_matches(list(mode), list(mode), module_info).
:- mode mode_list_matches(in, in, in) is semidet.
mode_list_matches([], [], _).
mode_list_matches([Mode1 | Modes1], [Mode2 | Modes2], ModuleInfo) :-
% Use mode_get_insts_semidet instead of mode_get_insts to avoid
% aborting if there are undefined modes.
mode_get_insts_semidet(ModuleInfo, Mode1, Inst1, Inst2),
mode_get_insts_semidet(ModuleInfo, Mode2, Inst1, Inst2),
mode_list_matches(Modes1, Modes2, ModuleInfo).
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list