aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
authorJ"orn Rennecke <joern.rennecke@st.com>2006-06-13 17:44:56 +0000
committerJoern Rennecke <amylaar@gcc.gnu.org>2006-06-13 18:44:56 +0100
commit31b6f0aee8fc46282f06ceadc057e1b623f54872 (patch)
tree77b0e8646b86bb0b70f9dec160ea2b7da24fb530 /gcc/config/sh
parentde4fb767a9e80685a673a65b590774336f108c4f (diff)
downloadgcc-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.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
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