1 /* Subroutines used for code generation for RISC-V 'V' Extension for GNU
2 compiler. Copyright (C) 2022-2022 Free Software Foundation, Inc. Contributed
3 by Juzhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define IN_TARGET_CODE 1
25 #include "coretypes.h"
29 #include "insn-config.h"
30 #include "insn-attr.h"
34 #include "stringpool.h"
43 #include "tm-constrs.h"
45 using namespace riscv_vector
;
47 namespace riscv_vector
{
49 template <int MAX_OPERANDS
> class insn_expander
52 insn_expander () : m_opno (0) {}
53 void add_output_operand (rtx x
, machine_mode mode
)
55 create_output_operand (&m_ops
[m_opno
++], x
, mode
);
56 gcc_assert (m_opno
<= MAX_OPERANDS
);
58 void add_input_operand (rtx x
, machine_mode mode
)
60 create_input_operand (&m_ops
[m_opno
++], x
, mode
);
61 gcc_assert (m_opno
<= MAX_OPERANDS
);
63 void add_all_one_mask_operand (machine_mode mode
)
65 add_input_operand (CONSTM1_RTX (mode
), mode
);
67 void add_vundef_operand (machine_mode mode
)
69 add_input_operand (gen_rtx_UNSPEC (mode
, gen_rtvec (1, const0_rtx
),
73 void add_policy_operand (enum tail_policy vta
, enum mask_policy vma
)
75 rtx tail_policy_rtx
= vta
== TAIL_UNDISTURBED
? const0_rtx
: const1_rtx
;
76 rtx mask_policy_rtx
= vma
== MASK_UNDISTURBED
? const0_rtx
: const1_rtx
;
77 add_input_operand (tail_policy_rtx
, Pmode
);
78 add_input_operand (mask_policy_rtx
, Pmode
);
81 void expand (enum insn_code icode
, bool temporary_volatile_p
= false)
83 if (temporary_volatile_p
)
85 temporary_volatile_ok
v (true);
86 expand_insn (icode
, m_opno
, m_ops
);
89 expand_insn (icode
, m_opno
, m_ops
);
94 expand_operand m_ops
[MAX_OPERANDS
];
97 /* Return true if X is a const_vector with all duplicate elements, which is in
98 the range between MINVAL and MAXVAL. */
100 const_vec_all_same_in_range_p (rtx x
, HOST_WIDE_INT minval
,
101 HOST_WIDE_INT maxval
)
104 return (const_vec_duplicate_p (x
, &elt
) && CONST_INT_P (elt
)
105 && IN_RANGE (INTVAL (elt
), minval
, maxval
));
109 emit_vlmax_vsetvl (machine_mode vmode
)
111 rtx vl
= gen_reg_rtx (Pmode
);
112 unsigned int sew
= GET_MODE_CLASS (vmode
) == MODE_VECTOR_BOOL
114 : GET_MODE_BITSIZE (GET_MODE_INNER (vmode
));
117 gen_vsetvl_no_side_effects (Pmode
, vl
, RVV_VLMAX
, gen_int_mode (sew
, Pmode
),
118 gen_int_mode (get_vlmul (vmode
), Pmode
),
119 const1_rtx
, const1_rtx
));
123 /* Emit an RVV unmask && vl mov from SRC to DEST. */
125 emit_pred_op (unsigned icode
, rtx dest
, rtx src
, machine_mode mask_mode
)
128 machine_mode mode
= GET_MODE (dest
);
130 e
.add_output_operand (dest
, mode
);
131 e
.add_all_one_mask_operand (mask_mode
);
132 e
.add_vundef_operand (mode
);
134 e
.add_input_operand (src
, GET_MODE (src
));
136 rtx vlmax
= emit_vlmax_vsetvl (mode
);
137 e
.add_input_operand (vlmax
, Pmode
);
139 if (GET_MODE_CLASS (mode
) != MODE_VECTOR_BOOL
)
140 e
.add_policy_operand (TAIL_AGNOSTIC
, MASK_AGNOSTIC
);
142 e
.expand ((enum insn_code
) icode
, MEM_P (dest
) || MEM_P (src
));
146 expand_const_vector (rtx target
, rtx src
, machine_mode mask_mode
)
148 machine_mode mode
= GET_MODE (target
);
149 scalar_mode elt_mode
= GET_MODE_INNER (mode
);
150 if (GET_MODE_CLASS (mode
) == MODE_VECTOR_BOOL
)
154 const_vec_duplicate_p (src
, &elt
)
155 && (rtx_equal_p (elt
, const0_rtx
) || rtx_equal_p (elt
, const1_rtx
)));
156 emit_pred_op (code_for_pred_mov (mode
), target
, src
, mode
);
161 if (const_vec_duplicate_p (src
, &elt
))
163 rtx tmp
= register_operand (target
, mode
) ? target
: gen_reg_rtx (mode
);
164 /* Element in range -16 ~ 15 integer or 0.0 floating-point,
165 we use vmv.v.i instruction. */
166 if (satisfies_constraint_vi (src
) || satisfies_constraint_Wc0 (src
))
167 emit_pred_op (code_for_pred_mov (mode
), tmp
, src
, mask_mode
);
169 emit_pred_op (code_for_pred_broadcast (mode
), tmp
,
170 force_reg (elt_mode
, elt
), mask_mode
);
173 emit_move_insn (target
, tmp
);
177 /* TODO: We only support const duplicate vector for now. More cases
178 will be supported when we support auto-vectorization:
181 2. multiple elts duplicate vector.
182 3. multiple patterns with multiple elts. */
185 /* Expand a pre-RA RVV data move from SRC to DEST.
186 It expands move for RVV fractional vector modes. */
188 legitimize_move (rtx dest
, rtx src
, machine_mode mask_mode
)
190 machine_mode mode
= GET_MODE (dest
);
191 if (CONST_VECTOR_P (src
))
193 expand_const_vector (dest
, src
, mask_mode
);
196 if (known_ge (GET_MODE_SIZE (mode
), BYTES_PER_RISCV_VECTOR
)
197 && GET_MODE_CLASS (mode
) != MODE_VECTOR_BOOL
)
199 /* Need to force register if mem <- !reg. */
200 if (MEM_P (dest
) && !REG_P (src
))
201 src
= force_reg (mode
, src
);
205 if (!register_operand (src
, mode
) && !register_operand (dest
, mode
))
207 rtx tmp
= gen_reg_rtx (mode
);
209 emit_pred_op (code_for_pred_mov (mode
), tmp
, src
, mask_mode
);
211 emit_move_insn (tmp
, src
);
214 emit_pred_op (code_for_pred_mov (mode
), dest
, src
, mask_mode
);
218 /* VTYPE information for machine_mode. */
219 struct mode_vtype_group
221 enum vlmul_type vlmul_for_min_vlen32
[NUM_MACHINE_MODES
];
222 uint8_t ratio_for_min_vlen32
[NUM_MACHINE_MODES
];
223 enum vlmul_type vlmul_for_min_vlen64
[NUM_MACHINE_MODES
];
224 uint8_t ratio_for_min_vlen64
[NUM_MACHINE_MODES
];
227 #define ENTRY(MODE, REQUIREMENT, VLMUL_FOR_MIN_VLEN32, RATIO_FOR_MIN_VLEN32, \
228 VLMUL_FOR_MIN_VLEN64, RATIO_FOR_MIN_VLEN64) \
229 vlmul_for_min_vlen32[MODE##mode] = VLMUL_FOR_MIN_VLEN32; \
230 ratio_for_min_vlen32[MODE##mode] = RATIO_FOR_MIN_VLEN32; \
231 vlmul_for_min_vlen64[MODE##mode] = VLMUL_FOR_MIN_VLEN64; \
232 ratio_for_min_vlen64[MODE##mode] = RATIO_FOR_MIN_VLEN64;
233 #include "riscv-vector-switch.def"
237 static mode_vtype_group mode_vtype_infos
;
239 /* Get vlmul field value by comparing LMUL with BYTES_PER_RISCV_VECTOR. */
241 get_vlmul (machine_mode mode
)
243 if (TARGET_MIN_VLEN
== 32)
244 return mode_vtype_infos
.vlmul_for_min_vlen32
[mode
];
246 return mode_vtype_infos
.vlmul_for_min_vlen64
[mode
];
249 /* Get ratio according to machine mode. */
251 get_ratio (machine_mode mode
)
253 if (TARGET_MIN_VLEN
== 32)
254 return mode_vtype_infos
.ratio_for_min_vlen32
[mode
];
256 return mode_vtype_infos
.ratio_for_min_vlen64
[mode
];
259 } // namespace riscv_vector