diff options
Diffstat (limited to 'gcc/tree-ssa-operands.c')
-rw-r--r-- | gcc/tree-ssa-operands.c | 537 |
1 files changed, 344 insertions, 193 deletions
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 1ec274b5518..0dafc966ae5 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -162,7 +162,7 @@ static vuse_optype_p free_vuses = NULL; static vdef_optype_p free_vdefs = NULL; /* Sets of symbols loaded and stored by a statement. These sets are - only used when the operand scanner is called via get_loads_and_stores. */ + only used when the operand scanner is called via update_loads_and_stores. */ static bitmap loaded_syms = NULL; static bitmap stored_syms = NULL; @@ -204,6 +204,40 @@ DEF_VEC_ALLOC_P(scb_t,heap); of changes for the popped statement. */ static VEC(scb_t,heap) *scb_stack; +/* Table, indexed by statement, for symbols loaded and stored by + statements that reference memory. */ +static htab_t mem_syms_tbl; + +/* Hashing and equality functions for MEM_SYMS_TBL. */ + +static hashval_t +mem_syms_hash (const void *p) +{ + return htab_hash_pointer ((const void *)((const mem_syms_map_t)p)->stmt); +} + +static int +mem_syms_eq (const void *p1, const void *p2) +{ + return ((const mem_syms_map_t)p1)->stmt == ((const mem_syms_map_t)p2)->stmt; +} + +static void +mem_syms_free (void *p) +{ + bitmap loads = ((mem_syms_map_t)p)->loads; + bitmap stores = ((mem_syms_map_t)p)->stores; + bool shared_p = loads == stores; + + BITMAP_FREE (loads); + + /* PHI nodes share loads/stores sets. Avoid freeing them twice. */ + if (!shared_p) + BITMAP_FREE (stores); + + free (p); +} + /* Return true if the parser should just gather symbols loaded/stored by the statement instead of scanning for operands. */ @@ -297,9 +331,11 @@ init_ssa_operands (void) build_vuses = VEC_alloc (tree, heap, 25); build_vdefs = VEC_alloc (tree, heap, 25); scb_stack = VEC_alloc (scb_t, heap, 20); - gcc_assert (operand_memory == NULL); operand_memory_index = SSA_OPERAND_MEMORY_SIZE; + gcc_assert (mem_syms_tbl == NULL); + mem_syms_tbl = htab_create (200, mem_syms_hash, mem_syms_eq, mem_syms_free); + ops_active = true; } @@ -330,6 +366,9 @@ fini_ssa_operands (void) ggc_free (ptr); } + htab_delete (mem_syms_tbl); + mem_syms_tbl = NULL; + ops_active = false; } @@ -1049,6 +1088,12 @@ append_vuse (void) static inline void add_virtual_operator (int flags) { + /* If no alias information exists, we are not going to build the + virtual SSA form, so adding a VDEF/VUSE operator will only upset + the SSA verifier because its operands will not be renamed. */ + if (!aliases_computed_p) + return; + /* If we are inside an ADDR_EXPR, then VAR is not being referenced but used to compute address arithmetic. */ if (flags & opf_no_vops) @@ -1071,7 +1116,7 @@ add_virtual_operator (int flags) static bool access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset, HOST_WIDE_INT size) -{ +{ bool offsetgtz = offset > 0; unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset; tree base = ref ? get_base_address (ref) : NULL; @@ -1240,9 +1285,9 @@ add_mem_symbol (tree decl, int flags) flags &= ~opf_def; uid = DECL_UID (decl); - if (flags & opf_def) + if (stored_syms && (flags & opf_def)) bitmap_set_bit (stored_syms, uid); - else + else if (loaded_syms) bitmap_set_bit (loaded_syms, uid); } @@ -1331,10 +1376,6 @@ get_mem_symbols_in_indirect_ref (tree expr, int flags, tree full_ref, tree *pptr = &TREE_OPERAND (expr, 0); tree ptr = *pptr; - /* If we don't have aliasing information, do nothing. */ - if (!aliases_computed_p) - return; - /* No symbols referenced if PTR is not a variable. */ if (!SSA_VAR_P (ptr)) return; @@ -1654,13 +1695,21 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags) /* .MEM should not be found in the code. */ gcc_assert (var != mem_var); - /* When gathering loads and stores, look for the symbols - associated with VAR, otherwise add the virtual operator - indicated by FLAGS. */ + /* Mark the statement as having memory operands. */ + s_ann->references_memory = true; + if (gathering_loads_stores ()) - add_mem_symbols_in_decl (var, flags); + { + /* When gathering loads and stores, look for the symbols + associated with VAR, otherwise add the virtual operator + indicated by FLAGS. */ + add_mem_symbols_in_decl (var, flags); + } else - add_virtual_operator (flags); + { + /* Otherwise, add a virtual operator for .MEM. */ + add_virtual_operator (flags); + } } } @@ -1686,6 +1735,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags) tree ptr = *pptr; stmt_ann_t s_ann = stmt_ann (stmt); + s_ann->references_memory = true; + /* If the dereference is volatile, mark the statement accordingly. */ if (TREE_THIS_VOLATILE (expr)) s_ann->has_volatile_ops = true; @@ -1700,27 +1751,20 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags) if (SSA_VAR_P (ptr)) { - /* Only add a reference to .MEM if we have alias information - available. Otherwise, the SSA renamer will try to access the - aliased symbols associated with this pointer dereference and - find nothing. */ - if (aliases_computed_p) - { - tree tag; + tree tag; - if (TREE_CODE (ptr) == SSA_NAME - && SSA_NAME_PTR_INFO (ptr) - && SSA_NAME_PTR_INFO (ptr)->name_mem_tag) - tag = SSA_NAME_PTR_INFO (ptr)->name_mem_tag; - else - { - tree sym = DECL_P (ptr) ? ptr : SSA_NAME_VAR (ptr); - tag = var_ann (sym)->symbol_mem_tag; - } - - if (tag) - add_virtual_operator (flags); + if (TREE_CODE (ptr) == SSA_NAME + && SSA_NAME_PTR_INFO (ptr) + && SSA_NAME_PTR_INFO (ptr)->name_mem_tag) + tag = SSA_NAME_PTR_INFO (ptr)->name_mem_tag; + else + { + tree sym = DECL_P (ptr) ? ptr : SSA_NAME_VAR (ptr); + tag = var_ann (sym)->symbol_mem_tag; } + + if (tag) + add_virtual_operator (flags); } else if (TREE_CODE (ptr) == INTEGER_CST) { @@ -1749,6 +1793,9 @@ static void get_tmr_operands (tree stmt, tree expr, int flags) { tree tag; + stmt_ann_t ann = stmt_ann (stmt); + + ann->references_memory = 1; /* When gathering memory symbols, there is no need to keep analyzing the rest of the expression. */ @@ -1763,10 +1810,7 @@ get_tmr_operands (tree stmt, tree expr, int flags) get_expr_operands (stmt, &TMR_INDEX (expr), opf_use); if (TMR_SYMBOL (expr)) - { - stmt_ann_t ann = stmt_ann (stmt); - add_to_addressable_set (TMR_SYMBOL (expr), &ann->addresses_taken); - } + add_to_addressable_set (TMR_SYMBOL (expr), &ann->addresses_taken); tag = TMR_TAG (expr); if (!tag) @@ -1788,6 +1832,8 @@ get_call_expr_operands (tree stmt, tree expr) tree op; int call_flags = call_expr_flags (expr); + stmt_ann (stmt)->references_memory = true; + if (!bitmap_empty_p (call_clobbered_vars) && !(call_flags & ECF_NOVOPS)) { /* A 'pure' or a 'const' function never call-clobbers anything. @@ -1881,6 +1927,8 @@ get_asm_expr_operands (tree stmt) unsigned i; bitmap_iterator bi; + s_ann->references_memory = true; + EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi) { tree var; @@ -2246,9 +2294,13 @@ build_ssa_operands (tree stmt) { stmt_ann_t ann = get_stmt_ann (stmt); - /* Initially assume that the statement has no volatile operands. */ + /* Initially assume that the statement has no volatile operands and + makes no memory references. */ if (ann) - ann->has_volatile_ops = false; + { + ann->has_volatile_ops = false; + ann->references_memory = false; + } start_ssa_stmt_operands (); @@ -2257,6 +2309,11 @@ build_ssa_operands (tree stmt) operand_build_sort_virtual (build_vdefs); finalize_ssa_stmt_operands (stmt); + + /* For added safety, assume that statements with volatile operands + also reference memory. */ + if (ann->has_volatile_ops) + ann->references_memory = true; } @@ -2272,6 +2329,182 @@ free_ssa_operands (stmt_operands_p ops) } +/* Lookup in MEM_SYMS_TBL a slot corresponding to STMT. Create a new + one if needed. */ + +mem_syms_map_t +get_loads_and_stores (tree stmt) +{ + struct mem_syms_map_d m, *mp; + void **slot; + + gcc_assert (mem_syms_tbl); + gcc_assert (stmt_references_memory_p (stmt)); + + m.stmt = stmt; + slot = htab_find_slot (mem_syms_tbl, (void *) &m, INSERT); + if (*slot == NULL) + { + mp = XNEW (struct mem_syms_map_d); + mp->stmt = stmt; + mp->loads = BITMAP_ALLOC (NULL); + + if (TREE_CODE (stmt) == PHI_NODE) + { + tree lhs_sym; + + /* PHI nodes load and store the same symbols. */ + mp->stores = mp->loads; + + /* Non-factored PHI nodes load and store exactly one symbol. */ + lhs_sym = SSA_NAME_VAR (PHI_RESULT (stmt)); + if (lhs_sym != mem_var) + bitmap_set_bit (mp->stores, DECL_UID (lhs_sym)); + } + else + mp->stores = BITMAP_ALLOC (NULL); + + *slot = (void *) mp; + } + else + mp = (mem_syms_map_t) *slot; + + return mp; +} + + +/* Delete the loads and stores sets associated with STMT. */ + +void +delete_loads_and_stores (tree stmt) +{ + if (mem_syms_tbl) + { + struct mem_syms_map_d m; + void **slot; + + m.stmt = stmt; + slot = htab_find_slot (mem_syms_tbl, (void *) &m, NO_INSERT); + if (slot) + htab_remove_elt (mem_syms_tbl, *slot); + } +} + + +/* Add LOADS and STORES to the corresponding sets in STMT. + + NOTE: Not to be used lightly. This is generally used by the SSA + renamer to initialize the factored symbols sets for factoring + PHI nodes. */ + +void +add_loads_and_stores (tree stmt, bitmap loads, bitmap stores) +{ + mem_syms_map_t mp = get_loads_and_stores (stmt); + + if (loads) + bitmap_ior_into (mp->loads, loads); + + if (stores) + bitmap_ior_into (mp->stores, stores); +} + + +/* Move the sets of loads and stores from OLD_STMT into NEW_STMT. + Remove the entry for OLD_STMT. */ + +void +move_loads_and_stores (tree new_stmt, tree old_stmt) +{ + void **slot; + mem_syms_map_t old_mp, new_mp; + + gcc_assert (TREE_CODE (new_stmt) == TREE_CODE (old_stmt)); + + old_mp = get_loads_and_stores (old_stmt); + new_mp = get_loads_and_stores (new_stmt); + + bitmap_copy (new_mp->loads, old_mp->loads); + + /* PHI nodes share their loads and stores sets. */ + if (TREE_CODE (new_stmt) != PHI_NODE) + bitmap_copy (new_mp->stores, old_mp->stores); + + slot = htab_find_slot (mem_syms_tbl, (void *) old_mp, NO_INSERT); + htab_remove_elt (mem_syms_tbl, *slot); +} + + +/* Update the sets of symbols loaded and stored by STMT. + + FIXME, if the statement has a store, we should use the SSA name on + its LHS as the index into an array. Only use hashing for + statements that only have a load operation. */ + +static void +update_loads_and_stores (tree stmt) +{ + mem_syms_map_t mp; + + memset (&clobber_stats, 0, sizeof (clobber_stats)); + + mp = get_loads_and_stores (stmt); + + if (mp->loads) + bitmap_clear (mp->loads); + else + mp->loads = BITMAP_ALLOC (NULL); + + if (mp->stores) + bitmap_clear (mp->stores); + else + mp->stores = BITMAP_ALLOC (NULL); + + /* Point the internal loaded/stored sets to the ones provided. */ + loaded_syms = mp->loads; + stored_syms = mp->stores; + + /* Parse the statement. We don't really care for its operands, so + there's no need to initialize anything. If any operand was added + to the cache, it is discarded. + + FIXME, unnecessary. A single call to parse_ssa_operands should + do everything. */ + gcc_assert (loaded_syms || stored_syms); + parse_ssa_operands (stmt); + truncate_ssa_stmt_operands (); + + /* We don't need the symbol sets anymore. */ + loaded_syms = NULL; + stored_syms = NULL; + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_loads_and_stores (dump_file, stmt); + + if (mp->loads && bitmap_empty_p (mp->loads)) + BITMAP_FREE (mp->loads); + + if (mp->stores && bitmap_empty_p (mp->stores)) + BITMAP_FREE (mp->stores); + + if (dump_file && (dump_flags & TDF_STATS)) + { + fprintf (dump_file, "Original clobbered vars: %d\n", + clobber_stats.clobbered_vars); + fprintf (dump_file, "Static write clobbers avoided: %d\n", + clobber_stats.static_write_clobbers_avoided); + fprintf (dump_file, "Static read clobbers avoided: %d\n", + clobber_stats.static_read_clobbers_avoided); + fprintf (dump_file, "Unescapable clobbers avoided: %d\n", + clobber_stats.unescapable_clobbers_avoided); + fprintf (dump_file, "Original read-only clobbers: %d\n", + clobber_stats.readonly_clobbers); + fprintf (dump_file, "Static read-only clobbers avoided: %d\n", + clobber_stats.static_readonly_clobbers_avoided); + } +} + + /* Get the operands of statement STMT. */ void @@ -2288,18 +2521,23 @@ update_stmt_operands (tree stmt) _DECL. This indicates a bug in the gimplifier. */ gcc_assert (!SSA_VAR_P (stmt)); - gcc_assert (ann->modified); - - /* This cannot be called from get_loads_and_stores. */ + /* This cannot be called from update_loads_and_stores. */ gcc_assert (!gathering_loads_stores ()); timevar_push (TV_TREE_OPS); + gcc_assert (ann->modified); build_ssa_operands (stmt); - - /* Clear the modified bit for STMT. */ ann->modified = 0; + /* If the statement makes memory references, collect symbols + referenced by it. + + FIXME, we should stop scanning the statement twice. With a + single scan we should get both operands and symbols. */ + if (stmt_references_memory_p (stmt)) + update_loads_and_stores (stmt); + timevar_pop (TV_TREE_OPS); } @@ -2626,157 +2864,42 @@ debug_immediate_uses_for (tree var) dump_immediate_uses_for (stderr, var); } -void debug_loads_and_stores (tree); -void dump_loads_and_stores (FILE *, tree, bitmap, bitmap); - -/* Dump symbols loaded and stored by STMT to FILE. If LOADS and - STORES are given, the statement is not scanned. */ +/* Dump symbols loaded and stored by STMT to FILE. */ void -dump_loads_and_stores (FILE *file, tree stmt, bitmap loads, bitmap stores) +dump_loads_and_stores (FILE *file, tree stmt) { - unsigned i; - bitmap_iterator bi; - bool free_memory_p = false; - - if (loads == NULL && stores == NULL) - { - loads = BITMAP_ALLOC (NULL); - stores = BITMAP_ALLOC (NULL); - get_loads_and_stores (stmt, loads, stores); - free_memory_p = true; - } + mem_syms_map_t mp; - fprintf (file, "\n\n"); print_generic_stmt (file, stmt, TDF_VOPS); - fprintf (file, "\tLOADS: { "); - EXECUTE_IF_SET_IN_BITMAP (loads, 0, i, bi) - { - print_generic_expr (file, referenced_var (i), 0); - fprintf (file, " "); - } - fprintf (file, "}\n"); - fprintf (file, "\tSTORES: { "); - EXECUTE_IF_SET_IN_BITMAP (stores, 0, i, bi) - { - print_generic_expr (file, referenced_var (i), 0); - fprintf (file, " "); - } - fprintf (file, "}\n"); + mp = get_loads_and_stores (stmt); - if (free_memory_p) + if (TREE_CODE (stmt) == PHI_NODE) { - BITMAP_FREE (loads); - BITMAP_FREE (stores); + fprintf (file, "\tLOADS/STORES: "); + dump_decl_set (file, mp->loads); + if (mp->loads != mp->stores) + fprintf (file, "\n\tWARNING. LOADS and STORES sets not shared.\n"); } -} - - -/* Dump symbols loaded and stored by STMT to stderr. */ - -void -debug_loads_and_stores (tree stmt) -{ - dump_loads_and_stores (stderr, stmt, NULL, NULL); -} - - -/* Collect all the symbols loaded and stored by the arguments of PHI - node PHI. Store the sets in LOADS and STORES respectively. */ - -static void -get_loads_and_stores_for_phi (tree phi, bitmap loads, bitmap stores) -{ - int i; - tree lhs = PHI_RESULT (phi); - - gcc_assert (!is_gimple_reg (lhs)); - - for (i = 0; i < PHI_NUM_ARGS (phi); i++) + else { - tree sym, arg; - - arg = PHI_ARG_DEF (phi, i); + fprintf (file, "\tLOADS: "); + dump_decl_set (file, mp->loads); - /* Avoid infinite recursion. */ - if (arg == lhs) - continue; - - sym = SSA_NAME_VAR (arg); - - if (sym == mem_var) - { - /* Recurse for an memory factored SSA name. */ - get_loads_and_stores (SSA_NAME_DEF_STMT (arg), loads, stores); - } - else - { - /* Otherwise, this PHI node will both load and store the - underlying symbol for ARG. */ - bitmap_set_bit (loads, DECL_UID (sym)); - bitmap_set_bit (stores, DECL_UID (sym)); - } + fprintf (file, "\tSTORES: "); + dump_decl_set (file, mp->stores); } } - - -/* Add to LOADED the set of symbols loaded by STMT and add to STORED - the set of symbols stored by STMT. Both sets must be allocated by - the caller. FIXME, should allow for either set to be NULL. */ +/* Dump symbols loaded and stored by STMT to stderr. */ void -get_loads_and_stores (tree stmt, bitmap loads, bitmap stores) +debug_loads_and_stores (tree stmt) { - gcc_assert (loads && stores); - memset (&clobber_stats, 0, sizeof (clobber_stats)); - - if (TREE_CODE (stmt) != PHI_NODE) - { - gcc_assert (stmt_references_memory_p (stmt)); - - /* Point the internal loaded/stored sets to the ones provided. */ - loaded_syms = loads; - stored_syms = stores; - - /* Parse the statement. We don't really care for its operands, so - there's no need to initialize anything. If any operand was added - to the cache, it is discarded. */ - parse_ssa_operands (stmt); - truncate_ssa_stmt_operands (); - - /* We don't need the symbol sets anymore. */ - loaded_syms = NULL; - stored_syms = NULL; - } - else - { - /* PHI nodes need special treatment. A PHI node loads/stores - all the symbols loaded/stored by its arguments. */ - get_loads_and_stores_for_phi (stmt, loads, stores); - } - - if (dump_file && (dump_flags & TDF_DETAILS)) - dump_loads_and_stores (dump_file, stmt, loads, stores); - - if (dump_file && (dump_flags & TDF_STATS)) - { - fprintf (dump_file, "Original clobbered vars: %d\n", - clobber_stats.clobbered_vars); - fprintf (dump_file, "Static write clobbers avoided: %d\n", - clobber_stats.static_write_clobbers_avoided); - fprintf (dump_file, "Static read clobbers avoided: %d\n", - clobber_stats.static_read_clobbers_avoided); - fprintf (dump_file, "Unescapable clobbers avoided: %d\n", - clobber_stats.unescapable_clobbers_avoided); - fprintf (dump_file, "Original read-only clobbers: %d\n", - clobber_stats.readonly_clobbers); - fprintf (dump_file, "Static read-only clobbers avoided: %d\n", - clobber_stats.static_readonly_clobbers_avoided); - } + dump_loads_and_stores (stderr, stmt); } @@ -2806,38 +2929,50 @@ push_stmt_changes (tree *stmt_p) if (stmt_references_memory_p (stmt)) { + mem_syms_map_t mp; + buf->loads = BITMAP_ALLOC (NULL); buf->stores = BITMAP_ALLOC (NULL); - get_loads_and_stores (stmt, buf->loads, buf->stores); + + mp = get_loads_and_stores (stmt); + + if (mp->loads) + bitmap_copy (buf->loads, mp->loads); + + if (mp->stores) + bitmap_copy (buf->stores, mp->stores); } VEC_safe_push (scb_t, heap, scb_stack, buf); } -/* Given two sets S1 and S2, mark the symbols in S1 U S2 for renaming - if S1 != S2. Sets S1 and S2 may be overwritten by this function. */ +/* Given two sets S1 and S2, mark the symbols that differ in S1 and S2 + for renaming. The set to mark for renaming is (S1 & ~S2) | (S2 & ~S1). */ static void mark_difference_for_renaming (bitmap s1, bitmap s2) { - bitmap tmp = NULL; - if (s1 == NULL && s2 == NULL) return; if (s1 && s2 == NULL) - tmp = s1; + mark_set_for_renaming (s1); else if (s1 == NULL && s2) - tmp = s2; + mark_set_for_renaming (s2); else if (!bitmap_equal_p (s1, s2)) { - tmp = s1; - bitmap_ior_into (tmp, s2); - } + bitmap t1 = BITMAP_ALLOC (NULL); + bitmap t2 = BITMAP_ALLOC (NULL); + + bitmap_and_compl (t1, s1, s2); + bitmap_and_compl (t2, s2, s1); + bitmap_ior_into (t1, t2); + mark_set_for_renaming (t1); - if (tmp) - mark_set_for_renaming (tmp); + BITMAP_FREE (t1); + BITMAP_FREE (t2); + } } @@ -2850,6 +2985,7 @@ pop_stmt_changes (tree *stmt_p) { tree op, stmt; ssa_op_iter iter; + mem_syms_map_t mp; bitmap loads, stores; scb_t buf; @@ -2872,9 +3008,9 @@ pop_stmt_changes (tree *stmt_p) loads = stores = NULL; if (stmt_references_memory_p (stmt)) { - loads = BITMAP_ALLOC (NULL); - stores = BITMAP_ALLOC (NULL); - get_loads_and_stores (stmt, loads, stores); + mp = get_loads_and_stores (stmt); + loads = mp->loads; + stores = mp->stores; } /* If LOADS is different from BUF->LOADS, the affected @@ -2908,9 +3044,24 @@ pop_stmt_changes (tree *stmt_p) BITMAP_FREE (buf->stores); buf->stmt_p = NULL; free (buf); +} - BITMAP_FREE (loads); - BITMAP_FREE (stores); + +/* Returns true if statement STMT may access memory. */ + +bool +stmt_references_memory_p (tree stmt) +{ + if (!ops_active) + return false; + + if (TREE_CODE (stmt) == PHI_NODE) + { + tree lhs_sym = SSA_NAME_VAR (PHI_RESULT (stmt)); + return lhs_sym == mem_var || !is_gimple_reg (lhs_sym); + } + + return stmt_ann (stmt)->references_memory; } #include "gt-tree-ssa-operands.h" |