diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 157 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/int24-mul.c | 86 |
4 files changed, 256 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d792244..c9e927a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2011-12-14 Georg-Johann Lay <avr@gjlay.de> + + PR target/50931 + * config/avr/avr.md (mulpsi3): New expander. + (*umulqihipsi3, *umulhiqipsi3): New insns. + (*mulsqipsi3.libgcc, *mulpsi3.libgcc): New insns. + (mulsqipsi3, *mulpsi3): New insn-and-splits. + (ashlpsi3): Turn to expander. Move insn code to... + (*ashlpsi3): ...this new insn. + 2011-12-14 Richard Guenther <rguenther@suse.de> * tree-cfg.c (replace_uses_by): Only mark blocks altered diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 940a46f..21e329b 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -2113,7 +2113,7 @@ [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) -;; To support widening multiplicatioon with constant we postpone +;; To support widening multiplication with constant we postpone ;; expanding to the implicit library call until post combine and ;; prior to register allocation. Clobber all hard registers that ;; might be used by the (widening) multiply until it is split and @@ -2575,6 +2575,132 @@ (set_attr "cc" "clobber")]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 24-bit multiply + +;; To support widening multiplication with constant we postpone +;; expanding to the implicit library call until post combine and +;; prior to register allocation. Clobber all hard registers that +;; might be used by the (widening) multiply until it is split and +;; it's final register footprint is worked out. + +(define_expand "mulpsi3" + [(parallel [(set (match_operand:PSI 0 "register_operand" "") + (mult:PSI (match_operand:PSI 1 "register_operand" "") + (match_operand:PSI 2 "nonmemory_operand" ""))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))])] + "AVR_HAVE_MUL" + { + if (s8_operand (operands[2], PSImode)) + { + rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode)); + emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1])); + DONE; + } + }) + +(define_insn "*umulqihipsi3" + [(set (match_operand:PSI 0 "register_operand" "=&r") + (mult:PSI (zero_extend:PSI (match_operand:QI 1 "register_operand" "r")) + (zero_extend:PSI (match_operand:HI 2 "register_operand" "r"))))] + "AVR_HAVE_MUL" + "mul %1,%A2 + movw %A0,r0 + mul %1,%B2 + clr %C0 + add %B0,r0 + adc %C0,r1 + clr __zero_reg__" + [(set_attr "length" "7") + (set_attr "cc" "clobber")]) + +(define_insn "*umulhiqipsi3" + [(set (match_operand:PSI 0 "register_operand" "=&r") + (mult:PSI (zero_extend:PSI (match_operand:HI 2 "register_operand" "r")) + (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))))] + "AVR_HAVE_MUL" + "mul %1,%A2 + movw %A0,r0 + mul %1,%B2 + add %B0,r0 + mov %C0,r1 + clr __zero_reg__ + adc %C0,__zero_reg__" + [(set_attr "length" "7") + (set_attr "cc" "clobber")]) + +(define_insn_and_split "mulsqipsi3" + [(set (match_operand:PSI 0 "pseudo_register_operand" "=r") + (mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" "r")) + (match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn"))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))] + "AVR_HAVE_MUL && !reload_completed" + { gcc_unreachable(); } + "&& 1" + [(set (reg:QI 25) + (match_dup 1)) + (set (reg:PSI 22) + (match_dup 2)) + (set (reg:PSI 18) + (mult:PSI (sign_extend:PSI (reg:QI 25)) + (reg:PSI 22))) + (set (match_dup 0) + (reg:PSI 18))]) + +(define_insn_and_split "*mulpsi3" + [(set (match_operand:PSI 0 "pseudo_register_operand" "=r") + (mult:PSI (match_operand:PSI 1 "pseudo_register_operand" "r") + (match_operand:PSI 2 "pseudo_register_or_const_int_operand" "rn"))) + (clobber (reg:HI 26)) + (clobber (reg:DI 18))] + "AVR_HAVE_MUL && !reload_completed" + { gcc_unreachable(); } + "&& 1" + [(set (reg:PSI 18) + (match_dup 1)) + (set (reg:PSI 22) + (match_dup 2)) + (parallel [(set (reg:PSI 22) + (mult:PSI (reg:PSI 22) + (reg:PSI 18))) + (clobber (reg:QI 21)) + (clobber (reg:QI 25)) + (clobber (reg:HI 26))]) + (set (match_dup 0) + (reg:PSI 22))] + { + if (s8_operand (operands[2], PSImode)) + { + rtx reg = force_reg (QImode, gen_int_mode (INTVAL (operands[2]), QImode)); + emit_insn (gen_mulsqipsi3 (operands[0], reg, operands[1])); + DONE; + } + }) + +(define_insn "*mulsqipsi3.libgcc" + [(set (reg:PSI 18) + (mult:PSI (sign_extend:PSI (reg:QI 25)) + (reg:PSI 22)))] + "AVR_HAVE_MUL" + "%~call __mulsqipsi3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +(define_insn "*mulpsi3.libgcc" + [(set (reg:PSI 22) + (mult:PSI (reg:PSI 22) + (reg:PSI 18))) + (clobber (reg:QI 21)) + (clobber (reg:QI 25)) + (clobber (reg:HI 26))] + "AVR_HAVE_MUL" + "%~call __mulpsi3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 24-bit signed/unsigned division and modulo. ;; Notice that the libgcc implementation return the quotient in R22 ;; and the remainder in R18 whereas the 32-bit [u]divmodsi4 @@ -3363,7 +3489,34 @@ (set_attr "adjust_len" "ashlsi") (set_attr "cc" "none,set_n,clobber,clobber")]) -(define_insn "ashlpsi3" +(define_expand "ashlpsi3" + [(parallel [(set (match_operand:PSI 0 "register_operand" "") + (ashift:PSI (match_operand:PSI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (scratch:QI))])] + "" + { + if (AVR_HAVE_MUL + && CONST_INT_P (operands[2])) + { + if (IN_RANGE (INTVAL (operands[2]), 3, 6)) + { + rtx xoffset = force_reg (QImode, gen_int_mode (1 << INTVAL (operands[2]), QImode)); + emit_insn (gen_mulsqipsi3 (operands[0], xoffset, operands[1])); + DONE; + } + else if (optimize_insn_for_speed_p () + && INTVAL (operands[2]) != 16 + && IN_RANGE (INTVAL (operands[2]), 9, 22)) + { + rtx xoffset = force_reg (PSImode, gen_int_mode (1 << INTVAL (operands[2]), PSImode)); + emit_insn (gen_mulpsi3 (operands[0], operands[1], xoffset)); + DONE; + } + } + }) + +(define_insn "*ashlpsi3" [(set (match_operand:PSI 0 "register_operand" "=r,r,r,r") (ashift:PSI (match_operand:PSI 1 "register_operand" "0,0,r,0") (match_operand:QI 2 "nonmemory_operand" "r,P,O,n"))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 93c7377..81d50c9d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-12-14 Georg-Johann Lay <avr@gjlay.de> + + PR target/50931 + * gcc.target/avr/torture/int24-mul.c: New. + 2011-12-14 Dodji Seketeli <dodji@redhat.com> PR c++/51476 diff --git a/gcc/testsuite/gcc.target/avr/torture/int24-mul.c b/gcc/testsuite/gcc.target/avr/torture/int24-mul.c new file mode 100644 index 0000000..084e5a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/int24-mul.c @@ -0,0 +1,86 @@ +/* { dg-do run } */ +/* { dg-options "-w" } */ + +#include <stdlib.h> + +const __pgm __int24 vals[] = + { + 0, 1, 2, 3, -1, -2, -3, 0xff, 0x100, 0x101, + 0xffL * 0xff, 0xfffL * 0xfff, 0x101010L, 0xaaaaaaL + }; + +void test_u (void) +{ + unsigned int i; + unsigned long la, lb, lc; + __uint24 a, b, c; + + int S = sizeof (vals) / sizeof (*vals); + + for (i = 0; i < 500; i++) + { + if (i < S*S) + { + a = vals[i / S]; + b = vals[i % S]; + } + else + { + if (i & 1) + a += 0x7654321L; + else + b += 0x5fe453L; + } + + c = a * b; + + la = a; + lb = b; + lc = 0xffffff & (la * lb); + + if (c != lc) + abort(); + } +} + +#define TEST_N_U(A1,A2,B) \ + do { \ + if ((0xffffff & (A1*B)) != A2*B) \ + abort(); \ + } while (0) + +void test_nu (void) +{ + unsigned long la; + unsigned int i; + int S = sizeof (vals) / sizeof (*vals); + __uint24 a; + + for (i = 0; i < 500; i++) + { + a = i < S + ? vals[i % S] + : a + 0x7654321; + + la = a; + + TEST_N_U (la, a, 2); + TEST_N_U (la, a, 3); + TEST_N_U (la, a, 4); + TEST_N_U (la, a, 5); + TEST_N_U (la, a, 15); + TEST_N_U (la, a, 16); + TEST_N_U (la, a, 128); + TEST_N_U (la, a, 0x1000); + } +} + +int main (void) +{ + test_u(); + test_nu(); + + exit(0); + + return 0; +} |