Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Sep 7, 2024
1 parent 613a31e commit c048cca
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 18 deletions.
6 changes: 3 additions & 3 deletions lib/compiler/src/beam_asm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ build_beam_debug_info_1(ExtraChunks0, Dict0) ->
DebugTab1 = [{Index,Info} ||
Index := Info <- maps:iterator(DebugTab0, ordered)],
DebugTab = build_bdi_fill_holes(DebugTab1),
NumVars = lists:sum([length(Vs) || {_,Vs} <- DebugTab]),
NumVars = lists:sum([length(Vs) || {_,_,Vs} <- DebugTab]),
{Contents0,Dict} = build_bdi(DebugTab, Dict0),
NumItems = length(Contents0),
Contents1 = iolist_to_binary(Contents0),
Expand All @@ -402,11 +402,11 @@ build_bdi_fill_holes([{I0,Item}|[{I1,_}|_]=T]) ->
I1 ->
[Item|build_bdi_fill_holes(T)];
Next ->
NewPair = {Next,{none,[]}},
NewPair = {Next,{none,0,[]}},
[Item|build_bdi_fill_holes([NewPair|T])]
end.

build_bdi([{FrameSize0,Vars0}|Items], Dict0) ->
build_bdi([{FrameSize0,_,Vars0}|Items], Dict0) ->
%% The debug information utilizes the encoding machinery for BEAM
%% instructions. The debug information for `executable_line`
%% instruction is translated to:
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler/src/beam_block.erl
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ collect({swap,D1,D2}) ->
collect({make_fun3,F,I,U,D,{list,Ss}}) -> {set,[D],Ss,{make_fun3,F,I,U}};
collect(_) -> error.

collect_executable_line({executable_line,_Loc,_Index,{_,Vars}}=I) ->
collect_executable_line({executable_line,_Loc,_Index,{_,_,Vars}}=I) ->
Ss = flatmap(fun({_Name,Regs}) -> Regs end, Vars),
{set,[],Ss,I}.

Expand Down
33 changes: 22 additions & 11 deletions lib/compiler/src/beam_ssa_codegen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ need_live_anno(Op) ->
bs_start_match -> true;
bs_skip -> true;
call -> true;
executable_line -> true;
put_map -> true;
update_record -> true;
_ -> false
Expand Down Expand Up @@ -825,6 +826,10 @@ need_y_init(#cg_set{op=bs_skip,args=[#b_literal{val=Type}|_]}) ->
_ -> false
end;
need_y_init(#cg_set{op=bs_start_match}) -> true;
need_y_init(#cg_set{op=executable_line,anno=Anno}) ->
%% If this instruction is used for debugging (as opposed to code coverage),
%% all Y registers must be initialized.
is_map_key(alias, Anno);
need_y_init(#cg_set{op=put_map}) -> true;
need_y_init(#cg_set{op=update_record}) -> true;
need_y_init(#cg_set{}) -> false.
Expand Down Expand Up @@ -993,9 +998,13 @@ add_debug_info_blk([], _Regs, _FrameSzMap, _VarMap) ->
[].

add_debug_info_is([#cg_alloc{stack=FrameSize}=I|Is],
Regs, _FrameSize, VarMap, Acc)
when is_integer(FrameSize) ->
add_debug_info_is(Is, Regs, FrameSize, VarMap, [I|Acc]);
Regs, FrameSize0, VarMap, Acc) ->
if
is_integer(FrameSize) ->
add_debug_info_is(Is, Regs, FrameSize, VarMap, [I|Acc]);
true ->
add_debug_info_is(Is, Regs, FrameSize0, VarMap, [I|Acc])
end;
add_debug_info_is([#cg_set{anno=#{was_phi := true},op=copy}=I|Is],
Regs, FrameSize, VarMap, Acc) ->
%% This copy operation originates from a phi node. The source and
Expand All @@ -1011,27 +1020,29 @@ add_debug_info_is([#cg_set{anno=Anno,op=copy,dst=#b_var{name=Dst},
VarMap0#{Dst => Src}
end,
add_debug_info_is(Is, Regs, FrameSize, VarMap, [I|Acc]);
add_debug_info_is([#cg_set{anno=Anno,op=executable_line,args=Args}=I0|Is],
add_debug_info_is([#cg_set{anno=Anno0,op=executable_line,args=Args}=I0|Is],
Regs, FrameSize, VarMap, Acc) ->
#{def_regs := DefRegs,
alias := Alias,
literals := Literals0} = Anno,
literals := Literals0,
live := NumLive0} = Anno0,
Literals1 = [{get_original_name(#b_var{name=Var}, VarMap, Alias),Val} ||
{Val,Var} <- Literals0],
Literals = [{hd(Vars),[{literal,Val}]} ||
{Vars,Val} <- Literals1, Vars =/= []],
LiveRegs = [{map_get(V, Regs),get_original_name(V, VarMap, Alias)} ||
V <- DefRegs,
not is_beam_register(V)],
S0 = sofs:family(LiveRegs, [{reg,[variable]}]),
RegVarMap = [{map_get(V, Regs),get_original_name(V, VarMap, Alias)} ||
V <- DefRegs,
not is_beam_register(V)],
S0 = sofs:family(RegVarMap, [{reg,[variable]}]),
S1 = sofs:family_to_relation(S0),
S2 = sofs:converse(S1),
S3 = sofs:relation_to_family(S2),
S = Literals ++ sofs:to_external(S3),
Info = {FrameSize,S},
NumLive = max(NumLive0, num_live(DefRegs, Regs)),
Info = {FrameSize,NumLive,S},
I = I0#cg_set{args=Args++[#b_literal{val=Info}]},
add_debug_info_is(Is, Regs, FrameSize, VarMap, [I|Acc]);
add_debug_info_is([I|Is], Regs, FrameSize, VarMap, Acc) ->
add_debug_info_is([#cg_set{}=I|Is], Regs, FrameSize, VarMap, Acc) ->
add_debug_info_is(Is, Regs, FrameSize, VarMap, [I|Acc]);
add_debug_info_is([], _Regs, FrameSize, VarMap, Info) ->
{reverse(Info),VarMap,FrameSize}.
Expand Down
17 changes: 17 additions & 0 deletions lib/compiler/src/beam_ssa_pre_codegen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2846,6 +2846,23 @@ res_place_gc_instrs([#b_set{op=call}=I|Is], Acc) ->
[_|_] ->
res_place_gc_instrs(Is, [I,gc|Acc])
end;
res_place_gc_instrs([#b_set{anno=Anno,op=executable_line}=I|Is], Acc0) ->
case is_map_key(alias, Anno) of
true ->
%% This instruction is for debugging. Treat it as an
%% instruction that can garbage collect to ensure that we
%% don't leave any uninitialized X registers in between
%% initialized X registers.
res_place_gc_instrs(Is, [gc,I|Acc0]);
false ->
%% Used for coverage. Treat it as a neutral instruction.
case Acc0 of
[test_heap|Acc] ->
res_place_gc_instrs(Is, [test_heap,I|Acc]);
Acc ->
res_place_gc_instrs(Is, [I|Acc])
end
end;
res_place_gc_instrs([#b_set{op=Op,args=Args}=I|Is], Acc0) ->
case beam_ssa_codegen:classify_heap_need(Op, Args) of
neutral ->
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler/src/beam_trim.erl
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,11 @@ remap_block([{set,Ds0,Ss0,Info}|Is], Remap) ->
[{set,Ds,Ss,Info}|remap_block(Is, Remap)];
remap_block([], _) -> [].

remap_debug_info({FrameSize0,Vars0}, {Trim,Map}) ->
remap_debug_info({FrameSize0,LiveRegs,Vars0}, {Trim,Map}) ->
FrameSize = FrameSize0 - Trim,
Vars = [{Name,[remap_arg(Arg, Trim, Map) || Arg <- Args]} ||
{Name,Args} <- Vars0],
{FrameSize,Vars}.
{FrameSize,LiveRegs,Vars}.

remap_args(Args, {Trim,Map}) ->
[remap_arg(Arg, Trim, Map) || Arg <- Args].
Expand Down
6 changes: 5 additions & 1 deletion lib/compiler/src/beam_validator.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2161,13 +2161,17 @@ validate_select_tuple_arity(Fail, [], _, #vst{}=Vst) ->
%% Validate executable_line instructions in the presence of BEAM debug info.
%%

validate_executable_line({Stk,Vars}, #vst{current=St}=Vst) ->
validate_executable_line({Stk,Live,Vars}, #vst{current=St}=Vst0) ->
case St of
#st{numy=Stk} ->
ok;
#st{numy=ActualStk} ->
error({beam_debug_info,frame_size,Stk,actual,ActualStk})
end,

verify_live(Live, Vst0),
verify_y_init(Vst0),
Vst = prune_x_regs(Live, Vst0),
_ = [validate_el_vars(Regs, Name, Vst) || {Name,Regs} <- Vars],
Vst.

Expand Down

0 comments on commit c048cca

Please sign in to comment.