Commit 1e5d7fd6 by Alexandre Oliva Committed by Alexandre Oliva

[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
parent 4d6ca95b
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> 2015-11-26 Maciej W. Rozycki <macro@imgtec.com>
* doc/invoke.texi (Option Summary) <MIPS Options>: Reorder * doc/invoke.texi (Option Summary) <MIPS Options>: Reorder
...@@ -3002,6 +3002,38 @@ assign_parm_setup_block (struct assign_parm_data_all *all, ...@@ -3002,6 +3002,38 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
emit_move_insn (change_address (mem, mode, 0), reg); 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 /* Blocks smaller than a word on a BYTES_BIG_ENDIAN
machine must be aligned to the left before storing machine must be aligned to the left before storing
to memory. Note that the previous test doesn't to memory. Note that the previous test doesn't
...@@ -3023,14 +3055,20 @@ assign_parm_setup_block (struct assign_parm_data_all *all, ...@@ -3023,14 +3055,20 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
tem = change_address (mem, word_mode, 0); tem = change_address (mem, word_mode, 0);
emit_move_insn (tem, x); emit_move_insn (tem, x);
} }
else if (!MEM_P (mem))
emit_move_insn (mem, entry_parm);
else else
move_block_from_reg (REGNO (entry_parm), mem, move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD); size_stored / UNITS_PER_WORD);
} }
else if (!MEM_P (mem)) else if (!MEM_P (mem))
{
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); emit_move_insn (mem, entry_parm);
}
else else
move_block_from_reg (REGNO (entry_parm), mem, move_block_from_reg (REGNO (entry_parm), mem,
size_stored / UNITS_PER_WORD); size_stored / UNITS_PER_WORD);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment