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; })