[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 <kito.cheng@gmail.com>
Co-Authored-By: Kuan-Lin Chen <kuanlinchentw@gmail.com>

From-SVN: r258998
This commit is contained in:
Chung-Ju Wu 2018-04-01 10:07:40 +00:00 committed by Chung-Ju Wu
parent af08e51d09
commit c4d8d0502e
10 changed files with 447 additions and 4 deletions

View 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.

View 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

View file

@ -53,6 +53,8 @@
UNSPEC_VOLATILE_MTUSR
UNSPEC_VOLATILE_SETGIE_EN
UNSPEC_VOLATILE_SETGIE_DIS
UNSPEC_VOLATILE_RELAX_GROUP
UNSPEC_VOLATILE_POP25_RETURN
])

View 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;
}
/* ------------------------------------------------------------------------ */

View 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 *);
/* ------------------------------------------------------------------------ */

View file

@ -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);
}

View 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 ();
}

View file

@ -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)]

View 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.

View 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