37
37
-export([core_transform/2, transform/1, transform/2]).
39
39
-import(cerl, [abstract/1, alias_pat/1, alias_var/1, apply_args/1,
40
apply_op/1, atom_name/1, atom_val/1, bin_seg_val/1,
41
bin_seg_size/1, bin_seg_unit/1, bin_seg_type/1,
42
bin_seg_flags/1, binary_segs/1, update_c_alias/3,
43
update_c_apply/3, update_c_binary/2, update_c_bin_seg/6,
40
apply_op/1, atom_name/1, atom_val/1, bitstr_val/1,
41
bitstr_size/1, bitstr_unit/1, bitstr_type/1,
42
bitstr_flags/1, binary_segments/1, update_c_alias/3,
43
update_c_apply/3, update_c_binary/2, update_c_bitstr/6,
44
44
update_c_call/4, update_c_case/3, update_c_catch/2,
45
45
update_c_clause/4, c_fun/2, c_int/1, c_let/3,
46
46
update_c_let/4, update_c_letrec/3, update_c_module/5,
176
177
%% about cluttering the process dictionary with debugging info, or
177
178
%% proper deallocation of ets-tables.
178
179
Opts1 = Opts ++ [{inline_size, default_size()},
179
{inline_effort, default_effort()}],
180
{inline_effort, default_effort()},
181
{inline_unroll, default_unroll()}],
181
183
Pid = spawn_link(fun () -> start(Reply, Tree, Ctxt, Opts1) end),
187
189
start(Reply, Tree, Ctxt, Opts) ->
189
191
case debug_runtime() of
191
put(inline_start_time,
192
element(1, erlang:statistics(runtime)));
193
%% put(inline_start_time,
194
%% element(1, erlang:statistics(runtime)));
196
198
Size = max(1, proplists:get_value(inline_size, Opts)),
197
199
Effort = max(1, proplists:get_value(inline_effort, Opts)),
200
Unroll = max(1, proplists:get_value(inline_unroll, Opts)),
198
201
case proplists:get_bool(verbose, Opts) of
200
203
io:fwrite("Inlining: inline_size=~w inline_effort=~w\n",
218
221
case debug_counters() of
220
put(counter_effort_triggers, 0),
221
put(counter_effort_max, 0),
222
put(counter_size_triggers, 0),
223
put(counter_size_max, 0);
223
%% put(counter_effort_triggers, 0),
224
%% put(counter_effort_max, 0),
225
%% put(counter_size_triggers, 0),
226
%% put(counter_size_max, 0);
228
231
report_debug() ->
229
232
case debug_runtime() of
231
{Time, _} = erlang:statistics(runtime),
232
report("Total run time for inlining: ~.2.0f s.\n",
233
[(Time - get(inline_start_time))/1000]);
234
%% {Time, _} = erlang:statistics(runtime),
235
%% report("Total run time for inlining: ~.2.0f s.\n",
236
%% [(Time - get(inline_start_time))/1000]);
237
240
case debug_counters() of
245
T1 = get(counter_effort_triggers),
246
T2 = get(counter_size_triggers),
247
E = get(counter_effort_max),
248
S = get(counter_size_max),
249
M1 = io_lib:fwrite("\tNumber of triggered "
250
"effort counters: ~p.\n", [T1]),
251
M2 = io_lib:fwrite("\tNumber of triggered "
252
"size counters: ~p.\n", [T2]),
253
M3 = io_lib:fwrite("\tLargest active effort counter: ~p.\n",
255
M4 = io_lib:fwrite("\tLargest active size counter: ~p.\n",
257
report("Counter statistics:\n~s", [[M1, M2, M3, M4]]).
247
%% counter_stats() ->
248
%% T1 = get(counter_effort_triggers),
249
%% T2 = get(counter_size_triggers),
250
%% E = get(counter_effort_max),
251
%% S = get(counter_size_max),
252
%% M1 = io_lib:fwrite("\tNumber of triggered "
253
%% "effort counters: ~p.\n", [T1]),
254
%% M2 = io_lib:fwrite("\tNumber of triggered "
255
%% "size counters: ~p.\n", [T2]),
256
%% M3 = io_lib:fwrite("\tLargest active effort counter: ~p.\n",
258
%% M4 = io_lib:fwrite("\tLargest active size counter: ~p.\n",
260
%% report("Counter statistics:\n~s", [[M1, M2, M3, M4]]).
260
263
%% =====================================================================
1276
1279
i_binary(E, Ren, Env, S) ->
1277
1280
%% Visit the segments for value.
1278
1281
{Es, S1} = mapfoldl(fun (E, S) ->
1279
i_bin_seg(E, Ren, Env, S)
1282
i_bitstr(E, Ren, Env, S)
1284
S, binary_segments(E)),
1282
1285
S2 = count_size(weight(binary), S1),
1283
1286
{update_c_binary(E, Es), S2}.
1285
i_bin_seg(E, Ren, Env, S) ->
1288
i_bitstr(E, Ren, Env, S) ->
1286
1289
%% It is not necessary to visit the Unit, Type and Flags fields,
1287
1290
%% since these are always literals.
1288
{Val, S1} = i(bin_seg_val(E), value, Ren, Env, S),
1289
{Size, S2} = i(bin_seg_size(E), value, Ren, Env, S1),
1290
Unit = bin_seg_unit(E),
1291
Type = bin_seg_type(E),
1292
Flags = bin_seg_flags(E),
1293
S3 = count_size(weight(bin_seg), S2),
1294
{update_c_bin_seg(E, Val, Size, Unit, Type, Flags), S3}.
1291
{Val, S1} = i(bitstr_val(E), value, Ren, Env, S),
1292
{Size, S2} = i(bitstr_size(E), value, Ren, Env, S1),
1293
Unit = bitstr_unit(E),
1294
Type = bitstr_type(E),
1295
Flags = bitstr_flags(E),
1296
S3 = count_size(weight(bitstr), S2),
1297
{update_c_bitstr(E, Val, Size, Unit, Type, Flags), S3}.
1296
1299
%% This is a simplified version of `i_pattern', for lists of parameter
1297
1300
%% variables only. It does not modify the state.
1348
1351
{Es, S1} = mapfoldl(fun (E, S) ->
1349
i_bin_seg_pattern(E, Ren, Env,
1352
i_bitstr_pattern(E, Ren, Env,
1355
S, binary_segments(E)),
1353
1356
S2 = count_size(weight(binary), S1),
1354
1357
{update_c_binary(E, Es), S2};
1374
i_bin_seg_pattern(E, Ren, Env, Ren0, Env0, S) ->
1377
i_bitstr_pattern(E, Ren, Env, Ren0, Env0, S) ->
1375
1378
%% It is not necessary to visit the Unit, Type and Flags fields,
1376
1379
%% since these are always literals. The Value field is a limited
1377
1380
%% pattern - either a literal or an unbound variable. The Size field
1378
1381
%% is a limited expression - either a literal or a variable bound in
1379
1382
%% the environment of the containing expression.
1380
{Val, S1} = i_pattern(bin_seg_val(E), Ren, Env, Ren0, Env0, S),
1381
{Size, S2} = i(bin_seg_size(E), value, Ren0, Env0, S1),
1382
Unit = bin_seg_unit(E),
1383
Type = bin_seg_type(E),
1384
Flags = bin_seg_flags(E),
1385
S3 = count_size(weight(bin_seg), S2),
1386
{update_c_bin_seg(E, Val, Size, Unit, Type, Flags), S3}.
1383
{Val, S1} = i_pattern(bitstr_val(E), Ren, Env, Ren0, Env0, S),
1384
{Size, S2} = i(bitstr_size(E), value, Ren0, Env0, S1),
1385
Unit = bitstr_unit(E),
1386
Type = bitstr_type(E),
1387
Flags = bitstr_flags(E),
1388
S3 = count_size(weight(bitstr), S2),
1389
{update_c_bitstr(E, Val, Size, Unit, Type, Flags), S3}.
1389
1392
%% ---------------------------------------------------------------------
2329
2333
C = st__get_effort(S),
2330
2334
C1 = counter__add(N, C, effort, S),
2331
2335
case debug_counters() of
2333
case counter__is_active(C1) of
2335
V = counter__value(C1),
2336
case V > get(counter_effort_max) of
2338
put(counter_effort_max, V);
2337
%% case counter__is_active(C1) of
2339
%% V = counter__value(C1),
2340
%% case V > get(counter_effort_max) of
2342
%% put(counter_effort_max, V);
2348
2352
st__set_effort(C1, S).
2351
2355
C = st__get_size(S),
2352
2356
C1 = counter__add(N, C, size, S),
2353
2357
case debug_counters() of
2355
case counter__is_active(C1) of
2357
V = counter__value(C1),
2358
case V > get(counter_size_max) of
2360
put(counter_size_max, V);
2359
%% case counter__is_active(C1) of
2361
%% V = counter__value(C1),
2362
%% case V > get(counter_size_max) of
2364
%% put(counter_size_max, V);
2370
2374
st__set_size(C1, S).
2535
2538
%% flag whether we are in the process of inlining a propagated
2536
2539
%% functional value. The "pending flags" are really counters limiting
2537
2540
%% the number of times an operand may be inlined recursively, causing
2538
%% loop unrolling; however, unrolling more than one iteration does not
2539
%% work offhand in the present implementation. (TODO: find out why.)
2540
%% Note that the initial value must be greater than zero in order for
2541
%% any inlining at all to be done.
2541
%% loop unrolling. Note that the initial value must be greater than zero
2542
%% in order for any inlining at all to be done.
2543
2544
%% Flags are stored in ETS-tables, one table for each class. The second
2544
2545
%% element in each stored tuple is the key (the "label").
2548
2549
effect = false}).
2549
2550
-record(app_flags, {lab, inlined = false}).
2551
st__new(Effort, Size) ->
2552
st__new(Effort, Size, Unroll) ->
2552
2553
#state{free = 0,
2553
2554
size = counter__new_passive(Size),
2554
effort = counter__new_passive(Effort),
2555
effort = counter__new_passive(Effort),
2555
2557
cache = dict:new(),
2556
2558
var_flags = ets:new(var, [set, private, {keypos, 2}]),
2557
2559
opnd_flags = ets:new(opnd, [set, private, {keypos, 2}]),
2699
2703
if V > 0, N1 =< 0 ->
2700
2704
case debug_counters() of
2704
put(counter_effort_triggers,
2705
get(counter_effort_triggers) + 1);
2707
put(counter_size_triggers,
2708
get(counter_size_triggers) + 1)
2708
%% put(counter_effort_triggers,
2709
%% get(counter_effort_triggers) + 1);
2711
%% put(counter_size_triggers,
2712
%% get(counter_size_triggers) + 1)
2713
2717
throw({counter_exceeded, Type, Data});
2728
2732
report_error(D) ->
2729
2733
report_error(D, []).
2731
report_error({F, L, D}, Vs) ->
2732
report({F, L, {error, D}}, Vs);
2733
2735
report_error(D, Vs) ->
2734
2736
report({error, D}, Vs).
2736
2738
report_warning(D) ->
2737
2739
report_warning(D, []).
2739
report_warning({F, L, D}, Vs) ->
2740
report({F, L, {warning, D}}, Vs);
2741
2741
report_warning(D, Vs) ->
2742
2742
report({warning, D}, Vs).
2756
2756
[io_lib:fwrite("~s:~w: ", [filename(F), L]), format(D, Vs)];
2757
2757
format({F, _L, D}, Vs) ->
2758
2758
[io_lib:fwrite("~s: ", [filename(F)]), format(D, Vs)];
2759
format({_F, _L, D}, Vs) ->
2761
2759
format(S, Vs) when list(S) ->
2762
2760
[io_lib:fwrite(S, Vs), $\n].