Commit b99353a2 by Kito Cheng Committed by Chung-Ju Wu

[NDS32] Implment n9 pipeline.

gcc/
	* config.gcc (nds32*): Add nds32-utils.o into extra_objs.
	* config/nds32/nds32-n9-2r1w.md: New file.
	* config/nds32/nds32-n9-3r2w.md: New file.
	* config/nds32/nds32-opts.h (nds32_cpu_type, nds32_mul_type,
	nds32_register_ports): New or modify for cpu n9.
	* config/nds32/nds32-pipelines-auxiliary.c: Implementation for n9
	pipeline.
	* config/nds32/nds32-protos.h: More declarations for n9 pipeline.
	* config/nds32/nds32-utils.c: New file.
	* config/nds32/nds32.h (TARGET_PIPELINE_N9, TARGET_PIPELINE_SIMPLE,
	TARGET_MUL_SLOW): Define.
	* config/nds32/nds32.md (pipeline_model): New attribute.
	* config/nds32/nds32.opt (mcpu, mconfig-mul, mconfig-register-ports):
	New options that support cpu n9.
	* config/nds32/pipelines.md: Include n9 settings.
	* config/nds32/t-nds32 (nds32-utils.o): Add dependency.

Co-Authored-By: Chung-Ju Wu <jasonwucj@gmail.com>

From-SVN: r259218
parent 43fa41c1
2018-04-08 Kito Cheng <kito.cheng@gmail.com>
Chung-Ju Wu <jasonwucj@gmail.com>
* config.gcc (nds32*): Add nds32-utils.o into extra_objs.
* config/nds32/nds32-n9-2r1w.md: New file.
* config/nds32/nds32-n9-3r2w.md: New file.
* config/nds32/nds32-opts.h (nds32_cpu_type, nds32_mul_type,
nds32_register_ports): New or modify for cpu n9.
* config/nds32/nds32-pipelines-auxiliary.c: Implementation for n9
pipeline.
* config/nds32/nds32-protos.h: More declarations for n9 pipeline.
* config/nds32/nds32-utils.c: New file.
* config/nds32/nds32.h (TARGET_PIPELINE_N9, TARGET_PIPELINE_SIMPLE,
TARGET_MUL_SLOW): Define.
* config/nds32/nds32.md (pipeline_model): New attribute.
* config/nds32/nds32.opt (mcpu, mconfig-mul, mconfig-register-ports):
New options that support cpu n9.
* config/nds32/pipelines.md: Include n9 settings.
* config/nds32/t-nds32 (nds32-utils.o): Add dependency.
2018-04-08 Chung-Ju Wu <jasonwucj@gmail.com> 2018-04-08 Chung-Ju Wu <jasonwucj@gmail.com>
* config/nds32/nds32-md-auxiliary.c (output_cond_branch): Output align * config/nds32/nds32-md-auxiliary.c (output_cond_branch): Output align
......
...@@ -445,7 +445,7 @@ mips*-*-*) ...@@ -445,7 +445,7 @@ mips*-*-*)
nds32*) nds32*)
cpu_type=nds32 cpu_type=nds32
extra_headers="nds32_intrinsic.h" 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 nds32-relax-opt.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 nds32-utils.o"
;; ;;
nios2-*-*) nios2-*-*)
cpu_type=nios2 cpu_type=nios2
......
;; Pipeline descriptions 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 N9 2R1W pipeline settings.
;; ------------------------------------------------------------------------
(define_automaton "nds32_n9_2r1w_machine")
;; ------------------------------------------------------------------------
;; Pipeline Stages
;; ------------------------------------------------------------------------
;; IF - Instruction Fetch
;; II - Instruction Issue / Instruction Decode
;; EX - Instruction Execution
;; MM - Memory Execution
;; WB - Instruction Retire / Result Write-Back
(define_cpu_unit "n9_2r1w_ii" "nds32_n9_2r1w_machine")
(define_cpu_unit "n9_2r1w_ex" "nds32_n9_2r1w_machine")
(define_cpu_unit "n9_2r1w_mm" "nds32_n9_2r1w_machine")
(define_cpu_unit "n9_2r1w_wb" "nds32_n9_2r1w_machine")
(define_insn_reservation "nds_n9_2r1w_unknown" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "unknown")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_misc" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "misc")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_mmu" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "mmu")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_alu" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "alu")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_alu_shift" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "alu_shift")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_pbsad" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "pbsad")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex*3, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_pbsada" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "pbsada")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex*3, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (match_test "nds32::load_single_p (insn)")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (match_test "nds32::store_single_p (insn)")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "1"))))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(ior (and (eq_attr "type" "load_multiple")
(eq_attr "combo" "2"))
(match_test "nds32::load_double_p (insn)"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_3" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "3"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_4" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "4"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_5" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "5"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*2, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_6" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "6"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*3, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_7" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "7"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*4, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_8" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "8"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*5, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_load_multiple_12" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "12"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*9, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "1"))))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(ior (and (eq_attr "type" "store_multiple")
(eq_attr "combo" "2"))
(match_test "nds32::store_double_p (insn)"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_3" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "3"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_4" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "4"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_5" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "5"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*2, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_6" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "6"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*3, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_7" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "7"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*4, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_8" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "8"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*5, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_store_multiple_12" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "12"))))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*9, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_mul_fast" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config != MUL_TYPE_SLOW")
(and (eq_attr "type" "mul")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_mul_slow" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config == MUL_TYPE_SLOW")
(and (eq_attr "type" "mul")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex*17, n9_2r1w_mm, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_mac_fast" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config != MUL_TYPE_SLOW")
(and (eq_attr "type" "mac")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_mac_slow" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config == MUL_TYPE_SLOW")
(and (eq_attr "type" "mac")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, (n9_2r1w_ii+n9_2r1w_ex)*17, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_div" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "div")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, (n9_2r1w_ii+n9_2r1w_ex)*34, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb")
(define_insn_reservation "nds_n9_2r1w_branch" 1
(and (match_test "nds32_register_ports_config == REG_PORT_2R1W")
(and (eq_attr "type" "branch")
(eq_attr "pipeline_model" "n9")))
"n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb")
;; ------------------------------------------------------------------------
;; Comment Notations and Bypass Rules
;; ------------------------------------------------------------------------
;; Producers (LHS)
;; LD_!bi
;; Load data from the memory (without updating the base register) and
;; produce the loaded data. The result is ready at MM. Because the register
;; port is 2R1W, two micro-operations are required if the base register
;; should be updated. In this case, the base register is updated by the
;; second micro-operation, and the updated result is ready at EX.
;; LMW(N, M)
;; There are N micro-operations within an instruction that loads multiple
;; words. The result produced by the M-th micro-operation is sent to
;; consumers. The result is ready at MM. If the base register should be
;; updated, an extra micro-operation is apppended to the end of the
;; sequence, and the result is ready at EX.
;; MUL, MAC
;; Compute data in the multiply-adder and produce the data. The result
;; is ready at MM.
;; DIV
;; Compute data in the divider and produce the data. The result is ready
;; at MM.
;;
;; Consumers (RHS)
;; ALU, PBSAD, PBSADA_RaRb, MUL, MAC, DIV, MMU
;; Require operands at EX.
;; ALU_SHIFT_Rb
;; An ALU-SHIFT instruction consists of a shift micro-operation followed
;; by an arithmetic micro-operation. The operand Rb is used by the first
;; micro-operation, and there are some latencies if data dependency occurs.
;; MOVD44_E
;; A double-word move instruction needs two micro-operations because the
;; reigster ports is 2R1W. The first micro-operation writes an even number
;; register, and the second micro-operation writes an odd number register.
;; Each input operand is required at EX for each micro-operation. MOVD44_E
;; stands for the first micro-operation.
;; MAC_RaRb, M2R
;; MAC instructions do multiplication at EX and do accumulation at MM, but
;; MAC instructions which operate on general purpose registers always
;; require operands at EX because MM stage cannot be forwarded in 2R1W mode.
;; ADDR_IN
;; If an instruction requires an address as its input operand, the address
;; is required at EX.
;; ST_bi
;; A post-increment store instruction requires its data at EX because MM
;; cannot be forwarded in 2R1W mode.
;; ST_!bi_RI
;; A store instruction with an immediate offset requires its data at EX
;; because MM cannot be forwarded in 2R1W mode. If the offset field is a
;; register (ST_!bi_RR), the instruction will be separated into two micro-
;; operations, and the second one requires the input operand at EX in order
;; to store it to the memory.
;; SMW(N, M)
;; There are N micro-operations within an instruction that stores multiple
;; words. Each M-th micro-operation requires its data at MM.
;; BR
;; If a branch instruction is conditional, its input data is required at EX.
;; LD_!bi, MUL, MAC
;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44_E, MUL, MAC_RaRb, M2R, DIV, ADDR_IN_!bi, ADDR_IN_bi_Ra, ST_bi, ST_!bi_RI, BR, MMU
(define_bypass 2
"nds_n9_2r1w_load,\
nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\
nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow"
"nds_n9_2r1w_alu, nds_n9_2r1w_alu_shift,\
nds_n9_2r1w_pbsad, nds_n9_2r1w_pbsada,\
nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\
nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow,\
nds_n9_2r1w_branch,\
nds_n9_2r1w_div,\
nds_n9_2r1w_load,nds_n9_2r1w_store,\
nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\
nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\
nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12,\
nds_n9_2r1w_store_multiple_1,nds_n9_2r1w_store_multiple_2, nds_n9_2r1w_store_multiple_3,\
nds_n9_2r1w_store_multiple_4,nds_n9_2r1w_store_multiple_5, nds_n9_2r1w_store_multiple_6,\
nds_n9_2r1w_store_multiple_7,nds_n9_2r1w_store_multiple_8, nds_n9_2r1w_store_multiple_12,\
nds_n9_2r1w_mmu"
"nds32_n9_2r1w_mm_to_ex_p"
)
;; LMW(N, N)
;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44_E, MUL, MAC_RaRb, M2R, DIV, ADDR_IN_!bi, ADDR_IN_bi_Ra, ST_bi, ST_!bi_RI, BR, MMU
(define_bypass 2
"nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\
nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\
nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12"
"nds_n9_2r1w_alu, nds_n9_2r1w_alu_shift,\
nds_n9_2r1w_pbsad, nds_n9_2r1w_pbsada,\
nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\
nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow,\
nds_n9_2r1w_branch,\
nds_n9_2r1w_div,\
nds_n9_2r1w_load,nds_n9_2r1w_store,\
nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\
nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\
nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12,\
nds_n9_2r1w_store_multiple_1,nds_n9_2r1w_store_multiple_2, nds_n9_2r1w_store_multiple_3,\
nds_n9_2r1w_store_multiple_4,nds_n9_2r1w_store_multiple_5, nds_n9_2r1w_store_multiple_6,\
nds_n9_2r1w_store_multiple_7,nds_n9_2r1w_store_multiple_8, nds_n9_2r1w_store_multiple_12,\
nds_n9_2r1w_mmu"
"nds32_n9_last_load_to_ex_p"
)
;; Pipeline descriptions 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 N9 3R2W pipeline settings.
;; ------------------------------------------------------------------------
(define_automaton "nds32_n9_3r2w_machine")
;; ------------------------------------------------------------------------
;; Pipeline Stages
;; ------------------------------------------------------------------------
;; IF - Instruction Fetch
;; II - Instruction Issue / Instruction Decode
;; EX - Instruction Execution
;; MM - Memory Execution
;; WB - Instruction Retire / Result Write-Back
(define_cpu_unit "n9_3r2w_ii" "nds32_n9_3r2w_machine")
(define_cpu_unit "n9_3r2w_ex" "nds32_n9_3r2w_machine")
(define_cpu_unit "n9_3r2w_mm" "nds32_n9_3r2w_machine")
(define_cpu_unit "n9_3r2w_wb" "nds32_n9_3r2w_machine")
(define_insn_reservation "nds_n9_3r2w_unknown" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "unknown")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_misc" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "misc")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mmu" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "mmu")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_alu" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "alu")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_alu_shift" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "alu_shift")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_pbsad" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "pbsad")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*3, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_pbsada" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "pbsada")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*3, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (match_test "nds32::load_single_p (insn)")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (match_test "nds32::store_single_p (insn)")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "1"))))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(ior (and (eq_attr "type" "load_multiple")
(eq_attr "combo" "2"))
(match_test "nds32::load_double_p (insn)"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_3" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "3"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_4" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "4"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_5" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "5"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*2, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_6" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "6"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*3, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_7" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "7"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*4, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_8" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "8"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*5, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_load_multiple_12" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "load_multiple")
(eq_attr "combo" "12"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*9, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "1"))))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(ior (and (eq_attr "type" "store_multiple")
(eq_attr "combo" "2"))
(match_test "nds32::store_double_p (insn)"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_3" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "3"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_4" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "4"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_5" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "5"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*2, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_6" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "6"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*3, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_7" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "7"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*4, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_8" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "8"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*5, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_store_multiple_12" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "pipeline_model" "n9")
(and (eq_attr "type" "store_multiple")
(eq_attr "combo" "12"))))
"n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*9, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mul_fast1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_1")
(and (eq_attr "type" "mul")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mul_fast2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_2")
(and (eq_attr "type" "mul")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*2, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mul_slow" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_SLOW")
(and (eq_attr "type" "mul")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*17, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mac_fast1" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_1")
(and (eq_attr "type" "mac")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mac_fast2" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_2")
(and (eq_attr "type" "mac")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*2, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_mac_slow" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_SLOW")
(and (eq_attr "type" "mac")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*17, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_div" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "div")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex*34, n9_3r2w_mm, n9_3r2w_wb")
(define_insn_reservation "nds_n9_3r2w_branch" 1
(and (match_test "nds32_register_ports_config == REG_PORT_3R2W")
(and (eq_attr "type" "branch")
(eq_attr "pipeline_model" "n9")))
"n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb")
;; ------------------------------------------------------------------------
;; Comment Notations and Bypass Rules
;; ------------------------------------------------------------------------
;; Producers (LHS)
;; LD
;; Load data from the memory and produce the loaded data. The result is
;; ready at MM.
;; LMW(N, M)
;; There are N micro-operations within an instruction that loads multiple
;; words. The result produced by the M-th micro-operation is sent to
;; consumers. The result is ready at MM.
;; MUL, MAC
;; Compute data in the multiply-adder and produce the data. The result
;; is ready at MM.
;; DIV
;; Compute data in the divider and produce the data. The result is ready
;; at MM.
;;
;; Consumers (RHS)
;; ALU, MOVD44, PBSAD, PBSADA_RaRb, MUL, MAC, DIV, MMU
;; Require operands at EX.
;; ALU_SHIFT_Rb
;; An ALU-SHIFT instruction consists of a shift micro-operation followed
;; by an arithmetic micro-operation. The operand Rb is used by the first
;; micro-operation, and there are some latencies if data dependency occurs.
;; MAC_RaRb
;; A MAC instruction does multiplication at EX and does accumulation at MM,
;; so the operand Rt is required at MM, and operands Ra and Rb are required
;; at EX.
;; ADDR_IN
;; If an instruction requires an address as its input operand, the address
;; is required at EX.
;; ST
;; A store instruction requires its data at MM.
;; SMW(N, M)
;; There are N micro-operations within an instruction that stores multiple
;; words. Each M-th micro-operation requires its data at MM.
;; BR
;; If a branch instruction is conditional, its input data is required at EX.
;; LD, MUL, MAC, DIV
;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU
(define_bypass 2
"nds_n9_3r2w_load,\
nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\
nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\
nds_n9_3r2w_div"
"nds_n9_3r2w_alu, nds_n9_3r2w_alu_shift,\
nds_n9_3r2w_pbsad, nds_n9_3r2w_pbsada,\
nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\
nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\
nds_n9_3r2w_branch,\
nds_n9_3r2w_div,\
nds_n9_3r2w_load,nds_n9_3r2w_store,\
nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\
nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\
nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12,\
nds_n9_3r2w_store_multiple_1,nds_n9_3r2w_store_multiple_2, nds_n9_3r2w_store_multiple_3,\
nds_n9_3r2w_store_multiple_4,nds_n9_3r2w_store_multiple_5, nds_n9_3r2w_store_multiple_6,\
nds_n9_3r2w_store_multiple_7,nds_n9_3r2w_store_multiple_8, nds_n9_3r2w_store_multiple_12,\
nds_n9_3r2w_mmu"
"nds32_n9_3r2w_mm_to_ex_p"
)
;; LMW(N, N)
;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU
(define_bypass 2
"nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\
nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\
nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12"
"nds_n9_3r2w_alu, nds_n9_3r2w_alu_shift,\
nds_n9_3r2w_pbsad, nds_n9_3r2w_pbsada,\
nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\
nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\
nds_n9_3r2w_branch,\
nds_n9_3r2w_div,\
nds_n9_3r2w_load,nds_n9_3r2w_store,\
nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\
nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\
nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12,\
nds_n9_3r2w_store_multiple_1,nds_n9_3r2w_store_multiple_2, nds_n9_3r2w_store_multiple_3,\
nds_n9_3r2w_store_multiple_4,nds_n9_3r2w_store_multiple_5, nds_n9_3r2w_store_multiple_6,\
nds_n9_3r2w_store_multiple_7,nds_n9_3r2w_store_multiple_8, nds_n9_3r2w_store_multiple_12,\
nds_n9_3r2w_mmu"
"nds32_n9_last_load_to_ex_p"
)
...@@ -34,6 +34,13 @@ enum nds32_arch_type ...@@ -34,6 +34,13 @@ enum nds32_arch_type
ARCH_V3S ARCH_V3S
}; };
/* The various ANDES CPU. */
enum nds32_cpu_type
{
CPU_N9,
CPU_SIMPLE
};
/* The code model defines the address generation strategy. */ /* The code model defines the address generation strategy. */
enum nds32_cmodel_type enum nds32_cmodel_type
{ {
...@@ -42,10 +49,19 @@ enum nds32_cmodel_type ...@@ -42,10 +49,19 @@ enum nds32_cmodel_type
CMODEL_LARGE CMODEL_LARGE
}; };
/* The various ANDES CPU. */ /* Multiply instruction configuration. */
enum nds32_cpu_type enum nds32_mul_type
{
MUL_TYPE_FAST_1,
MUL_TYPE_FAST_2,
MUL_TYPE_SLOW
};
/* Register ports configuration. */
enum nds32_register_ports
{ {
CPU_N9 REG_PORT_3R2W,
REG_PORT_2R1W
}; };
/* Which ABI to use. */ /* Which ABI to use. */
......
...@@ -27,10 +27,598 @@ ...@@ -27,10 +27,598 @@
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
#include "backend.h" #include "backend.h"
#include "rtl.h"
#include "insn-attr.h"
#include "insn-codes.h"
#include "target.h"
#include "nds32-protos.h"
/* ------------------------------------------------------------------------ */
namespace nds32 {
namespace scheduling {
/* Classify the memory access direction. It's unknown if the offset register
is not a constant value. */
enum memory_access_direction
{
MEM_ACCESS_DIR_POS,
MEM_ACCESS_DIR_NEG,
MEM_ACCESS_DIR_UNKNOWN
};
/* A safe wrapper to the function reg_overlap_mentioned_p (). */
bool
reg_overlap_p (rtx x, rtx in)
{
if (x == NULL_RTX || in == NULL_RTX)
return false;
return static_cast <bool> (reg_overlap_mentioned_p (x, in));
}
/* Determine the memory access direction of a load/store insn. */
memory_access_direction
determine_access_direction (rtx_insn *insn)
{
int post_update_rtx_index;
rtx plus_rtx;
rtx mem_rtx;
rtx offset_rtx;
switch (get_attr_type (insn))
{
case TYPE_LOAD_MULTIPLE:
gcc_assert (parallel_elements (insn) >= 2);
post_update_rtx_index = find_post_update_rtx (insn);
if (post_update_rtx_index != -1)
plus_rtx = SET_SRC (parallel_element (insn, post_update_rtx_index));
else
{
/* (parallel
[(set (reg) (mem (reg))) : index 0
(set (reg) (mem (plus (reg) (...)))) : index 1
...]) */
mem_rtx = SET_SRC (parallel_element (insn, 1));
if (GET_CODE (mem_rtx) == UNSPEC)
mem_rtx = XVECEXP (mem_rtx, 0, 0);
gcc_assert (MEM_P (mem_rtx));
plus_rtx = XEXP (mem_rtx, 0);
}
break;
case TYPE_STORE_MULTIPLE:
gcc_assert (parallel_elements (insn) >= 2);
post_update_rtx_index = find_post_update_rtx (insn);
if (post_update_rtx_index != -1)
plus_rtx = SET_SRC (parallel_element (insn, post_update_rtx_index));
else
{
/* (parallel
[(set (mem (reg)) (reg)) : index 0
(set (mem (plus (reg) (...))) (reg)) : index 1
...]) */
mem_rtx = SET_DEST (parallel_element (insn, 1));
if (GET_CODE (mem_rtx) == UNSPEC)
mem_rtx = XVECEXP (mem_rtx, 0, 0);
gcc_assert (MEM_P (mem_rtx));
plus_rtx = XEXP (mem_rtx, 0);
}
break;
case TYPE_LOAD:
case TYPE_STORE:
mem_rtx = extract_mem_rtx (insn);
switch (GET_CODE (XEXP (mem_rtx, 0)))
{
case POST_INC:
/* (mem (post_inc (...))) */
return MEM_ACCESS_DIR_POS;
case POST_DEC:
/* (mem (post_dec (...))) */
return MEM_ACCESS_DIR_NEG;
case PLUS:
/* (mem (plus (reg) (...))) */
plus_rtx = XEXP (mem_rtx, 0);
break;
case POST_MODIFY:
/* (mem (post_modify (reg) (plus (reg) (...)))) */
plus_rtx = XEXP (XEXP (mem_rtx, 0), 1);
break;
default:
gcc_unreachable ();
}
break;
default:
gcc_unreachable ();
}
gcc_assert (GET_CODE (plus_rtx) == PLUS);
offset_rtx = XEXP (plus_rtx, 1);
if (GET_CODE (offset_rtx) == CONST_INT)
{
if (INTVAL (offset_rtx) < 0)
return MEM_ACCESS_DIR_NEG;
else
return MEM_ACCESS_DIR_POS;
}
return MEM_ACCESS_DIR_UNKNOWN;
}
/* Return the nth load/store operation in the real micro-operation
accessing order. */
rtx
extract_nth_access_rtx (rtx_insn *insn, int n)
{
int n_elems = parallel_elements (insn);
int post_update_rtx_index = find_post_update_rtx (insn);
memory_access_direction direction = determine_access_direction (insn);
gcc_assert (direction != MEM_ACCESS_DIR_UNKNOWN);
/* Reverse the order if the direction negative. */
if (direction == MEM_ACCESS_DIR_NEG)
n = -1 * n - 1;
if (post_update_rtx_index != -1)
{
if (n >= 0 && post_update_rtx_index <= n)
++n;
else if (n < 0 && post_update_rtx_index >= n + n_elems)
--n;
}
return parallel_element (insn, n);
}
/* Returns the register operated by the nth load/store operation in the real
micro-operation accessing order. This function assumes INSN must be a
multiple-word load/store insn. */
rtx
extract_nth_lmsw_access_reg (rtx_insn *insn, int n)
{
rtx nth_rtx = extract_nth_access_rtx (insn, n);
if (nth_rtx == NULL_RTX)
return NULL_RTX;
switch (get_attr_type (insn))
{
case TYPE_LOAD_MULTIPLE:
return SET_DEST (nth_rtx);
case TYPE_STORE_MULTIPLE:
return SET_SRC (nth_rtx);
default:
gcc_unreachable ();
}
}
/* Returns the register operated by the nth load/store operation in the real
micro-operation accessing order. This function assumes INSN must be a
double-word load/store insn. */
rtx
extract_nth_ls2_access_reg (rtx_insn *insn, int n)
{
rtx reg;
machine_mode mode;
if (post_update_insn_p (insn))
{
memory_access_direction direction = determine_access_direction (insn);
gcc_assert (direction != MEM_ACCESS_DIR_UNKNOWN);
/* Reverse the order if the direction negative. */
if (direction == MEM_ACCESS_DIR_NEG)
n = -1 * n - 1;
}
/* Handle the out-of-range case. */
if (n < -2 || n > 1)
return NULL_RTX;
/* Convert the index to a positive one. */
if (n < 0)
n = 2 + n;
switch (get_attr_type (insn))
{
case TYPE_LOAD:
reg = SET_DEST (PATTERN (insn));
break;
case TYPE_STORE:
reg = SET_SRC (PATTERN (insn));
break;
default:
gcc_unreachable ();
}
gcc_assert (REG_P (reg) || GET_CODE (reg) == SUBREG);
switch (GET_MODE (reg))
{
case E_DImode:
mode = SImode;
break;
case E_DFmode:
mode = SFmode;
break;
default:
gcc_unreachable ();
}
if (n == 0)
return gen_lowpart (mode, reg);
else
return gen_highpart (mode, reg);
}
/* Returns the register operated by the nth load/store operation in the real
micro-operation accessing order. */
rtx
extract_nth_access_reg (rtx_insn *insn, int index)
{
switch (GET_CODE (PATTERN (insn)))
{
case PARALLEL:
return extract_nth_lmsw_access_reg (insn, index);
case SET:
return extract_nth_ls2_access_reg (insn, index);
default:
gcc_unreachable ();
}
}
/* Determine if the latency is occured when the consumer PBSADA_INSN uses the
value of DEF_REG in its Ra or Rb fields. */
bool
pbsada_insn_ra_rb_dep_reg_p (rtx pbsada_insn, rtx def_reg)
{
rtx unspec_rtx = SET_SRC (PATTERN (pbsada_insn));
gcc_assert (GET_CODE (unspec_rtx) == UNSPEC);
rtx pbsada_ra = XVECEXP (unspec_rtx, 0, 0);
rtx pbsada_rb = XVECEXP (unspec_rtx, 0, 1);
if (rtx_equal_p (def_reg, pbsada_ra)
|| rtx_equal_p (def_reg, pbsada_rb))
return true;
return false;
}
/* Check if INSN is a movd44 insn consuming DEF_REG. */
bool
movd44_even_dep_p (rtx_insn *insn, rtx def_reg)
{
if (!movd44_insn_p (insn))
return false;
rtx use_rtx = SET_SRC (PATTERN (insn));
if (REG_P (def_reg))
{
return rtx_equal_p (def_reg, use_rtx);
}
else if (GET_CODE (def_reg) == SUBREG
&& GET_MODE (def_reg) == SImode
&& rtx_equal_p (SUBREG_REG (def_reg), use_rtx))
{
if (TARGET_BIG_ENDIAN && SUBREG_BYTE (def_reg) == 4)
return true;
if (!TARGET_BIG_ENDIAN && SUBREG_BYTE (def_reg) == 0)
return true;
return false;
}
return false;
}
} // namespace scheduling
} // namespace nds32
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/* This file is prepared for future implementation of precise using namespace nds32;
pipeline description for nds32 target. */ using namespace nds32::scheduling;
/* Check the dependency between the producer defining DEF_REG and CONSUMER
requiring input operand at EX. */
bool
n9_2r1w_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg)
{
rtx use_rtx;
switch (get_attr_type (consumer))
{
case TYPE_ALU:
if (movd44_even_dep_p (consumer, def_reg))
return true;
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_PBSAD:
case TYPE_MUL:
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_ALU_SHIFT:
use_rtx = extract_shift_reg (consumer);
break;
case TYPE_PBSADA:
return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg);
case TYPE_MAC:
use_rtx = PATTERN (consumer);
break;
case TYPE_DIV:
if (INSN_CODE (consumer) == CODE_FOR_divmodsi4
|| INSN_CODE (consumer) == CODE_FOR_udivmodsi4)
use_rtx = SET_SRC (parallel_element (consumer, 0));
else
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_MMU:
if (GET_CODE (PATTERN (consumer)) == SET)
use_rtx = SET_SRC (PATTERN (consumer));
else
return true;
break;
case TYPE_LOAD:
/* ADDR_IN_bi_Ra, ADDR_IN_!bi */
if (post_update_insn_p (consumer))
use_rtx = extract_base_reg (consumer);
else
use_rtx = extract_mem_rtx (consumer);
break;
case TYPE_STORE:
/* ADDR_IN_bi_Ra, ADDR_IN_!bi */
if (post_update_insn_p (consumer))
use_rtx = extract_base_reg (consumer);
else
use_rtx = extract_mem_rtx (consumer);
if (reg_overlap_p (def_reg, use_rtx))
return true;
/* exclude ST_!bi_RR */
if (!post_update_insn_p (consumer)
&& !immed_offset_p (extract_mem_rtx (consumer)))
return false;
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_LOAD_MULTIPLE:
use_rtx = extract_base_reg (consumer);
break;
case TYPE_STORE_MULTIPLE:
/* ADDR_IN */
use_rtx = extract_base_reg (consumer);
if (reg_overlap_p (def_reg, use_rtx))
return true;
/* SMW (N, 1) */
use_rtx = extract_nth_access_rtx (consumer, 0);
break;
case TYPE_BRANCH:
use_rtx = PATTERN (consumer);
break;
default:
gcc_unreachable ();
}
if (reg_overlap_p (def_reg, use_rtx))
return true;
return false;
}
/* Check the dependency between the producer defining DEF_REG and CONSUMER
requiring input operand at EX. */
bool
n9_3r2w_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg)
{
rtx use_rtx;
switch (get_attr_type (consumer))
{
case TYPE_ALU:
case TYPE_PBSAD:
case TYPE_MUL:
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_ALU_SHIFT:
use_rtx = extract_shift_reg (consumer);
break;
case TYPE_PBSADA:
return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg);
case TYPE_MAC:
use_rtx = extract_mac_non_acc_rtx (consumer);
break;
/* Some special instructions, divmodsi4 and udivmodsi4, produce two
results, the quotient and the remainder. In 2R1W configuration,
it requires two micro-operations in order to write two registers.
We have to check the dependency from the producer to the first
micro-operation. */
case TYPE_DIV:
if (INSN_CODE (consumer) == CODE_FOR_divmodsi4
|| INSN_CODE (consumer) == CODE_FOR_udivmodsi4)
use_rtx = SET_SRC (parallel_element (consumer, 0));
else
use_rtx = SET_SRC (PATTERN (consumer));
break;
case TYPE_MMU:
if (GET_CODE (PATTERN (consumer)) == SET)
use_rtx = SET_SRC (PATTERN (consumer));
else
return true;
break;
case TYPE_LOAD:
case TYPE_STORE:
use_rtx = extract_mem_rtx (consumer);
break;
case TYPE_LOAD_MULTIPLE:
case TYPE_STORE_MULTIPLE:
use_rtx = extract_base_reg (consumer);
break;
case TYPE_BRANCH:
use_rtx = PATTERN (consumer);
break;
default:
gcc_unreachable ();
}
if (reg_overlap_p (def_reg, use_rtx))
return true;
return false;
}
/* Guard functions for N9 cores. */
/* Check dependencies from MM to EX. */
bool
nds32_n9_2r1w_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer)
{
rtx def_reg;
switch (get_attr_type (producer))
{
/* LD_!bi */
case TYPE_LOAD:
if (post_update_insn_p (producer))
return false;
def_reg = SET_DEST (PATTERN (producer));
break;
case TYPE_MUL:
case TYPE_MAC:
def_reg = SET_DEST (PATTERN (producer));
break;
default:
gcc_unreachable ();
}
return n9_2r1w_consumed_by_ex_dep_p (consumer, def_reg);
}
/* Check dependencies from MM to EX. */
bool
nds32_n9_3r2w_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer)
{
rtx def_reg;
switch (get_attr_type (producer))
{
case TYPE_LOAD:
case TYPE_MUL:
case TYPE_MAC:
def_reg = SET_DEST (PATTERN (producer));
break;
/* Some special instructions, divmodsi4 and udivmodsi4, produce two
results, the quotient and the remainder. We have to handle them
individually. */
case TYPE_DIV:
if (INSN_CODE (producer) == CODE_FOR_divmodsi4
|| INSN_CODE (producer) == CODE_FOR_udivmodsi4)
{
rtx def_reg1 = SET_DEST (parallel_element (producer, 0));
rtx def_reg2 = SET_DEST (parallel_element (producer, 1));
return (n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg1)
|| n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg2));
}
def_reg = SET_DEST (PATTERN (producer));
break;
default:
gcc_unreachable ();
}
return n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg);
}
/* Check dependencies from LMW(N, N) to EX. */
bool
nds32_n9_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer)
{
rtx last_def_reg = extract_nth_access_reg (producer, -1);
if (nds32_register_ports_config == REG_PORT_2R1W)
{
/* The base-update micro operation occupies the last cycle. */
if (post_update_insn_p (producer))
return false;
/* When the base register is in the list of a load multiple insn and the
access order of the base register is not the last one, we need an
additional micro operation to commit the load result to the base
register -- we can treat the base register as the last defined
register. */
size_t i;
size_t n_elems = parallel_elements (producer);
rtx base_reg = extract_base_reg (producer);
for (i = 0; i < n_elems; ++i)
{
rtx load_rtx = extract_nth_access_rtx (producer, i);
rtx list_element = SET_DEST (load_rtx);
if (rtx_equal_p (base_reg, list_element) && i != n_elems - 1)
{
last_def_reg = base_reg;
break;
}
}
return n9_2r1w_consumed_by_ex_dep_p (consumer, last_def_reg);
}
else
return n9_3r2w_consumed_by_ex_dep_p (consumer, last_def_reg);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -97,6 +97,13 @@ extern void nds32_expand_unaligned_store (rtx *, enum machine_mode); ...@@ -97,6 +97,13 @@ extern void nds32_expand_unaligned_store (rtx *, enum machine_mode);
extern bool nds32_valid_multiple_load_store_p (rtx, bool, bool); extern bool nds32_valid_multiple_load_store_p (rtx, bool, bool);
/* Auxiliary functions for guard function checking in pipelines.md. */
extern bool nds32_n9_2r1w_mm_to_ex_p (rtx_insn *, rtx_insn *);
extern bool nds32_n9_3r2w_mm_to_ex_p (rtx_insn *, rtx_insn *);
extern bool nds32_n9_last_load_to_ex_p (rtx_insn *, rtx_insn *);
/* Auxiliary functions for stack operation predicate checking. */ /* Auxiliary functions for stack operation predicate checking. */
extern bool nds32_valid_stack_push_pop_p (rtx, bool); extern bool nds32_valid_stack_push_pop_p (rtx, bool);
...@@ -225,6 +232,29 @@ extern void nds32_cpu_cpp_builtins(struct cpp_reader *); ...@@ -225,6 +232,29 @@ extern void nds32_cpu_cpp_builtins(struct cpp_reader *);
extern bool nds32_split_double_word_load_store_p (rtx *,bool); extern bool nds32_split_double_word_load_store_p (rtx *,bool);
namespace nds32 {
extern rtx extract_pattern_from_insn (rtx);
size_t parallel_elements (rtx);
rtx parallel_element (rtx, int);
bool load_single_p (rtx_insn *);
bool store_single_p (rtx_insn *);
bool load_double_p (rtx_insn *);
bool store_double_p (rtx_insn *);
bool post_update_insn_p (rtx_insn *);
bool immed_offset_p (rtx);
int find_post_update_rtx (rtx_insn *);
rtx extract_mem_rtx (rtx_insn *);
rtx extract_base_reg (rtx_insn *);
rtx extract_shift_reg (rtx);
bool movd44_insn_p (rtx_insn *);
rtx extract_mac_non_acc_rtx (rtx_insn *);
} // namespace nds32
/* Functions for create nds32 specific optimization pass. */ /* Functions for create nds32 specific optimization pass. */
extern rtl_opt_pass *make_pass_nds32_relax_opt (gcc::context *); extern rtl_opt_pass *make_pass_nds32_relax_opt (gcc::context *);
......
/* Auxiliary functions for pipeline descriptions pattern 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 "memmodel.h"
#include "tm_p.h"
#include "optabs.h" /* For GEN_FCN. */
#include "recog.h"
#include "tm-constrs.h"
#include "insn-attr.h"
namespace nds32 {
/* Get the rtx in the PATTERN field of an insn. If INSN is not an insn,
the funciton doesn't change anything and returns it directly. */
rtx
extract_pattern_from_insn (rtx insn)
{
if (INSN_P (insn))
return PATTERN (insn);
return insn;
}
/* Get the number of elements in a parallel rtx. */
size_t
parallel_elements (rtx parallel_rtx)
{
parallel_rtx = extract_pattern_from_insn (parallel_rtx);
gcc_assert (GET_CODE (parallel_rtx) == PARALLEL);
return XVECLEN (parallel_rtx, 0);
}
/* Extract an rtx from a parallel rtx with index NTH. If NTH is a negative
value, the function returns the last NTH rtx. */
rtx
parallel_element (rtx parallel_rtx, int nth)
{
parallel_rtx = extract_pattern_from_insn (parallel_rtx);
gcc_assert (GET_CODE (parallel_rtx) == PARALLEL);
int len = parallel_elements (parallel_rtx);
if (nth >= 0)
{
if (nth >= len)
return NULL_RTX;
return XVECEXP (parallel_rtx, 0, nth);
}
else
{
if (len + nth < 0)
return NULL_RTX;
return XVECEXP (parallel_rtx, 0, len + nth);
}
}
/* Functions to determine whether INSN is single-word, double-word
or partial-word load/store insn. */
bool
load_single_p (rtx_insn *insn)
{
if (get_attr_type (insn) != TYPE_LOAD)
return false;
if (INSN_CODE (insn) == CODE_FOR_move_di ||
INSN_CODE (insn) == CODE_FOR_move_df)
return false;
return true;
}
bool
store_single_p (rtx_insn *insn)
{
if (get_attr_type (insn) != TYPE_STORE)
return false;
if (INSN_CODE (insn) == CODE_FOR_move_di ||
INSN_CODE (insn) == CODE_FOR_move_df)
return false;
return true;
}
bool
load_double_p (rtx_insn *insn)
{
if (get_attr_type (insn) != TYPE_LOAD)
return false;
if (INSN_CODE (insn) != CODE_FOR_move_di &&
INSN_CODE (insn) != CODE_FOR_move_df)
return false;
return true;
}
bool
store_double_p (rtx_insn *insn)
{
if (get_attr_type (insn) != TYPE_STORE)
return false;
if (INSN_CODE (insn) != CODE_FOR_move_di &&
INSN_CODE (insn) != CODE_FOR_move_df)
return false;
return true;
}
/* Determine if INSN is a post update insn. */
bool
post_update_insn_p (rtx_insn *insn)
{
if (find_post_update_rtx (insn) == -1)
return false;
else
return true;
}
/* Check if the address of MEM_RTX consists of a base register and an
immediate offset. */
bool
immed_offset_p (rtx mem_rtx)
{
gcc_assert (MEM_P (mem_rtx));
rtx addr_rtx = XEXP (mem_rtx, 0);
/* (mem (reg)) is equivalent to (mem (plus (reg) (const_int 0))) */
if (REG_P (addr_rtx))
return true;
/* (mem (plus (reg) (const_int))) */
if (GET_CODE (addr_rtx) == PLUS
&& GET_CODE (XEXP (addr_rtx, 1)) == CONST_INT)
return true;
return false;
}
/* Find the post update rtx in INSN. If INSN is a load/store multiple insn,
the function returns the vector index of its parallel part. If INSN is a
single load/store insn, the function returns 0. If INSN is not a post-
update insn, the function returns -1. */
int
find_post_update_rtx (rtx_insn *insn)
{
rtx mem_rtx;
int i, len;
switch (get_attr_type (insn))
{
case TYPE_LOAD_MULTIPLE:
case TYPE_STORE_MULTIPLE:
/* Find a pattern in a parallel rtx:
(set (reg) (plus (reg) (const_int))) */
len = parallel_elements (insn);
for (i = 0; i < len; ++i)
{
rtx curr_insn = parallel_element (insn, i);
if (GET_CODE (curr_insn) == SET
&& REG_P (SET_DEST (curr_insn))
&& GET_CODE (SET_SRC (curr_insn)) == PLUS)
return i;
}
return -1;
case TYPE_LOAD:
case TYPE_FLOAD:
case TYPE_STORE:
case TYPE_FSTORE:
mem_rtx = extract_mem_rtx (insn);
/* (mem (post_inc (reg))) */
switch (GET_CODE (XEXP (mem_rtx, 0)))
{
case POST_INC:
case POST_DEC:
case POST_MODIFY:
return 0;
default:
return -1;
}
default:
gcc_unreachable ();
}
}
/* Extract the MEM rtx from a load/store insn. */
rtx
extract_mem_rtx (rtx_insn *insn)
{
rtx body = PATTERN (insn);
switch (get_attr_type (insn))
{
case TYPE_LOAD:
case TYPE_FLOAD:
if (MEM_P (SET_SRC (body)))
return SET_SRC (body);
/* unaligned address: (unspec [(mem)]) */
if (GET_CODE (SET_SRC (body)) == UNSPEC)
{
gcc_assert (MEM_P (XVECEXP (SET_SRC (body), 0, 0)));
return XVECEXP (SET_SRC (body), 0, 0);
}
/* (sign_extend (mem)) */
gcc_assert (MEM_P (XEXP (SET_SRC (body), 0)));
return XEXP (SET_SRC (body), 0);
case TYPE_STORE:
case TYPE_FSTORE:
if (MEM_P (SET_DEST (body)))
return SET_DEST (body);
/* unaligned address: (unspec [(mem)]) */
if (GET_CODE (SET_DEST (body)) == UNSPEC)
{
gcc_assert (MEM_P (XVECEXP (SET_DEST (body), 0, 0)));
return XVECEXP (SET_DEST (body), 0, 0);
}
/* (sign_extend (mem)) */
gcc_assert (MEM_P (XEXP (SET_DEST (body), 0)));
return XEXP (SET_DEST (body), 0);
default:
gcc_unreachable ();
}
}
/* Extract the base register from load/store insns. The function returns
NULL_RTX if the address is not consist of any registers. */
rtx
extract_base_reg (rtx_insn *insn)
{
int post_update_rtx_index;
rtx mem_rtx;
rtx plus_rtx;
/* Find the MEM rtx. If we can find an insn updating the base register,
the base register will be returned directly. */
switch (get_attr_type (insn))
{
case TYPE_LOAD_MULTIPLE:
post_update_rtx_index = find_post_update_rtx (insn);
if (post_update_rtx_index != -1)
return SET_DEST (parallel_element (insn, post_update_rtx_index));
mem_rtx = SET_SRC (parallel_element (insn, 0));
break;
case TYPE_STORE_MULTIPLE:
post_update_rtx_index = find_post_update_rtx (insn);
if (post_update_rtx_index != -1)
return SET_DEST (parallel_element (insn, post_update_rtx_index));
mem_rtx = SET_DEST (parallel_element (insn, 0));
break;
case TYPE_LOAD:
case TYPE_FLOAD:
case TYPE_STORE:
case TYPE_FSTORE:
mem_rtx = extract_mem_rtx (insn);
break;
default:
gcc_unreachable ();
}
gcc_assert (MEM_P (mem_rtx));
/* (mem (reg)) */
if (REG_P (XEXP (mem_rtx, 0)))
return XEXP (mem_rtx, 0);
plus_rtx = XEXP (mem_rtx, 0);
if (GET_CODE (plus_rtx) == SYMBOL_REF
|| GET_CODE (plus_rtx) == CONST)
return NULL_RTX;
gcc_assert (GET_CODE (plus_rtx) == PLUS
|| GET_CODE (plus_rtx) == POST_INC
|| GET_CODE (plus_rtx) == POST_DEC
|| GET_CODE (plus_rtx) == POST_MODIFY);
gcc_assert (REG_P (XEXP (plus_rtx, 0)));
/* (mem (plus (reg) (const_int))) or
(mem (post_inc (reg))) or
(mem (post_dec (reg))) or
(mem (post_modify (reg) (plus (reg) (reg)))) */
return XEXP (plus_rtx, 0);
}
/* Extract the register of the shift operand from an ALU_SHIFT rtx. */
rtx
extract_shift_reg (rtx alu_shift_rtx)
{
alu_shift_rtx = extract_pattern_from_insn (alu_shift_rtx);
rtx alu_rtx = SET_SRC (alu_shift_rtx);
rtx shift_rtx;
/* Various forms of ALU_SHIFT can be made by the combiner.
See the difference between add_slli and sub_slli in nds32.md. */
if (REG_P (XEXP (alu_rtx, 0)))
shift_rtx = XEXP (alu_rtx, 1);
else
shift_rtx = XEXP (alu_rtx, 0);
return XEXP (shift_rtx, 0);
}
/* Check if INSN is a movd44 insn. */
bool
movd44_insn_p (rtx_insn *insn)
{
if (get_attr_type (insn) == TYPE_ALU
&& (INSN_CODE (insn) == CODE_FOR_move_di
|| INSN_CODE (insn) == CODE_FOR_move_df))
{
rtx body = PATTERN (insn);
gcc_assert (GET_CODE (body) == SET);
rtx src = SET_SRC (body);
rtx dest = SET_DEST (body);
if ((REG_P (src) || GET_CODE (src) == SUBREG)
&& (REG_P (dest) || GET_CODE (dest) == SUBREG))
return true;
return false;
}
return false;
}
/* Extract the rtx representing non-accumulation operands of a MAC insn. */
rtx
extract_mac_non_acc_rtx (rtx_insn *insn)
{
rtx exp = SET_SRC (PATTERN (insn));
switch (get_attr_type (insn))
{
case TYPE_MAC:
if (REG_P (XEXP (exp, 0)))
return XEXP (exp, 1);
else
return XEXP (exp, 0);
default:
gcc_unreachable ();
}
}
} // namespace nds32
...@@ -502,6 +502,11 @@ enum nds32_builtins ...@@ -502,6 +502,11 @@ enum nds32_builtins
|| nds32_arch_option == ARCH_V3S) || nds32_arch_option == ARCH_V3S)
#define TARGET_ISA_V3M (nds32_arch_option == ARCH_V3M) #define TARGET_ISA_V3M (nds32_arch_option == ARCH_V3M)
#define TARGET_PIPELINE_N9 \
(nds32_cpu_option == CPU_N9)
#define TARGET_PIPELINE_SIMPLE \
(nds32_cpu_option == CPU_SIMPLE)
#define TARGET_CMODEL_SMALL \ #define TARGET_CMODEL_SMALL \
(nds32_cmodel_option == CMODEL_SMALL) (nds32_cmodel_option == CMODEL_SMALL)
#define TARGET_CMODEL_MEDIUM \ #define TARGET_CMODEL_MEDIUM \
...@@ -515,6 +520,8 @@ enum nds32_builtins ...@@ -515,6 +520,8 @@ enum nds32_builtins
(nds32_cmodel_option == CMODEL_SMALL\ (nds32_cmodel_option == CMODEL_SMALL\
|| nds32_cmodel_option == CMODEL_MEDIUM) || nds32_cmodel_option == CMODEL_MEDIUM)
#define TARGET_MUL_SLOW \
(nds32_mul_config == MUL_TYPE_SLOW)
/* Run-time Target Specification. */ /* Run-time Target Specification. */
#define TARGET_SOFT_FLOAT (nds32_abi == NDS32_ABI_V2) #define TARGET_SOFT_FLOAT (nds32_abi == NDS32_ABI_V2)
...@@ -553,6 +560,7 @@ enum nds32_builtins ...@@ -553,6 +560,7 @@ enum nds32_builtins
" %{!mno-ext-fpu-dp:%{!mext-fpu-dp:-mext-fpu-dp}}}" \ " %{!mno-ext-fpu-dp:%{!mext-fpu-dp:-mext-fpu-dp}}}" \
" %{march=v3s:%{!mfloat-abi=*:-mfloat-abi=hard}" \ " %{march=v3s:%{!mfloat-abi=*:-mfloat-abi=hard}" \
" %{!mno-ext-fpu-sp:%{!mext-fpu-sp:-mext-fpu-sp}}}" }, \ " %{!mno-ext-fpu-sp:%{!mext-fpu-sp:-mext-fpu-sp}}}" }, \
{"cpu", "%{!mcpu=*:-mcpu=%(VALUE)}" }, \
{"float", "%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}" } {"float", "%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}" }
#define CC1_SPEC \ #define CC1_SPEC \
......
...@@ -53,6 +53,15 @@ ...@@ -53,6 +53,15 @@
(include "nds32-peephole2.md") (include "nds32-peephole2.md")
;; ------------------------------------------------------------------------
;; CPU pipeline model.
(define_attr "pipeline_model" "n9,simple"
(const
(cond [(match_test "nds32_cpu_option == CPU_N9") (const_string "n9")
(match_test "nds32_cpu_option == CPU_SIMPLE") (const_string "simple")]
(const_string "n9"))))
;; Insn type, it is used to default other attribute values. ;; Insn type, it is used to default other attribute values.
(define_attr "type" (define_attr "type"
"unknown,load,store,load_multiple,store_multiple,alu,alu_shift,pbsad,pbsada,mul,mac,div,branch,mmu,misc,\ "unknown,load,store,load_multiple,store_multiple,alu,alu_shift,pbsad,pbsada,mul,mac,div,branch,mmu,misc,\
......
...@@ -177,6 +177,21 @@ Known cpu types (for use with the -mcpu= option): ...@@ -177,6 +177,21 @@ Known cpu types (for use with the -mcpu= option):
EnumValue EnumValue
Enum(nds32_cpu_type) String(n9) Value(CPU_N9) Enum(nds32_cpu_type) String(n9) Value(CPU_N9)
EnumValue
Enum(nds32_cpu_type) String(n903) Value(CPU_N9)
EnumValue
Enum(nds32_cpu_type) String(n903a) Value(CPU_N9)
EnumValue
Enum(nds32_cpu_type) String(n968) Value(CPU_N9)
EnumValue
Enum(nds32_cpu_type) String(n968a) Value(CPU_N9)
EnumValue
Enum(nds32_cpu_type) String(simple) Value(CPU_SIMPLE)
mconfig-fpu= mconfig-fpu=
Target RejectNegative Joined Enum(float_reg_number) Var(nds32_fp_regnum) Init(TARGET_CONFIG_FPU_DEFAULT) Target RejectNegative Joined Enum(float_reg_number) Var(nds32_fp_regnum) Init(TARGET_CONFIG_FPU_DEFAULT)
Specify a fpu configuration value from 0 to 7; 0-3 is as FPU spec says, and 4-7 is corresponding to 0-3. Specify a fpu configuration value from 0 to 7; 0-3 is as FPU spec says, and 4-7 is corresponding to 0-3.
...@@ -209,6 +224,38 @@ Enum(float_reg_number) String(6) Value(NDS32_CONFIG_FPU_6) ...@@ -209,6 +224,38 @@ Enum(float_reg_number) String(6) Value(NDS32_CONFIG_FPU_6)
EnumValue EnumValue
Enum(float_reg_number) String(7) Value(NDS32_CONFIG_FPU_7) Enum(float_reg_number) String(7) Value(NDS32_CONFIG_FPU_7)
mconfig-mul=
Target RejectNegative Joined Enum(nds32_mul_type) Var(nds32_mul_config) Init(MUL_TYPE_FAST_1)
Specify configuration of instruction mul: fast1, fast2 or slow. The default is fast1.
Enum
Name(nds32_mul_type) Type(enum nds32_mul_type)
EnumValue
Enum(nds32_mul_type) String(fast) Value(MUL_TYPE_FAST_1)
EnumValue
Enum(nds32_mul_type) String(fast1) Value(MUL_TYPE_FAST_1)
EnumValue
Enum(nds32_mul_type) String(fast2) Value(MUL_TYPE_FAST_2)
EnumValue
Enum(nds32_mul_type) String(slow) Value(MUL_TYPE_SLOW)
mconfig-register-ports=
Target RejectNegative Joined Enum(nds32_register_ports) Var(nds32_register_ports_config) Init(REG_PORT_3R2W)
Specify how many read/write ports for n9/n10 cores. The value should be 3r2w or 2r1w.
Enum
Name(nds32_register_ports) Type(enum nds32_register_ports)
EnumValue
Enum(nds32_register_ports) String(3r2w) Value(REG_PORT_3R2W)
EnumValue
Enum(nds32_register_ports) String(2r1w) Value(REG_PORT_2R1W)
mctor-dtor mctor-dtor
Target Report Target Report
Enable constructor/destructor feature. Enable constructor/destructor feature.
......
...@@ -18,12 +18,24 @@ ...@@ -18,12 +18,24 @@
;; along with GCC; see the file COPYING3. If not see ;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>. ;; <http://www.gnu.org/licenses/>.
(define_automaton "nds32_machine")
(define_cpu_unit "general_unit" "nds32_machine") ;; ------------------------------------------------------------------------
;; Include N9/N10 pipeline settings.
;; ------------------------------------------------------------------------
(include "nds32-n9-3r2w.md")
(include "nds32-n9-2r1w.md")
;; ------------------------------------------------------------------------
;; Define simple pipeline settings.
;; ------------------------------------------------------------------------
(define_automaton "nds32_simple_machine")
(define_cpu_unit "simple_unit" "nds32_simple_machine")
(define_insn_reservation "simple_insn" 1 (define_insn_reservation "simple_insn" 1
(eq_attr "type" "unknown,load,store,load_multiple,store_multiple,alu,alu_shift,mul,mac,div,branch,mmu,misc") (eq_attr "pipeline_model" "simple")
"general_unit") "simple_unit")
;; ------------------------------------------------------------------------ ;; ------------------------------------------------------------------------
...@@ -131,3 +131,16 @@ nds32-relax-opt.o: \ ...@@ -131,3 +131,16 @@ nds32-relax-opt.o: \
intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) intl.h libfuncs.h $(PARAMS_H) $(OPTS_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(srcdir)/config/nds32/nds32-relax-opt.c $(srcdir)/config/nds32/nds32-relax-opt.c
nds32-utils.o: \
$(srcdir)/config/nds32/nds32-utils.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-utils.c
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment