Hi all, In my tree added a pattern to the arm backend that's supposed to match: (set (reg:SI r0) (subreg:SI (plus:DI (mult:DI (sign_extend:DI (reg:SI r1)) (sign_extend:DI (reg:SI r2))) (const_int 2147483648 [0x80000000])) 4))
That is, take two SImode regs, sign-extend to DImode, multiply in DImode, add a const_int and take the most significant SImode subreg. Combine matches it fine but I get an ICE in lra: 0xa665a5 crash_signal $SRC/gcc/toplev.c:383 0x91ec1c lra_emit_add(rtx_def*, rtx_def*, rtx_def*) $SRC/gcc/lra.c:418 0x91ef8a lra_emit_move(rtx_def*, rtx_def*) $SRC/gcc/lra.c:528 0x9279b2 insert_move_for_subreg $SRC/gcc/lra-constraints.c:1371 0x931bdb simplify_operand_subreg $SRC/gcc/lra-constraints.c:1507 0x931bdb curr_insn_transform $SRC/gcc/lra-constraints.c:3437 0x934793 lra_constraints(bool) $SRC/gcc/lra-constraints.c:4451 0x9217d0 lra(_IO_FILE*) $SRC/gcc/lra.c:2292 0x8e0dba do_reload $SRC/gcc/ira.c:5418 0x8e0dba execute $SRC/gcc/ira.c:5589 I *think* the problem is that simplify_operand_subreg tries to break down this complex RTX involving the subreg into separate MULT/PLUS operations and breaking down the line. If I apply the attached patch that stops trying to simplify the subreg expression if the whole thing matches something already my code compiles succesfully, and passes arm testing and x86_64 bootstrap. However, I'm concerned that calling recog_memoized is too heavy-handed, is there a better approach? Or is this even the right way to go about this? I'm also attaching the patch to the arm backend that can be used to reproduce this ICE with the following C-code at -O2: int smmulr (int a, int b) { return ((long long)a * b + 0x80000000) >> 32; } Thanks, Kyrill 2015-02-10 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * lra-constraints.c (simplify_operand_subreg): Do not try to simplify subreg if the pattern already matches.
commit e21706a7e06aace9fb76040867561f6fac748ab8 Author: Kyrylo Tkachov <kyrylo.tkac...@arm.com> Date: Tue Feb 10 10:20:07 2015 +0000 [LRA][tmp] Do no try to simplify into subregs if whole insn has a match diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 827c453..5cb0422 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -1467,7 +1467,8 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) /* Force a reload of the SUBREG_REG if this is a constant or PLUS or if there may be a problem accessing OPERAND in the outer mode. */ - if ((REG_P (reg) + if (recog_memoized (curr_insn) < 0 + && ((REG_P (reg) && REGNO (reg) >= FIRST_PSEUDO_REGISTER && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0 /* Don't reload paradoxical subregs because we could be looping @@ -1479,7 +1480,7 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) /* Don't reload subreg for matching reload. It is actually valid subreg in LRA. */ && ! LRA_SUBREG_P (operand)) - || CONSTANT_P (reg) || GET_CODE (reg) == PLUS || MEM_P (reg)) + || CONSTANT_P (reg) || GET_CODE (reg) == PLUS || MEM_P (reg))) { enum reg_class rclass;
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index c13e9b2..8cf8776 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -1549,6 +1549,22 @@ (define_insn "*mulsidi3_v6" (set_attr "predicable_short_it" "no")] ) +(define_insn "*mulsidi3si_round_v6" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 3 "subreg_highpart_operator" + [(plus:DI + (mult:DI + (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r")) + (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))) + (const_int 2147483648)) +]))] + "TARGET_32BIT && arm_arch6" + "smmulr%?\\t%0, %1, %2" + [(set_attr "type" "smmulr") + (set_attr "predicable" "yes") + (set_attr "predicable_short_it" "no")] +) + (define_expand "umulsidi3" [(set (match_operand:DI 0 "s_register_operand" "") (mult:DI diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 08cc899..aeb21c1 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -117,6 +117,14 @@ (define_special_predicate "subreg_lowpart_operator" (and (match_code "subreg") (match_test "subreg_lowpart_p (op)"))) +(define_special_predicate "subreg_highpart_operator" + (and (match_code "subreg") + (match_test "GET_MODE_SIZE (mode) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) + && SUBREG_BYTE (op) + == subreg_highpart_offset (mode, + GET_MODE (SUBREG_REG (op)))"))) + ;; Reg, subreg(reg) or const_int. (define_predicate "reg_or_int_operand" (ior (match_code "const_int")