From: Weiwen Liu <weiwen.liu@yale.edu>
To: egcs@cygnus.com
Subject: Patch for COMPLEX support (part 2)
Date: Tue, 10 Feb 1998 03:34:00 -0000 [thread overview]
Message-ID: <Pine.OSF.3.96.980107191012.10607C-100000@ylws39> (raw)
Wed Jan 7 17:30:00 1998 Weiwen Liu <liu@hepunix.physics.yale.edu>
* machmode.h: define COMPLEX_MODE_P, COMPLEX_SUBMODE.
* regs.h (REG_SIZE): Consider complex modes.
* calls.c (arg_data): Add partial_real and partial_imag to
record the number of registers used for real/imaginary part.
* combine.c (expand_field_assignment): Exclude SUBREG of a
COMPLEX.
* explow.c (hard_function_value): Promote COMPLEX return
value if required.
* calls.c (expand_call): Deal with arguments of complex modes.
(store_one_arg): Likewise.
* emit-rtl.c (gen_lowpart_common): Likewise.
(gen_highpart): Likewise.
* expr.c (store_expr): Likewise.
(expand_expr): Likewise.
* function.c (aggregate_value_p): Likewise.
(assign_parms): Likewise.
(locate_and_pad_parm): Likewise.
(expand_function_start): Likewise.
* integrate.c (expand_inline_function): Likewise.
* reload.c (find_reloads): Likewise.
* stmt.c (expand_value_return): Likewise.
--- gcc/calls.c.orig Wed Dec 24 16:39:40 1997
+++ gcc/calls.c Wed Jan 7 10:57:01 1998
@@ -71,6 +71,10 @@ struct arg_data
/* Number of registers to use. 0 means put the whole arg in registers.
Also 0 if not passed in registers. */
int partial;
+ /* Number of registers to use for real part. */
+ int partial_real;
+ /* Number of registers to use for imaginary part. */
+ int partial_imag;
/* Non-zero if argument must be passed on stack.
Note that some arguments may be passed on the stack
even though pass_on_stack is zero, just because FUNCTION_ARG says so.
@@ -1012,7 +1016,9 @@ expand_call (exp, target, ignore)
tree type = TREE_TYPE (TREE_VALUE (p));
int unsignedp;
enum machine_mode mode;
-
+ enum machine_mode submode;
+ tree subtype;
+
args[i].tree_value = TREE_VALUE (p);
/* Replace erroneous argument with constant zero. */
@@ -1044,8 +1050,13 @@ expand_call (exp, target, ignore)
&& contains_placeholder_p (TYPE_SIZE (type)))
|| TREE_ADDRESSABLE (type)
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
- || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),
- type, argpos < n_named_args)
+ || FUNCTION_ARG_PASS_BY_REFERENCE
+ (args_so_far,
+ (! COMPLEX_MODE_P (TYPE_MODE (type)))?
+ TYPE_MODE (type) : COMPLEX_SUBMODE (TYPE_MODE (type)),
+ (! COMPLEX_MODE_P (TYPE_MODE (type)))?
+ type : type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0),
+ argpos < n_named_args)
#endif
)
{
@@ -1053,8 +1064,14 @@ expand_call (exp, target, ignore)
references instead of making a copy. */
if (current_function_is_thunk
#ifdef FUNCTION_ARG_CALLEE_COPIES
- || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
- type, argpos < n_named_args)
+ || (FUNCTION_ARG_CALLEE_COPIES
+ (args_so_far,
+ COMPLEX_MODE_P (TYPE_MODE (type))?
+ COMPLEX_SUBMODE (TYPE_MODE (type)) : TYPE_MODE (type),
+ COMPLEX_MODE_P (TYPE_MODE (type))?
+ type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0)
+ : type,
+ argpos < n_named_args)
/* If it's in a register, we must make a copy of it too. */
/* ??? Is this a sufficient test? Is there a better one? */
&& !(TREE_CODE (args[i].tree_value) == VAR_DECL
@@ -1117,21 +1134,81 @@ expand_call (exp, target, ignore)
mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
-
+ if (COMPLEX_MODE_P (mode))
+ {
+ submode = COMPLEX_SUBMODE (mode);
+ subtype = type_for_mode (submode, unsignedp);
+ }
+
#ifdef PROMOTE_FUNCTION_ARGS
- mode = promote_mode (type, mode, &unsignedp, 1);
+ if (! COMPLEX_MODE_P (mode))
+ {
+ mode = promote_mode (type, mode, &unsignedp, 1);
+ }
+ else
+ {
+ submode = promote_mode (subtype, submode, &unsignedp, 1);
+ subtype = type_for_mode (submode, unsignedp);
+ mode = mode_for_size (2 * GET_MODE_SIZE (submode) * BITS_PER_UNIT,
+ GET_MODE_CLASS (mode), 0);
+ }
#endif
args[i].unsignedp = unsignedp;
args[i].mode = mode;
- args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
- argpos < n_named_args);
+ if (! COMPLEX_MODE_P (mode))
+ {
+ args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
+ argpos < n_named_args);
#ifdef FUNCTION_ARG_PARTIAL_NREGS
- if (args[i].reg)
- args[i].partial
- = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
- argpos < n_named_args);
+ if (args[i].reg)
+ args[i].partial
+ = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
+ argpos < n_named_args);
#endif
+ /* Increment ARGS_SO_FAR, which has info about which arg-registers
+ have been used, etc. */
+ FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
+ argpos < n_named_args);
+ }
+ else
+ {
+ rtx realpart;
+ rtx imagpart;
+
+ realpart = FUNCTION_ARG (args_so_far, submode, subtype,
+ argpos < n_named_args);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+ args[i].partial_real = 0;
+ if (realpart)
+ {
+ args[i].partial_real
+ = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode, subtype,
+ argpos < n_named_args);
+ args[i].partial = args[i].partial_real;
+ }
+#endif
+ FUNCTION_ARG_ADVANCE (args_so_far, submode,
+ type, argpos < n_named_args);
+ imagpart = FUNCTION_ARG (args_so_far, submode, subtype,
+ argpos < n_named_args);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+ args[i].partial_imag = 0;
+ if (imagpart)
+ {
+ args[i].partial_imag
+ = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode, subtype,
+ argpos < n_named_args);
+ args[i].partial = args[i].partial_imag;
+ }
+#endif
+ FUNCTION_ARG_ADVANCE (args_so_far, submode,
+ type, argpos < n_named_args);
+ if (realpart != 0)
+ args[i].reg = gen_rtx (CONCAT, mode, realpart, imagpart);
+ else
+ args[i].reg = 0;
+ }
args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
@@ -1158,19 +1235,45 @@ expand_call (exp, target, ignore)
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
+ /* Allocate stack for a complex argument if its real part is
+ passed in register and its imaginary part is not. */
+ || (COMPLEX_MODE_P (mode) && XEXP (args[i].reg, 1) == 0)
#ifdef REG_PARM_STACK_SPACE
|| reg_parm_stack_space > 0
#endif
|| args[i].pass_on_stack)
- locate_and_pad_parm (mode, type,
+ {
+ enum machine_mode passed_mode = mode;
+ tree passed_type = type;
+ rtx reg = args[i].reg;
+
+ if (COMPLEX_MODE_P (mode) && args[i].reg != 0
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+ && REG_PARM_STACK_SPACE (fndecl) == 0
+#endif
+ )
+ {
+ /* If we do not need to allocate stack space for
+ arguments passing in register, and the real part
+ of a complex argument is passing in register,
+ we only allocate stack space for the imaginary part. */
+ if (XEXP (args[i].reg, 0) != 0 && args[i].partial_real == 0)
+ {
+ passed_mode = submode;
+ passed_type = subtype;
+ reg = XEXP (args[i].reg, 1);
+ }
+ }
+ locate_and_pad_parm (passed_mode, passed_type,
#ifdef STACK_PARMS_IN_REG_PARM_AREA
- 1,
+ 1,
#else
- args[i].reg != 0,
+ reg != 0,
#endif
- fndecl, &args_size, &args[i].offset,
- &args[i].size);
-
+ fndecl, &args_size, &args[i].offset,
+ &args[i].size);
+ }
+
#ifndef ARGS_GROW_DOWNWARD
args[i].slot_offset = args_size;
#endif
@@ -1203,12 +1306,6 @@ expand_call (exp, target, ignore)
SUB_PARM_SIZE (args[i].slot_offset, args_size.var);
}
#endif
-
- /* Increment ARGS_SO_FAR, which has info about which arg-registers
- have been used, etc. */
-
- FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
- argpos < n_named_args);
}
#ifdef FINAL_REG_PARM_STACK_SPACE
@@ -1375,10 +1472,33 @@ expand_call (exp, target, ignore)
= protect_from_queue (args[i].initial_value, 0);
if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
- args[i].value
- = convert_modes (args[i].mode,
- TYPE_MODE (TREE_TYPE (args[i].tree_value)),
- args[i].value, args[i].unsignedp);
+ {
+ if (! COMPLEX_MODE_P (args[i].mode))
+ args[i].value
+ = convert_modes (args[i].mode,
+ TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+ args[i].value, args[i].unsignedp);
+ else
+ {
+ enum machine_mode submode_orig
+ = COMPLEX_SUBMODE (TYPE_MODE
+ (TREE_TYPE (args[i].tree_value)));
+ enum machine_mode submode_final
+ = COMPLEX_SUBMODE (args[i].mode);
+ rtx realpart;
+ rtx imagpart;
+ realpart = convert_modes (submode_final, submode_orig,
+ gen_realpart (submode_orig,
+ args[i].value),
+ args[i].unsignedp);
+ imagpart = convert_modes (submode_final, submode_orig,
+ gen_imagpart (submode_orig,
+ args[i].value),
+ args[i].unsignedp);
+ args[i].value = gen_rtx (CONCAT, args[i].mode,
+ realpart, imagpart);
+ }
+ }
}
/* Now we are about to start emitting insns that can be deleted
@@ -1665,10 +1785,33 @@ expand_call (exp, target, ignore)
do it now. */
if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value)))
- args[i].value
- = convert_modes (args[i].mode,
- TYPE_MODE (TREE_TYPE (args[i].tree_value)),
- args[i].value, args[i].unsignedp);
+ {
+ if (! COMPLEX_MODE_P (args[i].mode))
+ args[i].value
+ = convert_modes (args[i].mode,
+ TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+ args[i].value, args[i].unsignedp);
+ else
+ {
+ enum machine_mode submode_orig
+ = COMPLEX_SUBMODE (TYPE_MODE
+ (TREE_TYPE (args[i].tree_value)));
+ enum machine_mode submode_final
+ = COMPLEX_SUBMODE (args[i].mode);
+ rtx realpart;
+ rtx imagpart;
+ realpart = convert_modes (submode_final, submode_orig,
+ gen_realpart (submode_orig,
+ args[i].value),
+ args[i].unsignedp);
+ imagpart = convert_modes (submode_final, submode_orig,
+ gen_imagpart (submode_orig,
+ args[i].value),
+ args[i].unsignedp);
+ args[i].value = gen_rtx (CONCAT, args[i].mode,
+ realpart, imagpart);
+ }
+ }
/* If the value is expensive, and we are inside an appropriately
short loop, put the value into a pseudo and then put the pseudo
@@ -1758,7 +1901,12 @@ expand_call (exp, target, ignore)
but we do preallocate space here if they want that. */
for (i = 0; i < num_actuals; i++)
- if (args[i].reg == 0 || args[i].pass_on_stack)
+ if (args[i].reg == 0 || args[i].pass_on_stack
+ /* Deal with the imaginary part of a complex argument
+ that is passed in stack. */
+ || (COMPLEX_MODE_P (args[i].mode)
+ && args[i].reg != 0 && args[i].partial == 0
+ && XEXP (args[i].reg, 1) == 0))
store_one_arg (&args[i], argblock, may_be_alloca,
args_size.var != 0, fndecl, reg_parm_stack_space);
@@ -1919,8 +2067,22 @@ expand_call (exp, target, ignore)
load the register(s) from memory. */
else if (nregs == -1)
- emit_move_insn (reg, args[i].value);
-
+ {
+ if (GET_CODE (reg) != CONCAT)
+ emit_move_insn (reg, args[i].value);
+ else
+ {
+ enum machine_mode submode
+ = COMPLEX_SUBMODE (args[i].value->mode);
+ if (XEXP (reg, 0))
+ emit_move_insn (XEXP (reg, 0),
+ gen_realpart (submode, args[i].value));
+ if (XEXP (reg, 1))
+ emit_move_insn (XEXP (reg, 1),
+ gen_imagpart (submode, args[i].value));
+ }
+ }
+
/* If we have pre-computed the values to put in the registers in
the case of non-aligned structures, copy them in now. */
@@ -1939,9 +2101,31 @@ expand_call (exp, target, ignore)
if (GET_CODE (reg) == PARALLEL)
use_group_regs (&call_fusage, reg);
else if (nregs == -1)
- use_reg (&call_fusage, reg);
+ {
+ if (GET_CODE (reg) != CONCAT)
+ use_reg (&call_fusage, reg);
+ else
+ {
+ if (XEXP (reg, 0))
+ use_reg (&call_fusage, XEXP (reg, 0));
+ if (XEXP (reg, 1))
+ use_reg (&call_fusage, XEXP (reg, 1));
+ }
+ }
else
- use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+ {
+ if (GET_CODE (reg) != CONCAT)
+ use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
+ else
+ {
+ if (args[i].partial_real)
+ use_regs (&call_fusage, REGNO (XEXP (reg, 0)),
+ args[i].partial_real);
+ else
+ use_regs (&call_fusage, REGNO (XEXP (reg, 1)),
+ args[i].partial_imag);
+ }
+ }
}
}
@@ -2193,6 +2377,41 @@ expand_call (exp, target, ignore)
SUBREG_PROMOTED_VAR_P (target) = 1;
SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
}
+ else if (GET_CODE (target) == CONCAT
+ && GET_CODE (XEXP (target, 0)) == REG
+ && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
+ && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+ {
+ tree type = TREE_TYPE (exp);
+ int unsignedp = TREE_UNSIGNED (type);
+ enum machine_mode submode_orig = COMPLEX_SUBMODE (TYPE_MODE (type));
+ enum machine_mode submode_final;
+ enum machine_mode promoted_mode;
+ rtx realpart;
+ rtx imagpart;
+
+ submode_final = promote_mode (type_for_mode (submode_orig, unsignedp),
+ submode_orig, &unsignedp, 1);
+ promoted_mode = mode_for_size (2 * GET_MODE_SIZE (submode_final)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (GET_MODE (target)), 0);
+
+ /* If we don't promote as expected, something is wrong. */
+ if (GET_MODE (target) != promoted_mode )
+ abort ();
+
+ realpart = gen_rtx (SUBREG, submode_orig,
+ gen_realpart (submode_final, target), 0);
+ SUBREG_PROMOTED_VAR_P (realpart) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (realpart) = unsignedp;
+
+ imagpart = gen_rtx (SUBREG, submode_orig,
+ gen_imagpart (submode_final, target), 0);
+ SUBREG_PROMOTED_VAR_P (imagpart) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (imagpart) = unsignedp;
+
+ target = gen_rtx (CONCAT, TYPE_MODE (type), realpart, imagpart);
+ }
#endif
/* If size of args is variable or this was a constructor call for a stack
@@ -3512,8 +3737,13 @@ store_one_arg (arg, argblock, may_be_all
/* If this isn't going to be placed on both the stack and in registers,
set up the register and number of words. */
if (! arg->pass_on_stack)
- reg = arg->reg, partial = arg->partial;
-
+ {
+ reg = arg->reg, partial = arg->partial;
+ if (reg && COMPLEX_MODE_P (reg->mode) && partial == 0)
+ /* Deal with the imaginary part passing in stack. */
+ reg = 0;
+ }
+
if (reg != 0 && partial == 0)
/* Being passed entirely in a register. We shouldn't be called in
this case. */
@@ -3560,8 +3790,31 @@ store_one_arg (arg, argblock, may_be_all
doesn't agree, convert the mode. */
if (arg->mode != TYPE_MODE (TREE_TYPE (pval)))
- arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
- arg->value, arg->unsignedp);
+ {
+ if (! COMPLEX_MODE_P (arg->mode))
+ arg->value
+ = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
+ arg->value, arg->unsignedp);
+ else
+ {
+ enum machine_mode submode_orig
+ = COMPLEX_SUBMODE (TYPE_MODE (TREE_TYPE (pval)));
+ enum machine_mode submode_final
+ = COMPLEX_SUBMODE (arg->mode);
+ rtx realpart;
+ rtx imagpart;
+ realpart = convert_modes (submode_final, submode_orig,
+ gen_realpart (submode_orig,
+ arg->value),
+ arg->unsignedp);
+ imagpart = convert_modes (submode_final, submode_orig,
+ gen_imagpart (submode_orig,
+ arg->value),
+ arg->unsignedp);
+ arg->value = gen_rtx (CONCAT, arg->mode,
+ realpart, imagpart);
+ }
+ }
#ifdef ACCUMULATE_OUTGOING_ARGS
if (arg->pass_on_stack)
@@ -3593,6 +3846,11 @@ store_one_arg (arg, argblock, may_be_all
else if (arg->mode != BLKmode)
{
register int size;
+ enum machine_mode mode
+ = (!COMPLEX_MODE_P (arg->mode)) ?
+ arg->mode : COMPLEX_SUBMODE (arg->mode);
+ tree type = (!COMPLEX_MODE_P (arg->mode))?
+ TREE_TYPE (pval) : TREE_TYPE (TREE_TYPE (pval));
/* Argument is a scalar, not entirely passed in registers.
(If part is passed in registers, arg->partial says how much
@@ -3604,7 +3862,7 @@ store_one_arg (arg, argblock, may_be_all
Note that in C the default argument promotions
will prevent such mismatches. */
- size = GET_MODE_SIZE (arg->mode);
+ size = GET_MODE_SIZE (mode);
/* Compute how much space the push instruction will push.
On many machines, pushing a byte will advance the stack
pointer by a halfword. */
@@ -3615,16 +3873,57 @@ store_one_arg (arg, argblock, may_be_all
/* Compute how much space the argument should get:
round up to a multiple of the alignment for arguments. */
- if (none != FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)))
+ if (none != FUNCTION_ARG_PADDING (mode, type))
used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
/ (PARM_BOUNDARY / BITS_PER_UNIT))
* (PARM_BOUNDARY / BITS_PER_UNIT));
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
- 0, partial, reg, used - size,
- argblock, ARGS_SIZE_RTX (arg->offset));
+ if (! COMPLEX_MODE_P (arg->mode))
+ emit_push_insn (arg->value, arg->mode, type, NULL_RTX,
+ 0, partial, reg, used - size,
+ argblock, ARGS_SIZE_RTX (arg->offset));
+ else
+ {
+ struct args_size offset;
+ offset.constant = arg->offset.constant;
+ offset.var = arg->offset.var;
+ if (arg->partial_real > 0
+ || arg->reg == 0
+ || XEXP (arg->reg, 0) == 0)
+ emit_push_insn (gen_realpart (mode, arg->value),
+ mode, type, NULL_RTX,
+ 0, arg->partial_real,
+ reg ? XEXP (arg->reg, 0) : reg, used - size,
+ argblock, ARGS_SIZE_RTX (offset));
+
+ if (!(arg->reg
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+ && REG_PARM_STACK_SPACE (fndecl) == 0
+#endif
+ && XEXP (arg->reg, 0) != 0 && arg->partial_real == 0)
+#ifdef ARGS_GROW_DOWNWARD
+ /* If the real part is passing in register, the imaginary
+ part in stack only, and ARGS_GROW_DOWNWARD is defined,
+ allocate the stack space for the imaginary part close to
+ next argument. */
+ && !(arg->reg
+ && XEXP (arg->reg, 0) != 0 && arg->partial_real == 0
+ && (XEXP (arg->reg, 1) == 0 || arg->partial_imag > 0))
+#endif
+ )
+ offset.constant += arg->size.constant / 2;
+
+ if (arg->partial_imag > 0
+ || arg->reg == 0
+ || XEXP (arg->reg, 1) == 0)
+ emit_push_insn (gen_imagpart (mode, arg->value),
+ mode, type, NULL_RTX,
+ 0, arg->partial_imag,
+ reg ? XEXP (arg->reg, 1) : reg, used - size,
+ argblock, ARGS_SIZE_RTX (offset));
+ }
}
else
{
@@ -3666,7 +3965,10 @@ store_one_arg (arg, argblock, may_be_all
??? Note that this can change arg->value from arg->stack to
arg->stack_slot and it matters when they are not the same.
It isn't totally clear that this is correct in all cases. */
- if (partial == 0)
+ if (partial == 0
+ /* Do not include the case where the real/imaginary part is
+ not partially in register. */
+ && arg->reg == 0)
arg->value = arg->stack_slot;
/* Once we have pushed something, pops can't safely
--- gcc/combine.c.orig Sat Dec 20 06:31:23 1997
+++ gcc/combine.c Tue Jan 6 17:26:53 1998
@@ -5297,8 +5297,10 @@ expand_field_assignment (x)
}
/* A SUBREG between two modes that occupy the same numbers of words
- can be done by moving the SUBREG to the source. */
+ can be done by moving the SUBREG to the source.
+ But a SUBREG of a COMPLEX should not be done. */
else if (GET_CODE (SET_DEST (x)) == SUBREG
+ && ! COMPLEX_MODE_P (GET_MODE (SUBREG_REG (SET_DEST (x))))
&& (((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
--- gcc/emit-rtl.c.orig Sat Dec 20 06:31:27 1997
+++ gcc/emit-rtl.c Tue Jan 6 17:42:46 1998
@@ -499,8 +499,7 @@ gen_reg_rtx (mode)
if (reload_in_progress || reload_completed)
abort ();
- if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
+ if (COMPLEX_MODE_P (mode))
{
/* For complex modes, don't make a single pseudo.
Instead, make a CONCAT of two pseudos.
@@ -637,10 +636,16 @@ gen_lowpart_common (mode, x)
/ UNITS_PER_WORD)))
return 0;
- if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
- word = ((GET_MODE_SIZE (GET_MODE (x))
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD);
+ if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > 0)
+ {
+ if (!COMPLEX_MODE_P (GET_MODE (x)))
+ word = ((GET_MODE_SIZE (GET_MODE (x))
+ - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ / UNITS_PER_WORD);
+ else
+ word = 2 * HARD_REGNO_NREGS (REGNO (x), COMPLEX_SUBMODE (GET_MODE (x)))
+ - HARD_REGNO_NREGS (REGNO (x), mode);
+ }
if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
&& (GET_MODE_CLASS (mode) == MODE_INT
@@ -1017,10 +1022,17 @@ gen_highpart (mode, x)
int word = 0;
if (! WORDS_BIG_ENDIAN
- && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
- word = ((GET_MODE_SIZE (GET_MODE (x))
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD);
+ && GET_MODE_SIZE (GET_MODE (x)) > 0)
+ {
+ if (!COMPLEX_MODE_P (GET_MODE (x)))
+ word = ((GET_MODE_SIZE (GET_MODE (x))
+ - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ / UNITS_PER_WORD);
+ else
+ word = 2 * HARD_REGNO_NREGS (REGNO (x),
+ COMPLEX_SUBMODE (GET_MODE (x)))
+ - HARD_REGNO_NREGS (REGNO (x), mode);
+ }
/*
* ??? This fails miserably for complex values being passed in registers
--- gcc/explow.c.orig Sat Dec 6 12:19:52 1997
+++ gcc/explow.c Wed Jan 7 16:34:26 1998
@@ -1322,7 +1322,29 @@ hard_function_value (valtype, func)
tree valtype;
tree func;
{
- rtx val = FUNCTION_VALUE (valtype, func);
+ rtx val;
+ enum machine_mode complex_mode = TYPE_MODE (valtype);
+
+ if (COMPLEX_MODE_P (complex_mode))
+ {
+ enum machine_mode orig_word_mode = word_mode;
+ enum machine_mode submode = COMPLEX_SUBMODE (complex_mode);
+ int unsignedp = TREE_UNSIGNED (valtype);
+ word_mode = submode;
+ val = FUNCTION_VALUE (type_for_mode (submode, unsignedp), func);
+ word_mode = orig_word_mode;
+#ifdef PROMOTE_FUNCTION_RETURN
+ submode = promote_mode (type_for_mode (submode, unsignedp),
+ submode, &unsignedp, 0);
+ complex_mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (complex_mode), 0);
+#endif
+ val = gen_rtx (REG, complex_mode, REGNO (val));
+ }
+ else
+ val = FUNCTION_VALUE (valtype, func);
+
if (GET_CODE (val) == REG
&& GET_MODE (val) == BLKmode)
{
--- gcc/expr.c.orig Fri Dec 19 11:41:58 1997
+++ gcc/expr.c Wed Jan 7 16:53:23 1998
@@ -2262,12 +2262,8 @@ emit_move_insn_1 (x, y)
emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
/* Expand complex moves by moving real part and imag part, if possible. */
- else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
- && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode)
- * BITS_PER_UNIT),
- (class == MODE_COMPLEX_INT
- ? MODE_INT : MODE_FLOAT),
- 0))
+ else if (COMPLEX_MODE_P (mode)
+ && BLKmode != (submode = COMPLEX_SUBMODE (mode))
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
@@ -3296,6 +3292,81 @@ store_expr (exp, target, want_value)
SUBREG_PROMOTED_UNSIGNED_P (target));
return want_value ? temp : NULL_RTX;
}
+ else if (GET_CODE (target) == CONCAT
+ && COMPLEX_MODE_P (GET_MODE (target))
+ && GET_CODE (XEXP (target, 0)) == SUBREG
+ && SUBREG_PROMOTED_VAR_P (XEXP (target, 0)))
+ /* Do the same as for the previous case. */
+ {
+ rtx realpart;
+ rtx imagpart;
+ if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (exp)))
+ && TREE_TYPE (TREE_TYPE (TREE_TYPE (exp))) == 0)
+ {
+ enum machine_mode mode;
+ tree type;
+
+ if (TREE_UNSIGNED (TREE_TYPE (exp))
+ != SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 0)))
+ exp
+ = convert
+ (signed_or_unsigned_type (SUBREG_PROMOTED_UNSIGNED_P
+ (XEXP (target, 0)),
+ TREE_TYPE (exp)),
+ exp);
+
+ mode = GET_MODE (SUBREG_REG (XEXP (target, 0)));
+ mode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT * 2,
+ GET_MODE_CLASS (GET_MODE (target)),
+ 0);
+
+ exp = convert (type_for_mode (mode,
+ SUBREG_PROMOTED_UNSIGNED_P
+ (XEXP (target, 0))),
+ exp);
+ }
+
+ temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+
+ realpart = gen_realpart (COMPLEX_SUBMODE (GET_MODE (temp)), temp);
+ imagpart = gen_imagpart (COMPLEX_SUBMODE (GET_MODE (temp)), temp);
+ if (GET_CODE (realpart) == MEM && want_value
+ && (MEM_VOLATILE_P (realpart)
+ || reg_mentioned_p (SUBREG_REG (XEXP (target, 0)),
+ XEXP (realpart, 0))))
+ realpart = copy_to_reg (realpart);
+ if (GET_CODE (imagpart) == MEM && want_value
+ && (MEM_VOLATILE_P (imagpart)
+ || reg_mentioned_p (SUBREG_REG (XEXP (target, 1)),
+ XEXP (imagpart, 0))))
+ imagpart = copy_to_reg (imagpart);
+
+ if (CONSTANT_P (realpart) && GET_MODE (realpart) == VOIDmode)
+ realpart = convert_modes (GET_MODE (SUBREG_REG
+ (XEXP (target, 0))),
+ COMPLEX_SUBMODE (TYPE_MODE
+ (TREE_TYPE (exp))),
+ realpart,
+ SUBREG_PROMOTED_UNSIGNED_P
+ (XEXP (target, 0)));
+ if (CONSTANT_P (imagpart) && GET_MODE (imagpart) == VOIDmode)
+ imagpart = convert_modes (GET_MODE (SUBREG_REG
+ (XEXP (target, 1))),
+ COMPLEX_SUBMODE (TYPE_MODE
+ (TREE_TYPE (exp))),
+ imagpart,
+ SUBREG_PROMOTED_UNSIGNED_P
+ (XEXP (target, 1)));
+
+ convert_move (SUBREG_REG (XEXP (target, 0)), realpart,
+ SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 0)));
+ convert_move (SUBREG_REG (XEXP (target, 1)), imagpart,
+ SUBREG_PROMOTED_UNSIGNED_P (XEXP (target, 1)));
+ temp = gen_rtx (CONCAT, TYPE_MODE (TREE_TYPE (exp)),
+ realpart, imagpart);
+
+ return want_value ? temp : NULL_RTX;
+ }
else
{
temp = expand_expr (exp, target, GET_MODE (target), 0);
@@ -4978,10 +5049,21 @@ expand_expr (exp, target, tmode, modifie
and 2) otherwise cse could produce an insn the machine
cannot support. */
- if (! cse_not_expected && mode != BLKmode && target
- && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER))
- target = subtarget;
+ if (! cse_not_expected && mode != BLKmode && target)
+ {
+ int flag = 1;
+
+ if (GET_CODE (target) == REG && REGNO (target) > FIRST_PSEUDO_REGISTER)
+ flag = 0;
+ else if (GET_CODE (target) == CONCAT
+ && GET_CODE (XEXP (target, 0)) == REG
+ && REGNO (XEXP (target, 0)) > FIRST_PSEUDO_REGISTER)
+ flag = 0;
+ if (flag)
+ target = subtarget;
+ }
+
switch (code)
{
case LABEL_DECL:
@@ -5160,6 +5242,38 @@ expand_expr (exp, target, tmode, modifie
return temp;
}
+ if (GET_CODE (DECL_RTL (exp)) == CONCAT
+ && COMPLEX_MODE_P (GET_MODE (DECL_RTL (exp)))
+ && GET_MODE (DECL_RTL (exp)) != mode)
+ {
+ rtx realpart;
+ rtx imagpart;
+ enum machine_mode submode_orig = COMPLEX_SUBMODE (mode);
+ enum machine_mode submode_final
+ = promote_mode (type_for_mode (submode_orig,
+ TREE_UNSIGNED (type)),
+ submode_orig, &unsignedp, 0);
+ enum machine_mode promoted_mode
+ = mode_for_size (2 * GET_MODE_SIZE (submode_final)
+ * BITS_PER_UNIT, GET_MODE_CLASS (mode), 0);
+ /* Get the signedness used for this variable. Ensure we get the
+ same mode we got when the variable was declared. */
+ if (GET_MODE (DECL_RTL (exp)) != promoted_mode)
+ abort ();
+
+ realpart = gen_rtx (SUBREG, submode_orig,
+ XEXP (DECL_RTL (exp), 0), 0);
+ imagpart = gen_rtx (SUBREG, submode_orig,
+ XEXP (DECL_RTL (exp), 1), 0);
+ SUBREG_PROMOTED_VAR_P (realpart) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (realpart) = unsignedp;
+ SUBREG_PROMOTED_VAR_P (imagpart) = 1;
+ SUBREG_PROMOTED_UNSIGNED_P (imagpart) = unsignedp;
+
+ temp = gen_rtx (CONCAT, mode, realpart, imagpart);
+ return temp;
+ }
+
return DECL_RTL (exp);
case INTEGER_CST:
@@ -5789,8 +5903,7 @@ expand_expr (exp, target, tmode, modifie
|| (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& ((mode1 != BLKmode && ! direct_load[(int) mode1]
- && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+ && ! COMPLEX_MODE_P (mode))
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (SLOW_UNALIGNED_ACCESS
@@ -6493,8 +6606,7 @@ expand_expr (exp, target, tmode, modifie
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
/* Handle complex values specially. */
- if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
- || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+ if (COMPLEX_MODE_P (mode))
return expand_complex_abs (mode, op0, target, unsignedp);
/* Unsigned abs is simply the operand. Testing here means we don't
@@ -10396,8 +10508,7 @@ do_jump (exp, if_false_label, if_true_la
if (integer_zerop (TREE_OPERAND (exp, 1)))
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
- else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+ else if (COMPLEX_MODE_P (TYPE_MODE (inner_type)))
do_jump
(fold
(build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
@@ -10430,8 +10541,7 @@ do_jump (exp, if_false_label, if_true_la
if (integer_zerop (TREE_OPERAND (exp, 1)))
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
- else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+ else if (COMPLEX_MODE_P (TYPE_MODE (inner_type)))
do_jump
(fold
(build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
--- gcc/function.c.orig Mon Dec 15 02:04:57 1997
+++ gcc/function.c Wed Jan 7 16:42:46 1998
@@ -3523,7 +3523,9 @@ aggregate_value_p (exp)
else
type = TREE_TYPE (exp);
- if (RETURN_IN_MEMORY (type))
+ if (RETURN_IN_MEMORY (COMPLEX_MODE_P (TYPE_MODE (type))?
+ type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (type)), 0)
+ : type))
return 1;
/* Types that are TREE_ADDRESSABLE must be constructed in memory,
and thus can't be returned in registers. */
@@ -3541,7 +3543,10 @@ aggregate_value_p (exp)
return 0;
regno = REGNO (reg);
- nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+ if (! COMPLEX_MODE_P (GET_MODE (reg)))
+ nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
+ else
+ nregs = 2*HARD_REGNO_NREGS (regno, COMPLEX_SUBMODE (TYPE_MODE (type)));
for (i = 0; i < nregs; i++)
if (! call_used_regs[regno + i])
return 1;
@@ -3661,7 +3666,13 @@ assign_parms (fndecl, second_time)
int did_conversion = 0;
tree passed_type = DECL_ARG_TYPE (parm);
tree nominal_type = TREE_TYPE (parm);
-
+ enum machine_mode submode;
+ tree subtype;
+ int nregs = 0;
+ int nregs_real = 0;
+ int nregs_imag = 0;
+ int in_regs;
+
/* Set LAST_NAMED if this is last named arg before some
anonymous args. We treat it as if it were anonymous too. */
int last_named = ((TREE_CHAIN (parm) == 0
@@ -3714,8 +3725,14 @@ assign_parms (fndecl, second_time)
&& contains_placeholder_p (TYPE_SIZE (passed_type)))
|| TREE_ADDRESSABLE (passed_type)
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
- || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
- passed_type, ! last_named)
+ || FUNCTION_ARG_PASS_BY_REFERENCE
+ (args_so_far,
+ (! COMPLEX_MODE_P (passed_mode))?
+ passed_mode : COMPLEX_SUBMODE (passed_mode),
+ (! COMPLEX_MODE_P (passed_mode))?
+ passed_type : type_for_mode (COMPLEX_SUBMODE (passed_mode),
+ 0),
+ ! last_named)
#endif
)
{
@@ -3725,25 +3742,31 @@ assign_parms (fndecl, second_time)
}
promoted_mode = passed_mode;
+ unsignedp = TREE_UNSIGNED (passed_type);
+ if (COMPLEX_MODE_P (promoted_mode))
+ {
+ submode = COMPLEX_SUBMODE (promoted_mode);
+ subtype = type_for_mode (submode, unsignedp);
+ }
+
#ifdef PROMOTE_FUNCTION_ARGS
/* Compute the mode in which the arg is actually extended to. */
- promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
-#endif
-
- /* Let machine desc say which reg (if any) the parm arrives in.
- 0 means it arrives on the stack. */
-#ifdef FUNCTION_INCOMING_ARG
- entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
- passed_type, ! last_named);
-#else
- entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ if (! COMPLEX_MODE_P (promoted_mode))
+ {
+ promoted_mode = promote_mode (passed_type, promoted_mode,
+ &unsignedp, 1);
+ }
+ else
+ {
+ submode = promote_mode (subtype, submode, &unsignedp, 1);
+ subtype = type_for_mode (submode, unsignedp);
+ promoted_mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (promoted_mode), 0);
+ }
#endif
- if (entry_parm == 0)
- promoted_mode = passed_mode;
-
#ifdef SETUP_INCOMING_VARARGS
/* If this is the last named parameter, do any required setup for
varargs or stdargs. We need to know about the case of this being an
@@ -3764,6 +3787,121 @@ assign_parms (fndecl, second_time)
}
#endif
+ if (! COMPLEX_MODE_P (promoted_mode))
+ {
+ /* Let machine desc say which reg (if any) the parm arrives in.
+ 0 means it arrives on the stack. */
+#ifdef FUNCTION_INCOMING_ARG
+ entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+ passed_type, ! last_named);
+#else
+ entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
+ passed_type, ! last_named);
+#endif
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+ if (entry_parm)
+ nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
+ passed_type, ! last_named);
+#endif
+
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+ in_regs = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+ in_regs = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
+ passed_type,
+ (! last_named
+ || varargs_setup)) != 0;
+#else
+ in_regs = FUNCTION_ARG (args_so_far, promoted_mode,
+ passed_type,
+ ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+ /* Update info on where next arg arrives in registers. */
+ FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
+ passed_type, ! last_named);
+ }
+ else
+ {
+ rtx realpart;
+ rtx imagpart;
+ int in_regs_real;
+ int in_regs_imag;
+
+#ifdef FUNCTION_INCOMING_ARG
+ realpart = FUNCTION_INCOMING_ARG (args_so_far, submode,
+ subtype, ! last_named);
+#else
+ realpart = FUNCTION_ARG (args_so_far, submode,
+ subtype, ! last_named);
+#endif
+
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+ if (realpart)
+ nregs_real = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode,
+ subtype, ! last_named);
+#endif
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+ in_regs_real = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+ in_regs_real = FUNCTION_INCOMING_ARG (args_so_far, submode, subtype,
+ (! last_named
+ || varargs_setup)) != 0;
+#else
+ in_regs_real = FUNCTION_ARG (args_so_far, submode, subtype,
+ ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+ FUNCTION_ARG_ADVANCE (args_so_far, submode,
+ subtype, !last_named);
+#ifdef FUNCTION_INCOMING_ARG
+ imagpart = FUNCTION_INCOMING_ARG (args_so_far, submode,
+ subtype, ! last_named);
+#else
+ imagpart = FUNCTION_ARG (args_so_far, submode,
+ subtype, ! last_named);
+#endif
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+ if (imagpart)
+ nregs_imag = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, submode,
+ subtype, ! last_named);
+#endif
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+ in_regs_imag = 1;
+#else
+#ifdef FUNCTION_INCOMING_ARG
+ in_regs_imag = FUNCTION_INCOMING_ARG (args_so_far, submode, subtype,
+ (! last_named
+ || varargs_setup)) != 0;
+#else
+ in_regs_imag = FUNCTION_ARG (args_so_far, submode, subtype,
+ ! last_named || varargs_setup) != 0;
+#endif
+#endif
+
+ FUNCTION_ARG_ADVANCE (args_so_far, submode,
+ subtype, !last_named);
+ if (realpart == 0 && imagpart == 0)
+ in_regs = in_regs_real;
+ else if (imagpart)
+ in_regs = in_regs_imag;
+ else if (realpart)
+ in_regs = in_regs_real;
+
+ if (realpart != 0)
+ entry_parm = gen_rtx (CONCAT, promoted_mode, realpart, imagpart);
+ else
+ entry_parm = 0;
+ }
+
+ if (entry_parm == 0)
+ promoted_mode = passed_mode;
+
/* Determine parm's home in the stack,
in case it arrives in the stack or we should pretend it did.
@@ -3777,40 +3915,114 @@ assign_parms (fndecl, second_time)
In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
0 as it was the previous time. */
- locate_and_pad_parm (promoted_mode, passed_type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
- 1,
-#else
-#ifdef FUNCTION_INCOMING_ARG
- FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
- passed_type,
- (! last_named
- || varargs_setup)) != 0,
-#else
- FUNCTION_ARG (args_so_far, promoted_mode,
- passed_type,
- ! last_named || varargs_setup) != 0,
-#endif
+ {
+ enum machine_mode pad_mode = promoted_mode;
+ tree pad_type = passed_type;
+
+ if (COMPLEX_MODE_P (promoted_mode) && entry_parm != 0
+#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
+ && REG_PARM_STACK_SPACE (fndecl) == 0
#endif
- fndecl, &stack_args_size, &stack_offset, &arg_size);
-
- if (! second_time)
- {
- rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
+ )
+ {
+ /* If we do not need to allocate stack space for
+ arguments passing in register, and the real part
+ of a complex argument is passing in register,
+ we only allocate stack space for the imaginary part. */
+ if (XEXP (entry_parm, 0) != 0 && nregs_real == 0
+ && (XEXP (entry_parm, 1) == 0 || nregs_imag > 0))
+ {
+ pad_mode = COMPLEX_SUBMODE (passed_mode);
+ pad_type = type_for_mode (pad_mode, unsignedp);
+ }
+ }
+ locate_and_pad_parm (pad_mode, pad_type, in_regs,
+ fndecl, &stack_args_size, &stack_offset,
+ &arg_size);
+
+ if (! second_time)
+ {
+ rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
- if (offset_rtx == const0_rtx)
- stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
- else
- stack_parm = gen_rtx (MEM, promoted_mode,
- gen_rtx (PLUS, Pmode,
- internal_arg_pointer, offset_rtx));
+ if (! COMPLEX_MODE_P (promoted_mode))
+ {
+ if (offset_rtx == const0_rtx)
+ stack_parm = gen_rtx (MEM, promoted_mode,
+ internal_arg_pointer);
+ else
+ stack_parm = gen_rtx (MEM, promoted_mode,
+ gen_rtx (PLUS, Pmode,
+ internal_arg_pointer,
+ offset_rtx));
+
+ /* If this is a memory ref that contains aggregate components,
+ mark it as such for cse and loop optimize. Likewise if it
+ is readonly. */
+ MEM_IN_STRUCT_P (stack_parm) = aggregate;
+ RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
+ }
+ else
+ {
+ rtx realpart;
+ rtx imagpart;
+ int imag_offset;
+ enum machine_mode stack_mode = promoted_mode;
+ enum machine_mode sub_stack_mode;
+
+ if (entry_parm
+ && XEXP (entry_parm, 0) != 0 && nregs_real == 0)
+ stack_mode = passed_mode;
+ sub_stack_mode = COMPLEX_SUBMODE (stack_mode);
+
+ if (offset_rtx == const0_rtx)
+ realpart = gen_rtx (MEM, sub_stack_mode,
+ internal_arg_pointer);
+ else
+ realpart = gen_rtx (MEM, sub_stack_mode,
+ gen_rtx (PLUS, Pmode,
+ internal_arg_pointer,
+ offset_rtx));
+ MEM_IN_STRUCT_P (realpart) = aggregate;
+ RTX_UNCHANGING_P (realpart) = TREE_READONLY (parm);
- /* If this is a memory ref that contains aggregate components,
- mark it as such for cse and loop optimize. Likewise if it
- is readonly. */
- MEM_IN_STRUCT_P (stack_parm) = aggregate;
- RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
- }
+ if (COMPLEX_MODE_P (pad_mode))
+ {
+ imag_offset = arg_size.constant / 2;
+ stack_offset.constant += imag_offset;
+
+ offset_rtx = ARGS_SIZE_RTX (stack_offset);
+ imagpart = gen_rtx (MEM, sub_stack_mode,
+ gen_rtx (PLUS, Pmode,
+ internal_arg_pointer,
+ offset_rtx));
+ MEM_IN_STRUCT_P (imagpart) = aggregate;
+ RTX_UNCHANGING_P (imagpart) = TREE_READONLY (parm);
+ }
+ else
+ imagpart = 0;
+#ifdef ARGS_GROW_DOWNWARD
+ /* If the real part is passing in register, the imaginary
+ part in stack only, and ARGS_GROW_DOWNWARD is defined,
+ allocate the stack space for the imaginary part close to
+ next argument. */
+ if (COMPLEX_MODE_P (promoted_mode) && entry_parm != 0
+ && XEXP (entry_parm, 0) != 0 && nregs_real == 0
+ && (XEXP (entry_parm, 1) == 0 || nregs_imag > 0))
+ {
+ rtx tmp = realpart;
+ realpart = imagpart;
+ imagpart = tmp;
+ }
+#endif
+ if (COMPLEX_MODE_P (pad_mode))
+ stack_parm = gen_rtx (CONCAT, stack_mode,
+ realpart, imagpart);
+ else
+ stack_parm = gen_rtx (CONCAT, stack_mode,
+ imagpart, realpart);
+ }
+ }
+ }
/* If this parameter was passed both in registers and in the stack,
use the copy on the stack. */
@@ -3826,15 +4038,49 @@ assign_parms (fndecl, second_time)
we could put it together in a pseudoreg directly,
but for now that's not worth bothering with. */
- if (entry_parm)
+ if (entry_parm != 0 && GET_CODE (entry_parm) == CONCAT
+ && COMPLEX_MODE_P (GET_MODE (entry_parm)))
{
- int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ if (nregs_real > 0 || nregs_imag > 0
+ || (XEXP (entry_parm, 0) && XEXP (entry_parm, 1) == 0))
+ {
+ if (nregs_real > 0 || nregs_imag > 0)
+ {
+ current_function_pretend_args_size
+ = ((((nregs_real + nregs_imag) * UNITS_PER_WORD)
+ + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
+ / (PARM_BOUNDARY / BITS_PER_UNIT)
+ * (PARM_BOUNDARY / BITS_PER_UNIT));
+ }
+ if (! second_time)
+ {
+ if (nregs_real > 0)
+ move_block_from_reg (REGNO (XEXP (entry_parm, 0)),
+ validize_mem (XEXP (stack_parm, 0)),
+ nregs_real,
+ int_size_in_bytes (DECL_ARG_TYPE
+ (parm))/2);
+ else if (nregs_imag > 0)
+ move_block_from_reg (REGNO (XEXP (entry_parm, 1)),
+ validize_mem (XEXP (stack_parm, 1)),
+ nregs_imag,
+ int_size_in_bytes (DECL_ARG_TYPE
+ (parm))/2);
+ }
+ if (XEXP (entry_parm, 0) && nregs_real == 0)
+ XEXP (entry_parm, 1) = stack_parm ? XEXP (stack_parm, 1) : 0;
+ else
+ entry_parm = stack_parm;
+ }
+ }
+ else if (entry_parm)
+ {
if (nregs > 0)
{
current_function_pretend_args_size
- = (((nregs * UNITS_PER_WORD) + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
+ = (((nregs * UNITS_PER_WORD)
+ + (PARM_BOUNDARY / BITS_PER_UNIT) - 1)
/ (PARM_BOUNDARY / BITS_PER_UNIT)
* (PARM_BOUNDARY / BITS_PER_UNIT));
@@ -3869,6 +4115,8 @@ assign_parms (fndecl, second_time)
to indicate there is no preallocated stack slot for the parm. */
if (entry_parm == stack_parm
+ || (COMPLEX_MODE_P (promoted_mode) && entry_parm && stack_parm
+ && XEXP (entry_parm, 1) == XEXP (stack_parm, 1))
#if defined (REG_PARM_STACK_SPACE) && ! defined (MAYBE_REG_PARM_STACK_SPACE)
/* On some machines, even if a parm value arrives in a register
there is still an (uninitialized) stack slot allocated for it.
@@ -3891,11 +4139,6 @@ assign_parms (fndecl, second_time)
/* No stack slot was pushed for this parm. */
stack_parm = 0;
- /* Update info on where next arg arrives in registers. */
-
- FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
- passed_type, ! last_named);
-
/* If this is our second time through, we are done with this parm. */
if (second_time)
continue;
@@ -3970,6 +4213,16 @@ assign_parms (fndecl, second_time)
if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
emit_insn (gen_rtx (USE, GET_MODE (entry_parm), entry_parm));
+ else if (GET_CODE (entry_parm) == CONCAT
+ && !(hide_last_arg && last_named))
+ {
+ if (GET_CODE (XEXP (entry_parm, 0)) == REG)
+ emit_insn (gen_rtx (USE, GET_MODE (XEXP (entry_parm, 0)),
+ XEXP (entry_parm, 0)));
+ if (GET_CODE (XEXP (entry_parm, 1)) == REG)
+ emit_insn (gen_rtx (USE, GET_MODE (XEXP (entry_parm, 1)),
+ XEXP (entry_parm, 1)));
+ }
#endif
/* ENTRY_PARM is an RTX for the parameter as it arrives,
@@ -4056,12 +4309,38 @@ assign_parms (fndecl, second_time)
unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
- promoted_nominal_mode
- = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
-
- parmreg = gen_reg_rtx (promoted_nominal_mode);
- mark_user_reg (parmreg);
-
+ if (! COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (parm))))
+ {
+ promoted_nominal_mode
+ = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
+
+ parmreg = gen_reg_rtx (promoted_nominal_mode);
+ mark_user_reg (parmreg);
+ }
+ else
+ {
+ enum machine_mode submode_nominal
+ = COMPLEX_SUBMODE (nominal_mode);
+ rtx realpart;
+ rtx imagpart;
+
+ submode_nominal
+ = promote_mode (type_for_mode (submode_nominal, unsignedp),
+ submode_nominal, &unsignedp, 0);
+ promoted_nominal_mode
+ = mode_for_size (2 * GET_MODE_SIZE (submode_nominal)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (nominal_mode), 0);
+
+ realpart = gen_reg_rtx (submode_nominal);
+ imagpart = gen_reg_rtx (submode_nominal);
+
+ parmreg = gen_rtx (CONCAT, promoted_nominal_mode,
+ realpart, imagpart);
+ mark_user_reg (realpart);
+ mark_user_reg (imagpart);
+ }
+
/* If this was an item that we received a pointer to, set DECL_RTL
appropriately. */
if (passed_pointer)
@@ -4075,7 +4354,10 @@ assign_parms (fndecl, second_time)
/* Copy the value into the register. */
if (nominal_mode != passed_mode
- || promoted_nominal_mode != promoted_mode)
+ || promoted_nominal_mode != promoted_mode
+ || (COMPLEX_MODE_P (passed_mode)
+ && GET_MODE (XEXP (entry_parm, 0))
+ != GET_MODE (XEXP (entry_parm, 1))))
{
/* ENTRY_PARM has been converted to PROMOTED_MODE, its
mode, by the caller. We now have to convert it to
@@ -4096,22 +4378,60 @@ assign_parms (fndecl, second_time)
a pseudo reg here, and save the conversion until after all
parameters have been moved. */
- rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
+ if (! COMPLEX_MODE_P (GET_MODE (entry_parm)))
+ {
+ rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
- emit_move_insn (tempreg, validize_mem (entry_parm));
+ emit_move_insn (tempreg, validize_mem (entry_parm));
- push_to_sequence (conversion_insns);
- tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+ push_to_sequence (conversion_insns);
+ tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
- expand_assignment (parm,
- make_tree (nominal_type, tempreg), 0, 0);
- conversion_insns = get_insns ();
- did_conversion = 1;
- end_sequence ();
+ expand_assignment (parm,
+ make_tree (nominal_type, tempreg), 0, 0);
+ conversion_insns = get_insns ();
+ did_conversion = 1;
+ end_sequence ();
+ }
+ else
+ {
+ rtx realpart = gen_reg_rtx (GET_MODE (XEXP (entry_parm, 0)));
+ rtx imagpart = gen_reg_rtx (GET_MODE (XEXP (entry_parm, 1)));
+ enum machine_mode submode_nominal
+ = COMPLEX_SUBMODE (nominal_mode);
+ rtx tempreg;
+
+ emit_move_insn (realpart,
+ validize_mem (XEXP (entry_parm, 0)));
+ emit_move_insn (imagpart,
+ validize_mem (XEXP (entry_parm, 1)));
+
+ push_to_sequence (conversion_insns);
+ realpart = convert_to_mode (submode_nominal, realpart, unsignedp);
+ imagpart = convert_to_mode (submode_nominal, imagpart, unsignedp);
+ tempreg = gen_rtx (CONCAT, nominal_mode,
+ realpart, imagpart);
+
+ expand_assignment (parm,
+ make_tree (nominal_type, tempreg), 0, 0);
+ conversion_insns = get_insns ();
+ did_conversion = 1;
+ end_sequence ();
+ }
}
else
- emit_move_insn (parmreg, validize_mem (entry_parm));
-
+ {
+ if (! COMPLEX_MODE_P (GET_MODE (entry_parm)))
+ emit_move_insn (parmreg, validize_mem (entry_parm));
+ else
+ {
+ emit_move_insn (XEXP (parmreg, 0),
+ validize_mem (XEXP (entry_parm, 0)));
+ emit_move_insn (XEXP (parmreg, 1),
+ validize_mem (XEXP (entry_parm, 1)));
+ }
+ }
+
/* If we were passed a pointer but the actual value
can safely live in a register, put it in one. */
if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
@@ -4145,10 +4465,16 @@ assign_parms (fndecl, second_time)
modified, don't do the copy. */
else if (passed_pointer
- && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
- TYPE_MODE (DECL_ARG_TYPE (parm)),
- DECL_ARG_TYPE (parm),
- ! last_named)
+ && FUNCTION_ARG_CALLEE_COPIES
+ (args_so_far,
+ (! COMPLEX_MODE_P (TYPE_MODE (DECL_ARG_TYPE (parm))))?
+ TYPE_MODE (DECL_ARG_TYPE (parm))
+ : COMPLEX_SUBMODE (TYPE_MODE (DECL_ARG_TYPE (parm))),
+ (! COMPLEX_MODE_P (TYPE_MODE (DECL_ARG_TYPE (parm))))?
+ DECL_ARG_TYPE (parm)
+ : type_for_mode (COMPLEX_SUBMODE (TYPE_MODE (DECL_ARG_TYPE (parm))),
+ 0),
+ ! last_named)
&& ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
{
rtx copy;
@@ -4219,15 +4545,13 @@ assign_parms (fndecl, second_time)
{
enum machine_mode submode = GET_MODE (XEXP (parmreg, 0));
- regnor = REGNO (gen_realpart (submode, parmreg));
- regnoi = REGNO (gen_imagpart (submode, parmreg));
+ regnor = REGNO (XEXP (parmreg, 0));
+ regnoi = REGNO (XEXP (parmreg, 1));
if (stack_parm != 0)
{
- parm_reg_stack_loc[regnor]
- = gen_realpart (submode, stack_parm);
- parm_reg_stack_loc[regnoi]
- = gen_imagpart (submode, stack_parm);
+ parm_reg_stack_loc[regnor] = XEXP (stack_parm, 0);
+ parm_reg_stack_loc[regnoi] = XEXP (stack_parm, 1);
}
else
{
@@ -4294,53 +4618,157 @@ assign_parms (fndecl, second_time)
/* Value must be stored in the stack slot STACK_PARM
during function execution. */
- if (promoted_mode != nominal_mode)
+ if (! COMPLEX_MODE_P (promoted_mode))
{
- /* Conversion is required. */
- rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
-
- emit_move_insn (tempreg, validize_mem (entry_parm));
+ if (promoted_mode != nominal_mode)
+ {
+ /* Conversion is required. */
+ rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
+
+ emit_move_insn (tempreg, validize_mem (entry_parm));
+
+ push_to_sequence (conversion_insns);
+ entry_parm
+ = convert_to_mode (nominal_mode, tempreg,
+ TREE_UNSIGNED (TREE_TYPE (parm)));
+ if (stack_parm)
+ {
+ /* ??? This may need a big-endian conversion on sparc64. */
+ stack_parm = change_address (stack_parm, nominal_mode,
+ NULL_RTX);
+ }
+ conversion_insns = get_insns ();
+ did_conversion = 1;
+ end_sequence ();
+ }
+ }
+ else
+ {
+ enum machine_mode submode_nominal
+ = COMPLEX_SUBMODE (nominal_mode);
+ rtx realpart;
+ rtx imagpart;
+ int unsignedp1 = TREE_UNSIGNED (TREE_TYPE (parm));
- push_to_sequence (conversion_insns);
- entry_parm = convert_to_mode (nominal_mode, tempreg,
- TREE_UNSIGNED (TREE_TYPE (parm)));
- if (stack_parm)
+ if (GET_MODE (XEXP (entry_parm, 0)) != submode_nominal)
{
- /* ??? This may need a big-endian conversion on sparc64. */
- stack_parm = change_address (stack_parm, nominal_mode,
- NULL_RTX);
+ realpart = gen_reg_rtx (submode);
+ emit_move_insn (realpart,
+ validize_mem (XEXP (entry_parm, 0)));
+ push_to_sequence (conversion_insns);
+ realpart = convert_to_mode (submode_nominal, realpart,
+ unsignedp1);
+ conversion_insns = get_insns ();
+ did_conversion = 1;
+ end_sequence ();
}
- conversion_insns = get_insns ();
- did_conversion = 1;
- end_sequence ();
+ else
+ realpart = XEXP (entry_parm, 0);
+
+ if (GET_MODE (XEXP (entry_parm, 1)) != submode_nominal)
+ {
+ imagpart = gen_reg_rtx (submode);
+ emit_move_insn (imagpart,
+ validize_mem (XEXP (entry_parm, 1)));
+ push_to_sequence (conversion_insns);
+ imagpart = convert_to_mode (submode_nominal, imagpart,
+ unsignedp1);
+ conversion_insns = get_insns ();
+ did_conversion = 1;
+ end_sequence ();
+ }
+ else
+ imagpart = XEXP (entry_parm, 1);
+
+ if (GET_MODE (XEXP (entry_parm, 0)) != submode_nominal
+ || GET_MODE (XEXP (entry_parm, 1)) != submode_nominal)
+ entry_parm = gen_rtx (CONCAT, nominal_mode,
+ realpart, imagpart);
}
if (entry_parm != stack_parm)
{
- if (stack_parm == 0)
+ enum machine_mode entry_mode = GET_MODE (entry_parm);
+
+ if (! COMPLEX_MODE_P (entry_mode))
{
- stack_parm
- = assign_stack_local (GET_MODE (entry_parm),
- GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
- /* If this is a memory ref that contains aggregate components,
- mark it as such for cse and loop optimize. */
- MEM_IN_STRUCT_P (stack_parm) = aggregate;
+ if (stack_parm == 0)
+ {
+ stack_parm
+ = assign_stack_local (GET_MODE (entry_parm),
+ GET_MODE_SIZE (GET_MODE
+ (entry_parm)), 0);
+ /* If this is a memory ref that contains aggregate components,
+ mark it as such for cse and loop optimize. */
+ MEM_IN_STRUCT_P (stack_parm) = aggregate;
+ }
+ }
+ else
+ {
+ rtx realpart;
+ rtx imagpart;
+ enum machine_mode submode
+ = COMPLEX_SUBMODE (entry_mode);
+
+ if (stack_parm == 0 || XEXP (stack_parm, 0) == 0)
+ {
+ realpart
+ = assign_stack_local (submode,
+ GET_MODE_SIZE (submode), 0);
+ MEM_IN_STRUCT_P (realpart) = aggregate;
+ }
+ if (stack_parm == 0 || XEXP (stack_parm, 1) == 0)
+ {
+ imagpart
+ = assign_stack_local (submode,
+ GET_MODE_SIZE (submode), 0);
+ MEM_IN_STRUCT_P (imagpart) = aggregate;
+ }
+ if (stack_parm == 0)
+ stack_parm = gen_rtx (CONCAT, entry_mode,
+ realpart, imagpart);
+ else if (XEXP (stack_parm, 0) == 0)
+ XEXP (stack_parm, 0) = realpart;
+ else if (XEXP (stack_parm, 1) == 0)
+ XEXP (stack_parm, 1) = imagpart;
}
-
if (promoted_mode != nominal_mode)
{
push_to_sequence (conversion_insns);
- emit_move_insn (validize_mem (stack_parm),
- validize_mem (entry_parm));
+ if (! COMPLEX_MODE_P (entry_mode))
+ {
+ emit_move_insn (validize_mem (stack_parm),
+ validize_mem (entry_parm));
+ }
+ else
+ {
+ emit_move_insn (validize_mem (XEXP (stack_parm, 0)),
+ validize_mem (XEXP (entry_parm, 0)));
+ emit_move_insn (validize_mem (XEXP (stack_parm, 1)),
+ validize_mem (XEXP (entry_parm, 1)));
+ }
+
conversion_insns = get_insns ();
end_sequence ();
}
else
- emit_move_insn (validize_mem (stack_parm),
- validize_mem (entry_parm));
+ {
+ if (! COMPLEX_MODE_P (entry_mode))
+ {
+ emit_move_insn (validize_mem (stack_parm),
+ validize_mem (entry_parm));
+ }
+ else
+ {
+ emit_move_insn (validize_mem (XEXP (stack_parm, 0)),
+ validize_mem (XEXP (entry_parm, 0)));
+ emit_move_insn (validize_mem (XEXP (stack_parm, 1)),
+ validize_mem (XEXP (entry_parm, 1)));
+ }
+ }
}
- if (flag_check_memory_usage)
- {
+ if (flag_check_memory_usage)
+ {
push_to_sequence (conversion_insns);
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
XEXP (stack_parm, 0), ptr_mode,
@@ -4511,12 +4939,32 @@ locate_and_pad_parm (passed_mode, type,
struct args_size *offset_ptr;
struct args_size *arg_size_ptr;
{
- tree sizetree
- = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
- enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
- int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
- int boundary_in_bytes = boundary / BITS_PER_UNIT;
+ tree sizetree;
+ enum direction where_pad;
+ enum machine_mode mode;
+ int boundary;
+ int boundary_in_bytes;
int reg_parm_stack_space = 0;
+ int i;
+
+ if (! COMPLEX_MODE_P (passed_mode))
+ {
+ sizetree = type ? size_in_bytes (type)
+ : size_int (GET_MODE_SIZE (passed_mode));
+ where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
+ boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
+ mode = passed_mode;
+ }
+ else
+ {
+ tree subtype;
+ mode = COMPLEX_SUBMODE (passed_mode);
+ subtype = type_for_mode (mode, 0);
+ sizetree = size_int (GET_MODE_SIZE (mode));
+ where_pad = FUNCTION_ARG_PADDING (mode, subtype);
+ boundary = FUNCTION_ARG_BOUNDARY (mode, subtype);
+ }
+ boundary_in_bytes = boundary / BITS_PER_UNIT;
#ifdef REG_PARM_STACK_SPACE
/* If we have found a stack parm before we reach the end of the
@@ -4562,7 +5010,13 @@ locate_and_pad_parm (passed_mode, type,
&& (TREE_CODE (sizetree) != INTEGER_CST
|| ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
- SUB_PARM_SIZE (*offset_ptr, sizetree);
+ if (COMPLEX_MODE_P (passed_mode))
+ {
+ SUB_PARM_SIZE (*offset_ptr, sizetree);
+ SUB_PARM_SIZE (*offset_ptr, sizetree);
+ }
+ else
+ SUB_PARM_SIZE (*offset_ptr, sizetree);
if (where_pad != downward)
pad_to_arg_alignment (offset_ptr, boundary);
if (initial_offset_ptr->var)
@@ -4593,14 +5047,20 @@ locate_and_pad_parm (passed_mode, type,
/* However, BLKmode args passed in regs have their padding done elsewhere.
The stack slot must be able to hold the entire register. */
&& !(in_regs && passed_mode == BLKmode))
- pad_below (offset_ptr, passed_mode, sizetree);
+ pad_below (offset_ptr, mode, sizetree);
if (where_pad != none
&& (TREE_CODE (sizetree) != INTEGER_CST
|| ((TREE_INT_CST_LOW (sizetree) * BITS_PER_UNIT) % PARM_BOUNDARY)))
sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
- ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+ if (COMPLEX_MODE_P (passed_mode))
+ {
+ ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+ ADD_PARM_SIZE (*arg_size_ptr, sizetree);
+ }
+ else
+ ADD_PARM_SIZE (*arg_size_ptr, sizetree);
#endif /* ARGS_GROW_DOWNWARD */
}
@@ -5586,10 +6046,61 @@ expand_function_start (subr, parms_have_
tree type = TREE_TYPE (DECL_RESULT (subr));
int unsignedp = TREE_UNSIGNED (type);
- mode = promote_mode (type, mode, &unsignedp, 1);
+ if (! COMPLEX_MODE_P (mode))
+ {
+ mode = promote_mode (type, mode, &unsignedp, 1);
+ }
+ else
+ {
+ enum machine_mode submode = COMPLEX_SUBMODE (mode);
+ submode = promote_mode (type_for_mode (submode,
+ TREE_UNSIGNED (type)),
+ submode, &unsignedp, 1);
+ mode = mode_for_size (2 * GET_MODE_SIZE (submode) * BITS_PER_UNIT,
+ GET_MODE_CLASS (mode), 0);
+ }
#endif
DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
+ }
+ else if (COMPLEX_MODE_P (DECL_MODE (DECL_RESULT (subr))))
+ /* To return a complex value, using two registers. */
+ {
+ enum machine_mode mode = DECL_MODE (DECL_RESULT (subr));
+ enum machine_mode submode = COMPLEX_SUBMODE (mode);
+ rtx realpart;
+ int unsignedp = TREE_UNSIGNED (TREE_TYPE (DECL_RESULT (subr)));
+ tree parttree = type_for_mode (submode, unsignedp);
+
+#ifdef FUNCTION_OUTGOING_VALUE
+ realpart = FUNCTION_OUTGOING_VALUE (parttree, subr);
+#else
+ realpart = FUNCTION_VALUE (parttree, subr);
+#endif
+
+ if (GET_CODE (realpart) == REG)
+ {
+#ifdef PROMOTE_FUNCTION_RETURN
+ submode = promote_mode (type_for_mode (submode, unsignedp),
+ submode, &unsignedp, 1);
+ mode = mode_for_size (2 * GET_MODE_SIZE (submode)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (mode), 0);
+#endif
+ DECL_RTL (DECL_RESULT (subr))
+ = gen_rtx (REG, mode, REGNO (realpart));
+ }
+ else
+ abort ();
+
+ /* Mark this reg as the function's return value. */
+ if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
+ {
+ REG_FUNCTION_VALUE_P (DECL_RTL (DECL_RESULT (subr))) = 1;
+ /* Needed because we may need to move this to memory
+ in case it's a named return value whose address is taken. */
+ DECL_REGISTER (DECL_RESULT (subr)) = 1;
+ }
}
else
/* Scalar, returned in a register. */
--- gcc/integrate.c.orig Thu Dec 18 17:42:35 1997
+++ gcc/integrate.c Wed Jan 7 16:45:26 1998
@@ -1382,11 +1382,32 @@ expand_inline_function (fndecl, parms, t
if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
/* The mode if LOC and ARG can differ if LOC was a variable
that had its mode promoted via PROMOTED_MODE. */
- arg_vals[i] = convert_modes (GET_MODE (loc),
- TYPE_MODE (TREE_TYPE (arg)),
- expand_expr (arg, NULL_RTX, mode,
- EXPAND_SUM),
- TREE_UNSIGNED (TREE_TYPE (formal)));
+ {
+ if (! COMPLEX_MODE_P (GET_MODE (loc)))
+ arg_vals[i]
+ = convert_modes (GET_MODE (loc),
+ TYPE_MODE (TREE_TYPE (arg)),
+ expand_expr (arg, NULL_RTX, mode,
+ EXPAND_SUM),
+ TREE_UNSIGNED (TREE_TYPE (formal)));
+ else
+ {
+ rtx temp = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
+ enum machine_mode mode_orig
+ = COMPLEX_SUBMODE (TYPE_MODE (TREE_TYPE (arg)));
+ enum machine_mode mode_final
+ = COMPLEX_SUBMODE (GET_MODE (loc));
+ rtx realpart = gen_realpart (mode_orig, temp);
+ rtx imagpart = gen_imagpart (mode_orig, temp);
+
+ realpart = convert_modes (mode_final, mode_orig, realpart,
+ TREE_UNSIGNED (TREE_TYPE (formal)));
+ imagpart = convert_modes (mode_final, mode_orig, imagpart,
+ TREE_UNSIGNED (TREE_TYPE (formal)));
+ arg_vals[i] = gen_rtx (CONCAT, GET_MODE (loc),
+ realpart, imagpart);
+ }
+ }
else
arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
}
@@ -1750,7 +1771,8 @@ expand_inline_function (fndecl, parms, t
/* If function's value was promoted before return,
avoid machine mode mismatch when we substitute INLINE_TARGET.
But TARGET is what we will return to the caller. */
- if (arriving_mode != departing_mode)
+ if (arriving_mode != departing_mode
+ && ! COMPLEX_MODE_P (arriving_mode))
{
/* Avoid creating a paradoxical subreg wider than
BITS_PER_WORD, since that is illegal. */
@@ -1765,6 +1787,41 @@ expand_inline_function (fndecl, parms, t
}
else
reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+ }
+ else if (arriving_mode != departing_mode)
+ {
+ /* Deal with complex return. */
+ enum machine_mode submode = COMPLEX_SUBMODE (departing_mode);
+ enum machine_mode promoted_submode
+ = COMPLEX_SUBMODE (arriving_mode);
+ rtx realpart;
+ rtx imagpart;
+
+ /* Avoid creating a paradoxical subreg wider than
+ BITS_PER_WORD, since that is illegal. */
+ if (GET_MODE_BITSIZE (promoted_submode) > BITS_PER_WORD)
+ {
+ if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (submode),
+ GET_MODE_BITSIZE (promoted_submode)))
+ /* Maybe could be handled by using convert_move () ? */
+ abort ();
+ reg_to_map = gen_reg_rtx (arriving_mode);
+ realpart = gen_lowpart (submode,
+ gen_realpart (promoted_submode,
+ reg_to_map));
+ imagpart = gen_lowpart (submode,
+ gen_imagpart (promoted_submode,
+ reg_to_map));
+ target = gen_rtx (CONCAT, departing_mode, realpart, imagpart);
+ }
+ else
+ {
+ realpart = gen_rtx (SUBREG, promoted_submode,
+ gen_realpart (submode, target), 0);
+ imagpart = gen_rtx (SUBREG, promoted_submode,
+ gen_imagpart (submode, target), 0);
+ reg_to_map = gen_rtx (CONCAT, arriving_mode, realpart, imagpart);
+ }
}
else
reg_to_map = target;
--- gcc/machmode.h.orig Mon Aug 11 11:57:11 1997
+++ gcc/machmode.h Wed Jan 7 11:48:11 1998
@@ -164,6 +164,17 @@ extern enum mode_class mode_class[];
(GET_MODE_CLASS (MODE) == MODE_FLOAT \
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+/* Nonzero if MODE is a complex mode. */
+#define COMPLEX_MODE_P(MODE) \
+ (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \
+ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+
+/* Determine the mode for the imaginary and real part of a complex MODE. */
+#define COMPLEX_SUBMODE(MODE) \
+mode_for_size (GET_MODE_UNIT_SIZE(MODE)*BITS_PER_UNIT, \
+ (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)? \
+ MODE_INT:MODE_FLOAT, 0)
+
/* Get the size in bytes of an object of mode MODE. */
extern int mode_size[];
--- gcc/recog.c.orig Sat Dec 6 12:21:30 1997
+++ gcc/recog.c Tue Jan 6 17:27:00 1998
@@ -898,8 +898,7 @@ register_operand (op, mode)
REGNO (SUBREG_REG (op)))
&& (GET_MODE_SIZE (mode)
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
+ && ! COMPLEX_MODE_P (GET_MODE (SUBREG_REG (op))))
return 0;
#endif
--- gcc/regs.h.orig Sun Nov 2 03:40:47 1997
+++ gcc/regs.h Tue Jan 6 17:27:01 1998
@@ -27,7 +27,10 @@ Boston, MA 02111-1307, USA. */
valid way to get this value. You cannot get it from the regno. */
#define REG_SIZE(R) \
- ((mode_size[(int) GET_MODE (R)] + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+ (GET_MODE_SIZE (GET_MODE (R)) == 0? \
+ 0:(((GET_MODE_UNIT_SIZE (GET_MODE (R)) + (UNITS_PER_WORD - 1)) \
+ / UNITS_PER_WORD) * (GET_MODE_SIZE (GET_MODE (R)) \
+ / GET_MODE_UNIT_SIZE (GET_MODE (R)))))
#ifndef SMALL_REGISTER_CLASSES
#define SMALL_REGISTER_CLASSES 0
--- gcc/reload.c.orig Mon Dec 15 12:55:27 1997
+++ gcc/reload.c Tue Jan 6 23:30:05 1998
@@ -2370,6 +2370,21 @@ find_reloads (insn, replace, ind_levels,
&& REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
return;
+ if (GET_CODE (SET_DEST (body)) == SUBREG
+ && GET_CODE (SUBREG_REG (SET_DEST (body))) == REG
+ && COMPLEX_MODE_P (GET_MODE (SUBREG_REG (SET_DEST (body)))))
+ {
+ rtx complex_dest = SUBREG_REG (SET_DEST (body));
+ int regno = REGNO (complex_dest) + SUBREG_WORD (SET_DEST (body));
+
+ if (regno < FIRST_PSEUDO_REGISTER
+ && GET_CODE (SET_SRC (body)) == REG
+ && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
+ && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
+ REGNO_REG_CLASS (regno)) == 2)
+ return;
+ }
+
case PARALLEL:
case ASM_OPERANDS:
reload_n_operands = noperands = asm_noperands (body);
@@ -2768,6 +2783,7 @@ find_reloads (insn, replace, ind_levels,
or which would handle that mode in the wrong number of
registers for subregging to work. */
|| (GET_CODE (operand) == REG
+ && !COMPLEX_MODE_P (GET_MODE (operand))
&& REGNO (operand) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (operand))
--- gcc/stmt.c.orig Fri Dec 19 11:41:53 1997
+++ gcc/stmt.c Wed Jan 7 16:47:02 1998
@@ -2620,19 +2620,59 @@ expand_value_return (val)
#ifdef PROMOTE_FUNCTION_RETURN
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
int unsignedp = TREE_UNSIGNED (type);
- enum machine_mode mode
- = promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)),
- &unsignedp, 1);
+ enum machine_mode mode_orig
+ = DECL_MODE (DECL_RESULT (current_function_decl));
+ enum machine_mode mode;
+ enum machine_mode submode;
+ enum machine_mode promoted_submode;
+ if (! COMPLEX_MODE_P (mode_orig))
+ {
+ mode = promote_mode (type, mode_orig, &unsignedp, 1);
+ }
+ else
+ {
+ submode = COMPLEX_SUBMODE (mode_orig);
+ promoted_submode
+ = promote_mode (type_for_mode (submode, unsignedp),
+ submode, &unsignedp, 1);
+ mode = mode_for_size (2 * GET_MODE_SIZE (promoted_submode)
+ * BITS_PER_UNIT,
+ GET_MODE_CLASS (mode_orig), 0);
+ }
+
if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
- convert_move (return_reg, val, unsignedp);
+ {
+ if (! COMPLEX_MODE_P (mode))
+ convert_move (return_reg, val, unsignedp);
+ else
+ {
+ convert_move (gen_realpart (promoted_submode, return_reg),
+ gen_realpart (submode, val), unsignedp);
+ convert_move (gen_imagpart (promoted_submode, return_reg),
+ gen_imagpart (submode, val), unsignedp);
+ }
+ }
else
#endif
emit_move_insn (return_reg, val);
}
if (GET_CODE (return_reg) == REG
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
- emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+ {
+ if (! COMPLEX_MODE_P (GET_MODE (return_reg)))
+ emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+ else
+ {
+ enum machine_mode submode = COMPLEX_SUBMODE (GET_MODE (return_reg));
+ int n = 2 * HARD_REGNO_NREGS (REGNO (return_reg), submode);
+ int k;
+
+ for (k = 0; k < n; k ++)
+ emit_insn (gen_rtx (USE, VOIDmode,
+ gen_rtx (REG, submode, REGNO (return_reg) + k)));
+ }
+ }
/* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */
else if (GET_CODE (return_reg) == PARALLEL)
next reply other threads:[~1998-02-10 3:34 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
1998-02-10 3:34 Weiwen Liu [this message]
-- strict thread matches above, loose matches on Subject: below --
1998-01-08 6:05 Weiwen Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.OSF.3.96.980107191012.10607C-100000@ylws39 \
--to=weiwen.liu@yale.edu \
--cc=egcs@cygnus.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).