]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/riscv/riscv-v.cc
13ee33938bb6ee83427cafcb8c2c56350642c124
[thirdparty/gcc.git] / gcc / config / riscv / riscv-v.cc
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.
4
5 This file is part of GCC.
6
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)
10 any later version.
11
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.
16
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/>. */
20
21 #define IN_TARGET_CODE 1
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "backend.h"
28 #include "rtl.h"
29 #include "insn-config.h"
30 #include "insn-attr.h"
31 #include "recog.h"
32 #include "alias.h"
33 #include "tree.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "explow.h"
37 #include "memmodel.h"
38 #include "emit-rtl.h"
39 #include "tm_p.h"
40 #include "target.h"
41 #include "expr.h"
42 #include "optabs.h"
43 #include "tm-constrs.h"
44
45 using namespace riscv_vector;
46
47 namespace riscv_vector {
48
49 template <int MAX_OPERANDS> class insn_expander
50 {
51 public:
52 insn_expander () : m_opno (0) {}
53 void add_output_operand (rtx x, machine_mode mode)
54 {
55 create_output_operand (&m_ops[m_opno++], x, mode);
56 gcc_assert (m_opno <= MAX_OPERANDS);
57 }
58 void add_input_operand (rtx x, machine_mode mode)
59 {
60 create_input_operand (&m_ops[m_opno++], x, mode);
61 gcc_assert (m_opno <= MAX_OPERANDS);
62 }
63 void add_all_one_mask_operand (machine_mode mode)
64 {
65 add_input_operand (CONSTM1_RTX (mode), mode);
66 }
67 void add_vundef_operand (machine_mode mode)
68 {
69 add_input_operand (gen_rtx_UNSPEC (mode, gen_rtvec (1, const0_rtx),
70 UNSPEC_VUNDEF),
71 mode);
72 }
73 void add_policy_operand (enum tail_policy vta, enum mask_policy vma)
74 {
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);
79 }
80
81 void expand (enum insn_code icode, bool temporary_volatile_p = false)
82 {
83 if (temporary_volatile_p)
84 {
85 temporary_volatile_ok v (true);
86 expand_insn (icode, m_opno, m_ops);
87 }
88 else
89 expand_insn (icode, m_opno, m_ops);
90 }
91
92 private:
93 int m_opno;
94 expand_operand m_ops[MAX_OPERANDS];
95 };
96
97 /* Return true if X is a const_vector with all duplicate elements, which is in
98 the range between MINVAL and MAXVAL. */
99 bool
100 const_vec_all_same_in_range_p (rtx x, HOST_WIDE_INT minval,
101 HOST_WIDE_INT maxval)
102 {
103 rtx elt;
104 return (const_vec_duplicate_p (x, &elt) && CONST_INT_P (elt)
105 && IN_RANGE (INTVAL (elt), minval, maxval));
106 }
107
108 static rtx
109 emit_vlmax_vsetvl (machine_mode vmode)
110 {
111 rtx vl = gen_reg_rtx (Pmode);
112 unsigned int sew = GET_MODE_CLASS (vmode) == MODE_VECTOR_BOOL
113 ? 8
114 : GET_MODE_BITSIZE (GET_MODE_INNER (vmode));
115
116 emit_insn (
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));
120 return vl;
121 }
122
123 /* Emit an RVV unmask && vl mov from SRC to DEST. */
124 void
125 emit_pred_op (unsigned icode, rtx dest, rtx src, machine_mode mask_mode)
126 {
127 insn_expander<7> e;
128 machine_mode mode = GET_MODE (dest);
129
130 e.add_output_operand (dest, mode);
131 e.add_all_one_mask_operand (mask_mode);
132 e.add_vundef_operand (mode);
133
134 e.add_input_operand (src, GET_MODE (src));
135
136 rtx vlmax = emit_vlmax_vsetvl (mode);
137 e.add_input_operand (vlmax, Pmode);
138
139 if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
140 e.add_policy_operand (TAIL_AGNOSTIC, MASK_AGNOSTIC);
141
142 e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src));
143 }
144
145 static void
146 expand_const_vector (rtx target, rtx src, machine_mode mask_mode)
147 {
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)
151 {
152 rtx elt;
153 gcc_assert (
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);
157 return;
158 }
159
160 rtx elt;
161 if (const_vec_duplicate_p (src, &elt))
162 {
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);
168 else
169 emit_pred_op (code_for_pred_broadcast (mode), tmp,
170 force_reg (elt_mode, elt), mask_mode);
171
172 if (tmp != target)
173 emit_move_insn (target, tmp);
174 return;
175 }
176
177 /* TODO: We only support const duplicate vector for now. More cases
178 will be supported when we support auto-vectorization:
179
180 1. series vector.
181 2. multiple elts duplicate vector.
182 3. multiple patterns with multiple elts. */
183 }
184
185 /* Expand a pre-RA RVV data move from SRC to DEST.
186 It expands move for RVV fractional vector modes. */
187 bool
188 legitimize_move (rtx dest, rtx src, machine_mode mask_mode)
189 {
190 machine_mode mode = GET_MODE (dest);
191 if (CONST_VECTOR_P (src))
192 {
193 expand_const_vector (dest, src, mask_mode);
194 return true;
195 }
196 if (known_ge (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR)
197 && GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
198 {
199 /* Need to force register if mem <- !reg. */
200 if (MEM_P (dest) && !REG_P (src))
201 src = force_reg (mode, src);
202
203 return false;
204 }
205 if (!register_operand (src, mode) && !register_operand (dest, mode))
206 {
207 rtx tmp = gen_reg_rtx (mode);
208 if (MEM_P (src))
209 emit_pred_op (code_for_pred_mov (mode), tmp, src, mask_mode);
210 else
211 emit_move_insn (tmp, src);
212 src = tmp;
213 }
214 emit_pred_op (code_for_pred_mov (mode), dest, src, mask_mode);
215 return true;
216 }
217
218 /* VTYPE information for machine_mode. */
219 struct mode_vtype_group
220 {
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];
225 mode_vtype_group ()
226 {
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"
234 }
235 };
236
237 static mode_vtype_group mode_vtype_infos;
238
239 /* Get vlmul field value by comparing LMUL with BYTES_PER_RISCV_VECTOR. */
240 enum vlmul_type
241 get_vlmul (machine_mode mode)
242 {
243 if (TARGET_MIN_VLEN == 32)
244 return mode_vtype_infos.vlmul_for_min_vlen32[mode];
245 else
246 return mode_vtype_infos.vlmul_for_min_vlen64[mode];
247 }
248
249 /* Get ratio according to machine mode. */
250 unsigned int
251 get_ratio (machine_mode mode)
252 {
253 if (TARGET_MIN_VLEN == 32)
254 return mode_vtype_infos.ratio_for_min_vlen32[mode];
255 else
256 return mode_vtype_infos.ratio_for_min_vlen64[mode];
257 }
258
259 } // namespace riscv_vector