mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 07:15:19 +00:00
Estimated hours taken: 12 Branches: main Remove almost all dependencies by the modules of parse_tree.m on the modules of hlds.m. The only such dependencies remaining now are on type_util.m. compiler/hlds_data.m: compiler/prog_data.m: Move the cons_id type from hlds_data to prog_data, since several parts of the parse tree data structure depend on it (particularly insts). Remove the need to import HLDS modules in prog_data.m by making the cons_ids that refer to procedure ids refer to them via a new type that contains shrouded pred_ids and proc_ids. Since pred_ids and proc_ids are abstract types in hlds_data, add predicates to hlds_data to shroud and unshroud them. Also move some other types, e.g. mode_id and class_id, from hlds_data to prog_data. compiler/hlds_data.m: compiler/prog_util.m: Move predicates for manipulating cons_ids from hlds_data to prog_util. compiler/inst.m: compiler/prog_data.m: Move the contents of inst.m to prog_data.m, since that is where it belongs, and since doing so eliminates a circular dependency. The separation doesn't serve any purpose any more, since we don't need to import hlds_data.m anymore to get access to the cons_id type. compiler/mode_util.m: compiler/prog_mode.m: compiler/parse_tree.m: Move the predicates in mode_util that don't depend on the HLDS to a new module prog_mode, which is part of parse_tree.m. compiler/notes/compiler_design.m: Mention prog_mode.m, and delete the mention of inst.m. compiler/mercury_to_mercury.m: compiler/hlds_out.m: Move the predicates that depend on HLDS out of mercury_to_mercury.m to hlds_out.m. Export from mercury_to_mercury.m the predicates needed by the moved predicates. compiler/hlds_out.m: compiler/prog_out.m: Move predicates for printing parts of the parse tree out of hlds_out.m to prog_out.m, since mercury_to_mercury.m needs to use them. compiler/purity.m: compiler/prog_out.m: Move predicates for printing purities from purity.m, which is part of check_hlds.m, to prog_out.m, since mercury_to_mercury.m needs to use them. compiler/passes_aux.m: compiler/prog_out.m: Move some utility predicates (e.g. for printing progress messages) from passes_aux.m to prog_out.m, since some predicates in submodules of parse_tree.m need to use them. compiler/foreign.m: compiler/prog_data.m: Move some types from foreign.m to prog_data.m to allow the elimination of some dependencies on foreign.m from submodules of parse_tree.m. compiler/*.m: Conform to the changes above, mostly by updating lists of imported modules and module qualifications. In some cases, also do some local cleanups such as converting predicate declarations to predmode syntax and fixing white space.
2111 lines
70 KiB
Mathematica
2111 lines
70 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-2001, 2003-2004 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: rl_sort.m
|
|
% Main author: stayl
|
|
%
|
|
% Work out what sorting and indexing is available, and introduce
|
|
% sort-merge, hashed or indexed operations where possible.
|
|
%
|
|
% Remove unnecessary sort and add_index operations.
|
|
%
|
|
%
|
|
% Eventually this module should:
|
|
%
|
|
% Generate sort and add_index instructions where required.
|
|
% At the moment sorts are inserted where they might be required by
|
|
% rl_gen.m, but for example a union may be optimized into a union_diff
|
|
% and no longer require sorted input.
|
|
%
|
|
% For some operations such as sort-merge union, all that is required
|
|
% is that all inputs are sorted on all of their attributes.
|
|
% For these, we will eventually use a `sort variable', which stands for
|
|
% any sort specifier which sorts on all attributes - it is up to this
|
|
% module to work out which attribute ordering to use.
|
|
%
|
|
% Not yet, if ever - All inputs to a call are assumed to be sorted in
|
|
% ascending order on ascending attributes, and outputs are returned sorted
|
|
% the same way - I'm not sure if this is a good idea.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
:- module aditi_backend__rl_sort.
|
|
|
|
:- interface.
|
|
|
|
:- import_module aditi_backend__rl_block.
|
|
|
|
:- import_module io.
|
|
|
|
:- pred rl_sort__proc(rl_opt_info, rl_opt_info, io__state, io__state).
|
|
:- mode rl_sort__proc(in, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module aditi_backend__rl.
|
|
:- import_module aditi_backend__rl_analyse.
|
|
:- import_module aditi_backend__rl_key.
|
|
:- import_module hlds__hlds_module.
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module assoc_list, bool, int, list, map, relation, require, set.
|
|
:- import_module std_util.
|
|
|
|
rl_sort__proc(Opt0, Opt, IO0, IO) :-
|
|
rl_sort__proc_2(IO0, IO, Opt0, Opt).
|
|
|
|
:- pred rl_sort__proc_2(io__state, io__state, rl_opt_info, rl_opt_info).
|
|
:- mode rl_sort__proc_2(di, uo, in, out) is det.
|
|
|
|
rl_sort__proc_2(IO0, IO) -->
|
|
rl_opt_info_get_first_block_id(FirstBlock),
|
|
rl_opt_info_get_last_block_id(LastBlock),
|
|
|
|
% Memoed relations are either guaranteed to be empty at the start
|
|
% of the first block or sorted as they were at the end of the last
|
|
% block, so we add an extra arc in the flow graph to take this into
|
|
% account. The confluence operator must ensure that required
|
|
% sortedness for memoed relations only is propagated along this arc.
|
|
rl_opt_info_get_memoed_relations(MemoedRels),
|
|
( { set__empty(MemoedRels) } ->
|
|
[]
|
|
;
|
|
rl_opt_info_get_flow_graph(FlowGraph0),
|
|
{ relation__lookup_element(FlowGraph0, FirstBlock, FirstKey) },
|
|
{ relation__lookup_element(FlowGraph0, LastBlock, LastKey) },
|
|
{ relation__add(FlowGraph0, LastKey, FirstKey, FlowGraph1) },
|
|
rl_opt_info_set_flow_graph(FlowGraph1)
|
|
),
|
|
|
|
%
|
|
% The forward pass - work out which relations are
|
|
% sorted at the start of each block.
|
|
%
|
|
{ map__init(AvailSortMap0) },
|
|
rl_opt_info_get_rev_block_order(RevOrder),
|
|
{ list__reverse(RevOrder, Order) },
|
|
list__foldl2(rl_sort__init_block,
|
|
RevOrder, AvailSortMap0, AvailSortMap1),
|
|
|
|
{ AvailSortConfluence = rl_sort__confluence },
|
|
{ AvailSortBlockUpdate = rl_sort__avail_block_update },
|
|
{ AvailSortEqual = rl_sort__unify },
|
|
{ AvailSortWrite = rl_sort__write_sort_data },
|
|
|
|
{ AvailSortAnalysis =
|
|
rl_analysis(
|
|
forward,
|
|
AvailSortConfluence,
|
|
AvailSortBlockUpdate,
|
|
AvailSortEqual,
|
|
AvailSortWrite
|
|
) },
|
|
|
|
{ map__init(AvailVarRequests0) },
|
|
rl_analyse(Order, AvailSortAnalysis, AvailSortMap1, AvailSortMap,
|
|
AvailVarRequests0, _AvailVarRequests, IO0, IO1),
|
|
|
|
%
|
|
% Go through the instructions using joins and indexes where possible.
|
|
%
|
|
list__foldl(rl_sort__exploit_sorting_and_indexing(AvailSortMap),
|
|
Order),
|
|
|
|
%
|
|
% Work out which relations are required to be sorted at
|
|
% the end of each block.
|
|
%
|
|
{ map__init(NeededSortMap0) },
|
|
list__foldl2(rl_sort__init_block,
|
|
RevOrder, NeededSortMap0, NeededSortMap1),
|
|
|
|
{ NeededSortConfluence = rl_sort__confluence },
|
|
{ NeededSortBlockUpdate = rl_sort__needed_block_update },
|
|
{ NeededSortEqual = rl_sort__unify },
|
|
{ NeededSortWrite = rl_sort__write_sort_data },
|
|
|
|
{ NeededSortAnalysis =
|
|
rl_analysis(
|
|
backward,
|
|
NeededSortConfluence,
|
|
NeededSortBlockUpdate,
|
|
NeededSortEqual,
|
|
NeededSortWrite
|
|
) },
|
|
|
|
{ map__init(NeededVarRequests0) },
|
|
rl_analyse(RevOrder, NeededSortAnalysis, NeededSortMap1,
|
|
NeededSortMap, NeededVarRequests0, _NeededVarRequests,
|
|
IO1, IO),
|
|
|
|
%
|
|
% Go through the instructions removing unnecessary
|
|
% sorts and add_indexes.
|
|
%
|
|
list__foldl(
|
|
rl_sort__add_indexing_and_remove_useless_ops(NeededSortMap),
|
|
Order),
|
|
|
|
%
|
|
% Remove the arc we added for memoed relations.
|
|
%
|
|
( { set__empty(MemoedRels) } ->
|
|
[]
|
|
;
|
|
rl_opt_info_get_flow_graph(FlowGraph2),
|
|
{ relation__lookup_element(FlowGraph2, FirstBlock, FirstKey1) },
|
|
{ relation__lookup_element(FlowGraph2, LastBlock, LastKey1) },
|
|
{ relation__remove(FlowGraph2, LastKey1,
|
|
FirstKey1, FlowGraph) },
|
|
rl_opt_info_set_flow_graph(FlowGraph)
|
|
).
|
|
|
|
% For each relation_id, record every required sortedness.
|
|
% We'll eventually have to pick one for each relation_id at each point.
|
|
:- type sort_data == block_data(sortedness, unit).
|
|
|
|
:- type sortedness
|
|
---> sortedness(
|
|
relation_sort_map,
|
|
var_sort_map
|
|
).
|
|
|
|
:- type sort_index
|
|
---> sort(sort_spec)
|
|
; index(index_spec)
|
|
.
|
|
|
|
:- type relation_sort_map == map(relation_id, sort_req_map).
|
|
:- type sort_req_map == map(sort_index, sort_req).
|
|
:- type var_sort_map == map(int, set(relation_id)).
|
|
|
|
% Possible sortednesses for each sortedness variable.
|
|
% This is passed globally.
|
|
:- type var_requests == map(int, set(sort_index)).
|
|
|
|
:- type sort_info
|
|
---> sort_info(
|
|
sortedness,
|
|
var_requests,
|
|
rl_opt_info
|
|
).
|
|
|
|
:- type sort_req
|
|
---> sort_req(
|
|
is_definite,
|
|
set(block_id) % requesting/producing blocks
|
|
).
|
|
|
|
:- type is_definite
|
|
---> definite % This sortedness is definitely required.
|
|
; maybe
|
|
% This sortedness is possibly required.
|
|
% Record which block_ids requested this
|
|
% sortedness.
|
|
% Sortednesses required within the loop
|
|
% are preferred.
|
|
.
|
|
|
|
:- type sort_data_map == block_data_map(sortedness, unit).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Filter out unneeded specs.
|
|
:- type spec_filter == pred(pair(sort_index, sort_req)).
|
|
:- inst spec_filter == (pred(in) is semidet).
|
|
|
|
:- func true_filter = (spec_filter::out(spec_filter)) is det.
|
|
true_filter = (pred(_::in) is semidet :- true).
|
|
|
|
:- func sort_filter = (spec_filter::out(spec_filter)) is det.
|
|
sort_filter = (pred((sort(_) - _)::in) is semidet).
|
|
|
|
:- func index_filter = (spec_filter::out(spec_filter)) is det.
|
|
index_filter = (pred((index(_) - _)::in) is semidet).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__init_block(block_id::in, sort_data_map::in,
|
|
sort_data_map::out, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__init_block(BlockId, SortData0, SortData) -->
|
|
{ map__init(SortMap0) },
|
|
{ map__init(SortBindings0) },
|
|
{ Value = sortedness(SortMap0, SortBindings0) },
|
|
{ BlockData = block_data(Value, Value, unit) },
|
|
{ map__det_insert(SortData0, BlockId, BlockData, SortData) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__unify(sortedness::in, sortedness::in,
|
|
var_requests::in) is semidet.
|
|
|
|
rl_sort__unify(sortedness(RelMap1, VarMap1),
|
|
sortedness(RelMap2, VarMap2), _) :-
|
|
rl_sort__map_equal(rl_sort__map_equal(unify), RelMap1, RelMap2),
|
|
rl_sort__map_equal(unify, VarMap1, VarMap2).
|
|
|
|
:- pred rl_sort__map_equal(pred(V, V), map(K, V), map(K, V)).
|
|
:- mode rl_sort__map_equal(pred(in, in) is semidet, in, in) is semidet.
|
|
|
|
rl_sort__map_equal(UnifyValue, Map1, Map2) :-
|
|
map__foldl(
|
|
(pred(Key1::in, Value1::in, _Unit0::in, Unit::out) is semidet :-
|
|
Unit = unit,
|
|
map__search(Map2, Key1, Value2),
|
|
call(UnifyValue, Value1, Value2)
|
|
), Map1, unit, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Merge the information from multiple blocks.
|
|
:- pred rl_sort__confluence(pair(block_id, sortedness)::in,
|
|
pair(block_id, maybe(sortedness))::in, sortedness::out,
|
|
var_requests::in, var_requests::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__confluence(CalledBlockId - CalledSortData0,
|
|
ThisBlockId - MaybeSortData0, SortData,
|
|
VarRequests, VarRequests) -->
|
|
rl_opt_info_get_last_block_id(LastBlockId),
|
|
rl_opt_info_get_first_block_id(FirstBlockId),
|
|
(
|
|
(
|
|
{ ThisBlockId = LastBlockId },
|
|
{ CalledBlockId = FirstBlockId }
|
|
;
|
|
{ ThisBlockId = FirstBlockId },
|
|
{ CalledBlockId = LastBlockId }
|
|
)
|
|
->
|
|
% Restrict the passed in data from the first block
|
|
% to the memoed relations.
|
|
rl_opt_info_get_memoed_relations(MemoedRels),
|
|
{ rl_sort__restrict(CalledSortData0,
|
|
MemoedRels, CalledSortData) }
|
|
;
|
|
{ CalledSortData = CalledSortData0 }
|
|
),
|
|
|
|
{ MaybeSortData0 = yes(SortData0) ->
|
|
SortData0 = sortedness(SortedRels0, SortVars0),
|
|
CalledSortData = sortedness(CalledSortedRels,
|
|
CalledSortVars),
|
|
rl_sort__merge_sort_maps(SortedRels0,
|
|
CalledSortedRels, SortedRels),
|
|
rl_sort__merge_maps(SortVars0,
|
|
CalledSortVars, SortVars),
|
|
SortData = sortedness(SortedRels, SortVars)
|
|
;
|
|
SortData = CalledSortData
|
|
}.
|
|
|
|
:- pred rl_sort__merge_maps(map(T, set(U))::in, map(T, set(U))::in,
|
|
map(T, set(U))::out) is det.
|
|
|
|
rl_sort__merge_maps(Map1, Map2, NewMap) :-
|
|
UnionValues =
|
|
(pred(_::in, Value1::in, Value2::in, Value::out) is semidet :-
|
|
set__union(Value1, Value2, Value)
|
|
),
|
|
Id = (pred(_::in, Value::in, Value::out) is semidet),
|
|
merge_map_keys(UnionValues, Id, Map1, Map2, NewMap).
|
|
|
|
:- pred merge_map_keys(pred(K, V, V, V)::(pred(in, in, in, out) is semidet),
|
|
pred(K, V, V)::(pred(in, in, out) is semidet),
|
|
map(K, V)::in, map(K, V)::in, map(K, V)::out) is det.
|
|
|
|
merge_map_keys(UnionValues, Id, Map1, Map2, MergedMap) :-
|
|
map__keys(Map1, Keys1),
|
|
map__keys(Map2, Keys2),
|
|
list__append(Keys1, Keys2, Keys),
|
|
list__sort_and_remove_dups(Keys, SortedKeys),
|
|
map__init(MergedMap0),
|
|
list__foldl(merge_map_key(UnionValues, Id, Map1, Map2),
|
|
SortedKeys, MergedMap0, MergedMap).
|
|
|
|
:- pred merge_map_key(pred(K, V, V, V)::(pred(in, in, in, out) is semidet),
|
|
pred(K, V, V)::(pred(in, in, out) is semidet),
|
|
map(K, V)::in, map(K, V)::in, K::in,
|
|
map(K, V)::in, map(K, V)::out) is det.
|
|
|
|
merge_map_key(Merge, Single, Map1, Map2, Key, MergedMap0, MergedMap) :-
|
|
maybe_map_search(Map1, Key, MaybeValue1),
|
|
maybe_map_search(Map2, Key, MaybeValue2),
|
|
(
|
|
merge_maybes(Merge, Single, Key, MaybeValue1, MaybeValue2,
|
|
Value)
|
|
->
|
|
map__det_insert(MergedMap0, Key, Value, MergedMap)
|
|
;
|
|
MergedMap = MergedMap0
|
|
).
|
|
|
|
:- pred maybe_map_search(map(K, V)::in, K::in, maybe(V)::out) is det.
|
|
|
|
maybe_map_search(Map, Key, MaybeValue) :-
|
|
( map__search(Map, Key, Value) ->
|
|
MaybeValue = yes(Value)
|
|
;
|
|
MaybeValue = no
|
|
).
|
|
|
|
:- pred merge_maybes(pred(K, V, V, V)::(pred(in, in, in, out) is semidet),
|
|
pred(K, V, V)::(pred(in, in, out) is semidet),
|
|
K::in, maybe(V)::in, maybe(V)::in, V::out) is semidet.
|
|
|
|
merge_maybes(Merge, _, K, yes(V1), yes(V2), V) :- Merge(K, V1, V2, V).
|
|
merge_maybes(_, Single, K, yes(V1), no, V) :- Single(K, V1, V).
|
|
merge_maybes(_, Single, K, no, yes(V2), V) :- Single(K, V2, V).
|
|
|
|
:- pred rl_sort__semidet_merge_sort_maps(relation_sort_map::in,
|
|
relation_sort_map::in, relation_sort_map::out) is semidet.
|
|
|
|
rl_sort__semidet_merge_sort_maps(A, B, C) :-
|
|
rl_sort__merge_sort_maps(A, B, C),
|
|
semidet_succeed.
|
|
|
|
:- pred rl_sort__merge_sort_maps(relation_sort_map::in, relation_sort_map::in,
|
|
relation_sort_map::out) is det.
|
|
|
|
rl_sort__merge_sort_maps(RelSortMap1, RelSortMap2, RelSortMap) :-
|
|
MergeValues = semidet_merge_sort_req_map,
|
|
SingleValue = semidet_definite_to_maybe_sort_req_map,
|
|
merge_map_keys(MergeValues, SingleValue,
|
|
RelSortMap1, RelSortMap2, RelSortMap).
|
|
|
|
:- pred rl_sort__semidet_merge_sort_req_map(relation_id::in, sort_req_map::in,
|
|
sort_req_map::in, sort_req_map::out) is semidet.
|
|
|
|
rl_sort__semidet_merge_sort_req_map(A, B, C, D) :-
|
|
rl_sort__merge_sort_req_map(A, B, C, D),
|
|
semidet_succeed.
|
|
|
|
:- pred rl_sort__merge_sort_req_map(relation_id::in, sort_req_map::in,
|
|
sort_req_map::in, sort_req_map::out) is det.
|
|
|
|
rl_sort__merge_sort_req_map(_, SortReqMap1, SortReqMap2, SortReqMap) :-
|
|
MergeValue = rl_sort__semidet_merge_sort_reqs,
|
|
SingleValue = rl_sort__semidet_definite_to_maybe_sort_req,
|
|
merge_map_keys(MergeValue, SingleValue, SortReqMap1,
|
|
SortReqMap2, SortReqMap).
|
|
|
|
:- pred rl_sort__union_sort_req_map(relation_id::in, sort_req_map::in,
|
|
sort_req_map::in, sort_req_map::out) is det.
|
|
|
|
rl_sort__union_sort_req_map(_, SortReqMap1, SortReqMap2, SortReqMap) :-
|
|
MergeValue = rl_sort__semidet_merge_sort_reqs,
|
|
SingleValue = (pred(_::in, X::in, X::out) is semidet),
|
|
merge_map_keys(MergeValue, SingleValue, SortReqMap1,
|
|
SortReqMap2, SortReqMap).
|
|
|
|
:- pred semidet_definite_to_maybe_sort_req_map(relation_id::in,
|
|
sort_req_map::in, sort_req_map::out) is semidet.
|
|
|
|
semidet_definite_to_maybe_sort_req_map(A, B, C) :-
|
|
definite_to_maybe_sort_req_map(A, B, C),
|
|
semidet_succeed.
|
|
|
|
:- pred definite_to_maybe_sort_req_map(relation_id::in,
|
|
sort_req_map::in, sort_req_map::out) is det.
|
|
|
|
definite_to_maybe_sort_req_map(_, SortReqMap0, SortReqMap) :-
|
|
map__map_values(rl_sort__definite_to_maybe_sort_req,
|
|
SortReqMap0, SortReqMap).
|
|
|
|
:- pred rl_sort__semidet_definite_to_maybe_sort_req(sort_index::in,
|
|
sort_req::in, sort_req::out) is semidet.
|
|
|
|
rl_sort__semidet_definite_to_maybe_sort_req(A, B, C) :-
|
|
rl_sort__definite_to_maybe_sort_req(A, B, C),
|
|
semidet_succeed.
|
|
|
|
:- pred rl_sort__definite_to_maybe_sort_req(sort_index::in, sort_req::in,
|
|
sort_req::out) is det.
|
|
|
|
rl_sort__definite_to_maybe_sort_req(_, sort_req(_, BlockIds),
|
|
sort_req(maybe, BlockIds)).
|
|
|
|
:- pred rl_sort__semidet_merge_sort_reqs(sort_index::in, sort_req::in,
|
|
sort_req::in, sort_req::out) is semidet.
|
|
|
|
rl_sort__semidet_merge_sort_reqs(A, B, C, D) :-
|
|
rl_sort__merge_sort_reqs(A, B, C, D),
|
|
semidet_succeed.
|
|
|
|
:- pred rl_sort__merge_sort_reqs(sort_index::in, sort_req::in,
|
|
sort_req::in, sort_req::out) is det.
|
|
|
|
rl_sort__merge_sort_reqs(_, Req0, Req1, Req) :-
|
|
Req0 = sort_req(Definite0, BlockIds0),
|
|
Req1 = sort_req(Definite1, BlockIds1),
|
|
set__union(BlockIds0, BlockIds1, BlockIds),
|
|
(
|
|
( Definite0 = maybe
|
|
; Definite1 = maybe
|
|
)
|
|
->
|
|
Definite = maybe
|
|
;
|
|
Definite= definite
|
|
),
|
|
Req = sort_req(Definite, BlockIds).
|
|
|
|
:- pred rl_sort__restrict(sortedness::in, set(relation_id)::in,
|
|
sortedness::out) is det.
|
|
|
|
rl_sort__restrict(SortData0, Rels, SortData) :-
|
|
SortData0 = sortedness(SortedRels0, SortVars0),
|
|
map__select(SortedRels0, Rels, SortedRels),
|
|
IntersectRels = (pred(_::in, VarRels0::in, VarRels::out) is det :-
|
|
set__intersect(VarRels0, Rels, VarRels)
|
|
),
|
|
map__map_values(IntersectRels, SortVars0, SortVars),
|
|
SortData = sortedness(SortedRels, SortVars).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__add_call_sortedness(block_id::in, relation_id::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__add_call_sortedness(_BlockId, _Output) --> [].
|
|
/*
|
|
% XXX I'm not sure whether this is a good idea, so it's commented
|
|
% out for now.
|
|
rl_opt_info_get_relation_info(Output, OutputInfo),
|
|
{ OutputInfo = relation_info(_, Schema, _, _) },
|
|
{ rl__ascending_sort_spec(Schema, Spec) },
|
|
{ rl_sort__add_relation_sortedness(BlockId, Spec, Output,
|
|
Sortedness0, Sortedness) }.
|
|
*/
|
|
|
|
:- pred rl_sort__add_relation_sortedness(block_id::in, sort_index::in,
|
|
relation_id::in, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__add_relation_sortedness(BlockId, Spec, RelationId) -->
|
|
{ set__singleton_set(BlockIds, BlockId) },
|
|
{ SortReq = sort_req(definite, BlockIds) },
|
|
{ map__from_assoc_list([Spec - SortReq], Map) },
|
|
rl_sort__add_relation_sortedness_map(Map, RelationId).
|
|
|
|
:- pred rl_sort__add_relation_sortedness_map(map(sort_index, sort_req)::in,
|
|
relation_id::in, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__add_relation_sortedness_map(NewSortSpecs, RelationId,
|
|
SortInfo0, SortInfo) :-
|
|
SortInfo0 = sort_info(Sortedness0, VarReqs0, RLInfo),
|
|
Sortedness0 = sortedness(RelMap0, VarMap0),
|
|
( map__search(RelMap0, RelationId, SortSpecs0) ->
|
|
map__keys(SortSpecs0, Specs0),
|
|
set__sorted_list_to_set(Specs0, SpecSet0),
|
|
rl_sort__get_vars(SpecSet0, Vars0),
|
|
rl_sort__union_sort_req_map(RelationId, NewSortSpecs,
|
|
SortSpecs0, SortSpecs),
|
|
map__det_update(RelMap0, RelationId, SortSpecs, RelMap)
|
|
;
|
|
set__init(Vars0),
|
|
map__det_insert(RelMap0, RelationId,
|
|
NewSortSpecs, RelMap),
|
|
SortSpecs = NewSortSpecs
|
|
),
|
|
|
|
map__keys(NewSortSpecs, NewSpecs0),
|
|
set__sorted_list_to_set(NewSpecs0, NewSpecs),
|
|
map__keys(SortSpecs, Specs1),
|
|
set__sorted_list_to_set(Specs1, Specs),
|
|
rl_sort__get_vars(Specs, Vars),
|
|
|
|
set__difference(Vars, Vars0, NewVars),
|
|
set__difference(Vars, NewVars, OldVars),
|
|
set__to_sorted_list(NewVars, NewVarsList),
|
|
set__to_sorted_list(OldVars, OldVarsList),
|
|
|
|
rl_sort__update_var_requests(OldVarsList, Specs, VarReqs0, VarReqs1),
|
|
rl_sort__update_var_requests(NewVarsList, NewSpecs, VarReqs1, VarReqs),
|
|
|
|
list__foldl(rl_sort__add_var_relation(RelationId), NewVarsList,
|
|
VarMap0, VarMap),
|
|
|
|
Sortedness = sortedness(RelMap, VarMap),
|
|
SortInfo = sort_info(Sortedness, VarReqs, RLInfo).
|
|
|
|
:- pred rl_sort__get_vars(set(sort_index)::in, set(int)::out) is det.
|
|
|
|
rl_sort__get_vars(Specs, Vars) :-
|
|
set__to_sorted_list(Specs, SpecList),
|
|
rl_sort__get_vars_2(SpecList, Vars0),
|
|
set__list_to_set(Vars0, Vars).
|
|
|
|
:- pred rl_sort__get_vars_2(list(sort_index)::in, list(int)::out) is det.
|
|
|
|
rl_sort__get_vars_2([], []).
|
|
rl_sort__get_vars_2([sort(sort_var(Var)) | Specs], [Var | Vars]) :-
|
|
rl_sort__get_vars_2(Specs, Vars).
|
|
rl_sort__get_vars_2([sort(attributes(_)) | _], []).
|
|
rl_sort__get_vars_2([index(_) | _], []).
|
|
|
|
:- pred rl_sort__update_var_requests(list(int)::in, set(sort_index)::in,
|
|
var_requests::in, var_requests::out) is det.
|
|
|
|
rl_sort__update_var_requests([], _, VarReqs, VarReqs).
|
|
rl_sort__update_var_requests([Var | Vars], Specs1, VarReqs0, VarReqs) :-
|
|
( map__search(VarReqs0, Var, Specs0) ->
|
|
set__union(Specs0, Specs1, Specs),
|
|
map__det_update(VarReqs0, Var, Specs, VarReqs1)
|
|
;
|
|
map__det_insert(VarReqs0, Var, Specs1, VarReqs1)
|
|
),
|
|
rl_sort__update_var_requests(Vars, Specs1, VarReqs1, VarReqs).
|
|
|
|
:- pred rl_sort__add_var_relation(relation_id::in, int::in,
|
|
var_sort_map::in, var_sort_map::out) is det.
|
|
|
|
rl_sort__add_var_relation(RelationId, Var, VarMap0, VarMap) :-
|
|
( map__search(VarMap0, Var, VarRels0) ->
|
|
set__insert(VarRels0, RelationId, VarRels),
|
|
map__det_update(VarMap0, Var, VarRels, VarMap)
|
|
;
|
|
set__singleton_set(VarRels, RelationId),
|
|
map__det_insert(VarMap0, Var, VarRels, VarMap)
|
|
).
|
|
|
|
:- pred rl_sort__remove_var_relation(relation_id::in, sort_index::in,
|
|
sort_req::in, var_sort_map::in, var_sort_map::out) is det.
|
|
|
|
rl_sort__remove_var_relation(RelationId, SortSpec, _, VarMap0, VarMap) :-
|
|
(
|
|
SortSpec = sort(sort_var(Var)),
|
|
map__search(VarMap0, Var, VarRels0)
|
|
->
|
|
set__delete(VarRels0, RelationId, VarRels),
|
|
map__det_update(VarMap0, Var, VarRels, VarMap)
|
|
;
|
|
VarMap = VarMap0
|
|
).
|
|
|
|
:- pred rl_sort__remove_relation_id(relation_id::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__remove_relation_id(RelationId, sort_info(Sortedness0, VarReq, C),
|
|
sort_info(Sortedness, VarReq, C)) :-
|
|
Sortedness0 = sortedness(RelMap0, VarMap0),
|
|
( map__search(RelMap0, RelationId, SortSpecs) ->
|
|
map__delete(RelMap0, RelationId, RelMap),
|
|
map__foldl(rl_sort__remove_var_relation(RelationId),
|
|
SortSpecs, VarMap0, VarMap),
|
|
Sortedness = sortedness(RelMap, VarMap)
|
|
;
|
|
Sortedness = Sortedness0
|
|
).
|
|
|
|
% Add the required sortedness of the first relation
|
|
% to that of the second.
|
|
:- pred rl_sort__assign_sortedness_and_indexing(block_id::in,
|
|
relation_id::in, relation_id::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__assign_sortedness_and_indexing(BlockId,
|
|
Relation1, Relation2) -->
|
|
rl_sort__assign_sortedness_and_indexing(true_filter, BlockId,
|
|
Relation1, Relation2).
|
|
|
|
:- pred rl_sort__assign_sortedness_and_indexing(spec_filter::in(spec_filter),
|
|
block_id::in, relation_id::in, relation_id::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__assign_sortedness_and_indexing(SpecFilter, BlockId,
|
|
TargetRelation, SourceRelation) -->
|
|
=(sort_info(sortedness(RelMap0, _), _, RLInfo)),
|
|
{ rl_opt_info_get_relation_info(SourceRelation,
|
|
SourceRelInfo, RLInfo, _) },
|
|
( { SourceRelInfo = relation_info(permanent(_), _, Indexes, _) } ->
|
|
{ map__init(Specs0) },
|
|
{ set__singleton_set(BlockIds, BlockId) },
|
|
{ list__foldl(
|
|
(pred(Index::in, SpecMap0::in, SpecMap::out) is det :-
|
|
map__set(SpecMap0, index(Index),
|
|
sort_req(definite, BlockIds), SpecMap)
|
|
), Indexes, Specs0, Specs1) },
|
|
{ map__to_assoc_list(Specs1, SpecAL1) },
|
|
{ list__filter(SpecFilter, SpecAL1, SpecAL) },
|
|
{ map__from_assoc_list(SpecAL, Specs) },
|
|
rl_sort__add_relation_sortedness_map(Specs, TargetRelation)
|
|
; { map__search(RelMap0, SourceRelation, Specs0) } ->
|
|
{ map__to_assoc_list(Specs0, SpecAL0) },
|
|
{ list__filter(SpecFilter, SpecAL0, SpecAL) },
|
|
{ map__from_assoc_list(SpecAL, Specs) },
|
|
rl_sort__add_relation_sortedness_map(Specs, TargetRelation)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred rl_sort__handle_output_indexing(block_id::in, output_rel::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__handle_output_indexing(BlockId, output_rel(Output, Indexes0)) -->
|
|
{ set__singleton_set(BlockIds, BlockId) },
|
|
{ list__sort_and_remove_dups(Indexes0, Indexes) },
|
|
{ list__map(
|
|
(pred(Index::in, Spec::out) is det :-
|
|
Spec = index(Index) - sort_req(definite, BlockIds)
|
|
), Indexes, Specs0) },
|
|
{ map__from_assoc_list(Specs0, Specs) },
|
|
rl_sort__add_relation_sortedness_map(Specs, Output).
|
|
|
|
:- pred rl_sort__assign_indexing(block_id::in, relation_id::in,
|
|
relation_id::in, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__assign_indexing(BlockId, Output, Input) -->
|
|
rl_sort__assign_sortedness_and_indexing(index_filter,
|
|
BlockId, Output, Input).
|
|
|
|
:- pred rl_sort__assign_sortedness(block_id::in, relation_id::in,
|
|
relation_id::in, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__assign_sortedness(BlockId, Output, Input) -->
|
|
rl_sort__assign_sortedness_and_indexing(sort_filter,
|
|
BlockId, Output, Input).
|
|
|
|
:- pred rl_sort__unset_relation(relation_id::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__unset_relation(Relation, SortInfo0, SortInfo) :-
|
|
SortInfo0 = sort_info(sortedness(RelMap0, VarMap), VarReqs, Info),
|
|
map__delete(RelMap0, Relation, RelMap),
|
|
SortInfo = sort_info(sortedness(RelMap, VarMap), VarReqs, Info).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Work out what sorting and indexing is required at the start
|
|
% of a block given the sorting and indexing required at the
|
|
% end of the block.
|
|
:- pred rl_sort__needed_block_update(block_id::in, sortedness::in,
|
|
sort_data::in, sort_data::out, var_requests::in,
|
|
var_requests::out, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__needed_block_update(BlockId, InValue0,
|
|
_SortData0, SortData, VarReqs0, VarReqs, Info0, Info) :-
|
|
rl_opt_info_get_last_block_id(LastBlockId, Info0, Info1),
|
|
rl_opt_info_get_output_relations(Outputs, Info1, Info2),
|
|
rl_opt_info_get_block(BlockId, Block, Info2, Info3),
|
|
SortInfo0 = sort_info(InValue0, VarReqs0, Info3),
|
|
( BlockId = LastBlockId ->
|
|
% For the last block, the in value is InValue0 (which contains
|
|
% the required sortedness of the memoed relations) plus
|
|
% the required sortedness of the output relations.
|
|
list__foldl(rl_sort__add_call_sortedness(BlockId), Outputs,
|
|
SortInfo0, SortInfo1)
|
|
;
|
|
SortInfo1 = SortInfo0
|
|
),
|
|
|
|
Block = block(_, Instrs, _, block_info(LiveAtStart, _)),
|
|
list__reverse(Instrs, RevInstrs),
|
|
list__foldl(rl_sort__instr_needed(BlockId), RevInstrs,
|
|
SortInfo1, sort_info(OutValue0, VarReqs, Info)),
|
|
rl_sort__restrict(OutValue0, LiveAtStart, OutValue),
|
|
SortData = block_data(InValue0, OutValue, unit).
|
|
|
|
:- pred rl_sort__instr_needed(block_id::in, rl_instruction::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__instr_needed(BlockId,
|
|
join(_Output, Input1, Input2, Type, _Exprn, _, _) - _) -->
|
|
(
|
|
{ Type = nested_loop }
|
|
;
|
|
{ Type = hash(_, _) }
|
|
;
|
|
{ Type = sort_merge(SortSpec1, SortSpec2) },
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec1),
|
|
Input1),
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec2),
|
|
Input2)
|
|
;
|
|
{ Type = index(Index, _) },
|
|
rl_sort__add_relation_sortedness(BlockId, index(Index),
|
|
Input2)
|
|
).
|
|
rl_sort__instr_needed(BlockId,
|
|
subtract(_Output, Input1, Input2, Type, _Exprn, _Semi) - _) -->
|
|
(
|
|
{ Type = semi_nested_loop }
|
|
;
|
|
{ Type = semi_hash(_, _) }
|
|
;
|
|
{ Type = semi_sort_merge(SortSpec1, SortSpec2) },
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec1),
|
|
Input1),
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec2),
|
|
Input2)
|
|
;
|
|
{ Type = semi_index(Index, _) },
|
|
rl_sort__add_relation_sortedness(BlockId, index(Index),
|
|
Input2)
|
|
).
|
|
rl_sort__instr_needed(BlockId,
|
|
difference(_Output, Input1, Input2, Type) - _) -->
|
|
{ Type = sort_merge(SortSpec) },
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec), Input1),
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec), Input2).
|
|
|
|
% XXX interpret projection conditions.
|
|
rl_sort__instr_needed(_, project(_, _Input1, _,
|
|
_, _) - _) --> [].
|
|
rl_sort__instr_needed(BlockId, union(_Output, Inputs, Type) - _) -->
|
|
{ Type = sort_merge(SortSpec) },
|
|
list__foldl(rl_sort__add_relation_sortedness(BlockId, sort(SortSpec)),
|
|
Inputs).
|
|
rl_sort__instr_needed(BlockId, insert(UoOutput, DiInput, _, InsertType, _) - _)
|
|
-->
|
|
( { InsertType = index(Index) } ->
|
|
rl_sort__assign_indexing(BlockId, DiInput, UoOutput),
|
|
rl_sort__add_relation_sortedness(BlockId,
|
|
index(Index), DiInput)
|
|
;
|
|
[]
|
|
).
|
|
rl_sort__instr_needed(BlockId,
|
|
union_diff(UoOutput, DiInput, _, _, Index, _) - _) -->
|
|
rl_sort__assign_indexing(BlockId, DiInput, UoOutput),
|
|
rl_sort__add_relation_sortedness(BlockId, index(Index), DiInput).
|
|
rl_sort__instr_needed(_BlockId, sort(_Output, _Input, _Attrs) - _) --> [].
|
|
rl_sort__instr_needed(BlockId, ref(Output, Input) - _) -->
|
|
rl_sort__assign_sortedness_and_indexing(BlockId, Input, Output).
|
|
rl_sort__instr_needed(BlockId, copy(Output, Input) - _) -->
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness(BlockId, Input, OutputRel).
|
|
rl_sort__instr_needed(BlockId, make_unique(Output, Input) - _) -->
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness(BlockId, Input, OutputRel).
|
|
rl_sort__instr_needed(_BlockId, init(_Output) - _) --> [].
|
|
rl_sort__instr_needed(_BlockId, insert_tuple(_, _, _) - _) --> [].
|
|
rl_sort__instr_needed(_BlockId, call(_, _Inputs, _Outputs, _) - _) --> [].
|
|
rl_sort__instr_needed(BlockId, aggregate(_Output, Input, _, _) - _) -->
|
|
% An aggregate's input is sorted on both attributes.
|
|
rl_sort__add_relation_sortedness(BlockId,
|
|
sort(attributes([1 - ascending, 2 - ascending])), Input).
|
|
rl_sort__instr_needed(_BlockId, add_index(_Output, _) - _) --> [].
|
|
rl_sort__instr_needed(_, clear(_) - _) --> [].
|
|
rl_sort__instr_needed(_, unset(Relation) - _) -->
|
|
rl_sort__unset_relation(Relation).
|
|
rl_sort__instr_needed(_, label(_) - _) --> [].
|
|
rl_sort__instr_needed(_, conditional_goto(_, _) - _) --> [].
|
|
rl_sort__instr_needed(_, goto(_) - _) --> [].
|
|
rl_sort__instr_needed(_, comment - _) --> [].
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__write_sort_data(sort_data::in, var_requests::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
rl_sort__write_sort_data(block_data(sortedness(InSortData, _),
|
|
sortedness(OutSortData, _), _), _) -->
|
|
io__write_string("in: "),
|
|
map__foldl(rl_sort__write_sort_req_map, InSortData),
|
|
io__nl,
|
|
io__write_string("out: "),
|
|
map__foldl(rl_sort__write_sort_req_map, OutSortData),
|
|
io__nl.
|
|
|
|
:- pred rl_sort__write_sort_req_map(relation_id::in,
|
|
map(sort_index, sort_req)::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
rl_sort__write_sort_req_map(Rel, SortMap) -->
|
|
io__write_int(Rel),
|
|
io__write_string(" -> "),
|
|
map__foldl(rl_sort__write_sort_req, SortMap),
|
|
io__nl.
|
|
|
|
:- pred rl_sort__write_sort_req(sort_index::in, sort_req::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
rl_sort__write_sort_req(SortIndex, SortReqs) -->
|
|
io__write_string("\t"),
|
|
io__write(SortIndex),
|
|
io__write_string(" - "),
|
|
io__write(SortReqs),
|
|
io__nl.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Work out what sorting and indexing is available at the end
|
|
% of a block given the sorting and indexing available at the start.
|
|
:- pred rl_sort__avail_block_update(block_id::in, sortedness::in,
|
|
sort_data::in, sort_data::out, var_requests::in, var_requests::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__avail_block_update(BlockId, InValue0, _SortData0, SortData,
|
|
VarRequests0, VarRequests, Info0, Info) :-
|
|
rl_opt_info_get_first_block_id(FirstBlockId, Info0, Info1),
|
|
rl_opt_info_get_block(BlockId, Block, Info1, Info2),
|
|
rl_opt_info_get_input_relations(Inputs, Info2, Info3),
|
|
SortInfo0 = sort_info(InValue0, VarRequests0, Info3),
|
|
( BlockId = FirstBlockId ->
|
|
% For the first block, the in value is InValue0 (which contains
|
|
% the required sortedness of the memoed relations) plus
|
|
% the required sortedness of the input relations.
|
|
list__foldl(rl_sort__add_call_sortedness(BlockId), Inputs,
|
|
SortInfo0, SortInfo1)
|
|
;
|
|
SortInfo1 = SortInfo0
|
|
),
|
|
SortInfo1 = sort_info(InValue, _, _),
|
|
|
|
Block = block(_, Instrs, _, block_info(_, LiveAtEnd)),
|
|
list__foldl(rl_sort__instr_avail(BlockId), Instrs,
|
|
SortInfo1, sort_info(OutValue0, VarRequests, Info)),
|
|
rl_sort__restrict(OutValue0, LiveAtEnd, OutValue),
|
|
|
|
SortData = block_data(InValue, OutValue, unit).
|
|
|
|
:- pred rl_sort__instr_avail(block_id::in, rl_instruction::in,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__instr_avail(BlockId,
|
|
join(Output, Input1, Input2, _Type, _Exprn,
|
|
SemiJoin, Trivial) - _)
|
|
-->
|
|
(
|
|
{ SemiJoin = yes(_) },
|
|
{ Trivial = yes(trivial_join_or_subtract_info(TupleNum, no)) }
|
|
->
|
|
%
|
|
% For trivial semi-joins, which test one of the inputs
|
|
% for emptiness and return the other, the sortedness
|
|
% and indexing for the returned relation is passed through
|
|
% to the output.
|
|
%
|
|
{ TupleNum = one, PassedInput = Input1
|
|
; TupleNum = two, PassedInput = Input2
|
|
},
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness_and_indexing(BlockId,
|
|
OutputRel, PassedInput)
|
|
;
|
|
rl_sort__handle_output_indexing(BlockId, Output)
|
|
).
|
|
rl_sort__instr_avail(BlockId,
|
|
subtract(Output, Input1, _Input2, _Type,
|
|
_Exprn, TrivialSubtract) - _)
|
|
-->
|
|
(
|
|
{ TrivialSubtract = yes(_) }
|
|
->
|
|
%
|
|
% For trivial subtracts, the sortedness and indexing for
|
|
% the first input relation is passed through to the output.
|
|
%
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness_and_indexing(BlockId,
|
|
OutputRel, Input1)
|
|
;
|
|
rl_sort__handle_output_indexing(BlockId, Output)
|
|
).
|
|
rl_sort__instr_avail(BlockId,
|
|
difference(Output, _Input1, _Input2, _Type) - _) -->
|
|
% { Type = sort_merge(SortSpec) },
|
|
% XXX is the output of a difference sorted?
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, project(Output, Input, Goal,
|
|
OtherProjectOutputs, _) - _) -->
|
|
rl_sort__handle_project_sortedness(Input, Output - Goal),
|
|
list__foldl(rl_sort__handle_project_sortedness(Input),
|
|
OtherProjectOutputs),
|
|
{ assoc_list__keys(OtherProjectOutputs, OtherOutputs) },
|
|
list__foldl(rl_sort__handle_output_indexing(BlockId),
|
|
[Output | OtherOutputs]).
|
|
rl_sort__instr_avail(BlockId, union(Output, _Inputs, Type) - _) -->
|
|
{ Type = sort_merge(SortSpec) },
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__add_relation_sortedness(BlockId, sort(SortSpec), OutputRel),
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, insert(UoOutput, DiInput, _Input, _Type, _) - _)
|
|
-->
|
|
rl_sort__assign_indexing(BlockId, UoOutput, DiInput).
|
|
rl_sort__instr_avail(BlockId,
|
|
union_diff(UoOutput, DiInput, _Input1, Diff, _, _) - _) -->
|
|
rl_sort__assign_indexing(BlockId, UoOutput, DiInput),
|
|
rl_sort__handle_output_indexing(BlockId, Diff).
|
|
rl_sort__instr_avail(BlockId, sort(Output, _Input, Attrs) - _) -->
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__add_relation_sortedness(BlockId,
|
|
sort(attributes(Attrs)), OutputRel),
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, ref(Output, Input) - _) -->
|
|
rl_sort__assign_sortedness_and_indexing(BlockId, Output, Input).
|
|
rl_sort__instr_avail(BlockId, copy(Output, Input) - _) -->
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness(BlockId, OutputRel, Input),
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, make_unique(Output, Input) - _) -->
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__assign_sortedness(BlockId, OutputRel, Input),
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, init(Output) - _) -->
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, insert_tuple(Output, _, _) - _) -->
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, call(_, _Inputs, Outputs, _) - _) -->
|
|
list__foldl(rl_sort__handle_output_indexing(BlockId), Outputs).
|
|
rl_sort__instr_avail(BlockId, aggregate(Output, _Input, _, _) - _) -->
|
|
% An aggregate's output is sorted on both attributes.
|
|
{ Output = output_rel(OutputRel, _) },
|
|
rl_sort__add_relation_sortedness(BlockId,
|
|
sort(attributes([1 - ascending, 2 - ascending])), OutputRel),
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(BlockId, add_index(Output, _) - _) -->
|
|
rl_sort__handle_output_indexing(BlockId, Output).
|
|
rl_sort__instr_avail(_, clear(_) - _) --> [].
|
|
rl_sort__instr_avail(_, unset(Relation) - _) -->
|
|
rl_sort__unset_relation(Relation).
|
|
rl_sort__instr_avail(_, label(_) - _) --> [].
|
|
rl_sort__instr_avail(_, conditional_goto(_, _) - _) --> [].
|
|
rl_sort__instr_avail(_, goto(_) - _) --> [].
|
|
rl_sort__instr_avail(_, comment - _) --> [].
|
|
|
|
:- pred rl_sort__handle_project_sortedness(relation_id::in,
|
|
pair(output_rel, rl_goal)::in, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__handle_project_sortedness(Input, output_rel(Output, _) - Goal) -->
|
|
=(sort_info(sortedness(RelMap0, _VarMap0), _, _)),
|
|
( { map__search(RelMap0, Input, InputSortedness) } ->
|
|
{ map__to_assoc_list(InputSortedness, InputSortednessAL) },
|
|
{ list__filter_map(rl_sort__interpret_project(Goal),
|
|
InputSortednessAL, OutputSortednessAL) },
|
|
{ map__from_assoc_list(OutputSortednessAL, OutputSortedness) },
|
|
rl_sort__add_relation_sortedness_map(OutputSortedness, Output)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred rl_sort__interpret_project(rl_goal::in, pair(sort_index, sort_req)::in,
|
|
pair(sort_index, sort_req)::out) is semidet.
|
|
|
|
rl_sort__interpret_project(RLGoal, sort(SortSpec0) - Reqs,
|
|
sort(SortSpec) - Reqs) :-
|
|
RLGoal = rl_goal(_, _, _, _, Inputs, Outputs, _, _),
|
|
Inputs = one_input(InputArgs),
|
|
(
|
|
% A select.
|
|
Outputs = no,
|
|
SortSpec = SortSpec0
|
|
;
|
|
% A project.
|
|
Outputs = yes(OutputArgs),
|
|
SortSpec0 = attributes(SortAttrs0),
|
|
|
|
% Work out the sort specification in terms
|
|
% of the input arguments.
|
|
list__map((pred(AttrDir::in, VarDir::out) is det :-
|
|
AttrDir = Attr - Dir,
|
|
list__index1_det(InputArgs, Attr, Var),
|
|
VarDir = Var - Dir
|
|
), SortAttrs0, VarAttrs0),
|
|
|
|
% Take the longest prefix of the sort specification that
|
|
% is in the output arguments (we could do better here
|
|
% by looking at the goal, since some of the outputs may
|
|
% be equivalent but not named identically to the input).
|
|
list__takewhile((pred(VarDir::in) is semidet :-
|
|
VarDir = Var - _,
|
|
list__member(Var, OutputArgs)
|
|
), VarAttrs0, VarAttrs, _),
|
|
VarAttrs \= [],
|
|
|
|
% Map those output arguments back into argument numbers.
|
|
list__map((pred(VarDir::in, AttrDirs::out) is det :-
|
|
VarDir = Var - Dir,
|
|
rl_sort__all_positions(OutputArgs,
|
|
1, Var, Attrs),
|
|
list__map((pred(X::in, Y::out) is det :-
|
|
Y = X - Dir
|
|
), Attrs, AttrDirs)
|
|
), VarAttrs, SortAttrs1),
|
|
list__condense(SortAttrs1, SortAttrs),
|
|
SortSpec = attributes(SortAttrs)
|
|
).
|
|
|
|
% Find all indexes of the variable in the list of variables.
|
|
% XXX possibly should be in list.m.
|
|
:- pred rl_sort__all_positions(list(prog_var)::in,
|
|
int::in, prog_var::in, list(int)::out) is det.
|
|
|
|
rl_sort__all_positions([], _, _, []).
|
|
rl_sort__all_positions([Arg | Args], Index0, Var, Attrs) :-
|
|
Index = Index0 + 1,
|
|
( Arg = Var ->
|
|
Attrs = [Index0 | Attrs1],
|
|
rl_sort__all_positions(Args, Index, Var, Attrs1)
|
|
;
|
|
rl_sort__all_positions(Args, Index, Var, Attrs)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__exploit_sorting_and_indexing(sort_data_map::in,
|
|
block_id::in, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__exploit_sorting_and_indexing(AvailSortMap, BlockId, Info0, Info) :-
|
|
rl_opt_info_get_block(BlockId, Block0, Info0, Info1),
|
|
Block0 = block(Label, Instrs0, EndInstr, BlockInfo),
|
|
|
|
map__lookup(AvailSortMap, BlockId, block_data(AvailSorts, _, _)),
|
|
map__init(VarRequests),
|
|
SortInfo0 = sort_info(AvailSorts, VarRequests, Info1),
|
|
|
|
list__foldl2(rl_sort__specialize_instr(BlockId),
|
|
Instrs0, [], RevInstrs, SortInfo0, sort_info(_, _, Info2)),
|
|
list__reverse(RevInstrs, Instrs),
|
|
Block = block(Label, Instrs, EndInstr, BlockInfo),
|
|
rl_opt_info_set_block(BlockId, Block, Info2, Info).
|
|
|
|
:- pred rl_sort__specialize_instr(block_id::in, rl_instruction::in,
|
|
list(rl_instruction)::in, list(rl_instruction)::out,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__specialize_instr(BlockId, Instr0, Instrs0, Instrs) -->
|
|
(
|
|
{ Instr0 = join(Output, Input1, Input2, Type, Exprn,
|
|
SemiJoin, TrivialJoin) - Comment }
|
|
->
|
|
rl_sort__specialize_join(Instr0, Output, Input1, Input2,
|
|
Type, Exprn, SemiJoin, TrivialJoin,
|
|
Comment, Instrs0, Instrs)
|
|
;
|
|
{ Instr0 = subtract(Output, Input1, Input2, Type, Exprn,
|
|
TrivialSubtract) - Comment }
|
|
->
|
|
rl_sort__specialize_subtract(Instr0, Output, Input1, Input2,
|
|
Type, Exprn, TrivialSubtract, Comment, Instrs0, Instrs)
|
|
;
|
|
{ Instr0 = project(Output, Input, Exprn, OtherOutputs, Type)
|
|
- Comment }
|
|
->
|
|
rl_sort__specialize_project(Instr0, Output, Input, Exprn,
|
|
OtherOutputs, Type, Comment, Instrs0, Instrs)
|
|
;
|
|
{ Instrs = [Instr0 | Instrs0] }
|
|
),
|
|
rl_sort__instr_avail(BlockId, Instr0).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Attempt to use an index/sort/hash join algorithm.
|
|
:- pred rl_sort__specialize_join(rl_instruction::in, output_rel::in,
|
|
relation_id::in, relation_id::in, join_type::in, rl_goal::in,
|
|
maybe(semi_join_info)::in, maybe(trivial_join_info)::in,
|
|
string::in, list(rl_instruction)::in,
|
|
list(rl_instruction)::out, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__specialize_join(Instr0, Output, Input1, Input2, JoinType,
|
|
Exprn, SemiJoin, TrivialJoin, Comment, Instrs0, Instrs,
|
|
SortInfo0, SortInfo) :-
|
|
SortInfo0 = sort_info(Sortedness0, SortVars, RLInfo0),
|
|
Sortedness0 = sortedness(RelSortMap, _),
|
|
|
|
rl_sort__introduce_indexed_join(RelSortMap, Output, Input1, Input2,
|
|
JoinType, Exprn, SemiJoin, TrivialJoin, Comment,
|
|
MaybeIndexJoinInstrs, RLInfo0, RLInfo1),
|
|
( MaybeIndexJoinInstrs = yes(IndexJoinInstrs) ->
|
|
RLInfo = RLInfo1,
|
|
JoinInstrs = IndexJoinInstrs
|
|
;
|
|
rl_sort__introduce_sort_join(RelSortMap,
|
|
Output, Input1, Input2, JoinType, Exprn, SemiJoin,
|
|
Comment, MaybeSortJoinInstrs, RLInfo1, RLInfo2),
|
|
( MaybeSortJoinInstrs = yes(SortJoinInstrs) ->
|
|
RLInfo = RLInfo2,
|
|
JoinInstrs = SortJoinInstrs
|
|
;
|
|
rl_sort__introduce_hash_join(Output,
|
|
Input1, Input2, JoinType, Exprn, SemiJoin,
|
|
Comment, MaybeHashJoinInstrs, RLInfo2, RLInfo),
|
|
( MaybeHashJoinInstrs = yes(HashJoinInstrs) ->
|
|
JoinInstrs = HashJoinInstrs
|
|
;
|
|
JoinInstrs = [Instr0]
|
|
)
|
|
)
|
|
),
|
|
list__reverse(JoinInstrs, RevJoinInstrs),
|
|
list__append(RevJoinInstrs, Instrs0, Instrs),
|
|
SortInfo = sort_info(Sortedness0, SortVars, RLInfo).
|
|
|
|
% Attempt to use an index/hash subtract algorithm.
|
|
:- pred rl_sort__specialize_subtract(rl_instruction::in, output_rel::in,
|
|
relation_id::in, relation_id::in, subtract_type::in, rl_goal::in,
|
|
maybe(trivial_subtract_info)::in, string::in,
|
|
list(rl_instruction)::in, list(rl_instruction)::out,
|
|
sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__specialize_subtract(Instr0, Output, Input1, Input2, SubtractType,
|
|
Exprn, TrivialSubtract, Comment, Instrs0, Instrs,
|
|
SortInfo0, SortInfo) :-
|
|
SortInfo0 = sort_info(Sortedness0, SortVars, RLInfo0),
|
|
Sortedness0 = sortedness(RelSortMap, _),
|
|
|
|
rl_sort__introduce_indexed_subtract(RelSortMap, Output, Input1, Input2,
|
|
SubtractType, Exprn, TrivialSubtract, Comment,
|
|
MaybeIndexSubtractInstrs, RLInfo0, RLInfo1),
|
|
( MaybeIndexSubtractInstrs = yes(IndexSubtractInstrs) ->
|
|
RLInfo = RLInfo1,
|
|
SubtractInstrs = IndexSubtractInstrs
|
|
;
|
|
RLInfo2 = RLInfo1,
|
|
/*
|
|
rl_sort__introduce_sort_subtract(RelSortMap,
|
|
Output, Input1, Input2, SubtractType, Exprn, Comment,
|
|
MaybeSortSubtractInstrs, RLInfo1, RLInfo2),
|
|
( MaybeSortSubtractInstrs = yes(SortSubtractInstrs) ->
|
|
RLInfo = RLInfo2,
|
|
SubtractInstrs = SortSubtractInstrs
|
|
;
|
|
*/
|
|
rl_sort__introduce_hash_subtract(Output,
|
|
Input1, Input2, SubtractType, Exprn, Comment,
|
|
MaybeHashSubtractInstrs, RLInfo2, RLInfo),
|
|
( MaybeHashSubtractInstrs = yes(HashSubtractInstrs) ->
|
|
SubtractInstrs = HashSubtractInstrs
|
|
;
|
|
SubtractInstrs = [Instr0]
|
|
)
|
|
%)
|
|
),
|
|
list__reverse(SubtractInstrs, RevSubtractInstrs),
|
|
list__append(RevSubtractInstrs, Instrs0, Instrs),
|
|
SortInfo = sort_info(Sortedness0, SortVars, RLInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__introduce_indexed_join(relation_sort_map::in, output_rel::in,
|
|
relation_id::in, relation_id::in, join_type::in,
|
|
rl_goal::in, maybe(semi_join_info)::in, maybe(trivial_join_info)::in,
|
|
string::in, maybe(list(rl_instruction))::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__introduce_indexed_join(RelSortMap, Output, Input1, Input2, _JoinType0,
|
|
Exprn0, _SemiJoin0, _TrivialJoin0, Comment,
|
|
MaybeIndexJoinInstrs, RLInfo0, RLInfo) :-
|
|
|
|
CanSwapInputs = yes,
|
|
rl_sort__is_indexed_join_or_subtract(RelSortMap, Input1, Input2,
|
|
CanSwapInputs, Exprn0, MaybeIndexInfo, RLInfo0, RLInfo1),
|
|
|
|
(
|
|
MaybeIndexInfo = no,
|
|
MaybeIndexJoinInstrs = no,
|
|
RLInfo = RLInfo1
|
|
;
|
|
MaybeIndexInfo = yes(
|
|
index_instr_info(Index, KeyRange, SwapInputs)),
|
|
JoinType = index(Index, KeyRange),
|
|
(
|
|
SwapInputs = yes,
|
|
rl__swap_goal_inputs(Exprn0, Exprn),
|
|
JoinInput1 = Input2,
|
|
JoinInput2 = Input1
|
|
;
|
|
SwapInputs = no,
|
|
Exprn = Exprn0,
|
|
JoinInput1 = Input1,
|
|
JoinInput2 = Input2
|
|
),
|
|
|
|
rl__is_semi_join(JoinType, Exprn, SemiJoin),
|
|
|
|
rl_opt_info_get_module_info(ModuleInfo, RLInfo1, RLInfo),
|
|
rl__is_trivial_join(ModuleInfo, JoinType, Exprn, SemiJoin,
|
|
TrivialJoin),
|
|
|
|
JoinInstr = join(Output, JoinInput1, JoinInput2,
|
|
JoinType, Exprn, SemiJoin, TrivialJoin) - Comment,
|
|
MaybeIndexJoinInstrs = yes([JoinInstr])
|
|
).
|
|
|
|
:- pred rl_sort__introduce_indexed_subtract(relation_sort_map::in,
|
|
output_rel::in, relation_id::in, relation_id::in, subtract_type::in,
|
|
rl_goal::in, maybe(trivial_subtract_info)::in, string::in,
|
|
maybe(list(rl_instruction))::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__introduce_indexed_subtract(RelSortMap, Output, Input1, Input2,
|
|
_SubtractType0, Exprn, _TrivialSubtract0, Comment,
|
|
MaybeIndexSubtractInstrs, RLInfo0, RLInfo) :-
|
|
|
|
CanSwapInputs = no,
|
|
rl_sort__is_indexed_join_or_subtract(RelSortMap, Input1, Input2,
|
|
CanSwapInputs, Exprn, MaybeIndexInfo, RLInfo0, RLInfo1),
|
|
|
|
(
|
|
MaybeIndexInfo = no,
|
|
MaybeIndexSubtractInstrs = no,
|
|
RLInfo = RLInfo1
|
|
;
|
|
MaybeIndexInfo = yes(index_instr_info(Index, KeyRange, _)),
|
|
SubtractType = semi_index(Index, KeyRange),
|
|
|
|
rl_opt_info_get_module_info(ModuleInfo, RLInfo1, RLInfo),
|
|
rl__is_trivial_subtract(ModuleInfo, SubtractType, Exprn,
|
|
TrivialSubtract),
|
|
|
|
SubtractInstr = subtract(Output, Input1, Input2,
|
|
SubtractType, Exprn, TrivialSubtract) - Comment,
|
|
MaybeIndexSubtractInstrs = yes([SubtractInstr])
|
|
).
|
|
|
|
:- type index_instr_info
|
|
---> index_instr_info(
|
|
index_spec,
|
|
key_range,
|
|
bool % Do the inputs need to be swapped
|
|
).
|
|
|
|
:- pred rl_sort__is_indexed_join_or_subtract(relation_sort_map::in,
|
|
relation_id::in, relation_id::in, bool::in,
|
|
rl_goal::in, maybe(index_instr_info)::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__is_indexed_join_or_subtract(RelSortMap, Input1, Input2,
|
|
CanSwapInputs, Exprn, MaybeIndexInfo, RLInfo0, RLInfo) :-
|
|
|
|
rl_opt_info_get_relation_info_map(RelMap, RLInfo0, RLInfo1),
|
|
rl_sort__get_relation_indexes(RelSortMap, RelMap,
|
|
Input1, Input1Indexes, IsBaseRelation1),
|
|
rl_sort__get_relation_indexes(RelSortMap, RelMap,
|
|
Input2, Input2Indexes, IsBaseRelation2),
|
|
|
|
( Input1Indexes = [], Input2Indexes = [] ->
|
|
MaybeIndexInfo = no,
|
|
RLInfo = RLInfo1
|
|
;
|
|
rl_opt_info_get_module_info(ModuleInfo, RLInfo1, RLInfo),
|
|
rl_sort__find_useful_join_indexes(ModuleInfo, Input1Indexes,
|
|
Exprn, one, IndexRanges1),
|
|
rl_sort__find_useful_join_indexes(ModuleInfo, Input2Indexes,
|
|
Exprn, two, IndexRanges2),
|
|
|
|
% XXX the choice of index here is slightly cheap and nasty
|
|
% when there are multiple possibilities.
|
|
(
|
|
IndexRanges1 = [],
|
|
IndexRanges2 = [],
|
|
Optimize = no,
|
|
SwapInputs = no
|
|
;
|
|
IndexRanges1 = [IndexRange1a | IndexRanges1a],
|
|
IndexRanges2 = [],
|
|
rl_sort__choose_join_index(IndexRanges1a,
|
|
IndexRange1a, IndexRange),
|
|
( CanSwapInputs = yes ->
|
|
Optimize = yes(IndexRange),
|
|
SwapInputs = yes
|
|
;
|
|
Optimize = no,
|
|
SwapInputs = no
|
|
)
|
|
;
|
|
IndexRanges1 = [],
|
|
IndexRanges2 = [IndexRange2a | IndexRanges2a],
|
|
rl_sort__choose_join_index(IndexRanges2a,
|
|
IndexRange2a, IndexRange),
|
|
Optimize = yes(IndexRange),
|
|
SwapInputs = no
|
|
;
|
|
IndexRanges1 = [IndexRange1a | IndexRanges1a],
|
|
IndexRanges2 = [IndexRange2a | IndexRanges2a],
|
|
rl_sort__choose_join_index(IndexRanges1a,
|
|
IndexRange1a, BestIndexRange1),
|
|
rl_sort__choose_join_index(IndexRanges2a,
|
|
IndexRange2a, BestIndexRange2),
|
|
|
|
% Prefer an index on a base relation, since they
|
|
% are more likely to be large.
|
|
% (XXX this isn't necessarily correct).
|
|
(
|
|
IsBaseRelation1 = yes,
|
|
IsBaseRelation2 = no,
|
|
CanSwapInputs = yes
|
|
->
|
|
SwapInputs = yes,
|
|
Optimize = yes(BestIndexRange1)
|
|
;
|
|
IsBaseRelation1 = no,
|
|
IsBaseRelation2 = yes
|
|
->
|
|
SwapInputs = no,
|
|
Optimize = yes(BestIndexRange2)
|
|
;
|
|
% In this case, we should generate conditional
|
|
% code to index the largest relation.
|
|
SwapInputs = no,
|
|
Optimize = yes(BestIndexRange2)
|
|
)
|
|
),
|
|
% XXX handle multiple key ranges.
|
|
( Optimize = yes(Index - [KeyRange]) ->
|
|
MaybeIndexInfo = yes(
|
|
index_instr_info(Index, KeyRange, SwapInputs))
|
|
;
|
|
MaybeIndexInfo = no
|
|
)
|
|
).
|
|
|
|
:- pred rl_sort__find_useful_join_indexes(module_info::in,
|
|
list(index_spec)::in, rl_goal::in, tuple_num::in,
|
|
index_ranges::out) is det.
|
|
|
|
rl_sort__find_useful_join_indexes(ModuleInfo, Indexes,
|
|
Goal, TupleNum, IndexRanges) :-
|
|
Goal = rl_goal(_, _, VarTypes, _, Inputs, _, _, VarBounds),
|
|
( VarBounds = [] ->
|
|
IndexRanges = []
|
|
;
|
|
list__filter_map(
|
|
(pred(Index::in, ThisIndexRanges::out) is semidet :-
|
|
Inputs = two_inputs(Args1, Args2),
|
|
(
|
|
TupleNum = one,
|
|
rl_key__get_join_key_ranges(ModuleInfo,
|
|
VarTypes, Args2, Args1, Index,
|
|
VarBounds, Ranges)
|
|
;
|
|
TupleNum = two,
|
|
rl_key__get_join_key_ranges(ModuleInfo,
|
|
VarTypes, Args1, Args2, Index,
|
|
VarBounds, Ranges)
|
|
),
|
|
ThisIndexRanges = Index - Ranges
|
|
), Indexes, IndexRanges)
|
|
).
|
|
|
|
:- type index_ranges == list(index_range).
|
|
:- type index_range == pair(index_spec, list(key_range)).
|
|
|
|
% XXX make a more intelligent choice here.
|
|
:- pred rl_sort__choose_join_index(index_ranges::in,
|
|
index_range::in, index_range::out) is det.
|
|
|
|
rl_sort__choose_join_index(_IndexRanges, IndexRange, IndexRange).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__introduce_sort_join(relation_sort_map::in, output_rel::in,
|
|
relation_id::in, relation_id::in, join_type::in,
|
|
rl_goal::in, maybe(semi_join_info)::in, string::in,
|
|
maybe(list(rl_instruction))::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__introduce_sort_join(SortMap, Output, Input1, Input2, _JoinType0,
|
|
Exprn, SemiJoin, Comment, MaybeSortJoinInstrs,
|
|
RLInfo, RLInfo) :-
|
|
Exprn = rl_goal(_, _, _, _, Inputs, _, _, VarBounds),
|
|
(
|
|
% XXX Sort-merge semi-joins are not yet implemented in Aditi.
|
|
SemiJoin = no,
|
|
|
|
rl_key__is_equijoin(Inputs, VarBounds, Attrs1, Attrs2),
|
|
|
|
map__search(SortMap, Input1, SortSpecs1),
|
|
find_equijoin_sort_spec(Attrs1, SortSpecs1, SortSpec1),
|
|
|
|
map__search(SortMap, Input2, SortSpecs2),
|
|
find_equijoin_sort_spec(Attrs2, SortSpecs2, SortSpec2)
|
|
->
|
|
JoinType = sort_merge(SortSpec1, SortSpec2),
|
|
% The join condition of an equi-join always depends
|
|
% on both input tuples.
|
|
TrivialJoin = no,
|
|
JoinInstr = join(Output, Input1, Input2,
|
|
JoinType, Exprn, SemiJoin, TrivialJoin) - Comment,
|
|
MaybeSortJoinInstrs = yes([JoinInstr])
|
|
;
|
|
MaybeSortJoinInstrs = no
|
|
).
|
|
|
|
%
|
|
% Look for sort_specs which match all equijoin attributes.
|
|
% We could look for partial matches, but that could
|
|
% cause inefficient code to be generated if the attributes
|
|
% sorted on are not selective enough - we could end
|
|
% up doing nested loop joins on large numbers of tuples.
|
|
%
|
|
:- pred find_equijoin_sort_spec(list(int)::in, map(sort_index, sort_req)::in,
|
|
sort_spec::out) is semidet.
|
|
|
|
find_equijoin_sort_spec(Attrs, SortSpecs0, SortSpec) :-
|
|
|
|
find_definite_sort_specs(SortSpecs0, SortSpecs),
|
|
list__filter_map(matching_sort_spec(Attrs),
|
|
SortSpecs, MatchingSortSpecs),
|
|
MatchingSortSpecs = [SortSpec | _].
|
|
|
|
%
|
|
% Succeed if the sort_spec sorts on all the given
|
|
% attributes in the correct order.
|
|
%
|
|
:- pred matching_sort_spec(list(int)::in,
|
|
sort_spec::in, sort_spec::out) is semidet.
|
|
|
|
matching_sort_spec(AttrNums, Spec0, Spec) :-
|
|
Spec0 = attributes(SortAttrs0),
|
|
assoc_list__keys(SortAttrs0, SortAttrNums0),
|
|
assoc_list__values(SortAttrs0, SortDirs0),
|
|
list__length(AttrNums, NumRequiredAttrs),
|
|
|
|
% The sort_spec can sort on more attributes -
|
|
% take the prefix that is needed.
|
|
list__take(NumRequiredAttrs, SortAttrNums0, AttrNums),
|
|
list__take(NumRequiredAttrs, SortDirs0, SortDirs),
|
|
assoc_list__from_corresponding_lists(AttrNums, SortDirs, SortAttrs),
|
|
Spec = attributes(SortAttrs).
|
|
|
|
:- pred find_definite_sort_specs(map(sort_index, sort_req)::in,
|
|
list(sort_spec)::out) is det.
|
|
|
|
find_definite_sort_specs(SortMap, SortSpecs) :-
|
|
map__foldl((pred(SortIndex::in, SortReq::in, Specs0::in, Specs::out)
|
|
is det :-
|
|
(
|
|
SortReq = sort_req(definite, _),
|
|
%(
|
|
SortIndex = sort(SortSpec),
|
|
SortSpec = attributes(SortAttrs),
|
|
\+ (
|
|
% We could probably handle
|
|
% relations sorted in descending
|
|
% order, but it might be a bit
|
|
% trickier. We don't generate
|
|
% sort instructions to produce
|
|
% reverse sorted relations, so
|
|
% it doesn't matter.
|
|
list__member(SortAttr, SortAttrs),
|
|
SortAttr = _ - descending
|
|
)
|
|
/*
|
|
% If a relation is definitely indexed, we
|
|
% should be doing an indexed join.
|
|
;
|
|
% B-tree indexed relations are sorted
|
|
% on the indexed attributes.
|
|
SortIndex = index(IndexSpec),
|
|
IndexSpec = index_spec(IndexType, Attrs),
|
|
( IndexType = unique_B_tree
|
|
; IndexType = non_unique_B_tree
|
|
),
|
|
list__length(Attrs, NumAttrs),
|
|
list__duplicate(NumAttrs, ascending, SortDirs),
|
|
assoc_list__from_corresponding_lists(Attrs,
|
|
SortDirs, SortAttrs),
|
|
SortSpec = attributes(SortAttrs)
|
|
)
|
|
*/
|
|
->
|
|
Specs = [SortSpec | Specs0]
|
|
;
|
|
Specs = Specs0
|
|
)
|
|
), SortMap, [], SortSpecs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_sort__introduce_hash_join(output_rel::in,
|
|
relation_id::in, relation_id::in, join_type::in,
|
|
rl_goal::in, maybe(semi_join_info)::in,
|
|
string::in, maybe(list(rl_instruction))::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__introduce_hash_join(Output, Input1, Input2, _JoinType0, Exprn,
|
|
SemiJoin, Comment, MaybeHashJoinInstrs,
|
|
RLInfo, RLInfo) :-
|
|
Inputs = Exprn ^ inputs,
|
|
VarBounds = Exprn ^ bounds,
|
|
(
|
|
rl_key__is_equijoin(Inputs, VarBounds, Attrs1, Attrs2)
|
|
->
|
|
JoinType = hash(Attrs1, Attrs2),
|
|
% The join condition of an equi-join always depends
|
|
% on both input tuples.
|
|
TrivialJoin = no,
|
|
JoinInstr = join(Output, Input1, Input2,
|
|
JoinType, Exprn, SemiJoin, TrivialJoin) - Comment,
|
|
MaybeHashJoinInstrs = yes([JoinInstr])
|
|
;
|
|
MaybeHashJoinInstrs = no
|
|
).
|
|
|
|
:- pred rl_sort__introduce_hash_subtract(output_rel::in,
|
|
relation_id::in, relation_id::in, subtract_type::in,
|
|
rl_goal::in, string::in, maybe(list(rl_instruction))::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__introduce_hash_subtract(Output, Input1, Input2, _SubtractType0, Exprn,
|
|
Comment, MaybeHashSubtractInstrs, RLInfo, RLInfo) :-
|
|
Inputs = Exprn ^ inputs,
|
|
VarBounds = Exprn ^ bounds,
|
|
(
|
|
rl_key__is_equijoin(Inputs, VarBounds, Attrs1, Attrs2)
|
|
->
|
|
SubtractType = semi_hash(Attrs1, Attrs2),
|
|
% The subtract condition of an equi-subtract always depends
|
|
% on both input tuples.
|
|
TrivialSubtract = no,
|
|
SubtractInstr = subtract(Output, Input1, Input2,
|
|
SubtractType, Exprn, TrivialSubtract) - Comment,
|
|
MaybeHashSubtractInstrs = yes([SubtractInstr])
|
|
;
|
|
MaybeHashSubtractInstrs = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Work out which index could be used for a project.
|
|
:- pred rl_sort__specialize_project(rl_instruction::in, output_rel::in,
|
|
relation_id::in, rl_goal::in, assoc_list(output_rel, rl_goal)::in,
|
|
project_type::in, string::in, list(rl_instruction)::in,
|
|
list(rl_instruction)::out, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__specialize_project(Instr0, OutputRel, Input, Exprn, ProjOutputs0,
|
|
_Type, Comment, Instrs0, Instrs, SortInfo0, SortInfo) :-
|
|
SortInfo0 = sort_info(Sortedness0, SortVars, RLInfo0),
|
|
Sortedness0 = sortedness(RelSortMap, _),
|
|
rl_opt_info_get_relation_info_map(RelMap, RLInfo0, RLInfo1),
|
|
rl_sort__get_relation_indexes(RelSortMap, RelMap,
|
|
Input, Indexes, _),
|
|
( Indexes = [] ->
|
|
Instrs = [Instr0 | Instrs0],
|
|
RLInfo = RLInfo1
|
|
;
|
|
ProjOutputs = [OutputRel - Exprn | ProjOutputs0],
|
|
rl_opt_info_get_module_info(ModuleInfo, RLInfo1, RLInfo2),
|
|
list__map(rl_sort__find_useful_project_indexes(ModuleInfo,
|
|
Indexes), ProjOutputs, ProjOutputIndexes),
|
|
|
|
% Partition out those expressions for which there
|
|
% are no suitable indexes.
|
|
list__filter((pred(ProjOutput::in) is semidet :-
|
|
ProjOutput = proj_output(_, _, [])
|
|
), ProjOutputIndexes, NoIndexOutputs0, IndexOutputs),
|
|
( IndexOutputs = [] ->
|
|
Instrs = [Instr0 | Instrs0],
|
|
RLInfo = RLInfo2
|
|
;
|
|
rl_sort__partition_project_outputs(IndexOutputs,
|
|
Partitions0),
|
|
( NoIndexOutputs0 = [] ->
|
|
Partitions = Partitions0
|
|
;
|
|
list__map(
|
|
(pred(POutput::in, PRel::out) is det :-
|
|
POutput = proj_output(ORel,
|
|
Goal, _),
|
|
PRel = ORel - Goal
|
|
), NoIndexOutputs0, NoIndexOutputs),
|
|
Partition = NoIndexOutputs - no,
|
|
Partitions = [Partition | Partitions0]
|
|
),
|
|
list__map(rl_sort__generate_project(Input, Comment),
|
|
Partitions, Projections),
|
|
list__append(Projections, Instrs0, Instrs),
|
|
RLInfo = RLInfo2
|
|
)
|
|
),
|
|
SortInfo = sort_info(Sortedness0, SortVars, RLInfo).
|
|
|
|
:- type proj_output
|
|
---> proj_output(
|
|
output_rel,
|
|
rl_goal,
|
|
assoc_list(index_spec, list(key_range))
|
|
).
|
|
|
|
:- type assigned_project_output ==
|
|
pair(assoc_list(output_rel, rl_goal),
|
|
maybe(pair(index_spec, list(key_range)))).
|
|
|
|
:- pred rl_sort__find_useful_project_indexes(module_info::in,
|
|
list(index_spec)::in, pair(output_rel, rl_goal)::in,
|
|
proj_output::out) is det.
|
|
|
|
rl_sort__find_useful_project_indexes(ModuleInfo, Indexes, OutputRel - Goal,
|
|
proj_output(OutputRel, Goal, IndexRanges)) :-
|
|
Goal = rl_goal(_, _, VarTypes, _, Inputs, _, _, VarBounds),
|
|
( VarBounds = [] ->
|
|
IndexRanges = []
|
|
;
|
|
list__filter_map(
|
|
(pred(Index::in, ThisIndexRanges::out) is semidet :-
|
|
Inputs = one_input(Args),
|
|
rl_key__get_select_key_ranges(ModuleInfo,
|
|
VarTypes, Args, Index, VarBounds,
|
|
Ranges),
|
|
ThisIndexRanges = Index - Ranges
|
|
), Indexes, IndexRanges)
|
|
).
|
|
|
|
% Find the set of indexes which results in the smallest
|
|
% number of passes over the input.
|
|
% XXX currently this is _very_ non-optimal.
|
|
:- pred rl_sort__partition_project_outputs(list(proj_output)::in,
|
|
list(assigned_project_output)::out) is det.
|
|
|
|
rl_sort__partition_project_outputs([], []).
|
|
rl_sort__partition_project_outputs([Output | Outputs],
|
|
[Partition | Partitions]) :-
|
|
( Output = proj_output(OutputRel0, Goal, [IndexRange | _]) ->
|
|
OutputRel = OutputRel0,
|
|
IndexRange = Index - KeyRanges,
|
|
Partition = [OutputRel - Goal] - yes(Index - KeyRanges)
|
|
;
|
|
error("rl_sort__partition_project_outputs")
|
|
),
|
|
rl_sort__partition_project_outputs(Outputs, Partitions).
|
|
|
|
:- pred rl_sort__generate_project(relation_id::in, string::in,
|
|
assigned_project_output::in, rl_instruction::out) is det.
|
|
|
|
rl_sort__generate_project(Input, Comment, Outputs - MaybeIndex, Instr) :-
|
|
( Outputs = [FirstOutput - FirstExprn | OtherOutputs] ->
|
|
% XXX handle multiple key ranges - at the moment you have
|
|
% to do each key range as a separate operation and then
|
|
% union together the results. It would be much better
|
|
% if all the key ranges could be applied as part of the
|
|
% same operation -- for joins overlapping key ranges could
|
|
% then be merged at runtime.
|
|
(
|
|
MaybeIndex = yes(Index - KeyRanges),
|
|
KeyRanges = [KeyRange]
|
|
->
|
|
Type = index(Index, KeyRange)
|
|
;
|
|
Type = filter
|
|
),
|
|
Instr = project(FirstOutput, Input, FirstExprn,
|
|
OtherOutputs, Type) - Comment
|
|
;
|
|
error("rl_sort__generate_project")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Work out which indexes a relation definitely has at this
|
|
% point in the code, also returning whether the relation is
|
|
% a base relation.
|
|
:- pred rl_sort__get_relation_indexes(relation_sort_map::in,
|
|
relation_info_map::in, relation_id::in, list(index_spec)::out,
|
|
bool::out) is det.
|
|
|
|
rl_sort__get_relation_indexes(RelSortMap, RelMap,
|
|
Rel, Indexes, IsBaseRelation) :-
|
|
map__lookup(RelMap, Rel, RelInfo),
|
|
( RelInfo = relation_info(permanent(_), _, Indexes0, _) ->
|
|
Indexes = Indexes0,
|
|
IsBaseRelation = yes
|
|
;
|
|
( map__search(RelSortMap, Rel, Specs0) ->
|
|
map__to_assoc_list(Specs0, SpecsAL),
|
|
list__filter_map(
|
|
(pred(SpecPair::in, Index::out) is semidet :-
|
|
SpecPair = index(Index)
|
|
- sort_req(definite, _)
|
|
), SpecsAL, Indexes)
|
|
;
|
|
Indexes = []
|
|
),
|
|
IsBaseRelation = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Remove unnecessary indexing and sorting operations.
|
|
:- pred rl_sort__add_indexing_and_remove_useless_ops(sort_data_map::in,
|
|
block_id::in, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_sort__add_indexing_and_remove_useless_ops(NeededSortMap,
|
|
BlockId, Info0, Info) :-
|
|
rl_opt_info_get_block(BlockId, Block0, Info0, Info1),
|
|
Block0 = block(Label, Instrs0, EndInstr, BlockInfo),
|
|
|
|
list__reverse(Instrs0, RevInstrs0),
|
|
map__lookup(NeededSortMap, BlockId, block_data(NeededSorts, _, _)),
|
|
map__init(VarRequests),
|
|
SortInfo0 = sort_info(NeededSorts, VarRequests, Info1),
|
|
|
|
list__foldl2(
|
|
rl_sort__add_indexing_and_remove_useless_ops_instr(BlockId),
|
|
RevInstrs0, [], Instrs, SortInfo0, sort_info(_, _, Info2)),
|
|
Block = block(Label, Instrs, EndInstr, BlockInfo),
|
|
rl_opt_info_set_block(BlockId, Block, Info2, Info).
|
|
|
|
:- pred rl_sort__add_indexing_and_remove_useless_ops_instr(block_id::in,
|
|
rl_instruction::in, list(rl_instruction)::in,
|
|
list(rl_instruction)::out, sort_info::in, sort_info::out) is det.
|
|
|
|
rl_sort__add_indexing_and_remove_useless_ops_instr(BlockId,
|
|
Instr, Instrs0, Instrs) -->
|
|
=(sort_info(sortedness(RelSortMap, _), _, _)),
|
|
(
|
|
{ Instr = add_index(OutputRel0, Input) - Comm }
|
|
->
|
|
{ rl_sort__map_output_rel(RelSortMap, rl_sort__map_spec,
|
|
OutputRel0, OutputRel) },
|
|
{ OutputRel = output_rel(Relation, NeededIndexes) },
|
|
{ NeededIndexes = [] ->
|
|
Instrs = [ref(Relation, Input) - Comm | Instrs0]
|
|
;
|
|
Instrs = [add_index(output_rel(Relation,
|
|
NeededIndexes), Input) - Comm | Instrs0]
|
|
}
|
|
;
|
|
{ Instr = sort(Output0, Input, SortSpec) - Comm }
|
|
->
|
|
{ rl_sort__map_output_rel(RelSortMap, rl_sort__map_spec,
|
|
Output0, Output) },
|
|
{ Output = output_rel(OutputRel, _) },
|
|
{ map__search(RelSortMap, OutputRel, NeededSpecs) ->
|
|
(
|
|
map__contains(NeededSpecs,
|
|
sort(attributes(SortSpec)))
|
|
->
|
|
SpecNeeded = yes
|
|
;
|
|
SpecNeeded = no
|
|
)
|
|
;
|
|
SpecNeeded = no
|
|
},
|
|
(
|
|
{ SpecNeeded = no },
|
|
list__foldl2(
|
|
rl_sort__add_indexing_and_remove_useless_ops_instr(
|
|
BlockId),
|
|
[add_index(Output, Input) - Comm],
|
|
Instrs0, Instrs)
|
|
;
|
|
{ SpecNeeded = yes },
|
|
{ rl_sort__map_spec(SortSpec, SortSpec1) },
|
|
{ Instrs = [sort(Output, Input, SortSpec1) - Comm |
|
|
Instrs0] }
|
|
)
|
|
;
|
|
{ Instr = join(Output0, Input1, Input2, Type,
|
|
Exprn, SemiJoin, TrivialJoin) - Comm },
|
|
{ TrivialJoin = yes(trivial_join_or_subtract_info(_, no)) }
|
|
->
|
|
{ rl_sort__trivial_join_or_subtract_output_indexes(RelSortMap,
|
|
Output0, Output) },
|
|
{ Instr1 = join(Output, Input1, Input2, Type,
|
|
Exprn, SemiJoin, TrivialJoin) - Comm },
|
|
{ Instrs = [Instr1 | Instrs0] }
|
|
;
|
|
{ Instr = subtract(Output0, Input1, Input2, Type,
|
|
Exprn, TrivialSubtract) - Comm },
|
|
{ TrivialSubtract = yes(_) }
|
|
->
|
|
{ rl_sort__trivial_join_or_subtract_output_indexes(RelSortMap,
|
|
Output0, Output) },
|
|
{ Instr1 = subtract(Output, Input1, Input2, Type,
|
|
Exprn, TrivialSubtract) - Comm },
|
|
{ Instrs = [Instr1 | Instrs0] }
|
|
;
|
|
{ rl_sort__map_sort_and_index_specs(
|
|
rl_sort__map_output_rel(RelSortMap, rl_sort__map_spec),
|
|
rl_sort__map_spec, rl_sort__map_spec,
|
|
Instr, Instr1) },
|
|
{ Instrs = [Instr1 | Instrs0] }
|
|
),
|
|
rl_sort__instr_needed(BlockId, Instr).
|
|
|
|
% In the cases where a trivial join or subtract creates its output
|
|
% relation instead of just passing out one of the inputs,
|
|
% make sure the created relation has the correct indexes.
|
|
:- pred rl_sort__trivial_join_or_subtract_output_indexes(relation_sort_map::in,
|
|
output_rel::in, output_rel::out) is det.
|
|
|
|
rl_sort__trivial_join_or_subtract_output_indexes(RelSortMap, Output0, Output) :-
|
|
rl_sort__map_output_rel(RelSortMap, rl_sort__map_spec,
|
|
Output0, Output1),
|
|
Output1 = output_rel(OutputRel, Indexes0),
|
|
( map__search(RelSortMap, OutputRel, NeededSorts0) ->
|
|
map__to_assoc_list(NeededSorts0, NeededSortsAL0),
|
|
list__filter_map(
|
|
(pred(SortIndex::in, Index::out) is semidet :-
|
|
SortIndex = index(Index) - _
|
|
), NeededSortsAL0, NeededIndexes),
|
|
list__delete_elems(NeededIndexes, Indexes0, Indexes1),
|
|
list__append(Indexes0, Indexes1, Indexes),
|
|
Output = output_rel(OutputRel, Indexes)
|
|
;
|
|
Output = Output1
|
|
).
|
|
|
|
% Eventually this will need to instantiate sort variables.
|
|
:- pred rl_sort__map_spec(T::in, T::out) is det.
|
|
|
|
rl_sort__map_spec(Spec, Spec).
|
|
|
|
:- pred rl_sort__map_output_rel(relation_sort_map::in,
|
|
pred(index_spec, index_spec)::(pred(in, out) is det),
|
|
output_rel::in, output_rel::out) is det.
|
|
|
|
rl_sort__map_output_rel(RelSortMap, MapIndex, output_rel(Output, Indexes0),
|
|
output_rel(Output, Indexes)) :-
|
|
( map__search(RelSortMap, Output, NeededSpecs) ->
|
|
list__filter(rl_sort__index_is_needed(NeededSpecs),
|
|
Indexes0, Indexes1),
|
|
list__map(MapIndex, Indexes1, Indexes)
|
|
;
|
|
Indexes = []
|
|
).
|
|
|
|
:- pred rl_sort__index_is_needed(map(sort_index, _T)::in,
|
|
index_spec::in) is semidet.
|
|
|
|
rl_sort__index_is_needed(NeededMap, Index) :-
|
|
map__contains(NeededMap, index(Index)).
|
|
|
|
|
|
% Update sort and index instruction specifiers for an instruction,
|
|
% binding sort variables and removing unneeded index specifiers.
|
|
:- pred rl_sort__map_sort_and_index_specs(
|
|
pred(output_rel, output_rel)::(pred(in, out) is det),
|
|
pred(index_spec, index_spec)::(pred(in, out) is det),
|
|
pred(sort_spec, sort_spec)::(pred(in, out) is det),
|
|
rl_instruction::in, rl_instruction::out) is det.
|
|
|
|
rl_sort__map_sort_and_index_specs(OutputPred, IndexPred, SortPred,
|
|
join(Output0, B, C, Type0, E, F, G) - H,
|
|
join(Output, B, C, Type, E, F, G) - H) :-
|
|
call(OutputPred, Output0, Output),
|
|
( Type0 = sort_merge(Sort1a, Sort2a) ->
|
|
call(SortPred, Sort1a, Sort1),
|
|
call(SortPred, Sort2a, Sort2),
|
|
Type = sort_merge(Sort1, Sort2)
|
|
; Type0 = index(Index0, Range) ->
|
|
call(IndexPred, Index0, Index),
|
|
Type = index(Index, Range)
|
|
;
|
|
Type = Type0
|
|
).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, IndexPred, SortPred,
|
|
subtract(Output0, B, C, Type0, E, F) - G,
|
|
subtract(Output, B, C, Type, E, F) - G) :-
|
|
call(OutputPred, Output0, Output),
|
|
( Type0 = semi_sort_merge(Sort1a, Sort2a) ->
|
|
call(SortPred, Sort1a, Sort1),
|
|
call(SortPred, Sort2a, Sort2),
|
|
Type = semi_sort_merge(Sort1, Sort2)
|
|
; Type0 = semi_index(Index0, Range) ->
|
|
call(IndexPred, Index0, Index),
|
|
Type = semi_index(Index, Range)
|
|
;
|
|
Type = Type0
|
|
).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, SortPred,
|
|
difference(Output0, B, C, Type0) - E,
|
|
difference(Output, B, C, Type) - E) :-
|
|
call(OutputPred, Output0, Output),
|
|
Type0 = sort_merge(SortSpec0),
|
|
call(SortPred, SortSpec0, SortSpec),
|
|
Type = sort_merge(SortSpec).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, IndexPred, _,
|
|
project(Output0,
|
|
B, C, ProjectOutputs0, Type0) - F,
|
|
project(Output,
|
|
B, C, ProjectOutputs, Type) - F) :-
|
|
call(OutputPred, Output0, Output),
|
|
list__map((pred(ProjOutput0::in, ProjOutput::out) is det :-
|
|
ProjOutput0 = OutputRel0 - Expr,
|
|
call(OutputPred, OutputRel0, OutputRel),
|
|
ProjOutput = OutputRel - Expr
|
|
), ProjectOutputs0, ProjectOutputs),
|
|
(
|
|
Type0 = index(Index0, Range),
|
|
call(IndexPred, Index0, Index),
|
|
Type = index(Index, Range)
|
|
;
|
|
Type0 = filter,
|
|
Type = filter
|
|
).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _IndexPred, SortPred,
|
|
union(Output0, Inputs, Type0) - Comm,
|
|
union(Output, Inputs, Type) - Comm) :-
|
|
call(OutputPred, Output0, Output),
|
|
Type0 = sort_merge(SortSpec0),
|
|
call(SortPred, SortSpec0, SortSpec),
|
|
Type = sort_merge(SortSpec).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, IndexPred, _,
|
|
insert(A, B, C, Type0, MaybeCopy0) - F,
|
|
insert(A, B, C, Type, MaybeCopy) - F) :-
|
|
(
|
|
Type0 = append,
|
|
Type = append
|
|
;
|
|
Type0 = index(Index0),
|
|
call(IndexPred, Index0, Index),
|
|
Type = index(Index)
|
|
),
|
|
(
|
|
MaybeCopy0 = yes(Copy0),
|
|
call(OutputPred, Copy0, Copy),
|
|
MaybeCopy = yes(Copy)
|
|
;
|
|
MaybeCopy0 = no,
|
|
MaybeCopy = no
|
|
).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, IndexPred, _,
|
|
union_diff(A, B, C, Diff0, Index0, MaybeCopy0) - G,
|
|
union_diff(A, B, C, Diff, Index, MaybeCopy) - G) :-
|
|
call(IndexPred, Index0, Index),
|
|
call(OutputPred, Diff0, Diff),
|
|
(
|
|
MaybeCopy0 = yes(Copy0),
|
|
call(OutputPred, Copy0, Copy),
|
|
MaybeCopy = yes(Copy)
|
|
;
|
|
MaybeCopy0 = no,
|
|
MaybeCopy = no
|
|
).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, SortPred,
|
|
sort(Output0, B, Attrs0) - D,
|
|
sort(Output, B, Attrs) - D) :-
|
|
call(OutputPred, Output0, Output),
|
|
call(SortPred, attributes(Attrs0), Spec),
|
|
( Spec = attributes(Attrs1) ->
|
|
Attrs = Attrs1
|
|
;
|
|
error("rl_sort__map_sort_and_index_specs: weird result")
|
|
).
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = ref(_, _) - _.
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
copy(Output0, Input) - Comm,
|
|
copy(Output, Input) - Comm) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
make_unique(Output0, Input) - Comm,
|
|
make_unique(Output, Input) - Comm) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
init(Output0) - Comm,
|
|
init(Output) - Comm) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
insert_tuple(Output0, B, C) - D,
|
|
insert_tuple(Output, B, C) - D) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
call(A, B, Outputs0, D) - E,
|
|
call(A, B, Outputs, D) - E) :-
|
|
list__map(OutputPred, Outputs0, Outputs).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
aggregate(Output0, B, C, D) - E,
|
|
aggregate(Output, B, C, D) - E) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(OutputPred, _, _,
|
|
add_index(Output0, Input) - Comm,
|
|
add_index(Output, Input) - Comm) :-
|
|
call(OutputPred, Output0, Output).
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = clear(_) - _.
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = unset(_) - _.
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = label(_) - _.
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = conditional_goto(_, _) - _.
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = goto(_) - _.
|
|
rl_sort__map_sort_and_index_specs(_, _, _, Instr, Instr) :-
|
|
Instr = comment - _.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% % Beyond this point is junk at the moment.
|
|
%
|
|
% % Do an assignment of sort specifiers to each sort variable.
|
|
% :- pred rl_sort__assign_sort_vars(sort_data_map::in, var_requests::in,
|
|
% sort_data_map::in, var_requests::in, map(int, sort_index)::out,
|
|
% rl_opt_info::in, rl_opt_info::out) is det.
|
|
%
|
|
% rl_sort__assign_sort_vars(_AvailData0, AvailRequests0, _NeededData0,
|
|
% NeededRequests, VarBindings) -->
|
|
% {
|
|
% map__keys(AvailRequests, VarsList0),
|
|
% map__keys(NeededRequests, VarsList1),
|
|
% set__sorted_list_to_set(VarsList0, Vars0),
|
|
% set__sorted_list_to_set(VarsList1, Vars1),
|
|
% set__union(Vars0, Vars1, Vars),
|
|
%
|
|
% map__init(VarBindings0),
|
|
%
|
|
% % Find out which sort vars can be allocated based on
|
|
% % available sortedness.
|
|
% rl_sort__single_request_vars(AvailRequests0,
|
|
% VarBindings0, VarBindings1),
|
|
% rl_sort__bind_vars(AvailRequests0, VarBindings1, AvailRequests),
|
|
%
|
|
% map__keys(VarBindings1, BoundVars1),
|
|
% set__delete_list(Vars, BoundVars1, UnboundVars1)
|
|
% },
|
|
% { set__empty(UnboundVars1) ->
|
|
% VarBindings = VarBindings0
|
|
% ;
|
|
% % Find out which sort vars can be allocated based on
|
|
% % needed sortedness intersecting with available sortedness.
|
|
% rl_sort__intersect_requests(AvailRequests, NeededRequests,
|
|
% IntersectedRequests),
|
|
%
|
|
% rl_sort__single_request_vars(IntersectedRequests,
|
|
% VarBindings1, VarBindings)
|
|
%
|
|
% % If there's anything left unbound, just pick one of the
|
|
% % available sortednesses. XXX try all with cost measurement
|
|
% % to pick the best.
|
|
% }.
|
|
%
|
|
% % Find all sort variables which have only one requested sortedness.
|
|
% :- pred rl_sort__single_request_vars(var_requests::in,
|
|
% map(int, sort_index)::in,
|
|
% map(int, sort_index)::out) is det.
|
|
%
|
|
% rl_sort__single_request_vars(Requests0, SingleVars0, SingleVars) :-
|
|
% IsSingleBindingVar =
|
|
% (pred(Var::in, Reqs0::in, Single0::in, Single::out) is det :-
|
|
% set__to_sorted_list(Reqs0, Reqs1),
|
|
% (
|
|
% \+ map__contains(Single0, Var),
|
|
% list__filter((pred(Req::in) is semidet :-
|
|
% \+ Req = sort_var(Var) - _
|
|
% ), Reqs1, [Request]),
|
|
% Request = attributes(_) - _
|
|
% ->
|
|
% map__det_insert(Single0, Var, Request, Single)
|
|
% ;
|
|
% Single = Single0
|
|
% )
|
|
% ),
|
|
% map__foldl(IsSingleBindingVar, Requests0, SingleVars0, SingleVars).
|
|
%
|
|
% :- pred rl_sort__intersect_requests(var_requests::in,
|
|
% var_requests::in, var_requests::out) is det.
|
|
%
|
|
% rl_sort__intersect_requests(Requests1, Requests2, Intersection) :-
|
|
% IntersectBindings =
|
|
% (pred(Key::in, Value0::in, Inter0::in, Inter::out) is det :-
|
|
% ( map__search(Inter0, Key, Value1) ->
|
|
% set__intersect(Value0, Value1, Value),
|
|
% map__det_update(Inter0, Key, Value, Inter)
|
|
% ;
|
|
% Inter = Inter0
|
|
% )
|
|
% ),
|
|
% map__foldl(IntersectBindings, Requests1, Requests2, Intersection).
|
|
|
|
%-----------------------------------------------------------------------------%
|