force_gimple_operand doesn't really do a "deep" verification
on its input when we ask for a non-simple result here.  Instead
it trusts that the CONSTRUCTOR PRE feeds it is valid GIMPLE.
Unfortunately that isn't so if its elements required a conversion.

The following fixes it by merging gimple_convert and its use
in PRE from match-and-simplify (which avoids force_gimple_operand
entirely in PRE).  The implementation of gimple_convert is of
course still using fold here.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

Richard.

2014-10-10  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/63419
        * gimple-fold.h (gimple_convert): New function.
        * gimple-fold.c (gimple_convert): Likewise.
        * tree-ssa-pre.c (create_expression_by_pieces): Use gimple_convert
        to split out required conversions early.

        * g++.dg/torture/pr63419.C: New testcase.

Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c   (revision 216069)
--- gcc/gimple-fold.c   (working copy)
*************** rewrite_to_defined_overflow (gimple stmt
*** 5282,5284 ****
--- 5282,5301 ----
  
    return stmts;
  }
+ 
+ /* Return OP converted to TYPE by emitting a conversion statement on SEQ
+    if required using location LOC.  Note that OP will be returned
+    unmodified if GIMPLE does not require an explicit conversion between
+    its type and TYPE.  */
+ 
+ tree
+ gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op)
+ {
+   if (useless_type_conversion_p (type, TREE_TYPE (op)))
+     return op;
+   op = fold_convert_loc (loc, type, op);
+   gimple_seq stmts = NULL;
+   op = force_gimple_operand (op, &stmts, true, NULL_TREE);
+   gimple_seq_add_seq_without_update (seq, stmts);
+   return op;
+ }
Index: gcc/gimple-fold.h
===================================================================
*** gcc/gimple-fold.h   (revision 216069)
--- gcc/gimple-fold.h   (working copy)
*************** extern tree gimple_fold_indirect_ref (tr
*** 45,48 ****
--- 45,55 ----
  extern bool arith_code_with_undefined_signed_overflow (tree_code);
  extern gimple_seq rewrite_to_defined_overflow (gimple);
  
+ extern tree gimple_convert (gimple_seq *, location_t, tree, tree);
+ inline tree
+ gimple_convert (gimple_seq *seq, tree type, tree op)
+ {
+   return gimple_convert (seq, UNKNOWN_LOCATION, type, op);
+ }
+ 
  #endif  /* GCC_GIMPLE_FOLD_H */
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c  (revision 216069)
--- gcc/tree-ssa-pre.c  (working copy)
*************** create_expression_by_pieces (basic_block
*** 2819,2830 ****
            if (nary->opcode == POINTER_PLUS_EXPR)
              {
                if (i == 0)
!                 genop[i] = fold_convert (nary->type, genop[i]);
                else if (i == 1)
!                 genop[i] = convert_to_ptrofftype (genop[i]);
              }
            else
!             genop[i] = fold_convert (TREE_TYPE (nary->op[i]), genop[i]);
          }
        if (nary->opcode == CONSTRUCTOR)
          {
--- 2819,2833 ----
            if (nary->opcode == POINTER_PLUS_EXPR)
              {
                if (i == 0)
!                 genop[i] = gimple_convert (&forced_stmts,
!                                            nary->type, genop[i]);
                else if (i == 1)
!                 genop[i] = gimple_convert (&forced_stmts,
!                                            sizetype, genop[i]);
              }
            else
!             genop[i] = gimple_convert (&forced_stmts,
!                                        TREE_TYPE (nary->op[i]), genop[i]);
          }
        if (nary->opcode == CONSTRUCTOR)
          {
*************** create_expression_by_pieces (basic_block
*** 2866,2873 ****
       statements.
       We have to call unshare_expr because force_gimple_operand may
       modify the tree we pass to it.  */
!   folded = force_gimple_operand (unshare_expr (folded), &forced_stmts,
                                 false, NULL);
  
    /* If we have any intermediate expressions to the value sets, add them
       to the value sets and chain them in the instruction stream.  */
--- 2869,2878 ----
       statements.
       We have to call unshare_expr because force_gimple_operand may
       modify the tree we pass to it.  */
!   gimple_seq tem = NULL;
!   folded = force_gimple_operand (unshare_expr (folded), &tem,
                                 false, NULL);
+   gimple_seq_add_seq_without_update (&forced_stmts, tem);
  
    /* If we have any intermediate expressions to the value sets, add them
       to the value sets and chain them in the instruction stream.  */

Reply via email to