From: Chen Liqin Date: Thu, 18 Oct 2007 06:53:22 +0000 (+0000) Subject: Because we merge score3 and score7 into the same backend, X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=254f522229578af1af093b2e4b6f1a0cc400d216;p=gcc.git Because we merge score3 and score7 into the same backend, so make a lot of changes in the code structure. Changelog: * config.gcc : update score-*-elf(extra_objs). * config/score/mac.md : Remove. * config/score/misc.md : Remove. * config/score/score7.md : Remove. * config/score/score-mdaux.h : Remove. * config/score/score-mdaux.c : Remove. * config/score/score-version.h : Remove. * config/score/score-generic.md : New. * config/score/score3.h : New. * config/score/score3.c : New. * config/score/score7.h : New. * config/score/score7.c : New. * config/score/mul-div.S : add flush_cache score3 support. * config/score/elf.h : Fix some typos. * config/score/score.md : merge score3 and score7 pattern. * config/score/score.c : use to seperate which target it used. * config/score/score.h : use to seperate the target macro. * config/score/score.opt : remove -mmac option , add -mscore3, -mscore3d and -march OPTION support. From-SVN: r129431 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d0114fd04bc..1bf4a2def8f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2007-10-18 Chen Liqin + + * config.gcc : update score-*-elf(extra_objs). + * config/score/mac.md : Remove. + * config/score/misc.md : Remove. + * config/score/score7.md : Remove. + * config/score/score-mdaux.h : Remove. + * config/score/score-mdaux.c : Remove. + * config/score/score-version.h : Remove. + * config/score/score-generic.md : New. + * config/score/score3.h : New. + * config/score/score3.c : New. + * config/score/score7.h : New. + * config/score/score7.c : New. + * config/score/mul-div.S : add flush_cache score3 support. + * config/score/elf.h : Fix some typos. + * config/score/score.md : merge score3 and score7 pattern. + * config/score/score.c : use to seperate which target it used. + * config/score/score.h : use to seperate the target macro. + * config/score/score.opt : remove -mmac option , add -mscore3, + -mscore3d and -march OPTION support. + 2007-10-17 Andrew Pinski * cfgexpand.c (expand_stack_vars): Add checking to make sure diff --git a/gcc/config.gcc b/gcc/config.gcc index 9c040c19c69..864fa7ce25a 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2127,7 +2127,7 @@ s390x-ibm-tpf*) score-*-elf) tm_file="dbxelf.h elfos.h score/elf.h score/score.h" tmake_file=score/t-score-elf - extra_objs="score-mdaux.o" + extra_objs="score7.o score3.o" ;; sh-*-elf* | sh[12346l]*-*-elf* | sh*-*-kaos* | \ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ diff --git a/gcc/config/score/crti.asm b/gcc/config/score/crti.asm index 88b9526f0e2..b1d3a2ba98b 100644 --- a/gcc/config/score/crti.asm +++ b/gcc/config/score/crti.asm @@ -34,6 +34,7 @@ # This file makes a stack frame for the contents of the .init and # .fini sections. +.extern _stack #ifndef __pic__ .section .init, "ax", @progbits @@ -88,9 +89,13 @@ _fini: .weak _start .ent _start .frame r0, 0, r3, 0 - .mask 0x00000000,0 + .mask 0x00000000, 0 _start: - la r28, _gp + mv r29, r3 + bl 0f +0: + .cpload r3 + mv r3, r29 la r8, __bss_start la r9, __bss_end__ sub! r9, r8 @@ -102,22 +107,23 @@ _start: sw r9, [r8]+, 4 bcnz 1b la r0, _stack - ldiu! r4, 0 - ldiu! r5, 0 - la r29, main + bl _init + la r4, _end + la r29, _init_argv brl r29 la r29, exit brl r29 .end _start .weak _init_argv - .ent + .ent _init_argv .frame r0, 0, r3, 0 .mask 0x00000000, 0 _init_argv: ldiu! r4, 0 ldiu! r5, 0 - j main + la r29, main + brl r29 .end _init_argv .globl _init @@ -126,7 +132,7 @@ _init: addi r0, -32 sw r3, [r0, 20] -.section .fini, "ax", @progbits + .section .fini, "ax", @progbits .globl _fini .type _fini, %function _fini: @@ -134,5 +140,3 @@ _fini: sw r3, [r0, 20] #endif - - diff --git a/gcc/config/score/elf.h b/gcc/config/score/elf.h index 6bc57c1bd9b..d04373ecd85 100644 --- a/gcc/config/score/elf.h +++ b/gcc/config/score/elf.h @@ -32,16 +32,16 @@ #define TYPE_OPERAND_FMT "@%s" #undef TYPE_ASM_OP -#define TYPE_ASM_OP "\t.type\t" +#define TYPE_ASM_OP "\t.type\t" #undef SIZE_ASM_OP -#define SIZE_ASM_OP "\t.size\t" +#define SIZE_ASM_OP "\t.size\t" /* A c expression whose value is a string containing the assembler operation to identify the following data as uninitialized global data. */ #ifndef BSS_SECTION_ASM_OP -#define BSS_SECTION_ASM_OP "\t.section\t.bss" +#define BSS_SECTION_ASM_OP "\t.section\t.bss" #endif #ifndef ASM_OUTPUT_ALIGNED_BSS diff --git a/gcc/config/score/mac.md b/gcc/config/score/mac.md deleted file mode 100644 index 0b534958d0e..00000000000 --- a/gcc/config/score/mac.md +++ /dev/null @@ -1,180 +0,0 @@ -;; Machine description for Sunplus S+CORE -;; 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 -;; . - -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. - -(define_insn "smaxsi3" - [(set (match_operand:SI 0 "register_operand" "=d") - (smax:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")))] - "TARGET_MAC || TARGET_SCORE7D" - "max %0, %1, %2" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "sminsi3" - [(set (match_operand:SI 0 "register_operand" "=d") - (smin:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")))] - "TARGET_MAC || TARGET_SCORE7D" - "min %0, %1, %2" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "abssi2" - [(set (match_operand:SI 0 "register_operand" "=d") - (abs:SI (match_operand:SI 1 "register_operand" "d")))] - "TARGET_MAC || TARGET_SCORE7D" - "abs %0, %1" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "clzsi2" - [(set (match_operand:SI 0 "register_operand" "=d") - (clz:SI (match_operand:SI 1 "register_operand" "d")))] - "TARGET_MAC || TARGET_SCORE7D" - "clz %0, %1" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "sffs" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:SI 1 "register_operand" "d")] SFFS))] - "TARGET_MAC || TARGET_SCORE7D" - "bitrev %0, %1, r0\;clz %0, %0\;addi %0, 0x1" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_expand "ffssi2" - [(set (match_operand:SI 0 "register_operand") - (ffs:SI (match_operand:SI 1 "register_operand")))] - "TARGET_MAC || TARGET_SCORE7D" -{ - emit_insn (gen_sffs (operands[0], operands[1])); - emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CC_NZmode, CC_REGNUM), - gen_rtx_COMPARE (CC_NZmode, operands[0], - GEN_INT (33)))); - emit_insn (gen_movsicc_internal (operands[0], - gen_rtx_fmt_ee (EQ, VOIDmode, operands[0], GEN_INT (33)), - GEN_INT (0), - operands[0])); - DONE; -}) - -(define_peephole2 - [(set (match_operand:SI 0 "loreg_operand" "") - (match_operand:SI 1 "register_operand" "")) - (set (match_operand:SI 2 "hireg_operand" "") - (match_operand:SI 3 "register_operand" ""))] - "TARGET_MAC || TARGET_SCORE7D" - [(parallel - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 2) (match_dup 3))])]) - -(define_peephole2 - [(set (match_operand:SI 0 "hireg_operand" "") - (match_operand:SI 1 "register_operand" "")) - (set (match_operand:SI 2 "loreg_operand" "") - (match_operand:SI 3 "register_operand" ""))] - "TARGET_MAC || TARGET_SCORE7D" - [(parallel - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (match_dup 1))])]) - -(define_insn "movtohilo" - [(parallel - [(set (match_operand:SI 0 "loreg_operand" "=l") - (match_operand:SI 1 "register_operand" "d")) - (set (match_operand:SI 2 "hireg_operand" "=h") - (match_operand:SI 3 "register_operand" "d"))])] - "TARGET_MAC || TARGET_SCORE7D" - "mtcehl %3, %1" - [(set_attr "type" "fce") - (set_attr "mode" "SI")]) - -(define_insn "mulsi3addsi" - [(set (match_operand:SI 0 "register_operand" "=l,l,d") - (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") - (match_operand:SI 3 "register_operand" "d,d,d")) - (match_operand:SI 1 "register_operand" "0,d,l"))) - (clobber (reg:SI HI_REGNUM))] - "TARGET_MAC || TARGET_SCORE7D" - "@ - mad %2, %3 - mtcel%S1 %1\;mad %2, %3 - mad %2, %3\;mfcel%S0 %0" - [(set_attr "mode" "SI")]) - -(define_insn "mulsi3subsi" - [(set (match_operand:SI 0 "register_operand" "=l,l,d") - (minus:SI (match_operand:SI 1 "register_operand" "0,d,l") - (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") - (match_operand:SI 3 "register_operand" "d,d,d")))) - (clobber (reg:SI HI_REGNUM))] - "TARGET_MAC || TARGET_SCORE7D" - "@ - msb %2, %3 - mtcel%S1 %1\;msb %2, %3 - msb %2, %3\;mfcel%S0 %0" - [(set_attr "mode" "SI")]) - -(define_insn "mulsidi3adddi" - [(set (match_operand:DI 0 "register_operand" "=x") - (plus:DI (mult:DI - (sign_extend:DI (match_operand:SI 2 "register_operand" "%d")) - (sign_extend:DI (match_operand:SI 3 "register_operand" "d"))) - (match_operand:DI 1 "register_operand" "0")))] - "TARGET_MAC || TARGET_SCORE7D" - "mad %2, %3" - [(set_attr "mode" "DI")]) - -(define_insn "umulsidi3adddi" - [(set (match_operand:DI 0 "register_operand" "=x") - (plus:DI (mult:DI - (zero_extend:DI (match_operand:SI 2 "register_operand" "%d")) - (zero_extend:DI (match_operand:SI 3 "register_operand" "d"))) - (match_operand:DI 1 "register_operand" "0")))] - "TARGET_MAC || TARGET_SCORE7D" - "madu %2, %3" - [(set_attr "mode" "DI")]) - -(define_insn "mulsidi3subdi" - [(set (match_operand:DI 0 "register_operand" "=x") - (minus:DI - (match_operand:DI 1 "register_operand" "0") - (mult:DI - (sign_extend:DI (match_operand:SI 2 "register_operand" "%d")) - (sign_extend:DI (match_operand:SI 3 "register_operand" "d")))))] - "TARGET_MAC || TARGET_SCORE7D" - "msb %2, %3" - [(set_attr "mode" "DI")]) - -(define_insn "umulsidi3subdi" - [(set (match_operand:DI 0 "register_operand" "=x") - (minus:DI - (match_operand:DI 1 "register_operand" "0") - (mult:DI (zero_extend:DI - (match_operand:SI 2 "register_operand" "%d")) - (zero_extend:DI - (match_operand:SI 3 "register_operand" "d")))))] - "TARGET_MAC || TARGET_SCORE7D" - "msbu %2, %3" - [(set_attr "mode" "DI")]) diff --git a/gcc/config/score/misc.md b/gcc/config/score/misc.md deleted file mode 100644 index c9b293d244c..00000000000 --- a/gcc/config/score/misc.md +++ /dev/null @@ -1,381 +0,0 @@ -;; Machine description for Sunplus S+CORE -;; 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 -;; . - -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. - -(define_insn "pushsi" - [(set (match_operand:SI 0 "push_operand" "=<") - (match_operand:SI 1 "register_operand" "d"))] - "" - "push! %1, [r0]" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "popsi" - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:SI 1 "pop_operand" ">"))] - "" - "pop! %0, [r0]" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_peephole2 - [(set (match_operand:SI 0 "g32reg_operand" "") - (match_operand:SI 1 "loreg_operand" "")) - (set (match_operand:SI 2 "g32reg_operand" "") - (match_operand:SI 3 "hireg_operand" ""))] - "" - [(parallel - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 2) (match_dup 3))])]) - -(define_peephole2 - [(set (match_operand:SI 0 "g32reg_operand" "") - (match_operand:SI 1 "hireg_operand" "")) - (set (match_operand:SI 2 "g32reg_operand" "") - (match_operand:SI 3 "loreg_operand" ""))] - "" - [(parallel - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (match_dup 1))])]) - -(define_insn "movhilo" - [(parallel - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:SI 1 "loreg_operand" "")) - (set (match_operand:SI 2 "register_operand" "=d") - (match_operand:SI 3 "hireg_operand" ""))])] - "" - "mfcehl %2, %0" - [(set_attr "type" "fce") - (set_attr "mode" "SI")]) - -(define_expand "movsicc" - [(set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (match_operator 1 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "register_operand" "")))] - "" -{ - mdx_movsicc (operands); -}) - -(define_insn "movsicc_internal" - [(set (match_operand:SI 0 "register_operand" "=d") - (if_then_else:SI (match_operator 1 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (match_operand:SI 2 "arith_operand" "d") - (match_operand:SI 3 "arith_operand" "0")))] - "" - "mv%C1 %0, %2" - [(set_attr "type" "cndmv") - (set_attr "mode" "SI")]) - -(define_insn "zero_extract_bittst" - [(set (reg:CC_NZ CC_REGNUM) - (compare:CC_NZ (unspec:SI - [(match_operand:SI 0 "register_operand" "*e,d") - (match_operand:SI 1 "const_uimm5" "")] - BITTST) - (const_int 0)))] - "" - "@ - bittst! %0, %c1 - bittst.c %0, %c1" - [(set_attr "type" "arith") - (set_attr "up_c" "yes") - (set_attr "mode" "SI")]) - -(define_expand "extzv" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extract (match_operand:SI 1 "memory_operand" "") - (match_operand:SI 2 "immediate_operand" "") - (match_operand:SI 3 "immediate_operand" "")))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" -{ - if (mdx_unaligned_load (operands)) - DONE; - else - FAIL; -}) - -(define_expand "insv" - [(set (zero_extract (match_operand:SI 0 "memory_operand" "") - (match_operand:SI 1 "immediate_operand" "") - (match_operand:SI 2 "immediate_operand" "")) - (match_operand:SI 3 "register_operand" ""))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" -{ - if (mdx_unaligned_store (operands)) - DONE; - else - FAIL; -}) - -(define_expand "extv" - [(set (match_operand:SI 0 "register_operand" "") - (sign_extract (match_operand:SI 1 "memory_operand" "") - (match_operand:SI 2 "immediate_operand" "") - (match_operand:SI 3 "immediate_operand" "")))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" -{ - if (mdx_unaligned_load (operands)) - DONE; - else - FAIL; -}) - -(define_expand "movmemsi" - [(parallel [(set (match_operand:BLK 0 "general_operand") - (match_operand:BLK 1 "general_operand")) - (use (match_operand:SI 2 "")) - (use (match_operand:SI 3 "const_int_operand"))])] - "!TARGET_SCORE5U && TARGET_ULS" -{ - if (mdx_block_move (operands)) - DONE; - else - FAIL; -}) - -(define_insn "move_lbu_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:QI 3 "register_operand" "=d") - (mem:QI (match_dup 1)))] - "" - "lbu %3, [%1]+, %2" - [(set_attr "type" "load") - (set_attr "mode" "QI")]) - -(define_insn "move_lhu_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:HI 3 "register_operand" "=d") - (mem:HI (match_dup 1)))] - "" - "lhu %3, [%1]+, %2" - [(set_attr "type" "load") - (set_attr "mode" "HI")]) - -(define_insn "move_lw_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:SI 3 "register_operand" "=d") - (mem:SI (match_dup 1)))] - "" - "lw %3, [%1]+, %2" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -(define_insn "move_sb_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:QI (match_dup 1)) - (match_operand:QI 3 "register_operand" "d"))] - "" - "sb %3, [%1]+, %2" - [(set_attr "type" "store") - (set_attr "mode" "QI")]) - -(define_insn "move_sh_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:HI (match_dup 1)) - (match_operand:HI 3 "register_operand" "d"))] - "" - "sh %3, [%1]+, %2" - [(set_attr "type" "store") - (set_attr "mode" "HI")]) - -(define_insn "move_sw_a" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:SI (match_dup 1)) - (match_operand:SI 3 "register_operand" "d"))] - "" - "sw %3, [%1]+, %2" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "move_lbu_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:QI 3 "register_operand" "=d") - (mem:QI (plus:SI (match_dup 1) - (match_dup 2))))] - "" - "lbu %3, [%1, %2]+" - [(set_attr "type" "load") - (set_attr "mode" "QI")]) - -(define_insn "move_lhu_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:HI 3 "register_operand" "=d") - (mem:HI (plus:SI (match_dup 1) - (match_dup 2))))] - "" - "lhu %3, [%1, %2]+" - [(set_attr "type" "load") - (set_attr "mode" "HI")]) - -(define_insn "move_lw_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (match_operand:SI 3 "register_operand" "=d") - (mem:SI (plus:SI (match_dup 1) - (match_dup 2))))] - "" - "lw %3, [%1, %2]+" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -(define_insn "move_sb_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:QI (plus:SI (match_dup 1) - (match_dup 2))) - (match_operand:QI 3 "register_operand" "d"))] - "" - "sb %3, [%1, %2]+" - [(set_attr "type" "store") - (set_attr "mode" "QI")]) - -(define_insn "move_sh_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:HI (plus:SI (match_dup 1) - (match_dup 2))) - (match_operand:HI 3 "register_operand" "d"))] - "" - "sh %3, [%1, %2]+" - [(set_attr "type" "store") - (set_attr "mode" "HI")]) - -(define_insn "move_sw_b" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "const_simm12" ""))) - (set (mem:SI (plus:SI (match_dup 1) - (match_dup 2))) - (match_operand:SI 3 "register_operand" "d"))] - "" - "sw %3, [%1, %2]+" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "move_lcb" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (reg:SI LC_REGNUM) - (unspec:SI [(mem:BLK (match_dup 1))] LCB))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "lcb [%1]+" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -(define_insn "move_lcw" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (match_operand:SI 2 "register_operand" "=d") - (unspec:SI [(mem:BLK (match_dup 1)) - (reg:SI LC_REGNUM)] LCW)) - (set (reg:SI LC_REGNUM) - (unspec:SI [(mem:BLK (match_dup 1))] LCB))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "lcw %2, [%1]+" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -(define_insn "move_lce" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (match_operand:SI 2 "register_operand" "=d") - (unspec:SI [(mem:BLK (match_dup 1)) - (reg:SI LC_REGNUM)] LCE))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "lce %2, [%1]+" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -(define_insn "move_scb" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (mem:BLK (match_dup 1)) - (unspec:BLK [(match_operand:SI 2 "register_operand" "d")] SCB)) - (set (reg:SI SC_REGNUM) - (unspec:SI [(match_dup 2)] SCLC))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "scb %2, [%1]+" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "move_scw" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (mem:BLK (match_dup 1)) - (unspec:BLK [(match_operand:SI 2 "register_operand" "d") - (reg:SI SC_REGNUM)] SCW)) - (set (reg:SI SC_REGNUM) - (unspec:SI [(match_dup 2)] SCLC))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "scw %2, [%1]+" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "move_sce" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (const_int 4))) - (set (mem:BLK (match_dup 1)) - (unspec:BLK [(reg:SI SC_REGNUM)] SCE))] - "!TARGET_SCORE5U && !TARGET_LITTLE_ENDIAN && TARGET_ULS" - "sce [%1]+" - [(set_attr "type" "store") - (set_attr "mode" "SI")]) - -(define_insn "andsi3_extzh" - [(set (match_operand:SI 0 "register_operand" "=d") - (and:SI (match_operand:SI 1 "register_operand" "d") - (const_int 65535)))] - "" - "extzh %0, %1" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - diff --git a/gcc/config/score/mul-div.S b/gcc/config/score/mul-div.S index 4853a0ae132..2015b3b79d9 100644 --- a/gcc/config/score/mul-div.S +++ b/gcc/config/score/mul-div.S @@ -14,8 +14,8 @@ 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 -. */ + along with GCC; see the file COPYING3. If not see + . */ #define ra r3 #define a0 r4 @@ -34,6 +34,10 @@ #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 @@ -70,6 +74,7 @@ _flush_cache: bcnz 2b br r3 #endif +#endif /* FUNCTION (U) INT32 v0 = __mulsi3 ((U) INT32 a0, (U) INT32 a1); @@ -205,6 +210,10 @@ __modsi3: .set pic .text .global _flush_cache +#ifdef __score3__ +_flush_cache: + br r3 +#else _flush_cache: addi r0, -8 # pic used .cpload r29 # pic used @@ -245,6 +254,7 @@ _flush_cache: addi r0, 8 # pic used br r3 #endif +#endif /* FUNCTION (U) INT32 v0 = __mulsi3 ((U) INT32 a0, (U) INT32 a1); @@ -345,7 +355,6 @@ __umodsi3: .cpload r29 # pic used li t1, 0 mv t3, ra -# jl __udivsi3 la r29, __udivsi3 brl r29 mv r4, a1 @@ -374,7 +383,6 @@ __divsi3: .cpload r29 # pic used mv t3, ra xor t2, a0, a1 -# jl __orgsi3 la r29, __orgsi3 brl r29 __divsi3_adjust: @@ -394,7 +402,6 @@ __modsi3: .cpload r29 # pic used mv t3, ra mv t2, a0 -# jl __orgsi3 la r29, __orgsi3 brl r29 mv r4, a1 diff --git a/gcc/config/score/predicates.md b/gcc/config/score/predicates.md index f0195e91f96..bd80df59bf8 100644 --- a/gcc/config/score/predicates.md +++ b/gcc/config/score/predicates.md @@ -17,16 +17,44 @@ ;; along with GCC; see the file COPYING3. If not see ;; . +(define_predicate "const_uimm5" + (match_code "const_int") +{ + return IMM_IN_RANGE (INTVAL (op), 5, 0); +}) + +(define_predicate "const_simm12" + (match_code "const_int") +{ + return IMM_IN_RANGE (INTVAL (op), 12, 1); +}) + +(define_predicate "const_simm15" + (match_code "const_int") +{ + return IMM_IN_RANGE (INTVAL (op), 15, 1); +}) + (define_predicate "arith_operand" (ior (match_code "const_int") (match_operand 0 "register_operand"))) +(define_predicate "score_register_operand" + (match_code "reg,subreg") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + return (GET_CODE (op) == REG) + && (REGNO (op) != CC_REGNUM); +}) + (define_predicate "const_call_insn_operand" (match_code "const,symbol_ref,label_ref") { enum score_symbol_type symbol_type; - return (mda_symbolic_constant_p (op, &symbol_type) + return (score_symbolic_constant_p (op, &symbol_type) && (symbol_type == SYMBOL_GENERAL)); }) @@ -34,12 +62,6 @@ (ior (match_operand 0 "const_call_insn_operand") (match_operand 0 "register_operand"))) -(define_predicate "const_uimm5" - (match_code "const_int") -{ - return IMM_IN_RANGE (INTVAL (op), 5, 0); -}) - (define_predicate "hireg_operand" (and (match_code "reg") (match_test "REGNO (op) == HI_REGNUM"))) @@ -62,15 +84,73 @@ (define_predicate "branch_nz_operator" (match_code "eq,ne,lt,ge")) -(define_predicate "const_simm12" - (match_code "const_int") +(define_predicate "score_load_multiple_operation" + (match_code "parallel") { - return IMM_IN_RANGE (INTVAL (op), 12, 1); + int count = XVECLEN (op, 0); + int dest_regno; + rtx src_addr; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG + || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM) + return 0; + + dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); + src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0); + + for (i = 1; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != SImode + || REGNO (SET_DEST (elt)) != (unsigned) (dest_regno + i) + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode + || GET_CODE (XEXP (SET_SRC (elt), 0)) != POST_INC) + return 0; + } + + return 1; }) -(define_predicate "const_simm15" - (match_code "const_int") +(define_predicate "score_store_multiple_operation" + (match_code "parallel") { - return IMM_IN_RANGE (INTVAL (op), 15, 1); + int count = XVECLEN (op, 0); + int src_regno; + rtx dest_addr; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM + || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG) + return 0; + + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); + dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0); + + for (i = 1; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != (unsigned) (src_regno + i) + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode + || GET_CODE (XEXP (SET_DEST (elt), 0)) != PRE_DEC) + return 0; + } + + return 1; }) diff --git a/gcc/config/score/score-conv.h b/gcc/config/score/score-conv.h index 2ac239365e2..67855da895e 100644 --- a/gcc/config/score/score-conv.h +++ b/gcc/config/score/score-conv.h @@ -17,11 +17,16 @@ along with GCC; see the file COPYING3. If not see . */ -#ifndef SCORE_CONV_0601 -#define SCORE_CONV_0601 +#ifndef GCC_SCORE_CONV_H +#define GCC_SCORE_CONV_H extern int target_flags; +/* Define the information needed to generate branch insns. This is + stored from the compare operation. */ +extern GTY(()) rtx cmp_op0; +extern GTY(()) rtx cmp_op1; + #define GP_REG_FIRST 0U #define GP_REG_LAST 31U #define GP_REG_NUM (GP_REG_LAST - GP_REG_FIRST + 1U) @@ -40,47 +45,38 @@ extern int target_flags; #define GP_REG_P(REGNO) REG_CONTAIN (REGNO, GP_REG_FIRST, GP_REG_NUM) +#define G8_REG_P(REGNO) REG_CONTAIN (REGNO, GP_REG_FIRST, 8) + #define G16_REG_P(REGNO) REG_CONTAIN (REGNO, GP_REG_FIRST, 16) #define CE_REG_P(REGNO) REG_CONTAIN (REGNO, CE_REG_FIRST, CE_REG_NUM) -#define UIMM_IN_RANGE(V, W) ((V) >= 0 && (V) < ((HOST_WIDE_INT) 1 << (W))) +#define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS) +#define SP_REG_CLASS_P(C) \ + ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS) +#define CP_REG_CLASS_P(C) \ + ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS) +#define CE_REG_CLASS_P(C) \ + ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS) + +#define UIMM_IN_RANGE(V, W) ((V) >= 0 && (V) < ((HOST_WIDE_INT) 1 << (W))) #define SIMM_IN_RANGE(V, W) \ ((V) >= (-1 * ((HOST_WIDE_INT) 1 << ((W) - 1))) \ && (V) < (1 * ((HOST_WIDE_INT) 1 << ((W) - 1)))) -#define IMM_IN_RANGE(V, W, S) \ +#define IMM_IN_RANGE(V, W, S) \ ((S) ? SIMM_IN_RANGE (V, W) : UIMM_IN_RANGE (V, W)) -#define IMM_IS_POW_OF_2(V, E1, E2) \ +#define IMM_IS_POW_OF_2(V, E1, E2) \ ((V) >= ((unsigned HOST_WIDE_INT) 1 << (E1)) \ && (V) <= ((unsigned HOST_WIDE_INT) 1 << (E2)) \ && ((V) & ((V) - 1)) == 0) -#define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3) - -#define SCORE_MAX_FIRST_STACK_STEP (0x3ff0) - -#define SCORE_SDATA_MAX score_sdata_max () - -#define DEFAULT_SDATA_MAX 8 - -#define CONST_HIGH_PART(VALUE) \ - (((VALUE) + 0x8000) & ~(unsigned HOST_WIDE_INT) 0xffff) - -#define CONST_LOW_PART(VALUE) ((VALUE) - CONST_HIGH_PART (VALUE)) - -#define PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) - -#define EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) - enum score_symbol_type { SYMBOL_GENERAL, - SYMBOL_SMALL_DATA /* The symbol refers to something in a small data section. */ + SYMBOL_SMALL_DATA /* The symbol refers to something in a small data section */ }; -int score_sdata_max (void); - #endif diff --git a/gcc/config/score/score-generic.md b/gcc/config/score/score-generic.md new file mode 100644 index 00000000000..f3341c5a376 --- /dev/null +++ b/gcc/config/score/score-generic.md @@ -0,0 +1,45 @@ +;; Machine description for Sunplus S+CORE +;; Sunplus S+CORE Pipeline Description +;; 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 +;; . + +(define_automaton "score") + +(define_cpu_unit "core" "score") + +(define_insn_reservation "memory" 3 + (eq_attr "type" "load") + "core") + +(define_insn_reservation "mul" 3 + (eq_attr "type" "mul,div") + "core") + +(define_insn_reservation "fce" 1 + (eq_attr "type" "fce") + "core") + +(define_insn_reservation "tsr" 1 + (eq_attr "type" "tsr,fsr") + "core") + +(define_insn_reservation "up_c" 1 + (eq_attr "up_c" "yes") + "core") diff --git a/gcc/config/score/score-mdaux.c b/gcc/config/score/score-mdaux.c deleted file mode 100644 index 7eb51530a6b..00000000000 --- a/gcc/config/score/score-mdaux.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* score-mdaux.c for Sunplus S+CORE processor - Copyright (C) 2005, 2006, 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 - . */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include -#include "rtl.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "real.h" -#include "insn-config.h" -#include "conditions.h" -#include "insn-attr.h" -#include "recog.h" -#include "toplev.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 "score-mdaux.h" - -#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) -#define INS_BUF_SZ 100 - -/* Define the information needed to generate branch insns. This is - stored from the compare operation. */ -rtx cmp_op0, cmp_op1; - -static char 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 -score_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 -score_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 score_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)) <= SCORE_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 -score_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 -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); -} - -struct score_frame_info * -mda_cached_frame (void) -{ - static struct score_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. */ -struct score_frame_info * -mda_compute_frame_size (HOST_WIDE_INT size) -{ - unsigned int regno; - struct score_frame_info *f = mda_cached_frame (); - - memset (f, 0, sizeof (struct score_frame_info)); - f->gp_reg_size = 0; - f->mask = 0; - f->var_size = SCORE_STACK_ALIGN (size); - f->args_size = current_function_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 && current_function_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 (score_save_reg_p (regno)) - { - f->gp_reg_size += GET_MODE_SIZE (SImode); - f->mask |= 1 << (regno - GP_REG_FIRST); - } - } - - if (current_function_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; -} - -/* Generate the prologue instructions for entry into a S+core function. */ -void -mdx_prologue (void) -{ -#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1 - - struct score_frame_info *f = mda_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 ()); - - for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--) - { - if (BITSET_P (f->mask, regno - GP_REG_FIRST)) - { - rtx mem = gen_rtx_MEM (SImode, - gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); - rtx reg = gen_rtx_REG (SImode, regno); - if (!current_function_calls_eh_return) - MEM_READONLY_P (mem) = 1; - EMIT_PL (emit_insn (gen_pushsi (mem, reg))); - } - } - - 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, PROLOGUE_TEMP_REGNUM), - GEN_INT (size))); - EMIT_PL (emit_insn - (gen_sub3_insn (stack_pointer_rtx, - stack_pointer_rtx, - gen_rtx_REG (Pmode, - 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 (GEN_INT (size - f->cprestore_size))); - else - emit_insn (gen_cprestore_use_sp (GEN_INT (size - f->cprestore_size))); - } - -#undef EMIT_PL -} - -/* Generate the epilogue instructions in a S+core function. */ -void -mdx_epilogue (int sibcall_p) -{ - struct score_frame_info *f = mda_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, EPILOGUE_TEMP_REGNUM), - GEN_INT (size)); - emit_insn (gen_add3_insn (base, base, - gen_rtx_REG (Pmode, - EPILOGUE_TEMP_REGNUM))); - } - } - - if (base != stack_pointer_rtx) - emit_move_insn (stack_pointer_rtx, base); - - if (current_function_calls_eh_return) - emit_insn (gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - EH_RETURN_STACKADJ_RTX)); - - for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++) - { - if (BITSET_P (f->mask, regno - GP_REG_FIRST)) - { - rtx mem = gen_rtx_MEM (SImode, - gen_rtx_POST_INC (SImode, stack_pointer_rtx)); - rtx reg = gen_rtx_REG (SImode, regno); - - if (!current_function_calls_eh_return) - MEM_READONLY_P (mem) = 1; - - emit_insn (gen_popsi (reg, mem)); - } - } - - if (!sibcall_p) - emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, RA_REGNUM))); -} - -/* Return true if X is a valid base register for the given mode. - Allow only hard registers if STRICT. */ -int -mda_valid_base_register_p (rtx x, int strict) -{ - if (!strict && GET_CODE (x) == SUBREG) - x = SUBREG_REG (x); - - return (GET_CODE (x) == REG - && score_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. */ -int -mda_classify_address (struct score_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 = ADD_REG; - info->reg = x; - info->offset = const0_rtx; - return mda_valid_base_register_p (info->reg, strict); - case PLUS: - info->type = ADD_REG; - info->reg = XEXP (x, 0); - info->offset = XEXP (x, 1); - return (mda_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 = ADD_REG; - info->reg = XEXP (x, 0); - info->offset = GEN_INT (GET_MODE_SIZE (mode)); - return mda_valid_base_register_p (info->reg, strict); - case CONST_INT: - info->type = ADD_CONST_INT; - return IMM_IN_RANGE (INTVAL (x), 15, 1); - case CONST: - case LABEL_REF: - case SYMBOL_REF: - info->type = ADD_SYMBOLIC; - return (mda_symbolic_constant_p (x, &info->symbol_type) - && (info->symbol_type == SYMBOL_GENERAL - || info->symbol_type == SYMBOL_SMALL_DATA)); - default: - return 0; - } -} - -void -mda_gen_cmp (enum machine_mode mode) -{ - emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), - gen_rtx_COMPARE (mode, cmp_op0, cmp_op1))); -} - -/* 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 -mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) -{ - HOST_WIDE_INT offset; - - score_split_const (x, &x, &offset); - if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) - *symbol_type = score_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 score_offset_within_object_p (x, offset); - } - gcc_unreachable (); -} - -void -mdx_movsicc (rtx *ops) -{ - enum machine_mode mode; - - mode = score_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, cmp_op0, cmp_op1))); -} - -/* Call and sibcall pattern all need call this function. */ -void -mdx_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 (addr, ops[1])); - else - emit_call_insn (gen_call_internal (addr, ops[1])); -} - -/* Call value and sibcall value pattern all need call this function. */ -void -mdx_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 (result, addr, arg)); - else - emit_call_insn (gen_call_value_internal (result, addr, arg)); -} - -/* Machine Split */ -void -mds_movdi (rtx *ops) -{ - rtx dst = ops[0]; - rtx src = ops[1]; - rtx dst0 = subw (dst, 0); - rtx dst1 = subw (dst, 1); - rtx src0 = subw (src, 0); - rtx src1 = 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 -mds_zero_extract_andi (rtx *ops) -{ - if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode)) - emit_insn (gen_zero_extract_bittst (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 (ops[3], ops[0], - gen_int_mode (mask, SImode))); - } -} - -/* Check addr could be present as PRE/POST mode. */ -static bool -mda_pindex_mem (rtx addr) -{ - if (GET_CODE (addr) == MEM) - { - switch (GET_CODE (XEXP (addr, 0))) - { - case PRE_DEC: - case POST_DEC: - case PRE_INC: - case POST_INC: - return true; - default: - break; - } - } - return false; -} - -/* Output asm code for ld/sw insn. */ -static int -pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum mda_mem_unit unit) -{ - struct score_address_info ai; - - gcc_assert (GET_CODE (ops[idata]) == REG); - gcc_assert (mda_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true)); - - if (!mda_pindex_mem (ops[iaddr]) - && ai.type == ADD_REG - && GET_CODE (ai.offset) == CONST_INT - && G16_REG_P (REGNO (ops[idata])) - && G16_REG_P (REGNO (ai.reg))) - { - if (INTVAL (ai.offset) == 0) - { - ops[iaddr] = ai.reg; - return snprintf (ip, INS_BUF_SZ, - "! %%%d, [%%%d]", idata, iaddr); - } - if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM) - { - HOST_WIDE_INT offset = INTVAL (ai.offset); - if (MDA_ALIGN_UNIT (offset, unit) - && CONST_OK_FOR_LETTER_P (offset >> unit, 'J')) - { - ops[iaddr] = ai.offset; - return snprintf (ip, INS_BUF_SZ, - "p! %%%d, %%c%d", idata, iaddr); - } - } - } - return snprintf (ip, INS_BUF_SZ, " %%%d, %%a%d", idata, iaddr); -} - -/* Output asm insn for load. */ -const char * -mdp_linsn (rtx *ops, enum mda_mem_unit unit, bool sign) -{ - const char *pre_ins[] = - {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"}; - char *ip; - - strcpy (ins, pre_ins[(sign ? 4 : 0) + unit]); - ip = ins + strlen (ins); - - if ((!sign && unit != MDA_HWORD) - || (sign && unit != MDA_BYTE)) - pr_addr_post (ops, 0, 1, ip, unit); - else - snprintf (ip, INS_BUF_SZ, " %%0, %%a1"); - - return ins; -} - -/* Output asm insn for store. */ -const char * -mdp_sinsn (rtx *ops, enum mda_mem_unit unit) -{ - const char *pre_ins[] = {"sb", "sh", "sw"}; - char *ip; - - strcpy (ins, pre_ins[unit]); - ip = ins + strlen (ins); - pr_addr_post (ops, 1, 0, ip, unit); - return ins; -} - -/* Output asm insn for load immediate. */ -const char * -mdp_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, 8, 0)) - return "ldiu! %0, %c1"; - else if (IMM_IN_RANGE (v, 16, 1)) - return "ldi %0, %c1"; - else if ((v & 0xffff) == 0) - return "ldis %0, %U1"; - else - return "li %0, %c1"; -} - -/* Output asm insn for move. */ -const char * -mdp_move (rtx *ops) -{ - gcc_assert (GET_CODE (ops[0]) == REG); - gcc_assert (GET_CODE (ops[1]) == REG); - - if (G16_REG_P (REGNO (ops[0]))) - { - if (G16_REG_P (REGNO (ops[1]))) - return "mv! %0, %1"; - else - return "mlfh! %0, %1"; - } - else if (G16_REG_P (REGNO (ops[1]))) - return "mhfl! %0, %1"; - else - return "mv %0, %1"; -} - -/* Emit lcb/lce insns. */ -bool -mdx_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 -mdx_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 -mdx_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 = alloca (sizeof (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 -mdx_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 -mdx_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 = alloca (sizeof (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 -mdx_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) - mdx_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 -mdx_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; - - 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) - { - mdx_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) - mdx_block_move_loop_head (dst_reg, dst_align, - src_reg, src_align, head_length); - - label = gen_label_rtx (); - emit_label (label); - - mdx_block_move_loop_body (dst_reg, dst_align, - src_reg, src_align, loop_mov_bytes); - - emit_insn (gen_cmpsi (dst_reg, final_dst)); - emit_jump_insn (gen_bne (label)); - - mdx_block_move_loop_foot (dst_reg, dst_align, - src_reg, src_align, leftover); -} - -/* Generate block move, for misc.md: "movmemsi". */ -bool -mdx_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) - { - mdx_block_move_straight (dst, src, INTVAL (length)); - return true; - } - else if (optimize && - !(flag_unroll_loops || flag_unroll_all_loops)) - { - mdx_block_move_loop (dst, src, INTVAL (length)); - return true; - } - } - return false; -} - -/* Generate add insn. */ -const char * -mdp_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 && G16_REG_P (REGNO (ops[0]))) - { - if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15)) - { - ops[2] = GEN_INT (ffs (v) - 1); - return "addei! %0, %c2"; - } - - if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15)) - { - ops[2] = GEN_INT (ffs (-v) - 1); - return "subei! %0, %c2"; - } - } - - if (set_cc) - return "addi.c %0, %c2"; - else - return "addi %0, %c2"; -} - -/* Output arith insn. */ -const char * -mdp_select (rtx *ops, const char *inst_pre, - bool commu, const char *letter, bool set_cc) -{ - gcc_assert (GET_CODE (ops[0]) == REG); - gcc_assert (GET_CODE (ops[1]) == REG); - - if (set_cc && G16_REG_P (REGNO (ops[0])) - && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1) - && REGNO (ops[0]) == REGNO (ops[1])) - { - snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s2", inst_pre, letter); - return ins; - } - - if (commu && set_cc && G16_REG_P (REGNO (ops[0])) - && G16_REG_P (REGNO (ops[1])) - && REGNO (ops[0]) == REGNO (ops[2])) - { - gcc_assert (GET_CODE (ops[2]) == REG); - snprintf (ins, INS_BUF_SZ, "%s! %%0, %%%s1", inst_pre, letter); - return ins; - } - - if (set_cc) - snprintf (ins, INS_BUF_SZ, "%s.c %%0, %%1, %%%s2", inst_pre, letter); - else - snprintf (ins, INS_BUF_SZ, "%s %%0, %%1, %%%s2", inst_pre, letter); - return ins; -} - diff --git a/gcc/config/score/score-mdaux.h b/gcc/config/score/score-mdaux.h deleted file mode 100644 index 99a40601305..00000000000 --- a/gcc/config/score/score-mdaux.h +++ /dev/null @@ -1,115 +0,0 @@ -/* score-mdaux.h for Sunplus S+CORE processor - 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 - . */ - -#ifndef SCORE_MDAUX_0621 -#define SCORE_MDAUX_0621 - -/* Machine Auxiliary Functions. */ -enum score_address_type -{ - ADD_REG, - ADD_CONST_INT, - ADD_SYMBOLIC -}; -#ifdef RTX_CODE -struct score_address_info -{ - enum score_address_type type; - rtx reg; - rtx offset; - enum rtx_code code; - enum score_symbol_type symbol_type; -}; -#endif - -struct score_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 */ -}; - -typedef void (*score_save_restore_fn) (rtx, rtx); - -int mda_valid_base_register_p (rtx x, int strict); - -#ifdef RTX_CODE -int mda_classify_address (struct score_address_info *info, - enum machine_mode mode, rtx x, int strict); - -struct score_frame_info *mda_compute_frame_size (HOST_WIDE_INT size); - -struct score_frame_info *mda_cached_frame (void); - -void mda_gen_cmp (enum machine_mode mode); -#endif - -int mda_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type); - -int mda_bp (void); - -/* Machine Expand. */ -void mdx_prologue (void); - -void mdx_epilogue (int sibcall_p); - -void mdx_movsicc (rtx *ops); - -void mdx_call (rtx *ops, bool sibcall); - -void mdx_call_value (rtx *ops, bool sibcall); - -/* Machine Split. */ -void mds_movdi (rtx *ops); - -void mds_zero_extract_andi (rtx *ops); - -/* Machine Print. */ -enum mda_mem_unit {MDA_BYTE = 0, MDA_HWORD = 1, MDA_WORD = 2}; - -#define MDA_ALIGN_UNIT(V, UNIT) !(V & ((1 << UNIT) - 1)) - -const char * mdp_linsn (rtx *ops, enum mda_mem_unit unit, bool sign); - -const char * mdp_sinsn (rtx *ops, enum mda_mem_unit unit); - -const char * mdp_select_add_imm (rtx *ops, bool set_cc); - -const char * mdp_select (rtx *ops, const char *inst_pre, - bool commu, const char *letter, bool set_cc); - -const char * mdp_limm (rtx *ops); - -const char * mdp_move (rtx *ops); - -/* Machine unaligned memory load/store. */ -bool mdx_unaligned_load (rtx* ops); - -bool mdx_unaligned_store (rtx* ops); - -bool mdx_block_move (rtx* ops); - -#endif - diff --git a/gcc/config/score/score-protos.h b/gcc/config/score/score-protos.h index ea99eeafb29..c240d8272dc 100644 --- a/gcc/config/score/score-protos.h +++ b/gcc/config/score/score-protos.h @@ -17,76 +17,80 @@ along with GCC; see the file COPYING3. If not see . */ -#ifndef __SCORE_PROTOS_H__ -#define __SCORE_PROTOS_H__ - -extern enum reg_class score_char_to_class[]; - -void score_override_options (void); - -void score_init_expanders (void); - -int score_hard_regno_mode_ok (unsigned int, enum machine_mode); - -int score_reg_class (int regno); - -enum reg_class score_preferred_reload_class (rtx x, enum reg_class class); - -enum reg_class score_secondary_reload_class (enum reg_class class, - enum machine_mode mode, rtx x); - -int score_const_ok_for_letter_p (HOST_WIDE_INT value, char c); - -int score_extra_constraint (rtx op, char c); - -rtx score_return_addr (int count, rtx frame); - -HOST_WIDE_INT score_initial_elimination_offset (int from, int to); - -rtx score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int named); - -int score_arg_partial_nregs (const CUMULATIVE_ARGS *cum, - enum machine_mode mode, tree type, int named); - -void score_init_cumulative_args (CUMULATIVE_ARGS *cum, - tree fntype, rtx libname); - -void score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int named); - -rtx score_function_value (const_tree valtype, const_tree func, enum machine_mode mode); - -rtx score_va_arg (tree va_list, tree type); - -void score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN); - -int score_address_p (enum machine_mode mode, rtx x, int strict); - -int score_legitimize_address (rtx *xloc); - -int score_regno_mode_ok_for_base_p (int regno, int strict); - -int score_register_move_cost (enum machine_mode mode, enum reg_class to, - enum reg_class from); - -void score_declare_object (FILE *stream, const char *name, - const char *directive, const char *fmt, ...) - ATTRIBUTE_PRINTF_4; - -void score_declare_object_name (FILE *stream, const char *name, tree decl); - -int score_output_external (FILE *file, tree decl, const char *name); - -void score_print_operand (FILE *file, rtx op, int letter); - -void score_print_operand_address (FILE *file, rtx addr); +#ifndef GCC_SCORE_PROTOS_H +#define GCC_SCORE_PROTOS_H + +/* Machine Print. */ +enum score_mem_unit {SCORE_BYTE = 0, SCORE_HWORD = 1, SCORE_WORD = 2}; + +#define SCORE_ALIGN_UNIT(V, UNIT) !(V & ((1 << UNIT) - 1)) + +extern void score_gen_cmp (enum machine_mode mode); +extern void score_prologue (void); +extern void score_epilogue (int sibcall_p); +extern void score_call (rtx *ops, bool sib); +extern void score_call_value (rtx *ops, bool sib); +extern void score_movdi (rtx *ops); +extern void score_zero_extract_andi (rtx *ops); +extern const char * score_linsn (rtx *ops, enum score_mem_unit unit, bool sign); +extern const char * score_sinsn (rtx *ops, enum score_mem_unit unit); +extern const char * score_limm (rtx *ops); +extern const char * score_move (rtx *ops); +extern bool score_unaligned_load (rtx* ops); +extern bool score_unaligned_store (rtx* ops); +extern bool score_block_move (rtx* ops); +extern int score_address_cost (rtx addr); +extern rtx score_function_arg (const CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, int named); +extern int score_address_p (enum machine_mode mode, rtx x, int strict); +extern int score_reg_class (int regno); +extern int score_register_move_cost (enum machine_mode mode, enum reg_class to, + enum reg_class from); +extern int score_hard_regno_mode_ok (unsigned int, enum machine_mode); +extern int score_const_ok_for_letter_p (HOST_WIDE_INT value, char c); +extern int score_extra_constraint (rtx op, char c); +extern rtx score_return_addr (int count, rtx frame); +extern void score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN); +extern int score_regno_mode_ok_for_base_p (int regno, int strict); +extern void score_function_arg_advance (CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, int named); +extern void score_init_cumulative_args (CUMULATIVE_ARGS *cum, + tree fntype, rtx libname); +extern void score_declare_object (FILE *stream, const char *name, + const char *directive, const char *fmt, ...); +extern int score_output_external (FILE *file, tree decl, const char *name); +extern void score_override_options (void); +extern enum reg_class score_secondary_reload_class (enum reg_class class, + enum machine_mode mode, + rtx x); +extern rtx score_function_value (tree valtype, tree func, + enum machine_mode mode); +extern enum reg_class score_preferred_reload_class (rtx x, + enum reg_class class); +extern HOST_WIDE_INT score_initial_elimination_offset (int from, int to); +extern void score_print_operand (FILE *file, rtx op, int letter); +extern void score_print_operand_address (FILE *file, rtx addr); +extern int score_legitimize_address (rtx *xloc); +extern int score_arg_partial_bytes (CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, bool named); +extern int score_symbolic_constant_p (rtx x, + enum score_symbol_type *symbol_type); +extern void score_movsicc (rtx *ops); +extern const char * score_select_add_imm (rtx *ops, bool set_cc); +extern const char * score_select (rtx *ops, const char *inst_pre, bool commu, + const char *letter, bool set_cc); +extern const char * score_output_casesi (rtx *operands); +extern const char * score_rpush (rtx *ops); +extern const char * score_rpop (rtx *ops); +extern bool score_rtx_costs (rtx x, int code, int outer_code, int *total); #ifdef RTX_CODE -enum machine_mode score_select_cc_mode (enum rtx_code op, rtx x, rtx y); +extern enum machine_mode score_select_cc_mode (enum rtx_code op, rtx x, rtx y); #endif -#include "score-mdaux.h" - -#endif /* __SCORE_PROTOS_H__ */ +extern struct extern_list *extern_head; +#endif /* GCC_SCORE_PROTOS_H */ diff --git a/gcc/config/score/score-version.h b/gcc/config/score/score-version.h deleted file mode 100644 index 0a54af16218..00000000000 --- a/gcc/config/score/score-version.h +++ /dev/null @@ -1,20 +0,0 @@ -/* score-version.h for Sunplus S+CORE processor - Copyright (C) 2005, 2007 Free Software Foundation, Inc. - - 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 - . */ - -#define SCORE_GCC_VERSION "1.2" diff --git a/gcc/config/score/score.c b/gcc/config/score/score.c index 6dba9903b7e..56c6c477082 100644 --- a/gcc/config/score/score.c +++ b/gcc/config/score/score.c @@ -22,7 +22,6 @@ #include "system.h" #include "coretypes.h" #include "tm.h" -#include #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" @@ -48,69 +47,52 @@ #include "target-def.h" #include "integrate.h" #include "langhooks.h" -#include "cfglayout.h" -#include "score-mdaux.h" - -#define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS) -#define SP_REG_CLASS_P(C) \ - ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS) -#define CP_REG_CLASS_P(C) \ - ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS) -#define CE_REG_CLASS_P(C) \ - ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS) - -static int score_arg_partial_bytes (CUMULATIVE_ARGS *, - enum machine_mode, tree, bool); - -static int score_symbol_insns (enum score_symbol_type); - -static int score_address_insns (rtx, enum machine_mode); - -static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *); - -static int score_address_cost (rtx); +#include "score7.h" +#include "score3.h" #undef TARGET_ASM_FILE_START -#define TARGET_ASM_FILE_START th_asm_file_start +#define TARGET_ASM_FILE_START score_asm_file_start #undef TARGET_ASM_FILE_END -#define TARGET_ASM_FILE_END th_asm_file_end +#define TARGET_ASM_FILE_END score_asm_file_end #undef TARGET_ASM_FUNCTION_PROLOGUE -#define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue +#define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue #undef TARGET_ASM_FUNCTION_EPILOGUE -#define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue +#define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue + +#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_SCHED_ISSUE_RATE -#define TARGET_SCHED_ISSUE_RATE th_issue_rate +#define TARGET_SCHED_ISSUE_RATE score_issue_rate #undef TARGET_ASM_SELECT_RTX_SECTION -#define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section +#define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section #undef TARGET_IN_SMALL_DATA_P -#define TARGET_IN_SMALL_DATA_P th_in_small_data_p +#define TARGET_IN_SMALL_DATA_P score_in_small_data_p #undef TARGET_FUNCTION_OK_FOR_SIBCALL -#define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall +#define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall #undef TARGET_STRICT_ARGUMENT_NAMING -#define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming +#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true #undef TARGET_ASM_OUTPUT_MI_THUNK -#define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk - -#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK -#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true +#define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk #undef TARGET_PROMOTE_FUNCTION_ARGS -#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true +#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true #undef TARGET_PROMOTE_FUNCTION_RETURN -#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true +#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true #undef TARGET_PROMOTE_PROTOTYPES -#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true +#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true #undef TARGET_MUST_PASS_IN_STACK #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size @@ -130,332 +112,146 @@ static int score_address_cost (rtx); #undef TARGET_ADDRESS_COST #define TARGET_ADDRESS_COST score_address_cost -#undef TARGET_DEFAULT_TARGET_FLAGS -#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT +struct extern_list *extern_head = 0; +rtx cmp_op0, cmp_op1; + +/* default 0 = NO_REGS */ +enum reg_class score_char_to_class[256]; /* Implement TARGET_RETURN_IN_MEMORY. In S+core, small structures are returned in a register. Objects with varying size must still be returned in memory. */ static bool -score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) +score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED) { - return ((TYPE_MODE (type) == BLKmode) - || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD) - || (int_size_in_bytes (type) == -1)); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_return_in_memory (type, fndecl); + else if (TARGET_SCORE3) + return score3_return_in_memory (type, fndecl); + + gcc_unreachable (); } /* Return nonzero when an argument must be passed by reference. */ static bool score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, - enum machine_mode mode, const_tree type, + enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) { /* If we have a variable-sized parameter, we have no choice. */ return targetm.calls.must_pass_in_stack (mode, type); } -/* Return a legitimate address for REG + OFFSET. */ -static rtx -score_add_offset (rtx temp ATTRIBUTE_UNUSED, 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. */ static void -th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, - HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, - tree function) -{ - rtx this, temp1, temp2, 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); - temp2 = gen_rtx_REG (Pmode, 9); - - /* Find out which register contains the "this" pointer. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) - this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); - else - this = gen_rtx_REG (Pmode, ARG_REG_FIRST); - - /* Add DELTA to THIS. */ - 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, this, offset)); - } - - /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ - if (vcall_offset != 0) - { - rtx addr; - - /* Set TEMP1 to *THIS. */ - emit_move_insn (temp1, gen_rtx_MEM (Pmode, this)); - - /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */ - addr = score_add_offset (temp2, temp1, vcall_offset); - - /* Load the offset and add it to THIS. */ - emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); - emit_insn (gen_add3_insn (this, this, temp1)); - } - - /* Jump to the target function. */ - fnaddr = XEXP (DECL_RTL (function), 0); - insn = emit_call_insn (gen_sibcall_internal (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; -} - -/* Implement TARGET_STRICT_ARGUMENT_NAMING. */ -static bool -th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED) +score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, + tree function) { - return true; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_output_mi_thunk (file, thunk_fndecl, delta, + vcall_offset, function); + else if (TARGET_SCORE3) + return score3_output_mi_thunk (file, thunk_fndecl, delta, + vcall_offset, function); + gcc_unreachable (); } /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ static bool -th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl, - ATTRIBUTE_UNUSED tree exp) +score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl, + ATTRIBUTE_UNUSED tree exp) { return true; } -struct score_arg_info -{ - /* The argument's size, in bytes. */ - unsigned int num_bytes; - - /* The number of words passed in registers, rounded up. */ - unsigned int reg_words; - - /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST, - or ARG_REG_NUM if the argument is passed entirely on the stack. */ - unsigned int reg_offset; - - /* The number of words that must be passed on the stack, rounded up. */ - unsigned int stack_words; - - /* The offset from the start of the stack overflow area of the argument's - first stack word. Only meaningful when STACK_WORDS is nonzero. */ - unsigned int stack_offset; -}; - -/* 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 -classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int named, struct score_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. */ static void -th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) +score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { - const char *fnname; - struct score_frame_info *f = mda_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 (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_function_prologue (file, size); + else if (TARGET_SCORE3) + return score3_function_prologue (file, size); - 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)); - } + gcc_unreachable (); } /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ static void -th_function_epilogue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED) +score_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); - } + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_function_epilogue (file, size); + else if (TARGET_SCORE3) + return score3_function_epilogue (file, size); + + gcc_unreachable (); } /* Implement TARGET_SCHED_ISSUE_RATE. */ static int -th_issue_rate (void) +score_issue_rate (void) { return 1; } -/* Returns true if X contains a SYMBOL_REF. */ -static bool -symbolic_expression_p (rtx x) -{ - if (GET_CODE (x) == SYMBOL_REF) - return true; - - if (GET_CODE (x) == CONST) - return symbolic_expression_p (XEXP (x, 0)); - - if (UNARY_P (x)) - return symbolic_expression_p (XEXP (x, 0)); - - if (ARITHMETIC_P (x)) - return (symbolic_expression_p (XEXP (x, 0)) - || symbolic_expression_p (XEXP (x, 1))); - - return false; -} - /* Choose the section to use for the constant rtx expression X that has mode MODE. */ static section * -th_select_rtx_section (enum machine_mode mode, rtx x, - unsigned HOST_WIDE_INT align) +score_select_rtx_section (enum machine_mode mode, rtx x, + unsigned HOST_WIDE_INT align) { - if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX) - return get_named_section (0, ".sdata", 0); - else if (flag_pic && symbolic_expression_p (x)) - return get_named_section (0, ".data.rel.ro", 3); - else - return mergeable_constant_section (mode, align, 0); + if (TARGET_SCORE5 || TARGET_SCORE5U || 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 (); } /* Implement TARGET_IN_SMALL_DATA_P. */ static bool -th_in_small_data_p (const_tree decl) +score_in_small_data_p (tree decl) { - HOST_WIDE_INT size; - - if (TREE_CODE (decl) == STRING_CST - || TREE_CODE (decl) == FUNCTION_DECL) - return false; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_in_small_data_p (decl); + else if (TARGET_SCORE3) + return score3_in_small_data_p (decl); - 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 <= SCORE_SDATA_MAX); + gcc_unreachable (); } /* Implement TARGET_ASM_FILE_START. */ static void -th_asm_file_start (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) + 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); + 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"); @@ -463,104 +259,116 @@ th_asm_file_start (void) /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit .externs for any small-data variables that turned out to be external. */ -struct extern_list *extern_head = 0; - static void -th_asm_file_end (void) +score_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); - } - } - } -} - -static unsigned int sdata_max; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_asm_file_end (); + else if (TARGET_SCORE3) + return score3_asm_file_end (); -int -score_sdata_max (void) -{ - return sdata_max; + gcc_unreachable (); } -/* default 0 = NO_REGS */ -enum reg_class score_char_to_class[256]; +#define MASK_ALL_CPU_BITS \ + (MASK_SCORE5 | MASK_SCORE5U | MASK_SCORE7 | MASK_SCORE7D \ + | MASK_SCORE3 | MASK_SCORE3D) -/* Implement OVERRIDE_OPTIONS macro. */ -void -score_override_options (void) +/* Implement TARGET_HANDLE_OPTION. */ +static bool +score_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) { - flag_pic = false; - if (!flag_pic) - sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX; - else + switch (code) { - sdata_max = 0; - if (g_switch_set && (g_switch_value != 0)) - warning (0, "-fPIC and -G are incompatible"); - } + case OPT_mscore7d: + target_flags &= ~(MASK_ALL_CPU_BITS); + target_flags |= MASK_SCORE7 | MASK_SCORE7D; + return true; - score_char_to_class['d'] = G32_REGS; - score_char_to_class['e'] = G16_REGS; - score_char_to_class['t'] = T32_REGS; + case OPT_mscore3d: + target_flags &= ~(MASK_ALL_CPU_BITS); + target_flags |= MASK_SCORE3 | MASK_SCORE3D; + return true; - score_char_to_class['h'] = HI_REG; - score_char_to_class['l'] = LO_REG; - score_char_to_class['x'] = CE_REGS; + 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) + { + target_flags &= ~(MASK_ALL_CPU_BITS); + target_flags |= MASK_SCORE7; + return true; + } + else if (strcmp (arg, "score7d") == 0) + { + target_flags &= ~(MASK_ALL_CPU_BITS); + 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; - 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; + default: + return true; + } +} - score_char_to_class['c'] = CR_REGS; +/* Implement OVERRIDE_OPTIONS macro. */ +void +score_override_options (void) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_override_options (); + else if (TARGET_SCORE3) + return score3_override_options (); - score_char_to_class['b'] = CP1_REGS; - score_char_to_class['f'] = CP2_REGS; - score_char_to_class['i'] = CP3_REGS; - score_char_to_class['j'] = CPA_REGS; + return score7_override_options (); } /* Implement REGNO_REG_CLASS macro. */ int score_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; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_reg_class (regno); + else if (TARGET_SCORE3) + return score3_reg_class (regno); - return NO_REGS; + gcc_unreachable (); } /* Implement PREFERRED_RELOAD_CLASS macro. */ enum reg_class score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class) { - if (reg_class_subset_p (G16_REGS, class)) - return G16_REGS; - if (reg_class_subset_p (G32_REGS, class)) - return G32_REGS; - return class; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_preferred_reload_class (x, class); + else if (TARGET_SCORE3) + return score3_preferred_reload_class (x, class); + + gcc_unreachable (); } /* Implement SECONDARY_INPUT_RELOAD_CLASS @@ -570,50 +378,36 @@ score_secondary_reload_class (enum reg_class class, 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 (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_secondary_reload_class (class, mode, x); + else if (TARGET_SCORE3) + return score3_secondary_reload_class (class, mode, x); - if (!GR_REG_CLASS_P (class)) - return GP_REG_P (regno) ? NO_REGS : G32_REGS; - return NO_REGS; + gcc_unreachable (); } /* Implement CONST_OK_FOR_LETTER_P macro. */ -/* imm constraints - I imm16 << 16 - J uimm5 - K uimm16 - L simm16 - M uimm14 - N simm14 */ int score_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; - } + 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 (); } /* Implement EXTRA_CONSTRAINT macro. */ -/* Z symbol_ref */ int score_extra_constraint (rtx op, char c) { - switch (c) - { - case 'Z': - return GET_CODE (op) == SYMBOL_REF; - default: - gcc_unreachable (); - } + 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 @@ -621,23 +415,12 @@ score_extra_constraint (rtx op, char c) int score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) { - int size = GET_MODE_SIZE (mode); - enum mode_class class = GET_MODE_CLASS (mode); - - if (class == MODE_CC) - return regno == CC_REGNUM; - else if (regno == FRAME_POINTER_REGNUM - || regno == ARG_POINTER_REGNUM) - return class == MODE_INT; - else if (GP_REG_P (regno)) - /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */ - return !(regno & 1) || (size <= UNITS_PER_WORD); - else if (CE_REG_P (regno)) - return (class == MODE_INT - && ((size <= UNITS_PER_WORD) - || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); - else - return (class == MODE_INT) && (size <= UNITS_PER_WORD); + if (TARGET_SCORE5 || TARGET_SCORE5U || 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 (); } /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame @@ -647,16 +430,12 @@ HOST_WIDE_INT score_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) { - struct score_frame_info *f = mda_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 (); - } + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_initial_elimination_offset (from, to); + else if (TARGET_SCORE3) + return score3_initial_elimination_offset (from, to); + + gcc_unreachable (); } /* Argument support functions. */ @@ -675,22 +454,25 @@ void score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named) { - struct score_arg_info info; - 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++; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_function_arg_advance (cum, mode, type, named); + else if (TARGET_SCORE3) + return score3_function_arg_advance (cum, mode, type, named); + + gcc_unreachable (); } /* Implement TARGET_ARG_PARTIAL_BYTES macro. */ -static int +int score_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool named) { - struct score_arg_info info; - classify_arg (cum, mode, type, named, &info); - return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0; + if (TARGET_SCORE5 || TARGET_SCORE5U || 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 (); } /* Implement FUNCTION_ARG macro. */ @@ -698,120 +480,63 @@ rtx score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named) { - struct score_arg_info info; - - if (mode == VOIDmode || !named) - return 0; - - classify_arg (cum, mode, type, named, &info); - - if (info.reg_offset == ARG_REG_NUM) - return 0; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_function_arg (cum, mode, type, named); + else if (TARGET_SCORE3) + return score3_function_arg (cum, mode, type, named); - 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; - } + gcc_unreachable (); } /* 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 -score_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED, +score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED, enum machine_mode mode) { - if (valtype) - { - int unsignedp; - mode = TYPE_MODE (valtype); - unsignedp = TYPE_UNSIGNED (valtype); - mode = promote_mode (valtype, mode, &unsignedp, 1); - } - return gen_rtx_REG (mode, RT_REGNUM); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_function_value (valtype, func, mode); + else if (TARGET_SCORE3) + return score3_function_value (valtype, func, mode); + + gcc_unreachable (); } /* Implement INITIALIZE_TRAMPOLINE macro. */ void score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN) { -#define FFCACHE "_flush_cache" -#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) - - rtx pfunc, pchain; - - pfunc = plus_constant (ADDR, CODE_SIZE); - pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode)); - - emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC); - emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE), - 0, VOIDmode, 2, - ADDR, Pmode, - GEN_INT (TRAMPOLINE_SIZE), SImode); -#undef FFCACHE -#undef CODE_SIZE + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_initialize_trampoline (ADDR, FUNC, CHAIN); + else if (TARGET_SCORE3) + return score3_initialize_trampoline (ADDR, FUNC, CHAIN); + + gcc_unreachable (); } /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */ int score_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); + if (TARGET_SCORE5 || TARGET_SCORE5U || 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 (); } /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */ int score_address_p (enum machine_mode mode, rtx x, int strict) { - struct score_address_info addr; - - return mda_classify_address (&addr, mode, x, strict); -} + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_address_p (mode, x, strict); + else if (TARGET_SCORE3) + return score3_address_p (mode, x, strict); -/* 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 -score_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 -score_split_symbol (rtx temp, rtx addr) -{ - rtx high = score_force_temporary (temp, - gen_rtx_HIGH (Pmode, copy_rtx (addr))); - return gen_rtx_LO_SUM (Pmode, high, addr); + gcc_unreachable (); } /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can @@ -820,25 +545,12 @@ score_split_symbol (rtx temp, rtx addr) int score_legitimize_address (rtx *xloc) { - enum score_symbol_type symbol_type; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_legitimize_address (xloc); + else if (TARGET_SCORE3) + return score3_legitimize_address (xloc); - if (mda_symbolic_constant_p (*xloc, &symbol_type) - && symbol_type == SYMBOL_GENERAL) - { - *xloc = score_split_symbol (0, *xloc); - return 1; - } - - if (GET_CODE (*xloc) == PLUS - && GET_CODE (XEXP (*xloc, 1)) == CONST_INT) - { - rtx reg = XEXP (*xloc, 0); - if (!mda_valid_base_register_p (reg, 0)) - reg = copy_to_mode_reg (Pmode, reg); - *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1))); - return 1; - } - return 0; + gcc_unreachable (); } /* Return a number assessing the cost of moving a register in class @@ -847,503 +559,633 @@ int score_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; + if (TARGET_SCORE5 || TARGET_SCORE5U || 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 (); } -/* Return the number of instructions needed to load a symbol of the - given type into a register. */ -static int -score_symbol_insns (enum score_symbol_type type) +/* Implement TARGET_RTX_COSTS macro. */ +bool +score_rtx_costs (rtx x, int code, int outer_code, int *total) { - switch (type) - { - case SYMBOL_GENERAL: - return 2; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_rtx_costs (x, code, outer_code, total); + else if (TARGET_SCORE3) + return score3_rtx_costs (x, code, outer_code, total); - case SYMBOL_SMALL_DATA: - return 1; - } + gcc_unreachable (); +} + +/* Implement TARGET_ADDRESS_COST macro. */ +int +score_address_cost (rtx addr) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_address_cost (addr); + else if (TARGET_SCORE3) + return score3_address_cost (addr); 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 -score_address_insns (rtx x, enum machine_mode mode) +/* Implement ASM_OUTPUT_EXTERNAL macro. */ +int +score_output_external (FILE *file ATTRIBUTE_UNUSED, + tree decl, const char *name) { - struct score_address_info addr; - int factor; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_output_external (file, decl, name); + else if (TARGET_SCORE3) + return score3_output_external (file, decl, name); - if (mode == BLKmode) - factor = 1; - else - factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - - if (mda_classify_address (&addr, mode, x, false)) - switch (addr.type) - { - case ADD_REG: - case ADD_CONST_INT: - return factor; - - case ADD_SYMBOLIC: - return factor * score_symbol_insns (addr.symbol_type); - } - return 0; + gcc_unreachable (); } -/* Implement TARGET_RTX_COSTS macro. */ -static bool -score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code, - int *total) +/* Implement RETURN_ADDR_RTX. Note, we do not support moving + back to a previous frame. */ +rtx +score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) { - enum machine_mode mode = GET_MODE (x); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_return_addr (count, frame); + else if (TARGET_SCORE3) + return score3_return_addr (count, frame); - 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; + gcc_unreachable (); +} - case CONST: - case SYMBOL_REF: - case LABEL_REF: - case CONST_DOUBLE: - *total = COSTS_N_INSNS (2); - return true; +/* Implement PRINT_OPERAND macro. */ +void +score_print_operand (FILE *file, rtx op, int c) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_print_operand (file, op, c); + else if (TARGET_SCORE3) + return score3_print_operand (file, op, c); - case MEM: - { - /* If the address is legitimate, return the number of - instructions it needs, otherwise use the default handling. */ - int n = score_address_insns (XEXP (x, 0), GET_MODE (x)); - if (n > 0) - { - *total = COSTS_N_INSNS (n + 1); - return true; - } - return false; - } + gcc_unreachable (); +} - case FFS: - *total = COSTS_N_INSNS (6); - return true; +/* Implement PRINT_OPERAND_ADDRESS macro. */ +void +score_print_operand_address (FILE *file, rtx x) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_print_operand_address (file, x); + else if (TARGET_SCORE3) + return score3_print_operand_address (file, x); - case NOT: - *total = COSTS_N_INSNS (1); - return true; + gcc_unreachable (); +} - case AND: - case IOR: - case XOR: - if (mode == DImode) - { - *total = COSTS_N_INSNS (2); - return true; - } - return false; +/* Implement SELECT_CC_MODE macro. */ +enum machine_mode +score_select_cc_mode (enum rtx_code op, rtx x, rtx y) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_select_cc_mode (op, x, y); + else if (TARGET_SCORE3) + return score3_select_cc_mode (op, x, y); - 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; + gcc_unreachable (); +} - case ABS: - *total = COSTS_N_INSNS (4); - return true; +/* 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 +score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_symbolic_constant_p (x, symbol_type); + else if (TARGET_SCORE3) + return score3_symbolic_constant_p (x, symbol_type); - case PLUS: - case MINUS: - if (mode == DImode) - { - *total = COSTS_N_INSNS (4); - return true; - } - *total = COSTS_N_INSNS (1); - return true; + gcc_unreachable (); +} - case NEG: - if (mode == DImode) - { - *total = COSTS_N_INSNS (4); - return true; - } - return false; +/* Generate the prologue instructions for entry into a S+core function. */ +void +score_prologue (void) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_prologue (); + else if (TARGET_SCORE3) + return score3_prologue (); - case MULT: - *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12); - return true; + gcc_unreachable (); +} - case DIV: - case MOD: - case UDIV: - case UMOD: - *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33); - return true; +/* Generate the epilogue instructions in a S+core function. */ +void +score_epilogue (int sibcall_p) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_epilogue (sibcall_p); + else if (TARGET_SCORE3) + return score3_epilogue (sibcall_p); - 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; + gcc_unreachable (); +} - default: - return false; - } +void +score_gen_cmp (enum machine_mode mode) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_gen_cmp (mode); + else if (TARGET_SCORE3) + return score3_gen_cmp (mode); + + gcc_unreachable (); } -/* Implement TARGET_ADDRESS_COST macro. */ -int -score_address_cost (rtx addr) +/* Call and sibcall pattern all need call this function. */ +void +score_call (rtx *ops, bool sib) { - return score_address_insns (addr, SImode); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_call (ops, sib); + else if (TARGET_SCORE3) + return score3_call (ops, sib); + + gcc_unreachable (); } -/* Implement ASM_OUTPUT_EXTERNAL macro. */ -int -score_output_external (FILE *file ATTRIBUTE_UNUSED, - tree decl, const char *name) +/* Call value and sibcall value pattern all need call this function. */ +void +score_call_value (rtx *ops, bool sib) { - register struct extern_list *p; + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_call_value (ops, sib); + else if (TARGET_SCORE3) + return score3_call_value (ops, sib); - if (th_in_small_data_p (decl)) - { - p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list)); - p->next = extern_head; - p->name = name; - p->size = int_size_in_bytes (TREE_TYPE (decl)); - extern_head = p; - } - return 0; + gcc_unreachable (); } -/* Output format asm string. */ void -score_declare_object (FILE *stream, const char *name, - const char *directive, const char *fmt, ...) +score_movsicc (rtx *ops) { - va_list ap; - fputs (directive, stream); - assemble_name (stream, name); - va_start (ap, fmt); - vfprintf (stream, fmt, ap); - va_end (ap); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_movsicc (ops); + else if (TARGET_SCORE3) + return score3_movsicc (ops); + + gcc_unreachable (); } -/* Implement RETURN_ADDR_RTX. Note, we do not support moving - back to a previous frame. */ -rtx -score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) +/* Machine Split */ +void +score_movdi (rtx *ops) { - if (count != 0) - return const0_rtx; - return get_hard_reg_initial_val (Pmode, RA_REGNUM); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_movdi (ops); + else if (TARGET_SCORE3) + return score3_movdi (ops); + + gcc_unreachable (); } -/* 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 -score_print_operand (FILE *file, rtx op, int c) +score_zero_extract_andi (rtx *ops) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_zero_extract_andi (ops); + else if (TARGET_SCORE3) + return score3_zero_extract_andi (ops); + + gcc_unreachable (); +} + +/* Output asm insn for move. */ +const char * +score_move (rtx *ops) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_move (ops); + else if (TARGET_SCORE3) + return score3_move (ops); + + 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) + return score7_linsn (ops, unit, sign); + else if (TARGET_SCORE3) + return score3_linsn (ops, unit, sign); + + 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) + return score7_sinsn (ops, unit); + else if (TARGET_SCORE3) + return score3_sinsn (ops, unit); + + gcc_unreachable (); +} + +/* Output asm insn for load immediate. */ +const char * +score_limm (rtx *ops) +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_limm (ops); + else if (TARGET_SCORE3) + return score3_limm (ops); + + gcc_unreachable (); +} + + +/* Generate add insn. */ +const char * +score_select_add_imm (rtx *ops, bool set_cc) { - enum rtx_code code = -1; - if (!PRINT_OPERAND_PUNCT_VALID_P (c)) - code = GET_CODE (op); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + return score7_select_add_imm (ops, set_cc); + else if (TARGET_SCORE3) + return score3_select_add_imm (ops, set_cc); - if (c == '[') + gcc_unreachable (); +} + +/* Output arith insn. */ +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) + 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 = alloca (sizeof (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) { - fprintf (file, ".set r1\n"); + 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 (c == ']') + else if (reg_count >= 1) { - fprintf (file, "\n\t.set nor1"); + 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])); } - else if (c == 'U') + + /* Store regs to dest. */ + if (MEM_ALIGN (dst) >= BITS_PER_WORD) { - gcc_assert (code == CONST_INT); - fprintf (file, HOST_WIDE_INT_PRINT_HEX, - (INTVAL (op) >> 16) & 0xffff); + 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 (c == 'D') + else if (reg_count >= 1) { - 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); + 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)); } - else if (c == 'S') + + /* Mop up any left-over bytes. */ + if (leftover > 0) { - gcc_assert (code == REG); - if (G16_REG_P (REGNO (op))) - fprintf (file, "!"); + 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); } - else if (c == 'V') +} + +/* 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) { - gcc_assert (code == REG); - fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!"); + emit_insn (gen_move_lcb (src_reg, src_reg)); + emit_insn (gen_move_lcw (src_reg, src_reg, temp)); } - else if (c == 'C') - { - enum machine_mode mode = GET_MODE (XEXP (op, 0)); + else + emit_insn (gen_move_lw_a (src_reg, + src_reg, gen_int_mode (4, SImode), temp)); - 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; + 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)); +} - 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); +/* 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 = alloca (sizeof (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 if (c == 'F') + else { - 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); + for (i = 0; i < reg_count; i++) + emit_insn (gen_move_lw_a (src_reg, + src_reg, gen_int_mode (4, SImode), regs[i])); } - else if (code == REG) + + if (dst_unaligned) { - int regnum = REGNO (op); - if ((c == 'H' && !WORDS_BIG_ENDIAN) - || (c == 'L' && WORDS_BIG_ENDIAN)) - regnum ++; - fprintf (file, "%s", reg_names[regnum]); + for (i = 0; i < reg_count; i++) + emit_insn (gen_move_scw (dst_reg, dst_reg, regs[i])); } else { - switch (code) - { - case MEM: - score_print_operand_address (file, op); - break; - default: - output_addr_const (file, op); - } + for (i = 0; i < reg_count; i++) + emit_insn (gen_move_sw_a (dst_reg, + dst_reg, gen_int_mode (4, SImode), regs[i])); } } -/* Implement PRINT_OPERAND_ADDRESS macro. */ -void -score_print_operand_address (FILE *file, rtx x) +/* 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) { - struct score_address_info addr; - enum rtx_code code = GET_CODE (x); - enum machine_mode mode = GET_MODE (x); + bool src_unaligned = (src_align < BITS_PER_WORD); + bool dst_unaligned = (dst_align < BITS_PER_WORD); + + HOST_WIDE_INT leftover; - if (code == MEM) - x = XEXP (x, 0); + leftover = length % UNITS_PER_WORD; + length -= leftover; - if (mda_classify_address (&addr, mode, x, true)) + 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) { - switch (addr.type) + 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) { - case 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 ADD_CONST_INT: - case ADD_SYMBOLIC: - output_addr_const (file, x); - return; + 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; } } - print_rtl (stderr, x); - gcc_unreachable (); } -/* Implement SELECT_CC_MODE macro. */ -enum machine_mode -score_select_cc_mode (enum rtx_code op, rtx x, rtx y) +#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) { - if ((op == EQ || op == NE || op == LT || op == GE) - && y == const0_rtx - && GET_MODE (x) == SImode) + 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; + + 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) { - 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; - } + iteration = (length - head_length) / loop_mov_bytes; + if (iteration > 1) + break; } - - if ((op == EQ || op == NE) - && (GET_CODE (y) == NEG) - && register_operand (XEXP (y, 0), SImode) - && register_operand (x, SImode)) + if (iteration <= 1) { - return CC_NZmode; + score_block_move_straight (dst, src, length); + return; } - return CCmode; + 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); + + emit_insn (gen_cmpsi (dst_reg, final_dst)); + emit_jump_insn (gen_bne (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; } struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/score/score.h b/gcc/config/score/score.h index d2c78012c24..8a1efb6f4f5 100644 --- a/gcc/config/score/score.h +++ b/gcc/config/score/score.h @@ -19,30 +19,53 @@ . */ #include "score-conv.h" -#include "score-version.h" - -/* Define the information needed to generate branch insns. This is - stored from the compare operation. */ -extern GTY(()) rtx cmp_op0; -extern GTY(()) rtx cmp_op1; /* Controlling the Compilation Driver. */ #undef SWITCH_TAKES_ARG #define SWITCH_TAKES_ARG(CHAR) \ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') -/* CC1_SPEC is the set of arguments to pass to the compiler proper. */ +#undef CPP_SPEC +#define CPP_SPEC "%{mscore3:-D__score3__} %{G*}" + #undef CC1_SPEC -#define CC1_SPEC "%{G*} %{!mel:-meb}" +#define CC1_SPEC "%{!mel:-meb} %{mel:-mel } \ +%{!mscore*:-mscore7} \ +%{mscore3:-mscore3} \ +%{mscore3d:-mscore3d} \ +%{mscore7:-mscore7} \ +%{mscore7d:-mscore7d} \ +%{G*}" #undef ASM_SPEC -#define ASM_SPEC \ - "%{!mel:-EB} %{mel:-EL} %{mscore5:-SCORE5} %{mscore5u:-SCORE5U} \ - %{mscore7:%{!mmac:-SCORE7}} %{mscore7:%{mmac:-SCORE7D}} \ - %{mscore7d:-SCORE7D} %{G*}" +#define ASM_SPEC "%{!mel:-EB} %{mel:-EL} \ +%{!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 -#define LINK_SPEC "%{!mel:-EB} %{mel:-EL} %{G*}" +#define LINK_SPEC "%{!mel:-EB} %{mel:-EL} \ +%{!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. */ #define TARGET_CPU_CPP_BUILTINS() \ @@ -54,16 +77,26 @@ extern GTY(()) rtx cmp_op1; builtin_define ("__scorele__"); \ else \ builtin_define ("__scorebe__"); \ + if (TARGET_SCORE5) \ + builtin_define ("__score5__"); \ if (TARGET_SCORE5U) \ builtin_define ("__score5u__"); \ - else \ + 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 MASK_SCORE7 +#define TARGET_DEFAULT 0 + +#define SCORE_GCC_VERSION "1.6" #define TARGET_VERSION \ - fprintf (stderr, "Sunplus S+CORE %s", SCORE_GCC_VERSION); + fprintf (stderr, "Sunplus S+core rev=%s", SCORE_GCC_VERSION); #define OVERRIDE_OPTIONS score_override_options () @@ -415,6 +448,7 @@ enum reg_class /* The class value for index registers. */ #define INDEX_REG_CLASS NO_REGS +extern enum reg_class score_char_to_class[256]; #define REG_CLASS_FROM_LETTER(C) score_char_to_class[(unsigned char) (C)] /* Addressing modes, and classification of registers for them. */ @@ -619,28 +653,58 @@ typedef struct score_args /* Generating Code for Profiling */ /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ -#define FUNCTION_PROFILER(FILE, LABELNO) \ -{ \ - fprintf (FILE, " .set r1 \n"); \ - fprintf (FILE, " mv r%d,r%d \n", AT_REGNUM, RA_REGNUM); \ - fprintf (FILE, " subi r%d, %d \n", STACK_POINTER_REGNUM, 8); \ - fprintf (FILE, " jl _mcount \n"); \ - fprintf (FILE, " .set nor1 \n"); \ -} +#define FUNCTION_PROFILER(FILE, LABELNO) \ + do { \ + if (TARGET_SCORE7) \ + { \ + fprintf (FILE, " .set r1 \n"); \ + fprintf (FILE, " mv r%d,r%d \n", AT_REGNUM, RA_REGNUM); \ + fprintf (FILE, " subi r%d, %d \n", STACK_POINTER_REGNUM, 8); \ + 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) -#define TRAMPOLINE_TEMPLATE(STREAM) \ -{ \ - fprintf (STREAM, "\t.set r1\n"); \ - fprintf (STREAM, "\tmv r31, r3\n"); \ - fprintf (STREAM, "\tbl nextinsn\n"); \ - fprintf (STREAM, "nextinsn:\n"); \ - fprintf (STREAM, "\tlw r1, [r3, 6*4-8]\n"); \ - fprintf (STREAM, "\tlw r23, [r3, 6*4-4]\n"); \ - fprintf (STREAM, "\tmv r3, r31\n"); \ - fprintf (STREAM, "\tbr! r1\n"); \ - fprintf (STREAM, "\tnop!\n"); \ - fprintf (STREAM, "\t.set nor1\n"); \ -} +#define TRAMPOLINE_TEMPLATE(STREAM) \ + do { \ + if (TARGET_SCORE7) \ + { \ + fprintf (STREAM, "\t.set r1\n"); \ + fprintf (STREAM, "\tmv r31, r3\n"); \ + fprintf (STREAM, "\tbl nextinsn\n"); \ + fprintf (STREAM, "nextinsn:\n"); \ + fprintf (STREAM, "\tlw r1, [r3, 6*4-8]\n"); \ + fprintf (STREAM, "\tlw r23, [r3, 6*4-4]\n"); \ + fprintf (STREAM, "\tmv r3, r31\n"); \ + fprintf (STREAM, "\tbr! r1\n"); \ + fprintf (STREAM, "\tnop!\n"); \ + fprintf (STREAM, "\t.set nor1\n"); \ + } \ + else if (TARGET_SCORE3) \ + { \ + fprintf (STREAM, "\t.set r1\n"); \ + fprintf (STREAM, "\tmv! r31, r3\n"); \ + fprintf (STREAM, "\tnop!\n"); \ + fprintf (STREAM, "\tbl nextinsn\n"); \ + fprintf (STREAM, "nextinsn:\n"); \ + fprintf (STREAM, "\tlw! r1, [r3, 6*4-8]\n"); \ + fprintf (STREAM, "\tnop!\n"); \ + fprintf (STREAM, "\tlw r23, [r3, 6*4-4]\n"); \ + fprintf (STREAM, "\tmv! r3, r31\n"); \ + fprintf (STREAM, "\tnop!\n"); \ + fprintf (STREAM, "\tbr! r1\n"); \ + fprintf (STREAM, "\tnop!\n"); \ + fprintf (STREAM, "\t.set nor1\n"); \ + } \ + } while (0) /* Trampolines for Nested Functions. */ #define TRAMPOLINE_INSNS 6 @@ -765,17 +829,23 @@ typedef struct score_args /* Output of Uninitialized Variables. */ /* This says how to define a global common symbol. */ #define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGN) \ - score_declare_object (STREAM, NAME, "\n\t.comm\t", \ - ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \ - SIZE, ALIGN / BITS_PER_UNIT); + do { \ + fputs ("\n\t.comm\t", STREAM); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, " , " HOST_WIDE_INT_PRINT_UNSIGNED ", %u\n", \ + SIZE, ALIGN / BITS_PER_UNIT); \ + } while (0) /* This says how to define a local common symbol (i.e., not visible to linker). */ #undef ASM_OUTPUT_ALIGNED_LOCAL -#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN) \ - score_declare_object (STREAM, NAME, "\n\t.lcomm\t", \ - ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \ - SIZE, ALIGN / BITS_PER_UNIT); +#define ASM_OUTPUT_ALIGNED_LOCAL(STREAM, NAME, SIZE, ALIGN) \ + do { \ + fputs ("\n\t.lcomm\t", STREAM); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, " , " HOST_WIDE_INT_PRINT_UNSIGNED ", %u\n", \ + SIZE, ALIGN / BITS_PER_UNIT); \ + } while (0) /* Globalizing directive for a label. */ #define GLOBAL_ASM_OP "\t.globl\t" @@ -790,8 +860,11 @@ typedef struct score_args #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) #undef ASM_DECLARE_OBJECT_NAME -#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ - score_declare_object (STREAM, NAME, "", ":\n") +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ + do { \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ":\n"); \ + } while (0) /* This says how to output an external. It would be possible not to output anything and let undefined symbol become external. However @@ -808,7 +881,7 @@ typedef struct score_args /* Local compiler-generated symbols must have a prefix that the assembler understands. */ -#define LOCAL_LABEL_PREFIX "." +#define LOCAL_LABEL_PREFIX (TARGET_SCORE7 ? "." : "$") #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ @@ -859,32 +932,88 @@ typedef struct score_args #define USER_LABEL_PREFIX "" /* This is how to output an insn to push a register on the stack. */ -#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ - do { \ - fprintf (STREAM, "\tpush! %s,[%s]\n", \ - reg_names[REGNO], \ - reg_names[STACK_POINTER_REGNUM]); \ +#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ + do { \ + if (TARGET_SCORE7) \ + 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. */ -#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ - do { \ - fprintf (STREAM, "\tpop! %s,[%s]\n", \ - reg_names[REGNO], \ - reg_names[STACK_POINTER_REGNUM]); \ +#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ + do { \ + if (TARGET_SCORE7) \ + 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. */ /* This is how to output an element of a case-vector. We can make the entries PC-relative in GP-relative when .gp(d)word is supported. */ -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \ +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \ + do { \ + if (TARGET_SCORE7) \ + 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); \ + 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. */ +#define ADDR_VEC_ALIGN(JUMPTABLE) (GET_MODE (PATTERN (JUMPTABLE)) == SImode ? 2 \ + : GET_MODE (PATTERN (JUMPTABLE)) == HImode ? 1 : 0) + +/* This is how to output a label which precedes a jumptable. Since + Score3 instructions are 2 bytes, we may need explicit alignment here. */ +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, JUMPTABLE) \ do { \ - 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); \ + if ((TARGET_SCORE7) && GET_MODE (PATTERN (JUMPTABLE)) == SImode) \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + (*targetm.asm_out.internal_label) (FILE, PREFIX, NUM); \ } while (0) +/* Specify the machine mode that this machine uses + 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) @@ -927,10 +1056,6 @@ typedef struct score_args /* The DWARF 2 CFA column which tracks the return address. */ #define DWARF_FRAME_RETURN_COLUMN 3 -/* Specify the machine mode that this machine uses - for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE SImode - /* Define if operations between registers always perform the operation on the full register even if a narrower mode is specified. */ #define WORD_REGISTER_OPERATIONS diff --git a/gcc/config/score/score.md b/gcc/config/score/score.md index c2b94c4eb17..e616c57aa7e 100644 --- a/gcc/config/score/score.md +++ b/gcc/config/score/score.md @@ -38,7 +38,6 @@ ; tce transfer to hi/lo registers ; fsr transfer from special registers ; tsr transfer to special registers -; pseudo pseudo instruction (define_constants [(CC_REGNUM 33) @@ -73,19 +72,19 @@ (SFFS 10)]) (define_attr "type" - "unknown,branch,jump,call,load,store,cmp,arith,move,const,nop,mul,div,cndmv,fce,tce,fsr,tsr,fcr,tcr,pseudo" + "unknown,branch,jump,call,load,store,cmp,arith,move,const,nop,mul,div,cndmv,fce,tce,fsr,tsr,fcr,tcr" (const_string "unknown")) -(define_attr "mode" "unknown,none,QI,HI,SI,DI" +(define_attr "mode" "unknown,QI,HI,SI,DI" (const_string "unknown")) +(define_attr "length" "" (const_int 4)) + (define_attr "up_c" "yes,no" (const_string "no")) -(include "score7.md") +(include "score-generic.md") (include "predicates.md") -(include "misc.md") -(include "mac.md") (define_expand "movqi" [(set (match_operand:QI 0 "nonimmediate_operand") @@ -99,25 +98,49 @@ } }) -(define_insn "*movqi_insns" +(define_insn "*movqi_insns_score7" + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a") + (match_operand:QI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))] + "(!MEM_P (operands[0]) || register_operand (operands[1], QImode)) + && (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return score_limm (operands); + case 1: return score_move (operands); + case 2: return score_linsn (operands, SCORE_BYTE, false); + case 3: return score_sinsn (operands, SCORE_BYTE); + case 4: return TARGET_SCORE7D ? \"mf%1%S0 %0\" : \"mf%1 %0\"; + case 5: return TARGET_SCORE7D ? \"mt%0%S1 %1\" : \"mt%0 %1\"; + case 6: return \"mfsr\t%0, %1\"; + case 7: return \"mtsr\t%1, %0\"; + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr") + (set_attr "mode" "QI")]) + +(define_insn "*movqi_insns_score3" [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a") (match_operand:QI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))] - "!MEM_P (operands[0]) || register_operand (operands[1], QImode)" + "(!MEM_P (operands[0]) || register_operand (operands[1], QImode)) + && (TARGET_SCORE3)" { switch (which_alternative) { - case 0: return mdp_limm (operands); - case 1: return mdp_move (operands); - case 2: return mdp_linsn (operands, MDA_BYTE, false); - case 3: return mdp_sinsn (operands, MDA_BYTE); - case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\"; - case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\"; - case 6: return \"mfsr %0, %1\"; - case 7: return \"mtsr %1, %0\"; + case 0: return score_limm (operands); + case 1: return \"mv!\t%0, %1\"; + case 2: return score_linsn (operands, SCORE_BYTE, false); + case 3: return score_sinsn (operands, SCORE_BYTE); + case 4: return TARGET_SCORE3D ? \"mf%1%S0\t%0\" : \"mf%1\t%0\"; + case 5: return TARGET_SCORE3D ? \"mt%0%S1\t%1\" : \"mt%0\t%1\"; + case 6: return \"mfsr\t%0, %1\"; + case 7: return \"mtsr\t%1, %0\"; default: gcc_unreachable (); } } [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr") + (set_attr "length" "6,2,6,6,4,4,4,4") (set_attr "mode" "QI")]) (define_expand "movhi" @@ -132,25 +155,49 @@ } }) -(define_insn "*movhi_insns" +(define_insn "*movhi_insns_score7" + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a") + (match_operand:HI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))] + "(!MEM_P (operands[0]) || register_operand (operands[1], HImode)) + && (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return score_limm (operands); + case 1: return score_move (operands); + case 2: return score_linsn (operands, SCORE_HWORD, false); + case 3: return score_sinsn (operands, SCORE_HWORD); + case 4: return TARGET_SCORE7D ? \"mf%1%S0 %0\" : \"mf%1 %0\"; + case 5: return TARGET_SCORE7D ? \"mt%0%S1 %1\" : \"mt%0 %1\"; + case 6: return \"mfsr\t%0, %1\"; + case 7: return \"mtsr\t%1, %0\"; + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr") + (set_attr "mode" "HI")]) + +(define_insn "*movhi_insns_score3" [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a") (match_operand:HI 1 "general_operand" "i,d,m,d,*x,d,*a,d"))] - "!MEM_P (operands[0]) || register_operand (operands[1], HImode)" + "(!MEM_P (operands[0]) || register_operand (operands[1], HImode)) + && (TARGET_SCORE3)" { switch (which_alternative) { - case 0: return mdp_limm (operands); - case 1: return mdp_move (operands); - case 2: return mdp_linsn (operands, MDA_HWORD, false); - case 3: return mdp_sinsn (operands, MDA_HWORD); - case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\"; - case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\"; - case 6: return \"mfsr %0, %1\"; - case 7: return \"mtsr %1, %0\"; + case 0: return score_limm (operands); + case 1: return \"mv!\t%0, %1\"; + case 2: return score_linsn (operands, SCORE_HWORD, false); + case 3: return score_sinsn (operands, SCORE_HWORD); + case 4: return TARGET_SCORE3D ? \"mf%1%S0\t%0\" : \"mf%1\t%0\"; + case 5: return TARGET_SCORE3D ? \"mt%0%S1\t%1\" : \"mt%0\t%1\"; + case 6: return \"mfsr\t%0, %1\"; + case 7: return \"mtsr\t%1, %0\"; default: gcc_unreachable (); } } [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr") + (set_attr "length" "6,2,6,6,4,4,4,4") (set_attr "mode" "HI")]) (define_expand "movsi" @@ -165,33 +212,62 @@ } }) -(define_insn "*movsi_insns" +(define_insn "*movsi_insns_score7" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,m,d,*x,d,*a,d,*c") (match_operand:SI 1 "general_operand" "i,d,m,d,*x,d,*a,d,*c,d"))] - "!MEM_P (operands[0]) || register_operand (operands[1], SImode)" + "(!MEM_P (operands[0]) || register_operand (operands[1], SImode)) + && (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { switch (which_alternative) { case 0: if (GET_CODE (operands[1]) != CONST_INT) - return \"la %0, %1\"; + return \"la\t%0, %1\"; else - return mdp_limm (operands); - case 1: return mdp_move (operands); - case 2: return mdp_linsn (operands, MDA_WORD, false); - case 3: return mdp_sinsn (operands, MDA_WORD); - case 4: return TARGET_MAC ? \"mf%1%S0 %0\" : \"mf%1 %0\"; - case 5: return TARGET_MAC ? \"mt%0%S1 %1\" : \"mt%0 %1\"; - case 6: return \"mfsr %0, %1\"; - case 7: return \"mtsr %1, %0\"; - case 8: return \"mfcr %0, %1\"; - case 9: return \"mtcr %1, %0\"; + return score_limm (operands); + case 1: return score_move (operands); + case 2: return score_linsn (operands, SCORE_WORD, false); + case 3: return score_sinsn (operands, SCORE_WORD); + case 4: return TARGET_SCORE7D ? \"mf%1%S0 %0\" : \"mf%1 %0\"; + case 5: return TARGET_SCORE7D ? \"mt%0%S1 %1\" : \"mt%0 %1\"; + case 6: return \"mfsr\t%0, %1\"; + case 7: return \"mtsr\t%1, %0\"; + case 8: return \"mfcr\t%0, %1\"; + case 9: return \"mtcr\t%1, %0\"; default: gcc_unreachable (); } } [(set_attr "type" "arith,move,load,store,fce,tce,fsr,tsr,fcr,tcr") (set_attr "mode" "SI")]) +(define_insn "*movsi_insns_score3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=ed,e,d,d,m,d,*x,d,*a") + (match_operand:SI 1 "general_operand" "i,e,d,m,d,*x,d,*a,d"))] + "(!MEM_P (operands[0]) || register_operand (operands[1], SImode)) + && (TARGET_SCORE3)" +{ + switch (which_alternative) + { + case 0: + if (GET_CODE (operands[1]) != CONST_INT) + return \"ldi48\t%0, %1\"; + else + return score_limm (operands); + case 1: return \"mv!\t%0, %1\"; + case 2: return \"mv!\t%0, %1\"; + case 3: return score_linsn (operands, SCORE_WORD, false); + case 4: return score_sinsn (operands, SCORE_WORD); + case 5: return TARGET_SCORE3D ? \"mf%1%S0\t%0\" : \"mf%1\t%0\"; + case 6: return TARGET_SCORE3D ? \"mt%0%S1\t%1\" : \"mt%0\t%1\"; + case 7: return \"mfsr\t%0, %1\"; + case 8: return \"mtsr\t%1, %0\"; + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith,move,move,load,store,fce,tce,fsr,tsr") + (set_attr "length" "6,2,2,6,6,4,4,4,4") + (set_attr "mode" "SI")]) + (define_insn_and_split "movdi" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,d,*x") (match_operand:DI 1 "general_operand" "i,d,m,d,*x,d"))] @@ -200,7 +276,7 @@ "reload_completed" [(const_int 0)] { - mds_movdi (operands); + score_movdi (operands); DONE; }) @@ -216,21 +292,41 @@ } }) -(define_insn "*movsf_insns" +(define_insn "*movsf_insns_score7" + [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,m") + (match_operand:SF 1 "general_operand" "i,d,m,d"))] + "(!MEM_P (operands[0]) || register_operand (operands[1], SFmode)) + && (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"li\t%0, %D1\";; + case 1: return score_move (operands); + case 2: return score_linsn (operands, SCORE_WORD, false); + case 3: return score_sinsn (operands, SCORE_WORD); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith,move,load,store") + (set_attr "mode" "SI")]) + +(define_insn "*movsf_insns_score3" [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,m") (match_operand:SF 1 "general_operand" "i,d,m,d"))] - "!MEM_P (operands[0]) || register_operand (operands[1], SFmode)" + "(!MEM_P (operands[0]) || register_operand (operands[1], SFmode)) + && (TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"li %0, %D1\";; - case 1: return mdp_move (operands); - case 2: return mdp_linsn (operands, MDA_WORD, false); - case 3: return mdp_sinsn (operands, MDA_WORD); + case 0: return \"li\t%0, %D1\"; + case 1: return \"mv!\t%0, %1\"; + case 2: return score_linsn (operands, SCORE_WORD, false); + case 3: return score_sinsn (operands, SCORE_WORD); default: gcc_unreachable (); } } [(set_attr "type" "arith,move,load,store") + (set_attr "length" "4,2,6,6") (set_attr "mode" "SI")]) (define_insn_and_split "movdf" @@ -241,51 +337,101 @@ "reload_completed" [(const_int 0)] { - mds_movdi (operands); + score_movdi (operands); DONE; }) -(define_insn "addsi3" +(define_expand "addsi3" + [(set (match_operand:SI 0 "score_register_operand" ) + (plus:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" + "" +) + +(define_insn "*addsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") (plus:SI (match_operand:SI 1 "register_operand" "0,0,d,d") (match_operand:SI 2 "arith_operand" "I,L,N,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"addis\t%0, %U2\"; + case 1: return score_select_add_imm (operands, false); + case 2: return \"addri\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", false); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*addsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d,d,d") + (plus:SI (match_operand:SI 1 "score_register_operand" "%0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,L,N,d")))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"addis %0, %U2\"; - case 1: return mdp_select_add_imm (operands, false); - case 2: return \"addri %0, %1, %c2\"; - case 3: return mdp_select (operands, "add", true, "", false); + case 0: return \"addis\t%0, %U2\"; + case 1: return score_select_add_imm (operands, false); + case 2: return \"addri\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", false); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "mode" "SI")]) -(define_insn "*addsi3_cmp" +(define_insn "*addsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (plus:SI (match_operand:SI 1 "register_operand" "0,0,d,d") (match_operand:SI 2 "arith_operand" "I,L,N,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d,d,d,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"addis.c\t%0, %U2\"; + case 1: return score_select_add_imm (operands, true); + case 2: return \"addri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*addsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (plus:SI + (match_operand:SI 1 "score_register_operand" "0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,L,N,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d,d,d"))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"addis.c %0, %U2\"; - case 1: return mdp_select_add_imm (operands, true); - case 2: return \"addri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "add", true, "", true); + case 0: return \"addis.c\t%0, %U2\"; + case 1: return score_select_add_imm (operands, true); + case 2: return \"addri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*addsi3_ucc" +(define_insn "*addsi3_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (plus:SI (match_operand:SI 1 "register_operand" "0,0,d,d") @@ -293,55 +439,140 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d,d,d,d") (plus:SI (match_dup 1) (match_dup 2)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"addis.c\t%0, %U2\"; + case 1: return score_select_add_imm (operands, true); + case 2: return \"addri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*addsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (plus:SI + (match_operand:SI 1 "score_register_operand" "0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,L,N,d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d,d,d,d") + (plus:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"addis.c %0, %U2\"; - case 1: return mdp_select_add_imm (operands, true); - case 2: return \"addri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "add", true, "", true); + case 0: return \"addis.c\t%0, %U2\"; + case 1: return score_select_add_imm (operands, true); + case 2: return \"addri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "add", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "adddi3" +(define_expand "adddi3" + [(parallel + [(set (match_operand:DI 0 "score_register_operand") + (plus:DI (match_operand:DI 1 "score_register_operand") + (match_operand:DI 2 "score_register_operand"))) + (clobber (reg:CC CC_REGNUM))])] + "" + "" +) + +(define_insn "*adddi3_score7" [(set (match_operand:DI 0 "register_operand" "=e,d") (plus:DI (match_operand:DI 1 "register_operand" "0,d") (match_operand:DI 2 "register_operand" "e,d"))) (clobber (reg:CC CC_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ add! %L0, %L2\;addc! %H0, %H2 add.c %L0, %L1, %L2\;addc %H0, %H1, %H2" [(set_attr "type" "arith") (set_attr "mode" "DI")]) -(define_insn "subsi3" +(define_insn "*adddi3_score3" + [(set (match_operand:DI 0 "score_register_operand" "=d") + (plus:DI (match_operand:DI 1 "score_register_operand" "d") + (match_operand:DI 2 "score_register_operand" "d"))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" + "add.c\t%L0, %L1, %L2\;addc\t%H0, %H1, %H2" + [(set_attr "type" "arith") + (set_attr "length" "8") + (set_attr "mode" "DI")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "score_register_operand") + (minus:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "score_register_operand")))] + "" + "" +) + +(define_insn "*subsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d") (minus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + return score_select (operands, "sub", false, "", false); +} + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*subsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=e,d") + (minus:SI (match_operand:SI 1 "score_register_operand" "0,d") + (match_operand:SI 2 "score_register_operand" "e,d")))] + "(TARGET_SCORE3)" { - return mdp_select (operands, "sub", false, "", false); + switch (which_alternative) + { + case 0: return \"sub!\t%0, %2\"; + case 1: return score_select (operands, "sub", false, "", false); + default: gcc_unreachable (); + } } [(set_attr "type" "arith") + (set_attr "length" "2,4") (set_attr "mode" "SI")]) -(define_insn "*subsi3_cmp" +(define_insn "*subsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + return score_select (operands, "sub", false, "", true); +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*subsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (minus:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" { - return mdp_select (operands, "sub", false, "", true); + return score_select (operands, "sub", false, "", true); } [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) @@ -359,86 +590,159 @@ (define_insn "subsi3_ucc_pcmp" [(parallel - [(set (reg:CC CC_REGNUM) - (compare:CC (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))) - (set (match_operand:SI 0 "register_operand" "=d") - (minus:SI (match_dup 1) (match_dup 2)))])] + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d"))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (minus:SI (match_dup 1) (match_dup 2)))])] "" { - return mdp_select (operands, "sub", false, "", true); + return score_select (operands, "sub", false, "", true); } [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) (define_insn "subsi3_ucc" [(set (reg:CC_NZ CC_REGNUM) - (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")) + (compare:CC_NZ (minus:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d") + (set (match_operand:SI 0 "score_register_operand" "=d") (minus:SI (match_dup 1) (match_dup 2)))] "" { - return mdp_select (operands, "sub", false, "", true); + return score_select (operands, "sub", false, "", true); } [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "subdi3" +(define_expand "subdi3" + [(parallel + [(set (match_operand:DI 0 "score_register_operand") + (minus:DI (match_operand:DI 1 "score_register_operand") + (match_operand:DI 2 "score_register_operand"))) + (clobber (reg:CC CC_REGNUM))])] + "" + "" +) + +(define_insn "*subdi3_score7" [(set (match_operand:DI 0 "register_operand" "=e,d") (minus:DI (match_operand:DI 1 "register_operand" "0,d") (match_operand:DI 2 "register_operand" "e,d"))) (clobber (reg:CC CC_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ sub! %L0, %L2\;subc %H0, %H1, %H2 sub.c %L0, %L1, %L2\;subc %H0, %H1, %H2" [(set_attr "type" "arith") (set_attr "mode" "DI")]) -(define_insn "andsi3" +(define_insn "*subdi3_score3" + [(set (match_operand:DI 0 "score_register_operand" "=d") + (minus:DI (match_operand:DI 1 "score_register_operand" "d") + (match_operand:DI 2 "score_register_operand" "d"))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" + "sub.c\t%L0, %L1, %L2\;subc\t%H0, %H1, %H2" + [(set_attr "type" "arith") + (set_attr "length" "8") + (set_attr "mode" "DI")]) + +(define_expand "andsi3" + [(set (match_operand:SI 0 "score_register_operand") + (and:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" + "" +) + +(define_insn "*andsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") (and:SI (match_operand:SI 1 "register_operand" "0,0,d,d") (match_operand:SI 2 "arith_operand" "I,K,M,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { switch (which_alternative) { - case 0: return \"andis %0, %U2\"; - case 1: return \"andi %0, %c2"; - case 2: return \"andri %0, %1, %c2\"; - case 3: return mdp_select (operands, "and", true, "", false); + case 0: return \"andis\t%0, %U2\"; + case 1: return \"andi\t%0, %c2"; + case 2: return \"andri\t%0, %1, %c2\"; + case 3: return score_select (operands, "and", true, "", false); default: gcc_unreachable (); } } [(set_attr "type" "arith") (set_attr "mode" "SI")]) -(define_insn "andsi3_cmp" +(define_insn "*andsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=e,d,d,d,d") + (and:SI (match_operand:SI 1 "score_register_operand" "%0,0,0,d,d") + (match_operand:SI 2 "arith_operand" "e,I,K,M,d")))] + "(TARGET_SCORE3)" +{ + switch (which_alternative) + { + case 0: return \"and!\t%0, %2\"; + case 1: return \"andis\t%0, %U2\"; + case 2: return \"andi\t%0, %c2"; + case 3: return \"andri\t%0, %1, %c2\"; + case 4: return score_select (operands, "and", true, "", false); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "length" "2,4,4,4,4") + (set_attr "mode" "SI")]) + +(define_insn "andsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (and:SI (match_operand:SI 1 "register_operand" "0,0,0,d") (match_operand:SI 2 "arith_operand" "I,K,M,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d,d,d,d"))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"andis.c\t%0, %U2\"; + case 1: return \"andi.c\t%0, %c2"; + case 2: return \"andri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "and", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "andsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (and:SI (match_operand:SI 1 "score_register_operand" "0,0,0,d") + (match_operand:SI 2 "arith_operand" "I,K,M,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d,d,d"))] "" { switch (which_alternative) { - case 0: return \"andis.c %0, %U2\"; - case 1: return \"andi.c %0, %c2"; - case 2: return \"andri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "and", true, "", true); + case 0: return \"andis.c\t%0, %U2\"; + case 1: return \"andi.c\t%0, %c2"; + case 2: return \"andri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "and", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*andsi3_ucc" +(define_insn "*andsi3_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (and:SI (match_operand:SI 1 "register_operand" "0,0,d,d") @@ -446,25 +750,50 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d,d,d,d") (and:SI (match_dup 1) (match_dup 2)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"andis.c\t%0, %U2\"; + case 1: return \"andi.c\t%0, %c2"; + case 2: return \"andri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "and", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*andsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (and:SI + (match_operand:SI 1 "score_register_operand" "0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,K,M,d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d,d,d,d") + (and:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"andis.c %0, %U2\"; - case 1: return \"andi.c %0, %c2"; - case 2: return \"andri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "and", true, "", true); + case 0: return \"andis.c\t%0, %U2\"; + case 1: return \"andi.c\t%0, %c2"; + case 2: return \"andri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "and", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) + (define_insn_and_split "*zero_extract_andi" [(set (reg:CC CC_REGNUM) (compare:CC (zero_extract:SI - (match_operand:SI 0 "register_operand" "d") + (match_operand:SI 0 "score_register_operand" "d") (match_operand:SI 1 "const_uimm5" "") (match_operand:SI 2 "const_uimm5" "")) (const_int 0)))] @@ -473,29 +802,57 @@ "" [(const_int 1)] { - mds_zero_extract_andi (operands); + score_zero_extract_andi (operands); DONE; }) -(define_insn "iorsi3" +(define_expand "iorsi3" + [(set (match_operand:SI 0 "score_register_operand") + (ior:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" + "" +) + +(define_insn "*iorsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d") (match_operand:SI 2 "arith_operand" "I,K,M,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"oris\t%0, %U2\"; + case 1: return \"ori\t%0, %c2\"; + case 2: return \"orri\t%0, %1, %c2\"; + case 3: return score_select (operands, "or", true, "", false); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=e,d,d,d,d") + (ior:SI (match_operand:SI 1 "score_register_operand" "%0,0,0,d,d") + (match_operand:SI 2 "arith_operand" "e,I,K,M,d")))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"oris %0, %U2\"; - case 1: return \"ori %0, %c2\"; - case 2: return \"orri %0, %1, %c2\"; - case 3: return mdp_select (operands, "or", true, "", false); + case 0: return \"or!\t%0, %2\"; + case 1: return \"oris\t%0, %U2\"; + case 2: return \"ori\t%0, %c2\"; + case 3: return \"orri\t%0, %1, %c2\"; + case 4: return score_select (operands, "or", true, "", false); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "2,4,4,4,4") (set_attr "mode" "SI")]) -(define_insn "iorsi3_ucc" +(define_insn "*iorsi3_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d") @@ -503,70 +860,155 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d,d,d,d") (ior:SI (match_dup 1) (match_dup 2)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"oris.c\t%0, %U2\"; + case 1: return \"ori.c\t%0, %c2\"; + case 2: return \"orri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "or", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ior:SI + (match_operand:SI 1 "score_register_operand" "0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,K,M,d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d,d,d,d") + (ior:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"oris.c %0, %U2\"; - case 1: return \"ori.c %0, %c2\"; - case 2: return \"orri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "or", true, "", true); + case 0: return \"oris.c\t%0, %U2\"; + case 1: return \"ori.c\t%0, %c2\"; + case 2: return \"orri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "or", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "iorsi3_cmp" +(define_insn "*iorsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (ior:SI (match_operand:SI 1 "register_operand" "0,0,d,d") (match_operand:SI 2 "arith_operand" "I,K,M,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d,d,d,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"oris.c\t%0, %U2\"; + case 1: return \"ori.c\t%0, %c2\"; + case 2: return \"orri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "or", true, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ior:SI + (match_operand:SI 1 "score_register_operand" "0,0,d,d") + (match_operand:SI 2 "arith_operand" "I,K,M,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d,d,d"))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"oris.c %0, %U2\"; - case 1: return \"ori.c %0, %c2\"; - case 2: return \"orri.c %0, %1, %c2\"; - case 3: return mdp_select (operands, "or", true, "", true); + case 0: return \"oris.c\t%0, %U2\"; + case 1: return \"ori.c\t%0, %c2\"; + case 2: return \"orri.c\t%0, %1, %c2\"; + case 3: return score_select (operands, "or", true, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4,4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "xorsi3" +(define_expand "xorsi3" + [(set (match_operand:SI 0 "score_register_operand") + (xor:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "score_register_operand")))] + "" + "" +) + +(define_insn "*xorsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d") (xor:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + return score_select (operands, "xor", true, "", false); +} + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d") + (xor:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")))] + "(TARGET_SCORE3)" { - return mdp_select (operands, "xor", true, "", false); + return score_select (operands, "xor", true, "", false); } [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "mode" "SI")]) -(define_insn "xorsi3_ucc" + +(define_insn "*xorsi3_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (xor:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (xor:SI (match_dup 1) (match_dup 2)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + return score_select (operands, "xor", true, "", true); +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (xor:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (xor:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { - return mdp_select (operands, "xor", true, "", true); + return score_select (operands, "xor", true, "", true); } [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "xorsi3_cmp" + +(define_insn "*xorsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (xor:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")) @@ -574,28 +1016,66 @@ (clobber (match_scratch:SI 0 "=d"))] "" { - return mdp_select (operands, "xor", true, "", true); + return score_select (operands, "xor", true, "", true); } [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] - "" -{ +(define_insn "*xorsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (xor:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "" +{ + return score_select (operands, "xor", true, "", true); +} + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "score_register_operand") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand")))] + "" + "" +) + +(define_insn "*extendqisi2_score7" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"extsb\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_BYTE, true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith,load") + (set_attr "mode" "SI")]) + +(define_insn "*extendqisi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] + "(TARGET_SCORE3)" +{ switch (which_alternative) { - case 0: return \"extsb %0, %1\"; - case 1: return mdp_linsn (operands, MDA_BYTE, true); + case 0: return \"extsb\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_BYTE, true); default: gcc_unreachable (); } } [(set_attr "type" "arith,load") + (set_attr "length" "4,4") (set_attr "mode" "SI")]) -(define_insn "*extendqisi2_ucc" +(define_insn "*extendqisi2_ucc_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (ashiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -604,13 +1084,29 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (sign_extend:SI (match_operand:QI 2 "register_operand" "0")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extsb.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*extendqisi2_cmp" +(define_insn "*extendqisi2_ucc_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (ashiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 24)) + (const_int 24)) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (sign_extend:SI (match_operand:QI 2 "score_register_operand" "0")))] + "(TARGET_SCORE3)" + "extsb.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*extendqisi2_cmp_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (ashiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -618,28 +1114,66 @@ (const_int 24)) (const_int 0))) (clobber (match_scratch:SI 0 "=d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extsb.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "extendhisi2" +(define_insn "*extendqisi2_cmp_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (ashiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 24)) + (const_int 24)) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "extsb.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "score_register_operand") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand")))] + "" + "" +) + +(define_insn "*extendhisi2_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"extsh\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_HWORD, true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith, load") + (set_attr "mode" "SI")]) + +(define_insn "*extendhisi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"extsh %0, %1\"; - case 1: return mdp_linsn (operands, MDA_HWORD, true); + case 0: return \"extsh\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_HWORD, true); default: gcc_unreachable (); } } [(set_attr "type" "arith, load") + (set_attr "length" "4,4") (set_attr "mode" "SI")]) -(define_insn "*extendhisi2_ucc" +(define_insn "*extendhisi2_ucc_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (ashiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -648,13 +1182,29 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (sign_extend:SI (match_operand:HI 2 "register_operand" "0")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extsh.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*extendhisi2_cmp" +(define_insn "*extendhisi2_ucc_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (ashiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 16)) + (const_int 16)) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (sign_extend:SI (match_operand:HI 2 "score_register_operand" "0")))] + "(TARGET_SCORE3)" + "extsh.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*extendhisi2_cmp_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (ashiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -662,28 +1212,66 @@ (const_int 16)) (const_int 0))) (clobber (match_scratch:SI 0 "=d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extsh.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "zero_extendqisi2" +(define_insn "*extendhisi2_cmp_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (ashiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 16)) + (const_int 16)) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "extsh.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "score_register_operand") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand")))] + "" + "" +) + +(define_insn "*zero_extendqisi2_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"extzb\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_BYTE, false); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith, load") + (set_attr "mode" "SI")]) + +(define_insn "*zero_extendqisi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"extzb %0, %1\"; - case 1: return mdp_linsn (operands, MDA_BYTE, false); + case 0: return \"extzb\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_BYTE, false); default: gcc_unreachable (); } - } +} [(set_attr "type" "arith, load") + (set_attr "length" "4,4") (set_attr "mode" "SI")]) -(define_insn "*zero_extendqisi2_ucc" +(define_insn "*zero_extendqisi2_ucc_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (lshiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -692,13 +1280,29 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:QI 2 "register_operand" "0")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extzb.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*zero_extendqisi2_cmp" +(define_insn "*zero_extendqisi2_ucc_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (lshiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 24)) + (const_int 24)) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (zero_extend:SI (match_operand:QI 2 "score_register_operand" "0")))] + "(TARGET_SCORE3)" + "extzb.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*zero_extendqisi2_cmp_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (lshiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -706,28 +1310,66 @@ (const_int 24)) (const_int 0))) (clobber (match_scratch:SI 0 "=d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extzb.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "zero_extendhisi2" +(define_insn "*zero_extendqisi2_cmp_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (lshiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 24)) + (const_int 24)) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "extzb.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "score_register_operand") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand")))] + "" + "" +) + +(define_insn "*zero_extendhisi2_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"extzh\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_HWORD, false); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith, load") + (set_attr "mode" "SI")]) + +(define_insn "*zero_extendhisi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,m")))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"extzh %0, %1\"; - case 1: return mdp_linsn (operands, MDA_HWORD, false); + case 0: return \"extzh\t%0, %1\"; + case 1: return score_linsn (operands, SCORE_HWORD, false); default: gcc_unreachable (); } - } +} [(set_attr "type" "arith, load") + (set_attr "length" "4,4") (set_attr "mode" "SI")]) -(define_insn "*zero_extendhisi2_ucc" +(define_insn "*zero_extendhisi2_ucc_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (lshiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -736,13 +1378,29 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:HI 2 "register_operand" "0")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extzh.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*zero_extendhisi2_cmp" +(define_insn "*zero_extendhisi2_ucc_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (lshiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 16)) + (const_int 16)) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (zero_extend:SI (match_operand:HI 2 "score_register_operand" "0")))] + "(TARGET_SCORE3)" + "extzh.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*zero_extendhisi2_cmp_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (lshiftrt:SI (ashift:SI (match_operand:SI 1 "register_operand" "d") @@ -750,78 +1408,235 @@ (const_int 16)) (const_int 0))) (clobber (match_scratch:SI 0 "=d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "extzh.c %0, %1" [(set_attr "type" "arith") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "mulsi3" +(define_insn "*zero_extendhisi2_cmp_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (lshiftrt:SI + (ashift:SI (match_operand:SI 1 "score_register_operand" "d") + (const_int 16)) + (const_int 16)) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "extzh.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "score_register_operand") + (mult:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "score_register_operand")))] + "" +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + emit_insn (gen_mulsi3_score7 (operands[0], operands[1], operands[2])); + else if (TARGET_SCORE3) + emit_insn (gen_mulsi3_score3 (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_insn "mulsi3_score7" [(set (match_operand:SI 0 "register_operand" "=l") (mult:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI HI_REGNUM))] - "!TARGET_SCORE5U" + (clobber (reg:SI HI_REGNUM))] + "(TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D)" "mul %1, %2" [(set_attr "type" "mul") (set_attr "mode" "SI")]) -(define_insn "mulsidi3" +(define_insn "mulsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d") + (mult:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d")))] + "(TARGET_SCORE3)" + "mulr.l\t%0, %1, %2" + [(set_attr "type" "mul") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "score_register_operand") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "score_register_operand")) + (sign_extend:DI + (match_operand:SI 2 "score_register_operand"))))] + "" +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + emit_insn (gen_mulsidi3_score7 (operands[0], operands[1], operands[2])); + else if (TARGET_SCORE3) + emit_insn (gen_mulsidi3_score3 (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_insn "mulsidi3_score7" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))] - "!TARGET_SCORE5U" + "(TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D)" "mul %1, %2" [(set_attr "type" "mul") (set_attr "mode" "DI")]) -(define_insn "umulsidi3" +(define_insn "mulsidi3_score3" + [(set (match_operand:DI 0 "score_register_operand" "=d") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "score_register_operand" "d")) + (sign_extend:DI + (match_operand:SI 2 "score_register_operand" "d"))))] + "(TARGET_SCORE3)" + "mulr\t%0, %1, %2" + [(set_attr "type" "mul") + (set_attr "length" "4") + (set_attr "mode" "DI")]) + +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "score_register_operand") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "score_register_operand")) + (zero_extend:DI + (match_operand:SI 2 "score_register_operand"))))] + "" +{ + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + emit_insn (gen_umulsidi3_score7 (operands[0], operands[1], operands[2])); + else if (TARGET_SCORE3) + emit_insn (gen_umulsidi3_score3 (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_insn "umulsidi3_score7" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))] - "!TARGET_SCORE5U" + "(TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D)" "mulu %1, %2" [(set_attr "type" "mul") (set_attr "mode" "DI")]) -(define_insn "divmodsi4" +(define_insn "umulsidi3_score3" + [(set (match_operand:DI 0 "score_register_operand" "=d") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "score_register_operand" "d")) + (zero_extend:DI + (match_operand:SI 2 "score_register_operand" "d"))))] + "(TARGET_SCORE3)" + "mulur\t%0, %1, %2" + [(set_attr "type" "mul") + (set_attr "length" "4") + (set_attr "mode" "DI")]) + +(define_expand "divmodsi4" + [(parallel + [(set (match_operand:SI 0 "score_register_operand") + (div:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "score_register_operand"))) + (set (match_operand:SI 3 "score_register_operand") + (mod:SI (match_dup 1) (match_dup 2)))])] + "" + "" +) + +(define_insn "*divmodsi4_score7" [(set (match_operand:SI 0 "register_operand" "=l") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=h") (mod:SI (match_dup 1) (match_dup 2)))] - "!TARGET_SCORE5U" + "(TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D)" "div %1, %2" [(set_attr "type" "div") (set_attr "mode" "SI")]) -(define_insn "udivmodsi4" +(define_insn "*divmodsi4_score3" + [(set (match_operand:SI 0 "score_register_operand" "=l") + (div:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d"))) + (set (match_operand:SI 3 "score_register_operand" "=h") + (mod:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" + "div\t%1, %2" + [(set_attr "type" "div") + (set_attr "mode" "SI")]) + +(define_expand "udivmodsi4" + [(parallel + [(set (match_operand:SI 0 "score_register_operand") + (udiv:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "score_register_operand"))) + (set (match_operand:SI 3 "score_register_operand") + (umod:SI (match_dup 1) (match_dup 2)))])] + "" + "" +) + +(define_insn "*udivmodsi4_score7" [(set (match_operand:SI 0 "register_operand" "=l") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=h") (umod:SI (match_dup 1) (match_dup 2)))] - "!TARGET_SCORE5U" + "(TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D)" "divu %1, %2" [(set_attr "type" "div") (set_attr "mode" "SI")]) -(define_insn "ashlsi3" +(define_insn "*udivmodsi4_score3" + [(set (match_operand:SI 0 "score_register_operand" "=l") + (udiv:SI (match_operand:SI 1 "score_register_operand" "d") + (match_operand:SI 2 "score_register_operand" "d"))) + (set (match_operand:SI 3 "score_register_operand" "=h") + (umod:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" + "divu\t%1, %2" + [(set_attr "type" "div") + (set_attr "mode" "SI")]) + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "score_register_operand") + (ashift:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" + "" +) + +(define_insn "*ashlsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (ashift:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ slli %0, %1, %c2 sll %0, %1, %2" [(set_attr "type" "arith") (set_attr "mode" "SI")]) -(define_insn "ashlsi3_ucc" +(define_insn "*ashlsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=e,d,d") + (ashift:SI (match_operand:SI 1 "score_register_operand" "0,d,d") + (match_operand:SI 2 "arith_operand" "J,J,d")))] + "(TARGET_SCORE3)" + "@ + slli!\t%0, %c2 + slli\t%0, %1, %c2 + sll\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "length" "2,4,4") + (set_attr "mode" "SI")]) + +(define_insn "*ashlsi3_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (ashift:SI (match_operand:SI 1 "register_operand" "d,d") @@ -829,12 +1644,12 @@ (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d,d") (ashift:SI (match_dup 1) (match_dup 2)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { switch (which_alternative) { - case 0: return mdp_select (operands, "slli", false, "c", true); - case 1: return mdp_select (operands, "sll", false, "", true); + case 0: return score_select (operands, "slli", false, "c", true); + case 1: return score_select (operands, "sll", false, "", true); default: gcc_unreachable (); } } @@ -842,51 +1657,41 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "ashlsi3_cmp" +(define_insn "*ashlsi3_ucc_score3" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (ashift:SI - (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 1 "score_register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] - "" + (set (match_operand:SI 0 "score_register_operand" "=d,d") + (ashift:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return mdp_select (operands, "slli", false, "c", true); - case 1: return mdp_select (operands, "sll", false, "", true); + case 0: return score_select (operands, "slli", false, "c", true); + case 1: return score_select (operands, "sll", false, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "arith_operand" "J,d")))] - "" - "@ - srai %0, %1, %c2 - sra %0, %1, %2" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "ashrsi3_ucc" +(define_insn "*ashlsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) - (compare:CC_NZ (ashiftrt:SI + (compare:CC_NZ (ashift:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") - (ashiftrt:SI (match_dup 1) (match_dup 2)))] - "" + (clobber (match_scratch:SI 0 "=d,d"))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { switch (which_alternative) { - case 0: return \"srai.c %0, %1, %c2\"; - case 1: return mdp_select (operands, "sra", false, "", true); + case 0: return score_select (operands, "slli", false, "c", true); + case 1: return score_select (operands, "sll", false, "", true); default: gcc_unreachable (); } } @@ -894,92 +1699,289 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "ashrsi3_cmp" +(define_insn "*ashlsi3_cmp_score3" [(set (reg:CC_NZ CC_REGNUM) - (compare:CC_NZ (ashiftrt:SI - (match_operand:SI 1 "register_operand" "d,d") + (compare:CC_NZ (ashift:SI + (match_operand:SI 1 "score_register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d,d"))] - "" + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return \"srai.c %0, %1, %c2\"; - case 1: return mdp_select (operands, "sra", false, "", true); + case 0: return score_select (operands, "slli", false, "c", true); + case 1: return score_select (operands, "sll", false, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "lshrsi3" + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "score_register_operand") + (ashiftrt:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" + "" +) + +(define_insn "*ashrsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ - srli %0, %1, %c2 - srl %0, %1, %2" + srai %0, %1, %c2 + sra %0, %1, %2" [(set_attr "type" "arith") (set_attr "mode" "SI")]) -(define_insn "lshrsi3_ucc" - [(set (reg:CC_NZ CC_REGNUM) - (compare:CC_NZ (lshiftrt:SI - (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "arith_operand" "J,d")) +(define_insn "*ashrsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (ashiftrt:SI (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")))] + "(TARGET_SCORE3)" + "@ + srai\t%0, %1, %c2 + sra\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "length" "4,4") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_ucc_score7" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ashiftrt:SI + (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d,d") - (lshiftrt:SI (match_dup 1) (match_dup 2)))] + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"srai.c\t%0, %1, %c2\"; + case 1: return score_select (operands, "sra", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ashiftrt:SI + (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d,d") + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" +{ + switch (which_alternative) + { + case 0: return \"srai.c\t%0, %1, %c2\"; + case 1: return score_select (operands, "sra", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "length" "4,4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_cmp_score7" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ashiftrt:SI + (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d"))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return \"srai.c\t%0, %1, %c2\"; + case 1: return score_select (operands, "sra", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "ashrsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (ashiftrt:SI + (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d"))] + "(TARGET_SCORE3)" +{ + switch (which_alternative) + { + case 0: return \"srai.c\t%0, %1, %c2\"; + case 1: return score_select (operands, "sra", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "length" "4,4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "score_register_operand") + (lshiftrt:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand")))] + "" "" +) + +(define_insn "*lshrsi3_score7" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "@ + srli %0, %1, %c2 + srl %0, %1, %2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=e,d,d") + (lshiftrt:SI (match_operand:SI 1 "score_register_operand" "0,d,d") + (match_operand:SI 2 "arith_operand" "J,J,d")))] + "(TARGET_SCORE3)" + "@ + srli!\t%0, %c2 + srli\t%0, %1, %c2 + srl\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "length" "2,4,4") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_ucc_score7" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (lshiftrt:SI + (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (set (match_operand:SI 0 "register_operand" "=d,d") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return score_select (operands, "srli", false, "c", true); + case 1: return score_select (operands, "srl", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (lshiftrt:SI + (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d,d") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return mdp_select (operands, "srli", false, "c", true); - case 1: return mdp_select (operands, "srl", false, "", true); + case 0: return score_select (operands, "srli", false, "c", true); + case 1: return score_select (operands, "srl", false, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "lshrsi3_cmp" +(define_insn "*lshrsi3_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=d,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + switch (which_alternative) + { + case 0: return score_select (operands, "srli", false, "c", true); + case 1: return score_select (operands, "srl", false, "", true); + default: gcc_unreachable (); + } +} + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (lshiftrt:SI + (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d,d"))] + "(TARGET_SCORE3)" { switch (which_alternative) { - case 0: return mdp_select (operands, "srli", false, "c", true); - case 1: return mdp_select (operands, "srl", false, "", true); + case 0: return score_select (operands, "srli", false, "c", true); + case 1: return score_select (operands, "srl", false, "", true); default: gcc_unreachable (); } } [(set_attr "type" "arith") + (set_attr "length" "4,4") (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "negsi2" +(define_expand "negsi2" + [(set (match_operand:SI 0 "score_register_operand") + (neg:SI (match_operand:SI 1 "score_register_operand")))] + "" + "" +) + +(define_insn "*negsi2_score7" [(set (match_operand:SI 0 "register_operand" "=d") (neg:SI (match_operand:SI 1 "register_operand" "d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "neg %0, %1" [(set_attr "type" "arith") (set_attr "mode" "SI")]) -(define_insn "*negsi2_cmp" +(define_insn "*negsi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d") + (neg:SI (match_operand:SI 1 "score_register_operand" "d")))] + "(TARGET_SCORE3)" + "neg\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "*negsi2_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=e,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ neg! %0, %1 neg.c %0, %1" @@ -987,13 +1989,25 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "negsi2_ucc" +(define_insn "*negsi2_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (neg:SI (match_operand:SI 1 "score_register_operand" "d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "neg.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*negsi2_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (neg:SI (match_operand:SI 1 "register_operand" "e,d")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=e,d") (neg:SI (match_dup 1)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ neg! %0, %1 neg.c %0, %1" @@ -1001,21 +2015,51 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "one_cmplsi2" +(define_insn "*negsi2_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (neg:SI (match_operand:SI 1 "score_register_operand" "d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (neg:SI (match_dup 1)))] + "(TARGET_SCORE3)" + "neg.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + + +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "score_register_operand") + (not:SI (match_operand:SI 1 "score_register_operand")))] + "" + "" +) + +(define_insn "*one_cmplsi2_score7" [(set (match_operand:SI 0 "register_operand" "=d") (not:SI (match_operand:SI 1 "register_operand" "d")))] - "" - "not %0, %1" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "not\t%0, %1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*one_cmplsi2_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d") + (not:SI (match_operand:SI 1 "score_register_operand" "d")))] + "(TARGET_SCORE3)" + "not\t%0, %1" [(set_attr "type" "arith") + (set_attr "length" "4") (set_attr "mode" "SI")]) -(define_insn "one_cmplsi2_ucc" +(define_insn "*one_cmplsi2_ucc_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=e,d") (not:SI (match_dup 1)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ not! %0, %1 not.c %0, %1" @@ -1023,12 +2067,25 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "one_cmplsi2_cmp" +(define_insn "*one_cmplsi2_ucc_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (not:SI (match_operand:SI 1 "score_register_operand" "d")) + (const_int 0))) + (set (match_operand:SI 0 "score_register_operand" "=d") + (not:SI (match_dup 1)))] + "(TARGET_SCORE3)" + "not.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*one_cmplsi2_cmp_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (not:SI (match_operand:SI 1 "register_operand" "e,d")) (const_int 0))) (clobber (match_scratch:SI 0 "=e,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ not! %0, %1 not.c %0, %1" @@ -1036,33 +2093,175 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "rotlsi3" +(define_insn "*one_cmplsi2_cmp_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (not:SI (match_operand:SI 1 "score_register_operand" "d")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "not.c\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "rotlsi3" + [(parallel + [(set (match_operand:SI 0 "score_register_operand") + (rotate:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand"))) + (clobber (reg:CC CC_REGNUM))])] + "" + "" +) + +(define_insn "*rotlsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (rotate:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d"))) (clobber (reg:CC CC_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ roli.c %0, %1, %c2 rol.c %0, %1, %2" [(set_attr "type" "arith") (set_attr "mode" "SI")]) -(define_insn "rotrsi3" +(define_insn "*rotlsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (rotate:SI (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d"))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" + "@ + roli.c\t%0, %1, %c2 + rol.c\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "length" "4,4") + (set_attr "mode" "SI")]) + +(define_expand "rotrsi3" + [(parallel + [(set (match_operand:SI 0 "score_register_operand") + (rotatert:SI (match_operand:SI 1 "score_register_operand") + (match_operand:SI 2 "arith_operand"))) + (clobber (reg:CC CC_REGNUM))])] + "" + "" +) + +(define_insn "*rotrsi3_score7" [(set (match_operand:SI 0 "register_operand" "=d,d") (rotatert:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "J,d"))) (clobber (reg:CC CC_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ rori.c %0, %1, %c2 ror.c %0, %1, %2" [(set_attr "type" "arith") (set_attr "mode" "SI")]) +(define_insn "*rotrsi3_score3" + [(set (match_operand:SI 0 "score_register_operand" "=d,d") + (rotatert:SI (match_operand:SI 1 "score_register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "J,d"))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" + "@ + rori.c\t%0, %1, %c2 + ror.c\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "length" "4,4") + (set_attr "mode" "SI")]) + +(define_insn "cbrancheqz" + [(set (pc) (if_then_else + (eq (match_operand:SI 0 "score_register_operand" "d") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" +{ + if (get_attr_length (insn) == 4) + return \"bcmpeqz\t%0, %1\"; + else + return \"cmpi!\t%0, 0\;beq!\t%1\"; +} + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 1) (pc)) (const_int -504)) + (le (minus (match_dup 1) (pc)) (const_int 502))) + (const_int 4) + (const_int 6)))]) + +(define_insn "cbrancheq" + [(set (pc) (if_then_else + (eq (match_operand:SI 0 "score_register_operand" "d") + (match_operand:SI 1 "score_register_operand" "d")) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" +{ + if (get_attr_length (insn) == 4) + return \"bcmpeq\t%0, %1, %2\"; + else + return \"cmp!\t%0, %1\;beq!\t%2\"; +} + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -504)) + (le (minus (match_dup 2) (pc)) (const_int 502))) + (const_int 4) + (const_int 6)))]) + +(define_insn "cbranchnez" + [(set (pc) (if_then_else + (ne (match_operand:SI 0 "score_register_operand" "d") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" +{ + if (get_attr_length (insn) == 4) + return \"bcmpnez\t%0, %1\"; + else + return \"cmpi!\t%0, 0\;bne\t%1\"; +} + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 1) (pc)) (const_int -504)) + (le (minus (match_dup 1) (pc)) (const_int 502))) + (const_int 4) + (const_int 6)))]) + +(define_insn "cbranchne" + [(set (pc) (if_then_else + (ne (match_operand:SI 0 "score_register_operand" "d") + (match_operand:SI 1 "score_register_operand" "d")) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "(TARGET_SCORE3)" +{ + if (get_attr_length (insn) == 4) + return \"bcmpne\t%0, %1, %2\"; + else + return \"cmp!\t%0, %1\;bne\t%2\"; +} + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -504)) + (le (minus (match_dup 2) (pc)) (const_int 502))) + (const_int 4) + (const_int 6)))]) + (define_expand "cmpsi" - [(match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "arith_operand" "")] + [(match_operand:SI 0 "score_register_operand") + (match_operand:SI 1 "arith_operand")] "" { cmp_op0 = operands[0]; @@ -1070,11 +2269,11 @@ DONE; }) -(define_insn "cmpsi_nz" +(define_insn "cmpsi_nz_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (match_operand:SI 0 "register_operand" "d,e,d") (match_operand:SI 1 "arith_operand" "L,e,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ cmpi.c %0, %c1 cmp! %0, %1 @@ -1083,11 +2282,25 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "cmpsi_n" +(define_insn "cmpsi_nz_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (match_operand:SI 0 "score_register_operand" "d,d,d") + (match_operand:SI 1 "arith_operand" "O,L,d")))] + "(TARGET_SCORE3)" + "@ + cmpi!\t%0, %c1 + cmpi.c\t%0, %c1 + cmp!\t %0, %1" + [(set_attr "type" "cmp") + (set_attr "length" "2,4,2") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "cmpsi_n_score7" [(set (reg:CC_N CC_REGNUM) (compare:CC_N (match_operand:SI 0 "register_operand" "d,e,d") (match_operand:SI 1 "arith_operand" "L,e,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ cmpi.c %0, %c1 cmp! %0, %1 @@ -1096,12 +2309,26 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "*cmpsi_to_addsi" +(define_insn "cmpsi_n_score3" + [(set (reg:CC_N CC_REGNUM) + (compare:CC_N (match_operand:SI 0 "score_register_operand" "d,d,d") + (match_operand:SI 1 "arith_operand" "O,L,d")))] + "(TARGET_SCORE3)" + "@ + cmpi!\t%0, %c1 + cmpi.c\t%0, %c1 + cmp!\t%0, %1" + [(set_attr "type" "cmp") + (set_attr "length" "2,4,2") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "*cmpsi_to_addsi_score7" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (match_operand:SI 1 "register_operand" "0,d") (neg:SI (match_operand:SI 2 "register_operand" "e,d")))) (clobber (match_scratch:SI 0 "=e,d"))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ add! %0, %2 add.c %0, %1, %2" @@ -1109,11 +2336,23 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) -(define_insn "cmpsi_cc" +(define_insn "*cmpsi_to_addsi_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (match_operand:SI 1 "score_register_operand" "d") + (neg:SI (match_operand:SI 2 "score_register_operand" "d")))) + (clobber (match_scratch:SI 0 "=d"))] + "(TARGET_SCORE3)" + "add.c\t%0, %1, %2" + [(set_attr "type" "cmp") + (set_attr "length" "4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "cmpsi_cc_score7" [(set (reg:CC CC_REGNUM) (compare:CC (match_operand:SI 0 "register_operand" "d,e,d") (match_operand:SI 1 "arith_operand" "L,e,d")))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "@ cmpi.c %0, %c1 cmp! %0, %1 @@ -1122,6 +2361,20 @@ (set_attr "up_c" "yes") (set_attr "mode" "SI")]) +(define_insn "cmpsi_cc_score3" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:SI 0 "score_register_operand" "d,d,d") + (match_operand:SI 1 "arith_operand" "O,L,d")))] + "(TARGET_SCORE3)" + "@ + cmpi!\t%0, %c1 + cmpi.c\t%0, %c1 + cmp!\t%0, %1" + [(set_attr "type" "cmp") + (set_attr "length" "2,4,2") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + (define_expand "beq" [(set (pc) (if_then_else (eq (reg:CC CC_REGNUM) (const_int 0)) @@ -1129,7 +2382,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bne" @@ -1139,7 +2392,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bgt" @@ -1149,7 +2402,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "ble" @@ -1159,7 +2412,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bge" @@ -1169,7 +2422,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "blt" @@ -1179,7 +2432,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bgtu" @@ -1189,7 +2442,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bleu" @@ -1199,7 +2452,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bgeu" @@ -1209,7 +2462,7 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) (define_expand "bltu" @@ -1219,10 +2472,10 @@ (pc)))] "" { - mda_gen_cmp (CCmode); + score_gen_cmp (CCmode); }) -(define_insn "branch_n" +(define_insn "*branch_n_score7" [(set (pc) (if_then_else (match_operator 0 "branch_n_operator" @@ -1230,11 +2483,24 @@ (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "b%C0 %1" [(set_attr "type" "branch")]) -(define_insn "branch_nz" +(define_insn "*branch_n_score3" + [(set (pc) + (if_then_else + (match_operator 0 "branch_n_operator" + [(reg:CC_N CC_REGNUM) + (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "(TARGET_SCORE3)" + "b%C0\t%1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*branch_nz_score7" [(set (pc) (if_then_else (match_operator 0 "branch_nz_operator" @@ -1242,21 +2508,48 @@ (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" "b%C0 %1" [(set_attr "type" "branch")]) -(define_insn "branch_cc" +(define_insn "*branch_nz_score3" [(set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC CC_REGNUM) + (match_operator 0 "branch_nz_operator" + [(reg:CC_NZ CC_REGNUM) (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "" - "b%C0 %1" - [(set_attr "type" "branch")]) + "(TARGET_SCORE3)" + "b%C0\t%1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + + +(define_insn "*branch_cc_score7" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(reg:CC CC_REGNUM) + (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "b%C0 %1" + [(set_attr "type" "branch")]) + +(define_insn "*branch_cc_score3" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(reg:CC CC_REGNUM) + (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "(TARGET_SCORE3)" + "b%C0\t%1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) (define_insn "jump" [(set (pc) @@ -1264,11 +2557,12 @@ "" { if (!flag_pic) - return \"j %0\"; + return \"j\t%0\"; else - return \"b %0\"; + return \"b\t%0\"; } - [(set_attr "type" "jump")]) + [(set_attr "type" "jump") + (set_attr "length" "4")]) (define_expand "sibcall" [(parallel [(call (match_operand 0 "" "") @@ -1276,135 +2570,235 @@ (use (match_operand 2 "" ""))])] "" { - mdx_call (operands, true); + score_call (operands, true); DONE; }) -(define_insn "sibcall_internal" +(define_insn "sibcall_internal_score7" [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "t,Z")) (match_operand 1 "" "")) (clobber (reg:SI RT_REGNUM))] - "SIBLING_CALL_P (insn)" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + && SIBLING_CALL_P (insn)" { if (!flag_pic) switch (which_alternative) { - case 0: return \"br%S0 %0\"; - case 1: return \"j %0\"; + case 0: return \"br%S0\t%0\"; + case 1: return \"j\t%0\"; default: gcc_unreachable (); } else switch (which_alternative) { - case 0: return \"mv r29, %0\;br r29\"; - case 1: return \"la r29, %0\;br r29\"; + case 0: return \"mv\tr29, %0\;br\tr29\"; + case 1: return \"la\tr29, %0\;br\tr29\"; default: gcc_unreachable (); } } [(set_attr "type" "call")]) +(define_insn "sibcall_internal_score3" + [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "t,Z")) + (match_operand 1 "" "")) + (clobber (reg:SI RT_REGNUM))] + "(TARGET_SCORE3) && (SIBLING_CALL_P (insn))" +{ + if (!flag_pic) + switch (which_alternative) + { + case 0: return \"br%S0\t%0\"; + case 1: return \"j\t%0\"; + default: gcc_unreachable (); + } + else + switch (which_alternative) + { + case 0: return \"mv!\tr29, %0\;br!\tr29\"; + case 1: return \"ldi48\tr29, %0\;br!\tr29\"; + default: gcc_unreachable (); + } +} + [(set_attr "type" "call") + (set_attr "length" "4,8")]) + (define_expand "sibcall_value" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (use (match_operand 3 "" ""))])] "" { - mdx_call_value (operands, true); + score_call_value (operands, true); DONE; }) -(define_insn "sibcall_value_internal" +(define_insn "sibcall_value_internal_score7" [(set (match_operand 0 "register_operand" "=d,d") (call (mem:SI (match_operand:SI 1 "call_insn_operand" "t,Z")) (match_operand 2 "" ""))) (clobber (reg:SI RT_REGNUM))] - "SIBLING_CALL_P (insn)" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + && SIBLING_CALL_P (insn)" { if (!flag_pic) switch (which_alternative) { - case 0: return \"br%S1 %1\"; - case 1: return \"j %1\"; + case 0: return \"br%S1\t%1\"; + case 1: return \"j\t%1\"; default: gcc_unreachable (); } else switch (which_alternative) { - case 0: return \"mv r29, %1\;br r29\"; - case 1: return \"la r29, %1\;br r29\"; + case 0: return \"mv\tr29, %1\;br\tr29\"; + case 1: return \"la\tr29, %1\;br\tr29\"; default: gcc_unreachable (); } } [(set_attr "type" "call")]) +(define_insn "sibcall_value_internal_score3" + [(set (match_operand 0 "score_register_operand" "=d,d") + (call (mem:SI (match_operand:SI 1 "call_insn_operand" "t,Z")) + (match_operand 2 "" ""))) + (clobber (reg:SI RT_REGNUM))] + "(TARGET_SCORE3) && (SIBLING_CALL_P (insn))" +{ + if (!flag_pic) + switch (which_alternative) + { + case 0: return \"br%S1\t%1\"; + case 1: return \"j\t%1\"; + default: gcc_unreachable (); + } + else + switch (which_alternative) + { + case 0: return \"mv!\tr29, %1\;br!\tr29\"; + case 1: return \"ldi48\tr29, %1\;br!\tr29\"; + default: gcc_unreachable (); + } +} + [(set_attr "length" "4,8") + (set_attr "type" "call")]) + (define_expand "call" [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" "")) (use (match_operand 2 "" ""))])] "" { - mdx_call (operands, false); + score_call (operands, false); DONE; }) -(define_insn "call_internal" +(define_insn "call_internal_score7" [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "d,Z")) (match_operand 1 "" "")) (clobber (reg:SI RA_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { if (!flag_pic) switch (which_alternative) { - case 0: return \"brl%S0 %0\"; - case 1: return \"jl %0\"; + case 0: return \"brl%S0\t%0\"; + case 1: return \"jl\t%0\"; default: gcc_unreachable (); } else switch (which_alternative) { - case 0: return \"mv r29, %0\;brl r29\"; - case 1: return \"la r29, %0\;brl r29\"; + case 0: return \"mv\tr29, %0\;brl\tr29\"; + case 1: return \"la\tr29, %0\;brl\tr29\"; default: gcc_unreachable (); } } [(set_attr "type" "call")]) +(define_insn "call_internal_score3" + [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "d,Z")) + (match_operand 1 "" "")) + (clobber (reg:SI RA_REGNUM))] + "(TARGET_SCORE3)" +{ + if (!flag_pic) + switch (which_alternative) + { + case 0: return \"brl!\t%0\"; + case 1: return \"jl\t%0\"; + default: gcc_unreachable (); + } + else + switch (which_alternative) + { + case 0: return \"mv!\tr29, %0\;brl!\tr29\"; + case 1: return \"ldi48\tr29, %0\;brl!\tr29\"; + default: gcc_unreachable (); + } +} + [(set_attr "length" "4,8") + (set_attr "type" "call")]) + (define_expand "call_value" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (use (match_operand 3 "" ""))])] "" { - mdx_call_value (operands, false); + score_call_value (operands, false); DONE; }) -(define_insn "call_value_internal" +(define_insn "call_value_internal_score7" [(set (match_operand 0 "register_operand" "=d,d") (call (mem:SI (match_operand:SI 1 "call_insn_operand" "d,Z")) (match_operand 2 "" ""))) (clobber (reg:SI RA_REGNUM))] - "" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" { if (!flag_pic) switch (which_alternative) { - case 0: return \"brl%S1 %1\"; - case 1: return \"jl %1\"; + case 0: return \"brl%S1\t%1\"; + case 1: return \"jl\t%1\"; default: gcc_unreachable (); } else switch (which_alternative) { - case 0: return \"mv r29, %1\;brl r29\"; - case 1: return \"la r29, %1\;brl r29\"; + case 0: return \"mv\tr29, %1\;brl\tr29\"; + case 1: return \"la\tr29, %1\;brl\tr29\"; default: gcc_unreachable (); } } [(set_attr "type" "call")]) +(define_insn "call_value_internal_score3" + [(set (match_operand 0 "score_register_operand" "=d,d") + (call (mem:SI (match_operand:SI 1 "call_insn_operand" "d,Z")) + (match_operand 2 "" ""))) + (clobber (reg:SI RA_REGNUM))] + "(TARGET_SCORE3)" +{ + if (!flag_pic) + switch (which_alternative) + { + case 0: return \"brl!\t%1\"; + case 1: return \"jl\t%1\"; + default: gcc_unreachable (); + } + else + switch (which_alternative) + { + case 0: return \"mv!\tr29, %1\;brl!\tr29\"; + case 1: return \"ldi48\tr29, %1\;brl!\tr29\"; + default: gcc_unreachable (); + } +} + [(set_attr "length" "4,8") + (set_attr "type" "call")]) + (define_expand "indirect_jump" - [(set (pc) (match_operand 0 "register_operand" "d"))] + [(set (pc) (match_operand 0 "score_register_operand" "d"))] "" { rtx dest; @@ -1413,44 +2807,105 @@ || GET_MODE (dest) != Pmode) operands[0] = copy_to_mode_reg (Pmode, dest); - emit_jump_insn (gen_indirect_jump_internal1 (operands[0])); + emit_jump_insn (gen_indirect_jump_internal_score (operands[0])); DONE; }) -(define_insn "indirect_jump_internal1" - [(set (pc) (match_operand:SI 0 "register_operand" "d"))] +(define_insn "indirect_jump_internal_score" + [(set (pc) (match_operand:SI 0 "score_register_operand" "d"))] "" "br%S0 %0" [(set_attr "type" "jump")]) +(define_expand "casesi" + [(match_operand:SI 0 "score_register_operand" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound + (match_operand:SI 2 "const_int_operand" "") ; total range + (match_operand:SI 3 "" "") ; table label + (match_operand:SI 4 "" "")] ; Out of range label + "TARGET_SCORE3" +{ + rtx reg; + if (operands[1] != const0_rtx) + { + reg = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (reg, operands[0], + GEN_INT (-INTVAL (operands[1])))); + operands[0] = reg; + } + + if (!CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'L')) + operands[2] = force_reg (SImode, operands[2]); + + reg = gen_reg_rtx (SImode); + emit_jump_insn (gen_score3_casesi_internal (operands[0], operands[2], + operands[3], operands[4], reg)); + DONE; +}) + +(define_insn "score3_casesi_internal" + [(parallel [(set (pc) + (if_then_else + (leu (match_operand:SI 0 "score_register_operand" "e") + (match_operand:SI 1 "arith_operand" "dL")) + (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4)) + (label_ref (match_operand 2 "" "")))) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CC CC_REGNUM)) + (clobber (match_operand:SI 4 "score_register_operand" "=e")) + (use (label_ref (match_dup 2)))])] + "TARGET_SCORE3 && !flag_pic" + "* + return score_output_casesi(operands); + " + [(set_attr "length" "20")]) + (define_expand "tablejump" [(set (pc) - (match_operand 0 "register_operand" "d")) + (match_operand 0 "score_register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "" { - emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1])); + if (TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + emit_jump_insn (gen_tablejump_internal_score7 (operands[0], operands[1])); + else if (TARGET_SCORE3) + emit_jump_insn (gen_tablejump_internal_score3 (operands[0], operands[1])); + DONE; }) -(define_insn "tablejump_internal1" +(define_insn "tablejump_internal_score7" [(set (pc) (match_operand:SI 0 "register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] - "" - "* - if (flag_pic) - return \"mv r29, %0\;.cpadd r29\;br r29\"; - else - return \"br%S0 %0\"; - " + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" +{ + if (flag_pic) + return \"mv\tr29, %0\;.cpadd\tr29\;br\tr29\"; + else + return \"br%S0\t%0\"; +} [(set_attr "type" "jump")]) +(define_insn "tablejump_internal_score3" + [(set (pc) + (match_operand:SI 0 "score_register_operand" "d")) + (use (label_ref (match_operand 1 "" "")))] + "(TARGET_SCORE3)" +{ + if (flag_pic) + return \"mv!\tr29, %0\;.cpadd\tr29\;br!\tr29\"; + else + return \"br%S0\t%0\"; +} + [(set_attr "type" "jump") + (set_attr "length" "8")]) + (define_expand "prologue" [(const_int 1)] "" { - mdx_prologue (); + score_prologue (); DONE; }) @@ -1458,7 +2913,7 @@ [(const_int 2)] "" { - mdx_epilogue (false); + score_epilogue (false); DONE; }) @@ -1466,15 +2921,22 @@ [(const_int 2)] "" { - mdx_epilogue (true); + score_epilogue (true); DONE; }) -(define_insn "return_internal" +(define_insn "return_internal_score7" [(return) (use (match_operand 0 "pmode_register_operand" "d"))] - "" - "br%S0 %0") + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "br%S0\t%0") + +(define_insn "return_internal_score3" + [(return) + (use (match_operand 0 "pmode_register_operand" "d"))] + "(TARGET_SCORE3)" + "br%S0\t%0" + [(set_attr "length" "4")]) (define_insn "nop" [(const_int 0)] @@ -1482,26 +2944,49 @@ "#nop!" ) -(define_insn "cpload" +(define_insn "cpload_score7" [(unspec_volatile:SI [(const_int 1)] CPLOAD)] - "flag_pic" - ".cpload r29" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + && flag_pic" + ".cpload\tr29" ) -(define_insn "cprestore_use_fp" +(define_insn "cpload_score3" + [(unspec_volatile:SI [(const_int 1)] CPLOAD)] + "(TARGET_SCORE3) && flag_pic" + ".cpload\tr29" + [(set_attr "length" "4")]) + +(define_insn "cprestore_use_fp_score7" [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE) (use (reg:SI FP_REGNUM))] - "flag_pic" - ".cprestore r2, %0" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + && flag_pic" + ".cprestore\tr2, %0" ) -(define_insn "cprestore_use_sp" +(define_insn "cprestore_use_fp_score3" + [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE) + (use (reg:SI FP_REGNUM))] + "(TARGET_SCORE3) && flag_pic" + ".cprestore\tr2, %0" + [(set_attr "length" "4")]) + +(define_insn "cprestore_use_sp_score7" [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE) (use (reg:SI SP_REGNUM))] - "flag_pic" - ".cprestore r0, %0" + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D) + && flag_pic" + ".cprestore\tr0, %0" ) +(define_insn "cprestore_use_sp_score3" + [(unspec_volatile:SI [(match_operand:SI 0 "" "")] CPRESTORE) + (use (reg:SI SP_REGNUM))] + "(TARGET_SCORE3) && flag_pic" + ".cprestore\tr0, %0" + [(set_attr "length" "4")]) + (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo (use (match_operand 1 "" "")) ; iterations; zero if unknown @@ -1509,20 +2994,20 @@ (use (match_operand 3 "" "")) ; loop level (use (match_operand 4 "" ""))] ; label "!TARGET_NHWLOOP" - { - if (INTVAL (operands[3]) > 1) - FAIL; +{ + if (INTVAL (operands[3]) > 1) + FAIL; - if (GET_MODE (operands[0]) == SImode) - { - rtx sr0 = gen_rtx_REG (SImode, CN_REGNUM); - emit_jump_insn (gen_doloop_end_si (sr0, operands[4])); - } - else - FAIL; + if (GET_MODE (operands[0]) == SImode) + { + rtx sr0 = gen_rtx_REG (SImode, CN_REGNUM); + emit_jump_insn (gen_doloop_end_si (sr0, operands[4])); + } + else + FAIL; - DONE; - }) + DONE; +}) (define_insn "doloop_end_si" [(set (pc) @@ -1534,8 +3019,692 @@ (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) - (clobber (reg:CC CC_REGNUM)) -] + (clobber (reg:CC CC_REGNUM))] "!TARGET_NHWLOOP" "bcnz %1" - [(set_attr "type" "branch")]) + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "pushsi_score7" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "register_operand" "d"))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "push!\t%1, [r0]" + [(set_attr "type" "store") + (set_attr "mode" "SI")]) + +(define_insn "pushsi_score3" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "register_operand" "d"))] + "(TARGET_SCORE3)" + "push!\t%1" + [(set_attr "type" "store") + (set_attr "length" "2") + (set_attr "mode" "SI")]) + +(define_insn "popsi_score7" + [(set (match_operand:SI 0 "register_operand" "=d") + (match_operand:SI 1 "pop_operand" ">"))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "pop!\t%0, [r0]" + [(set_attr "type" "store") + (set_attr "mode" "SI")]) + +(define_insn "popsi_score3" + [(set (match_operand:SI 0 "register_operand" "=d") + (match_operand:SI 1 "pop_operand" ">"))] + "(TARGET_SCORE3)" + "pop!\t%0" + [(set_attr "type" "store") + (set_attr "length" "2") + (set_attr "mode" "SI")]) + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" "")) + (clobber (reg:SI 0))])] + "(TARGET_SCORE3)" +{ + int regno, count, i; + + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[1]) != MEM + || XEXP (operands[1], 0) != stack_pointer_rtx + || GET_CODE (operands[0]) != REG) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[0]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + for (i = 0; i < count; i++) + XVECEXP (operands[3], 0, i) + = gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, regno + i), + gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx))); +}) + +(define_insn "" + [(match_parallel 0 "score_load_multiple_operation" + [(set (match_operand:SI 1 "register_operand" "=d") + (mem:SI (post_inc:SI (reg:SI SP_REGNUM))))])] + "(TARGET_SCORE3)" +{ + return score_rpop (operands); +} + [(set_attr "length" "2")]) + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" "")) + (clobber (reg:SI 0))])] + "(TARGET_SCORE3)" +{ + int regno, count, i; + + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != MEM + || XEXP (operands[0], 0) != stack_pointer_rtx + || GET_CODE (operands[1]) != REG) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[1]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + for (i = 0; i < count; i++) + XVECEXP (operands[3], 0, i) + = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)), + gen_rtx_REG (SImode, regno + i)); +}) + +(define_insn "" + [(match_parallel 0 "score_store_multiple_operation" + [(set (mem:SI (pre_dec:SI (reg:SI SP_REGNUM))) + (match_operand:SI 1 "register_operand" "d"))])] + "(TARGET_SCORE3)" +{ + return score_rpush (operands); +} + [(set_attr "length" "2")]) + +(define_peephole2 + [(set (match_operand:SI 0 "g32reg_operand" "") + (match_operand:SI 1 "loreg_operand" "")) + (set (match_operand:SI 2 "g32reg_operand" "") + (match_operand:SI 3 "hireg_operand" ""))] + "" + [(parallel + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))])]) + +(define_peephole2 + [(set (match_operand:SI 0 "g32reg_operand" "") + (match_operand:SI 1 "hireg_operand" "")) + (set (match_operand:SI 2 "g32reg_operand" "") + (match_operand:SI 3 "loreg_operand" ""))] + "" + [(parallel + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 0) (match_dup 1))])]) + +(define_insn "movhilo" + [(parallel + [(set (match_operand:SI 0 "register_operand" "=d") + (match_operand:SI 1 "loreg_operand" "")) + (set (match_operand:SI 2 "register_operand" "=d") + (match_operand:SI 3 "hireg_operand" ""))])] + "" + "mfcehl\t%2, %0" + [(set_attr "type" "fce") + (set_attr "mode" "SI")]) + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(reg:CC CC_REGNUM) (const_int 0)]) + (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")))] + "" +{ + score_movsicc (operands); +}) + +(define_insn "movsicc_internal_score7" + [(set (match_operand:SI 0 "register_operand" "=d") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(reg:CC CC_REGNUM) (const_int 0)]) + (match_operand:SI 2 "arith_operand" "d") + (match_operand:SI 3 "arith_operand" "0")))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "mv%C1\t%0, %2" + [(set_attr "type" "cndmv") + (set_attr "mode" "SI")]) + +(define_insn "movsicc_internal_score3" + [(set (match_operand:SI 0 "register_operand" "=d") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(reg:CC CC_REGNUM) (const_int 0)]) + (match_operand:SI 2 "arith_operand" "d") + (match_operand:SI 3 "arith_operand" "0")))] + "(TARGET_SCORE3)" + "mv%G1\t%0, %2" + [(set_attr "type" "cndmv") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "zero_extract_bittst_score7" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (unspec:SI + [(match_operand:SI 0 "register_operand" "*e,d") + (match_operand:SI 1 "const_uimm5" "")] + BITTST) + (const_int 0)))] + "(TARGET_SCORE5 || TARGET_SCORE5U || TARGET_SCORE7 || TARGET_SCORE7D)" + "@ + bittst!\t%0, %c1 + bittst.c\t%0, %c1" + [(set_attr "type" "arith") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_insn "zero_extract_bittst_score3" + [(set (reg:CC_NZ CC_REGNUM) + (compare:CC_NZ (unspec:SI + [(match_operand:SI 0 "register_operand" "e,d") + (match_operand:SI 1 "const_uimm5" "")] + BITTST) + (const_int 0)))] + "(TARGET_SCORE3)" + "@ + bittst!\t%0, %c1 + bittst.c\t%0, %c1" + [(set_attr "type" "arith") + (set_attr "length" "2,4") + (set_attr "up_c" "yes") + (set_attr "mode" "SI")]) + +(define_expand "extzv" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extract (match_operand:SI 1 "memory_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" +{ + if (score_unaligned_load (operands)) + DONE; + else + FAIL; +}) + +(define_expand "insv" + [(set (zero_extract (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "")) + (match_operand:SI 3 "register_operand" ""))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" +{ + if (score_unaligned_store (operands)) + DONE; + else + FAIL; +}) + +(define_expand "extv" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extract (match_operand:SI 1 "memory_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" +{ + if (score_unaligned_load (operands)) + DONE; + else + FAIL; +}) + +(define_expand "movmemsi" + [(parallel [(set (match_operand:BLK 0 "general_operand") + (match_operand:BLK 1 "general_operand")) + (use (match_operand:SI 2 "")) + (use (match_operand:SI 3 "const_int_operand"))])] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" +{ + if (score_block_move (operands)) + DONE; + else + FAIL; +}) + +(define_insn "move_lbu_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:QI 3 "register_operand" "=d") + (mem:QI (match_dup 1)))] + "" + "lbu\t%3, [%1]+, %2" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "QI")]) + +(define_insn "move_lhu_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:HI 3 "register_operand" "=d") + (mem:HI (match_dup 1)))] + "" + "lhu\t%3, [%1]+, %2" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "HI")]) + +(define_insn "move_lw_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:SI 3 "register_operand" "=d") + (mem:SI (match_dup 1)))] + "" + "lw\t%3, [%1]+, %2" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_sb_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:QI (match_dup 1)) + (match_operand:QI 3 "register_operand" "d"))] + "" + "sb\t%3, [%1]+, %2" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "QI")]) + +(define_insn "move_sh_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:HI (match_dup 1)) + (match_operand:HI 3 "register_operand" "d"))] + "" + "sh\t%3, [%1]+, %2" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "HI")]) + +(define_insn "move_sw_a" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:SI (match_dup 1)) + (match_operand:SI 3 "register_operand" "d"))] + "" + "sw\t%3, [%1]+, %2" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_lbu_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:QI 3 "register_operand" "=d") + (mem:QI (plus:SI (match_dup 1) + (match_dup 2))))] + "" + "lbu\t%3, [%1, %2]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "QI")]) + +(define_insn "move_lhu_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:HI 3 "register_operand" "=d") + (mem:HI (plus:SI (match_dup 1) + (match_dup 2))))] + "" + "lhu\t%3, [%1, %2]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "HI")]) + +(define_insn "move_lw_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (match_operand:SI 3 "register_operand" "=d") + (mem:SI (plus:SI (match_dup 1) + (match_dup 2))))] + "" + "lw\t%3, [%1, %2]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_sb_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:QI (plus:SI (match_dup 1) + (match_dup 2))) + (match_operand:QI 3 "register_operand" "d"))] + "" + "sb\t%3, [%1, %2]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "QI")]) + +(define_insn "move_sh_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:HI (plus:SI (match_dup 1) + (match_dup 2))) + (match_operand:HI 3 "register_operand" "d"))] + "" + "sh\t%3, [%1, %2]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "HI")]) + +(define_insn "move_sw_b" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_simm12" ""))) + (set (mem:SI (plus:SI (match_dup 1) + (match_dup 2))) + (match_operand:SI 3 "register_operand" "d"))] + "" + "sw\t%3, [%1, %2]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_lcb" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (reg:SI LC_REGNUM) + (unspec:SI [(mem:BLK (match_dup 1))] LCB))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "lcb\t[%1]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_lcw" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (match_operand:SI 2 "register_operand" "=d") + (unspec:SI [(mem:BLK (match_dup 1)) + (reg:SI LC_REGNUM)] LCW)) + (set (reg:SI LC_REGNUM) + (unspec:SI [(mem:BLK (match_dup 1))] LCB))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "lcw\t%2, [%1]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_lce" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (match_operand:SI 2 "register_operand" "=d") + (unspec:SI [(mem:BLK (match_dup 1)) + (reg:SI LC_REGNUM)] LCE))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "lce\t%2, [%1]+" + [(set_attr "type" "load") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_scb" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (mem:BLK (match_dup 1)) + (unspec:BLK [(match_operand:SI 2 "register_operand" "d")] SCB)) + (set (reg:SI SC_REGNUM) + (unspec:SI [(match_dup 2)] SCLC))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "scb\t%2, [%1]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_scw" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (mem:BLK (match_dup 1)) + (unspec:BLK [(match_operand:SI 2 "register_operand" "d") + (reg:SI SC_REGNUM)] SCW)) + (set (reg:SI SC_REGNUM) + (unspec:SI [(match_dup 2)] SCLC))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "scw\t%2, [%1]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "move_sce" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (const_int 4))) + (set (mem:BLK (match_dup 1)) + (unspec:BLK [(reg:SI SC_REGNUM)] SCE))] + "((TARGET_SCORE5 || TARGET_SCORE7 || TARGET_SCORE7D) + && (!TARGET_LITTLE_ENDIAN) && (TARGET_ULS)) + || (TARGET_SCORE3 && TARGET_ULS)" + "sce [%1]+" + [(set_attr "type" "store") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "andsi3_extzh" + [(set (match_operand:SI 0 "register_operand" "=d") + (and:SI (match_operand:SI 1 "register_operand" "d") + (const_int 65535)))] + "" + "extzh\t%0, %1" + [(set_attr "type" "arith") + (set_attr "length" "4") + (set_attr "mode" "SI")]) + +(define_insn "clzsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (clz:SI (match_operand:SI 1 "register_operand" "d")))] + "(TARGET_SCORE7D || TARGET_SCORE3)" + "clz\t%0, %1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (smax:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "max\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (smin:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "min\t%0, %1, %2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (abs:SI (match_operand:SI 1 "register_operand" "d")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "abs\t%0, %1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "sffs" + [(set (match_operand:SI 0 "register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "register_operand" "d")] SFFS))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "bitrev\t%0, %1, r0\;clz\t%0, %0\;addi\t%0, 0x1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "ffssi2" + [(set (match_operand:SI 0 "register_operand") + (ffs:SI (match_operand:SI 1 "register_operand")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" +{ + emit_insn (gen_sffs (operands[0], operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CC_NZmode, CC_REGNUM), + gen_rtx_COMPARE (CC_NZmode, operands[0], + GEN_INT (33)))); + if (TARGET_SCORE7D) + emit_insn (gen_movsicc_internal_score7 (operands[0], + gen_rtx_fmt_ee (EQ, VOIDmode, operands[0], GEN_INT (33)), + GEN_INT (0), + operands[0])); + else + emit_insn (gen_movsicc_internal_score3 (operands[0], + gen_rtx_fmt_ee (EQ, VOIDmode, operands[0], GEN_INT (33)), + GEN_INT (0), + operands[0])); + DONE; +}) + +(define_peephole2 + [(set (match_operand:SI 0 "loreg_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "hireg_operand" "") + (match_operand:SI 3 "register_operand" ""))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + [(parallel + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))])]) + +(define_peephole2 + [(set (match_operand:SI 0 "hireg_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "loreg_operand" "") + (match_operand:SI 3 "register_operand" ""))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + [(parallel + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 0) (match_dup 1))])]) + +(define_insn "movtohilo" + [(parallel + [(set (match_operand:SI 0 "loreg_operand" "=l") + (match_operand:SI 1 "register_operand" "d")) + (set (match_operand:SI 2 "hireg_operand" "=h") + (match_operand:SI 3 "register_operand" "d"))])] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "mtcehl\t%3, %1" + [(set_attr "type" "fce") + (set_attr "mode" "SI")]) + +(define_insn "mulsi3addsi" + [(set (match_operand:SI 0 "register_operand" "=l,l,d") + (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") + (match_operand:SI 3 "register_operand" "d,d,d")) + (match_operand:SI 1 "register_operand" "0,d,l"))) + (clobber (reg:SI HI_REGNUM))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "@ + mad\t%2, %3 + mtcel%S1\t%1\;mad\t%2, %3 + mad\t%2, %3\;mfcel%S0\t%0" + [(set_attr "mode" "SI")]) + +(define_insn "mulsi3subsi" + [(set (match_operand:SI 0 "register_operand" "=l,l,d") + (minus:SI (match_operand:SI 1 "register_operand" "0,d,l") + (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") + (match_operand:SI 3 "register_operand" "d,d,d")))) + (clobber (reg:SI HI_REGNUM))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "@ + msb\t%2, %3 + mtcel%S1\t%1\;msb\t%2, %3 + msb\t%2, %3\;mfcel%S0\t%0" + [(set_attr "mode" "SI")]) + +(define_insn "mulsidi3adddi" + [(set (match_operand:DI 0 "register_operand" "=x") + (plus:DI (mult:DI + (sign_extend:DI (match_operand:SI 2 "register_operand" "%d")) + (sign_extend:DI (match_operand:SI 3 "register_operand" "d"))) + (match_operand:DI 1 "register_operand" "0")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "mad\t%2, %3" + [(set_attr "mode" "DI")]) + +(define_insn "umulsidi3adddi" + [(set (match_operand:DI 0 "register_operand" "=x") + (plus:DI (mult:DI + (zero_extend:DI (match_operand:SI 2 "register_operand" "%d")) + (zero_extend:DI (match_operand:SI 3 "register_operand" "d"))) + (match_operand:DI 1 "register_operand" "0")))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "madu\t%2, %3" + [(set_attr "mode" "DI")]) + +(define_insn "mulsidi3subdi" + [(set (match_operand:DI 0 "register_operand" "=x") + (minus:DI + (match_operand:DI 1 "register_operand" "0") + (mult:DI + (sign_extend:DI (match_operand:SI 2 "register_operand" "%d")) + (sign_extend:DI (match_operand:SI 3 "register_operand" "d")))))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "msb\t%2, %3" + [(set_attr "mode" "DI")]) + +(define_insn "umulsidi3subdi" + [(set (match_operand:DI 0 "register_operand" "=x") + (minus:DI + (match_operand:DI 1 "register_operand" "0") + (mult:DI (zero_extend:DI + (match_operand:SI 2 "register_operand" "%d")) + (zero_extend:DI + (match_operand:SI 3 "register_operand" "d")))))] + "(TARGET_SCORE7D || TARGET_SCORE3D)" + "msbu\t%2, %3" + [(set_attr "mode" "DI")]) + diff --git a/gcc/config/score/score.opt b/gcc/config/score/score.opt index 2558530305f..e521f7a1f44 100644 --- a/gcc/config/score/score.opt +++ b/gcc/config/score/score.opt @@ -34,10 +34,6 @@ muls Target RejectNegative Report Mask(ULS) Enable unaligned load/store instruction -mmac -Target RejectNegative Report Mask(MAC) -Enable mac instruction - mscore5 Target RejectNegative Report Mask(SCORE5) Support SCORE 5 ISA @@ -53,3 +49,15 @@ Support SCORE 7 ISA 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 diff --git a/gcc/config/score/score3.c b/gcc/config/score/score3.c new file mode 100644 index 00000000000..f268cbaf2df --- /dev/null +++ b/gcc/config/score/score3.c @@ -0,0 +1,1945 @@ +/* score3.c for Sunplus S+CORE processor + 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 + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "recog.h" +#include "toplev.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" + +#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) +#define INS_BUF_SZ 128 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. */ +extern rtx cmp_op0, cmp_op1; +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 = current_function_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 && current_function_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 (current_function_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 (tree type, 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, 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 = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); + else + this = gen_rtx_REG (Pmode, ARG_REG_FIRST); + + /* Add DELTA to THIS. */ + 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, this, offset)); + } + + /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ + if (vcall_offset != 0) + { + rtx addr; + + /* Set TEMP1 to *THIS. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, this)); + + /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */ + addr = score3_add_offset (temp1, vcall_offset); + + /* Load the offset and add it to THIS. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); + emit_insn (gen_add3_insn (this, this, 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 *XLOC can + be legitimized in a way that the generic machinery might not expect, + put the new address in *XLOC and return true. */ +int +score3_legitimize_address (rtx *xloc) +{ + enum score_symbol_type symbol_type; + + if (score3_symbolic_constant_p (*xloc, &symbol_type) + && symbol_type == SYMBOL_GENERAL) + { + *xloc = score3_split_symbol (0, *xloc); + return 1; + } + + if (GET_CODE (*xloc) == PLUS + && GET_CODE (XEXP (*xloc, 1)) == CONST_INT) + { + rtx reg = XEXP (*xloc, 0); + if (!score3_valid_base_register_p (reg, 0)) + reg = copy_to_mode_reg (Pmode, reg); + *xloc = score3_add_offset (reg, INTVAL (XEXP (*xloc, 1))); + return 1; + } + return 0; +} + +/* 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, + tree type, int 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 (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 OVERRIDE_OPTIONS macro. */ +void +score3_override_options (void) +{ + flag_pic = false; + if (!flag_pic) + score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX; + else + { + score3_sdata_max = 0; + if (g_switch_set && (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 class) +{ + if (reg_class_subset_p (G16_REGS, class)) + return G16_REGS; + if (reg_class_subset_p (G32_REGS, class)) + return G32_REGS; + return class; +} + +/* Implement SECONDARY_INPUT_RELOAD_CLASS + and SECONDARY_OUTPUT_RELOAD_CLASS macro. */ +enum reg_class +score3_secondary_reload_class (enum reg_class class, + 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 (class)) + 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 class = GET_MODE_CLASS (mode); + + if (class == MODE_CC) + return regno == CC_REGNUM; + else if (regno == FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return class == MODE_INT; + else if (GP_REG_P (regno)) + return !(regno & 1) || (size <= UNITS_PER_WORD); + else if (CE_REG_P (regno)) + return (class == MODE_INT + && ((size <= UNITS_PER_WORD) + || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); + else + return (class == 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 FUNCTION_ARG_ADVANCE macro. */ +void +score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int 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 FUNCTION_ARG macro. */ +rtx +score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int 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 (tree valtype, tree func ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (valtype) + { + int unsignedp; + mode = TYPE_MODE (valtype); + unsignedp = TYPE_UNSIGNED (valtype); + mode = promote_mode (valtype, mode, &unsignedp, 1); + } + return gen_rtx_REG (mode, RT_REGNUM); +} + +/* Implement INITIALIZE_TRAMPOLINE macro. */ +void +score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN) +{ +#define FFCACHE "_flush_cache" +#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) + + rtx pfunc, pchain; + + pfunc = plus_constant (ADDR, CODE_SIZE); + pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode)); + + emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC); + emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN); + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE), + 0, 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 GO_IF_LEGITIMATE_ADDRESS macro. */ +int +score3_address_p (enum machine_mode mode, rtx x, int 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) +{ + 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 = (struct extern_list *) ggc_alloc (sizeof (struct 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 = -1; + 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, use for mv. */ + { + 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 (!current_function_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 (!current_function_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 (current_function_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))); +} + +void +score3_gen_cmp (enum machine_mode mode) +{ + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), + gen_rtx_COMPARE (mode, cmp_op0, cmp_op1))); +} + +/* 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, cmp_op0, cmp_op1))); +} + +/* 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 (); + } +} diff --git a/gcc/config/score/score3.h b/gcc/config/score/score3.h new file mode 100644 index 00000000000..098da9500d2 --- /dev/null +++ b/gcc/config/score/score3.h @@ -0,0 +1,159 @@ +/* score3.h for Sunplus S+CORE processor + 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 + . */ + +#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 (tree type, + 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 int score3_legitimize_address (rtx *xloc); +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 (tree decl); +extern void score3_asm_file_start (void); +extern void score3_asm_file_end (void); +extern void score3_override_options (void); +extern int score3_reg_class (int regno); +extern enum reg_class score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, + enum reg_class class); +extern enum reg_class +score3_secondary_reload_class (enum reg_class class, + 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, + tree type, + int 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, + tree type, + int named); +extern rtx score3_function_value (tree valtype, + tree func ATTRIBUTE_UNUSED, + enum machine_mode mode); +extern void score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN); +extern int score3_regno_mode_ok_for_base_p (int regno, int strict); +extern int score3_address_p (enum machine_mode mode, rtx x, int 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); +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_gen_cmp (enum machine_mode mode); +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 diff --git a/gcc/config/score/score7.c b/gcc/config/score/score7.c new file mode 100644 index 00000000000..34271cc36b2 --- /dev/null +++ b/gcc/config/score/score7.c @@ -0,0 +1,1849 @@ +/* score7.c for Sunplus S+CORE processor + 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 + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "recog.h" +#include "toplev.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 "score7.h" + +#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) +#define INS_BUF_SZ 128 + +/* Define the information needed to generate branch insns. This is + stored from the compare operation. */ +extern rtx cmp_op0, cmp_op1; +extern enum reg_class score_char_to_class[256]; + +static int score7_sdata_max; +static char score7_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 +score7_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 +score7_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 +score7_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)) <= SCORE7_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 +score7_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 +score7_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 score7_frame_info * +score7_cached_frame (void) +{ + static struct score7_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 score7_frame_info * +score7_compute_frame_size (HOST_WIDE_INT size) +{ + unsigned int regno; + struct score7_frame_info *f = score7_cached_frame (); + + memset (f, 0, sizeof (struct score7_frame_info)); + f->gp_reg_size = 0; + f->mask = 0; + f->var_size = SCORE7_STACK_ALIGN (size); + f->args_size = current_function_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 && current_function_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 (score7_save_reg_p (regno)) + { + f->gp_reg_size += GET_MODE_SIZE (SImode); + f->mask |= 1 << (regno - GP_REG_FIRST); + } + } + + if (current_function_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 +score7_valid_base_register_p (rtx x, int strict) +{ + if (!strict && GET_CODE (x) == SUBREG) + x = SUBREG_REG (x); + + return (GET_CODE (x) == REG + && score7_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 +score7_classify_address (struct score7_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 = SCORE7_ADD_REG; + info->reg = x; + info->offset = const0_rtx; + return score7_valid_base_register_p (info->reg, strict); + case PLUS: + info->type = SCORE7_ADD_REG; + info->reg = XEXP (x, 0); + info->offset = XEXP (x, 1); + return (score7_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 = SCORE7_ADD_REG; + info->reg = XEXP (x, 0); + info->offset = GEN_INT (GET_MODE_SIZE (mode)); + return score7_valid_base_register_p (info->reg, strict); + case CONST_INT: + info->type = SCORE7_ADD_CONST_INT; + return IMM_IN_RANGE (INTVAL (x), 15, 1); + case CONST: + case LABEL_REF: + case SYMBOL_REF: + info->type = SCORE7_ADD_SYMBOLIC; + return (score7_symbolic_constant_p (x, &info->symbol_type) + && (info->symbol_type == SYMBOL_GENERAL + || info->symbol_type == SYMBOL_SMALL_DATA)); + default: + return 0; + } +} + +bool +score7_return_in_memory (tree type, 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 +score7_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 +score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, + tree function) +{ + rtx this, 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 = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); + else + this = gen_rtx_REG (Pmode, ARG_REG_FIRST); + + /* Add DELTA to THIS. */ + 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, this, offset)); + } + + /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ + if (vcall_offset != 0) + { + rtx addr; + + /* Set TEMP1 to *THIS. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, this)); + + /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */ + addr = score7_add_offset (temp1, vcall_offset); + + /* Load the offset and add it to THIS. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); + emit_insn (gen_add3_insn (this, this, temp1)); + } + + /* Jump to the target function. */ + fnaddr = XEXP (DECL_RTL (function), 0); + insn = emit_call_insn (gen_sibcall_internal_score7 (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 +score7_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 +score7_split_symbol (rtx temp, rtx addr) +{ + rtx high = score7_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 *XLOC can + be legitimized in a way that the generic machinery might not expect, + put the new address in *XLOC and return true. */ +int +score7_legitimize_address (rtx *xloc) +{ + enum score_symbol_type symbol_type; + + if (score7_symbolic_constant_p (*xloc, &symbol_type) + && symbol_type == SYMBOL_GENERAL) + { + *xloc = score7_split_symbol (0, *xloc); + return 1; + } + + if (GET_CODE (*xloc) == PLUS + && GET_CODE (XEXP (*xloc, 1)) == CONST_INT) + { + rtx reg = XEXP (*xloc, 0); + if (!score7_valid_base_register_p (reg, 0)) + reg = copy_to_mode_reg (Pmode, reg); + *xloc = score7_add_offset (reg, INTVAL (XEXP (*xloc, 1))); + return 1; + } + return 0; +} + +/* 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 +score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int named, struct score7_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 +score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ + const char *fnname; + struct score7_frame_info *f = score7_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 +score7_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 +score7_symbolic_expression_p (rtx x) +{ + if (GET_CODE (x) == SYMBOL_REF) + return true; + + if (GET_CODE (x) == CONST) + return score7_symbolic_expression_p (XEXP (x, 0)); + + if (UNARY_P (x)) + return score7_symbolic_expression_p (XEXP (x, 0)); + + if (ARITHMETIC_P (x)) + return (score7_symbolic_expression_p (XEXP (x, 0)) + || score7_symbolic_expression_p (XEXP (x, 1))); + + return false; +} + +/* Choose the section to use for the constant rtx expression X that has + mode MODE. */ +section * +score7_select_rtx_section (enum machine_mode mode, rtx x, + unsigned HOST_WIDE_INT align) +{ + if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX) + return get_named_section (0, ".sdata", 0); + else if (flag_pic && score7_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 +score7_in_small_data_p (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 <= SCORE7_SDATA_MAX); +} + +/* Implement TARGET_ASM_FILE_START. */ +void +score7_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 +score7_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 OVERRIDE_OPTIONS macro. */ +void +score7_override_options (void) +{ + flag_pic = false; + if (!flag_pic) + score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX; + else + { + score7_sdata_max = 0; + if (g_switch_set && (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 +score7_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 +score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class) +{ + if (reg_class_subset_p (G16_REGS, class)) + return G16_REGS; + if (reg_class_subset_p (G32_REGS, class)) + return G32_REGS; + return class; +} + +/* Implement SECONDARY_INPUT_RELOAD_CLASS + and SECONDARY_OUTPUT_RELOAD_CLASS macro. */ +enum reg_class +score7_secondary_reload_class (enum reg_class class, + 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 (class)) + 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 */ +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. */ +int +score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) +{ + int size = GET_MODE_SIZE (mode); + enum mode_class class = GET_MODE_CLASS (mode); + + if (class == MODE_CC) + return regno == CC_REGNUM; + else if (regno == FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return class == MODE_INT; + else if (GP_REG_P (regno)) + /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */ + return !(regno & 1) || (size <= UNITS_PER_WORD); + else if (CE_REG_P (regno)) + return (class == MODE_INT + && ((size <= UNITS_PER_WORD) + || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); + else + return (class == 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 +score7_initial_elimination_offset (int from, + int to ATTRIBUTE_UNUSED) +{ + struct score7_frame_info *f = score7_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 FUNCTION_ARG_ADVANCE macro. */ +void +score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int named) +{ + struct score7_arg_info info; + score7_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 +score7_arg_partial_bytes (CUMULATIVE_ARGS *cum, + enum machine_mode mode, tree type, bool named) +{ + struct score7_arg_info info; + score7_classify_arg (cum, mode, type, named, &info); + return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0; +} + +/* Implement FUNCTION_ARG macro. */ +rtx +score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int named) +{ + struct score7_arg_info info; + + if (mode == VOIDmode || !named) + return 0; + + score7_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 +score7_function_value (tree valtype, tree func ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (valtype) + { + int unsignedp; + mode = TYPE_MODE (valtype); + unsignedp = TYPE_UNSIGNED (valtype); + mode = promote_mode (valtype, mode, &unsignedp, 1); + } + return gen_rtx_REG (mode, RT_REGNUM); +} + +/* Implement INITIALIZE_TRAMPOLINE macro. */ +void +score7_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN) +{ +#define FFCACHE "_flush_cache" +#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) + + rtx pfunc, pchain; + + pfunc = plus_constant (ADDR, CODE_SIZE); + pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode)); + + emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC); + emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN); + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE), + 0, 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 +score7_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 GO_IF_LEGITIMATE_ADDRESS macro. */ +int +score7_address_p (enum machine_mode mode, rtx x, int strict) +{ + struct score7_address_info addr; + + return score7_classify_address (&addr, mode, x, strict); +} + +/* Return a number assessing the cost of moving a register in class + FROM to class TO. */ +int +score7_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 +score7_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 +score7_address_insns (rtx x, enum machine_mode mode) +{ + struct score7_address_info addr; + int factor; + + if (mode == BLKmode) + factor = 1; + else + factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + if (score7_classify_address (&addr, mode, x, false)) + switch (addr.type) + { + case SCORE7_ADD_REG: + case SCORE7_ADD_CONST_INT: + return factor; + + case SCORE7_ADD_SYMBOLIC: + return factor * score7_symbol_insns (addr.symbol_type); + } + return 0; +} + +/* Implement TARGET_RTX_COSTS macro. */ +bool +score7_rtx_costs (rtx x, int code, int outer_code, int *total) +{ + 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 = score7_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 +score7_address_cost (rtx addr) +{ + return score7_address_insns (addr, SImode); +} + +/* Implement ASM_OUTPUT_EXTERNAL macro. */ +int +score7_output_external (FILE *file ATTRIBUTE_UNUSED, + tree decl, const char *name) +{ + register struct extern_list *p; + + if (score7_in_small_data_p (decl)) + { + p = (struct extern_list *) ggc_alloc (sizeof (struct 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 +score7_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 +score7_print_operand (FILE *file, rtx op, int c) +{ + enum rtx_code code = -1; + 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 == '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: + score7_print_operand_address (file, op); + break; + default: + output_addr_const (file, op); + } + } +} + +/* Implement PRINT_OPERAND_ADDRESS macro. */ +void +score7_print_operand_address (FILE *file, rtx x) +{ + struct score7_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 (score7_classify_address (&addr, mode, x, true)) + { + switch (addr.type) + { + case SCORE7_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 SCORE7_ADD_CONST_INT: + case SCORE7_ADD_SYMBOLIC: + output_addr_const (file, x); + return; + } + } + print_rtl (stderr, x); + gcc_unreachable (); +} + +/* Implement SELECT_CC_MODE macro. */ +enum machine_mode +score7_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; +} + +/* Generate the prologue instructions for entry into a S+core function. */ +void +score7_prologue (void) +{ +#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1 + + struct score7_frame_info *f = score7_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_score7 ()); + + for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--) + { + if (BITSET_P (f->mask, regno - GP_REG_FIRST)) + { + rtx mem = gen_rtx_MEM (SImode, + gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); + rtx reg = gen_rtx_REG (SImode, regno); + if (!current_function_calls_eh_return) + MEM_READONLY_P (mem) = 1; + EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg))); + } + } + + 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, SCORE7_PROLOGUE_TEMP_REGNUM), + GEN_INT (size))); + EMIT_PL (emit_insn + (gen_sub3_insn (stack_pointer_rtx, + stack_pointer_rtx, + gen_rtx_REG (Pmode, + SCORE7_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_score7 (GEN_INT (size - f->cprestore_size))); + else + emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size))); + } + +#undef EMIT_PL +} + +/* Generate the epilogue instructions in a S+core function. */ +void +score7_epilogue (int sibcall_p) +{ + struct score7_frame_info *f = score7_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, SCORE7_EPILOGUE_TEMP_REGNUM), + GEN_INT (size)); + emit_insn (gen_add3_insn (base, base, + gen_rtx_REG (Pmode, + SCORE7_EPILOGUE_TEMP_REGNUM))); + } + } + + if (base != stack_pointer_rtx) + emit_move_insn (stack_pointer_rtx, base); + + if (current_function_calls_eh_return) + emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + EH_RETURN_STACKADJ_RTX)); + + for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++) + { + if (BITSET_P (f->mask, regno - GP_REG_FIRST)) + { + rtx mem = gen_rtx_MEM (SImode, + gen_rtx_POST_INC (SImode, stack_pointer_rtx)); + rtx reg = gen_rtx_REG (SImode, regno); + + if (!current_function_calls_eh_return) + MEM_READONLY_P (mem) = 1; + + emit_insn (gen_popsi_score7 (reg, mem)); + } + } + + if (!sibcall_p) + emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM))); +} + +void +score7_gen_cmp (enum machine_mode mode) +{ + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), + gen_rtx_COMPARE (mode, cmp_op0, cmp_op1))); +} + +/* 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 +score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) +{ + HOST_WIDE_INT offset; + + score7_split_const (x, &x, &offset); + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + *symbol_type = score7_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 score7_offset_within_object_p (x, offset); + } + gcc_unreachable (); +} + +void +score7_movsicc (rtx *ops) +{ + enum machine_mode mode; + + mode = score7_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, cmp_op0, cmp_op1))); +} + +/* Call and sibcall pattern all need call this function. */ +void +score7_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_score7 (addr, ops[1])); + else + emit_call_insn (gen_call_internal_score7 (addr, ops[1])); +} + +/* Call value and sibcall value pattern all need call this function. */ +void +score7_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_score7 (result, addr, arg)); + else + emit_call_insn (gen_call_value_internal_score7 (result, addr, arg)); +} + +/* Machine Split */ +void +score7_movdi (rtx *ops) +{ + rtx dst = ops[0]; + rtx src = ops[1]; + rtx dst0 = score7_subw (dst, 0); + rtx dst1 = score7_subw (dst, 1); + rtx src0 = score7_subw (src, 0); + rtx src1 = score7_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 +score7_zero_extract_andi (rtx *ops) +{ + if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode)) + emit_insn (gen_zero_extract_bittst_score7 (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_score7 (ops[3], ops[0], + gen_int_mode (mask, SImode))); + } +} + +/* Check addr could be present as PRE/POST mode. */ +static bool +score7_pindex_mem (rtx addr) +{ + if (GET_CODE (addr) == MEM) + { + switch (GET_CODE (XEXP (addr, 0))) + { + case PRE_DEC: + case POST_DEC: + case PRE_INC: + case POST_INC: + return true; + default: + break; + } + } + return false; +} + +/* Output asm code for ld/sw insn. */ +static int +score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit) +{ + struct score7_address_info ai; + + gcc_assert (GET_CODE (ops[idata]) == REG); + gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true)); + + if (!score7_pindex_mem (ops[iaddr]) + && ai.type == SCORE7_ADD_REG + && GET_CODE (ai.offset) == CONST_INT + && G16_REG_P (REGNO (ops[idata])) + && G16_REG_P (REGNO (ai.reg))) + { + if (INTVAL (ai.offset) == 0) + { + ops[iaddr] = ai.reg; + return snprintf (ip, INS_BUF_SZ, + "!\t%%%d, [%%%d]", idata, iaddr); + } + if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM) + { + HOST_WIDE_INT offset = INTVAL (ai.offset); + if (SCORE_ALIGN_UNIT (offset, unit) + && CONST_OK_FOR_LETTER_P (offset >> unit, 'J')) + { + ops[iaddr] = ai.offset; + return snprintf (ip, INS_BUF_SZ, + "p!\t%%%d, %%c%d", idata, iaddr); + } + } + } + return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr); +} + +/* Output asm insn for load. */ +const char * +score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign) +{ + const char *pre_ins[] = + {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"}; + char *ip; + + strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]); + ip = score7_ins + strlen (score7_ins); + + if ((!sign && unit != SCORE_HWORD) + || (sign && unit != SCORE_BYTE)) + score7_pr_addr_post (ops, 0, 1, ip, unit); + else + snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1"); + + return score7_ins; +} + +/* Output asm insn for store. */ +const char * +score7_sinsn (rtx *ops, enum score_mem_unit unit) +{ + const char *pre_ins[] = {"sb", "sh", "sw"}; + char *ip; + + strcpy (score7_ins, pre_ins[unit]); + ip = score7_ins + strlen (score7_ins); + score7_pr_addr_post (ops, 1, 0, ip, unit); + return score7_ins; +} + +/* Output asm insn for load immediate. */ +const char * +score7_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, 8, 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 * +score7_move (rtx *ops) +{ + gcc_assert (GET_CODE (ops[0]) == REG); + gcc_assert (GET_CODE (ops[1]) == REG); + + if (G16_REG_P (REGNO (ops[0]))) + { + if (G16_REG_P (REGNO (ops[1]))) + return "mv!\t%0, %1"; + else + return "mlfh!\t%0, %1"; + } + else if (G16_REG_P (REGNO (ops[1]))) + return "mhfl!\t%0, %1"; + else + return "mv\t%0, %1"; +} + +/* Generate add insn. */ +const char * +score7_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 && G16_REG_P (REGNO (ops[0]))) + { + if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15)) + { + ops[2] = GEN_INT (ffs (v) - 1); + return "addei!\t%0, %c2"; + } + + if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15)) + { + ops[2] = GEN_INT (ffs (-v) - 1); + return "subei!\t%0, %c2"; + } + } + + if (set_cc) + return "addi.c\t%0, %c2"; + else + return "addi\t%0, %c2"; +} + +/* Output arith insn. */ +const char * +score7_select (rtx *ops, const char *inst_pre, + bool commu, const char *letter, bool set_cc) +{ + gcc_assert (GET_CODE (ops[0]) == REG); + gcc_assert (GET_CODE (ops[1]) == REG); + + if (set_cc && G16_REG_P (REGNO (ops[0])) + && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1) + && REGNO (ops[0]) == REGNO (ops[1])) + { + snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter); + return score7_ins; + } + + if (commu && set_cc && G16_REG_P (REGNO (ops[0])) + && G16_REG_P (REGNO (ops[1])) + && REGNO (ops[0]) == REGNO (ops[2])) + { + gcc_assert (GET_CODE (ops[2]) == REG); + snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter); + return score7_ins; + } + + if (set_cc) + snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter); + else + snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter); + return score7_ins; +} + diff --git a/gcc/config/score/score7.h b/gcc/config/score/score7.h new file mode 100644 index 00000000000..900aa6f4924 --- /dev/null +++ b/gcc/config/score/score7.h @@ -0,0 +1,157 @@ +/* score7.h for Sunplus S+CORE processor + 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 + . */ + +#ifndef GCC_SCORE7_H +#define GCC_SCORE7_H + +enum score7_address_type +{ + SCORE7_ADD_REG, + SCORE7_ADD_CONST_INT, + SCORE7_ADD_SYMBOLIC +}; + +struct score7_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 score7_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 score7_address_info +{ + enum score7_address_type type; + rtx reg; + rtx offset; + enum rtx_code code; + enum score_symbol_type symbol_type; +}; +#endif + +#define SCORE7_SDATA_MAX score7_sdata_max +#define SCORE7_STACK_ALIGN(LOC) (((LOC) + 3) & ~3) +#define SCORE7_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) +#define SCORE7_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) +#define SCORE7_DEFAULT_SDATA_MAX 8 + +extern int score7_symbolic_constant_p (rtx x, + enum score_symbol_type *symbol_type); +extern bool score7_return_in_memory (tree type, + tree fndecl ATTRIBUTE_UNUSED); +extern void score7_output_mi_thunk (FILE *file, + tree thunk_fndecl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, + HOST_WIDE_INT vcall_offset, + tree function); +extern int score7_legitimize_address (rtx *xloc); +extern void +score7_function_prologue (FILE *file, + HOST_WIDE_INT size ATTRIBUTE_UNUSED); +extern void +score7_function_epilogue (FILE *file, + HOST_WIDE_INT size ATTRIBUTE_UNUSED); +extern section *score7_select_rtx_section (enum machine_mode mode, rtx x, + unsigned HOST_WIDE_INT align); +extern bool score7_in_small_data_p (tree decl); +extern void score7_asm_file_start (void); +extern void score7_asm_file_end (void); +extern void score7_override_options (void); +extern int score7_reg_class (int regno); +extern enum reg_class score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, + enum reg_class class); +extern enum +reg_class score7_secondary_reload_class (enum reg_class class, + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x); +extern int score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c); +extern int score7_extra_constraint (rtx op, char c); +extern int score7_hard_regno_mode_ok (unsigned int regno, + enum machine_mode mode); +extern HOST_WIDE_INT +score7_initial_elimination_offset (int from, + int to ATTRIBUTE_UNUSED); +extern void score7_function_arg_advance (CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, + int named); +extern int score7_arg_partial_bytes (CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, + bool named); +extern rtx score7_function_arg (const CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, + int named); +extern rtx score7_function_value (tree valtype, + tree func ATTRIBUTE_UNUSED, + enum machine_mode mode); +extern void score7_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN); +extern int score7_regno_mode_ok_for_base_p (int regno, int strict); +extern int score7_address_p (enum machine_mode mode, rtx x, int strict); +extern int score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, + enum reg_class from, + enum reg_class to); +extern bool score7_rtx_costs (rtx x, int code, int outer_code, int *total); +extern int score7_address_cost (rtx addr); +extern int score7_output_external (FILE *file ATTRIBUTE_UNUSED, + tree decl, + const char *name); +extern rtx score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED); +extern void score7_print_operand (FILE *file, rtx op, int c); +extern void score7_print_operand_address (FILE *file, rtx x); +extern enum machine_mode score7_select_cc_mode (enum rtx_code op, + rtx x, + rtx y); +extern void score7_prologue (void); +extern void score7_epilogue (int sibcall_p); +extern void score7_gen_cmp (enum machine_mode mode); +extern void score7_call (rtx *ops, bool sib); +extern void score7_call_value (rtx *ops, bool sib); +extern void score7_movsicc (rtx *ops); +extern void score7_movdi (rtx *ops); +extern void score7_zero_extract_andi (rtx *ops); +extern const char * score7_select_add_imm (rtx *ops, bool set_cc); +extern const char * score7_select (rtx *ops, const char *inst_pre, bool commu, + const char *letter, bool set_cc); +extern const char * score7_move (rtx *ops); +extern const char * score7_limm (rtx *ops); +extern const char * +score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign); +extern const char * +score7_sinsn (rtx *ops, enum score_mem_unit unit); +#endif diff --git a/gcc/config/score/score7.md b/gcc/config/score/score7.md deleted file mode 100644 index abd2aad23bb..00000000000 --- a/gcc/config/score/score7.md +++ /dev/null @@ -1,45 +0,0 @@ -;; Machine description for Sunplus S+CORE -;; Sunplus S+CORE 7 Pipeline Description -;; 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 -;; . - -(define_automaton "score") - -(define_cpu_unit "core" "score") - -(define_insn_reservation "memory" 3 - (eq_attr "type" "load") - "core") - -(define_insn_reservation "mul" 3 - (eq_attr "type" "mul,div") - "core") - -(define_insn_reservation "fce" 1 - (eq_attr "type" "fce") - "core") - -(define_insn_reservation "tsr" 1 - (eq_attr "type" "tsr,fsr") - "core") - -(define_insn_reservation "up_c" 1 - (eq_attr "up_c" "yes") - "core") diff --git a/gcc/config/score/t-score-elf b/gcc/config/score/t-score-elf index d8bc89fe95c..f27484fea46 100644 --- a/gcc/config/score/t-score-elf +++ b/gcc/config/score/t-score-elf @@ -1,9 +1,16 @@ # Additional Backend Files -score-mdaux.o: $(srcdir)/config/score/score-mdaux.c $(CONFIG_H) $(SYSTEM_H) \ +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 toplev.h $(TM_P_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/score/score-mdaux.c + $(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 toplev.h $(TM_P_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/score/score3.c + # Assemble startup files. $(T)crti.o: $(srcdir)/config/score/crti.asm $(GCC_PASSES) @@ -35,8 +42,8 @@ dp-bit.c: $(srcdir)/config/fp-bit.c # without the $gp register. TARGET_LIBGCC2_CFLAGS = -G 0 -MULTILIB_OPTIONS = mmac mel fPIC -MULTILIB_MATCHES = fPIC=fpic +MULTILIB_OPTIONS = mscore3 mel +MULTILIB_MATCHES = mscore3=march?score3 EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o