diff options
author | amylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-06-13 17:44:56 +0000 |
---|---|---|
committer | amylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-06-13 17:44:56 +0000 |
commit | 2b2f5cfbdd0e559f9062c294bceb7f486b9cb9da (patch) | |
tree | 77b0e8646b86bb0b70f9dec160ea2b7da24fb530 /gcc | |
parent | 679f19b4de2f05a8dcc4d6218648b864bb3eb175 (diff) | |
download | gcc-2b2f5cfbdd0e559f9062c294bceb7f486b9cb9da.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@114616 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/sh/lib1funcs.asm | 48 | ||||
-rw-r--r-- | gcc/config/sh/lib1funcs.h | 12 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 31 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 15 | ||||
-rw-r--r-- | gcc/config/sh/t-sh | 9 | ||||
-rw-r--r-- | gcc/longlong.h | 41 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/div.C | 13 |
9 files changed, 175 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0707924a77d..b8a49a4c1d3 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 a815c3619e9..466b89046f3 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 566f3a5fc96..0e4100ee9ed 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 929b60f89c8..7e11e3f199d 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 d05fc10f840..41e06447e73 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 c81cc3fd020..3ebc09d6e3c 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 cdcabed6a40..c4131c67b21 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 9371ad6ff04..5a547a7db75 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 00000000000..14d7536ce19 --- /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; +} |