summaryrefslogtreecommitdiff
path: root/gcc/config/nds32
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/nds32')
-rw-r--r--gcc/config/nds32/constants.md3
-rw-r--r--gcc/config/nds32/constraints.md2
-rw-r--r--gcc/config/nds32/iterators.md2
-rw-r--r--gcc/config/nds32/nds32-cost.c295
-rw-r--r--gcc/config/nds32/nds32-doubleword.md2
-rw-r--r--gcc/config/nds32/nds32-fp-as-gp.c97
-rw-r--r--gcc/config/nds32/nds32-intrinsic.c280
-rw-r--r--gcc/config/nds32/nds32-intrinsic.md2
-rw-r--r--gcc/config/nds32/nds32-isr.c629
-rw-r--r--gcc/config/nds32/nds32-md-auxiliary.c896
-rw-r--r--gcc/config/nds32/nds32-memory-manipulation.c193
-rw-r--r--gcc/config/nds32/nds32-modes.def2
-rw-r--r--gcc/config/nds32/nds32-multiple.md2
-rw-r--r--gcc/config/nds32/nds32-opts.h10
-rw-r--r--gcc/config/nds32/nds32-peephole2.md5
-rw-r--r--gcc/config/nds32/nds32-pipelines-auxiliary.c89
-rw-r--r--gcc/config/nds32/nds32-predicates.c431
-rw-r--r--gcc/config/nds32/nds32-protos.h44
-rw-r--r--gcc/config/nds32/nds32.c3110
-rw-r--r--gcc/config/nds32/nds32.h112
-rw-r--r--gcc/config/nds32/nds32.md254
-rw-r--r--gcc/config/nds32/nds32.opt30
-rw-r--r--gcc/config/nds32/nds32_intrinsic.h2
-rw-r--r--gcc/config/nds32/pipelines.md2
-rw-r--r--gcc/config/nds32/predicates.md10
-rw-r--r--gcc/config/nds32/t-mlibs16
-rw-r--r--gcc/config/nds32/t-nds3251
27 files changed, 3945 insertions, 2626 deletions
diff --git a/gcc/config/nds32/constants.md b/gcc/config/nds32/constants.md
index 2c317a98e2b..ea1cd4cf52b 100644
--- a/gcc/config/nds32/constants.md
+++ b/gcc/config/nds32/constants.md
@@ -1,5 +1,5 @@
;; Constant defintions of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
@@ -41,6 +41,7 @@
UNSPEC_VOLATILE_MTUSR
UNSPEC_VOLATILE_SETGIE_EN
UNSPEC_VOLATILE_SETGIE_DIS
+ UNSPEC_VOLATILE_POP25_RETURN
])
;; ------------------------------------------------------------------------
diff --git a/gcc/config/nds32/constraints.md b/gcc/config/nds32/constraints.md
index 1177144a426..d84583b2645 100644
--- a/gcc/config/nds32/constraints.md
+++ b/gcc/config/nds32/constraints.md
@@ -1,5 +1,5 @@
;; Constraint definitions of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/iterators.md b/gcc/config/nds32/iterators.md
index cda049038d9..892b4e0b470 100644
--- a/gcc/config/nds32/iterators.md
+++ b/gcc/config/nds32/iterators.md
@@ -1,6 +1,6 @@
;; Code and mode itertator and attribute definitions
;; of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/nds32-cost.c b/gcc/config/nds32/nds32-cost.c
new file mode 100644
index 00000000000..c6ec5ab845a
--- /dev/null
+++ b/gcc/config/nds32/nds32-cost.c
@@ -0,0 +1,295 @@
+/* Subroutines used for calculate rtx costs of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+bool
+nds32_rtx_costs_impl (rtx x,
+ int code,
+ int outer_code,
+ int opno ATTRIBUTE_UNUSED,
+ int *total,
+ bool speed)
+{
+ /* According to 'speed', goto suitable cost model section. */
+ if (speed)
+ goto performance_cost;
+ else
+ goto size_cost;
+
+
+performance_cost:
+ /* This is section for performance cost model. */
+
+ /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
+ We treat it as 4-cycle cost for each instruction
+ under performance consideration. */
+ switch (code)
+ {
+ case SET:
+ /* For 'SET' rtx, we need to return false
+ so that it can recursively calculate costs. */
+ return false;
+
+ case USE:
+ /* Used in combine.c as a marker. */
+ *total = 0;
+ break;
+
+ case MULT:
+ *total = COSTS_N_INSNS (1);
+ break;
+
+ case DIV:
+ case UDIV:
+ case MOD:
+ case UMOD:
+ *total = COSTS_N_INSNS (7);
+ break;
+
+ default:
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+
+ return true;
+
+
+size_cost:
+ /* This is section for size cost model. */
+
+ /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
+ We treat it as 4-byte cost for each instruction
+ under code size consideration. */
+ switch (code)
+ {
+ case SET:
+ /* For 'SET' rtx, we need to return false
+ so that it can recursively calculate costs. */
+ return false;
+
+ case USE:
+ /* Used in combine.c as a marker. */
+ *total = 0;
+ break;
+
+ case CONST_INT:
+ /* All instructions involving constant operation
+ need to be considered for cost evaluation. */
+ if (outer_code == SET)
+ {
+ /* (set X imm5s), use movi55, 2-byte cost.
+ (set X imm20s), use movi, 4-byte cost.
+ (set X BIG_INT), use sethi/ori, 8-byte cost. */
+ if (satisfies_constraint_Is05 (x))
+ *total = COSTS_N_INSNS (1) - 2;
+ else if (satisfies_constraint_Is20 (x))
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else if (outer_code == PLUS || outer_code == MINUS)
+ {
+ /* Possible addi333/subi333 or subi45/addi45, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu05 (x))
+ *total = COSTS_N_INSNS (1) - 2;
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ else if (outer_code == ASHIFT)
+ {
+ /* Possible slli333, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu03 (x))
+ *total = COSTS_N_INSNS (1) - 2;
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ else if (outer_code == ASHIFTRT || outer_code == LSHIFTRT)
+ {
+ /* Possible srai45 or srli45, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu05 (x))
+ *total = COSTS_N_INSNS (1) - 2;
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ else
+ {
+ /* For other cases, simply set it 4-byte cost. */
+ *total = COSTS_N_INSNS (1);
+ }
+ break;
+
+ case CONST_DOUBLE:
+ /* It requires high part and low part processing, set it 8-byte cost. */
+ *total = COSTS_N_INSNS (2);
+ break;
+
+ default:
+ /* For other cases, generally we set it 4-byte cost
+ and stop resurively traversing. */
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+
+ return true;
+}
+
+int
+nds32_address_cost_impl (rtx address,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ addr_space_t as ATTRIBUTE_UNUSED,
+ bool speed)
+{
+ rtx plus0, plus1;
+ enum rtx_code code;
+
+ code = GET_CODE (address);
+
+ /* According to 'speed', goto suitable cost model section. */
+ if (speed)
+ goto performance_cost;
+ else
+ goto size_cost;
+
+performance_cost:
+ /* This is section for performance cost model. */
+
+ /* FALLTHRU, currently we use same cost model as size_cost. */
+
+size_cost:
+ /* This is section for size cost model. */
+
+ switch (code)
+ {
+ case POST_MODIFY:
+ case POST_INC:
+ case POST_DEC:
+ /* We encourage that rtx contains
+ POST_MODIFY/POST_INC/POST_DEC behavior. */
+ return 0;
+
+ case SYMBOL_REF:
+ /* We can have gp-relative load/store for symbol_ref.
+ Have it 4-byte cost. */
+ return COSTS_N_INSNS (1);
+
+ case CONST:
+ /* It is supposed to be the pattern (const (plus symbol_ref const_int)).
+ Have it 4-byte cost. */
+ return COSTS_N_INSNS (1);
+
+ case REG:
+ /* Simply return 4-byte costs. */
+ return COSTS_N_INSNS (1);
+
+ case PLUS:
+ /* We do not need to check if the address is a legitimate address,
+ because this hook is never called with an invalid address.
+ But we better check the range of
+ const_int value for cost, if it exists. */
+ plus0 = XEXP (address, 0);
+ plus1 = XEXP (address, 1);
+
+ if (REG_P (plus0) && CONST_INT_P (plus1))
+ {
+ /* If it is possible to be lwi333/swi333 form,
+ make it 2-byte cost. */
+ if (satisfies_constraint_Iu05 (plus1))
+ return (COSTS_N_INSNS (1) - 2);
+ else
+ return COSTS_N_INSNS (1);
+ }
+
+ /* For other 'plus' situation, make it cost 4-byte. */
+ return COSTS_N_INSNS (1);
+
+ default:
+ break;
+ }
+
+ return COSTS_N_INSNS (4);
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-doubleword.md b/gcc/config/nds32/nds32-doubleword.md
index e68bfece5e1..f98dc7992b2 100644
--- a/gcc/config/nds32/nds32-doubleword.md
+++ b/gcc/config/nds32/nds32-doubleword.md
@@ -1,5 +1,5 @@
;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/nds32-fp-as-gp.c b/gcc/config/nds32/nds32-fp-as-gp.c
new file mode 100644
index 00000000000..e7b7c7071b1
--- /dev/null
+++ b/gcc/config/nds32/nds32-fp-as-gp.c
@@ -0,0 +1,97 @@
+/* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Function to determine whether it is worth to do fp_as_gp optimization.
+ Return 0: It is NOT worth to do fp_as_gp optimization.
+ Return 1: It is APPROXIMATELY worth to do fp_as_gp optimization.
+ Note that if it is worth to do fp_as_gp optimization,
+ we MUST set FP_REGNUM ever live in this function. */
+int
+nds32_fp_as_gp_check_available (void)
+{
+ /* By default we return 0. */
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-intrinsic.c b/gcc/config/nds32/nds32-intrinsic.c
new file mode 100644
index 00000000000..9f0851d9f77
--- /dev/null
+++ b/gcc/config/nds32/nds32-intrinsic.c
@@ -0,0 +1,280 @@
+/* Intrinsic functions of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Function to expand builtin function for
+ '[(unspec_volatile [(reg)])]'. */
+static rtx
+nds32_expand_builtin_null_ftype_reg (enum insn_code icode,
+ tree exp, rtx target)
+{
+ /* Mapping:
+ ops[0] <--> value0 <--> arg0 */
+ struct expand_operand ops[1];
+ tree arg0;
+ rtx value0;
+
+ /* Grab the incoming arguments and extract its rtx. */
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ value0 = expand_normal (arg0);
+
+ /* Create operands. */
+ create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
+
+ /* Emit new instruction. */
+ if (!maybe_expand_insn (icode, 1, ops))
+ error ("invalid argument to built-in function");
+
+ return target;
+}
+
+/* Function to expand builtin function for
+ '[(set (reg) (unspec_volatile [(imm)]))]'. */
+static rtx
+nds32_expand_builtin_reg_ftype_imm (enum insn_code icode,
+ tree exp, rtx target)
+{
+ /* Mapping:
+ ops[0] <--> target <--> exp
+ ops[1] <--> value0 <--> arg0 */
+ struct expand_operand ops[2];
+ tree arg0;
+ rtx value0;
+
+ /* Grab the incoming arguments and extract its rtx. */
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ value0 = expand_normal (arg0);
+
+ /* Create operands. */
+ create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
+ create_input_operand (&ops[1], value0, TYPE_MODE (TREE_TYPE (arg0)));
+
+ /* Emit new instruction. */
+ if (!maybe_expand_insn (icode, 2, ops))
+ error ("invalid argument to built-in function");
+
+ return target;
+}
+
+/* Function to expand builtin function for
+ '[(unspec_volatile [(reg) (imm)])]' pattern. */
+static rtx
+nds32_expand_builtin_null_ftype_reg_imm (enum insn_code icode,
+ tree exp, rtx target)
+{
+ /* Mapping:
+ ops[0] <--> value0 <--> arg0
+ ops[1] <--> value1 <--> arg1 */
+ struct expand_operand ops[2];
+ tree arg0, arg1;
+ rtx value0, value1;
+
+ /* Grab the incoming arguments and extract its rtx. */
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ arg1 = CALL_EXPR_ARG (exp, 1);
+ value0 = expand_normal (arg0);
+ value1 = expand_normal (arg1);
+
+ /* Create operands. */
+ create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
+ create_input_operand (&ops[1], value1, TYPE_MODE (TREE_TYPE (arg1)));
+
+ /* Emit new instruction. */
+ if (!maybe_expand_insn (icode, 2, ops))
+ error ("invalid argument to built-in function");
+
+ return target;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void
+nds32_init_builtins_impl (void)
+{
+ tree pointer_type_node = build_pointer_type (integer_type_node);
+
+ tree void_ftype_void = build_function_type (void_type_node,
+ void_list_node);
+
+ tree void_ftype_pint = build_function_type_list (void_type_node,
+ pointer_type_node,
+ NULL_TREE);
+
+ tree int_ftype_int = build_function_type_list (integer_type_node,
+ integer_type_node,
+ NULL_TREE);
+
+ tree void_ftype_int_int = build_function_type_list (void_type_node,
+ integer_type_node,
+ integer_type_node,
+ NULL_TREE);
+
+ /* Cache. */
+ add_builtin_function ("__builtin_nds32_isync", void_ftype_pint,
+ NDS32_BUILTIN_ISYNC,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ add_builtin_function ("__builtin_nds32_isb", void_ftype_void,
+ NDS32_BUILTIN_ISB,
+ BUILT_IN_MD, NULL, NULL_TREE);
+
+ /* Register Transfer. */
+ add_builtin_function ("__builtin_nds32_mfsr", int_ftype_int,
+ NDS32_BUILTIN_MFSR,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ add_builtin_function ("__builtin_nds32_mfusr", int_ftype_int,
+ NDS32_BUILTIN_MFUSR,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ add_builtin_function ("__builtin_nds32_mtsr", void_ftype_int_int,
+ NDS32_BUILTIN_MTSR,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ add_builtin_function ("__builtin_nds32_mtusr", void_ftype_int_int,
+ NDS32_BUILTIN_MTUSR,
+ BUILT_IN_MD, NULL, NULL_TREE);
+
+ /* Interrupt. */
+ add_builtin_function ("__builtin_nds32_setgie_en", void_ftype_void,
+ NDS32_BUILTIN_SETGIE_EN,
+ BUILT_IN_MD, NULL, NULL_TREE);
+ add_builtin_function ("__builtin_nds32_setgie_dis", void_ftype_void,
+ NDS32_BUILTIN_SETGIE_DIS,
+ BUILT_IN_MD, NULL, NULL_TREE);
+}
+
+
+rtx
+nds32_expand_builtin_impl (tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+
+ int fcode = DECL_FUNCTION_CODE (fndecl);
+
+ switch (fcode)
+ {
+ /* Cache. */
+ case NDS32_BUILTIN_ISYNC:
+ return nds32_expand_builtin_null_ftype_reg
+ (CODE_FOR_unspec_volatile_isync, exp, target);
+ case NDS32_BUILTIN_ISB:
+ /* Since there are no result and operands for isb instruciton,
+ we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_isb ());
+ return target;
+
+ /* Register Transfer. */
+ case NDS32_BUILTIN_MFSR:
+ return nds32_expand_builtin_reg_ftype_imm
+ (CODE_FOR_unspec_volatile_mfsr, exp, target);
+ case NDS32_BUILTIN_MFUSR:
+ return nds32_expand_builtin_reg_ftype_imm
+ (CODE_FOR_unspec_volatile_mfusr, exp, target);
+ case NDS32_BUILTIN_MTSR:
+ return nds32_expand_builtin_null_ftype_reg_imm
+ (CODE_FOR_unspec_volatile_mtsr, exp, target);
+ case NDS32_BUILTIN_MTUSR:
+ return nds32_expand_builtin_null_ftype_reg_imm
+ (CODE_FOR_unspec_volatile_mtusr, exp, target);
+
+ /* Interrupt. */
+ case NDS32_BUILTIN_SETGIE_EN:
+ /* Since there are no result and operands for setgie.e instruciton,
+ we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_setgie_en ());
+ return target;
+ case NDS32_BUILTIN_SETGIE_DIS:
+ /* Since there are no result and operands for setgie.d instruciton,
+ we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_setgie_dis ());
+ return target;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return NULL_RTX;
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-intrinsic.md b/gcc/config/nds32/nds32-intrinsic.md
index 3c1d05e482e..db4f8cef4db 100644
--- a/gcc/config/nds32/nds32-intrinsic.md
+++ b/gcc/config/nds32/nds32-intrinsic.md
@@ -1,5 +1,5 @@
;; Intrinsic patterns description of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/nds32-isr.c b/gcc/config/nds32/nds32-isr.c
new file mode 100644
index 00000000000..1896fde9f1e
--- /dev/null
+++ b/gcc/config/nds32/nds32-isr.c
@@ -0,0 +1,629 @@
+/* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
+ 0 for reset handler with __attribute__((reset())),
+ 1-8 for exception handler with __attribute__((exception(1,...,8))),
+ and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
+ We use an array to record essential information for each vector. */
+static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
+
+/* ------------------------------------------------------------------------ */
+
+/* A helper function to emit section head template. */
+static void
+nds32_emit_section_head_template (char section_name[],
+ char symbol_name[],
+ int align_value,
+ bool object_p)
+{
+ const char *flags_str;
+ const char *type_str;
+
+ flags_str = (object_p) ? "\"a\"" : "\"ax\"";
+ type_str = (object_p) ? "@object" : "@function";
+
+ fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
+ fprintf (asm_out_file, "\t.align\t%d\n", align_value);
+ fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
+ fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
+ fprintf (asm_out_file, "%s:\n", symbol_name);
+}
+
+/* A helper function to emit section tail template. */
+static void
+nds32_emit_section_tail_template (char symbol_name[])
+{
+ fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
+}
+
+/* Function to emit isr jump table section. */
+static void
+nds32_emit_isr_jmptbl_section (int vector_id)
+{
+ char section_name[100];
+ char symbol_name[100];
+
+ /* Prepare jmptbl section and symbol name. */
+ snprintf (section_name, sizeof (section_name),
+ ".nds32_jmptbl.%02d", vector_id);
+ snprintf (symbol_name, sizeof (symbol_name),
+ "_nds32_jmptbl_%02d", vector_id);
+
+ nds32_emit_section_head_template (section_name, symbol_name, 2, true);
+ fprintf (asm_out_file, "\t.word\t%s\n",
+ nds32_isr_vectors[vector_id].func_name);
+ nds32_emit_section_tail_template (symbol_name);
+}
+
+/* Function to emit isr vector section. */
+static void
+nds32_emit_isr_vector_section (int vector_id)
+{
+ unsigned int vector_number_offset = 0;
+ const char *c_str = "CATEGORY";
+ const char *sr_str = "SR";
+ const char *nt_str = "NT";
+ const char *vs_str = "VS";
+ char first_level_handler_name[100];
+ char section_name[100];
+ char symbol_name[100];
+
+ /* Set the vector number offset so that we can calculate
+ the value that user specifies in the attribute.
+ We also prepare the category string for first level handler name. */
+ switch (nds32_isr_vectors[vector_id].category)
+ {
+ case NDS32_ISR_INTERRUPT:
+ vector_number_offset = 9;
+ c_str = "i";
+ break;
+ case NDS32_ISR_EXCEPTION:
+ vector_number_offset = 0;
+ c_str = "e";
+ break;
+ case NDS32_ISR_NONE:
+ case NDS32_ISR_RESET:
+ /* Normally it should not be here. */
+ gcc_unreachable ();
+ break;
+ }
+
+ /* Prepare save reg string for first level handler name. */
+ switch (nds32_isr_vectors[vector_id].save_reg)
+ {
+ case NDS32_SAVE_ALL:
+ sr_str = "sa";
+ break;
+ case NDS32_PARTIAL_SAVE:
+ sr_str = "ps";
+ break;
+ }
+
+ /* Prepare nested type string for first level handler name. */
+ switch (nds32_isr_vectors[vector_id].nested_type)
+ {
+ case NDS32_NESTED:
+ nt_str = "ns";
+ break;
+ case NDS32_NOT_NESTED:
+ nt_str = "nn";
+ break;
+ case NDS32_NESTED_READY:
+ nt_str = "nr";
+ break;
+ }
+
+ /* Currently we have 4-byte or 16-byte size for each vector.
+ If it is 4-byte, the first level handler name has suffix string "_4b". */
+ vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
+
+ /* Now we can create first level handler name. */
+ snprintf (first_level_handler_name, sizeof (first_level_handler_name),
+ "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
+
+ /* Prepare vector section and symbol name. */
+ snprintf (section_name, sizeof (section_name),
+ ".nds32_vector.%02d", vector_id);
+ snprintf (symbol_name, sizeof (symbol_name),
+ "_nds32_vector_%02d%s", vector_id, vs_str);
+
+
+ /* Everything is ready. We can start emit vector section content. */
+ nds32_emit_section_head_template (section_name, symbol_name,
+ floor_log2 (nds32_isr_vector_size), false);
+
+ /* According to the vector size, the instructions in the
+ vector section may be different. */
+ if (nds32_isr_vector_size == 4)
+ {
+ /* This block is for 4-byte vector size.
+ Hardware $VID support is necessary and only one instruction
+ is needed in vector section. */
+ fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
+ first_level_handler_name);
+ }
+ else
+ {
+ /* This block is for 16-byte vector size.
+ There is NO hardware $VID so that we need several instructions
+ such as pushing GPRs and preparing software vid at vector section.
+ For pushing GPRs, there are four variations for
+ 16-byte vector content and we have to handle each combination.
+ For preparing software vid, note that the vid need to
+ be substracted vector_number_offset. */
+ if (TARGET_REDUCED_REGS)
+ {
+ if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
+ {
+ /* Case of reduced set registers and save_all attribute. */
+ fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
+
+ }
+ else
+ {
+ /* Case of reduced set registers and partial_save attribute. */
+ fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
+ }
+ }
+ else
+ {
+ if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
+ {
+ /* Case of full set registers and save_all attribute. */
+ fprintf (asm_out_file, "\t! full set regs + save_all\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
+ }
+ else
+ {
+ /* Case of full set registers and partial_save attribute. */
+ fprintf (asm_out_file, "\t! full set regs + partial_save\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
+ fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
+ }
+ }
+
+ fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
+ vector_id - vector_number_offset);
+ fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
+ first_level_handler_name);
+ }
+
+ nds32_emit_section_tail_template (symbol_name);
+}
+
+/* Function to emit isr reset handler content.
+ Including all jmptbl/vector references, jmptbl section,
+ vector section, nmi handler section, and warm handler section. */
+static void
+nds32_emit_isr_reset_content (void)
+{
+ unsigned int i;
+ unsigned int total_n_vectors;
+ const char *vs_str;
+ char reset_handler_name[100];
+ char section_name[100];
+ char symbol_name[100];
+
+ total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
+ vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
+
+ fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
+
+ /* Create references in .rodata according to total number of vectors. */
+ fprintf (asm_out_file, "\t.section\t.rodata\n");
+ fprintf (asm_out_file, "\t.align\t2\n");
+
+ /* Emit jmptbl references. */
+ fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
+ for (i = 0; i < total_n_vectors; i++)
+ fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
+
+ /* Emit vector references. */
+ fprintf (asm_out_file, "\t ! references to vector section entries\n");
+ for (i = 0; i < total_n_vectors; i++)
+ fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
+
+ /* Emit jmptbl_00 section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
+ snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
+
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_section_head_template (section_name, symbol_name, 2, true);
+ fprintf (asm_out_file, "\t.word\t%s\n",
+ nds32_isr_vectors[0].func_name);
+ nds32_emit_section_tail_template (symbol_name);
+
+ /* Emit vector_00 section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
+ snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
+ snprintf (reset_handler_name, sizeof (reset_handler_name),
+ "_nds32_reset%s", vs_str);
+
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_section_head_template (section_name, symbol_name,
+ floor_log2 (nds32_isr_vector_size), false);
+ fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
+ reset_handler_name);
+ nds32_emit_section_tail_template (symbol_name);
+
+ /* Emit nmi handler section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_nmih");
+ snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
+
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_section_head_template (section_name, symbol_name, 2, true);
+ fprintf (asm_out_file, "\t.word\t%s\n",
+ (strlen (nds32_isr_vectors[0].nmi_name) == 0)
+ ? "0"
+ : nds32_isr_vectors[0].nmi_name);
+ nds32_emit_section_tail_template (symbol_name);
+
+ /* Emit warm handler section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_wrh");
+ snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
+
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_section_head_template (section_name, symbol_name, 2, true);
+ fprintf (asm_out_file, "\t.word\t%s\n",
+ (strlen (nds32_isr_vectors[0].warm_name) == 0)
+ ? "0"
+ : nds32_isr_vectors[0].warm_name);
+ nds32_emit_section_tail_template (symbol_name);
+
+ fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
+}
+
+/* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
+ to check if there are any conflict isr-specific attributes being set.
+ We need to check:
+ 1. Only 'save_all' or 'partial_save' in the attributes.
+ 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
+ 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
+void
+nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
+{
+ int save_all_p, partial_save_p;
+ int nested_p, not_nested_p, nested_ready_p;
+ int intr_p, excp_p, reset_p;
+
+ /* Initialize variables. */
+ save_all_p = partial_save_p = 0;
+ nested_p = not_nested_p = nested_ready_p = 0;
+ intr_p = excp_p = reset_p = 0;
+
+ /* We must check at MOST one attribute to set save-reg. */
+ if (lookup_attribute ("save_all", func_attrs))
+ save_all_p = 1;
+ if (lookup_attribute ("partial_save", func_attrs))
+ partial_save_p = 1;
+
+ if ((save_all_p + partial_save_p) > 1)
+ error ("multiple save reg attributes to function %qD", func_decl);
+
+ /* We must check at MOST one attribute to set nested-type. */
+ if (lookup_attribute ("nested", func_attrs))
+ nested_p = 1;
+ if (lookup_attribute ("not_nested", func_attrs))
+ not_nested_p = 1;
+ if (lookup_attribute ("nested_ready", func_attrs))
+ nested_ready_p = 1;
+
+ if ((nested_p + not_nested_p + nested_ready_p) > 1)
+ error ("multiple nested types attributes to function %qD", func_decl);
+
+ /* We must check at MOST one attribute to
+ set interrupt/exception/reset. */
+ if (lookup_attribute ("interrupt", func_attrs))
+ intr_p = 1;
+ if (lookup_attribute ("exception", func_attrs))
+ excp_p = 1;
+ if (lookup_attribute ("reset", func_attrs))
+ reset_p = 1;
+
+ if ((intr_p + excp_p + reset_p) > 1)
+ error ("multiple interrupt attributes to function %qD", func_decl);
+}
+
+/* Function to construct isr vectors information array.
+ We DO NOT HAVE TO check if the attributes are valid
+ because those works are supposed to be done on
+ nds32_merge_decl_attributes() and nds32_insert_attributes(). */
+void
+nds32_construct_isr_vectors_information (tree func_attrs,
+ const char *func_name)
+{
+ tree save_all, partial_save;
+ tree nested, not_nested, nested_ready;
+ tree intr, excp, reset;
+
+ save_all = lookup_attribute ("save_all", func_attrs);
+ partial_save = lookup_attribute ("partial_save", func_attrs);
+
+ nested = lookup_attribute ("nested", func_attrs);
+ not_nested = lookup_attribute ("not_nested", func_attrs);
+ nested_ready = lookup_attribute ("nested_ready", func_attrs);
+
+ intr = lookup_attribute ("interrupt", func_attrs);
+ excp = lookup_attribute ("exception", func_attrs);
+ reset = lookup_attribute ("reset", func_attrs);
+
+ /* If there is no interrupt/exception/reset, we can return immediately. */
+ if (!intr && !excp && !reset)
+ return;
+
+ /* If we are here, either we have interrupt/exception,
+ or reset attribute. */
+ if (intr || excp)
+ {
+ tree id_list;
+
+ /* Prepare id list so that we can traverse and set vector id. */
+ id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
+
+ while (id_list)
+ {
+ tree id;
+ int vector_id;
+ unsigned int vector_number_offset;
+
+ /* The way to handle interrupt or exception is the same,
+ we just need to take care of actual vector number.
+ For interrupt(0..63), the actual vector number is (9..72).
+ For exception(1..8), the actual vector number is (1..8). */
+ vector_number_offset = (intr) ? (9) : (0);
+
+ /* Pick up each vector id value. */
+ id = TREE_VALUE (id_list);
+ /* Add vector_number_offset to get actual vector number. */
+ vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
+
+ /* Enable corresponding vector and set function name. */
+ nds32_isr_vectors[vector_id].category = (intr)
+ ? (NDS32_ISR_INTERRUPT)
+ : (NDS32_ISR_EXCEPTION);
+ strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
+
+ /* Set register saving scheme. */
+ if (save_all)
+ nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
+ else if (partial_save)
+ nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
+
+ /* Set nested type. */
+ if (nested)
+ nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
+ else if (not_nested)
+ nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
+ else if (nested_ready)
+ nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
+
+ /* Advance to next id. */
+ id_list = TREE_CHAIN (id_list);
+ }
+ }
+ else
+ {
+ tree id_list;
+ tree id;
+ tree nmi, warm;
+
+ /* Deal with reset attribute. Its vector number is always 0. */
+ nds32_isr_vectors[0].category = NDS32_ISR_RESET;
+
+ /* Prepare id_list and identify id value so that
+ we can set total number of vectors. */
+ id_list = TREE_VALUE (reset);
+ id = TREE_VALUE (id_list);
+
+ /* The total vectors = interrupt + exception numbers + reset.
+ There are 8 exception and 1 reset in nds32 architecture. */
+ nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
+ strcpy (nds32_isr_vectors[0].func_name, func_name);
+
+ /* Retrieve nmi and warm function. */
+ nmi = lookup_attribute ("nmi", func_attrs);
+ warm = lookup_attribute ("warm", func_attrs);
+
+ if (nmi != NULL_TREE)
+ {
+ tree nmi_func_list;
+ tree nmi_func;
+
+ nmi_func_list = TREE_VALUE (nmi);
+ nmi_func = TREE_VALUE (nmi_func_list);
+
+ /* Record nmi function name. */
+ strcpy (nds32_isr_vectors[0].nmi_name,
+ IDENTIFIER_POINTER (nmi_func));
+ }
+
+ if (warm != NULL_TREE)
+ {
+ tree warm_func_list;
+ tree warm_func;
+
+ warm_func_list = TREE_VALUE (warm);
+ warm_func = TREE_VALUE (warm_func_list);
+
+ /* Record warm function name. */
+ strcpy (nds32_isr_vectors[0].warm_name,
+ IDENTIFIER_POINTER (warm_func));
+ }
+ }
+}
+
+/* A helper function to handle isr stuff at the beginning of asm file. */
+void
+nds32_asm_file_start_for_isr (void)
+{
+ int i;
+
+ /* Initialize isr vector information array before compiling functions. */
+ for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
+ {
+ nds32_isr_vectors[i].category = NDS32_ISR_NONE;
+ strcpy (nds32_isr_vectors[i].func_name, "");
+ nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
+ nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
+ nds32_isr_vectors[i].total_n_vectors = 0;
+ strcpy (nds32_isr_vectors[i].nmi_name, "");
+ strcpy (nds32_isr_vectors[i].warm_name, "");
+ }
+}
+
+/* A helper function to handle isr stuff at the end of asm file. */
+void
+nds32_asm_file_end_for_isr (void)
+{
+ int i;
+
+ /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
+ for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
+ if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
+ break;
+
+ if (i == NDS32_N_ISR_VECTORS)
+ return;
+
+ /* At least one vector is NOT NDS32_ISR_NONE,
+ we should output isr vector information. */
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+ fprintf (asm_out_file, "\t! The isr vector information:\n");
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+
+ /* Check reset handler first. Its vector number is always 0. */
+ if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
+ {
+ nds32_emit_isr_reset_content ();
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+ }
+
+ /* Check other vectors, starting from vector number 1. */
+ for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
+ {
+ if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
+ || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
+ {
+ /* Found one vector which is interupt or exception.
+ Output its jmptbl and vector section content. */
+ fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+ nds32_emit_isr_jmptbl_section (i);
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_isr_vector_section (i);
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+ }
+ }
+}
+
+/* Return true if FUNC is a isr function. */
+bool
+nds32_isr_function_p (tree func)
+{
+ tree t_intr;
+ tree t_excp;
+ tree t_reset;
+
+ tree attrs;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ abort ();
+
+ attrs = DECL_ATTRIBUTES (func);
+
+ t_intr = lookup_attribute ("interrupt", attrs);
+ t_excp = lookup_attribute ("exception", attrs);
+ t_reset = lookup_attribute ("reset", attrs);
+
+ return ((t_intr != NULL_TREE)
+ || (t_excp != NULL_TREE)
+ || (t_reset != NULL_TREE));
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c
new file mode 100644
index 00000000000..2f4927731be
--- /dev/null
+++ b/gcc/config/nds32/nds32-md-auxiliary.c
@@ -0,0 +1,896 @@
+/* Auxiliary functions for output asm template or expand rtl
+ pattern of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* A helper function to return character based on byte size. */
+static char
+nds32_byte_to_size (int byte)
+{
+ switch (byte)
+ {
+ case 4:
+ return 'w';
+ case 2:
+ return 'h';
+ case 1:
+ return 'b';
+ default:
+ /* Normally it should not be here. */
+ gcc_unreachable ();
+ }
+}
+
+/* A helper function to return memory format. */
+enum nds32_16bit_address_type
+nds32_mem_format (rtx op)
+{
+ machine_mode mode_test;
+ int val;
+ int regno;
+
+ if (!TARGET_16_BIT)
+ return ADDRESS_NOT_16BIT_FORMAT;
+
+ mode_test = GET_MODE (op);
+
+ op = XEXP (op, 0);
+
+ /* 45 format. */
+ if (GET_CODE (op) == REG && (mode_test == SImode))
+ return ADDRESS_REG;
+
+ /* 333 format for QI/HImode. */
+ if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
+ return ADDRESS_LO_REG_IMM3U;
+
+ /* post_inc 333 format. */
+ if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
+ {
+ regno = REGNO(XEXP (op, 0));
+
+ if (regno < 8)
+ return ADDRESS_POST_INC_LO_REG_IMM3U;
+ }
+
+ /* post_inc 333 format. */
+ if ((GET_CODE (op) == POST_MODIFY)
+ && (mode_test == SImode)
+ && (REG_P (XEXP (XEXP (op, 1), 0)))
+ && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
+ {
+ regno = REGNO (XEXP (XEXP (op, 1), 0));
+ val = INTVAL (XEXP (XEXP (op, 1), 1));
+ if (regno < 8 && val < 32)
+ return ADDRESS_POST_INC_LO_REG_IMM3U;
+ }
+
+ if ((GET_CODE (op) == PLUS)
+ && (GET_CODE (XEXP (op, 0)) == REG)
+ && (GET_CODE (XEXP (op, 1)) == CONST_INT))
+ {
+ val = INTVAL (XEXP (op, 1));
+
+ regno = REGNO(XEXP (op, 0));
+
+ if (regno > 7
+ && regno != SP_REGNUM
+ && regno != FP_REGNUM)
+ return ADDRESS_NOT_16BIT_FORMAT;
+
+ switch (mode_test)
+ {
+ case QImode:
+ /* 333 format. */
+ if (val >= 0 && val < 8 && regno < 8)
+ return ADDRESS_LO_REG_IMM3U;
+ break;
+
+ case HImode:
+ /* 333 format. */
+ if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
+ return ADDRESS_LO_REG_IMM3U;
+ break;
+
+ case SImode:
+ case SFmode:
+ case DFmode:
+ /* fp imply 37 format. */
+ if ((regno == FP_REGNUM) &&
+ (val >= 0 && val < 512 && (val % 4 == 0)))
+ return ADDRESS_FP_IMM7U;
+ /* sp imply 37 format. */
+ else if ((regno == SP_REGNUM) &&
+ (val >= 0 && val < 512 && (val % 4 == 0)))
+ return ADDRESS_SP_IMM7U;
+ /* 333 format. */
+ else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
+ return ADDRESS_LO_REG_IMM3U;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return ADDRESS_NOT_16BIT_FORMAT;
+}
+
+/* Output 16-bit store. */
+const char *
+nds32_output_16bit_store (rtx *operands, int byte)
+{
+ char pattern[100];
+ char size;
+ rtx code = XEXP (operands[0], 0);
+
+ size = nds32_byte_to_size (byte);
+
+ switch (nds32_mem_format (operands[0]))
+ {
+ case ADDRESS_REG:
+ operands[0] = code;
+ output_asm_insn ("swi450\t%1, [%0]", operands);
+ break;
+ case ADDRESS_LO_REG_IMM3U:
+ snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
+ output_asm_insn (pattern, operands);
+ break;
+ case ADDRESS_POST_INC_LO_REG_IMM3U:
+ snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
+ output_asm_insn (pattern, operands);
+ break;
+ case ADDRESS_FP_IMM7U:
+ output_asm_insn ("swi37\t%1, %0", operands);
+ break;
+ case ADDRESS_SP_IMM7U:
+ /* Get immediate value and set back to operands[1]. */
+ operands[0] = XEXP (code, 1);
+ output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
+ break;
+ default:
+ break;
+ }
+
+ return "";
+}
+
+/* Output 16-bit load. */
+const char *
+nds32_output_16bit_load (rtx *operands, int byte)
+{
+ char pattern[100];
+ unsigned char size;
+ rtx code = XEXP (operands[1], 0);
+
+ size = nds32_byte_to_size (byte);
+
+ switch (nds32_mem_format (operands[1]))
+ {
+ case ADDRESS_REG:
+ operands[1] = code;
+ output_asm_insn ("lwi450\t%0, [%1]", operands);
+ break;
+ case ADDRESS_LO_REG_IMM3U:
+ snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
+ output_asm_insn (pattern, operands);
+ break;
+ case ADDRESS_POST_INC_LO_REG_IMM3U:
+ snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
+ output_asm_insn (pattern, operands);
+ break;
+ case ADDRESS_FP_IMM7U:
+ output_asm_insn ("lwi37\t%0, %1", operands);
+ break;
+ case ADDRESS_SP_IMM7U:
+ /* Get immediate value and set back to operands[0]. */
+ operands[1] = XEXP (code, 1);
+ output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
+ break;
+ default:
+ break;
+ }
+
+ return "";
+}
+
+/* Output 32-bit store. */
+const char *
+nds32_output_32bit_store (rtx *operands, int byte)
+{
+ char pattern[100];
+ unsigned char size;
+ rtx code = XEXP (operands[0], 0);
+
+ size = nds32_byte_to_size (byte);
+
+ switch (GET_CODE (code))
+ {
+ case REG:
+ /* (mem (reg X))
+ => access location by using register,
+ use "sbi / shi / swi" */
+ snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
+ break;
+
+ case SYMBOL_REF:
+ case CONST:
+ /* (mem (symbol_ref X))
+ (mem (const (...)))
+ => access global variables,
+ use "sbi.gp / shi.gp / swi.gp" */
+ operands[0] = XEXP (operands[0], 0);
+ snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
+ break;
+
+ case POST_INC:
+ /* (mem (post_inc reg))
+ => access location by using register which will be post increment,
+ use "sbi.bi / shi.bi / swi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "s%ci.bi\t%%1, %%0, %d", size, byte);
+ break;
+
+ case POST_DEC:
+ /* (mem (post_dec reg))
+ => access location by using register which will be post decrement,
+ use "sbi.bi / shi.bi / swi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "s%ci.bi\t%%1, %%0, -%d", size, byte);
+ break;
+
+ case POST_MODIFY:
+ switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (post_modify (reg) (plus (reg) (reg))))
+ => access location by using register which will be
+ post modified with reg,
+ use "sb.bi/ sh.bi / sw.bi" */
+ snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
+ break;
+ case CONST_INT:
+ /* (mem (post_modify (reg) (plus (reg) (const_int))))
+ => access location by using register which will be
+ post modified with const_int,
+ use "sbi.bi/ shi.bi / swi.bi" */
+ snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case PLUS:
+ switch (GET_CODE (XEXP (code, 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+ => access location by adding two registers,
+ use "sb / sh / sw" */
+ snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
+ break;
+ case CONST_INT:
+ /* (mem (plus reg const_int))
+ => access location by adding one register with const_int,
+ use "sbi / shi / swi" */
+ snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case LO_SUM:
+ operands[2] = XEXP (code, 1);
+ operands[0] = XEXP (code, 0);
+ snprintf (pattern, sizeof (pattern),
+ "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
+ break;
+
+ default:
+ abort ();
+ }
+
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+/* Output 32-bit load. */
+const char *
+nds32_output_32bit_load (rtx *operands, int byte)
+{
+ char pattern[100];
+ unsigned char size;
+ rtx code;
+
+ code = XEXP (operands[1], 0);
+
+ size = nds32_byte_to_size (byte);
+
+ switch (GET_CODE (code))
+ {
+ case REG:
+ /* (mem (reg X))
+ => access location by using register,
+ use "lbi / lhi / lwi" */
+ snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
+ break;
+
+ case SYMBOL_REF:
+ case CONST:
+ /* (mem (symbol_ref X))
+ (mem (const (...)))
+ => access global variables,
+ use "lbi.gp / lhi.gp / lwi.gp" */
+ operands[1] = XEXP (operands[1], 0);
+ snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
+ break;
+
+ case POST_INC:
+ /* (mem (post_inc reg))
+ => access location by using register which will be post increment,
+ use "lbi.bi / lhi.bi / lwi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "l%ci.bi\t%%0, %%1, %d", size, byte);
+ break;
+
+ case POST_DEC:
+ /* (mem (post_dec reg))
+ => access location by using register which will be post decrement,
+ use "lbi.bi / lhi.bi / lwi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "l%ci.bi\t%%0, %%1, -%d", size, byte);
+ break;
+
+ case POST_MODIFY:
+ switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (post_modify (reg) (plus (reg) (reg))))
+ => access location by using register which will be
+ post modified with reg,
+ use "lb.bi/ lh.bi / lw.bi" */
+ snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
+ break;
+ case CONST_INT:
+ /* (mem (post_modify (reg) (plus (reg) (const_int))))
+ => access location by using register which will be
+ post modified with const_int,
+ use "lbi.bi/ lhi.bi / lwi.bi" */
+ snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case PLUS:
+ switch (GET_CODE (XEXP (code, 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+ use "lb / lh / lw" */
+ snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
+ break;
+ case CONST_INT:
+ /* (mem (plus reg const_int))
+ => access location by adding one register with const_int,
+ use "lbi / lhi / lwi" */
+ snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case LO_SUM:
+ operands[2] = XEXP (code, 1);
+ operands[1] = XEXP (code, 0);
+ snprintf (pattern, sizeof (pattern),
+ "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
+ break;
+
+ default:
+ abort ();
+ }
+
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+/* Output 32-bit load with signed extension. */
+const char *
+nds32_output_32bit_load_s (rtx *operands, int byte)
+{
+ char pattern[100];
+ unsigned char size;
+ rtx code;
+
+ code = XEXP (operands[1], 0);
+
+ size = nds32_byte_to_size (byte);
+
+ switch (GET_CODE (code))
+ {
+ case REG:
+ /* (mem (reg X))
+ => access location by using register,
+ use "lbsi / lhsi" */
+ snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
+ break;
+
+ case SYMBOL_REF:
+ case CONST:
+ /* (mem (symbol_ref X))
+ (mem (const (...)))
+ => access global variables,
+ use "lbsi.gp / lhsi.gp" */
+ operands[1] = XEXP (operands[1], 0);
+ snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
+ break;
+
+ case POST_INC:
+ /* (mem (post_inc reg))
+ => access location by using register which will be post increment,
+ use "lbsi.bi / lhsi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "l%csi.bi\t%%0, %%1, %d", size, byte);
+ break;
+
+ case POST_DEC:
+ /* (mem (post_dec reg))
+ => access location by using register which will be post decrement,
+ use "lbsi.bi / lhsi.bi" */
+ snprintf (pattern, sizeof (pattern),
+ "l%csi.bi\t%%0, %%1, -%d", size, byte);
+ break;
+
+ case POST_MODIFY:
+ switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (post_modify (reg) (plus (reg) (reg))))
+ => access location by using register which will be
+ post modified with reg,
+ use "lbs.bi/ lhs.bi" */
+ snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
+ break;
+ case CONST_INT:
+ /* (mem (post_modify (reg) (plus (reg) (const_int))))
+ => access location by using register which will be
+ post modified with const_int,
+ use "lbsi.bi/ lhsi.bi" */
+ snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case PLUS:
+ switch (GET_CODE (XEXP (code, 1)))
+ {
+ case REG:
+ case SUBREG:
+ /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+ use "lbs / lhs" */
+ snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
+ break;
+ case CONST_INT:
+ /* (mem (plus reg const_int))
+ => access location by adding one register with const_int,
+ use "lbsi / lhsi" */
+ snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case LO_SUM:
+ operands[2] = XEXP (code, 1);
+ operands[1] = XEXP (code, 0);
+ snprintf (pattern, sizeof (pattern),
+ "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
+ break;
+
+ default:
+ abort ();
+ }
+
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+/* Function to output stack push operation.
+ We need to deal with normal stack push multiple or stack v3push. */
+const char *
+nds32_output_stack_push (rtx par_rtx)
+{
+ /* A string pattern for output_asm_insn(). */
+ char pattern[100];
+ /* The operands array which will be used in output_asm_insn(). */
+ rtx operands[3];
+ /* Pick up varargs first regno and last regno for further use. */
+ int rb_va_args = cfun->machine->va_args_first_regno;
+ int re_va_args = cfun->machine->va_args_last_regno;
+ int last_argument_regno = NDS32_FIRST_GPR_REGNUM
+ + NDS32_MAX_GPR_REGS_FOR_ARGS
+ - 1;
+ /* Pick up callee-saved first regno and last regno for further use. */
+ int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno;
+ int re_callee_saved = cfun->machine->callee_saved_regs_last_regno;
+
+ /* First we need to check if we are pushing argument registers not used
+ for the named arguments. If so, we have to create 'smw.adm' (push.s)
+ instruction. */
+ if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
+ {
+ /* Set operands[0] and operands[1]. */
+ operands[0] = gen_rtx_REG (SImode, rb_va_args);
+ operands[1] = gen_rtx_REG (SImode, re_va_args);
+ /* Create assembly code pattern: "Rb, Re, { }". */
+ snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
+ /* We use output_asm_insn() to output assembly code by ourself. */
+ output_asm_insn (pattern, operands);
+ return "";
+ }
+
+ /* If we step here, we are going to do v3push or multiple push operation. */
+
+ /* The v3push/v3pop instruction should only be applied on
+ none-isr and none-variadic function. */
+ if (TARGET_V3PUSH
+ && !nds32_isr_function_p (current_function_decl)
+ && (cfun->machine->va_args_size == 0))
+ {
+ /* For stack v3push:
+ operands[0]: Re
+ operands[1]: imm8u */
+
+ /* This variable is to check if 'push25 Re,imm8u' is available. */
+ int sp_adjust;
+
+ /* Set operands[0]. */
+ operands[0] = gen_rtx_REG (SImode, re_callee_saved);
+
+ /* Check if we can generate 'push25 Re,imm8u',
+ otherwise, generate 'push25 Re,0'. */
+ sp_adjust = cfun->machine->local_size
+ + cfun->machine->out_args_size
+ + cfun->machine->callee_saved_area_padding_bytes;
+ if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
+ && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
+ operands[1] = GEN_INT (sp_adjust);
+ else
+ operands[1] = GEN_INT (0);
+
+ /* Create assembly code pattern. */
+ snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
+ }
+ else
+ {
+ /* For normal stack push multiple:
+ operands[0]: Rb
+ operands[1]: Re
+ operands[2]: En4 */
+
+ /* This variable is used to check if we only need to generate En4 field.
+ As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
+ int push_en4_only_p = 0;
+
+ /* Set operands[0] and operands[1]. */
+ operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
+ operands[1] = gen_rtx_REG (SImode, re_callee_saved);
+
+ /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
+ if (!cfun->machine->fp_size
+ && !cfun->machine->gp_size
+ && !cfun->machine->lp_size
+ && REGNO (operands[0]) == SP_REGNUM
+ && REGNO (operands[1]) == SP_REGNUM)
+ {
+ /* No need to generate instruction. */
+ return "";
+ }
+ else
+ {
+ /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
+ if (REGNO (operands[0]) == SP_REGNUM
+ && REGNO (operands[1]) == SP_REGNUM)
+ push_en4_only_p = 1;
+
+ /* Create assembly code pattern.
+ We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
+ snprintf (pattern, sizeof (pattern),
+ "push.s\t%s{%s%s%s }",
+ push_en4_only_p ? "" : "%0, %1, ",
+ cfun->machine->fp_size ? " $fp" : "",
+ cfun->machine->gp_size ? " $gp" : "",
+ cfun->machine->lp_size ? " $lp" : "");
+ }
+ }
+
+ /* We use output_asm_insn() to output assembly code by ourself. */
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+/* Function to output stack pop operation.
+ We need to deal with normal stack pop multiple or stack v3pop. */
+const char *
+nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
+{
+ /* A string pattern for output_asm_insn(). */
+ char pattern[100];
+ /* The operands array which will be used in output_asm_insn(). */
+ rtx operands[3];
+ /* Pick up callee-saved first regno and last regno for further use. */
+ int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno;
+ int re_callee_saved = cfun->machine->callee_saved_regs_last_regno;
+
+ /* If we step here, we are going to do v3pop or multiple pop operation. */
+
+ /* The v3push/v3pop instruction should only be applied on
+ none-isr and none-variadic function. */
+ if (TARGET_V3PUSH
+ && !nds32_isr_function_p (current_function_decl)
+ && (cfun->machine->va_args_size == 0))
+ {
+ /* For stack v3pop:
+ operands[0]: Re
+ operands[1]: imm8u */
+
+ /* This variable is to check if 'pop25 Re,imm8u' is available. */
+ int sp_adjust;
+
+ /* Set operands[0]. */
+ operands[0] = gen_rtx_REG (SImode, re_callee_saved);
+
+ /* Check if we can generate 'pop25 Re,imm8u',
+ otherwise, generate 'pop25 Re,0'.
+ We have to consider alloca issue as well.
+ If the function does call alloca(), the stack pointer is not fixed.
+ In that case, we cannot use 'pop25 Re,imm8u' directly.
+ We have to caculate stack pointer from frame pointer
+ and then use 'pop25 Re,0'. */
+ sp_adjust = cfun->machine->local_size
+ + cfun->machine->out_args_size
+ + cfun->machine->callee_saved_area_padding_bytes;
+ if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
+ && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
+ && !cfun->calls_alloca)
+ operands[1] = GEN_INT (sp_adjust);
+ else
+ operands[1] = GEN_INT (0);
+
+ /* Create assembly code pattern. */
+ snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
+ }
+ else
+ {
+ /* For normal stack pop multiple:
+ operands[0]: Rb
+ operands[1]: Re
+ operands[2]: En4 */
+
+ /* This variable is used to check if we only need to generate En4 field.
+ As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
+ int pop_en4_only_p = 0;
+
+ /* Set operands[0] and operands[1]. */
+ operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
+ operands[1] = gen_rtx_REG (SImode, re_callee_saved);
+
+ /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
+ if (!cfun->machine->fp_size
+ && !cfun->machine->gp_size
+ && !cfun->machine->lp_size
+ && REGNO (operands[0]) == SP_REGNUM
+ && REGNO (operands[1]) == SP_REGNUM)
+ {
+ /* No need to generate instruction. */
+ return "";
+ }
+ else
+ {
+ /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
+ if (REGNO (operands[0]) == SP_REGNUM
+ && REGNO (operands[1]) == SP_REGNUM)
+ pop_en4_only_p = 1;
+
+ /* Create assembly code pattern.
+ We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
+ snprintf (pattern, sizeof (pattern),
+ "pop.s\t%s{%s%s%s }",
+ pop_en4_only_p ? "" : "%0, %1, ",
+ cfun->machine->fp_size ? " $fp" : "",
+ cfun->machine->gp_size ? " $gp" : "",
+ cfun->machine->lp_size ? " $lp" : "");
+ }
+ }
+
+ /* We use output_asm_insn() to output assembly code by ourself. */
+ output_asm_insn (pattern, operands);
+ return "";
+}
+
+/* Function to generate PC relative jump table.
+ Refer to nds32.md for more details.
+
+ The following is the sample for the case that diff value
+ can be presented in '.short' size.
+
+ addi $r1, $r1, -(case_lower_bound)
+ slti $ta, $r1, (case_number)
+ beqz $ta, .L_skip_label
+
+ la $ta, .L35 ! get jump table address
+ lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
+ addi $ta, $r1, $ta
+ jr5 $ta
+
+ ! jump table entry
+ L35:
+ .short .L25-.L35
+ .short .L26-.L35
+ .short .L27-.L35
+ .short .L28-.L35
+ .short .L29-.L35
+ .short .L30-.L35
+ .short .L31-.L35
+ .short .L32-.L35
+ .short .L33-.L35
+ .short .L34-.L35 */
+const char *
+nds32_output_casesi_pc_relative (rtx *operands)
+{
+ machine_mode mode;
+ rtx diff_vec;
+
+ diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
+
+ gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+ /* Step C: "t <-- operands[1]". */
+ output_asm_insn ("la\t$ta, %l1", operands);
+
+ /* Get the mode of each element in the difference vector. */
+ mode = GET_MODE (diff_vec);
+
+ /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
+ where m is 0, 1, or 2 to load address-diff value from table. */
+ switch (mode)
+ {
+ case QImode:
+ output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
+ break;
+ case HImode:
+ output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
+ break;
+ case SImode:
+ output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Step E: "t <-- z + t".
+ Add table label_ref with address-diff value to
+ obtain target case address. */
+ output_asm_insn ("add\t$ta, %2, $ta", operands);
+
+ /* Step F: jump to target with register t. */
+ if (TARGET_16_BIT)
+ return "jr5\t$ta";
+ else
+ return "jr\t$ta";
+}
+
+/* Function to generate normal jump table. */
+const char *
+nds32_output_casesi (rtx *operands)
+{
+ /* Step C: "t <-- operands[1]". */
+ output_asm_insn ("la\t$ta, %l1", operands);
+
+ /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
+ output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
+
+ /* No need to perform Step E, which is only used for
+ pc relative jump table. */
+
+ /* Step F: jump to target with register z. */
+ if (TARGET_16_BIT)
+ return "jr5\t%2";
+ else
+ return "jr\t%2";
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-memory-manipulation.c b/gcc/config/nds32/nds32-memory-manipulation.c
new file mode 100644
index 00000000000..2f333371d78
--- /dev/null
+++ b/gcc/config/nds32/nds32-memory-manipulation.c
@@ -0,0 +1,193 @@
+/* Auxiliary functions for expand movmem, setmem, cmpmem, load_multiple
+ and store_multiple pattern of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Functions to expand load_multiple and store_multiple.
+ They are auxiliary extern functions to help create rtx template.
+ Check nds32-multiple.md file for the patterns. */
+rtx
+nds32_expand_load_multiple (int base_regno, int count,
+ rtx base_addr, rtx basemem)
+{
+ int par_index;
+ int offset;
+ rtx result;
+ rtx new_addr, mem, reg;
+
+ /* Create the pattern that is presented in nds32-multiple.md. */
+
+ result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+ for (par_index = 0; par_index < count; par_index++)
+ {
+ offset = par_index * 4;
+ /* 4-byte for loading data to each register. */
+ new_addr = plus_constant (Pmode, base_addr, offset);
+ mem = adjust_automodify_address_nv (basemem, SImode,
+ new_addr, offset);
+ reg = gen_rtx_REG (SImode, base_regno + par_index);
+
+ XVECEXP (result, 0, par_index) = gen_rtx_SET (VOIDmode, reg, mem);
+ }
+
+ return result;
+}
+
+rtx
+nds32_expand_store_multiple (int base_regno, int count,
+ rtx base_addr, rtx basemem)
+{
+ int par_index;
+ int offset;
+ rtx result;
+ rtx new_addr, mem, reg;
+
+ /* Create the pattern that is presented in nds32-multiple.md. */
+
+ result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+
+ for (par_index = 0; par_index < count; par_index++)
+ {
+ offset = par_index * 4;
+ /* 4-byte for storing data to memory. */
+ new_addr = plus_constant (Pmode, base_addr, offset);
+ mem = adjust_automodify_address_nv (basemem, SImode,
+ new_addr, offset);
+ reg = gen_rtx_REG (SImode, base_regno + par_index);
+
+ XVECEXP (result, 0, par_index) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+
+ return result;
+}
+
+/* Function to move block memory content by
+ using load_multiple and store_multiple.
+ This is auxiliary extern function to help create rtx template.
+ Check nds32-multiple.md file for the patterns. */
+int
+nds32_expand_movmemqi (rtx dstmem, rtx srcmem, rtx total_bytes, rtx alignment)
+{
+ HOST_WIDE_INT in_words, out_words;
+ rtx dst_base_reg, src_base_reg;
+ int maximum_bytes;
+
+ /* 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 (32 bytes) for moving memory block
+ may easily consume all of them.
+ It makes register allocation/spilling hard to work.
+ So we only allow maximum=4 registers (16 bytes) for
+ moving memory block under reduced-set registers. */
+ if (TARGET_REDUCED_REGS)
+ maximum_bytes = 16;
+ else
+ maximum_bytes = 32;
+
+ /* 1. Total_bytes is integer for sure.
+ 2. Alignment is integer for sure.
+ 3. Maximum 4 or 8 registers, 4 * 4 = 16 bytes, 8 * 4 = 32 bytes.
+ 4. Requires (n * 4) block size.
+ 5. Requires 4-byte alignment. */
+ if (GET_CODE (total_bytes) != CONST_INT
+ || GET_CODE (alignment) != CONST_INT
+ || INTVAL (total_bytes) > maximum_bytes
+ || INTVAL (total_bytes) & 3
+ || INTVAL (alignment) & 3)
+ return 0;
+
+ dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0));
+ src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0));
+
+ out_words = in_words = INTVAL (total_bytes) / UNITS_PER_WORD;
+
+ emit_insn (nds32_expand_load_multiple (0, in_words, src_base_reg, srcmem));
+ emit_insn (nds32_expand_store_multiple (0, out_words, dst_base_reg, dstmem));
+
+ /* Successfully create patterns, return 1. */
+ return 1;
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-modes.def b/gcc/config/nds32/nds32-modes.def
index 041560eb71c..cfd0fe76d6c 100644
--- a/gcc/config/nds32/nds32-modes.def
+++ b/gcc/config/nds32/nds32-modes.def
@@ -1,5 +1,5 @@
/* Extra machine modes of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
diff --git a/gcc/config/nds32/nds32-multiple.md b/gcc/config/nds32/nds32-multiple.md
index 6783cbaf88e..977a144bb21 100644
--- a/gcc/config/nds32/nds32-multiple.md
+++ b/gcc/config/nds32/nds32-multiple.md
@@ -1,5 +1,5 @@
;; Load/Store Multiple patterns description of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.for NDS32.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/nds32-opts.h b/gcc/config/nds32/nds32-opts.h
index b05e2d44934..1aa0d31dff4 100644
--- a/gcc/config/nds32/nds32-opts.h
+++ b/gcc/config/nds32/nds32-opts.h
@@ -1,5 +1,5 @@
/* Definitions for option handling of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
@@ -32,4 +32,12 @@ enum nds32_arch_type
ARCH_V3M
};
+/* The code model defines the address generation strategy. */
+enum nds32_cmodel_type
+{
+ CMODEL_SMALL,
+ CMODEL_MEDIUM,
+ CMODEL_LARGE
+};
+
#endif
diff --git a/gcc/config/nds32/nds32-peephole2.md b/gcc/config/nds32/nds32-peephole2.md
index f9cd6dfc74b..df391cc0088 100644
--- a/gcc/config/nds32/nds32-peephole2.md
+++ b/gcc/config/nds32/nds32-peephole2.md
@@ -1,5 +1,5 @@
;; define_peephole2 optimization patterns of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
@@ -19,7 +19,6 @@
;; <http://www.gnu.org/licenses/>.
-;; Use define_peephole and define_peephole2 to handle possible
-;; target-specific optimization in this file.
+;; Use define_peephole2 to handle possible target-specific optimization.
;; ------------------------------------------------------------------------
diff --git a/gcc/config/nds32/nds32-pipelines-auxiliary.c b/gcc/config/nds32/nds32-pipelines-auxiliary.c
new file mode 100644
index 00000000000..6cc95939d2f
--- /dev/null
+++ b/gcc/config/nds32/nds32-pipelines-auxiliary.c
@@ -0,0 +1,89 @@
+/* Auxiliary functions for pipeline descriptions pattern of Andes
+ NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* This file is prepared for future implementation of precise
+ pipeline description for nds32 target. */
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-predicates.c b/gcc/config/nds32/nds32-predicates.c
new file mode 100644
index 00000000000..209b25f4c74
--- /dev/null
+++ b/gcc/config/nds32/nds32-predicates.c
@@ -0,0 +1,431 @@
+/* Predicate functions of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2015 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
+ <http://www.gnu.org/licenses/>. */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h" /* Required by recog.h. */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h" /* For DFA state_t. */
+#include "insn-codes.h" /* For CODE_FOR_xxx. */
+#include "reload.h" /* For push_reload(). */
+#include "flags.h"
+#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h" /* For GEN_FCN. */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h" /* For add_builtin_function(). */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* A subroutine that checks multiple load and store
+ using consecutive registers.
+ OP is a parallel rtx we would like to check.
+ LOAD_P indicates whether we are checking load operation.
+ PAR_INDEX is starting element of parallel rtx.
+ FIRST_ELT_REGNO is used to tell starting register number.
+ COUNT helps us to check consecutive register numbers. */
+static bool
+nds32_consecutive_registers_load_store_p (rtx op,
+ bool load_p,
+ int par_index,
+ int first_elt_regno,
+ int count)
+{
+ int i;
+ int check_regno;
+ rtx elt;
+ rtx elt_reg;
+ rtx elt_mem;
+
+ for (i = 0; i < count; i++)
+ {
+ /* Pick up each element from parallel rtx. */
+ elt = XVECEXP (op, 0, i + par_index);
+
+ /* If this element is not a 'set' rtx, return false immediately. */
+ if (GET_CODE (elt) != SET)
+ return false;
+
+ /* Pick up reg and mem of this element. */
+ elt_reg = load_p ? SET_DEST (elt) : SET_SRC (elt);
+ elt_mem = load_p ? SET_SRC (elt) : SET_DEST (elt);
+
+ /* If elt_reg is not a expected reg rtx, return false. */
+ if (GET_CODE (elt_reg) != REG || GET_MODE (elt_reg) != SImode)
+ return false;
+ /* If elt_mem is not a expected mem rtx, return false. */
+ if (GET_CODE (elt_mem) != MEM || GET_MODE (elt_mem) != SImode)
+ return false;
+
+ /* The consecutive registers should be in (Rb,Rb+1...Re) order. */
+ check_regno = first_elt_regno + i;
+
+ /* If the register number is not continuous, return false. */
+ if (REGNO (elt_reg) != (unsigned int) check_regno)
+ return false;
+ }
+
+ return true;
+}
+
+/* Function to check whether the OP is a valid load/store operation.
+ This is a helper function for the predicates:
+ 'nds32_load_multiple_operation' and 'nds32_store_multiple_operation'
+ in predicates.md file.
+
+ The OP is supposed to be a parallel rtx.
+ For each element within this parallel rtx:
+ (set (reg) (mem addr)) is the form for load operation.
+ (set (mem addr) (reg)) is the form for store operation.
+ We have to extract reg and mem of every element and
+ check if the information is valid for multiple load/store operation. */
+bool
+nds32_valid_multiple_load_store (rtx op, bool load_p)
+{
+ int count;
+ int first_elt_regno;
+ 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)
+ return false;
+
+ /* Pick up regno of first element for further detail checking.
+ Note that the form is different between load and store operation. */
+ if (load_p)
+ {
+ if (GET_CODE (SET_DEST (elt)) != REG
+ || GET_CODE (SET_SRC (elt)) != MEM)
+ return false;
+
+ first_elt_regno = REGNO (SET_DEST (elt));
+ }
+ else
+ {
+ if (GET_CODE (SET_SRC (elt)) != REG
+ || GET_CODE (SET_DEST (elt)) != MEM)
+ return false;
+
+ first_elt_regno = REGNO (SET_SRC (elt));
+ }
+
+ /* Perform detail check for each element.
+ Refer to nds32-multiple.md for more information
+ about following checking.
+ The starting element of parallel rtx is index 0. */
+ if (!nds32_consecutive_registers_load_store_p (op, load_p, 0,
+ first_elt_regno,
+ count))
+ return false;
+
+ /* Pass all test, this is a valid rtx. */
+ return true;
+}
+
+/* Function to check whether the OP is a valid stack push/pop operation.
+ For a valid stack operation, it must satisfy following conditions:
+ 1. Consecutive registers push/pop operations.
+ 2. Valid $fp/$gp/$lp push/pop operations.
+ 3. The last element must be stack adjustment rtx.
+ See the prologue/epilogue implementation for details. */
+bool
+nds32_valid_stack_push_pop_p (rtx op, bool push_p)
+{
+ int index;
+ int total_count;
+ int rest_count;
+ int first_regno;
+ int save_fp, save_gp, save_lp;
+ rtx elt;
+ rtx elt_reg;
+ rtx elt_mem;
+ rtx elt_plus;
+
+ /* Get the counts of elements in the parallel rtx. */
+ total_count = XVECLEN (op, 0);
+
+ /* Perform some quick check for that every element should be 'set'. */
+ for (index = 0; index < total_count; index++)
+ {
+ elt = XVECEXP (op, 0, index);
+ if (GET_CODE (elt) != SET)
+ return false;
+ }
+
+ /* For push operation, the parallel rtx looks like:
+ (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
+ (reg:SI Rb))
+ (set (mem (plus (reg:SI SP_REGNUM) (const_int -28)))
+ (reg:SI Rb+1))
+ ...
+ (set (mem (plus (reg:SI SP_REGNUM) (const_int -16)))
+ (reg:SI Re))
+ (set (mem (plus (reg:SI SP_REGNUM) (const_int -12)))
+ (reg:SI FP_REGNUM))
+ (set (mem (plus (reg:SI SP_REGNUM) (const_int -8)))
+ (reg:SI GP_REGNUM))
+ (set (mem (plus (reg:SI SP_REGNUM) (const_int -4)))
+ (reg:SI LP_REGNUM))
+ (set (reg:SI SP_REGNUM)
+ (plus (reg:SI SP_REGNUM) (const_int -32)))])
+
+ For pop operation, the parallel rtx looks like:
+ (parallel [(set (reg:SI Rb)
+ (mem (reg:SI SP_REGNUM)))
+ (set (reg:SI Rb+1)
+ (mem (plus (reg:SI SP_REGNUM) (const_int 4))))
+ ...
+ (set (reg:SI Re)
+ (mem (plus (reg:SI SP_REGNUM) (const_int 16))))
+ (set (reg:SI FP_REGNUM)
+ (mem (plus (reg:SI SP_REGNUM) (const_int 20))))
+ (set (reg:SI GP_REGNUM)
+ (mem (plus (reg:SI SP_REGNUM) (const_int 24))))
+ (set (reg:SI LP_REGNUM)
+ (mem (plus (reg:SI SP_REGNUM) (const_int 28))))
+ (set (reg:SI SP_REGNUM)
+ (plus (reg:SI SP_REGNUM) (const_int 32)))]) */
+
+ /* 1. Consecutive registers push/pop operations.
+ We need to calculate how many registers should be consecutive.
+ The $sp adjustment rtx, $fp push rtx, $gp push rtx,
+ and $lp push rtx are excluded. */
+
+ /* Detect whether we have $fp, $gp, or $lp in the parallel rtx. */
+ save_fp = reg_mentioned_p (gen_rtx_REG (SImode, FP_REGNUM), op);
+ save_gp = reg_mentioned_p (gen_rtx_REG (SImode, GP_REGNUM), op);
+ save_lp = reg_mentioned_p (gen_rtx_REG (SImode, LP_REGNUM), op);
+ /* Exclude last $sp adjustment rtx. */
+ rest_count = total_count - 1;
+ /* Exclude $fp, $gp, and $lp if they are in the parallel rtx. */
+ if (save_fp)
+ rest_count--;
+ if (save_gp)
+ rest_count--;
+ if (save_lp)
+ rest_count--;
+
+ if (rest_count > 0)
+ {
+ elt = XVECEXP (op, 0, 0);
+ /* Pick up register element. */
+ elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
+ first_regno = REGNO (elt_reg);
+
+ /* The 'push' operation is a kind of store operation.
+ The 'pop' operation is a kind of load operation.
+ Pass corresponding false/true as second argument (bool load_p).
+ The par_index is supposed to start with index 0. */
+ if (!nds32_consecutive_registers_load_store_p (op,
+ !push_p ? true : false,
+ 0,
+ first_regno,
+ rest_count))
+ return false;
+ }
+
+ /* 2. Valid $fp/$gp/$lp push/pop operations.
+ Remember to set start index for checking them. */
+
+ /* The rest_count is the start index for checking $fp/$gp/$lp. */
+ index = rest_count;
+ /* If index < 0, this parallel rtx is definitely
+ not a valid stack push/pop operation. */
+ if (index < 0)
+ return false;
+
+ /* Check $fp/$gp/$lp one by one.
+ We use 'push_p' to pick up reg rtx and mem rtx. */
+ if (save_fp)
+ {
+ elt = XVECEXP (op, 0, index);
+ elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
+ elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
+ index++;
+
+ if (GET_CODE (elt_mem) != MEM
+ || GET_CODE (elt_reg) != REG
+ || REGNO (elt_reg) != FP_REGNUM)
+ return false;
+ }
+ if (save_gp)
+ {
+ elt = XVECEXP (op, 0, index);
+ elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
+ elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
+ index++;
+
+ if (GET_CODE (elt_mem) != MEM
+ || GET_CODE (elt_reg) != REG
+ || REGNO (elt_reg) != GP_REGNUM)
+ return false;
+ }
+ if (save_lp)
+ {
+ elt = XVECEXP (op, 0, index);
+ elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
+ elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
+ index++;
+
+ if (GET_CODE (elt_mem) != MEM
+ || GET_CODE (elt_reg) != REG
+ || REGNO (elt_reg) != LP_REGNUM)
+ return false;
+ }
+
+ /* 3. The last element must be stack adjustment rtx.
+ Its form of rtx should be:
+ (set (reg:SI SP_REGNUM)
+ (plus (reg:SI SP_REGNUM) (const_int X)))
+ The X could be positive or negative value. */
+
+ /* Pick up the last element. */
+ elt = XVECEXP (op, 0, total_count - 1);
+
+ /* Extract its destination and source rtx. */
+ elt_reg = SET_DEST (elt);
+ elt_plus = SET_SRC (elt);
+
+ /* Check this is (set (stack_reg) (plus stack_reg const)) pattern. */
+ if (GET_CODE (elt_reg) != REG
+ || GET_CODE (elt_plus) != PLUS
+ || REGNO (elt_reg) != SP_REGNUM)
+ return false;
+
+ /* Pass all test, this is a valid rtx. */
+ return true;
+}
+
+/* Function to check if 'bclr' instruction can be used with IVAL. */
+int
+nds32_can_use_bclr_p (int ival)
+{
+ int one_bit_count;
+
+ /* Calculate the number of 1-bit of (~ival), if there is only one 1-bit,
+ it means the original ival has only one 0-bit,
+ So it is ok to perform 'bclr' operation. */
+
+ one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (~ival));
+
+ /* 'bclr' is a performance extension instruction. */
+ return (TARGET_PERF_EXT && (one_bit_count == 1));
+}
+
+/* Function to check if 'bset' instruction can be used with IVAL. */
+int
+nds32_can_use_bset_p (int ival)
+{
+ int one_bit_count;
+
+ /* Caculate the number of 1-bit of ival, if there is only one 1-bit,
+ it is ok to perform 'bset' operation. */
+
+ one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival));
+
+ /* 'bset' is a performance extension instruction. */
+ return (TARGET_PERF_EXT && (one_bit_count == 1));
+}
+
+/* Function to check if 'btgl' instruction can be used with IVAL. */
+int
+nds32_can_use_btgl_p (int ival)
+{
+ int one_bit_count;
+
+ /* Caculate the number of 1-bit of ival, if there is only one 1-bit,
+ it is ok to perform 'btgl' operation. */
+
+ one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival));
+
+ /* 'btgl' is a performance extension instruction. */
+ return (TARGET_PERF_EXT && (one_bit_count == 1));
+}
+
+/* Function to check if 'bitci' instruction can be used with IVAL. */
+int
+nds32_can_use_bitci_p (int ival)
+{
+ /* If we are using V3 ISA, we have 'bitci' instruction.
+ Try to see if we can present 'andi' semantic with
+ such 'bit-clear-immediate' operation.
+ For example, 'andi $r0,$r0,0xfffffffc' can be
+ presented with 'bitci $r0,$r0,3'. */
+ return (TARGET_ISA_V3
+ && (ival < 0)
+ && satisfies_constraint_Iu15 (gen_int_mode (~ival, SImode)));
+}
+
+/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h
index 6d94027bb6e..620d897535a 100644
--- a/gcc/config/nds32/nds32-protos.h
+++ b/gcc/config/nds32/nds32-protos.h
@@ -1,5 +1,5 @@
/* Prototypes for exported functions of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
@@ -30,8 +30,8 @@ extern void nds32_init_expanders (void);
/* -- 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);
+extern int nds32_hard_regno_nregs (int, machine_mode);
+extern int nds32_hard_regno_mode_ok (int, machine_mode);
/* Register Classes. */
@@ -58,15 +58,15 @@ extern void nds32_init_cumulative_args (CUMULATIVE_ARGS *,
/* -- Function Entry and Exit. */
extern void nds32_expand_prologue (void);
-extern void nds32_expand_epilogue (void);
+extern void nds32_expand_epilogue (bool);
extern void nds32_expand_prologue_v3push (void);
-extern void nds32_expand_epilogue_v3pop (void);
+extern void nds32_expand_epilogue_v3pop (bool);
/* ------------------------------------------------------------------------ */
/* Auxiliary functions for auxiliary macros in nds32.h. */
-extern bool nds32_ls_333_p (rtx, rtx, rtx, enum machine_mode);
+extern bool nds32_ls_333_p (rtx, rtx, rtx, machine_mode);
/* Auxiliary functions for expanding rtl used in nds32-multiple.md. */
@@ -80,7 +80,7 @@ extern bool nds32_valid_multiple_load_store (rtx, bool);
/* Auxiliary functions for stack operation predicate checking. */
-extern bool nds32_valid_stack_push_pop (rtx, bool);
+extern bool nds32_valid_stack_push_pop_p (rtx, bool);
/* Auxiliary functions for bit operation detection. */
@@ -92,11 +92,10 @@ 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);
+extern int nds32_adjust_insn_length (rtx_insn *, 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. */
@@ -118,11 +117,34 @@ extern const char *nds32_output_32bit_load_s (rtx *, int);
/* Auxiliary functions to output stack push/pop instruction. */
-extern const char *nds32_output_stack_push (void);
-extern const char *nds32_output_stack_pop (void);
+extern const char *nds32_output_stack_push (rtx);
+extern const char *nds32_output_stack_pop (rtx);
+
+/* Auxiliary functions to check using return with null epilogue. */
+
+extern int nds32_can_use_return_insn (void);
/* Auxiliary functions to decide output alignment or not. */
extern int nds32_target_alignment (rtx);
+/* Auxiliary functions to expand builtin functions. */
+
+extern void nds32_init_builtins_impl (void);
+extern rtx nds32_expand_builtin_impl (tree, rtx, rtx,
+ machine_mode, int);
+
+/* Auxiliary functions for ISR implementation. */
+
+extern void nds32_check_isr_attrs_conflict (tree, tree);
+extern void nds32_construct_isr_vectors_information (tree, const char *);
+extern void nds32_asm_file_start_for_isr (void);
+extern void nds32_asm_file_end_for_isr (void);
+extern bool nds32_isr_function_p (tree);
+
+/* Auxiliary functions for cost calculation. */
+
+extern bool nds32_rtx_costs_impl (rtx, int, int, int, int *, bool);
+extern int nds32_address_cost_impl (rtx, machine_mode, addr_space_t, bool);
+
/* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c
index 645d8dda335..1845bc21812 100644
--- a/gcc/config/nds32/nds32.c
+++ b/gcc/config/nds32/nds32.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
@@ -18,12 +18,21 @@
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-
+/* ------------------------------------------------------------------------ */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
#include "tree.h"
#include "stor-layout.h"
#include "varasm.h"
@@ -39,9 +48,28 @@
#include "reload.h" /* For push_reload(). */
#include "flags.h"
#include "function.h"
+#include "hashtab.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "recog.h"
#include "diagnostic-core.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "lcm.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
+#include "predict.h"
+#include "basic-block.h"
#include "df.h"
#include "tm_p.h"
#include "tm-constrs.h"
@@ -50,6 +78,7 @@
#include "target-def.h"
#include "langhooks.h" /* For add_builtin_function(). */
#include "ggc.h"
+#include "builtins.h"
/* ------------------------------------------------------------------------ */
@@ -72,13 +101,6 @@
/* PART 1: Auxiliary static variable definitions and
target hook static variable definitions. */
-/* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
- 0 for reset handler with __attribute__((reset())),
- 1-8 for exception handler with __attribute__((exception(1,...,8))),
- and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
- We use an array to record essential information for each vector. */
-static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
-
/* Define intrinsic register names.
Please refer to nds32_intrinsic.h file, the index is corresponding to
'enum nds32_intrinsic_registers' data type values.
@@ -131,7 +153,7 @@ static struct machine_function *
nds32_init_machine_status (void)
{
struct machine_function *machine;
- machine = ggc_alloc_cleared_machine_function ();
+ machine = ggc_cleared_alloc<machine_function> ();
/* Initially assume this function needs prologue/epilogue. */
machine->naked_p = 0;
@@ -156,16 +178,30 @@ nds32_compute_stack_frame (void)
cfun->machine->naked_p = 0;
/* Get variadic arguments size to prepare pretend arguments and
- push them into stack at prologue.
- Currently, we do not push variadic arguments by ourself.
- We have GCC handle all the works.
- The caller will push all corresponding nameless arguments into stack,
- and the callee is able to retrieve them without problems.
- These variables are still preserved in case one day
- we would like caller passing arguments with registers. */
- cfun->machine->va_args_size = 0;
- cfun->machine->va_args_first_regno = SP_REGNUM;
- cfun->machine->va_args_last_regno = SP_REGNUM;
+ we will push them into stack at prologue by ourself. */
+ cfun->machine->va_args_size = crtl->args.pretend_args_size;
+ if (cfun->machine->va_args_size != 0)
+ {
+ cfun->machine->va_args_first_regno
+ = NDS32_GPR_ARG_FIRST_REGNUM
+ + NDS32_MAX_GPR_REGS_FOR_ARGS
+ - (crtl->args.pretend_args_size / UNITS_PER_WORD);
+ cfun->machine->va_args_last_regno
+ = NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS - 1;
+ }
+ else
+ {
+ cfun->machine->va_args_first_regno = SP_REGNUM;
+ cfun->machine->va_args_last_regno = SP_REGNUM;
+ }
+
+ /* Important: We need to make sure that varargs area is 8-byte alignment. */
+ block_size = cfun->machine->va_args_size;
+ if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size))
+ {
+ cfun->machine->va_args_area_padding_bytes
+ = NDS32_ROUND_UP_DOUBLE_WORD (block_size) - block_size;
+ }
/* Get local variables, incoming variables, and temporary variables size.
Note that we need to make sure it is 8-byte alignment because
@@ -221,7 +257,8 @@ nds32_compute_stack_frame (void)
which means we do not have to save
any callee-saved registers.
condition 2: Both $lp and $fp are NOT live in this function,
- which means we do not need to save them.
+ which means we do not need to save them and there
+ is no outgoing size.
condition 3: There is no local_size, which means
we do not need to adjust $sp. */
if (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl))
@@ -231,8 +268,11 @@ nds32_compute_stack_frame (void)
&& !df_regs_ever_live_p (LP_REGNUM)
&& cfun->machine->local_size == 0))
{
- /* Set this function 'naked_p' and
- other functions can check this flag. */
+ /* Set this function 'naked_p' and other functions can check this flag.
+ Note that in nds32 port, the 'naked_p = 1' JUST means there is no
+ callee-saved, local size, and outgoing size.
+ The varargs space and ret instruction may still present in
+ the prologue/epilogue expanding. */
cfun->machine->naked_p = 1;
/* No need to save $fp, $gp, and $lp.
@@ -256,8 +296,11 @@ nds32_compute_stack_frame (void)
we need to make sure Rb is $r6 and Re is
located on $r6, $r8, $r10, or $r14.
Some results above will be discarded and recomputed.
- Note that it is only available under V3/V3M ISA. */
- if (TARGET_V3PUSH)
+ Note that it is only available under V3/V3M ISA and we
+ DO NOT setup following stuff for isr or variadic function. */
+ if (TARGET_V3PUSH
+ && !nds32_isr_function_p (current_function_decl)
+ && (cfun->machine->va_args_size == 0))
{
/* Recompute:
cfun->machine->fp_size
@@ -322,12 +365,10 @@ nds32_compute_stack_frame (void)
}
/* Important: We need to make sure that
- (va_args_size + fp_size + gp_size
- + lp_size + callee_saved_regs_size)
+ (fp_size + gp_size + lp_size + callee_saved_regs_size)
is 8-byte alignment.
If it is not, calculate the padding bytes. */
- block_size = cfun->machine->va_args_size
- + cfun->machine->fp_size
+ block_size = cfun->machine->fp_size
+ cfun->machine->gp_size
+ cfun->machine->lp_size
+ cfun->machine->callee_saved_regs_size;
@@ -353,21 +394,22 @@ nds32_compute_stack_frame (void)
The overall concept are:
"push registers to memory",
"adjust stack pointer". */
-static rtx
-nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
- rtx En4 ATTRIBUTE_UNUSED)
+static void
+nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
{
int regno;
int extra_count;
int num_use_regs;
int par_index;
int offset;
+ int save_fp, save_gp, save_lp;
rtx reg;
rtx mem;
rtx push_rtx;
rtx adjust_sp_rtx;
rtx parallel_insn;
+ rtx dwarf;
/* We need to provide a customized rtx which contains
necessary information for data analysis,
@@ -388,13 +430,18 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
(set (reg:SI SP_REGNUM)
(plus (reg:SI SP_REGNUM) (const_int -32)))]) */
+ /* Determine whether we need to save $fp, $gp, or $lp. */
+ save_fp = INTVAL (En4) & 0x8;
+ save_gp = INTVAL (En4) & 0x4;
+ save_lp = INTVAL (En4) & 0x2;
+
/* Calculate the number of registers that will be pushed. */
extra_count = 0;
- if (cfun->machine->fp_size)
+ if (save_fp)
extra_count++;
- if (cfun->machine->gp_size)
+ if (save_gp)
extra_count++;
- if (cfun->machine->lp_size)
+ if (save_lp)
extra_count++;
/* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */
if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
@@ -417,7 +464,7 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
/* Rb and Re may be SP_REGNUM.
We need to break this loop immediately. */
if (regno == SP_REGNUM)
- break;
+ break;
reg = gen_rtx_REG (SImode, regno);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -431,7 +478,7 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
}
/* Create (set mem fp), (set mem gp), and (set mem lp) if necessary. */
- if (cfun->machine->fp_size)
+ if (save_fp)
{
reg = gen_rtx_REG (SImode, FP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -443,7 +490,7 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
offset = offset + 4;
par_index++;
}
- if (cfun->machine->gp_size)
+ if (save_gp)
{
reg = gen_rtx_REG (SImode, GP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -455,7 +502,7 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
offset = offset + 4;
par_index++;
}
- if (cfun->machine->lp_size)
+ if (save_lp)
{
reg = gen_rtx_REG (SImode, LP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -479,7 +526,21 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
- return parallel_insn;
+ parallel_insn = emit_insn (parallel_insn);
+
+ /* The insn rtx 'parallel_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (parallel_insn) = 1;
+
+ /* Don't use GCC's logic for CFI info if we are generate a push for VAARG
+ since we will not restore those register at epilogue. */
+ if (vaarg_p)
+ {
+ dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA,
+ copy_rtx (adjust_sp_rtx), NULL_RTX);
+ REG_NOTES (parallel_insn) = dwarf;
+ }
}
/* Function to create a parallel rtx pattern
@@ -487,21 +548,22 @@ nds32_gen_stack_push_multiple (rtx Rb, rtx Re,
The overall concept are:
"pop registers from memory",
"adjust stack pointer". */
-static rtx
-nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
- rtx En4 ATTRIBUTE_UNUSED)
+static void
+nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
{
int regno;
int extra_count;
int num_use_regs;
int par_index;
int offset;
+ int save_fp, save_gp, save_lp;
rtx reg;
rtx mem;
rtx pop_rtx;
rtx adjust_sp_rtx;
rtx parallel_insn;
+ rtx dwarf = NULL_RTX;
/* We need to provide a customized rtx which contains
necessary information for data analysis,
@@ -522,13 +584,18 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
(set (reg:SI SP_REGNUM)
(plus (reg:SI SP_REGNUM) (const_int 32)))]) */
+ /* Determine whether we need to restore $fp, $gp, or $lp. */
+ save_fp = INTVAL (En4) & 0x8;
+ save_gp = INTVAL (En4) & 0x4;
+ save_lp = INTVAL (En4) & 0x2;
+
/* Calculate the number of registers that will be poped. */
extra_count = 0;
- if (cfun->machine->fp_size)
+ if (save_fp)
extra_count++;
- if (cfun->machine->gp_size)
+ if (save_gp)
extra_count++;
- if (cfun->machine->lp_size)
+ if (save_lp)
extra_count++;
/* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */
if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
@@ -551,7 +618,7 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
/* Rb and Re may be SP_REGNUM.
We need to break this loop immediately. */
if (regno == SP_REGNUM)
- break;
+ break;
reg = gen_rtx_REG (SImode, regno);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -562,10 +629,12 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
}
/* Create (set fp mem), (set gp mem), and (set lp mem) if necessary. */
- if (cfun->machine->fp_size)
+ if (save_fp)
{
reg = gen_rtx_REG (SImode, FP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -576,8 +645,10 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
}
- if (cfun->machine->gp_size)
+ if (save_gp)
{
reg = gen_rtx_REG (SImode, GP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -588,8 +659,10 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
}
- if (cfun->machine->lp_size)
+ if (save_lp)
{
reg = gen_rtx_REG (SImode, LP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -600,6 +673,8 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
}
/* Create (set sp sp+x). */
@@ -610,9 +685,19 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx, offset));
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
- RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
- return parallel_insn;
+ /* Tell gcc we adjust SP in this insn. */
+ dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf);
+
+ parallel_insn = emit_insn (parallel_insn);
+
+ /* The insn rtx 'parallel_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (parallel_insn) = 1;
+
+ /* Add CFI info by manual. */
+ REG_NOTES (parallel_insn) = dwarf;
}
/* Function to create a parallel rtx pattern
@@ -620,11 +705,11 @@ nds32_gen_stack_pop_multiple (rtx Rb, rtx Re,
The overall concept are:
"push registers to memory",
"adjust stack pointer". */
-static rtx
-nds32_gen_stack_v3push (rtx Rb,
- rtx Re,
- rtx En4 ATTRIBUTE_UNUSED,
- rtx imm8u)
+static void
+nds32_emit_stack_v3push (rtx Rb,
+ rtx Re,
+ rtx En4 ATTRIBUTE_UNUSED,
+ rtx imm8u)
{
int regno;
int num_use_regs;
@@ -640,8 +725,7 @@ nds32_gen_stack_v3push (rtx Rb,
/* We need to provide a customized rtx which contains
necessary information for data analysis,
so we create a parallel rtx like this:
- (parallel [
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
+ (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
(reg:SI Rb))
(set (mem (plus (reg:SI SP_REGNUM) (const_int -28)))
(reg:SI Rb+1))
@@ -733,7 +817,12 @@ nds32_gen_stack_v3push (rtx Rb,
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
- return parallel_insn;
+ parallel_insn = emit_insn (parallel_insn);
+
+ /* The insn rtx 'parallel_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (parallel_insn) = 1;
}
/* Function to create a parallel rtx pattern
@@ -741,11 +830,11 @@ nds32_gen_stack_v3push (rtx Rb,
The overall concept are:
"pop registers from memory",
"adjust stack pointer". */
-static rtx
-nds32_gen_stack_v3pop (rtx Rb,
- rtx Re,
- rtx En4 ATTRIBUTE_UNUSED,
- rtx imm8u)
+static void
+nds32_emit_stack_v3pop (rtx Rb,
+ rtx Re,
+ rtx En4 ATTRIBUTE_UNUSED,
+ rtx imm8u)
{
int regno;
int num_use_regs;
@@ -757,6 +846,7 @@ nds32_gen_stack_v3pop (rtx Rb,
rtx pop_rtx;
rtx adjust_sp_rtx;
rtx parallel_insn;
+ rtx dwarf = NULL_RTX;
/* We need to provide a customized rtx which contains
necessary information for data analysis,
@@ -807,6 +897,8 @@ nds32_gen_stack_v3pop (rtx Rb,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
}
/* Create (set fp mem). */
@@ -819,6 +911,8 @@ nds32_gen_stack_v3pop (rtx Rb,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+
/* Create (set gp mem). */
reg = gen_rtx_REG (SImode, GP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -829,6 +923,8 @@ nds32_gen_stack_v3pop (rtx Rb,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+
/* Create (set lp mem ). */
reg = gen_rtx_REG (SImode, LP_REGNUM);
mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -839,6 +935,7 @@ nds32_gen_stack_v3pop (rtx Rb,
RTX_FRAME_RELATED_P (pop_rtx) = 1;
offset = offset + 4;
par_index++;
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
/* Create (set sp sp+x+imm8u). */
@@ -850,507 +947,19 @@ nds32_gen_stack_v3pop (rtx Rb,
stack_pointer_rtx,
offset + INTVAL (imm8u)));
XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
- RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
-
- return parallel_insn;
-}
-
-/* A subroutine that checks multiple load and store
- using consecutive registers.
- OP is a parallel rtx we would like to check.
- LOAD_P indicates whether we are checking load operation.
- PAR_INDEX is starting element of parallel rtx.
- FIRST_ELT_REGNO is used to tell starting register number.
- COUNT helps us to check consecutive register numbers. */
-static bool
-nds32_consecutive_registers_load_store_p (rtx op,
- bool load_p,
- int par_index,
- int first_elt_regno,
- int count)
-{
- int i;
- int check_regno;
- rtx elt;
- rtx elt_reg;
- rtx elt_mem;
-
- for (i = 0; i < count; i++)
- {
- /* Pick up each element from parallel rtx. */
- elt = XVECEXP (op, 0, i + par_index);
-
- /* If this element is not a 'set' rtx, return false immediately. */
- if (GET_CODE (elt) != SET)
- return false;
-
- /* Pick up reg and mem of this element. */
- elt_reg = load_p ? SET_DEST (elt) : SET_SRC (elt);
- elt_mem = load_p ? SET_SRC (elt) : SET_DEST (elt);
-
- /* If elt_reg is not a expected reg rtx, return false. */
- if (GET_CODE (elt_reg) != REG || GET_MODE (elt_reg) != SImode)
- return false;
- /* If elt_mem is not a expected mem rtx, return false. */
- if (GET_CODE (elt_mem) != MEM || GET_MODE (elt_mem) != SImode)
- return false;
-
- /* The consecutive registers should be in (Rb,Rb+1...Re) order. */
- check_regno = first_elt_regno + i;
-
- /* If the register number is not continuous, return false. */
- if (REGNO (elt_reg) != (unsigned int) check_regno)
- return false;
- }
-
- return true;
-}
-
-/* A helper function to emit section head template. */
-static void
-nds32_emit_section_head_template (char section_name[],
- char symbol_name[],
- int align_value,
- bool object_p)
-{
- const char *flags_str;
- const char *type_str;
-
- flags_str = (object_p) ? "\"a\"" : "\"ax\"";
- type_str = (object_p) ? "@object" : "@function";
-
- fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
- fprintf (asm_out_file, "\t.align\t%d\n", align_value);
- fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
- fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
- fprintf (asm_out_file, "%s:\n", symbol_name);
-}
-
-/* A helper function to emit section tail template. */
-static void
-nds32_emit_section_tail_template (char symbol_name[])
-{
- fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
-}
-
-/* Function to emit isr jump table section. */
-static void
-nds32_emit_isr_jmptbl_section (int vector_id)
-{
- char section_name[100];
- char symbol_name[100];
-
- /* Prepare jmptbl section and symbol name. */
- snprintf (section_name, sizeof (section_name),
- ".nds32_jmptbl.%02d", vector_id);
- snprintf (symbol_name, sizeof (symbol_name),
- "_nds32_jmptbl_%02d", vector_id);
-
- nds32_emit_section_head_template (section_name, symbol_name, 2, true);
- fprintf (asm_out_file, "\t.word\t%s\n",
- nds32_isr_vectors[vector_id].func_name);
- nds32_emit_section_tail_template (symbol_name);
-}
-
-/* Function to emit isr vector section. */
-static void
-nds32_emit_isr_vector_section (int vector_id)
-{
- unsigned int vector_number_offset = 0;
- const char *c_str = "CATEGORY";
- const char *sr_str = "SR";
- const char *nt_str = "NT";
- const char *vs_str = "VS";
- char first_level_handler_name[100];
- char section_name[100];
- char symbol_name[100];
-
- /* Set the vector number offset so that we can calculate
- the value that user specifies in the attribute.
- We also prepare the category string for first level handler name. */
- switch (nds32_isr_vectors[vector_id].category)
- {
- case NDS32_ISR_INTERRUPT:
- vector_number_offset = 9;
- c_str = "i";
- break;
- case NDS32_ISR_EXCEPTION:
- vector_number_offset = 0;
- c_str = "e";
- break;
- case NDS32_ISR_NONE:
- case NDS32_ISR_RESET:
- /* Normally it should not be here. */
- gcc_unreachable ();
- break;
- }
-
- /* Prepare save reg string for first level handler name. */
- switch (nds32_isr_vectors[vector_id].save_reg)
- {
- case NDS32_SAVE_ALL:
- sr_str = "sa";
- break;
- case NDS32_PARTIAL_SAVE:
- sr_str = "ps";
- break;
- }
-
- /* Prepare nested type string for first level handler name. */
- switch (nds32_isr_vectors[vector_id].nested_type)
- {
- case NDS32_NESTED:
- nt_str = "ns";
- break;
- case NDS32_NOT_NESTED:
- nt_str = "nn";
- break;
- case NDS32_NESTED_READY:
- nt_str = "nr";
- break;
- }
- /* Currently we have 4-byte or 16-byte size for each vector.
- If it is 4-byte, the first level handler name has suffix string "_4b". */
- vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
+ /* Tell gcc we adjust SP in this insn. */
+ dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf);
- /* Now we can create first level handler name. */
- snprintf (first_level_handler_name, sizeof (first_level_handler_name),
- "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
+ parallel_insn = emit_insn (parallel_insn);
- /* Prepare vector section and symbol name. */
- snprintf (section_name, sizeof (section_name),
- ".nds32_vector.%02d", vector_id);
- snprintf (symbol_name, sizeof (symbol_name),
- "_nds32_vector_%02d%s", vector_id, vs_str);
+ /* The insn rtx 'parallel_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (parallel_insn) = 1;
-
- /* Everything is ready. We can start emit vector section content. */
- nds32_emit_section_head_template (section_name, symbol_name,
- floor_log2 (nds32_isr_vector_size), false);
-
- /* According to the vector size, the instructions in the
- vector section may be different. */
- if (nds32_isr_vector_size == 4)
- {
- /* This block is for 4-byte vector size.
- Hardware $VID support is necessary and only one instruction
- is needed in vector section. */
- fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
- first_level_handler_name);
- }
- else
- {
- /* This block is for 16-byte vector size.
- There is NO hardware $VID so that we need several instructions
- such as pushing GPRs and preparing software vid at vector section.
- For pushing GPRs, there are four variations for
- 16-byte vector content and we have to handle each combination.
- For preparing software vid, note that the vid need to
- be substracted vector_number_offset. */
- if (TARGET_REDUCED_REGS)
- {
- if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
- {
- /* Case of reduced set registers and save_all attribute. */
- fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
-
- }
- else
- {
- /* Case of reduced set registers and partial_save attribute. */
- fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
- }
- }
- else
- {
- if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
- {
- /* Case of full set registers and save_all attribute. */
- fprintf (asm_out_file, "\t! full set regs + save_all\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
- }
- else
- {
- /* Case of full set registers and partial_save attribute. */
- fprintf (asm_out_file, "\t! full set regs + partial_save\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
- fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
- }
- }
-
- fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
- vector_id - vector_number_offset);
- fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
- first_level_handler_name);
- }
-
- nds32_emit_section_tail_template (symbol_name);
-}
-
-/* Function to emit isr reset handler content.
- Including all jmptbl/vector references, jmptbl section,
- vector section, nmi handler section, and warm handler section. */
-static void
-nds32_emit_isr_reset_content (void)
-{
- unsigned int i;
- unsigned int total_n_vectors;
- const char *vs_str;
- char reset_handler_name[100];
- char section_name[100];
- char symbol_name[100];
-
- total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
- vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
-
- fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
-
- /* Create references in .rodata according to total number of vectors. */
- fprintf (asm_out_file, "\t.section\t.rodata\n");
- fprintf (asm_out_file, "\t.align\t2\n");
-
- /* Emit jmptbl references. */
- fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
- for (i = 0; i < total_n_vectors; i++)
- fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
-
- /* Emit vector references. */
- fprintf (asm_out_file, "\t ! references to vector section entries\n");
- for (i = 0; i < total_n_vectors; i++)
- fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
-
- /* Emit jmptbl_00 section. */
- snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
- snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
-
- fprintf (asm_out_file, "\t! ....................................\n");
- nds32_emit_section_head_template (section_name, symbol_name, 2, true);
- fprintf (asm_out_file, "\t.word\t%s\n",
- nds32_isr_vectors[0].func_name);
- nds32_emit_section_tail_template (symbol_name);
-
- /* Emit vector_00 section. */
- snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
- snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
- snprintf (reset_handler_name, sizeof (reset_handler_name),
- "_nds32_reset%s", vs_str);
-
- fprintf (asm_out_file, "\t! ....................................\n");
- nds32_emit_section_head_template (section_name, symbol_name,
- floor_log2 (nds32_isr_vector_size), false);
- fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
- reset_handler_name);
- nds32_emit_section_tail_template (symbol_name);
-
- /* Emit nmi handler section. */
- snprintf (section_name, sizeof (section_name), ".nds32_nmih");
- snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
-
- fprintf (asm_out_file, "\t! ....................................\n");
- nds32_emit_section_head_template (section_name, symbol_name, 2, true);
- fprintf (asm_out_file, "\t.word\t%s\n",
- (strlen (nds32_isr_vectors[0].nmi_name) == 0)
- ? "0"
- : nds32_isr_vectors[0].nmi_name);
- nds32_emit_section_tail_template (symbol_name);
-
- /* Emit warm handler section. */
- snprintf (section_name, sizeof (section_name), ".nds32_wrh");
- snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
-
- fprintf (asm_out_file, "\t! ....................................\n");
- nds32_emit_section_head_template (section_name, symbol_name, 2, true);
- fprintf (asm_out_file, "\t.word\t%s\n",
- (strlen (nds32_isr_vectors[0].warm_name) == 0)
- ? "0"
- : nds32_isr_vectors[0].warm_name);
- nds32_emit_section_tail_template (symbol_name);
-
- fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
-}
-
-/* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
- to check if there are any conflict isr-specific attributes being set.
- We need to check:
- 1. Only 'save_all' or 'partial_save' in the attributes.
- 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
- 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
-static void
-nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
-{
- int save_all_p, partial_save_p;
- int nested_p, not_nested_p, nested_ready_p;
- int intr_p, excp_p, reset_p;
-
- /* Initialize variables. */
- save_all_p = partial_save_p = 0;
- nested_p = not_nested_p = nested_ready_p = 0;
- intr_p = excp_p = reset_p = 0;
-
- /* We must check at MOST one attribute to set save-reg. */
- if (lookup_attribute ("save_all", func_attrs))
- save_all_p = 1;
- if (lookup_attribute ("partial_save", func_attrs))
- partial_save_p = 1;
-
- if ((save_all_p + partial_save_p) > 1)
- error ("multiple save reg attributes to function %qD", func_decl);
-
- /* We must check at MOST one attribute to set nested-type. */
- if (lookup_attribute ("nested", func_attrs))
- nested_p = 1;
- if (lookup_attribute ("not_nested", func_attrs))
- not_nested_p = 1;
- if (lookup_attribute ("nested_ready", func_attrs))
- nested_ready_p = 1;
-
- if ((nested_p + not_nested_p + nested_ready_p) > 1)
- error ("multiple nested types attributes to function %qD", func_decl);
-
- /* We must check at MOST one attribute to
- set interrupt/exception/reset. */
- if (lookup_attribute ("interrupt", func_attrs))
- intr_p = 1;
- if (lookup_attribute ("exception", func_attrs))
- excp_p = 1;
- if (lookup_attribute ("reset", func_attrs))
- reset_p = 1;
-
- if ((intr_p + excp_p + reset_p) > 1)
- error ("multiple interrupt attributes to function %qD", func_decl);
-}
-
-/* Function to construct isr vectors information array.
- We DO NOT HAVE TO check if the attributes are valid
- because those works are supposed to be done on
- nds32_merge_decl_attributes() and nds32_insert_attributes(). */
-static void
-nds32_construct_isr_vectors_information (tree func_attrs,
- const char *func_name)
-{
- tree save_all, partial_save;
- tree nested, not_nested, nested_ready;
- tree intr, excp, reset;
-
- save_all = lookup_attribute ("save_all", func_attrs);
- partial_save = lookup_attribute ("partial_save", func_attrs);
-
- nested = lookup_attribute ("nested", func_attrs);
- not_nested = lookup_attribute ("not_nested", func_attrs);
- nested_ready = lookup_attribute ("nested_ready", func_attrs);
-
- intr = lookup_attribute ("interrupt", func_attrs);
- excp = lookup_attribute ("exception", func_attrs);
- reset = lookup_attribute ("reset", func_attrs);
-
- /* If there is no interrupt/exception/reset, we can return immediately. */
- if (!intr && !excp && !reset)
- return;
-
- /* If we are here, either we have interrupt/exception,
- or reset attribute. */
- if (intr || excp)
- {
- tree id_list;
-
- /* Prepare id list so that we can traverse and set vector id. */
- id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
-
- while (id_list)
- {
- tree id;
- int vector_id;
- unsigned int vector_number_offset;
-
- /* The way to handle interrupt or exception is the same,
- we just need to take care of actual vector number.
- For interrupt(0..63), the actual vector number is (9..72).
- For exception(1..8), the actual vector number is (1..8). */
- vector_number_offset = (intr) ? (9) : (0);
-
- /* Pick up each vector id value. */
- id = TREE_VALUE (id_list);
- /* Add vector_number_offset to get actual vector number. */
- vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
-
- /* Enable corresponding vector and set function name. */
- nds32_isr_vectors[vector_id].category = (intr)
- ? (NDS32_ISR_INTERRUPT)
- : (NDS32_ISR_EXCEPTION);
- strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
-
- /* Set register saving scheme. */
- if (save_all)
- nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
- else if (partial_save)
- nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
-
- /* Set nested type. */
- if (nested)
- nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
- else if (not_nested)
- nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
- else if (nested_ready)
- nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
-
- /* Advance to next id. */
- id_list = TREE_CHAIN (id_list);
- }
- }
- else
- {
- tree id_list;
- tree id;
- tree nmi, warm;
-
- /* Deal with reset attribute. Its vector number is always 0. */
- nds32_isr_vectors[0].category = NDS32_ISR_RESET;
-
- /* Prepare id_list and identify id value so that
- we can set total number of vectors. */
- id_list = TREE_VALUE (reset);
- id = TREE_VALUE (id_list);
-
- /* The total vectors = interrupt + exception numbers + reset.
- There are 8 exception and 1 reset in nds32 architecture. */
- nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
- strcpy (nds32_isr_vectors[0].func_name, func_name);
-
- /* Retrieve nmi and warm function. */
- nmi = lookup_attribute ("nmi", func_attrs);
- warm = lookup_attribute ("warm", func_attrs);
-
- if (nmi != NULL_TREE)
- {
- tree nmi_func_list;
- tree nmi_func;
-
- nmi_func_list = TREE_VALUE (nmi);
- nmi_func = TREE_VALUE (nmi_func_list);
-
- /* Record nmi function name. */
- strcpy (nds32_isr_vectors[0].nmi_name,
- IDENTIFIER_POINTER (nmi_func));
- }
-
- if (warm != NULL_TREE)
- {
- tree warm_func_list;
- tree warm_func;
-
- warm_func_list = TREE_VALUE (warm);
- warm_func = TREE_VALUE (warm_func_list);
-
- /* Record warm function name. */
- strcpy (nds32_isr_vectors[0].warm_name,
- IDENTIFIER_POINTER (warm_func));
- }
- }
+ /* Add CFI info by manual. */
+ REG_NOTES (parallel_insn) = dwarf;
}
/* Function that may creates more instructions
@@ -1434,7 +1043,7 @@ nds32_force_addi_stack_int (int full_value)
/* Return true if MODE/TYPE need double word alignment. */
static bool
-nds32_needs_double_word_align (enum machine_mode mode, const_tree type)
+nds32_needs_double_word_align (machine_mode mode, const_tree type)
{
unsigned int align;
@@ -1490,7 +1099,7 @@ nds32_address_register_rtx_p (rtx x, bool strict)
INDEX : Check if this rtx is valid to be a index for address.
STRICT : If it is true, we are in reload pass or after reload pass. */
static bool
-nds32_legitimate_index_p (enum machine_mode outer_mode,
+nds32_legitimate_index_p (machine_mode outer_mode,
rtx index,
bool strict)
{
@@ -1610,123 +1219,6 @@ nds32_legitimate_index_p (enum machine_mode outer_mode,
}
}
-/* Function to expand builtin function for
- '[(unspec_volatile [(reg)])]'. */
-static rtx
-nds32_expand_builtin_null_ftype_reg (enum insn_code icode,
- tree exp, rtx target)
-{
- /* Mapping:
- ops[0] <--> value0 <--> arg0 */
- struct expand_operand ops[1];
- tree arg0;
- rtx value0;
-
- /* Grab the incoming arguments and extract its rtx. */
- arg0 = CALL_EXPR_ARG (exp, 0);
- value0 = expand_normal (arg0);
-
- /* Create operands. */
- create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
-
- /* Emit new instruction. */
- if (!maybe_expand_insn (icode, 1, ops))
- error ("invalid argument to built-in function");
-
- return target;
-}
-
-/* Function to expand builtin function for
- '[(set (reg) (unspec_volatile [(imm)]))]'. */
-static rtx
-nds32_expand_builtin_reg_ftype_imm (enum insn_code icode,
- tree exp, rtx target)
-{
- /* Mapping:
- ops[0] <--> target <--> exp
- ops[1] <--> value0 <--> arg0 */
- struct expand_operand ops[2];
- tree arg0;
- rtx value0;
-
- /* Grab the incoming arguments and extract its rtx. */
- arg0 = CALL_EXPR_ARG (exp, 0);
- value0 = expand_normal (arg0);
-
- /* Create operands. */
- create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
- create_input_operand (&ops[1], value0, TYPE_MODE (TREE_TYPE (arg0)));
-
- /* Emit new instruction. */
- if (!maybe_expand_insn (icode, 2, ops))
- error ("invalid argument to built-in function");
-
- return target;
-}
-
-/* Function to expand builtin function for
- '[(unspec_volatile [(reg) (imm)])]' pattern. */
-static rtx
-nds32_expand_builtin_null_ftype_reg_imm (enum insn_code icode,
- tree exp, rtx target)
-{
- /* Mapping:
- ops[0] <--> value0 <--> arg0
- ops[1] <--> value1 <--> arg1 */
- struct expand_operand ops[2];
- tree arg0, arg1;
- rtx value0, value1;
-
- /* Grab the incoming arguments and extract its rtx. */
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- value0 = expand_normal (arg0);
- value1 = expand_normal (arg1);
-
- /* Create operands. */
- create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
- create_input_operand (&ops[1], value1, TYPE_MODE (TREE_TYPE (arg1)));
-
- /* Emit new instruction. */
- if (!maybe_expand_insn (icode, 2, ops))
- error ("invalid argument to built-in function");
-
- return target;
-}
-
-/* A helper function to return character based on byte size. */
-static char
-nds32_byte_to_size (int byte)
-{
- switch (byte)
- {
- case 4:
- return 'w';
- case 2:
- return 'h';
- case 1:
- return 'b';
- default:
- /* Normally it should not be here. */
- gcc_unreachable ();
- }
-}
-
-/* A helper function to check if this function should contain prologue. */
-static int
-nds32_have_prologue_p (void)
-{
- int i;
-
- for (i = 0; i < 28; i++)
- if (NDS32_REQUIRED_CALLEE_SAVED_P (i))
- return 1;
-
- return (flag_pic
- || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
- || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM));
-}
-
/* ------------------------------------------------------------------------ */
/* PART 3: Implement target hook stuff definitions. */
@@ -1735,7 +1227,7 @@ nds32_have_prologue_p (void)
static unsigned char
nds32_class_max_nregs (reg_class_t rclass ATTRIBUTE_UNUSED,
- enum machine_mode mode)
+ machine_mode mode)
{
/* Return the maximum number of consecutive registers
needed to represent "mode" in a register of "rclass". */
@@ -1816,7 +1308,8 @@ nds32_register_priority (int hard_regno)
/* -- Eliminating Frame Pointer and Arg Pointer. */
-static bool nds32_can_eliminate (const int from_reg, const int to_reg)
+static bool
+nds32_can_eliminate (const int from_reg, const int to_reg)
{
if (from_reg == ARG_POINTER_REGNUM && to_reg == STACK_POINTER_REGNUM)
return true;
@@ -1836,9 +1329,10 @@ static bool nds32_can_eliminate (const int from_reg, const int to_reg)
/* -- Passing Arguments in Registers. */
static rtx
-nds32_function_arg (cumulative_args_t ca, enum machine_mode mode,
+nds32_function_arg (cumulative_args_t ca, machine_mode mode,
const_tree type, bool named)
{
+ unsigned int regno;
CUMULATIVE_ARGS *cum = get_cumulative_args (ca);
/* The last time this hook is called,
@@ -1846,46 +1340,161 @@ nds32_function_arg (cumulative_args_t ca, enum machine_mode mode,
if (mode == VOIDmode)
return NULL_RTX;
- /* For nameless arguments, they are passed on the stack. */
+ /* For nameless arguments, we need to take care it individually. */
if (!named)
- return NULL_RTX;
-
- /* If there are still registers available, return it. */
- if (NDS32_ARG_PASS_IN_REG_P (cum->reg_offset, mode, type))
{
- /* Pick up the next available register number. */
- unsigned int regno;
+ /* If we are under hard float abi, we have arguments passed on the
+ stack and all situation can be handled by GCC itself. */
+ if (TARGET_HARD_FLOAT)
+ return NULL_RTX;
+
+ if (NDS32_ARG_PARTIAL_IN_GPR_REG_P (cum->gpr_offset, mode, type))
+ {
+ /* If we still have enough registers to pass argument, pick up
+ next available register number. */
+ regno
+ = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type);
+ return gen_rtx_REG (mode, regno);
+ }
- regno = NDS32_AVAILABLE_REGNUM_FOR_ARG (cum->reg_offset, mode, type);
- return gen_rtx_REG (mode, regno);
- }
- else
- {
/* No register available, return NULL_RTX.
The compiler will use stack to pass argument instead. */
return NULL_RTX;
}
+
+ /* The following is to handle named argument.
+ Note that the strategies of TARGET_HARD_FLOAT and !TARGET_HARD_FLOAT
+ are different. */
+ if (TARGET_HARD_FLOAT)
+ {
+ /* Currently we have not implemented hard float yet. */
+ gcc_unreachable ();
+ }
+ else
+ {
+ /* For !TARGET_HARD_FLOAT calling convention, we always use GPR to pass
+ argument. Since we allow to pass argument partially in registers,
+ we can just return it if there are still registers available. */
+ if (NDS32_ARG_PARTIAL_IN_GPR_REG_P (cum->gpr_offset, mode, type))
+ {
+ /* Pick up the next available register number. */
+ regno
+ = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type);
+ return gen_rtx_REG (mode, regno);
+ }
+
+ }
+
+ /* No register available, return NULL_RTX.
+ The compiler will use stack to pass argument instead. */
+ return NULL_RTX;
+}
+
+static bool
+nds32_must_pass_in_stack (machine_mode mode, const_tree type)
+{
+ /* Return true if a type must be passed in memory.
+ If it is NOT using hard float abi, small aggregates can be
+ passed in a register even we are calling a variadic function.
+ So there is no need to take padding into consideration. */
+ if (TARGET_HARD_FLOAT)
+ return must_pass_in_stack_var_size_or_pad (mode, type);
+ else
+ return must_pass_in_stack_var_size (mode, type);
+}
+
+static int
+nds32_arg_partial_bytes (cumulative_args_t ca, machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ /* Returns the number of bytes at the beginning of an argument that
+ must be put in registers. The value must be zero for arguments that are
+ passed entirely in registers or that are entirely pushed on the stack.
+ Besides, TARGET_FUNCTION_ARG for these arguments should return the
+ first register to be used by the caller for this argument. */
+ unsigned int needed_reg_count;
+ unsigned int remaining_reg_count;
+ CUMULATIVE_ARGS *cum;
+
+ cum = get_cumulative_args (ca);
+
+ /* Under hard float abi, we better have argument entirely passed in
+ registers or pushed on the stack so that we can reduce the complexity
+ of dealing with cum->gpr_offset and cum->fpr_offset. */
+ if (TARGET_HARD_FLOAT)
+ return 0;
+
+ /* If we have already runned out of argument registers, return zero
+ so that the argument will be entirely pushed on the stack. */
+ if (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
+ >= NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS)
+ return 0;
+
+ /* Calculate how many registers do we need for this argument. */
+ needed_reg_count = NDS32_NEED_N_REGS_FOR_ARG (mode, type);
+
+ /* Calculate how many argument registers have left for passing argument.
+ Note that we should count it from next available register number. */
+ remaining_reg_count
+ = NDS32_MAX_GPR_REGS_FOR_ARGS
+ - (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
+ - NDS32_GPR_ARG_FIRST_REGNUM);
+
+ /* Note that we have to return the nubmer of bytes, not registers count. */
+ if (needed_reg_count > remaining_reg_count)
+ return remaining_reg_count * UNITS_PER_WORD;
+
+ return 0;
}
static void
-nds32_function_arg_advance (cumulative_args_t ca, enum machine_mode mode,
+nds32_function_arg_advance (cumulative_args_t ca, machine_mode mode,
const_tree type, bool named)
{
+ machine_mode sub_mode;
CUMULATIVE_ARGS *cum = get_cumulative_args (ca);
- /* Advance next register for use.
- Only named argument could be advanced. */
if (named)
{
- cum->reg_offset
- = NDS32_AVAILABLE_REGNUM_FOR_ARG (cum->reg_offset, mode, type)
- - NDS32_GPR_ARG_FIRST_REGNUM
- + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
+ /* We need to further check TYPE and MODE so that we can determine
+ which kind of register we shall advance. */
+ if (type && TREE_CODE (type) == COMPLEX_TYPE)
+ sub_mode = TYPE_MODE (TREE_TYPE (type));
+ else
+ sub_mode = mode;
+
+ /* Under hard float abi, we may advance FPR registers. */
+ if (TARGET_HARD_FLOAT && GET_MODE_CLASS (sub_mode) == MODE_FLOAT)
+ {
+ /* Currently we have not implemented hard float yet. */
+ gcc_unreachable ();
+ }
+ else
+ {
+ cum->gpr_offset
+ = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
+ - NDS32_GPR_ARG_FIRST_REGNUM
+ + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
+ }
+ }
+ else
+ {
+ /* If this nameless argument is NOT under TARGET_HARD_FLOAT,
+ we can advance next register as well so that caller is
+ able to pass arguments in registers and callee must be
+ in charge of pushing all of them into stack. */
+ if (!TARGET_HARD_FLOAT)
+ {
+ cum->gpr_offset
+ = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
+ - NDS32_GPR_ARG_FIRST_REGNUM
+ + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
+ }
}
}
static unsigned int
-nds32_function_arg_boundary (enum machine_mode mode, const_tree type)
+nds32_function_arg_boundary (machine_mode mode, const_tree type)
{
return (nds32_needs_double_word_align (mode, type)
? NDS32_DOUBLE_WORD_ALIGNMENT
@@ -1899,7 +1508,7 @@ nds32_function_value (const_tree ret_type,
const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
bool outgoing ATTRIBUTE_UNUSED)
{
- enum machine_mode mode;
+ machine_mode mode;
int unsignedp;
mode = TYPE_MODE (ret_type);
@@ -1911,7 +1520,7 @@ nds32_function_value (const_tree ret_type,
}
static rtx
-nds32_libcall_value (enum machine_mode mode,
+nds32_libcall_value (machine_mode mode,
const_rtx fun ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM);
@@ -2108,12 +1717,53 @@ nds32_warn_func_return (tree decl)
/* Implementing the Varargs Macros. */
+static void
+nds32_setup_incoming_varargs (cumulative_args_t ca,
+ machine_mode mode,
+ tree type,
+ int *pretend_args_size,
+ int second_time ATTRIBUTE_UNUSED)
+{
+ unsigned int total_args_regs;
+ unsigned int num_of_used_regs;
+ unsigned int remaining_reg_count;
+ CUMULATIVE_ARGS *cum;
+
+ /* If we are under hard float abi, we do not need to set *pretend_args_size.
+ So that all nameless arguments are pushed by caller and all situation
+ can be handled by GCC itself. */
+ if (TARGET_HARD_FLOAT)
+ return;
+
+ /* We are using NDS32_MAX_GPR_REGS_FOR_ARGS registers,
+ counting from NDS32_GPR_ARG_FIRST_REGNUM, for saving incoming arguments.
+ However, for nameless(anonymous) arguments, we should push them on the
+ stack so that all the nameless arguments appear to have been passed
+ consecutively in the memory for accessing. Hence, we need to check and
+ exclude the registers that are used for named arguments. */
+
+ cum = get_cumulative_args (ca);
+
+ /* The MODE and TYPE describe the last argument.
+ We need those information to determine the remaining registers
+ for varargs. */
+ total_args_regs
+ = NDS32_MAX_GPR_REGS_FOR_ARGS + NDS32_GPR_ARG_FIRST_REGNUM;
+ num_of_used_regs
+ = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
+ + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
+
+ remaining_reg_count = total_args_regs - num_of_used_regs;
+ *pretend_args_size = remaining_reg_count * UNITS_PER_WORD;
+
+ return;
+}
+
static bool
nds32_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
{
- /* Return true so that all the named arguments for FUNCTION_ARG have named=1.
- If return false, for the variadic function, all named arguments EXCEPT
- the last are treated as named. */
+ /* If this hook returns true, the named argument of FUNCTION_ARG is always
+ true for named arguments, and false for unnamed arguments. */
return true;
}
@@ -2284,7 +1934,7 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
/* Addressing Modes. */
static bool
-nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict)
{
/* For (mem:DI addr) or (mem:DF addr) case,
we only allow 'addr' to be [reg], [symbol_ref],
@@ -2320,24 +1970,27 @@ nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
return nds32_address_register_rtx_p (x, strict);
case SYMBOL_REF:
-
- if (!TARGET_GP_DIRECT
+ /* (mem (symbol_ref A)) => [symbol_ref] */
+ /* If -mcmodel=large, the 'symbol_ref' is not a valid address
+ during or after LRA/reload phase. */
+ if (TARGET_CMODEL_LARGE
&& (reload_completed
|| reload_in_progress
|| lra_in_progress))
return false;
-
- /* (mem (symbol_ref A)) => [symbol_ref] */
- return !currently_expanding_to_rtl;
-
- case CONST:
-
- if (!TARGET_GP_DIRECT
+ /* If -mcmodel=medium and the symbol references to rodata section,
+ the 'symbol_ref' is not a valid address during or after
+ LRA/reload phase. */
+ if (TARGET_CMODEL_MEDIUM
+ && NDS32_SYMBOL_REF_RODATA_P (x)
&& (reload_completed
|| reload_in_progress
|| lra_in_progress))
return false;
+ return true;
+
+ case CONST:
/* (mem (const (...)))
=> [ + const_addr ], where const_addr = symbol_ref + const_int */
if (GET_CODE (XEXP (x, 0)) == PLUS)
@@ -2348,9 +2001,30 @@ nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
rtx op1 = XEXP (plus_op, 1);
if (GET_CODE (op0) == SYMBOL_REF && CONST_INT_P (op1))
- return true;
- else
- return false;
+ {
+ /* Now we see the [ + const_addr ] pattern, but we need
+ some further checking. */
+ /* If -mcmodel=large, the 'const_addr' is not a valid address
+ during or after LRA/reload phase. */
+ if (TARGET_CMODEL_LARGE
+ && (reload_completed
+ || reload_in_progress
+ || lra_in_progress))
+ return false;
+ /* If -mcmodel=medium and the symbol references to rodata section,
+ the 'const_addr' is not a valid address during or after
+ LRA/reload phase. */
+ if (TARGET_CMODEL_MEDIUM
+ && NDS32_SYMBOL_REF_RODATA_P (op0)
+ && (reload_completed
+ || reload_in_progress
+ || lra_in_progress))
+ return false;
+
+ /* At this point we can make sure 'const_addr' is a
+ valid address. */
+ return true;
+ }
}
return false;
@@ -2405,8 +2079,14 @@ nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
return false;
case LO_SUM:
- if (!TARGET_GP_DIRECT)
- return true;
+ /* (mem (lo_sum (reg) (symbol_ref))) */
+ /* (mem (lo_sum (reg) (const))) */
+ gcc_assert (REG_P (XEXP (x, 0)));
+ if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
+ || GET_CODE (XEXP (x, 1)) == CONST)
+ return nds32_legitimate_address_p (mode, XEXP (x, 1), strict);
+ else
+ return false;
default:
return false;
@@ -2416,9 +2096,10 @@ nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
/* Describing Relative Costs of Operations. */
-static int nds32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
- reg_class_t from,
- reg_class_t to)
+static int
+nds32_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t from,
+ reg_class_t to)
{
if (from == HIGH_REGS || to == HIGH_REGS)
return 6;
@@ -2426,9 +2107,10 @@ static int nds32_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
return 2;
}
-static int nds32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
- reg_class_t rclass ATTRIBUTE_UNUSED,
- bool in ATTRIBUTE_UNUSED)
+static int
+nds32_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t rclass ATTRIBUTE_UNUSED,
+ bool in ATTRIBUTE_UNUSED)
{
return 8;
}
@@ -2441,209 +2123,59 @@ static bool
nds32_rtx_costs (rtx x,
int code,
int outer_code,
- int opno ATTRIBUTE_UNUSED,
+ int opno,
int *total,
bool speed)
{
- /* According to 'speed', goto suitable cost model section. */
- if (speed)
- goto performance_cost;
- else
- goto size_cost;
-
-
-performance_cost:
- /* This is section for performance cost model. */
-
- /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
- We treat it as 4-cycle cost for each instruction
- under performance consideration. */
- switch (code)
- {
- case SET:
- /* For 'SET' rtx, we need to return false
- so that it can recursively calculate costs. */
- return false;
-
- case USE:
- /* Used in combine.c as a marker. */
- *total = 0;
- break;
-
- case MULT:
- *total = COSTS_N_INSNS (1);
- break;
-
- case DIV:
- case UDIV:
- case MOD:
- case UMOD:
- *total = COSTS_N_INSNS (7);
- break;
-
- default:
- *total = COSTS_N_INSNS (1);
- break;
- }
+ return nds32_rtx_costs_impl (x, code, outer_code, opno, total, speed);
+}
- return true;
+static int
+nds32_address_cost (rtx address,
+ machine_mode mode,
+ addr_space_t as,
+ bool speed)
+{
+ return nds32_address_cost_impl (address, mode, as, speed);
+}
+
+/* Dividing the Output into Sections (Texts, Data, . . . ). */
-size_cost:
- /* This is section for size cost model. */
+/* If references to a symbol or a constant must be treated differently
+ depending on something about the variable or function named by the symbol
+ (such as what section it is in), we use this hook to store flags
+ in symbol_ref rtx. */
+static void
+nds32_encode_section_info (tree decl, rtx rtl, int new_decl_p)
+{
+ default_encode_section_info (decl, rtl, new_decl_p);
- /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
- We treat it as 4-byte cost for each instruction
- under code size consideration. */
- switch (code)
+ /* For the memory rtx, if it references to rodata section, we can store
+ NDS32_SYMBOL_FLAG_RODATA flag into symbol_ref rtx so that the
+ nds32_legitimate_address_p() can determine how to treat such symbol_ref
+ based on -mcmodel=X and this information. */
+ if (MEM_P (rtl) && MEM_READONLY_P (rtl))
{
- case SET:
- /* For 'SET' rtx, we need to return false
- so that it can recursively calculate costs. */
- return false;
+ rtx addr = XEXP (rtl, 0);
- case USE:
- /* Used in combine.c as a marker. */
- *total = 0;
- break;
-
- case CONST_INT:
- /* All instructions involving constant operation
- need to be considered for cost evaluation. */
- if (outer_code == SET)
- {
- /* (set X imm5s), use movi55, 2-byte cost.
- (set X imm20s), use movi, 4-byte cost.
- (set X BIG_INT), use sethi/ori, 8-byte cost. */
- if (satisfies_constraint_Is05 (x))
- *total = COSTS_N_INSNS (1) - 2;
- else if (satisfies_constraint_Is20 (x))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (2);
- }
- else if (outer_code == PLUS || outer_code == MINUS)
- {
- /* Possible addi333/subi333 or subi45/addi45, 2-byte cost.
- General case, cost 1 instruction with 4-byte. */
- if (satisfies_constraint_Iu05 (x))
- *total = COSTS_N_INSNS (1) - 2;
- else
- *total = COSTS_N_INSNS (1);
- }
- else if (outer_code == ASHIFT)
- {
- /* Possible slli333, 2-byte cost.
- General case, cost 1 instruction with 4-byte. */
- if (satisfies_constraint_Iu03 (x))
- *total = COSTS_N_INSNS (1) - 2;
- else
- *total = COSTS_N_INSNS (1);
- }
- else if (outer_code == ASHIFTRT || outer_code == LSHIFTRT)
+ if (GET_CODE (addr) == SYMBOL_REF)
{
- /* Possible srai45 or srli45, 2-byte cost.
- General case, cost 1 instruction with 4-byte. */
- if (satisfies_constraint_Iu05 (x))
- *total = COSTS_N_INSNS (1) - 2;
- else
- *total = COSTS_N_INSNS (1);
+ /* For (mem (symbol_ref X)) case. */
+ SYMBOL_REF_FLAGS (addr) |= NDS32_SYMBOL_FLAG_RODATA;
}
- else
+ else if (GET_CODE (addr) == CONST
+ && GET_CODE (XEXP (addr, 0)) == PLUS)
{
- /* For other cases, simply set it 4-byte cost. */
- *total = COSTS_N_INSNS (1);
- }
- break;
-
- case CONST_DOUBLE:
- /* It requires high part and low part processing, set it 8-byte cost. */
- *total = COSTS_N_INSNS (2);
- break;
-
- default:
- /* For other cases, generally we set it 4-byte cost
- and stop resurively traversing. */
- *total = COSTS_N_INSNS (1);
- break;
- }
-
- return true;
-}
-
-static int nds32_address_cost (rtx address,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- addr_space_t as ATTRIBUTE_UNUSED,
- bool speed)
-{
- rtx plus0, plus1;
- enum rtx_code code;
-
- code = GET_CODE (address);
-
- /* According to 'speed', goto suitable cost model section. */
- if (speed)
- goto performance_cost;
- else
- goto size_cost;
-
-performance_cost:
- /* This is section for performance cost model. */
-
- /* FALLTHRU, currently we use same cost model as size_cost. */
-
-size_cost:
- /* This is section for size cost model. */
-
- switch (code)
- {
- case POST_MODIFY:
- case POST_INC:
- case POST_DEC:
- /* We encourage that rtx contains
- POST_MODIFY/POST_INC/POST_DEC behavior. */
- return 0;
-
- case SYMBOL_REF:
- /* We can have gp-relative load/store for symbol_ref.
- Have it 4-byte cost. */
- return COSTS_N_INSNS (1);
-
- case CONST:
- /* It is supposed to be the pattern (const (plus symbol_ref const_int)).
- Have it 4-byte cost. */
- return COSTS_N_INSNS (1);
-
- case REG:
- /* Simply return 4-byte costs. */
- return COSTS_N_INSNS (1);
+ /* For (mem (const (plus (symbol_ref X) (const_int N)))) case. */
+ rtx plus_op = XEXP (addr, 0);
+ rtx op0 = XEXP (plus_op, 0);
+ rtx op1 = XEXP (plus_op, 1);
- case PLUS:
- /* We do not need to check if the address is a legitimate address,
- because this hook is never called with an invalid address.
- But we better check the range of
- const_int value for cost, if it exists. */
- plus0 = XEXP (address, 0);
- plus1 = XEXP (address, 1);
-
- if (REG_P (plus0) && CONST_INT_P (plus1))
- {
- /* If it is possible to be lwi333/swi333 form,
- make it 2-byte cost. */
- if (satisfies_constraint_Iu05 (plus1))
- return (COSTS_N_INSNS (1) - 2);
- else
- return COSTS_N_INSNS (1);
+ if (GET_CODE (op0) == SYMBOL_REF && CONST_INT_P (op1))
+ SYMBOL_REF_FLAGS (op0) |= NDS32_SYMBOL_FLAG_RODATA;
}
-
- /* For other 'plus' situation, make it cost 4-byte. */
- return COSTS_N_INSNS (1);
-
- default:
- break;
}
-
- return COSTS_N_INSNS (4);
}
@@ -2654,8 +2186,6 @@ size_cost:
static void
nds32_asm_file_start (void)
{
- int i;
-
default_file_start ();
/* Tell assembler which ABI we are using. */
@@ -2670,26 +2200,6 @@ nds32_asm_file_start (void)
"for checking inconsistency on interrupt handler\n");
fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size);
- /* If user enables '-mforce-fp-as-gp' or compiles programs with -Os,
- the compiler may produce 'la $fp,_FP_BASE_' instruction
- at prologue for fp-as-gp optimization.
- We should emit weak reference of _FP_BASE_ to avoid undefined reference
- in case user does not pass '--relax' option to linker. */
- if (TARGET_FORCE_FP_AS_GP || optimize_size)
- {
- fprintf (asm_out_file, "\t! This weak reference is required to do "
- "fp-as-gp link time optimization\n");
- fprintf (asm_out_file, "\t.weak\t_FP_BASE_\n");
- }
- /* If user enables '-mex9', we should emit relaxation directive
- to tell linker that this file is allowed to do ex9 optimization. */
- if (TARGET_EX9)
- {
- fprintf (asm_out_file, "\t! This relaxation directive is required "
- "to do ex9 link time optimization\n");
- fprintf (asm_out_file, "\t.relax\tex9\n");
- }
-
fprintf (asm_out_file, "\t! ------------------------------------\n");
if (TARGET_ISA_V2)
@@ -2699,6 +2209,13 @@ nds32_asm_file_start (void)
if (TARGET_ISA_V3M)
fprintf (asm_out_file, "\t! ISA family\t\t: %s\n", "V3M");
+ if (TARGET_CMODEL_SMALL)
+ fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "SMALL");
+ if (TARGET_CMODEL_MEDIUM)
+ fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "MEDIUM");
+ if (TARGET_CMODEL_LARGE)
+ fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "LARGE");
+
fprintf (asm_out_file, "\t! Endian setting\t: %s\n",
((TARGET_BIG_ENDIAN) ? "big-endian"
: "little-endian"));
@@ -2720,9 +2237,6 @@ nds32_asm_file_start (void)
fprintf (asm_out_file, "\t! 16-bit instructions\t: %s\n",
((TARGET_16_BIT) ? "Yes"
: "No"));
- fprintf (asm_out_file, "\t! GP base access\t: %s\n",
- ((TARGET_GP_DIRECT) ? "Yes"
- : "No"));
fprintf (asm_out_file, "\t! Reduced registers set\t: %s\n",
((TARGET_REDUCED_REGS) ? "Yes"
: "No"));
@@ -2741,61 +2255,13 @@ nds32_asm_file_start (void)
fprintf (asm_out_file, "\t! ------------------------------------\n");
- /* Initialize isr vector information array before compiling functions. */
- for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
- {
- nds32_isr_vectors[i].category = NDS32_ISR_NONE;
- strcpy (nds32_isr_vectors[i].func_name, "");
- nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
- nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
- nds32_isr_vectors[i].total_n_vectors = 0;
- strcpy (nds32_isr_vectors[i].nmi_name, "");
- strcpy (nds32_isr_vectors[i].warm_name, "");
- }
+ nds32_asm_file_start_for_isr ();
}
static void
nds32_asm_file_end (void)
{
- int i;
-
- /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
- for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
- if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
- break;
-
- if (i == NDS32_N_ISR_VECTORS)
- return;
-
- /* At least one vector is NOT NDS32_ISR_NONE,
- we should output isr vector information. */
- fprintf (asm_out_file, "\t! ------------------------------------\n");
- fprintf (asm_out_file, "\t! The isr vector information:\n");
- fprintf (asm_out_file, "\t! ------------------------------------\n");
-
- /* Check reset handler first. Its vector number is always 0. */
- if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
- {
- nds32_emit_isr_reset_content ();
- fprintf (asm_out_file, "\t! ------------------------------------\n");
- }
-
- /* Check other vectors, starting from vector number 1. */
- for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
- {
- if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
- || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
- {
- /* Found one vector which is interupt or exception.
- Output its jmptbl and vector section content. */
- fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
- fprintf (asm_out_file, "\t! ------------------------------------\n");
- nds32_emit_isr_jmptbl_section (i);
- fprintf (asm_out_file, "\t! ....................................\n");
- nds32_emit_isr_vector_section (i);
- fprintf (asm_out_file, "\t! ------------------------------------\n");
- }
- }
+ nds32_asm_file_end_for_isr ();
fprintf (asm_out_file, "\t! ------------------------------------\n");
}
@@ -3148,8 +2614,8 @@ nds32_insert_attributes (tree decl, tree *attributes)
id = TREE_VALUE (id_list);
/* Issue error if it is not a valid integer value. */
if (TREE_CODE (id) != INTEGER_CST
- || TREE_INT_CST_LOW (id) < lower_bound
- || TREE_INT_CST_LOW (id) > upper_bound)
+ || wi::ltu_p (id, lower_bound)
+ || wi::gtu_p (id, upper_bound))
error ("invalid id value for interrupt/exception attribute");
/* Advance to next id. */
@@ -3176,8 +2642,8 @@ nds32_insert_attributes (tree decl, tree *attributes)
/* 3. Check valid integer value for reset. */
if (TREE_CODE (id) != INTEGER_CST
- || TREE_INT_CST_LOW (id) < lower_bound
- || TREE_INT_CST_LOW (id) > upper_bound)
+ || wi::ltu_p (id, lower_bound)
+ || wi::gtu_p (id, upper_bound))
error ("invalid id value for reset attribute");
/* 4. Check valid function for nmi/warm. */
@@ -3267,12 +2733,6 @@ nds32_option_override (void)
fixed_regs[r] = call_used_regs[r] = 1;
}
- /* See if user explicitly would like to use fp-as-gp optimization.
- If so, we must prevent $fp from being allocated
- during register allocation. */
- if (TARGET_FORCE_FP_AS_GP)
- fixed_regs[FP_REGNUM] = call_used_regs[FP_REGNUM] = 1;
-
if (!TARGET_16_BIT)
{
/* Under no 16 bit ISA, we need to strictly disable TARGET_V3PUSH. */
@@ -3290,109 +2750,17 @@ nds32_option_override (void)
static void
nds32_init_builtins (void)
{
- tree pointer_type_node = build_pointer_type (integer_type_node);
-
- tree void_ftype_void = build_function_type (void_type_node,
- void_list_node);
-
- tree void_ftype_pint = build_function_type_list (void_type_node,
- pointer_type_node,
- NULL_TREE);
-
- tree int_ftype_int = build_function_type_list (integer_type_node,
- integer_type_node,
- NULL_TREE);
-
- tree void_ftype_int_int = build_function_type_list (void_type_node,
- integer_type_node,
- integer_type_node,
- NULL_TREE);
-
- /* Cache. */
- add_builtin_function ("__builtin_nds32_isync", void_ftype_pint,
- NDS32_BUILTIN_ISYNC,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_nds32_isb", void_ftype_void,
- NDS32_BUILTIN_ISB,
- BUILT_IN_MD, NULL, NULL_TREE);
-
- /* Register Transfer. */
- add_builtin_function ("__builtin_nds32_mfsr", int_ftype_int,
- NDS32_BUILTIN_MFSR,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_nds32_mfusr", int_ftype_int,
- NDS32_BUILTIN_MFUSR,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_nds32_mtsr", void_ftype_int_int,
- NDS32_BUILTIN_MTSR,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_nds32_mtusr", void_ftype_int_int,
- NDS32_BUILTIN_MTUSR,
- BUILT_IN_MD, NULL, NULL_TREE);
-
- /* Interrupt. */
- add_builtin_function ("__builtin_nds32_setgie_en", void_ftype_void,
- NDS32_BUILTIN_SETGIE_EN,
- BUILT_IN_MD, NULL, NULL_TREE);
- add_builtin_function ("__builtin_nds32_setgie_dis", void_ftype_void,
- NDS32_BUILTIN_SETGIE_DIS,
- BUILT_IN_MD, NULL, NULL_TREE);
+ nds32_init_builtins_impl ();
}
static rtx
nds32_expand_builtin (tree exp,
rtx target,
- rtx subtarget ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- int ignore ATTRIBUTE_UNUSED)
+ rtx subtarget,
+ machine_mode mode,
+ int ignore)
{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-
- int fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- /* Cache. */
- case NDS32_BUILTIN_ISYNC:
- return nds32_expand_builtin_null_ftype_reg
- (CODE_FOR_unspec_volatile_isync, exp, target);
- case NDS32_BUILTIN_ISB:
- /* Since there are no result and operands for isb instruciton,
- we can simply emit this rtx. */
- emit_insn (gen_unspec_volatile_isb ());
- return target;
-
- /* Register Transfer. */
- case NDS32_BUILTIN_MFSR:
- return nds32_expand_builtin_reg_ftype_imm
- (CODE_FOR_unspec_volatile_mfsr, exp, target);
- case NDS32_BUILTIN_MFUSR:
- return nds32_expand_builtin_reg_ftype_imm
- (CODE_FOR_unspec_volatile_mfusr, exp, target);
- case NDS32_BUILTIN_MTSR:
- return nds32_expand_builtin_null_ftype_reg_imm
- (CODE_FOR_unspec_volatile_mtsr, exp, target);
- case NDS32_BUILTIN_MTUSR:
- return nds32_expand_builtin_null_ftype_reg_imm
- (CODE_FOR_unspec_volatile_mtusr, exp, target);
-
- /* Interrupt. */
- case NDS32_BUILTIN_SETGIE_EN:
- /* Since there are no result and operands for setgie.e instruciton,
- we can simply emit this rtx. */
- emit_insn (gen_unspec_volatile_setgie_en ());
- return target;
- case NDS32_BUILTIN_SETGIE_DIS:
- /* Since there are no result and operands for setgie.d instruciton,
- we can simply emit this rtx. */
- emit_insn (gen_unspec_volatile_setgie_dis ());
- return target;
-
- default:
- gcc_unreachable ();
- }
-
- return NULL_RTX;
+ return nds32_expand_builtin_impl (exp, target, subtarget, mode, ignore);
}
@@ -3417,13 +2785,13 @@ nds32_init_expanders (void)
int
nds32_hard_regno_nregs (int regno ATTRIBUTE_UNUSED,
- enum machine_mode mode)
+ machine_mode mode)
{
return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
}
int
-nds32_hard_regno_mode_ok (int regno, enum machine_mode mode)
+nds32_hard_regno_mode_ok (int regno, machine_mode mode)
{
/* Restrict double-word quantities to even register pairs. */
if (HARD_REGNO_NREGS (regno, mode) == 1
@@ -3542,7 +2910,7 @@ nds32_init_cumulative_args (CUMULATIVE_ARGS *cum,
/* Initial available registers
(in offset, corresponding to NDS32_GPR_ARG_FIRST_REGNUM)
for passing arguments. */
- cum->reg_offset = 0;
+ cum->gpr_offset = 0;
}
/* -- Function Entry and Exit. */
@@ -3556,19 +2924,41 @@ nds32_expand_prologue (void)
int en4_const;
rtx Rb, Re;
- rtx push_insn;
rtx fp_adjust_insn, sp_adjust_insn;
- /* Before computing everything for stack frame size,
- we check if it is still worth to use fp_as_gp optimization.
- If it is, the 'df_regs_ever_live_p (FP_REGNUM)' will be set
- so that $fp will be saved on stack. */
- cfun->machine->fp_as_gp_p = nds32_fp_as_gp_check_available ();
-
/* Compute and setup stack frame size.
The result will be in cfun->machine. */
nds32_compute_stack_frame ();
+ /* If this is a variadic function, first we need to push argument
+ registers that hold the unnamed argument value. */
+ if (cfun->machine->va_args_size != 0)
+ {
+ Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno);
+ Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno);
+ /* No need to push $fp, $gp, or $lp, so use GEN_INT(0). */
+ nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true);
+
+ /* We may also need to adjust stack pointer for padding bytes
+ because varargs may cause $sp not 8-byte aligned. */
+ if (cfun->machine->va_args_area_padding_bytes)
+ {
+ /* Generate sp adjustment instruction. */
+ sp_adjust = cfun->machine->va_args_area_padding_bytes;
+ sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-1 * sp_adjust));
+
+ /* Emit rtx into instructions list and receive INSN rtx form. */
+ sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+ /* The insn rtx 'sp_adjust_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+ }
+ }
+
/* If the function is 'naked',
we do not have to generate prologue code fragment. */
if (cfun->machine->naked_p)
@@ -3578,7 +2968,7 @@ nds32_expand_prologue (void)
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_regs_first_regno);
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_regs_last_regno);
- /* push_insn = gen_stack_push_multiple(first_regno, last_regno),
+ /* nds32_emit_stack_push_multiple(first_regno, last_regno),
the pattern 'stack_push_multiple' is implemented in nds32.md.
For En4 field, we have to calculate its constant value.
Refer to Andes ISA for more information. */
@@ -3596,14 +2986,7 @@ nds32_expand_prologue (void)
if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
{
/* Create multiple push instruction rtx. */
- push_insn = nds32_gen_stack_push_multiple (Rb, Re, GEN_INT (en4_const));
- /* Emit rtx into instructions list and receive INSN rtx form. */
- push_insn = emit_insn (push_insn);
-
- /* The insn rtx 'push_insn' will change frame layout.
- We need to use RTX_FRAME_RELATED_P so that GCC is able to
- generate CFI (Call Frame Information) stuff. */
- RTX_FRAME_RELATED_P (push_insn) = 1;
+ nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (en4_const), false);
}
/* Check frame_pointer_needed to see
@@ -3625,6 +3008,9 @@ nds32_expand_prologue (void)
GEN_INT (fp_adjust));
/* Emit rtx into instructions list and receive INSN rtx form. */
fp_adjust_insn = emit_insn (fp_adjust_insn);
+
+ /* The insn rtx 'fp_adjust_insn' will change frame layout. */
+ RTX_FRAME_RELATED_P (fp_adjust_insn) = 1;
}
/* Adjust $sp = $sp - local_size - out_args_size
@@ -3658,13 +3044,12 @@ nds32_expand_prologue (void)
/* Function for normal multiple pop epilogue. */
void
-nds32_expand_epilogue (void)
+nds32_expand_epilogue (bool sibcall_p)
{
int sp_adjust;
int en4_const;
rtx Rb, Re;
- rtx pop_insn;
rtx sp_adjust_insn;
/* Compute and setup stack frame size.
@@ -3676,15 +3061,36 @@ nds32_expand_epilogue (void)
emit_insn (gen_blockage ());
/* If the function is 'naked', we do not have to generate
- epilogue code fragment BUT 'ret' instruction. */
+ epilogue code fragment BUT 'ret' instruction.
+ However, if this function is also a variadic function,
+ we need to create adjust stack pointer before 'ret' instruction. */
if (cfun->machine->naked_p)
{
- /* Generate return instruction by using
- unspec_volatile_func_return pattern.
- Make sure this instruction is after gen_blockage().
- NOTE that $lp will become 'live'
- after this instruction has been emitted. */
- emit_insn (gen_unspec_volatile_func_return ());
+ /* If this is a variadic function, we do not have to restore argument
+ registers but need to adjust stack pointer back to previous stack
+ frame location before return. */
+ if (cfun->machine->va_args_size != 0)
+ {
+ /* Generate sp adjustment instruction.
+ We need to consider padding bytes here. */
+ sp_adjust = cfun->machine->va_args_size
+ + cfun->machine->va_args_area_padding_bytes;
+ sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (sp_adjust));
+ /* Emit rtx into instructions list and receive INSN rtx form. */
+ sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+ /* The insn rtx 'sp_adjust_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+ }
+
+ /* Generate return instruction by using 'return_internal' pattern.
+ Make sure this instruction is after gen_blockage(). */
+ if (!sibcall_p)
+ emit_jump_insn (gen_return_internal ());
return;
}
@@ -3705,6 +3111,9 @@ nds32_expand_epilogue (void)
GEN_INT (-1 * sp_adjust));
/* Emit rtx into instructions list and receive INSN rtx form. */
sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+ /* The insn rtx 'sp_adjust_insn' will change frame layout. */
+ RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
}
else
{
@@ -3733,6 +3142,9 @@ nds32_expand_epilogue (void)
GEN_INT (sp_adjust));
/* Emit rtx into instructions list and receive INSN rtx form. */
sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+ /* The insn rtx 'sp_adjust_insn' will change frame layout. */
+ RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
}
}
@@ -3740,7 +3152,7 @@ nds32_expand_epilogue (void)
Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_regs_first_regno);
Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_regs_last_regno);
- /* pop_insn = gen_stack_pop_multiple(first_regno, last_regno),
+ /* nds32_emit_stack_pop_multiple(first_regno, last_regno),
the pattern 'stack_pop_multiple' is implementad in nds32.md.
For En4 field, we have to calculate its constant value.
Refer to Andes ISA for more information. */
@@ -3758,14 +3170,33 @@ nds32_expand_epilogue (void)
if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
{
/* Create multiple pop instruction rtx. */
- pop_insn = nds32_gen_stack_pop_multiple (Rb, Re, GEN_INT (en4_const));
- /* Emit pop instruction. */
- emit_insn (pop_insn);
+ nds32_emit_stack_pop_multiple (Rb, Re, GEN_INT (en4_const));
}
- /* Generate return instruction by using
- unspec_volatile_func_return pattern. */
- emit_insn (gen_unspec_volatile_func_return ());
+ /* If this is a variadic function, we do not have to restore argument
+ registers but need to adjust stack pointer back to previous stack
+ frame location before return. */
+ if (cfun->machine->va_args_size != 0)
+ {
+ /* Generate sp adjustment instruction.
+ We need to consider padding bytes here. */
+ sp_adjust = cfun->machine->va_args_size
+ + cfun->machine->va_args_area_padding_bytes;
+ sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (sp_adjust));
+ /* Emit rtx into instructions list and receive INSN rtx form. */
+ sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+ /* The insn rtx 'sp_adjust_insn' will change frame layout.
+ We need to use RTX_FRAME_RELATED_P so that GCC is able to
+ generate CFI (Call Frame Information) stuff. */
+ RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+ }
+
+ /* Generate return instruction. */
+ if (!sibcall_p)
+ emit_jump_insn (gen_return_internal ());
}
/* Function for v3push prologue. */
@@ -3776,15 +3207,8 @@ nds32_expand_prologue_v3push (void)
int sp_adjust;
rtx Rb, Re;
- rtx push_insn;
rtx fp_adjust_insn, sp_adjust_insn;
- /* Before computing everything for stack frame size,
- we check if it is still worth to use fp_as_gp optimization.
- If it is, the 'df_regs_ever_live_p (FP_REGNUM)' will be set
- so that $fp will be saved on stack. */
- cfun->machine->fp_as_gp_p = nds32_fp_as_gp_check_available ();
-
/* Compute and setup stack frame size.
The result will be in cfun->machine. */
nds32_compute_stack_frame ();
@@ -3809,18 +3233,11 @@ nds32_expand_prologue_v3push (void)
{
/* We can use 'push25 Re,imm8u'. */
- /* push_insn = gen_stack_v3push(last_regno, sp_adjust),
+ /* nds32_emit_stack_v3push(last_regno, sp_adjust),
the pattern 'stack_v3push' is implemented in nds32.md.
The (const_int 14) means v3push always push { $fp $gp $lp }. */
- push_insn = nds32_gen_stack_v3push (Rb, Re,
- GEN_INT (14), GEN_INT (sp_adjust));
- /* emit rtx into instructions list and receive INSN rtx form */
- push_insn = emit_insn (push_insn);
-
- /* The insn rtx 'push_insn' will change frame layout.
- We need to use RTX_FRAME_RELATED_P so that GCC is able to
- generate CFI (Call Frame Information) stuff. */
- RTX_FRAME_RELATED_P (push_insn) = 1;
+ nds32_emit_stack_v3push (Rb, Re,
+ GEN_INT (14), GEN_INT (sp_adjust));
/* Check frame_pointer_needed to see
if we shall emit fp adjustment instruction. */
@@ -3853,18 +3270,11 @@ nds32_expand_prologue_v3push (void)
/* We have to use 'push25 Re,0' and
expand one more instruction to adjust $sp later. */
- /* push_insn = gen_stack_v3push(last_regno, sp_adjust),
+ /* nds32_emit_stack_v3push(last_regno, sp_adjust),
the pattern 'stack_v3push' is implemented in nds32.md.
The (const_int 14) means v3push always push { $fp $gp $lp }. */
- push_insn = nds32_gen_stack_v3push (Rb, Re,
- GEN_INT (14), GEN_INT (0));
- /* Emit rtx into instructions list and receive INSN rtx form. */
- push_insn = emit_insn (push_insn);
-
- /* The insn rtx 'push_insn' will change frame layout.
- We need to use RTX_FRAME_RELATED_P so that GCC is able to
- generate CFI (Call Frame Information) stuff. */
- RTX_FRAME_RELATED_P (push_insn) = 1;
+ nds32_emit_stack_v3push (Rb, Re,
+ GEN_INT (14), GEN_INT (0));
/* Check frame_pointer_needed to see
if we shall emit fp adjustment instruction. */
@@ -3919,12 +3329,11 @@ nds32_expand_prologue_v3push (void)
/* Function for v3pop epilogue. */
void
-nds32_expand_epilogue_v3pop (void)
+nds32_expand_epilogue_v3pop (bool sibcall_p)
{
int sp_adjust;
rtx Rb, Re;
- rtx pop_insn;
rtx sp_adjust_insn;
/* Compute and setup stack frame size.
@@ -3939,12 +3348,10 @@ nds32_expand_epilogue_v3pop (void)
epilogue code fragment BUT 'ret' instruction. */
if (cfun->machine->naked_p)
{
- /* Generate return instruction by using
- unspec_volatile_func_return pattern.
- Make sure this instruction is after gen_blockage().
- NOTE that $lp will become 'live'
- after this instruction has been emitted. */
- emit_insn (gen_unspec_volatile_func_return ());
+ /* Generate return instruction by using 'return_internal' pattern.
+ Make sure this instruction is after gen_blockage(). */
+ if (!sibcall_p)
+ emit_jump_insn (gen_return_internal ());
return;
}
@@ -3971,14 +3378,11 @@ nds32_expand_epilogue_v3pop (void)
{
/* We can use 'pop25 Re,imm8u'. */
- /* pop_insn = gen_stack_v3pop(last_regno, sp_adjust),
+ /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
the pattern 'stack_v3pop' is implementad in nds32.md.
The (const_int 14) means v3pop always pop { $fp $gp $lp }. */
- pop_insn = nds32_gen_stack_v3pop (Rb, Re,
- GEN_INT (14), GEN_INT (sp_adjust));
-
- /* Emit pop instruction. */
- emit_insn (pop_insn);
+ nds32_emit_stack_v3pop (Rb, Re,
+ GEN_INT (14), GEN_INT (sp_adjust));
}
else
{
@@ -4035,15 +3439,34 @@ nds32_expand_epilogue_v3pop (void)
}
}
- /* pop_insn = gen_stack_v3pop(last_regno, sp_adjust),
+ /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
the pattern 'stack_v3pop' is implementad in nds32.md. */
/* The (const_int 14) means v3pop always pop { $fp $gp $lp }. */
- pop_insn = nds32_gen_stack_v3pop (Rb, Re,
- GEN_INT (14), GEN_INT (0));
-
- /* Emit pop instruction. */
- emit_insn (pop_insn);
+ nds32_emit_stack_v3pop (Rb, Re,
+ GEN_INT (14), GEN_INT (0));
}
+
+ /* Generate return instruction. */
+ emit_jump_insn (gen_pop25return ());
+}
+
+/* Return nonzero if this function is known to have a null epilogue.
+ This allows the optimizer to omit jumps to jumps if no stack
+ was created. */
+int
+nds32_can_use_return_insn (void)
+{
+ /* Prior to reloading, we can't tell how many registers must be saved.
+ Thus we can not determine whether this function has null epilogue. */
+ if (!reload_completed)
+ return 0;
+
+ /* If no stack was created, two conditions must be satisfied:
+ 1. This is a naked function.
+ So there is no callee-saved, local size, or outgoing size.
+ 2. This is NOT a variadic function.
+ So there is no pushing arguement registers into the stack. */
+ return (cfun->machine->naked_p && (cfun->machine->va_args_size == 0));
}
/* ------------------------------------------------------------------------ */
@@ -4052,7 +3475,7 @@ nds32_expand_epilogue_v3pop (void)
This is auxiliary extern function for auxiliary macro in nds32.h.
Because it is a little complicated, we use function instead of macro. */
bool
-nds32_ls_333_p (rtx rt, rtx ra, rtx imm, enum machine_mode mode)
+nds32_ls_333_p (rtx rt, rtx ra, rtx imm, machine_mode mode)
{
if (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS
&& REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS)
@@ -4071,348 +3494,11 @@ nds32_ls_333_p (rtx rt, rtx ra, rtx imm, enum machine_mode mode)
}
-/* Functions to expand load_multiple and store_multiple.
- They are auxiliary extern functions to help create rtx template.
- Check nds32-multiple.md file for the patterns. */
-rtx
-nds32_expand_load_multiple (int base_regno, int count,
- rtx base_addr, rtx basemem)
-{
- int par_index;
- int offset;
- rtx result;
- rtx new_addr, mem, reg;
-
- /* Create the pattern that is presented in nds32-multiple.md. */
-
- result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
-
- for (par_index = 0; par_index < count; par_index++)
- {
- offset = par_index * 4;
- /* 4-byte for loading data to each register. */
- new_addr = plus_constant (Pmode, base_addr, offset);
- mem = adjust_automodify_address_nv (basemem, SImode,
- new_addr, offset);
- reg = gen_rtx_REG (SImode, base_regno + par_index);
-
- XVECEXP (result, 0, par_index) = gen_rtx_SET (VOIDmode, reg, mem);
- }
-
- return result;
-}
-
-rtx
-nds32_expand_store_multiple (int base_regno, int count,
- rtx base_addr, rtx basemem)
-{
- int par_index;
- int offset;
- rtx result;
- rtx new_addr, mem, reg;
-
- /* Create the pattern that is presented in nds32-multiple.md. */
-
- result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
-
- for (par_index = 0; par_index < count; par_index++)
- {
- offset = par_index * 4;
- /* 4-byte for storing data to memory. */
- new_addr = plus_constant (Pmode, base_addr, offset);
- mem = adjust_automodify_address_nv (basemem, SImode,
- new_addr, offset);
- reg = gen_rtx_REG (SImode, base_regno + par_index);
-
- XVECEXP (result, 0, par_index) = gen_rtx_SET (VOIDmode, mem, reg);
- }
-
- return result;
-}
-
-/* Function to move block memory content by
- using load_multiple and store_multiple.
- This is auxiliary extern function to help create rtx template.
- Check nds32-multiple.md file for the patterns. */
-int
-nds32_expand_movmemqi (rtx dstmem, rtx srcmem, rtx total_bytes, rtx alignment)
-{
- HOST_WIDE_INT in_words, out_words;
- rtx dst_base_reg, src_base_reg;
- int maximum_bytes;
-
- /* 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 (32 bytes) for moving memory block
- may easily consume all of them.
- It makes register allocation/spilling hard to work.
- So we only allow maximum=4 registers (16 bytes) for
- moving memory block under reduced-set registers. */
- if (TARGET_REDUCED_REGS)
- maximum_bytes = 16;
- else
- maximum_bytes = 32;
-
- /* 1. Total_bytes is integer for sure.
- 2. Alignment is integer for sure.
- 3. Maximum 4 or 8 registers, 4 * 4 = 16 bytes, 8 * 4 = 32 bytes.
- 4. Requires (n * 4) block size.
- 5. Requires 4-byte alignment. */
- if (GET_CODE (total_bytes) != CONST_INT
- || GET_CODE (alignment) != CONST_INT
- || INTVAL (total_bytes) > maximum_bytes
- || INTVAL (total_bytes) & 3
- || INTVAL (alignment) & 3)
- return 0;
-
- dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0));
- src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0));
-
- out_words = in_words = INTVAL (total_bytes) / UNITS_PER_WORD;
-
- emit_insn (nds32_expand_load_multiple (0, in_words, src_base_reg, srcmem));
- emit_insn (nds32_expand_store_multiple (0, out_words, dst_base_reg, dstmem));
-
- /* Successfully create patterns, return 1. */
- return 1;
-}
-
-/* Function to check whether the OP is a valid load/store operation.
- This is a helper function for the predicates:
- 'nds32_load_multiple_operation' and 'nds32_store_multiple_operation'
- in predicates.md file.
-
- The OP is supposed to be a parallel rtx.
- For each element within this parallel rtx:
- (set (reg) (mem addr)) is the form for load operation.
- (set (mem addr) (reg)) is the form for store operation.
- We have to extract reg and mem of every element and
- check if the information is valid for multiple load/store operation. */
-bool
-nds32_valid_multiple_load_store (rtx op, bool load_p)
-{
- int count;
- int first_elt_regno;
- 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)
- return false;
-
- /* Pick up regno of first element for further detail checking.
- Note that the form is different between load and store operation. */
- if (load_p)
- {
- if (GET_CODE (SET_DEST (elt)) != REG
- || GET_CODE (SET_SRC (elt)) != MEM)
- return false;
-
- first_elt_regno = REGNO (SET_DEST (elt));
- }
- else
- {
- if (GET_CODE (SET_SRC (elt)) != REG
- || GET_CODE (SET_DEST (elt)) != MEM)
- return false;
-
- first_elt_regno = REGNO (SET_SRC (elt));
- }
-
- /* Perform detail check for each element.
- Refer to nds32-multiple.md for more information
- about following checking.
- The starting element of parallel rtx is index 0. */
- if (!nds32_consecutive_registers_load_store_p (op, load_p, 0,
- first_elt_regno,
- count))
- return false;
-
- /* Pass all test, this is a valid rtx. */
- return true;
-}
-
-/* Function to check whether the OP is a valid stack push/pop operation.
- For a valid stack operation, it must satisfy following conditions:
- 1. Consecutive registers push/pop operations.
- 2. Valid $fp/$gp/$lp push/pop operations.
- 3. The last element must be stack adjustment rtx.
- See the prologue/epilogue implementation for details. */
-bool
-nds32_valid_stack_push_pop (rtx op, bool push_p)
-{
- int index;
- int total_count;
- int rest_count;
- int first_regno;
- rtx elt;
- rtx elt_reg;
- rtx elt_mem;
- rtx elt_plus;
-
- /* Get the counts of elements in the parallel rtx. */
- total_count = XVECLEN (op, 0);
-
- /* Perform some quick check for that every element should be 'set'. */
- for (index = 0; index < total_count; index++)
- {
- elt = XVECEXP (op, 0, index);
- if (GET_CODE (elt) != SET)
- return false;
- }
-
- /* For push operation, the parallel rtx looks like:
- (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
- (reg:SI Rb))
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -28)))
- (reg:SI Rb+1))
- ...
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -16)))
- (reg:SI Re))
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -12)))
- (reg:SI FP_REGNUM))
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -8)))
- (reg:SI GP_REGNUM))
- (set (mem (plus (reg:SI SP_REGNUM) (const_int -4)))
- (reg:SI LP_REGNUM))
- (set (reg:SI SP_REGNUM)
- (plus (reg:SI SP_REGNUM) (const_int -32)))])
-
- For pop operation, the parallel rtx looks like:
- (parallel [(set (reg:SI Rb)
- (mem (reg:SI SP_REGNUM)))
- (set (reg:SI Rb+1)
- (mem (plus (reg:SI SP_REGNUM) (const_int 4))))
- ...
- (set (reg:SI Re)
- (mem (plus (reg:SI SP_REGNUM) (const_int 16))))
- (set (reg:SI FP_REGNUM)
- (mem (plus (reg:SI SP_REGNUM) (const_int 20))))
- (set (reg:SI GP_REGNUM)
- (mem (plus (reg:SI SP_REGNUM) (const_int 24))))
- (set (reg:SI LP_REGNUM)
- (mem (plus (reg:SI SP_REGNUM) (const_int 28))))
- (set (reg:SI SP_REGNUM)
- (plus (reg:SI SP_REGNUM) (const_int 32)))]) */
-
- /* 1. Consecutive registers push/pop operations.
- We need to calculate how many registers should be consecutive.
- The $sp adjustment rtx, $fp push rtx, $gp push rtx,
- and $lp push rtx are excluded. */
-
- /* Exclude last $sp adjustment rtx. */
- rest_count = total_count - 1;
- /* Exclude $fp, $gp, and $lp if they are in the parallel rtx. */
- if (cfun->machine->fp_size)
- rest_count--;
- if (cfun->machine->gp_size)
- rest_count--;
- if (cfun->machine->lp_size)
- rest_count--;
-
- if (rest_count > 0)
- {
- elt = XVECEXP (op, 0, 0);
- /* Pick up register element. */
- elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
- first_regno = REGNO (elt_reg);
-
- /* The 'push' operation is a kind of store operation.
- The 'pop' operation is a kind of load operation.
- Pass corresponding false/true as second argument (bool load_p).
- The par_index is supposed to start with index 0. */
- if (!nds32_consecutive_registers_load_store_p (op,
- !push_p ? true : false,
- 0,
- first_regno,
- rest_count))
- return false;
- }
-
- /* 2. Valid $fp/$gp/$lp push/pop operations.
- Remember to set start index for checking them. */
-
- /* The rest_count is the start index for checking $fp/$gp/$lp. */
- index = rest_count;
- /* If index < 0, this parallel rtx is definitely
- not a valid stack push/pop operation. */
- if (index < 0)
- return false;
-
- /* Check $fp/$gp/$lp one by one.
- We use 'push_p' to pick up reg rtx and mem rtx. */
- if (cfun->machine->fp_size)
- {
- elt = XVECEXP (op, 0, index);
- elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
- elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
- index++;
-
- if (GET_CODE (elt_mem) != MEM
- || GET_CODE (elt_reg) != REG
- || REGNO (elt_reg) != FP_REGNUM)
- return false;
- }
- if (cfun->machine->gp_size)
- {
- elt = XVECEXP (op, 0, index);
- elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
- elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
- index++;
-
- if (GET_CODE (elt_mem) != MEM
- || GET_CODE (elt_reg) != REG
- || REGNO (elt_reg) != GP_REGNUM)
- return false;
- }
- if (cfun->machine->lp_size)
- {
- elt = XVECEXP (op, 0, index);
- elt_mem = push_p ? SET_DEST (elt) : SET_SRC (elt);
- elt_reg = push_p ? SET_SRC (elt) : SET_DEST (elt);
- index++;
-
- if (GET_CODE (elt_mem) != MEM
- || GET_CODE (elt_reg) != REG
- || REGNO (elt_reg) != LP_REGNUM)
- return false;
- }
-
- /* 3. The last element must be stack adjustment rtx.
- Its form of rtx should be:
- (set (reg:SI SP_REGNUM)
- (plus (reg:SI SP_REGNUM) (const_int X)))
- The X could be positive or negative value. */
-
- /* Pick up the last element. */
- elt = XVECEXP (op, 0, total_count - 1);
-
- /* Extract its destination and source rtx. */
- elt_reg = SET_DEST (elt);
- elt_plus = SET_SRC (elt);
-
- /* Check this is (set (stack_reg) (plus stack_reg const)) pattern. */
- if (GET_CODE (elt_reg) != REG
- || GET_CODE (elt_plus) != PLUS
- || REGNO (elt_reg) != SP_REGNUM)
- return false;
-
- /* Pass all test, this is a valid rtx. */
- return true;
-}
-
/* Computing the Length of an Insn.
Modifies the length assigned to instruction INSN.
LEN is the initially computed length of the insn. */
int
-nds32_adjust_insn_length (rtx insn, int length)
+nds32_adjust_insn_length (rtx_insn *insn, int length)
{
rtx src, dst;
@@ -4439,979 +3525,11 @@ nds32_adjust_insn_length (rtx insn, int length)
}
-/* Function to check if 'bclr' instruction can be used with IVAL. */
-int
-nds32_can_use_bclr_p (int ival)
-{
- int one_bit_count;
-
- /* Calculate the number of 1-bit of (~ival), if there is only one 1-bit,
- it means the original ival has only one 0-bit,
- So it is ok to perform 'bclr' operation. */
-
- one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (~ival));
-
- /* 'bclr' is a performance extension instruction. */
- return (TARGET_PERF_EXT && (one_bit_count == 1));
-}
-
-/* Function to check if 'bset' instruction can be used with IVAL. */
-int
-nds32_can_use_bset_p (int ival)
-{
- int one_bit_count;
-
- /* Caculate the number of 1-bit of ival, if there is only one 1-bit,
- it is ok to perform 'bset' operation. */
-
- one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival));
-
- /* 'bset' is a performance extension instruction. */
- return (TARGET_PERF_EXT && (one_bit_count == 1));
-}
-
-/* Function to check if 'btgl' instruction can be used with IVAL. */
-int
-nds32_can_use_btgl_p (int ival)
-{
- int one_bit_count;
-
- /* Caculate the number of 1-bit of ival, if there is only one 1-bit,
- it is ok to perform 'btgl' operation. */
-
- one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival));
-
- /* 'btgl' is a performance extension instruction. */
- return (TARGET_PERF_EXT && (one_bit_count == 1));
-}
-
-/* Function to check if 'bitci' instruction can be used with IVAL. */
-int
-nds32_can_use_bitci_p (int ival)
-{
- /* If we are using V3 ISA, we have 'bitci' instruction.
- Try to see if we can present 'andi' semantic with
- such 'bit-clear-immediate' operation.
- For example, 'andi $r0,$r0,0xfffffffc' can be
- presented with 'bitci $r0,$r0,3'. */
- return (TARGET_ISA_V3
- && (ival < 0)
- && satisfies_constraint_Iu15 (gen_int_mode (~ival, SImode)));
-}
-
-
-/* Return true if is load/store with SYMBOL_REF addressing mode
- and memory mode is SImode. */
-bool
-nds32_symbol_load_store_p (rtx insn)
-{
- rtx mem_src = NULL_RTX;
-
- switch (get_attr_type (insn))
- {
- case TYPE_LOAD:
- mem_src = SET_SRC (PATTERN (insn));
- break;
- case TYPE_STORE:
- mem_src = SET_DEST (PATTERN (insn));
- break;
- default:
- break;
- }
-
- /* Find load/store insn with addressing mode is SYMBOL_REF. */
- if (mem_src != NULL_RTX)
- {
- if ((GET_CODE (mem_src) == ZERO_EXTEND)
- || (GET_CODE (mem_src) == SIGN_EXTEND))
- mem_src = XEXP (mem_src, 0);
-
- if ((GET_CODE (XEXP (mem_src, 0)) == SYMBOL_REF)
- || (GET_CODE (XEXP (mem_src, 0)) == LO_SUM))
- return true;
- }
-
- return false;
-}
-
-/* Function to determine whether it is worth to do fp_as_gp optimization.
- Return 0: It is NOT worth to do fp_as_gp optimization.
- Return 1: It is APPROXIMATELY worth to do fp_as_gp optimization.
- Note that if it is worth to do fp_as_gp optimization,
- we MUST set FP_REGNUM ever live in this function. */
-int
-nds32_fp_as_gp_check_available (void)
-{
- /* If there exists ANY of following conditions,
- we DO NOT perform fp_as_gp optimization:
- 1. TARGET_FORBID_FP_AS_GP is set
- regardless of the TARGET_FORCE_FP_AS_GP.
- 2. User explicitly uses 'naked' attribute.
- 3. Not optimize for size.
- 4. Need frame pointer.
- 5. If $fp is already required to be saved,
- it means $fp is already choosen by register allocator.
- Thus we better not to use it for fp_as_gp optimization.
- 6. This function is a vararg function.
- DO NOT apply fp_as_gp optimization on this function
- because it may change and break stack frame.
- 7. The epilogue is empty.
- This happens when the function uses exit()
- or its attribute is no_return.
- In that case, compiler will not expand epilogue
- so that we have no chance to output .omit_fp_end directive. */
- if (TARGET_FORBID_FP_AS_GP
- || lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl))
- || !optimize_size
- || frame_pointer_needed
- || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
- || (cfun->stdarg == 1)
- || (find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == NULL))
- return 0;
-
- /* Now we can check the possibility of using fp_as_gp optimization. */
- if (TARGET_FORCE_FP_AS_GP)
- {
- /* User explicitly issues -mforce-fp-as-gp option. */
- df_set_regs_ever_live (FP_REGNUM, 1);
- return 1;
- }
- else
- {
- /* In the following we are going to evaluate whether
- it is worth to do fp_as_gp optimization. */
- int good_gain = 0;
- int symbol_count = 0;
-
- int threshold;
- rtx insn;
-
- /* We check if there already requires prologue.
- Note that $gp will be saved in prologue for PIC code generation.
- After that, we can set threshold by the existence of prologue.
- Each fp-implied instruction will gain 2-byte code size
- from gp-aware instruction, so we have following heuristics. */
- if (flag_pic
- || nds32_have_prologue_p ())
- {
- /* Have-prologue:
- Compiler already intends to generate prologue content,
- so the fp_as_gp optimization will only insert
- 'la $fp,_FP_BASE_' instruction, which will be
- converted into 4-byte instruction at link time.
- The threshold is "3" symbol accesses, 2 + 2 + 2 > 4. */
- threshold = 3;
- }
- else
- {
- /* None-prologue:
- Compiler originally does not generate prologue content,
- so the fp_as_gp optimization will NOT ONLY insert
- 'la $fp,_FP_BASE' instruction, but also causes
- push/pop instructions.
- If we are using v3push (push25/pop25),
- the threshold is "5" symbol accesses, 5*2 > 4 + 2 + 2;
- If we are using normal push (smw/lmw),
- the threshold is "5+2" symbol accesses 7*2 > 4 + 4 + 4. */
- threshold = 5 + (TARGET_V3PUSH ? 0 : 2);
- }
-
- /* We would like to traverse every instruction in this function.
- So we need to have push_topmost_sequence()/pop_topmost_sequence()
- surrounding our for-loop evaluation. */
- push_topmost_sequence ();
- /* Counting the insn number which the addressing mode is symbol. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (single_set (insn) && nds32_symbol_load_store_p (insn))
- symbol_count++;
-
- if (symbol_count == threshold)
- {
- good_gain = 1;
- break;
- }
- }
- pop_topmost_sequence ();
-
- /* Enable fp_as_gp optimization when potential gain is good enough. */
- if (good_gain)
- {
- df_set_regs_ever_live (FP_REGNUM, 1);
- return 1;
- }
- }
-
- /* By default we return 0. */
- return 0;
-}
-
-
-/* Function to generate PC relative jump table.
- Refer to nds32.md for more details.
-
- The following is the sample for the case that diff value
- can be presented in '.short' size.
-
- addi $r1, $r1, -(case_lower_bound)
- slti $ta, $r1, (case_number)
- beqz $ta, .L_skip_label
-
- la $ta, .L35 ! get jump table address
- lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
- addi $ta, $r1, $ta
- jr5 $ta
-
- ! jump table entry
- L35:
- .short .L25-.L35
- .short .L26-.L35
- .short .L27-.L35
- .short .L28-.L35
- .short .L29-.L35
- .short .L30-.L35
- .short .L31-.L35
- .short .L32-.L35
- .short .L33-.L35
- .short .L34-.L35 */
-const char *
-nds32_output_casesi_pc_relative (rtx *operands)
-{
- enum machine_mode mode;
- rtx diff_vec;
-
- diff_vec = PATTERN (NEXT_INSN (operands[1]));
-
- gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
-
- /* Step C: "t <-- operands[1]". */
- output_asm_insn ("la\t$ta, %l1", operands);
-
- /* Get the mode of each element in the difference vector. */
- mode = GET_MODE (diff_vec);
-
- /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
- where m is 0, 1, or 2 to load address-diff value from table. */
- switch (mode)
- {
- case QImode:
- output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
- break;
- case HImode:
- output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
- break;
- case SImode:
- output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
- break;
- default:
- gcc_unreachable ();
- }
-
- /* Step E: "t <-- z + t".
- Add table label_ref with address-diff value to
- obtain target case address. */
- output_asm_insn ("add\t$ta, %2, $ta", operands);
-
- /* Step F: jump to target with register t. */
- if (TARGET_16_BIT)
- return "jr5\t$ta";
- else
- return "jr\t$ta";
-}
-
-/* Function to generate normal jump table. */
-const char *
-nds32_output_casesi (rtx *operands)
-{
- /* Step C: "t <-- operands[1]". */
- output_asm_insn ("la\t$ta, %l1", operands);
-
- /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
- output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
-
- /* No need to perform Step E, which is only used for
- pc relative jump table. */
-
- /* Step F: jump to target with register z. */
- if (TARGET_16_BIT)
- return "jr5\t%2";
- else
- return "jr\t%2";
-}
-
-
-/* Function to return memory format. */
-enum nds32_16bit_address_type
-nds32_mem_format (rtx op)
-{
- enum machine_mode mode_test;
- int val;
- int regno;
-
- if (!TARGET_16_BIT)
- return ADDRESS_NOT_16BIT_FORMAT;
-
- mode_test = GET_MODE (op);
-
- op = XEXP (op, 0);
-
- /* 45 format. */
- if (GET_CODE (op) == REG && (mode_test == SImode))
- return ADDRESS_REG;
-
- /* 333 format for QI/HImode. */
- if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
- return ADDRESS_LO_REG_IMM3U;
-
- /* post_inc 333 format. */
- if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
- {
- regno = REGNO(XEXP (op, 0));
-
- if (regno < 8)
- return ADDRESS_POST_INC_LO_REG_IMM3U;
- }
-
- /* post_inc 333 format. */
- if ((GET_CODE (op) == POST_MODIFY)
- && (mode_test == SImode)
- && (REG_P (XEXP (XEXP (op, 1), 0)))
- && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
- {
- regno = REGNO (XEXP (XEXP (op, 1), 0));
- val = INTVAL (XEXP (XEXP (op, 1), 1));
- if (regno < 8 && val < 32)
- return ADDRESS_POST_INC_LO_REG_IMM3U;
- }
-
- if ((GET_CODE (op) == PLUS)
- && (GET_CODE (XEXP (op, 0)) == REG)
- && (GET_CODE (XEXP (op, 1)) == CONST_INT))
- {
- val = INTVAL (XEXP (op, 1));
-
- regno = REGNO(XEXP (op, 0));
-
- if (regno > 7
- && regno != SP_REGNUM
- && regno != FP_REGNUM)
- return ADDRESS_NOT_16BIT_FORMAT;
-
- switch (mode_test)
- {
- case QImode:
- /* 333 format. */
- if (val >= 0 && val < 8 && regno < 8)
- return ADDRESS_LO_REG_IMM3U;
- break;
-
- case HImode:
- /* 333 format. */
- if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
- return ADDRESS_LO_REG_IMM3U;
- break;
-
- case SImode:
- case SFmode:
- case DFmode:
- /* fp imply 37 format. */
- if ((regno == FP_REGNUM) &&
- (val >= 0 && val < 512 && (val % 4 == 0)))
- return ADDRESS_FP_IMM7U;
- /* sp imply 37 format. */
- else if ((regno == SP_REGNUM) &&
- (val >= 0 && val < 512 && (val % 4 == 0)))
- return ADDRESS_SP_IMM7U;
- /* 333 format. */
- else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
- return ADDRESS_LO_REG_IMM3U;
- break;
-
- default:
- break;
- }
- }
-
- return ADDRESS_NOT_16BIT_FORMAT;
-}
-
-/* Output 16-bit store. */
-const char *
-nds32_output_16bit_store (rtx *operands, int byte)
-{
- char pattern[100];
- char size;
- rtx code = XEXP (operands[0], 0);
-
- size = nds32_byte_to_size (byte);
-
- switch (nds32_mem_format (operands[0]))
- {
- case ADDRESS_REG:
- operands[0] = code;
- output_asm_insn ("swi450\t%1, [%0]", operands);
- break;
- case ADDRESS_LO_REG_IMM3U:
- snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
- output_asm_insn (pattern, operands);
- break;
- case ADDRESS_POST_INC_LO_REG_IMM3U:
- snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
- output_asm_insn (pattern, operands);
- break;
- case ADDRESS_FP_IMM7U:
- output_asm_insn ("swi37\t%1, %0", operands);
- break;
- case ADDRESS_SP_IMM7U:
- /* Get immediate value and set back to operands[1]. */
- operands[0] = XEXP (code, 1);
- output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
- break;
- default:
- break;
- }
-
- return "";
-}
-
-/* Output 16-bit load. */
-const char *
-nds32_output_16bit_load (rtx *operands, int byte)
-{
- char pattern[100];
- unsigned char size;
- rtx code = XEXP (operands[1], 0);
-
- size = nds32_byte_to_size (byte);
-
- switch (nds32_mem_format (operands[1]))
- {
- case ADDRESS_REG:
- operands[1] = code;
- output_asm_insn ("lwi450\t%0, [%1]", operands);
- break;
- case ADDRESS_LO_REG_IMM3U:
- snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
- output_asm_insn (pattern, operands);
- break;
- case ADDRESS_POST_INC_LO_REG_IMM3U:
- snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
- output_asm_insn (pattern, operands);
- break;
- case ADDRESS_FP_IMM7U:
- output_asm_insn ("lwi37\t%0, %1", operands);
- break;
- case ADDRESS_SP_IMM7U:
- /* Get immediate value and set back to operands[0]. */
- operands[1] = XEXP (code, 1);
- output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
- break;
- default:
- break;
- }
-
- return "";
-}
-
-/* Output 32-bit store. */
-const char *
-nds32_output_32bit_store (rtx *operands, int byte)
-{
- char pattern[100];
- unsigned char size;
- rtx code = XEXP (operands[0], 0);
-
- size = nds32_byte_to_size (byte);
-
- switch (GET_CODE (code))
- {
- case REG:
- /* (mem (reg X))
- => access location by using register,
- use "sbi / shi / swi" */
- snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
- break;
-
- case SYMBOL_REF:
- case CONST:
- /* (mem (symbol_ref X))
- (mem (const (...)))
- => access global variables,
- use "sbi.gp / shi.gp / swi.gp" */
- operands[0] = XEXP (operands[0], 0);
- snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
- break;
-
- case POST_INC:
- /* (mem (post_inc reg))
- => access location by using register which will be post increment,
- use "sbi.bi / shi.bi / swi.bi" */
- snprintf (pattern, sizeof (pattern),
- "s%ci.bi\t%%1, %%0, %d", size, byte);
- break;
-
- case POST_DEC:
- /* (mem (post_dec reg))
- => access location by using register which will be post decrement,
- use "sbi.bi / shi.bi / swi.bi" */
- snprintf (pattern, sizeof (pattern),
- "s%ci.bi\t%%1, %%0, -%d", size, byte);
- break;
-
- case POST_MODIFY:
- switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (post_modify (reg) (plus (reg) (reg))))
- => access location by using register which will be
- post modified with reg,
- use "sb.bi/ sh.bi / sw.bi" */
- snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
- break;
- case CONST_INT:
- /* (mem (post_modify (reg) (plus (reg) (const_int))))
- => access location by using register which will be
- post modified with const_int,
- use "sbi.bi/ shi.bi / swi.bi" */
- snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
- break;
- default:
- abort ();
- }
- break;
-
- case PLUS:
- switch (GET_CODE (XEXP (code, 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
- => access location by adding two registers,
- use "sb / sh / sw" */
- snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
- break;
- case CONST_INT:
- /* (mem (plus reg const_int))
- => access location by adding one register with const_int,
- use "sbi / shi / swi" */
- snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
- break;
- default:
- abort ();
- }
- break;
-
- case LO_SUM:
- operands[2] = XEXP (code, 1);
- operands[0] = XEXP (code, 0);
- snprintf (pattern, sizeof (pattern),
- "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
- break;
-
- default:
- abort ();
- }
-
- output_asm_insn (pattern, operands);
- return "";
-}
-
-/* Output 32-bit load. */
-const char *
-nds32_output_32bit_load (rtx *operands, int byte)
-{
- char pattern[100];
- unsigned char size;
- rtx code;
-
- code = XEXP (operands[1], 0);
-
- size = nds32_byte_to_size (byte);
-
- switch (GET_CODE (code))
- {
- case REG:
- /* (mem (reg X))
- => access location by using register,
- use "lbi / lhi / lwi" */
- snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
- break;
-
- case SYMBOL_REF:
- case CONST:
- /* (mem (symbol_ref X))
- (mem (const (...)))
- => access global variables,
- use "lbi.gp / lhi.gp / lwi.gp" */
- operands[1] = XEXP (operands[1], 0);
- snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
- break;
-
- case POST_INC:
- /* (mem (post_inc reg))
- => access location by using register which will be post increment,
- use "lbi.bi / lhi.bi / lwi.bi" */
- snprintf (pattern, sizeof (pattern),
- "l%ci.bi\t%%0, %%1, %d", size, byte);
- break;
-
- case POST_DEC:
- /* (mem (post_dec reg))
- => access location by using register which will be post decrement,
- use "lbi.bi / lhi.bi / lwi.bi" */
- snprintf (pattern, sizeof (pattern),
- "l%ci.bi\t%%0, %%1, -%d", size, byte);
- break;
-
- case POST_MODIFY:
- switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (post_modify (reg) (plus (reg) (reg))))
- => access location by using register which will be
- post modified with reg,
- use "lb.bi/ lh.bi / lw.bi" */
- snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
- break;
- case CONST_INT:
- /* (mem (post_modify (reg) (plus (reg) (const_int))))
- => access location by using register which will be
- post modified with const_int,
- use "lbi.bi/ lhi.bi / lwi.bi" */
- snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
- break;
- default:
- abort ();
- }
- break;
-
- case PLUS:
- switch (GET_CODE (XEXP (code, 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
- use "lb / lh / lw" */
- snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
- break;
- case CONST_INT:
- /* (mem (plus reg const_int))
- => access location by adding one register with const_int,
- use "lbi / lhi / lwi" */
- snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
- break;
- default:
- abort ();
- }
- break;
-
- case LO_SUM:
- operands[2] = XEXP (code, 1);
- operands[1] = XEXP (code, 0);
- snprintf (pattern, sizeof (pattern),
- "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
- break;
-
- default:
- abort ();
- }
-
- output_asm_insn (pattern, operands);
- return "";
-}
-
-/* Output 32-bit load with signed extension. */
-const char *
-nds32_output_32bit_load_s (rtx *operands, int byte)
-{
- char pattern[100];
- unsigned char size;
- rtx code;
-
- code = XEXP (operands[1], 0);
-
- size = nds32_byte_to_size (byte);
-
- switch (GET_CODE (code))
- {
- case REG:
- /* (mem (reg X))
- => access location by using register,
- use "lbsi / lhsi" */
- snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
- break;
-
- case SYMBOL_REF:
- case CONST:
- /* (mem (symbol_ref X))
- (mem (const (...)))
- => access global variables,
- use "lbsi.gp / lhsi.gp" */
- operands[1] = XEXP (operands[1], 0);
- snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
- break;
-
- case POST_INC:
- /* (mem (post_inc reg))
- => access location by using register which will be post increment,
- use "lbsi.bi / lhsi.bi" */
- snprintf (pattern, sizeof (pattern),
- "l%csi.bi\t%%0, %%1, %d", size, byte);
- break;
-
- case POST_DEC:
- /* (mem (post_dec reg))
- => access location by using register which will be post decrement,
- use "lbsi.bi / lhsi.bi" */
- snprintf (pattern, sizeof (pattern),
- "l%csi.bi\t%%0, %%1, -%d", size, byte);
- break;
-
- case POST_MODIFY:
- switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (post_modify (reg) (plus (reg) (reg))))
- => access location by using register which will be
- post modified with reg,
- use "lbs.bi/ lhs.bi" */
- snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
- break;
- case CONST_INT:
- /* (mem (post_modify (reg) (plus (reg) (const_int))))
- => access location by using register which will be
- post modified with const_int,
- use "lbsi.bi/ lhsi.bi" */
- snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
- break;
- default:
- abort ();
- }
- break;
-
- case PLUS:
- switch (GET_CODE (XEXP (code, 1)))
- {
- case REG:
- case SUBREG:
- /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
- use "lbs / lhs" */
- snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
- break;
- case CONST_INT:
- /* (mem (plus reg const_int))
- => access location by adding one register with const_int,
- use "lbsi / lhsi" */
- snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
- break;
- default:
- abort ();
- }
- break;
-
- case LO_SUM:
- operands[2] = XEXP (code, 1);
- operands[1] = XEXP (code, 0);
- snprintf (pattern, sizeof (pattern),
- "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
- break;
-
- default:
- abort ();
- }
-
- output_asm_insn (pattern, operands);
- return "";
-}
-
-/* Function to output stack push operation.
- We need to deal with normal stack push multiple or stack v3push. */
-const char *
-nds32_output_stack_push (void)
-{
- /* A string pattern for output_asm_insn(). */
- char pattern[100];
- /* The operands array which will be used in output_asm_insn(). */
- rtx operands[3];
- /* Pick up callee-saved first regno and last regno for further use. */
- int rb_regno = cfun->machine->callee_saved_regs_first_regno;
- int re_regno = cfun->machine->callee_saved_regs_last_regno;
-
- if (TARGET_V3PUSH)
- {
- /* For stack v3push:
- operands[0]: Re
- operands[1]: imm8u */
-
- /* This variable is to check if 'push25 Re,imm8u' is available. */
- int sp_adjust;
-
- /* Set operands[0]. */
- operands[0] = gen_rtx_REG (SImode, re_regno);
-
- /* Check if we can generate 'push25 Re,imm8u',
- otherwise, generate 'push25 Re,0'. */
- sp_adjust = cfun->machine->local_size
- + cfun->machine->out_args_size
- + cfun->machine->callee_saved_area_padding_bytes;
- if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
- && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
- operands[1] = GEN_INT (sp_adjust);
- else
- operands[1] = GEN_INT (0);
-
- /* Create assembly code pattern. */
- snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
- }
- else
- {
- /* For normal stack push multiple:
- operands[0]: Rb
- operands[1]: Re
- operands[2]: En4 */
-
- /* This variable is used to check if we only need to generate En4 field.
- As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
- int push_en4_only_p = 0;
-
- /* Set operands[0] and operands[1]. */
- operands[0] = gen_rtx_REG (SImode, rb_regno);
- operands[1] = gen_rtx_REG (SImode, re_regno);
-
- /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
- if (!cfun->machine->fp_size
- && !cfun->machine->gp_size
- && !cfun->machine->lp_size
- && REGNO (operands[0]) == SP_REGNUM
- && REGNO (operands[1]) == SP_REGNUM)
- {
- /* No need to generate instruction. */
- return "";
- }
- else
- {
- /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
- if (REGNO (operands[0]) == SP_REGNUM
- && REGNO (operands[1]) == SP_REGNUM)
- push_en4_only_p = 1;
-
- /* Create assembly code pattern.
- We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
- snprintf (pattern, sizeof (pattern),
- "push.s\t%s{%s%s%s }",
- push_en4_only_p ? "" : "%0, %1, ",
- cfun->machine->fp_size ? " $fp" : "",
- cfun->machine->gp_size ? " $gp" : "",
- cfun->machine->lp_size ? " $lp" : "");
- }
- }
-
- /* We use output_asm_insn() to output assembly code by ourself. */
- output_asm_insn (pattern, operands);
- return "";
-}
-
-/* Function to output stack pop operation.
- We need to deal with normal stack pop multiple or stack v3pop. */
-const char *
-nds32_output_stack_pop (void)
-{
- /* A string pattern for output_asm_insn(). */
- char pattern[100];
- /* The operands array which will be used in output_asm_insn(). */
- rtx operands[3];
- /* Pick up callee-saved first regno and last regno for further use. */
- int rb_regno = cfun->machine->callee_saved_regs_first_regno;
- int re_regno = cfun->machine->callee_saved_regs_last_regno;
-
- if (TARGET_V3PUSH)
- {
- /* For stack v3pop:
- operands[0]: Re
- operands[1]: imm8u */
-
- /* This variable is to check if 'pop25 Re,imm8u' is available. */
- int sp_adjust;
-
- /* Set operands[0]. */
- operands[0] = gen_rtx_REG (SImode, re_regno);
-
- /* Check if we can generate 'pop25 Re,imm8u',
- otherwise, generate 'pop25 Re,0'.
- We have to consider alloca issue as well.
- If the function does call alloca(), the stack pointer is not fixed.
- In that case, we cannot use 'pop25 Re,imm8u' directly.
- We have to caculate stack pointer from frame pointer
- and then use 'pop25 Re,0'. */
- sp_adjust = cfun->machine->local_size
- + cfun->machine->out_args_size
- + cfun->machine->callee_saved_area_padding_bytes;
- if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
- && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
- && !cfun->calls_alloca)
- operands[1] = GEN_INT (sp_adjust);
- else
- operands[1] = GEN_INT (0);
-
- /* Create assembly code pattern. */
- snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
- }
- else
- {
- /* For normal stack pop multiple:
- operands[0]: Rb
- operands[1]: Re
- operands[2]: En4 */
-
- /* This variable is used to check if we only need to generate En4 field.
- As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
- int pop_en4_only_p = 0;
-
- /* Set operands[0] and operands[1]. */
- operands[0] = gen_rtx_REG (SImode, rb_regno);
- operands[1] = gen_rtx_REG (SImode, re_regno);
-
- /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
- if (!cfun->machine->fp_size
- && !cfun->machine->gp_size
- && !cfun->machine->lp_size
- && REGNO (operands[0]) == SP_REGNUM
- && REGNO (operands[1]) == SP_REGNUM)
- {
- /* No need to generate instruction. */
- return "";
- }
- else
- {
- /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
- if (REGNO (operands[0]) == SP_REGNUM
- && REGNO (operands[1]) == SP_REGNUM)
- pop_en4_only_p = 1;
-
- /* Create assembly code pattern.
- We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
- snprintf (pattern, sizeof (pattern),
- "pop.s\t%s{%s%s%s }",
- pop_en4_only_p ? "" : "%0, %1, ",
- cfun->machine->fp_size ? " $fp" : "",
- cfun->machine->gp_size ? " $gp" : "",
- cfun->machine->lp_size ? " $lp" : "");
- }
- }
-
- /* We use output_asm_insn() to output assembly code by ourself. */
- output_asm_insn (pattern, operands);
- return "";
-}
-
/* Return align 2 (log base 2) if the next instruction of LABEL is 4 byte. */
int
nds32_target_alignment (rtx label)
{
- rtx insn;
+ rtx_insn *insn;
if (optimize_size)
return 0;
@@ -5499,6 +3617,12 @@ nds32_target_alignment (rtx label)
#undef TARGET_FUNCTION_ARG
#define TARGET_FUNCTION_ARG nds32_function_arg
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK nds32_must_pass_in_stack
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES nds32_arg_partial_bytes
+
#undef TARGET_FUNCTION_ARG_ADVANCE
#define TARGET_FUNCTION_ARG_ADVANCE nds32_function_arg_advance
@@ -5552,6 +3676,9 @@ nds32_target_alignment (rtx label)
/* Implementing the Varargs Macros. */
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS nds32_setup_incoming_varargs
+
#undef TARGET_STRICT_ARGUMENT_NAMING
#define TARGET_STRICT_ARGUMENT_NAMING nds32_strict_argument_naming
@@ -5606,6 +3733,9 @@ nds32_target_alignment (rtx label)
/* Dividing the Output into Sections (Texts, Data, . . . ). */
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO nds32_encode_section_info
+
/* Position Independent Code. */
diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h
index 38847e5697c..8e4ebecf3be 100644
--- a/gcc/config/nds32/nds32.h
+++ b/gcc/config/nds32/nds32.h
@@ -1,5 +1,5 @@
/* Definitions of target machine of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
@@ -24,6 +24,14 @@
/* The following are auxiliary macros or structure declarations
that are used all over the nds32.c and nds32.h. */
+/* Use SYMBOL_FLAG_MACH_DEP to define our own symbol_ref flag.
+ It is used in nds32_encode_section_info() to store flag in symbol_ref
+ in case the symbol should be placed in .rodata section.
+ So that we can check it in nds32_legitimate_address_p(). */
+#define NDS32_SYMBOL_FLAG_RODATA \
+ (SYMBOL_FLAG_MACH_DEP << 0)
+#define NDS32_SYMBOL_REF_RODATA_P(x) \
+ ((SYMBOL_REF_FLAGS (x) & NDS32_SYMBOL_FLAG_RODATA) != 0)
/* Computing the Length of an Insn. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
@@ -109,7 +117,7 @@ enum nds32_16bit_address_type
/* ------------------------------------------------------------------------ */
/* Define maximum numbers of registers for passing arguments. */
-#define NDS32_MAX_REGS_FOR_ARGS 6
+#define NDS32_MAX_GPR_REGS_FOR_ARGS 6
/* Define the register number for first argument. */
#define NDS32_GPR_ARG_FIRST_REGNUM 0
@@ -117,6 +125,10 @@ enum nds32_16bit_address_type
/* Define the register number for return value. */
#define NDS32_GPR_RET_FIRST_REGNUM 0
+/* Define the first integer register number. */
+#define NDS32_FIRST_GPR_REGNUM 0
+/* Define the last integer register number. */
+#define NDS32_LAST_GPR_REGNUM 31
/* Define double word alignment bits. */
#define NDS32_DOUBLE_WORD_ALIGNMENT 64
@@ -154,19 +166,27 @@ enum nds32_16bit_address_type
b) Otherwise, the register number can be odd or even value.
2. If it is required ONLY one register,
the register number can be odd or even value. */
-#define NDS32_AVAILABLE_REGNUM_FOR_ARG(reg_offset, mode, type) \
- ((NDS32_NEED_N_REGS_FOR_ARG (mode, type) > 1) \
- ? ((NDS32_MODE_TYPE_ALIGN (mode, type) > PARM_BOUNDARY) \
- ? (((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM + 1) & ~1) \
- : ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM)) \
+#define NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG(reg_offset, mode, type) \
+ ((NDS32_NEED_N_REGS_FOR_ARG (mode, type) > 1) \
+ ? ((NDS32_MODE_TYPE_ALIGN (mode, type) > PARM_BOUNDARY) \
+ ? (((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM + 1) & ~1) \
+ : ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM)) \
: ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM))
/* This macro is to check if there are still available registers
- for passing argument. */
-#define NDS32_ARG_PASS_IN_REG_P(reg_offset, mode, type) \
- (((reg_offset) < NDS32_MAX_REGS_FOR_ARGS) \
- && ((reg_offset) + NDS32_NEED_N_REGS_FOR_ARG (mode, type) \
- <= NDS32_MAX_REGS_FOR_ARGS))
+ for passing argument, which must be entirely in registers. */
+#define NDS32_ARG_ENTIRE_IN_GPR_REG_P(reg_offset, mode, type) \
+ ((NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (reg_offset, mode, type) \
+ + NDS32_NEED_N_REGS_FOR_ARG (mode, type)) \
+ <= (NDS32_GPR_ARG_FIRST_REGNUM \
+ + NDS32_MAX_GPR_REGS_FOR_ARGS))
+
+/* This macro is to check if there are still available registers
+ for passing argument, either entirely in registers or partially
+ in registers. */
+#define NDS32_ARG_PARTIAL_IN_GPR_REG_P(reg_offset, mode, type) \
+ (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (reg_offset, mode, type) \
+ < NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS)
/* This macro is to check if the register is required to be saved on stack.
If call_used_regs[regno] == 0, regno is the callee-saved register.
@@ -203,18 +223,19 @@ struct GTY(()) machine_function
/* The padding bytes in callee-saved area may be required. */
int callee_saved_area_padding_bytes;
- /* The first required register that should be saved on stack
- for va_args (one named argument + nameless arguments). */
- int va_args_first_regno;
- /* The last required register that should be saved on stack
- for va_args (one named argument + nameless arguments). */
- int va_args_last_regno;
-
/* The first required callee-saved register. */
int callee_saved_regs_first_regno;
/* The last required callee-saved register. */
int callee_saved_regs_last_regno;
+ /* The padding bytes in varargs area may be required. */
+ int va_args_area_padding_bytes;
+
+ /* The first required register that should be saved on stack for va_args. */
+ int va_args_first_regno;
+ /* The last required register that should be saved on stack for va_args. */
+ int va_args_last_regno;
+
/* Indicate that whether this function needs
prologue/epilogue code generation. */
int naked_p;
@@ -226,7 +247,7 @@ struct GTY(()) machine_function
/* A C structure that contains the arguments information. */
typedef struct
{
- unsigned int reg_offset;
+ unsigned int gpr_offset;
} nds32_cumulative_args;
/* ------------------------------------------------------------------------ */
@@ -331,6 +352,22 @@ enum nds32_builtins
#define TARGET_ISA_V3 (nds32_arch_option == ARCH_V3)
#define TARGET_ISA_V3M (nds32_arch_option == ARCH_V3M)
+#define TARGET_CMODEL_SMALL \
+ (nds32_cmodel_option == CMODEL_SMALL)
+#define TARGET_CMODEL_MEDIUM \
+ (nds32_cmodel_option == CMODEL_MEDIUM)
+#define TARGET_CMODEL_LARGE \
+ (nds32_cmodel_option == CMODEL_LARGE)
+
+/* When -mcmodel=small or -mcmodel=medium,
+ compiler may generate gp-base instruction directly. */
+#define TARGET_GP_DIRECT \
+ (nds32_cmodel_option == CMODEL_SMALL\
+ || nds32_cmodel_option == CMODEL_MEDIUM)
+
+#define TARGET_SOFT_FLOAT 1
+#define TARGET_HARD_FLOAT 0
+
/* ------------------------------------------------------------------------ */
/* Controlling the Compilation Driver. */
@@ -344,13 +381,10 @@ enum nds32_builtins
#define ASM_SPEC \
" %{mbig-endian:-EB} %{mlittle-endian:-EL}"
-/* If user issues -mrelax, -mforce-fp-as-gp, or -mex9,
- we need to pass '--relax' to linker.
- Besides, for -mex9, we need to further pass '--mex9'. */
+/* If user issues -mrelax, we need to pass '--relax' to linker. */
#define LINK_SPEC \
" %{mbig-endian:-EB} %{mlittle-endian:-EL}" \
- " %{mrelax|mforce-fp-as-gp|mex9:--relax}" \
- " %{mex9:--mex9}"
+ " %{mrelax:--relax}"
#define LIB_SPEC \
" -lc -lgloss"
@@ -375,17 +409,22 @@ enum nds32_builtins
#define ENDFILE_SPEC \
" %{!mno-ctor-dtor:crtend1.o%s}"
-/* The TARGET_BIG_ENDIAN_DEFAULT is defined if we configure gcc
- with --target=nds32be-* setting.
- Check gcc/config.gcc for more information.
- In addition, currently we only have elf toolchain,
- where mgp-direct is always the default. */
+/* The TARGET_BIG_ENDIAN_DEFAULT is defined if we
+ configure gcc with --target=nds32be-* setting.
+ Check gcc/config.gcc for more information. */
#ifdef TARGET_BIG_ENDIAN_DEFAULT
-#define MULTILIB_DEFAULTS { "mbig-endian", "mgp-direct" }
+# define NDS32_ENDIAN_DEFAULT "mbig-endian"
#else
-#define MULTILIB_DEFAULTS { "mlittle-endian", "mgp-direct" }
+# define NDS32_ENDIAN_DEFAULT "mlittle-endian"
#endif
+/* Currently we only have elf toolchain,
+ where -mcmodel=medium is always the default. */
+#define NDS32_CMODEL_DEFAULT "mcmodel=medium"
+
+#define MULTILIB_DEFAULTS \
+ { NDS32_ENDIAN_DEFAULT, NDS32_CMODEL_DEFAULT }
+
/* Run-time Target Specification. */
@@ -553,7 +592,7 @@ enum nds32_builtins
/* Tell IRA to use the order we define rather than messing it up with its
own cost calculations. */
-#define HONOR_REG_ALLOC_ORDER
+#define HONOR_REG_ALLOC_ORDER optimize_size
/* The number of consecutive hard regs needed starting at
reg "regno" for holding a value of mode "mode". */
@@ -663,7 +702,8 @@ enum reg_class
#define STACK_POINTER_OFFSET 0
-#define FIRST_PARM_OFFSET(fundecl) 0
+#define FIRST_PARM_OFFSET(fundecl) \
+ (NDS32_DOUBLE_WORD_ALIGN_P (crtl->args.pretend_args_size) ? 0 : 4)
#define RETURN_ADDR_RTX(count, frameaddr) \
nds32_return_addr_rtx (count, frameaddr)
@@ -709,7 +749,7 @@ enum reg_class
'comparison of unsigned expression >= 0 is always true' warning. */
#define FUNCTION_ARG_REGNO_P(regno) \
(((int) regno - NDS32_GPR_ARG_FIRST_REGNUM >= 0) \
- && ((int) regno - NDS32_GPR_ARG_FIRST_REGNUM < NDS32_MAX_REGS_FOR_ARGS))
+ && ((int) regno - NDS32_GPR_ARG_FIRST_REGNUM < NDS32_MAX_GPR_REGS_FOR_ARGS))
#define DEFAULT_PCC_STRUCT_RETURN 0
@@ -813,6 +853,8 @@ enum reg_class
/* Position Independent Code. */
+#define PIC_OFFSET_TABLE_REGNUM GP_REGNUM
+
/* Defining the Output Assembler Language. */
diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md
index 0402cadd6b2..64823a13a47 100644
--- a/gcc/config/nds32/nds32.md
+++ b/gcc/config/nds32/nds32.md
@@ -1,5 +1,5 @@
;; Machine description of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
@@ -261,7 +261,7 @@
(define_insn "add<mode>3"
[(set (match_operand:QIHISI 0 "register_operand" "= d, l, d, l, d, l, k, l, r, r")
- (plus:QIHISI (match_operand:QIHISI 1 "register_operand" " 0, l, 0, l, %0, l, 0, k, r, r")
+ (plus:QIHISI (match_operand:QIHISI 1 "register_operand" "% 0, l, 0, l, 0, l, 0, k, r, r")
(match_operand:QIHISI 2 "nds32_rimm15s_operand" " In05, In03, Iu05, Iu03, r, l, Is10, Iu06, Is15, r")))]
""
{
@@ -382,9 +382,9 @@
;; Multiplication instructions.
(define_insn "mulsi3"
- [(set (match_operand:SI 0 "register_operand" "= w, r")
- (mult:SI (match_operand:SI 1 "register_operand" " %0, r")
- (match_operand:SI 2 "register_operand" " w, r")))]
+ [(set (match_operand:SI 0 "register_operand" "=w, r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%0, r")
+ (match_operand:SI 2 "register_operand" " w, r")))]
""
"@
mul33\t%0, %2
@@ -489,9 +489,9 @@
)
(define_insn "andsi3"
- [(set (match_operand:SI 0 "register_operand" "= w, r, l, l, l, l, l, l, r, r, r, r, r")
- (and:SI (match_operand:SI 1 "register_operand" " %0, r, l, l, l, l, 0, 0, r, r, r, r, r")
- (match_operand:SI 2 "general_operand" " w, r, Izeb, Izeh, Ixls, Ix11, Ibms, Ifex, Izeb, Izeh, Iu15, Ii15, Ic15")))]
+ [(set (match_operand:SI 0 "register_operand" "=w, r, l, l, l, l, l, l, r, r, r, r, r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0, r, l, l, l, l, 0, 0, r, r, r, r, r")
+ (match_operand:SI 2 "general_operand" " w, r, Izeb, Izeh, Ixls, Ix11, Ibms, Ifex, Izeb, Izeh, Iu15, Ii15, Ic15")))]
""
{
HOST_WIDE_INT mask = INTVAL (operands[2]);
@@ -585,9 +585,9 @@
;; For V3/V3M ISA, we have 'or33' instruction.
;; So we can identify 'or Rt3,Rt3,Ra3' case and set its length to be 2.
(define_insn "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "= w, r, r, r")
- (ior:SI (match_operand:SI 1 "register_operand" " %0, r, r, r")
- (match_operand:SI 2 "general_operand" " w, r, Iu15, Ie15")))]
+ [(set (match_operand:SI 0 "register_operand" "=w, r, r, r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0, r, r, r")
+ (match_operand:SI 2 "general_operand" " w, r, Iu15, Ie15")))]
""
{
int one_position;
@@ -645,9 +645,9 @@
;; For V3/V3M ISA, we have 'xor33' instruction.
;; So we can identify 'xor Rt3,Rt3,Ra3' case and set its length to be 2.
(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "= w, r, r, r")
- (xor:SI (match_operand:SI 1 "register_operand" " %0, r, r, r")
- (match_operand:SI 2 "general_operand" " w, r, Iu15, It15")))]
+ [(set (match_operand:SI 0 "register_operand" "=w, r, r, r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0, r, r, r")
+ (match_operand:SI 2 "general_operand" " w, r, Iu15, It15")))]
""
{
int one_position;
@@ -1902,7 +1902,8 @@ create_template:
(define_expand "call"
[(parallel [(call (match_operand 0 "memory_operand" "")
(match_operand 1))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
""
)
@@ -1910,7 +1911,8 @@ create_template:
(define_insn "*call_register"
[(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r"))
(match_operand 1))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
"@
jral5\t%0
@@ -1921,11 +1923,20 @@ create_template:
(define_insn "*call_immediate"
[(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
(match_operand 1))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
- "jal\t%0"
+{
+ if (TARGET_CMODEL_LARGE)
+ return "bal\t%0";
+ else
+ return "jal\t%0";
+}
[(set_attr "type" "branch")
- (set_attr "length" "4")])
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_CMODEL_LARGE")
+ (const_int 12)
+ (const_int 4)))])
;; Subroutine call instruction returning a value.
@@ -1938,7 +1949,8 @@ create_template:
[(parallel [(set (match_operand 0)
(call (match_operand 1 "memory_operand" "")
(match_operand 2)))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
""
)
@@ -1947,7 +1959,8 @@ create_template:
[(parallel [(set (match_operand 0)
(call (mem (match_operand:SI 1 "register_operand" "r, r"))
(match_operand 2)))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
"@
jral5\t%1
@@ -1959,20 +1972,129 @@ create_template:
[(parallel [(set (match_operand 0)
(call (mem (match_operand:SI 1 "immediate_operand" "i"))
(match_operand 2)))
- (clobber (reg:SI LP_REGNUM))])]
+ (clobber (reg:SI LP_REGNUM))
+ (clobber (reg:SI TA_REGNUM))])]
""
- "jal\t%1"
+{
+ if (TARGET_CMODEL_LARGE)
+ return "bal\t%1";
+ else
+ return "jal\t%1";
+}
[(set_attr "type" "branch")
- (set_attr "length" "4")])
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_CMODEL_LARGE")
+ (const_int 12)
+ (const_int 4)))])
+
+
+;; ----------------------------------------------------------------------------
+
+;; The sibcall patterns.
+;; sibcall
+;; sibcall_register
+;; sibcall_immediate
+
+(define_expand "sibcall"
+ [(parallel [(call (match_operand 0 "memory_operand" "")
+ (const_int 0))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+ ""
+)
+
+(define_insn "*sibcall_register"
+ [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r"))
+ (match_operand 1))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+ "@
+ jr5\t%0
+ jr\t%0"
+ [(set_attr "type" "branch,branch")
+ (set_attr "length" " 2, 4")])
+
+(define_insn "*sibcall_immediate"
+ [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
+ (match_operand 1))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+{
+ if (TARGET_CMODEL_LARGE)
+ return "b\t%0";
+ else
+ return "j\t%0";
+}
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_CMODEL_LARGE")
+ (const_int 12)
+ (const_int 4)))])
+
+;; sibcall_value
+;; sibcall_value_register
+;; sibcall_value_immediate
+
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0)
+ (call (match_operand 1 "memory_operand" "")
+ (const_int 0)))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+ ""
+)
+
+(define_insn "*sibcall_value_register"
+ [(parallel [(set (match_operand 0)
+ (call (mem (match_operand:SI 1 "register_operand" "r, r"))
+ (match_operand 2)))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+ "@
+ jr5\t%1
+ jr\t%1"
+ [(set_attr "type" "branch,branch")
+ (set_attr "length" " 2, 4")])
+
+(define_insn "*sibcall_value_immediate"
+ [(parallel [(set (match_operand 0)
+ (call (mem (match_operand:SI 1 "immediate_operand" "i"))
+ (match_operand 2)))
+ (clobber (reg:SI TA_REGNUM))
+ (return)])]
+ ""
+{
+ if (TARGET_CMODEL_LARGE)
+ return "b\t%1";
+ else
+ return "j\t%1";
+}
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_CMODEL_LARGE")
+ (const_int 12)
+ (const_int 4)))])
+
+
+;; ----------------------------------------------------------------------------
;; prologue and epilogue.
(define_expand "prologue" [(const_int 0)]
""
{
- /* Note that only under V3/V3M ISA, we could use v3push prologue. */
- if (TARGET_V3PUSH)
+ /* Note that only under V3/V3M ISA, we could use v3push prologue.
+ In addition, we do not want to use v3push for isr function
+ and variadic function. */
+ if (TARGET_V3PUSH
+ && !nds32_isr_function_p (current_function_decl)
+ && (cfun->machine->va_args_size == 0))
nds32_expand_prologue_v3push ();
else
nds32_expand_prologue ();
@@ -1982,11 +2104,29 @@ create_template:
(define_expand "epilogue" [(const_int 0)]
""
{
- /* Note that only under V3/V3M ISA, we could use v3pop epilogue. */
- if (TARGET_V3PUSH)
- nds32_expand_epilogue_v3pop ();
+ /* Note that only under V3/V3M ISA, we could use v3pop epilogue.
+ In addition, we do not want to use v3pop for isr function
+ and variadic function. */
+ if (TARGET_V3PUSH
+ && !nds32_isr_function_p (current_function_decl)
+ && (cfun->machine->va_args_size == 0))
+ nds32_expand_epilogue_v3pop (false);
+ else
+ nds32_expand_epilogue (false);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue" [(const_int 0)]
+ ""
+{
+ /* Pass true to indicate that this is sibcall epilogue and
+ exit from a function without the final branch back to the
+ calling function. */
+ if (TARGET_V3PUSH && !nds32_isr_function_p (current_function_decl))
+ nds32_expand_epilogue_v3pop (true);
else
- nds32_expand_epilogue ();
+ nds32_expand_epilogue (true);
+
DONE;
})
@@ -2025,12 +2165,14 @@ create_template:
])]
""
{
- return nds32_output_stack_push ();
+ return nds32_output_stack_push (operands[0]);
}
[(set_attr "type" "misc")
(set_attr "enabled" "1")
(set (attr "length")
- (if_then_else (match_test "TARGET_V3PUSH")
+ (if_then_else (match_test "TARGET_V3PUSH
+ && !nds32_isr_function_p (cfun->decl)
+ && (cfun->machine->va_args_size == 0)")
(const_int 2)
(const_int 4)))])
@@ -2045,28 +2187,40 @@ create_template:
])]
""
{
- return nds32_output_stack_pop ();
+ return nds32_output_stack_pop (operands[0]);
}
[(set_attr "type" "misc")
(set_attr "enabled" "1")
(set (attr "length")
- (if_then_else (match_test "TARGET_V3PUSH")
+ (if_then_else (match_test "TARGET_V3PUSH
+ && !nds32_isr_function_p (cfun->decl)
+ && (cfun->machine->va_args_size == 0)")
(const_int 2)
(const_int 4)))])
;; ----------------------------------------------------------------------------
-;; unspec operation patterns
+;; Return operation patterns
;; ----------------------------------------------------------------------------
-;; In nds32 target, the 'ret5' instuction is actually 'jr5 $lp'.
-;; This pattern is designed to distinguish function return
-;; from general indirect_jump pattern so that we can directly
-;; generate 'ret5' for readability.
+;; Use this pattern to expand a return instruction
+;; with simple_return rtx if no epilogue is required.
+(define_expand "return"
+ [(simple_return)]
+ "nds32_can_use_return_insn ()"
+ ""
+)
-(define_insn "unspec_volatile_func_return"
- [(set (pc)
- (unspec_volatile:SI [(reg:SI LP_REGNUM)] UNSPEC_VOLATILE_FUNC_RETURN))]
+;; This pattern is expanded only by the shrink-wrapping optimization
+;; on paths where the function prologue has not been executed.
+(define_expand "simple_return"
+ [(simple_return)]
+ ""
+ ""
+)
+
+(define_insn "return_internal"
+ [(simple_return)]
""
{
if (TARGET_16_BIT)
@@ -2074,7 +2228,7 @@ create_template:
else
return "ret";
}
- [(set_attr "type" "misc")
+ [(set_attr "type" "branch")
(set_attr "enabled" "1")
(set (attr "length")
(if_then_else (match_test "TARGET_16_BIT")
@@ -2166,7 +2320,7 @@ create_template:
(const_int 4))
(label_ref (match_operand 1 "" "")))))
(use (label_ref (match_dup 1)))
- (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=r"))
(clobber (reg:SI TA_REGNUM))])]
""
{
@@ -2219,3 +2373,15 @@ create_template:
(set_attr "length" "4")])
;; ----------------------------------------------------------------------------
+
+;; Pseudo NOPs
+
+(define_insn "pop25return"
+ [(return)
+ (unspec_volatile:SI [(reg:SI LP_REGNUM)] UNSPEC_VOLATILE_POP25_RETURN)]
+ ""
+ "! return for pop 25"
+ [(set_attr "length" "0")]
+)
+
+;; ----------------------------------------------------------------------------
diff --git a/gcc/config/nds32/nds32.opt b/gcc/config/nds32/nds32.opt
index 4974f3b867b..0d573daa548 100644
--- a/gcc/config/nds32/nds32.opt
+++ b/gcc/config/nds32/nds32.opt
@@ -1,5 +1,5 @@
; Options of Andes NDS32 cpu for GNU compiler
-; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+; Copyright (C) 2012-2015 Free Software Foundation, Inc.
; Contributed by Andes Technology Corporation.
;
; This file is part of GCC.
@@ -53,10 +53,6 @@ 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 RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE)
Specify the size of each interrupt vector, which must be 4 or 16.
@@ -71,6 +67,7 @@ Specify the name of the target architecture.
Enum
Name(nds32_arch_type) Type(enum nds32_arch_type)
+Known arch types (for use with the -march= option):
EnumValue
Enum(nds32_arch_type) String(v2) Value(ARCH_V2)
@@ -81,17 +78,22 @@ 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 Mask(FORCE_FP_AS_GP)
-Prevent $fp being allocated during register allocation so that compiler is able to force performing fp-as-gp optimization.
+mcmodel=
+Target RejectNegative Joined Enum(nds32_cmodel_type) Var(nds32_cmodel_option) Init(CMODEL_MEDIUM)
+Specify the address generation strategy for code model.
+
+Enum
+Name(nds32_cmodel_type) Type(enum nds32_cmodel_type)
+Known cmodel types (for use with the -mcmodel= option):
-mforbid-fp-as-gp
-Target Report 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'.
+EnumValue
+Enum(nds32_cmodel_type) String(small) Value(CMODEL_SMALL)
-mex9
-Target Report Mask(EX9)
-Use special directives to guide linker doing ex9 optimization.
+EnumValue
+Enum(nds32_cmodel_type) String(medium) Value(CMODEL_MEDIUM)
+
+EnumValue
+Enum(nds32_cmodel_type) String(large) Value(CMODEL_LARGE)
mctor-dtor
Target Report
diff --git a/gcc/config/nds32/nds32_intrinsic.h b/gcc/config/nds32/nds32_intrinsic.h
index 3908051f726..5993eadc142 100644
--- a/gcc/config/nds32/nds32_intrinsic.h
+++ b/gcc/config/nds32/nds32_intrinsic.h
@@ -1,5 +1,5 @@
/* Intrinsic definitions of Andes NDS32 cpu for GNU compiler
- Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Copyright (C) 2012-2015 Free Software Foundation, Inc.
Contributed by Andes Technology Corporation.
This file is part of GCC.
diff --git a/gcc/config/nds32/pipelines.md b/gcc/config/nds32/pipelines.md
index 18cee9b5672..cf017358180 100644
--- a/gcc/config/nds32/pipelines.md
+++ b/gcc/config/nds32/pipelines.md
@@ -1,5 +1,5 @@
;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
diff --git a/gcc/config/nds32/predicates.md b/gcc/config/nds32/predicates.md
index 0a40d68b8cf..6ee1a06ab80 100644
--- a/gcc/config/nds32/predicates.md
+++ b/gcc/config/nds32/predicates.md
@@ -1,5 +1,5 @@
;; Predicate definitions of Andes NDS32 cpu for GNU compiler
-;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
;; Contributed by Andes Technology Corporation.
;;
;; This file is part of GCC.
@@ -77,16 +77,16 @@
(match_code "parallel")
{
/* To verify 'push' operation, pass 'true' for the second argument.
- See the implementation in nds32.c for details. */
- return nds32_valid_stack_push_pop (op, true);
+ See the implementation in nds32-predicates.c for details. */
+ return nds32_valid_stack_push_pop_p (op, true);
})
(define_special_predicate "nds32_stack_pop_operation"
(match_code "parallel")
{
/* To verify 'pop' operation, pass 'false' for the second argument.
- See the implementation in nds32.c for details. */
- return nds32_valid_stack_push_pop (op, false);
+ See the implementation in nds32-predicates.c for details. */
+ return nds32_valid_stack_push_pop_p (op, false);
})
;; ------------------------------------------------------------------------
diff --git a/gcc/config/nds32/t-mlibs b/gcc/config/nds32/t-mlibs
index 199ee3129c8..d9e5ba4b952 100644
--- a/gcc/config/nds32/t-mlibs
+++ b/gcc/config/nds32/t-mlibs
@@ -1,5 +1,5 @@
# The multilib settings of Andes NDS32 cpu for GNU compiler
-# Copyright (C) 2012-2014 Free Software Foundation, Inc.
+# Copyright (C) 2012-2015 Free Software Foundation, Inc.
# Contributed by Andes Technology Corporation.
#
# This file is part of GCC.
@@ -18,21 +18,9 @@
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
-# We need to build following multilibs combinations:
-#
-# 1. <None multilibs>
-# 2. -mlittle-endian
-# 3. -mbig-endian
-# 4. -mgp-direct
-# 5. -mno-gp-direct
-# 6. -mlittle-endian -mgp-direct
-# 7. -mlittle-endian -mno-gp-direct
-# 8. -mbig-endian -mgp-direct
-# 9. -mbig-endian -mno-gp-direct
-#
# 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 mgp-direct/mno-gp-direct
+MULTILIB_OPTIONS = mcmodel=small/mcmodel=medium/mcmodel=large
# ------------------------------------------------------------------------
diff --git a/gcc/config/nds32/t-nds32 b/gcc/config/nds32/t-nds32
new file mode 100644
index 00000000000..ea36cc71b64
--- /dev/null
+++ b/gcc/config/nds32/t-nds32
@@ -0,0 +1,51 @@
+# General rules that all nds32/ targets must have.
+# Copyright (C) 2012-2015 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
+# <http://www.gnu.org/licenses/>.
+
+nds32-cost.o: $(srcdir)/config/nds32/nds32-cost.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-intrinsic.o: $(srcdir)/config/nds32/nds32-intrinsic.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-isr.o: $(srcdir)/config/nds32/nds32-isr.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-md-auxiliary.o: $(srcdir)/config/nds32/nds32-md-auxiliary.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-pipelines-auxiliary.o: $(srcdir)/config/nds32/nds32-pipelines-auxiliary.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-predicates.o: $(srcdir)/config/nds32/nds32-predicates.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-memory-manipulation.o: $(srcdir)/config/nds32/nds32-memory-manipulation.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+nds32-fp-as-gp.o: $(srcdir)/config/nds32/nds32-fp-as-gp.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)