summaryrefslogtreecommitdiff
path: root/lib/compiler/src/compile.erl
diff options
context:
space:
mode:
authorFrej Drejhammar <frej.drejhammar@gmail.com>2022-11-30 14:59:44 +0100
committerFrej Drejhammar <frej.drejhammar@gmail.com>2023-01-19 14:34:24 +0100
commitdae4eda4983741e5631f90c52811fe2aeab84634 (patch)
tree1611d9bde209cb92e9e57b05f72d81260262144b /lib/compiler/src/compile.erl
parent0341cdfca0dcff05b629c9e3c0ff77f4b6a593b3 (diff)
downloaderlang-dae4eda4983741e5631f90c52811fe2aeab84634.tar.gz
compiler: Implement SSA checking pass
This patch adds a new pass, enabled by `+{check_ssa,post_ssa_opt}`, which runs after the ssa_opt pass. The pass uses SSA check directives embedded as comments in the source file and parsed by erl_parse to check the structure of the emitted BEAM SSA. In the SSA checker, match rules are applied sequentially on the SSA representation for a function, in the same order as if it had been dumped to disk. If the current pattern doesn't match, the checker tries with the next instruction. If the checker reaches the end of the SSA representation without having matched all patterns, the check is considered failed. When a pattern is matched against an SSA instruction, the values of variables already bound are considered and if the patterns matches, free variables introduced in the successfully matched pattern are bound to the values they have in the matched instruction.
Diffstat (limited to 'lib/compiler/src/compile.erl')
-rw-r--r--lib/compiler/src/compile.erl21
1 files changed, 20 insertions, 1 deletions
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 61c2512222..390effeb41 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -291,6 +291,8 @@ expand_opt(no_type_opt=O, Os) ->
no_ssa_opt_type_finish | Os];
expand_opt(no_module_opt=O, Os) ->
[O,no_recv_opt | Os];
+expand_opt({check_ssa,Tag}, Os) ->
+ [check_ssa, Tag | Os];
expand_opt(O, Os) -> [O|Os].
-spec format_error(error_description()) -> iolist().
@@ -773,6 +775,16 @@ select_list_passes_1([P|Ps], Opts, Acc) ->
select_list_passes_1([], _, Acc) ->
{not_done,reverse(Acc)}.
+make_ssa_check_pass(PassFlag) ->
+ F = fun (Code, St) ->
+ case beam_ssa_check:module(Code, PassFlag) of
+ ok -> {ok, Code, St};
+ {error, Errors} ->
+ {error, St#compile{errors=St#compile.errors++Errors}}
+ end
+ end,
+ {iff, PassFlag, {PassFlag, F}}.
+
%% The standard passes (almost) always run.
standard_passes() ->
@@ -877,6 +889,7 @@ kernel_passes() ->
{unless,no_bsm_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
{unless,no_ssa_opt,{pass,beam_ssa_opt}},
+ make_ssa_check_pass(post_ssa_opt),
{iff,dssaopt,{listing,"ssaopt"}},
{unless,no_ssa_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
@@ -1029,7 +1042,13 @@ do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
{location,StartLocation},
{reserved_word_fun, ResWordFun},
{features, Features},
- extra]),
+ extra|
+ case member(check_ssa, Opts) of
+ true ->
+ [{compiler_internal,[ssa_checks]}];
+ false ->
+ []
+ end]),
case R of
%% FIXME Extra should include used features as well
{ok,Forms0,Extra} ->