@@ -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;
}
}
@@ -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. */
@@ -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]);
@@ -2214,23 +2214,28 @@ 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;
+ insn_code icode = direct_optab_handler (optab, mode);
+ return optab_supported_p (icode, opt_type);
}
/* 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;
+ insn_code icode = get_multi_vector_move (types.first, optab);
+ return optab_supported_p (icode, opt_type);
}
#define direct_unary_optab_supported_p direct_optab_supported_p
@@ -2240,12 +2245,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 +2260,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 +2270,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. */
@@ -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 *);
@@ -35,6 +35,36 @@ struct target_optabs *this_fn_optabs = &default_target_optabs;
struct target_optabs *this_target_optabs = &default_target_optabs;
#endif
+/* Return true if ICODE is a valid instruction number and the instruction
+ is supported for optimization type OPT_TYPE. We allow CODE_FOR_nothing
+ to be passed so that callers can use this function instead of, rather
+ than as well as, an explicit check for CODE_nothing. */
+
+bool
+optab_supported_p (insn_code icode, optimization_type opt_type)
+{
+ if (icode == CODE_FOR_nothing)
+ return false;
+
+ switch (opt_type)
+ {
+ case OPTIMIZE_FOR_SPEED:
+ return (get_bool_attr_mask (icode, BA_PREFERRED_FOR_SPEED)
+ == get_bool_attr_mask (icode, BA_ENABLED));
+
+ case OPTIMIZE_FOR_SIZE:
+ return (get_bool_attr_mask (icode, BA_PREFERRED_FOR_SIZE)
+ == get_bool_attr_mask (icode, BA_ENABLED));
+
+ case OPTIMIZE_FOR_BOTH:
+ /* Require the choice to be good for both size and speed. */
+ return ((get_bool_attr_mask (icode, BA_PREFERRED_FOR_SIZE)
+ & get_bool_attr_mask (icode, BA_PREFERRED_FOR_SPEED))
+ == get_bool_attr_mask (icode, BA_ENABLED));
+ }
+ gcc_unreachable ();
+}
+
/* Enumerates the possible types of structure operand to an
extraction_insn. */
enum extraction_type { ET_unaligned_mem, ET_reg };
@@ -136,6 +136,7 @@ bool get_best_mem_extraction_insn (extraction_insn *,
enum extraction_pattern,
HOST_WIDE_INT, HOST_WIDE_INT, machine_mode);
+bool optab_supported_p (insn_code, optimization_type);
enum insn_code can_extend_p (machine_mode, machine_mode, int);
enum insn_code can_float_p (machine_mode, machine_mode, int);
enum insn_code can_fix_p (machine_mode, machine_mode, int, bool *);
@@ -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
@@ -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);
@@ -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);
@@ -1663,7 +1663,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;
}
}
@@ -11124,7 +11124,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);