diff options
-rw-r--r-- | gcc/ChangeLog | 38 | ||||
-rw-r--r-- | gcc/builtins.c | 3 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 46 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 69 | ||||
-rw-r--r-- | gcc/coretypes.h | 12 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 14 | ||||
-rw-r--r-- | gcc/doc/tm.texi.in | 2 | ||||
-rw-r--r-- | gcc/gimple-match-head.c | 2 | ||||
-rw-r--r-- | gcc/internal-fn.c | 43 | ||||
-rw-r--r-- | gcc/internal-fn.h | 6 | ||||
-rw-r--r-- | gcc/optabs-query.c | 30 | ||||
-rw-r--r-- | gcc/optabs-query.h | 6 | ||||
-rw-r--r-- | gcc/predict.c | 20 | ||||
-rw-r--r-- | gcc/predict.h | 2 | ||||
-rw-r--r-- | gcc/target.def | 17 | ||||
-rw-r--r-- | gcc/targhooks.c | 8 | ||||
-rw-r--r-- | gcc/targhooks.h | 3 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr68432-1.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr68432-2.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr68432-3.c | 17 | ||||
-rw-r--r-- | gcc/tree-vect-patterns.c | 4 | ||||
-rw-r--r-- | gcc/tree-vect-stmts.c | 3 | ||||
-rw-r--r-- | gcc/tree.c | 3 |
24 files changed, 297 insertions, 91 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 09bc243ef7f..b7e853d061d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,43 @@ 2015-12-02 Richard Sandiford <richard.sandiford@arm.com> + PR tree-optimization/68432 + * coretypes.h (optimization_type): New enum. + * doc/tm.texi.in (TARGET_OPTAB_SUPPORTED_P): New hook. + * doc/tm.texi: Regenerate. + * target.def (optab_supported_p): New hook. + * targhooks.h (default_optab_supported_p): Declare. + * targhooks.c (default_optab_supported_p): New function. + * predict.h (function_optimization_type): Declare. + (bb_optimization_type): Likewise. + * predict.c (function_optimization_type): New function. + (bb_optimization_type): Likewise. + * optabs-query.h (convert_optab_handler): Define an overload + that takes an optimization type. + (direct_optab_handler): Likewise. + * optabs-query.c (convert_optab_handler): Likewise. + (direct_optab_handler): Likewise. + * internal-fn.h (direct_internal_fn_supported_p): Take an + optimization_type argument. + * internal-fn.c (direct_optab_supported_p): Likewise. + (multi_vector_optab_supported_p): Likewise. + (direct_internal_fn_supported_p): Likewise. + * builtins.c (replacement_internal_fn): Update call to + direct_internal_fn_supported_p. + * gimple-match-head.c (build_call_internal): Likewise. + * tree-vect-patterns.c (vect_recog_pow_pattern): Likewise. + * tree-vect-stmts.c (vectorizable_internal_function): Likewise. + * tree.c (maybe_build_call_expr_loc): Likewise. + * config/i386/i386.c (ix86_optab_supported_p): New function. + (TARGET_OPTAB_SUPPORTED_P): Define. + * config/i386/i386.md (asinxf2): Remove optimize_insn_for_size_p check. + (asin<mode>2, acosxf2, acos<mode>2, log1pxf2, log1p<mode>2) + (expNcorexf3, expxf2, exp<mode>2, exp10xf2, exp10<mode>2, exp2xf2) + (exp2<mode>2, expm1xf2, expm1<mode>2, ldexpxf3, ldexp<mode>3) + (scalbxf3, scalb<mode>3, rint<mode>2, round<mode>2) + (<rounding_insn>xf2, <rounding_insn><mode>2): Likewise. + +2015-12-02 Richard Sandiford <richard.sandiford@arm.com> + * Makefile.in (GENSUPPORT_H): New macro. (build/gensupport.o, build/read-rtl.o, build/genattr.o) (build/genattr-common.o, build/genattrtab.o, build/genautomata.o) diff --git a/gcc/builtins.c b/gcc/builtins.c index df5c4930997..7c614e6336e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1962,7 +1962,8 @@ replacement_internal_fn (gcall *call) if (ifn != IFN_LAST) { tree_pair types = direct_internal_fn_types (ifn, call); - if (direct_internal_fn_supported_p (ifn, types)) + optimization_type opt_type = bb_optimization_type (gimple_bb (call)); + if (direct_internal_fn_supported_p (ifn, types, opt_type)) return ifn; } } diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 23a42734007..05e7fe6d39a 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -54100,6 +54100,49 @@ ix86_operands_ok_for_move_multiple (rtx *operands, bool load, return true; } +/* Implement the TARGET_OPTAB_SUPPORTED_P hook. */ + +static bool +ix86_optab_supported_p (int op, machine_mode mode1, machine_mode, + optimization_type opt_type) +{ + switch (op) + { + case asin_optab: + case acos_optab: + case log1p_optab: + case exp_optab: + case exp10_optab: + case exp2_optab: + case expm1_optab: + case ldexp_optab: + case scalb_optab: + case round_optab: + return opt_type == OPTIMIZE_FOR_SPEED; + + case rint_optab: + if (SSE_FLOAT_MODE_P (mode1) + && TARGET_SSE_MATH + && !flag_trapping_math + && !TARGET_ROUND) + return opt_type == OPTIMIZE_FOR_SPEED; + return true; + + case floor_optab: + case ceil_optab: + case btrunc_optab: + if (SSE_FLOAT_MODE_P (mode1) + && TARGET_SSE_MATH + && !flag_trapping_math + && TARGET_ROUND) + return true; + return opt_type == OPTIMIZE_FOR_SPEED; + + default: + return true; + } +} + /* Address space support. This is not "far pointers" in the 16-bit sense, but an easy way @@ -54645,6 +54688,9 @@ ix86_addr_space_zero_address_valid (addr_space_t as) #undef TARGET_ABSOLUTE_BIGGEST_ALIGNMENT #define TARGET_ABSOLUTE_BIGGEST_ALIGNMENT 512 +#undef TARGET_OPTAB_SUPPORTED_P +#define TARGET_OPTAB_SUPPORTED_P ix86_optab_supported_p + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-i386.h" diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index cbb9ffd86af..e8c5f061331 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -14726,9 +14726,6 @@ { int i; - if (optimize_insn_for_size_p ()) - FAIL; - for (i = 2; i < 6; i++) operands[i] = gen_reg_rtx (XFmode); @@ -14746,9 +14743,6 @@ rtx op0 = gen_reg_rtx (XFmode); rtx op1 = gen_reg_rtx (XFmode); - if (optimize_insn_for_size_p ()) - FAIL; - emit_insn (gen_extend<mode>xf2 (op1, operands[1])); emit_insn (gen_asinxf2 (op0, op1)); emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0)); @@ -14770,9 +14764,6 @@ { int i; - if (optimize_insn_for_size_p ()) - FAIL; - for (i = 2; i < 6; i++) operands[i] = gen_reg_rtx (XFmode); @@ -14790,9 +14781,6 @@ rtx op0 = gen_reg_rtx (XFmode); rtx op1 = gen_reg_rtx (XFmode); - if (optimize_insn_for_size_p ()) - FAIL; - emit_insn (gen_extend<mode>xf2 (op1, operands[1])); emit_insn (gen_acosxf2 (op0, op1)); emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0)); @@ -14953,9 +14941,6 @@ "TARGET_USE_FANCY_MATH_387 && flag_unsafe_math_optimizations" { - if (optimize_insn_for_size_p ()) - FAIL; - ix86_emit_i387_log1p (operands[0], operands[1]); DONE; }) @@ -14970,9 +14955,6 @@ { rtx op0; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); operands[1] = gen_rtx_FLOAT_EXTEND (XFmode, operands[1]); @@ -15121,9 +15103,6 @@ { int i; - if (optimize_insn_for_size_p ()) - FAIL; - for (i = 3; i < 10; i++) operands[i] = gen_reg_rtx (XFmode); @@ -15138,9 +15117,6 @@ { rtx op2; - if (optimize_insn_for_size_p ()) - FAIL; - op2 = gen_reg_rtx (XFmode); emit_move_insn (op2, standard_80387_constant_rtx (5)); /* fldl2e */ @@ -15158,9 +15134,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); @@ -15178,9 +15151,6 @@ { rtx op2; - if (optimize_insn_for_size_p ()) - FAIL; - op2 = gen_reg_rtx (XFmode); emit_move_insn (op2, standard_80387_constant_rtx (6)); /* fldl2t */ @@ -15198,9 +15168,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); @@ -15218,9 +15185,6 @@ { rtx op2; - if (optimize_insn_for_size_p ()) - FAIL; - op2 = gen_reg_rtx (XFmode); emit_move_insn (op2, CONST1_RTX (XFmode)); /* fld1 */ @@ -15238,9 +15202,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); @@ -15278,9 +15239,6 @@ { int i; - if (optimize_insn_for_size_p ()) - FAIL; - for (i = 2; i < 13; i++) operands[i] = gen_reg_rtx (XFmode); @@ -15300,9 +15258,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); @@ -15320,8 +15275,6 @@ && flag_unsafe_math_optimizations" { rtx tmp1, tmp2; - if (optimize_insn_for_size_p ()) - FAIL; tmp1 = gen_reg_rtx (XFmode); tmp2 = gen_reg_rtx (XFmode); @@ -15343,9 +15296,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); @@ -15366,9 +15316,6 @@ "TARGET_USE_FANCY_MATH_387 && flag_unsafe_math_optimizations" { - if (optimize_insn_for_size_p ()) - FAIL; - operands[3] = gen_reg_rtx (XFmode); }) @@ -15383,9 +15330,6 @@ { rtx op0, op1, op2; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); op2 = gen_reg_rtx (XFmode); @@ -15463,8 +15407,6 @@ if (TARGET_ROUND) emit_insn (gen_sse4_1_round<mode>2 (operands[0], operands[1], GEN_INT (ROUND_MXCSR))); - else if (optimize_insn_for_size_p ()) - FAIL; else ix86_expand_rint (operands[0], operands[1]); } @@ -15491,9 +15433,6 @@ || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH && !flag_trapping_math && !flag_rounding_math)" { - if (optimize_insn_for_size_p ()) - FAIL; - if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH && !flag_trapping_math && !flag_rounding_math) { @@ -15747,8 +15686,7 @@ FRNDINT_ROUNDING)) (clobber (reg:CC FLAGS_REG))])] "TARGET_USE_FANCY_MATH_387 - && flag_unsafe_math_optimizations - && !optimize_insn_for_size_p ()") + && flag_unsafe_math_optimizations") (define_expand "<rounding_insn><mode>2" [(parallel [(set (match_operand:MODEF 0 "register_operand") @@ -15768,8 +15706,6 @@ if (TARGET_ROUND) emit_insn (gen_sse4_1_round<mode>2 (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>))); - else if (optimize_insn_for_size_p ()) - FAIL; else if (TARGET_64BIT || (<MODE>mode != DFmode)) { if (ROUND_<ROUNDING> == ROUND_FLOOR) @@ -15797,9 +15733,6 @@ { rtx op0, op1; - if (optimize_insn_for_size_p ()) - FAIL; - op0 = gen_reg_rtx (XFmode); op1 = gen_reg_rtx (XFmode); emit_insn (gen_extend<mode>xf2 (op1, operands[1])); diff --git a/gcc/coretypes.h b/gcc/coretypes.h index d4a75db3b28..5a9fb630527 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -200,6 +200,18 @@ enum node_frequency { NODE_FREQUENCY_HOT }; +/* Ways of optimizing code. */ +enum optimization_type { + /* Prioritize speed over size. */ + OPTIMIZE_FOR_SPEED, + + /* Only do things that are good for both size and speed. */ + OPTIMIZE_FOR_BOTH, + + /* Prioritize size over speed. */ + OPTIMIZE_FOR_SIZE +}; + /* Possible initialization status of a variable. When requested by the user, this information is tracked and recorded in the DWARF debug information, along with the variable's location. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 7146ec55836..a84ad5723b6 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -6425,6 +6425,20 @@ Define this macro if a non-short-circuit operation produced by @code{BRANCH_COST} is greater than or equal to the value 2. @end defmac +@deftypefn {Target Hook} bool TARGET_OPTAB_SUPPORTED_P (int @var{op}, machine_mode @var{mode1}, machine_mode @var{mode2}, optimization_type @var{opt_type}) +Return true if the optimizers should use optab @var{op} with +modes @var{mode1} and @var{mode2} for optimization type @var{opt_type}. +The optab is known to have an associated @file{.md} instruction +whose C condition is true. @var{mode2} is only meaningful for conversion +optabs; for direct optabs it is a copy of @var{mode1}. + +For example, when called with @var{op} equal to @code{rint_optab} and +@var{mode1} equal to @code{DFmode}, the hook should say whether the +optimizers should use optab @code{rintdf2}. + +The default hook returns true for all inputs. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, machine_mode @var{mode}, int @var{outer_code}, int @var{opno}, int *@var{total}, bool @var{speed}) This target hook describes the relative costs of RTL expressions. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 0677fc1c8cc..a0a0a812fc1 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -4746,6 +4746,8 @@ Define this macro if a non-short-circuit operation produced by @code{BRANCH_COST} is greater than or equal to the value 2. @end defmac +@hook TARGET_OPTAB_SUPPORTED_P + @hook TARGET_RTX_COSTS @hook TARGET_ADDRESS_COST diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c index bdc1f982864..049ebab3f47 100644 --- a/gcc/gimple-match-head.c +++ b/gcc/gimple-match-head.c @@ -261,7 +261,7 @@ build_call_internal (internal_fn fn, tree type, unsigned int nargs, tree *ops) if (direct_internal_fn_p (fn)) { tree_pair types = direct_internal_fn_types (fn, type, ops); - if (!direct_internal_fn_supported_p (fn, types)) + if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH)) return NULL; } return gimple_build_call_internal (fn, nargs, ops[0], ops[1], ops[2]); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index b15657f442b..2be2d8806f1 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -2214,23 +2214,30 @@ direct_internal_fn_types (internal_fn fn, gcall *call) } /* Return true if OPTAB is supported for TYPES (whose modes should be - the same). Used for simple direct optabs. */ + the same) when the optimization type is OPT_TYPE. Used for simple + direct optabs. */ static bool -direct_optab_supported_p (direct_optab optab, tree_pair types) +direct_optab_supported_p (direct_optab optab, tree_pair types, + optimization_type opt_type) { machine_mode mode = TYPE_MODE (types.first); gcc_checking_assert (mode == TYPE_MODE (types.second)); - return direct_optab_handler (optab, mode) != CODE_FOR_nothing; + return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing; } /* Return true if load/store lanes optab OPTAB is supported for - array type TYPES.first. */ + array type TYPES.first when the optimization type is OPT_TYPE. */ static bool -multi_vector_optab_supported_p (convert_optab optab, tree_pair types) +multi_vector_optab_supported_p (convert_optab optab, tree_pair types, + optimization_type opt_type) { - return get_multi_vector_move (types.first, optab) != CODE_FOR_nothing; + gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE); + machine_mode imode = TYPE_MODE (types.first); + machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first)); + return (convert_optab_handler (optab, imode, vmode, opt_type) + != CODE_FOR_nothing); } #define direct_unary_optab_supported_p direct_optab_supported_p @@ -2240,12 +2247,14 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types) #define direct_mask_store_optab_supported_p direct_optab_supported_p #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p -/* Return true if FN is supported for the types in TYPES. The types - are those associated with the "type0" and "type1" fields of FN's - direct_internal_fn_info structure. */ +/* Return true if FN is supported for the types in TYPES when the + optimization type is OPT_TYPE. The types are those associated with + the "type0" and "type1" fields of FN's direct_internal_fn_info + structure. */ bool -direct_internal_fn_supported_p (internal_fn fn, tree_pair types) +direct_internal_fn_supported_p (internal_fn fn, tree_pair types, + optimization_type opt_type) { switch (fn) { @@ -2253,7 +2262,8 @@ direct_internal_fn_supported_p (internal_fn fn, tree_pair types) case IFN_##CODE: break; #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \ case IFN_##CODE: \ - return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types); + return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \ + opt_type); #include "internal-fn.def" case IFN_LAST: @@ -2262,16 +2272,17 @@ direct_internal_fn_supported_p (internal_fn fn, tree_pair types) gcc_unreachable (); } -/* Return true if FN is supported for type TYPE. The caller knows that - the "type0" and "type1" fields of FN's direct_internal_fn_info - structure are the same. */ +/* Return true if FN is supported for type TYPE when the optimization + type is OPT_TYPE. The caller knows that the "type0" and "type1" + fields of FN's direct_internal_fn_info structure are the same. */ bool -direct_internal_fn_supported_p (internal_fn fn, tree type) +direct_internal_fn_supported_p (internal_fn fn, tree type, + optimization_type opt_type) { const direct_internal_fn_info &info = direct_internal_fn (fn); gcc_checking_assert (info.type0 == info.type1); - return direct_internal_fn_supported_p (fn, tree_pair (type, type)); + return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type); } /* Return true if IFN_SET_EDOM is supported. */ diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h index aea6abdaf7e..ef27f09cdc9 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -166,8 +166,10 @@ direct_internal_fn (internal_fn fn) extern tree_pair direct_internal_fn_types (internal_fn, tree, tree *); extern tree_pair direct_internal_fn_types (internal_fn, gcall *); -extern bool direct_internal_fn_supported_p (internal_fn, tree_pair); -extern bool direct_internal_fn_supported_p (internal_fn, tree); +extern bool direct_internal_fn_supported_p (internal_fn, tree_pair, + optimization_type); +extern bool direct_internal_fn_supported_p (internal_fn, tree, + optimization_type); extern bool set_edom_supported_p (void); extern void expand_internal_call (gcall *); diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c index c20597c7bcb..2f9c7cde278 100644 --- a/gcc/optabs-query.c +++ b/gcc/optabs-query.c @@ -35,6 +35,36 @@ struct target_optabs *this_fn_optabs = &default_target_optabs; struct target_optabs *this_target_optabs = &default_target_optabs; #endif +/* Return the insn used to perform conversion OP from mode FROM_MODE + to mode TO_MODE; return CODE_FOR_nothing if the target does not have + such an insn, or if it is unsuitable for optimization type OPT_TYPE. */ + +insn_code +convert_optab_handler (convert_optab optab, machine_mode to_mode, + machine_mode from_mode, optimization_type opt_type) +{ + insn_code icode = convert_optab_handler (optab, to_mode, from_mode); + if (icode == CODE_FOR_nothing + || !targetm.optab_supported_p (optab, to_mode, from_mode, opt_type)) + return CODE_FOR_nothing; + return icode; +} + +/* Return the insn used to implement mode MODE of OP; return + CODE_FOR_nothing if the target does not have such an insn, + or if it is unsuitable for optimization type OPT_TYPE. */ + +insn_code +direct_optab_handler (convert_optab optab, machine_mode mode, + optimization_type opt_type) +{ + insn_code icode = direct_optab_handler (optab, mode); + if (icode == CODE_FOR_nothing + || !targetm.optab_supported_p (optab, mode, mode, opt_type)) + return CODE_FOR_nothing; + return icode; +} + /* Enumerates the possible types of structure operand to an extraction_insn. */ enum extraction_type { ET_unaligned_mem, ET_reg }; diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h index 48bcf7c71d2..8a5f042b461 100644 --- a/gcc/optabs-query.h +++ b/gcc/optabs-query.h @@ -46,6 +46,9 @@ convert_optab_handler (convert_optab op, machine_mode to_mode, return raw_optab_handler (scode); } +enum insn_code convert_optab_handler (convert_optab, machine_mode, + machine_mode, optimization_type); + /* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing if the target does not have such an insn. */ @@ -55,6 +58,9 @@ direct_optab_handler (direct_optab op, machine_mode mode) return optab_handler (op, mode); } +enum insn_code direct_optab_handler (convert_optab, machine_mode, + optimization_type); + /* Return true if UNOPTAB is for a trapping-on-overflow operation. */ inline bool diff --git a/gcc/predict.c b/gcc/predict.c index 7e0f848f177..d5c40def863 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -269,6 +269,16 @@ optimize_function_for_speed_p (struct function *fun) return !optimize_function_for_size_p (fun); } +/* Return the optimization type that should be used for the function FUN. */ + +optimization_type +function_optimization_type (struct function *fun) +{ + return (optimize_function_for_speed_p (fun) + ? OPTIMIZE_FOR_SPEED + : OPTIMIZE_FOR_SIZE); +} + /* Return TRUE when BB should be optimized for size. */ bool @@ -286,6 +296,16 @@ optimize_bb_for_speed_p (const_basic_block bb) return !optimize_bb_for_size_p (bb); } +/* Return the optimization type that should be used for block BB. */ + +optimization_type +bb_optimization_type (const_basic_block bb) +{ + return (optimize_bb_for_speed_p (bb) + ? OPTIMIZE_FOR_SPEED + : OPTIMIZE_FOR_SIZE); +} + /* Return TRUE when BB should be optimized for size. */ bool diff --git a/gcc/predict.h b/gcc/predict.h index 85150fe8b6f..486ce171f87 100644 --- a/gcc/predict.h +++ b/gcc/predict.h @@ -54,8 +54,10 @@ extern bool probably_never_executed_bb_p (struct function *, const_basic_block); extern bool probably_never_executed_edge_p (struct function *, edge); extern bool optimize_function_for_size_p (struct function *); extern bool optimize_function_for_speed_p (struct function *); +extern optimization_type function_optimization_type (struct function *); extern bool optimize_bb_for_size_p (const_basic_block); extern bool optimize_bb_for_speed_p (const_basic_block); +extern optimization_type bb_optimization_type (const_basic_block); extern bool optimize_edge_for_size_p (edge); extern bool optimize_edge_for_speed_p (edge); extern bool optimize_insn_for_size_p (void); diff --git a/gcc/target.def b/gcc/target.def index 1d40012c5a2..197189282b1 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -3434,6 +3434,23 @@ move would be greater than that of a library call.", enum by_pieces_operation op, bool speed_p), default_use_by_pieces_infrastructure_p) +DEFHOOK +(optab_supported_p, + "Return true if the optimizers should use optab @var{op} with\n\ +modes @var{mode1} and @var{mode2} for optimization type @var{opt_type}.\n\ +The optab is known to have an associated @file{.md} instruction\n\ +whose C condition is true. @var{mode2} is only meaningful for conversion\n\ +optabs; for direct optabs it is a copy of @var{mode1}.\n\ +\n\ +For example, when called with @var{op} equal to @code{rint_optab} and\n\ +@var{mode1} equal to @code{DFmode}, the hook should say whether the\n\ +optimizers should use optab @code{rintdf2}.\n\ +\n\ +The default hook returns true for all inputs.", + bool, (int op, machine_mode mode1, machine_mode mode2, + optimization_type opt_type), + default_optab_supported_p) + /* True for MODE if the target expects that registers in this mode will be allocated to registers in a small register class. The compiler is allowed to use registers explicitly used in the rtl as spill registers diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 3868230c662..70456096542 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1953,4 +1953,12 @@ can_use_doloop_if_innermost (const widest_int &, const widest_int &, return loop_depth == 1; } +/* Default implementation of TARGET_OPTAB_SUPPORTED_P. */ + +bool +default_optab_supported_p (int, machine_mode, machine_mode, optimization_type) +{ + return true; +} + #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index c8094704c09..281b5fed1fb 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -250,4 +250,7 @@ extern void default_setup_incoming_vararg_bounds (cumulative_args_t ca ATTRIBUTE tree type ATTRIBUTE_UNUSED, int *pretend_arg_size ATTRIBUTE_UNUSED, int second_time ATTRIBUTE_UNUSED); +extern bool default_optab_supported_p (int, machine_mode, machine_mode, + optimization_type); + #endif /* GCC_TARGHOOKS_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1ef533d908a..0d686b2d5e8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-12-02 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/i386/pr68432-1.c: New test. + * gcc.target/i386/pr68432-2.c: Likewise. + * gcc.target/i386/pr68432-3.c: Likewise. + 2015-12-02 Andreas Krebbel <krebbel@linux.vnet.ibm.com> * gcc.target/s390/zvector/vec-splat-2.c: New test. diff --git a/gcc/testsuite/gcc.target/i386/pr68432-1.c b/gcc/testsuite/gcc.target/i386/pr68432-1.c new file mode 100644 index 00000000000..8493652369e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr68432-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */ + +float +f1 (float f) +{ + return __builtin_rintf (f); +} + +double +f2 (double f) +{ + return __builtin_rint (f); +} + +/* { dg-final { scan-assembler-times "\tucomiss\t" 1 } } */ +/* { dg-final { scan-assembler-times "\tucomisd\t" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr68432-2.c b/gcc/testsuite/gcc.target/i386/pr68432-2.c new file mode 100644 index 00000000000..8a0c2955895 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr68432-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */ + +float +f1 (float f) +{ + return __builtin_rintf (f); +} + +double +f2 (double f) +{ + return __builtin_rint (f); +} + +/* { dg-final { scan-assembler-not "\tucomiss\t" } } */ +/* { dg-final { scan-assembler-not "\tucomisd\t" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr68432-3.c b/gcc/testsuite/gcc.target/i386/pr68432-3.c new file mode 100644 index 00000000000..5f22972338e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr68432-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -msse2 -mfpmath=sse" } */ + +float __attribute__ ((cold)) +f1 (float f) +{ + return __builtin_rintf (f); +} + +double __attribute__ ((cold)) +f2 (double f) +{ + return __builtin_rint (f); +} + +/* { dg-final { scan-assembler-not "\tucomiss\t" } } */ +/* { dg-final { scan-assembler-not "\tucomisd\t" } } */ diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 5bab1f57a18..cd142e13903 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -1056,7 +1056,9 @@ vect_recog_pow_pattern (vec<gimple *> *stmts, tree *type_in, && real_equal (&TREE_REAL_CST (exp), &dconsthalf)) { *type_in = get_vectype_for_scalar_type (TREE_TYPE (base)); - if (*type_in && direct_internal_fn_supported_p (IFN_SQRT, *type_in)) + if (*type_in + && direct_internal_fn_supported_p (IFN_SQRT, *type_in, + OPTIMIZE_FOR_SPEED)) { gcall *stmt = gimple_build_call_internal (IFN_SQRT, 1, base); var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt); diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0b0c4685f7d..9f116528b47 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -1681,7 +1681,8 @@ vectorizable_internal_function (combined_fn cfn, tree fndecl, { tree type0 = (info.type0 < 0 ? vectype_out : vectype_in); tree type1 = (info.type1 < 0 ? vectype_out : vectype_in); - if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1))) + if (direct_internal_fn_supported_p (ifn, tree_pair (type0, type1), + OPTIMIZE_FOR_SPEED)) return ifn; } } diff --git a/gcc/tree.c b/gcc/tree.c index 2387debccb2..4f7ce7e5070 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -11118,7 +11118,8 @@ maybe_build_call_expr_loc (location_t loc, combined_fn fn, tree type, if (direct_internal_fn_p (ifn)) { tree_pair types = direct_internal_fn_types (ifn, type, argarray); - if (!direct_internal_fn_supported_p (ifn, types)) + if (!direct_internal_fn_supported_p (ifn, types, + OPTIMIZE_FOR_BOTH)) return NULL_TREE; } return build_call_expr_internal_loc_array (loc, ifn, type, n, argarray); |