- tree sym;
-
- if (TREE_CODE (var) != SSA_NAME)
- {
- tree mpt;
- var_ann_t ann;
-
- /* If VAR belongs to a memory partition, use it instead of VAR. */
- mpt = memory_partition (var);
- if (mpt)
- var = mpt;
-
- /* Don't allow duplicate entries. */
- ann = get_var_ann (var);
- if (ann->in_vuse_list)
- return;
- else if (ann->in_vdef_list)
- {
- /* We don't want a vuse if we already have a vdef, but we must
- still put this in build_loads. */
- bitmap_set_bit (build_loads, DECL_UID (var));
- return;
- }
-
- ann->in_vuse_list = true;
- sym = var;
- }
- else
- sym = SSA_NAME_VAR (var);
-
- VEC_safe_push (tree, heap, build_vuses, var);
- bitmap_set_bit (build_loads, DECL_UID (sym));
-}
-
-
-/* REF is a tree that contains the entire pointer dereference
- expression, if available, or NULL otherwise. ALIAS is the variable
- we are asking if REF can access. OFFSET and SIZE come from the
- memory access expression that generated this virtual operand.
-
- XXX: We should handle the NO_ALIAS attributes here. */
-
-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;
-
- /* If ALIAS is .GLOBAL_VAR then the memory reference REF must be
- using a call-clobbered memory tag. By definition, call-clobbered
- memory tags can always touch .GLOBAL_VAR. */
- if (alias == gimple_global_var (cfun))
- return true;
-
- /* If ref is a TARGET_MEM_REF, just return true, as we can't really
- disambiguate them right now. */
- if (ref && TREE_CODE (ref) == TARGET_MEM_REF)
- return true;
-
- /* If ALIAS is an SFT, it can't be touched if the offset
- and size of the access is not overlapping with the SFT offset and
- size. This is only true if we are accessing through a pointer
- to a type that is the same as SFT_PARENT_VAR. Otherwise, we may
- be accessing through a pointer to some substruct of the
- structure, and if we try to prune there, we will have the wrong
- offset, and get the wrong answer.
- i.e., we can't prune without more work if we have something like
-
- struct gcc_target
- {
- struct asm_out
- {
- const char *byte_op;
- struct asm_int_op
- {
- const char *hi;
- } aligned_op;
- } asm_out;
- } targetm;
-
- foo = &targetm.asm_out.aligned_op;
- return foo->hi;
-
- SFT.1, which represents hi, will have SFT_OFFSET=32 because in
- terms of SFT_PARENT_VAR, that is where it is.
- However, the access through the foo pointer will be at offset 0. */
- if (size != -1
- && TREE_CODE (alias) == STRUCT_FIELD_TAG
- && base
- && TREE_TYPE (base) == TREE_TYPE (SFT_PARENT_VAR (alias))
- && !overlap_subvar (offset, size, alias, NULL))
- {
-#ifdef ACCESS_DEBUGGING
- fprintf (stderr, "Access to ");
- print_generic_expr (stderr, ref, 0);
- fprintf (stderr, " may not touch ");
- print_generic_expr (stderr, alias, 0);
- fprintf (stderr, " in function %s\n", get_name (current_function_decl));
-#endif
- return false;
- }
-
- /* Without strict aliasing, it is impossible for a component access
- through a pointer to touch a random variable, unless that
- variable *is* a structure or a pointer.
-
- That is, given p->c, and some random global variable b,
- there is no legal way that p->c could be an access to b.
-
- Without strict aliasing on, we consider it legal to do something
- like:
-
- struct foos { int l; };
- int foo;
- static struct foos *getfoo(void);
- int main (void)
- {
- struct foos *f = getfoo();
- f->l = 1;
- foo = 2;
- if (f->l == 1)
- abort();
- exit(0);
- }
- static struct foos *getfoo(void)
- { return (struct foos *)&foo; }
-
- (taken from 20000623-1.c)
-
- The docs also say/imply that access through union pointers
- is legal (but *not* if you take the address of the union member,
- i.e. the inverse), such that you can do
-
- typedef union {
- int d;
- } U;
-
- int rv;
- void breakme()
- {
- U *rv0;
- U *pretmp = (U*)&rv;
- rv0 = pretmp;
- rv0->d = 42;
- }
- To implement this, we just punt on accesses through union
- pointers entirely.
-
- Another case we have to allow is accessing a variable
- through an array access at offset zero. This happens from
- code generated by the fortran frontend like
-
- char[1:1] & my_char_ref;
- char my_char;
- my_char_ref_1 = (char[1:1] &) &my_char;
- D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};
- */
- else if (ref
- && flag_strict_aliasing
- && TREE_CODE (ref) != INDIRECT_REF
- && !MTAG_P (alias)
- && base
- && (TREE_CODE (base) != INDIRECT_REF
- || TREE_CODE (TREE_TYPE (base)) != UNION_TYPE)
- && (TREE_CODE (base) != INDIRECT_REF
- || TREE_CODE (ref) != ARRAY_REF
- || offset != 0
- || (DECL_SIZE (alias)
- && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST
- && size != -1
- && (unsigned HOST_WIDE_INT)size
- != TREE_INT_CST_LOW (DECL_SIZE (alias))))
- && !AGGREGATE_TYPE_P (TREE_TYPE (alias))
- && TREE_CODE (TREE_TYPE (alias)) != COMPLEX_TYPE
- && !var_ann (alias)->is_heapvar
- /* When the struct has may_alias attached to it, we need not to
- return true. */
- && get_alias_set (base))
- {
-#ifdef ACCESS_DEBUGGING
- fprintf (stderr, "Access to ");
- print_generic_expr (stderr, ref, 0);
- fprintf (stderr, " may not touch ");
- print_generic_expr (stderr, alias, 0);
- fprintf (stderr, " in function %s\n", get_name (current_function_decl));
-#endif
- return false;
- }
-
- /* If the offset of the access is greater than the size of one of
- the possible aliases, it can't be touching that alias, because it
- would be past the end of the structure. */
- else if (ref
- && flag_strict_aliasing
- && TREE_CODE (ref) != INDIRECT_REF
- && !MTAG_P (alias)
- && !POINTER_TYPE_P (TREE_TYPE (alias))
- && offsetgtz
- && DECL_SIZE (alias)
- && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST
- && uoffset > TREE_INT_CST_LOW (DECL_SIZE (alias)))
- {
-#ifdef ACCESS_DEBUGGING
- fprintf (stderr, "Access to ");
- print_generic_expr (stderr, ref, 0);
- fprintf (stderr, " may not touch ");
- print_generic_expr (stderr, alias, 0);
- fprintf (stderr, " in function %s\n", get_name (current_function_decl));
-#endif
- return false;
- }
-
- return true;
-}
-
-
-/* Given an aggregate expression FULL_REF, return the number of
- aggregates that are containing FULL_REF. So, given a structure
- reference a.b.c.d, the nesting level for this expression is 2 (the
- number of '.' in the expression minus 1). */
-
-static unsigned
-ref_nesting_level (tree full_ref)
-{
- unsigned nesting_level = 0;
-
- if (!handled_component_p (full_ref))
- return 0;
-
- full_ref = TREE_OPERAND (full_ref, 0);
- while (handled_component_p (full_ref))
- {
- nesting_level++;
- full_ref = TREE_OPERAND (full_ref, 0);
- }
-
- return nesting_level;
-}
-
-
-/* Add the actual variables FULL_REF can access, given a member of
- FULL_REF's points-to set VAR, where FULL_REF is an access of SIZE at
- OFFSET from var. IS_CALL_SITE is true if this is a call, and IS_DEF
- is true if this is supposed to be a vdef, and false if this should
- be a VUSE.
-
- The real purpose of this function is to take a points-to set for a
- pointer to a structure, say
-
- struct s {
- int a;
- int b;
- } foo, *foop = &foo;
-
- and discover which variables an access, such as foop->b, can alias.
-
- This is necessary because foop only actually points to foo's first
- member, so that is all the points-to set contains. However, an access
- to foop->a may be touching some single SFT if we have created some
- SFT's for a structure.
-
- FULL_REF is the original memory expression being analyzed. */
-
-static bool
-add_vars_for_offset (tree full_ref, tree var, unsigned HOST_WIDE_INT offset,
- unsigned HOST_WIDE_INT size, bool is_def)
-{
- bool added = false;
- tree subvar;
- subvar_t sv;
- unsigned int i;
-
- if (full_ref
- && SFT_NESTING_LEVEL (var) > 0
- && ref_nesting_level (full_ref) < SFT_NESTING_LEVEL (var))
- {
- /* Since VAR is an SFT inside a nested structure, the OFFSET
- computed by get_ref_base_and_extent is the offset from the
- start of the immediately containing structure. If VAR is an
- SFT inside a nested structure, then FULL_REF may be a
- reference to the structure immediately enclosing SFT, and so
- OFFSET will be the offset from the start of the immediately
- enclosing structure.
-
- However, to find out what other SFTs are affected by this
- reference, we need to know the offsets starting at the root
- structure in the nesting hierarchy.
-
- For instance, given the following structure:
-
- struct X {
- int a;
- struct Y {
- int b;
- struct Z {
- int c[3];
- } d;
- } e;
- } m;
-
- and the following address expression:
-
- p_1 = &m.e.d;
-
- This structure will receive 5 SFTs, namely 2 for fields 'a'
- and 'b' and 3 for the array 'c' in struct Z. So, the
- reference p_1->c[2] and m.e.d.c[2] access the exact same
- memory location (ie, SFT.5).
-
- Now, alias analysis computed the points-to set for pointer
- p_1 as { SFT.3 } because that is the first field that p_1
- actually points to. When the expression p_1->c[2] is
- analyzed, get_ref_base_and_extent will return an offset of 96
- because we are accessing the third element of the array. But
- the SFT we are looking for is actually at offset 160,
- counting from the top of struct X.
-
- Therefore, we adjust OFFSET by the offset of VAR so that we
- can get at all the fields starting at VAR. */
- offset += SFT_OFFSET (var);
- }
-
- /* Add all subvars of var that overlap with the access.
- Binary search for the first relevant SFT. */
- sv = get_subvars_for_var (SFT_PARENT_VAR (var));
- if (!get_first_overlapping_subvar (sv, offset, size, &i))
- return false;
-
- for (; VEC_iterate (tree, sv, i, subvar); ++i)
- {
- if (SFT_OFFSET (subvar) > offset
- && size <= SFT_OFFSET (subvar) - offset)
- break;