mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 13:55:07 +00:00
Estimated hours taken: 2 Branches: main compiler/*.m: Import only one compiler module per line. Sort the blocks of imports. This makes it easier to merge in changes. In a couple of places, remove unnecessary imports.
540 lines
19 KiB
Mathematica
540 lines
19 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-1999, 2003 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_liveness.m
|
|
% Main author: stayl
|
|
%
|
|
% Use rl_analyse.m to compute the liveness of relations.
|
|
% Remove dead code and insert instructions unset relation variables
|
|
% to make sure that temporaries are kept no longer than they are needed.
|
|
% Work out which relations need to be saved across calls.
|
|
% Insert explicit initialisations for relations used before they are defined.
|
|
% Make sure the inputs to uniondiff and insert instructions have at most
|
|
% one reference by inserting copy or make_unique instructions.
|
|
%-----------------------------------------------------------------------------%
|
|
:- module aditi_backend__rl_liveness.
|
|
|
|
:- interface.
|
|
|
|
:- import_module aditi_backend__rl_block.
|
|
|
|
:- import_module io.
|
|
|
|
:- pred rl_liveness(rl_opt_info, rl_opt_info, io__state, io__state).
|
|
:- mode rl_liveness(in, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module aditi_backend__rl.
|
|
:- import_module aditi_backend__rl_analyse.
|
|
|
|
:- import_module bool, int, list, map, relation, require, set, std_util.
|
|
|
|
rl_liveness(Opt0, Opt, IO0, IO) :-
|
|
rl_liveness_2(IO0, IO, Opt0, Opt).
|
|
|
|
:- pred rl_liveness_2(io__state, io__state, rl_opt_info, rl_opt_info).
|
|
:- mode rl_liveness_2(di, uo, in, out) is det.
|
|
|
|
rl_liveness_2(IO0, IO) -->
|
|
rl_opt_info_get_input_relations(Inputs),
|
|
rl_opt_info_get_output_relations(Outputs),
|
|
rl_opt_info_get_memoed_relations(MemoedRels),
|
|
{ set__insert_list(MemoedRels, Inputs, LiveAtStart) },
|
|
{ set__insert_list(MemoedRels, Outputs, LiveAtEnd) },
|
|
|
|
%
|
|
% Work out which relations are live at the end of each block.
|
|
%
|
|
rl_opt_info_get_rev_block_order(RevOrder),
|
|
{ map__init(LiveMap0) },
|
|
list__foldl2(rl_liveness__init_block_liveness(LiveAtEnd),
|
|
RevOrder, LiveMap0, LiveMap1),
|
|
|
|
{ LiveConfluence = rl_liveness__confluence },
|
|
{ LiveBlockUpdate = rl_liveness__update_block_liveness },
|
|
{ LiveEqual = rl_liveness__unify },
|
|
{ LiveWrite = rl_analyse__write_gen_kill_data },
|
|
|
|
{ LiveAnalysis =
|
|
rl_analysis(
|
|
backward,
|
|
LiveConfluence,
|
|
LiveBlockUpdate,
|
|
LiveEqual,
|
|
LiveWrite
|
|
) },
|
|
rl_analyse(RevOrder, LiveAnalysis, LiveMap1, LiveMap,
|
|
unit, _, IO0, IO1),
|
|
|
|
%
|
|
% Work out which relations have been initialised
|
|
% at the end of each block.
|
|
%
|
|
{ map__init(CreateMap0) },
|
|
list__foldl2(rl_liveness__init_block_creation(LiveAtStart),
|
|
RevOrder, CreateMap0, CreateMap1),
|
|
|
|
{ CreateConfluence = rl_liveness__confluence },
|
|
{ CreateBlockUpdate = rl_liveness__update_block_creation },
|
|
{ CreateEqual = rl_liveness__unify },
|
|
{ CreateWrite = rl_analyse__write_gen_kill_data },
|
|
|
|
{ CreateAnalysis =
|
|
rl_analysis(
|
|
forward,
|
|
CreateConfluence,
|
|
CreateBlockUpdate,
|
|
CreateEqual,
|
|
CreateWrite
|
|
) },
|
|
|
|
{ list__reverse(RevOrder, Order) },
|
|
rl_analyse(Order, CreateAnalysis, CreateMap1, CreateMap,
|
|
unit, _, IO1, IO),
|
|
|
|
list__foldl(
|
|
rl_liveness__insert_init_and_unset_instructions(LiveAtStart,
|
|
LiveAtEnd, LiveMap, CreateMap),
|
|
Order
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type live_data == gen_kill_data.
|
|
:- type live_data_map == gen_kill_data_map.
|
|
|
|
:- pred rl_liveness__init_block_liveness(set(relation_id)::in, block_id::in,
|
|
live_data_map::in, live_data_map::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__init_block_liveness(LiveAtEndofLast, BlockId,
|
|
LiveData0, LiveData) -->
|
|
rl_opt_info_get_block(BlockId, Block),
|
|
{ Block = block(_, Instrs, MaybeBranch, _) },
|
|
{ set__init(Def0) },
|
|
{ set__init(Use0) },
|
|
{ set__init(DefinedRels0) },
|
|
{ set__init(UsedRels0) },
|
|
|
|
{ list__foldl2(rl_liveness__instr_use_before_def, Instrs,
|
|
Use0, Use1, DefinedRels0, DefinedRels1) },
|
|
{ MaybeBranch = yes(BranchInstr) ->
|
|
rl_liveness__instr_use_before_def(BranchInstr, Use1, Use,
|
|
DefinedRels1, _)
|
|
;
|
|
Use = Use1
|
|
},
|
|
|
|
{ list__foldl2(rl_liveness__instr_def_before_use, Instrs,
|
|
Def0, Def, UsedRels0, _) },
|
|
% The branch instruction at the end of the block
|
|
% can't define any relations.
|
|
|
|
rl_opt_info_get_last_block_id(LastBlockId),
|
|
{ BlockId = LastBlockId ->
|
|
EndLiveRels1 = LiveAtEndofLast,
|
|
set__difference(EndLiveRels1, Def, StartLiveRels0),
|
|
set__union(StartLiveRels0, Use, StartLiveRels)
|
|
;
|
|
set__init(EndLiveRels1),
|
|
set__init(StartLiveRels)
|
|
},
|
|
{ MaybeBranch = yes(Branch) ->
|
|
% The relations used in the branch at the end
|
|
% are always live at the end of the block.
|
|
rl__instr_relations(Branch, BranchInputs, _),
|
|
set__insert_list(EndLiveRels1, BranchInputs, EndLiveRels)
|
|
;
|
|
EndLiveRels = EndLiveRels1
|
|
},
|
|
{ BlockData = block_data(EndLiveRels, StartLiveRels, Use - Def) },
|
|
{ map__det_insert(LiveData0, BlockId, BlockData, LiveData) }.
|
|
|
|
% Find all relations used in the block before
|
|
% any definitions in the block. These relations
|
|
% are required to be live on entry to the block.
|
|
:- pred rl_liveness__instr_use_before_def(rl_instruction::in,
|
|
set(relation_id)::in, set(relation_id)::out,
|
|
set(relation_id)::in, set(relation_id)::out) is det.
|
|
|
|
rl_liveness__instr_use_before_def(Instr, Use0, Use,
|
|
DefinedRels0, DefinedRels) :-
|
|
rl__instr_relations(Instr, Inputs, Outputs),
|
|
set__list_to_set(Inputs, InputSet),
|
|
set__difference(InputSet, DefinedRels0, UndefinedUsedRels),
|
|
set__union(Use0, UndefinedUsedRels, Use),
|
|
set__insert_list(DefinedRels0, Outputs, DefinedRels).
|
|
|
|
% Find all relations defined in the block before any uses
|
|
% in the block. These relations are dead at the start of
|
|
% the block.
|
|
:- pred rl_liveness__instr_def_before_use(rl_instruction::in,
|
|
set(relation_id)::in, set(relation_id)::out,
|
|
set(relation_id)::in, set(relation_id)::out) is det.
|
|
|
|
rl_liveness__instr_def_before_use(Instr, DefinedRels0, DefinedRels,
|
|
UsedRels0, UsedRels) :-
|
|
rl__instr_relations(Instr, Inputs, Outputs),
|
|
set__insert_list(UsedRels0, Inputs, UsedRels),
|
|
set__list_to_set(Outputs, OutputSet),
|
|
set__difference(OutputSet, UsedRels, UnusedDefinedRels),
|
|
set__union(DefinedRels0, UnusedDefinedRels, DefinedRels).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Given the required liveness at the end of the block, compute
|
|
% the required liveness at the start of the block.
|
|
:- pred rl_liveness__update_block_liveness(block_id::in,
|
|
int_set::in, live_data::in, live_data::out, unit::in, unit::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__update_block_liveness(BlockId, EndLiveRels0,
|
|
BlockData0, BlockData, _, unit) -->
|
|
rl_opt_info_get_block(BlockId, Block),
|
|
rl_opt_info_get_last_block_id(LastBlockId),
|
|
{ BlockId = LastBlockId ->
|
|
% The last block never branches to anywhere,
|
|
% so its liveness information never changes.
|
|
BlockData = BlockData0
|
|
;
|
|
BlockData0 = block_data(_, _, Use - Def),
|
|
Block = block(_, _, MaybeBranch, _),
|
|
( MaybeBranch = yes(Branch) ->
|
|
% The relations used in the branch at the end
|
|
% are always live at the end of the block.
|
|
rl__instr_relations(Branch, BranchInputs, _),
|
|
set__insert_list(EndLiveRels0,
|
|
BranchInputs, EndLiveRels)
|
|
;
|
|
EndLiveRels = EndLiveRels0
|
|
),
|
|
set__difference(EndLiveRels, Def, StartLiveRels0),
|
|
set__union(StartLiveRels0, Use, StartLiveRels),
|
|
BlockData = block_data(EndLiveRels, StartLiveRels, Use - Def)
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Combine the data from multiple callers/callees of a block.
|
|
:- pred rl_liveness__confluence(pair(block_id, int_set)::in,
|
|
pair(block_id, maybe(int_set))::in, int_set::out,
|
|
unit::in, unit::out, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__confluence(_ - Data, _ - no, Data, _, unit) --> [].
|
|
rl_liveness__confluence(_ - Data1, _ - yes(Data2), Data, _, unit) -->
|
|
{ set__union(Data1, Data2, Data) }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_liveness__unify(int_set::in, int_set::in, unit::in) is semidet.
|
|
|
|
rl_liveness__unify(Data, Data, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type creation_data == gen_kill_data.
|
|
:- type creation_data_map == gen_kill_data_map.
|
|
|
|
:- pred rl_liveness__init_block_creation(set(relation_id)::in, block_id::in,
|
|
creation_data_map::in, creation_data_map::out,
|
|
rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__init_block_creation(CreatedAtStartOfFirst, BlockId,
|
|
CreateMap0, CreateMap) -->
|
|
rl_opt_info_get_block(BlockId, Block),
|
|
{ Block = block(_, Instrs, _, _) },
|
|
{ set__init(Created0) },
|
|
{ AddCreated = lambda([Instr::in, C0::in, C::out] is det, (
|
|
rl__instr_relations(Instr, _, Outputs),
|
|
set__insert_list(C0, Outputs, C)
|
|
)) },
|
|
{ list__foldl(AddCreated, Instrs, Created0, Created) },
|
|
|
|
rl_opt_info_get_first_block_id(FirstBlock),
|
|
{ BlockId = FirstBlock ->
|
|
InCreated = CreatedAtStartOfFirst,
|
|
set__union(InCreated, Created, OutCreated)
|
|
;
|
|
set__init(InCreated),
|
|
OutCreated = Created
|
|
},
|
|
{ set__init(Dummy) },
|
|
{ BlockData = block_data(InCreated, OutCreated, Created - Dummy) },
|
|
{ map__det_insert(CreateMap0, BlockId, BlockData, CreateMap) }.
|
|
|
|
:- pred rl_liveness__update_block_creation(block_id::in,
|
|
int_set::in, creation_data::in, creation_data::out,
|
|
unit::in, unit::out, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__update_block_creation(BlockId, InCreated,
|
|
BlockData0, BlockData, _, unit) -->
|
|
rl_opt_info_get_first_block_id(FirstBlockId),
|
|
{ BlockId = FirstBlockId ->
|
|
% The first block is never branched to from anywhere,
|
|
% so its initial liveness never changes.
|
|
BlockData = BlockData0
|
|
;
|
|
BlockData0 = block_data(_, _, Created - Dummy),
|
|
set__union(InCreated, Created, OutCreated),
|
|
BlockData = block_data(InCreated, OutCreated, Created - Dummy)
|
|
}.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl_liveness__insert_init_and_unset_instructions(set(relation_id)::in,
|
|
set(relation_id)::in, live_data_map::in, creation_data_map::in,
|
|
block_id::in, rl_opt_info::in, rl_opt_info::out) is det.
|
|
|
|
rl_liveness__insert_init_and_unset_instructions(CreatedAtStart, LiveAtEnd,
|
|
LiveMap, CreateMap, BlockId) -->
|
|
rl_opt_info_get_first_block_id(FirstBlockId),
|
|
rl_opt_info_get_last_block_id(LastBlockId),
|
|
rl_opt_info_get_block(BlockId, Block0),
|
|
{ Block0 = block(Label, Instrs0, Branch, _BlockInfo0) },
|
|
|
|
%
|
|
% Go backwards over the instructions removing dead code
|
|
% and inserting instructions to drop temporaries as
|
|
% soon as they become dead.
|
|
%
|
|
{ list__reverse(Instrs0, RevInstrs0) },
|
|
{ map__lookup(LiveMap, BlockId, LiveData) },
|
|
{ LiveData = block_data(BlockLiveAtEnd, _, _) },
|
|
{ list__foldl2(rl_liveness__insert_unset_instructions,
|
|
RevInstrs0, [], Instrs1, BlockLiveAtEnd, BlockLiveAtStart) },
|
|
|
|
%
|
|
% Drop relations which are live at the end of a
|
|
% calling block but are dead at the start of
|
|
% this block.
|
|
%
|
|
rl_opt_info_get_flow_graph(Graph),
|
|
{ relation__lookup_element(Graph, BlockId, BlockKey) },
|
|
{ relation__lookup_to(Graph, BlockKey, CallingBlockKeys0) },
|
|
{ set__to_sorted_list(CallingBlockKeys0, CallingBlockKeys) },
|
|
{ list__map(relation__lookup_key(Graph), CallingBlockKeys,
|
|
CallingBlocks) },
|
|
{ GetLiveOutputs =
|
|
lambda([CallingBlock::in, LiveRels::out] is det, (
|
|
map__lookup(LiveMap, CallingBlock, CallingData),
|
|
CallingData = block_data(LiveRels, _, _)
|
|
)) },
|
|
{ list__map(GetLiveOutputs, CallingBlocks, CallingBlockLiveRels0) },
|
|
( { BlockId = FirstBlockId } ->
|
|
{ CallingBlockLiveRels1 = CreatedAtStart }
|
|
;
|
|
{ set__init(CallingBlockLiveRels1) }
|
|
),
|
|
{ list__foldl(set__union, CallingBlockLiveRels0,
|
|
CallingBlockLiveRels1, CallingBlockLiveRels) },
|
|
{ set__difference(CallingBlockLiveRels,
|
|
BlockLiveAtStart, DeadAtStart0) },
|
|
{ set__to_sorted_list(DeadAtStart0, DeadAtStart) },
|
|
{ list__map(rl_liveness__drop_rel, DeadAtStart, DropDeadRels) },
|
|
|
|
%
|
|
% Go forwards over the instructions adding creates for
|
|
% relations which should be live at the start of the
|
|
% block but are not.
|
|
%
|
|
rl_opt_info_get_relation_info_map(RelInfoMap),
|
|
{ map__lookup(CreateMap, BlockId, CreateData) },
|
|
{ CreateData = block_data(BlockCreatedAtStart, _, _) },
|
|
{ list__foldl2(rl_liveness__insert_init_instructions(RelInfoMap),
|
|
Instrs1, [], RevInstrs1, BlockCreatedAtStart,
|
|
BlockCreatedAtEnd) },
|
|
{ list__reverse(RevInstrs1, Instrs2) },
|
|
|
|
%
|
|
% Add creates for relations which are live at the
|
|
% start of a called block but which are not initialised
|
|
% by any caller of this block and are not created
|
|
% by this block.
|
|
%
|
|
{ relation__lookup_from(Graph, BlockKey, CalledBlockKeys0) },
|
|
{ set__to_sorted_list(CalledBlockKeys0, CalledBlockKeys) },
|
|
{ list__map(relation__lookup_key(Graph), CalledBlockKeys,
|
|
CalledBlocks) },
|
|
{ GetCreatedOutputs =
|
|
lambda([CalledBlock::in, CalledInitAtStart::out] is det, (
|
|
map__lookup(CreateMap, CalledBlock, CalledCreateData),
|
|
map__lookup(LiveMap, CalledBlock, CalledLiveData),
|
|
CalledLiveData = block_data(_, CalledLiveAtStart, _),
|
|
CalledCreateData =
|
|
block_data(_, CalledInitAtStart0, _),
|
|
set__intersect(CalledInitAtStart0, CalledLiveAtStart,
|
|
CalledInitAtStart)
|
|
)) },
|
|
{ list__map(GetCreatedOutputs, CalledBlocks, CalledBlockCreated0) },
|
|
( { BlockId = LastBlockId } ->
|
|
{ CalledBlockCreated1 = LiveAtEnd }
|
|
;
|
|
{ set__init(CalledBlockCreated1) }
|
|
),
|
|
{ list__foldl(set__union, CalledBlockCreated0,
|
|
CalledBlockCreated1, CalledBlockCreated) },
|
|
{ set__difference(CalledBlockCreated, BlockCreatedAtEnd,
|
|
NotCreatedAtEnd0) },
|
|
{ set__to_sorted_list(NotCreatedAtEnd0, NotCreatedAtEnd) },
|
|
|
|
{ list__filter_map(rl_liveness__init_rel(RelInfoMap),
|
|
NotCreatedAtEnd, CreateRels) },
|
|
|
|
{ list__condense([DropDeadRels, Instrs2, CreateRels], Instrs) },
|
|
|
|
{ BlockInfo = block_info(BlockLiveAtStart, BlockLiveAtEnd) },
|
|
{ Block = block(Label, Instrs, Branch, BlockInfo) },
|
|
rl_opt_info_set_block(BlockId, Block).
|
|
|
|
% Go backwards over the instructions inserting instructions
|
|
% to unset relation variables that become dead.
|
|
% Also add instructions to make sure inputs to operations
|
|
% such as B-tree union_diff have only one reference and can
|
|
% be updated.
|
|
:- pred rl_liveness__insert_unset_instructions(rl_instruction::in,
|
|
list(rl_instruction)::in, list(rl_instruction)::out,
|
|
set(relation_id)::in, set(relation_id)::out) is det.
|
|
|
|
rl_liveness__insert_unset_instructions(Instr0, Instrs0, Instrs,
|
|
LiveRels0, LiveRels) :-
|
|
rl__instr_relations(Instr0, Inputs, Outputs),
|
|
set__list_to_set(Outputs, OutputSet),
|
|
set__intersect(OutputSet, LiveRels0, LiveOutputs),
|
|
(
|
|
set__empty(LiveOutputs)
|
|
->
|
|
( rl_liveness__undroppable_instr(Instr0) ->
|
|
Instrs = [Instr0 | Instrs0]
|
|
;
|
|
Instrs = Instrs0
|
|
),
|
|
LiveRels = LiveRels0
|
|
;
|
|
% Order is important here. Relations that are defined
|
|
% by the instruction are made dead, then relations
|
|
% used are made live.
|
|
set__difference(LiveRels0, OutputSet, LiveRels1),
|
|
|
|
set__insert_list(LiveRels1, Inputs, LiveRels),
|
|
|
|
% Produce instructions to unset all the relation variables
|
|
% made dead by this instruction.
|
|
set__difference(LiveRels, LiveRels0, KilledRels0),
|
|
set__difference(OutputSet, LiveRels0, StillBornRels),
|
|
set__union(KilledRels0, StillBornRels, KilledRels1),
|
|
set__to_sorted_list(KilledRels1, KilledRels),
|
|
list__map(rl_liveness__drop_rel, KilledRels, PostInstrs0),
|
|
|
|
(
|
|
% Attach to the call the set of relations which
|
|
% need to be saved across it.
|
|
Instr0 = call(ProcInputs, CallInputs,
|
|
CallOutputs, _) - Comment
|
|
->
|
|
set__list_to_set(Inputs, InputSet),
|
|
set__intersect(LiveRels1, InputSet, LiveInputs),
|
|
PreInstrs = [],
|
|
PostInstrs1 = [],
|
|
Instr = call(ProcInputs, CallInputs, CallOutputs,
|
|
LiveInputs) - Comment
|
|
;
|
|
% Make sure there is only one reference to the
|
|
% destructively updated input to a union_diff.
|
|
Instr0 = union_diff(UoOutput, DiInput, Input, Diff,
|
|
Index, yes(CopyRel)) - Comment
|
|
->
|
|
( set__member(DiInput, KilledRels0) ->
|
|
PreInstrs = [make_unique(CopyRel, DiInput) - ""]
|
|
;
|
|
PreInstrs = [copy(CopyRel, DiInput) - ""]
|
|
),
|
|
CopyRel = output_rel(CopyRelation, _),
|
|
Instr = union_diff(UoOutput, CopyRelation,
|
|
Input, Diff, Index, no) - Comment,
|
|
PostInstrs1 = [unset(CopyRelation) - ""]
|
|
;
|
|
% Make sure there is only one reference to the
|
|
% destructively updated input to an insert.
|
|
Instr0 = insert(UoOutput, DiInput, Input, InsertType,
|
|
yes(CopyRel)) - Comment
|
|
->
|
|
( set__member(DiInput, KilledRels0) ->
|
|
PreInstrs = [make_unique(CopyRel, DiInput) - ""]
|
|
;
|
|
PreInstrs = [copy(CopyRel, DiInput) - ""]
|
|
),
|
|
CopyRel = output_rel(CopyRelation, _),
|
|
Instr = insert(UoOutput, CopyRelation,
|
|
Input, InsertType, no) - Comment,
|
|
PostInstrs1 = [unset(CopyRelation) - ""]
|
|
;
|
|
Instr = Instr0,
|
|
PreInstrs = [],
|
|
PostInstrs1 = []
|
|
),
|
|
|
|
% Add the instructions to unset the newly dead
|
|
% relation variables after the instruction.
|
|
list__condense(
|
|
[
|
|
PreInstrs,
|
|
[Instr],
|
|
PostInstrs0,
|
|
PostInstrs1,
|
|
Instrs0
|
|
],
|
|
Instrs)
|
|
).
|
|
|
|
:- pred rl_liveness__undroppable_instr(rl_instruction::in) is semidet.
|
|
|
|
rl_liveness__undroppable_instr(label(_) - _).
|
|
rl_liveness__undroppable_instr(goto(_) - _).
|
|
rl_liveness__undroppable_instr(conditional_goto(_, _) - _).
|
|
rl_liveness__undroppable_instr(clear(_) - _).
|
|
rl_liveness__undroppable_instr(unset(_) - _).
|
|
|
|
:- pred rl_liveness__drop_rel(relation_id::in, rl_instruction::out) is det.
|
|
|
|
rl_liveness__drop_rel(Rel, unset(Rel) - "").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Add create instructions to explicitly initialise free relation
|
|
% variables just before they are used.
|
|
:- pred rl_liveness__insert_init_instructions(relation_info_map::in,
|
|
rl_instruction::in, list(rl_instruction)::in,
|
|
list(rl_instruction)::out, set(relation_id)::in,
|
|
set(relation_id)::out) is det.
|
|
|
|
rl_liveness__insert_init_instructions(RelInfoMap, Instr,
|
|
RevInstrs0, RevInstrs, CreatedRels0, CreatedRels) :-
|
|
rl__instr_relations(Instr, Inputs, Outputs),
|
|
|
|
set__list_to_set(Inputs, InputSet),
|
|
set__difference(InputSet, CreatedRels0, UninitialisedInputs0),
|
|
set__to_sorted_list(UninitialisedInputs0, UninitialisedInputs),
|
|
list__filter_map(rl_liveness__init_rel(RelInfoMap),
|
|
UninitialisedInputs, Initialisations),
|
|
|
|
list__append([Instr | Initialisations], RevInstrs0, RevInstrs),
|
|
set__insert_list(CreatedRels0, Outputs, CreatedRels1),
|
|
set__union(CreatedRels1, UninitialisedInputs0, CreatedRels).
|
|
|
|
:- pred rl_liveness__init_rel(relation_info_map::in,
|
|
relation_id::in, rl_instruction::out) is semidet.
|
|
|
|
rl_liveness__init_rel(RelInfoMap, Rel, init(output_rel(Rel, [])) - "") :-
|
|
map__lookup(RelInfoMap, Rel, RelInfo),
|
|
% Only initialise temporary relations.
|
|
RelInfo = relation_info(temporary(_), _, _, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|