From 65a324b459e60405cebe9e34ee6b3496559cd217 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 26 Oct 2009 16:30:15 +0000 Subject: [PATCH] MAINTAINERS: Add myself as a maintainer for the RX port. * MAINTAINERS: Add myself as a maintainer for the RX port. gcc * config.gcc: Add support for RX target. * config/rx: New directory. * config/rx/constraints.md: New file. * config/rx/predicates.md: New file. * config/rx/rx.c: New file. * config/rx/rx.h: New file. * config/rx/rx.md: New file. * config/rx/rx.opt: New file. * config/rx/rx-protos.h: New file. * config/rx/t-rx: New file. * doc/extend.texi: Document RX function attributes. * doc/invoke.texi: Document RX specific command line options. * doc/contrib.texi: Document RX contribution. * doc/md.texi: Document RX constraints. * doc/install.texi: Document RX support. libgcc * config.host: Add support for RX target. * config/rx: New directory. * config/rx/rx-abi-functions.c: New file. Supplementary functions for libgcc to support the RX ABI. * config/rx/rx-abi.h: New file. Supplementary header file for libgcc RX ABI functions. * config/rx/t-rx: New file: Makefile fragment for building libgcc for the RX. gcc/testsuite * lib/target-supports.exp (check_profiling_available): Profiling is not, currently, available for the RX port. (check_effective_target_hard_float): Add support for RX target. * gcc.target/rx: New directory. * gcc.target/rx/builtins.c: New test file. * gcc.target/rx/interrupts.c: New test file. * gcc.target/rx/rx-abi-function-tests.c: New test file. * gcc.target/rx/zero-width-bitfield.c: New test file. * gcc.target/rx/i272091.c: New test file. * gcc.target/rx/packed-struct.c: New test file. * gcc.target/rx/rx.exp: New file: Drives RX tests. From-SVN: r153557 --- ChangeLog | 4 + MAINTAINERS | 1 + gcc/ChangeLog | 18 + gcc/config.gcc | 6 +- gcc/config/rx/constraints.md | 81 + gcc/config/rx/predicates.md | 282 ++ gcc/config/rx/rx-protos.h | 52 + gcc/config/rx/rx.c | 2363 +++++++++++++++++ gcc/config/rx/rx.h | 632 +++++ gcc/config/rx/rx.md | 1780 +++++++++++++ gcc/config/rx/rx.opt | 74 + gcc/config/rx/t-rx | 32 + gcc/doc/contrib.texi | 4 +- gcc/doc/extend.texi | 132 +- gcc/doc/install.texi | 8 + gcc/doc/invoke.texi | 119 +- gcc/doc/md.texi | 26 + gcc/doc/tm.texi | 42 +- gcc/testsuite/ChangeLog | 15 + gcc/testsuite/gcc.target/rx/builtins.c | 159 ++ gcc/testsuite/gcc.target/rx/i272091.c | 27 + gcc/testsuite/gcc.target/rx/interrupts.c | 58 + gcc/testsuite/gcc.target/rx/packed-struct.c | 55 + .../gcc.target/rx/rx-abi-function-tests.c | 159 ++ gcc/testsuite/gcc.target/rx/rx.exp | 43 + .../gcc.target/rx/zero-width-bitfield.c | 32 + gcc/testsuite/lib/target-supports.exp | 19 +- libgcc/ChangeLog | 11 + libgcc/config.host | 4 + libgcc/config/rx/rx-abi-functions.c | 90 + libgcc/config/rx/rx-abi.h | 235 ++ libgcc/config/rx/t-rx | 44 + 32 files changed, 6578 insertions(+), 29 deletions(-) create mode 100644 gcc/config/rx/constraints.md create mode 100644 gcc/config/rx/predicates.md create mode 100644 gcc/config/rx/rx-protos.h create mode 100644 gcc/config/rx/rx.c create mode 100644 gcc/config/rx/rx.h create mode 100644 gcc/config/rx/rx.md create mode 100644 gcc/config/rx/rx.opt create mode 100644 gcc/config/rx/t-rx create mode 100644 gcc/testsuite/gcc.target/rx/builtins.c create mode 100644 gcc/testsuite/gcc.target/rx/i272091.c create mode 100644 gcc/testsuite/gcc.target/rx/interrupts.c create mode 100644 gcc/testsuite/gcc.target/rx/packed-struct.c create mode 100644 gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c create mode 100644 gcc/testsuite/gcc.target/rx/rx.exp create mode 100644 gcc/testsuite/gcc.target/rx/zero-width-bitfield.c create mode 100644 libgcc/config/rx/rx-abi-functions.c create mode 100644 libgcc/config/rx/rx-abi.h create mode 100644 libgcc/config/rx/t-rx diff --git a/ChangeLog b/ChangeLog index d7011d35f77..7c9bcf60b2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-16 Nick Clifton + + * MAINTAINERS: Add myself as a maintainer for the RX port. + 2009-10-26 Johannes Singler * MAINTAINERS (Write After Approval): Update my e-mail address. diff --git a/MAINTAINERS b/MAINTAINERS index 8df8173448e..ed045813a06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -82,6 +82,7 @@ picochip port Daniel Towner dant@picochip.com rs6000 port Geoff Keating geoffk@geoffk.org rs6000 port David Edelsohn edelsohn@gnu.org rs6000 vector extns Aldy Hernandez aldyh@redhat.com +rx port Nick Clifton nickc@redhat.com s390 port Hartmut Penner hpenner@de.ibm.com s390 port Ulrich Weigand uweigand@de.ibm.com s390 port Andreas Krebbel Andreas.Krebbel@de.ibm.com diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 53a554ed6c9..ea4e772bfb2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2009-10-26 Nick Clifton + + * config.gcc: Add support for RX target. + * config/rx: New directory. + * config/rx/constraints.md: New file. + * config/rx/predicates.md: New file. + * config/rx/rx.c: New file. + * config/rx/rx.h: New file. + * config/rx/rx.md: New file. + * config/rx/rx.opt: New file. + * config/rx/rx-protos.h: New file. + * config/rx/t-rx: New file. + * doc/extend.texi: Document RX function attributes. + * doc/invoke.texi: Document RX specific command line options. + * doc/contrib.texi: Document RX contribution. + * doc/md.texi: Document RX constraints. + * doc/install.texi: Document RX support. + 2009-10-26 Michael Matz PR tree-optimization/41783 diff --git a/gcc/config.gcc b/gcc/config.gcc index 7666dd61861..7dac3004cd8 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -287,7 +287,7 @@ i[34567]86-*-*) extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h - immintrin.h x86intrin.h avxintrin.h + immintrin.h x86intrin.h avxintrin.h ia32intrin.h cross-stdarg.h" ;; x86_64-*-*) @@ -2077,6 +2077,10 @@ rs6000-ibm-aix[6789].* | powerpc-ibm-aix[6789].*) use_gcc_stdint=wrap extra_headers=altivec.h ;; +rx-*-elf*) + tm_file="dbxelf.h elfos.h svr4.h newlib-stdint.h ${tm_file} ../../libgcc/config/rx/rx-abi.h" + tmake_file="${tmake_file} rx/t-rx" + ;; s390-*-linux*) tm_file="s390/s390.h dbxelf.h elfos.h svr4.h linux.h glibc-stdint.h s390/linux.h" ;; diff --git a/gcc/config/rx/constraints.md b/gcc/config/rx/constraints.md new file mode 100644 index 00000000000..f15b586afb5 --- /dev/null +++ b/gcc/config/rx/constraints.md @@ -0,0 +1,81 @@ +;; Constraint definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +(define_constraint "Symbol" + "@internal Constraint on the type of rtx allowed in call insns" + (match_test "GET_CODE (op) == SYMBOL_REF") +) + + +(define_constraint "Int08" + "@internal A signed or unsigned 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 8), (1 << 8) - 1)") + ) +) + +(define_constraint "Sint08" + "@internal A signed 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 7), (1 << 7) - 1)") + ) +) + +(define_constraint "Sint16" + "@internal A signed 16-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 15), (1 << 15) - 1)") + ) +) + +(define_constraint "Sint24" + "@internal A signed 24-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 23), (1 << 23) - 1)") + ) +) + +;; This constraint is used by the SUBSI3 pattern because the +;; RX SUB instruction can only take a 4-bit unsigned integer +;; value. +(define_constraint "Uint04" + "@internal An unsigned 4-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 15)") + ) +) + +;; This is used in arithmetic and logic instructions for +;; a source operand that lies in memory and which satisfies +;; rx_restricted_memory_address(). + +(define_memory_constraint "Q" + "A MEM which only uses REG or REG+INT addressing." + (and (match_code "mem") + (ior (match_code "reg" "0") + (and (match_code "plus" "0") + (and (match_code "reg,subreg" "00") + (match_code "const_int" "01") + ) + ) + ) + ) +) diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md new file mode 100644 index 00000000000..75cf8ebaed8 --- /dev/null +++ b/gcc/config/rx/predicates.md @@ -0,0 +1,282 @@ +;; Predicate definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; 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 +;; . + + + +;; Check that the operand is suitable for a call insn. +;; Only registers and symbol refs are allowed. + +(define_predicate "rx_call_operand" + (match_code "symbol_ref,reg") +) + +;; For sibcall operations we can only use a symbolic address. + +(define_predicate "rx_symbolic_call_operand" + (match_code "symbol_ref") +) + +;; Check that the operand is suitable for a shift insn +;; Only small integers or a value in a register are permitted. + +(define_predicate "rx_shift_operand" + (match_code "const_int,reg") + { + if (CONST_INT_P (op)) + return IN_RANGE (INTVAL (op), 0, 31); + return true; + } +) + +;; Check that the operand is suitable as the source operand +;; for a logic or arithmeitc instruction. Registers, integers +;; and a restricted subset of memory addresses are allowed. + +(define_predicate "rx_source_operand" + (match_code "const_int,reg,mem") + { + if (CONST_INT_P (op)) + return rx_is_legitimate_constant (op); + + if (! MEM_P (op)) + return true; + + /* Do not allow size conversions whilst accessing memory. */ + if (GET_MODE (op) != mode) + return false; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Check that the operand is suitable as the source operand +;; for a comparison instruction. This is the same as +;; rx_source_operand except that SUBREGs are allowed but +;; CONST_INTs are not. + +(define_predicate "rx_compare_operand" + (match_code "subreg,reg,mem") + { + if (GET_CODE (op) == SUBREG) + return REG_P (XEXP (op, 0)); + + if (! MEM_P (op)) + return true; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Return true if OP is a store multiple operation. This looks like: +;; +;; [(set (SP) (MINUS (SP) (INT))) +;; (set (MEM (SP)) (REG)) +;; (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated} +;; ] + +(define_special_predicate "rx_store_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int src_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != MINUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! MEM_P (SET_DEST (element)) + || ! REG_P (XEXP (SET_DEST (element), 0)) + || REGNO (XEXP (SET_DEST (element), 0)) != SP_REG + || ! REG_P (SET_SRC (element))) + return false; + + src_regno = REGNO (SET_SRC (element)); + + /* Check that the remaining elements use SP- + addressing and incremental register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || REGNO (SET_SRC (element)) != src_regno + (i - 1) + || ! MEM_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS + || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated} +;; ] + +(define_special_predicate "rx_load_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements use SP+ + addressing and incremental register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a pop-and-return load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated} +;; (return) +;; ] + +(define_special_predicate "rx_rtsd_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements, if any, and except + for the last one, use SP+ addressing and incremental + register numbers. */ + for (i = 2; i < count - 1; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + + /* The last element must be a RETURN. */ + element = XVECEXP (op, 0, count - 1); + return GET_CODE (element) == RETURN; +}) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h new file mode 100644 index 00000000000..5c37fe0a83c --- /dev/null +++ b/gcc/config/rx/rx-protos.h @@ -0,0 +1,52 @@ +/* Exported function prototypes from the Renesas RX backend. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#ifndef GCC_RX_PROTOS_H +#define GCC_RX_PROTOS_H + +/* A few abbreviations to make the prototypes shorter. */ +#define Mmode enum machine_mode +#define Fargs CUMULATIVE_ARGS + +extern void rx_conditional_register_usage (void); +extern void rx_expand_prologue (void); +extern int rx_initial_elimination_offset (int, int); + +#ifdef RTX_CODE +extern void rx_emit_stack_popm (rtx *, bool); +extern void rx_emit_stack_pushm (rtx *); +extern void rx_expand_epilogue (bool); +extern bool rx_expand_insv (rtx *); +extern const char * rx_gen_cond_branch_template (rtx, bool); +extern char * rx_gen_move_template (rtx *, bool); +extern bool rx_is_legitimate_constant (rtx); +extern bool rx_is_mode_dependent_addr (rtx); +extern bool rx_is_restricted_memory_address (rtx, Mmode); +extern void rx_notice_update_cc (rtx body, rtx insn); +extern void rx_print_operand (FILE *, rtx, int); +extern void rx_print_operand_address (FILE *, rtx); +#endif + +#ifdef TREE_CODE +extern unsigned int rx_function_arg_size (Mmode, const_tree); +extern struct rtx_def * rx_function_arg (Fargs *, Mmode, const_tree, bool); +#endif + +#endif /* GCC_RX_PROTOS_H */ diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c new file mode 100644 index 00000000000..cf2b098e83c --- /dev/null +++ b/gcc/config/rx/rx.c @@ -0,0 +1,2363 @@ +/* Subroutines used for code generation on Renesas RX processors. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 + . */ + +/* To Do: + + * Re-enable memory-to-memory copies and fix up reload. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "libfuncs.h" +#include "recog.h" +#include "toplev.h" +#include "reload.h" +#include "df.h" +#include "ggc.h" +#include "tm_p.h" +#include "debug.h" +#include "target.h" +#include "target-def.h" +#include "langhooks.h" + +/* Return true if OP is a reference to an object in a small data area. */ + +static bool +rx_small_data_operand (rtx op) +{ + if (rx_small_data_limit == 0) + return false; + + if (GET_CODE (op) == SYMBOL_REF) + return SYMBOL_REF_SMALL_P (op); + + return false; +} + +static bool +rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED) +{ + if (RTX_OK_FOR_BASE (x, strict)) + /* Register Indirect. */ + return true; + + if (GET_MODE_SIZE (mode) == 4 + && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)) + /* Pre-decrement Register Indirect or + Post-increment Register Indirect. */ + return RTX_OK_FOR_BASE (XEXP (x, 0), strict); + + if (GET_CODE (x) == PLUS) + { + rtx arg1 = XEXP (x, 0); + rtx arg2 = XEXP (x, 1); + rtx index = NULL_RTX; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, strict)) + index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, strict)) + index = arg1; + else + return false; + + switch (GET_CODE (index)) + { + case CONST_INT: + { + /* Register Relative: REG + INT. + Only positive, mode-aligned, mode-sized + displacements are allowed. */ + HOST_WIDE_INT val = INTVAL (index); + int factor; + + if (val < 0) + return false; + + switch (GET_MODE_SIZE (mode)) + { + default: + case 4: factor = 4; break; + case 2: factor = 2; break; + case 1: factor = 1; break; + } + + if (val > (65535 * factor)) + return false; + return (val % factor) == 0; + } + + case REG: + /* Unscaled Indexed Register Indirect: REG + REG + Size has to be "QI", REG has to be valid. */ + return GET_MODE_SIZE (mode) == 1 && RTX_OK_FOR_BASE (index, strict); + + case MULT: + { + /* Scaled Indexed Register Indirect: REG + (REG * FACTOR) + Factor has to equal the mode size, REG has to be valid. */ + rtx factor; + + factor = XEXP (index, 1); + index = XEXP (index, 0); + + return REG_P (index) + && RTX_OK_FOR_BASE (index, strict) + && CONST_INT_P (factor) + && GET_MODE_SIZE (mode) == INTVAL (factor); + } + + default: + return false; + } + } + + /* Small data area accesses turn into register relative offsets. */ + return rx_small_data_operand (x); +} + +/* Returns TRUE for simple memory addreses, ie ones + that do not involve register indirect addressing + or pre/post increment/decrement. */ + +bool +rx_is_restricted_memory_address (rtx mem, enum machine_mode mode) +{ + rtx base, index; + + if (! rx_is_legitimate_address + (mode, mem, reload_in_progress || reload_completed)) + return false; + + switch (GET_CODE (mem)) + { + case REG: + /* Simple memory addresses are OK. */ + return true; + + case PRE_DEC: + case POST_INC: + return false; + + case PLUS: + /* Only allow REG+INT addressing. */ + base = XEXP (mem, 0); + index = XEXP (mem, 1); + + return RX_REG_P (base) && CONST_INT_P (index); + + case SYMBOL_REF: + /* Can happen when small data is being supported. + Assume that it will be resolved into GP+INT. */ + return true; + + default: + gcc_unreachable (); + } +} + +bool +rx_is_mode_dependent_addr (rtx addr) +{ + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + switch (GET_CODE (addr)) + { + /* --REG and REG++ only work in SImode. */ + case PRE_DEC: + case POST_INC: + return true; + + case MINUS: + case PLUS: + if (! REG_P (XEXP (addr, 0))) + return true; + + addr = XEXP (addr, 1); + + switch (GET_CODE (addr)) + { + case REG: + /* REG+REG only works in SImode. */ + return true; + + case CONST_INT: + /* REG+INT is only mode independent if INT is a + multiple of 4, positive and will fit into 8-bits. */ + if (((INTVAL (addr) & 3) == 0) + && IN_RANGE (INTVAL (addr), 4, 252)) + return false; + return true; + + case SYMBOL_REF: + case LABEL_REF: + return true; + + case MULT: + gcc_assert (REG_P (XEXP (addr, 0))); + gcc_assert (CONST_INT_P (XEXP (addr, 1))); + /* REG+REG*SCALE is always mode dependent. */ + return true; + + default: + /* Not recognized, so treat as mode dependent. */ + return true; + } + + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case REG: + /* These are all mode independent. */ + return false; + + default: + /* Everything else is unrecognized, + so treat as mode dependent. */ + return true; + } +} + + +/* A C compound statement to output to stdio stream FILE the + assembler syntax for an instruction operand that is a memory + reference whose address is ADDR. */ + +void +rx_print_operand_address (FILE * file, rtx addr) +{ + switch (GET_CODE (addr)) + { + case REG: + fprintf (file, "["); + rx_print_operand (file, addr, 0); + fprintf (file, "]"); + break; + + case PRE_DEC: + fprintf (file, "[-"); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "]"); + break; + + case POST_INC: + fprintf (file, "["); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "+]"); + break; + + case PLUS: + { + rtx arg1 = XEXP (addr, 0); + rtx arg2 = XEXP (addr, 1); + rtx base, index; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, true)) + base = arg1, index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, true)) + base = arg2, index = arg1; + else + { + rx_print_operand (file, arg1, 0); + fprintf (file, " + "); + rx_print_operand (file, arg2, 0); + break; + } + + if (REG_P (index) || GET_CODE (index) == MULT) + { + fprintf (file, "["); + rx_print_operand (file, index, 'A'); + fprintf (file, ","); + } + else /* GET_CODE (index) == CONST_INT */ + { + rx_print_operand (file, index, 'A'); + fprintf (file, "["); + } + rx_print_operand (file, base, 0); + fprintf (file, "]"); + break; + } + + case LABEL_REF: + case SYMBOL_REF: + case CONST: + fprintf (file, "#"); + default: + output_addr_const (file, addr); + break; + } +} + +static void +rx_print_integer (FILE * file, HOST_WIDE_INT val) +{ + if (IN_RANGE (val, -64, 64)) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, val); + else + fprintf (file, + TARGET_AS100_SYNTAX + ? "0%" HOST_WIDE_INT_PRINT "xH" : HOST_WIDE_INT_PRINT_HEX, + val); +} + +static bool +rx_assemble_integer (rtx x, unsigned int size, int is_aligned) +{ + const char * op = integer_asm_op (size, is_aligned); + + if (! CONST_INT_P (x)) + return default_assemble_integer (x, size, is_aligned); + + if (op == NULL) + return false; + fputs (op, asm_out_file); + + rx_print_integer (asm_out_file, INTVAL (x)); + fputc ('\n', asm_out_file); + return true; +} + + +int rx_float_compare_mode; + +/* Handles the insertion of a single operand into the assembler output. + The % directives supported are: + + %A Print an operand without a leading # character. + %B Print an integer comparison name. + %C Print a control register name. + %F Print a condition code flag name. + %H Print high part of a DImode register, integer or address. + %L Print low part of a DImode register, integer or address. + %Q If the operand is a MEM, then correctly generate + register indirect or register relative addressing. */ + +void +rx_print_operand (FILE * file, rtx op, int letter) +{ + switch (letter) + { + case 'A': + /* Print an operand without a leading #. */ + if (MEM_P (op)) + op = XEXP (op, 0); + + switch (GET_CODE (op)) + { + case LABEL_REF: + case SYMBOL_REF: + output_addr_const (file, op); + break; + case CONST_INT: + fprintf (file, "%ld", (long) INTVAL (op)); + break; + default: + rx_print_operand (file, op, 0); + break; + } + break; + + case 'B': + switch (GET_CODE (op)) + { + case LT: fprintf (file, "lt"); break; + case GE: fprintf (file, "ge"); break; + case GT: fprintf (file, "gt"); break; + case LE: fprintf (file, "le"); break; + case GEU: fprintf (file, "geu"); break; + case LTU: fprintf (file, "ltu"); break; + case GTU: fprintf (file, "gtu"); break; + case LEU: fprintf (file, "leu"); break; + case EQ: fprintf (file, "eq"); break; + case NE: fprintf (file, "ne"); break; + default: debug_rtx (op); gcc_unreachable (); + } + break; + + case 'C': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: fprintf (file, "psw"); break; + case 2: fprintf (file, "usp"); break; + case 3: fprintf (file, "fpsw"); break; + case 4: fprintf (file, "cpen"); break; + case 8: fprintf (file, "bpsw"); break; + case 9: fprintf (file, "bpc"); break; + case 0xa: fprintf (file, "isp"); break; + case 0xb: fprintf (file, "fintv"); break; + case 0xc: fprintf (file, "intb"); break; + default: + gcc_unreachable (); + } + break; + + case 'F': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: case 'c': case 'C': fprintf (file, "C"); break; + case 1: case 'z': case 'Z': fprintf (file, "Z"); break; + case 2: case 's': case 'S': fprintf (file, "S"); break; + case 3: case 'o': case 'O': fprintf (file, "O"); break; + case 8: case 'i': case 'I': fprintf (file, "I"); break; + case 9: case 'u': case 'U': fprintf (file, "U"); break; + default: + gcc_unreachable (); + } + break; + + case 'H': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 0 : 1)]); + else if (CONST_INT_P (op)) + { + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op) >> 32); + } + else + { + gcc_assert (MEM_P (op)); + + if (! WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'L': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 1 : 0)]); + else if (CONST_INT_P (op)) + { + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op) & 0xffffffff); + } + else + { + gcc_assert (MEM_P (op)); + + if (WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'Q': + if (MEM_P (op)) + { + HOST_WIDE_INT offset; + + op = XEXP (op, 0); + + if (REG_P (op)) + offset = 0; + else if (GET_CODE (op) == PLUS) + { + rtx displacement; + + if (REG_P (XEXP (op, 0))) + { + displacement = XEXP (op, 1); + op = XEXP (op, 0); + } + else + { + displacement = XEXP (op, 0); + op = XEXP (op, 1); + gcc_assert (REG_P (op)); + } + + gcc_assert (CONST_INT_P (displacement)); + offset = INTVAL (displacement); + gcc_assert (offset >= 0); + + fprintf (file, "%ld", offset); + } + else + gcc_unreachable (); + + fprintf (file, "["); + rx_print_operand (file, op, 0); + fprintf (file, "]."); + + switch (GET_MODE_SIZE (GET_MODE (op))) + { + case 1: + gcc_assert (offset < 65535 * 1); + fprintf (file, "B"); + break; + case 2: + gcc_assert (offset % 2 == 0); + gcc_assert (offset < 65535 * 2); + fprintf (file, "W"); + break; + default: + gcc_assert (offset % 4 == 0); + gcc_assert (offset < 65535 * 4); + fprintf (file, "L"); + break; + } + break; + } + + /* Fall through. */ + + default: + switch (GET_CODE (op)) + { + case MULT: + /* Should be the scaled part of an + indexed register indirect address. */ + { + rtx base = XEXP (op, 0); + rtx index = XEXP (op, 1); + + /* Check for a swaped index register and scaling factor. + Not sure if this can happen, but be prepared to handle it. */ + if (CONST_INT_P (base) && REG_P (index)) + { + rtx tmp = base; + base = index; + index = tmp; + } + + gcc_assert (REG_P (base)); + gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); + gcc_assert (CONST_INT_P (index)); + /* Do not try to verify the value of the scalar as it is based + on the mode of the MEM not the mode of the MULT. (Which + will always be SImode). */ + fprintf (file, "%s", reg_names [REGNO (base)]); + break; + } + + case MEM: + output_address (XEXP (op, 0)); + break; + + case PLUS: + output_address (op); + break; + + case REG: + gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [REGNO (op)]); + break; + + case SUBREG: + gcc_assert (subreg_regno (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [subreg_regno (op)]); + break; + + /* This will only be single precision.... */ + case CONST_DOUBLE: + { + unsigned long val; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + fprintf (file, TARGET_AS100_SYNTAX ? "#0%lxH" : "#0x%lx", val); + break; + } + + case CONST_INT: + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op)); + break; + + case SYMBOL_REF: + case CONST: + case LABEL_REF: + case CODE_LABEL: + case UNSPEC: + rx_print_operand_address (file, op); + break; + + default: + gcc_unreachable (); + } + break; + } +} + +/* Returns an assembler template for a move instruction. */ + +char * +rx_gen_move_template (rtx * operands, bool is_movu) +{ + static char template [64]; + const char * extension = TARGET_AS100_SYNTAX ? ".L" : ""; + const char * src_template; + const char * dst_template; + rtx dest = operands[0]; + rtx src = operands[1]; + + /* Decide which extension, if any, should be given to the move instruction. */ + switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src)) + { + case QImode: + /* The .B extension is not valid when + loading an immediate into a register. */ + if (! REG_P (dest) || ! CONST_INT_P (src)) + extension = ".B"; + break; + case HImode: + if (! REG_P (dest) || ! CONST_INT_P (src)) + /* The .W extension is not valid when + loading an immediate into a register. */ + extension = ".W"; + break; + case SFmode: + case SImode: + extension = ".L"; + break; + case VOIDmode: + /* This mode is used by constants. */ + break; + default: + debug_rtx (src); + gcc_unreachable (); + } + + if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0))) + src_template = "%%gp(%A1)[r13]"; + else + src_template = "%1"; + + if (MEM_P (dest) && rx_small_data_operand (XEXP (dest, 0))) + dst_template = "%%gp(%A0)[r13]"; + else + dst_template = "%0"; + + sprintf (template, "%s%s\t%s, %s", is_movu ? "movu" : "mov", + extension, src_template, dst_template); + return template; +} + +/* Returns an assembler template for a conditional branch instruction. */ + +const char * +rx_gen_cond_branch_template (rtx condition, bool reversed) +{ + enum rtx_code code = GET_CODE (condition); + + + if ((cc_status.flags & CC_NO_OVERFLOW) && ! rx_float_compare_mode) + gcc_assert (code != GT && code != GE && code != LE && code != LT); + + if ((cc_status.flags & CC_NO_CARRY) || rx_float_compare_mode) + gcc_assert (code != GEU && code != GTU && code != LEU && code != LTU); + + if (reversed) + { + if (rx_float_compare_mode) + code = reverse_condition_maybe_unordered (code); + else + code = reverse_condition (code); + } + + /* We do not worry about encoding the branch length here as GAS knows + how to choose the smallest version, and how to expand a branch that + is to a destination that is out of range. */ + + switch (code) + { + case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:"; + case LTGT: return "bo\t1f\n\tbne\t%0\n1:"; + case UNLT: return "bo\t1f\n\tbn\t%0\n1:"; + case UNGE: return "bo\t1f\n\tbpz\t%0\n1:"; + case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:"; + case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:"; + case UNORDERED: return "bo\t%0"; + case ORDERED: return "bno\t%0"; + + case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0"; + case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0"; + case GT: return "bgt\t%0"; + case LE: return "ble\t%0"; + case GEU: return "bgeu\t%0"; + case LTU: return "bltu\t%0"; + case GTU: return "bgtu\t%0"; + case LEU: return "bleu\t%0"; + case EQ: return "beq\t%0"; + case NE: return "bne\t%0"; + default: + gcc_unreachable (); + } +} + +/* Return VALUE rounded up to the next ALIGNMENT boundary. */ + +static inline unsigned int +rx_round_up (unsigned int value, unsigned int alignment) +{ + alignment -= 1; + return (value + alignment) & (~ alignment); +} + +/* Return the number of bytes in the argument registers + occupied by an argument of type TYPE and mode MODE. */ + +unsigned int +rx_function_arg_size (Mmode mode, const_tree type) +{ + unsigned int num_bytes; + + num_bytes = (mode == BLKmode) + ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + return rx_round_up (num_bytes, UNITS_PER_WORD); +} + +#define NUM_ARG_REGS 4 +#define MAX_NUM_ARG_BYTES (NUM_ARG_REGS * UNITS_PER_WORD) + +/* Return an RTL expression describing the register holding a function + parameter of mode MODE and type TYPE or NULL_RTX if the parameter should + be passed on the stack. CUM describes the previous parameters to the + function and NAMED is false if the parameter is part of a variable + parameter list, or the last named parameter before the start of a + variable parameter list. */ + +rtx +rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named) +{ + unsigned int next_reg; + unsigned int bytes_so_far = *cum; + unsigned int size; + unsigned int rounded_size; + + /* An exploded version of rx_function_arg_size. */ + size = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + + rounded_size = rx_round_up (size, UNITS_PER_WORD); + + /* Don't pass this arg via registers if there + are insufficient registers to hold all of it. */ + if (rounded_size + bytes_so_far > MAX_NUM_ARG_BYTES) + return NULL_RTX; + + /* Unnamed arguments and the last named argument in a + variadic function are always passed on the stack. */ + if (!named) + return NULL_RTX; + + /* Structures must occupy an exact number of registers, + otherwise they are passed on the stack. */ + if ((type == NULL || AGGREGATE_TYPE_P (type)) + && (size % UNITS_PER_WORD) != 0) + return NULL_RTX; + + next_reg = (bytes_so_far / UNITS_PER_WORD) + 1; + + return gen_rtx_REG (mode, next_reg); +} + +/* Return an RTL describing where a function return value of type RET_TYPE + is held. */ + +static rtx +rx_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (ret_type), FUNC_RETURN_REGNUM); +} + +static bool +rx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT size; + + if (TYPE_MODE (type) != BLKmode + && ! AGGREGATE_TYPE_P (type)) + return false; + + size = int_size_in_bytes (type); + /* Large structs and those whose size is not an + exact multiple of 4 are returned in memory. */ + return size < 1 + || size > 16 + || (size % UNITS_PER_WORD) != 0; +} + +static rtx +rx_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (Pmode, STRUCT_VAL_REGNUM); +} + +static bool +rx_return_in_msb (const_tree valtype) +{ + return TARGET_BIG_ENDIAN_DATA + && (AGGREGATE_TYPE_P (valtype) || TREE_CODE (valtype) == COMPLEX_TYPE); +} + +/* Returns true if the provided function has the specified attribute. */ + +static inline bool +has_func_attr (const_tree decl, const char * func_attr) +{ + if (decl == NULL_TREE) + decl = current_function_decl; + + return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE; +} + +/* Returns true if the provided function has + the "[fast_]interrupt" attribute. */ + +static inline bool +is_fast_interrupt_func (const_tree decl) +{ + return has_func_attr (decl, "interrupt") + || has_func_attr (decl, "fast_interrupt") ; +} + +/* Returns true if the provided function has the "exception" attribute. */ + +static inline bool +is_exception_func (const_tree decl) +{ + return has_func_attr (decl, "exception"); +} + +/* Returns true if the provided function has the "naked" attribute. */ + +static inline bool +is_naked_func (const_tree decl) +{ + return has_func_attr (decl, "naked"); +} + +static bool use_fixed_regs = false; + +void +rx_conditional_register_usage (void) +{ + static bool using_fixed_regs = false; + + if (rx_small_data_limit > 0) + fixed_regs[GP_BASE_REGNUM] = call_used_regs [GP_BASE_REGNUM] = 1; + + if (use_fixed_regs != using_fixed_regs) + { + static char saved_fixed_regs[FIRST_PSEUDO_REGISTER]; + static char saved_call_used_regs[FIRST_PSEUDO_REGISTER]; + + if (use_fixed_regs) + { + unsigned int switched = 0; + unsigned int r; + + /* This is for fast interrupt handlers. Any register in + the range r10 to r13 (inclusive) that is currently + marked as fixed is now a viable, call-saved register. + All other registers are fixed. */ + memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs); + memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs); + + for (r = 1; r < 10; r++) + fixed_regs[r] = call_used_regs[r] = 1; + + for (r = 10; r <= 13; r++) + if (fixed_regs[r]) + { + fixed_regs[r] = 0; + call_used_regs[r] = 1; + ++ switched; + } + else + { + fixed_regs[r] = 1; + call_used_regs[r] = 1; + } + + fixed_regs[14] = call_used_regs[14] = 1; + fixed_regs[15] = call_used_regs[15] = 1; + + if (switched == 0) + { + static bool warned = false; + + if (! warned) + { + warning (0, "no fixed registers available " + "for use by fast interrupt handler"); + warned = true; + } + } + } + else + { + /* Restore the normal register masks. */ + memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs); + memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs); + } + + using_fixed_regs = use_fixed_regs; + } +} + +/* Perform any actions necessary before starting to compile FNDECL. + For the RX we use this to make sure that we have the correct + set of register masks selected. If FNDECL is NULL then we are + compiling top level things. */ + +static void +rx_set_current_function (tree fndecl) +{ + /* Remember the last target of rx_set_current_function. */ + static tree rx_previous_fndecl; + bool prev_was_interrupt; + bool current_is_interrupt; + + /* Only change the context if the function changes. This hook is called + several times in the course of compiling a function, and we don't want + to slow things down too much or call target_reinit when it isn't safe. */ + if (fndecl == rx_previous_fndecl) + return; + + prev_was_interrupt + = rx_previous_fndecl + ? is_fast_interrupt_func (rx_previous_fndecl) : false; + current_is_interrupt + = fndecl ? is_fast_interrupt_func (fndecl) : false; + + if (prev_was_interrupt != current_is_interrupt) + { + use_fixed_regs = current_is_interrupt; + target_reinit (); + } + + rx_previous_fndecl = fndecl; +} + +/* Typical stack layout should looks like this after the function's prologue: + + | | + -- ^ + | | \ | + | | arguments saved | Increasing + | | on the stack | addresses + PARENT arg pointer -> | | / + -------------------------- ---- ------------------- + CHILD |ret | return address + -- + | | \ + | | call saved + | | registers + | | / + -- + | | \ + | | local + | | variables + frame pointer -> | | / + -- + | | \ + | | outgoing | Decreasing + | | arguments | addresses + current stack pointer -> | | / | + -------------------------- ---- ------------------ V + | | */ + +static unsigned int +bit_count (unsigned int x) +{ + const unsigned int m1 = 0x55555555; + const unsigned int m2 = 0x33333333; + const unsigned int m4 = 0x0f0f0f0f; + + x -= (x >> 1) & m1; + x = (x & m2) + ((x >> 2) & m2); + x = (x + (x >> 4)) & m4; + x += x >> 8; + + return (x + (x >> 16)) & 0x3f; +} + +/* Returns either the lowest numbered and highest numbered registers that + occupy the call-saved area of the stack frame, if the registers are + stored as a contiguous block, or else a bitmask of the individual + registers if they are stored piecemeal. + + Also computes the size of the frame and the size of the outgoing + arguments block (in bytes). */ + +static void +rx_get_stack_layout (unsigned int * lowest, + unsigned int * highest, + unsigned int * register_mask, + unsigned int * frame_size, + unsigned int * stack_size) +{ + unsigned int reg; + unsigned int low; + unsigned int high; + unsigned int fixed_reg = 0; + unsigned int save_mask; + unsigned int pushed_mask; + unsigned int unneeded_pushes; + + if (is_naked_func (NULL_TREE) + || is_fast_interrupt_func (NULL_TREE)) + { + /* Naked functions do not create their own stack frame. + Instead the programmer must do that for us. + + Fast interrupt handlers use fixed registers that have + been epsecially released to the function, so they do + not need or want a stack frame. */ + * lowest = 0; + * highest = 0; + * register_mask = 0; + * frame_size = 0; + * stack_size = 0; + return; + } + + for (save_mask = high = low = 0, reg = 1; reg < FIRST_PSEUDO_REGISTER; reg++) + { + if (df_regs_ever_live_p (reg) + && (! call_used_regs[reg] + /* Even call clobbered registered must + be pushed inside exception handlers. */ + || is_exception_func (NULL_TREE))) + { + if (low == 0) + low = reg; + high = reg; + + save_mask |= 1 << reg; + } + + /* Remember if we see a fixed register + after having found the low register. */ + if (low != 0 && fixed_reg == 0 && fixed_regs [reg]) + fixed_reg = reg; + } + + /* Decide if it would be faster fill in the call-saved area of the stack + frame using multiple PUSH instructions instead of a single PUSHM + instruction. + + SAVE_MASK is a bitmask of the registers that must be stored in the + call-save area. PUSHED_MASK is a bitmask of the registers that would + be pushed into the area if we used a PUSHM instruction. UNNEEDED_PUSHES + is a bitmask of those registers in pushed_mask that are not in + save_mask. + + We use a simple heuristic that says that it is better to use + multiple PUSH instructions if the number of unnecessary pushes is + greater than the number of necessary pushes. + + We also use multiple PUSH instructions if there are any fixed registers + between LOW and HIGH. The only way that this can happen is if the user + has specified --fixed- on the command line and in such + circumstances we do not want to touch the fixed registers at all. + + FIXME: Is it worth improving this heuristic ? */ + pushed_mask = (-1 << low) & ~(-1 << (high + 1)); + unneeded_pushes = (pushed_mask & (~ save_mask)) & pushed_mask; + + if ((fixed_reg && fixed_reg <= high) + || (optimize_function_for_speed_p (cfun) + && bit_count (save_mask) < bit_count (unneeded_pushes))) + { + /* Use multiple pushes. */ + * lowest = 0; + * highest = 0; + * register_mask = save_mask; + } + else + { + /* Use one push multiple instruction. */ + * lowest = low; + * highest = high; + * register_mask = 0; + } + + * frame_size = rx_round_up + (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT); + + if (crtl->args.size > 0) + * frame_size += rx_round_up + (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT); + + * stack_size = rx_round_up + (crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT); +} + +/* Generate a PUSHM instruction that matches the given operands. */ + +void +rx_emit_stack_pushm (rtx * operands) +{ + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + last_reg = (INTVAL (operands[0]) / UNITS_PER_WORD) - 1; + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_SRC (first_push); + gcc_assert (REG_P (first_push)); + + asm_fprintf (asm_out_file, "\tpushm\t%s-%s\n", + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); + +} + +/* Generate a PARALLEL that will pass the rx_store_multiple_vector predicate. */ + +static rtx +gen_rx_store_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT ((count - 1) * UNITS_PER_WORD))); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT (i * UNITS_PER_WORD))), + gen_rtx_REG (SImode, low + i)); + + return vector; +} + +void +rx_expand_prologue (void) +{ + unsigned int stack_size; + unsigned int frame_size; + unsigned int mask; + unsigned int low; + unsigned int high; + rtx insn; + + /* Naked functions use their own, programmer provided prologues. */ + if (is_naked_func (NULL_TREE) + /* Fast interrupt functions never use the stack. */ + || is_fast_interrupt_func (NULL_TREE)) + return; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + /* If we use any of the callee-saved registers, save them now. */ + if (mask) + { + unsigned int reg; + + /* Push registers in reverse order. */ + for (reg = FIRST_PSEUDO_REGISTER; reg --;) + if (mask & (1 << reg)) + { + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, reg))); + RTX_FRAME_RELATED_P (insn) = 1; + } + } + else if (low) + { + if (high == low) + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, low))); + else + insn = emit_insn (gen_stack_pushm (GEN_INT (((high - low) + 1) + * UNITS_PER_WORD), + gen_rx_store_vector (low, high))); + RTX_FRAME_RELATED_P (insn) = 1; + } + + /* If needed, set up the frame pointer. */ + if (frame_pointer_needed) + { + if (frame_size) + insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + + RTX_FRAME_RELATED_P (insn) = 1; + } + + insn = NULL_RTX; + + /* Allocate space for the outgoing args. + If the stack frame has not already been set up then handle this as well. */ + if (stack_size) + { + if (frame_size) + { + if (frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + stack_size))); + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + (frame_size + stack_size)))); + } + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) stack_size))); + } + else if (frame_size) + { + if (! frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + } + + if (insn != NULL_RTX) + RTX_FRAME_RELATED_P (insn) = 1; +} + +static void +rx_output_function_prologue (FILE * file, + HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED) +{ + if (is_fast_interrupt_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n"); + + if (is_exception_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Exception Handler\n"); + + if (is_naked_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Naked Function\n"); + + if (cfun->static_chain_decl != NULL) + asm_fprintf (file, "\t; Note: Nested function declared " + "inside another function.\n"); + + if (crtl->calls_eh_return) + asm_fprintf (file, "\t; Note: Calls __builtin_eh_return.\n"); +} + +/* Generate a POPM or RTSD instruction that matches the given operands. */ + +void +rx_emit_stack_popm (rtx * operands, bool is_popm) +{ + HOST_WIDE_INT stack_adjust; + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + stack_adjust = INTVAL (operands[0]); + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + last_reg = XVECLEN (operands[1], 0) - (is_popm ? 2 : 3); + + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_DEST (first_push); + gcc_assert (REG_P (first_push)); + + if (is_popm) + asm_fprintf (asm_out_file, "\tpopm\t%s-%s\n", + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); + else + asm_fprintf (asm_out_file, "\trtsd\t#%d, %s-%s\n", + (int) stack_adjust, + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); +} + +/* Generate a PARALLEL which will satisfy the rx_rtsd_vector predicate. */ + +static rtx +gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int bias = 3; + unsigned int count = (high - low) + bias; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, adjust)); + + for (i = 0; i < count - 2; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + XVECEXP (vector, 0, count - 1) = gen_rtx_RETURN (VOIDmode); + + return vector; +} + +/* Generate a PARALLEL which will satisfy the rx_load_multiple_vector predicate. */ + +static rtx +gen_rx_popm_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + (count - 1) * UNITS_PER_WORD)); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + return vector; +} + +void +rx_expand_epilogue (bool is_sibcall) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int register_mask; + unsigned int regs_size; + unsigned HOST_WIDE_INT total_size; + + if (is_naked_func (NULL_TREE)) + { + /* Naked functions use their own, programmer provided epilogues. + But, in order to keep gcc happy we have to generate some kind of + epilogue RTL. */ + emit_jump_insn (gen_naked_return ()); + return; + } + + rx_get_stack_layout (& low, & high, & register_mask, + & frame_size, & stack_size); + + total_size = frame_size + stack_size; + regs_size = ((high - low) + 1) * UNITS_PER_WORD; + + /* See if we are unable to use the special stack frame deconstruct and + return instructions. In most cases we can use them, but the exceptions + are: + + - Sibling calling functions deconstruct the frame but do not return to + their caller. Instead they branch to their sibling and allow their + return instruction to return to this function's parent. + + - Fast interrupt and exception handling functions have to use special + return instructions. + + - Functions where we have pushed a fragmented set of registers into the + call-save area must have the same set of registers popped. */ + if (is_sibcall + || is_fast_interrupt_func (NULL_TREE) + || is_exception_func (NULL_TREE) + || register_mask) + { + /* Cannot use the special instructions - deconstruct by hand. */ + if (total_size) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + + if (register_mask) + { + unsigned int reg; + + for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) + if (register_mask & (1 << reg)) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, reg))); + } + else if (low) + { + if (high == low) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, low))); + else + emit_insn (gen_stack_popm (GEN_INT (regs_size), + gen_rx_popm_vector (low, high))); + } + + if (is_fast_interrupt_func (NULL_TREE)) + emit_jump_insn (gen_fast_interrupt_return ()); + else if (is_exception_func (NULL_TREE)) + emit_jump_insn (gen_exception_return ()); + else if (! is_sibcall) + emit_jump_insn (gen_simple_return ()); + + return; + } + + /* If we allocated space on the stack, free it now. */ + if (total_size) + { + unsigned HOST_WIDE_INT rtsd_size; + + /* See if we can use the RTSD instruction. */ + rtsd_size = total_size + regs_size; + if (rtsd_size < 1024 && (rtsd_size % 4) == 0) + { + if (low) + emit_jump_insn (gen_pop_and_return + (GEN_INT (rtsd_size), + gen_rx_rtsd_vector (rtsd_size, low, high))); + else + emit_jump_insn (gen_deallocate_and_return (GEN_INT (total_size))); + + return; + } + + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + } + + if (low) + emit_jump_insn (gen_pop_and_return (GEN_INT (regs_size), + gen_rx_rtsd_vector (regs_size, + low, high))); + else + emit_jump_insn (gen_simple_return ()); +} + + +/* Compute the offset (in words) between FROM (arg pointer + or frame pointer) and TO (frame pointer or stack pointer). + See ASCII art comment at the start of rx_expand_prologue + for more information. */ + +int +rx_initial_elimination_offset (int from, int to) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int mask; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + if (from == ARG_POINTER_REGNUM) + { + /* Extend the computed size of the stack frame to + include the registers pushed in the prologue. */ + if (low) + frame_size += ((high - low) + 1) * UNITS_PER_WORD; + else + frame_size += bit_count (mask) * UNITS_PER_WORD; + + /* Remember to include the return address. */ + frame_size += 1 * UNITS_PER_WORD; + + if (to == FRAME_POINTER_REGNUM) + return frame_size; + + gcc_assert (to == STACK_POINTER_REGNUM); + return frame_size + stack_size; + } + + gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM); + return stack_size; +} + +/* Update the status of the condition + codes (cc0) based on the given INSN. */ + +void +rx_notice_update_cc (rtx body, rtx insn) +{ + switch (get_attr_cc (insn)) + { + case CC_NONE: + /* Insn does not affect cc0 at all. */ + break; + case CC_CLOBBER: + /* Insn doesn't leave cc0 in a usable state. */ + CC_STATUS_INIT; + break; + case CC_SET_ZSOC: + /* The insn sets all the condition code bits. */ + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (body); + break; + case CC_SET_ZSO: + /* Insn sets the Z,S and O flags, but not the C flag. */ + CC_STATUS_INIT; + cc_status.flags |= CC_NO_CARRY; + /* Do not set the value1 field in this case. The final_scan_insn() + function naively believes that if cc_status.value1 is set then + it can eliminate *any* comparison against that value, even if + the type of comparison cannot be satisfied by the range of flag + bits being set here. See gcc.c-torture/execute/20041210-1.c + for an example of this in action. */ + break; + case CC_SET_ZS: + /* Insn sets the Z and S flags, but not the O or C flags. */ + CC_STATUS_INIT; + cc_status.flags |= (CC_NO_CARRY | CC_NO_OVERFLOW); + /* See comment above regarding cc_status.value1. */ + break; + default: + gcc_unreachable (); + } +} + +/* Decide if a variable should go into one of the small data sections. */ + +static bool +rx_in_small_data (const_tree decl) +{ + int size; + const_tree section; + + if (rx_small_data_limit == 0) + return false; + + if (TREE_CODE (decl) != VAR_DECL) + return false; + + /* We do not put read-only variables into a small data area because + they would be placed with the other read-only sections, far away + from the read-write data sections, and we only have one small + data area pointer. + Similarly commons are placed in the .bss section which might be + far away (and out of alignment with respect to) the .data section. */ + if (TREE_READONLY (decl) || DECL_COMMON (decl)) + return false; + + section = DECL_SECTION_NAME (decl); + if (section) + { + const char * const name = TREE_STRING_POINTER (section); + + return (strcmp (name, "D_2") == 0) || (strcmp (name, "B_2") == 0); + } + + size = int_size_in_bytes (TREE_TYPE (decl)); + + return (size > 0) && (size <= rx_small_data_limit); +} + +/* Return a section for X. + The only special thing we do here is to honor small data. */ + +static section * +rx_select_rtx_section (enum machine_mode mode, + rtx x, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0 + && GET_MODE_SIZE (mode) <= rx_small_data_limit + && align <= (unsigned HOST_WIDE_INT) rx_small_data_limit * BITS_PER_UNIT) + return sdata_section; + + return default_elf_select_rtx_section (mode, x, align); +} + +static section * +rx_select_section (tree decl, + int reloc, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0) + { + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_SDATA: return sdata_section; + case SECCAT_SBSS: return sbss_section; + case SECCAT_SRODATA: + /* Fall through. We do not put small, read only + data into the C_2 section because we are not + using the C_2 section. We do not use the C_2 + section because it is located with the other + read-only data sections, far away from the read-write + data sections and we only have one small data + pointer (r13). */ + default: + break; + } + } + + /* If we are supporting the Renesas assembler + we cannot use mergeable sections. */ + if (TARGET_AS100_SYNTAX) + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_RODATA_MERGE_CONST: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_STR: + return readonly_data_section; + + default: + break; + } + + return default_elf_select_section (decl, reloc, align); +} + +enum rx_builtin +{ + RX_BUILTIN_BRK, + RX_BUILTIN_CLRPSW, + RX_BUILTIN_INT, + RX_BUILTIN_MACHI, + RX_BUILTIN_MACLO, + RX_BUILTIN_MULHI, + RX_BUILTIN_MULLO, + RX_BUILTIN_MVFACHI, + RX_BUILTIN_MVFACMI, + RX_BUILTIN_MVFC, + RX_BUILTIN_MVTACHI, + RX_BUILTIN_MVTACLO, + RX_BUILTIN_MVTC, + RX_BUILTIN_RACW, + RX_BUILTIN_REVW, + RX_BUILTIN_RMPA, + RX_BUILTIN_ROUND, + RX_BUILTIN_SAT, + RX_BUILTIN_SETPSW, + RX_BUILTIN_WAIT, + RX_BUILTIN_max +}; + +static void +rx_init_builtins (void) +{ +#define ADD_RX_BUILTIN1(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE##_type_node, \ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN2(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN3(UC_NAME,LC_NAME,RET_TYPE,ARG_TYPE1,ARG_TYPE2,ARG_TYPE3) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + ARG_TYPE3##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + + ADD_RX_BUILTIN1 (BRK, "brk", void, void); + ADD_RX_BUILTIN1 (CLRPSW, "clrpsw", void, integer); + ADD_RX_BUILTIN1 (SETPSW, "setpsw", void, integer); + ADD_RX_BUILTIN1 (INT, "int", void, integer); + ADD_RX_BUILTIN2 (MACHI, "machi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MACLO, "maclo", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULHI, "mulhi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULLO, "mullo", void, intSI, intSI); + ADD_RX_BUILTIN1 (MVFACHI, "mvfachi", intSI, void); + ADD_RX_BUILTIN1 (MVFACMI, "mvfacmi", intSI, void); + ADD_RX_BUILTIN1 (MVTACHI, "mvtachi", void, intSI); + ADD_RX_BUILTIN1 (MVTACLO, "mvtaclo", void, intSI); + ADD_RX_BUILTIN1 (RMPA, "rmpa", void, void); + ADD_RX_BUILTIN1 (MVFC, "mvfc", intSI, integer); + ADD_RX_BUILTIN2 (MVTC, "mvtc", void, integer, integer); + ADD_RX_BUILTIN1 (RACW, "racw", void, integer); + ADD_RX_BUILTIN1 (ROUND, "round", intSI, float); + ADD_RX_BUILTIN1 (REVW, "revw", intSI, intSI); + ADD_RX_BUILTIN1 (SAT, "sat", intSI, intSI); + ADD_RX_BUILTIN1 (WAIT, "wait", void, void); +} + +static rtx +rx_expand_builtin_stz (rtx arg, rtx target, rtx (* gen_func)(rtx, rtx)) +{ + if (! CONST_INT_P (arg)) + return NULL_RTX; + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target, arg)); + + return target; +} + +static rtx +rx_expand_void_builtin_1_arg (rtx arg, rtx (* gen_func)(rtx), bool reg) +{ + if (reg && ! REG_P (arg)) + arg = force_reg (SImode, arg); + + emit_insn (gen_func (arg)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvtc (tree exp) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! CONST_INT_P (arg1)) + return NULL_RTX; + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_mvtc (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvfc (tree t_arg, rtx target) +{ + rtx arg = expand_normal (t_arg); + + if (! CONST_INT_P (arg)) + return NULL_RTX; + + if (! REG_P (target)) + target = force_reg (SImode, target); + + emit_insn (gen_mvfc (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin_mac (tree exp, rtx (* gen_func)(rtx, rtx)) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! REG_P (arg1)) + arg1 = force_reg (SImode, arg1); + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_func (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_int_builtin_1_arg (rtx arg, + rtx target, + rtx (* gen_func)(rtx, rtx), + bool mem_ok) +{ + if (! REG_P (arg)) + if (!mem_ok || ! MEM_P (arg)) + arg = force_reg (SImode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target, arg)); + + return target; +} + +static rtx +rx_expand_int_builtin_0_arg (rtx target, rtx (* gen_func)(rtx)) +{ + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target)); + + return target; +} + +static rtx +rx_expand_builtin_round (rtx arg, rtx target) +{ + if ((! REG_P (arg) && ! MEM_P (arg)) + || GET_MODE (arg) != SFmode) + arg = force_reg (SFmode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_lrintsf2 (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin (tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + tree arg = CALL_EXPR_ARGS (exp) ? CALL_EXPR_ARG (exp, 0) : NULL_TREE; + rtx op = arg ? expand_normal (arg) : NULL_RTX; + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX; + case RX_BUILTIN_CLRPSW: return rx_expand_void_builtin_1_arg + (op, gen_clrpsw, false); + case RX_BUILTIN_SETPSW: return rx_expand_void_builtin_1_arg + (op, gen_setpsw, false); + case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg + (op, gen_int, false); + case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi); + case RX_BUILTIN_MACLO: return rx_expand_builtin_mac (exp, gen_maclo); + case RX_BUILTIN_MULHI: return rx_expand_builtin_mac (exp, gen_mulhi); + case RX_BUILTIN_MULLO: return rx_expand_builtin_mac (exp, gen_mullo); + case RX_BUILTIN_MVFACHI: return rx_expand_int_builtin_0_arg + (target, gen_mvfachi); + case RX_BUILTIN_MVFACMI: return rx_expand_int_builtin_0_arg + (target, gen_mvfacmi); + case RX_BUILTIN_MVTACHI: return rx_expand_void_builtin_1_arg + (op, gen_mvtachi, true); + case RX_BUILTIN_MVTACLO: return rx_expand_void_builtin_1_arg + (op, gen_mvtaclo, true); + case RX_BUILTIN_RMPA: emit_insn (gen_rmpa ()); return NULL_RTX; + case RX_BUILTIN_MVFC: return rx_expand_builtin_mvfc (arg, target); + case RX_BUILTIN_MVTC: return rx_expand_builtin_mvtc (exp); + case RX_BUILTIN_RACW: return rx_expand_void_builtin_1_arg + (op, gen_racw, false); + case RX_BUILTIN_ROUND: return rx_expand_builtin_round (op, target); + case RX_BUILTIN_REVW: return rx_expand_int_builtin_1_arg + (op, target, gen_revw, false); + case RX_BUILTIN_SAT: return rx_expand_int_builtin_1_arg + (op, target, gen_sat, false); + case RX_BUILTIN_WAIT: emit_insn (gen_wait ()); return NULL_RTX; + + default: + internal_error ("bad builtin code"); + break; + } + + return NULL_RTX; +} + +/* Place an element into a constructor or destructor section. + Like default_ctor_section_asm_out_constructor in varasm.c + except that it uses .init_array (or .fini_array) and it + handles constructor priorities. */ + +static void +rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor) +{ + section * s; + + if (priority != DEFAULT_INIT_PRIORITY) + { + char buf[18]; + + sprintf (buf, "%s.%.5u", + is_ctor ? ".init_array" : ".fini_array", + priority); + s = get_section (buf, SECTION_WRITE, NULL_TREE); + } + else if (is_ctor) + s = ctors_section; + else + s = dtors_section; + + switch_to_section (s); + assemble_align (POINTER_SIZE); + assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); +} + +static void +rx_elf_asm_constructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */true); +} + +static void +rx_elf_asm_destructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */false); +} + +/* Check "interrupt", "exception" and "naked" attributes. */ + +static tree +rx_handle_func_attribute (tree * node, + tree name, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + gcc_assert (args == NULL_TREE); + + if (TREE_CODE (* node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + * no_add_attrs = true; + } + + /* FIXME: We ought to check for conflicting attributes. */ + + /* FIXME: We ought to check that the interrupt and exception + handler attributes have been applied to void functions. */ + return NULL_TREE; +} + +/* Table of RX specific attributes. */ +const struct attribute_spec rx_attribute_table[] = +{ + /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler. */ + { "interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "exception", 0, 0, true, false, false, rx_handle_func_attribute }, + { "naked", 0, 0, true, false, false, rx_handle_func_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +static bool +rx_allocate_stack_slots_for_args (void) +{ + /* Naked functions should not allocate stack slots for arguments. */ + return ! is_naked_func (NULL_TREE); +} + +static bool +rx_func_attr_inlinable (const_tree decl) +{ + return ! is_fast_interrupt_func (decl) + && ! is_exception_func (decl) + && ! is_naked_func (decl); +} + +static void +rx_file_start (void) +{ + if (! TARGET_AS100_SYNTAX) + default_file_start (); +} + +static bool +rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Try to generate code for the "isnv" pattern which inserts bits + into a word. + operands[0] => Location to be altered. + operands[1] => Number of bits to change. + operands[2] => Starting bit. + operands[3] => Value to insert. + Returns TRUE if successful, FALSE otherwise. */ + +bool +rx_expand_insv (rtx * operands) +{ + if (INTVAL (operands[1]) != 1 + || ! CONST_INT_P (operands[3])) + return false; + + if (MEM_P (operands[0]) + && INTVAL (operands[2]) > 7) + return false; + + switch (INTVAL (operands[3])) + { + case 0: + if (MEM_P (operands[0])) + emit_insn (gen_bitclr_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitclr (operands[0], operands[0], operands[2])); + break; + case 1: + case -1: + if (MEM_P (operands[0])) + emit_insn (gen_bitset_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitset (operands[0], operands[0], operands[2])); + break; + default: + return false; + } + return true; +} + +/* Returns true if X a legitimate constant for an immediate + operand on the RX. X is already known to satisfy CONSTANT_P. */ + +bool +rx_is_legitimate_constant (rtx x) +{ + HOST_WIDE_INT val; + + switch (GET_CODE (x)) + { + case CONST: + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + { + if (! CONST_INT_P (XEXP (x, 1))) + return false; + + /* GCC would not pass us CONST_INT + CONST_INT so we + know that we have {SYMBOL|LABEL} + CONST_INT. */ + x = XEXP (x, 0); + gcc_assert (! CONST_INT_P (x)); + } + + switch (GET_CODE (x)) + { + case LABEL_REF: + case SYMBOL_REF: + return true; + + /* One day we may have to handle UNSPEC constants here. */ + default: + /* FIXME: Can this ever happen ? */ + abort (); + return false; + } + break; + + case LABEL_REF: + case SYMBOL_REF: + return true; + case CONST_DOUBLE: + return rx_max_constant_size == 0; + case CONST_VECTOR: + return false; + default: + gcc_assert (CONST_INT_P (x)); + break; + } + + if (rx_max_constant_size == 0) + /* If there is no constraint on the size of constants + used as operands, then any value is legitimate. */ + return true; + + val = INTVAL (x); + + /* rx_max_constant_size specifies the maximum number + of bytes that can be used to hold a signed value. */ + return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)), + ( 1 << (rx_max_constant_size * 8))); +} + +/* Extra processing for target specific command line options. */ + +static bool +rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value) +{ + switch (code) + { + case OPT_mint_register_: + switch (value) + { + case 4: + fixed_regs[10] = call_used_regs [10] = 1; + /* Fall through. */ + case 3: + fixed_regs[11] = call_used_regs [11] = 1; + /* Fall through. */ + case 2: + fixed_regs[12] = call_used_regs [12] = 1; + /* Fall through. */ + case 1: + fixed_regs[13] = call_used_regs [13] = 1; + /* Fall through. */ + case 0: + return true; + default: + return false; + } + break; + + case OPT_mmax_constant_size_: + /* Make sure that the the -mmax-constant_size option is in range. */ + return IN_RANGE (value, 0, 4); + + default: + return true; + } +} + +static int +rx_address_cost (rtx addr, bool speed) +{ + rtx a, b; + + if (GET_CODE (addr) != PLUS) + return COSTS_N_INSNS (1); + + a = XEXP (addr, 0); + b = XEXP (addr, 1); + + if (REG_P (a) && REG_P (b)) + /* Try to discourage REG+REG addressing as it keeps two registers live. */ + return COSTS_N_INSNS (4); + + if (speed) + /* [REG+OFF] is just as fast as [REG]. */ + return COSTS_N_INSNS (1); + + if (CONST_INT_P (b) + && ((INTVAL (b) > 128) || INTVAL (b) < -127)) + /* Try to discourage REG + when optimizing for size. */ + return COSTS_N_INSNS (2); + + return COSTS_N_INSNS (1); +} + +static bool +rx_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + /* We can always eliminate to the frame pointer. + We can eliminate to the stack pointer unless a frame + pointer is needed. */ + + return to == FRAME_POINTER_REGNUM + || ( to == STACK_POINTER_REGNUM && ! frame_pointer_needed); +} + + +static void +rx_trampoline_template (FILE * file) +{ + /* Output assembler code for a block containing the constant + part of a trampoline, leaving space for the variable parts. + + On the RX, (where r8 is the static chain regnum) the trampoline + looks like: + + mov #, r8 + mov #, r9 + jmp r9 + + In big-endian-data-mode however instructions are read into the CPU + 4 bytes at a time. These bytes are then swapped around before being + passed to the decoder. So...we must partition our trampoline into + 4 byte packets and swap these packets around so that the instruction + reader will reverse the process. But, in order to avoid splitting + the 32-bit constants across these packet boundaries, (making inserting + them into the constructed trampoline very difficult) we have to pad the + instruction sequence with NOP insns. ie: + + nop + nop + mov.l #<...>, r8 + nop + nop + mov.l #<...>, r9 + jmp r9 + nop + nop */ + + if (! TARGET_BIG_ENDIAN_DATA) + { + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", STATIC_CHAIN_REGNUM); + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", TRAMPOLINE_TEMP_REGNUM); + asm_fprintf (file, "\tjmp\tr%d\n", TRAMPOLINE_TEMP_REGNUM); + } + else + { + char r8 = '0' + STATIC_CHAIN_REGNUM; + char r9 = '0' + TRAMPOLINE_TEMP_REGNUM; + + if (TARGET_AS100_SYNTAX) + { + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r8); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r9); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 003H, 003H, 00%cH, 07fH\n", r9); + } + else + { + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r8); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r9); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x03, 0x03, 0x0%c, 0x7f\n", r9); + } + } +} + +static void +rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + + emit_block_move (tramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + + if (TARGET_BIG_ENDIAN_DATA) + { + emit_move_insn (adjust_address (tramp, SImode, 4), chain); + emit_move_insn (adjust_address (tramp, SImode, 12), fnaddr); + } + else + { + emit_move_insn (adjust_address (tramp, SImode, 2), chain); + emit_move_insn (adjust_address (tramp, SImode, 6 + 2), fnaddr); + } +} + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE rx_function_value + +#undef TARGET_RETURN_IN_MSB +#define TARGET_RETURN_IN_MSB rx_return_in_msb + +#undef TARGET_IN_SMALL_DATA_P +#define TARGET_IN_SMALL_DATA_P rx_in_small_data + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY rx_return_in_memory + +#undef TARGET_HAVE_SRODATA_SECTION +#define TARGET_HAVE_SRODATA_SECTION true + +#undef TARGET_ASM_SELECT_RTX_SECTION +#define TARGET_ASM_SELECT_RTX_SECTION rx_select_rtx_section + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION rx_select_section + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS rx_init_builtins + +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN rx_expand_builtin + +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR rx_elf_asm_constructor + +#undef TARGET_ASM_DESTRUCTOR +#define TARGET_ASM_DESTRUCTOR rx_elf_asm_destructor + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX rx_struct_value_rtx + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE rx_attribute_table + +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START rx_file_start + +#undef TARGET_MS_BITFIELD_LAYOUT_P +#define TARGET_MS_BITFIELD_LAYOUT_P rx_is_ms_bitfield_layout + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P rx_is_legitimate_address + +#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS rx_allocate_stack_slots_for_args + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE rx_output_function_prologue + +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P rx_func_attr_inlinable + +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION rx_set_current_function + +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION rx_handle_option + +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER rx_assemble_integer + +#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P +#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true + +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET 32 + +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST rx_address_cost + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE rx_can_eliminate + +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE rx_trampoline_template + +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT rx_trampoline_init + +struct gcc_target targetm = TARGET_INITIALIZER; + +/* #include "gt-rx.h" */ diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h new file mode 100644 index 00000000000..a01e194910b --- /dev/null +++ b/gcc/config/rx/rx.h @@ -0,0 +1,632 @@ +/* GCC backend definitions for the Renesas RX processor. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__RX__"); \ + builtin_assert ("cpu=RX"); \ + builtin_assert ("machine=RX"); \ + \ + if (TARGET_BIG_ENDIAN_DATA) \ + builtin_define ("__RX_BIG_ENDIAN__"); \ + else \ + builtin_define ("__RX_LITTLE_ENDIAN__");\ + \ + if (TARGET_64BIT_DOUBLES) \ + builtin_define ("__RX_64BIT_DOUBLES__");\ + else \ + builtin_define ("__RX_32BIT_DOUBLES__");\ + \ + if (TARGET_AS100_SYNTAX) \ + builtin_define ("__RX_AS100_SYNTAX__"); \ + else \ + builtin_define ("__RX_GAS_SYNTAX__"); \ + } \ + while (0) + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +#undef ASM_SPEC +#define ASM_SPEC "\ +%{mbig-endian-data:-mbig-endian-data} \ +%{m64bit-doubles:-m64bit-doubles} \ +%{msmall-data-limit*:-msmall-data-limit} \ +%{mrelax:-relax} \ +" + +#undef LIB_SPEC +#define LIB_SPEC " \ +--start-group \ +-lc \ +%{msim*:-lsim}%{!msim*:-lnosys} \ +%{fprofile-arcs|fprofile-generate|coverage:-lgcov} \ +--end-group \ +%{!T*: %{msim*:%Trx-sim.ld}%{!msim*:%Trx.ld}} \ +" + +#undef LINK_SPEC +#define LINK_SPEC "%{mbig-endian-data:--oformat elf32-rx-be} %{mrelax:-relax}" + + +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA +#define WORDS_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA + +#ifdef __RX_BIG_ENDIAN__ +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define UNITS_PER_WORD 4 + +#define INT_TYPE_SIZE 32 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 + +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE (TARGET_64BIT_DOUBLES ? 64 : 32) +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE + +#ifdef __RX_64BIT_DOUBLES__ +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 +#define LIBGCC2_DOUBLE_TYPE_SIZE 64 +#define LIBGCC2_HAS_DF_MODE 1 +#else +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 32 +#define LIBGCC2_DOUBLE_TYPE_SIZE 32 +#endif + +#define DEFAULT_SIGNED_CHAR 0 + +#define STRICT_ALIGNMENT 1 +#define FUNCTION_BOUNDARY 8 +#define BIGGEST_ALIGNMENT 32 +#define STACK_BOUNDARY 32 +#define PARM_BOUNDARY 8 + +#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) 32 + +#define STACK_GROWS_DOWNWARD 1 +#define FRAME_GROWS_DOWNWARD 0 +#define FIRST_PARM_OFFSET(FNDECL) 0 + +#define MAX_REGS_PER_ADDRESS 2 + +#define Pmode SImode +#define POINTER_SIZE 32 +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#define POINTERS_EXTEND_UNSIGNED 1 +#define FUNCTION_MODE QImode +#define CASE_VECTOR_MODE Pmode +#define WORD_REGISTER_OPERATIONS 1 +#define HAS_LONG_COND_BRANCH 0 +#define HAS_LONG_UNCOND_BRANCH 0 + +#define MOVE_MAX 4 +#define STARTING_FRAME_OFFSET 0 + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0 +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define LEGITIMATE_CONSTANT_P(X) rx_is_legitimate_constant (X) + +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +#define HAVE_PRE_DECCREMENT 1 +#define HAVE_POST_INCREMENT 1 + +#define MOVE_RATIO(SPEED) ((SPEED) ? 4 : 2) +#define SLOW_BYTE_ACCESS 1 + +#define STORE_FLAG_VALUE 1 +#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND +#define SHORT_IMMEDIATES_SIGN_EXTEND 1 + +enum reg_class +{ + NO_REGS, /* No registers in set. */ + GR_REGS, /* Integer registers. */ + ALL_REGS, /* All registers. */ + LIM_REG_CLASSES /* Max value + 1. */ +}; + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "GR_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000 }, /* No registers, */ \ + { 0x0000ffff }, /* Integer registers. */ \ + { 0x0000ffff } /* All registers. */ \ +} + +#define IRA_COVER_CLASSES \ + { \ + GR_REGS, LIM_REG_CLASSES \ + } + +#define SMALL_REGISTER_CLASSES 0 +#define N_REG_CLASSES (int) LIM_REG_CLASSES +#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \ + + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +#define GENERAL_REGS GR_REGS +#define BASE_REG_CLASS GR_REGS +#define INDEX_REG_CLASS GR_REGS + +#define FIRST_PSEUDO_REGISTER 16 + +#define REGNO_REG_CLASS(REGNO) ((REGNO) < FIRST_PSEUDO_REGISTER \ + ? GR_REGS : NO_REGS) + +#define STACK_POINTER_REGNUM 0 +#define FUNC_RETURN_REGNUM 1 +#define FRAME_POINTER_REGNUM 6 +#define ARG_POINTER_REGNUM 7 +#define STATIC_CHAIN_REGNUM 8 +#define TRAMPOLINE_TEMP_REGNUM 9 +#define STRUCT_VAL_REGNUM 15 + +/* This is the register which is used to hold the address of the start + of the small data area, if that feature is being used. Note - this + register must not be call_used because otherwise library functions + that are compiled without small data support might clobber it. + + FIXME: The function gcc/config/rx/rx.c:rx_gen_move_template() has a + built in copy of this register's name, rather than constructing the + name from this #define. */ +#define GP_BASE_REGNUM 13 + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = rx_initial_elimination_offset ((FROM), (TO)) + + +#define FUNCTION_ARG_REGNO_P(N) (((N) >= 1) && ((N) <= 4)) +#define FUNCTION_VALUE_REGNO_P(N) ((N) == FUNC_RETURN_REGNUM) +#define DEFAULT_PCC_STRUCT_RETURN 0 + +#define FIXED_REGISTERS \ +{ \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ +} + +#define CALL_USED_REGISTERS \ +{ \ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 \ +} + +#define CONDITIONAL_REGISTER_USAGE \ + rx_conditional_register_usage () + +#define LIBCALL_VALUE(MODE) \ + gen_rtx_REG (((GET_MODE_CLASS (MODE) != MODE_INT \ + || GET_MODE_SIZE (MODE) >= 4) \ + ? (MODE) \ + : SImode), \ + FUNC_RETURN_REGNUM) + +/* Order of allocation of registers. */ + +#define REG_ALLOC_ORDER \ +{ 7, 10, 11, 12, 13, 14, 4, 3, 2, 1, 9, 8, 6, 5, 15 \ +} + +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + +#define REGNO_IN_RANGE(REGNO, MIN, MAX) \ + (IN_RANGE ((REGNO), (MIN), (MAX)) \ + || (reg_renumber != NULL \ + && reg_renumber[(REGNO)] >= (MIN) \ + && reg_renumber[(REGNO)] <= (MAX))) + +#ifdef REG_OK_STRICT +#define REGNO_OK_FOR_BASE_P(regno) REGNO_IN_RANGE (regno, 0, 15) +#else +#define REGNO_OK_FOR_BASE_P(regno) 1 +#endif + +#define REGNO_OK_FOR_INDEX_P(regno) REGNO_OK_FOR_BASE_P (regno) + +#define RTX_OK_FOR_BASE(X, STRICT) \ + ((STRICT) ? \ + ( (REG_P (X) \ + && REGNO_IN_RANGE (REGNO (X), 0, 15)) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)) \ + && REGNO_IN_RANGE (REGNO (SUBREG_REG (X)), 0, 15))) \ + : \ + ( (REG_P (X) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)))))) + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ + do \ + { \ + if (rx_is_mode_dependent_addr (ADDR)) \ + goto LABEL; \ + } \ + while (0) + + +#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (-4))) \ + : NULL_RTX) + +#define INCOMING_RETURN_ADDR_RTX gen_rtx_MEM (Pmode, stack_pointer_rtx) + +#define ACCUMULATE_OUTGOING_ARGS 1 + +typedef unsigned int CUMULATIVE_ARGS; + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ + (CUM) = 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + rx_function_arg (& CUM, MODE, TYPE, NAMED) + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += rx_function_arg_size (MODE, TYPE) + +#define TRAMPOLINE_SIZE (! TARGET_BIG_ENDIAN_DATA ? 14 : 20) +#define TRAMPOLINE_ALIGNMENT 32 + +#define NO_PROFILE_COUNTERS 1 +#define PROFILE_BEFORE_PROLOGUE 1 + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tbsr\t__mcount\n"); + + +#define HARD_REGNO_NREGS(REGNO, MODE) CLASS_MAX_NREGS (0, MODE) + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + REGNO_REG_CLASS (REGNO) == GR_REGS + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ( ( GET_MODE_CLASS (MODE1) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \ + == ( GET_MODE_CLASS (MODE2) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT)) + + +#define REGISTER_NAMES \ + { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" \ + }; + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + { "sp", STACK_POINTER_REGNUM } \ + , { "fp", FRAME_POINTER_REGNUM } \ + , { "arg", ARG_POINTER_REGNUM } \ + , { "chain", STATIC_CHAIN_REGNUM } \ +} + +#define DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D,DATA" \ + : "\t.section D,\"aw\",@progbits\n\t.p2align 2") + +#define SDATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D_2,DATA,ALIGN=2" \ + : "\t.section D_2,\"aw\",@progbits\n\t.p2align 1") + +#undef READONLY_DATA_SECTION_ASM_OP +#define READONLY_DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION C,ROMDATA,ALIGN=4" \ + : "\t.section C,\"a\",@progbits\n\t.p2align 2") + +#define BSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B,DATA,ALIGN=4" \ + : "\t.section B,\"w\",@nobits\n\t.p2align 2") + +#define SBSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B_2,DATA,ALIGN=2" \ + : "\t.section B_2,\"w\",@nobits\n\t.p2align 1") + +/* The following definitions are conditional depending upon whether the + compiler is being built or crtstuff.c is being compiled by the built + compiler. */ +#if defined CRT_BEGIN || defined CRT_END +# ifdef __RX_AS100_SYNTAX +# define TEXT_SECTION_ASM_OP "\t.SECTION P,CODE" +# define CTORS_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define DTORS_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# define INIT_ARRAY_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define FINI_ARRAY_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# else +# define TEXT_SECTION_ASM_OP "\t.section P,\"ax\"" +# define CTORS_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define DTORS_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# define INIT_ARRAY_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define FINI_ARRAY_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# endif +#else +# define TEXT_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION P,CODE" : "\t.section P,\"ax\"") + +# define CTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define DTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") + +# define INIT_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define FINI_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") +#endif + +#define GLOBAL_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.GLB\t" : "\t.global\t") +#define ASM_COMMENT_START " ;" +#define ASM_APP_ON "" +#define ASM_APP_OFF "" +#define LOCAL_LABEL_PREFIX "L" +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +#define ASM_OUTPUT_ALIGN(STREAM, LOG) \ + do \ + { \ + if ((LOG) == 0) \ + break; \ + if (TARGET_AS100_SYNTAX) \ + { \ + if ((LOG) >= 2) \ + fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \ + else \ + fprintf (STREAM, "\t.ALIGN 2\n"); \ + } \ + else \ + fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \ + } \ + while (0) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, TARGET_AS100_SYNTAX ? "\t.LWORD L%d\n" : "\t.long .L%d\n", \ + VALUE) + +/* This is how to output an element of a case-vector that is relative. + Note: The local label referenced by the "3b" below is emitted by + the tablejump insn. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, TARGET_AS100_SYNTAX \ + ? "\t.LWORD L%d - ?-\n" : "\t.long .L%d - 1b\n", VALUE) + +#define ASM_OUTPUT_SIZE_DIRECTIVE(STREAM, NAME, SIZE) \ + do \ + { \ + HOST_WIDE_INT size_ = (SIZE); \ + \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ", " HOST_WIDE_INT_PRINT_DEC "\n", size_); \ + } \ + while (0) + +#define ASM_OUTPUT_MEASURED_SIZE(STREAM, NAME) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", .-", STREAM); \ + assemble_name (STREAM, NAME); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#define ASM_OUTPUT_TYPE_DIRECTIVE(STREAM, NAME, TYPE) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (TYPE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", ", STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, TYPE); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + do \ + { \ + sprintf (LABEL, TARGET_AS100_SYNTAX ? "*%s%u" : "*.%s%u", \ + PREFIX, (unsigned) (NUM)); \ + } \ + while (0) + +#undef ASM_OUTPUT_EXTERNAL +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + targetm.asm_out.globalize_label (FILE, NAME); \ + default_elf_asm_output_external (FILE, DECL, NAME); \ + } \ + while (0) + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + { \ + fprintf ((FILE), "\t.GLB\t"); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), "\n"); \ + assemble_name ((FILE), (NAME)); \ + switch ((ALIGN) / BITS_PER_UNIT) \ + { \ + case 4: \ + fprintf ((FILE), ":\t.BLKL\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 4); \ + break; \ + case 2: \ + fprintf ((FILE), ":\t.BLKW\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 2); \ + break; \ + default: \ + fprintf ((FILE), ":\t.BLKB\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE)); \ + break; \ + } \ + } \ + else \ + { \ + fprintf ((FILE), "%s", COMMON_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \ + (SIZE), (ALIGN) / BITS_PER_UNIT); \ + } \ + } \ + while (0) + +#undef SKIP_ASM_OP +#define SKIP_ASM_OP (TARGET_AS100_SYNTAX ? "\t.BLKB\t" : "\t.zero\t") + +#undef ASM_OUTPUT_LIMITED_STRING +#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ + do \ + { \ + const unsigned char *_limited_str = \ + (const unsigned char *) (STR); \ + unsigned ch; \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX \ + ? "\t.BYTE\t\"" : "\t.string\t\""); \ + \ + for (; (ch = *_limited_str); _limited_str++) \ + { \ + int escape; \ + \ + switch (escape = ESCAPES[ch]) \ + { \ + case 0: \ + putc (ch, (FILE)); \ + break; \ + case 1: \ + fprintf ((FILE), "\\%03o", ch); \ + break; \ + default: \ + putc ('\\', (FILE)); \ + putc (escape, (FILE)); \ + break; \ + } \ + } \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX ? "\"\n\t.BYTE\t0\n" : "\"\n");\ + } \ + while (0) + +#undef IDENT_ASM_OP +#define IDENT_ASM_OP (TARGET_AS100_SYNTAX \ + ? "\t.END\t; Built by: ": "\t.ident\t") + +/* For PIC put jump tables into the text section so that the offsets that + they contain are always computed between two same-section symbols. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +#define PRINT_OPERAND(FILE, X, CODE) \ + rx_print_operand (FILE, X, CODE) +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + rx_print_operand_address (FILE, ADDR) + + +#define CC_NO_CARRY 0400 +#define NOTICE_UPDATE_CC(EXP, INSN) rx_notice_update_cc (EXP, INSN) + +extern int rx_float_compare_mode; + +/* This is a version of REG_P that also returns TRUE for SUBREGs. */ +#define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG) + +/* Like REG_P except that this macro is true for SET expressions. */ +#define SET_P(rtl) (GET_CODE (rtl) == SET) + +#define CAN_DEBUG_WITHOUT_FP 1 + +/* The AS100 assembler does not support .leb128 and .uleb128, but + the compiler-build-time configure tests will have enabled their + use because GAS supports them. So default to generating STABS + debug information instead of DWARF2 when generating AS100 + compatible output. */ +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE (TARGET_AS100_SYNTAX \ + ? DBX_DEBUG : DWARF2_DEBUG) + +#undef CC1_SPEC +#define CC1_SPEC "%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}}" + +/* For some unknown reason LTO compression is not working, at + least on my local system. So set the default compression + level to none, for now. */ +#define OVERRIDE_OPTIONS \ + do \ + { \ + if (flag_lto_compression_level == -1) \ + flag_lto_compression_level = 0; \ + } \ + while (0) + +/* This macro is used to decide when RX FPU instructions can be used. */ +#define ALLOW_RX_FPU_INSNS flag_unsafe_math_optimizations diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md new file mode 100644 index 00000000000..165da4f41a1 --- /dev/null +++ b/gcc/config/rx/rx.md @@ -0,0 +1,1780 @@ +;; Machine Description for Renesas RX processors +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 +;; . + + +;; This code iterator allows all branch instructions to +;; be generated from a single define_expand template. +(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu + unordered ordered ]) + +;; This code iterator is used for sign- and zero- extensions. +(define_mode_iterator small_int_modes [(HI "") (QI "")]) + +;; We do not handle DFmode here because by default it is +;; the same as SFmode, and if -m64bit-doubles is active +;; then all operations on doubles have to be handled by +;; library functions. +(define_mode_iterator register_modes + [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")]) + + +;; Used to map RX condition names to GCC +;; condition names for builtin instructions. +(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu + unge unlt uneq ltgt]) +(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt") + (le "le") (gtu "gtu") (geu "geu") (ltu "ltu") + (leu "leu") (unge "pz") (unlt "n") (uneq "o") + (ltgt "no")]) + +(define_constants + [ + (SP_REG 0) + + (UNSPEC_LOW_REG 0) + (UNSPEC_HIGH_REG 1) + + (UNSPEC_RTE 10) + (UNSPEC_RTFI 11) + (UNSPEC_NAKED 12) + + (UNSPEC_MOVSTR 20) + (UNSPEC_MOVMEM 21) + (UNSPEC_SETMEM 22) + (UNSPEC_STRLEN 23) + (UNSPEC_CMPSTRN 24) + + (UNSPEC_BUILTIN_BRK 30) + (UNSPEC_BUILTIN_CLRPSW 31) + (UNSPEC_BUILTIN_INT 32) + (UNSPEC_BUILTIN_MACHI 33) + (UNSPEC_BUILTIN_MACLO 34) + (UNSPEC_BUILTIN_MULHI 35) + (UNSPEC_BUILTIN_MULLO 36) + (UNSPEC_BUILTIN_MVFACHI 37) + (UNSPEC_BUILTIN_MVFACMI 38) + (UNSPEC_BUILTIN_MVFC 39) + (UNSPEC_BUILTIN_MVFCP 40) + (UNSPEC_BUILTIN_MVTACHI 41) + (UNSPEC_BUILTIN_MVTACLO 42) + (UNSPEC_BUILTIN_MVTC 43) + (UNSPEC_BUILTIN_MVTCP 44) + (UNSPEC_BUILTIN_OPEPC 45) + (UNSPEC_BUILTIN_RACW 46) + (UNSPEC_BUILTIN_REVW 47) + (UNSPEC_BUILTIN_RMPA 48) + (UNSPEC_BUILTIN_ROUND 49) + (UNSPEC_BUILTIN_SAT 50) + (UNSPEC_BUILTIN_SETPSW 51) + (UNSPEC_BUILTIN_WAIT 52) + ] +) + +;; Condition code settings: +;; none - insn does not affect the condition code bits +;; set_zs - insn sets z,s to usable values; +;; set_zso - insn sets z,s,o to usable values; +;; set_zsoc - insn sets z,s,o,c to usable values; +;; clobber - value of cc0 is unknown +(define_attr "cc" "none,set_zs,set_zso,set_zsoc,clobber" (const_string "none")) + +(define_attr "length" "" (const_int 8)) + +(include "predicates.md") +(include "constraints.md") + +;; Pipeline description. + +;; The RX only has a single pipeline. It has five stages (fetch, +;; decode, execute, memory access, writeback) each of which normally +;; takes a single CPU clock cycle. + +;; The timings attribute consists of two numbers, the first is the +;; throughput, which is the number of cycles the instruction takes +;; to execute and generate a result. The second is the latency +;; which is the effective number of cycles the instruction takes to +;; execute if its result is used by the following instruction. The +;; latency is always greater than or equal to the throughput. +;; These values were taken from tables 2.13 and 2.14 in section 2.8 +;; of the RX610 Group Hardware Manual v0.11 + +;; Note - it would be nice to use strings rather than integers for +;; the possible values of this attribute, so that we can have the +;; gcc build mechanism check for values that are not supported by +;; the reservations below. But this will not work because the code +;; in rx_adjust_sched_cost() needs integers not strings. + +(define_attr "timings" "" (const_int 11)) + +(define_automaton "pipelining") +(define_cpu_unit "throughput" "pipelining") + +(define_insn_reservation "throughput__1_latency__1" 1 + (eq_attr "timings" "11") "throughput") +(define_insn_reservation "throughput__1_latency__2" 2 + (eq_attr "timings" "12") "throughput,nothing") +(define_insn_reservation "throughput__2_latency__2" 1 + (eq_attr "timings" "22") "throughput*2") +(define_insn_reservation "throughput__3_latency__3" 1 + (eq_attr "timings" "33") "throughput*3") +(define_insn_reservation "throughput__3_latency__4" 2 + (eq_attr "timings" "34") "throughput*3,nothing") +(define_insn_reservation "throughput__4_latency__4" 1 + (eq_attr "timings" "44") "throughput*4") +(define_insn_reservation "throughput__4_latency__5" 2 + (eq_attr "timings" "45") "throughput*4,nothing") +(define_insn_reservation "throughput__5_latency__5" 1 + (eq_attr "timings" "55") "throughput*5") +(define_insn_reservation "throughput__5_latency__6" 2 + (eq_attr "timings" "56") "throughput*5,nothing") +(define_insn_reservation "throughput__6_latency__6" 1 + (eq_attr "timings" "66") "throughput*6") +(define_insn_reservation "throughput_10_latency_10" 1 + (eq_attr "timings" "1010") "throughput*10") +(define_insn_reservation "throughput_11_latency_11" 1 + (eq_attr "timings" "1111") "throughput*11") +(define_insn_reservation "throughput_16_latency_16" 1 + (eq_attr "timings" "1616") "throughput*16") +(define_insn_reservation "throughput_18_latency_18" 1 + (eq_attr "timings" "1818") "throughput*18") + +;; Comparisons + +(define_expand "cbranchsi4" + [(set (cc0) (compare:CC (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "" +) + +(define_expand "cbranchsf4" + [(set (cc0) (compare:CC (match_operand:SF 1 "register_operand") + (match_operand:SF 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + "" +) + +;; The TST instruction is not used as it does not set the Carry flag, +;; so for example, the LessThan comparison cannot be tested. +;; +;; (define_insn "tstsi" +;; [(set (cc0) +;; (match_operand:SI 0 "rx_source_operand" "r,i,Q")))] +;; "" +;; { +;; rx_float_compare_mode = false; +;; return "tst\t%Q0"; +;; } +;; [(set_attr "cc" "set_zs") +;; (set_attr "timings" "11,11,33") +;; (set_attr "length" "3,7,6")] +;; ) + +(define_insn "cmpsi" + [(set (cc0) (compare:CC + (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI 1 "rx_source_operand" + "r,Uint04,Int08,Sint16,Sint24,i,Q")))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q1, %Q0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,5")] +) + +;; This pattern is disabled when -fnon-call-exceptions is active because +;; it could generate a floating point exception, which would introduce an +;; edge into the flow graph between this insn and the conditional branch +;; insn to follow, thus breaking the cc0 relationship. Run the g++ test +;; g++.dg/eh/080514-1.C to see this happen. +(define_insn "cmpsf" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "r,r,r") + (match_operand:SF 1 "rx_source_operand" "r,i,Q")))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + { + rx_float_compare_mode = true; + return "fcmp\t%1, %0"; + } + [(set_attr "cc" "set_zso") + (set_attr "timings" "11,11,33") + (set_attr "length" "3,7,5")] +) + +;; Flow Control Instructions: + +(define_expand "b" + [(set (pc) + (if_then_else (most_cond (cc0) (const_int 0)) + (label_ref (match_operand 0)) + (pc)))] + "" + "" +) + +(define_insn "*conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { + return rx_gen_cond_branch_template (operands[1], false); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "*reveresed_conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + { + return rx_gen_cond_branch_template (operands[1], true); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "bra\t%0" + [(set_attr "length" "4") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp\t%0" + [(set_attr "length" "2") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" + : "\n1:\tbra\t%0") + : "jmp\t%0"; + } + [(set_attr "cc" "clobber") ;; FIXME: This clobber is wrong. + (set_attr "timings" "33") + (set_attr "length" "2")] +) + +(define_insn "simple_return" + [(return)] + "" + "rts" + [(set_attr "length" "1") + (set_attr "timings" "55")] +) + +(define_insn "deallocate_and_return" + [(set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 0 "immediate_operand" "i"))) + (return)] + "" + "rtsd\t%0" + [(set_attr "length" "2") + (set_attr "timings" "55")] +) + +(define_insn "pop_and_return" + [(match_parallel 1 "rx_rtsd_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, false); + return ""; + } + [(set_attr "length" "3") + (set_attr "timings" "56")] +) + +(define_insn "fast_interrupt_return" + [(unspec_volatile [(return)] UNSPEC_RTFI) ] + "" + "rtfi" + [(set_attr "length" "2") + (set_attr "timings" "33")] +) + +(define_insn "exception_return" + [(unspec_volatile [(return)] UNSPEC_RTE) ] + "" + "rte" + [(set_attr "length" "2") + (set_attr "timings" "66")] +) + +(define_insn "naked_return" + [(unspec_volatile [(return)] UNSPEC_NAKED) ] + "" + "; Naked function: epilogue provided by programmer." +) + + +;; Note - the following set of patterns do not use the "memory_operand" +;; predicate or an "m" constraint because we do not allow symbol_refs +;; or label_refs as legitmate memory addresses. This matches the +;; behaviour of most of the RX instructions. Only the call/branch +;; instructions are allowed to refer to symbols/labels directly. +;; The call operands are in QImode because that is the value of +;; FUNCTION_MODE + +(define_expand "call" + [(call (match_operand:QI 0 "general_operand") + (match_operand:SI 1 "general_operand"))] + "" + { + rtx dest = XEXP (operands[0], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_internal (dest, operands[1])); + DONE; + } +) + +(define_insn "call_internal" + [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol")) + (match_operand:SI 1 "general_operand" "g,g"))] + "" + "@ + jsr\t%A0 + bsr\t%A0" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand") + (call (match_operand:QI 1 "general_operand") + (match_operand:SI 2 "general_operand")))] + "" + { + rtx dest = XEXP (operands[1], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2])); + DONE; + } +) + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=r,r") + (call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol")) + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + jsr\t%A1 + bsr\t%A1" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall" + [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 1 "general_operand" "g")) + (return) + (use (match_operand 2 "" ""))] + "" + "bra\t%A0" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall_value" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 2 "general_operand" "g"))) + (return) + (use (match_operand 3 "" ""))] + "" + "bra\t%A1" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +;; Function Prologue/Epilogue Instructions + +(define_expand "prologue" + [(const_int 0)] + "" + "rx_expand_prologue (); DONE;" +) + +(define_expand "epilogue" + [(return)] + "" + "rx_expand_epilogue (false); DONE;" +) + +(define_expand "sibcall_epilogue" + [(return)] + "" + "rx_expand_epilogue (true); DONE;" +) + +;; Move Instructions + +;; Note - we do not allow memory to memory moves, even though the ISA +;; supports them. The reason is that the conditions on such moves are +;; too restrictive, specifically the source addressing mode is limited +;; by the destination addressing mode and vice versa. (For example it +;; is not possible to use indexed register indirect addressing for one +;; of the operands if the other operand is anything other than a register, +;; but it is possible to use register relative addressing when the other +;; operand also uses register relative or register indirect addressing). +;; +;; GCC does not support computing legitimate addresses based on the +;; nature of other operands involved in the instruction, and reload is +;; not smart enough to cope with a whole variety of different memory +;; addressing constraints, so it is simpler and safer to just refuse +;; to support memory to memory moves. + +(define_expand "mov" + [(set (match_operand:register_modes 0 "general_operand") + (match_operand:register_modes 1 "general_operand"))] + "" + { + if (MEM_P (operand0) && MEM_P (operand1)) + operands[1] = copy_to_mode_reg (mode, operand1); + } +) + +(define_insn "*mov_internal" + [(set (match_operand:register_modes + 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q") + (match_operand:register_modes + 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8") + (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")] +) + +(define_insn "extendsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "2,6") + (set_attr "timings" "11,12")] +) + +(define_insn "zero_extendsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, true); } + [(set_attr "length" "2,4") + (set_attr "timings" "11,12")] +) + +(define_insn "stack_push" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (const_int 4))) + (set:SI (mem:SI (reg:SI SP_REG)) + (match_operand:SI 0 "register_operand" "r"))] + "" + "push.l\t%0" + [(set_attr "length" "2")] +) + +(define_insn "stack_pushm" + [(match_parallel 1 "rx_store_multiple_vector" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_pushm (operands); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "44")] ;; The timing is a guesstimate average timing. +) + +(define_insn "stack_pop" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (mem:SI (reg:SI SP_REG))) + (set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (const_int 4)))] + "" + "pop\t%0" + [(set_attr "length" "2") + (set_attr "timings" "12")] +) + +(define_insn "stack_popm" + [(match_parallel 1 "rx_load_multiple_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, true); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "45")] ;; The timing is a guesstimate average timing. +) + +(define_insn "cstoresi4" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (match_operator:SI + 1 "comparison_operator" + [(match_operand:SI + 2 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI + 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,22,44") + (set_attr "length" "5,5,6,7,8,9,8")] +) + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand") + (if_then_else:SI (match_operand:SI 1 "comparison_operator") + (match_operand:SI 2 "nonmemory_operand") + (match_operand:SI 3 "immediate_operand")))] + "" + { + if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) + FAIL; + if (! CONST_INT_P (operands[3])) + FAIL; + } +) + +(define_insn "*movsieq" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (eq (match_operand:SI + 3 "register_operand" "r,r,r") + (match_operand:SI + 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI + 1 "nonmemory_operand" "0,i,r") + (match_operand:SI + 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstnz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +(define_insn "*movsine" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (ne (match_operand:SI 3 "register_operand" "r,r,r") + (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI 1 "nonmemory_operand" "0,i,r") + (match_operand:SI 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +;; Arithmetic Instructions + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (abs:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + abs\t%0 + abs\t%1, %0" + [(set_attr "cc" "set_zso") + (set_attr "length" "2,3")] +) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" + "=r,r,r,r,r,r,r,r,r,r,r,r") + (plus:SI (match_operand:SI + 1 "register_operand" + "%0,0,0,0,0,0,r,r,r,r,r,0") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,3,3,4,5,6,5")] +) + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:DI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "add\t%L2, %L0\n\tadc\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,44") + (set_attr "length" "5,7,9,11,13,11")] +) + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %1, %0 + and\t%Q2, %0 + and\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +;; Byte swap (single 32-bit value). +(define_insn "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "+r") + (bswap:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "revl\t%1, %0" + [(set_attr "length" "3")] +) + +;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits. +(define_insn "bswaphi2" + [(set (match_operand:HI 0 "register_operand" "+r") + (bswap:HI (match_operand:HI 1 "register_operand" "r")))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (div:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "div\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1111") ;; Strictly speaking the timing should be + ;; 2222, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (udiv:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "divu\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1010") ;; Strictly speaking the timing should be + ;; 2020, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Note - these patterns are suppressed in big-endian mode because they +;; generate a little endian result. ie the most significant word of the +;; result is placed in the higher numbered register of the destination +;; register pair. + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (mult:DI (sign_extend:DI (match_operand:SI + 1 "register_operand" "%0,0,0,0,0,0")) + (sign_extend:DI (match_operand:SI + 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "22,22,22,22,22,44")] +) + +;; See comment for mulsidi3. +;; Note - the zero_extends are to distinguish this pattern from the +;; mulsidi3 pattern. Immediate mode addressing is not supported +;; because gcc cannot handle the expression: (zero_extend (const_int)). +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" + "=r,r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" + "%0,0")) + (zero_extend:DI (match_operand:SI 2 "rx_compare_operand" + "r,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emulu\t%Q2, %0 + emulu\t%Q2, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22,44")] +) + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (smax:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "max\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "11,11,11,11,11,33")] +) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (smin:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q,r")))] + "" + "@ + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + mov.l\t%1,%0\n\tmin\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6,5") + (set_attr "timings" "11,11,11,11,11,33,22")] +) + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,Q,r") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,Q,0,r")))] + "" + "@ + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q1, %0 + mul\t%Q2, %1, %0" + [(set_attr "length" "2,2,3,4,5,6,5,5,3") + (set_attr "timings" "11,11,11,11,11,11,33,33,11")] +) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (neg:SI (match_operand:SI 1 "register_operand" "0,r")))] + ;; The NEG instruction does not comply with -fwrapv semantics. + ;; See gcc.c-torture/execute/pr22493-1.c for an example of this. + "! flag_wrapv" + "@ + neg\t%0 + neg\t%1, %0" + [(set_attr "length" "2,3")] +) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (not:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + not\t%0 + not\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "2,3")] +) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %1, %0 + or\t%Q2, %0 + or\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotl\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotr\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shar\t%2, %0 + shar\t%2, %0 + shar\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shlr\t%2, %0 + shlr\t%2, %0 + shlr\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shll\t%2, %0 + shll\t%2, %0 + shll\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") + (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))] + "" + "@ + sub\t%2, %0 + sub\t%2, %0 + add\t%N2, %0 + sub\t%2, %1, %0 + sub\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,33") + (set_attr "length" "2,2,6,3,5")] +) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (minus:DI (match_operand:DI 1 "register_operand" "0,0") + (match_operand:DI 2 "rx_source_operand" "r,Q")))] + "" + "sub\t%L2, %L0\n\tsbb\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,44") + (set_attr "length" "5,11")] +) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Floating Point Instructions +;; These patterns are only enabled with -ffast-math because the RX FPU +;; cannot handle sub-normal values. + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (plus:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fadd\t%2, %0 + fadd\t%2, %0 + fadd\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (div:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fdiv\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "1616,1616,1818") + (set_attr "length" "3,7,5")] +) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fmul\t%2, %0 + fmul\t%2, %0 + fmul\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "33,33,55") + (set_attr "length" "3,7,5")] +) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (minus:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fsub\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "ftoi\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=r,r") + (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "itof\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,6")] +) + +;; Bit manipulation instructions. +;; Note - there are two versions of each pattern because the memory +;; accessing versions use QImode whilst the register accessing +;; versions use SImode. +;; The peephole are here because the combiner only looks at a maximum +;; of three instructions at a time. + +(define_insn "bitset" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (ior:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitset_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (ior:QI (match_operand:QI 1 "memory_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (ior (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (ior (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (ior:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +(define_insn "bitinvert" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (xor:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitinvert_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (xor:QI (match_operand:QI 1 "register_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0.B" + [(set_attr "length" "5") + (set_attr "timings" "33")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (xor (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (xor:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (xor (reg A) (reg C))) +;; (set (reg C) (reg A)) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (xor:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +(define_insn "bitclr" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (and:SI (match_operand:SI 1 "register_operand" "0") + (not:SI (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitclr_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (and:QI (match_operand:QI 1 "memory_operand" "0") + (not:QI (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg C) (and (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (and:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg A) (and (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (and:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +(define_expand "insv" + [(set:SI (zero_extract:SI (match_operand:SI + 0 "nonimmediate_operand") ;; Destination + (match_operand + 1 "immediate_operand") ;; # of bits to set + (match_operand + 2 "immediate_operand")) ;; Starting bit + (match_operand + 3 "immediate_operand"))] ;; Bits to insert + "" + { + if (rx_expand_insv (operands)) + DONE; + FAIL; + } +) + +;; Atomic exchange operation. + +(define_insn "sync_lock_test_and_setsi" + [(set:SI (match_operand:SI 0 "register_operand" "=r,r") + (match_operand:SI 1 "rx_compare_operand" "=r,Q")) + (set:SI (match_dup 1) + (match_operand:SI 2 "register_operand" "0,0"))] + "" + "xchg\t%1, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22")] +) + + +;; Block move functions. + +(define_expand "movstr" + [(set:SI (match_operand:BLK 1 "memory_operand") ;; Dest + (match_operand:BLK 2 "memory_operand")) ;; Source + (use (match_operand:SI 0 "register_operand")) ;; Updated Dest + ] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + rtx dest_copy = gen_reg_rtx (SImode); + + emit_move_insn (len, GEN_INT (-1)); + emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + operands[1] = replace_equiv_address_nv (operands[1], addr1); + operands[2] = replace_equiv_address_nv (operands[2], addr2); + emit_move_insn (dest_copy, addr1); + emit_insn (gen_rx_movstr ()); + emit_move_insn (len, GEN_INT (-1)); + emit_insn (gen_rx_strend (operands[0], dest_copy)); + DONE; + } +) + +(define_insn "rx_movstr" + [(set:SI (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "smovu" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_insn "rx_strend" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") + (reg:SI 3)] UNSPEC_STRLEN)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "mov\t%1, r1\n\tmov\t#0, r2\n\tsuntil.b\n\tmov\tr1, %0\n\tsub\t#1, %0" + [(set_attr "length" "10") + (set_attr "cc" "clobber") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "movmemsi" + [(parallel + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:BLK 1 "memory_operand")) ;; Source + (use (match_operand:SI 2 "register_operand")) ;; Length in bytes + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM)] + )] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + if (REG_P (operands[0]) && (REGNO (operands[0]) == 2 + || REGNO (operands[0]) == 3)) + FAIL; + if (REG_P (operands[1]) && (REGNO (operands[1]) == 1 + || REGNO (operands[1]) == 3)) + FAIL; + if (REG_P (operands[2]) && (REGNO (operands[2]) == 1 + || REGNO (operands[2]) == 2)) + FAIL; + emit_move_insn (addr1, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[2], NULL_RTX)); + operands[0] = replace_equiv_address_nv (operands[0], addr1); + operands[1] = replace_equiv_address_nv (operands[1], addr2); + emit_insn (gen_rx_movmem ()); + DONE; + } +) + +(define_insn "rx_movmem" + [(set (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (use (reg:SI 3)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "smovf" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "setmemsi" + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:QI 2 "nonmemory_operand")) ;; Value + (use (match_operand:SI 1 "nonmemory_operand")) ;; Length + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)] + "" + { + rtx addr = gen_rtx_REG (SImode, 1); + rtx val = gen_rtx_REG (QImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (addr, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[1], NULL_RTX)); + emit_move_insn (val, operands[2]); + emit_insn (gen_rx_setmem ()); + DONE; + } +) + +(define_insn "rx_setmem" + [(set:BLK (mem:BLK (reg:SI 1)) (reg 2)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 3))] + "" + "sstr.b" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "cmpstrnsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (use (match_operand:SI + 3 "register_operand")) ;; Max Length + (match_operand:SI + 4 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[3], NULL_RTX)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_expand "cmpstrsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (match_operand:SI + 3 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_reg (SImode, XEXP (operands[1], 0))); + emit_move_insn (str2, force_reg (SImode, XEXP (operands[2], 0))); + emit_move_insn (len, GEN_INT (-1)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_insn "rx_cmpstrn" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] + UNSPEC_CMPSTRN)) + (use (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:BLK 2 "memory_operand" "m")) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "scmpu ; Perform the string comparison + mov #-1, %0 ; Set up -1 result (which cannot be created + ; by the SC insn) + bnc ?+ ; If Carry is not set skip over + scne.L %0 ; Set result based on Z flag +?: +" + [(set_attr "length" "9") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +;; Builtin Functions +;; +;; GCC does not have the ability to generate the following instructions +;; on its own so they are provided as builtins instead. To use them from +;; a program for example invoke them as __builtin_rx_. For +;; example: +;; +;; int short_byte_swap (int arg) { return __builtin_rx_revw (arg); } + +;;---------- Accumulator Support ------------------------ + +;; Multiply & Accumulate (high) +(define_insn "machi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACHI)] + "" + "machi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply & Accumulate (low) +(define_insn "maclo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACLO)] + "" + "maclo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (high) +(define_insn "mulhi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULHI)] + "" + "mulhi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (low) +(define_insn "mullo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULLO)] + "" + "mullo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (high) +(define_insn "mvfachi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACHI))] + "" + "mvfachi\t%0" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (middle) +(define_insn "mvfacmi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACMI))] + "" + "mvfacmi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (high) +(define_insn "mvtachi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACHI)] + "" + "mvtachi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (low) +(define_insn "mvtaclo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACLO)] + "" + "mvtaclo\t%0" + [(set_attr "length" "3")] +) + +;; Round Accumulator +(define_insn "racw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_RACW)] + "" + "racw\t%0" + [(set_attr "length" "3")] +) + +;; Repeat multiply and accumulate +(define_insn "rmpa" + [(unspec:SI [(const_int 0) (reg:SI 1) (reg:SI 2) (reg:SI 3) + (reg:SI 4) (reg:SI 5) (reg:SI 6)] + UNSPEC_BUILTIN_RMPA) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "rmpa" + [(set_attr "length" "2") + (set_attr "timings" "1010")] +) + +;;---------- Arithmetic ------------------------ + +;; Byte swap (two 16-bit values). +(define_insn "revw" + [(set (match_operand:SI 0 "register_operand" "+r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_REVW))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +;; Round to integer. +(define_insn "lrintsf2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(match_operand:SF 1 "rx_compare_operand" "r,Q")] + UNSPEC_BUILTIN_ROUND))] + "" + "round\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +;; Saturate to 32-bits +(define_insn "sat" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "0")] + UNSPEC_BUILTIN_SAT))] + "" + "sat\t%0" + [(set_attr "length" "2")] +) + +;;---------- Control Registers ------------------------ + +;; Clear Processor Status Word +(define_insn "clrpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_CLRPSW) + (clobber (cc0))] + "" + "clrpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Set Processor Status Word +(define_insn "setpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_SETPSW) + (clobber (cc0))] + "" + "setpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Move from control register +(define_insn "mvfc" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFC))] + "" + "mvfc\t%C1, %0" + [(set_attr "length" "3")] +) + +;; Move to control register +(define_insn "mvtc" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + (match_operand:SI 1 "nonmemory_operand" "r,i")] + UNSPEC_BUILTIN_MVTC) + (clobber (cc0))] + "" + "mvtc\t%1, %C0" + [(set_attr "length" "3,7") + (set_attr "cc" "clobber")] ;; Just in case the control + ;; register selected is the psw. +) + +;;---------- Interrupts ------------------------ + +;; Break +(define_insn "brk" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_BRK)] + "" + "brk" + [(set_attr "length" "1") + (set_attr "timings" "66")] +) + +;; Interrupt +(define_insn "int" + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_INT)] + "" + "int\t%0" + [(set_attr "length" "3")] +) + +;; Wait +(define_insn "wait" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_WAIT)] + "" + "wait" + [(set_attr "length" "2")] +) + +;;---------- CoProcessor Support ------------------------ + +;; FIXME: The instructions are currently commented out because +;; the bit patterns have not been finalized, so the assembler +;; does not support them. Once they are decided and the assembler +;; supports them, enable the instructions here. + +;; Move from co-processor register +(define_insn "mvfcp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFCP))] + "" + "; mvfcp\t%1, %0, %2" + [(set_attr "length" "5")] +) + +;; Move to co-processor register +(define_insn "mvtcp" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + (match_operand:SI 1 "nonmemory_operand" "i,r") + (match_operand:SI 2 "immediate_operand" "i,i")] + UNSPEC_BUILTIN_MVTCP)] + "" + "; mvtcp\t%0, %1, %2" + [(set_attr "length" "7,5")] +) + +;; Co-processor operation +(define_insn "opecp" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i") + (match_operand:SI 1 "immediate_operand" "i")] + UNSPEC_BUILTIN_OPEPC)] + "" + "; opecp\t%0, %1" + [(set_attr "length" "5")] +) + +;;---------- Misc ------------------------ + +;; Required by cfglayout.c... +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "length" "1")] +) diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt new file mode 100644 index 00000000000..83e75bfba76 --- /dev/null +++ b/gcc/config/rx/rx.opt @@ -0,0 +1,74 @@ +; Command line options for the Renesas RX port of GCC. +; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; 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 +; . +;--------------------------------------------------- + +m64bit-doubles +Target RejectNegative Mask(64BIT_DOUBLES) +Store doubles in 64 bits. + +m32bit-doubles +Target RejectNegative InverseMask(64BIT_DOUBLES) +Stores doubles in 32 bits. This is the default. + +;--------------------------------------------------- + +mbig-endian-data +Target RejectNegative Mask(BIG_ENDIAN_DATA) +Data is stored in big-endian format. + +mlittle-endian-data +Target RejectNegative InverseMask(BIG_ENDIAN_DATA) +Data is stored in little-endian format. (Default). + +;--------------------------------------------------- + +msmall-data-limit= +Target RejectNegative Joined UInteger Var(rx_small_data_limit) Init(0) +Maximum size of global and static variables which can be placed into the small data area. + +;--------------------------------------------------- + +msim +Target +Use the simulator runtime. + +;--------------------------------------------------- + +mas100-syntax +Target Mask(AS100_SYNTAX) +Generate assembler output that is compatible with the Renesas AS100 assembler. This may restrict some of the compiler's capabilities. The default is to generate GAS compatable syntax. + +;--------------------------------------------------- + +mrelax +Target +Enable linker relaxation. + +;--------------------------------------------------- + +mmax-constant-size= +Target RejectNegative Joined UInteger Var(rx_max_constant_size) Init(0) +Maximum size in bytes of constant values allowed as operands. + +;--------------------------------------------------- + +mint-register= +Target RejectNegative Joined UInteger Var(rx_interrupt_registers) Init(0) +Specifies the number of registers to reserve for interrupt handlers. diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx new file mode 100644 index 00000000000..39cda72af57 --- /dev/null +++ b/gcc/config/rx/t-rx @@ -0,0 +1,32 @@ +# Makefile fragment for building GCC for the Renesas RX target. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 +# . + +# Enable multilibs: + +MULTILIB_OPTIONS = m64bit-doubles mbig-endian-data +MULTILIB_DIRNAMES = 64fp big-endian-data +MULTILIB_MATCHES = m64bit-doubles=mieee +MULTILIB_EXCEPTIONS = +MULTILIB_EXTRA_OPTS = + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi index d2d1673cc3b..ca86f28dd39 100644 --- a/gcc/doc/contrib.texi +++ b/gcc/doc/contrib.texi @@ -173,8 +173,8 @@ The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project} for all of their merged runtime code. @item -Nick Clifton for arm, mcore, fr30, v850, m32r work, @option{--help}, and -other random hacking. +Nick Clifton for arm, mcore, fr30, v850, m32r, rx work, +@option{--help}, and other random hacking. @item Michael Cook for libstdc++ cleanup patches to reduce warnings. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a0f66214e3f..6883766cfc6 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2244,6 +2244,13 @@ on data in the eight bit data area. Note the eight bit data area is limited to You must use GAS and GLD from GNU binutils version 2.7 or later for this attribute to work correctly. +@item exception +@cindex exception handler functions on the RX processor +Use this attribute on the RX to indicate that the specified function +is an exception handler. The compiler will generate function entry and +exit sequences suitable for use in an exception handler when this +attribute is present. + @item exception_handler @cindex exception handler functions on the Blackfin processor Use this attribute on the Blackfin to indicate that the specified function @@ -2280,7 +2287,7 @@ addressing modes. @item fast_interrupt @cindex interrupt handler functions -Use this attribute on the M32C port to indicate that the specified +Use this attribute on the M32C and RX ports to indicate that the specified function is a fast interrupt handler. This is just like the @code{interrupt} attribute, except that @code{freit} is used to return instead of @code{reit}. @@ -2472,8 +2479,8 @@ This attribute is ignored for R8C target. @item interrupt @cindex interrupt handler functions -Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS -and Xstormy16 ports to indicate that the specified function is an +Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS, +RX and Xstormy16 ports to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. @@ -2689,7 +2696,7 @@ support for the swap suffix in the assembler. (GNU Binutils 2.19.51 or later) @item naked @cindex function without a prologue/epilogue code -Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate that +Use this attribute on the ARM, AVR, IP2K, RX and SPU ports to indicate that the specified function does not need prologue/epilogue sequences generated by the compiler. It is up to the programmer to provide these sequences. The only statements that can be safely included in naked functions are @@ -7460,6 +7467,7 @@ instructions, but allow the compiler to schedule those calls. * Other MIPS Built-in Functions:: * picoChip Built-in Functions:: * PowerPC AltiVec/VSX Built-in Functions:: +* RX Built-in Functions:: * SPARC VIS Built-in Functions:: * SPU Built-in Functions:: @end menu @@ -11754,6 +11762,121 @@ long __builtin_bpermd (long, long); int __builtin_bswap16 (int); @end smallexample +@node RX Built-in Functions +@subsection RX Built-in Functions +GCC supports some of the RX instructions which cannot be expressed in +the C programming language via the use of built-in functions. The +following functions are supported: + +@deftypefn {Built-in Function} void __builtin_rx_brk (void) +Generates the @code{brk} machine instruction. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_clrpsw (int) +Generates the @code{clrpsw} machine instruction to clear the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_int (int) +Generates the @code{int} machine instruction to generate an interrupt +with the specified value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_machi (int, int) +Generates the @code{machi} machine instruction to add the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_maclo (int, int) +Generates the @code{maclo} machine instruction to add the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mulhi (int, int) +Generates the @code{mulhi} machine instruction to place the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mullo (int, int) +Generates the @code{mullo} machine instruction to place the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfachi (void) +Generates the @code{mvfachi} machine instruction to read the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfacmi (void) +Generates the @code{mvfacmi} machine instruction to read the middle +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfc (int) +Generates the @code{mvfc} machine instruction which reads the control +register specified in its argument and returns its value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtachi (int) +Generates the @code{mvtachi} machine instruction to set the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtaclo (int) +Generates the @code{mvtaclo} machine instruction to set the bottom +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtc (int reg, int val) +Generates the @code{mvtc} machine instruction which sets control +register number @code{reg} to @code{val}. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtipl (int) +Generates the @code{mvtipl} machine instruction set the interrupt +priority level. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_racw (int) +Generates the @code{racw} machine instruction to round the accumulator +according to the specified mode. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_revw (int) +Generates the @code{revw} machine instruction which swaps the bytes in +the argument so that bits 0--7 now occupy bits 8--15 and vice versa, +and also bits 16--23 occupy bits 24--31 and vice versa. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_rmpa (void) +Generates the @code{rmpa} machine instruction which initiates a +repeated multiply and accumulate sequence. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_round (float) +Generates the @code{round} machine instruction which returns the +floating point argument rounded according to the current rounding mode +set in the floating point status word register. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_sat (int) +Generates the @code{sat} machine instruction which returns the +saturated value of the argument. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_setpsw (int) +Generates the @code{setpsw} machine instruction to set the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_wait (void) +Generates the @code{wait} machine instruction. +@end deftypefn + @node SPARC VIS Built-in Functions @subsection SPARC VIS Built-in Functions @@ -12003,7 +12126,6 @@ extern int foo (); @end table - @node RS/6000 and PowerPC Pragmas @subsection RS/6000 and PowerPC Pragmas diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index c04f9cb65d5..0fd68244ea7 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -4001,6 +4001,14 @@ the PSIM simulator. @heading @anchor{powerpcle-x-eabi}powerpcle-*-eabi Embedded PowerPC system in little endian mode. +@html +
+@end html +@heading @anchor{rx-x-elf}rx-*-elf +The Renesas RX processor. See +@uref{http://eu.renesas.com/fmwk.jsp?cnt=rx600_series_landing.jsp&fp=/products/mpumcu/rx_family/rx600_series} +for more information about this processor. + @html
@end html diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 7b20ced5483..b45df833f2e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -783,6 +783,16 @@ See RS/6000 and PowerPC Options. -msim -mmvme -mads -myellowknife -memb -msdata @gol -msdata=@var{opt} -mvxworks -G @var{num} -pthread} +@emph{RX Options} +@gccoptlist{-m64bit-doubles -m32bit-doubles -mieee -mno-ieee@gol +-mbig-endian-data -mlittle-endian-data @gol +-msmall-data @gol +-msim -mno-sim@gol +-mas100-syntax -mno-as100-syntax@gol +-mrelax@gol +-mmax-constant-size=@gol +-mint-register=} + @emph{S/390 and zSeries Options} @gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol -mhard-float -msoft-float -mhard-dfp -mno-hard-dfp @gol @@ -9530,6 +9540,7 @@ platform. * picoChip Options:: * PowerPC Options:: * RS/6000 and PowerPC Options:: +* RX Options:: * S/390 and zSeries Options:: * Score Options:: * SH Options:: @@ -10943,7 +10954,7 @@ These @samp{-m} options are defined for the DEC Alpha/VMS implementations: @table @gcctabopt @item -mvms-return-codes @opindex mvms-return-codes -Return VMS condition codes from main. The default is to return POSIX +Return VMS condition codes from main. The default is to return POSIX style condition (e.g.@: error) codes. @item -mdebug-main=@var{prefix} @@ -15362,6 +15373,112 @@ This option sets flags for both the preprocessor and linker. @end table +@node RX Options +@subsection RX Options +@cindex RX Options + +These @option{-m} options are defined for RX implementations: + +@table @gcctabopt +@item -m64bit-doubles +@itemx -m32bit-doubles +@opindex m64bit-doubles +@opindex m32bit-doubles +Make the @code{double} data type be 64-bits (@option{-m64bit-doubles}) +or 32-bits (@option{-m32bit-doubles}) in size. The default is +@option{-m32bit-doubles}. @emph{Note} the RX's hardware floating +point instructions are only used for 32-bit floating point values, and +then only if @option{-ffast-math} has been specified on the command +line. This is because the RX FPU instructions do not properly support +denormal (or sub-normal) values. + +@item -mbig-endian-data +@itemx -mlittle-endian-data +@opindex mbig-endian-data +@opindex mlittle-endian-data +Store data (but not code) in the big-endian format. The default is +@option{-mlittle-endian-data}, ie to store data in the little endian +format. + +@item -msmall-data-limit=@var{N} +@opindex msmall-data-limit +Specifies the maximum size in bytes of global and static variables +which can be placed into the small data area. Using the small data +area can lead to smaller and faster code, but the size of area is +limited and it is up to the programmer to ensure that the area does +not overflow. Also when the small data area is used one of the RX's +registers (@code{r13}) is reserved for use pointing to this area, so +it is no longer available for use by the compiler. This could result +in slower and/or larger code if variables which once could have been +held in @code{r13} are now pushed onto the stack. + +Note, common variables (variables which have not been initialised) and +constants are not placed into the small data area as they are assigned +to other sections in the output executeable. + +The default value is zero, which disables this feature. Note, this +feature is not enabled by default with higher optimization levels +(@option{-O2} etc) because of the potentially deterimental effects of +reserving register @code{r13}. It is up to the programmer to +experiment and discover whether this feature is of benefit to their +program. + +@item -msim +@item -mno-sim +@opindex msim +@opindex mno-sim +Use the simulator runtime. The default is to use the libgloss board +specific runtime. + +@item -mas100-syntax +@item -mno-as100-syntax +@opindex mas100-syntax +@opindex mno-as100-syntax +When generating assembler output use a syntax that is compatible with +Renesas's AS100 assembler. This syntax can also be handled by the GAS +assembler but it has some restrictions so generating it is not the +default option. + +@item -mmax-constant-size=@var{N} +@opindex mmax-constant-size +Specifies the maxium size, in bytes, of a constant that can be used as +an operand in a RX instruction. Although the RX instruction set does +allow consants of up to 4 bytes in length to be used in instructions, +a longer value equates to a longer instruction. Thus in some +circumstances it can be beneficial to restrict the size of constants +that are used in instructions. Constants that are too big are instead +placed into a constant pool and referenced via register indirection. + +The value @var{N} can be between 0 and 3. A value of 0, the default, +means that constants of any size are allowed. + +@item -mrelax +@opindex mrelax +Enable linker relaxation. Linker relaxation is a process whereby the +linker will attempt to reduce the size of a program by finding shorter +versions of various instructions. Disabled by default. + +@item -mint-register=@var{N} +@opindex mint-register +Specify the number of registers to reserve for fast interrupt handler +functions. The value @var{N} can be between 0 and 4. A value of 1 +means that register @code{r13} will be reserved for ther exclusive use +of fast interrupt handlers. A value of 2 reserves @code{r13} and +@code{r12}. A value of 3 reserves @code{r13}, @code{r12} and +@code{r11}, and a value of 4 reserves @code{r13} through @code{r10}. +A value of 0, the default, does not reserve any registers. +@end table + +@emph{Note:} The generic GCC command line @option{-ffixed-@var{reg}} +has special significance to the RX port when used with the +@code{interrupt} function attribute. This attribute indicates a +function intended to process fast interrupts. GCC will will ensure +that it only uses the registers @code{r10}, @code{r11}, @code{r12} +and/or @code{r13} and only provided that the normal use of the +corresponding registers have been restricted via the +@option{-ffixed-@var{reg}} or @option{-mint-register} command line +options. + @node S/390 and zSeries Options @subsection S/390 and zSeries Options @cindex S/390 and zSeries Options diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 8a1a389924c..dcfba921207 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -2897,6 +2897,32 @@ A constant in the range of 0 to @minus{}255. @end table +@item RX---@file{config/rx/constraints.md} +@table @code +@item Q +An address which does not involve register indirect addressing or +pre/post increment/decrement addressing. + +@item Symbol +A symbol reference. + +@item Int08 +A constant in the range @minus{}256 to 255, inclusive. + +@item Sint08 +A constant in the range @minus{}128 to 127, inclusive. + +@item Sint16 +A constant in the range @minus{}32768 to 32767, inclusive. + +@item Sint24 +A constant in the range @minus{}8388608 to 8388607, inclusive. + +@item Uint04 +A constant in the range 0 to 15, inclusive. + +@end table + @need 1000 @item SPARC---@file{config/sparc/sparc.h} @table @code diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 805ebf2b3ab..ba86a08487e 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3529,7 +3529,7 @@ dynamically if their size exceeds @code{STACK_CHECK_MAX_VAR_SIZE} bytes. @defmac STACK_CHECK_BUILTIN A nonzero value if stack checking is done by the configuration files in a machine-dependent manner. You should define this macro if stack checking -is require by the ABI of your machine or if you would like to do stack +is required by the ABI of your machine or if you would like to do stack checking in some more efficient way than the generic approach. The default value of this macro is zero. @end defmac @@ -3788,7 +3788,7 @@ registers @code{regs_ever_live} and @code{call_used_regs}. If @code{ELIMINABLE_REGS} is defined, this macro will be not be used and need not be defined. Otherwise, it must be defined even if -@code{TARGET_FRAME_POINTER_REQUIRED} is always return true; in that +@code{TARGET_FRAME_POINTER_REQUIRED} always returns true; in that case, you may set @var{depth-var} to anything. @end defmac @@ -4205,7 +4205,6 @@ on the stack. The compiler knows how to track the amount of stack space used for arguments without any special help. @end defmac - @defmac FUNCTION_ARG_OFFSET (@var{mode}, @var{type}) If defined, a C expression that is the number of bytes to add to the offset of the argument passed in memory. This is needed for the SPU, @@ -5370,9 +5369,10 @@ post-address side-effect generation involving a register displacement. @defmac CONSTANT_ADDRESS_P (@var{x}) A C expression that is 1 if the RTX @var{x} is a constant which -is a valid address. On most machines, this can be defined as -@code{CONSTANT_P (@var{x})}, but a few machines are more restrictive -in which constant addresses are supported. +is a valid address. On most machines the default definition of +@code{(CONSTANT_P (@var{x}) && GET_CODE (@var{x}) != CONST_DOUBLE)} +is acceptable, but a few machines are more restrictive as to which +constant addresses are supported. @end defmac @defmac CONSTANT_P (@var{x}) @@ -6127,7 +6127,7 @@ this macro is defined, it should produce a nonzero value when @code{STRICT_ALIGNMENT} is nonzero. @end defmac -@defmac MOVE_RATIO +@defmac MOVE_RATIO (@var{speed}) The threshold of number of scalar memory-to-memory move insns, @emph{below} which a sequence of insns should be generated instead of a string move insn or a library call. Increasing the value will always @@ -6137,6 +6137,9 @@ Note that on machines where the corresponding move insn is a @code{define_expand} that emits a sequence of insns, this macro counts the number of such sequences. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6152,12 +6155,15 @@ A C expression used by @code{move_by_pieces} to determine the largest unit a load or store used to copy memory is. Defaults to @code{MOVE_MAX}. @end defmac -@defmac CLEAR_RATIO +@defmac CLEAR_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{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. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6168,13 +6174,16 @@ will be used. Defaults to 1 if @code{move_by_pieces_ninsns} returns less than @code{CLEAR_RATIO}. @end defmac -@defmac SET_RATIO +@defmac SET_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{below} which a sequence of insns should be generated to set memory to a constant value, instead of a block set insn or a library call. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, it defaults to the value of @code{MOVE_RATIO}. @end defmac @@ -6189,7 +6198,7 @@ than @code{SET_RATIO}. @defmac STORE_BY_PIECES_P (@var{size}, @var{alignment}) A C expression used to determine whether @code{store_by_pieces} will be -used to set a chunk of memory to a constant string value, or whether some +used to set a chunk of memory to a constant string value, or whether some other mechanism will be used. Used by @code{__builtin_strcpy} when called with a constant source string. Defaults to 1 if @code{move_by_pieces_ninsns} returns less @@ -6255,7 +6264,7 @@ Define this macro if a non-short-circuit operation produced by @code{BRANCH_COST} is greater than or equal to the value 2. @end defmac -@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}) +@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}, bool @var{speed}) This target hook describes the relative costs of RTL expressions. The cost may depend on the precise form of the expression, which is @@ -6274,15 +6283,15 @@ necessary. Traditionally, the default costs are @code{COSTS_N_INSNS (5)} for multiplications, @code{COSTS_N_INSNS (7)} for division and modulus operations, and @code{COSTS_N_INSNS (1)} for all other operations. -When optimizing for code size, i.e.@: when @code{optimize_size} is -nonzero, this target hook should be used to estimate the relative +When optimizing for code size, i.e.@: when @code{speed} is +false, this target hook should be used to estimate the relative size cost of an expression, again relative to @code{COSTS_N_INSNS}. The hook returns true when all subexpressions of @var{x} have been processed, and false when @code{rtx_cost} should recurse. @end deftypefn -@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}) +@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}, bool @var{speed}) This hook computes the cost of an addressing mode that contains @var{address}. If not defined, the cost is computed from the @var{address} expression and the @code{TARGET_RTX_COST} hook. @@ -6384,7 +6393,7 @@ debug output to. @var{verbose} is the verbose level provided by list of instructions that are ready to be scheduled. @var{n_readyp} is a pointer to the number of elements in the ready list. The scheduler reads the ready list in reverse order, starting with -@var{ready}[@var{*n_readyp}-1] and going to @var{ready}[0]. @var{clock} +@var{ready}[@var{*n_readyp} @minus{} 1] and going to @var{ready}[0]. @var{clock} is the timer tick of the scheduler. You may modify the ready list and the number of ready insns. The return value is the number of insns that can issue this cycle; normally this is just @code{issue_rate}. See also @@ -9516,7 +9525,7 @@ attributes, or a copy of the list may be made if further changes are needed. @end deftypefn -@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (tree @var{fndecl}) +@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (const_tree @var{fndecl}) @cindex inlining This target hook returns @code{true} if it is ok to inline @var{fndecl} into the current function, despite its having target-specific @@ -10910,7 +10919,6 @@ to the stack. Therefore, this hook should return true in general, but false for naked functions. The default implementation always returns true. @end deftypefn - @deftypevr {Target Hook} {unsigned HOST_WIDE_INT} TARGET_CONST_ANCHOR On some architectures it can take multiple instructions to synthesize a constant. If there is another constant already in a register that diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7f370779af7..08a7de5fa03 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2009-10-26 Nick Clifton + + * lib/target-supports.exp (check_profiling_available): + Profiling is not, currently, available for the RX port. + (check_effective_target_hard_float): Add support for RX + target. + * gcc.target/rx: New directory. + * gcc.target/rx/builtins.c: New test file. + * gcc.target/rx/interrupts.c: New test file. + * gcc.target/rx/rx-abi-function-tests.c: New test file. + * gcc.target/rx/zero-width-bitfield.c: New test file. + * gcc.target/rx/i272091.c: New test file. + * gcc.target/rx/packed-struct.c: New test file. + * gcc.target/rx/rx.exp: New file: Drives RX tests. + 2009-10-26 Andrew Pinski * gcc.dg/lto/20091014-1_0.c: Replace -shared with -r -nostlib. diff --git a/gcc/testsuite/gcc.target/rx/builtins.c b/gcc/testsuite/gcc.target/rx/builtins.c new file mode 100644 index 00000000000..07448024b44 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/builtins.c @@ -0,0 +1,159 @@ +/* { dg-do run } */ +/* { dg-options "-fno-ipa-cp-clone" } */ + +/* Verify that the RX specific builtin functions work. */ + +/* IPA CP cloning is disabled because the constant propagation + has no understanding of the saturation behaviour of the + __builtin_rx_sat function and so it will optimize away the + saturation addition test. */ + +#include +#include + +/* We need to prevent these functions from being inlined + as otherwise gcc will attempt to optimize away their + arguments and we need the operations on them in order + to correctly set the psw flags. */ + +int saturate_add (int, int) __attribute__((__noinline__)); +int subtract_with_borrow (int, int, int) __attribute__((__noinline__)); +int exchange (int, int) __attribute__((__noinline__)); + +int +half_word_swap (int arg) +{ + return __builtin_rx_revw (arg); +} + +int +saturate_add (int arg1, int arg2) +{ + arg1 += arg2; + return __builtin_rx_sat (arg1); +} + +long +multiply_and_accumulate (long arg1, long arg2, long arg3) +{ + __builtin_rx_mvtaclo (0); + __builtin_rx_mvtachi (0); + + __builtin_rx_mullo (arg1, arg2); + __builtin_rx_mulhi (arg1, arg2); + __builtin_rx_maclo (arg1, arg3); + __builtin_rx_machi (arg1, arg3); + + __builtin_rx_racw (1); + + arg1 = __builtin_rx_mvfachi (); + arg1 += __builtin_rx_mvfacmi (); + + return arg1; +} + +int +rxround (float arg) +{ + return __builtin_rx_round (arg); +} + +/* #define DEBUG 1 */ + +#ifdef DEBUG +#define CHECK_0ARG(func, result) \ + if (func () != result) \ + { \ + printf (#func " () fails: %x not %x\n", func (), result); \ + abort (); \ + } + +#define CHECK_1ARG(func, arg, result) \ + if (func (arg) != result) \ + { \ + printf (#func " (" #arg ") fails: %x not %x\n", func (arg), result); \ + abort (); \ + } + +#define CHECK_2ARG(func, arg1, arg2, result) \ + if (func (arg1, arg2) != result) \ + { \ + printf (#func " (" #arg1 "," #arg2 ") fails: %x not %x\n", \ + func (arg1, arg2), result); \ + abort (); \ + } + +#define CHECK_3ARG(func, arg1, arg2, arg3, result) \ + if (func (arg1, arg2, arg3) != result) \ + { \ + printf (#func " (" #arg1 "," #arg2 "," #arg3 ") fails: %x not %x\n", \ + func (arg1, arg2, arg3), result); \ + abort (); \ + } +#else +#define CHECK_0ARG(func, result) \ + if (func () != result) \ + abort (); + +#define CHECK_1ARG(func, arg, result) \ + if (func (arg) != result) \ + abort (); + +#define CHECK_2ARG(func, arg1, arg2, result) \ + if (func (arg1, arg2) != result) \ + abort (); + +#define CHECK_3ARG(func, arg1, arg2, arg3, result) \ + if (func (arg1, arg2, arg3) != result) \ + abort (); +#endif + +int +main (void) +{ + CHECK_1ARG (half_word_swap, 0x12345678, 0x34127856); + CHECK_2ARG (saturate_add, 0x80000000, 0x80000000, 0x80000000); + CHECK_3ARG (multiply_and_accumulate, 0x111, 0x222, 0x333, 0x70007); + CHECK_1ARG (rxround, 0.5, 1); + return 0; +} + +/* The following builtins are compiled but + not executed because they need OS support. */ + +void +rxbreak (void) +{ + __builtin_rx_brk (); +} + +void +interrupt (void) +{ + __builtin_rx_int (0x12); +} + +int +get_stack_pointer (void) +{ + return __builtin_rx_mvfc (2); +} + +void +set_stack_pointer (int value) +{ + __builtin_rx_mvtc (2, value); + __builtin_rx_mvtc (2, 0x1234); +} + +void +wait (void) +{ + __builtin_rx_wait (); +} + +void +rmpa (int * multiplicand, int * multiplier, int num) +{ + __builtin_rx_rmpa (); +} diff --git a/gcc/testsuite/gcc.target/rx/i272091.c b/gcc/testsuite/gcc.target/rx/i272091.c new file mode 100644 index 00000000000..39da576326f --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/i272091.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-msmall-data-limit=100" } */ + +double a=6.76,b=7.34,c=0.54; +double x_1= 45.46; +static double SD_1; +static double SD_init = 45.54; +double DD_1; +double DD_init=769.0; + + +int main() +{ + volatile double x,y,z; + + x = 56.76; + y = 4.5645; + + z = x + y; + z = x - 4.65; + z = 4.566 - x; + z = x * y; + b = 8; + c = 34; + return 0; +} + diff --git a/gcc/testsuite/gcc.target/rx/interrupts.c b/gcc/testsuite/gcc.target/rx/interrupts.c new file mode 100644 index 00000000000..910e870f11b --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/interrupts.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-mint-register=3" } */ + +/* Verify that the RX specific function attributes work. */ + +void interrupt (void) __attribute__((__interrupt__)); +void exception (void) __attribute__((__exception__)); +int naked (int) __attribute__((__naked__)); + +int flag = 0; + +/* Fast interrupt handler. Only uses registers marked as fixed + by the -fixed-xxx gcc command line option. Returns via RTFI. */ + +void +interrupt (void) +{ + flag = 1; +} + +/* Exception handler. Must preserve any register it uses, even + call clobbered ones. Returns via RTE. */ + +void +exception (void) +{ + switch (flag) + { + case 0: + flag = -1; + break; + case 1: + case 2: + case 4: + flag = flag - 2; + break; + case 5: + case 7: + case 6: + flag ^= 3; + break; + default: + naked (flag * 2); + break; + } +} + +/* Naked function. The programmer must supply the function's + prologue and epilogue instructions. */ + +int +naked (int arg) +{ + flag = arg; +} + +/* { dg-final { scan-assembler "rtfi" } } */ +/* { dg-final { scan-assembler "rte" } } */ diff --git a/gcc/testsuite/gcc.target/rx/packed-struct.c b/gcc/testsuite/gcc.target/rx/packed-struct.c new file mode 100644 index 00000000000..8c2a4345b82 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/packed-struct.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ + +struct unpacked +{ + int i; + char c; +}; + +#pragma pack(1) + +struct packed +{ + int i; + char c; +}; + +struct packed_contains_unpacked +{ + char c; + struct unpacked uuuu; /* This should generate an error message. */ +}; /* { dg-error "unpacked structure/union inside a packed struct" "XFAILed until patch for generic GCC structure layout code is accepted" { xfail rx-*-* } } */ + +union contains_unpacked +{ + char c; + struct unpacked uuuu; /* This should not. */ +}; + +struct packed_contains_packed +{ + char c; + struct packed ppppp; /* This should not. */ +}; + +#pragma pack() + +struct unpacked_contains_packed +{ + char c; + struct packed p; +}; + +struct unpacked_contains_unpacked +{ + char c; + struct unpacked u; +}; + + +int s1 = sizeof (struct unpacked); +int s2 = sizeof (struct packed); +int s3 = sizeof (struct packed_contains_unpacked); +int s4 = sizeof (struct packed_contains_packed); +int s5 = sizeof (struct unpacked_contains_packed); +int s6 = sizeof (struct unpacked_contains_unpacked); diff --git a/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c b/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c new file mode 100644 index 00000000000..0c4ec3f6b05 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c @@ -0,0 +1,159 @@ +/* { dg-do run } */ +/* { dg-options "-msim" } */ +/* Note: The -msim abiove is actually there to override the default + options which include -ansi -pendantic and -Wlong-long... */ + +extern int printf (const char *, ...); +extern void exit (int); +extern void abort (void); + +extern signed long _COM_CONVf32s (float); +extern unsigned long _COM_CONVf32u (float); +extern float _COM_CONV32sf (signed long); +extern float _COM_CONV32uf (unsigned long); +extern float _COM_ADDf (float, float); +extern float _COM_SUBf (float, float); +extern float _COM_MULf (float, float); +extern float _COM_DIVf (float, float); +extern int _COM_CMPLTf (float, float); + +extern long long _COM_MUL64 (long long, long long); +extern signed long long _COM_DIV64s (long long, long long); +extern unsigned long long _COM_DIV64u (unsigned long long, unsigned long long); +extern long long _COM_SHLL64 (long long, int); +extern long long _COM_SHLR64 (long long, int); +extern long long _COM_SHAR64 (long long, int); +extern signed long long _COM_CONVf64s (float); +extern unsigned long long _COM_CONVf64u (float); +extern signed long long _COM_CONVd64s (double); +extern unsigned long long _COM_CONVd64u (double); +extern float _COM_CONV64sf (signed long long); +extern float _COM_CONV64uf (unsigned long long); +extern double _COM_CONV64sd (signed long long); +extern double _COM_CONV64ud (unsigned long long); +extern signed long long _COM_MOD64s (long long, long long); +extern unsigned long long _COM_MOD64u (unsigned long long, unsigned long long); +extern int _COM_CMPLT64s (long long, long long); +extern int _COM_CMPLT64u (unsigned long long, unsigned long long); +extern int _COM_CMPGT64s (long long, long long); +extern int _COM_CMPGT64u (unsigned long long, unsigned long long); +extern int _COM_CMPLE64s (long long, long long); +extern int _COM_CMPLE64u (unsigned long long, unsigned long long); +extern int _COM_CMPGE64s (long long, long long); +extern int _COM_CMPGE64u (unsigned long long, unsigned long long); +extern int _COM_CMPEQ64 (long long, long long); +extern int _COM_CMPNE64 (long long, long long); + +extern double _COM_ADDd (double, double); +extern double _COM_SUBd (double, double); +extern double _COM_MULd (double, double); +extern double _COM_DIVd (double, double); +extern signed long _COM_CONVd32s (double); +extern unsigned long _COM_CONVd32u (double); +extern double _COM_CONV32sd (signed long); +extern double _COM_CONV32ud (unsigned long); +extern double _COM_CONVfd (float); +extern float _COM_CONVdf (double); +extern double _COM_NEGd (double); + + +/* #define DEBUG 1 */ + +#ifdef DEBUG +# define TEST1(func,arg1,result) if (func (arg1) != result) printf ("fail: " #func " (" #arg1 ") returns %x rather than " #result "\n", func (arg1)) +# define TEST2(func,arg1,arg2,result) if (func (arg1, arg2) != result) printf ("fail: " #func " (" #arg1 ", " #arg2 ") returns %x rather than " #result "\n", func (arg1, arg2)) +# define TEST_CMP(func, low_arg, high_arg, lt_result, eq_result, gt_result) \ + do \ + { \ + int res; \ + \ + if ((res = func (low_arg, high_arg)) != lt_result) printf ("fail: " #func " (" #low_arg ", " #high_arg ") returns %d rather than %d\n", res, lt_result); \ + if ((res = func (high_arg, low_arg)) != gt_result) printf ("fail: " #func " (" #high_arg ", " #low_arg ") returns %d rather than %d\n", res, gt_result); \ + if ((res = func (low_arg, low_arg)) != eq_result) printf ("fail: " #func " (" #low_arg ", " #low_arg ") returns %d rather than %d\n", res, eq_result); \ + } \ + while (0) +#else +# define TEST1(func,arg1,result) if (func (arg1) != result) abort () +# define TEST2(func,arg1,arg2,result) if (func (arg1, arg2) != result) abort () +# define TEST_CMP(func,low,high,lt_res,eq_res,gt_res) \ + if ( (func (low, high) != lt_res) \ + || (func (high, low) != gt_res) \ + || (func (low, low) != eq_res)) \ + abort (); +#endif + + +int +main (void) +{ +#ifdef DEBUG + printf ("Tests starting\n"); +#endif + + TEST1 (_COM_CONVf32s, -2.0f, -2); + TEST1 (_COM_CONVf32u, -2.0f, (unsigned) -2); + TEST1 (_COM_CONV32sf, -2, -2.0f); + TEST1 (_COM_CONV32uf, 2, 2.0f); + TEST2 (_COM_ADDf, 1.0f, 2.0f, 3.0f); + TEST2 (_COM_SUBf, 3.0f, 2.0f, 1.0f); + TEST2 (_COM_MULf, 2.0f, 3.0f, 6.0f); + TEST2 (_COM_DIVf, 6.0f, 2.0f, 3.0f); + TEST_CMP (_COM_CMPLTf, 1.0f, 2.0f, 1, 0, 0); + TEST_CMP (_COM_CMPGTf, 1.0f, 2.0f, 0, 0, 1); + TEST_CMP (_COM_CMPLEf, 1.0f, 2.0f, 1, 1, 0); + TEST_CMP (_COM_CMPGEf, 1.0f, 2.0f, 0, 1, 1); + TEST_CMP (_COM_CMPEQf, 1.0f, 2.0f, 0, 1, 0); + TEST_CMP (_COM_CMPNEf, 1.0f, 2.0f, 1, 0, 1); + + + TEST2 (_COM_MUL64, 2LL, 4LL, 8LL); + TEST2 (_COM_DIV64s, 6LL, 3LL, 2LL); + TEST2 (_COM_DIV64u, 6ULL, 3ULL, 2ULL); + TEST2 (_COM_SHLL64, 6LL, 3, 48LL); + TEST2 (_COM_SHLR64, 8LL, 2, 2LL); + TEST2 (_COM_SHAR64, -1LL, 2, -1LL); + TEST1 (_COM_CONVf64s, -2.0f, -2LL); + TEST1 (_COM_CONVf64u, 2.0f, 2ULL); + TEST1 (_COM_CONVd64s, -2.0, -2LL); + TEST1 (_COM_CONVd64u, 2.0, 2ULL); + TEST1 (_COM_CONV64sf, -2LL, -2.0f); + TEST1 (_COM_CONV64uf, 2ULL, 2.0f); + TEST1 (_COM_CONV64sd, -2LL, -2.0); + TEST1 (_COM_CONV64ud, 2ULL, 2.0); + TEST2 (_COM_MOD64s, 4LL, 3LL, 1LL); + TEST2 (_COM_MOD64u, 4ULL, 3ULL, 1ULL); + TEST_CMP (_COM_CMPLT64s, 1LL, 2LL, 1, 0, 0); + TEST_CMP (_COM_CMPLT64u, 1ULL, 2ULL, 1, 0, 0); + TEST_CMP (_COM_CMPGT64s, 1LL, 2LL, 0, 0, 1); + TEST_CMP (_COM_CMPGT64u, 1ULL, 2ULL, 0, 0, 1); + TEST_CMP (_COM_CMPLE64s, 1LL, 2LL, 1, 1, 0); + TEST_CMP (_COM_CMPLE64u, 1ULL, 2ULL, 1, 1, 0); + TEST_CMP (_COM_CMPGE64s, 1LL, 2LL, 0, 1, 1); + TEST_CMP (_COM_CMPGE64u, 1ULL, 2ULL, 0, 1, 1); + TEST_CMP (_COM_CMPEQ64, 1LL, 2LL, 0, 1, 0); + TEST_CMP (_COM_CMPNE64, 1LL, 2LL, 1, 0, 1); + + + TEST2 (_COM_ADDd, 1.0, 2.0, 3.0); + TEST2 (_COM_SUBd, 3.0, 2.0, 1.0); + TEST2 (_COM_MULd, 2.0, 3.0, 6.0); + TEST2 (_COM_DIVd, 6.0, 2.0, 3.0); + TEST1 (_COM_CONVd32s, -2.0, -2); + TEST1 (_COM_CONVd32u, -2.0, (unsigned) -2); + TEST1 (_COM_CONV32sd, -2, -2.0); + TEST1 (_COM_CONV32ud, 2, 2.0); + TEST1 (_COM_CONVfd, 2.0f, 2.0); + TEST1 (_COM_CONVdf, 2.0, 2.0f); + TEST1 (_COM_NEGd, -2.0, 2.0); + TEST_CMP (_COM_CMPLTd, 1.0, 2.0, 1, 0, 0); + TEST_CMP (_COM_CMPGTd, 1.0, 2.0, 0, 0, 1); + TEST_CMP (_COM_CMPLEd, 1.0, 2.0, 1, 1, 0); + TEST_CMP (_COM_CMPGEd, 1.0, 2.0, 0, 1, 1); + TEST_CMP (_COM_CMPEQd, 1.0, 2.0, 0, 1, 0); + TEST_CMP (_COM_CMPNEd, 1.0, 2.0, 1, 0, 1); + +#ifdef DEBUG + printf ("Tests finished\n"); +#endif + exit (0); +} diff --git a/gcc/testsuite/gcc.target/rx/rx.exp b/gcc/testsuite/gcc.target/rx/rx.exp new file mode 100644 index 00000000000..aa516e4555d --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/rx.exp @@ -0,0 +1,43 @@ +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't the right target. +if { ![istarget rx-*-*] } then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Find all tests +set tests [lsort [find $srcdir/$subdir *.\[cS\]]] + +# Main loop. +gcc-dg-runtest $tests $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c b/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c new file mode 100644 index 00000000000..26cf5a2b542 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c @@ -0,0 +1,32 @@ +/* { dg-do run { xfail rx-*-* } } */ +/* { dg-skip-if "skipped until patch for generic zero=width bit-field handling is accepted" { rx-*-* } { "*" } { "" } } */ +/* { dg-options "-msim" } */ +/* Note: The -msim abiove is actually there to override the default + options which do not allow the GCC extension of zero-width bitfields. */ + +extern void abort (void); +extern void exit (int); + +struct S_zero +{ + int f1: 4; + int f2: 0; + short f3: 4; +} S_zero; + +struct S_norm +{ + int f1: 4; + short f3: 4; +} S_norm; + + +int +main (void) +{ + if (sizeof (S_zero) != 4 || sizeof (S_norm) != 8) + abort (); + + exit (0); + return 0; +} diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index f8e83ec0988..51a6a397386 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -501,6 +501,7 @@ proc check_profiling_available { test_what } { || [istarget mep-*-elf] || [istarget mips*-*-elf*] || [istarget moxie-*-elf*] + || [istarget rx-*-*] || [istarget xstormy16-*] || [istarget xtensa*-*-elf] || [istarget *-*-rtems*] @@ -686,6 +687,18 @@ proc check_effective_target_hard_float { } { }] } + # This proc is actually checking the availabilty of FPU + # support for doubles, so on the RX we must fail if the + # 64-bit double multilib has been selected. + if { [istarget rx-*-*] } { + return 0 + # return [check_no_compiler_messages hard_float assembly { + #if defined __RX_64_BIT_DOUBLES__ + #error FOO + #endif + # }] + } + # The generic test equates hard_float with "no call for adding doubles". return [check_no_messages_and_pattern hard_float "!\\(call" rtl-expand { double a (double b, double c) { return b + c; } @@ -2505,8 +2518,8 @@ proc check_effective_target_vect_short_mult { } { if { [istarget ia64-*-*] || [istarget spu-*-*] || [istarget i?86-*-*] - || [istarget x86_64-*-*] - || [istarget powerpc*-*-*] + || [istarget x86_64-*-*] + || [istarget powerpc*-*-*] || [check_effective_target_arm32] } { set et_vect_short_mult_saved 1 } @@ -2646,7 +2659,7 @@ proc check_effective_target_section_anchors { } { verbose "check_effective_target_section_anchors: using cached result" 2 } else { set et_section_anchors_saved 0 - if { [istarget powerpc*-*-*] + if { [istarget powerpc*-*-*] || [istarget arm*-*-*] } { set et_section_anchors_saved 1 } diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index e951502ca76..2db5d2901c8 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,14 @@ +2009-10-26 Nick Clifton + + * config.host: Add support for RX target. + * config/rx: New directory. + * config/rx/rx-abi-functions.c: New file. Supplementary + functions for libgcc to support the RX ABI. + * config/rx/rx-abi.h: New file. Supplementary header file for + libgcc RX ABI functions. + * config/rx/t-rx: New file: Makefile fragment for building + libgcc for the RX. + 2009-10-09 Uros Bizjak * config/i386/32/sfp-machine.h (__FP_FRAC_SUB_4): Change operand diff --git a/libgcc/config.host b/libgcc/config.host index 91b70548101..f0861159adc 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -482,6 +482,10 @@ rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*) ;; rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*) ;; +rx-*-elf) + extra_parts="crtbegin.o crtend.o" + tmake_file="rx/t-rx" + ;; s390-*-linux*) tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi" ;; diff --git a/libgcc/config/rx/rx-abi-functions.c b/libgcc/config/rx/rx-abi-functions.c new file mode 100644 index 00000000000..10dd9530d6b --- /dev/null +++ b/libgcc/config/rx/rx-abi-functions.c @@ -0,0 +1,90 @@ +/* RX C ABI functions + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 + along with GCC; see the file COPYING3. If not see + . */ + + +/* The RX C ABI includes the specification of a set of compiler support + functions. Libgcc2 includes some of them, although the names have to + be changed (see rx-abi.h), and the rest are defined here. + + FIXME: Given that FINE_GRAINED_LIBRARIES is defined we ought to consider + compiling this file multiple times with one function per iteration being + compiled. */ + +#ifdef __RX_64BIT_DOUBLES__ + +int _COM_CMPLTd (double a, double b) { return __ltdf2 (a, b) == -1; } +int _COM_CMPGTd (double a, double b) { return __gtdf2 (a, b) == 1; } +int _COM_CMPLEd (double a, double b) { return __ledf2 (a, b) != 1; } +int _COM_CMPGEd (double a, double b) { return __gedf2 (a, b) != -1; } +int _COM_CMPEQd (double a, double b) { return __eqdf2 (a, b) == 0; } +int _COM_CMPNEd (double a, double b) { return __nedf2 (a, b) != 0; } + +int _COM_CMPLTf (double, double) __attribute__ ((weak, alias ("_COM_CMPLTd"))); +int _COM_CMPGTf (double, double) __attribute__ ((weak, alias ("_COM_CMPGTd"))); +int _COM_CMPLEf (double, double) __attribute__ ((weak, alias ("_COM_CMPLEd"))); +int _COM_CMPGEf (double, double) __attribute__ ((weak, alias ("_COM_CMPGEd"))); +int _COM_CMPEQf (double, double) __attribute__ ((weak, alias ("_COM_CMPEQd"))); +int _COM_CMPNEf (double, double) __attribute__ ((weak, alias ("_COM_CMPNEd"))); + +#else /* 32-bit doubles. */ + +double _COM_CONVfd (float a) { return a; } +float _COM_CONVdf (double a) { return a; } + +int _COM_CMPLTd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPLTf"))); +int _COM_CMPGTd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPGTf"))); +int _COM_CMPLEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPLEf"))); +int _COM_CMPGEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPGEf"))); +int _COM_CMPEQd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPEQf"))); +int _COM_CMPNEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPNEf"))); + +signed long long _COM_CONVd64s (double a) { return (signed long long) a; } +unsigned long long _COM_CONVd64u (double a) { return (unsigned long long) a; } + +int _COM_CMPLTf (float a, float b) { return __ltsf2 (a, b) == -1; } +int _COM_CMPGTf (float a, float b) { return __gtsf2 (a, b) == 1; } +int _COM_CMPLEf (float a, float b) { return __lesf2 (a, b) != 1; } +int _COM_CMPGEf (float a, float b) { return __gesf2 (a, b) != -1; } +int _COM_CMPEQf (float a, float b) { return __eqsf2 (a, b) == 0; } +int _COM_CMPNEf (float a, float b) { return __nesf2 (a, b) != 0; } + +#endif /* 64-bit vs 32-bit doubles. */ + +double _COM_CONV64sd (signed long long a) { return (double) a; } +double _COM_CONV64ud (unsigned long long a) { return (double) a; } + +extern int __cmpdi2 (long long, long long); +extern int __ucmpdi2 (long long, long long); + +int _COM_CMPLT64s (long long a, long long b) { return __cmpdi2 (a, b) == 0; } +int _COM_CMPLT64u (long long a, long long b) { return __ucmpdi2 (a, b) == 0; } +int _COM_CMPGT64s (long long a, long long b) { return __cmpdi2 (a, b) == 2; } +int _COM_CMPGT64u (long long a, long long b) { return __ucmpdi2 (a, b) == 2; } +int _COM_CMPLE64s (long long a, long long b) { return __cmpdi2 (a, b) != 2; } +int _COM_CMPLE64u (long long a, long long b) { return __ucmpdi2 (a, b) != 2; } +int _COM_CMPGE64s (long long a, long long b) { return __cmpdi2 (a, b) != 0; } +int _COM_CMPGE64u (long long a, long long b) { return __ucmpdi2 (a, b) != 0; } +int _COM_CMPEQ64 (long long a, long long b) { return __cmpdi2 (a, b) == 1; } +int _COM_CMPNE64 (long long a, long long b) { return __cmpdi2 (a, b) != 1; } + diff --git a/libgcc/config/rx/rx-abi.h b/libgcc/config/rx/rx-abi.h new file mode 100644 index 00000000000..8a0bbdcd82c --- /dev/null +++ b/libgcc/config/rx/rx-abi.h @@ -0,0 +1,235 @@ +/* Header file for RX ABI versions of libgcc functions. + Copyright (C) 2009 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 + along with GCC; see the file COPYING3. If not see + . */ + +/* Make __COM_ an alias for __. */ +#define RENAME_LIBRARY(GCC_NAME, RX_NAME) \ + __asm__ (".globl\t__COM_" #RX_NAME "\n" \ + ".set\t__COM_" #RX_NAME ", ___" #GCC_NAME "\n"); + + +/* The long-long aliases... */ + +#ifdef L_muldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, MUL64) +#endif + +#ifdef L_divdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdi3, DIV64s) +#endif + +#ifdef L_udivdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivdi3, DIV64u) +#endif + +#ifdef L_ashldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashldi3, SHLL64) +#endif + +#ifdef L_lshrdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (lshrdi3, SHLR64) +#endif + +#ifdef L_ashrdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashrdi3, SHAR64) +#endif + +#ifdef L_fixsfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, CONVf64s) +#endif + +#ifdef L_fixunssfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, CONVf64u) +#endif + +#ifdef L_floatdisf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64sf) +#endif + +#ifdef L_floatundisf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundisf, CONV64uf) +#endif + +#ifdef L_moddi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (moddi3, MOD64s) +#endif + +#ifdef L_umoddi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (umoddi3, MOD64u) +#endif + + +#ifdef L_si_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatsisf, CONV32sf) +#endif + +#ifdef L_usi_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatunsisf, CONV32uf) +#endif + + + +#ifdef __RX_64BIT_DOUBLES__ + +/* Float (32-bit) aliases... */ + +#ifdef L_sf_to_si +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfsi, CONVf32s) +#endif + +#ifdef L_fixunssfsi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfsi, CONVf32u) +#endif + +#ifdef L_addsub_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (addsf3, ADDf) \ + RENAME_LIBRARY (subsf3, SUBf) +#endif + +#ifdef L_mul_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (mulsf3, MULf) +#endif + +#ifdef L_div_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divsf3, DIVf) +#endif + +/* Double (64-bit) aliases... */ + +#ifdef L_addsub_df +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (adddf3, ADDd) \ + RENAME_LIBRARY (subdf3, SUBd) +#endif + +#ifdef L_mul_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldf3, MULd) +#endif + +#ifdef L_div_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdf3, DIVd) +#endif + +#ifdef L_fixdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfdi, CONVd64s) +#endif + +#ifdef L_fixunsdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfdi, CONVd64u) +#endif + +#ifdef L_floatdidf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64sd) +#endif + +#ifdef L_floatundidf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64ud) +#endif + +#ifdef L_df_to_si +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfsi, CONVd32s) +#endif + +#ifdef L_fixunsdfsi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfsi, CONVd32u) +#endif + +#ifdef L_si_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatsidf, CONV32sd) +#endif + +#ifdef L_usi_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatunsidf, CONV32ud) +#endif + +#ifdef L_sf_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (extendsfdf2, CONVfd) +#endif + +#ifdef L_df_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (truncdfsf2, CONVdf) +#endif + +#ifdef L_negate_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (negdf2, NEGd) +#endif + +/* The 64-bit comparison functions do not have aliases because libgcc2 + does not provide them. Instead they have to be supplied in + rx-abi-functions.c. */ + + +#else /* 32-bit doubles. */ + + +#ifdef L_addsub_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (addsf3, ADDd) \ + RENAME_LIBRARY (subsf3, SUBd) \ + RENAME_LIBRARY (addsf3, ADDf) \ + RENAME_LIBRARY (subsf3, SUBf) +#endif + +#ifdef L_mul_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (mulsf3, MULd) \ + RENAME_LIBRARY (mulsf3, MULf) +#endif + +#ifdef L_div_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (divsf3, DIVd) \ + RENAME_LIBRARY (divsf3, DIVf) +#endif + +#ifdef L_sf_to_si +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (fixsfsi, CONVd32s) \ + RENAME_LIBRARY (fixsfsi, CONVf32s) +#endif + +#ifdef L_fixunssfsi +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (fixunssfsi, CONVd32u) \ + RENAME_LIBRARY (fixunssfsi, CONVf32u) +#endif + +#ifdef L_si_to_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (floatsisf, CONV32sd) \ + RENAME_LIBRARY (floatsisf, CONV32sf) +#endif + +#ifdef L_usi_to_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (floatunsisf, CONV32ud) \ + RENAME_LIBRARY (floatunsisf, CONV32uf) +#endif + +#ifdef L_negate_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (negsf2, NEGd) +#endif + +#endif /* 64-bit vs 32-bit doubles. */ diff --git a/libgcc/config/rx/t-rx b/libgcc/config/rx/t-rx new file mode 100644 index 00000000000..1e66af0c8d3 --- /dev/null +++ b/libgcc/config/rx/t-rx @@ -0,0 +1,44 @@ +# Makefile fragment for building LIBGCC for the Renesas RX target. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 +# . + + +# Add functions required by the RX ABI which are not part of +# the normal libgcc sources: + +LIB2ADD = $(srcdir)/config/rx/rx-abi-functions.c + + +# We need special handling of the floating point conversion +# routines, to allow for the varying size of a double: + +FPBIT = fp-bit.c +$(gcc_objdir)/fp-bit.c: $(gcc_srcdir)/config/fp-bit.c + echo '#define FLOAT' > $@ + echo '#ifndef __RX_64BIT_DOUBLES__' >> $@ + echo '#define DF SF' >> $@ + echo '#define FLOAT_ONLY' >> $@ + echo '#endif' >> $@ + cat $(gcc_srcdir)/config/fp-bit.c >> $@ + +DPBIT = dp-bit.c +$(gcc_objdir)/dp-bit.c: $(gcc_srcdir)/config/fp-bit.c + echo '#ifdef __RX_64BIT_DOUBLES__' > $@ + cat $(gcc_srcdir)/config/fp-bit.c >> $@ + echo '#endif' >> $@