[NDS32] Add relax optimization as new pass.
authorChung-Ju Wu <jasonwucj@gmail.com>
Sun, 1 Apr 2018 10:07:40 +0000 (10:07 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Sun, 1 Apr 2018 10:07:40 +0000 (10:07 +0000)
gcc/
* config.gcc (nds32): Add nds32-relax-opt.o into extra_objs.
* config/nds32/constants.md (unspec_volatile_element): Add
UNSPEC_VOLATILE_RELAX_GROUP.
* config/nds32/nds32-relax-opt.c: New file.
* config/nds32/nds32-predicates.c
(nds32_symbol_load_store_p): New function.
* config/nds32/nds32-protos.h
(nds32_symbol_load_store_p): Declare function.
(make_pass_nds32_relax_opt): Declare new rtl pass function.
* config/nds32/nds32.c
(nds32_register_pass): New function to register pass.
(nds32_register_passes): New function to register passes.
* config/nds32/nds32.md (relax_group): New pattern.
* config/nds32/nds32.opt (mrelax-hint): New option.
* config/nds32/t-nds32 (nds32-relax-opt.o): New dependency.

Co-Authored-By: Kito Cheng <kito.cheng@gmail.com>
Co-Authored-By: Kuan-Lin Chen <kuanlinchentw@gmail.com>
From-SVN: r258998

gcc/ChangeLog
gcc/config.gcc
gcc/config/nds32/constants.md
gcc/config/nds32/nds32-predicates.c
gcc/config/nds32/nds32-protos.h
gcc/config/nds32/nds32-relax-opt.c [new file with mode: 0644]
gcc/config/nds32/nds32.c
gcc/config/nds32/nds32.md
gcc/config/nds32/nds32.opt
gcc/config/nds32/t-nds32

index 41b0da5a566a96b681e3de122f402cbc98947835..29c82d92faa30fdea1e3bb1343b2ce2dc3f8a1cd 100644 (file)
@@ -1,3 +1,23 @@
+2018-04-01  Chung-Ju Wu  <jasonwucj@gmail.com>
+           Kito Cheng  <kito.cheng@gmail.com>
+           Kuan-Lin Chen <kuanlinchentw@gmail.com>
+
+       * config.gcc (nds32): Add nds32-relax-opt.o into extra_objs.
+       * config/nds32/constants.md (unspec_volatile_element): Add
+       UNSPEC_VOLATILE_RELAX_GROUP.
+       * config/nds32/nds32-relax-opt.c: New file.
+       * config/nds32/nds32-predicates.c
+       (nds32_symbol_load_store_p): New function.
+       * config/nds32/nds32-protos.h
+       (nds32_symbol_load_store_p): Declare function.
+       (make_pass_nds32_relax_opt): Declare new rtl pass function.
+       * config/nds32/nds32.c
+       (nds32_register_pass): New function to register pass.
+       (nds32_register_passes): New function to register passes.
+       * config/nds32/nds32.md (relax_group): New pattern.
+       * config/nds32/nds32.opt (mrelax-hint): New option.
+       * config/nds32/t-nds32 (nds32-relax-opt.o): New dependency.
+
 2018-04-01  Kito Cheng  <kito.cheng@gmail.com>
 
        * config/nds32/t-nds32: Modify files dependency.
index 1b58c060a927444d0d0c5f62ba2ff255624bb4d1..b8a9877b432420e21100cfe55378a0ace267729b 100644 (file)
@@ -445,7 +445,7 @@ mips*-*-*)
 nds32*)
        cpu_type=nds32
        extra_headers="nds32_intrinsic.h"
-       extra_objs="nds32-cost.o nds32-intrinsic.o nds32-isr.o nds32-md-auxiliary.o nds32-pipelines-auxiliary.o nds32-predicates.o nds32-memory-manipulation.o nds32-fp-as-gp.o"
+       extra_objs="nds32-cost.o nds32-intrinsic.o nds32-isr.o nds32-md-auxiliary.o nds32-pipelines-auxiliary.o nds32-predicates.o nds32-memory-manipulation.o nds32-fp-as-gp.o nds32-relax-opt.o"
        ;;
 nios2-*-*)
        cpu_type=nios2
index 482e39ecfbaca56a15efd9e8fffdaf71f4c711df..77fb71c34200cc045f3273d5bbfe6375012921b1 100644 (file)
@@ -53,6 +53,8 @@
   UNSPEC_VOLATILE_MTUSR
   UNSPEC_VOLATILE_SETGIE_EN
   UNSPEC_VOLATILE_SETGIE_DIS
+
+  UNSPEC_VOLATILE_RELAX_GROUP
   UNSPEC_VOLATILE_POP25_RETURN
 ])
 
index c54eefba027d9d35f073b801aac16d83e66d1151..c313efcb83199c40d9f373e16bf4baf84a8bf35a 100644 (file)
@@ -35,6 +35,7 @@
 #include "emit-rtl.h"
 #include "recog.h"
 #include "tm-constrs.h"
+#include "insn-attr.h"
 
 /* ------------------------------------------------------------------------ */
 
@@ -414,4 +415,37 @@ nds32_can_use_bitci_p (int ival)
          && 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 *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;
+}
 /* ------------------------------------------------------------------------ */
index 61105001c72061d2d7224c026438c908d6c57fa8..1387cca62ea643e4e242c6152c28dd13a226ad8e 100644 (file)
@@ -109,6 +109,8 @@ extern int nds32_adjust_insn_length (rtx_insn *, int);
 
 extern int nds32_fp_as_gp_check_available (void);
 
+extern bool nds32_symbol_load_store_p (rtx_insn *);
+
 /* Auxiliary functions for jump table generation.  */
 
 extern const char *nds32_output_casesi_pc_relative (rtx *);
@@ -164,4 +166,7 @@ extern int nds32_address_cost_impl (rtx, machine_mode, addr_space_t, bool);
 /* Auxiliary functions for pre-define marco.  */
 extern void nds32_cpu_cpp_builtins(struct cpp_reader *);
 
+/* Functions for create nds32 specific optimization pass.  */
+extern rtl_opt_pass *make_pass_nds32_relax_opt (gcc::context *);
+
 /* ------------------------------------------------------------------------ */
diff --git a/gcc/config/nds32/nds32-relax-opt.c b/gcc/config/nds32/nds32-relax-opt.c
new file mode 100644 (file)
index 0000000..0349be4
--- /dev/null
@@ -0,0 +1,324 @@
+/* relax-opt pass of Andes NDS32 cpu for GNU compiler
+   Copyright (C) 2012-2018 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/>.  */
+
+/* ------------------------------------------------------------------------ */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "optabs.h"            /* For GEN_FCN.  */
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "output.h"
+#include "explow.h"
+#include "expr.h"
+#include "tm-constrs.h"
+#include "builtins.h"
+#include "cpplib.h"
+#include "insn-attr.h"
+#include "cfgrtl.h"
+#include "tree-pass.h"
+
+/* This is used to create unique relax hint id value.
+   The initial value is 0.  */
+static int relax_group_id = 0;
+
+/* Group the following pattern as relax candidates:
+
+   1. sethi    $ra, hi20(sym)
+      ori      $ra, $ra, lo12(sym)
+    ==>
+      addi.gp  $ra, sym
+
+   2. sethi    $ra, hi20(sym)
+      lwi      $rb, [$ra + lo12(sym)]
+    ==>
+      lwi.gp   $rb, [(sym)]
+
+   3. sethi    $ra, hi20(sym)
+      ori      $ra, $ra, lo12(sym)
+      lwi      $rb, [$ra]
+      swi      $rc, [$ra]
+    ==>
+      lwi37    $rb, [(sym)]
+      swi37    $rc, [(sym)] */
+
+/* Return true if is load/store with REG addressing mode
+   and memory mode is SImode.  */
+static bool
+nds32_reg_base_load_store_p (rtx_insn *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 REG.  */
+  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)) == REG)
+       return true;
+    }
+
+  return false;
+}
+
+/* Return true if insn is a sp/fp base or sp/fp plus load-store instruction.  */
+
+static bool
+nds32_sp_base_or_plus_load_store_p (rtx_insn *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 REG.  */
+  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)) == PLUS))
+       mem_src = XEXP (mem_src, 0);
+
+      if (REG_P (XEXP (mem_src, 0))
+         && ((frame_pointer_needed
+              && REGNO (XEXP (mem_src, 0)) == FP_REGNUM)
+             || REGNO (XEXP (mem_src, 0)) == SP_REGNUM))
+       return true;
+    }
+
+  return false;
+}
+
+/* Return true if is load with [REG + REG/CONST_INT]  addressing mode.  */
+static bool
+nds32_plus_reg_load_store_p (rtx_insn *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 [REG + REG/CONST].  */
+  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)) == PLUS))
+       mem_src = XEXP (mem_src, 0);
+      else
+       return false;
+
+      if (GET_CODE (XEXP (mem_src, 0)) == REG)
+       return true;
+
+    }
+
+  return false;
+}
+
+/* Group the relax candidates with group id.  */
+static void
+nds32_group_insns (rtx sethi)
+{
+  df_ref def_record, use_record;
+  df_link *link;
+  rtx_insn *use_insn = NULL;
+  rtx group_id;
+
+  def_record = DF_INSN_DEFS (sethi);
+
+  for (link = DF_REF_CHAIN (def_record); link; link = link->next)
+    {
+      if (!DF_REF_INSN_INFO (link->ref))
+       continue;
+
+      use_insn = DF_REF_INSN (link->ref);
+
+      /* Skip if define insn and use insn not in the same basic block.  */
+      if (!dominated_by_p (CDI_DOMINATORS,
+                          BLOCK_FOR_INSN (use_insn),
+                          BLOCK_FOR_INSN (sethi)))
+       return;
+
+      /* Skip if the low-part used register is from different high-part
+        instructions.  */
+      use_record = DF_INSN_USES (use_insn);
+      if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next)
+       return;
+
+      /* Skip if use_insn not active insn.  */
+      if (!active_insn_p (use_insn))
+       return;
+
+     /* Initial use_insn_type.  */
+      if (!(recog_memoized (use_insn) == CODE_FOR_lo_sum
+           || nds32_symbol_load_store_p (use_insn)
+           || (nds32_reg_base_load_store_p (use_insn)
+               &&!nds32_sp_base_or_plus_load_store_p (use_insn))))
+       return;
+    }
+
+  group_id = GEN_INT (relax_group_id);
+  /* Insert .relax_* directive for sethi.  */
+  emit_insn_before (gen_relax_group (group_id), sethi);
+
+  /* Scan the use insns and insert the directive.  */
+  for (link = DF_REF_CHAIN (def_record); link; link = link->next)
+    {
+      if (!DF_REF_INSN_INFO (link->ref))
+       continue;
+
+      use_insn = DF_REF_INSN (link->ref);
+
+      /* Insert .relax_* directive.  */
+      if (active_insn_p (use_insn))
+       emit_insn_before (gen_relax_group (group_id), use_insn);
+    }
+
+  relax_group_id++;
+}
+
+/* Group the relax candidate instructions for linker.  */
+static void
+nds32_relax_group (void)
+{
+  rtx_insn *insn;
+
+  compute_bb_for_insn ();
+
+  df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
+  df_insn_rescan_all ();
+  df_analyze ();
+  df_set_flags (DF_DEFER_INSN_RESCAN);
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  insn = get_insns ();
+  gcc_assert (NOTE_P (insn));
+
+  for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn))
+    {
+      if (NONJUMP_INSN_P (insn))
+       {
+         /* Find sethi ra, symbol  instruction.  */
+         if (recog_memoized (insn) == CODE_FOR_sethi
+             && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0),
+                                        SImode))
+           nds32_group_insns (insn);
+       }
+    }
+
+  /* We must call df_finish_pass manually because it should be invoked before
+     BB information is destroyed. Hence we cannot set the TODO_df_finish flag
+     to the pass manager.  */
+  df_insn_rescan_all ();
+  df_finish_pass (false);
+  free_dominance_info (CDI_DOMINATORS);
+}
+
+static unsigned int
+nds32_relax_opt (void)
+{
+  if (TARGET_RELAX_HINT)
+    nds32_relax_group ();
+  return 1;
+}
+
+const pass_data pass_data_nds32_relax_opt =
+{
+  RTL_PASS,                            /* type */
+  "relax_opt",                         /* name */
+  OPTGROUP_NONE,                       /* optinfo_flags */
+  TV_MACH_DEP,                         /* tv_id */
+  0,                                   /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_df_finish,                      /* todo_flags_finish */
+};
+
+class pass_nds32_relax_opt : public rtl_opt_pass
+{
+public:
+  pass_nds32_relax_opt (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *) { return TARGET_RELAX_HINT; }
+  unsigned int execute (function *) { return nds32_relax_opt (); }
+};
+
+rtl_opt_pass *
+make_pass_nds32_relax_opt (gcc::context *ctxt)
+{
+  return new pass_nds32_relax_opt (ctxt);
+}
index f405ea13e9ea8921d5c46bd800028af51f29ce68..bdbff14109b4ac328a76fc142bba4ef30f4dafda 100644 (file)
@@ -29,6 +29,7 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tree-pass.h"
 #include "stringpool.h"
 #include "attribs.h"
 #include "df.h"
@@ -48,6 +49,7 @@
 #include "tm-constrs.h"
 #include "builtins.h"
 #include "cpplib.h"
+#include "context.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -1227,6 +1229,36 @@ nds32_legitimate_index_p (machine_mode outer_mode,
     }
 }
 
+static void
+nds32_register_pass (
+  rtl_opt_pass *(*make_pass_func) (gcc::context *),
+  enum pass_positioning_ops pass_pos,
+  const char *ref_pass_name)
+{
+  opt_pass *new_opt_pass = make_pass_func (g);
+
+  struct register_pass_info insert_pass =
+    {
+      new_opt_pass,    /* pass */
+      ref_pass_name,   /* reference_pass_name */
+      1,               /* ref_pass_instance_number */
+      pass_pos         /* po_op */
+    };
+
+  register_pass (&insert_pass);
+}
+
+/* This function is called from nds32_option_override ().
+   All new passes should be registered here.  */
+static void
+nds32_register_passes (void)
+{
+  nds32_register_pass (
+    make_pass_nds32_relax_opt,
+    PASS_POS_INSERT_AFTER,
+    "mach");
+}
+
 /* ------------------------------------------------------------------------ */
 
 /* PART 3: Implement target hook stuff definitions.  */
@@ -2776,6 +2808,8 @@ nds32_option_override (void)
   /* Currently, we don't support PIC code generation yet.  */
   if (flag_pic)
     sorry ("position-independent code not supported");
+
+  nds32_register_passes ();
 }
 
 \f
index 58a13c1abfd83227c44540e872ed75146865892d..e9bd7914effbcfe7d02fe8ec8d16450606c5a2fb 100644 (file)
 
 ;; We use nds32_symbolic_operand to limit that only CONST/SYMBOL_REF/LABEL_REF
 ;; are able to match such instruction template.
-(define_insn "*move_addr"
+(define_insn "move_addr"
   [(set (match_operand:SI 0 "register_operand"       "=l, r")
        (match_operand:SI 1 "nds32_symbolic_operand" " i, i"))]
   ""
    (set_attr "length"  "8")])
 
 
-(define_insn "*sethi"
+(define_insn "sethi"
   [(set (match_operand:SI 0 "register_operand"                "=r")
        (high:SI (match_operand:SI 1 "nds32_symbolic_operand" " i")))]
   ""
    (set_attr "length" "4")])
 
 
-(define_insn "*lo_sum"
+(define_insn "lo_sum"
   [(set (match_operand:SI 0 "register_operand"                  "=r")
        (lo_sum:SI (match_operand:SI 1 "register_operand"       " r")
                   (match_operand:SI 2 "nds32_symbolic_operand" " i")))]
@@ -2370,6 +2370,13 @@ create_template:
 
 ;; Pseudo NOPs
 
+(define_insn "relax_group"
+  [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_RELAX_GROUP)]
+  ""
+  ".relax_hint %0"
+  [(set_attr "length" "0")]
+)
+
 (define_insn "pop25return"
   [(return)
    (unspec_volatile:SI [(reg:SI LP_REGNUM)] UNSPEC_VOLATILE_POP25_RETURN)]
index 876e8411f06ba578c065146bf78d9058e5f72804..d6d2f20dbacd0372f8ef55348d19c292c24cea7d 100644 (file)
@@ -77,6 +77,10 @@ m16-bit
 Target Report Mask(16_BIT)
 Generate 16-bit instructions.
 
+mrelax-hint
+Target Report Mask(RELAX_HINT)
+Insert relax hint for linker to do relaxation.
+
 mvh
 Target Report Mask(VH)
 Enable Virtual Hosting support.
index e2055adfafda18b1dc4a0c8abd3efd9e5f0af9f1..0f1c3857c2a57a250dd78b377c5eff7baa0a52c4 100644 (file)
@@ -118,3 +118,16 @@ nds32-fp-as-gp.o: \
   intl.h libfuncs.h $(PARAMS_H) $(OPTS_H)
        $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
                $(srcdir)/config/nds32/nds32-fp-as-gp.c
+
+nds32-relax-opt.o: \
+  $(srcdir)/config/nds32/nds32-relax-opt.c \
+  $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+  $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \
+  insn-config.h conditions.h output.h dumpfile.h \
+  $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \
+  $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \
+  $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \
+  $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \
+  intl.h libfuncs.h $(PARAMS_H) $(OPTS_H)
+       $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+               $(srcdir)/config/nds32/nds32-relax-opt.c