diff options
author | J"orn Rennecke <joern.rennecke@st.com> | 2006-06-13 17:44:56 +0000 |
---|---|---|
committer | Joern Rennecke <amylaar@gcc.gnu.org> | 2006-06-13 18:44:56 +0100 |
commit | 31b6f0aee8fc46282f06ceadc057e1b623f54872 (patch) | |
tree | 77b0e8646b86bb0b70f9dec160ea2b7da24fb530 /gcc/config/sh | |
parent | de4fb767a9e80685a673a65b590774336f108c4f (diff) | |
download | gcc-31b6f0aee8fc46282f06ceadc057e1b623f54872.zip gcc-31b6f0aee8fc46282f06ceadc057e1b623f54872.tar.gz gcc-31b6f0aee8fc46282f06ceadc057e1b623f54872.tar.bz2 |
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
Diffstat (limited to 'gcc/config/sh')
-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 |
5 files changed, 106 insertions, 9 deletions
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 |