anchor.diff:              end, Labels).
   
   -spec vvars_block(Id, State) -> #vvars{} when
  -    Id :: beam_ssa:label(),
  -    State :: #vvars{}.
  +      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(Blocks, State) -> #vvars{} when
  -    Blocks :: list(beam_ssa:b_blk()),
  -    State :: #vvars{}.
  +-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 = #b_var{ name = DstName }, op = phi } | Is], State0) ->
  +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(DstName, State0));
  -vvars_block_1([#b_set{ dst = #b_var{ name = DstName }, args = Args }=I | Is], State0) ->
  -    ok = vvars_assert_args(Args, I, State0),
  -    vvars_block_1(Is, vvars_save_var(DstName, State0)).
  +    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{}.
  +      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;
  
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:     vvars_terminator_1(Labels, From, State).
  
  -spec vvars_terminator_1(Labels, From, State) -> #vvars{} when
        Labels :: list(beam_ssa:label()),
        From :: beam_ssa:label(),
        State :: #vvars{}.
  vvars_terminator_1(Labels0, From, State0) ->
      %% Filter out all branches that have already been taken. This should result
      %% in either all of Labels0 or an empty list.
      Labels = [To || To <- Labels0,
                      not maps:is_key({From, To}, State0#vvars.branch_def_vars)],
      true = Labels =:= Labels0 orelse Labels =:= [], %Assertion
      State1 = foldl(fun(To, State) ->
                             vvars_save_branch(From, To, State)
                     end, State0, Labels),
      foldl(fun(To, State) ->
                    vvars_block(To, State)
            end, State1, Labels).
  
  %% Gets all variable names in args, ignoring literals etc
  -spec vvars_get_variables(Args) -> list(beam_ssa:b_var()) when
        Args :: list(beam_ssa:argument()).
  vvars_get_variables(Args) ->
      [Var || #b_var{}=Var <- Args].
  
  %% Checks that all variables in Args are defined in all paths leading to the
  %% current State.
  -spec vvars_assert_args(Args, I, State) -> ok when
        Args :: list(beam_ssa:argument()),
        I :: beam_ssa:terminator() | beam_ssa:b_set(),
        State :: #vvars{}.
  vvars_assert_args(Args, I, #vvars{defined_vars=DefVars}=State) ->
      foreach(fun(#b_remote{mod=Mod,name=Name}) ->
                      vvars_assert_args([Mod,Name], I, State);
                 (#b_var{}=Var) ->
                      case gb_sets:is_member(Var, DefVars) of
                          true -> ok;
                          false -> throw({unknown_variable,Var,I})
                      end;
                 (_) -> ok
              end, Args).
  
  %% Checks that all given labels are defined in State.
  -spec vvars_assert_labels(Labels, I, State) -> ok when
        Labels :: list(beam_ssa:label()),
        I :: beam_ssa:terminator(),
        State :: #vvars{}.
  vvars_assert_labels(Labels, I, #vvars{blocks=Blocks}) ->
      foreach(fun(Label) ->
                      case maps:is_key(Label, Blocks) of
                          false -> throw({unknown_block, Label, I});
                          true -> ok
                      end
              end, Labels).
  
  -spec vvars_save_branch(From, To, State) -> #vvars{} when
        From :: beam_ssa:label(),
        To :: beam_ssa:label(),
        State :: #vvars{}.
  vvars_save_branch(From, To, State) ->
      DefVars = State#vvars.defined_vars,
      Branches0 = State#vvars.branch_def_vars,
  