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. */