anchor.diff:  is_pure_test({test,has_map_fields,_,[_|_]}) -> true;
   is_pure_test({test,is_bitstr,_,[_]}) -> true;
   is_pure_test({test,is_function2,_,[_,_]}) -> true;
  -is_pure_test({test,Op,_,Ops}) -> 
  +is_pure_test({test,Op,_,Ops}) ->
       erl_internal:new_type_test(Op, length(Ops)).
   
   %% split_even/1
  
positive.code: -type fail() :: beam_asm:fail() | 'fail'.
  -type test() :: {'test',atom(),fail(),[beam_asm:src()]} |
  		{'test',atom(),fail(),integer(),list(),beam_asm:reg()}.
  -type result_cache() :: gb_trees:tree(beam_asm:label(), 'killed' | 'used').
  
  -record(live,
  	{lbl :: code_index(),            %Label to code index.
  	 res :: result_cache()}).        %Result cache for each label.
  
  %% is_killed(Register, [Instruction], State) -> true|false
  %%  Determine whether a register is killed by the instruction sequence.
  %%  If true is returned, it means that the register will not be
  %%  referenced in ANY way (not even indirectly by an allocate instruction);
  %%  i.e. it is OK to enter the instruction sequence with Register
  %%  containing garbage.
  %%
  %%  The state (constructed by index_instructions/1) is used to allow us
  %%  to determine the kill state across branches.
  
  -spec is_killed(beam_asm:reg(), [instruction()], code_index()) -> boolean().
  
  is_killed(R, Is, D) ->
      St = #live{lbl=D,res=gb_trees:empty()},
      case check_liveness(R, Is, St) of
  	{killed,_} -> true;
  	{exit_not_used,_} -> false;
  	{_,_} -> false
      end.
  
  %% is_killed_at(Reg, Lbl, State) -> true|false
  %%  Determine whether Reg is killed at label Lbl.
  
  -spec is_killed_at(beam_asm:reg(), beam_asm:label(), code_index()) -> boolean().
  
  is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
      St0 = #live{lbl=D,res=gb_trees:empty()},
      case check_liveness_at(R, Lbl, St0) of
  	{killed,_} -> true;
  	{exit_not_used,_} -> false;
  	{_,_} -> false
      end.
  
  %% is_not_used(Register, [Instruction], State) -> true|false
  %%  Determine whether a register is never used in the instruction sequence
  %%  (it could still be referenced by an allocate instruction, meaning that
  %%  it MUST be initialized, but that its value does not matter).
  %%    The state is used to allow us to determine the usage state
  %%  across branches.
  
  -spec is_not_used(beam_asm:reg(), [instruction()], code_index()) -> boolean().
  
  is_not_used(R, Is, D) ->
      St = #live{lbl=D,res=gb_trees:empty()},
      case check_liveness(R, Is, St) of
  	{used,_} -> false;
  	{exit_not_used,_} -> true;
  	{_,_} -> true
      end.
  
  %% index_labels(FunctionIs) -> State
  %%  Index the instruction sequence so that we can quickly
  %%  look up the instruction following a specific label.
  
  -spec index_labels([instruction()]) -> code_index().
  
  index_labels(Is) ->
      index_labels_1(Is, []).
  
  %% empty_label_index() -> State
  %%  Create an empty label index.
  
  -spec empty_label_index() -> code_index().
  
  empty_label_index() ->
      gb_trees:empty().
  
  %% index_label(Label, [Instruction], State) -> State
  %%  Add an index for a label.
  
  -spec index_label(beam_asm:label(), [instruction()], code_index()) ->
     code_index().
  
  index_label(Lbl, Is0, Acc) ->
      Is = drop_labels(Is0),
      gb_trees:enter(Lbl, Is, Acc).
  
  
  %% code_at(Label, State) -> [I].
  %%  Retrieve the code at the given label.
  
  -spec code_at(beam_asm:label(), code_index()) -> [instruction()].
  
  code_at(L, Ll) ->
      gb_trees:get(L, Ll).
  
  %% replace_labels(FunctionIs, Tail, ReplaceDb, Fallback) -> FunctionIs.
  %%  Replace all labels in instructions according to the ReplaceDb.
  
negative.code: %% %CopyrightEnd%
  %%
  %% Purpose : Common utilities used by several optimization passes.
  %%
  
  -module(beam_utils).
  -export([replace_labels/4,is_pure_test/1,split_even/1]).
  
  -export_type([code_index/0,module_code/0,instruction/0]).
  
  -import(lists, [map/2,reverse/1]).
  
  %% instruction() describes all instructions that are used during optimization
  %% (from beam_a to beam_z).
  