aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2018-09-24 12:29:09 +0200
committerBjörn Gustavsson <[email protected]>2018-09-26 12:49:26 +0200
commit7318da161d5ed7987c6e524e670219337160abc1 (patch)
tree783a83e6cee3a69a49203b2fb1480d0054c54dab
parent8e12d5652d6bb12f18d8a1fe3a1cc0b1ebed4111 (diff)
downloadotp-7318da161d5ed7987c6e524e670219337160abc1.tar.gz
otp-7318da161d5ed7987c6e524e670219337160abc1.tar.bz2
otp-7318da161d5ed7987c6e524e670219337160abc1.zip
beam_ssa_pre_codegen: Fix bug in sanitization of get_map_element
The source map for `get_map_element` is not supposed to be a literal, and the sanitization code is supposed to ensure that. The sanitization incorrectly translated this code: Map = get_tuple_element literal {ok,#{key=>value}}, literal 1 Var = get_map_element Map, literal {a,key} To this code: Var = get_map_element literal #{key=>value}, literal {a,key} Make sure to substitute the arguments for `get_map_element` before looking for a literal source map.
-rw-r--r--lib/compiler/src/beam_ssa_pre_codegen.erl43
1 files changed, 28 insertions, 15 deletions
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
index ca3b792ed6..811f3d79e5 100644
--- a/lib/compiler/src/beam_ssa_pre_codegen.erl
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -574,21 +574,24 @@ sanitize([], Count, Blocks0, Values) ->
false -> remove_unreachable(Ls, Blocks, Reachable, [])
end,Count}.
-sanitize_is([#b_set{op=get_map_element,
- args=[#b_literal{}=Map,Key]}=I0|Is],
- Count0, Values, _Changed, Acc) ->
- {MapVar,Count} = new_var('@ssa_map', Count0),
- I = I0#b_set{args=[MapVar,Key]},
- Copy = #b_set{op=copy,dst=MapVar,args=[Map]},
- sanitize_is(Is, Count, Values, true, [I,Copy|Acc]);
+sanitize_is([#b_set{op=get_map_element,args=Args0}=I0|Is],
+ Count0, Values, Changed, Acc) ->
+ case sanitize_args(Args0, Values) of
+ [#b_literal{}=Map,Key] ->
+ %% Bind the literal map to a variable.
+ {MapVar,Count} = new_var('@ssa_map', Count0),
+ I = I0#b_set{args=[MapVar,Key]},
+ Copy = #b_set{op=copy,dst=MapVar,args=[Map]},
+ sanitize_is(Is, Count, Values, true, [I,Copy|Acc]);
+ [_,_]=Args0 ->
+ sanitize_is(Is, Count0, Values, Changed, [I0|Acc]);
+ [_,_]=Args ->
+ I = I0#b_set{args=Args},
+ sanitize_is(Is, Count0, Values, Changed, [I|Acc])
+ end;
sanitize_is([#b_set{op=Op,dst=Dst,args=Args0}=I0|Is0],
- Count, Values, Changed, Acc) ->
- Args = map(fun(Var) ->
- case Values of
- #{Var:=New} -> New;
- #{} -> Var
- end
- end, Args0),
+ Count, Values, Changed0, Acc) ->
+ Args = sanitize_args(Args0, Values),
case sanitize_instr(Op, Args, I0) of
{value,Value0} ->
Value = #b_literal{val=Value0},
@@ -596,7 +599,9 @@ sanitize_is([#b_set{op=Op,dst=Dst,args=Args0}=I0|Is0],
{ok,I} ->
sanitize_is(Is0, Count, Values, true, [I|Acc]);
ok ->
- sanitize_is(Is0, Count, Values, Changed, [I0|Acc])
+ I = I0#b_set{args=Args},
+ Changed = Changed0 orelse Args =/= Args0,
+ sanitize_is(Is0, Count, Values, Changed, [I|Acc])
end;
sanitize_is([], Count, Values, Changed, Acc) ->
case Changed of
@@ -606,6 +611,14 @@ sanitize_is([], Count, Values, Changed, Acc) ->
no_change
end.
+sanitize_args(Args, Values) ->
+ map(fun(Var) ->
+ case Values of
+ #{Var:=New} -> New;
+ #{} -> Var
+ end
+ end, Args).
+
sanitize_instr({bif,Bif}, [#b_literal{val=Lit}], _I) ->
case erl_bifs:is_pure(erlang, Bif, 1) of
false ->