[RFC? PATCH]: Fix PR rtl-optimization/26449, ICE in loop invariant motion

Zdenek Dvorak rakdver@kam.mff.cuni.cz
Sat Sep 15 19:31:00 GMT 2007


Hello,

> (insn 147 146 148 21 loop-15.c:11 (set (subreg:V4SI (reg:V2DI 131) 0)
>         (vec_select:V4SI (vec_concat:V8SI (reg:V4SI 139)
>                 (reg:V4SI 134))
>             (parallel [
>                     (const_int 0 [0x0])
>                     (const_int 4 [0x4])
>                     (const_int 1 [0x1])
>                     (const_int 5 [0x5])
>                 ]))) 1270 {sse2_punpckldq} (nil))
> 
> 
> By changing the code around line 1215 to
> 
> --cut here--
>      /* If the SET_DEST of the invariant insn is a pseudo, we can just move
>     the insn out of the loop.  Otherwise, we have to use gen_move_insn
>     to let emit_move_insn produce a valid instruction stream.  */
>      if ((REG_P (dest) && !HARD_REGISTER_P (dest))
>      || (GET_CODE (dest) == SUBREG && REG_P (SUBREG_REG (dest))
>          && !HARD_REGISTER_P (SUBREG_REG (dest))))
>    {
> --cut here--
> 
> we pass SUBREG of the pseudo through the same path, decomposing above 
> insn into (invariant):
> 
> (insn 147 146 151 2 loop-15.c:12 (set (reg:V4SI 153)
>        (vec_select:V4SI (vec_concat:V8SI (reg:V4SI 139)
>                (reg:V4SI 152))
>            (parallel [
>                    (const_int 0 [0x0])
>                    (const_int 4 [0x4])
>                    (const_int 1 [0x1])
>                    (const_int 5 [0x5])
>                ]))) 1270 {sse2_punpckldq} (nil))

I think there is no guarantee that subreg can be replaced by a register
and you will still obtain a valid insn.  I think for now the best way
might be to avoid using force_operand completely, like in the patch
below.  There are probably some cases where this change will make us
avoid doing the invariant motion, but if some of them shows to be
important, we may re-introduce handling for it in some safer way later.

force_operand was originally added here to enable us to change

(set (mem:DF (plus:SI (reg/f:SI 7 sp)
                 (const_int 8 [0x8])) [0 S8 A32])
        (const_double:DF -858993460 [0xcccccccc]
2.00000000000000011102230246251565404236316680908e-1
[0x0.ccccccccccccdp-2]))

to (set (mem:DF (plus:SI (reg/f:SI 7 sp)
                 (const_int 8 [0x8])) [0 S8 A32])
        (reg:DF the_invariant_register))

where loading the constant to (reg:DF the_invariant_register) has to be
done using force_operand; this does not seem to be all that important to
me.

Zdenek

Index: loop-invariant.c
===================================================================
*** loop-invariant.c	(revision 128372)
--- loop-invariant.c	(working copy)
*************** find_invariants_to_move (void)
*** 1154,1173 ****
      }
  }
  
- /* Returns true if all insns in SEQ are valid.  */
- 
- static bool
- seq_insns_valid_p (rtx seq)
- {
-   rtx x;
- 
-   for (x = seq; x; x = NEXT_INSN (x))
-     if (insn_invalid_p (x))
-       return false;
- 
-   return true;
- }
- 
  /* Move invariant INVNO out of the LOOP.  Returns true if this succeeds, false
     otherwise.  */
  
--- 1154,1159 ----
*************** move_invariant_reg (struct loop *loop, u
*** 1178,1184 ****
    struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
    unsigned i;
    basic_block preheader = loop_preheader_edge (loop)->src;
!   rtx reg, set, dest, seq, op;
    struct use *use;
    bitmap_iterator bi;
  
--- 1164,1170 ----
    struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
    unsigned i;
    basic_block preheader = loop_preheader_edge (loop)->src;
!   rtx reg, set, dest, note;
    struct use *use;
    bitmap_iterator bi;
  
*************** move_invariant_reg (struct loop *loop, u
*** 1209,1257 ****
        dest = SET_DEST (set);
        reg = gen_reg_rtx (GET_MODE (dest));
  
!       /* If the SET_DEST of the invariant insn is a pseudo, we can just move
! 	 the insn out of the loop.  Otherwise, we have to use gen_move_insn
! 	 to let emit_move_insn produce a valid instruction stream.  */
!       if (REG_P (dest) && !HARD_REGISTER_P (dest))
! 	{
! 	  rtx note;
  
! 	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
! 	  SET_DEST (set) = reg;
! 	  df_insn_rescan (inv->insn);
! 	  reorder_insns (inv->insn, inv->insn, BB_END (preheader));
! 
! 	  /* If there is a REG_EQUAL note on the insn we just moved, and
! 	     insn is in a basic block that is not always executed, the note
! 	     may no longer be valid after we move the insn.
! 	     Note that uses in REG_EQUAL notes are taken into account in
! 	     the computation of invariants.  Hence it is safe to retain the
! 	     note even if the note contains register references.  */
! 	  if (! inv->always_executed
! 	      && (note = find_reg_note (inv->insn, REG_EQUAL, NULL_RTX)))
! 	    remove_note (inv->insn, note);
! 	}
!       else
! 	{
! 	  start_sequence ();
! 	  op = force_operand (SET_SRC (set), reg);
! 	  if (!op)
! 	    {
! 	      end_sequence ();
! 	      goto fail;
! 	    }
! 	  if (op != reg)
! 	    emit_move_insn (reg, op);
! 	  seq = get_insns ();
! 	  end_sequence ();
! 
! 	  if (!seq_insns_valid_p (seq))
! 	    goto fail;
! 	  emit_insn_after (seq, BB_END (preheader));
!       
! 	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
! 	  delete_insn (inv->insn);
! 	}
      }
    else
      {
--- 1195,1217 ----
        dest = SET_DEST (set);
        reg = gen_reg_rtx (GET_MODE (dest));
  
!       /* Try replacing the destination by a new pseudoregister.  */
!       if (!validate_change (inv->insn, &SET_DEST (set), reg, false))
! 	goto fail;
!       df_insn_rescan (inv->insn);
  
!       emit_insn_after (gen_move_insn (dest, reg), inv->insn);
!       reorder_insns (inv->insn, inv->insn, BB_END (preheader));
! 
!       /* If there is a REG_EQUAL note on the insn we just moved, and
! 	 insn is in a basic block that is not always executed, the note
! 	 may no longer be valid after we move the insn.
! 	 Note that uses in REG_EQUAL notes are taken into account in
! 	 the computation of invariants.  Hence it is safe to retain the
! 	 note even if the note contains register references.  */
!       if (! inv->always_executed
! 	  && (note = find_reg_note (inv->insn, REG_EQUAL, NULL_RTX)))
! 	remove_note (inv->insn, note);
      }
    else
      {



More information about the Gcc-patches mailing list