I believe there is a bug in fold_widened_comparison() present in all versions
of gcc including 4.1 
    
The lines 6103 - 6105 of fold-const.c (gcc 4.0.1) looks like:
    
    arg1_unw = get_unwidened (arg1, shorter_type);
    if (!arg1_unw)
      return NULL_TREE; 

Notice that get_unwidened() never returns zero, so the if() may
look redundant, but actually it has to be arg1_unw == arg1 comparison
that will signify that get_unwidened() failed to adjust arg1
to shorter type.

The diff for fix looks like:
------- fold-const.c -------
*** fold-const.c_old    Mon Aug 22 17:57:51 2005
--- fold-const.c        Mon Aug 22 16:42:59 2005
***************
*** 6101,6107 ****
      return NULL_TREE;
    
    arg1_unw = get_unwidened (arg1, shorter_type);
!   if (!arg1_unw)
      return NULL_TREE;
    
    /* If possible, express the comparison in the shorter mode.  */
--- 6101,6107 ----
      return NULL_TREE; 
    
    arg1_unw = get_unwidened (arg1, shorter_type);
!   if (arg1_unw == arg1)
      return NULL_TREE;
  
    /* If possible, express the comparison in the shorter mode.  */


Unfortunately I don't have a source example that demonstrates this bug,
but if you take the source from PR #21331 and run it on platform
with 64-bit longs the function foo():
unsigned long
foo ()
{ unsigned long retval;
  retval = bar ();
  if (retval == -1)  return 0;
  return 3;  }

will contain an expression: (long long unsigned intD.6) D.1112 == -1.

 <eq_expr fef90230
    type <boolean_type fef92880 _Bool public unsigned QI
        size <integer_cst fef84200 constant invariant 8>
        unit size <integer_cst fef84220 constant invariant 1>
        align 8 symtab 0 alias set -1 precision 1 min <integer_cst fef84740 0>
max <integer_cst fef84780 1>>
   
    arg 0 <nop_expr fef84ea0
        type <integer_type fef92700 long unsigned int sizes-gimplified public
unsigned DI
            size <integer_cst fef845c0 constant invariant 64>
            unit size <integer_cst fef845e0 constant invariant 8>
            align 64 symtab 0 alias set -1 precision 64 min <integer_cst
fef84680 0> max <integer_cst fef84660 18446744073709551615>>
       
        arg 0 <var_decl ff00eff0 D.1108 type <integer_type fef92580 int>
            used ignored SI file simple.c line 8
            size <integer_cst fef844a0 constant invariant 32>
            unit size <integer_cst fef84160 constant invariant 4>
            align 32 context <function_decl ff00ee58 foo> chain <var_decl
ff00f078 D.1109>>>
    arg 1 <integer_cst fef84660 type <integer_type fef92700 long unsigned int>
constant invariant 18446744073709551615>
    simple.c:9>

and if you try to apply fold() to this expression you'll receive an incorrect
result.
The fold(eq_expr above) will produce zero.

Let's take a look at fold_widened_comparison() to better understand the problem:

static tree
fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
{
  tree arg0_unw = get_unwidened (arg0, NULL_TREE);
  tree arg1_unw;
  tree shorter_type, outer_type;
  tree min, max;
  bool above, below;

  if (arg0_unw == arg0)
    return NULL_TREE;
  shorter_type = TREE_TYPE (arg0_unw);

  if (TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (shorter_type))
    return NULL_TREE;

  arg1_unw = get_unwidened (arg1, shorter_type);
  if (arg1_unw == arg1) /* *********** line 6103.  fixed */
    return NULL_TREE;

The first call to get_unwidened(arg0 == nop_expr of var_decl) will remove
NOP_EXPR and
will return 32-bit VAR_DECL.
2nd call to get_unwidened(arg1 == 64-bit integer_cst) will return 64-bit integer
cst.
and incorrect check in line 6103 will fail to recognize type mismatch.
Further calls to fold_relational_const() will compare max 32-bit const with our 
arg1
64-bit constant and incorrectly determine that such eq_expr is always zero.

The fix is trivial. If 2nd get_unwidened() returned the same tree, don't do any
further folding.

Alexey.

-- 
           Summary: fold() bug
           Product: gcc
           Version: 4.0.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: tree-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: alexey dot starovoytov at sun dot com
                CC: gcc-bugs at gcc dot gnu dot org
 GCC build triplet: x86_64-unknown-linux-gnu
  GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: x86_64-unknown-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23522

Reply via email to