From 47a2ff39ac75c69b41f90f05a63fd9a2e6c0b36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Sat, 1 Sep 2018 10:57:33 +0200 Subject: Introduce a put_tuple2 instruction Sometimes when building a tuple, there is no way to avoid an extra `move` instruction. Consider this code: make_tuple(A) -> {ok,A}. The corresponding BEAM code looks like this: {test_heap,3,1}. {put_tuple,2,{x,1}}. {put,{atom,ok}}. {put,{x,0}}. {move,{x,1},{x,0}}. return. To avoid overwriting the source register `{x,0}`, a `move` instruction is necessary. The problem doesn't exist when building a list: %% build_list(A) -> [A]. {test_heap,2,1}. {put_list,{x,0},nil,{x,0}}. return. Introduce a new `put_tuple2` instruction that builds a tuple in a single instruction, so that the `move` instruction can be eliminated: %% make_tuple(A) -> {ok,A}. {test_heap,3,1}. {put_tuple2,{x,0},{list,[{atom,ok},{x,0}]}}. return. Note that the BEAM loader already combines `put_tuple` and `put` instructions into an internal instruction similar to `put_tuple2`. Therefore the introduction of the new instruction will not speed up execution of tuple building itself, but it will be less work for the loader to load the new instruction. --- lib/compiler/src/beam_ssa_pre_codegen.erl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'lib/compiler/src/beam_ssa_pre_codegen.erl') diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl index bbc3739eb5..54aa2efaf6 100644 --- a/lib/compiler/src/beam_ssa_pre_codegen.erl +++ b/lib/compiler/src/beam_ssa_pre_codegen.erl @@ -79,8 +79,9 @@ {'ok',beam_ssa:b_module()}. module(#b_module{body=Fs0}=Module, Opts) -> + FixTuples = proplists:get_bool(no_put_tuple2, Opts), ExtraAnnos = proplists:get_bool(dprecg, Opts), - Ps = passes(ExtraAnnos), + Ps = passes(FixTuples, ExtraAnnos), Fs = functions(Fs0, Ps), {ok,Module#b_module{body=Fs}}. @@ -113,13 +114,16 @@ functions([], _Ps) -> []. }). -define(PASS(N), {N,fun N/1}). -passes(ExtraAnnos) -> +passes(FixTuples, ExtraAnnos) -> Ps = [?PASS(assert_no_critical_edges), %% Preliminaries. ?PASS(fix_bs), ?PASS(sanitize), - ?PASS(fix_tuples), + case FixTuples of + false -> ignore; + true -> ?PASS(fix_tuples) + end, ?PASS(place_frames), ?PASS(fix_receives), @@ -151,10 +155,7 @@ passes(ExtraAnnos) -> ?PASS(fix_aliased_regs), ?PASS(frame_size), ?PASS(turn_yregs)], - case ExtraAnnos of - false -> [P || P <- Ps, P =/= ignore]; - true -> Ps - end. + [P || P <- Ps, P =/= ignore]. function(#b_function{anno=Anno,args=Args,bs=Blocks0,cnt=Count0}=F0, Ps) -> try @@ -693,9 +694,11 @@ prune_phi(#b_set{args=Args0}=Phi, Reachable) -> %%% %% fix_tuples(St0) -> St. -%% We must split tuple creation into two instruction to mirror the -%% the way tuples are created in BEAM. Each put_tuple instruction is -%% split into put_tuple_arity followed by put_tuple_elements. +%% If compatibility with a previous version of Erlang has been +%% requested, tuple creation must be split into two instruction to +%% mirror the the way tuples are created in BEAM prior to OTP 22. +%% Each put_tuple instruction is split into put_tuple_arity followed +%% by put_tuple_elements. fix_tuples(#st{ssa=Blocks0,cnt=Count0}=St) -> F = fun (#b_set{op=put_tuple,args=Args}=Put, C0) -> -- cgit v1.2.3