diff options
author | Paul Woegerer <paul.woegerer@nsc.com> | 2005-07-22 09:49:48 +0000 |
---|---|---|
committer | Paul Woegerer <woepaul@gcc.gnu.org> | 2005-07-22 09:49:48 +0000 |
commit | db8697336fbb1f6665adbfa24a72a4dbbd549398 (patch) | |
tree | a33f7560f0dde97a44c7a0bdcb0fa5fd23a44569 /gcc/config | |
parent | 0fb6f88ac7ab49796b45268f6df19371bfa96416 (diff) | |
download | gcc-db8697336fbb1f6665adbfa24a72a4dbbd549398.zip gcc-db8697336fbb1f6665adbfa24a72a4dbbd549398.tar.gz gcc-db8697336fbb1f6665adbfa24a72a4dbbd549398.tar.bz2 |
config.gcc: Add crx-elf support.
* config.gcc: Add crx-elf support.
* doc/contrib.texi: Mention crx.
* doc/extend.texi: Document crx extensions.
* doc/install.texi: Document crx install.
* doc/invoke.texi: Document crx options.
* doc/md.texi: Document crx constraints.
* config/crx/crx-protos.h: New file.
* config/crx/crx.c: New file.
* config/crx/crx.h: New file.
* config/crx/crx.md: New file.
* config/crx/crx.opt: New file.
* config/crx/t-crx: New file.
From-SVN: r102278
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/crx/crx-protos.h | 75 | ||||
-rw-r--r-- | gcc/config/crx/crx.c | 1485 | ||||
-rw-r--r-- | gcc/config/crx/crx.h | 533 | ||||
-rw-r--r-- | gcc/config/crx/crx.md | 920 | ||||
-rw-r--r-- | gcc/config/crx/crx.opt | 28 | ||||
-rw-r--r-- | gcc/config/crx/t-crx | 19 |
6 files changed, 3060 insertions, 0 deletions
diff --git a/gcc/config/crx/crx-protos.h b/gcc/config/crx/crx-protos.h new file mode 100644 index 0000000..ebee79bd --- /dev/null +++ b/gcc/config/crx/crx-protos.h @@ -0,0 +1,75 @@ +/* Prototypes for exported functions defined in crx.c + Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef GCC_CRX_PROTOS_H +#define GCC_CRX_PROTOS_H + + +/* Register usage. */ +extern enum reg_class crx_regno_reg_class (int); +extern int crx_hard_regno_mode_ok (int regno, enum machine_mode); +#ifdef RTX_CODE +extern enum reg_class crx_secondary_reload_class (enum reg_class, enum machine_mode, rtx); +#endif /* RTX_CODE */ + +/* Passing function arguments. */ +extern int crx_function_arg_regno_p (int); +#ifdef TREE_CODE +extern void crx_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); +#ifdef RTX_CODE +extern void crx_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx); +extern rtx crx_function_arg (struct cumulative_args *, enum machine_mode, tree, int); +#endif /* RTX_CODE */ +#endif /* TREE_CODE */ + +#ifdef RTX_CODE +/* Addressing Modes. */ +extern int crx_legitimate_address_p (enum machine_mode, rtx, int); + +extern int crx_const_double_ok (rtx op); + +/* Instruction output. */ +extern void crx_print_operand (FILE *, rtx, int); +extern void crx_print_operand_address (FILE *, rtx); + +/* Misc functions called from crx.md. */ +extern rtx crx_expand_compare (enum rtx_code, enum machine_mode); +extern void crx_expand_branch (enum rtx_code, rtx); +extern void crx_expand_scond (enum rtx_code, rtx); + +extern void crx_expand_movmem_single (rtx, rtx, rtx, rtx, rtx, unsigned HOST_WIDE_INT *); +extern int crx_expand_movmem (rtx, rtx, rtx, rtx); +#endif /* RTX_CODE */ + +/* Routines to compute costs. */ +extern int crx_memory_move_cost (enum machine_mode, enum reg_class, int); + +/* Prologue/Epilogue functions. */ +extern int crx_initial_elimination_offset (int, int); +extern char *crx_prepare_push_pop_string (int); +extern void crx_expand_prologue (void); +extern void crx_expand_epilogue (void); + + +/* Handling the "interrupt" attribute */ +extern int crx_interrupt_function_p (void); + +#endif /* GCC_CRX_PROTOS_H */ diff --git a/gcc/config/crx/crx.c b/gcc/config/crx/crx.c new file mode 100644 index 0000000..28d88ff --- /dev/null +++ b/gcc/config/crx/crx.c @@ -0,0 +1,1485 @@ +/* Output routines for GCC for CRX. + Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/*****************************************************************************/ +/* HEADER INCLUDES */ +/*****************************************************************************/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "tm_p.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-codes.h" +#include "insn-attr.h" +#include "flags.h" +#include "except.h" +#include "function.h" +#include "recog.h" +#include "expr.h" +#include "optabs.h" +#include "toplev.h" +#include "basic-block.h" +#include "target.h" +#include "target-def.h" + +/*****************************************************************************/ +/* DEFINITIONS */ +/*****************************************************************************/ + +/* Maximum number of register used for passing parameters. */ +#define MAX_REG_FOR_PASSING_ARGS 5 + +/* Minimum number register used for passing parameters. */ +#define MIN_REG_FOR_PASSING_ARGS 2 + +/* The maximum count of words supported in the assembly of the architecture in + * a push/pop instruction. */ +#define MAX_COUNT 8 + +/* Predicate is true if the current function is a 'noreturn' function, i.e. it + * is qualified as volatile. */ +#define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl)) + +/* The following 3 macros are used in crx_legitimate_address_p() */ + +/* Returns 1 if the scale factor of an index address is valid. */ +#define SCALE_FOR_INDEX_P(X) \ + (GET_CODE (X) == CONST_INT \ + && (INTVAL (X) == 1 || INTVAL (X) == 2 \ + || INTVAL(X) == 4 || INTVAL (X) == 8)) + +/* Nonzero if the rtx X is a signed const int of n bits */ +#define RTX_SIGNED_INT_FITS_N_BITS(X,n) \ + ((GET_CODE(X) == CONST_INT \ + && SIGNED_INT_FITS_N_BITS(INTVAL(X),n)) ? 1 : 0) + +/* Nonzero if the rtx X is a unsigned const int of n bits */ +#define RTX_UNSIGNED_INT_FITS_N_BITS(X,n) \ + ((GET_CODE(X) == CONST_INT \ + && UNSIGNED_INT_FITS_N_BITS(INTVAL(X),n)) ? 1 : 0) + + +/* Register relative legal displacement */ +#define CRX_REGISTER_RELATIVE_DISP_P(X) \ + (CONSTANT_ADDRESS_P(X) \ + && (GET_CODE (X) != CONST_INT \ + || RTX_SIGNED_INT_FITS_N_BITS(X, GET_MODE_BITSIZE (Pmode)))) + +/*****************************************************************************/ +/* STATIC VARIABLES */ +/*****************************************************************************/ + +/* Non-zero if the last param processed is passed in a register. */ +static int last_parm_in_reg; + +/* Will hold the number of the last register the prologue saves, -1 if no + * register is saved. */ +static int last_reg_to_save; + +/* Each object in the array is a register number. Mark 1 for registers that + * need to be saved. */ +static int save_regs[FIRST_PSEUDO_REGISTER]; + +/* Number of bytes saved on the stack for non-scratch registers */ +static int sum_regs = 0; + +/* Number of bytes saved on the stack for local variables. */ +static int local_vars_size; + +/* The sum of 2 sizes: locals vars and padding byte for saving the registers. + * Used in expand_prologue() and expand_epilogue(). */ +static int size_for_adjusting_sp; + +/* In case of a POST_INC or POST_DEC memory reference, we must report the mode + * of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */ +static enum machine_mode output_memory_reference_mode; + +/*****************************************************************************/ +/* GLOBAL VARIABLES */ +/*****************************************************************************/ + +/* Table of machine attributes. */ +const struct attribute_spec crx_attribute_table[]; + +/* Test and compare insns use these globals to generate branch insns. */ +rtx crx_compare_op0 = NULL_RTX; +rtx crx_compare_op1 = NULL_RTX; + +/*****************************************************************************/ +/* TARGETM FUNCTION PROTOTYPES */ +/*****************************************************************************/ + +static bool crx_fixed_condition_code_regs (unsigned int *, unsigned int *); +static rtx crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED); +static bool crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED); + +/*****************************************************************************/ +/* STACK LAYOUT AND CALLING CONVENTIONS */ +/*****************************************************************************/ + +#undef TARGET_FIXED_CONDITION_CODE_REGS +#define TARGET_FIXED_CONDITION_CODE_REGS crx_fixed_condition_code_regs + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX crx_struct_value_rtx + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY crx_return_in_memory + +/*****************************************************************************/ +/* TARGET-SPECIFIC USES OF `__attribute__' */ +/*****************************************************************************/ + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE crx_attribute_table + +const struct attribute_spec crx_attribute_table[] = { + /* ISRs have special prologue and epilogue requirements. */ + {"interrupt", 0, 0, false, true, true, NULL}, + {NULL, 0, 0, false, false, false, NULL} +}; + + +/* Initialize 'targetm' variable which contains pointers to functions and data + * relating to the target machine. */ + +struct gcc_target targetm = TARGET_INITIALIZER; + + +/*****************************************************************************/ +/* TARGET HOOK IMPLEMENTATIONS */ +/*****************************************************************************/ + +/* Return the fixed registers used for condition codes. */ + +static bool +crx_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) +{ + *p1 = CC_REGNUM; + *p2 = INVALID_REGNUM; + return true; +} + +/* Implements hook TARGET_STRUCT_VALUE_RTX. */ + +static rtx +crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (Pmode, CRX_STRUCT_VALUE_REGNUM); +} + +/* Implements hook TARGET_RETURN_IN_MEMORY. */ + +static bool +crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) +{ + if (TYPE_MODE (type) == BLKmode) + { + HOST_WIDE_INT size = int_size_in_bytes (type); + return (size == -1 || size > 8); + } + else + return false; +} + + +/*****************************************************************************/ +/* MACRO IMPLEMENTATIONS */ +/*****************************************************************************/ + +/* STACK LAYOUT AND CALLING CONVENTIONS ROUTINES */ +/* --------------------------------------------- */ + +/* Return nonzero if the current function being compiled is an interrupt + * function as specified by the "interrupt" attribute. */ + +int +crx_interrupt_function_p (void) +{ + tree attributes; + + attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + return lookup_attribute ("interrupt", attributes) != NULL_TREE; +} + +/* Compute values for the array save_regs and the variable sum_regs. The index + * of save_regs is numbers of register, each will get 1 if we need to save it + * in the current function, 0 if not. sum_regs is the total sum of the + * registers being saved. */ + +static void +crx_compute_save_regs (void) +{ + unsigned int regno; + + /* initialize here so in case the function is no-return it will be -1. */ + last_reg_to_save = -1; + + /* No need to save any registers if the function never returns. */ + if (FUNC_IS_NORETURN_P (current_function_decl)) + return; + + /* Initialize the number of bytes to be saved. */ + sum_regs = 0; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (fixed_regs[regno]) + { + save_regs[regno] = 0; + continue; + } + + /* If this reg is used and not call-used (except RA), save it. */ + if (crx_interrupt_function_p()) + { + if (!current_function_is_leaf && call_used_regs[regno]) + /* this is a volatile reg in a non-leaf interrupt routine - save it + * for the sake of its sons. */ + save_regs[regno] = 1; + + else if (regs_ever_live[regno]) + /* This reg is used - save it. */ + save_regs[regno] = 1; + else + /* This reg is not used, and is not a volatile - don't save. */ + save_regs[regno] = 0; + } + else + { + /* If this reg is used and not call-used (except RA), save it. */ + if (regs_ever_live[regno] + && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM)) + save_regs[regno] = 1; + else + save_regs[regno] = 0; + } + } + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (save_regs[regno] == 1) + { + last_reg_to_save = regno; + sum_regs += UNITS_PER_WORD; + } +} + +/* Compute the size of the local area and the size to be adjusted by the + * prologue and epilogue. */ + +static void +crx_compute_frame (void) +{ + /* For aligning the local variables. */ + int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT; + int padding_locals; + + /* Padding needed for each element of the frame. */ + local_vars_size = get_frame_size (); + + /* Align to the stack alignment. */ + padding_locals = local_vars_size % stack_alignment; + if (padding_locals) + padding_locals = stack_alignment - padding_locals; + + local_vars_size += padding_locals; + + size_for_adjusting_sp = local_vars_size + (ACCUMULATE_OUTGOING_ARGS ? + current_function_outgoing_args_size : 0); +} + +/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */ + +int +crx_initial_elimination_offset (int from, int to) +{ + /* Compute this since we need to use sum_regs. */ + crx_compute_save_regs (); + + /* Compute this since we need to use local_vars_size. */ + crx_compute_frame (); + + if ((from) == FRAME_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM) + return (ACCUMULATE_OUTGOING_ARGS ? + current_function_outgoing_args_size : 0); + else if ((from) == ARG_POINTER_REGNUM && (to) == FRAME_POINTER_REGNUM) + return (sum_regs + local_vars_size); + else if ((from) == ARG_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM) + return (sum_regs + local_vars_size + + (ACCUMULATE_OUTGOING_ARGS ? + current_function_outgoing_args_size : 0)); + else + abort (); +} + +/* REGISTER USAGE */ +/* -------------- */ + +/* Return the class number of the smallest class containing reg number REGNO. + * This could be a conditional expression or could index an array. */ + +enum reg_class +crx_regno_reg_class (int regno) +{ + if (regno >= 0 && regno < SP_REGNUM) + return NOSP_REGS; + + if (regno == SP_REGNUM) return GENERAL_REGS; + + if (regno == LO_REGNUM) return LO_REGS; + if (regno == HI_REGNUM) return HI_REGS; + + return NO_REGS; +} + +/* Transfer between HILO_REGS and memory via secondary reloading. */ + +enum reg_class +crx_secondary_reload_class (enum reg_class class, + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x ATTRIBUTE_UNUSED) +{ + if (reg_classes_intersect_p (class, HILO_REGS) + && true_regnum (x) == -1) + return GENERAL_REGS; + + return NO_REGS; +} + +/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */ + +int +crx_hard_regno_mode_ok (int regno, enum machine_mode mode) +{ + /* CC can only hold CCmode values. */ + if (regno == CC_REGNUM) + return GET_MODE_CLASS (mode) == MODE_CC; + if (GET_MODE_CLASS (mode) == MODE_CC) + return 0; + /* HILO registers can only hold SImode and DImode */ + if (HILO_REGNO_P (regno)) + return mode == SImode || mode == DImode; + return 1; +} + +/* PASSING FUNCTION ARGUMENTS */ +/* -------------------------- */ + +/* If enough param regs are available for passing the param of type TYPE return + * the number of registers needed else 0. */ + +static int +enough_regs_for_param (CUMULATIVE_ARGS * cum, tree type, + enum machine_mode mode) +{ + int type_size; + int remaining_size; + + if (mode != BLKmode) + type_size = GET_MODE_BITSIZE (mode); + else + type_size = int_size_in_bytes (type) * BITS_PER_UNIT; + + remaining_size = + BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS - + (MIN_REG_FOR_PASSING_ARGS + cum->ints) + 1); + + /* Any variable which is too big to pass in two registers, will pass on + * stack. */ + if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD)) + return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD; + + return 0; +} + +/* Implements the macro FUNCTION_ARG defined in crx.h. */ + +rtx +crx_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, + int named ATTRIBUTE_UNUSED) +{ + last_parm_in_reg = 0; + + /* Function_arg() is called with this type just after all the args have had + * their registers assigned. The rtx that function_arg returns from this type + * is supposed to pass to 'gen_call' but currently it is not implemented (see + * macro GEN_CALL). */ + if (type == void_type_node) + return NULL_RTX; + + if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0)) + return NULL_RTX; + + if (mode == BLKmode) + { + /* Enable structures that need padding bytes at the end to pass to a + * function in registers. */ + if (enough_regs_for_param (cum, type, mode) != 0) + { + last_parm_in_reg = 1; + return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints); + } + } + + if (MIN_REG_FOR_PASSING_ARGS + cum->ints > MAX_REG_FOR_PASSING_ARGS) + return NULL_RTX; + else + { + if (enough_regs_for_param (cum, type, mode) != 0) + { + last_parm_in_reg = 1; + return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints); + } + } + + return NULL_RTX; +} + +/* Implements the macro INIT_CUMULATIVE_ARGS defined in crx.h. */ + +void +crx_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, + rtx libfunc ATTRIBUTE_UNUSED) +{ + tree param, next_param; + + cum->ints = 0; + + /* Determine if this function has variable arguments. This is indicated by + * the last argument being 'void_type_mode' if there are no variable + * arguments. Change here for a different vararg. */ + for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; + param != (tree) 0; param = next_param) + { + next_param = TREE_CHAIN (param); + if (next_param == (tree) 0 && TREE_VALUE (param) != void_type_node) + { + cum->ints = -1; + return; + } + } +} + +/* Implements the macro FUNCTION_ARG_ADVANCE defined in crx.h. */ + +void +crx_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, + tree type, int named ATTRIBUTE_UNUSED) +{ + /* l holds the number of registers required */ + int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD; + + /* If the parameter isn't passed on a register don't advance cum. */ + if (!last_parm_in_reg) + return; + + if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0)) + return; + + if (mode == SImode || mode == HImode || mode == QImode || mode == DImode) + { + if (l <= 1) + cum->ints += 1; + else + cum->ints += l; + } + else if (mode == SFmode || mode == DFmode) + cum->ints += l; + else if ((mode) == BLKmode) + { + if ((l = enough_regs_for_param (cum, type, mode)) != 0) + cum->ints += l; + } + +} + +/* Implements the macro FUNCTION_ARG_REGNO_P defined in crx.h. Return non-zero + * if N is a register used for passing parameters. */ + +int +crx_function_arg_regno_p (int n) +{ + return (n <= MAX_REG_FOR_PASSING_ARGS && n >= MIN_REG_FOR_PASSING_ARGS); +} + +/* ADDRESSING MODES */ +/* ---------------- */ + +/* Implements the macro GO_IF_LEGITIMATE_ADDRESS defined in crx.h. + * The legitimate addressing modes for the CRX are: + * + * Relocations --> const | symbol_ref | label_ref + * Absolute address --> 32 bit absolute + * Post increment --> reg + 12 bit disp. + * Post modify --> reg + 12 bit disp. + * Register relative --> reg | 32 bit disp. + reg | 4 bit + reg + * Scaled index --> reg + reg | 22 bit disp. + reg + reg | + * 22 disp. + reg + reg + (2 | 4 | 8) */ + +int +crx_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x, int strict) +{ + /* Absolute address */ + if (RTX_UNSIGNED_INT_FITS_N_BITS(x, GET_MODE_BITSIZE(Pmode))) + return 1; + + /* Label */ + if (GET_CODE (x) == CONST + || GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == LABEL_REF + || (GET_CODE (x) == REG && (strict ? STRICT_REG_OK_FOR_BASE_P (x) + : NONSTRICT_REG_OK_FOR_BASE_P (x)))) + return 1; + + /* Post increment - The first argument is a register and the second is + * 12-bit long int. */ + if (GET_CODE (x) == POST_INC || GET_CODE (x) == POST_DEC) + { + /* Don't allow modes to be referenced through post autoinc/dec that + * cannot be loaded/stored with a single instruction */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) + return 0; + + if((GET_CODE (XEXP (x, 0)) == REG) + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)) + : NONSTRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)))) + return 1; + } + + /* Post modify */ + if (GET_CODE (x) == POST_MODIFY) + { + /* Don't allow modes to be referenced through post autoinc/dec that + * cannot be loaded/stored with a single instruction */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) + return 0; + + if (!(GET_CODE (XEXP (x, 0)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)) + : NONSTRICT_REG_OK_FOR_BASE_P (XEXP (x, 0))) + && RTX_SIGNED_INT_FITS_N_BITS(XEXP (XEXP (x, 1), 1), 12))) + return 0; + + if(!(GET_CODE (XEXP (x, 1)) == PLUS || GET_CODE (XEXP (x, 1)) == MINUS)) + return 0; + + if(!rtx_equal_p(XEXP (x, 0), XEXP (XEXP (x, 1), 0))) + return 0; + + return 1; + } + + if (GET_CODE (x) == PLUS) + { + /* Register relative */ + if (GET_CODE (XEXP (x, 0)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)) + : NONSTRICT_REG_OK_FOR_BASE_P (XEXP (x, 0))) + && (CRX_REGISTER_RELATIVE_DISP_P (XEXP (x, 1)))) + return 1; + + /* Scaled index with factor 1 */ + /* 1a. reg + reg */ + if (GET_CODE (XEXP (x, 0)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 0)) + : REG_OK_FOR_INDEX_P (XEXP (x, 0))) + && GET_CODE (XEXP (x, 1)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 1)) + : REG_OK_FOR_INDEXED_BASE_P (XEXP (x, 1)))) + return 1; + + /* Scaled index with different factor */ + /* 1b. reg * scale + reg */ + if (GET_CODE (XEXP (x, 0)) == MULT + && GET_CODE (XEXP( XEXP (x, 0), 0)) == REG + && (strict ? STRICT_REG_OK_FOR_INDEX_P (XEXP( XEXP (x, 0), 0)) + : NONSTRICT_REG_OK_FOR_INDEX_P (XEXP( XEXP (x, 0), 0))) + && (SCALE_FOR_INDEX_P (XEXP( XEXP (x, 0), 1))) + && GET_CODE (XEXP (x, 1)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (x, 1)) + : NONSTRICT_REG_OK_FOR_BASE_P (XEXP (x, 1)))) + return 1; + + if (GET_CODE (XEXP (x, 0)) == PLUS) + { + /* 2. reg + reg + 22 bit disp. */ + if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (XEXP (x, 0), 0)) + : REG_OK_FOR_INDEX_P (XEXP (XEXP (x, 0), 0))) + && GET_CODE (XEXP (XEXP (x, 0), 1)) == REG + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (XEXP (x, 0), 1)) + : REG_OK_FOR_INDEXED_BASE_P (XEXP (XEXP (x, 0), 1))) + && (RTX_SIGNED_INT_FITS_N_BITS(XEXP (x, 1), 22))) + return 1; + + /* 3. reg * scale + reg + 22 bit disp. */ + if ((GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT) + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == REG) + && (strict ? + STRICT_REG_OK_FOR_BASE_P (XEXP (XEXP (XEXP (x, 0), 0), 0)) + : + REG_OK_FOR_INDEXED_BASE_P (XEXP (XEXP (XEXP (x, 0), 0), 0))) + && (SCALE_FOR_INDEX_P (XEXP (XEXP (XEXP (x, 0), 0), 1))) + && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG) + && (strict ? STRICT_REG_OK_FOR_BASE_P (XEXP (XEXP (x, 0), 1)) : + REG_OK_FOR_INDEX_P (XEXP (XEXP (x, 0), 1))) + && (RTX_SIGNED_INT_FITS_N_BITS(XEXP (x, 1), 22))) + return 1; + } + } + + return 0; +} + +/* ROUTINES TO COMPUTE COSTS */ +/* ------------------------- */ + +/* Return the cost of moving data of mode MODE between a register of class + * CLASS and memory; IN is zero if the value is to be written to memory, + * non-zero if it is to be read in. This cost is relative to those in + * REGISTER_MOVE_COST. */ + +int +crx_memory_move_cost (enum machine_mode mode, + enum reg_class class ATTRIBUTE_UNUSED, + int in ATTRIBUTE_UNUSED) +{ + /* One LD or ST takes twice the time of a simple reg-reg move */ + if (reg_classes_intersect_p (class, GENERAL_REGS)) + { + /* printf("GENERAL_REGS LD/ST = %d\n", 4 * HARD_REGNO_NREGS (0, mode));*/ + return 4 * HARD_REGNO_NREGS (0, mode); + } + else if (reg_classes_intersect_p (class, HILO_REGS)) + { + /* HILO to memory and vice versa */ + /* printf("HILO_REGS %s = %d\n",in ? "LD" : "ST", + (REGISTER_MOVE_COST(mode, + in ? GENERAL_REGS : HILO_REGS, + in ? HILO_REGS : GENERAL_REGS) + 4) + * HARD_REGNO_NREGS (0, mode)); */ + return (REGISTER_MOVE_COST(mode, + in ? GENERAL_REGS : HILO_REGS, + in ? HILO_REGS : GENERAL_REGS) + 4) + * HARD_REGNO_NREGS (0, mode); + } + else /* default (like in i386) */ + { + /* printf("ANYREGS = 100\n"); */ + return 100; + } +} + +/* INSTRUCTION OUTPUT */ +/* ------------------ */ + +/* Print to FILE addr expression of the form post_inc/dec (in this case + * post_offset is zero) or post_inc/dec + post_offset */ + +static void +print_post_operand_address (FILE * file, rtx addr, int post_offset) +{ + int displmnt; + + if (GET_CODE (addr) == POST_MODIFY) + { + displmnt = INTVAL(XEXP( XEXP (addr, 1), 1)); + if (GET_CODE (XEXP (addr, 1)) == MINUS) displmnt = (-1) * displmnt; + } + else + { + displmnt = GET_MODE_SIZE (output_memory_reference_mode); + /* Make the displacement negative for POST_DEC */ + if (GET_CODE (addr) == POST_DEC) displmnt = (-1) * displmnt; + } + + if (GET_CODE (XEXP (addr, 0)) != REG) + abort (); + + displmnt += post_offset; + + fprintf (file, "%d(%s)+", displmnt, reg_names[REGNO (XEXP (addr, 0))]); +} + +/* Check if constant rtx contains label_ref. */ + +static rtx +const_and_contains_label_ref (rtx x) +{ + if (!x) + return NULL_RTX; + + if (GET_CODE (x) == LABEL_REF) + return x; + + /* Check within enclosing const. */ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == LABEL_REF) + return XEXP (x, 0); + + return NULL_RTX; +} + +/* Check if rtx contains symbol_ref. */ + +static rtx +const_and_contains_symbol_ref (rtx x) +{ + if (!x) + return NULL_RTX; + + if (GET_CODE (x) == SYMBOL_REF) + return x; + + /* Check within enclosing const. */ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + return XEXP (x, 0); + + return NULL_RTX; +} + +/* Check if a const_double is ok for crx store-immediate instructions */ + +int +crx_const_double_ok (rtx op) +{ + if (GET_MODE (op) == DFmode) + { + REAL_VALUE_TYPE r; + long l[2]; + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + REAL_VALUE_TO_TARGET_DOUBLE (r, l); + return (UNSIGNED_INT_FITS_N_BITS(l[0], 4) && + UNSIGNED_INT_FITS_N_BITS(l[1], 4)) ? 1 : 0; + } + + if (GET_MODE (op) == SFmode) + { + REAL_VALUE_TYPE r; + long l; + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + REAL_VALUE_TO_TARGET_SINGLE (r, l); + return UNSIGNED_INT_FITS_N_BITS(l, 4) ? 1 : 0; + } + + return (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4) && + UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4)) ? 1 : 0; +} + +/* Implements the macro PRINT_OPERAND defined in crx.h. */ + +void +crx_print_operand (FILE * file, rtx x, int code) +{ + switch (code) + { + case 'p' : + if (GET_CODE (x) == REG) { + if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode) + { + int regno = REGNO (x); + if (regno + 1 >= SP_REGNUM) abort (); + fprintf (file, "{%s, %s}", reg_names[regno], reg_names[regno + 1]); + return; + } + else + { + if (REGNO (x) >= SP_REGNUM) abort (); + fprintf (file, "%s", reg_names[REGNO (x)]); + return; + } + } + + case 'd' : + { + const char *crx_cmp_str; + switch (GET_CODE (x)) + { /* MD: compare(reg, reg or imm) but CRX: cmp(reg or imm, reg) + * -> swap all non symmetric ops */ + case EQ : crx_cmp_str = "eq"; break; + case NE : crx_cmp_str = "ne"; break; + case GT : crx_cmp_str = "lt"; break; + case GTU : crx_cmp_str = "lo"; break; + case LT : crx_cmp_str = "gt"; break; + case LTU : crx_cmp_str = "hi"; break; + case GE : crx_cmp_str = "le"; break; + case GEU : crx_cmp_str = "ls"; break; + case LE : crx_cmp_str = "ge"; break; + case LEU : crx_cmp_str = "hs"; break; + default : abort (); + } + fprintf (file, "%s", crx_cmp_str); + return; + } + + case 'H': + /* Print high part of a double precision value. */ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + if (GET_MODE (x) == SFmode) abort (); + if (GET_MODE (x) == DFmode) + { + /* High part of a DF const. */ + REAL_VALUE_TYPE r; + long l[2]; + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_TARGET_DOUBLE (r, l); + + fprintf (file, "$0x%lx", l[1]); + return; + } + + /* -- Fallthrough to handle DI consts -- */ + + case CONST_INT: + { + rtx high, low; + split_double (x, &low, &high); + putc ('$', file); + output_addr_const (file, high); + return; + } + + case REG: + if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort (); + fprintf (file, "%s", reg_names[REGNO (x) + 1]); + return; + + case MEM: + /* Adjust memory address to high part. */ + { + rtx adj_mem = x; + adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4); + + output_memory_reference_mode = GET_MODE (adj_mem); + output_address (XEXP (adj_mem, 0)); + return; + } + + default: + abort (); + } + + case 'L': + /* Print low part of a double precision value. */ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + if (GET_MODE (x) == SFmode) abort (); + if (GET_MODE (x) == DFmode) + { + /* High part of a DF const. */ + REAL_VALUE_TYPE r; + long l[2]; + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_TARGET_DOUBLE (r, l); + + fprintf (file, "$0x%lx", l[0]); + return; + } + + /* -- Fallthrough to handle DI consts -- */ + + case CONST_INT: + { + rtx high, low; + split_double (x, &low, &high); + putc ('$', file); + output_addr_const (file, low); + return; + } + + case REG: + fprintf (file, "%s", reg_names[REGNO (x)]); + return; + + case MEM: + output_memory_reference_mode = GET_MODE (x); + output_address (XEXP (x, 0)); + return; + + default: + abort (); + } + + case 0 : /* default */ + switch (GET_CODE(x)) + { + case REG: + fprintf (file, "%s", reg_names[REGNO (x)]); + return; + + case MEM: + output_memory_reference_mode = GET_MODE (x); + output_address (XEXP (x, 0)); + return; + + case CONST_DOUBLE: + { + REAL_VALUE_TYPE r; + long l; + + /* Always use H and L for double precision - see above */ + gcc_assert(GET_MODE (x) == SFmode); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_TARGET_SINGLE (r, l); + + fprintf (file, "$0x%lx", l); + return; + } + + default: + putc ('$', file); + output_addr_const (file, x); + return; + } + + default: + output_operand_lossage ("invalid %%xn code"); + } + + abort (); +} + +/* Implements the macro PRINT_OPERAND_ADDRESS defined in crx.h. */ + +void +crx_print_operand_address (FILE * file, rtx addr) +{ + rtx breg = 0, ireg = 0; + rtx offset = 0; + rtx post_offset = 0; + rtx scale = 0; + int mem = 0; + +retry: + switch (GET_CODE (addr)) + { + case MEM: + fprintf (file, "0("); + addr = XEXP (addr, 0); + mem = 1; + goto retry; + case REG: + fprintf (file, "0(%s)", reg_names[REGNO (addr)]); + break; + case MULT: + abort (); + break; + case PLUS: + switch (GET_CODE (XEXP (addr, 0))) + { + case REG: + if (GET_CODE (XEXP (addr, 1)) == REG) + { + ireg = XEXP (addr, 0); + breg = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + if (REG_OK_FOR_BASE_P (XEXP (addr, 0)) + && ((GET_CODE (XEXP (addr, 1)) == CONST_INT) + || (const_and_contains_symbol_ref (XEXP (addr, 1))) + || (const_and_contains_label_ref (XEXP (addr, 1))))) + ireg = XEXP (addr, 0); + else + breg = XEXP (addr, 0); + + offset = XEXP (addr, 1); + } + else + abort (); + break; + case MULT: + ireg = XEXP (XEXP (addr, 0), 0); + scale = XEXP (XEXP (addr, 0), 1); + breg = XEXP (addr, 1); + break; + case PLUS: + if ((GET_CODE (XEXP (XEXP (addr, 0), 0)) == MULT) + && (GET_CODE (XEXP (XEXP (XEXP (addr, 0), 0), 0)) == REG) + && (SCALE_FOR_INDEX_P (XEXP (XEXP (XEXP (addr, 0), 0), 1))) + && (GET_CODE (XEXP (XEXP (addr, 0), 1)) == REG) + && (GET_CODE (XEXP (addr, 1)) == CONST_INT)) + { + ireg = XEXP (XEXP (XEXP (addr, 0), 0), 0); + breg = XEXP (XEXP (addr, 0), 1); + scale = (XEXP (XEXP (XEXP (addr, 0), 0), 1)); + offset = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (XEXP (addr, 0), 0)) == REG + && GET_CODE (XEXP (XEXP (addr, 0), 1)) == REG + && CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + ireg = XEXP (XEXP (addr, 0), 0); + breg = XEXP (XEXP (addr, 0), 1); + offset = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (XEXP (addr, 0), 0)) == REG + && GET_CODE (XEXP (addr, 1)) == REG + && CONSTANT_ADDRESS_P (XEXP (XEXP (addr, 0), 1))) + { + ireg = XEXP (XEXP (addr, 0), 0); + breg = XEXP (addr, 1); + offset = XEXP (XEXP (addr, 0), 1); + } + else + abort (); + break; + default: + if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + offset = addr; + else if (GET_CODE (XEXP (addr, 0)) == POST_INC + || GET_CODE (XEXP (addr, 0)) == POST_DEC) + post_offset = XEXP (addr, 1); + else + abort (); + } + + break; + } + + if (scale) + { + fprintf (file, "%ld(%s,%s,%ld)", offset ? INTVAL (offset) : 0, + reg_names[REGNO (breg)], reg_names[REGNO (ireg)], + INTVAL (scale)); + } + else + { + /* If this is (POST_DEC/INC expression + post_offset) make addr = + * POST_DEC/INC expression */ + if (post_offset != 0) + { + addr = XEXP (addr, 0); + print_post_operand_address (file, addr, INTVAL (post_offset)); + break; + } + + if (ireg != 0) + { + if (offset != 0) + { + output_addr_const (file, offset); + /* Print modifier if relevant. */ + } + else + { + fprintf (file, "0"); + } + /* Print address string */ + if (breg != 0) + { + fprintf (file, "(%s,%s)", reg_names[REGNO (breg)], + reg_names[REGNO (ireg)]); + } + else + fprintf (file, "(%s)", reg_names[REGNO (ireg)]); + } + else + { + if (offset != 0) + { + output_addr_const (file, offset); + } + else + { + fprintf (file, "0"); + } + + if (breg != 0) + { + if (offset == 0) + fprintf (file, "0"); + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + } + } + } + break; + + case POST_DEC: + case POST_INC: + case POST_MODIFY: + print_post_operand_address (file, addr, 0); + break; + + default: + + output_addr_const (file, addr); + } + + if (mem) + fprintf (file, ")"); +} + + +/*****************************************************************************/ +/* MACHINE DESCRIPTION HELPER-FUNCTIONS */ +/*****************************************************************************/ + +void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase, + rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p) +{ + rtx addr, mem; + unsigned HOST_WIDE_INT offset = *offset_p; + + /* Load */ + addr = plus_constant (src, offset); + mem = adjust_automodify_address (srcbase, SImode, addr, offset); + emit_move_insn (tmp_reg, mem); + + /* Store */ + addr = plus_constant (dst, offset); + mem = adjust_automodify_address (dstbase, SImode, addr, offset); + emit_move_insn (mem, tmp_reg); + + *offset_p = offset + 4; +} + +int +crx_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp) +{ + unsigned HOST_WIDE_INT count = 0, offset, si_moves, i; + HOST_WIDE_INT align = 0; + + rtx src, dst; + rtx tmp_reg; + + if (GET_CODE (align_exp) == CONST_INT) + { /* Only if aligned */ + align = INTVAL (align_exp); + if (align & 3) return 0; + } + + if (GET_CODE (count_exp) == CONST_INT) + { /* No more than 16 SImode moves */ + count = INTVAL (count_exp); + if (count > 64) return 0; + } + + tmp_reg = gen_reg_rtx(SImode); + + /* Create psrs for the src and dest pointers */ + dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0)); + if (dst != XEXP (dstbase, 0)) + dstbase = replace_equiv_address_nv (dstbase, dst); + src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0)); + if (src != XEXP (srcbase, 0)) + srcbase = replace_equiv_address_nv (srcbase, src); + + offset = 0; + + /* Emit SImode moves */ + si_moves = count >> 2; + for (i = 0; i < si_moves; i++) + crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); + + /* Special cases */ + if (count & 3) + { + offset = count - 4; + crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset); + } + + gcc_assert (offset == count); + + return 1; +} + +rtx +crx_expand_compare (enum rtx_code code, enum machine_mode mode) +{ + rtx op0, op1, cc_reg, ret; + + op0 = crx_compare_op0; + op1 = crx_compare_op1; + + /* Emit the compare that writes into CC_REGNUM) */ + cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); + ret = gen_rtx_COMPARE (CCmode, op0, op1); + emit_insn (gen_rtx_SET (VOIDmode, cc_reg, ret)); + /* debug_rtx (get_last_insn ()); */ + + /* Return the rtx for using the result in CC_REGNUM */ + return gen_rtx_fmt_ee (code, mode, cc_reg, const0_rtx); +} + +void +crx_expand_branch (enum rtx_code code, rtx label) +{ + rtx tmp = crx_expand_compare (code, VOIDmode); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + /* debug_rtx (get_last_insn ()); */ +} + +void +crx_expand_scond (enum rtx_code code, rtx dest) +{ + rtx tmp = crx_expand_compare (code, GET_MODE (dest)); + emit_move_insn (dest, tmp); + /* debug_rtx (get_last_insn ()); */ +} + +static void +mpushpop_str (char *stringbuffer, const char *mnemonic, char *mask) +{ + if(strlen(mask) > 2 || crx_interrupt_function_p ()) /* needs 2-word instr. */ + sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask); + else /* single word instruction */ + sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask); +} + +/* Called from crx.md. The return value depends on the parameter push_or_pop: + * When push_or_pop is zero -> string for push instructions of prologue. + * When push_or_pop is nonzero -> string for pop/popret/retx in epilogue. + * Relies on the assumptions: + * 1. RA is the last register to be saved. + * 2. The maximal value of the counter is MAX_COUNT. */ + +char * +crx_prepare_push_pop_string (int push_or_pop) +{ + /* j is the number of registers being saved, takes care that there won't be + * more than 8 in one push/pop instruction */ + + /* For the register mask string */ + static char mask_str[50]; + + /* i is the index of save_regs[], going from 0 until last_reg_to_save */ + int i = 0; + + int ra_in_bitmask = 0; + + char *return_str; + + /* For reversing on the push instructions if there are more than one. */ + char *temp_str; + + return_str = (char *) xmalloc (120); + temp_str = (char *) xmalloc (120); + + /* Initialize */ + memset (return_str, 0, 3); + + while (i <= last_reg_to_save) + { + /* Prepare mask for one instruction. */ + mask_str[0] = 0; + + if (i <= SP_REGNUM) + { /* Add regs unit full or SP register reached */ + int j = 0; + while (j < MAX_COUNT && i <= SP_REGNUM) + { + if (save_regs[i]) + { + /* TODO to use ra_in_bitmask for detecting last pop is not + * smart it prevents things like: popret r5 */ + if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1; + if (j > 0) strcat (mask_str, ", "); + strcat (mask_str, reg_names[i]); + ++j; + } + ++i; + } + } + else + { + /* Handle hi/lo savings */ + while (i <= last_reg_to_save) + { + if (save_regs[i]) + { + strcat (mask_str, "lo, hi"); + i = last_reg_to_save + 1; + break; + } + ++i; + } + } + + if (strlen(mask_str) == 0) continue; + + if (push_or_pop == 1) + { + if (crx_interrupt_function_p ()) + mpushpop_str (temp_str, "popx", mask_str); + else + { + if (ra_in_bitmask) + { + mpushpop_str (temp_str, "popret", mask_str); + ra_in_bitmask = 0; + } + else mpushpop_str (temp_str, "pop", mask_str); + } + + strcat (return_str, temp_str); + } + else + { + /* push - We need to reverse the order of the instructions if there + * are more than one. (since the pop will not be reversed in the + * epilogue */ + if (crx_interrupt_function_p ()) + mpushpop_str (temp_str, "pushx", mask_str); + else + mpushpop_str (temp_str, "push", mask_str); + strcat (temp_str, return_str); + strcpy (strcat (return_str, "\t"), temp_str); + } + + } + + if (push_or_pop == 1) + { + /* pop */ + if (crx_interrupt_function_p ()) + strcat (return_str, "\n\tretx\n"); + + else if (!FUNC_IS_NORETURN_P (current_function_decl) + && !save_regs[RETURN_ADDRESS_REGNUM]) + strcat (return_str, "\n\tjump\tra\n"); + } + + /* Skip the newline and the tab in the start of return_str. */ + return_str += 2; + return return_str; +} + +/* CompactRISC CRX Architecture stack layout: + + 0 +--------------------- + | + . + . + | + +==================== Sp(x)=Ap(x+1) + A | Args for functions + | | called by X and Dynamically + | | Dynamic allocations allocated and + | | (alloca, variable deallocated + Stack | length arrays). + grows +-------------------- Fp(x) + down| | Local vaiables of X + ward| +-------------------- + | | Regs saved for X-1 + | +==================== Sp(x-1)=Ap(x) + | Args for func X + | pushed by X-1 + +-------------------- Fp(x-1) + | + | + V + +*/ + +void +crx_expand_prologue (void) +{ + crx_compute_frame (); + crx_compute_save_regs (); + + /* If there is no need in push and adjustment to sp, return. */ + if (size_for_adjusting_sp + sum_regs == 0) + return; + + if (last_reg_to_save != -1) + /* If there are registers to push. */ + emit_insn (gen_push_for_prologue (GEN_INT (sum_regs))); + + if (size_for_adjusting_sp > 0) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-(size_for_adjusting_sp)))); + + if (frame_pointer_needed) + /* Initialize the frame pointer with the value of the stack pointer + * pointing now to the locals. */ + emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); +} + +/* Generate insn that updates the stack for local variables and padding for + * registers we save. - Generate the appropriate return insn. */ + +void +crx_expand_epilogue (void) +{ + rtx return_reg; + + /* Nonzero if we need to return and pop only RA. This will generate a + * different insn. This differentiate is for the peepholes for call as last + * statement in function. */ + int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM] + && (sum_regs == UNITS_PER_WORD)); + + /* Return register. */ + return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM); + + if (frame_pointer_needed) + /* Restore the stack pointer with the frame pointers value */ + emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + + if (size_for_adjusting_sp > 0) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (size_for_adjusting_sp))); + + if (crx_interrupt_function_p ()) + emit_jump_insn (gen_interrupt_return ()); + else if (last_reg_to_save == -1) + /* Nothing to pop */ + /* Don't output jump for interrupt routine, only retx. */ + emit_jump_insn (gen_indirect_jump_return ()); + else if (only_popret_RA) + emit_jump_insn (gen_popret_RA_return ()); + else + emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs))); +} + diff --git a/gcc/config/crx/crx.h b/gcc/config/crx/crx.h new file mode 100644 index 0000000..e7ec8ce --- /dev/null +++ b/gcc/config/crx/crx.h @@ -0,0 +1,533 @@ +/* Definitions of target machine for GNU compiler, for CRX. + Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. */ + +#ifndef GCC_CRX_H +#define GCC_CRX_H + +/*****************************************************************************/ +/* CONTROLLING THE DRIVER */ +/*****************************************************************************/ + +#define CC1PLUS_SPEC "%{!frtti:-fno-rtti} \ + %{!fenforce-eh-specs:-fno-enforce-eh-specs} \ + %{!fexceptions:-fno-exceptions} \ + %{!fthreadsafe-statics:-fno-threadsafe-statics}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crti.o%s crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +/*****************************************************************************/ +/* RUN-TIME TARGET SPECIFICATION */ +/*****************************************************************************/ + +#ifndef TARGET_CPU_CPP_BUILTINS +#define TARGET_CPU_CPP_BUILTINS() \ +do { \ + builtin_define("__CRX__"); \ + builtin_define("__CR__"); \ +} while (0) +#endif + +#define TARGET_VERSION fputs (" (CRX/ELF)", stderr); + +/* Put each function in its own section so that PAGE-instruction + * relaxation can do its best. */ +#define OPTIMIZATION_OPTIONS(LEVEL, SIZEFLAG) \ + do { \ + if ((LEVEL) || (SIZEFLAG)) \ + flag_function_sections = 1; \ + } while (0) + +/* Show we can debug even without a frame pointer. */ +#define CAN_DEBUG_WITHOUT_FP + +/*****************************************************************************/ +/* STORAGE LAYOUT */ +/*****************************************************************************/ + +#define BITS_BIG_ENDIAN 0 + +#define BYTES_BIG_ENDIAN 0 + +#define WORDS_BIG_ENDIAN 0 + +#define UNITS_PER_WORD 4 + +#define POINTER_SIZE 32 + +#define PARM_BOUNDARY 32 + +#define STACK_BOUNDARY 32 + +#define FUNCTION_BOUNDARY 32 + +#define STRUCTURE_SIZE_BOUNDARY 32 + +#define BIGGEST_ALIGNMENT 32 + +/* In CRX arrays of chars are word-aligned, so strcpy() will be faster. */ +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + (TREE_CODE (TYPE) == ARRAY_TYPE && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ + && (ALIGN) < BITS_PER_WORD \ + ? (BITS_PER_WORD) : (ALIGN)) + +/* In CRX strings are word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(CONSTANT, ALIGN) \ + (TREE_CODE (CONSTANT) == STRING_CST && (ALIGN) < BITS_PER_WORD \ + ? (BITS_PER_WORD) : (ALIGN)) + +#define STRICT_ALIGNMENT 0 + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/*****************************************************************************/ +/* LAYOUT OF SOURCE LANGUAGE DATA TYPES */ +/*****************************************************************************/ + +#define INT_TYPE_SIZE 32 + +#define SHORT_TYPE_SIZE 16 + +#define LONG_TYPE_SIZE 32 + +#define LONG_LONG_TYPE_SIZE 64 + +#define FLOAT_TYPE_SIZE 32 + +#define DOUBLE_TYPE_SIZE 64 + +#define LONG_DOUBLE_TYPE_SIZE 64 + +#define DEFAULT_SIGNED_CHAR 1 + +#define SIZE_TYPE "unsigned int" + +#define PTRDIFF_TYPE "int" + +/*****************************************************************************/ +/* REGISTER USAGE. */ +/*****************************************************************************/ + +#define FIRST_PSEUDO_REGISTER 19 + +/* On the CRX, only the stack pointer (r15) is such. */ +#define FIXED_REGISTERS \ + { \ + /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + /* r11 r12 r13 ra sp r16 r17 cc */ \ + 0, 0, 0, 0, 1, 0, 0, 1 \ + } + +/* On the CRX, calls clobbers r0-r6 (scratch registers), ra (the return address) + * and sp - (the stack pointer which is fixed). */ +#define CALL_USED_REGISTERS \ + { \ + /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 */ \ + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ + /* r11 r12 r13 ra sp r16 r17 cc */ \ + 0, 0, 0, 1, 1, 1, 1, 1 \ + } + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* On the CRX architecture, HILO regs can only hold SI mode. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) crx_hard_regno_mode_ok(REGNO, MODE) + +/* So far no patterns for moving CCMODE data are available */ +#define AVOID_CCMODE_COPIES + +/* Interrupt functions can only use registers that have already been saved by + * the prologue, even if they would normally be call-clobbered. */ +#define HARD_REGNO_RENAME_OK(SRC, DEST) \ + (!crx_interrupt_function_p () || regs_ever_live[DEST]) + +#define MODES_TIEABLE_P(MODE1, MODE2) 1 + +enum reg_class +{ + NO_REGS, + LO_REGS, + HI_REGS, + HILO_REGS, + NOSP_REGS, + GENERAL_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ + { \ + "NO_REGS", \ + "LO_REGS", \ + "HI_REGS", \ + "HILO_REGS", \ + "NOSP_REGS", \ + "GENERAL_REGS", \ + "ALL_REGS" \ + } + +#define REG_CLASS_CONTENTS \ + { \ + {0x00000000}, /* NO_REGS */ \ + {0x00010000}, /* LO_REGS : 16 */ \ + {0x00020000}, /* HI_REGS : 17 */ \ + {0x00030000}, /* HILO_REGS : 16, 17 */ \ + {0x00007fff}, /* NOSP_REGS : 0 - 14 */ \ + {0x0000ffff}, /* GENERAL_REGS : 0 - 15 */ \ + {0x0007ffff} /* ALL_REGS : 0 - 18 */ \ + } + +#define REGNO_REG_CLASS(REGNO) crx_regno_reg_class(REGNO) + +#define BASE_REG_CLASS GENERAL_REGS + +#define INDEX_REG_CLASS GENERAL_REGS + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'b' ? NOSP_REGS : \ + (C) == 'l' ? LO_REGS : \ + (C) == 'h' ? HI_REGS : \ + (C) == 'k' ? HILO_REGS : \ + NO_REGS) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 16 \ + || (reg_renumber && (unsigned)reg_renumber[REGNO] < 16)) + +#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO) +#define REGNO_OK_FOR_INDEXED_BASE_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO) + +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + +#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \ + crx_secondary_reload_class (CLASS, MODE, X) + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD + +#define SIGNED_INT_FITS_N_BITS(imm, N) \ + ((((imm) < ((long long)1<<((N)-1))) && ((imm) >= -((long long)1<<((N)-1)))) ? 1 : 0) + +#define UNSIGNED_INT_FITS_N_BITS(imm, N) \ + (((imm) < ((long long)1<<(N)) && (imm) >= (long long)0) ? 1 : 0) + +#define HILO_REGNO_P(regno) \ + (reg_classes_intersect_p(REGNO_REG_CLASS(regno), HILO_REGS)) + +#define INT_CST4(VALUE) \ + (((VALUE) >= -1 && (VALUE) <= 4) || (VALUE) == -4 \ + || (VALUE) == 7 || (VALUE) == 8 || (VALUE) == 16 || (VALUE) == 32 \ + || (VALUE) == 20 || (VALUE) == 12 || (VALUE) == 48) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + /* Legal const for store immediate instructions */ \ + ((C) == 'I' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 3) : \ + (C) == 'J' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 4) : \ + (C) == 'K' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 5) : \ + (C) == 'L' ? INT_CST4(VALUE) : \ + 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? crx_const_double_ok (VALUE) : \ + 0) + +/*****************************************************************************/ +/* STACK LAYOUT AND CALLING CONVENTIONS. */ +/*****************************************************************************/ + +#define STACK_GROWS_DOWNWARD + +#define STARTING_FRAME_OFFSET 0 + +#define STACK_POINTER_REGNUM 15 + +#define FRAME_POINTER_REGNUM 13 + +#define ARG_POINTER_REGNUM 12 + +#define STATIC_CHAIN_REGNUM 1 + +#define RETURN_ADDRESS_REGNUM 14 + +#define FIRST_PARM_OFFSET(FNDECL) 0 + +#define FRAME_POINTER_REQUIRED (current_function_calls_alloca) + +#define ELIMINABLE_REGS \ + { \ + { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \ + } + +#define CAN_ELIMINATE(FROM, TO) \ + ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1) + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + do { \ + (OFFSET) = crx_initial_elimination_offset ((FROM), (TO)); \ + } while (0) + +/*****************************************************************************/ +/* PASSING FUNCTION ARGUMENTS */ +/*****************************************************************************/ + +#define ACCUMULATE_OUTGOING_ARGS (TARGET_NO_PUSH_ARGS) + +#define PUSH_ARGS (!TARGET_NO_PUSH_ARGS) + +#define PUSH_ROUNDING(BYTES) (((BYTES) + 3) & ~3) + +#define RETURN_POPS_ARGS(FNDECL, FUNTYPE, SIZE) 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((rtx) crx_function_arg(&(CUM), (MODE), (TYPE), (NAMED))) + +#ifndef CUMULATIVE_ARGS +struct cumulative_args +{ + int ints; +}; + +#define CUMULATIVE_ARGS struct cumulative_args +#endif + +/* On the CRX architecture, Varargs routines should receive their parameters on + * the stack. */ + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ + crx_init_cumulative_args(&(CUM), (FNTYPE), (LIBNAME)) + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + crx_function_arg_advance(&(CUM), (MODE), (TYPE), (NAMED)) + +#define FUNCTION_ARG_REGNO_P(REGNO) crx_function_arg_regno_p((REGNO)) + +/*****************************************************************************/ +/* RETURNING FUNCTION VALUE */ +/*****************************************************************************/ + +/* On the CRX, the return value is in R0 */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx_REG(TYPE_MODE (VALTYPE), 0) + +#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 0) + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +#define CRX_STRUCT_VALUE_REGNUM 0 + +/*****************************************************************************/ +/* GENERATING CODE FOR PROFILING - NOT IMPLEMENTED */ +/*****************************************************************************/ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(STREAM, LABELNO) \ +{ \ + sorry ("Profiler support for CRX"); \ +} + +/*****************************************************************************/ +/* TRAMPOLINES FOR NESTED FUNCTIONS - NOT SUPPORTED */ +/*****************************************************************************/ + +#define TRAMPOLINE_SIZE 32 + +#define INITIALIZE_TRAMPOLINE(addr, fnaddr, static_chain) \ +{ \ + sorry ("Trampoline support for CRX"); \ +} + +/*****************************************************************************/ +/* ADDRESSING MODES */ +/*****************************************************************************/ + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST \ + || GET_CODE (X) == CONST_INT) + +#define MAX_REGS_PER_ADDRESS 2 + +#define HAVE_POST_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +#define HAVE_POST_MODIFY_DISP 1 +#define HAVE_POST_MODIFY_REG 0 + +#define STRICT_REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define STRICT_REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P(REGNO(X)) +#define STRICT_REG_OK_FOR_INDEXED_BASE_P(X) REGNO_OK_FOR_INDEXED_BASE_P(REGNO(X)) + +#define NONSTRICT_REG_OK_FOR_BASE_P(X) 1 +#define NONSTRICT_REG_OK_FOR_INDEX_P(X) 1 +#define NONSTRICT_REG_OK_FOR_INDEXED_BASE_P(X) 1 + +#ifdef REG_OK_STRICT +#define REG_OK_FOR_BASE_P(X) STRICT_REG_OK_FOR_BASE_P(X) +#define REG_OK_FOR_INDEX_P(X) STRICT_REG_OK_FOR_INDEX_P(X) +#define REG_OK_FOR_INDEXED_BASE_P(X) STRICT_REG_OK_FOR_INDEXED_BASE_P(X) +#else +#define REG_OK_FOR_BASE_P(X) NONSTRICT_REG_OK_FOR_BASE_P(X) +#define REG_OK_FOR_INDEX_P(X) NONSTRICT_REG_OK_FOR_INDEX_P(X) +#define REG_OK_FOR_INDEXED_BASE_P(X) NONSTRICT_REG_OK_FOR_INDEXED_BASE_P(X) +#endif /* REG_OK_STRICT */ + +#ifdef REG_OK_STRICT +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (crx_legitimate_address_p (MODE, X, 1)) \ + goto LABEL; \ +} +#else +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ +{ \ + if (crx_legitimate_address_p (MODE, X, 0)) \ + goto LABEL; \ +} +#endif + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) {} + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ +{ \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == POST_DEC) \ + goto LABEL; \ +} + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/*****************************************************************************/ +/* CONDITION CODE STATUS */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* RELATIVE COSTS OF OPERATIONS */ +/*****************************************************************************/ + +#define MEMORY_MOVE_COST(MODE, CLASS, IN) crx_memory_move_cost(MODE, CLASS, IN) +/* Moving to processor register flushes pipeline - thus asymmetric */ +#define REGISTER_MOVE_COST(MODE, FROM, TO) ((TO != GENERAL_REGS) ? 8 : 2) +/* Assume best case (branch predicted) */ +#define BRANCH_COST 2 + +#define SLOW_BYTE_ACCESS 1 + +/*****************************************************************************/ +/* DIVIDING THE OUTPUT INTO SECTIONS */ +/*****************************************************************************/ + +#define TEXT_SECTION_ASM_OP "\t.section\t.text" + +#define DATA_SECTION_ASM_OP "\t.section\t.data" + +#define BSS_SECTION_ASM_OP "\t.section\t.bss" + +/*****************************************************************************/ +/* POSITION INDEPENDENT CODE */ +/*****************************************************************************/ + +#define PIC_OFFSET_TABLE_REGNUM 12 + +#define LEGITIMATE_PIC_OPERAND_P(X) 1 + +/*****************************************************************************/ +/* ASSEMBLER FORMAT */ +/*****************************************************************************/ + +#define GLOBAL_ASM_OP "\t.globl\t" + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ + asm_fprintf (STREAM, "%U%s", (*targetm.strip_name_encoding) (NAME)); + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/*****************************************************************************/ +/* INSTRUCTION OUTPUT */ +/*****************************************************************************/ + +#define REGISTER_NAMES \ + { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "r13", "ra", "sp", \ + "lo", "hi", "cc" \ + } + +#define PRINT_OPERAND(STREAM, X, CODE) \ + crx_print_operand(STREAM, X, CODE) + +#define PRINT_OPERAND_ADDRESS(STREAM, ADDR) \ + crx_print_operand_address(STREAM, ADDR) + +/*****************************************************************************/ +/* OUTPUT OF DISPATCH TABLES */ +/*****************************************************************************/ + +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ + asm_fprintf ((STREAM), "\t.long\t.L%d\n", (VALUE)) + +/*****************************************************************************/ +/* ALIGNMENT IN ASSEMBLER FILE */ +/*****************************************************************************/ + +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ + asm_fprintf ((STREAM), "\t.align\t%d\n", 1 << (POWER)) + +/*****************************************************************************/ +/* MISCELLANEOUS PARAMETERS */ +/*****************************************************************************/ + +#define CASE_VECTOR_MODE Pmode + +#define MOVE_MAX 4 + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define STORE_FLAG_VALUE 1 + +#define Pmode SImode + +#define FUNCTION_MODE QImode + +/*****************************************************************************/ +/* EXTERNAL DECLARATIONS FOR VARIABLES DEFINED IN CRX.C */ +/*****************************************************************************/ + +extern rtx crx_compare_op0; /* operand 0 for comparisons */ +extern rtx crx_compare_op1; /* operand 1 for comparisons */ + +#endif /* ! GCC_CRX_H */ diff --git a/gcc/config/crx/crx.md b/gcc/config/crx/crx.md new file mode 100644 index 0000000..54dcd49 --- /dev/null +++ b/gcc/config/crx/crx.md @@ -0,0 +1,920 @@ +;; GCC machine description for CRX. +;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +;; 2001, 2002, 2003, 2004 +;; Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, 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 COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. */ + +;; Register numbers + +(define_constants + [(SP_REGNUM 15) ; Stack pointer + (RA_REGNUM 14) ; Return address + (LO_REGNUM 16) ; LO register + (HI_REGNUM 17) ; HI register + (CC_REGNUM 18) ; Condition code register + ] +) + +(define_attr "length" "" ( const_int 6 ) ) + +(define_asm_attributes + [(set_attr "length" "6")] +) + +;; Predicates + +(define_predicate "u4bits_operand" + (match_code "const_int,const_double") + { + if (GET_CODE (op) == CONST_DOUBLE) + return crx_const_double_ok (op); + return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 4)) ? 1 : 0; + } +) + +(define_predicate "cst4_operand" + (and (match_code "const_int") + (match_test "INT_CST4(INTVAL(op))"))) + +(define_predicate "reg_or_u4bits_operand" + (ior (match_operand 0 "u4bits_operand") + (match_operand 0 "register_operand"))) + +(define_predicate "reg_or_cst4_operand" + (ior (match_operand 0 "cst4_operand") + (match_operand 0 "register_operand"))) + +(define_predicate "reg_or_sym_operand" + (ior (match_code "symbol_ref") + (match_operand 0 "register_operand"))) + +(define_predicate "nosp_reg_operand" + (and (match_operand 0 "register_operand") + (match_test "REGNO (op) != SP_REGNUM"))) + +(define_predicate "store_operand" + (and (match_operand 0 "memory_operand") + (not (match_operand 0 "push_operand")))) + +;; Mode Macro Definitions + +(define_mode_macro ALLMT [QI HI SI SF DI DF]) +(define_mode_macro CRXMM [QI HI SI SF]) +(define_mode_macro CRXIM [QI HI SI]) +(define_mode_macro DIDFM [DI DF]) +(define_mode_macro SISFM [SI SF]) +(define_mode_macro SHORT [QI HI]) + +(define_mode_attr tIsa [(QI "b") (HI "w") (SI "d") (SF "d")]) +(define_mode_attr lImmArith [(QI "4") (HI "4") (SI "6")]) +(define_mode_attr lImmRotl [(QI "2") (HI "2") (SI "4")]) +(define_mode_attr IJK [(QI "I") (HI "J") (SI "K")]) +(define_mode_attr iF [(QI "i") (HI "i") (SI "i") (DI "i") (SF "F") (DF "F")]) +(define_mode_attr JG [(QI "J") (HI "J") (SI "J") (DI "J") (SF "G") (DF "G")]) +; In HI or QI mode we push 4 bytes. +(define_mode_attr pushCnstr [(QI "X") (HI "X") (SI "<") (SF "<") (DI "<") (DF "<")]) +(define_mode_attr tpush [(QI "") (HI "") (SI "") (SF "") (DI "sp, ") (DF "sp, ")]) +(define_mode_attr lpush [(QI "2") (HI "2") (SI "2") (SF "2") (DI "4") (DF "4")]) + + +;; Code Macro Definitions + +(define_code_macro sz_xtnd [sign_extend zero_extend]) +(define_code_attr sIsa [(sign_extend "") (zero_extend "u")]) +(define_code_attr sPat [(sign_extend "s") (zero_extend "u")]) +(define_code_attr szPat [(sign_extend "") (zero_extend "zero_")]) +(define_code_attr szIsa [(sign_extend "s") (zero_extend "z")]) + +(define_code_macro sh_oprnd [ashift ashiftrt lshiftrt]) +(define_code_attr shIsa [(ashift "ll") (ashiftrt "ra") (lshiftrt "rl")]) +(define_code_attr shPat [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr")]) + +(define_code_macro mima_oprnd [smax umax smin umin]) +(define_code_attr mimaIsa [(smax "maxs") (umax "maxu") (smin "mins") (umin "minu")]) + +(define_code_macro any_cond [eq ne gt gtu lt ltu ge geu le leu]) + +;; Addition Instructions + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0") + (match_operand:DI 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "addd\\t%L2, %L1\;addcd\\t%H2, %H1" + [(set_attr "length" "4,12")] +) + +(define_insn "add<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (plus:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "add<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Subtract Instructions + +(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 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "subd\\t%L2, %L1\;subcd\\t%H2, %H1" + [(set_attr "length" "4,12")] +) + +(define_insn "sub<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (minus:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "sub<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Multiply Instructions + +(define_insn "mul<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (mult:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "mul<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Widening-multiplication Instructions + +(define_insn "<sIsa>mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=k") + (mult:DI (sz_xtnd:DI (match_operand:SI 1 "register_operand" "%r")) + (sz_xtnd:DI (match_operand:SI 2 "register_operand" "r")))) + (clobber (reg:CC CC_REGNUM))] + "" + "mull<sPat>d\\t%2, %1" + [(set_attr "length" "4")] +) + +(define_insn "<sIsa>mulhisi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "%0")) + (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r")))) + (clobber (reg:CC CC_REGNUM))] + "" + "mul<sPat>wd\\t%2, %0" + [(set_attr "length" "4")] +) + +(define_insn "<sIsa>mulqihi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (mult:HI (sz_xtnd:HI (match_operand:QI 1 "register_operand" "%0")) + (sz_xtnd:HI (match_operand:QI 2 "register_operand" "r")))) + (clobber (reg:CC CC_REGNUM))] + "" + "mul<sPat>bw\\t%2, %0" + [(set_attr "length" "4")] +) + +;; Logical Instructions - and + +(define_insn "and<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (and:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "and<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Logical Instructions - or + +(define_insn "ior<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (ior:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "or<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Logical Instructions - xor + +(define_insn "xor<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (xor:CRXIM (match_operand:CRXIM 1 "register_operand" "%0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,i"))) + (clobber (reg:CC CC_REGNUM))] + "" + "xor<tIsa>\\t%2, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Sign and Zero Extend Instructions + +(define_insn "<szPat>extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "<szIsa>extwd\\t%1, %0" + [(set_attr "length" "4")] +) + +(define_insn "<szPat>extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sz_xtnd:SI (match_operand:QI 1 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "<szIsa>extbd\\t%1, %0" + [(set_attr "length" "4")] +) + +(define_insn "<szPat>extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sz_xtnd:HI (match_operand:QI 1 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "<szIsa>extbw\\t%1, %0" + [(set_attr "length" "4")] +) + +;; Negation Instructions + +(define_insn "neg<mode>2" + [(set (match_operand:CRXIM 0 "register_operand" "=r") + (neg:CRXIM (match_operand:CRXIM 1 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "neg<tIsa>\\t%1, %0" + [(set_attr "length" "4")] +) + +;; Absolute Instructions + +(define_insn "abs<mode>2" + [(set (match_operand:CRXIM 0 "register_operand" "=r") + (abs:CRXIM (match_operand:CRXIM 1 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "abs<tIsa>\\t%1, %0" + [(set_attr "length" "4")] +) + +;; Max and Min Instructions + +(define_insn "<code><mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r") + (mima_oprnd:CRXIM (match_operand:CRXIM 1 "register_operand" "%0") + (match_operand:CRXIM 2 "register_operand" "r")))] + "" + "<mimaIsa><tIsa>\\t%2, %0" + [(set_attr "length" "4")] +) + +;; One's Complement + +(define_insn "one_cmpl<mode>2" + [(set (match_operand:CRXIM 0 "register_operand" "=r") + (not:CRXIM (match_operand:CRXIM 1 "register_operand" "0"))) + (clobber (reg:CC CC_REGNUM))] + "" + "xor<tIsa>\\t$-1, %0" + [(set_attr "length" "2")] +) + +;; Rotate Instructions + +(define_insn "rotl<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (rotate:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") + (match_operand:CRXIM 2 "nonmemory_operand" "r,<IJK>"))) + (clobber (reg:CC CC_REGNUM))] + "" + "@ + rotl<tIsa>\\t%2, %0 + rot<tIsa>\\t%2, %0" + [(set_attr "length" "4,<lImmRotl>")] +) + +(define_insn "rotr<mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r") + (rotatert:CRXIM (match_operand:CRXIM 1 "register_operand" "0") + (match_operand:CRXIM 2 "register_operand" "r"))) + (clobber (reg:CC CC_REGNUM))] + "" + "rotr<tIsa>\\t%2, %0" + [(set_attr "length" "4")] +) + +;; Arithmetic Left and Right Shift Instructions + +(define_insn "<shPat><mode>3" + [(set (match_operand:CRXIM 0 "register_operand" "=r,r") + (sh_oprnd:CRXIM (match_operand:CRXIM 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "r,<IJK>"))) + (clobber (reg:CC CC_REGNUM))] + "" + "s<shIsa><tIsa>\\t%2, %0" + [(set_attr "length" "2,2")] +) + +;; Bit Set Instructions + +(define_insn "extv" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "" + { + static char buf[100]; + int strpntr; + int size = INTVAL (operands[2]); + int pos = INTVAL (operands[3]); + strpntr = sprintf (buf, "ram\t$%d, $31, $%d, %%1, %%0\;", + BITS_PER_WORD - (size + pos), BITS_PER_WORD - size); + sprintf (buf + strpntr, "srad\t$%d, %%0", BITS_PER_WORD - size); + return buf; + } + [(set_attr "length" "6")] +) + +(define_insn "extzv" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "" + { + static char buf[40]; + int size = INTVAL (operands[2]); + int pos = INTVAL (operands[3]); + sprintf (buf, "ram\t$%d, $%d, $0, %%1, %%0", + (BITS_PER_WORD - pos) % BITS_PER_WORD, size - 1); + return buf; + } + [(set_attr "length" "4")] +) + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "register_operand" "r"))] + "" + { + static char buf[40]; + int size = INTVAL (operands[1]); + int pos = INTVAL (operands[2]); + sprintf (buf, "rim\t$%d, $%d, $%d, %%3, %%0", + pos, size + pos - 1, pos); + return buf; + } + [(set_attr "length" "4")] +) + +;; Move Instructions + +(define_expand "mov<mode>" + [(set (match_operand:ALLMT 0 "nonimmediate_operand" "") + (match_operand:ALLMT 1 "general_operand" ""))] + "" + { + if (!(reload_in_progress || reload_completed)) + { + if (!register_operand (operands[0], <MODE>mode)) + { + if (push_operand (operands[0], <MODE>mode) ? + !nosp_reg_operand (operands[1], <MODE>mode) : + !reg_or_u4bits_operand (operands[1], <MODE>mode)) + { + operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]); + } + } + } + } +) + +(define_insn "push<mode>_internal" + [(set (match_operand:ALLMT 0 "push_operand" "=<pushCnstr>") + (match_operand:ALLMT 1 "nosp_reg_operand" "b"))] + "" + "push\t<tpush>%p1" + [(set_attr "length" "<lpush>")] +) + +(define_insn "mov<mode>_regs" + [(set (match_operand:SISFM 0 "register_operand" "=r, r, r, k") + (match_operand:SISFM 1 "nonmemory_operand" "r, <iF>, k, r"))] + "" + "@ + movd\\t%1, %0 + movd\\t%1, %0 + mfpr\\t%1, %0 + mtpr\\t%1, %0" + [(set_attr "length" "2,6,4,4")] +) + +(define_insn "mov<mode>_regs" + [(set (match_operand:DIDFM 0 "register_operand" "=r, r, r, k") + (match_operand:DIDFM 1 "nonmemory_operand" "r, <iF>, k, r"))] + "" + { + switch (which_alternative) + { + case 0: if (REGNO (operands[0]) > REGNO (operands[1])) + return "movd\t%H1, %H0\;movd\t%L1, %L0"; + else + return "movd\t%L1, %L0\;movd\t%H1, %H0"; + case 1: return "movd\t%H1, %H0\;movd\t%L1, %L0"; + case 2: return "mfpr\t%H1, %H0\;mfpr\t%L1, %L0"; + case 3: return "mtpr\t%H1, %H0\;mtpr\t%L1, %L0"; + default: gcc_unreachable (); + } + } + [(set_attr "length" "4,12,8,8")] +) + +(define_insn "mov<mode>_regs" ; no HI/QI mode in HILO regs + [(set (match_operand:SHORT 0 "register_operand" "=r, r") + (match_operand:SHORT 1 "nonmemory_operand" "r, i"))] + "" + "mov<tIsa>\\t%1, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +(define_insn "mov<mode>_load" + [(set (match_operand:CRXMM 0 "register_operand" "=r") + (match_operand:CRXMM 1 "memory_operand" "m"))] + "" + "load<tIsa>\\t%1, %0" + [(set_attr "length" "6")] +) + +(define_insn "mov<mode>_load" + [(set (match_operand:DIDFM 0 "register_operand" "=r") + (match_operand:DIDFM 1 "memory_operand" "m"))] + "" + { + rtx first_dest_reg = gen_rtx_REG (SImode, REGNO (operands[0])); + if (reg_overlap_mentioned_p (first_dest_reg, operands[1])) + return "loadd\t%H1, %H0\;loadd\t%L1, %L0"; + return "loadd\t%L1, %L0\;loadd\t%H1, %H0"; + } + [(set_attr "length" "12")] +) + +(define_insn "mov<mode>_store" + [(set (match_operand:CRXMM 0 "store_operand" "=m, m") + (match_operand:CRXMM 1 "reg_or_u4bits_operand" "r, <JG>"))] + "" + "stor<tIsa>\\t%1, %0" + [(set_attr "length" "6")] +) + +(define_insn "mov<mode>_store" + [(set (match_operand:DIDFM 0 "store_operand" "=m, m") + (match_operand:DIDFM 1 "reg_or_u4bits_operand" "r, <JG>"))] + "" + "stord\t%H1, %H0\;stord\t%L1, %L0" + [(set_attr "length" "12")] +) + +;; Movmem Instruction + +(define_expand "movmemsi" + [(use (match_operand:BLK 0 "memory_operand" "")) + (use (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:SI 2 "nonmemory_operand" "")) + (use (match_operand:SI 3 "const_int_operand" ""))] + "" + { + if (crx_expand_movmem (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; + } +) + +;; Compare and Branch Instructions + +(define_insn "cbranch<mode>4" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:CRXIM 1 "register_operand" "r") + (match_operand:CRXIM 2 "reg_or_cst4_operand" "rL")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "cmpb%d0<tIsa>\\t%2, %1, %l3" + [(set_attr "length" "6")] +) + +;; Compare Instructions + +(define_expand "cmp<mode>" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:CRXIM 0 "register_operand" "") + (match_operand:CRXIM 1 "nonmemory_operand" "")))] + "" + { + crx_compare_op0 = operands[0]; + crx_compare_op1 = operands[1]; + DONE; + } +) + +(define_insn "cmp<mode>_internal" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:CRXIM 0 "register_operand" "r,r") + (match_operand:CRXIM 1 "nonmemory_operand" "r,i")))] + "" + "cmp<tIsa>\\t%1, %0" + [(set_attr "length" "2,<lImmArith>")] +) + +;; Conditional Branch Instructions + +(define_expand "b<code>" + [(set (pc) + (if_then_else (any_cond (reg:CC CC_REGNUM) + (const_int 0)) + (label_ref (match_operand 0 "")) + (pc)))] + "" + { + crx_expand_branch (<CODE>, operands[0]); + DONE; + } +) + +(define_insn "bCOND_internal" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC CC_REGNUM) + (const_int 0)]) + (label_ref (match_operand 1 "")) + (pc)))] + "" + "b%d0\\t%l1" + [(set_attr "length" "6")] +) + +;; Scond Instructions + +(define_expand "s<code>" + [(set (match_operand:SI 0 "register_operand") + (any_cond:SI (reg:CC CC_REGNUM) (const_int 0)))] + "" + { + crx_expand_scond (<CODE>, operands[0]); + DONE; + } +) + +(define_insn "sCOND_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operator:SI 1 "comparison_operator" + [(reg:CC CC_REGNUM) (const_int 0)]))] + "" + "s%d1\\t%0" + [(set_attr "length" "2")] +) + +;; Jumps and Branches + +(define_insn "indirect_jump_return" + [(parallel + [(set (pc) + (reg:SI RA_REGNUM)) + (return)]) + ] + "reload_completed" + "jump\\tra" + [(set_attr "length" "2")] +) + +(define_insn "indirect_jump" + [(set (pc) + (match_operand:SI 0 "reg_or_sym_operand" "r,i"))] + "" + "@ + jump\\t%0 + br\\t%a0" + [(set_attr "length" "2,6")] +) + +(define_insn "interrupt_return" + [(parallel + [(unspec_volatile [(const_int 0)] 0) + (return)])] + "" + { + return crx_prepare_push_pop_string (1); + } + [(set_attr "length" "14")] +) + +(define_insn "jump_to_imm" + [(set (pc) + (match_operand 0 "immediate_operand" "i"))] + "" + "br\\t%c0" + [(set_attr "length" "6")] +) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br\\t%l0" + [(set_attr "length" "6")] +) + +;; Function Prologue and Epilogue + +(define_expand "prologue" + [(const_int 0)] + "" + { + crx_expand_prologue (); + DONE; + } +) + +(define_insn "push_for_prologue" + [(parallel + [(set (reg:SI SP_REGNUM) + (minus:SI (reg:SI SP_REGNUM) + (match_operand:SI 0 "immediate_operand" "i")))])] + "reload_completed" + { + return crx_prepare_push_pop_string (0); + } + [(set_attr "length" "4")] +) + +(define_expand "epilogue" + [(return)] + "" + { + crx_expand_epilogue (); + DONE; + } +) + +(define_insn "pop_and_popret_return" + [(parallel + [(set (reg:SI SP_REGNUM) + (plus:SI (reg:SI SP_REGNUM) + (match_operand:SI 0 "immediate_operand" "i"))) + (use (reg:SI RA_REGNUM)) + (return)]) + ] + "reload_completed" + { + return crx_prepare_push_pop_string (1); + } + [(set_attr "length" "4")] +) + +(define_insn "popret_RA_return" + [(parallel + [(use (reg:SI RA_REGNUM)) + (return)]) + ] + "reload_completed" + "popret\\tra" + [(set_attr "length" "2")] +) + +;; Table Jump + +(define_insn "tablejump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r")) + (use (label_ref:SI (match_operand 1 "" "" )))] + "" + "jump\\t%0" + [(set_attr "length" "2")] +) + +;; Call Instructions + +(define_expand "call" + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand 1 "" ""))] + "" + { + emit_call_insn (gen_crx_call (operands[0], operands[1])); + DONE; + } +) + +(define_expand "crx_call" + [(parallel + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand 1 "" "")) + (clobber (reg:SI RA_REGNUM))])] + "" + "" +) + +(define_insn "crx_call_insn_branch" + [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) + (match_operand 1 "" "")) + (clobber (match_operand:SI 2 "register_operand" "+r"))] + "" + "bal\\tra, %a0" + [(set_attr "length" "6")] +) + +(define_insn "crx_call_insn_jump" + [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) + (match_operand 1 "" "")) + (clobber (match_operand:SI 2 "register_operand" "+r"))] + "" + "jal\\t%0" + [(set_attr "length" "2")] +) + +(define_insn "crx_call_insn_jalid" + [(call (mem:QI (mem:SI (plus:SI + (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")))) + (match_operand 2 "" "")) + (clobber (match_operand:SI 3 "register_operand" "+r"))] + "" + "jalid\\t%0, %1" + [(set_attr "length" "4")] +) + +;; Call Value Instructions + +(define_expand "call_value" + [(set (match_operand 0 "general_operand" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand 2 "" "")))] + "" + { + emit_call_insn (gen_crx_call_value (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_expand "crx_call_value" + [(parallel + [(set (match_operand 0 "general_operand" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "" ""))) + (clobber (reg:SI RA_REGNUM))])] + "" + "" +) + +(define_insn "crx_call_value_insn_branch" + [(set (match_operand 0 "" "=g") + (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) + (match_operand 2 "" ""))) + (clobber (match_operand:SI 3 "register_operand" "+r"))] + "" + "bal\\tra, %a1" + [(set_attr "length" "6")] +) + +(define_insn "crx_call_value_insn_jump" + [(set (match_operand 0 "" "=g") + (call (mem:QI (match_operand:SI 1 "register_operand" "r")) + (match_operand 2 "" ""))) + (clobber (match_operand:SI 3 "register_operand" "+r"))] + "" + "jal\\t%1" + [(set_attr "length" "2")] +) + +(define_insn "crx_call_value_insn_jalid" + [(set (match_operand 0 "" "=g") + (call (mem:QI (mem:SI (plus:SI + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))) + (match_operand 3 "" ""))) + (clobber (match_operand:SI 4 "register_operand" "+r"))] + "" + "jalid\\t%0, %1" + [(set_attr "length" "4")] +) + +;; Nop + +(define_insn "nop" + [(const_int 0)] + "" + "" +) + +;; Multiply and Accumulate Instructions + +(define_insn "<sPat>madsidi3" + [(set (match_operand:DI 0 "register_operand" "+k") + (plus:DI + (mult:DI (sz_xtnd:DI (match_operand:SI 1 "register_operand" "%r")) + (sz_xtnd:DI (match_operand:SI 2 "register_operand" "r"))) + (match_dup 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_MAC" + "mac<sPat>d\\t%2, %1" + [(set_attr "length" "4")] +) + +(define_insn "<sPat>madhisi3" + [(set (match_operand:SI 0 "register_operand" "+l") + (plus:SI + (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "%r")) + (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r"))) + (match_dup 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_MAC" + "mac<sPat>w\\t%2, %1" + [(set_attr "length" "4")] +) + +(define_insn "<sPat>madqihi3" + [(set (match_operand:HI 0 "register_operand" "+l") + (plus:HI + (mult:HI (sz_xtnd:HI (match_operand:QI 1 "register_operand" "%r")) + (sz_xtnd:HI (match_operand:QI 2 "register_operand" "r"))) + (match_dup 0))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_MAC" + "mac<sPat>b\\t%2, %1" + [(set_attr "length" "4")] +) + +;; Loop Instructions + +(define_expand "doloop_end" + [(use (match_operand 0 "" "")) ; loop pseudo + (use (match_operand 1 "" "")) ; iterations; zero if unknown + (use (match_operand 2 "" "")) ; max iterations + (use (match_operand 3 "" "")) ; loop level + (use (match_operand 4 "" ""))] ; label + "" + { + switch (GET_MODE (operands[0])) + { + case SImode: + emit_jump_insn (gen_doloop_end_si (operands[4], operands[0], operands[0])); + break; + case HImode: + emit_jump_insn (gen_doloop_end_hi (operands[4], operands[0], operands[0])); + break; + case QImode: + emit_jump_insn (gen_doloop_end_qi (operands[4], operands[0], operands[0])); + break; + default: + FAIL; + } + DONE; + } +) + +(define_insn "doloop_end_<mode>" + [(set (pc) + (if_then_else (ne (match_operand:CRXIM 1 "register_operand" "r,m") + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_operand:CRXIM 2 "register_operand" "=r,m") (plus:CRXIM (match_dup 1) (const_int -1))) + (clobber (match_scratch:CRXIM 3 "=X,r")) + (clobber (reg:CC CC_REGNUM))] + "" + "@ + dbnz<tIsa>\\t%1, %l0 + load<tIsa>\\t%1, %3\;add<tIsa>\\t$-1, %3\;stor<tIsa>\\t%3, %1\;bne\\t%l0" + [(set_attr "length" "6, 12")] +) diff --git a/gcc/config/crx/crx.opt b/gcc/config/crx/crx.opt new file mode 100644 index 0000000..9abd3c4 --- /dev/null +++ b/gcc/config/crx/crx.opt @@ -0,0 +1,28 @@ +; Options for the National Semiconductor CRX port of the compiler. + +; Copyright (C) 2005 Free Software Foundation, Inc. +; +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 2, 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 COPYING. If not, write to the Free +; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +; 02110-1301, USA. + +mmac +Target Report Mask(MAC) +Support multiply accumulate instructions + +mno-push-args +Target Report RejectNegative Mask(NO_PUSH_ARGS) +Do not use push to store function arguments diff --git a/gcc/config/crx/t-crx b/gcc/config/crx/t-crx new file mode 100644 index 0000000..012fad1 --- /dev/null +++ b/gcc/config/crx/t-crx @@ -0,0 +1,19 @@ +# CRX Target Makefile + +# Mingw specific compilation fixes +USE_COLLECT2 = +STMP_FIXINC = + +# Software emulation for integer div and mod +LIB2FUNCS_EXTRA = $(srcdir)/config/udivmodsi4.c $(srcdir)/config/udivmod.c $(srcdir)/config/divmod.c + +# Build the floating point emulation libraries. +FPBIT = fp-bit.c +DPBIT = dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + cat $(srcdir)/config/fp-bit.c > dp-bit.c |