static bool arm_vectorize_vec_perm_const_ok (enum machine_mode vmode,
const unsigned char *sel);
+
+static int arm_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
+ tree vectype,
+ int misalign ATTRIBUTE_UNUSED);
+static unsigned arm_add_stmt_cost (void *data, int count,
+ enum vect_cost_for_stmt kind,
+ struct _stmt_vec_info *stmt_info,
+ int misalign,
+ enum vect_cost_model_location where);
+
static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
bool op0_preserve_value);
\f
#define TARGET_VECTORIZE_VEC_PERM_CONST_OK \
arm_vectorize_vec_perm_const_ok
+#undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
+#define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \
+ arm_builtin_vectorization_cost
+#undef TARGET_VECTORIZE_ADD_STMT_COST
+#define TARGET_VECTORIZE_ADD_STMT_COST arm_add_stmt_cost
+
#undef TARGET_CANONICALIZE_COMPARISON
#define TARGET_CANONICALIZE_COMPARISON \
arm_canonicalize_comparison
l1_size, \
l1_line_size
+/* arm generic vectorizer costs. */
+static const
+struct cpu_vec_costs arm_default_vec_cost = {
+ 1, /* scalar_stmt_cost. */
+ 1, /* scalar load_cost. */
+ 1, /* scalar_store_cost. */
+ 1, /* vec_stmt_cost. */
+ 1, /* vec_to_scalar_cost. */
+ 1, /* scalar_to_vec_cost. */
+ 1, /* vec_align_load_cost. */
+ 1, /* vec_unalign_load_cost. */
+ 1, /* vec_unalign_store_cost. */
+ 1, /* vec_store_cost. */
+ 3, /* cond_taken_branch_cost. */
+ 1, /* cond_not_taken_branch_cost. */
+};
+
const struct tune_params arm_slowmul_tune =
{
arm_slowmul_rtx_costs,
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_fastmul_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
/* StrongARM has early execution of branches, so a sequence that is worth
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_xscale_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_9e_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_v6t2_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
/* Generic Cortex tuning. Use more specific tunings if appropriate. */
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_cortex_a15_tune =
arm_default_branch_cost,
true, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
/* Branches can be dual-issued on Cortex-A5, so conditional execution is
arm_cortex_a5_branch_cost,
false, /* Prefer LDRD/STRD. */
{false, false}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_cortex_a9_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
/* The arm_v6m_tune is duplicated from arm_cortex_tune, rather than
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{false, false}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
const struct tune_params arm_fa726te_tune =
arm_default_branch_cost,
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
+ &arm_default_vec_cost, /* Vectorizer costs. */
};
}
}
+/* Vectorizer cost model implementation. */
+
+/* Implement targetm.vectorize.builtin_vectorization_cost. */
+static int
+arm_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
+ tree vectype,
+ int misalign ATTRIBUTE_UNUSED)
+{
+ unsigned elements;
+
+ switch (type_of_cost)
+ {
+ case scalar_stmt:
+ return current_tune->vec_costs->scalar_stmt_cost;
+
+ case scalar_load:
+ return current_tune->vec_costs->scalar_load_cost;
+
+ case scalar_store:
+ return current_tune->vec_costs->scalar_store_cost;
+
+ case vector_stmt:
+ return current_tune->vec_costs->vec_stmt_cost;
+
+ case vector_load:
+ return current_tune->vec_costs->vec_align_load_cost;
+
+ case vector_store:
+ return current_tune->vec_costs->vec_store_cost;
+
+ case vec_to_scalar:
+ return current_tune->vec_costs->vec_to_scalar_cost;
+
+ case scalar_to_vec:
+ return current_tune->vec_costs->scalar_to_vec_cost;
+
+ case unaligned_load:
+ return current_tune->vec_costs->vec_unalign_load_cost;
+
+ case unaligned_store:
+ return current_tune->vec_costs->vec_unalign_store_cost;
+
+ case cond_branch_taken:
+ return current_tune->vec_costs->cond_taken_branch_cost;
+
+ case cond_branch_not_taken:
+ return current_tune->vec_costs->cond_not_taken_branch_cost;
+
+ case vec_perm:
+ case vec_promote_demote:
+ return current_tune->vec_costs->vec_stmt_cost;
+
+ case vec_construct:
+ elements = TYPE_VECTOR_SUBPARTS (vectype);
+ return elements / 2 + 1;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Implement targetm.vectorize.add_stmt_cost. */
+
+static unsigned
+arm_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind,
+ struct _stmt_vec_info *stmt_info, int misalign,
+ enum vect_cost_model_location where)
+{
+ unsigned *cost = (unsigned *) data;
+ unsigned retval = 0;
+
+ if (flag_vect_cost_model)
+ {
+ tree vectype = stmt_info ? stmt_vectype (stmt_info) : NULL_TREE;
+ int stmt_cost = arm_builtin_vectorization_cost (kind, vectype, misalign);
+
+ /* Statements in an inner loop relative to the loop being
+ vectorized are weighted more heavily. The value here is
+ arbitrary and could potentially be improved with analysis. */
+ if (where == vect_body && stmt_info && stmt_in_inner_loop_p (stmt_info))
+ count *= 50; /* FIXME. */
+
+ retval = (unsigned) (count * stmt_cost);
+ cost[where] += retval;
+ }
+
+ return retval;
+}
/* Return true if and only if this insn can dual-issue only as older. */
static bool