-
-/* Fold the statement pointed to by STMT_P. In some cases, this function may
- replace the whole statement with a new one. Returns true iff folding
- makes any changes. */
-
-bool
-fold_stmt (tree *stmt_p)
-{
- tree rhs, result, stmt;
- struct fold_stmt_r_data fold_stmt_r_data;
- bool changed = false;
- bool inside_addr_expr = false;
-
- stmt = *stmt_p;
-
- fold_stmt_r_data.stmt = stmt;
- fold_stmt_r_data.changed_p = &changed;
- fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
-
- /* If we replaced constants and the statement makes pointer dereferences,
- then we may need to fold instances of *&VAR into VAR, etc. */
- if (walk_tree (stmt_p, fold_stmt_r, &fold_stmt_r_data, NULL))
- {
- *stmt_p = build_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], 0);
- return true;
- }
-
- rhs = get_rhs (stmt);
- if (!rhs)
- return changed;
- result = NULL_TREE;
-
- if (TREE_CODE (rhs) == CALL_EXPR)
- {
- tree callee;
-
- /* Check for builtins that CCP can handle using information not
- available in the generic fold routines. */
- callee = get_callee_fndecl (rhs);
- if (callee && DECL_BUILT_IN (callee))
- result = ccp_fold_builtin (stmt, rhs);
- else
- {
- /* Check for resolvable OBJ_TYPE_REF. The only sorts we can resolve
- here are when we've propagated the address of a decl into the
- object slot. */
- /* ??? Should perhaps do this in fold proper. However, doing it
- there requires that we create a new CALL_EXPR, and that requires
- copying EH region info to the new node. Easier to just do it
- here where we can just smash the call operand. Also
- CALL_EXPR_RETURN_SLOT_OPT needs to be handled correctly and
- copied, fold_call_expr does not have not information. */
- callee = CALL_EXPR_FN (rhs);
- if (TREE_CODE (callee) == OBJ_TYPE_REF
- && lang_hooks.fold_obj_type_ref
- && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
- && DECL_P (TREE_OPERAND
- (OBJ_TYPE_REF_OBJECT (callee), 0)))
- {
- tree t;
-
- /* ??? Caution: Broken ADDR_EXPR semantics means that
- looking at the type of the operand of the addr_expr
- can yield an array type. See silly exception in
- check_pointer_types_r. */
-
- t = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (callee)));
- t = lang_hooks.fold_obj_type_ref (callee, t);
- if (t)
- {
- CALL_EXPR_FN (rhs) = t;
- changed = true;
- }
- }
- }
- }
- else if (TREE_CODE (rhs) == COND_EXPR)
- {
- tree temp = fold (COND_EXPR_COND (rhs));
- if (temp != COND_EXPR_COND (rhs))
- result = fold_build3 (COND_EXPR, TREE_TYPE (rhs), temp,
- COND_EXPR_THEN (rhs), COND_EXPR_ELSE (rhs));
- }
-
- /* If we couldn't fold the RHS, hand over to the generic fold routines. */
- if (result == NULL_TREE)
- result = fold (rhs);
-
- /* Strip away useless type conversions. Both the NON_LVALUE_EXPR that
- may have been added by fold, and "useless" type conversions that might
- now be apparent due to propagation. */
- STRIP_USELESS_TYPE_CONVERSION (result);
-
- if (result != rhs)
- changed |= set_rhs (stmt_p, result);
-
- return changed;
-}
-
-/* Perform the minimal folding on statement STMT. Only operations like
- *&x created by constant propagation are handled. The statement cannot
- be replaced with a new one. */
-
-bool
-fold_stmt_inplace (tree stmt)
-{
- tree old_stmt = stmt, rhs, new_rhs;
- struct fold_stmt_r_data fold_stmt_r_data;
- bool changed = false;
- bool inside_addr_expr = false;
-
- fold_stmt_r_data.stmt = stmt;
- fold_stmt_r_data.changed_p = &changed;
- fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
-
- walk_tree (&stmt, fold_stmt_r, &fold_stmt_r_data, NULL);
- gcc_assert (stmt == old_stmt);
-
- rhs = get_rhs (stmt);
- if (!rhs || rhs == stmt)
- return changed;
-
- new_rhs = fold (rhs);
- STRIP_USELESS_TYPE_CONVERSION (new_rhs);
- if (new_rhs == rhs)
- return changed;
-
- changed |= set_rhs (&stmt, new_rhs);
- gcc_assert (stmt == old_stmt);
-
- return changed;
-}
-\f
-/* Convert EXPR into a GIMPLE value suitable for substitution on the
- RHS of an assignment. Insert the necessary statements before
- iterator *SI_P.
- When IGNORE is set, don't worry about the return value. */
-
-static tree
-convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr, bool ignore)
-{
- tree_stmt_iterator ti;
- tree stmt = bsi_stmt (*si_p);
- tree tmp, stmts = NULL;
-
- push_gimplify_context ();
- if (ignore)
- {
- tmp = build_empty_stmt ();
- gimplify_and_add (expr, &stmts);
- }
- else
- tmp = get_initialized_tmp_var (expr, &stmts, NULL);
- pop_gimplify_context (NULL);
-
- if (EXPR_HAS_LOCATION (stmt))
- annotate_all_with_locus (&stmts, EXPR_LOCATION (stmt));
-
- /* The replacement can expose previously unreferenced variables. */
- for (ti = tsi_start (stmts); !tsi_end_p (ti); tsi_next (&ti))
- {
- tree new_stmt = tsi_stmt (ti);
- find_new_referenced_vars (tsi_stmt_ptr (ti));
- bsi_insert_before (si_p, new_stmt, BSI_NEW_STMT);
- mark_symbols_for_renaming (new_stmt);
- bsi_next (si_p);
- }
-
- return tmp;
-}
-
-