re PR target/28014 (space-optimized divide used inconsistently)

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
This commit is contained in:
J"orn Rennecke 2006-06-13 17:44:56 +00:00 committed by Joern Rennecke
parent de4fb767a9
commit 31b6f0aee8
9 changed files with 175 additions and 13 deletions

View 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>

View 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 */

View 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__ */

View 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':

View file

@ -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]);
}

View 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

View 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) \

View 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

View file

@ -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;
}