%-----------------------------------------------------------------------------% % Copyright (C) 1998-2001 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 rl_sort. :- interface. :- import_module 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 hlds_module, prog_data, rl, rl_analyse, rl_key. :- 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( lambda([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 = lambda([_::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( lambda([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( lambda([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( lambda([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( lambda([VarDir::in] is semidet, ( VarDir = Var - _, list__member(Var, OutputArgs) )), VarAttrs0, VarAttrs, _), VarAttrs \= [], % Map those output arguments back into argument numbers. list__map( lambda([VarDir::in, AttrDirs::out] is det, ( VarDir = Var - Dir, rl_sort__all_positions(OutputArgs, 1, Var, Attrs), list__map(lambda([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 is 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( lambda([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(lambda([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( lambda([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( lambda([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( lambda([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(lambda([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 = lambda([Var::in, Reqs0::in, Single0::in, Single::out] is det, ( set__to_sorted_list(Reqs0, Reqs1), ( \+ map__contains(Single0, Var), list__filter(lambda([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 = lambda([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). */ %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%