anchor.diff:              Ds = Ds0#{Dst=>I},
               {I, Ts, Ds, Sub0}
       end;
  -simplify(#b_set{op=succeeded,dst=Dst,args=[Arg],anno=Anno}=I,
  -         Ts0, Ds0, _Ls, Sub0) ->
  -    Type = case Ds0 of
  -               #{ Arg := #b_set{op=call} } ->
  -                   %% Calls can always throw exceptions and their return types
  -                   %% are what they return on success, so we must avoid
  -                   %% simplifying arguments in case `Arg` would become a
  -                   %% literal, which would trick 'succeeded' into thinking it
  -                   %% can't fail.
  -                   type(succeeded, [Arg], Anno, Ts0, Ds0);
  -               #{ Arg := _ } ->
  -                   Args = simplify_args([Arg], Ts0, Sub0),
  -                   type(succeeded, Args, Anno, Ts0, Ds0);
  -               #{} ->
  -                   %% The checked instruction has been removed and substituted,
  -                   %% so we can assume it always succeeds.
  -                   #{ Arg := _ } = Sub0,        %Assertion.
  -                   beam_types:make_atom(true)
  -           end,
  -    case beam_types:get_singleton_value(Type) of
  -        {ok, Lit} ->
  -            Sub = Sub0#{ Dst => #b_literal{val=Lit} },
  +simplify(#b_set{op=succeeded,dst=Dst}=I0, Ts0, Ds0, _Ls, Sub0) ->
  +    case will_succeed(I0, Ts0, Ds0, Sub0) of
  +        yes ->
  +            Lit = #b_literal{val=true},
  +            Sub = Sub0#{ Dst => Lit },
               {Lit, Sub};
  -        error ->
  -            Ts = Ts0#{ Dst => Type },
  +        no ->
  +            Lit = #b_literal{val=false},
  +            Sub = Sub0#{ Dst => Lit },
  +            {Lit, Sub};
  +        maybe ->
  +            %% Note that we never simplify args; this instruction is specific
  +            %% to the operation being checked, and simplifying could break that
  +            %% connection.
  +            I = beam_ssa:normalize(I0),
  +            Ts = Ts0#{ Dst => beam_types:make_boolean() },
               Ds = Ds0#{ Dst => I },
               {I, Ts, Ds, Sub0}
       end;
  
positive.code:                             {Es, Index + 1}
                      end, {#{}, 1}, Args),
      #t_tuple{exact=true,size=length(Args),elements=Es};
  type(succeeded, [#b_var{}=Src], _Anno, Ts, _Ds)
    when map_get(Src, Ts) =:= none ->
      beam_types:make_atom(false);
  type(succeeded, [#b_var{}=Src], _Anno, Ts, Ds) ->
      case maps:get(Src, Ds) of
          #b_set{op={bif,Bif},args=BifArgs} ->
              ArgTypes = normalized_types(BifArgs, Ts),
              case beam_call_types:will_succeed(erlang, Bif, ArgTypes) of
                  yes -> beam_types:make_atom(true);
                  no -> beam_types:make_atom(false);
                  maybe -> beam_types:make_boolean()
              end;
          #b_set{op=call,args=[#b_remote{mod=#b_literal{val=Mod},
                                         name=#b_literal{val=Func}} |
                               CallArgs]} ->
              ArgTypes = normalized_types(CallArgs, Ts),
              case beam_call_types:will_succeed(Mod, Func, ArgTypes) of
                  yes -> beam_types:make_atom(true);
                  no -> beam_types:make_atom(false);
                  maybe -> beam_types:make_boolean()
              end;
          #b_set{op=bs_get_tail} ->
              beam_types:make_atom(true);
          #b_set{op=bs_start_match,args=[_, Arg]} ->
              ArgType = raw_type(Arg, Ts),
              case beam_types:is_bs_matchable_type(ArgType) of
                  true ->
                      %% In the future we may be able to remove this instruction
                      %% altogether when we have a #t_bs_context{}, but for now
                      %% we need to keep it for compatibility with older releases
                      %% of OTP.
                      beam_types:make_atom(true);
                  false ->
                      %% Is it at all possible to match?
                      case beam_types:meet(ArgType, #t_bs_matchable{}) of
                          none -> beam_types:make_atom(false);
                          _ -> beam_types:make_boolean()
                      end
              end;
          #b_set{op=get_hd} ->
              beam_types:make_atom(true);
          #b_set{op=get_tl} ->
              beam_types:make_atom(true);
          #b_set{op=get_tuple_element} ->
              beam_types:make_atom(true);
          #b_set{op=put_tuple} ->
              beam_types:make_atom(true);
          #b_set{op=wait} ->
              beam_types:make_atom(false);
          #b_set{} ->
              beam_types:make_boolean()
      end;
  type(succeeded, [#b_literal{}], _Anno, _Ts, _Ds) ->
      beam_types:make_atom(true);
  type(_, _, _, _, _) -> any.
  
  %% We seldom know how far a match operation may advance, but we can often tell
  
negative.code:             I
      end;
  simplify(I, _Ts) -> I.
  
  will_succeed(#b_set{args=[Src]}, Ts, Ds, Sub) ->
      case {Ds, Ts} of
          {#{}, #{ Src := none }} ->
              %% Checked operation never returns.
              no;
          {#{ Src := I }, #{}} ->
              will_succeed_1(I, Src, Ts, Sub);
          {#{}, #{}} ->
              %% The checked instruction has been removed and substituted, so we
              %% can assume it always succeeds.
              true = is_map_key(Src, Sub),        %Assertion.
              yes
      end.
  
  will_succeed_1(#b_set{op=bs_get_tail}, _Src, _Ts, _Sub) ->
      yes;
  will_succeed_1(#b_set{op=bs_start_match,args=[_, Arg]}, _Src, Ts, _Sub) ->
      ArgType = raw_type(Arg, Ts),
      case beam_types:is_bs_matchable_type(ArgType) of
          true ->
              %% In the future we may be able to remove this instruction
              %% altogether when we have a #t_bs_context{}, but for now we need
              %% to keep it for compatibility with older releases of OTP.
              yes;
          false ->
              %% Is it at all possible to match?
              case beam_types:meet(ArgType, #t_bs_matchable{}) of
                  none -> no;
                  _ -> maybe
              end
      end;
  
  will_succeed_1(#b_set{op={bif,Bif},args=BifArgs}, _Src, Ts, _Sub) ->
      ArgTypes = normalized_types(BifArgs, Ts),
      beam_call_types:will_succeed(erlang, Bif, ArgTypes);
  will_succeed_1(#b_set{op=call,
                        args=[#b_remote{mod=#b_literal{val=Mod},
                              name=#b_literal{val=Func}} |
                              CallArgs]},
                 _Src, Ts, _Sub) ->
              ArgTypes = normalized_types(CallArgs, Ts),
              beam_call_types:will_succeed(Mod, Func, ArgTypes);
  
  will_succeed_1(#b_set{op=get_hd}, _Src, _Ts, _Sub) ->
      yes;
  will_succeed_1(#b_set{op=get_tl}, _Src, _Ts, _Sub) ->
      yes;
  will_succeed_1(#b_set{op=get_tuple_element}, _Src, _Ts, _Sub) ->
      yes;
  will_succeed_1(#b_set{op=put_tuple}, _Src, _Ts, _Sub) ->
      yes;
  
  %% These operations may fail even though we know their return value on success.
  will_succeed_1(#b_set{op=call}, _Src, _Ts, _Sub) ->
      maybe;
  
  will_succeed_1(#b_set{op=wait}, _Src, _Ts, _Sub) ->
      no;
  
  will_succeed_1(#b_set{}, Src, Ts, Sub) ->
      case simplify_arg(Src, Ts, Sub) of
          #b_var{}=Src ->
              %% No substitution; might fail at runtime.
              maybe;
          _ ->
              %% Substituted with literal or other variable; always succeeds.
              yes
      end.
  
  simplify_is_record(I, #t_tuple{exact=Exact,
                                 size=Size,
  