aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2011-12-14 10:00:56 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2011-12-14 10:00:56 +0000
commitd7288dfb9fac1451adede96e855c8fde9ee5f2c1 (patch)
treeda23e4e79b412c8171d2375bf3121ad99e702e08 /gcc
parent552d2db5659aae080edbfdb27f446a98334b323d (diff)
downloadgcc-d7288dfb9fac1451adede96e855c8fde9ee5f2c1.zip
gcc-d7288dfb9fac1451adede96e855c8fde9ee5f2c1.tar.gz
gcc-d7288dfb9fac1451adede96e855c8fde9ee5f2c1.tar.bz2
re PR target/50931 ([avr] Support a 24-bit scalar integer mode)
libgcc/ PR target/50931 * config/avr/t-avr (LIB1ASMSRC): Add _mulpsi3, _mulsqipsi3. * config/avr/lib1funcs.S (__mulpsi3, __mulsqipsi3): New functions. gcc/ 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. testsuite/ PR target/50931 * gcc.target/avr/torture/int24-mul.c: New testcase. From-SVN: r182328
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/avr/avr.md157
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/int24-mul.c86
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;
+}