From 3e0cef6dddb0eeba482ef43bbca8eeac4b57666a Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Tue, 13 Sep 2011 09:23:36 +0000 Subject: [PATCH] re PR target/50358 (AVR: Implement [u]maddqihi4 [u]msubqihi4 patterns on the enhanced core) PR target/50358 * config/avr/predicates.md (const_1_to_6_operand): New predicate. * config/avr/avr.md: (extend_s): New code attribute. (mul_r_d): New code attribute. (*maddqihi4, *umaddqihi4): New insns. (*msubqihi4, *umsubqihi4): New insns. (*usmaddqihi4, *sumaddqihi4): New insns. (*usmsubqihi4, *susubdqihi4): New insns. (*umaddqihi4.uconst, *maddqihi4.sconst): New insn-and-splits. (*umsubqihi4.uconst, *msubqihi4.sconst): New insn-and-splits. (*umsubqihi4.uconst.ashift): New insn-and-split. (*msubqihi4.sconst.ashift): New insn-and-split. (*sumaddqihi4.uconst): New insn-and-split. (*sumsubqihi4.uconst): New insn-and-split. * config/avr/avr.c (avr_rtx_costs): Report costs of above in case PLUS:HI and MINUS:HI. From-SVN: r178806 --- gcc/ChangeLog | 19 +++ gcc/config/avr/avr.c | 21 +++ gcc/config/avr/avr.md | 270 +++++++++++++++++++++++++++++++++++ gcc/config/avr/predicates.md | 5 + 4 files changed, 315 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ef42f55a4f5..020e8483dd3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2011-09-13 Georg-Johann Lay + + PR target/50358 + * config/avr/predicates.md (const_1_to_6_operand): New predicate. + * config/avr/avr.md: (extend_s): New code attribute. + (mul_r_d): New code attribute. + (*maddqihi4, *umaddqihi4): New insns. + (*msubqihi4, *umsubqihi4): New insns. + (*usmaddqihi4, *sumaddqihi4): New insns. + (*usmsubqihi4, *susubdqihi4): New insns. + (*umaddqihi4.uconst, *maddqihi4.sconst): New insn-and-splits. + (*umsubqihi4.uconst, *msubqihi4.sconst): New insn-and-splits. + (*umsubqihi4.uconst.ashift): New insn-and-split. + (*msubqihi4.sconst.ashift): New insn-and-split. + (*sumaddqihi4.uconst): New insn-and-split. + (*sumsubqihi4.uconst): New insn-and-split. + * config/avr/avr.c (avr_rtx_costs): Report costs of above in case + PLUS:HI and MINUS:HI. + 2011-09-13 Revital Eres modulo-sched.c (remove_node_from_ps): Return void instead of bool. diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index b6793bc82ca..773aec2442d 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -5576,6 +5576,16 @@ avr_rtx_costs (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED, break; case HImode: + if (AVR_HAVE_MUL + && (MULT == GET_CODE (XEXP (x, 0)) + || ASHIFT == GET_CODE (XEXP (x, 0))) + && register_operand (XEXP (x, 1), HImode) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)))) + { + *total = COSTS_N_INSNS (speed ? 5 : 4); + return true; + } if (GET_CODE (XEXP (x, 1)) != CONST_INT) { *total = COSTS_N_INSNS (2); @@ -5608,6 +5618,17 @@ avr_rtx_costs (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED, return true; case MINUS: + if (AVR_HAVE_MUL + && HImode == mode + && register_operand (XEXP (x, 0), HImode) + && (MULT == GET_CODE (XEXP (x, 1)) + || ASHIFT == GET_CODE (XEXP (x, 1))) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)))) + { + *total = COSTS_N_INSNS (speed ? 5 : 4); + return true; + } case AND: case IOR: *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)); diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index c120afdb026..8721314e73b 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -150,6 +150,15 @@ [(sign_extend "") (zero_extend "u")]) +(define_code_attr extend_s + [(sign_extend "s") + (zero_extend "")]) + +;; Constrain input operand of widening multiply, i.e. MUL resp. MULS. +(define_code_attr mul_r_d + [(zero_extend "r") + (sign_extend "d")]) + ;;======================================================================== ;; The following is used by nonlocal_goto and setjmp. @@ -1128,6 +1137,267 @@ [(set_attr "length" "4") (set_attr "cc" "clobber")]) +;****************************************************************************** +; multiply-add/sub HI: $0 = $3 +/- $1*$2 with 8-bit values $1, $2 +;****************************************************************************** + +;; We don't use standard insns/expanders as they lead to cumbersome code for, +;; e.g, +;; +;; int foo (unsigned char z) +;; { +;; extern int aInt[]; +;; return aInt[3*z+2]; +;; } +;; +;; because the constant +4 then is added explicitely instead of consuming it +;; with the aInt symbol. Therefore, we rely on insn combine which takes costs +;; into account more accurately and doesn't do burte-force multiply-add/sub. +;; The implementational effort is the same so we are fine with that approach. + + +;; "*maddqihi4" +;; "*umaddqihi4" +(define_insn "*maddqihi4" + [(set (match_operand:HI 0 "register_operand" "=r") + (plus:HI (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "")) + (any_extend:HI (match_operand:QI 2 "register_operand" ""))) + (match_operand:HI 3 "register_operand" "0")))] + + "AVR_HAVE_MUL" + "mul %1,%2 + add %A0,r0 + adc %B0,r1 + clr __zero_reg__" + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +;; "*msubqihi4" +;; "*umsubqihi4" +(define_insn "*msubqihi4" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "")) + (any_extend:HI (match_operand:QI 2 "register_operand" "")))))] + "AVR_HAVE_MUL" + "mul %1,%2 + sub %A0,r0 + sbc %B0,r1 + clr __zero_reg__" + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +;; "*usmaddqihi4" +;; "*sumaddqihi4" +(define_insn "*msubqihi4" + [(set (match_operand:HI 0 "register_operand" "=r") + (plus:HI (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "a")) + (any_extend2:HI (match_operand:QI 2 "register_operand" "a"))) + (match_operand:HI 3 "register_operand" "0")))] + "AVR_HAVE_MUL + && reload_completed + && != " + { + output_asm_insn ( == SIGN_EXTEND + ? "mulsu %1,%2" : "mulsu %2,%1", operands); + + return "add %A0,r0\;adc %B0,r1\;clr __zero_reg__"; + } + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +;; "*usmsubqihi4" +;; "*sumsubqihi4" +(define_insn "*msubqihi4" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "a")) + (any_extend2:HI (match_operand:QI 2 "register_operand" "a")))))] + "AVR_HAVE_MUL + && reload_completed + && != " + { + output_asm_insn ( == SIGN_EXTEND + ? "mulsu %1,%2" : "mulsu %2,%1", operands); + + return "sub %A0,r0\;sbc %B0,r1\;clr __zero_reg__"; + } + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +;; Handle small constants + +(define_insn_and_split "*umaddqihi4.uconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (plus:HI (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) + (match_operand:HI 2 "u8_operand" "M")) + (match_operand:HI 3 "register_operand" "0"))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *umaddqihi4 + (set (match_dup 0) + (plus:HI (mult:HI (zero_extend:HI (match_dup 1)) + (zero_extend:HI (match_dup 4))) + (match_dup 3)))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) + +(define_insn_and_split "*umsubqihi4.uconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) + (match_operand:HI 2 "u8_operand" "M")))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *umsubqihi4 + (set (match_dup 0) + (minus:HI (match_dup 3) + (mult:HI (zero_extend:HI (match_dup 1)) + (zero_extend:HI (match_dup 4)))))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) + +;; Same as the insn above, but combiner tries versions canonicalized to ASHIFT +;; for MULT with power of 2 and skips trying MULT insn above. + +(define_insn_and_split "*umsubqihi4.uconst.ashift" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (ashift:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r")) + (match_operand:HI 2 "const_2_to_7_operand" "n")))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *umsubqihi4 + (set (match_dup 0) + (minus:HI (match_dup 3) + (mult:HI (zero_extend:HI (match_dup 1)) + (zero_extend:HI (match_dup 4)))))] + { + operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode); + }) + +(define_insn_and_split "*maddqihi4.sconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (plus:HI (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d")) + (match_operand:HI 2 "s8_operand" "n")) + (match_operand:HI 3 "register_operand" "0"))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *maddqihi4 + (set (match_dup 0) + (plus:HI (mult:HI (sign_extend:HI (match_dup 1)) + (sign_extend:HI (match_dup 4))) + (match_dup 3)))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) + +(define_insn_and_split "*msubqihi4.sconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d")) + (match_operand:HI 2 "s8_operand" "M")))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *smsubqihi4 + (set (match_dup 0) + (minus:HI (match_dup 3) + (mult:HI (sign_extend:HI (match_dup 1)) + (sign_extend:HI (match_dup 4)))))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) + +;; Same as the insn above, but combiner tries versions canonicalized to ASHIFT +;; for MULT with power of 2 and skips trying MULT insn above. We omit 128 +;; because this would require an extra pattern for just one value. + +(define_insn_and_split "*msubqihi4.sconst.ashift" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "d")) + (match_operand:HI 2 "const_1_to_6_operand" "M")))) + (clobber (match_scratch:QI 4 "=&d"))] + "AVR_HAVE_MUL" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *smsubqihi4 + (set (match_dup 0) + (minus:HI (match_dup 3) + (mult:HI (sign_extend:HI (match_dup 1)) + (sign_extend:HI (match_dup 4)))))] + { + operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode); + }) + +;; For signed/unsigned combinations that require narrow constraint "a" +;; just provide a pattern if signed/unsigned combination is actually needed. + +(define_insn_and_split "*sumaddqihi4.uconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (plus:HI (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a")) + (match_operand:HI 2 "u8_operand" "M")) + (match_operand:HI 3 "register_operand" "0"))) + (clobber (match_scratch:QI 4 "=&a"))] + "AVR_HAVE_MUL + && !s8_operand (operands[2], VOIDmode)" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *sumaddqihi4 + (set (match_dup 0) + (plus:HI (mult:HI (sign_extend:HI (match_dup 1)) + (zero_extend:HI (match_dup 4))) + (match_dup 3)))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) + +(define_insn_and_split "*sumsubqihi4.uconst" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (match_operand:HI 3 "register_operand" "0") + (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "a")) + (match_operand:HI 2 "u8_operand" "M")))) + (clobber (match_scratch:QI 4 "=&a"))] + "AVR_HAVE_MUL + && !s8_operand (operands[2], VOIDmode)" + "#" + "&& reload_completed" + [(set (match_dup 4) + (match_dup 2)) + ; *sumsubqihi4 + (set (match_dup 0) + (minus:HI (match_dup 3) + (mult:HI (sign_extend:HI (match_dup 1)) + (zero_extend:HI (match_dup 4)))))] + { + operands[2] = gen_int_mode (INTVAL (operands[2]), QImode); + }) ;****************************************************************************** ; mul HI: $1 = sign/zero-extend, $2 = small constant diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md index 98262d54f55..1881e8b5162 100644 --- a/gcc/config/avr/predicates.md +++ b/gcc/config/avr/predicates.md @@ -78,6 +78,11 @@ (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), 2, 7)"))) +;; Return 1 if OP is constant integer 1..6 for MODE. +(define_predicate "const_1_to_6_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 1, 6)"))) + ;; Return 1 if OP is constant integer 2..6 for MODE. (define_predicate "const_2_to_6_operand" (and (match_code "const_int") -- 2.30.2