mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-21 20:33:55 +00:00
Estimated hours taken: 220
Aditi update syntax, type and mode checking.
Change the hlds_goal for constructions in preparation for
structure reuse to avoid making multiple conflicting changes.
compiler/hlds_goal.m:
Merge `higher_order_call' and `class_method_call' into a single
`generic_call' goal type. This also has alternatives for the
various Aditi builtins for which type declarations can't
be written.
Remove the argument types field from higher-order/class method calls.
It wasn't used often, and wasn't updated by optimizations
such as inlining. The types can be obtained from the vartypes
field of the proc_info.
Add a `lambda_eval_method' field to lambda_goals.
Add a field to constructions to identify which RL code fragment should
be used for an top-down Aditi closure.
Add fields to constructions to hold structure reuse information.
This is currently ignored -- the changes to implement structure
reuse will be committed to the alias branch.
This is included here to avoid lots of CVS conflicts caused by
changing the definition of `hlds_goal' twice.
Add a field to `some' goals to specify whether the quantification
can be removed. This is used to make it easier to ensure that
indexes are used for updates.
Add a field to lambda_goals to describe whether the modes were
guessed by the compiler and may need fixing up after typechecking
works out the argument types.
Add predicate `hlds_goal__generic_call_id' to work out a call_id
for a generic call for use in error messages.
compiler/purity.m:
compiler/post_typecheck.m:
Fill in the modes of Aditi builtin calls and closure constructions.
This needs to know which are the `aditi__state' arguments, so
it must be done after typechecking.
compiler/prog_data.m:
Added `:- type sym_name_and_arity ---> sym_name/arity'.
Add a type `lambda_eval_method', which describes how a closure
is to be executed. The alternatives are normal Mercury execution,
bottom-up execution by Aditi and top-down execution by Aditi.
compiler/prog_out.m:
Add predicate `prog_out__write_sym_name_and_arity', which
replaces duplicated inline code in a few places.
compiler/hlds_data.m:
Add a `lambda_eval_method' field to `pred_const' cons_ids and
`pred_closure_tag' cons_tags.
compiler/hlds_pred.m:
Remove type `pred_call_id', replace it with type `simple_call_id',
which combines a `pred_or_func' and a `sym_name_and_arity'.
Add a type `call_id' which describes all the different types of call,
including normal calls, higher-order and class-method calls
and Aditi builtins.
Add `aditi_top_down' to the type `marker'.
Remove `aditi_interface' from type `marker'. Interfacing to
Aditi predicates is now handled by `generic_call' hlds_goals.
Add a type `rl_exprn_id' which identifies a predicate to
be executed top-down by Aditi.
Add a `maybe(rl_exprn_id)' field to type `proc_info'.
Add predicate `adjust_func_arity' to convert between the arity
of a function to its arity as a predicate.
Add predicates `get_state_args' and `get_state_args_det' to
extract the DCG state arguments from an argument list.
Add predicate `pred_info_get_call_id' to get a `simple_call_id'
for a predicate for use in error messages.
compiler/hlds_out.m:
Write the new representation for call_ids.
Add a predicate `hlds_out__write_call_arg_id' which
replaces similar code in mode_errors.m and typecheck.m.
compiler/prog_io_goal.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on pred expressions.
compiler/prog_io_util.m:
compiler/prog_io_pragma.m:
Add predicates
- `prog_io_util:parse_name_and_arity' to parse `SymName/Arity'
(moved from prog_io_pragma.m).
- `prog_io_util:parse_pred_or_func_name_and_arity to parse
`pred SymName/Arity' or `func SymName/Arity'.
- `prog_io_util:parse_pred_or_func_and_args' to parse terms resembling
a clause head (moved from prog_io_pragma.m).
compiler/type_util.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on higher-order types.
Add predicates `construct_higher_order_type',
`construct_higher_order_pred_type' and
`construct_higher_order_func_type' to avoid some code duplication.
compiler/mode_util.m:
Add predicate `unused_mode/1', which returns `builtin:unused'.
Add functions `aditi_di_mode/0', `aditi_ui_mode/0' and
`aditi_uo_mode/0' which return `in', `in', and `out', but will
be changed to return `di', `ui' and `uo' when alias tracking
is implemented.
compiler/goal_util.m:
Add predicate `goal_util__generic_call_vars' which returns
any arguments to a generic_call which are not in the argument list,
for example the closure passed to a higher-order call or
the typeclass_info for a class method call.
compiler/llds.m:
compiler/exprn_aux.m:
compiler/dupelim.m:
compiler/llds_out.m:
compiler/opt_debug.m:
Add builtin labels for the Aditi update operations.
compiler/hlds_module.m:
Add predicate predicate_table_search_pf_sym, used for finding
possible matches for a call with the wrong number of arguments.
compiler/intermod.m:
Don't write predicates which build `aditi_top_down' goals,
because there is currently no way to tell importing modules
which RL code fragment to use.
compiler/simplify.m:
Obey the `cannot_remove' field of explicit quantification goals.
compiler/make_hlds.m:
Parse Aditi updates.
Don't typecheck clauses for which syntax errors in Aditi updates
are found - this avoids spurious "undefined predicate `aditi_insert/3'"
errors.
Factor out some common code to handle terms of the form `Head :- Body'.
Factor out common code in the handling of pred and func expressions.
compiler/typecheck.m:
Typecheck Aditi builtins.
Allow the argument types of matching predicates to be adjusted
when typechecking the higher-order arguments of Aditi builtins.
Change `typecheck__resolve_pred_overloading' to take a list of
argument types rather than a `map(var, type)' and a list of
arguments to allow a transformation to be performed on the
argument types before passing them.
compiler/error_util.m:
Move the part of `report_error_num_args' which writes
"wrong number of arguments (<x>; expected <y>)" from
typecheck.m for use by make_hlds.m when reporting errors
for Aditi builtins.
compiler/modes.m:
compiler/unique_modes.m:
compiler/modecheck_call.m:
Modecheck Aditi builtins.
compiler/lambda.m:
Handle the markers for predicates introduced for
`aditi_top_down' and `aditi_bottom_up' lambda expressions.
compiler/polymorphism.m:
Add extra type_infos to `aditi_insert' calls
describing the tuple to insert.
compiler/call_gen.m:
Generate code for Aditi builtins.
compiler/unify_gen.m:
compiler/bytecode_gen.m:
Abort on `aditi_top_down' and `aditi_bottom_up' lambda
expressions - code generation for them is not yet implemented.
compiler/magic.m:
Use the `aditi_call' generic_call rather than create
a new procedure for each Aditi predicate called from C.
compiler/rl_out.pp:
compiler/rl_gen.m:
compiler/rl.m:
Move some utility code used by magic.m and call_gen.m into rl.m.
Remove an XXX comment about reference counting being not yet
implemented - Evan has fixed that.
library/ops.m:
compiler/mercury_to_mercury.m:
doc/transition_guide.texi:
Add unary prefix operators `aditi_bottom_up' and `aditi_top_down',
used as qualifiers on lambda expressions.
Add infix operator `==>' to separate the tuples in an
`aditi_modify' call.
compiler/follow_vars.m:
Thread a `map(prog_var, type)' through, needed because
type information is no longer held in higher-order call goals.
compiler/table_gen.m:
Use the `make_*_construction' predicates in hlds_goal.m
to construct constants.
compiler/*.m:
Trivial changes to add extra fields to hlds_goal structures.
doc/reference_manual.texi:
Document Aditi updates.
Use @samp{pragma base_relation} instead of
@samp{:- pragma base_relation} throughout the Aditi documentation
to be consistent with other parts of the reference manual.
tests/valid/Mmakefile:
tests/valid/aditi_update.m:
tests/valid/aditi.m:
Test case.
tests/valid/Mmakefile:
Remove some hard-coded --intermodule-optimization rules which are
no longer needed because `mmake depend' is now run in this directory.
tests/invalid/*.err_exp:
Fix expected output for changes in reporting of call_ids
in typecheck.m.
tests/invalid/Mmakefile
tests/invalid/aditi_update_errors.{m,err_exp}:
tests/invalid/aditi_update_mode_errors.{m,err_exp}:
Test error messages for Aditi updates.
tests/valid/aditi.m:
tests/invalid/aditi.m:
Cut down version of extras/aditi/aditi.m to provide basic declarations
for Aditi compilation such as `aditi__state' and the modes
`aditi_di', `aditi_uo' and `aditi_ui'. Installing extras/aditi/aditi.m
somewhere would remove the need for these.
677 lines
23 KiB
Mathematica
677 lines
23 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% file: call_gen.m
|
|
%
|
|
% main author: conway.
|
|
%
|
|
% This module provides predicates for generating procedure calls,
|
|
% including calls to higher-order pred variables.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module call_gen.
|
|
|
|
:- interface.
|
|
|
|
:- import_module prog_data, hlds_pred, hlds_goal, llds, code_info.
|
|
:- import_module list, set, assoc_list.
|
|
|
|
:- pred call_gen__generate_generic_call(code_model, generic_call,
|
|
list(prog_var), list(mode), determinism,
|
|
hlds_goal_info, code_tree, code_info, code_info).
|
|
:- mode call_gen__generate_generic_call(in, in, in, in, in, in,
|
|
out, in, out) is det.
|
|
|
|
:- pred call_gen__generate_call(code_model, pred_id, proc_id, list(prog_var),
|
|
hlds_goal_info, code_tree, code_info, code_info).
|
|
:- mode call_gen__generate_call(in, in, in, in, in, out, in, out) is det.
|
|
|
|
:- pred call_gen__generate_builtin(code_model, pred_id, proc_id, list(prog_var),
|
|
code_tree, code_info, code_info).
|
|
:- mode call_gen__generate_builtin(in, in, in, in, out, in, out) is det.
|
|
|
|
:- pred call_gen__partition_args(assoc_list(prog_var, arg_info),
|
|
list(prog_var), list(prog_var)).
|
|
:- mode call_gen__partition_args(in, out, out) is det.
|
|
|
|
:- pred call_gen__input_arg_locs(assoc_list(prog_var, arg_info),
|
|
assoc_list(prog_var, arg_loc)).
|
|
:- mode call_gen__input_arg_locs(in, out) is det.
|
|
|
|
:- pred call_gen__output_arg_locs(assoc_list(prog_var, arg_info),
|
|
assoc_list(prog_var, arg_loc)).
|
|
:- mode call_gen__output_arg_locs(in, out) is det.
|
|
|
|
:- pred call_gen__save_variables(set(prog_var), code_tree,
|
|
code_info, code_info).
|
|
:- mode call_gen__save_variables(in, out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds_module, hlds_data, code_util, rl.
|
|
:- import_module arg_info, type_util, mode_util, unify_proc, instmap.
|
|
:- import_module trace, globals, options.
|
|
:- import_module std_util, bool, int, tree, map.
|
|
:- import_module varset, require, string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
call_gen__generate_call(CodeModel, PredId, ModeId, Arguments, GoalInfo, Code)
|
|
-->
|
|
|
|
% Find out which arguments are input and which are output.
|
|
code_info__get_pred_proc_arginfo(PredId, ModeId, ArgInfo),
|
|
{ assoc_list__from_corresponding_lists(Arguments, ArgInfo, ArgsInfos) },
|
|
|
|
% Save the known variables on the stack, except those
|
|
% generated by this call.
|
|
{ call_gen__select_out_args(ArgsInfos, OutArgs) },
|
|
call_gen__save_variables(OutArgs, SaveCode),
|
|
|
|
% Save possibly unknown variables on the stack as well
|
|
% if they may be needed on backtracking, and figure out the
|
|
% call model.
|
|
call_gen__prepare_for_call(CodeModel, FlushCode, CallModel),
|
|
|
|
% Move the input arguments to their registers.
|
|
code_info__setup_call(ArgsInfos, caller, SetupCode),
|
|
|
|
trace__prepare_for_call(TraceCode),
|
|
|
|
% Figure out what locations are live at the call point,
|
|
% for use by the value numbering optimization.
|
|
{ call_gen__input_args(ArgInfo, InputArguments) },
|
|
call_gen__generate_call_vn_livevals(InputArguments, OutArgs,
|
|
LiveCode),
|
|
|
|
% Figure out what variables will be live at the return point,
|
|
% and where, for use in the accurate garbage collector, and
|
|
% in the debugger.
|
|
code_info__get_instmap(InstMap),
|
|
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
|
|
{ instmap__apply_instmap_delta(InstMap, InstMapDelta, ReturnInstMap) },
|
|
{ call_gen__output_arg_locs(ArgsInfos, OutputArgLocs) },
|
|
% We must update the code generator state to reflect
|
|
% the situation after the call before building
|
|
% the return liveness info. No later code in this
|
|
% predicate depends on the old state.
|
|
call_gen__rebuild_registers(ArgsInfos),
|
|
code_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
|
|
ReturnLiveLvalues),
|
|
|
|
% Make the call.
|
|
code_info__get_module_info(ModuleInfo),
|
|
|
|
code_info__make_entry_label(ModuleInfo, PredId, ModeId, yes, Address),
|
|
code_info__get_next_label(ReturnLabel),
|
|
{ call_gen__call_comment(CodeModel, CallComment) },
|
|
{ CallCode = node([
|
|
call(Address, label(ReturnLabel), ReturnLiveLvalues, CallModel)
|
|
- CallComment,
|
|
label(ReturnLabel)
|
|
- "continuation label"
|
|
]) },
|
|
|
|
call_gen__handle_failure(CodeModel, FailHandlingCode),
|
|
|
|
{ Code =
|
|
tree(SaveCode,
|
|
tree(FlushCode,
|
|
tree(SetupCode,
|
|
tree(TraceCode,
|
|
tree(LiveCode,
|
|
tree(CallCode,
|
|
FailHandlingCode))))))
|
|
}.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%
|
|
% For a generic_call,
|
|
% we split the arguments into inputs and outputs, put the inputs
|
|
% in the locations expected by mercury__do_call_closure in
|
|
% runtime/mercury_ho_call.c, generate the call to that code,
|
|
% and pick up the outputs from the locations that we know
|
|
% the runtime system leaves them in.
|
|
%
|
|
|
|
call_gen__generate_generic_call(_OuterCodeModel, GenericCall, Args,
|
|
Modes, Det, GoalInfo, Code) -->
|
|
list__map_foldl(code_info__variable_type, Args, Types),
|
|
{ determinism_to_code_model(Det, CodeModel) },
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ make_arg_infos(Types, Modes, CodeModel, ModuleInfo, ArgInfos) },
|
|
{ assoc_list__from_corresponding_lists(Args, ArgInfos, ArgsInfos) },
|
|
{ call_gen__partition_args(ArgsInfos, InVars, OutVars) },
|
|
{ set__list_to_set(OutVars, OutArgs) },
|
|
call_gen__save_variables(OutArgs, SaveCode),
|
|
|
|
call_gen__prepare_for_call(CodeModel, FlushCode, CallModel),
|
|
|
|
{ call_gen__generic_call_info(CodeModel, GenericCall,
|
|
CodeAddr, FirstInput) },
|
|
|
|
% place the immediate input arguments in registers
|
|
call_gen__generate_immediate_args(InVars, FirstInput,
|
|
InLocs, ImmediateCode),
|
|
code_info__generate_call_stack_vn_livevals(OutArgs, LiveVals0),
|
|
{ call_gen__extra_livevals(FirstInput, ExtraLiveVals) },
|
|
{ set__insert_list(LiveVals0, ExtraLiveVals, LiveVals1) },
|
|
{ set__insert_list(LiveVals1, InLocs, LiveVals) },
|
|
|
|
{ CodeModel = model_semi ->
|
|
FirstOutput = 2
|
|
;
|
|
FirstOutput = 1
|
|
},
|
|
{ call_gen__outvars_to_outargs(OutVars, FirstOutput, OutArguments) },
|
|
{ call_gen__output_arg_locs(OutArguments, OutputArgLocs) },
|
|
|
|
code_info__get_instmap(InstMap),
|
|
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
|
|
{ instmap__apply_instmap_delta(InstMap, InstMapDelta, ReturnInstMap) },
|
|
|
|
% Doing this after generating the immediate input arguments,
|
|
% results in slightly more efficient code by not moving
|
|
% the immediate arguments twice.
|
|
call_gen__generic_call_setup(GenericCall, InVars, OutVars, SetupCode),
|
|
|
|
trace__prepare_for_call(TraceCode),
|
|
|
|
% We must update the code generator state to reflect
|
|
% the situation after the call before building
|
|
% the return liveness info. No later code in this
|
|
% predicate depends on the old state.
|
|
call_gen__rebuild_registers(OutArguments),
|
|
code_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
|
|
ReturnLiveLvalues),
|
|
|
|
code_info__get_next_label(ReturnLabel),
|
|
{ CallCode = node([
|
|
livevals(LiveVals)
|
|
- "",
|
|
call(CodeAddr, label(ReturnLabel), ReturnLiveLvalues,
|
|
CallModel)
|
|
- "Setup and call",
|
|
label(ReturnLabel)
|
|
- "Continuation label"
|
|
]) },
|
|
|
|
call_gen__handle_failure(CodeModel, FailHandlingCode),
|
|
|
|
{ Code =
|
|
tree(SaveCode,
|
|
tree(FlushCode,
|
|
tree(ImmediateCode,
|
|
tree(SetupCode,
|
|
tree(TraceCode,
|
|
tree(CallCode,
|
|
FailHandlingCode))))))
|
|
}.
|
|
|
|
% The registers before the first input argument are all live.
|
|
:- pred call_gen__extra_livevals(int, list(lval)).
|
|
:- mode call_gen__extra_livevals(in, out) is det.
|
|
|
|
call_gen__extra_livevals(FirstInput, ExtraLiveVals) :-
|
|
call_gen__extra_livevals(1, FirstInput, ExtraLiveVals).
|
|
|
|
:- pred call_gen__extra_livevals(int, int, list(lval)).
|
|
:- mode call_gen__extra_livevals(in, in, out) is det.
|
|
|
|
call_gen__extra_livevals(Reg, FirstInput, ExtraLiveVals) :-
|
|
( Reg < FirstInput ->
|
|
ExtraLiveVals = [reg(r, Reg) | ExtraLiveVals1],
|
|
NextReg is Reg + 1,
|
|
call_gen__extra_livevals(NextReg, FirstInput, ExtraLiveVals1)
|
|
;
|
|
ExtraLiveVals = []
|
|
).
|
|
|
|
% call_gen__generic_call_info(CodeModel, GenericCall,
|
|
% CodeAddr, FirstImmediateInputReg).
|
|
:- pred call_gen__generic_call_info(code_model, generic_call, code_addr, int).
|
|
:- mode call_gen__generic_call_info(in, in, out, out) is det.
|
|
|
|
call_gen__generic_call_info(_, higher_order(_, _, _), do_call_closure, 4).
|
|
call_gen__generic_call_info(_, class_method(_, _, _, _),
|
|
do_call_class_method, 5).
|
|
call_gen__generic_call_info(CodeModel, aditi_builtin(aditi_call(_,_,_,_),_),
|
|
CodeAddr, 5) :-
|
|
( CodeModel = model_det, CodeAddr = do_det_aditi_call
|
|
; CodeModel = model_semi, CodeAddr = do_semidet_aditi_call
|
|
; CodeModel = model_non, CodeAddr = do_nondet_aditi_call
|
|
).
|
|
call_gen__generic_call_info(CodeModel, aditi_builtin(aditi_insert(_), _),
|
|
do_aditi_insert, 3) :-
|
|
require(unify(CodeModel, model_det), "aditi_insert not model_det").
|
|
call_gen__generic_call_info(CodeModel, aditi_builtin(aditi_delete(_,_), _),
|
|
do_aditi_delete, 2) :-
|
|
require(unify(CodeModel, model_det), "aditi_delete not model_det").
|
|
call_gen__generic_call_info(CodeModel,
|
|
aditi_builtin(aditi_bulk_operation(BulkOp, _), _),
|
|
CodeAddr, 2) :-
|
|
( BulkOp = insert, CodeAddr = do_aditi_bulk_insert
|
|
; BulkOp = delete, CodeAddr = do_aditi_bulk_delete
|
|
),
|
|
require(unify(CodeModel, model_det),
|
|
"aditi_bulk_operation not model_det").
|
|
call_gen__generic_call_info(CodeModel, aditi_builtin(aditi_modify(_,_), _),
|
|
do_aditi_modify, 2) :-
|
|
require(unify(CodeModel, model_det), "aditi_modify not model_det").
|
|
|
|
% Produce code to set up the arguments to a generic call
|
|
% that are always present, such as the closure for a higher-order call,
|
|
% the typeclass_info for a class method call or the relation
|
|
% name for an Aditi update operation.
|
|
:- pred call_gen__generic_call_setup(generic_call, list(prog_var),
|
|
list(prog_var), code_tree, code_info, code_info).
|
|
:- mode call_gen__generic_call_setup(in, in, in, out, in, out) is det.
|
|
|
|
call_gen__generic_call_setup(higher_order(PredVar, _, _),
|
|
InVars, OutVars, SetupCode) -->
|
|
call_gen__place_generic_call_var(PredVar, "closure", PredVarCode),
|
|
{ list__length(InVars, NInVars) },
|
|
{ list__length(OutVars, NOutVars) },
|
|
{ NumArgCode = node([
|
|
assign(reg(r, 2), const(int_const(NInVars))) -
|
|
"Assign number of immediate input arguments",
|
|
assign(reg(r, 3), const(int_const(NOutVars))) -
|
|
"Assign number of output arguments"
|
|
]) },
|
|
{ SetupCode = tree(PredVarCode, NumArgCode) }.
|
|
call_gen__generic_call_setup(class_method(TCVar, Method, _, _),
|
|
InVars, OutVars, SetupCode) -->
|
|
call_gen__place_generic_call_var(TCVar, "typeclass_info", TCVarCode),
|
|
{ list__length(InVars, NInVars) },
|
|
{ list__length(OutVars, NOutVars) },
|
|
{ ArgsCode = node([
|
|
assign(reg(r, 2), const(int_const(Method))) -
|
|
"Index of class method in typeclass info",
|
|
assign(reg(r, 3), const(int_const(NInVars))) -
|
|
"Assign number of immediate input arguments",
|
|
assign(reg(r, 4), const(int_const(NOutVars))) -
|
|
"Assign number of output arguments"
|
|
]) },
|
|
{ SetupCode = tree(TCVarCode, ArgsCode) }.
|
|
call_gen__generic_call_setup(aditi_builtin(Builtin, _),
|
|
InVars, OutVars, SetupCode) -->
|
|
call_gen__aditi_builtin_setup(Builtin, InVars, OutVars,
|
|
SetupCode).
|
|
|
|
:- pred call_gen__place_generic_call_var(prog_var, string, code_tree,
|
|
code_info, code_info).
|
|
:- mode call_gen__place_generic_call_var(in, in, out, in, out) is det.
|
|
|
|
call_gen__place_generic_call_var(Var, Description, Code) -->
|
|
code_info__produce_variable(Var, VarCode, VarRVal),
|
|
{ VarRVal = lval(reg(r, 1)) ->
|
|
CopyCode = empty
|
|
;
|
|
% We don't need to clear r1 first - the arguments
|
|
% should have been moved into their proper positions and
|
|
% all other variables should have been saved by now.
|
|
string__append("Copy ", Description, Comment),
|
|
CopyCode = node([
|
|
assign(reg(r, 1), VarRVal) - Comment
|
|
])
|
|
},
|
|
{ Code = tree(VarCode, CopyCode) }.
|
|
|
|
:- pred call_gen__aditi_builtin_setup(aditi_builtin,
|
|
list(prog_var), list(prog_var), code_tree, code_info, code_info).
|
|
:- mode call_gen__aditi_builtin_setup(in, in, in, out, in, out) is det.
|
|
|
|
call_gen__aditi_builtin_setup(
|
|
aditi_call(PredProcId, NumInputs, InputTypes, NumOutputs),
|
|
_, _, SetupCode) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ rl__get_entry_proc_name(ModuleInfo, PredProcId, ProcName) },
|
|
{ rl__proc_name_to_string(ProcName, ProcStr) },
|
|
{ rl__schema_to_string(ModuleInfo, InputTypes, InputSchema) },
|
|
{ SetupCode = node([
|
|
assign(reg(r, 1), const(string_const(ProcStr))) -
|
|
"Assign name of procedure to call",
|
|
assign(reg(r, 2), const(int_const(NumInputs))) -
|
|
"Assign number of input arguments",
|
|
assign(reg(r, 3), const(string_const(InputSchema))) -
|
|
"Assign schema of input arguments",
|
|
assign(reg(r, 4), const(int_const(NumOutputs))) -
|
|
"Assign number of output arguments"
|
|
]) }.
|
|
call_gen__aditi_builtin_setup(aditi_insert(PredId), Inputs, _, SetupCode) -->
|
|
call_gen__setup_base_relation_name(PredId, NameCode),
|
|
{ list__length(Inputs, NumInputs) },
|
|
{ SetupCode =
|
|
tree(NameCode,
|
|
node([
|
|
assign(reg(r, 2), const(int_const(NumInputs))) -
|
|
"Assign arity of relation to insert into"
|
|
])
|
|
) }.
|
|
call_gen__aditi_builtin_setup(aditi_delete(PredId, _), _, _, SetupCode) -->
|
|
call_gen__setup_base_relation_name(PredId, SetupCode).
|
|
call_gen__aditi_builtin_setup(aditi_bulk_operation(_, PredId), _, _,
|
|
SetupCode) -->
|
|
call_gen__setup_base_relation_name(PredId, SetupCode).
|
|
call_gen__aditi_builtin_setup(aditi_modify(PredId, _), _, _, SetupCode) -->
|
|
call_gen__setup_base_relation_name(PredId, SetupCode).
|
|
|
|
:- pred call_gen__setup_base_relation_name(pred_id,
|
|
code_tree, code_info, code_info).
|
|
:- mode call_gen__setup_base_relation_name(in, out, in, out) is det.
|
|
|
|
call_gen__setup_base_relation_name(PredId, SetupCode) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ rl__permanent_relation_name(ModuleInfo, PredId, ProcStr) },
|
|
{ SetupCode = node([
|
|
assign(reg(r, 1), const(string_const(ProcStr))) -
|
|
"Assign name of base relation"
|
|
]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__prepare_for_call(code_model, code_tree, call_model,
|
|
code_info, code_info).
|
|
:- mode call_gen__prepare_for_call(in, out, out, in, out) is det.
|
|
|
|
call_gen__prepare_for_call(CodeModel, FlushCode, CallModel) -->
|
|
code_info__succip_is_used,
|
|
(
|
|
{ CodeModel = model_det },
|
|
{ CallModel = det },
|
|
{ FlushCode = empty }
|
|
;
|
|
{ CodeModel = model_semi },
|
|
{ CallModel = semidet },
|
|
{ FlushCode = empty }
|
|
;
|
|
{ CodeModel = model_non },
|
|
code_info__may_use_nondet_tailcall(TailCall),
|
|
{ CallModel = nondet(TailCall) },
|
|
code_info__flush_resume_vars_to_stack(FlushCode),
|
|
code_info__set_resume_point_and_frame_to_unknown
|
|
).
|
|
|
|
:- pred call_gen__handle_failure(code_model, code_tree, code_info, code_info).
|
|
:- mode call_gen__handle_failure(in, out, in, out ) is det.
|
|
|
|
call_gen__handle_failure(CodeModel, FailHandlingCode) -->
|
|
( { CodeModel = model_semi } ->
|
|
code_info__get_next_label(ContLab),
|
|
{ FailTestCode = node([
|
|
if_val(lval(reg(r, 1)), label(ContLab))
|
|
- "test for success"
|
|
]) },
|
|
code_info__generate_failure(FailCode),
|
|
{ ContLabelCode = node([
|
|
label(ContLab)
|
|
- ""
|
|
]) },
|
|
{ FailHandlingCode =
|
|
tree(FailTestCode,
|
|
tree(FailCode,
|
|
ContLabelCode))
|
|
}
|
|
;
|
|
{ FailHandlingCode = empty }
|
|
).
|
|
|
|
:- pred call_gen__call_comment(code_model, string).
|
|
:- mode call_gen__call_comment(in, out) is det.
|
|
|
|
call_gen__call_comment(model_det, "branch to det procedure").
|
|
call_gen__call_comment(model_semi, "branch to semidet procedure").
|
|
call_gen__call_comment(model_non, "branch to nondet procedure").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
call_gen__save_variables(Args, Code) -->
|
|
code_info__get_known_variables(Variables0),
|
|
{ set__list_to_set(Variables0, Vars0) },
|
|
{ set__difference(Vars0, Args, Vars1) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__lookup_bool_option(Globals, typeinfo_liveness,
|
|
TypeinfoLiveness) },
|
|
(
|
|
{ TypeinfoLiveness = yes }
|
|
->
|
|
code_info__get_proc_info(ProcInfo),
|
|
{ proc_info_get_typeinfo_vars_setwise(ProcInfo, Vars1,
|
|
TypeInfoVars) },
|
|
{ set__union(Vars1, TypeInfoVars, Vars) }
|
|
;
|
|
{ Vars = Vars1 }
|
|
),
|
|
{ set__to_sorted_list(Vars, Variables) },
|
|
call_gen__save_variables_2(Variables, Code).
|
|
|
|
:- pred call_gen__save_variables_2(list(prog_var), code_tree,
|
|
code_info, code_info).
|
|
:- mode call_gen__save_variables_2(in, out, in, out) is det.
|
|
|
|
call_gen__save_variables_2([], empty) --> [].
|
|
call_gen__save_variables_2([Var | Vars], Code) -->
|
|
code_info__save_variable_on_stack(Var, CodeA),
|
|
call_gen__save_variables_2(Vars, CodeB),
|
|
{ Code = tree(CodeA, CodeB) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__rebuild_registers(assoc_list(prog_var, arg_info),
|
|
code_info, code_info).
|
|
:- mode call_gen__rebuild_registers(in, in, out) is det.
|
|
|
|
call_gen__rebuild_registers(Args) -->
|
|
code_info__clear_all_registers,
|
|
call_gen__rebuild_registers_2(Args).
|
|
|
|
:- pred call_gen__rebuild_registers_2(assoc_list(prog_var, arg_info),
|
|
code_info, code_info).
|
|
:- mode call_gen__rebuild_registers_2(in, in, out) is det.
|
|
|
|
call_gen__rebuild_registers_2([]) --> [].
|
|
call_gen__rebuild_registers_2([Var - arg_info(ArgLoc, Mode) | Args]) -->
|
|
(
|
|
{ Mode = top_out }
|
|
->
|
|
{ code_util__arg_loc_to_register(ArgLoc, Register) },
|
|
code_info__set_var_location(Var, Register)
|
|
;
|
|
{ true }
|
|
),
|
|
call_gen__rebuild_registers_2(Args).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
call_gen__generate_builtin(CodeModel, PredId, ProcId, Args, Code) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ predicate_module(ModuleInfo, PredId, ModuleName) },
|
|
{ predicate_name(ModuleInfo, PredId, PredName) },
|
|
{
|
|
code_util__translate_builtin(ModuleName, PredName,
|
|
ProcId, Args, MaybeTestPrime, MaybeAssignPrime)
|
|
->
|
|
MaybeTest = MaybeTestPrime,
|
|
MaybeAssign = MaybeAssignPrime
|
|
;
|
|
error("Unknown builtin predicate")
|
|
},
|
|
(
|
|
{ CodeModel = model_det },
|
|
(
|
|
{ MaybeTest = no },
|
|
{ MaybeAssign = yes(Var - Rval) }
|
|
->
|
|
code_info__cache_expression(Var, Rval),
|
|
{ Code = empty }
|
|
;
|
|
{ error("Malformed det builtin predicate") }
|
|
)
|
|
;
|
|
{ CodeModel = model_semi },
|
|
(
|
|
{ MaybeTest = yes(Test) }
|
|
->
|
|
( { Test = binop(BinOp, X0, Y0) } ->
|
|
call_gen__generate_builtin_arg(X0, X, CodeX),
|
|
call_gen__generate_builtin_arg(Y0, Y, CodeY),
|
|
{ Rval = binop(BinOp, X, Y) },
|
|
{ ArgCode = tree(CodeX, CodeY) }
|
|
; { Test = unop(UnOp, X0) } ->
|
|
call_gen__generate_builtin_arg(X0, X, ArgCode),
|
|
{ Rval = unop(UnOp, X) }
|
|
;
|
|
{ error("Malformed semi builtin predicate") }
|
|
),
|
|
code_info__fail_if_rval_is_false(Rval, TestCode),
|
|
( { MaybeAssign = yes(Var - AssignRval) } ->
|
|
code_info__cache_expression(Var, AssignRval)
|
|
;
|
|
[]
|
|
),
|
|
{ Code = tree(ArgCode, TestCode) }
|
|
;
|
|
{ error("Malformed semi builtin predicate") }
|
|
)
|
|
;
|
|
{ CodeModel = model_non },
|
|
{ error("Nondet builtin predicate") }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__generate_builtin_arg(rval, rval, code_tree,
|
|
code_info, code_info).
|
|
:- mode call_gen__generate_builtin_arg(in, out, out, in, out) is det.
|
|
|
|
call_gen__generate_builtin_arg(Rval0, Rval, Code) -->
|
|
( { Rval0 = var(Var) } ->
|
|
code_info__produce_variable(Var, Code, Rval)
|
|
;
|
|
{ Rval = Rval0 },
|
|
{ Code = empty }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
call_gen__partition_args([], [], []).
|
|
call_gen__partition_args([V - arg_info(_Loc,Mode) | Rest], Ins, Outs) :-
|
|
(
|
|
Mode = top_in
|
|
->
|
|
call_gen__partition_args(Rest, Ins0, Outs),
|
|
Ins = [V | Ins0]
|
|
;
|
|
call_gen__partition_args(Rest, Ins, Outs0),
|
|
Outs = [V | Outs0]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__select_out_args(assoc_list(prog_var, arg_info),
|
|
set(prog_var)).
|
|
:- mode call_gen__select_out_args(in, out) is det.
|
|
|
|
call_gen__select_out_args([], Out) :-
|
|
set__init(Out).
|
|
call_gen__select_out_args([V - arg_info(_Loc, Mode) | Rest], Out) :-
|
|
call_gen__select_out_args(Rest, Out0),
|
|
(
|
|
Mode = top_out
|
|
->
|
|
set__insert(Out0, V, Out)
|
|
;
|
|
Out = Out0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__input_args(list(arg_info), list(arg_loc)).
|
|
:- mode call_gen__input_args(in, out) is det.
|
|
|
|
call_gen__input_args([], []).
|
|
call_gen__input_args([arg_info(Loc, Mode) | Args], Vs) :-
|
|
(
|
|
Mode = top_in
|
|
->
|
|
Vs = [Loc |Vs0]
|
|
;
|
|
Vs = Vs0
|
|
),
|
|
call_gen__input_args(Args, Vs0).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
call_gen__input_arg_locs([], []).
|
|
call_gen__input_arg_locs([Var - arg_info(Loc, Mode) | Args], Vs) :-
|
|
(
|
|
Mode = top_in
|
|
->
|
|
Vs = [Var - Loc | Vs0]
|
|
;
|
|
Vs = Vs0
|
|
),
|
|
call_gen__input_arg_locs(Args, Vs0).
|
|
|
|
call_gen__output_arg_locs([], []).
|
|
call_gen__output_arg_locs([Var - arg_info(Loc, Mode) | Args], Vs) :-
|
|
(
|
|
Mode = top_out
|
|
->
|
|
Vs = [Var - Loc | Vs0]
|
|
;
|
|
Vs = Vs0
|
|
),
|
|
call_gen__output_arg_locs(Args, Vs0).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__generate_call_vn_livevals(list(arg_loc)::in,
|
|
set(prog_var)::in, code_tree::out,
|
|
code_info::in, code_info::out) is det.
|
|
|
|
call_gen__generate_call_vn_livevals(InputArgLocs, OutputArgs, Code) -->
|
|
code_info__generate_call_vn_livevals(InputArgLocs, OutputArgs,
|
|
LiveVals),
|
|
{ Code = node([
|
|
livevals(LiveVals) - ""
|
|
]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__generate_immediate_args(list(prog_var), int, list(lval),
|
|
code_tree, code_info, code_info).
|
|
:- mode call_gen__generate_immediate_args(in, in, out, out, in, out) is det.
|
|
|
|
call_gen__generate_immediate_args([], _N, [], empty) --> [].
|
|
call_gen__generate_immediate_args([V | Vs], N0, [Lval | Lvals], Code) -->
|
|
{ Lval = reg(r, N0) },
|
|
code_info__place_var(V, Lval, Code0),
|
|
{ N1 is N0 + 1 },
|
|
call_gen__generate_immediate_args(Vs, N1, Lvals, Code1),
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred call_gen__outvars_to_outargs(list(prog_var), int,
|
|
assoc_list(prog_var, arg_info)).
|
|
:- mode call_gen__outvars_to_outargs(in, in, out) is det.
|
|
|
|
call_gen__outvars_to_outargs([], _N, []).
|
|
call_gen__outvars_to_outargs([V | Vs], N0, [V - Arg | ArgInfos]) :-
|
|
Arg = arg_info(N0, top_out),
|
|
N1 is N0 + 1,
|
|
call_gen__outvars_to_outargs(Vs, N1, ArgInfos).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|