On Tue, Dec 17, 2024 at 10:43:49AM -0500, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk? Shall we also backport this to release branches?
> It's not a regression but seems like a safe fix for an inconvenient
> issue.
>
> -- >8 --
>
> For the testcase in the PR we hang during constraint normalization
> ultimately because one of the constraints is complex enough that its
> conjunctive normal form is calculated to have more than 2^31 clauses,
> which causes the size calculation (through an int) to overflow and so
> the optimization in subsumes_constraints_nonnull
>
> if (dnf_size (lhs) <= cnf_size (rhs))
> // iterate over DNF of LHS
> else
> // iterate over CNF of RHS
>
> incorrectly decides to loop over the CNF (billions of clauses) instead
> of the DNF (thousands of clauses).
>
> I haven't verified that the result of cnf_size is correct for the
> problematic constraint but integer overflow is definitely plausible
> given that CNF/DNF can be exponentially larger than the original
> constraint in the worst case.
>
> This patch fixes this by using a 64-bit unsigned int during DNF/CNF size
> calculation which is enough to avoid overflow in the testcase, and we now
> compile it in ~3 seconds.
Sorry for a silly question, but is there a reason to prefer
unsigned HOST_WIDE_INT over uint64_t?
Patch seems fine, though, thanks.
> In theory doubling the precision will only let us handle a ~2x bigger
> constraint before risking overflow in the worst case given the
> exponential-ness, but I suppose it should suffice for now.
>
> PR c++/118069
>
> gcc/cp/ChangeLog:
>
> * logic.cc (dnf_size_r): Use unsigned HOST_WIDE_INT instead of int.
> (cnf_size_r): Likewise.
> (dnf_size): Likewise.
> (cnf_size): Likewise.
> ---
> gcc/cp/logic.cc | 24 ++++++++++++------------
> 1 file changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc
> index fab2c357dc4..e46ea0ebb78 100644
> --- a/gcc/cp/logic.cc
> +++ b/gcc/cp/logic.cc
> @@ -349,7 +349,7 @@ atomic_p (tree t)
> distributing. In general, a conjunction for which this flag is set
> is considered a disjunction for the purpose of counting. */
>
> -static std::pair<int, bool>
> +static std::pair<unsigned HOST_WIDE_INT, bool>
> dnf_size_r (tree t)
> {
> if (atomic_p (t))
> @@ -360,9 +360,9 @@ dnf_size_r (tree t)
> the results. */
> tree lhs = TREE_OPERAND (t, 0);
> tree rhs = TREE_OPERAND (t, 1);
> - std::pair<int, bool> p1 = dnf_size_r (lhs);
> - std::pair<int, bool> p2 = dnf_size_r (rhs);
> - int n1 = p1.first, n2 = p2.first;
> + auto p1 = dnf_size_r (lhs);
> + auto p2 = dnf_size_r (rhs);
> + unsigned HOST_WIDE_INT n1 = p1.first, n2 = p2.first;
> bool d1 = p1.second, d2 = p2.second;
>
> if (disjunction_p (t))
> @@ -457,7 +457,7 @@ dnf_size_r (tree t)
> distributing. In general, a disjunction for which this flag is set
> is considered a conjunction for the purpose of counting. */
>
> -static std::pair<int, bool>
> +static std::pair<unsigned HOST_WIDE_INT, bool>
> cnf_size_r (tree t)
> {
> if (atomic_p (t))
> @@ -468,9 +468,9 @@ cnf_size_r (tree t)
> the results. */
> tree lhs = TREE_OPERAND (t, 0);
> tree rhs = TREE_OPERAND (t, 1);
> - std::pair<int, bool> p1 = cnf_size_r (lhs);
> - std::pair<int, bool> p2 = cnf_size_r (rhs);
> - int n1 = p1.first, n2 = p2.first;
> + auto p1 = cnf_size_r (lhs);
> + auto p2 = cnf_size_r (rhs);
> + unsigned HOST_WIDE_INT n1 = p1.first, n2 = p2.first;
> bool d1 = p1.second, d2 = p2.second;
>
> if (disjunction_p (t))
> @@ -560,10 +560,10 @@ cnf_size_r (tree t)
> /* Count the number conjunctive clauses that would be created
> when rewriting T to DNF. */
>
> -static int
> +static unsigned HOST_WIDE_INT
> dnf_size (tree t)
> {
> - std::pair<int, bool> result = dnf_size_r (t);
> + auto result = dnf_size_r (t);
> return result.first == 0 ? 1 : result.first;
> }
>
> @@ -571,10 +571,10 @@ dnf_size (tree t)
> /* Count the number disjunctive clauses that would be created
> when rewriting T to CNF. */
>
> -static int
> +static unsigned HOST_WIDE_INT
> cnf_size (tree t)
> {
> - std::pair<int, bool> result = cnf_size_r (t);
> + auto result = cnf_size_r (t);
> return result.first == 0 ? 1 : result.first;
> }
>
> --
> 2.48.0.rc0
>
Marek