diff options
Diffstat (limited to 'gcc/config/nds32/nds32-pipelines-auxiliary.c')
-rw-r--r-- | gcc/config/nds32/nds32-pipelines-auxiliary.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/gcc/config/nds32/nds32-pipelines-auxiliary.c b/gcc/config/nds32/nds32-pipelines-auxiliary.c index 7ab5539deaa9..560137c248f3 100644 --- a/gcc/config/nds32/nds32-pipelines-auxiliary.c +++ b/gcc/config/nds32/nds32-pipelines-auxiliary.c @@ -306,6 +306,19 @@ pbsada_insn_ra_rb_dep_reg_p (rtx pbsada_insn, rtx def_reg) return false; } +/* Determine if the latency is occured when the consumer PBSADA_INSN uses the + value of DEF_REG in its Rt field. */ +bool +pbsada_insn_rt_dep_reg_p (rtx pbsada_insn, rtx def_reg) +{ + rtx pbsada_rt = SET_DEST (PATTERN (pbsada_insn)); + + if (rtx_equal_p (def_reg, pbsada_rt)) + 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) @@ -918,6 +931,153 @@ n10_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg) return false; } +/* Check dependencies from any stages to ALU_E1 (E1). This is a helper + function of n13_consumed_by_e1_dep_p (). */ +bool +n13_alu_e1_insn_dep_reg_p (rtx_insn *alu_e1_insn, rtx def_reg) +{ + rtx unspec_rtx, operand_ra, operand_rb; + rtx src_rtx, dst_rtx; + + switch (INSN_CODE (alu_e1_insn)) + { + /* BSP and BSE are supported by built-in functions, the corresponding + patterns are formed by UNSPEC RTXs. We have to handle them + individually. */ + case CODE_FOR_unspec_bsp: + case CODE_FOR_unspec_bse: + unspec_rtx = SET_SRC (parallel_element (alu_e1_insn, 0)); + gcc_assert (GET_CODE (unspec_rtx) == UNSPEC); + + operand_ra = XVECEXP (unspec_rtx, 0, 0); + operand_rb = XVECEXP (unspec_rtx, 0, 1); + + if (rtx_equal_p (def_reg, operand_ra) + || rtx_equal_p (def_reg, operand_rb)) + return true; + + return false; + + /* Unlink general ALU instructions, MOVD44 requires operands at E1. */ + case CODE_FOR_move_di: + case CODE_FOR_move_df: + src_rtx = SET_SRC (PATTERN (alu_e1_insn)); + dst_rtx = SET_DEST (PATTERN (alu_e1_insn)); + + if (REG_P (dst_rtx) && REG_P (src_rtx) + && rtx_equal_p (src_rtx, def_reg)) + return true; + + return false; + + default: + return false; + } +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at E1. Because the address generation unti is + at E1, the address input should be ready at E1. Note that the branch + target is also a kind of addresses, so we have to check it. */ +bool +n13_consumed_by_e1_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + /* ALU_E1 */ + case TYPE_ALU: + return n13_alu_e1_insn_dep_reg_p (consumer, def_reg); + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_PBSAD: + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + case TYPE_DIV: + if (divmod_p (consumer)) + 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_BRANCH: + use_rtx = extract_branch_target_rtx (consumer); + 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; + + default: + return false; + } + + 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 E2. */ +bool +n13_consumed_by_e2_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_STORE: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_rt_dep_reg_p (consumer, def_reg); + + case TYPE_STORE_MULTIPLE: + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + case TYPE_BRANCH: + use_rtx = extract_branch_condition_rtx (consumer); + break; + + default: + gcc_unreachable(); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} } // anonymous namespace /* ------------------------------------------------------------------------ */ @@ -1371,4 +1531,115 @@ nds32_n10_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) return n10_consumed_by_ex_dep_p (consumer, last_def_reg); } + +/* Guard functions for N12/N13 cores. */ + +/* Check dependencies from E2 to E1. */ +bool +nds32_n13_e2_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + /* Only post-update load/store instructions are considered. These + instructions produces address output at E2. */ + case TYPE_LOAD: + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + case TYPE_ALU: + case TYPE_ALU_SHIFT: + case TYPE_PBSAD: + case TYPE_PBSADA: + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_BRANCH: + return true; + + case TYPE_DIV: + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to handle them + individually. */ + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (n13_consumed_by_e1_dep_p (consumer, def_reg1) + || n13_consumed_by_e1_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return n13_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from Load-Store Unit (E3) to E1. */ +bool +nds32_n13_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + gcc_assert (get_attr_type (producer) == TYPE_LOAD); + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + + return n13_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from Load-Store Unit (E3) to E2. */ +bool +nds32_n13_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + gcc_assert (get_attr_type (producer) == TYPE_LOAD); + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + + return n13_consumed_by_e2_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to E1. */ +bool +nds32_n13_last_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return n13_consumed_by_e1_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N) to E2. */ +bool +nds32_n13_last_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return n13_consumed_by_e2_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N-1) to E2. */ +bool +nds32_n13_last_two_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_two_def_reg = extract_nth_access_reg (producer, -2); + + if (last_two_def_reg == NULL_RTX) + return false; + + return n13_consumed_by_e1_dep_p (consumer, last_two_def_reg); +} /* ------------------------------------------------------------------------ */ |