2
2
%% -*- erlang-indent-level: 2 -*-
4
3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
%% analyze(CFG) - returns a livenes analyzis of CFG.
11
%% liveout(Liveness, Label) - returns a set of variables that are alive at
9
%% analyze(CFG) - returns a liveness analysis of CFG.
10
%% liveout(Liveness, Label) - returns a set of variables that are live at
12
11
%% exit from basic block named Label.
13
%% livein(Liveness, Label) - returns a set of variables that are alive at
12
%% livein(Liveness, Label) - returns a set of variables that are live at
14
13
%% entry to the basic block named Label.
15
%% list(Instructions, LiveOut) - Given a list of instructions and a
16
%% liveout-set, returns a set of variables live at the first instruction.
14
%% livein_from_liveout(Instructions, LiveOut) - Given a list of instructions
15
%% and a liveout-set, returns a set of variables live at the
19
19
-export([analyze/1,
21
-ifdef(LIVEOUT_NEEDED).
27
%%-export([livein_from_liveout/2]).
28
-ifdef(DEBUG_LIVENESS).
29
-export([annotate_liveness/2]).
27
32
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29
34
%% Interface functions that MUST be implemented in the including file
32
36
%% cfg_bb(CFG, L) -> BasicBlock, extract a basic block from a cfg.
33
37
%% cfg_postorder(CFG) -> [Labels], the labels of the cfg in postorder
34
38
%% cfg_succ_map(CFG) -> SuccMap, a successor mapping.
35
39
%% cfg_succ(CFG, L) -> [Labels],
36
%% cfg_bb_update(CFG, L, NewBB) ->
39
41
%% defines(Instr) ->
43
%% Plus the following, if basic block annotations are needed
46
%% cfg_bb_add(CFG, L, NewBB) ->
40
47
%% mk_comment(Text) ->
44
50
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
119
Kill = ordsets:subtract(LiveOut, kill(L, Liveness)),
114
120
LiveIn = ordsets:union(Kill, gen(L,Liveness)),
115
121
{NewLiveness, ChangedP} = update_livein(L, LiveIn, Liveness),
117
doit_once(Ls, NewLiveness, Changed+ChangedP).
121
%% Given a list of instructions and liveout, calculates livein
123
-ifdef(HIPE_LIVENESS_CALC_LARGEST_LIVESET).
126
list([I|Is], LiveOut) ->
127
LiveIn = list(Is, LiveOut),
128
InstrGen = ordsets:from_list(uses(I)),
129
InstrKill = ordsets:from_list(defines(I)),
130
Live = ordsets:union(InstrGen, ordsets:subtract(LiveIn, InstrKill)),
132
Max = get(hipe_largest_liveset),
133
if Le > Max -> put(hipe_largest_liveset,Le);
141
list([I|Is], LiveOut) ->
142
LiveIn = list(Is, LiveOut),
143
InstrGen = ordsets:from_list(uses(I)),
144
InstrKill = ordsets:from_list(defines(I)),
145
Live = ordsets:union(InstrGen, ordsets:subtract(LiveIn, InstrKill)),
122
doit_once(Ls, NewLiveness, Changed+ChangedP).
126
%% %% Given a list of instructions and liveout, calculates livein
128
%% livein_from_liveout(List, LiveOut) when is_list(List)->
129
%% livein_from_liveout_1(lists:reverse(List), gb_sets:from_list(LiveOut));
130
%% livein_from_liveout(Instr, LiveOut) ->
131
%% livein_from_liveout_1([Instr], gb_sets:from_list(LiveOut)).
133
%% livein_from_liveout_1([], LiveOut) ->
134
%% gb_sets:to_list(LiveOut);
135
%% livein_from_liveout_1([I|Is], LiveOut) ->
138
%% DefSet = gb_sets:from_list(Def),
139
%% UseSet = gb_sets:from_list(Use),
140
%% LiveIn = gb_sets:union(gb_sets:difference(LiveOut, DefSet), UseSet),
141
%% Le = gb_sets:size(LiveIn),
142
%% Max = get(hipe_largest_liveset),
143
%% if Le > Max -> put(hipe_largest_liveset,Le);
146
%% livein_from_liveout_1(Is, LiveIn).
151
149
%% updates liveness for a basic block
172
169
liveout(Liveness, L) ->
173
Succ = successors(L, Liveness),
175
[] -> % special case if no successors
178
liveout1(Succ, Liveness)
170
Succ = successors(L, Liveness),
172
[] -> % special case if no successors
175
liveout1(Succ, Liveness)
181
178
liveout1(Labels, Liveness) ->
182
179
liveout1(Labels, Liveness, ordsets:new()).
183
liveout1([], Liveness, Live) ->
181
liveout1([], _Liveness, Live) ->
185
183
liveout1([L|Ls], Liveness,Live) ->
186
liveout1(Ls, Liveness, ordsets:union(livein(Liveness, L),Live)).
184
liveout1(Ls, Liveness, ordsets:union(livein(Liveness, L),Live)).
190
187
successors(L, Liveness) ->
191
{_GK,_LiveIn, Successors} = liveness_lookup(L, Liveness),
188
{_GK,_LiveIn, Successors} = liveness_lookup(L, Liveness),
194
191
livein(Liveness, L) ->
195
{_GK, LiveIn,_Successors} = liveness_lookup(L, Liveness),
192
{_GK, LiveIn,_Successors} = liveness_lookup(L, Liveness),
198
195
kill(L, Liveness) ->
199
{{_Gen,Kill},_LiveIn,_Successors} = liveness_lookup(L, Liveness),
196
{{_Gen,Kill},_LiveIn,_Successors} = liveness_lookup(L, Liveness),
202
199
gen(L, Liveness) ->
203
{{Gen,_Kill},_LiveIn,_Successors} = liveness_lookup(L, Liveness),
200
{{Gen,_Kill},_LiveIn,_Successors} = liveness_lookup(L, Liveness),
207
204
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215
212
%% - Successors is a list of the successors to the block.
219
216
init([L|Ls], CFG) ->
221
Code = hipe_bb:code(BB),
222
SuccMap = cfg_succ_map(CFG),
223
Succ = cfg_succ(SuccMap, L),
224
Transfer = make_bb_transfer(Code, Succ),
225
[{L, {Transfer, ordsets:new(), Succ}} | init(Ls, CFG)].
218
Code = hipe_bb:code(BB),
219
SuccMap = cfg_succ_map(CFG),
220
Succ = cfg_succ(SuccMap, L),
221
Transfer = make_bb_transfer(Code, Succ),
222
[{L, {Transfer, ordsets:new(), Succ}} | init(Ls, CFG)].
228
225
make_bb_transfer([], _Succ) ->
229
{ordsets:new(), ordsets:new()}; % {Gen, Kill}
226
{ordsets:new(), ordsets:new()}; % {Gen, Kill}
230
227
make_bb_transfer([I|Is], Succ) ->
231
{Gen, Kill} = make_bb_transfer(Is, Succ),
232
InstrGen = ordsets:from_list(uses(I)),
233
InstrKill = ordsets:from_list(defines(I)),
234
Gen1 = ordsets:subtract(Gen, InstrKill),
235
Gen2 = ordsets:union(Gen1, InstrGen),
236
Kill1 = ordsets:union(Kill, InstrKill),
237
Kill2 = ordsets:subtract(Kill1, InstrGen),
228
{Gen, Kill} = make_bb_transfer(Is, Succ),
229
InstrGen = ordsets:from_list(uses(I)),
230
InstrKill = ordsets:from_list(defines(I)),
231
Gen1 = ordsets:subtract(Gen, InstrKill),
232
Gen2 = ordsets:union(Gen1, InstrGen),
233
Kill1 = ordsets:union(Kill, InstrKill),
234
Kill2 = ordsets:subtract(Kill1, InstrGen),
241
242
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243
244
%% Annotate each basic block with liveness info
246
annotate(CFG, Liveness) ->
247
Labels = cfg_labels(CFG),
248
annotate_bb(Labels, CFG, Liveness).
250
annotate_bb([], CFG, _Liveness) ->
252
annotate_bb([L|Ls], CFG, Liveness) ->
254
Code0 = hipe_bb:code(BB),
255
LiveIn = strip(livein(Liveness, L)),
256
LiveOut = strip(liveout(Liveness, L)),
257
Code = [mk_comment({live_in, LiveIn}),
258
mk_comment({live_out, LiveOut})
260
NewBB = hipe_bb:code_update(BB, Code),
261
NewCFG = cfg_bb_update(CFG, L, NewBB),
262
annotate_bb(Ls, NewCFG, Liveness).
247
-ifdef(DEBUG_LIVENESS).
249
annotate_liveness(CFG, Liveness) ->
250
Labels = cfg_labels(CFG),
251
annotate_liveness_bb(Labels, CFG, Liveness).
253
annotate_liveness_bb([], CFG, _Liveness) ->
255
annotate_liveness_bb([L|Ls], CFG, Liveness) ->
257
Code0 = hipe_bb:code(BB),
258
LiveIn = strip(livein(Liveness, L)),
259
LiveOut = strip(liveout(Liveness, L)),
260
Code = [mk_comment({live_in, LiveIn}),
261
mk_comment({live_out, LiveOut})
263
NewBB = hipe_bb:code_update(BB, Code),
264
NewCFG = cfg_bb_add(CFG, L, NewBB),
265
annotate_liveness_bb(Ls, NewCFG, Liveness).
267
269
strip([{_,Y}|Xs]) ->
272
-endif. % DEBUG_LIVENESS
271
275
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273
277
liveness_init(List) ->
274
?vector_from_list(dense(0,lists:sort(List), [])).
275
% liveness_init(List) -> hipe_hash:init(List).
278
liveness_init(List, gb_trees:empty()).
280
liveness_init([{Lbl, Data}|Left], Acc) ->
281
liveness_init(Left, gb_trees:insert(Lbl, Data, Acc));
282
liveness_init([], Acc) ->
277
285
liveness_lookup(Label, Liveness) ->
278
?vector_get(Label+1, Liveness).
279
%% liveness_lookup(Label, Liveness) ->
280
%% {found, {GK, LiveIn, Successors}} = hipe_hash:lookup(Label, Liveness),
281
%% {GK, LiveIn, Successors}.
286
gb_trees:get(Label, Liveness).
282
287
liveness_update(Label, Val, Liveness) ->
283
?vector_set(Label+1, Liveness, Val).
285
%% liveness_update(Label, Val, Liveness) ->
286
%% hipe_hash:update(Label, Val, Liveness).
289
%% Build a dense mapping
291
%% Done reverse the list.
293
dense(N, [{Pos, Data}|Ms], Vs) when N =:= Pos ->
294
%% N makes sure the mapping is dense. N is he next key.
295
dense(N+1, Ms, [Data|Vs]);
296
dense(N, Source, Vs) ->
297
%% The source was sparce, make up some placeholders...
288
gb_trees:update(Label, Val, Liveness).
291
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293
%% pp/1 pretty prints liveness information for a CFG
296
-ifdef(PRETTY_PRINT).
298
Liveness=analyze(Cfg),
299
Labels=cfg_labels(Cfg),
300
ok=print_blocks(Labels, Liveness, Cfg).
302
print_blocks([Lbl|Rest], Liveness, Cfg) ->
303
io:format("~nLivein:", []),
304
pp_liveness_info(livein(Liveness, Lbl)),
305
io:format("Label ~w:~n" , [Lbl]),
307
io:format("Liveout:", []),
308
pp_liveness_info(liveout(Liveness, Lbl)),
309
print_blocks(Rest, Liveness, Cfg);
310
print_blocks([], _Liveness, _Cfg) ->
312
-endif. % PRETTY_PRINT