From: J"orn Rennecke Date: Tue, 13 Jun 2006 17:44:56 +0000 (+0000) Subject: re PR target/28014 (space-optimized divide used inconsistently) X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=31b6f0aee8fc46282f06ceadc057e1b623f54872;p=platform%2Fupstream%2Fgcc.git 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 --- 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 + + 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 * configure.ac (HAS_MCONTEXT_T_UNDERSCORES): Include 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 + + PR target/28014: + * g++.dg/eh/div.C: New test. + 2006-06-13 Jakub Jelinek 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; +}