From 97616707129ecfa4ea73703f415216a93bed1e97 Mon Sep 17 00:00:00 2001 From: wmi Date: Tue, 5 Nov 2013 02:28:13 +0000 Subject: [PATCH] Backport r204369 from trunk to enable macrofusion on x86 (The second one of three patches). git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/google@204379 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc-4_8/gcc/config/i386/i386.c | 197 +++++++++++++++++++++++++++++++---- gcc-4_8/gcc/config/i386/i386.h | 11 +- gcc-4_8/gcc/config/i386/x86-tune.def | 5 +- gcc-4_8/gcc/doc/tm.texi | 11 ++ gcc-4_8/gcc/doc/tm.texi.in | 4 + gcc-4_8/gcc/haifa-sched.c | 49 +++++++++ gcc-4_8/gcc/target.def | 13 +++ 7 files changed, 265 insertions(+), 25 deletions(-) diff --git a/gcc-4_8/gcc/config/i386/i386.c b/gcc-4_8/gcc/config/i386/i386.c index 3acedab9767..1484942501e 100644 --- a/gcc-4_8/gcc/config/i386/i386.c +++ b/gcc-4_8/gcc/config/i386/i386.c @@ -2002,10 +2002,25 @@ static unsigned int initial_ix86_tune_features[X86_TUNE_LAST] = { from integer to FP. */ m_AMDFAM10, - /* X86_TUNE_FUSE_CMP_AND_BRANCH: Fuse a compare or test instruction - with a subsequent conditional jump instruction into a single - compare-and-branch uop. */ - m_BDVER, + /* X86_TUNE_FUSE_CMP_AND_BRANCH_32: Fuse compare with a subsequent + conditional jump instruction for 32 bit TARGET. + FIXME: revisit for generic. */ + m_GENERIC | m_CORE_ALL | m_BDVER, + + /* X86_TUNE_FUSE_CMP_AND_BRANCH_64: Fuse compare with a subsequent + conditional jump instruction for TARGET_64BIT. + FIXME: revisit for generic. */ + m_GENERIC | m_COREI7 | m_COREI7_AVX | m_HASWELL | m_BDVER, + + /* X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS: Fuse compare with a + subsequent conditional jump instruction when the condition jump + check sign flag (SF) or overflow flag (OF). */ + m_GENERIC | m_COREI7 | m_COREI7_AVX | m_HASWELL | m_BDVER, + + /* X86_TUNE_FUSE_ALU_AND_BRANCH: Fuse alu with a subsequent conditional + jump instruction when the alu instruction produces the CCFLAG consumed by + the conditional jump instruction. */ + m_GENERIC | m_COREI7_AVX | m_HASWELL, /* X86_TUNE_OPT_AGU: Optimize for Address Generation Unit. This flag will impact LEA instruction selection. */ @@ -24332,6 +24347,42 @@ ix86_instantiate_decls (void) instantiate_decl_rtl (s->rtl); } +/* Check whether x86 address PARTS is a pc-relative address. */ + +static bool +rip_relative_addr_p (struct ix86_address *parts) +{ + rtx base, index, disp; + + base = parts->base; + index = parts->index; + disp = parts->disp; + + if (disp && !base && !index) + { + if (TARGET_64BIT) + { + rtx symbol = disp; + + if (GET_CODE (disp) == CONST) + symbol = XEXP (disp, 0); + if (GET_CODE (symbol) == PLUS + && CONST_INT_P (XEXP (symbol, 1))) + symbol = XEXP (symbol, 0); + + if (GET_CODE (symbol) == LABEL_REF + || (GET_CODE (symbol) == SYMBOL_REF + && SYMBOL_REF_TLS_MODEL (symbol) == 0) + || (GET_CODE (symbol) == UNSPEC + && (XINT (symbol, 1) == UNSPEC_GOTPCREL + || XINT (symbol, 1) == UNSPEC_PCREL + || XINT (symbol, 1) == UNSPEC_GOTNTPOFF))) + return true; + } + } + return false; +} + /* Calculate the length of the memory address in the instruction encoding. Includes addr32 prefix, does not include the one-byte modrm, opcode, or other prefixes. We never generate addr32 prefix for LEA insn. */ @@ -24403,25 +24454,8 @@ memory_address_length (rtx addr, bool lea) else if (disp && !base && !index) { len += 4; - if (TARGET_64BIT) - { - rtx symbol = disp; - - if (GET_CODE (disp) == CONST) - symbol = XEXP (disp, 0); - if (GET_CODE (symbol) == PLUS - && CONST_INT_P (XEXP (symbol, 1))) - symbol = XEXP (symbol, 0); - - if (GET_CODE (symbol) != LABEL_REF - && (GET_CODE (symbol) != SYMBOL_REF - || SYMBOL_REF_TLS_MODEL (symbol) != 0) - && (GET_CODE (symbol) != UNSPEC - || (XINT (symbol, 1) != UNSPEC_GOTPCREL - && XINT (symbol, 1) != UNSPEC_PCREL - && XINT (symbol, 1) != UNSPEC_GOTNTPOFF))) - len++; - } + if (rip_relative_addr_p (&parts)) + len++; } else { @@ -24882,6 +24916,119 @@ ia32_multipass_dfa_lookahead (void) } } +/* Return true if target platform supports macro-fusion. */ + +static bool +ix86_macro_fusion_p () +{ + return TARGET_FUSE_CMP_AND_BRANCH; +} + +/* Check whether current microarchitecture support macro fusion + for insn pair "CONDGEN + CONDJMP". Refer to + "Intel Architectures Optimization Reference Manual". */ + +static bool +ix86_macro_fusion_pair_p (rtx condgen, rtx condjmp) +{ + rtx src, dest; + rtx single_set = single_set (condgen); + enum rtx_code ccode; + rtx compare_set = NULL_RTX, test_if, cond; + rtx alu_set = NULL_RTX, addr = NULL_RTX; + + if (get_attr_type (condgen) != TYPE_TEST + && get_attr_type (condgen) != TYPE_ICMP + && get_attr_type (condgen) != TYPE_INCDEC + && get_attr_type (condgen) != TYPE_ALU) + return false; + + if (single_set == NULL_RTX + && !TARGET_FUSE_ALU_AND_BRANCH) + return false; + + if (single_set != NULL_RTX) + compare_set = single_set; + else + { + int i; + rtx pat = PATTERN (condgen); + for (i = 0; i < XVECLEN (pat, 0); i++) + if (GET_CODE (XVECEXP (pat, 0, i)) == SET) + { + rtx set_src = SET_SRC (XVECEXP (pat, 0, i)); + if (GET_CODE (set_src) == COMPARE) + compare_set = XVECEXP (pat, 0, i); + else + alu_set = XVECEXP (pat, 0, i); + } + } + if (compare_set == NULL_RTX) + return false; + src = SET_SRC (compare_set); + if (GET_CODE (src) != COMPARE) + return false; + + /* Macro-fusion for cmp/test MEM-IMM + conditional jmp is not + supported. */ + if ((MEM_P (XEXP (src, 0)) + && CONST_INT_P (XEXP (src, 1))) + || (MEM_P (XEXP (src, 1)) + && CONST_INT_P (XEXP (src, 0)))) + return false; + + /* No fusion for RIP-relative address. */ + if (MEM_P (XEXP (src, 0))) + addr = XEXP (XEXP (src, 0), 0); + else if (MEM_P (XEXP (src, 1))) + addr = XEXP (XEXP (src, 1), 0); + + if (addr) { + ix86_address parts; + int ok = ix86_decompose_address (addr, &parts); + gcc_assert (ok); + + if (rip_relative_addr_p (&parts)) + return false; + } + + test_if = SET_SRC (pc_set (condjmp)); + cond = XEXP (test_if, 0); + ccode = GET_CODE (cond); + /* Check whether conditional jump use Sign or Overflow Flags. */ + if (!TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS + && (ccode == GE + || ccode == GT + || ccode == LE + || ccode == LT)) + return false; + + /* Return true for TYPE_TEST and TYPE_ICMP. */ + if (get_attr_type (condgen) == TYPE_TEST + || get_attr_type (condgen) == TYPE_ICMP) + return true; + + /* The following is the case that macro-fusion for alu + jmp. */ + if (!TARGET_FUSE_ALU_AND_BRANCH || !alu_set) + return false; + + /* No fusion for alu op with memory destination operand. */ + dest = SET_DEST (alu_set); + if (MEM_P (dest)) + return false; + + /* Macro-fusion for inc/dec + unsigned conditional jump is not + supported. */ + if (get_attr_type (condgen) == TYPE_INCDEC + && (ccode == GEU + || ccode == GTU + || ccode == LEU + || ccode == LTU)) + return false; + + return true; +} + /* Try to reorder ready list to take advantage of Atom pipelined IMUL execution. It is applied if (1) IMUL instruction is on the top of list; @@ -42929,6 +43076,10 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val) #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ ia32_multipass_dfa_lookahead +#undef TARGET_SCHED_MACRO_FUSION_P +#define TARGET_SCHED_MACRO_FUSION_P ix86_macro_fusion_p +#undef TARGET_SCHED_MACRO_FUSION_PAIR_P +#define TARGET_SCHED_MACRO_FUSION_PAIR_P ix86_macro_fusion_pair_p #undef TARGET_FUNCTION_OK_FOR_SIBCALL #define TARGET_FUNCTION_OK_FOR_SIBCALL ix86_function_ok_for_sibcall diff --git a/gcc-4_8/gcc/config/i386/i386.h b/gcc-4_8/gcc/config/i386/i386.h index 2f8e9ee97b6..c546d9425c6 100644 --- a/gcc-4_8/gcc/config/i386/i386.h +++ b/gcc-4_8/gcc/config/i386/i386.h @@ -354,8 +354,17 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; ix86_tune_features[X86_TUNE_USE_VECTOR_FP_CONVERTS] #define TARGET_USE_VECTOR_CONVERTS \ ix86_tune_features[X86_TUNE_USE_VECTOR_CONVERTS] +#define TARGET_FUSE_CMP_AND_BRANCH_32 \ + ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_32] +#define TARGET_FUSE_CMP_AND_BRANCH_64 \ + ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_64] #define TARGET_FUSE_CMP_AND_BRANCH \ - ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH] + (TARGET_64BIT ? TARGET_FUSE_CMP_AND_BRANCH_64 \ + : TARGET_FUSE_CMP_AND_BRANCH_32) +#define TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS \ + ix86_tune_features[X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS] +#define TARGET_FUSE_ALU_AND_BRANCH \ + ix86_tune_features[X86_TUNE_FUSE_ALU_AND_BRANCH] #define TARGET_OPT_AGU ix86_tune_features[X86_TUNE_OPT_AGU] #define TARGET_VECTORIZE_DOUBLE \ ix86_tune_features[X86_TUNE_VECTORIZE_DOUBLE] diff --git a/gcc-4_8/gcc/config/i386/x86-tune.def b/gcc-4_8/gcc/config/i386/x86-tune.def index afd2da1f8fb..e8cdbf5b290 100644 --- a/gcc-4_8/gcc/config/i386/x86-tune.def +++ b/gcc-4_8/gcc/config/i386/x86-tune.def @@ -84,7 +84,10 @@ DEF_TUNE (X86_TUNE_NOT_VECTORMODE, "not_vectormode") DEF_TUNE (X86_TUNE_USE_VECTOR_FP_CONVERTS, "use_vector_fp_converts") DEF_TUNE (X86_TUNE_USE_VECTOR_CONVERTS, "use_vector_converts") - DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH, "fuse_cmp_and_branch") + DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_32, "fuse_cmp_and_branch_32") + DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_64, "fuse_cmp_and_branch_64") + DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS, "fuse_cmp_and_branch_soflags") + DEF_TUNE (X86_TUNE_FUSE_ALU_AND_BRANCH, "fuse_alu_and_branch") DEF_TUNE (X86_TUNE_OPT_AGU, "opt_agu") DEF_TUNE (X86_TUNE_VECTORIZE_DOUBLE, "vectorize_double") DEF_TUNE (X86_TUNE_SOFTWARE_PREFETCHING_BENEFICIAL, "software_prefetching_beneficial") diff --git a/gcc-4_8/gcc/doc/tm.texi b/gcc-4_8/gcc/doc/tm.texi index cbbc82dfe39..ea02e5f8eb4 100644 --- a/gcc-4_8/gcc/doc/tm.texi +++ b/gcc-4_8/gcc/doc/tm.texi @@ -6551,6 +6551,17 @@ scheduling one insn causes other insns to become ready in the same cycle. These other insns can then be taken into account properly. @end deftypefn +@deftypefn {Target Hook} bool TARGET_SCHED_MACRO_FUSION_P (void) +This hook is used to check whether target platform supports macro fusion. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_SCHED_MACRO_FUSION_PAIR_P (rtx @var{condgen}, rtx @var{condjmp}) +This hook is used to check whether two insns could be macro fused for +target microarchitecture. If this hook returns true for the given insn pair +(@var{condgen} and @var{condjmp}), scheduler will put them into a sched +group, and they will not be scheduled apart. +@end deftypefn + @deftypefn {Target Hook} void TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK (rtx @var{head}, rtx @var{tail}) This hook is called after evaluation forward dependencies of insns in chain given by two parameter values (@var{head} and @var{tail} diff --git a/gcc-4_8/gcc/doc/tm.texi.in b/gcc-4_8/gcc/doc/tm.texi.in index dfba947f51b..3ecada65e19 100644 --- a/gcc-4_8/gcc/doc/tm.texi.in +++ b/gcc-4_8/gcc/doc/tm.texi.in @@ -6455,6 +6455,10 @@ scheduling one insn causes other insns to become ready in the same cycle. These other insns can then be taken into account properly. @end deftypefn +@hook TARGET_SCHED_MACRO_FUSION_P + +@hook TARGET_SCHED_MACRO_FUSION_PAIR_P + @hook TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK This hook is called after evaluation forward dependencies of insns in chain given by two parameter values (@var{head} and @var{tail} diff --git a/gcc-4_8/gcc/haifa-sched.c b/gcc-4_8/gcc/haifa-sched.c index c4591bfe35b..4d15b60d564 100644 --- a/gcc-4_8/gcc/haifa-sched.c +++ b/gcc-4_8/gcc/haifa-sched.c @@ -6511,6 +6511,50 @@ setup_sched_dump (void) ? stderr : dump_file); } +/* Try to group comparison and the following conditional jump INSN if + they're already adjacent. This is to prevent scheduler from scheduling + them apart. */ + +static void +try_group_insn (rtx insn) +{ + unsigned int condreg1, condreg2; + rtx cc_reg_1; + rtx prev; + + if (!any_condjump_p (insn)) + return; + + targetm.fixed_condition_code_regs (&condreg1, &condreg2); + cc_reg_1 = gen_rtx_REG (CCmode, condreg1); + prev = prev_nonnote_nondebug_insn (insn); + if (!reg_referenced_p (cc_reg_1, PATTERN (insn)) + || !prev + || !modified_in_p (cc_reg_1, prev)) + return; + + /* Different microarchitectures support macro fusions for different + combinations of insn pairs. */ + if (!targetm.sched.macro_fusion_pair_p + || !targetm.sched.macro_fusion_pair_p (prev, insn)) + return; + + SCHED_GROUP_P (insn) = 1; +} + +/* If the last cond jump and the cond register defining insn are consecutive + before scheduling, we want them to be in a schedule group. This is good + for performance on microarchitectures supporting macro-fusion. */ + +static void +group_insns_for_macro_fusion () +{ + basic_block bb; + + FOR_EACH_BB (bb) + try_group_insn (BB_END (bb)); +} + /* Initialize some global state for the scheduler. This function works with the common data shared between all the schedulers. It is called from the scheduler specific initialization routine. */ @@ -6637,6 +6681,11 @@ sched_init (void) } curr_state = xmalloc (dfa_state_size); + + /* Group compare and branch insns for macro-fusion. */ + if (targetm.sched.macro_fusion_p + && targetm.sched.macro_fusion_p ()) + group_insns_for_macro_fusion (); } static void haifa_init_only_bb (basic_block, basic_block); diff --git a/gcc-4_8/gcc/target.def b/gcc-4_8/gcc/target.def index 831cad8119b..21cfb816e72 100644 --- a/gcc-4_8/gcc/target.def +++ b/gcc-4_8/gcc/target.def @@ -591,6 +591,19 @@ DEFHOOK "", int, (FILE *file, int verbose, rtx *ready, int *n_readyp, int clock), NULL) +DEFHOOK +(macro_fusion_p, + "This hook is used to check whether target platform supports macro fusion.", + bool, (void), NULL) + +DEFHOOK +(macro_fusion_pair_p, + "This hook is used to check whether two insns could be macro fused for\n\ +target microarchitecture. If this hook returns true for the given insn pair\n\ +(@var{condgen} and @var{condjmp}), scheduler will put them into a sched\n\ +group, and they will not be scheduled apart.", + bool, (rtx condgen, rtx condjmp), NULL) + /* The following member value is a pointer to a function called after evaluation forward dependencies of insns in chain given by two parameter values (head and tail correspondingly). */ -- 2.11.4.GIT