summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgavin <gavin@138bc75d-0d04-0410-961f-82ee72b054a4>1998-10-01 13:00:21 +0000
committergavin <gavin@138bc75d-0d04-0410-961f-82ee72b054a4>1998-10-01 13:00:21 +0000
commit25eb0f5951809b0eb1014fd79a628160f452ac20 (patch)
tree9b145af594c102bee9b10b504ce7129d9016e08b
parente115fee2ed4cb2c3b4407f6457aa82ae6d54aa1f (diff)
downloadppe42-gcc-25eb0f5951809b0eb1014fd79a628160f452ac20.tar.gz
ppe42-gcc-25eb0f5951809b0eb1014fd79a628160f452ac20.zip
* calls.c (expand_call) : Encapsulate code into
copy_blkmode_from_reg. * expr.c (copy_blkmode_from_reg): New function. * expr.h (copy_blkmode_from_reg): New function. * integrate.c (function_cannot_inline_p): We can inline these now. (expand_inline_function): Use copy_blkmode_from_reg if needed. Avoid creating BLKmode REGs. (copy_rtx_and_substitute): Don't try to SUBREG a BLKmode object. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@22714 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/calls.c70
-rw-r--r--gcc/expr.c82
-rw-r--r--gcc/expr.h5
-rw-r--r--gcc/integrate.c32
5 files changed, 126 insertions, 76 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ce607e1509e..f4e7eab7e38 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+Thu Oct 1 15:56:01 1998 Gavin Romig-Koch <gavin@cygnus.com>
+
+ * calls.c (expand_call) : Encapsulate code into
+ copy_blkmode_from_reg.
+ * expr.c (copy_blkmode_from_reg): New function.
+ * expr.h (copy_blkmode_from_reg): New function.
+ * integrate.c (function_cannot_inline_p): We can inline
+ these now.
+ (expand_inline_function): Use copy_blkmode_from_reg
+ if needed. Avoid creating BLKmode REGs.
+ (copy_rtx_and_substitute): Don't try to SUBREG a BLKmode
+ object.
+
Thu Oct 1 10:42:27 1998 Nick Clifton <nickc@cygnus.com>
* c-pragma.c: Add support for HANDLE_PRAGMA_PACK and
diff --git a/gcc/calls.c b/gcc/calls.c
index 728d6d68a5d..2bddc2a32a1 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -2105,75 +2105,7 @@ expand_call (exp, target, ignore)
when function inlining is being done. */
emit_move_insn (target, valreg);
else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
- {
- /* Some machines (the PA for example) want to return all small
- structures in registers regardless of the structure's alignment.
-
- Deal with them explicitly by copying from the return registers
- into the target MEM locations. */
- int bytes = int_size_in_bytes (TREE_TYPE (exp));
- rtx src = NULL, dst = NULL;
- int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
- int bitpos, xbitpos, big_endian_correction = 0;
-
- if (target == 0)
- {
- target = assign_stack_temp (BLKmode, bytes, 0);
- MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
- preserve_temp_slots (target);
- }
-
- /* This code assumes valreg is at least a full word. If it isn't,
- copy it into a new pseudo which is a full word. */
- if (GET_MODE (valreg) != BLKmode
- && GET_MODE_SIZE (GET_MODE (valreg)) < UNITS_PER_WORD)
- valreg = convert_to_mode (word_mode, valreg,
- TREE_UNSIGNED (TREE_TYPE (exp)));
-
- /* Structures whose size is not a multiple of a word are aligned
- to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
- machine, this means we must skip the empty high order bytes when
- calculating the bit offset. */
- if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
- big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
- * BITS_PER_UNIT));
-
- /* Copy the structure BITSIZE bites at a time.
-
- We could probably emit more efficient code for machines
- which do not use strict alignment, but it doesn't seem
- worth the effort at the current time. */
- for (bitpos = 0, xbitpos = big_endian_correction;
- bitpos < bytes * BITS_PER_UNIT;
- bitpos += bitsize, xbitpos += bitsize)
- {
-
- /* We need a new source operand each time xbitpos is on a
- word boundary and when xbitpos == big_endian_correction
- (the first time through). */
- if (xbitpos % BITS_PER_WORD == 0
- || xbitpos == big_endian_correction)
- src = operand_subword_force (valreg,
- xbitpos / BITS_PER_WORD,
- BLKmode);
-
- /* We need a new destination operand each time bitpos is on
- a word boundary. */
- if (bitpos % BITS_PER_WORD == 0)
- dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, BLKmode);
-
- /* Use xbitpos for the source extraction (right justified) and
- xbitpos for the destination store (left justified). */
- store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
- extract_bit_field (src, bitsize,
- xbitpos % BITS_PER_WORD, 1,
- NULL_RTX, word_mode,
- word_mode,
- bitsize / BITS_PER_UNIT,
- BITS_PER_WORD),
- bitsize / BITS_PER_UNIT, BITS_PER_WORD);
- }
- }
+ target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp));
else
target = copy_to_reg (valreg);
diff --git a/gcc/expr.c b/gcc/expr.c
index 3582f5b9124..445f1516156 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2064,6 +2064,88 @@ emit_group_store (orig_dst, src, ssize, align)
emit_move_insn (orig_dst, dst);
}
+/* Generate code to copy a BLKmode object of TYPE out of a
+ set of registers starting with SRCREG into TGTBLK. If TGTBLK
+ is null, a stack temporary is created. TGTBLK is returned.
+
+ The primary purpose of this routine is to handle functions
+ that return BLKmode structures in registers. Some machines
+ (the PA for example) want to return all small structures
+ in registers regardless of the structure's alignment.
+ */
+
+rtx
+copy_blkmode_from_reg(tgtblk,srcreg,type)
+ rtx tgtblk;
+ rtx srcreg;
+ tree type;
+{
+ int bytes = int_size_in_bytes (type);
+ rtx src = NULL, dst = NULL;
+ int bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
+ int bitpos, xbitpos, big_endian_correction = 0;
+
+ if (tgtblk == 0)
+ {
+ tgtblk = assign_stack_temp (BLKmode, bytes, 0);
+ MEM_IN_STRUCT_P (tgtblk) = AGGREGATE_TYPE_P (type);
+ preserve_temp_slots (tgtblk);
+ }
+
+ /* This code assumes srcreg is at least a full word. If it isn't,
+ copy it into a new pseudo which is a full word. */
+ if (GET_MODE (srcreg) != BLKmode
+ && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
+ srcreg = convert_to_mode (word_mode, srcreg,
+ TREE_UNSIGNED (type));
+
+ /* Structures whose size is not a multiple of a word are aligned
+ to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
+ machine, this means we must skip the empty high order bytes when
+ calculating the bit offset. */
+ if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
+ big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
+ * BITS_PER_UNIT));
+
+ /* Copy the structure BITSIZE bites at a time.
+
+ We could probably emit more efficient code for machines
+ which do not use strict alignment, but it doesn't seem
+ worth the effort at the current time. */
+ for (bitpos = 0, xbitpos = big_endian_correction;
+ bitpos < bytes * BITS_PER_UNIT;
+ bitpos += bitsize, xbitpos += bitsize)
+ {
+
+ /* We need a new source operand each time xbitpos is on a
+ word boundary and when xbitpos == big_endian_correction
+ (the first time through). */
+ if (xbitpos % BITS_PER_WORD == 0
+ || xbitpos == big_endian_correction)
+ src = operand_subword_force (srcreg,
+ xbitpos / BITS_PER_WORD,
+ BLKmode);
+
+ /* We need a new destination operand each time bitpos is on
+ a word boundary. */
+ if (bitpos % BITS_PER_WORD == 0)
+ dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
+
+ /* Use xbitpos for the source extraction (right justified) and
+ xbitpos for the destination store (left justified). */
+ store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
+ extract_bit_field (src, bitsize,
+ xbitpos % BITS_PER_WORD, 1,
+ NULL_RTX, word_mode,
+ word_mode,
+ bitsize / BITS_PER_UNIT,
+ BITS_PER_WORD),
+ bitsize / BITS_PER_UNIT, BITS_PER_WORD);
+ }
+ return tgtblk;
+}
+
+
/* Add a USE expression for REG to the (possibly empty) list pointed
to by CALL_FUSAGE. REG must denote a hard register. */
diff --git a/gcc/expr.h b/gcc/expr.h
index 6d8d22a84d3..353e6fdfe46 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -732,6 +732,11 @@ extern void emit_group_load PROTO((rtx, rtx, int, int));
PARALLEL. */
extern void emit_group_store PROTO((rtx, rtx, int, int));
+#ifdef TREE_CODE
+/* Copy BLKmode object from a set of registers. */
+extern rtx copy_blkmode_from_reg PROTO((rtx,rtx,tree));
+#endif
+
/* Mark REG as holding a parameter for the next CALL_INSN. */
extern void use_reg PROTO((rtx *, rtx));
/* Mark NREGS consecutive regs, starting at REGNO, as holding parameters
diff --git a/gcc/integrate.c b/gcc/integrate.c
index d3fb05bbbfc..db82e322b06 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -154,11 +154,6 @@ function_cannot_inline_p (fndecl)
if (current_function_returns_pcc_struct)
return "inline functions not supported for this return value type";
- /* We can't inline functions that return BLKmode structures in registers. */
- if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
- && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
- return "inline functions not supported for this return value type";
-
/* We can't inline functions that return structures of varying size. */
if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
return "function with varying-size return value cannot be inline";
@@ -1804,7 +1799,23 @@ expand_inline_function (fndecl, parms, target, ignore, type,
Let the combiner substitute the MEM if that is valid. */
if (target == 0 || GET_CODE (target) != REG
|| GET_MODE (target) != departing_mode)
+ {
+ /* Don't make BLKmode registers. If this looks like
+ a BLKmode object being returned in a register, get
+ the mode from that, otherwise abort. */
+ if (departing_mode == BLKmode)
+ {
+ if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl))))
+ {
+ departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
+ arriving_mode = departing_mode;
+ }
+ else
+ abort();
+ }
+
target = gen_reg_rtx (departing_mode);
+ }
/* If function's value was promoted before return,
avoid machine mode mismatch when we substitute INLINE_TARGET.
@@ -2164,6 +2175,12 @@ expand_inline_function (fndecl, parms, target, ignore, type,
emit_line_note (input_filename, lineno);
+ /* If the function returns a BLKmode object in a register, copy it
+ out of the temp register into a BLKmode memory object. */
+ if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
+ && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
+ target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
+
if (structure_value_addr)
{
target = gen_rtx_MEM (TYPE_MODE (type),
@@ -2428,12 +2445,13 @@ copy_rtx_and_substitute (orig, map)
{
/* This is a reference to the function return value. If
the function doesn't have a return value, error. If the
- mode doesn't agree, make a SUBREG. */
+ mode doesn't agree, and it ain't BLKmode, make a SUBREG. */
if (map->inline_target == 0)
/* Must be unrolling loops or replicating code if we
reach here, so return the register unchanged. */
return orig;
- else if (mode != GET_MODE (map->inline_target))
+ else if (GET_MODE (map->inline_target) != BLKmode
+ && mode != GET_MODE (map->inline_target))
return gen_lowpart (mode, map->inline_target);
else
return map->inline_target;
OpenPOWER on IntegriCloud