-/* Compute immediate uses.
-
- CALC_FOR is an optional function pointer which indicates whether
- immediate uses information should be calculated for a given SSA
- variable. If NULL, then information is computed for all
- variables.
-
- FLAGS is one of {TDFA_USE_OPS, TDFA_USE_VOPS}. It is used by
- compute_immediate_uses_for_stmt to determine whether to look at
- virtual and/or real operands while computing def-use chains. */
-
-void
-compute_immediate_uses (int flags, bool (*calc_for)(tree))
-{
- basic_block bb;
- block_stmt_iterator si;
-
- FOR_EACH_BB (bb)
- {
- tree phi;
-
- for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
- compute_immediate_uses_for_phi (phi, calc_for);
-
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- {
- tree stmt = bsi_stmt (si);
- get_stmt_operands (stmt);
- compute_immediate_uses_for_stmt (stmt, flags, calc_for);
- }
- }
-}
-
-
-/* Invalidates dataflow information for a statement STMT. */
-
-static void
-free_df_for_stmt (tree stmt)
-{
- stmt_ann_t ann = stmt_ann (stmt);
-
- if (ann && ann->df)
- {
- /* If we have a varray of immediate uses, then go ahead and release
- it for re-use. */
- if (ann->df->immediate_uses)
- ggc_free (ann->df->immediate_uses);
-
- /* Similarly for the main dataflow structure. */
- ggc_free (ann->df);
- ann->df = NULL;
- }
-}
-
-
-/* Invalidate dataflow information for the whole function. */
-
-void
-free_df (void)
-{
- basic_block bb;
- block_stmt_iterator si;
-
- FOR_EACH_BB (bb)
- {
- tree phi;
-
- for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
- free_df_for_stmt (phi);
-
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- {
- tree stmt = bsi_stmt (si);
- free_df_for_stmt (stmt);
- }
- }
-}
-
-
-/* Helper for compute_immediate_uses. Check all the USE and/or VUSE
- operands in phi node PHI and add a def-use edge between their
- defining statement and PHI. CALC_FOR is as in
- compute_immediate_uses.
-
- PHI nodes are easy, we only need to look at their arguments. */
-
-static void
-compute_immediate_uses_for_phi (tree phi, bool (*calc_for)(tree))
-{
- int i;
-
-#ifdef ENABLE_CHECKING
- if (TREE_CODE (phi) != PHI_NODE)
- abort ();
-#endif
-
- for (i = 0; i < PHI_NUM_ARGS (phi); i++)
- {
- tree arg = PHI_ARG_DEF (phi, i);
-
- if (TREE_CODE (arg) == SSA_NAME && (!calc_for || calc_for (arg)))
- {
- tree imm_rdef_stmt = SSA_NAME_DEF_STMT (PHI_ARG_DEF (phi, i));
- if (!IS_EMPTY_STMT (imm_rdef_stmt))
- add_immediate_use (imm_rdef_stmt, phi);
- }
- }
-}
-
-
-/* Another helper for compute_immediate_uses. Depending on the value
- of FLAGS, check all the USE and/or VUSE operands in STMT and add a
- def-use edge between their defining statement and STMT. CALC_FOR
- is as in compute_immediate_uses. */
-
-static void
-compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree))
-{
- size_t i;
- use_optype uses;
- vuse_optype vuses;
- v_may_def_optype v_may_defs;
- stmt_ann_t ann;
-
-#ifdef ENABLE_CHECKING
- /* PHI nodes are handled elsewhere. */
- if (TREE_CODE (stmt) == PHI_NODE)
- abort ();
-#endif
-
- /* Look at USE_OPS or VUSE_OPS according to FLAGS. */
- ann = stmt_ann (stmt);
- if (flags & TDFA_USE_OPS)
- {
- uses = USE_OPS (ann);
- for (i = 0; i < NUM_USES (uses); i++)
- {
- tree use = USE_OP (uses, i);
- tree imm_stmt = SSA_NAME_DEF_STMT (use);
- if (!IS_EMPTY_STMT (imm_stmt) && (!calc_for || calc_for (use)))
- add_immediate_use (imm_stmt, stmt);
- }
- }
-
- if (flags & TDFA_USE_VOPS)
- {
- vuses = VUSE_OPS (ann);
- for (i = 0; i < NUM_VUSES (vuses); i++)
- {
- tree vuse = VUSE_OP (vuses, i);
- tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse);
- if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse)))
- add_immediate_use (imm_rdef_stmt, stmt);
- }
-
- v_may_defs = V_MAY_DEF_OPS (ann);
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
- {
- tree vuse = V_MAY_DEF_OP (v_may_defs, i);
- tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse);
- if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse)))
- add_immediate_use (imm_rdef_stmt, stmt);
- }
- }
-}
-
-
-/* Add statement USE_STMT to the list of statements that use definitions
- made by STMT. */
-
-static void
-add_immediate_use (tree stmt, tree use_stmt)
-{
- stmt_ann_t ann = get_stmt_ann (stmt);
- struct dataflow_d *df;
-
- df = ann->df;
- if (df == NULL)
- {
- df = ann->df = ggc_alloc (sizeof (struct dataflow_d));
- memset ((void *) df, 0, sizeof (struct dataflow_d));
- df->uses[0] = use_stmt;
- return;
- }
-
- if (!df->uses[1])
- {
- df->uses[1] = use_stmt;
- return;
- }
-
- if (ann->df->immediate_uses == NULL)
- VARRAY_TREE_INIT (ann->df->immediate_uses, 4, "immediate_uses");
-
- VARRAY_PUSH_TREE (ann->df->immediate_uses, use_stmt);
-}
-
-
-/* If the immediate use of USE points to OLD, then redirect it to NEW. */
-
-static void
-redirect_immediate_use (tree use, tree old, tree new)
-{
- tree imm_stmt = SSA_NAME_DEF_STMT (use);
- struct dataflow_d *df = get_stmt_ann (imm_stmt)->df;
- unsigned int num_uses = num_immediate_uses (df);
- unsigned int i;
-
- for (i = 0; i < num_uses; i++)
- {
- if (immediate_use (df, i) == old)
- {
- if (i == 0 || i == 1)
- df->uses[i] = new;
- else
- VARRAY_TREE (df->immediate_uses, i - 2) = new;
- }
- }
-}
-
-
-/* Redirect all immediate uses for operands in OLD so that they point
- to NEW. This routine should have no knowledge of how immediate
- uses are stored. */
-
-void
-redirect_immediate_uses (tree old, tree new)
-{
- stmt_ann_t ann = get_stmt_ann (old);
- use_optype uses = USE_OPS (ann);
- vuse_optype vuses = VUSE_OPS (ann);
- v_may_def_optype v_may_defs = V_MAY_DEF_OPS (ann);
- unsigned int i;
-
- /* Look at USE_OPS or VUSE_OPS according to FLAGS. */
- for (i = 0; i < NUM_USES (uses); i++)
- redirect_immediate_use (USE_OP (uses, i), old, new);
-
- for (i = 0; i < NUM_VUSES (vuses); i++)
- redirect_immediate_use (VUSE_OP (vuses, i), old, new);
-
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
- redirect_immediate_use (V_MAY_DEF_OP (v_may_defs, i), old, new);
-}
-
-