aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@gcc.gnu.org>2003-06-27 10:52:03 -0700
committerRichard Henderson <rth@gcc.gnu.org>2003-06-27 10:52:03 -0700
commit7e4fb06a5182286640bf73410d09ab324c5e73ad (patch)
tree49762bdb5dbf79cca9a0994dd11b48b208a92a1e /gcc
parent75d75435b640d134ed3b195e1d3b068bbf1fc6ba (diff)
downloadgcc-7e4fb06a5182286640bf73410d09ab324c5e73ad.zip
gcc-7e4fb06a5182286640bf73410d09ab324c5e73ad.tar.gz
gcc-7e4fb06a5182286640bf73410d09ab324c5e73ad.tar.bz2
alpha.c (function_arg): Don't pass small aggregates in floating point registers.
* config/alpha/alpha.c (function_arg): Don't pass small aggregates in floating point registers. Validate that we don't receive complex values here. Use #elif. (return_in_memory, function_value): New. (alpha_va_arg): Handle complex values as two arguments. * config/alpha/alpha.h (RETURN_IN_MEMORY): Use return_in_memory. (FUNCTION_VALUE, LIBCALL_VALUE): Use function_value. (SPLIT_COMPLEX_ARGS): New. * config/alpha/alpha-protos.h: Update. From-SVN: r68591
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/config/alpha/alpha-protos.h3
-rw-r--r--gcc/config/alpha/alpha.c163
-rw-r--r--gcc/config/alpha/alpha.h27
4 files changed, 174 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a86f0a8..9d71ea6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,4 +1,16 @@
-2003-06-13 Ulrich Weigand <uweigand@de.ibm.com>
+2003-06-27 Richard Henderson <rth@redhat.com>
+
+ * config/alpha/alpha.c (function_arg): Don't pass small aggregates
+ in floating point registers. Validate that we don't receive complex
+ values here. Use #elif.
+ (return_in_memory, function_value): New.
+ (alpha_va_arg): Handle complex values as two arguments.
+ * config/alpha/alpha.h (RETURN_IN_MEMORY): Use return_in_memory.
+ (FUNCTION_VALUE, LIBCALL_VALUE): Use function_value.
+ (SPLIT_COMPLEX_ARGS): New.
+ * config/alpha/alpha-protos.h: Update.
+
+2003-06-27 Ulrich Weigand <uweigand@de.ibm.com>
* ggc-page.c (inverse_table): Change type of mult to size_t.
(compute_inverse): Compute inverse using size_t, not unsigned int.
diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h
index 3a342eb..0e14e6b 100644
--- a/gcc/config/alpha/alpha-protos.h
+++ b/gcc/config/alpha/alpha-protos.h
@@ -135,6 +135,9 @@ extern void alpha_setup_incoming_varargs (CUMULATIVE_ARGS, enum machine_mode,
extern void alpha_va_start (tree, rtx);
extern rtx alpha_va_arg (tree, tree);
extern rtx function_arg (CUMULATIVE_ARGS, enum machine_mode, tree, int);
+extern rtx function_value (tree, tree, enum machine_mode);
+extern bool return_in_memory (tree, enum machine_mode);
+
extern void alpha_start_function (FILE *, const char *, tree);
extern void alpha_end_function (FILE *, const char *, tree);
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 1d1be31d..d1b884f 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -5864,14 +5864,25 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
int basereg;
int num_args;
- /* Set up defaults for FP operands passed in FP registers, and
- integral operands passed in integer registers. */
- if (TARGET_FPREGS
- && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (mode) == MODE_FLOAT))
- basereg = 32 + 16;
- else
+ /* Don't get confused and pass small structures in FP registers. */
+ if (type && AGGREGATE_TYPE_P (type))
basereg = 16;
+ else
+ {
+#ifdef ENABLE_CHECKING
+ /* With SPLIT_COMPLEX_ARGS, we shouldn't see any raw complex
+ values here. */
+ if (COMPLEX_MODE_P (mode))
+ abort ();
+#endif
+
+ /* Set up defaults for FP operands passed in FP registers, and
+ integral operands passed in integer registers. */
+ if (TARGET_FPREGS && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ basereg = 32 + 16;
+ else
+ basereg = 16;
+ }
/* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for
the three platforms, so we can't avoid conditional compilation. */
@@ -5884,8 +5895,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type))
return NULL_RTX;
}
-#else
-#if TARGET_ABI_UNICOSMK
+#elif TARGET_ABI_UNICOSMK
{
int size;
@@ -5949,7 +5959,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
}
}
}
-#else
+#elif TARGET_ABI_OSF
{
if (cum >= 6)
return NULL_RTX;
@@ -5963,12 +5973,119 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named))
basereg = 16;
}
-#endif /* TARGET_ABI_UNICOSMK */
-#endif /* TARGET_ABI_OPEN_VMS */
+#else
+#error Unhandled ABI
+#endif
return gen_rtx_REG (mode, num_args + basereg);
}
+/* Return true if TYPE must be returned in memory, instead of in registers. */
+
+bool
+return_in_memory (tree type, enum machine_mode mode)
+{
+ int size;
+
+ if (type)
+ {
+ mode = TYPE_MODE (type);
+
+ /* All aggregates are returned in memory. */
+ if (AGGREGATE_TYPE_P (type))
+ return true;
+ }
+
+ size = GET_MODE_SIZE (mode);
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_VECTOR_FLOAT:
+ /* Pass all float vectors in memory, like an aggregate. */
+ return true;
+
+ case MODE_COMPLEX_FLOAT:
+ /* We judge complex floats on the size of their element,
+ not the size of the whole type. */
+ size = GET_MODE_UNIT_SIZE (mode);
+ break;
+
+ case MODE_INT:
+ case MODE_FLOAT:
+ case MODE_COMPLEX_INT:
+ case MODE_VECTOR_INT:
+ break;
+
+ default:
+ /* ??? We get called on all sorts of random stuff from
+ aggregate_value_p. We can't abort, but it's not clear
+ what's safe to return. Pretend it's a struct I guess. */
+ return true;
+ }
+
+ /* Otherwise types must fit in one register. */
+ return size > UNITS_PER_WORD;
+}
+
+/* Define how to find the value returned by a function. VALTYPE is the
+ data type of the value (as a tree). If the precise function being
+ called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0.
+ MODE is set instead of VALTYPE for libcalls.
+
+ On Alpha the value is found in $0 for integer functions and
+ $f0 for floating-point functions. */
+
+rtx
+function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ unsigned int regnum;
+ enum mode_class class;
+
+#ifdef ENABLE_CHECKING
+ if (return_in_memory (valtype, mode))
+ abort ();
+#endif
+
+ if (valtype)
+ mode = TYPE_MODE (valtype);
+
+ class = GET_MODE_CLASS (mode);
+ switch (class)
+ {
+ case MODE_INT:
+ /* Do the same thing as PROMOTE_MODE. */
+ mode = DImode;
+ /* FALLTHRU */
+
+ case MODE_COMPLEX_INT:
+ case MODE_VECTOR_INT:
+ regnum = 0;
+ break;
+
+ case MODE_FLOAT:
+ regnum = 32;
+ break;
+
+ case MODE_COMPLEX_FLOAT:
+ {
+ enum machine_mode cmode = GET_MODE_INNER (mode);
+
+ return gen_rtx_PARALLEL
+ (VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32),
+ GEN_INT (0)),
+ gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33),
+ GEN_INT (GET_MODE_SIZE (cmode)))));
+ }
+
+ default:
+ abort ();
+ }
+
+ return gen_rtx_REG (mode, regnum);
+}
+
tree
alpha_build_va_list (void)
{
@@ -6162,7 +6279,27 @@ alpha_va_arg (tree valist, tree type)
indirect = 1;
rounded_size = size_int (UNITS_PER_WORD);
}
- else if (FLOAT_TYPE_P (type))
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ rtx real_part, imag_part, value, tmp;
+
+ real_part = alpha_va_arg (valist, TREE_TYPE (type));
+ imag_part = alpha_va_arg (valist, TREE_TYPE (type));
+
+ /* ??? Most irritatingly, we're not returning the value here,
+ but the address. Since real_part and imag_part are not
+ necessarily contiguous, we must copy to local storage. */
+
+ real_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), real_part);
+ imag_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), imag_part);
+ value = gen_rtx_CONCAT (TYPE_MODE (type), real_part, imag_part);
+
+ tmp = assign_temp (type, 0, 1, 0);
+ emit_move_insn (tmp, value);
+
+ return XEXP (tmp, 0);
+ }
+ else if (TREE_CODE (type) == REAL_TYPE)
{
tree fpaddend, cond;
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 7ba7b15..267d292 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -994,25 +994,14 @@ extern int alpha_memory_latency;
On Alpha the value is found in $0 for integer functions and
$f0 for floating-point functions. */
-#define FUNCTION_VALUE(VALTYPE, FUNC) \
- gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
- && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
- || POINTER_TYPE_P (VALTYPE)) \
- ? word_mode : TYPE_MODE (VALTYPE), \
- ((TARGET_FPREGS \
- && (TREE_CODE (VALTYPE) == REAL_TYPE \
- || TREE_CODE (VALTYPE) == COMPLEX_TYPE)) \
- ? 32 : 0))
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ function_value (VALTYPE, FUNC, VOIDmode)
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
-#define LIBCALL_VALUE(MODE) \
- gen_rtx_REG (MODE, \
- (TARGET_FPREGS \
- && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
- || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
- ? 32 : 0))
+#define LIBCALL_VALUE(MODE) \
+ function_value (NULL, NULL, MODE)
/* The definition of this macro implies that there are cases where
a scalar value cannot be returned in registers.
@@ -1021,10 +1010,7 @@ extern int alpha_memory_latency;
are integers whose size is larger than 64 bits. */
#define RETURN_IN_MEMORY(TYPE) \
- (TYPE_MODE (TYPE) == BLKmode \
- || TYPE_MODE (TYPE) == TFmode \
- || TYPE_MODE (TYPE) == TCmode \
- || (TREE_CODE (TYPE) == INTEGER_TYPE && TYPE_PRECISION (TYPE) > 64))
+ return_in_memory (TYPE, VOIDmode)
/* 1 if N is a possible register number for a function value
as seen by the caller. */
@@ -1889,3 +1875,6 @@ do { \
/* Generate calls to memcpy, etc., not bcopy, etc. */
#define TARGET_MEM_FUNCTIONS 1
+
+/* Pass complex arguments independently. */
+#define SPLIT_COMPLEX_ARGS 1