summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-06 08:50:12 +0000
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-06 08:50:12 +0000
commit8992df51cbb8c833d37770b28547b157523a92b7 (patch)
tree0edeb5eefb9376aad7c7391332316f9d2fd7e437
parent8173baf5feae49224e485ad85a5f34d468be531f (diff)
downloadgcc-8992df51cbb8c833d37770b28547b157523a92b7.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@219219 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog5
-rwxr-xr-xconfigure4
-rw-r--r--configure.ac4
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/common/config/visium/visium-common.c38
-rw-r--r--gcc/config.gcc4
-rw-r--r--gcc/config/visium/constraints.md83
-rw-r--r--gcc/config/visium/elf.h25
-rw-r--r--gcc/config/visium/gr5.md145
-rw-r--r--gcc/config/visium/gr6.md186
-rw-r--r--gcc/config/visium/predicates.md157
-rw-r--r--gcc/config/visium/t-visium21
-rw-r--r--gcc/config/visium/visium-modes.def37
-rw-r--r--gcc/config/visium/visium-opts.h30
-rw-r--r--gcc/config/visium/visium-protos.h66
-rw-r--r--gcc/config/visium/visium.c4085
-rw-r--r--gcc/config/visium/visium.h1739
-rw-r--r--gcc/config/visium/visium.md2749
-rw-r--r--gcc/config/visium/visium.opt82
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/doc/extend.texi11
-rw-r--r--gcc/doc/install.texi10
-rw-r--r--gcc/doc/invoke.texi76
-rw-r--r--gcc/doc/md.texi50
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/gcc.dg/20020312-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/tls/thr-cse-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/loop-1.c3
-rw-r--r--gcc/testsuite/gcc.dg/weak/typeof-2.c2
-rw-r--r--gcc/testsuite/lib/target-supports.exp6
-rw-r--r--libgcc/ChangeLog5
-rw-r--r--libgcc/config.host4
-rw-r--r--libgcc/config/visium/crti.S46
-rw-r--r--libgcc/config/visium/crtn.S40
-rw-r--r--libgcc/config/visium/divdi3.c25
-rw-r--r--libgcc/config/visium/lib2funcs.c323
-rw-r--r--libgcc/config/visium/memcpy.c862
-rw-r--r--libgcc/config/visium/memcpy.h33
-rw-r--r--libgcc/config/visium/memset.c664
-rw-r--r--libgcc/config/visium/memset.h33
-rw-r--r--libgcc/config/visium/moddi3.c25
-rw-r--r--libgcc/config/visium/set_trampoline_parity.c25
-rw-r--r--libgcc/config/visium/t-visium29
-rw-r--r--libgcc/config/visium/udivdi3.c25
-rw-r--r--libgcc/config/visium/udivmoddi4.c25
-rw-r--r--libgcc/config/visium/umoddi3.c25
48 files changed, 11829 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index da50e84fa5f..f5834a66180 100644
--- 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.
diff --git a/configure b/configure
index 168e7fed10c..a69a64d2486 100755
--- 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.
diff --git a/configure.ac b/configure.ac
index 720502686c9..7c51079aa6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -667,6 +667,10 @@ case "${target}" in
# for explicit misaligned loads.
noconfigdirs="$noconfigdirs target-libssp"
;;
+ visium-*-*)
+ # No hosted I/O support.
+ noconfigdirs="$noconfigdirs target-libssp"
+ ;;
esac
# Disable libstdc++-v3 for some systems.
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 12c2f939fe6..812f980938b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2015-01-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * config.gcc: Add Visium support.
+ * configure.ac: Likewise.
+ * configure: Regenerate.
+ * doc/extend.texi (interrupt attribute): Add Visium.
+ * doc/invoke.texi: Document Visium options.
+ * doc/install.texi: Document Visium target.
+ * doc/md.texi: Document Visium constraints.
+ * common/config/visium: New directory.
+ * config/visium: Likewise.
+
2015-01-05 Segher Boessenkool <segher@kernel.crashing.org>
* simplify-rtx.c (simplify_binary_operation_1): Handle more cases
diff --git a/gcc/common/config/visium/visium-common.c b/gcc/common/config/visium/visium-common.c
new file mode 100644
index 00000000000..ce4541cd321
--- /dev/null
+++ b/gcc/common/config/visium/visium-common.c
@@ -0,0 +1,38 @@
+/* Common hooks for Visium.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ Contributed by C.Nettleton,J.P.Parkes and P.Garbett.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+
+/* Set default optimization options. */
+static const struct default_options visium_option_optimization_table[] =
+ {
+ { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE visium_option_optimization_table
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 878dbcc31d1..857b3b0bc95 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -2888,6 +2888,10 @@ vax-*-openbsd*)
extra_options="${extra_options} openbsd.opt"
use_collect2=yes
;;
+visium-*-elf*)
+ tm_file="dbxelf.h elfos.h ${tm_file} visium/elf.h newlib-stdint.h"
+ tmake_file="visium/t-visium visium/t-crtstuff"
+ ;;
xstormy16-*-elf)
# For historical reasons, the target files omit the 'x'.
tm_file="dbxelf.h elfos.h newlib-stdint.h stormy16/stormy16.h"
diff --git a/gcc/config/visium/constraints.md b/gcc/config/visium/constraints.md
new file mode 100644
index 00000000000..93900e89c33
--- /dev/null
+++ b/gcc/config/visium/constraints.md
@@ -0,0 +1,83 @@
+;; Constraint definitions for Visium.
+;; Copyright (C) 2006-2015 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; Register constraints
+
+(define_register_constraint "b" "MDB"
+ "EAM register mdb")
+
+(define_register_constraint "c" "MDC"
+ "EAM register mdc")
+
+(define_register_constraint "f" "TARGET_FPU ? FP_REGS : NO_REGS"
+ "Floating point register")
+
+(define_register_constraint "k" "SIBCALL_REGS"
+ "Register for sibcall optimization")
+
+(define_register_constraint "l" "LOW_REGS"
+ "General register, but not r29, r30 and r31")
+
+(define_register_constraint "t" "R1"
+ "Register r1")
+
+(define_register_constraint "u" "R2"
+ "Register r2")
+
+(define_register_constraint "v" "R3"
+ "Register r3")
+
+;; Immediate integer operand constraints
+
+(define_constraint "J"
+ "Integer constant in the range 0 .. 65535 (16-bit immediate)"
+ (and (match_code "const_int")
+ (match_test "0 <= ival && ival <= 65535")))
+
+(define_constraint "K"
+ "Integer constant in the range 1 .. 31 (5-bit immediate)"
+ (and (match_code "const_int")
+ (match_test "1 <= ival && ival <= 31")))
+
+(define_constraint "L"
+ "Integer constant in the range -65535 .. -1 (16-bit negative immediate)"
+ (and (match_code "const_int")
+ (match_test "-65535 <= ival && ival <= -1")))
+
+(define_constraint "M"
+ "Integer constant -1"
+ (and (match_code "const_int")
+ (match_test "ival == -1")))
+
+(define_constraint "O"
+ "Integer constant 0"
+ (and (match_code "const_int")
+ (match_test "ival == 0")))
+
+(define_constraint "P"
+ "Integer constant 32"
+ (and (match_code "const_int")
+ (match_test "ival == 32")))
+
+;; Immediate FP operand constraints
+
+(define_constraint "G"
+ "Floating-point constant 0.0"
+ (and (match_code "const_double")
+ (match_test "op == CONST0_RTX (mode)")))
diff --git a/gcc/config/visium/elf.h b/gcc/config/visium/elf.h
new file mode 100644
index 00000000000..713773daacc
--- /dev/null
+++ b/gcc/config/visium/elf.h
@@ -0,0 +1,25 @@
+/* ELF-specific defines for Visium.
+ Copyright (C) 2005-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Turn on DWARF-2 frame unwinding. */
+#define INCOMING_FRAME_SP_OFFSET 0
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGNUM)
+#define DWARF_FRAME_REGNUM(REGNO) (REGNO)
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGNUM)
diff --git a/gcc/config/visium/gr5.md b/gcc/config/visium/gr5.md
new file mode 100644
index 00000000000..9880b4d9beb
--- /dev/null
+++ b/gcc/config/visium/gr5.md
@@ -0,0 +1,145 @@
+;; Scheduling description for GR5.
+;; Copyright (C) 2013-2015 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; GR5 is a single-issue processor.
+
+;; CPU execution units:
+;;
+;; issue Only one instruction can be issued on a given cycle.
+;; There is no need to model the CPU pipeline in any
+;; more detail than this.
+;;
+;; mem Memory Unit: all accesses to memory.
+;;
+;; eam Extended Arithmetic Module: multiply, divide and
+;; 64-bit shifts.
+;;
+;; fp_slot[0|1|2|3] The 4 FIFO slots of the floating-point unit. Only
+;; the instruction at slot 0 can execute, but an FP
+;; instruction can issue if any of the slots is free.
+
+(define_automaton "gr5,gr5_fpu")
+
+(define_cpu_unit "gr5_issue" "gr5")
+(define_cpu_unit "gr5_mem" "gr5")
+(define_cpu_unit "gr5_eam" "gr5")
+(define_cpu_unit "gr5_fp_slot0,gr5_fp_slot1,gr5_fp_slot2,gr5_fp_slot3" "gr5_fpu")
+
+;; The CPU instructions which write to general registers and so do not totally
+;; complete until they reach the store stage of the pipeline. This is not the
+;; complete storage register class: mem_reg, eam_reg and fpu_reg are excluded
+;; since we must keep the reservation sets non-overlapping.
+(define_insn_reservation "gr5_storage_register" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "imm_reg,arith,arith2,logic,call"))
+ "gr5_issue")
+
+(define_insn_reservation "gr5_read_mem" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "mem_reg"))
+ "gr5_issue + gr5_mem")
+
+;; The latency of 2 and the reservation of gr5_mem on the second cycle ensures
+;; that no reads will be scheduled on the second cycle, which would otherwise
+;; stall the pipeline for 1 cycle.
+(define_insn_reservation "gr5_write_mem" 2
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "reg_mem"))
+ "gr5_issue, gr5_mem")
+
+;; Try to avoid the pipeline hazard of addressing off a register that has
+;; not yet been stored.
+(define_bypass 2 "gr5_storage_register" "gr5_read_mem" "gr5_hazard_bypass_p")
+(define_bypass 2 "gr5_storage_register" "gr5_write_mem" "gr5_hazard_bypass_p")
+(define_bypass 2 "gr5_read_mem" "gr5_read_mem" "gr5_hazard_bypass_p")
+(define_bypass 2 "gr5_read_mem" "gr5_write_mem" "gr5_hazard_bypass_p")
+
+;; Other CPU instructions complete by the process stage.
+(define_insn_reservation "gr5_cpu_other" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "abs_branch,branch,cmp,ret,rfi,dsi,nop"))
+ "gr5_issue")
+
+;; EAM instructions.
+
+(define_insn_reservation "gr5_write_eam" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "reg_eam"))
+ "gr5_issue")
+
+(define_reservation "gr5_issue_eam" "(gr5_issue + gr5_eam)")
+
+(define_insn_reservation "gr5_read_eam" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "eam_reg"))
+ "gr5_issue_eam")
+
+;; Try to avoid the pipeline hazard of addressing off a register that has
+;; not yet been stored.
+(define_bypass 2 "gr5_read_eam" "gr5_read_mem" "gr5_hazard_bypass_p")
+(define_bypass 2 "gr5_read_eam" "gr5_write_mem" "gr5_hazard_bypass_p")
+
+(define_insn_reservation "gr5_shiftdi" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "shiftdi"))
+ "gr5_issue_eam")
+
+(define_insn_reservation "gr5_mul" 3
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "mul"))
+ "gr5_issue_eam, gr5_eam*2")
+
+(define_insn_reservation "gr5_div" 34
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "div"))
+ "gr5_issue_eam, gr5_eam*33")
+
+(define_insn_reservation "gr5_divd" 66
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "divd"))
+ "gr5_issue_eam, gr5_eam*65")
+
+;; FPU instructions.
+
+(define_reservation "gr5_fp_slotany" "(gr5_fp_slot0 | gr5_fp_slot1 | gr5_fp_slot2 | gr5_fp_slot3)")
+
+(define_insn_reservation "gr5_fp_other" 1
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "fp_reg,reg_fp,fcmp"))
+ "gr5_issue")
+
+(define_insn_reservation "gr5_fp_1cycle" 2
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "fmove,ftoi"))
+ "gr5_issue + gr5_fp_slotany, gr5_fp_slot0")
+
+(define_insn_reservation "gr5_fp_2cycle" 3
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "itof"))
+ "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*2")
+
+(define_insn_reservation "gr5_fp_3cycle" 4
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "fp"))
+ "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*3")
+
+(define_insn_reservation "gr5_fp_30cycle" 31
+ (and (eq_attr "cpu" "gr5")
+ (eq_attr "type" "fdiv,fsqrt"))
+ "gr5_issue + gr5_fp_slotany, gr5_fp_slot0*30")
diff --git a/gcc/config/visium/gr6.md b/gcc/config/visium/gr6.md
new file mode 100644
index 00000000000..3129045af18
--- /dev/null
+++ b/gcc/config/visium/gr6.md
@@ -0,0 +1,186 @@
+;; Scheduling description for GR6.
+;; Copyright (C) 2013-2015 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; GR6 is a dual-issue, superscalar, out-of-order processor.
+;;
+;; The GR6 pipeline has 3 major components:
+;; 1. The FETCH/DECODE/DISPATCH stages, an in-order front-end,
+;; 2. The PROCESS stage, which is the out-of-order core,
+;; 3. The STORE stage, an in-order register storage stage.
+;;
+;; The front-end and the back-end (PROCESS + STORE) are connected through a set
+;; of reservation stations which, among other things, serve as buffers for the
+;; decoded instructions. The reservation stations are attached to a specific
+;; execution unit of the PROCESS stage and the DISPATCH stage is responsible
+;; for dispatching the decoded instructions to the appropriate stations. Most
+;; execution units have multiple reservation stations, thus making it possible
+;; to dispatch two instructions per unit on a given cycle, but only one of them
+;; can be executed on the next cycle.
+;;
+;; Since the core executes the instructions out of order, the most important
+;; consideration for performance tuning is to make sure that enough decoded
+;; instructions are ready for execution in the PROCESS stage while not stalling
+;; the front-end, i.e while not trying to dispatch a decoded instruction to an
+;; execution unit whose reservation stations are full. Therefore, we do not
+;; model the reservation stations (which is equivalent to pretending that there
+;; is only one of them for each execution unit) but only the execution unit,
+;; thus preserving some margin in case the unit itself stalls unexpectedly.
+
+;; CPU execution units:
+;;
+;; inst[1|2] The front-end: 2 instructions can be issued on a given
+;; cycle by the FETCH/DECODE/DISPATCH stages, except for
+;; the Block Move instructions.
+;;
+;; mov Move Execution Unit: immediate moves into registers.
+;;
+;; alu[1|2] The 2 Arithmetic and Logic Units: other instructions
+;; operating on the registers.
+;;
+;; bru Branch Resolution Unit: all branches.
+;;
+;; mem_wr Memory Write Unit: all writes to memory.
+;;
+;; mem_rd Memory Read Unit: all reads from memory.
+;;
+;; mem_eam EAM interface: reads and writes from and to the EAM
+;; and reads from the FP registers.
+;;
+;; eam Extended Arithmetic Module: multiply, divide and
+;; 64-bit shifts.
+;;
+;; fpcu Floating-Point Compare Unit: FP comparisons.
+;;
+;; fpu[1|2|3|4] The 4 Floating-Point Units: all other instructions
+;; operating on the FP registers.
+
+(define_automaton "gr6,gr6_fpu")
+
+(define_cpu_unit "gr6_inst1, gr6_inst2" "gr6")
+(define_cpu_unit "gr6_mov" "gr6")
+(define_cpu_unit "gr6_alu1,gr6_alu2" "gr6")
+(define_cpu_unit "gr6_bru" "gr6")
+(define_cpu_unit "gr6_mem_wr,gr6_mem_rd,gr6_mem_eam" "gr6")
+(define_cpu_unit "gr6_eam" "gr6")
+(define_cpu_unit "gr6_fpcu" "gr6")
+(define_cpu_unit "gr6_fpu1,gr6_fpu2,gr6_fpu3,gr6_fpu4" "gr6_fpu")
+
+(define_reservation "gr6_issue" "(gr6_inst1 | gr6_inst2)")
+(define_reservation "gr6_single_issue" "gr6_inst1 + gr6_inst2")
+
+(define_insn_reservation "gr6_immediate" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "imm_reg"))
+ "gr6_issue + gr6_mov")
+
+(define_insn_reservation "gr6_alu" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "arith,arith2,logic,cmp"))
+ "gr6_issue + (gr6_alu1 | gr6_alu2)")
+
+(define_insn_reservation "gr6_branch" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "abs_branch,branch,call,ret,rfi"))
+ "gr6_issue + gr6_bru")
+
+(define_insn_reservation "gr6_block_move" 16
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "bmi"))
+ "gr6_single_issue*16")
+
+(define_insn_reservation "gr6_cpu_other" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "dsi,nop"))
+ "gr6_issue")
+
+(define_insn_reservation "gr6_write_mem" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "reg_mem"))
+ "gr6_issue + gr6_mem_wr")
+
+(define_insn_reservation "gr6_read_mem" 6
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "mem_reg"))
+ "gr6_issue + gr6_mem_rd, nothing*5")
+
+;; EAM instructions.
+
+(define_insn_reservation "gr6_write_eam" 2
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "reg_eam"))
+ "gr6_issue + gr6_mem_eam, nothing")
+
+(define_reservation "gr6_issue_eam" "gr6_issue + gr6_mem_eam + gr6_eam")
+
+(define_insn_reservation "gr6_read_eam" 2
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "eam_reg"))
+ "gr6_issue_eam, nothing")
+
+(define_insn_reservation "gr6_shiftdi" 2
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "shiftdi"))
+ "gr6_issue_eam, gr6_eam")
+
+(define_insn_reservation "gr6_mul" 3
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "mul"))
+ "gr6_issue_eam, gr6_eam*2")
+
+(define_insn_reservation "gr6_div" 34
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "div"))
+ "gr6_issue_eam, gr6_eam*33")
+
+(define_insn_reservation "gr6_divd" 66
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "divd"))
+ "gr6_issue_eam, gr6_eam*65")
+
+;; FPU instructions.
+
+(define_insn_reservation "gr6_read_fp" 2
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "fp_reg"))
+ "gr6_issue + gr6_mem_eam, nothing")
+
+(define_insn_reservation "gr6_cmp_fp" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "fcmp"))
+ "gr6_issue + gr6_fpcu")
+
+(define_insn_reservation "gr6_fp_1cycle" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "fmove,ftoi,itof"))
+ "gr6_issue + gr6_fpu1")
+
+(define_insn_reservation "gr6_fp_3cycle" 3
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "fp"))
+ "gr6_issue + gr6_fpu2, nothing*2")
+
+(define_insn_reservation "gr6_fp_17cycle" 17
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "fdiv,fsqrt"))
+ "gr6_issue + gr6_fpu3, gr6_fpu3*14, nothing*2")
+
+(define_insn_reservation "gr6_write_fp" 1
+ (and (eq_attr "cpu" "gr6")
+ (eq_attr "type" "reg_fp"))
+ "gr6_issue + gr6_fpu4")
diff --git a/gcc/config/visium/predicates.md b/gcc/config/visium/predicates.md
new file mode 100644
index 00000000000..66d282ea1ce
--- /dev/null
+++ b/gcc/config/visium/predicates.md
@@ -0,0 +1,157 @@
+;; Predicate definitions for Visium.
+;; Copyright (C) 2005-2015 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; Return true if OP is the constant 0.
+(define_predicate "const0_operand"
+ (and (match_code "const_int,const_double")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Return true if OP is a constant in the range 1 .. 31.
+(define_predicate "const_shift_operand"
+ (and (match_code "const_int")
+ (match_test "1 <= INTVAL (op) && INTVAL (op) <= 31")))
+
+;; Return true if OP is either a register or the constant 0.
+(define_predicate "reg_or_0_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "const0_operand")))
+
+;; Return true if OP is either a register or a constant in the range 1 .. 31.
+(define_predicate "reg_or_shift_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "const_shift_operand")))
+
+;; Return true if OP is either a register or the constant 32.
+(define_predicate "reg_or_32_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) == 32"))))
+
+;; Return true if OP is a general register.
+(define_predicate "gpc_reg_operand"
+ (match_operand 0 "register_operand")
+{
+ if (GET_CODE (op) == SUBREG)
+ {
+ op = SUBREG_REG (op);
+ if (GET_CODE (op) != REG)
+ return 1;
+ }
+
+ unsigned int regno = REGNO (op);
+ return (regno >= FIRST_PSEUDO_REGISTER
+ || TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], regno));
+})
+
+;; Return true if OP is the MDB register.
+(define_predicate "mdb_reg_operand"
+ (match_operand 0 "register_operand")
+{
+ unsigned int regno = reg_or_subreg_regno (op);
+ return (regno == MDB_REGNUM);
+})
+
+;; Return true if OP is the MDC register.
+(define_predicate "mdc_reg_operand"
+ (match_operand 0 "register_operand")
+{
+ unsigned int regno = reg_or_subreg_regno (op);
+ return (regno == MDC_REGNUM);
+})
+
+;; Return true if OP is an rvalue which is not an EAM register.
+(define_predicate "non_eam_src_operand"
+ (match_operand 0 "general_operand")
+{
+ unsigned int regno = reg_or_subreg_regno (op);
+ return (regno != MDB_REGNUM && regno != MDC_REGNUM);
+})
+
+;; Return true if OP is an lvalue which is not an EAM register.
+(define_predicate "non_eam_dst_operand"
+ (match_operand 0 "nonimmediate_operand")
+{
+ unsigned int regno = reg_or_subreg_regno (op);
+ return (regno != MDB_REGNUM && regno != MDC_REGNUM);
+})
+
+;; Return true if OP is a floating-point register.
+(define_predicate "fp_reg_operand"
+ (match_code "reg")
+{
+ unsigned int regno = REGNO (op);
+ return (regno >= FIRST_PSEUDO_REGISTER || FP_REGISTER_P (regno));
+})
+
+;; Return true if OP is a floating-point register or the constant 0.
+(define_predicate "fp_reg_or_0_operand"
+ (ior (match_operand 0 "fp_reg_operand")
+ (match_operand 0 "const0_operand")))
+
+;; Return true if OP can be used as the second operand in a 32-bit or 64-bit
+;; add or subtract instruction. Note that adding a negative constant may be
+;; transformed into subtracting a positive constant, and vice versa.
+(define_predicate "add_operand"
+ (ior (match_operand 0 "gpc_reg_operand")
+ (and (match_code "const_int")
+ (match_test ("INTVAL (op) >= -65535 && INTVAL (op) <= 65535")))))
+
+;; Return true if OP is (or could be) outside the range 0 .. 65535, which is
+;; the range of the immediate operands, but accept -1 for NOT.
+(define_predicate "large_immediate_operand"
+ (ior (match_code "const,label_ref,symbol_ref")
+ (and (match_code "const_int")
+ (match_test ("INTVAL (op) < -1 || INTVAL (op) > 65535")))))
+
+;; Return true if OP is a valid FP comparison operator.
+(define_predicate "visium_fp_comparison_operator"
+ (match_code "eq,ne,ordered,unordered,unlt,unle,ungt,unge,lt,le,gt,ge"))
+
+;; Return true if OP is a valid comparison operator for CC_BTSTmode.
+(define_special_predicate "visium_btst_operator"
+ (match_code "eq,ne"))
+
+;; Return true if OP is a valid comparison operator for CC_NOOVmode.
+(define_special_predicate "visium_noov_operator"
+ (match_code "eq,ne,ge,lt"))
+
+;; Return true if OP is a valid comparison operator for a branch. This allows
+;; the use of MATCH_OPERATOR to recognize all the branch insns.
+(define_predicate "visium_branch_operator"
+ (match_operand 0 "comparison_operator")
+{
+ enum rtx_code code = GET_CODE (op);
+ /* These 2 comparison codes are not supported. */
+ if (code == UNEQ || code == LTGT)
+ return false;
+ enum machine_mode cc_mode = GET_MODE (XEXP (op, 0));
+ if (cc_mode == CC_NOOVmode)
+ return visium_noov_operator (op, mode);
+ if (cc_mode == CC_BTSTmode)
+ return visium_btst_operator (op, mode);
+ return true;
+})
+
+;; Return true if OP is a valid comparison operator for an integer cstore.
+(define_predicate "visium_int_cstore_operator"
+ (match_code "eq,ne,ltu,gtu,leu,geu"))
+
+;; Return true if OP is a valid comparison operator for an FP cstore.
+(define_predicate "visium_fp_cstore_operator"
+ (match_code "lt,gt,unge,unle"))
diff --git a/gcc/config/visium/t-visium b/gcc/config/visium/t-visium
new file mode 100644
index 00000000000..e06141c349b
--- /dev/null
+++ b/gcc/config/visium/t-visium
@@ -0,0 +1,21 @@
+# Multilibs for Visium.
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+MULTILIB_OPTIONS = mcpu=gr6
+MULTILIB_DIRNAMES = gr6
diff --git a/gcc/config/visium/visium-modes.def b/gcc/config/visium/visium-modes.def
new file mode 100644
index 00000000000..8aa30d6201e
--- /dev/null
+++ b/gcc/config/visium/visium-modes.def
@@ -0,0 +1,37 @@
+/* Machine description for Visium.
+ Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Add any extra modes needed to represent the condition code.
+
+ On the Visium, we have a "no-overflow" mode which is used when arithmetic
+ instructions set the condition code. Different branches are used in this
+ case for some operations.
+
+ We also have a "bit-test" mode which is used when the bit-test instruction
+ sets the condition code.
+
+ We also have two modes to indicate that the condition code is set by the
+ the floating-point unit. One for comparisons which generate an exception
+ if the result is unordered (CCFPEmode) and one for comparisons which never
+ generate such an exception (CCFPmode). */
+
+CC_MODE (CC_NOOV);
+CC_MODE (CC_BTST);
+CC_MODE (CCFP);
+CC_MODE (CCFPE);
diff --git a/gcc/config/visium/visium-opts.h b/gcc/config/visium/visium-opts.h
new file mode 100644
index 00000000000..b438d520ab7
--- /dev/null
+++ b/gcc/config/visium/visium-opts.h
@@ -0,0 +1,30 @@
+/* Definitions for option handling for Visium.
+ Copyright (C) 2005-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef VISIUM_OPTS_H
+#define VISIUM_OPTS_H
+
+/* Processor type.
+ These must match the values for the cpu attribute in visium.md. */
+enum processor_type {
+ PROCESSOR_GR5,
+ PROCESSOR_GR6
+};
+
+#endif
diff --git a/gcc/config/visium/visium-protos.h b/gcc/config/visium/visium-protos.h
new file mode 100644
index 00000000000..5f36f285f31
--- /dev/null
+++ b/gcc/config/visium/visium-protos.h
@@ -0,0 +1,66 @@
+/* Prototypes of target machine for Visium.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ Contributed by C.Nettleton,J.P.Parkes and P.Garbett.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_VISIUM_PROTOS_H
+#define GCC_VISIUM_PROTOS_H
+
+extern unsigned int visium_data_alignment (tree, unsigned int);
+extern void visium_init_expanders (void);
+extern int visium_interrupt_function_p (void);
+extern bool visium_can_use_return_insn_p (void);
+extern void visium_expand_prologue (void);
+extern void visium_expand_epilogue (void);
+extern int visium_epilogue_uses (int);
+extern void visium_profile_hook (void);
+extern int visium_hard_regno_rename_ok (unsigned int, unsigned int);
+extern int visium_initial_elimination_offset (int from, int to);
+#ifdef RTX_CODE
+extern void prepare_move_operands (rtx *, enum machine_mode);
+extern bool ok_for_simple_move_operands (rtx *, enum machine_mode);
+extern bool ok_for_simple_move_strict_operands (rtx *, enum machine_mode);
+extern bool ok_for_simple_arith_logic_operands (rtx *, enum machine_mode);
+extern void visium_initialize_trampoline (rtx, rtx, rtx);
+extern int empty_delay_slot (rtx_insn *);
+extern int gr5_hazard_bypass_p (rtx_insn *, rtx_insn *);
+extern rtx visium_return_addr_rtx (int, rtx);
+extern rtx visium_eh_return_handler_rtx (void);
+extern rtx visium_dynamic_chain_address (rtx);
+extern rtx visium_legitimize_reload_address (rtx, enum machine_mode, int, int,
+ int);
+extern enum machine_mode visium_select_cc_mode (enum rtx_code, rtx, rtx);
+extern void visium_split_cbranch (enum rtx_code, rtx, rtx, rtx);
+extern const char *output_ubranch (rtx, rtx_insn *);
+extern const char *output_cbranch (rtx, enum rtx_code, enum machine_mode, int,
+ rtx_insn *);
+extern void notice_update_cc (rtx, rtx);
+extern void print_operand (FILE *, rtx, int);
+extern void print_operand_address (FILE *, rtx);
+extern void split_double_move (rtx *, enum machine_mode);
+extern void visium_expand_copysign (rtx *, enum machine_mode);
+extern void visium_expand_int_cstore (rtx *, enum machine_mode);
+extern void visium_expand_fp_cstore (rtx *, enum machine_mode);
+extern void visium_split_cstore (enum rtx_code, rtx, rtx,
+ enum rtx_code, rtx, rtx);
+extern int visium_expand_block_move (rtx *);
+extern int visium_expand_block_set (rtx *);
+extern unsigned int reg_or_subreg_regno (rtx);
+#endif /* RTX_CODE */
+
+#endif
diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c
new file mode 100644
index 00000000000..c8efd154286
--- /dev/null
+++ b/gcc/config/visium/visium.c
@@ -0,0 +1,4085 @@
+/* Output routines for Visium.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "calls.h"
+#include "varasm.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "expr.h"
+#include "function.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "tm_p.h"
+#include "ggc.h"
+#include "optabs.h"
+#include "target.h"
+#include "target-def.h"
+#include "common/common-target.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+#include "langhooks.h"
+#include "reload.h"
+#include "tm-constrs.h"
+#include "df.h"
+#include "params.h"
+#include "errors.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "builtins.h"
+
+/* Machine specific function data. */
+struct GTY (()) machine_function
+{
+ /* Size of the frame of the function. */
+ int frame_size;
+
+ /* Size of the reg parm save area, non-zero only for functions with variable
+ argument list. We cannot use the crtl->args.pretend_args_size machinery
+ for this purpose because this size is added to virtual_incoming_args_rtx
+ to give the location of the first parameter passed by the caller on the
+ stack and virtual_incoming_args_rtx is also the location of the first
+ parameter on the stack. So crtl->args.pretend_args_size can be non-zero
+ only if the first non-register named parameter is not passed entirely on
+ the stack and this runs afoul of the need to have a reg parm save area
+ even with a variable argument list starting on the stack because of the
+ separate handling of general and floating-point registers. */
+ int reg_parm_save_area_size;
+
+ /* True if we have created an rtx which relies on the frame pointer. */
+ bool frame_needed;
+
+ /* True if we have exposed the flags register. From this moment on, we
+ cannot generate simple operations for integer registers. We could
+ use reload_completed for this purpose, but this would cripple the
+ postreload CSE and GCSE passes which run before postreload split. */
+ bool flags_exposed;
+};
+
+#define visium_frame_size cfun->machine->frame_size
+#define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
+#define visium_frame_needed cfun->machine->frame_needed
+#define visium_flags_exposed cfun->machine->flags_exposed
+
+/* 1 if the next opcode is to be specially indented. */
+int visium_indent_opcode = 0;
+
+/* Register number used for long branches when LR isn't available. It
+ must be a call-used register since it isn't saved on function entry.
+ We do not care whether the branch is predicted or not on the GR6,
+ given how unlikely it is to have a long branch in a leaf function. */
+static unsigned int long_branch_regnum = 31;
+
+static void visium_output_address (FILE *, enum machine_mode, rtx);
+static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
+static inline bool current_function_saves_fp (void);
+static inline bool current_function_saves_lr (void);
+static inline bool current_function_has_lr_slot (void);
+
+/* Supported attributes:
+ interrupt -- specifies this function is an interrupt handler. */
+static const struct attribute_spec visium_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
+ {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
+ {NULL, 0, 0, false, false, false, NULL, false}
+};
+
+static struct machine_function *visium_init_machine_status (void);
+
+/* Target hooks and TARGET_INITIALIZER */
+
+static bool visium_pass_by_reference (cumulative_args_t, enum machine_mode,
+ const_tree, bool);
+
+static rtx visium_function_arg (cumulative_args_t, enum machine_mode,
+ const_tree, bool);
+
+static void visium_function_arg_advance (cumulative_args_t, enum machine_mode,
+ const_tree, bool);
+
+static bool visium_return_in_memory (const_tree, const_tree fntype);
+
+static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
+ bool);
+
+static rtx visium_libcall_value (enum machine_mode, const_rtx);
+
+static void visium_setup_incoming_varargs (cumulative_args_t,
+ enum machine_mode,
+ tree, int *, int);
+
+static void visium_va_start (tree valist, rtx nextarg);
+
+static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
+
+static bool visium_function_ok_for_sibcall (tree, tree);
+
+static bool visium_frame_pointer_required (void);
+
+static tree visium_build_builtin_va_list (void);
+
+static tree visium_md_asm_clobbers (tree, tree, tree);
+
+static bool visium_legitimate_constant_p (enum machine_mode, rtx);
+
+static bool visium_legitimate_address_p (enum machine_mode, rtx, bool);
+
+static void visium_conditional_register_usage (void);
+
+static rtx visium_legitimize_address (rtx, rtx, enum machine_mode);
+
+static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
+ enum machine_mode,
+ secondary_reload_info *);
+
+static bool visium_class_likely_spilled_p (reg_class_t);
+
+static void visium_trampoline_init (rtx, tree, rtx);
+
+static int visium_issue_rate (void);
+
+static int visium_adjust_priority (rtx_insn *, int);
+
+static int visium_adjust_cost (rtx_insn *, rtx, rtx_insn *, int);
+
+static int visium_register_move_cost (enum machine_mode, reg_class_t,
+ reg_class_t);
+
+static int visium_memory_move_cost (enum machine_mode, reg_class_t, bool);
+
+static bool visium_rtx_costs (rtx, int, int, int, int *, bool);
+
+static void visium_option_override (void);
+
+static unsigned int visium_reorg (void);
+
+/* Setup the global target hooks structure. */
+
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET 31
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG visium_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY visium_return_in_memory
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE visium_function_value
+
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE visium_libcall_value
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
+
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
+
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
+
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE visium_attribute_table
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
+
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
+
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE visium_issue_rate
+
+#undef TARGET_SCHED_ADJUST_PRIORITY
+#define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST visium_adjust_cost
+
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
+
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST visium_register_move_cost
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS visium_rtx_costs
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
+
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD visium_secondary_reload
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE visium_option_override
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT visium_trampoline_init
+
+#undef TARGET_MD_ASM_CLOBBERS
+#define TARGET_MD_ASM_CLOBBERS visium_md_asm_clobbers
+
+#undef TARGET_FLAGS_REGNUM
+#define TARGET_FLAGS_REGNUM FLAGS_REGNUM
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+namespace {
+
+const pass_data pass_data_visium_reorg =
+{
+ RTL_PASS, /* type */
+ "mach2", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_MACH_DEP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_visium_reorg : public rtl_opt_pass
+{
+public:
+ pass_visium_reorg(gcc::context *ctxt)
+ : rtl_opt_pass(pass_data_visium_reorg, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *)
+ {
+ return visium_reorg ();
+ }
+
+}; // class pass_work_around_errata
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_visium_reorg (gcc::context *ctxt)
+{
+ return new pass_visium_reorg (ctxt);
+}
+
+/* Options override for Visium. */
+
+static void
+visium_option_override (void)
+{
+ if (flag_pic == 1)
+ warning (OPT_fpic, "-fpic is not supported");
+ if (flag_pic == 2)
+ warning (OPT_fPIC, "-fPIC is not supported");
+
+ /* MCM is the default in the GR5/GR6 era. */
+ target_flags |= MASK_MCM;
+
+ /* FPU is the default with MCM, but don't override an explicit option. */
+ if ((target_flags_explicit & MASK_FPU) == 0)
+ target_flags |= MASK_FPU;
+
+ /* The supervisor mode is the default. */
+ if ((target_flags_explicit & MASK_SV_MODE) == 0)
+ target_flags |= MASK_SV_MODE;
+
+ /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
+ if (visium_cpu_and_features == PROCESSOR_GR6)
+ {
+ target_flags |= MASK_BMI;
+ if (target_flags & MASK_FPU)
+ target_flags |= MASK_FPU_IEEE;
+ }
+
+ /* Set -mtune from -mcpu if not specified. */
+ if (!global_options_set.x_visium_cpu)
+ visium_cpu = visium_cpu_and_features;
+
+ /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
+ boundaries for GR6 so they start a new burst mode window. */
+ if (align_functions == 0)
+ {
+ if (visium_cpu == PROCESSOR_GR6)
+ align_functions = 64;
+ else
+ align_functions = 256;
+
+ /* Allow the size of compilation units to double because of inlining.
+ In practice the global size of the object code is hardly affected
+ because the additional instructions will take up the padding. */
+ maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
+ global_options.x_param_values,
+ global_options_set.x_param_values);
+ }
+
+ /* Likewise for loops. */
+ if (align_loops == 0)
+ {
+ if (visium_cpu == PROCESSOR_GR6)
+ align_loops = 64;
+ else
+ {
+ align_loops = 256;
+ /* But not if they are too far away from a 256-byte boundary. */
+ align_loops_max_skip = 31;
+ }
+ }
+
+ /* Align all jumps on quadword boundaries for the burst mode, and even
+ on 8-quadword boundaries for GR6 so they start a new window. */
+ if (align_jumps == 0)
+ {
+ if (visium_cpu == PROCESSOR_GR6)
+ align_jumps = 64;
+ else
+ align_jumps = 8;
+ }
+
+ /* We register a machine-specific pass. This pass must be scheduled as
+ late as possible so that we have the (essentially) final form of the
+ insn stream to work on. Registering the pass must be done at start up.
+ It's convenient to do it here. */
+ opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
+ struct register_pass_info insert_pass_visium_reorg =
+ {
+ visium_reorg_pass, /* pass */
+ "dbr", /* reference_pass_name */
+ 1, /* ref_pass_instance_number */
+ PASS_POS_INSERT_AFTER /* po_op */
+ };
+ register_pass (&insert_pass_visium_reorg);
+}
+
+/* Return the number of instructions that can issue on the same cycle. */
+
+static int
+visium_issue_rate (void)
+{
+ switch (visium_cpu)
+ {
+ case PROCESSOR_GR5:
+ return 1;
+
+ case PROCESSOR_GR6:
+ return 2;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the adjusted PRIORITY of INSN. */
+
+static int
+visium_adjust_priority (rtx_insn *insn, int priority)
+{
+ /* On the GR5, we slightly increase the priority of writes in order to avoid
+ scheduling a read on the next cycle. This is necessary in addition to the
+ associated insn reservation because there are no data dependencies.
+ We also slightly increase the priority of reads from ROM in order to group
+ them as much as possible. These reads are a bit problematic because they
+ conflict with the instruction fetches, i.e. the data and instruction buses
+ tread on each other's toes when they are executed. */
+ if (visium_cpu == PROCESSOR_GR5
+ && reload_completed
+ && INSN_P (insn)
+ && recog_memoized (insn) >= 0)
+ {
+ enum attr_type attr_type = get_attr_type (insn);
+ if (attr_type == TYPE_REG_MEM
+ || (attr_type == TYPE_MEM_REG
+ && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
+ return priority + 1;
+ }
+
+ return priority;
+}
+
+/* Adjust the cost of a scheduling dependency. Return the new cost of
+ a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
+
+static int
+visium_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost)
+{
+ enum attr_type attr_type;
+
+ /* Don't adjust costs for true dependencies as they are described with
+ bypasses. But we make an exception for the first scheduling pass to
+ help the subsequent postreload compare elimination pass. */
+ if (REG_NOTE_KIND (link) == REG_DEP_TRUE)
+ {
+ if (!reload_completed
+ && recog_memoized (insn) >= 0
+ && get_attr_type (insn) == TYPE_CMP)
+ {
+ rtx pat = PATTERN (insn);
+ gcc_assert (GET_CODE (pat) == SET);
+ rtx src = SET_SRC (pat);
+
+ /* Only the branches can be modified by the postreload compare
+ elimination pass, not the cstores because they accept only
+ unsigned comparison operators and they are eliminated if
+ one of the operands is zero. */
+ if (GET_CODE (src) == IF_THEN_ELSE
+ && XEXP (XEXP (src, 0), 1) == const0_rtx
+ && recog_memoized (dep_insn) >= 0)
+ {
+ enum attr_type dep_attr_type = get_attr_type (dep_insn);
+
+ /* The logical instructions use CCmode and thus work with any
+ comparison operator, whereas the arithmetic instructions use
+ CC_NOOVmode and thus work with only a small subset. */
+ if (dep_attr_type == TYPE_LOGIC
+ || (dep_attr_type == TYPE_ARITH
+ && visium_noov_operator (XEXP (src, 0),
+ GET_MODE (XEXP (src, 0)))))
+ return 0;
+ }
+ }
+
+ return cost;
+ }
+
+ if (recog_memoized (insn) < 0)
+ return 0;
+
+ attr_type = get_attr_type (insn);
+
+ /* Anti dependency: DEP_INSN reads a register that INSN writes some
+ cycles later. */
+ if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
+ {
+ /* On the GR5, the latency of FP instructions needs to be taken into
+ account for every dependency involving a write. */
+ if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
+ {
+ /* INSN is FLOAD. */
+ rtx pat = PATTERN (insn);
+ rtx dep_pat = PATTERN (dep_insn);
+
+ if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+ /* If this happens, we have to extend this to schedule
+ optimally. Return 0 for now. */
+ return 0;
+
+ if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
+ {
+ if (recog_memoized (dep_insn) < 0)
+ return 0;
+
+ switch (get_attr_type (dep_insn))
+ {
+ case TYPE_FDIV:
+ case TYPE_FSQRT:
+ case TYPE_FTOI:
+ case TYPE_ITOF:
+ case TYPE_FP:
+ case TYPE_FMOVE:
+ /* A fload can't be issued until a preceding arithmetic
+ operation has finished if the target of the fload is
+ any of the sources (or destination) of the arithmetic
+ operation. Note that the latency may be (much)
+ greater than this if the preceding instruction
+ concerned is in a queue. */
+ return insn_default_latency (dep_insn);
+
+ default:
+ return 0;
+ }
+ }
+ }
+
+ /* On the GR6, we try to make sure that the link register is restored
+ sufficiently ahead of the return as to yield a correct prediction
+ from the branch predictor. By default there is no true dependency
+ but an anti dependency between them, so we simply reuse it. */
+ else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
+ {
+ rtx dep_pat = PATTERN (dep_insn);
+ if (GET_CODE (dep_pat) == SET
+ && REG_P (SET_DEST (dep_pat))
+ && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
+ return 8;
+ }
+
+ /* For other anti dependencies, the cost is 0. */
+ return 0;
+ }
+
+ /* Output dependency: DEP_INSN writes a register that INSN writes some
+ cycles later. */
+ else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+ {
+ /* On the GR5, the latency of FP instructions needs to be taken into
+ account for every dependency involving a write. */
+ if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
+ {
+ /* INSN is FLOAD. */
+ rtx pat = PATTERN (insn);
+ rtx dep_pat = PATTERN (dep_insn);
+
+ if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+ /* If this happens, we have to extend this to schedule
+ optimally. Return 0 for now. */
+ return 0;
+
+ if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
+ {
+ if (recog_memoized (dep_insn) < 0)
+ return 0;
+
+ switch (get_attr_type (dep_insn))
+ {
+ case TYPE_FDIV:
+ case TYPE_FSQRT:
+ case TYPE_FTOI:
+ case TYPE_ITOF:
+ case TYPE_FP:
+ case TYPE_FMOVE:
+ /* A fload can't be issued until a preceding arithmetic
+ operation has finished if the target of the fload is
+ the destination of the arithmetic operation. Note that
+ the latency may be (much) greater than this if the
+ preceding instruction concerned is in a queue. */
+ return insn_default_latency (dep_insn);
+
+ default:
+ return 0;
+ }
+ }
+ }
+
+ /* For other output dependencies, the cost is 0. */
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Handle an "interrupt_handler" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+visium_handle_interrupt_attr (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (!TARGET_SV_MODE)
+ {
+ error ("an interrupt handler cannot be compiled with -muser-mode");
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Return non-zero if the current function is an interrupt function. */
+
+int
+visium_interrupt_function_p (void)
+{
+ return
+ lookup_attribute ("interrupt",
+ DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
+}
+
+/* Conditionally modify the settings of the register file. */
+
+static void
+visium_conditional_register_usage (void)
+{
+ /* If the supervisor mode is disabled, mask some general registers. */
+ if (!TARGET_SV_MODE)
+ {
+ if (visium_cpu_and_features == PROCESSOR_GR5)
+ {
+ fixed_regs[24] = call_used_regs[24] = 1;
+ fixed_regs[25] = call_used_regs[25] = 1;
+ fixed_regs[26] = call_used_regs[26] = 1;
+ fixed_regs[27] = call_used_regs[27] = 1;
+ fixed_regs[28] = call_used_regs[28] = 1;
+ call_really_used_regs[24] = 0;
+ call_really_used_regs[25] = 0;
+ call_really_used_regs[26] = 0;
+ call_really_used_regs[27] = 0;
+ call_really_used_regs[28] = 0;
+ }
+
+ fixed_regs[31] = call_used_regs[31] = 1;
+ call_really_used_regs[31] = 0;
+
+ /* We also need to change the long-branch register. */
+ if (visium_cpu_and_features == PROCESSOR_GR5)
+ long_branch_regnum = 20;
+ else
+ long_branch_regnum = 28;
+ }
+
+ /* If the FPU is disabled, mask the FP registers. */
+ if (!TARGET_FPU)
+ {
+ for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
+ {
+ fixed_regs[i] = call_used_regs[i] = 1;
+ call_really_used_regs[i] = 0;
+ }
+ }
+}
+
+/* Prepend to CLOBBERS hard registers that are automatically clobbered for
+ an asm We do this for the FLAGS to maintain source compatibility with
+ the original cc0-based compiler. */
+
+static tree
+visium_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
+ tree inputs ATTRIBUTE_UNUSED,
+ tree clobbers)
+{
+ const char *flags = reg_names[FLAGS_REGNUM];
+ return tree_cons (NULL_TREE, build_string (strlen (flags), flags), clobbers);
+}
+
+/* Return true if X is a legitimate constant for a MODE immediate operand.
+ X is guaranteed to satisfy the CONSTANT_P predicate. */
+
+static bool
+visium_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+/* Compute the alignment for a variable. The alignment of an aggregate is
+ set to be at least that of a scalar less than or equal to it in size. */
+
+unsigned int
+visium_data_alignment (tree type, unsigned int align)
+{
+ if (AGGREGATE_TYPE_P (type)
+ && TYPE_SIZE (type)
+ && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
+ {
+ if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
+ return 32;
+
+ if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
+ return 16;
+ }
+
+ return align;
+}
+
+/* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
+ it is OK to rename a hard register FROM to another hard register TO. */
+
+int
+visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
+ unsigned int to)
+{
+ /* If the function doesn't save LR, then the long-branch register will be
+ used for long branches so we need to know whether it is live before the
+ frame layout is computed. */
+ if (!current_function_saves_lr () && to == long_branch_regnum)
+ return 0;
+
+ /* Interrupt functions can only use registers that have already been
+ saved by the prologue, even if they would normally be call-clobbered. */
+ if (crtl->is_leaf
+ && !df_regs_ever_live_p (to)
+ && visium_interrupt_function_p ())
+ return 0;
+
+ return 1;
+}
+
+/* Return true if it is ok to do sibling call optimization for the specified
+ call expression EXP. DECL will be the called function, or NULL if this
+ is an indirect call. */
+
+static bool
+visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
+ tree exp ATTRIBUTE_UNUSED)
+{
+ return !visium_interrupt_function_p ();
+}
+
+/* Prepare operands for a move define_expand in MODE. */
+
+void
+prepare_move_operands (rtx *operands, enum machine_mode mode)
+{
+ /* If the output is not a register, the input must be. */
+ if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
+ operands[1] = force_reg (mode, operands[1]);
+}
+
+/* Return true if the operands are valid for a simple move insn. */
+
+bool
+ok_for_simple_move_operands (rtx *operands, enum machine_mode mode)
+{
+ /* One of the operands must be a register. */
+ if (!register_operand (operands[0], mode)
+ && !reg_or_0_operand (operands[1], mode))
+ return false;
+
+ /* Once the flags are exposed, no simple moves between integer registers. */
+ if (visium_flags_exposed
+ && gpc_reg_operand (operands[0], mode)
+ && gpc_reg_operand (operands[1], mode))
+ return false;
+
+ return true;
+}
+
+/* Return true if the operands are valid for a simple move strict insn. */
+
+bool
+ok_for_simple_move_strict_operands (rtx *operands, enum machine_mode mode)
+{
+ /* Once the flags are exposed, no simple moves between integer registers.
+ Note that, in QImode only, a zero source counts as an integer register
+ since it will be emitted as r0. */
+ if (visium_flags_exposed
+ && gpc_reg_operand (operands[0], mode)
+ && (gpc_reg_operand (operands[1], mode)
+ || (mode == QImode && operands[1] == const0_rtx)))
+ return false;
+
+ return true;
+}
+
+/* Return true if the operands are valid for a simple arithmetic or logical
+ insn. */
+
+bool
+ok_for_simple_arith_logic_operands (rtx *, enum machine_mode)
+{
+ /* Once the flags are exposed, no simple arithmetic or logical operations
+ between integer registers. */
+ return !visium_flags_exposed;
+}
+
+/* Return non-zero if a branch or call instruction will be emitting a nop
+ into its delay slot. */
+
+int
+empty_delay_slot (rtx_insn *insn)
+{
+ rtx seq;
+
+ /* If no previous instruction (should not happen), return true. */
+ if (PREV_INSN (insn) == NULL)
+ return 1;
+
+ seq = NEXT_INSN (PREV_INSN (insn));
+ if (GET_CODE (PATTERN (seq)) == SEQUENCE)
+ return 0;
+
+ return 1;
+}
+
+/* Wrapper around single_set which returns the first SET of a pair if the
+ second SET is to the flags register. */
+
+static rtx
+single_set_and_flags (rtx_insn *insn)
+{
+ if (multiple_sets (insn))
+ {
+ rtx pat = PATTERN (insn);
+ if (XVECLEN (pat, 0) == 2
+ && GET_CODE (XVECEXP (pat, 0, 1)) == SET
+ && REG_P (SET_DEST (XVECEXP (pat, 0, 1)))
+ && REGNO (SET_DEST (XVECEXP (pat, 0, 1))) == FLAGS_REGNUM)
+ return XVECEXP (pat, 0, 0);
+ }
+
+ return single_set (insn);
+}
+
+/* This is called with OUT_INSN an instruction setting a (base) register
+ and IN_INSN a read or a write. Return 1 if these instructions together
+ constitute a pipeline hazard.
+
+ On the original architecture, a pipeline data hazard occurs when the Dest
+ of one instruction becomes the SrcA for an immediately following READ or
+ WRITE instruction with a non-zero index (indexing occurs at the decode
+ stage and so a NOP must be inserted in-between for this to work).
+
+ An example is:
+
+ move.l r2,r1
+ read.l r4,10(r2)
+
+ On the MCM, the non-zero index condition is lifted but the hazard is
+ patched up by the hardware through the injection of wait states:
+
+ move.l r2,r1
+ read.l r4,(r2)
+
+ We nevertheless try to schedule instructions around this. */
+
+int
+gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
+{
+ rtx out_set, in_set, dest, memexpr;
+ unsigned int out_reg, in_reg;
+
+ /* A CALL is storage register class, but the link register is of no
+ interest here. */
+ if (GET_CODE (out_insn) == CALL_INSN)
+ return 0;
+
+ out_set = single_set_and_flags (out_insn);
+ dest = SET_DEST (out_set);
+
+ /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
+ occurs prior to reload. */
+ if (GET_CODE (dest) == MEM)
+ return 0;
+
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+ out_reg = REGNO (dest);
+
+ in_set = single_set_and_flags (in_insn);
+
+ /* If IN_INSN is MEM := MEM, it's the source that counts. */
+ if (GET_CODE (SET_SRC (in_set)) == MEM)
+ memexpr = XEXP (SET_SRC (in_set), 0);
+ else
+ memexpr = XEXP (SET_DEST (in_set), 0);
+
+ if (GET_CODE (memexpr) == PLUS)
+ {
+ memexpr = XEXP (memexpr, 0);
+ if (GET_CODE (memexpr) == SUBREG)
+ in_reg = REGNO (SUBREG_REG (memexpr));
+ else
+ in_reg = REGNO (memexpr);
+
+ if (in_reg == out_reg)
+ return 1;
+ }
+ else if (TARGET_MCM)
+ {
+ if (GET_CODE (memexpr) == STRICT_LOW_PART)
+ memexpr = XEXP (memexpr, 0);
+ if (GET_CODE (memexpr) == SUBREG)
+ memexpr = SUBREG_REG (memexpr);
+ in_reg = REGNO (memexpr);
+
+ if (in_reg == out_reg)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return true if INSN is an empty asm instruction. */
+
+static bool
+empty_asm_p (rtx insn)
+{
+ rtx body = PATTERN (insn);
+ const char *templ;
+
+ if (GET_CODE (body) == ASM_INPUT)
+ templ = XSTR (body, 0);
+ else if (asm_noperands (body) >= 0)
+ templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+ else
+ templ = NULL;
+
+ return (templ && templ[0] == '\0');
+}
+
+/* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
+ LAST_REG records the register set in the last insn and LAST_INSN_CALL
+ records whether the last insn was a call insn. */
+
+static void
+gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
+{
+ unsigned int dest_reg = 0;
+ rtx set;
+
+ switch (GET_CODE (insn))
+ {
+ case CALL_INSN:
+ *last_reg = 0;
+ *last_insn_call = true;
+ return;
+
+ case JUMP_INSN:
+ /* If this is an empty asm, just skip it. */
+ if (!empty_asm_p (insn))
+ {
+ *last_reg = 0;
+ *last_insn_call = false;
+ }
+ return;
+
+ case INSN:
+ /* If this is an empty asm, just skip it. */
+ if (empty_asm_p (insn))
+ return;
+ break;
+
+ default:
+ return;
+ }
+
+ set = single_set_and_flags (insn);
+ if (set != NULL_RTX)
+ {
+ rtx dest = SET_DEST (set);
+ const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
+ rtx memrtx = NULL;
+
+ if (GET_CODE (SET_SRC (set)) == MEM)
+ {
+ memrtx = XEXP (SET_SRC (set), 0);
+ if (GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+ if (REG_P (dest))
+ dest_reg = REGNO (dest);
+
+ /* If this is a DI or DF mode memory to register
+ copy, then if rd = rs we get
+
+ rs + 1 := 1[rs]
+ rs := [rs]
+
+ otherwise the order is
+
+ rd := [rs]
+ rd + 1 := 1[rs] */
+
+ if (double_p)
+ {
+ unsigned int base_reg;
+
+ if (GET_CODE (memrtx) == PLUS)
+ base_reg = REGNO (XEXP (memrtx, 0));
+ else
+ base_reg = REGNO (memrtx);
+
+ if (dest_reg != base_reg)
+ dest_reg++;
+ }
+ }
+
+ else if (GET_CODE (dest) == MEM)
+ memrtx = XEXP (dest, 0);
+
+ else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
+ {
+ if (GET_CODE (dest) == STRICT_LOW_PART
+ ||GET_CODE (dest) == ZERO_EXTRACT)
+ dest = XEXP (dest, 0);
+ dest_reg = REGNO (dest);
+
+ if (GET_CODE (SET_SRC (set)) == REG)
+ {
+ unsigned int srcreg = REGNO (SET_SRC (set));
+
+ /* Check for rs := rs, which will be deleted. */
+ if (srcreg == dest_reg)
+ return;
+
+ /* In the case of a DI or DF mode move from register to
+ register there is overlap if rd = rs + 1 in which case
+ the order of the copies is reversed :
+
+ rd + 1 := rs + 1;
+ rd := rs */
+
+ if (double_p && dest_reg != srcreg + 1)
+ dest_reg++;
+ }
+ }
+
+ /* If this is the delay slot of a call insn, any register it sets
+ is not relevant. */
+ if (*last_insn_call)
+ dest_reg = 0;
+
+ /* If the previous insn sets the value of a register, and this insn
+ uses a base register, check for the pipeline hazard where it is
+ the same register in each case. */
+ if (*last_reg != 0 && memrtx != NULL_RTX)
+ {
+ unsigned int reg = 0;
+
+ /* Check for an index (original architecture). */
+ if (GET_CODE (memrtx) == PLUS)
+ reg = REGNO (XEXP (memrtx, 0));
+
+ /* Check for an MCM target or rs := [rs], in DI or DF mode. */
+ else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
+ reg = REGNO (memrtx);
+
+ /* Remove any pipeline hazard by inserting a NOP. */
+ if (reg == *last_reg)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "inserting nop before insn %d\n", INSN_UID (insn));
+ emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
+ emit_insn_after (gen_blockage (), insn);
+ }
+ }
+
+ *last_reg = dest_reg;
+ }
+
+ *last_insn_call = false;
+}
+
+/* Go through the instruction stream and insert nops where necessary to avoid
+ pipeline hazards. There are two cases:
+
+ 1. On the original architecture, it is invalid to set the value of a
+ (base) register and then use it in an address with a non-zero index
+ in the next instruction.
+
+ 2. On the MCM, setting the value of a (base) register and then using
+ it in address (including with zero index) in the next instruction
+ will result in a pipeline stall of 3 cycles. */
+
+static void
+gr5_hazard_avoidance (void)
+{
+ unsigned int last_reg = 0;
+ bool last_insn_call = false;
+ rtx_insn *insn;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ {
+ rtx pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == SEQUENCE)
+ {
+ for (int i = 0; i < XVECLEN (pat, 0); i++)
+ gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
+ &last_reg, &last_insn_call);
+ }
+
+ else if (GET_CODE (insn) == CALL_INSN)
+ {
+ /* This call is going to get a nop in its delay slot. */
+ last_reg = 0;
+ last_insn_call = false;
+ }
+
+ else
+ gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
+ }
+
+ else if (GET_CODE (insn) == BARRIER)
+ last_reg = 0;
+}
+
+/* Perform a target-specific pass over the instruction stream. The compiler
+ will run it at all optimization levels, just after the point at which it
+ normally does delayed-branch scheduling. */
+
+static unsigned int
+visium_reorg (void)
+{
+ if (visium_cpu == PROCESSOR_GR5)
+ gr5_hazard_avoidance ();
+
+ return 0;
+}
+/* Return true if an argument must be passed by indirect reference. */
+
+static bool
+visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
+}
+
+/* Define how arguments are passed.
+
+ A range of general registers and floating registers is available
+ for passing arguments. When the class of registers which an
+ argument would normally use is exhausted, that argument, is passed
+ in the overflow region of the stack. No argument is split between
+ registers and stack.
+
+ Arguments of type float or _Complex float go in FP registers if FP
+ hardware is available. If there is no FP hardware, arguments of
+ type float go in general registers. All other arguments are passed
+ in general registers. */
+
+static rtx
+visium_function_arg (cumulative_args_t pcum_v, enum machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
+{
+ int size;
+ CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
+
+ size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ if (mode == VOIDmode)
+ return GEN_INT (0);
+
+ /* Scalar or complex single precision floating point arguments are returned
+ in floating registers. */
+ if (TARGET_FPU
+ && ((GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
+ || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
+ {
+ if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
+ return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
+ else
+ return NULL_RTX;
+ }
+
+ if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
+ return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
+
+ return NULL_RTX;
+}
+
+/* Update the summarizer variable pointed to by PCUM_V to advance past an
+ argument in the argument list. The values MODE, TYPE and NAMED describe
+ that argument. Once this is done, the variable CUM is suitable for
+ analyzing the _following_ argument with visium_function_arg. */
+
+static void
+visium_function_arg_advance (cumulative_args_t pcum_v,
+ enum machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named)
+{
+ int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ int stack_size = 0;
+ CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
+
+ /* Scalar or complex single precision floating point arguments are returned
+ in floating registers. */
+ if (TARGET_FPU
+ && ((GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
+ || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
+ {
+ if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
+ ca->frcount += size;
+ else
+ {
+ stack_size = size;
+ ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
+ }
+ }
+ else
+ {
+ /* Everything else goes in a general register, if enough are
+ available. */
+ if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
+ ca->grcount += size;
+ else
+ {
+ stack_size = size;
+ ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
+ }
+ }
+
+ if (named)
+ ca->stack_words += stack_size;
+}
+
+/* Specify whether to return the return value in memory. */
+
+static bool
+visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
+}
+
+/* Define how scalar values are returned. */
+
+static rtx
+visium_function_value_1 (enum machine_mode mode)
+{
+ /* Scalar or complex single precision floating point values
+ are returned in floating register f1. */
+ if (TARGET_FPU
+ && ((GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
+ || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
+ return gen_rtx_REG (mode, FP_RETURN_REGNUM);
+
+ /* All others are returned in r1. */
+ return gen_rtx_REG (mode, RETURN_REGNUM);
+}
+
+/* Return an RTX representing the place where a function returns or receives
+ a value of data type RET_TYPE. */
+
+static rtx
+visium_function_value (const_tree ret_type,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return visium_function_value_1 (TYPE_MODE (ret_type));
+}
+
+/* Return an RTX representing the place where the library function result will
+ be returned. */
+
+static rtx
+visium_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+ return visium_function_value_1 (mode);
+}
+
+/* Store the anonymous register arguments into the stack so that all the
+ arguments appear to have been passed consecutively on the stack. */
+
+static void
+visium_setup_incoming_varargs (cumulative_args_t pcum_v,
+ enum machine_mode mode,
+ tree type,
+ int *pretend_size ATTRIBUTE_UNUSED,
+ int no_rtl)
+{
+ cumulative_args_t local_args_so_far;
+ CUMULATIVE_ARGS local_copy;
+ CUMULATIVE_ARGS *locargs;
+ int gp_saved, fp_saved, size;
+
+ /* Create an internal cumulative_args_t pointer to internally define
+ storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
+ make global changes. */
+ local_args_so_far.p = &local_copy;
+ locargs = get_cumulative_args (pcum_v);
+
+#ifdef ENABLE_CHECKING
+ local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
+#endif
+
+ local_copy.grcount = locargs->grcount;
+ local_copy.frcount = locargs->frcount;
+ local_copy.stack_words = locargs->stack_words;
+
+ /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
+ argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
+ argument, to find out how many registers are left over. */
+ TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
+
+ /* Find how many registers we need to save. */
+ locargs = get_cumulative_args (local_args_so_far);
+ gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
+ fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
+ size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
+
+ if (!no_rtl && size > 0)
+ {
+ /* To avoid negative offsets, which are not valid addressing modes on
+ the Visium, we create a base register for the pretend args. */
+ rtx ptr
+ = force_reg (Pmode,
+ plus_constant (Pmode, virtual_incoming_args_rtx, -size));
+
+ if (gp_saved > 0)
+ {
+ rtx mem
+ = gen_rtx_MEM (BLKmode,
+ plus_constant (Pmode,
+ ptr,
+ fp_saved * UNITS_PER_HWFPVALUE));
+ MEM_NOTRAP_P (mem) = 1;
+ set_mem_alias_set (mem, get_varargs_alias_set ());
+ move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
+ }
+
+ if (fp_saved > 0)
+ {
+ rtx mem = gen_rtx_MEM (BLKmode, ptr);
+ MEM_NOTRAP_P (mem) = 1;
+ set_mem_alias_set (mem, get_varargs_alias_set ());
+ gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
+ move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
+ }
+ }
+
+ visium_reg_parm_save_area_size = size;
+}
+
+/* Define the `__builtin_va_list' type for the ABI. */
+
+static tree
+visium_build_builtin_va_list (void)
+{
+ tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
+
+ record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__overflow_argptr"), ptr_type_node);
+ f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__gpr_base"), ptr_type_node);
+ f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__fpr_base"), ptr_type_node);
+ f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__gpr_bytes"),
+ short_unsigned_type_node);
+ f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__fpr_bytes"),
+ short_unsigned_type_node);
+
+ DECL_FIELD_CONTEXT (f_ovfl) = record;
+ DECL_FIELD_CONTEXT (f_gbase) = record;
+ DECL_FIELD_CONTEXT (f_fbase) = record;
+ DECL_FIELD_CONTEXT (f_gbytes) = record;
+ DECL_FIELD_CONTEXT (f_fbytes) = record;
+ TYPE_FIELDS (record) = f_ovfl;
+ TREE_CHAIN (f_ovfl) = f_gbase;
+ TREE_CHAIN (f_gbase) = f_fbase;
+ TREE_CHAIN (f_fbase) = f_gbytes;
+ TREE_CHAIN (f_gbytes) = f_fbytes;
+ layout_type (record);
+
+ return record;
+}
+
+/* Implement `va_start' for varargs and stdarg. */
+
+static void
+visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
+{
+ const CUMULATIVE_ARGS *ca = &crtl->args.info;
+ int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
+ int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
+ int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
+ tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
+ tree ovfl, gbase, gbytes, fbase, fbytes, t;
+
+ f_ovfl = TYPE_FIELDS (va_list_type_node);
+ f_gbase = TREE_CHAIN (f_ovfl);
+ f_fbase = TREE_CHAIN (f_gbase);
+ f_gbytes = TREE_CHAIN (f_fbase);
+ f_fbytes = TREE_CHAIN (f_gbytes);
+ ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
+ gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
+ NULL_TREE);
+ fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
+ NULL_TREE);
+ gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
+ NULL_TREE);
+ fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
+ NULL_TREE);
+
+ /* Store the stacked vararg pointer in the OVFL member. */
+ t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
+ t = fold_build_pointer_plus_hwi (t, named_stack_size);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Store the base address of the GPR save area into GBASE. */
+ t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
+ offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
+ t = fold_build_pointer_plus_hwi (t, -offset);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Store the base address of the FPR save area into FBASE. */
+ if (fp_saved)
+ {
+ t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
+ offset = gp_saved * UNITS_PER_WORD
+ + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
+ t = fold_build_pointer_plus_hwi (t, -offset);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
+ /* Fill in the GBYTES member. */
+ t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
+ size_int (gp_saved * UNITS_PER_WORD));
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Fill in the FBYTES member. */
+ t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
+ fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+/* Implement `va_arg'. */
+
+static tree
+visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
+ gimple_seq *post_p)
+{
+ tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
+ tree ovfl, base, bytes;
+ HOST_WIDE_INT size, rsize;
+ const bool by_reference_p
+ = pass_by_reference (NULL, TYPE_MODE (type), type, false);
+ const bool float_reg_arg_p
+ = (TARGET_FPU && !by_reference_p
+ && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
+ && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
+ || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
+ && (GET_MODE_SIZE (TYPE_MODE (type))
+ <= UNITS_PER_HWFPVALUE * 2))));
+ const int max_save_area_size
+ = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
+ : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
+ tree t, u, offs;
+ tree lab_false, lab_over, addr;
+ tree ptrtype = build_pointer_type (type);
+
+ if (by_reference_p)
+ {
+ t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
+ return build_va_arg_indirect_ref (t);
+ }
+
+ size = int_size_in_bytes (type);
+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+ f_ovfl = TYPE_FIELDS (va_list_type_node);
+ f_gbase = TREE_CHAIN (f_ovfl);
+ f_fbase = TREE_CHAIN (f_gbase);
+ f_gbytes = TREE_CHAIN (f_fbase);
+ f_fbytes = TREE_CHAIN (f_gbytes);
+
+ /* We maintain separate pointers and offsets for floating-point and
+ general registers, but we need similar code in both cases.
+
+ Let:
+
+ BYTES be the number of unused bytes in the register save area.
+ BASE be the base address of the register save area.
+ OFFS be the current offset into the register save area. Either
+ MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
+ MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
+ depending upon whether the argument is in general or floating
+ registers.
+ ADDR_RTX be the address of the argument.
+ RSIZE be the size in bytes of the argument.
+ OVFL be the pointer to the stack overflow area.
+
+ The code we want is:
+
+ 1: if (bytes >= rsize)
+ 2: {
+ 3: addr_rtx = base + offs;
+ 4: bytes -= rsize;
+ 5: }
+ 6: else
+ 7: {
+ 8: bytes = 0;
+ 9: addr_rtx = ovfl;
+ 10: ovfl += rsize;
+ 11: }
+
+ */
+
+ addr = create_tmp_var (ptr_type_node, "addr");
+ lab_false = create_artificial_label (UNKNOWN_LOCATION);
+ lab_over = create_artificial_label (UNKNOWN_LOCATION);
+ if (float_reg_arg_p)
+ bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
+ f_fbytes, NULL_TREE);
+ else
+ bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
+ f_gbytes, NULL_TREE);
+
+ /* [1] Emit code to branch if bytes < rsize. */
+ t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
+ t = build2 (LT_EXPR, boolean_type_node, bytes, t);
+ u = build1 (GOTO_EXPR, void_type_node, lab_false);
+ t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
+ gimplify_and_add (t, pre_p);
+
+ /* [3] Emit code for: addr_rtx = base + offs, where
+ offs = max_save_area_size - bytes. */
+ t = fold_convert (sizetype, bytes);
+ offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
+ if (float_reg_arg_p)
+ base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
+ NULL_TREE);
+ else
+ base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
+ NULL_TREE);
+
+ t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
+ t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+ gimplify_and_add (t, pre_p);
+
+ /* [4] Emit code for: bytes -= rsize. */
+ t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
+ t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
+ gimplify_and_add (t, pre_p);
+
+ /* [6] Emit code to branch over the else clause, then the label. */
+ t = build1 (GOTO_EXPR, void_type_node, lab_over);
+ gimplify_and_add (t, pre_p);
+ t = build1 (LABEL_EXPR, void_type_node, lab_false);
+ gimplify_and_add (t, pre_p);
+
+ /* [8] Emit code for: bytes = 0. */
+ t = fold_convert (TREE_TYPE (bytes), size_int (0));
+ t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
+ gimplify_and_add (t, pre_p);
+
+ /* [9] Emit code for: addr_rtx = ovfl. */
+ ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
+ t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
+ gimplify_and_add (t, pre_p);
+
+ /* [10] Emit code for: ovfl += rsize. */
+ t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
+ t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
+ gimplify_and_add (t, pre_p);
+ t = build1 (LABEL_EXPR, void_type_node, lab_over);
+ gimplify_and_add (t, pre_p);
+ addr = fold_convert (ptrtype, addr);
+
+ return build_va_arg_indirect_ref (addr);
+}
+
+/* Return true if OP is an offset suitable for use as a displacement in the
+ address of a memory access in mode MODE. */
+
+static bool
+rtx_ok_for_offset_p (enum machine_mode mode, rtx op)
+{
+ if (!CONST_INT_P (op) || INTVAL (op) < 0)
+ return false;
+
+ switch (mode)
+ {
+ case QImode:
+ return INTVAL (op) <= 31;
+
+ case HImode:
+ return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
+
+ case SImode:
+ case SFmode:
+ return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
+
+ case DImode:
+ case DFmode:
+ return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
+
+ default:
+ return false;
+ }
+}
+
+/* Return whether X is a legitimate memory address for a memory operand
+ of mode MODE.
+
+ Legitimate addresses are defined in two variants: a strict variant
+ and a non-strict one. The STRICT parameter chooses which variant
+ is desired by the caller.
+
+ The strict variant is used in the reload pass. It must be defined
+ so that any pseudo-register that has not been allocated a hard
+ register is considered a memory reference. This is because in
+ contexts where some kind of register is required, a
+ pseudo-register with no hard register must be rejected. For
+ non-hard registers, the strict variant should look up the
+ `reg_renumber' array; it should then proceed using the hard
+ register number in the array, or treat the pseudo as a memory
+ reference if the array holds `-1'.
+
+ The non-strict variant is used in other passes. It must be
+ defined to accept all pseudo-registers in every context where some
+ kind of register is required. */
+
+static bool
+visium_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+ rtx base;
+ unsigned int regno;
+
+ /* If X is base+disp, check that we have an appropriate offset. */
+ if (GET_CODE (x) == PLUS)
+ {
+ if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
+ return false;
+ base = XEXP (x, 0);
+ }
+ else
+ base = x;
+
+ /* Now check the base: it must be either a register or a subreg thereof. */
+ if (GET_CODE (base) == SUBREG)
+ base = SUBREG_REG (base);
+ if (!REG_P (base))
+ return false;
+
+ regno = REGNO (base);
+
+ /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
+ if (strict)
+ return REGNO_OK_FOR_BASE_P (regno);
+
+ /* For the non-strict variant, the register may also be a pseudo. */
+ return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ MODE and WIN are passed so that this macro can use
+ GO_IF_LEGITIMATE_ADDRESS.
+
+ It is always safe for this macro to do nothing. It exists to recognize
+ opportunities to optimize the output.
+
+ For Visium
+
+ memory (reg + <out of range int>)
+
+ is transformed to
+
+ base_int = <out of range int> & ~mask
+ ptr_reg = reg + base_int
+ memory (ptr_reg + <out of range int> - base_int)
+
+ Thus ptr_reg is a base register for a range of addresses,
+ which should help CSE.
+
+ For a 1 byte reference mask is 0x1f
+ for a 2 byte reference mask is 0x3f
+ For a 4 byte reference mask is 0x7f
+
+ This reflects the indexing range of the processor.
+
+ For a > 4 byte reference the mask is 0x7f provided all of the words
+ can be accessed with the base address obtained. Otherwise a mask
+ of 0x3f is used.
+
+ On rare occasions an unaligned base register value with an
+ unaligned offset is generated. Unaligned offsets are left alone for
+ this reason. */
+
+static rtx
+visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
+ {
+ int offset = INTVAL (XEXP (x, 1));
+ int size = GET_MODE_SIZE (mode);
+ int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
+ int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
+ int offset_base = offset & ~mask;
+
+ /* Check that all of the words can be accessed. */
+ if (4 < size && 0x80 < size + offset - offset_base)
+ offset_base = offset & ~0x3f;
+ if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
+ {
+ rtx ptr_reg = force_reg (Pmode,
+ gen_rtx_PLUS (Pmode,
+ XEXP (x, 0),
+ GEN_INT (offset_base)));
+
+ return plus_constant (Pmode, ptr_reg, offset - offset_base);
+ }
+ }
+
+ return x;
+}
+
+/* Perform a similar function to visium_legitimize_address, but this time
+ for reload. Generating new registers is not an option here. Parts
+ that need reloading are indicated by calling push_reload. */
+
+rtx
+visium_legitimize_reload_address (rtx x, enum machine_mode mode, int opnum,
+ int type, int ind ATTRIBUTE_UNUSED)
+{
+ rtx newrtx, tem = NULL_RTX;
+
+ if (mode == BLKmode)
+ return NULL_RTX;
+
+ if (optimize && GET_CODE (x) == PLUS)
+ tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
+ XEXP (x, 1));
+
+ newrtx = tem ? tem : x;
+ if (GET_CODE (newrtx) == PLUS
+ && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
+ && GET_CODE (XEXP (newrtx, 0)) == REG
+ && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
+ {
+ int offset = INTVAL (XEXP (newrtx, 1));
+ int size = GET_MODE_SIZE (mode);
+ int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
+ int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
+ int offset_base = offset & ~mask;
+
+ /* Check that all of the words can be accessed. */
+ if (4 < size && 0x80 < size + offset - offset_base)
+ offset_base = offset & ~0x3f;
+
+ if (offset_base && (offset & mask1) == 0)
+ {
+ rtx temp = gen_rtx_PLUS (Pmode,
+ XEXP (newrtx, 0), GEN_INT (offset_base));
+
+ x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
+ push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
+ (enum reload_type) type);
+ return x;
+ }
+ }
+
+ return NULL_RTX;
+}
+
+/* Return the cost of moving data of mode MODE from a register in class FROM to
+ one in class TO. A value of 2 is the default; other values are interpreted
+ relative to that. */
+
+static int
+visium_register_move_cost (enum machine_mode mode, reg_class_t from,
+ reg_class_t to)
+{
+ const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
+
+ if (from == MDB || to == MDB)
+ return 4;
+ else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
+ return 4 * numwords;
+ else
+ return 2 * numwords;
+}
+
+/* Return the cost of moving data of mode MODE between a register of class
+ CLASS and memory. IN is zero if the value is to be written to memory,
+ non-zero if it is to be read in. This cost is relative to those in
+ visium_register_move_cost. */
+
+static int
+visium_memory_move_cost (enum machine_mode mode,
+ reg_class_t to ATTRIBUTE_UNUSED,
+ bool in)
+{
+ /* Moving data in can be from PROM and this is expensive. */
+ if (in)
+ {
+ if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+ return 7;
+ else
+ return 13;
+ }
+
+ /* Moving data out is mostly to RAM and should be cheaper. */
+ else
+ {
+ if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+ return 6;
+ else
+ return 12;
+ }
+}
+
+/* Return the relative costs of expression X. */
+
+static bool
+visium_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
+ int opno ATTRIBUTE_UNUSED, int *total,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ /* Small integers are as cheap as registers. 4-byte values can
+ be fetched as immediate constants - let's give that the cost
+ of an extra insn. */
+ *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
+ return true;
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (2);
+ return true;
+
+ case CONST_DOUBLE:
+ {
+ rtx high, low;
+ split_double (x, &high, &low);
+ *total =
+ COSTS_N_INSNS
+ (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
+ return true;
+ }
+
+ case MULT:
+ *total = COSTS_N_INSNS (3);
+ return false;
+
+ case DIV:
+ case UDIV:
+ case MOD:
+ case UMOD:
+ if (mode == DImode)
+ *total = COSTS_N_INSNS (64);
+ else
+ *total = COSTS_N_INSNS (32);
+ return false;
+
+ case PLUS:
+ case MINUS:
+ case NEG:
+ /* DImode operations are performed directly on the ALU. */
+ if (mode == DImode)
+ *total = COSTS_N_INSNS (2);
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ /* DImode operations are performed on the EAM instead. */
+ if (mode == DImode)
+ *total = COSTS_N_INSNS (3);
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ case COMPARE:
+ /* This matches the btst pattern. */
+ if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
+ && XEXP (x, 1) == const0_rtx
+ && XEXP (XEXP (x, 0), 1) == const1_rtx
+ && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
+ *total = COSTS_N_INSNS (1);
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+/* Split a double move of OPERANDS in MODE. */
+
+void
+split_double_move (rtx *operands, enum machine_mode mode)
+{
+ bool swap = false;
+
+ /* Check register to register with overlap. */
+ if (GET_CODE (operands[0]) == REG
+ && GET_CODE (operands[1]) == REG
+ && REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ swap = true;
+
+ /* Check memory to register where the base reg overlaps the destination. */
+ if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
+ {
+ rtx op = XEXP (operands[1], 0);
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
+ swap = true;
+
+ if (GET_CODE (op) == PLUS)
+ {
+ rtx x = XEXP (op, 0);
+ rtx y = XEXP (op, 1);
+
+ if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
+ swap = true;
+
+ if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
+ swap = true;
+ }
+ }
+
+ if (swap)
+ {
+ operands[2] = operand_subword (operands[0], 1, 1, mode);
+ operands[3] = operand_subword (operands[1], 1, 1, mode);
+ operands[4] = operand_subword (operands[0], 0, 1, mode);
+ operands[5] = operand_subword (operands[1], 0, 1, mode);
+ }
+ else
+ {
+ operands[2] = operand_subword (operands[0], 0, 1, mode);
+ operands[3] = operand_subword (operands[1], 0, 1, mode);
+ operands[4] = operand_subword (operands[0], 1, 1, mode);
+ operands[5] = operand_subword (operands[1], 1, 1, mode);
+ }
+}
+
+/* Expand a copysign of OPERANDS in MODE. */
+
+void
+visium_expand_copysign (rtx *operands, enum machine_mode mode)
+{
+ rtx dest = operands[0];
+ rtx op0 = operands[1];
+ rtx op1 = operands[2];
+ rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
+ rtx x;
+
+ /* We manually handle SFmode because the abs and neg instructions of
+ the FPU on the MCM have a non-standard behavior wrt NaNs. */
+ gcc_assert (mode == SFmode);
+
+ /* First get all the non-sign bits of OP0. */
+ if (GET_CODE (op0) == CONST_DOUBLE)
+ {
+ if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
+ op0 = simplify_unary_operation (ABS, mode, op0, mode);
+ if (op0 != CONST0_RTX (mode))
+ {
+ long l;
+ REAL_VALUE_TYPE rv;
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op0);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+ op0 = force_reg (SImode, GEN_INT (trunc_int_for_mode (l, SImode)));
+ }
+ }
+ else
+ {
+ op0 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op0));
+ op0 = force_reg (SImode, gen_rtx_AND (SImode, op0, mask));
+ }
+
+ /* Then get the sign bit of OP1. */
+ mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
+ op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
+ op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
+
+ /* Finally OR the two values. */
+ if (op0 == CONST0_RTX (SFmode))
+ x = op1;
+ else
+ x = force_reg (SImode, gen_rtx_IOR (SImode, op0, op1));
+
+ /* And move the result to the destination. */
+ emit_insn (gen_rtx_SET (VOIDmode, dest, gen_lowpart (SFmode, x)));
+}
+
+/* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
+ the result in the C flag and use the ADC/SUBC instructions to write it into
+ the destination register.
+
+ It would also be possible to implement support for LT/GT/LE/GE by means of
+ the RFLAG instruction followed by some shifts, but this can pessimize the
+ generated code. */
+
+void
+visium_expand_int_cstore (rtx *operands, enum machine_mode mode)
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
+ bool reverse = false;
+
+ switch (code)
+ {
+ case EQ:
+ case NE:
+ /* We use a special comparison to get the result in the C flag. */
+ if (op2 != const0_rtx)
+ op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
+ op1 = gen_rtx_NOT (mode, op1);
+ op2 = constm1_rtx;
+ if (code == EQ)
+ reverse = true;
+ break;
+
+ case LEU:
+ case GEU:
+ /* The result is naturally in the C flag modulo a couple of tricks. */
+ code = reverse_condition (code);
+ reverse = true;
+
+ /* ... fall through ... */
+
+ case LTU:
+ case GTU:
+ if (code == GTU)
+ {
+ rtx tmp = op1;
+ op1 = op2;
+ op2 = tmp;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* We need either a single ADC or a SUBC and a PLUS. */
+ sltu = gen_rtx_LTU (SImode, op1, op2);
+
+ if (reverse)
+ {
+ rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
+ emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
+ }
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, op0, sltu));
+}
+
+/* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
+ result in the C flag and use the ADC/SUBC instructions to write it into
+ the destination register. */
+
+void
+visium_expand_fp_cstore (rtx *operands,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
+ bool reverse = false;
+
+ switch (code)
+ {
+ case UNLE:
+ case UNGE:
+ /* The result is naturally in the C flag modulo a couple of tricks. */
+ code = reverse_condition_maybe_unordered (code);
+ reverse = true;
+
+ /* ... fall through ... */
+
+ case LT:
+ case GT:
+ if (code == GT)
+ {
+ rtx tmp = op1;
+ op1 = op2;
+ op2 = tmp;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* We need either a single ADC or a SUBC and a PLUS. */
+ slt = gen_rtx_LT (SImode, op1, op2);
+
+ if (reverse)
+ {
+ rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
+ emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
+ }
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, op0, slt));
+}
+
+/* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
+ operation with OP_CODE, operands OP0 and OP1. */
+
+void
+visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
+ enum rtx_code code, rtx op2, rtx op3)
+{
+ enum machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
+
+ /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
+ if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
+ cc_mode = CCFPmode;
+
+ rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
+ rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
+ switch (op_code)
+ {
+ case SET:
+ break;
+ case NEG:
+ x = gen_rtx_NEG (SImode, x);
+ break;
+ case PLUS:
+ case MINUS:
+ x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
+ XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, op0, x);
+ flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
+ XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
+ emit_insn (pat);
+
+ visium_flags_exposed = true;
+}
+
+/* Generate a call to a library function to move BYTES_RTX bytes from SRC with
+ address SRC_REG to DST with address DST_REG in 4-byte chunks. */
+
+static void
+expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memcpy");
+ unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
+ unsigned int rem = bytes % 4;
+
+ if (TARGET_BMI)
+ {
+ unsigned int i;
+ rtx insn;
+
+ emit_move_insn (regno_reg_rtx[1], dst_reg);
+ emit_move_insn (regno_reg_rtx[2], src_reg);
+ emit_move_insn (regno_reg_rtx[3], bytes_rtx);
+
+ insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
+ XVECEXP (insn, 0, 0)
+ = gen_rtx_SET (VOIDmode,
+ replace_equiv_address_nv (dst, regno_reg_rtx[1]),
+ replace_equiv_address_nv (src, regno_reg_rtx[2]));
+ XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
+ for (i = 1; i <= 6; i++)
+ XVECEXP (insn, 0, 1 + i)
+ = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
+ emit_insn (insn);
+ }
+ else
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
+ Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ GEN_INT (bytes >> 2),
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ if (rem == 0)
+ return;
+
+ dst = replace_equiv_address_nv (dst, dst_reg);
+ src = replace_equiv_address_nv (src, src_reg);
+ bytes -= rem;
+
+ if (rem > 1)
+ {
+ emit_move_insn (adjust_address_nv (dst, HImode, bytes),
+ adjust_address_nv (src, HImode, bytes));
+ bytes += 2;
+ rem -= 2;
+ }
+
+ if (rem > 0)
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes),
+ adjust_address_nv (src, QImode, bytes));
+}
+
+/* Generate a call to a library function to move BYTES_RTX bytes from SRC with
+ address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
+
+static void
+expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memcpy");
+ unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
+ unsigned int rem = bytes % 2;
+
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
+ Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ GEN_INT (bytes >> 1),
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ if (rem == 0)
+ return;
+
+ dst = replace_equiv_address_nv (dst, dst_reg);
+ src = replace_equiv_address_nv (src, src_reg);
+ bytes -= rem;
+
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes),
+ adjust_address_nv (src, QImode, bytes));
+}
+
+/* Generate a call to a library function to move BYTES_RTX bytes from address
+ SRC_REG to address DST_REG in 1-byte chunks. */
+
+static void
+expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memcpy");
+
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
+ src_reg, Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ bytes_rtx,
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+}
+
+/* Generate a call to a library function to set BYTES_RTX bytes of DST with
+ address DST_REG to VALUE_RTX in 4-byte chunks. */
+
+static void
+expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memset");
+ unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
+ unsigned int rem = bytes % 4;
+
+ value_rtx = convert_to_mode (Pmode, value_rtx, 1);
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
+ value_rtx, Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ GEN_INT (bytes >> 2),
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ if (rem == 0)
+ return;
+
+ dst = replace_equiv_address_nv (dst, dst_reg);
+ bytes -= rem;
+
+ if (rem > 1)
+ {
+ if (CONST_INT_P (value_rtx))
+ {
+ const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
+ emit_move_insn (adjust_address_nv (dst, HImode, bytes),
+ gen_int_mode ((value << 8) | value, HImode));
+ }
+ else
+ {
+ rtx temp = convert_to_mode (QImode, value_rtx, 1);
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
+ }
+ bytes += 2;
+ rem -= 2;
+ }
+
+ if (rem > 0)
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes),
+ convert_to_mode (QImode, value_rtx, 1));
+}
+
+/* Generate a call to a library function to set BYTES_RTX bytes of DST with
+ address DST_REG to VALUE_RTX in 2-byte chunks. */
+
+static void
+expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memset");
+ unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
+ unsigned int rem = bytes % 2;
+
+ value_rtx = convert_to_mode (Pmode, value_rtx, 1);
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
+ value_rtx, Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ GEN_INT (bytes >> 1),
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ if (rem == 0)
+ return;
+
+ dst = replace_equiv_address_nv (dst, dst_reg);
+ bytes -= rem;
+
+ emit_move_insn (adjust_address_nv (dst, QImode, bytes),
+ convert_to_mode (QImode, value_rtx, 1));
+}
+
+/* Generate a call to a library function to set BYTES_RTX bytes at address
+ DST_REG to VALUE_RTX in 1-byte chunks. */
+
+static void
+expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
+{
+ const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memset");
+
+ value_rtx = convert_to_mode (Pmode, value_rtx, 1);
+ emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
+ value_rtx, Pmode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ bytes_rtx,
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+}
+
+/* Expand string/block move operations.
+
+ operands[0] is the pointer to the destination.
+ operands[1] is the pointer to the source.
+ operands[2] is the number of bytes to move.
+ operands[3] is the alignment.
+
+ Return 1 upon success, 0 otherwise. */
+
+int
+visium_expand_block_move (rtx *operands)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+ rtx bytes_rtx = operands[2];
+ rtx align_rtx = operands[3];
+ const int align = INTVAL (align_rtx);
+ rtx dst_reg, src_reg;
+ tree dst_expr, src_expr;
+
+ /* We only handle a fixed number of bytes for now. */
+ if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
+ return 0;
+
+ /* Copy the addresses into scratch registers. */
+ dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+ src_reg = copy_addr_to_reg (XEXP (src, 0));
+
+ /* Move the data with the appropriate granularity. */
+ if (align >= 4)
+ expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
+ else if (align >= 2)
+ expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
+ else
+ expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
+
+ /* Since DST and SRC are passed to a libcall, mark the corresponding
+ tree EXPR as addressable. */
+ dst_expr = MEM_EXPR (dst);
+ src_expr = MEM_EXPR (src);
+ if (dst_expr)
+ mark_addressable (dst_expr);
+ if (src_expr)
+ mark_addressable (src_expr);
+
+ return 1;
+}
+
+/* Expand string/block set operations.
+
+ operands[0] is the pointer to the destination.
+ operands[1] is the number of bytes to set.
+ operands[2] is the source value.
+ operands[3] is the alignment.
+
+ Return 1 upon success, 0 otherwise. */
+
+int
+visium_expand_block_set (rtx *operands)
+{
+ rtx dst = operands[0];
+ rtx bytes_rtx = operands[1];
+ rtx value_rtx = operands[2];
+ rtx align_rtx = operands[3];
+ const int align = INTVAL (align_rtx);
+ rtx dst_reg;
+ tree dst_expr;
+
+ /* We only handle a fixed number of bytes for now. */
+ if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
+ return 0;
+
+ /* Copy the address into a scratch register. */
+ dst_reg = copy_addr_to_reg (XEXP (dst, 0));
+
+ /* Set the data with the appropriate granularity. */
+ if (align >= 4)
+ expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
+ else if (align >= 2)
+ expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
+ else
+ expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
+
+ /* Since DST is passed to a libcall, mark the corresponding
+ tree EXPR as addressable. */
+ dst_expr = MEM_EXPR (dst);
+ if (dst_expr)
+ mark_addressable (dst_expr);
+
+ return 1;
+}
+
+/* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
+ trampoline, FNDECL is the FUNCTION_DECL for the nested function and
+ STATIC_CHAIN is an RTX for the static chain value that should be passed
+ to the function when it is called. */
+
+static void
+visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
+{
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx addr = XEXP (m_tramp, 0);
+
+ /* The trampoline initialization sequence is:
+
+ moviu r9,%u FUNCTION
+ movil r9,%l FUNCTION
+ moviu r20,%u STATIC
+ bra tr,r9,r9
+ movil r20,%l STATIC
+
+ We don't use r0 as the destination register of the branch because we want
+ the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
+ predict the branch target. */
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
+ plus_constant (SImode,
+ expand_shift (RSHIFT_EXPR, SImode, fnaddr,
+ 16, NULL_RTX, 1),
+ 0x04a90000));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
+ plus_constant (SImode,
+ expand_and (SImode, fnaddr, GEN_INT (0xffff),
+ NULL_RTX),
+ 0x04890000));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
+ plus_constant (SImode,
+ expand_shift (RSHIFT_EXPR, SImode,
+ static_chain,
+ 16, NULL_RTX, 1),
+ 0x04b40000));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
+ gen_int_mode (0xff892404, SImode));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
+ plus_constant (SImode,
+ expand_and (SImode, static_chain,
+ GEN_INT (0xffff), NULL_RTX),
+ 0x04940000));
+
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__set_trampoline_parity"),
+ LCT_NORMAL, VOIDmode, 1, addr, SImode);
+}
+
+/* Return true if the current function must have and use a frame pointer. */
+
+static bool
+visium_frame_pointer_required (void)
+{
+ /* The frame pointer is required if the function isn't leaf to be able to
+ do manual stack unwinding. */
+ if (!crtl->is_leaf)
+ return true;
+
+ /* If the stack pointer is dynamically modified in the function, it cannot
+ serve as the frame pointer. */
+ if (!crtl->sp_is_unchanging)
+ return true;
+
+ /* If the function receives nonlocal gotos, it needs to save the frame
+ pointer in the nonlocal_goto_save_area object. */
+ if (cfun->has_nonlocal_label)
+ return true;
+
+ /* The frame also needs to be established in some special cases. */
+ if (visium_frame_needed)
+ return true;
+
+ return false;
+}
+
+/* Profiling support. Just a call to MCOUNT is needed. No labelled counter
+ location is involved. Proper support for __builtin_return_address is also
+ required, which is fairly straightforward provided a frame gets created. */
+
+void
+visium_profile_hook (void)
+{
+ visium_frame_needed = true;
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
+ VOIDmode, 0);
+}
+
+/* A C expression whose value is RTL representing the address in a stack frame
+ where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
+ an RTL expression for the address of the stack frame itself.
+
+ If you don't define this macro, the default is to return the value of
+ FRAMEADDR--that is, the stack frame address is also the address of the stack
+ word that points to the previous frame. */
+
+rtx
+visium_dynamic_chain_address (rtx frame)
+{
+ /* This is the default, but we need to make sure the frame gets created. */
+ visium_frame_needed = true;
+ return frame;
+}
+
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame, after the
+ prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
+ pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
+ defined.
+
+ The value of the expression must always be the correct address when COUNT is
+ zero, but may be `NULL_RTX' if there is not way to determine the return
+ address of other frames. */
+
+rtx
+visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+ /* Dont try to compute anything other than frame zero. */
+ if (count != 0)
+ return NULL_RTX;
+
+ visium_frame_needed = true;
+ return
+ gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
+}
+
+/* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
+ location in which to store the address of an exception handler to which we
+ should return. */
+
+rtx
+visium_eh_return_handler_rtx (void)
+{
+ rtx mem
+ = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
+ MEM_VOLATILE_P (mem) = 1;
+ return mem;
+}
+
+static struct machine_function *
+visium_init_machine_status (void)
+{
+ return ggc_cleared_alloc<machine_function> ();
+}
+
+/* The per-function data machinery is needed to indicate when a frame
+ is required. */
+
+void
+visium_init_expanders (void)
+{
+ init_machine_status = visium_init_machine_status;
+}
+
+/* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
+ return the mode to be used for the comparison. */
+
+enum machine_mode
+visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
+{
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+ {
+ switch (code)
+ {
+ case EQ:
+ case NE:
+ case ORDERED:
+ case UNORDERED:
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ return CCFPmode;
+
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ return CCFPEmode;
+
+ /* These 2 comparison codes are not supported. */
+ case UNEQ:
+ case LTGT:
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ if (op1 != const0_rtx)
+ return CCmode;
+
+ switch (GET_CODE (op0))
+ {
+ case PLUS:
+ case MINUS:
+ case NEG:
+ case ASHIFT:
+ case LTU:
+ case LT:
+ /* The V flag may be set differently from a COMPARE with zero.
+ The consequence is that a comparison operator testing V must
+ be turned into another operator not testing V and yielding
+ the same result for a comparison with zero. That's possible
+ for GE/LT which become NC/NS respectively, but not for GT/LE
+ for which the altered operator doesn't exist on the Visium. */
+ return CC_NOOVmode;
+
+ case ZERO_EXTRACT:
+ /* This is a btst, the result is in C instead of Z. */
+ return CC_BTSTmode;
+
+ case CONST_INT:
+ /* This is a degenerate case, typically an uninitialized variable. */
+ gcc_assert (op0 == constm1_rtx);
+ case REG:
+ case AND:
+ case IOR:
+ case XOR:
+ case NOT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ case TRUNCATE:
+ case SIGN_EXTEND:
+ /* Pretend that the flags are set as for a COMPARE with zero.
+ That's mostly true, except for the 2 right shift insns that
+ will set the C flag. But the C flag is relevant only for
+ the unsigned comparison operators and they are eliminated
+ when applied to a comparison with zero. */
+ return CCmode;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
+
+void
+visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
+{
+ enum machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
+ rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
+
+ rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
+ pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
+
+ visium_flags_exposed = true;
+}
+
+/* Branch instructions on the Visium.
+
+ Setting aside the interrupt-handling specific instructions, the ISA has
+ two branch instructions: BRR and BRA. The former is used to implement
+ short branches (+/- 2^17) within functions and its target is encoded in
+ the instruction. The latter is used to implement all the other types
+ of control flow changes and its target might not be statically known
+ or even easily predictable at run time. Here's a complete summary of
+ the patterns that generate a BRA instruction:
+
+ 1. Indirect jump
+ 2. Table jump
+ 3. Call
+ 4. Sibling call
+ 5. Return
+ 6. Long branch
+ 7. Trampoline
+
+ Among these patterns, only the return (5) and the long branch (6) can be
+ conditional; all the other patterns are always unconditional.
+
+ The following algorithm can be used to identify the pattern for which
+ the BRA instruction was generated and work out its target:
+
+ A. If the source is r21 and the destination is r0, this is a return (5)
+ and the target is the caller (i.e. the value of r21 on function's
+ entry).
+
+ B. If the source is rN, N != 21 and the destination is r0, this is either
+ an indirect jump or a table jump (1, 2) and the target is not easily
+ predictable.
+
+ C. If the source is rN, N != 21 and the destination is r21, this is a call
+ (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
+ unless this is an indirect call in which case the target is not easily
+ predictable.
+
+ D. If the source is rN, N != 21 and the destination is also rN, this is
+ either a sibling call or a trampoline (4, 7) and the target is given
+ by the preceding MOVIL/MOVIU pair for rN.
+
+ E. If the source is r21 and the destination is also r21, this is a long
+ branch (6) and the target is given by the preceding MOVIL/MOVIU pair
+ for r21.
+
+ The other combinations are not used. This implementation has been devised
+ to accommodate the branch predictor of the GR6 but is used unconditionally
+ by the compiler, i.e. including for earlier processors. */
+
+/* Output a conditional/unconditional branch to LABEL. COND is the string
+ condition. INSN is the instruction. */
+
+static const char *
+output_branch (rtx label, const char *cond, rtx_insn *insn)
+{
+ char str[64];
+ rtx operands[2];
+
+ gcc_assert (cond);
+ operands[0] = label;
+
+ /* If the length of the instruction is greater than 8, then this is a
+ long branch and we need to work harder to emit it properly. */
+ if (get_attr_length (insn) > 8)
+ {
+ bool spilled;
+
+ /* If the link register has been saved, then we use it. */
+ if (current_function_saves_lr ())
+ {
+ operands[1] = regno_reg_rtx [LINK_REGNUM];
+ spilled = false;
+ }
+
+ /* Or else, if the long-branch register isn't live, we use it. */
+ else if (!df_regs_ever_live_p (long_branch_regnum))
+ {
+ operands[1] = regno_reg_rtx [long_branch_regnum];
+ spilled = false;
+ }
+
+ /* Otherwise, we will use the long-branch register but we need to
+ spill it to the stack and reload it at the end. We should have
+ reserved the LR slot for this purpose. */
+ else
+ {
+ operands[1] = regno_reg_rtx [long_branch_regnum];
+ spilled = true;
+ gcc_assert (current_function_has_lr_slot ());
+ }
+
+ /* First emit the spill to the stack:
+
+ insn_in_delay_slot
+ write.l [1](sp),reg */
+ if (spilled)
+ {
+ if (final_sequence)
+ {
+ rtx_insn *delay = NEXT_INSN (insn);
+ int seen;
+ gcc_assert (delay);
+
+ final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
+ PATTERN (delay) = gen_blockage ();
+ INSN_CODE (delay) = -1;
+ }
+
+ if (current_function_saves_fp ())
+ output_asm_insn ("write.l 1(sp),%1", operands);
+ else
+ output_asm_insn ("write.l (sp),%1", operands);
+ }
+
+ /* Then emit the core sequence:
+
+ moviu reg,%u label
+ movil reg,%l label
+ bra tr,reg,reg
+
+ We don't use r0 as the destination register of the branch because we
+ want the Branch Pre-decode Logic of the GR6 to use the Address Load
+ Array to predict the branch target. */
+ output_asm_insn ("moviu %1,%%u %0", operands);
+ output_asm_insn ("movil %1,%%l %0", operands);
+ strcpy (str, "bra ");
+ strcat (str, cond);
+ strcat (str, ",%1,%1");
+ if (!spilled)
+ strcat (str, "%#");
+ strcat (str, "\t\t;long branch");
+ output_asm_insn (str, operands);
+
+ /* Finally emit the reload:
+
+ read.l reg,[1](sp) */
+ if (spilled)
+ {
+ if (current_function_saves_fp ())
+ output_asm_insn (" read.l %1,1(sp)", operands);
+ else
+ output_asm_insn (" read.l %1,(sp)", operands);
+ }
+ }
+
+ /* Or else, if the label is PC, then this is a return. */
+ else if (label == pc_rtx)
+ {
+ strcpy (str, "bra ");
+ strcat (str, cond);
+ strcat (str, ",r21,r0%#\t\t;return");
+ output_asm_insn (str, operands);
+ }
+
+ /* Otherwise, this is a short branch. */
+ else
+ {
+ strcpy (str, "brr ");
+ strcat (str, cond);
+ strcat (str, ",%0%#");
+ output_asm_insn (str, operands);
+ }
+
+ return "";
+}
+
+/* Output an unconditional branch to LABEL. INSN is the instruction. */
+
+const char *
+output_ubranch (rtx label, rtx_insn *insn)
+{
+ return output_branch (label, "tr", insn);
+}
+
+/* Output a conditional branch to LABEL. CODE is the comparison code.
+ CC_MODE is the mode of the CC register. REVERSED is non-zero if we
+ should reverse the sense of the comparison. INSN is the instruction. */
+
+const char *
+output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
+ int reversed, rtx_insn *insn)
+{
+ const char *cond;
+
+ if (reversed)
+ {
+ if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
+ code = reverse_condition_maybe_unordered (code);
+ else
+ code = reverse_condition (code);
+ }
+
+ switch (code)
+ {
+ case NE:
+ if (cc_mode == CC_BTSTmode)
+ cond = "cs";
+ else
+ cond = "ne";
+ break;
+
+ case EQ:
+ if (cc_mode == CC_BTSTmode)
+ cond = "cc";
+ else
+ cond = "eq";
+ break;
+
+ case GE:
+ if (cc_mode == CC_NOOVmode)
+ cond = "nc";
+ else
+ cond = "ge";
+ break;
+
+ case GT:
+ cond = "gt";
+ break;
+
+ case LE:
+ if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
+ cond = "ls";
+ else
+ cond = "le";
+ break;
+
+ case LT:
+ if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
+ cond = "ns";
+ else if (cc_mode == CC_NOOVmode)
+ cond = "ns";
+ else
+ cond = "lt";
+ break;
+
+ case GEU:
+ cond = "cc";
+ break;
+
+ case GTU:
+ cond = "hi";
+ break;
+
+ case LEU:
+ cond = "ls";
+ break;
+
+ case LTU:
+ cond = "cs";
+ break;
+
+ case UNORDERED:
+ cond = "os";
+ break;
+
+ case ORDERED:
+ cond = "oc";
+ break;
+
+ case UNGE:
+ cond = "nc";
+ break;
+
+ case UNGT:
+ cond = "hi";
+ break;
+
+ case UNLE:
+ cond = "le";
+ break;
+
+ case UNLT:
+ cond = "lt";
+ break;
+
+ /* These 2 comparison codes are not supported. */
+ case UNEQ:
+ case LTGT:
+ default:
+ gcc_unreachable ();
+ }
+
+ return output_branch (label, cond, insn);
+}
+
+/* Helper function for PRINT_OPERAND (STREAM, X, CODE). Output to stdio
+ stream FILE the assembler syntax for an instruction operand OP subject
+ to the modifier LETTER. */
+
+void
+print_operand (FILE *file, rtx op, int letter)
+{
+ switch (letter)
+ {
+ case '#':
+ /* Output an insn in a delay slot. */
+ if (final_sequence)
+ visium_indent_opcode = 1;
+ else
+ fputs ("\n\t nop", file);
+ return;
+
+ case 'b':
+ /* Print LS 8 bits of operand. */
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
+ return;
+
+ case 'w':
+ /* Print LS 16 bits of operand. */
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
+ return;
+
+ case 'u':
+ /* Print MS 16 bits of operand. */
+ fprintf (file,
+ HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
+ return;
+
+ case 'r':
+ /* It's either a register or zero. */
+ if (GET_CODE (op) == REG)
+ fputs (reg_names[REGNO (op)], file);
+ else
+ fputs (reg_names[0], file);
+ return;
+
+ case 'f':
+ /* It's either a FP register or zero. */
+ if (GET_CODE (op) == REG)
+ fputs (reg_names[REGNO (op)], file);
+ else
+ fputs (reg_names[FP_FIRST_REGNUM], file);
+ return;
+ }
+
+ switch (GET_CODE (op))
+ {
+ case REG:
+ if (letter == 'd')
+ fputs (reg_names[REGNO (op) + 1], file);
+ else
+ fputs (reg_names[REGNO (op)], file);
+ break;
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST:
+ output_addr_const (file, op);
+ break;
+
+ case MEM:
+ visium_output_address (file, GET_MODE (op), XEXP (op, 0));
+ break;
+
+ case CONST_INT:
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
+ break;
+
+ case CODE_LABEL:
+ asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
+ break;
+
+ case HIGH:
+ print_operand (file, XEXP (op, 1), letter);
+ break;
+
+ default:
+ fatal_insn ("illegal operand ", op);
+ }
+}
+
+/* Output to stdio stream FILE the assembler syntax for an instruction operand
+ that is a memory reference in MODE and whose address is ADDR. */
+
+static void
+visium_output_address (FILE *file, enum machine_mode mode, rtx addr)
+{
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ case SUBREG:
+ fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
+ break;
+
+ case PLUS:
+ {
+ rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
+
+ switch (GET_CODE (x))
+ {
+ case REG:
+ case SUBREG:
+ if (CONST_INT_P (y))
+ {
+ unsigned int regno = true_regnum (x);
+ HOST_WIDE_INT val = INTVAL (y);
+ switch (mode)
+ {
+ case SImode:
+ case DImode:
+ case SFmode:
+ case DFmode:
+ val >>= 2;
+ break;
+
+ case HImode:
+ val >>= 1;
+ break;
+
+ case QImode:
+ default:
+ break;
+ }
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
+ reg_names[regno]);
+ }
+ else
+ fatal_insn ("illegal operand address (1)", addr);
+ break;
+
+ default:
+ if (CONSTANT_P (x) && CONSTANT_P (y))
+ output_addr_const (file, addr);
+ else
+ fatal_insn ("illegal operand address (2)", addr);
+ break;
+ }
+ }
+ break;
+
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_INT:
+ case CONST:
+ output_addr_const (file, addr);
+ break;
+
+ case NOTE:
+ if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
+ fatal_insn ("illegal operand address (3)", addr);
+ break;
+
+ case CODE_LABEL:
+ asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
+ break;
+
+ default:
+ fatal_insn ("illegal operand address (4)", addr);
+ break;
+ }
+}
+
+/* Helper function for PRINT_OPERAND_ADDRESS (STREAM, X). Output to stdio
+ stream FILE the assembler syntax for an instruction operand that is a
+ memory reference whose address is ADDR. */
+
+void
+print_operand_address (FILE *file, rtx addr)
+{
+ visium_output_address (file, QImode, addr);
+}
+
+/* The Visium stack frames look like:
+
+ Before call After call
+ +-----------------------+ +-----------------------+
+ | | | |
+ high | previous | | previous |
+ mem | frame | | frame |
+ | | | |
+ +-----------------------+ +-----------------------+
+ | | | |
+ | arguments on stack | | arguments on stack |
+ | | | |
+ SP+0->+-----------------------+ +-----------------------+
+ | reg parm save area, |
+ | only created for |
+ | variable argument |
+ | functions |
+ +-----------------------+
+ | |
+ | register save area |
+ | |
+ +-----------------------+
+ | |
+ | local variables |
+ | |
+ FP+8->+-----------------------+
+ | return address |
+ FP+4->+-----------------------+
+ | previous FP |
+ FP+0->+-----------------------+
+ | |
+ | alloca allocations |
+ | |
+ +-----------------------+
+ | |
+ low | arguments on stack |
+ mem | |
+ SP+0->+-----------------------+
+
+ Notes:
+ 1) The "reg parm save area" does not exist for non variable argument fns.
+ 2) The FP register is not saved if `frame_pointer_needed' is zero and it
+ is not altered in the current function.
+ 3) The return address is not saved if there is no frame pointer and the
+ current function is leaf.
+ 4) If the return address is not saved and the static chain register is
+ live in the function, we allocate the return address slot to be able
+ to spill the register for a long branch. */
+
+/* Define the register classes for local purposes. */
+enum reg_type { general, mdb, mdc, floating, last_type};
+
+#define GET_REG_TYPE(regno) \
+ (GP_REGISTER_P (regno) ? general : \
+ (regno) == MDB_REGNUM ? mdb : \
+ (regno) == MDC_REGNUM ? mdc : \
+ floating)
+
+/* First regno of each register type. */
+const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
+
+/* Size in bytes of each register type. */
+const int reg_type_size[last_type] = {4, 8, 4, 4};
+
+/* Structure to be filled in by visium_compute_frame_size. */
+struct visium_frame_info
+{
+ unsigned int save_area_size; /* # bytes in the reg parm save area. */
+ unsigned int reg_size1; /* # bytes to store first block of regs. */
+ unsigned int reg_size2; /* # bytes to store second block of regs. */
+ unsigned int max_reg1; /* max. regno in first block */
+ unsigned int var_size; /* # bytes that variables take up. */
+ unsigned int save_fp; /* Nonzero if fp must be saved. */
+ unsigned int save_lr; /* Nonzero if lr must be saved. */
+ unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
+ unsigned int combine; /* Nonzero if we can combine the allocation of
+ variables and regs. */
+ unsigned int interrupt; /* Nonzero if the function is an interrupt
+ handler. */
+ unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
+};
+
+/* Current frame information calculated by visium_compute_frame_size. */
+static struct visium_frame_info current_frame_info;
+
+/* Accessor for current_frame_info.save_fp. */
+
+static inline bool
+current_function_saves_fp (void)
+{
+ return current_frame_info.save_fp != 0;
+}
+
+/* Accessor for current_frame_info.save_lr. */
+
+static inline bool
+current_function_saves_lr (void)
+{
+ return current_frame_info.save_lr != 0;
+}
+
+/* Accessor for current_frame_info.lr_slot. */
+
+static inline bool
+current_function_has_lr_slot (void)
+{
+ return current_frame_info.lr_slot != 0;
+}
+
+/* Return non-zero if register REGNO needs to be saved in the frame. */
+
+static int
+visium_save_reg_p (int interrupt, int regno)
+{
+ switch (regno)
+ {
+ case HARD_FRAME_POINTER_REGNUM:
+ /* This register is call-saved but handled specially. */
+ return 0;
+
+ case MDC_REGNUM:
+ /* This register is fixed but can be modified. */
+ break;
+
+ case 29:
+ case 30:
+ /* These registers are fixed and hold the interrupt context. */
+ return (interrupt != 0);
+
+ default:
+ /* The other fixed registers are either immutable or special. */
+ if (fixed_regs[regno])
+ return 0;
+ break;
+ }
+
+ if (interrupt)
+ {
+ if (crtl->is_leaf)
+ {
+ if (df_regs_ever_live_p (regno))
+ return 1;
+ }
+ else if (call_used_regs[regno])
+ return 1;
+
+ /* To save mdb requires two temporary registers. To save mdc or
+ any of the floating registers requires one temporary
+ register. If this is an interrupt routine, the temporary
+ registers need to be saved as well. These temporary registers
+ are call used, so we only need deal with the case of leaf
+ functions here. */
+ if (regno == PROLOGUE_TMP_REGNUM)
+ {
+ if (df_regs_ever_live_p (MDB_REGNUM)
+ || df_regs_ever_live_p (MDC_REGNUM))
+ return 1;
+
+ for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
+ if (df_regs_ever_live_p (i))
+ return 1;
+ }
+
+ else if (regno == PROLOGUE_TMP_REGNUM + 1)
+ {
+ if (df_regs_ever_live_p (MDB_REGNUM))
+ return 1;
+ }
+ }
+
+ return df_regs_ever_live_p (regno) && !call_used_regs[regno];
+}
+
+/* Compute the frame size required by the function. This function is called
+ during the reload pass and also by visium_expand_prologue. */
+
+static int
+visium_compute_frame_size (int size)
+{
+ const int save_area_size = visium_reg_parm_save_area_size;
+ const int var_size = VISIUM_STACK_ALIGN (size);
+ const int save_fp
+ = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
+ const int save_lr = frame_pointer_needed || !crtl->is_leaf;
+ const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
+ const int local_frame_offset
+ = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
+ const int interrupt = visium_interrupt_function_p ();
+ unsigned int mask[last_type];
+ int reg_size1 = 0;
+ int max_reg1 = 0;
+ int reg_size2 = 0;
+ int reg_size;
+ int combine;
+ int frame_size;
+ int regno;
+
+ memset (mask, 0, last_type * sizeof (unsigned int));
+
+ /* The registers may need stacking in 2 blocks since only 32 32-bit words
+ can be indexed from a given base address. */
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (visium_save_reg_p (interrupt, regno))
+ {
+ enum reg_type reg_type = GET_REG_TYPE (regno);
+ int mask_bit = 1 << (regno - first_regno[reg_type]);
+ int nbytes = reg_type_size[reg_type];
+
+ if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
+ break;
+
+ reg_size1 += nbytes;
+ max_reg1 = regno;
+ mask[reg_type] |= mask_bit;
+ }
+ }
+
+ for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (visium_save_reg_p (interrupt, regno))
+ {
+ enum reg_type reg_type = GET_REG_TYPE (regno);
+ int mask_bit = 1 << (regno - first_regno[reg_type]);
+ int nbytes = reg_type_size[reg_type];
+
+ reg_size2 += nbytes;
+ mask[reg_type] |= mask_bit;
+ }
+ }
+
+ reg_size = reg_size2 ? reg_size2 : reg_size1;
+ combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
+ frame_size
+ = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
+
+ current_frame_info.save_area_size = save_area_size;
+ current_frame_info.reg_size1 = reg_size1;
+ current_frame_info.max_reg1 = max_reg1;
+ current_frame_info.reg_size2 = reg_size2;
+ current_frame_info.var_size = var_size;
+ current_frame_info.save_fp = save_fp;
+ current_frame_info.save_lr = save_lr;
+ current_frame_info.lr_slot = lr_slot;
+ current_frame_info.combine = combine;
+ current_frame_info.interrupt = interrupt;
+
+ memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
+
+ return frame_size;
+}
+
+/* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
+ the offset between two registers, one to be eliminated, and the other its
+ replacement, at the start of a routine. */
+
+int
+visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
+{
+ const int frame_size = visium_compute_frame_size (get_frame_size ());
+ const int save_fp = current_frame_info.save_fp;
+ const int save_lr = current_frame_info.save_lr;
+ const int lr_slot = current_frame_info.lr_slot;
+ const int local_frame_offset
+ = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
+ int offset;
+
+ if (from == FRAME_POINTER_REGNUM)
+ offset = local_frame_offset;
+ else if (from == ARG_POINTER_REGNUM)
+ offset = frame_size;
+ else
+ gcc_unreachable ();
+
+ return offset;
+}
+
+/* For an interrupt handler, we may be saving call-clobbered registers.
+ Say the epilogue uses these in addition to the link register. */
+
+int
+visium_epilogue_uses (int regno)
+{
+ if (regno == LINK_REGNUM)
+ return 1;
+
+ if (reload_completed)
+ {
+ enum reg_type reg_type = GET_REG_TYPE (regno);
+ int mask_bit = 1 << (regno - first_regno[reg_type]);
+
+ return (current_frame_info.mask[reg_type] & mask_bit) != 0;
+ }
+
+ return 0;
+}
+
+/* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
+
+static rtx
+emit_frame_insn (rtx x)
+{
+ x = emit_insn (x);
+ RTX_FRAME_RELATED_P (x) = 1;
+ return x;
+}
+
+/* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
+ HIGH_REGNO at OFFSET from the stack pointer. */
+
+static void
+visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
+{
+ /* If this is an interrupt handler function, then mark the register
+ stores as volatile. This will prevent the instruction scheduler
+ from scrambling the order of register saves. */
+ const int volatile_p = current_frame_info.interrupt;
+ int regno;
+
+ /* Allocate the stack space. */
+ emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-alloc)));
+
+ for (regno = low_regno; regno <= high_regno; regno++)
+ {
+ enum reg_type reg_type = GET_REG_TYPE (regno);
+ int mask_bit = 1 << (regno - first_regno[reg_type]);
+ rtx insn;
+
+ if (current_frame_info.mask[reg_type] & mask_bit)
+ {
+ offset -= reg_type_size[reg_type];
+ switch (reg_type)
+ {
+ case general:
+ {
+ rtx mem
+ = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
+ }
+ break;
+
+ case mdb:
+ {
+ rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (DImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (DImode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movdi (tmp, reg));
+ /* Do not generate CFI if in interrupt handler. */
+ if (volatile_p)
+ emit_insn (gen_movdi (mem, tmp));
+ else
+ {
+ insn = emit_frame_insn (gen_movdi (mem, tmp));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, mem, reg));
+ }
+ }
+ break;
+
+ case mdc:
+ {
+ rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (SImode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movsi (tmp, reg));
+ insn = emit_frame_insn (gen_movsi (mem, tmp));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, mem, reg));
+ }
+ break;
+
+ case floating:
+ {
+ rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (SFmode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (SFmode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movsf (tmp, reg));
+ insn = emit_frame_insn (gen_movsf (mem, tmp));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, mem, reg));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/* This function generates the code for function entry. */
+
+void
+visium_expand_prologue (void)
+{
+ const int frame_size = visium_compute_frame_size (get_frame_size ());
+ const int save_area_size = current_frame_info.save_area_size;
+ const int reg_size1 = current_frame_info.reg_size1;
+ const int max_reg1 = current_frame_info.max_reg1;
+ const int reg_size2 = current_frame_info.reg_size2;
+ const int var_size = current_frame_info.var_size;
+ const int save_fp = current_frame_info.save_fp;
+ const int save_lr = current_frame_info.save_lr;
+ const int lr_slot = current_frame_info.lr_slot;
+ const int local_frame_offset
+ = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
+ const int combine = current_frame_info.combine;
+ int reg_size;
+ int first_reg;
+ int fsize;
+
+ /* Save the frame size for future references. */
+ visium_frame_size = frame_size;
+
+ if (flag_stack_usage_info)
+ current_function_static_stack_size = frame_size;
+
+ /* If the registers have to be stacked in 2 blocks, stack the first one. */
+ if (reg_size2)
+ {
+ visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
+ reg_size = reg_size2;
+ first_reg = max_reg1 + 1;
+ fsize = local_frame_offset + var_size + reg_size2;
+ }
+ else
+ {
+ reg_size = reg_size1;
+ first_reg = 0;
+ fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
+ }
+
+ /* If we can't combine register stacking with variable allocation, partially
+ allocate and stack the (remaining) registers now. */
+ if (reg_size && !combine)
+ visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
+ first_reg, FIRST_PSEUDO_REGISTER - 1);
+
+ /* If we can combine register stacking with variable allocation, fully
+ allocate and stack the (remaining) registers now. */
+ if (reg_size && combine)
+ visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
+ first_reg, FIRST_PSEUDO_REGISTER - 1);
+
+ /* Otherwise space may still need to be allocated for the variables. */
+ else if (fsize)
+ {
+ const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
+
+ if (alloc_size > 65535)
+ {
+ rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
+ emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
+ insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
+ stack_pointer_rtx,
+ tmp));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (-alloc_size))));
+ }
+ else
+ emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-alloc_size)));
+ }
+
+ if (save_fp)
+ emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
+ hard_frame_pointer_rtx));
+
+ if (frame_pointer_needed)
+ emit_frame_insn (gen_stack_save ());
+
+ if (save_lr)
+ {
+ rtx base_rtx, mem;
+
+ /* Normally the frame pointer and link register get saved via
+ write.l (sp),fp
+ move.l fp,sp
+ write.l 1(sp),r21
+
+ Indexing off sp rather than fp to store the link register
+ avoids presenting the instruction scheduler with an initial
+ pipeline hazard. If however the frame is needed for eg.
+ __builtin_return_address which needs to retrieve the saved
+ value of the link register from the stack at fp + 4 then
+ indexing from sp can confuse the dataflow, causing the link
+ register to be retrieved before it has been saved. */
+ if (cfun->machine->frame_needed)
+ base_rtx = hard_frame_pointer_rtx;
+ else
+ base_rtx = stack_pointer_rtx;
+
+ mem = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ base_rtx, save_fp * UNITS_PER_WORD));
+ emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
+ }
+}
+
+static GTY(()) rtx cfa_restores;
+
+/* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
+
+static void
+visium_add_cfa_restore_note (rtx reg)
+{
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+}
+
+/* Add queued REG_CFA_RESTORE notes to INSN, if any. */
+
+static void
+visium_add_queued_cfa_restore_notes (rtx insn)
+{
+ rtx last;
+ if (!cfa_restores)
+ return;
+ for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
+ ;
+ XEXP (last, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = cfa_restores;
+ cfa_restores = NULL_RTX;
+}
+
+/* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
+ from the stack pointer and pop DEALLOC bytes off the stack. */
+
+static void
+visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
+{
+ /* If this is an interrupt handler function, then mark the register
+ restores as volatile. This will prevent the instruction scheduler
+ from scrambling the order of register restores. */
+ const int volatile_p = current_frame_info.interrupt;
+ int r30_offset = -1;
+ int regno;
+
+ for (regno = high_regno; regno >= low_regno; --regno)
+ {
+ enum reg_type reg_type = GET_REG_TYPE (regno);
+ int mask_bit = 1 << (regno - first_regno[reg_type]);
+
+ if (current_frame_info.mask[reg_type] & mask_bit)
+ {
+ switch (reg_type)
+ {
+ case general:
+ /* Postpone restoring the interrupted context registers
+ until last, since they need to be preceded by a dsi. */
+ if (regno == 29)
+ ;
+ else if (regno == 30)
+ r30_offset = offset;
+ else
+ {
+ rtx mem
+ = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset));
+ rtx reg = gen_rtx_REG (SImode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movsi (reg, mem));
+ visium_add_cfa_restore_note (reg);
+ }
+ break;
+
+ case mdb:
+ {
+ rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (DImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (DImode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movdi (tmp, mem));
+ emit_insn (gen_movdi (reg, tmp));
+ /* Do not generate CFI if in interrupt handler. */
+ if (!volatile_p)
+ visium_add_cfa_restore_note (reg);
+ }
+ break;
+
+ case mdc:
+ {
+ rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (SImode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movsi (tmp, mem));
+ emit_insn (gen_movsi (reg, tmp));
+ visium_add_cfa_restore_note (reg);
+ }
+ break;
+
+ case floating:
+ {
+ rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
+ rtx mem
+ = gen_frame_mem (SFmode,
+ plus_constant (Pmode,
+ stack_pointer_rtx, offset));
+ rtx reg = gen_rtx_REG (SFmode, regno);
+ MEM_VOLATILE_P (mem) = volatile_p;
+ emit_insn (gen_movsf (tmp, mem));
+ emit_insn (gen_movsf (reg, tmp));
+ visium_add_cfa_restore_note (reg);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ offset += reg_type_size[reg_type];
+ }
+ }
+
+ /* If the interrupted context needs to be restored, precede the
+ restores of r29 and r30 by a dsi. */
+ if (r30_offset >= 0)
+ {
+ emit_insn (gen_dsi ());
+ emit_move_insn (gen_rtx_REG (SImode, 30),
+ gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ r30_offset)));
+ emit_move_insn (gen_rtx_REG (SImode, 29),
+ gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ r30_offset + 4)));
+ }
+
+ /* Deallocate the stack space. */
+ rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (dealloc))));
+ visium_add_queued_cfa_restore_notes (insn);
+}
+
+/* This function generates the code for function exit. */
+
+void
+visium_expand_epilogue (void)
+{
+ const int save_area_size = current_frame_info.save_area_size;
+ const int reg_size1 = current_frame_info.reg_size1;
+ const int max_reg1 = current_frame_info.max_reg1;
+ const int reg_size2 = current_frame_info.reg_size2;
+ const int var_size = current_frame_info.var_size;
+ const int restore_fp = current_frame_info.save_fp;
+ const int restore_lr = current_frame_info.save_lr;
+ const int lr_slot = current_frame_info.lr_slot;
+ const int local_frame_offset
+ = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
+ const int combine = current_frame_info.combine;
+ int reg_size;
+ int last_reg;
+ int fsize;
+
+ /* Do not bother restoring the stack pointer if it hasn't been changed in
+ the function since it was saved _after_ the allocation of the frame. */
+ if (!crtl->sp_is_unchanging)
+ emit_insn (gen_stack_restore ());
+
+ /* Restore the frame pointer if necessary. The usual code would be:
+
+ move.l sp,fp
+ read.l fp,(sp)
+
+ but for the MCM this constitutes a stall/hazard so it is changed to:
+
+ move.l sp,fp
+ read.l fp,(fp)
+
+ if the stack pointer has actually been restored. */
+ if (restore_fp)
+ {
+ rtx src;
+
+ if (TARGET_MCM && !crtl->sp_is_unchanging)
+ src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
+ else
+ src = gen_frame_mem (SImode, stack_pointer_rtx);
+
+ rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
+ add_reg_note (insn, REG_CFA_ADJUST_CFA,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ hard_frame_pointer_rtx));
+ visium_add_cfa_restore_note (hard_frame_pointer_rtx);
+ }
+
+ /* Restore the link register if necessary. */
+ if (restore_lr)
+ {
+ rtx mem = gen_frame_mem (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ restore_fp * UNITS_PER_WORD));
+ rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
+ emit_insn (gen_movsi (reg, mem));
+ visium_add_cfa_restore_note (reg);
+ }
+
+ /* If we have two blocks of registers, deal with the second one first. */
+ if (reg_size2)
+ {
+ reg_size = reg_size2;
+ last_reg = max_reg1 + 1;
+ fsize = local_frame_offset + var_size + reg_size2;
+ }
+ else
+ {
+ reg_size = reg_size1;
+ last_reg = 0;
+ fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
+ }
+
+ /* If the variable allocation could be combined with register stacking,
+ restore the (remaining) registers and fully deallocate now. */
+ if (reg_size && combine)
+ visium_restore_regs (fsize, local_frame_offset + var_size,
+ FIRST_PSEUDO_REGISTER - 1, last_reg);
+
+ /* Otherwise deallocate the variables first. */
+ else if (fsize)
+ {
+ const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
+ rtx insn;
+
+ if (pop_size > 65535)
+ {
+ rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
+ emit_move_insn (tmp, GEN_INT (pop_size));
+ insn = emit_frame_insn (gen_stack_pop (tmp));
+ }
+ else
+ insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (pop_size))));
+ visium_add_queued_cfa_restore_notes (insn);
+ }
+
+ /* If the variable allocation couldn't be combined with register stacking,
+ restore the (remaining) registers now and partially deallocate. */
+ if (reg_size && !combine)
+ visium_restore_regs (fsize - local_frame_offset - var_size, 0,
+ FIRST_PSEUDO_REGISTER - 1, last_reg);
+
+ /* If the first block of registers has yet to be restored, do it now. */
+ if (reg_size2)
+ visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
+
+ /* If this is an exception return, make the necessary stack adjustment. */
+ if (crtl->calls_eh_return)
+ emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
+}
+
+/* Return true if it is appropriate to emit `return' instructions in the
+ body of a function. */
+
+bool
+visium_can_use_return_insn_p (void)
+{
+ return reload_completed
+ && visium_frame_size == 0
+ && !visium_interrupt_function_p ();
+}
+
+/* Return the register class required for an intermediate register used to
+ copy a register of RCLASS from/to X. If no such intermediate register is
+ required, return NO_REGS. If more than one such intermediate register is
+ required, describe the one that is closest in the copy chain to the reload
+ register. */
+
+static reg_class_t
+visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
+ reg_class_t rclass,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+ int regno = true_regnum (x);
+
+ /* For MDB, MDC and FP_REGS, a general register is needed for a move to
+ or from memory. */
+ if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
+ return GENERAL_REGS;
+
+ /* Moves between MDB, MDC and FP_REGS also require a general register. */
+ else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
+ || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
+ return GENERAL_REGS;
+
+ /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
+ else if ((regno == R_MDB && rclass == MDC)
+ || (rclass == MDB && regno == R_MDC))
+ return GENERAL_REGS;
+
+ return NO_REGS;
+}
+
+/* Return true if pseudos that have been assigned to registers of RCLASS
+ would likely be spilled because registers of RCLASS are needed for
+ spill registers. */
+
+static bool
+visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
+{
+ /* Return false for classes R1, R2 and R3, which are intended to be used
+ only in the source code in conjunction with block move instructions. */
+ return false;
+}
+
+/* Return the register number if OP is a REG or a SUBREG of a REG, and
+ INVALID_REGNUM in all the other cases. */
+
+unsigned int
+reg_or_subreg_regno (rtx op)
+{
+ unsigned int regno;
+
+ if (GET_CODE (op) == REG)
+ regno = REGNO (op);
+ else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
+ {
+ if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
+ regno = subreg_regno (op);
+ else
+ regno = REGNO (SUBREG_REG (op));
+ }
+ else
+ regno = INVALID_REGNUM;
+
+ return regno;
+}
+
+#include "gt-visium.h"
diff --git a/gcc/config/visium/visium.h b/gcc/config/visium/visium.h
new file mode 100644
index 00000000000..d78e221c998
--- /dev/null
+++ b/gcc/config/visium/visium.h
@@ -0,0 +1,1739 @@
+/* Definitions of target machine for Visium.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Controlling the Compilation Driver, `gcc' */
+
+/* Pass -mtune=* options to the assembler */
+#undef ASM_SPEC
+#define ASM_SPEC "%{mcpu=gr6:-mtune=gr6; :-mtune=mcm}"
+
+/* Define symbols for the preprocessor. */
+#define CPP_SPEC "%{mcpu=gr6:-D__gr6__; :-D__gr5__}"
+
+/* Targets of a link */
+#define LIB_SPEC "\
+%{msim : --start-group -lc -lsim --end-group ; \
+ mdebug : --start-group -lc -ldebug --end-group ; \
+ : -lc -lnosys }"
+
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+#define STARTFILE_SPEC "crti.o%s crtbegin.o%s crt0.o%s"
+
+/* Run-time Target Specification */
+
+/* TARGET_CPU_CPP_BUILTINS() This function-like macro expands to a
+ block of code that defines built-in preprocessor macros and
+ assertions for the target cpu, using the functions builtin_define,
+ builtin_define_std and builtin_assert. When the front end calls
+ this macro it provides a trailing semicolon, and since it has
+ finished command line option processing your code can use those
+ results freely. builtin_assert takes a string in the form you pass
+ to the command-line option -A, such as cpu=mips, and creates the
+ assertion. builtin_define takes a string in the form accepted by
+ option -D and unconditionally defines the macro.
+
+ builtin_define_std takes a string representing the name of an
+ object-like macro. If it doesn't lie in the user's namespace,
+ builtin_define_std defines it unconditionally. Otherwise, it
+ defines a version with two leading underscores, and another version
+ with two leading and trailing underscores, and defines the original
+ only if an ISO standard was not requested on the command line. For
+ example, passing unix defines __unix, __unix__ and possibly unix;
+ passing _mips defines __mips, __mips__ and possibly _mips, and
+ passing _ABI64 defines only _ABI64.
+
+ You can also test for the C dialect being compiled. The variable
+ c_language is set to one of clk_c, clk_cplusplus or
+ clk_objective_c. Note that if we are preprocessing assembler, this
+ variable will be clk_c but the function-like macro
+ preprocessing_asm_p() will return true, so you might want to check
+ for that first. If you need to check for strict ANSI, the variable
+ flag_iso can be used. The function-like macro
+ preprocessing_trad_p() can be used to check for traditional
+ preprocessing. */
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define ("__VISIUM__"); \
+ if (TARGET_MCM) \
+ builtin_define ("__VISIUM_ARCH_MCM__"); \
+ if (TARGET_BMI) \
+ builtin_define ("__VISIUM_ARCH_BMI__"); \
+ if (TARGET_FPU_IEEE) \
+ builtin_define ("__VISIUM_ARCH_FPU_IEEE__"); \
+ } \
+ while (0)
+
+/* Recast the cpu class to be the cpu attribute.
+ Every file includes us, but not every file includes insn-attr.h. */
+#define visium_cpu_attr ((enum attr_cpu) visium_cpu)
+
+/* Defining data structures for per-function information.
+
+ If the target needs to store information on a per-function basis,
+ GCC provides a macro and a couple of variables to allow this. Note,
+ just using statics to store the information is a bad idea, since
+ GCC supports nested functions, so you can be halfway through
+ encoding one function when another one comes along.
+
+ GCC defines a data structure called struct function which contains
+ all of the data specific to an individual function. This structure
+ contains a field called machine whose type is struct
+ machine_function *, which can be used by targets to point to their
+ own specific data.
+
+ If a target needs per-function specific data it should define the
+ type struct machine_function and also the macro
+ INIT_EXPANDERS. This macro should be used to initialize the
+ function pointer init_machine_status. This pointer is explained
+ below.
+
+ One typical use of per-function, target specific data is to create
+ an RTX to hold the register containing the function's return
+ address. This RTX can then be used to implement the
+ __builtin_return_address function, for level 0.
+
+ Note--earlier implementations of GCC used a single data area to
+ hold all of the per-function information. Thus when processing of a
+ nested function began the old per-function data had to be pushed
+ onto a stack, and when the processing was finished, it had to be
+ popped off the stack. GCC used to provide function pointers called
+ save_machine_status and restore_machine_status to handle the saving
+ and restoring of the target specific information. Since the single
+ data area approach is no longer used, these pointers are no longer
+ supported.
+
+ The macro and function pointers are described below.
+
+ INIT_EXPANDERS:
+
+ Macro called to initialize any target specific information. This
+ macro is called once per function, before generation of any RTL has
+ begun. The intention of this macro is to allow the initialization
+ of the function pointers below.
+
+ init_machine_status:
+ This is a void (*)(struct function *) function pointer. If this
+ pointer is non-NULL it will be called once per function, before
+ function compilation starts, in order to allow the target to
+ perform any target specific initialization of the struct function
+ structure. It is intended that this would be used to initialize the
+ machine of that structure. struct machine_function structures are
+ expected to be freed by GC. Generally, any memory that they
+ reference must be allocated by using ggc_alloc, including the
+ structure itself. */
+
+#define INIT_EXPANDERS visium_init_expanders ()
+
+/* Storage Layout
+
+ Note that the definitions of the macros in this table which are
+ sizes or alignments measured in bits do not need to be constant.
+ They can be C expressions that refer to static variables, such as
+ the `target_flags'.
+
+ `BITS_BIG_ENDIAN'
+
+ Define this macro to have the value 1 if the most significant bit
+ in a byte has the lowest number; otherwise define it to have the
+ value zero. This means that bit-field instructions count from the
+ most significant bit. If the machine has no bit-field
+ instructions, then this must still be defined, but it doesn't
+ matter which value it is defined to. This macro need not be a
+ constant.
+
+ This macro does not affect the way structure fields are packed into
+ bytes or words; that is controlled by `BYTES_BIG_ENDIAN'. */
+#define BITS_BIG_ENDIAN 1
+
+/* `BYTES_BIG_ENDIAN'
+
+ Define this macro to have the value 1 if the most significant byte
+ in a word has the lowest number. This macro need not be a
+ constant.*/
+#define BYTES_BIG_ENDIAN 1
+
+/* `WORDS_BIG_ENDIAN'
+
+ Define this macro to have the value 1 if, in a multiword object,
+ the most significant word has the lowest number. This applies to
+ both memory locations and registers; GNU CC fundamentally assumes
+ that the order of words in memory is the same as the order in
+ registers. This macro need not be a constant. */
+#define WORDS_BIG_ENDIAN 1
+
+/* `BITS_PER_WORD'
+
+ Number of bits in a word; normally 32. */
+#define BITS_PER_WORD 32
+
+/* `UNITS_PER_WORD'
+
+ Number of storage units in a word; normally 4. */
+#define UNITS_PER_WORD 4
+
+/* `POINTER_SIZE'
+
+ Width of a pointer, in bits. You must specify a value no wider
+ than the width of `Pmode'. If it is not equal to the width of
+ `Pmode', you must define `POINTERS_EXTEND_UNSIGNED'. */
+#define POINTER_SIZE 32
+
+/* `PARM_BOUNDARY'
+
+ Normal alignment required for function parameters on the stack, in
+ bits. All stack parameters receive at least this much alignment
+ regardless of data type. On most machines, this is the same as the
+ size of an integer. */
+#define PARM_BOUNDARY 32
+
+/* `STACK_BOUNDARY'
+
+ Define this macro if you wish to preserve a certain alignment for
+ the stack pointer. The definition is a C expression for the
+ desired alignment (measured in bits).
+
+ If `PUSH_ROUNDING' is not defined, the stack will always be aligned
+ to the specified boundary. If `PUSH_ROUNDING' is defined and
+ specifies a less strict alignment than `STACK_BOUNDARY', the stack
+ may be momentarily unaligned while pushing arguments. */
+#define STACK_BOUNDARY 32
+
+#define VISIUM_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
+
+/* `FUNCTION_BOUNDARY'
+
+ Alignment required for a function entry point, in bits. */
+#define FUNCTION_BOUNDARY 32
+
+/* `BIGGEST_ALIGNMENT'
+
+ Biggest alignment that any data type can require on this machine,
+ in bits. */
+#define BIGGEST_ALIGNMENT 32
+
+/* `DATA_ALIGNMENT (TYPE, BASIC-ALIGN)`
+
+ If defined, a C expression to compute the alignment for a variable
+ in the static store. TYPE is the data type, and BASIC-ALIGN is
+ the alignment that the object would ordinarily have. The value of
+ this macro is used instead of that alignment to align the object. */
+#define DATA_ALIGNMENT(TYPE,ALIGN) visium_data_alignment (TYPE, ALIGN)
+
+/* `CONSTANT_ALIGNMENT (CONSTANT, BASIC-ALIGN)`
+
+ If defined, a C expression to compute the alignment given to a
+ constant that is being placed in memory. CONSTANT is the constant
+ and BASIC-ALIGN is the alignment that the object would ordinarily
+ have. The value of this macro is used instead of that alignment to
+ align the object. */
+#define CONSTANT_ALIGNMENT(EXP,ALIGN) \
+ visium_data_alignment (TREE_TYPE (EXP), ALIGN)
+
+/* `LOCAL_ALIGNMENT (TYPE, BASIC-ALIGN)`
+
+ If defined, a C expression to compute the alignment for a variable
+ in the local store. TYPE is the data type, and BASIC-ALIGN is the
+ alignment that the object would ordinarily have. The value of this
+ macro is used instead of that alignment to align the object. */
+#define LOCAL_ALIGNMENT(TYPE,ALIGN) visium_data_alignment (TYPE, ALIGN)
+
+/* `EMPTY_FIELD_BOUNDARY'
+
+ Alignment in bits to be given to a structure bit field that follows
+ an empty field such as `int : 0;'.
+
+ Note that `PCC_BITFIELD_TYPE_MATTERS' also affects the alignment
+ that results from an empty field. */
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* `STRICT_ALIGNMENT'
+
+ Define this macro to be the value 1 if instructions will fail to
+ work if given data not on the nominal alignment. If instructions
+ will merely go slower in that case, define this macro as 0. */
+#define STRICT_ALIGNMENT 1
+
+/* `TARGET_FLOAT_FORMAT'
+
+ A code distinguishing the floating point format of the target
+ machine. There are three defined values:
+
+ `IEEE_FLOAT_FORMAT'
+ This code indicates IEEE floating point. It is the default;
+ there is no need to define this macro when the format is IEEE.
+
+ `VAX_FLOAT_FORMAT'
+ This code indicates the peculiar format used on the Vax.
+
+ `UNKNOWN_FLOAT_FORMAT'
+ This code indicates any other format.
+
+ The value of this macro is compared with `HOST_FLOAT_FORMAT' to
+ determine whether the target machine has the same format as the
+ host machine. If any other formats are actually in use on
+ supported machines, new codes should be defined for them.
+
+ The ordering of the component words of floating point values
+ stored in memory is controlled by `FLOAT_WORDS_BIG_ENDIAN' for the
+ target machine and `HOST_FLOAT_WORDS_BIG_ENDIAN' for the host. */
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+#define UNITS_PER_HWFPVALUE 4
+
+/* Layout of Source Language Data Types
+
+ These macros define the sizes and other characteristics of the
+ standard basic data types used in programs being compiled. Unlike
+ the macros in the previous section, these apply to specific
+ features of C and related languages, rather than to fundamental
+ aspects of storage layout. */
+
+/* `INT_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `int' on the target
+ machine. If you don't define this, the default is one word. */
+#define INT_TYPE_SIZE 32
+
+/* `SHORT_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `short' on the
+ target machine. If you don't define this, the default is half a
+ word. (If this would be less than one storage unit, it is rounded
+ up to one unit.) */
+#define SHORT_TYPE_SIZE 16
+
+/* `LONG_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `long' on the
+ target machine. If you don't define this, the default is one word. */
+#define LONG_TYPE_SIZE 32
+
+/* `LONG_LONG_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `long long' on the
+ target machine. If you don't define this, the default is two
+ words. If you want to support GNU Ada on your machine, the value
+ of macro must be at least 64. */
+#define LONG_LONG_TYPE_SIZE 64
+
+/* `CHAR_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `char' on the
+ target machine. If you don't define this, the default is one
+ quarter of a word. (If this would be less than one storage unit,
+ it is rounded up to one unit.) */
+#define CHAR_TYPE_SIZE 8
+
+/* `FLOAT_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `float' on the
+ target machine. If you don't define this, the default is one word. */
+#define FLOAT_TYPE_SIZE 32
+
+/* `DOUBLE_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `double' on the
+ target machine. If you don't define this, the default is two
+ words. */
+#define DOUBLE_TYPE_SIZE 64
+
+/* `LONG_DOUBLE_TYPE_SIZE'
+
+ A C expression for the size in bits of the type `long double' on
+ the target machine. If you don't define this, the default is two
+ words. */
+#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE
+
+/* `WIDEST_HARDWARE_FP_SIZE'
+
+ A C expression for the size in bits of the widest floating-point
+ format supported by the hardware. If you define this macro, you
+ must specify a value less than or equal to the value of
+ `LONG_DOUBLE_TYPE_SIZE'. If you do not define this macro, the
+ value of `LONG_DOUBLE_TYPE_SIZE' is the default. */
+
+/* `DEFAULT_SIGNED_CHAR'
+
+ An expression whose value is 1 or 0, according to whether the type
+ `char' should be signed or unsigned by default. The user can
+ always override this default with the options `-fsigned-char' and
+ `-funsigned-char'. */
+#define DEFAULT_SIGNED_CHAR 0
+
+/* `SIZE_TYPE'
+
+ A C expression for a string describing the name of the data type to
+ use for size values. The typedef name `size_t' is defined using
+ the contents of the string.
+
+ The string can contain more than one keyword. If so, separate them
+ with spaces, and write first any length keyword, then `unsigned' if
+ appropriate, and finally `int'. The string must exactly match one
+ of the data type names defined in the function
+ `init_decl_processing' in the file `c-decl.c'. You may not omit
+ `int' or change the order--that would cause the compiler to crash
+ on startup.
+
+ If you don't define this macro, the default is `"long unsigned
+ int"'. */
+#define SIZE_TYPE "unsigned int"
+
+/* `PTRDIFF_TYPE'
+
+ A C expression for a string describing the name of the data type to
+ use for the result of subtracting two pointers. The typedef name
+ `ptrdiff_t' is defined using the contents of the string. See
+ `SIZE_TYPE' above for more information.
+
+ If you don't define this macro, the default is `"long int"'. */
+#define PTRDIFF_TYPE "long int"
+
+/* Newlib uses the unsigned type corresponding to ptrdiff_t for
+ uintptr_t; this is the same as size_t for most newlib-using
+ targets, but not for us. */
+#define UINTPTR_TYPE "long unsigned int"
+
+/* `WCHAR_TYPE'
+
+ A C expression for a string describing the name of the data type to
+ use for wide characters. The typedef name `wchar_t' is defined
+ using the contents of the string. See `SIZE_TYPE' above for more
+ information.
+
+ If you don't define this macro, the default is `"int"'. */
+#define WCHAR_TYPE "short int"
+
+/* `WCHAR_TYPE_SIZE'
+
+ A C expression for the size in bits of the data type for wide
+ characters. This is used in `cpp', which cannot make use of
+ `WCHAR_TYPE'. */
+#define WCHAR_TYPE_SIZE 16
+
+/* Register Usage
+
+ This section explains how to describe what registers the target
+ machine has, and how (in general) they can be used. */
+
+/* `FIRST_PSEUDO_REGISTER'
+
+ Number of actual hardware registers.
+ The hardware registers are assigned numbers for the compiler
+ from 0 to just below FIRST_PSEUDO_REGISTER.
+ All registers that the compiler knows about must be given numbers,
+ even those that are not normally considered general registers.
+
+ Register 51 is used as the argument pointer register.
+ Register 52 is used as the soft frame pointer register. */
+#define FIRST_PSEUDO_REGISTER 53
+
+#define RETURN_REGNUM 1
+#define PROLOGUE_TMP_REGNUM 9
+#define LINK_REGNUM 21
+#define GP_LAST_REGNUM 31
+#define GP_REGISTER_P(REGNO) \
+ (((unsigned) (REGNO)) <= GP_LAST_REGNUM)
+
+#define MDB_REGNUM 32
+#define MDC_REGNUM 33
+
+#define FP_FIRST_REGNUM 34
+#define FP_LAST_REGNUM 49
+#define FP_RETURN_REGNUM (FP_FIRST_REGNUM + 1)
+#define FP_REGISTER_P(REGNO) \
+ (FP_FIRST_REGNUM <= (REGNO) && (REGNO) <= FP_LAST_REGNUM)
+
+#define FLAGS_REGNUM 50
+
+/* `FIXED_REGISTERS'
+
+ An initializer that says which registers are used for fixed
+ purposes all throughout the compiled code and are therefore not
+ available for general allocation. These would include the stack
+ pointer, the frame pointer (except on machines where that can be
+ used as a general register when no frame pointer is needed), the
+ program counter on machines where that is considered one of the
+ addressable registers, and any other numbered register with a
+ standard use.
+
+ This information is expressed as a sequence of numbers, separated
+ by commas and surrounded by braces. The Nth number is 1 if
+ register N is fixed, 0 otherwise.
+
+ The table initialized from this macro, and the table initialized by
+ the following one, may be overridden at run time either
+ automatically, by the actions of the macro
+ `CONDITIONAL_REGISTER_USAGE', or by the user with the command
+ options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'.
+
+ r0 and f0 are immutable registers hardwired to 0.
+ r21 is the link register used for procedure linkage.
+ r23 is the stack pointer register.
+ r29 and r30 hold the interrupt context.
+ mdc is a read-only register because the writemdc instruction
+ terminates all the operations of the EAM on the GR6. */
+#define FIXED_REGISTERS \
+ { 1, 0, 0, 0, 0, 0, 0, 0, /* r0 .. r7 */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, /* r8 .. r15 */ \
+ 0, 0, 0, 0, 0, 1, 0, 1, /* r16 .. r23 */ \
+ 0, 0, 0, 0, 0, 1, 1, 0, /* r24 .. r31 */ \
+ 0, 1, /* mdb, mdc */ \
+ 1, 0, 0, 0, 0, 0, 0, 0, /* f0 .. f7 */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \
+ 1, 1, 1 } /* flags, arg, frame */
+
+/* `CALL_USED_REGISTERS'
+
+ Like `FIXED_REGISTERS' but has 1 for each register that is
+ clobbered (in general) by function calls as well as for fixed
+ registers. This macro therefore identifies the registers that are
+ not available for general allocation of values that must live
+ across function calls.
+
+ If a register has 0 in `CALL_USED_REGISTERS', the compiler
+ automatically saves it on function entry and restores it on
+ function exit, if the register is used within the function. */
+#define CALL_USED_REGISTERS \
+ { 1, 1, 1, 1, 1, 1, 1, 1, /* r0 .. r7 */ \
+ 1, 1, 1, 0, 0, 0, 0, 0, /* r8 .. r15 */ \
+ 0, 0, 0, 0, 1, 1, 0, 1, /* r16 .. r23 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, /* r24 .. r31 */ \
+ 1, 1, /* mdb, mdc */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, /* f0 .. f7 */ \
+ 1, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \
+ 1, 1, 1 } /* flags, arg, frame */
+
+/* Like `CALL_USED_REGISTERS' except this macro doesn't require that
+ the entire set of `FIXED_REGISTERS' be included.
+ (`CALL_USED_REGISTERS' must be a superset of `FIXED_REGISTERS').
+ This macro is optional. If not specified, it defaults to the value
+ of `CALL_USED_REGISTERS'. */
+#define CALL_REALLY_USED_REGISTERS \
+ { 0, 1, 1, 1, 1, 1, 1, 1, /* r0 .. r7 */ \
+ 1, 1, 1, 0, 0, 0, 0, 0, /* r8 .. r15 */ \
+ 0, 0, 0, 0, 1, 0, 0, 0, /* r16 .. r23 */ \
+ 1, 1, 1, 1, 1, 0, 0, 1, /* r24 .. r31 */ \
+ 1, 1, /* mdb, mdc */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, /* f0 .. f7 */ \
+ 1, 0, 0, 0, 0, 0, 0, 0, /* f8 .. f15 */ \
+ 1, 0, 0 } /* flags, arg, frame */
+
+/* `REG_ALLOC_ORDER'
+
+ If defined, an initializer for a vector of integers, containing the
+ numbers of hard registers in the order in which GCC should prefer
+ to use them (from most preferred to least).
+
+ If this macro is not defined, registers are used lowest numbered
+ first (all else being equal). */
+#define REG_ALLOC_ORDER \
+ { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, /* r10 .. r1 */ \
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, /* r11 .. r20 */ \
+ 22, /* fp */ \
+ 24, 25, 26, 27, 28, /* r24 .. r28 */ \
+ 31, /* r31 */ \
+ 32, 33, /* mdb, mdc */ \
+ 42, 41, 40, 39, 38, 37, 36, 35, /* f8 .. f1 */ \
+ 43, 44, 45, 46, 47, 48, 49, /* f9 .. f15 */ \
+ 21, 23, /* lr, sp */ \
+ 29, 30, /* r29, r30 */ \
+ 50, 51, 52, /* flags, arg, frame */ \
+ 0, 34 } /* r0, f0 */
+
+/* `HARD_REGNO_NREGS (REGNO, MODE)'
+
+ A C expression for the number of consecutive hard registers,
+ starting at register number REGNO, required to hold a value of mode
+ MODE. */
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((REGNO) == MDB_REGNUM ? \
+ ((GET_MODE_SIZE (MODE) + 2 * UNITS_PER_WORD - 1) / (2 * UNITS_PER_WORD)) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* `HARD_REGNO_RENAME_OK (OLD_REG, NEW_REG)'
+
+ A C expression which is nonzero if hard register NEW_REG can be
+ considered for use as a rename register for hard register OLD_REG. */
+#define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \
+ visium_hard_regno_rename_ok (OLD_REG, NEW_REG)
+
+/* `HARD_REGNO_MODE_OK (REGNO, MODE)'
+
+ A C expression that is nonzero if it is permissible to store a
+ value of mode MODE in hard register number REGNO (or in several
+ registers starting with that one).
+
+ Modes with sizes which cross from the one register class to the
+ other cannot be allowed. Only single floats are allowed in the
+ floating point registers, and only fixed point values in the EAM
+ registers. */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ (GP_REGISTER_P (REGNO) ? \
+ GP_REGISTER_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1) \
+ : FP_REGISTER_P (REGNO) ? \
+ (MODE) == SFmode || ((MODE) == SImode && TARGET_FPU_IEEE) \
+ : GET_MODE_CLASS (MODE) == MODE_INT \
+ && HARD_REGNO_NREGS (REGNO, MODE) == 1)
+
+/* `MODES_TIEABLE_P (MODE1, MODE2)'
+
+ A C expression that is nonzero if a value of mode MODE1 is
+ accessible in mode MODE2 without copying.
+
+ If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R,
+ MODE2)' are always the same for any R, then `MODES_TIEABLE_P
+ (MODE1, MODE2)' should be nonzero. If they differ for any R, you
+ should define this macro to return zero unless some other mechanism
+ ensures the accessibility of the value in a narrower mode.
+
+ You should define this macro to return nonzero in as many cases as
+ possible since doing so will allow GNU CC to perform better
+ register allocation. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((GET_MODE_CLASS (MODE1) == MODE_INT) \
+ && (GET_MODE_CLASS (MODE2) == MODE_INT))
+
+/* Register Classes
+
+ On many machines, the numbered registers are not all equivalent.
+ For example, certain registers may not be allowed for indexed
+ addressing; certain registers may not be allowed in some
+ instructions. These machine restrictions are described to the
+ compiler using "register classes".
+
+ `enum reg_class'
+
+ An enumeral type that must be defined with all the register class
+ names as enumeral values. `NO_REGS' must be first. `ALL_REGS'
+ must be the last register class, followed by one more enumeral
+ value, `LIM_REG_CLASSES', which is not a register class but rather
+ tells how many classes there are.
+
+ Each register class has a number, which is the value of casting the
+ class name to type `int'. The number serves as an index in many of
+ the tables described below. */
+
+enum reg_class
+{
+ NO_REGS,
+ MDB,
+ MDC,
+ FP_REGS,
+ FLAGS,
+ R1,
+ R2,
+ R3,
+ SIBCALL_REGS,
+ LOW_REGS,
+ GENERAL_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+/* `N_REG_CLASSES'
+
+ The number of distinct register classes, defined as follows. */
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* `REG_CLASS_NAMES'
+
+ An initializer containing the names of the register classes as C
+ string constants. These names are used in writing some of the
+ debugging dumps. */
+#define REG_CLASS_NAMES \
+ {"NO_REGS", "MDB", "MDC", "FP_REGS", "FLAGS", "R1", "R2", "R3", \
+ "SIBCALL_REGS", "LOW_REGS", "GENERAL_REGS", "ALL_REGS"}
+
+/* `REG_CLASS_CONTENTS'
+
+ An initializer containing the contents of the register classes, as
+ integers which are bit masks. The Nth integer specifies the
+ contents of class N. The way the integer MASK is interpreted is
+ that register R is in the class if `MASK & (1 << R)' is 1.
+
+ When the machine has more than 32 registers, an integer does not
+ suffice. Then the integers are replaced by sub-initializers,
+ braced groupings containing several integers. Each sub-initializer
+ must be suitable as an initializer for the type `HARD_REG_SET'
+ which is defined in `hard-reg-set.h'. */
+#define REG_CLASS_CONTENTS { \
+ {0x00000000, 0x00000000}, /* NO_REGS */ \
+ {0x00000000, 0x00000001}, /* MDB */ \
+ {0x00000000, 0x00000002}, /* MDC */ \
+ {0x00000000, 0x0003fffc}, /* FP_REGS */ \
+ {0x00000000, 0x00040000}, /* FLAGS */ \
+ {0x00000002, 0x00000000}, /* R1 */ \
+ {0x00000004, 0x00000000}, /* R2 */ \
+ {0x00000008, 0x00000000}, /* R3 */ \
+ {0x000005ff, 0x00000000}, /* SIBCALL_REGS */ \
+ {0x1fffffff, 0x00000000}, /* LOW_REGS */ \
+ {0xffffffff, 0x00180000}, /* GENERAL_REGS */ \
+ {0xffffffff, 0x001fffff}} /* ALL_REGS */
+
+/* `REGNO_REG_CLASS (REGNO)'
+
+ A C expression whose value is a register class containing hard
+ register REGNO. In general there is more than one such class;
+ choose a class which is "minimal", meaning that no smaller class
+ also contains the register. */
+#define REGNO_REG_CLASS(REGNO) \
+ ((REGNO) == MDB_REGNUM ? MDB : \
+ (REGNO) == MDC_REGNUM ? MDC : \
+ FP_REGISTER_P (REGNO) ? FP_REGS : \
+ (REGNO) == FLAGS_REGNUM ? FLAGS : \
+ (REGNO) == 1 ? R1 : \
+ (REGNO) == 2 ? R2 : \
+ (REGNO) == 3 ? R3 : \
+ (REGNO) <= 8 || (REGNO) == 10 ? SIBCALL_REGS : \
+ (REGNO) <= 28 ? LOW_REGS : \
+ GENERAL_REGS)
+
+/* `BASE_REG_CLASS'
+
+ A macro whose definition is the name of the class to which a valid
+ base register must belong. A base register is one used in an
+ address which is the register value plus a displacement. */
+#define BASE_REG_CLASS GENERAL_REGS
+
+#define BASE_REGISTER_P(REGNO) \
+ (GP_REGISTER_P (REGNO) \
+ || (REGNO) == ARG_POINTER_REGNUM \
+ || (REGNO) == FRAME_POINTER_REGNUM)
+
+/* `INDEX_REG_CLASS'
+
+ A macro whose definition is the name of the class to which a valid
+ index register must belong. An index register is one used in an
+ address where its value is either multiplied by a scale factor or
+ added to another register (as well as added to a displacement). */
+#define INDEX_REG_CLASS NO_REGS
+
+/* `REGNO_OK_FOR_BASE_P (NUM)'
+
+ A C expression which is nonzero if register number NUM is suitable
+ for use as a base register in operand addresses. It may be either
+ a suitable hard register or a pseudo register that has been
+ allocated such a hard register. */
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ (BASE_REGISTER_P (REGNO) || BASE_REGISTER_P ((unsigned)reg_renumber[REGNO]))
+
+/* `REGNO_OK_FOR_INDEX_P (NUM)'
+
+ A C expression which is nonzero if register number NUM is suitable
+ for use as an index register in operand addresses. It may be
+ either a suitable hard register or a pseudo register that has been
+ allocated such a hard register.
+
+ The difference between an index register and a base register is
+ that the index register may be scaled. If an address involves the
+ sum of two registers, neither one of them scaled, then either one
+ may be labeled the "base" and the other the "index"; but whichever
+ labeling is used must fit the machine's constraints of which
+ registers may serve in each capacity. The compiler will try both
+ labelings, looking for one that is valid, and will reload one or
+ both registers only if neither labeling works. */
+#define REGNO_OK_FOR_INDEX_P(REGNO) 0
+
+/* `PREFERRED_RELOAD_CLASS (X, CLASS)'
+
+ A C expression that places additional restrictions on the register
+ class to use when it is necessary to copy value X into a register
+ in class CLASS. The value is a register class; perhaps CLASS, or
+ perhaps another, smaller class.
+
+ Sometimes returning a more restrictive class makes better code.
+ For example, on the 68000, when X is an integer constant that is in
+ range for a `moveq' instruction, the value of this macro is always
+ `DATA_REGS' as long as CLASS includes the data registers.
+ Requiring a data register guarantees that a `moveq' will be used.
+
+ If X is a `const_double', by returning `NO_REGS' you can force X
+ into a memory constant. This is useful on certain machines where
+ immediate floating values cannot be loaded into certain kinds of
+ registers. */
+#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+
+/* `CANNOT_CHANGE_MODE_CLASS (from, to, class)
+
+ If defined, a C expression that returns nonzero for a `class' for
+ which a change from mode `from' to mode `to' is invalid.
+
+ It's not obvious from the above that MDB cannot change mode. However
+ difficulties arise from expressions of the form
+
+ (subreg:SI (reg:DI R_MDB) 0)
+
+ There is no way to convert that reference to a single machine
+ register and, without the following definition, reload will quietly
+ convert it to
+
+ (reg:SI R_MDB) */
+#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \
+ (CLASS == MDB ? (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) : 0)
+
+/* `CLASS_MAX_NREGS (CLASS, MODE)'
+
+ A C expression for the maximum number of consecutive registers of
+ class CLASS needed to hold a value of mode MODE.
+
+ This is closely related to the macro `HARD_REGNO_NREGS'. In fact,
+ the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be
+ the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO
+ values in the class CLASS.
+
+ This macro helps control the handling of multiple-word values in
+ the reload pass. */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((CLASS) == MDB ? \
+ ((GET_MODE_SIZE (MODE) + 2 * UNITS_PER_WORD - 1) / (2 * UNITS_PER_WORD)) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* Stack Layout and Calling Conventions
+
+ Basic Stack Layout
+
+ `STACK_GROWS_DOWNWARD'
+ Define this macro if pushing a word onto the stack moves the stack
+ pointer to a smaller address. */
+#define STACK_GROWS_DOWNWARD 1
+
+/* `STARTING_FRAME_OFFSET'
+
+ Offset from the frame pointer to the first local variable slot to
+ be allocated.
+
+ If `FRAME_GROWS_DOWNWARD', find the next slot's offset by
+ subtracting the first slot's length from `STARTING_FRAME_OFFSET'.
+ Otherwise, it is found by adding the length of the first slot to
+ the value `STARTING_FRAME_OFFSET'. */
+#define STARTING_FRAME_OFFSET 0
+
+/* `FIRST_PARM_OFFSET (FUNDECL)'
+
+ Offset from the argument pointer register to the first argument's
+ address. On some machines it may depend on the data type of the
+ function.
+
+ If `ARGS_GROW_DOWNWARD', this is the offset to the location above
+ the first argument's address. */
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+/* `DYNAMIC_CHAIN_ADDRESS (FRAMEADDR)'
+
+ A C expression whose value is RTL representing the address in a
+ stack frame where the pointer to the caller's frame is stored.
+ Assume that FRAMEADDR is an RTL expression for the address of the
+ stack frame itself.
+
+ If you don't define this macro, the default is to return the value
+ of FRAMEADDR--that is, the stack frame address is also the address
+ of the stack word that points to the previous frame. */
+#define DYNAMIC_CHAIN_ADDRESS(FRAMEADDR) \
+ visium_dynamic_chain_address (FRAMEADDR)
+
+/* `RETURN_ADDR_RTX (COUNT, FRAMEADDR)'
+
+ A C expression whose value is RTL representing the value of the
+ return address for the frame COUNT steps up from the current frame,
+ after the prologue. FRAMEADDR is the frame pointer of the COUNT
+ frame, or the frame pointer of the COUNT - 1 frame if
+ `RETURN_ADDR_IN_PREVIOUS_FRAME' is defined.
+
+ The value of the expression must always be the correct address when
+ COUNT is zero, but may be `NULL_RTX' if there is not way to
+ determine the return address of other frames. */
+#define RETURN_ADDR_RTX(COUNT,FRAMEADDR) \
+ visium_return_addr_rtx (COUNT, FRAMEADDR)
+
+/* Exception Handling
+
+ `EH_RETURN_DATA_REGNO'
+
+ A C expression whose value is the Nth register number used for data
+ by exception handlers or INVALID_REGNUM if fewer than N registers
+ are available.
+
+ The exception handling library routines communicate with the
+ exception handlers via a set of agreed upon registers. */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 11 : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (SImode, 8)
+#define EH_RETURN_HANDLER_RTX visium_eh_return_handler_rtx ()
+
+/* Registers That Address the Stack Frame
+
+ This discusses registers that address the stack frame.
+
+ `STACK_POINTER_REGNUM'
+
+ The register number of the stack pointer register, which must also
+ be a fixed register according to `FIXED_REGISTERS'. On most
+ machines, the hardware determines which register this is. */
+#define STACK_POINTER_REGNUM 23
+
+/* `FRAME_POINTER_REGNUM'
+
+ The register number of the frame pointer register, which is used to
+ access automatic variables in the stack frame. On some machines,
+ the hardware determines which register this is. On other machines,
+ you can choose any register you wish for this purpose. */
+#define FRAME_POINTER_REGNUM 52
+
+/* `HARD_FRAME_POINTER_REGNUM'
+
+ On some machines the offset between the frame pointer and starting
+ offset of the automatic variables is not known until after register
+ allocation has been done (for example, because the saved registers
+ are between these two locations). On those machines, define
+ `FRAME_POINTER_REGNUM' the number of a special, fixed register to
+ be used internally until the offset is known, and define
+ `HARD_FRAME_POINTER_REGNUM' to be the actual hard register number
+ used for the frame pointer. */
+#define HARD_FRAME_POINTER_REGNUM 22
+
+/* `ARG_POINTER_REGNUM'
+
+ The register number of the arg pointer register, which is used to
+ access the function's argument list. On some machines, this is the
+ same as the frame pointer register. On some machines, the hardware
+ determines which register this is. On other machines, you can
+ choose any register you wish for this purpose. If this is not the
+ same register as the frame pointer register, then you must mark it
+ as a fixed register according to `FIXED_REGISTERS', or arrange to
+ be able to eliminate it (*note Elimination::.). */
+#define ARG_POINTER_REGNUM 51
+
+/* `STATIC_CHAIN_REGNUM'
+ `STATIC_CHAIN_INCOMING_REGNUM'
+
+ Register numbers used for passing a function's static chain
+ pointer. If register windows are used, the register number as seen
+ by the called function is `STATIC_CHAIN_INCOMING_REGNUM', while the
+ register number as seen by the calling function is
+ `STATIC_CHAIN_REGNUM'. If these registers are the same,
+ `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
+
+ The static chain register need not be a fixed register.
+
+ If the static chain is passed in memory, these macros should not be
+ defined; instead, the next two macros should be defined. */
+#define STATIC_CHAIN_REGNUM 20
+
+/* `ELIMINABLE_REGS'
+
+ If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. If
+ it is not defined, the only elimination attempted by the compiler
+ is to replace references to the frame pointer with references to
+ the stack pointer.
+
+ The definition of this macro is a list of structure
+ initializations, each of which specifies an original and
+ replacement register.
+
+ On some machines, the position of the argument pointer is not known
+ until the compilation is completed. In such a case, a separate
+ hard register must be used for the argument pointer. This register
+ can be eliminated by replacing it with either the frame pointer or
+ the argument pointer, depending on whether or not the frame pointer
+ has been eliminated.
+
+ Note that the elimination of the argument pointer with the stack
+ pointer is specified first since that is the preferred elimination. */
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+
+/* `INITIAL_ELIMINATION_OFFSET (FROM-REG, TO-REG, OFFSET-VAR)'
+
+ This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It
+ specifies the initial difference between the specified pair of
+ registers. This macro must be defined if `ELIMINABLE_REGS' is
+ defined. */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET = visium_initial_elimination_offset (FROM, TO))
+
+/* Passing Function Arguments on the Stack
+
+ The macros in this section control how arguments are passed on the
+ stack. See the following section for other macros that control
+ passing certain arguments in registers.
+
+ Passing Arguments in Registers
+
+ This section describes the macros which let you control how various
+ types of arguments are passed in registers or how they are arranged
+ in the stack.
+
+ Define the general purpose, and floating point registers used for
+ passing arguments */
+#define MAX_ARGS_IN_GP_REGISTERS 8
+#define GP_ARG_FIRST 1
+#define GP_ARG_LAST (GP_ARG_FIRST + MAX_ARGS_IN_GP_REGISTERS - 1)
+#define MAX_ARGS_IN_FP_REGISTERS 8
+#define FP_ARG_FIRST (FP_FIRST_REGNUM + 1)
+#define FP_ARG_LAST (FP_ARG_FIRST + MAX_ARGS_IN_FP_REGISTERS - 1)
+
+/* Define a data type for recording info about an argument list during the
+processing of that argument list. */
+
+struct visium_args
+{
+ /* The count of general registers used */
+ int grcount;
+ /* The count of floating registers used */
+ int frcount;
+ /* The number of stack words used by named arguments */
+ int stack_words;
+};
+
+/* `CUMULATIVE_ARGS'
+
+ A C type for declaring a variable that is used as the first
+ argument of `FUNCTION_ARG' and other related values. For some
+ target machines, the type `int' suffices and can hold the number of
+ bytes of argument so far.
+
+ There is no need to record in `CUMULATIVE_ARGS' anything about the
+ arguments that have been passed on the stack. The compiler has
+ other variables to keep track of that. For target machines on
+ which all arguments are passed on the stack, there is no need to
+ store anything in `CUMULATIVE_ARGS'; however, the data structure
+ must exist and should not be empty, so use `int'. */
+#define CUMULATIVE_ARGS struct visium_args
+
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS) \
+ do { \
+ (CUM).grcount = 0; \
+ (CUM).frcount = 0; \
+ (CUM).stack_words = 0; \
+ } while (0)
+
+/* `FUNCTION_ARG_REGNO_P (REGNO)'
+
+ A C expression that is nonzero if REGNO is the number of a hard
+ register in which function arguments are sometimes passed. This
+ does *not* include implicit arguments such as the static chain and
+ the structure-value address. On many machines, no registers can be
+ used for this purpose since all function arguments are pushed on
+ the stack. */
+#define FUNCTION_ARG_REGNO_P(N) \
+ ((GP_ARG_FIRST <= (N) && (N) <= GP_ARG_LAST) \
+ || (TARGET_FPU && FP_ARG_FIRST <= (N) && (N) <= FP_ARG_LAST))
+
+/* `FUNCTION_VALUE_REGNO_P (REGNO)'
+
+ A C expression that is nonzero if REGNO is the number of a hard
+ register in which the values of called function may come back.
+
+ A register whose use for returning values is limited to serving as
+ the second of a pair (for a value of type `double', say) need not
+ be recognized by this macro. If the machine has register windows,
+ so that the caller and the called function use different registers
+ for the return value, this macro should recognize only the caller's
+ register numbers. */
+#define FUNCTION_VALUE_REGNO_P(N) \
+ ((N) == RETURN_REGNUM || (TARGET_FPU && (N) == FP_RETURN_REGNUM))
+
+/* How Large Values Are Returned
+
+ When a function value's mode is `BLKmode' (and in some other
+ cases), the value is not returned according to `FUNCTION_VALUE'.
+ Instead, the caller passes the address of a block of memory in
+ which the value should be stored. This address is called the
+ "structure value address".
+
+ This section describes how to control returning structure values in
+ memory.
+
+ `DEFAULT_PCC_STRUCT_RETURN'
+
+ Define this macro to be 1 if all structure and union return values
+ must be in memory. Since this results in slower code, this should
+ be defined only if needed for compatibility with other compilers or
+ with an ABI. If you define this macro to be 0, then the
+ conventions used for structure and union return values are decided
+ by the `RETURN_IN_MEMORY' macro.
+
+ If not defined, this defaults to the value 1. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* `STRUCT_VALUE'
+
+ If the structure value address is not passed in a register, define
+ `STRUCT_VALUE' as an expression returning an RTX for the place
+ where the address is passed. If it returns 0, the address is
+ passed as an "invisible" first argument. */
+#define STRUCT_VALUE 0
+
+/* Caller-Saves Register Allocation
+
+ If you enable it, GNU CC can save registers around function calls.
+ This makes it possible to use call-clobbered registers to hold
+ variables that must live across calls.
+
+ Function Entry and Exit
+
+ This section describes the macros that output function entry
+ ("prologue") and exit ("epilogue") code.
+
+ `EXIT_IGNORE_STACK'
+
+ Define this macro as a C expression that is nonzero if the return
+ instruction or the function epilogue ignores the value of the stack
+ pointer; in other words, if it is safe to delete an instruction to
+ adjust the stack pointer before a return from the function.
+
+ Note that this macro's value is relevant only for functions for
+ which frame pointers are maintained. It is never safe to delete a
+ final stack adjustment in a function that has no frame pointer, and
+ the compiler knows this regardless of `EXIT_IGNORE_STACK'. */
+#define EXIT_IGNORE_STACK 1
+
+/* `EPILOGUE_USES (REGNO)'
+
+ Define this macro as a C expression that is nonzero for registers
+ are used by the epilogue or the `return' pattern. The stack and
+ frame pointer registers are already be assumed to be used as
+ needed. */
+#define EPILOGUE_USES(REGNO) visium_epilogue_uses (REGNO)
+
+/* Generating Code for Profiling
+
+ These macros will help you generate code for profiling. */
+
+#define PROFILE_HOOK(LABEL) visium_profile_hook ()
+#define FUNCTION_PROFILER(FILE, LABELNO) do {} while (0)
+#define NO_PROFILE_COUNTERS 1
+
+/* Trampolines for Nested Functions
+
+ A trampoline is a small piece of code that is created at run time
+ when the address of a nested function is taken. It normally resides
+ on the stack, in the stack frame of the containing function. These
+ macros tell GCC how to generate code to allocate and initialize a
+ trampoline.
+
+ The instructions in the trampoline must do two things: load a
+ constant address into the static chain register, and jump to the
+ real address of the nested function. On CISC machines such as the
+ m68k, this requires two instructions, a move immediate and a
+ jump. Then the two addresses exist in the trampoline as word-long
+ immediate operands. On RISC machines, it is often necessary to load
+ each address into a register in two parts. Then pieces of each
+ address form separate immediate operands.
+
+ The code generated to initialize the trampoline must store the
+ variable parts--the static chain value and the function
+ address--into the immediate operands of the instructions. On a CISC
+ machine, this is simply a matter of copying each address to a
+ memory reference at the proper offset from the start of the
+ trampoline. On a RISC machine, it may be necessary to take out
+ pieces of the address and store them separately.
+
+ On the Visium, the trampoline is
+
+ moviu r9,%u FUNCTION
+ movil r9,%l FUNCTION
+ moviu r20,%u STATIC
+ bra tr,r9,r0
+ movil r20,%l STATIC
+
+ A difficulty is setting the correct instruction parity at run time.
+
+
+ TRAMPOLINE_SIZE
+ A C expression for the size in bytes of the trampoline, as an integer. */
+#define TRAMPOLINE_SIZE 20
+
+/* Implicit calls to library routines
+
+ Avoid calling library routines (sqrtf) just to set `errno' to EDOM */
+#define TARGET_EDOM 33
+
+/* Addressing Modes
+
+ `MAX_REGS_PER_ADDRESS'
+
+ A number, the maximum number of registers that can appear in a
+ valid memory address. Note that it is up to you to specify a value
+ equal to the maximum number that `TARGET_LEGITIMATE_ADDRESS_P' would
+ ever accept. */
+#define MAX_REGS_PER_ADDRESS 1
+
+/* `LEGITIMIZE_RELOAD_ADDRESS (X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)'
+
+ A C compound statement that attempts to replace X, which is an
+ address that needs reloading, with a valid memory address for an
+ operand of mode MODE. WIN will be a C statement label elsewhere
+ in the code. It is not necessary to define this macro, but it
+ might be useful for performance reasons. */
+#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \
+do \
+{ \
+ rtx new_x = visium_legitimize_reload_address ((AD), (MODE), (OPNUM), \
+ (int) (TYPE), (IND)); \
+ if (new_x) \
+ { \
+ (AD) = new_x; \
+ goto WIN; \
+ } \
+} while (0)
+
+/* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
+ return the mode to be used for the comparison. */
+#define SELECT_CC_MODE(OP,X,Y) visium_select_cc_mode ((OP), (X), (Y))
+
+/* Return nonzero if MODE implies a floating point inequality can be
+ reversed. For Visium this is always true because we have a full
+ compliment of ordered and unordered comparisons, but until generic
+ code knows how to reverse it correctly we keep the old definition. */
+#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode && (MODE) != CCFPmode)
+
+/* `BRANCH_COST'
+
+ A C expression for the cost of a branch instruction. A value of 1
+ is the default; other values are interpreted relative to that. */
+#define BRANCH_COST(A,B) 10
+
+/* Override BRANCH_COST heuristics for complex logical ops. */
+#define LOGICAL_OP_NON_SHORT_CIRCUIT 0
+
+/* `SLOW_BYTE_ACCESS'
+
+ Define this macro as a C expression which is nonzero if accessing
+ less than a word of memory (i.e. a `char' or a `short') is no
+ faster than accessing a word of memory, i.e., if such access
+ require more than one instruction or if there is no difference in
+ cost between byte and (aligned) word loads.
+
+ When this macro is not defined, the compiler will access a field by
+ finding the smallest containing object; when it is defined, a
+ fullword load will be used if alignment permits. Unless bytes
+ accesses are faster than word accesses, using word accesses is
+ preferable since it may eliminate subsequent memory access if
+ subsequent accesses occur to other fields in the same word of the
+ structure, but to different bytes. */
+#define SLOW_BYTE_ACCESS 0
+
+/* `MOVE_RATIO (SPEED)`
+
+ The threshold of number of scalar memory-to-memory move insns,
+ _below_ which a sequence of insns should be generated instead of a
+ string move insn or a library call. Increasing the value will
+ always make code faster, but eventually incurs high cost in
+ increased code size.
+
+ Since we have a movmemsi pattern, the default MOVE_RATIO is 2, which
+ is too low given that movmemsi will invoke a libcall. */
+#define MOVE_RATIO(speed) ((speed) ? 9 : 3)
+
+/* `CLEAR_RATIO (SPEED)`
+
+ The threshold of number of scalar move insns, _below_ which a
+ sequence of insns should be generated to clear memory instead of a
+ string clear insn or a library call. Increasing the value will
+ always make code faster, but eventually incurs high cost in
+ increased code size.
+
+ Since we have a setmemsi pattern, the default CLEAR_RATIO is 2, which
+ is too low given that setmemsi will invoke a libcall. */
+#define CLEAR_RATIO(speed) ((speed) ? 13 : 5)
+
+/* `MOVE_MAX'
+
+ The maximum number of bytes that a single instruction can move
+ quickly between memory and registers or between two memory
+ locations. */
+#define MOVE_MAX 4
+
+/* `MAX_MOVE_MAX'
+
+ The maximum number of bytes that a single instruction can move
+ quickly between memory and registers or between two memory
+ locations. If this is undefined, the default is `MOVE_MAX'.
+ Otherwise, it is the constant value that is the largest value that
+ `MOVE_MAX' can have at run-time. */
+#define MAX_MOVE_MAX 4
+
+/* `SHIFT_COUNT_TRUNCATED'
+
+ A C expression that is nonzero if on this machine the number of
+ bits actually used for the count of a shift operation is equal to
+ the number of bits needed to represent the size of the object being
+ shifted. When this macro is non-zero, the compiler will assume
+ that it is safe to omit a sign-extend, zero-extend, and certain
+ bitwise `and' instructions that truncates the count of a shift
+ operation. On machines that have instructions that act on
+ bitfields at variable positions, which may include `bit test'
+ instructions, a nonzero `SHIFT_COUNT_TRUNCATED' also enables
+ deletion of truncations of the values that serve as arguments to
+ bitfield instructions. */
+#define SHIFT_COUNT_TRUNCATED 0
+
+/* `TRULY_NOOP_TRUNCATION (OUTPREC, INPREC)'
+
+ A C expression which is nonzero if on this machine it is safe to
+ "convert" an integer of INPREC bits to one of OUTPREC bits (where
+ OUTPREC is smaller than INPREC) by merely operating on it as if it
+ had only OUTPREC bits.
+
+ On many machines, this expression can be 1.
+
+ When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for
+ modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result.
+ If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in
+ such cases may improve things. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* `STORE_FLAG_VALUE'
+
+ A C expression describing the value returned by a comparison
+ operator with an integral mode and stored by a store-flag
+ instruction (`sCOND') when the condition is true. This description
+ must apply to *all* the `sCOND' patterns and all the comparison
+ operators whose results have a `MODE_INT' mode. */
+#define STORE_FLAG_VALUE 1
+
+/* `Pmode'
+
+ An alias for the machine mode for pointers. On most machines,
+ define this to be the integer mode corresponding to the width of a
+ hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit
+ machines. On some machines you must define this to be one of the
+ partial integer modes, such as `PSImode'.
+
+ The width of `Pmode' must be at least as large as the value of
+ `POINTER_SIZE'. If it is not equal, you must define the macro
+ `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to
+ `Pmode'. */
+#define Pmode SImode
+
+/* `FUNCTION_MODE'
+
+ An alias for the machine mode used for memory references to
+ functions being called, in `call' RTL expressions. On most
+ machines this should be `QImode'. */
+#define FUNCTION_MODE SImode
+
+/* `NO_IMPLICIT_EXTERN_C'
+
+ Define this macro if the system header files support C++ as well as
+ C. This macro inhibits the usual method of using system header
+ files in C++, which is to pretend that the file's contents are
+ enclosed in `extern "C" {...}'. */
+#define NO_IMPLICIT_EXTERN_C
+
+/* Dividing the Output into Sections (Texts, Data, ...)
+
+ An object file is divided into sections containing different types
+ of data. In the most common case, there are three sections: the
+ "text section", which holds instructions and read-only data; the
+ "data section", which holds initialized writable data; and the "bss
+ section", which holds uninitialized data. Some systems have other
+ kinds of sections.
+
+ `TEXT_SECTION_ASM_OP'
+
+ A C expression whose value is a string containing the assembler
+ operation that should precede instructions and read-only data.
+ Normally `".text"' is right. */
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+/* `DATA_SECTION_ASM_OP'
+
+ A C expression whose value is a string containing the assembler
+ operation to identify the following data as writable initialized
+ data. Normally `".data"' is right. */
+#define DATA_SECTION_ASM_OP "\t.data"
+
+/* `BSS_SECTION_ASM_OP'
+
+ If defined, a C expression whose value is a string containing the
+ assembler operation to identify the following data as uninitialized
+ global data. If not defined, and neither `ASM_OUTPUT_BSS' nor
+ `ASM_OUTPUT_ALIGNED_BSS' are defined, uninitialized global data
+ will be output in the data section if `-fno-common' is passed,
+ otherwise `ASM_OUTPUT_COMMON' will be used.
+
+ `EXTRA_SECTIONS'
+
+ A list of names for sections other than the standard two, which are
+ `in_text' and `in_data'. You need not define this macro on a
+ system with no other sections (that GCC needs to use).
+
+ `EXTRA_SECTION_FUNCTIONS'
+
+ One or more functions to be defined in `varasm.c'. These functions
+ should do jobs analogous to those of `text_section' and
+ `data_section', for your additional sections. Do not define this
+ macro if you do not define `EXTRA_SECTIONS'.
+
+ `JUMP_TABLES_IN_TEXT_SECTION' Define this macro if jump tables (for
+ `tablejump' insns) should be output in the text section, along with
+ the assembler instructions. Otherwise, the readonly data section
+ is used.
+
+ This macro is irrelevant if there is no separate readonly data
+ section. */
+#undef JUMP_TABLES_IN_TEXT_SECTION
+
+
+/* The Overall Framework of an Assembler File
+
+ This describes the overall framework of an assembler file.
+
+ `ASM_COMMENT_START'
+
+ A C string constant describing how to begin a comment in the target
+ assembler language. The compiler assumes that the comment will end
+ at the end of the line. */
+#define ASM_COMMENT_START ";"
+
+/* `ASM_APP_ON'
+
+ A C string constant for text to be output before each `asm'
+ statement or group of consecutive ones. Normally this is `"#APP"',
+ which is a comment that has no effect on most assemblers but tells
+ the GNU assembler that it must check the lines that follow for all
+ valid assembler constructs. */
+#define ASM_APP_ON "#APP\n"
+
+/* `ASM_APP_OFF'
+
+ A C string constant for text to be output after each `asm'
+ statement or group of consecutive ones. Normally this is
+ `"#NO_APP"', which tells the GNU assembler to resume making the
+ time-saving assumptions that are valid for ordinary compiler
+ output. */
+#define ASM_APP_OFF "#NO_APP\n"
+
+/* Output of Data
+
+ This describes data output.
+
+ Output and Generation of Labels
+
+ This is about outputting labels.
+
+ `ASM_OUTPUT_LABEL (STREAM, NAME)'
+
+ A C statement (sans semicolon) to output to the stdio stream STREAM
+ the assembler definition of a label named NAME. Use the expression
+ `assemble_name (STREAM, NAME)' to output the name itself; before
+ and after that, output the additional assembler syntax for defining
+ the name, and a newline. */
+#define ASM_OUTPUT_LABEL(STREAM,NAME) \
+ do { assemble_name (STREAM, NAME); fputs (":\n", STREAM); } while (0)
+
+/* Globalizing directive for a label */
+#define GLOBAL_ASM_OP "\t.global "
+
+/* `ASM_OUTPUT_LABELREF (STREAM, NAME)'
+
+ A C statement (sans semicolon) to output to the stdio stream STREAM
+ a reference in assembler syntax to a label named NAME. This should
+ add `_' to the front of the name, if that is customary on your
+ operating system, as it is in most Berkeley Unix systems. This
+ macro is used in `assemble_name'. */
+#define ASM_OUTPUT_LABELREF(STREAM,NAME) \
+ asm_fprintf (STREAM, "%U%s", NAME)
+
+/* Output of Assembler Instructions
+
+ This describes assembler instruction output.
+
+ `REGISTER_NAMES'
+
+ A C initializer containing the assembler's names for the machine
+ registers, each one as a C string constant. This is what
+ translates register numbers in the compiler into assembler
+ language. */
+#define REGISTER_NAMES \
+ {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "r16", "r17", "r18", "r19", "r20", "r21", "fp", "sp", \
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
+ "mdb", "mdc", \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "flags","argp","sfp" }
+
+/* `ADDITIONAL_REGISTER_NAMES`
+
+ If defined, a C initializer for an array of structures containing
+ a name and a register number. This macro defines additional names
+ for hard registers, thus allowing the `asm' option in declarations
+ to refer to registers using alternate names. */
+#define ADDITIONAL_REGISTER_NAMES \
+ {{"r22", HARD_FRAME_POINTER_REGNUM}, {"r23", STACK_POINTER_REGNUM}}
+
+/* `PRINT_OPERAND (STREAM, X, CODE)'
+
+ A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand X. X is an RTL
+ expression.
+
+ CODE is a value that can be used to specify one of several ways of
+ printing the operand. It is used when identical operands must be
+ printed differently depending on the context. CODE comes from the
+ `%' specification that was used to request printing of the operand.
+ If the specification was just `%DIGIT' then CODE is 0; if the
+ specification was `%LTR DIGIT' then CODE is the ASCII code for LTR.
+
+ If X is a register, this macro should print the register's name.
+ The names can be found in an array `reg_names' whose type is `char
+ *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
+
+ When the machine description has a specification `%PUNCT' (a `%'
+ followed by a punctuation character), this macro is called with a
+ null pointer for X and the punctuation character for CODE. */
+#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE)
+
+/* `PRINT_OPERAND_PUNCT_VALID_P (CODE)'
+
+ A C expression which evaluates to true if CODE is a valid
+ punctuation character for use in the `PRINT_OPERAND' macro. If
+ `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no
+ punctuation characters (except for the standard one, `%') are used */
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '#')
+
+/* `PRINT_OPERAND_ADDRESS (STREAM, X)'
+
+ A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand that is a memory
+ reference whose address is X. X is an RTL expression.
+
+ On some machines, the syntax for a symbolic address depends on the
+ section that the address refers to. On these machines, define the
+ macro `ENCODE_SECTION_INFO' to store the information into the
+ `symbol_ref', and then check for it here. */
+#define PRINT_OPERAND_ADDRESS(STREAM, ADDR) \
+ print_operand_address (STREAM, ADDR)
+
+/* `REGISTER_PREFIX'
+ `LOCAL_LABEL_PREFIX'
+ `USER_LABEL_PREFIX'
+ `IMMEDIATE_PREFIX'
+
+ If defined, C string expressions to be used for the `%R', `%L',
+ `%U', and `%I' options of `asm_fprintf' (see `final.c'). These are
+ useful when a single `md' file must support multiple assembler
+ formats. In that case, the various `tm.h' files can define these
+ macros differently. */
+#define REGISTER_PREFIX ""
+#define LOCAL_LABEL_PREFIX "."
+#define IMMEDIATE_PREFIX "#"
+
+/* `ASM_OUTPUT_REG_PUSH (STREAM, REGNO)'
+
+ A C expression to output to STREAM some assembler code which will
+ push hard register number REGNO onto the stack. The code need not
+ be optimal, since this macro is used only when profiling. */
+#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \
+ asm_fprintf (STREAM, "\tsubi sp,4\n\twrite.l (sp),%s\n", \
+ reg_names[REGNO])
+
+/* `ASM_OUTPUT_REG_POP (STREAM, REGNO)'
+
+ A C expression to output to STREAM some assembler code which will
+ pop hard register number REGNO off of the stack. The code need not
+ be optimal, since this macro is used only when profiling. */
+#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \
+ asm_fprintf (STREAM, "\tread.l %s,(sp)\n\taddi sp,4\n", \
+ reg_names[REGNO])
+
+
+/* Output of Dispatch Tables
+
+ This concerns dispatch tables.
+
+ `ASM_OUTPUT_ADDR_DIFF_ELT (STREAM, VALUE, REL)'
+
+ A C statement to output to the stdio stream STREAM an assembler
+ pseudo-instruction to generate a difference between two labels.
+ VALUE and REL are the numbers of two internal labels. The
+ definitions of these labels are output using
+ `ASM_OUTPUT_INTERNAL_LABEL', and they must be printed in the same
+ way here.
+
+ You must provide this macro on machines where the addresses in a
+ dispatch table are relative to the table's own address. If
+ defined, GNU CC will also use this macro on all machines when
+ producing PIC. */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \
+ switch (GET_MODE (BODY)) \
+ { \
+ case SImode: \
+ asm_fprintf ((STREAM), "\t.long\t%LL%d-%LL%d\n", (VALUE),(REL)); \
+ break; \
+ case HImode: \
+ asm_fprintf ((STREAM), "\t.word\t%LL%d-%LL%d\n", (VALUE),(REL)); \
+ break; \
+ case QImode: \
+ asm_fprintf ((STREAM), "\t.byte\t%LL%d-%LL%d\n", (VALUE),(REL)); \
+ break; \
+ default: \
+ break; \
+ }
+
+/* `ASM_OUTPUT_ADDR_VEC_ELT (STREAM, VALUE)'
+
+ This macro should be provided on machines where the addresses in a
+ dispatch table are absolute.
+
+ The definition should be a C statement to output to the stdio
+ stream STREAM an assembler pseudo-instruction to generate a
+ reference to a label. VALUE is the number of an internal label
+ whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+ asm_fprintf (STREAM, "\t.long %LL%d\n", VALUE)
+
+/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)'
+
+ Define this if something special must be output at the end of a
+ jump-table. The definition should be a C statement to be executed
+ after the assembler code for the table is written. It should write
+ the appropriate code to stdio stream STREAM. The argument TABLE is
+ the jump-table insn, and NUM is the label-number of the preceding
+ label.
+
+ If this macro is not defined, nothing special is output at the end
+ of a jump table.
+
+ Here we output a word of zero so that jump-tables can be seperated
+ in reverse assembly. */
+#define ASM_OUTPUT_CASE_END(STREAM, NUM, TABLE) \
+ asm_fprintf (STREAM, "\t.long 0\n");
+
+/* Assembler Commands for Alignment
+
+ This describes commands for alignment.
+
+ `ASM_OUTPUT_ALIGN_CODE (STREAM)'
+
+ A C expression to output text to align the location counter in the
+ way that is desirable at a point in the code that is reached only
+ by jumping.
+
+ This macro need not be defined if you don't want any special
+ alignment to be done at such a time. Most machine descriptions do
+ not currently define the macro. */
+#undef ASM_OUTPUT_ALIGN_CODE
+
+/* `ASM_OUTPUT_LOOP_ALIGN (STREAM)'
+
+ A C expression to output text to align the location counter in the
+ way that is desirable at the beginning of a loop.
+
+ This macro need not be defined if you don't want any special
+ alignment to be done at such a time. Most machine descriptions do
+ not currently define the macro. */
+#undef ASM_OUTPUT_LOOP_ALIGN
+
+/* `ASM_OUTPUT_ALIGN (STREAM, POWER)'
+
+ A C statement to output to the stdio stream STREAM an assembler
+ command to advance the location counter to a multiple of 2 to the
+ POWER bytes. POWER will be a C expression of type `int'. */
+#define ASM_OUTPUT_ALIGN(STREAM,LOG) \
+ if ((LOG) != 0) \
+ fprintf (STREAM, "\t.align %d\n", (1<<(LOG)))
+
+/* `ASM_OUTPUT_MAX_SKIP_ALIGN (STREAM, POWER, MAX_SKIP)`
+
+ A C statement to output to the stdio stream STREAM an assembler
+ command to advance the location counter to a multiple of 2 to the
+ POWER bytes, but only if MAX_SKIP or fewer bytes are needed to
+ satisfy the alignment request. POWER and MAX_SKIP will be a C
+ expression of type `int'. */
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM,LOG,MAX_SKIP) \
+ if ((LOG) != 0) { \
+ if ((MAX_SKIP) == 0) fprintf ((STREAM), "\t.p2align %d\n", (LOG)); \
+ else { \
+ fprintf ((STREAM), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \
+ /* Make sure that we have at least 8-byte alignment if > 8-byte \
+ alignment is preferred. */ \
+ if ((LOG) > 3 \
+ && (1 << (LOG)) > ((MAX_SKIP) + 1) \
+ && (MAX_SKIP) >= 7) \
+ fputs ("\t.p2align 3\n", (STREAM)); \
+ } \
+ }
+
+/* Controlling Debugging Information Format
+
+ This describes how to specify debugging information.
+
+ mda is known to GDB, but not to GCC. */
+#define DBX_REGISTER_NUMBER(REGNO) \
+ ((REGNO) > MDB_REGNUM ? (REGNO) + 1 : (REGNO))
+
+/* `DEBUGGER_AUTO_OFFSET (X)'
+
+ A C expression that returns the integer offset value for an
+ automatic variable having address X (an RTL expression). The
+ default computation assumes that X is based on the frame-pointer
+ and gives the offset from the frame-pointer. This is required for
+ targets that produce debugging output for DBX or COFF-style
+ debugging output for SDB and allow the frame-pointer to be
+ eliminated when the `-g' options is used. */
+#define DEBUGGER_AUTO_OFFSET(X) \
+ (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)
+
+/* Miscellaneous Parameters
+
+ `CASE_VECTOR_MODE'
+
+ An alias for a machine mode name. This is the machine mode that
+ elements of a jump-table should have. */
+#define CASE_VECTOR_MODE SImode
+
+/* `CASE_VECTOR_PC_RELATIVE'
+ Define this macro if jump-tables should contain relative addresses. */
+#undef CASE_VECTOR_PC_RELATIVE
+
+/* This says how to output assembler code to declare an
+ unitialised external linkage data object. */
+#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
+( fputs ("\n\t.comm ", (STREAM)), \
+ assemble_name ((STREAM), (NAME)), \
+ fprintf ((STREAM), ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", ROUNDED))
+
+/* This says how to output assembler code to declare an
+ unitialised internal linkage data object. */
+#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \
+( fputs ("\n\t.lcomm ", (STREAM)), \
+ assemble_name ((STREAM), (NAME)), \
+ fprintf ((STREAM), ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", ROUNDED))
+
+/* Prettify the assembly. */
+extern int visium_indent_opcode;
+
+#define ASM_OUTPUT_OPCODE(FILE, PTR) \
+ do { \
+ if (visium_indent_opcode) \
+ { \
+ putc (' ', FILE); \
+ visium_indent_opcode = 0; \
+ } \
+ } while (0)
diff --git a/gcc/config/visium/visium.md b/gcc/config/visium/visium.md
new file mode 100644
index 00000000000..969cb887a6c
--- /dev/null
+++ b/gcc/config/visium/visium.md
@@ -0,0 +1,2749 @@
+;; Machine description for Visium.
+;; Copyright (C) 2002-2015 Free Software Foundation, Inc.
+;; Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Extra register constraints are:
+;; 'b' EAM register mdb
+;; 'c' EAM register mdc
+;; 'f' Floating-point register
+;; 'k' Register that can be used as the target of a sibcall, i.e. call-used
+;; general register not clobbered in the epilogue: r1-r8 and r10
+;; 'l' Low general register, i.e. general register accessible in user mode
+;; on the GR6 and, consequently, that can be used as the target of a
+;; branch with prediction: r1-r28
+;; 't' Register r1
+;; 'u' Register r2
+;; 'v' Register r3
+;;
+;; Immediate integer operand constraints are:
+;; 'J' 0 .. 65535 (16-bit immediate)
+;; 'K' 1 .. 31 (5-bit immediate)
+;; 'L' -1 .. -65535 (16-bit negative immediate)
+;; 'M' -1 (minus one)
+;; 'O' 0 (integer zero)
+;; 'P' 32 (thirty two)
+;;
+;; Immediate FP operand constraints are:
+;; 'G' 0.0 (floating-point zero)
+;;
+;; Operand substitution characters are:
+;; %# delay slot follows, if empty, fill with NOP
+;; %b LS 8 bits of immediate operand
+;; %w LS 16 bits of immediate operand
+;; %u MS 16 bits of immediate operand
+;; %r register or zero (r0)
+;; %f FP register or zero (f0)
+;; %d second register in a pair
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+;; Registers by name.
+(define_constants [
+ (R_R1 1)
+ (R_R2 2)
+ (R_R3 3)
+ (R_R4 4)
+ (R_R5 5)
+ (R_R6 6)
+ (R_LINK 21)
+ (R_FP 22)
+ (R_SP 23)
+ (R_MDB 32)
+ (R_MDC 33)
+ (R_FLAGS 50)
+])
+
+;; UNSPEC usage.
+(define_c_enum "unspec" [
+ UNSPEC_MDBHI
+ UNSPEC_FLOAD
+ UNSPEC_FSTORE
+ UNSPEC_ITOF
+ UNSPEC_FTOI
+ UNSPEC_NOP
+])
+
+;; UNSPEC_VOLATILE usage.
+(define_c_enum "unspecv" [
+ UNSPECV_BLOCKAGE
+ UNSPECV_DSI
+])
+
+(include "predicates.md")
+(include "constraints.md")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Attributes.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; Instruction type.
+;
+;imm_reg Move of immediate value to register.
+;mem_reg Move from memory to register.
+;eam_reg Move from EAM to register.
+;fp_reg Move from FPU to register.
+;reg_mem Move from register to memory.
+;reg_eam Move from register to EAM.
+;reg_fp Move from register to FPU.
+;arith Arithmetic operation, result in register, sets overflow.
+;arith2 Two successive arithmetic operations.
+;logic Logical operation, result in register, does not set overflow.
+;abs_branch Absolute branch.
+;branch Branch.
+;bmi Block move.
+;call Call to subprogram.
+;ret Return from subprogram.
+;rfi Return from interrupt.
+;dsi Disable interrupts.
+;cmp Compare or test.
+;div EAM 32/32 division.
+;divd EAM 64/32 division.
+;mul EAM 32 * 32 -> 64 multiplication.
+;shiftdi EAM 64 bit shift.
+;fdiv Floating point divide.
+;fsqrt Floating point square root.
+;ftoi Fix float to integer.
+;itof Float integer.
+;fmove Floating point move w/ or w/o change of sign: fmove, fabs, fneg.
+;fcmp Floating point compare or test.
+;fp Other floating point operations.
+;nop No operation.
+;multi Multiple instructions which split.
+;asm User asm instructions.
+
+(define_attr "type"
+"imm_reg,mem_reg,eam_reg,fp_reg,reg_mem,reg_eam,reg_fp,arith,arith2,logic,abs_branch,branch,bmi,call,ret,rfi,dsi,cmp,div,divd,mul,shiftdi,fdiv,fsqrt,ftoi,itof,fmove,fcmp,fp,nop,multi,asm" (const_string "logic"))
+
+; Those insns that occupy 4 bytes.
+(define_attr "single_insn" "no,yes"
+ (if_then_else (eq_attr "type" "arith2,rfi,multi")
+ (const_string "no")
+ (const_string "yes")))
+
+; True if branch or call will be emitting a nop into its delay slot.
+(define_attr "empty_delay_slot" "false,true"
+ (symbol_ref "(empty_delay_slot (insn)
+ ? EMPTY_DELAY_SLOT_TRUE : EMPTY_DELAY_SLOT_FALSE)"))
+
+; Length in bytes.
+; The allowed range for the offset of short branches is [-131072;131068]
+; and it is counted from the address of the insn so we need to subtract
+; 8 for forward branches because (pc) points to the next insn for them.
+(define_attr "length" ""
+ (cond [(eq_attr "type" "abs_branch,call,ret")
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 8)
+ (const_int 4))
+ (eq_attr "type" "branch")
+ (if_then_else (leu (plus (minus (match_dup 0) (pc))
+ (const_int 131060))
+ (const_int 262120))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 8)
+ (const_int 4))
+ (const_int 20))
+ (eq_attr "single_insn" "no")
+ (const_int 8)] (const_int 4)))
+
+(define_asm_attributes [(set_attr "type" "asm")])
+
+; Delay slots.
+(define_delay (eq_attr "type" "abs_branch,branch,call,ret")
+ [(and (eq_attr "type" "!abs_branch,branch,call,ret,rfi,bmi,mul,div,divd,fdiv,fsqrt,asm")
+ (eq_attr "single_insn" "yes"))
+ (nil) (nil)])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Processor pipeline description.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; Attribute for cpu type.
+; These must match the values for enum processor_type in visium-opts.h.
+(define_attr "cpu" "gr5,gr6" (const (symbol_ref "visium_cpu_attr")))
+
+(include "gr5.md")
+(include "gr6.md")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Iterators.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_mode_iterator QHI [QI HI])
+(define_mode_iterator I [QI HI SI])
+(define_mode_attr s [(QI ".b") (HI ".w") (SI ".l")])
+
+; This code iterator allows signed and unsigned widening multiplications
+; to use the same template.
+(define_code_iterator any_extend [sign_extend zero_extend])
+
+; <u> expands to an empty string when doing a signed operation and
+; "u" when doing an unsigned operation.
+(define_code_attr u [(sign_extend "") (zero_extend "u")])
+
+; <su> is like <u>, but the signed form expands to "s" rather than "".
+(define_code_attr su [(sign_extend "s") (zero_extend "u")])
+
+; This code iterator allows returns and simple returns to use the same template.
+(define_code_iterator any_return [return simple_return])
+(define_code_attr return_pred [(return "visium_can_use_return_insn_p ()")
+ (simple_return "!visium_interrupt_function_p ()")])
+(define_code_attr return_str [(return "") (simple_return "simple_")])
+
+; This code iterator allows integer and FP cstores to use the same template.
+(define_code_iterator any_scc [ltu lt])
+(define_code_attr scc_str [(ltu "sltu") (lt "slt")])
+
+;This code iterator allows cstore splitters to use the same template.
+(define_code_iterator any_add [plus minus])
+(define_code_attr add_op [(plus "PLUS") (minus "MINUS")])
+(define_code_attr add_str [(plus "plus") (minus "minus")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Substitutions.
+;;
+;; They are used to define the second instruction of the pairs required by
+;; the postreload compare elimination pass, with a first variant for the
+;; logical insns and a second variant for the arithmetic insns.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_subst "flags_subst_logic"
+ [(set (match_operand 0 "") (match_operand 1 ""))
+ (clobber (reg:CC R_FLAGS))]
+ ""
+ [(set (match_dup 0) (match_dup 1))
+ (set (reg:CC R_FLAGS)
+ (compare:CC (match_dup 1) (const_int 0)))])
+
+(define_subst_attr "subst_logic" "flags_subst_logic" "_flags" "_set_flags")
+
+(define_subst "flags_subst_arith"
+ [(set (match_operand 0 "") (match_operand 1 ""))
+ (clobber (reg:CC R_FLAGS))]
+ ""
+ [(set (match_dup 0) (match_dup 1))
+ (set (reg:CC_NOOV R_FLAGS)
+ (compare:CC_NOOV (match_dup 1) (const_int 0)))])
+
+(define_subst_attr "subst_arith" "flags_subst_arith" "_flags" "_set_flags")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; QImode moves
+;;
+;; For moving among registers we use the move.b instruction. This is
+;; actually an OR instruction using an alias. For moving between register
+;; and memory we need the address of the memory location in a register.
+;; However, we can accept an expression (reg + offset) where offset is in
+;; the range 0 .. 31.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, QImode);
+})
+
+(define_insn "*movqi_insn"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r")
+ (match_operand:QI 1 "general_operand" " r,rO, r, r,?b,?c,i,m"))]
+ "ok_for_simple_move_operands (operands, QImode)"
+ "@
+ #
+ write.b %0,%r1
+ writemd %1,r0 ;movqi ?b r
+ writemdc %1 ;movqi ?c r
+ readmda %0 ;movqi r ?b
+ readmdc %0 ;movqi r ?c
+ moviq %0,%b1 ;movqi r i
+ read.b %0,%1"
+ [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,mem_reg")])
+
+(define_insn "*movqi_insn<subst_logic>"
+ [(set (match_operand:QI 0 "gpc_reg_operand" "=r")
+ (match_operand:QI 1 "gpc_reg_operand" "r"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.b %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (match_operand:QI 0 "gpc_reg_operand" "")
+ (match_operand:QI 1 "gpc_reg_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+(define_expand "movstrictqi"
+ [(set (strict_low_part (match_operand:QI 0 "register_operand" ""))
+ (match_operand:QI 1 "general_operand" ""))]
+ "")
+
+(define_insn "*movstrictqi_insn"
+ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r,r"))
+ (match_operand:QI 1 "general_operand" "rO,m"))]
+ "ok_for_simple_move_strict_operands (operands, QImode)"
+ "@
+ #
+ read.b %0,%1"
+ [(set_attr "type" "logic,mem_reg")])
+
+(define_insn "*movstrictqi_insn<subst_logic>"
+ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
+ (match_operand:QI 1 "reg_or_0_operand" "rO"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.b %0,%r1"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (strict_low_part (match_operand:QI 0 "register_operand" ""))
+ (match_operand:QI 1 "reg_or_0_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (strict_low_part (match_dup 0)) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; HImode moves
+;;
+;; For moving among registers we use the move.w instruction. This is
+;; actually an OR instruction using an alias. For moving between register
+;; and memory we need the address of the memory location in a register.
+;; However, we can accept an expression (reg + offset) where offset is in
+;; the range 0 .. 62 and is shifted right one place in the assembled
+;; instruction.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, HImode);
+})
+
+(define_insn "*movhi_insn"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r")
+ (match_operand:HI 1 "general_operand" " r,rO, r, r,?b,?c,i,m"))]
+ "ok_for_simple_move_operands (operands, HImode)"
+ "@
+ #
+ write.w %0,%r1
+ writemd %1,r0 ;movhi ?b r
+ writemdc %1 ;movhi ?c r
+ readmda %0 ;movhi r ?b
+ readmdc %0 ;movhi r ?c
+ moviq %0,%w1 ;movhi r i
+ read.w %0,%1"
+ [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,mem_reg")])
+
+(define_insn "*movhi_insn<subst_logic>"
+ [(set (match_operand:HI 0 "gpc_reg_operand" "=r")
+ (match_operand:HI 1 "gpc_reg_operand" "r"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.w %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (match_operand:HI 0 "gpc_reg_operand" "")
+ (match_operand:HI 1 "gpc_reg_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+(define_expand "movstricthi"
+ [(set (strict_low_part (match_operand:HI 0 "register_operand" ""))
+ (match_operand:HI 1 "general_operand" ""))]
+ "")
+
+(define_insn "*movstricthi_insn"
+ [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r,r,r"))
+ (match_operand:HI 1 "general_operand" " r,i,m"))]
+ "ok_for_simple_move_strict_operands (operands, HImode)"
+ "@
+ #
+ movil %0,%w1
+ read.w %0,%1"
+ [(set_attr "type" "logic,imm_reg,mem_reg")])
+
+(define_insn "*movstricthi_insn<subst_logic>"
+ [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
+ (match_operand:HI 1 "register_operand" "r"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.w %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (strict_low_part (match_operand:HI 0 "register_operand" ""))
+ (match_operand:HI 1 "register_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (strict_low_part (match_dup 0)) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; SImode moves
+;;
+;; For moving among registers we use the move.l instruction. This is
+;; actually an OR instruction using an alias. For moving between register
+;; and memory we need the address of the memory location in a register.
+;; However, we can accept an expression (reg + offset) where offset is in
+;; the range 0 .. 124 and is shifted right two places in the assembled
+;; instruction.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, SImode);
+})
+
+(define_insn "*movsi_high"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (high:SI (match_operand:SI 1 "immediate_operand" "n,i")) )]
+ ""
+ "@
+ moviu %0,%u1
+ moviu %0,%%u %a1"
+ [(set_attr "type" "imm_reg")])
+
+; We only care about the lower 16 bits of the constant
+; being inserted into the upper 16 bits of the register.
+(define_insn "*moviu"
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (const_int 16)
+ (const_int 0))
+ (match_operand:SI 1 "const_int_operand" "n"))]
+ ""
+ "moviu %0,%w1"
+ [(set_attr "type" "imm_reg")])
+
+(define_insn "*movsi_losum"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "immediate_operand" "n,i")))]
+ ""
+ "@
+ movil %0,%w2
+ movil %0,%%l %a2"
+ [(set_attr "type" "imm_reg")])
+
+(define_insn "*movil"
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (const_int 16)
+ (const_int 16))
+ (match_operand:SI 1 "const_int_operand" "n"))]
+ ""
+ "movil %0,%w1"
+ [(set_attr "type" "imm_reg")])
+
+(define_insn "*movsi_insn_no_ieee"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r,r,r, r,!f")
+ (match_operand:SI 1 "general_operand" " r,rO, r, r,?b,?c,J,M,i,m,!f, r"))]
+ "!TARGET_FPU_IEEE && ok_for_simple_move_operands (operands, SImode)"
+ "@
+ #
+ write.l %0,%r1
+ writemd %1,r0 ;movsi ?b r
+ writemdc %1 ;movsi ?c r
+ readmda %0 ;movsi r ?b
+ readmdc %0 ;movsi r ?c
+ moviq %0,%1 ;movsi r J
+ #
+ # ;movsi r i
+ read.l %0,%1
+ fstore %0,%1
+ fload %0,%1"
+ [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,logic,multi,mem_reg,fp_reg,reg_fp")])
+
+(define_insn "*movsi_insn"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m,?b,?c, r, r,r,r,r,r, r,?f,f")
+ (match_operand:SI 1 "general_operand" " r,rO, r, r,?b,?c,J,M,i,m,?f, r,f"))]
+ "TARGET_FPU_IEEE && ok_for_simple_move_operands (operands, SImode)"
+ "@
+ #
+ write.l %0,%r1
+ writemd %1,r0 ;movsi ?b r
+ writemdc %1 ;movsi ?c r
+ readmda %0 ;movsi r ?b
+ readmdc %0 ;movsi r ?c
+ moviq %0,%1 ;movsi r J
+ #
+ # ;movsi r i
+ read.l %0,%1
+ fstore %0,%1
+ fload %0,%1
+ fmove %0,%1"
+ [(set_attr "type" "logic,reg_mem,reg_eam,reg_eam,eam_reg,eam_reg,imm_reg,logic,multi,mem_reg,fp_reg,reg_fp,fmove")])
+
+(define_insn "*movsi_insn<subst_logic>"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.l %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_insn "*movsi_insn_m1<subst_logic>"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (const_int -1))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "not.l %0,r0"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_operand:SI 1 "gpc_reg_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (const_int -1))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (const_int -1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+(define_insn "*movsi_mdbhi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI))]
+ ""
+ "readmdb %0"
+ [(set_attr "type" "eam_reg")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_operand:SI 1 "large_immediate_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (high:SI (match_dup 1)) )
+ (set (match_dup 0)
+ (lo_sum:SI (match_dup 0) (match_dup 1)))]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; DImode moves
+;;
+;; When the destination is the EAM register MDB, then we use the writemd
+;; instruction. In all other cases we split the move into two 32-bit moves.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, DImode);
+})
+
+(define_insn "*movdi_insn"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "= r, m, r,??b")
+ (match_operand:DI 1 "general_operand" "rim,rO,?b, r"))]
+ "ok_for_simple_move_operands (operands, DImode)"
+ "@
+ #
+ #
+ #
+ writemd %d1,%1 ;movdi ?b r"
+ [(set_attr "type" "multi,multi,multi,reg_eam")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "") (reg:DI R_MDB))]
+ "reload_completed"
+ [(set (match_dup 1) (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI))
+ (set (match_dup 2) (reg:SI R_MDB))]
+{
+ operands[1] = operand_subword (operands[0], 0, 1, DImode);
+ operands[2] = operand_subword (operands[0], 1, 1, DImode);
+})
+
+(define_split
+ [(set (match_operand:DI 0 "non_eam_dst_operand" "")
+ (match_operand:DI 1 "non_eam_src_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+{
+ split_double_move (operands, DImode);
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; SFmode moves
+;;
+;; Constants are constructed in a GP register and moved to the FP register.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, SFmode);
+})
+
+(define_insn "*movsf_insn"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,r,r, m,r,r,r")
+ (match_operand:SF 1 "general_operand" " f,G,r,f,r,rG,G,F,m"))]
+ "ok_for_simple_move_operands (operands, SFmode)"
+ "@
+ fmove %0,%1
+ fmove %0,f0
+ fload %0,%1
+ fstore %0,%1
+ #
+ write.l %0,%r1
+ moviq %0,0
+ #
+ read.l %0,%1"
+ [(set_attr "type" "fmove,fmove,reg_fp,fp_reg,logic,reg_mem,imm_reg,multi,mem_reg")])
+
+(define_insn "*movsf_insn"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=r")
+ (match_operand:SF 1 "gpc_reg_operand" "r"))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.l %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (match_operand:SF 1 "gpc_reg_operand" ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (match_operand:SF 1 "const_double_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 3))]
+{
+ long l;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ operands[2] = operand_subword (operands[0], 0, 0, SFmode);
+ operands[3] = GEN_INT (trunc_int_for_mode (l, SImode));
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; DFmode moves
+;;
+;; We always split a DFmode move into two SImode moves.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, DFmode);
+})
+
+(define_insn "*movdf_insn"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "= r, m")
+ (match_operand:DF 1 "general_operand" "rFm,rG"))]
+ "ok_for_simple_move_operands (operands, DFmode)"
+ "#"
+ [(set_attr "type" "multi")])
+
+(define_split
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+{
+ split_double_move (operands, DFmode);
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Add
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "add<mode>3"
+ [(set (match_operand:QHI 0 "register_operand" "")
+ (plus:QHI (match_operand:QHI 1 "register_operand" "")
+ (match_operand:QHI 2 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*add<mode>3_insn"
+ [(set (match_operand:QHI 0 "register_operand" "=r")
+ (plus:QHI (match_operand:QHI 1 "register_operand" "%r")
+ (match_operand:QHI 2 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (plus:QHI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+(define_insn "*add<mode>3_insn<subst_arith>"
+ [(set (match_operand:QHI 0 "register_operand" "=r")
+ (plus:QHI (match_operand:QHI 1 "register_operand" "%r")
+ (match_operand:QHI 2 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "add<s> %0,%1,%2"
+ [(set_attr "type" "arith")])
+
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "add_operand" "")))]
+ "")
+
+(define_expand "addsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "add_operand" "")))
+ (clobber (reg:CC R_FLAGS))])]
+ "reload_completed"
+ "")
+
+(define_insn_and_split "*addsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,r,0")
+ (match_operand:SI 2 "add_operand" " L,r,J")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+; Favour the addition of small negative constants, since they are
+; expensive to load into a register.
+
+(define_insn "*addsi3_insn<subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,r,0")
+ (match_operand:SI 2 "add_operand" " L,r,J")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "@
+ subi %0,%n2
+ add.l %0,%1,%2
+ addi %0,%2"
+ [(set_attr "type" "arith")])
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "add_operand" "")))]
+ "")
+
+(define_insn_and_split "*addi3_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,&r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0,0, r")
+ (match_operand:DI 2 "add_operand" " J,L, r")))]
+ "ok_for_simple_arith_logic_operands (operands, DImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (plus:DI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith2")])
+
+; Disfavour the use of add.l because of the early clobber.
+
+(define_insn "*adddi3_insn_flags"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,&r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0,0, r")
+ (match_operand:DI 2 "add_operand" " J,L, r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "@
+ addi %d0,%2\n\tadc.l %0,%0,r0
+ subi %d0,%n2\n\tsubc.l %0,%0,r0
+ add.l %d0,%d1,%d2\n\tadc.l %0,%1,%2"
+ [(set_attr "type" "arith2")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Add with Carry
+;;
+;; Only SI mode is supported as slt[u] for the sake of cstore.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*<scc_str><subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_scc:SI (reg R_FLAGS) (const_int 0)))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "adc.l %0,r0,r0"
+ [(set_attr "type" "arith")])
+
+(define_insn "*plus_<scc_str><subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (any_scc:SI (reg R_FLAGS) (const_int 0))))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "adc.l %0,%1,r0"
+ [(set_attr "type" "arith")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Subtract
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "sub<mode>3"
+ [(set (match_operand:QHI 0 "register_operand" "")
+ (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "")
+ (match_operand:QHI 2 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*sub<mode>3_insn"
+ [(set (match_operand:QHI 0 "register_operand" "=r")
+ (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
+ (match_operand:QHI 2 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (minus:QHI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+(define_insn "*sub<mode>3_insn<subst_arith>"
+ [(set (match_operand:QHI 0 "register_operand" "=r")
+ (minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
+ (match_operand:QHI 2 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "sub<s> %0,%r1,%2"
+ [(set_attr "type" "arith")])
+
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
+ (match_operand:SI 2 "add_operand" "")))]
+ "")
+
+(define_expand "subsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
+ (match_operand:SI 2 "add_operand" "")))
+ (clobber (reg:CC R_FLAGS))])]
+ "reload_completed"
+ "")
+
+(define_insn_and_split "*subsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" " 0,rO,0")
+ (match_operand:SI 2 "add_operand" " L,r, J")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (minus:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+; Favour the subtraction of small negative constants, since they are
+; expensive to load into a register.
+
+(define_insn "*subsi3_insn<subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r,r, r")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" " 0,rO,0")
+ (match_operand:SI 2 "add_operand" " L,r, J")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "@
+ addi %0,%n2
+ sub.l %0,%r1,%2
+ subi %0,%2"
+ [(set_attr "type" "arith")])
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "add_operand" "")))]
+ "")
+
+(define_insn_and_split "*subdi3_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,&r")
+ (minus:DI (match_operand:DI 1 "register_operand" " 0,0, r")
+ (match_operand:DI 2 "add_operand" " J,L, r")))]
+ "ok_for_simple_arith_logic_operands (operands, DImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (minus:DI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith2")])
+
+; Disfavour the use of the sub.l because of the early clobber.
+
+(define_insn "*subdi3_insn_flags"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,&r")
+ (minus:DI (match_operand:DI 1 "register_operand" " 0,0, r")
+ (match_operand:DI 2 "add_operand" " J,L, r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "@
+ subi %d0,%2\n\tsubc.l %0,%0,r0
+ addi %d0,%n2\n\tadc.l %0,%0,r0
+ sub.l %d0,%d1,%d2\n\tsubc.l %0,%1,%2"
+ [(set_attr "type" "arith2")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Subtract with Carry
+;;
+;; Only SI mode is supported as neg<slt[u]> for the sake of cstore.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*neg_<scc_str><subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (any_scc:SI (reg R_FLAGS) (const_int 0))))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "subc.l %0,r0,r0"
+ [(set_attr "type" "arith")])
+
+(define_insn "*minus_<scc_str><subst_arith>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (any_scc:SI (reg R_FLAGS) (const_int 0))))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "subc.l %0,%1,r0"
+ [(set_attr "type" "arith")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Negate
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "neg<mode>2"
+ [(set (match_operand:I 0 "register_operand" "")
+ (neg:I (match_operand:I 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*neg<mode>2_insn"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (neg:I (match_operand:I 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (neg:I (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+(define_insn "*neg<mode>2_insn<subst_arith>"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (neg:I (match_operand:I 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "sub<s> %0,r0,%1"
+ [(set_attr "type" "arith")])
+
+(define_expand "negdi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (neg:DI (match_operand:DI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*negdi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, DImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (neg:DI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith2")])
+
+(define_insn "*negdi2_insn_flags"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "sub.l %d0,r0,%d1\n\tsubc.l %0,r0,%1"
+ [(set_attr "type" "arith2")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer Multiply (non-widening and widening, signed and unsigned)
+;;
+;; Only SI mode is supported.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; The mults and multu instructions clear MDC but we only pretend that they
+; clobber it to keep things relatively simple.
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (mult:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "mults %1,%2"
+ [(set_attr "type" "mul")])
+
+; The names are mulsidi3 and umulsidi3 here.
+
+(define_insn "<u>mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=b")
+ (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+ (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "mult<su> %1,%2"
+ [(set_attr "type" "mul")])
+
+; But they are smulsi3_highpart and umulsi3_highpart here.
+
+(define_insn_and_split "<su>mulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (ashiftrt:DI
+ (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+ (any_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))
+ (clobber (reg:DI R_MDB))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "#"
+ "reload_completed"
+ [(parallel [(set (reg:DI R_MDB)
+ (mult:DI (any_extend:DI (match_dup 1))
+ (any_extend:DI (match_dup 2))))
+ (clobber (reg:SI R_MDC))])
+ (set (match_dup 0) (unspec:SI [(reg:DI R_MDB)] UNSPEC_MDBHI))]
+ ""
+ [(set_attr "type" "multi")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer divide and modulus (signed and unsigned)
+;;
+;; Only SI mode is supported.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*divmodsi4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (div:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (reg:SI R_MDC) (mod:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "divs %2"
+ [(set_attr "type" "div")])
+
+(define_insn_and_split "divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (div:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (div:SI (match_dup 1) (match_dup 2)))
+ (set (reg:SI R_MDC) (mod:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 3) (reg:SI R_MDC))]
+ ""
+ [(set_attr "type" "multi")])
+
+(define_insn "*udivmodsi4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (udiv:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (reg:SI R_MDC) (umod:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "divu %2"
+ [(set_attr "type" "div")])
+
+(define_insn_and_split "udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (udiv:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (umod:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (udiv:SI (match_dup 1) (match_dup 2)))
+ (set (reg:SI R_MDC) (umod:SI (match_dup 1) (match_dup 2)))])
+ (set (match_dup 3) (reg:SI R_MDC))]
+ ""
+ [(set_attr "type" "multi")])
+
+; FIXME. How do we persuade the compiler to use 64/32 bit divides directly ?
+
+(define_insn "*divds"
+ [(set (reg:DI R_MDB)
+ (div:DI (reg:DI R_MDB) (sign_extend:DI (match_operand:SI 0 "register_operand" "r"))))
+ (set (reg:SI R_MDC) (truncate:SI (mod:DI (reg:DI R_MDB) (sign_extend:DI (match_dup 0)))))]
+ ""
+ "divds %0"
+ [(set_attr "type" "divd")])
+
+(define_insn "*divdu"
+ [(set (reg:DI R_MDB)
+ (udiv:DI (reg:DI R_MDB) (zero_extend:DI (match_operand:SI 0 "register_operand" "r"))))
+ (set (reg:SI R_MDC) (truncate:SI (umod:DI (reg:DI R_MDB) (zero_extend:DI (match_dup 0)))))]
+ ""
+ "divdu %0"
+ [(set_attr "type" "divd")])
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Bitwise Logical AND
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "and<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (and:I (match_operand:I 1 "register_operand" "")
+ (match_operand:I 2 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*and<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (and:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (and:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*and<mode>3_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (and:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "and<s> %0,%1,%2"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Bitwise Inclusive Logical OR
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "ior<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (ior:I (match_operand:I 1 "register_operand" "")
+ (match_operand:I 2 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*ior<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (ior:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ior:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*ior<mode>3_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (ior:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "or<s> %0,%1,%2"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Bitwise Exclusive Logical OR
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "xor<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (xor:I (match_operand:I 1 "register_operand" "")
+ (match_operand:I 2 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*xor<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (xor:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (xor:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*xor<mode>3_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (xor:I (match_operand:I 1 "register_operand" "%r")
+ (match_operand:I 2 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "xor<s> %0,%1,%2"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Bitwise Logical NOT
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "one_cmpl<mode>2"
+ [(set (match_operand:I 0 "register_operand" "")
+ (not:I (match_operand:I 1 "reg_or_0_operand" "")))]
+ "")
+
+(define_insn_and_split "*one_cmpl<mode>2_insn"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (not:I (match_operand:I 1 "reg_or_0_operand" "rO")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (not:I (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*one_cmpl<mode>2_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r")
+ (not:I (match_operand:I 1 "reg_or_0_operand" "rO")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "not<s> %0,%r1"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Arithmetic Shift Left
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "ashl<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (ashift:I (match_operand:I 1 "register_operand" "")
+ (match_operand:QI 2 "reg_or_shift_operand" "")))]
+ "")
+
+(define_insn_and_split "*ashl<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (ashift:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashift:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "arith")])
+
+(define_insn "*ashl<mode>3_insn<subst_arith>"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (ashift:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "asl<s> %0,%1,%2"
+ [(set_attr "type" "arith")])
+
+(define_insn "ashldi3"
+ [(set (match_operand:DI 0 "register_operand" "=b,r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "0,r")
+ (match_operand:QI 2 "reg_or_32_operand" "r,P")))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "@
+ asld %2
+ #"
+ [(set_attr "type" "shiftdi,multi")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (const_int 32)))
+ (clobber (reg:SI R_MDC))]
+ "reload_completed"
+ [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 4))
+ (set (subreg:SI (match_dup 0) 4) (const_int 0))]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Arithmetic Shift Right
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "ashr<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (ashiftrt:I (match_operand:I 1 "register_operand" "")
+ (match_operand:QI 2 "reg_or_shift_operand" "")))]
+ "")
+
+(define_insn_and_split "*ashr<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (ashiftrt:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashiftrt:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*ashr<mode>3_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (ashiftrt:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "asr<s> %0,%1,%2"
+ [(set_attr "type" "logic")])
+
+(define_insn "ashrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=b,r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,r")
+ (match_operand:QI 2 "reg_or_32_operand" "r,P")))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "@
+ asrd %2
+ #"
+ [(set_attr "type" "shiftdi,multi")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (const_int 32)))
+ (clobber (reg:SI R_MDC))]
+ "reload_completed"
+ [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 0))
+ (parallel [(set (subreg:SI (match_dup 0) 0)
+ (ashiftrt:SI (subreg:SI (match_dup 1) 0) (const_int 31)))
+ (clobber (reg:CC R_FLAGS))])]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Logical Shift Right
+;;
+;; Modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "lshr<mode>3"
+ [(set (match_operand:I 0 "register_operand" "")
+ (lshiftrt:I (match_operand:I 1 "register_operand" "")
+ (match_operand:QI 2 "reg_or_shift_operand" "")))]
+ "")
+
+(define_insn_and_split "*lshr<mode>3_insn"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (lshiftrt:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))]
+ "ok_for_simple_arith_logic_operands (operands, <MODE>mode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (lshiftrt:I (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*lshr<mode>3_insn<subst_logic>"
+ [(set (match_operand:I 0 "register_operand" "=r,r")
+ (lshiftrt:I (match_operand:I 1 "register_operand" "r,r")
+ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "lsr<s> %0,%1,%2"
+ [(set_attr "type" "logic")])
+
+(define_insn "lshrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=b,r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "0,r")
+ (match_operand:QI 2 "reg_or_32_operand" "r,P")))
+ (clobber (reg:SI R_MDC))]
+ ""
+ "@
+ lsrd %2
+ #"
+ [(set_attr "type" "shiftdi,multi")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (const_int 32)))
+ (clobber (reg:SI R_MDC))]
+ "reload_completed"
+ [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 0))
+ (set (subreg:SI (match_dup 0) 0) (const_int 0))]
+ "")
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Truncate
+;;
+;; Truncations among modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "trunchiqi2"
+ [(set (match_operand:QI 0 "register_operand" "")
+ (truncate:QI (match_operand:HI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*trunchiqi2_insn"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (truncate:QI (match_operand:HI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, QImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (truncate:QI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*trunchiqi2_insn<subst_logic>"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (truncate:QI (match_operand:HI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.b %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_expand "truncsihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (truncate:HI (match_operand:SI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*truncsihi2_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (truncate:HI (match_operand:SI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, HImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (truncate:HI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*truncsihi2_insn<subst_logic>"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (truncate:HI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.w %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_expand "truncdisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (truncate:SI (match_operand:DI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*truncdisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI (match_operand:DI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (truncate:SI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*truncdisi2_insn<subst_logic>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI (match_operand:DI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.l %0,%d1"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Sign-extend
+;;
+;; Sign-extensions among modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*extendqihi2_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, HImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*extendqihi2_insn<subst_logic>"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "extb.w %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_expand "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1)))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*extendqisi2_insn<subst_logic>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "extb.l %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_expand "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*extendhisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))
+ (clobber (reg:CC R_FLAGS))])]
+ ""
+ [(set_attr "type" "logic")])
+
+(define_insn "*extendhisi2_insn<subst_logic>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "extw.l %0,%1"
+ [(set_attr "type" "logic")])
+
+(define_expand "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*extendsidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, DImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 3) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])
+ (parallel [(set (match_dup 2)
+ (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (clobber (reg:CC R_FLAGS))])]
+{
+ operands[2] = operand_subword (operands[0], 0, 0, DImode);
+ operands[3] = operand_subword (operands[0], 1, 0, DImode);
+}
+ [(set_attr "type" "multi")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Zero-extend
+;;
+;; Zero-extensions among modes QI, HI, SI and DI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; QI is zero-extended to wider modes by shifting left and then performing
+; a logical shift right to insert the zeroes. This avoids the need to use
+; another register.
+
+(define_expand "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*zero_extendqihi2_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, HImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashift:HI (match_dup 2) (const_int 8)))
+ (clobber (reg:CC R_FLAGS))])
+ (parallel [(set (match_dup 0)
+ (lshiftrt:HI (match_dup 0) (const_int 8)))
+ (clobber (reg:CC R_FLAGS))])]
+{
+ operands[2] = gen_rtx_SUBREG (HImode, operands[1], 0);
+}
+ [(set_attr "type" "multi")])
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*zero_extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, SImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashift:SI (match_dup 2) (const_int 24)))
+ (clobber (reg:CC R_FLAGS))])
+ (parallel [(set (match_dup 0)
+ (lshiftrt:SI (match_dup 0) (const_int 24)))
+ (clobber (reg:CC R_FLAGS))])]
+{
+ operands[2] = gen_rtx_SUBREG (SImode, operands[1], 0);
+}
+ [(set_attr "type" "multi")])
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+ ""
+ "moviu %0,0"
+ [(set_attr "type" "imm_reg")])
+
+(define_expand "zero_extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "")))]
+ "")
+
+(define_insn_and_split "*zero_extendsidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
+ "ok_for_simple_arith_logic_operands (operands, DImode)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 3) (match_dup 1))
+ (clobber (reg:CC R_FLAGS))])
+ (set (match_dup 2) (const_int 0))]
+{
+ operands[2] = operand_subword (operands[0], 0, 0, DImode);
+ operands[3] = operand_subword (operands[0], 1, 0, DImode);
+}
+ [(set_attr "type" "multi")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Bit Test
+;;
+;; Only SI mode is supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; BITS_BIG_ENDIAN is defined to 1 so operand #1 counts from the MSB.
+
+(define_insn "*btst"
+ [(set (reg:CC_BTST R_FLAGS)
+ (compare:CC_BTST (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:QI 1 "const_shift_operand" "K"))
+ (const_int 0)))]
+ "reload_completed"
+ "lsr.l r0,%0,32-%1"
+ [(set_attr "type" "logic")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Integer comparisons
+;;
+;; Modes QI, HI and SI are supported directly.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*cmp<mode>"
+ [(set (reg:CC R_FLAGS)
+ (compare:CC (match_operand:I 0 "register_operand" "r")
+ (match_operand:I 1 "reg_or_0_operand" "rO")))]
+ "reload_completed"
+ "cmp<s> %0,%r1"
+ [(set_attr "type" "cmp")])
+
+(define_insn "*cmp<mode>_sne"
+ [(set (reg:CC R_FLAGS)
+ (compare:CC (not:I (match_operand:I 0 "register_operand" "r"))
+ (const_int -1)))]
+ "reload_completed"
+ "cmp<s> r0,%0"
+ [(set_attr "type" "cmp")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Single float operations
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (plus:SF (match_operand:SF 1 "fp_reg_operand" "%f")
+ (match_operand:SF 2 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fadd %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (minus:SF (match_operand:SF 1 "fp_reg_operand" "f")
+ (match_operand:SF 2 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fsub %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (mult:SF (match_operand:SF 1 "fp_reg_operand" "%f")
+ (match_operand:SF 2 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fmult %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (div:SF (match_operand:SF 1 "fp_reg_operand" "f")
+ (match_operand:SF 2 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fdiv %0,%1,%2"
+ [(set_attr "type" "fdiv")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fsqrt %0,%1"
+ [(set_attr "type" "fsqrt")])
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (neg:SF (match_operand:SF 1 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fneg %0,%1"
+ [(set_attr "type" "fmove")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (abs:SF (match_operand:SF 1 "fp_reg_operand" "f")))]
+ "TARGET_FPU"
+ "fabs %0,%1"
+ [(set_attr "type" "fmove")])
+
+(define_expand "copysignsf3"
+ [(match_operand:SF 0 "register_operand" "")
+ (match_operand:SF 1 "nonmemory_operand" "")
+ (match_operand:SF 2 "register_operand" "")]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+{
+ visium_expand_copysign (operands, SFmode);
+ DONE;
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Single float <-> single integer conversions for !TARGET_FPU_IEEE
+;;
+;; An FMOVE instruction converts a signalling NaN (zero high order bit of the
+;; mantissa) to a quiet NaN (-1). This is acceptable when the data to be
+;; moved is in fact a floating-point number, but to avoid nasty surprises
+;; integers must in general be kept out of the floating-point registers.
+;; HARD_REGNO_MODE_OK thus only allows SFmode in these registers.
+;; However, since FTOI and ITOF use floating-point registers for both their
+;; inputs and outputs, to use these instructions integers must transiently
+;; occupy such registers. To disguise this from the compiler, UNSPECs are
+;; used for floating-point operations on integers and floating from general
+;; register to floating-point register and fixing in the reverse direction
+;; are only split into the individual UNSPEC operations after reload.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*fload_no_ieee"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (unspec:SF [(match_operand:SI 1 "register_operand" "r")] UNSPEC_FLOAD))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "fload %0,%1"
+ [(set_attr "type" "reg_fp")])
+
+(define_insn "*itof_no_ieee"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_ITOF))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "itof %0,%1"
+ [(set_attr "type" "itof")])
+
+(define_insn_and_split "*floatsisf2_no_ieee"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (float:SF (match_operand:SI 1 "register_operand" "r")))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 0)
+ (unspec:SF [(match_dup 1)] UNSPEC_FLOAD))
+ (set (match_dup 0)
+ (unspec:SF [(match_dup 0)] UNSPEC_ITOF))]
+ ""
+ [(set_attr "type" "multi")])
+
+(define_insn "*ftoi_no_ieee"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_FTOI))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "ftoi %0,%1"
+ [(set_attr "type" "ftoi")])
+
+(define_insn "*fstore_no_ieee"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SF 1 "fp_reg_operand" "f")] UNSPEC_FSTORE))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "fstore %0,%1"
+ [(set_attr "type" "fp_reg")])
+
+(define_insn_and_split "fix_truncsfsi2_no_ieee"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" "f"))))
+ (clobber (match_scratch:SF 2 "=1"))]
+ "TARGET_FPU && !TARGET_FPU_IEEE"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 1)
+ (unspec:SF [(match_dup 1)] UNSPEC_FTOI))
+ (set (match_dup 0)
+ (unspec:SI [(match_dup 1)] UNSPEC_FSTORE))]
+ ""
+ [(set_attr "type" "multi")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Single float <-> single integer conversions
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*itof"
+ [(set (match_operand:SF 0 "fp_reg_operand" "=f")
+ (float:SF (match_operand:SI 1 "register_operand" "f")))]
+ "TARGET_FPU_IEEE"
+ "itof %0,%1"
+ [(set_attr "type" "itof")])
+
+(define_expand "floatsisf2"
+ [(set (match_operand:SF 0 "fp_reg_operand" "")
+ (float:SF (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_FPU"
+ "")
+
+(define_insn "*ftoi"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" "f"))))]
+ "TARGET_FPU_IEEE"
+ "ftoi %0,%1"
+ [(set_attr "type" "ftoi")])
+
+(define_expand "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (fix:SF (match_operand:SF 1 "fp_reg_operand" ""))))]
+ "TARGET_FPU"
+{
+ if (!TARGET_FPU_IEEE)
+ {
+ emit_insn (gen_fix_truncsfsi2_no_ieee (operands[0], operands[1]));
+ DONE;
+ }
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Single float comparisons
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "*cmpsf_fp"
+ [(set (reg:CCFP R_FLAGS)
+ (compare:CCFP (match_operand:SF 0 "fp_reg_or_0_operand" "fG")
+ (match_operand:SF 1 "fp_reg_or_0_operand" "fG")))]
+ "TARGET_FPU && reload_completed"
+ "fcmp r0,%f0,%f1"
+ [(set_attr "type" "fcmp")])
+
+(define_insn "*cmpsf_fpe"
+ [(set (reg:CCFPE R_FLAGS)
+ (compare:CCFPE (match_operand:SF 0 "fp_reg_or_0_operand" "fG")
+ (match_operand:SF 1 "fp_reg_or_0_operand" "fG")))]
+ "TARGET_FPU && reload_completed"
+ "fcmpe r0,%f0,%f1"
+ [(set_attr "type" "fcmp")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Conditional branch instructions
+;;
+;; Note - we do not specify the two instructions necessary to perform
+;; a compare-and-branch in the cbranch<mode>4 pattern because that would
+;; allow the comparison to be moved away from the jump before the reload
+;; pass has completed. That would be problematical because reload can
+;; generate instructions in between which would clobber the CC register.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "cbranch<mode>4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand:I 1 "register_operand")
+ (match_operand:I 2 "reg_or_0_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+)
+
+(define_insn_and_split "*cbranch<mode>4_insn"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand:I 1 "register_operand" "r")
+ (match_operand:I 2 "reg_or_0_operand" "rO")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cbranch (GET_CODE (operands[0]), operands[1], operands[2],
+ operands[3]);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*cbranchsi4_btst_insn"
+ [(set (pc)
+ (if_then_else (match_operator 0 "visium_btst_operator"
+ [(zero_extract:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:QI 2 "const_shift_operand" "K"))
+ (const_int 0)])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
+ XEXP (operands[0], 1), operands[3]);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "visium_fp_comparison_operator"
+ [(match_operand:SF 1 "fp_reg_operand")
+ (match_operand:SF 2 "fp_reg_or_0_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "TARGET_FPU"
+)
+
+(define_insn_and_split "*cbranchsf4_insn"
+ [(set (pc)
+ (if_then_else (match_operator 0 "visium_fp_comparison_operator"
+ [(match_operand:SF 1 "fp_reg_operand" "f")
+ (match_operand:SF 2 "fp_reg_or_0_operand" "fG")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "TARGET_FPU"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cbranch (GET_CODE (operands[0]), operands[1], operands[2],
+ operands[3]);
+ DONE;
+}
+ [(set_attr "type" "fcmp")])
+
+; Now match both normal and inverted branches.
+
+(define_insn "*normal_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "visium_branch_operator"
+ [(reg R_FLAGS) (const_int 0)])
+ (label_ref (match_operand 0 ""))
+ (pc)))]
+ "reload_completed"
+{
+ return output_cbranch (operands[0], GET_CODE (operands[1]),
+ GET_MODE (XEXP (operands[1], 0)), 0, insn);
+}
+ [(set_attr "type" "branch")])
+
+(define_insn "*inverted_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "visium_branch_operator"
+ [(reg R_FLAGS) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 ""))))]
+ "reload_completed"
+{
+ return output_cbranch (operands[0], GET_CODE (operands[1]),
+ GET_MODE (XEXP (operands[1], 0)), 1, insn);
+}
+ [(set_attr "type" "branch")])
+
+; And then match both normal and inverted returns.
+
+(define_insn "*cond_<return_str>return"
+ [(set (pc)
+ (if_then_else (match_operator 0 "visium_branch_operator"
+ [(reg R_FLAGS) (const_int 0)])
+ (any_return)
+ (pc)))]
+ "<return_pred> && reload_completed"
+{
+ return output_cbranch (pc_rtx, GET_CODE (operands[0]),
+ GET_MODE (XEXP (operands[0], 0)), 0, insn);
+}
+ [(set_attr "type" "ret")])
+
+(define_insn "*inverted_cond_<return_str>return"
+ [(set (pc)
+ (if_then_else (match_operator 0 "visium_branch_operator"
+ [(reg R_FLAGS) (const_int 0)])
+ (pc)
+ (any_return)))]
+ "<return_pred> && reload_completed"
+{
+ return output_cbranch (pc_rtx, GET_CODE (operands[0]),
+ GET_MODE (XEXP (operands[0], 0)), 1, insn);
+}
+ [(set_attr "type" "ret")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Unconditional branch instructions
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+{
+ return output_ubranch (operands[0], insn);
+}
+ [(set_attr "type" "branch")])
+
+(define_insn "indirect_jump"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "bra tr,%0,r0%# ;indirect jump"
+ [(set_attr "type" "abs_branch")])
+
+(define_insn "tablejump"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "bra tr,%0,r0%# ;tablejump"
+ [(set_attr "type" "abs_branch")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Subprogram call instructions
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; Subroutine call instruction returning no value. Operand 0 is the function
+; to call; operand 1 is the number of bytes of arguments pushed (in mode
+; 'SImode', except it is normally a 'const_int'); operand 2 is the number of
+; registers used as operands.
+
+(define_expand "call"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (match_dup 3))])]
+ ""
+{
+ if (GET_CODE (XEXP (operands[0], 0)) != REG)
+ XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+
+ if (!operands[2])
+ operands[2] = const0_rtx;
+
+ operands[3] = gen_rtx_REG (Pmode, R_LINK);
+})
+
+(define_insn "*call_internal"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l,!r"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (match_operand 3 "" ""))]
+ "!SIBLING_CALL_P (insn)"
+ "bra tr,%0,%3%# ;call"
+ [(set_attr "type" "call")])
+
+; Subroutine call instruction returning a value. Operand 0 is the hard
+; register in which the value is returned. There are three more operands, the
+; same as the three operands of the 'call' instruction (but with numbers
+; increased by one).
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "register_operand" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (match_dup 4))])]
+ ""
+{
+ if (GET_CODE (XEXP (operands[1], 0)) != REG)
+ XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+
+ if (!operands[3])
+ operands[3] = const0_rtx;
+
+ operands[4] = gen_rtx_REG (Pmode, R_LINK);
+})
+
+(define_insn "*call_value_internal"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l,!r"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (match_operand 4 "" ""))]
+ "!SIBLING_CALL_P (insn)"
+ "bra tr,%1,%4%# ;call value"
+ [(set_attr "type" "call")])
+
+; Tail calls are similar, except that the link register is not used. But
+; we don't use r0 as the destination register of the branch because we want
+; the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
+; predict the branch target.
+
+(define_expand "sibcall"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (match_dup 3))])]
+ ""
+{
+ if (GET_CODE (XEXP (operands[0], 0)) != REG)
+ XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+
+ if (!operands[2])
+ operands[2] = const0_rtx;
+
+ operands[3] = gen_rtx_SCRATCH (SImode);
+})
+
+(define_insn "*sibcall_internal"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "k"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (match_scratch:SI 3 "=0"))]
+ "SIBLING_CALL_P (insn)"
+ "bra tr,%0,%0%# ;sibcall"
+ [(set_attr "type" "call")])
+
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0 "register_operand" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (match_dup 4))])]
+ ""
+{
+ if (GET_CODE (XEXP (operands[1], 0)) != REG)
+ XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+
+ if (!operands[3])
+ operands[3] = const0_rtx;
+
+ operands[4] = gen_rtx_SCRATCH (SImode);
+})
+
+(define_insn "*sibcall_value_internal"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "k"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (match_scratch:SI 4 "=1"))]
+ "SIBLING_CALL_P (insn)"
+ "bra tr,%1,%1%# ;sibcall value"
+ [(set_attr "type" "call")])
+
+; Call subroutine returning any type.
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "" "")
+ (const_int 0))
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")])]
+ ""
+{
+ int i;
+
+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
+
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
+
+ DONE;
+})
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Compare-and-store instructions
+;;
+;; Modes QI, HI, SI and SF are supported directly.
+;;
+;; Note - we do not specify the two instructions necessary to perform
+;; a compare-and-store in the cstore<mode>4 pattern because that would
+;; allow the comparison to be moved away from the store before the reload
+;; pass has completed. That would be problematical because reload can
+;; generate instructions in between which would clobber the CC register.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_expand "cstore<mode>4"
+ [(set (match_operand:SI 0)
+ (match_operator:SI 1 "visium_int_cstore_operator"
+ [(match_operand:I 2 "register_operand")
+ (match_operand:I 3 "reg_or_0_operand")]))]
+ ""
+{
+ visium_expand_int_cstore (operands, <MODE>mode);
+ DONE;
+})
+
+(define_insn_and_split "*cstore<mode>4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (match_operand:I 1 "register_operand" "r")
+ (match_operand:I 2 "reg_or_0_operand" "rO")))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (SET, operands[0], NULL_RTX,
+ LTU, operands[1], operands[2]);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*neg_cstore<mode>4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (ltu:SI (match_operand:I 1 "register_operand" "r")
+ (match_operand:I 2 "reg_or_0_operand" "rO"))))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (NEG, operands[0], NULL_RTX,
+ LTU, operands[1], operands[2]);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*<add_str>_cstore<mode>4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_add:SI (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (match_operand:I 2 "register_operand" "r")
+ (match_operand:I 3 "reg_or_0_operand" "rO"))))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (<add_op>, operands[0], operands[1],
+ LTU, operands[2], operands[3]);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*cstore<mode>4_sne_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (not:I (match_operand:I 1 "register_operand" "r"))
+ (const_int -1)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (SET, operands[0], NULL_RTX,
+ LTU, gen_rtx_NOT (<MODE>mode, operands[1]), constm1_rtx);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*neg_cstore<mode>4_sne_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (ltu:SI (not:I (match_operand:I 1 "register_operand" "r"))
+ (const_int -1))))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (NEG, operands[0], NULL_RTX,
+ LTU, gen_rtx_NOT (<MODE>mode, operands[1]), constm1_rtx);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_insn_and_split "*<add_str>_cstore<mode>4_sne_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_add:SI (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (not:I (match_operand:I 2 "register_operand" "r"))
+ (const_int -1))))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (<add_op>, operands[0], operands[1],
+ LTU, gen_rtx_NOT (<MODE>mode, operands[2]), constm1_rtx);
+ DONE;
+}
+ [(set_attr "type" "cmp")])
+
+(define_expand "cstoresf4"
+ [(set (match_operand:SI 0)
+ (match_operator:SI 1 "visium_fp_cstore_operator"
+ [(match_operand:SF 2 "fp_reg_operand")
+ (match_operand:SF 3 "fp_reg_or_0_operand")]))]
+ "TARGET_FPU"
+{
+ visium_expand_fp_cstore (operands, SFmode);
+ DONE;
+})
+
+(define_insn_and_split "*cstoresf4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_operand:SF 1 "fp_reg_or_0_operand" "fG")
+ (match_operand:SF 2 "fp_reg_or_0_operand" "fG")))]
+ "TARGET_FPU"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (SET, operands [0], NULL_RTX,
+ LT, operands[1], operands[2]);
+ DONE;
+}
+ [(set_attr "type" "fcmp")])
+
+(define_insn_and_split "*neg_cstoresf4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (lt:SI (match_operand:SF 1 "fp_reg_or_0_operand" "fG")
+ (match_operand:SF 2 "fp_reg_or_0_operand" "fG"))))]
+ "TARGET_FPU"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (NEG, operands [0], NULL_RTX,
+ LT, operands[1], operands[2]);
+ DONE;
+}
+ [(set_attr "type" "fcmp")])
+
+(define_insn_and_split "*<add_str>_cstoresf4_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (any_add:SI (match_operand:SI 1 "register_operand" "r")
+ (lt:SI (match_operand:SF 2 "fp_reg_or_0_operand" "fG")
+ (match_operand:SF 3 "fp_reg_or_0_operand" "fG"))))]
+ "TARGET_FPU"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ visium_split_cstore (<add_op>, operands [0], operands[1],
+ LT, operands[2], operands[3]);
+ DONE;
+}
+ [(set_attr "type" "fcmp")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; RTL pro/epilogue support
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+; Expand prologue in RTL
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+{
+ visium_expand_prologue ();
+ DONE;
+})
+
+; Expand epilogue in RTL
+(define_expand "epilogue"
+ [(return)]
+ ""
+{
+ visium_expand_epilogue ();
+})
+
+; Expand epilogue without a final jump in RTL
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ visium_expand_epilogue ();
+ DONE;
+})
+
+; The artificial dependency on the link register is to prevent the
+; frame instruction from being put in a call delay slot, which can
+; confuse the CFI machinery.
+
+(define_insn "stack_save"
+ [(set (reg:SI R_FP) (reg:SI R_SP))
+ (use (reg:SI R_LINK))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.l fp,sp ;stack_save"
+ [(set_attr "type" "logic")])
+
+; The construct (mem:BLK (scratch)) is considered to alias all other
+; memory accesses. Thus it can be used as a memory barrier in stack
+; deallocation patterns.
+
+(define_insn "stack_restore"
+ [(set (reg:SI R_SP) (reg:SI R_FP))
+ (clobber (mem:BLK (scratch)))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "move.l sp,fp ;stack_restore"
+ [(set_attr "type" "logic")])
+
+(define_insn "stack_pop"
+ [(set (reg:SI R_SP)
+ (plus:SI (reg:SI R_SP) (match_operand:SI 0 "add_operand" "J,r")))
+ (clobber (mem:BLK (scratch)))
+ (clobber (reg:CC R_FLAGS))]
+ "reload_completed"
+ "@
+ addi sp,%0 ;stack pop
+ add.l sp,sp,%0 ;stack pop"
+ [(set_attr "type" "arith")])
+
+(define_expand "<return_str>return"
+ [(any_return)]
+ "<return_pred>"
+ "")
+
+(define_insn "*<return_str>return_internal"
+ [(any_return)]
+ "!visium_interrupt_function_p ()"
+{
+ return output_ubranch (pc_rtx, insn);
+}
+ [(set_attr "type" "ret")])
+
+(define_insn "*return_internal_interrupt"
+ [(return)]
+ "visium_interrupt_function_p ()"
+ "rfi\n\t nop ;return from interrupt"
+ [(set_attr "type" "rfi")])
+
+(define_insn "dsi"
+ [(unspec_volatile [(const_int 0)] UNSPECV_DSI)]
+ ""
+ "dsi"
+ [(set_attr "type" "dsi")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; NOP (no-op instruction)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop ;generated nop"
+ [(set_attr "type" "nop")])
+
+(define_insn "hazard_nop"
+ [(unspec_volatile [(const_int 0)] UNSPEC_NOP)]
+ ""
+ "nop ;hazard avoidance nop"
+ [(set_attr "type" "nop")])
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
+ ""
+ ""
+ [(set_attr "type" "nop")])
+
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; String/block operations
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+
+;; String/block move insn.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movmemsi"
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:SI 2 "general_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ ""
+{
+ if (visium_expand_block_move (operands))
+ DONE;
+ else
+ FAIL;
+})
+
+(define_insn "*bmd"
+ [(set (mem:BLK (reg:SI R_R1))
+ (mem:BLK (reg:SI R_R2)))
+ (use (reg:SI R_R3))
+ (clobber (reg:SI R_R1))
+ (clobber (reg:SI R_R2))
+ (clobber (reg:SI R_R3))
+ (clobber (reg:SI R_R4))
+ (clobber (reg:SI R_R5))
+ (clobber (reg:SI R_R6))]
+ "TARGET_BMI"
+ "bmd r1,r2,r3"
+ [(set_attr "type" "bmi")])
+
+;; String/block set insn.
+;; Argument 0 is the destination
+;; Argument 1 is the length
+;; Argument 2 is the value
+;; Argument 3 is the alignment
+
+(define_expand "setmemsi"
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand 2 "nonmemory_operand" ""))
+ (use (match_operand:SI 1 "general_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ ""
+{
+ if (visium_expand_block_set (operands))
+ DONE;
+ else
+ FAIL;
+})
diff --git a/gcc/config/visium/visium.opt b/gcc/config/visium/visium.opt
new file mode 100644
index 00000000000..75c166e7765
--- /dev/null
+++ b/gcc/config/visium/visium.opt
@@ -0,0 +1,82 @@
+; Options for Visium.
+; Copyright (C) 2005-2015 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published
+; by the Free Software Foundation; either version 3, or (at your
+; option) any later version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT
+; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+; License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>. */
+
+HeaderInclude
+config/visium/visium-opts.h
+
+mdebug
+Target RejectNegative
+Link with libc.a and libdebug.a
+
+msim
+Target RejectNegative
+Link with libc.a and libsim.a
+
+mfpu
+Target Report Mask(FPU)
+Use hardware FP (default)
+
+mhard-float
+Target RejectNegative Mask(FPU) MaskExists
+Use hardware FP
+
+msoft-float
+Target RejectNegative InverseMask(FPU)
+Do not use hardware FP
+
+mcpu=
+Target RejectNegative Joined Var(visium_cpu_and_features) Enum(visium_processor_type) Init(PROCESSOR_GR5)
+Use features of and schedule code for given CPU
+
+mtune=
+Target RejectNegative Joined Var(visium_cpu) Enum(visium_processor_type) Init(PROCESSOR_GR5)
+Schedule code for given CPU
+
+Enum
+Name(visium_processor_type) Type(enum processor_type)
+
+EnumValue
+Enum(visium_processor_type) String(mcm) Value(PROCESSOR_GR5)
+
+EnumValue
+Enum(visium_processor_type) String(gr5) Value(PROCESSOR_GR5)
+
+EnumValue
+Enum(visium_processor_type) String(gr6) Value(PROCESSOR_GR6)
+
+msv-mode
+Target Mask(SV_MODE)
+Generate code for the supervisor mode (default)
+
+muser-mode
+Target InverseMask(SV_MODE)
+Generate code for the user mode
+
+menable-trampolines
+Target RejectNegative
+Only retained for backward compatibility.
+
+Mask(MCM)
+; Generate code for the MCM
+
+Mask(BMI)
+; Generate the Block Move Instructions
+
+Mask(FPU_IEEE)
+; Generate code for an IEEE-compliant FPU
diff --git a/gcc/configure b/gcc/configure
index b589a2a4806..8670f730cef 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -26502,7 +26502,7 @@ esac
case "$cpu_type" in
aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \
| mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \
- | xstormy16 | xtensa)
+ | visium | xstormy16 | xtensa)
insn="nop"
;;
ia64 | s390)
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 0169823fd7f..d0101415cca 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4442,7 +4442,7 @@ esac
case "$cpu_type" in
aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \
| mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \
- | xstormy16 | xtensa)
+ | visium | xstormy16 | xtensa)
insn="nop"
;;
ia64 | s390)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f68cd7f6285..25226824043 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2935,12 +2935,11 @@ least version 2.20.1), and GNU C library (at least version 2.11.1).
@item interrupt
@cindex interrupt handler functions
Use this attribute on the ARC, ARM, AVR, CR16, Epiphany, M32C, M32R/D,
-m68k, MeP, MIPS, MSP430, RL78, RX and Xstormy16 ports to indicate that
-the specified function is an
-interrupt handler. The compiler generates function entry and exit
-sequences suitable for use in an interrupt handler when this attribute
-is present. With Epiphany targets it may also generate a special section with
-code to initialize the interrupt vector table.
+m68k, MeP, MIPS, MSP430, RL78, RX, Visium and Xstormy16 ports to indicate
+that the specified function is an interrupt handler. The compiler generates
+function entry and exit sequences suitable for use in an interrupt handler
+when this attribute is present. With Epiphany targets it may also generate
+a special section with code to initialize the interrupt vector table.
Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, MicroBlaze,
and SH processors can be specified via the @code{interrupt_handler} attribute.
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 1e05310e7fc..94e039d09a1 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -3349,6 +3349,8 @@ information have to.
@item
@uref{#tilepro-x-linux,,tilepro-*-linux*}
@item
+@uref{#visium-x-elf, visium-*-elf}
+@item
@uref{#x-x-vxworks,,*-*-vxworks*}
@item
@uref{#x86-64-x-x,,x86_64-*-*, amd64-*-*}
@@ -4650,6 +4652,14 @@ binutils-2.22 or newer.
@html
<hr />
@end html
+@anchor{visium-x-elf}
+@heading visium-*-elf
+CDS VISIUMcore processor.
+This configuration is intended for embedded systems.
+
+@html
+<hr />
+@end html
@anchor{x-x-vxworks}
@heading *-*-vxworks*
Support for VxWorks is in flux. At present GCC supports @emph{only} the
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c42898cd601..2e587f5d842 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1064,6 +1064,10 @@ See RS/6000 and PowerPC Options.
@emph{VAX Options}
@gccoptlist{-mg -mgnu -munix}
+@emph{Visium Options}
+@gccoptlist{-mdebug -msim -mfpu -mno-fpu -mhard-float -msoft-float @gol
+-mcpu=@var{cpu-type} -mtune=@var{cpu-type} -msv-mode -muser-mode}
+
@emph{VMS Options}
@gccoptlist{-mvms-return-codes -mdebug-main=@var{prefix} -mmalloc64 @gol
-mpointer-size=@var{size}}
@@ -11936,6 +11940,7 @@ platform.
* TILEPro Options::
* V850 Options::
* VAX Options::
+* Visium Options::
* VMS Options::
* VxWorks Options::
* x86-64 Options::
@@ -22606,6 +22611,77 @@ GNU assembler is being used.
Output code for G-format floating-point numbers instead of D-format.
@end table
+@node Visium Options
+@subsection Visium Options
+@cindex Visium options
+
+@table @gcctabopt
+
+@item -mdebug
+@opindex mdebug
+A program which performs file I/O and is destined to run on an MCM target
+should be linked with this option. It causes the libraries libc.a and
+libdebug.a to be linked. The program should be run on the target under
+the control of the GDB remote debugging stub.
+
+@item -msim
+@opindex msim
+A program which performs file I/O and is destined to run on the simulator
+should be linked with option. This causes libraries libc.a and libsim.a to
+be linked.
+
+@item -mfpu
+@itemx -mhard-float
+@opindex mfpu
+@opindex mhard-float
+Generate code containing floating-point instructions. This is the
+default.
+
+@item -mno-fpu
+@itemx -msoft-float
+@opindex mno-fpu
+@opindex msoft-float
+Generate code containing library calls for floating-point.
+
+@option{-msoft-float} changes the calling convention in the output file;
+therefore, it is only useful if you compile @emph{all} of a program with
+this option. In particular, you need to compile @file{libgcc.a}, the
+library that comes with GCC, with @option{-msoft-float} in order for
+this to work.
+
+@item -mcpu=@var{cpu_type}
+@opindex mcpu
+Set the instruction set, register set, and instruction scheduling parameters
+for machine type @var{cpu_type}. Supported values for @var{cpu_type} are
+@samp{mcm}, @samp{gr5} and @samp{gr6}.
+
+@samp{mcm} is a synonym of @samp{gr5} present for backward compatibility.
+
+By default (unless configured otherwise), GCC generates code for the GR5
+variant of the Visium architecture.
+
+With @option{-mcpu=gr6}, GCC generates code for the GR6 variant of the Visium
+architecture. The only difference from GR5 code is that the compiler will
+generate block move instructions.
+
+@item -mtune=@var{cpu_type}
+@opindex mtune
+Set the instruction scheduling parameters for machine type @var{cpu_type},
+but do not set the instruction set or register set that the option
+@option{-mcpu=@var{cpu_type}} would.
+
+@item -msv-mode
+@opindex msv-mode
+Generate code for the supervisor mode, where there are no restrictions on
+the access to general registers. This is the default.
+
+@item -muser-mode
+@opindex muser-mode
+Generate code for the user mode, where the access to some general registers
+is forbidden: on the GR5, registers r24 to r31 cannot be accessed in this
+mode; on the GR6, only registers r29 to r31 are affected.
+@end table
+
@node VMS Options
@subsection VMS Options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 48bd4825c32..934ed236c65 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -3972,6 +3972,56 @@ A 2-element vector constant with identical elements.
@end table
+@item Visium---@file{config/visium/constraints.md}
+@table @code
+@item b
+EAM register @code{mdb}
+
+@item c
+EAM register @code{mdc}
+
+@item f
+Floating point register
+
+@ifset INTERNALS
+@item k
+Register for sibcall optimization
+@end ifset
+
+@item l
+General register, but not @code{r29}, @code{r30} and @code{r31}
+
+@item t
+Register @code{r1}
+
+@item u
+Register @code{r2}
+
+@item v
+Register @code{r3}
+
+@item G
+Floating-point constant 0.0
+
+@item J
+Integer constant in the range 0 .. 65535 (16-bit immediate)
+
+@item K
+Integer constant in the range 1 .. 31 (5-bit immediate)
+
+@item L
+Integer constant in the range @minus{}65535 .. @minus{}1 (16-bit negative immediate)
+
+@item M
+Integer constant @minus{}1
+
+@item O
+Integer constant 0
+
+@item P
+Integer constant 32
+@end table
+
@item Xtensa---@file{config/xtensa/constraints.md}
@table @code
@item a
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cac2f79d40a..cbd491cc49d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2015-01-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * lib/target-supports.exp (check_profiling_available): Return 0 for
+ Visium.
+ (check_effective_target_tls_runtime): Likewise.
+ (check_effective_target_logical_op_short_circuit): Return 1 for Visium.
+ * gcc.dg/20020312-2.c: Adjust for Visium.
+ * gcc.dg/tls/thr-cse-1.c: Likewise
+ * gcc.dg/tree-ssa/20040204-1.c: Likewise
+ * gcc.dg/tree-ssa/loop-1.c: Likewise.
+ * gcc.dg/weak/typeof-2.c: Likewise.
+
2015-01-05 Radovan Obradovic <radovan.obradovic@imgtec.com>
PR rtl-optimization/64287
diff --git a/gcc/testsuite/gcc.dg/20020312-2.c b/gcc/testsuite/gcc.dg/20020312-2.c
index de217412af5..71201fee26b 100644
--- a/gcc/testsuite/gcc.dg/20020312-2.c
+++ b/gcc/testsuite/gcc.dg/20020312-2.c
@@ -80,6 +80,8 @@ extern void abort (void);
/* No pic register. */
#elif defined(__vax__)
/* No pic register. */
+#elif defined(__VISIUM__)
+/* No pic register. */
#elif defined(__xstormy16__)
/* No pic register. */
#elif defined(__XTENSA__)
diff --git a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c
index 8e64424b72a..da2fbff96a9 100644
--- a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c
+++ b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c
@@ -18,11 +18,11 @@ int foo (int b, int c, int d)
return a;
}
-/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "spu-*-*" "i?86-*-mingw*" "x86_64-*-mingw*" } } } } } */
+/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "spu-*-*" "i?86-*-mingw*" "x86_64-*-mingw*" visium-*-* } } } } } */
/* { dg-final { scan-assembler-not "call\tL___emutls_get_address.stub.*call\tL___emutls_get_address.stub.*" { target "*-*-darwin8" } } } */
/* { dg-final { scan-assembler-not "(b,l|bl) __emutls_get_address.*(b,l|bl) __emutls_get_address.*" { target "hppa*-*-hpux*" } } } */
/* { dg-final { scan-assembler-not "(brsl|brasl)\t__emutls_get_address.*(brsl|brasl)\t__emutls_get_address.*" { target spu-*-* } } } */
/* { dg-final { scan-assembler-not "tls_lookup.*tls_lookup.*" { target *-wrs-vxworks } } } */
/* { dg-final { scan-assembler-not "call\t___emutls_get_address.*call\t___emutls_get_address" { target "i?86-*-mingw*" } } } */
/* { dg-final { scan-assembler-not "call\t__emutls_get_address.*call\t__emutls_get_address" { target "x86_64-*-mingw*" } } } */
-
+/* { dg-final { scan-assembler-not "%l __emutls_get_address.*%l __emutls_get_address" { target visium-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
index 2793336a5cb..42f6a4cc646 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
@@ -33,5 +33,5 @@ void test55 (int x, int y)
that the && should be emitted (based on BRANCH_COST). Fix this
by teaching dom to look through && and register all components
as true. */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* sparc*-*-* spu-*-* x86_64-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-*" } } } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c
index dd52c50faf4..f63c8a7ab6a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c
@@ -49,7 +49,7 @@ int xxx(void)
/* CRIS keeps the address in a register. */
/* m68k sometimes puts the address in a register, depending on CPU and PIC. */
-/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* } } } */
+/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* visium-*-* } } } */
/* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-* } } } */
/* { dg-final { scan-assembler-times "= foo" 5 { target ia64*-*-* } } } */
/* { dg-final { scan-assembler-times "call\[ \t\]*_foo" 5 { target i?86-*-mingw* i?86-*-cygwin* } } } */
@@ -57,3 +57,4 @@ int xxx(void)
/* { dg-final { scan-assembler-times "jsr|bsrf|blink\ttr?,r18" 5 { target sh*-*-* } } } */
/* { dg-final { scan-assembler-times "Jsr \\\$r" 5 { target cris-*-* } } } */
/* { dg-final { scan-assembler-times "\[jb\]sr" 5 { target fido-*-* m68k-*-* } } } */
+/* { dg-final { scan-assembler-times "bra *tr,r\[1-9\]*,r21" 5 { target visium-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/weak/typeof-2.c b/gcc/testsuite/gcc.dg/weak/typeof-2.c
index 45a12ebf918..d4273e361b7 100644
--- a/gcc/testsuite/gcc.dg/weak/typeof-2.c
+++ b/gcc/testsuite/gcc.dg/weak/typeof-2.c
@@ -48,4 +48,6 @@ int bar3 (int x)
// { dg-final { if [string match m68k-*-* $target_triplet ] {return} } }
// Likewise for moxie targets.
// { dg-final { if [string match moxie-*-* $target_triplet ] {return} } }
+// Likewise for Visium targets.
+// { dg-final { if [string match visium-*-* $target_triplet ] {return} } }
// { dg-final { scan-assembler "baz3.*baz3.*baz3.*baz3.*baz3.*baz3" } }
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index e335913e914..119d2c578d4 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -538,6 +538,7 @@ proc check_profiling_available { test_what } {
|| [istarget powerpc-*-elf]
|| [istarget rx-*-*]
|| [istarget tic6x-*-elf]
+ || [istarget visium-*-*]
|| [istarget xstormy16-*]
|| [istarget xtensa*-*-elf]
|| [istarget *-*-rtems*]
@@ -707,9 +708,9 @@ proc check_effective_target_tls_emulated {} {
# Return 1 if TLS executables can run correctly, 0 otherwise.
proc check_effective_target_tls_runtime {} {
- # MSP430 runtime does not have TLS support, but just
+ # The runtime does not have TLS support, but just
# running the test below is insufficient to show this.
- if { [istarget msp430-*-*] } {
+ if { [istarget msp430-*-*] || [istarget visium-*-*] } {
return 0
}
return [check_runtime tls_runtime {
@@ -6085,6 +6086,7 @@ proc check_effective_target_logical_op_short_circuit {} {
|| [istarget s390*-*-*]
|| [istarget powerpc*-*-*]
|| [istarget nios2*-*-*]
+ || [istarget visium-*-*]
|| [check_effective_target_arm_cortex_m] } {
return 1
}
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 55fb239dc82..241747f9562 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,8 @@
+2015-01-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * config.host: Add Visium support.
+ * config/visium: New directory.
+
2015-01-05 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/libgcc/config.host b/libgcc/config.host
index e0db9f9d206..667eb312a66 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -1235,6 +1235,10 @@ vax-*-netbsdelf*)
;;
vax-*-openbsd*)
;;
+visium-*-elf*)
+ extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o"
+ tmake_file="visium/t-visium t-fdpbit"
+ ;;
xstormy16-*-elf)
tmake_file="stormy16/t-stormy16 t-fdpbit"
;;
diff --git a/libgcc/config/visium/crti.S b/libgcc/config/visium/crti.S
new file mode 100644
index 00000000000..158ae0f3261
--- /dev/null
+++ b/libgcc/config/visium/crti.S
@@ -0,0 +1,46 @@
+/* crti.S for Visium.
+ Copyright (C) 2005-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+ .file "crti.o"
+ .ident "GNU C crti.o"
+
+ .section .init
+ .globl __init
+ .type __init,@function
+__init:
+ subi r23,8
+ nop
+ write.l (r23),r22
+ write.l 1(r23),r21
+ move.l r22,r23
+
+ .section .fini
+ .globl __fini
+ .type __fini,@function
+__fini:
+ subi r23,8
+ nop
+ write.l (r23),r22
+ write.l 1(r23),r21
+ move.l r22,r23
diff --git a/libgcc/config/visium/crtn.S b/libgcc/config/visium/crtn.S
new file mode 100644
index 00000000000..a60f4de021e
--- /dev/null
+++ b/libgcc/config/visium/crtn.S
@@ -0,0 +1,40 @@
+/* crtn.S for Visium.
+ Copyright (C) 2005-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+ .file "crtn.o"
+ .ident "GNU C crtn.o"
+
+ .section .init
+ move.l r23,r22
+ read.l r22,(r22)
+ read.l r21,1(r23)
+ bra tr,r21,r0
+ addi r23,8
+
+ .section .fini
+ move.l r23,r22
+ read.l r22,(r22)
+ read.l r21,1(r23)
+ bra tr,r21,r0
+ addi r23,8
diff --git a/libgcc/config/visium/divdi3.c b/libgcc/config/visium/divdi3.c
new file mode 100644
index 00000000000..38b747a9865
--- /dev/null
+++ b/libgcc/config/visium/divdi3.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_divdi3
+#include "lib2funcs.c"
diff --git a/libgcc/config/visium/lib2funcs.c b/libgcc/config/visium/lib2funcs.c
new file mode 100644
index 00000000000..ba720a36d9e
--- /dev/null
+++ b/libgcc/config/visium/lib2funcs.c
@@ -0,0 +1,323 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+
+#ifdef HAVE_GAS_HIDDEN
+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
+#else
+#define ATTRIBUTE_HIDDEN
+#endif
+
+/* Work out the largest "word" size that we can deal with on this target. */
+#if MIN_UNITS_PER_WORD > 4
+# define LIBGCC2_MAX_UNITS_PER_WORD 8
+#elif (MIN_UNITS_PER_WORD > 2 \
+ || (MIN_UNITS_PER_WORD > 1 && __SIZEOF_LONG_LONG__ > 4))
+# define LIBGCC2_MAX_UNITS_PER_WORD 4
+#else
+# define LIBGCC2_MAX_UNITS_PER_WORD MIN_UNITS_PER_WORD
+#endif
+
+/* Work out what word size we are using for this compilation.
+ The value can be set on the command line. */
+#ifndef LIBGCC2_UNITS_PER_WORD
+#define LIBGCC2_UNITS_PER_WORD LIBGCC2_MAX_UNITS_PER_WORD
+#endif
+
+#if LIBGCC2_UNITS_PER_WORD <= LIBGCC2_MAX_UNITS_PER_WORD
+
+#include "libgcc2.h"
+
+/* umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two
+ UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype
+ word product in HIGH_PROD and LOW_PROD. */
+
+#undef umul_ppmm
+#define umul_ppmm(wh, wl, u, v) \
+ do { \
+ /* Generate multu instruction. */ \
+ UDWtype __t = (UDWtype)(u) * (UDWtype)(v); \
+ (wl) = (UWtype)__t; \
+ (wh) = (UWtype)(__t >> W_TYPE_SIZE); \
+ } while (0)
+
+/* sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE
+ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
+ and is lost. */
+
+#undef sub_ddmmss
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub.l %0,%2,%4\n\t" \
+ "subc.l %1,%3,%5" \
+ : "=&r" (sl), "=r" (sh) \
+ : "r" (al), "r" (ah), "r" (bl), "r" (bh))
+
+/* udiv_qqrnnd(high_quotient, low_quotient, remainder, high_numerator,
+ low_numerator, denominator) divides a UDWtype, composed by the UWtype
+ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+ in QUOTIENT and the remainder in REMAINDER. */
+
+#define udiv_qqrnnd(qh, ql, r, nh, nl, d) \
+ __asm__ ("writemd %3,%4\n\t" \
+ "divdu %5\n\t" \
+ "readmda %0\n\t" \
+ "readmdb %1\n\t" \
+ "readmdc %2" \
+ : "=r" (ql), "=r" (qh), "=r" (r) \
+ : "r" (nl), "r" (nh), "r" (d) \
+ : "mdb", "mdc")
+
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+ defined (L_umoddi3) || defined (L_moddi3))
+#define L_udivmoddi4
+#endif
+
+#ifdef L_udivmoddi4
+
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+ defined (L_umoddi3) || defined (L_moddi3))
+static inline __attribute__ ((__always_inline__))
+#endif
+UDWtype
+__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
+{
+ const DWunion nn = {.ll = n};
+ const DWunion dd = {.ll = d};
+ DWunion rr;
+ UWtype d0, d1, n0, n1, n2;
+ UWtype q0, q1;
+ UWtype b, bm;
+
+ d0 = dd.s.low;
+ d1 = dd.s.high;
+ n0 = nn.s.low;
+ n1 = nn.s.high;
+
+ if (d1 == 0)
+ {
+ /* qq = NN / 0d */
+
+ if (d0 == 0)
+ d0 = 1 / d0; /* Divide intentionally by zero. */
+
+ udiv_qqrnnd (q1, q0, n0, n1, n0, d0);
+
+ /* Remainder in n0. */
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = 0;
+ *rp = rr.ll;
+ }
+ }
+
+ else
+ {
+ if (d1 > n1)
+ {
+ /* 00 = nn / DD */
+
+ q0 = 0;
+ q1 = 0;
+
+ /* Remainder in n1n0. */
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ count_leading_zeros (bm, d1);
+ if (bm == 0)
+ {
+ /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
+ conclude (the most significant bit of n1 is set) /\ (the
+ quotient digit q0 = 0 or 1).
+
+ This special case is necessary, not an optimization. */
+
+ /* The condition on the next line takes advantage of that
+ n1 >= d1 (true due to program flow). */
+ if (n1 > d1 || n0 >= d0)
+ {
+ q0 = 1;
+ sub_ddmmss (n1, n0, n1, n0, d1, d0);
+ }
+ else
+ q0 = 0;
+
+ q1 = 0;
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ UWtype m1, m0;
+ /* Normalize. */
+
+ b = W_TYPE_SIZE - bm;
+
+ d1 = (d1 << bm) | (d0 >> b);
+ d0 = d0 << bm;
+ n2 = n1 >> b;
+ n1 = (n1 << bm) | (n0 >> b);
+ n0 = n0 << bm;
+
+ udiv_qqrnnd (q1, q0, n1, n2, n1, d1);
+ umul_ppmm (m1, m0, q0, d0);
+
+ if (m1 > n1 || (m1 == n1 && m0 > n0))
+ {
+ q0--;
+ sub_ddmmss (m1, m0, m1, m0, d1, d0);
+ }
+
+ /* Remainder in (n1n0 - m1m0) >> bm. */
+ if (rp != 0)
+ {
+ sub_ddmmss (n1, n0, n1, n0, m1, m0);
+ rr.s.low = (n1 << b) | (n0 >> bm);
+ rr.s.high = n1 >> bm;
+ *rp = rr.ll;
+ }
+ }
+ }
+ }
+
+ const DWunion ww = {{.low = q0, .high = q1}};
+ return ww.ll;
+}
+#endif
+
+#ifdef L_divdi3
+DWtype
+__divdi3 (DWtype u, DWtype v)
+{
+ Wtype c = 0;
+ DWunion uu = {.ll = u};
+ DWunion vv = {.ll = v};
+ DWtype w;
+
+ if (uu.s.high < 0)
+ c = ~c,
+ uu.ll = -uu.ll;
+ if (vv.s.high < 0)
+ c = ~c,
+ vv.ll = -vv.ll;
+
+ w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
+ if (c)
+ w = -w;
+
+ return w;
+}
+#endif
+
+#ifdef L_moddi3
+DWtype
+__moddi3 (DWtype u, DWtype v)
+{
+ Wtype c = 0;
+ DWunion uu = {.ll = u};
+ DWunion vv = {.ll = v};
+ DWtype w;
+
+ if (uu.s.high < 0)
+ c = ~c,
+ uu.ll = -uu.ll;
+ if (vv.s.high < 0)
+ vv.ll = -vv.ll;
+
+ (void) __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w);
+ if (c)
+ w = -w;
+
+ return w;
+}
+#endif
+
+#ifdef L_umoddi3
+UDWtype
+__umoddi3 (UDWtype u, UDWtype v)
+{
+ UDWtype w;
+
+ (void) __udivmoddi4 (u, v, &w);
+
+ return w;
+}
+#endif
+
+#ifdef L_udivdi3
+UDWtype
+__udivdi3 (UDWtype n, UDWtype d)
+{
+ return __udivmoddi4 (n, d, (UDWtype *) 0);
+}
+#endif
+
+#ifdef L_set_trampoline_parity
+#undef int
+extern void __set_trampoline_parity (UWtype *);
+
+static inline UWtype
+parity_bit (UWtype x)
+{
+ x ^= x << 16;
+ x ^= x << 8;
+ x ^= x << 4;
+ x ^= x << 2;
+ x ^= x << 1;
+ return x & ((UWtype) 1 << (W_TYPE_SIZE - 1));
+}
+
+void
+__set_trampoline_parity (UWtype *addr)
+{
+ int i;
+
+ for (i = 0; i < (TRAMPOLINE_SIZE * BITS_PER_UNIT) / W_TYPE_SIZE; i++)
+ addr[i] |= parity_bit (addr[i]);
+}
+#endif
+
+#endif /* LIBGCC2_UNITS_PER_WORD <= MIN_UNITS_PER_WORD */
diff --git a/libgcc/config/visium/memcpy.c b/libgcc/config/visium/memcpy.c
new file mode 100644
index 00000000000..21efdd0f77b
--- /dev/null
+++ b/libgcc/config/visium/memcpy.c
@@ -0,0 +1,862 @@
+/* Copyright (C) 2012-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be kept in sync with newlib/libc/machine/visium/memcpy.c */
+
+#include <stddef.h>
+#include "memcpy.h"
+
+#define INST_BARRIER __asm__ __volatile__ ("":::"memory");
+
+#define MOVE_32_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ m0 = in [8]; \
+ m1 = in [9]; \
+ m2 = in [10]; \
+ m3 = in [11]; \
+ out [8] = m0; \
+ out [9] = m1; \
+ out [10] = m2; \
+ out [11] = m3; \
+ INST_BARRIER \
+ m0 = in [12]; \
+ m1 = in [13]; \
+ m2 = in [14]; \
+ m3 = in [15]; \
+ out [12] = m0; \
+ out [13] = m1; \
+ out [14] = m2; \
+ out [15] = m3; \
+ INST_BARRIER \
+ m0 = in [16]; \
+ m1 = in [17]; \
+ m2 = in [18]; \
+ m3 = in [19]; \
+ out [16] = m0; \
+ out [17] = m1; \
+ out [18] = m2; \
+ out [19] = m3; \
+ INST_BARRIER \
+ m0 = in [20]; \
+ m1 = in [21]; \
+ m2 = in [22]; \
+ m3 = in [23]; \
+ out [20] = m0; \
+ out [21] = m1; \
+ out [22] = m2; \
+ out [23] = m3; \
+ INST_BARRIER \
+ m0 = in [24]; \
+ m1 = in [25]; \
+ m2 = in [26]; \
+ m3 = in [27]; \
+ out [24] = m0; \
+ out [25] = m1; \
+ out [26] = m2; \
+ out [27] = m3; \
+ INST_BARRIER \
+ m0 = in [28]; \
+ m1 = in [29]; \
+ m2 = in [30]; \
+ m3 = in [31]; \
+ out [28] = m0; \
+ out [29] = m1; \
+ out [30] = m2; \
+ out [31] = m3; \
+ INST_BARRIER \
+ in += 32; \
+ out += 32; \
+} while(0)
+
+#define MOVE_16_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ m0 = in [8]; \
+ m1 = in [9]; \
+ m2 = in [10]; \
+ m3 = in [11]; \
+ out [8] = m0; \
+ out [9] = m1; \
+ out [10] = m2; \
+ out [11] = m3; \
+ INST_BARRIER \
+ m0 = in [12]; \
+ m1 = in [13]; \
+ m2 = in [14]; \
+ m3 = in [15]; \
+ out [12] = m0; \
+ out [13] = m1; \
+ out [14] = m2; \
+ out [15] = m3; \
+ INST_BARRIER \
+ in += 16; \
+ out += 16; \
+} while(0)
+
+#define MOVE_12_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ m0 = in [8]; \
+ m1 = in [9]; \
+ m2 = in [10]; \
+ m3 = in [11]; \
+ out [8] = m0; \
+ out [9] = m1; \
+ out [10] = m2; \
+ out [11] = m3; \
+ INST_BARRIER \
+ in += 12; \
+ out += 12; \
+} while(0)
+
+#define MOVE_11_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ m0 = in [8]; \
+ m1 = in [9]; \
+ m2 = in [10]; \
+ out [8] = m0; \
+ out [9] = m1; \
+ out [10] = m2; \
+ INST_BARRIER \
+ in += 11; \
+ out += 11; \
+} while(0)
+
+#define MOVE_10_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ m0 = in [8]; \
+ out [5] = m1; \
+ m1 = in [9]; \
+ out [6] = m2; \
+ out [7] = m3; \
+ out [8] = m0; \
+ out [9] = m1; \
+ INST_BARRIER \
+ in += 10; \
+ out += 10; \
+} while(0)
+
+#define MOVE_9_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ m0 = in [8]; \
+ out [8] = m0; \
+ in += 9; \
+ out += 9; \
+} while(0)
+
+#define MOVE_8_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ m3 = in [7]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ out [7] = m3; \
+ INST_BARRIER \
+ in += 8; \
+ out += 8; \
+} while(0)
+
+#define MOVE_7_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ m1 = in [5]; \
+ m2 = in [6]; \
+ out [4] = m0; \
+ out [5] = m1; \
+ out [6] = m2; \
+ INST_BARRIER \
+ in += 7; \
+ out += 7; \
+} while(0)
+
+#define MOVE_6_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ INST_BARRIER \
+ m0 = in [4]; \
+ out [1] = m1; \
+ INST_BARRIER \
+ m1 = in [5]; \
+ out [2] = m2; \
+ out [3] = m3; \
+ out [4] = m0; \
+ out [5] = m1; \
+ INST_BARRIER \
+ in += 6; \
+ out += 6; \
+} while(0)
+
+#define MOVE_5_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ INST_BARRIER \
+ out [0] = m0; \
+ m0 = in [4]; \
+ INST_BARRIER \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ out [4] = m0; \
+ INST_BARRIER \
+ in += 5; \
+ out += 5; \
+} while(0)
+
+#define MOVE_4_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ m3 = in [3]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ out [3] = m3; \
+ INST_BARRIER \
+ in += 4; \
+ out += 4; \
+} while(0)
+
+#define MOVE_3_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ m2 = in [2]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ out [2] = m2; \
+ INST_BARRIER \
+ in += 3; \
+ out += 3; \
+} while(0)
+
+#define MOVE_2_OBJECTS(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ m1 = in [1]; \
+ out [0] = m0; \
+ out [1] = m1; \
+ INST_BARRIER \
+ in += 2; \
+ out += 2; \
+} while(0)
+
+#define MOVE_1_OBJECT(in,out) \
+do { \
+ INST_BARRIER \
+ m0 = in [0]; \
+ out [0] = m0; \
+ INST_BARRIER \
+ in += 1; \
+ out += 1; \
+} while(0)
+
+
+static inline void
+__int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ int value = n;
+ int loop_var;
+ const int *in = s2;
+ int *out = s1;
+ int count;
+ int m0,m1,m2,m3;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ MOVE_1_OBJECT (in, out);
+ break;
+ case 2:
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 3:
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 4:
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 5:
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 6:
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 7:
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 8:
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 9:
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 10:
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 11:
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 12:
+ MOVE_12_OBJECTS (in, out);
+ break;
+ case 13:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 14:
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 15:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 16:
+ MOVE_16_OBJECTS (in, out);
+ break;
+ case 17:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 18:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 19:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 20:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 21:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 22:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 23:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 24:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 25:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 26:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 27:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 28:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 29:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 30:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 31:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ MOVE_32_OBJECTS (in, out);
+}
+
+static inline void
+__shrt_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ int value = n;
+ int loop_var;
+ const short int *in = s2;
+ int short *out = s1;
+ int count;
+ int m0,m1,m2,m3;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ MOVE_1_OBJECT (in, out);
+ break;
+ case 2:
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 3:
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 4:
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 5:
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 6:
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 7:
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 8:
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 9:
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 10:
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 11:
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 12:
+ MOVE_12_OBJECTS (in, out);
+ break;
+ case 13:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 14:
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 15:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 16:
+ MOVE_16_OBJECTS (in, out);
+ break;
+ case 17:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 18:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 19:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 20:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 21:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 22:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 23:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 24:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 25:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 26:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 27:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 28:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 29:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 30:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 31:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ MOVE_32_OBJECTS (in, out);
+}
+
+
+static inline void
+__byte_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ int value = n;
+ int loop_var;
+ const char *in = s2;
+ char *out = s1;
+ int count;
+ int m0,m1,m2,m3;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ MOVE_1_OBJECT (in, out);
+ break;
+ case 2:
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 3:
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 4:
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 5:
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 6:
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 7:
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 8:
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 9:
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 10:
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 11:
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 12:
+ MOVE_12_OBJECTS (in, out);
+ break;
+ case 13:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 14:
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 15:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 16:
+ MOVE_16_OBJECTS (in, out);
+ break;
+ case 17:
+ MOVE_11_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 18:
+ MOVE_9_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 19:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_3_OBJECTS (in, out);
+ break;
+ case 20:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 21:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_5_OBJECTS (in, out);
+ break;
+ case 22:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_6_OBJECTS (in, out);
+ break;
+ case 23:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_7_OBJECTS (in, out);
+ break;
+ case 24:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ break;
+ case 25:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ break;
+ case 26:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_10_OBJECTS (in, out);
+ break;
+ case 27:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ break;
+ case 28:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_8_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 29:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_9_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ case 30:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_12_OBJECTS (in, out);
+ MOVE_2_OBJECTS (in, out);
+ break;
+ case 31:
+ MOVE_16_OBJECTS (in, out);
+ MOVE_11_OBJECTS (in, out);
+ MOVE_4_OBJECTS (in, out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ MOVE_32_OBJECTS (in, out);
+}
+
+
+/* Exposed interface. */
+
+#ifndef __VISIUM_ARCH_BMI__
+
+void
+__long_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ __int_memcpy (s1, s2, n);
+}
+
+#endif /* !__VISIUM_ARCH_BMI__ */
+
+void
+__wrd_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ __shrt_int_memcpy (s1, s2, n);
+}
+
+void
+__byt_memcpy (void *__restrict s1, const void *__restrict s2, size_t n)
+{
+ __byte_memcpy (s1, s2, n);
+}
diff --git a/libgcc/config/visium/memcpy.h b/libgcc/config/visium/memcpy.h
new file mode 100644
index 00000000000..5df81763fb5
--- /dev/null
+++ b/libgcc/config/visium/memcpy.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2012-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Specialized variants of memcpy called directly from compiled code. */
+
+extern void
+__long_int_memcpy (void *__restrict s1, const void *__restrict s2, size_t n);
+
+extern void
+__wrd_memcpy (void *__restrict s1, const void *__restrict s2, size_t n);
+
+extern void
+__byt_memcpy (void *__restrict s1, const void *__restrict s2, size_t n);
diff --git a/libgcc/config/visium/memset.c b/libgcc/config/visium/memset.c
new file mode 100644
index 00000000000..5f81679fddc
--- /dev/null
+++ b/libgcc/config/visium/memset.c
@@ -0,0 +1,664 @@
+/* Copyright (C) 2012-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be kept in sync with newlib/libc/machine/visium/memset.c */
+
+#include <stddef.h>
+#include "memset.h"
+
+#define SET_32_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out [9] = m0; \
+ out [10] = m0; \
+ out [11] = m0; \
+ out [12] = m0; \
+ out [13] = m0; \
+ out [14] = m0; \
+ out [15] = m0; \
+ out [16] = m0; \
+ out [17] = m0; \
+ out [18] = m0; \
+ out [19] = m0; \
+ out [20] = m0; \
+ out [21] = m0; \
+ out [22] = m0; \
+ out [23] = m0; \
+ out [24] = m0; \
+ out [25] = m0; \
+ out [26] = m0; \
+ out [27] = m0; \
+ out [28] = m0; \
+ out [29] = m0; \
+ out [30] = m0; \
+ out [31] = m0; \
+ out += 32; \
+} while(0)
+
+#define SET_16_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out [9] = m0; \
+ out [10] = m0; \
+ out [11] = m0; \
+ out [12] = m0; \
+ out [13] = m0; \
+ out [14] = m0; \
+ out [15] = m0; \
+ out += 16; \
+} while(0)
+
+#define SET_12_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out [9] = m0; \
+ out [10] = m0; \
+ out [11] = m0; \
+ out += 12; \
+} while(0)
+
+#define SET_11_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out [9] = m0; \
+ out [10] = m0; \
+ out += 11; \
+} while(0)
+
+#define SET_10_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out [9] = m0; \
+ out += 10; \
+} while(0)
+
+#define SET_9_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out [8] = m0; \
+ out += 9; \
+} while(0)
+
+#define SET_8_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out [7] = m0; \
+ out += 8; \
+} while(0)
+
+#define SET_7_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out [6] = m0; \
+ out += 7; \
+} while(0)
+
+#define SET_6_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out [5] = m0; \
+ out += 6; \
+} while(0)
+
+#define SET_5_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out [4] = m0; \
+ out += 5; \
+} while(0)
+
+#define SET_4_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out [3] = m0; \
+ out += 4; \
+} while(0)
+
+#define SET_3_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out [2] = m0; \
+ out += 3; \
+} while(0)
+
+#define SET_2_OBJECTS(out) \
+do { \
+ out [0] = m0; \
+ out [1] = m0; \
+ out += 2; \
+} while(0)
+
+#define SET_1_OBJECT(out) \
+do { \
+ out [0] = m0; \
+ out += 1; \
+} while(0)
+
+
+static inline void
+__int_memset (void *__restrict s1, int val, size_t n)
+{
+ int value = n;
+ int loop_var;
+ int *out = s1;
+ int count;
+ int m0 = val;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ SET_1_OBJECT (out);
+ break;
+ case 2:
+ SET_2_OBJECTS (out);
+ break;
+ case 3:
+ SET_3_OBJECTS (out);
+ break;
+ case 4:
+ SET_4_OBJECTS (out);
+ break;
+ case 5:
+ SET_5_OBJECTS (out);
+ break;
+ case 6:
+ SET_6_OBJECTS (out);
+ break;
+ case 7:
+ SET_7_OBJECTS (out);
+ break;
+ case 8:
+ SET_8_OBJECTS (out);
+ break;
+ case 9:
+ SET_9_OBJECTS (out);
+ break;
+ case 10:
+ SET_10_OBJECTS (out);
+ break;
+ case 11:
+ SET_11_OBJECTS (out);
+ break;
+ case 12:
+ SET_12_OBJECTS (out);
+ break;
+ case 13:
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 14:
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 15:
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 16:
+ SET_16_OBJECTS (out);
+ break;
+ case 17:
+ SET_11_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 18:
+ SET_9_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 19:
+ SET_16_OBJECTS (out);
+ SET_3_OBJECTS (out);
+ break;
+ case 20:
+ SET_16_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 21:
+ SET_16_OBJECTS (out);
+ SET_5_OBJECTS (out);
+ break;
+ case 22:
+ SET_16_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 23:
+ SET_16_OBJECTS (out);
+ SET_7_OBJECTS (out);
+ break;
+ case 24:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ break;
+ case 25:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 26:
+ SET_16_OBJECTS (out);
+ SET_10_OBJECTS (out);
+ break;
+ case 27:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ break;
+ case 28:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 29:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 30:
+ SET_16_OBJECTS (out);
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 31:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ SET_32_OBJECTS (out);
+}
+
+static inline void
+__short_int_memset (void *__restrict s1, int val, size_t n)
+{
+ int value = n;
+ int loop_var;
+ int short *out = s1;
+ int count;
+ int m0 = val;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ SET_1_OBJECT (out);
+ break;
+ case 2:
+ SET_2_OBJECTS (out);
+ break;
+ case 3:
+ SET_3_OBJECTS (out);
+ break;
+ case 4:
+ SET_4_OBJECTS (out);
+ break;
+ case 5:
+ SET_5_OBJECTS (out);
+ break;
+ case 6:
+ SET_6_OBJECTS (out);
+ break;
+ case 7:
+ SET_7_OBJECTS (out);
+ break;
+ case 8:
+ SET_8_OBJECTS (out);
+ break;
+ case 9:
+ SET_9_OBJECTS (out);
+ break;
+ case 10:
+ SET_10_OBJECTS (out);
+ break;
+ case 11:
+ SET_11_OBJECTS (out);
+ break;
+ case 12:
+ SET_12_OBJECTS (out);
+ break;
+ case 13:
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 14:
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 15:
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 16:
+ SET_16_OBJECTS (out);
+ break;
+ case 17:
+ SET_11_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 18:
+ SET_9_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 19:
+ SET_16_OBJECTS (out);
+ SET_3_OBJECTS (out);
+ break;
+ case 20:
+ SET_16_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 21:
+ SET_16_OBJECTS (out);
+ SET_5_OBJECTS (out);
+ break;
+ case 22:
+ SET_16_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 23:
+ SET_16_OBJECTS (out);
+ SET_7_OBJECTS (out);
+ break;
+ case 24:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ break;
+ case 25:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 26:
+ SET_16_OBJECTS (out);
+ SET_10_OBJECTS (out);
+ break;
+ case 27:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ break;
+ case 28:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 29:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 30:
+ SET_16_OBJECTS (out);
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 31:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ SET_32_OBJECTS (out);
+}
+
+static inline void
+__byte_memset (void *__restrict s1, int val, size_t n)
+{
+ int value = n;
+ int loop_var;
+ char *out = s1;
+ int count;
+ int m0 = val;
+
+ /* This code currently give a stall for any value with a 1->2 in the low 5
+ bits, i.e. 1,2, 33,34 ? not acceptable! */
+ switch (value & 0x1f)
+ {
+ case 0:
+ break;
+ case 1:
+ SET_1_OBJECT (out);
+ break;
+ case 2:
+ SET_2_OBJECTS (out);
+ break;
+ case 3:
+ SET_3_OBJECTS (out);
+ break;
+ case 4:
+ SET_4_OBJECTS (out);
+ break;
+ case 5:
+ SET_5_OBJECTS (out);
+ break;
+ case 6:
+ SET_6_OBJECTS (out);
+ break;
+ case 7:
+ SET_7_OBJECTS (out);
+ break;
+ case 8:
+ SET_8_OBJECTS (out);
+ break;
+ case 9:
+ SET_9_OBJECTS (out);
+ break;
+ case 10:
+ SET_10_OBJECTS (out);
+ break;
+ case 11:
+ SET_11_OBJECTS (out);
+ break;
+ case 12:
+ SET_12_OBJECTS (out);
+ break;
+ case 13:
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 14:
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 15:
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 16:
+ SET_16_OBJECTS (out);
+ break;
+ case 17:
+ SET_11_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 18:
+ SET_9_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 19:
+ SET_16_OBJECTS (out);
+ SET_3_OBJECTS (out);
+ break;
+ case 20:
+ SET_16_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 21:
+ SET_16_OBJECTS (out);
+ SET_5_OBJECTS (out);
+ break;
+ case 22:
+ SET_16_OBJECTS (out);
+ SET_6_OBJECTS (out);
+ break;
+ case 23:
+ SET_16_OBJECTS (out);
+ SET_7_OBJECTS (out);
+ break;
+ case 24:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ break;
+ case 25:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ break;
+ case 26:
+ SET_16_OBJECTS (out);
+ SET_10_OBJECTS (out);
+ break;
+ case 27:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ break;
+ case 28:
+ SET_16_OBJECTS (out);
+ SET_8_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 29:
+ SET_16_OBJECTS (out);
+ SET_9_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ case 30:
+ SET_16_OBJECTS (out);
+ SET_12_OBJECTS (out);
+ SET_2_OBJECTS (out);
+ break;
+ case 31:
+ SET_16_OBJECTS (out);
+ SET_11_OBJECTS (out);
+ SET_4_OBJECTS (out);
+ break;
+ }
+
+ /* This loop governs the asmptoptic behaviour of this algorithm, for long
+ word copies. */
+ count = value >> 5;
+ for (loop_var = 0; loop_var < count; loop_var++)
+ SET_32_OBJECTS (out);
+}
+
+
+/* Exposed interface. */
+
+void
+__long_int_memset (void *__restrict s, int c, size_t n)
+{
+ int ic = (c << 24) + ((char) c << 16) + ((char) c << 8) + (char) c;
+ __int_memset (s, ic, n);
+}
+
+void
+__wrd_memset (void *__restrict s, int c, size_t n)
+{
+ int sc = ((c << 8) + (char) c);
+ __short_int_memset (s, sc, n);
+}
+
+void
+__byt_memset (void *__restrict s, int c, size_t n)
+{
+ __byte_memset (s, c, n);
+}
diff --git a/libgcc/config/visium/memset.h b/libgcc/config/visium/memset.h
new file mode 100644
index 00000000000..92eb1a3b859
--- /dev/null
+++ b/libgcc/config/visium/memset.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2012-2015 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Specialized variants of memset called directly from compiled code. */
+
+extern void
+__long_int_memset (void *__restrict s, int c, size_t n);
+
+extern void
+__wrd_memset (void *__restrict s, int c, size_t n);
+
+extern void
+__byt_memset (void *__restrict s, int c, size_t n);
diff --git a/libgcc/config/visium/moddi3.c b/libgcc/config/visium/moddi3.c
new file mode 100644
index 00000000000..bf7a63f3a3a
--- /dev/null
+++ b/libgcc/config/visium/moddi3.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_moddi3
+#include "lib2funcs.c"
diff --git a/libgcc/config/visium/set_trampoline_parity.c b/libgcc/config/visium/set_trampoline_parity.c
new file mode 100644
index 00000000000..134cf2b7c87
--- /dev/null
+++ b/libgcc/config/visium/set_trampoline_parity.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_set_trampoline_parity
+#include "lib2funcs.c"
diff --git a/libgcc/config/visium/t-visium b/libgcc/config/visium/t-visium
new file mode 100644
index 00000000000..ea5976291c1
--- /dev/null
+++ b/libgcc/config/visium/t-visium
@@ -0,0 +1,29 @@
+# Copyright (C) 2003-2015 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+LIB2FUNCS_EXCLUDE += _divdi3 _moddi3 _udivdi3 _umoddi3 _udivmoddi4
+
+LIB2ADD += \
+ $(srcdir)/config/visium/divdi3.c \
+ $(srcdir)/config/visium/moddi3.c \
+ $(srcdir)/config/visium/udivdi3.c \
+ $(srcdir)/config/visium/umoddi3.c \
+ $(srcdir)/config/visium/udivmoddi4.c \
+ $(srcdir)/config/visium/memcpy.c \
+ $(srcdir)/config/visium/memset.c \
+ $(srcdir)/config/visium/set_trampoline_parity.c
diff --git a/libgcc/config/visium/udivdi3.c b/libgcc/config/visium/udivdi3.c
new file mode 100644
index 00000000000..c595251971b
--- /dev/null
+++ b/libgcc/config/visium/udivdi3.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_udivdi3
+#include "lib2funcs.c"
diff --git a/libgcc/config/visium/udivmoddi4.c b/libgcc/config/visium/udivmoddi4.c
new file mode 100644
index 00000000000..bd45a5c7c6f
--- /dev/null
+++ b/libgcc/config/visium/udivmoddi4.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_udivmoddi4
+#include "lib2funcs.c"
diff --git a/libgcc/config/visium/umoddi3.c b/libgcc/config/visium/umoddi3.c
new file mode 100644
index 00000000000..cd2b23e0d05
--- /dev/null
+++ b/libgcc/config/visium/umoddi3.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#define L_umoddi3
+#include "lib2funcs.c"