diff --git gcc/config/nds32/constants.md gcc/config/nds32/constants.md new file mode 100644 index 0000000..af51117 --- /dev/null +++ gcc/config/nds32/constants.md @@ -0,0 +1,55 @@ +;; Constant defintions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 +;; . + + +;; Register numbers. +(define_constants + [(R8_REGNUM 8) + (TA_REGNUM 15) + (FP_REGNUM 28) + (GP_REGNUM 29) + (LP_REGNUM 30) + (SP_REGNUM 31) + ]) + + +;; The unpec operation index. +(define_c_enum "unspec_element" [ + UNSPEC_STACK_PUSH_MULTIPLE + UNSPEC_STACK_POP_MULTIPLE + UNSPEC_STACK_V3PUSH + UNSPEC_STACK_V3POP + UNSPEC_FUNC_RETURN +]) + + +;; The unspec_volatile operation index. +(define_c_enum "unspec_volatile_element" [ + UNSPEC_VOLATILE_ISYNC + UNSPEC_VOLATILE_ISB + UNSPEC_VOLATILE_MFSR + UNSPEC_VOLATILE_MFUSR + UNSPEC_VOLATILE_MTSR + UNSPEC_VOLATILE_MTUSR + UNSPEC_VOLATILE_SETGIE_EN + UNSPEC_VOLATILE_SETGIE_DIS +]) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/constraints.md gcc/config/nds32/constraints.md new file mode 100644 index 0000000..40af0ca --- /dev/null +++ gcc/config/nds32/constraints.md @@ -0,0 +1,248 @@ +;; Constraint definitions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 16.8.7 Defining Machine-Specific Constraints for detail. + +;; NO contrains can be prefixed with: E F V X g i m n o p r s +;; Machine-dependent integer: I J K L M N O P +;; Machine-dependent floating: G H + + +(define_register_constraint "w" "(TARGET_ISA_V3 || TARGET_ISA_V3M) ? LOW_REGS : NO_REGS" + "LOW register class $r0 ~ $r7 constraint for V3 ISA") + +(define_register_constraint "l" "LOW_REGS" + "LOW register class $r0 ~ $r7") + +(define_register_constraint "d" "MIDDLE_REGS" + "MIDDLE register class $r0 ~ $r11, $r16 ~ $r19") + +(define_register_constraint "h" "HIGH_REGS" + "HIGH register class $r12 ~ $r14, $r20 ~ $r31") + + +(define_register_constraint "t" "R15_TA_REG" + "Temporary Assist register $ta (i.e. $r15)") + +(define_register_constraint "k" "STACK_REG" + "Stack register $sp") + + +(define_constraint "Iu03" + "Unsigned immediate 3-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 3) && ival >= 0"))) + +(define_constraint "Iu04" + "Unsigned immediate 4-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 4) && ival >= 0"))) + +(define_constraint "Is05" + "Signed immediate 5-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 4) && ival >= -(1 << 4)"))) + +(define_constraint "Iu05" + "Unsigned immediate 5-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 5) && ival >= 0"))) + +;; Ip05 is special and dedicated for v3 movpi45 instruction. +;; movpi45 has imm5u field but the range is 16 ~ 47. +(define_constraint "Ip05" + "Unsigned immediate 5-bit value for movpi45 instruction with range 16-47" + (and (match_code "const_int") + (match_test "ival < ((1 << 5) + 16) + && ival >= (0 + 16) + && (TARGET_ISA_V3 || TARGET_ISA_V3M)"))) + +(define_constraint "Iu06" + "Unsigned immediate 6-bit value constraint for addri36.sp instruction" + (and (match_code "const_int") + (match_test "ival < (1 << 6) + && ival >= 0 + && (ival % 4 == 0) + && (TARGET_ISA_V3 || TARGET_ISA_V3M)"))) + +(define_constraint "Iu08" + "Unsigned immediate 8-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 8) && ival >= 0"))) + +(define_constraint "Iu09" + "Unsigned immediate 9-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 9) && ival >= 0"))) + + +(define_constraint "Is10" + "Signed immediate 10-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 9) && ival >= -(1 << 9)"))) + +(define_constraint "Is11" + "Signed immediate 11-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 10) && ival >= -(1 << 10)"))) + + +(define_constraint "Is15" + "Signed immediate 15-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 14) && ival >= -(1 << 14)"))) + +(define_constraint "Iu15" + "Unsigned immediate 15-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 15) && ival >= 0"))) + + +;; Ic15 is special and dedicated for performance extension +;; 'bclr' (single-bit-clear) instruction. +;; It is used in andsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'bclr' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'andi' instruction.) +(define_constraint "Ic15" + "A constant which is not in the range of imm15u but ok for bclr instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_bclr_p (ival)"))) + +;; Ie15 is special and dedicated for performance extension +;; 'bset' (single-bit-set) instruction. +;; It is used in iorsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'bset' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'ori' instruction.) +(define_constraint "Ie15" + "A constant which is not in the range of imm15u but ok for bset instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_bset_p (ival)"))) + +;; It15 is special and dedicated for performance extension +;; 'btgl' (single-bit-toggle) instruction. +;; It is used in xorsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'btgl' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'xori' instruction.) +(define_constraint "It15" + "A constant which is not in the range of imm15u but ok for btgl instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_btgl_p (ival)"))) + + +;; Ii15 is special and dedicated for v3 isa +;; 'bitci' (bit-clear-immediate) instruction. +;; It is used in andsi3 pattern and recognized for the immediate whose +;; (~ival) value is in the range of imm15u and OK for 'bitci' instruction. +;; For example, 'andi $r0,$r0,0xfffffffc' can be presented +; with 'bitci $r0,$r0,3'. +(define_constraint "Ii15" + "A constant whose compliment value is in the range of imm15u + and ok for bitci instruction" + (and (match_code "const_int") + (match_test "nds32_can_use_bitci_p (ival)"))) + + +(define_constraint "Is16" + "Signed immediate 16-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 15) && ival >= -(1 << 15)"))) + +(define_constraint "Is17" + "Signed immediate 17-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 16) && ival >= -(1 << 16)"))) + + +(define_constraint "Is19" + "Signed immediate 19-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 18) && ival >= -(1 << 18)"))) + + +(define_constraint "Is20" + "Signed immediate 20-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 19) && ival >= -(1 << 19)"))) + + +(define_constraint "Ispl" + "The immediate value that need to be split" + (and (match_code "const_int") + (match_test "(ival & 0xfff) != 0"))) + +(define_constraint "Ihig" + "The immediate value that can be simply set high 20-bit" + (and (match_code "const_int") + (match_test "(ival != 0) && ((ival & 0xfff) == 0)"))) + + +(define_constraint "Izeb" + "The immediate value 0xff" + (and (match_code "const_int") + (match_test "(ival == 0xff)"))) + +(define_constraint "Ixls" + "The immediate value 0x01" + (and (match_code "const_int") + (match_test "TARGET_PERF_EXT && (ival == 0x1)"))) + +(define_constraint "Ix11" + "The immediate value 0x7ff" + (and (match_code "const_int") + (match_test "TARGET_PERF_EXT && (ival == 0x7ff)"))) + +(define_constraint "Ibms" + "The immediate value with power of 2" + (and (match_code "const_int") + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) + && (floor_log2 (ival) < 8) + && (ival > 0) + && (ival == (1 << floor_log2 (ival)))"))) + +(define_constraint "Ifex" + "The immediate value with power of 2 minus 1" + (and (match_code "const_int") + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) + && (ival < 256) + && (ival > 0) + && (floor_log2 (ival + 1) - 1 < 8) + && ((ival + 1) == (1 << floor_log2 (ival + 1)))"))) + + +(define_memory_constraint "U33" + "Memory constraint for 333 format" + (and (match_code "mem") + (match_test "nds32_mem_format (op) == ADDRESS_LO_REG_IMM3U"))) + +(define_memory_constraint "U45" + "Memory constraint for 45 format" + (and (match_code "mem") + (match_test "nds32_mem_format (op) == ADDRESS_REG"))) + +(define_memory_constraint "U37" + "Memory constraint for 37 format" + (and (match_code "mem") + (match_test "nds32_mem_format (op) == ADDRESS_SP_IMM7U + || nds32_mem_format (op) == ADDRESS_FP_IMM7U"))) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/iterators.md gcc/config/nds32/iterators.md new file mode 100644 index 0000000..6ec5196 --- /dev/null +++ gcc/config/nds32/iterators.md @@ -0,0 +1,55 @@ +;; Code and mode itertator and attribute definitions +;; of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 +;; . + +;;---------------------------------------------------------------------------- +;; Mode iterators. +;;---------------------------------------------------------------------------- + +;; A list of integer modes that are up to one word long. +(define_mode_iterator QIHISI [QI HI SI]) + +;; A list of integer modes that are up to one half-word long. +(define_mode_iterator QIHI [QI HI]) + +;; A list of the modes that are up to double-word long. +(define_mode_iterator DIDF [DI DF]) + + +;;---------------------------------------------------------------------------- +;; Mode attributes. +;;---------------------------------------------------------------------------- + +(define_mode_attr size [(QI "b") (HI "h") (SI "w")]) + +(define_mode_attr byte [(QI "1") (HI "2") (SI "4")]) + + +;;---------------------------------------------------------------------------- +;; Code iterators. +;;---------------------------------------------------------------------------- + + +;;---------------------------------------------------------------------------- +;; Code attributes. +;;---------------------------------------------------------------------------- + + +;;---------------------------------------------------------------------------- diff --git gcc/config/nds32/nds32-modes.def gcc/config/nds32/nds32-modes.def new file mode 100644 index 0000000..9d32ada --- /dev/null +++ gcc/config/nds32/nds32-modes.def @@ -0,0 +1,21 @@ +/* Extra machine modes of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 + . */ + +/* So far, there is no need to define any modes for nds32 target. */ diff --git gcc/config/nds32/nds32-opts.h gcc/config/nds32/nds32-opts.h new file mode 100644 index 0000000..86d8b4f --- /dev/null +++ gcc/config/nds32/nds32-opts.h @@ -0,0 +1,35 @@ +/* Definitions for option handling of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 nds32_OPTS_H +#define nds32_OPTS_H + +#define NDS32_DEFAULT_CACHE_BLOCK_SIZE 16 +#define NDS32_DEFAULT_ISR_VECTOR_SIZE (TARGET_ISA_V3 ? 4 : 16) + +/* The various ANDES ISA. */ +enum nds32_arch_type +{ + ARCH_V2, + ARCH_V3, + ARCH_V3M +}; + +#endif diff --git gcc/config/nds32/nds32-protos.h gcc/config/nds32/nds32-protos.h new file mode 100644 index 0000000..a14ee99 --- /dev/null +++ gcc/config/nds32/nds32-protos.h @@ -0,0 +1,114 @@ +/* Prototypes for exported functions of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 + . */ + + +/* ------------------------------------------------------------------------ */ + +/* Defining Data Structures for Per-function Information. */ + +extern void nds32_init_expanders (void); + + +/* Register Usage. */ + +/* -- How Values Fit in Registers. */ + +extern int nds32_hard_regno_nregs (int, enum machine_mode); +extern int nds32_hard_regno_mode_ok (int, enum machine_mode); + + +/* Register Classes. */ + +extern enum reg_class nds32_regno_reg_class (int); + + +/* Stack Layout and Calling Conventions. */ + +/* -- Basic Stack Layout. */ + +extern rtx nds32_return_addr_rtx (int, rtx); + +/* -- Eliminating Frame Pointer and Arg Pointer. */ + +extern HOST_WIDE_INT nds32_initial_elimination_offset (unsigned int, + unsigned int); + +/* -- Passing Arguments in Registers. */ + +extern void nds32_init_cumulative_args (CUMULATIVE_ARGS *, + tree, rtx, tree, int); + +/* -- Function Entry and Exit. */ + +extern void nds32_expand_prologue (void); +extern void nds32_expand_epilogue (void); +extern void nds32_expand_prologue_v3push (void); +extern void nds32_expand_epilogue_v3pop (void); + +/* ------------------------------------------------------------------------ */ + +/* Auxiliary functions for auxiliary macros in nds32.h. */ + +extern bool nds32_ls_333_p (rtx, rtx, rtx, enum machine_mode); + +/* Auxiliary functions for expanding rtl used in nds32.multiple.md. */ + +extern rtx nds32_expand_load_multiple (int, int, rtx, rtx); +extern rtx nds32_expand_store_multiple (int, int, rtx, rtx); +extern int nds32_expand_movmemqi (rtx, rtx, rtx, rtx); + +/* Auxiliary functions for bit operation detection. */ + +extern int nds32_can_use_bclr_p (int); +extern int nds32_can_use_bset_p (int); +extern int nds32_can_use_btgl_p (int); + +extern int nds32_can_use_bitci_p (int); + +/* Auxiliary function for 'Computing the Length of an Insn'. */ + +extern int nds32_adjust_insn_length (rtx, int); + +/* Auxiliary functions for FP_AS_GP detection. */ + +extern bool nds32_symbol_load_store_p (rtx); +extern int nds32_fp_as_gp_check_available (void); + +/* Auxiliary functions for jump table generation. */ + +extern const char *nds32_output_casesi_pc_relative (rtx *); +extern const char *nds32_output_casesi (rtx *); + +/* Auxiliary functions to identify 16 bit addresing mode. */ + +extern enum nds32_16bit_address_type nds32_mem_format (rtx); + +/* Auxiliary functions to output assembly code. */ + +extern const char *nds32_output_16bit_store (rtx *, int); +extern const char *nds32_output_16bit_load (rtx *, int); +extern const char *nds32_output_32bit_store (rtx *, int); +extern const char *nds32_output_32bit_load (rtx *, int); + +/* Auxiliary functions to decide output alignment or not. */ + +extern int nds32_target_alignment (rtx); + +/* ------------------------------------------------------------------------ */ diff --git gcc/config/nds32/nds32.doubleword.md gcc/config/nds32/nds32.doubleword.md new file mode 100644 index 0000000..c44ff36 --- /dev/null +++ gcc/config/nds32/nds32.doubleword.md @@ -0,0 +1,391 @@ +;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 +;; . + + +;; ------------------------------------------------------------- +;; Move DImode/DFmode instructions. +;; ------------------------------------------------------------- + + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" +{ + /* Need to force register if mem <- !reg. */ + if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1])) + operands[1] = force_reg (DImode, operands[1]); +}) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" +{ + /* Need to force register if mem <- !reg. */ + if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1])) + operands[1] = force_reg (DFmode, operands[1]); +}) + + +(define_insn "move_" + [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m") + (match_operand:DIDF 1 "general_operand" " r, i, m, r"))] + "" +{ + rtx addr; + rtx otherops[5]; + + switch (which_alternative) + { + case 0: + return "movd44\t%0, %1"; + + case 1: + /* reg <- const_int, we ask gcc to split instruction. */ + return "#"; + + case 2: + /* Refer to nds32_legitimate_address_p() in nds32.c, + we only allow "reg", "symbol_ref", "const", and "reg + const_int" + as address rtx for DImode/DFmode memory access. */ + addr = XEXP (operands[1], 0); + + otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + otherops[2] = addr; + + if (REG_P (addr)) + { + /* (reg) <- (mem (reg)) */ + output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops); + } + else if (GET_CODE (addr) == PLUS) + { + /* (reg) <- (mem (plus (reg) (const_int))) */ + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (REG_P (op0)) + { + otherops[2] = op0; + otherops[3] = op1; + otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode); + } + else + { + otherops[2] = op1; + otherops[3] = op0; + otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode); + } + + /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */ + if (REGNO (otherops[0]) != REGNO (otherops[2])) + { + output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops); + output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops); + } + else + { + output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops); + output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops); + } + } + else + { + /* (reg) <- (mem (symbol_ref ...)) + (reg) <- (mem (const ...)) */ + output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops); + output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops); + } + + /* We have already used output_asm_insn() by ourself, + so return an empty string. */ + return ""; + + case 3: + /* Refer to nds32_legitimate_address_p() in nds32.c, + we only allow "reg", "symbol_ref", "const", and "reg + const_int" + as address rtx for DImode/DFmode memory access. */ + addr = XEXP (operands[0], 0); + + otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1])); + otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + otherops[2] = addr; + + if (REG_P (addr)) + { + /* (mem (reg)) <- (reg) */ + output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops); + } + else if (GET_CODE (addr) == PLUS) + { + /* (mem (plus (reg) (const_int))) <- (reg) */ + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (REG_P (op0)) + { + otherops[2] = op0; + otherops[3] = op1; + otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode); + } + else + { + otherops[2] = op1; + otherops[3] = op0; + otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode); + } + + /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */ + if (REGNO (otherops[0]) != REGNO (otherops[2])) + { + output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops); + output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops); + } + else + { + output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops); + output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops); + } + } + else + { + /* (mem (symbol_ref ...)) <- (reg) + (mem (const ...)) <- (reg) */ + output_asm_insn ("swi.gp\t%0, [ + %2]", otherops); + output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops); + } + + /* We have already used output_asm_insn() by ourself, + so return an empty string. */ + return ""; + + default: + gcc_unreachable (); + } +} + [(set_attr "type" "move,move,move,move") + (set_attr "length" " 4, 16, 8, 8")]) + +(define_split + [(set (match_operand:DIDF 0 "register_operand" "") + (match_operand:DIDF 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] +{ + /* Construct lowpart rtx. */ + operands[2] = gen_lowpart (SImode, operands[0]); + operands[3] = gen_lowpart (SImode, operands[1]); + + /* Construct highpart rtx. */ + /* Note that operands[1] can be VOIDmode constant, + so we need to use gen_highpart_mode(). + Refer to gcc/emit-rtl.c for more information. */ + operands[4] = gen_highpart (SImode, operands[0]); + operands[5] = gen_highpart_mode (SImode, + GET_MODE (operands[0]), operands[1]); +}) + +(define_split + [(set (match_operand:DIDF 0 "register_operand" "") + (match_operand:DIDF 1 "register_operand" ""))] + "reload_completed + && (TARGET_ISA_V2 || !TARGET_16_BIT)" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] +{ + operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart (SImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + + /* Handle a partial overlap. */ + if (rtx_equal_p (operands[0], operands[3])) + { + rtx tmp0 = operands[0]; + rtx tmp1 = operands[1]; + + operands[0] = operands[2]; + operands[1] = operands[3]; + operands[2] = tmp0; + operands[3] = tmp1; + } +}) + +;; ------------------------------------------------------------- +;; Boolean DImode instructions. +;; ------------------------------------------------------------- + +;; Boolean and,ior,xor insns. + +;; 'and' operation. + +(define_expand "anddi3" + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")))] + "" + "" +) + +; Use '#' to split instruction. +(define_insn "*anddi3_insn" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (and:DI (match_operand:DI 1 "register_operand" " %0, r") + (match_operand:DI 2 "register_operand" " r, r")))] + "" + "#" + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +; The zero extend of operand 2 clears the high word of the output operand. +(define_insn_and_split "*anddi_zesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (and:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, r")))] + "" + "#" + "reload_completed" + [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) (const_int 0))] +{ + operands[3] = gen_highpart (SImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); +} + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +(define_insn "*anddi_sesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (and:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, r")))] + "" + "#" + [(set_attr "length" "8")]) + + +;; 'ior' operation. + +(define_expand "iordi3" + [(set (match_operand:DI 0 "register_operand" "") + (ior:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")))] + "" + "" +) + +; Use '#' to split instruction. +(define_insn "*iordi3_insn" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (ior:DI (match_operand:DI 1 "register_operand" " %0, r") + (match_operand:DI 2 "register_operand" " r, r")))] + "" + "#" + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +(define_insn "*iordi_zesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (ior:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, ?r")))] + "" + "#" + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +(define_insn "*iordi_sesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (ior:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, r")))] + "" + "#" + [(set_attr "length" "8")]) + + +;; 'xor' operation. + +(define_expand "xordi3" + [(set (match_operand:DI 0 "register_operand" "") + (xor:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")))] + "" + "" +) + +; Use '#' to split instruction. +(define_insn "*xordi3_insn" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (xor:DI (match_operand:DI 1 "register_operand" " %0, r") + (match_operand:DI 2 "register_operand" " r, r")))] + "" + "#" + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +(define_insn "*xordi_zesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (xor:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, ?r")))] + "" + "#" + [(set_attr "length" "8")]) + +; Use '#' to split instruction. +(define_insn "*xordi_sesidi_di" + [(set (match_operand:DI 0 "register_operand" "=&r, &r") + (xor:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) + (match_operand:DI 1 "register_operand" " 0, r")))] + "" + "#" + [(set_attr "length" "8")]) + + +;; Split up double word logical operations. + +;; Split up simple DImode logical operations. Simply perform the logical +;; operation on the upper and lower halves of the registers. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operator:DI 6 "nds32_logical_binary_operator" + [(match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")]))] + "reload_completed" + [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) + (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))] +{ + /* Note that operands[0], operands[1], + and operands[2] will be assigned new rtx, + so be careful of the order when using them. */ + + operands[3] = gen_highpart (SImode, operands[0]); + operands[0] = gen_lowpart (SImode, operands[0]); + + operands[4] = gen_highpart (SImode, operands[1]); + operands[1] = gen_lowpart (SImode, operands[1]); + + operands[5] = gen_highpart (SImode, operands[2]); + operands[2] = gen_lowpart (SImode, operands[2]); +}) + + +;; ------------------------------------------------------------- diff --git gcc/config/nds32/nds32.intrinsic.md gcc/config/nds32/nds32.intrinsic.md new file mode 100644 index 0000000..4ee2d85 --- /dev/null +++ gcc/config/nds32/nds32.intrinsic.md @@ -0,0 +1,97 @@ +;; Intrinsic patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 +;; . + +;; ------------------------------------------------------------------------ + +;; Register Transfer. + +(define_insn "unspec_volatile_mfsr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFSR))] + "" + "mfsr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mfusr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFUSR))] + "" + "mfusr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mtsr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTSR)] + "" + "mtsr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mtusr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTUSR)] + "" + "mtusr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +;; ------------------------------------------------------------------------ + +;; Interrupt Instructions. + +(define_insn "unspec_volatile_setgie_en" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_EN)] + "" + "setgie.e" + [(set_attr "type" "misc")] +) + +(define_insn "unspec_volatile_setgie_dis" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_DIS)] + "" + "setgie.d" + [(set_attr "type" "misc")] +) + +;; ------------------------------------------------------------------------ + +;; Cache Synchronization Instructions + +(define_insn "unspec_volatile_isync" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_ISYNC)] + "" + "isync\t%0" + [(set_attr "type" "misc")] +) + +(define_insn "unspec_volatile_isb" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_ISB)] + "" + "isb" + [(set_attr "type" "misc")] +) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32.multiple.md gcc/config/nds32/nds32.multiple.md new file mode 100644 index 0000000..1b3e05b --- /dev/null +++ gcc/config/nds32/nds32.multiple.md @@ -0,0 +1,410 @@ +;; Load/Store Multiple patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation.for NDS32. +;; +;; 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 +;; . + + +;; Load Multiple Insns. +;; +;; opernads[0] is the first of the consecutive registers. +;; operands[1] is the first memory location. +;; operands[2] is the number of consecutive registers. + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" +{ + int maximum; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot + be used for register allocation), + using 8 registers for load_multiple may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers for load_multiple + under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + maximum = 4; + else + maximum = 8; + + /* Here are the conditions that must be all passed, + otherwise we have to FAIL this rtx generation: + 1. The number of consecutive registers must be integer. + 2. Maximum 4 or 8 registers for lmw.bi instruction + (based on this nds32.multiple.md design). + 3. Minimum 2 registers for lmw.bi instruction + (based on this nds32.multiple.md design). + 4. operands[0] must be register for sure. + 5. operands[1] must be memory for sure. + 6. Do not cross $r15 register because it is not allocatable. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > maximum + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != REG + || GET_CODE (operands[1]) != MEM + || REGNO (operands[0]) + INTVAL (operands[2]) > TA_REGNUM) + FAIL; + + /* For (mem addr), we force_reg on addr here, + so that nds32_expand_load_multiple can easily use it. */ + operands[3] = nds32_expand_load_multiple (REGNO (operands[0]), + INTVAL (operands[2]), + force_reg (SImode, + XEXP (operands[1], 0)), + operands[1]); +}) + +;; Ordinary Load Multiple. + +(define_insn "*lmwsi8" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28))))])] + "(XVECLEN (operands[0], 0) == 8)" + "lmw.bi\t%2, [%1], %9, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi7" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24))))])] + "(XVECLEN (operands[0], 0) == 7)" + "lmw.bi\t%2, [%1], %8, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi6" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20))))])] + "(XVECLEN (operands[0], 0) == 6)" + "lmw.bi\t%2, [%1], %7, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi5" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16))))])] + "(XVECLEN (operands[0], 0) == 5)" + "lmw.bi\t%2, [%1], %6, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi4" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] + "(XVECLEN (operands[0], 0) == 4)" + "lmw.bi\t%2, [%1], %5, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi3" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] + "(XVECLEN (operands[0], 0) == 3)" + "lmw.bi\t%2, [%1], %4, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi2" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4))))])] + "(XVECLEN (operands[0], 0) == 2)" + "lmw.bi\t%2, [%1], %3, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + + +;; Store Multiple Insns. +;; +;; operands[0] is the first memory location. +;; opernads[1] is the first of the consecutive registers. +;; operands[2] is the number of consecutive registers. + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" +{ + int maximum; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot + be used for register allocation), + using 8 registers for store_multiple may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers for store_multiple + under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + maximum = 4; + else + maximum = 8; + + /* Here are the conditions that must be all passed, + otherwise we have to FAIL this rtx generation: + 1. The number of consecutive registers must be integer. + 2. Maximum 4 or 8 registers for smw.bi instruction + (based on this nds32.multiple.md design). + 3. Minimum 2 registers for smw.bi instruction + (based on this nds32.multiple.md design). + 4. operands[0] must be memory for sure. + 5. operands[1] must be register for sure. + 6. Do not cross $r15 register because it is not allocatable. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > maximum + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != REG + || REGNO (operands[1]) + INTVAL (operands[2]) > TA_REGNUM) + FAIL; + + /* For (mem addr), we force_reg on addr here, + so that nds32_expand_store_multiple can easily use it. */ + operands[3] = nds32_expand_store_multiple (REGNO (operands[1]), + INTVAL (operands[2]), + force_reg (SImode, + XEXP (operands[0], 0)), + operands[0]); +}) + +;; Ordinary Store Multiple. + +(define_insn "*stmsi8" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 8)" + "smw.bi\t%2, [%1], %9, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi7" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 7)" + "smw.bi\t%2, [%1], %8, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi6" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 6)" + "smw.bi\t%2, [%1], %7, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi5" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 5)" + "smw.bi\t%2, [%1], %6, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi4" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 4)" + "smw.bi\t%2, [%1], %5, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi3" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 3)" + "smw.bi\t%2, [%1], %4, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi2" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 2)" + "smw.bi\t%2, [%1], %3, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +;; Move a block of memory if it is word aligned and MORE than 2 words long. +;; We could let this apply for blocks of less than this, but it clobbers so +;; many registers that there is then probably a better way. +;; +;; operands[0] is the destination block of memory. +;; operands[1] is the source block of memory. +;; operands[2] is the number of bytes to move. +;; operands[3] is the known shared alignment. + +(define_expand "movmemqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" +{ + if (nds32_expand_movmemqi (operands[0], + operands[1], + operands[2], + operands[3])) + DONE; + + FAIL; +}) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32.opt gcc/config/nds32/nds32.opt new file mode 100644 index 0000000..b7303e3 --- /dev/null +++ gcc/config/nds32/nds32.opt @@ -0,0 +1,98 @@ +; Options of Andes NDS32 cpu for GNU compiler +; Copyright (C) 2012-2013 Free Software Foundation, Inc. +; Contributed by Andes Technology Corporation. +; +; 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 +; . + +HeaderInclude +config/nds32/nds32-opts.h + +mbig-endian +Target Report RejectNegative Negative(mlittle-endian) Mask(BIG_ENDIAN) +Generate code in big-endian mode. + +mlittle-endian +Target Report RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN) +Generate code in little-endian mode. + +mreduced-regs +Target Report RejectNegative Negative(mfull-regs) Mask(REDUCED_REGS) +Use reduced-set registers for register allocation. + +mfull-regs +Target Report RejectNegative Negative(mreduced-regs) InverseMask(REDUCED_REGS) +Use full-set registers for register allocation. + +mcmov +Target Report Mask(CMOV) +Generate conditional move instructions. + +mperf-ext +Target Report Mask(PERF_EXT) +Generate performance extension instructions. + +mv3push +Target Report Mask(V3PUSH) +Generate v3 push25/pop25 instructions. + +m16-bit +Target Report Mask(16_BIT) +Generate 16-bit instructions. + +mgp-direct +Target Report Mask(GP_DIRECT) +Generate GP base instructions directly. + +misr-vector-size= +Target Report RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE) +Specify the size of each vector for interrupt handler. The valid value is 4 or 16. + +mcache-block-size= +Target Report RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE) +Specify the size of each cache block. The size is the power of 2 in bytes. The valid value is: 4, 8, 16, 32, 64, 128, 256, or 512. + +march= +Target RejectNegative Joined Enum(nds32_arch_type) Var(nds32_arch_option) Init(ARCH_V3) +Specify the name of the target architecture. The valid value is: v2, v3, or v3m. + +Enum +Name(nds32_arch_type) Type(enum nds32_arch_type) + +EnumValue +Enum(nds32_arch_type) String(v2) Value(ARCH_V2) + +EnumValue +Enum(nds32_arch_type) String(v3) Value(ARCH_V3) + +EnumValue +Enum(nds32_arch_type) String(v3m) Value(ARCH_V3M) + +mforce-fp-as-gp +Target Report RejectNegative Mask(FORCE_FP_AS_GP) +Prevent $fp being allocated during register allocation so that compiler is able to force using $fp to access static and global variables for code-size reduction. Then compiler will use special directives and code generation to guide linker doing fp-as-gp optimization (NOTE: This is link time optimization so make sure you pass '--relax' option to linker at linking stage). + +mforbid-fp-as-gp +Target Report RejectNegative Mask(FORBID_FP_AS_GP) +Forbid using $fp to access static and global variables. This option strictly forbids fp-as-gp optimization regardless of '-mforce-fp-as-gp'. + +mex9 +Target Report RejectNegative Mask(EX9) +Use special directives to guide linker doing ex9 optimization (NOTE: This is link time optimization so make sure you pass '--relax' and '--mex9' option to linker at linking stage). + +mno-ctor-dtor +Target Report RejectNegative +Disable constructor/destructor feature. diff --git gcc/config/nds32/nds32.peephole2.md gcc/config/nds32/nds32.peephole2.md new file mode 100644 index 0000000..c1f1f1f --- /dev/null +++ gcc/config/nds32/nds32.peephole2.md @@ -0,0 +1,160 @@ +;; define_peephole2 optimization patterns of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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 +;; . + + +;; Merge single move to sign_extend load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand")))))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3)))))] +) + +;; Merge single move to zero_extend load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand")))))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3)))))] +) + +;; Merge single move to load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:QIHISI 2 "register_operand" "") + (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand"))))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3))))] +) + +;; Merge single move to store. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand"))) + (match_operand:QIHISI 2 "register_operand" ""))] + "peep2_reg_dead_p (2, operands[0])" + [(set (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3))) + (match_dup 2))] +) + +;; ------------------------------------------------------------------------------------ + +;; Merge single addi to sign_extend load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 4 "immediate_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand")))))] + "peep2_reg_dead_p (2, operands[0]) + && CONST_INT_P (operands[4]) + && CONST_INT_P (operands[3]) + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" + [(set (match_dup 2) + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3)))))] +{ + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), + SImode); +}) + +;; Merge single addi to zero_extend load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 4 "immediate_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand")))))] + "peep2_reg_dead_p (2, operands[0]) + && CONST_INT_P (operands[4]) + && CONST_INT_P (operands[3]) + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" + [(set (match_dup 2) + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3)))))] +{ + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), + SImode); +}) + +;; Merge single addi to load. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 4 "immediate_operand" ""))) + (set (match_operand:QIHISI 2 "register_operand" "") + (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand"))))] + "peep2_reg_dead_p (2, operands[0]) + && CONST_INT_P (operands[4]) + && CONST_INT_P (operands[3]) + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" + [(set (match_dup 2) + (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3))))] +{ + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), + SImode); +}) + +;; Merge single addi to store. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 4 "immediate_operand" ""))) + (set (mem:QIHISI (plus:SI (match_dup 0) + (match_operand:SI 3 "immediate_operand"))) + (match_operand:QIHISI 2 "register_operand" ""))] + "peep2_reg_dead_p (2, operands[0]) + && CONST_INT_P (operands[4]) + && CONST_INT_P (operands[3]) + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" + [(set (mem:QIHISI (plus:SI (match_dup 1) + (match_dup 3))) + (match_dup 2))] +{ + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), + SImode); +}) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32_intrinsic.h gcc/config/nds32/nds32_intrinsic.h new file mode 100644 index 0000000..33064a9 --- /dev/null +++ gcc/config/nds32/nds32_intrinsic.h @@ -0,0 +1,37 @@ +/* Intrinsic definitions of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _NDS32_INTRINSIC_H +#define _NDS32_INTRINSIC_H + +enum nds32_intrinsic_registers +{ + __NDS32_REG_PSW__ = 1024, + __NDS32_REG_IPSW__, + __NDS32_REG_ITYPE__, + __NDS32_REG_IPC__ +}; + +#endif /* nds32_intrinsic.h */ diff --git gcc/config/nds32/pipelines.md gcc/config/nds32/pipelines.md new file mode 100644 index 0000000..9c8c56b --- /dev/null +++ gcc/config/nds32/pipelines.md @@ -0,0 +1,29 @@ +;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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_automaton "nds32_machine") + +(define_cpu_unit "general_unit" "nds32_machine") + +(define_insn_reservation "simple_insn" 1 + (eq_attr "type" "unknown,load,store,move,alu,compare,branch,call,misc") + "general_unit") + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/predicates.md gcc/config/nds32/predicates.md new file mode 100644 index 0000000..12f7e68 --- /dev/null +++ gcc/config/nds32/predicates.md @@ -0,0 +1,179 @@ +;; Predicate definitions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; 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_predicate "nds32_equality_comparison_operator" + (match_code "eq,ne")) + +(define_predicate "nds32_greater_less_comparison_operator" + (match_code "gt,ge,lt,le")) + +(define_special_predicate "nds32_logical_binary_operator" + (match_code "and,ior,xor")) + +;; Reg, subreg(reg) or const_int. +(define_predicate "nds32_reg_or_int_operand" + (ior (match_operand 0 "immediate_operand") + (match_operand 0 "register_operand")) +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (REG_P (op)) + return true; + + if (GET_CODE (op) == CONST_INT) + return true; + return false; +}) + +(define_predicate "nds32_rimm15s_operand" + (match_operand 0 "general_operand") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + if (GET_CODE (op) == REG) + return true; + if (GET_CODE (op) != CONST_INT) + return false; + + return satisfies_constraint_Is15 (op); +}) + +(define_predicate "nds32_nonmemory_nonsymbol_operand" + (match_operand 0 "nonmemory_operand") +{ + switch (GET_CODE (op)) + { + case SYMBOL_REF: + case LABEL_REF: + case CONST: + return false; + default: + return true; + } +}) + +(define_predicate "nds32_symbolic_operand" + (match_code "const,symbol_ref,label_ref")) + +(define_predicate "nds32_reg_constant_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "const_int_operand"))) + +(define_predicate "nds32_imm5u_operand" + (match_operand 0 "immediate_operand") +{ + return satisfies_constraint_Iu05 (op); +}) + +(define_special_predicate "nds32_load_multiple_operation" + (match_code "parallel") +{ + HOST_WIDE_INT count; + int dest_regno; + rtx src_addr; + + int i; + rtx elt; + + /* Get the counts of elements in the parallel rtx. */ + count = XVECLEN (op, 0); + + /* Pick up the first element. */ + elt = XVECEXP (op, 0, 0); + + /* Perform some quick check for the first element in the parallel rtx. */ + if (GET_CODE (elt) != SET + || count <= 1 + || count > 8 + || GET_CODE (SET_DEST (elt)) != REG + || GET_CODE (SET_SRC (elt)) != MEM) + return false; + + dest_regno = REGNO (SET_DEST (elt)); + src_addr = XEXP (SET_SRC (elt), 0); + + /* Perform detail check for each element. */ + for (i = 0; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + /* Refer to nds32.multiple.md for more information + about following checking. */ + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != SImode + || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i) + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode + || (GET_CODE (src_addr) != REG && GET_CODE (src_addr) != PLUS)) + return false; + } + + return true; +}) + +(define_special_predicate "nds32_store_multiple_operation" + (match_code "parallel") +{ + HOST_WIDE_INT count; + int src_regno; + rtx dest_addr; + + int i; + rtx elt; + + /* Get the counts of elements in the parallel rtx. */ + count = XVECLEN (op, 0); + + /* Pick up the first element. */ + elt = XVECEXP (op, 0, 0); + + /* Perform some quick check for the first element in the parallel rtx. */ + if (GET_CODE (elt) != SET + || count <= 1 + || count > 8 + || GET_CODE (SET_SRC (elt)) != REG + || GET_CODE (SET_DEST (elt)) != MEM) + return false; + + src_regno = REGNO (SET_SRC (elt)); + dest_addr = XEXP (SET_DEST (elt), 0); + + /* Perform detail check for each element. */ + for (i = 0; i < count; i++) + { + elt = XVECEXP (op, 0, i); + + /* Refer to nds32.multiple.md for more information + about following checking. */ + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i) + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode + || (GET_CODE (dest_addr) != REG && GET_CODE (dest_addr) != PLUS)) + return false; + } + + return true; +}) +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/t-mlibs gcc/config/nds32/t-mlibs new file mode 100644 index 0000000..d770824 --- /dev/null +++ gcc/config/nds32/t-mlibs @@ -0,0 +1,30 @@ +# The multilib settings of Andes NDS32 cpu for GNU compiler +# Copyright (C) 2012-2013 Free Software Foundation, Inc. +# Contributed by Andes Technology Corporation. +# +# 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 +# . + +# We need to build following multilibs: +# -mlittle-endian +# -mbig-endian +# +# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the +# driver program which options are defaults for this target and thus +# do not need to be handled specially. +MULTILIB_OPTIONS = mlittle-endian/mbig-endian + +# ------------------------------------------------------------------------