Skip to content

Commit 184b724

Browse files
committed
More optimizations for differences
* when a1 < a2 * when a1 == a2 and c2 == bottom and d2 == bottom * when a1 == a2 and u2 == bottom
1 parent 47fea95 commit 184b724

File tree

1 file changed

+50
-12
lines changed

1 file changed

+50
-12
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4495,8 +4495,7 @@ defmodule Module.Types.Descr do
44954495
_ ->
44964496
case bdd_compare(bdd1, bdd2) do
44974497
{:lt, {lit1, c1, u1, d1}, bdd2} ->
4498-
{lit1, bdd_difference(bdd_union(c1, u1), bdd2), :bdd_bot,
4499-
bdd_difference(bdd_union(d1, u1), bdd2)}
4498+
{lit1, bdd_difference(c1, bdd2), bdd_difference(u1, bdd2), bdd_difference(d1, bdd2)}
45004499

45014500
{:gt, bdd1, {lit2, c2, u2, d2}} ->
45024501
# The proper formula is:
@@ -4510,10 +4509,44 @@ defmodule Module.Types.Descr do
45104509

45114510
{:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->
45124511
cond do
4513-
u2 == :bdd_bot and d2 == :bdd_bot ->
4514-
{lit, bdd_difference(c1, c2), bdd_difference(u1, c2), bdd_union(u1, d1)}
4512+
c2 == :bdd_bot and d2 == :bdd_bot ->
4513+
{lit, bdd_difference(c1, u2), bdd_difference(u1, u2), bdd_difference(d1, u2)}
4514+
4515+
u2 == :bdd_bot ->
4516+
cond do
4517+
d2 == :bdd_bot ->
4518+
{lit, bdd_difference(c1, c2), bdd_difference(u1, c2), bdd_union(u1, d1)}
4519+
4520+
c2 == :bdd_bot ->
4521+
{lit, bdd_union(u1, c1), bdd_difference(u1, d2), bdd_difference(c1, c2)}
4522+
4523+
true ->
4524+
# If d2 or c2 are bottom, we can remove one union.
4525+
#
4526+
# For example, if d2 is bottom, we have this BDD:
4527+
#
4528+
# {l, (C1 or U1) and not C2, U1 and not C2, D1 or U1}
4529+
#
4530+
# Where the constrained part is:
4531+
#
4532+
# (l and (C1 or U1) and not C2)
4533+
#
4534+
# Which expands to:
4535+
#
4536+
# (l and C1 and not C2) or (l and U1 and not C2)
4537+
#
4538+
# Given (U1 and not C2) is already part of the uncertain/union,
4539+
# we can skip (l and U1 and not C2), and we end up with:
4540+
#
4541+
# {l, C1 and not C2, U1 and not C2, D1 or U1}
4542+
#
4543+
# Which are the formulas used above.
4544+
{lit, bdd_difference(bdd_union(u1, c1), c2),
4545+
bdd_difference(bdd_difference(u1, c2), d2),
4546+
bdd_difference(bdd_union(u1, d1), d2)}
4547+
end
45154548

4516-
u1 == u2 ->
4549+
u1 == :bdd_bot or u1 == u2 ->
45174550
{lit, bdd_difference_union(c1, c2, u2), :bdd_bot,
45184551
bdd_difference_union(d1, d2, u2)}
45194552

@@ -4574,15 +4607,20 @@ defmodule Module.Types.Descr do
45744607
bdd_intersection(bdd1, d2)}
45754608

45764609
# Notice that (l ? c1, u1, d1) and (l ? c2, u2, d2) is, on paper, equivalent to
4577-
# [(l /\ c1) \/ u1 \/ (not l /\ d1)] and [(l /\ c2) \/ u2 \/ (not l /\ d2)]
4610+
# [(l and c1) or u1 or (not l and d1)] and [(l and c2) or u2 or (not l and d2)].
4611+
#
45784612
# which is equivalent, by distributivity of intersection over union, to
4579-
# l /\ [(c1 /\ c2) \/ (c1 /\ u2) \/ (u1 /\ c2)]
4580-
# \/ (u1 /\ u2)
4581-
# \/ [(not l) /\ ((d1 /\ u2) \/ (d1 /\ d2) \/ (u1 /\ d2))]
4613+
#
4614+
# l and [(c1 and c2) or (c1 and u2) or (u1 and c2)]
4615+
# or (u1 and u2)
4616+
# or [(not l) and ((d1 and u2) or (d1 and d2) or (u1 and d2))]
4617+
#
45824618
# which is equivalent, by factoring out c1 in the first disjunct, and d1 in the third, to
4583-
# l /\ [c1 /\ (c2 \/ u2)] \/ (u1 /\ c2)
4584-
# \/ (u1 /\ u2)
4585-
# \/ (not l) /\ [d1 /\ (u2 \/ d2) \/ (u1 /\ d2)]
4619+
#
4620+
# l and [c1 and (c2 or u2)] or (u1 and c2)
4621+
# or (u1 and u2)
4622+
# or (not l) and [d1 and (u2 or d2) or (u1 and d2)]
4623+
#
45864624
# This last expression gives the following implementation:
45874625
{:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->
45884626
{lit, bdd_union(bdd_intersection_union(c1, c2, u2), bdd_intersection(u1, c2)),

0 commit comments

Comments
 (0)