anchor.diff:      ok.
   
   -spec vvars_phi_nodes_1(Is, Id, State) -> ok when
  -    Is :: list(beam_ssa:b_set()),
  -    Id :: beam_ssa:label(),
  -    State :: #vvars{}.
  +      Is :: list(beam_ssa:b_set()),
  +      Id :: beam_ssa:label(),
  +      State :: #vvars{}.
   vvars_phi_nodes_1([#b_set{ op = phi, args = Phis }=I | Is], Id, State) ->
       ok = vvars_assert_phi_paths(Phis, I, Id, State),
       ok = vvars_assert_phi_vars(Phis, I, Id, State),
       vvars_phi_nodes_1(Is, Id, State);
   vvars_phi_nodes_1([_ | Is], Id, _State) ->
  -    case [Dst || #b_set{op=phi,dst=#b_var{name=Dst}} <- Is] of
  -        [Name|_] ->
  -            throw({phi_inside_block, Name, Id});
  +    case [Dst || #b_set{op=phi,dst=Dst} <- Is] of
  +        [Var|_] ->
  +            throw({phi_inside_block, Var, Id});
           [] ->
               ok
       end;
  
positive.code:         [_|_]=MissingPaths -> throw({missing_phi_paths, MissingPaths, I});
          [] -> ok
      end.
      %% %% The following test is sometimes useful to find missing optimizations.
      %% %% It is commented out, though, because it can be triggered by
      %% %% by weird but legal code.
      %% case ordsets:subtract(ProvidedPaths, RequiredPaths) of
      %%     [_|_]=GarbagePaths -> throw({garbage_phi_paths, GarbagePaths, I});
      %%     [] -> ok
      %% end.
  
  %% Checks whether all variables used in this phi node are defined in the branch
  %% they arrived on.
  -spec vvars_assert_phi_vars(Phis, I, Id, State) -> ok when
      Phis :: list({beam_ssa:argument(), beam_ssa:label()}),
      Id :: beam_ssa:label(),
      I :: beam_ssa:b_set(),
      State :: #vvars{}.
  vvars_assert_phi_vars(Phis, I, Id, #vvars{blocks=Blocks,
                                            branch_def_vars=BranchDefVars}) ->
      Vars = [{Var, From} || {#b_var{}=Var, From} <- Phis],
      foreach(fun({#b_var{name=VarName}, From}) ->
                      BranchKey = {From, Id},
                      case BranchDefVars of
                          #{BranchKey:=DefVars} ->
                              case gb_sets:is_member(VarName, DefVars) of
                                  true -> ok;
                                  false -> throw({unknown_variable, VarName, I})
                              end;
                          #{} ->
                              throw({unknown_phi_variable, VarName, BranchKey, I})
                      end
              end, Vars),
      Labels = [From || {#b_literal{},From} <- Phis],
  
negative.code:             end, Labels).
  
  -spec vvars_block(Id, State) -> #vvars{} when
        Id :: beam_ssa:label(),
        State :: #vvars{}.
  vvars_block(Id, State0) ->
      #{ Id := #b_blk{ is = Is, last = Terminator} } = State0#vvars.blocks,
      #{ Id := DefVars } = State0#vvars.branch_def_vars,
      State = State0#vvars{ defined_vars = DefVars },
      vvars_terminator(Terminator, Id, vvars_block_1(Is, State)).
  
  -spec vvars_block_1(Is, State) -> #vvars{} when
        Is :: list(#b_set{}),
        State :: #vvars{}.
  vvars_block_1([], State) ->
      State;
  vvars_block_1([#b_set{ dst = Dst, op = phi } | Is], State) ->
      %% We don't check phi node arguments at this point since we may not have
      %% visited their definition yet. They'll be handled later on in
      %% vvars_phi_nodes/1 after all blocks are processed.
      vvars_block_1(Is, vvars_save_var(Dst, State));
  vvars_block_1([#b_set{ dst = Dst, args = Args }=I | Is], State) ->
      ok = vvars_assert_args(Args, I, State),
      vvars_block_1(Is, vvars_save_var(Dst, State)).
  
  -spec vvars_terminator(Terminator, From, State) -> #vvars{} when
        Terminator :: beam_ssa:terminator(),
        From :: beam_ssa:label(),
        State :: #vvars{}.
  vvars_terminator(#b_ret{ arg = Arg }=I, _From, State) ->
      ok = vvars_assert_args([Arg], I, State),
      State;
  