> 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  <ebotca...@adacore.com>

        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 Botcazou
Index: 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;

Reply via email to