summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/cfgexpand.c6
-rw-r--r--gcc/config/i386/i386-protos.h2
-rw-r--r--gcc/config/i386/i386.c35
-rw-r--r--gcc/config/i386/i386.h9
-rw-r--r--gcc/defaults.h4
-rw-r--r--gcc/doc/tm.texi8
-rw-r--r--gcc/emit-rtl.c6
-rw-r--r--gcc/function.c6
9 files changed, 84 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 17bb0cd6962..f3d298e7ea3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,17 @@
2009-07-11 Jakub Jelinek <jakub@redhat.com>
+ PR rtl-optimization/40667
+ * defaults.h (MINIMUM_ALIGNMENT): Define if not defined.
+ * doc/tm.texi (MINIMUM_ALIGNMENT): Document it.
+ * config/i386/i386.h (MINIMUM_ALIGNMENT): Define.
+ * config/i386/i386.c (ix86_minimum_alignment): New function.
+ * config/i386/i386-protos.h (ix86_minimum_alignment): New prototype.
+ * cfgexpand.c (expand_one_var): Use MINIMIM_ALIGNMENT.
+ * emit-rtl.c (gen_reg_rtx): Likewise.
+ * function.c (assign_parms): Likewise. If nominal_type needs
+ bigger alignment than FUNCTION_ARG_BOUNDARY, use its alignment
+ rather than passed_type's alignment.
+
PR target/40668
* function.c (assign_parm_setup_stack): Adjust
MEM_OFFSET (data->stack_parm) if promoted_mode is different
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 62b5c4515d1..c8d19fb19e2 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1164,9 +1164,11 @@ expand_one_var (tree var, bool toplevel, bool really_expand)
variables, which won't be on stack, we collect alignment of
type and ignore user specified alignment. */
if (TREE_STATIC (var) || DECL_EXTERNAL (var))
- align = TYPE_ALIGN (TREE_TYPE (var));
+ align = MINIMUM_ALIGNMENT (TREE_TYPE (var),
+ TYPE_MODE (TREE_TYPE (var)),
+ TYPE_ALIGN (TREE_TYPE (var)));
else
- align = DECL_ALIGN (var);
+ align = MINIMUM_ALIGNMENT (var, DECL_MODE (var), DECL_ALIGN (var));
if (crtl->stack_alignment_estimated < align)
{
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index d1d601a6a67..2e92219de0f 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -199,6 +199,8 @@ extern int ix86_return_pops_args (tree, tree, int);
extern int ix86_data_alignment (tree, int);
extern unsigned int ix86_local_alignment (tree, enum machine_mode,
unsigned int);
+extern unsigned int ix86_minimum_alignment (tree, enum machine_mode,
+ unsigned int);
extern int ix86_constant_alignment (tree, int);
extern tree ix86_handle_shared_attribute (tree *, tree, tree, int, bool *);
extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 684403136ce..f05eb5c74c8 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -20087,6 +20087,41 @@ ix86_local_alignment (tree exp, enum machine_mode mode,
}
return align;
}
+
+/* Compute the minimum required alignment for dynamic stack realignment
+ purposes for a local variable, parameter or a stack slot. EXP is
+ the data type or decl itself, MODE is its mode and ALIGN is the
+ alignment that the object would ordinarily have. */
+
+unsigned int
+ix86_minimum_alignment (tree exp, enum machine_mode mode,
+ unsigned int align)
+{
+ tree type, decl;
+
+ if (TARGET_64BIT || align != 64 || ix86_preferred_stack_boundary >= 64)
+ return align;
+
+ if (exp && DECL_P (exp))
+ {
+ type = TREE_TYPE (exp);
+ decl = exp;
+ }
+ else
+ {
+ type = exp;
+ decl = NULL;
+ }
+
+ /* Don't do dynamic stack realignment for long long objects with
+ -mpreferred-stack-boundary=2. */
+ if ((mode == DImode || (type && TYPE_MODE (type) == DImode))
+ && (!type || !TYPE_USER_ALIGN (type))
+ && (!decl || !DECL_USER_ALIGN (decl)))
+ return 32;
+
+ return align;
+}
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 97483b7cf36..f9b9dd17803 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -831,6 +831,15 @@ enum target_cpu_default
#define LOCAL_DECL_ALIGNMENT(DECL) \
ix86_local_alignment ((DECL), VOIDmode, DECL_ALIGN (DECL))
+/* If defined, a C expression to compute the minimum required alignment
+ for dynamic stack realignment purposes for EXP (a TYPE or DECL),
+ MODE, assuming normal alignment ALIGN.
+
+ If this macro is not defined, then (ALIGN) will be used. */
+
+#define MINIMUM_ALIGNMENT(EXP, MODE, ALIGN) \
+ ix86_minimum_alignment (EXP, MODE, ALIGN)
+
/* If defined, a C expression that gives the alignment boundary, in
bits, of an argument with the specified mode and type. If it is
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 11873a8c8a5..b6cec4b249b 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1138,6 +1138,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
LOCAL_ALIGNMENT (TREE_TYPE (DECL), DECL_ALIGN (DECL))
#endif
+#ifndef MINIMUM_ALIGNMENT
+#define MINIMUM_ALIGNMENT(EXP,MODE,ALIGN) (ALIGN)
+#endif
+
/* Alignment value for attribute ((aligned)). */
#ifndef ATTRIBUTE_ALIGNED_VALUE
#define ATTRIBUTE_ALIGNED_VALUE BIGGEST_ALIGNMENT
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index e328210385c..41ed0317521 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1227,6 +1227,14 @@ One use of this macro is to increase alignment of medium-size data to
make it all fit in fewer cache lines.
@end defmac
+@defmac MINIMUM_ALIGNMENT (@var{exp}, @var{mode}, @var{align})
+If defined, a C expression to compute the minimum required alignment
+for dynamic stack realignment purposes for @var{exp} (a type or decl),
+@var{mode}, assuming normal alignment @var{align}.
+
+If this macro is not defined, then @var{align} will be used.
+@end defmac
+
@defmac EMPTY_FIELD_BOUNDARY
Alignment in bits to be given to a structure bit-field that follows an
empty field such as @code{int : 0;}.
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index df2b4b749b3..d20f2b55273 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -869,7 +869,11 @@ gen_reg_rtx (enum machine_mode mode)
if (SUPPORTS_STACK_ALIGNMENT
&& crtl->stack_alignment_estimated < align
&& !crtl->stack_realign_processed)
- crtl->stack_alignment_estimated = align;
+ {
+ unsigned int min_align = MINIMUM_ALIGNMENT (NULL, mode, align);
+ if (crtl->stack_alignment_estimated < min_align)
+ crtl->stack_alignment_estimated = min_align;
+ }
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
diff --git a/gcc/function.c b/gcc/function.c
index 258f5941950..e31c12ada35 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3146,8 +3146,12 @@ assign_parms (tree fndecl)
{
unsigned int align = FUNCTION_ARG_BOUNDARY (data.promoted_mode,
data.passed_type);
+ align = MINIMUM_ALIGNMENT (data.passed_type, data.promoted_mode,
+ align);
if (TYPE_ALIGN (data.nominal_type) > align)
- align = TYPE_ALIGN (data.passed_type);
+ align = MINIMUM_ALIGNMENT (data.nominal_type,
+ TYPE_MODE (data.nominal_type),
+ TYPE_ALIGN (data.nominal_type));
if (crtl->stack_alignment_estimated < align)
{
gcc_assert (!crtl->stack_realign_processed);