summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-20 21:00:23 +0000
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-20 21:00:23 +0000
commit7e91b548b970eb3b300adad4d1e58587dfd170a2 (patch)
tree98407a614491ba2e6e3f90bd531334efd0366b60 /gcc
parentc8fbcf5814ca7d33e2ed28e487be37e72372c18e (diff)
downloadgcc-7e91b548b970eb3b300adad4d1e58587dfd170a2.tar.gz
PR rtl-optimization/54315
* calls.c (expand_call): Don't deal specifically with BLKmode values returned in naked registers. * expr.h (copy_blkmode_from_reg): Adjust prototype. * expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and make it required. Assert that SRCREG hasn't BLKmode. Add a couple of short-circuits for common cases and be prepared for sub-word registers. (expand_assignment): Call copy_blkmode_from_reg for BLKmode values returned in naked registers. (store_expr): Likewise. (store_field): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192641 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/calls.c10
-rw-r--r--gcc/expr.c131
-rw-r--r--gcc/expr.h2
4 files changed, 98 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0403a90eb45..7a1aff9b248 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2012-10-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR rtl-optimization/54315
+ * calls.c (expand_call): Don't deal specifically with BLKmode values
+ returned in naked registers.
+ * expr.h (copy_blkmode_from_reg): Adjust prototype.
+ * expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and
+ make it required. Assert that SRCREG hasn't BLKmode. Add a couple of
+ short-circuits for common cases and be prepared for sub-word registers.
+ (expand_assignment): Call copy_blkmode_from_reg for BLKmode values
+ returned in naked registers.
+ (store_expr): Likewise.
+ (store_field): Likewise.
+
2012-10-20 Jan Hubicka <jh@suse.cz>
* loop-unroll.c (decide_unroll_constant_iterations): Don't
diff --git a/gcc/calls.c b/gcc/calls.c
index d4ef639dc10..64e4b09870c 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3327,16 +3327,6 @@ expand_call (tree exp, rtx target, int ignore)
sibcall_failure = 1;
}
}
- else if (TYPE_MODE (rettype) == BLKmode)
- {
- rtx val = valreg;
- if (GET_MODE (val) != BLKmode)
- val = avoid_likely_spilled_reg (val);
- target = copy_blkmode_from_reg (target, val, rettype);
-
- /* We can not support sibling calls for this case. */
- sibcall_failure = 1;
- }
else
target = copy_to_reg (avoid_likely_spilled_reg (valreg));
diff --git a/gcc/expr.c b/gcc/expr.c
index 8fa19fd5ce1..f00ae6a9eac 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2086,39 +2086,23 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
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.
+/* Copy a BLKmode object of TYPE out of a register SRCREG into TARGET.
- The 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. */
+ This is used on targets that return BLKmode values in registers. */
-rtx
-copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
+void
+copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
{
unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
rtx src = NULL, dst = NULL;
unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
+ enum machine_mode mode = GET_MODE (srcreg);
+ enum machine_mode tmode = GET_MODE (target);
enum machine_mode copy_mode;
- if (tgtblk == 0)
- {
- tgtblk = assign_temp (build_qualified_type (type,
- (TYPE_QUALS (type)
- | TYPE_QUAL_CONST)),
- 1, 1);
- 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, TYPE_UNSIGNED (type));
+ /* BLKmode registers created in the back-end shouldn't have survived. */
+ gcc_assert (mode != BLKmode);
/* If the structure doesn't take up a whole number of words, see whether
SRCREG is padded on the left or on the right. If it's on the left,
@@ -2136,22 +2120,54 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
padding_correction
= (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
+ /* We can use a single move if we have an exact mode for the size. */
+ else if (MEM_P (target)
+ && (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
+ || MEM_ALIGN (target) >= GET_MODE_ALIGNMENT (mode))
+ && bytes == GET_MODE_SIZE (mode))
+ {
+ emit_move_insn (adjust_address (target, mode, 0), srcreg);
+ return;
+ }
+
+ /* And if we additionally have the same mode for a register. */
+ else if (REG_P (target)
+ && GET_MODE (target) == mode
+ && bytes == GET_MODE_SIZE (mode))
+ {
+ emit_move_insn (target, srcreg);
+ return;
+ }
+
+ /* 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_SIZE (mode) < UNITS_PER_WORD)
+ {
+ srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
+ mode = word_mode;
+ }
+
/* Copy the structure BITSIZE bits at a time. If the target lives in
memory, take care of not reading/writing past its end by selecting
a copy mode suited to BITSIZE. This should always be possible given
how it is computed.
+ If the target lives in register, make sure not to select a copy mode
+ larger than the mode of the register.
+
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. */
copy_mode = word_mode;
- if (MEM_P (tgtblk))
+ if (MEM_P (target))
{
enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
if (mem_mode != BLKmode)
copy_mode = mem_mode;
}
+ else if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
+ copy_mode = tmode;
for (bitpos = 0, xbitpos = padding_correction;
bitpos < bytes * BITS_PER_UNIT;
@@ -2160,15 +2176,15 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
/* We need a new source operand each time xbitpos is on a
word boundary and when xbitpos == padding_correction
(the first time through). */
- if (xbitpos % BITS_PER_WORD == 0
- || xbitpos == padding_correction)
- src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
- GET_MODE (srcreg));
+ if (xbitpos % BITS_PER_WORD == 0 || xbitpos == padding_correction)
+ src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD, mode);
/* 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);
+ if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
+ dst = target;
+ else if (bitpos % BITS_PER_WORD == 0)
+ dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, tmode);
/* Use xbitpos for the source extraction (right justified) and
bitpos for the destination store (left justified). */
@@ -2177,8 +2193,6 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
xbitpos % BITS_PER_WORD, 1, false,
NULL_RTX, copy_mode, copy_mode));
}
-
- return tgtblk;
}
/* Copy BLKmode value SRC into a register of mode MODE. Return the
@@ -4883,7 +4897,12 @@ expand_assignment (tree to, tree from, bool nontemporal)
emit_group_store (to_rtx, value, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
else if (GET_MODE (to_rtx) == BLKmode)
- emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
+ {
+ if (REG_P (value))
+ copy_blkmode_from_reg (to_rtx, value, TREE_TYPE (from));
+ else
+ emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
+ }
else
{
if (POINTER_TYPE_P (TREE_TYPE (to)))
@@ -5225,21 +5244,26 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
supposed to be bit-copied or bit-initialized. */
&& expr_size (exp) != const0_rtx)
{
- if (GET_MODE (temp) != GET_MODE (target)
- && GET_MODE (temp) != VOIDmode)
+ if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode)
{
- int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
- if (GET_MODE (target) == BLKmode
- && GET_MODE (temp) == BLKmode)
- emit_block_move (target, temp, expr_size (exp),
- (call_param_p
- ? BLOCK_OP_CALL_PARM
- : BLOCK_OP_NORMAL));
- else if (GET_MODE (target) == BLKmode)
- store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
- 0, 0, 0, GET_MODE (temp), temp);
+ if (GET_MODE (target) == BLKmode)
+ {
+ if (REG_P (temp))
+ {
+ if (TREE_CODE (exp) == CALL_EXPR)
+ copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
+ else
+ store_bit_field (target,
+ INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+ 0, 0, 0, GET_MODE (temp), temp);
+ }
+ else
+ emit_block_move (target, temp, expr_size (exp),
+ (call_param_p
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+ }
else
- convert_move (target, temp, unsignedp);
+ convert_move (target, temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
}
else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
@@ -6328,7 +6352,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
twice, once with emit_move_insn and once via store_field. */
if (mode == BLKmode
- && (REG_P (target) || GET_CODE (target) == SUBREG))
+ && (REG_P (target) || GET_CODE (target) == SUBREG)
+ && TREE_CODE (exp) != CALL_EXPR)
{
rtx object = assign_temp (type, 1, 1);
rtx blk_object = adjust_address (object, BLKmode, 0);
@@ -6477,6 +6502,16 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
temp = temp_target;
}
+ /* Handle calls that return BLKmode values in registers. */
+ else if (mode == BLKmode
+ && REG_P (temp)
+ && TREE_CODE (exp) == CALL_EXPR)
+ {
+ rtx temp_target = gen_reg_rtx (GET_MODE (temp));
+ copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
+ temp = temp_target;
+ }
+
/* Store the value in the bitfield. */
store_bit_field (target, bitsize, bitpos,
bitregion_start, bitregion_end,
diff --git a/gcc/expr.h b/gcc/expr.h
index 562ffe03aca..0f5e8541fb0 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -335,7 +335,7 @@ extern rtx emit_group_move_into_temps (rtx);
extern void emit_group_store (rtx, rtx, tree, int);
/* Copy BLKmode object from a set of registers. */
-extern rtx copy_blkmode_from_reg (rtx, rtx, tree);
+extern void copy_blkmode_from_reg (rtx, rtx, tree);
/* Mark REG as holding a parameter for the next CALL_INSN.
Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode. */