aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2018-08-13 09:53:58 +0200
committerBjörn Gustavsson <[email protected]>2018-08-17 09:51:00 +0200
commit004257f6fc1ea9efea1c99a93211e2f39b1d14ad (patch)
treed765a97c8d23e340a2c3415400266daf04e95c9a /lib/hipe
parentf107c76b7996c731670e52788801f534fa5326aa (diff)
downloadotp-004257f6fc1ea9efea1c99a93211e2f39b1d14ad.tar.gz
otp-004257f6fc1ea9efea1c99a93211e2f39b1d14ad.tar.bz2
otp-004257f6fc1ea9efea1c99a93211e2f39b1d14ad.zip
hipe_beam_to_icode: Correct translation of get_map_elements
If one of the destination registers for get_map_elements is the same as the map source, extract that element last.
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl18
1 files changed, 17 insertions, 1 deletions
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index f429d40272..4f099baab3 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -1139,9 +1139,10 @@ trans_fun([{test,has_map_fields,{f,Lbl},Map,{list,Keys}}|Instructions], Env) ->
lists:flatten([[K, {r, 0}] || K <- Keys])),
[MapMove, TestInstructions | trans_fun(Instructions, Env2)];
trans_fun([{get_map_elements,{f,Lbl},Map,{list,KVPs}}|Instructions], Env) ->
+ KVPs1 = overwrite_map_last(Map, KVPs),
{MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
{TestInstructions, GetInstructions, Env2} =
- trans_map_query(MapVar, map_label(Lbl), Env1, KVPs),
+ trans_map_query(MapVar, map_label(Lbl), Env1, KVPs1),
[MapMove, TestInstructions, GetInstructions | trans_fun(Instructions, Env2)];
%%--- put_map_assoc ---
trans_fun([{put_map_assoc,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) ->
@@ -1563,6 +1564,21 @@ trans_type_test2(function2, Lbl, Arg, Arity, Env) ->
hipe_icode:label_name(True), map_label(Lbl)),
{[Move1,Move2,I,True],Env2}.
+
+%%
+%% Makes sure that if a get_map_elements instruction will overwrite
+%% the map source, it will be done last.
+%%
+overwrite_map_last(Map, KVPs) ->
+ overwrite_map_last2(Map, KVPs, []).
+
+overwrite_map_last2(Map, [Key,Map|KVPs], _Last) ->
+ overwrite_map_last2(Map, KVPs, [Key,Map]);
+overwrite_map_last2(Map, [Key,Val|KVPs], Last) ->
+ [Key,Val|overwrite_map_last2(Map, KVPs, Last)];
+overwrite_map_last2(_Map, [], Last) ->
+ Last.
+
%%
%% Handles the get_map_elements instruction and the has_map_fields
%% test instruction.