> On the following testcase we ICE on i686-linux (32-bit), because we store
> (first 96-bit, then 72-bit) structure into the first part of a 2x 96-bit
> complex long double, and for 96-bit floats there is no corresponding
> integral mode that covers it and we ICE when op0 is not in MEM (it is a
> REG).
The test triggers an ICE in simplify_subreg because the innermode is BLKmode:
gcc_assert (innermode != BLKmode);
on PowerPC64/VxWorks at -O1 and above. This comes from this call:
if (MEM_P (result))
from_rtx = change_address (result, to_mode, NULL_RTX);
else
from_rtx
= simplify_gen_subreg (to_mode, result,
TYPE_MODE (TREE_TYPE (from)), 0);
in expand_assignment, where 'result' is not a MEM despite TREE_TYPE (from)
having BLKmode. That's as expected because 'from' is a CALL_EXPR whose result
is returned as a TImode register to avoid using BLKmode and thus spilling it
to memory in between.
It turns out that simplify_subreg contains another assertion:
gcc_assert (GET_MODE (op) == innermode
|| GET_MODE (op) == VOIDmode);
so we can equivalently pass GET_MODE (result) as the mode, except when it is
VOIDmode in which case we can still use TYPE_MODE (TREE_TYPE (from)).
Tested on PowerPC64/VxWorks and x86-64/Linux, applied on mainline as obvious.
2019-12-07 Eric Botcazou <[email protected]>
PR middle-end/90840
* expr.c (expand_assignment): In the case of a CONCAT on the LHS, make
sure to pass a valid inner mode in calls to simplify_gen_subreg.
--
Eric BotcazouIndex: expr.c
===================================================================
--- expr.c (revision 278938)
+++ expr.c (working copy)
@@ -5285,13 +5285,16 @@ expand_assignment (tree to, tree from, b
}
else
{
+ machine_mode from_mode
+ = GET_MODE (result) == VOIDmode
+ ? TYPE_MODE (TREE_TYPE (from))
+ : GET_MODE (result);
rtx from_rtx;
if (MEM_P (result))
from_rtx = change_address (result, to_mode, NULL_RTX);
else
from_rtx
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)), 0);
+ = simplify_gen_subreg (to_mode, result, from_mode, 0);
if (from_rtx)
{
emit_move_insn (XEXP (to_rtx, 0),
@@ -5303,12 +5306,9 @@ expand_assignment (tree to, tree from, b
{
to_mode = GET_MODE_INNER (to_mode);
rtx from_real
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)),
- 0);
+ = simplify_gen_subreg (to_mode, result, from_mode, 0);
rtx from_imag
- = simplify_gen_subreg (to_mode, result,
- TYPE_MODE (TREE_TYPE (from)),
+ = simplify_gen_subreg (to_mode, result, from_mode,
GET_MODE_SIZE (to_mode));
if (!from_real || !from_imag)
goto concat_store_slow;