aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
authorJoern Rennecke <amylaar@gcc.gnu.org>2005-08-19 13:25:58 +0100
committerJoern Rennecke <amylaar@gcc.gnu.org>2005-08-19 13:25:58 +0100
commit21bdb106e797193b1d02abcacd6f27bb61bb12ec (patch)
tree2606925fc93394a3c44f139738dadd36a1a6323f /gcc/config/sh
parente27ce37987e028aeba1c9c58d8a93f5e8dbf5da0 (diff)
downloadgcc-21bdb106e797193b1d02abcacd6f27bb61bb12ec.zip
gcc-21bdb106e797193b1d02abcacd6f27bb61bb12ec.tar.gz
gcc-21bdb106e797193b1d02abcacd6f27bb61bb12ec.tar.bz2
sh.c (find_sole_member): New function.
* sh.c (find_sole_member): New function. (sh_gimplify_va_arg_expr): Use it. Allow RECORD_TYPE mode mismatch if the record's alignment is larger than the size of its only member. From-SVN: r103275
Diffstat (limited to 'gcc/config/sh')
-rw-r--r--gcc/config/sh/sh.c42
1 files changed, 32 insertions, 10 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index ed132f6..9d39ac6 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -6632,6 +6632,27 @@ sh_va_start (tree valist, rtx nextarg)
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
+/* TYPE is a RECORD_TYPE. If there is only a single non-zero-sized
+ member, return it. */
+static tree
+find_sole_member (tree type)
+{
+ tree field, member = NULL_TREE;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ if (!DECL_SIZE (field))
+ return NULL_TREE;
+ if (integer_zerop (DECL_SIZE (field)))
+ continue;
+ if (member)
+ return NULL_TREE;
+ member = field;
+ }
+ return member;
+}
/* Implement `va_arg'. */
static tree
@@ -6657,6 +6678,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
int pass_as_float;
tree lab_false;
+ tree member;
f_next_o = TYPE_FIELDS (va_list_type_node);
f_next_o_limit = TREE_CHAIN (f_next_o);
@@ -6679,22 +6701,22 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
like their member. This is relevant if the latter has a REAL_TYPE
or COMPLEX_TYPE type. */
while (TREE_CODE (type) == RECORD_TYPE
- && TYPE_FIELDS (type)
- && TREE_CODE (TYPE_FIELDS (type)) == FIELD_DECL
- && (TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == REAL_TYPE
- || TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == RECORD_TYPE)
- && TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
+ && (member = find_sole_member (type))
+ && (TREE_CODE (TREE_TYPE (member)) == REAL_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE))
{
- tree field_type = TREE_TYPE (TYPE_FIELDS (type));
+ tree field_type = TREE_TYPE (member);
if (TYPE_MODE (type) == TYPE_MODE (field_type))
type = field_type;
else
{
- gcc_assert (TYPE_ALIGN (type)
- < GET_MODE_ALIGNMENT (TYPE_MODE (field_type)));
- break;
+ gcc_assert ((TYPE_ALIGN (type)
+ < GET_MODE_ALIGNMENT (TYPE_MODE (field_type)))
+ || (TYPE_ALIGN (type)
+ > GET_MODE_BITSIZE (TYPE_MODE (field_type))));
+ break;
}
}