https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68623

            Bug ID: 68623
           Summary: lra doesn't check predicate after reloading an early
                    clobber
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mrs at gcc dot gnu.org
  Target Milestone: ---

lra doesn't check the predicate after reload an output register to ensure the
instruction remains valid. The predicate is the load_multiple_operation and it
ensures that the hard registers are sequential.  When the first output register
is the same as the address, then the input register must be reloaded.  The
output register cannot be, unless all the output registers are and then the
specific property embodied by load_multiple_operation would need to be
preserved.  Here is the pattern:

(define_insn "*ldmdi2"
 [(match_parallel 0 "load_multiple_operation"
   [(set (match_operand:DI 1 "a_hard_register_operand" "=&r")
         (mem:DI (match_operand:DI 2 "register_operand" "r")))
    (set (match_operand:DI 3 "c1_hard_register_operand" "")
         (mem:DI (plus:DI (match_dup 2) (match_operand 4 "const_int_operand"
"KS10"))))])]
 ""
 "ldm\t%1,{%2,%3|0(%2),2}"
 [(set_attr "type" "ldm")
  (set_attr "count" "2")])

and the instruction after reload:

(insn 28 27 55 2 (parallel [
            (set (reg:DI 27 $work1 [208])
                (mem:DI (reg/v/f:DI 19 $a1 [orig:187 p ] [187]) [0  S8 A64]))
            (set (reg:DI 20 $a2)
                (mem:DI (plus:DI (reg/v/f:DI 19 $a1 [orig:187 p ] [187])
                        (const_int 8 [0x8])) [0  S8 A64]))
        ]) t.c:28 349 {*ldmdi2}
     (nil))

before reload, $a1 is set in the first set.  $a1 and $a2 are sequential.  The
predicate:

(define_predicate "load_multiple_operation"
  (match_code "parallel")
{
  int count = XVECLEN (op, 0);                                                  
  int dest_regno;                                                               
  rtx src_addr;                                                                 
  int i;                                                                        

  /* Perform a quick check so we don't blow up below.  */
  if (count <= 1
      || GET_CODE (XVECEXP (op, 0, 0)) != SET
      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
    return 0;                                                                   

  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));                           
  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);                            

  if (dest_regno >= FIRST_PSEUDO_REGISTER
      || (dest_regno + count) > FIRST_PSEUDO_REGISTER)
    return 0;                                                                   


  /* Check, is base, or base + displacement.  */

  if (GET_CODE (src_addr) != REG)
    return 0;                                                                   

  for (i = 1; i < count; i++)                                                   
    {
      rtx elt = XVECEXP (op, 0, i);                                             
      if (debugit) {
        printf("i = %d\n",i);                                                   
        debug_rtx(elt);                                                         
      }
      if (GET_CODE (elt) != SET
          || GET_CODE (SET_DEST (elt)) != REG
          || GET_MODE (SET_DEST (elt)) != DImode
          || REGNO (SET_DEST (elt)) != (unsigned) (dest_regno + i)
          || GET_CODE (SET_SRC (elt)) != MEM
          || GET_MODE (SET_SRC (elt)) != DImode
          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
          || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
          || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
          || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 8)
        return 0;                                                               
    }

  return 1;                                                                     
})

Reply via email to