File: labelopt.m

package info (click to toggle)
mercury 0.10.1-3
  • links: PTS
  • area: main
  • in suites: woody
  • size: 21,984 kB
  • ctags: 11,923
  • sloc: objc: 187,634; ansic: 66,107; sh: 7,570; lisp: 1,568; cpp: 1,337; makefile: 614; perl: 511; awk: 274; asm: 252; exp: 32; xml: 12; fortran: 3; csh: 1
file content (155 lines) | stat: -rw-r--r-- 4,601 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
%-----------------------------------------------------------------------------%
% Copyright (C) 1994-1999 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.
%-----------------------------------------------------------------------------%

% labelopt.m - module to eliminate useless labels and dead code.

% Author: zs.

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

:- module labelopt.

:- interface.

:- import_module bool, list, set.
:- import_module llds.

	% Build up a set showing which labels are branched to,
	% then traverse the instruction list removing unnecessary labels.
	% If the instruction before the label branches away, we also
	% remove the instruction block following the label.

:- pred labelopt_main(list(instruction)::in, bool::in, set(label)::in,
	list(instruction)::out, bool::out) is det.

	% Build up a set showing which labels are referred to.
	% The input set is the list of labels referred to from outside
	% the given list of instructions.

:- pred labelopt__build_useset(list(instruction)::in, set(label)::in,
	set(label)::out) is det.

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

:- implementation.

:- import_module opt_util.
:- import_module std_util.

labelopt_main(Instrs0, Final, LayoutLabelSet, Instrs, Mod) :-
	labelopt__build_useset(Instrs0, LayoutLabelSet, Useset),
	labelopt__instr_list(Instrs0, yes, Useset, Instrs1, Mod),
	( Final = yes, Mod = yes ->
		labelopt_main(Instrs1, Final, LayoutLabelSet, Instrs, _)
	;
		Instrs = Instrs1
	).

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

labelopt__build_useset([], Useset, Useset).
labelopt__build_useset([Instr | Instructions], Useset0, Useset) :-
	Instr = Uinstr - _Comment,
	opt_util__instr_labels(Uinstr, Labels, _CodeAddresses),
	set__insert_list(Useset0, Labels, Useset1),
	labelopt__build_useset(Instructions, Useset1, Useset).

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

	% Go through the given instruction sequence. When we find a label,
	% we check whether the label can be branched to either from within
	% the procedure or from the outside. If yes, we leave it alone.
	% If not, we delete it. We delete the following code as well if
	% the label was preceded by code that cannot fall through.

:- pred labelopt__instr_list(list(instruction)::in, bool::in, set(label)::in,
	list(instruction)::out, bool::out) is det.

labelopt__instr_list([], _Fallthrough, _Useset, [], no).
labelopt__instr_list([Instr0 | MoreInstrs0],
		Fallthrough, Useset, MoreInstrs, Mod) :-
	Instr0 = Uinstr0 - _Comment,
	( Uinstr0 = label(Label) ->
		(
			( Label = exported(_)
			; Label = local(_)
			; set__member(Label, Useset)
			)
		->
			ReplInstrs = [Instr0],
			Fallthrough1 = yes,
			Mod0 = no
		;
			labelopt__eliminate(Instr0, yes(Fallthrough),
				ReplInstrs, Mod0),
			Fallthrough1 = Fallthrough
		)
	;
		( Fallthrough = yes ->
			ReplInstrs = [Instr0],
			Mod0 = no
		;
			labelopt__eliminate(Instr0, no, ReplInstrs, Mod0)
		),
		opt_util__can_instr_fall_through(Uinstr0, Canfallthrough),
		( Canfallthrough = yes ->
			Fallthrough1 = Fallthrough
		;
			Fallthrough1 = no
		)
	),
	labelopt__instr_list(MoreInstrs0, Fallthrough1, Useset,
		MoreInstrs1, Mod1),
	list__append(ReplInstrs, MoreInstrs1, MoreInstrs),
	( Mod0 = no, Mod1 = no ->
		Mod = no
	;
		Mod = yes
	).

	% Instead of removing eliminated instructions from the instruction list,
	% we can replace them by placeholder comments. The original comment
	% field on the instruction is often enough to deduce what the
	% eliminated instruction was.

:- pred labelopt__eliminate(instruction::in, maybe(bool)::in,
	list(instruction)::out, bool::out) is det.

labelopt__eliminate(Uinstr0 - Comment0, Label, Instr, Mod) :-
	labelopt_eliminate_total(Total),
	(
		Total = yes,
		Instr = [],
		Mod = yes
	;
		Total = no,
		( Uinstr0 = comment(_) ->
			Comment = Comment0,
			Uinstr = Uinstr0,
			Mod = no
		;
			( Label = yes(Follow) ->
				( Follow = yes ->
					Uinstr = comment("eliminated label only")
				;
					% Follow = no,
					Uinstr = comment("eliminated label and block")
				)
			;
				% Label = no,
				Uinstr = comment("eliminated instruction")
			),
			Comment = Comment0,
			Mod = yes
		),
		Instr = [Uinstr - Comment]
	).

:- pred labelopt_eliminate_total(bool::out) is det.

labelopt_eliminate_total(yes).

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