configure.ac: Add Visium support.
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 6 Jan 2015 08:50:12 +0000 (08:50 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Tue, 6 Jan 2015 08:50:12 +0000 (08:50 +0000)
* configure.ac: Add Visium support.
* configure: Regenerate.
libgcc/
* config.host: Add Visium support.
* config/visium: New directory.
gcc/
* 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.
gcc/testsuite/
* 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.

From-SVN: r219219

48 files changed:
ChangeLog
configure
configure.ac
gcc/ChangeLog
gcc/common/config/visium/visium-common.c [new file with mode: 0644]
gcc/config.gcc
gcc/config/visium/constraints.md [new file with mode: 0644]
gcc/config/visium/elf.h [new file with mode: 0644]
gcc/config/visium/gr5.md [new file with mode: 0644]
gcc/config/visium/gr6.md [new file with mode: 0644]
gcc/config/visium/predicates.md [new file with mode: 0644]
gcc/config/visium/t-visium [new file with mode: 0644]
gcc/config/visium/visium-modes.def [new file with mode: 0644]
gcc/config/visium/visium-opts.h [new file with mode: 0644]
gcc/config/visium/visium-protos.h [new file with mode: 0644]
gcc/config/visium/visium.c [new file with mode: 0644]
gcc/config/visium/visium.h [new file with mode: 0644]
gcc/config/visium/visium.md [new file with mode: 0644]
gcc/config/visium/visium.opt [new file with mode: 0644]
gcc/configure
gcc/configure.ac
gcc/doc/extend.texi
gcc/doc/install.texi
gcc/doc/invoke.texi
gcc/doc/md.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/20020312-2.c
gcc/testsuite/gcc.dg/tls/thr-cse-1.c
gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
gcc/testsuite/gcc.dg/tree-ssa/loop-1.c
gcc/testsuite/gcc.dg/weak/typeof-2.c
gcc/testsuite/lib/target-supports.exp
libgcc/ChangeLog
libgcc/config.host
libgcc/config/visium/crti.S [new file with mode: 0644]
libgcc/config/visium/crtn.S [new file with mode: 0644]
libgcc/config/visium/divdi3.c [new file with mode: 0644]
libgcc/config/visium/lib2funcs.c [new file with mode: 0644]
libgcc/config/visium/memcpy.c [new file with mode: 0644]
libgcc/config/visium/memcpy.h [new file with mode: 0644]
libgcc/config/visium/memset.c [new file with mode: 0644]
libgcc/config/visium/memset.h [new file with mode: 0644]
libgcc/config/visium/moddi3.c [new file with mode: 0644]
libgcc/config/visium/set_trampoline_parity.c [new file with mode: 0644]
libgcc/config/visium/t-visium [new file with mode: 0644]
libgcc/config/visium/udivdi3.c [new file with mode: 0644]
libgcc/config/visium/udivmoddi4.c [new file with mode: 0644]
libgcc/config/visium/umoddi3.c [new file with mode: 0644]

index da50e84fa5fa9798d9937533aae99b2879a91fe0..f5834a66180aff9221ac22244b8952eed5978f4e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
index 168e7fed10ccfec9aaf83360f4b4f902dde4c3d8..a69a64d2486f84633f1022b0687ce280b04c90fc 100755 (executable)
--- a/configure
+++ b/configure
@@ -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.
index 720502686c98e01455849bd6dbc3d050df14f3f7..7c51079aa6adfc8dad5ff7f7b1f6666b75b60691 100644 (file)
@@ -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.
index 12c2f939fe662e014962844e870cc2756f0d045c..812f980938b9fbe6204e8a4d02b9e82848bff0b8 100644 (file)
@@ -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 (file)
index 0000000..ce4541c
--- /dev/null
@@ -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;
index 878dbcc31d1ae241961127b638ec197dbe1c1212..857b3b0bc952a8a723d992861d6886b4cff5ef9e 100644 (file)
@@ -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 (file)
index 0000000..93900e8
--- /dev/null
@@ -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 (file)
index 0000000..713773d
--- /dev/null
@@ -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 (file)
index 0000000..9880b4d
--- /dev/null
@@ -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 (file)
index 0000000..3129045
--- /dev/null
@@ -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 (file)
index 0000000..66d282e
--- /dev/null
@@ -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 (file)
index 0000000..e06141c
--- /dev/null
@@ -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 (file)
index 0000000..8aa30d6
--- /dev/null
@@ -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 (file)
index 0000000..b438d52
--- /dev/null
@@ -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 (file)
index 0000000..5f36f28
--- /dev/null
@@ -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 (file)
index 0000000..c8efd15
--- /dev/null
@@ -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 (file)
index 0000000..d78e221
--- /dev/null
@@ -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 (file)
index 0000000..969cb88
--- /dev/null
@@ -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 (file)
index 0000000..75c166e
--- /dev/null
@@ -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
index b589a2a4806f08b7b31a87f0b5d16d4488ca03f1..8670f730cef07e09a06763a8a11910311e327bc8 100755 (executable)
@@ -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)
index 0169823fd7f54f2cbfcc61bbfd273a65d17f2a06..d0101415cca94e3c592e07b96ccd1e61902e48bd 100644 (file)
@@ -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)
index f68cd7f62854e6f3748caa70280b8427aa13dd7e..25226824043dd404ec030b335880a59268991cf1 100644 (file)
@@ -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.
index 1e05310e7fc7262b583fc4a9d304c96cc23487ff..94e039d09a18d6920c294002ec8dcdef9c73d6ef 100644 (file)
@@ -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-*-*}
@@ -4647,6 +4649,14 @@ port requires binutils-2.23 or newer.
 The TILEPro processor running GNU/Linux.  This port requires
 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
index c42898cd6018328ab7a009f4f3393daa771e6460..2e587f5d8423563850c9f0f274895000e036e513 100644 (file)
@@ -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
 
index 48bd4825c32ede44fd391bc77b6190de31404160..934ed236c653af8effdc3efb7ca0e121d2e7b2d1 100644 (file)
@@ -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
index cac2f79d40aa08aff6f06a9899be2de0bfab23f7..cbd491cc49de9bf39bc78526e298f8dcba0fa4db 100644 (file)
@@ -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
index de217412af5c2d12802518a14a7bbd3cb8df0078..71201fee26bc4b106bce50118130c748b16c9723 100644 (file)
@@ -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__)
index 8e64424b72a4d40163432d1666a1a16b3645ae98..da2fbff96a97d6c608fd4e1d4fdfe8ce8e4e5668 100644 (file)
@@ -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-*-* } } } */
index 2793336a5cbe22cdfd0b04958b9fa35e32fb4c08..42f6a4cc646879891fb3a7605e883d6d0bece06d 100644 (file)
@@ -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" } } */
index dd52c50faf4d9f82d83699e801848a7ba79381f4..f63c8a7ab6a7925c7bedc5d0f542d69345cf81e3 100644 (file)
@@ -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-*-* } } } */
index 45a12ebf918986ed29cbae92074e8e2e565fd6b4..d4273e361b75365d07ef04f830983fc27af4c92c 100644 (file)
@@ -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" } }
index e335913e914c222c6050aa32b1d74f8c3a4784b2..119d2c578d417d32cd7157399c97bd3926e51203 100644 (file)
@@ -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
     }
index 55fb239dc8285c53dbd3cbd5671e9a77e516cbd0..241747f9562866472787bb42fe82b5703842b058 100644 (file)
@@ -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.
index e0db9f9d206e87a1518b5eb92bfcfe9d471e66e0..667eb312a66cb81c6450506f6b6215061d7b0aa3 100644 (file)
@@ -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 (file)
index 0000000..158ae0f
--- /dev/null
@@ -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 (file)
index 0000000..a60f4de
--- /dev/null
@@ -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 (file)
index 0000000..38b747a
--- /dev/null
@@ -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 (file)
index 0000000..ba720a3
--- /dev/null
@@ -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")
+\f
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+     defined (L_umoddi3) || defined (L_moddi3))
+#define L_udivmoddi4
+#endif
+\f
+#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
+\f
+#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
+\f
+#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 (file)
index 0000000..21efdd0
--- /dev/null
@@ -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 (file)
index 0000000..5df8176
--- /dev/null
@@ -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 (file)
index 0000000..5f81679
--- /dev/null
@@ -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 (file)
index 0000000..92eb1a3
--- /dev/null
@@ -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 (file)
index 0000000..bf7a63f
--- /dev/null
@@ -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 (file)
index 0000000..134cf2b
--- /dev/null
@@ -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 (file)
index 0000000..ea59762
--- /dev/null
@@ -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 (file)
index 0000000..c595251
--- /dev/null
@@ -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 (file)
index 0000000..bd45a5c
--- /dev/null
@@ -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 (file)
index 0000000..cd2b23e
--- /dev/null
@@ -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"