mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 21:04:00 +00:00
Estimated hours taken: 100
Branches: main
Make definitions of abstract types available when generating
code for importing modules. This is necessary for the .NET
back-end, and for `:- pragma export' on the C back-end.
compiler/prog_data.m:
compiler/modules.m:
compiler/make.dependencies.m:
compiler/recompilation.version.m:
Handle implementation sections in interface files.
There is a new pseudo-declaration `abstract_imported'
which is applied to items from the implementation
section of an interface file. `abstract_imported'
items may not be used in the error checking passes
for the curent module.
compiler/equiv_type_hlds.m:
compiler/notes/compiler_design.html:
New file.
Go over the HLDS expanding all types fully after
semantic checking has been run.
compiler/mercury_compile.m:
Add the new pass.
Don't write the `.opt' file if there are any errors.
compiler/instmap.m:
Add a predicate instmap_delta_map_foldl to apply
a procedure to all insts in an instmap.
compiler/equiv_type.m:
Export predicates for use by equiv_type_hlds.m
Reorder arguments so state variables and higher-order
programming can be used.
compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
compiler/mercury_to_mercury.m:
Handle `:- pragma foreign_type' as a form of type
declaration rather than a pragma.
compiler/hlds_data.m:
compiler/*.m:
Add a field to the type_info_cell_constructor cons_id
to identify the type_ctor, which is needed by
equiv_type_hlds.m.
compiler/module_qual.m:
Donn't allow items from the implementation section of
interface files to match items in the current module.
compiler/*.m:
tests/*/*.m:
Add missing imports which only became apparent with
the bug fixes above.
Remove unnecessary imports which only became apparent with
the bug fixes above.
tests/hard_coded/Mmakefile:
tests/hard_coded/export_test2.{m,exp}:
Test case.
tests/invalid/Mmakefile:
tests/invalid/missing_interface_import2.{m,err_exp}:
Test case.
2438 lines
84 KiB
Mathematica
2438 lines
84 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-2003 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: rl_exprn.m
|
|
% Main author: stayl
|
|
%
|
|
% This module should only be imported by rl_out.m. XXX make it a sub-module.
|
|
%
|
|
% Generate RL "expressions" to evaluate join conditions.
|
|
%
|
|
% The code generated here is pretty awful. Each variable used in the
|
|
% expression is assigned its own register. All calls are generated inline -
|
|
% recursive calls and calls to imported predicates result in an abort.
|
|
% Unifications are generated eagerly.
|
|
%
|
|
% For complicated join conditions (for example anything containing
|
|
% calls to non-builtin predicates) we will probably generate Mercury bytecode,
|
|
% when the interpreter is done.
|
|
%
|
|
% Expressions are arranged into fragments. Each fragment consists of
|
|
% rl_PROC_expr_frag(N) followed by rl_EXP_* bytecodes to implement the
|
|
% fragment. Jumps addresses start at zero at the first instruction following
|
|
% the rl_PROC_expr_frag.
|
|
% 0 - initialisation: run once before anything else. Used to initialise
|
|
% the rule numbers (see below).
|
|
% 1 - group initialisation: has access to the first tuple in an aggregate group
|
|
% 2 - test - returns either zero/non-zero or -1/0/1 as for strcmp,
|
|
% depending on the operation.
|
|
% 3 - project - constructs an output tuple.
|
|
% 4 - cleanup - currently not used.
|
|
%
|
|
% Expressions have their own constant table separate from the procedure
|
|
% constant table. This is set up using rl_HEAD_const_* bytecodes before
|
|
% any fragments.
|
|
%
|
|
% Each expression has zero, one or two input tuples, a tuple to store
|
|
% local variables and zero, one or two output tuples.
|
|
%
|
|
% Expressions also need to set up rule numbers to identify data constructors.
|
|
% This is done with rl_EXP_define_var_rule(RuleNo, TypeIndex, NameIndex, Arity)
|
|
% (`var' refers to the schema of the tuple holding the local expression
|
|
% variables). TypeIndex and NameIndex are indices into the expression's
|
|
% constant table holding the type name and constructor name. `RuleNo' is
|
|
% used for bytecodes such as rl_EXP_test_functor and rl_EXP_construct_term
|
|
% to specify which constructor to use.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
:- module aditi_backend__rl_exprn.
|
|
|
|
:- interface.
|
|
|
|
:- import_module aditi_backend__rl.
|
|
:- import_module aditi_backend__rl_code.
|
|
:- import_module aditi_backend__rl_file.
|
|
:- import_module hlds__hlds_module.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module list.
|
|
|
|
% rl_exprn__generate_compare_exprn(ModuleInfo, SortSpec,
|
|
% InputSchema, CompareCodes).
|
|
%
|
|
% Generate an expression to compare tuples with the
|
|
% given schema on the given attributes.
|
|
:- pred rl_exprn__generate_compare_exprn(module_info::in, sort_spec::in,
|
|
list(type)::in, list(bytecode)::out) is det.
|
|
|
|
% rl_exprn__generate_sort_merge_compare_exprn(ModuleInfo, Attrs1,
|
|
% Schema1, Attrs2, Schema2, CompareCodes).
|
|
%
|
|
% Generate an expression to compare the join attributes in
|
|
% a sort-merge equi-join.
|
|
:- pred rl_exprn__generate_sort_merge_compare_exprn(module_info::in,
|
|
sort_spec::in, list(type)::in, sort_spec::in, list(type)::in,
|
|
list(bytecode)::out) is det.
|
|
|
|
% rl_exprn__generate_equijoin_exprn(ModuleInfo, Attrs,
|
|
% Schema, Code)
|
|
%
|
|
% Generate an expression to compare the join attributes in
|
|
% an equi-join.
|
|
:- pred rl_exprn__generate_equijoin_exprn(module_info::in, list(int)::in,
|
|
list(type)::in, list(bytecode)::out) is det.
|
|
|
|
% rl_exprn__generate_hash_function(ModuleInfo, HashAttrs,
|
|
% InputSchema, ExprnCode).
|
|
%
|
|
% Generate an expression to compute a hash value for the given
|
|
% attributes of a tuple.
|
|
:- pred rl_exprn__generate_hash_function(module_info::in, list(int)::in,
|
|
list(type)::in, list(bytecode)::out) is det.
|
|
|
|
% rl_exprn__generate_key_range(ModuleInfo, KeyRange, ExprnCode,
|
|
% NumParams, LowerBoundSchema, UpperBoundSchema,
|
|
% MaxTermDepth, ExprnVarTypes).
|
|
%
|
|
% Generate an expression to produce the upper and lower
|
|
% bounds for a B-tree access.
|
|
:- pred rl_exprn__generate_key_range(module_info::in, key_range::in,
|
|
list(bytecode)::out, int::out, list(type)::out, list(type)::out,
|
|
int::out, list(type)::out) is det.
|
|
|
|
% Generate an expression to produce either the tuple
|
|
% to insert or the tuple to delete for a modification
|
|
% query.
|
|
:- pred rl_exprn__generate_modify_project_exprn(module_info::in,
|
|
tuple_num::in, list(type)::in, list(bytecode)::out) is det.
|
|
|
|
% rl_exprn__generate(ModuleInfo, Goal, ExprnCode, NumParams,
|
|
% ExprnMode, ExprnVarTypes).
|
|
%
|
|
% Generate an expression for a join/project/subtract condition.
|
|
:- pred rl_exprn__generate(module_info::in, rl_goal::in, list(bytecode)::out,
|
|
int::out, exprn_mode::out, list(type)::out) is det.
|
|
|
|
% rl_exprn__aggregate(ModuleInfo, InitAccPred, UpdateAccPred,
|
|
% GrpByType, NonGrpByType, AccType, ExprnCode, Decls).
|
|
%
|
|
% Given the closures used to create the initial accumulator for each
|
|
% group and update the accumulator for each tuple, create
|
|
% an expression to evaluate the aggregate.
|
|
:- pred rl_exprn__aggregate(module_info::in, pred_proc_id::in,
|
|
pred_proc_id::in, (type)::in, (type)::in, (type)::in,
|
|
list(bytecode)::out, list(type)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module aditi_backend__rl_out.
|
|
:- import_module backend_libs__builtin_ops.
|
|
:- import_module check_hlds__inst_match.
|
|
:- import_module check_hlds__mode_util.
|
|
:- import_module check_hlds__type_util.
|
|
:- import_module hlds__error_util.
|
|
:- import_module hlds__hlds_data.
|
|
:- import_module hlds__hlds_goal.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module hlds__instmap.
|
|
:- import_module hlds__special_pred.
|
|
:- import_module libs__tree.
|
|
:- import_module parse_tree__prog_out.
|
|
:- import_module parse_tree__prog_util.
|
|
:- import_module transform_hlds__inlining.
|
|
|
|
:- import_module assoc_list, bool, char, int, map.
|
|
:- import_module require, set, std_util, string, term, varset.
|
|
|
|
% A compare expression tests each attribute in a list of attributes
|
|
% in turn.
|
|
rl_exprn__generate_compare_exprn(_ModuleInfo, Spec, Schema, Code) :-
|
|
(
|
|
Spec = attributes(Attrs0),
|
|
|
|
% We're comparing corresponding attributes from each tuple.
|
|
assoc_list__from_corresponding_lists(Attrs0, Attrs0,
|
|
CompareAttrs)
|
|
;
|
|
Spec = sort_var(_),
|
|
error("rl_exprn__generate_compare_exprn: unbound sort_var")
|
|
),
|
|
rl_exprn__do_generate_compare_exprn(Schema, CompareAttrs, Code).
|
|
|
|
rl_exprn__generate_sort_merge_compare_exprn(_ModuleInfo, Spec1, Schema1,
|
|
Spec2, _Schema2, Code) :-
|
|
|
|
(
|
|
Spec1 = attributes(Attrs1),
|
|
Spec2 = attributes(Attrs2)
|
|
->
|
|
assoc_list__from_corresponding_lists(Attrs1, Attrs2,
|
|
CompareAttrs)
|
|
;
|
|
error(
|
|
"rl_exprn__generate_sort_merge_compare_exprn: unbound sort_var")
|
|
),
|
|
rl_exprn__do_generate_compare_exprn(Schema1, CompareAttrs, Code).
|
|
|
|
:- pred rl_exprn__do_generate_compare_exprn(list(type)::in,
|
|
assoc_list(pair(int, sort_dir))::in, list(bytecode)::out) is det.
|
|
|
|
rl_exprn__do_generate_compare_exprn(Schema1, CompareAttrs, Code) :-
|
|
|
|
list__foldl(rl_exprn__generate_compare_instrs(Schema1),
|
|
CompareAttrs, empty, CompareCode),
|
|
|
|
ExprnCode =
|
|
tree(node([rl_PROC_expr_frag(2)]),
|
|
tree(CompareCode,
|
|
node([
|
|
rl_EXP_int_immed(0), % return equal
|
|
rl_EXP_int_result,
|
|
rl_PROC_expr_end
|
|
])
|
|
)),
|
|
|
|
tree__flatten(ExprnCode, Instrs0),
|
|
list__condense(Instrs0, Code).
|
|
|
|
:- pred rl_exprn__generate_compare_instrs(list(type)::in,
|
|
pair(pair(int, sort_dir))::in, byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__generate_compare_instrs(Types1, (Attr1a - Dir1) - (Attr2a - Dir2),
|
|
Code0, Code) :-
|
|
require(unify(Dir1, Dir2),
|
|
"rl_exprn__generate_compare_instrs: sort directions not equal"),
|
|
|
|
rl_exprn__adjust_arg_number(Attr1a, Attr1),
|
|
rl_exprn__adjust_arg_number(Attr2a, Attr2),
|
|
|
|
list__index0_det(Types1, Attr1, Type),
|
|
rl_exprn__type_to_aditi_type(Type, AType),
|
|
rl_exprn__compare_bytecode(AType, CompareByteCode),
|
|
rl_exprn__get_input_field_code(one, AType, Attr1, FieldCode1),
|
|
rl_exprn__get_input_field_code(two, AType, Attr2, FieldCode2),
|
|
(
|
|
Dir1 = ascending,
|
|
CompareAttr = node([
|
|
FieldCode1,
|
|
FieldCode2,
|
|
CompareByteCode,
|
|
rl_EXP_return_if_nez
|
|
])
|
|
;
|
|
Dir1 = descending,
|
|
CompareAttr = node([
|
|
FieldCode2,
|
|
FieldCode1,
|
|
CompareByteCode,
|
|
rl_EXP_return_if_nez
|
|
])
|
|
),
|
|
Code = tree(Code0, CompareAttr).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__generate_equijoin_exprn(_, Attrs0, Schema, Code) :-
|
|
list__map(rl_exprn__adjust_arg_number, Attrs0, Attrs),
|
|
rl_exprn__generate_equijoin_instrs(Attrs, Schema,
|
|
empty, TestCode),
|
|
ExprnCode =
|
|
tree(node([rl_PROC_expr_frag(2)]),
|
|
tree(TestCode,
|
|
node([rl_PROC_expr_end])
|
|
)),
|
|
|
|
tree__flatten(ExprnCode, Instrs0),
|
|
list__condense(Instrs0, Code).
|
|
|
|
:- pred rl_exprn__generate_equijoin_instrs(list(int)::in, list(type)::in,
|
|
byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__generate_equijoin_instrs([], _, Code, Code).
|
|
rl_exprn__generate_equijoin_instrs([Attr | Attrs], Schema, Code0, Code) :-
|
|
list__index0_det(Schema, Attr, AttrType),
|
|
rl_exprn__type_to_aditi_type(AttrType, AType),
|
|
rl_exprn__test_bytecode(AType, TestBytecode),
|
|
rl_exprn__get_input_field_code(one, AType, Attr, FieldCode1),
|
|
rl_exprn__get_input_field_code(two, AType, Attr, FieldCode2),
|
|
Code1 =
|
|
tree(Code0,
|
|
node([
|
|
FieldCode1,
|
|
FieldCode2,
|
|
TestBytecode,
|
|
rl_EXP_fail_if_false
|
|
])
|
|
),
|
|
rl_exprn__generate_equijoin_instrs(Attrs, Schema, Code1, Code).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__generate_hash_function(_ModuleInfo, Attrs0, Schema, Code) :-
|
|
list__map(rl_exprn__adjust_arg_number, Attrs0, Attrs),
|
|
IsFirst = yes,
|
|
rl_exprn__generate_hash_function_2(Attrs, Schema, IsFirst,
|
|
empty, HashCode),
|
|
ExprnCode =
|
|
tree(node([rl_PROC_expr_frag(2)]),
|
|
tree(HashCode,
|
|
node([rl_EXP_hash_result, rl_PROC_expr_end])
|
|
)),
|
|
|
|
tree__flatten(ExprnCode, Instrs0),
|
|
list__condense(Instrs0, Code).
|
|
|
|
:- pred rl_exprn__generate_hash_function_2(list(int)::in, list(type)::in,
|
|
bool::in, byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__generate_hash_function_2([], _, _, Code, Code).
|
|
rl_exprn__generate_hash_function_2([Attr | Attrs], Schema,
|
|
IsFirst, Code0, Code) :-
|
|
list__index0_det(Schema, Attr, Type),
|
|
rl_exprn__type_to_aditi_type(Type, AType),
|
|
rl_exprn__hash_bytecode(AType, HashCode),
|
|
rl_exprn__get_input_field_code(one, AType, Attr, FieldCode),
|
|
( IsFirst = no ->
|
|
CombineCode = node([rl_EXP_hash_combine])
|
|
;
|
|
CombineCode = empty
|
|
),
|
|
|
|
Code1 =
|
|
tree(Code0,
|
|
tree(node([FieldCode, HashCode]),
|
|
CombineCode
|
|
)),
|
|
IsFirst1 = no,
|
|
rl_exprn__generate_hash_function_2(Attrs, Schema, IsFirst1,
|
|
Code1, Code).
|
|
|
|
:- pred rl_exprn__hash_bytecode(aditi_type::in, bytecode::out) is det.
|
|
|
|
rl_exprn__hash_bytecode(int, rl_EXP_int_hash).
|
|
rl_exprn__hash_bytecode(string, rl_EXP_str_hash).
|
|
rl_exprn__hash_bytecode(float, rl_EXP_flt_hash).
|
|
rl_exprn__hash_bytecode(term(_), rl_EXP_term_hash).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The compiler numbers arguments starting at 1, Aditi numbers
|
|
% arguments starting at 0.
|
|
:- pred rl_exprn__adjust_arg_number(int::in, int::out) is det.
|
|
|
|
rl_exprn__adjust_arg_number(Attr, Attr - 1).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__generate_key_range(ModuleInfo,
|
|
key_range(LowerBound, UpperBound, MaybeArgTypes, KeyTypes),
|
|
Code, NumParams, Output1Schema, Output2Schema,
|
|
MaxDepth, Decls) :-
|
|
( MaybeArgTypes = yes(_) ->
|
|
NumParams = 1
|
|
;
|
|
NumParams = 0
|
|
),
|
|
rl_exprn_info_init(ModuleInfo, Info0),
|
|
% Generate code to produce the lower bound term.
|
|
rl_exprn__generate_bound(ModuleInfo, MaybeArgTypes, KeyTypes,
|
|
one, LowerBound, LowerBoundCode, Output1Schema,
|
|
MaxDepth0, Info0, Info1),
|
|
% Generate code to produce the upper bound term.
|
|
rl_exprn__generate_bound(ModuleInfo, MaybeArgTypes, KeyTypes,
|
|
two, UpperBound, UpperBoundCode, Output2Schema,
|
|
MaxDepth1, Info1, Info2),
|
|
ProjectCode = tree(LowerBoundCode, UpperBoundCode),
|
|
int__max(MaxDepth0, MaxDepth1, MaxDepth),
|
|
|
|
rl_exprn__generate_decls(ConstCode, InitCode, Decls, Info2, _Info),
|
|
|
|
rl_exprn__generate_fragments(ConstCode, InitCode, empty,
|
|
empty, ProjectCode, empty, Code).
|
|
|
|
:- pred rl_exprn__generate_bound(module_info::in, maybe(list(type))::in,
|
|
list(type)::in, tuple_num::in, bounding_tuple::in, byte_tree::out,
|
|
list(type)::out, int::out, rl_exprn_info::in,
|
|
rl_exprn_info::out) is det.
|
|
|
|
% An output schema of [] signals to the relational operation that
|
|
% that end of the key range has no bound (it doesn't make sense
|
|
% to have a key with no attributes).
|
|
rl_exprn__generate_bound(_, _, _, _, infinity, empty, [], 0) --> [].
|
|
rl_exprn__generate_bound(ModuleInfo, MaybeArgTypes, KeyTypes,
|
|
TupleNum, bound(Attrs), Code, KeyTypes, MaxDepth) -->
|
|
{ assoc_list__values(Attrs, AttrValues) },
|
|
rl_exprn__generate_bound_2(ModuleInfo, MaybeArgTypes,
|
|
TupleNum, no, AttrValues, empty, Code, 0, 1, MaxDepth).
|
|
|
|
:- pred rl_exprn__generate_bound_2(module_info::in, maybe(list(type))::in,
|
|
tuple_num::in, bool::in, list(key_attr)::in, byte_tree::in,
|
|
byte_tree::out, int::in, int::in, int::out, rl_exprn_info::in,
|
|
rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_bound_2(_, _, _, _, [], Code, Code,
|
|
_, MaxDepth, MaxDepth) --> [].
|
|
rl_exprn__generate_bound_2(ModuleInfo, MaybeArgTypes, TupleNum, IsSubTerm,
|
|
[Attr | Attrs], Code0, Code, Index0, MaxDepth0, MaxDepth) -->
|
|
rl_exprn__generate_bound_3(ModuleInfo, MaybeArgTypes, IsSubTerm,
|
|
Index0, TupleNum, Attr, AttrCode, Depth),
|
|
{ int__max(MaxDepth0, Depth, MaxDepth1) },
|
|
{ Index = Index0 + 1 },
|
|
rl_exprn__generate_bound_2(ModuleInfo, MaybeArgTypes, TupleNum,
|
|
IsSubTerm, Attrs, tree(Code0, AttrCode),
|
|
Code, Index, MaxDepth1, MaxDepth).
|
|
|
|
:- pred rl_exprn__generate_bound_3(module_info::in, maybe(list(type))::in,
|
|
bool::in, int::in, tuple_num::in, key_attr::in, byte_tree::out,
|
|
int::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_bound_3(_, _, _, _, _, infinity, _, _, _, _) :-
|
|
% Eventually the B-tree lookup code will be able to handle this case.
|
|
% For now we have to be careful not to generate it in rl_key.m.
|
|
error("rl_exprn__generate_bound_3: embedded infinities NYI").
|
|
|
|
rl_exprn__generate_bound_3(_ModuleInfo, MaybeArgTypes, IsSubTerm, FieldNum,
|
|
TupleNum, input_field(InputFieldNum0), Code, 1, Info, Info) :-
|
|
rl_exprn__adjust_arg_number(InputFieldNum0, InputFieldNum),
|
|
rl_exprn__get_key_arg(MaybeArgTypes, InputFieldNum, FieldType0),
|
|
rl_exprn__type_to_aditi_type(FieldType0, FieldType),
|
|
rl_exprn__get_input_field_code(one, FieldType, InputFieldNum, GetCode),
|
|
(
|
|
IsSubTerm = yes,
|
|
rl_exprn__set_term_arg_code(FieldType, FieldNum, PutCode)
|
|
;
|
|
IsSubTerm = no,
|
|
rl_exprn__set_output_field_code(TupleNum, FieldType,
|
|
FieldNum, PutCode)
|
|
),
|
|
Code = node([GetCode, PutCode]).
|
|
|
|
rl_exprn__generate_bound_3(ModuleInfo, MaybeArgTypes, IsSubTerm, FieldNum,
|
|
TupleNum, functor(ConsId, Type, Attrs), Code, Depth) -->
|
|
rl_exprn__set_term_arg_cons_id_code(ConsId, Type, TupleNum,
|
|
FieldNum, IsSubTerm, CreateTerm, NeedPop),
|
|
rl_exprn__generate_bound_2(ModuleInfo, MaybeArgTypes, TupleNum, yes,
|
|
Attrs, node(CreateTerm), Code0, 0, 1, Depth0),
|
|
{ NeedPop = yes ->
|
|
Code = tree(Code0, node([rl_EXP_term_pop]))
|
|
;
|
|
Code = Code0
|
|
},
|
|
{ Depth = Depth0 + 1 }.
|
|
|
|
:- pred rl_exprn__get_key_arg(maybe(list(T))::in, int::in, T::out) is det.
|
|
|
|
rl_exprn__get_key_arg(yes(Args), Index, Arg) :-
|
|
list__index0_det(Args, Index, Arg).
|
|
rl_exprn__get_key_arg(no, _, _) :-
|
|
error("rl_exprn__get_key_arg").
|
|
|
|
:- pred rl_exprn__set_term_arg_cons_id_code(cons_id::in, (type)::in,
|
|
tuple_num::in, int::in, bool::in, list(bytecode)::out, bool::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__set_term_arg_cons_id_code(cons(SymName, Arity), Type, TupleNum,
|
|
FieldNum, IsSubTerm, Code, NeedPop) -->
|
|
( { rl_exprn__is_char_cons_id(cons(SymName, Arity), Type, Int) } ->
|
|
rl_exprn__set_term_arg_cons_id_code(int_const(Int), Type,
|
|
TupleNum, FieldNum, IsSubTerm, Code, NeedPop)
|
|
;
|
|
{
|
|
TupleNum = one,
|
|
ExprnTuple = output1
|
|
;
|
|
TupleNum = two,
|
|
ExprnTuple = output2
|
|
},
|
|
rl_exprn__cons_id_to_rule_number(cons(SymName, Arity), Type,
|
|
ExprnTuple, Rule),
|
|
{
|
|
IsSubTerm = no,
|
|
(
|
|
TupleNum = one,
|
|
Code = [rl_EXP_new_term_output1(FieldNum,
|
|
Rule)]
|
|
;
|
|
TupleNum = two,
|
|
Code = [rl_EXP_new_term_output2(FieldNum,
|
|
Rule)]
|
|
),
|
|
NeedPop = no
|
|
;
|
|
IsSubTerm = yes,
|
|
Code = [
|
|
rl_EXP_term_dup,
|
|
rl_EXP_set_term_arg(FieldNum, Rule)
|
|
],
|
|
NeedPop = yes
|
|
}
|
|
).
|
|
rl_exprn__set_term_arg_cons_id_code(int_const(Int), _, TupleNum, FieldNum,
|
|
IsSubTerm, Code, no) -->
|
|
rl_exprn_info_lookup_const(int(Int), Index),
|
|
{ rl_exprn__set_term_arg_cons_id_code_2(int, TupleNum,
|
|
FieldNum, IsSubTerm, SetArgCode) },
|
|
{ Code0 = [rl_EXP_int_push(Index), SetArgCode] },
|
|
{ IsSubTerm = yes ->
|
|
Code = [rl_EXP_term_dup | Code0]
|
|
;
|
|
Code = Code0
|
|
}.
|
|
rl_exprn__set_term_arg_cons_id_code(float_const(Float), _, TupleNum, FieldNum,
|
|
IsSubTerm, Code, no) -->
|
|
rl_exprn_info_lookup_const(float(Float), Index),
|
|
{ rl_exprn__set_term_arg_cons_id_code_2(float, TupleNum,
|
|
FieldNum, IsSubTerm, SetArgCode) },
|
|
{ Code0 = [rl_EXP_flt_push(Index), SetArgCode] },
|
|
{ IsSubTerm = yes ->
|
|
Code = [rl_EXP_term_dup | Code0]
|
|
;
|
|
Code = Code0
|
|
}.
|
|
rl_exprn__set_term_arg_cons_id_code(string_const(Str), _, TupleNum, FieldNum,
|
|
IsSubTerm, Code, no) -->
|
|
rl_exprn_info_lookup_const(string(Str), Index),
|
|
{ rl_exprn__set_term_arg_cons_id_code_2(string, TupleNum,
|
|
FieldNum, IsSubTerm, SetArgCode) },
|
|
{ Code0 = [rl_EXP_str_push(Index), SetArgCode] },
|
|
{ IsSubTerm = yes ->
|
|
Code = [rl_EXP_term_dup | Code0]
|
|
;
|
|
Code = Code0
|
|
}.
|
|
rl_exprn__set_term_arg_cons_id_code(pred_const(_, _, _), _, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(type_ctor_info_const(_, _, _),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(base_typeclass_info_const(_, _, _, _),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(type_info_cell_constructor(_),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(typeclass_info_cell_constructor,
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(tabling_pointer_const(_, _),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(deep_profiling_proc_static(_),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
rl_exprn__set_term_arg_cons_id_code(table_io_decl(_),
|
|
_, _, _, _, _, _) -->
|
|
{ error("rl_exprn__set_term_arg_cons_id_code") }.
|
|
|
|
:- pred rl_exprn__set_term_arg_cons_id_code_2(aditi_type::in, tuple_num::in,
|
|
int::in, bool::in, bytecode::out) is det.
|
|
|
|
rl_exprn__set_term_arg_cons_id_code_2(int, one, FieldNum,
|
|
no, rl_EXP_output1_int(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(int, two, FieldNum,
|
|
no, rl_EXP_output2_int(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(int, _, FieldNum,
|
|
yes, rl_EXP_set_int_arg(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(float, one, FieldNum,
|
|
no, rl_EXP_output1_flt(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(float, two, FieldNum,
|
|
no, rl_EXP_output2_flt(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(float, _, FieldNum,
|
|
yes, rl_EXP_set_flt_arg(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(string, one, FieldNum,
|
|
no, rl_EXP_output1_str(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(string, two, FieldNum,
|
|
no, rl_EXP_output2_str(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(string, _, FieldNum,
|
|
yes, rl_EXP_set_str_arg(FieldNum)).
|
|
rl_exprn__set_term_arg_cons_id_code_2(term(_), _, _, _, _) :-
|
|
error("rl_exprn__set_term_arg_cons_id_code_2").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__generate_modify_project_exprn(_ModuleInfo, TupleNum, Types, Codes) :-
|
|
list__length(Types, NumAttrs),
|
|
rl_exprn__generate_modify_project_exprn_2(Types,
|
|
NumAttrs, TupleNum, 0, empty, ProjectCode),
|
|
CodeTree =
|
|
tree(node([rl_PROC_expr_frag(3)]),
|
|
tree(ProjectCode,
|
|
node([rl_PROC_expr_end])
|
|
)),
|
|
tree__flatten(CodeTree, CodeList),
|
|
list__condense(CodeList, Codes).
|
|
|
|
:- pred rl_exprn__generate_modify_project_exprn_2(list(type)::in, int::in,
|
|
tuple_num::in, int::in, byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__generate_modify_project_exprn_2([], _, _, _, Code, Code).
|
|
rl_exprn__generate_modify_project_exprn_2([Type | Types],
|
|
NumAttrs, TupleNum, Attr, Code0, Code) :-
|
|
rl_exprn__type_to_aditi_type(Type, AType),
|
|
(
|
|
TupleNum = one,
|
|
InputAttr = Attr
|
|
;
|
|
TupleNum = two,
|
|
InputAttr = Attr + NumAttrs
|
|
),
|
|
rl_exprn__get_input_field_code(one, AType, InputAttr, InputFieldCode),
|
|
rl_exprn__set_output_field_code(one, AType, Attr, OutputFieldCode),
|
|
Code1 =
|
|
tree(Code0,
|
|
node([InputFieldCode, OutputFieldCode])
|
|
),
|
|
rl_exprn__generate_modify_project_exprn_2(Types,
|
|
NumAttrs, TupleNum, Attr + 1, Code1, Code).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__generate(ModuleInfo, RLGoal, Code, NumParams, Mode, Decls) :-
|
|
RLGoal = rl_goal(_, VarSet, VarTypes, InstMap,
|
|
Inputs, MaybeOutputs, Goals, _),
|
|
rl_exprn_info_init(ModuleInfo, InstMap, VarTypes, VarSet, Info0),
|
|
rl_exprn__generate_2(Inputs, MaybeOutputs, Goals,
|
|
Code, NumParams, Mode, Decls, Info0, _).
|
|
|
|
:- pred rl_exprn__generate_2(rl_goal_inputs::in, rl_goal_outputs::in,
|
|
list(hlds_goal)::in, list(bytecode)::out, int::out, exprn_mode::out,
|
|
list(type)::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_2(Inputs, MaybeOutputs, GoalList,
|
|
Code, NumParams, Mode, Decls) -->
|
|
{ goal_list_determinism(GoalList, Detism) },
|
|
{ determinism_components(Detism, CanFail, _) },
|
|
{ goal_list_nonlocals(GoalList, NonLocals0) },
|
|
{ MaybeOutputs = yes(OutputNonLocals) ->
|
|
set__insert_list(NonLocals0, OutputNonLocals, NonLocals)
|
|
;
|
|
NonLocals = NonLocals0
|
|
},
|
|
(
|
|
{ Inputs = no_inputs },
|
|
{ NumParams = 0 },
|
|
{ InputCode = empty }
|
|
;
|
|
{ Inputs = one_input(InputVars) },
|
|
{ NumParams = 1 },
|
|
rl_exprn__deconstruct_input_tuple(one, 0, InputVars,
|
|
NonLocals, InputCode)
|
|
;
|
|
{ Inputs = two_inputs(InputVars1, InputVars2) },
|
|
{ NumParams = 2 },
|
|
rl_exprn__deconstruct_input_tuple(one, 0,
|
|
InputVars1, NonLocals, InputCode1),
|
|
rl_exprn__deconstruct_input_tuple(two, 0,
|
|
InputVars2, NonLocals, InputCode2),
|
|
{ InputCode = tree(InputCode1, InputCode2) }
|
|
),
|
|
|
|
{ CanFail = can_fail ->
|
|
Fail = node([rl_EXP_return_false])
|
|
;
|
|
% Should cause an error if it is encountered.
|
|
Fail = node([rl_EXP_last_bytecode])
|
|
},
|
|
|
|
rl_exprn__goals(GoalList, Fail, GoalCode),
|
|
|
|
( { MaybeOutputs = yes(OutputVars) } ->
|
|
rl_exprn__construct_output_tuple(GoalList,
|
|
OutputVars, OutputCode),
|
|
{ Mode = generate }
|
|
;
|
|
{ OutputCode = empty },
|
|
{ Mode = test }
|
|
),
|
|
|
|
{
|
|
CanFail = can_fail,
|
|
EvalCode =
|
|
tree(InputCode,
|
|
GoalCode
|
|
),
|
|
ProjectCode = OutputCode
|
|
;
|
|
CanFail = cannot_fail,
|
|
% For projections, the eval fragment is not run.
|
|
EvalCode = empty,
|
|
ProjectCode0 =
|
|
tree(InputCode,
|
|
tree(GoalCode,
|
|
OutputCode
|
|
)),
|
|
rl_exprn__resolve_addresses(ProjectCode0, ProjectCode)
|
|
},
|
|
|
|
% Need to do the init code last, since it also needs to define
|
|
% the rule constants for the other fragments.
|
|
rl_exprn__generate_decls(ConstCode, InitCode, Decls),
|
|
|
|
{ rl_exprn__generate_fragments(ConstCode, InitCode,
|
|
empty, EvalCode, ProjectCode, empty, Code) }.
|
|
|
|
:- pred rl_exprn__generate_fragments(byte_tree::in, byte_tree::in,
|
|
byte_tree::in, byte_tree::in, byte_tree::in, byte_tree::in,
|
|
list(bytecode)::out) is det.
|
|
|
|
rl_exprn__generate_fragments(DeclCode, InitCode, GroupInitCode,
|
|
EvalCode, ProjectCode, CleanupCode, Code) :-
|
|
list__foldl(
|
|
(pred(FragAndCode::in, Tree0::in, Tree::out) is det :-
|
|
FragAndCode = FragNo - FragCode0,
|
|
( tree__tree_of_lists_is_empty(FragCode0) ->
|
|
Tree = Tree0
|
|
;
|
|
rl_exprn__resolve_addresses(FragCode0,
|
|
FragCode),
|
|
Tree =
|
|
tree(Tree0,
|
|
tree(node([rl_PROC_expr_frag(FragNo)]),
|
|
FragCode
|
|
))
|
|
)
|
|
),
|
|
[0 - InitCode, 1 - GroupInitCode, 2 - EvalCode,
|
|
3 - ProjectCode, 4 - CleanupCode],
|
|
empty, FragmentsCode),
|
|
|
|
CodeTree =
|
|
tree(DeclCode,
|
|
tree(FragmentsCode,
|
|
node([rl_PROC_expr_end])
|
|
)),
|
|
tree__flatten(CodeTree, Code0),
|
|
list__condense(Code0, Code).
|
|
|
|
:- pred rl_exprn__generate_decls(byte_tree::out, byte_tree::out,
|
|
list(type)::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_decls(node(ConstCode), node(RuleCodes), VarTypes) -->
|
|
rl_exprn_info_get_rules(Rules - _),
|
|
{ map__to_assoc_list(Rules, RulesAL) },
|
|
{ assoc_list__reverse_members(RulesAL, RulesLA0) },
|
|
{ list__sort(RulesLA0, RulesLA) },
|
|
list__map_foldl(rl_exprn__generate_rule, RulesLA, RuleCodes),
|
|
|
|
rl_exprn_info_get_consts(Consts - _),
|
|
{ map__to_assoc_list(Consts, ConstsAL) },
|
|
{ assoc_list__reverse_members(ConstsAL, ConstsLA0) },
|
|
{ list__sort(ConstsLA0, ConstsLA) },
|
|
{ list__map(rl_exprn__generate_const_decl, ConstsLA, ConstCode) },
|
|
rl_exprn_info_get_decls(VarTypes).
|
|
|
|
:- pred rl_exprn__generate_const_decl(pair(int, rl_const)::in,
|
|
bytecode::out) is det.
|
|
|
|
rl_exprn__generate_const_decl(Addr - Const, Code) :-
|
|
(
|
|
Const = int(Int),
|
|
Code = rl_HEAD_const_int(Addr, Int)
|
|
;
|
|
Const = float(Float),
|
|
Code = rl_HEAD_const_flt(Addr, Float)
|
|
;
|
|
Const = string(Str),
|
|
Code = rl_HEAD_const_str(Addr, Str)
|
|
).
|
|
|
|
:- pred rl_exprn__generate_rule(pair(int, pair(rl_rule, exprn_tuple))::in, bytecode::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_rule(RuleNo - (Rule - RuleTuple), Code) -->
|
|
{ Rule = rl_rule(Type, Name, Arity) },
|
|
rl_exprn_info_lookup_const(string(Type), TypeIndex),
|
|
rl_exprn_info_lookup_const(string(Name), NameIndex),
|
|
{
|
|
RuleTuple = input1,
|
|
Code = rl_EXP_define_input1_rule(RuleNo,
|
|
TypeIndex, NameIndex, Arity)
|
|
;
|
|
RuleTuple = input2,
|
|
Code = rl_EXP_define_input2_rule(RuleNo,
|
|
TypeIndex, NameIndex, Arity)
|
|
;
|
|
RuleTuple = variables,
|
|
Code = rl_EXP_define_var_rule(RuleNo,
|
|
TypeIndex, NameIndex, Arity)
|
|
;
|
|
RuleTuple = output1,
|
|
Code = rl_EXP_define_output1_rule(RuleNo,
|
|
TypeIndex, NameIndex, Arity)
|
|
;
|
|
RuleTuple = output2,
|
|
Code = rl_EXP_define_output2_rule(RuleNo,
|
|
TypeIndex, NameIndex, Arity)
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Shift the inputs to the expression out of the input tuple.
|
|
:- pred rl_exprn__deconstruct_input_tuple(tuple_num::in, int::in,
|
|
list(prog_var)::in, set(prog_var)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__deconstruct_input_tuple(_, _, [], _, empty) --> [].
|
|
rl_exprn__deconstruct_input_tuple(TupleNo, FieldNo, [Var | Vars],
|
|
NonLocals, Code) -->
|
|
( { set__member(Var, NonLocals) } ->
|
|
rl_exprn_info_lookup_var(Var, VarReg),
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
rl_exprn__assign(reg(VarReg),
|
|
input_field(TupleNo, FieldNo), Type, Code0)
|
|
;
|
|
{ Code0 = empty }
|
|
),
|
|
{ NextField = FieldNo + 1 },
|
|
rl_exprn__deconstruct_input_tuple(TupleNo, NextField, Vars,
|
|
NonLocals, Code1),
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
% Move the outputs of the expression into the output tuple.
|
|
:- pred rl_exprn__construct_output_tuple(list(hlds_goal)::in,
|
|
list(prog_var)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__construct_output_tuple(Goals, Vars, Code) -->
|
|
{ goal_list_determinism(Goals, Detism) },
|
|
( { determinism_components(Detism, _, at_most_zero) } ->
|
|
% The condition never succeeds, so don't try to
|
|
% construct the output.
|
|
{ Code = empty }
|
|
;
|
|
{ FirstField = 0 },
|
|
rl_exprn__construct_output_tuple_2(FirstField, Vars, Code)
|
|
).
|
|
|
|
:- pred rl_exprn__construct_output_tuple_2(int::in, list(prog_var)::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__construct_output_tuple_2(_, [], empty) --> [].
|
|
rl_exprn__construct_output_tuple_2(FieldNo, [Var | Vars], Code) -->
|
|
rl_exprn_info_lookup_var(Var, VarReg),
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
rl_exprn__assign(output_field(FieldNo), reg(VarReg), Type, Code0),
|
|
{ NextField = FieldNo + 1 },
|
|
rl_exprn__construct_output_tuple_2(NextField, Vars, Code1),
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__goals(list(hlds_goal)::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__goals([], _, empty) --> [].
|
|
rl_exprn__goals([Goal | Goals], Fail, Code) -->
|
|
rl_exprn__goal(Goal, Fail, Code0),
|
|
rl_exprn__goals(Goals, Fail, Code1),
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
:- pred rl_exprn__goal(hlds_goal::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__goal(unify(_, _, _, Uni, _) - Info, Fail, Code) -->
|
|
rl_exprn__unify(Uni, Info, Fail, Code).
|
|
rl_exprn__goal(call(PredId, ProcId, Args, _, _, _) - Info, Fail, Code) -->
|
|
rl_exprn__call(PredId, ProcId, Args, Info, Fail, Code).
|
|
rl_exprn__goal(not(NegGoal) - _, Fail, Code) -->
|
|
rl_exprn_info_get_next_label_id(EndLabel),
|
|
{ NotFail = node([rl_EXP_jmp(EndLabel)]) },
|
|
rl_exprn__goal(NegGoal, NotFail, NegCode),
|
|
{ Code =
|
|
tree(NegCode,
|
|
tree(Fail,
|
|
node([rl_PROC_label(EndLabel)])
|
|
)) }.
|
|
rl_exprn__goal(if_then_else(_, Cond, Then, Else) - _, Fail, Code) -->
|
|
rl_exprn_info_get_next_label_id(StartElse),
|
|
rl_exprn_info_get_next_label_id(EndIte),
|
|
{ CondFail = node([rl_EXP_jmp(StartElse)]) },
|
|
rl_exprn__goal(Cond, CondFail, CondCode),
|
|
rl_exprn__goal(Then, Fail, ThenCode),
|
|
rl_exprn__goal(Else, Fail, ElseCode),
|
|
{ Code =
|
|
tree(CondCode,
|
|
tree(ThenCode,
|
|
tree(node([rl_EXP_jmp(EndIte), rl_PROC_label(StartElse)]),
|
|
tree(ElseCode,
|
|
node([rl_PROC_label(EndIte)])
|
|
)))) }.
|
|
rl_exprn__goal(conj(Goals) - _, Fail, Code) -->
|
|
rl_exprn__goals(Goals, Fail, Code).
|
|
rl_exprn__goal(par_conj(_) - _, _, _) -->
|
|
{ error("rl_exprn__goal: par_conj not yet implemented") }.
|
|
rl_exprn__goal(disj(Goals) - _Info, Fail, Code) -->
|
|
% Nondet disjunctions should have been transformed into
|
|
% separate Aditi predicates by dnf.m.
|
|
rl_exprn_info_get_next_label_id(EndDisj),
|
|
{ GotoEnd = node([rl_EXP_jmp(EndDisj)]) },
|
|
rl_exprn__disj(Goals, GotoEnd, Fail, DisjCode),
|
|
{ Code = tree(DisjCode, node([rl_PROC_label(EndDisj)])) }.
|
|
rl_exprn__goal(switch(Var, _, Cases) - _, Fail, Code) -->
|
|
rl_exprn_info_get_next_label_id(EndSwitch),
|
|
{ GotoEnd = node([rl_EXP_jmp(EndSwitch)]) },
|
|
rl_exprn__cases(Var, Cases, GotoEnd, Fail, SwitchCode),
|
|
{ Code = tree(SwitchCode, node([rl_PROC_label(EndSwitch)])) }.
|
|
rl_exprn__goal(generic_call(_, _, _, _) - _, _, _) -->
|
|
{ error("rl_exprn__goal: higher-order and class-method calls not yet implemented") }.
|
|
rl_exprn__goal(foreign_proc(_, _, _, _, _, _, _) - _, _, _) -->
|
|
{ error("rl_exprn__goal: foreign_proc not yet implemented") }.
|
|
rl_exprn__goal(some(_, _, Goal) - _, Fail, Code) -->
|
|
rl_exprn__goal(Goal, Fail, Code).
|
|
rl_exprn__goal(shorthand(_) - _, _, _) -->
|
|
% these should have been expanded out by now
|
|
{ error("rl_exprn__goal: unexpected shorthand") }.
|
|
|
|
:- pred rl_exprn__cases(prog_var::in, list(case)::in, byte_tree::in,
|
|
byte_tree::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__cases(_, [], _, Fail, Fail) --> [].
|
|
rl_exprn__cases(Var, [case(ConsId, Goal) | Cases], Succeed, Fail, Code) -->
|
|
rl_exprn_info_get_next_label_id(NextCase),
|
|
{ Jmp = rl_EXP_jmp(NextCase) },
|
|
rl_exprn__functor_test(Var, ConsId, node([Jmp]), TestCode),
|
|
rl_exprn__goal(Goal, Fail, GoalCode),
|
|
rl_exprn__cases(Var, Cases, Succeed, Fail, Code1),
|
|
{ Code =
|
|
tree(TestCode,
|
|
tree(GoalCode,
|
|
tree(Succeed,
|
|
tree(node([rl_PROC_label(NextCase)]),
|
|
Code1
|
|
)))) }.
|
|
|
|
:- pred rl_exprn__disj(list(hlds_goal)::in, byte_tree::in,
|
|
byte_tree::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__disj([], _, Fail, Fail) --> [].
|
|
rl_exprn__disj([Goal | Goals], Succeed, Fail, Code) -->
|
|
rl_exprn_info_get_next_label_id(NextDisj),
|
|
{ TryNext = node([rl_EXP_jmp(NextDisj)]) },
|
|
{ NextLabel = node([rl_PROC_label(NextDisj)]) },
|
|
rl_exprn__goal(Goal, TryNext, GoalCode),
|
|
rl_exprn__disj(Goals, Succeed, Fail, Code1),
|
|
{ Code =
|
|
tree(GoalCode,
|
|
tree(Succeed,
|
|
tree(NextLabel,
|
|
Code1
|
|
))) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__call(pred_id::in, proc_id::in, list(prog_var)::in,
|
|
hlds_goal_info::in, byte_tree::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__call(PredId, ProcId, Vars, GoalInfo, Fail, Code) -->
|
|
rl_exprn_info_get_module_info(ModuleInfo),
|
|
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
|
|
PredInfo, ProcInfo) },
|
|
{ proc_info_inferred_determinism(ProcInfo, Detism) },
|
|
rl_exprn_info_get_parent_pred_proc_ids(Parents0),
|
|
(
|
|
% XXX Nondet top-down calls are not yet implemented.
|
|
{ determinism_components(Detism, _, at_most_many) }
|
|
->
|
|
{ goal_info_get_context(GoalInfo, Context) },
|
|
{ rl_exprn__call_not_implemented_error(Context,
|
|
ModuleInfo, PredId, ProcId,
|
|
"nondeterministic Mercury calls in Aditi procedures") }
|
|
;
|
|
% XXX Top-down calls to imported predicates
|
|
% are not yet implemented.
|
|
{ pred_info_is_imported(PredInfo) },
|
|
|
|
% Calls to `unify/2' and `compare/3' will have been
|
|
% transformed into the type-specific versions
|
|
% by polymorphism.m. Polymorphic types are not allowed
|
|
% in Aditi predicates so the types must be known.
|
|
\+ {
|
|
% `index/2' doesn't work in Aditi.
|
|
is_unify_or_compare_pred(PredInfo),
|
|
\+ (pred_info_name(PredInfo) = "__Index__")
|
|
},
|
|
{ \+ pred_info_is_builtin(PredInfo) },
|
|
{ \+ rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
|
|
ProcId, _) }
|
|
->
|
|
{ goal_info_get_context(GoalInfo, Context) },
|
|
{ rl_exprn__call_not_implemented_error(Context,
|
|
ModuleInfo, PredId, ProcId,
|
|
"calls to imported Mercury procedures from Aditi") }
|
|
;
|
|
% XXX Recursive top-down calls are not yet implemented.
|
|
{ set__member(proc(PredId, ProcId), Parents0) }
|
|
->
|
|
{ goal_info_get_context(GoalInfo, Context) },
|
|
{ rl_exprn__call_not_implemented_error(Context,
|
|
ModuleInfo, PredId, ProcId,
|
|
"recursive Mercury calls in Aditi procedures") }
|
|
;
|
|
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
|
|
Fail, Vars, Code)
|
|
).
|
|
|
|
:- pred rl_exprn__call_not_implemented_error(prog_context::in, module_info::in,
|
|
pred_id::in, proc_id::in, string::in) is erroneous.
|
|
|
|
rl_exprn__call_not_implemented_error(Context,
|
|
ModuleInfo, PredId, ProcId, ErrorDescr) :-
|
|
error_util__describe_one_proc_name(ModuleInfo,
|
|
proc(PredId, ProcId), ProcName),
|
|
prog_out__context_to_string(Context, ContextStr),
|
|
string__append_list(
|
|
[
|
|
ContextStr, "in call to ", ProcName, ":\n",
|
|
"sorry, not yet implemented - ", ErrorDescr
|
|
],
|
|
Msg),
|
|
error(Msg).
|
|
|
|
:- pred rl_exprn__call_body(pred_id::in, proc_id::in, pred_info::in,
|
|
proc_info::in, byte_tree::in, list(prog_var)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo, Fail, Args, Code) -->
|
|
{ pred_info_get_maybe_special_pred(PredInfo, MaybeSpecial) },
|
|
(
|
|
{ pred_info_is_builtin(PredInfo) }
|
|
->
|
|
rl_exprn__generate_builtin_call(PredId, ProcId, PredInfo,
|
|
Args, Fail, Code)
|
|
;
|
|
{ rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
|
|
ProcId, Bytecode) }
|
|
->
|
|
rl_exprn__generate_extra_aditi_builtin(Bytecode,
|
|
Args, Code)
|
|
;
|
|
% Handle unify/2 specially, since it is possibly recursive,
|
|
% which will cause the code below to fall over. Also, magic.m
|
|
% doesn't add type_info arguments yet.
|
|
{ MaybeSpecial = yes(unify - _) },
|
|
{ list__reverse(Args, [Arg1, Arg2 | _]) },
|
|
{ hlds_pred__in_in_unification_proc_id(ProcId) }
|
|
->
|
|
rl_exprn_info_lookup_var(Arg1, Arg1Loc),
|
|
rl_exprn_info_lookup_var(Arg2, Arg2Loc),
|
|
rl_exprn_info_lookup_var_type(Arg1, Type),
|
|
rl_exprn__test(reg(Arg1Loc), reg(Arg2Loc), Type, Fail, Code)
|
|
;
|
|
% Handle compare/3 specially for the same reason
|
|
% as unify/2 above.
|
|
{ MaybeSpecial = yes(compare - _) },
|
|
{ list__reverse(Args, [Arg2, Arg1, Res | _]) }
|
|
->
|
|
rl_exprn_info_lookup_var(Arg1, Arg1Loc),
|
|
rl_exprn_info_lookup_var(Arg2, Arg2Loc),
|
|
rl_exprn_info_lookup_var(Res, ResultReg),
|
|
rl_exprn_info_lookup_var_type(Arg1, Type),
|
|
rl_exprn_info_lookup_var_type(Res, ResType),
|
|
rl_exprn__generate_push(reg(Arg1Loc), Type, PushCode1),
|
|
rl_exprn__generate_push(reg(Arg2Loc), Type, PushCode2),
|
|
{ rl_exprn__type_to_aditi_type(Type, AditiType) },
|
|
{ rl_exprn__compare_bytecode(AditiType, Compare) },
|
|
|
|
{ mercury_public_builtin_module(Builtin) },
|
|
{ EQConsId = cons(qualified(Builtin, "="), 0) },
|
|
{ LTConsId = cons(qualified(Builtin, "<"), 0) },
|
|
{ GTConsId = cons(qualified(Builtin, ">"), 0) },
|
|
rl_exprn__cons_id_to_rule_number(EQConsId, ResType, EQRuleNo),
|
|
rl_exprn__cons_id_to_rule_number(GTConsId, ResType, GTRuleNo),
|
|
rl_exprn__cons_id_to_rule_number(LTConsId, ResType, LTRuleNo),
|
|
|
|
rl_exprn_info_get_next_label_id(GTLabel),
|
|
rl_exprn_info_get_next_label_id(LTLabel),
|
|
rl_exprn_info_get_next_label_id(EndLabel),
|
|
|
|
{ Code =
|
|
tree(PushCode1,
|
|
tree(PushCode2,
|
|
node([
|
|
Compare,
|
|
rl_EXP_b3way(LTLabel, GTLabel),
|
|
rl_EXP_new_term_var(ResultReg, EQRuleNo),
|
|
rl_EXP_term_pop,
|
|
rl_EXP_jmp(EndLabel),
|
|
rl_PROC_label(LTLabel),
|
|
rl_EXP_new_term_var(ResultReg, LTRuleNo),
|
|
rl_EXP_term_pop,
|
|
rl_EXP_jmp(EndLabel),
|
|
rl_PROC_label(GTLabel),
|
|
rl_EXP_new_term_var(ResultReg, GTRuleNo),
|
|
rl_EXP_term_pop,
|
|
rl_PROC_label(EndLabel)
|
|
])
|
|
)) }
|
|
;
|
|
% XXX temporary hack until we allow Mercury calls from Aditi -
|
|
% generate the goal of the called procedure, not a call to
|
|
% the called procedure.
|
|
rl_exprn_info_get_parent_pred_proc_ids(Parents0),
|
|
{ set__insert(Parents0, proc(PredId, ProcId), Parents) },
|
|
rl_exprn_info_set_parent_pred_proc_ids(Parents),
|
|
rl_exprn__inline_call(PredId, ProcId,
|
|
PredInfo, ProcInfo, Args, Goal),
|
|
rl_exprn__goal(Goal, Fail, Code),
|
|
rl_exprn_info_set_parent_pred_proc_ids(Parents0)
|
|
).
|
|
|
|
:- pred rl_exprn__inline_call(pred_id::in, proc_id::in, pred_info::in,
|
|
proc_info::in, list(prog_var)::in, hlds_goal::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__inline_call(_PredId, _ProcId, CalledPredInfo,
|
|
CalledProcInfo, Args, Goal) -->
|
|
|
|
rl_exprn_info_get_varset(VarSet0),
|
|
rl_exprn_info_get_vartypes(VarTypes0),
|
|
{ varset__init(TVarSet0) },
|
|
{ map__init(TVarMap0) },
|
|
{ inlining__do_inline_call([], Args, CalledPredInfo, CalledProcInfo,
|
|
VarSet0, VarSet, VarTypes0, VarTypes, TVarSet0, _, TVarMap0, _,
|
|
Goal) },
|
|
|
|
rl_exprn_info_set_varset(VarSet),
|
|
rl_exprn_info_set_vartypes(VarTypes).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__unify(unification::in, hlds_goal_info::in,
|
|
byte_tree::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__unify(construct(Var, ConsId, Args, UniModes, _, _, _),
|
|
GoalInfo, _Fail, Code) -->
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
rl_exprn_info_lookup_var(Var, VarReg),
|
|
(
|
|
{ ConsId = cons(SymName, _) },
|
|
(
|
|
{ mercury_private_builtin_module(Builtin) },
|
|
{ SymName = qualified(Builtin, TypeInfo) },
|
|
( { TypeInfo = "type_info" }
|
|
; { TypeInfo = "type_ctor_info" }
|
|
)
|
|
->
|
|
% XXX for now we ignore these and hope it doesn't
|
|
% matter. They may be introduced for calls to the
|
|
% automatically generated unification and comparison
|
|
% procedures.
|
|
{ Code = empty }
|
|
;
|
|
{ rl_exprn__is_char_cons_id(ConsId, Type, Int) }
|
|
->
|
|
rl_exprn__assign(reg(VarReg), const(int(Int)),
|
|
Type, Code)
|
|
;
|
|
rl_exprn__cons_id_to_rule_number(ConsId, Type, RuleNo),
|
|
{ Create = rl_EXP_new_term_var(VarReg, RuleNo) },
|
|
{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
|
|
rl_exprn__handle_functor_args(Args, UniModes,
|
|
NonLocals, 0, ConsId, ArgCodes),
|
|
{ Code =
|
|
tree(node([Create]),
|
|
tree(ArgCodes,
|
|
node([rl_EXP_term_pop])
|
|
)) }
|
|
)
|
|
;
|
|
{ ConsId = int_const(Int) },
|
|
rl_exprn__assign(reg(VarReg), const(int(Int)), Type, Code)
|
|
;
|
|
{ ConsId = string_const(String) },
|
|
rl_exprn__assign(reg(VarReg), const(string(String)),
|
|
Type, Code)
|
|
;
|
|
{ ConsId = float_const(Float) },
|
|
rl_exprn__assign(reg(VarReg), const(float(Float)), Type, Code)
|
|
;
|
|
{ ConsId = pred_const(_, _, _) },
|
|
{ error("rl_exprn__unify: unsupported cons_id - pred_const") }
|
|
;
|
|
{ ConsId = type_ctor_info_const(_, _, _) },
|
|
% XXX for now we ignore these and hope it doesn't matter.
|
|
% They may be introduced for calls to the automatically
|
|
% generated unification and comparison procedures.
|
|
{ Code = empty }
|
|
;
|
|
{ ConsId = base_typeclass_info_const(_, _, _, _) },
|
|
{ error("rl_exprn__unify: unsupported cons_id - base_typeclass_info_const") }
|
|
;
|
|
{ ConsId = type_info_cell_constructor(_) },
|
|
% XXX for now we ignore these and hope it doesn't matter.
|
|
{ Code = empty }
|
|
;
|
|
{ ConsId = typeclass_info_cell_constructor },
|
|
{ error("rl_exprn__unify: unsupported cons_id - typeclass_info_cell_constructor") }
|
|
;
|
|
{ ConsId = tabling_pointer_const(_, _) },
|
|
{ error("rl_exprn__unify: unsupported cons_id - tabling_pointer_const") }
|
|
;
|
|
{ ConsId = deep_profiling_proc_static(_) },
|
|
{ error("rl_exprn__unify: unsupported cons_id - deep_profiling_proc_static") }
|
|
;
|
|
{ ConsId = table_io_decl(_) },
|
|
{ error("rl_exprn__unify: unsupported cons_id - table_io_decl") }
|
|
).
|
|
|
|
rl_exprn__unify(deconstruct(Var, ConsId, Args, UniModes, CanFail, _CanCGC),
|
|
GoalInfo, Fail, Code) -->
|
|
rl_exprn_info_lookup_var(Var, VarLoc),
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
( { CanFail = can_fail } ->
|
|
rl_exprn__functor_test(Var, ConsId, Fail, TestCode)
|
|
;
|
|
{ TestCode = empty }
|
|
),
|
|
( { Args \= [] } ->
|
|
{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
|
|
rl_exprn__generate_push(reg(VarLoc), Type, PushCode),
|
|
rl_exprn__handle_functor_args(Args, UniModes,
|
|
NonLocals, 0, ConsId, ArgCodes0),
|
|
{ ArgCodes =
|
|
tree(PushCode,
|
|
tree(ArgCodes0,
|
|
node([rl_EXP_term_pop])
|
|
)) }
|
|
;
|
|
{ ArgCodes = empty }
|
|
),
|
|
{ Code = tree(TestCode, ArgCodes) }.
|
|
rl_exprn__unify(complicated_unify(_, _, _), _, _, _) -->
|
|
{ error("rl_gen__unify: complicated_unify") }.
|
|
rl_exprn__unify(assign(Var1, Var2), _GoalInfo, _Fail, Code) -->
|
|
rl_exprn_info_lookup_var(Var1, Var1Loc),
|
|
rl_exprn_info_lookup_var(Var2, Var2Loc),
|
|
rl_exprn_info_lookup_var_type(Var1, Type),
|
|
rl_exprn__assign(reg(Var1Loc), reg(Var2Loc), Type, Code).
|
|
rl_exprn__unify(simple_test(Var1, Var2), _GoalInfo, Fail, Code) -->
|
|
% Note that the type here isn't necessarily one of the builtins -
|
|
% magic.m uses simple_test for all in-in unifications it introduces.
|
|
rl_exprn_info_lookup_var(Var1, Var1Loc),
|
|
rl_exprn_info_lookup_var(Var2, Var2Loc),
|
|
rl_exprn_info_lookup_var_type(Var1, Type),
|
|
rl_exprn__test(reg(Var1Loc), reg(Var2Loc), Type, Fail, Code).
|
|
|
|
:- pred rl_exprn__assign(rl_lval::in, rl_rval::in, (type)::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__assign(Lval, Rval, Type, Code) -->
|
|
rl_exprn__generate_push(Rval, Type, PushCode),
|
|
rl_exprn__generate_pop(Lval, Type, PopCode),
|
|
{ Code = tree(PushCode, PopCode) }.
|
|
|
|
:- pred rl_exprn__test(rl_rval::in, rl_rval::in, (type)::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__test(Var1Loc, Var2Loc, Type, Fail, Code) -->
|
|
rl_exprn__generate_push(Var1Loc, Type, PushCode1),
|
|
rl_exprn__generate_push(Var2Loc, Type, PushCode2),
|
|
rl_exprn_info_get_next_label_id(Label),
|
|
{ rl_exprn__type_to_aditi_type(Type, AditiType) },
|
|
|
|
{ rl_exprn__test_bytecode(AditiType, EqInstr) },
|
|
{ Code =
|
|
tree(PushCode1,
|
|
tree(PushCode2,
|
|
tree(node([EqInstr]),
|
|
tree(node([rl_EXP_bnez(Label)]),
|
|
tree(Fail,
|
|
node([rl_PROC_label(Label)])
|
|
))))) }.
|
|
|
|
:- pred rl_exprn__test_bytecode(aditi_type::in, bytecode::out) is det.
|
|
|
|
rl_exprn__test_bytecode(int, rl_EXP_int_eq).
|
|
rl_exprn__test_bytecode(float, rl_EXP_flt_eq).
|
|
rl_exprn__test_bytecode(string, rl_EXP_str_eq).
|
|
rl_exprn__test_bytecode(term(_), rl_EXP_term_eq).
|
|
|
|
:- pred rl_exprn__functor_test(prog_var::in, cons_id::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__functor_test(Var, ConsId, Fail, Code) -->
|
|
rl_exprn_info_lookup_var(Var, VarReg),
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
( { ConsId = int_const(Int) } ->
|
|
rl_exprn__test(reg(VarReg), const(int(Int)), Type, Fail, Code)
|
|
; { ConsId = string_const(String) } ->
|
|
rl_exprn__test(reg(VarReg), const(string(String)),
|
|
Type, Fail, Code)
|
|
; { ConsId = float_const(Float) } ->
|
|
rl_exprn__test(reg(VarReg), const(float(Float)),
|
|
Type, Fail, Code)
|
|
; { rl_exprn__is_char_cons_id(ConsId, Type, Int) } ->
|
|
rl_exprn__test(reg(VarReg), const(int(Int)), Type, Fail, Code)
|
|
; { ConsId = cons(_, _) } ->
|
|
rl_exprn_info_get_next_label_id(Label),
|
|
rl_exprn__cons_id_to_rule_number(ConsId, Type, RuleNo),
|
|
rl_exprn__generate_push(reg(VarReg), Type, PushCode),
|
|
{ Code =
|
|
tree(PushCode,
|
|
tree(node([
|
|
rl_EXP_test_functor(RuleNo),
|
|
rl_EXP_bnez(Label)
|
|
]),
|
|
tree(Fail,
|
|
node([rl_PROC_label(Label)])
|
|
))) }
|
|
;
|
|
{ error("rl_exprn__functor_test: unsupported cons_id") }
|
|
).
|
|
|
|
:- pred rl_exprn__is_char_cons_id(cons_id::in,
|
|
(type)::in, int::out) is semidet.
|
|
|
|
rl_exprn__is_char_cons_id(ConsId, Type, Int) :-
|
|
ConsId = cons(unqualified(CharStr), 0),
|
|
type_to_ctor_and_args(Type, unqualified("character") - 0, _),
|
|
% Convert characters to integers.
|
|
( string__to_char_list(CharStr, [Char]) ->
|
|
char__to_int(Char, Int)
|
|
;
|
|
error("rl_exprn__unify: invalid char")
|
|
).
|
|
|
|
:- pred rl_exprn__handle_functor_args(list(prog_var)::in, list(uni_mode)::in,
|
|
set(prog_var)::in, int::in, cons_id::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__handle_functor_args([], [_|_], _, _, _, _) -->
|
|
{ error("rl_exprn__handle_functor_args") }.
|
|
rl_exprn__handle_functor_args([_|_], [], _, _, _, _) -->
|
|
{ error("rl_exprn__handle_functor_args") }.
|
|
rl_exprn__handle_functor_args([], [], _, _, _, empty) --> [].
|
|
rl_exprn__handle_functor_args([Arg | Args], [Mode | Modes], NonLocals,
|
|
Index, ConsId, Code) -->
|
|
{ NextIndex = Index + 1 },
|
|
rl_exprn__handle_functor_args(Args, Modes, NonLocals,
|
|
NextIndex, ConsId, Code0),
|
|
( { set__member(Arg, NonLocals) } ->
|
|
rl_exprn_info_lookup_var_type(Arg, Type),
|
|
rl_exprn_info_get_module_info(ModuleInfo),
|
|
|
|
{ Mode = ((LI - RI) -> (LF - RF)) },
|
|
{ mode_to_arg_mode(ModuleInfo, (LI -> LF), Type, LeftMode) },
|
|
{ mode_to_arg_mode(ModuleInfo, (RI -> RF), Type, RightMode) },
|
|
(
|
|
{ LeftMode = top_in },
|
|
{ RightMode = top_in }
|
|
->
|
|
% Can't have test in arg unification.
|
|
{ error("test in arg of [de]construction") }
|
|
;
|
|
{ LeftMode = top_in },
|
|
{ RightMode = top_out }
|
|
->
|
|
rl_exprn_info_lookup_var(Arg, ArgReg),
|
|
{ rl_exprn__type_to_aditi_type(Type, AditiType) },
|
|
{ rl_exprn__get_term_arg_code(AditiType,
|
|
Index, TermArgCode) },
|
|
rl_exprn__generate_pop(reg(ArgReg), Type, PopCode),
|
|
{ Code1 =
|
|
tree(node([rl_EXP_term_dup]),
|
|
tree(node([TermArgCode]),
|
|
PopCode
|
|
)) }
|
|
;
|
|
{ LeftMode = top_out },
|
|
{ RightMode = top_in }
|
|
->
|
|
rl_exprn_info_lookup_var(Arg, ArgLoc),
|
|
{ rl_exprn__type_to_aditi_type(Type, AditiType) },
|
|
{ rl_exprn__set_term_arg_code(AditiType,
|
|
Index, TermArgCode) },
|
|
rl_exprn__generate_push(reg(ArgLoc), Type, PushCode),
|
|
{ Code1 =
|
|
tree(node([rl_EXP_term_dup]),
|
|
tree(PushCode,
|
|
node([TermArgCode])
|
|
)) }
|
|
;
|
|
{ LeftMode = top_unused },
|
|
{ RightMode = top_unused }
|
|
->
|
|
{ Code1 = empty }
|
|
;
|
|
{ error("rl_exprn__handle_functor_args: weird unification") }
|
|
),
|
|
{ Code = tree(Code1, Code0) }
|
|
;
|
|
{ Code = Code0 }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__cons_id_to_rule_number(cons_id::in, (type)::in, int::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__cons_id_to_rule_number(ConsId, Type, RuleNo) -->
|
|
rl_exprn__cons_id_to_rule_number(ConsId, Type, variables, RuleNo).
|
|
|
|
:- pred rl_exprn__cons_id_to_rule_number(cons_id::in, (type)::in,
|
|
exprn_tuple::in, int::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__cons_id_to_rule_number(ConsId, Type, ExprnTuple, RuleNo) -->
|
|
(
|
|
{ ConsId = cons(ConsName, Arity) },
|
|
{ type_to_ctor_and_args(Type, TypeCtor, Args) }
|
|
->
|
|
% These names should not be quoted, since they are not
|
|
% being parsed, just compared against other strings.
|
|
{ rl__mangle_type_name(TypeCtor, Args, MangledTypeName) },
|
|
{ rl__mangle_ctor_name(ConsName, Arity, MangledConsName) },
|
|
{ Rule = rl_rule(MangledTypeName, MangledConsName, Arity) },
|
|
rl_exprn_info_lookup_rule(Rule - ExprnTuple, RuleNo)
|
|
;
|
|
{ error("rl_exprn__cons_id_to_rule_number") }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Put a value on top of the expression stack.
|
|
:- pred rl_exprn__generate_push(rl_rval::in, (type)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_push(reg(Reg), Type0, Code) -->
|
|
{ rl_exprn__type_to_aditi_type(Type0, Type) },
|
|
rl_exprn__do_generate_push_var(Reg, Type, Code).
|
|
|
|
rl_exprn__generate_push(const(Const), _Type, node([ByteCode])) -->
|
|
rl_exprn_info_lookup_const(Const, ConstNo),
|
|
{
|
|
Const = int(_),
|
|
ByteCode = rl_EXP_int_push(ConstNo)
|
|
;
|
|
Const = float(_),
|
|
ByteCode = rl_EXP_flt_push(ConstNo)
|
|
;
|
|
Const = string(_),
|
|
ByteCode = rl_EXP_str_push(ConstNo)
|
|
}.
|
|
rl_exprn__generate_push(input_field(TupleNo, FieldNo),
|
|
Type0, node([ByteCode])) -->
|
|
{ rl_exprn__type_to_aditi_type(Type0, Type) },
|
|
{ rl_exprn__get_input_field_code(TupleNo, Type, FieldNo, ByteCode) }.
|
|
rl_exprn__generate_push(term_arg(TermLoc, _ConsId, Field, TermType),
|
|
Type0, ByteCodes) -->
|
|
{ rl_exprn__type_to_aditi_type(Type0, AditiType) },
|
|
rl_exprn__generate_push(TermLoc, TermType, PushCodes),
|
|
{
|
|
AditiType = int,
|
|
ByteCode = rl_EXP_get_int_arg(Field)
|
|
;
|
|
AditiType = float,
|
|
ByteCode = rl_EXP_get_flt_arg(Field)
|
|
;
|
|
AditiType = string,
|
|
ByteCode = rl_EXP_get_str_arg(Field)
|
|
;
|
|
AditiType = term(_),
|
|
ByteCode = rl_EXP_get_term_arg(Field)
|
|
},
|
|
{ ByteCodes =
|
|
tree(PushCodes,
|
|
node([ByteCode])
|
|
) }.
|
|
|
|
:- pred rl_exprn__do_generate_push_var(int::in, aditi_type::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__do_generate_push_var(Index, Type, node([ByteCode])) -->
|
|
{
|
|
Type = int,
|
|
ByteCode = rl_EXP_int_push_var(Index)
|
|
;
|
|
Type = float,
|
|
ByteCode = rl_EXP_flt_push_var(Index)
|
|
;
|
|
Type = string,
|
|
ByteCode = rl_EXP_str_push_var(Index)
|
|
;
|
|
Type = term(_),
|
|
ByteCode = rl_EXP_term_push_var(Index)
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Get the value on top of the expression stack and put it in the
|
|
% specified rl_lval.
|
|
:- pred rl_exprn__generate_pop(rl_lval::in, (type)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_pop(reg(Reg), Type0, ByteCode) -->
|
|
{ rl_exprn__type_to_aditi_type(Type0, Type) },
|
|
rl_exprn__do_generate_pop_var(Reg, Type, ByteCode).
|
|
|
|
rl_exprn__generate_pop(output_field(FieldNo), Type0, node([ByteCode])) -->
|
|
{ rl_exprn__type_to_aditi_type(Type0, Type) },
|
|
{
|
|
Type = int,
|
|
ByteCode = rl_EXP_output_int(FieldNo)
|
|
;
|
|
Type = float,
|
|
ByteCode = rl_EXP_output_flt(FieldNo)
|
|
;
|
|
Type = string,
|
|
ByteCode = rl_EXP_output_str(FieldNo)
|
|
;
|
|
Type = term(_),
|
|
% This bytecode copies the argument term adjusting rule numbers
|
|
% if the schemas of the argument term and the output tuple
|
|
% do not match.
|
|
ByteCode = rl_EXP_put_term_output(FieldNo)
|
|
}.
|
|
rl_exprn__generate_pop(term_arg(Reg, _ConsId, Field, TermType), Type0, Code) -->
|
|
% There's no swap operation (and to do a swap, the expression
|
|
% evaluator would probably need to know the types of the top
|
|
% two elements of the stack, so rl_EXP_swap_int_int,
|
|
% rl_EXP_swap_int_flt, etc).
|
|
{ rl_exprn__type_to_aditi_type(Type0, Type) },
|
|
rl_exprn_info_get_free_reg(Type0, TmpIndex),
|
|
rl_exprn__generate_pop(reg(TmpIndex), Type0, PopCode1),
|
|
rl_exprn__generate_push(reg(Reg), TermType, PushCode1),
|
|
rl_exprn__generate_push(reg(TmpIndex), Type0, PushCode2),
|
|
(
|
|
{ Type = int },
|
|
{ SetArg = rl_EXP_set_int_arg(Field) }
|
|
;
|
|
{ Type = float },
|
|
{ SetArg = rl_EXP_set_flt_arg(Field) }
|
|
;
|
|
{ Type = string },
|
|
{ SetArg = rl_EXP_set_str_arg(Field) }
|
|
;
|
|
{ Type = term(_) },
|
|
{ SetArg = rl_EXP_put_term_arg(Field) }
|
|
),
|
|
{ Code =
|
|
tree(PopCode1,
|
|
tree(PushCode1,
|
|
tree(PushCode2,
|
|
node([SetArg])
|
|
))) }.
|
|
|
|
:- pred rl_exprn__do_generate_pop_var(int::in, aditi_type::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__do_generate_pop_var(Index, Type, node([ByteCode])) -->
|
|
{
|
|
Type = int,
|
|
ByteCode = rl_EXP_int_pop_var(Index)
|
|
;
|
|
Type = float,
|
|
ByteCode = rl_EXP_flt_pop_var(Index)
|
|
;
|
|
Type = string,
|
|
ByteCode = rl_EXP_str_pop_var(Index)
|
|
;
|
|
Type = term(_),
|
|
ByteCode = rl_EXP_put_term_var(Index)
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__generate_builtin_call(pred_id::in, proc_id::in,
|
|
pred_info::in, list(prog_var)::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_builtin_call(_PredId, ProcId,
|
|
PredInfo, Args, Fail, Code) -->
|
|
{ PredModule0 = pred_info_module(PredInfo) },
|
|
{ PredName = pred_info_name(PredInfo) },
|
|
|
|
%
|
|
% Generate LLDS for the builtin, then convert that to Aditi bytecode.
|
|
%
|
|
(
|
|
{ builtin_ops__translate_builtin(PredModule0, PredName,
|
|
ProcId, Args, SimpleCode) }
|
|
->
|
|
(
|
|
{ SimpleCode = test(TestExpr) },
|
|
( rl_exprn__simple_expr_to_rl_rval(TestExpr, RvalCode) ->
|
|
rl_exprn_info_get_next_label_id(SuccLabel),
|
|
{ Code =
|
|
tree(RvalCode,
|
|
tree(node([rl_EXP_bnez(SuccLabel)]),
|
|
tree(Fail,
|
|
node([rl_PROC_label(SuccLabel)])
|
|
))) }
|
|
;
|
|
{ error("rl_exprn__generate_exprn_instr: invalid test") }
|
|
)
|
|
;
|
|
{ SimpleCode = assign(OutputVar, AssignExpr) },
|
|
rl_exprn_info_lookup_var(OutputVar, OutputLoc),
|
|
rl_exprn_info_lookup_var_type(OutputVar, Type),
|
|
{ rl_exprn__type_to_aditi_type(Type, AditiType) },
|
|
rl_exprn__maybe_simple_expr_to_rl_rval(yes(AssignExpr),
|
|
AditiType, RvalCode),
|
|
rl_exprn__generate_pop(reg(OutputLoc), Type, PopCode),
|
|
{ Code = tree(RvalCode, PopCode) }
|
|
)
|
|
;
|
|
{ prog_out__sym_name_to_string(PredModule0, PredModule) },
|
|
{ Arity = pred_info_arity(PredInfo) },
|
|
{ string__format("Sorry, not implemented in Aditi: %s.%s/%i",
|
|
[s(PredModule), s(PredName), i(Arity)], Msg) },
|
|
{ error(Msg) }
|
|
).
|
|
|
|
:- pred rl_exprn__maybe_simple_expr_to_rl_rval(maybe(simple_expr(prog_var))::in,
|
|
aditi_type::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__maybe_simple_expr_to_rl_rval(no, _, empty) --> [].
|
|
rl_exprn__maybe_simple_expr_to_rl_rval(yes(LLDSRval), _ResultType, Code) -->
|
|
( rl_exprn__simple_expr_to_rl_rval(LLDSRval, RvalCode) ->
|
|
{ Code = RvalCode }
|
|
;
|
|
{ error("rl_exprn__maybe_simple_expr_to_rl_rval: invalid simple_expr") }
|
|
).
|
|
|
|
:- pred rl_exprn__simple_expr_to_rl_rval(simple_expr(prog_var)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is semidet.
|
|
|
|
rl_exprn__simple_expr_to_rl_rval(leaf(Var), Code) -->
|
|
rl_exprn_info_lookup_var(Var, VarLoc),
|
|
rl_exprn_info_lookup_var_type(Var, Type),
|
|
rl_exprn__generate_push(reg(VarLoc), Type, Code).
|
|
rl_exprn__simple_expr_to_rl_rval(int_const(Int), PushCode) -->
|
|
{ rl_exprn__aditi_type_to_type(int, Type1) },
|
|
rl_exprn__generate_push(const(int(Int)), Type1, PushCode).
|
|
rl_exprn__simple_expr_to_rl_rval(float_const(Float), PushCode) -->
|
|
{ rl_exprn__aditi_type_to_type(float, Type1) },
|
|
rl_exprn__generate_push(const(float(Float)), Type1, PushCode).
|
|
rl_exprn__simple_expr_to_rl_rval(unary(_UnOp, _Expr), _Code) -->
|
|
% None of the MLDS/LLDS unary builtins are implemented in Aditi.
|
|
% The only one which is returned by builtin_ops__translate_builtin
|
|
% is `bitwise_complement', for which there is no corresponding
|
|
% bytecode in Aditi-RL.
|
|
{ fail }.
|
|
rl_exprn__simple_expr_to_rl_rval(binary(BinOp, Expr1, Expr2), Code) -->
|
|
rl_exprn__simple_expr_to_rl_rval(Expr1, Code1),
|
|
rl_exprn__simple_expr_to_rl_rval(Expr2, Code2),
|
|
{ rl_exprn__binop_bytecode(BinOp, Bytecode) },
|
|
{ Code =
|
|
tree(Code1,
|
|
tree(Code2,
|
|
node([Bytecode])
|
|
)) }.
|
|
|
|
:- pred rl_exprn__binop_bytecode(binary_op::in, bytecode::out) is semidet.
|
|
|
|
rl_exprn__binop_bytecode((+), rl_EXP_int_add).
|
|
rl_exprn__binop_bytecode((-), rl_EXP_int_sub).
|
|
rl_exprn__binop_bytecode((*), rl_EXP_int_mult).
|
|
rl_exprn__binop_bytecode((/), rl_EXP_int_div).
|
|
rl_exprn__binop_bytecode((mod), rl_EXP_int_mod).
|
|
rl_exprn__binop_bytecode(eq, rl_EXP_int_eq).
|
|
rl_exprn__binop_bytecode(ne, rl_EXP_int_ne).
|
|
rl_exprn__binop_bytecode(str_eq, rl_EXP_str_eq).
|
|
rl_exprn__binop_bytecode(str_ne, rl_EXP_str_ne).
|
|
rl_exprn__binop_bytecode(str_lt, rl_EXP_str_lt).
|
|
rl_exprn__binop_bytecode(str_gt, rl_EXP_str_gt).
|
|
rl_exprn__binop_bytecode(str_le, rl_EXP_str_le).
|
|
rl_exprn__binop_bytecode(str_ge, rl_EXP_str_ge).
|
|
rl_exprn__binop_bytecode((<), rl_EXP_int_lt).
|
|
rl_exprn__binop_bytecode((>), rl_EXP_int_gt).
|
|
rl_exprn__binop_bytecode((>=), rl_EXP_int_ge).
|
|
rl_exprn__binop_bytecode((<=), rl_EXP_int_le).
|
|
rl_exprn__binop_bytecode(float_plus, rl_EXP_flt_add).
|
|
rl_exprn__binop_bytecode(float_minus, rl_EXP_flt_sub).
|
|
rl_exprn__binop_bytecode(float_times, rl_EXP_flt_mult).
|
|
rl_exprn__binop_bytecode(float_divide, rl_EXP_flt_div).
|
|
rl_exprn__binop_bytecode(float_eq, rl_EXP_flt_eq).
|
|
rl_exprn__binop_bytecode(float_ne, rl_EXP_flt_ne).
|
|
rl_exprn__binop_bytecode(float_lt, rl_EXP_flt_lt).
|
|
rl_exprn__binop_bytecode(float_gt, rl_EXP_flt_gt).
|
|
rl_exprn__binop_bytecode(float_le, rl_EXP_flt_le).
|
|
rl_exprn__binop_bytecode(float_ge, rl_EXP_flt_ge).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate code for deterministic library predicates and functions
|
|
% for which all arguments except the last are input.
|
|
% This is not an exhaustive list, it's just the ones that
|
|
% Aditi happens to have bytecodes for.
|
|
% This is only needed until Aditi can call arbitrary Mercury code.
|
|
:- pred rl_exprn__generate_extra_aditi_builtin(bytecode::in,
|
|
list(prog_var)::in, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__generate_extra_aditi_builtin(Bytecode, Args, Code) -->
|
|
% The extra aditi builtins are not all functions, but
|
|
% this does the right thing.
|
|
{ pred_args_to_func_args(Args, InArgs, OutArg) },
|
|
|
|
rl_exprn__push_builtin_args(InArgs, empty, PushCode),
|
|
|
|
rl_exprn_info_lookup_var(OutArg, OutReg),
|
|
rl_exprn_info_lookup_var_type(OutArg, OutVarType),
|
|
rl_exprn__generate_pop(reg(OutReg), OutVarType, PopCode),
|
|
|
|
{ Code =
|
|
tree(PushCode,
|
|
tree(node([Bytecode]),
|
|
PopCode
|
|
)) }.
|
|
|
|
:- pred rl_exprn__push_builtin_args(list(prog_var)::in, byte_tree::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__push_builtin_args([], Code, Code) --> [].
|
|
rl_exprn__push_builtin_args([Var | Vars], Code0, Code) -->
|
|
rl_exprn_info_lookup_var(Var, VarReg),
|
|
rl_exprn_info_lookup_var_type(Var, VarType),
|
|
rl_exprn__generate_push(reg(VarReg), VarType, Code1),
|
|
rl_exprn__push_builtin_args(Vars, tree(Code0, Code1), Code).
|
|
|
|
:- pred rl_exprn__is_simple_extra_aditi_builtin(pred_info::in, proc_id::in,
|
|
bytecode::out) is semidet.
|
|
|
|
rl_exprn__is_simple_extra_aditi_builtin(PredInfo, ProcId, Bytecode) :-
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredModule = unqualified(PredModuleName),
|
|
PredName = pred_info_name(PredInfo),
|
|
PredArity0 = pred_info_arity(PredInfo),
|
|
hlds_pred__proc_id_to_int(ProcId, ProcInt),
|
|
adjust_func_arity(PredOrFunc, PredArity, PredArity0),
|
|
rl_exprn__simple_extra_builtin(PredOrFunc, PredModuleName,
|
|
PredName, PredArity, ProcInt, Bytecode).
|
|
|
|
:- pred rl_exprn__simple_extra_builtin(pred_or_func::in, string::in,
|
|
string::in, int::in, int::in, bytecode::in) is semidet.
|
|
:- mode rl_exprn__simple_extra_builtin(in, in, in, in, out, out) is semidet.
|
|
|
|
rl_exprn__simple_extra_builtin(predicate, "int", "to_float", 2, 0,
|
|
rl_EXP_int_toflt).
|
|
rl_exprn__simple_extra_builtin(predicate, "int", "max", 3, 0, rl_EXP_int_max).
|
|
rl_exprn__simple_extra_builtin(predicate, "int", "min", 3, 0, rl_EXP_int_min).
|
|
rl_exprn__simple_extra_builtin(predicate, "int", "abs", 2, 0, rl_EXP_int_abs).
|
|
|
|
rl_exprn__simple_extra_builtin(function, "float", "float", 1, 0,
|
|
rl_EXP_int_toflt).
|
|
rl_exprn__simple_extra_builtin(function, "float",
|
|
"truncate_to_int", 1, 0, rl_EXP_flt_toint).
|
|
rl_exprn__simple_extra_builtin(function, "float", "pow", 2, 0, rl_EXP_flt_pow).
|
|
rl_exprn__simple_extra_builtin(predicate, "float", "pow", 3, 0,
|
|
rl_EXP_flt_pow).
|
|
rl_exprn__simple_extra_builtin(function, "float", "abs", 1, 0, rl_EXP_flt_abs).
|
|
rl_exprn__simple_extra_builtin(predicate, "float", "abs", 2, 0,
|
|
rl_EXP_flt_abs).
|
|
rl_exprn__simple_extra_builtin(function, "float", "max", 2, 0, rl_EXP_flt_max).
|
|
rl_exprn__simple_extra_builtin(predicate, "float", "max", 3, 0,
|
|
rl_EXP_flt_max).
|
|
rl_exprn__simple_extra_builtin(function, "float", "min", 2, 0, rl_EXP_flt_min).
|
|
rl_exprn__simple_extra_builtin(predicate, "float", "min", 3, 0,
|
|
rl_EXP_flt_min).
|
|
|
|
rl_exprn__simple_extra_builtin(function, "math", "ceiling", 1, 0,
|
|
rl_EXP_flt_ceil).
|
|
rl_exprn__simple_extra_builtin(function, "math", "floor", 1, 0,
|
|
rl_EXP_flt_floor).
|
|
rl_exprn__simple_extra_builtin(function, "math", "round", 1, 0,
|
|
rl_EXP_flt_round).
|
|
rl_exprn__simple_extra_builtin(function, "math", "sqrt", 1, 0,
|
|
rl_EXP_flt_sqrt).
|
|
rl_exprn__simple_extra_builtin(function, "math", "pow", 2, 0, rl_EXP_flt_pow).
|
|
rl_exprn__simple_extra_builtin(function, "math", "exp", 1, 0, rl_EXP_flt_exp).
|
|
rl_exprn__simple_extra_builtin(function, "math", "ln", 1, 0, rl_EXP_flt_log).
|
|
rl_exprn__simple_extra_builtin(function, "math", "log10", 1, 0,
|
|
rl_EXP_flt_log10).
|
|
rl_exprn__simple_extra_builtin(function, "math", "log2", 1, 0,
|
|
rl_EXP_flt_log2).
|
|
rl_exprn__simple_extra_builtin(function, "math", "sin", 1, 0, rl_EXP_flt_sin).
|
|
rl_exprn__simple_extra_builtin(function, "math", "cos", 1, 0, rl_EXP_flt_cos).
|
|
rl_exprn__simple_extra_builtin(function, "math", "tan", 1, 0, rl_EXP_flt_tan).
|
|
rl_exprn__simple_extra_builtin(function, "math", "asin", 1, 0,
|
|
rl_EXP_flt_asin).
|
|
rl_exprn__simple_extra_builtin(function, "math", "acos", 1, 0,
|
|
rl_EXP_flt_acos).
|
|
rl_exprn__simple_extra_builtin(function, "math", "atan", 1, 0,
|
|
rl_EXP_flt_atan).
|
|
rl_exprn__simple_extra_builtin(function, "math", "sinh", 1, 0,
|
|
rl_EXP_flt_sinh).
|
|
rl_exprn__simple_extra_builtin(function, "math", "cosh", 1, 0,
|
|
rl_EXP_flt_cosh).
|
|
rl_exprn__simple_extra_builtin(function, "math", "tanh", 1, 0,
|
|
rl_EXP_flt_tanh).
|
|
|
|
rl_exprn__simple_extra_builtin(predicate, "string", "length", 2, 0,
|
|
rl_EXP_str_length).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl_exprn__aggregate(ModuleInfo, ComputeInitial, UpdateAcc, GrpByType,
|
|
NonGrpByType, AccType, AggCode, Decls) :-
|
|
|
|
map__init(VarTypes),
|
|
varset__init(VarSet),
|
|
instmap__init_reachable(InstMap),
|
|
rl_exprn_info_init(ModuleInfo, InstMap, VarTypes, VarSet, Info0),
|
|
rl_exprn__aggregate_2(ComputeInitial, UpdateAcc, GrpByType,
|
|
NonGrpByType, AccType, AggCode, Decls, Info0, _).
|
|
|
|
:- pred rl_exprn__aggregate_2(pred_proc_id::in, pred_proc_id::in,
|
|
(type)::in, (type)::in, (type)::in, list(bytecode)::out,
|
|
list(type)::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__aggregate_2(ComputeInitial, UpdateAcc, GrpByType,
|
|
NonGrpByType, AccType, AggCode, Decls) -->
|
|
|
|
rl_exprn_info_get_free_reg(GrpByType, GrpByReg),
|
|
rl_exprn_info_get_free_reg(AccType, AccReg),
|
|
|
|
%
|
|
% Initialise the accumulator and group-by variables.
|
|
%
|
|
rl_exprn__aggregate_init(ComputeInitial, GrpByReg, GrpByType,
|
|
NonGrpByType, AccReg, AccType, InitCode0, GroupInitCode),
|
|
|
|
%
|
|
% Generate a test to check whether the current tuple is
|
|
% in the current group.
|
|
%
|
|
rl_exprn__test(reg(GrpByReg), input_field(one, 0),
|
|
GrpByType, node([rl_EXP_return_false]), TestCode),
|
|
|
|
%
|
|
% Generate code to update the accumulator.
|
|
%
|
|
rl_exprn__aggregate_update(UpdateAcc, GrpByReg, GrpByType,
|
|
NonGrpByType, AccReg, AccType, UpdateCode),
|
|
{ EvalCode = tree(TestCode, UpdateCode) },
|
|
|
|
%
|
|
% Create the output tuple.
|
|
%
|
|
rl_exprn__assign(output_field(0), reg(GrpByReg),
|
|
GrpByType, GrpByOutputCode),
|
|
rl_exprn__assign(output_field(1), reg(AccReg),
|
|
AccType, AccOutputCode),
|
|
{ ProjectCode = tree(GrpByOutputCode, AccOutputCode) },
|
|
|
|
rl_exprn__generate_decls(ConstCode, DeclCode, Decls),
|
|
|
|
{ InitCode = tree(DeclCode, InitCode0) },
|
|
{ rl_exprn__generate_fragments(ConstCode, InitCode, GroupInitCode,
|
|
EvalCode, ProjectCode, empty, AggCode) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate code to initialise the accumulator for a group and
|
|
% put the group-by variable in a known place.
|
|
:- pred rl_exprn__aggregate_init(pred_proc_id::in, reg_id::in, (type)::in,
|
|
(type)::in, reg_id::in, (type)::in, byte_tree::out, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__aggregate_init(ComputeClosure, GrpByReg, GrpByType, NonGrpByType,
|
|
AccReg, AccType, InitCode, GroupInitCode) -->
|
|
|
|
% Put the group-by value for this group in its place.
|
|
rl_exprn__assign(reg(GrpByReg), input_field(one, 0),
|
|
GrpByType, GrpByAssign),
|
|
|
|
rl_exprn_info_get_free_reg(NonGrpByType, NonGrpByReg),
|
|
rl_exprn__assign(reg(NonGrpByReg), input_field(one, 1),
|
|
NonGrpByType, NonGrpByAssign),
|
|
|
|
rl_exprn_info_get_free_reg(AccType, InitialAccReg),
|
|
|
|
%
|
|
% Compute the initial accumulator given the first tuple in
|
|
% the group, and assign it to a register.
|
|
%
|
|
{ Args = [GrpByReg, NonGrpByReg, InitialAccReg] },
|
|
{ ArgTypes = [GrpByType, NonGrpByType, AccType] },
|
|
rl_exprn__closure(ComputeClosure, Args, ArgTypes, IsConst, AccCode0),
|
|
|
|
% Restore the initial value of the accumulator at the start
|
|
% of a new group.
|
|
rl_exprn__assign(reg(AccReg), reg(InitialAccReg), AccType, AccAssign),
|
|
|
|
{ IsConst = yes ->
|
|
% If the initial accumulator is constant, it can be
|
|
% computed once in the init fragment, rather than
|
|
% once per group.
|
|
InitCode = AccCode0,
|
|
GroupInitCode = tree(GrpByAssign, AccAssign)
|
|
;
|
|
InitCode = empty,
|
|
GroupInitCode =
|
|
tree(GrpByAssign,
|
|
tree(NonGrpByAssign,
|
|
tree(AccCode0,
|
|
AccAssign
|
|
)))
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Generate code to compute the new accumulator given the
|
|
% next element in the group, then destructively update the
|
|
% old accumulator.
|
|
:- pred rl_exprn__aggregate_update(pred_proc_id::in, reg_id::in,
|
|
(type)::in, (type)::in, reg_id::in, (type)::in,
|
|
byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__aggregate_update(UpdateClosure, GrpByReg, GrpByType, NonGrpByType,
|
|
AccReg, AccType, Code) -->
|
|
|
|
rl_exprn_info_get_free_reg(NonGrpByType, NonGrpByReg),
|
|
rl_exprn__assign(reg(NonGrpByReg), input_field(one, 1),
|
|
NonGrpByType, NonGrpByCode),
|
|
|
|
% Allocate a location to collect the new accumulator.
|
|
rl_exprn_info_get_free_reg(AccType, OutputAccReg),
|
|
rl_exprn__assign(reg(AccReg), reg(OutputAccReg),
|
|
AccType, AccAssignCode),
|
|
|
|
{ Args = [GrpByReg, NonGrpByReg, AccReg, OutputAccReg] },
|
|
{ ArgTypes = [GrpByType, NonGrpByType, AccType, AccType] },
|
|
|
|
rl_exprn__closure(UpdateClosure, Args, ArgTypes, _, UpdateCode),
|
|
{ Code =
|
|
tree(NonGrpByCode,
|
|
tree(UpdateCode,
|
|
AccAssignCode
|
|
)) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Evaluate a deterministic closure to compute the initial value
|
|
% or update the accumulator for an aggregate.
|
|
% Return whether the input arguments are actually used in
|
|
% constructing the outputs. If not, the closure is constant
|
|
% and can be evaluated once, instead of once per group.
|
|
:- pred rl_exprn__closure(pred_proc_id::in, list(reg_id)::in, list(type)::in,
|
|
bool::out, byte_tree::out,
|
|
rl_exprn_info::in, rl_exprn_info::out) is det.
|
|
|
|
rl_exprn__closure(proc(PredId, ProcId), ArgLocs, ArgTypes, IsConst, Code) -->
|
|
rl_exprn_info_get_module_info(ModuleInfo),
|
|
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
|
|
PredInfo, ProcInfo) },
|
|
|
|
% Create dummy variables for the arguments of the procedure.
|
|
rl_exprn_info_get_varset(VarSet0),
|
|
rl_exprn_info_get_vartypes(VarTypes0),
|
|
{ list__length(ArgTypes, NumVars) },
|
|
{ varset__new_vars(VarSet0, NumVars, ArgVars, VarSet) },
|
|
{ map__det_insert_from_corresponding_lists(VarTypes0,
|
|
ArgVars, ArgTypes, VarTypes) },
|
|
rl_exprn_info_set_varset(VarSet),
|
|
rl_exprn_info_set_vartypes(VarTypes),
|
|
|
|
rl_exprn_info_set_var_locs(ArgVars, ArgLocs),
|
|
|
|
% Check if the closure depends on the input arguments.
|
|
{ proc_info_goal(ProcInfo, Goal) },
|
|
{ Goal = _ - GoalInfo },
|
|
{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
|
|
{ proc_info_headvars(ProcInfo, HeadVars) },
|
|
{ proc_info_argmodes(ProcInfo, ArgModes) },
|
|
{ partition_args(ModuleInfo, ArgModes, HeadVars, InputArgs, _) },
|
|
{ set__list_to_set(InputArgs, InputArgSet) },
|
|
{ set__intersect(InputArgSet, NonLocals, UsedInputArgs) },
|
|
( { set__empty(UsedInputArgs) } ->
|
|
{ IsConst = yes }
|
|
;
|
|
{ IsConst = no }
|
|
),
|
|
|
|
{ Fail = node([rl_EXP_return_false]) },
|
|
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
|
|
Fail, ArgVars, Code).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Return the bytecode used to get a field from an input term.
|
|
:- pred rl_exprn__get_input_field_code(tuple_num::in, aditi_type::in,
|
|
int::in, bytecode::out) is det.
|
|
|
|
rl_exprn__get_input_field_code(one, int, Attr, rl_EXP_int_field1(Attr)).
|
|
rl_exprn__get_input_field_code(one, string, Attr, rl_EXP_str_field1(Attr)).
|
|
rl_exprn__get_input_field_code(one, float, Attr, rl_EXP_flt_field1(Attr)).
|
|
rl_exprn__get_input_field_code(one, term(_), Attr, rl_EXP_term_field1(Attr)).
|
|
rl_exprn__get_input_field_code(two, int, Attr, rl_EXP_int_field2(Attr)).
|
|
rl_exprn__get_input_field_code(two, string, Attr, rl_EXP_str_field2(Attr)).
|
|
rl_exprn__get_input_field_code(two, float, Attr, rl_EXP_flt_field2(Attr)).
|
|
rl_exprn__get_input_field_code(two, term(_), Attr, rl_EXP_term_field2(Attr)).
|
|
|
|
% Return the bytecode used to set a field in the output term.
|
|
:- pred rl_exprn__set_output_field_code(tuple_num::in,
|
|
aditi_type::in, int::in, bytecode::out) is det.
|
|
|
|
rl_exprn__set_output_field_code(one, int, Attr, rl_EXP_output1_int(Attr)).
|
|
rl_exprn__set_output_field_code(one, string, Attr, rl_EXP_output1_str(Attr)).
|
|
rl_exprn__set_output_field_code(one, float, Attr, rl_EXP_output1_flt(Attr)).
|
|
rl_exprn__set_output_field_code(one, term(_), Attr,
|
|
rl_EXP_put_term_output1(Attr)).
|
|
rl_exprn__set_output_field_code(two, int, Attr, rl_EXP_output2_int(Attr)).
|
|
rl_exprn__set_output_field_code(two, string, Attr, rl_EXP_output2_str(Attr)).
|
|
rl_exprn__set_output_field_code(two, float, Attr, rl_EXP_output2_flt(Attr)).
|
|
rl_exprn__set_output_field_code(two, term(_), Attr,
|
|
rl_EXP_put_term_output2(Attr)).
|
|
|
|
% Return the bytecode used to extract a field from a term.
|
|
:- pred rl_exprn__get_term_arg_code(aditi_type::in,
|
|
int::in, bytecode::out) is det.
|
|
|
|
rl_exprn__get_term_arg_code(int, Index, rl_EXP_get_int_arg(Index)).
|
|
rl_exprn__get_term_arg_code(float, Index, rl_EXP_get_flt_arg(Index)).
|
|
rl_exprn__get_term_arg_code(string, Index, rl_EXP_get_str_arg(Index)).
|
|
rl_exprn__get_term_arg_code(term(_), Index, rl_EXP_get_term_arg(Index)).
|
|
|
|
% Return the bytecode used to set a field in a term.
|
|
:- pred rl_exprn__set_term_arg_code(aditi_type::in,
|
|
int::in, bytecode::out) is det.
|
|
|
|
rl_exprn__set_term_arg_code(int, Index, rl_EXP_set_int_arg(Index)).
|
|
rl_exprn__set_term_arg_code(float, Index, rl_EXP_set_flt_arg(Index)).
|
|
rl_exprn__set_term_arg_code(string, Index, rl_EXP_set_str_arg(Index)).
|
|
% This bytecode copies the argument term adjusting rule numbers
|
|
% if the schemas of the argument term and the term having its
|
|
% argument set do not match.
|
|
rl_exprn__set_term_arg_code(term(_), Index, rl_EXP_put_term_arg(Index)).
|
|
|
|
:- pred rl_exprn__compare_bytecode(aditi_type::in, bytecode::out) is det.
|
|
|
|
rl_exprn__compare_bytecode(int, rl_EXP_int_cmp).
|
|
rl_exprn__compare_bytecode(float, rl_EXP_flt_cmp).
|
|
rl_exprn__compare_bytecode(string, rl_EXP_str_cmp).
|
|
rl_exprn__compare_bytecode(term(_), rl_EXP_term_cmp).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type aditi_type
|
|
---> int
|
|
; string
|
|
; float
|
|
; term(type).
|
|
|
|
:- pred rl_exprn__type_to_aditi_type((type)::in, aditi_type::out) is det.
|
|
|
|
rl_exprn__type_to_aditi_type(Type, AditiType) :-
|
|
( type_to_ctor_and_args(Type, TypeCtor, _) ->
|
|
( TypeCtor = unqualified("int") - 0 ->
|
|
AditiType = int
|
|
; TypeCtor = unqualified("character") - 0 ->
|
|
AditiType = int
|
|
; TypeCtor = unqualified("string") - 0 ->
|
|
AditiType = string
|
|
; TypeCtor = unqualified("float") - 0 ->
|
|
AditiType = float
|
|
;
|
|
AditiType = term(Type)
|
|
)
|
|
;
|
|
% All types in Aditi relations must be bound. This case
|
|
% can happen if an argument of an aggregate init or update
|
|
% closure is not used. int is a bit of a lie, but since
|
|
% the argument is not used, it should be harmless.
|
|
AditiType = int
|
|
).
|
|
|
|
:- pred rl_exprn__aditi_type_to_type(aditi_type::in, (type)::out) is det.
|
|
|
|
rl_exprn__aditi_type_to_type(int, Int) :-
|
|
construct_type(unqualified("int") - 0, [], Int).
|
|
rl_exprn__aditi_type_to_type(float, Float) :-
|
|
construct_type(unqualified("float") - 0, [], Float).
|
|
rl_exprn__aditi_type_to_type(string, Str) :-
|
|
construct_type(unqualified("string") - 0, [], Str).
|
|
rl_exprn__aditi_type_to_type(term(Type), Type).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_exprn__resolve_addresses(byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__resolve_addresses(ByteTree0, ByteTree) :-
|
|
map__init(Labels0),
|
|
rl_exprn__get_exprn_labels(0, _, Labels0, Labels,
|
|
ByteTree0, ByteTree1),
|
|
ResolveAddr = (pred(Code0::in, Code::out) is det :-
|
|
% This is incomplete, but we don't generate any
|
|
% of the other jump instructions.
|
|
( Code0 = rl_EXP_jmp(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_jmp(Label)
|
|
; Code0 = rl_EXP_beqz(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_beqz(Label)
|
|
; Code0 = rl_EXP_bnez(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bnez(Label)
|
|
; Code0 = rl_EXP_bltz(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bltz(Label)
|
|
; Code0 = rl_EXP_blez(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_blez(Label)
|
|
; Code0 = rl_EXP_bgez(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bgez(Label)
|
|
; Code0 = rl_EXP_bgtz(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bgtz(Label)
|
|
; Code0 = rl_EXP_bt(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bt(Label)
|
|
; Code0 = rl_EXP_bf(Label0) ->
|
|
map__lookup(Labels, Label0, Label),
|
|
Code = rl_EXP_bf(Label)
|
|
;
|
|
Code = Code0
|
|
)
|
|
),
|
|
rl_out__resolve_addresses(ResolveAddr, ByteTree1, ByteTree).
|
|
|
|
:- pred rl_exprn__get_exprn_labels(int::in, int::out, map(label_id, int)::in,
|
|
map(label_id, int)::out, byte_tree::in, byte_tree::out) is det.
|
|
|
|
rl_exprn__get_exprn_labels(PC0, PC0, Labels, Labels, empty, empty).
|
|
rl_exprn__get_exprn_labels(PC0, PC, Labels0, Labels,
|
|
tree(CodeA0, CodeB0), tree(CodeA, CodeB)) :-
|
|
rl_exprn__get_exprn_labels(PC0, PC1, Labels0, Labels1, CodeA0, CodeA),
|
|
rl_exprn__get_exprn_labels(PC1, PC, Labels1, Labels, CodeB0, CodeB).
|
|
rl_exprn__get_exprn_labels(PC0, PC, Labels0, Labels,
|
|
node(Instrs0), node(Instrs)) :-
|
|
rl_exprn__get_exprn_labels_list(PC0, PC,
|
|
Labels0, Labels, Instrs0, Instrs).
|
|
|
|
:- pred rl_exprn__get_exprn_labels_list(int::in, int::out,
|
|
map(label_id, int)::in, map(label_id, int)::out,
|
|
list(bytecode)::in, list(bytecode)::out) is det.
|
|
|
|
rl_exprn__get_exprn_labels_list(PC, PC, Labels, Labels, [], []).
|
|
rl_exprn__get_exprn_labels_list(PC0, PC, Labels0, Labels,
|
|
[Instr | Instrs0], Instrs) :-
|
|
( Instr = rl_PROC_label(_) ->
|
|
PC1 = PC0
|
|
;
|
|
functor(Instr, _, Arity),
|
|
PC1 = PC0 + Arity + 1 % +1 for the opcode
|
|
),
|
|
rl_exprn__get_exprn_labels_list(PC1, PC, Labels0, Labels1,
|
|
Instrs0, Instrs1),
|
|
( Instr = rl_PROC_label(Label) ->
|
|
% Register the label and remove the instruction.
|
|
map__det_insert(Labels1, Label, PC0, Labels),
|
|
Instrs = Instrs1
|
|
;
|
|
Labels = Labels1,
|
|
Instrs = [Instr | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type rl_lval
|
|
---> reg(reg_id)
|
|
|
|
% A field in the output tuple
|
|
; output_field(
|
|
int % field no
|
|
)
|
|
|
|
% A field of a term.
|
|
; term_arg(
|
|
reg_id,
|
|
cons_id,
|
|
int,
|
|
type % type of the term
|
|
).
|
|
|
|
:- type rl_rval
|
|
---> reg(reg_id)
|
|
|
|
; const(rl_const)
|
|
|
|
% A field in one of the input tuples
|
|
; input_field(
|
|
tuple_num,
|
|
int % field no
|
|
)
|
|
|
|
% An argument of a term in a register
|
|
; term_arg(
|
|
rl_rval, % register holding the term
|
|
cons_id,
|
|
int, % arg no
|
|
type % type of the term
|
|
).
|
|
|
|
:- type input_tuple
|
|
---> one
|
|
; two.
|
|
|
|
:- type reg_id == int.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type rl_exprn_info.
|
|
|
|
:- pred rl_exprn_info_init(module_info, instmap, map(prog_var, type),
|
|
prog_varset, rl_exprn_info).
|
|
:- mode rl_exprn_info_init(in, in, in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_init(module_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_init(in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_module_info(module_info,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_module_info(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_instmap(instmap, rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_instmap(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_instmap(instmap, rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_instmap(in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_vartypes(map(prog_var, type),
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_vartypes(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_vartypes(map(prog_var, type),
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_vartypes(in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_varset(prog_varset, rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_varset(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_varset(prog_varset, rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_varset(in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_vars(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_vars(in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_lookup_var(prog_var, int, rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_lookup_var(in, out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_free_reg((type), reg_id,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_free_reg(in, out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_next_label_id(label_id,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_next_label_id(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_lookup_const(rl_const, int,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_lookup_const(in, out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_consts(id_map(rl_const),
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_consts(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_lookup_rule(pair(rl_rule, exprn_tuple), int,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_lookup_rule(in, out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_rules(id_map(pair(rl_rule, exprn_tuple)),
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_rules(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_parent_pred_proc_ids(set(pred_proc_id),
|
|
rl_exprn_info, rl_exprn_info) is det.
|
|
:- mode rl_exprn_info_get_parent_pred_proc_ids(out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_parent_pred_proc_ids(set(pred_proc_id),
|
|
rl_exprn_info, rl_exprn_info) is det.
|
|
:- mode rl_exprn_info_set_parent_pred_proc_ids(in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_lookup_var_type(prog_var, type,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_lookup_var_type(in, out, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_var_locs(list(prog_var), list(reg_id),
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_var_locs(in, in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_set_var_loc(prog_var, reg_id,
|
|
rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_set_var_loc(in, in, in, out) is det.
|
|
|
|
:- pred rl_exprn_info_get_decls(list(type), rl_exprn_info, rl_exprn_info).
|
|
:- mode rl_exprn_info_get_decls(out, in, out) is det.
|
|
|
|
:- type rl_exprn_info
|
|
---> rl_exprn_info(
|
|
module_info,
|
|
instmap, % not yet used.
|
|
map(prog_var, type),
|
|
prog_varset,
|
|
id_map(prog_var),
|
|
label_id, % next label.
|
|
id_map(rl_const),
|
|
id_map(pair(rl_rule, exprn_tuple)),
|
|
set(pred_proc_id), % parent pred_proc_ids, used
|
|
% to abort on recursion.
|
|
list(type) % variable declarations in reverse.
|
|
).
|
|
|
|
:- type rl_rule
|
|
---> rl_rule(
|
|
string, % mangled type name Module__Name
|
|
string, % mangled functor name Module__Name
|
|
int % arity
|
|
).
|
|
|
|
% Each expression has a number of tuples associated with it,
|
|
% each of which has its own rule table.
|
|
:- type exprn_tuple
|
|
---> input1
|
|
; input2
|
|
; variables
|
|
; output1
|
|
; output2
|
|
.
|
|
|
|
:- type id_map(T) == pair(map(T, int), int).
|
|
|
|
:- pred id_map_init(id_map(T)::out) is det.
|
|
|
|
id_map_init(Empty - 0) :-
|
|
map__init(Empty).
|
|
|
|
:- pred id_map_lookup(T::in, int::out, bool::out,
|
|
id_map(T)::in, id_map(T)::out) is det.
|
|
|
|
id_map_lookup(Id, IdIndex, Added, Map0 - Index0, Map - Index) :-
|
|
( map__search(Map0, Id, IdIndex0) ->
|
|
IdIndex = IdIndex0,
|
|
Map = Map0,
|
|
Index = Index0,
|
|
Added = no
|
|
;
|
|
IdIndex = Index0,
|
|
Index = Index0 + 1,
|
|
Added = yes,
|
|
map__det_insert(Map0, Id, Index0, Map)
|
|
).
|
|
|
|
:- pred id_map_lookup(T::in, int::out, id_map(T)::in, id_map(T)::out) is det.
|
|
|
|
id_map_lookup(Id, IdIndex, Map0, Map) :-
|
|
id_map_lookup(Id, IdIndex, _, Map0, Map).
|
|
|
|
rl_exprn_info_init(ModuleInfo, Info0) :-
|
|
map__init(VarTypes),
|
|
varset__init(VarSet),
|
|
instmap__init_reachable(InstMap),
|
|
rl_exprn_info_init(ModuleInfo, InstMap, VarTypes, VarSet, Info0).
|
|
|
|
rl_exprn_info_init(ModuleInfo, InstMap, VarTypes, VarSet, Info) :-
|
|
id_map_init(VarMap),
|
|
id_map_init(ConstMap),
|
|
id_map_init(RuleMap),
|
|
set__init(Parents),
|
|
Label = 0,
|
|
Info = rl_exprn_info(ModuleInfo, InstMap, VarTypes, VarSet,
|
|
VarMap, Label, ConstMap, RuleMap, Parents, []).
|
|
|
|
rl_exprn_info_get_module_info(A, Info, Info) :-
|
|
Info = rl_exprn_info(A,_,_,_,_,_,_,_,_,_).
|
|
rl_exprn_info_get_instmap(B, Info, Info) :-
|
|
Info = rl_exprn_info(_,B,_,_,_,_,_,_,_,_).
|
|
rl_exprn_info_get_vartypes(C, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,C,_,_,_,_,_,_,_).
|
|
rl_exprn_info_get_varset(D, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,D,_,_,_,_,_,_).
|
|
rl_exprn_info_get_vars(E, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,_,E,_,_,_,_,_).
|
|
rl_exprn_info_get_consts(G, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,_,_,_,G,_,_,_).
|
|
rl_exprn_info_get_rules(H, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,_,_,_,_,H,_,_).
|
|
rl_exprn_info_get_parent_pred_proc_ids(I, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,_,_,_,_,_,I,_).
|
|
rl_exprn_info_get_decls(J, Info, Info) :-
|
|
Info = rl_exprn_info(_,_,_,_,_,_,_,_,_,J0),
|
|
list__reverse(J0, J).
|
|
|
|
rl_exprn_info_set_instmap(B, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,_,C,D,E,F,G,H,I,J),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,H,I,J).
|
|
rl_exprn_info_set_vartypes(C, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,_,D,E,F,G,H,I,J),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,H,I,J).
|
|
rl_exprn_info_set_varset(D, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,_,E,F,G,H,I,J),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,H,I,J).
|
|
rl_exprn_info_set_vars(E, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,_,F,G,H,I,J),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,H,I,J).
|
|
rl_exprn_info_set_parent_pred_proc_ids(I, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,E,F,G,H,_,J),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,H,I,J).
|
|
rl_exprn_info_get_free_reg(Type, Loc, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,VarMap0,F,G,H,I,RegTypes0),
|
|
VarMap0 = Map - Loc,
|
|
Loc1 = Loc + 1,
|
|
VarMap = Map - Loc1,
|
|
RegTypes = [Type | RegTypes0],
|
|
Info = rl_exprn_info(A,B,C,D,VarMap,F,G,H,I,RegTypes).
|
|
rl_exprn_info_lookup_var(Var, Loc, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,VarTypes,D,VarMap0,F,G,H,I,RegTypes0),
|
|
id_map_lookup(Var, Loc, Added, VarMap0, VarMap),
|
|
( Added = yes ->
|
|
map__lookup(VarTypes, Var, Type),
|
|
RegTypes = [Type | RegTypes0]
|
|
;
|
|
RegTypes = RegTypes0
|
|
),
|
|
Info = rl_exprn_info(A,B,VarTypes,D,VarMap,F,G,H,I,RegTypes).
|
|
rl_exprn_info_get_next_label_id(Label0, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,E,Label0,G,H,I,J),
|
|
Label = Label0 + 1,
|
|
Info = rl_exprn_info(A,B,C,D,E,Label,G,H,I,J).
|
|
rl_exprn_info_lookup_const(Const, Loc, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,E,F,Consts0,H,I,J),
|
|
id_map_lookup(Const, Loc, Consts0, Consts),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,Consts,H,I,J).
|
|
rl_exprn_info_lookup_rule(Rule, Loc, Info0, Info) :-
|
|
Info0 = rl_exprn_info(A,B,C,D,E,F,G,Rules0,I,J),
|
|
id_map_lookup(Rule, Loc, Rules0, Rules),
|
|
Info = rl_exprn_info(A,B,C,D,E,F,G,Rules,I,J).
|
|
|
|
rl_exprn_info_lookup_var_type(Var, Type) -->
|
|
rl_exprn_info_get_vartypes(VarTypes),
|
|
{ map__lookup(VarTypes, Var, Type) }.
|
|
|
|
rl_exprn_info_set_var_locs([], []) --> [].
|
|
rl_exprn_info_set_var_locs([_|_], []) -->
|
|
{ error("rl_exprn_info_set_var_locs") }.
|
|
rl_exprn_info_set_var_locs([], [_|_]) -->
|
|
{ error("rl_exprn_info_set_var_locs") }.
|
|
rl_exprn_info_set_var_locs([Var | Vars], [Loc | Locs]) -->
|
|
rl_exprn_info_set_var_loc(Var, Loc),
|
|
rl_exprn_info_set_var_locs(Vars, Locs).
|
|
|
|
rl_exprn_info_set_var_loc(Var, Loc) -->
|
|
rl_exprn_info_get_vars(VarMap0 - NextVar),
|
|
{ map__det_insert(VarMap0, Var, Loc, VarMap) },
|
|
rl_exprn_info_set_vars(VarMap - NextVar).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|