mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-15 22:51:38 +08:00
config.gcc: Add v850e-*-* target.
2002-08-27 Nick Clifton <nickc@redhat.com> Catherine Moore <clm@redhat.com> Jim Wilson <wilson@cygnus.com> * config.gcc: Add v850e-*-* target. Add --with-cpu= support for v850. * config/v850/lib1funcs.asm: Add v850e callt functions. * config/v850/v850.h: Add support for v850e target. * config/v850/v850.c: Add functions to support v850e target. * config/v850/v850-protos.h: Add prototypes for new functions in v850.c. * config/v850/v850.md: Add patterns for v850e instructions. * doc/invoke.texi: Document new v850e command line switches. Co-Authored-By: Catherine Moore <clm@redhat.com> Co-Authored-By: Jim Wilson <wilson@cygnus.com> From-SVN: r56612
This commit is contained in:
parent
361d6b4285
commit
b43783196f
@ -1,3 +1,16 @@
|
||||
2002-08-27 Nick Clifton <nickc@redhat.com>
|
||||
Catherine Moore <clm@redhat.com>
|
||||
Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
* config.gcc: Add v850e-*-* target.
|
||||
Add --with-cpu= support for v850.
|
||||
* config/v850/lib1funcs.asm: Add v850e callt functions.
|
||||
* config/v850/v850.h: Add support for v850e target.
|
||||
* config/v850/v850.c: Add functions to support v850e target.
|
||||
* config/v850/v850-protos.h: Add prototypes for new functions in v850.c.
|
||||
* config/v850/v850.md: Add patterns for v850e instructions.
|
||||
* doc/invoke.texi: Document new v850e command line switches.
|
||||
|
||||
Tue Aug 27 18:30:47 2002 J"orn Rennecke <joern.rennecke@superh.com>
|
||||
Aldy Hernandez <aldyh at redhat dot com>
|
||||
|
||||
|
@ -2643,6 +2643,21 @@ v850-*-rtems*)
|
||||
c_target_objs="v850-c.o"
|
||||
cxx_target_objs="v850-c.o"
|
||||
;;
|
||||
v850e-*-*)
|
||||
target_cpu_default="TARGET_CPU_v850e"
|
||||
tm_file="dbxelf.h elfos.h svr4.h v850/v850.h"
|
||||
tm_p_file=v850/v850-protos.h
|
||||
tmake_file=v850/t-v850
|
||||
md_file=v850/v850.md
|
||||
out_file=v850/v850.c
|
||||
if test x$stabs = xyes
|
||||
then
|
||||
tm_file="${tm_file} dbx.h"
|
||||
fi
|
||||
use_collect2=no
|
||||
c_target_objs="v850-c.o"
|
||||
cxx_target_objs="v850-c.o"
|
||||
;;
|
||||
v850-*-*)
|
||||
target_cpu_default="TARGET_CPU_generic"
|
||||
tm_file="dbxelf.h elfos.h svr4.h ${tm_file}"
|
||||
@ -2952,6 +2967,22 @@ sparc*-*-*)
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
v850*-*-*)
|
||||
case "x$with_cpu" in
|
||||
x)
|
||||
;;
|
||||
v850e)
|
||||
target_cpu_default2="TARGET_CPU_$with_cpu"
|
||||
;;
|
||||
*)
|
||||
if test x$pass2done = xyes
|
||||
then
|
||||
echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$target_cpu_default2" != ""
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* libgcc routines for NEC V850.
|
||||
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
@ -1114,7 +1114,7 @@ __return_r29_r31:
|
||||
.type __save_r31,@function
|
||||
/* Allocate space and save register 31 on the stack */
|
||||
/* Also allocate space for the argument save area */
|
||||
/* Called via: jalr __save_r29_r31,r10 */
|
||||
/* Called via: jalr __save_r31,r10 */
|
||||
__save_r31:
|
||||
addi -20,sp,sp
|
||||
st.w r31,16[sp]
|
||||
@ -1130,7 +1130,7 @@ __return_r31:
|
||||
ld.w 16[sp],r31
|
||||
addi 20,sp,sp
|
||||
jmp [r31]
|
||||
.size __return_r29_r31,.-__return_r29_r31
|
||||
.size __return_r31,.-__return_r31
|
||||
#endif /* L_save_31c */
|
||||
|
||||
#ifdef L_save_varargs
|
||||
@ -1267,3 +1267,378 @@ __restore_all_interrupt:
|
||||
jmp [r10]
|
||||
.size __restore_all_interrupt,.-__restore_all_interrupt
|
||||
#endif /* L_save_all_interrupt */
|
||||
|
||||
|
||||
#if defined __v850e__
|
||||
#ifdef L_callt_save_r2_r29
|
||||
/* Put these functions into the call table area. */
|
||||
.call_table_text
|
||||
|
||||
/* Allocate space and save registers 2, 20 .. 29 on the stack. */
|
||||
/* Called via: callt ctoff(__callt_save_r2_r29). */
|
||||
.align 2
|
||||
.L_save_r2_r29:
|
||||
add -4, sp
|
||||
st.w r2, 0[sp]
|
||||
prepare {r20 - r29}, 0
|
||||
ctret
|
||||
|
||||
/* Restore saved registers, deallocate stack and return to the user. */
|
||||
/* Called via: callt ctoff(__callt_return_r2_r29). */
|
||||
.align 2
|
||||
.L_return_r2_r29:
|
||||
dispose 0, {r20-r29}
|
||||
ld.w 0[sp], r2
|
||||
add 4, sp
|
||||
jmp [r31]
|
||||
|
||||
/* Place the offsets of the start of these routines into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_save_r2_r29
|
||||
.type __callt_save_r2_r29,@function
|
||||
__callt_save_r2_r29: .short ctoff(.L_save_r2_r29)
|
||||
|
||||
.global __callt_return_r2_r29
|
||||
.type __callt_return_r2_r29,@function
|
||||
__callt_return_r2_r29: .short ctoff(.L_return_r2_r29)
|
||||
|
||||
#endif /* L_callt_save_r2_r29 */
|
||||
|
||||
#ifdef L_callt_save_r2_r31
|
||||
/* Put these functions into the call table area. */
|
||||
.call_table_text
|
||||
|
||||
/* Allocate space and save registers 2 and 20 .. 29, 31 on the stack. */
|
||||
/* Also allocate space for the argument save area. */
|
||||
/* Called via: callt ctoff(__callt_save_r2_r31). */
|
||||
.align 2
|
||||
.L_save_r2_r31:
|
||||
add -4, sp
|
||||
st.w r2, 0[sp]
|
||||
prepare {r20 - r29, r31}, 4
|
||||
ctret
|
||||
|
||||
/* Restore saved registers, deallocate stack and return to the user. */
|
||||
/* Called via: callt ctoff(__callt_return_r2_r31). */
|
||||
.align 2
|
||||
.L_return_r2_r31:
|
||||
dispose 4, {r20 - r29, r31}
|
||||
ld.w 0[sp], r2
|
||||
addi 4, sp, sp
|
||||
jmp [r31]
|
||||
|
||||
/* Place the offsets of the start of these routines into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_save_r2_r31
|
||||
.type __callt_save_r2_r31,@function
|
||||
__callt_save_r2_r31: .short ctoff(.L_save_r2_r31)
|
||||
|
||||
.global __callt_return_r2_r31
|
||||
.type __callt_return_r2_r31,@function
|
||||
__callt_return_r2_r31: .short ctoff(.L_return_r2_r31)
|
||||
|
||||
#endif /* L_callt_save_r2_r31 */
|
||||
|
||||
|
||||
#ifdef L_callt_save_r6_r9
|
||||
/* Put these functions into the call table area. */
|
||||
.call_table_text
|
||||
|
||||
/* Save registers r6 - r9 onto the stack in the space reserved for them.
|
||||
Use by variable argument functions.
|
||||
Called via: callt ctoff(__callt_save_r6_r9). */
|
||||
.align 2
|
||||
.L_save_r6_r9:
|
||||
mov ep,r1
|
||||
mov sp,ep
|
||||
sst.w r6,0[ep]
|
||||
sst.w r7,4[ep]
|
||||
sst.w r8,8[ep]
|
||||
sst.w r9,12[ep]
|
||||
mov r1,ep
|
||||
ctret
|
||||
|
||||
/* Place the offsets of the start of this routines into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_save_r6_r9
|
||||
.type __callt_save_r6_r9,@function
|
||||
__callt_save_r6_r9: .short ctoff(.L_save_r6_r9)
|
||||
#endif /* L_callt_save_r6_r9 */
|
||||
|
||||
|
||||
#ifdef L_callt_save_interrupt
|
||||
/* Put this functions into the call table area */
|
||||
.call_table_text
|
||||
|
||||
/* Save registers r1, ep, gp, r10 on stack and load up with expected values. */
|
||||
/* Called via: callt ctoff(__callt_save_interrupt). */
|
||||
.align 2
|
||||
.L_save_interrupt:
|
||||
/* SP has already been moved before callt ctoff(_save_interrupt). */
|
||||
/* addi -24, sp, sp */
|
||||
st.w ep, 0[sp]
|
||||
st.w gp, 4[sp]
|
||||
st.w r1, 8[sp]
|
||||
/* R10 has alread been saved bofore callt ctoff(_save_interrupt). */
|
||||
/* st.w r10, 12[sp] */
|
||||
mov hilo(__ep),ep
|
||||
mov hilo(__gp),gp
|
||||
ctret
|
||||
|
||||
/* Place the offsets of the start of the routine into the call table. */
|
||||
.call_table_data
|
||||
.global __callt_save_interrupt
|
||||
.type __callt_save_interrupt,@function
|
||||
__callt_save_interrupt: .short ctoff(.L_save_interrupt)
|
||||
|
||||
.call_table_text
|
||||
|
||||
/* Restore saved registers, deallocate stack and return from the interrupt. */
|
||||
/* Called via: callt ctoff(__callt_restore_itnerrupt). */
|
||||
.text
|
||||
.align 2
|
||||
.globl __return_interrupt
|
||||
.type __return_interrupt,@function
|
||||
.L_return_interrupt:
|
||||
ld.w 20[sp], r1
|
||||
ldsr r1, ctpsw
|
||||
ld.w 16[sp], r1
|
||||
ldsr r1, ctpc
|
||||
ld.w 12[sp], r10
|
||||
ld.w 8[sp], r1
|
||||
ld.w 4[sp], gp
|
||||
ld.w 0[sp], ep
|
||||
addi 24, sp, sp
|
||||
reti
|
||||
|
||||
/* Place the offsets of the start of the routine into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_return_interrupt
|
||||
.type __callt_return_interrupt,@function
|
||||
__callt_return_interrupt: .short ctoff(.L_return_interrupt)
|
||||
|
||||
#endif /* L_callt_save_interrupt */
|
||||
|
||||
#ifdef L_callt_save_all_interrupt
|
||||
/* Put this functions into the call table area. */
|
||||
.call_table_text
|
||||
|
||||
/* Save all registers except for those saved in __save_interrupt. */
|
||||
/* Allocate enough stack for all of the registers & 16 bytes of space. */
|
||||
/* Called via: callt ctoff(__callt_save_all_interrupt). */
|
||||
.align 2
|
||||
.L_save_all_interrupt:
|
||||
addi -60, sp, sp
|
||||
mov ep, r1
|
||||
mov sp, ep
|
||||
sst.w r2, 56[ep]
|
||||
sst.w r5, 52[ep]
|
||||
sst.w r6, 48[ep]
|
||||
sst.w r7, 44[ep]
|
||||
sst.w r8, 40[ep]
|
||||
sst.w r9, 36[ep]
|
||||
sst.w r11, 32[ep]
|
||||
sst.w r12, 28[ep]
|
||||
sst.w r13, 24[ep]
|
||||
sst.w r14, 20[ep]
|
||||
sst.w r15, 16[ep]
|
||||
sst.w r16, 12[ep]
|
||||
sst.w r17, 8[ep]
|
||||
sst.w r18, 4[ep]
|
||||
sst.w r19, 0[ep]
|
||||
mov r1, ep
|
||||
|
||||
prepare {r20 - r29, r31}, 4
|
||||
ctret
|
||||
|
||||
/* Restore all registers saved in __save_all_interrupt. */
|
||||
/* & deallocate the stack space. */
|
||||
/* Called via: callt ctoff(__callt_restore_all_interrupt). */
|
||||
.align 2
|
||||
.L_restore_all_interrupt:
|
||||
dispose 4, {r20 - r29, r31}
|
||||
|
||||
mov ep, r1
|
||||
mov sp, ep
|
||||
sld.w 0 [ep], r19
|
||||
sld.w 4 [ep], r18
|
||||
sld.w 8 [ep], r17
|
||||
sld.w 12[ep], r16
|
||||
sld.w 16[ep], r15
|
||||
sld.w 20[ep], r14
|
||||
sld.w 24[ep], r13
|
||||
sld.w 28[ep], r12
|
||||
sld.w 32[ep], r11
|
||||
sld.w 36[ep], r9
|
||||
sld.w 40[ep], r8
|
||||
sld.w 44[ep], r7
|
||||
sld.w 48[ep], r6
|
||||
sld.w 52[ep], r5
|
||||
sld.w 56[ep], r2
|
||||
mov r1, ep
|
||||
addi 60, sp, sp
|
||||
ctret
|
||||
|
||||
/* Place the offsets of the start of these routines into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_save_all_interrupt
|
||||
.type __callt_save_all_interrupt,@function
|
||||
__callt_save_all_interrupt: .short ctoff(.L_save_all_interrupt)
|
||||
|
||||
.global __callt_restore_all_interrupt
|
||||
.type __callt_restore_all_interrupt,@function
|
||||
__callt_restore_all_interrupt: .short ctoff(.L_restore_all_interrupt)
|
||||
|
||||
#endif /* L_callt_save_all_interrupt */
|
||||
|
||||
|
||||
#define MAKE_CALLT_FUNCS( START ) \
|
||||
.call_table_text ;\
|
||||
.align 2 ;\
|
||||
/* Allocate space and save registers START .. r29 on the stack. */ ;\
|
||||
/* Called via: callt ctoff(__callt_save_START_r29). */ ;\
|
||||
.L_save_##START##_r29: ;\
|
||||
prepare { START - r29 }, 0 ;\
|
||||
ctret ;\
|
||||
;\
|
||||
/* Restore saved registers, deallocate stack and return. */ ;\
|
||||
/* Called via: callt ctoff(__return_START_r29) */ ;\
|
||||
.align 2 ;\
|
||||
.L_return_##START##_r29: ;\
|
||||
dispose 0, { START - r29 }, r31 ;\
|
||||
;\
|
||||
/* Place the offsets of the start of these funcs into the call table. */;\
|
||||
.call_table_data ;\
|
||||
;\
|
||||
.global __callt_save_##START##_r29 ;\
|
||||
.type __callt_save_##START##_r29,@function ;\
|
||||
__callt_save_##START##_r29: .short ctoff(.L_save_##START##_r29 ) ;\
|
||||
;\
|
||||
.global __callt_return_##START##_r29 ;\
|
||||
.type __callt_return_##START##_r29,@function ;\
|
||||
__callt_return_##START##_r29: .short ctoff(.L_return_##START##_r29 )
|
||||
|
||||
|
||||
#define MAKE_CALLT_CFUNCS( START ) \
|
||||
.call_table_text ;\
|
||||
.align 2 ;\
|
||||
/* Allocate space and save registers START .. r31 on the stack. */ ;\
|
||||
/* Called via: callt ctoff(__callt_save_START_r31c). */ ;\
|
||||
.L_save_##START##_r31c: ;\
|
||||
prepare { START - r29, r31}, 4 ;\
|
||||
ctret ;\
|
||||
;\
|
||||
/* Restore saved registers, deallocate stack and return. */ ;\
|
||||
/* Called via: callt ctoff(__return_START_r31c). */ ;\
|
||||
.align 2 ;\
|
||||
.L_return_##START##_r31c: ;\
|
||||
dispose 4, { START - r29, r31}, r31 ;\
|
||||
;\
|
||||
/* Place the offsets of the start of these funcs into the call table. */;\
|
||||
.call_table_data ;\
|
||||
;\
|
||||
.global __callt_save_##START##_r31c ;\
|
||||
.type __callt_save_##START##_r31c,@function ;\
|
||||
__callt_save_##START##_r31c: .short ctoff(.L_save_##START##_r31c ) ;\
|
||||
;\
|
||||
.global __callt_return_##START##_r31c ;\
|
||||
.type __callt_return_##START##_r31c,@function ;\
|
||||
__callt_return_##START##_r31c: .short ctoff(.L_return_##START##_r31c )
|
||||
|
||||
|
||||
#ifdef L_callt_save_20
|
||||
MAKE_CALLT_FUNCS (r20)
|
||||
#endif
|
||||
#ifdef L_callt_save_21
|
||||
MAKE_CALLT_FUNCS (r21)
|
||||
#endif
|
||||
#ifdef L_callt_save_22
|
||||
MAKE_CALLT_FUNCS (r22)
|
||||
#endif
|
||||
#ifdef L_callt_save_23
|
||||
MAKE_CALLT_FUNCS (r23)
|
||||
#endif
|
||||
#ifdef L_callt_save_24
|
||||
MAKE_CALLT_FUNCS (r24)
|
||||
#endif
|
||||
#ifdef L_callt_save_25
|
||||
MAKE_CALLT_FUNCS (r25)
|
||||
#endif
|
||||
#ifdef L_callt_save_26
|
||||
MAKE_CALLT_FUNCS (r26)
|
||||
#endif
|
||||
#ifdef L_callt_save_27
|
||||
MAKE_CALLT_FUNCS (r27)
|
||||
#endif
|
||||
#ifdef L_callt_save_28
|
||||
MAKE_CALLT_FUNCS (r28)
|
||||
#endif
|
||||
#ifdef L_callt_save_29
|
||||
MAKE_CALLT_FUNCS (r29)
|
||||
#endif
|
||||
|
||||
#ifdef L_callt_save_20c
|
||||
MAKE_CALLT_CFUNCS (r20)
|
||||
#endif
|
||||
#ifdef L_callt_save_21c
|
||||
MAKE_CALLT_CFUNCS (r21)
|
||||
#endif
|
||||
#ifdef L_callt_save_22c
|
||||
MAKE_CALLT_CFUNCS (r22)
|
||||
#endif
|
||||
#ifdef L_callt_save_23c
|
||||
MAKE_CALLT_CFUNCS (r23)
|
||||
#endif
|
||||
#ifdef L_callt_save_24c
|
||||
MAKE_CALLT_CFUNCS (r24)
|
||||
#endif
|
||||
#ifdef L_callt_save_25c
|
||||
MAKE_CALLT_CFUNCS (r25)
|
||||
#endif
|
||||
#ifdef L_callt_save_26c
|
||||
MAKE_CALLT_CFUNCS (r26)
|
||||
#endif
|
||||
#ifdef L_callt_save_27c
|
||||
MAKE_CALLT_CFUNCS (r27)
|
||||
#endif
|
||||
#ifdef L_callt_save_28c
|
||||
MAKE_CALLT_CFUNCS (r28)
|
||||
#endif
|
||||
#ifdef L_callt_save_29c
|
||||
MAKE_CALLT_CFUNCS (r29)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef L_callt_save_31c
|
||||
.call_table_text
|
||||
.align 2
|
||||
/* Allocate space and save register r31 on the stack. */
|
||||
/* Called via: callt ctoff(__callt_save_r31c). */
|
||||
.L_callt_save_r31c:
|
||||
prepare {r31}, 4
|
||||
ctret
|
||||
|
||||
/* Restore saved registers, deallocate stack and return. */
|
||||
/* Called via: callt ctoff(__return_r31c). */
|
||||
.align 2
|
||||
.L_callt_return_r31c:
|
||||
dispose 4, {r31}, r31
|
||||
|
||||
/* Place the offsets of the start of these funcs into the call table. */
|
||||
.call_table_data
|
||||
|
||||
.global __callt_save_r31c
|
||||
.type __callt_save_r31c,@function
|
||||
__callt_save_r31c: .short ctoff(.L_callt_save_r31c)
|
||||
|
||||
.global __callt_return_r31c
|
||||
.type __callt_return_r31c,@function
|
||||
__callt_return_r31c: .short ctoff(.L_callt_return_r31c)
|
||||
#endif
|
||||
|
||||
#endif /* __v850e__ */
|
||||
|
@ -29,7 +29,34 @@ LIB1ASMFUNCS = _mulsi3 \
|
||||
_save_31c \
|
||||
_save_varargs \
|
||||
_save_interrupt \
|
||||
_save_all_interrupt
|
||||
_save_all_interrupt \
|
||||
_callt_save_20 \
|
||||
_callt_save_21 \
|
||||
_callt_save_22 \
|
||||
_callt_save_23 \
|
||||
_callt_save_24 \
|
||||
_callt_save_25 \
|
||||
_callt_save_26 \
|
||||
_callt_save_27 \
|
||||
_callt_save_28 \
|
||||
_callt_save_29 \
|
||||
_callt_save_20c \
|
||||
_callt_save_21c \
|
||||
_callt_save_22c \
|
||||
_callt_save_23c \
|
||||
_callt_save_24c \
|
||||
_callt_save_25c \
|
||||
_callt_save_26c \
|
||||
_callt_save_27c \
|
||||
_callt_save_28c \
|
||||
_callt_save_29c \
|
||||
_callt_save_31c \
|
||||
_callt_save_varargs \
|
||||
_callt_save_interrupt \
|
||||
_callt_save_all_interrupt \
|
||||
_callt_save_r2_r29 \
|
||||
_callt_save_r2_r31 \
|
||||
_callt_save_r6_r9
|
||||
|
||||
# We want fine grained libraries, so use the new code to build the
|
||||
# floating point emulation libraries.
|
||||
@ -50,6 +77,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
|
||||
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
||||
|
||||
TCFLAGS = -Wa,-mwarn-signed-overflow -Wa,-mwarn-unsigned-overflow
|
||||
# Create non-target specific versions of the libraries
|
||||
TCFLAGS += -mno-app-regs -msmall-sld -mv850 -D__v850e__ -Wa,-mv850any
|
||||
|
||||
v850-c.o: $(srcdir)/config/v850/v850-c.c $(RTL_H) $(TREE_H) $(CONFIG_H)
|
||||
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
|
||||
|
@ -53,6 +53,10 @@ extern void notice_update_cc PARAMS ((rtx, rtx));
|
||||
extern char * construct_save_jarl PARAMS ((rtx));
|
||||
extern char * construct_restore_jr PARAMS ((rtx));
|
||||
#ifdef HAVE_MACHINE_MODES
|
||||
extern char * construct_dispose_instruction PARAMS ((rtx));
|
||||
extern char * construct_prepare_instruction PARAMS ((rtx));
|
||||
extern int pattern_is_ok_for_prepare PARAMS ((rtx, Mmode));
|
||||
extern int pattern_is_ok_for_dispose PARAMS ((rtx, Mmode));
|
||||
extern int ep_memory_operand PARAMS ((rtx, Mmode, int));
|
||||
extern int reg_or_0_operand PARAMS ((rtx, Mmode));
|
||||
extern int reg_or_int5_operand PARAMS ((rtx, Mmode));
|
||||
|
@ -142,6 +142,13 @@ override_options ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that the US_BIT_SET mask has been correctly initialised. */
|
||||
if ((target_flags & MASK_US_MASK_SET) == 0)
|
||||
{
|
||||
target_flags |= MASK_US_MASK_SET;
|
||||
target_flags &= ~MASK_US_BIT_SET;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +183,9 @@ function_arg (cum, mode, type, named)
|
||||
else
|
||||
size = GET_MODE_SIZE (mode);
|
||||
|
||||
if (size < 1)
|
||||
return 0;
|
||||
|
||||
if (type)
|
||||
align = TYPE_ALIGN (type) / BITS_PER_UNIT;
|
||||
else
|
||||
@ -696,6 +706,38 @@ print_operand_address (file, addr)
|
||||
}
|
||||
}
|
||||
|
||||
/* When assemble_integer is used to emit the offsets for a switch
|
||||
table it can encounter (TRUNCATE:HI (MINUS:SI (LABEL_REF:SI) (LABEL_REF:SI))).
|
||||
output_addr_const will normally barf at this, but it is OK to omit
|
||||
the truncate and just emit the difference of the two labels. The
|
||||
.hword directive will automatically handle the truncation for us.
|
||||
|
||||
Returns 1 if rtx was handled, 0 otherwise. */
|
||||
|
||||
int
|
||||
v850_output_addr_const_extra (file, x)
|
||||
FILE * file;
|
||||
rtx x;
|
||||
{
|
||||
if (GET_CODE (x) != TRUNCATE)
|
||||
return 0;
|
||||
|
||||
x = XEXP (x, 0);
|
||||
|
||||
/* We must also handle the case where the switch table was passed a
|
||||
constant value and so has been collapsed. In this case the first
|
||||
label will have been deleted. In such a case it is OK to emit
|
||||
nothing, since the table will not be used.
|
||||
(cf gcc.c-torture/compile/990801-1.c). */
|
||||
if (GET_CODE (x) == MINUS
|
||||
&& GET_CODE (XEXP (x, 0)) == LABEL_REF
|
||||
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == CODE_LABEL
|
||||
&& INSN_DELETED_P (XEXP (XEXP (x, 0), 0)))
|
||||
return 1;
|
||||
|
||||
output_addr_const (file, x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return appropriate code to load up a 1, 2, or 4 integer/floating
|
||||
point value. */
|
||||
@ -716,16 +758,19 @@ output_move_single (operands)
|
||||
{
|
||||
HOST_WIDE_INT value = INTVAL (src);
|
||||
|
||||
if (CONST_OK_FOR_J (value)) /* signed 5 bit immediate */
|
||||
if (CONST_OK_FOR_J (value)) /* Signed 5 bit immediate. */
|
||||
return "mov %1,%0";
|
||||
|
||||
else if (CONST_OK_FOR_K (value)) /* signed 16 bit immediate */
|
||||
else if (CONST_OK_FOR_K (value)) /* Signed 16 bit immediate. */
|
||||
return "movea lo(%1),%.,%0";
|
||||
|
||||
else if (CONST_OK_FOR_L (value)) /* upper 16 bits were set */
|
||||
else if (CONST_OK_FOR_L (value)) /* Upper 16 bits were set. */
|
||||
return "movhi hi(%1),%.,%0";
|
||||
|
||||
else /* random constant */
|
||||
/* A random constant. */
|
||||
else if (TARGET_V850E)
|
||||
return "mov %1,%0";
|
||||
else
|
||||
return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
|
||||
}
|
||||
|
||||
@ -734,16 +779,21 @@ output_move_single (operands)
|
||||
HOST_WIDE_INT high, low;
|
||||
|
||||
const_double_split (src, &high, &low);
|
||||
if (CONST_OK_FOR_J (high)) /* signed 5 bit immediate */
|
||||
|
||||
if (CONST_OK_FOR_J (high)) /* Signed 5 bit immediate. */
|
||||
return "mov %F1,%0";
|
||||
|
||||
else if (CONST_OK_FOR_K (high)) /* signed 16 bit immediate */
|
||||
else if (CONST_OK_FOR_K (high)) /* Signed 16 bit immediate. */
|
||||
return "movea lo(%F1),%.,%0";
|
||||
|
||||
else if (CONST_OK_FOR_L (high)) /* upper 16 bits were set */
|
||||
else if (CONST_OK_FOR_L (high)) /* Upper 16 bits were set. */
|
||||
return "movhi hi(%F1),%.,%0";
|
||||
|
||||
else /* random constant */
|
||||
/* A random constant. */
|
||||
else if (TARGET_V850E)
|
||||
return "mov %F1,%0";
|
||||
|
||||
else
|
||||
return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0";
|
||||
}
|
||||
|
||||
@ -757,7 +807,10 @@ output_move_single (operands)
|
||||
|| GET_CODE (src) == SYMBOL_REF
|
||||
|| GET_CODE (src) == CONST)
|
||||
{
|
||||
return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
|
||||
if (TARGET_V850E)
|
||||
return "mov hilo(%1),%0";
|
||||
else
|
||||
return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
|
||||
}
|
||||
|
||||
else if (GET_CODE (src) == HIGH)
|
||||
@ -881,11 +934,25 @@ ep_memory_offset (mode, unsignedp)
|
||||
switch (mode)
|
||||
{
|
||||
case QImode:
|
||||
max_offset = (1 << 7);
|
||||
if (TARGET_SMALL_SLD)
|
||||
max_offset = (1 << 4);
|
||||
else if (TARGET_V850E
|
||||
&& ( ( unsignedp && ! TARGET_US_BIT_SET)
|
||||
|| (! unsignedp && TARGET_US_BIT_SET)))
|
||||
max_offset = (1 << 4);
|
||||
else
|
||||
max_offset = (1 << 7);
|
||||
break;
|
||||
|
||||
case HImode:
|
||||
max_offset = (1 << 8);
|
||||
if (TARGET_SMALL_SLD)
|
||||
max_offset = (1 << 5);
|
||||
else if (TARGET_V850E
|
||||
&& ( ( unsignedp && ! TARGET_US_BIT_SET)
|
||||
|| (! unsignedp && TARGET_US_BIT_SET)))
|
||||
max_offset = (1 << 5);
|
||||
else
|
||||
max_offset = (1 << 8);
|
||||
break;
|
||||
|
||||
case SImode:
|
||||
@ -985,6 +1052,32 @@ reg_or_int5_operand (op, mode)
|
||||
return register_operand (op, mode);
|
||||
}
|
||||
|
||||
/* Return true if OP is either a register or a signed nine bit integer. */
|
||||
|
||||
int
|
||||
reg_or_int9_operand (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
if (GET_CODE (op) == CONST_INT)
|
||||
return CONST_OK_FOR_O (INTVAL (op));
|
||||
|
||||
return register_operand (op, mode);
|
||||
}
|
||||
|
||||
/* Return true if OP is either a register or a const integer. */
|
||||
|
||||
int
|
||||
reg_or_const_operand (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
if (GET_CODE (op) == CONST_INT)
|
||||
return TRUE;
|
||||
|
||||
return register_operand (op, mode);
|
||||
}
|
||||
|
||||
/* Return true if OP is a valid call operand. */
|
||||
|
||||
int
|
||||
@ -1129,6 +1222,16 @@ Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, end
|
||||
else if (GET_CODE (SET_SRC (pattern)) == MEM)
|
||||
p_mem = &SET_SRC (pattern);
|
||||
|
||||
else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND
|
||||
&& GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
|
||||
p_mem = &XEXP (SET_SRC (pattern), 0);
|
||||
|
||||
else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND
|
||||
&& GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
|
||||
{
|
||||
p_mem = &XEXP (SET_SRC (pattern), 0);
|
||||
unsignedp = TRUE;
|
||||
}
|
||||
else
|
||||
p_mem = (rtx *)0;
|
||||
|
||||
@ -1278,6 +1381,16 @@ void v850_reorg (start_insn)
|
||||
else if (GET_CODE (src) == MEM)
|
||||
mem = src;
|
||||
|
||||
else if (GET_CODE (src) == SIGN_EXTEND
|
||||
&& GET_CODE (XEXP (src, 0)) == MEM)
|
||||
mem = XEXP (src, 0);
|
||||
|
||||
else if (GET_CODE (src) == ZERO_EXTEND
|
||||
&& GET_CODE (XEXP (src, 0)) == MEM)
|
||||
{
|
||||
mem = XEXP (src, 0);
|
||||
unsignedp = TRUE;
|
||||
}
|
||||
else
|
||||
mem = NULL_RTX;
|
||||
|
||||
@ -1531,8 +1644,11 @@ expand_prologue ()
|
||||
/* Save/setup global registers for interrupt functions right now. */
|
||||
if (interrupt_handler)
|
||||
{
|
||||
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
|
||||
emit_insn (gen_callt_save_interrupt ());
|
||||
else
|
||||
emit_insn (gen_save_interrupt ());
|
||||
|
||||
|
||||
actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
|
||||
|
||||
if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
|
||||
@ -1544,7 +1660,10 @@ expand_prologue ()
|
||||
{
|
||||
if (TARGET_PROLOG_FUNCTION)
|
||||
{
|
||||
emit_insn (gen_save_r6_r9 ());
|
||||
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
|
||||
emit_insn (gen_save_r6_r9_v850e ());
|
||||
else
|
||||
emit_insn (gen_save_r6_r9 ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1656,7 +1775,10 @@ Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
|
||||
/* Special case interrupt functions that save all registers for a call. */
|
||||
if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
|
||||
{
|
||||
emit_insn (gen_save_all_interrupt ());
|
||||
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
|
||||
emit_insn (gen_callt_save_all_interrupt ());
|
||||
else
|
||||
emit_insn (gen_save_all_interrupt ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1888,7 +2010,10 @@ Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
|
||||
for a call. */
|
||||
if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
|
||||
{
|
||||
emit_insn (gen_restore_all_interrupt ());
|
||||
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
|
||||
emit_insn (gen_callt_restore_all_interrupt ());
|
||||
else
|
||||
emit_insn (gen_restore_all_interrupt ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1926,7 +2051,12 @@ Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
|
||||
|
||||
/* And return or use reti for interrupt handlers. */
|
||||
if (interrupt_handler)
|
||||
emit_jump_insn (gen_restore_interrupt ());
|
||||
{
|
||||
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
|
||||
emit_insn (gen_callt_return_interrupt ());
|
||||
else
|
||||
emit_jump_insn (gen_return_interrupt ());
|
||||
}
|
||||
else if (actual_fsize)
|
||||
emit_jump_insn (gen_return_internal ());
|
||||
else
|
||||
@ -2233,10 +2363,9 @@ register_is_ok_for_epilogue (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode ATTRIBUTE_UNUSED mode;
|
||||
{
|
||||
/* The save/restore routines can only cope with registers 2, and 20 - 31 */
|
||||
return (GET_CODE (op) == REG)
|
||||
&& (((REGNO (op) >= 20) && REGNO (op) <= 31)
|
||||
|| REGNO (op) == 2);
|
||||
/* The save/restore routines can only cope with registers 20 - 31. */
|
||||
return ((GET_CODE (op) == REG)
|
||||
&& (((REGNO (op) >= 20) && REGNO (op) <= 31)));
|
||||
}
|
||||
|
||||
/* Return non-zero if the given RTX is suitable for collapsing into
|
||||
@ -2817,6 +2946,392 @@ v850_insert_attributes (decl, attr_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return non-zero if the given RTX is suitable
|
||||
for collapsing into a DISPOSE instruction. */
|
||||
|
||||
int
|
||||
pattern_is_ok_for_dispose (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode mode ATTRIBUTE_UNUSED;
|
||||
{
|
||||
int count = XVECLEN (op, 0);
|
||||
int i;
|
||||
|
||||
/* If there are no registers to restore then
|
||||
the dispose instruction is not suitable. */
|
||||
if (count <= 2)
|
||||
return 0;
|
||||
|
||||
/* The pattern matching has already established that we are performing a
|
||||
function epilogue and that we are popping at least one register. We must
|
||||
now check the remaining entries in the vector to make sure that they are
|
||||
also register pops. There is no good reason why there should ever be
|
||||
anything else in this vector, but being paranoid always helps...
|
||||
|
||||
The test below performs the C equivalent of this machine description
|
||||
pattern match:
|
||||
|
||||
(set (match_operand:SI n "register_is_ok_for_epilogue" "r")
|
||||
(mem:SI (plus:SI (reg:SI 3)
|
||||
(match_operand:SI n "immediate_operand" "i"))))
|
||||
*/
|
||||
|
||||
for (i = 3; i < count; i++)
|
||||
{
|
||||
rtx vector_element = XVECEXP (op, 0, i);
|
||||
rtx dest;
|
||||
rtx src;
|
||||
rtx plus;
|
||||
|
||||
if (GET_CODE (vector_element) != SET)
|
||||
return 0;
|
||||
|
||||
dest = SET_DEST (vector_element);
|
||||
src = SET_SRC (vector_element);
|
||||
|
||||
if ( GET_CODE (dest) != REG
|
||||
|| GET_MODE (dest) != SImode
|
||||
|| ! register_is_ok_for_epilogue (dest, SImode)
|
||||
|| GET_CODE (src) != MEM
|
||||
|| GET_MODE (src) != SImode)
|
||||
return 0;
|
||||
|
||||
plus = XEXP (src, 0);
|
||||
|
||||
if ( GET_CODE (plus) != PLUS
|
||||
|| GET_CODE (XEXP (plus, 0)) != REG
|
||||
|| GET_MODE (XEXP (plus, 0)) != SImode
|
||||
|| REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
|
||||
|| GET_CODE (XEXP (plus, 1)) != CONST_INT)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Construct a DISPOSE instruction that is the equivalent of
|
||||
the given RTX. We have already verified that this should
|
||||
be possible. */
|
||||
|
||||
char *
|
||||
construct_dispose_instruction (op)
|
||||
rtx op;
|
||||
{
|
||||
int count = XVECLEN (op, 0);
|
||||
int stack_bytes;
|
||||
unsigned long int mask;
|
||||
int i;
|
||||
static char buff[ 100 ]; /* XXX */
|
||||
int use_callt = 0;
|
||||
|
||||
if (count <= 2)
|
||||
{
|
||||
error ("Bogus DISPOSE construction: %d\n", count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Work out how many bytes to pop off the
|
||||
stack before retrieving registers. */
|
||||
if (GET_CODE (XVECEXP (op, 0, 1)) != SET)
|
||||
abort ();
|
||||
if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)
|
||||
abort ();
|
||||
if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)
|
||||
abort ();
|
||||
|
||||
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
|
||||
|
||||
/* Each pop will remove 4 bytes from the stack... */
|
||||
stack_bytes -= (count - 2) * 4;
|
||||
|
||||
/* Make sure that the amount we are popping
|
||||
will fit into the DISPOSE instruction. */
|
||||
if (stack_bytes > 128)
|
||||
{
|
||||
error ("Too much stack space to dispose of: %d", stack_bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now compute the bit mask of registers to push. */
|
||||
mask = 0;
|
||||
|
||||
for (i = 2; i < count; i++)
|
||||
{
|
||||
rtx vector_element = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (vector_element) != SET)
|
||||
abort ();
|
||||
if (GET_CODE (SET_DEST (vector_element)) != REG)
|
||||
abort ();
|
||||
if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))
|
||||
abort ();
|
||||
|
||||
if (REGNO (SET_DEST (vector_element)) == 2)
|
||||
use_callt = 1;
|
||||
else
|
||||
mask |= 1 << REGNO (SET_DEST (vector_element));
|
||||
}
|
||||
|
||||
if (! TARGET_DISABLE_CALLT
|
||||
&& (use_callt || stack_bytes == 0 || stack_bytes == 16))
|
||||
{
|
||||
if (use_callt)
|
||||
{
|
||||
sprintf (buff, "callt ctoff(__callt_return_r2_r%d)", (mask & (1 << 31)) ? 31 : 29);
|
||||
return buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 20; i < 32; i++)
|
||||
if (mask & (1 << i))
|
||||
break;
|
||||
|
||||
if (i == 31)
|
||||
sprintf (buff, "callt ctoff(__callt_return_r31c)");
|
||||
else
|
||||
sprintf (buff, "callt ctoff(__callt_return_r%d_r%d%s)",
|
||||
i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static char regs [100]; /* XXX */
|
||||
int done_one;
|
||||
|
||||
/* Generate the DISPOSE instruction. Note we could just issue the
|
||||
bit mask as a number as the assembler can cope with this, but for
|
||||
the sake of our readers we turn it into a textual description. */
|
||||
regs[0] = 0;
|
||||
done_one = 0;
|
||||
|
||||
for (i = 20; i < 32; i++)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
int first;
|
||||
|
||||
if (done_one)
|
||||
strcat (regs, ", ");
|
||||
else
|
||||
done_one = 1;
|
||||
|
||||
first = i;
|
||||
strcat (regs, reg_names[ first ]);
|
||||
|
||||
for (i++; i < 32; i++)
|
||||
if ((mask & (1 << i)) == 0)
|
||||
break;
|
||||
|
||||
if (i > first + 1)
|
||||
{
|
||||
strcat (regs, " - ");
|
||||
strcat (regs, reg_names[ i - 1 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (buff, "dispose %d {%s}, r31", stack_bytes / 4, regs);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* Return non-zero if the given RTX is suitable
|
||||
for collapsing into a PREPARE instruction. */
|
||||
|
||||
int
|
||||
pattern_is_ok_for_prepare (op, mode)
|
||||
rtx op;
|
||||
enum machine_mode mode ATTRIBUTE_UNUSED;
|
||||
{
|
||||
int count = XVECLEN (op, 0);
|
||||
int i;
|
||||
|
||||
/* If there are no registers to restore then the prepare instruction
|
||||
is not suitable. */
|
||||
if (count <= 1)
|
||||
return 0;
|
||||
|
||||
/* The pattern matching has already established that we are adjusting the
|
||||
stack and pushing at least one register. We must now check that the
|
||||
remaining entries in the vector to make sure that they are also register
|
||||
pushes.
|
||||
|
||||
The test below performs the C equivalent of this machine description
|
||||
pattern match:
|
||||
|
||||
(set (mem:SI (plus:SI (reg:SI 3)
|
||||
(match_operand:SI 2 "immediate_operand" "i")))
|
||||
(match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
|
||||
|
||||
*/
|
||||
|
||||
for (i = 2; i < count; i++)
|
||||
{
|
||||
rtx vector_element = XVECEXP (op, 0, i);
|
||||
rtx dest;
|
||||
rtx src;
|
||||
rtx plus;
|
||||
|
||||
if (GET_CODE (vector_element) != SET)
|
||||
return 0;
|
||||
|
||||
dest = SET_DEST (vector_element);
|
||||
src = SET_SRC (vector_element);
|
||||
|
||||
if ( GET_CODE (dest) != MEM
|
||||
|| GET_MODE (dest) != SImode
|
||||
|| GET_CODE (src) != REG
|
||||
|| GET_MODE (src) != SImode
|
||||
|| ! register_is_ok_for_epilogue (src, SImode)
|
||||
)
|
||||
return 0;
|
||||
|
||||
plus = XEXP (dest, 0);
|
||||
|
||||
if ( GET_CODE (plus) != PLUS
|
||||
|| GET_CODE (XEXP (plus, 0)) != REG
|
||||
|| GET_MODE (XEXP (plus, 0)) != SImode
|
||||
|| REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
|
||||
|| GET_CODE (XEXP (plus, 1)) != CONST_INT)
|
||||
return 0;
|
||||
|
||||
/* If the register is being pushed somewhere other than the stack
|
||||
space just aquired by the first operand then abandon this quest.
|
||||
Note: the test is <= becuase both values are negative. */
|
||||
if (INTVAL (XEXP (plus, 1))
|
||||
<= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Construct a PREPARE instruction that is the equivalent of
|
||||
the given RTL. We have already verified that this should
|
||||
be possible. */
|
||||
|
||||
char *
|
||||
construct_prepare_instruction (op)
|
||||
rtx op;
|
||||
{
|
||||
int count = XVECLEN (op, 0);
|
||||
int stack_bytes;
|
||||
unsigned long int mask;
|
||||
int i;
|
||||
static char buff[ 100 ]; /* XXX */
|
||||
int use_callt = 0;
|
||||
|
||||
if (count <= 1)
|
||||
{
|
||||
error ("Bogus PREPEARE construction: %d\n", count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Work out how many bytes to push onto
|
||||
the stack after storing the registers. */
|
||||
if (GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
abort ();
|
||||
if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS)
|
||||
abort ();
|
||||
if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT)
|
||||
abort ();
|
||||
|
||||
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
|
||||
|
||||
/* Each push will put 4 bytes from the stack. */
|
||||
stack_bytes += (count - 1) * 4;
|
||||
|
||||
/* Make sure that the amount we are popping
|
||||
will fit into the DISPOSE instruction. */
|
||||
if (stack_bytes < -128)
|
||||
{
|
||||
error ("Too much stack space to prepare: %d", stack_bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now compute the bit mask of registers to push. */
|
||||
mask = 0;
|
||||
for (i = 1; i < count; i++)
|
||||
{
|
||||
rtx vector_element = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (vector_element) != SET)
|
||||
abort ();
|
||||
if (GET_CODE (SET_SRC (vector_element)) != REG)
|
||||
abort ();
|
||||
if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode))
|
||||
abort ();
|
||||
|
||||
if (REGNO (SET_SRC (vector_element)) == 2)
|
||||
use_callt = 1;
|
||||
else
|
||||
mask |= 1 << REGNO (SET_SRC (vector_element));
|
||||
}
|
||||
|
||||
if ((! TARGET_DISABLE_CALLT)
|
||||
&& (use_callt || stack_bytes == 0 || stack_bytes == -16))
|
||||
{
|
||||
if (use_callt)
|
||||
{
|
||||
sprintf (buff, "callt ctoff(__callt_save_r2_r%d)", (mask & (1 << 31)) ? 31 : 29 );
|
||||
return buff;
|
||||
}
|
||||
|
||||
for (i = 20; i < 32; i++)
|
||||
if (mask & (1 << i))
|
||||
break;
|
||||
|
||||
if (i == 31)
|
||||
sprintf (buff, "callt ctoff(__callt_save_r31c)");
|
||||
else
|
||||
sprintf (buff, "callt ctoff(__callt_save_r%d_r%d%s)",
|
||||
i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
static char regs [100]; /* XXX */
|
||||
int done_one;
|
||||
|
||||
|
||||
/* Generate the PREPARE instruction. Note we could just issue the
|
||||
bit mask as a number as the assembler can cope with this, but for
|
||||
the sake of our readers we turn it into a textual description. */
|
||||
regs[0] = 0;
|
||||
done_one = 0;
|
||||
|
||||
for (i = 20; i < 32; i++)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
int first;
|
||||
|
||||
if (done_one)
|
||||
strcat (regs, ", ");
|
||||
else
|
||||
done_one = 1;
|
||||
|
||||
first = i;
|
||||
strcat (regs, reg_names[ first ]);
|
||||
|
||||
for (i++; i < 32; i++)
|
||||
if ((mask & (1 << i)) == 0)
|
||||
break;
|
||||
|
||||
if (i > first + 1)
|
||||
{
|
||||
strcat (regs, " - ");
|
||||
strcat (regs, reg_names[ i - 1 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (buff, "prepare {%s}, %d", regs, (- stack_bytes) / 4);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* Implement `va_arg'. */
|
||||
|
||||
|
@ -31,8 +31,8 @@ Boston, MA 02111-1307, USA. */
|
||||
#undef STARTFILE_SPEC
|
||||
#undef ASM_SPEC
|
||||
|
||||
|
||||
#define TARGET_CPU_generic 1
|
||||
#define TARGET_CPU_v850e 2
|
||||
|
||||
#ifndef TARGET_CPU_DEFAULT
|
||||
#define TARGET_CPU_DEFAULT TARGET_CPU_generic
|
||||
@ -43,9 +43,22 @@ Boston, MA 02111-1307, USA. */
|
||||
#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850__}"
|
||||
#define TARGET_VERSION fprintf (stderr, " (NEC V850)");
|
||||
|
||||
/* Choose which processor will be the default.
|
||||
We must pass a -mv850xx option to the assembler if no explicit -mv* option
|
||||
is given, because the assembler's processor default may not be correct. */
|
||||
#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e
|
||||
#undef MASK_DEFAULT
|
||||
#define MASK_DEFAULT MASK_V850E
|
||||
#undef SUBTARGET_ASM_SPEC
|
||||
#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e}"
|
||||
#undef SUBTARGET_CPP_SPEC
|
||||
#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e__}"
|
||||
#undef TARGET_VERSION
|
||||
#define TARGET_VERSION fprintf (stderr, " (NEC V850E)");
|
||||
#endif
|
||||
|
||||
#define ASM_SPEC "%{mv*:-mv%*}"
|
||||
#define CPP_SPEC "%{mv850ea:-D__v850ea__} %{mv850e:-D__v850e__} %{mv850:-D__v850__} %(subtarget_cpp_spec)"
|
||||
#define CPP_SPEC "%{mv850e:-D__v850e__} %{mv850:-D__v850__} %(subtarget_cpp_spec)"
|
||||
|
||||
#define EXTRA_SPECS \
|
||||
{ "subtarget_asm_spec", SUBTARGET_ASM_SPEC }, \
|
||||
@ -67,8 +80,15 @@ extern int target_flags;
|
||||
|
||||
#define MASK_CPU 0x00000030
|
||||
#define MASK_V850 0x00000010
|
||||
#define MASK_V850E 0x00000020
|
||||
#define MASK_SMALL_SLD 0x00000040
|
||||
|
||||
#define MASK_BIG_SWITCH 0x00000100
|
||||
#define MASK_NO_APP_REGS 0x00000200
|
||||
#define MASK_DISABLE_CALLT 0x00000400
|
||||
|
||||
#define MASK_US_BIT_SET 0x00001000
|
||||
#define MASK_US_MASK_SET 0x00002000
|
||||
|
||||
/* Macros used in the machine description to test the flags. */
|
||||
|
||||
@ -107,8 +127,23 @@ extern int target_flags;
|
||||
/* Whether to emit 2 byte per entry or 4 byte per entry switch tables. */
|
||||
#define TARGET_BIG_SWITCH (target_flags & MASK_BIG_SWITCH)
|
||||
|
||||
/* General debug flag */
|
||||
#define TARGET_DEBUG (target_flags & MASK_DEBUG)
|
||||
/* General debug flag. */
|
||||
#define TARGET_DEBUG (target_flags & MASK_DEBUG)
|
||||
#define TARGET_V850E ((target_flags & MASK_V850E) == MASK_V850E)
|
||||
|
||||
#define TARGET_US_BIT_SET (target_flags & MASK_US_BIT_SET)
|
||||
|
||||
/* Whether to assume that the SLD.B and SLD.H instructions only have small
|
||||
displacement fields, thus allowing the generated code to run on any of
|
||||
the V850 range of processors. */
|
||||
#define TARGET_SMALL_SLD (target_flags & MASK_SMALL_SLD)
|
||||
|
||||
/* True if callt will not be used for function prolog & epilog. */
|
||||
#define TARGET_DISABLE_CALLT (target_flags & MASK_DISABLE_CALLT)
|
||||
|
||||
/* False if r2 and r5 can be used by the compiler. True if r2
|
||||
and r5 are to be fixed registers (for compatibility with GHS). */
|
||||
#define TARGET_NO_APP_REGS (target_flags & MASK_NO_APP_REGS)
|
||||
|
||||
/* Macro to define tables used to set the flags.
|
||||
This is a list in braces of pairs in braces,
|
||||
@ -134,6 +169,19 @@ extern int target_flags;
|
||||
{ "v850", MASK_V850, \
|
||||
N_("Compile for the v850 processor") }, \
|
||||
{ "v850", -(MASK_V850 ^ MASK_CPU), "" }, \
|
||||
{ "v850e", MASK_V850E, N_("Compile for v850e processor") }, \
|
||||
{ "v850e", -(MASK_V850E ^ MASK_CPU), "" }, /* Make sure that the other bits are cleared. */ \
|
||||
{ "small-sld", MASK_SMALL_SLD, N_("Enable the use of the short load instructions") }, \
|
||||
{ "no-small-sld", -MASK_SMALL_SLD, "" }, \
|
||||
{ "disable-callt", MASK_DISABLE_CALLT, \
|
||||
N_("Do not use the callt instruction") }, \
|
||||
{ "no-disable-callt", -MASK_DISABLE_CALLT, "" }, \
|
||||
{ "US-bit-set", (MASK_US_BIT_SET | MASK_US_MASK_SET), "" }, \
|
||||
{ "no-US-bit-set", -MASK_US_BIT_SET, "" }, \
|
||||
{ "no-US-bit-set", MASK_US_MASK_SET, "" }, \
|
||||
{ "app-regs", -MASK_NO_APP_REGS, "" }, \
|
||||
{ "no-app-regs", MASK_NO_APP_REGS, \
|
||||
N_("Do not use registers r2 and r5") }, \
|
||||
{ "big-switch", MASK_BIG_SWITCH, \
|
||||
N_("Use 4 byte entries in switch tables") },\
|
||||
{ "", MASK_DEFAULT, ""}}
|
||||
@ -327,6 +375,17 @@ extern struct small_memory_info small_memory[(int)SMALL_MEMORY_max];
|
||||
0, 1, 3, 4, 5, 30, 32, 33 /* fixed registers */ \
|
||||
}
|
||||
|
||||
/* If TARGET_NO_APP_REGS is not defined then add r2 and r5 to
|
||||
the pool of fixed registers. See PR 14505. */
|
||||
#define CONDITIONAL_REGISTER_USAGE \
|
||||
{ \
|
||||
if (TARGET_NO_APP_REGS) \
|
||||
{ \
|
||||
fixed_regs[2] = 1; call_used_regs[2] = 1; \
|
||||
fixed_regs[5] = 1; call_used_regs[5] = 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Return number of consecutive hard regs needed starting at reg REGNO
|
||||
to hold something of mode MODE.
|
||||
|
||||
@ -457,11 +516,11 @@ enum reg_class
|
||||
#define CONST_OK_FOR_M(VALUE) ((unsigned)(VALUE) < 0x10000)
|
||||
/* 5 bit unsigned immediate in shift instructions */
|
||||
#define CONST_OK_FOR_N(VALUE) ((unsigned) (VALUE) <= 31)
|
||||
/* 9 bit signed immediate for word multiply instruction. */
|
||||
#define CONST_OK_FOR_O(VALUE) ((unsigned) (VALUE) + 0x100 < 0x200)
|
||||
|
||||
#define CONST_OK_FOR_O(VALUE) 0
|
||||
#define CONST_OK_FOR_P(VALUE) 0
|
||||
|
||||
|
||||
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
|
||||
((C) == 'I' ? CONST_OK_FOR_I (VALUE) : \
|
||||
(C) == 'J' ? CONST_OK_FOR_J (VALUE) : \
|
||||
@ -851,7 +910,7 @@ extern int current_function_anonymous_args;
|
||||
((C) == 'Q' ? ep_memory_operand (OP, GET_MODE (OP), 0) \
|
||||
: (C) == 'R' ? special_symbolref_operand (OP, VOIDmode) \
|
||||
: (C) == 'S' ? (GET_CODE (OP) == SYMBOL_REF && ! ZDA_NAME_P (XSTR (OP, 0))) \
|
||||
: (C) == 'T' ? 0 \
|
||||
: (C) == 'T' ? ep_memory_operand(OP,GET_MODE(OP),TRUE) \
|
||||
: (C) == 'U' ? ((GET_CODE (OP) == SYMBOL_REF && ZDA_NAME_P (XSTR (OP, 0))) \
|
||||
|| (GET_CODE (OP) == CONST \
|
||||
&& GET_CODE (XEXP (OP, 0)) == PLUS \
|
||||
@ -1136,17 +1195,9 @@ zbss_section () \
|
||||
#undef USER_LABEL_PREFIX
|
||||
#define USER_LABEL_PREFIX "_"
|
||||
|
||||
/* When assemble_integer is used to emit the offsets for a switch
|
||||
table it can encounter (TRUNCATE:HI (MINUS:SI (LABEL_REF:SI) (LABEL_REF:SI))).
|
||||
output_addr_const will normally barf at this, but it is OK to omit
|
||||
the truncate and just emit the difference of the two labels. The
|
||||
.hword directive will automatically handle the truncation for us. */
|
||||
|
||||
#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \
|
||||
if (GET_CODE (x) == TRUNCATE) \
|
||||
output_addr_const (FILE, XEXP (X, 0)); \
|
||||
else \
|
||||
goto FAIL;
|
||||
#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \
|
||||
if (! v850_output_addr_const_extra (FILE, X)) \
|
||||
goto FAIL
|
||||
|
||||
/* This says how to output the assembler to define a global
|
||||
uninitialized but not common symbol. */
|
||||
@ -1243,10 +1294,12 @@ zbss_section () \
|
||||
|
||||
/* This is how to output an element of a case-vector that is relative. */
|
||||
|
||||
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
|
||||
fprintf (FILE, "\t%s .L%d-.L%d\n", \
|
||||
#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
|
||||
fprintf (FILE, "\t%s %s.L%d-.L%d%s\n", \
|
||||
(TARGET_BIG_SWITCH ? ".long" : ".short"), \
|
||||
VALUE, REL)
|
||||
(! TARGET_BIG_SWITCH && TARGET_V850E ? "(" : ""), \
|
||||
VALUE, REL, \
|
||||
(! TARGET_BIG_SWITCH && TARGET_V850E ? ")>>1" : ""))
|
||||
|
||||
#define ASM_OUTPUT_ALIGN(FILE, LOG) \
|
||||
if ((LOG) != 0) \
|
||||
@ -1426,6 +1479,9 @@ extern union tree_node * GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_K
|
||||
{ "pattern_is_ok_for_prologue", { PARALLEL }}, \
|
||||
{ "pattern_is_ok_for_epilogue", { PARALLEL }}, \
|
||||
{ "register_is_ok_for_epilogue",{ REG }}, \
|
||||
{ "pattern_is_ok_for_dispose", { PARALLEL }}, \
|
||||
{ "pattern_is_ok_for_prepare", { PARALLEL }}, \
|
||||
{ "register_is_ok_for_dispose", { REG }}, \
|
||||
{ "not_power_of_two_operand", { CONST_INT }},
|
||||
|
||||
#endif /* ! GCC_V850_H */
|
||||
|
@ -1,5 +1,5 @@
|
||||
;; GCC machine description for NEC V850
|
||||
;; Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
|
||||
;; Contributed by Jeff Law (law@cygnus.com).
|
||||
|
||||
;; This file is part of GNU CC.
|
||||
@ -153,6 +153,7 @@
|
||||
must be done with HIGH & LO_SUM patterns. */
|
||||
if (CONSTANT_P (operands[1])
|
||||
&& GET_CODE (operands[1]) != HIGH
|
||||
&& ! TARGET_V850E
|
||||
&& !special_symbolref_operand (operands[1], VOIDmode)
|
||||
&& !(GET_CODE (operands[1]) == CONST_INT
|
||||
&& (CONST_OK_FOR_J (INTVAL (operands[1]))
|
||||
@ -174,6 +175,24 @@
|
||||
}
|
||||
}")
|
||||
|
||||
;; This is the same as the following pattern, except that it includes
|
||||
;; support for arbitrary 32 bit immediates.
|
||||
|
||||
;; ??? This always loads addresses using hilo. If the only use of this address
|
||||
;; was in a load/store, then we would get smaller code if we only loaded the
|
||||
;; upper part with hi, and then put the lower part in the load/store insn.
|
||||
|
||||
(define_insn "*movsi_internal_v850e"
|
||||
[(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m,r")
|
||||
(match_operand:SI 1 "general_operand" "Jr,K,L,Q,Ir,m,R,r,I,i"))]
|
||||
"TARGET_V850E
|
||||
&& (register_operand (operands[0], SImode)
|
||||
|| reg_or_0_operand (operands[1], SImode))"
|
||||
"* return output_move_single (operands);"
|
||||
[(set_attr "length" "2,4,4,2,2,4,4,4,4,6")
|
||||
(set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
|
||||
(set_attr "type" "other,other,other,load,other,load,other,other,other,other")])
|
||||
|
||||
(define_insn "*movsi_internal"
|
||||
[(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m")
|
||||
(match_operand:SI 1 "movsi_source_operand" "Jr,K,L,Q,Ir,m,R,r,I"))]
|
||||
@ -377,6 +396,94 @@
|
||||
(set_attr "cc" "none_0hit,none_0hit")
|
||||
(set_attr "type" "mult")])
|
||||
|
||||
;; ??? The scheduling info is probably wrong.
|
||||
|
||||
;; ??? This instruction can also generate the 32 bit highpart, but using it
|
||||
;; may increase code size counter to the desired result.
|
||||
|
||||
;; ??? This instructions can also give a DImode result.
|
||||
|
||||
;; ??? There is unsigned version, but it matters only for the DImode/highpart
|
||||
;; results.
|
||||
|
||||
(define_insn "mulsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(mult:SI (match_operand:SI 1 "register_operand" "%0")
|
||||
;; %redact changeone /reg_or_int9/ 'register' unless nec-no-copyright
|
||||
(match_operand:SI 2 "reg_or_int9_operand" "rO")))]
|
||||
"TARGET_V850E"
|
||||
"mul %2,%1,%."
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "none_0hit")
|
||||
(set_attr "type" "mult")])
|
||||
|
||||
;; ----------------------------------------------------------------------
|
||||
;; DIVIDE INSTRUCTIONS
|
||||
;; ----------------------------------------------------------------------
|
||||
|
||||
;; ??? These insns do set the Z/N condition codes, except that they are based
|
||||
;; on only one of the two results, so it doesn't seem to make sense to use
|
||||
;; them.
|
||||
|
||||
;; ??? The scheduling info is probably wrong.
|
||||
|
||||
(define_insn "divmodsi4"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(div:SI (match_operand:SI 1 "register_operand" "0")
|
||||
(match_operand:SI 2 "register_operand" "r")))
|
||||
(set (match_operand:SI 3 "register_operand" "=r")
|
||||
(mod:SI (match_dup 1)
|
||||
(match_dup 2)))]
|
||||
"TARGET_V850E"
|
||||
"div %2,%0,%3"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")
|
||||
(set_attr "type" "other")])
|
||||
|
||||
(define_insn "udivmodsi4"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(udiv:SI (match_operand:SI 1 "register_operand" "0")
|
||||
(match_operand:SI 2 "register_operand" "r")))
|
||||
(set (match_operand:SI 3 "register_operand" "=r")
|
||||
(umod:SI (match_dup 1)
|
||||
(match_dup 2)))]
|
||||
"TARGET_V850E"
|
||||
"divu %2,%0,%3"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")
|
||||
(set_attr "type" "other")])
|
||||
|
||||
;; ??? There is a 2 byte instruction for generating only the quotient.
|
||||
;; However, it isn't clear how to compute the length field correctly.
|
||||
|
||||
(define_insn "divmodhi4"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(div:HI (match_operand:HI 1 "register_operand" "0")
|
||||
(match_operand:HI 2 "register_operand" "r")))
|
||||
(set (match_operand:HI 3 "register_operand" "=r")
|
||||
(mod:HI (match_dup 1)
|
||||
(match_dup 2)))]
|
||||
"TARGET_V850E"
|
||||
"divh %2,%0,%3"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")
|
||||
(set_attr "type" "other")])
|
||||
|
||||
;; Half-words are sign-extended by default, so we must zero extend to a word
|
||||
;; here before doing the divide.
|
||||
|
||||
(define_insn "udivmodhi4"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(udiv:HI (match_operand:HI 1 "register_operand" "0")
|
||||
(match_operand:HI 2 "register_operand" "r")))
|
||||
(set (match_operand:HI 3 "register_operand" "=r")
|
||||
(umod:HI (match_dup 1)
|
||||
(match_dup 2)))]
|
||||
"TARGET_V850E"
|
||||
"zxh %0 ; divhu %2,%0,%3"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")
|
||||
(set_attr "type" "other")])
|
||||
|
||||
;; ----------------------------------------------------------------------
|
||||
;; AND INSTRUCTIONS
|
||||
@ -734,6 +841,245 @@
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "none_0hit")])
|
||||
|
||||
;; ----------------------------------------------------------------------
|
||||
;; CONDITIONAL MOVE INSTRUCTIONS
|
||||
;; ----------------------------------------------------------------------
|
||||
|
||||
;; Instructions using cc0 aren't allowed to have input reloads, so we must
|
||||
;; hide the fact that this instruction uses cc0. We do so by including the
|
||||
;; compare instruction inside it.
|
||||
|
||||
;; ??? This is very ugly. The right way to do this is to modify cmpsi so
|
||||
;; that it doesn't emit RTL, and then modify the bcc/scc patterns so that
|
||||
;; they emit RTL for the compare instruction. Unfortunately, this requires
|
||||
;; lots of changes that will be hard to sanitise. So for now, cmpsi still
|
||||
;; emits RTL, and I get the compare operands here from the previous insn.
|
||||
|
||||
(define_expand "movsicc"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(match_dup 4) (match_dup 5)])
|
||||
;; %redact changeone /const/ 'int5' unless nec-no-copyright
|
||||
(match_operand:SI 2 "reg_or_const_operand" "rJ")
|
||||
;; %redact changeone /const/ '0' unless nec-no-copyright
|
||||
(match_operand:SI 3 "reg_or_const_operand" "rI")))]
|
||||
"TARGET_V850E"
|
||||
"
|
||||
{
|
||||
rtx insn = get_last_insn_anywhere ();
|
||||
|
||||
if ( (GET_CODE (operands[2]) == CONST_INT
|
||||
&& GET_CODE (operands[3]) == CONST_INT))
|
||||
{
|
||||
int o2 = INTVAL (operands[2]);
|
||||
int o3 = INTVAL (operands[3]);
|
||||
|
||||
if (o2 == 1 && o3 == 0)
|
||||
FAIL; /* setf */
|
||||
if (o3 == 1 && o2 == 0)
|
||||
FAIL; /* setf */
|
||||
if (o2 == 0 && (o3 < -16 || o3 > 15) && exact_log2 (o3) >= 0)
|
||||
FAIL; /* setf + shift */
|
||||
if (o3 == 0 && (o2 < -16 || o2 > 15) && exact_log2 (o2) >=0)
|
||||
FAIL; /* setf + shift */
|
||||
if (o2 != 0)
|
||||
operands[2] = copy_to_mode_reg (SImode, operands[2]);
|
||||
if (o3 !=0 )
|
||||
operands[3] = copy_to_mode_reg (SImode, operands[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GET_CODE (operands[2]) != REG)
|
||||
operands[2] = copy_to_mode_reg (SImode,operands[2]);
|
||||
if (GET_CODE (operands[3]) != REG)
|
||||
operands[3] = copy_to_mode_reg (SImode, operands[3]);
|
||||
}
|
||||
if (GET_CODE (insn) == INSN
|
||||
&& GET_CODE (PATTERN (insn)) == SET
|
||||
&& SET_DEST (PATTERN (insn)) == cc0_rtx)
|
||||
{
|
||||
rtx src = SET_SRC (PATTERN (insn));
|
||||
|
||||
if (GET_CODE (src) == COMPARE)
|
||||
{
|
||||
operands[4] = XEXP (src, 0);
|
||||
operands[5] = XEXP (src, 1);
|
||||
}
|
||||
else if (GET_CODE (src) == REG
|
||||
|| GET_CODE (src) == SUBREG)
|
||||
{
|
||||
operands[4] = src;
|
||||
operands[5] = const0_rtx;
|
||||
}
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
else
|
||||
abort ();
|
||||
}")
|
||||
|
||||
;; ??? Clobbering the condition codes is overkill.
|
||||
|
||||
;; ??? We sometimes emit an unnecessary compare instruction because the
|
||||
;; condition codes may have already been set by an earlier instruction,
|
||||
;; but we have no code here to avoid the compare if it is unnecessary.
|
||||
|
||||
(define_insn "*movsicc_normal"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(match_operand:SI 4 "register_operand" "r")
|
||||
(match_operand:SI 5 "reg_or_int5_operand" "rJ")])
|
||||
(match_operand:SI 2 "reg_or_int5_operand" "rJ")
|
||||
(match_operand:SI 3 "reg_or_0_operand" "rI")))]
|
||||
"TARGET_V850E"
|
||||
"cmp %5,%4 ; cmov %c1,%2,%z3,%0"
|
||||
[(set_attr "length" "6")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "*movsicc_reversed"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(match_operand:SI 4 "register_operand" "r")
|
||||
(match_operand:SI 5 "reg_or_int5_operand" "rJ")])
|
||||
(match_operand:SI 2 "reg_or_0_operand" "rI")
|
||||
(match_operand:SI 3 "reg_or_int5_operand" "rJ")))]
|
||||
"TARGET_V850E"
|
||||
"cmp %5,%4 ; cmov %C1,%3,%z2,%0"
|
||||
[(set_attr "length" "6")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "*movsicc_tst1"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(zero_extract:SI
|
||||
(match_operand:QI 2 "memory_operand" "m")
|
||||
(const_int 1)
|
||||
(match_operand 3 "const_int_operand" "n"))
|
||||
(const_int 0)])
|
||||
(match_operand:SI 4 "reg_or_int5_operand" "rJ")
|
||||
(match_operand:SI 5 "reg_or_0_operand" "rI")))]
|
||||
"TARGET_V850E"
|
||||
"tst1 %3,%2 ; cmov %c1,%4,%z5,%0"
|
||||
[(set_attr "length" "8")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "*movsicc_tst1_reversed"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(zero_extract:SI
|
||||
(match_operand:QI 2 "memory_operand" "m")
|
||||
(const_int 1)
|
||||
(match_operand 3 "const_int_operand" "n"))
|
||||
(const_int 0)])
|
||||
(match_operand:SI 4 "reg_or_0_operand" "rI")
|
||||
(match_operand:SI 5 "reg_or_int5_operand" "rJ")))]
|
||||
"TARGET_V850E"
|
||||
"tst1 %3,%2 ; cmov %C1,%5,%z4,%0"
|
||||
[(set_attr "length" "8")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Matching for sasf requires combining 4 instructions, so we provide a
|
||||
;; dummy pattern to match the first 3, which will always be turned into the
|
||||
;; second pattern by subsequent combining. As above, we must include the
|
||||
;; comparison to avoid input reloads in an insn using cc0.
|
||||
|
||||
(define_insn "*sasf_1"
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(ior:SI (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
|
||||
(ashift:SI (match_operand:SI 2 "register_operand" "")
|
||||
(const_int 1))))]
|
||||
"TARGET_V850E"
|
||||
"* abort ();")
|
||||
|
||||
(define_insn "*sasf_2"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(ior:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(match_operand:SI 3 "register_operand" "r")
|
||||
(match_operand:SI 4 "reg_or_int5_operand" "rJ")])
|
||||
(ashift:SI (match_operand:SI 2 "register_operand" "0")
|
||||
(const_int 1))))]
|
||||
"TARGET_V850E"
|
||||
"cmp %4,%3 ; sasf %c1,%0"
|
||||
[(set_attr "length" "6")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_split
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(if_then_else:SI
|
||||
(match_operator 1 "comparison_operator"
|
||||
[(match_operand:SI 4 "register_operand" "")
|
||||
(match_operand:SI 5 "reg_or_int5_operand" "")])
|
||||
(match_operand:SI 2 "const_int_operand" "")
|
||||
(match_operand:SI 3 "const_int_operand" "")))]
|
||||
"TARGET_V850E
|
||||
&& ((INTVAL (operands[2]) ^ INTVAL (operands[3])) == 1)
|
||||
&& ((INTVAL (operands[2]) + INTVAL (operands[3])) != 1)
|
||||
&& (GET_CODE (operands[5]) == CONST_INT
|
||||
|| REGNO (operands[0]) != REGNO (operands[5]))
|
||||
&& REGNO (operands[0]) != REGNO (operands[4])"
|
||||
[(set (match_dup 0) (match_dup 6))
|
||||
(set (match_dup 0)
|
||||
(ior:SI (match_op_dup 7 [(match_dup 4) (match_dup 5)])
|
||||
(ashift:SI (match_dup 0) (const_int 1))))]
|
||||
"
|
||||
{
|
||||
operands[6] = GEN_INT (INTVAL (operands[2]) >> 1);
|
||||
if (INTVAL (operands[2]) & 0x1)
|
||||
operands[7] = operands[1];
|
||||
else
|
||||
operands[7] = gen_rtx (reverse_condition (GET_CODE (operands[1])),
|
||||
GET_MODE (operands[1]), XEXP (operands[1], 0),
|
||||
XEXP (operands[1], 1));
|
||||
}")
|
||||
;; ---------------------------------------------------------------------
|
||||
;; BYTE SWAP INSTRUCTIONS
|
||||
;; ---------------------------------------------------------------------
|
||||
|
||||
(define_expand "rotlhi3"
|
||||
[(set (match_operand:HI 0 "register_operand" "")
|
||||
(rotate:HI (match_operand:HI 1 "register_operand" "")
|
||||
(match_operand:HI 2 "const_int_operand" "")))]
|
||||
"TARGET_V850E"
|
||||
"
|
||||
{
|
||||
if (INTVAL (operands[2]) != 8)
|
||||
FAIL;
|
||||
}")
|
||||
|
||||
(define_insn "*rotlhi3_8"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(rotate:HI (match_operand:HI 1 "register_operand" "r")
|
||||
(const_int 8)))]
|
||||
"TARGET_V850E"
|
||||
"bsh %1,%0"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_expand "rotlsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(rotate:SI (match_operand:SI 1 "register_operand" "")
|
||||
(match_operand:SI 2 "const_int_operand" "")))]
|
||||
"TARGET_V850E"
|
||||
"
|
||||
{
|
||||
if (INTVAL (operands[2]) != 16)
|
||||
FAIL;
|
||||
}")
|
||||
|
||||
(define_insn "*rotlsi3_16"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(rotate:SI (match_operand:SI 1 "register_operand" "r")
|
||||
(const_int 16)))]
|
||||
"TARGET_V850E"
|
||||
"hsw %1,%0"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; ----------------------------------------------------------------------
|
||||
;; JUMP INSTRUCTIONS
|
||||
@ -921,6 +1267,20 @@
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "switch"
|
||||
[(set (pc)
|
||||
(plus:SI
|
||||
(sign_extend:SI
|
||||
(mem:HI
|
||||
(plus:SI (ashift:SI (match_operand:SI 0 "register_operand" "r")
|
||||
(const_int 1))
|
||||
(label_ref (match_operand 1 "" "")))))
|
||||
(label_ref (match_dup 1))))]
|
||||
"TARGET_V850E"
|
||||
"switch %0"
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_expand "casesi"
|
||||
[(match_operand:SI 0 "register_operand" "")
|
||||
(match_operand:SI 1 "register_operand" "")
|
||||
@ -940,6 +1300,12 @@
|
||||
/* Branch to the default label if out of range of the table. */
|
||||
emit_jump_insn (gen_bgtu (operands[4]));
|
||||
|
||||
if (! TARGET_BIG_SWITCH && TARGET_V850E)
|
||||
{
|
||||
emit_jump_insn (gen_switch (reg, operands[3]));
|
||||
DONE;
|
||||
}
|
||||
|
||||
/* Shift index for the table array access. */
|
||||
emit_insn (gen_ashlsi3 (reg, reg, GEN_INT (TARGET_BIG_SWITCH ? 2 : 1)));
|
||||
/* Load the table address into a pseudo. */
|
||||
@ -1084,6 +1450,18 @@
|
||||
;; EXTEND INSTRUCTIONS
|
||||
;; ----------------------------------------------------------------------
|
||||
|
||||
(define_insn ""
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
|
||||
(zero_extend:SI
|
||||
(match_operand:HI 1 "nonimmediate_operand" "0,r,T,m")))]
|
||||
"TARGET_V850E"
|
||||
"@
|
||||
zxh %0
|
||||
andi 65535,%1,%0
|
||||
sld.hu %1,%0
|
||||
ld.hu %1,%0"
|
||||
[(set_attr "length" "2,4,2,4")
|
||||
(set_attr "cc" "none_0hit,set_znv,none_0hit,none_0hit")])
|
||||
|
||||
(define_insn "zero_extendhisi2"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
@ -1094,6 +1472,18 @@
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "set_znv")])
|
||||
|
||||
(define_insn ""
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
|
||||
(zero_extend:SI
|
||||
(match_operand:QI 1 "nonimmediate_operand" "0,r,T,m")))]
|
||||
"TARGET_V850E"
|
||||
"@
|
||||
zxb %0
|
||||
andi 255,%1,%0
|
||||
sld.bu %1,%0
|
||||
ld.bu %1,%0"
|
||||
[(set_attr "length" "2,4,2,4")
|
||||
(set_attr "cc" "none_0hit,set_znv,none_0hit,none_0hit")])
|
||||
|
||||
(define_insn "zero_extendqisi2"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
@ -1106,6 +1496,18 @@
|
||||
|
||||
;;- sign extension instructions
|
||||
|
||||
;; ??? The extendhisi2 pattern should not emit shifts for v850e?
|
||||
|
||||
(define_insn "*extendhisi_insn"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
|
||||
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,Q,m")))]
|
||||
"TARGET_V850E"
|
||||
"@
|
||||
sxh %0
|
||||
sld.h %1,%0
|
||||
ld.h %1,%0"
|
||||
[(set_attr "length" "2,2,4")
|
||||
(set_attr "cc" "none_0hit,none_0hit,none_0hit")])
|
||||
|
||||
;; ??? This is missing a sign extend from memory pattern to match the ld.h
|
||||
;; instruction.
|
||||
@ -1124,6 +1526,18 @@
|
||||
operands[2] = gen_reg_rtx (SImode);
|
||||
}")
|
||||
|
||||
;; ??? The extendqisi2 pattern should not emit shifts for v850e?
|
||||
|
||||
(define_insn "*extendqisi_insn"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
|
||||
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,Q,m")))]
|
||||
"TARGET_V850E"
|
||||
"@
|
||||
sxb %0
|
||||
sld.b %1,%0
|
||||
ld.b %1,%0"
|
||||
[(set_attr "length" "2,2,4")
|
||||
(set_attr "cc" "none_0hit,none_0hit,none_0hit")])
|
||||
|
||||
;; ??? This is missing a sign extend from memory pattern to match the ld.b
|
||||
;; instruction.
|
||||
@ -1229,6 +1643,21 @@
|
||||
;; RTXs. These RTXs will then be turned into a suitable call to a worker
|
||||
;; function.
|
||||
|
||||
;;
|
||||
;; Actually, convert the RTXs into a PREPARE instruction.
|
||||
;;
|
||||
(define_insn ""
|
||||
[(match_parallel 0 "pattern_is_ok_for_prepare"
|
||||
[(set (reg:SI 3)
|
||||
(plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
|
||||
(set (mem:SI (plus:SI (reg:SI 3)
|
||||
(match_operand:SI 2 "immediate_operand" "i")))
|
||||
(match_operand:SI 3 "register_is_ok_for_epilogue" "r"))])]
|
||||
"TARGET_PROLOG_FUNCTION && TARGET_V850E"
|
||||
"* return construct_prepare_instruction (operands[0]);
|
||||
"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn ""
|
||||
[(match_parallel 0 "pattern_is_ok_for_prologue"
|
||||
@ -1245,6 +1674,23 @@
|
||||
(const_string "4")))
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;;
|
||||
;; Actually, turn the RTXs into a DISPOSE instruction.
|
||||
;;
|
||||
(define_insn ""
|
||||
[(match_parallel 0 "pattern_is_ok_for_dispose"
|
||||
[(return)
|
||||
(set (reg:SI 3)
|
||||
(plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
|
||||
(set (match_operand:SI 2 "register_is_ok_for_epilogue" "=r")
|
||||
(mem:SI (plus:SI (reg:SI 3)
|
||||
(match_operand:SI 3 "immediate_operand" "i"))))])]
|
||||
"TARGET_PROLOG_FUNCTION && TARGET_V850E"
|
||||
"* return construct_dispose_instruction (operands[0]);
|
||||
"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
;; This pattern will match a return RTX followed by any number of pop RTXs
|
||||
;; and possible a stack adjustment as well. These RTXs will be turned into
|
||||
;; a suitable call to a worker function.
|
||||
@ -1266,30 +1712,94 @@
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Initialize an interrupt function. Do not depend on TARGET_PROLOG_FUNCTION.
|
||||
(define_insn "callt_save_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 2)]
|
||||
"TARGET_V850E && !TARGET_DISABLE_CALLT"
|
||||
;; The CALLT instruction stores the next address of CALLT to CTPC register
|
||||
;; without saving its previous value. So if the interrupt handler
|
||||
;; or its caller could possibily execute the CALLT insn, save_interrupt
|
||||
;; MUST NOT be called via CALLT.
|
||||
"*
|
||||
{
|
||||
output_asm_insn (\"addi -24, sp, sp\", operands);
|
||||
output_asm_insn (\"st.w r10, 12[sp]\", operands);
|
||||
output_asm_insn (\"stsr ctpc, r10\", operands);
|
||||
output_asm_insn (\"st.w r10, 16[sp]\", operands);
|
||||
output_asm_insn (\"stsr ctpsw, r10\", operands);
|
||||
output_asm_insn (\"st.w r10, 20[sp]\", operands);
|
||||
output_asm_insn (\"callt ctoff(__callt_save_interrupt)\", operands);
|
||||
return \"\";
|
||||
}"
|
||||
[(set_attr "length" "26")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "callt_return_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 3)]
|
||||
"TARGET_V850E && !TARGET_DISABLE_CALLT"
|
||||
"callt ctoff(__callt_return_interrupt)"
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "save_interrupt"
|
||||
[(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int -16)))
|
||||
(set (mem:SI (reg:SI 3)) (reg:SI 30))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -4))) (reg:SI 10))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -8))) (reg:SI 4))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 1))]
|
||||
"TARGET_V850 && ! TARGET_LONG_CALLS"
|
||||
"add -16, sp ; st.w r10, 12[sp] ; jarl __save_interrupt, r10"
|
||||
[(set_attr "length" "12")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Restore r1, r4, r10, and return from the interrupt
|
||||
(define_insn "restore_interrupt"
|
||||
[(return)
|
||||
(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int 16)))
|
||||
(set (reg:SI 30) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
|
||||
(set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 8))))
|
||||
(set (reg:SI 4) (mem:SI (plus:SI (reg:SI 3) (const_int 4))))
|
||||
(set (reg:SI 1) (mem:SI (reg:SI 3)))]
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -16))) (reg:SI 30))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 4))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -8))) (reg:SI 1))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int -4))) (reg:SI 10))]
|
||||
""
|
||||
"jr __return_interrupt"
|
||||
[(set_attr "length" "4")
|
||||
"*
|
||||
{
|
||||
if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
|
||||
return \"add -16,sp\;st.w r10,12[sp]\;jarl __save_interrupt,r10\";
|
||||
else
|
||||
{
|
||||
output_asm_insn (\"add -16, sp\", operands);
|
||||
output_asm_insn (\"st.w r10, 12[sp]\", operands);
|
||||
output_asm_insn (\"st.w ep, 0[sp]\", operands);
|
||||
output_asm_insn (\"st.w gp, 4[sp]\", operands);
|
||||
output_asm_insn (\"st.w r1, 8[sp]\", operands);
|
||||
output_asm_insn (\"movhi hi(__ep), r0, ep\", operands);
|
||||
output_asm_insn (\"movea lo(__ep), ep, ep\", operands);
|
||||
output_asm_insn (\"movhi hi(__gp), r0, gp\", operands);
|
||||
output_asm_insn (\"movea lo(__gp), gp, gp\", operands);
|
||||
return \"\";
|
||||
}
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
|
||||
(const_int 10)
|
||||
(const_int 34)))
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Restore r1, r4, r10, and return from the interrupt
|
||||
(define_insn "return_interrupt"
|
||||
[(return)
|
||||
(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int 16)))
|
||||
(set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
|
||||
(set (reg:SI 1) (mem:SI (plus:SI (reg:SI 3) (const_int 8))))
|
||||
(set (reg:SI 4) (mem:SI (plus:SI (reg:SI 3) (const_int 4))))
|
||||
(set (reg:SI 30) (mem:SI (reg:SI 3)))]
|
||||
""
|
||||
"*
|
||||
{
|
||||
if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
|
||||
return \"jr __return_interrupt\";
|
||||
else
|
||||
{
|
||||
output_asm_insn (\"ld.w 0[sp], ep\", operands);
|
||||
output_asm_insn (\"ld.w 4[sp], gp\", operands);
|
||||
output_asm_insn (\"ld.w 8[sp], r1\", operands);
|
||||
output_asm_insn (\"ld.w 12[sp], r10\", operands);
|
||||
output_asm_insn (\"addi 16, sp, sp\", operands);
|
||||
output_asm_insn (\"reti\", operands);
|
||||
return \"\";
|
||||
}
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
|
||||
(const_int 4)
|
||||
(const_int 24)))
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
|
||||
;; Save all registers except for the registers saved in save_interrupt when
|
||||
;; an interrupt function makes a call.
|
||||
@ -1298,21 +1808,130 @@
|
||||
;; This is needed because the rest of the compiler is not ready to handle
|
||||
;; insns this complicated.
|
||||
|
||||
(define_insn "callt_save_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 0)]
|
||||
"TARGET_V850E && !TARGET_DISABLE_CALLT"
|
||||
"callt ctoff(__callt_save_all_interrupt)"
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "save_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 0)]
|
||||
""
|
||||
"*
|
||||
{
|
||||
if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
|
||||
return \"jarl __save_all_interrupt,r10\";
|
||||
|
||||
output_asm_insn (\"addi -120, sp, sp\", operands);
|
||||
output_asm_insn (\"mov ep, r1\", operands);
|
||||
output_asm_insn (\"mov sp, ep\", operands);
|
||||
output_asm_insn (\"sst.w r31, 116[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r2, 112[ep]\", operands);
|
||||
output_asm_insn (\"sst.w gp, 108[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r6, 104[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r7, 100[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r8, 96[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r9, 92[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r11, 88[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r12, 84[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r13, 80[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r14, 76[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r15, 72[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r16, 68[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r17, 64[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r18, 60[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r19, 56[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r20, 52[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r21, 48[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r22, 44[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r23, 40[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r24, 36[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r25, 32[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r26, 28[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r27, 24[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r28, 20[ep]\", operands);
|
||||
output_asm_insn (\"sst.w r29, 16[ep]\", operands);
|
||||
output_asm_insn (\"mov r1, ep\", operands);
|
||||
return \"\";
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
|
||||
(const_int 4)
|
||||
(const_int 62)
|
||||
))
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "_save_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 0)]
|
||||
"TARGET_V850 && ! TARGET_LONG_CALLS"
|
||||
"jarl __save_all_interrupt,r10"
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
|
||||
;; Restore all registers saved when an interrupt function makes a call.
|
||||
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
|
||||
;; all of memory. This blocks insns from being moved across this point.
|
||||
;; This is needed because the rest of the compiler is not ready to handle
|
||||
;; insns this complicated.
|
||||
|
||||
(define_insn "callt_restore_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 1)]
|
||||
"TARGET_V850E && !TARGET_DISABLE_CALLT"
|
||||
"callt ctoff(__callt_restore_all_interrupt)"
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "restore_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 1)]
|
||||
""
|
||||
"*
|
||||
{
|
||||
if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
|
||||
return \"jarl __restore_all_interrupt,r10\";
|
||||
else
|
||||
{
|
||||
output_asm_insn (\"mov ep, r1\", operands);
|
||||
output_asm_insn (\"mov sp, ep\", operands);
|
||||
output_asm_insn (\"sld.w 116[ep], r31\", operands);
|
||||
output_asm_insn (\"sld.w 112[ep], r2\", operands);
|
||||
output_asm_insn (\"sld.w 108[ep], gp\", operands);
|
||||
output_asm_insn (\"sld.w 104[ep], r6\", operands);
|
||||
output_asm_insn (\"sld.w 100[ep], r7\", operands);
|
||||
output_asm_insn (\"sld.w 96[ep], r8\", operands);
|
||||
output_asm_insn (\"sld.w 92[ep], r9\", operands);
|
||||
output_asm_insn (\"sld.w 88[ep], r11\", operands);
|
||||
output_asm_insn (\"sld.w 84[ep], r12\", operands);
|
||||
output_asm_insn (\"sld.w 80[ep], r13\", operands);
|
||||
output_asm_insn (\"sld.w 76[ep], r14\", operands);
|
||||
output_asm_insn (\"sld.w 72[ep], r15\", operands);
|
||||
output_asm_insn (\"sld.w 68[ep], r16\", operands);
|
||||
output_asm_insn (\"sld.w 64[ep], r17\", operands);
|
||||
output_asm_insn (\"sld.w 60[ep], r18\", operands);
|
||||
output_asm_insn (\"sld.w 56[ep], r19\", operands);
|
||||
output_asm_insn (\"sld.w 52[ep], r20\", operands);
|
||||
output_asm_insn (\"sld.w 48[ep], r21\", operands);
|
||||
output_asm_insn (\"sld.w 44[ep], r22\", operands);
|
||||
output_asm_insn (\"sld.w 40[ep], r23\", operands);
|
||||
output_asm_insn (\"sld.w 36[ep], r24\", operands);
|
||||
output_asm_insn (\"sld.w 32[ep], r25\", operands);
|
||||
output_asm_insn (\"sld.w 28[ep], r26\", operands);
|
||||
output_asm_insn (\"sld.w 24[ep], r27\", operands);
|
||||
output_asm_insn (\"sld.w 20[ep], r28\", operands);
|
||||
output_asm_insn (\"sld.w 16[ep], r29\", operands);
|
||||
output_asm_insn (\"mov r1, ep\", operands);
|
||||
output_asm_insn (\"addi 120, sp, sp\", operands);
|
||||
return \"\";
|
||||
}
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
|
||||
(const_int 4)
|
||||
(const_int 62)
|
||||
))
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "_restore_all_interrupt"
|
||||
[(unspec_volatile [(const_int 0)] 1)]
|
||||
"TARGET_V850 && ! TARGET_LONG_CALLS"
|
||||
"jarl __restore_all_interrupt,r10"
|
||||
@ -1320,6 +1939,17 @@
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Save r6-r9 for a variable argument function
|
||||
(define_insn "save_r6_r9_v850e"
|
||||
[(set (mem:SI (reg:SI 3)) (reg:SI 6))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int 8))) (reg:SI 8))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int 12))) (reg:SI 9))
|
||||
]
|
||||
"TARGET_PROLOG_FUNCTION && TARGET_V850E && !TARGET_DISABLE_CALLT"
|
||||
"callt ctoff(__callt_save_r6_r9)"
|
||||
[(set_attr "length" "2")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "save_r6_r9"
|
||||
[(set (mem:SI (reg:SI 3)) (reg:SI 6))
|
||||
(set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))
|
||||
|
@ -577,6 +577,9 @@ in the following sections.
|
||||
-mlong-calls -mno-long-calls -mep -mno-ep @gol
|
||||
-mprolog-function -mno-prolog-function -mspace @gol
|
||||
-mtda=@var{n} -msda=@var{n} -mzda=@var{n} @gol
|
||||
-mapp-regs -mno-app-regs @gol
|
||||
-mdisable-callt -mno-disable-callt @gol
|
||||
-mv850e @gol
|
||||
-mv850 -mbig-switch}
|
||||
|
||||
@emph{NS32K Options}
|
||||
@ -8682,6 +8685,34 @@ Specify that the target processor is the V850.
|
||||
Generate code suitable for big switch tables. Use this option only if
|
||||
the assembler/linker complain about out of range branches within a switch
|
||||
table.
|
||||
|
||||
@item -mapp-regs
|
||||
@opindex -mapp-regs
|
||||
This option will cause r2 and r5 to be used in the code generated by
|
||||
the compiler. This setting is the default.
|
||||
|
||||
@item -mno-app-regs
|
||||
@opindex -mno-app-regs
|
||||
This option will cause r2 and r5 to be treated as fixed registers.
|
||||
|
||||
@item -mv850e
|
||||
@opindex -mv850e
|
||||
Specify that the target processor is the V850E. The preprocessor
|
||||
constant @samp{__v850e__} will be defined if this option is used.
|
||||
|
||||
If neither @option{-mv850} nor @option{-mv850e} are defined
|
||||
then a default target processor will be chosen and the relevant
|
||||
@samp{__v850*__} preprocessor constant will be defined.
|
||||
|
||||
The preprocessor constants @samp{__v850} and @samp{__v851__} are always
|
||||
defined, regardless of which processor variant is the target.
|
||||
|
||||
@item -mdisable-callt
|
||||
@opindex -mdisable-callt
|
||||
This option will suppress generation of the CALLT instruction for the
|
||||
v850e flavors of the v850 architecture. The default is
|
||||
@option{-mno-disable-callt} which allows the CALLT instruction to be used.
|
||||
|
||||
@end table
|
||||
|
||||
@node ARC Options
|
||||
|
Loading…
x
Reference in New Issue
Block a user