mirror of git://gcc.gnu.org/git/gcc.git
[PR67753] adjust for padding when bypassing memory in assign_parm_setup_block
Storing a register in memory as a full word and then accessing the same memory address under a smaller-than-word mode amounts to right-shifting of the register word on big endian machines. So, if BLOCK_REG_PADDING chooses upward padding for BYTES_BIG_ENDIAN, and we're copying from the entry_parm REG directly to a pseudo, bypassing any stack slot, perform the shifting explicitly. This fixes the miscompile of function_return_val_10 in gcc.target/aarch64/aapcs64/func-ret-4.c for target aarch64_be-elf introduced in the first patch for 67753. for gcc/ChangeLog PR rtl-optimization/67753 PR rtl-optimization/64164 * function.c (assign_parm_setup_block): Right-shift upward-padded big-endian args when bypassing the stack slot. From-SVN: r230985
This commit is contained in:
parent
4d6ca95b9a
commit
1e5d7fd638
|
|
@ -1,3 +1,10 @@
|
|||
2015-11-26 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
PR rtl-optimization/67753
|
||||
PR rtl-optimization/64164
|
||||
* function.c (assign_parm_setup_block): Right-shift
|
||||
upward-padded big-endian args when bypassing the stack slot.
|
||||
|
||||
2015-11-26 Maciej W. Rozycki <macro@imgtec.com>
|
||||
|
||||
* doc/invoke.texi (Option Summary) <MIPS Options>: Reorder
|
||||
|
|
|
|||
|
|
@ -3002,6 +3002,38 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
|
|||
emit_move_insn (change_address (mem, mode, 0), reg);
|
||||
}
|
||||
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
/* Storing the register in memory as a full word, as
|
||||
move_block_from_reg below would do, and then using the
|
||||
MEM in a smaller mode, has the effect of shifting right
|
||||
if BYTES_BIG_ENDIAN. If we're bypassing memory, the
|
||||
shifting must be explicit. */
|
||||
else if (!MEM_P (mem))
|
||||
{
|
||||
rtx x;
|
||||
|
||||
/* If the assert below fails, we should have taken the
|
||||
mode != BLKmode path above, unless we have downward
|
||||
padding of smaller-than-word arguments on a machine
|
||||
with little-endian bytes, which would likely require
|
||||
additional changes to work correctly. */
|
||||
gcc_checking_assert (BYTES_BIG_ENDIAN
|
||||
&& (BLOCK_REG_PADDING (mode,
|
||||
data->passed_type, 1)
|
||||
== upward));
|
||||
|
||||
int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
|
||||
|
||||
x = gen_rtx_REG (word_mode, REGNO (entry_parm));
|
||||
x = expand_shift (RSHIFT_EXPR, word_mode, x, by,
|
||||
NULL_RTX, 1);
|
||||
x = force_reg (word_mode, x);
|
||||
x = gen_lowpart_SUBREG (GET_MODE (mem), x);
|
||||
|
||||
emit_move_insn (mem, x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN
|
||||
machine must be aligned to the left before storing
|
||||
to memory. Note that the previous test doesn't
|
||||
|
|
@ -3023,14 +3055,20 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
|
|||
tem = change_address (mem, word_mode, 0);
|
||||
emit_move_insn (tem, x);
|
||||
}
|
||||
else if (!MEM_P (mem))
|
||||
emit_move_insn (mem, entry_parm);
|
||||
else
|
||||
move_block_from_reg (REGNO (entry_parm), mem,
|
||||
size_stored / UNITS_PER_WORD);
|
||||
}
|
||||
else if (!MEM_P (mem))
|
||||
emit_move_insn (mem, entry_parm);
|
||||
{
|
||||
gcc_checking_assert (size > UNITS_PER_WORD);
|
||||
#ifdef BLOCK_REG_PADDING
|
||||
gcc_checking_assert (BLOCK_REG_PADDING (GET_MODE (mem),
|
||||
data->passed_type, 0)
|
||||
== upward);
|
||||
#endif
|
||||
emit_move_insn (mem, entry_parm);
|
||||
}
|
||||
else
|
||||
move_block_from_reg (REGNO (entry_parm), mem,
|
||||
size_stored / UNITS_PER_WORD);
|
||||
|
|
|
|||
Loading…
Reference in New Issue