- bool res = true;
- tree new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
- new_rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), new_rhs);
- /* If we have folded the VCE, then we have to create a new statement. */
- if (TREE_CODE (new_rhs) != VIEW_CONVERT_EXPR)
- {
- gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
- new_rhs = force_gimple_operand_gsi (&gsi, new_rhs, true, NULL, true, GSI_SAME_STMT);
- /* As we change the deference to a SSA_NAME, we need to return false to make sure that
- the statement does not get removed. */
- res = false;
- }
- *rhsp = new_rhs;
- fold_stmt_inplace (use_stmt);
- tidy_after_forward_propagate_addr (use_stmt);
- return res;
+ tree def_rhs_base, new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
+ new_rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), new_rhs);
+ if (TREE_CODE (new_rhs) != VIEW_CONVERT_EXPR)
+ {
+ /* If we have folded the VIEW_CONVERT_EXPR then the result is only
+ valid if we can replace the whole rhs of the use statement. */
+ if (rhs != gimple_assign_rhs1 (use_stmt))
+ return false;
+ new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, true, NULL,
+ true, GSI_NEW_STMT);
+ gimple_assign_set_rhs1 (use_stmt, new_rhs);
+ tidy_after_forward_propagate_addr (use_stmt);
+ return res;
+ }
+ /* If the defining rhs comes from an indirect reference, then do not
+ convert into a VIEW_CONVERT_EXPR. Likewise if we'll end up taking
+ the address of a V_C_E of a constant. */
+ def_rhs_base = TREE_OPERAND (def_rhs, 0);
+ while (handled_component_p (def_rhs_base))
+ def_rhs_base = TREE_OPERAND (def_rhs_base, 0);
+ if (!INDIRECT_REF_P (def_rhs_base)
+ && (!addr_p
+ || !is_gimple_min_invariant (def_rhs)))
+ {
+ /* We may have arbitrary VIEW_CONVERT_EXPRs in a nested component
+ reference. Place it there and fold the thing. */
+ *rhsp = new_rhs;
+ fold_stmt_inplace (use_stmt);
+ tidy_after_forward_propagate_addr (use_stmt);
+ return res;
+ }