;; Machine description for auto-vectorization using RVV for GNU compiler.
;; Copyright (C) 2023-2024 Free Software Foundation, Inc.
;; Contributed by Juzhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd.
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; .
;; =========================================================================
;; == Loads/Stores
;; =========================================================================
(define_expand "mask_len_load"
[(match_operand:V 0 "register_operand")
(match_operand:V 1 "memory_operand")
(match_operand: 2 "vector_mask_operand")
(match_operand:V 3 "maskload_else_operand")
(match_operand 4 "autovec_length_operand")
(match_operand 5 "const_0_operand")]
"TARGET_VECTOR"
{
riscv_vector::expand_load_store (operands, true);
DONE;
})
(define_expand "mask_len_store"
[(match_operand:V 0 "memory_operand")
(match_operand:V 1 "register_operand")
(match_operand: 2 "vector_mask_operand")
(match_operand 3 "autovec_length_operand")
(match_operand 4 "const_0_operand")]
"TARGET_VECTOR"
{
riscv_vector::expand_load_store (operands, false);
DONE;
})
;; =========================================================================
;; == Gather Load
;; =========================================================================
(define_expand "mask_len_gather_load"
[(match_operand:RATIO64 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO64I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
(define_expand "mask_len_gather_load"
[(match_operand:RATIO32 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO32I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
(define_expand "mask_len_gather_load"
[(match_operand:RATIO16 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO16I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
(define_expand "mask_len_gather_load"
[(match_operand:RATIO8 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO8I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
(define_expand "mask_len_gather_load"
[(match_operand:RATIO4 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO4I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
(define_expand "mask_len_gather_load"
[(match_operand:RATIO2 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO2I 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
;; When SEW = 8 and LMUL = 8, we can't find any index mode with
;; larger SEW. Since RVV indexed load/store support zero extend
;; implicitly and not support scaling, we should only allow
;; operands[3] and operands[4] to be const_1_operand.
(define_expand "mask_len_gather_load"
[(match_operand:RATIO1 0 "register_operand")
(match_operand 1 "pmode_reg_or_0_operand")
(match_operand:RATIO1 2 "register_operand")
(match_operand 3 "")
(match_operand 4 "")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "maskload_else_operand")
(match_operand 7 "autovec_length_operand")
(match_operand 8 "const_0_operand")]
"TARGET_VECTOR"
{
riscv_vector::expand_gather_scatter (operands, true);
DONE;
})
;; =========================================================================
;; == Scatter Store
;; =========================================================================
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO64I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO64 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO32I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO32 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO16I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO16 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO8I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO8 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO4I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO4 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO2I 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO2 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR && riscv_vector::gather_scatter_valid_offset_p (mode)"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
;; When SEW = 8 and LMUL = 8, we can't find any index mode with
;; larger SEW. Since RVV indexed load/store support zero extend
;; implicitly and not support scaling, we should only allow
;; operands[3] and operands[4] to be const_1_operand.
(define_expand "mask_len_scatter_store"
[(match_operand 0 "pmode_reg_or_0_operand")
(match_operand:RATIO1 1 "register_operand")
(match_operand 2 "")
(match_operand 3 "")
(match_operand:RATIO1 4 "register_operand")
(match_operand: 5 "vector_mask_operand")
(match_operand 6 "autovec_length_operand")
(match_operand 7 "const_0_operand")]
"TARGET_VECTOR"
{
riscv_vector::expand_gather_scatter (operands, false);
DONE;
})
;; =========================================================================
;; == Array Load/Store
;; =========================================================================
(define_expand "vec_mask_len_load_lanes"
[(match_operand:VT 0 "register_operand")
(match_operand:VT 1 "memory_operand")
(match_operand: 2 "vector_mask_operand")
(match_operand 3 "maskload_else_operand")
(match_operand 4 "autovec_length_operand")
(match_operand 5 "const_0_operand")]
"TARGET_VECTOR_AUTOVEC_SEGMENT"
{
riscv_vector::expand_lanes_load_store (operands, true);
DONE;
}
)
(define_expand "vec_mask_len_store_lanes"
[(match_operand:VT 0 "memory_operand")
(match_operand:VT 1 "register_operand")
(match_operand: 2 "vector_mask_operand")
(match_operand 3 "autovec_length_operand")
(match_operand 4 "const_0_operand")]
"TARGET_VECTOR_AUTOVEC_SEGMENT"
{
riscv_vector::expand_lanes_load_store (operands, false);
DONE;
}
)
;; =========================================================================
;; == Vector creation
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [BOOL] Duplicate element
;; -------------------------------------------------------------------------
;; The patterns in this section are synthetic.
;; -------------------------------------------------------------------------
;; Implement a predicate broadcast by shifting the low bit of the scalar
;; input into the top bit by duplicate the input and do a compare with zero.
(define_expand "vec_duplicate"
[(set (match_operand:VB 0 "register_operand")
(vec_duplicate:VB (match_operand:QI 1 "register_operand")))]
"TARGET_VECTOR"
{
poly_int64 nunits = GET_MODE_NUNITS (mode);
machine_mode mode = riscv_vector::get_vector_mode (QImode, nunits).require ();
rtx dup = expand_vector_broadcast (mode, operands[1]);
riscv_vector::expand_vec_cmp (operands[0], NE, dup, CONST0_RTX (mode));
DONE;
}
)
;; -------------------------------------------------------------------------
;; ---- [INT] Linear series
;; -------------------------------------------------------------------------
;; Includes:
;; - vid.v
;; - vmul.vx
;; - vadd.vx/vadd.vi
;; -------------------------------------------------------------------------
(define_expand "vec_series"
[(match_operand:V_VLSI 0 "register_operand")
(match_operand: 1 "reg_or_int_operand")
(match_operand: 2 "reg_or_int_operand")]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_series (operands[0], operands[1], operands[2]);
DONE;
}
)
;; -------------------------------------------------------------------------
;; ---- [INT,FP] permutation
;; -------------------------------------------------------------------------
;; This is the pattern permutes the vector
;; -------------------------------------------------------------------------
(define_expand "vec_perm"
[(match_operand:V_VLS 0 "register_operand")
(match_operand:V_VLS 1 "register_operand")
(match_operand:V_VLS 2 "register_operand")
(match_operand: 3 "vector_perm_operand")]
"TARGET_VECTOR && GET_MODE_NUNITS (mode).is_constant ()"
{
riscv_vector::expand_vec_perm (operands[0], operands[1],
operands[2], operands[3]);
DONE;
}
)
;; -------------------------------------------------------------------------
;; ---- [INT,FP] Initialize from individual elements
;; -------------------------------------------------------------------------
;; This is the pattern initialize the vector
;; -------------------------------------------------------------------------
(define_expand "vec_init"
[(match_operand:V_VLSI 0 "register_operand")
(match_operand 1 "")]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_init (operands[0], operands[1]);
DONE;
}
)
;; We split RVV floating-point because we are going to
;; use vfslide1down/vfslide1up for FP16 which need TARGET_ZVFH.
(define_expand "vec_init"
[(match_operand:V_VLSF 0 "register_operand")
(match_operand 1 "")]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_init (operands[0], operands[1]);
DONE;
}
)
;; Provide a vec_init for mask registers by initializing
;; a QImode vector and comparing it against 0.
(define_expand "vec_initqi"
[(match_operand:VB 0 "register_operand")
(match_operand 1 "")]
"TARGET_VECTOR"
{
machine_mode qimode = riscv_vector::get_vector_mode
(QImode, GET_MODE_NUNITS (mode)).require ();
rtx tmp = gen_reg_rtx (qimode);
riscv_vector::expand_vec_init (tmp, operands[1]);
riscv_vector::expand_vec_cmp (operands[0], NE, tmp, CONST0_RTX (qimode));
DONE;
}
)
;; Slide an RVV vector left and insert a scalar into element 0.
(define_expand "vec_shl_insert_"
[(match_operand:VI 0 "register_operand")
(match_operand:VI 1 "register_operand")
(match_operand: 2 "reg_or_0_operand")]
"TARGET_VECTOR"
{
insn_code icode = code_for_pred_slide (UNSPEC_VSLIDE1UP, mode);
rtx ops[] = {operands[0], operands[1], operands[2]};
riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops);
DONE;
})
(define_expand "vec_shl_insert_"
[(match_operand:VF 0 "register_operand")
(match_operand:VF 1 "register_operand")
(match_operand: 2 "register_operand")]
"TARGET_VECTOR"
{
insn_code icode = code_for_pred_slide (UNSPEC_VFSLIDE1UP, mode);
rtx ops[] = {operands[0], operands[1], operands[2]};
riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops);
DONE;
})
;; ========================================================================
;; == Vector operations
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [INT] Binary operations
;; -------------------------------------------------------------------------
;; Includes:
;; - vadd.vv/vsub.vv/...
;; - vadd.vi/vsub.vi/...
;; -------------------------------------------------------------------------
(define_insn_and_split "3"
[(set (match_operand:V_VLSI 0 "register_operand")
(any_int_binop_no_shift:V_VLSI
(match_operand:V_VLSI 1 "")
(match_operand:V_VLSI 2 "")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
riscv_vector::emit_vlmax_insn (code_for_pred (, mode),
riscv_vector::BINARY_OP, operands);
DONE;
}
[(set_attr "type" "vialu")])
;; -------------------------------------------------------------------------
;; ---- [INT] Binary shifts by scalar.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vx/vsra.vx/vsrl.vx
;; - vsll.vi/vsra.vi/vsrl.vi
;; -------------------------------------------------------------------------
(define_insn_and_split "3"
[(set (match_operand:V_VLSI 0 "register_operand" "=vr")
(any_shift:V_VLSI
(match_operand:V_VLSI 1 "register_operand" " vr")
(match_operand: 2 "vector_scalar_shift_operand" " rK")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
operands[2] = gen_lowpart (Pmode, operands[2]);
riscv_vector::emit_vlmax_insn (code_for_pred_scalar (, mode),
riscv_vector::BINARY_OP, operands);
DONE;
}
[(set_attr "type" "vshift")
(set_attr "mode" "")])
;; -------------------------------------------------------------------------
;; ---- [INT] Binary shifts by vector.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vv/vsra.vv/vsrl.vv
;; -------------------------------------------------------------------------
(define_insn_and_split "v3"
[(set (match_operand:V_VLSI 0 "register_operand" "=vr,vr")
(any_shift:V_VLSI
(match_operand:V_VLSI 1 "register_operand" " vr,vr")
(match_operand:V_VLSI 2 "vector_shift_operand" " vr,vk")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
riscv_vector::emit_vlmax_insn (code_for_pred (, mode),
riscv_vector::BINARY_OP, operands);
DONE;
}
[(set_attr "type" "vshift")
(set_attr "mode" "")])
;; -------------------------------------------------------------------------
;; ---- [BOOL] Binary logical operations
;; -------------------------------------------------------------------------
;; Includes:
;; - vmand.mm
;; - vmxor.mm
;; - vmor.mm
;; -------------------------------------------------------------------------
(define_insn_and_split "3"
[(set (match_operand:VB_VLS 0 "register_operand" "=vr")
(any_bitwise:VB_VLS (match_operand:VB_VLS 1 "register_operand" " vr")
(match_operand:VB_VLS 2 "register_operand" " vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_MASK_OP, operands);
DONE;
}
[(set_attr "type" "vmalu")
(set_attr "mode" "")])
;; -------------------------------------------------------------------------
;; ---- [BOOL] Inverse
;; -------------------------------------------------------------------------
;; Includes:
;; - vmnot.m
;; -------------------------------------------------------------------------
(define_insn_and_split "one_cmpl2"
[(set (match_operand:VB_VLS 0 "register_operand" "=vr")
(not:VB_VLS (match_operand:VB_VLS 1 "register_operand" " vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_not (mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_MASK_OP, operands);
DONE;
}
[(set_attr "type" "vmalu")
(set_attr "mode" "")])
;; =========================================================================
;; == Comparisons and selects
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [INT,FP] Select based on masks
;; -------------------------------------------------------------------------
;; Includes merging patterns for:
;; - vmerge.vv
;; - vmerge.vx
;; - vfmerge.vf
;; -------------------------------------------------------------------------
(define_insn_and_split "vcond_mask_"
[(set (match_operand:V_VLS 0 "register_operand")
(if_then_else:V_VLS
(match_operand: 3 "register_operand")
(match_operand:V_VLS 1 "nonmemory_operand")
(match_operand:V_VLS 2 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
/* The order of vcond_mask is opposite to pred_merge. */
std::swap (operands[1], operands[2]);
riscv_vector::emit_vlmax_insn (code_for_pred_merge (mode),
riscv_vector::MERGE_OP, operands);
DONE;
}
[(set_attr "type" "vector")]
)
(define_expand "vcond_mask_len_"
[(match_operand:V 0 "register_operand")
(match_operand: 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),
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),
riscv_vector::MERGE_OP_TU,
ops, operands[4]);
}
DONE;
}
[(set_attr "type" "vector")]
)
;; -------------------------------------------------------------------------
;; ---- [BOOL] Select based on masks
;; -------------------------------------------------------------------------
;; Includes merging patterns for:
;; - vmand.mm
;; - vmor.mm
;; - vmnot.m
;; -------------------------------------------------------------------------
(define_expand "vcond_mask_"
[(match_operand:VB_VLS 0 "register_operand")
(match_operand:VB_VLS 1 "register_operand")
(match_operand:VB_VLS 2 "register_operand")
(match_operand:VB_VLS 3 "register_operand")]
"TARGET_VECTOR"
{
/* mask1 = operands[3] & operands[1]. */
rtx mask1 = expand_binop (mode, and_optab, operands[1],
operands[3], NULL_RTX, 0,
OPTAB_DIRECT);
/* mask2 = ~operands[3] & operands[2]. */
rtx inverse = expand_unop (mode, one_cmpl_optab, operands[3],
NULL_RTX, 0);
rtx mask2 = expand_binop (mode, and_optab, operands[2],
inverse, NULL_RTX, 0,
OPTAB_DIRECT);
/* result = mask1 | mask2. */
rtx result = expand_binop (mode, ior_optab, mask1,
mask2, NULL_RTX, 0,
OPTAB_DIRECT);
emit_move_insn (operands[0], result);
DONE;
})
;; -------------------------------------------------------------------------
;; ---- [INT,FP] Comparisons
;; -------------------------------------------------------------------------
;; Includes:
;; - vms.
;; -------------------------------------------------------------------------
(define_expand "vec_cmp"
[(set (match_operand: 0 "register_operand")
(match_operator: 1 "comparison_operator"
[(match_operand:V_VLSI 2 "register_operand")
(match_operand:V_VLSI 3 "nonmemory_operand")]))]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_cmp (operands[0], GET_CODE (operands[1]),
operands[2], operands[3]);
DONE;
}
)
(define_expand "vec_cmpu"
[(set (match_operand: 0 "register_operand")
(match_operator: 1 "comparison_operator"
[(match_operand:V_VLSI 2 "register_operand")
(match_operand:V_VLSI 3 "nonmemory_operand")]))]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_cmp (operands[0], GET_CODE (operands[1]),
operands[2], operands[3]);
DONE;
}
)
(define_expand "vec_cmp"
[(set (match_operand: 0 "register_operand")
(match_operator: 1 "comparison_operator"
[(match_operand:V_VLSF 2 "register_operand")
(match_operand:V_VLSF 3 "register_operand")]))]
"TARGET_VECTOR"
{
riscv_vector::expand_vec_cmp_float (operands[0], GET_CODE (operands[1]),
operands[2], operands[3], false);
DONE;
}
)
;; -------------------------------------------------------------------------
;; ---- [INT] Sign and zero extension
;; -------------------------------------------------------------------------
;; Includes:
;; - vzext.vf[2|4|8]
;; - vsext.vf[2|4|8]
;; -------------------------------------------------------------------------
;; Use define_insn_and_split to define vsext.vf2/vzext.vf2 will help
;; to combine instructions as below:
;; vsext.vf2 + vsext.vf2 + vadd.vv ==> vwadd.vv
(define_insn_and_split "2"
[(set (match_operand:VWEXTI 0 "register_operand" "=&vr")
(any_extend:VWEXTI
(match_operand: 1 "register_operand" "vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_vf2 (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vext")
(set_attr "mode" "")])
(define_insn_and_split "2"
[(set (match_operand:VQEXTI 0 "register_operand")
(any_extend:VQEXTI
(match_operand: 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_vf4 (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vext")])
(define_insn_and_split "2"
[(set (match_operand:VOEXTI 0 "register_operand")
(any_extend:VOEXTI
(match_operand: 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_vf8 (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vext")])
;; -------------------------------------------------------------------------
;; ---- [INT] Truncation
;; -------------------------------------------------------------------------
;; - vncvt.x.x.w
;; -------------------------------------------------------------------------
(define_insn_and_split "trunc2"
[(set (match_operand: 0 "register_operand" "=vr")
(truncate:
(match_operand:VWEXTI 1 "register_operand" " vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_trunc (mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vshift")
(set_attr "mode" "")])
;; -------------------------------------------------------------------------
;; Truncation to a mode whose inner mode size is a quarter of mode's.
;; We emulate this with two consecutive vncvts.
;; -------------------------------------------------------------------------
(define_expand "trunc2"
[(set (match_operand: 0 "register_operand")
(truncate:
(match_operand:VQEXTI 1 "register_operand")))]
"TARGET_VECTOR"
{
rtx half = gen_reg_rtx (mode);
emit_insn (gen_trunc2 (half, operands[1]));
emit_insn (gen_trunc2 (operands[0], half));
DONE;
})
;; -------------------------------------------------------------------------
;; Truncation to a mode whose inner mode size is an eighth of mode's.
;; We emulate this with three consecutive vncvts.
;; -------------------------------------------------------------------------
(define_expand "trunc2"
[(set (match_operand: 0 "register_operand")
(truncate:
(match_operand:VOEXTI 1 "register_operand")))]
"TARGET_VECTOR"
{
rtx quarter = gen_reg_rtx (mode);
emit_insn (gen_trunc2 (quarter, operands[1]));
emit_insn (gen_trunc2 (operands[0], quarter));
DONE;
})
;; -------------------------------------------------------------------------
;; ---- [FP] Widening.
;; -------------------------------------------------------------------------
;; - vfwcvt.f.f.v
;; -------------------------------------------------------------------------
(define_insn_and_split "extend2"
[(set (match_operand:VWEXTF_ZVFHMIN 0 "register_operand" "=&vr")
(float_extend:VWEXTF_ZVFHMIN
(match_operand: 1 "register_operand" " vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_extend (mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vfwcvtftof")
(set_attr "mode" "")])
(define_expand "extend2"
[(set (match_operand:VQEXTF 0 "register_operand")
(float_extend:VQEXTF
(match_operand: 1 "register_operand")))]
"TARGET_VECTOR && (TARGET_ZVFHMIN || TARGET_ZVFH)"
{
rtx dblw = gen_reg_rtx (mode);
emit_insn (gen_extend2 (dblw, operands[1]));
emit_insn (gen_extend2 (operands[0], dblw));
DONE;
})
;; -------------------------------------------------------------------------
;; ---- [FP] Narrowing.
;; -------------------------------------------------------------------------
;; - vfncvt.f.f.w
;; -------------------------------------------------------------------------
(define_insn_and_split "trunc2"
[(set (match_operand: 0 "register_operand" "=vr")
(float_truncate:
(match_operand:VWEXTF_ZVFHMIN 1 "register_operand" " vr")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_trunc (mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands);
DONE;
}
[(set_attr "type" "vfncvtftof")
(set_attr "mode" "")])
;; -------------------------------------------------------------------------
;; Narrowing to a mode whose inner mode size is a quarter of mode's.
;; We emulate this with two consecutive vfncvts.
;; -------------------------------------------------------------------------
(define_expand "trunc2"
[(set (match_operand: 0 "register_operand")
(float_truncate:
(match_operand:VQEXTF 1 "register_operand")))]
"TARGET_VECTOR && (TARGET_ZVFHMIN || TARGET_ZVFH)"
{
rtx half = gen_reg_rtx (mode);
rtx opshalf[] = {half, operands[1]};
/* According to the RISC-V V Spec 13.19. we need to use
vfncvt.rod.f.f.w for all steps but the last. */
insn_code icode = code_for_pred_rod_trunc (mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, opshalf);
emit_insn (gen_trunc2 (operands[0], half));
DONE;
})
;; =========================================================================
;; == Conversions
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [INT<-FP] Conversions
;; -------------------------------------------------------------------------
;; Includes:
;; - vfcvt.rtz.xu.f.v
;; - vfcvt.rtz.x.f.v
;; -------------------------------------------------------------------------
(define_insn_and_split "2"
[(set (match_operand: 0 "register_operand")
(any_fix:
(match_operand:V_VLSF 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP, operands);
DONE;
}
[(set_attr "type" "vfcvtftoi")])
;; -------------------------------------------------------------------------
;; ---- [FP<-INT] Conversions
;; -------------------------------------------------------------------------
;; Includes:
;; - vfcvt.f.xu.v
;; - vfcvt.f.x.v
;; -------------------------------------------------------------------------
(define_insn_and_split "2"
[(set (match_operand:V_VLSF 0 "register_operand")
(any_float:V_VLSF
(match_operand: 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred (, mode);
riscv_vector::emit_vlmax_insn (icode, riscv_vector::UNARY_OP_FRM_DYN, operands);
DONE;
}
[(set_attr "type" "vfcvtitof")])
;; =========================================================================
;; == Widening/narrowing Conversions
;; =========================================================================
;; -------------------------------------------------------------------------
;; ---- [INT<-FP] Widening Conversions
;; -------------------------------------------------------------------------
;; Includes:
;; - vfwcvt.rtz.xu.f.v
;; - vfwcvt.rtz.x.f.v
;; -------------------------------------------------------------------------
(define_insn_and_split "2"
[(set (match_operand:VWCONVERTI 0 "register_operand")
(any_fix:VWCONVERTI
(match_operand: 1 "register_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
insn_code icode = code_for_pred_widen (