1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% Purpose : Converts intermediate assembly code to final format. 21 22-module(beam_flatten). 23 24-export([module/2]). 25 26-import(lists, [reverse/1,reverse/2]). 27 28-spec module(beam_utils:module_code(), [compile:option()]) -> 29 {'ok',beam_utils:module_code()}. 30 31module({Mod,Exp,Attr,Fs,Lc}, _Opt) -> 32 {ok,{Mod,Exp,Attr,[function(F) || F <- Fs],Lc}}. 33 34function({function,Name,Arity,CLabel,Is0}) -> 35 Is1 = block(Is0), 36 Is = opt(Is1), 37 {function,Name,Arity,CLabel,Is}. 38 39block(Is) -> 40 block(Is, []). 41 42block([{block,Is0}|Is1], Acc) -> block(Is1, norm_block(Is0, Acc)); 43block([I|Is], Acc) -> block(Is, [I|Acc]); 44block([], Acc) -> reverse(Acc). 45 46norm_block([{set,[],[],{alloc,R,Alloc}}|Is], Acc0) -> 47 case insert_alloc_in_bs_init(Acc0, Alloc) of 48 impossible -> 49 norm_block(Is, reverse(norm_allocate(Alloc, R), Acc0)); 50 Acc -> 51 norm_block(Is, Acc) 52 end; 53norm_block([{set,[D1],[S],get_hd},{set,[D2],[S],get_tl}|Is], Acc) -> 54 I = {get_list,S,D1,D2}, 55 norm_block(Is, [I|Acc]); 56norm_block([I|Is], Acc) -> norm_block(Is, [norm(I)|Acc]); 57norm_block([], Acc) -> Acc. 58 59norm({set,[D],As,{bif,N,F}}) -> {bif,N,F,As,D}; 60norm({set,[D],As,{alloc,R,{gc_bif,N,F}}}) -> {gc_bif,N,F,R,As,D}; 61norm({set,[D],[],init}) -> {init,D}; 62norm({set,[D],[S],move}) -> {move,S,D}; 63norm({set,[D],[S],fmove}) -> {fmove,S,D}; 64norm({set,[D],[S],fconv}) -> {fconv,S,D}; 65norm({set,[D],[S1,S2],put_list}) -> {put_list,S1,S2,D}; 66norm({set,[D],[],{put_tuple,A}}) -> {put_tuple,A,D}; 67norm({set,[],[S],put}) -> {put,S}; 68norm({set,[D],[S],{get_tuple_element,I}}) -> {get_tuple_element,S,I,D}; 69norm({set,[],[S,D],{set_tuple_element,I}}) -> {set_tuple_element,S,D,I}; 70norm({set,[D],[S],get_hd}) -> {get_hd,S,D}; 71norm({set,[D],[S],get_tl}) -> {get_tl,S,D}; 72norm({set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}}) -> 73 {put_map,F,Op,S,D,R,{list,Puts}}; 74norm({set,[],[],remove_message}) -> remove_message; 75norm({set,[],[],fclearerror}) -> fclearerror; 76norm({set,[],[],fcheckerror}) -> {fcheckerror,{f,0}}; 77norm({set,[],[],{line,_}=Line}) -> Line. 78 79norm_allocate({_Zero,nostack,Nh,[]}, Regs) -> 80 [{test_heap,Nh,Regs}]; 81norm_allocate({zero,0,Nh,[]}, Regs) -> 82 norm_allocate({nozero,0,Nh,[]}, Regs); 83norm_allocate({zero,Ns,0,[]}, Regs) -> 84 [{allocate_zero,Ns,Regs}]; 85norm_allocate({zero,Ns,Nh,[]}, Regs) -> 86 [{allocate_heap_zero,Ns,Nh,Regs}]; 87norm_allocate({nozero,Ns,0,Inits}, Regs) -> 88 [{allocate,Ns,Regs}|Inits]; 89norm_allocate({nozero,Ns,Nh,Inits}, Regs) -> 90 [{allocate_heap,Ns,Nh,Regs}|Inits]. 91 92%% insert_alloc_in_bs_init(ReverseInstructionStream, AllocationInfo) -> 93%% impossible | ReverseInstructionStream' 94%% A bs_init/6 instruction should not be followed by a test heap instruction. 95%% Given the AllocationInfo from a test heap instruction, merge the 96%% allocation amounts into the previous bs_init/6 instruction (if any). 97%% 98insert_alloc_in_bs_init([{bs_put,_,_,_}=I|Is], Alloc) -> 99 %% The instruction sequence ends with an bs_put/4 instruction. 100 %% We'll need to search backwards for the bs_init/6 instruction. 101 insert_alloc_1(Is, Alloc, [I]); 102insert_alloc_in_bs_init(_, _) -> impossible. 103 104insert_alloc_1([{bs_init=Op,Fail,Info0,Live,Ss,Dst}|Is], 105 {_,nostack,Ws2,[]}, Acc) when is_integer(Live) -> 106 %% The number of extra heap words is always in the second position 107 %% in the Info tuple. 108 Ws1 = element(2, Info0), 109 Al = beam_utils:combine_heap_needs(Ws1, Ws2), 110 Info = setelement(2, Info0, Al), 111 I = {Op,Fail,Info,Live,Ss,Dst}, 112 reverse(Acc, [I|Is]); 113insert_alloc_1([{bs_put,_,_,_}=I|Is], Alloc, Acc) -> 114 insert_alloc_1(Is, Alloc, [I|Acc]). 115 116%% opt(Is0) -> Is 117%% Simple peep-hole optimization to move a {move,Any,{x,0}} past 118%% any kill up to the next call instruction. (To give the loader 119%% an opportunity to combine the 'move' and the 'call' instructions.) 120%% 121opt(Is) -> 122 opt_1(Is, []). 123 124opt_1([{move,_,{x,0}}=I|Is0], Acc0) -> 125 case move_past_kill(Is0, I, Acc0) of 126 impossible -> opt_1(Is0, [I|Acc0]); 127 {Is,Acc} -> opt_1(Is, Acc) 128 end; 129opt_1([I|Is], Acc) -> 130 opt_1(Is, [I|Acc]); 131opt_1([], Acc) -> reverse(Acc). 132 133move_past_kill([{kill,Src}|_], {move,Src,_}, _) -> 134 impossible; 135move_past_kill([{kill,_}=I|Is], Move, Acc) -> 136 move_past_kill(Is, Move, [I|Acc]); 137move_past_kill([{trim,N,_}=I|Is], {move,Src,Dst}=Move, Acc) -> 138 case Src of 139 {y,Y} when Y < N-> impossible; 140 {y,Y} -> {Is,[{move,{y,Y-N},Dst},I|Acc]}; 141 _ -> {Is,[Move,I|Acc]} 142 end; 143move_past_kill(Is, Move, Acc) -> 144 {Is,[Move|Acc]}. 145