File: rl_liveness.m

package info (click to toggle)
mercury 0.9-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 18,488 kB
  • ctags: 9,800
  • sloc: objc: 146,680; ansic: 51,418; sh: 6,436; lisp: 1,567; cpp: 1,040; perl: 854; makefile: 450; asm: 232; awk: 203; exp: 32; fortran: 3; csh: 1
file content (536 lines) | stat: -rw-r--r-- 19,170 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
%-----------------------------------------------------------------------------%
% Copyright (C) 1998-1999 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 rl_liveness.

:- interface.

:- import_module 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 rl, 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(_), _, _, _).

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%