[(set_attr "type" "vector")]
)
+(define_expand "vcond_mask_len_<mode>"
+ [(match_operand:V 0 "register_operand")
+ (match_operand:<VM> 1 "nonmemory_operand")
+ (match_operand:V 2 "nonmemory_operand")
+ (match_operand:V 3 "autovec_else_operand")
+ (match_operand 4 "autovec_length_operand")
+ (match_operand 5 "const_0_operand")]
+ "TARGET_VECTOR"
+ {
+ if (satisfies_constraint_Wc1 (operands[1]))
+ riscv_vector::expand_cond_len_unop (code_for_pred_mov (<MODE>mode),
+ operands);
+ else
+ {
+ /* The order of then and else is opposite to pred_merge. */
+ rtx ops[] = {operands[0], operands[3], operands[3], operands[2],
+ operands[1]};
+ riscv_vector::emit_nonvlmax_insn (code_for_pred_merge (<MODE>mode),
+ riscv_vector::MERGE_OP_TU,
+ ops, operands[4]);
+ }
+ DONE;
+ }
+ [(set_attr "type" "vector")]
+)
+
;; -------------------------------------------------------------------------
;; ---- [BOOL] Select based on masks
;; -------------------------------------------------------------------------
/* For vmerge, no mask operand, no mask policy operand. */
MERGE_OP = __NORMAL_OP_TA2 | TERNARY_OP_P,
+ /* For vmerge with TU policy. */
+ MERGE_OP_TU = HAS_DEST_P | HAS_MERGE_P | TERNARY_OP_P | TU_POLICY_P,
+
/* For vm<compare>, no tail policy operand. */
COMPARE_OP = __NORMAL_OP_MA | TERNARY_OP_P,
COMPARE_OP_MU = __MASK_OP_MU | TERNARY_OP_P,
&& icode != maybe_code_for_pred_widen (FLOAT, mode)
&& icode != maybe_code_for_pred_widen (UNSIGNED_FLOAT, mode)
/* vfsgnj */
- && icode != maybe_code_for_pred (UNSPEC_VCOPYSIGN, mode);
+ && icode != maybe_code_for_pred (UNSPEC_VCOPYSIGN, mode)
+ && icode != maybe_code_for_pred_mov (mode);
}
/* Subroutine to expand COND_LEN_* patterns. */
Similar to @code{vcond@var{m}@var{n}} but operand 3 holds a pre-computed
result of vector comparison.
+@cindex @code{vcond_mask_len_@var{m}@var{n}} instruction pattern
+@item @samp{vcond_mask_@var{m}@var{n}}
+Set each element of operand 0 to the corresponding element of operand 2
+or operand 3. Choose operand 2 if both the element index is less than
+operand 4 plus operand 5 and the corresponding element of operand 1
+is nonzero:
+
+@smallexample
+for (i = 0; i < GET_MODE_NUNITS (@var{m}); i++)
+ op0[i] = i < op4 + op5 && op1[i] ? op2[i] : op3[i];
+@end smallexample
+
+Operands 0, 2 and 3 have mode @var{m}. Operand 1 has mode @var{n}.
+Operands 4 and 5 have a target-dependent scalar integer mode.
+
@cindex @code{maskload@var{m}@var{n}} instruction pattern
@item @samp{maskload@var{m}@var{n}}
Perform a masked load of vector from memory operand 1 of mode @var{m}
&& VECTOR_TYPE_P (res_op->type)
&& gimple_simplified_result_is_gimple_val (res_op))
{
- new_op.set_op (VEC_COND_EXPR, res_op->type,
- res_op->cond.cond, res_op->ops[0],
- res_op->cond.else_value);
+ tree len = res_op->cond.len;
+ if (!len)
+ new_op.set_op (VEC_COND_EXPR, res_op->type,
+ res_op->cond.cond, res_op->ops[0],
+ res_op->cond.else_value);
+ else
+ new_op.set_op (IFN_VCOND_MASK_LEN, res_op->type,
+ res_op->cond.cond, res_op->ops[0],
+ res_op->cond.else_value,
+ res_op->cond.len, res_op->cond.bias);
*res_op = new_op;
return gimple_resimplify3 (seq, res_op, valueize);
}
enum uncond { UNCOND };
/* Build an unconditional op. */
- gimple_match_cond (uncond) : cond (NULL_TREE), else_value (NULL_TREE) {}
+ gimple_match_cond (uncond) : cond (NULL_TREE), else_value (NULL_TREE), len
+ (NULL_TREE), bias (NULL_TREE) {}
gimple_match_cond (tree, tree);
gimple_match_cond (tree, tree, tree, tree);
inline
gimple_match_cond::gimple_match_cond (tree cond_in, tree else_value_in)
- : cond (cond_in), else_value (else_value_in)
+ : cond (cond_in), else_value (else_value_in), len (NULL_TREE),
+ bias (NULL_TREE)
{
}
#define store_lanes_direct { 0, 0, false }
#define mask_store_lanes_direct { 0, 0, false }
#define vec_cond_mask_direct { 1, 0, false }
+#define vec_cond_mask_len_direct { 1, 1, false }
#define vec_cond_direct { 2, 0, false }
#define scatter_store_direct { 3, 1, false }
#define len_store_direct { 3, 3, false }
case IFN_MASK_LEN_STORE:
case IFN_MASK_LEN_LOAD_LANES:
case IFN_MASK_LEN_STORE_LANES:
+ case IFN_VCOND_MASK_LEN:
return 3;
default:
case IFN_MASK_LEN_SCATTER_STORE:
return 4;
+ case IFN_VCOND_MASK_LEN:
+ return 0;
+
default:
return (conditional_internal_fn_code (fn) != ERROR_MARK
|| get_unconditional_internal_fn (fn) != IFN_LAST ? 0 : -1);
DEF_INTERNAL_OPTAB_FN (VCONDEQ, ECF_CONST | ECF_NOTHROW, vcondeq, vec_cond)
DEF_INTERNAL_OPTAB_FN (VCOND_MASK, ECF_CONST | ECF_NOTHROW,
vcond_mask, vec_cond_mask)
+DEF_INTERNAL_OPTAB_FN (VCOND_MASK_LEN, ECF_CONST | ECF_NOTHROW,
+ vcond_mask_len, cond_len_unary)
DEF_INTERNAL_OPTAB_FN (VEC_SET, ECF_CONST | ECF_NOTHROW, vec_set, vec_set)
DEF_INTERNAL_OPTAB_FN (VEC_EXTRACT, ECF_CONST | ECF_NOTHROW,
negate bit_not)
(define_operator_list COND_UNARY
IFN_COND_NEG IFN_COND_NOT)
+(define_operator_list COND_LEN_UNARY
+ IFN_COND_LEN_NEG IFN_COND_LEN_NOT)
/* Binary operations and their associated IFN_COND_* function. */
(define_operator_list UNCOND_BINARY
&& is_truth_type_for (op_type, TREE_TYPE (@0)))
(cond_op (bit_not @0) @2 @1)))))
+(for uncond_op (UNCOND_UNARY)
+ cond_op (COND_LEN_UNARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@3 @1)) @2 @4 @5)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0)))
+ (cond_op @0 @1 @2 @4 @5))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@3 @2)) @4 @5)
+ (with { tree op_type = TREE_TYPE (@3); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0)))
+ (cond_op (bit_not @0) @2 @1 @4 @5)))))
+
/* `(a ? -1 : 0) ^ b` can be converted into a conditional not. */
(simplify
(bit_xor:c (vec_cond @0 uniform_integer_cst_p@1 uniform_integer_cst_p@2) @3)
&& single_use (@4))
(view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1)))))))
+(for uncond_op (UNCOND_BINARY)
+ cond_op (COND_LEN_BINARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@4 @1 @2)) @3 @5 @6)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@4))
+ (view_convert (cond_op @0 @1 @2 (view_convert:op_type @3) @5 @6)))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@4 @2 @3)) @5 @6)
+ (with { tree op_type = TREE_TYPE (@4); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@4))
+ (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1) @5 @6))))))
+
/* Same for ternary operations. */
(for uncond_op (UNCOND_TERNARY)
cond_op (COND_TERNARY)
&& single_use (@5))
(view_convert (cond_op (bit_not @0) @2 @3 @4
(view_convert:op_type @1)))))))
+
+(for uncond_op (UNCOND_TERNARY)
+ cond_op (COND_LEN_TERNARY)
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@5 @1 @2 @3)) @4 @6 @7)
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@5))
+ (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @4) @6 @7)))))
+ (simplify
+ (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@5 @2 @3 @4 @6 @7)))
+ (with { tree op_type = TREE_TYPE (@5); }
+ (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+ && is_truth_type_for (op_type, TREE_TYPE (@0))
+ && single_use (@5))
+ (view_convert (cond_op (bit_not @0) @2 @3 @4 (view_convert:op_type @1) @6 @7))))))
#endif
/* Detect cases in which a VEC_COND_EXPR effectively replaces the
OPTAB_D (cond_len_fnms_optab, "cond_len_fnms$a")
OPTAB_D (cond_len_neg_optab, "cond_len_neg$a")
OPTAB_D (cond_len_one_cmpl_optab, "cond_len_one_cmpl$a")
+OPTAB_D (vcond_mask_len_optab, "vcond_mask_len_$a")
OPTAB_D (cmov_optab, "cmov$a6")
OPTAB_D (cstore_optab, "cstore$a4")
OPTAB_D (ctrap_optab, "ctrap$a4")
/* { dg-do compile } */
/* { dg-additional-options "-fgimple -fdump-tree-optimized -ffast-math" } */
+/* { dg-additional-options "-fno-vect-cost-model" { target { riscv_v } } } */
double __GIMPLE (ssa, startwith("loop"))
neg_xi (double *x)