Skip to content

Commit d596853

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 640275b commit d596853

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,19 +4495,52 @@ 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
{lit2, bdd_difference(bdd1, bdd_union(c2, u2)), :bdd_bot,
45034502
bdd_difference(bdd1, bdd_union(d2, u2))}
45044503

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

4510-
u1 == u2 ->
4543+
u1 == :bdd_bot or u1 == u2 ->
45114544
{lit, bdd_difference_union(c1, c2, u2), :bdd_bot,
45124545
bdd_difference_union(d1, d2, u2)}
45134546

@@ -4568,15 +4601,20 @@ defmodule Module.Types.Descr do
45684601
bdd_intersection(bdd1, d2)}
45694602

45704603
# Notice that (l ? c1, u1, d1) and (l ? c2, u2, d2) is, on paper, equivalent to
4571-
# [(l /\ c1) \/ u1 \/ (not l /\ d1)] and [(l /\ c2) \/ u2 \/ (not l /\ d2)]
4604+
# [(l and c1) or u1 or (not l and d1)] and [(l and c2) or u2 or (not l and d2)].
4605+
#
45724606
# which is equivalent, by distributivity of intersection over union, to
4573-
# l /\ [(c1 /\ c2) \/ (c1 /\ u2) \/ (u1 /\ c2)]
4574-
# \/ (u1 /\ u2)
4575-
# \/ [(not l) /\ ((d1 /\ u2) \/ (d1 /\ d2) \/ (u1 /\ d2))]
4607+
#
4608+
# l and [(c1 and c2) or (c1 and u2) or (u1 and c2)]
4609+
# or (u1 and u2)
4610+
# or [(not l) and ((d1 and u2) or (d1 and d2) or (u1 and d2))]
4611+
#
45764612
# which is equivalent, by factoring out c1 in the first disjunct, and d1 in the third, to
4577-
# l /\ [c1 /\ (c2 \/ u2)] \/ (u1 /\ c2)
4578-
# \/ (u1 /\ u2)
4579-
# \/ (not l) /\ [d1 /\ (u2 \/ d2) \/ (u1 /\ d2)]
4613+
#
4614+
# l and [c1 and (c2 or u2)] or (u1 and c2)
4615+
# or (u1 and u2)
4616+
# or (not l) and [d1 and (u2 or d2) or (u1 and d2)]
4617+
#
45804618
# This last expression gives the following implementation:
45814619
{:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->
45824620
{lit, bdd_union(bdd_intersection_union(c1, c2, u2), bdd_intersection(u1, c2)),

0 commit comments

Comments
 (0)