diff options
48 files changed, 11829 insertions, 14 deletions
@@ -1,3 +1,8 @@ +2015-01-06 Eric Botcazou <ebotcazou@adacore.com> + + * configure.ac: Add Visium support. + * configure: Regenerate. + 2015-01-04 Andreas Schwab <schwab@linux-m68k.org> * configure.ac: Use OBJCOPY for OBJCOPY_FOR_TARGET. @@ -3317,6 +3317,10 @@ case "${target}" in # for explicit misaligned loads. noconfigdirs="$noconfigdirs target-libssp" ;; + visium-*-*) + # No hosted I/O support. + noconfigdirs="$noconfigdirs target-libssp" + ;; esac # Disable libstdc++-v3 for some systems. diff --git a/configure.ac b/configure.ac index 7205026..7c51079 100644 --- a/configure.ac +++ b/configure.ac @@ -667,6 +667,10 @@ case "${target}" in # for explicit misaligned loads. noconfigdirs="$noconfigdirs target-libssp" ;; + visium-*-*) + # No hosted I/O support. + noconfigdirs="$noconfigdirs target-libssp" + ;; esac # Disable libstdc++-v3 for some systems. diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 12c2f93..812f980 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2015-01-06 Eric Botcazou <ebotcazou@adacore.com> + + * config.gcc: Add Visium support. + * configure.ac: Likewise. + * configure: Regenerate. + * doc/extend.texi (interrupt attribute): Add Visium. + * doc/invoke.texi: Document Visium options. + * doc/install.texi: Document Visium target. + * doc/md.texi: Document Visium constraints. + * common/config/visium: New directory. + * config/visium: Likewise. + 2015-01-05 Segher Boessenkool <segher@kernel.crashing.org> * simplify-rtx.c (simplify_binary_operation_1): Handle more cases diff --git a/gcc/common/config/visium/visium-common.c b/gcc/common/config/visium/visium-common.c new file mode 100644 index 0000000..ce4541c --- /dev/null +++ b/gcc/common/config/visium/visium-common.c @@ -0,0 +1,38 @@ +/* Common hooks for Visium. + Copyright (C) 2002-2015 Free Software Foundation, Inc. + Contributed by C.Nettleton,J.P.Parkes and P.Garbett. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "common/common-target.h" +#include "common/common-target-def.h" + +/* Set default optimization options. */ +static const struct default_options visium_option_optimization_table[] = + { + { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, + { OPT_LEVELS_NONE, 0, NULL, 0 } + }; + +#undef TARGET_OPTION_OPTIMIZATION_TABLE +#define TARGET_OPTION_OPTIMIZATION_TABLE visium_option_optimization_table + +struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; diff --git a/gcc/config.gcc b/gcc/config.gcc index 878dbcc..857b3b0 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2888,6 +2888,10 @@ vax-*-openbsd*) extra_options="${extra_options} openbsd.opt" use_collect2=yes ;; +visium-*-elf*) + tm_file="dbxelf.h elfos.h ${tm_file} visium/elf.h newlib-stdint.h" + tmake_file="visium/t-visium visium/t-crtstuff" + ;; xstormy16-*-elf) # For historical reasons, the target files omit the 'x'. tm_file="dbxelf.h elfos.h newlib-stdint.h stormy16/stormy16.h" diff --git a/gcc/config/visium/constraints.md b/gcc/config/visium/constraints.md new file mode 100644 index 0000000..93900e8 --- /dev/null +++ b/gcc/config/visium/constraints.md @@ -0,0 +1,83 @@ +;; Constraint definitions for Visium. +;; Copyright (C) 2006-2015 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 +;; <http://www.gnu.org/licenses/>. + +;; Register constraints + +(define_register_constraint "b" "MDB" + "EAM register mdb") + +(define_register_constraint "c" "MDC" + "EAM register mdc") + +(define_register_constraint "f" "TARGET_FPU ? FP_REGS : NO_REGS" + "Floating point register") + +(define_register_constraint "k" "SIBCALL_REGS" + "Register for sibcall optimization") + +(define_register_constraint "l" "LOW_REGS" + "General register, but not r29, r30 and r31") + +(define_register_constraint "t" "R1" + "Register r1") + +(define_register_constraint "u" "R2" + "Register r2") + +(define_register_constraint "v" "R3" + "Register r3") + +;; Immediate integer operand constraints + +(define_constraint "J" + "Integer constant in the range 0 .. 65535 (16-bit immediate)" + (and (match_code "const_int") + (match_test "0 <= ival && ival <= 65535"))) + +(define_constraint "K" + "Integer constant in the range 1 .. 31 (5-bit immediate)" + (and (match_code "const_int") + (match_test "1 <= ival && ival <= 31"))) + +(define_constraint "L" + "Integer constant in the range -65535 .. -1 (16-bit negative immediate)" + (and (match_code "const_int") + (match_test "-65535 <= ival && ival <= -1"))) + +(define_constraint "M" + "Integer constant -1" + (and (match_code "const_int") + (match_test "ival == -1"))) + +(define_constraint "O" + "Integer constant 0" + (and (match_code "const_int") + (match_test "ival == 0"))) + +(define_constraint "P" + "Integer constant 32" + (and (match_code "const_int") + (match_test "ival == 32"))) + +;; Immediate FP operand constraints + +(define_constraint "G" + "Floating-point constant 0.0" + (and (match_code "const_double") + (match_test "op == CONST0_RTX (mode)"))) diff --git a/gcc/config/visium/elf.h b/gcc/config/visium/elf.h new file mode 100644 index 0000000..713773d --- /dev/null +++ b/gcc/config/visium/elf.h @@ -0,0 +1,25 @@ +/* ELF-specific defines for Visium. + Copyright (C) 2005-2015 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 + <http://www.gnu.org/licenses/>. */ + + +/* Turn on DWARF-2 frame unwinding. */ +#define INCOMING_FRAME_SP_OFFSET 0 +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGNUM) +#define DWARF_FRAME_REGNUM(REGNO) (REGNO) +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGNUM) diff --git a/gcc/config/visium/gr5.md b/gcc/config/visium/gr5.md new file mode 100644 index 0000000..9880b4d --- /dev/null +++ b/gcc/config/visium/gr5.md @@ -0,0 +1,145 @@ +;; Scheduling description for GR5. +;; Copyright (C) 2013-2015 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 +;; <http://www.gnu.org/licenses/>. + +;; GR5 is a single-issue processor. + +;; CPU execution units: +;; +;; issue Only one instruction can be issued on a given cycle. +;; There is no need to model the CPU pipeline in any +;; more detail than this. +;; +;; mem Memory Unit: all accesses to memory. +;; +;; eam Extended Arithmetic Module: multiply, divide and +;; 64-bit shifts. +;; +;; fp_slot[0|1|2|3] The 4 FIFO slots of the floating-point unit. Only +;; the instruction at slot 0 can execute, but an FP +;; instruction can issue if any of the slots is free. + +(define_automaton "gr5,gr5_fpu") + +(define_cpu_unit "gr5_issue" "gr5") +(define_cpu_unit "gr5_mem" "gr5") +(define_cpu_unit "gr5_eam" "gr5") +(define_cpu_unit "gr5_fp_slot0,gr5_fp_slot1,gr5_fp_slot2,gr5_fp_slot3" "gr5_fpu") + +;; The CPU instructions which write to general registers and so do not totally +;; complete until they reach the store stage of the pipeline. This is not the +;; complete storage register class: mem_reg, eam_reg and fpu_reg are excluded +;; since we must keep the reservation sets non-overlapping. +(define_insn_reservation "gr5_storage_register" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "imm_reg,arith,arith2,logic,call")) + "gr5_issue") + +(define_insn_reservation "gr5_read_mem" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "mem_reg")) + "gr5_issue + gr5_mem") + +;; The latency of 2 and the reservation of gr5_mem on the second cycle ensures +;; that no reads will be scheduled on the second cycle, which would otherwise +;; stall the pipeline for 1 cycle. +(define_insn_reservation "gr5_write_mem" 2 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "reg_mem")) + "gr5_issue, gr5_mem") + +;; Try to avoid the pipeline hazard of addressing off a register that has +;; not yet been stored. +(define_bypass 2 "gr5_storage_register" "gr5_read_mem" "gr5_hazard_bypass_p") +(define_bypass 2 "gr5_storage_register" "gr5_write_mem" "gr5_hazard_bypass_p") +(define_bypass 2 "gr5_read_mem" "gr5_read_mem" "gr5_hazard_bypass_p") +(define_bypass 2 "gr5_read_mem" "gr5_write_mem" "gr5_hazard_bypass_p") + +;; Other CPU instructions complete by the process stage. +(define_insn_reservation "gr5_cpu_other" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "abs_branch,branch,cmp,ret,rfi,dsi,nop")) + "gr5_issue") + +;; EAM instructions. + +(define_insn_reservation "gr5_write_eam" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "reg_eam")) + "gr5_issue") + +(define_reservation "gr5_issue_eam" "(gr5_issue + gr5_eam)") + +(define_insn_reservation "gr5_read_eam" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "eam_reg")) + "gr5_issue_eam") + +;; Try to avoid the pipeline hazard of addressing off a register that has +;; not yet been stored. +(define_bypass 2 "gr5_read_eam" "gr5_read_mem" "gr5_hazard_bypass_p") +(define_bypass 2 "gr5_read_eam" "gr5_write_mem" "gr5_hazard_bypass_p") + +(define_insn_reservation "gr5_shiftdi" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "shiftdi")) + "gr5_issue_eam") + +(define_insn_reservation "gr5_mul" 3 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "mul")) + "gr5_issue_eam, gr5_eam*2") + +(define_insn_reservation "gr5_div" 34 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "div")) + "gr5_issue_eam, gr5_eam*33") + +(define_insn_reservation "gr5_divd" 66 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "divd")) + "gr5_issue_eam, gr5_eam*65") + +;; FPU instructions. + +(define_reservation "gr5_fp_slotany" "(gr5_fp_slot0 | gr5_fp_slot1 | gr5_fp_slot2 | gr5_fp_slot3)") + +(define_insn_reservation "gr5_fp_other" 1 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "fp_reg,reg_fp,fcmp")) + "gr5_issue") + +(define_insn_reservation "gr5_fp_1cycle" 2 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "fmove,ftoi")) + "gr5_issue + gr5_fp_slotany, gr5_fp_slot0") + +(define_insn_reservation "gr5_fp_2cycle" 3 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "itof")) + "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*2") + +(define_insn_reservation "gr5_fp_3cycle" 4 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "fp")) + "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*3") + +(define_insn_reservation "gr5_fp_30cycle" 31 + (and (eq_attr "cpu" "gr5") + (eq_attr "type" "fdiv,fsqrt")) + "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*30") diff --git a/gcc/config/visium/gr6.md b/gcc/config/visium/gr6.md new file mode 100644 index 0000000..3129045 --- /dev/null +++ b/gcc/config/visium/gr6.md @@ -0,0 +1,186 @@ +;; Scheduling description for GR6. +;; Copyright (C) 2013-2015 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 +;; <http://www.gnu.org/licenses/>. + +;; GR6 is a dual-issue, superscalar, out-of-order processor. +;; +;; The GR6 pipeline has 3 major components: +;; 1. The FETCH/DECODE/DISPATCH stages, an in-order front-end, +;; 2. The PROCESS stage, which is the out-of-order core, +;; 3. The STORE stage, an in-order register storage stage. +;; +;; The front-end and the back-end (PROCESS + STORE) are connected through a set +;; of reservation stations which, among other things, serve as buffers for the +;; decoded instructions. The reservation stations are attached to a specific +;; execution unit of the PROCESS stage and the DISPATCH stage is responsible +;; for dispatching the decoded instructions to the appropriate stations. Most +;; execution units have multiple reservation stations, thus making it possible +;; to dispatch two instructions per unit on a given cycle, but only one of them +;; can be executed on the next cycle. +;; +;; Since the core executes the instructions out of order, the most important +;; consideration for performance tuning is to make sure that enough decoded +;; instructions are ready for execution in the PROCESS stage while not stalling +;; the front-end, i.e while not trying to dispatch a decoded instruction to an +;; execution unit whose reservation stations are full. Therefore, we do not +;; model the reservation stations (which is equivalent to pretending that there +;; is only one of them for each execution unit) but only the execution unit, +;; thus preserving some margin in case the unit itself stalls unexpectedly. + +;; CPU execution units: +;; +;; inst[1|2] The front-end: 2 instructions can be issued on a given +;; cycle by the FETCH/DECODE/DISPATCH stages, except for +;; the Block Move instructions. +;; +;; mov Move Execution Unit: immediate moves into registers. +;; +;; alu[1|2] The 2 Arithmetic and Logic Units: other instructions +;; operating on the registers. +;; +;; bru Branch Resolution Unit: all branches. +;; +;; mem_wr Memory Write Unit: all writes to memory. +;; +;; mem_rd Memory Read Unit: all reads from memory. +;; +;; mem_eam EAM interface: reads and writes from and to the EAM +;; and reads from the FP registers. +;; +;; eam Extended Arithmetic Module: multiply, divide and +;; 64-bit shifts. +;; +;; fpcu Floating-Point Compare Unit: FP comparisons. +;; +;; fpu[1|2|3|4] The 4 Floating-Point Units: all other instructions +;; operating on the FP registers. + +(define_automaton "gr6,gr6_fpu") + +(define_cpu_unit "gr6_inst1, gr6_inst2" "gr6") +(define_cpu_unit "gr6_mov" "gr6") +(define_cpu_unit "gr6_alu1,gr6_alu2" "gr6") +(define_cpu_unit "gr6_bru" "gr6") +(define_cpu_unit "gr6_mem_wr,gr6_mem_rd,gr6_mem_eam" "gr6") +(define_cpu_unit "gr6_eam" "gr6") +(define_cpu_unit "gr6_fpcu" "gr6") +(define_cpu_unit "gr6_fpu1,gr6_fpu2,gr6_fpu3,gr6_fpu4" "gr6_fpu") + +(define_reservation "gr6_issue" "(gr6_inst1 | gr6_inst2)") +(define_reservation "gr6_single_issue" "gr6_inst1 + gr6_inst2") + +(define_insn_reservation "gr6_immediate" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "imm_reg")) + "gr6_issue + gr6_mov") + +(define_insn_reservation "gr6_alu" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "arith,arith2,logic,cmp")) + "gr6_issue + (gr6_alu1 | gr6_alu2)") + +(define_insn_reservation "gr6_branch" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "abs_branch,branch,call,ret,rfi")) + "gr6_issue + gr6_bru") + +(define_insn_reservation "gr6_block_move" 16 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "bmi")) + "gr6_single_issue*16") + +(define_insn_reservation "gr6_cpu_other" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "dsi,nop")) + "gr6_issue") + +(define_insn_reservation "gr6_write_mem" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "reg_mem")) + "gr6_issue + gr6_mem_wr") + +(define_insn_reservation "gr6_read_mem" 6 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "mem_reg")) + "gr6_issue + gr6_mem_rd, nothing*5") + +;; EAM instructions. + +(define_insn_reservation "gr6_write_eam" 2 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "reg_eam")) + "gr6_issue + gr6_mem_eam, nothing") + +(define_reservation "gr6_issue_eam" "gr6_issue + gr6_mem_eam + gr6_eam") + +(define_insn_reservation "gr6_read_eam" 2 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "eam_reg")) + "gr6_issue_eam, nothing") + +(define_insn_reservation "gr6_shiftdi" 2 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "shiftdi")) + "gr6_issue_eam, gr6_eam") + +(define_insn_reservation "gr6_mul" 3 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "mul")) + "gr6_issue_eam, gr6_eam*2") + +(define_insn_reservation "gr6_div" 34 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "div")) + "gr6_issue_eam, gr6_eam*33") + +(define_insn_reservation "gr6_divd" 66 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "divd")) + "gr6_issue_eam, gr6_eam*65") + +;; FPU instructions. + +(define_insn_reservation "gr6_read_fp" 2 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "fp_reg")) + "gr6_issue + gr6_mem_eam, nothing") + +(define_insn_reservation "gr6_cmp_fp" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "fcmp")) + "gr6_issue + gr6_fpcu") + +(define_insn_reservation "gr6_fp_1cycle" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "fmove,ftoi,itof")) + "gr6_issue + gr6_fpu1") + +(define_insn_reservation "gr6_fp_3cycle" 3 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "fp")) + "gr6_issue + gr6_fpu2, nothing*2") + +(define_insn_reservation "gr6_fp_17cycle" 17 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "fdiv,fsqrt")) + "gr6_issue + gr6_fpu3, gr6_fpu3*14, nothing*2") + +(define_insn_reservation "gr6_write_fp" 1 + (and (eq_attr "cpu" "gr6") + (eq_attr "type" "reg_fp")) + "gr6_issue + gr6_fpu4") diff --git a/gcc/config/visium/predicates.md b/gcc/config/visium/predicates.md new file mode 100644 index 0000000..66d282e --- /dev/null +++ b/gcc/config/visium/predicates.md @@ -0,0 +1,157 @@ +;; Predicate definitions for Visium. +;; Copyright (C) 2005-2015 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 +;; <http://www.gnu.org/licenses/>. + +;; Return true if OP is the constant 0. +(define_predicate "const0_operand" + (and (match_code "const_int,const_double") + (match_test "op == CONST0_RTX (mode)"))) + +;; Return true if OP is a constant in the range 1 .. 31. +(define_predicate "const_shift_operand" + (and (match_code "const_int") + (match_test "1 <= INTVAL (op) && INTVAL (op) <= 31"))) + +;; Return true if OP is either a register or the constant 0. +(define_predicate "reg_or_0_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "const0_operand"))) + +;; Return true if OP is either a register or a constant in the range 1 .. 31. +(define_predicate "reg_or_shift_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "const_shift_operand"))) + +;; Return true if OP is either a register or the constant 32. +(define_predicate "reg_or_32_operand" + (ior (match_operand 0 "register_operand") + (and (match_code "const_int") + (match_test "INTVAL (op) == 32")))) + +;; Return true if OP is a general register. +(define_predicate "gpc_reg_operand" + (match_operand 0 "register_operand") +{ + if (GET_CODE (op) == SUBREG) + { + op = SUBREG_REG (op); + if (GET_CODE (op) != REG) + return 1; + } + + unsigned int regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER + || TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], regno)); +}) + +;; Return true if OP is the MDB register. +(define_predicate "mdb_reg_operand" + (match_operand 0 "register_operand") +{ + unsigned int regno = reg_or_subreg_regno (op); + return (regno == MDB_REGNUM); +}) + +;; Return true if OP is the MDC register. +(define_predicate "mdc_reg_operand" + (match_operand 0 "register_operand") +{ + unsigned int regno = reg_or_subreg_regno (op); + return (regno == MDC_REGNUM); +}) + +;; Return true if OP is an rvalue which is not an EAM register. +(define_predicate "non_eam_src_operand" + (match_operand 0 "general_operand") +{ + unsigned int regno = reg_or_subreg_regno (op); + return (regno != MDB_REGNUM && regno != MDC_REGNUM); +}) + +;; Return true if OP is an lvalue which is not an EAM register. +(define_predicate "non_eam_dst_operand" + (match_operand 0 "nonimmediate_operand") +{ + unsigned int regno = reg_or_subreg_regno (op); + return (regno != MDB_REGNUM && regno != MDC_REGNUM); +}) + +;; Return true if OP is a floating-point register. +(define_predicate "fp_reg_operand" + (match_code "reg") +{ + unsigned int regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || FP_REGISTER_P (regno)); +}) + +;; Return true if OP is a floating-point register or the constant 0. +(define_predicate "fp_reg_or_0_operand" + (ior (match_operand 0 "fp_reg_operand") + (match_operand 0 "const0_operand"))) + +;; Return true if OP can be used as the second operand in a 32-bit or 64-bit +;; add or subtract instruction. Note that adding a negative constant may be +;; transformed into subtracting a positive constant, and vice versa. +(define_predicate "add_operand" + (ior (match_operand 0 "gpc_reg_operand") + (and (match_code "const_int") + (match_test ("INTVAL (op) >= -65535 && INTVAL (op) <= 65535"))))) + +;; Return true if OP is (or could be) outside the range 0 .. 65535, which is +;; the range of the immediate operands, but accept -1 for NOT. +(define_predicate "large_immediate_operand" + (ior (match_code "const,label_ref,symbol_ref") + (and (match_code "const_int") + (match_test ("INTVAL (op) < -1 || INTVAL (op) > 65535"))))) + +;; Return true if OP is a valid FP comparison operator. +(define_predicate "visium_fp_comparison_operator" + (match_code "eq,ne,ordered,unordered,unlt,unle,ungt,unge,lt,le,gt,ge")) + +;; Return true if OP is a valid comparison operator for CC_BTSTmode. +(define_special_predicate "visium_btst_operator" + (match_code "eq,ne")) + +;; Return true if OP is a valid comparison operator for CC_NOOVmode. +(define_special_predicate "visium_noov_operator" + (match_code "eq,ne,ge,lt")) + +;; Return true if OP is a valid comparison operator for a branch. This allows +;; the use of MATCH_OPERATOR to recognize all the branch insns. +(define_predicate "visium_branch_operator" + (match_operand 0 "comparison_operator") +{ + enum rtx_code code = GET_CODE (op); + /* These 2 comparison codes are not supported. */ + if (code == UNEQ || code == LTGT) + return false; + enum machine_mode cc_mode = GET_MODE (XEXP (op, 0)); + if (cc_mode == CC_NOOVmode) + return visium_noov_operator (op, mode); + if (cc_mode == CC_BTSTmode) + return visium_btst_operator (op, mode); + return true; +}) + +;; Return true if OP is a valid comparison operator for an integer cstore. +(define_predicate "visium_int_cstore_operator" + (match_code "eq,ne,ltu,gtu,leu,geu")) + +;; Return true if OP is a valid comparison operator for an FP cstore. +(define_predicate "visium_fp_cstore_operator" + (match_code "lt,gt,unge,unle")) diff --git a/gcc/config/visium/t-visium b/gcc/config/visium/t-visium new file mode 100644 index 0000000..e06141c --- /dev/null +++ b/gcc/config/visium/t-visium @@ -0,0 +1,21 @@ +# Multilibs for Visium. +# Copyright (C) 2012-2015 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 +# <http://www.gnu.org/licenses/>. + +MULTILIB_OPTIONS = mcpu=gr6 +MULTILIB_DIRNAMES = gr6 diff --git a/gcc/config/visium/visium-modes.def b/gcc/config/visium/visium-modes.def new file mode 100644 index 0000000..8aa30d6 --- /dev/null +++ b/gcc/config/visium/visium-modes.def @@ -0,0 +1,37 @@ +/* Machine description for Visium. + Copyright (C) 2014-2015 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 +<http://www.gnu.org/licenses/>. */ + +/* Add any extra modes needed to represent the condition code. + + On the Visium, we have a "no-overflow" mode which is used when arithmetic + instructions set the condition code. Different branches are used in this + case for some operations. + + We also have a "bit-test" mode which is used when the bit-test instruction + sets the condition code. + + We also have two modes to indicate that the condition code is set by the + the floating-point unit. One for comparisons which generate an exception + if the result is unordered (CCFPEmode) and one for comparisons which never + generate such an exception (CCFPmode). */ + +CC_MODE (CC_NOOV); +CC_MODE (CC_BTST); +CC_MODE (CCFP); +CC_MODE (CCFPE); diff --git a/gcc/config/visium/visium-opts.h b/gcc/config/visium/visium-opts.h new file mode 100644 index 0000000..b438d52 --- /dev/null +++ b/gcc/config/visium/visium-opts.h @@ -0,0 +1,30 @@ +/* Definitions for option handling for Visium. + Copyright (C) 2005-2015 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 +<http://www.gnu.org/licenses/>. */ + +#ifndef VISIUM_OPTS_H +#define VISIUM_OPTS_H + +/* Processor type. + These must match the values for the cpu attribute in visium.md. */ +enum processor_type { + PROCESSOR_GR5, + PROCESSOR_GR6 +}; + +#endif diff --git a/gcc/config/visium/visium-protos.h b/gcc/config/visium/visium-protos.h new file mode 100644 index 0000000..5f36f28 --- /dev/null +++ b/gcc/config/visium/visium-protos.h @@ -0,0 +1,66 @@ +/* Prototypes of target machine for Visium. + Copyright (C) 2002-2015 Free Software Foundation, Inc. + Contributed by C.Nettleton,J.P.Parkes and P.Garbett. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_VISIUM_PROTOS_H +#define GCC_VISIUM_PROTOS_H + +extern unsigned int visium_data_alignment (tree, unsigned int); +extern void visium_init_expanders (void); +extern int visium_interrupt_function_p (void); +extern bool visium_can_use_return_insn_p (void); +extern void visium_expand_prologue (void); +extern void visium_expand_epilogue (void); +extern int visium_epilogue_uses (int); +extern void visium_profile_hook (void); +extern int visium_hard_regno_rename_ok (unsigned int, unsigned int); +extern int visium_initial_elimination_offset (int from, int to); +#ifdef RTX_CODE +extern void prepare_move_operands (rtx *, enum machine_mode); +extern bool ok_for_simple_move_operands (rtx *, enum machine_mode); +extern bool ok_for_simple_move_strict_operands (rtx *, enum machine_mode); +extern bool ok_for_simple_arith_logic_operands (rtx *, enum machine_mode); +extern void visium_initialize_trampoline (rtx, rtx, rtx); +extern int empty_delay_slot (rtx_insn *); +extern int gr5_hazard_bypass_p (rtx_insn *, rtx_insn *); +extern rtx visium_return_addr_rtx (int, rtx); +extern rtx visium_eh_return_handler_rtx (void); +extern rtx visium_dynamic_chain_address (rtx); +extern rtx visium_legitimize_reload_address (rtx, enum machine_mode, int, int, + int); +extern enum machine_mode visium_select_cc_mode (enum rtx_code, rtx, rtx); +extern void visium_split_cbranch (enum rtx_code, rtx, rtx, rtx); +extern const char *output_ubranch (rtx, rtx_insn *); +extern const char *output_cbranch (rtx, enum rtx_code, enum machine_mode, int, + rtx_insn *); +extern void notice_update_cc (rtx, rtx); +extern void print_operand (FILE *, rtx, int); +extern void print_operand_address (FILE *, rtx); +extern void split_double_move (rtx *, enum machine_mode); +extern void visium_expand_copysign (rtx *, enum machine_mode); +extern void visium_expand_int_cstore (rtx *, enum machine_mode); +extern void visium_expand_fp_cstore (rtx *, enum machine_mode); +extern void visium_split_cstore (enum rtx_code, rtx, rtx, + enum rtx_code, rtx, rtx); +extern int visium_expand_block_move (rtx *); +extern int visium_expand_block_set (rtx *); +extern unsigned int reg_or_subreg_regno (rtx); +#endif /* RTX_CODE */ + +#endif diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c new file mode 100644 index 0000000..c8efd15 --- /dev/null +++ b/gcc/config/visium/visium.c @@ -0,0 +1,4085 @@ +/* Output routines for Visium. + Copyright (C) 2002-2015 Free Software Foundation, Inc. + Contributed by C.Nettleton, J.P.Parkes and P.Garbett. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "calls.h" +#include "varasm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "expr.h" +#include "function.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "tm_p.h" +#include "ggc.h" +#include "optabs.h" +#include "target.h" +#include "target-def.h" +#include "common/common-target.h" +#include "predict.h" +#include "basic-block.h" +#include "gimple-expr.h" +#include "gimplify.h" +#include "langhooks.h" +#include "reload.h" +#include "tm-constrs.h" +#include "df.h" +#include "params.h" +#include "errors.h" +#include "tree-pass.h" +#include "context.h" +#include "builtins.h" + +/* Machine specific function data. */ +struct GTY (()) machine_function +{ + /* Size of the frame of the function. */ + int frame_size; + + /* Size of the reg parm save area, non-zero only for functions with variable + argument list. We cannot use the crtl->args.pretend_args_size machinery + for this purpose because this size is added to virtual_incoming_args_rtx + to give the location of the first parameter passed by the caller on the + stack and virtual_incoming_args_rtx is also the location of the first + parameter on the stack. So crtl->args.pretend_args_size can be non-zero + only if the first non-register named parameter is not passed entirely on + the stack and this runs afoul of the need to have a reg parm save area + even with a variable argument list starting on the stack because of the + separate handling of general and floating-point registers. */ + int reg_parm_save_area_size; + + /* True if we have created an rtx which relies on the frame pointer. */ + bool frame_needed; + + /* True if we have exposed the flags register. From this moment on, we + cannot generate simple operations for integer registers. We could + use reload_completed for this purpose, but this would cripple the + postreload CSE and GCSE passes which run before postreload split. */ + bool flags_exposed; +}; + +#define visium_frame_size cfun->machine->frame_size +#define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size +#define visium_frame_needed cfun->machine->frame_needed +#define visium_flags_exposed cfun->machine->flags_exposed + +/* 1 if the next opcode is to be specially indented. */ +int visium_indent_opcode = 0; + +/* Register number used for long branches when LR isn't available. It + must be a call-used register since it isn't saved on function entry. + We do not care whether the branch is predicted or not on the GR6, + given how unlikely it is to have a long branch in a leaf function. */ +static unsigned int long_branch_regnum = 31; + +static void visium_output_address (FILE *, enum machine_mode, rtx); +static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *); +static inline bool current_function_saves_fp (void); +static inline bool current_function_saves_lr (void); +static inline bool current_function_has_lr_slot (void); + +/* Supported attributes: + interrupt -- specifies this function is an interrupt handler. */ +static const struct attribute_spec visium_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, + affects_type_identity } */ + {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false}, + {NULL, 0, 0, false, false, false, NULL, false} +}; + +static struct machine_function *visium_init_machine_status (void); + +/* Target hooks and TARGET_INITIALIZER */ + +static bool visium_pass_by_reference (cumulative_args_t, enum machine_mode, + const_tree, bool); + +static rtx visium_function_arg (cumulative_args_t, enum machine_mode, + const_tree, bool); + +static void visium_function_arg_advance (cumulative_args_t, enum machine_mode, + const_tree, bool); + +static bool visium_return_in_memory (const_tree, const_tree fntype); + +static rtx visium_function_value (const_tree, const_tree fn_decl_or_type, + bool); + +static rtx visium_libcall_value (enum machine_mode, const_rtx); + +static void visium_setup_incoming_varargs (cumulative_args_t, + enum machine_mode, + tree, int *, int); + +static void visium_va_start (tree valist, rtx nextarg); + +static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *); + +static bool visium_function_ok_for_sibcall (tree, tree); + +static bool visium_frame_pointer_required (void); + +static tree visium_build_builtin_va_list (void); + +static tree visium_md_asm_clobbers (tree, tree, tree); + +static bool visium_legitimate_constant_p (enum machine_mode, rtx); + +static bool visium_legitimate_address_p (enum machine_mode, rtx, bool); + +static void visium_conditional_register_usage (void); + +static rtx visium_legitimize_address (rtx, rtx, enum machine_mode); + +static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t, + enum machine_mode, + secondary_reload_info *); + +static bool visium_class_likely_spilled_p (reg_class_t); + +static void visium_trampoline_init (rtx, tree, rtx); + +static int visium_issue_rate (void); + +static int visium_adjust_priority (rtx_insn *, int); + +static int visium_adjust_cost (rtx_insn *, rtx, rtx_insn *, int); + +static int visium_register_move_cost (enum machine_mode, reg_class_t, + reg_class_t); + +static int visium_memory_move_cost (enum machine_mode, reg_class_t, bool); + +static bool visium_rtx_costs (rtx, int, int, int, int *, bool); + +static void visium_option_override (void); + +static unsigned int visium_reorg (void); + +/* Setup the global target hooks structure. */ + +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET 31 + +#undef TARGET_PASS_BY_REFERENCE +#define TARGET_PASS_BY_REFERENCE visium_pass_by_reference + +#undef TARGET_FUNCTION_ARG +#define TARGET_FUNCTION_ARG visium_function_arg + +#undef TARGET_FUNCTION_ARG_ADVANCE +#define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY visium_return_in_memory + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE visium_function_value + +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE visium_libcall_value + +#undef TARGET_SETUP_INCOMING_VARARGS +#define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs + +#undef TARGET_EXPAND_BUILTIN_VA_START +#define TARGET_EXPAND_BUILTIN_VA_START visium_va_start + +#undef TARGET_BUILD_BUILTIN_VA_LIST +#define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list + +#undef TARGET_GIMPLIFY_VA_ARG_EXPR +#define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg + +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE visium_attribute_table + +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 + +#undef TARGET_STRICT_ARGUMENT_NAMING +#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true + +#undef TARGET_SCHED_ISSUE_RATE +#define TARGET_SCHED_ISSUE_RATE visium_issue_rate + +#undef TARGET_SCHED_ADJUST_PRIORITY +#define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority + +#undef TARGET_SCHED_ADJUST_COST +#define TARGET_SCHED_ADJUST_COST visium_adjust_cost + +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST visium_memory_move_cost + +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST visium_register_move_cost + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS visium_rtx_costs + +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall + +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required + +#undef TARGET_SECONDARY_RELOAD +#define TARGET_SECONDARY_RELOAD visium_secondary_reload + +#undef TARGET_CLASS_LIKELY_SPILLED_P +#define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p + +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE visium_option_override + +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage + +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT visium_trampoline_init + +#undef TARGET_MD_ASM_CLOBBERS +#define TARGET_MD_ASM_CLOBBERS visium_md_asm_clobbers + +#undef TARGET_FLAGS_REGNUM +#define TARGET_FLAGS_REGNUM FLAGS_REGNUM + +struct gcc_target targetm = TARGET_INITIALIZER; + +namespace { + +const pass_data pass_data_visium_reorg = +{ + RTL_PASS, /* type */ + "mach2", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_visium_reorg : public rtl_opt_pass +{ +public: + pass_visium_reorg(gcc::context *ctxt) + : rtl_opt_pass(pass_data_visium_reorg, ctxt) + {} + + /* opt_pass methods: */ + virtual unsigned int execute (function *) + { + return visium_reorg (); + } + +}; // class pass_work_around_errata + +} // anon namespace + +rtl_opt_pass * +make_pass_visium_reorg (gcc::context *ctxt) +{ + return new pass_visium_reorg (ctxt); +} + +/* Options override for Visium. */ + +static void +visium_option_override (void) +{ + if (flag_pic == 1) + warning (OPT_fpic, "-fpic is not supported"); + if (flag_pic == 2) + warning (OPT_fPIC, "-fPIC is not supported"); + + /* MCM is the default in the GR5/GR6 era. */ + target_flags |= MASK_MCM; + + /* FPU is the default with MCM, but don't override an explicit option. */ + if ((target_flags_explicit & MASK_FPU) == 0) + target_flags |= MASK_FPU; + + /* The supervisor mode is the default. */ + if ((target_flags_explicit & MASK_SV_MODE) == 0) + target_flags |= MASK_SV_MODE; + + /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */ + if (visium_cpu_and_features == PROCESSOR_GR6) + { + target_flags |= MASK_BMI; + if (target_flags & MASK_FPU) + target_flags |= MASK_FPU_IEEE; + } + + /* Set -mtune from -mcpu if not specified. */ + if (!global_options_set.x_visium_cpu) + visium_cpu = visium_cpu_and_features; + + /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword) + boundaries for GR6 so they start a new burst mode window. */ + if (align_functions == 0) + { + if (visium_cpu == PROCESSOR_GR6) + align_functions = 64; + else + align_functions = 256; + + /* Allow the size of compilation units to double because of inlining. + In practice the global size of the object code is hardly affected + because the additional instructions will take up the padding. */ + maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100, + global_options.x_param_values, + global_options_set.x_param_values); + } + + /* Likewise for loops. */ + if (align_loops == 0) + { + if (visium_cpu == PROCESSOR_GR6) + align_loops = 64; + else + { + align_loops = 256; + /* But not if they are too far away from a 256-byte boundary. */ + align_loops_max_skip = 31; + } + } + + /* Align all jumps on quadword boundaries for the burst mode, and even + on 8-quadword boundaries for GR6 so they start a new window. */ + if (align_jumps == 0) + { + if (visium_cpu == PROCESSOR_GR6) + align_jumps = 64; + else + align_jumps = 8; + } + + /* We register a machine-specific pass. This pass must be scheduled as + late as possible so that we have the (essentially) final form of the + insn stream to work on. Registering the pass must be done at start up. + It's convenient to do it here. */ + opt_pass *visium_reorg_pass = make_pass_visium_reorg (g); + struct register_pass_info insert_pass_visium_reorg = + { + visium_reorg_pass, /* pass */ + "dbr", /* reference_pass_name */ + 1, /* ref_pass_instance_number */ + PASS_POS_INSERT_AFTER /* po_op */ + }; + register_pass (&insert_pass_visium_reorg); +} + +/* Return the number of instructions that can issue on the same cycle. */ + +static int +visium_issue_rate (void) +{ + switch (visium_cpu) + { + case PROCESSOR_GR5: + return 1; + + case PROCESSOR_GR6: + return 2; + + default: + gcc_unreachable (); + } +} + +/* Return the adjusted PRIORITY of INSN. */ + +static int +visium_adjust_priority (rtx_insn *insn, int priority) +{ + /* On the GR5, we slightly increase the priority of writes in order to avoid + scheduling a read on the next cycle. This is necessary in addition to the + associated insn reservation because there are no data dependencies. + We also slightly increase the priority of reads from ROM in order to group + them as much as possible. These reads are a bit problematic because they + conflict with the instruction fetches, i.e. the data and instruction buses + tread on each other's toes when they are executed. */ + if (visium_cpu == PROCESSOR_GR5 + && reload_completed + && INSN_P (insn) + && recog_memoized (insn) >= 0) + { + enum attr_type attr_type = get_attr_type (insn); + if (attr_type == TYPE_REG_MEM + || (attr_type == TYPE_MEM_REG + && MEM_READONLY_P (SET_SRC (PATTERN (insn))))) + return priority + 1; + } + + return priority; +} + +/* Adjust the cost of a scheduling dependency. Return the new cost of + a dependency LINK of INSN on DEP_INSN. COST is the current cost. */ + +static int +visium_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost) +{ + enum attr_type attr_type; + + /* Don't adjust costs for true dependencies as they are described with + bypasses. But we make an exception for the first scheduling pass to + help the subsequent postreload compare elimination pass. */ + if (REG_NOTE_KIND (link) == REG_DEP_TRUE) + { + if (!reload_completed + && recog_memoized (insn) >= 0 + && get_attr_type (insn) == TYPE_CMP) + { + rtx pat = PATTERN (insn); + gcc_assert (GET_CODE (pat) == SET); + rtx src = SET_SRC (pat); + + /* Only the branches can be modified by the postreload compare + elimination pass, not the cstores because they accept only + unsigned comparison operators and they are eliminated if + one of the operands is zero. */ + if (GET_CODE (src) == IF_THEN_ELSE + && XEXP (XEXP (src, 0), 1) == const0_rtx + && recog_memoized (dep_insn) >= 0) + { + enum attr_type dep_attr_type = get_attr_type (dep_insn); + + /* The logical instructions use CCmode and thus work with any + comparison operator, whereas the arithmetic instructions use + CC_NOOVmode and thus work with only a small subset. */ + if (dep_attr_type == TYPE_LOGIC + || (dep_attr_type == TYPE_ARITH + && visium_noov_operator (XEXP (src, 0), + GET_MODE (XEXP (src, 0))))) + return 0; + } + } + + return cost; + } + + if (recog_memoized (insn) < 0) + return 0; + + attr_type = get_attr_type (insn); + + /* Anti dependency: DEP_INSN reads a register that INSN writes some + cycles later. */ + if (REG_NOTE_KIND (link) == REG_DEP_ANTI) + { + /* On the GR5, the latency of FP instructions needs to be taken into + account for every dependency involving a write. */ + if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5) + { + /* INSN is FLOAD. */ + rtx pat = PATTERN (insn); + rtx dep_pat = PATTERN (dep_insn); + + if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) + /* If this happens, we have to extend this to schedule + optimally. Return 0 for now. */ + return 0; + + if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat))) + { + if (recog_memoized (dep_insn) < 0) + return 0; + + switch (get_attr_type (dep_insn)) + { + case TYPE_FDIV: + case TYPE_FSQRT: + case TYPE_FTOI: + case TYPE_ITOF: + case TYPE_FP: + case TYPE_FMOVE: + /* A fload can't be issued until a preceding arithmetic + operation has finished if the target of the fload is + any of the sources (or destination) of the arithmetic + operation. Note that the latency may be (much) + greater than this if the preceding instruction + concerned is in a queue. */ + return insn_default_latency (dep_insn); + + default: + return 0; + } + } + } + + /* On the GR6, we try to make sure that the link register is restored + sufficiently ahead of the return as to yield a correct prediction + from the branch predictor. By default there is no true dependency + but an anti dependency between them, so we simply reuse it. */ + else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6) + { + rtx dep_pat = PATTERN (dep_insn); + if (GET_CODE (dep_pat) == SET + && REG_P (SET_DEST (dep_pat)) + && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM) + return 8; + } + + /* For other anti dependencies, the cost is 0. */ + return 0; + } + + /* Output dependency: DEP_INSN writes a register that INSN writes some + cycles later. */ + else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT) + { + /* On the GR5, the latency of FP instructions needs to be taken into + account for every dependency involving a write. */ + if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5) + { + /* INSN is FLOAD. */ + rtx pat = PATTERN (insn); + rtx dep_pat = PATTERN (dep_insn); + + if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) + /* If this happens, we have to extend this to schedule + optimally. Return 0 for now. */ + return 0; + + if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat))) + { + if (recog_memoized (dep_insn) < 0) + return 0; + + switch (get_attr_type (dep_insn)) + { + case TYPE_FDIV: + case TYPE_FSQRT: + case TYPE_FTOI: + case TYPE_ITOF: + case TYPE_FP: + case TYPE_FMOVE: + /* A fload can't be issued until a preceding arithmetic + operation has finished if the target of the fload is + the destination of the arithmetic operation. Note that + the latency may be (much) greater than this if the + preceding instruction concerned is in a queue. */ + return insn_default_latency (dep_insn); + + default: + return 0; + } + } + } + + /* For other output dependencies, the cost is 0. */ + return 0; + } + + return 0; +} + +/* Handle an "interrupt_handler" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +visium_handle_interrupt_attr (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + else if (!TARGET_SV_MODE) + { + error ("an interrupt handler cannot be compiled with -muser-mode"); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Return non-zero if the current function is an interrupt function. */ + +int +visium_interrupt_function_p (void) +{ + return + lookup_attribute ("interrupt", + DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE; +} + +/* Conditionally modify the settings of the register file. */ + +static void +visium_conditional_register_usage (void) +{ + /* If the supervisor mode is disabled, mask some general registers. */ + if (!TARGET_SV_MODE) + { + if (visium_cpu_and_features == PROCESSOR_GR5) + { + fixed_regs[24] = call_used_regs[24] = 1; + fixed_regs[25] = call_used_regs[25] = 1; + fixed_regs[26] = call_used_regs[26] = 1; + fixed_regs[27] = call_used_regs[27] = 1; + fixed_regs[28] = call_used_regs[28] = 1; + call_really_used_regs[24] = 0; + call_really_used_regs[25] = 0; + call_really_used_regs[26] = 0; + call_really_used_regs[27] = 0; + call_really_used_regs[28] = 0; + } + + fixed_regs[31] = call_used_regs[31] = 1; + call_really_used_regs[31] = 0; + + /* We also need to change the long-branch register. */ + if (visium_cpu_and_features == PROCESSOR_GR5) + long_branch_regnum = 20; + else + long_branch_regnum = 28; + } + + /* If the FPU is disabled, mask the FP registers. */ + if (!TARGET_FPU) + { + for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++) + { + fixed_regs[i] = call_used_regs[i] = 1; + call_really_used_regs[i] = 0; + } + } +} + +/* Prepend to CLOBBERS hard registers that are automatically clobbered for + an asm We do this for the FLAGS to maintain source compatibility with + the original cc0-based compiler. */ + +static tree +visium_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED, + tree inputs ATTRIBUTE_UNUSED, + tree clobbers) +{ + const char *flags = reg_names[FLAGS_REGNUM]; + return tree_cons (NULL_TREE, build_string (strlen (flags), flags), clobbers); +} + +/* Return true if X is a legitimate constant for a MODE immediate operand. + X is guaranteed to satisfy the CONSTANT_P predicate. */ + +static bool +visium_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x ATTRIBUTE_UNUSED) +{ + return true; +} + +/* Compute the alignment for a variable. The alignment of an aggregate is + set to be at least that of a scalar less than or equal to it in size. */ + +unsigned int +visium_data_alignment (tree type, unsigned int align) +{ + if (AGGREGATE_TYPE_P (type) + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32) + { + if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32) + return 32; + + if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16) + return 16; + } + + return align; +} + +/* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if + it is OK to rename a hard register FROM to another hard register TO. */ + +int +visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED, + unsigned int to) +{ + /* If the function doesn't save LR, then the long-branch register will be + used for long branches so we need to know whether it is live before the + frame layout is computed. */ + if (!current_function_saves_lr () && to == long_branch_regnum) + return 0; + + /* Interrupt functions can only use registers that have already been + saved by the prologue, even if they would normally be call-clobbered. */ + if (crtl->is_leaf + && !df_regs_ever_live_p (to) + && visium_interrupt_function_p ()) + return 0; + + return 1; +} + +/* Return true if it is ok to do sibling call optimization for the specified + call expression EXP. DECL will be the called function, or NULL if this + is an indirect call. */ + +static bool +visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED) +{ + return !visium_interrupt_function_p (); +} + +/* Prepare operands for a move define_expand in MODE. */ + +void +prepare_move_operands (rtx *operands, enum machine_mode mode) +{ + /* If the output is not a register, the input must be. */ + if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode)) + operands[1] = force_reg (mode, operands[1]); +} + +/* Return true if the operands are valid for a simple move insn. */ + +bool +ok_for_simple_move_operands (rtx *operands, enum machine_mode mode) +{ + /* One of the operands must be a register. */ + if (!register_operand (operands[0], mode) + && !reg_or_0_operand (operands[1], mode)) + return false; + + /* Once the flags are exposed, no simple moves between integer registers. */ + if (visium_flags_exposed + && gpc_reg_operand (operands[0], mode) + && gpc_reg_operand (operands[1], mode)) + return false; + + return true; +} + +/* Return true if the operands are valid for a simple move strict insn. */ + +bool +ok_for_simple_move_strict_operands (rtx *operands, enum machine_mode mode) +{ + /* Once the flags are exposed, no simple moves between integer registers. + Note that, in QImode only, a zero source counts as an integer register + since it will be emitted as r0. */ + if (visium_flags_exposed + && gpc_reg_operand (operands[0], mode) + && (gpc_reg_operand (operands[1], mode) + || (mode == QImode && operands[1] == const0_rtx))) + return false; + + return true; +} + +/* Return true if the operands are valid for a simple arithmetic or logical + insn. */ + +bool +ok_for_simple_arith_logic_operands (rtx *, enum machine_mode) +{ + /* Once the flags are exposed, no simple arithmetic or logical operations + between integer registers. */ + return !visium_flags_exposed; +} + +/* Return non-zero if a branch or call instruction will be emitting a nop + into its delay slot. */ + +int +empty_delay_slot (rtx_insn *insn) +{ + rtx seq; + + /* If no previous instruction (should not happen), return true. */ + if (PREV_INSN (insn) == NULL) + return 1; + + seq = NEXT_INSN (PREV_INSN (insn)); + if (GET_CODE (PATTERN (seq)) == SEQUENCE) + return 0; + + return 1; +} + +/* Wrapper around single_set which returns the first SET of a pair if the + second SET is to the flags register. */ + +static rtx +single_set_and_flags (rtx_insn *insn) +{ + if (multiple_sets (insn)) + { + rtx pat = PATTERN (insn); + if (XVECLEN (pat, 0) == 2 + && GET_CODE (XVECEXP (pat, 0, 1)) == SET + && REG_P (SET_DEST (XVECEXP (pat, 0, 1))) + && REGNO (SET_DEST (XVECEXP (pat, 0, 1))) == FLAGS_REGNUM) + return XVECEXP (pat, 0, 0); + } + + return single_set (insn); +} + +/* This is called with OUT_INSN an instruction setting a (base) register + and IN_INSN a read or a write. Return 1 if these instructions together + constitute a pipeline hazard. + + On the original architecture, a pipeline data hazard occurs when the Dest + of one instruction becomes the SrcA for an immediately following READ or + WRITE instruction with a non-zero index (indexing occurs at the decode + stage and so a NOP must be inserted in-between for this to work). + + An example is: + + move.l r2,r1 + read.l r4,10(r2) + + On the MCM, the non-zero index condition is lifted but the hazard is + patched up by the hardware through the injection of wait states: + + move.l r2,r1 + read.l r4,(r2) + + We nevertheless try to schedule instructions around this. */ + +int +gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) +{ + rtx out_set, in_set, dest, memexpr; + unsigned int out_reg, in_reg; + + /* A CALL is storage register class, but the link register is of no + interest here. */ + if (GET_CODE (out_insn) == CALL_INSN) + return 0; + + out_set = single_set_and_flags (out_insn); + dest = SET_DEST (out_set); + + /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only + occurs prior to reload. */ + if (GET_CODE (dest) == MEM) + return 0; + + if (GET_CODE (dest) == STRICT_LOW_PART) + dest = XEXP (dest, 0); + if (GET_CODE (dest) == SUBREG) + dest = SUBREG_REG (dest); + out_reg = REGNO (dest); + + in_set = single_set_and_flags (in_insn); + + /* If IN_INSN is MEM := MEM, it's the source that counts. */ + if (GET_CODE (SET_SRC (in_set)) == MEM) + memexpr = XEXP (SET_SRC (in_set), 0); + else + memexpr = XEXP (SET_DEST (in_set), 0); + + if (GET_CODE (memexpr) == PLUS) + { + memexpr = XEXP (memexpr, 0); + if (GET_CODE (memexpr) == SUBREG) + in_reg = REGNO (SUBREG_REG (memexpr)); + else + in_reg = REGNO (memexpr); + + if (in_reg == out_reg) + return 1; + } + else if (TARGET_MCM) + { + if (GET_CODE (memexpr) == STRICT_LOW_PART) + memexpr = XEXP (memexpr, 0); + if (GET_CODE (memexpr) == SUBREG) + memexpr = SUBREG_REG (memexpr); + in_reg = REGNO (memexpr); + + if (in_reg == out_reg) + return 1; + } + + return 0; +} + +/* Return true if INSN is an empty asm instruction. */ + +static bool +empty_asm_p (rtx insn) +{ + rtx body = PATTERN (insn); + const char *templ; + + if (GET_CODE (body) == ASM_INPUT) + templ = XSTR (body, 0); + else if (asm_noperands (body) >= 0) + templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); + else + templ = NULL; + + return (templ && templ[0] == '\0'); +} + +/* Insert a NOP immediately before INSN wherever there is a pipeline hazard. + LAST_REG records the register set in the last insn and LAST_INSN_CALL + records whether the last insn was a call insn. */ + +static void +gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call) +{ + unsigned int dest_reg = 0; + rtx set; + + switch (GET_CODE (insn)) + { + case CALL_INSN: + *last_reg = 0; + *last_insn_call = true; + return; + + case JUMP_INSN: + /* If this is an empty asm, just skip it. */ + if (!empty_asm_p (insn)) + { + *last_reg = 0; + *last_insn_call = false; + } + return; + + case INSN: + /* If this is an empty asm, just skip it. */ + if (empty_asm_p (insn)) + return; + break; + + default: + return; + } + + set = single_set_and_flags (insn); + if (set != NULL_RTX) + { + rtx dest = SET_DEST (set); + const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD; + rtx memrtx = NULL; + + if (GET_CODE (SET_SRC (set)) == MEM) + { + memrtx = XEXP (SET_SRC (set), 0); + if (GET_CODE (dest) == STRICT_LOW_PART) + dest = XEXP (dest, 0); + if (REG_P (dest)) + dest_reg = REGNO (dest); + + /* If this is a DI or DF mode memory to register + copy, then if rd = rs we get + + rs + 1 := 1[rs] + rs := [rs] + + otherwise the order is + + rd := [rs] + rd + 1 := 1[rs] */ + + if (double_p) + { + unsigned int base_reg; + + if (GET_CODE (memrtx) == PLUS) + base_reg = REGNO (XEXP (memrtx, 0)); + else + base_reg = REGNO (memrtx); + + if (dest_reg != base_reg) + dest_reg++; + } + } + + else if (GET_CODE (dest) == MEM) + memrtx = XEXP (dest, 0); + + else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC) + { + if (GET_CODE (dest) == STRICT_LOW_PART + ||GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + dest_reg = REGNO (dest); + + if (GET_CODE (SET_SRC (set)) == REG) + { + unsigned int srcreg = REGNO (SET_SRC (set)); + + /* Check for rs := rs, which will be deleted. */ + if (srcreg == dest_reg) + return; + + /* In the case of a DI or DF mode move from register to + register there is overlap if rd = rs + 1 in which case + the order of the copies is reversed : + + rd + 1 := rs + 1; + rd := rs */ + + if (double_p && dest_reg != srcreg + 1) + dest_reg++; + } + } + + /* If this is the delay slot of a call insn, any register it sets + is not relevant. */ + if (*last_insn_call) + dest_reg = 0; + + /* If the previous insn sets the value of a register, and this insn + uses a base register, check for the pipeline hazard where it is + the same register in each case. */ + if (*last_reg != 0 && memrtx != NULL_RTX) + { + unsigned int reg = 0; + + /* Check for an index (original architecture). */ + if (GET_CODE (memrtx) == PLUS) + reg = REGNO (XEXP (memrtx, 0)); + + /* Check for an MCM target or rs := [rs], in DI or DF mode. */ + else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg)) + reg = REGNO (memrtx); + + /* Remove any pipeline hazard by inserting a NOP. */ + if (reg == *last_reg) + { + if (dump_file) + fprintf (dump_file, + "inserting nop before insn %d\n", INSN_UID (insn)); + emit_insn_after (gen_hazard_nop (), prev_active_insn (insn)); + emit_insn_after (gen_blockage (), insn); + } + } + + *last_reg = dest_reg; + } + + *last_insn_call = false; +} + +/* Go through the instruction stream and insert nops where necessary to avoid + pipeline hazards. There are two cases: + + 1. On the original architecture, it is invalid to set the value of a + (base) register and then use it in an address with a non-zero index + in the next instruction. + + 2. On the MCM, setting the value of a (base) register and then using + it in address (including with zero index) in the next instruction + will result in a pipeline stall of 3 cycles. */ + +static void +gr5_hazard_avoidance (void) +{ + unsigned int last_reg = 0; + bool last_insn_call = false; + rtx_insn *insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + rtx pat = PATTERN (insn); + + if (GET_CODE (pat) == SEQUENCE) + { + for (int i = 0; i < XVECLEN (pat, 0); i++) + gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)), + &last_reg, &last_insn_call); + } + + else if (GET_CODE (insn) == CALL_INSN) + { + /* This call is going to get a nop in its delay slot. */ + last_reg = 0; + last_insn_call = false; + } + + else + gr5_avoid_hazard (insn, &last_reg, &last_insn_call); + } + + else if (GET_CODE (insn) == BARRIER) + last_reg = 0; +} + +/* Perform a target-specific pass over the instruction stream. The compiler + will run it at all optimization levels, just after the point at which it + normally does delayed-branch scheduling. */ + +static unsigned int +visium_reorg (void) +{ + if (visium_cpu == PROCESSOR_GR5) + gr5_hazard_avoidance (); + + return 0; +} +/* Return true if an argument must be passed by indirect reference. */ + +static bool +visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + const_tree type, + bool named ATTRIBUTE_UNUSED) +{ + return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE); +} + +/* Define how arguments are passed. + + A range of general registers and floating registers is available + for passing arguments. When the class of registers which an + argument would normally use is exhausted, that argument, is passed + in the overflow region of the stack. No argument is split between + registers and stack. + + Arguments of type float or _Complex float go in FP registers if FP + hardware is available. If there is no FP hardware, arguments of + type float go in general registers. All other arguments are passed + in general registers. */ + +static rtx +visium_function_arg (cumulative_args_t pcum_v, enum machine_mode mode, + const_tree type ATTRIBUTE_UNUSED, + bool named ATTRIBUTE_UNUSED) +{ + int size; + CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v); + + size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + if (mode == VOIDmode) + return GEN_INT (0); + + /* Scalar or complex single precision floating point arguments are returned + in floating registers. */ + if (TARGET_FPU + && ((GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) + || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2))) + { + if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS) + return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount); + else + return NULL_RTX; + } + + if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS) + return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST); + + return NULL_RTX; +} + +/* Update the summarizer variable pointed to by PCUM_V to advance past an + argument in the argument list. The values MODE, TYPE and NAMED describe + that argument. Once this is done, the variable CUM is suitable for + analyzing the _following_ argument with visium_function_arg. */ + +static void +visium_function_arg_advance (cumulative_args_t pcum_v, + enum machine_mode mode, + const_tree type ATTRIBUTE_UNUSED, + bool named) +{ + int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + int stack_size = 0; + CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v); + + /* Scalar or complex single precision floating point arguments are returned + in floating registers. */ + if (TARGET_FPU + && ((GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) + || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2))) + { + if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS) + ca->frcount += size; + else + { + stack_size = size; + ca->frcount = MAX_ARGS_IN_FP_REGISTERS; + } + } + else + { + /* Everything else goes in a general register, if enough are + available. */ + if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS) + ca->grcount += size; + else + { + stack_size = size; + ca->grcount = MAX_ARGS_IN_GP_REGISTERS; + } + } + + if (named) + ca->stack_words += stack_size; +} + +/* Specify whether to return the return value in memory. */ + +static bool +visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE); +} + +/* Define how scalar values are returned. */ + +static rtx +visium_function_value_1 (enum machine_mode mode) +{ + /* Scalar or complex single precision floating point values + are returned in floating register f1. */ + if (TARGET_FPU + && ((GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) + || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2))) + return gen_rtx_REG (mode, FP_RETURN_REGNUM); + + /* All others are returned in r1. */ + return gen_rtx_REG (mode, RETURN_REGNUM); +} + +/* Return an RTX representing the place where a function returns or receives + a value of data type RET_TYPE. */ + +static rtx +visium_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return visium_function_value_1 (TYPE_MODE (ret_type)); +} + +/* Return an RTX representing the place where the library function result will + be returned. */ + +static rtx +visium_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +{ + return visium_function_value_1 (mode); +} + +/* Store the anonymous register arguments into the stack so that all the + arguments appear to have been passed consecutively on the stack. */ + +static void +visium_setup_incoming_varargs (cumulative_args_t pcum_v, + enum machine_mode mode, + tree type, + int *pretend_size ATTRIBUTE_UNUSED, + int no_rtl) +{ + cumulative_args_t local_args_so_far; + CUMULATIVE_ARGS local_copy; + CUMULATIVE_ARGS *locargs; + int gp_saved, fp_saved, size; + + /* Create an internal cumulative_args_t pointer to internally define + storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not + make global changes. */ + local_args_so_far.p = &local_copy; + locargs = get_cumulative_args (pcum_v); + +#ifdef ENABLE_CHECKING + local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC; +#endif + + local_copy.grcount = locargs->grcount; + local_copy.frcount = locargs->frcount; + local_copy.stack_words = locargs->stack_words; + + /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named + argument. Advance a local copy of ARGS_SO_FAR past the last "real" named + argument, to find out how many registers are left over. */ + TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1); + + /* Find how many registers we need to save. */ + locargs = get_cumulative_args (local_args_so_far); + gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount; + fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0); + size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE); + + if (!no_rtl && size > 0) + { + /* To avoid negative offsets, which are not valid addressing modes on + the Visium, we create a base register for the pretend args. */ + rtx ptr + = force_reg (Pmode, + plus_constant (Pmode, virtual_incoming_args_rtx, -size)); + + if (gp_saved > 0) + { + rtx mem + = gen_rtx_MEM (BLKmode, + plus_constant (Pmode, + ptr, + fp_saved * UNITS_PER_HWFPVALUE)); + MEM_NOTRAP_P (mem) = 1; + set_mem_alias_set (mem, get_varargs_alias_set ()); + move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved); + } + + if (fp_saved > 0) + { + rtx mem = gen_rtx_MEM (BLKmode, ptr); + MEM_NOTRAP_P (mem) = 1; + set_mem_alias_set (mem, get_varargs_alias_set ()); + gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE); + move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved); + } + } + + visium_reg_parm_save_area_size = size; +} + +/* Define the `__builtin_va_list' type for the ABI. */ + +static tree +visium_build_builtin_va_list (void) +{ + tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record; + + record = (*lang_hooks.types.make_type) (RECORD_TYPE); + f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL, + get_identifier ("__overflow_argptr"), ptr_type_node); + f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL, + get_identifier ("__gpr_base"), ptr_type_node); + f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL, + get_identifier ("__fpr_base"), ptr_type_node); + f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL, + get_identifier ("__gpr_bytes"), + short_unsigned_type_node); + f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL, + get_identifier ("__fpr_bytes"), + short_unsigned_type_node); + + DECL_FIELD_CONTEXT (f_ovfl) = record; + DECL_FIELD_CONTEXT (f_gbase) = record; + DECL_FIELD_CONTEXT (f_fbase) = record; + DECL_FIELD_CONTEXT (f_gbytes) = record; + DECL_FIELD_CONTEXT (f_fbytes) = record; + TYPE_FIELDS (record) = f_ovfl; + TREE_CHAIN (f_ovfl) = f_gbase; + TREE_CHAIN (f_gbase) = f_fbase; + TREE_CHAIN (f_fbase) = f_gbytes; + TREE_CHAIN (f_gbytes) = f_fbytes; + layout_type (record); + + return record; +} + +/* Implement `va_start' for varargs and stdarg. */ + +static void +visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) +{ + const CUMULATIVE_ARGS *ca = &crtl->args.info; + int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount; + int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0); + int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset; + tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes; + tree ovfl, gbase, gbytes, fbase, fbytes, t; + + f_ovfl = TYPE_FIELDS (va_list_type_node); + f_gbase = TREE_CHAIN (f_ovfl); + f_fbase = TREE_CHAIN (f_gbase); + f_gbytes = TREE_CHAIN (f_fbase); + f_fbytes = TREE_CHAIN (f_gbytes); + ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE); + gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase, + NULL_TREE); + fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase, + NULL_TREE); + gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes, + NULL_TREE); + fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes, + NULL_TREE); + + /* Store the stacked vararg pointer in the OVFL member. */ + t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx); + t = fold_build_pointer_plus_hwi (t, named_stack_size); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Store the base address of the GPR save area into GBASE. */ + t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx); + offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD; + t = fold_build_pointer_plus_hwi (t, -offset); + t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Store the base address of the FPR save area into FBASE. */ + if (fp_saved) + { + t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx); + offset = gp_saved * UNITS_PER_WORD + + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE; + t = fold_build_pointer_plus_hwi (t, -offset); + t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } + + /* Fill in the GBYTES member. */ + t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes, + size_int (gp_saved * UNITS_PER_WORD)); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Fill in the FBYTES member. */ + t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes), + fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE)); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); +} + +/* Implement `va_arg'. */ + +static tree +visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, + gimple_seq *post_p) +{ + tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes; + tree ovfl, base, bytes; + HOST_WIDE_INT size, rsize; + const bool by_reference_p + = pass_by_reference (NULL, TYPE_MODE (type), type, false); + const bool float_reg_arg_p + = (TARGET_FPU && !by_reference_p + && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT + && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE) + || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT + && (GET_MODE_SIZE (TYPE_MODE (type)) + <= UNITS_PER_HWFPVALUE * 2)))); + const int max_save_area_size + = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE + : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD); + tree t, u, offs; + tree lab_false, lab_over, addr; + tree ptrtype = build_pointer_type (type); + + if (by_reference_p) + { + t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p); + return build_va_arg_indirect_ref (t); + } + + size = int_size_in_bytes (type); + rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; + f_ovfl = TYPE_FIELDS (va_list_type_node); + f_gbase = TREE_CHAIN (f_ovfl); + f_fbase = TREE_CHAIN (f_gbase); + f_gbytes = TREE_CHAIN (f_fbase); + f_fbytes = TREE_CHAIN (f_gbytes); + + /* We maintain separate pointers and offsets for floating-point and + general registers, but we need similar code in both cases. + + Let: + + BYTES be the number of unused bytes in the register save area. + BASE be the base address of the register save area. + OFFS be the current offset into the register save area. Either + MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes + depending upon whether the argument is in general or floating + registers. + ADDR_RTX be the address of the argument. + RSIZE be the size in bytes of the argument. + OVFL be the pointer to the stack overflow area. + + The code we want is: + + 1: if (bytes >= rsize) + 2: { + 3: addr_rtx = base + offs; + 4: bytes -= rsize; + 5: } + 6: else + 7: { + 8: bytes = 0; + 9: addr_rtx = ovfl; + 10: ovfl += rsize; + 11: } + + */ + + addr = create_tmp_var (ptr_type_node, "addr"); + lab_false = create_artificial_label (UNKNOWN_LOCATION); + lab_over = create_artificial_label (UNKNOWN_LOCATION); + if (float_reg_arg_p) + bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist), + f_fbytes, NULL_TREE); + else + bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist), + f_gbytes, NULL_TREE); + + /* [1] Emit code to branch if bytes < rsize. */ + t = fold_convert (TREE_TYPE (bytes), size_int (rsize)); + t = build2 (LT_EXPR, boolean_type_node, bytes, t); + u = build1 (GOTO_EXPR, void_type_node, lab_false); + t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE); + gimplify_and_add (t, pre_p); + + /* [3] Emit code for: addr_rtx = base + offs, where + offs = max_save_area_size - bytes. */ + t = fold_convert (sizetype, bytes); + offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t); + if (float_reg_arg_p) + base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase, + NULL_TREE); + else + base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase, + NULL_TREE); + + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs); + t = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (t, pre_p); + + /* [4] Emit code for: bytes -= rsize. */ + t = fold_convert (TREE_TYPE (bytes), size_int (rsize)); + t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t); + t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t); + gimplify_and_add (t, pre_p); + + /* [6] Emit code to branch over the else clause, then the label. */ + t = build1 (GOTO_EXPR, void_type_node, lab_over); + gimplify_and_add (t, pre_p); + t = build1 (LABEL_EXPR, void_type_node, lab_false); + gimplify_and_add (t, pre_p); + + /* [8] Emit code for: bytes = 0. */ + t = fold_convert (TREE_TYPE (bytes), size_int (0)); + t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t); + gimplify_and_add (t, pre_p); + + /* [9] Emit code for: addr_rtx = ovfl. */ + ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE); + t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl); + gimplify_and_add (t, pre_p); + + /* [10] Emit code for: ovfl += rsize. */ + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t); + gimplify_and_add (t, pre_p); + t = build1 (LABEL_EXPR, void_type_node, lab_over); + gimplify_and_add (t, pre_p); + addr = fold_convert (ptrtype, addr); + + return build_va_arg_indirect_ref (addr); +} + +/* Return true if OP is an offset suitable for use as a displacement in the + address of a memory access in mode MODE. */ + +static bool +rtx_ok_for_offset_p (enum machine_mode mode, rtx op) +{ + if (!CONST_INT_P (op) || INTVAL (op) < 0) + return false; + + switch (mode) + { + case QImode: + return INTVAL (op) <= 31; + + case HImode: + return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63; + + case SImode: + case SFmode: + return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127; + + case DImode: + case DFmode: + return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123; + + default: + return false; + } +} + +/* Return whether X is a legitimate memory address for a memory operand + of mode MODE. + + Legitimate addresses are defined in two variants: a strict variant + and a non-strict one. The STRICT parameter chooses which variant + is desired by the caller. + + The strict variant is used in the reload pass. It must be defined + so that any pseudo-register that has not been allocated a hard + register is considered a memory reference. This is because in + contexts where some kind of register is required, a + pseudo-register with no hard register must be rejected. For + non-hard registers, the strict variant should look up the + `reg_renumber' array; it should then proceed using the hard + register number in the array, or treat the pseudo as a memory + reference if the array holds `-1'. + + The non-strict variant is used in other passes. It must be + defined to accept all pseudo-registers in every context where some + kind of register is required. */ + +static bool +visium_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +{ + rtx base; + unsigned int regno; + + /* If X is base+disp, check that we have an appropriate offset. */ + if (GET_CODE (x) == PLUS) + { + if (!rtx_ok_for_offset_p (mode, XEXP (x, 1))) + return false; + base = XEXP (x, 0); + } + else + base = x; + + /* Now check the base: it must be either a register or a subreg thereof. */ + if (GET_CODE (base) == SUBREG) + base = SUBREG_REG (base); + if (!REG_P (base)) + return false; + + regno = REGNO (base); + + /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */ + if (strict) + return REGNO_OK_FOR_BASE_P (regno); + + /* For the non-strict variant, the register may also be a pseudo. */ + return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER; +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For Visium + + memory (reg + <out of range int>) + + is transformed to + + base_int = <out of range int> & ~mask + ptr_reg = reg + base_int + memory (ptr_reg + <out of range int> - base_int) + + Thus ptr_reg is a base register for a range of addresses, + which should help CSE. + + For a 1 byte reference mask is 0x1f + for a 2 byte reference mask is 0x3f + For a 4 byte reference mask is 0x7f + + This reflects the indexing range of the processor. + + For a > 4 byte reference the mask is 0x7f provided all of the words + can be accessed with the base address obtained. Otherwise a mask + of 0x3f is used. + + On rare occasions an unaligned base register value with an + unaligned offset is generated. Unaligned offsets are left alone for + this reason. */ + +static rtx +visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode) + { + int offset = INTVAL (XEXP (x, 1)); + int size = GET_MODE_SIZE (mode); + int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f)); + int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3)); + int offset_base = offset & ~mask; + + /* Check that all of the words can be accessed. */ + if (4 < size && 0x80 < size + offset - offset_base) + offset_base = offset & ~0x3f; + if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0) + { + rtx ptr_reg = force_reg (Pmode, + gen_rtx_PLUS (Pmode, + XEXP (x, 0), + GEN_INT (offset_base))); + + return plus_constant (Pmode, ptr_reg, offset - offset_base); + } + } + + return x; +} + +/* Perform a similar function to visium_legitimize_address, but this time + for reload. Generating new registers is not an option here. Parts + that need reloading are indicated by calling push_reload. */ + +rtx +visium_legitimize_reload_address (rtx x, enum machine_mode mode, int opnum, + int type, int ind ATTRIBUTE_UNUSED) +{ + rtx newrtx, tem = NULL_RTX; + + if (mode == BLKmode) + return NULL_RTX; + + if (optimize && GET_CODE (x) == PLUS) + tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0), + XEXP (x, 1)); + + newrtx = tem ? tem : x; + if (GET_CODE (newrtx) == PLUS + && GET_CODE (XEXP (newrtx, 1)) == CONST_INT + && GET_CODE (XEXP (newrtx, 0)) == REG + && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0)))) + { + int offset = INTVAL (XEXP (newrtx, 1)); + int size = GET_MODE_SIZE (mode); + int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f)); + int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3)); + int offset_base = offset & ~mask; + + /* Check that all of the words can be accessed. */ + if (4 < size && 0x80 < size + offset - offset_base) + offset_base = offset & ~0x3f; + + if (offset_base && (offset & mask1) == 0) + { + rtx temp = gen_rtx_PLUS (Pmode, + XEXP (newrtx, 0), GEN_INT (offset_base)); + + x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base)); + push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, + (enum reload_type) type); + return x; + } + } + + return NULL_RTX; +} + +/* Return the cost of moving data of mode MODE from a register in class FROM to + one in class TO. A value of 2 is the default; other values are interpreted + relative to that. */ + +static int +visium_register_move_cost (enum machine_mode mode, reg_class_t from, + reg_class_t to) +{ + const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2; + + if (from == MDB || to == MDB) + return 4; + else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS)) + return 4 * numwords; + else + return 2 * numwords; +} + +/* Return the cost of moving data of mode MODE between a register of class + CLASS and memory. IN is zero if the value is to be written to memory, + non-zero if it is to be read in. This cost is relative to those in + visium_register_move_cost. */ + +static int +visium_memory_move_cost (enum machine_mode mode, + reg_class_t to ATTRIBUTE_UNUSED, + bool in) +{ + /* Moving data in can be from PROM and this is expensive. */ + if (in) + { + if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) + return 7; + else + return 13; + } + + /* Moving data out is mostly to RAM and should be cheaper. */ + else + { + if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) + return 6; + else + return 12; + } +} + +/* Return the relative costs of expression X. */ + +static bool +visium_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, int *total, + bool speed ATTRIBUTE_UNUSED) +{ + enum machine_mode mode = GET_MODE (x); + + switch (code) + { + case CONST_INT: + /* Small integers are as cheap as registers. 4-byte values can + be fetched as immediate constants - let's give that the cost + of an extra insn. */ + *total = COSTS_N_INSNS (!satisfies_constraint_J (x)); + return true; + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + *total = COSTS_N_INSNS (2); + return true; + + case CONST_DOUBLE: + { + rtx high, low; + split_double (x, &high, &low); + *total = + COSTS_N_INSNS + (!satisfies_constraint_J (high) + !satisfies_constraint_J (low)); + return true; + } + + case MULT: + *total = COSTS_N_INSNS (3); + return false; + + case DIV: + case UDIV: + case MOD: + case UMOD: + if (mode == DImode) + *total = COSTS_N_INSNS (64); + else + *total = COSTS_N_INSNS (32); + return false; + + case PLUS: + case MINUS: + case NEG: + /* DImode operations are performed directly on the ALU. */ + if (mode == DImode) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (1); + return false; + + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + /* DImode operations are performed on the EAM instead. */ + if (mode == DImode) + *total = COSTS_N_INSNS (3); + else + *total = COSTS_N_INSNS (1); + return false; + + case COMPARE: + /* This matches the btst pattern. */ + if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT + && XEXP (x, 1) == const0_rtx + && XEXP (XEXP (x, 0), 1) == const1_rtx + && satisfies_constraint_K (XEXP (XEXP (x, 0), 2))) + *total = COSTS_N_INSNS (1); + return false; + + default: + return false; + } +} + +/* Split a double move of OPERANDS in MODE. */ + +void +split_double_move (rtx *operands, enum machine_mode mode) +{ + bool swap = false; + + /* Check register to register with overlap. */ + if (GET_CODE (operands[0]) == REG + && GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1]) + 1) + swap = true; + + /* Check memory to register where the base reg overlaps the destination. */ + if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM) + { + rtx op = XEXP (operands[1], 0); + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0])) + swap = true; + + if (GET_CODE (op) == PLUS) + { + rtx x = XEXP (op, 0); + rtx y = XEXP (op, 1); + + if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0])) + swap = true; + + if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0])) + swap = true; + } + } + + if (swap) + { + operands[2] = operand_subword (operands[0], 1, 1, mode); + operands[3] = operand_subword (operands[1], 1, 1, mode); + operands[4] = operand_subword (operands[0], 0, 1, mode); + operands[5] = operand_subword (operands[1], 0, 1, mode); + } + else + { + operands[2] = operand_subword (operands[0], 0, 1, mode); + operands[3] = operand_subword (operands[1], 0, 1, mode); + operands[4] = operand_subword (operands[0], 1, 1, mode); + operands[5] = operand_subword (operands[1], 1, 1, mode); + } +} + +/* Expand a copysign of OPERANDS in MODE. */ + +void +visium_expand_copysign (rtx *operands, enum machine_mode mode) +{ + rtx dest = operands[0]; + rtx op0 = operands[1]; + rtx op1 = operands[2]; + rtx mask = force_reg (SImode, GEN_INT (0x7fffffff)); + rtx x; + + /* We manually handle SFmode because the abs and neg instructions of + the FPU on the MCM have a non-standard behavior wrt NaNs. */ + gcc_assert (mode == SFmode); + + /* First get all the non-sign bits of OP0. */ + if (GET_CODE (op0) == CONST_DOUBLE) + { + if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0))) + op0 = simplify_unary_operation (ABS, mode, op0, mode); + if (op0 != CONST0_RTX (mode)) + { + long l; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, op0); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + op0 = force_reg (SImode, GEN_INT (trunc_int_for_mode (l, SImode))); + } + } + else + { + op0 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op0)); + op0 = force_reg (SImode, gen_rtx_AND (SImode, op0, mask)); + } + + /* Then get the sign bit of OP1. */ + mask = force_reg (SImode, gen_rtx_NOT (SImode, mask)); + op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1)); + op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask)); + + /* Finally OR the two values. */ + if (op0 == CONST0_RTX (SFmode)) + x = op1; + else + x = force_reg (SImode, gen_rtx_IOR (SImode, op0, op1)); + + /* And move the result to the destination. */ + emit_insn (gen_rtx_SET (VOIDmode, dest, gen_lowpart (SFmode, x))); +} + +/* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate + the result in the C flag and use the ADC/SUBC instructions to write it into + the destination register. + + It would also be possible to implement support for LT/GT/LE/GE by means of + the RFLAG instruction followed by some shifts, but this can pessimize the + generated code. */ + +void +visium_expand_int_cstore (rtx *operands, enum machine_mode mode) +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu; + bool reverse = false; + + switch (code) + { + case EQ: + case NE: + /* We use a special comparison to get the result in the C flag. */ + if (op2 != const0_rtx) + op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2)); + op1 = gen_rtx_NOT (mode, op1); + op2 = constm1_rtx; + if (code == EQ) + reverse = true; + break; + + case LEU: + case GEU: + /* The result is naturally in the C flag modulo a couple of tricks. */ + code = reverse_condition (code); + reverse = true; + + /* ... fall through ... */ + + case LTU: + case GTU: + if (code == GTU) + { + rtx tmp = op1; + op1 = op2; + op2 = tmp; + } + break; + + default: + gcc_unreachable (); + } + + /* We need either a single ADC or a SUBC and a PLUS. */ + sltu = gen_rtx_LTU (SImode, op1, op2); + + if (reverse) + { + rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu)); + emit_insn (gen_add3_insn (op0, tmp, const1_rtx)); + } + else + emit_insn (gen_rtx_SET (VOIDmode, op0, sltu)); +} + +/* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the + result in the C flag and use the ADC/SUBC instructions to write it into + the destination register. */ + +void +visium_expand_fp_cstore (rtx *operands, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt; + bool reverse = false; + + switch (code) + { + case UNLE: + case UNGE: + /* The result is naturally in the C flag modulo a couple of tricks. */ + code = reverse_condition_maybe_unordered (code); + reverse = true; + + /* ... fall through ... */ + + case LT: + case GT: + if (code == GT) + { + rtx tmp = op1; + op1 = op2; + op2 = tmp; + } + break; + + default: + gcc_unreachable (); + } + + /* We need either a single ADC or a SUBC and a PLUS. */ + slt = gen_rtx_LT (SImode, op1, op2); + + if (reverse) + { + rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt)); + emit_insn (gen_add3_insn (op0, tmp, const1_rtx)); + } + else + emit_insn (gen_rtx_SET (VOIDmode, op0, slt)); +} + +/* Split a compare-and-store with CODE, operands OP2 and OP3, combined with + operation with OP_CODE, operands OP0 and OP1. */ + +void +visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1, + enum rtx_code code, rtx op2, rtx op3) +{ + enum machine_mode cc_mode = visium_select_cc_mode (code, op2, op3); + + /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */ + if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS)) + cc_mode = CCFPmode; + + rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM); + rtx x = gen_rtx_COMPARE (cc_mode, op2, op3); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx); + switch (op_code) + { + case SET: + break; + case NEG: + x = gen_rtx_NEG (SImode, x); + break; + case PLUS: + case MINUS: + x = gen_rtx_fmt_ee (op_code, SImode, op1, x); + break; + default: + gcc_unreachable (); + } + + rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2)); + XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, op0, x); + flags = gen_rtx_REG (CCmode, FLAGS_REGNUM); + XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags); + emit_insn (pat); + + visium_flags_exposed = true; +} + +/* Generate a call to a library function to move BYTES_RTX bytes from SRC with + address SRC_REG to DST with address DST_REG in 4-byte chunks. */ + +static void +expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memcpy"); + unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx); + unsigned int rem = bytes % 4; + + if (TARGET_BMI) + { + unsigned int i; + rtx insn; + + emit_move_insn (regno_reg_rtx[1], dst_reg); + emit_move_insn (regno_reg_rtx[2], src_reg); + emit_move_insn (regno_reg_rtx[3], bytes_rtx); + + insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8)); + XVECEXP (insn, 0, 0) + = gen_rtx_SET (VOIDmode, + replace_equiv_address_nv (dst, regno_reg_rtx[1]), + replace_equiv_address_nv (src, regno_reg_rtx[2])); + XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]); + for (i = 1; i <= 6; i++) + XVECEXP (insn, 0, 1 + i) + = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]); + emit_insn (insn); + } + else + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg, + Pmode, + convert_to_mode (TYPE_MODE (sizetype), + GEN_INT (bytes >> 2), + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); + if (rem == 0) + return; + + dst = replace_equiv_address_nv (dst, dst_reg); + src = replace_equiv_address_nv (src, src_reg); + bytes -= rem; + + if (rem > 1) + { + emit_move_insn (adjust_address_nv (dst, HImode, bytes), + adjust_address_nv (src, HImode, bytes)); + bytes += 2; + rem -= 2; + } + + if (rem > 0) + emit_move_insn (adjust_address_nv (dst, QImode, bytes), + adjust_address_nv (src, QImode, bytes)); +} + +/* Generate a call to a library function to move BYTES_RTX bytes from SRC with + address SRC_REG to DST with address DST_REG in 2-bytes chunks. */ + +static void +expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memcpy"); + unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx); + unsigned int rem = bytes % 2; + + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg, + Pmode, + convert_to_mode (TYPE_MODE (sizetype), + GEN_INT (bytes >> 1), + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); + if (rem == 0) + return; + + dst = replace_equiv_address_nv (dst, dst_reg); + src = replace_equiv_address_nv (src, src_reg); + bytes -= rem; + + emit_move_insn (adjust_address_nv (dst, QImode, bytes), + adjust_address_nv (src, QImode, bytes)); +} + +/* Generate a call to a library function to move BYTES_RTX bytes from address + SRC_REG to address DST_REG in 1-byte chunks. */ + +static void +expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memcpy"); + + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, + src_reg, Pmode, + convert_to_mode (TYPE_MODE (sizetype), + bytes_rtx, + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); +} + +/* Generate a call to a library function to set BYTES_RTX bytes of DST with + address DST_REG to VALUE_RTX in 4-byte chunks. */ + +static void +expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memset"); + unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx); + unsigned int rem = bytes % 4; + + value_rtx = convert_to_mode (Pmode, value_rtx, 1); + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, + value_rtx, Pmode, + convert_to_mode (TYPE_MODE (sizetype), + GEN_INT (bytes >> 2), + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); + if (rem == 0) + return; + + dst = replace_equiv_address_nv (dst, dst_reg); + bytes -= rem; + + if (rem > 1) + { + if (CONST_INT_P (value_rtx)) + { + const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff; + emit_move_insn (adjust_address_nv (dst, HImode, bytes), + gen_int_mode ((value << 8) | value, HImode)); + } + else + { + rtx temp = convert_to_mode (QImode, value_rtx, 1); + emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp); + emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp); + } + bytes += 2; + rem -= 2; + } + + if (rem > 0) + emit_move_insn (adjust_address_nv (dst, QImode, bytes), + convert_to_mode (QImode, value_rtx, 1)); +} + +/* Generate a call to a library function to set BYTES_RTX bytes of DST with + address DST_REG to VALUE_RTX in 2-byte chunks. */ + +static void +expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memset"); + unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx); + unsigned int rem = bytes % 2; + + value_rtx = convert_to_mode (Pmode, value_rtx, 1); + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, + value_rtx, Pmode, + convert_to_mode (TYPE_MODE (sizetype), + GEN_INT (bytes >> 1), + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); + if (rem == 0) + return; + + dst = replace_equiv_address_nv (dst, dst_reg); + bytes -= rem; + + emit_move_insn (adjust_address_nv (dst, QImode, bytes), + convert_to_mode (QImode, value_rtx, 1)); +} + +/* Generate a call to a library function to set BYTES_RTX bytes at address + DST_REG to VALUE_RTX in 1-byte chunks. */ + +static void +expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx) +{ + const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memset"); + + value_rtx = convert_to_mode (Pmode, value_rtx, 1); + emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, + value_rtx, Pmode, + convert_to_mode (TYPE_MODE (sizetype), + bytes_rtx, + TYPE_UNSIGNED (sizetype)), + TYPE_MODE (sizetype)); +} + +/* Expand string/block move operations. + + operands[0] is the pointer to the destination. + operands[1] is the pointer to the source. + operands[2] is the number of bytes to move. + operands[3] is the alignment. + + Return 1 upon success, 0 otherwise. */ + +int +visium_expand_block_move (rtx *operands) +{ + rtx dst = operands[0]; + rtx src = operands[1]; + rtx bytes_rtx = operands[2]; + rtx align_rtx = operands[3]; + const int align = INTVAL (align_rtx); + rtx dst_reg, src_reg; + tree dst_expr, src_expr; + + /* We only handle a fixed number of bytes for now. */ + if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0) + return 0; + + /* Copy the addresses into scratch registers. */ + dst_reg = copy_addr_to_reg (XEXP (dst, 0)); + src_reg = copy_addr_to_reg (XEXP (src, 0)); + + /* Move the data with the appropriate granularity. */ + if (align >= 4) + expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx); + else if (align >= 2) + expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx); + else + expand_block_move_1 (dst_reg, src_reg, bytes_rtx); + + /* Since DST and SRC are passed to a libcall, mark the corresponding + tree EXPR as addressable. */ + dst_expr = MEM_EXPR (dst); + src_expr = MEM_EXPR (src); + if (dst_expr) + mark_addressable (dst_expr); + if (src_expr) + mark_addressable (src_expr); + + return 1; +} + +/* Expand string/block set operations. + + operands[0] is the pointer to the destination. + operands[1] is the number of bytes to set. + operands[2] is the source value. + operands[3] is the alignment. + + Return 1 upon success, 0 otherwise. */ + +int +visium_expand_block_set (rtx *operands) +{ + rtx dst = operands[0]; + rtx bytes_rtx = operands[1]; + rtx value_rtx = operands[2]; + rtx align_rtx = operands[3]; + const int align = INTVAL (align_rtx); + rtx dst_reg; + tree dst_expr; + + /* We only handle a fixed number of bytes for now. */ + if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0) + return 0; + + /* Copy the address into a scratch register. */ + dst_reg = copy_addr_to_reg (XEXP (dst, 0)); + + /* Set the data with the appropriate granularity. */ + if (align >= 4) + expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx); + else if (align >= 2) + expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx); + else + expand_block_set_1 (dst_reg, value_rtx, bytes_rtx); + + /* Since DST is passed to a libcall, mark the corresponding + tree EXPR as addressable. */ + dst_expr = MEM_EXPR (dst); + if (dst_expr) + mark_addressable (dst_expr); + + return 1; +} + +/* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the + trampoline, FNDECL is the FUNCTION_DECL for the nested function and + STATIC_CHAIN is an RTX for the static chain value that should be passed + to the function when it is called. */ + +static void +visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + rtx addr = XEXP (m_tramp, 0); + + /* The trampoline initialization sequence is: + + moviu r9,%u FUNCTION + movil r9,%l FUNCTION + moviu r20,%u STATIC + bra tr,r9,r9 + movil r20,%l STATIC + + We don't use r0 as the destination register of the branch because we want + the Branch Pre-decode Logic of the GR6 to use the Address Load Array to + predict the branch target. */ + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)), + plus_constant (SImode, + expand_shift (RSHIFT_EXPR, SImode, fnaddr, + 16, NULL_RTX, 1), + 0x04a90000)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)), + plus_constant (SImode, + expand_and (SImode, fnaddr, GEN_INT (0xffff), + NULL_RTX), + 0x04890000)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)), + plus_constant (SImode, + expand_shift (RSHIFT_EXPR, SImode, + static_chain, + 16, NULL_RTX, 1), + 0x04b40000)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)), + gen_int_mode (0xff892404, SImode)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)), + plus_constant (SImode, + expand_and (SImode, static_chain, + GEN_INT (0xffff), NULL_RTX), + 0x04940000)); + + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__set_trampoline_parity"), + LCT_NORMAL, VOIDmode, 1, addr, SImode); +} + +/* Return true if the current function must have and use a frame pointer. */ + +static bool +visium_frame_pointer_required (void) +{ + /* The frame pointer is required if the function isn't leaf to be able to + do manual stack unwinding. */ + if (!crtl->is_leaf) + return true; + + /* If the stack pointer is dynamically modified in the function, it cannot + serve as the frame pointer. */ + if (!crtl->sp_is_unchanging) + return true; + + /* If the function receives nonlocal gotos, it needs to save the frame + pointer in the nonlocal_goto_save_area object. */ + if (cfun->has_nonlocal_label) + return true; + + /* The frame also needs to be established in some special cases. */ + if (visium_frame_needed) + return true; + + return false; +} + +/* Profiling support. Just a call to MCOUNT is needed. No labelled counter + location is involved. Proper support for __builtin_return_address is also + required, which is fairly straightforward provided a frame gets created. */ + +void +visium_profile_hook (void) +{ + visium_frame_needed = true; + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL, + VOIDmode, 0); +} + +/* A C expression whose value is RTL representing the address in a stack frame + where the pointer to the caller's frame is stored. Assume that FRAMEADDR is + an RTL expression for the address of the stack frame itself. + + If you don't define this macro, the default is to return the value of + FRAMEADDR--that is, the stack frame address is also the address of the stack + word that points to the previous frame. */ + +rtx +visium_dynamic_chain_address (rtx frame) +{ + /* This is the default, but we need to make sure the frame gets created. */ + visium_frame_needed = true; + return frame; +} + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame, after the + prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame + pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is + defined. + + The value of the expression must always be the correct address when COUNT is + zero, but may be `NULL_RTX' if there is not way to determine the return + address of other frames. */ + +rtx +visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) +{ + /* Dont try to compute anything other than frame zero. */ + if (count != 0) + return NULL_RTX; + + visium_frame_needed = true; + return + gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4)); +} + +/* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a + location in which to store the address of an exception handler to which we + should return. */ + +rtx +visium_eh_return_handler_rtx (void) +{ + rtx mem + = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4)); + MEM_VOLATILE_P (mem) = 1; + return mem; +} + +static struct machine_function * +visium_init_machine_status (void) +{ + return ggc_cleared_alloc<machine_function> (); +} + +/* The per-function data machinery is needed to indicate when a frame + is required. */ + +void +visium_init_expanders (void) +{ + init_machine_status = visium_init_machine_status; +} + +/* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE, + return the mode to be used for the comparison. */ + +enum machine_mode +visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1) +{ + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) + { + switch (code) + { + case EQ: + case NE: + case ORDERED: + case UNORDERED: + case UNLT: + case UNLE: + case UNGT: + case UNGE: + return CCFPmode; + + case LT: + case LE: + case GT: + case GE: + return CCFPEmode; + + /* These 2 comparison codes are not supported. */ + case UNEQ: + case LTGT: + default: + gcc_unreachable (); + } + } + + if (op1 != const0_rtx) + return CCmode; + + switch (GET_CODE (op0)) + { + case PLUS: + case MINUS: + case NEG: + case ASHIFT: + case LTU: + case LT: + /* The V flag may be set differently from a COMPARE with zero. + The consequence is that a comparison operator testing V must + be turned into another operator not testing V and yielding + the same result for a comparison with zero. That's possible + for GE/LT which become NC/NS respectively, but not for GT/LE + for which the altered operator doesn't exist on the Visium. */ + return CC_NOOVmode; + + case ZERO_EXTRACT: + /* This is a btst, the result is in C instead of Z. */ + return CC_BTSTmode; + + case CONST_INT: + /* This is a degenerate case, typically an uninitialized variable. */ + gcc_assert (op0 == constm1_rtx); + case REG: + case AND: + case IOR: + case XOR: + case NOT: + case ASHIFTRT: + case LSHIFTRT: + case TRUNCATE: + case SIGN_EXTEND: + /* Pretend that the flags are set as for a COMPARE with zero. + That's mostly true, except for the 2 right shift insns that + will set the C flag. But the C flag is relevant only for + the unsigned comparison operators and they are eliminated + when applied to a comparison with zero. */ + return CCmode; + + default: + gcc_unreachable (); + } +} + +/* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */ + +void +visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label) +{ + enum machine_mode cc_mode = visium_select_cc_mode (code, op0, op1); + rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM); + + rtx x = gen_rtx_COMPARE (cc_mode, op0, op1); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label), + pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); + + visium_flags_exposed = true; +} + +/* Branch instructions on the Visium. + + Setting aside the interrupt-handling specific instructions, the ISA has + two branch instructions: BRR and BRA. The former is used to implement + short branches (+/- 2^17) within functions and its target is encoded in + the instruction. The latter is used to implement all the other types + of control flow changes and its target might not be statically known + or even easily predictable at run time. Here's a complete summary of + the patterns that generate a BRA instruction: + + 1. Indirect jump + 2. Table jump + 3. Call + 4. Sibling call + 5. Return + 6. Long branch + 7. Trampoline + + Among these patterns, only the return (5) and the long branch (6) can be + conditional; all the other patterns are always unconditional. + + The following algorithm can be used to identify the pattern for which + the BRA instruction was generated and work out its target: + + A. If the source is r21 and the destination is r0, this is a return (5) + and the target is the caller (i.e. the value of r21 on function's + entry). + + B. If the source is rN, N != 21 and the destination is r0, this is either + an indirect jump or a table jump (1, 2) and the target is not easily + predictable. + + C. If the source is rN, N != 21 and the destination is r21, this is a call + (3) and the target is given by the preceding MOVIL/MOVIU pair for rN, + unless this is an indirect call in which case the target is not easily + predictable. + + D. If the source is rN, N != 21 and the destination is also rN, this is + either a sibling call or a trampoline (4, 7) and the target is given + by the preceding MOVIL/MOVIU pair for rN. + + E. If the source is r21 and the destination is also r21, this is a long + branch (6) and the target is given by the preceding MOVIL/MOVIU pair + for r21. + + The other combinations are not used. This implementation has been devised + to accommodate the branch predictor of the GR6 but is used unconditionally + by the compiler, i.e. including for earlier processors. */ + +/* Output a conditional/unconditional branch to LABEL. COND is the string + condition. INSN is the instruction. */ + +static const char * +output_branch (rtx label, const char *cond, rtx_insn *insn) +{ + char str[64]; + rtx operands[2]; + + gcc_assert (cond); + operands[0] = label; + + /* If the length of the instruction is greater than 8, then this is a + long branch and we need to work harder to emit it properly. */ + if (get_attr_length (insn) > 8) + { + bool spilled; + + /* If the link register has been saved, then we use it. */ + if (current_function_saves_lr ()) + { + operands[1] = regno_reg_rtx [LINK_REGNUM]; + spilled = false; + } + + /* Or else, if the long-branch register isn't live, we use it. */ + else if (!df_regs_ever_live_p (long_branch_regnum)) + { + operands[1] = regno_reg_rtx [long_branch_regnum]; + spilled = false; + } + + /* Otherwise, we will use the long-branch register but we need to + spill it to the stack and reload it at the end. We should have + reserved the LR slot for this purpose. */ + else + { + operands[1] = regno_reg_rtx [long_branch_regnum]; + spilled = true; + gcc_assert (current_function_has_lr_slot ()); + } + + /* First emit the spill to the stack: + + insn_in_delay_slot + write.l [1](sp),reg */ + if (spilled) + { + if (final_sequence) + { + rtx_insn *delay = NEXT_INSN (insn); + int seen; + gcc_assert (delay); + + final_scan_insn (delay, asm_out_file, optimize, 0, &seen); + PATTERN (delay) = gen_blockage (); + INSN_CODE (delay) = -1; + } + + if (current_function_saves_fp ()) + output_asm_insn ("write.l 1(sp),%1", operands); + else + output_asm_insn ("write.l (sp),%1", operands); + } + + /* Then emit the core sequence: + + moviu reg,%u label + movil reg,%l label + bra tr,reg,reg + + We don't use r0 as the destination register of the branch because we + want the Branch Pre-decode Logic of the GR6 to use the Address Load + Array to predict the branch target. */ + output_asm_insn ("moviu %1,%%u %0", operands); + output_asm_insn ("movil %1,%%l %0", operands); + strcpy (str, "bra "); + strcat (str, cond); + strcat (str, ",%1,%1"); + if (!spilled) + strcat (str, "%#"); + strcat (str, "\t\t;long branch"); + output_asm_insn (str, operands); + + /* Finally emit the reload: + + read.l reg,[1](sp) */ + if (spilled) + { + if (current_function_saves_fp ()) + output_asm_insn (" read.l %1,1(sp)", operands); + else + output_asm_insn (" read.l %1,(sp)", operands); + } + } + + /* Or else, if the label is PC, then this is a return. */ + else if (label == pc_rtx) + { + strcpy (str, "bra "); + strcat (str, cond); + strcat (str, ",r21,r0%#\t\t;return"); + output_asm_insn (str, operands); + } + + /* Otherwise, this is a short branch. */ + else + { + strcpy (str, "brr "); + strcat (str, cond); + strcat (str, ",%0%#"); + output_asm_insn (str, operands); + } + + return ""; +} + +/* Output an unconditional branch to LABEL. INSN is the instruction. */ + +const char * +output_ubranch (rtx label, rtx_insn *insn) +{ + return output_branch (label, "tr", insn); +} + +/* Output a conditional branch to LABEL. CODE is the comparison code. + CC_MODE is the mode of the CC register. REVERSED is non-zero if we + should reverse the sense of the comparison. INSN is the instruction. */ + +const char * +output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode, + int reversed, rtx_insn *insn) +{ + const char *cond; + + if (reversed) + { + if (cc_mode == CCFPmode || cc_mode == CCFPEmode) + code = reverse_condition_maybe_unordered (code); + else + code = reverse_condition (code); + } + + switch (code) + { + case NE: + if (cc_mode == CC_BTSTmode) + cond = "cs"; + else + cond = "ne"; + break; + + case EQ: + if (cc_mode == CC_BTSTmode) + cond = "cc"; + else + cond = "eq"; + break; + + case GE: + if (cc_mode == CC_NOOVmode) + cond = "nc"; + else + cond = "ge"; + break; + + case GT: + cond = "gt"; + break; + + case LE: + if (cc_mode == CCFPmode || cc_mode == CCFPEmode) + cond = "ls"; + else + cond = "le"; + break; + + case LT: + if (cc_mode == CCFPmode || cc_mode == CCFPEmode) + cond = "ns"; + else if (cc_mode == CC_NOOVmode) + cond = "ns"; + else + cond = "lt"; + break; + + case GEU: + cond = "cc"; + break; + + case GTU: + cond = "hi"; + break; + + case LEU: + cond = "ls"; + break; + + case LTU: + cond = "cs"; + break; + + case UNORDERED: + cond = "os"; + break; + + case ORDERED: + cond = "oc"; + break; + + case UNGE: + cond = "nc"; + break; + + case UNGT: + cond = "hi"; + break; + + case UNLE: + cond = "le"; + break; + + case UNLT: + cond = "lt"; + break; + + /* These 2 comparison codes are not supported. */ + case UNEQ: + case LTGT: + default: + gcc_unreachable (); + } + + return output_branch (label, cond, insn); +} + +/* Helper function for PRINT_OPERAND (STREAM, X, CODE). Output to stdio + stream FILE the assembler syntax for an instruction operand OP subject + to the modifier LETTER. */ + +void +print_operand (FILE *file, rtx op, int letter) +{ + switch (letter) + { + case '#': + /* Output an insn in a delay slot. */ + if (final_sequence) + visium_indent_opcode = 1; + else + fputs ("\n\t nop", file); + return; + + case 'b': + /* Print LS 8 bits of operand. */ + fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff); + return; + + case 'w': + /* Print LS 16 bits of operand. */ + fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff); + return; + + case 'u': + /* Print MS 16 bits of operand. */ + fprintf (file, + HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff); + return; + + case 'r': + /* It's either a register or zero. */ + if (GET_CODE (op) == REG) + fputs (reg_names[REGNO (op)], file); + else + fputs (reg_names[0], file); + return; + + case 'f': + /* It's either a FP register or zero. */ + if (GET_CODE (op) == REG) + fputs (reg_names[REGNO (op)], file); + else + fputs (reg_names[FP_FIRST_REGNUM], file); + return; + } + + switch (GET_CODE (op)) + { + case REG: + if (letter == 'd') + fputs (reg_names[REGNO (op) + 1], file); + else + fputs (reg_names[REGNO (op)], file); + break; + + case SYMBOL_REF: + case LABEL_REF: + case CONST: + output_addr_const (file, op); + break; + + case MEM: + visium_output_address (file, GET_MODE (op), XEXP (op, 0)); + break; + + case CONST_INT: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op)); + break; + + case CODE_LABEL: + asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op)); + break; + + case HIGH: + print_operand (file, XEXP (op, 1), letter); + break; + + default: + fatal_insn ("illegal operand ", op); + } +} + +/* Output to stdio stream FILE the assembler syntax for an instruction operand + that is a memory reference in MODE and whose address is ADDR. */ + +static void +visium_output_address (FILE *file, enum machine_mode mode, rtx addr) +{ + switch (GET_CODE (addr)) + { + case REG: + case SUBREG: + fprintf (file, "(%s)", reg_names[true_regnum (addr)]); + break; + + case PLUS: + { + rtx x = XEXP (addr, 0), y = XEXP (addr, 1); + + switch (GET_CODE (x)) + { + case REG: + case SUBREG: + if (CONST_INT_P (y)) + { + unsigned int regno = true_regnum (x); + HOST_WIDE_INT val = INTVAL (y); + switch (mode) + { + case SImode: + case DImode: + case SFmode: + case DFmode: + val >>= 2; + break; + + case HImode: + val >>= 1; + break; + + case QImode: + default: + break; + } + fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val, + reg_names[regno]); + } + else + fatal_insn ("illegal operand address (1)", addr); + break; + + default: + if (CONSTANT_P (x) && CONSTANT_P (y)) + output_addr_const (file, addr); + else + fatal_insn ("illegal operand address (2)", addr); + break; + } + } + break; + + case LABEL_REF: + case SYMBOL_REF: + case CONST_INT: + case CONST: + output_addr_const (file, addr); + break; + + case NOTE: + if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL) + fatal_insn ("illegal operand address (3)", addr); + break; + + case CODE_LABEL: + asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr)); + break; + + default: + fatal_insn ("illegal operand address (4)", addr); + break; + } +} + +/* Helper function for PRINT_OPERAND_ADDRESS (STREAM, X). Output to stdio + stream FILE the assembler syntax for an instruction operand that is a + memory reference whose address is ADDR. */ + +void +print_operand_address (FILE *file, rtx addr) +{ + visium_output_address (file, QImode, addr); +} + +/* The Visium stack frames look like: + + Before call After call + +-----------------------+ +-----------------------+ + | | | | + high | previous | | previous | + mem | frame | | frame | + | | | | + +-----------------------+ +-----------------------+ + | | | | + | arguments on stack | | arguments on stack | + | | | | + SP+0->+-----------------------+ +-----------------------+ + | reg parm save area, | + | only created for | + | variable argument | + | functions | + +-----------------------+ + | | + | register save area | + | | + +-----------------------+ + | | + | local variables | + | | + FP+8->+-----------------------+ + | return address | + FP+4->+-----------------------+ + | previous FP | + FP+0->+-----------------------+ + | | + | alloca allocations | + | | + +-----------------------+ + | | + low | arguments on stack | + mem | | + SP+0->+-----------------------+ + + Notes: + 1) The "reg parm save area" does not exist for non variable argument fns. + 2) The FP register is not saved if `frame_pointer_needed' is zero and it + is not altered in the current function. + 3) The return address is not saved if there is no frame pointer and the + current function is leaf. + 4) If the return address is not saved and the static chain register is + live in the function, we allocate the return address slot to be able + to spill the register for a long branch. */ + +/* Define the register classes for local purposes. */ +enum reg_type { general, mdb, mdc, floating, last_type}; + +#define GET_REG_TYPE(regno) \ + (GP_REGISTER_P (regno) ? general : \ + (regno) == MDB_REGNUM ? mdb : \ + (regno) == MDC_REGNUM ? mdc : \ + floating) + +/* First regno of each register type. */ +const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM}; + +/* Size in bytes of each register type. */ +const int reg_type_size[last_type] = {4, 8, 4, 4}; + +/* Structure to be filled in by visium_compute_frame_size. */ +struct visium_frame_info +{ + unsigned int save_area_size; /* # bytes in the reg parm save area. */ + unsigned int reg_size1; /* # bytes to store first block of regs. */ + unsigned int reg_size2; /* # bytes to store second block of regs. */ + unsigned int max_reg1; /* max. regno in first block */ + unsigned int var_size; /* # bytes that variables take up. */ + unsigned int save_fp; /* Nonzero if fp must be saved. */ + unsigned int save_lr; /* Nonzero if lr must be saved. */ + unsigned int lr_slot; /* Nonzero if the lr slot is needed. */ + unsigned int combine; /* Nonzero if we can combine the allocation of + variables and regs. */ + unsigned int interrupt; /* Nonzero if the function is an interrupt + handler. */ + unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */ +}; + +/* Current frame information calculated by visium_compute_frame_size. */ +static struct visium_frame_info current_frame_info; + +/* Accessor for current_frame_info.save_fp. */ + +static inline bool +current_function_saves_fp (void) +{ + return current_frame_info.save_fp != 0; +} + +/* Accessor for current_frame_info.save_lr. */ + +static inline bool +current_function_saves_lr (void) +{ + return current_frame_info.save_lr != 0; +} + +/* Accessor for current_frame_info.lr_slot. */ + +static inline bool +current_function_has_lr_slot (void) +{ + return current_frame_info.lr_slot != 0; +} + +/* Return non-zero if register REGNO needs to be saved in the frame. */ + +static int +visium_save_reg_p (int interrupt, int regno) +{ + switch (regno) + { + case HARD_FRAME_POINTER_REGNUM: + /* This register is call-saved but handled specially. */ + return 0; + + case MDC_REGNUM: + /* This register is fixed but can be modified. */ + break; + + case 29: + case 30: + /* These registers are fixed and hold the interrupt context. */ + return (interrupt != 0); + + default: + /* The other fixed registers are either immutable or special. */ + if (fixed_regs[regno]) + return 0; + break; + } + + if (interrupt) + { + if (crtl->is_leaf) + { + if (df_regs_ever_live_p (regno)) + return 1; + } + else if (call_used_regs[regno]) + return 1; + + /* To save mdb requires two temporary registers. To save mdc or + any of the floating registers requires one temporary + register. If this is an interrupt routine, the temporary + registers need to be saved as well. These temporary registers + are call used, so we only need deal with the case of leaf + functions here. */ + if (regno == PROLOGUE_TMP_REGNUM) + { + if (df_regs_ever_live_p (MDB_REGNUM) + || df_regs_ever_live_p (MDC_REGNUM)) + return 1; + + for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++) + if (df_regs_ever_live_p (i)) + return 1; + } + + else if (regno == PROLOGUE_TMP_REGNUM + 1) + { + if (df_regs_ever_live_p (MDB_REGNUM)) + return 1; + } + } + + return df_regs_ever_live_p (regno) && !call_used_regs[regno]; +} + +/* Compute the frame size required by the function. This function is called + during the reload pass and also by visium_expand_prologue. */ + +static int +visium_compute_frame_size (int size) +{ + const int save_area_size = visium_reg_parm_save_area_size; + const int var_size = VISIUM_STACK_ALIGN (size); + const int save_fp + = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM); + const int save_lr = frame_pointer_needed || !crtl->is_leaf; + const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum); + const int local_frame_offset + = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD; + const int interrupt = visium_interrupt_function_p (); + unsigned int mask[last_type]; + int reg_size1 = 0; + int max_reg1 = 0; + int reg_size2 = 0; + int reg_size; + int combine; + int frame_size; + int regno; + + memset (mask, 0, last_type * sizeof (unsigned int)); + + /* The registers may need stacking in 2 blocks since only 32 32-bit words + can be indexed from a given base address. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (visium_save_reg_p (interrupt, regno)) + { + enum reg_type reg_type = GET_REG_TYPE (regno); + int mask_bit = 1 << (regno - first_regno[reg_type]); + int nbytes = reg_type_size[reg_type]; + + if (reg_size1 + nbytes > 32 * UNITS_PER_WORD) + break; + + reg_size1 += nbytes; + max_reg1 = regno; + mask[reg_type] |= mask_bit; + } + } + + for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (visium_save_reg_p (interrupt, regno)) + { + enum reg_type reg_type = GET_REG_TYPE (regno); + int mask_bit = 1 << (regno - first_regno[reg_type]); + int nbytes = reg_type_size[reg_type]; + + reg_size2 += nbytes; + mask[reg_type] |= mask_bit; + } + } + + reg_size = reg_size2 ? reg_size2 : reg_size1; + combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD; + frame_size + = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size; + + current_frame_info.save_area_size = save_area_size; + current_frame_info.reg_size1 = reg_size1; + current_frame_info.max_reg1 = max_reg1; + current_frame_info.reg_size2 = reg_size2; + current_frame_info.var_size = var_size; + current_frame_info.save_fp = save_fp; + current_frame_info.save_lr = save_lr; + current_frame_info.lr_slot = lr_slot; + current_frame_info.combine = combine; + current_frame_info.interrupt = interrupt; + + memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int)); + + return frame_size; +} + +/* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define + the offset between two registers, one to be eliminated, and the other its + replacement, at the start of a routine. */ + +int +visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) +{ + const int frame_size = visium_compute_frame_size (get_frame_size ()); + const int save_fp = current_frame_info.save_fp; + const int save_lr = current_frame_info.save_lr; + const int lr_slot = current_frame_info.lr_slot; + const int local_frame_offset + = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD; + int offset; + + if (from == FRAME_POINTER_REGNUM) + offset = local_frame_offset; + else if (from == ARG_POINTER_REGNUM) + offset = frame_size; + else + gcc_unreachable (); + + return offset; +} + +/* For an interrupt handler, we may be saving call-clobbered registers. + Say the epilogue uses these in addition to the link register. */ + +int +visium_epilogue_uses (int regno) +{ + if (regno == LINK_REGNUM) + return 1; + + if (reload_completed) + { + enum reg_type reg_type = GET_REG_TYPE (regno); + int mask_bit = 1 << (regno - first_regno[reg_type]); + + return (current_frame_info.mask[reg_type] & mask_bit) != 0; + } + + return 0; +} + +/* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */ + +static rtx +emit_frame_insn (rtx x) +{ + x = emit_insn (x); + RTX_FRAME_RELATED_P (x) = 1; + return x; +} + +/* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to + HIGH_REGNO at OFFSET from the stack pointer. */ + +static void +visium_save_regs (int alloc, int offset, int low_regno, int high_regno) +{ + /* If this is an interrupt handler function, then mark the register + stores as volatile. This will prevent the instruction scheduler + from scrambling the order of register saves. */ + const int volatile_p = current_frame_info.interrupt; + int regno; + + /* Allocate the stack space. */ + emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-alloc))); + + for (regno = low_regno; regno <= high_regno; regno++) + { + enum reg_type reg_type = GET_REG_TYPE (regno); + int mask_bit = 1 << (regno - first_regno[reg_type]); + rtx insn; + + if (current_frame_info.mask[reg_type] & mask_bit) + { + offset -= reg_type_size[reg_type]; + switch (reg_type) + { + case general: + { + rtx mem + = gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + MEM_VOLATILE_P (mem) = volatile_p; + emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno))); + } + break; + + case mdb: + { + rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (DImode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (DImode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movdi (tmp, reg)); + /* Do not generate CFI if in interrupt handler. */ + if (volatile_p) + emit_insn (gen_movdi (mem, tmp)); + else + { + insn = emit_frame_insn (gen_movdi (mem, tmp)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, mem, reg)); + } + } + break; + + case mdc: + { + rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (SImode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movsi (tmp, reg)); + insn = emit_frame_insn (gen_movsi (mem, tmp)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, mem, reg)); + } + break; + + case floating: + { + rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (SFmode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (SFmode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movsf (tmp, reg)); + insn = emit_frame_insn (gen_movsf (mem, tmp)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, mem, reg)); + } + break; + + default: + break; + } + } + } +} + +/* This function generates the code for function entry. */ + +void +visium_expand_prologue (void) +{ + const int frame_size = visium_compute_frame_size (get_frame_size ()); + const int save_area_size = current_frame_info.save_area_size; + const int reg_size1 = current_frame_info.reg_size1; + const int max_reg1 = current_frame_info.max_reg1; + const int reg_size2 = current_frame_info.reg_size2; + const int var_size = current_frame_info.var_size; + const int save_fp = current_frame_info.save_fp; + const int save_lr = current_frame_info.save_lr; + const int lr_slot = current_frame_info.lr_slot; + const int local_frame_offset + = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD; + const int combine = current_frame_info.combine; + int reg_size; + int first_reg; + int fsize; + + /* Save the frame size for future references. */ + visium_frame_size = frame_size; + + if (flag_stack_usage_info) + current_function_static_stack_size = frame_size; + + /* If the registers have to be stacked in 2 blocks, stack the first one. */ + if (reg_size2) + { + visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1); + reg_size = reg_size2; + first_reg = max_reg1 + 1; + fsize = local_frame_offset + var_size + reg_size2; + } + else + { + reg_size = reg_size1; + first_reg = 0; + fsize = local_frame_offset + var_size + reg_size1 + save_area_size; + } + + /* If we can't combine register stacking with variable allocation, partially + allocate and stack the (remaining) registers now. */ + if (reg_size && !combine) + visium_save_regs (fsize - local_frame_offset - var_size, reg_size, + first_reg, FIRST_PSEUDO_REGISTER - 1); + + /* If we can combine register stacking with variable allocation, fully + allocate and stack the (remaining) registers now. */ + if (reg_size && combine) + visium_save_regs (fsize, local_frame_offset + var_size + reg_size, + first_reg, FIRST_PSEUDO_REGISTER - 1); + + /* Otherwise space may still need to be allocated for the variables. */ + else if (fsize) + { + const int alloc_size = reg_size ? local_frame_offset + var_size : fsize; + + if (alloc_size > 65535) + { + rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn; + emit_insn (gen_movsi (tmp, GEN_INT (alloc_size))); + insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx, + stack_pointer_rtx, + tmp)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (-alloc_size)))); + } + else + emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-alloc_size))); + } + + if (save_fp) + emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx), + hard_frame_pointer_rtx)); + + if (frame_pointer_needed) + emit_frame_insn (gen_stack_save ()); + + if (save_lr) + { + rtx base_rtx, mem; + + /* Normally the frame pointer and link register get saved via + write.l (sp),fp + move.l fp,sp + write.l 1(sp),r21 + + Indexing off sp rather than fp to store the link register + avoids presenting the instruction scheduler with an initial + pipeline hazard. If however the frame is needed for eg. + __builtin_return_address which needs to retrieve the saved + value of the link register from the stack at fp + 4 then + indexing from sp can confuse the dataflow, causing the link + register to be retrieved before it has been saved. */ + if (cfun->machine->frame_needed) + base_rtx = hard_frame_pointer_rtx; + else + base_rtx = stack_pointer_rtx; + + mem = gen_frame_mem (SImode, + plus_constant (Pmode, + base_rtx, save_fp * UNITS_PER_WORD)); + emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM))); + } +} + +static GTY(()) rtx cfa_restores; + +/* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */ + +static void +visium_add_cfa_restore_note (rtx reg) +{ + cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); +} + +/* Add queued REG_CFA_RESTORE notes to INSN, if any. */ + +static void +visium_add_queued_cfa_restore_notes (rtx insn) +{ + rtx last; + if (!cfa_restores) + return; + for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1)) + ; + XEXP (last, 1) = REG_NOTES (insn); + REG_NOTES (insn) = cfa_restores; + cfa_restores = NULL_RTX; +} + +/* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET + from the stack pointer and pop DEALLOC bytes off the stack. */ + +static void +visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno) +{ + /* If this is an interrupt handler function, then mark the register + restores as volatile. This will prevent the instruction scheduler + from scrambling the order of register restores. */ + const int volatile_p = current_frame_info.interrupt; + int r30_offset = -1; + int regno; + + for (regno = high_regno; regno >= low_regno; --regno) + { + enum reg_type reg_type = GET_REG_TYPE (regno); + int mask_bit = 1 << (regno - first_regno[reg_type]); + + if (current_frame_info.mask[reg_type] & mask_bit) + { + switch (reg_type) + { + case general: + /* Postpone restoring the interrupted context registers + until last, since they need to be preceded by a dsi. */ + if (regno == 29) + ; + else if (regno == 30) + r30_offset = offset; + else + { + rtx mem + = gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, + offset)); + rtx reg = gen_rtx_REG (SImode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movsi (reg, mem)); + visium_add_cfa_restore_note (reg); + } + break; + + case mdb: + { + rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (DImode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (DImode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movdi (tmp, mem)); + emit_insn (gen_movdi (reg, tmp)); + /* Do not generate CFI if in interrupt handler. */ + if (!volatile_p) + visium_add_cfa_restore_note (reg); + } + break; + + case mdc: + { + rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (SImode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movsi (tmp, mem)); + emit_insn (gen_movsi (reg, tmp)); + visium_add_cfa_restore_note (reg); + } + break; + + case floating: + { + rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM); + rtx mem + = gen_frame_mem (SFmode, + plus_constant (Pmode, + stack_pointer_rtx, offset)); + rtx reg = gen_rtx_REG (SFmode, regno); + MEM_VOLATILE_P (mem) = volatile_p; + emit_insn (gen_movsf (tmp, mem)); + emit_insn (gen_movsf (reg, tmp)); + visium_add_cfa_restore_note (reg); + } + break; + + default: + break; + } + + offset += reg_type_size[reg_type]; + } + } + + /* If the interrupted context needs to be restored, precede the + restores of r29 and r30 by a dsi. */ + if (r30_offset >= 0) + { + emit_insn (gen_dsi ()); + emit_move_insn (gen_rtx_REG (SImode, 30), + gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, + r30_offset))); + emit_move_insn (gen_rtx_REG (SImode, 29), + gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, + r30_offset + 4))); + } + + /* Deallocate the stack space. */ + rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc))); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (dealloc)))); + visium_add_queued_cfa_restore_notes (insn); +} + +/* This function generates the code for function exit. */ + +void +visium_expand_epilogue (void) +{ + const int save_area_size = current_frame_info.save_area_size; + const int reg_size1 = current_frame_info.reg_size1; + const int max_reg1 = current_frame_info.max_reg1; + const int reg_size2 = current_frame_info.reg_size2; + const int var_size = current_frame_info.var_size; + const int restore_fp = current_frame_info.save_fp; + const int restore_lr = current_frame_info.save_lr; + const int lr_slot = current_frame_info.lr_slot; + const int local_frame_offset + = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD; + const int combine = current_frame_info.combine; + int reg_size; + int last_reg; + int fsize; + + /* Do not bother restoring the stack pointer if it hasn't been changed in + the function since it was saved _after_ the allocation of the frame. */ + if (!crtl->sp_is_unchanging) + emit_insn (gen_stack_restore ()); + + /* Restore the frame pointer if necessary. The usual code would be: + + move.l sp,fp + read.l fp,(sp) + + but for the MCM this constitutes a stall/hazard so it is changed to: + + move.l sp,fp + read.l fp,(fp) + + if the stack pointer has actually been restored. */ + if (restore_fp) + { + rtx src; + + if (TARGET_MCM && !crtl->sp_is_unchanging) + src = gen_frame_mem (SImode, hard_frame_pointer_rtx); + else + src = gen_frame_mem (SImode, stack_pointer_rtx); + + rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src)); + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + hard_frame_pointer_rtx)); + visium_add_cfa_restore_note (hard_frame_pointer_rtx); + } + + /* Restore the link register if necessary. */ + if (restore_lr) + { + rtx mem = gen_frame_mem (SImode, + plus_constant (Pmode, + stack_pointer_rtx, + restore_fp * UNITS_PER_WORD)); + rtx reg = gen_rtx_REG (SImode, LINK_REGNUM); + emit_insn (gen_movsi (reg, mem)); + visium_add_cfa_restore_note (reg); + } + + /* If we have two blocks of registers, deal with the second one first. */ + if (reg_size2) + { + reg_size = reg_size2; + last_reg = max_reg1 + 1; + fsize = local_frame_offset + var_size + reg_size2; + } + else + { + reg_size = reg_size1; + last_reg = 0; + fsize = local_frame_offset + var_size + reg_size1 + save_area_size; + } + + /* If the variable allocation could be combined with register stacking, + restore the (remaining) registers and fully deallocate now. */ + if (reg_size && combine) + visium_restore_regs (fsize, local_frame_offset + var_size, + FIRST_PSEUDO_REGISTER - 1, last_reg); + + /* Otherwise deallocate the variables first. */ + else if (fsize) + { + const int pop_size = reg_size ? local_frame_offset + var_size : fsize; + rtx insn; + + if (pop_size > 65535) + { + rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM); + emit_move_insn (tmp, GEN_INT (pop_size)); + insn = emit_frame_insn (gen_stack_pop (tmp)); + } + else + insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size))); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (pop_size)))); + visium_add_queued_cfa_restore_notes (insn); + } + + /* If the variable allocation couldn't be combined with register stacking, + restore the (remaining) registers now and partially deallocate. */ + if (reg_size && !combine) + visium_restore_regs (fsize - local_frame_offset - var_size, 0, + FIRST_PSEUDO_REGISTER - 1, last_reg); + + /* If the first block of registers has yet to be restored, do it now. */ + if (reg_size2) + visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0); + + /* If this is an exception return, make the necessary stack adjustment. */ + if (crtl->calls_eh_return) + emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX)); +} + +/* Return true if it is appropriate to emit `return' instructions in the + body of a function. */ + +bool +visium_can_use_return_insn_p (void) +{ + return reload_completed + && visium_frame_size == 0 + && !visium_interrupt_function_p (); +} + +/* Return the register class required for an intermediate register used to + copy a register of RCLASS from/to X. If no such intermediate register is + required, return NO_REGS. If more than one such intermediate register is + required, describe the one that is closest in the copy chain to the reload + register. */ + +static reg_class_t +visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x, + reg_class_t rclass, + enum machine_mode mode ATTRIBUTE_UNUSED, + secondary_reload_info *sri ATTRIBUTE_UNUSED) +{ + int regno = true_regnum (x); + + /* For MDB, MDC and FP_REGS, a general register is needed for a move to + or from memory. */ + if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS)) + return GENERAL_REGS; + + /* Moves between MDB, MDC and FP_REGS also require a general register. */ + else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS) + || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC))) + return GENERAL_REGS; + + /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */ + else if ((regno == R_MDB && rclass == MDC) + || (rclass == MDB && regno == R_MDC)) + return GENERAL_REGS; + + return NO_REGS; +} + +/* Return true if pseudos that have been assigned to registers of RCLASS + would likely be spilled because registers of RCLASS are needed for + spill registers. */ + +static bool +visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED) +{ + /* Return false for classes R1, R2 and R3, which are intended to be used + only in the source code in conjunction with block move instructions. */ + return false; +} + +/* Return the register number if OP is a REG or a SUBREG of a REG, and + INVALID_REGNUM in all the other cases. */ + +unsigned int +reg_or_subreg_regno (rtx op) +{ + unsigned int regno; + + if (GET_CODE (op) == REG) + regno = REGNO (op); + else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) + { + if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER) + regno = subreg_regno (op); + else + regno = REGNO (SUBREG_REG (op)); + } + else + regno = INVALID_REGNUM; + + return regno; +} + +#include "gt-visium.h" diff --git a/gcc/config/visium/visium.h b/gcc/config/visium/visium.h new file mode 100644 index 0000000..d78e221 --- /dev/null +++ b/gcc/config/visium/visium.h @@ -0,0 +1,1739 @@ +/* Definitions of target machine for Visium. + Copyright (C) 2002-2015 Free Software Foundation, Inc. + Contributed by C.Nettleton, J.P.Parkes and P.Garbett. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + + +/* Controlling the Compilation Driver, `gcc' */ + +/* Pass -mtune=* options to the assembler */ +#undef ASM_SPEC +#define ASM_SPEC "%{mcpu=gr6:-mtune=gr6; :-mtune=mcm}" + +/* Define symbols for the preprocessor. */ +#define CPP_SPEC "%{mcpu=gr6:-D__gr6__; :-D__gr5__}" + +/* Targets of a link */ +#define LIB_SPEC "\ +%{msim : --start-group -lc -lsim --end-group ; \ + mdebug : --start-group -lc -ldebug --end-group ; \ + : -lc -lnosys }" + +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" +#define STARTFILE_SPEC "crti.o%s crtbegin.o%s crt0.o%s" + +/* Run-time Target Specification */ + +/* TARGET_CPU_CPP_BUILTINS() This function-like macro expands to a + block of code that defines built-in preprocessor macros and + assertions for the target cpu, using the functions builtin_define, + builtin_define_std and builtin_assert. When the front end calls + this macro it provides a trailing semicolon, and since it has + finished command line option processing your code can use those + results freely. builtin_assert takes a string in the form you pass + to the command-line option -A, such as cpu=mips, and creates the + assertion. builtin_define takes a string in the form accepted by + option -D and unconditionally defines the macro. + + builtin_define_std takes a string representing the name of an + object-like macro. If it doesn't lie in the user's namespace, + builtin_define_std defines it unconditionally. Otherwise, it + defines a version with two leading underscores, and another version + with two leading and trailing underscores, and defines the original + only if an ISO standard was not requested on the command line. For + example, passing unix defines __unix, __unix__ and possibly unix; + passing _mips defines __mips, __mips__ and possibly _mips, and + passing _ABI64 defines only _ABI64. + + You can also test for the C dialect being compiled. The variable + c_language is set to one of clk_c, clk_cplusplus or + clk_objective_c. Note that if we are preprocessing assembler, this + variable will be clk_c but the function-like macro + preprocessing_asm_p() will return true, so you might want to check + for that first. If you need to check for strict ANSI, the variable + flag_iso can be used. The function-like macro + preprocessing_trad_p() can be used to check for traditional + preprocessing. */ +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__VISIUM__"); \ + if (TARGET_MCM) \ + builtin_define ("__VISIUM_ARCH_MCM__"); \ + if (TARGET_BMI) \ + builtin_define ("__VISIUM_ARCH_BMI__"); \ + if (TARGET_FPU_IEEE) \ + builtin_define ("__VISIUM_ARCH_FPU_IEEE__"); \ + } \ + while (0) + +/* Recast the cpu class to be the cpu attribute. + Every file includes us, but not every file includes insn-attr.h. */ +#define visium_cpu_attr ((enum attr_cpu) visium_cpu) + +/* Defining data structures for per-function information. + + If the target needs to store information on a per-function basis, + GCC provides a macro and a couple of variables to allow this. Note, + just using statics to store the information is a bad idea, since + GCC supports nested functions, so you can be halfway through + encoding one function when another one comes along. + + GCC defines a data structure called struct function which contains + all of the data specific to an individual function. This structure + contains a field called machine whose type is struct + machine_function *, which can be used by targets to point to their + own specific data. + + If a target needs per-function specific data it should define the + type struct machine_function and also the macro + INIT_EXPANDERS. This macro should be used to initialize the + function pointer init_machine_status. This pointer is explained + below. + + One typical use of per-function, target specific data is to create + an RTX to hold the register containing the function's return + address. This RTX can then be used to implement the + __builtin_return_address function, for level 0. + + Note--earlier implementations of GCC used a single data area to + hold all of the per-function information. Thus when processing of a + nested function began the old per-function data had to be pushed + onto a stack, and when the processing was finished, it had to be + popped off the stack. GCC used to provide function pointers called + save_machine_status and restore_machine_status to handle the saving + and restoring of the target specific information. Since the single + data area approach is no longer used, these pointers are no longer + supported. + + The macro and function pointers are described below. + + INIT_EXPANDERS: + + Macro called to initialize any target specific information. This + macro is called once per function, before generation of any RTL has + begun. The intention of this macro is to allow the initialization + of the function pointers below. + + init_machine_status: + This is a void (*)(struct function *) function pointer. If this + pointer is non-NULL it will be called once per function, before + function compilation starts, in order to allow the target to + perform any target specific initialization of the struct function + structure. It is intended that this would be used to initialize the + machine of that structure. struct machine_function structures are + expected to be freed by GC. Generally, any memory that they + reference must be allocated by using ggc_alloc, including the + structure itself. */ + +#define INIT_EXPANDERS visium_init_expanders () + +/* Storage Layout + + Note that the definitions of the macros in this table which are + sizes or alignments measured in bits do not need to be constant. + They can be C expressions that refer to static variables, such as + the `target_flags'. + + `BITS_BIG_ENDIAN' + + Define this macro to have the value 1 if the most significant bit + in a byte has the lowest number; otherwise define it to have the + value zero. This means that bit-field instructions count from the + most significant bit. If the machine has no bit-field + instructions, then this must still be defined, but it doesn't + matter which value it is defined to. This macro need not be a + constant. + + This macro does not affect the way structure fields are packed into + bytes or words; that is controlled by `BYTES_BIG_ENDIAN'. */ +#define BITS_BIG_ENDIAN 1 + +/* `BYTES_BIG_ENDIAN' + + Define this macro to have the value 1 if the most significant byte + in a word has the lowest number. This macro need not be a + constant.*/ +#define BYTES_BIG_ENDIAN 1 + +/* `WORDS_BIG_ENDIAN' + + Define this macro to have the value 1 if, in a multiword object, + the most significant word has the lowest number. This applies to + both memory locations and registers; GNU CC fundamentally assumes + that the order of words in memory is the same as the order in + registers. This macro need not be a constant. */ +#define WORDS_BIG_ENDIAN 1 + +/* `BITS_PER_WORD' + + Number of bits in a word; normally 32. */ +#define BITS_PER_WORD 32 + +/* `UNITS_PER_WORD' + + Number of storage units in a word; normally 4. */ +#define UNITS_PER_WORD 4 + +/* `POINTER_SIZE' + + Width of a pointer, in bits. You must specify a value no wider + than the width of `Pmode'. If it is not equal to the width of + `Pmode', you must define `POINTERS_EXTEND_UNSIGNED'. */ +#define POINTER_SIZE 32 + +/* `PARM_BOUNDARY' + + Normal alignment required for function parameters on the stack, in + bits. All stack parameters receive at least this much alignment + regardless of data type. On most machines, this is the same as the + size of an integer. */ +#define PARM_BOUNDARY 32 + +/* `STACK_BOUNDARY' + + Define this macro if you wish to preserve a certain alignment for + the stack pointer. The definition is a C expression for the + desired alignment (measured in bits). + + If `PUSH_ROUNDING' is not defined, the stack will always be aligned + to the specified boundary. If `PUSH_ROUNDING' is defined and + specifies a less strict alignment than `STACK_BOUNDARY', the stack + may be momentarily unaligned while pushing arguments. */ +#define STACK_BOUNDARY 32 + +#define VISIUM_STACK_ALIGN(LOC) (((LOC) + 3) & ~3) + +/* `FUNCTION_BOUNDARY' + + Alignment required for a function entry point, in bits. */ +#define FUNCTION_BOUNDARY 32 + +/* `BIGGEST_ALIGNMENT' + + Biggest alignment that any data type can require on this machine, + in bits. */ +#define BIGGEST_ALIGNMENT 32 + +/* `DATA_ALIGNMENT (TYPE, BASIC-ALIGN)` + + If defined, a C expression to compute the alignment for a variable + in the static store. TYPE is the data type, and BASIC-ALIGN is + the alignment that the object would ordinarily have. The value of + this macro is used instead of that alignment to align the object. */ +#define DATA_ALIGNMENT(TYPE,ALIGN) visium_data_alignment (TYPE, ALIGN) + +/* `CONSTANT_ALIGNMENT (CONSTANT, BASIC-ALIGN)` + + If defined, a C expression to compute the alignment given to a + constant that is being placed in memory. CONSTANT is the constant + and BASIC-ALIGN is the alignment that the object would ordinarily + have. The value of this macro is used instead of that alignment to + align the object. */ +#define CONSTANT_ALIGNMENT(EXP,ALIGN) \ + visium_data_alignment (TREE_TYPE (EXP), ALIGN) + +/* `LOCAL_ALIGNMENT (TYPE, BASIC-ALIGN)` + + If defined, a C expression to compute the alignment for a variable + in the local store. TYPE is the data type, and BASIC-ALIGN is the + alignment that the object would ordinarily have. The value of this + macro is used instead of that alignment to align the object. */ +#define LOCAL_ALIGNMENT(TYPE,ALIGN) visium_data_alignment (TYPE, ALIGN) + +/* `EMPTY_FIELD_BOUNDARY' + + Alignment in bits to be given to a structure bit field that follows + an empty field such as `int : 0;'. + + Note that `PCC_BITFIELD_TYPE_MATTERS' also affects the alignment + that results from an empty field. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* `STRICT_ALIGNMENT' + + Define this macro to be the value 1 if instructions will fail to + work if given data not on the nominal alignment. If instructions + will merely go slower in that case, define this macro as 0. */ +#define STRICT_ALIGNMENT 1 + +/* `TARGET_FLOAT_FORMAT' + + A code distinguishing the floating point format of the target + machine. There are three defined values: + + `IEEE_FLOAT_FORMAT' + This code indicates IEEE floating point. It is the default; + there is no need to define this macro when the format is IEEE. + + `VAX_FLOAT_FORMAT' + This code indicates the peculiar format used on the Vax. + + `UNKNOWN_FLOAT_FORMAT' + This code indicates any other format. + + The value of this macro is compared with `HOST_FLOAT_FORMAT' to + determine whether the target machine has the same format as the + host machine. If any other formats are actually in use on + supported machines, new codes should be defined for them. + + The ordering of the component words of floating point values + stored in memory is controlled by `FLOAT_WORDS_BIG_ENDIAN' for the + target machine and `HOST_FLOAT_WORDS_BIG_ENDIAN' for the host. */ +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT +#define UNITS_PER_HWFPVALUE 4 + +/* Layout of Source Language Data Types + + These macros define the sizes and other characteristics of the + standard basic data types used in programs being compiled. Unlike + the macros in the previous section, these apply to specific + features of C and related languages, rather than to fundamental + aspects of storage layout. */ + +/* `INT_TYPE_SIZE' + + A C expression for the size in bits of the type `int' on the target + machine. If you don't define this, the default is one word. */ +#define INT_TYPE_SIZE 32 + +/* `SHORT_TYPE_SIZE' + + A C expression for the size in bits of the type `short' on the + target machine. If you don't define this, the default is half a + word. (If this would be less than one storage unit, it is rounded + up to one unit.) */ +#define SHORT_TYPE_SIZE 16 + +/* `LONG_TYPE_SIZE' + + A C expression for the size in bits of the type `long' on the + target machine. If you don't define this, the default is one word. */ +#define LONG_TYPE_SIZE 32 + +/* `LONG_LONG_TYPE_SIZE' + + A C expression for the size in bits of the type `long long' on the + target machine. If you don't define this, the default is two + words. If you want to support GNU Ada on your machine, the value + of macro must be at least 64. */ +#define LONG_LONG_TYPE_SIZE 64 + +/* `CHAR_TYPE_SIZE' + + A C expression for the size in bits of the type `char' on the + target machine. If you don't define this, the default is one + quarter of a word. (If this would be less than one storage unit, + it is rounded up to one unit.) */ +#define CHAR_TYPE_SIZE 8 + +/* `FLOAT_TYPE_SIZE' + + A C expression for the size in bits of the type `float' on the + target machine. If you don't define this, the default is one word. */ +#define FLOAT_TYPE_SIZE 32 + +/* `DOUBLE_TYPE_SIZE' + + A C expression for the size in bits of the type `double' on the + target machine. If you don't define this, the default is two + words. */ +#define DOUBLE_TYPE_SIZE 64 + +/* `LONG_DOUBLE_TYPE_SIZE' + + A C expression for the size in bits of the type `long double' on + the target machine. If you don't define this, the default is two + words. */ +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE + +/* `WIDEST_HARDWARE_FP_SIZE' + + A C expression for the size in bits of the widest floating-point + format supported by the hardware. If you define this macro, you + must specify a value less than or equal to the value of + `LONG_DOUBLE_TYPE_SIZE'. If you do not define this macro, the + value of `LONG_DOUBLE_TYPE_SIZE' is the default. */ + +/* `DEFAULT_SIGNED_CHAR' + + An expression whose value is 1 or 0, according to whether the type + `char' should be signed or unsigned by default. The user can + always override this default with the options `-fsigned-char' and + `-funsigned-char'. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* `SIZE_TYPE' + + A C expression for a string describing the name of the data type to + use for size values. The typedef name `size_t' is defined using + the contents of the string. + + The string can contain more than one keyword. If so, separate them + with spaces, and write first any length keyword, then `unsigned' if + appropriate, and finally `int'. The string must exactly match one + of the data type names defined in the function + `init_decl_processing' in the file `c-decl.c'. You may not omit + `int' or change the order--that would cause the compiler to crash + on startup. + + If you don't define this macro, the default is `"long unsigned + int"'. */ +#define SIZE_TYPE "unsigned int" + +/* `PTRDIFF_TYPE' + + A C expression for a string describing the name of the data type to + use for the result of subtracting two pointers. The typedef name + `ptrdiff_t' is defined using the contents of the string. See + `SIZE_TYPE' above for more information. + + If you don't define this macro, the default is `"long int"'. */ +#define PTRDIFF_TYPE "long int" + +/* Newlib uses the unsigned type corresponding to ptrdiff_t for + uintptr_t; this is the same as size_t for most newlib-using + targets, but not for us. */ +#define UINTPTR_TYPE "long unsigned int" + +/* `WCHAR_TYPE' + + A C expression for a string describing the name of the data type to + use for wide characters. The typedef name `wchar_t' is defined + using the contents of the string. See `SIZE_TYPE' above for more + information. + + If you don't define this macro, the default is `"int"'. */ +#define WCHAR_TYPE "short int" + +/* `WCHAR_TYPE_SIZE' + + A C expression for the size in bits of the data type for wide + characters. This is used in `cpp', which cannot make use of + `WCHAR_TYPE'. */ +#define WCHAR_TYPE_SIZE 16 + +/* Register Usage + + This section explains how to describe what registers the target + machine has, and how (in general) they can be used. */ + +/* `FIRST_PSEUDO_REGISTER' + + Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + Register 51 is used as the argument pointer register. + Register 52 is used as the soft frame pointer register. */ +#define FIRST_PSEUDO_REGISTER 53 + +#define RETURN_REGNUM 1 +#define PROLOGUE_TMP_REGNUM 9 +#define LINK_REGNUM 21 +#define GP_LAST_REGNUM 31 +#define GP_REGISTER_P(REGNO) \ + (((unsigned) (REGNO)) <= GP_LAST_REGNUM) + +#define MDB_REGNUM 32 +#define MDC_REGNUM 33 + +#define FP_FIRST_REGNUM 34 +#define FP_LAST_REGNUM 49 +#define FP_RETURN_REGNUM (FP_FIRST_REGNUM + 1) +#define FP_REGISTER_P(REGNO) \ + (FP_FIRST_REGNUM <= (REGNO) && (REGNO) <= FP_LAST_REGNUM) + +#define FLAGS_REGNUM 50 + +/* `FIXED_REGISTERS' + + An initializer that says which registers are used for fixed + purposes all throughout the compiled code and are therefore not + available for general allocation. These would include the stack + pointer, the frame pointer (except on machines where that can be + used as a general register when no frame pointer is needed), the + program counter on machines where that is considered one of the + addressable registers, and any other numbered register with a + standard use. + + This information is expressed as a sequence of numbers, separated + by commas and surrounded by braces. The Nth number is 1 if + register N is fixed, 0 otherwise. + + The table initialized from this macro, and the table initialized by + the following one, may be overridden at run time either + automatically, by the actions of the macro + `CONDITIONAL_REGISTER_USAGE', or by the user with the command + options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. + + r0 and f0 are immutable registers hardwired to 0. + r21 is the link register used for procedure linkage. + r23 is the stack pointer register. + r29 and r30 hold the interrupt context. + mdc is a read-only register because the writemdc instruction + terminates all the operations of the EAM on the GR6. */ +#define FIXED_REGISTERS \ + { 1, 0, 0, 0, 0, 0, 0, 0, /* r0 .. r7 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, /* r8 .. r15 */ \ + 0, 0, 0, 0, 0, 1, 0, 1, /* r16 .. r23 */ \ + 0, 0, 0, 0, 0, 1, 1, 0, /* r24 .. r31 */ \ + 0, 1, /* mdb, mdc */ \ + 1, 0, 0, 0, 0, 0, 0, 0, /* f0 .. f7 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \ + 1, 1, 1 } /* flags, arg, frame */ + +/* `CALL_USED_REGISTERS' + + Like `FIXED_REGISTERS' but has 1 for each register that is + clobbered (in general) by function calls as well as for fixed + registers. This macro therefore identifies the registers that are + not available for general allocation of values that must live + across function calls. + + If a register has 0 in `CALL_USED_REGISTERS', the compiler + automatically saves it on function entry and restores it on + function exit, if the register is used within the function. */ +#define CALL_USED_REGISTERS \ + { 1, 1, 1, 1, 1, 1, 1, 1, /* r0 .. r7 */ \ + 1, 1, 1, 0, 0, 0, 0, 0, /* r8 .. r15 */ \ + 0, 0, 0, 0, 1, 1, 0, 1, /* r16 .. r23 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, /* r24 .. r31 */ \ + 1, 1, /* mdb, mdc */ \ + 1, 1, 1, 1, 1, 1, 1, 1, /* f0 .. f7 */ \ + 1, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \ + 1, 1, 1 } /* flags, arg, frame */ + +/* Like `CALL_USED_REGISTERS' except this macro doesn't require that + the entire set of `FIXED_REGISTERS' be included. + (`CALL_USED_REGISTERS' must be a superset of `FIXED_REGISTERS'). + This macro is optional. If not specified, it defaults to the value + of `CALL_USED_REGISTERS'. */ +#define CALL_REALLY_USED_REGISTERS \ + { 0, 1, 1, 1, 1, 1, 1, 1, /* r0 .. r7 */ \ + 1, 1, 1, 0, 0, 0, 0, 0, /* r8 .. r15 */ \ + 0, 0, 0, 0, 1, 0, 0, 0, /* r16 .. r23 */ \ + 1, 1, 1, 1, 1, 0, 0, 1, /* r24 .. r31 */ \ + 1, 1, /* mdb, mdc */ \ + 1, 1, 1, 1, 1, 1, 1, 1, /* f0 .. f7 */ \ + 1, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \ + 1, 0, 0 } /* flags, arg, frame */ + +/* `REG_ALLOC_ORDER' + + If defined, an initializer for a vector of integers, containing the + numbers of hard registers in the order in which GCC should prefer + to use them (from most preferred to least). + + If this macro is not defined, registers are used lowest numbered + first (all else being equal). */ +#define REG_ALLOC_ORDER \ + { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, /* r10 .. r1 */ \ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, /* r11 .. r20 */ \ + 22, /* fp */ \ + 24, 25, 26, 27, 28, /* r24 .. r28 */ \ + 31, /* r31 */ \ + 32, 33, /* mdb, mdc */ \ + 42, 41, 40, 39, 38, 37, 36, 35, /* f8 .. f1 */ \ + 43, 44, 45, 46, 47, 48, 49, /* f9 .. f15 */ \ + 21, 23, /* lr, sp */ \ + 29, 30, /* r29, r30 */ \ + 50, 51, 52, /* flags, arg, frame */ \ + 0, 34 } /* r0, f0 */ + +/* `HARD_REGNO_NREGS (REGNO, MODE)' + + A C expression for the number of consecutive hard registers, + starting at register number REGNO, required to hold a value of mode + MODE. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) == MDB_REGNUM ? \ + ((GET_MODE_SIZE (MODE) + 2 * UNITS_PER_WORD - 1) / (2 * UNITS_PER_WORD)) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* `HARD_REGNO_RENAME_OK (OLD_REG, NEW_REG)' + + A C expression which is nonzero if hard register NEW_REG can be + considered for use as a rename register for hard register OLD_REG. */ +#define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \ + visium_hard_regno_rename_ok (OLD_REG, NEW_REG) + +/* `HARD_REGNO_MODE_OK (REGNO, MODE)' + + A C expression that is nonzero if it is permissible to store a + value of mode MODE in hard register number REGNO (or in several + registers starting with that one). + + Modes with sizes which cross from the one register class to the + other cannot be allowed. Only single floats are allowed in the + floating point registers, and only fixed point values in the EAM + registers. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (GP_REGISTER_P (REGNO) ? \ + GP_REGISTER_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1) \ + : FP_REGISTER_P (REGNO) ? \ + (MODE) == SFmode || ((MODE) == SImode && TARGET_FPU_IEEE) \ + : GET_MODE_CLASS (MODE) == MODE_INT \ + && HARD_REGNO_NREGS (REGNO, MODE) == 1) + +/* `MODES_TIEABLE_P (MODE1, MODE2)' + + A C expression that is nonzero if a value of mode MODE1 is + accessible in mode MODE2 without copying. + + If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, + MODE2)' are always the same for any R, then `MODES_TIEABLE_P + (MODE1, MODE2)' should be nonzero. If they differ for any R, you + should define this macro to return zero unless some other mechanism + ensures the accessibility of the value in a narrower mode. + + You should define this macro to return nonzero in as many cases as + possible since doing so will allow GNU CC to perform better + register allocation. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((GET_MODE_CLASS (MODE1) == MODE_INT) \ + && (GET_MODE_CLASS (MODE2) == MODE_INT)) + +/* Register Classes + + On many machines, the numbered registers are not all equivalent. + For example, certain registers may not be allowed for indexed + addressing; certain registers may not be allowed in some + instructions. These machine restrictions are described to the + compiler using "register classes". + + `enum reg_class' + + An enumeral type that must be defined with all the register class + names as enumeral values. `NO_REGS' must be first. `ALL_REGS' + must be the last register class, followed by one more enumeral + value, `LIM_REG_CLASSES', which is not a register class but rather + tells how many classes there are. + + Each register class has a number, which is the value of casting the + class name to type `int'. The number serves as an index in many of + the tables described below. */ + +enum reg_class +{ + NO_REGS, + MDB, + MDC, + FP_REGS, + FLAGS, + R1, + R2, + R3, + SIBCALL_REGS, + LOW_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +/* `N_REG_CLASSES' + + The number of distinct register classes, defined as follows. */ +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* `REG_CLASS_NAMES' + + An initializer containing the names of the register classes as C + string constants. These names are used in writing some of the + debugging dumps. */ +#define REG_CLASS_NAMES \ + {"NO_REGS", "MDB", "MDC", "FP_REGS", "FLAGS", "R1", "R2", "R3", \ + "SIBCALL_REGS", "LOW_REGS", "GENERAL_REGS", "ALL_REGS"} + +/* `REG_CLASS_CONTENTS' + + An initializer containing the contents of the register classes, as + integers which are bit masks. The Nth integer specifies the + contents of class N. The way the integer MASK is interpreted is + that register R is in the class if `MASK & (1 << R)' is 1. + + When the machine has more than 32 registers, an integer does not + suffice. Then the integers are replaced by sub-initializers, + braced groupings containing several integers. Each sub-initializer + must be suitable as an initializer for the type `HARD_REG_SET' + which is defined in `hard-reg-set.h'. */ +#define REG_CLASS_CONTENTS { \ + {0x00000000, 0x00000000}, /* NO_REGS */ \ + {0x00000000, 0x00000001}, /* MDB */ \ + {0x00000000, 0x00000002}, /* MDC */ \ + {0x00000000, 0x0003fffc}, /* FP_REGS */ \ + {0x00000000, 0x00040000}, /* FLAGS */ \ + {0x00000002, 0x00000000}, /* R1 */ \ + {0x00000004, 0x00000000}, /* R2 */ \ + {0x00000008, 0x00000000}, /* R3 */ \ + {0x000005ff, 0x00000000}, /* SIBCALL_REGS */ \ + {0x1fffffff, 0x00000000}, /* LOW_REGS */ \ + {0xffffffff, 0x00180000}, /* GENERAL_REGS */ \ + {0xffffffff, 0x001fffff}} /* ALL_REGS */ + +/* `REGNO_REG_CLASS (REGNO)' + + A C expression whose value is a register class containing hard + register REGNO. In general there is more than one such class; + choose a class which is "minimal", meaning that no smaller class + also contains the register. */ +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == MDB_REGNUM ? MDB : \ + (REGNO) == MDC_REGNUM ? MDC : \ + FP_REGISTER_P (REGNO) ? FP_REGS : \ + (REGNO) == FLAGS_REGNUM ? FLAGS : \ + (REGNO) == 1 ? R1 : \ + (REGNO) == 2 ? R2 : \ + (REGNO) == 3 ? R3 : \ + (REGNO) <= 8 || (REGNO) == 10 ? SIBCALL_REGS : \ + (REGNO) <= 28 ? LOW_REGS : \ + GENERAL_REGS) + +/* `BASE_REG_CLASS' + + A macro whose definition is the name of the class to which a valid + base register must belong. A base register is one used in an + address which is the register value plus a displacement. */ +#define BASE_REG_CLASS GENERAL_REGS + +#define BASE_REGISTER_P(REGNO) \ + (GP_REGISTER_P (REGNO) \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (REGNO) == FRAME_POINTER_REGNUM) + +/* `INDEX_REG_CLASS' + + A macro whose definition is the name of the class to which a valid + index register must belong. An index register is one used in an + address where its value is either multiplied by a scale factor or + added to another register (as well as added to a displacement). */ +#define INDEX_REG_CLASS NO_REGS + +/* `REGNO_OK_FOR_BASE_P (NUM)' + + A C expression which is nonzero if register number NUM is suitable + for use as a base register in operand addresses. It may be either + a suitable hard register or a pseudo register that has been + allocated such a hard register. */ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + (BASE_REGISTER_P (REGNO) || BASE_REGISTER_P ((unsigned)reg_renumber[REGNO])) + +/* `REGNO_OK_FOR_INDEX_P (NUM)' + + A C expression which is nonzero if register number NUM is suitable + for use as an index register in operand addresses. It may be + either a suitable hard register or a pseudo register that has been + allocated such a hard register. + + The difference between an index register and a base register is + that the index register may be scaled. If an address involves the + sum of two registers, neither one of them scaled, then either one + may be labeled the "base" and the other the "index"; but whichever + labeling is used must fit the machine's constraints of which + registers may serve in each capacity. The compiler will try both + labelings, looking for one that is valid, and will reload one or + both registers only if neither labeling works. */ +#define REGNO_OK_FOR_INDEX_P(REGNO) 0 + +/* `PREFERRED_RELOAD_CLASS (X, CLASS)' + + A C expression that places additional restrictions on the register + class to use when it is necessary to copy value X into a register + in class CLASS. The value is a register class; perhaps CLASS, or + perhaps another, smaller class. + + Sometimes returning a more restrictive class makes better code. + For example, on the 68000, when X is an integer constant that is in + range for a `moveq' instruction, the value of this macro is always + `DATA_REGS' as long as CLASS includes the data registers. + Requiring a data register guarantees that a `moveq' will be used. + + If X is a `const_double', by returning `NO_REGS' you can force X + into a memory constant. This is useful on certain machines where + immediate floating values cannot be loaded into certain kinds of + registers. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + +/* `CANNOT_CHANGE_MODE_CLASS (from, to, class) + + If defined, a C expression that returns nonzero for a `class' for + which a change from mode `from' to mode `to' is invalid. + + It's not obvious from the above that MDB cannot change mode. However + difficulties arise from expressions of the form + + (subreg:SI (reg:DI R_MDB) 0) + + There is no way to convert that reference to a single machine + register and, without the following definition, reload will quietly + convert it to + + (reg:SI R_MDB) */ +#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \ + (CLASS == MDB ? (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) : 0) + +/* `CLASS_MAX_NREGS (CLASS, MODE)' + + A C expression for the maximum number of consecutive registers of + class CLASS needed to hold a value of mode MODE. + + This is closely related to the macro `HARD_REGNO_NREGS'. In fact, + the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be + the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO + values in the class CLASS. + + This macro helps control the handling of multiple-word values in + the reload pass. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == MDB ? \ + ((GET_MODE_SIZE (MODE) + 2 * UNITS_PER_WORD - 1) / (2 * UNITS_PER_WORD)) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack Layout and Calling Conventions + + Basic Stack Layout + + `STACK_GROWS_DOWNWARD' + Define this macro if pushing a word onto the stack moves the stack + pointer to a smaller address. */ +#define STACK_GROWS_DOWNWARD 1 + +/* `STARTING_FRAME_OFFSET' + + Offset from the frame pointer to the first local variable slot to + be allocated. + + If `FRAME_GROWS_DOWNWARD', find the next slot's offset by + subtracting the first slot's length from `STARTING_FRAME_OFFSET'. + Otherwise, it is found by adding the length of the first slot to + the value `STARTING_FRAME_OFFSET'. */ +#define STARTING_FRAME_OFFSET 0 + +/* `FIRST_PARM_OFFSET (FUNDECL)' + + Offset from the argument pointer register to the first argument's + address. On some machines it may depend on the data type of the + function. + + If `ARGS_GROW_DOWNWARD', this is the offset to the location above + the first argument's address. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* `DYNAMIC_CHAIN_ADDRESS (FRAMEADDR)' + + A C expression whose value is RTL representing the address in a + stack frame where the pointer to the caller's frame is stored. + Assume that FRAMEADDR is an RTL expression for the address of the + stack frame itself. + + If you don't define this macro, the default is to return the value + of FRAMEADDR--that is, the stack frame address is also the address + of the stack word that points to the previous frame. */ +#define DYNAMIC_CHAIN_ADDRESS(FRAMEADDR) \ + visium_dynamic_chain_address (FRAMEADDR) + +/* `RETURN_ADDR_RTX (COUNT, FRAMEADDR)' + + A C expression whose value is RTL representing the value of the + return address for the frame COUNT steps up from the current frame, + after the prologue. FRAMEADDR is the frame pointer of the COUNT + frame, or the frame pointer of the COUNT - 1 frame if + `RETURN_ADDR_IN_PREVIOUS_FRAME' is defined. + + The value of the expression must always be the correct address when + COUNT is zero, but may be `NULL_RTX' if there is not way to + determine the return address of other frames. */ +#define RETURN_ADDR_RTX(COUNT,FRAMEADDR) \ + visium_return_addr_rtx (COUNT, FRAMEADDR) + +/* Exception Handling + + `EH_RETURN_DATA_REGNO' + + A C expression whose value is the Nth register number used for data + by exception handlers or INVALID_REGNUM if fewer than N registers + are available. + + The exception handling library routines communicate with the + exception handlers via a set of agreed upon registers. */ +#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 11 : INVALID_REGNUM) +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, 8) +#define EH_RETURN_HANDLER_RTX visium_eh_return_handler_rtx () + +/* Registers That Address the Stack Frame + + This discusses registers that address the stack frame. + + `STACK_POINTER_REGNUM' + + The register number of the stack pointer register, which must also + be a fixed register according to `FIXED_REGISTERS'. On most + machines, the hardware determines which register this is. */ +#define STACK_POINTER_REGNUM 23 + +/* `FRAME_POINTER_REGNUM' + + The register number of the frame pointer register, which is used to + access automatic variables in the stack frame. On some machines, + the hardware determines which register this is. On other machines, + you can choose any register you wish for this purpose. */ +#define FRAME_POINTER_REGNUM 52 + +/* `HARD_FRAME_POINTER_REGNUM' + + On some machines the offset between the frame pointer and starting + offset of the automatic variables is not known until after register + allocation has been done (for example, because the saved registers + are between these two locations). On those machines, define + `FRAME_POINTER_REGNUM' the number of a special, fixed register to + be used internally until the offset is known, and define + `HARD_FRAME_POINTER_REGNUM' to be the actual hard register number + used for the frame pointer. */ +#define HARD_FRAME_POINTER_REGNUM 22 + +/* `ARG_POINTER_REGNUM' + + The register number of the arg pointer register, which is used to + access the function's argument list. On some machines, this is the + same as the frame pointer register. On some machines, the hardware + determines which register this is. On other machines, you can + choose any register you wish for this purpose. If this is not the + same register as the frame pointer register, then you must mark it + as a fixed register according to `FIXED_REGISTERS', or arrange to + be able to eliminate it (*note Elimination::.). */ +#define ARG_POINTER_REGNUM 51 + +/* `STATIC_CHAIN_REGNUM' + `STATIC_CHAIN_INCOMING_REGNUM' + + Register numbers used for passing a function's static chain + pointer. If register windows are used, the register number as seen + by the called function is `STATIC_CHAIN_INCOMING_REGNUM', while the + register number as seen by the calling function is + `STATIC_CHAIN_REGNUM'. If these registers are the same, + `STATIC_CHAIN_INCOMING_REGNUM' need not be defined. + + The static chain register need not be a fixed register. + + If the static chain is passed in memory, these macros should not be + defined; instead, the next two macros should be defined. */ +#define STATIC_CHAIN_REGNUM 20 + +/* `ELIMINABLE_REGS' + + If defined, this macro specifies a table of register pairs used to + eliminate unneeded registers that point into the stack frame. If + it is not defined, the only elimination attempted by the compiler + is to replace references to the frame pointer with references to + the stack pointer. + + The definition of this macro is a list of structure + initializations, each of which specifies an original and + replacement register. + + On some machines, the position of the argument pointer is not known + until the compilation is completed. In such a case, a separate + hard register must be used for the argument pointer. This register + can be eliminated by replacing it with either the frame pointer or + the argument pointer, depending on whether or not the frame pointer + has been eliminated. + + Note that the elimination of the argument pointer with the stack + pointer is specified first since that is the preferred elimination. */ +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +/* `INITIAL_ELIMINATION_OFFSET (FROM-REG, TO-REG, OFFSET-VAR)' + + This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It + specifies the initial difference between the specified pair of + registers. This macro must be defined if `ELIMINABLE_REGS' is + defined. */ +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET = visium_initial_elimination_offset (FROM, TO)) + +/* Passing Function Arguments on the Stack + + The macros in this section control how arguments are passed on the + stack. See the following section for other macros that control + passing certain arguments in registers. + + Passing Arguments in Registers + + This section describes the macros which let you control how various + types of arguments are passed in registers or how they are arranged + in the stack. + + Define the general purpose, and floating point registers used for + passing arguments */ +#define MAX_ARGS_IN_GP_REGISTERS 8 +#define GP_ARG_FIRST 1 +#define GP_ARG_LAST (GP_ARG_FIRST + MAX_ARGS_IN_GP_REGISTERS - 1) +#define MAX_ARGS_IN_FP_REGISTERS 8 +#define FP_ARG_FIRST (FP_FIRST_REGNUM + 1) +#define FP_ARG_LAST (FP_ARG_FIRST + MAX_ARGS_IN_FP_REGISTERS - 1) + +/* Define a data type for recording info about an argument list during the +processing of that argument list. */ + +struct visium_args +{ + /* The count of general registers used */ + int grcount; + /* The count of floating registers used */ + int frcount; + /* The number of stack words used by named arguments */ + int stack_words; +}; + +/* `CUMULATIVE_ARGS' + + A C type for declaring a variable that is used as the first + argument of `FUNCTION_ARG' and other related values. For some + target machines, the type `int' suffices and can hold the number of + bytes of argument so far. + + There is no need to record in `CUMULATIVE_ARGS' anything about the + arguments that have been passed on the stack. The compiler has + other variables to keep track of that. For target machines on + which all arguments are passed on the stack, there is no need to + store anything in `CUMULATIVE_ARGS'; however, the data structure + must exist and should not be empty, so use `int'. */ +#define CUMULATIVE_ARGS struct visium_args + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS) \ + do { \ + (CUM).grcount = 0; \ + (CUM).frcount = 0; \ + (CUM).stack_words = 0; \ + } while (0) + +/* `FUNCTION_ARG_REGNO_P (REGNO)' + + A C expression that is nonzero if REGNO is the number of a hard + register in which function arguments are sometimes passed. This + does *not* include implicit arguments such as the static chain and + the structure-value address. On many machines, no registers can be + used for this purpose since all function arguments are pushed on + the stack. */ +#define FUNCTION_ARG_REGNO_P(N) \ + ((GP_ARG_FIRST <= (N) && (N) <= GP_ARG_LAST) \ + || (TARGET_FPU && FP_ARG_FIRST <= (N) && (N) <= FP_ARG_LAST)) + +/* `FUNCTION_VALUE_REGNO_P (REGNO)' + + A C expression that is nonzero if REGNO is the number of a hard + register in which the values of called function may come back. + + A register whose use for returning values is limited to serving as + the second of a pair (for a value of type `double', say) need not + be recognized by this macro. If the machine has register windows, + so that the caller and the called function use different registers + for the return value, this macro should recognize only the caller's + register numbers. */ +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == RETURN_REGNUM || (TARGET_FPU && (N) == FP_RETURN_REGNUM)) + +/* How Large Values Are Returned + + When a function value's mode is `BLKmode' (and in some other + cases), the value is not returned according to `FUNCTION_VALUE'. + Instead, the caller passes the address of a block of memory in + which the value should be stored. This address is called the + "structure value address". + + This section describes how to control returning structure values in + memory. + + `DEFAULT_PCC_STRUCT_RETURN' + + Define this macro to be 1 if all structure and union return values + must be in memory. Since this results in slower code, this should + be defined only if needed for compatibility with other compilers or + with an ABI. If you define this macro to be 0, then the + conventions used for structure and union return values are decided + by the `RETURN_IN_MEMORY' macro. + + If not defined, this defaults to the value 1. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* `STRUCT_VALUE' + + If the structure value address is not passed in a register, define + `STRUCT_VALUE' as an expression returning an RTX for the place + where the address is passed. If it returns 0, the address is + passed as an "invisible" first argument. */ +#define STRUCT_VALUE 0 + +/* Caller-Saves Register Allocation + + If you enable it, GNU CC can save registers around function calls. + This makes it possible to use call-clobbered registers to hold + variables that must live across calls. + + Function Entry and Exit + + This section describes the macros that output function entry + ("prologue") and exit ("epilogue") code. + + `EXIT_IGNORE_STACK' + + Define this macro as a C expression that is nonzero if the return + instruction or the function epilogue ignores the value of the stack + pointer; in other words, if it is safe to delete an instruction to + adjust the stack pointer before a return from the function. + + Note that this macro's value is relevant only for functions for + which frame pointers are maintained. It is never safe to delete a + final stack adjustment in a function that has no frame pointer, and + the compiler knows this regardless of `EXIT_IGNORE_STACK'. */ +#define EXIT_IGNORE_STACK 1 + +/* `EPILOGUE_USES (REGNO)' + + Define this macro as a C expression that is nonzero for registers + are used by the epilogue or the `return' pattern. The stack and + frame pointer registers are already be assumed to be used as + needed. */ +#define EPILOGUE_USES(REGNO) visium_epilogue_uses (REGNO) + +/* Generating Code for Profiling + + These macros will help you generate code for profiling. */ + +#define PROFILE_HOOK(LABEL) visium_profile_hook () +#define FUNCTION_PROFILER(FILE, LABELNO) do {} while (0) +#define NO_PROFILE_COUNTERS 1 + +/* Trampolines for Nested Functions + + A trampoline is a small piece of code that is created at run time + when the address of a nested function is taken. It normally resides + on the stack, in the stack frame of the containing function. These + macros tell GCC how to generate code to allocate and initialize a + trampoline. + + The instructions in the trampoline must do two things: load a + constant address into the static chain register, and jump to the + real address of the nested function. On CISC machines such as the + m68k, this requires two instructions, a move immediate and a + jump. Then the two addresses exist in the trampoline as word-long + immediate operands. On RISC machines, it is often necessary to load + each address into a register in two parts. Then pieces of each + address form separate immediate operands. + + The code generated to initialize the trampoline must store the + variable parts--the static chain value and the function + address--into the immediate operands of the instructions. On a CISC + machine, this is simply a matter of copying each address to a + memory reference at the proper offset from the start of the + trampoline. On a RISC machine, it may be necessary to take out + pieces of the address and store them separately. + + On the Visium, the trampoline is + + moviu r9,%u FUNCTION + movil r9,%l FUNCTION + moviu r20,%u STATIC + bra tr,r9,r0 + movil r20,%l STATIC + + A difficulty is setting the correct instruction parity at run time. + + + TRAMPOLINE_SIZE + A C expression for the size in bytes of the trampoline, as an integer. */ +#define TRAMPOLINE_SIZE 20 + +/* Implicit calls to library routines + + Avoid calling library routines (sqrtf) just to set `errno' to EDOM */ +#define TARGET_EDOM 33 + +/* Addressing Modes + + `MAX_REGS_PER_ADDRESS' + + A number, the maximum number of registers that can appear in a + valid memory address. Note that it is up to you to specify a value + equal to the maximum number that `TARGET_LEGITIMATE_ADDRESS_P' would + ever accept. */ +#define MAX_REGS_PER_ADDRESS 1 + +/* `LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)' + + A C compound statement that attempts to replace X, which is an + address that needs reloading, with a valid memory address for an + operand of mode MODE. WIN will be a C statement label elsewhere + in the code. It is not necessary to define this macro, but it + might be useful for performance reasons. */ +#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \ +do \ +{ \ + rtx new_x = visium_legitimize_reload_address ((AD), (MODE), (OPNUM), \ + (int) (TYPE), (IND)); \ + if (new_x) \ + { \ + (AD) = new_x; \ + goto WIN; \ + } \ +} while (0) + +/* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE, + return the mode to be used for the comparison. */ +#define SELECT_CC_MODE(OP,X,Y) visium_select_cc_mode ((OP), (X), (Y)) + +/* Return nonzero if MODE implies a floating point inequality can be + reversed. For Visium this is always true because we have a full + compliment of ordered and unordered comparisons, but until generic + code knows how to reverse it correctly we keep the old definition. */ +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode && (MODE) != CCFPmode) + +/* `BRANCH_COST' + + A C expression for the cost of a branch instruction. A value of 1 + is the default; other values are interpreted relative to that. */ +#define BRANCH_COST(A,B) 10 + +/* Override BRANCH_COST heuristics for complex logical ops. */ +#define LOGICAL_OP_NON_SHORT_CIRCUIT 0 + +/* `SLOW_BYTE_ACCESS' + + Define this macro as a C expression which is nonzero if accessing + less than a word of memory (i.e. a `char' or a `short') is no + faster than accessing a word of memory, i.e., if such access + require more than one instruction or if there is no difference in + cost between byte and (aligned) word loads. + + When this macro is not defined, the compiler will access a field by + finding the smallest containing object; when it is defined, a + fullword load will be used if alignment permits. Unless bytes + accesses are faster than word accesses, using word accesses is + preferable since it may eliminate subsequent memory access if + subsequent accesses occur to other fields in the same word of the + structure, but to different bytes. */ +#define SLOW_BYTE_ACCESS 0 + +/* `MOVE_RATIO (SPEED)` + + The threshold of number of scalar memory-to-memory move insns, + _below_ which a sequence of insns should be generated instead of a + string move insn or a library call. Increasing the value will + always make code faster, but eventually incurs high cost in + increased code size. + + Since we have a movmemsi pattern, the default MOVE_RATIO is 2, which + is too low given that movmemsi will invoke a libcall. */ +#define MOVE_RATIO(speed) ((speed) ? 9 : 3) + +/* `CLEAR_RATIO (SPEED)` + + The threshold of number of scalar move insns, _below_ which a + sequence of insns should be generated to clear memory instead of a + string clear insn or a library call. Increasing the value will + always make code faster, but eventually incurs high cost in + increased code size. + + Since we have a setmemsi pattern, the default CLEAR_RATIO is 2, which + is too low given that setmemsi will invoke a libcall. */ +#define CLEAR_RATIO(speed) ((speed) ? 13 : 5) + +/* `MOVE_MAX' + + The maximum number of bytes that a single instruction can move + quickly between memory and registers or between two memory + locations. */ +#define MOVE_MAX 4 + +/* `MAX_MOVE_MAX' + + The maximum number of bytes that a single instruction can move + quickly between memory and registers or between two memory + locations. If this is undefined, the default is `MOVE_MAX'. + Otherwise, it is the constant value that is the largest value that + `MOVE_MAX' can have at run-time. */ +#define MAX_MOVE_MAX 4 + +/* `SHIFT_COUNT_TRUNCATED' + + A C expression that is nonzero if on this machine the number of + bits actually used for the count of a shift operation is equal to + the number of bits needed to represent the size of the object being + shifted. When this macro is non-zero, the compiler will assume + that it is safe to omit a sign-extend, zero-extend, and certain + bitwise `and' instructions that truncates the count of a shift + operation. On machines that have instructions that act on + bitfields at variable positions, which may include `bit test' + instructions, a nonzero `SHIFT_COUNT_TRUNCATED' also enables + deletion of truncations of the values that serve as arguments to + bitfield instructions. */ +#define SHIFT_COUNT_TRUNCATED 0 + +/* `TRULY_NOOP_TRUNCATION (OUTPREC, INPREC)' + + A C expression which is nonzero if on this machine it is safe to + "convert" an integer of INPREC bits to one of OUTPREC bits (where + OUTPREC is smaller than INPREC) by merely operating on it as if it + had only OUTPREC bits. + + On many machines, this expression can be 1. + + When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for + modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result. + If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in + such cases may improve things. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* `STORE_FLAG_VALUE' + + A C expression describing the value returned by a comparison + operator with an integral mode and stored by a store-flag + instruction (`sCOND') when the condition is true. This description + must apply to *all* the `sCOND' patterns and all the comparison + operators whose results have a `MODE_INT' mode. */ +#define STORE_FLAG_VALUE 1 + +/* `Pmode' + + An alias for the machine mode for pointers. On most machines, + define this to be the integer mode corresponding to the width of a + hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit + machines. On some machines you must define this to be one of the + partial integer modes, such as `PSImode'. + + The width of `Pmode' must be at least as large as the value of + `POINTER_SIZE'. If it is not equal, you must define the macro + `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to + `Pmode'. */ +#define Pmode SImode + +/* `FUNCTION_MODE' + + An alias for the machine mode used for memory references to + functions being called, in `call' RTL expressions. On most + machines this should be `QImode'. */ +#define FUNCTION_MODE SImode + +/* `NO_IMPLICIT_EXTERN_C' + + Define this macro if the system header files support C++ as well as + C. This macro inhibits the usual method of using system header + files in C++, which is to pretend that the file's contents are + enclosed in `extern "C" {...}'. */ +#define NO_IMPLICIT_EXTERN_C + +/* Dividing the Output into Sections (Texts, Data, ...) + + An object file is divided into sections containing different types + of data. In the most common case, there are three sections: the + "text section", which holds instructions and read-only data; the + "data section", which holds initialized writable data; and the "bss + section", which holds uninitialized data. Some systems have other + kinds of sections. + + `TEXT_SECTION_ASM_OP' + + A C expression whose value is a string containing the assembler + operation that should precede instructions and read-only data. + Normally `".text"' is right. */ +#define TEXT_SECTION_ASM_OP "\t.text" + +/* `DATA_SECTION_ASM_OP' + + A C expression whose value is a string containing the assembler + operation to identify the following data as writable initialized + data. Normally `".data"' is right. */ +#define DATA_SECTION_ASM_OP "\t.data" + +/* `BSS_SECTION_ASM_OP' + + If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as uninitialized + global data. If not defined, and neither `ASM_OUTPUT_BSS' nor + `ASM_OUTPUT_ALIGNED_BSS' are defined, uninitialized global data + will be output in the data section if `-fno-common' is passed, + otherwise `ASM_OUTPUT_COMMON' will be used. + + `EXTRA_SECTIONS' + + A list of names for sections other than the standard two, which are + `in_text' and `in_data'. You need not define this macro on a + system with no other sections (that GCC needs to use). + + `EXTRA_SECTION_FUNCTIONS' + + One or more functions to be defined in `varasm.c'. These functions + should do jobs analogous to those of `text_section' and + `data_section', for your additional sections. Do not define this + macro if you do not define `EXTRA_SECTIONS'. + + `JUMP_TABLES_IN_TEXT_SECTION' Define this macro if jump tables (for + `tablejump' insns) should be output in the text section, along with + the assembler instructions. Otherwise, the readonly data section + is used. + + This macro is irrelevant if there is no separate readonly data + section. */ +#undef JUMP_TABLES_IN_TEXT_SECTION + + +/* The Overall Framework of an Assembler File + + This describes the overall framework of an assembler file. + + `ASM_COMMENT_START' + + A C string constant describing how to begin a comment in the target + assembler language. The compiler assumes that the comment will end + at the end of the line. */ +#define ASM_COMMENT_START ";" + +/* `ASM_APP_ON' + + A C string constant for text to be output before each `asm' + statement or group of consecutive ones. Normally this is `"#APP"', + which is a comment that has no effect on most assemblers but tells + the GNU assembler that it must check the lines that follow for all + valid assembler constructs. */ +#define ASM_APP_ON "#APP\n" + +/* `ASM_APP_OFF' + + A C string constant for text to be output after each `asm' + statement or group of consecutive ones. Normally this is + `"#NO_APP"', which tells the GNU assembler to resume making the + time-saving assumptions that are valid for ordinary compiler + output. */ +#define ASM_APP_OFF "#NO_APP\n" + +/* Output of Data + + This describes data output. + + Output and Generation of Labels + + This is about outputting labels. + + `ASM_OUTPUT_LABEL (STREAM, NAME)' + + A C statement (sans semicolon) to output to the stdio stream STREAM + the assembler definition of a label named NAME. Use the expression + `assemble_name (STREAM, NAME)' to output the name itself; before + and after that, output the additional assembler syntax for defining + the name, and a newline. */ +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ + do { assemble_name (STREAM, NAME); fputs (":\n", STREAM); } while (0) + +/* Globalizing directive for a label */ +#define GLOBAL_ASM_OP "\t.global " + +/* `ASM_OUTPUT_LABELREF (STREAM, NAME)' + + A C statement (sans semicolon) to output to the stdio stream STREAM + a reference in assembler syntax to a label named NAME. This should + add `_' to the front of the name, if that is customary on your + operating system, as it is in most Berkeley Unix systems. This + macro is used in `assemble_name'. */ +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + asm_fprintf (STREAM, "%U%s", NAME) + +/* Output of Assembler Instructions + + This describes assembler instruction output. + + `REGISTER_NAMES' + + A C initializer containing the assembler's names for the machine + registers, each one as a C string constant. This is what + translates register numbers in the compiler into assembler + language. */ +#define REGISTER_NAMES \ + {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \ + "r16", "r17", "r18", "r19", "r20", "r21", "fp", "sp", \ + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \ + "mdb", "mdc", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "flags","argp","sfp" } + +/* `ADDITIONAL_REGISTER_NAMES` + + If defined, a C initializer for an array of structures containing + a name and a register number. This macro defines additional names + for hard registers, thus allowing the `asm' option in declarations + to refer to registers using alternate names. */ +#define ADDITIONAL_REGISTER_NAMES \ + {{"r22", HARD_FRAME_POINTER_REGNUM}, {"r23", STACK_POINTER_REGNUM}} + +/* `PRINT_OPERAND (STREAM, X, CODE)' + + A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand X. X is an RTL + expression. + + CODE is a value that can be used to specify one of several ways of + printing the operand. It is used when identical operands must be + printed differently depending on the context. CODE comes from the + `%' specification that was used to request printing of the operand. + If the specification was just `%DIGIT' then CODE is 0; if the + specification was `%LTR DIGIT' then CODE is the ASCII code for LTR. + + If X is a register, this macro should print the register's name. + The names can be found in an array `reg_names' whose type is `char + *[]'. `reg_names' is initialized from `REGISTER_NAMES'. + + When the machine description has a specification `%PUNCT' (a `%' + followed by a punctuation character), this macro is called with a + null pointer for X and the punctuation character for CODE. */ +#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE) + +/* `PRINT_OPERAND_PUNCT_VALID_P (CODE)' + + A C expression which evaluates to true if CODE is a valid + punctuation character for use in the `PRINT_OPERAND' macro. If + `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no + punctuation characters (except for the standard one, `%') are used */ +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '#') + +/* `PRINT_OPERAND_ADDRESS (STREAM, X)' + + A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand that is a memory + reference whose address is X. X is an RTL expression. + + On some machines, the syntax for a symbolic address depends on the + section that the address refers to. On these machines, define the + macro `ENCODE_SECTION_INFO' to store the information into the + `symbol_ref', and then check for it here. */ +#define PRINT_OPERAND_ADDRESS(STREAM, ADDR) \ + print_operand_address (STREAM, ADDR) + +/* `REGISTER_PREFIX' + `LOCAL_LABEL_PREFIX' + `USER_LABEL_PREFIX' + `IMMEDIATE_PREFIX' + + If defined, C string expressions to be used for the `%R', `%L', + `%U', and `%I' options of `asm_fprintf' (see `final.c'). These are + useful when a single `md' file must support multiple assembler + formats. In that case, the various `tm.h' files can define these + macros differently. */ +#define REGISTER_PREFIX "" +#define LOCAL_LABEL_PREFIX "." +#define IMMEDIATE_PREFIX "#" + +/* `ASM_OUTPUT_REG_PUSH (STREAM, REGNO)' + + A C expression to output to STREAM some assembler code which will + push hard register number REGNO onto the stack. The code need not + be optimal, since this macro is used only when profiling. */ +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + asm_fprintf (STREAM, "\tsubi sp,4\n\twrite.l (sp),%s\n", \ + reg_names[REGNO]) + +/* `ASM_OUTPUT_REG_POP (STREAM, REGNO)' + + A C expression to output to STREAM some assembler code which will + pop hard register number REGNO off of the stack. The code need not + be optimal, since this macro is used only when profiling. */ +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + asm_fprintf (STREAM, "\tread.l %s,(sp)\n\taddi sp,4\n", \ + reg_names[REGNO]) + + +/* Output of Dispatch Tables + + This concerns dispatch tables. + + `ASM_OUTPUT_ADDR_DIFF_ELT (STREAM, VALUE, REL)' + + A C statement to output to the stdio stream STREAM an assembler + pseudo-instruction to generate a difference between two labels. + VALUE and REL are the numbers of two internal labels. The + definitions of these labels are output using + `ASM_OUTPUT_INTERNAL_LABEL', and they must be printed in the same + way here. + + You must provide this macro on machines where the addresses in a + dispatch table are relative to the table's own address. If + defined, GNU CC will also use this macro on all machines when + producing PIC. */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ + switch (GET_MODE (BODY)) \ + { \ + case SImode: \ + asm_fprintf ((STREAM), "\t.long\t%LL%d-%LL%d\n", (VALUE),(REL)); \ + break; \ + case HImode: \ + asm_fprintf ((STREAM), "\t.word\t%LL%d-%LL%d\n", (VALUE),(REL)); \ + break; \ + case QImode: \ + asm_fprintf ((STREAM), "\t.byte\t%LL%d-%LL%d\n", (VALUE),(REL)); \ + break; \ + default: \ + break; \ + } + +/* `ASM_OUTPUT_ADDR_VEC_ELT (STREAM, VALUE)' + + This macro should be provided on machines where the addresses in a + dispatch table are absolute. + + The definition should be a C statement to output to the stdio + stream STREAM an assembler pseudo-instruction to generate a + reference to a label. VALUE is the number of an internal label + whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ + asm_fprintf (STREAM, "\t.long %LL%d\n", VALUE) + +/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)' + + Define this if something special must be output at the end of a + jump-table. The definition should be a C statement to be executed + after the assembler code for the table is written. It should write + the appropriate code to stdio stream STREAM. The argument TABLE is + the jump-table insn, and NUM is the label-number of the preceding + label. + + If this macro is not defined, nothing special is output at the end + of a jump table. + + Here we output a word of zero so that jump-tables can be seperated + in reverse assembly. */ +#define ASM_OUTPUT_CASE_END(STREAM, NUM, TABLE) \ + asm_fprintf (STREAM, "\t.long 0\n"); + +/* Assembler Commands for Alignment + + This describes commands for alignment. + + `ASM_OUTPUT_ALIGN_CODE (STREAM)' + + A C expression to output text to align the location counter in the + way that is desirable at a point in the code that is reached only + by jumping. + + This macro need not be defined if you don't want any special + alignment to be done at such a time. Most machine descriptions do + not currently define the macro. */ +#undef ASM_OUTPUT_ALIGN_CODE + +/* `ASM_OUTPUT_LOOP_ALIGN (STREAM)' + + A C expression to output text to align the location counter in the + way that is desirable at the beginning of a loop. + + This macro need not be defined if you don't want any special + alignment to be done at such a time. Most machine descriptions do + not currently define the macro. */ +#undef ASM_OUTPUT_LOOP_ALIGN + +/* `ASM_OUTPUT_ALIGN (STREAM, POWER)' + + A C statement to output to the stdio stream STREAM an assembler + command to advance the location counter to a multiple of 2 to the + POWER bytes. POWER will be a C expression of type `int'. */ +#define ASM_OUTPUT_ALIGN(STREAM,LOG) \ + if ((LOG) != 0) \ + fprintf (STREAM, "\t.align %d\n", (1<<(LOG))) + +/* `ASM_OUTPUT_MAX_SKIP_ALIGN (STREAM, POWER, MAX_SKIP)` + + A C statement to output to the stdio stream STREAM an assembler + command to advance the location counter to a multiple of 2 to the + POWER bytes, but only if MAX_SKIP or fewer bytes are needed to + satisfy the alignment request. POWER and MAX_SKIP will be a C + expression of type `int'. */ +#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM,LOG,MAX_SKIP) \ + if ((LOG) != 0) { \ + if ((MAX_SKIP) == 0) fprintf ((STREAM), "\t.p2align %d\n", (LOG)); \ + else { \ + fprintf ((STREAM), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + /* Make sure that we have at least 8-byte alignment if > 8-byte \ + alignment is preferred. */ \ + if ((LOG) > 3 \ + && (1 << (LOG)) > ((MAX_SKIP) + 1) \ + && (MAX_SKIP) >= 7) \ + fputs ("\t.p2align 3\n", (STREAM)); \ + } \ + } + +/* Controlling Debugging Information Format + + This describes how to specify debugging information. + + mda is known to GDB, but not to GCC. */ +#define DBX_REGISTER_NUMBER(REGNO) \ + ((REGNO) > MDB_REGNUM ? (REGNO) + 1 : (REGNO)) + +/* `DEBUGGER_AUTO_OFFSET (X)' + + A C expression that returns the integer offset value for an + automatic variable having address X (an RTL expression). The + default computation assumes that X is based on the frame-pointer + and gives the offset from the frame-pointer. This is required for + targets that produce debugging output for DBX or COFF-style + debugging output for SDB and allow the frame-pointer to be + eliminated when the `-g' options is used. */ +#define DEBUGGER_AUTO_OFFSET(X) \ + (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) + +/* Miscellaneous Parameters + + `CASE_VECTOR_MODE' + + An alias for a machine mode name. This is the machine mode that + elements of a jump-table should have. */ +#define CASE_VECTOR_MODE SImode + +/* `CASE_VECTOR_PC_RELATIVE' + Define this macro if jump-tables should contain relative addresses. */ +#undef CASE_VECTOR_PC_RELATIVE + +/* This says how to output assembler code to declare an + unitialised external linkage data object. */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +( fputs ("\n\t.comm ", (STREAM)), \ + assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", ROUNDED)) + +/* This says how to output assembler code to declare an + unitialised internal linkage data object. */ +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ +( fputs ("\n\t.lcomm ", (STREAM)), \ + assemble_name ((STREAM), (NAME)), \ + fprintf ((STREAM), ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", ROUNDED)) + +/* Prettify the assembly. */ +extern int visium_indent_opcode; + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ + do { \ + if (visium_indent_opcode) \ + { \ + putc (' ', FILE); \ + visium_indent_opcode = 0; \ + } \ + } while (0) diff --git a/gcc/config/visium/visium.md b/gcc/config/visium/visium.md new file mode 100644 index 0000000..969cb88 --- /dev/null +++ b/gcc/config/visium/visium.md @@ -0,0 +1,2749 @@ +;; Machine description for Visium. +;; Copyright (C) 2002-2015 Free Software Foundation, Inc. +;; Contributed by C.Nettleton, J.P.Parkes and P.Garbett. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Extra register constraints are: +;; 'b' EAM register mdb +;; 'c' EAM register mdc +;; 'f' Floating-point register +;; 'k' Register that can be used as the target of a sibcall, i.e. call-used +;; general register not clobbered in the epilogue: r1-r8 and r10 +;; 'l' Low general register, i.e. general register accessible in user mode +;; on the GR6 and, consequently, that can be used as the target of a +;; branch with prediction: r1-r28 +;; 't' Register r1 +;; 'u' Register r2 +;; 'v' Register r3 +;; +;; Immediate integer operand constraints are: +;; 'J' 0 .. 65535 (16-bit immediate) +;; 'K' 1 .. 31 (5-bit immediate) +;; 'L' -1 .. -65535 (16-bit negative immediate) +;; 'M' -1 (minus one) +;; 'O' 0 (integer zero) +;; 'P' 32 (thirty two) +;; +;; Immediate FP operand constraints are: +;; 'G' 0.0 (floating-point zero) +;; +;; Operand substitution characters are: +;; %# delay slot follows, if empty, fill with NOP +;; %b LS 8 bits of immediate operand +;; %w LS 16 bits of immediate operand +;; %u MS 16 bits of immediate operand +;; %r register or zero (r0) +;; %f FP register or zero (f0) +;; %d second register in a pair +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +;; Registers by name. +(define_constants [ + (R_R1 1) + (R_R2 2) + (R_R3 3) + (R_R4 4) + (R_R5 5) + (R_R6 6) + (R_LINK 21) + (R_FP 22) + (R_SP 23) + (R_MDB 32) + (R_MDC 33) + (R_FLAGS 50) +]) + +;; UNSPEC usage. +(define_c_enum "unspec" [ + UNSPEC_MDBHI + UNSPEC_FLOAD + UNSPEC_FSTORE + UNSPEC_ITOF + UNSPEC_FTOI + UNSPEC_NOP +]) + +;; UNSPEC_VOLATILE usage. +(define_c_enum "unspecv" [ + UNSPECV_BLOCKAGE + UNSPECV_DSI +]) + +(include "predicates.md") +(include "constraints.md") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Attributes. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; Instruction type. +; +;imm_reg Move of immediate value to register. +;mem_reg Move from memory to register. +;eam_reg Move from EAM to register. +;fp_reg Move from FPU to register. +;reg_mem Move from register to memory. +;reg_eam Move from register to EAM. +;reg_fp Move from register to FPU. +;arith Arithmetic operation, result in register, sets overflow. +;arith2 Two successive arithmetic operations. +;logic Logical operation, result in register, does not set overflow. +;abs_branch Absolute branch. +;branch Branch. +;bmi Block move. +;call Call to subprogram. +;ret Return from subprogram. +;rfi Return from interrupt. +;dsi Disable interrupts. +;cmp Compare or test. +;div EAM 32/32 division. +;divd EAM 64/32 division. +;mul EAM 32 * 32 -> 64 multiplication. +;shiftdi EAM 64 bit shift. +;fdiv Floating point divide. +;fsqrt Floating point square root. +;ftoi Fix float to integer. +;itof Float integer. +;fmove Floating point move w/ or w/o change of sign: fmove, fabs, fneg. +;fcmp Floating point compare or test. +;fp Other floating point operations. +;nop No operation. +;multi Multiple instructions which split. +;asm User asm instructions. + +(define_attr "type" +"imm_reg,mem_reg,eam_reg,fp_reg,reg_mem,reg_eam,reg_fp,arith,arith2,logic,abs_branch,branch,bmi,call,ret,rfi,dsi,cmp,div,divd,mul,shiftdi,fdiv,fsqrt,ftoi,itof,fmove,fcmp,fp,nop,multi,asm" (const_string "logic")) + +; Those insns that occupy 4 bytes. +(define_attr "single_insn" "no,yes" + (if_then_else (eq_attr "type" "arith2,rfi,multi") + (const_string "no") + (const_string "yes"))) + +; True if branch or call will be emitting a nop into its delay slot. +(define_attr "empty_delay_slot" "false,true" + (symbol_ref "(empty_delay_slot (insn) + ? EMPTY_DELAY_SLOT_TRUE : EMPTY_DELAY_SLOT_FALSE)")) + +; Length in bytes. +; The allowed range for the offset of short branches is [-131072;131068] +; and it is counted from the address of the insn so we need to subtract +; 8 for forward branches because (pc) points to the next insn for them. +(define_attr "length" "" + (cond [(eq_attr "type" "abs_branch,call,ret") + (if_then_else (eq_attr "empty_delay_slot" "true") + (const_int 8) + (const_int 4)) + (eq_attr "type" "branch") + (if_then_else (leu (plus (minus (match_dup 0) (pc)) + (const_int 131060)) + (const_int 262120)) + (if_then_else (eq_attr "empty_delay_slot" "true") + (const_int 8) + (const_int 4)) + (const_int 20)) + (eq_attr "single_insn" "no") + (const_int 8)] (const_int 4))) + +(define_asm_attributes [(set_attr "type" "asm")]) + +; Delay slots. +(define_delay (eq_attr "type" "abs_branch,branch,call,ret") + [(and (eq_attr "type" "!abs_branch,branch,call,ret,rfi,bmi,mul,div,divd,fdiv,fsqrt,asm") + (eq_attr "single_insn" "yes")) + (nil) (nil)]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Processor pipeline description. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; Attribute for cpu type. +; These must match the values for enum processor_type in visium-opts.h. +(define_attr "cpu" "gr5,gr6" (const (symbol_ref "visium_cpu_attr"))) + +(include "gr5.md") +(include "gr6.md") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Iterators. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_mode_iterator QHI [QI HI]) +(define_mode_iterator I [QI HI SI]) +(define_mode_attr s [(QI ".b") (HI ".w") (SI ".l")]) + +; This code iterator allows signed and unsigned widening multiplications +; to use the same template. +(define_code_iterator any_extend [sign_extend zero_extend]) + +; <u> expands to an empty string when doing a signed operation and +; "u" when doing an unsigned operation. +(define_code_attr u [(sign_extend "") (zero_extend "u")]) + +; <su> is like <u>, but the signed form expands to "s" rather than "". +(define_code_attr su [(sign_extend "s") (zero_extend "u")]) + +; This code iterator allows returns and simple returns to use the same template. +(define_code_iterator any_return [return simple_return]) +(define_code_attr return_pred [(return "visium_can_use_return_insn_p ()") + (simple_return "!visium_interrupt_function_p ()")]) +(define_code_attr return_str [(return "") (simple_return "simple_")]) + +; This code iterator allows integer and FP cstores to use the same template. +(define_code_iterator any_scc [ltu lt]) +(define_code_attr scc_str [(ltu "sltu") (lt "slt")]) + +;This code iterator allows cstore splitters to use the same template. +(define_code_iterator any_add [plus minus]) +(define_code_attr add_op [(plus "PLUS") (minus "MINUS")]) +(define_code_attr add_str [(plus "plus") (minus "minus")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Substitutions. +;; +;; They are used to define the second instruction of the pairs required by +;; the postreload compare elimination pass, with a first variant for the +;; logical insns and a second variant for the arithmetic insns. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_subst "flags_subst_logic" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg:CC R_FLAGS))] + "" + [(set (match_dup 0) (match_dup 1)) + (set (reg:CC R_FLAGS) + (compare:CC (match_dup 1) (const_int 0)))]) + +(define_subst_attr "subst_logic" "flags_subst_logic" "_flags" "_set_flags") + +(define_subst "flags_subst_arith" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg:CC R_FLAGS))] + "" + [(set (match_dup 0) (match_dup 1)) + (set (reg:CC_NOOV R_FLAGS) + (compare:CC_NOOV (match_dup 1) (const_int 0)))]) + +(define_subst_attr "subst_arith" "flags_subst_arith" "_flags" "_set_flags") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; QImode moves +;; +;; For moving among registers we use the move.b instruction. This is +;; actually an OR instruction using an alias. For moving between register +;; and memory we need the address of the memory location in a register. +;; However, we can accept an expression (reg + offset) where offset is in +;; the range 0 .. 31. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, QImode); +}) + +(define_insn "*movqi_insn" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r") + (match_operand:QI 1 "general_operand" " r,rO, r, r,?b,?c,i,m"))] + "ok_for_simple_move_operands (operands, QImode)" + "@ + # + write.b %0,%r1 + writemd %1,r0 ;movqi ?b r + writemdc %1 ;movqi ?c r + readmda %0 ;movqi r ?b + readmdc %0 ;movqi r ?c + moviq %0,%b1 ;movqi r i + read.b %0,%1" + [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,mem_reg")]) + +(define_insn "*movqi_insn<subst_logic>" + [(set (match_operand:QI 0 "gpc_reg_operand" "=r") + (match_operand:QI 1 "gpc_reg_operand" "r")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.b %0,%1" + [(set_attr "type" "logic")]) + +(define_split + [(set (match_operand:QI 0 "gpc_reg_operand" "") + (match_operand:QI 1 "gpc_reg_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +(define_expand "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "")) + (match_operand:QI 1 "general_operand" ""))] + "") + +(define_insn "*movstrictqi_insn" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r,r")) + (match_operand:QI 1 "general_operand" "rO,m"))] + "ok_for_simple_move_strict_operands (operands, QImode)" + "@ + # + read.b %0,%1" + [(set_attr "type" "logic,mem_reg")]) + +(define_insn "*movstrictqi_insn<subst_logic>" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r")) + (match_operand:QI 1 "reg_or_0_operand" "rO")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.b %0,%r1" + [(set_attr "type" "logic")]) + +(define_split + [(set (strict_low_part (match_operand:QI 0 "register_operand" "")) + (match_operand:QI 1 "reg_or_0_operand" ""))] + "reload_completed" + [(parallel [(set (strict_low_part (match_dup 0)) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; HImode moves +;; +;; For moving among registers we use the move.w instruction. This is +;; actually an OR instruction using an alias. For moving between register +;; and memory we need the address of the memory location in a register. +;; However, we can accept an expression (reg + offset) where offset is in +;; the range 0 .. 62 and is shifted right one place in the assembled +;; instruction. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, HImode); +}) + +(define_insn "*movhi_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r") + (match_operand:HI 1 "general_operand" " r,rO, r, r,?b,?c,i,m"))] + "ok_for_simple_move_operands (operands, HImode)" + "@ + # + write.w %0,%r1 + writemd %1,r0 ;movhi ?b r + writemdc %1 ;movhi ?c r + readmda %0 ;movhi r ?b + readmdc %0 ;movhi r ?c + moviq %0,%w1 ;movhi r i + read.w %0,%1" + [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,mem_reg")]) + +(define_insn "*movhi_insn<subst_logic>" + [(set (match_operand:HI 0 "gpc_reg_operand" "=r") + (match_operand:HI 1 "gpc_reg_operand" "r")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.w %0,%1" + [(set_attr "type" "logic")]) + +(define_split + [(set (match_operand:HI 0 "gpc_reg_operand" "") + (match_operand:HI 1 "gpc_reg_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +(define_expand "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "")) + (match_operand:HI 1 "general_operand" ""))] + "") + +(define_insn "*movstricthi_insn" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r,r,r")) + (match_operand:HI 1 "general_operand" " r,i,m"))] + "ok_for_simple_move_strict_operands (operands, HImode)" + "@ + # + movil %0,%w1 + read.w %0,%1" + [(set_attr "type" "logic,imm_reg,mem_reg")]) + +(define_insn "*movstricthi_insn<subst_logic>" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r")) + (match_operand:HI 1 "register_operand" "r")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.w %0,%1" + [(set_attr "type" "logic")]) + +(define_split + [(set (strict_low_part (match_operand:HI 0 "register_operand" "")) + (match_operand:HI 1 "register_operand" ""))] + "reload_completed" + [(parallel [(set (strict_low_part (match_dup 0)) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; SImode moves +;; +;; For moving among registers we use the move.l instruction. This is +;; actually an OR instruction using an alias. For moving between register +;; and memory we need the address of the memory location in a register. +;; However, we can accept an expression (reg + offset) where offset is in +;; the range 0 .. 124 and is shifted right two places in the assembled +;; instruction. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, SImode); +}) + +(define_insn "*movsi_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (high:SI (match_operand:SI 1 "immediate_operand" "n,i")) )] + "" + "@ + moviu %0,%u1 + moviu %0,%%u %a1" + [(set_attr "type" "imm_reg")]) + +; We only care about the lower 16 bits of the constant +; being inserted into the upper 16 bits of the register. +(define_insn "*moviu" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (const_int 16) + (const_int 0)) + (match_operand:SI 1 "const_int_operand" "n"))] + "" + "moviu %0,%w1" + [(set_attr "type" "imm_reg")]) + +(define_insn "*movsi_losum" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "immediate_operand" "n,i")))] + "" + "@ + movil %0,%w2 + movil %0,%%l %a2" + [(set_attr "type" "imm_reg")]) + +(define_insn "*movil" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (const_int 16) + (const_int 16)) + (match_operand:SI 1 "const_int_operand" "n"))] + "" + "movil %0,%w1" + [(set_attr "type" "imm_reg")]) + +(define_insn "*movsi_insn_no_ieee" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r,r,r, r,!f") + (match_operand:SI 1 "general_operand" " r,rO, r, r,?b,?c,J,M,i,m,!f, r"))] + "!TARGET_FPU_IEEE && ok_for_simple_move_operands (operands, SImode)" + "@ + # + write.l %0,%r1 + writemd %1,r0 ;movsi ?b r + writemdc %1 ;movsi ?c r + readmda %0 ;movsi r ?b + readmdc %0 ;movsi r ?c + moviq %0,%1 ;movsi r J + # + # ;movsi r i + read.l %0,%1 + fstore %0,%1 + fload %0,%1" + [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,logic,multi,mem_reg,fp_reg,reg_fp")]) + +(define_insn "*movsi_insn" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r,r,r, r,?f,f") + (match_operand:SI 1 "general_operand" " r,rO, r, r,?b,?c,J,M,i,m,?f, r,f"))] + "TARGET_FPU_IEEE && ok_for_simple_move_operands (operands, SImode)" + "@ + # + write.l %0,%r1 + writemd %1,r0 ;movsi ?b r + writemdc %1 ;movsi ?c r + readmda %0 ;movsi r ?b + readmdc %0 ;movsi r ?c + moviq %0,%1 ;movsi r J + # + # ;movsi r i + read.l %0,%1 + fstore %0,%1 + fload %0,%1 + fmove %0,%1" + [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,logic,multi,mem_reg,fp_reg,reg_fp,fmove")]) + +(define_insn "*movsi_insn<subst_logic>" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (match_operand:SI 1 "gpc_reg_operand" "r")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.l %0,%1" + [(set_attr "type" "logic")]) + +(define_insn "*movsi_insn_m1<subst_logic>" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (const_int -1)) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "not.l %0,r0" + [(set_attr "type" "logic")]) + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (match_operand:SI 1 "gpc_reg_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (const_int -1))] + "reload_completed" + [(parallel [(set (match_dup 0) (const_int -1)) + (clobber (reg:CC R_FLAGS))])] + "") + +(define_insn "*movsi_mdbhi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI))] + "" + "readmdb %0" + [(set_attr "type" "eam_reg")]) + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (match_operand:SI 1 "large_immediate_operand" ""))] + "reload_completed" + [(set (match_dup 0) + (high:SI (match_dup 1)) ) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) (match_dup 1)))] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; DImode moves +;; +;; When the destination is the EAM register MDB, then we use the writemd +;; instruction. In all other cases we split the move into two 32-bit moves. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, DImode); +}) + +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "nonimmediate_operand" "= r, m, r,??b") + (match_operand:DI 1 "general_operand" "rim,rO,?b, r"))] + "ok_for_simple_move_operands (operands, DImode)" + "@ + # + # + # + writemd %d1,%1 ;movdi ?b r" + [(set_attr "type" "multi,multi,multi,reg_eam")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") (reg:DI R_MDB))] + "reload_completed" + [(set (match_dup 1) (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI)) + (set (match_dup 2) (reg:SI R_MDB))] +{ + operands[1] = operand_subword (operands[0], 0, 1, DImode); + operands[2] = operand_subword (operands[0], 1, 1, DImode); +}) + +(define_split + [(set (match_operand:DI 0 "non_eam_dst_operand" "") + (match_operand:DI 1 "non_eam_src_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] +{ + split_double_move (operands, DImode); +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; SFmode moves +;; +;; Constants are constructed in a GP register and moved to the FP register. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, SFmode); +}) + +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,r,r, m,r,r,r") + (match_operand:SF 1 "general_operand" " f,G,r,f,r,rG,G,F,m"))] + "ok_for_simple_move_operands (operands, SFmode)" + "@ + fmove %0,%1 + fmove %0,f0 + fload %0,%1 + fstore %0,%1 + # + write.l %0,%r1 + moviq %0,0 + # + read.l %0,%1" + [(set_attr "type" "fmove,fmove,reg_fp,fp_reg,logic,reg_mem,imm_reg,multi,mem_reg")]) + +(define_insn "*movsf_insn" + [(set (match_operand:SF 0 "gpc_reg_operand" "=r") + (match_operand:SF 1 "gpc_reg_operand" "r")) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.l %0,%1" + [(set_attr "type" "logic")]) + +(define_split + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operand:SF 1 "gpc_reg_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) + (clobber (reg:CC R_FLAGS))])] + "") + +(define_split + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operand:SF 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3))] +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + operands[2] = operand_subword (operands[0], 0, 0, SFmode); + operands[3] = GEN_INT (trunc_int_for_mode (l, SImode)); +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; DFmode moves +;; +;; We always split a DFmode move into two SImode moves. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" +{ + prepare_move_operands (operands, DFmode); +}) + +(define_insn "*movdf_insn" + [(set (match_operand:DF 0 "nonimmediate_operand" "= r, m") + (match_operand:DF 1 "general_operand" "rFm,rG"))] + "ok_for_simple_move_operands (operands, DFmode)" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] +{ + split_double_move (operands, DFmode); +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Add +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "add<mode>3" + [(set (match_operand:QHI 0 "register_operand" "") + (plus:QHI (match_operand:QHI 1 "register_operand" "") + (match_operand:QHI 2 "register_operand" "")))] + "") + +(define_insn_and_split "*add<mode>3_insn" + [(set (match_operand:QHI 0 "register_operand" "=r") + (plus:QHI (match_operand:QHI 1 "register_operand" "%r") + (match_operand:QHI 2 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (plus:QHI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +(define_insn "*add<mode>3_insn<subst_arith>" + [(set (match_operand:QHI 0 "register_operand" "=r") + (plus:QHI (match_operand:QHI 1 "register_operand" "%r") + (match_operand:QHI 2 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "add<s> %0,%1,%2" + [(set_attr "type" "arith")]) + +(define_expand "addsi3" + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "add_operand" "")))] + "") + +(define_expand "addsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "add_operand" ""))) + (clobber (reg:CC R_FLAGS))])] + "reload_completed" + "") + +(define_insn_and_split "*addsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%0,r,0") + (match_operand:SI 2 "add_operand" " L,r,J")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (plus:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +; Favour the addition of small negative constants, since they are +; expensive to load into a register. + +(define_insn "*addsi3_insn<subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%0,r,0") + (match_operand:SI 2 "add_operand" " L,r,J"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "@ + subi %0,%n2 + add.l %0,%1,%2 + addi %0,%2" + [(set_attr "type" "arith")]) + +(define_expand "adddi3" + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "add_operand" "")))] + "") + +(define_insn_and_split "*addi3_insn" + [(set (match_operand:DI 0 "register_operand" "=r,r,&r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0, r") + (match_operand:DI 2 "add_operand" " J,L, r")))] + "ok_for_simple_arith_logic_operands (operands, DImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (plus:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith2")]) + +; Disfavour the use of add.l because of the early clobber. + +(define_insn "*adddi3_insn_flags" + [(set (match_operand:DI 0 "register_operand" "=r,r,&r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0, r") + (match_operand:DI 2 "add_operand" " J,L, r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "@ + addi %d0,%2\n\tadc.l %0,%0,r0 + subi %d0,%n2\n\tsubc.l %0,%0,r0 + add.l %d0,%d1,%d2\n\tadc.l %0,%1,%2" + [(set_attr "type" "arith2")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Add with Carry +;; +;; Only SI mode is supported as slt[u] for the sake of cstore. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*<scc_str><subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r") + (any_scc:SI (reg R_FLAGS) (const_int 0))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "adc.l %0,r0,r0" + [(set_attr "type" "arith")]) + +(define_insn "*plus_<scc_str><subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "r") + (any_scc:SI (reg R_FLAGS) (const_int 0)))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "adc.l %0,%1,r0" + [(set_attr "type" "arith")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Subtract +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "sub<mode>3" + [(set (match_operand:QHI 0 "register_operand" "") + (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "") + (match_operand:QHI 2 "register_operand" "")))] + "") + +(define_insn_and_split "*sub<mode>3_insn" + [(set (match_operand:QHI 0 "register_operand" "=r") + (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO") + (match_operand:QHI 2 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (minus:QHI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +(define_insn "*sub<mode>3_insn<subst_arith>" + [(set (match_operand:QHI 0 "register_operand" "=r") + (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO") + (match_operand:QHI 2 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "sub<s> %0,%r1,%2" + [(set_attr "type" "arith")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "") + (match_operand:SI 2 "add_operand" "")))] + "") + +(define_expand "subsi3_flags" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "") + (match_operand:SI 2 "add_operand" ""))) + (clobber (reg:CC R_FLAGS))])] + "reload_completed" + "") + +(define_insn_and_split "*subsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=r,r, r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" " 0,rO,0") + (match_operand:SI 2 "add_operand" " L,r, J")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (minus:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +; Favour the subtraction of small negative constants, since they are +; expensive to load into a register. + +(define_insn "*subsi3_insn<subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r,r, r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" " 0,rO,0") + (match_operand:SI 2 "add_operand" " L,r, J"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "@ + addi %0,%n2 + sub.l %0,%r1,%2 + subi %0,%2" + [(set_attr "type" "arith")]) + +(define_expand "subdi3" + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "add_operand" "")))] + "") + +(define_insn_and_split "*subdi3_insn" + [(set (match_operand:DI 0 "register_operand" "=r,r,&r") + (minus:DI (match_operand:DI 1 "register_operand" " 0,0, r") + (match_operand:DI 2 "add_operand" " J,L, r")))] + "ok_for_simple_arith_logic_operands (operands, DImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (minus:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith2")]) + +; Disfavour the use of the sub.l because of the early clobber. + +(define_insn "*subdi3_insn_flags" + [(set (match_operand:DI 0 "register_operand" "=r,r,&r") + (minus:DI (match_operand:DI 1 "register_operand" " 0,0, r") + (match_operand:DI 2 "add_operand" " J,L, r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "@ + subi %d0,%2\n\tsubc.l %0,%0,r0 + addi %d0,%n2\n\tadc.l %0,%0,r0 + sub.l %d0,%d1,%d2\n\tsubc.l %0,%1,%2" + [(set_attr "type" "arith2")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Subtract with Carry +;; +;; Only SI mode is supported as neg<slt[u]> for the sake of cstore. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*neg_<scc_str><subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (any_scc:SI (reg R_FLAGS) (const_int 0)))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "subc.l %0,r0,r0" + [(set_attr "type" "arith")]) + +(define_insn "*minus_<scc_str><subst_arith>" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (any_scc:SI (reg R_FLAGS) (const_int 0)))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "subc.l %0,%1,r0" + [(set_attr "type" "arith")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Negate +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "neg<mode>2" + [(set (match_operand:I 0 "register_operand" "") + (neg:I (match_operand:I 1 "register_operand" "")))] + "") + +(define_insn_and_split "*neg<mode>2_insn" + [(set (match_operand:I 0 "register_operand" "=r") + (neg:I (match_operand:I 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (neg:I (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +(define_insn "*neg<mode>2_insn<subst_arith>" + [(set (match_operand:I 0 "register_operand" "=r") + (neg:I (match_operand:I 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "sub<s> %0,r0,%1" + [(set_attr "type" "arith")]) + +(define_expand "negdi2" + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (match_operand:DI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*negdi2_insn" + [(set (match_operand:DI 0 "register_operand" "=&r") + (neg:DI (match_operand:DI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, DImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (neg:DI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith2")]) + +(define_insn "*negdi2_insn_flags" + [(set (match_operand:DI 0 "register_operand" "=&r") + (neg:DI (match_operand:DI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "sub.l %d0,r0,%d1\n\tsubc.l %0,r0,%1" + [(set_attr "type" "arith2")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer Multiply (non-widening and widening, signed and unsigned) +;; +;; Only SI mode is supported. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; The mults and multu instructions clear MDC but we only pretend that they +; clobber it to keep things relatively simple. + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=b") + (mult:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "register_operand" "r"))) + (clobber (reg:SI R_MDC))] + "" + "mults %1,%2" + [(set_attr "type" "mul")]) + +; The names are mulsidi3 and umulsidi3 here. + +(define_insn "<u>mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=b") + (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "%r")) + (any_extend:DI (match_operand:SI 2 "register_operand" "r")))) + (clobber (reg:SI R_MDC))] + "" + "mult<su> %1,%2" + [(set_attr "type" "mul")]) + +; But they are smulsi3_highpart and umulsi3_highpart here. + +(define_insn_and_split "<su>mulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI + (ashiftrt:DI + (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "%r")) + (any_extend:DI (match_operand:SI 2 "register_operand" "r"))) + (const_int 32)))) + (clobber (reg:DI R_MDB)) + (clobber (reg:SI R_MDC))] + "" + "#" + "reload_completed" + [(parallel [(set (reg:DI R_MDB) + (mult:DI (any_extend:DI (match_dup 1)) + (any_extend:DI (match_dup 2)))) + (clobber (reg:SI R_MDC))]) + (set (match_dup 0) (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI))] + "" + [(set_attr "type" "multi")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer divide and modulus (signed and unsigned) +;; +;; Only SI mode is supported. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*divmodsi4_insn" + [(set (match_operand:SI 0 "register_operand" "=b") + (div:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r"))) + (set (reg:SI R_MDC) (mod:SI (match_dup 1) (match_dup 2)))] + "" + "divs %2" + [(set_attr "type" "div")]) + +(define_insn_and_split "divmodsi4" + [(set (match_operand:SI 0 "register_operand" "=b") + (div:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "=r") + (mod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:SI R_MDC))] + "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (div:SI (match_dup 1) (match_dup 2))) + (set (reg:SI R_MDC) (mod:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 3) (reg:SI R_MDC))] + "" + [(set_attr "type" "multi")]) + +(define_insn "*udivmodsi4_insn" + [(set (match_operand:SI 0 "register_operand" "=b") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r"))) + (set (reg:SI R_MDC) (umod:SI (match_dup 1) (match_dup 2)))] + "" + "divu %2" + [(set_attr "type" "div")]) + +(define_insn_and_split "udivmodsi4" + [(set (match_operand:SI 0 "register_operand" "=b") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "=r") + (umod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:SI R_MDC))] + "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (udiv:SI (match_dup 1) (match_dup 2))) + (set (reg:SI R_MDC) (umod:SI (match_dup 1) (match_dup 2)))]) + (set (match_dup 3) (reg:SI R_MDC))] + "" + [(set_attr "type" "multi")]) + +; FIXME. How do we persuade the compiler to use 64/32 bit divides directly ? + +(define_insn "*divds" + [(set (reg:DI R_MDB) + (div:DI (reg:DI R_MDB) (sign_extend:DI (match_operand:SI 0 "register_operand" "r")))) + (set (reg:SI R_MDC) (truncate:SI (mod:DI (reg:DI R_MDB) (sign_extend:DI (match_dup 0)))))] + "" + "divds %0" + [(set_attr "type" "divd")]) + +(define_insn "*divdu" + [(set (reg:DI R_MDB) + (udiv:DI (reg:DI R_MDB) (zero_extend:DI (match_operand:SI 0 "register_operand" "r")))) + (set (reg:SI R_MDC) (truncate:SI (umod:DI (reg:DI R_MDB) (zero_extend:DI (match_dup 0)))))] + "" + "divdu %0" + [(set_attr "type" "divd")]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bitwise Logical AND +;; +;; Modes QI, HI and SI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "and<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (and:I (match_operand:I 1 "register_operand" "") + (match_operand:I 2 "register_operand" "")))] + "") + +(define_insn_and_split "*and<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r") + (and:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (and:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*and<mode>3_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r") + (and:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "and<s> %0,%1,%2" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bitwise Inclusive Logical OR +;; +;; Modes QI, HI and SI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "ior<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (ior:I (match_operand:I 1 "register_operand" "") + (match_operand:I 2 "register_operand" "")))] + "") + +(define_insn_and_split "*ior<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r") + (ior:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ior:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*ior<mode>3_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r") + (ior:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "or<s> %0,%1,%2" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bitwise Exclusive Logical OR +;; +;; Modes QI, HI and SI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "xor<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (xor:I (match_operand:I 1 "register_operand" "") + (match_operand:I 2 "register_operand" "")))] + "") + +(define_insn_and_split "*xor<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r") + (xor:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (xor:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*xor<mode>3_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r") + (xor:I (match_operand:I 1 "register_operand" "%r") + (match_operand:I 2 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "xor<s> %0,%1,%2" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bitwise Logical NOT +;; +;; Modes QI, HI and SI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "one_cmpl<mode>2" + [(set (match_operand:I 0 "register_operand" "") + (not:I (match_operand:I 1 "reg_or_0_operand" "")))] + "") + +(define_insn_and_split "*one_cmpl<mode>2_insn" + [(set (match_operand:I 0 "register_operand" "=r") + (not:I (match_operand:I 1 "reg_or_0_operand" "rO")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (not:I (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*one_cmpl<mode>2_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r") + (not:I (match_operand:I 1 "reg_or_0_operand" "rO"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "not<s> %0,%r1" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Arithmetic Shift Left +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "ashl<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (ashift:I (match_operand:I 1 "register_operand" "") + (match_operand:QI 2 "reg_or_shift_operand" "")))] + "") + +(define_insn_and_split "*ashl<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r,r") + (ashift:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ashift:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "arith")]) + +(define_insn "*ashl<mode>3_insn<subst_arith>" + [(set (match_operand:I 0 "register_operand" "=r,r") + (ashift:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "asl<s> %0,%1,%2" + [(set_attr "type" "arith")]) + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "register_operand" "=b,r") + (ashift:DI (match_operand:DI 1 "register_operand" "0,r") + (match_operand:QI 2 "reg_or_32_operand" "r,P"))) + (clobber (reg:SI R_MDC))] + "" + "@ + asld %2 + #" + [(set_attr "type" "shiftdi,multi")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (const_int 32))) + (clobber (reg:SI R_MDC))] + "reload_completed" + [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 4)) + (set (subreg:SI (match_dup 0) 4) (const_int 0))] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Arithmetic Shift Right +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "ashr<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (ashiftrt:I (match_operand:I 1 "register_operand" "") + (match_operand:QI 2 "reg_or_shift_operand" "")))] + "") + +(define_insn_and_split "*ashr<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r,r") + (ashiftrt:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ashiftrt:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*ashr<mode>3_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r,r") + (ashiftrt:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "asr<s> %0,%1,%2" + [(set_attr "type" "logic")]) + +(define_insn "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "=b,r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,r") + (match_operand:QI 2 "reg_or_32_operand" "r,P"))) + (clobber (reg:SI R_MDC))] + "" + "@ + asrd %2 + #" + [(set_attr "type" "shiftdi,multi")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (const_int 32))) + (clobber (reg:SI R_MDC))] + "reload_completed" + [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 0)) + (parallel [(set (subreg:SI (match_dup 0) 0) + (ashiftrt:SI (subreg:SI (match_dup 1) 0) (const_int 31))) + (clobber (reg:CC R_FLAGS))])] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Logical Shift Right +;; +;; Modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "lshr<mode>3" + [(set (match_operand:I 0 "register_operand" "") + (lshiftrt:I (match_operand:I 1 "register_operand" "") + (match_operand:QI 2 "reg_or_shift_operand" "")))] + "") + +(define_insn_and_split "*lshr<mode>3_insn" + [(set (match_operand:I 0 "register_operand" "=r,r") + (lshiftrt:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] + "ok_for_simple_arith_logic_operands (operands, <MODE>mode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (lshiftrt:I (match_dup 1) (match_dup 2))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*lshr<mode>3_insn<subst_logic>" + [(set (match_operand:I 0 "register_operand" "=r,r") + (lshiftrt:I (match_operand:I 1 "register_operand" "r,r") + (match_operand:QI 2 "reg_or_shift_operand" "r,K"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "lsr<s> %0,%1,%2" + [(set_attr "type" "logic")]) + +(define_insn "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=b,r") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0,r") + (match_operand:QI 2 "reg_or_32_operand" "r,P"))) + (clobber (reg:SI R_MDC))] + "" + "@ + lsrd %2 + #" + [(set_attr "type" "shiftdi,multi")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (const_int 32))) + (clobber (reg:SI R_MDC))] + "reload_completed" + [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 0)) + (set (subreg:SI (match_dup 0) 0) (const_int 0))] + "") + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Truncate +;; +;; Truncations among modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "") + (truncate:QI (match_operand:HI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*trunchiqi2_insn" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, QImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (truncate:QI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*trunchiqi2_insn<subst_logic>" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.b %0,%1" + [(set_attr "type" "logic")]) + +(define_expand "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "") + (truncate:HI (match_operand:SI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*truncsihi2_insn" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, HImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (truncate:HI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*truncsihi2_insn<subst_logic>" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.w %0,%1" + [(set_attr "type" "logic")]) + +(define_expand "truncdisi2" + [(set (match_operand:SI 0 "register_operand" "") + (truncate:SI (match_operand:DI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*truncdisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:DI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (truncate:SI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*truncdisi2_insn<subst_logic>" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:DI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.l %0,%d1" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Sign-extend +;; +;; Sign-extensions among modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*extendqihi2_insn" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, HImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*extendqihi2_insn<subst_logic>" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "extb.w %0,%1" + [(set_attr "type" "logic")]) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*extendqisi2_insn<subst_logic>" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "extb.l %0,%1" + [(set_attr "type" "logic")]) + +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*extendhisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "register_operand" ""))) + (clobber (reg:CC R_FLAGS))])] + "" + [(set_attr "type" "logic")]) + +(define_insn "*extendhisi2_insn<subst_logic>" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r"))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "extw.l %0,%1" + [(set_attr "type" "logic")]) + +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*extendsidi2_insn" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, DImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 3) (match_dup 1)) + (clobber (reg:CC R_FLAGS))]) + (parallel [(set (match_dup 2) + (ashiftrt:SI (match_dup 1) (const_int 31))) + (clobber (reg:CC R_FLAGS))])] +{ + operands[2] = operand_subword (operands[0], 0, 0, DImode); + operands[3] = operand_subword (operands[0], 1, 0, DImode); +} + [(set_attr "type" "multi")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Zero-extend +;; +;; Zero-extensions among modes QI, HI, SI and DI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; QI is zero-extended to wider modes by shifting left and then performing +; a logical shift right to insert the zeroes. This avoids the need to use +; another register. + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*zero_extendqihi2_insn" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, HImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ashift:HI (match_dup 2) (const_int 8))) + (clobber (reg:CC R_FLAGS))]) + (parallel [(set (match_dup 0) + (lshiftrt:HI (match_dup 0) (const_int 8))) + (clobber (reg:CC R_FLAGS))])] +{ + operands[2] = gen_rtx_SUBREG (HImode, operands[1], 0); +} + [(set_attr "type" "multi")]) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*zero_extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, SImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ashift:SI (match_dup 2) (const_int 24))) + (clobber (reg:CC R_FLAGS))]) + (parallel [(set (match_dup 0) + (lshiftrt:SI (match_dup 0) (const_int 24))) + (clobber (reg:CC R_FLAGS))])] +{ + operands[2] = gen_rtx_SUBREG (SImode, operands[1], 0); +} + [(set_attr "type" "multi")]) + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))] + "" + "moviu %0,0" + [(set_attr "type" "imm_reg")]) + +(define_expand "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:SI 1 "register_operand" "")))] + "") + +(define_insn_and_split "*zero_extendsidi2_insn" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))] + "ok_for_simple_arith_logic_operands (operands, DImode)" + "#" + "reload_completed" + [(parallel [(set (match_dup 3) (match_dup 1)) + (clobber (reg:CC R_FLAGS))]) + (set (match_dup 2) (const_int 0))] +{ + operands[2] = operand_subword (operands[0], 0, 0, DImode); + operands[3] = operand_subword (operands[0], 1, 0, DImode); +} + [(set_attr "type" "multi")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bit Test +;; +;; Only SI mode is supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; BITS_BIG_ENDIAN is defined to 1 so operand #1 counts from the MSB. + +(define_insn "*btst" + [(set (reg:CC_BTST R_FLAGS) + (compare:CC_BTST (zero_extract:SI + (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:QI 1 "const_shift_operand" "K")) + (const_int 0)))] + "reload_completed" + "lsr.l r0,%0,32-%1" + [(set_attr "type" "logic")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Integer comparisons +;; +;; Modes QI, HI and SI are supported directly. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*cmp<mode>" + [(set (reg:CC R_FLAGS) + (compare:CC (match_operand:I 0 "register_operand" "r") + (match_operand:I 1 "reg_or_0_operand" "rO")))] + "reload_completed" + "cmp<s> %0,%r1" + [(set_attr "type" "cmp")]) + +(define_insn "*cmp<mode>_sne" + [(set (reg:CC R_FLAGS) + (compare:CC (not:I (match_operand:I 0 "register_operand" "r")) + (const_int -1)))] + "reload_completed" + "cmp<s> r0,%0" + [(set_attr "type" "cmp")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Single float operations +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "addsf3" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (plus:SF (match_operand:SF 1 "fp_reg_operand" "%f") + (match_operand:SF 2 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fadd %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (minus:SF (match_operand:SF 1 "fp_reg_operand" "f") + (match_operand:SF 2 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fsub %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (mult:SF (match_operand:SF 1 "fp_reg_operand" "%f") + (match_operand:SF 2 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fmult %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (div:SF (match_operand:SF 1 "fp_reg_operand" "f") + (match_operand:SF 2 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fdiv %0,%1,%2" + [(set_attr "type" "fdiv")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (sqrt:SF (match_operand:SF 1 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fsqrt %0,%1" + [(set_attr "type" "fsqrt")]) + +(define_insn "negsf2" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (neg:SF (match_operand:SF 1 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fneg %0,%1" + [(set_attr "type" "fmove")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (abs:SF (match_operand:SF 1 "fp_reg_operand" "f")))] + "TARGET_FPU" + "fabs %0,%1" + [(set_attr "type" "fmove")]) + +(define_expand "copysignsf3" + [(match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "nonmemory_operand" "") + (match_operand:SF 2 "register_operand" "")] + "TARGET_FPU && !TARGET_FPU_IEEE" +{ + visium_expand_copysign (operands, SFmode); + DONE; +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Single float <-> single integer conversions for !TARGET_FPU_IEEE +;; +;; An FMOVE instruction converts a signalling NaN (zero high order bit of the +;; mantissa) to a quiet NaN (-1). This is acceptable when the data to be +;; moved is in fact a floating-point number, but to avoid nasty surprises +;; integers must in general be kept out of the floating-point registers. +;; HARD_REGNO_MODE_OK thus only allows SFmode in these registers. +;; However, since FTOI and ITOF use floating-point registers for both their +;; inputs and outputs, to use these instructions integers must transiently +;; occupy such registers. To disguise this from the compiler, UNSPECs are +;; used for floating-point operations on integers and floating from general +;; register to floating-point register and fixing in the reverse direction +;; are only split into the individual UNSPEC operations after reload. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*fload_no_ieee" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (unspec:SF [(match_operand:SI 1 "register_operand" "r")] UNSPEC_FLOAD))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "fload %0,%1" + [(set_attr "type" "reg_fp")]) + +(define_insn "*itof_no_ieee" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (unspec:SF [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_ITOF))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "itof %0,%1" + [(set_attr "type" "itof")]) + +(define_insn_and_split "*floatsisf2_no_ieee" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (float:SF (match_operand:SI 1 "register_operand" "r")))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "#" + "&& reload_completed" + [(set (match_dup 0) + (unspec:SF [(match_dup 1)] UNSPEC_FLOAD)) + (set (match_dup 0) + (unspec:SF [(match_dup 0)] UNSPEC_ITOF))] + "" + [(set_attr "type" "multi")]) + +(define_insn "*ftoi_no_ieee" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (unspec:SF [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_FTOI))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "ftoi %0,%1" + [(set_attr "type" "ftoi")]) + +(define_insn "*fstore_no_ieee" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_FSTORE))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "fstore %0,%1" + [(set_attr "type" "fp_reg")]) + +(define_insn_and_split "fix_truncsfsi2_no_ieee" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" "f")))) + (clobber (match_scratch:SF 2 "=1"))] + "TARGET_FPU && !TARGET_FPU_IEEE" + "#" + "&& reload_completed" + [(set (match_dup 1) + (unspec:SF [(match_dup 1)] UNSPEC_FTOI)) + (set (match_dup 0) + (unspec:SI [(match_dup 1)] UNSPEC_FSTORE))] + "" + [(set_attr "type" "multi")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Single float <-> single integer conversions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*itof" + [(set (match_operand:SF 0 "fp_reg_operand" "=f") + (float:SF (match_operand:SI 1 "register_operand" "f")))] + "TARGET_FPU_IEEE" + "itof %0,%1" + [(set_attr "type" "itof")]) + +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "fp_reg_operand" "") + (float:SF (match_operand:SI 1 "register_operand" "")))] + "TARGET_FPU" + "") + +(define_insn "*ftoi" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" "f"))))] + "TARGET_FPU_IEEE" + "ftoi %0,%1" + [(set_attr "type" "ftoi")]) + +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" ""))))] + "TARGET_FPU" +{ + if (!TARGET_FPU_IEEE) + { + emit_insn (gen_fix_truncsfsi2_no_ieee (operands[0], operands[1])); + DONE; + } +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Single float comparisons +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "*cmpsf_fp" + [(set (reg:CCFP R_FLAGS) + (compare:CCFP (match_operand:SF 0 "fp_reg_or_0_operand" "fG") + (match_operand:SF 1 "fp_reg_or_0_operand" "fG")))] + "TARGET_FPU && reload_completed" + "fcmp r0,%f0,%f1" + [(set_attr "type" "fcmp")]) + +(define_insn "*cmpsf_fpe" + [(set (reg:CCFPE R_FLAGS) + (compare:CCFPE (match_operand:SF 0 "fp_reg_or_0_operand" "fG") + (match_operand:SF 1 "fp_reg_or_0_operand" "fG")))] + "TARGET_FPU && reload_completed" + "fcmpe r0,%f0,%f1" + [(set_attr "type" "fcmp")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Conditional branch instructions +;; +;; Note - we do not specify the two instructions necessary to perform +;; a compare-and-branch in the cbranch<mode>4 pattern because that would +;; allow the comparison to be moved away from the jump before the reload +;; pass has completed. That would be problematical because reload can +;; generate instructions in between which would clobber the CC register. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "cbranch<mode>4" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:I 1 "register_operand") + (match_operand:I 2 "reg_or_0_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] + "" +) + +(define_insn_and_split "*cbranch<mode>4_insn" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:I 1 "register_operand" "r") + (match_operand:I 2 "reg_or_0_operand" "rO")]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cbranch (GET_CODE (operands[0]), operands[1], operands[2], + operands[3]); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*cbranchsi4_btst_insn" + [(set (pc) + (if_then_else (match_operator 0 "visium_btst_operator" + [(zero_extract:SI + (match_operand:SI 1 "register_operand" "r") + (const_int 1) + (match_operand:QI 2 "const_shift_operand" "K")) + (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0), + XEXP (operands[0], 1), operands[3]); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_expand "cbranchsf4" + [(set (pc) + (if_then_else (match_operator 0 "visium_fp_comparison_operator" + [(match_operand:SF 1 "fp_reg_operand") + (match_operand:SF 2 "fp_reg_or_0_operand")]) + (label_ref (match_operand 3 "")) + (pc)))] + "TARGET_FPU" +) + +(define_insn_and_split "*cbranchsf4_insn" + [(set (pc) + (if_then_else (match_operator 0 "visium_fp_comparison_operator" + [(match_operand:SF 1 "fp_reg_operand" "f") + (match_operand:SF 2 "fp_reg_or_0_operand" "fG")]) + (label_ref (match_operand 3 "")) + (pc)))] + "TARGET_FPU" + "#" + "&& reload_completed" + [(const_int 0)] +{ + visium_split_cbranch (GET_CODE (operands[0]), operands[1], operands[2], + operands[3]); + DONE; +} + [(set_attr "type" "fcmp")]) + +; Now match both normal and inverted branches. + +(define_insn "*normal_branch" + [(set (pc) + (if_then_else (match_operator 1 "visium_branch_operator" + [(reg R_FLAGS) (const_int 0)]) + (label_ref (match_operand 0 "")) + (pc)))] + "reload_completed" +{ + return output_cbranch (operands[0], GET_CODE (operands[1]), + GET_MODE (XEXP (operands[1], 0)), 0, insn); +} + [(set_attr "type" "branch")]) + +(define_insn "*inverted_branch" + [(set (pc) + (if_then_else (match_operator 1 "visium_branch_operator" + [(reg R_FLAGS) (const_int 0)]) + (pc) + (label_ref (match_operand 0 ""))))] + "reload_completed" +{ + return output_cbranch (operands[0], GET_CODE (operands[1]), + GET_MODE (XEXP (operands[1], 0)), 1, insn); +} + [(set_attr "type" "branch")]) + +; And then match both normal and inverted returns. + +(define_insn "*cond_<return_str>return" + [(set (pc) + (if_then_else (match_operator 0 "visium_branch_operator" + [(reg R_FLAGS) (const_int 0)]) + (any_return) + (pc)))] + "<return_pred> && reload_completed" +{ + return output_cbranch (pc_rtx, GET_CODE (operands[0]), + GET_MODE (XEXP (operands[0], 0)), 0, insn); +} + [(set_attr "type" "ret")]) + +(define_insn "*inverted_cond_<return_str>return" + [(set (pc) + (if_then_else (match_operator 0 "visium_branch_operator" + [(reg R_FLAGS) (const_int 0)]) + (pc) + (any_return)))] + "<return_pred> && reload_completed" +{ + return output_cbranch (pc_rtx, GET_CODE (operands[0]), + GET_MODE (XEXP (operands[0], 0)), 1, insn); +} + [(set_attr "type" "ret")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Unconditional branch instructions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" +{ + return output_ubranch (operands[0], insn); +} + [(set_attr "type" "branch")]) + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r"))] + "" + "bra tr,%0,r0%# ;indirect jump" + [(set_attr "type" "abs_branch")]) + +(define_insn "tablejump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "bra tr,%0,r0%# ;tablejump" + [(set_attr "type" "abs_branch")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Subprogram call instructions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; Subroutine call instruction returning no value. Operand 0 is the function +; to call; operand 1 is the number of bytes of arguments pushed (in mode +; 'SImode', except it is normally a 'const_int'); operand 2 is the number of +; registers used as operands. + +(define_expand "call" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (match_dup 3))])] + "" +{ + if (GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + + if (!operands[2]) + operands[2] = const0_rtx; + + operands[3] = gen_rtx_REG (Pmode, R_LINK); +}) + +(define_insn "*call_internal" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l,!r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (match_operand 3 "" ""))] + "!SIBLING_CALL_P (insn)" + "bra tr,%0,%3%# ;call" + [(set_attr "type" "call")]) + +; Subroutine call instruction returning a value. Operand 0 is the hard +; register in which the value is returned. There are three more operands, the +; same as the three operands of the 'call' instruction (but with numbers +; increased by one). + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "register_operand" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (match_dup 4))])] + "" +{ + if (GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + + if (!operands[3]) + operands[3] = const0_rtx; + + operands[4] = gen_rtx_REG (Pmode, R_LINK); +}) + +(define_insn "*call_value_internal" + [(set (match_operand 0 "register_operand" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "l,!r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (match_operand 4 "" ""))] + "!SIBLING_CALL_P (insn)" + "bra tr,%1,%4%# ;call value" + [(set_attr "type" "call")]) + +; Tail calls are similar, except that the link register is not used. But +; we don't use r0 as the destination register of the branch because we want +; the Branch Pre-decode Logic of the GR6 to use the Address Load Array to +; predict the branch target. + +(define_expand "sibcall" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (match_dup 3))])] + "" +{ + if (GET_CODE (XEXP (operands[0], 0)) != REG) + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + + if (!operands[2]) + operands[2] = const0_rtx; + + operands[3] = gen_rtx_SCRATCH (SImode); +}) + +(define_insn "*sibcall_internal" + [(call (mem:SI (match_operand:SI 0 "register_operand" "k")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (match_scratch:SI 3 "=0"))] + "SIBLING_CALL_P (insn)" + "bra tr,%0,%0%# ;sibcall" + [(set_attr "type" "call")]) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "register_operand" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (match_dup 4))])] + "" +{ + if (GET_CODE (XEXP (operands[1], 0)) != REG) + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + + if (!operands[3]) + operands[3] = const0_rtx; + + operands[4] = gen_rtx_SCRATCH (SImode); +}) + +(define_insn "*sibcall_value_internal" + [(set (match_operand 0 "register_operand" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "k")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (match_scratch:SI 4 "=1"))] + "SIBLING_CALL_P (insn)" + "bra tr,%1,%1%# ;sibcall value" + [(set_attr "type" "call")]) + +; Call subroutine returning any type. +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" +{ + int i; + + emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Compare-and-store instructions +;; +;; Modes QI, HI, SI and SF are supported directly. +;; +;; Note - we do not specify the two instructions necessary to perform +;; a compare-and-store in the cstore<mode>4 pattern because that would +;; allow the comparison to be moved away from the store before the reload +;; pass has completed. That would be problematical because reload can +;; generate instructions in between which would clobber the CC register. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_expand "cstore<mode>4" + [(set (match_operand:SI 0) + (match_operator:SI 1 "visium_int_cstore_operator" + [(match_operand:I 2 "register_operand") + (match_operand:I 3 "reg_or_0_operand")]))] + "" +{ + visium_expand_int_cstore (operands, <MODE>mode); + DONE; +}) + +(define_insn_and_split "*cstore<mode>4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (ltu:SI (match_operand:I 1 "register_operand" "r") + (match_operand:I 2 "reg_or_0_operand" "rO")))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (SET, operands[0], NULL_RTX, + LTU, operands[1], operands[2]); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*neg_cstore<mode>4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (ltu:SI (match_operand:I 1 "register_operand" "r") + (match_operand:I 2 "reg_or_0_operand" "rO"))))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (NEG, operands[0], NULL_RTX, + LTU, operands[1], operands[2]); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*<add_str>_cstore<mode>4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (any_add:SI (match_operand:SI 1 "register_operand" "r") + (ltu:SI (match_operand:I 2 "register_operand" "r") + (match_operand:I 3 "reg_or_0_operand" "rO"))))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (<add_op>, operands[0], operands[1], + LTU, operands[2], operands[3]); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*cstore<mode>4_sne_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (ltu:SI (not:I (match_operand:I 1 "register_operand" "r")) + (const_int -1)))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (SET, operands[0], NULL_RTX, + LTU, gen_rtx_NOT (<MODE>mode, operands[1]), constm1_rtx); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*neg_cstore<mode>4_sne_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (ltu:SI (not:I (match_operand:I 1 "register_operand" "r")) + (const_int -1))))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (NEG, operands[0], NULL_RTX, + LTU, gen_rtx_NOT (<MODE>mode, operands[1]), constm1_rtx); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_insn_and_split "*<add_str>_cstore<mode>4_sne_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (any_add:SI (match_operand:SI 1 "register_operand" "r") + (ltu:SI (not:I (match_operand:I 2 "register_operand" "r")) + (const_int -1))))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + visium_split_cstore (<add_op>, operands[0], operands[1], + LTU, gen_rtx_NOT (<MODE>mode, operands[2]), constm1_rtx); + DONE; +} + [(set_attr "type" "cmp")]) + +(define_expand "cstoresf4" + [(set (match_operand:SI 0) + (match_operator:SI 1 "visium_fp_cstore_operator" + [(match_operand:SF 2 "fp_reg_operand") + (match_operand:SF 3 "fp_reg_or_0_operand")]))] + "TARGET_FPU" +{ + visium_expand_fp_cstore (operands, SFmode); + DONE; +}) + +(define_insn_and_split "*cstoresf4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (lt:SI (match_operand:SF 1 "fp_reg_or_0_operand" "fG") + (match_operand:SF 2 "fp_reg_or_0_operand" "fG")))] + "TARGET_FPU" + "#" + "&& reload_completed" + [(const_int 0)] +{ + visium_split_cstore (SET, operands [0], NULL_RTX, + LT, operands[1], operands[2]); + DONE; +} + [(set_attr "type" "fcmp")]) + +(define_insn_and_split "*neg_cstoresf4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (lt:SI (match_operand:SF 1 "fp_reg_or_0_operand" "fG") + (match_operand:SF 2 "fp_reg_or_0_operand" "fG"))))] + "TARGET_FPU" + "#" + "&& reload_completed" + [(const_int 0)] +{ + visium_split_cstore (NEG, operands [0], NULL_RTX, + LT, operands[1], operands[2]); + DONE; +} + [(set_attr "type" "fcmp")]) + +(define_insn_and_split "*<add_str>_cstoresf4_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (any_add:SI (match_operand:SI 1 "register_operand" "r") + (lt:SI (match_operand:SF 2 "fp_reg_or_0_operand" "fG") + (match_operand:SF 3 "fp_reg_or_0_operand" "fG"))))] + "TARGET_FPU" + "#" + "&& reload_completed" + [(const_int 0)] +{ + visium_split_cstore (<add_op>, operands [0], operands[1], + LT, operands[2], operands[3]); + DONE; +} + [(set_attr "type" "fcmp")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; RTL pro/epilogue support +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +; Expand prologue in RTL +(define_expand "prologue" + [(const_int 0)] + "" +{ + visium_expand_prologue (); + DONE; +}) + +; Expand epilogue in RTL +(define_expand "epilogue" + [(return)] + "" +{ + visium_expand_epilogue (); +}) + +; Expand epilogue without a final jump in RTL +(define_expand "sibcall_epilogue" + [(return)] + "" +{ + visium_expand_epilogue (); + DONE; +}) + +; The artificial dependency on the link register is to prevent the +; frame instruction from being put in a call delay slot, which can +; confuse the CFI machinery. + +(define_insn "stack_save" + [(set (reg:SI R_FP) (reg:SI R_SP)) + (use (reg:SI R_LINK)) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.l fp,sp ;stack_save" + [(set_attr "type" "logic")]) + +; The construct (mem:BLK (scratch)) is considered to alias all other +; memory accesses. Thus it can be used as a memory barrier in stack +; deallocation patterns. + +(define_insn "stack_restore" + [(set (reg:SI R_SP) (reg:SI R_FP)) + (clobber (mem:BLK (scratch))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "move.l sp,fp ;stack_restore" + [(set_attr "type" "logic")]) + +(define_insn "stack_pop" + [(set (reg:SI R_SP) + (plus:SI (reg:SI R_SP) (match_operand:SI 0 "add_operand" "J,r"))) + (clobber (mem:BLK (scratch))) + (clobber (reg:CC R_FLAGS))] + "reload_completed" + "@ + addi sp,%0 ;stack pop + add.l sp,sp,%0 ;stack pop" + [(set_attr "type" "arith")]) + +(define_expand "<return_str>return" + [(any_return)] + "<return_pred>" + "") + +(define_insn "*<return_str>return_internal" + [(any_return)] + "!visium_interrupt_function_p ()" +{ + return output_ubranch (pc_rtx, insn); +} + [(set_attr "type" "ret")]) + +(define_insn "*return_internal_interrupt" + [(return)] + "visium_interrupt_function_p ()" + "rfi\n\t nop ;return from interrupt" + [(set_attr "type" "rfi")]) + +(define_insn "dsi" + [(unspec_volatile [(const_int 0)] UNSPECV_DSI)] + "" + "dsi" + [(set_attr "type" "dsi")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; NOP (no-op instruction) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +(define_insn "nop" + [(const_int 0)] + "" + "nop ;generated nop" + [(set_attr "type" "nop")]) + +(define_insn "hazard_nop" + [(unspec_volatile [(const_int 0)] UNSPEC_NOP)] + "" + "nop ;hazard avoidance nop" + [(set_attr "type" "nop")]) + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] + "" + "" + [(set_attr "type" "nop")]) + +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; String/block operations +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; + +;; String/block move insn. +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment + +(define_expand "movmemsi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:SI 2 "general_operand" "")) + (use (match_operand:SI 3 "const_int_operand" ""))])] + "" +{ + if (visium_expand_block_move (operands)) + DONE; + else + FAIL; +}) + +(define_insn "*bmd" + [(set (mem:BLK (reg:SI R_R1)) + (mem:BLK (reg:SI R_R2))) + (use (reg:SI R_R3)) + (clobber (reg:SI R_R1)) + (clobber (reg:SI R_R2)) + (clobber (reg:SI R_R3)) + (clobber (reg:SI R_R4)) + (clobber (reg:SI R_R5)) + (clobber (reg:SI R_R6))] + "TARGET_BMI" + "bmd r1,r2,r3" + [(set_attr "type" "bmi")]) + +;; String/block set insn. +;; Argument 0 is the destination +;; Argument 1 is the length +;; Argument 2 is the value +;; Argument 3 is the alignment + +(define_expand "setmemsi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand 2 "nonmemory_operand" "")) + (use (match_operand:SI 1 "general_operand" "")) + (use (match_operand:SI 3 "const_int_operand" ""))])] + "" +{ + if (visium_expand_block_set (operands)) + DONE; + else + FAIL; +}) diff --git a/gcc/config/visium/visium.opt b/gcc/config/visium/visium.opt new file mode 100644 index 0000000..75c166e --- /dev/null +++ b/gcc/config/visium/visium.opt @@ -0,0 +1,82 @@ +; Options for Visium. +; Copyright (C) 2005-2015 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 +; <http://www.gnu.org/licenses/>. */ + +HeaderInclude +config/visium/visium-opts.h + +mdebug +Target RejectNegative +Link with libc.a and libdebug.a + +msim +Target RejectNegative +Link with libc.a and libsim.a + +mfpu +Target Report Mask(FPU) +Use hardware FP (default) + +mhard-float +Target RejectNegative Mask(FPU) MaskExists +Use hardware FP + +msoft-float +Target RejectNegative InverseMask(FPU) +Do not use hardware FP + +mcpu= +Target RejectNegative Joined Var(visium_cpu_and_features) Enum(visium_processor_type) Init(PROCESSOR_GR5) +Use features of and schedule code for given CPU + +mtune= +Target RejectNegative Joined Var(visium_cpu) Enum(visium_processor_type) Init(PROCESSOR_GR5) +Schedule code for given CPU + +Enum +Name(visium_processor_type) Type(enum processor_type) + +EnumValue +Enum(visium_processor_type) String(mcm) Value(PROCESSOR_GR5) + +EnumValue +Enum(visium_processor_type) String(gr5) Value(PROCESSOR_GR5) + +EnumValue +Enum(visium_processor_type) String(gr6) Value(PROCESSOR_GR6) + +msv-mode +Target Mask(SV_MODE) +Generate code for the supervisor mode (default) + +muser-mode +Target InverseMask(SV_MODE) +Generate code for the user mode + +menable-trampolines +Target RejectNegative +Only retained for backward compatibility. + +Mask(MCM) +; Generate code for the MCM + +Mask(BMI) +; Generate the Block Move Instructions + +Mask(FPU_IEEE) +; Generate code for an IEEE-compliant FPU diff --git a/gcc/configure b/gcc/configure index b589a2a..8670f73 100755 --- a/gcc/configure +++ b/gcc/configure @@ -26502,7 +26502,7 @@ esac case "$cpu_type" in aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \ | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ - | xstormy16 | xtensa) + | visium | xstormy16 | xtensa) insn="nop" ;; ia64 | s390) diff --git a/gcc/configure.ac b/gcc/configure.ac index 0169823..d010141 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4442,7 +4442,7 @@ esac case "$cpu_type" in aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \ | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ - | xstormy16 | xtensa) + | visium | xstormy16 | xtensa) insn="nop" ;; ia64 | s390) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f68cd7f6..2522682 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2935,12 +2935,11 @@ least version 2.20.1), and GNU C library (at least version 2.11.1). @item interrupt @cindex interrupt handler functions Use this attribute on the ARC, ARM, AVR, CR16, Epiphany, M32C, M32R/D, -m68k, MeP, MIPS, MSP430, RL78, RX and Xstormy16 ports to indicate that -the specified function is an -interrupt handler. The compiler generates function entry and exit -sequences suitable for use in an interrupt handler when this attribute -is present. With Epiphany targets it may also generate a special section with -code to initialize the interrupt vector table. +m68k, MeP, MIPS, MSP430, RL78, RX, Visium and Xstormy16 ports to indicate +that the specified function is an interrupt handler. The compiler generates +function entry and exit sequences suitable for use in an interrupt handler +when this attribute is present. With Epiphany targets it may also generate +a special section with code to initialize the interrupt vector table. Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, MicroBlaze, and SH processors can be specified via the @code{interrupt_handler} attribute. diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 1e05310..94e039d 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -3349,6 +3349,8 @@ information have to. @item @uref{#tilepro-x-linux,,tilepro-*-linux*} @item +@uref{#visium-x-elf, visium-*-elf} +@item @uref{#x-x-vxworks,,*-*-vxworks*} @item @uref{#x86-64-x-x,,x86_64-*-*, amd64-*-*} @@ -4650,6 +4652,14 @@ binutils-2.22 or newer. @html <hr /> @end html +@anchor{visium-x-elf} +@heading visium-*-elf +CDS VISIUMcore processor. +This configuration is intended for embedded systems. + +@html +<hr /> +@end html @anchor{x-x-vxworks} @heading *-*-vxworks* Support for VxWorks is in flux. At present GCC supports @emph{only} the diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c42898c..2e587f5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1064,6 +1064,10 @@ See RS/6000 and PowerPC Options. @emph{VAX Options} @gccoptlist{-mg -mgnu -munix} +@emph{Visium Options} +@gccoptlist{-mdebug -msim -mfpu -mno-fpu -mhard-float -msoft-float @gol +-mcpu=@var{cpu-type} -mtune=@var{cpu-type} -msv-mode -muser-mode} + @emph{VMS Options} @gccoptlist{-mvms-return-codes -mdebug-main=@var{prefix} -mmalloc64 @gol -mpointer-size=@var{size}} @@ -11936,6 +11940,7 @@ platform. * TILEPro Options:: * V850 Options:: * VAX Options:: +* Visium Options:: * VMS Options:: * VxWorks Options:: * x86-64 Options:: @@ -22606,6 +22611,77 @@ GNU assembler is being used. Output code for G-format floating-point numbers instead of D-format. @end table +@node Visium Options +@subsection Visium Options +@cindex Visium options + +@table @gcctabopt + +@item -mdebug +@opindex mdebug +A program which performs file I/O and is destined to run on an MCM target +should be linked with this option. It causes the libraries libc.a and +libdebug.a to be linked. The program should be run on the target under +the control of the GDB remote debugging stub. + +@item -msim +@opindex msim +A program which performs file I/O and is destined to run on the simulator +should be linked with option. This causes libraries libc.a and libsim.a to +be linked. + +@item -mfpu +@itemx -mhard-float +@opindex mfpu +@opindex mhard-float +Generate code containing floating-point instructions. This is the +default. + +@item -mno-fpu +@itemx -msoft-float +@opindex mno-fpu +@opindex msoft-float +Generate code containing library calls for floating-point. + +@option{-msoft-float} changes the calling convention in the output file; +therefore, it is only useful if you compile @emph{all} of a program with +this option. In particular, you need to compile @file{libgcc.a}, the +library that comes with GCC, with @option{-msoft-float} in order for +this to work. + +@item -mcpu=@var{cpu_type} +@opindex mcpu +Set the instruction set, register set, and instruction scheduling parameters +for machine type @var{cpu_type}. Supported values for @var{cpu_type} are +@samp{mcm}, @samp{gr5} and @samp{gr6}. + +@samp{mcm} is a synonym of @samp{gr5} present for backward compatibility. + +By default (unless configured otherwise), GCC generates code for the GR5 +variant of the Visium architecture. + +With @option{-mcpu=gr6}, GCC generates code for the GR6 variant of the Visium +architecture. The only difference from GR5 code is that the compiler will +generate block move instructions. + +@item -mtune=@var{cpu_type} +@opindex mtune +Set the instruction scheduling parameters for machine type @var{cpu_type}, +but do not set the instruction set or register set that the option +@option{-mcpu=@var{cpu_type}} would. + +@item -msv-mode +@opindex msv-mode +Generate code for the supervisor mode, where there are no restrictions on +the access to general registers. This is the default. + +@item -muser-mode +@opindex muser-mode +Generate code for the user mode, where the access to some general registers +is forbidden: on the GR5, registers r24 to r31 cannot be accessed in this +mode; on the GR6, only registers r29 to r31 are affected. +@end table + @node VMS Options @subsection VMS Options diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 48bd482..934ed23 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -3972,6 +3972,56 @@ A 2-element vector constant with identical elements. @end table +@item Visium---@file{config/visium/constraints.md} +@table @code +@item b +EAM register @code{mdb} + +@item c +EAM register @code{mdc} + +@item f +Floating point register + +@ifset INTERNALS +@item k +Register for sibcall optimization +@end ifset + +@item l +General register, but not @code{r29}, @code{r30} and @code{r31} + +@item t +Register @code{r1} + +@item u +Register @code{r2} + +@item v +Register @code{r3} + +@item G +Floating-point constant 0.0 + +@item J +Integer constant in the range 0 .. 65535 (16-bit immediate) + +@item K +Integer constant in the range 1 .. 31 (5-bit immediate) + +@item L +Integer constant in the range @minus{}65535 .. @minus{}1 (16-bit negative immediate) + +@item M +Integer constant @minus{}1 + +@item O +Integer constant 0 + +@item P +Integer constant 32 +@end table + @item Xtensa---@file{config/xtensa/constraints.md} @table @code @item a diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cac2f79..cbd491c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2015-01-06 Eric Botcazou <ebotcazou@adacore.com> + + * lib/target-supports.exp (check_profiling_available): Return 0 for + Visium. + (check_effective_target_tls_runtime): Likewise. + (check_effective_target_logical_op_short_circuit): Return 1 for Visium. + * gcc.dg/20020312-2.c: Adjust for Visium. + * gcc.dg/tls/thr-cse-1.c: Likewise + * gcc.dg/tree-ssa/20040204-1.c: Likewise + * gcc.dg/tree-ssa/loop-1.c: Likewise. + * gcc.dg/weak/typeof-2.c: Likewise. + 2015-01-05 Radovan Obradovic <radovan.obradovic@imgtec.com> PR rtl-optimization/64287 diff --git a/gcc/testsuite/gcc.dg/20020312-2.c b/gcc/testsuite/gcc.dg/20020312-2.c index de21741..71201fe 100644 --- a/gcc/testsuite/gcc.dg/20020312-2.c +++ b/gcc/testsuite/gcc.dg/20020312-2.c @@ -80,6 +80,8 @@ extern void abort (void); /* No pic register. */ #elif defined(__vax__) /* No pic register. */ +#elif defined(__VISIUM__) +/* No pic register. */ #elif defined(__xstormy16__) /* No pic register. */ #elif defined(__XTENSA__) diff --git a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c index 8e64424..da2fbff 100644 --- a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c +++ b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c @@ -18,11 +18,11 @@ int foo (int b, int c, int d) return a; } -/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "spu-*-*" "i?86-*-mingw*" "x86_64-*-mingw*" } } } } } */ +/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "spu-*-*" "i?86-*-mingw*" "x86_64-*-mingw*" visium-*-* } } } } } */ /* { dg-final { scan-assembler-not "call\tL___emutls_get_address.stub.*call\tL___emutls_get_address.stub.*" { target "*-*-darwin8" } } } */ /* { dg-final { scan-assembler-not "(b,l|bl) __emutls_get_address.*(b,l|bl) __emutls_get_address.*" { target "hppa*-*-hpux*" } } } */ /* { dg-final { scan-assembler-not "(brsl|brasl)\t__emutls_get_address.*(brsl|brasl)\t__emutls_get_address.*" { target spu-*-* } } } */ /* { dg-final { scan-assembler-not "tls_lookup.*tls_lookup.*" { target *-wrs-vxworks } } } */ /* { dg-final { scan-assembler-not "call\t___emutls_get_address.*call\t___emutls_get_address" { target "i?86-*-mingw*" } } } */ /* { dg-final { scan-assembler-not "call\t__emutls_get_address.*call\t__emutls_get_address" { target "x86_64-*-mingw*" } } } */ - +/* { dg-final { scan-assembler-not "%l __emutls_get_address.*%l __emutls_get_address" { target visium-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c index 2793336..42f6a4c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c @@ -33,5 +33,5 @@ void test55 (int x, int y) that the && should be emitted (based on BRANCH_COST). Fix this by teaching dom to look through && and register all components as true. */ -/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* sparc*-*-* spu-*-* x86_64-*-*" } } } } */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-*" } } } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c index dd52c50..f63c8a7 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c @@ -49,7 +49,7 @@ int xxx(void) /* CRIS keeps the address in a register. */ /* m68k sometimes puts the address in a register, depending on CPU and PIC. */ -/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* } } } */ +/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* visium-*-* } } } */ /* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-* } } } */ /* { dg-final { scan-assembler-times "= foo" 5 { target ia64*-*-* } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*_foo" 5 { target i?86-*-mingw* i?86-*-cygwin* } } } */ @@ -57,3 +57,4 @@ int xxx(void) /* { dg-final { scan-assembler-times "jsr|bsrf|blink\ttr?,r18" 5 { target sh*-*-* } } } */ /* { dg-final { scan-assembler-times "Jsr \\\$r" 5 { target cris-*-* } } } */ /* { dg-final { scan-assembler-times "\[jb\]sr" 5 { target fido-*-* m68k-*-* } } } */ +/* { dg-final { scan-assembler-times "bra *tr,r\[1-9\]*,r21" 5 { target visium-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/weak/typeof-2.c b/gcc/testsuite/gcc.dg/weak/typeof-2.c index 45a12eb..d4273e3 100644 --- a/gcc/testsuite/gcc.dg/weak/typeof-2.c +++ b/gcc/testsuite/gcc.dg/weak/typeof-2.c @@ -48,4 +48,6 @@ int bar3 (int x) // { dg-final { if [string match m68k-*-* $target_triplet ] {return} } } // Likewise for moxie targets. // { dg-final { if [string match moxie-*-* $target_triplet ] {return} } } +// Likewise for Visium targets. +// { dg-final { if [string match visium-*-* $target_triplet ] {return} } } // { dg-final { scan-assembler "baz3.*baz3.*baz3.*baz3.*baz3.*baz3" } } diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index e335913..119d2c5 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -538,6 +538,7 @@ proc check_profiling_available { test_what } { || [istarget powerpc-*-elf] || [istarget rx-*-*] || [istarget tic6x-*-elf] + || [istarget visium-*-*] || [istarget xstormy16-*] || [istarget xtensa*-*-elf] || [istarget *-*-rtems*] @@ -707,9 +708,9 @@ proc check_effective_target_tls_emulated {} { # Return 1 if TLS executables can run correctly, 0 otherwise. proc check_effective_target_tls_runtime {} { - # MSP430 runtime does not have TLS support, but just + # The runtime does not have TLS support, but just # running the test below is insufficient to show this. - if { [istarget msp430-*-*] } { + if { [istarget msp430-*-*] || [istarget visium-*-*] } { return 0 } return [check_runtime tls_runtime { @@ -6085,6 +6086,7 @@ proc check_effective_target_logical_op_short_circuit {} { || [istarget s390*-*-*] || [istarget powerpc*-*-*] || [istarget nios2*-*-*] + || [istarget visium-*-*] || [check_effective_target_arm_cortex_m] } { return 1 } diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 55fb239..241747f 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,8 @@ +2015-01-06 Eric Botcazou <ebotcazou@adacore.com> + + * config.host: Add Visium support. + * config/visium: New directory. + 2015-01-05 Jakub Jelinek <jakub@redhat.com> Update copyright years. diff --git a/libgcc/config.host b/libgcc/config.host index e0db9f9..667eb31 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -1235,6 +1235,10 @@ vax-*-netbsdelf*) ;; vax-*-openbsd*) ;; +visium-*-elf*) + extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o" + tmake_file="visium/t-visium t-fdpbit" + ;; xstormy16-*-elf) tmake_file="stormy16/t-stormy16 t-fdpbit" ;; diff --git a/libgcc/config/visium/crti.S b/libgcc/config/visium/crti.S new file mode 100644 index 0000000..158ae0f --- /dev/null +++ b/libgcc/config/visium/crti.S @@ -0,0 +1,46 @@ +/* crti.S for Visium. + Copyright (C) 2005-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + + .file "crti.o" + .ident "GNU C crti.o" + + .section .init + .globl __init + .type __init,@function +__init: + subi r23,8 + nop + write.l (r23),r22 + write.l 1(r23),r21 + move.l r22,r23 + + .section .fini + .globl __fini + .type __fini,@function +__fini: + subi r23,8 + nop + write.l (r23),r22 + write.l 1(r23),r21 + move.l r22,r23 diff --git a/libgcc/config/visium/crtn.S b/libgcc/config/visium/crtn.S new file mode 100644 index 0000000..a60f4de --- /dev/null +++ b/libgcc/config/visium/crtn.S @@ -0,0 +1,40 @@ +/* crtn.S for Visium. + Copyright (C) 2005-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + + .file "crtn.o" + .ident "GNU C crtn.o" + + .section .init + move.l r23,r22 + read.l r22,(r22) + read.l r21,1(r23) + bra tr,r21,r0 + addi r23,8 + + .section .fini + move.l r23,r22 + read.l r22,(r22) + read.l r21,1(r23) + bra tr,r21,r0 + addi r23,8 diff --git a/libgcc/config/visium/divdi3.c b/libgcc/config/visium/divdi3.c new file mode 100644 index 0000000..38b747a --- /dev/null +++ b/libgcc/config/visium/divdi3.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_divdi3 +#include "lib2funcs.c" diff --git a/libgcc/config/visium/lib2funcs.c b/libgcc/config/visium/lib2funcs.c new file mode 100644 index 0000000..ba720a3 --- /dev/null +++ b/libgcc/config/visium/lib2funcs.c @@ -0,0 +1,323 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "libgcc_tm.h" + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +/* Work out the largest "word" size that we can deal with on this target. */ +#if MIN_UNITS_PER_WORD > 4 +# define LIBGCC2_MAX_UNITS_PER_WORD 8 +#elif (MIN_UNITS_PER_WORD > 2 \ + || (MIN_UNITS_PER_WORD > 1 && __SIZEOF_LONG_LONG__ > 4)) +# define LIBGCC2_MAX_UNITS_PER_WORD 4 +#else +# define LIBGCC2_MAX_UNITS_PER_WORD MIN_UNITS_PER_WORD +#endif + +/* Work out what word size we are using for this compilation. + The value can be set on the command line. */ +#ifndef LIBGCC2_UNITS_PER_WORD +#define LIBGCC2_UNITS_PER_WORD LIBGCC2_MAX_UNITS_PER_WORD +#endif + +#if LIBGCC2_UNITS_PER_WORD <= LIBGCC2_MAX_UNITS_PER_WORD + +#include "libgcc2.h" + +/* umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two + UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. */ + +#undef umul_ppmm +#define umul_ppmm(wh, wl, u, v) \ + do { \ + /* Generate multu instruction. */ \ + UDWtype __t = (UDWtype)(u) * (UDWtype)(v); \ + (wl) = (UWtype)__t; \ + (wh) = (UWtype)(__t >> W_TYPE_SIZE); \ + } while (0) + +/* sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. */ + +#undef sub_ddmmss +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub.l %0,%2,%4\n\t" \ + "subc.l %1,%3,%5" \ + : "=&r" (sl), "=r" (sh) \ + : "r" (al), "r" (ah), "r" (bl), "r" (bh)) + +/* udiv_qqrnnd(high_quotient, low_quotient, remainder, high_numerator, + low_numerator, denominator) divides a UDWtype, composed by the UWtype + HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + in QUOTIENT and the remainder in REMAINDER. */ + +#define udiv_qqrnnd(qh, ql, r, nh, nl, d) \ + __asm__ ("writemd %3,%4\n\t" \ + "divdu %5\n\t" \ + "readmda %0\n\t" \ + "readmdb %1\n\t" \ + "readmdc %2" \ + : "=r" (ql), "=r" (qh), "=r" (r) \ + : "r" (nl), "r" (nh), "r" (d) \ + : "mdb", "mdc") + +#if (defined (L_udivdi3) || defined (L_divdi3) || \ + defined (L_umoddi3) || defined (L_moddi3)) +#define L_udivmoddi4 +#endif + +#ifdef L_udivmoddi4 + +#if (defined (L_udivdi3) || defined (L_divdi3) || \ + defined (L_umoddi3) || defined (L_moddi3)) +static inline __attribute__ ((__always_inline__)) +#endif +UDWtype +__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + + if (d1 == 0) + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qqrnnd (q1, q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qqrnnd (q1, q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + const DWunion ww = {{.low = q0, .high = q1}}; + return ww.ll; +} +#endif + +#ifdef L_divdi3 +DWtype +__divdi3 (DWtype u, DWtype v) +{ + Wtype c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; + + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + if (vv.s.high < 0) + c = ~c, + vv.ll = -vv.ll; + + w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); + if (c) + w = -w; + + return w; +} +#endif + +#ifdef L_moddi3 +DWtype +__moddi3 (DWtype u, DWtype v) +{ + Wtype c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; + + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + if (vv.s.high < 0) + vv.ll = -vv.ll; + + (void) __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w); + if (c) + w = -w; + + return w; +} +#endif + +#ifdef L_umoddi3 +UDWtype +__umoddi3 (UDWtype u, UDWtype v) +{ + UDWtype w; + + (void) __udivmoddi4 (u, v, &w); + + return w; +} +#endif + +#ifdef L_udivdi3 +UDWtype +__udivdi3 (UDWtype n, UDWtype d) +{ + return __udivmoddi4 (n, d, (UDWtype *) 0); +} +#endif + +#ifdef L_set_trampoline_parity +#undef int +extern void __set_trampoline_parity (UWtype *); + +static inline UWtype +parity_bit (UWtype x) +{ + x ^= x << 16; + x ^= x << 8; + x ^= x << 4; + x ^= x << 2; + x ^= x << 1; + return x & ((UWtype) 1 << (W_TYPE_SIZE - 1)); +} + +void +__set_trampoline_parity (UWtype *addr) +{ + int i; + + for (i = 0; i < (TRAMPOLINE_SIZE * BITS_PER_UNIT) / W_TYPE_SIZE; i++) + addr[i] |= parity_bit (addr[i]); +} +#endif + +#endif /* LIBGCC2_UNITS_PER_WORD <= MIN_UNITS_PER_WORD */ diff --git a/libgcc/config/visium/memcpy.c b/libgcc/config/visium/memcpy.c new file mode 100644 index 0000000..21efdd0 --- /dev/null +++ b/libgcc/config/visium/memcpy.c @@ -0,0 +1,862 @@ +/* Copyright (C) 2012-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +/* This file must be kept in sync with newlib/libc/machine/visium/memcpy.c */ + +#include <stddef.h> +#include "memcpy.h" + +#define INST_BARRIER __asm__ __volatile__ ("":::"memory"); + +#define MOVE_32_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + m0 = in [8]; \ + m1 = in [9]; \ + m2 = in [10]; \ + m3 = in [11]; \ + out [8] = m0; \ + out [9] = m1; \ + out [10] = m2; \ + out [11] = m3; \ + INST_BARRIER \ + m0 = in [12]; \ + m1 = in [13]; \ + m2 = in [14]; \ + m3 = in [15]; \ + out [12] = m0; \ + out [13] = m1; \ + out [14] = m2; \ + out [15] = m3; \ + INST_BARRIER \ + m0 = in [16]; \ + m1 = in [17]; \ + m2 = in [18]; \ + m3 = in [19]; \ + out [16] = m0; \ + out [17] = m1; \ + out [18] = m2; \ + out [19] = m3; \ + INST_BARRIER \ + m0 = in [20]; \ + m1 = in [21]; \ + m2 = in [22]; \ + m3 = in [23]; \ + out [20] = m0; \ + out [21] = m1; \ + out [22] = m2; \ + out [23] = m3; \ + INST_BARRIER \ + m0 = in [24]; \ + m1 = in [25]; \ + m2 = in [26]; \ + m3 = in [27]; \ + out [24] = m0; \ + out [25] = m1; \ + out [26] = m2; \ + out [27] = m3; \ + INST_BARRIER \ + m0 = in [28]; \ + m1 = in [29]; \ + m2 = in [30]; \ + m3 = in [31]; \ + out [28] = m0; \ + out [29] = m1; \ + out [30] = m2; \ + out [31] = m3; \ + INST_BARRIER \ + in += 32; \ + out += 32; \ +} while(0) + +#define MOVE_16_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + m0 = in [8]; \ + m1 = in [9]; \ + m2 = in [10]; \ + m3 = in [11]; \ + out [8] = m0; \ + out [9] = m1; \ + out [10] = m2; \ + out [11] = m3; \ + INST_BARRIER \ + m0 = in [12]; \ + m1 = in [13]; \ + m2 = in [14]; \ + m3 = in [15]; \ + out [12] = m0; \ + out [13] = m1; \ + out [14] = m2; \ + out [15] = m3; \ + INST_BARRIER \ + in += 16; \ + out += 16; \ +} while(0) + +#define MOVE_12_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + m0 = in [8]; \ + m1 = in [9]; \ + m2 = in [10]; \ + m3 = in [11]; \ + out [8] = m0; \ + out [9] = m1; \ + out [10] = m2; \ + out [11] = m3; \ + INST_BARRIER \ + in += 12; \ + out += 12; \ +} while(0) + +#define MOVE_11_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + m0 = in [8]; \ + m1 = in [9]; \ + m2 = in [10]; \ + out [8] = m0; \ + out [9] = m1; \ + out [10] = m2; \ + INST_BARRIER \ + in += 11; \ + out += 11; \ +} while(0) + +#define MOVE_10_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + m0 = in [8]; \ + out [5] = m1; \ + m1 = in [9]; \ + out [6] = m2; \ + out [7] = m3; \ + out [8] = m0; \ + out [9] = m1; \ + INST_BARRIER \ + in += 10; \ + out += 10; \ +} while(0) + +#define MOVE_9_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + m0 = in [8]; \ + out [8] = m0; \ + in += 9; \ + out += 9; \ +} while(0) + +#define MOVE_8_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + m3 = in [7]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + out [7] = m3; \ + INST_BARRIER \ + in += 8; \ + out += 8; \ +} while(0) + +#define MOVE_7_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + m0 = in [4]; \ + m1 = in [5]; \ + m2 = in [6]; \ + out [4] = m0; \ + out [5] = m1; \ + out [6] = m2; \ + INST_BARRIER \ + in += 7; \ + out += 7; \ +} while(0) + +#define MOVE_6_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + INST_BARRIER \ + m0 = in [4]; \ + out [1] = m1; \ + INST_BARRIER \ + m1 = in [5]; \ + out [2] = m2; \ + out [3] = m3; \ + out [4] = m0; \ + out [5] = m1; \ + INST_BARRIER \ + in += 6; \ + out += 6; \ +} while(0) + +#define MOVE_5_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + INST_BARRIER \ + out [0] = m0; \ + m0 = in [4]; \ + INST_BARRIER \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + out [4] = m0; \ + INST_BARRIER \ + in += 5; \ + out += 5; \ +} while(0) + +#define MOVE_4_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + m3 = in [3]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + out [3] = m3; \ + INST_BARRIER \ + in += 4; \ + out += 4; \ +} while(0) + +#define MOVE_3_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + m2 = in [2]; \ + out [0] = m0; \ + out [1] = m1; \ + out [2] = m2; \ + INST_BARRIER \ + in += 3; \ + out += 3; \ +} while(0) + +#define MOVE_2_OBJECTS(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + m1 = in [1]; \ + out [0] = m0; \ + out [1] = m1; \ + INST_BARRIER \ + in += 2; \ + out += 2; \ +} while(0) + +#define MOVE_1_OBJECT(in,out) \ +do { \ + INST_BARRIER \ + m0 = in [0]; \ + out [0] = m0; \ + INST_BARRIER \ + in += 1; \ + out += 1; \ +} while(0) + + +static inline void +__int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + int value = n; + int loop_var; + const int *in = s2; + int *out = s1; + int count; + int m0,m1,m2,m3; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + MOVE_1_OBJECT (in, out); + break; + case 2: + MOVE_2_OBJECTS (in, out); + break; + case 3: + MOVE_3_OBJECTS (in, out); + break; + case 4: + MOVE_4_OBJECTS (in, out); + break; + case 5: + MOVE_5_OBJECTS (in, out); + break; + case 6: + MOVE_6_OBJECTS (in, out); + break; + case 7: + MOVE_7_OBJECTS (in, out); + break; + case 8: + MOVE_8_OBJECTS (in, out); + break; + case 9: + MOVE_9_OBJECTS (in, out); + break; + case 10: + MOVE_10_OBJECTS (in, out); + break; + case 11: + MOVE_11_OBJECTS (in, out); + break; + case 12: + MOVE_12_OBJECTS (in, out); + break; + case 13: + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 14: + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 15: + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 16: + MOVE_16_OBJECTS (in, out); + break; + case 17: + MOVE_11_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 18: + MOVE_9_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 19: + MOVE_16_OBJECTS (in, out); + MOVE_3_OBJECTS (in, out); + break; + case 20: + MOVE_16_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 21: + MOVE_16_OBJECTS (in, out); + MOVE_5_OBJECTS (in, out); + break; + case 22: + MOVE_16_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 23: + MOVE_16_OBJECTS (in, out); + MOVE_7_OBJECTS (in, out); + break; + case 24: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + break; + case 25: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 26: + MOVE_16_OBJECTS (in, out); + MOVE_10_OBJECTS (in, out); + break; + case 27: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + break; + case 28: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 29: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 30: + MOVE_16_OBJECTS (in, out); + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 31: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + MOVE_32_OBJECTS (in, out); +} + +static inline void +__shrt_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + int value = n; + int loop_var; + const short int *in = s2; + int short *out = s1; + int count; + int m0,m1,m2,m3; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + MOVE_1_OBJECT (in, out); + break; + case 2: + MOVE_2_OBJECTS (in, out); + break; + case 3: + MOVE_3_OBJECTS (in, out); + break; + case 4: + MOVE_4_OBJECTS (in, out); + break; + case 5: + MOVE_5_OBJECTS (in, out); + break; + case 6: + MOVE_6_OBJECTS (in, out); + break; + case 7: + MOVE_7_OBJECTS (in, out); + break; + case 8: + MOVE_8_OBJECTS (in, out); + break; + case 9: + MOVE_9_OBJECTS (in, out); + break; + case 10: + MOVE_10_OBJECTS (in, out); + break; + case 11: + MOVE_11_OBJECTS (in, out); + break; + case 12: + MOVE_12_OBJECTS (in, out); + break; + case 13: + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 14: + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 15: + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 16: + MOVE_16_OBJECTS (in, out); + break; + case 17: + MOVE_11_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 18: + MOVE_9_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 19: + MOVE_16_OBJECTS (in, out); + MOVE_3_OBJECTS (in, out); + break; + case 20: + MOVE_16_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 21: + MOVE_16_OBJECTS (in, out); + MOVE_5_OBJECTS (in, out); + break; + case 22: + MOVE_16_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 23: + MOVE_16_OBJECTS (in, out); + MOVE_7_OBJECTS (in, out); + break; + case 24: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + break; + case 25: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 26: + MOVE_16_OBJECTS (in, out); + MOVE_10_OBJECTS (in, out); + break; + case 27: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + break; + case 28: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 29: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 30: + MOVE_16_OBJECTS (in, out); + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 31: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + MOVE_32_OBJECTS (in, out); +} + + +static inline void +__byte_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + int value = n; + int loop_var; + const char *in = s2; + char *out = s1; + int count; + int m0,m1,m2,m3; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + MOVE_1_OBJECT (in, out); + break; + case 2: + MOVE_2_OBJECTS (in, out); + break; + case 3: + MOVE_3_OBJECTS (in, out); + break; + case 4: + MOVE_4_OBJECTS (in, out); + break; + case 5: + MOVE_5_OBJECTS (in, out); + break; + case 6: + MOVE_6_OBJECTS (in, out); + break; + case 7: + MOVE_7_OBJECTS (in, out); + break; + case 8: + MOVE_8_OBJECTS (in, out); + break; + case 9: + MOVE_9_OBJECTS (in, out); + break; + case 10: + MOVE_10_OBJECTS (in, out); + break; + case 11: + MOVE_11_OBJECTS (in, out); + break; + case 12: + MOVE_12_OBJECTS (in, out); + break; + case 13: + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 14: + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 15: + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 16: + MOVE_16_OBJECTS (in, out); + break; + case 17: + MOVE_11_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 18: + MOVE_9_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 19: + MOVE_16_OBJECTS (in, out); + MOVE_3_OBJECTS (in, out); + break; + case 20: + MOVE_16_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 21: + MOVE_16_OBJECTS (in, out); + MOVE_5_OBJECTS (in, out); + break; + case 22: + MOVE_16_OBJECTS (in, out); + MOVE_6_OBJECTS (in, out); + break; + case 23: + MOVE_16_OBJECTS (in, out); + MOVE_7_OBJECTS (in, out); + break; + case 24: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + break; + case 25: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + break; + case 26: + MOVE_16_OBJECTS (in, out); + MOVE_10_OBJECTS (in, out); + break; + case 27: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + break; + case 28: + MOVE_16_OBJECTS (in, out); + MOVE_8_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 29: + MOVE_16_OBJECTS (in, out); + MOVE_9_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + case 30: + MOVE_16_OBJECTS (in, out); + MOVE_12_OBJECTS (in, out); + MOVE_2_OBJECTS (in, out); + break; + case 31: + MOVE_16_OBJECTS (in, out); + MOVE_11_OBJECTS (in, out); + MOVE_4_OBJECTS (in, out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + MOVE_32_OBJECTS (in, out); +} + + +/* Exposed interface. */ + +#ifndef __VISIUM_ARCH_BMI__ + +void +__long_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + __int_memcpy (s1, s2, n); +} + +#endif /* !__VISIUM_ARCH_BMI__ */ + +void +__wrd_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + __shrt_int_memcpy (s1, s2, n); +} + +void +__byt_memcpy (void *__restrict s1, const void *__restrict s2, size_t n) +{ + __byte_memcpy (s1, s2, n); +} diff --git a/libgcc/config/visium/memcpy.h b/libgcc/config/visium/memcpy.h new file mode 100644 index 0000000..5df8176 --- /dev/null +++ b/libgcc/config/visium/memcpy.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2012-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +/* Specialized variants of memcpy called directly from compiled code. */ + +extern void +__long_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n); + +extern void +__wrd_memcpy (void *__restrict s1, const void *__restrict s2, size_t n); + +extern void +__byt_memcpy (void *__restrict s1, const void *__restrict s2, size_t n); diff --git a/libgcc/config/visium/memset.c b/libgcc/config/visium/memset.c new file mode 100644 index 0000000..5f81679 --- /dev/null +++ b/libgcc/config/visium/memset.c @@ -0,0 +1,664 @@ +/* Copyright (C) 2012-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +/* This file must be kept in sync with newlib/libc/machine/visium/memset.c */ + +#include <stddef.h> +#include "memset.h" + +#define SET_32_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out [9] = m0; \ + out [10] = m0; \ + out [11] = m0; \ + out [12] = m0; \ + out [13] = m0; \ + out [14] = m0; \ + out [15] = m0; \ + out [16] = m0; \ + out [17] = m0; \ + out [18] = m0; \ + out [19] = m0; \ + out [20] = m0; \ + out [21] = m0; \ + out [22] = m0; \ + out [23] = m0; \ + out [24] = m0; \ + out [25] = m0; \ + out [26] = m0; \ + out [27] = m0; \ + out [28] = m0; \ + out [29] = m0; \ + out [30] = m0; \ + out [31] = m0; \ + out += 32; \ +} while(0) + +#define SET_16_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out [9] = m0; \ + out [10] = m0; \ + out [11] = m0; \ + out [12] = m0; \ + out [13] = m0; \ + out [14] = m0; \ + out [15] = m0; \ + out += 16; \ +} while(0) + +#define SET_12_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out [9] = m0; \ + out [10] = m0; \ + out [11] = m0; \ + out += 12; \ +} while(0) + +#define SET_11_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out [9] = m0; \ + out [10] = m0; \ + out += 11; \ +} while(0) + +#define SET_10_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out [9] = m0; \ + out += 10; \ +} while(0) + +#define SET_9_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out [8] = m0; \ + out += 9; \ +} while(0) + +#define SET_8_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out [7] = m0; \ + out += 8; \ +} while(0) + +#define SET_7_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out [6] = m0; \ + out += 7; \ +} while(0) + +#define SET_6_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out [5] = m0; \ + out += 6; \ +} while(0) + +#define SET_5_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out [4] = m0; \ + out += 5; \ +} while(0) + +#define SET_4_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out [3] = m0; \ + out += 4; \ +} while(0) + +#define SET_3_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out [2] = m0; \ + out += 3; \ +} while(0) + +#define SET_2_OBJECTS(out) \ +do { \ + out [0] = m0; \ + out [1] = m0; \ + out += 2; \ +} while(0) + +#define SET_1_OBJECT(out) \ +do { \ + out [0] = m0; \ + out += 1; \ +} while(0) + + +static inline void +__int_memset (void *__restrict s1, int val, size_t n) +{ + int value = n; + int loop_var; + int *out = s1; + int count; + int m0 = val; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + SET_1_OBJECT (out); + break; + case 2: + SET_2_OBJECTS (out); + break; + case 3: + SET_3_OBJECTS (out); + break; + case 4: + SET_4_OBJECTS (out); + break; + case 5: + SET_5_OBJECTS (out); + break; + case 6: + SET_6_OBJECTS (out); + break; + case 7: + SET_7_OBJECTS (out); + break; + case 8: + SET_8_OBJECTS (out); + break; + case 9: + SET_9_OBJECTS (out); + break; + case 10: + SET_10_OBJECTS (out); + break; + case 11: + SET_11_OBJECTS (out); + break; + case 12: + SET_12_OBJECTS (out); + break; + case 13: + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 14: + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 15: + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 16: + SET_16_OBJECTS (out); + break; + case 17: + SET_11_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 18: + SET_9_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 19: + SET_16_OBJECTS (out); + SET_3_OBJECTS (out); + break; + case 20: + SET_16_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 21: + SET_16_OBJECTS (out); + SET_5_OBJECTS (out); + break; + case 22: + SET_16_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 23: + SET_16_OBJECTS (out); + SET_7_OBJECTS (out); + break; + case 24: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + break; + case 25: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 26: + SET_16_OBJECTS (out); + SET_10_OBJECTS (out); + break; + case 27: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + break; + case 28: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 29: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 30: + SET_16_OBJECTS (out); + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 31: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + SET_32_OBJECTS (out); +} + +static inline void +__short_int_memset (void *__restrict s1, int val, size_t n) +{ + int value = n; + int loop_var; + int short *out = s1; + int count; + int m0 = val; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + SET_1_OBJECT (out); + break; + case 2: + SET_2_OBJECTS (out); + break; + case 3: + SET_3_OBJECTS (out); + break; + case 4: + SET_4_OBJECTS (out); + break; + case 5: + SET_5_OBJECTS (out); + break; + case 6: + SET_6_OBJECTS (out); + break; + case 7: + SET_7_OBJECTS (out); + break; + case 8: + SET_8_OBJECTS (out); + break; + case 9: + SET_9_OBJECTS (out); + break; + case 10: + SET_10_OBJECTS (out); + break; + case 11: + SET_11_OBJECTS (out); + break; + case 12: + SET_12_OBJECTS (out); + break; + case 13: + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 14: + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 15: + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 16: + SET_16_OBJECTS (out); + break; + case 17: + SET_11_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 18: + SET_9_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 19: + SET_16_OBJECTS (out); + SET_3_OBJECTS (out); + break; + case 20: + SET_16_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 21: + SET_16_OBJECTS (out); + SET_5_OBJECTS (out); + break; + case 22: + SET_16_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 23: + SET_16_OBJECTS (out); + SET_7_OBJECTS (out); + break; + case 24: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + break; + case 25: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 26: + SET_16_OBJECTS (out); + SET_10_OBJECTS (out); + break; + case 27: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + break; + case 28: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 29: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 30: + SET_16_OBJECTS (out); + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 31: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + SET_32_OBJECTS (out); +} + +static inline void +__byte_memset (void *__restrict s1, int val, size_t n) +{ + int value = n; + int loop_var; + char *out = s1; + int count; + int m0 = val; + + /* This code currently give a stall for any value with a 1->2 in the low 5 + bits, i.e. 1,2, 33,34 ? not acceptable! */ + switch (value & 0x1f) + { + case 0: + break; + case 1: + SET_1_OBJECT (out); + break; + case 2: + SET_2_OBJECTS (out); + break; + case 3: + SET_3_OBJECTS (out); + break; + case 4: + SET_4_OBJECTS (out); + break; + case 5: + SET_5_OBJECTS (out); + break; + case 6: + SET_6_OBJECTS (out); + break; + case 7: + SET_7_OBJECTS (out); + break; + case 8: + SET_8_OBJECTS (out); + break; + case 9: + SET_9_OBJECTS (out); + break; + case 10: + SET_10_OBJECTS (out); + break; + case 11: + SET_11_OBJECTS (out); + break; + case 12: + SET_12_OBJECTS (out); + break; + case 13: + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 14: + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 15: + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 16: + SET_16_OBJECTS (out); + break; + case 17: + SET_11_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 18: + SET_9_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 19: + SET_16_OBJECTS (out); + SET_3_OBJECTS (out); + break; + case 20: + SET_16_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 21: + SET_16_OBJECTS (out); + SET_5_OBJECTS (out); + break; + case 22: + SET_16_OBJECTS (out); + SET_6_OBJECTS (out); + break; + case 23: + SET_16_OBJECTS (out); + SET_7_OBJECTS (out); + break; + case 24: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + break; + case 25: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + break; + case 26: + SET_16_OBJECTS (out); + SET_10_OBJECTS (out); + break; + case 27: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + break; + case 28: + SET_16_OBJECTS (out); + SET_8_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 29: + SET_16_OBJECTS (out); + SET_9_OBJECTS (out); + SET_4_OBJECTS (out); + break; + case 30: + SET_16_OBJECTS (out); + SET_12_OBJECTS (out); + SET_2_OBJECTS (out); + break; + case 31: + SET_16_OBJECTS (out); + SET_11_OBJECTS (out); + SET_4_OBJECTS (out); + break; + } + + /* This loop governs the asmptoptic behaviour of this algorithm, for long + word copies. */ + count = value >> 5; + for (loop_var = 0; loop_var < count; loop_var++) + SET_32_OBJECTS (out); +} + + +/* Exposed interface. */ + +void +__long_int_memset (void *__restrict s, int c, size_t n) +{ + int ic = (c << 24) + ((char) c << 16) + ((char) c << 8) + (char) c; + __int_memset (s, ic, n); +} + +void +__wrd_memset (void *__restrict s, int c, size_t n) +{ + int sc = ((c << 8) + (char) c); + __short_int_memset (s, sc, n); +} + +void +__byt_memset (void *__restrict s, int c, size_t n) +{ + __byte_memset (s, c, n); +} diff --git a/libgcc/config/visium/memset.h b/libgcc/config/visium/memset.h new file mode 100644 index 0000000..92eb1a3 --- /dev/null +++ b/libgcc/config/visium/memset.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2012-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +/* Specialized variants of memset called directly from compiled code. */ + +extern void +__long_int_memset (void *__restrict s, int c, size_t n); + +extern void +__wrd_memset (void *__restrict s, int c, size_t n); + +extern void +__byt_memset (void *__restrict s, int c, size_t n); diff --git a/libgcc/config/visium/moddi3.c b/libgcc/config/visium/moddi3.c new file mode 100644 index 0000000..bf7a63f --- /dev/null +++ b/libgcc/config/visium/moddi3.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_moddi3 +#include "lib2funcs.c" diff --git a/libgcc/config/visium/set_trampoline_parity.c b/libgcc/config/visium/set_trampoline_parity.c new file mode 100644 index 0000000..134cf2b --- /dev/null +++ b/libgcc/config/visium/set_trampoline_parity.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_set_trampoline_parity +#include "lib2funcs.c" diff --git a/libgcc/config/visium/t-visium b/libgcc/config/visium/t-visium new file mode 100644 index 0000000..ea59762 --- /dev/null +++ b/libgcc/config/visium/t-visium @@ -0,0 +1,29 @@ +# Copyright (C) 2003-2015 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 +# <http://www.gnu.org/licenses/>. + +LIB2FUNCS_EXCLUDE += _divdi3 _moddi3 _udivdi3 _umoddi3 _udivmoddi4 + +LIB2ADD += \ + $(srcdir)/config/visium/divdi3.c \ + $(srcdir)/config/visium/moddi3.c \ + $(srcdir)/config/visium/udivdi3.c \ + $(srcdir)/config/visium/umoddi3.c \ + $(srcdir)/config/visium/udivmoddi4.c \ + $(srcdir)/config/visium/memcpy.c \ + $(srcdir)/config/visium/memset.c \ + $(srcdir)/config/visium/set_trampoline_parity.c diff --git a/libgcc/config/visium/udivdi3.c b/libgcc/config/visium/udivdi3.c new file mode 100644 index 0000000..c595251 --- /dev/null +++ b/libgcc/config/visium/udivdi3.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_udivdi3 +#include "lib2funcs.c" diff --git a/libgcc/config/visium/udivmoddi4.c b/libgcc/config/visium/udivmoddi4.c new file mode 100644 index 0000000..bd45a5c --- /dev/null +++ b/libgcc/config/visium/udivmoddi4.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_udivmoddi4 +#include "lib2funcs.c" diff --git a/libgcc/config/visium/umoddi3.c b/libgcc/config/visium/umoddi3.c new file mode 100644 index 0000000..cd2b23e --- /dev/null +++ b/libgcc/config/visium/umoddi3.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2014-2015 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#define L_umoddi3 +#include "lib2funcs.c" |