File 1883-Remove-beam_digraph-using-graph-module-instead.patch of Package erlang

From 98e83675b7bcd3be6e38884eb36483383eb66029 Mon Sep 17 00:00:00 2001
From: Richard Carlsson <carlsson.richard@gmail.com>
Date: Fri, 9 Jan 2026 23:40:58 +0100
Subject: [PATCH 3/3] Remove beam_digraph, using graph module instead

---
 lib/compiler/src/Makefile           |   1 -
 lib/compiler/src/beam_digraph.erl   | 338 ----------------------------
 lib/compiler/src/beam_ssa_alias.erl |   2 +-
 lib/compiler/src/beam_ssa_bool.erl  | 126 +++++------
 lib/compiler/src/beam_ssa_recv.erl  |  14 +-
 lib/compiler/src/beam_ssa_ss.erl    | 148 ++++++------
 lib/compiler/src/compile.erl        |   3 +-
 lib/compiler/src/compiler.app.src   |   3 +-
 8 files changed, 147 insertions(+), 488 deletions(-)
 delete mode 100644 lib/compiler/src/beam_digraph.erl

diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 631f76e3ee..7434a9b4d2 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -56,7 +56,6 @@ MODULES =  \
 	beam_core_to_ssa \
 	beam_clean \
 	beam_dict \
-	beam_digraph \
 	beam_disasm \
 	beam_doc \
 	beam_flatten \
diff --git a/lib/compiler/src/beam_digraph.erl b/lib/compiler/src/beam_digraph.erl
deleted file mode 100644
index 71a94bca14..0000000000
--- a/lib/compiler/src/beam_digraph.erl
+++ /dev/null
@@ -1,338 +0,0 @@
-
-%%
-%% %CopyrightBegin%
-%%
-%% SPDX-License-Identifier: Apache-2.0
-%%
-%% Copyright Ericsson AB 2019-2025. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%%     http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Digraph data type. Similar to the digraph module, but provides a
-%% functional API. The functional API allows us to revert to a
-%% previous version of the digraph when an optimization that may have
-%% damaged the digraph has failed.
-%%
-
--module(beam_digraph).
--moduledoc false.
-
--export([new/0,
-         add_vertex/2, add_vertex/3, add_edge/3, add_edge/4,
-         del_edge/2, del_edges/2,
-         del_vertex/2,
-         edges/1,
-         foldv/3,
-         has_vertex/2,
-         is_path/3,
-         in_degree/2, in_edges/2, in_neighbours/2,
-         no_vertices/1,
-         out_degree/2, out_edges/2, out_neighbours/2,
-         vertex/2, vertex/3, vertices/1,
-         reverse_postorder/2,
-         roots/1,
-         topsort/1,
-         strong_components/2]).
-
-%% Debugging.
--define(DEBUG, false).
--if(?DEBUG).
--export([dump/1,dump/2,dump/3]).
--endif.
-
--import(lists, [foldl/3, reverse/1]).
-
--type edge_map() :: #{ vertex() => ordsets:ordset(vertex()) }.
--type vertice_map() :: #{ vertex() => label() }.
-
--record(dg, {vs = #{} :: vertice_map(),
-             in_es = #{} :: edge_map(),
-             out_es = #{} :: edge_map()}).
-
--type graph() :: #dg{}.
-
--type vertex() :: term().
--type label() :: term().
--type edge() :: {vertex(), vertex(), label()}.
-
--spec new() -> graph().
-new() -> #dg{}.
-
--spec add_vertex(graph(), vertex()) -> graph().
-add_vertex(Dg, V) ->
-    add_vertex(Dg, V, vertex).
-
--spec add_vertex(graph(), vertex(), label()) -> graph().
-add_vertex(Dg, V, Label) ->
-    #dg{vs=Vs0} = Dg,
-    Vs = Vs0#{V=>Label},
-    Dg#dg{vs=Vs}.
-
--spec del_vertex(graph(), vertex()) -> graph().
-del_vertex(Dg, V) ->
-    #dg{vs=Vs0,in_es=InEsMap0,out_es=OutEsMap0} = Dg,
-    InEs = maps:get(V, InEsMap0, []),
-    OutEsMap = foldl(fun({From,_,_}=E, A) -> edge_map_del(From, E, A) end,
-                     maps:remove(V, OutEsMap0), InEs),
-    OutEs = maps:get(V, OutEsMap0, []),
-    InEsMap = foldl(fun({_,To,_}=E, A) -> edge_map_del(To, E, A) end,
-                    maps:remove(V, InEsMap0), OutEs),
-    Vs = maps:remove(V, Vs0),
-    Dg#dg{vs=Vs,in_es=InEsMap,out_es=OutEsMap}.
-
--spec add_edge(graph(), vertex(), vertex()) -> graph().
-add_edge(Dg, From, To) ->
-    add_edge(Dg, From, To, edge).
-
--spec add_edge(graph(), vertex(), vertex(), label()) -> graph().
-add_edge(Dg, From, To, Label) ->
-    #dg{in_es=InEsMap0,out_es=OutEsMap0} = Dg,
-    Name = {From,To,Label},
-    InEsMap = edge_map_add(To, Name, InEsMap0),
-    OutEsMap = edge_map_add(From, Name, OutEsMap0),
-    Dg#dg{in_es=InEsMap,out_es=OutEsMap}.
-
-edge_map_add(V, E, EsMap) ->
-    Es0 = maps:get(V, EsMap, []),
-    Es = ordsets:add_element(E, Es0),
-    EsMap#{V=>Es}.
-
--spec del_edge(graph(), edge()) -> graph().
-del_edge(Dg, {From,To,_}=E) ->
-    #dg{in_es=InEsMap0,out_es=OutEsMap0} = Dg,
-    InEsMap = edge_map_del(To, E, InEsMap0),
-    OutEsMap = edge_map_del(From, E, OutEsMap0),
-    Dg#dg{in_es=InEsMap,out_es=OutEsMap}.
-
-edge_map_del(V, E, EsMap) ->
-    Es0 = maps:get(V, EsMap, []),
-    Es = Es0 -- [E],
-    EsMap#{V:=Es}.
-
--spec del_edges(graph(), [edge()]) -> graph().
-del_edges(G, Es) when is_list(Es) ->
-    foldl(fun(E, A) -> del_edge(A, E) end, G, Es).
-
-%% Fold over the vertices of the graph, the order is unspecified.
--spec foldv(graph(), fun((vertex(), label(), any()) -> any()), any()) -> any().
-foldv(#dg{vs=Vs}, Fun, Acc) ->
-    maps:fold(Fun, Acc, Vs).
-
--spec has_vertex(graph(), vertex()) -> boolean().
-has_vertex(#dg{vs=Vs}, V) ->
-    is_map_key(V, Vs).
-
--spec in_degree(graph(), vertex()) -> non_neg_integer().
-in_degree(#dg{in_es=InEsMap}, V) ->
-    length(maps:get(V, InEsMap, [])).
-
--spec in_edges(graph(), vertex()) -> [edge()].
-in_edges(#dg{in_es=InEsMap}, V) ->
-    maps:get(V, InEsMap, []).
-
--spec in_neighbours(graph(), vertex()) -> [vertex()].
-in_neighbours(#dg{in_es=InEsMap}, V) ->
-    [From || {From,_,_} <:- maps:get(V, InEsMap, [])].
-
--spec is_path(graph(), vertex(), vertex()) -> boolean().
-is_path(G, From, To) ->
-    Seen = sets:new(),
-    try
-        _ = is_path_1([From], To, G, Seen),
-        false
-    catch
-        throw:true ->
-            true
-    end.
-
-is_path_1([To|_], To, _G, _Seen) ->
-    throw(true);
-is_path_1([V|Vs], To, G, Seen0) ->
-    case sets:is_element(V, Seen0) of
-        true ->
-            is_path_1(Vs, To, G, Seen0);
-        false ->
-            Seen1 = sets:add_element(V, Seen0),
-            Successors = out_neighbours(G, V),
-            Seen = is_path_1(Successors, To, G, Seen1),
-            is_path_1(Vs, To, G, Seen)
-    end;
-is_path_1([], _To, _G, Seen) ->
-    Seen.
-
--spec out_degree(graph(), vertex()) -> non_neg_integer().
-out_degree(#dg{out_es=OutEsMap}, V) ->
-    length(maps:get(V, OutEsMap, [])).
-
--spec out_edges(graph(), vertex()) -> [edge()].
-out_edges(#dg{out_es=OutEsMap}, V) ->
-    maps:get(V, OutEsMap, []).
-
--spec out_neighbours(graph(), vertex()) -> [vertex()].
-out_neighbours(#dg{out_es=OutEsMap}, V) ->
-    [To || {_,To,_} <:- maps:get(V, OutEsMap, [])].
-
--spec no_vertices(graph()) -> non_neg_integer().
-no_vertices(#dg{vs=Vs}) ->
-    map_size(Vs).
-
--spec vertex(graph(), vertex()) -> label().
-vertex(#dg{vs=Vs}, V) ->
-    map_get(V, Vs).
-
-%% As vertex/2 but if the vertex does not exist a default value is
-%% returned.
--spec vertex(graph(), vertex(), label()) -> label().
-vertex(#dg{vs=Vs}, V, Default) ->
-    maps:get(V, Vs, Default).
-
--spec vertices(graph()) -> [{vertex(), label()}].
-vertices(#dg{vs=Vs}) ->
-    maps:to_list(Vs).
-
--spec reverse_postorder(graph(), [vertex()]) -> [vertex()].
-reverse_postorder(G, Vs) ->
-    Seen = sets:new(),
-    {RPO, _} = reverse_postorder_1(Vs, G, Seen, []),
-    RPO.
-
-reverse_postorder_1([V|Vs], G, Seen0, Acc0) ->
-    case sets:is_element(V, Seen0) of
-        true ->
-            reverse_postorder_1(Vs, G, Seen0, Acc0);
-        false ->
-            Seen1 = sets:add_element(V, Seen0),
-            Successors = out_neighbours(G, V),
-            {Acc,Seen} = reverse_postorder_1(Successors, G, Seen1, Acc0),
-            reverse_postorder_1(Vs, G, Seen, [V|Acc])
-    end;
-reverse_postorder_1([], _, Seen, Acc) ->
-    {Acc, Seen}.
-
--spec roots(graph()) -> [vertex()].
-roots(G) ->
-    roots_1(vertices(G), G).
-
-roots_1([{V,_}|Vs], G) ->
-    case in_degree(G, V) of
-        0 ->
-            [V|roots_1(Vs, G)];
-        _ ->
-            roots_1(Vs, G)
-    end;
-roots_1([], _G) -> [].
-
--spec topsort(graph()) -> [vertex()].
-topsort(G) ->
-    Seen = roots(G),
-    reverse_postorder(G, Seen).
-
--spec edges(graph()) -> [edge()].
-edges(#dg{out_es=OutEsMap}) ->
-    maps:fold(fun(_, Es, Acc) ->
-                      Es ++ Acc
-              end, [], OutEsMap).
-
-%%
-%% Kosaraju's algorithm
-%%
-%% Visit each node in reverse post order. If the node has not been assigned to
-%% a component yet, start a new component and add all of its in-neighbors to it
-%% if they don't yet belong to one. Keep going until all nodes have been
-%% visited.
-%%
-%% https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
-%%
-
--spec strong_components(graph(), [vertex()]) -> ComponentMap when
-      %% Vertices together with their components.
-      ComponentMap :: #{ vertex() => [vertex()] }.
-strong_components(G, Vs) ->
-    sc_1(Vs, G, #{}, #{}).
-
-sc_1([V | Vs], G, Roots0, Components) when not is_map_key(V, Roots0) ->
-    %% V has not been assigned to a component, start a new one with this one as
-    %% the root.
-    {Roots, Component} = sc_2([V], G, V, Roots0, []),
-    sc_1(Vs, G, Roots, Components#{ V => Component });
-sc_1([V | Vs], G, Roots, Components0) ->
-    %% V is already part of a component, copy it over.
-    Root = map_get(V, Roots),
-    Components = Components0#{ V => map_get(Root, Components0) },
-
-    sc_1(Vs, G, Roots, Components);
-sc_1([], _G, _Roots, Components) ->
-    Components.
-
-sc_2([V | Vs], G, Root, Roots, Acc) when not is_map_key(V, Roots) ->
-    %% V has not been assigned to a component, so assign it to the current one.
-    sc_2(in_neighbours(G, V) ++ Vs, G, Root, Roots#{ V => Root }, [V | Acc]);
-sc_2([_V | Vs], G, Root, Roots, Acc) ->
-    %% V is already part of a component, skip it.
-    sc_2(Vs, G, Root, Roots, Acc);
-sc_2([], _G, _Root, Roots, Acc) ->
-    {Roots, reverse(Acc)}.
-
--if(?DEBUG).
-
-%%
-%% Dumps the graph as a string in dot (graphviz) format.
-%%
-%% Use dot(1) to convert to an image:
-%%
-%%    dot [input] -T[format]
-%%    dot graph_file -Tsvg > graph.svg
-
--spec dump(any()) -> any().
-dump(G) ->
-    Formatter = fun(Node) -> io_lib:format("~p", [Node]) end,
-    io:format("~s", [dump_1(G, Formatter)]).
-
--spec dump(any(), any()) -> any().
-dump(G, FileName) ->
-    Formatter = fun(Node) -> io_lib:format("~p", [Node]) end,
-    dump(G, FileName, Formatter).
-
--spec dump(any(), any(), any()) -> any().
-dump(G, FileName, Formatter) ->
-    {ok, Fd} = file:open(FileName, [write]),
-    io:fwrite(Fd, "~s", [dump_1(G, Formatter)]),
-    file:close(Fd).
-
-dump_1(G, Formatter) ->
-    Vs = maps:keys(G#dg.vs),
-
-    {Map, Vertices} = dump_vertices(Vs, 0, Formatter,#{}, []),
-    Edges = dump_edges(Vs, G, Map, []),
-
-    io_lib:format("digraph g {~n~s~n~s~n}~n", [Vertices, Edges]).
-
-dump_vertices([V | Vs], Counter, Formatter, Map, Acc) ->
-    VerticeSlug = io_lib:format("    ~p [label=\"~s\"]~n",
-                                [Counter, Formatter(V)]),
-    dump_vertices(Vs, Counter + 1, Formatter,
-                  Map#{ V => Counter }, [VerticeSlug | Acc]);
-dump_vertices([], _Counter, _Formatter, Map, Acc) ->
-    {Map, Acc}.
-
-dump_edges([V | Vs], G, Map, Acc) ->
-    SelfId = map_get(V, Map),
-    EdgeSlug = [io_lib:format("    ~p -> ~p~n", [SelfId, map_get(To, Map)]) ||
-                {_, To, _} <- out_edges(G, V)],
-    dump_edges(Vs, G, Map, [EdgeSlug | Acc]);
-dump_edges([], _G, _Map, Acc) ->
-    Acc.
-
--endif.
diff --git a/lib/compiler/src/beam_ssa_alias.erl b/lib/compiler/src/beam_ssa_alias.erl
index 4a317254cc..e46856a5c7 100644
--- a/lib/compiler/src/beam_ssa_alias.erl
+++ b/lib/compiler/src/beam_ssa_alias.erl
@@ -99,7 +99,7 @@ fn(#b_local{name=#b_literal{val=N},arity=A}) ->
 
 -type lbl2ss() :: #{ beam_ssa:label() => sharing_state() }.
 
--type sharing_state() :: any(). % A beam_digraph graph.
+-type sharing_state() :: any(). % A graph
 
 -type type_db() :: #{ beam_ssa:b_var() := type() }.
 
diff --git a/lib/compiler/src/beam_ssa_bool.erl b/lib/compiler/src/beam_ssa_bool.erl
index f16bc29cc2..a64afe71b8 100644
--- a/lib/compiler/src/beam_ssa_bool.erl
+++ b/lib/compiler/src/beam_ssa_bool.erl
@@ -830,7 +830,7 @@ cdb_update_workset([], _Seen, Ws) -> Ws.
 
 build_digraph(Bs, #b_br{succ=Succ,fail=Fail}, St0) ->
     Ignore = ordsets:from_list([Succ,Fail]),
-    G0 = beam_digraph:new(),
+    G0 = graph:new(),
     {Map0,G1,St1} = build_mapping(Bs, #{}, G0, St0),
     {Map,G2} = add_external_vertices(Ignore, Map0, G1),
     {G,St} = build_digraph_1(Bs, G2, Map, St1),
@@ -848,13 +848,13 @@ build_mapping([{L,Blk}|Bs], Map0, G0, St0) ->
                 #b_blk{is=[]} -> br;
                 #b_blk{} -> initial
             end,
-    G = beam_digraph:add_vertex(G0, Vtx, Label),
+    G = graph:add_vertex(G0, Vtx, Label),
     build_mapping(Bs, Map, G, St);
 build_mapping([], Map, G, St) ->
     {Map,G,St}.
 
 add_external_vertices([V|Vs], Map0, G0) ->
-    G = beam_digraph:add_vertex(G0, V, {external,#{}}),
+    G = graph:add_vertex(G0, V, {external,#{}}),
     Map = Map0#{V=>V},
     add_external_vertices(Vs, Map, G);
 add_external_vertices([], Map, G) ->
@@ -890,11 +890,11 @@ build_digraph_is([], Last, From, Map, G0, St) ->
     case Last of
         #b_br{bool=#b_literal{val=true},succ=To0,fail=To0} ->
             To = map_get(To0, Map),
-            G = beam_digraph:add_edge(G0, From, To, next),
+            G = graph:add_edge(G0, From, To, next),
             {G,St};
         #b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0} ->
             #{Succ0:=Succ,Fail0:=Fail} = Map,
-            case beam_digraph:vertex(G0, From) of
+            case graph:vertex(G0, From) of
                 #b_set{dst=Bool} ->
                     G = add_succ_fail_edges(From, Succ, Fail, G0),
                     {G,St};
@@ -903,7 +903,7 @@ build_digraph_is([], Last, From, Map, G0, St) ->
                     not_possible();
                 br ->
                     G1 = add_succ_fail_edges(From, Succ, Fail, G0),
-                    G = beam_digraph:add_vertex(G1, From, {br,Bool}),
+                    G = graph:add_vertex(G1, From, {br,Bool}),
                     {G,St}
             end;
         _ ->
@@ -911,14 +911,14 @@ build_digraph_is([], Last, From, Map, G0, St) ->
     end.
 
 build_digraph_is_1(I, Is, Last, Vtx, Map, G0, St0) ->
-    G1 = beam_digraph:add_vertex(G0, Vtx, I),
+    G1 = graph:add_vertex(G0, Vtx, I),
     case Is of
         [] ->
             build_digraph_is(Is, Last, Vtx, Map, G1, St0);
         [_|_] ->
             {NextVtx,St} = new_label(St0),
-            G2 = beam_digraph:add_vertex(G1, NextVtx, initial),
-            G = beam_digraph:add_edge(G2, Vtx, NextVtx, next),
+            G2 = graph:add_vertex(G1, NextVtx, initial),
+            G = graph:add_edge(G2, Vtx, NextVtx, next),
             build_digraph_is(Is, Last, NextVtx, Map, G, St)
     end.
 
@@ -996,7 +996,7 @@ opt_digraph_instr(#b_set{dst=Dst}=I, G0, St) ->
         #b_set{op=phi,dst=Bool} ->
             Vtx = get_vertex(Bool, St),
             G2 = del_out_edges(Vtx, G1),
-            G = beam_digraph:add_edge(G2, Vtx, Succ, next),
+            G = graph:add_edge(G2, Vtx, Succ, next),
             redirect_test(Bool, {fail,Fail}, G, St);
         #b_set{} ->
             G1
@@ -1020,8 +1020,8 @@ ensure_single_use_1(Bool, Vtx, Uses, G) ->
                       (_) -> false
                    end, Uses) of
         {[_],[_]} ->
-            case {beam_digraph:vertex(G, Fail),
-                  beam_digraph:in_edges(G, Fail)} of
+            case {graph:vertex(G, Fail),
+                  graph:in_edges(G, Fail)} of
                 {{external,Bs0}, [_]} ->
                     %% The only other use of the variable Bool
                     %% is in the failure block and it can only
@@ -1029,7 +1029,7 @@ ensure_single_use_1(Bool, Vtx, Uses, G) ->
                     %% replace it with the literal `false`
                     %% in that block.
                     Bs = Bs0#{Bool => #b_literal{val=false}},
-                    beam_digraph:add_vertex(G, Fail, {external,Bs});
+                    graph:add_vertex(G, Fail, {external,Bs});
                 _ ->
                     not_possible()
             end;
@@ -1040,8 +1040,8 @@ ensure_single_use_1(Bool, Vtx, Uses, G) ->
 convert_to_br_node(I, Target, G0, St) ->
     Vtx = get_vertex(I, St),
     G1 = del_out_edges(Vtx, G0),
-    G = beam_digraph:add_vertex(G1, Vtx, br),
-    beam_digraph:add_edge(G, Vtx, Target, next).
+    G = graph:add_vertex(G1, Vtx, br),
+    graph:add_edge(G, Vtx, Target, next).
 
 
 %% ensure_no_failing_instructions(First, Second, G, St) -> ok.
@@ -1056,7 +1056,7 @@ convert_to_br_node(I, Target, G0, St) ->
 ensure_no_failing_instructions(First, Second, G, St) ->
     Vs = covered(get_vertex(First, St), get_vertex(Second, St), G),
     case any(fun(V) ->
-                     case beam_digraph:vertex(G, V) of
+                     case graph:vertex(G, V) of
                          #b_set{op=Op} ->
                              can_fail(Op, V, G);
                          _ ->
@@ -1092,10 +1092,10 @@ eaten_by_phi(V, G) ->
     end.
 
 follow_branch(G, Br) ->
-    case beam_digraph:vertex(G, Br) of
+    case graph:vertex(G, Br) of
         br ->
-            [To] = beam_digraph:out_neighbours(G, Br),
-            beam_digraph:vertex(G, To);
+            [To] = graph:out_neighbours(G, Br),
+            graph:vertex(G, To);
         _ ->
             none
     end.
@@ -1107,7 +1107,7 @@ follow_branch(G, Br) ->
 
 order_args([#b_var{}=VarA,#b_var{}=VarB], G, St) ->
     {VA,VB} = {get_vertex(VarA, St),get_vertex(VarB, St)},
-    case beam_digraph:is_path(G, VA, VB) of
+    case graph:has_path(G, VA, VB) of
         true ->
             %% Core Erlang code generated by v3_core always
             %% has operands already in correct order.
@@ -1115,7 +1115,7 @@ order_args([#b_var{}=VarA,#b_var{}=VarB], G, St) ->
         false ->
             %% Core Erlang code generated by other frontends
             %% such as LFE may have the operands swapped.
-            true = beam_digraph:is_path(G, VB, VA),       %Assertion.
+            true = graph:has_path(G, VB, VA),       %Assertion.
             {VarB,VarB}
     end;
 order_args(_Args, _G, _St) ->
@@ -1159,7 +1159,7 @@ redirect_test_1(V, SuccFail, G) ->
 
 redirect_phi(Phi, Args, SuccFail, G0, St) ->
     PhiVtx = get_vertex(Phi, St),
-    G = beam_digraph:add_vertex(G0, PhiVtx, br),
+    G = graph:add_vertex(G0, PhiVtx, br),
     redirect_phi_1(PhiVtx, sort(Args), SuccFail, G, St).
 
 redirect_phi_1(PhiVtx, [{#b_literal{val=false},FalseExit},
@@ -1219,15 +1219,15 @@ redirect_phi_1(PhiVtx, [{#b_literal{val=false},FalseExit},
     %%
     ensure_disjoint_paths(G0, BoolVtx, FalseExit),
 
-    [FalseOut] = beam_digraph:out_edges(G0, FalseExit),
-    G1 = beam_digraph:del_edge(G0, FalseOut),
+    [FalseOut] = graph:out_edges(G0, FalseExit),
+    G1 = graph:del_edge(G0, FalseOut),
     case SuccFail of
         {fail,Fail} ->
-            G2 = beam_digraph:add_edge(G1, FalseExit, Fail, next),
+            G2 = graph:add_edge(G1, FalseExit, Fail, next),
             G = add_succ_fail_edges(BoolVtx, PhiVtx, FalseExit, G2),
             do_opt_digraph([SuccBool], G, St);
         {succ,Succ} ->
-            G2 = beam_digraph:add_edge(G1, FalseExit, PhiVtx, next),
+            G2 = graph:add_edge(G1, FalseExit, PhiVtx, next),
             G = add_succ_fail_edges(BoolVtx, Succ, PhiVtx, G2),
             do_opt_digraph([SuccBool], G, St)
     end;
@@ -1241,9 +1241,9 @@ redirect_phi_1(PhiVtx, [{#b_literal{val=true},TrueExit},
     %% must ensure that paths are disjoint.
     ensure_disjoint_paths(G0, BoolVtx, TrueExit),
 
-    [TrueOut] = beam_digraph:out_edges(G0, TrueExit),
-    G1 = beam_digraph:del_edge(G0, TrueOut),
-    G2 = beam_digraph:add_edge(G1, TrueExit, PhiVtx, next),
+    [TrueOut] = graph:out_edges(G0, TrueExit),
+    G1 = graph:del_edge(G0, TrueOut),
+    G2 = graph:add_edge(G1, TrueExit, PhiVtx, next),
     G = add_succ_fail_edges(BoolVtx, PhiVtx, Fail, G2),
     %% As as future improvement, we could follow TrueExit
     %% back to its originating boolean expression and
@@ -1254,19 +1254,19 @@ redirect_phi_1(_PhiVtx, [{#b_literal{val=false},FalseExit},
                SuccFail, G0, _St) ->
     case SuccFail of
         {fail,Fail} ->
-            [FalseOut] = beam_digraph:out_edges(G0, FalseExit),
-            G = beam_digraph:del_edge(G0, FalseOut),
-            beam_digraph:add_edge(G, FalseExit, Fail, next);
+            [FalseOut] = graph:out_edges(G0, FalseExit),
+            G = graph:del_edge(G0, FalseOut),
+            graph:add_edge(G, FalseExit, Fail, next);
         {succ,Succ} ->
-            [TrueOut] = beam_digraph:out_edges(G0, TrueExit),
-            G = beam_digraph:del_edge(G0, TrueOut),
-            beam_digraph:add_edge(G, TrueExit, Succ, next)
+            [TrueOut] = graph:out_edges(G0, TrueExit),
+            G = graph:del_edge(G0, TrueOut),
+            graph:add_edge(G, TrueExit, Succ, next)
     end;
 redirect_phi_1(_PhiVtx, _Args, _SuccFail, _G, _St) ->
     not_possible().
 
 digraph_bool_def(G) ->
-    Vs = beam_digraph:vertices(G),
+    Vs = graph:vertices_with_labels(G),
     #{Dst => Vtx || {Vtx,#b_set{dst=Dst}} <- Vs}.
 
 %% ensure_disjoint_paths(G, Vertex1, Vertex2) -> ok.
@@ -1275,7 +1275,7 @@ digraph_bool_def(G) ->
 %%  directions, but better safe than sorry.)
 
 ensure_disjoint_paths(G, V1, V2) ->
-    case beam_digraph:is_path(G, V1, V2) orelse beam_digraph:is_path(G, V2, V1) of
+    case graph:has_path(G, V1, V2) orelse graph:has_path(G, V2, V1) of
         true -> not_possible();
         false -> ok
     end.
@@ -1294,7 +1294,7 @@ ensure_disjoint_paths(G, V1, V2) ->
 %%%
 
 shortcut_branches(Vtx, G, St) ->
-    Vs = reverse(beam_digraph:reverse_postorder(G, [Vtx])),
+    Vs = reverse(graph:reverse_postorder(G, [Vtx])),
     do_shortcut_branches(Vs, G, St).
 
 do_shortcut_branches([V|Vs], G0, St) ->
@@ -1319,11 +1319,11 @@ do_shortcut_branches([], G, _St) -> G.
 redirect_edge(_From, To, {_Label,To}, G) ->
     G;
 redirect_edge(From, To0, {Label,To}, G0) ->
-    G = beam_digraph:del_edge(G0, {From,To0,Label}),
-    beam_digraph:add_edge(G, From, To, Label).
+    G = graph:del_edge(G0, {From,To0,Label}),
+    graph:add_edge(G, From, To, Label).
 
 eval_bs(Vtx, G, St) ->
-    case beam_digraph:vertex(G, Vtx) of
+    case graph:vertex(G, Vtx) of
         #b_set{op={bif,'=:='},args=[#b_var{}=Bool,#b_literal{val=true}]} ->
             case get_def(Bool, G, St) of
                 #b_set{op=phi}=Phi ->
@@ -1359,7 +1359,7 @@ phi_bs(#b_set{op=phi,dst=PhiDst,args=PhiArgs}) ->
     end.
 
 eval_instr(Vtx, G, Bs) ->
-    case beam_digraph:vertex(G, Vtx) of
+    case graph:vertex(G, Vtx) of
         #b_set{} when map_size(Bs) =:= 0 ->
             %% With no bindings, eval_safe_bool_expr() is
             %% unlikely to do anything useful. If we would
@@ -1375,8 +1375,8 @@ eval_instr(Vtx, G, Bs) ->
         br ->
             %% We can shortcut this branch unless its
             %% target is a phi node.
-            [Next] = beam_digraph:out_neighbours(G, Vtx),
-            case beam_digraph:vertex(G, Next) of
+            [Next] = graph:out_neighbours(G, Vtx),
+            case graph:vertex(G, Next) of
                 #b_set{op=phi} -> Vtx;
                 _ -> eval_instr(Next, G, Bs)
             end;
@@ -1436,7 +1436,7 @@ eval_literal_args([], Acc) ->
 %%%
 
 ensure_init(Root, G, G0) ->
-    Vs = beam_digraph:vertices(G),
+    Vs = graph:vertices_with_labels(G),
 
     %% Build an ordset of a all variables used by the code
     %% before the optimization.
@@ -1446,7 +1446,7 @@ ensure_init(Root, G, G0) ->
     %% the digraph. Variables not included in this map have been
     %% defined by code before the code in the digraph.
     Vars = #{Dst => unset || {_,#b_set{dst=Dst}} <- Vs},
-    RPO = beam_digraph:reverse_postorder(G, [Root]),
+    RPO = graph:reverse_postorder(G, [Root]),
     ensure_init_1(RPO, Used, G, #{Root=>Vars}).
 
 ensure_init_1([V|Vs], Used, G, InitMaps0) ->
@@ -1456,10 +1456,10 @@ ensure_init_1([], _, _, _) -> ok.
 
 ensure_init_instr(Vtx, Used, G, InitMaps0) ->
     VarMap0 = map_get(Vtx, InitMaps0),
-    case beam_digraph:vertex(G, Vtx) of
+    case graph:vertex(G, Vtx) of
         #b_set{dst=Dst}=I ->
             do_ensure_init_instr(I, VarMap0, InitMaps0),
-            OutVs = beam_digraph:out_neighbours(G, Vtx),
+            OutVs = graph:out_neighbours(G, Vtx),
             VarMap = VarMap0#{Dst=>set},
             InitMaps = InitMaps0#{Vtx:=VarMap},
             ensure_init_successors(OutVs, G, VarMap, InitMaps);
@@ -1502,17 +1502,17 @@ ensure_init_instr(Vtx, Used, G, InitMaps0) ->
                     end
             end;
         _ ->
-            OutVs = beam_digraph:out_neighbours(G, Vtx),
+            OutVs = graph:out_neighbours(G, Vtx),
             ensure_init_successors(OutVs, G, VarMap0, InitMaps0)
     end.
 
 ensure_init_used(G) ->
-    Vs = beam_digraph:vertices(G),
+    Vs = graph:vertices_with_labels(G),
     ensure_init_used_1(Vs, G, []).
 
 ensure_init_used_1([{Vtx,#b_set{dst=Dst}=I}|Vs], G, Acc0) ->
     Acc1 = [beam_ssa:used(I)|Acc0],
-    case beam_digraph:out_degree(G, Vtx) of
+    case graph:out_degree(G, Vtx) of
         2 ->
             Acc = [[Dst]|Acc1],
             ensure_init_used_1(Vs, G, Acc);
@@ -1600,7 +1600,7 @@ digraph_to_ssa([], _G, Blocks, Seen) ->
     {Blocks,Seen}.
 
 digraph_to_ssa_blk(From, G, Blocks, Acc0) ->
-    case beam_digraph:vertex(G, From) of
+    case graph:vertex(G, From) of
         #b_set{dst=Dst}=I ->
             case get_targets(From, G) of
                 {br,Succ,Fail} ->
@@ -1662,7 +1662,7 @@ get_def(#b_var{}=Bool, #st{defs=Defs}) ->
 get_def(Var, G, #st{ldefs=LDefs,defs=Defs}) ->
     case LDefs of
         #{Var:=Vtx} ->
-            beam_digraph:vertex(G, Vtx);
+            graph:vertex(G, Vtx);
         #{} ->
             %% Not in the graph. Returning definitions for phi nodes
             %% outside the graph is useful for shortcut_branches().
@@ -1673,10 +1673,10 @@ get_def(Var, G, #st{ldefs=LDefs,defs=Defs}) ->
     end.
 
 add_succ_fail_edges(From, Succ, Fail, G0) ->
-    G1 = beam_digraph:add_edge(G0, From, Succ, succ),
-    G = beam_digraph:add_edge(G1, From, Fail, fail),
-    case beam_digraph:out_edges(G0, From) of
-        [{From,_,next}=E] -> beam_digraph:del_edge(G, E);
+    G1 = graph:add_edge(G0, From, Succ, succ),
+    G = graph:add_edge(G1, From, Fail, fail),
+    case graph:out_edges(G0, From) of
+        [{From,_,next}=E] -> graph:del_edge(G, E);
         [] -> G
     end.
 
@@ -1686,7 +1686,7 @@ get_vertex(#b_var{}=Var, #st{ldefs=LDefs}) ->
     map_get(Var, LDefs).
 
 get_targets(Vtx, G) when is_integer(Vtx) ->
-    case beam_digraph:out_edges(G, Vtx) of
+    case graph:out_edges(G, Vtx) of
         [{_,To,next}] ->
             {br,To};
         [{_,Succ,succ},{_,Fail,fail}] ->
@@ -1701,7 +1701,7 @@ get_targets(#b_var{}=Var, G, #st{ldefs=LDefs}) ->
     get_targets(map_get(Var, LDefs), G).
 
 del_out_edges(V, G) ->
-    beam_digraph:del_edges(G, beam_digraph:out_edges(G, V)).
+    graph:del_edges(G, graph:out_edges(G, V)).
 
 covered(From, To, G) ->
     Seen0 = #{},
@@ -1711,7 +1711,7 @@ covered(From, To, G) ->
 covered_1(To, To, _G, Seen) ->
     {yes,Seen};
 covered_1(From, To, G, Seen) ->
-    Vs = beam_digraph:out_neighbours(G, From),
+    Vs = graph:out_neighbours(G, From),
     covered_list(Vs, To, G, Seen, no).
 
 covered_list([V|Vs], To, G, Seen0, AnyFound) ->
@@ -1734,10 +1734,10 @@ covered_list([], _, _, Seen, AnyFound) ->
     {AnyFound,Seen}.
 
 digraph_roots(G) ->
-    digraph_roots_1(beam_digraph:vertices(G), G).
+    digraph_roots_1(graph:vertices(G), G).
 
-digraph_roots_1([{V,_}|Vs], G) ->
-    case beam_digraph:in_degree(G, V) of
+digraph_roots_1([V|Vs], G) ->
+    case graph:in_degree(G, V) of
         0 ->
             [V|digraph_roots_1(Vs, G)];
         _ ->
diff --git a/lib/compiler/src/beam_ssa_recv.erl b/lib/compiler/src/beam_ssa_recv.erl
index 77559a80ff..562147ce1a 100644
--- a/lib/compiler/src/beam_ssa_recv.erl
+++ b/lib/compiler/src/beam_ssa_recv.erl
@@ -119,7 +119,7 @@
 format_error(OptInfo) ->
     format_opt_info(OptInfo).
 
--record(scan, { graph=beam_digraph:new(),
+-record(scan, { graph=graph:new(),
                 module :: #{ beam_ssa:b_local() => {beam_ssa:block_map(),
                                                     [beam_ssa:b_var()],
                                                     [beam_ssa:b_var()]} },
@@ -317,16 +317,16 @@ scan_add_edge(From, To, State) ->
 scan_add_edge(From, To, Label, State0) ->
     State = scan_add_vertex(To, scan_add_vertex(From, State0)),
 
-    Graph = beam_digraph:add_edge(State#scan.graph, From, To, Label),
+    Graph = graph:add_edge(State#scan.graph, From, To, Label),
 
     State#scan{graph=Graph}.
 
 scan_add_vertex(Vertex, #scan{graph=Graph0}=State) ->
-    case beam_digraph:has_vertex(Graph0, Vertex) of
+    case graph:has_vertex(Graph0, Vertex) of
         true ->
             State;
         false ->
-            Graph = beam_digraph:add_vertex(Graph0, Vertex),
+            Graph = graph:add_vertex(Graph0, Vertex),
             State#scan{graph=Graph}
     end.
 
@@ -463,7 +463,7 @@ propagate_references_1([{Vertex, Ref} | VRefs], G, Acc0) ->
                   Acc0;
               false ->
                   Acc1 = Acc0#{ Vertex => sets:add_element(Ref, Refs) },
-                  Next = pr_successors(beam_digraph:out_edges(G, Vertex), Ref),
+                  Next = pr_successors(graph:out_edges(G, Vertex), Ref),
                   propagate_references_1(Next, G, Acc1)
           end,
     propagate_references_1(VRefs, G, Acc);
@@ -681,7 +681,7 @@ intersect_uses_1([{Vertex, Ref} | Vs], RefMap, Graph, Acc0) ->
               {true, false} ->
                   %% This block lies between reference creation and the receive
                   %% block, add it to the intersection.
-                  Edges = beam_digraph:in_edges(Graph, Vertex),
+                  Edges = graph:in_edges(Graph, Vertex),
                   Next = iu_predecessors(Edges, Ref),
                   ActiveRefs = sets:add_element(Ref, ActiveRefs0),
                   intersect_uses_1(Next, RefMap, Graph,
@@ -735,7 +735,7 @@ plan_markers_1(MakeRefs0, FuncId, UsageMap) ->
 
 plan_clears(UsageMap, Graph) ->
     maps:fold(fun({FuncId, _}=Vertex, ActiveRefs, Acc) ->
-                      Edges = beam_digraph:out_edges(Graph, Vertex),
+                      Edges = graph:out_edges(Graph, Vertex),
                       case plan_clears_1(Edges, ActiveRefs, UsageMap) of
                           [_|_]=Clears ->
                               Clears0 = maps:get(FuncId, Acc, []),
diff --git a/lib/compiler/src/beam_ssa_ss.erl b/lib/compiler/src/beam_ssa_ss.erl
index f0ef95da45..f12f27fd67 100644
--- a/lib/compiler/src/beam_ssa_ss.erl
+++ b/lib/compiler/src/beam_ssa_ss.erl
@@ -22,7 +22,7 @@
 %%
 %% This module provides a database storing the sharing status for the
 %% variables in a function. The database is represented as a graph
-%% (beam_digraph) where the nodes are variables and values. Edges are
+%% where the nodes are variables and values. Edges are
 %% extraction and embedding operations. Nodes are labeled with the
 %% sharing status of the variable and edges are labeled with the type
 %% of extraction/embedding operation.
@@ -82,7 +82,7 @@
 -define(ASSERT(Assert), skip).
 -endif.
 
--type sharing_state() :: any(). % A beam_digraph graph.
+-type sharing_state() :: any(). % A graph
 -type sharing_status() :: 'unique' | 'aliased' | 'no_info'.
 -type element() :: 'hd' | 'tl' | non_neg_integer().
 
@@ -98,7 +98,7 @@ add_vertex(State, V, Status) ->
                 plain -> ok;
                 #b_literal{} -> ok
             end),
-    beam_digraph:add_vertex(State, V, Status).
+    graph:add_vertex(State, V, Status).
 
 add_edge(State, Src, Dst, Lbl) ->
     ?ASSERT(begin
@@ -119,15 +119,15 @@ add_edge(State, Src, Dst, Lbl) ->
                         ok
                 end
             end),
-    beam_digraph:add_edge(State, Src, Dst, Lbl).
+    graph:add_edge(State, Src, Dst, Lbl).
 
 -spec derive_from(beam_ssa:b_var(), beam_ssa:b_var(), sharing_state()) ->
           sharing_state().
 derive_from(Dst, Src, State) ->
     ?DP("Deriving ~p from ~p~nSS:~n~s~n", [Dst, Src, dump(State)]),
     ?assert_state(State),
-    case {beam_digraph:vertex(State, Dst, unique),
-          beam_digraph:vertex(State, Src, plain)} of
+    case {graph:vertex(State, Dst, unique),
+          graph:vertex(State, Src, plain)} of
         {_,plain} ->
             State;
         {aliased,_} ->
@@ -146,7 +146,7 @@ derive_from(Dst, Src, State) ->
                 false ->
                     %% Source is not aliased and has not been embedded
                     %% in a term, record that it now is.
-                    State1 = case beam_digraph:has_vertex(State, Dst) of
+                    State1 = case graph:has_vertex(State, Dst) of
                                  true ->
                                      State;
                                  false ->
@@ -173,15 +173,15 @@ add_embedding(Dst, Src, Element, State0) ->
     %% element.
     State1 = case Src of
                  plain ->
-                     beam_digraph:add_vertex(State0, Src, unique);
+                     graph:add_vertex(State0, Src, unique);
                  #b_literal{} ->
-                     beam_digraph:add_vertex(State0, Src, unique);
+                     graph:add_vertex(State0, Src, unique);
                  _ ->
-                     case beam_digraph:has_vertex(State0, Src) of
+                     case graph:has_vertex(State0, Src) of
                          true ->
                              State0;
                          false ->
-                             beam_digraph:add_vertex(State0, Src, unique)
+                             graph:add_vertex(State0, Src, unique)
                      end
              end,
 
@@ -196,7 +196,7 @@ add_embedding(Dst, Src, Element, State0) ->
 
     %% If the variable being embedded ends up with more than one
     %% out-edge, the source will be aliased, unless it is a plain value.
-    case beam_digraph:out_edges(State, Src) of
+    case graph:out_edges(State, Src) of
         [_] ->
             State;
         _ when Src =/= plain ->
@@ -215,13 +215,13 @@ add_embedding(Dst, Src, Element, State0) ->
 extract(Dst, Src, Element, State) ->
     ?DP("Extracting ~p[~p] into ~p~n", [Src,Element,Dst]),
     ?assert_state(State),
-    case beam_digraph:vertex(State, Src, plain) of
+    case graph:vertex(State, Src, plain) of
         aliased ->
             %% The pair/tuple is aliased, so what is extracted will be aliased.
             ?assert_state(set_status(Dst, aliased, State));
         unique ->
             %% The aggregate is unique, but elements can be aliased.
-            OutEdges = beam_digraph:out_edges(State, Src),
+            OutEdges = graph:out_edges(State, Src),
             ?ASSERT(true = is_integer(Element)
                     orelse (Element =:= hd) orelse (Element =:= tl)),
             ?DP("dst: ~p, src: ~p, e: ~p, out-edges: ~p~n",
@@ -258,7 +258,7 @@ extract_element(Dst, Src, Element, [], State0) ->
 
 extract_status_for_element(Element, Src, Dst, State0) ->
     ?DP("    extract_status_for_element(~p, ~p)~n", [Element, Src]),
-    InEdges = beam_digraph:in_edges(State0, Src),
+    InEdges = graph:in_edges(State0, Src),
     ?DP("    in-edges: ~p~n", [InEdges]),
     Embeddings = [Var || {Var,_,{embed,SE}} <- InEdges, Element =:= SE],
     Extracts = [Ex || {_,_,{extract,_}}=Ex <- InEdges],
@@ -273,8 +273,8 @@ extract_status_for_element(Element, Src, Dst, State0) ->
             ?DP("    found embedding~n"),
             ?DP("    the source is ~p~n", [Var]),
             ?DP("    SS~n~s~n", [dump(State0)]),
-            ?DP("    status ~p~n", [beam_digraph:vertex(State0, Var, unique)]),
-            State = set_status(Dst, beam_digraph:vertex(State0, Var, unique),
+            ?DP("    status ~p~n", [graph:vertex(State0, Var, unique)]),
+            State = set_status(Dst, graph:vertex(State0, Var, unique),
                                State0),
             ?DP("    Returned SS~n~s~n", [dump(State)]),
             ?assert_state(State);
@@ -292,9 +292,9 @@ get_status_of_extracted_element(Aggregate, [First|Rest]=Elements, State) ->
     %% extracts from unique aggregates. This implies that when the
     %% chain is traced backwards, no aliased aggregates will be found,
     %% but in case that invariant is ever broken, assert.
-    ?ASSERT(unique = beam_digraph:vertex(State, Aggregate, unique)),
+    ?ASSERT(unique = graph:vertex(State, Aggregate, unique)),
     ?DP("      aggregate is unique~n"),
-    InEdges = beam_digraph:in_edges(State, Aggregate),
+    InEdges = graph:in_edges(State, Aggregate),
     Embeddings = [Src || {Src,_,{embed,E}} <- InEdges, First =:= E],
     Extracts = [{Src,E} || {Src,_,{extract,E}} <- InEdges],
     ?DP("      embeddings ~p~n", [Embeddings]),
@@ -309,7 +309,7 @@ get_status_of_extracted_element(Aggregate, [First|Rest]=Elements, State) ->
     end;
 get_status_of_extracted_element(Aggregate, [], State) ->
     ?DP("    ~s(~p, [], ...)~n", [?FUNCTION_NAME, Aggregate]),
-    S = beam_digraph:vertex(State, Aggregate, unique),
+    S = graph:vertex(State, Aggregate, unique),
     ?DP("      bottomed out, status is ~p~n", [S]),
     S.
 
@@ -320,11 +320,11 @@ forward_status(Main, Other) ->
     ?DP("Forwarding state~n"),
     ?assert_state(Main),
     ?assert_state(Other),
-    R = beam_digraph:foldv(
+    R = graph:fold_vertices(
           Main,
           fun(#b_var{}=V, S, Acc) when S =/= aliased ->
                   maybe
-                      true ?= beam_digraph:has_vertex(Other, V),
+                      true ?= graph:has_vertex(Other, V),
                       aliased ?= get_status(V, Other),
                       set_status(V, aliased, Acc)
                   else
@@ -340,15 +340,15 @@ forward_status(Main, Other) ->
 -spec get_status(beam_ssa:b_var(), sharing_state()) ->
           sharing_status().
 get_status(V=#b_var{}, State) ->
-    beam_digraph:vertex(State, V, unique).
+    graph:vertex(State, V, unique).
 
 -spec merge(sharing_state(), sharing_state()) -> sharing_state().
 merge(StateA, StateB) ->
     ?DP("Merging states~n"),
     ?assert_state(StateA),
     ?assert_state(StateB),
-    SizeA = beam_digraph:no_vertices(StateA),
-    SizeB = beam_digraph:no_vertices(StateB),
+    SizeA = graph:no_vertices(StateA),
+    SizeB = graph:no_vertices(StateB),
     %% Always merge the smaller state into the larger.
     {Small,Large} = if SizeA < SizeB ->
                             {StateA,StateB};
@@ -360,14 +360,14 @@ merge(StateA, StateB) ->
     ?DP(dump(Small)),
     ?DP("Large:~n"),
     ?DP(dump(Large)),
-    R = merge(Large, Small, beam_digraph:vertices(Small),
+    R = merge(Large, Small, graph:vertices_with_labels(Small),
               sets:new(), sets:new()),
     ?assert_state(R).
 
 merge(Dest, Source, [{V,VStatus}|Vertices], Edges0, Forced) ->
 
     Edges = accumulate_edges(V, Source, Edges0),
-    DestStatus = beam_digraph:vertex(Dest, V, false),
+    DestStatus = graph:vertex(Dest, V, false),
     case {DestStatus,VStatus} of
         {Status,Status} ->
             %% Same status in both states.
@@ -402,7 +402,7 @@ merge1(Dest0, Source, [{plain,To,Lbl}|Edges], Fixups, Forced) ->
     merge1(Dest, Source, Edges, Fixups, Forced);
 merge1(Dest0, Source, [{From,To,Lbl}=Edge|Edges], Fixups, Forced) ->
     ?DP("  Adding edge ~p -> ~p, lbl: ~p~n", [From,To,Lbl]),
-    OutEdges = beam_digraph:out_edges(Dest0, From),
+    OutEdges = graph:out_edges(Dest0, From),
     case {ordsets:is_element(Edge, OutEdges),ordsets:is_empty(OutEdges)} of
         {true,_} ->
             ?DP("   Already exists~n"),
@@ -431,7 +431,7 @@ merge1(Dest, _Source, [], Fixups, Forced) ->
     merge2(Dest, _Source, sets:to_list(Fixups), Forced).
 
 merge2(Dest0, _Source, [{alias,From,Lbl}|Fixups], Forced) ->
-    OutEdges = beam_digraph:out_edges(Dest0, From),
+    OutEdges = graph:out_edges(Dest0, From),
     Dest = foldl(fun({#b_var{},To,L}, Acc) when L =:= Lbl ->
                          set_status(To, aliased, Acc);
                     (_, Acc) ->
@@ -445,15 +445,15 @@ merge2(Dest0, _Source, [], Forced) ->
     ?assert_state(Dest).
 
 accumulate_edges(V, State, Edges0) ->
-    InEdges = beam_digraph:in_edges(State, V),
-    OutEdges = beam_digraph:out_edges(State, V),
+    InEdges = graph:in_edges(State, V),
+    OutEdges = graph:out_edges(State, V),
     foldl(fun sets:add_element/2,
           foldl(fun sets:add_element/2, Edges0, InEdges),
           OutEdges).
 
 -spec new() -> sharing_state().
 new() ->
-    beam_digraph:new().
+    graph:new().
 
 -spec phi(beam_ssa:b_var(), [beam_ssa:b_var()],
           sharing_state(), non_neg_integer())
@@ -498,9 +498,9 @@ prune([{0,_}|_], _, _, _) ->
 prune([{Depth,V}|Work], Killed, LiveVars, State0) ->
     case is_safe_to_prune(V, LiveVars, State0) of
         true ->
-            State = beam_digraph:del_vertex(State0, V),
+            State = graph:del_vertex(State0, V),
             Ins = [{Depth - 1, I}
-                   || I <- beam_digraph:in_neighbours(State0, V)],
+                   || I <- graph:in_neighbours(State0, V)],
             prune(Ins++Work, Killed, LiveVars, State);
         false ->
             prune(Work, Killed, LiveVars, State0)
@@ -514,7 +514,7 @@ is_safe_to_prune(V, LiveVars, State) ->
             false;
         false ->
             %% Safe to prune if all out-neighbours are safe-to-prune.
-            case beam_digraph:out_neighbours(State, V) of
+            case graph:out_neighbours(State, V) of
                 [] ->
                     true;
                 Outs ->
@@ -537,9 +537,9 @@ prune_by_add(LiveVars, State) ->
     ?assert_state(State),
     ?DP("Pruning to ~p~n", [sets:to_list(LiveVars)]),
     ?DP("~s~n", [dump(State)]),
-    ?DP("Vertices: ~p~n", [beam_digraph:vertices(State)]),
+    ?DP("Vertices: ~p~n", [graph:vertices_with_labels(State)]),
     R = prune_by_add([{0,V} || V <- sets:to_list(LiveVars),
-                               beam_digraph:has_vertex(State, V)],
+                               graph:has_vertex(State, V)],
                      [], new(), State),
     ?DP("Pruned result~n~s~n", [dump(R)]),
     ?assert_state(R).
@@ -548,15 +548,15 @@ prune_by_add([{Depth0,V}|Wanted], Edges, New0, Old) ->
     ?DP("Looking at ~p~n", [V]),
     ?DP("Curr:~n~s~n", [dump(New0)]),
     ?DP("Wanted: ~p~n", [Wanted]),
-    case beam_digraph:has_vertex(New0, V) of
+    case graph:has_vertex(New0, V) of
         true ->
             %% This variable is already added.
             prune_by_add(Wanted, Edges, New0, Old);
         false when Depth0 < ?SS_DEPTH_LIMIT ->
             %% This variable has to be kept. Add it to the new graph.
-            New = add_vertex(New0, V, beam_digraph:vertex(Old, V)),
+            New = add_vertex(New0, V, graph:vertex(Old, V)),
             %% Add all incoming edges to this node.
-            InEdges = beam_digraph:in_edges(Old, V),
+            InEdges = graph:in_edges(Old, V),
             Depth = Depth0 + 1,
             InNodes = [{Depth, From} || {From,_,_} <:- InEdges],
             prune_by_add(InNodes ++ Wanted, InEdges ++ Edges, New, Old);
@@ -594,7 +594,7 @@ set_call_result(Dst, {unique,Elements}, SS0, Cnt0) ->
                                   tl -> ok;
                                   E when is_integer(E), E >= 0 -> ok
                               end),
-                      SS2 = beam_digraph:add_edge(SS1, V, Dst, {embed,Idx}),
+                      SS2 = graph:add_edge(SS1, V, Dst, {embed,Idx}),
                       set_call_result(V, Element, SS2, Cnt+1)
               end, {SS0,Cnt0}, Elements).
 
@@ -618,7 +618,7 @@ set_status(#b_var{}=V, Status, State0) ->
     %%   is embedded remains unchanged.
 
     ?DP("Setting status of ~p to ~p~n", [V,Status]),
-    case beam_digraph:vertex(State0, V, unique) of
+    case graph:vertex(State0, V, unique) of
         Status ->
             %% Status is unchanged.
             State0;
@@ -634,7 +634,7 @@ set_status(#b_var{}=V, Status, State0) ->
 
 set_alias([#b_var{}=V|Vars], State0) ->
     %% TODO: fold into the above
-    case beam_digraph:vertex(State0, V, unique) of
+    case graph:vertex(State0, V, unique) of
         aliased ->
             set_alias(Vars, State0);
         _ ->
@@ -645,9 +645,9 @@ set_alias([], State) ->
     State.
 
 get_alias_edges(V, State) ->
-    OutEdges = [To || {#b_var{},To,_} <- beam_digraph:out_edges(State, V)],
+    OutEdges = [To || {#b_var{},To,_} <- graph:out_edges(State, V)],
     EmbedEdges = [Src
-                  || {#b_var{}=Src,_,Lbl} <- beam_digraph:in_edges(State, V),
+                  || {#b_var{}=Src,_,Lbl} <- graph:in_edges(State, V),
                      case Lbl of
                          embed -> true;
                          {embed,_} -> true;
@@ -657,11 +657,11 @@ get_alias_edges(V, State) ->
 
 -spec size(sharing_state()) -> non_neg_integer().
 size(State) ->
-    beam_digraph:no_vertices(State).
+    graph:no_vertices(State).
 
 -spec variables(sharing_state()) -> [beam_ssa:b_var()].
 variables(State) ->
-    [V || {V,_Lbl} <:- beam_digraph:vertices(State)].
+    graph:vertices(State).
 
 -type call_in_arg_status() :: no_info
                             | unique
@@ -755,18 +755,18 @@ merge_in_arg(#b_var{}=V, Status, 0, State) ->
             aliased
     end;
 merge_in_arg(#b_var{}=V, unique, _Cutoff, State) ->
-    case beam_digraph:vertex(State, V, unique) of
+    case graph:vertex(State, V, unique) of
         no_info ->
             unique;
         S ->
             S
     end;
 merge_in_arg(#b_var{}=V, Status, Cutoff, State) ->
-    case beam_digraph:vertex(State, V, unique) of
+    case graph:vertex(State, V, unique) of
         aliased ->
             aliased;
         unique ->
-            InEdges = beam_digraph:in_edges(State, V),
+            InEdges = graph:in_edges(State, V),
             Elements = case Status of
                            {unique,Es} -> Es;
                            no_info -> #{}
@@ -861,7 +861,7 @@ merge_elements([{_Src,_,embed}|Rest], _Elements0, Cutoff, State) ->
     merge_elements(Rest, no_info, Cutoff, State);
 merge_elements([{Src,V,{extract,E}}], Elements, Cutoff, State) ->
     ?DP("Looking for an embedding of the ~p element from ~p~n", [E, Src]),
-    InEdges = beam_digraph:in_edges(State, Src),
+    InEdges = graph:in_edges(State, Src),
     case [Other || {Other,_,{embed,EdgeOp}} <- InEdges, EdgeOp =:= E] of
         [Next] ->
             ?DP("Found: ~p~n", [Next]),
@@ -901,14 +901,14 @@ init_element(Idx, Status, Child, Cnt0, SS0) ->
                 tl -> ok;
                 I when is_integer(I), I >= 0 -> ok
             end),
-    SS = beam_digraph:add_edge(SS1, ElemV, Child, {embed,Idx}),
+    SS = graph:add_edge(SS1, ElemV, Child, {embed,Idx}),
     {SS,Cnt}.
 
 %% Internal helpers
 
 -spec has_out_edges(beam_ssa:b_var(), sharing_state()) -> boolean().
 has_out_edges(V, State) ->
-    beam_digraph:out_edges(State, V) =/= [].
+    graph:out_edges(State, V) =/= [].
 
 %% Debug support below
 
@@ -927,23 +927,23 @@ assert_state(State) ->
 %% Check that we don't have edges between non-existing nodes
 assert_bad_edges(State) ->
     [{assert_variable_exists(F, State), assert_variable_exists(T, State)}
-     || {F,T,_} <:- beam_digraph:edges(State)].
+     || {F,T,_} <:- graph:edges(State)].
 
 
 %% Check that extracted and embedded elements of an aliased variable
 %% are aliased.
 assert_aliased_parent_implies_aliased(State) ->
-    [assert_apia(A, State) || {A,aliased} <- beam_digraph:vertices(State)].
+    [assert_apia(A, State) || {A,aliased} <- graph:vertices_with_labels(State)].
 
 assert_apia(Parent, State) ->
     Children = [Child
-                || {_,Child,Info} <:- beam_digraph:out_edges(State, Parent),
+                || {_,Child,Info} <:- graph:out_edges(State, Parent),
                    case Info of
                        {extract,_} -> true;
                        embed -> true;
                        {embed,_} -> false
                    end],
-    [case beam_digraph:vertex(State, Child, unique) of
+    [case graph:vertex(State, Child, unique) of
          aliased ->
              ok;
          _ ->
@@ -955,13 +955,13 @@ assert_apia(Parent, State) ->
 %% Check that elements which are embedded twice or more times are
 %% aliased.
 assert_embedded_in_aliased_implies_aliased(State) ->
-    [assert_eiaia(A, State) || {A,aliased} <- beam_digraph:vertices(State)].
+    [assert_eiaia(A, State) || {A,aliased} <- graph:vertices_with_labels(State)].
 
 assert_eiaia(Embedder, State) ->
     NotAliased = [ Src
-                   || {Src,_,embed} <- beam_digraph:in_edges(State, Embedder),
-                      beam_digraph:vertex(State, Src, unique) =/= aliased,
-                      beam_digraph:vertex(State, Src, unique) =/= no_info],
+                   || {Src,_,embed} <- graph:in_edges(State, Embedder),
+                      graph:vertex(State, Src, unique) =/= aliased,
+                      graph:vertex(State, Src, unique) =/= no_info],
     case NotAliased of
         [] ->
             State;
@@ -975,11 +975,11 @@ assert_eiaia(Embedder, State) ->
 %% Check that elements which are embedded twice or more times are
 %% aliased.
 assert_multiple_embeddings_force_aliasing(State) ->
-    [assert_mefa(V, State) || {V,unique} <- beam_digraph:vertices(State)].
+    [assert_mefa(V, State) || {V,unique} <- graph:vertices_with_labels(State)].
 
 assert_mefa(V, State) ->
-    NotAliased = [ B || {B,_,embed} <- beam_digraph:out_edges(State, V),
-                        beam_digraph:vertex(State, B, unique) =/= aliased],
+    NotAliased = [ B || {B,_,embed} <- graph:out_edges(State, V),
+                        graph:vertex(State, B, unique) =/= aliased],
     case NotAliased of
         [_,_|_] ->
             io:format("Expected ~p to be aliased in:~n~s.~n", [V, dump(State)]),
@@ -990,7 +990,7 @@ assert_mefa(V, State) ->
 
 %% Check that elements which are extracted twice are aliased.
 assert_multiple_extractions_force_aliasing(State) ->
-    [assert_mxfa(V, State) || {V,_} <:- beam_digraph:vertices(State)].
+    [assert_mxfa(V, State) || V <:- graph:vertices(State)].
 
 assert_mxfa(V, State) ->
     %% Build a map of the extracted values keyed by element.
@@ -1002,11 +1002,11 @@ assert_mxfa(V, State) ->
                           Acc;
                      ({_,_,{embed,_}}, Acc) ->
                           Acc
-                  end, #{}, beam_digraph:out_edges(State, V)),
+                  end, #{}, graph:out_edges(State, V)),
     Bad = maps:fold(
             fun(_Elem, [_,_|_]=Vars, Acc) ->
                     [X || X <- Vars,
-                          beam_digraph:vertex(State, X, unique) =/= aliased]
+                          graph:vertex(State, X, unique) =/= aliased]
                         ++ Acc;
                (_, _, Acc) ->
                     Acc
@@ -1020,12 +1020,12 @@ assert_mxfa(V, State) ->
     end.
 
 assert_variable_exists(plain, State) ->
-    case beam_digraph:has_vertex(State, plain) of
+    case graph:has_vertex(State, plain) of
         false ->
             io:format("Expected ~p in~n ~s.~n", [plain, dump(State)]),
             throw(assertion_failure);
         _ ->
-            case beam_digraph:vertex(State, plain, unique) of
+            case graph:vertex(State, plain, unique) of
                 unique -> State;
                 Other ->
                     io:format("Expected plain to be unique, was ~p, in:~n~p~n",
@@ -1036,7 +1036,7 @@ assert_variable_exists(plain, State) ->
 assert_variable_exists(#b_literal{}, State) ->
     State;
 assert_variable_exists(#b_var{}=V, State) ->
-    case beam_digraph:has_vertex(State, V) of
+    case graph:has_vertex(State, V) of
         false ->
             io:format("Expected ~p in~n~s.~n", [V, dump(State)]),
             throw(assertion_failure);
@@ -1049,17 +1049,17 @@ assert_variable_exists(#b_var{}=V, State) ->
 -ifdef(PROVIDE_DUMP).
 -spec dump(sharing_state()) -> iolist().
 dump(State) ->
-    Ls = lists:enumerate(0, beam_digraph:vertices(State)),
-    V2Id = #{ V=>Id || {Id,{V,_}} <- Ls },
+    Ls = lists:enumerate(0, graph:vertices(State)),
+    V2Id = #{ V=>Id || {Id,V} <- Ls },
     [
      "digraph G {\n",
      [ io_lib:format("  ~p [label=\"~p:~p\",shape=\"box\"]~n",
-                     [Id,V,beam_digraph:vertex(State, V)])
+                     [Id,V,graph:vertex(State, V)])
        || V:=Id <- V2Id],
      [ io_lib:format("  ~p -> ~p [label=\"~p\"]~n",
                      [maps:get(From, V2Id, plain),
                       maps:get(To, V2Id),
                       Lbl])
-       || {From,To,Lbl} <- beam_digraph:edges(State)],
+       || {From,To,Lbl} <- graph:edges(State)],
      "}\n"].
 -endif.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index f627aec471..d080321346 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -3125,8 +3125,7 @@ pre_load() ->
 	 beam_clean,
          beam_core_to_ssa,
 	 beam_dict,
-	 beam_digraph,
-     beam_doc,
+         beam_doc,
 	 beam_flatten,
 	 beam_jump,
 	 beam_opcodes,
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 7b1f0be40f..62efb772bc 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -31,7 +31,6 @@
 	     beam_clean,
 	     beam_core_to_ssa,
 	     beam_dict,
-	     beam_digraph,
 	     beam_disasm,
          beam_doc,
 	     beam_flatten,
@@ -87,5 +86,5 @@
   {registered, []},
   {applications, [kernel, stdlib]},
   {env, []},
-  {runtime_dependencies, ["stdlib-6.0","kernel-8.4","erts-13.0",
+  {runtime_dependencies, ["stdlib-@OTP-19922@","kernel-8.4","erts-13.0",
 			  "crypto-5.1"]}]}.
-- 
2.51.0

openSUSE Build Service is sponsored by