Files
mercury/compiler/passes_aux.m
Zoltan Somogyi 3c2a19adfd Make closures always include layout information, not just in grades in which
Estimated hours taken: 51

Make closures always include layout information, not just in grades in which
typeinfo liveness is turned on. This requires separating two notions,
which were previously combined:

-	Body typeinfo liveness means that when a variable X is live, any
	typeinfo variables describing type variables that occur in the type
	of X must also be live.

-	Interface typeinfo liveness means that when the input arguments
	of a procedure include a polymorphically typed variable (e.g. X),
	typeinfo variables describing type variables that occur in the type
	of X must also be among the arguments.

This change turns on interface typeinfo liveness for procedures that either
have their address taken in the current module, or are exported and thus may
have their address taken in some other module.

compiler/hlds_pred.m:
	Centralize decisions wrt whether procedure interfaces and bodies
	use typeinfo liveness here.

compiler/options.m:
	Rename the typeinfo_liveness option as body_typeinfo_liveness,
	since this reflects its new function.

compiler/call_gen.m:
compiler/higher_order.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/unused_args.m:
	Use hlds_pred.m to make decisions about liveness.

compiler/lambda.m:
	Always include the relevant typeinfos in the interfaces of procedures
	created for lambdas.

compiler/continuation_info.m:
compiler/stack_layout.m:
compiler/unify_gen.m:
	Modify the predicates that record and use layout information about
	closures to always do so, since the necessary information is now
	always available about the interfaces of procedures which can be
	put into closures. Previously, they only did so if typeinfo_liveness
	was set.

	Also, generate information about the types of the variables in a
	closure from the pred_info's arg types field, not from the proc_info's
	var types field, because unlike the latter, it is valid even for
	imported predicates.

compiler/hlds_out.m:
	Print the non-clause-related information in the clauses_info part
	of a pred_info (e.g. the type parameters) even if the predicate
	has no actual clauses. Simplify the code a bit by getting rid of
	a duplicate test.

compiler/middle_rec.m:
	Require that the code generated for the base case not refer to any
	stack slots if this way of generating code is to be used. This is
	necessary because the base case is executed when the current procedure
	has no stack frame, and thus any references to stack slots would
	refer to and possibly overwrite the data in another procedure's frame.
	In the absence of requiring body typeinfo liveness for exported
	procedures, such references were not generated; in its presence,
	they were. However, we now require only interface liveness for
	exported procedures, so we can still use middle recursion for them.

compiler/handle_options.m:
	Do not turn off middle_rec if (body) typeinfo liveness is turned on,
	now that the bug has been fixed. For polymorphic predicates, the base
	case will still contain references to stack slots, and thus the
	middle-rec optimization will not applied for them, but the optimization
	may apply to monomorphic predicates.

compiler/passes_aux.m:
	Add the ability to call compiler passes with the procedure id
	as well as the predicate id of the procedure they are passed.

tests/hard_coded/typeclasses/Mmakefile:
	Refer to --body-typeinfo-liveness instead of --typeinfo-liveness.
1999-08-13 01:43:50 +00:00

514 lines
16 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995-1999 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.
%-----------------------------------------------------------------------------%
% This file contains auxiliary routines for the passes
% of the front and back ends of the compiler.
% Author: zs
:- module passes_aux.
:- interface.
:- import_module hlds_module, hlds_pred, prog_data.
:- import_module io, std_util, list, bool.
%-----------------------------------------------------------------------------%
:- type task ---> update_proc(pred(
proc_info, module_info, proc_info))
; update_proc_predid(pred(
proc_info, pred_id, module_info, proc_info))
; update_proc_predprocid(pred(
proc_info, pred_id, proc_id,
module_info, proc_info))
; update_proc_io(pred(
pred_id, proc_id, module_info,
proc_info, proc_info, io__state, io__state))
; update_proc_error(pred(
pred_id, proc_id, module_info, module_info,
proc_info, proc_info, int, int,
io__state, io__state))
; update_pred_error(pred_error_task)
; update_module(pred(
proc_info, proc_info,
module_info, module_info))
; update_module_io(pred(
pred_id, proc_id, proc_info, proc_info,
module_info, module_info,
io__state, io__state))
% It would be better to use an existentially-quantified type
% rather than `univ' here, but the current version of Mercury
% doesn't support existentially-quantified types.
; update_module_cookie(pred(
pred_id, proc_id, proc_info, proc_info,
univ, univ, module_info, module_info),
univ)
.
:- type pred_error_task ==
pred(pred_id, module_info, module_info, pred_info, pred_info,
int, int, io__state, io__state).
/****************
Note that update_module_cookie causes some difficulties.
Ideally, it should be implemented using existential types:
:- type task --->
...
; some [T] update_module_cookie(pred(
pred_id, proc_id, proc_info, proc_info,
T, T, module_info, module_info),
T)
That would avoid the need for messing about with type_to_univ and
univ_to_type.
Originally, it was implemented by changing `task' to `task(T)':
:- type task(T) --->
...
; update_module_cookie(pred(
pred_id, proc_id, proc_info, proc_info,
T, T, module_info, module_info),
T)
but that is not a good solution, because it causes a lot of warnings
about unbound type variables.
****************/
:- inst task = bound(( update_proc(pred(in, in, out) is det)
; update_proc_predid(pred(in, in, in, out) is det)
; update_proc_predprocid(pred(in, in, in, in, out)
is det)
; update_proc_io(pred(in, in, in, in, out, di, uo)
is det)
; update_proc_error(pred(in, in, in, out, in, out,
out, out, di, uo) is det)
; update_pred_error(pred(in, in, out, in, out,
out, out, di, uo) is det)
; update_module(pred(in, out, in, out) is det)
; update_module_io(pred(in, in, in, out,
in, out, di, uo) is det)
; update_module_cookie(pred(in, in, in, out, in, out,
in, out) is det, ground)
)).
:- inst pred_error_task =
(pred(in, in, out, in, out, out, out, di, uo) is det).
:- mode task :: task -> task.
:- pred process_all_nonimported_procs(task, module_info, module_info,
io__state, io__state).
:- mode process_all_nonimported_procs(task, in, out, di, uo) is det.
% Process procedures for which a given test succeeds.
:- pred process_matching_nonimported_procs(task, pred(pred_info),
module_info, module_info, io__state, io__state).
:- mode process_matching_nonimported_procs(task, pred(in) is semidet,
in, out, di, uo) is det.
:- pred process_matching_nonimported_procs(task, task, pred(pred_info),
module_info, module_info, io__state, io__state).
:- mode process_matching_nonimported_procs(task, out(task),
pred(in) is semidet, in, out, di, uo) is det.
:- pred process_all_nonimported_nonaditi_procs(task, module_info, module_info,
io__state, io__state).
:- mode process_all_nonimported_nonaditi_procs(task, in, out, di, uo) is det.
:- pred process_all_nonimported_nonaditi_procs(task, task,
module_info, module_info, io__state, io__state).
:- mode process_all_nonimported_nonaditi_procs(task, out(task),
in, out, di, uo) is det.
:- pred process_all_nonimported_procs(task, task,
module_info, module_info, io__state, io__state).
:- mode process_all_nonimported_procs(task, out(task), in, out, di, uo) is det.
:- pred write_pred_progress_message(string::in, pred_id::in, module_info::in,
io__state::di, io__state::uo) is det.
:- pred write_proc_progress_message(string::in, pred_id::in, proc_id::in,
module_info::in, io__state::di, io__state::uo) is det.
:- pred maybe_report_stats(bool::in, io__state::di, io__state::uo) is det.
:- pred maybe_write_string(bool::in, string::in,
io__state::di, io__state::uo) is det.
:- pred maybe_flush_output(bool::in, io__state::di, io__state::uo) is det.
:- pred report_error(string::in, io__state::di, io__state::uo) is det.
:- pred invoke_system_command(string::in, bool::out,
io__state::di, io__state::uo) is det.
:- pred maybe_report_sizes(module_info::in, io__state::di, io__state::uo)
is det.
:- pred report_pred_proc_id(module_info, pred_id, proc_id,
maybe(prog_context), prog_context, io__state, io__state).
:- mode report_pred_proc_id(in, in, in, in, out, di, uo) is det.
:- pred report_pred_name_mode(pred_or_func, string, list((mode)),
io__state, io__state).
:- mode report_pred_name_mode(in, in, in, di, uo) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module options, globals, hlds_out, prog_out, mode_util.
:- import_module mercury_to_mercury.
:- import_module varset.
:- import_module int, map, tree234, require.
process_all_nonimported_procs(Task, ModuleInfo0, ModuleInfo) -->
{ True = lambda([_PredInfo::in] is semidet, true) },
process_matching_nonimported_procs(Task, True,
ModuleInfo0, ModuleInfo).
process_all_nonimported_nonaditi_procs(Task, ModuleInfo0, ModuleInfo) -->
{ NotAditi = lambda([PredInfo::in] is semidet, (
\+ hlds_pred__pred_info_is_aditi_relation(PredInfo)
)) },
process_matching_nonimported_procs(Task, NotAditi,
ModuleInfo0, ModuleInfo).
process_all_nonimported_nonaditi_procs(Task0, Task,
ModuleInfo0, ModuleInfo) -->
{ NotAditi = lambda([PredInfo::in] is semidet, (
\+ hlds_pred__pred_info_is_aditi_relation(PredInfo)
)) },
process_matching_nonimported_procs(Task0, Task, NotAditi,
ModuleInfo0, ModuleInfo).
process_all_nonimported_procs(Task0, Task, ModuleInfo0, ModuleInfo) -->
{ True = lambda([_PredInfo::in] is semidet, true) },
process_matching_nonimported_procs(Task0, Task, True,
ModuleInfo0, ModuleInfo).
process_matching_nonimported_procs(Task, Filter, ModuleInfo0, ModuleInfo) -->
{ module_info_predids(ModuleInfo0, PredIds) },
( { Task = update_pred_error(Pred) } ->
list__foldl2(process_nonimported_pred(Pred, Filter), PredIds,
ModuleInfo0, ModuleInfo)
;
process_nonimported_procs_in_preds(PredIds, Task, _, Filter,
ModuleInfo0, ModuleInfo)
).
process_matching_nonimported_procs(Task0, Task, Filter,
ModuleInfo0, ModuleInfo) -->
{ module_info_predids(ModuleInfo0, PredIds) },
process_nonimported_procs_in_preds(PredIds, Task0, Task, Filter,
ModuleInfo0, ModuleInfo).
:- pred process_nonimported_pred(pred_error_task, pred(pred_info), pred_id,
module_info, module_info, io__state, io__state).
:- mode process_nonimported_pred(in(pred_error_task), pred(in) is semidet, in,
in, out, di, uo) is det.
process_nonimported_pred(Task, Filter, PredId, ModuleInfo0, ModuleInfo,
IO0, IO) :-
module_info_pred_info(ModuleInfo0, PredId, PredInfo0),
(
( pred_info_is_imported(PredInfo0)
; \+ call(Filter, PredInfo0)
)
->
ModuleInfo = ModuleInfo0,
IO = IO0
;
call(Task, PredId, ModuleInfo0, ModuleInfo1,
PredInfo0, PredInfo, WarnCnt, ErrCnt, IO0, IO1),
module_info_set_pred_info(ModuleInfo1,
PredId, PredInfo, ModuleInfo2),
passes_aux__handle_errors(WarnCnt, ErrCnt,
ModuleInfo2, ModuleInfo, IO1, IO)
).
:- pred process_nonimported_procs_in_preds(list(pred_id), task, task,
pred(pred_info), module_info, module_info, io__state, io__state).
:- mode process_nonimported_procs_in_preds(in, task, out(task),
pred(in) is semidet, in, out, di, uo) is det.
process_nonimported_procs_in_preds([], Task, Task, _, ModuleInfo, ModuleInfo)
--> [].
process_nonimported_procs_in_preds([PredId | PredIds], Task0, Task, Filter,
ModuleInfo0, ModuleInfo) -->
{ module_info_preds(ModuleInfo0, PredTable) },
{ map__lookup(PredTable, PredId, PredInfo) },
( { call(Filter, PredInfo) } ->
{ pred_info_non_imported_procids(PredInfo, ProcIds) },
process_nonimported_procs(ProcIds, PredId, Task0, Task1,
ModuleInfo0, ModuleInfo1)
;
{ ModuleInfo1 = ModuleInfo0 },
{ Task1 = Task0 }
),
process_nonimported_procs_in_preds(PredIds, Task1, Task, Filter,
ModuleInfo1, ModuleInfo).
:- pred process_nonimported_procs(list(proc_id), pred_id, task, task,
module_info, module_info, io__state, io__state).
:- mode process_nonimported_procs(in, in, task, out(task), in, out, di, uo)
is det.
process_nonimported_procs([], _PredId, Task, Task,
ModuleInfo, ModuleInfo, State, State).
process_nonimported_procs([ProcId | ProcIds], PredId, Task0, Task,
ModuleInfo0, ModuleInfo, State0, State) :-
module_info_preds(ModuleInfo0, Preds0),
map__lookup(Preds0, PredId, Pred0),
pred_info_procedures(Pred0, Procs0),
map__lookup(Procs0, ProcId, Proc0),
(
Task0 = update_module(Closure),
call(Closure, Proc0, Proc, ModuleInfo0, ModuleInfo8),
Task1 = Task0,
State9 = State0
;
Task0 = update_module_io(Closure),
call(Closure, PredId, ProcId, Proc0, Proc,
ModuleInfo0, ModuleInfo8, State0, State9),
Task1 = Task0
;
Task0 = update_proc(Closure),
call(Closure, Proc0, ModuleInfo0, Proc),
ModuleInfo8 = ModuleInfo0,
Task1 = Task0,
State9 = State0
;
Task0 = update_proc_predid(Closure),
call(Closure, Proc0, PredId, ModuleInfo0, Proc),
ModuleInfo8 = ModuleInfo0,
Task1 = Task0,
State9 = State0
;
Task0 = update_proc_predprocid(Closure),
call(Closure, Proc0, PredId, ProcId, ModuleInfo0, Proc),
ModuleInfo8 = ModuleInfo0,
Task1 = Task0,
State9 = State0
;
Task0 = update_proc_io(Closure),
call(Closure, PredId, ProcId, ModuleInfo0,
Proc0, Proc, State0, State9),
ModuleInfo8 = ModuleInfo0,
Task1 = Task0
;
Task0 = update_proc_error(Closure),
call(Closure, PredId, ProcId, ModuleInfo0, ModuleInfo1,
Proc0, Proc, WarnCnt, ErrCnt, State0, State1),
Task1 = Task0,
passes_aux__handle_errors(WarnCnt, ErrCnt,
ModuleInfo1, ModuleInfo8, State1, State9)
;
Task0 = update_pred_error(_),
error("passes_aux:process_non_imported_procs")
;
Task0 = update_module_cookie(Closure, Cookie0),
call(Closure, PredId, ProcId, Proc0, Proc,
Cookie0, Cookie1, ModuleInfo0, ModuleInfo8),
Task1 = update_module_cookie(Closure, Cookie1),
State9 = State0
),
% If the pass changed the module_info, it may have changed
% the pred table or the proc table for this pred_id. Don't
% take any chances.
module_info_preds(ModuleInfo8, Preds8),
map__lookup(Preds8, PredId, Pred8),
pred_info_procedures(Pred8, Procs8),
map__det_update(Procs8, ProcId, Proc, Procs),
pred_info_set_procedures(Pred8, Procs, Pred),
map__det_update(Preds8, PredId, Pred, Preds),
module_info_set_preds(ModuleInfo8, Preds, ModuleInfo9),
process_nonimported_procs(ProcIds, PredId, Task1, Task,
ModuleInfo9, ModuleInfo, State9, State).
write_pred_progress_message(Message, PredId, ModuleInfo) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
( { VeryVerbose = yes } ->
io__write_string(Message),
hlds_out__write_pred_id(ModuleInfo, PredId),
io__write_string("\n")
;
[]
).
write_proc_progress_message(Message, PredId, ProcId, ModuleInfo) -->
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
( { VeryVerbose = yes } ->
io__write_string(Message),
hlds_out__write_pred_proc_id(ModuleInfo, PredId, ProcId),
io__write_string("\n")
;
[]
).
maybe_report_stats(yes) --> io__report_stats.
maybe_report_stats(no) --> [].
maybe_write_string(yes, String) --> io__write_string(String).
maybe_write_string(no, _) --> [].
maybe_flush_output(yes) --> io__flush_output.
maybe_flush_output(no) --> [].
report_error(ErrorMessage) -->
io__write_string("Error: "),
io__write_string(ErrorMessage),
io__write_string("\n"),
io__set_exit_status(1).
:- pred passes_aux__handle_errors(int, int, module_info, module_info,
io__state, io__state).
:- mode passes_aux__handle_errors(in, in, in, out, di, uo) is det.
passes_aux__handle_errors(WarnCnt, ErrCnt, ModuleInfo1, ModuleInfo8,
State1, State9) :-
globals__io_lookup_bool_option(halt_at_warn, HaltAtWarn,
State1, State2),
(
(
ErrCnt > 0
;
WarnCnt > 0,
HaltAtWarn = yes
)
->
io__set_exit_status(1, State2, State9),
module_info_incr_errors(ModuleInfo1, ModuleInfo8)
;
ModuleInfo8 = ModuleInfo1,
State9 = State2
).
invoke_system_command(Command, Succeeded) -->
globals__io_lookup_bool_option(verbose, Verbose),
( { Verbose = yes } ->
io__write_string("% Invoking system command `"),
io__write_string(Command),
io__write_string("'...\n"),
io__flush_output
;
[]
),
io__call_system(Command, Result),
( { Result = ok(0) } ->
maybe_write_string(Verbose, "% done.\n"),
{ Succeeded = yes }
; { Result = ok(_) } ->
report_error("system command returned non-zero exit status."),
{ Succeeded = no }
;
report_error("unable to invoke system command."),
{ Succeeded = no }
).
maybe_report_sizes(HLDS) -->
globals__io_lookup_bool_option(statistics, Statistics),
( { Statistics = yes } ->
report_sizes(HLDS)
;
[]
).
:- pred report_sizes(module_info, io__state, io__state).
:- mode report_sizes(in, di, uo) is det.
report_sizes(ModuleInfo) -->
{ module_info_preds(ModuleInfo, Preds) },
tree_stats("Pred table", Preds),
{ module_info_types(ModuleInfo, Types) },
tree_stats("Type table", Types),
{ module_info_ctors(ModuleInfo, Ctors) },
tree_stats("Constructor table", Ctors).
:- pred tree_stats(string, map(_K, _V), io__state, io__state).
:- mode tree_stats(in, in, di, uo) is det.
tree_stats(Description, Tree) -->
{ map__count(Tree, Count) },
io__write_string(Description),
io__write_string(": count = "),
io__write_int(Count),
io__write_string("\n").
%-----------------------------------------------------------------------------%
report_pred_proc_id(ModuleInfo, PredId, ProcId, MaybeContext, Context) -->
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
PredInfo, ProcInfo) },
{ pred_info_name(PredInfo, PredName) },
{ pred_info_arity(PredInfo, Arity) },
{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
{ proc_info_context(ProcInfo, Context) },
{ proc_info_argmodes(ProcInfo, ArgModes0) },
% We need to strip off the extra type_info arguments inserted at the
% front by polymorphism.m - we only want the last `PredArity' of them.
%
{ list__length(ArgModes0, NumArgModes) },
{ NumToDrop is NumArgModes - Arity },
( { list__drop(NumToDrop, ArgModes0, ArgModes1) } ->
{ ArgModes = ArgModes1 }
;
{ error("report_pred_proc_id: list__drop failed") }
),
(
{ MaybeContext = yes(OutContext) }
;
{ MaybeContext = no },
{ OutContext = Context }
),
prog_out__write_context(OutContext),
io__write_string("In `"),
report_pred_name_mode(PredOrFunc, PredName, ArgModes),
io__write_string("':\n").
report_pred_name_mode(predicate, PredName, ArgModes) -->
io__write_string(PredName),
( { ArgModes \= [] } ->
{ varset__init(InstVarSet) }, % XXX inst var names
io__write_string("("),
{ strip_builtin_qualifiers_from_mode_list(ArgModes,
ArgModes1) },
mercury_output_mode_list(ArgModes1, InstVarSet),
io__write_string(")")
;
[]
).
report_pred_name_mode(function, FuncName, ArgModes) -->
{ varset__init(InstVarSet) }, % XXX inst var names
{ strip_builtin_qualifiers_from_mode_list(ArgModes, ArgModes1) },
{ pred_args_to_func_args(ArgModes1, FuncArgModes, FuncRetMode) },
io__write_string(FuncName),
( { FuncArgModes \= [] } ->
io__write_string("("),
mercury_output_mode_list(FuncArgModes, InstVarSet),
io__write_string(")")
;
[]
),
io__write_string(" = "),
mercury_output_mode(FuncRetMode, InstVarSet).
%-----------------------------------------------------------------------------%