Commit 9d6193a7 by Chen Liqin Committed by Chen Liqin

config.gcc (score-*-elf): add extra_parts .., update tmake_file, extra_objs.

	* config.gcc (score-*-elf): add extra_parts .., update tmake_file, extra_objs.
	* config/score/score3.c: Delete.
	* config/score/score3.h: Delete.
	* config/score/mul-div.S: Delete.
	* config/score/sfp-machine.h: Add new file.
	* config/score/constraints.md: Add new file.
	* config/score/t-score-softfp: Add new file.
	* config/score/t-score-elf: Remove score3.o and multilib generate.
	* config/score/score7.c (score7_const_ok_for_letter_p): Delete.
	(score7_extra_constraint): Delete.
	(score7_option_override): Remove unused code which mode to constraint.md.
	* config/score/score.c: Remove score3 and score5 define and code.
	* config/score/score.h: Remove score3 and score5 define and code.
	* config/score/score.md: Remove score3 template and unusal insn generate.
	* config/score/score.opt: Remove score3 and score5 options.

From-SVN: r170864
parent fdc1806a
2011-03-11 Chen Liqin <liqin.gcc@gmail.com>
* config.gcc (score-*-elf): add extra_parts .., update tmake_file, extra_objs.
* config/score/score3.c: Delete.
* config/score/score3.h: Delete.
* config/score/mul-div.S: Delete.
* config/score/sfp-machine.h: Add new file.
* config/score/constraints.md: Add new file.
* config/score/t-score-softfp: Add new file.
* config/score/t-score-elf: Remove score3.o and multilib generate.
* config/score/score7.c (score7_const_ok_for_letter_p): Delete.
(score7_extra_constraint): Delete.
(score7_option_override): Remove unused code which mode to constraint.md.
* config/score/score.c: Remove score3 and score5 define and code.
* config/score/score.h: Remove score3 and score5 define and code.
* config/score/score.md: Remove score3 template and unusal insn generate.
* config/score/score.opt: Remove score3 and score5 options.
2011-03-10 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* config/pa/pa-hpux10.h (TARGET_OS_CPP_BUILTINS): Define _REENTRANT
......
......@@ -2306,9 +2306,12 @@ s390x-ibm-tpf*)
extra_options="${extra_options} s390/tpf.opt"
;;
score-*-elf)
gas=yes
gnu_ld=yes
tm_file="dbxelf.h elfos.h score/elf.h score/score.h newlib-stdint.h"
tmake_file=score/t-score-elf
extra_objs="score7.o score3.o"
extra_parts="crti.o crtn.o crtbegin.o crtend.o"
tmake_file="${tmake_file} score/t-score-elf score/t-score-softfp soft-fp/t-softfp"
extra_objs="score7.o"
;;
sh-*-elf* | sh[12346l]*-*-elf* | \
sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \
......
;; Constraint definitions for S+CORE
;; Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Contributed by Sunnorth.
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;; GCC is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
;; License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>. */
;; -------------------------------------------------------------------------
;; Constraints
;; -------------------------------------------------------------------------
;; Register constraints.
(define_register_constraint "d" "G32_REGS"
"r0 to r31")
(define_register_constraint "e" "G16_REGS"
"r0 to r15")
(define_register_constraint "t" "T32_REGS"
"r8 to r11 | r22 to r27")
(define_register_constraint "h" "HI_REG"
"hi")
(define_register_constraint "l" "LO_REG"
"lo")
(define_register_constraint "x" "CE_REGS"
"hi + lo")
(define_register_constraint "q" "CN_REG"
"cnt")
(define_register_constraint "y" "LC_REG"
"lcb")
(define_register_constraint "z" "SC_REG"
"scb")
(define_register_constraint "a" "SP_REGS"
"cnt + lcb + scb")
(define_register_constraint "c" "CR_REGS"
"cr0 to cr15")
;; Integer constant constraints.
(define_constraint "I"
"High 16-bit constant (32-bit constant with 16 LSBs zero)."
(and (match_code "const_int")
(match_test "(ival & 0xffff) == 0")))
(define_constraint "J"
"Unsigned 5 bit integer (in the range 0 to 31)."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 31")))
(define_constraint "K"
"Unsigned 16 bit integer (in the range 0 to 65535)."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 65535")))
(define_constraint "L"
"Signed 16 bit integer (in the range −32768 to 32767)."
(and (match_code "const_int")
(match_test "ival >= -32768 && ival <= 32767")))
(define_constraint "M"
"Unsigned 14 bit integer (in the range 0 to 16383)."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 16383")))
(define_constraint "N"
"Signed 14 bit integer (in the range −8192 to 8191)."
(and (match_code "const_int")
(match_test "ival >= -8192 && ival <= 8191")))
(define_constraint "Z"
"Any SYMBOL_REF."
(and (match_code "symbol_ref")
(match_test "GET_CODE (op) == SYMBOL_REF")))
# crti.asm for Sunplus S+CORE
#
# Copyright (C) 2005, 2009 Free Software Foundation, Inc.
# Copyright (C) 2005, 2009, 2010 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
......
# crtn.asm for Sunplus S+CORE
# Copyright (C) 2005, 2009 Free Software Foundation, Inc.
# Copyright (C) 2005, 2009, 2010 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
......
/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by Sunnorth
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define ra r3
#define a0 r4
#define a1 r5
#define a2 r6
#define a3 r7
#define v0 r23
#define t0 r8
#define t1 r9
#define t2 r10
#define t3 r11
#define t4 r22
#ifndef __pic__
#if !defined(L_mulsi3) && !defined(L_divsi3)
.text
.global _flush_cache
#ifdef __score3__
_flush_cache:
br r3
#else
_flush_cache:
srli r9, r5, 4
mv r8, r4
mtsr r9, sr0
1:
cache 0xe, [r8, 0] # write back invalid dcache
addi r8, 16
bcnz 1b
mfcr r8, cr4
bittst! r8, 0x3 # if LDM is enable, write back LDM
beq! 6f
ldi r10, 0
cache 0xc, [r10, 0]
6:
bittst! r8, 0x2 # if LIM is enable, refill it
beq! 7f
cache 0x4, [r10, 0]
7:
#nop!
#nop!
#nop!
#nop!
#nop!
mv r8, r4
mtsr r9, sr0
2:
cache 0x2, [r8, 0] # invalid unlock icache
#nop!
#nop!
#nop!
#nop!
#nop!
addi r8, 16
bcnz 2b
br r3
#endif
#endif
/* FUNCTION
(U) INT32 v0 = __mulsi3 ((U) INT32 a0, (U) INT32 a1);
REGISTERS:
use t0
modify a0
a1 -> become 0
NOTE:
this seems to give better performance to just rotate and add. */
#ifdef L_mulsi3
.text
.global __umulsi3
.global __mulsi3
/* signed multiplication (32x32) */
.ent __mulsi3
__umulsi3:
__mulsi3:
li t1, 0
__mulsi3_loop:
andri.c t0, a1, 1 # t0 = multiplier[0]
srli a1, a1, 1 # a1 /= 2
beq __mulsi3_loop2 # skip if (t0 == 0)
add t1, t1, a0 # add multiplicand
__mulsi3_loop2:
slli a0, a0, 1 # multiplicand mul 2
cmpi.c a1, 0
bne __mulsi3_loop
mv r4, t1
br ra
.end __mulsi3
#endif /* L_mulsi3 */
/* FUNCTION
UINT32 (v0) = __udivsi3 (UINT32 (a0), UINT32 (a1));
INT32 (v0) = __divsi3 (INT32 (a0), INT32 (a1));
UINT32 (v0) = __umodsi3 (UINT32 (a0), UINT32 (a1));
INT32 (v0) = __modsi3 (INT32 (a0), INT32 (a1));
DESCRIPTION
performs 32-bit division/modulo.
REGISTERS
used t0 bit-index
t1
modify a0 becomes remainer */
#ifdef L_divsi3
.text
.global __udivsi3
.global __umodsi3
.global __divsi3
.global __modsi3
/* unsigned division */
.ent __udivsi3
__udivsi3:
li t4, 0
cmpi.c a1, 0
beq __uds_exit
li t0, 1
blt __uds_ok
__uds_normalize:
cmp.c a0, a1
bcc __uds_ok
slli a1, a1, 1
slli t0, t0, 1
cmpi.c a1, 0
bge __uds_normalize
__uds_ok:
__uds_loop2:
cmp.c a0, a1
bcc __uds_loop3
sub a0, a0, a1
or t4, t4, t0
__uds_loop3:
srli t0, t0, 1
srli a1, a1, 1
cmpi.c t0, 0
bne __uds_loop2
__uds_exit:
mv a1, a0
mv r4, t4
br ra
.end __udivsi3
/* unsigned modulus */
.ent __umodsi3
__umodsi3:
mv t3, ra
jl __udivsi3
mv r4, a1
br t3
.end __umodsi3
/* abs and div */
.ent __orgsi3
__orgsi3:
cmpi.c a0, 0
bge __orgsi3_a0p
neg a0, a0
__orgsi3_a0p:
cmpi.c a1, 0
bge __udivsi3
neg a1, a1
b __udivsi3 # goto udivsi3
.end __orgsi3
/* signed division */
.ent __divsi3
__divsi3:
mv t3, ra
xor t2, a0, a1
jl __orgsi3
__divsi3_adjust:
cmpi.c t2, 0
bge __divsi3_exit
neg r4, r4
__divsi3_exit:
br t3
.end __divsi3
/* signed modulus */
.ent __modsi3
__modsi3:
mv t3, ra
mv t2, a0
jl __orgsi3
mv r4, a1
b __divsi3_adjust
.end __modsi3
#endif /* L_divsi3 */
#else /* -fPIC */
#if !defined(L_mulsi3) && !defined(L_divsi3)
.set pic
.text
.global _flush_cache
#ifdef __score3__
_flush_cache:
br r3
#else
_flush_cache:
addi r0, -8 # pic used
.cpload r29 # pic used
srli r9, r5, 4
mv r8, r4
mtsr r9, sr0
1:
cache 0xe, [r8, 0] # write back invalid dcache
addi r8, 16
bcnz 1b
mfcr r8, cr4
bittst! r8, 0x3 # if LDM is enable, write back LDM
beq! 6f
ldi r10, 0
cache 0xc, [r10, 0]
6:
bittst! r8, 0x2 # if LIM is enable, refill it
beq! 7f
cache 0x4, [r10, 0]
7:
#nop!
#nop!
#nop!
#nop!
#nop!
mv r8, r4
mtsr r9, sr0
2:
cache 0x2, [r8, 0] # invalid unlock icache
#nop!
#nop!
#nop!
#nop!
#nop!
addi r8, 16
bcnz 2b
.cprestore r0, 12 # pic used
addi r0, 8 # pic used
br r3
#endif
#endif
/* FUNCTION
(U) INT32 v0 = __mulsi3 ((U) INT32 a0, (U) INT32 a1);
REGISTERS:
use t0
modify a0
a1 -> become 0
NOTE:
this seems to give better performance to just rotate and add. */
#ifdef L_mulsi3
.set pic
.text
.global __umulsi3
.global __mulsi3
/* signed multiplication (32x32) */
.ent __mulsi3
__umulsi3:
__mulsi3:
addi r0, -8 # pic used
.cpload r29 # pic used
li t1, 0
__mulsi3_loop:
andri.c t0, a1, 1 # t0 = multiplier[0]
srli a1, a1, 1 # a1 /= 2
beq __mulsi3_loop2 # skip if (t0 == 0)
add t1, t1, a0 # add multiplicand
__mulsi3_loop2:
slli a0, a0, 1 # multiplicand mul 2
cmpi.c a1, 0
bne __mulsi3_loop
mv r4, t1
.cprestore r0, 12 # pic used
addi r0, 8 # pic used
br ra
.end __mulsi3
#endif /* L_mulsi3 */
/* FUNCTION
UINT32 (v0) = __udivsi3 (UINT32 (a0), UINT32 (a1));
INT32 (v0) = __divsi3 (INT32 (a0), INT32 (a1));
UINT32 (v0) = __umodsi3 (UINT32 (a0), UINT32 (a1));
INT32 (v0) = __modsi3 (INT32 (a0), INT32 (a1));
DESCRIPTION
performs 32-bit division/modulo.
REGISTERS
used t0 bit-index
t1
modify a0 becomes remainer */
#ifdef L_divsi3
.set pic
.text
.global __udivsi3
.global __umodsi3
.global __divsi3
.global __modsi3
/* unsigned division */
.ent __udivsi3
__udivsi3:
addi r0, -8 # pic used
.cpload r29 # pic used
li t4, 0
cmpi.c a1, 0
beq __uds_exit
li t0, 1
blt __uds_ok
__uds_normalize:
cmp.c a0, a1
bcc __uds_ok
slli a1, a1, 1
slli t0, t0, 1
cmpi.c a1, 0
bge __uds_normalize
__uds_ok:
__uds_loop2:
cmp.c a0, a1
bcc __uds_loop3
sub a0, a0, a1
or t4, t4, t0
__uds_loop3:
srli t0, t0, 1
srli a1, a1, 1
cmpi.c t0, 0
bne __uds_loop2
__uds_exit:
mv a1, a0
mv r4, t4
.cprestore r0, 12 # pic used
addi r0, 8 # pic used
br ra
.end __udivsi3
/* unsigned modulus */
.ent __umodsi3
__umodsi3:
addi r0, -8 # pic used
.cpload r29 # pic used
li t1, 0
mv t3, ra
la r29, __udivsi3
brl r29
mv r4, a1
.cprestore r0, 12 # pic used
addi r0, 8 # pic used
br t3
.end __umodsi3
/* abs and div */
.ent __orgsi3
__orgsi3:
cmpi.c a0, 0
bge __orgsi3_a0p
neg a0, a0
__orgsi3_a0p:
cmpi.c a1, 0
bge __udivsi3
neg a1, a1
b __udivsi3 # goto udivsi3
.end __orgsi3
/* signed division */
.ent __divsi3
__divsi3:
addi r0, -8 # pic used
.cpload r29 # pic used
mv t3, ra
xor t2, a0, a1
la r29, __orgsi3
brl r29
__divsi3_adjust:
cmpi.c t2, 0
bge __divsi3_exit
neg r4, r4
__divsi3_exit:
.cprestore r0, 12 # pic used
addi r0, 8 # pic used
br t3
.end __divsi3
/* signed modulus */
.ent __modsi3
__modsi3:
addi r0, -8 # pic used
.cpload r29 # pic used
mv t3, ra
mv t2, a0
la r29, __orgsi3
brl r29
mv r4, a1
b __divsi3_adjust
.end __modsi3
#endif /*L_divsi3 */
#endif
;; Machine description for Sunplus S+CORE
;; Sunplus S+CORE Pipeline Description
;; Copyright (C) 2005, 2007
;; Copyright (C) 2005, 2007, 2010
;; Free Software Foundation, Inc.
;; Contributed by Sunnorth.
......
/* score-modes.def for Sunplus S+CORE processor
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 2005, 2007, 2010 Free Software Foundation, Inc.
This file is part of GCC.
......
......@@ -47,7 +47,6 @@
#include "integrate.h"
#include "langhooks.h"
#include "score7.h"
#include "score3.h"
#include "df.h"
static void score_option_override (void);
......@@ -73,10 +72,13 @@ static const struct default_options score_option_optimization_table[] =
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION score_handle_option
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE score_option_override
#undef TARGET_OPTION_OPTIMIZATION_TABLE
#define TARGET_OPTION_OPTIMIZATION_TABLE score_option_optimization_table
......@@ -156,12 +158,10 @@ enum reg_class score_char_to_class[256];
static bool
score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_return_in_memory (type, fndecl);
else if (TARGET_SCORE3)
return score3_return_in_memory (type, fndecl);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Return nonzero when an argument must be passed by reference. */
......@@ -181,10 +181,8 @@ score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function);
else if (TARGET_SCORE3)
score3_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function);
else
gcc_unreachable ();
}
......@@ -201,10 +199,8 @@ score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
static void
score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_function_prologue (file, size);
else if (TARGET_SCORE3)
score3_function_prologue (file, size);
else
gcc_unreachable ();
}
......@@ -215,10 +211,8 @@ static void
score_function_epilogue (FILE *file,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_function_epilogue (file, size);
else if (TARGET_SCORE3)
score3_function_epilogue (file, size);
else
gcc_unreachable ();
}
......@@ -236,48 +230,32 @@ static section *
score_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_select_rtx_section (mode, x, align);
else if (TARGET_SCORE3)
return score3_select_rtx_section (mode, x, align);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_IN_SMALL_DATA_P. */
static bool
score_in_small_data_p (const_tree decl)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_in_small_data_p (decl);
else if (TARGET_SCORE3)
return score3_in_small_data_p (decl);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_ASM_FILE_START. */
static void
score_asm_file_start (void)
{
if (TARGET_SCORE5)
fprintf (asm_out_file, "# Sunplus S+core5 %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else if (TARGET_SCORE5U)
fprintf (asm_out_file, "# Sunplus S+core5u %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else if (TARGET_SCORE7D)
if (TARGET_SCORE7D)
fprintf (asm_out_file, "# Sunplus S+core7d %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else if (TARGET_SCORE7)
fprintf (asm_out_file, "# Sunplus S+core7 %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else if (TARGET_SCORE3D)
fprintf (asm_out_file, "# Sunplus S+core3d %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else if (TARGET_SCORE3)
fprintf (asm_out_file, "# Sunplus S+core3 %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
else
fprintf (asm_out_file, "# Sunplus S+core unknown %s rev=%s\n",
TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION);
......@@ -293,17 +271,13 @@ score_asm_file_start (void)
static void
score_asm_file_end (void)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_asm_file_end ();
else if (TARGET_SCORE3)
score3_asm_file_end ();
else
gcc_unreachable ();
}
#define MASK_ALL_CPU_BITS \
(MASK_SCORE5 | MASK_SCORE5U | MASK_SCORE7 | MASK_SCORE7D \
| MASK_SCORE3 | MASK_SCORE3D)
#define MASK_ALL_CPU_BITS (MASK_SCORE7 | MASK_SCORE7D)
/* Implement TARGET_HANDLE_OPTION. */
static bool
......@@ -316,25 +290,8 @@ score_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
target_flags |= MASK_SCORE7 | MASK_SCORE7D;
return true;
case OPT_mscore3d:
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE3 | MASK_SCORE3D;
return true;
case OPT_march_:
if (strcmp (arg, "score5") == 0)
{
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE5;
return true;
}
else if (strcmp (arg, "score5u") == 0)
{
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE5U;
return true;
}
else if (strcmp (arg, "score7") == 0)
if (strcmp (arg, "score7") == 0)
{
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE7;
......@@ -346,18 +303,6 @@ score_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
target_flags |= MASK_SCORE7 | MASK_SCORE7D;
return true;
}
else if (strcmp (arg, "score3") == 0)
{
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE3;
return true;
}
else if (strcmp (arg, "score3d") == 0)
{
target_flags &= ~(MASK_ALL_CPU_BITS);
target_flags |= MASK_SCORE3 | MASK_SCORE3D;
return true;
}
else
return false;
......@@ -370,11 +315,7 @@ score_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
static void
score_option_override (void)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
score7_option_override ();
else if (TARGET_SCORE3)
score3_option_override ();
else
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_option_override ();
}
......@@ -382,24 +323,20 @@ score_option_override (void)
int
score_reg_class (int regno)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_reg_class (regno);
else if (TARGET_SCORE3)
return score3_reg_class (regno);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement PREFERRED_RELOAD_CLASS macro. */
enum reg_class
score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_preferred_reload_class (x, rclass);
else if (TARGET_SCORE3)
return score3_preferred_reload_class (x, rclass);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement SECONDARY_INPUT_RELOAD_CLASS
......@@ -409,49 +346,22 @@ score_secondary_reload_class (enum reg_class rclass,
enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_secondary_reload_class (rclass, mode, x);
else if (TARGET_SCORE3)
return score3_secondary_reload_class (rclass, mode, x);
gcc_unreachable ();
}
/* Implement CONST_OK_FOR_LETTER_P macro. */
int
score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
return score7_const_ok_for_letter_p (value, c);
else if (TARGET_SCORE3)
return score3_const_ok_for_letter_p (value, c);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement EXTRA_CONSTRAINT macro. */
int
score_extra_constraint (rtx op, char c)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
return score7_extra_constraint (op, c);
else if (TARGET_SCORE3)
return score3_extra_constraint (op, c);
gcc_unreachable ();
}
/* Return truth value on whether or not a given hard register
can support a given mode. */
int
score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_hard_regno_mode_ok (regno, mode);
else if (TARGET_SCORE3)
return score3_hard_regno_mode_ok (regno, mode);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* We can always eliminate to the hard frame pointer. We can eliminate
......@@ -471,12 +381,10 @@ HOST_WIDE_INT
score_initial_elimination_offset (int from,
int to ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_initial_elimination_offset (from, to);
else if (TARGET_SCORE3)
return score3_initial_elimination_offset (from, to);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Argument support functions. */
......@@ -495,10 +403,8 @@ static void
score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_function_arg_advance (cum, mode, type, named);
else if (TARGET_SCORE3)
score3_function_arg_advance (cum, mode, type, named);
else
gcc_unreachable ();
}
......@@ -508,12 +414,10 @@ int
score_arg_partial_bytes (CUMULATIVE_ARGS *cum,
enum machine_mode mode, tree type, bool named)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_arg_partial_bytes (cum, mode, type, named);
else if (TARGET_SCORE3)
return score3_arg_partial_bytes (cum, mode, type, named);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_FUNCTION_ARG hook. */
......@@ -521,12 +425,10 @@ static rtx
score_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_function_arg (cum, mode, type, named);
else if (TARGET_SCORE3)
return score3_function_arg (cum, mode, type, named);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
......@@ -536,22 +438,18 @@ rtx
score_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED,
enum machine_mode mode)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_function_value (valtype, func, mode);
else if (TARGET_SCORE3)
return score3_function_value (valtype, func, mode);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
static void
score_asm_trampoline_template (FILE *f)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_asm_trampoline_template (f);
else if (TARGET_SCORE3)
score3_asm_trampoline_template (f);
else
gcc_unreachable ();
}
......@@ -560,12 +458,9 @@ score_asm_trampoline_template (FILE *f)
static void
score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{
/* ??? These two routines are identical. */
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if ( TARGET_SCORE7 || TARGET_SCORE7D)
score7_trampoline_init (m_tramp, fndecl, chain_value);
else if (TARGET_SCORE3)
score3_trampoline_init (m_tramp, fndecl, chain_value);
else
else
gcc_unreachable ();
}
......@@ -573,24 +468,20 @@ score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
int
score_regno_mode_ok_for_base_p (int regno, int strict)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_regno_mode_ok_for_base_p (regno, strict);
else if (TARGET_SCORE3)
return score3_regno_mode_ok_for_base_p (regno, strict);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_LEGITIMIZE_ADDRESS_P. */
static bool
score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_legitimate_address_p (mode, x, strict);
else if (TARGET_SCORE3)
return score3_legitimate_address_p (mode, x, strict);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* This function is used to implement LEGITIMIZE_ADDRESS. If X can
......@@ -600,12 +491,10 @@ static rtx
score_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_legitimize_address (x);
else if (TARGET_SCORE3)
return score3_legitimize_address (x);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Return a number assessing the cost of moving a register in class
......@@ -614,12 +503,10 @@ int
score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
enum reg_class from, enum reg_class to)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_register_move_cost (mode, from, to);
else if (TARGET_SCORE3)
return score3_register_move_cost (mode, from, to);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_RTX_COSTS macro. */
......@@ -627,12 +514,10 @@ bool
score_rtx_costs (rtx x, int code, int outer_code, int *total,
bool speed ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_rtx_costs (x, code, outer_code, total, speed);
else if (TARGET_SCORE3)
return score3_rtx_costs (x, code, outer_code, total, speed);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement TARGET_ADDRESS_COST macro. */
......@@ -640,12 +525,10 @@ int
score_address_cost (rtx addr,
bool speed ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_address_cost (addr);
else if (TARGET_SCORE3)
return score3_address_cost (addr);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement ASM_OUTPUT_EXTERNAL macro. */
......@@ -653,12 +536,10 @@ int
score_output_external (FILE *file ATTRIBUTE_UNUSED,
tree decl, const char *name)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_output_external (file, decl, name);
else if (TARGET_SCORE3)
return score3_output_external (file, decl, name);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement RETURN_ADDR_RTX. Note, we do not support moving
......@@ -666,22 +547,18 @@ score_output_external (FILE *file ATTRIBUTE_UNUSED,
rtx
score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_return_addr (count, frame);
else if (TARGET_SCORE3)
return score3_return_addr (count, frame);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Implement PRINT_OPERAND macro. */
void
score_print_operand (FILE *file, rtx op, int c)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_print_operand (file, op, c);
else if (TARGET_SCORE3)
score3_print_operand (file, op, c);
else
gcc_unreachable ();
}
......@@ -690,10 +567,8 @@ score_print_operand (FILE *file, rtx op, int c)
void
score_print_operand_address (FILE *file, rtx x)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_print_operand_address (file, x);
else if (TARGET_SCORE3)
score3_print_operand_address (file, x);
else
gcc_unreachable ();
}
......@@ -702,12 +577,10 @@ score_print_operand_address (FILE *file, rtx x)
enum machine_mode
score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_select_cc_mode (op, x, y);
else if (TARGET_SCORE3)
return score3_select_cc_mode (op, x, y);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Return true if X is a symbolic constant that can be calculated in
......@@ -716,22 +589,18 @@ score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
int
score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_symbolic_constant_p (x, symbol_type);
else if (TARGET_SCORE3)
return score3_symbolic_constant_p (x, symbol_type);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Generate the prologue instructions for entry into a S+core function. */
void
score_prologue (void)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_prologue ();
else if (TARGET_SCORE3)
score3_prologue ();
else
gcc_unreachable ();
}
......@@ -740,10 +609,8 @@ score_prologue (void)
void
score_epilogue (int sibcall_p)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_epilogue (sibcall_p);
else if (TARGET_SCORE3)
score3_epilogue (sibcall_p);
else
gcc_unreachable ();
}
......@@ -752,10 +619,8 @@ score_epilogue (int sibcall_p)
void
score_call (rtx *ops, bool sib)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_call (ops, sib);
else if (TARGET_SCORE3)
score3_call (ops, sib);
else
gcc_unreachable ();
}
......@@ -764,10 +629,8 @@ score_call (rtx *ops, bool sib)
void
score_call_value (rtx *ops, bool sib)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_call_value (ops, sib);
else if (TARGET_SCORE3)
score3_call_value (ops, sib);
else
gcc_unreachable ();
}
......@@ -775,10 +638,8 @@ score_call_value (rtx *ops, bool sib)
void
score_movsicc (rtx *ops)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_movsicc (ops);
else if (TARGET_SCORE3)
score3_movsicc (ops);
else
gcc_unreachable ();
}
......@@ -787,10 +648,8 @@ score_movsicc (rtx *ops)
void
score_movdi (rtx *ops)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_movdi (ops);
else if (TARGET_SCORE3)
score3_movdi (ops);
else
gcc_unreachable ();
}
......@@ -798,10 +657,8 @@ score_movdi (rtx *ops)
void
score_zero_extract_andi (rtx *ops)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
score7_zero_extract_andi (ops);
else if (TARGET_SCORE3)
score3_zero_extract_andi (ops);
else
gcc_unreachable ();
}
......@@ -810,48 +667,40 @@ score_zero_extract_andi (rtx *ops)
const char *
score_move (rtx *ops)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_move (ops);
else if (TARGET_SCORE3)
return score3_move (ops);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Output asm insn for load. */
const char *
score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_linsn (ops, unit, sign);
else if (TARGET_SCORE3)
return score3_linsn (ops, unit, sign);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Output asm insn for store. */
const char *
score_sinsn (rtx *ops, enum score_mem_unit unit)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_sinsn (ops, unit);
else if (TARGET_SCORE3)
return score3_sinsn (ops, unit);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Output asm insn for load immediate. */
const char *
score_limm (rtx *ops)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_limm (ops);
else if (TARGET_SCORE3)
return score3_limm (ops);
gcc_unreachable ();
else
gcc_unreachable ();
}
......@@ -859,12 +708,10 @@ score_limm (rtx *ops)
const char *
score_select_add_imm (rtx *ops, bool set_cc)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_select_add_imm (ops, set_cc);
else if (TARGET_SCORE3)
return score3_select_add_imm (ops, set_cc);
gcc_unreachable ();
else
gcc_unreachable ();
}
/* Output arith insn. */
......@@ -872,366 +719,10 @@ const char *
score_select (rtx *ops, const char *inst_pre,
bool commu, const char *letter, bool set_cc)
{
if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)
if (TARGET_SCORE7 || TARGET_SCORE7D)
return score7_select (ops, inst_pre, commu, letter, set_cc);
else if (TARGET_SCORE3)
return score3_select (ops, inst_pre, commu, letter, set_cc);
gcc_unreachable ();
}
/* Output switch case insn, only supported in score3. */
const char *
score_output_casesi (rtx *operands)
{
if (TARGET_SCORE3)
return score3_output_casesi (operands);
gcc_unreachable ();
}
/* Output rpush insn, only supported in score3. */
const char *
score_rpush (rtx *operands)
{
if (TARGET_SCORE3)
return score3_rpush (operands);
gcc_unreachable ();
}
/* Output rpop insn, only supported in score3. */
const char *
score_rpop (rtx *operands)
{
if (TARGET_SCORE3)
return score3_rpop (operands);
gcc_unreachable ();
}
/* Emit lcb/lce insns. */
bool
score_unaligned_load (rtx *ops)
{
rtx dst = ops[0];
rtx src = ops[1];
rtx len = ops[2];
rtx off = ops[3];
rtx addr_reg;
if (INTVAL (len) != BITS_PER_WORD
|| (INTVAL (off) % BITS_PER_UNIT) != 0)
return false;
gcc_assert (GET_MODE_SIZE (GET_MODE (dst)) == GET_MODE_SIZE (SImode));
addr_reg = copy_addr_to_reg (XEXP (src, 0));
emit_insn (gen_move_lcb (addr_reg, addr_reg));
emit_insn (gen_move_lce (addr_reg, addr_reg, dst));
return true;
}
/* Emit scb/sce insns. */
bool
score_unaligned_store (rtx *ops)
{
rtx dst = ops[0];
rtx len = ops[1];
rtx off = ops[2];
rtx src = ops[3];
rtx addr_reg;
if (INTVAL(len) != BITS_PER_WORD
|| (INTVAL(off) % BITS_PER_UNIT) != 0)
return false;
gcc_assert (GET_MODE_SIZE (GET_MODE (src)) == GET_MODE_SIZE (SImode));
addr_reg = copy_addr_to_reg (XEXP (dst, 0));
emit_insn (gen_move_scb (addr_reg, addr_reg, src));
emit_insn (gen_move_sce (addr_reg, addr_reg));
return true;
}
/* If length is short, generate move insns straight. */
static void
score_block_move_straight (rtx dst, rtx src, HOST_WIDE_INT length)
{
HOST_WIDE_INT leftover;
int i, reg_count;
rtx *regs;
leftover = length % UNITS_PER_WORD;
length -= leftover;
reg_count = length / UNITS_PER_WORD;
regs = XALLOCAVEC (rtx, reg_count);
for (i = 0; i < reg_count; i++)
regs[i] = gen_reg_rtx (SImode);
/* Load from src to regs. */
if (MEM_ALIGN (src) >= BITS_PER_WORD)
{
HOST_WIDE_INT offset = 0;
for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
emit_move_insn (regs[i], adjust_address (src, SImode, offset));
}
else if (reg_count >= 1)
{
rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
emit_insn (gen_move_lcb (src_reg, src_reg));
for (i = 0; i < (reg_count - 1); i++)
emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
emit_insn (gen_move_lce (src_reg, src_reg, regs[i]));
}
/* Store regs to dest. */
if (MEM_ALIGN (dst) >= BITS_PER_WORD)
{
HOST_WIDE_INT offset = 0;
for (i = 0; i < reg_count; offset += UNITS_PER_WORD, i++)
emit_move_insn (adjust_address (dst, SImode, offset), regs[i]);
}
else if (reg_count >= 1)
{
rtx dst_reg = copy_addr_to_reg (XEXP (dst, 0));
emit_insn (gen_move_scb (dst_reg, dst_reg, regs[0]));
for (i = 1; i < reg_count; i++)
emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
emit_insn (gen_move_sce (dst_reg, dst_reg));
}
/* Mop up any left-over bytes. */
if (leftover > 0)
{
src = adjust_address (src, BLKmode, length);
dst = adjust_address (dst, BLKmode, length);
move_by_pieces (dst, src, leftover,
MIN (MEM_ALIGN (src), MEM_ALIGN (dst)), 0);
}
}
/* Generate loop head when dst or src is unaligned. */
static void
score_block_move_loop_head (rtx dst_reg, HOST_WIDE_INT dst_align,
rtx src_reg, HOST_WIDE_INT src_align,
HOST_WIDE_INT length)
{
bool src_unaligned = (src_align < BITS_PER_WORD);
bool dst_unaligned = (dst_align < BITS_PER_WORD);
rtx temp = gen_reg_rtx (SImode);
gcc_assert (length == UNITS_PER_WORD);
if (src_unaligned)
{
emit_insn (gen_move_lcb (src_reg, src_reg));
emit_insn (gen_move_lcw (src_reg, src_reg, temp));
}
else
emit_insn (gen_move_lw_a (src_reg,
src_reg, gen_int_mode (4, SImode), temp));
if (dst_unaligned)
emit_insn (gen_move_scb (dst_reg, dst_reg, temp));
else
emit_insn (gen_move_sw_a (dst_reg,
dst_reg, gen_int_mode (4, SImode), temp));
}
/* Generate loop body, copy length bytes per iteration. */
static void
score_block_move_loop_body (rtx dst_reg, HOST_WIDE_INT dst_align,
rtx src_reg, HOST_WIDE_INT src_align,
HOST_WIDE_INT length)
{
int reg_count = length / UNITS_PER_WORD;
rtx *regs = XALLOCAVEC (rtx, reg_count);
int i;
bool src_unaligned = (src_align < BITS_PER_WORD);
bool dst_unaligned = (dst_align < BITS_PER_WORD);
for (i = 0; i < reg_count; i++)
regs[i] = gen_reg_rtx (SImode);
if (src_unaligned)
{
for (i = 0; i < reg_count; i++)
emit_insn (gen_move_lcw (src_reg, src_reg, regs[i]));
}
else
{
for (i = 0; i < reg_count; i++)
emit_insn (gen_move_lw_a (src_reg,
src_reg, gen_int_mode (4, SImode), regs[i]));
}
if (dst_unaligned)
{
for (i = 0; i < reg_count; i++)
emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i]));
}
else
{
for (i = 0; i < reg_count; i++)
emit_insn (gen_move_sw_a (dst_reg,
dst_reg, gen_int_mode (4, SImode), regs[i]));
}
}
/* Generate loop foot, copy the leftover bytes. */
static void
score_block_move_loop_foot (rtx dst_reg, HOST_WIDE_INT dst_align,
rtx src_reg, HOST_WIDE_INT src_align,
HOST_WIDE_INT length)
{
bool src_unaligned = (src_align < BITS_PER_WORD);
bool dst_unaligned = (dst_align < BITS_PER_WORD);
HOST_WIDE_INT leftover;
leftover = length % UNITS_PER_WORD;
length -= leftover;
if (length > 0)
score_block_move_loop_body (dst_reg, dst_align,
src_reg, src_align, length);
if (dst_unaligned)
emit_insn (gen_move_sce (dst_reg, dst_reg));
if (leftover > 0)
{
HOST_WIDE_INT src_adj = src_unaligned ? -4 : 0;
HOST_WIDE_INT dst_adj = dst_unaligned ? -4 : 0;
rtx temp;
gcc_assert (leftover < UNITS_PER_WORD);
if (leftover >= UNITS_PER_WORD / 2
&& src_align >= BITS_PER_WORD / 2
&& dst_align >= BITS_PER_WORD / 2)
{
temp = gen_reg_rtx (HImode);
emit_insn (gen_move_lhu_b (src_reg, src_reg,
gen_int_mode (src_adj, SImode), temp));
emit_insn (gen_move_sh_b (dst_reg, dst_reg,
gen_int_mode (dst_adj, SImode), temp));
leftover -= UNITS_PER_WORD / 2;
src_adj = UNITS_PER_WORD / 2;
dst_adj = UNITS_PER_WORD / 2;
}
while (leftover > 0)
{
temp = gen_reg_rtx (QImode);
emit_insn (gen_move_lbu_b (src_reg, src_reg,
gen_int_mode (src_adj, SImode), temp));
emit_insn (gen_move_sb_b (dst_reg, dst_reg,
gen_int_mode (dst_adj, SImode), temp));
leftover--;
src_adj = 1;
dst_adj = 1;
}
}
}
#define MIN_MOVE_REGS 3
#define MIN_MOVE_BYTES (MIN_MOVE_REGS * UNITS_PER_WORD)
#define MAX_MOVE_REGS 4
#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
/* The length is large, generate a loop if necessary.
The loop is consisted by loop head/body/foot. */
static void
score_block_move_loop (rtx dst, rtx src, HOST_WIDE_INT length)
{
HOST_WIDE_INT src_align = MEM_ALIGN (src);
HOST_WIDE_INT dst_align = MEM_ALIGN (dst);
HOST_WIDE_INT loop_mov_bytes;
HOST_WIDE_INT iteration = 0;
HOST_WIDE_INT head_length = 0, leftover;
rtx label, src_reg, dst_reg, final_dst, test;
bool gen_loop_head = (src_align < BITS_PER_WORD
|| dst_align < BITS_PER_WORD);
if (gen_loop_head)
head_length += UNITS_PER_WORD;
for (loop_mov_bytes = MAX_MOVE_BYTES;
loop_mov_bytes >= MIN_MOVE_BYTES;
loop_mov_bytes -= UNITS_PER_WORD)
{
iteration = (length - head_length) / loop_mov_bytes;
if (iteration > 1)
break;
}
if (iteration <= 1)
{
score_block_move_straight (dst, src, length);
return;
}
leftover = (length - head_length) % loop_mov_bytes;
length -= leftover;
src_reg = copy_addr_to_reg (XEXP (src, 0));
dst_reg = copy_addr_to_reg (XEXP (dst, 0));
final_dst = expand_simple_binop (Pmode, PLUS, dst_reg, GEN_INT (length),
0, 0, OPTAB_WIDEN);
if (gen_loop_head)
score_block_move_loop_head (dst_reg, dst_align,
src_reg, src_align, head_length);
label = gen_label_rtx ();
emit_label (label);
score_block_move_loop_body (dst_reg, dst_align,
src_reg, src_align, loop_mov_bytes);
test = gen_rtx_NE (VOIDmode, dst_reg, final_dst);
emit_jump_insn (gen_cbranchsi4 (test, dst_reg, final_dst, label));
score_block_move_loop_foot (dst_reg, dst_align,
src_reg, src_align, leftover);
}
/* Generate block move, for misc.md: "movmemsi". */
bool
score_block_move (rtx *ops)
{
rtx dst = ops[0];
rtx src = ops[1];
rtx length = ops[2];
if (TARGET_LITTLE_ENDIAN
&& (MEM_ALIGN (src) < BITS_PER_WORD || MEM_ALIGN (dst) < BITS_PER_WORD)
&& INTVAL (length) >= UNITS_PER_WORD)
return false;
if (GET_CODE (length) == CONST_INT)
{
if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
{
score_block_move_straight (dst, src, INTVAL (length));
return true;
}
else if (optimize &&
!(flag_unroll_loops || flag_unroll_all_loops))
{
score_block_move_loop (dst, src, INTVAL (length));
return true;
}
}
return false;
gcc_unreachable ();
}
static void
......
......@@ -20,14 +20,9 @@
#include "score-conv.h"
#undef CPP_SPEC
#define CPP_SPEC "%{mscore3:-D__score3__} %{G*}"
#undef CC1_SPEC
#define CC1_SPEC "%{!mel:-meb} %{mel:-mel } \
%{!mscore*:-mscore7} \
%{mscore3:-mscore3} \
%{mscore3d:-mscore3d} \
%{mscore7:-mscore7} \
%{mscore7d:-mscore7d} \
%{G*}"
......@@ -37,14 +32,8 @@
%{!mscore*:-march=score7} \
%{mscore7:-march=score7} \
%{mscore7d:-march=score7} \
%{mscore3:-march=score3} \
%{mscore3d:-march=score3} \
%{march=score5:-march=score7} \
%{march=score5u:-march=score7} \
%{march=score7:-march=score7} \
%{march=score7d:-march=score7} \
%{march=score3:-march=score3} \
%{march=score3d:-march=score3} \
%{G*}"
#undef LINK_SPEC
......@@ -52,14 +41,8 @@
%{!mscore*:-mscore7_elf} \
%{mscore7:-mscore7_elf} \
%{mscore7d:-mscore7_elf} \
%{mscore3:-mscore3_elf} \
%{mscore3d:-mscore3_elf} \
%{march=score5:-mscore7_elf} \
%{march=score5u:-mscore7_elf} \
%{march=score7:-mscore7_elf} \
%{march=score7d:-mscore7_elf} \
%{march=score3:-mscore3_elf} \
%{march=score3d:-mscore3_elf} \
%{G*}"
/* Run-time Target Specification. */
......@@ -72,18 +55,10 @@
builtin_define ("__scorele__"); \
else \
builtin_define ("__scorebe__"); \
if (TARGET_SCORE5) \
builtin_define ("__score5__"); \
if (TARGET_SCORE5U) \
builtin_define ("__score5u__"); \
if (TARGET_SCORE7) \
builtin_define ("__score7__"); \
if (TARGET_SCORE7D) \
builtin_define ("__score7d__"); \
if (TARGET_SCORE3) \
builtin_define ("__score3__"); \
if (TARGET_SCORE3D) \
builtin_define ("__score3d__"); \
} while (0)
#define TARGET_DEFAULT 0
......@@ -466,25 +441,6 @@ extern enum reg_class score_char_to_class[256];
(GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
? reg_classes_intersect_p (HI_REG, (CLASS)) : 0)
/* The letters I, J, K, L, M, N, O, and P in a register constraint
string can be used to stand for particular ranges of immediate
operands. This macro defines what the ranges are. C is the
letter, and VALUE is a constant value. Return 1 if VALUE is
in the range specified by C. */
#define CONST_OK_FOR_LETTER_P(VALUE, C) score_const_ok_for_letter_p (VALUE, C)
/* Similar, but for floating constants, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' && (VALUE) == CONST0_RTX (GET_MODE (VALUE)))
/* Letters in the range `Q' through `U' may be defined in a
machine-dependent fashion to stand for arbitrary operand types.
The machine description macro `EXTRA_CONSTRAINT' is passed the
operand as its first argument and the constraint letter as its
second operand. */
#define EXTRA_CONSTRAINT(VALUE, C) score_extra_constraint (VALUE, C)
/* Basic Stack Layout. */
/* Stack layout; function entry, exit and calling. */
......@@ -514,6 +470,7 @@ extern enum reg_class score_char_to_class[256];
/* The register that holds the return address in exception handlers. */
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_REGNUM)
#define EH_RETURN_HANDLER_RTX gen_rtx_REG (SImode, 30)
/* Registers That Address the Stack Frame. */
/* Register to use for pushing function arguments. */
......@@ -615,14 +572,6 @@ typedef struct score_args
fprintf (FILE, " jl _mcount \n"); \
fprintf (FILE, " .set nor1 \n"); \
} \
else if (TARGET_SCORE3) \
{ \
fprintf (FILE, " .set r1 \n"); \
fprintf (FILE, " mv! r%d,r%d \n", AT_REGNUM, RA_REGNUM); \
fprintf (FILE, " addi! r%d, %d \n", STACK_POINTER_REGNUM, -8);\
fprintf (FILE, " jl _mcount \n"); \
fprintf (FILE, " .set nor1 \n"); \
} \
} while (0)
/* Trampolines for Nested Functions. */
......@@ -825,9 +774,6 @@ typedef struct score_args
fprintf (STREAM, "\tpush! %s,[%s]\n", \
reg_names[REGNO], \
reg_names[STACK_POINTER_REGNUM]); \
else if (TARGET_SCORE3) \
fprintf (STREAM, "\tpush!\t%s\n", \
reg_names[REGNO]); \
} while (0)
/* This is how to output an insn to pop a register from the stack. */
......@@ -837,9 +783,6 @@ typedef struct score_args
fprintf (STREAM, "\tpop! %s,[%s]\n", \
reg_names[REGNO], \
reg_names[STACK_POINTER_REGNUM]); \
else if (TARGET_SCORE3) \
fprintf (STREAM, "\tpop!\t%s\n", \
reg_names[REGNO]); \
} while (0)
/* Output of Dispatch Tables. */
......@@ -852,28 +795,6 @@ typedef struct score_args
fprintf (STREAM, "\t.gpword %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
else \
fprintf (STREAM, "\t.word %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
else if (TARGET_SCORE3) \
{ \
switch (GET_MODE(BODY)) \
{ \
case QImode: /* TBB */ \
asm_fprintf (STREAM, "\t.byte\t(%LL%d-%LL%d_tbb)/2\n", \
VALUE, REL); \
break; \
case HImode: /* TBH */ \
asm_fprintf (STREAM, "\t.2byte\t(%LL%d-%LL%d_tbb)/2\n", \
VALUE, REL); \
break; \
case SImode: \
if (flag_pic) \
fprintf (STREAM, "\t.gpword %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
else \
fprintf (STREAM, "\t.word %sL%d\n", LOCAL_LABEL_PREFIX, VALUE); \
break; \
default: \
gcc_unreachable(); \
} \
} \
} while (0)
/* Jump table alignment is explicit in ASM_OUTPUT_CASE_LABEL. */
......@@ -894,13 +815,6 @@ typedef struct score_args
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE SImode
#define CASE_VECTOR_PC_RELATIVE (TARGET_SCORE3)
#define CASE_VECTOR_SHORTEN_MODE(min, max, body) \
((min < 0 || max >= 0x2000 || TARGET_SCORE7) ? SImode \
: (max >= 0x200) ? HImode \
: QImode)
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
fprintf (STREAM, "\t.word %sL%d\n", LOCAL_LABEL_PREFIX, VALUE)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
; Options for the Sunnorth port of the compiler.
; Copyright (C) 2005, 2007 Free Software Foundation, Inc.
; Copyright (C) 2005, 2007, 2010 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
......@@ -34,14 +34,6 @@ muls
Target RejectNegative Report Mask(ULS)
Enable unaligned load/store instruction
mscore5
Target RejectNegative Report Mask(SCORE5)
Support SCORE 5 ISA
mscore5u
Target RejectNegative Report Mask(SCORE5U)
Support SCORE 5U ISA
mscore7
Target RejectNegative Report Mask(SCORE7)
Support SCORE 7 ISA
......@@ -50,14 +42,6 @@ mscore7d
Target RejectNegative Report Mask(SCORE7D)
Support SCORE 7D ISA
mscore3
Target RejectNegative Report Mask(SCORE3)
Support SCORE 3 ISA
mscore3d
Target RejectNegative Report Mask(SCORE3D)
Support SCORE 3d ISA
march=
Target RejectNegative Joined
Specify the name of the target architecture
/* score3.c for Sunplus S+CORE processor
Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Sunnorth
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
#include "recog.h"
#include "diagnostic-core.h"
#include "output.h"
#include "tree.h"
#include "function.h"
#include "expr.h"
#include "optabs.h"
#include "flags.h"
#include "reload.h"
#include "tm_p.h"
#include "ggc.h"
#include "gstab.h"
#include "hashtab.h"
#include "debug.h"
#include "target.h"
#include "target-def.h"
#include "integrate.h"
#include "langhooks.h"
#include "cfglayout.h"
#include "score3.h"
#include "df.h"
#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
#define INS_BUF_SZ 128
extern enum reg_class score_char_to_class[256];
static int score3_sdata_max;
static char score3_ins[INS_BUF_SZ + 8];
/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
to the same object as SYMBOL. */
static int
score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
{
if (GET_CODE (symbol) != SYMBOL_REF)
return 0;
if (CONSTANT_POOL_ADDRESS_P (symbol)
&& offset >= 0
&& offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
return 1;
if (SYMBOL_REF_DECL (symbol) != 0
&& offset >= 0
&& offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
return 1;
return 0;
}
/* Split X into a base and a constant offset, storing them in *BASE
and *OFFSET respectively. */
static void
score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
{
*offset = 0;
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
*offset += INTVAL (XEXP (x, 1));
x = XEXP (x, 0);
}
*base = x;
}
/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
static enum score_symbol_type
score3_classify_symbol (rtx x)
{
if (GET_CODE (x) == LABEL_REF)
return SYMBOL_GENERAL;
gcc_assert (GET_CODE (x) == SYMBOL_REF);
if (CONSTANT_POOL_ADDRESS_P (x))
{
if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
return SYMBOL_SMALL_DATA;
return SYMBOL_GENERAL;
}
if (SYMBOL_REF_SMALL_P (x))
return SYMBOL_SMALL_DATA;
return SYMBOL_GENERAL;
}
/* Return true if the current function must save REGNO. */
static int
score3_save_reg_p (unsigned int regno)
{
/* Check call-saved registers. */
if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
return 1;
/* We need to save the old frame pointer before setting up a new one. */
if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
return 1;
/* We need to save the incoming return address if it is ever clobbered
within the function. */
if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
return 1;
return 0;
}
/* Return one word of double-word value OP, taking into account the fixed
endianness of certain registers. HIGH_P is true to select the high part,
false to select the low part. */
static rtx
score3_subw (rtx op, int high_p)
{
unsigned int byte;
enum machine_mode mode = GET_MODE (op);
if (mode == VOIDmode)
mode = DImode;
byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
if (GET_CODE (op) == MEM)
return adjust_address (op, SImode, byte);
return simplify_gen_subreg (SImode, op, mode, byte);
}
static struct score3_frame_info *
score3_cached_frame (void)
{
static struct score3_frame_info _frame_info;
return &_frame_info;
}
/* Return the bytes needed to compute the frame pointer from the current
stack pointer. SIZE is the size (in bytes) of the local variables. */
static struct score3_frame_info *
score3_compute_frame_size (HOST_WIDE_INT size)
{
unsigned int regno;
struct score3_frame_info *f = score3_cached_frame ();
memset (f, 0, sizeof (struct score3_frame_info));
f->gp_reg_size = 0;
f->mask = 0;
f->var_size = SCORE3_STACK_ALIGN (size);
f->args_size = crtl->outgoing_args_size;
f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
if (f->var_size == 0 && current_function_is_leaf)
f->args_size = f->cprestore_size = 0;
if (f->args_size == 0 && cfun->calls_alloca)
f->args_size = UNITS_PER_WORD;
f->total_size = f->var_size + f->args_size + f->cprestore_size;
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
{
if (score3_save_reg_p (regno))
{
f->gp_reg_size += GET_MODE_SIZE (SImode);
f->mask |= 1 << (regno - GP_REG_FIRST);
}
}
if (crtl->calls_eh_return)
{
unsigned int i;
for (i = 0;; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
f->gp_reg_size += GET_MODE_SIZE (SImode);
f->mask |= 1 << (regno - GP_REG_FIRST);
}
}
f->total_size += f->gp_reg_size;
f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
if (f->mask)
{
HOST_WIDE_INT offset;
offset = (f->args_size + f->cprestore_size + f->var_size
+ f->gp_reg_size - GET_MODE_SIZE (SImode));
f->gp_sp_offset = offset;
}
else
f->gp_sp_offset = 0;
return f;
}
/* Return true if X is a valid base register for the given mode.
Allow only hard registers if STRICT. */
static int
score3_valid_base_register_p (rtx x, int strict)
{
if (!strict && GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
return (GET_CODE (x) == REG
&& score3_regno_mode_ok_for_base_p (REGNO (x), strict));
}
/* Return true if X is a valid address for machine mode MODE. If it is,
fill in INFO appropriately. STRICT is true if we should only accept
hard base registers. */
static int
score3_classify_address (struct score3_address_info *info,
enum machine_mode mode, rtx x, int strict)
{
info->code = GET_CODE (x);
switch (info->code)
{
case REG:
case SUBREG:
info->type = SCORE3_ADD_REG;
info->reg = x;
info->offset = const0_rtx;
return score3_valid_base_register_p (info->reg, strict);
case PLUS:
info->type = SCORE3_ADD_REG;
info->reg = XEXP (x, 0);
info->offset = XEXP (x, 1);
return (score3_valid_base_register_p (info->reg, strict)
&& GET_CODE (info->offset) == CONST_INT
&& IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
case PRE_DEC:
case POST_DEC:
case PRE_INC:
case POST_INC:
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
return false;
info->type = SCORE3_ADD_REG;
info->reg = XEXP (x, 0);
info->offset = GEN_INT (GET_MODE_SIZE (mode));
return score3_valid_base_register_p (info->reg, strict);
case CONST_INT:
info->type = SCORE3_ADD_CONST_INT;
return 1;
case CONST:
case LABEL_REF:
case SYMBOL_REF:
info->type = SCORE3_ADD_SYMBOLIC;
return (score3_symbolic_constant_p (x, &info->symbol_type)
&& (info->symbol_type == SYMBOL_GENERAL
|| info->symbol_type == SYMBOL_SMALL_DATA));
default:
return 0;
}
}
bool
score3_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
{
return ((TYPE_MODE (type) == BLKmode)
|| (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
|| (int_size_in_bytes (type) == -1));
}
/* Return a legitimate address for REG + OFFSET. */
static rtx
score3_add_offset (rtx reg, HOST_WIDE_INT offset)
{
if (!IMM_IN_RANGE (offset, 15, 1))
{
reg = expand_simple_binop (GET_MODE (reg), PLUS,
gen_int_mode (offset & 0xffffc000,
GET_MODE (reg)),
reg, NULL, 0, OPTAB_WIDEN);
offset &= 0x3fff;
}
return plus_constant (reg, offset);
}
/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
in order to avoid duplicating too much logic from elsewhere. */
void
score3_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
rtx this_rtx, temp1, insn, fnaddr;
/* Pretend to be a post-reload pass while generating rtl. */
reload_completed = 1;
/* Mark the end of the (empty) prologue. */
emit_note (NOTE_INSN_PROLOGUE_END);
/* We need two temporary registers in some cases. */
temp1 = gen_rtx_REG (Pmode, 8);
/* Find out which register contains the "this" pointer. */
if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
else
this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
/* Add DELTA to THIS_RTX. */
if (delta != 0)
{
rtx offset = GEN_INT (delta);
if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
{
emit_move_insn (temp1, offset);
offset = temp1;
}
emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
}
/* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
if (vcall_offset != 0)
{
rtx addr;
/* Set TEMP1 to *THIS_RTX. */
emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
/* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
addr = score3_add_offset (temp1, vcall_offset);
/* Load the offset and add it to THIS_RTX. */
emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
}
/* Jump to the target function. */
fnaddr = XEXP (DECL_RTL (function), 0);
insn = emit_call_insn (gen_sibcall_internal_score3 (fnaddr, const0_rtx));
SIBLING_CALL_P (insn) = 1;
/* Run just enough of rest_of_compilation. This sequence was
"borrowed" from alpha.c. */
insn = get_insns ();
insn_locators_alloc ();
split_all_insns_noflow ();
shorten_branches (insn);
final_start_function (insn, file, 1);
final (insn, file, 1);
final_end_function ();
/* Clean up the vars set above. Note that final_end_function resets
the global pointer for us. */
reload_completed = 0;
}
/* Copy VALUE to a register and return that register. If new psuedos
are allowed, copy it into a new register, otherwise use DEST. */
static rtx
score3_force_temporary (rtx dest, rtx value)
{
if (can_create_pseudo_p ())
return force_reg (Pmode, value);
else
{
emit_move_insn (copy_rtx (dest), value);
return dest;
}
}
/* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
and is used to load the high part into a register. */
static rtx
score3_split_symbol (rtx temp, rtx addr)
{
rtx high = score3_force_temporary (temp,
gen_rtx_HIGH (Pmode, copy_rtx (addr)));
return gen_rtx_LO_SUM (Pmode, high, addr);
}
/* This function is used to implement LEGITIMIZE_ADDRESS. If X can
be legitimized in a way that the generic machinery might not expect,
return the new address. */
rtx
score3_legitimize_address (rtx x)
{
enum score_symbol_type symbol_type;
if (score3_symbolic_constant_p (x, &symbol_type)
&& symbol_type == SYMBOL_GENERAL)
return score3_split_symbol (0, x);
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
{
rtx reg = XEXP (x, 0);
if (!score3_valid_base_register_p (reg, 0))
reg = copy_to_mode_reg (Pmode, reg);
return score3_add_offset (reg, INTVAL (XEXP (x, 1)));
}
return x;
}
/* Fill INFO with information about a single argument. CUM is the
cumulative state for earlier arguments. MODE is the mode of this
argument and TYPE is its type (if known). NAMED is true if this
is a named (fixed) argument rather than a variable one. */
static void
score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named, struct score3_arg_info *info)
{
int even_reg_p;
unsigned int num_words, max_regs;
even_reg_p = 0;
if (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_FLOAT)
even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
else
if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
even_reg_p = 1;
if (TARGET_MUST_PASS_IN_STACK (mode, type))
info->reg_offset = ARG_REG_NUM;
else
{
info->reg_offset = cum->num_gprs;
if (even_reg_p)
info->reg_offset += info->reg_offset & 1;
}
if (mode == BLKmode)
info->num_bytes = int_size_in_bytes (type);
else
info->num_bytes = GET_MODE_SIZE (mode);
num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
max_regs = ARG_REG_NUM - info->reg_offset;
/* Partition the argument between registers and stack. */
info->reg_words = MIN (num_words, max_regs);
info->stack_words = num_words - info->reg_words;
/* The alignment applied to registers is also applied to stack arguments. */
if (info->stack_words)
{
info->stack_offset = cum->stack_words;
if (even_reg_p)
info->stack_offset += info->stack_offset & 1;
}
}
/* Set up the stack and frame (if desired) for the function. */
void
score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
const char *fnname;
struct score3_frame_info *f = score3_cached_frame ();
HOST_WIDE_INT tsize = f->total_size;
fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
if (!flag_inhibit_size_directive)
{
fputs ("\t.ent\t", file);
assemble_name (file, fnname);
fputs ("\n", file);
}
assemble_name (file, fnname);
fputs (":\n", file);
if (!flag_inhibit_size_directive)
{
fprintf (file,
"\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
"# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
", args= " HOST_WIDE_INT_PRINT_DEC
", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
(reg_names[(frame_pointer_needed)
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
tsize,
reg_names[RA_REGNUM],
current_function_is_leaf ? 1 : 0,
f->var_size,
f->num_gp,
f->args_size,
f->cprestore_size);
fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
f->mask,
(f->gp_sp_offset - f->total_size));
}
}
/* Do any necessary cleanup after a function to restore stack, frame,
and regs. */
void
score3_function_epilogue (FILE *file,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
if (!flag_inhibit_size_directive)
{
const char *fnname;
fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
fputs ("\t.end\t", file);
assemble_name (file, fnname);
fputs ("\n", file);
}
}
/* Returns true if X contains a SYMBOL_REF. */
static bool
score3_symbolic_expression_p (rtx x)
{
if (GET_CODE (x) == SYMBOL_REF)
return true;
if (GET_CODE (x) == CONST)
return score3_symbolic_expression_p (XEXP (x, 0));
if (UNARY_P (x))
return score3_symbolic_expression_p (XEXP (x, 0));
if (ARITHMETIC_P (x))
return (score3_symbolic_expression_p (XEXP (x, 0))
|| score3_symbolic_expression_p (XEXP (x, 1)));
return false;
}
/* Choose the section to use for the constant rtx expression X that has
mode MODE. */
section *
score3_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
return get_named_section (0, ".sdata", 0);
else if (flag_pic && score3_symbolic_expression_p (x))
return get_named_section (0, ".data.rel.ro", 3);
else
return mergeable_constant_section (mode, align, 0);
}
/* Implement TARGET_IN_SMALL_DATA_P. */
bool
score3_in_small_data_p (const_tree decl)
{
HOST_WIDE_INT size;
if (TREE_CODE (decl) == STRING_CST
|| TREE_CODE (decl) == FUNCTION_DECL)
return false;
if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
{
const char *name;
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
if (strcmp (name, ".sdata") != 0
&& strcmp (name, ".sbss") != 0)
return true;
if (!DECL_EXTERNAL (decl))
return false;
}
size = int_size_in_bytes (TREE_TYPE (decl));
return (size > 0 && size <= SCORE3_SDATA_MAX);
}
/* Implement TARGET_ASM_FILE_START. */
void
score3_asm_file_start (void)
{
default_file_start ();
fprintf (asm_out_file, ASM_COMMENT_START
"GCC for S+core %s \n", SCORE_GCC_VERSION);
if (flag_pic)
fprintf (asm_out_file, "\t.set pic\n");
}
/* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
.externs for any small-data variables that turned out to be external. */
void
score3_asm_file_end (void)
{
tree name_tree;
struct extern_list *p;
if (extern_head)
{
fputs ("\n", asm_out_file);
for (p = extern_head; p != 0; p = p->next)
{
name_tree = get_identifier (p->name);
if (!TREE_ASM_WRITTEN (name_tree)
&& TREE_SYMBOL_REFERENCED (name_tree))
{
TREE_ASM_WRITTEN (name_tree) = 1;
fputs ("\t.extern\t", asm_out_file);
assemble_name (asm_out_file, p->name);
fprintf (asm_out_file, ", %d\n", p->size);
}
}
}
}
/* Implement TARGET_OPTION_OVERRIDE hook. */
void
score3_option_override (void)
{
flag_pic = false;
if (!flag_pic)
score3_sdata_max = (global_options_set.x_g_switch_value
? g_switch_value
: SCORE3_DEFAULT_SDATA_MAX);
else
{
score3_sdata_max = 0;
if (global_options_set.x_g_switch_value && (g_switch_value != 0))
warning (0, "-fPIC and -G are incompatible");
}
score_char_to_class['d'] = G32_REGS;
score_char_to_class['e'] = G16_REGS;
score_char_to_class['t'] = T32_REGS;
score_char_to_class['h'] = HI_REG;
score_char_to_class['l'] = LO_REG;
score_char_to_class['x'] = CE_REGS;
score_char_to_class['q'] = CN_REG;
score_char_to_class['y'] = LC_REG;
score_char_to_class['z'] = SC_REG;
score_char_to_class['a'] = SP_REGS;
score_char_to_class['c'] = CR_REGS;
}
/* Implement REGNO_REG_CLASS macro. */
int
score3_reg_class (int regno)
{
int c;
gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
if (regno == FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM)
return ALL_REGS;
for (c = 0; c < N_REG_CLASSES; c++)
if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
return c;
return NO_REGS;
}
/* Implement PREFERRED_RELOAD_CLASS macro. */
enum reg_class
score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
{
if (reg_class_subset_p (G16_REGS, rclass))
return G16_REGS;
if (reg_class_subset_p (G32_REGS, rclass))
return G32_REGS;
return rclass;
}
/* Implement SECONDARY_INPUT_RELOAD_CLASS
and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
enum reg_class
score3_secondary_reload_class (enum reg_class rclass,
enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x)
{
int regno = -1;
if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
regno = true_regnum (x);
if (!GR_REG_CLASS_P (rclass))
return GP_REG_P (regno) ? NO_REGS : G32_REGS;
return NO_REGS;
}
/* Implement CONST_OK_FOR_LETTER_P macro. */
/* imm constraints
I imm16 << 16
J uimm5
K uimm16
L simm16
M uimm14
N simm14
O simm14
P simm5
Q uimm32 */
int
score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
{
switch (c)
{
case 'I': return ((value & 0xffff) == 0);
case 'J': return IMM_IN_RANGE (value, 5, 0);
case 'K': return IMM_IN_RANGE (value, 16, 0);
case 'L': return IMM_IN_RANGE (value, 16, 1);
case 'M': return IMM_IN_RANGE (value, 14, 0);
case 'N': return IMM_IN_RANGE (value, 14, 1);
case 'O': return IMM_IN_RANGE (value, 5, 1);
case 'P': return IMM_IN_RANGE (value, 6, 1);
case 'Q': return score_extra_constraint (GEN_INT(value), c);
default : return 0;
}
}
/* Implement EXTRA_CONSTRAINT macro. */
/*
Q uimm32
Z symbol_ref */
int
score3_extra_constraint (rtx op, char c)
{
switch (c)
{
case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
case 'Z':
return GET_CODE (op) == SYMBOL_REF;
default:
gcc_unreachable ();
}
}
/* Return truth value on whether or not a given hard register
can support a given mode. */
int
score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
{
int size = GET_MODE_SIZE (mode);
enum mode_class mclass = GET_MODE_CLASS (mode);
if (mclass == MODE_CC)
return regno == CC_REGNUM;
else if (regno == FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM)
return mclass == MODE_INT;
else if (GP_REG_P (regno))
return !(regno & 1) || (size <= UNITS_PER_WORD);
else if (CE_REG_P (regno))
return (mclass == MODE_INT
&& ((size <= UNITS_PER_WORD)
|| (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
else
return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
}
/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
pointer or argument pointer. TO is either the stack pointer or
hard frame pointer. */
HOST_WIDE_INT
score3_initial_elimination_offset (int from,
int to ATTRIBUTE_UNUSED)
{
struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
switch (from)
{
case ARG_POINTER_REGNUM:
return f->total_size;
case FRAME_POINTER_REGNUM:
return 0;
default:
gcc_unreachable ();
}
}
/* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
void
score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named)
{
struct score3_arg_info info;
score3_classify_arg (cum, mode, type, named, &info);
cum->num_gprs = info.reg_offset + info.reg_words;
if (info.stack_words > 0)
cum->stack_words = info.stack_offset + info.stack_words;
cum->arg_number++;
}
/* Implement TARGET_ARG_PARTIAL_BYTES macro. */
int
score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
enum machine_mode mode, tree type, bool named)
{
struct score3_arg_info info;
score3_classify_arg (cum, mode, type, named, &info);
return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
}
/* Implement TARGET_FUNCTION_ARG hook. */
rtx
score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named)
{
struct score3_arg_info info;
if (mode == VOIDmode || !named)
return 0;
score3_classify_arg (cum, mode, type, named, &info);
if (info.reg_offset == ARG_REG_NUM)
return 0;
if (!info.stack_words)
return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
else
{
rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
unsigned int i, part_offset = 0;
for (i = 0; i < info.reg_words; i++)
{
rtx reg;
reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
GEN_INT (part_offset));
part_offset += UNITS_PER_WORD;
}
return ret;
}
}
/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
VALTYPE is the return type and MODE is VOIDmode. For libcalls,
VALTYPE is null and MODE is the mode of the return value. */
rtx
score3_function_value (const_tree valtype, const_tree func,
enum machine_mode mode)
{
if (valtype)
{
int unsignedp;
mode = TYPE_MODE (valtype);
unsignedp = TYPE_UNSIGNED (valtype);
mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
}
return gen_rtx_REG (mode, RT_REGNUM);
}
/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
void
score3_asm_trampoline_template (FILE *f)
{
fprintf (f, "\t.set r1\n");
fprintf (f, "\tmv! r31, r3\n");
fprintf (f, "\tnop!\n");
fprintf (f, "\tbl nextinsn\n");
fprintf (f, "nextinsn:\n");
fprintf (f, "\tlw! r1, [r3, 6*4-8]\n");
fprintf (f, "\tnop!\n");
fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
fprintf (f, "\tmv! r3, r31\n");
fprintf (f, "\tnop!\n");
fprintf (f, "\tbr! r1\n");
fprintf (f, "\tnop!\n");
fprintf (f, "\t.set nor1\n");
}
/* Implement TARGET_TRAMPOLINE_INIT. */
void
score3_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{
#define FFCACHE "_flush_cache"
#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
rtx addr = XEXP (m_tramp, 0);
rtx mem;
emit_block_move (m_tramp, assemble_trampoline_template (),
GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
mem = adjust_address (m_tramp, SImode, CODE_SIZE);
emit_move_insn (mem, fnaddr);
mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
emit_move_insn (mem, chain_value);
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
LCT_NORMAL, VOIDmode, 2,
addr, Pmode,
GEN_INT (TRAMPOLINE_SIZE), SImode);
#undef FFCACHE
#undef CODE_SIZE
}
/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
int
score3_regno_mode_ok_for_base_p (int regno, int strict)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
if (!strict)
return 1;
regno = reg_renumber[regno];
}
if (regno == ARG_POINTER_REGNUM
|| regno == FRAME_POINTER_REGNUM)
return 1;
return GP_REG_P (regno);
}
/* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
bool
score3_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
{
struct score3_address_info addr;
return score3_classify_address (&addr, mode, x, strict);
}
/* Return a number assessing the cost of moving a register in class
FROM to class TO. */
int
score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
enum reg_class from, enum reg_class to)
{
if (GR_REG_CLASS_P (from))
{
if (GR_REG_CLASS_P (to))
return 2;
else if (SP_REG_CLASS_P (to))
return 4;
else if (CP_REG_CLASS_P (to))
return 5;
else if (CE_REG_CLASS_P (to))
return 6;
}
if (GR_REG_CLASS_P (to))
{
if (GR_REG_CLASS_P (from))
return 2;
else if (SP_REG_CLASS_P (from))
return 4;
else if (CP_REG_CLASS_P (from))
return 5;
else if (CE_REG_CLASS_P (from))
return 6;
}
return 12;
}
/* Return the number of instructions needed to load a symbol of the
given type into a register. */
static int
score3_symbol_insns (enum score_symbol_type type)
{
switch (type)
{
case SYMBOL_GENERAL:
return 2;
case SYMBOL_SMALL_DATA:
return 1;
}
gcc_unreachable ();
}
/* Return the number of instructions needed to load or store a value
of mode MODE at X. Return 0 if X isn't valid for MODE. */
static int
score3_address_insns (rtx x, enum machine_mode mode)
{
struct score3_address_info addr;
int factor;
if (mode == BLKmode)
factor = 1;
else
factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (score3_classify_address (&addr, mode, x, false))
switch (addr.type)
{
case SCORE3_ADD_REG:
case SCORE3_ADD_CONST_INT:
return factor;
case SCORE3_ADD_SYMBOLIC:
return factor * score3_symbol_insns (addr.symbol_type);
}
return 0;
}
/* Implement TARGET_RTX_COSTS macro. */
bool
score3_rtx_costs (rtx x, int code, int outer_code, int *total,
bool speed ATTRIBUTE_UNUSED)
{
enum machine_mode mode = GET_MODE (x);
switch (code)
{
case CONST_INT:
if (outer_code == SET)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
*total = COSTS_N_INSNS (1);
else
*total = COSTS_N_INSNS (2);
}
else if (outer_code == PLUS || outer_code == MINUS)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
*total = 0;
else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
*total = 1;
else
*total = COSTS_N_INSNS (2);
}
else if (outer_code == AND || outer_code == IOR)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
*total = 0;
else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
*total = 1;
else
*total = COSTS_N_INSNS (2);
}
else
{
*total = 0;
}
return true;
case CONST:
case SYMBOL_REF:
case LABEL_REF:
case CONST_DOUBLE:
*total = COSTS_N_INSNS (2);
return true;
case MEM:
{
/* If the address is legitimate, return the number of
instructions it needs, otherwise use the default handling. */
int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
if (n > 0)
{
*total = COSTS_N_INSNS (n + 1);
return true;
}
return false;
}
case FFS:
*total = COSTS_N_INSNS (6);
return true;
case NOT:
*total = COSTS_N_INSNS (1);
return true;
case AND:
case IOR:
case XOR:
if (mode == DImode)
{
*total = COSTS_N_INSNS (2);
return true;
}
return false;
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
if (mode == DImode)
{
*total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
? 4 : 12);
return true;
}
return false;
case ABS:
*total = COSTS_N_INSNS (4);
return true;
case PLUS:
case MINUS:
if (mode == DImode)
{
*total = COSTS_N_INSNS (4);
return true;
}
*total = COSTS_N_INSNS (1);
return true;
case NEG:
if (mode == DImode)
{
*total = COSTS_N_INSNS (4);
return true;
}
return false;
case MULT:
*total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
return true;
case DIV:
case MOD:
case UDIV:
case UMOD:
*total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
return true;
case SIGN_EXTEND:
case ZERO_EXTEND:
switch (GET_MODE (XEXP (x, 0)))
{
case QImode:
case HImode:
if (GET_CODE (XEXP (x, 0)) == MEM)
{
*total = COSTS_N_INSNS (2);
if (!TARGET_LITTLE_ENDIAN &&
side_effects_p (XEXP (XEXP (x, 0), 0)))
*total = 100;
}
else
*total = COSTS_N_INSNS (1);
break;
default:
*total = COSTS_N_INSNS (1);
break;
}
return true;
default:
return false;
}
}
/* Implement TARGET_ADDRESS_COST macro. */
int
score3_address_cost (rtx addr)
{
return score3_address_insns (addr, SImode);
}
/* Implement ASM_OUTPUT_EXTERNAL macro. */
int
score3_output_external (FILE *file ATTRIBUTE_UNUSED,
tree decl, const char *name)
{
register struct extern_list *p;
if (score3_in_small_data_p (decl))
{
p = ggc_alloc_extern_list ();
p->next = extern_head;
p->name = name;
p->size = int_size_in_bytes (TREE_TYPE (decl));
extern_head = p;
}
return 0;
}
/* Implement RETURN_ADDR_RTX. Note, we do not support moving
back to a previous frame. */
rtx
score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
{
if (count != 0)
return const0_rtx;
return get_hard_reg_initial_val (Pmode, RA_REGNUM);
}
/* Implement PRINT_OPERAND macro. */
/* Score-specific operand codes:
'[' print .set nor1 directive
']' print .set r1 directive
'U' print hi part of a CONST_INT rtx
'E' print log2(v)
'F' print log2(~v)
'D' print SFmode const double
'S' selectively print "!" if operand is 15bit instruction accessible
'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
'L' low part of DImode reg operand
'H' high part of DImode reg operand
'C' print part of opcode for a branch condition. */
void
score3_print_operand (FILE *file, rtx op, int c)
{
enum rtx_code code = UNKNOWN;
if (!PRINT_OPERAND_PUNCT_VALID_P (c))
code = GET_CODE (op);
if (c == '[')
{
fprintf (file, ".set r1\n");
}
else if (c == ']')
{
fprintf (file, "\n\t.set nor1");
}
else if (c == 'U')
{
gcc_assert (code == CONST_INT);
fprintf (file, HOST_WIDE_INT_PRINT_HEX,
(INTVAL (op) >> 16) & 0xffff);
}
else if (c == 'D')
{
if (GET_CODE (op) == CONST_DOUBLE)
{
rtx temp = gen_lowpart (SImode, op);
gcc_assert (GET_MODE (op) == SFmode);
fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
}
else
output_addr_const (file, op);
}
else if (c == 'S')
{
gcc_assert (code == REG);
if (G16_REG_P (REGNO (op)))
fprintf (file, "!");
}
else if (c == 'V')
{
gcc_assert (code == REG);
fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
}
else if (c == 'C')
{
enum machine_mode mode = GET_MODE (XEXP (op, 0));
switch (code)
{
case EQ: fputs ("eq!", file); break;
case NE: fputs ("ne!", file); break;
case GT: fputs ("gt!", file); break;
case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
case LE: fputs ("le!", file); break;
case GTU: fputs ("gtu!", file); break;
case GEU: fputs ("cs", file); break;
case LTU: fputs ("cc", file); break;
case LEU: fputs ("leu!", file); break;
default:
output_operand_lossage ("invalid operand for code: '%c'", code);
}
}
else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
{
enum machine_mode mode = GET_MODE (XEXP (op, 0));
switch (code)
{
case EQ: fputs ("eq", file); break;
case NE: fputs ("ne", file); break;
case GT: fputs ("gt", file); break;
case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
case LE: fputs ("le", file); break;
case GTU: fputs ("gtu", file); break;
case GEU: fputs ("cs", file); break;
case LTU: fputs ("cc", file); break;
case LEU: fputs ("leu", file); break;
default:
output_operand_lossage ("invalid operand for code: '%c'", code);
}
}
else if (c == 'E')
{
unsigned HOST_WIDE_INT i;
unsigned HOST_WIDE_INT pow2mask = 1;
unsigned HOST_WIDE_INT val;
val = INTVAL (op);
for (i = 0; i < 32; i++)
{
if (val == pow2mask)
break;
pow2mask <<= 1;
}
gcc_assert (i < 32);
fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
}
else if (c == 'F')
{
unsigned HOST_WIDE_INT i;
unsigned HOST_WIDE_INT pow2mask = 1;
unsigned HOST_WIDE_INT val;
val = ~INTVAL (op);
for (i = 0; i < 32; i++)
{
if (val == pow2mask)
break;
pow2mask <<= 1;
}
gcc_assert (i < 32);
fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
}
else if (code == REG)
{
int regnum = REGNO (op);
if ((c == 'H' && !WORDS_BIG_ENDIAN)
|| (c == 'L' && WORDS_BIG_ENDIAN))
regnum ++;
fprintf (file, "%s", reg_names[regnum]);
}
else
{
switch (code)
{
case MEM:
score3_print_operand_address (file, op);
break;
default:
output_addr_const (file, op);
}
}
}
/* Implement PRINT_OPERAND_ADDRESS macro. */
void
score3_print_operand_address (FILE *file, rtx x)
{
struct score3_address_info addr;
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
if (code == MEM)
x = XEXP (x, 0);
if (score3_classify_address (&addr, mode, x, true))
{
switch (addr.type)
{
case SCORE3_ADD_REG:
{
switch (addr.code)
{
case PRE_DEC:
fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
INTVAL (addr.offset));
break;
case POST_DEC:
fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
INTVAL (addr.offset));
break;
case PRE_INC:
fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
INTVAL (addr.offset));
break;
case POST_INC:
fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
INTVAL (addr.offset));
break;
default:
if (INTVAL(addr.offset) == 0)
fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
else
fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
INTVAL(addr.offset));
break;
}
}
return;
case SCORE3_ADD_CONST_INT:
case SCORE3_ADD_SYMBOLIC:
output_addr_const (file, x);
return;
}
}
print_rtl (stderr, x);
gcc_unreachable ();
}
/* Implement SELECT_CC_MODE macro. */
enum machine_mode
score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
{
if ((op == EQ || op == NE || op == LT || op == GE)
&& y == const0_rtx
&& GET_MODE (x) == SImode)
{
switch (GET_CODE (x))
{
case PLUS:
case MINUS:
case NEG:
case AND:
case IOR:
case XOR:
case NOT:
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
return CC_NZmode;
case SIGN_EXTEND:
case ZERO_EXTEND:
case ROTATE:
case ROTATERT:
return (op == LT || op == GE) ? CC_Nmode : CCmode;
default:
return CCmode;
}
}
if ((op == EQ || op == NE)
&& (GET_CODE (y) == NEG)
&& register_operand (XEXP (y, 0), SImode)
&& register_operand (x, SImode))
{
return CC_NZmode;
}
return CCmode;
}
#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
/* return 0, no more bit set in mask. */
static int rpush_first (int mask, int sb, int *rd)
{
int i, cnt = 1;
if ((mask & (1 << sb)) == 0)
return 0;
*rd = sb;
for (i = sb-1; i >= 0; i--)
{
if (mask & (1 << i))
{
cnt ++;
continue;
}
*rd = i+1;
break;;
}
return cnt;
}
static void
rpush (int rd, int cnt)
{
rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
rtx reg = gen_rtx_REG (SImode, rd);
if (!crtl->calls_eh_return)
MEM_READONLY_P (mem) = 1;
if (cnt == 1)
EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
else
{
int i;
rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
gen_rtx_REG (SImode, rd),
GEN_INT (cnt));
rtx pat = PATTERN (insn);
for (i = 0; i < XVECLEN (pat, 0); i++)
if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
EMIT_PL (emit_insn (insn));
}
}
/* Generate the prologue instructions for entry into a S+core function. */
void
score3_prologue (void)
{
struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
HOST_WIDE_INT size;
int regno;
size = f->total_size - f->gp_reg_size;
if (flag_pic)
emit_insn (gen_cpload_score3 ());
{
int cnt, rd;
for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
{
cnt = rpush_first (f->mask, regno, &rd);
if (cnt != 0)
{
rpush (rd, cnt);
regno = regno - cnt;
}
}
}
if (size > 0)
{
rtx insn;
if (CONST_OK_FOR_LETTER_P (-size, 'L'))
EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-size))));
else
{
EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
GEN_INT (size)));
EMIT_PL (emit_insn
(gen_sub3_insn (stack_pointer_rtx,
stack_pointer_rtx,
gen_rtx_REG (Pmode,
SCORE3_PROLOGUE_TEMP_REGNUM))));
}
insn = get_last_insn ();
REG_NOTES (insn) =
alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx,
-size)),
REG_NOTES (insn));
}
if (frame_pointer_needed)
EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
if (flag_pic && f->cprestore_size)
{
if (frame_pointer_needed)
emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
else
emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
}
}
/* return 0, no more bit set in mask. */
static int
rpop_first (int mask, int sb, int *rd)
{
int i, cnt = 1;
if ((mask & (1 << sb)) == 0)
return 0;
*rd = sb;
for (i = sb+1; i < 32; i++)
if (mask & (1 << i))
cnt++;
else
break;;
return cnt;
}
static void
rpop (int rd, int cnt)
{
rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
rtx reg = gen_rtx_REG (SImode, rd);
if (!crtl->calls_eh_return)
MEM_READONLY_P (mem) = 1;
if (cnt == 1)
emit_insn (gen_popsi_score3 (reg, mem));
else
emit_insn (gen_load_multiple (reg,
gen_rtx_MEM (SImode, stack_pointer_rtx),
GEN_INT (cnt)));
}
/* Generate the epilogue instructions in a S+core function. */
void
score3_epilogue (int sibcall_p)
{
struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
HOST_WIDE_INT size;
int regno;
rtx base;
size = f->total_size - f->gp_reg_size;
if (!frame_pointer_needed)
base = stack_pointer_rtx;
else
base = hard_frame_pointer_rtx;
if (size)
{
if (CONST_OK_FOR_LETTER_P (size, 'L'))
emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
else
{
emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
GEN_INT (size));
emit_insn (gen_add3_insn (base, base,
gen_rtx_REG (Pmode,
SCORE3_EPILOGUE_TEMP_REGNUM)));
}
}
if (base != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, base);
if (crtl->calls_eh_return)
emit_insn (gen_add3_insn (stack_pointer_rtx,
stack_pointer_rtx,
EH_RETURN_STACKADJ_RTX));
{
int cnt, rd;
for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
{
cnt = rpop_first (f->mask, regno, &rd);
if (cnt != 0)
{
rpop (rd, cnt);
regno = regno + cnt;
}
}
}
if (!sibcall_p)
emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
}
/* Return true if X is a symbolic constant that can be calculated in
the same way as a bare symbol. If it is, store the type of the
symbol in *SYMBOL_TYPE. */
int
score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
{
HOST_WIDE_INT offset;
score3_split_const (x, &x, &offset);
if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
*symbol_type = score3_classify_symbol (x);
else
return 0;
if (offset == 0)
return 1;
/* if offset > 15bit, must reload */
if (!IMM_IN_RANGE (offset, 15, 1))
return 0;
switch (*symbol_type)
{
case SYMBOL_GENERAL:
return 1;
case SYMBOL_SMALL_DATA:
return score3_offset_within_object_p (x, offset);
}
gcc_unreachable ();
}
void
score3_movsicc (rtx *ops)
{
enum machine_mode mode;
mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
XEXP (ops[1], 1))));
}
/* Call and sibcall pattern all need call this function. */
void
score3_call (rtx *ops, bool sib)
{
rtx addr = XEXP (ops[0], 0);
if (!call_insn_operand (addr, VOIDmode))
{
rtx oaddr = addr;
addr = gen_reg_rtx (Pmode);
gen_move_insn (addr, oaddr);
}
if (sib)
emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
else
emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
}
/* Call value and sibcall value pattern all need call this function. */
void
score3_call_value (rtx *ops, bool sib)
{
rtx result = ops[0];
rtx addr = XEXP (ops[1], 0);
rtx arg = ops[2];
if (!call_insn_operand (addr, VOIDmode))
{
rtx oaddr = addr;
addr = gen_reg_rtx (Pmode);
gen_move_insn (addr, oaddr);
}
if (sib)
emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
else
emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
}
/* Machine Split */
void
score3_movdi (rtx *ops)
{
rtx dst = ops[0];
rtx src = ops[1];
rtx dst0 = score3_subw (dst, 0);
rtx dst1 = score3_subw (dst, 1);
rtx src0 = score3_subw (src, 0);
rtx src1 = score3_subw (src, 1);
if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
{
emit_move_insn (dst1, src1);
emit_move_insn (dst0, src0);
}
else
{
emit_move_insn (dst0, src0);
emit_move_insn (dst1, src1);
}
}
void
score3_zero_extract_andi (rtx *ops)
{
if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
else
{
unsigned HOST_WIDE_INT mask;
mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
mask = mask << INTVAL (ops[2]);
emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
gen_int_mode (mask, SImode)));
}
}
const char *
score3_rpush (rtx *ops)
{
snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
return score3_ins;
}
const char *
score3_rpop (rtx *ops)
{
snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
return score3_ins;
}
/* Output asm code for ld/sw insn. */
static int
score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
enum score_mem_unit unit ATTRIBUTE_UNUSED)
{
struct score3_address_info ai;
gcc_assert (GET_CODE (ops[idata]) == REG);
gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
if (ai.type == SCORE3_ADD_REG
&& ai.code == REG
&& GET_CODE (ai.offset) == CONST_INT
&& G16_REG_P (REGNO (ops[idata]))
&& G8_REG_P (REGNO (ai.reg))
&& ((INTVAL (ai.offset) & 3) == 0)
&& (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
{
ops[iaddr] = ai.reg;
return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
HOST_WIDE_INT_PRINT_DEC "]",
idata, iaddr, INTVAL (ai.offset));
}
if (ai.type == SCORE3_ADD_SYMBOLIC)
return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
}
/* Output asm insn for load. */
const char *
score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
{
const char *pre_ins[] =
{"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
char *ip;
strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
ip = score3_ins + strlen (score3_ins);
if (unit == SCORE_WORD)
score3_pr_addr_post (ops, 0, 1, ip, unit);
else
snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
return score3_ins;
}
/* Output asm insn for store. */
const char *
score3_sinsn (rtx *ops, enum score_mem_unit unit)
{
const char *pre_ins[] = {"sb", "sh", "sw"};
char *ip;
strcpy (score3_ins, pre_ins[unit]);
ip = score3_ins + strlen (score3_ins);
if (unit == SCORE_WORD)
score3_pr_addr_post (ops, 1, 0, ip, unit);
else
snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
return score3_ins;
}
/* Output asm insn for load immediate. */
const char *
score3_limm (rtx *ops)
{
HOST_WIDE_INT v;
gcc_assert (GET_CODE (ops[0]) == REG);
gcc_assert (GET_CODE (ops[1]) == CONST_INT);
v = INTVAL (ops[1]);
if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
return "ldiu!\t%0, %c1";
else if (IMM_IN_RANGE (v, 16, 1))
return "ldi\t%0, %c1";
else if ((v & 0xffff) == 0)
return "ldis\t%0, %U1";
else
return "li\t%0, %c1";
}
/* Output asm insn for move. */
const char *
score3_move (rtx *ops)
{
gcc_assert (GET_CODE (ops[0]) == REG);
gcc_assert (GET_CODE (ops[1]) == REG);
return "mv!\t%0, %1";
}
/* Generate add insn. */
const char *
score3_select_add_imm (rtx *ops, bool set_cc)
{
HOST_WIDE_INT v = INTVAL (ops[2]);
gcc_assert (GET_CODE (ops[2]) == CONST_INT);
gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
if (set_cc)
return "addi.c\t%0, %c2";
else
if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
return "addi!\t%0, %c2";
else
return "addi\t%0, %c2";
}
/* Output arith insn. */
const char *
score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
const char *letter, bool set_cc)
{
gcc_assert (GET_CODE (ops[0]) == REG);
gcc_assert (GET_CODE (ops[1]) == REG);
if (set_cc)
snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
else
snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
return score3_ins;
}
/* Output a Score3 casesi instruction. */
const char *
score3_output_casesi (rtx *operands)
{
rtx diff_vec = PATTERN (next_real_insn (operands[2]));
gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
output_asm_insn ("cmpi.c\t%0, %1", operands);
output_asm_insn ("bgtu\t%3", operands);
switch (GET_MODE(diff_vec))
{
case QImode:
output_asm_insn ("ldi48\t%4, %2", operands);
output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
return "brr!\t%4";
case HImode:
output_asm_insn ("ldi48\t%4, %2", operands);
output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
return "brr!\t%4";
case SImode:
output_asm_insn ("ldi48\t%4, %2", operands);
output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
return "br!\t%4";
default:
gcc_unreachable ();
}
}
/* score3.h for Sunplus S+CORE processor
Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Sunnorth
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_SCORE3_H
#define GCC_SCORE3_H
enum score3_address_type
{
SCORE3_ADD_REG,
SCORE3_ADD_CONST_INT,
SCORE3_ADD_SYMBOLIC
};
struct score3_frame_info
{
HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
HOST_WIDE_INT var_size; /* bytes that variables take up */
HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
unsigned int mask; /* mask of saved gp registers */
int num_gp; /* number of gp registers saved */
};
struct score3_arg_info
{
unsigned int num_bytes; /* The argument's size in bytes */
unsigned int reg_words; /* The number of words passed in registers */
unsigned int reg_offset; /* The offset of the first register from */
/* GP_ARG_FIRST or FP_ARG_FIRST etc */
unsigned int stack_words; /* The number of words that must be passed */
/* on the stack */
unsigned int stack_offset; /* The offset from the start of the stack */
/* overflow area */
};
#ifdef RTX_CODE
struct score3_address_info
{
enum score3_address_type type;
rtx reg;
rtx offset;
enum rtx_code code;
enum score_symbol_type symbol_type;
};
#endif
#define SCORE3_SDATA_MAX score3_sdata_max
#define SCORE3_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
#define SCORE3_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
#define SCORE3_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
#define SCORE3_DEFAULT_SDATA_MAX 8
extern int score3_symbolic_constant_p (rtx x,
enum score_symbol_type *symbol_type);
extern bool score3_return_in_memory (const_tree type,
const_tree fndecl ATTRIBUTE_UNUSED);
extern void score3_output_mi_thunk (FILE *file,
tree thunk_fndecl ATTRIBUTE_UNUSED,
HOST_WIDE_INT delta,
HOST_WIDE_INT vcall_offset,
tree function);
extern rtx score3_legitimize_address (rtx x);
extern void
score3_function_prologue (FILE *file,
HOST_WIDE_INT size ATTRIBUTE_UNUSED);
extern void
score3_function_epilogue (FILE *file,
HOST_WIDE_INT size ATTRIBUTE_UNUSED);
extern section *score3_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align);
extern bool score3_in_small_data_p (const_tree decl);
extern void score3_asm_file_start (void);
extern void score3_asm_file_end (void);
extern void score3_option_override (void);
extern int score3_reg_class (int regno);
extern enum reg_class score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED,
enum reg_class rclass);
extern enum reg_class
score3_secondary_reload_class (enum reg_class rclass,
enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x);
extern int score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c);
extern int score3_extra_constraint (rtx op, char c);
extern int score3_hard_regno_mode_ok (unsigned int regno,
enum machine_mode mode);
extern HOST_WIDE_INT
score3_initial_elimination_offset (int from,
int to ATTRIBUTE_UNUSED);
extern void score3_function_arg_advance (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
const_tree type,
bool named);
extern int score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
tree type,
bool named);
extern rtx score3_function_arg (const CUMULATIVE_ARGS *cum,
enum machine_mode mode,
const_tree type,
bool named);
extern rtx score3_function_value (const_tree valtype,
const_tree func ATTRIBUTE_UNUSED,
enum machine_mode mode);
extern void score3_asm_trampoline_template (FILE *);
extern void score3_trampoline_init (rtx, tree, rtx);
extern int score3_regno_mode_ok_for_base_p (int regno, int strict);
extern bool score3_legitimate_address_p (enum machine_mode mode, rtx x,
bool strict);
extern int score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
enum reg_class from,
enum reg_class to);
extern bool score3_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed);
extern int score3_address_cost (rtx addr);
extern int score3_output_external (FILE *file ATTRIBUTE_UNUSED,
tree decl,
const char *name);
extern rtx score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED);
extern void score3_print_operand (FILE *file, rtx op, int c);
extern void score3_print_operand_address (FILE *file, rtx x);
extern enum machine_mode
score3_select_cc_mode (enum rtx_code op, rtx x, rtx y);
extern void score3_prologue (void);
extern void score3_epilogue (int sibcall_p);
extern void score3_call (rtx *ops, bool sib);
extern void score3_call_value (rtx *ops, bool sib);
extern void score3_movsicc (rtx *ops);
extern void score3_movdi (rtx *ops);
extern void score3_zero_extract_andi (rtx *ops);
extern const char * score3_select_add_imm (rtx *ops, bool set_cc);
extern const char * score3_select (rtx *ops, const char *inst_pre, bool commu,
const char *letter, bool set_cc);
extern const char * score3_move (rtx *ops);
extern const char * score3_limm (rtx *ops);
extern const char *
score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign);
extern const char *
score3_sinsn (rtx *ops, enum score_mem_unit unit);
extern const char * score3_output_casesi (rtx *operands);
extern const char * score3_rpush (rtx *ops);
extern const char * score3_rpop (rtx *ops);
#endif
......@@ -340,7 +340,7 @@ score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
if (delta != 0)
{
rtx offset = GEN_INT (delta);
if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
if (!(delta >= -32768 && delta <= 32767))
{
emit_move_insn (temp1, offset);
offset = temp1;
......@@ -638,31 +638,8 @@ void
score7_option_override (void)
{
flag_pic = false;
if (!flag_pic)
score7_sdata_max = (global_options_set.x_g_switch_value
? g_switch_value
: SCORE7_DEFAULT_SDATA_MAX);
else
{
score7_sdata_max = 0;
if (global_options_set.x_g_switch_value && (g_switch_value != 0))
warning (0, "-fPIC and -G are incompatible");
}
score_char_to_class['d'] = G32_REGS;
score_char_to_class['e'] = G16_REGS;
score_char_to_class['t'] = T32_REGS;
score_char_to_class['h'] = HI_REG;
score_char_to_class['l'] = LO_REG;
score_char_to_class['x'] = CE_REGS;
score7_sdata_max = SCORE7_DEFAULT_SDATA_MAX;
score_char_to_class['q'] = CN_REG;
score_char_to_class['y'] = LC_REG;
score_char_to_class['z'] = SC_REG;
score_char_to_class['a'] = SP_REGS;
score_char_to_class['c'] = CR_REGS;
}
/* Implement REGNO_REG_CLASS macro. */
......@@ -710,42 +687,6 @@ score7_secondary_reload_class (enum reg_class rclass,
return NO_REGS;
}
/* Implement CONST_OK_FOR_LETTER_P macro. */
/* imm constraints
I imm16 << 16
J uimm5
K uimm16
L simm16
M uimm14
N simm14 */
int
score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
{
switch (c)
{
case 'I': return ((value & 0xffff) == 0);
case 'J': return IMM_IN_RANGE (value, 5, 0);
case 'K': return IMM_IN_RANGE (value, 16, 0);
case 'L': return IMM_IN_RANGE (value, 16, 1);
case 'M': return IMM_IN_RANGE (value, 14, 0);
case 'N': return IMM_IN_RANGE (value, 14, 1);
default : return 0;
}
}
/* Implement EXTRA_CONSTRAINT macro. */
/* Z symbol_ref */
int
score7_extra_constraint (rtx op, char c)
{
switch (c)
{
case 'Z':
return GET_CODE (op) == SYMBOL_REF;
default:
gcc_unreachable ();
}
}
/* Return truth value on whether or not a given hard register
can support a given mode. */
......@@ -884,7 +825,6 @@ score7_asm_trampoline_template (FILE *f)
void
score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{
#define FFCACHE "_flush_cache"
#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
......@@ -899,11 +839,6 @@ score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
emit_move_insn (mem, chain_value);
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
LCT_NORMAL, VOIDmode, 2,
addr, Pmode,
GEN_INT (TRAMPOLINE_SIZE), SImode);
#undef FFCACHE
#undef CODE_SIZE
}
......@@ -1018,28 +953,28 @@ score7_rtx_costs (rtx x, int code, int outer_code, int *total,
case CONST_INT:
if (outer_code == SET)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
if (((INTVAL (x) & 0xffff) == 0)
|| (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
*total = COSTS_N_INSNS (1);
else
*total = COSTS_N_INSNS (2);
}
else if (outer_code == PLUS || outer_code == MINUS)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
*total = 0;
else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
else if (((INTVAL (x) & 0xffff) == 0)
|| (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
*total = 1;
else
*total = COSTS_N_INSNS (2);
}
else if (outer_code == AND || outer_code == IOR)
{
if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
*total = 0;
else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
|| CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
else if (((INTVAL (x) & 0xffff) == 0)
|| (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
*total = 1;
else
*total = COSTS_N_INSNS (2);
......@@ -1456,7 +1391,7 @@ score7_prologue (void)
{
rtx insn;
if (CONST_OK_FOR_LETTER_P (-size, 'L'))
if (size >= -32768 && size <= 32767)
EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-size))));
......@@ -1511,7 +1446,7 @@ score7_epilogue (int sibcall_p)
if (size)
{
if (CONST_OK_FOR_LETTER_P (size, 'L'))
if (size >= -32768 && size <= 32767)
emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
else
{
......@@ -1714,7 +1649,7 @@ score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_un
{
HOST_WIDE_INT offset = INTVAL (ai.offset);
if (SCORE_ALIGN_UNIT (offset, unit)
&& CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
&& (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
{
ops[iaddr] = ai.offset;
return snprintf (ip, INS_BUF_SZ,
......
#define _FP_W_TYPE_SIZE 32
#define _FP_W_TYPE unsigned long
#define _FP_WS_TYPE signed long
#define _FP_I_TYPE long
/* The type of the result of a floating point comparison. This must
match `__libgcc_cmp_return__' in GCC for the target. */
typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
#define CMPtype __gcc_CMPtype
#define _FP_MUL_MEAT_S(R,X,Y) \
_FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_D(R,X,Y) \
_FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
#define _FP_MUL_MEAT_Q(R,X,Y) \
_FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_loop(S,R,X,Y)
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
/* Someone please check this. */
#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
do { \
if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \
&& !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \
{ \
R##_s = Y##_s; \
_FP_FRAC_COPY_##wc(R,Y); \
} \
else \
{ \
R##_s = X##_s; \
_FP_FRAC_COPY_##wc(R,X); \
} \
R##_c = FP_CLS_NAN; \
} while (0)
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
# define __BYTE_ORDER __BIG_ENDIAN
/* Define ALIASNAME as a strong alias for NAME. */
# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((alias (#name)));
......@@ -19,17 +19,10 @@
# Additional Backend Files
score7.o: $(srcdir)/config/score/score7.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(RTL_H) output.h flags.h $(TREE_H) \
expr.h $(TM_P_H)
expr.h toplev.h $(TM_P_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(srcdir)/config/score/score7.c
score3.o: $(srcdir)/config/score/score3.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(RTL_H) output.h flags.h $(TREE_H) \
expr.h $(TM_P_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(srcdir)/config/score/score3.c
# Assemble startup files.
$(T)crti.o: $(srcdir)/config/score/crti.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
......@@ -38,33 +31,3 @@ $(T)crti.o: $(srcdir)/config/score/crti.asm $(GCC_PASSES)
$(T)crtn.o: $(srcdir)/config/score/crtn.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
-c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/score/crtn.asm
LIB1ASMSRC = score/mul-div.S
LIB1ASMFUNCS = _mulsi3 _divsi3 _flush_cache
FPBIT = fp-bit.c
DPBIT = dp-bit.c
# If any special flags are necessary when building libgcc2 put them here.
TARGET_LIBGCC2_CFLAGS = -g
fp-bit.c: $(srcdir)/config/fp-bit.c
echo '#define FLOAT' > fp-bit.c
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
dp-bit.c: $(srcdir)/config/fp-bit.c
cat $(srcdir)/config/fp-bit.c > dp-bit.c
# We must build libgcc2.a with -G 0, in case the user wants to link
# without the $gp register.
TARGET_LIBGCC2_CFLAGS = -G 0
MULTILIB_OPTIONS = mscore3 mel
MULTILIB_MATCHES = mscore3=march?score3
EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
softfp_float_modes := sf df
softfp_int_modes := si di
softfp_extensions := sfdf
softfp_truncations := dfsf
softfp_machine_header := score/sfp-machine.h
softfp_exclude_libgcc2 := y
# softfp seems to be missing a whole bunch of prototypes.
TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment