From c4d8d0502ef162362e3fcb2fd249ce92b2fd031d Mon Sep 17 00:00:00 2001 From: Chung-Ju Wu Date: Sun, 1 Apr 2018 10:07:40 +0000 Subject: [PATCH] [NDS32] Add relax optimization as new pass. 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 Co-Authored-By: Kuan-Lin Chen From-SVN: r258998 --- gcc/ChangeLog | 20 ++ gcc/config.gcc | 2 +- gcc/config/nds32/constants.md | 2 + gcc/config/nds32/nds32-predicates.c | 34 +++ gcc/config/nds32/nds32-protos.h | 5 + gcc/config/nds32/nds32-relax-opt.c | 324 ++++++++++++++++++++++++++++ gcc/config/nds32/nds32.c | 34 +++ gcc/config/nds32/nds32.md | 13 +- gcc/config/nds32/nds32.opt | 4 + gcc/config/nds32/t-nds32 | 13 ++ 10 files changed, 447 insertions(+), 4 deletions(-) create mode 100644 gcc/config/nds32/nds32-relax-opt.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 41b0da5a566..29c82d92faa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2018-04-01 Chung-Ju Wu + Kito Cheng + Kuan-Lin Chen + + * 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 * config/nds32/t-nds32: Modify files dependency. diff --git a/gcc/config.gcc b/gcc/config.gcc index 1b58c060a92..b8a9877b432 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -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 diff --git a/gcc/config/nds32/constants.md b/gcc/config/nds32/constants.md index 482e39ecfba..77fb71c3420 100644 --- a/gcc/config/nds32/constants.md +++ b/gcc/config/nds32/constants.md @@ -53,6 +53,8 @@ UNSPEC_VOLATILE_MTUSR UNSPEC_VOLATILE_SETGIE_EN UNSPEC_VOLATILE_SETGIE_DIS + + UNSPEC_VOLATILE_RELAX_GROUP UNSPEC_VOLATILE_POP25_RETURN ]) diff --git a/gcc/config/nds32/nds32-predicates.c b/gcc/config/nds32/nds32-predicates.c index c54eefba027..c313efcb831 100644 --- a/gcc/config/nds32/nds32-predicates.c +++ b/gcc/config/nds32/nds32-predicates.c @@ -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; +} /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index 61105001c72..1387cca62ea 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -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 index 00000000000..0349be4725d --- /dev/null +++ b/gcc/config/nds32/nds32-relax-opt.c @@ -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 + . */ + +/* ------------------------------------------------------------------------ */ + +#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); +} diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index f405ea13e9e..bdbff14109b 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -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 (); } diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index 58a13c1abfd..e9bd7914eff 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -179,7 +179,7 @@ ;; 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"))] "" @@ -188,7 +188,7 @@ (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")))] "" @@ -197,7 +197,7 @@ (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)] diff --git a/gcc/config/nds32/nds32.opt b/gcc/config/nds32/nds32.opt index 876e8411f06..d6d2f20dbac 100644 --- a/gcc/config/nds32/nds32.opt +++ b/gcc/config/nds32/nds32.opt @@ -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. diff --git a/gcc/config/nds32/t-nds32 b/gcc/config/nds32/t-nds32 index e2055adfafd..0f1c3857c2a 100644 --- a/gcc/config/nds32/t-nds32 +++ b/gcc/config/nds32/t-nds32 @@ -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 -- 2.30.2