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

Reply via email to