aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/config/sh/lib1funcs.asm48
-rw-r--r--gcc/config/sh/lib1funcs.h12
-rw-r--r--gcc/config/sh/sh.c31
-rw-r--r--gcc/config/sh/sh.md15
-rw-r--r--gcc/config/sh/t-sh9
-rw-r--r--gcc/longlong.h41
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/eh/div.C13
9 files changed, 175 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0707924..b8a49a4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/config/sh/lib1funcs.asm b/gcc/config/sh/lib1funcs.asm
index a815c36..466b890 100644
--- a/gcc/config/sh/lib1funcs.asm
+++ b/gcc/config/sh/lib1funcs.asm
@@ -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 */
diff --git a/gcc/config/sh/lib1funcs.h b/gcc/config/sh/lib1funcs.h
index 566f3a5..0e4100e 100644
--- a/gcc/config/sh/lib1funcs.h
+++ b/gcc/config/sh/lib1funcs.h
@@ -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__ */
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 929b60f..7e11e3f 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -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':
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index d05fc10..41e0644 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -1829,6 +1829,21 @@
/* 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]);
}
diff --git a/gcc/config/sh/t-sh b/gcc/config/sh/t-sh
index c81cc3f..3ebc09d 100644
--- a/gcc/config/sh/t-sh
+++ b/gcc/config/sh/t-sh
@@ -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
diff --git a/gcc/longlong.h b/gcc/longlong.h
index cdcabed..c4131c6 100644
--- a/gcc/longlong.h
+++ b/gcc/longlong.h
@@ -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) \
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9371ad6..5a547a7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..14d7536
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/div.C
@@ -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;
+}