re PR target/28014 (space-optimized divide used inconsistently)
authorJ"orn Rennecke <joern.rennecke@st.com>
Tue, 13 Jun 2006 17:44:56 +0000 (17:44 +0000)
committerJoern Rennecke <amylaar@gcc.gnu.org>
Tue, 13 Jun 2006 17:44:56 +0000 (18:44 +0100)
        PR target/28014:

        gcc:
        * config/sh/t-sh (LIB1ASMFUNCS): Add _udiv_qrnnd16
        * config/sh/sh.c (print_operand): Add !SHMEDIA functionality to 'M'.
        * config/sh/lib1funcs.h (SL, SL1): Define.
        * config/sh/lib1funcs.asm (__udiv_qrnnd16): New hidden function.
        * longlong.h (__sh__): Define umul_ppmm, udiv_qrnnd and sub_ddmmss.
        * config/sh/t-sh ($(T)unwind-dw2-Os-4-200.o): New rule.
        (OBJS_Os_4_200): New variable.
        ($(T)libgcc-Os-4-200.a): Use it.
        * sh.md (udivsi3): For TARGET_DIVIDE_CALL_TABLE, avoid function call
        when dividing 1 and/or by 0.

        gcc/testsuite:
        * g++.dg/eh/div.C: New test.

From-SVN: r114616

gcc/ChangeLog
gcc/config/sh/lib1funcs.asm
gcc/config/sh/lib1funcs.h
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/config/sh/t-sh
gcc/longlong.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/eh/div.C [new file with mode: 0644]

index 0707924..b8a49a4 100644 (file)
@@ -1,3 +1,17 @@
+2006-06-06  J"orn Rennecke <joern.rennecke@st.com>
+
+       PR target/28014:
+       * config/sh/t-sh (LIB1ASMFUNCS): Add _udiv_qrnnd16
+       * config/sh/sh.c (print_operand): Add !SHMEDIA functionality to 'M'.
+       * config/sh/lib1funcs.h (SL, SL1): Define.
+       * config/sh/lib1funcs.asm (__udiv_qrnnd16): New hidden function.
+       * longlong.h (__sh__): Define umul_ppmm, udiv_qrnnd and sub_ddmmss.
+       * config/sh/t-sh ($(T)unwind-dw2-Os-4-200.o): New rule.
+       (OBJS_Os_4_200): New variable.
+       ($(T)libgcc-Os-4-200.a): Use it.
+       * sh.md (udivsi3): For TARGET_DIVIDE_CALL_TABLE, avoid function call
+       when dividing 1 and/or by 0.
+
 2006-06-13  Roger Sayle  <roger@eyesopen.com>
 
        * configure.ac (HAS_MCONTEXT_T_UNDERSCORES): Include <sys/signal.h>
index a815c36..466b890 100644 (file)
@@ -3843,3 +3843,51 @@ LOCAL(div_table_inv):
 #endif /* SH3 / SH4 */
 
 #endif /* L_div_table */
+
+#ifdef L_udiv_qrnnd_16
+#if !__SHMEDIA__
+       HIDDEN_FUNC(GLOBAL(udiv_qrnnd_16))
+       /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */
+       /* n1 < d, but n1 might be larger than d1.  */
+       .global GLOBAL(udiv_qrnnd_16)
+       .balign 8
+GLOBAL(udiv_qrnnd_16):
+       div0u
+       cmp/hi r6,r0
+       bt .Lots
+       .rept 16
+       div1 r6,r0 
+       .endr
+       extu.w r0,r1
+       bt 0f
+       add r6,r0
+0:     rotcl r1
+       mulu.w r1,r5
+       xtrct r4,r0
+       swap.w r0,r0
+       sts macl,r2
+       cmp/hs r2,r0
+       sub r2,r0
+       bt 0f
+       addc r5,r0
+       add #-1,r1
+       bt 0f
+1:     add #-1,r1
+       rts
+       add r5,r0
+       .balign 8
+.Lots:
+       sub r5,r0
+       swap.w r4,r1
+       xtrct r0,r1
+       clrt
+       mov r1,r0
+       addc r5,r0
+       mov #-1,r1
+       SL1(bf, 1b,
+       shlr16 r1)
+0:     rts
+       nop
+       ENDFUNC(GLOBAL(udiv_qrnnd_16))
+#endif /* !__SHMEDIA__ */
+#endif /* L_udiv_qrnnd_16 */
index 566f3a5..0e4100e 100644 (file)
@@ -67,3 +67,15 @@ Boston, MA 02110-1301, USA.  */
 #define DR40 fr4
 #define DR41 fr5
 #endif /* !__LITTLE_ENDIAN__ */
+
+#ifdef __sh1__
+#define SL(branch, dest, in_slot, in_slot_arg2) \
+       in_slot, in_slot_arg2; branch dest
+#define SL1(branch, dest, in_slot) \
+       in_slot; branch dest
+#else /* ! __sh1__ */
+#define SL(branch, dest, in_slot, in_slot_arg2) \
+       branch##.s dest; in_slot, in_slot_arg2
+#define SL1(branch, dest, in_slot) \
+       branch##/s dest; in_slot
+#endif /* !__sh1__ */
index 929b60f..7e11e3f 100644 (file)
@@ -662,7 +662,8 @@ print_operand_address (FILE *stream, rtx x)
    'R'  print the LSW of a dp value - changes if in little endian
    'S'  print the MSW of a dp value - changes if in little endian
    'T'  print the next word of a dp value - same as 'R' in big endian mode.
-   'M'  print an `x' if `m' will print `base,index'.
+   'M'  SHMEDIA: print an `x' if `m' will print `base,index'.
+        otherwise: print .b / .w / .l / .s / .d suffix if operand is a MEM.
    'N'  print 'r63' if the operand is (const_int 0).
    'd'  print a V2SF reg as dN instead of fpN.
    'm'  print a pair `base,offset' or `base,index', for LD and ST.
@@ -820,11 +821,29 @@ print_operand (FILE *stream, rtx x, int code)
        }
       break;
     case 'M':
-      if (GET_CODE (x) == MEM
-         && GET_CODE (XEXP (x, 0)) == PLUS
-         && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
-             || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
-       fputc ('x', stream);
+      if (TARGET_SHMEDIA)
+       {
+         if (GET_CODE (x) == MEM
+             && GET_CODE (XEXP (x, 0)) == PLUS
+             && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
+                 || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
+           fputc ('x', stream);
+       }
+      else
+       {
+         if (GET_CODE (x) == MEM)
+           {
+             switch (GET_MODE (x))
+               {
+               case QImode: fputs (".b", stream); break;
+               case HImode: fputs (".w", stream); break;
+               case SImode: fputs (".l", stream); break;
+               case SFmode: fputs (".s", stream); break;
+               case DFmode: fputs (".d", stream); break;
+               default: gcc_unreachable ();
+               }
+           }
+       }
       break;
 
     case 'm':
index d05fc10..41e0644 100644 (file)
   /* Emit the move of the address to a pseudo outside of the libcall.  */
   if (TARGET_DIVIDE_CALL_TABLE)
     {
+      /* libgcc2:__udivmoddi4 is not supposed to use an actual division, since
+        that causes problems when the divide code is supposed to come from a
+        separate library.  Division by zero is undefined, so dividing 1 can be
+        implemented by comparing with the divisor.  */
+      if (operands[1] == const1_rtx && currently_expanding_to_rtl)
+       {
+         emit_insn (gen_cmpsi (operands[1], operands[2]));
+         emit_insn (gen_sgeu (operands[0]));
+         DONE;
+       }
+      else if (operands[2] == const0_rtx)
+       {
+         emit_move_insn (operands[0], operands[2]);
+         DONE;
+       }
       function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT);
       last = gen_udivsi3_i4_int (operands[0], operands[3]);
     }
index c81cc3f..3ebc09d 100644 (file)
@@ -5,7 +5,7 @@ sh-c.o: $(srcdir)/config/sh/sh-c.c \
 LIB1ASMSRC = sh/lib1funcs.asm
 LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movmem \
   _movmem_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \
-  _div_table \
+  _div_table _udiv_qrnnd_16 \
   $(LIB1ASMFUNCS_CACHE)
 
 # We want fine grained libraries, so use the new code to build the
@@ -98,8 +98,11 @@ $(T)sdivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PAS
        $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_sdivsi3_i4i -x assembler-with-cpp $<
 $(T)udivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PASSES)
        $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_udivsi3_i4i -x assembler-with-cpp $<
-$(T)libgcc-Os-4-200.a: $(T)sdivsi3_i4i-Os-4-200.o $(T)udivsi3_i4i-Os-4-200.o $(GCC_PASSES)
-       $(AR_CREATE_FOR_TARGET) $@ $(T)sdivsi3_i4i-Os-4-200.o $(T)udivsi3_i4i-Os-4-200.o
+$(T)unwind-dw2-Os-4-200.o: $(srcdir)/unwind-dw2.c $(srcdir)/unwind-generic.h unwind-pe.h unwind.inc unwind-dw2-fde.h unwind-dw2.h $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h config.status stmp-int-hdrs tsystem.h $(GCC_PASSES)
+       $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) $(vis_hide) -fexceptions -Os -c -o $@ $<
+OBJS_Os_4_200=$(T)sdivsi3_i4i-Os-4-200.o $(T)udivsi3_i4i-Os-4-200.o $(T)unwind-dw2-Os-4-200.o
+$(T)libgcc-Os-4-200.a: $(OBJS_Os_4_200) $(GCC_PASSES)
+       $(AR_CREATE_FOR_TARGET) $@ $(OBJS_Os_4_200)
 
 # Local Variables:
 # mode: Makefile
index cdcabed..c4131c6 100644 (file)
@@ -831,18 +831,51 @@ UDItype __umulsidi3 (USItype, USItype);
   } while (0)
 #endif
 
-#if defined (__sh2__) && W_TYPE_SIZE == 32
+#if defined(__sh__) && !__SHMEDIA__ && W_TYPE_SIZE == 32
+#ifndef __sh1__
 #define umul_ppmm(w1, w0, u, v) \
   __asm__ (                                                            \
-       "dmulu.l        %2,%3\n\tsts    macl,%1\n\tsts  mach,%0"                \
-          : "=r" ((USItype)(w1)),                                      \
-            "=r" ((USItype)(w0))                                       \
+       "dmulu.l        %2,%3\n\tsts%M1 macl,%1\n\tsts%M0       mach,%0"        \
+          : "=r<" ((USItype)(w1)),                                     \
+            "=r<" ((USItype)(w0))                                      \
           : "r" ((USItype)(u)),                                        \
             "r" ((USItype)(v))                                         \
           : "macl", "mach")
 #define UMUL_TIME 5
 #endif
 
+/* This is the same algorithm as __udiv_qrnnd_c.  */
+#define UDIV_NEEDS_NORMALIZATION 1
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {                                                                 \
+    extern UWtype __udiv_qrnnd_16 (UWtype, UWtype)                     \
+                        __attribute__ ((visibility ("hidden")));       \
+    /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */ \
+    __asm__ (                                                          \
+       "mov%M4 %4,r5\n"                                                \
+"      swap.w %3,r4\n"                                                 \
+"      swap.w r5,r6\n"                                                 \
+"      jsr @%5\n"                                                      \
+"      shll16 r6\n"                                                    \
+"      swap.w r4,r4\n"                                                 \
+"      jsr @%5\n"                                                      \
+"      swap.w r1,%0\n"                                                 \
+"      or r1,%0"                                                       \
+       : "=r" (q), "=&z" (r)                                           \
+       : "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16)          \
+       : "r1", "r2", "r4", "r5", "r6", "pr");                          \
+  } while (0)
+
+#define UDIV_TIME 80
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)                             \
+  __asm__ ("clrt;subc %5,%1; subc %4,%0"                               \
+          : "=r" (sh), "=r" (sl)                                       \
+          : "0" (ah), "1" (al), "r" (bh), "r" (bl))
+
+#endif /* __sh__ */
+
 #if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32
 #define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
 #define count_leading_zeros(count, x) \
index 9371ad6..5a547a7 100644 (file)
@@ -1,3 +1,8 @@
+2006-06-13  J"orn Rennecke <joern.rennecke@st.com>
+
+       PR target/28014:
+       * g++.dg/eh/div.C: New test.
+
 2006-06-13  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/27894
diff --git a/gcc/testsuite/g++.dg/eh/div.C b/gcc/testsuite/g++.dg/eh/div.C
new file mode 100644 (file)
index 0000000..14d7536
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do link }
+// { dg-options "-Os" }
+/* PR target/28014: main references unsigned divide, and the unwinder
+   references signed divide.
+   If libgcc contains an object which defines both, and linking is done with
+   a space-optimized library that defines these functions in separate objects,
+   you end up with the function for unsigned divide defined twice.  */
+int
+main (int c, char **argv)
+
+{
+  return 0xffffU/c;
+}