diff options
Diffstat (limited to 'gcc/tree-ssa-operands.c')
-rw-r--r-- | gcc/tree-ssa-operands.c | 567 |
1 files changed, 476 insertions, 91 deletions
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 916814dc4de..979337b12ae 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -127,9 +127,9 @@ static GTY (()) varray_type ro_call_vuses; static bool clobbered_aliased_loads; static bool clobbered_aliased_stores; static bool ro_call_aliased_loads; +static stmt_operands_p parse_old_ops = NULL; def_operand_p NULL_DEF_OPERAND_P = { NULL }; -use_operand_p NULL_USE_OPERAND_P = { NULL }; static void note_addressable (tree, stmt_ann_t); static void get_expr_operands (tree, tree *, int); @@ -165,7 +165,7 @@ allocate_use_optype (unsigned num) { use_optype use_ops; unsigned size; - size = sizeof (struct use_optype_d) + sizeof (tree *) * (num - 1); + size = sizeof (struct use_optype_d) + sizeof (use_operand_type_t) * (num - 1); use_ops = ggc_alloc (size); use_ops->num_uses = num; return use_ops; @@ -194,7 +194,8 @@ allocate_vuse_optype (unsigned num) { vuse_optype vuse_ops; unsigned size; - size = sizeof (struct vuse_optype_d) + sizeof (tree) * (num - 1); + size = sizeof (struct vuse_optype_d) + + sizeof (vuse_operand_type_t) * (num - 1); vuse_ops = ggc_alloc (size); vuse_ops->num_vuses = num; return vuse_ops; @@ -222,6 +223,10 @@ free_uses (use_optype *uses) { if (*uses) { + unsigned int x; + use_optype use = *uses; + for (x = 0; x < use->num_uses; x++) + delink_imm_use (&(use->uses[x])); ggc_free (*uses); *uses = NULL; } @@ -248,6 +253,10 @@ free_vuses (vuse_optype *vuses) { if (*vuses) { + unsigned int x; + vuse_optype vuse = *vuses; + for (x = 0; x < vuse->num_vuses; x++) + delink_imm_use (&(vuse->vuses[x].imm_use)); ggc_free (*vuses); *vuses = NULL; } @@ -261,6 +270,10 @@ free_v_may_defs (v_may_def_optype *v_may_defs) { if (*v_may_defs) { + unsigned int x; + v_may_def_optype v_may_def = *v_may_defs; + for (x = 0; x < v_may_def->num_v_may_defs; x++) + delink_imm_use (&(v_may_def->v_may_defs[x].imm_use)); ggc_free (*v_may_defs); *v_may_defs = NULL; } @@ -274,6 +287,10 @@ free_v_must_defs (v_must_def_optype *v_must_defs) { if (*v_must_defs) { + unsigned int x; + v_must_def_optype v_must_def = *v_must_defs; + for (x = 0; x < v_must_def->num_v_must_defs; x++) + delink_imm_use (&(v_must_def->v_must_defs[x].imm_use)); ggc_free (*v_must_defs); *v_must_defs = NULL; } @@ -322,6 +339,62 @@ fini_ssa_operands (void) } } +/* Initialize V_USES index INDEX to VAL for STMT. If OLD is present, preserve + the position of the may-def in the immediate_use list. */ + +static inline void +initialize_vuse_operand (vuse_optype vuses, unsigned int index, tree val, + tree stmt, ssa_imm_use_t *old) +{ + vuse_operand_type_t *ptr; + ptr = &(vuses->vuses[index]); + ptr->use = val; + ptr->imm_use.use = &(ptr->use); + if (old) + relink_imm_use_stmt (&(ptr->imm_use), old, stmt); + else + link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt); +} + + +/* Initialize V_MAY_DEF_OPS index X to be DEF = MAY_DEF <USE> for STMT. If + OLD is present, preserve the position of the may-def in the immediate_use + list. */ + +static inline void +initialize_v_may_def_operand (v_may_def_optype v_may_def_ops, unsigned int x, + tree def, tree use, tree stmt, ssa_imm_use_t *old) +{ + v_def_use_operand_type_t *ptr; + ptr = &(v_may_def_ops->v_may_defs[x]); + ptr->def = def; + ptr->use = use; + ptr->imm_use.use = &(ptr->use); + if (old) + relink_imm_use_stmt (&(ptr->imm_use), old, stmt); + else + link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt); +} + + +/* Initialize V_MUST_DEF_OPS index X to be DEF = MUST_DEF <USE> for STMT. If + OLD is present, preserve the position of the may-def in the immediate_use + list. */ + +static inline void +initialize_v_must_def_operand (v_must_def_optype v_must_def_ops, unsigned int x, + tree def, tree use, tree stmt, ssa_imm_use_t *old) +{ + v_def_use_operand_type_t *ptr; + ptr = &(v_must_def_ops->v_must_defs[x]); + ptr->def = def; + ptr->use = use; + ptr->imm_use.use = &(ptr->use); + if (old) + relink_imm_use_stmt (&(ptr->imm_use), old, stmt); + else + link_imm_use_stmt (&(ptr->imm_use), ptr->use, stmt); +} /* All the finalize_ssa_* routines do the work required to turn the build_ VARRAY into an operand_vector of the appropriate type. The original vector, @@ -332,7 +405,7 @@ fini_ssa_operands (void) /* Return a new def operand vector for STMT, comparing to OLD_OPS_P. */ static def_optype -finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) +finalize_ssa_defs (def_optype *old_ops_p, tree stmt) { unsigned num, x; def_optype def_ops, old_ops; @@ -343,13 +416,13 @@ finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) return NULL; /* There should only be a single real definition per assignment. */ - gcc_assert (TREE_CODE (stmt) != MODIFY_EXPR || num <= 1); + gcc_assert ((stmt && TREE_CODE (stmt) != MODIFY_EXPR) || num <= 1); old_ops = *old_ops_p; /* Compare old vector and new array. */ build_diff = true; - if (old_ops && old_ops->num_defs == num) + if (stmt && old_ops && old_ops->num_defs == num) { build_diff = false; for (x = 0; x < num; x++) @@ -378,12 +451,45 @@ finalize_ssa_defs (def_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) } +/* Make sure PTR is inn the correct immediate use list. Since uses are simply + pointers into the stmt TREE, there is no way of telling if anyone has + changed what this pointer points to via TREE_OPERANDS (exp, 0) = <...>. + THe contents are different, but the the pointer is still the same. This + routine will check to make sure PTR is in the correct list, and if it isn't + put it in the correct list. */ + +static inline void +correct_use_link (ssa_imm_use_t *ptr, tree stmt) +{ + ssa_imm_use_t *prev; + tree root; + + /* Fold_stmt () may have changed the stmt pointers. */ + if (ptr->stmt != stmt) + ptr->stmt = stmt; + + prev = ptr->prev; + if (prev) + { + /* find the root, which has a non-NULL stmt, and a NULL use. */ + while (prev->stmt == NULL || prev->use != NULL) + prev = prev->prev; + root = prev->stmt; + if (root == *(ptr->use)) + return; + } + /* Its in the wrong list if we reach here. */ + delink_imm_use (ptr); + link_imm_use (ptr, *(ptr->use)); +} + + /* Return a new use operand vector for STMT, comparing to OLD_OPS_P. */ static use_optype -finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) +finalize_ssa_uses (use_optype *old_ops_p, tree stmt) { - unsigned num, x; + unsigned num, x, num_old, i; use_optype use_ops, old_ops; bool build_diff; @@ -403,30 +509,53 @@ finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) } #endif old_ops = *old_ops_p; + num_old = ((stmt && old_ops) ? old_ops->num_uses : 0); /* Check if the old vector and the new array are the same. */ build_diff = true; - if (old_ops && old_ops->num_uses == num) + if (stmt && old_ops && num_old == num) { build_diff = false; for (x = 0; x < num; x++) - if (old_ops->uses[x].use != VARRAY_TREE_PTR (build_uses, x)) - { - build_diff = true; - break; - } + { + tree *var_p = VARRAY_TREE_PTR (build_uses, x); + tree *node = old_ops->uses[x].use; + /* Check the pointer values to see if they are the same. */ + if (node != var_p) + { + build_diff = true; + break; + } + } } if (!build_diff) { use_ops = old_ops; *old_ops_p = NULL; + for (i = 0; i < num_old; i++) + correct_use_link (&(use_ops->uses[i]), stmt); } else { use_ops = allocate_use_optype (num); for (x = 0; x < num ; x++) - use_ops->uses[x].use = VARRAY_TREE_PTR (build_uses, x); + { + tree *var = VARRAY_TREE_PTR (build_uses, x); + use_ops->uses[x].use = var; + for (i = 0; i < num_old; i++) + { + ssa_imm_use_t *ptr = &(old_ops->uses[i]); + if (ptr->use == var) + { + relink_imm_use_stmt (&(use_ops->uses[x]), ptr, stmt); + correct_use_link (&(use_ops->uses[x]), stmt); + break; + } + } + if (i == num_old) + link_imm_use_stmt (&(use_ops->uses[x]), *var, stmt); + } } VARRAY_POP_ALL (build_uses); @@ -437,7 +566,7 @@ finalize_ssa_uses (use_optype *old_ops_p, tree stmt ATTRIBUTE_UNUSED) /* Return a new v_may_def operand vector for STMT, comparing to OLD_OPS_P. */ static v_may_def_optype -finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p) +finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p, tree stmt) { unsigned num, x, i, old_num; v_may_def_optype v_may_def_ops, old_ops; @@ -452,7 +581,7 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p) /* Check if the old vector and the new array are the same. */ build_diff = true; - if (old_ops && old_ops->num_v_may_defs == num) + if (stmt && old_ops && old_ops->num_v_may_defs == num) { old_num = num; build_diff = false; @@ -475,6 +604,8 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p) { v_may_def_ops = old_ops; *old_ops_p = NULL; + for (x = 0; x < num; x++) + correct_use_link (&(v_may_def_ops->v_may_defs[x].imm_use), stmt); } else { @@ -490,14 +621,18 @@ finalize_ssa_v_may_defs (v_may_def_optype *old_ops_p) result = SSA_NAME_VAR (result); if (result == var) { - v_may_def_ops->v_may_defs[x] = old_ops->v_may_defs[i]; + initialize_v_may_def_operand (v_may_def_ops, x, + old_ops->v_may_defs[i].def, + old_ops->v_may_defs[i].use, + stmt, + &(old_ops->v_may_defs[i].imm_use)); break; } } if (i == old_num) { - v_may_def_ops->v_may_defs[x].def = var; - v_may_def_ops->v_may_defs[x].use = var; + initialize_v_may_def_operand (v_may_def_ops, x, var, var, stmt, + NULL); } } } @@ -528,7 +663,7 @@ cleanup_v_may_defs (void) /* Return a new vuse operand vector, comparing to OLD_OPS_P. */ static vuse_optype -finalize_ssa_vuses (vuse_optype *old_ops_p) +finalize_ssa_vuses (vuse_optype *old_ops_p, tree stmt) { unsigned num, x, i, num_v_may_defs, old_num; vuse_optype vuse_ops, old_ops; @@ -613,14 +748,14 @@ finalize_ssa_vuses (vuse_optype *old_ops_p) /* Determine whether vuses is the same as the old vector. */ build_diff = true; - if (old_ops && old_ops->num_vuses == num) + if (stmt && old_ops && old_ops->num_vuses == num) { old_num = num; build_diff = false; for (x = 0; x < num ; x++) { tree v; - v = old_ops->vuses[x]; + v = old_ops->vuses[x].use; if (TREE_CODE (v) == SSA_NAME) v = SSA_NAME_VAR (v); if (v != VARRAY_TREE (build_vuses, x)) @@ -637,6 +772,8 @@ finalize_ssa_vuses (vuse_optype *old_ops_p) { vuse_ops = old_ops; *old_ops_p = NULL; + for (x = 0; x < num; x++) + correct_use_link (&(vuse_ops->vuses[x].imm_use), stmt); } else { @@ -647,17 +784,18 @@ finalize_ssa_vuses (vuse_optype *old_ops_p) /* Look for VAR in the old vector, and use that SSA_NAME. */ for (i = 0; i < old_num; i++) { - result = old_ops->vuses[i]; + result = old_ops->vuses[i].use; if (TREE_CODE (result) == SSA_NAME) result = SSA_NAME_VAR (result); if (result == var) { - vuse_ops->vuses[x] = old_ops->vuses[i]; + initialize_vuse_operand (vuse_ops, x, old_ops->vuses[i].use, + stmt, &(old_ops->vuses[i].imm_use)); break; } } if (i == old_num) - vuse_ops->vuses[x] = var; + initialize_vuse_operand (vuse_ops, x, var, stmt, NULL); } } @@ -672,11 +810,11 @@ finalize_ssa_vuses (vuse_optype *old_ops_p) /* Return a new v_must_def operand vector for STMT, comparing to OLD_OPS_P. */ static v_must_def_optype -finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, - tree stmt ATTRIBUTE_UNUSED) +finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, tree stmt) { unsigned num, x, i, old_num = 0; v_must_def_optype v_must_def_ops, old_ops; + tree result, var; bool build_diff; num = VARRAY_ACTIVE_SIZE (build_v_must_defs); @@ -694,7 +832,7 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, /* Check if the old vector and the new array are the same. */ build_diff = true; - if (old_ops && old_ops->num_v_must_defs == num) + if (stmt && old_ops && old_ops->num_v_must_defs == num) { old_num = num; build_diff = false; @@ -717,13 +855,15 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, { v_must_def_ops = old_ops; *old_ops_p = NULL; + for (x = 0; x < num; x++) + correct_use_link (&(v_must_def_ops->v_must_defs[x].imm_use), stmt); } else { v_must_def_ops = allocate_v_must_def_optype (num); for (x = 0; x < num ; x++) { - tree result, var = VARRAY_TREE (build_v_must_defs, x); + var = VARRAY_TREE (build_v_must_defs, x); /* Look for VAR in the original vector. */ for (i = 0; i < old_num; i++) { @@ -732,15 +872,18 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p, result = SSA_NAME_VAR (result); if (result == var) { - v_must_def_ops->v_must_defs[x].def = old_ops->v_must_defs[i].def; - v_must_def_ops->v_must_defs[x].use = old_ops->v_must_defs[i].use; + initialize_v_must_def_operand (v_must_def_ops, x, + old_ops->v_must_defs[i].def, + old_ops->v_must_defs[i].use, + stmt, + &(old_ops->v_must_defs[i].imm_use)); break; } } if (i == old_num) { - v_must_def_ops->v_must_defs[x].def = var; - v_must_def_ops->v_must_defs[x].use = var; + initialize_v_must_def_operand (v_must_def_ops, x, var, var, stmt, + NULL); } } } @@ -760,8 +903,9 @@ finalize_ssa_stmt_operands (tree stmt, stmt_operands_p old_ops, new_ops->use_ops = finalize_ssa_uses (&(old_ops->use_ops), stmt); new_ops->v_must_def_ops = finalize_ssa_v_must_defs (&(old_ops->v_must_def_ops), stmt); - new_ops->v_may_def_ops = finalize_ssa_v_may_defs (&(old_ops->v_may_def_ops)); - new_ops->vuse_ops = finalize_ssa_vuses (&(old_ops->vuse_ops)); + new_ops->v_may_def_ops + = finalize_ssa_v_may_defs (&(old_ops->v_may_def_ops), stmt); + new_ops->vuse_ops = finalize_ssa_vuses (&(old_ops->vuse_ops), stmt); } @@ -847,46 +991,15 @@ append_v_must_def (tree var) VARRAY_PUSH_TREE (build_v_must_defs, var); } -/* Create an operands cache for STMT, returning it in NEW_OPS. OLD_OPS are the - original operands, and if ANN is non-null, appropriate stmt flags are set - in the stmt's annotation. Note that some fields in old_ops may - change to NULL, although none of the memory they originally pointed to - will be destroyed. It is appropriate to call free_stmt_operands() on - the value returned in old_ops. - - The rationale for this: Certain optimizations wish to examine the difference - between new_ops and old_ops after processing. If a set of operands don't - change, new_ops will simply assume the pointer in old_ops, and the old_ops - pointer will be set to NULL, indicating no memory needs to be cleared. - Usage might appear something like: - - old_ops_copy = old_ops = stmt_ann(stmt)->operands; - build_ssa_operands (stmt, NULL, &old_ops, &new_ops); - <* compare old_ops_copy and new_ops *> - free_ssa_operands (old_ops); */ +/* Parse STMT looking for operands. OLD_OPS is the original stmt operand + cache for STMT, if it exested before. When fniished, the various build_* + operand vectors will have potential operands. in them. */ + static void -build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops, - stmt_operands_p new_ops) +parse_ssa_operands (tree stmt) { enum tree_code code; - tree_ann_t saved_ann = stmt->common.ann; - - /* Replace stmt's annotation with the one passed in for the duration - of the operand building process. This allows "fake" stmts to be built - and not be included in other data structures which can be built here. */ - stmt->common.ann = (tree_ann_t) ann; - - /* Initially assume that the statement has no volatile operands, nor - makes aliased loads or stores. */ - if (ann) - { - ann->has_volatile_ops = false; - ann->makes_aliased_stores = false; - ann->makes_aliased_loads = false; - } - - start_ssa_stmt_operands (); code = TREE_CODE (stmt); switch (code) @@ -963,8 +1076,62 @@ build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops, get_expr_operands (stmt, &stmt, opf_none); break; } +} + +/* Create an operands cache for STMT, returning it in NEW_OPS. OLD_OPS are the + original operands, and if ANN is non-null, appropriate stmt flags are set + in the stmt's annotation. If ANN is NULL, this is not considered a "real" + stmt, and none of the operands will be entered into their respective + immediate uses tables. This is to allow stmts to be processed when they + are not actually in the CFG. + + Note that some fields in old_ops may change to NULL, although none of the + memory they originally pointed to will be destroyed. It is appropriate + to call free_stmt_operands() on the value returned in old_ops. + + The rationale for this: Certain optimizations wish to examine the difference + between new_ops and old_ops after processing. If a set of operands don't + change, new_ops will simply assume the pointer in old_ops, and the old_ops + pointer will be set to NULL, indicating no memory needs to be cleared. + Usage might appear something like: + + old_ops_copy = old_ops = stmt_ann(stmt)->operands; + build_ssa_operands (stmt, NULL, &old_ops, &new_ops); + <* compare old_ops_copy and new_ops *> + free_ssa_operands (old_ops); */ + +static void +build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops, + stmt_operands_p new_ops) +{ + tree_ann_t saved_ann = stmt->common.ann; + + /* Replace stmt's annotation with the one passed in for the duration + of the operand building process. This allows "fake" stmts to be built + and not be included in other data structures which can be built here. */ + stmt->common.ann = (tree_ann_t) ann; - finalize_ssa_stmt_operands (stmt, old_ops, new_ops); + parse_old_ops = old_ops; + + /* Initially assume that the statement has no volatile operands, nor + makes aliased loads or stores. */ + if (ann) + { + ann->has_volatile_ops = false; + ann->makes_aliased_stores = false; + ann->makes_aliased_loads = false; + } + + start_ssa_stmt_operands (); + + parse_ssa_operands (stmt); + + parse_old_ops = NULL; + + if (ann) + finalize_ssa_stmt_operands (stmt, old_ops, new_ops); + else + finalize_ssa_stmt_operands (NULL, old_ops, new_ops); stmt->common.ann = saved_ann; } @@ -987,25 +1154,73 @@ free_ssa_operands (stmt_operands_p ops) } +/* Swap operands EXP0 and EXP1 in STMT. */ + +static void +swap_tree_operands (tree *exp0, tree *exp1) +{ + tree op0, op1; + op0 = *exp0; + op1 = *exp1; + + /* If the operand cache is active, attempt to preserve the relative positions + of these two operands in their respective immediate use lists. */ + if (build_defs != NULL && op0 != op1 && parse_old_ops != NULL) + { + unsigned x, use0, use1; + use_optype uses = parse_old_ops->use_ops; + use0 = use1 = NUM_USES (uses); + /* Find the 2 operands in the cache, if they are there. */ + for (x = 0; x < NUM_USES (uses); x++) + if (USE_OP_PTR (uses, x)->use == exp0) + { + use0 = x; + break; + } + for (x = 0; x < NUM_USES (uses); x++) + if (USE_OP_PTR (uses, x)->use == exp1) + { + use1 = x; + break; + } + /* If both uses don't have operand entries, there isnt much we can do + at this point. Presumably we dont need to worry about it. */ + if (use0 != NUM_USES (uses) && use1 != NUM_USES (uses)) + { + tree *tmp = USE_OP_PTR (uses, use1)->use; + gcc_assert (use0 != use1); + + USE_OP_PTR (uses, use1)->use = USE_OP_PTR (uses, use0)->use; + USE_OP_PTR (uses, use0)->use = tmp; + } + } + + /* Now swap the data. */ + *exp0 = op1; + *exp1 = op0; +} + /* Get the operands of statement STMT. Note that repeated calls to get_stmt_operands for the same statement will do nothing until the - statement is marked modified by a call to modify_stmt(). */ + statement is marked modified by a call to mark_stmt_modified(). */ void -get_stmt_operands (tree stmt) +update_stmt_operands (tree stmt) { stmt_ann_t ann; stmt_operands_t old_operands; + /* If get_stmt_operands is called before SSA is initialized, dont + do anything. */ + if (build_defs == NULL) + return; /* The optimizers cannot handle statements that are nothing but a _DECL. This indicates a bug in the gimplifier. */ gcc_assert (!SSA_VAR_P (stmt)); ann = get_stmt_ann (stmt); - /* If the statement has not been modified, the operands are still valid. */ - if (!ann->modified) - return; + gcc_assert (ann->modified); timevar_push (TV_TREE_OPS); @@ -1017,7 +1232,7 @@ get_stmt_operands (tree stmt) /* Clear the modified bit for STMT. Subsequent calls to get_stmt_operands for this statement will do nothing until the - statement is marked modified by a call to modify_stmt(). */ + statement is marked modified by a call to mark_stmt_modified(). */ ann->modified = 0; timevar_pop (TV_TREE_OPS); @@ -1239,15 +1454,15 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) || code == GE_EXPR) { TREE_SET_CODE (expr, swap_tree_comparison (code)); - TREE_OPERAND (expr, 0) = op1; - TREE_OPERAND (expr, 1) = op0; + swap_tree_operands (&TREE_OPERAND (expr, 0), + &TREE_OPERAND (expr, 1)); } /* For a commutative operator we can just swap the operands. */ else if (commutative_tree_code (code)) { - TREE_OPERAND (expr, 0) = op1; - TREE_OPERAND (expr, 1) = op0; + swap_tree_operands (&TREE_OPERAND (expr, 0), + &TREE_OPERAND (expr, 1)); } } @@ -1884,7 +2099,7 @@ copy_virtual_operands (tree dst, tree src) { *vuses_new = allocate_vuse_optype (NUM_VUSES (vuses)); for (i = 0; i < NUM_VUSES (vuses); i++) - SET_VUSE_OP (*vuses_new, i, VUSE_OP (vuses, i)); + initialize_vuse_operand (*vuses_new, i, VUSE_OP (vuses, i), dst, NULL); } if (v_may_defs) @@ -1892,19 +2107,23 @@ copy_virtual_operands (tree dst, tree src) *v_may_defs_new = allocate_v_may_def_optype (NUM_V_MAY_DEFS (v_may_defs)); for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++) { - SET_V_MAY_DEF_OP (*v_may_defs_new, i, V_MAY_DEF_OP (v_may_defs, i)); - SET_V_MAY_DEF_RESULT (*v_may_defs_new, i, - V_MAY_DEF_RESULT (v_may_defs, i)); + initialize_v_may_def_operand (*v_may_defs_new, i, + V_MAY_DEF_RESULT (v_may_defs, i), + V_MAY_DEF_OP (v_may_defs, i), dst, + NULL); } } if (v_must_defs) { - *v_must_defs_new = allocate_v_must_def_optype (NUM_V_MUST_DEFS (v_must_defs)); + *v_must_defs_new + = allocate_v_must_def_optype (NUM_V_MUST_DEFS (v_must_defs)); for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++) { - SET_V_MUST_DEF_RESULT (*v_must_defs_new, i, V_MUST_DEF_RESULT (v_must_defs, i)); - SET_V_MUST_DEF_KILL (*v_must_defs_new, i, V_MUST_DEF_KILL (v_must_defs, i)); + initialize_v_must_def_operand (*v_must_defs_new, i, + V_MUST_DEF_RESULT (v_must_defs, i), + V_MUST_DEF_KILL (v_must_defs, i), dst, + NULL); } } } @@ -1951,7 +2170,173 @@ create_ssa_artficial_load_stmt (stmt_operands_p old_ops, tree new_stmt) } /* Now set the vuses for this new stmt. */ - ann->operands.vuse_ops = finalize_ssa_vuses (&(tmp.vuse_ops)); + ann->operands.vuse_ops = finalize_ssa_vuses (&(tmp.vuse_ops), NULL); +} + + + +/* Issue immediate use error for VAR to debug file F. */ +static void +verify_abort (FILE *f, ssa_imm_use_t *var) +{ + tree stmt; + stmt = var->stmt; + if (stmt) + { + if (stmt_modified_p(stmt)) + { + fprintf (f, " STMT MODIFIED. - <0x%x> ", (unsigned int)stmt); + print_generic_stmt (f, stmt, TDF_SLIM); + } + } + fprintf (f, " IMM ERROR : (use_p : tree: 0x%X:0x%x)", (unsigned int)var, + (unsigned int)var->use); + print_generic_expr (f, USE_FROM_PTR (var), TDF_SLIM); + fprintf(f, "\n"); +} + + +/* Scan the immediate_use list for VAR making sure its linked properly. + return RTUE iof there is a problem. */ + +bool +verify_imm_links (FILE *f, tree var) +{ + ssa_imm_use_t *ptr, *prev; + ssa_imm_use_t *list; + int count; + + gcc_assert (TREE_CODE (var) == SSA_NAME); + + list = &(SSA_NAME_IMM_USE_NODE (var)); + gcc_assert (list->use == NULL); + + if (list->prev == NULL) + { + gcc_assert (list->next == NULL); + return false; + } + + prev = list; + count = 0; + for (ptr = list->next; ptr != list; ) + { + if (prev != ptr->prev) + { + verify_abort (f, ptr); + return true; + } + + if (ptr->use == NULL) + { + verify_abort (f, ptr); /* 2 roots, or SAFE guard node. */ + return true; + } + else + if (*(ptr->use) != var) + { + verify_abort (f, ptr); + return true; + } + + prev = ptr; + ptr = ptr->next; + /* Avoid infinite loops. */ + if (count++ > 30000) + { + verify_abort (f, ptr); + return true; + } + } + + /* Verify list in the other direction. */ + prev = list; + for (ptr = list->prev; ptr != list; ) + { + if (prev != ptr->next) + { + verify_abort (f, ptr); + return true; + } + prev = ptr; + ptr = ptr->prev; + if (count-- < 0) + { + verify_abort (f, ptr); + return true; + } + } + + if (count != 0) + { + verify_abort (f, ptr); + return true; + } + + return false; +} + + +/* Dump all the immediate uses to FILE. */ + +void +dump_immediate_uses_for (FILE *file, tree var) +{ + imm_use_iterator iter; + use_operand_p use_p; + + gcc_assert (var && TREE_CODE (var) == SSA_NAME); + + print_generic_expr (file, var, TDF_SLIM); + fprintf (file, " : -->"); + if (has_zero_uses (var)) + fprintf (file, " no uses.\n"); + else + if (has_single_use (var)) + fprintf (file, " single use.\n"); + else + fprintf (file, "%d uses.\n", num_imm_uses (var)); + + FOR_EACH_IMM_USE_FAST (use_p, iter, var) + { + print_generic_stmt (file, USE_STMT (use_p), TDF_SLIM); + } + fprintf(file, "\n"); +} + +/* Dump all the immediate uses to FILE. */ + +void +dump_immediate_uses (FILE *file) +{ + tree var; + unsigned int x; + + fprintf (file, "Immediate_uses: \n\n"); + for (x = 1; x < num_ssa_names; x++) + { + var = ssa_name(x); + if (!var) + continue; + dump_immediate_uses_for (file, var); + } +} + + +/* Dump def-use edges on stderr. */ + +void +debug_immediate_uses (void) +{ + dump_immediate_uses (stderr); +} + +/* Dump def-use edges on stderr. */ + +void +debug_immediate_uses_for (tree var) +{ + dump_immediate_uses_for (stderr, var); } #include "gt-tree-ssa-operands.h" |