1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%% Purpose: Run the Erlang compiler.
21
22-module(compile).
23
24%% High-level interface.
25-export([file/1,file/2,noenv_file/2,format_error/1]).
26-export([forms/1,forms/2,noenv_forms/2]).
27-export([output_generated/1,noenv_output_generated/1]).
28-export([options/0]).
29-export([env_compiler_options/0]).
30
31%% Erlc interface.
32-export([compile/3,compile_asm/3,compile_core/3,compile_abstr/3]).
33
34%% Utility functions for compiler passes.
35-export([run_sub_passes/2]).
36
37-export_type([option/0]).
38-export_type([forms/0]).
39
40-include("erl_compile.hrl").
41-include("core_parse.hrl").
42
43-import(lists, [member/2,reverse/1,reverse/2,keyfind/3,last/1,
44		map/2,flatmap/2,flatten/1,foreach/2,foldr/3,any/2]).
45
46-define(SUB_PASS_TIMES, compile__sub_pass_times).
47
48%%----------------------------------------------------------------------
49
50-type abstract_code() :: [erl_parse:abstract_form()].
51
52%% Internal representations used for 'from_asm' compilation can also be valid,
53%% but have no relevant types defined.
54-type forms() :: abstract_code() | cerl:c_module().
55
56-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
57
58-type error_description() :: erl_lint:error_description().
59-type error_info() :: erl_lint:error_info().
60-type errors()   :: [{file:filename(), [error_info()]}].
61-type warnings() :: [{file:filename(), [error_info()]}].
62-type mod_ret()  :: {'ok', module()}
63                  | {'ok', module(), cerl:c_module()} %% with option 'to_core'
64                  | {'ok',                            %% with option 'to_pp'
65                     module() | [],                   %% module() if 'to_exp'
66                     abstract_code()}
67                  | {'ok', module(), warnings()}.
68-type bin_ret()  :: {'ok', module(), binary()}
69                  | {'ok', module(), binary(), warnings()}.
70-type err_ret()  :: 'error' | {'error', errors(), warnings()}.
71-type comp_ret() :: mod_ret() | bin_ret() | err_ret().
72
73
74%%----------------------------------------------------------------------
75
76%%
77%%  Exported functions
78%%
79
80
81%% file(FileName)
82%% file(FileName, Options)
83%%  Compile the module in file FileName.
84
85-define(DEFAULT_OPTIONS, [verbose,report_errors,report_warnings]).
86
87-spec file(module() | file:filename()) -> comp_ret().
88
89file(File) -> file(File, ?DEFAULT_OPTIONS).
90
91-spec file(module() | file:filename(), [option()] | option()) -> comp_ret().
92
93file(File, Opts) when is_list(Opts) ->
94    do_compile({file,File}, Opts++env_default_opts());
95file(File, Opt) ->
96    file(File, [Opt|?DEFAULT_OPTIONS]).
97
98-spec forms(abstract_code()) -> comp_ret().
99
100forms(Forms) -> forms(Forms, ?DEFAULT_OPTIONS).
101
102-spec forms(forms(), [option()] | option()) -> comp_ret().
103
104forms(Forms, Opts) when is_list(Opts) ->
105    do_compile({forms,Forms}, [binary|Opts++env_default_opts()]);
106forms(Forms, Opt) when is_atom(Opt) ->
107    forms(Forms, [Opt|?DEFAULT_OPTIONS]).
108
109%% Given a list of compilation options, returns true if compile:file/2
110%% would have generated a Beam file, false otherwise (if only a binary or a
111%% listing file would have been generated).
112
113-spec output_generated([option()]) -> boolean().
114
115output_generated(Opts) ->
116    noenv_output_generated(Opts++env_default_opts()).
117
118%%
119%% Variants of the same function that don't consult ERL_COMPILER_OPTIONS
120%% for default options.
121%%
122
123-spec noenv_file(module() | file:filename(), [option()] | option()) -> comp_ret().
124
125noenv_file(File, Opts) when is_list(Opts) ->
126    do_compile({file,File}, Opts);
127noenv_file(File, Opt) ->
128    noenv_file(File, [Opt|?DEFAULT_OPTIONS]).
129
130-spec noenv_forms(forms(), [option()] | option()) -> comp_ret().
131
132noenv_forms(Forms, Opts) when is_list(Opts) ->
133    do_compile({forms,Forms}, [binary|Opts]);
134noenv_forms(Forms, Opt) when is_atom(Opt) ->
135    noenv_forms(Forms, [Opt|?DEFAULT_OPTIONS]).
136
137-spec noenv_output_generated([option()]) -> boolean().
138
139noenv_output_generated(Opts) ->
140    {_,Passes} = passes(file, expand_opts(Opts)),
141    any(fun ({save_binary,_T,_F}) -> true;
142	    (_Other) -> false
143	end, Passes).
144
145%%
146%% Retrieve ERL_COMPILER_OPTIONS as a list of terms
147%%
148
149-spec env_compiler_options() -> [term()].
150
151env_compiler_options() -> env_default_opts().
152
153
154%%%
155%%% Run sub passes from a compiler pass.
156%%%
157
158-spec run_sub_passes([term()], term()) -> term().
159
160run_sub_passes(Ps, St) ->
161    case get(?SUB_PASS_TIMES) of
162        undefined ->
163            Runner = fun(_Name, Run, S) -> Run(S) end,
164            run_sub_passes_1(Ps, Runner, St);
165        Times when is_list(Times) ->
166            Runner = fun(Name, Run, S0) ->
167                             T1 = erlang:monotonic_time(),
168                             S = Run(S0),
169                             T2 = erlang:monotonic_time(),
170                             put(?SUB_PASS_TIMES,
171                                 [{Name,T2-T1}|get(?SUB_PASS_TIMES)]),
172                             S
173                     end,
174            run_sub_passes_1(Ps, Runner, St)
175    end.
176
177%%
178%%  Local functions
179%%
180
181-define(pass(P), {P,fun P/2}).
182-define(pass(P,T), {P,fun T/1,fun P/2}).
183
184env_default_opts() ->
185    Key = "ERL_COMPILER_OPTIONS",
186    case os:getenv(Key) of
187	false -> [];
188	Str when is_list(Str) ->
189	    case erl_scan:string(Str) of
190		{ok,Tokens,_} ->
191                    Dot = {dot, erl_anno:new(1)},
192		    case erl_parse:parse_term(Tokens ++ [Dot]) of
193			{ok,List} when is_list(List) -> List;
194			{ok,Term} -> [Term];
195			{error,_Reason} ->
196			    io:format("Ignoring bad term in ~s\n", [Key]),
197			    []
198		    end;
199		{error, {_,_,_Reason}, _} ->
200		    io:format("Ignoring bad term in ~s\n", [Key]),
201		    []
202	    end
203    end.
204
205do_compile(Input, Opts0) ->
206    Opts = expand_opts(Opts0),
207    IntFun = internal_fun(Input, Opts),
208
209    %% Some tools, like Dialyzer, has already spawned workers
210    %% and spawning extra workers actually slow the compilation
211    %% down instead of speeding it up, so we provide a mechanism
212    %% to bypass the compiler process.
213    case lists:member(no_spawn_compiler_process, Opts) of
214        true ->
215            IntFun();
216        false ->
217            {Pid,Ref} =
218                spawn_monitor(fun() ->
219                                      exit(IntFun())
220                              end),
221            receive
222                {'DOWN',Ref,process,Pid,Rep} -> Rep
223            end
224    end.
225
226internal_fun(Input, Opts) ->
227    fun() ->
228            try
229                internal(Input, Opts)
230            catch
231                Class:Reason:Stk ->
232                    internal_error(Class, Reason, Stk)
233            end
234    end.
235
236internal_error(Class, Reason, Stk) ->
237    Error = ["\n*** Internal compiler error ***\n",
238             format_error_reason(Class, Reason, Stk),
239             "\n"],
240    io:put_chars(Error),
241    error.
242
243expand_opts(Opts0) ->
244    %% {debug_info_key,Key} implies debug_info.
245    Opts = case {proplists:get_value(debug_info_key, Opts0),
246		 proplists:get_value(encrypt_debug_info, Opts0),
247		 proplists:get_value(debug_info, Opts0)} of
248	       {undefined,undefined,_} -> Opts0;
249	       {_,_,undefined} -> [debug_info|Opts0];
250	       {_,_,_} -> Opts0
251	   end,
252    %% iff,unless processing is to complex...
253    Opts1 = case proplists:is_defined(makedep_side_effect,Opts) of
254                true -> proplists:delete(makedep,Opts);
255                false -> Opts
256            end,
257    foldr(fun expand_opt/2, [], Opts1).
258
259expand_opt(basic_validation, Os) ->
260    [no_code_generation,to_pp,binary|Os];
261expand_opt(strong_validation, Os) ->
262    [no_code_generation,to_kernel,binary|Os];
263expand_opt(report, Os) ->
264    [report_errors,report_warnings|Os];
265expand_opt(return, Os) ->
266    [return_errors,return_warnings|Os];
267expand_opt(no_bsm3, Os) ->
268    %% The new bsm pass requires bsm3 instructions.
269    [no_bsm3,no_bsm_opt|expand_opt(no_bsm4, Os)];
270expand_opt(no_bsm4, Os) ->
271    %% bsm4 instructions are only used when type optimization has determined
272    %% that a match instruction won't fail.
273    expand_opt(no_type_opt, Os);
274expand_opt(r18, Os) ->
275    expand_opt_before_21(Os);
276expand_opt(r19, Os) ->
277    expand_opt_before_21(Os);
278expand_opt(r20, Os) ->
279    expand_opt_before_21(Os);
280expand_opt(r21, Os) ->
281    expand_opt(r22, [no_put_tuple2 | expand_opt(no_bsm3, Os)]);
282expand_opt(r22, Os) ->
283    expand_opt(r23, [no_shared_fun_wrappers, no_swap | expand_opt(no_bsm4, Os)]);
284expand_opt(r23, Os) ->
285    expand_opt(no_make_fun3, [no_ssa_opt_float, no_recv_opt, no_init_yregs | Os]);
286expand_opt(no_make_fun3, Os) ->
287    [no_make_fun3, no_fun_opt | Os];
288expand_opt({debug_info_key,_}=O, Os) ->
289    [encrypt_debug_info,O|Os];
290expand_opt(no_type_opt=O, Os) ->
291    %% Be sure to keep the no_type_opt option so that it will
292    %% be recorded in the BEAM file, allowing the test suites
293    %% to recompile the file with this option.
294    [O,no_ssa_opt_type_start,
295     no_ssa_opt_type_continue,
296     no_ssa_opt_type_finish | Os];
297expand_opt(no_module_opt=O, Os) ->
298    [O,no_recv_opt | Os];
299expand_opt(O, Os) -> [O|Os].
300
301expand_opt_before_21(Os) ->
302    [no_init_yregs, no_make_fun3, no_fun_opt,
303     no_shared_fun_wrappers, no_swap,
304     no_put_tuple2, no_get_hd_tl, no_ssa_opt_record,
305     no_utf8_atoms, no_recv_opt | expand_opt(no_bsm3, Os)].
306
307
308-spec format_error(error_description()) -> iolist().
309
310format_error(no_crypto) ->
311    "this system is not configured with crypto support.";
312format_error(bad_crypto_key) ->
313    "invalid crypto key.";
314format_error(no_crypto_key) ->
315    "no crypto key supplied.";
316format_error({open,E}) ->
317    io_lib:format("open error '~ts'", [file:format_error(E)]);
318format_error({epp,E}) ->
319    epp:format_error(E);
320format_error(write_error) ->
321    "error writing file";
322format_error({write_error, Error}) ->
323    io_lib:format("error writing file: ~ts", [file:format_error(Error)]);
324format_error({rename,From,To,Error}) ->
325    io_lib:format("failed to rename ~ts to ~ts: ~ts",
326		  [From,To,file:format_error(Error)]);
327format_error({parse_transform,M,{C,R,Stk}}) ->
328    E = format_error_reason(C, R, Stk),
329    io_lib:format("error in parse transform '~ts':\n~ts", [M, E]);
330format_error({undef_parse_transform,M}) ->
331    io_lib:format("undefined parse transform '~ts'", [M]);
332format_error({core_transform,M,{C,R,Stk}}) ->
333    E = format_error_reason(C, R, Stk),
334    io_lib:format("error in core transform '~s':\n~ts", [M, E]);
335format_error({crash,Pass,Reason,Stk}) ->
336    io_lib:format("internal error in pass ~p:\n~ts", [Pass,format_error_reason({Reason, Stk})]);
337format_error({bad_return,Pass,Reason}) ->
338    io_lib:format("internal error in pass ~p: bad return value:\n~tP", [Pass,Reason,20]);
339format_error({module_name,Mod,Filename}) ->
340    io_lib:format("Module name '~s' does not match file name '~ts'", [Mod,Filename]).
341
342format_error_reason({Reason, Stack}) when is_list(Stack) ->
343    format_error_reason(error, Reason, Stack).
344
345format_error_reason(Class, Reason, Stack) ->
346    StackFun = fun
347	(escript, run,      2) -> true;
348	(escript, start,    1) -> true;
349	(init,    start_it, 1) -> true;
350	(init,    start_em, 1) -> true;
351	(_Mod, _Fun, _Arity)   -> false
352    end,
353    FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end,
354    Opts = #{stack_trim_fun => StackFun,
355             format_fun => FormatFun},
356    erl_error:format_exception(Class, Reason, Stack, Opts).
357
358%% The compile state record.
359-record(compile, {filename="" :: file:filename(),
360		  dir=""      :: file:filename(),
361		  base=""     :: file:filename(),
362		  ifile=""    :: file:filename(),
363		  ofile=""    :: file:filename(),
364		  module=[]   :: module() | [],
365		  abstract_code=[] :: abstract_code(), %Abstract code for debugger.
366		  options=[]  :: [option()],  %Options for compilation
367		  mod_options=[]  :: [option()], %Options for module_info
368                  encoding=none :: none | epp:source_encoding(),
369		  errors=[]     :: errors(),
370		  warnings=[]   :: warnings(),
371		  extra_chunks=[] :: [{binary(), binary()}]}).
372
373internal({forms,Forms}, Opts0) ->
374    {_,Ps} = passes(forms, Opts0),
375    Source = proplists:get_value(source, Opts0, ""),
376    Opts1 = proplists:delete(source, Opts0),
377    Compile = build_compile(Opts1),
378    NewForms = case with_columns(Opts0) of
379                   true ->
380                       Forms;
381                   false ->
382                       strip_columns(Forms)
383               end,
384    internal_comp(Ps, NewForms, Source, "", Compile);
385internal({file,File}, Opts) ->
386    {Ext,Ps} = passes(file, Opts),
387    Compile = build_compile(Opts),
388    internal_comp(Ps, none, File, Ext, Compile).
389
390build_compile(Opts0) ->
391    ExtraChunks = proplists:get_value(extra_chunks, Opts0, []),
392    Opts1 = proplists:delete(extra_chunks, Opts0),
393    #compile{options=Opts1,mod_options=Opts1,extra_chunks=ExtraChunks}.
394
395internal_comp(Passes, Code0, File, Suffix, St0) ->
396    Dir = filename:dirname(File),
397    Base = filename:basename(File, Suffix),
398    St1 = St0#compile{filename=File, dir=Dir, base=Base,
399		      ifile=erlfile(Dir, Base, Suffix),
400		      ofile=objfile(Base, St0)},
401    Run = runner(File, St1),
402    case fold_comp(Passes, Run, Code0, St1) of
403        {ok,Code,St2} -> comp_ret_ok(Code, St2);
404        {error,St2} -> comp_ret_err(St2)
405    end.
406
407fold_comp([{delay,Ps0}|Passes], Run, Code, #compile{options=Opts}=St) ->
408    Ps = select_passes(Ps0, Opts) ++ Passes,
409    fold_comp(Ps, Run, Code, St);
410fold_comp([{Name,Test,Pass}|Ps], Run, Code, St) ->
411    case Test(St) of
412	false ->				%Pass is not needed.
413	    fold_comp(Ps, Run, Code, St);
414	true ->					%Run pass in the usual way.
415	    fold_comp([{Name,Pass}|Ps], Run, Code, St)
416    end;
417fold_comp([{Name,Pass}|Ps], Run, Code0, St0) ->
418    try Run({Name,Pass}, Code0, St0) of
419	{ok,Code,St1} ->
420            fold_comp(Ps, Run, Code, St1);
421	{error,_St1}=Error ->
422            Error
423    catch
424        error:Reason:Stk ->
425	    Es = [{St0#compile.ifile,[{none,?MODULE,{crash,Name,Reason,Stk}}]}],
426	    {error,St0#compile{errors=St0#compile.errors ++ Es}}
427    end;
428fold_comp([], _Run, Code, St) -> {ok,Code,St}.
429
430run_sub_passes_1([{Name,Run}|Ps], Runner, St0)
431  when is_atom(Name), is_function(Run, 1) ->
432    try Runner(Name, Run, St0) of
433        St ->
434            run_sub_passes_1(Ps, Runner, St)
435    catch
436        C:E:Stk ->
437            io:format("Sub pass ~s\n", [Name]),
438            erlang:raise(C, E, Stk)
439    end;
440run_sub_passes_1([], _, St) -> St.
441
442runner(File, #compile{options=Opts}) ->
443    Run0 = fun({_Name,Fun}, Code, St) ->
444                   Fun(Code, St)
445           end,
446    Run1 = case member(time, Opts) of
447               true  ->
448                   case File of
449                       none -> ok;
450                       _ -> io:format("Compiling ~ts\n", [File])
451                   end,
452                   fun run_tc/3;
453               false ->
454                   Run0
455           end,
456    case keyfind(eprof, 1, Opts) of
457        {eprof,EprofPass} ->
458            fun(P, Code, St) ->
459                    run_eprof(P, Code, EprofPass, St)
460            end;
461        false ->
462            Run1
463    end.
464
465run_tc({Name,Fun}, Code, St) ->
466    OldTimes = put(?SUB_PASS_TIMES, []),
467    T1 = erlang:monotonic_time(),
468    Val = Fun(Code, St),
469    T2 = erlang:monotonic_time(),
470    Times = get(?SUB_PASS_TIMES),
471    case OldTimes of
472        undefined -> erase(?SUB_PASS_TIMES);
473        _ -> put(?SUB_PASS_TIMES, OldTimes)
474    end,
475    Elapsed = erlang:convert_time_unit(T2 - T1, native, microsecond),
476    Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize),
477    Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])),
478    io:format(" ~-30s: ~10.3f s ~12s\n",
479	      [Name,Elapsed/1000000,Mem]),
480    print_times(Times, Name),
481    Val.
482
483print_times(Times0, Name) ->
484    Fam0 = rel2fam(Times0),
485    Fam1 = [{W,lists:sum(Times)} || {W,Times} <- Fam0],
486    Fam = reverse(lists:keysort(2, Fam1)),
487    Total = case lists:sum([T || {_,T} <- Fam]) of
488                0 -> 1;
489                Total0 -> Total0
490            end,
491    case Fam of
492        [] ->
493            ok;
494        [_|_] ->
495            io:format("    %% Sub passes of ~s from slowest to fastest:\n", [Name]),
496            print_times_1(Fam, Total)
497    end.
498
499print_times_1([{Name,T}|Ts], Total) ->
500    Elapsed = erlang:convert_time_unit(T, native, microsecond),
501    io:format("    ~-27s: ~10.3f s ~3w %\n",
502              [Name,Elapsed/1000000,round(100*T/Total)]),
503    print_times_1(Ts, Total);
504print_times_1([], _Total) -> ok.
505
506run_eprof({Name,Fun}, Code, Name, St) ->
507    io:format("~p: Running eprof\n", [Name]),
508    c:appcall(tools, eprof, start_profiling, [[self()]]),
509    try
510        Fun(Code, St)
511    after
512        c:appcall(tools, eprof, stop_profiling, []),
513        c:appcall(tools, eprof, analyze, [])
514    end;
515run_eprof({_,Fun}, Code, _, St) ->
516    Fun(Code, St).
517
518comp_ret_ok(Code, #compile{warnings=Warn0,module=Mod,options=Opts}=St) ->
519    Warn1 = filter_warnings(Warn0, Opts),
520    case werror(St) of
521        true ->
522            case member(report_warnings, Opts) of
523                true ->
524		    io:format("~p: warnings being treated as errors\n",
525			      [?MODULE]);
526                false ->
527		    ok
528            end,
529            comp_ret_err(St);
530        false ->
531            Warn = messages_per_file(Warn1),
532            report_warnings(St#compile{warnings = Warn}),
533            Ret1 = case member(binary, Opts) andalso
534		       not member(no_code_generation, Opts) of
535                       true -> [Code];
536                       false -> []
537                   end,
538            Ret2 = case member(return_warnings, Opts) of
539                       true -> Ret1 ++ [Warn];
540                       false -> Ret1
541                   end,
542            list_to_tuple([ok,Mod|Ret2])
543    end.
544
545comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) ->
546    Warn = messages_per_file(Warn0),
547    Err = messages_per_file(Err0),
548    report_errors(St#compile{errors=Err}),
549    report_warnings(St#compile{warnings=Warn}),
550    case member(return_errors, Opts) of
551	true -> {error,Err,Warn};
552	false -> error
553    end.
554
555not_werror(St) -> not werror(St).
556
557werror(#compile{options=Opts,warnings=Ws}) ->
558    Ws =/= [] andalso member(warnings_as_errors, Opts).
559
560%% messages_per_file([{File,[Message]}]) -> [{File,[Message]}]
561messages_per_file(Ms) ->
562    T = lists:sort([{File,M} || {File,Messages} <- Ms, M <- Messages]),
563    PrioMs = [erl_scan, epp, erl_parse],
564    {Prio0, Rest} =
565        lists:mapfoldl(fun(M, A) ->
566                               lists:partition(fun({_,{_,Mod,_}}) -> Mod =:= M;
567                                                  (_) -> false
568                                               end, A)
569                       end, T, PrioMs),
570    Prio = lists:sort(fun({_,{L1,_,_}}, {_,{L2,_,_}}) -> L1 =< L2 end,
571                      lists:append(Prio0)),
572    flatmap(fun mpf/1, [Prio, Rest]).
573
574mpf(Ms) ->
575    [{File,[M || {F,M} <- Ms, F =:= File]} ||
576	File <- lists:usort([F || {F,_} <- Ms])].
577
578%% passes(forms|file, [Option]) -> {Extension,[{Name,PassFun}]}
579%%  Figure out the extension of the input file and which passes
580%%  that need to be run.
581
582passes(Type, Opts) ->
583    {Ext,Passes0} = passes_1(Opts),
584
585    Passes1 = case Type of
586                  file ->
587                      Passes0;
588                  forms ->
589                      fix_first_pass(Passes0)
590              end,
591
592    Passes2 = select_passes(Passes1, Opts),
593
594    %% If the last pass saves the resulting binary to a file,
595    %% insert a first pass to remove the file.
596    Passes = case last(Passes2) of
597                 {save_binary, _TestFun, _Fun} ->
598                     [?pass(remove_file) | Passes2];
599                 _ ->
600                     Passes2
601             end,
602
603    {Ext, Passes}.
604
605passes_1([Opt|Opts]) ->
606    case pass(Opt) of
607	{_,_}=Res -> Res;
608	none -> passes_1(Opts)
609    end;
610passes_1([]) ->
611    {".erl",[?pass(parse_module)|standard_passes()]}.
612
613pass(from_abstr) ->
614    {".abstr", [?pass(consult_abstr) | abstr_passes(non_verified_abstr)]};
615pass(from_core) ->
616    {".core",[?pass(parse_core)|core_passes(non_verified_core)]};
617pass(from_asm) ->
618    {".S",[?pass(beam_consult_asm)|asm_passes()]};
619pass(_) -> none.
620
621%% For compilation from forms, replace the first pass with a pass
622%% that retrieves the module name. The module name is needed for
623%% proper diagnostics.
624
625fix_first_pass([{consult_abstr, _} | Passes]) ->
626    %% Simply remove this pass. The module name will be set after
627    %% running the v3_core pass.
628    Passes;
629fix_first_pass([{parse_core,_}|Passes]) ->
630    [?pass(get_module_name_from_core)|Passes];
631fix_first_pass([{beam_consult_asm,_}|Passes]) ->
632    [?pass(get_module_name_from_asm)|Passes];
633fix_first_pass([_|Passes]) ->
634    %% When compiling from abstract code, the module name
635    %% will be set after running the v3_core pass.
636    Passes.
637
638
639%% select_passes([Command], Opts) -> [{Name,Function}]
640%%  Interpret the lists of commands to return a pure list of passes.
641%%
642%%  Command can be one of:
643%%
644%%    {pass,Mod}	Will be expanded to a call to the external
645%%			function Mod:module(Code, Options).  This
646%%			function must transform the code and return
647%%			{ok,NewCode} or {ok,NewCode,Warnings}.
648%%			Example: {pass,beam_ssa_codegen}
649%%
650%%    {Name,Fun}	Name is an atom giving the name of the pass.
651%%    			Fun is an 'fun' taking one argument: a #compile{} record.
652%%			The fun should return {ok,NewCompileRecord} or
653%%			{error,NewCompileRecord}.
654%%			Note: ?pass(Name) is equvivalent to {Name,fun Name/1}.
655%%			Example: ?pass(parse_module)
656%%
657%%    {Name,Test,Fun}	Like {Name,Fun} above, but the pass will be run
658%%			(and listed by the `time' option) only if Test(St)
659%%			returns true.
660%%
661%%    {src_listing,Ext}	Produces an Erlang source listing with the
662%%			the file extension Ext.  (Ext should not contain
663%%			a period.)  No more passes will be run.
664%%
665%%    {listing,Ext}	Produce an listing of the terms in the internal
666%%			representation.  The extension of the listing
667%%			file will be Ext.  (Ext should not contain
668%%			a period.)   No more passes will be run.
669%%
670%%    done              End compilation at this point.
671%%
672%%    {done,Ext}        End compilation at this point. Produce a listing
673%%                      as with {listing,Ext}, unless 'binary' is
674%%                      specified, in which case the current
675%%                      representation of the code is returned without
676%%                      creating an output file.
677%%
678%%    {iff,Flag,Cmd}	If the given Flag is given in the option list,
679%%			Cmd will be interpreted as a command.
680%%			Otherwise, Cmd will be ignored.
681%%			Example: {iff,dcg,{listing,"codegen}}
682%%
683%%    {unless,Flag,Cmd}	If the given Flag is NOT given in the option list,
684%%			Cmd will be interpreted as a command.
685%%			Otherwise, Cmd will be ignored.
686%%			Example: {unless,no_kernopt,{pass,sys_kernopt}}
687%%
688
689select_passes([{pass,Mod}|Ps], Opts) ->
690    F = fun(Code0, St) ->
691		case Mod:module(Code0, St#compile.options) of
692		    {ok,Code} ->
693			{ok,Code,St};
694		    {ok,Code,Ws} ->
695			{ok,Code,St#compile{warnings=St#compile.warnings++Ws}};
696                    Other ->
697                        Es = [{St#compile.ifile,[{none,?MODULE,{bad_return,Mod,Other}}]}],
698                        {error,St#compile{errors=St#compile.errors ++ Es}}
699		end
700	end,
701    [{Mod,F}|select_passes(Ps, Opts)];
702select_passes([{_,Fun}=P|Ps], Opts) when is_function(Fun) ->
703    [P|select_passes(Ps, Opts)];
704select_passes([{_,Test,Fun}=P|Ps], Opts) when is_function(Test),
705					      is_function(Fun) ->
706    [P|select_passes(Ps, Opts)];
707select_passes([{src_listing,Ext}|_], _Opts) ->
708    [{listing,fun (Code, St) -> src_listing(Ext, Code, St) end}];
709select_passes([{listing,Ext}|_], _Opts) ->
710    [{listing,fun (Code, St) -> listing(Ext, Code, St) end}];
711select_passes([done|_], _Opts) ->
712    [];
713select_passes([{done,Ext}|_], Opts) ->
714    select_passes([{unless,binary,{listing,Ext}}], Opts);
715select_passes([{iff,Flag,Pass}|Ps], Opts) ->
716    select_cond(Flag, true, Pass, Ps, Opts);
717select_passes([{unless,Flag,Pass}|Ps], Opts) ->
718    select_cond(Flag, false, Pass, Ps, Opts);
719select_passes([{delay,Passes0}|Ps], Opts) when is_list(Passes0) ->
720    %% Delay evaluation of compiler options and which compiler passes to run.
721    %% Since we must know beforehand whether a listing will be produced, we
722    %% will go through the list of passes and evaluate all conditions that
723    %% select a list pass.
724    case select_list_passes(Passes0, Opts) of
725	{done,Passes} ->
726	    [{delay,Passes}];
727	{not_done,Passes} ->
728	    [{delay,Passes}|select_passes(Ps, Opts)]
729    end;
730select_passes([], _Opts) ->
731    [];
732select_passes([List|Ps], Opts) when is_list(List) ->
733    case select_passes(List, Opts) of
734	[] -> select_passes(Ps, Opts);
735	Nested ->
736	    case last(Nested) of
737		{listing,_Fun} -> Nested;
738		_Other         -> Nested ++ select_passes(Ps, Opts)
739	    end
740    end.
741
742select_cond(Flag, ShouldBe, Pass, Ps, Opts) ->
743    ShouldNotBe = not ShouldBe,
744    case member(Flag, Opts) of
745	ShouldBe    -> select_passes([Pass|Ps], Opts);
746	ShouldNotBe -> select_passes(Ps, Opts)
747    end.
748
749%% select_list_passes([Pass], Opts) -> {done,[Pass]} | {not_done,[Pass]}
750%%  Evaluate all conditions having to do with listings in the list of
751%%  passes.
752
753select_list_passes(Ps, Opts) ->
754    select_list_passes_1(Ps, Opts, []).
755
756select_list_passes_1([{iff,Flag,{listing,_}=Listing}|Ps], Opts, Acc) ->
757    case member(Flag, Opts) of
758	true -> {done,reverse(Acc, [Listing])};
759	false -> select_list_passes_1(Ps, Opts, Acc)
760    end;
761select_list_passes_1([{iff,Flag,{done,Ext}}|Ps], Opts, Acc) ->
762    case member(Flag, Opts) of
763	false ->
764	    select_list_passes_1(Ps, Opts, Acc);
765	true ->
766	    {done,case member(binary, Opts) of
767		      false -> reverse(Acc, [{listing,Ext}]);
768		      true -> reverse(Acc)
769		  end}
770    end;
771select_list_passes_1([{iff=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
772    case select_list_passes(List0, Opts) of
773	{done,List} -> {done,reverse(Acc) ++ List};
774	{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
775    end;
776select_list_passes_1([{unless=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
777    case select_list_passes(List0, Opts) of
778	{done,List} -> {done,reverse(Acc) ++ List};
779	{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
780    end;
781select_list_passes_1([P|Ps], Opts, Acc) ->
782    select_list_passes_1(Ps, Opts, [P|Acc]);
783select_list_passes_1([], _, Acc) ->
784    {not_done,reverse(Acc)}.
785
786%% The standard passes (almost) always run.
787
788standard_passes() ->
789    [?pass(transform_module),
790
791     {iff,makedep_side_effect,?pass(makedep_and_output)},
792     {iff,makedep,[
793	 ?pass(makedep),
794	 {unless,binary,?pass(makedep_output)}
795       ]},
796     {iff,makedep,done},
797
798     {iff,'dpp',{listing,"pp"}},
799     ?pass(lint_module),
800
801     {iff,'P',{src_listing,"P"}},
802     {iff,'to_pp',{done,"P"}},
803
804     {iff,'dabstr',{listing,"abstr"}}
805     | abstr_passes(verified_abstr)].
806
807abstr_passes(AbstrStatus) ->
808    case AbstrStatus of
809        non_verified_abstr -> [{unless, no_lint, ?pass(lint_module)}];
810        verified_abstr -> []
811    end ++
812        [
813         %% Add all -compile() directives to #compile.options
814         ?pass(compile_directives),
815
816         {delay,[{iff,debug_info,?pass(save_abstract_code)}]},
817
818         ?pass(expand_records),
819         {iff,'dexp',{listing,"expand"}},
820         {iff,'E',{src_listing,"E"}},
821         {iff,'to_exp',{done,"E"}},
822
823         %% Conversion to Core Erlang.
824         ?pass(core),
825         {iff,'dcore',{listing,"core"}},
826         {iff,'to_core0',{done,"core"}}
827         | core_passes(verified_core)].
828
829core_passes(CoreStatus) ->
830    %% Optimization and transforms of Core Erlang code.
831    case CoreStatus of
832        non_verified_core ->
833            [?pass(core_lint_module),
834             {unless,no_core_prepare,{pass,sys_core_prepare}},
835             {iff,dprep,{listing,"prepare"}}];
836        verified_core ->
837            [{iff,clint0,?pass(core_lint_module)}]
838    end ++
839        [
840         {delay,
841          [{unless,no_copt,
842            [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/2},
843             {iff,doldinline,{listing,"oldinline"}},
844             {unless,no_fold,{pass,sys_core_fold}},
845             {iff,dcorefold,{listing,"corefold"}},
846             {core_inline_module,fun test_core_inliner/1,fun core_inline_module/2},
847             {iff,dinline,{listing,"inline"}},
848             {core_fold_after_inlining,fun test_any_inliner/1,
849              fun core_fold_module_after_inlining/2},
850             {iff,dcopt,{listing,"copt"}},
851             {unless,no_alias,{pass,sys_core_alias}},
852             {iff,dalias,{listing,"core_alias"}},
853             ?pass(core_transforms)]},
854           {iff,'to_core',{done,"core"}}]}
855         | kernel_passes()].
856
857kernel_passes() ->
858    %% Optimizations that must be done after all other optimizations.
859    [{pass,sys_core_bsm},
860     {iff,dcbsm,{listing,"core_bsm"}},
861
862     {iff,clint,?pass(core_lint_module)},
863
864     %% Kernel Erlang and code generation.
865     ?pass(v3_kernel),
866     {iff,dkern,{listing,"kernel"}},
867     {iff,'to_kernel',{done,"kernel"}},
868     {pass,beam_kernel_to_ssa},
869     {iff,dssa,{listing,"ssa"}},
870     {iff,ssalint,{pass,beam_ssa_lint}},
871     {delay,
872      [{unless,no_bool_opt,{pass,beam_ssa_bool}},
873       {iff,dbool,{listing,"bool"}},
874       {unless,no_bool_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
875
876       {unless,no_share_opt,{pass,beam_ssa_share}},
877       {iff,dssashare,{listing,"ssashare"}},
878       {unless,no_share_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
879
880       {unless,no_recv_opt,{pass,beam_ssa_recv}},
881       {iff,drecv,{listing,"recv"}},
882       {unless,no_recv_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
883
884       {unless,no_bsm_opt,{pass,beam_ssa_bsm}},
885       {iff,dssabsm,{listing,"ssabsm"}},
886       {unless,no_bsm_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
887
888       {unless,no_fun_opt,{pass,beam_ssa_funs}},
889       {iff,dssafuns,{listing,"ssafuns"}},
890       {unless,no_fun_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
891
892       {unless,no_ssa_opt,{pass,beam_ssa_opt}},
893       {iff,dssaopt,{listing,"ssaopt"}},
894       {unless,no_ssa_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
895
896       {unless,no_throw_opt,{pass,beam_ssa_throw}},
897       {iff,dthrow,{listing,"throw"}},
898       {unless,no_throw_opt,{iff,ssalint,{pass,beam_ssa_lint}}}]},
899
900     {pass,beam_ssa_pre_codegen},
901     {iff,dprecg,{listing,"precodegen"}},
902     {iff,ssalint,{pass,beam_ssa_lint}},
903     {pass,beam_ssa_codegen},
904     {iff,dcg,{listing,"codegen"}},
905     {iff,doldcg,{listing,"codegen"}},
906     ?pass(beam_validator_strong)
907     | asm_passes()].
908
909asm_passes() ->
910    %% Assembly level optimisations.
911    [{delay,
912      [{pass,beam_a},
913       {iff,da,{listing,"a"}},
914       {unless,no_postopt,
915	[{pass,beam_block},
916	 {iff,dblk,{listing,"block"}},
917	 {unless,no_jopt,{pass,beam_jump}},
918	 {iff,djmp,{listing,"jump"}},
919	 {unless,no_peep_opt,{pass,beam_peep}},
920	 {iff,dpeep,{listing,"peep"}},
921	 {pass,beam_clean},
922	 {iff,dclean,{listing,"clean"}},
923	 {unless,no_stack_trimming,{pass,beam_trim}},
924	 {iff,dtrim,{listing,"trim"}},
925	 {pass,beam_flatten}]},
926
927       %% If post optimizations are turned off, we still
928       %% need to do a few clean-ups to code.
929       {iff,no_postopt,[{pass,beam_clean}]},
930
931       {iff,diffable,?pass(diffable)},
932       {pass,beam_z},
933       {iff,diffable,{listing,"S"}},
934       {iff,dz,{listing,"z"}},
935       {iff,dopt,{listing,"optimize"}},
936       {iff,'S',{listing,"S"}},
937       {iff,'to_asm',{done,"S"}}]},
938     ?pass(beam_validator_weak),
939     ?pass(beam_asm)
940     | binary_passes()].
941
942binary_passes() ->
943    [{iff,'to_dis',?pass(to_dis)},
944     {unless,binary,?pass(save_binary,not_werror)}
945    ].
946
947%%%
948%%% Compiler passes.
949%%%
950
951%% Remove the target file so we don't have an old one if the compilation fail.
952remove_file(Code, St) ->
953    _ = file:delete(St#compile.ofile),
954    {ok,Code,St}.
955
956-record(asm_module, {module,
957		     exports,
958		     labels,
959		     functions=[],
960		     attributes=[]}).
961
962preprocess_asm_forms(Forms) ->
963    R = #asm_module{},
964    R1 = collect_asm(Forms, R),
965    {R1#asm_module.module,
966     {R1#asm_module.module,
967      R1#asm_module.exports,
968      R1#asm_module.attributes,
969      reverse(R1#asm_module.functions),
970      R1#asm_module.labels}}.
971
972collect_asm([{module,M} | Rest], R) ->
973    collect_asm(Rest, R#asm_module{module=M});
974collect_asm([{exports,M} | Rest], R) ->
975    collect_asm(Rest, R#asm_module{exports=M});
976collect_asm([{labels,M} | Rest], R) ->
977    collect_asm(Rest, R#asm_module{labels=M});
978collect_asm([{function,A,B,C} | Rest0], R0) ->
979    {Code,Rest} = collect_asm_function(Rest0, []),
980    Func = {function,A,B,C,Code},
981    R = R0#asm_module{functions=[Func | R0#asm_module.functions]},
982    collect_asm(Rest, R);
983collect_asm([{attributes, Attr} | Rest], R) ->
984    collect_asm(Rest, R#asm_module{attributes=Attr});
985collect_asm([], R) -> R.
986
987collect_asm_function([{function,_,_,_}|_]=Is, Acc) ->
988    {reverse(Acc),Is};
989collect_asm_function([I|Is], Acc) ->
990    collect_asm_function(Is, [I|Acc]);
991collect_asm_function([], Acc) ->
992    {reverse(Acc),[]}.
993
994beam_consult_asm(_Code, St) ->
995    case file:consult(St#compile.ifile) of
996	{ok,Forms0} ->
997            Encoding = epp:read_encoding(St#compile.ifile),
998	    {Module,Forms} = preprocess_asm_forms(Forms0),
999	    {ok,Forms,St#compile{module=Module,encoding=Encoding}};
1000	{error,E} ->
1001	    Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
1002	    {error,St#compile{errors=St#compile.errors ++ Es}}
1003    end.
1004
1005get_module_name_from_asm({Mod,_,_,_,_}=Asm, St) ->
1006    {ok,Asm,St#compile{module=Mod}};
1007get_module_name_from_asm(Asm, St) ->
1008    %% Invalid Beam assembly code. Let it crash in a later pass.
1009    {ok,Asm,St}.
1010
1011parse_module(_Code, St) ->
1012    case do_parse_module(utf8, St) of
1013	{ok,_,_}=Ret ->
1014	    Ret;
1015	{error,_}=Ret ->
1016	    Ret
1017    end.
1018
1019do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
1020    SourceName0 = proplists:get_value(source, Opts, File),
1021    SourceName = case member(deterministic, Opts) of
1022                     true -> filename:basename(SourceName0);
1023                     false -> SourceName0
1024                 end,
1025    StartLocation = case with_columns(Opts) of
1026                        true ->
1027                            {1,1};
1028                        false ->
1029                            1
1030                    end,
1031    R = epp:parse_file(File,
1032                       [{includes,[".",Dir|inc_paths(Opts)]},
1033                        {source_name, SourceName},
1034                        {macros,pre_defs(Opts)},
1035                        {default_encoding,DefEncoding},
1036                        {location,StartLocation},
1037                        extra]),
1038    case R of
1039	{ok,Forms0,Extra} ->
1040	    Encoding = proplists:get_value(encoding, Extra),
1041            Forms = case with_columns(Opts ++ compile_options(Forms0)) of
1042                        true ->
1043                            Forms0;
1044                        false ->
1045                            strip_columns(Forms0)
1046                    end,
1047            {ok,Forms,St#compile{encoding=Encoding}};
1048	{error,E} ->
1049	    Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}],
1050	    {error,St#compile{errors=St#compile.errors ++ Es}}
1051    end.
1052
1053with_columns(Opts) ->
1054    case proplists:get_value(error_location, Opts, column) of
1055        column -> true;
1056        line -> false
1057    end.
1058
1059consult_abstr(_Code, St) ->
1060    case file:consult(St#compile.ifile) of
1061	{ok,Forms} ->
1062            Encoding = epp:read_encoding(St#compile.ifile),
1063	    {ok,Forms,St#compile{encoding=Encoding}};
1064	{error,E} ->
1065	    Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
1066	    {error,St#compile{errors=St#compile.errors ++ Es}}
1067    end.
1068
1069parse_core(_Code, St) ->
1070    case file:read_file(St#compile.ifile) of
1071	{ok,Bin} ->
1072	    case core_scan:string(binary_to_list(Bin)) of
1073		{ok,Toks,_} ->
1074		    case core_parse:parse(Toks) of
1075			{ok,Mod} ->
1076			    Name = (Mod#c_module.name)#c_literal.val,
1077			    {ok,Mod,St#compile{module=Name}};
1078			{error,E} ->
1079			    Es = [{St#compile.ifile,[E]}],
1080			    {error,St#compile{errors=St#compile.errors ++ Es}}
1081		    end;
1082		{error,E,_} ->
1083		    Es = [{St#compile.ifile,[E]}],
1084		    {error,St#compile{errors=St#compile.errors ++ Es}}
1085	    end;
1086	{error,E} ->
1087	    Es = [{St#compile.ifile,[{none,compile,{open,E}}]}],
1088	    {error,St#compile{errors=St#compile.errors ++ Es}}
1089    end.
1090
1091get_module_name_from_core(Core, St) ->
1092    try
1093        Mod = cerl:concrete(cerl:module_name(Core)),
1094        {ok,Core,St#compile{module=Mod}}
1095    catch
1096        _:_ ->
1097            %% Invalid Core Erlang code. Let it crash in a later pass.
1098            {ok,Core,St}
1099    end.
1100
1101compile_options([{attribute,_L,compile,C}|Fs]) when is_list(C) ->
1102    C ++ compile_options(Fs);
1103compile_options([{attribute,_L,compile,C}|Fs]) ->
1104    [C|compile_options(Fs)];
1105compile_options([_F|Fs]) -> compile_options(Fs);
1106compile_options([]) -> [].
1107
1108clean_parse_transforms(Fs) ->
1109    clean_parse_transforms_1(Fs, []).
1110
1111clean_parse_transforms_1([{attribute,L,compile,C0}|Fs], Acc) when is_list(C0) ->
1112    C = lists:filter(fun({parse_transform,_}) -> false;
1113			(_) -> true
1114		     end, C0),
1115    clean_parse_transforms_1(Fs, [{attribute,L,compile,C}|Acc]);
1116clean_parse_transforms_1([{attribute,_,compile,{parse_transform,_}}|Fs], Acc) ->
1117    clean_parse_transforms_1(Fs, Acc);
1118clean_parse_transforms_1([F|Fs], Acc) ->
1119    clean_parse_transforms_1(Fs, [F|Acc]);
1120clean_parse_transforms_1([], Acc) -> reverse(Acc).
1121
1122transforms(Os) -> [ M || {parse_transform,M} <- Os ].
1123
1124transform_module(Code0, #compile{options=Opt}=St) ->
1125    %% Extract compile options from code into options field.
1126    case transforms(Opt ++ compile_options(Code0)) of
1127	[] ->
1128            %% No parse transforms.
1129            {ok,Code0,St};
1130	Ts ->
1131	    %% Remove parse_transform attributes from the abstract code to
1132	    %% prevent parse transforms to be run more than once.
1133	    Code = clean_parse_transforms(Code0),
1134	    foldl_transform(Ts, Code, St)
1135    end.
1136
1137foldl_transform([T|Ts], Code0, St) ->
1138    Name = "transform " ++ atom_to_list(T),
1139    case code:ensure_loaded(T) =:= {module,T} andalso
1140        erlang:function_exported(T, parse_transform, 2) of
1141        true ->
1142            Fun = fun(Code, S) ->
1143                          T:parse_transform(Code, S#compile.options)
1144                  end,
1145            Run = runner(none, St),
1146            StrippedCode = maybe_strip_columns(Code0, T, St),
1147            try Run({Name, Fun}, StrippedCode, St) of
1148                {error,Es,Ws} ->
1149                    {error,St#compile{warnings=St#compile.warnings ++ Ws,
1150                                      errors=St#compile.errors ++ Es}};
1151                {warning, Forms, Ws} ->
1152                    foldl_transform(Ts, Forms,
1153                                    St#compile{warnings=St#compile.warnings ++ Ws});
1154                Forms ->
1155                    foldl_transform(Ts, Forms, St)
1156            catch
1157                Class:Reason:Stk ->
1158                    Es = [{St#compile.ifile,[{none,compile,
1159                                              {parse_transform,T,{Class,Reason,Stk}}}]}],
1160                    {error,St#compile{errors=St#compile.errors ++ Es}}
1161            end;
1162        false ->
1163            Es = [{St#compile.ifile,[{none,compile,
1164                                      {undef_parse_transform,T}}]}],
1165            {error,St#compile{errors=St#compile.errors ++ Es}}
1166    end;
1167foldl_transform([], Code, St) ->
1168    %% We may need to strip columns added by parse transforms before returning
1169    %% them back to the compiler. We pass ?MODULE as a bit of a hack to get the
1170    %% correct default.
1171    {ok, maybe_strip_columns(Code, ?MODULE, St), St}.
1172
1173%%% If a parse transform does not support column numbers it can say so using
1174%%% the parse_transform_info callback. The error_location is taken from both
1175%%% compiler options and from the parse transform and if either of them want
1176%%% to only use lines, we strip columns.
1177maybe_strip_columns(Code, T, St) ->
1178    PTErrorLocation =
1179        case erlang:function_exported(T, parse_transform_info, 0) of
1180            true ->
1181                maps:get(error_location, T:parse_transform_info(), column);
1182            false ->
1183                column
1184        end,
1185    ConfigErrorLocation = proplists:get_value(error_location, St#compile.options, column),
1186    if
1187        PTErrorLocation =:= line; ConfigErrorLocation =:= line ->
1188            strip_columns(Code);
1189        true -> Code
1190    end.
1191
1192strip_columns(Code) ->
1193    F = fun(A) -> erl_anno:set_location(erl_anno:line(A), A) end,
1194    [case Form of
1195         {eof,{Line,_Col}} ->
1196             {eof,Line};
1197         {ErrorOrWarning,{{Line,_Col},Module,Reason}}
1198           when ErrorOrWarning =:= error;
1199                ErrorOrWarning =:= warning ->
1200             {ErrorOrWarning,{Line,Module,Reason}};
1201         Form ->
1202             erl_parse:map_anno(F, Form)
1203     end || Form <- Code].
1204
1205get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
1206
1207core_transforms(Code, St) ->
1208    %% The options field holds the complete list of options at this
1209    Ts = get_core_transforms(St#compile.options),
1210    foldl_core_transforms(Ts, Code, St).
1211
1212foldl_core_transforms([T|Ts], Code0, St) ->
1213    Name = "core transform " ++ atom_to_list(T),
1214    Fun = fun(Code, S) -> T:core_transform(Code, S#compile.options) end,
1215    Run = runner(none, St),
1216    try Run({Name, Fun}, Code0, St) of
1217	Forms ->
1218	    foldl_core_transforms(Ts, Forms, St)
1219    catch
1220        Class:Reason:Stk ->
1221            Es = [{St#compile.ifile,[{none,compile,
1222                                      {core_transform,T,{Class,Reason,Stk}}}]}],
1223            {error,St#compile{errors=St#compile.errors ++ Es}}
1224    end;
1225foldl_core_transforms([], Code, St) -> {ok,Code,St}.
1226
1227%%% Fetches the module name from a list of forms. The module attribute must
1228%%% be present.
1229get_module([{attribute,_,module,M} | _]) -> M;
1230get_module([_ | Rest]) ->
1231    get_module(Rest).
1232
1233%%% A #compile state is returned, where St.base has been filled in
1234%%% with the module name from Forms, as a string, in case it wasn't
1235%%% set in St (i.e., it was "").
1236add_default_base(St, Forms) ->
1237    F = St#compile.filename,
1238    case F of
1239	"" ->
1240 	    M = get_module(Forms),
1241	    St#compile{base=atom_to_list(M)};
1242	_ ->
1243	    St
1244    end.
1245
1246lint_module(Code, St) ->
1247    case erl_lint:module(Code, St#compile.ifile, St#compile.options) of
1248	{ok,Ws} ->
1249	    %% Insert name of module as base name, if needed. This is
1250	    %% for compile:forms to work with listing files.
1251	    St1 = add_default_base(St, Code),
1252	    {ok,Code,St1#compile{warnings=St1#compile.warnings ++ Ws}};
1253	{error,Es,Ws} ->
1254	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
1255			      errors=St#compile.errors ++ Es}}
1256    end.
1257
1258core_lint_module(Code, St) ->
1259    case core_lint:module(Code, St#compile.options) of
1260	{ok,Ws} ->
1261	    {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
1262	{error,Es,Ws} ->
1263	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
1264			      errors=St#compile.errors ++ Es}}
1265    end.
1266
1267%% makedep + output and continue
1268makedep_and_output(Code0, St) ->
1269    {ok,DepCode,St1} = makedep(Code0,St),
1270    case makedep_output(DepCode, St1) of
1271        {ok,_IgnoreCode,St2} ->
1272            {ok,Code0,St2};
1273        {error,St2} ->
1274            {error,St2}
1275    end.
1276
1277makedep(Code0, #compile{ifile=Ifile,ofile=Ofile,options=Opts}=St) ->
1278
1279    %% Get the target of the Makefile rule.
1280    Target0 =
1281	case proplists:get_value(makedep_target, Opts) of
1282	    undefined ->
1283		%% The target is derived from the output filename: possibly
1284		%% remove the current working directory to obtain a relative
1285		%% path.
1286		shorten_filename(Ofile);
1287	    T ->
1288		%% The caller specified one.
1289		T
1290	end,
1291
1292    %% Quote the target is the called asked for this.
1293    Target1 = case proplists:get_value(makedep_quote_target, Opts) of
1294		  true ->
1295		      %% For now, only "$" is replaced by "$$".
1296		      Fun = fun
1297				($$) -> "$$";
1298				(C)  -> C
1299			    end,
1300		      map(Fun, Target0);
1301		  _ ->
1302		      Target0
1303	      end,
1304    Target = Target1 ++ ":",
1305
1306    %% List the dependencies (includes) for this target.
1307    {MainRule,PhonyRules} = makedep_add_headers(
1308      Ifile,          % The input file name.
1309      Code0,          % The parsed source.
1310      [],             % The list of dependencies already added.
1311      length(Target), % The current line length.
1312      Target,         % The target.
1313      "",             % Phony targets.
1314      Opts),
1315
1316    %% Prepare the content of the Makefile. For instance:
1317    %%   hello.erl: hello.hrl common.hrl
1318    %%
1319    %% Or if phony targets are enabled:
1320    %%   hello.erl: hello.hrl common.hrl
1321    %%
1322    %%   hello.hrl:
1323    %%
1324    %%   common.hrl:
1325    Makefile = case proplists:get_value(makedep_phony, Opts) of
1326		   true -> MainRule ++ PhonyRules;
1327		   _ -> MainRule
1328	       end,
1329    Code = unicode:characters_to_binary([Makefile,"\n"]),
1330    {ok,Code,St}.
1331
1332makedep_add_headers(Ifile, [{attribute,_,file,{File,_}}|Rest],
1333		    Included, LineLen, MainTarget, Phony, Opts) ->
1334    %% The header "File" exists, add it to the dependencies.
1335    {Included1,LineLen1,MainTarget1,Phony1} =
1336	makedep_add_header(Ifile, Included, LineLen, MainTarget, Phony, File),
1337    makedep_add_headers(Ifile, Rest, Included1, LineLen1,
1338			MainTarget1, Phony1, Opts);
1339makedep_add_headers(Ifile, [{error,{_,epp,{include,file,File}}}|Rest],
1340		    Included, LineLen, MainTarget, Phony, Opts) ->
1341    %% The header "File" doesn't exist, do we add it to the dependencies?
1342    case proplists:get_value(makedep_add_missing, Opts) of
1343        true ->
1344            {Included1,LineLen1,MainTarget1,Phony1} =
1345		makedep_add_header(Ifile, Included, LineLen, MainTarget,
1346				   Phony, File),
1347            makedep_add_headers(Ifile, Rest, Included1, LineLen1,
1348				MainTarget1, Phony1, Opts);
1349        _ ->
1350            makedep_add_headers(Ifile, Rest, Included, LineLen,
1351				MainTarget, Phony, Opts)
1352    end;
1353makedep_add_headers(Ifile, [_|Rest], Included, LineLen,
1354		    MainTarget, Phony, Opts) ->
1355    makedep_add_headers(Ifile, Rest, Included,
1356			LineLen, MainTarget, Phony, Opts);
1357makedep_add_headers(_Ifile, [], _Included, _LineLen,
1358		    MainTarget, Phony, _Opts) ->
1359    {MainTarget,Phony}.
1360
1361makedep_add_header(Ifile, Included, LineLen, MainTarget, Phony, File) ->
1362    case member(File, Included) of
1363	true ->
1364	    %% This file was already listed in the dependencies, skip it.
1365            {Included,LineLen,MainTarget,Phony};
1366	false ->
1367            Included1 = [File|Included],
1368
1369	    %% Remove "./" in front of the dependency filename.
1370	    File1 = case File of
1371			"./" ++ File0 -> File0;
1372			_ -> File
1373	    end,
1374
1375	    %% Prepare the phony target name.
1376	    Phony1 = case File of
1377			 Ifile -> Phony;
1378			 _     -> Phony ++ "\n\n" ++ File1 ++ ":"
1379	    end,
1380
1381	    %% Add the file to the dependencies. Lines longer than 76 columns
1382	    %% are split.
1383	    if
1384		LineLen + 1 + length(File1) > 76 ->
1385                    LineLen1 = 2 + length(File1),
1386                    MainTarget1 = MainTarget ++ " \\\n  " ++ File1,
1387                    {Included1,LineLen1,MainTarget1,Phony1};
1388		true ->
1389                    LineLen1 = LineLen + 1 + length(File1),
1390                    MainTarget1 = MainTarget ++ " " ++ File1,
1391                    {Included1,LineLen1,MainTarget1,Phony1}
1392	    end
1393    end.
1394
1395makedep_output(Code, #compile{options=Opts,ofile=Ofile}=St) ->
1396    %% Write this Makefile (Code) to the selected output.
1397    %% If no output is specified, the default is to write to a file named after
1398    %% the output file.
1399    Output = case proplists:get_value(makedep_output, Opts) of
1400                 undefined ->
1401                     %% Prepare the default filename.
1402                     outfile(filename:basename(Ofile, ".beam"), "Pbeam", Opts);
1403                 Other ->
1404                     Other
1405             end,
1406
1407    if
1408        is_list(Output) ->
1409            %% Write the depedencies to a file.
1410            case file:write_file(Output, Code) of
1411                ok ->
1412                    {ok,Code,St};
1413                {error,Reason} ->
1414                    Err = {St#compile.ifile,[{none,?MODULE,{write_error,Reason}}]},
1415                    {error,St#compile{errors=St#compile.errors++[Err]}}
1416            end;
1417        true ->
1418            %% Write the depedencies to a device.
1419            try io:fwrite(Output, "~ts", [Code]) of
1420                ok ->
1421                    {ok,Code,St}
1422            catch
1423                error:_ ->
1424                    Err = {St#compile.ifile,[{none,?MODULE,write_error}]},
1425                    {error,St#compile{errors=St#compile.errors++[Err]}}
1426            end
1427    end.
1428
1429expand_records(Code0, #compile{options=Opts}=St) ->
1430    Code = erl_expand_records:module(Code0, Opts),
1431    {ok,Code,St}.
1432
1433compile_directives(Forms, #compile{options=Opts0}=St) ->
1434    Opts = expand_opts(flatten([C || {attribute,_,compile,C} <- Forms])),
1435    {ok, Forms, St#compile{options=Opts ++ Opts0}}.
1436
1437core(Forms, #compile{options=Opts}=St) ->
1438    {ok,Core,Ws} = v3_core:module(Forms, Opts),
1439    Mod = cerl:concrete(cerl:module_name(Core)),
1440    {ok,Core,St#compile{module=Mod,options=Opts,
1441                        warnings=St#compile.warnings++Ws}}.
1442
1443core_fold_module_after_inlining(Code0, #compile{options=Opts}=St) ->
1444    %% Inlining may produce code that generates spurious warnings.
1445    %% Ignore all warnings.
1446    {ok,Code,_Ws} = sys_core_fold:module(Code0, Opts),
1447    {ok,Code,St}.
1448
1449v3_kernel(Code0, #compile{options=Opts,warnings=Ws0}=St) ->
1450    {ok,Code,Ws} = v3_kernel:module(Code0, Opts),
1451    case Ws =:= [] orelse test_core_inliner(St) of
1452	false ->
1453	    {ok,Code,St#compile{warnings=Ws0++Ws}};
1454	true ->
1455	    %% cerl_inline may produce code that generates spurious
1456	    %% warnings. Ignore any such warnings.
1457	    {ok,Code,St}
1458    end.
1459
1460test_old_inliner(#compile{options=Opts}) ->
1461    %% The point of this test is to avoid loading the old inliner
1462    %% if we know that it will not be used.
1463    any(fun({inline,_}) -> true;
1464	   (_) -> false
1465	end, Opts).
1466
1467test_core_inliner(#compile{options=Opts}) ->
1468    case any(fun(no_inline) -> true;
1469		(_) -> false
1470	     end, Opts) of
1471	true -> false;
1472	false ->
1473	    any(fun(inline) -> true;
1474		   (_) -> false
1475		end, Opts)
1476    end.
1477
1478test_any_inliner(St) ->
1479    test_old_inliner(St) orelse test_core_inliner(St).
1480
1481core_old_inliner(Code0, #compile{options=Opts}=St) ->
1482    {ok,Code} = sys_core_inline:module(Code0, Opts),
1483    {ok,Code,St}.
1484
1485core_inline_module(Code0, #compile{options=Opts}=St) ->
1486    Code = cerl_inline:core_transform(Code0, Opts),
1487    {ok,Code,St}.
1488
1489save_abstract_code(Code, St) ->
1490    {ok,Code,St#compile{abstract_code=erl_parse:anno_to_term(Code)}}.
1491
1492debug_info(#compile{module=Module,ofile=OFile}=St) ->
1493    {DebugInfo,Opts2} = debug_info_chunk(St),
1494    case member(encrypt_debug_info, Opts2) of
1495	true ->
1496	    case lists:keytake(debug_info_key, 1, Opts2) of
1497		{value,{_, Key},Opts3} ->
1498		    encrypt_debug_info(DebugInfo, Key, [{debug_info_key,'********'} | Opts3]);
1499		false ->
1500		    Mode = proplists:get_value(crypto_mode, Opts2, des3_cbc),
1501		    case beam_lib:get_crypto_key({debug_info, Mode, Module, OFile}) of
1502			error ->
1503			    {error, [{none,?MODULE,no_crypto_key}]};
1504			Key ->
1505			    encrypt_debug_info(DebugInfo, {Mode, Key}, Opts2)
1506		    end
1507	    end;
1508	false ->
1509	    {ok,DebugInfo,Opts2}
1510    end.
1511
1512debug_info_chunk(#compile{mod_options=ModOpts0,
1513                          options=CompOpts,
1514                          abstract_code=Abst}) ->
1515    AbstOpts = cleanup_compile_options(ModOpts0),
1516    {Backend,Metadata,ModOpts} =
1517        case proplists:get_value(debug_info, CompOpts, false) of
1518            {OptBackend,OptMetadata} when is_atom(OptBackend) ->
1519                ModOpts1 = proplists:delete(debug_info, ModOpts0),
1520                {OptBackend,OptMetadata,ModOpts1};
1521            true ->
1522                ModOpts1 = proplists:delete(debug_info, ModOpts0),
1523                {erl_abstract_code,{Abst,AbstOpts},[debug_info | ModOpts1]};
1524            false ->
1525                {erl_abstract_code,{none,AbstOpts},ModOpts0}
1526        end,
1527    DebugInfo = erlang:term_to_binary({debug_info_v1,Backend,Metadata},
1528                                      [compressed]),
1529    {DebugInfo, ModOpts}.
1530
1531encrypt_debug_info(DebugInfo, Key, Opts) ->
1532    try
1533	RealKey = generate_key(Key),
1534	case start_crypto() of
1535	    ok -> {ok,encrypt(RealKey, DebugInfo),Opts};
1536	    {error,_}=E -> E
1537	end
1538    catch
1539	error:_ ->
1540	    {error,[{none,?MODULE,bad_crypto_key}]}
1541    end.
1542
1543cleanup_compile_options(Opts) ->
1544    IsDeterministic = lists:member(deterministic, Opts),
1545    lists:filter(fun(Opt) ->
1546                         keep_compile_option(Opt, IsDeterministic)
1547                 end, Opts).
1548
1549%% Include paths and current directory don't affect compilation, but they might
1550%% be helpful so we include them unless we're doing a deterministic build.
1551keep_compile_option({i, _}, Deterministic) ->
1552    not Deterministic;
1553keep_compile_option({cwd, _}, Deterministic) ->
1554    not Deterministic;
1555%% We are storing abstract, not asm or core.
1556keep_compile_option(from_asm, _Deterministic) ->
1557    false;
1558keep_compile_option(from_core, _Deterministic) ->
1559    false;
1560keep_compile_option(from_abstr, _Deterministic) ->
1561    false;
1562%% Parse transform and macros have already been applied.
1563keep_compile_option({parse_transform, _}, _Deterministic) ->
1564    false;
1565keep_compile_option({d, _, _}, _Deterministic) ->
1566    false;
1567%% Do not affect compilation result on future calls.
1568keep_compile_option(Option, _Deterministic) ->
1569    effects_code_generation(Option).
1570
1571start_crypto() ->
1572    try crypto:start() of
1573	{error,{already_started,crypto}} -> ok;
1574	ok -> ok
1575    catch
1576	error:_ ->
1577	    {error,[{none,?MODULE,no_crypto}]}
1578    end.
1579
1580generate_key({Type,String}) when is_atom(Type), is_list(String) ->
1581    beam_lib:make_crypto_key(Type, String);
1582generate_key(String) when is_list(String) ->
1583    generate_key({des3_cbc,String}).
1584
1585encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) ->
1586    Bin1 = case byte_size(Bin0) rem BlockSize of
1587	       0 -> Bin0;
1588	       N -> list_to_binary([Bin0,crypto:strong_rand_bytes(BlockSize-N)])
1589	   end,
1590    Bin = crypto:crypto_one_time(des_ede3_cbc, Key, IVec, Bin1, true),
1591    TypeString = atom_to_list(Type),
1592    list_to_binary([0,length(TypeString),TypeString,Bin]).
1593
1594beam_validator_strong(Code, St) ->
1595    beam_validator_1(Code, St, strong).
1596
1597beam_validator_weak(Code, St) ->
1598    beam_validator_1(Code, St, weak).
1599
1600beam_validator_1(Code, #compile{errors=Errors0}=St, Level) ->
1601    case beam_validator:validate(Code, Level) of
1602        ok ->
1603            {ok, Code, St};
1604        {error, Es} ->
1605            {error, St#compile{errors=Errors0 ++ Es}}
1606    end.
1607
1608beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) ->
1609    case debug_info(St) of
1610	{ok,DebugInfo,Opts0} ->
1611	    Opts1 = [O || O <- Opts0, effects_code_generation(O)],
1612	    Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks],
1613	    CompileInfo = compile_info(File, CompilerOpts, Opts1),
1614	    {ok,Code} = beam_asm:module(Code0, Chunks, CompileInfo, CompilerOpts),
1615	    {ok,Code,St#compile{abstract_code=[]}};
1616	{error,Es} ->
1617	    {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
1618    end.
1619
1620compile_info(File, CompilerOpts, Opts) ->
1621    IsSlim = member(slim, CompilerOpts),
1622    IsDeterministic = member(deterministic, CompilerOpts),
1623    Info0 = proplists:get_value(compile_info, Opts, []),
1624    Info1 =
1625	case paranoid_absname(File) of
1626	    [_|_] = Source when not IsSlim, not IsDeterministic ->
1627		[{source,Source} | Info0];
1628	    _ ->
1629		Info0
1630	end,
1631    Info2 =
1632	case IsDeterministic of
1633	    false -> [{options,proplists:delete(compile_info, Opts)} | Info1];
1634	    true -> Info1
1635	end,
1636    Info2.
1637
1638paranoid_absname(""=File) ->
1639    File;
1640paranoid_absname(File) ->
1641    case file:get_cwd() of
1642	{ok,Cwd} ->
1643	    filename:absname(File, Cwd);
1644	_ ->
1645	    File
1646    end.
1647
1648%% effects_code_generation(Option) -> true|false.
1649%%  Determine whether the option could have any effect on the
1650%%  generated code in the BEAM file (as opposed to how
1651%%  errors will be reported).
1652
1653effects_code_generation(Option) ->
1654    case Option of
1655	beam -> false;
1656	report_warnings -> false;
1657	report_errors -> false;
1658	return_errors-> false;
1659	return_warnings-> false;
1660	warnings_as_errors -> false;
1661	binary -> false;
1662	verbose -> false;
1663	{cwd,_} -> false;
1664	{outdir, _} -> false;
1665	_ -> true
1666    end.
1667
1668save_binary(Code, #compile{module=Mod,ofile=Outfile,options=Opts}=St) ->
1669    %% Test that the module name and output file name match.
1670    case member(no_error_module_mismatch, Opts) of
1671	true ->
1672	    save_binary_1(Code, St);
1673	false ->
1674	    Base = filename:rootname(filename:basename(Outfile)),
1675	    case atom_to_list(Mod) of
1676		Base ->
1677		    save_binary_1(Code, St);
1678		_ ->
1679		    Es = [{St#compile.ofile,
1680			   [{none,?MODULE,{module_name,Mod,Base}}]}],
1681		    {error,St#compile{errors=St#compile.errors ++ Es}}
1682	    end
1683    end.
1684
1685save_binary_1(Code, St) ->
1686    Ofile = St#compile.ofile,
1687    Tfile = tmpfile(Ofile),		%Temp working file
1688    case write_binary(Tfile, Code, St) of
1689	ok ->
1690	    case file:rename(Tfile, Ofile) of
1691		ok ->
1692		    {ok,none,St};
1693		{error,RenameError} ->
1694                    Es = [{Ofile,[{none,?MODULE,{rename,Tfile,Ofile,
1695                                                 RenameError}}]}],
1696                    _ = file:delete(Tfile),
1697		    {error,St#compile{errors=St#compile.errors ++ Es}}
1698	    end;
1699	{error,Error} ->
1700	    Es = [{Tfile,[{none,compile,{write_error,Error}}]}],
1701	    {error,St#compile{errors=St#compile.errors ++ Es}}
1702    end.
1703
1704write_binary(Name, Bin, St) ->
1705    Opts = case member(compressed, St#compile.options) of
1706	       true -> [compressed];
1707	       false -> []
1708	   end,
1709    case file:write_file(Name, Bin, Opts) of
1710	ok -> ok;
1711	{error,_}=Error -> Error
1712    end.
1713
1714%% report_errors(State) -> ok
1715%% report_warnings(State) -> ok
1716
1717report_errors(#compile{options=Opts,errors=Errors}) ->
1718    case member(report_errors, Opts) of
1719	true ->
1720	    foreach(fun ({{F,_L},Eds}) -> sys_messages:list_errors(F, Eds, Opts);
1721			({F,Eds}) -> sys_messages:list_errors(F, Eds, Opts) end,
1722		    Errors);
1723	false -> ok
1724    end.
1725
1726report_warnings(#compile{options=Opts,warnings=Ws0}) ->
1727    Werror = member(warnings_as_errors, Opts),
1728    P = case Werror of
1729	    true -> "";
1730	    false -> "Warning: "
1731	end,
1732    ReportWerror = Werror andalso member(report_errors, Opts),
1733    case member(report_warnings, Opts) orelse ReportWerror of
1734	true ->
1735	    Ws1 = flatmap(fun({{F,_L},Eds}) -> sys_messages:format_messages(F, P, Eds, Opts);
1736			     ({F,Eds}) -> sys_messages:format_messages(F, P, Eds, Opts) end,
1737			  Ws0),
1738	    Ws = lists:sort(Ws1),
1739	    foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws);
1740	false -> ok
1741    end.
1742
1743%%%
1744%%% Filter warnings.
1745%%%
1746
1747filter_warnings(Ws, Opts) ->
1748    Ignore = ignore_tags(Opts, sets:new([{version,2}])),
1749    filter_warnings_1(Ws, Ignore).
1750
1751filter_warnings_1([{Source,Ws0}|T], Ignore) ->
1752    Ws = [W || W <- Ws0, not ignore_warning(W, Ignore)],
1753    [{Source,Ws}|filter_warnings_1(T, Ignore)];
1754filter_warnings_1([], _Ignore) -> [].
1755
1756ignore_warning({_Location,Pass,{Category,_}}, Ignore) ->
1757    IgnoreMod = case Pass of
1758                    v3_core -> true;
1759                    sys_core_fold -> true;
1760                    v3_kernel -> true;
1761                    _ -> false
1762                end,
1763    IgnoreMod andalso sets:is_element(Category, Ignore);
1764ignore_warning(_, _) -> false.
1765
1766ignore_tags([nowarn_opportunistic|_], _Ignore) ->
1767    sets:from_list([failed,ignored,nomatch], [{version,2}]);
1768ignore_tags([nowarn_failed|Opts], Ignore) ->
1769    ignore_tags(Opts, sets:add_element(failed, Ignore));
1770ignore_tags([nowarn_ignored|Opts], Ignore) ->
1771    ignore_tags(Opts, sets:add_element(ignored, Ignore));
1772ignore_tags([nowarn_nomatch|Opts], Ignore) ->
1773    ignore_tags(Opts, sets:add_element(nomatch, Ignore));
1774ignore_tags([_|Opts], Ignore) ->
1775    ignore_tags(Opts, Ignore);
1776ignore_tags([], Ignore) -> Ignore.
1777
1778%% erlfile(Dir, Base) -> ErlFile
1779%% outfile(Base, Extension, Options) -> OutputFile
1780%% objfile(Base, Target, Options) -> ObjFile
1781%% tmpfile(ObjFile) -> TmpFile
1782%%  Work out the correct input and output file names.
1783
1784erlfile(".", Base, Suffix) ->
1785    Base ++ Suffix;
1786erlfile(Dir, Base, Suffix) ->
1787    filename:join(Dir, Base ++ Suffix).
1788
1789outfile(Base, Ext, Opts) when is_list(Ext) ->
1790    Obase = case keyfind(outdir, 1, Opts) of
1791		{outdir, Odir} -> filename:join(Odir, Base);
1792		_Other -> Base			% Not found or bad format
1793	    end,
1794    Obase ++ "." ++ Ext.
1795
1796objfile(Base, St) ->
1797    outfile(Base, "beam", St#compile.options).
1798
1799tmpfile(Ofile) ->
1800    reverse([$#|tl(reverse(Ofile))]).
1801
1802%% pre_defs(Options)
1803%% inc_paths(Options)
1804%%  Extract the predefined macros and include paths from the option list.
1805
1806pre_defs([{d,M,V}|Opts]) ->
1807    [{M,V}|pre_defs(Opts)];
1808pre_defs([{d,M}|Opts]) ->
1809    [M|pre_defs(Opts)];
1810pre_defs([_|Opts]) ->
1811    pre_defs(Opts);
1812pre_defs([]) -> [].
1813
1814inc_paths(Opts) ->
1815    [ P || {i,P} <- Opts, is_list(P) ].
1816
1817src_listing(Ext, Code, St) ->
1818    listing(fun (Lf, {_Mod,_Exp,Fs}) -> do_src_listing(Lf, Fs);
1819		(Lf, Fs) -> do_src_listing(Lf, Fs) end,
1820	    Ext, Code, St).
1821
1822do_src_listing(Lf, Fs) ->
1823    Opts = [lists:keyfind(encoding, 1, io:getopts(Lf))],
1824    foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F, Opts),"\n"]) end,
1825	    Fs).
1826
1827listing(Ext, Code, St0) ->
1828    St = St0#compile{encoding = none},
1829    listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, Code, St).
1830
1831listing(LFun, Ext, Code, St) ->
1832    Lfile = outfile(St#compile.base, Ext, St#compile.options),
1833    case file:open(Lfile, [write,delayed_write]) of
1834	{ok,Lf} ->
1835            output_encoding(Lf, St),
1836	    LFun(Lf, Code),
1837	    ok = file:close(Lf),
1838	    {ok,Code,St};
1839	{error,Error} ->
1840	    Es = [{Lfile,[{none,compile,{write_error,Error}}]}],
1841	    {error,St#compile{errors=St#compile.errors ++ Es}}
1842    end.
1843
1844to_dis(Code, #compile{module=Module,ofile=Outfile}=St) ->
1845    Loaded = code:is_loaded(Module),
1846    Sticky = code:is_sticky(Module),
1847    _ = [code:unstick_mod(Module) || Sticky],
1848
1849    {module,Module} = code:load_binary(Module, "", Code),
1850    DestDir = filename:dirname(Outfile),
1851    DisFile = filename:join(DestDir, atom_to_list(Module) ++ ".dis"),
1852    ok = erts_debug:dis_to_file(Module, DisFile),
1853
1854    %% Restore loaded module
1855    _ = [{module, Module} = code:load_file(Module) || Loaded =/= false],
1856    [code:stick_mod(Module) || Sticky],
1857    {ok,Code,St}.
1858
1859output_encoding(F, #compile{encoding = none}) ->
1860    ok = io:setopts(F, [{encoding, epp:default_encoding()}]);
1861output_encoding(F, #compile{encoding = Encoding}) ->
1862    ok = io:setopts(F, [{encoding, Encoding}]),
1863    ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
1864
1865%%%
1866%%% Transform the BEAM code to make it more friendly for
1867%%% diffing: using function names instead of labels for
1868%%% local calls and number labels relative to each function.
1869%%%
1870
1871diffable(Code0, St) ->
1872    {Mod,Exp,Attr,Fs0,NumLabels} = Code0,
1873    EntryLabels0 = [{Entry,{Name,Arity}} ||
1874                       {function,Name,Arity,Entry,_} <- Fs0],
1875    EntryLabels = maps:from_list(EntryLabels0),
1876    Fs = [diffable_fix_function(F, EntryLabels) || F <- Fs0],
1877    Code = {Mod,Exp,Attr,Fs,NumLabels},
1878    {ok,Code,St}.
1879
1880diffable_fix_function({function,Name,Arity,Entry0,Is0}, LabelMap0) ->
1881    Entry = maps:get(Entry0, LabelMap0),
1882    {Is1,LabelMap} = diffable_label_map(Is0, 1, LabelMap0, []),
1883    Fb = fun(Old) -> error({no_fb,Old}) end,
1884    Is = beam_utils:replace_labels(Is1, [], LabelMap, Fb),
1885    {function,Name,Arity,Entry,Is}.
1886
1887diffable_label_map([{label,Old}|Is], New, Map, Acc) ->
1888    case Map of
1889        #{Old:=NewLabel} ->
1890            diffable_label_map(Is, New, Map, [{label,NewLabel}|Acc]);
1891        #{} ->
1892            diffable_label_map(Is, New+1, Map#{Old=>New}, [{label,New}|Acc])
1893    end;
1894diffable_label_map([I|Is], New, Map, Acc) ->
1895    diffable_label_map(Is, New, Map, [I|Acc]);
1896diffable_label_map([], _New, Map, Acc) ->
1897    {Acc,Map}.
1898
1899-spec options() -> 'ok'.
1900
1901options() ->
1902    help(standard_passes()).
1903
1904help([{delay,Ps}|T]) ->
1905    help(Ps),
1906    help(T);
1907help([{iff,Flag,{src_listing,Ext}}|T]) ->
1908    io:fwrite("~p - Generate .~s source listing file\n", [Flag,Ext]),
1909    help(T);
1910help([{iff,Flag,{listing,Ext}}|T]) ->
1911    io:fwrite("~p - Generate .~s file\n", [Flag,Ext]),
1912    help(T);
1913help([{iff,Flag,{Name,Fun}}|T]) when is_function(Fun) ->
1914    io:fwrite("~p - Run ~s\n", [Flag,Name]),
1915    help(T);
1916help([{iff,_Flag,Action}|T]) ->
1917    help(Action),
1918    help(T);
1919help([{unless,Flag,{pass,Pass}}|T]) ->
1920    io:fwrite("~p - Skip the ~s pass\n", [Flag,Pass]),
1921    help(T);
1922help([{unless,no_postopt=Flag,List}|T]) when is_list(List) ->
1923    %% Hard-coded knowledge here.
1924    io:fwrite("~p - Skip all post optimisation\n", [Flag]),
1925    help(List),
1926    help(T);
1927help([{unless,_Flag,Action}|T]) ->
1928    help(Action),
1929    help(T);
1930help([_|T]) ->
1931    help(T);
1932help(_) ->
1933    ok.
1934
1935rel2fam(S0) ->
1936    S1 = sofs:relation(S0),
1937    S = sofs:rel2fam(S1),
1938    sofs:to_external(S).
1939
1940%% compile(AbsFileName, Outfilename, Options)
1941%%   Compile entry point for erl_compile.
1942
1943-spec compile(file:filename(), _, #options{}) -> 'ok' | 'error'.
1944
1945compile(File0, _OutFile, Options) ->
1946    pre_load(),
1947    File = shorten_filename(File0),
1948    case file(File, make_erl_options(Options)) of
1949	{ok,_Mod} -> ok;
1950	Other -> Other
1951    end.
1952
1953-spec compile_asm(file:filename(), _, #options{}) -> 'ok' | 'error'.
1954
1955compile_asm(File0, _OutFile, Opts) ->
1956    File = shorten_filename(File0),
1957    case file(File, [from_asm|make_erl_options(Opts)]) of
1958	{ok,_Mod} -> ok;
1959	Other -> Other
1960    end.
1961
1962-spec compile_core(file:filename(), _, #options{}) -> 'ok' | 'error'.
1963
1964compile_core(File0, _OutFile, Opts) ->
1965    File = shorten_filename(File0),
1966    case file(File, [from_core|make_erl_options(Opts)]) of
1967	{ok,_Mod} -> ok;
1968	Other -> Other
1969    end.
1970
1971-spec compile_abstr(file:filename(), _, #options{}) -> 'ok' | 'error'.
1972
1973compile_abstr(File0, _OutFile, Opts) ->
1974    File = shorten_filename(File0),
1975    case file(File, [from_abstr|make_erl_options(Opts)]) of
1976	{ok,_Mod} -> ok;
1977	Other -> Other
1978    end.
1979
1980shorten_filename(Name0) ->
1981    {ok,Cwd} = file:get_cwd(),
1982    case lists:prefix(Cwd, Name0) of
1983	false -> Name0;
1984	true ->
1985	    case lists:nthtail(length(Cwd), Name0) of
1986		"/"++N -> N;
1987		N -> N
1988	    end
1989    end.
1990
1991%% Converts generic compiler options to specific options.
1992
1993make_erl_options(Opts) ->
1994    #options{includes=Includes,
1995	     defines=Defines,
1996	     outdir=Outdir,
1997	     warning=Warning,
1998	     verbose=Verbose,
1999	     specific=Specific,
2000	     cwd=Cwd} = Opts,
2001    Options = [verbose || Verbose] ++
2002	[report_warnings || Warning =/= 0] ++
2003	map(fun ({Name,Value}) ->
2004		    {d,Name,Value};
2005		(Name) ->
2006		    {d,Name}
2007            end, Defines),
2008    Options ++ [report_errors, {cwd, Cwd}, {outdir, Outdir} |
2009                [{i, Dir} || Dir <- Includes]] ++ Specific.
2010
2011pre_load() ->
2012    L = [beam_a,
2013	 beam_asm,
2014	 beam_block,
2015	 beam_call_types,
2016	 beam_clean,
2017	 beam_dict,
2018	 beam_digraph,
2019	 beam_flatten,
2020	 beam_jump,
2021	 beam_kernel_to_ssa,
2022	 beam_opcodes,
2023	 beam_peep,
2024	 beam_ssa,
2025	 beam_ssa_bc_size,
2026	 beam_ssa_bool,
2027	 beam_ssa_bsm,
2028	 beam_ssa_codegen,
2029	 beam_ssa_dead,
2030         beam_ssa_funs,
2031	 beam_ssa_opt,
2032	 beam_ssa_pre_codegen,
2033	 beam_ssa_recv,
2034	 beam_ssa_share,
2035	 beam_ssa_throw,
2036	 beam_ssa_type,
2037	 beam_trim,
2038	 beam_types,
2039	 beam_utils,
2040	 beam_validator,
2041	 beam_z,
2042	 cerl,
2043	 cerl_clauses,
2044	 cerl_trees,
2045	 core_lib,
2046	 epp,
2047	 erl_bifs,
2048	 erl_expand_records,
2049	 erl_lint,
2050	 erl_parse,
2051	 erl_scan,
2052	 sys_core_alias,
2053	 sys_core_bsm,
2054	 sys_core_fold,
2055	 v3_core,
2056	 v3_kernel],
2057    _ = code:ensure_modules_loaded(L),
2058    ok.
2059