RISC-V: Implement autovec abs, vneg, vnot.
Checks
Commit Message
Hi,
this patch implements autovec expanders of abs<mode>2, vneg<mode>2 and
vnot<mode>2 for integers. I also tried to refactor the helper code
in riscv-v.cc a bit. Guess it's not enough to warrant a separate patch
though.
Regards
Robin
gcc/ChangeLog:
* config/riscv/autovec.md (<optab><mode>2): Fix typo.
(abs<mode>2): New expander.
* config/riscv/riscv-protos.h (emit_len_masked_op): Declare.
(emit_len_cmp): Declare.
(enum tail_policy): Add undefined.
(enum mask_policy): Add undefined.
* config/riscv/riscv-v.cc (const_vlmax_p): Fix typo.
(emit_pred_op): Swap mask and dest.
(emit_pred_binop): Dito.
(emit_pred_cmp_op): Dito.
(emit_vlmax_reg_op): Dito.
(emit_len_masked_op): New function.
(emit_len_cmp): New function.
(emit_index_op): Use helper function.
(get_prefer_tail_policy): Rename.
(get_preferred_tail_policy): To this.
(get_prefer_mask_policy): Rename.
(get_preferred_mask_policy): To this.
(slide1_sew64_helper): Dito.
* config/riscv/riscv-vector-builtins.cc (get_tail_policy_for_pred):
Dito.
(get_mask_policy_for_pred): Dito.
* config/riscv/riscv-vsetvl.cc (get_default_ta): Dito.
(get_default_ma): Dito.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
gcc/config/riscv/autovec.md | 51 +++++-
gcc/config/riscv/riscv-protos.h | 8 +-
gcc/config/riscv/riscv-v.cc | 146 ++++++++++++++----
gcc/config/riscv/riscv-vector-builtins.cc | 4 +-
gcc/config/riscv/riscv-vsetvl.cc | 8 +-
.../riscv/rvv/autovec/unop/abs-run.c | 29 ++++
.../riscv/rvv/autovec/unop/abs-rv32gcv.c | 7 +
.../riscv/rvv/autovec/unop/abs-rv64gcv.c | 7 +
.../riscv/rvv/autovec/unop/abs-template.h | 26 ++++
.../riscv/rvv/autovec/unop/vneg-run.c | 29 ++++
.../riscv/rvv/autovec/unop/vneg-rv32gcv.c | 6 +
.../riscv/rvv/autovec/unop/vneg-rv64gcv.c | 6 +
.../riscv/rvv/autovec/unop/vneg-template.h | 17 ++
.../riscv/rvv/autovec/unop/vnot-run.c | 33 ++++
.../riscv/rvv/autovec/unop/vnot-rv32gcv.c | 6 +
.../riscv/rvv/autovec/unop/vnot-rv64gcv.c | 6 +
.../riscv/rvv/autovec/unop/vnot-template.h | 21 +++
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp | 2 +
18 files changed, 377 insertions(+), 35 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
Comments
>> + TAIL_UNDEFINED = -1,
>> + MASK_UNDEFINED = -1,
Why you add this ?
>> + void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
>> + enum mask_policy vma = MASK_UNDEFINED)
No, you should just specify this as TAIL_ANY or MASK_ANY as default value.
>>const_vlmax_p (machine_mode mode)
>>{
>>- poly_uint64 nuints = GET_MODE_NUNITS (mode);
>>+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
>>- return nuints.is_constant ()
>>+ return nunits.is_constant ()
>> /* The vsetivli can only hold register 0~31. */
>>- ? (IN_RANGE (nuints.to_constant (), 0, 31))
>>+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
>> /* Only allowed in VLS-VLMAX mode. */
>> : false;
>>}
Meaningless change ?
>> /* For the instruction that doesn't require TA, we still need a default value
>> to emit vsetvl. We pick up the default value according to prefer policy. */
>> - return (bool) (get_prefer_tail_policy () & 0x1
>> - || (get_prefer_tail_policy () >> 1 & 0x1));
>> + return (bool) (get_preferred_tail_policy () & 0x1
>> + || (get_preferred_tail_policy () >> 1 & 0x1));
>> }
>> /* Get default mask policy. */
>> @@ -576,8 +576,8 @@ get_default_ma ()
>> {
>> /* For the instruction that doesn't require MA, we still need a default value
>> to emit vsetvl. We pick up the default value according to prefer policy. */
>> - return (bool) (get_prefer_mask_policy () & 0x1
>> - || (get_prefer_mask_policy () >> 1 & 0x1));
>> + return (bool) (get_preferred_mask_policy () & 0x1
>> + || (get_preferred_mask_policy () >> 1 & 0x1));
Why you change it ?
>> +/* Emit an RVV comparison. */
>> +static void
>> +emit_pred_cmp (unsigned icode, rtx mask, rtx dest, rtx cmp,
>> + rtx src1, rtx src2,
>> + rtx len, machine_mode mask_mode)
>> +{
>> + insn_expander<9> e;
>> +
>> + e.set_dest_and_mask (dest, mask, mask_mode);
>> +
>> + e.add_input_operand (cmp, GET_MODE (cmp));
>> +
>> + e.add_source_operand (src1, GET_MODE (src1));
>> + e.add_source_operand (src2, GET_MODE (src2));
You are using comparison helper which I added one in my downstream
when I am working on comparison autovec patterns:
I think you can normalize my code with yours:
/* Emit an RVV comparison. If one of SRC1 and SRC2 is a scalar operand, its
data_mode is specified using SCALAR_MODE. */
static void
emit_pred_comparison (unsigned icode, rtx_code rcode, rtx mask, rtx dest,
rtx src1, rtx src2, rtx len, machine_mode mask_mode,
machine_mode scalar_mode = VOIDmode)
{
insn_expander<9> e;
e.set_dest_and_mask (mask, dest, mask_mode);
machine_mode data_mode = GET_MODE (src1);
gcc_assert (VECTOR_MODE_P (GET_MODE (src1))
|| VECTOR_MODE_P (GET_MODE (src2)));
if (!insn_operand_matches ((enum insn_code) icode, e.opno () + 1, src1))
src1 = force_reg (data_mode, src1);
if (!insn_operand_matches ((enum insn_code) icode, e.opno () + 2, src2))
{
if (VECTOR_MODE_P (GET_MODE (src2)))
src2 = force_reg (data_mode, src2);
else
src2 = force_reg (scalar_mode, src2);
}
rtx comparison = gen_rtx_fmt_ee (rcode, mask_mode, src1, src2);
if (!VECTOR_MODE_P (GET_MODE (src2)))
comparison = gen_rtx_fmt_ee (rcode, mask_mode, src1,
gen_rtx_VEC_DUPLICATE (data_mode, src2));
e.add_fixed_operand (comparison);
e.add_fixed_operand (src1);
if (CONST_INT_P (src2))
e.add_integer_operand (src2);
else
e.add_fixed_operand (src2);
e.set_len_and_policy (len, true, false, true);
e.expand ((enum insn_code) icode, false);
}
static void
emit_len_comparison (unsigned icode, rtx_code rcode, rtx dest, rtx src1,
rtx src2, rtx len, machine_mode mask_mode,
machine_mode scalar_mode)
{
emit_pred_comparison (icode, rcode, NULL_RTX, dest, src1, src2, len,
mask_mode, scalar_mode);
}
/* Expand an RVV integer comparison using the RVV equivalent of:
(set TARGET (CODE OP0 OP1)). */
void
expand_vec_cmp_int (rtx target, rtx_code code, rtx op0, rtx op1)
{
machine_mode mask_mode = GET_MODE (target);
machine_mode data_mode = GET_MODE (op0);
insn_code icode;
bool scalar_p = false;
if (CONST_VECTOR_P (op1))
{
rtx elt;
if (const_vec_duplicate_p (op1, &elt))
op1 = elt;
scalar_p = true;
}
switch (code)
{
case LE:
case LEU:
case GT:
case GTU:
if (scalar_p)
icode = code_for_pred_cmp_scalar (data_mode);
else
icode = code_for_pred_cmp (data_mode);
break;
case EQ:
case NE:
if (scalar_p)
icode = code_for_pred_eqne_scalar (data_mode);
else
icode = code_for_pred_cmp (data_mode);
break;
case LT:
case LTU:
if (scalar_p)
icode = code_for_pred_cmp_scalar (data_mode);
else
icode = code_for_pred_ltge (data_mode);
break;
case GE:
case GEU:
if (scalar_p)
icode = code_for_pred_ge_scalar (data_mode);
else
icode = code_for_pred_ltge (data_mode);
break;
default:
break;
}
emit_len_comparison (icode, code, target, op0, op1, NULL, mask_mode,
GET_MODE_INNER (data_mode));
}
This is how I use it:
(define_expand "vec_cmp<mode><vm>"
[(set (match_operand:<VM> 0 "register_operand")
(match_operator:<VM> 1 "comparison_operator"
[(match_operand:VI 2 "register_operand")
(match_operand:VI 3 "nonmemory_operand")]))]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_cmp_int (operands[0], GET_CODE (operands[1]),
operands[2], operands[3]);
DONE;
}
)
I am almost done all comparison autovec patterns, soon will send them after testing.
Thanks.
juzhe.zhong@rivai.ai
From: Robin Dapp
Date: 2023-05-19 19:32
To: gcc-patches; Kito Cheng; juzhe.zhong@rivai.ai; palmer; Michael Collison; jeffreyalaw
CC: rdapp.gcc
Subject: [PATCH] RISC-V: Implement autovec abs, vneg, vnot.
Hi,
this patch implements autovec expanders of abs<mode>2, vneg<mode>2 and
vnot<mode>2 for integers. I also tried to refactor the helper code
in riscv-v.cc a bit. Guess it's not enough to warrant a separate patch
though.
Regards
Robin
gcc/ChangeLog:
* config/riscv/autovec.md (<optab><mode>2): Fix typo.
(abs<mode>2): New expander.
* config/riscv/riscv-protos.h (emit_len_masked_op): Declare.
(emit_len_cmp): Declare.
(enum tail_policy): Add undefined.
(enum mask_policy): Add undefined.
* config/riscv/riscv-v.cc (const_vlmax_p): Fix typo.
(emit_pred_op): Swap mask and dest.
(emit_pred_binop): Dito.
(emit_pred_cmp_op): Dito.
(emit_vlmax_reg_op): Dito.
(emit_len_masked_op): New function.
(emit_len_cmp): New function.
(emit_index_op): Use helper function.
(get_prefer_tail_policy): Rename.
(get_preferred_tail_policy): To this.
(get_prefer_mask_policy): Rename.
(get_preferred_mask_policy): To this.
(slide1_sew64_helper): Dito.
* config/riscv/riscv-vector-builtins.cc (get_tail_policy_for_pred):
Dito.
(get_mask_policy_for_pred): Dito.
* config/riscv/riscv-vsetvl.cc (get_default_ta): Dito.
(get_default_ma): Dito.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
gcc/config/riscv/autovec.md | 51 +++++-
gcc/config/riscv/riscv-protos.h | 8 +-
gcc/config/riscv/riscv-v.cc | 146 ++++++++++++++----
gcc/config/riscv/riscv-vector-builtins.cc | 4 +-
gcc/config/riscv/riscv-vsetvl.cc | 8 +-
.../riscv/rvv/autovec/unop/abs-run.c | 29 ++++
.../riscv/rvv/autovec/unop/abs-rv32gcv.c | 7 +
.../riscv/rvv/autovec/unop/abs-rv64gcv.c | 7 +
.../riscv/rvv/autovec/unop/abs-template.h | 26 ++++
.../riscv/rvv/autovec/unop/vneg-run.c | 29 ++++
.../riscv/rvv/autovec/unop/vneg-rv32gcv.c | 6 +
.../riscv/rvv/autovec/unop/vneg-rv64gcv.c | 6 +
.../riscv/rvv/autovec/unop/vneg-template.h | 17 ++
.../riscv/rvv/autovec/unop/vnot-run.c | 33 ++++
.../riscv/rvv/autovec/unop/vnot-rv32gcv.c | 6 +
.../riscv/rvv/autovec/unop/vnot-rv64gcv.c | 6 +
.../riscv/rvv/autovec/unop/vnot-template.h | 21 +++
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp | 2 +
18 files changed, 377 insertions(+), 35 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index ce0b46537ad..8060a5cdf90 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -161,7 +161,7 @@ (define_expand "<optab><mode>3"
})
;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vv/vsra.vv/vsrl.vv
@@ -180,3 +180,52 @@ (define_expand "v<optab><mode>3"
NULL_RTX, <VM>mode);
DONE;
})
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+ [(set (match_operand:VI 0 "register_operand")
+ (any_int_unop:VI
+ (match_operand:VI 1 "register_operand")))]
+ "TARGET_VECTOR"
+{
+ riscv_vector::emit_len_op (code_for_pred (<CODE>, <MODE>mode),
+ operands[0], operands[1], NULL_RTX, <VM>mode);
+ DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+ [(set (match_operand:VI 0 "register_operand")
+ (match_operand:VI 1 "register_operand"))]
+ "TARGET_VECTOR"
+{
+ // Create a zero constant.
+ rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+
+ // Compare the source vector against it.
+ rtx ltcmp = gen_rtx_LT (<VM>mode, operands[1], zero);
+
+ // Mask out all non-negative elements.
+ rtx mask = gen_reg_rtx (<VM>mode);
+ riscv_vector::emit_len_cmp (code_for_pred_ltge (<MODE>mode),
+ mask, ltcmp, operands[1], zero,
+ NULL_RTX, <VM>mode);
+
+ // Emit a masked vneg, negating only the negative elements.
+ riscv_vector::emit_masked_len_op (code_for_pred (NEG, <MODE>mode),
+ mask, operands[0], operands[1],
+ NULL_RTX, <VM>mode);
+ DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 12634d0ac1a..7c588086fa0 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -171,6 +171,8 @@ void emit_vlmax_reg_op (unsigned, rtx, rtx, rtx, machine_mode);
void emit_len_op (unsigned, rtx, rtx, rtx, machine_mode);
void emit_len_binop (unsigned, rtx, rtx, rtx, rtx, machine_mode,
machine_mode = VOIDmode);
+void emit_masked_len_op (unsigned, rtx, rtx, rtx, rtx, machine_mode);
+void emit_len_cmp (unsigned, rtx, rtx, rtx, rtx, rtx, machine_mode);
enum vlmul_type get_vlmul (machine_mode);
unsigned int get_ratio (machine_mode);
unsigned int get_nf (machine_mode);
@@ -181,6 +183,7 @@ int get_avl_type (rtx);
unsigned int calculate_ratio (unsigned int, enum vlmul_type);
enum tail_policy
{
+ TAIL_UNDEFINED = -1,
TAIL_UNDISTURBED = 0,
TAIL_AGNOSTIC = 1,
TAIL_ANY = 2,
@@ -188,12 +191,13 @@ enum tail_policy
enum mask_policy
{
+ MASK_UNDEFINED = -1,
MASK_UNDISTURBED = 0,
MASK_AGNOSTIC = 1,
MASK_ANY = 2,
};
-enum tail_policy get_prefer_tail_policy ();
-enum mask_policy get_prefer_mask_policy ();
+enum tail_policy get_preferred_tail_policy ();
+enum mask_policy get_preferred_mask_policy ();
rtx get_avl_type_rtx (enum avl_type);
opt_machine_mode get_vector_mode (scalar_mode, poly_uint64);
opt_machine_mode get_tuple_mode (machine_mode, unsigned int);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index d65e7300303..64ad3970267 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -54,11 +54,11 @@ namespace riscv_vector {
static bool
const_vlmax_p (machine_mode mode)
{
- poly_uint64 nuints = GET_MODE_NUNITS (mode);
+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
- return nuints.is_constant ()
+ return nunits.is_constant ()
/* The vsetivli can only hold register 0~31. */
- ? (IN_RANGE (nuints.to_constant (), 0, 31))
+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
/* Only allowed in VLS-VLMAX mode. */
: false;
}
@@ -66,38 +66,68 @@ const_vlmax_p (machine_mode mode)
template <int MAX_OPERANDS> class insn_expander
{
public:
- insn_expander () : m_opno (0), has_dest(false) {}
+ insn_expander () : m_opno (0), has_dest (false) {}
+
void add_output_operand (rtx x, machine_mode mode)
{
create_output_operand (&m_ops[m_opno++], x, mode);
gcc_assert (m_opno <= MAX_OPERANDS);
}
+
+ void add_source_operand (rtx x, machine_mode mode)
+ {
+ add_src (x);
+ add_input_operand (x, mode);
+ }
+
void add_input_operand (rtx x, machine_mode mode)
{
create_input_operand (&m_ops[m_opno++], x, mode);
gcc_assert (m_opno <= MAX_OPERANDS);
}
+
void add_all_one_mask_operand (machine_mode mode)
{
add_input_operand (CONSTM1_RTX (mode), mode);
}
+
void add_vundef_operand (machine_mode mode)
{
add_input_operand (RVV_VUNDEF (mode), mode);
}
- void add_policy_operand (enum tail_policy vta, enum mask_policy vma)
+
+ void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
+ enum mask_policy vma = MASK_UNDEFINED)
{
- rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
- rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
- add_input_operand (tail_policy_rtx, Pmode);
- add_input_operand (mask_policy_rtx, Pmode);
+ /* If no policies were specified, use the default ones. */
+ if (vta == TAIL_UNDEFINED)
+ vta = get_preferred_tail_policy ();
+ if (vma == MASK_UNDEFINED)
+ vma = get_preferred_mask_policy ();
+
+ /* RVV Spec 3.4.3.
+ Mask destination tail elements are always treated as tail-agnostic,
+ regardless of the setting of vta. */
+ if (!is_mask_destination_instruction ())
+ {
+ rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
+ add_input_operand (tail_policy_rtx, Pmode);
+ }
+
+ /* RVV Spec 15.1.
+ Vector mask logical instructions are always unmasked. */
+ if (!is_mask_logical_instruction ())
+ {
+ rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
+ add_input_operand (mask_policy_rtx, Pmode);
+ }
}
void add_avl_type_operand (avl_type type)
{
add_input_operand (gen_int_mode (type, Pmode), Pmode);
}
- void set_dest_and_mask (rtx mask, rtx dest, machine_mode mask_mode)
+ void set_dest_and_mask (rtx dest, rtx mask, machine_mode mask_mode)
{
dest_mode = GET_MODE (dest);
has_dest = true;
@@ -133,8 +163,7 @@ public:
add_input_operand (len, Pmode);
- if (GET_MODE_CLASS (dest_mode) != MODE_VECTOR_BOOL)
- add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ());
+ add_policy_operands ();
add_avl_type_operand (vlmax_p ? avl_type::VLMAX : avl_type::NONVLMAX);
}
@@ -150,9 +179,36 @@ public:
expand_insn (icode, m_opno, m_ops);
}
+ bool is_mask_destination_instruction ()
+ {
+ gcc_assert (has_dest);
+ return (GET_MODE_CLASS (dest_mode) == MODE_VECTOR_BOOL);
+ }
+
+ bool is_mask_logical_instruction ()
+ {
+ if (!is_mask_destination_instruction ())
+ return false;
+
+ if (!srcs.length ())
+ return false;
+
+ for (rtx src : srcs)
+ if (GET_MODE_CLASS (GET_MODE (src)) != MODE_VECTOR_BOOL)
+ return false;
+
+ return true;
+ }
+
+ void add_src (rtx src)
+ {
+ srcs.quick_push (src);
+ }
+
private:
int m_opno;
bool has_dest;
+ auto_vec<rtx, 3> srcs;
machine_mode dest_mode;
expand_operand m_ops[MAX_OPERANDS];
};
@@ -252,9 +308,9 @@ emit_pred_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
machine_mode mask_mode, bool force_vlmax = false)
{
insn_expander<8> e;
- e.set_dest_and_mask (mask, dest, mask_mode);
+ e.set_dest_and_mask (dest, mask, mask_mode);
- e.add_input_operand (src, GET_MODE (src));
+ e.add_source_operand (src, GET_MODE (src));
e.set_len_and_policy (len, force_vlmax);
@@ -269,20 +325,40 @@ emit_pred_binop (unsigned icode, rtx mask, rtx dest, rtx src1, rtx src2,
machine_mode scalar_mode = VOIDmode)
{
insn_expander<9> e;
- e.set_dest_and_mask (mask, dest, mask_mode);
+ e.set_dest_and_mask (dest, mask, mask_mode);
gcc_assert (VECTOR_MODE_P (GET_MODE (src1))
|| VECTOR_MODE_P (GET_MODE (src2)));
if (VECTOR_MODE_P (GET_MODE (src1)))
- e.add_input_operand (src1, GET_MODE (src1));
+ e.add_source_operand (src1, GET_MODE (src1));
else
- e.add_input_operand (src1, scalar_mode);
+ e.add_source_operand (src1, scalar_mode);
if (VECTOR_MODE_P (GET_MODE (src2)))
- e.add_input_operand (src2, GET_MODE (src2));
+ e.add_source_operand (src2, GET_MODE (src2));
else
- e.add_input_operand (src2, scalar_mode);
+ e.add_source_operand (src2, scalar_mode);
+
+ e.set_len_and_policy (len);
+
+ e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src1) || MEM_P (src2));
+}
+
+/* Emit an RVV comparison. */
+static void
+emit_pred_cmp (unsigned icode, rtx mask, rtx dest, rtx cmp,
+ rtx src1, rtx src2,
+ rtx len, machine_mode mask_mode)
+{
+ insn_expander<9> e;
+
+ e.set_dest_and_mask (dest, mask, mask_mode);
+
+ e.add_input_operand (cmp, GET_MODE (cmp));
+
+ e.add_source_operand (src1, GET_MODE (src1));
+ e.add_source_operand (src2, GET_MODE (src2));
e.set_len_and_policy (len);
@@ -332,6 +408,8 @@ emit_vlmax_reg_op (unsigned icode, rtx dest, rtx src, rtx len,
/* Force VLMAX */ true);
}
+/* Emit a binary operation with sources SRC1 and SRC2 and a given length
+ LEN. */
void
emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
machine_mode mask_mode, machine_mode scalar_mode)
@@ -340,13 +418,29 @@ emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
mask_mode, scalar_mode);
}
+/* Emit a masked operation with a given length LEN. */
+void
+emit_masked_len_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
+ machine_mode mask_mode)
+{
+ emit_pred_op (icode, mask, dest, src, len, mask_mode);
+}
+
+/* Emit an unmasked comparison whose result is stored in the mask DEST. */
+void
+emit_len_cmp (unsigned icode, rtx dest, rtx op, rtx src1, rtx src2,
+ rtx len, machine_mode mask_mode)
+{
+ emit_pred_cmp (icode, NULL_RTX, dest, op, src1, src2, len, mask_mode);
+}
+
/* Emit vid.v instruction. */
static void
emit_index_op (rtx dest, machine_mode mask_mode)
{
insn_expander<7> e;
- e.set_dest_and_mask (NULL, dest, mask_mode);
+ e.set_dest_and_mask (dest, NULL, mask_mode);
e.set_len_and_policy (NULL, true);
@@ -621,9 +715,9 @@ get_ma (rtx ma)
return INTVAL (ma);
}
-/* Get prefer tail policy. */
+/* Get preferred tail policy. */
enum tail_policy
-get_prefer_tail_policy ()
+get_preferred_tail_policy ()
{
/* TODO: By default, we choose to use TAIL_ANY which allows
compiler pick up either agnostic or undisturbed. Maybe we
@@ -632,9 +726,9 @@ get_prefer_tail_policy ()
return TAIL_ANY;
}
-/* Get prefer mask policy. */
+/* Get preferred mask policy. */
enum mask_policy
-get_prefer_mask_policy ()
+get_preferred_mask_policy ()
{
/* TODO: By default, we choose to use MASK_ANY which allows
compiler pick up either agnostic or undisturbed. Maybe we
@@ -935,8 +1029,8 @@ slide1_sew64_helper (int unspec, machine_mode mode, machine_mode demote_mode,
}
rtx temp = gen_reg_rtx (demote_mode);
- rtx ta = gen_int_mode (get_prefer_tail_policy (), Pmode);
- rtx ma = gen_int_mode (get_prefer_mask_policy (), Pmode);
+ rtx ta = gen_int_mode (get_preferred_tail_policy (), Pmode);
+ rtx ma = gen_int_mode (get_preferred_mask_policy (), Pmode);
rtx merge = RVV_VUNDEF (demote_mode);
/* Handle vslide1<ud>_tu. */
if (register_operand (ops[2], mode)
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index dd714bfcee2..0487827e65e 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -2743,7 +2743,7 @@ get_tail_policy_for_pred (enum predication_type_index pred)
{
if (pred == PRED_TYPE_tu || pred == PRED_TYPE_tum || pred == PRED_TYPE_tumu)
return gen_int_mode (TAIL_UNDISTURBED, Pmode);
- return gen_int_mode (get_prefer_tail_policy (), Pmode);
+ return gen_int_mode (get_preferred_tail_policy (), Pmode);
}
/* Get MASK policy for predication. If predication indicates MU, return the MU.
@@ -2753,7 +2753,7 @@ get_mask_policy_for_pred (enum predication_type_index pred)
{
if (pred == PRED_TYPE_tumu || pred == PRED_TYPE_mu)
return gen_int_mode (MASK_UNDISTURBED, Pmode);
- return gen_int_mode (get_prefer_mask_policy (), Pmode);
+ return gen_int_mode (get_preferred_mask_policy (), Pmode);
}
tree
diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 9847d649d1d..0ecd0bfa2ea 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -566,8 +566,8 @@ get_default_ta ()
{
/* For the instruction that doesn't require TA, we still need a default value
to emit vsetvl. We pick up the default value according to prefer policy. */
- return (bool) (get_prefer_tail_policy () & 0x1
- || (get_prefer_tail_policy () >> 1 & 0x1));
+ return (bool) (get_preferred_tail_policy () & 0x1
+ || (get_preferred_tail_policy () >> 1 & 0x1));
}
/* Get default mask policy. */
@@ -576,8 +576,8 @@ get_default_ma ()
{
/* For the instruction that doesn't require MA, we still need a default value
to emit vsetvl. We pick up the default value according to prefer policy. */
- return (bool) (get_prefer_mask_policy () & 0x1
- || (get_prefer_mask_policy () >> 1 & 0x1));
+ return (bool) (get_preferred_mask_policy () & 0x1
+ || (get_preferred_mask_policy () >> 1 & 0x1));
}
/* Helper function to get TA operand. */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
new file mode 100644
index 00000000000..d6aaa785055
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vabs_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == abs (i - 127)); \
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
new file mode 100644
index 00000000000..cbe0ba0b0ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
new file mode 100644
index 00000000000..c0c52176a42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
new file mode 100644
index 00000000000..a54238c8ff2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = abs (a[i]); \
+ }
+
+#define TEST_TYPE2(TYPE) \
+ __attribute__((noipa)) \
+ void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = llabs (a[i]); \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
new file mode 100644
index 00000000000..abeb50f21ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vneg_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
new file mode 100644
index 00000000000..69d9ebb0953
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
new file mode 100644
index 00000000000..d2c2e17c13e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
new file mode 100644
index 00000000000..72701fceb8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,17 @@
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vneg_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = -a[i]; \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
new file mode 100644
index 00000000000..1c6836742cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,33 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vnot_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t) \
+ RUN(uint8_t) \
+ RUN(uint16_t) \
+ RUN(uint32_t) \
+ RUN(uint64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
new file mode 100644
index 00000000000..ecc4316bd4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
new file mode 100644
index 00000000000..67e28af2cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
new file mode 100644
index 00000000000..19c78d6e49b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,21 @@
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vnot_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = ~a[i]; \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(uint8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(uint16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(uint32_t) \
+ TEST_TYPE(int64_t) \
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index bc99cc0c3cf..54e35cb6c62 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -63,6 +63,8 @@ foreach op $AUTOVEC_TEST_OPTS {
"" "$op"
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/binop/*.\[cS\]]] \
"" "$op"
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+ "" "$op"
}
# VLS-VLMAX tests
--
2.40.1
>>> + TAIL_UNDEFINED = -1,
>>> + MASK_UNDEFINED = -1,
> Why you add this ?
>
>>> + void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
>>> + enum mask_policy vma = MASK_UNDEFINED)
> No, you should just specify this as TAIL_ANY or MASK_ANY as default value.
That's the value I intended for "unspecified" i.e. the caller
didn't specify and then set it to the default. _ANY can work as
well I guess.
>
>>>const_vlmax_p (machine_mode mode)
>>>{
>>>- poly_uint64 nuints = GET_MODE_NUNITS (mode);
>>>+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
>>>- return nuints.is_constant ()
>>>+ return nunits.is_constant ()
>>> /* The vsetivli can only hold register 0~31. */
>>>- ? (IN_RANGE (nuints.to_constant (), 0, 31))
>>>+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
>>> /* Only allowed in VLS-VLMAX mode. */
>>> : false;
>>>}
> Meaningless change ?
Typo.
>
>>> /* For the instruction that doesn't require TA, we still need a default value
>>> to emit vsetvl. We pick up the default value according to prefer policy. */
>>> - return (bool) (get_prefer_tail_policy () & 0x1
>>> - || (get_prefer_tail_policy () >> 1 & 0x1));
>>> + return (bool) (get_preferred_tail_policy () & 0x1
>>> + || (get_preferred_tail_policy () >> 1 & 0x1));
>>> }
>>> /* Get default mask policy. */
>>> @@ -576,8 +576,8 @@ get_default_ma ()
>>> {
>>> /* For the instruction that doesn't require MA, we still need a default value
>>> to emit vsetvl. We pick up the default value according to prefer policy. */
>>> - return (bool) (get_prefer_mask_policy () & 0x1
>>> - || (get_prefer_mask_policy () >> 1 & 0x1));
>>> + return (bool) (get_preferred_mask_policy () & 0x1
>>> + || (get_preferred_mask_policy () >> 1 & 0x1));
> Why you change it ?
Typo/grammar imho.
What about the rest of the changes? It's not all typos but I tried
to unify the mask/policy handling a bit.
> You are using comparison helper which I added one in my downstream
> when I am working on comparison autovec patterns:
>
> I think you can normalize my code with yours:
I wasn't aware that I'm only using one of several helpers, just refactored
what iss upstream. Yes your code looks reasonable and it surely works
with the patch without much rework.
> I am almost done all comparison autovec patterns, soon will send them after testing.
Good, looking forward to it.
Regards
Robin
>> What about the rest of the changes? It's not all typos but I tried
>> to unify the mask/policy handling a bit.
Oh, I see. You rename get_prefer into get_preferred.
This makes perfect sense to me.
juzhe.zhong@rivai.ai
From: Robin Dapp
Date: 2023-05-19 20:07
To: 钟居哲; gcc-patches; kito.cheng; palmer; Michael Collison; Jeff Law
CC: rdapp.gcc
Subject: Re: [PATCH] RISC-V: Implement autovec abs, vneg, vnot.
>>> + TAIL_UNDEFINED = -1,
>>> + MASK_UNDEFINED = -1,
> Why you add this ?
>
>>> + void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
>>> + enum mask_policy vma = MASK_UNDEFINED)
> No, you should just specify this as TAIL_ANY or MASK_ANY as default value.
That's the value I intended for "unspecified" i.e. the caller
didn't specify and then set it to the default. _ANY can work as
well I guess.
>
>>>const_vlmax_p (machine_mode mode)
>>>{
>>>- poly_uint64 nuints = GET_MODE_NUNITS (mode);
>>>+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
>>>- return nuints.is_constant ()
>>>+ return nunits.is_constant ()
>>> /* The vsetivli can only hold register 0~31. */
>>>- ? (IN_RANGE (nuints.to_constant (), 0, 31))
>>>+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
>>> /* Only allowed in VLS-VLMAX mode. */
>>> : false;
>>>}
> Meaningless change ?
Typo.
>
>>> /* For the instruction that doesn't require TA, we still need a default value
>>> to emit vsetvl. We pick up the default value according to prefer policy. */
>>> - return (bool) (get_prefer_tail_policy () & 0x1
>>> - || (get_prefer_tail_policy () >> 1 & 0x1));
>>> + return (bool) (get_preferred_tail_policy () & 0x1
>>> + || (get_preferred_tail_policy () >> 1 & 0x1));
>>> }
>>> /* Get default mask policy. */
>>> @@ -576,8 +576,8 @@ get_default_ma ()
>>> {
>>> /* For the instruction that doesn't require MA, we still need a default value
>>> to emit vsetvl. We pick up the default value according to prefer policy. */
>>> - return (bool) (get_prefer_mask_policy () & 0x1
>>> - || (get_prefer_mask_policy () >> 1 & 0x1));
>>> + return (bool) (get_preferred_mask_policy () & 0x1
>>> + || (get_preferred_mask_policy () >> 1 & 0x1));
> Why you change it ?
Typo/grammar imho.
What about the rest of the changes? It's not all typos but I tried
to unify the mask/policy handling a bit.
> You are using comparison helper which I added one in my downstream
> when I am working on comparison autovec patterns:
>
> I think you can normalize my code with yours:
I wasn't aware that I'm only using one of several helpers, just refactored
what iss upstream. Yes your code looks reasonable and it surely works
with the patch without much rework.
> I am almost done all comparison autovec patterns, soon will send them after testing.
Good, looking forward to it.
Regards
Robin
As discussed with Juzhe off-list, I will rebase this patch against
Juzhe's vec_cmp/vcond patch once that hits the trunk.
Regards
Robin
So I expect you will also apply those refactor on Juzhe's new changes?
If so I would like to have a separated NFC refactor patch if possible.
e.g.
Juzhe's vec_cmp/vcond -> NFC refactor patch -> abs, vneg, vnot
On Mon, May 22, 2023 at 4:59 PM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> As discussed with Juzhe off-list, I will rebase this patch against
> Juzhe's vec_cmp/vcond patch once that hits the trunk.
>
> Regards
> Robin
Yeah, I agree wit kito.
For example, I see you have rename "get_prefer_***" into "get_preferred_**"
I think this NFC patch should be separated patch.
Thanks.
juzhe.zhong@rivai.ai
From: Kito Cheng
Date: 2023-05-22 17:05
To: Robin Dapp
CC: 钟居哲; gcc-patches; palmer; Michael Collison; Jeff Law
Subject: Re: [PATCH] RISC-V: Implement autovec abs, vneg, vnot.
So I expect you will also apply those refactor on Juzhe's new changes?
If so I would like to have a separated NFC refactor patch if possible.
e.g.
Juzhe's vec_cmp/vcond -> NFC refactor patch -> abs, vneg, vnot
On Mon, May 22, 2023 at 4:59 PM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> As discussed with Juzhe off-list, I will rebase this patch against
> Juzhe's vec_cmp/vcond patch once that hits the trunk.
>
> Regards
> Robin
> So I expect you will also apply those refactor on Juzhe's new changes?
> If so I would like to have a separated NFC refactor patch if possible.
What's NFC? :) Do you mean to just have the refactor part as a separate
patch? If yes, I agree.
> e.g.
> Juzhe's vec_cmp/vcond -> NFC refactor patch -> abs, vneg, vnot
> > So I expect you will also apply those refactor on Juzhe's new changes?
> > If so I would like to have a separated NFC refactor patch if possible.
>
> What's NFC? :) Do you mean to just have the refactor part as a separate
> patch? If yes, I agree.
NFC: non-functional-change, that's a term used in LLVM, I just forgot
that's kind of rare term used here,
@@ -161,7 +161,7 @@ (define_expand "<optab><mode>3"
})
;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vv/vsra.vv/vsrl.vv
@@ -180,3 +180,52 @@ (define_expand "v<optab><mode>3"
NULL_RTX, <VM>mode);
DONE;
})
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+ [(set (match_operand:VI 0 "register_operand")
+ (any_int_unop:VI
+ (match_operand:VI 1 "register_operand")))]
+ "TARGET_VECTOR"
+{
+ riscv_vector::emit_len_op (code_for_pred (<CODE>, <MODE>mode),
+ operands[0], operands[1], NULL_RTX, <VM>mode);
+ DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+ [(set (match_operand:VI 0 "register_operand")
+ (match_operand:VI 1 "register_operand"))]
+ "TARGET_VECTOR"
+{
+ // Create a zero constant.
+ rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+
+ // Compare the source vector against it.
+ rtx ltcmp = gen_rtx_LT (<VM>mode, operands[1], zero);
+
+ // Mask out all non-negative elements.
+ rtx mask = gen_reg_rtx (<VM>mode);
+ riscv_vector::emit_len_cmp (code_for_pred_ltge (<MODE>mode),
+ mask, ltcmp, operands[1], zero,
+ NULL_RTX, <VM>mode);
+
+ // Emit a masked vneg, negating only the negative elements.
+ riscv_vector::emit_masked_len_op (code_for_pred (NEG, <MODE>mode),
+ mask, operands[0], operands[1],
+ NULL_RTX, <VM>mode);
+ DONE;
+})
@@ -171,6 +171,8 @@ void emit_vlmax_reg_op (unsigned, rtx, rtx, rtx, machine_mode);
void emit_len_op (unsigned, rtx, rtx, rtx, machine_mode);
void emit_len_binop (unsigned, rtx, rtx, rtx, rtx, machine_mode,
machine_mode = VOIDmode);
+void emit_masked_len_op (unsigned, rtx, rtx, rtx, rtx, machine_mode);
+void emit_len_cmp (unsigned, rtx, rtx, rtx, rtx, rtx, machine_mode);
enum vlmul_type get_vlmul (machine_mode);
unsigned int get_ratio (machine_mode);
unsigned int get_nf (machine_mode);
@@ -181,6 +183,7 @@ int get_avl_type (rtx);
unsigned int calculate_ratio (unsigned int, enum vlmul_type);
enum tail_policy
{
+ TAIL_UNDEFINED = -1,
TAIL_UNDISTURBED = 0,
TAIL_AGNOSTIC = 1,
TAIL_ANY = 2,
@@ -188,12 +191,13 @@ enum tail_policy
enum mask_policy
{
+ MASK_UNDEFINED = -1,
MASK_UNDISTURBED = 0,
MASK_AGNOSTIC = 1,
MASK_ANY = 2,
};
-enum tail_policy get_prefer_tail_policy ();
-enum mask_policy get_prefer_mask_policy ();
+enum tail_policy get_preferred_tail_policy ();
+enum mask_policy get_preferred_mask_policy ();
rtx get_avl_type_rtx (enum avl_type);
opt_machine_mode get_vector_mode (scalar_mode, poly_uint64);
opt_machine_mode get_tuple_mode (machine_mode, unsigned int);
@@ -54,11 +54,11 @@ namespace riscv_vector {
static bool
const_vlmax_p (machine_mode mode)
{
- poly_uint64 nuints = GET_MODE_NUNITS (mode);
+ poly_uint64 nunits = GET_MODE_NUNITS (mode);
- return nuints.is_constant ()
+ return nunits.is_constant ()
/* The vsetivli can only hold register 0~31. */
- ? (IN_RANGE (nuints.to_constant (), 0, 31))
+ ? (IN_RANGE (nunits.to_constant (), 0, 31))
/* Only allowed in VLS-VLMAX mode. */
: false;
}
@@ -66,38 +66,68 @@ const_vlmax_p (machine_mode mode)
template <int MAX_OPERANDS> class insn_expander
{
public:
- insn_expander () : m_opno (0), has_dest(false) {}
+ insn_expander () : m_opno (0), has_dest (false) {}
+
void add_output_operand (rtx x, machine_mode mode)
{
create_output_operand (&m_ops[m_opno++], x, mode);
gcc_assert (m_opno <= MAX_OPERANDS);
}
+
+ void add_source_operand (rtx x, machine_mode mode)
+ {
+ add_src (x);
+ add_input_operand (x, mode);
+ }
+
void add_input_operand (rtx x, machine_mode mode)
{
create_input_operand (&m_ops[m_opno++], x, mode);
gcc_assert (m_opno <= MAX_OPERANDS);
}
+
void add_all_one_mask_operand (machine_mode mode)
{
add_input_operand (CONSTM1_RTX (mode), mode);
}
+
void add_vundef_operand (machine_mode mode)
{
add_input_operand (RVV_VUNDEF (mode), mode);
}
- void add_policy_operand (enum tail_policy vta, enum mask_policy vma)
+
+ void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
+ enum mask_policy vma = MASK_UNDEFINED)
{
- rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
- rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
- add_input_operand (tail_policy_rtx, Pmode);
- add_input_operand (mask_policy_rtx, Pmode);
+ /* If no policies were specified, use the default ones. */
+ if (vta == TAIL_UNDEFINED)
+ vta = get_preferred_tail_policy ();
+ if (vma == MASK_UNDEFINED)
+ vma = get_preferred_mask_policy ();
+
+ /* RVV Spec 3.4.3.
+ Mask destination tail elements are always treated as tail-agnostic,
+ regardless of the setting of vta. */
+ if (!is_mask_destination_instruction ())
+ {
+ rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
+ add_input_operand (tail_policy_rtx, Pmode);
+ }
+
+ /* RVV Spec 15.1.
+ Vector mask logical instructions are always unmasked. */
+ if (!is_mask_logical_instruction ())
+ {
+ rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
+ add_input_operand (mask_policy_rtx, Pmode);
+ }
}
void add_avl_type_operand (avl_type type)
{
add_input_operand (gen_int_mode (type, Pmode), Pmode);
}
- void set_dest_and_mask (rtx mask, rtx dest, machine_mode mask_mode)
+ void set_dest_and_mask (rtx dest, rtx mask, machine_mode mask_mode)
{
dest_mode = GET_MODE (dest);
has_dest = true;
@@ -133,8 +163,7 @@ public:
add_input_operand (len, Pmode);
- if (GET_MODE_CLASS (dest_mode) != MODE_VECTOR_BOOL)
- add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ());
+ add_policy_operands ();
add_avl_type_operand (vlmax_p ? avl_type::VLMAX : avl_type::NONVLMAX);
}
@@ -150,9 +179,36 @@ public:
expand_insn (icode, m_opno, m_ops);
}
+ bool is_mask_destination_instruction ()
+ {
+ gcc_assert (has_dest);
+ return (GET_MODE_CLASS (dest_mode) == MODE_VECTOR_BOOL);
+ }
+
+ bool is_mask_logical_instruction ()
+ {
+ if (!is_mask_destination_instruction ())
+ return false;
+
+ if (!srcs.length ())
+ return false;
+
+ for (rtx src : srcs)
+ if (GET_MODE_CLASS (GET_MODE (src)) != MODE_VECTOR_BOOL)
+ return false;
+
+ return true;
+ }
+
+ void add_src (rtx src)
+ {
+ srcs.quick_push (src);
+ }
+
private:
int m_opno;
bool has_dest;
+ auto_vec<rtx, 3> srcs;
machine_mode dest_mode;
expand_operand m_ops[MAX_OPERANDS];
};
@@ -252,9 +308,9 @@ emit_pred_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
machine_mode mask_mode, bool force_vlmax = false)
{
insn_expander<8> e;
- e.set_dest_and_mask (mask, dest, mask_mode);
+ e.set_dest_and_mask (dest, mask, mask_mode);
- e.add_input_operand (src, GET_MODE (src));
+ e.add_source_operand (src, GET_MODE (src));
e.set_len_and_policy (len, force_vlmax);
@@ -269,20 +325,40 @@ emit_pred_binop (unsigned icode, rtx mask, rtx dest, rtx src1, rtx src2,
machine_mode scalar_mode = VOIDmode)
{
insn_expander<9> e;
- e.set_dest_and_mask (mask, dest, mask_mode);
+ e.set_dest_and_mask (dest, mask, mask_mode);
gcc_assert (VECTOR_MODE_P (GET_MODE (src1))
|| VECTOR_MODE_P (GET_MODE (src2)));
if (VECTOR_MODE_P (GET_MODE (src1)))
- e.add_input_operand (src1, GET_MODE (src1));
+ e.add_source_operand (src1, GET_MODE (src1));
else
- e.add_input_operand (src1, scalar_mode);
+ e.add_source_operand (src1, scalar_mode);
if (VECTOR_MODE_P (GET_MODE (src2)))
- e.add_input_operand (src2, GET_MODE (src2));
+ e.add_source_operand (src2, GET_MODE (src2));
else
- e.add_input_operand (src2, scalar_mode);
+ e.add_source_operand (src2, scalar_mode);
+
+ e.set_len_and_policy (len);
+
+ e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src1) || MEM_P (src2));
+}
+
+/* Emit an RVV comparison. */
+static void
+emit_pred_cmp (unsigned icode, rtx mask, rtx dest, rtx cmp,
+ rtx src1, rtx src2,
+ rtx len, machine_mode mask_mode)
+{
+ insn_expander<9> e;
+
+ e.set_dest_and_mask (dest, mask, mask_mode);
+
+ e.add_input_operand (cmp, GET_MODE (cmp));
+
+ e.add_source_operand (src1, GET_MODE (src1));
+ e.add_source_operand (src2, GET_MODE (src2));
e.set_len_and_policy (len);
@@ -332,6 +408,8 @@ emit_vlmax_reg_op (unsigned icode, rtx dest, rtx src, rtx len,
/* Force VLMAX */ true);
}
+/* Emit a binary operation with sources SRC1 and SRC2 and a given length
+ LEN. */
void
emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
machine_mode mask_mode, machine_mode scalar_mode)
@@ -340,13 +418,29 @@ emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
mask_mode, scalar_mode);
}
+/* Emit a masked operation with a given length LEN. */
+void
+emit_masked_len_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
+ machine_mode mask_mode)
+{
+ emit_pred_op (icode, mask, dest, src, len, mask_mode);
+}
+
+/* Emit an unmasked comparison whose result is stored in the mask DEST. */
+void
+emit_len_cmp (unsigned icode, rtx dest, rtx op, rtx src1, rtx src2,
+ rtx len, machine_mode mask_mode)
+{
+ emit_pred_cmp (icode, NULL_RTX, dest, op, src1, src2, len, mask_mode);
+}
+
/* Emit vid.v instruction. */
static void
emit_index_op (rtx dest, machine_mode mask_mode)
{
insn_expander<7> e;
- e.set_dest_and_mask (NULL, dest, mask_mode);
+ e.set_dest_and_mask (dest, NULL, mask_mode);
e.set_len_and_policy (NULL, true);
@@ -621,9 +715,9 @@ get_ma (rtx ma)
return INTVAL (ma);
}
-/* Get prefer tail policy. */
+/* Get preferred tail policy. */
enum tail_policy
-get_prefer_tail_policy ()
+get_preferred_tail_policy ()
{
/* TODO: By default, we choose to use TAIL_ANY which allows
compiler pick up either agnostic or undisturbed. Maybe we
@@ -632,9 +726,9 @@ get_prefer_tail_policy ()
return TAIL_ANY;
}
-/* Get prefer mask policy. */
+/* Get preferred mask policy. */
enum mask_policy
-get_prefer_mask_policy ()
+get_preferred_mask_policy ()
{
/* TODO: By default, we choose to use MASK_ANY which allows
compiler pick up either agnostic or undisturbed. Maybe we
@@ -935,8 +1029,8 @@ slide1_sew64_helper (int unspec, machine_mode mode, machine_mode demote_mode,
}
rtx temp = gen_reg_rtx (demote_mode);
- rtx ta = gen_int_mode (get_prefer_tail_policy (), Pmode);
- rtx ma = gen_int_mode (get_prefer_mask_policy (), Pmode);
+ rtx ta = gen_int_mode (get_preferred_tail_policy (), Pmode);
+ rtx ma = gen_int_mode (get_preferred_mask_policy (), Pmode);
rtx merge = RVV_VUNDEF (demote_mode);
/* Handle vslide1<ud>_tu. */
if (register_operand (ops[2], mode)
@@ -2743,7 +2743,7 @@ get_tail_policy_for_pred (enum predication_type_index pred)
{
if (pred == PRED_TYPE_tu || pred == PRED_TYPE_tum || pred == PRED_TYPE_tumu)
return gen_int_mode (TAIL_UNDISTURBED, Pmode);
- return gen_int_mode (get_prefer_tail_policy (), Pmode);
+ return gen_int_mode (get_preferred_tail_policy (), Pmode);
}
/* Get MASK policy for predication. If predication indicates MU, return the MU.
@@ -2753,7 +2753,7 @@ get_mask_policy_for_pred (enum predication_type_index pred)
{
if (pred == PRED_TYPE_tumu || pred == PRED_TYPE_mu)
return gen_int_mode (MASK_UNDISTURBED, Pmode);
- return gen_int_mode (get_prefer_mask_policy (), Pmode);
+ return gen_int_mode (get_preferred_mask_policy (), Pmode);
}
tree
@@ -566,8 +566,8 @@ get_default_ta ()
{
/* For the instruction that doesn't require TA, we still need a default value
to emit vsetvl. We pick up the default value according to prefer policy. */
- return (bool) (get_prefer_tail_policy () & 0x1
- || (get_prefer_tail_policy () >> 1 & 0x1));
+ return (bool) (get_preferred_tail_policy () & 0x1
+ || (get_preferred_tail_policy () >> 1 & 0x1));
}
/* Get default mask policy. */
@@ -576,8 +576,8 @@ get_default_ma ()
{
/* For the instruction that doesn't require MA, we still need a default value
to emit vsetvl. We pick up the default value according to prefer policy. */
- return (bool) (get_prefer_mask_policy () & 0x1
- || (get_prefer_mask_policy () >> 1 & 0x1));
+ return (bool) (get_preferred_mask_policy () & 0x1
+ || (get_preferred_mask_policy () >> 1 & 0x1));
}
/* Helper function to get TA operand. */
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vabs_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == abs (i - 127)); \
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
new file mode 100644
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = abs (a[i]); \
+ }
+
+#define TEST_TYPE2(TYPE) \
+ __attribute__((noipa)) \
+ void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = llabs (a[i]); \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
new file mode 100644
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vneg_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
new file mode 100644
@@ -0,0 +1,17 @@
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vneg_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = -a[i]; \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+ TYPE a##TYPE[SZ]; \
+ for (int i = 0; i < SZ; i++) \
+ { \
+ a##TYPE[i] = i - 127; \
+ } \
+ vnot_##TYPE (a##TYPE, a##TYPE, SZ); \
+ for (int i = 0; i < SZ; i++) \
+ assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN_ALL() \
+ RUN(int8_t) \
+ RUN(int16_t) \
+ RUN(int32_t) \
+ RUN(int64_t) \
+ RUN(uint8_t) \
+ RUN(uint16_t) \
+ RUN(uint32_t) \
+ RUN(uint64_t)
+
+int main ()
+{
+ RUN_ALL()
+}
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
new file mode 100644
@@ -0,0 +1,21 @@
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+ __attribute__((noipa)) \
+ void vnot_##TYPE (TYPE *dst, TYPE *a, int n) \
+ { \
+ for (int i = 0; i < n; i++) \
+ dst[i] = ~a[i]; \
+ }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(uint8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(uint16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(uint32_t) \
+ TEST_TYPE(int64_t) \
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
@@ -63,6 +63,8 @@ foreach op $AUTOVEC_TEST_OPTS {
"" "$op"
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/binop/*.\[cS\]]] \
"" "$op"
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+ "" "$op"
}
# VLS-VLMAX tests