/* Inline functions for tree-flow.h Copyright (C) 2001, 2003, 2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc. Contributed by Diego Novillo This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #ifndef _TREE_FLOW_INLINE_H #define _TREE_FLOW_INLINE_H 1 /* Inline functions for manipulating various data structures defined in tree-flow.h. See tree-flow.h for documentation. */ /* Return true when gimple SSA form was built. gimple_in_ssa_p is queried by gimplifier in various early stages before SSA infrastructure is initialized. Check for presence of the datastructures at first place. */ static inline bool gimple_in_ssa_p (const struct function *fun) { return fun && fun->gimple_df && fun->gimple_df->in_ssa_p; } /* Array of all variables referenced in the function. */ static inline htab_t gimple_referenced_vars (const struct function *fun) { if (!fun->gimple_df) return NULL; return fun->gimple_df->referenced_vars; } /* Artificial variable used for the virtual operand FUD chain. */ static inline tree gimple_vop (const struct function *fun) { gcc_checking_assert (fun && fun->gimple_df); return fun->gimple_df->vop; } /* Initialize the hashtable iterator HTI to point to hashtable TABLE */ static inline void * first_htab_element (htab_iterator *hti, htab_t table) { hti->htab = table; hti->slot = table->entries; hti->limit = hti->slot + htab_size (table); do { PTR x = *(hti->slot); if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) break; } while (++(hti->slot) < hti->limit); if (hti->slot < hti->limit) return *(hti->slot); return NULL; } /* Return current non-empty/deleted slot of the hashtable pointed to by HTI, or NULL if we have reached the end. */ static inline bool end_htab_p (const htab_iterator *hti) { if (hti->slot >= hti->limit) return true; return false; } /* Advance the hashtable iterator pointed to by HTI to the next element of the hashtable. */ static inline void * next_htab_element (htab_iterator *hti) { while (++(hti->slot) < hti->limit) { PTR x = *(hti->slot); if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) return x; }; return NULL; } /* Get the variable with uid UID from the list of referenced vars. */ static inline tree referenced_var (unsigned int uid) { tree var = referenced_var_lookup (cfun, uid); gcc_assert (var || uid == 0); return var; } /* Initialize ITER to point to the first referenced variable in the referenced_vars hashtable, and return that variable. */ static inline tree first_referenced_var (struct function *fn, referenced_var_iterator *iter) { return (tree) first_htab_element (&iter->hti, gimple_referenced_vars (fn)); } /* Return true if we have hit the end of the referenced variables ITER is iterating through. */ static inline bool end_referenced_vars_p (const referenced_var_iterator *iter) { return end_htab_p (&iter->hti); } /* Make ITER point to the next referenced_var in the referenced_var hashtable, and return that variable. */ static inline tree next_referenced_var (referenced_var_iterator *iter) { return (tree) next_htab_element (&iter->hti); } /* Return the variable annotation for T, which must be a _DECL node. Return NULL if the variable annotation doesn't already exist. */ static inline var_ann_t var_ann (const_tree t) { const var_ann_t *p = DECL_VAR_ANN_PTR (t); return p ? *p : NULL; } /* Get the number of the next statement uid to be allocated. */ static inline unsigned int gimple_stmt_max_uid (struct function *fn) { return fn->last_stmt_uid; } /* Set the number of the next statement uid to be allocated. */ static inline void set_gimple_stmt_max_uid (struct function *fn, unsigned int maxid) { fn->last_stmt_uid = maxid; } /* Set the number of the next statement uid to be allocated. */ static inline unsigned int inc_gimple_stmt_max_uid (struct function *fn) { return fn->last_stmt_uid++; } /* Return the line number for EXPR, or return -1 if we have no line number information for it. */ static inline int get_lineno (const_gimple stmt) { location_t loc; if (!stmt) return -1; loc = gimple_location (stmt); if (loc == UNKNOWN_LOCATION) return -1; return LOCATION_LINE (loc); } /* Delink an immediate_uses node from its chain. */ static inline void delink_imm_use (ssa_use_operand_t *linknode) { /* Return if this node is not in a list. */ if (linknode->prev == NULL) return; linknode->prev->next = linknode->next; linknode->next->prev = linknode->prev; linknode->prev = NULL; linknode->next = NULL; } /* Link ssa_imm_use node LINKNODE into the chain for LIST. */ static inline void link_imm_use_to_list (ssa_use_operand_t *linknode, ssa_use_operand_t *list) { /* Link the new node at the head of the list. If we are in the process of traversing the list, we won't visit any new nodes added to it. */ linknode->prev = list; linknode->next = list->next; list->next->prev = linknode; list->next = linknode; } /* Link ssa_imm_use node LINKNODE into the chain for DEF. */ static inline void link_imm_use (ssa_use_operand_t *linknode, tree def) { ssa_use_operand_t *root; if (!def || TREE_CODE (def) != SSA_NAME) linknode->prev = NULL; else { root = &(SSA_NAME_IMM_USE_NODE (def)); if (linknode->use) gcc_checking_assert (*(linknode->use) == def); link_imm_use_to_list (linknode, root); } } /* Set the value of a use pointed to by USE to VAL. */ static inline void set_ssa_use_from_ptr (use_operand_p use, tree val) { delink_imm_use (use); *(use->use) = val; link_imm_use (use, val); } /* Link ssa_imm_use node LINKNODE into the chain for DEF, with use occurring in STMT. */ static inline void link_imm_use_stmt (ssa_use_operand_t *linknode, tree def, gimple stmt) { if (stmt) link_imm_use (linknode, def); else link_imm_use (linknode, NULL); linknode->loc.stmt = stmt; } /* Relink a new node in place of an old node in the list. */ static inline void relink_imm_use (ssa_use_operand_t *node, ssa_use_operand_t *old) { /* The node one had better be in the same list. */ gcc_checking_assert (*(old->use) == *(node->use)); node->prev = old->prev; node->next = old->next; if (old->prev) { old->prev->next = node; old->next->prev = node; /* Remove the old node from the list. */ old->prev = NULL; } } /* Relink ssa_imm_use node LINKNODE into the chain for OLD, with use occurring in STMT. */ static inline void relink_imm_use_stmt (ssa_use_operand_t *linknode, ssa_use_operand_t *old, gimple stmt) { if (stmt) relink_imm_use (linknode, old); else link_imm_use (linknode, NULL); linknode->loc.stmt = stmt; } /* Return true is IMM has reached the end of the immediate use list. */ static inline bool end_readonly_imm_use_p (const imm_use_iterator *imm) { return (imm->imm_use == imm->end_p); } /* Initialize iterator IMM to process the list for VAR. */ static inline use_operand_p first_readonly_imm_use (imm_use_iterator *imm, tree var) { imm->end_p = &(SSA_NAME_IMM_USE_NODE (var)); imm->imm_use = imm->end_p->next; #ifdef ENABLE_CHECKING imm->iter_node.next = imm->imm_use->next; #endif if (end_readonly_imm_use_p (imm)) return NULL_USE_OPERAND_P; return imm->imm_use; } /* Bump IMM to the next use in the list. */ static inline use_operand_p next_readonly_imm_use (imm_use_iterator *imm) { use_operand_p old = imm->imm_use; #ifdef ENABLE_CHECKING /* If this assertion fails, it indicates the 'next' pointer has changed since the last bump. This indicates that the list is being modified via stmt changes, or SET_USE, or somesuch thing, and you need to be using the SAFE version of the iterator. */ gcc_assert (imm->iter_node.next == old->next); imm->iter_node.next = old->next->next; #endif imm->imm_use = old->next; if (end_readonly_imm_use_p (imm)) return NULL_USE_OPERAND_P; return imm->imm_use; } /* tree-cfg.c */ extern bool has_zero_uses_1 (const ssa_use_operand_t *head); extern bool single_imm_use_1 (const ssa_use_operand_t *head, use_operand_p *use_p, gimple *stmt); /* Return true if VAR has no nondebug uses. */ static inline bool has_zero_uses (const_tree var) { const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); /* A single use_operand means there is no items in the list. */ if (ptr == ptr->next) return true; /* If there are debug stmts, we have to look at each use and see whether there are any nondebug uses. */ if (!MAY_HAVE_DEBUG_STMTS) return false; return has_zero_uses_1 (ptr); } /* Return true if VAR has a single nondebug use. */ static inline bool has_single_use (const_tree var) { const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); /* If there aren't any uses whatsoever, we're done. */ if (ptr == ptr->next) return false; /* If there's a single use, check that it's not a debug stmt. */ if (ptr == ptr->next->next) return !is_gimple_debug (USE_STMT (ptr->next)); /* If there are debug stmts, we have to look at each of them. */ if (!MAY_HAVE_DEBUG_STMTS) return false; return single_imm_use_1 (ptr, NULL, NULL); } /* If VAR has only a single immediate nondebug use, return true, and set USE_P and STMT to the use pointer and stmt of occurrence. */ static inline bool single_imm_use (const_tree var, use_operand_p *use_p, gimple *stmt) { const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var)); /* If there aren't any uses whatsoever, we're done. */ if (ptr == ptr->next) { return_false: *use_p = NULL_USE_OPERAND_P; *stmt = NULL; return false; } /* If there's a single use, check that it's not a debug stmt. */ if (ptr == ptr->next->next) { if (!is_gimple_debug (USE_STMT (ptr->next))) { *use_p = ptr->next; *stmt = ptr->next->loc.stmt; return true; } else goto return_false; } /* If there are debug stmts, we have to look at each of them. */ if (!MAY_HAVE_DEBUG_STMTS) goto return_false; return single_imm_use_1 (ptr, use_p, stmt); } /* Return the number of nondebug immediate uses of VAR. */ static inline unsigned int num_imm_uses (const_tree var) { const ssa_use_operand_t *const start = &(SSA_NAME_IMM_USE_NODE (var)); const ssa_use_operand_t *ptr; unsigned int num = 0; if (!MAY_HAVE_DEBUG_STMTS) for (ptr = start->next; ptr != start; ptr = ptr->next) num++; else for (ptr = start->next; ptr != start; ptr = ptr->next) if (!is_gimple_debug (USE_STMT (ptr))) num++; return num; } /* Return the tree pointed-to by USE. */ static inline tree get_use_from_ptr (use_operand_p use) { return *(use->use); } /* Return the tree pointed-to by DEF. */ static inline tree get_def_from_ptr (def_operand_p def) { return *def; } /* Return a use_operand_p pointer for argument I of PHI node GS. */ static inline use_operand_p gimple_phi_arg_imm_use_ptr (gimple gs, int i) { return &gimple_phi_arg (gs, i)->imm_use; } /* Return the tree operand for argument I of PHI node GS. */ static inline tree gimple_phi_arg_def (gimple gs, size_t index) { struct phi_arg_d *pd = gimple_phi_arg (gs, index); return get_use_from_ptr (&pd->imm_use); } /* Return a pointer to the tree operand for argument I of PHI node GS. */ static inline tree * gimple_phi_arg_def_ptr (gimple gs, size_t index) { return &gimple_phi_arg (gs, index)->def; } /* Return the edge associated with argument I of phi node GS. */ static inline edge gimple_phi_arg_edge (gimple gs, size_t i) { return EDGE_PRED (gimple_bb (gs), i); } /* Return the source location of gimple argument I of phi node GS. */ static inline source_location gimple_phi_arg_location (gimple gs, size_t i) { return gimple_phi_arg (gs, i)->locus; } /* Return the source location of the argument on edge E of phi node GS. */ static inline source_location gimple_phi_arg_location_from_edge (gimple gs, edge e) { return gimple_phi_arg (gs, e->dest_idx)->locus; } /* Set the source location of gimple argument I of phi node GS to LOC. */ static inline void gimple_phi_arg_set_location (gimple gs, size_t i, source_location loc) { gimple_phi_arg (gs, i)->locus = loc; } /* Return TRUE if argument I of phi node GS has a location record. */ static inline bool gimple_phi_arg_has_location (gimple gs, size_t i) { return gimple_phi_arg_location (gs, i) != UNKNOWN_LOCATION; } /* Return the PHI nodes for basic block BB, or NULL if there are no PHI nodes. */ static inline gimple_seq phi_nodes (const_basic_block bb) { gcc_checking_assert (!(bb->flags & BB_RTL)); if (!bb->il.gimple) return NULL; return bb->il.gimple->phi_nodes; } /* Set PHI nodes of a basic block BB to SEQ. */ static inline void set_phi_nodes (basic_block bb, gimple_seq seq) { gimple_stmt_iterator i; gcc_checking_assert (!(bb->flags & BB_RTL)); bb->il.gimple->phi_nodes = seq; if (seq) for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) gimple_set_bb (gsi_stmt (i), bb); } /* Return the phi argument which contains the specified use. */ static inline int phi_arg_index_from_use (use_operand_p use) { struct phi_arg_d *element, *root; size_t index; gimple phi; /* Since the use is the first thing in a PHI argument element, we can calculate its index based on casting it to an argument, and performing pointer arithmetic. */ phi = USE_STMT (use); element = (struct phi_arg_d *)use; root = gimple_phi_arg (phi, 0); index = element - root; /* Make sure the calculation doesn't have any leftover bytes. If it does, then imm_use is likely not the first element in phi_arg_d. */ gcc_checking_assert ((((char *)element - (char *)root) % sizeof (struct phi_arg_d)) == 0 && index < gimple_phi_capacity (phi)); return index; } /* Mark VAR as used, so that it'll be preserved during rtl expansion. */ static inline void set_is_used (tree var) { var_ann_t ann = var_ann (var); ann->used = true; } /* Clear VAR's used flag. */ static inline void clear_is_used (tree var) { var_ann_t ann = var_ann (var); ann->used = false; } /* Return true if VAR is marked as used. */ static inline bool is_used_p (tree var) { var_ann_t ann = var_ann (var); return ann->used; } /* Return true if T (assumed to be a DECL) is a global variable. A variable is considered global if its storage is not automatic. */ static inline bool is_global_var (const_tree t) { return (TREE_STATIC (t) || DECL_EXTERNAL (t)); } /* Return true if VAR may be aliased. A variable is considered as maybe aliased if it has its address taken by the local TU or possibly by another TU and might be modified through a pointer. */ static inline bool may_be_aliased (const_tree var) { return (TREE_CODE (var) != CONST_DECL && !((TREE_STATIC (var) || TREE_PUBLIC (var) || DECL_EXTERNAL (var)) && TREE_READONLY (var) && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (var))) && (TREE_PUBLIC (var) || DECL_EXTERNAL (var) || TREE_ADDRESSABLE (var))); } /* PHI nodes should contain only ssa_names and invariants. A test for ssa_name is definitely simpler; don't let invalid contents slip in in the meantime. */ static inline bool phi_ssa_name_p (const_tree t) { if (TREE_CODE (t) == SSA_NAME) return true; gcc_checking_assert (is_gimple_min_invariant (t)); return false; } /* Returns the loop of the statement STMT. */ static inline struct loop * loop_containing_stmt (gimple stmt) { basic_block bb = gimple_bb (stmt); if (!bb) return NULL; return bb->loop_father; } /* ----------------------------------------------------------------------- */ /* The following set of routines are used to iterator over various type of SSA operands. */ /* Return true if PTR is finished iterating. */ static inline bool op_iter_done (const ssa_op_iter *ptr) { return ptr->done; } /* Get the next iterator use value for PTR. */ static inline use_operand_p op_iter_next_use (ssa_op_iter *ptr) { use_operand_p use_p; gcc_checking_assert (ptr->iter_type == ssa_op_iter_use); if (ptr->uses) { use_p = USE_OP_PTR (ptr->uses); ptr->uses = ptr->uses->next; return use_p; } if (ptr->phi_i < ptr->num_phi) { return PHI_ARG_DEF_PTR (ptr->phi_stmt, (ptr->phi_i)++); } ptr->done = true; return NULL_USE_OPERAND_P; } /* Get the next iterator def value for PTR. */ static inline def_operand_p op_iter_next_def (ssa_op_iter *ptr) { def_operand_p def_p; gcc_checking_assert (ptr->iter_type == ssa_op_iter_def); if (ptr->defs) { def_p = DEF_OP_PTR (ptr->defs); ptr->defs = ptr->defs->next; return def_p; } ptr->done = true; return NULL_DEF_OPERAND_P; } /* Get the next iterator tree value for PTR. */ static inline tree op_iter_next_tree (ssa_op_iter *ptr) { tree val; gcc_checking_assert (ptr->iter_type == ssa_op_iter_tree); if (ptr->uses) { val = USE_OP (ptr->uses); ptr->uses = ptr->uses->next; return val; } if (ptr->defs) { val = DEF_OP (ptr->defs); ptr->defs = ptr->defs->next; return val; } ptr->done = true; return NULL_TREE; } /* This functions clears the iterator PTR, and marks it done. This is normally used to prevent warnings in the compile about might be uninitialized components. */ static inline void clear_and_done_ssa_iter (ssa_op_iter *ptr) { ptr->defs = NULL; ptr->uses = NULL; ptr->iter_type = ssa_op_iter_none; ptr->phi_i = 0; ptr->num_phi = 0; ptr->phi_stmt = NULL; ptr->done = true; } /* Initialize the iterator PTR to the virtual defs in STMT. */ static inline void op_iter_init (ssa_op_iter *ptr, gimple stmt, int flags) { /* PHI nodes require a different iterator initialization path. We do not support iterating over virtual defs or uses without iterating over defs or uses at the same time. */ gcc_checking_assert (gimple_code (stmt) != GIMPLE_PHI && (!(flags & SSA_OP_VDEF) || (flags & SSA_OP_DEF)) && (!(flags & SSA_OP_VUSE) || (flags & SSA_OP_USE))); ptr->defs = (flags & (SSA_OP_DEF|SSA_OP_VDEF)) ? gimple_def_ops (stmt) : NULL; if (!(flags & SSA_OP_VDEF) && ptr->defs && gimple_vdef (stmt) != NULL_TREE) ptr->defs = ptr->defs->next; ptr->uses = (flags & (SSA_OP_USE|SSA_OP_VUSE)) ? gimple_use_ops (stmt) : NULL; if (!(flags & SSA_OP_VUSE) && ptr->uses && gimple_vuse (stmt) != NULL_TREE) ptr->uses = ptr->uses->next; ptr->done = false; ptr->phi_i = 0; ptr->num_phi = 0; ptr->phi_stmt = NULL; } /* Initialize iterator PTR to the use operands in STMT based on FLAGS. Return the first use. */ static inline use_operand_p op_iter_init_use (ssa_op_iter *ptr, gimple stmt, int flags) { gcc_checking_assert ((flags & SSA_OP_ALL_DEFS) == 0 && (flags & SSA_OP_USE)); op_iter_init (ptr, stmt, flags); ptr->iter_type = ssa_op_iter_use; return op_iter_next_use (ptr); } /* Initialize iterator PTR to the def operands in STMT based on FLAGS. Return the first def. */ static inline def_operand_p op_iter_init_def (ssa_op_iter *ptr, gimple stmt, int flags) { gcc_checking_assert ((flags & SSA_OP_ALL_USES) == 0 && (flags & SSA_OP_DEF)); op_iter_init (ptr, stmt, flags); ptr->iter_type = ssa_op_iter_def; return op_iter_next_def (ptr); } /* Initialize iterator PTR to the operands in STMT based on FLAGS. Return the first operand as a tree. */ static inline tree op_iter_init_tree (ssa_op_iter *ptr, gimple stmt, int flags) { op_iter_init (ptr, stmt, flags); ptr->iter_type = ssa_op_iter_tree; return op_iter_next_tree (ptr); } /* If there is a single operand in STMT matching FLAGS, return it. Otherwise return NULL. */ static inline tree single_ssa_tree_operand (gimple stmt, int flags) { tree var; ssa_op_iter iter; var = op_iter_init_tree (&iter, stmt, flags); if (op_iter_done (&iter)) return NULL_TREE; op_iter_next_tree (&iter); if (op_iter_done (&iter)) return var; return NULL_TREE; } /* If there is a single operand in STMT matching FLAGS, return it. Otherwise return NULL. */ static inline use_operand_p single_ssa_use_operand (gimple stmt, int flags) { use_operand_p var; ssa_op_iter iter; var = op_iter_init_use (&iter, stmt, flags); if (op_iter_done (&iter)) return NULL_USE_OPERAND_P; op_iter_next_use (&iter); if (op_iter_done (&iter)) return var; return NULL_USE_OPERAND_P; } /* If there is a single operand in STMT matching FLAGS, return it. Otherwise return NULL. */ static inline def_operand_p single_ssa_def_operand (gimple stmt, int flags) { def_operand_p var; ssa_op_iter iter; var = op_iter_init_def (&iter, stmt, flags); if (op_iter_done (&iter)) return NULL_DEF_OPERAND_P; op_iter_next_def (&iter); if (op_iter_done (&iter)) return var; return NULL_DEF_OPERAND_P; } /* Return true if there are zero operands in STMT matching the type given in FLAGS. */ static inline bool zero_ssa_operands (gimple stmt, int flags) { ssa_op_iter iter; op_iter_init_tree (&iter, stmt, flags); return op_iter_done (&iter); } /* Return the number of operands matching FLAGS in STMT. */ static inline int num_ssa_operands (gimple stmt, int flags) { ssa_op_iter iter; tree t; int num = 0; gcc_checking_assert (gimple_code (stmt) != GIMPLE_PHI); FOR_EACH_SSA_TREE_OPERAND (t, stmt, iter, flags) num++; return num; } static inline use_operand_p op_iter_init_phiuse (ssa_op_iter *ptr, gimple phi, int flags); /* Delink all immediate_use information for STMT. */ static inline void delink_stmt_imm_use (gimple stmt) { ssa_op_iter iter; use_operand_p use_p; if (ssa_operands_active ()) FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_ALL_USES) delink_imm_use (use_p); } /* If there is a single DEF in the PHI node which matches FLAG, return it. Otherwise return NULL_DEF_OPERAND_P. */ static inline tree single_phi_def (gimple stmt, int flags) { tree def = PHI_RESULT (stmt); if ((flags & SSA_OP_DEF) && is_gimple_reg (def)) return def; if ((flags & SSA_OP_VIRTUAL_DEFS) && !is_gimple_reg (def)) return def; return NULL_TREE; } /* Initialize the iterator PTR for uses matching FLAGS in PHI. FLAGS should be either SSA_OP_USES or SSA_OP_VIRTUAL_USES. */ static inline use_operand_p op_iter_init_phiuse (ssa_op_iter *ptr, gimple phi, int flags) { tree phi_def = gimple_phi_result (phi); int comp; clear_and_done_ssa_iter (ptr); ptr->done = false; gcc_checking_assert ((flags & (SSA_OP_USE | SSA_OP_VIRTUAL_USES)) != 0); comp = (is_gimple_reg (phi_def) ? SSA_OP_USE : SSA_OP_VIRTUAL_USES); /* If the PHI node doesn't the operand type we care about, we're done. */ if ((flags & comp) == 0) { ptr->done = true; return NULL_USE_OPERAND_P; } ptr->phi_stmt = phi; ptr->num_phi = gimple_phi_num_args (phi); ptr->iter_type = ssa_op_iter_use; return op_iter_next_use (ptr); } /* Start an iterator for a PHI definition. */ static inline def_operand_p op_iter_init_phidef (ssa_op_iter *ptr, gimple phi, int flags) { tree phi_def = PHI_RESULT (phi); int comp; clear_and_done_ssa_iter (ptr); ptr->done = false; gcc_checking_assert ((flags & (SSA_OP_DEF | SSA_OP_VIRTUAL_DEFS)) != 0); comp = (is_gimple_reg (phi_def) ? SSA_OP_DEF : SSA_OP_VIRTUAL_DEFS); /* If the PHI node doesn't have the operand type we care about, we're done. */ if ((flags & comp) == 0) { ptr->done = true; return NULL_DEF_OPERAND_P; } ptr->iter_type = ssa_op_iter_def; /* The first call to op_iter_next_def will terminate the iterator since all the fields are NULL. Simply return the result here as the first and therefore only result. */ return PHI_RESULT_PTR (phi); } /* Return true is IMM has reached the end of the immediate use stmt list. */ static inline bool end_imm_use_stmt_p (const imm_use_iterator *imm) { return (imm->imm_use == imm->end_p); } /* Finished the traverse of an immediate use stmt list IMM by removing the placeholder node from the list. */ static inline void end_imm_use_stmt_traverse (imm_use_iterator *imm) { delink_imm_use (&(imm->iter_node)); } /* Immediate use traversal of uses within a stmt require that all the uses on a stmt be sequentially listed. This routine is used to build up this sequential list by adding USE_P to the end of the current list currently delimited by HEAD and LAST_P. The new LAST_P value is returned. */ static inline use_operand_p move_use_after_head (use_operand_p use_p, use_operand_p head, use_operand_p last_p) { gcc_checking_assert (USE_FROM_PTR (use_p) == USE_FROM_PTR (head)); /* Skip head when we find it. */ if (use_p != head) { /* If use_p is already linked in after last_p, continue. */ if (last_p->next == use_p) last_p = use_p; else { /* Delink from current location, and link in at last_p. */ delink_imm_use (use_p); link_imm_use_to_list (use_p, last_p); last_p = use_p; } } return last_p; } /* This routine will relink all uses with the same stmt as HEAD into the list immediately following HEAD for iterator IMM. */ static inline void link_use_stmts_after (use_operand_p head, imm_use_iterator *imm) { use_operand_p use_p; use_operand_p last_p = head; gimple head_stmt = USE_STMT (head); tree use = USE_FROM_PTR (head); ssa_op_iter op_iter; int flag; /* Only look at virtual or real uses, depending on the type of HEAD. */ flag = (is_gimple_reg (use) ? SSA_OP_USE : SSA_OP_VIRTUAL_USES); if (gimple_code (head_stmt) == GIMPLE_PHI) { FOR_EACH_PHI_ARG (use_p, head_stmt, op_iter, flag) if (USE_FROM_PTR (use_p) == use) last_p = move_use_after_head (use_p, head, last_p); } else { if (flag == SSA_OP_USE) { FOR_EACH_SSA_USE_OPERAND (use_p, head_stmt, op_iter, flag) if (USE_FROM_PTR (use_p) == use) last_p = move_use_after_head (use_p, head, last_p); } else if ((use_p = gimple_vuse_op (head_stmt)) != NULL_USE_OPERAND_P) { if (USE_FROM_PTR (use_p) == use) last_p = move_use_after_head (use_p, head, last_p); } } /* Link iter node in after last_p. */ if (imm->iter_node.prev != NULL) delink_imm_use (&imm->iter_node); link_imm_use_to_list (&(imm->iter_node), last_p); } /* Initialize IMM to traverse over uses of VAR. Return the first statement. */ static inline gimple first_imm_use_stmt (imm_use_iterator *imm, tree var) { imm->end_p = &(SSA_NAME_IMM_USE_NODE (var)); imm->imm_use = imm->end_p->next; imm->next_imm_name = NULL_USE_OPERAND_P; /* iter_node is used as a marker within the immediate use list to indicate where the end of the current stmt's uses are. Initialize it to NULL stmt and use, which indicates a marker node. */ imm->iter_node.prev = NULL_USE_OPERAND_P; imm->iter_node.next = NULL_USE_OPERAND_P; imm->iter_node.loc.stmt = NULL; imm->iter_node.use = NULL; if (end_imm_use_stmt_p (imm)) return NULL; link_use_stmts_after (imm->imm_use, imm); return USE_STMT (imm->imm_use); } /* Bump IMM to the next stmt which has a use of var. */ static inline gimple next_imm_use_stmt (imm_use_iterator *imm) { imm->imm_use = imm->iter_node.next; if (end_imm_use_stmt_p (imm)) { if (imm->iter_node.prev != NULL) delink_imm_use (&imm->iter_node); return NULL; } link_use_stmts_after (imm->imm_use, imm); return USE_STMT (imm->imm_use); } /* This routine will return the first use on the stmt IMM currently refers to. */ static inline use_operand_p first_imm_use_on_stmt (imm_use_iterator *imm) { imm->next_imm_name = imm->imm_use->next; return imm->imm_use; } /* Return TRUE if the last use on the stmt IMM refers to has been visited. */ static inline bool end_imm_use_on_stmt_p (const imm_use_iterator *imm) { return (imm->imm_use == &(imm->iter_node)); } /* Bump to the next use on the stmt IMM refers to, return NULL if done. */ static inline use_operand_p next_imm_use_on_stmt (imm_use_iterator *imm) { imm->imm_use = imm->next_imm_name; if (end_imm_use_on_stmt_p (imm)) return NULL_USE_OPERAND_P; else { imm->next_imm_name = imm->imm_use->next; return imm->imm_use; } } /* Return true if VAR cannot be modified by the program. */ static inline bool unmodifiable_var_p (const_tree var) { if (TREE_CODE (var) == SSA_NAME) var = SSA_NAME_VAR (var); return TREE_READONLY (var) && (TREE_STATIC (var) || DECL_EXTERNAL (var)); } /* Return true if REF, a handled component reference, has an ARRAY_REF somewhere in it. */ static inline bool ref_contains_array_ref (const_tree ref) { gcc_checking_assert (handled_component_p (ref)); do { if (TREE_CODE (ref) == ARRAY_REF) return true; ref = TREE_OPERAND (ref, 0); } while (handled_component_p (ref)); return false; } /* Return true if REF has an VIEW_CONVERT_EXPR somewhere in it. */ static inline bool contains_view_convert_expr_p (const_tree ref) { while (handled_component_p (ref)) { if (TREE_CODE (ref) == VIEW_CONVERT_EXPR) return true; ref = TREE_OPERAND (ref, 0); } return false; } /* Return true, if the two ranges [POS1, SIZE1] and [POS2, SIZE2] overlap. SIZE1 and/or SIZE2 can be (unsigned)-1 in which case the range is open-ended. Otherwise return false. */ static inline bool ranges_overlap_p (unsigned HOST_WIDE_INT pos1, unsigned HOST_WIDE_INT size1, unsigned HOST_WIDE_INT pos2, unsigned HOST_WIDE_INT size2) { if (pos1 >= pos2 && (size2 == (unsigned HOST_WIDE_INT)-1 || pos1 < (pos2 + size2))) return true; if (pos2 >= pos1 && (size1 == (unsigned HOST_WIDE_INT)-1 || pos2 < (pos1 + size1))) return true; return false; } /* Accessor to tree-ssa-operands.c caches. */ static inline struct ssa_operands * gimple_ssa_operands (const struct function *fun) { return &fun->gimple_df->ssa_operands; } /* Given an edge_var_map V, return the PHI arg definition. */ static inline tree redirect_edge_var_map_def (edge_var_map *v) { return v->def; } /* Given an edge_var_map V, return the PHI result. */ static inline tree redirect_edge_var_map_result (edge_var_map *v) { return v->result; } /* Given an edge_var_map V, return the PHI arg location. */ static inline source_location redirect_edge_var_map_location (edge_var_map *v) { return v->locus; } /* Return an SSA_NAME node for variable VAR defined in statement STMT in function cfun. */ static inline tree make_ssa_name (tree var, gimple stmt) { return make_ssa_name_fn (cfun, var, stmt); } /* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that denotes the starting address of the memory access EXP. Returns NULL_TREE if the offset is not constant or any component is not BITS_PER_UNIT-aligned. VALUEIZE if non-NULL is used to valueize SSA names. It should return its argument or a constant if the argument is known to be constant. */ static inline tree get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset, tree (*valueize) (tree)) { HOST_WIDE_INT byte_offset = 0; /* Compute cumulative byte-offset for nested component-refs and array-refs, and find the ultimate containing object. */ while (1) { switch (TREE_CODE (exp)) { case BIT_FIELD_REF: return NULL_TREE; case COMPONENT_REF: { tree field = TREE_OPERAND (exp, 1); tree this_offset = component_ref_field_offset (exp); HOST_WIDE_INT hthis_offset; if (!this_offset || TREE_CODE (this_offset) != INTEGER_CST || (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) % BITS_PER_UNIT)) return NULL_TREE; hthis_offset = TREE_INT_CST_LOW (this_offset); hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) / BITS_PER_UNIT); byte_offset += hthis_offset; } break; case ARRAY_REF: case ARRAY_RANGE_REF: { tree index = TREE_OPERAND (exp, 1); tree low_bound, unit_size; if (valueize && TREE_CODE (index) == SSA_NAME) index = (*valueize) (index); /* If the resulting bit-offset is constant, track it. */ if (TREE_CODE (index) == INTEGER_CST && (low_bound = array_ref_low_bound (exp), TREE_CODE (low_bound) == INTEGER_CST) && (unit_size = array_ref_element_size (exp), TREE_CODE (unit_size) == INTEGER_CST)) { HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index); hindex -= TREE_INT_CST_LOW (low_bound); hindex *= TREE_INT_CST_LOW (unit_size); byte_offset += hindex; } else return NULL_TREE; } break; case REALPART_EXPR: break; case IMAGPART_EXPR: byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp))); break; case VIEW_CONVERT_EXPR: break; case MEM_REF: { tree base = TREE_OPERAND (exp, 0); if (valueize && TREE_CODE (base) == SSA_NAME) base = (*valueize) (base); /* Hand back the decl for MEM[&decl, off]. */ if (TREE_CODE (base) == ADDR_EXPR) { if (!integer_zerop (TREE_OPERAND (exp, 1))) { double_int off = mem_ref_offset (exp); gcc_assert (off.high == -1 || off.high == 0); byte_offset += double_int_to_shwi (off); } exp = TREE_OPERAND (base, 0); } goto done; } case TARGET_MEM_REF: { tree base = TREE_OPERAND (exp, 0); if (valueize && TREE_CODE (base) == SSA_NAME) base = (*valueize) (base); /* Hand back the decl for MEM[&decl, off]. */ if (TREE_CODE (base) == ADDR_EXPR) { if (TMR_INDEX (exp) || TMR_INDEX2 (exp)) return NULL_TREE; if (!integer_zerop (TMR_OFFSET (exp))) { double_int off = mem_ref_offset (exp); gcc_assert (off.high == -1 || off.high == 0); byte_offset += double_int_to_shwi (off); } exp = TREE_OPERAND (base, 0); } goto done; } default: goto done; } exp = TREE_OPERAND (exp, 0); } done: *poffset = byte_offset; return exp; } #endif /* _TREE_FLOW_INLINE_H */