This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH to improve use of alias sets
- To: egcs-patches at cygnus dot com
- Subject: PATCH to improve use of alias sets
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Tue, 22 Sep 1998 01:08:16 -0700
- Cc: Jeff Law <law at cygnus dot com>, Michael Tiemann <tiemann at cygnus dot com>
- Reply-to: mark at markmitchell dot com
Michael Tiemann provided this example today:
typedef float vec_t;
typedef vec_t vec3_t[3];
typedef struct
{
vec3_t viewoffset;
} ps_t;
typedef struct gc_s
{
ps_t ps;
} gc_t;
struct ed_s
{
struct gc_s *client;
};
typedef struct ed_s ed_t;
void foo1 (ed_t *ent)
{
vec3_t v;
struct gc_s *client;
bar (v);
client = ent->client;
client->ps.viewoffset[0] = v[0];
client->ps.viewoffset[1] = v[1];
client->ps.viewoffset[2] = v[2];
}
void foo2 (ed_t *ent)
{
vec3_t v;
bar (v);
ent->client->ps.viewoffset[0] = v[0];
ent->client->ps.viewoffset[1] = v[1];
ent->client->ps.viewoffset[2] = v[2];
}
Here, the code for `foo1' was better than that for `foo2'; in the
latter `ent->client' was reloaded on each access, despite the fact
that stores into `viewoffset[i]' are to floats, and therefore cannot
possibly affent `ent->client' which is a `struct gs*'.
It turns out that we weren't threading alias sets through to
store_field. This patch fixes this, thereby eliminating the redundant
loads in `foo2', and presumably increasing the usefulness of the
alias-set optimizations. I verified that no new test failures occur
after bootstrapping with this patch on x86-linux-gnu.
At the same time, I tweaked c_get_alias_set a bit; type-punning was
not handled quite right. Also, alias sets for ARRAY_TYPEs were
incorrect; that doesn't matter yet, but might at some point in the
future.
Jeff, OK?
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
Mon Sep 21 12:46:22 1998 Mark Mitchell <mark@markmitchell.com>
* c-common.c (c_get_alias_set): Tighten slightly for FUNCTION_TYPEs
and ARRAY_TYPEs. Tidy up. Improve support for type-punning.
* expr.c (store_field): Add alias_set parameter. Set the
MEM_ALIAS_SET accordingly, if the target is a MEM.
(expand_assignment): Use it.
(store_constructor_field): Pass 0.
(expand_expr): Likewise.
Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.33
diff -c -p -r1.33 c-common.c
*** c-common.c 1998/09/20 23:54:07 1.33
--- c-common.c 1998/09/21 19:48:40
*************** c_get_alias_set (t)
*** 2990,3003 ****
return 0;
type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
! ? t : TREE_TYPE (t);
if (type == error_mark_node)
return 0;
! if (TYPE_ALIAS_SET_KNOWN_P (type))
! /* If we've already calculated the value, just return it. */
! return TYPE_ALIAS_SET (type);
if (TREE_CODE (t) == BIT_FIELD_REF)
/* Perhaps reads and writes to this piece of data alias fields
--- 2990,3002 ----
return 0;
type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
! ? t : TREE_TYPE (t);
if (type == error_mark_node)
return 0;
! /* Deal with special cases first; for certain kinds of references
! we're interested in more than just the type. */
if (TREE_CODE (t) == BIT_FIELD_REF)
/* Perhaps reads and writes to this piece of data alias fields
*************** c_get_alias_set (t)
*** 3005,3010 ****
--- 3004,3010 ----
let's just assume that bitfields can alias everything, which is
the conservative assumption. */
return 0;
+
if (TREE_CODE (t) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE)
/* Permit type-punning when accessing a union, provided the
*************** c_get_alias_set (t)
*** 3014,3026 ****
GCC extension, albeit a common and useful one; the C standard
says that such accesses have implementation-defined behavior. */
return 0;
else if (TYPE_MAIN_VARIANT (type) != type)
! {
! /* The C standard specifically allows aliasing between
! cv-qualified variants of types. */
! TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
! return TYPE_ALIAS_SET (type);
! }
else if (TREE_CODE (type) == INTEGER_TYPE)
{
tree signed_variant;
--- 3014,3029 ----
GCC extension, albeit a common and useful one; the C standard
says that such accesses have implementation-defined behavior. */
return 0;
+
+ /* From here on, only the type matters. */
+
+ if (TYPE_ALIAS_SET_KNOWN_P (type))
+ /* If we've already calculated the value, just return it. */
+ return TYPE_ALIAS_SET (type);
else if (TYPE_MAIN_VARIANT (type) != type)
! /* The C standard specifically allows aliasing between
! cv-qualified variants of types. */
! TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
else if (TREE_CODE (type) == INTEGER_TYPE)
{
tree signed_variant;
*************** c_get_alias_set (t)
*** 3031,3064 ****
signed_variant = signed_type (type);
if (signed_variant != type)
! {
! TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
! return TYPE_ALIAS_SET (type);
! }
else if (signed_variant == signed_char_type_node)
/* The C standard guarantess that any object may be accessed
via an lvalue that has character type. We don't have to
check for unsigned_char_type_node or char_type_node because
we are specifically looking at the signed variant. */
! {
! TYPE_ALIAS_SET (type) = 0;
! return TYPE_ALIAS_SET (type);
! }
}
else if (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
! {
! /* If TYPE is a struct or union type then we're reading or
! writing an entire struct. Thus, we don't know anything about
! aliasing. (In theory, such an access can only alias objects
! whose type is the same as one of the fields, recursively, but
! we don't yet make any use of that information.) */
! TYPE_ALIAS_SET (type) = 0;
! return TYPE_ALIAS_SET (type);
! }
- /* TYPE is something we haven't seen before. Put it in a new alias
- set. */
- TYPE_ALIAS_SET (type) = new_alias_set ();
return TYPE_ALIAS_SET (type);
}
--- 3034,3070 ----
signed_variant = signed_type (type);
if (signed_variant != type)
! TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
else if (signed_variant == signed_char_type_node)
/* The C standard guarantess that any object may be accessed
via an lvalue that has character type. We don't have to
check for unsigned_char_type_node or char_type_node because
we are specifically looking at the signed variant. */
! TYPE_ALIAS_SET (type) = 0;
}
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ /* Anything that can alias one of the array elements can alias
+ the entire array as well. */
+ TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type));
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ /* There are no objects of FUNCTION_TYPE, so there's no point in
+ using up an alias set for them. (There are, of course,
+ pointers and references to functions, but that's
+ different.) */
+ TYPE_ALIAS_SET (type) = 0;
else if (TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
! /* If TYPE is a struct or union type then we're reading or
! writing an entire struct. Thus, we don't know anything about
! aliasing. (In theory, such an access can only alias objects
! whose type is the same as one of the fields, recursively, but
! we don't yet make any use of that information.) */
! TYPE_ALIAS_SET (type) = 0;
!
! if (!TYPE_ALIAS_SET_KNOWN_P (type))
! /* TYPE is something we haven't seen before. Put it in a new
! alias set. */
! TYPE_ALIAS_SET (type) = new_alias_set ();
return TYPE_ALIAS_SET (type);
}
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.96
diff -c -p -r1.96 expr.c
*** expr.c 1998/09/15 19:18:52 1.96
--- expr.c 1998/09/21 19:49:15
*************** static void store_constructor_field PROT
*** 168,174 ****
tree, tree, int));
static void store_constructor PROTO((tree, rtx, int));
static rtx store_field PROTO((rtx, int, int, enum machine_mode, tree,
! enum machine_mode, int, int, int));
static enum memory_use_mode
get_memory_usage_from_modifier PROTO((enum expand_modifier));
static tree save_noncopied_parts PROTO((tree, tree));
--- 168,175 ----
tree, tree, int));
static void store_constructor PROTO((tree, rtx, int));
static rtx store_field PROTO((rtx, int, int, enum machine_mode, tree,
! enum machine_mode, int, int,
! int, int));
static enum memory_use_mode
get_memory_usage_from_modifier PROTO((enum expand_modifier));
static tree save_noncopied_parts PROTO((tree, tree));
*************** expand_assignment (to, from, want_value,
*** 3223,3229 ****
unsignedp,
/* Required alignment of containing datum. */
alignment,
! int_size_in_bytes (TREE_TYPE (tem)));
preserve_temp_slots (result);
free_temp_slots ();
pop_temp_slots ();
--- 3224,3231 ----
unsignedp,
/* Required alignment of containing datum. */
alignment,
! int_size_in_bytes (TREE_TYPE (tem)),
! get_alias_set (to));
preserve_temp_slots (result);
free_temp_slots ();
pop_temp_slots ();
*************** store_constructor_field (target, bitsize
*** 3805,3811 ****
else
store_field (target, bitsize, bitpos, mode, exp,
VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
! int_size_in_bytes (type));
}
/* Store the value of constructor EXP into the rtx TARGET.
--- 3807,3813 ----
else
store_field (target, bitsize, bitpos, mode, exp,
VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
! int_size_in_bytes (type), 0);
}
/* Store the value of constructor EXP into the rtx TARGET.
*************** store_constructor (exp, target, cleared)
*** 4355,4365 ****
In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
ALIGN is the alignment that TARGET is known to have, measured in bytes.
! TOTAL_SIZE is the size in bytes of the structure, or -1 if varying. */
static rtx
store_field (target, bitsize, bitpos, mode, exp, value_mode,
! unsignedp, align, total_size)
rtx target;
int bitsize, bitpos;
enum machine_mode mode;
--- 4357,4371 ----
In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
ALIGN is the alignment that TARGET is known to have, measured in bytes.
! TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.
+ ALIAS_SET is the alias set for the destination. This value will
+ (in general) be different from that for TARGET, since TARGET is a
+ reference to the containing structure. */
+
static rtx
store_field (target, bitsize, bitpos, mode, exp, value_mode,
! unsignedp, align, total_size, alias_set)
rtx target;
int bitsize, bitpos;
enum machine_mode mode;
*************** store_field (target, bitsize, bitpos, mo
*** 4368,4373 ****
--- 4374,4380 ----
int unsignedp;
int align;
int total_size;
+ int alias_set;
{
HOST_WIDE_INT width_mask = 0;
*************** store_field (target, bitsize, bitpos, mo
*** 4403,4409 ****
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
! align, total_size);
/* Even though we aren't returning target, we need to
give it the updated value. */
--- 4410,4416 ----
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
! align, total_size, alias_set);
/* Even though we aren't returning target, we need to
give it the updated value. */
*************** store_field (target, bitsize, bitpos, mo
*** 4518,4523 ****
--- 4525,4531 ----
(bitpos
/ BITS_PER_UNIT))));
MEM_IN_STRUCT_P (to_rtx) = 1;
+ MEM_ALIAS_SET (to_rtx) = alias_set;
return store_expr (exp, to_rtx, value_mode != VOIDmode);
}
*************** expand_expr (exp, target, tmode, modifie
*** 6584,6590 ****
store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, 1,
! int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))));
else
abort ();
--- 6592,6599 ----
store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, 1,
! int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))),
! 0);
else
abort ();