Bug 80297 - [6 Regression] Compiler time crash: type mismatch in binary expression
Summary: [6 Regression] Compiler time crash: type mismatch in binary expression
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.0
: P2 normal
Target Milestone: 6.4
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks: yarpgen
  Show dependency treegraph
 
Reported: 2017-04-03 21:54 UTC by Dmitry Babokin
Modified: 2021-11-01 23:07 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-04-04 00:00:00


Attachments
gcc7-pr80297.patch (919 bytes, patch)
2017-04-04 11:51 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry Babokin 2017-04-03 21:54:49 UTC
Top of the tree gcc crashes when compiler the following test case. Gcc 4.8 works well.

> cat f.cpp
extern const unsigned long int var_14;
extern const long long int var_15;
void foo() {
  if (0)
    int a = 809 >> -(var_14 & !var_15) + var_14 - (long long)(var_14 & !var_15);
}


> g++ -std=c++11 -w -O0 -c f.cpp
f.cpp: In function ‘void foo()’:
f.cpp:3:6: error: type mismatch in binary expression
 void foo() {
      ^~~
unsigned int

unsigned int

bool

_8 = _6 - _7;
f.cpp:3:6: internal compiler error: verify_gimple failed
0xdae8dd verify_gimple_in_seq(gimple*)
	../../gcc/gcc/tree-cfg.c:4934
0xafe1cd gimplify_body(tree_node*, bool)
	../../gcc/gcc/gimplify.c:12500
0xafe534 gimplify_function_tree(tree_node*)
	../../gcc/gcc/gimplify.c:12590
0x96e90f cgraph_node::analyze()
	../../gcc/gcc/cgraphunit.c:657
0x9718f9 analyze_functions
	../../gcc/gcc/cgraphunit.c:1118
0x9729b2 symbol_table::finalize_compilation_unit()
	../../gcc/gcc/cgraphunit.c:2603
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Comment 1 Jakub Jelinek 2017-04-04 05:40:20 UTC
Started with r229360.  Debugging.
Comment 2 Jakub Jelinek 2017-04-04 05:59:31 UTC
So far this looks like some tree sharing issue.
                      *expr_p = gimple_boolify (*expr_p);
                      if (!useless_type_conversion_p (org_type,
                                                      TREE_TYPE (*expr_p)))
                        {
                          *expr_p = fold_convert_loc (input_location,
                                                      org_type, *expr_p);
                          ret = GS_OK;
                        }
changes in place unsigned int type into bool and then wraps into cast to unsigned int, but that now bool EQ_EXPR appears somewhere else too.
Comment 3 Jakub Jelinek 2017-04-04 06:31:05 UTC
So, it is indeed that
/* Fold (A & ~B) - (A & B) into (A ^ B) - B.  */
(simplify
 (minus (bit_and:cs @0 (bit_not @1)) (bit_and:cs @0 @1))
  (minus (bit_xor @0 @1) @1))
pattern which uses @1 more than once.  For normal generic folding it wouldn't be as big problem, because we unshare everything before gimplification.
Except that in this case it triggers late, already during gimplification:
#0  generic_simplify_87 (loc=2147483653, type=<integer_type 0x7fffefae0690 unsigned int>, op0=<bit_and_expr 0x7fffefc51398>, 
    op1=<bit_and_expr 0x7fffefc51348>, captures=0x7fffffffb6b0) at generic-match.c:3644
#1  0x00000000016f22d1 in generic_simplify_MINUS_EXPR (loc=2147483653, code=MINUS_EXPR, type=<integer_type 0x7fffefae0690 unsigned int>, 
    op0=<bit_and_expr 0x7fffefc51398>, op1=<bit_and_expr 0x7fffefc51348>) at generic-match.c:12824
#2  0x00000000017406be in generic_simplify (loc=2147483653, code=MINUS_EXPR, type=<integer_type 0x7fffefae0690 unsigned int>, 
    op0=<bit_and_expr 0x7fffefc51398>, op1=<bit_and_expr 0x7fffefc51348>) at generic-match.c:33944
#3  0x0000000000d3a0ab in fold_binary_loc (loc=2147483653, code=MINUS_EXPR, type=<integer_type 0x7fffefae0690 unsigned int>, 
    op0=<bit_and_expr 0x7fffefc51398>, op1=<bit_and_expr 0x7fffefc51348>) at ../../gcc/fold-const.c:9157
#4  0x0000000000d4a1d5 in fold_build2_stat_loc (loc=2147483653, code=MINUS_EXPR, type=<integer_type 0x7fffefae0690 unsigned int>, 
    op0=<bit_and_expr 0x7fffefc51398>, op1=<bit_and_expr 0x7fffefc51348>) at ../../gcc/fold-const.c:12285
#5  0x0000000000bef110 in convert_to_integer_1 (type=<integer_type 0x7fffefae0690 unsigned int>, expr=<minus_expr 0x7fffefc511b8>, dofold=true)
    at ../../gcc/convert.c:850
#6  0x0000000000befb32 in convert_to_integer_maybe_fold (type=<integer_type 0x7fffefae0690 unsigned int>, expr=<minus_expr 0x7fffefc511b8>, 
    dofold=true) at ../../gcc/convert.c:978
#7  0x0000000000971dc6 in ocp_convert (type=<integer_type 0x7fffefae0690 unsigned int>, expr=<minus_expr 0x7fffefc511b8>, convtype=143, flags=17, 
    complain=3) at ../../gcc/cp/cvt.c:812
#8  0x0000000000974646 in convert (type=<integer_type 0x7fffefae0690 unsigned int>, expr=<minus_expr 0x7fffefc511b8>) at ../../gcc/cp/cvt.c:1590
#9  0x0000000000adfc72 in c_gimplify_expr (expr_p=0x7fffefc51318, pre_p=0x7fffffffd988, post_p=0x7fffffffd2a0)
    at ../../gcc/c-family/c-gimplify.c:247
#10 0x0000000000a4ae60 in cp_gimplify_expr (expr_p=0x7fffefc51318, pre_p=0x7fffffffd988, post_p=0x7fffffffd2a0) at ../../gcc/cp/cp-gimplify.c:863
#11 0x0000000000df0bdd in gimplify_expr (expr_p=0x7fffefc51318, pre_p=0x7fffffffd988, post_p=0x7fffffffd2a0, 
    gimple_test_f=0xdc4cde <is_gimple_reg_rhs_or_call(tree)>, fallback=1) at ../../gcc/gimplify.c:11145
#12 0x0000000000dd5b63 in gimplify_modify_expr (expr_p=0x7fffffffd3b8, pre_p=0x7fffffffd988, post_p=0x7fffffffd2a0, want_value=false)
    at ../../gcc/gimplify.c:5465

So, either we need to unshare_expr in GENERIC every time some operand is used multiple times, or have some flag we set after unsharing fn body and is set until expansion in case GENERIC folding is used during gimple optimizations (fold_build* etc.).
So far genmatch.c uses unshare_expr only for COND_EXPR or VEC_COND_EXPR conditions.
Dunno how many patterns are affected:
(simplify
 (mult (abs@1 @0) @1)
 (mult @0 @0))

(for copysigns (COPYSIGN)
 (simplify
  (mult (copysigns@2 @0 @1) @2)
  (mult @0 @0)))

(simplify
 (bit_ior:c (bit_and:cs @0 (bit_not @2)) (bit_and:cs @1 @2))
 (bit_xor (bit_and (bit_xor @0 @1) @2) @0))

(for cmp (eq ge le)
 (simplify
  (cmp @0 @0)
  (if (! FLOAT_TYPE_P (TREE_TYPE (@0))
       || ! HONOR_NANS (@0))
   { constant_boolean_node (true, type); }
   (if (cmp != EQ_EXPR)
    (eq @0 @0)))))

(for cmp (unlt ungt)
 (simplify
  (cmp @0 @0)
  (unordered @0 @0)))

       (if (! HONOR_NANS (@0))
        { constant_boolean_node (true, type); }
        /* x <= +Inf is the same as x == x, i.e. !isnan(x).  */
        (eq @0 @0)))

(simplify
 (minus (bit_and:cs @0 (bit_not @1)) (bit_and:cs @0 @1))
  (minus (bit_xor @0 @1) @1))
(simplify
 (minus (bit_and:s @0 INTEGER_CST@2) (bit_and:s @0 INTEGER_CST@1))
 (if (wi::bit_not (@2) == @1)
  (minus (bit_xor @0 @1) @1)))

(simplify
 (minus (bit_and:cs @0 @1) (bit_and:cs @0 (bit_not @1)))
  (minus @1 (bit_xor @0 @1)))

are what I found.  So shall genmatch.c watch for captures used multiple times and in GENERIC emit unshare_expr for the second and further uses in there?
Comment 4 Richard Biener 2017-04-04 07:44:55 UTC
genmatch (correctly) allows tree sharing in GENERIC, just uses unshare_expr on GENERIC parts that we still have in GIMPLE.

folding from inside the gimplifier is tricky for this reason (as it expects unshared GENERIC).  I'd say the gimplifier needs to avoid GENERIC folding
and/or call unshare_expr on its results...

Given we now have "SSA" during gimplification the gimplifier could use
fold_stmt (gsi, follow_single_use_edges).  But I see this case is even
from the gimplify langhook doing the folding ... :/

As said, genmatch not avoiding tree sharing in GENERIC is a feature and
mimics what fold-const.c does so the issue isn't new but latent anyway.
Comment 5 Richard Biener 2017-04-04 07:49:43 UTC
We can experiment with adding unshare_exprs to genmatch and see in how many patterns that triggers.  But as said, the general issue looks latent to me.
Folding during gimplification is dangerous.
Comment 6 Jakub Jelinek 2017-04-04 10:21:12 UTC
(In reply to Richard Biener from comment #5)
> We can experiment with adding unshare_exprs to genmatch and see in how many
> patterns that triggers.  But as said, the general issue looks latent to me.
> Folding during gimplification is dangerous.

It isn't just folding during gimplification, we have hundreds of fold_build* calls in tons of GIMPLE passes too, and at that point unsharing is also needed.
I'll try to implement the unsharing and we can see how many patterns it affects and based on that decide if we want some cfun flag to control the unsharing or not, ok?
Comment 7 rguenther@suse.de 2017-04-04 10:28:47 UTC
On Tue, 4 Apr 2017, jakub at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80297
> 
> --- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
> (In reply to Richard Biener from comment #5)
> > We can experiment with adding unshare_exprs to genmatch and see in how many
> > patterns that triggers.  But as said, the general issue looks latent to me.
> > Folding during gimplification is dangerous.
> 
> It isn't just folding during gimplification, we have hundreds of fold_build*
> calls in tons of GIMPLE passes too, and at that point unsharing is also needed.

Well, any GENERIC created there needs to go through force_gimple_operand
again.  Hmm, but that doesn't unshare either.

> I'll try to implement the unsharing and we can see how many patterns it affects
> and based on that decide if we want some cfun flag to control the unsharing or
> not, ok?

Ok.  But given the above we have no choice..

What are the exact rules for GENERIC?  ISTR it was that 
sub-expression sharing is allowed, right?  Or is that just for
frontend GENERIC?  OTOH it would mean that fold-const.c has to cope
with tree sharing but may not generate "new" sharing?  That would be
quite a difficult thing to verify with a verifier...
Comment 8 Jakub Jelinek 2017-04-04 11:51:43 UTC
Created attachment 41121 [details]
gcc7-pr80297.patch

Patch I'm going to test.
Comment 9 rguenther@suse.de 2017-04-04 11:54:20 UTC
On Tue, 4 Apr 2017, jakub at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80297
> 
> --- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
> Created attachment 41121 [details]
>   --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41121&action=edit
> gcc7-pr80297.patch
> 
> Patch I'm going to test.

LGTM.
Comment 10 Jakub Jelinek 2017-04-04 19:15:27 UTC
Author: jakub
Date: Tue Apr  4 19:14:47 2017
New Revision: 246693

URL: https://gcc.gnu.org/viewcvs?rev=246693&root=gcc&view=rev
Log:
	PR c++/80297
	* genmatch.c (capture::gen_transform): For GENERIC unshare_expr
	captures used multiple times, except for the last use.
	* generic-match-head.c: Include gimplify.h.

	* g++.dg/torture/pr80297.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr80297.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/generic-match-head.c
    trunk/gcc/genmatch.c
    trunk/gcc/testsuite/ChangeLog
Comment 11 Jakub Jelinek 2017-04-04 19:39:19 UTC
Fixed on the trunk so far.
Comment 12 Jakub Jelinek 2017-05-05 21:52:32 UTC
Author: jakub
Date: Fri May  5 21:52:00 2017
New Revision: 247697

URL: https://gcc.gnu.org/viewcvs?rev=247697&root=gcc&view=rev
Log:
	Backported from mainline
	2017-04-04  Jakub Jelinek  <jakub@redhat.com>
		    Richard Biener  <rguenther@suse.de>

	PR c++/80297
	* genmatch.c (capture::gen_transform): For GENERIC unshare_expr
	captures used multiple times, except for the last use.
	* generic-match-head.c: Include gimplify.h.

	* g++.dg/torture/pr80297.C: New test.

Added:
    branches/gcc-6-branch/gcc/testsuite/g++.dg/torture/pr80297.C
Modified:
    branches/gcc-6-branch/gcc/ChangeLog
    branches/gcc-6-branch/gcc/generic-match-head.c
    branches/gcc-6-branch/gcc/genmatch.c
    branches/gcc-6-branch/gcc/testsuite/ChangeLog
Comment 13 Jakub Jelinek 2017-05-29 10:58:20 UTC
Fixed.