Files
mercury/compiler/lambda.m
Zoltan Somogyi 649b6908c3 Rename branch_delay_slot to have_delay_slot.
Estimated hours taken: 8

options.m:
	Rename branch_delay_slot to have_delay_slot.
	Set optimize_delay_slot in -O2 only if have_delay_slot was set earlier.
	This is possible now because the default optimization level is now
	set in mc.

mercury_compile:
	Change verbose output a bit to be more consistent.

dead_proc_elim:
	Export the predicates that will eventually be needed by inlining.m.

inlining.m:
	Use the information about the number of times each procedure is called
	to inline local nonrecursive procedures that are called exactly once.
	EXCEPT that this is turned off at the moment, since the inlining of
	parse_dcg_goal_2 in prog_io, which this change enables, causes the
	compiler to emit incorrect code.

prog_io:
	Moved the data type definitions to prog_data. (Even though prog_io.m
	is ten times the size of prog_data.m, the sizes of the .c files are
	not too dissimilar.)
1996-04-24 01:00:23 +00:00

348 lines
13 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995 University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
% file: lambda.m
% main author: fjh
% This module is a pass over the HLDS to deal with lambda expressions.
%
% Lambda expressions are converted into separate predicates, so for
% example we translate
%
% :- pred p(int::in) is det.
% p(X) :-
% V__1 = lambda([Y::out] is nondet, q(Y, X))),
% solutions(V__1, List),
% ...
% :- pred q(int::out, int::in) is nondet.
%
% into
%
% p(X) :-
% V__1 = '__LambdaGoal__1'(X)
% solutions(V__1, List),
% ...
%
% :- pred '__LambdaGoal__1'(int::in, int::out) is nondet.
% '__LambdaGoal__1'(X, Y) :- q(Y, X).
%-----------------------------------------------------------------------------%
:- module (lambda).
:- interface.
:- import_module hlds_module, hlds_pred, prog_data.
:- import_module list, set, map, term, varset.
:- pred lambda__process_pred(pred_id, module_info, module_info).
:- mode lambda__process_pred(in, in, out) is det.
:- pred lambda__transform_lambda(list(var), list(mode), determinism,
set(var), hlds__goal, unification,
varset, map(var, type), tvarset, module_info,
unify_rhs, unification, module_info).
:- mode lambda__transform_lambda(in, in, in, in, in, in, in, in, in, in,
out, out, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, hlds_data, make_hlds.
:- import_module prog_util, mode_util, inst_match, llds.
:- import_module bool, string, std_util, require.
:- type lambda_info --->
lambda_info(
varset, % from the proc_info
map(var, type), % from the proc_info
tvarset, % from the proc_info
module_info
).
%-----------------------------------------------------------------------------%
% This whole section just traverses the module structure.
lambda__process_pred(PredId, ModuleInfo0, ModuleInfo) :-
module_info_pred_info(ModuleInfo0, PredId, PredInfo),
pred_info_procids(PredInfo, ProcIds),
lambda__process_procs(PredId, ProcIds, ModuleInfo0, ModuleInfo).
:- pred lambda__process_procs(pred_id, list(proc_id), module_info, module_info).
:- mode lambda__process_procs(in, in, in, out) is det.
lambda__process_procs(_PredId, [], ModuleInfo, ModuleInfo).
lambda__process_procs(PredId, [ProcId | ProcIds], ModuleInfo0, ModuleInfo) :-
lambda__process_proc(PredId, ProcId, ModuleInfo0, ModuleInfo1),
lambda__process_procs(PredId, ProcIds, ModuleInfo1, ModuleInfo).
:- pred lambda__process_proc(pred_id, proc_id, module_info, module_info).
:- mode lambda__process_proc(in, in, in, out) is det.
lambda__process_proc(PredId, ProcId, ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
lambda__process_proc_2(ProcInfo0, PredInfo0, ModuleInfo0,
ProcInfo, PredInfo1, ModuleInfo1),
pred_info_procedures(PredInfo1, ProcTable1),
map__set(ProcTable1, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo1, ProcTable, PredInfo),
module_info_preds(ModuleInfo1, PredTable1),
map__set(PredTable1, PredId, PredInfo, PredTable),
module_info_set_preds(ModuleInfo1, PredTable, ModuleInfo).
:- pred lambda__process_proc_2(proc_info, pred_info, module_info,
proc_info, pred_info, module_info).
:- mode lambda__process_proc_2(in, in, in, out, out, out) is det.
lambda__process_proc_2(ProcInfo0, PredInfo0, ModuleInfo0,
ProcInfo, PredInfo, ModuleInfo) :-
% grab the appropriate fields from the pred_info and proc_info
pred_info_typevarset(PredInfo0, TypeVarSet0),
proc_info_variables(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_goal(ProcInfo0, Goal0),
% process the goal
Info0 = lambda_info(VarSet0, VarTypes0, TypeVarSet0, ModuleInfo0),
lambda__process_goal(Goal0, Goal, Info0, Info),
Info = lambda_info(VarSet, VarTypes, TypeVarSet, ModuleInfo),
% set the new values of the fields in proc_info and pred_info
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
proc_info_set_variables(ProcInfo1, VarSet, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo).
:- pred lambda__process_goal(hlds__goal, hlds__goal,
lambda_info, lambda_info).
:- mode lambda__process_goal(in, out, in, out) is det.
lambda__process_goal(Goal0 - GoalInfo0, Goal) -->
lambda__process_goal_2(Goal0, GoalInfo0, Goal).
:- pred lambda__process_goal_2(hlds__goal_expr, hlds__goal_info,
hlds__goal, lambda_info, lambda_info).
:- mode lambda__process_goal_2(in, in, out, in, out) is det.
lambda__process_goal_2(unify(XVar, Y, Mode, Unification, Context), GoalInfo,
Unify - GoalInfo) -->
( { Y = lambda_goal(Vars, Modes, Det, LambdaGoal0) } ->
% for lambda expressions, we must convert the lambda expression
% into a new predicate
{ LambdaGoal0 = _ - GoalInfo0 },
{ goal_info_get_nonlocals(GoalInfo0, NonLocals0) },
lambda__process_lambda(Vars, Modes, Det, NonLocals0,
LambdaGoal0, Unification, Y1, Unification1),
{ Unify = unify(XVar, Y1, Mode, Unification1, Context) }
;
% ordinary unifications are left unchanged
{ Unify = unify(XVar, Y, Mode, Unification, Context) }
).
% the rest of the clauses just process goals recursively
lambda__process_goal_2(conj(Goals0), GoalInfo, conj(Goals) - GoalInfo) -->
lambda__process_goal_list(Goals0, Goals).
lambda__process_goal_2(disj(Goals0, FV), GoalInfo, disj(Goals, FV) - GoalInfo)
-->
lambda__process_goal_list(Goals0, Goals).
lambda__process_goal_2(not(Goal0), GoalInfo, not(Goal) - GoalInfo) -->
lambda__process_goal(Goal0, Goal).
lambda__process_goal_2(switch(Var, CanFail, Cases0, FV), GoalInfo,
switch(Var, CanFail, Cases, FV) - GoalInfo) -->
lambda__process_cases(Cases0, Cases).
lambda__process_goal_2(some(Vars, Goal0), GoalInfo,
some(Vars, Goal) - GoalInfo) -->
lambda__process_goal(Goal0, Goal).
lambda__process_goal_2(if_then_else(Vars, A0, B0, C0, FV), GoalInfo,
if_then_else(Vars, A, B, C, FV) - GoalInfo) -->
lambda__process_goal(A0, A),
lambda__process_goal(B0, B),
lambda__process_goal(C0, C).
lambda__process_goal_2(call(A,B,C,D,E,F,G), GoalInfo,
call(A,B,C,D,E,F,G) - GoalInfo) -->
[].
lambda__process_goal_2(pragma_c_code(A,B,C,D,E), GoalInfo,
pragma_c_code(A,B,C,D,E) - GoalInfo) -->
[].
:- pred lambda__process_goal_list(list(hlds__goal), list(hlds__goal),
lambda_info, lambda_info).
:- mode lambda__process_goal_list(in, out, in, out) is det.
lambda__process_goal_list([], []) --> [].
lambda__process_goal_list([Goal0 | Goals0], [Goal | Goals]) -->
lambda__process_goal(Goal0, Goal),
lambda__process_goal_list(Goals0, Goals).
:- pred lambda__process_cases(list(case), list(case),
lambda_info, lambda_info).
:- mode lambda__process_cases(in, out, in, out) is det.
lambda__process_cases([], []) --> [].
lambda__process_cases([case(ConsId, Goal0) | Cases0],
[case(ConsId, Goal) | Cases]) -->
lambda__process_goal(Goal0, Goal),
lambda__process_cases(Cases0, Cases).
:- pred lambda__process_lambda(list(var), list(mode), determinism,
set(var), hlds__goal, unification, unify_rhs, unification,
lambda_info, lambda_info).
:- mode lambda__process_lambda(in, in, in, in, in, in, out, out,
in, out) is det.
lambda__process_lambda(Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
Unification0, Functor, Unification, LambdaInfo0, LambdaInfo) :-
LambdaInfo0 = lambda_info(VarSet, VarTypes, TVarSet, ModuleInfo0),
lambda__transform_lambda(Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
Unification0, VarSet, VarTypes, TVarSet, ModuleInfo0,
Functor, Unification, ModuleInfo),
LambdaInfo = lambda_info(VarSet, VarTypes, TVarSet, ModuleInfo).
lambda__transform_lambda(Vars, Modes, Detism, OrigNonLocals0, LambdaGoal,
Unification0, VarSet, VarTypes, TVarSet, ModuleInfo0,
Functor, Unification, ModuleInfo) :-
(
Unification0 = construct(Var0, _, _, UniModes0)
->
Var = Var0,
UniModes = UniModes0
;
error("polymorphism__transform_lambda: wierd unification")
),
% Optimize a special case: replace
% `lambda([Y1, Y2, ...] is Detism, p(X1, X2, ..., Y1, Y2, ...))'
% where `p' has determinism `Detism' with
% `p(X1, X2, ...)'
%
% This optimization is only valid if the modes of the Xi are
% input, since only input arguments can be curried.
LambdaGoal = _ - LambdaGoalInfo,
goal_info_get_nonlocals(LambdaGoalInfo, NonLocals0),
set__delete_list(NonLocals0, Vars, NonLocals),
set__to_sorted_list(NonLocals, ArgVars1),
(
LambdaGoal = call(PredId0, ProcId0, CallVars, _, _, PredName, _)
- _,
list__remove_suffix(CallVars, Vars, InitialVars),
module_info_pred_proc_info(ModuleInfo0, PredId0, ProcId0, _,
Call_ProcInfo),
proc_info_interface_code_model(Call_ProcInfo, Call_CodeModel),
determinism_to_code_model(Detism, CodeModel),
% Check that the code models are compatible.
% Note that det is not compatible with semidet,
% and semidet is not compatible with nondet,
% since the arguments go in different registers.
% But det is compatible with nondet.
( CodeModel = Call_CodeModel
; CodeModel = model_non, Call_CodeModel = model_det
),
% check that the curried arguments are all input
proc_info_argmodes(Call_ProcInfo, Call_ArgModes),
list__length(InitialVars, NumInitialVars),
list__take(NumInitialVars, Call_ArgModes, CurriedArgModes),
\+ ( list__member(Mode, CurriedArgModes),
\+ mode_is_input(ModuleInfo0, Mode)
)
->
ArgVars = InitialVars,
PredId = PredId0,
ProcId = ProcId0,
unqualify_name(PredName, PName),
ModuleInfo = ModuleInfo0
;
% Prepare to create a new predicate for the lambda
% expression: work out the arguments, module name, predicate
% name, arity, arg types, determinism,
% context, status, etc. for the new predicate
ArgVars = ArgVars1,
list__append(ArgVars, Vars, AllArgVars),
module_info_name(ModuleInfo0, ModuleName),
module_info_next_lambda_count(ModuleInfo0, LambdaCount,
ModuleInfo1),
string__int_to_string(LambdaCount, LambdaCountStr),
string__append("__LambdaGoal__", LambdaCountStr, PName0),
string__append(ModuleName, PName0, PName),
PredName = unqualified(PName),
map__apply_to_list(AllArgVars, VarTypes, ArgTypes),
goal_info_context(LambdaGoalInfo, LambdaContext),
% the TVarSet is a superset of what it really ought be,
% but that shouldn't matter
lambda__uni_modes_to_modes(UniModes, OrigArgModes),
% We have to jump through hoops to work out the mode
% of the lambda predicate. For introduced
% type_info arguments, we use the mode "in". For the original
% non-local vars, we use the modes from `UniModes'.
% For the lambda var arguments at the end,
% we use the mode in the lambda expression.
list__length(ArgVars, NumArgVars),
In = user_defined_mode(unqualified("in"), []),
list__duplicate(NumArgVars, In, InModes),
map__from_corresponding_lists(ArgVars, InModes,
ArgModesMap),
set__delete_list(OrigNonLocals0, Vars, OrigNonLocals),
set__to_sorted_list(OrigNonLocals, OrigArgVars),
map__from_corresponding_lists(OrigArgVars, OrigArgModes,
OrigArgModesMap),
map__overlay(ArgModesMap, OrigArgModesMap, ArgModesMap1),
map__values(ArgModesMap1, ArgModes1),
list__append(ArgModes1, Modes, AllArgModes),
% Now construct the proc_info and pred_info for the new
% single-mode predicate, using the information computed above
proc_info_create(VarSet, VarTypes, AllArgVars, AllArgModes,
Detism, LambdaGoal, LambdaContext, ProcInfo),
pred_info_create(ModuleName, PredName, TVarSet, ArgTypes,
true, LambdaContext, local, [], predicate, ProcInfo,
ProcId, PredInfo),
% save the new predicate in the predicate table
module_info_get_predicate_table(ModuleInfo1, PredicateTable0),
predicate_table_insert(PredicateTable0, PredInfo,
PredId, PredicateTable),
module_info_set_predicate_table(ModuleInfo1, PredicateTable,
ModuleInfo)
),
Functor = functor(term__atom(PName), ArgVars),
ConsId = pred_const(PredId, ProcId),
Unification = construct(Var, ConsId, ArgVars, UniModes).
:- pred lambda__uni_modes_to_modes(list(uni_mode), list(mode)).
:- mode lambda__uni_modes_to_modes(in, out) is det.
% This predicate works out the modes of the original non-local
% variables of a lambda expression based on the list of uni_mode
% in the unify_info for the lambda unification.
lambda__uni_modes_to_modes([], []).
lambda__uni_modes_to_modes([UniMode | UniModes], [Mode | Modes]) :-
UniMode = ((_Initial0 - Initial1) -> (_Final0 - _Final1)),
Mode = (Initial1 -> Initial1),
lambda__uni_modes_to_modes(UniModes, Modes).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%