-/* Return an expression tree corresponding to the PREDICATE of GIMPLE_COND
- statement STMT. */
-
-static tree
-gimple_cond_pred_to_tree (gimple stmt)
-{
- /* We're sometimes presented with such code:
- D.123_1 = x < y;
- if (D.123_1 != 0)
- ...
- This would expand to two comparisons which then later might
- be cleaned up by combine. But some pattern matchers like if-conversion
- work better when there's only one compare, so make up for this
- here as special exception if TER would have made the same change. */
- tree lhs = gimple_cond_lhs (stmt);
- if (SA.values
- && TREE_CODE (lhs) == SSA_NAME
- && bitmap_bit_p (SA.values, SSA_NAME_VERSION (lhs)))
- lhs = gimple_assign_rhs_to_tree (SSA_NAME_DEF_STMT (lhs));
-
- return build2 (gimple_cond_code (stmt), boolean_type_node,
- lhs, gimple_cond_rhs (stmt));
-}
-
-/* Helper for gimple_to_tree. Set EXPR_LOCATION for every expression
- inside *TP. DATA is the location to set. */
-
-static tree
-set_expr_location_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data)
-{
- location_t *loc = (location_t *) data;
- if (EXPR_P (*tp))
- SET_EXPR_LOCATION (*tp, *loc);
-
- return NULL_TREE;
-}
-
-
-/* RTL expansion has traditionally been done on trees, so the
- transition to doing it on GIMPLE tuples is very invasive to the RTL
- expander. To facilitate the transition, this function takes a
- GIMPLE tuple STMT and returns the same statement in the form of a
- tree. */
-
-static tree
-gimple_to_tree (gimple stmt)
-{
- tree t;
- int rn;
- tree_ann_common_t ann;
- location_t loc;
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_ASSIGN:
- {
- tree lhs = gimple_assign_lhs (stmt);
-
- t = gimple_assign_rhs_to_tree (stmt);
- t = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, t);
- if (gimple_assign_nontemporal_move_p (stmt))
- MOVE_NONTEMPORAL (t) = true;
- }
- break;
-
- case GIMPLE_COND:
- t = gimple_cond_pred_to_tree (stmt);
- t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
- break;
-
- case GIMPLE_GOTO:
- t = build1 (GOTO_EXPR, void_type_node, gimple_goto_dest (stmt));
- break;
-
- case GIMPLE_LABEL:
- t = build1 (LABEL_EXPR, void_type_node, gimple_label_label (stmt));
- break;
-
- case GIMPLE_RETURN:
- {
- tree retval = gimple_return_retval (stmt);
-
- if (retval && retval != error_mark_node)
- {
- tree result = DECL_RESULT (current_function_decl);
-
- /* If we are not returning the current function's RESULT_DECL,
- build an assignment to it. */
- if (retval != result)
- {
- /* I believe that a function's RESULT_DECL is unique. */
- gcc_assert (TREE_CODE (retval) != RESULT_DECL);
-
- retval = build2 (MODIFY_EXPR, TREE_TYPE (result),
- result, retval);
- }
- }
- t = build1 (RETURN_EXPR, void_type_node, retval);
- }
- break;
-
- case GIMPLE_ASM:
- {
- size_t i, n;
- tree out, in, cl;
- const char *s;
-
- out = NULL_TREE;
- n = gimple_asm_noutputs (stmt);
- if (n > 0)
- {
- t = out = gimple_asm_output_op (stmt, 0);
- for (i = 1; i < n; i++)
- {
- TREE_CHAIN (t) = gimple_asm_output_op (stmt, i);
- t = gimple_asm_output_op (stmt, i);
- }
- }
-
- in = NULL_TREE;
- n = gimple_asm_ninputs (stmt);
- if (n > 0)
- {
- t = in = gimple_asm_input_op (stmt, 0);
- for (i = 1; i < n; i++)
- {
- TREE_CHAIN (t) = gimple_asm_input_op (stmt, i);
- t = gimple_asm_input_op (stmt, i);
- }
- }
-
- cl = NULL_TREE;
- n = gimple_asm_nclobbers (stmt);
- if (n > 0)
- {
- t = cl = gimple_asm_clobber_op (stmt, 0);
- for (i = 1; i < n; i++)
- {
- TREE_CHAIN (t) = gimple_asm_clobber_op (stmt, i);
- t = gimple_asm_clobber_op (stmt, i);
- }
- }
-
- s = gimple_asm_string (stmt);
- t = build4 (ASM_EXPR, void_type_node, build_string (strlen (s), s),
- out, in, cl);
- ASM_VOLATILE_P (t) = gimple_asm_volatile_p (stmt);
- ASM_INPUT_P (t) = gimple_asm_input_p (stmt);
- }
- break;
-
- case GIMPLE_CALL:
- {
- size_t i;
- tree fn;
- tree_ann_common_t ann;
-
- t = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
-
- CALL_EXPR_FN (t) = gimple_call_fn (stmt);
- TREE_TYPE (t) = gimple_call_return_type (stmt);
- CALL_EXPR_STATIC_CHAIN (t) = gimple_call_chain (stmt);
-
- for (i = 0; i < gimple_call_num_args (stmt); i++)
- CALL_EXPR_ARG (t, i) = gimple_call_arg (stmt, i);
-
- if (!(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE)))
- TREE_SIDE_EFFECTS (t) = 1;
-
- if (gimple_call_flags (stmt) & ECF_NOTHROW)
- TREE_NOTHROW (t) = 1;
-
- CALL_EXPR_TAILCALL (t) = gimple_call_tail_p (stmt);
- CALL_EXPR_RETURN_SLOT_OPT (t) = gimple_call_return_slot_opt_p (stmt);
- CALL_FROM_THUNK_P (t) = gimple_call_from_thunk_p (stmt);
- CALL_CANNOT_INLINE_P (t) = gimple_call_cannot_inline_p (stmt);
- CALL_EXPR_VA_ARG_PACK (t) = gimple_call_va_arg_pack_p (stmt);
-
- /* If the call has a LHS then create a MODIFY_EXPR to hold it. */
- {
- tree lhs = gimple_call_lhs (stmt);
-
- if (lhs)
- t = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, t);
- }
-
- /* Record the original call statement, as it may be used
- to retrieve profile information during expansion. */
-
- if ((fn = gimple_call_fndecl (stmt)) != NULL_TREE
- && DECL_BUILT_IN (fn))
- {
- ann = get_tree_common_ann (t);
- ann->stmt = stmt;
- }
- }
- break;
-
- case GIMPLE_SWITCH:
- {
- tree label_vec;
- size_t i;
- tree elt = gimple_switch_label (stmt, 0);
-
- label_vec = make_tree_vec (gimple_switch_num_labels (stmt));
-
- if (!CASE_LOW (elt) && !CASE_HIGH (elt))
- {
- for (i = 1; i < gimple_switch_num_labels (stmt); i++)
- TREE_VEC_ELT (label_vec, i - 1) = gimple_switch_label (stmt, i);
-
- /* The default case in a SWITCH_EXPR must be at the end of
- the label vector. */
- TREE_VEC_ELT (label_vec, i - 1) = gimple_switch_label (stmt, 0);
- }
- else
- {
- for (i = 0; i < gimple_switch_num_labels (stmt); i++)
- TREE_VEC_ELT (label_vec, i) = gimple_switch_label (stmt, i);
- }
-
- t = build3 (SWITCH_EXPR, void_type_node, gimple_switch_index (stmt),
- NULL, label_vec);
- }
- break;
-
- case GIMPLE_NOP:
- case GIMPLE_PREDICT:
- t = build1 (NOP_EXPR, void_type_node, size_zero_node);
- break;
-
- case GIMPLE_RESX:
- t = build_resx (gimple_resx_region (stmt));
- break;
-
- default:
- if (errorcount == 0)
- {
- error ("Unrecognized GIMPLE statement during RTL expansion");
- print_gimple_stmt (stderr, stmt, 4, 0);
- gcc_unreachable ();
- }
- else
- {
- /* Ignore any bad gimple codes if we're going to die anyhow,
- so we can at least set TREE_ASM_WRITTEN and have the rest
- of compilation advance without sudden ICE death. */
- t = build1 (NOP_EXPR, void_type_node, size_zero_node);
- break;
- }
- }
-
- /* If STMT is inside an exception region, record it in the generated
- expression. */
- rn = lookup_stmt_eh_region (stmt);
- if (rn >= 0)
- {
- tree call = get_call_expr_in (t);
-
- ann = get_tree_common_ann (t);
- ann->rn = rn;
-
- /* For a CALL_EXPR on the RHS of an assignment, calls.c looks up
- the CALL_EXPR not the assignment statment for EH region number. */
- if (call && call != t)
- {
- ann = get_tree_common_ann (call);
- ann->rn = rn;
- }
- }
-
- /* Set EXPR_LOCATION in all the embedded expressions. */
- loc = gimple_location (stmt);
- walk_tree (&t, set_expr_location_r, (void *) &loc, NULL);
-
- TREE_BLOCK (t) = gimple_block (stmt);
-
- return t;
-}
-
-
-/* Release back to GC memory allocated by gimple_to_tree. */
-
-static void
-release_stmt_tree (gimple stmt, tree stmt_tree)
-{
- tree_ann_common_t ann;
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_ASSIGN:
- if (get_gimple_rhs_class (gimple_expr_code (stmt)) != GIMPLE_SINGLE_RHS)
- ggc_free (TREE_OPERAND (stmt_tree, 1));
- break;
- case GIMPLE_COND:
- ggc_free (COND_EXPR_COND (stmt_tree));
- break;
- case GIMPLE_RETURN:
- if (TREE_OPERAND (stmt_tree, 0)
- && TREE_CODE (TREE_OPERAND (stmt_tree, 0)) == MODIFY_EXPR)
- ggc_free (TREE_OPERAND (stmt_tree, 0));
- break;
- case GIMPLE_CALL:
- if (gimple_call_lhs (stmt))
- {
- ann = tree_common_ann (TREE_OPERAND (stmt_tree, 1));
- if (ann)
- ggc_free (ann);
- ggc_free (TREE_OPERAND (stmt_tree, 1));
- }
- break;
- default:
- break;
- }
- ann = tree_common_ann (stmt_tree);
- if (ann)
- ggc_free (ann);
- ggc_free (stmt_tree);
-}
-
-
-/* Verify that there is exactly single jump instruction since last and attach
- REG_BR_PROB note specifying probability.
- ??? We really ought to pass the probability down to RTL expanders and let it
- re-distribute it when the conditional expands into multiple conditionals.
- This is however difficult to do. */
-void
-add_reg_br_prob_note (rtx last, int probability)
-{
- if (profile_status == PROFILE_ABSENT)
- return;
- for (last = NEXT_INSN (last); last && NEXT_INSN (last); last = NEXT_INSN (last))
- if (JUMP_P (last))
- {
- /* It is common to emit condjump-around-jump sequence when we don't know
- how to reverse the conditional. Special case this. */
- if (!any_condjump_p (last)
- || !JUMP_P (NEXT_INSN (last))
- || !simplejump_p (NEXT_INSN (last))
- || !NEXT_INSN (NEXT_INSN (last))
- || !BARRIER_P (NEXT_INSN (NEXT_INSN (last)))
- || !NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))
- || !LABEL_P (NEXT_INSN (NEXT_INSN (NEXT_INSN (last))))
- || NEXT_INSN (NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))))
- goto failed;
- gcc_assert (!find_reg_note (last, REG_BR_PROB, 0));
- add_reg_note (last, REG_BR_PROB,
- GEN_INT (REG_BR_PROB_BASE - probability));
- return;
- }
- if (!last || !JUMP_P (last) || !any_condjump_p (last))
- goto failed;
- gcc_assert (!find_reg_note (last, REG_BR_PROB, 0));
- add_reg_note (last, REG_BR_PROB, GEN_INT (probability));
- return;
-failed:
- if (dump_file)
- fprintf (dump_file, "Failed to add probability note\n");
-}
-