]>
Commit | Line | Data |
---|---|---|
09cae750 | 1 | /* Subroutines used for code generation for RISC-V. |
7adcbafe | 2 | Copyright (C) 2011-2022 Free Software Foundation, Inc. |
09cae750 PD |
3 | Contributed by Andrew Waterman (andrew@sifive.com). |
4 | Based on MIPS target for GNU compiler. | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GCC; see the file COPYING3. If not see | |
20 | <http://www.gnu.org/licenses/>. */ | |
21 | ||
8fcc61f8 RS |
22 | #define IN_TARGET_CODE 1 |
23 | ||
8e966210 | 24 | #define INCLUDE_STRING |
09cae750 PD |
25 | #include "config.h" |
26 | #include "system.h" | |
27 | #include "coretypes.h" | |
7d935cdd | 28 | #include "target.h" |
09cae750 PD |
29 | #include "tm.h" |
30 | #include "rtl.h" | |
31 | #include "regs.h" | |
09cae750 | 32 | #include "insn-config.h" |
09cae750 PD |
33 | #include "insn-attr.h" |
34 | #include "recog.h" | |
35 | #include "output.h" | |
09cae750 | 36 | #include "alias.h" |
09cae750 | 37 | #include "tree.h" |
314e6352 ML |
38 | #include "stringpool.h" |
39 | #include "attribs.h" | |
09cae750 | 40 | #include "varasm.h" |
09cae750 PD |
41 | #include "stor-layout.h" |
42 | #include "calls.h" | |
43 | #include "function.h" | |
09cae750 PD |
44 | #include "explow.h" |
45 | #include "memmodel.h" | |
46 | #include "emit-rtl.h" | |
09cae750 PD |
47 | #include "reload.h" |
48 | #include "tm_p.h" | |
09cae750 | 49 | #include "basic-block.h" |
1b68a156 JL |
50 | #include "expr.h" |
51 | #include "optabs.h" | |
09cae750 | 52 | #include "bitmap.h" |
09cae750 | 53 | #include "df.h" |
09cae750 | 54 | #include "diagnostic.h" |
09cae750 | 55 | #include "builtins.h" |
fb5621b1 | 56 | #include "predict.h" |
de6320a8 | 57 | #include "tree-pass.h" |
00f34291 | 58 | #include "opts.h" |
b4feb49c | 59 | #include "tm-constrs.h" |
60 | #include "rtl-iter.h" | |
7d935cdd JZZ |
61 | |
62 | /* This file should be included last. */ | |
63 | #include "target-def.h" | |
09cae750 PD |
64 | |
65 | /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ | |
66 | #define UNSPEC_ADDRESS_P(X) \ | |
67 | (GET_CODE (X) == UNSPEC \ | |
68 | && XINT (X, 1) >= UNSPEC_ADDRESS_FIRST \ | |
69 | && XINT (X, 1) < UNSPEC_ADDRESS_FIRST + NUM_SYMBOL_TYPES) | |
70 | ||
71 | /* Extract the symbol or label from UNSPEC wrapper X. */ | |
72 | #define UNSPEC_ADDRESS(X) \ | |
73 | XVECEXP (X, 0, 0) | |
74 | ||
75 | /* Extract the symbol type from UNSPEC wrapper X. */ | |
76 | #define UNSPEC_ADDRESS_TYPE(X) \ | |
77 | ((enum riscv_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST)) | |
78 | ||
79 | /* True if bit BIT is set in VALUE. */ | |
80 | #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0) | |
81 | ||
82 | /* Classifies an address. | |
83 | ||
84 | ADDRESS_REG | |
85 | A natural register + offset address. The register satisfies | |
86 | riscv_valid_base_register_p and the offset is a const_arith_operand. | |
87 | ||
88 | ADDRESS_LO_SUM | |
89 | A LO_SUM rtx. The first operand is a valid base register and | |
90 | the second operand is a symbolic address. | |
91 | ||
92 | ADDRESS_CONST_INT | |
93 | A signed 16-bit constant address. | |
94 | ||
95 | ADDRESS_SYMBOLIC: | |
96 | A constant symbolic address. */ | |
97 | enum riscv_address_type { | |
98 | ADDRESS_REG, | |
99 | ADDRESS_LO_SUM, | |
100 | ADDRESS_CONST_INT, | |
101 | ADDRESS_SYMBOLIC | |
102 | }; | |
103 | ||
104 | /* Information about a function's frame layout. */ | |
105 | struct GTY(()) riscv_frame_info { | |
106 | /* The size of the frame in bytes. */ | |
3496ca4e | 107 | poly_int64 total_size; |
09cae750 PD |
108 | |
109 | /* Bit X is set if the function saves or restores GPR X. */ | |
110 | unsigned int mask; | |
111 | ||
112 | /* Likewise FPR X. */ | |
113 | unsigned int fmask; | |
114 | ||
115 | /* How much the GPR save/restore routines adjust sp (or 0 if unused). */ | |
116 | unsigned save_libcall_adjustment; | |
117 | ||
118 | /* Offsets of fixed-point and floating-point save areas from frame bottom */ | |
3496ca4e | 119 | poly_int64 gp_sp_offset; |
120 | poly_int64 fp_sp_offset; | |
09cae750 PD |
121 | |
122 | /* Offset of virtual frame pointer from stack pointer/frame bottom */ | |
3496ca4e | 123 | poly_int64 frame_pointer_offset; |
09cae750 PD |
124 | |
125 | /* Offset of hard frame pointer from stack pointer/frame bottom */ | |
3496ca4e | 126 | poly_int64 hard_frame_pointer_offset; |
09cae750 PD |
127 | |
128 | /* The offset of arg_pointer_rtx from the bottom of the frame. */ | |
3496ca4e | 129 | poly_int64 arg_pointer_offset; |
7b9b6969 KC |
130 | |
131 | /* Reset this struct, clean all field to zero. */ | |
132 | void reset(void); | |
09cae750 PD |
133 | }; |
134 | ||
ec74725c | 135 | enum riscv_privilege_levels { |
8528f27b | 136 | UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE |
ec74725c JW |
137 | }; |
138 | ||
09cae750 PD |
139 | struct GTY(()) machine_function { |
140 | /* The number of extra stack bytes taken up by register varargs. | |
141 | This area is allocated by the callee at the very top of the frame. */ | |
142 | int varargs_size; | |
143 | ||
8cad5b14 KC |
144 | /* True if current function is a naked function. */ |
145 | bool naked_p; | |
146 | ||
d0ebdd9f JW |
147 | /* True if current function is an interrupt function. */ |
148 | bool interrupt_handler_p; | |
ec74725c JW |
149 | /* For an interrupt handler, indicates the privilege level. */ |
150 | enum riscv_privilege_levels interrupt_mode; | |
d0ebdd9f JW |
151 | |
152 | /* True if attributes on current function have been checked. */ | |
153 | bool attributes_checked_p; | |
154 | ||
09cae750 PD |
155 | /* The current frame information, calculated by riscv_compute_frame_info. */ |
156 | struct riscv_frame_info frame; | |
157 | }; | |
158 | ||
159 | /* Information about a single argument. */ | |
160 | struct riscv_arg_info { | |
161 | /* True if the argument is at least partially passed on the stack. */ | |
162 | bool stack_p; | |
163 | ||
164 | /* The number of integer registers allocated to this argument. */ | |
165 | unsigned int num_gprs; | |
166 | ||
167 | /* The offset of the first register used, provided num_gprs is nonzero. | |
168 | If passed entirely on the stack, the value is MAX_ARGS_IN_REGISTERS. */ | |
169 | unsigned int gpr_offset; | |
170 | ||
171 | /* The number of floating-point registers allocated to this argument. */ | |
172 | unsigned int num_fprs; | |
173 | ||
174 | /* The offset of the first register used, provided num_fprs is nonzero. */ | |
175 | unsigned int fpr_offset; | |
176 | }; | |
177 | ||
178 | /* Information about an address described by riscv_address_type. | |
179 | ||
180 | ADDRESS_CONST_INT | |
181 | No fields are used. | |
182 | ||
183 | ADDRESS_REG | |
184 | REG is the base register and OFFSET is the constant offset. | |
185 | ||
186 | ADDRESS_LO_SUM | |
187 | REG and OFFSET are the operands to the LO_SUM and SYMBOL_TYPE | |
188 | is the type of symbol it references. | |
189 | ||
190 | ADDRESS_SYMBOLIC | |
191 | SYMBOL_TYPE is the type of symbol that the address references. */ | |
192 | struct riscv_address_info { | |
193 | enum riscv_address_type type; | |
194 | rtx reg; | |
195 | rtx offset; | |
196 | enum riscv_symbol_type symbol_type; | |
197 | }; | |
198 | ||
199 | /* One stage in a constant building sequence. These sequences have | |
200 | the form: | |
201 | ||
202 | A = VALUE[0] | |
203 | A = A CODE[1] VALUE[1] | |
204 | A = A CODE[2] VALUE[2] | |
205 | ... | |
206 | ||
207 | where A is an accumulator, each CODE[i] is a binary rtl operation | |
208 | and each VALUE[i] is a constant integer. CODE[0] is undefined. */ | |
209 | struct riscv_integer_op { | |
210 | enum rtx_code code; | |
211 | unsigned HOST_WIDE_INT value; | |
212 | }; | |
213 | ||
214 | /* The largest number of operations needed to load an integer constant. | |
215 | The worst case is LUI, ADDI, SLLI, ADDI, SLLI, ADDI, SLLI, ADDI. */ | |
216 | #define RISCV_MAX_INTEGER_OPS 8 | |
217 | ||
218 | /* Costs of various operations on the different architectures. */ | |
219 | ||
72eb8335 | 220 | struct riscv_tune_param |
09cae750 PD |
221 | { |
222 | unsigned short fp_add[2]; | |
223 | unsigned short fp_mul[2]; | |
224 | unsigned short fp_div[2]; | |
225 | unsigned short int_mul[2]; | |
226 | unsigned short int_div[2]; | |
227 | unsigned short issue_rate; | |
228 | unsigned short branch_cost; | |
229 | unsigned short memory_cost; | |
b646d7d2 | 230 | unsigned short fmv_cost; |
82285692 | 231 | bool slow_unaligned_access; |
09cae750 PD |
232 | }; |
233 | ||
72eb8335 KC |
234 | /* Information about one micro-arch we know about. */ |
235 | struct riscv_tune_info { | |
236 | /* This micro-arch canonical name. */ | |
09cae750 PD |
237 | const char *name; |
238 | ||
88108b27 AW |
239 | /* Which automaton to use for tuning. */ |
240 | enum riscv_microarchitecture_type microarchitecture; | |
241 | ||
72eb8335 KC |
242 | /* Tuning parameters for this micro-arch. */ |
243 | const struct riscv_tune_param *tune_param; | |
09cae750 PD |
244 | }; |
245 | ||
246 | /* Global variables for machine-dependent things. */ | |
247 | ||
82285692 | 248 | /* Whether unaligned accesses execute very slowly. */ |
fb5621b1 | 249 | bool riscv_slow_unaligned_access_p; |
82285692 | 250 | |
0ce42fe1 AW |
251 | /* Stack alignment to assume/maintain. */ |
252 | unsigned riscv_stack_boundary; | |
253 | ||
b579523b JW |
254 | /* If non-zero, this is an offset to be added to SP to redefine the CFA |
255 | when restoring the FP register from the stack. Only valid when generating | |
256 | the epilogue. */ | |
257 | static int epilogue_cfa_sp_offset; | |
258 | ||
09cae750 | 259 | /* Which tuning parameters to use. */ |
72eb8335 | 260 | static const struct riscv_tune_param *tune_param; |
09cae750 | 261 | |
88108b27 AW |
262 | /* Which automaton to use for tuning. */ |
263 | enum riscv_microarchitecture_type riscv_microarchitecture; | |
264 | ||
3496ca4e | 265 | /* The number of chunks in a single vector register. */ |
266 | poly_uint16 riscv_vector_chunks; | |
267 | ||
268 | /* The number of bytes in a vector chunk. */ | |
269 | unsigned riscv_bytes_per_vector_chunk; | |
270 | ||
09cae750 PD |
271 | /* Index R is the smallest register class that contains register R. */ |
272 | const enum reg_class riscv_regno_to_class[FIRST_PSEUDO_REGISTER] = { | |
273 | GR_REGS, GR_REGS, GR_REGS, GR_REGS, | |
274 | GR_REGS, GR_REGS, SIBCALL_REGS, SIBCALL_REGS, | |
3599dfba AB |
275 | JALR_REGS, JALR_REGS, SIBCALL_REGS, SIBCALL_REGS, |
276 | SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, | |
277 | SIBCALL_REGS, SIBCALL_REGS, JALR_REGS, JALR_REGS, | |
09cae750 PD |
278 | JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, |
279 | JALR_REGS, JALR_REGS, JALR_REGS, JALR_REGS, | |
280 | SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, SIBCALL_REGS, | |
281 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
282 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
283 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
284 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
285 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
286 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
287 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
288 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
31380d4b | 289 | FRAME_REGS, FRAME_REGS, VL_REGS, VTYPE_REGS, |
290 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
291 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
292 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
293 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
294 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
295 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
296 | NO_REGS, NO_REGS, NO_REGS, NO_REGS, | |
297 | VM_REGS, VD_REGS, VD_REGS, VD_REGS, | |
298 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
299 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
300 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
301 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
302 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
303 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
304 | VD_REGS, VD_REGS, VD_REGS, VD_REGS, | |
09cae750 PD |
305 | }; |
306 | ||
307 | /* Costs to use when optimizing for rocket. */ | |
72eb8335 | 308 | static const struct riscv_tune_param rocket_tune_info = { |
09cae750 PD |
309 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ |
310 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */ | |
311 | {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ | |
312 | {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ | |
313 | {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ | |
314 | 1, /* issue_rate */ | |
315 | 3, /* branch_cost */ | |
82285692 | 316 | 5, /* memory_cost */ |
b646d7d2 | 317 | 8, /* fmv_cost */ |
82285692 | 318 | true, /* slow_unaligned_access */ |
09cae750 PD |
319 | }; |
320 | ||
88108b27 | 321 | /* Costs to use when optimizing for Sifive 7 Series. */ |
72eb8335 | 322 | static const struct riscv_tune_param sifive_7_tune_info = { |
88108b27 AW |
323 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ |
324 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */ | |
325 | {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ | |
326 | {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ | |
327 | {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ | |
328 | 2, /* issue_rate */ | |
329 | 4, /* branch_cost */ | |
330 | 3, /* memory_cost */ | |
b646d7d2 | 331 | 8, /* fmv_cost */ |
88108b27 AW |
332 | true, /* slow_unaligned_access */ |
333 | }; | |
334 | ||
78222855 J |
335 | /* Costs to use when optimizing for T-HEAD c906. */ |
336 | static const struct riscv_tune_param thead_c906_tune_info = { | |
337 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ | |
338 | {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */ | |
339 | {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ | |
340 | {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ | |
341 | {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ | |
342 | 1, /* issue_rate */ | |
343 | 3, /* branch_cost */ | |
344 | 5, /* memory_cost */ | |
b646d7d2 | 345 | 8, /* fmv_cost */ |
78222855 J |
346 | false, /* slow_unaligned_access */ |
347 | }; | |
348 | ||
09cae750 | 349 | /* Costs to use when optimizing for size. */ |
72eb8335 | 350 | static const struct riscv_tune_param optimize_size_tune_info = { |
09cae750 PD |
351 | {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* fp_add */ |
352 | {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* fp_mul */ | |
353 | {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* fp_div */ | |
354 | {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* int_mul */ | |
355 | {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* int_div */ | |
356 | 1, /* issue_rate */ | |
357 | 1, /* branch_cost */ | |
82285692 | 358 | 2, /* memory_cost */ |
b646d7d2 | 359 | 8, /* fmv_cost */ |
82285692 | 360 | false, /* slow_unaligned_access */ |
09cae750 PD |
361 | }; |
362 | ||
8cad5b14 | 363 | static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *); |
ec74725c | 364 | static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); |
8cad5b14 KC |
365 | |
366 | /* Defining target-specific uses of __attribute__. */ | |
367 | static const struct attribute_spec riscv_attribute_table[] = | |
368 | { | |
369 | /* Syntax: { name, min_len, max_len, decl_required, type_required, | |
370 | function_type_required, affects_type_identity, handler, | |
371 | exclude } */ | |
372 | ||
373 | /* The attribute telling no prologue/epilogue. */ | |
374 | { "naked", 0, 0, true, false, false, false, | |
375 | riscv_handle_fndecl_attribute, NULL }, | |
d0ebdd9f | 376 | /* This attribute generates prologue/epilogue for interrupt handlers. */ |
ec74725c JW |
377 | { "interrupt", 0, 1, false, true, true, false, |
378 | riscv_handle_type_attribute, NULL }, | |
8cad5b14 | 379 | |
03f33657 JZZ |
380 | /* The following two are used for the built-in properties of the Vector type |
381 | and are not used externally */ | |
382 | {"RVV sizeless type", 4, 4, false, true, false, true, NULL, NULL}, | |
383 | {"RVV type", 0, 0, false, true, false, true, NULL, NULL}, | |
384 | ||
8cad5b14 KC |
385 | /* The last attribute spec is set to be NULL. */ |
386 | { NULL, 0, 0, false, false, false, false, NULL, NULL } | |
387 | }; | |
388 | ||
d0e0c130 KC |
389 | /* Order for the CLOBBERs/USEs of gpr_save. */ |
390 | static const unsigned gpr_save_reg_order[] = { | |
391 | INVALID_REGNUM, T0_REGNUM, T1_REGNUM, RETURN_ADDR_REGNUM, | |
392 | S0_REGNUM, S1_REGNUM, S2_REGNUM, S3_REGNUM, S4_REGNUM, | |
393 | S5_REGNUM, S6_REGNUM, S7_REGNUM, S8_REGNUM, S9_REGNUM, | |
394 | S10_REGNUM, S11_REGNUM | |
395 | }; | |
396 | ||
09cae750 | 397 | /* A table describing all the processors GCC knows about. */ |
72eb8335 | 398 | static const struct riscv_tune_info riscv_tune_info_table[] = { |
97d1ed67 KC |
399 | #define RISCV_TUNE(TUNE_NAME, PIPELINE_MODEL, TUNE_INFO) \ |
400 | { TUNE_NAME, PIPELINE_MODEL, & TUNE_INFO}, | |
401 | #include "riscv-cores.def" | |
09cae750 PD |
402 | }; |
403 | ||
7b9b6969 KC |
404 | void riscv_frame_info::reset(void) |
405 | { | |
406 | total_size = 0; | |
407 | mask = 0; | |
408 | fmask = 0; | |
409 | save_libcall_adjustment = 0; | |
410 | ||
411 | gp_sp_offset = 0; | |
412 | fp_sp_offset = 0; | |
413 | ||
414 | frame_pointer_offset = 0; | |
415 | ||
416 | hard_frame_pointer_offset = 0; | |
417 | ||
418 | arg_pointer_offset = 0; | |
419 | } | |
420 | ||
6efd040c L |
421 | /* Implement TARGET_MIN_ARITHMETIC_PRECISION. */ |
422 | ||
423 | static unsigned int | |
424 | riscv_min_arithmetic_precision (void) | |
425 | { | |
426 | return 32; | |
427 | } | |
428 | ||
72eb8335 | 429 | /* Return the riscv_tune_info entry for the given name string. */ |
09cae750 | 430 | |
72eb8335 KC |
431 | static const struct riscv_tune_info * |
432 | riscv_parse_tune (const char *tune_string) | |
09cae750 | 433 | { |
72eb8335 | 434 | const riscv_cpu_info *cpu = riscv_find_cpu (tune_string); |
09cae750 | 435 | |
72eb8335 KC |
436 | if (cpu) |
437 | tune_string = cpu->tune; | |
438 | ||
439 | for (unsigned i = 0; i < ARRAY_SIZE (riscv_tune_info_table); i++) | |
440 | if (strcmp (riscv_tune_info_table[i].name, tune_string) == 0) | |
441 | return riscv_tune_info_table + i; | |
442 | ||
443 | error ("unknown cpu %qs for %<-mtune%>", tune_string); | |
444 | return riscv_tune_info_table; | |
09cae750 PD |
445 | } |
446 | ||
447 | /* Helper function for riscv_build_integer; arguments are as for | |
448 | riscv_build_integer. */ | |
449 | ||
450 | static int | |
451 | riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS], | |
b8506a8a | 452 | HOST_WIDE_INT value, machine_mode mode) |
09cae750 PD |
453 | { |
454 | HOST_WIDE_INT low_part = CONST_LOW_PART (value); | |
455 | int cost = RISCV_MAX_INTEGER_OPS + 1, alt_cost; | |
456 | struct riscv_integer_op alt_codes[RISCV_MAX_INTEGER_OPS]; | |
457 | ||
458 | if (SMALL_OPERAND (value) || LUI_OPERAND (value)) | |
459 | { | |
460 | /* Simply ADDI or LUI. */ | |
461 | codes[0].code = UNKNOWN; | |
462 | codes[0].value = value; | |
463 | return 1; | |
464 | } | |
4e1e0d79 JW |
465 | if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value)) |
466 | { | |
467 | /* Simply BSETI. */ | |
468 | codes[0].code = UNKNOWN; | |
469 | codes[0].value = value; | |
4e72ccad PT |
470 | |
471 | /* RISC-V sign-extends all 32bit values that live in a 32bit | |
472 | register. To avoid paradoxes, we thus need to use the | |
473 | sign-extended (negative) representation (-1 << 31) for the | |
474 | value, if we want to build (1 << 31) in SImode. This will | |
475 | then expand to an LUI instruction. */ | |
2c721ea9 | 476 | if (TARGET_64BIT && mode == SImode && value == (HOST_WIDE_INT_1U << 31)) |
4e72ccad PT |
477 | codes[0].value = (HOST_WIDE_INT_M1U << 31); |
478 | ||
4e1e0d79 JW |
479 | return 1; |
480 | } | |
09cae750 PD |
481 | |
482 | /* End with ADDI. When constructing HImode constants, do not generate any | |
483 | intermediate value that is not itself a valid HImode constant. The | |
484 | XORI case below will handle those remaining HImode constants. */ | |
01726bc9 KT |
485 | if (low_part != 0 |
486 | && (mode != HImode | |
487 | || value - low_part <= ((1 << (GET_MODE_BITSIZE (HImode) - 1)) - 1))) | |
09cae750 | 488 | { |
2c721ea9 AP |
489 | HOST_WIDE_INT upper_part = value - low_part; |
490 | if (mode != VOIDmode) | |
491 | upper_part = trunc_int_for_mode (value - low_part, mode); | |
492 | ||
493 | alt_cost = 1 + riscv_build_integer_1 (alt_codes, upper_part, mode); | |
09cae750 PD |
494 | if (alt_cost < cost) |
495 | { | |
496 | alt_codes[alt_cost-1].code = PLUS; | |
497 | alt_codes[alt_cost-1].value = low_part; | |
498 | memcpy (codes, alt_codes, sizeof (alt_codes)); | |
499 | cost = alt_cost; | |
500 | } | |
501 | } | |
502 | ||
503 | /* End with XORI. */ | |
504 | if (cost > 2 && (low_part < 0 || mode == HImode)) | |
505 | { | |
506 | alt_cost = 1 + riscv_build_integer_1 (alt_codes, value ^ low_part, mode); | |
507 | if (alt_cost < cost) | |
508 | { | |
509 | alt_codes[alt_cost-1].code = XOR; | |
510 | alt_codes[alt_cost-1].value = low_part; | |
511 | memcpy (codes, alt_codes, sizeof (alt_codes)); | |
512 | cost = alt_cost; | |
513 | } | |
514 | } | |
515 | ||
516 | /* Eliminate trailing zeros and end with SLLI. */ | |
517 | if (cost > 2 && (value & 1) == 0) | |
518 | { | |
519 | int shift = ctz_hwi (value); | |
520 | unsigned HOST_WIDE_INT x = value; | |
521 | x = sext_hwi (x >> shift, HOST_BITS_PER_WIDE_INT - shift); | |
522 | ||
523 | /* Don't eliminate the lower 12 bits if LUI might apply. */ | |
524 | if (shift > IMM_BITS && !SMALL_OPERAND (x) && LUI_OPERAND (x << IMM_BITS)) | |
525 | shift -= IMM_BITS, x <<= IMM_BITS; | |
526 | ||
527 | alt_cost = 1 + riscv_build_integer_1 (alt_codes, x, mode); | |
528 | if (alt_cost < cost) | |
529 | { | |
530 | alt_codes[alt_cost-1].code = ASHIFT; | |
531 | alt_codes[alt_cost-1].value = shift; | |
532 | memcpy (codes, alt_codes, sizeof (alt_codes)); | |
533 | cost = alt_cost; | |
534 | } | |
535 | } | |
536 | ||
26d2818b JW |
537 | if (cost > 2 && TARGET_64BIT && TARGET_ZBB) |
538 | { | |
539 | int leading_ones = clz_hwi (~value); | |
540 | int trailing_ones = ctz_hwi (~value); | |
541 | ||
542 | /* If all bits are one except a few that are zero, and the zero bits | |
543 | are within a range of 11 bits, and at least one of the upper 32-bits | |
544 | is a zero, then we can generate a constant by loading a small | |
545 | negative constant and rotating. */ | |
546 | if (leading_ones < 32 | |
547 | && ((64 - leading_ones - trailing_ones) < 12)) | |
548 | { | |
549 | codes[0].code = UNKNOWN; | |
550 | /* The sign-bit might be zero, so just rotate to be safe. */ | |
551 | codes[0].value = (((unsigned HOST_WIDE_INT) value >> trailing_ones) | |
552 | | (value << (64 - trailing_ones))); | |
553 | codes[1].code = ROTATERT; | |
554 | codes[1].value = 64 - trailing_ones; | |
555 | cost = 2; | |
556 | } | |
557 | /* Handle the case where the 11 bit range of zero bits wraps around. */ | |
558 | else | |
559 | { | |
560 | int upper_trailing_ones = ctz_hwi (~value >> 32); | |
561 | int lower_leading_ones = clz_hwi (~value << 32); | |
562 | ||
563 | if (upper_trailing_ones < 32 && lower_leading_ones < 32 | |
564 | && ((64 - upper_trailing_ones - lower_leading_ones) < 12)) | |
565 | { | |
566 | codes[0].code = UNKNOWN; | |
567 | /* The sign-bit might be zero, so just rotate to be safe. */ | |
568 | codes[0].value = ((value << (32 - upper_trailing_ones)) | |
569 | | ((unsigned HOST_WIDE_INT) value | |
570 | >> (32 + upper_trailing_ones))); | |
571 | codes[1].code = ROTATERT; | |
572 | codes[1].value = 32 - upper_trailing_ones; | |
573 | cost = 2; | |
574 | } | |
575 | } | |
576 | } | |
577 | ||
09cae750 PD |
578 | gcc_assert (cost <= RISCV_MAX_INTEGER_OPS); |
579 | return cost; | |
580 | } | |
581 | ||
582 | /* Fill CODES with a sequence of rtl operations to load VALUE. | |
583 | Return the number of operations needed. */ | |
584 | ||
585 | static int | |
586 | riscv_build_integer (struct riscv_integer_op *codes, HOST_WIDE_INT value, | |
b8506a8a | 587 | machine_mode mode) |
09cae750 PD |
588 | { |
589 | int cost = riscv_build_integer_1 (codes, value, mode); | |
590 | ||
591 | /* Eliminate leading zeros and end with SRLI. */ | |
592 | if (value > 0 && cost > 2) | |
593 | { | |
594 | struct riscv_integer_op alt_codes[RISCV_MAX_INTEGER_OPS]; | |
595 | int alt_cost, shift = clz_hwi (value); | |
596 | HOST_WIDE_INT shifted_val; | |
597 | ||
598 | /* Try filling trailing bits with 1s. */ | |
599 | shifted_val = (value << shift) | ((((HOST_WIDE_INT) 1) << shift) - 1); | |
600 | alt_cost = 1 + riscv_build_integer_1 (alt_codes, shifted_val, mode); | |
601 | if (alt_cost < cost) | |
602 | { | |
603 | alt_codes[alt_cost-1].code = LSHIFTRT; | |
604 | alt_codes[alt_cost-1].value = shift; | |
605 | memcpy (codes, alt_codes, sizeof (alt_codes)); | |
606 | cost = alt_cost; | |
607 | } | |
608 | ||
609 | /* Try filling trailing bits with 0s. */ | |
610 | shifted_val = value << shift; | |
611 | alt_cost = 1 + riscv_build_integer_1 (alt_codes, shifted_val, mode); | |
612 | if (alt_cost < cost) | |
613 | { | |
614 | alt_codes[alt_cost-1].code = LSHIFTRT; | |
615 | alt_codes[alt_cost-1].value = shift; | |
616 | memcpy (codes, alt_codes, sizeof (alt_codes)); | |
617 | cost = alt_cost; | |
618 | } | |
619 | } | |
620 | ||
621 | return cost; | |
622 | } | |
623 | ||
624 | /* Return the cost of constructing VAL in the event that a scratch | |
625 | register is available. */ | |
626 | ||
627 | static int | |
628 | riscv_split_integer_cost (HOST_WIDE_INT val) | |
629 | { | |
630 | int cost; | |
631 | unsigned HOST_WIDE_INT loval = sext_hwi (val, 32); | |
632 | unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32); | |
633 | struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS]; | |
634 | ||
635 | cost = 2 + riscv_build_integer (codes, loval, VOIDmode); | |
636 | if (loval != hival) | |
637 | cost += riscv_build_integer (codes, hival, VOIDmode); | |
638 | ||
639 | return cost; | |
640 | } | |
641 | ||
642 | /* Return the cost of constructing the integer constant VAL. */ | |
643 | ||
644 | static int | |
645 | riscv_integer_cost (HOST_WIDE_INT val) | |
646 | { | |
647 | struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS]; | |
648 | return MIN (riscv_build_integer (codes, val, VOIDmode), | |
649 | riscv_split_integer_cost (val)); | |
650 | } | |
651 | ||
652 | /* Try to split a 64b integer into 32b parts, then reassemble. */ | |
653 | ||
654 | static rtx | |
b8506a8a | 655 | riscv_split_integer (HOST_WIDE_INT val, machine_mode mode) |
09cae750 PD |
656 | { |
657 | unsigned HOST_WIDE_INT loval = sext_hwi (val, 32); | |
658 | unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32); | |
659 | rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode); | |
660 | ||
a923a463 JW |
661 | riscv_move_integer (hi, hi, hival, mode, FALSE); |
662 | riscv_move_integer (lo, lo, loval, mode, FALSE); | |
09cae750 PD |
663 | |
664 | hi = gen_rtx_fmt_ee (ASHIFT, mode, hi, GEN_INT (32)); | |
665 | hi = force_reg (mode, hi); | |
666 | ||
667 | return gen_rtx_fmt_ee (PLUS, mode, hi, lo); | |
668 | } | |
669 | ||
670 | /* Return true if X is a thread-local symbol. */ | |
671 | ||
672 | static bool | |
673 | riscv_tls_symbol_p (const_rtx x) | |
674 | { | |
675 | return SYMBOL_REF_P (x) && SYMBOL_REF_TLS_MODEL (x) != 0; | |
676 | } | |
677 | ||
678 | /* Return true if symbol X binds locally. */ | |
679 | ||
680 | static bool | |
681 | riscv_symbol_binds_local_p (const_rtx x) | |
682 | { | |
683 | if (SYMBOL_REF_P (x)) | |
684 | return (SYMBOL_REF_DECL (x) | |
685 | ? targetm.binds_local_p (SYMBOL_REF_DECL (x)) | |
686 | : SYMBOL_REF_LOCAL_P (x)); | |
687 | else | |
688 | return false; | |
689 | } | |
690 | ||
691 | /* Return the method that should be used to access SYMBOL_REF or | |
692 | LABEL_REF X. */ | |
693 | ||
694 | static enum riscv_symbol_type | |
695 | riscv_classify_symbol (const_rtx x) | |
696 | { | |
697 | if (riscv_tls_symbol_p (x)) | |
698 | return SYMBOL_TLS; | |
699 | ||
700 | if (GET_CODE (x) == SYMBOL_REF && flag_pic && !riscv_symbol_binds_local_p (x)) | |
701 | return SYMBOL_GOT_DISP; | |
702 | ||
703 | return riscv_cmodel == CM_MEDLOW ? SYMBOL_ABSOLUTE : SYMBOL_PCREL; | |
704 | } | |
705 | ||
706 | /* Classify the base of symbolic expression X. */ | |
707 | ||
708 | enum riscv_symbol_type | |
709 | riscv_classify_symbolic_expression (rtx x) | |
710 | { | |
711 | rtx offset; | |
712 | ||
713 | split_const (x, &x, &offset); | |
714 | if (UNSPEC_ADDRESS_P (x)) | |
715 | return UNSPEC_ADDRESS_TYPE (x); | |
716 | ||
717 | return riscv_classify_symbol (x); | |
718 | } | |
719 | ||
720 | /* Return true if X is a symbolic constant. If it is, store the type of | |
721 | the symbol in *SYMBOL_TYPE. */ | |
722 | ||
723 | bool | |
724 | riscv_symbolic_constant_p (rtx x, enum riscv_symbol_type *symbol_type) | |
725 | { | |
726 | rtx offset; | |
727 | ||
728 | split_const (x, &x, &offset); | |
729 | if (UNSPEC_ADDRESS_P (x)) | |
730 | { | |
731 | *symbol_type = UNSPEC_ADDRESS_TYPE (x); | |
732 | x = UNSPEC_ADDRESS (x); | |
733 | } | |
734 | else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) | |
735 | *symbol_type = riscv_classify_symbol (x); | |
736 | else | |
737 | return false; | |
738 | ||
739 | if (offset == const0_rtx) | |
740 | return true; | |
741 | ||
742 | /* Nonzero offsets are only valid for references that don't use the GOT. */ | |
743 | switch (*symbol_type) | |
744 | { | |
745 | case SYMBOL_ABSOLUTE: | |
746 | case SYMBOL_PCREL: | |
747 | case SYMBOL_TLS_LE: | |
748 | /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */ | |
749 | return sext_hwi (INTVAL (offset), 32) == INTVAL (offset); | |
750 | ||
751 | default: | |
752 | return false; | |
753 | } | |
754 | } | |
755 | ||
756 | /* Returns the number of instructions necessary to reference a symbol. */ | |
757 | ||
758 | static int riscv_symbol_insns (enum riscv_symbol_type type) | |
759 | { | |
760 | switch (type) | |
761 | { | |
762 | case SYMBOL_TLS: return 0; /* Depends on the TLS model. */ | |
763 | case SYMBOL_ABSOLUTE: return 2; /* LUI + the reference. */ | |
764 | case SYMBOL_PCREL: return 2; /* AUIPC + the reference. */ | |
765 | case SYMBOL_TLS_LE: return 3; /* LUI + ADD TP + the reference. */ | |
766 | case SYMBOL_GOT_DISP: return 3; /* AUIPC + LD GOT + the reference. */ | |
767 | default: gcc_unreachable (); | |
768 | } | |
769 | } | |
770 | ||
771 | /* Implement TARGET_LEGITIMATE_CONSTANT_P. */ | |
772 | ||
773 | static bool | |
b8506a8a | 774 | riscv_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) |
09cae750 PD |
775 | { |
776 | return riscv_const_insns (x) > 0; | |
777 | } | |
778 | ||
779 | /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */ | |
780 | ||
781 | static bool | |
b8506a8a | 782 | riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) |
09cae750 PD |
783 | { |
784 | enum riscv_symbol_type type; | |
785 | rtx base, offset; | |
786 | ||
b4feb49c | 787 | /* There's no way to calculate VL-based values using relocations. */ |
788 | subrtx_iterator::array_type array; | |
789 | FOR_EACH_SUBRTX (iter, array, x, ALL) | |
790 | if (GET_CODE (*iter) == CONST_POLY_INT) | |
791 | return true; | |
792 | ||
09cae750 PD |
793 | /* There is no assembler syntax for expressing an address-sized |
794 | high part. */ | |
795 | if (GET_CODE (x) == HIGH) | |
796 | return true; | |
797 | ||
798 | split_const (x, &base, &offset); | |
799 | if (riscv_symbolic_constant_p (base, &type)) | |
800 | { | |
801 | /* As an optimization, don't spill symbolic constants that are as | |
802 | cheap to rematerialize as to access in the constant pool. */ | |
803 | if (SMALL_OPERAND (INTVAL (offset)) && riscv_symbol_insns (type) > 0) | |
804 | return true; | |
805 | ||
806 | /* As an optimization, avoid needlessly generate dynamic relocations. */ | |
807 | if (flag_pic) | |
808 | return true; | |
809 | } | |
810 | ||
811 | /* TLS symbols must be computed by riscv_legitimize_move. */ | |
812 | if (tls_referenced_p (x)) | |
813 | return true; | |
814 | ||
815 | return false; | |
816 | } | |
817 | ||
818 | /* Return true if register REGNO is a valid base register for mode MODE. | |
819 | STRICT_P is true if REG_OK_STRICT is in effect. */ | |
820 | ||
821 | int | |
822 | riscv_regno_mode_ok_for_base_p (int regno, | |
b8506a8a | 823 | machine_mode mode ATTRIBUTE_UNUSED, |
09cae750 PD |
824 | bool strict_p) |
825 | { | |
826 | if (!HARD_REGISTER_NUM_P (regno)) | |
827 | { | |
828 | if (!strict_p) | |
829 | return true; | |
830 | regno = reg_renumber[regno]; | |
831 | } | |
832 | ||
833 | /* These fake registers will be eliminated to either the stack or | |
834 | hard frame pointer, both of which are usually valid base registers. | |
835 | Reload deals with the cases where the eliminated form isn't valid. */ | |
836 | if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) | |
837 | return true; | |
838 | ||
839 | return GP_REG_P (regno); | |
840 | } | |
841 | ||
842 | /* Return true if X is a valid base register for mode MODE. | |
843 | STRICT_P is true if REG_OK_STRICT is in effect. */ | |
844 | ||
845 | static bool | |
b8506a8a | 846 | riscv_valid_base_register_p (rtx x, machine_mode mode, bool strict_p) |
09cae750 PD |
847 | { |
848 | if (!strict_p && GET_CODE (x) == SUBREG) | |
849 | x = SUBREG_REG (x); | |
850 | ||
851 | return (REG_P (x) | |
852 | && riscv_regno_mode_ok_for_base_p (REGNO (x), mode, strict_p)); | |
853 | } | |
854 | ||
855 | /* Return true if, for every base register BASE_REG, (plus BASE_REG X) | |
856 | can address a value of mode MODE. */ | |
857 | ||
858 | static bool | |
b8506a8a | 859 | riscv_valid_offset_p (rtx x, machine_mode mode) |
09cae750 PD |
860 | { |
861 | /* Check that X is a signed 12-bit number. */ | |
862 | if (!const_arith_operand (x, Pmode)) | |
863 | return false; | |
864 | ||
865 | /* We may need to split multiword moves, so make sure that every word | |
866 | is accessible. */ | |
3496ca4e | 867 | if (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD |
868 | && !SMALL_OPERAND (INTVAL (x) + GET_MODE_SIZE (mode).to_constant () - UNITS_PER_WORD)) | |
09cae750 PD |
869 | return false; |
870 | ||
871 | return true; | |
872 | } | |
873 | ||
874 | /* Should a symbol of type SYMBOL_TYPE should be split in two? */ | |
875 | ||
876 | bool | |
877 | riscv_split_symbol_type (enum riscv_symbol_type symbol_type) | |
878 | { | |
879 | if (symbol_type == SYMBOL_TLS_LE) | |
880 | return true; | |
881 | ||
882 | if (!TARGET_EXPLICIT_RELOCS) | |
883 | return false; | |
884 | ||
885 | return symbol_type == SYMBOL_ABSOLUTE || symbol_type == SYMBOL_PCREL; | |
886 | } | |
887 | ||
888 | /* Return true if a LO_SUM can address a value of mode MODE when the | |
026216a7 JW |
889 | LO_SUM symbol has type SYM_TYPE. X is the LO_SUM second operand, which |
890 | is used when the mode is BLKmode. */ | |
09cae750 PD |
891 | |
892 | static bool | |
026216a7 JW |
893 | riscv_valid_lo_sum_p (enum riscv_symbol_type sym_type, machine_mode mode, |
894 | rtx x) | |
09cae750 | 895 | { |
026216a7 JW |
896 | int align, size; |
897 | ||
09cae750 PD |
898 | /* Check that symbols of type SYMBOL_TYPE can be used to access values |
899 | of mode MODE. */ | |
900 | if (riscv_symbol_insns (sym_type) == 0) | |
901 | return false; | |
902 | ||
903 | /* Check that there is a known low-part relocation. */ | |
904 | if (!riscv_split_symbol_type (sym_type)) | |
905 | return false; | |
906 | ||
026216a7 JW |
907 | /* We can't tell size or alignment when we have BLKmode, so try extracing a |
908 | decl from the symbol if possible. */ | |
909 | if (mode == BLKmode) | |
910 | { | |
911 | rtx offset; | |
912 | ||
913 | /* Extract the symbol from the LO_SUM operand, if any. */ | |
914 | split_const (x, &x, &offset); | |
915 | ||
916 | /* Might be a CODE_LABEL. We can compute align but not size for that, | |
917 | so don't bother trying to handle it. */ | |
918 | if (!SYMBOL_REF_P (x)) | |
919 | return false; | |
920 | ||
921 | /* Use worst case assumptions if we don't have a SYMBOL_REF_DECL. */ | |
922 | align = (SYMBOL_REF_DECL (x) | |
923 | ? DECL_ALIGN (SYMBOL_REF_DECL (x)) | |
924 | : 1); | |
925 | size = (SYMBOL_REF_DECL (x) && DECL_SIZE (SYMBOL_REF_DECL (x)) | |
926 | ? tree_to_uhwi (DECL_SIZE (SYMBOL_REF_DECL (x))) | |
927 | : 2*BITS_PER_WORD); | |
928 | } | |
929 | else | |
930 | { | |
931 | align = GET_MODE_ALIGNMENT (mode); | |
3496ca4e | 932 | size = GET_MODE_BITSIZE (mode).to_constant (); |
026216a7 JW |
933 | } |
934 | ||
09cae750 PD |
935 | /* We may need to split multiword moves, so make sure that each word |
936 | can be accessed without inducing a carry. */ | |
026216a7 JW |
937 | if (size > BITS_PER_WORD |
938 | && (!TARGET_STRICT_ALIGN || size > align)) | |
09cae750 PD |
939 | return false; |
940 | ||
941 | return true; | |
942 | } | |
943 | ||
31380d4b | 944 | /* Return true if mode is the RVV mode. */ |
945 | ||
946 | static bool | |
947 | riscv_v_ext_vector_mode_p (machine_mode mode) | |
948 | { | |
03f33657 JZZ |
949 | #define ENTRY(MODE, REQUIREMENT) \ |
950 | case MODE##mode: \ | |
951 | return true; | |
952 | switch (mode) | |
953 | { | |
954 | #include "riscv-vector-switch.def" | |
955 | default: | |
956 | return false; | |
957 | } | |
958 | ||
959 | return false; | |
960 | } | |
961 | ||
962 | /* Return true if mode is the RVV enabled mode. | |
963 | For example: 'VNx1DI' mode is disabled if MIN_VLEN == 32. | |
964 | 'VNx1SI' mode is enabled if MIN_VLEN == 32. */ | |
965 | ||
966 | bool | |
967 | riscv_v_ext_enabled_vector_mode_p (machine_mode mode) | |
968 | { | |
969 | #define ENTRY(MODE, REQUIREMENT) \ | |
970 | case MODE##mode: \ | |
971 | return REQUIREMENT; | |
972 | switch (mode) | |
973 | { | |
974 | #include "riscv-vector-switch.def" | |
975 | default: | |
976 | return false; | |
977 | } | |
978 | ||
979 | return false; | |
31380d4b | 980 | } |
981 | ||
09cae750 PD |
982 | /* Return true if X is a valid address for machine mode MODE. If it is, |
983 | fill in INFO appropriately. STRICT_P is true if REG_OK_STRICT is in | |
984 | effect. */ | |
985 | ||
986 | static bool | |
987 | riscv_classify_address (struct riscv_address_info *info, rtx x, | |
b8506a8a | 988 | machine_mode mode, bool strict_p) |
09cae750 PD |
989 | { |
990 | switch (GET_CODE (x)) | |
991 | { | |
992 | case REG: | |
993 | case SUBREG: | |
994 | info->type = ADDRESS_REG; | |
995 | info->reg = x; | |
996 | info->offset = const0_rtx; | |
997 | return riscv_valid_base_register_p (info->reg, mode, strict_p); | |
998 | ||
999 | case PLUS: | |
31380d4b | 1000 | /* RVV load/store disallow any offset. */ |
1001 | if (riscv_v_ext_vector_mode_p (mode)) | |
1002 | return false; | |
1003 | ||
09cae750 PD |
1004 | info->type = ADDRESS_REG; |
1005 | info->reg = XEXP (x, 0); | |
1006 | info->offset = XEXP (x, 1); | |
1007 | return (riscv_valid_base_register_p (info->reg, mode, strict_p) | |
1008 | && riscv_valid_offset_p (info->offset, mode)); | |
1009 | ||
1010 | case LO_SUM: | |
31380d4b | 1011 | /* RVV load/store disallow LO_SUM. */ |
1012 | if (riscv_v_ext_vector_mode_p (mode)) | |
1013 | return false; | |
1014 | ||
09cae750 PD |
1015 | info->type = ADDRESS_LO_SUM; |
1016 | info->reg = XEXP (x, 0); | |
1017 | info->offset = XEXP (x, 1); | |
1018 | /* We have to trust the creator of the LO_SUM to do something vaguely | |
1019 | sane. Target-independent code that creates a LO_SUM should also | |
1020 | create and verify the matching HIGH. Target-independent code that | |
1021 | adds an offset to a LO_SUM must prove that the offset will not | |
1022 | induce a carry. Failure to do either of these things would be | |
1023 | a bug, and we are not required to check for it here. The RISC-V | |
1024 | backend itself should only create LO_SUMs for valid symbolic | |
1025 | constants, with the high part being either a HIGH or a copy | |
1026 | of _gp. */ | |
1027 | info->symbol_type | |
1028 | = riscv_classify_symbolic_expression (info->offset); | |
1029 | return (riscv_valid_base_register_p (info->reg, mode, strict_p) | |
026216a7 | 1030 | && riscv_valid_lo_sum_p (info->symbol_type, mode, info->offset)); |
09cae750 PD |
1031 | |
1032 | case CONST_INT: | |
31380d4b | 1033 | /* RVV load/store disallow CONST_INT. */ |
1034 | if (riscv_v_ext_vector_mode_p (mode)) | |
1035 | return false; | |
1036 | ||
09cae750 PD |
1037 | /* Small-integer addresses don't occur very often, but they |
1038 | are legitimate if x0 is a valid base register. */ | |
1039 | info->type = ADDRESS_CONST_INT; | |
1040 | return SMALL_OPERAND (INTVAL (x)); | |
1041 | ||
1042 | default: | |
1043 | return false; | |
1044 | } | |
1045 | } | |
1046 | ||
1047 | /* Implement TARGET_LEGITIMATE_ADDRESS_P. */ | |
1048 | ||
1049 | static bool | |
b8506a8a | 1050 | riscv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p) |
09cae750 PD |
1051 | { |
1052 | struct riscv_address_info addr; | |
1053 | ||
1054 | return riscv_classify_address (&addr, x, mode, strict_p); | |
1055 | } | |
1056 | ||
de6320a8 CB |
1057 | /* Return true if hard reg REGNO can be used in compressed instructions. */ |
1058 | ||
1059 | static bool | |
1060 | riscv_compressed_reg_p (int regno) | |
1061 | { | |
1062 | /* x8-x15/f8-f15 are compressible registers. */ | |
1063 | return (TARGET_RVC && (IN_RANGE (regno, GP_REG_FIRST + 8, GP_REG_FIRST + 15) | |
1064 | || IN_RANGE (regno, FP_REG_FIRST + 8, FP_REG_FIRST + 15))); | |
1065 | } | |
1066 | ||
1067 | /* Return true if x is an unsigned 5-bit immediate scaled by 4. */ | |
1068 | ||
1069 | static bool | |
1070 | riscv_compressed_lw_offset_p (rtx x) | |
1071 | { | |
1072 | return (CONST_INT_P (x) | |
1073 | && (INTVAL (x) & 3) == 0 | |
1074 | && IN_RANGE (INTVAL (x), 0, CSW_MAX_OFFSET)); | |
1075 | } | |
1076 | ||
1077 | /* Return true if load/store from/to address x can be compressed. */ | |
1078 | ||
1079 | static bool | |
1080 | riscv_compressed_lw_address_p (rtx x) | |
1081 | { | |
1082 | struct riscv_address_info addr; | |
1083 | bool result = riscv_classify_address (&addr, x, GET_MODE (x), | |
1084 | reload_completed); | |
1085 | ||
de6320a8 CB |
1086 | /* Return false if address is not compressed_reg + small_offset. */ |
1087 | if (!result | |
1088 | || addr.type != ADDRESS_REG | |
a4953810 JW |
1089 | /* Before reload, assume all registers are OK. */ |
1090 | || (reload_completed | |
1091 | && !riscv_compressed_reg_p (REGNO (addr.reg)) | |
1092 | && addr.reg != stack_pointer_rtx) | |
de6320a8 CB |
1093 | || !riscv_compressed_lw_offset_p (addr.offset)) |
1094 | return false; | |
1095 | ||
1096 | return result; | |
1097 | } | |
1098 | ||
09cae750 PD |
1099 | /* Return the number of instructions needed to load or store a value |
1100 | of mode MODE at address X. Return 0 if X isn't valid for MODE. | |
1101 | Assume that multiword moves may need to be split into word moves | |
1102 | if MIGHT_SPLIT_P, otherwise assume that a single load or store is | |
1103 | enough. */ | |
1104 | ||
1105 | int | |
b8506a8a | 1106 | riscv_address_insns (rtx x, machine_mode mode, bool might_split_p) |
09cae750 | 1107 | { |
e89a689f | 1108 | struct riscv_address_info addr = {}; |
09cae750 PD |
1109 | int n = 1; |
1110 | ||
1111 | if (!riscv_classify_address (&addr, x, mode, false)) | |
efc60124 JW |
1112 | { |
1113 | /* This could be a pattern from the pic.md file. In which case we want | |
1114 | this address to always have a cost of 3 to make it as expensive as the | |
1115 | most expensive symbol. This prevents constant propagation from | |
1116 | preferring symbols over register plus offset. */ | |
1117 | return 3; | |
1118 | } | |
09cae750 PD |
1119 | |
1120 | /* BLKmode is used for single unaligned loads and stores and should | |
1121 | not count as a multiword mode. */ | |
31380d4b | 1122 | if (!riscv_v_ext_vector_mode_p (mode) && mode != BLKmode && might_split_p) |
3496ca4e | 1123 | n += (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
09cae750 PD |
1124 | |
1125 | if (addr.type == ADDRESS_LO_SUM) | |
1126 | n += riscv_symbol_insns (addr.symbol_type) - 1; | |
1127 | ||
1128 | return n; | |
1129 | } | |
1130 | ||
1131 | /* Return the number of instructions needed to load constant X. | |
1132 | Return 0 if X isn't a valid constant. */ | |
1133 | ||
1134 | int | |
1135 | riscv_const_insns (rtx x) | |
1136 | { | |
1137 | enum riscv_symbol_type symbol_type; | |
1138 | rtx offset; | |
1139 | ||
1140 | switch (GET_CODE (x)) | |
1141 | { | |
1142 | case HIGH: | |
1143 | if (!riscv_symbolic_constant_p (XEXP (x, 0), &symbol_type) | |
1144 | || !riscv_split_symbol_type (symbol_type)) | |
1145 | return 0; | |
1146 | ||
1147 | /* This is simply an LUI. */ | |
1148 | return 1; | |
1149 | ||
1150 | case CONST_INT: | |
1151 | { | |
1152 | int cost = riscv_integer_cost (INTVAL (x)); | |
1153 | /* Force complicated constants to memory. */ | |
1154 | return cost < 4 ? cost : 0; | |
1155 | } | |
1156 | ||
1157 | case CONST_DOUBLE: | |
1158 | case CONST_VECTOR: | |
1159 | /* We can use x0 to load floating-point zero. */ | |
1160 | return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0; | |
1161 | ||
1162 | case CONST: | |
1163 | /* See if we can refer to X directly. */ | |
1164 | if (riscv_symbolic_constant_p (x, &symbol_type)) | |
1165 | return riscv_symbol_insns (symbol_type); | |
1166 | ||
1167 | /* Otherwise try splitting the constant into a base and offset. */ | |
1168 | split_const (x, &x, &offset); | |
1169 | if (offset != 0) | |
1170 | { | |
1171 | int n = riscv_const_insns (x); | |
1172 | if (n != 0) | |
1173 | return n + riscv_integer_cost (INTVAL (offset)); | |
1174 | } | |
1175 | return 0; | |
1176 | ||
1177 | case SYMBOL_REF: | |
1178 | case LABEL_REF: | |
1179 | return riscv_symbol_insns (riscv_classify_symbol (x)); | |
1180 | ||
8fe75147 | 1181 | /* TODO: In RVV, we get CONST_POLY_INT by using csrr VLENB |
1182 | instruction and several scalar shift or mult instructions, | |
1183 | it is so far unknown. We set it to 4 temporarily. */ | |
1184 | case CONST_POLY_INT: | |
1185 | return 4; | |
1186 | ||
09cae750 PD |
1187 | default: |
1188 | return 0; | |
1189 | } | |
1190 | } | |
1191 | ||
1192 | /* X is a doubleword constant that can be handled by splitting it into | |
1193 | two words and loading each word separately. Return the number of | |
1194 | instructions required to do this. */ | |
1195 | ||
1196 | int | |
1197 | riscv_split_const_insns (rtx x) | |
1198 | { | |
1199 | unsigned int low, high; | |
1200 | ||
1201 | low = riscv_const_insns (riscv_subword (x, false)); | |
1202 | high = riscv_const_insns (riscv_subword (x, true)); | |
1203 | gcc_assert (low > 0 && high > 0); | |
1204 | return low + high; | |
1205 | } | |
1206 | ||
1207 | /* Return the number of instructions needed to implement INSN, | |
1208 | given that it loads from or stores to MEM. */ | |
1209 | ||
1210 | int | |
1211 | riscv_load_store_insns (rtx mem, rtx_insn *insn) | |
1212 | { | |
b8506a8a | 1213 | machine_mode mode; |
09cae750 PD |
1214 | bool might_split_p; |
1215 | rtx set; | |
1216 | ||
1217 | gcc_assert (MEM_P (mem)); | |
1218 | mode = GET_MODE (mem); | |
1219 | ||
1220 | /* Try to prove that INSN does not need to be split. */ | |
1221 | might_split_p = true; | |
3496ca4e | 1222 | if (GET_MODE_BITSIZE (mode).to_constant () <= 32) |
09cae750 | 1223 | might_split_p = false; |
3496ca4e | 1224 | else if (GET_MODE_BITSIZE (mode).to_constant () == 64) |
09cae750 PD |
1225 | { |
1226 | set = single_set (insn); | |
1227 | if (set && !riscv_split_64bit_move_p (SET_DEST (set), SET_SRC (set))) | |
1228 | might_split_p = false; | |
1229 | } | |
1230 | ||
1231 | return riscv_address_insns (XEXP (mem, 0), mode, might_split_p); | |
1232 | } | |
1233 | ||
1234 | /* Emit a move from SRC to DEST. Assume that the move expanders can | |
1235 | handle all moves if !can_create_pseudo_p (). The distinction is | |
1236 | important because, unlike emit_move_insn, the move expanders know | |
1237 | how to force Pmode objects into the constant pool even when the | |
1238 | constant pool address is not itself legitimate. */ | |
1239 | ||
1240 | rtx | |
1241 | riscv_emit_move (rtx dest, rtx src) | |
1242 | { | |
1243 | return (can_create_pseudo_p () | |
1244 | ? emit_move_insn (dest, src) | |
1245 | : emit_move_insn_1 (dest, src)); | |
1246 | } | |
1247 | ||
1248 | /* Emit an instruction of the form (set TARGET SRC). */ | |
1249 | ||
1250 | static rtx | |
1251 | riscv_emit_set (rtx target, rtx src) | |
1252 | { | |
1253 | emit_insn (gen_rtx_SET (target, src)); | |
1254 | return target; | |
1255 | } | |
1256 | ||
1257 | /* Emit an instruction of the form (set DEST (CODE X Y)). */ | |
1258 | ||
1259 | static rtx | |
1260 | riscv_emit_binary (enum rtx_code code, rtx dest, rtx x, rtx y) | |
1261 | { | |
1262 | return riscv_emit_set (dest, gen_rtx_fmt_ee (code, GET_MODE (dest), x, y)); | |
1263 | } | |
1264 | ||
1265 | /* Compute (CODE X Y) and store the result in a new register | |
1266 | of mode MODE. Return that new register. */ | |
1267 | ||
1268 | static rtx | |
b8506a8a | 1269 | riscv_force_binary (machine_mode mode, enum rtx_code code, rtx x, rtx y) |
09cae750 PD |
1270 | { |
1271 | return riscv_emit_binary (code, gen_reg_rtx (mode), x, y); | |
1272 | } | |
1273 | ||
28bddf0e MC |
1274 | static rtx |
1275 | riscv_swap_instruction (rtx inst) | |
1276 | { | |
1277 | gcc_assert (GET_MODE (inst) == SImode); | |
1278 | if (BYTES_BIG_ENDIAN) | |
1279 | inst = expand_unop (SImode, bswap_optab, inst, gen_reg_rtx (SImode), 1); | |
1280 | return inst; | |
1281 | } | |
1282 | ||
09cae750 PD |
1283 | /* Copy VALUE to a register and return that register. If new pseudos |
1284 | are allowed, copy it into a new register, otherwise use DEST. */ | |
1285 | ||
1286 | static rtx | |
a923a463 | 1287 | riscv_force_temporary (rtx dest, rtx value, bool in_splitter) |
09cae750 | 1288 | { |
a923a463 JW |
1289 | /* We can't call gen_reg_rtx from a splitter, because this might realloc |
1290 | the regno_reg_rtx array, which would invalidate reg rtx pointers in the | |
1291 | combine undo buffer. */ | |
1292 | if (can_create_pseudo_p () && !in_splitter) | |
09cae750 PD |
1293 | return force_reg (Pmode, value); |
1294 | else | |
1295 | { | |
1296 | riscv_emit_move (dest, value); | |
1297 | return dest; | |
1298 | } | |
1299 | } | |
1300 | ||
1301 | /* Wrap symbol or label BASE in an UNSPEC address of type SYMBOL_TYPE, | |
1302 | then add CONST_INT OFFSET to the result. */ | |
1303 | ||
1304 | static rtx | |
1305 | riscv_unspec_address_offset (rtx base, rtx offset, | |
1306 | enum riscv_symbol_type symbol_type) | |
1307 | { | |
1308 | base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), | |
1309 | UNSPEC_ADDRESS_FIRST + symbol_type); | |
1310 | if (offset != const0_rtx) | |
1311 | base = gen_rtx_PLUS (Pmode, base, offset); | |
1312 | return gen_rtx_CONST (Pmode, base); | |
1313 | } | |
1314 | ||
1315 | /* Return an UNSPEC address with underlying address ADDRESS and symbol | |
1316 | type SYMBOL_TYPE. */ | |
1317 | ||
1318 | rtx | |
1319 | riscv_unspec_address (rtx address, enum riscv_symbol_type symbol_type) | |
1320 | { | |
1321 | rtx base, offset; | |
1322 | ||
1323 | split_const (address, &base, &offset); | |
1324 | return riscv_unspec_address_offset (base, offset, symbol_type); | |
1325 | } | |
1326 | ||
1327 | /* If OP is an UNSPEC address, return the address to which it refers, | |
1328 | otherwise return OP itself. */ | |
1329 | ||
1330 | static rtx | |
1331 | riscv_strip_unspec_address (rtx op) | |
1332 | { | |
1333 | rtx base, offset; | |
1334 | ||
1335 | split_const (op, &base, &offset); | |
1336 | if (UNSPEC_ADDRESS_P (base)) | |
1337 | op = plus_constant (Pmode, UNSPEC_ADDRESS (base), INTVAL (offset)); | |
1338 | return op; | |
1339 | } | |
1340 | ||
1341 | /* If riscv_unspec_address (ADDR, SYMBOL_TYPE) is a 32-bit value, add the | |
1342 | high part to BASE and return the result. Just return BASE otherwise. | |
1343 | TEMP is as for riscv_force_temporary. | |
1344 | ||
1345 | The returned expression can be used as the first operand to a LO_SUM. */ | |
1346 | ||
1347 | static rtx | |
1348 | riscv_unspec_offset_high (rtx temp, rtx addr, enum riscv_symbol_type symbol_type) | |
1349 | { | |
1350 | addr = gen_rtx_HIGH (Pmode, riscv_unspec_address (addr, symbol_type)); | |
a923a463 | 1351 | return riscv_force_temporary (temp, addr, FALSE); |
09cae750 PD |
1352 | } |
1353 | ||
1354 | /* Load an entry from the GOT for a TLS GD access. */ | |
1355 | ||
1356 | static rtx riscv_got_load_tls_gd (rtx dest, rtx sym) | |
1357 | { | |
1358 | if (Pmode == DImode) | |
1359 | return gen_got_load_tls_gddi (dest, sym); | |
1360 | else | |
1361 | return gen_got_load_tls_gdsi (dest, sym); | |
1362 | } | |
1363 | ||
1364 | /* Load an entry from the GOT for a TLS IE access. */ | |
1365 | ||
1366 | static rtx riscv_got_load_tls_ie (rtx dest, rtx sym) | |
1367 | { | |
1368 | if (Pmode == DImode) | |
1369 | return gen_got_load_tls_iedi (dest, sym); | |
1370 | else | |
1371 | return gen_got_load_tls_iesi (dest, sym); | |
1372 | } | |
1373 | ||
1374 | /* Add in the thread pointer for a TLS LE access. */ | |
1375 | ||
1376 | static rtx riscv_tls_add_tp_le (rtx dest, rtx base, rtx sym) | |
1377 | { | |
1378 | rtx tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); | |
1379 | if (Pmode == DImode) | |
1380 | return gen_tls_add_tp_ledi (dest, base, tp, sym); | |
1381 | else | |
1382 | return gen_tls_add_tp_lesi (dest, base, tp, sym); | |
1383 | } | |
1384 | ||
1385 | /* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise | |
1386 | it appears in a MEM of that mode. Return true if ADDR is a legitimate | |
1387 | constant in that context and can be split into high and low parts. | |
1388 | If so, and if LOW_OUT is nonnull, emit the high part and store the | |
1389 | low part in *LOW_OUT. Leave *LOW_OUT unchanged otherwise. | |
1390 | ||
1391 | TEMP is as for riscv_force_temporary and is used to load the high | |
1392 | part into a register. | |
1393 | ||
1394 | When MODE is MAX_MACHINE_MODE, the low part is guaranteed to be | |
1395 | a legitimize SET_SRC for an .md pattern, otherwise the low part | |
1396 | is guaranteed to be a legitimate address for mode MODE. */ | |
1397 | ||
1398 | bool | |
a923a463 JW |
1399 | riscv_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out, |
1400 | bool in_splitter) | |
09cae750 PD |
1401 | { |
1402 | enum riscv_symbol_type symbol_type; | |
1403 | ||
1404 | if ((GET_CODE (addr) == HIGH && mode == MAX_MACHINE_MODE) | |
1405 | || !riscv_symbolic_constant_p (addr, &symbol_type) | |
1406 | || riscv_symbol_insns (symbol_type) == 0 | |
1407 | || !riscv_split_symbol_type (symbol_type)) | |
1408 | return false; | |
1409 | ||
1410 | if (low_out) | |
1411 | switch (symbol_type) | |
1412 | { | |
1413 | case SYMBOL_ABSOLUTE: | |
1414 | { | |
1415 | rtx high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); | |
a923a463 | 1416 | high = riscv_force_temporary (temp, high, in_splitter); |
09cae750 PD |
1417 | *low_out = gen_rtx_LO_SUM (Pmode, high, addr); |
1418 | } | |
1419 | break; | |
1420 | ||
1421 | case SYMBOL_PCREL: | |
1422 | { | |
1423 | static unsigned seqno; | |
1424 | char buf[32]; | |
1425 | rtx label; | |
1426 | ||
1427 | ssize_t bytes = snprintf (buf, sizeof (buf), ".LA%u", seqno); | |
1428 | gcc_assert ((size_t) bytes < sizeof (buf)); | |
1429 | ||
1430 | label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); | |
1431 | SYMBOL_REF_FLAGS (label) |= SYMBOL_FLAG_LOCAL; | |
ad117173 JW |
1432 | /* ??? Ugly hack to make weak symbols work. May need to change the |
1433 | RTL for the auipc and/or low patterns to get a better fix for | |
1434 | this. */ | |
1435 | if (! nonzero_address_p (addr)) | |
1436 | SYMBOL_REF_WEAK (label) = 1; | |
09cae750 PD |
1437 | |
1438 | if (temp == NULL) | |
1439 | temp = gen_reg_rtx (Pmode); | |
1440 | ||
1441 | if (Pmode == DImode) | |
1442 | emit_insn (gen_auipcdi (temp, copy_rtx (addr), GEN_INT (seqno))); | |
1443 | else | |
1444 | emit_insn (gen_auipcsi (temp, copy_rtx (addr), GEN_INT (seqno))); | |
1445 | ||
1446 | *low_out = gen_rtx_LO_SUM (Pmode, temp, label); | |
1447 | ||
1448 | seqno++; | |
1449 | } | |
1450 | break; | |
1451 | ||
1452 | default: | |
1453 | gcc_unreachable (); | |
1454 | } | |
1455 | ||
1456 | return true; | |
1457 | } | |
1458 | ||
1459 | /* Return a legitimate address for REG + OFFSET. TEMP is as for | |
1460 | riscv_force_temporary; it is only needed when OFFSET is not a | |
1461 | SMALL_OPERAND. */ | |
1462 | ||
1463 | static rtx | |
1464 | riscv_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset) | |
1465 | { | |
1466 | if (!SMALL_OPERAND (offset)) | |
1467 | { | |
1468 | rtx high; | |
1469 | ||
1470 | /* Leave OFFSET as a 16-bit offset and put the excess in HIGH. | |
1471 | The addition inside the macro CONST_HIGH_PART may cause an | |
1472 | overflow, so we need to force a sign-extension check. */ | |
1473 | high = gen_int_mode (CONST_HIGH_PART (offset), Pmode); | |
1474 | offset = CONST_LOW_PART (offset); | |
a923a463 JW |
1475 | high = riscv_force_temporary (temp, high, FALSE); |
1476 | reg = riscv_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg), | |
1477 | FALSE); | |
09cae750 PD |
1478 | } |
1479 | return plus_constant (Pmode, reg, offset); | |
1480 | } | |
1481 | ||
1482 | /* The __tls_get_attr symbol. */ | |
1483 | static GTY(()) rtx riscv_tls_symbol; | |
1484 | ||
1485 | /* Return an instruction sequence that calls __tls_get_addr. SYM is | |
1486 | the TLS symbol we are referencing and TYPE is the symbol type to use | |
1487 | (either global dynamic or local dynamic). RESULT is an RTX for the | |
1488 | return value location. */ | |
1489 | ||
1490 | static rtx_insn * | |
1491 | riscv_call_tls_get_addr (rtx sym, rtx result) | |
1492 | { | |
1493 | rtx a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST), func; | |
1494 | rtx_insn *insn; | |
1495 | ||
1496 | if (!riscv_tls_symbol) | |
1497 | riscv_tls_symbol = init_one_libfunc ("__tls_get_addr"); | |
1498 | func = gen_rtx_MEM (FUNCTION_MODE, riscv_tls_symbol); | |
1499 | ||
1500 | start_sequence (); | |
1501 | ||
1502 | emit_insn (riscv_got_load_tls_gd (a0, sym)); | |
1503 | insn = emit_call_insn (gen_call_value (result, func, const0_rtx, NULL)); | |
1504 | RTL_CONST_CALL_P (insn) = 1; | |
1505 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0); | |
1506 | insn = get_insns (); | |
1507 | ||
1508 | end_sequence (); | |
1509 | ||
1510 | return insn; | |
1511 | } | |
1512 | ||
1513 | /* Generate the code to access LOC, a thread-local SYMBOL_REF, and return | |
1514 | its address. The return value will be both a valid address and a valid | |
1515 | SET_SRC (either a REG or a LO_SUM). */ | |
1516 | ||
1517 | static rtx | |
1518 | riscv_legitimize_tls_address (rtx loc) | |
1519 | { | |
1520 | rtx dest, tp, tmp; | |
1521 | enum tls_model model = SYMBOL_REF_TLS_MODEL (loc); | |
1522 | ||
dca7e570 JW |
1523 | #if 0 |
1524 | /* TLS copy relocs are now deprecated and should not be used. */ | |
09cae750 PD |
1525 | /* Since we support TLS copy relocs, non-PIC TLS accesses may all use LE. */ |
1526 | if (!flag_pic) | |
1527 | model = TLS_MODEL_LOCAL_EXEC; | |
dca7e570 | 1528 | #endif |
09cae750 PD |
1529 | |
1530 | switch (model) | |
1531 | { | |
1532 | case TLS_MODEL_LOCAL_DYNAMIC: | |
1533 | /* Rely on section anchors for the optimization that LDM TLS | |
1534 | provides. The anchor's address is loaded with GD TLS. */ | |
1535 | case TLS_MODEL_GLOBAL_DYNAMIC: | |
1536 | tmp = gen_rtx_REG (Pmode, GP_RETURN); | |
1537 | dest = gen_reg_rtx (Pmode); | |
1538 | emit_libcall_block (riscv_call_tls_get_addr (loc, tmp), dest, tmp, loc); | |
1539 | break; | |
1540 | ||
1541 | case TLS_MODEL_INITIAL_EXEC: | |
1542 | /* la.tls.ie; tp-relative add */ | |
1543 | tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); | |
1544 | tmp = gen_reg_rtx (Pmode); | |
1545 | emit_insn (riscv_got_load_tls_ie (tmp, loc)); | |
1546 | dest = gen_reg_rtx (Pmode); | |
1547 | emit_insn (gen_add3_insn (dest, tmp, tp)); | |
1548 | break; | |
1549 | ||
1550 | case TLS_MODEL_LOCAL_EXEC: | |
1551 | tmp = riscv_unspec_offset_high (NULL, loc, SYMBOL_TLS_LE); | |
1552 | dest = gen_reg_rtx (Pmode); | |
1553 | emit_insn (riscv_tls_add_tp_le (dest, tmp, loc)); | |
1554 | dest = gen_rtx_LO_SUM (Pmode, dest, | |
1555 | riscv_unspec_address (loc, SYMBOL_TLS_LE)); | |
1556 | break; | |
1557 | ||
1558 | default: | |
1559 | gcc_unreachable (); | |
1560 | } | |
1561 | return dest; | |
1562 | } | |
1563 | \f | |
1564 | /* If X is not a valid address for mode MODE, force it into a register. */ | |
1565 | ||
1566 | static rtx | |
b8506a8a | 1567 | riscv_force_address (rtx x, machine_mode mode) |
09cae750 PD |
1568 | { |
1569 | if (!riscv_legitimate_address_p (mode, x, false)) | |
1570 | x = force_reg (Pmode, x); | |
1571 | return x; | |
1572 | } | |
1573 | ||
de6320a8 CB |
1574 | /* Modify base + offset so that offset fits within a compressed load/store insn |
1575 | and the excess is added to base. */ | |
1576 | ||
1577 | static rtx | |
1578 | riscv_shorten_lw_offset (rtx base, HOST_WIDE_INT offset) | |
1579 | { | |
1580 | rtx addr, high; | |
1581 | /* Leave OFFSET as an unsigned 5-bit offset scaled by 4 and put the excess | |
1582 | into HIGH. */ | |
1583 | high = GEN_INT (offset & ~CSW_MAX_OFFSET); | |
1584 | offset &= CSW_MAX_OFFSET; | |
1585 | if (!SMALL_OPERAND (INTVAL (high))) | |
1586 | high = force_reg (Pmode, high); | |
1587 | base = force_reg (Pmode, gen_rtx_PLUS (Pmode, high, base)); | |
1588 | addr = plus_constant (Pmode, base, offset); | |
1589 | return addr; | |
1590 | } | |
1591 | ||
09cae750 PD |
1592 | /* This function is used to implement LEGITIMIZE_ADDRESS. If X can |
1593 | be legitimized in a way that the generic machinery might not expect, | |
1594 | return a new address, otherwise return NULL. MODE is the mode of | |
1595 | the memory being accessed. */ | |
1596 | ||
1597 | static rtx | |
1598 | riscv_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, | |
b8506a8a | 1599 | machine_mode mode) |
09cae750 PD |
1600 | { |
1601 | rtx addr; | |
1602 | ||
1603 | if (riscv_tls_symbol_p (x)) | |
1604 | return riscv_legitimize_tls_address (x); | |
1605 | ||
1606 | /* See if the address can split into a high part and a LO_SUM. */ | |
a923a463 | 1607 | if (riscv_split_symbol (NULL, x, mode, &addr, FALSE)) |
09cae750 PD |
1608 | return riscv_force_address (addr, mode); |
1609 | ||
de6320a8 | 1610 | /* Handle BASE + OFFSET. */ |
09cae750 PD |
1611 | if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) |
1612 | && INTVAL (XEXP (x, 1)) != 0) | |
1613 | { | |
1614 | rtx base = XEXP (x, 0); | |
1615 | HOST_WIDE_INT offset = INTVAL (XEXP (x, 1)); | |
1616 | ||
1617 | if (!riscv_valid_base_register_p (base, mode, false)) | |
1618 | base = copy_to_mode_reg (Pmode, base); | |
de6320a8 CB |
1619 | if (optimize_function_for_size_p (cfun) |
1620 | && (strcmp (current_pass->name, "shorten_memrefs") == 0) | |
1621 | && mode == SImode) | |
1622 | /* Convert BASE + LARGE_OFFSET into NEW_BASE + SMALL_OFFSET to allow | |
1623 | possible compressed load/store. */ | |
1624 | addr = riscv_shorten_lw_offset (base, offset); | |
1625 | else | |
1626 | addr = riscv_add_offset (NULL, base, offset); | |
09cae750 PD |
1627 | return riscv_force_address (addr, mode); |
1628 | } | |
1629 | ||
1630 | return x; | |
1631 | } | |
1632 | ||
51175507 JW |
1633 | /* Load VALUE into DEST. TEMP is as for riscv_force_temporary. ORIG_MODE |
1634 | is the original src mode before promotion. */ | |
09cae750 PD |
1635 | |
1636 | void | |
51175507 | 1637 | riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value, |
a923a463 | 1638 | machine_mode orig_mode, bool in_splitter) |
09cae750 PD |
1639 | { |
1640 | struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS]; | |
b8506a8a | 1641 | machine_mode mode; |
09cae750 PD |
1642 | int i, num_ops; |
1643 | rtx x; | |
1644 | ||
a923a463 JW |
1645 | /* We can't call gen_reg_rtx from a splitter, because this might realloc |
1646 | the regno_reg_rtx array, which would invalidate reg rtx pointers in the | |
1647 | combine undo buffer. */ | |
1648 | bool can_create_pseudo = can_create_pseudo_p () && ! in_splitter; | |
1649 | ||
09cae750 | 1650 | mode = GET_MODE (dest); |
51175507 JW |
1651 | /* We use the original mode for the riscv_build_integer call, because HImode |
1652 | values are given special treatment. */ | |
1653 | num_ops = riscv_build_integer (codes, value, orig_mode); | |
09cae750 | 1654 | |
a923a463 | 1655 | if (can_create_pseudo && num_ops > 2 /* not a simple constant */ |
09cae750 PD |
1656 | && num_ops >= riscv_split_integer_cost (value)) |
1657 | x = riscv_split_integer (value, mode); | |
1658 | else | |
1659 | { | |
2c721ea9 | 1660 | codes[0].value = trunc_int_for_mode (codes[0].value, mode); |
09cae750 PD |
1661 | /* Apply each binary operation to X. */ |
1662 | x = GEN_INT (codes[0].value); | |
1663 | ||
1664 | for (i = 1; i < num_ops; i++) | |
1665 | { | |
a923a463 | 1666 | if (!can_create_pseudo) |
09cae750 PD |
1667 | x = riscv_emit_set (temp, x); |
1668 | else | |
1669 | x = force_reg (mode, x); | |
2c721ea9 | 1670 | codes[i].value = trunc_int_for_mode (codes[i].value, mode); |
09cae750 PD |
1671 | x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value)); |
1672 | } | |
1673 | } | |
1674 | ||
1675 | riscv_emit_set (dest, x); | |
1676 | } | |
1677 | ||
1678 | /* Subroutine of riscv_legitimize_move. Move constant SRC into register | |
1679 | DEST given that SRC satisfies immediate_operand but doesn't satisfy | |
1680 | move_operand. */ | |
1681 | ||
1682 | static void | |
b8506a8a | 1683 | riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src) |
09cae750 PD |
1684 | { |
1685 | rtx base, offset; | |
1686 | ||
1687 | /* Split moves of big integers into smaller pieces. */ | |
1688 | if (splittable_const_int_operand (src, mode)) | |
1689 | { | |
a923a463 | 1690 | riscv_move_integer (dest, dest, INTVAL (src), mode, FALSE); |
09cae750 PD |
1691 | return; |
1692 | } | |
1693 | ||
1694 | /* Split moves of symbolic constants into high/low pairs. */ | |
a923a463 | 1695 | if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src, FALSE)) |
09cae750 PD |
1696 | { |
1697 | riscv_emit_set (dest, src); | |
1698 | return; | |
1699 | } | |
1700 | ||
1701 | /* Generate the appropriate access sequences for TLS symbols. */ | |
1702 | if (riscv_tls_symbol_p (src)) | |
1703 | { | |
1704 | riscv_emit_move (dest, riscv_legitimize_tls_address (src)); | |
1705 | return; | |
1706 | } | |
1707 | ||
1708 | /* If we have (const (plus symbol offset)), and that expression cannot | |
1709 | be forced into memory, load the symbol first and add in the offset. Also | |
1710 | prefer to do this even if the constant _can_ be forced into memory, as it | |
1711 | usually produces better code. */ | |
1712 | split_const (src, &base, &offset); | |
1713 | if (offset != const0_rtx | |
1714 | && (targetm.cannot_force_const_mem (mode, src) || can_create_pseudo_p ())) | |
1715 | { | |
a923a463 | 1716 | base = riscv_force_temporary (dest, base, FALSE); |
09cae750 PD |
1717 | riscv_emit_move (dest, riscv_add_offset (NULL, base, INTVAL (offset))); |
1718 | return; | |
1719 | } | |
1720 | ||
1721 | src = force_const_mem (mode, src); | |
1722 | ||
1723 | /* When using explicit relocs, constant pool references are sometimes | |
1724 | not legitimate addresses. */ | |
a923a463 | 1725 | riscv_split_symbol (dest, XEXP (src, 0), mode, &XEXP (src, 0), FALSE); |
09cae750 PD |
1726 | riscv_emit_move (dest, src); |
1727 | } | |
1728 | ||
b4feb49c | 1729 | /* Report when we try to do something that requires vector when vector is |
1730 | disabled. This is an error of last resort and isn't very high-quality. It | |
1731 | usually involves attempts to measure the vector length in some way. */ | |
1732 | ||
1733 | static void | |
1734 | riscv_report_v_required (void) | |
1735 | { | |
1736 | static bool reported_p = false; | |
1737 | ||
1738 | /* Avoid reporting a slew of messages for a single oversight. */ | |
1739 | if (reported_p) | |
1740 | return; | |
1741 | ||
1742 | error ("this operation requires the RVV ISA extension"); | |
1743 | inform (input_location, "you can enable RVV using the command-line" | |
1744 | " option %<-march%>, or by using the %<target%>" | |
1745 | " attribute or pragma"); | |
1746 | reported_p = true; | |
1747 | } | |
1748 | ||
1749 | /* Helper function to operation for rtx_code CODE. */ | |
1750 | static void | |
1751 | riscv_expand_op (enum rtx_code code, machine_mode mode, rtx op0, rtx op1, | |
1752 | rtx op2) | |
1753 | { | |
1754 | if (can_create_pseudo_p ()) | |
1755 | { | |
1756 | rtx result; | |
1757 | if (GET_RTX_CLASS (code) == RTX_UNARY) | |
1758 | result = expand_simple_unop (mode, code, op1, NULL_RTX, false); | |
1759 | else | |
1760 | result = expand_simple_binop (mode, code, op1, op2, NULL_RTX, false, | |
1761 | OPTAB_DIRECT); | |
1762 | riscv_emit_move (op0, result); | |
1763 | } | |
1764 | else | |
1765 | { | |
1766 | rtx pat; | |
1767 | /* The following implementation is for prologue and epilogue. | |
1768 | Because prologue and epilogue can not use pseudo register. | |
1769 | We can't using expand_simple_binop or expand_simple_unop. */ | |
1770 | if (GET_RTX_CLASS (code) == RTX_UNARY) | |
1771 | pat = gen_rtx_fmt_e (code, mode, op1); | |
1772 | else | |
1773 | pat = gen_rtx_fmt_ee (code, mode, op1, op2); | |
1774 | emit_insn (gen_rtx_SET (op0, pat)); | |
1775 | } | |
1776 | } | |
1777 | ||
1778 | /* Expand mult operation with constant integer, multiplicand also used as a | |
1779 | * temporary register. */ | |
1780 | ||
1781 | static void | |
1782 | riscv_expand_mult_with_const_int (machine_mode mode, rtx dest, rtx multiplicand, | |
1783 | int multiplier) | |
1784 | { | |
1785 | if (multiplier == 0) | |
1786 | { | |
1787 | riscv_emit_move (dest, GEN_INT (0)); | |
1788 | return; | |
1789 | } | |
1790 | ||
1791 | bool neg_p = multiplier < 0; | |
1792 | int multiplier_abs = abs (multiplier); | |
1793 | ||
1794 | if (multiplier_abs == 1) | |
1795 | { | |
1796 | if (neg_p) | |
1797 | riscv_expand_op (NEG, mode, dest, multiplicand, NULL_RTX); | |
1798 | else | |
1799 | riscv_emit_move (dest, multiplicand); | |
1800 | } | |
1801 | else | |
1802 | { | |
1803 | if (pow2p_hwi (multiplier_abs)) | |
1804 | { | |
1805 | /* | |
1806 | multiplicand = [BYTES_PER_RISCV_VECTOR]. | |
1807 | 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 8]. | |
1808 | Sequence: | |
1809 | csrr a5, vlenb | |
1810 | slli a5, a5, 3 | |
1811 | 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 8]. | |
1812 | Sequence: | |
1813 | csrr a5, vlenb | |
1814 | slli a5, a5, 3 | |
1815 | neg a5, a5 | |
1816 | */ | |
1817 | riscv_expand_op (ASHIFT, mode, dest, multiplicand, | |
1818 | gen_int_mode (exact_log2 (multiplier_abs), QImode)); | |
1819 | if (neg_p) | |
1820 | riscv_expand_op (NEG, mode, dest, dest, NULL_RTX); | |
1821 | } | |
1822 | else if (pow2p_hwi (multiplier_abs + 1)) | |
1823 | { | |
1824 | /* | |
1825 | multiplicand = [BYTES_PER_RISCV_VECTOR]. | |
1826 | 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 7]. | |
1827 | Sequence: | |
1828 | csrr a5, vlenb | |
1829 | slli a4, a5, 3 | |
1830 | sub a5, a4, a5 | |
1831 | 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 7]. | |
1832 | Sequence: | |
1833 | csrr a5, vlenb | |
1834 | slli a4, a5, 3 | |
1835 | sub a5, a4, a5 + neg a5, a5 => sub a5, a5, a4 | |
1836 | */ | |
1837 | riscv_expand_op (ASHIFT, mode, dest, multiplicand, | |
1838 | gen_int_mode (exact_log2 (multiplier_abs + 1), | |
1839 | QImode)); | |
1840 | if (neg_p) | |
1841 | riscv_expand_op (MINUS, mode, dest, multiplicand, dest); | |
1842 | else | |
1843 | riscv_expand_op (MINUS, mode, dest, dest, multiplicand); | |
1844 | } | |
1845 | else if (pow2p_hwi (multiplier - 1)) | |
1846 | { | |
1847 | /* | |
1848 | multiplicand = [BYTES_PER_RISCV_VECTOR]. | |
1849 | 1. const_poly_int:P [BYTES_PER_RISCV_VECTOR * 9]. | |
1850 | Sequence: | |
1851 | csrr a5, vlenb | |
1852 | slli a4, a5, 3 | |
1853 | add a5, a4, a5 | |
1854 | 2. const_poly_int:P [-BYTES_PER_RISCV_VECTOR * 9]. | |
1855 | Sequence: | |
1856 | csrr a5, vlenb | |
1857 | slli a4, a5, 3 | |
1858 | add a5, a4, a5 | |
1859 | neg a5, a5 | |
1860 | */ | |
1861 | riscv_expand_op (ASHIFT, mode, dest, multiplicand, | |
1862 | gen_int_mode (exact_log2 (multiplier_abs - 1), | |
1863 | QImode)); | |
1864 | riscv_expand_op (PLUS, mode, dest, dest, multiplicand); | |
1865 | if (neg_p) | |
1866 | riscv_expand_op (NEG, mode, dest, dest, NULL_RTX); | |
1867 | } | |
1868 | else | |
1869 | { | |
1870 | /* We use multiplication for remaining cases. */ | |
1871 | gcc_assert ( | |
1872 | TARGET_MUL | |
1873 | && "M-extension must be enabled to calculate the poly_int " | |
1874 | "size/offset."); | |
1875 | riscv_emit_move (dest, gen_int_mode (multiplier, mode)); | |
1876 | riscv_expand_op (MULT, mode, dest, dest, multiplicand); | |
1877 | } | |
1878 | } | |
1879 | } | |
1880 | ||
1881 | /* Analyze src and emit const_poly_int mov sequence. */ | |
1882 | ||
1883 | static void | |
1884 | riscv_legitimize_poly_move (machine_mode mode, rtx dest, rtx tmp, rtx src) | |
1885 | { | |
1886 | poly_int64 value = rtx_to_poly_int64 (src); | |
1887 | int offset = value.coeffs[0]; | |
1888 | int factor = value.coeffs[1]; | |
1889 | int vlenb = BYTES_PER_RISCV_VECTOR.coeffs[1]; | |
1890 | int div_factor = 0; | |
1891 | /* Calculate (const_poly_int:MODE [m, n]) using scalar instructions. | |
1892 | For any (const_poly_int:MODE [m, n]), the calculation formula is as | |
1893 | follows. | |
1894 | constant = m - n. | |
1895 | When minimum VLEN = 32, poly of VLENB = (4, 4). | |
1896 | base = vlenb(4, 4) or vlenb/2(2, 2) or vlenb/4(1, 1). | |
1897 | When minimum VLEN > 32, poly of VLENB = (8, 8). | |
1898 | base = vlenb(8, 8) or vlenb/2(4, 4) or vlenb/4(2, 2) or vlenb/8(1, 1). | |
1899 | magn = (n, n) / base. | |
1900 | (m, n) = base * magn + constant. | |
1901 | This calculation doesn't need div operation. */ | |
1902 | ||
1903 | emit_move_insn (tmp, gen_int_mode (BYTES_PER_RISCV_VECTOR, mode)); | |
1904 | ||
1905 | if (BYTES_PER_RISCV_VECTOR.is_constant ()) | |
1906 | { | |
1907 | gcc_assert (value.is_constant ()); | |
1908 | riscv_emit_move (dest, GEN_INT (value.to_constant ())); | |
1909 | return; | |
1910 | } | |
1911 | else if ((factor % vlenb) == 0) | |
1912 | div_factor = 1; | |
1913 | else if ((factor % (vlenb / 2)) == 0) | |
1914 | div_factor = 2; | |
1915 | else if ((factor % (vlenb / 4)) == 0) | |
1916 | div_factor = 4; | |
1917 | else if ((factor % (vlenb / 8)) == 0) | |
1918 | div_factor = 8; | |
1919 | else | |
1920 | gcc_unreachable (); | |
1921 | ||
1922 | if (div_factor != 1) | |
1923 | riscv_expand_op (LSHIFTRT, mode, tmp, tmp, | |
1924 | gen_int_mode (exact_log2 (div_factor), QImode)); | |
1925 | ||
1926 | riscv_expand_mult_with_const_int (mode, dest, tmp, | |
1927 | factor / (vlenb / div_factor)); | |
1928 | HOST_WIDE_INT constant = offset - factor; | |
1929 | ||
1930 | if (constant == 0) | |
1931 | return; | |
1932 | else if (SMALL_OPERAND (constant)) | |
1933 | riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode)); | |
1934 | else | |
1935 | { | |
1936 | /* Handle the constant value is not a 12-bit value. */ | |
1937 | rtx high; | |
1938 | ||
1939 | /* Leave OFFSET as a 16-bit offset and put the excess in HIGH. | |
1940 | The addition inside the macro CONST_HIGH_PART may cause an | |
1941 | overflow, so we need to force a sign-extension check. */ | |
1942 | high = gen_int_mode (CONST_HIGH_PART (constant), mode); | |
1943 | constant = CONST_LOW_PART (constant); | |
1944 | riscv_emit_move (tmp, high); | |
1945 | riscv_expand_op (PLUS, mode, dest, tmp, dest); | |
1946 | riscv_expand_op (PLUS, mode, dest, dest, gen_int_mode (constant, mode)); | |
1947 | } | |
1948 | } | |
1949 | ||
09cae750 PD |
1950 | /* If (set DEST SRC) is not a valid move instruction, emit an equivalent |
1951 | sequence that is valid. */ | |
1952 | ||
1953 | bool | |
b8506a8a | 1954 | riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) |
09cae750 | 1955 | { |
b4feb49c | 1956 | if (CONST_POLY_INT_P (src)) |
1957 | { | |
6bfea641 JZZ |
1958 | /* |
1959 | Handle: | |
1960 | (insn 183 182 184 6 (set (mem:QI (plus:DI (reg/f:DI 156) | |
1961 | (const_int 96 [0x60])) [0 S1 A8]) | |
1962 | (const_poly_int:QI [8, 8])) | |
1963 | "../../../../riscv-gcc/libgcc/unwind-dw2.c":1579:3 -1 (nil)) | |
1964 | */ | |
1965 | if (MEM_P (dest)) | |
1966 | { | |
1967 | emit_move_insn (dest, force_reg (mode, src)); | |
1968 | return true; | |
1969 | } | |
b4feb49c | 1970 | poly_int64 value = rtx_to_poly_int64 (src); |
1971 | if (!value.is_constant () && !TARGET_VECTOR) | |
1972 | { | |
1973 | riscv_report_v_required (); | |
1974 | return false; | |
1975 | } | |
1976 | ||
1977 | if (satisfies_constraint_vp (src)) | |
1978 | return false; | |
1979 | ||
1980 | if (GET_MODE_SIZE (mode).to_constant () < GET_MODE_SIZE (Pmode)) | |
1981 | { | |
1982 | /* In RV32 system, handle (const_poly_int:QI [m, n]) | |
1983 | (const_poly_int:HI [m, n]). | |
1984 | In RV64 system, handle (const_poly_int:QI [m, n]) | |
1985 | (const_poly_int:HI [m, n]) | |
1986 | (const_poly_int:SI [m, n]). */ | |
1987 | rtx tmp = gen_reg_rtx (Pmode); | |
1988 | riscv_legitimize_poly_move (Pmode, gen_lowpart (Pmode, dest), tmp, | |
1989 | src); | |
1990 | } | |
1991 | else | |
1992 | { | |
1993 | /* In RV32 system, handle (const_poly_int:SI [m, n]) | |
1994 | (const_poly_int:DI [m, n]). | |
1995 | In RV64 system, handle (const_poly_int:DI [m, n]). | |
1996 | FIXME: Maybe we could gen SImode in RV32 and then sign-extend to DImode, | |
1997 | the offset should not exceed 4GiB in general. */ | |
1998 | rtx tmp = gen_reg_rtx (mode); | |
1999 | riscv_legitimize_poly_move (mode, dest, tmp, src); | |
2000 | } | |
2001 | return true; | |
2002 | } | |
18fabc35 LH |
2003 | /* Expand |
2004 | (set (reg:QI target) (mem:QI (address))) | |
2005 | to | |
2006 | (set (reg:DI temp) (zero_extend:DI (mem:QI (address)))) | |
2007 | (set (reg:QI target) (subreg:QI (reg:DI temp) 0)) | |
2008 | with auto-sign/zero extend. */ | |
2009 | if (GET_MODE_CLASS (mode) == MODE_INT | |
3496ca4e | 2010 | && GET_MODE_SIZE (mode).to_constant () < UNITS_PER_WORD |
18fabc35 LH |
2011 | && can_create_pseudo_p () |
2012 | && MEM_P (src)) | |
2013 | { | |
2014 | rtx temp_reg; | |
2015 | int zero_extend_p; | |
2016 | ||
2017 | temp_reg = gen_reg_rtx (word_mode); | |
2018 | zero_extend_p = (LOAD_EXTEND_OP (mode) == ZERO_EXTEND); | |
2019 | emit_insn (gen_extend_insn (temp_reg, src, word_mode, mode, | |
2020 | zero_extend_p)); | |
2021 | riscv_emit_move (dest, gen_lowpart (mode, temp_reg)); | |
2022 | return true; | |
2023 | } | |
2024 | ||
09cae750 PD |
2025 | if (!register_operand (dest, mode) && !reg_or_0_operand (src, mode)) |
2026 | { | |
51175507 JW |
2027 | rtx reg; |
2028 | ||
2029 | if (GET_CODE (src) == CONST_INT) | |
2030 | { | |
2031 | /* Apply the equivalent of PROMOTE_MODE here for constants to | |
2032 | improve cse. */ | |
2033 | machine_mode promoted_mode = mode; | |
2034 | if (GET_MODE_CLASS (mode) == MODE_INT | |
3496ca4e | 2035 | && GET_MODE_SIZE (mode).to_constant () < UNITS_PER_WORD) |
51175507 JW |
2036 | promoted_mode = word_mode; |
2037 | ||
2038 | if (splittable_const_int_operand (src, mode)) | |
2039 | { | |
2040 | reg = gen_reg_rtx (promoted_mode); | |
a923a463 | 2041 | riscv_move_integer (reg, reg, INTVAL (src), mode, FALSE); |
51175507 JW |
2042 | } |
2043 | else | |
2044 | reg = force_reg (promoted_mode, src); | |
2045 | ||
2046 | if (promoted_mode != mode) | |
2047 | reg = gen_lowpart (mode, reg); | |
2048 | } | |
2049 | else | |
2050 | reg = force_reg (mode, src); | |
2051 | riscv_emit_move (dest, reg); | |
09cae750 PD |
2052 | return true; |
2053 | } | |
2054 | ||
2055 | /* We need to deal with constants that would be legitimate | |
2056 | immediate_operands but aren't legitimate move_operands. */ | |
2057 | if (CONSTANT_P (src) && !move_operand (src, mode)) | |
2058 | { | |
2059 | riscv_legitimize_const_move (mode, dest, src); | |
2060 | set_unique_reg_note (get_last_insn (), REG_EQUAL, copy_rtx (src)); | |
2061 | return true; | |
2062 | } | |
2063 | ||
13e4f305 KC |
2064 | /* RISC-V GCC may generate non-legitimate address due to we provide some |
2065 | pattern for optimize access PIC local symbol and it's make GCC generate | |
2066 | unrecognizable instruction during optmizing. */ | |
2067 | ||
2068 | if (MEM_P (dest) && !riscv_legitimate_address_p (mode, XEXP (dest, 0), | |
2069 | reload_completed)) | |
2070 | { | |
2071 | XEXP (dest, 0) = riscv_force_address (XEXP (dest, 0), mode); | |
2072 | } | |
2073 | ||
2074 | if (MEM_P (src) && !riscv_legitimate_address_p (mode, XEXP (src, 0), | |
2075 | reload_completed)) | |
2076 | { | |
2077 | XEXP (src, 0) = riscv_force_address (XEXP (src, 0), mode); | |
2078 | } | |
2079 | ||
09cae750 PD |
2080 | return false; |
2081 | } | |
2082 | ||
2083 | /* Return true if there is an instruction that implements CODE and accepts | |
2084 | X as an immediate operand. */ | |
2085 | ||
2086 | static int | |
2087 | riscv_immediate_operand_p (int code, HOST_WIDE_INT x) | |
2088 | { | |
2089 | switch (code) | |
2090 | { | |
2091 | case ASHIFT: | |
2092 | case ASHIFTRT: | |
2093 | case LSHIFTRT: | |
2094 | /* All shift counts are truncated to a valid constant. */ | |
2095 | return true; | |
2096 | ||
2097 | case AND: | |
2098 | case IOR: | |
2099 | case XOR: | |
2100 | case PLUS: | |
2101 | case LT: | |
2102 | case LTU: | |
2103 | /* These instructions take 12-bit signed immediates. */ | |
2104 | return SMALL_OPERAND (x); | |
2105 | ||
2106 | case LE: | |
2107 | /* We add 1 to the immediate and use SLT. */ | |
2108 | return SMALL_OPERAND (x + 1); | |
2109 | ||
2110 | case LEU: | |
2111 | /* Likewise SLTU, but reject the always-true case. */ | |
2112 | return SMALL_OPERAND (x + 1) && x + 1 != 0; | |
2113 | ||
2114 | case GE: | |
2115 | case GEU: | |
2116 | /* We can emulate an immediate of 1 by using GT/GTU against x0. */ | |
2117 | return x == 1; | |
2118 | ||
2119 | default: | |
2120 | /* By default assume that x0 can be used for 0. */ | |
2121 | return x == 0; | |
2122 | } | |
2123 | } | |
2124 | ||
2125 | /* Return the cost of binary operation X, given that the instruction | |
2126 | sequence for a word-sized or smaller operation takes SIGNLE_INSNS | |
2127 | instructions and that the sequence of a double-word operation takes | |
2128 | DOUBLE_INSNS instructions. */ | |
2129 | ||
2130 | static int | |
2131 | riscv_binary_cost (rtx x, int single_insns, int double_insns) | |
2132 | { | |
31380d4b | 2133 | if (!riscv_v_ext_vector_mode_p (GET_MODE (x)) |
2134 | && GET_MODE_SIZE (GET_MODE (x)).to_constant () == UNITS_PER_WORD * 2) | |
09cae750 PD |
2135 | return COSTS_N_INSNS (double_insns); |
2136 | return COSTS_N_INSNS (single_insns); | |
2137 | } | |
2138 | ||
2139 | /* Return the cost of sign- or zero-extending OP. */ | |
2140 | ||
2141 | static int | |
2142 | riscv_extend_cost (rtx op, bool unsigned_p) | |
2143 | { | |
2144 | if (MEM_P (op)) | |
2145 | return 0; | |
2146 | ||
2147 | if (unsigned_p && GET_MODE (op) == QImode) | |
2148 | /* We can use ANDI. */ | |
2149 | return COSTS_N_INSNS (1); | |
2150 | ||
04a9b554 KC |
2151 | /* ZBA provide zext.w. */ |
2152 | if (TARGET_ZBA && TARGET_64BIT && unsigned_p && GET_MODE (op) == SImode) | |
2153 | return COSTS_N_INSNS (1); | |
2154 | ||
3329d892 KC |
2155 | /* ZBB provide zext.h, sext.b and sext.h. */ |
2156 | if (TARGET_ZBB) | |
2157 | { | |
2158 | if (!unsigned_p && GET_MODE (op) == QImode) | |
2159 | return COSTS_N_INSNS (1); | |
2160 | ||
2161 | if (GET_MODE (op) == HImode) | |
2162 | return COSTS_N_INSNS (1); | |
2163 | } | |
2164 | ||
09cae750 PD |
2165 | if (!unsigned_p && GET_MODE (op) == SImode) |
2166 | /* We can use SEXT.W. */ | |
2167 | return COSTS_N_INSNS (1); | |
2168 | ||
2169 | /* We need to use a shift left and a shift right. */ | |
2170 | return COSTS_N_INSNS (2); | |
2171 | } | |
2172 | ||
2173 | /* Implement TARGET_RTX_COSTS. */ | |
2174 | ||
08539f3e JW |
2175 | #define SINGLE_SHIFT_COST 1 |
2176 | ||
09cae750 PD |
2177 | static bool |
2178 | riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UNUSED, | |
2179 | int *total, bool speed) | |
2180 | { | |
31380d4b | 2181 | /* TODO: We set RVV instruction cost as 1 by default. |
2182 | Cost Model need to be well analyzed and supported in the future. */ | |
2183 | if (riscv_v_ext_vector_mode_p (mode)) | |
2184 | { | |
2185 | *total = COSTS_N_INSNS (1); | |
2186 | return true; | |
2187 | } | |
2188 | ||
09cae750 PD |
2189 | bool float_mode_p = FLOAT_MODE_P (mode); |
2190 | int cost; | |
2191 | ||
2192 | switch (GET_CODE (x)) | |
2193 | { | |
2194 | case CONST_INT: | |
2195 | if (riscv_immediate_operand_p (outer_code, INTVAL (x))) | |
2196 | { | |
2197 | *total = 0; | |
2198 | return true; | |
2199 | } | |
2200 | /* Fall through. */ | |
2201 | ||
2202 | case SYMBOL_REF: | |
2203 | case LABEL_REF: | |
2204 | case CONST_DOUBLE: | |
ef85d150 VG |
2205 | /* With TARGET_SUPPORTS_WIDE_INT const int can't be in CONST_DOUBLE |
2206 | rtl object. Weird recheck due to switch-case fall through above. */ | |
2207 | if (GET_CODE (x) == CONST_DOUBLE) | |
2208 | gcc_assert (GET_MODE (x) != VOIDmode); | |
2209 | /* Fall through. */ | |
2210 | ||
09cae750 PD |
2211 | case CONST: |
2212 | if ((cost = riscv_const_insns (x)) > 0) | |
2213 | { | |
2214 | /* If the constant is likely to be stored in a GPR, SETs of | |
2215 | single-insn constants are as cheap as register sets; we | |
2216 | never want to CSE them. */ | |
2217 | if (cost == 1 && outer_code == SET) | |
2218 | *total = 0; | |
2219 | /* When we load a constant more than once, it usually is better | |
2220 | to duplicate the last operation in the sequence than to CSE | |
2221 | the constant itself. */ | |
2222 | else if (outer_code == SET || GET_MODE (x) == VOIDmode) | |
2223 | *total = COSTS_N_INSNS (1); | |
2224 | } | |
2225 | else /* The instruction will be fetched from the constant pool. */ | |
2226 | *total = COSTS_N_INSNS (riscv_symbol_insns (SYMBOL_ABSOLUTE)); | |
2227 | return true; | |
2228 | ||
2229 | case MEM: | |
2230 | /* If the address is legitimate, return the number of | |
2231 | instructions it needs. */ | |
2232 | if ((cost = riscv_address_insns (XEXP (x, 0), mode, true)) > 0) | |
2233 | { | |
a4953810 JW |
2234 | /* When optimizing for size, make uncompressible 32-bit addresses |
2235 | more expensive so that compressible 32-bit addresses are | |
2236 | preferred. */ | |
2237 | if (TARGET_RVC && !speed && riscv_mshorten_memrefs && mode == SImode | |
2238 | && !riscv_compressed_lw_address_p (XEXP (x, 0))) | |
2239 | cost++; | |
2240 | ||
72eb8335 | 2241 | *total = COSTS_N_INSNS (cost + tune_param->memory_cost); |
09cae750 PD |
2242 | return true; |
2243 | } | |
2244 | /* Otherwise use the default handling. */ | |
2245 | return false; | |
2246 | ||
98cf74a2 MR |
2247 | case IF_THEN_ELSE: |
2248 | if (TARGET_SFB_ALU | |
2249 | && register_operand (XEXP (x, 1), mode) | |
2250 | && sfb_alu_operand (XEXP (x, 2), mode) | |
2251 | && comparison_operator (XEXP (x, 0), VOIDmode)) | |
2252 | { | |
2253 | /* For predicated conditional-move operations we assume the cost | |
2254 | of a single instruction even though there are actually two. */ | |
2255 | *total = COSTS_N_INSNS (1); | |
2256 | return true; | |
2257 | } | |
2258 | else if (LABEL_REF_P (XEXP (x, 1)) && XEXP (x, 2) == pc_rtx) | |
2259 | { | |
2260 | if (equality_operator (XEXP (x, 0), mode) | |
2261 | && GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTRACT) | |
2262 | { | |
2263 | *total = COSTS_N_INSNS (SINGLE_SHIFT_COST + 1); | |
2264 | return true; | |
2265 | } | |
2266 | if (order_operator (XEXP (x, 0), mode)) | |
2267 | { | |
2268 | *total = COSTS_N_INSNS (1); | |
2269 | return true; | |
2270 | } | |
2271 | } | |
2272 | return false; | |
2273 | ||
09cae750 | 2274 | case NOT: |
3496ca4e | 2275 | *total = COSTS_N_INSNS (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD ? 2 : 1); |
09cae750 PD |
2276 | return false; |
2277 | ||
2278 | case AND: | |
04a9b554 KC |
2279 | /* slli.uw pattern for zba. */ |
2280 | if (TARGET_ZBA && TARGET_64BIT && mode == DImode | |
2281 | && GET_CODE (XEXP (x, 0)) == ASHIFT) | |
2282 | { | |
2283 | rtx and_rhs = XEXP (x, 1); | |
2284 | rtx ashift_lhs = XEXP (XEXP (x, 0), 0); | |
2285 | rtx ashift_rhs = XEXP (XEXP (x, 0), 1); | |
2286 | if (REG_P (ashift_lhs) | |
2287 | && CONST_INT_P (ashift_rhs) | |
2288 | && CONST_INT_P (and_rhs) | |
2289 | && ((INTVAL (and_rhs) >> INTVAL (ashift_rhs)) == 0xffffffff)) | |
2290 | *total = COSTS_N_INSNS (1); | |
2291 | return true; | |
2292 | } | |
77b84fb0 KC |
2293 | /* bclri pattern for zbs. */ |
2294 | if (TARGET_ZBS | |
2295 | && not_single_bit_mask_operand (XEXP (x, 1), VOIDmode)) | |
2296 | { | |
2297 | *total = COSTS_N_INSNS (1); | |
2298 | return true; | |
2299 | } | |
2300 | /* bclr pattern for zbs. */ | |
2301 | if (TARGET_ZBS | |
2302 | && REG_P (XEXP (x, 1)) | |
2303 | && GET_CODE (XEXP (x, 0)) == ROTATE | |
2304 | && CONST_INT_P (XEXP ((XEXP (x, 0)), 0)) | |
2305 | && INTVAL (XEXP ((XEXP (x, 0)), 0)) == -2) | |
2306 | { | |
2307 | *total = COSTS_N_INSNS (1); | |
2308 | return true; | |
2309 | } | |
2310 | ||
04a9b554 | 2311 | gcc_fallthrough (); |
09cae750 PD |
2312 | case IOR: |
2313 | case XOR: | |
3329d892 KC |
2314 | /* orn, andn and xorn pattern for zbb. */ |
2315 | if (TARGET_ZBB | |
2316 | && GET_CODE (XEXP (x, 0)) == NOT) | |
2317 | { | |
2318 | *total = riscv_binary_cost (x, 1, 2); | |
2319 | return true; | |
2320 | } | |
77b84fb0 KC |
2321 | |
2322 | /* bset[i] and binv[i] pattern for zbs. */ | |
2323 | if ((GET_CODE (x) == IOR || GET_CODE (x) == XOR) | |
2324 | && TARGET_ZBS | |
2325 | && ((GET_CODE (XEXP (x, 0)) == ASHIFT | |
2326 | && CONST_INT_P (XEXP (XEXP (x, 0), 0))) | |
2327 | || single_bit_mask_operand (XEXP (x, 1), VOIDmode))) | |
2328 | { | |
2329 | *total = COSTS_N_INSNS (1); | |
2330 | return true; | |
2331 | } | |
2332 | ||
09cae750 PD |
2333 | /* Double-word operations use two single-word operations. */ |
2334 | *total = riscv_binary_cost (x, 1, 2); | |
2335 | return false; | |
2336 | ||
08539f3e JW |
2337 | case ZERO_EXTRACT: |
2338 | /* This is an SImode shift. */ | |
bd0a3e24 JJ |
2339 | if (outer_code == SET |
2340 | && CONST_INT_P (XEXP (x, 1)) | |
2341 | && CONST_INT_P (XEXP (x, 2)) | |
2342 | && (INTVAL (XEXP (x, 2)) > 0) | |
08539f3e JW |
2343 | && (INTVAL (XEXP (x, 1)) + INTVAL (XEXP (x, 2)) == 32)) |
2344 | { | |
2345 | *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); | |
2346 | return true; | |
2347 | } | |
77b84fb0 KC |
2348 | /* bext pattern for zbs. */ |
2349 | if (TARGET_ZBS && outer_code == SET | |
2350 | && GET_CODE (XEXP (x, 1)) == CONST_INT | |
2351 | && INTVAL (XEXP (x, 1)) == 1) | |
2352 | { | |
2353 | *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); | |
2354 | return true; | |
2355 | } | |
08539f3e JW |
2356 | return false; |
2357 | ||
09cae750 | 2358 | case ASHIFT: |
77b84fb0 KC |
2359 | /* bset pattern for zbs. */ |
2360 | if (TARGET_ZBS | |
2361 | && CONST_INT_P (XEXP (x, 0)) | |
2362 | && INTVAL (XEXP (x, 0)) == 1) | |
2363 | { | |
2364 | *total = COSTS_N_INSNS (1); | |
2365 | return true; | |
2366 | } | |
2367 | gcc_fallthrough (); | |
09cae750 PD |
2368 | case ASHIFTRT: |
2369 | case LSHIFTRT: | |
08539f3e JW |
2370 | *total = riscv_binary_cost (x, SINGLE_SHIFT_COST, |
2371 | CONSTANT_P (XEXP (x, 1)) ? 4 : 9); | |
09cae750 PD |
2372 | return false; |
2373 | ||
2374 | case ABS: | |
2375 | *total = COSTS_N_INSNS (float_mode_p ? 1 : 3); | |
2376 | return false; | |
2377 | ||
2378 | case LO_SUM: | |
2379 | *total = set_src_cost (XEXP (x, 0), mode, speed); | |
2380 | return true; | |
2381 | ||
2382 | case LT: | |
08539f3e JW |
2383 | /* This is an SImode shift. */ |
2384 | if (outer_code == SET && GET_MODE (x) == DImode | |
2385 | && GET_MODE (XEXP (x, 0)) == SImode) | |
2386 | { | |
2387 | *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); | |
2388 | return true; | |
2389 | } | |
2390 | /* Fall through. */ | |
09cae750 PD |
2391 | case LTU: |
2392 | case LE: | |
2393 | case LEU: | |
2394 | case GT: | |
2395 | case GTU: | |
2396 | case GE: | |
2397 | case GEU: | |
2398 | case EQ: | |
2399 | case NE: | |
2400 | /* Branch comparisons have VOIDmode, so use the first operand's | |
2401 | mode instead. */ | |
2402 | mode = GET_MODE (XEXP (x, 0)); | |
2403 | if (float_mode_p) | |
72eb8335 | 2404 | *total = tune_param->fp_add[mode == DFmode]; |
09cae750 PD |
2405 | else |
2406 | *total = riscv_binary_cost (x, 1, 3); | |
2407 | return false; | |
2408 | ||
2409 | case UNORDERED: | |
2410 | case ORDERED: | |
2411 | /* (FEQ(A, A) & FEQ(B, B)) compared against 0. */ | |
2412 | mode = GET_MODE (XEXP (x, 0)); | |
72eb8335 | 2413 | *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (2); |
09cae750 PD |
2414 | return false; |
2415 | ||
2416 | case UNEQ: | |
09cae750 PD |
2417 | /* (FEQ(A, A) & FEQ(B, B)) compared against FEQ(A, B). */ |
2418 | mode = GET_MODE (XEXP (x, 0)); | |
72eb8335 | 2419 | *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (3); |
09cae750 PD |
2420 | return false; |
2421 | ||
9069e948 KC |
2422 | case LTGT: |
2423 | /* (FLT(A, A) || FGT(B, B)). */ | |
2424 | mode = GET_MODE (XEXP (x, 0)); | |
72eb8335 | 2425 | *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (2); |
9069e948 KC |
2426 | return false; |
2427 | ||
09cae750 PD |
2428 | case UNGE: |
2429 | case UNGT: | |
2430 | case UNLE: | |
2431 | case UNLT: | |
2432 | /* FLT or FLE, but guarded by an FFLAGS read and write. */ | |
2433 | mode = GET_MODE (XEXP (x, 0)); | |
72eb8335 | 2434 | *total = tune_param->fp_add[mode == DFmode] + COSTS_N_INSNS (4); |
09cae750 PD |
2435 | return false; |
2436 | ||
2437 | case MINUS: | |
2438 | case PLUS: | |
04a9b554 KC |
2439 | /* add.uw pattern for zba. */ |
2440 | if (TARGET_ZBA | |
2441 | && (TARGET_64BIT && (mode == DImode)) | |
2442 | && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND | |
2443 | && REG_P (XEXP (XEXP (x, 0), 0)) | |
2444 | && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode) | |
2445 | { | |
2446 | *total = COSTS_N_INSNS (1); | |
2447 | return true; | |
2448 | } | |
2449 | /* shNadd pattern for zba. */ | |
2450 | if (TARGET_ZBA | |
2451 | && ((!TARGET_64BIT && (mode == SImode)) || | |
2452 | (TARGET_64BIT && (mode == DImode))) | |
2453 | && (GET_CODE (XEXP (x, 0)) == ASHIFT) | |
2454 | && REG_P (XEXP (XEXP (x, 0), 0)) | |
c33a5cc9 MR |
2455 | && CONST_INT_P (XEXP (XEXP (x, 0), 1)) |
2456 | && IN_RANGE (INTVAL (XEXP (XEXP (x, 0), 1)), 1, 3)) | |
04a9b554 KC |
2457 | { |
2458 | *total = COSTS_N_INSNS (1); | |
2459 | return true; | |
2460 | } | |
2461 | /* shNadd.uw pattern for zba. | |
2462 | [(set (match_operand:DI 0 "register_operand" "=r") | |
2463 | (plus:DI | |
2464 | (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r") | |
2465 | (match_operand:QI 2 "immediate_operand" "I")) | |
2466 | (match_operand 3 "immediate_operand" "")) | |
2467 | (match_operand:DI 4 "register_operand" "r")))] | |
2468 | "TARGET_64BIT && TARGET_ZBA | |
2469 | && (INTVAL (operands[2]) >= 1) && (INTVAL (operands[2]) <= 3) | |
2470 | && (INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff" | |
2471 | */ | |
2472 | if (TARGET_ZBA | |
2473 | && (TARGET_64BIT && (mode == DImode)) | |
2474 | && (GET_CODE (XEXP (x, 0)) == AND) | |
2475 | && (REG_P (XEXP (x, 1)))) | |
2476 | { | |
2477 | do { | |
2478 | rtx and_lhs = XEXP (XEXP (x, 0), 0); | |
2479 | rtx and_rhs = XEXP (XEXP (x, 0), 1); | |
2480 | if (GET_CODE (and_lhs) != ASHIFT) | |
2481 | break; | |
2482 | if (!CONST_INT_P (and_rhs)) | |
2483 | break; | |
2484 | ||
04a9b554 KC |
2485 | rtx ashift_rhs = XEXP (and_lhs, 1); |
2486 | ||
2487 | if (!CONST_INT_P (ashift_rhs) | |
2488 | || !IN_RANGE (INTVAL (ashift_rhs), 1, 3)) | |
2489 | break; | |
2490 | ||
2491 | if (CONST_INT_P (and_rhs) | |
2492 | && ((INTVAL (and_rhs) >> INTVAL (ashift_rhs)) == 0xffffffff)) | |
2493 | { | |
2494 | *total = COSTS_N_INSNS (1); | |
2495 | return true; | |
2496 | } | |
2497 | } while (false); | |
2498 | } | |
2499 | ||
09cae750 | 2500 | if (float_mode_p) |
72eb8335 | 2501 | *total = tune_param->fp_add[mode == DFmode]; |
09cae750 PD |
2502 | else |
2503 | *total = riscv_binary_cost (x, 1, 4); | |
2504 | return false; | |
2505 | ||
2506 | case NEG: | |
2507 | { | |
2508 | rtx op = XEXP (x, 0); | |
2509 | if (GET_CODE (op) == FMA && !HONOR_SIGNED_ZEROS (mode)) | |
2510 | { | |
72eb8335 | 2511 | *total = (tune_param->fp_mul[mode == DFmode] |
09cae750 PD |
2512 | + set_src_cost (XEXP (op, 0), mode, speed) |
2513 | + set_src_cost (XEXP (op, 1), mode, speed) | |
2514 | + set_src_cost (XEXP (op, 2), mode, speed)); | |
2515 | return true; | |
2516 | } | |
2517 | } | |
2518 | ||
2519 | if (float_mode_p) | |
72eb8335 | 2520 | *total = tune_param->fp_add[mode == DFmode]; |
09cae750 | 2521 | else |
3496ca4e | 2522 | *total = COSTS_N_INSNS (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD ? 4 : 1); |
09cae750 PD |
2523 | return false; |
2524 | ||
2525 | case MULT: | |
2526 | if (float_mode_p) | |
72eb8335 | 2527 | *total = tune_param->fp_mul[mode == DFmode]; |
ff3cc569 AW |
2528 | else if (!TARGET_MUL) |
2529 | /* Estimate the cost of a library call. */ | |
2530 | *total = COSTS_N_INSNS (speed ? 32 : 6); | |
3496ca4e | 2531 | else if (GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD) |
72eb8335 | 2532 | *total = 3 * tune_param->int_mul[0] + COSTS_N_INSNS (2); |
09cae750 PD |
2533 | else if (!speed) |
2534 | *total = COSTS_N_INSNS (1); | |
2535 | else | |
72eb8335 | 2536 | *total = tune_param->int_mul[mode == DImode]; |
09cae750 PD |
2537 | return false; |
2538 | ||
2539 | case DIV: | |
2540 | case SQRT: | |
2541 | case MOD: | |
2542 | if (float_mode_p) | |
2543 | { | |
72eb8335 | 2544 | *total = tune_param->fp_div[mode == DFmode]; |
09cae750 PD |
2545 | return false; |
2546 | } | |
2547 | /* Fall through. */ | |
2548 | ||
2549 | case UDIV: | |
2550 | case UMOD: | |
ff3cc569 AW |
2551 | if (!TARGET_DIV) |
2552 | /* Estimate the cost of a library call. */ | |
2553 | *total = COSTS_N_INSNS (speed ? 32 : 6); | |
2554 | else if (speed) | |
72eb8335 | 2555 | *total = tune_param->int_div[mode == DImode]; |
09cae750 PD |
2556 | else |
2557 | *total = COSTS_N_INSNS (1); | |
2558 | return false; | |
2559 | ||
09cae750 | 2560 | case ZERO_EXTEND: |
08539f3e JW |
2561 | /* This is an SImode shift. */ |
2562 | if (GET_CODE (XEXP (x, 0)) == LSHIFTRT) | |
2563 | { | |
2564 | *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); | |
2565 | return true; | |
2566 | } | |
2567 | /* Fall through. */ | |
2568 | case SIGN_EXTEND: | |
09cae750 PD |
2569 | *total = riscv_extend_cost (XEXP (x, 0), GET_CODE (x) == ZERO_EXTEND); |
2570 | return false; | |
2571 | ||
2572 | case FLOAT: | |
2573 | case UNSIGNED_FLOAT: | |
2574 | case FIX: | |
2575 | case FLOAT_EXTEND: | |
2576 | case FLOAT_TRUNCATE: | |
72eb8335 | 2577 | *total = tune_param->fp_add[mode == DFmode]; |
09cae750 PD |
2578 | return false; |
2579 | ||
2580 | case FMA: | |
72eb8335 | 2581 | *total = (tune_param->fp_mul[mode == DFmode] |
09cae750 PD |
2582 | + set_src_cost (XEXP (x, 0), mode, speed) |
2583 | + set_src_cost (XEXP (x, 1), mode, speed) | |
2584 | + set_src_cost (XEXP (x, 2), mode, speed)); | |
2585 | return true; | |
2586 | ||
2587 | case UNSPEC: | |
2588 | if (XINT (x, 1) == UNSPEC_AUIPC) | |
2589 | { | |
2590 | /* Make AUIPC cheap to avoid spilling its result to the stack. */ | |
2591 | *total = 1; | |
2592 | return true; | |
2593 | } | |
2594 | return false; | |
2595 | ||
2596 | default: | |
2597 | return false; | |
2598 | } | |
2599 | } | |
2600 | ||
2601 | /* Implement TARGET_ADDRESS_COST. */ | |
2602 | ||
2603 | static int | |
b8506a8a | 2604 | riscv_address_cost (rtx addr, machine_mode mode, |
09cae750 PD |
2605 | addr_space_t as ATTRIBUTE_UNUSED, |
2606 | bool speed ATTRIBUTE_UNUSED) | |
2607 | { | |
de6320a8 CB |
2608 | /* When optimizing for size, make uncompressible 32-bit addresses more |
2609 | * expensive so that compressible 32-bit addresses are preferred. */ | |
2610 | if (TARGET_RVC && !speed && riscv_mshorten_memrefs && mode == SImode | |
2611 | && !riscv_compressed_lw_address_p (addr)) | |
2612 | return riscv_address_insns (addr, mode, false) + 1; | |
09cae750 PD |
2613 | return riscv_address_insns (addr, mode, false); |
2614 | } | |
2615 | ||
2616 | /* Return one word of double-word value OP. HIGH_P is true to select the | |
2617 | high part or false to select the low part. */ | |
2618 | ||
2619 | rtx | |
2620 | riscv_subword (rtx op, bool high_p) | |
2621 | { | |
fffefe3d | 2622 | unsigned int byte = (high_p != BYTES_BIG_ENDIAN) ? UNITS_PER_WORD : 0; |
b8506a8a | 2623 | machine_mode mode = GET_MODE (op); |
09cae750 PD |
2624 | |
2625 | if (mode == VOIDmode) | |
2626 | mode = TARGET_64BIT ? TImode : DImode; | |
2627 | ||
2628 | if (MEM_P (op)) | |
2629 | return adjust_address (op, word_mode, byte); | |
2630 | ||
2631 | if (REG_P (op)) | |
2632 | gcc_assert (!FP_REG_RTX_P (op)); | |
2633 | ||
2634 | return simplify_gen_subreg (word_mode, op, mode, byte); | |
2635 | } | |
2636 | ||
2637 | /* Return true if a 64-bit move from SRC to DEST should be split into two. */ | |
2638 | ||
2639 | bool | |
2640 | riscv_split_64bit_move_p (rtx dest, rtx src) | |
2641 | { | |
2642 | if (TARGET_64BIT) | |
2643 | return false; | |
2644 | ||
2645 | /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case | |
2646 | of zeroing an FPR with FCVT.D.W. */ | |
2647 | if (TARGET_DOUBLE_FLOAT | |
2648 | && ((FP_REG_RTX_P (src) && FP_REG_RTX_P (dest)) | |
2649 | || (FP_REG_RTX_P (dest) && MEM_P (src)) | |
2650 | || (FP_REG_RTX_P (src) && MEM_P (dest)) | |
2651 | || (FP_REG_RTX_P (dest) && src == CONST0_RTX (GET_MODE (src))))) | |
2652 | return false; | |
2653 | ||
2654 | return true; | |
2655 | } | |
2656 | ||
2657 | /* Split a doubleword move from SRC to DEST. On 32-bit targets, | |
2658 | this function handles 64-bit moves for which riscv_split_64bit_move_p | |
2659 | holds. For 64-bit targets, this function handles 128-bit moves. */ | |
2660 | ||
2661 | void | |
2662 | riscv_split_doubleword_move (rtx dest, rtx src) | |
2663 | { | |
2664 | rtx low_dest; | |
2665 | ||
2666 | /* The operation can be split into two normal moves. Decide in | |
2667 | which order to do them. */ | |
2668 | low_dest = riscv_subword (dest, false); | |
2669 | if (REG_P (low_dest) && reg_overlap_mentioned_p (low_dest, src)) | |
2670 | { | |
2671 | riscv_emit_move (riscv_subword (dest, true), riscv_subword (src, true)); | |
2672 | riscv_emit_move (low_dest, riscv_subword (src, false)); | |
2673 | } | |
2674 | else | |
2675 | { | |
2676 | riscv_emit_move (low_dest, riscv_subword (src, false)); | |
2677 | riscv_emit_move (riscv_subword (dest, true), riscv_subword (src, true)); | |
2678 | } | |
2679 | } | |
2680 | \f | |
2681 | /* Return the appropriate instructions to move SRC into DEST. Assume | |
2682 | that SRC is operand 1 and DEST is operand 0. */ | |
2683 | ||
2684 | const char * | |
2685 | riscv_output_move (rtx dest, rtx src) | |
2686 | { | |
2687 | enum rtx_code dest_code, src_code; | |
b8506a8a | 2688 | machine_mode mode; |
09cae750 | 2689 | bool dbl_p; |
27d68a60 | 2690 | unsigned width; |
09cae750 PD |
2691 | |
2692 | dest_code = GET_CODE (dest); | |
2693 | src_code = GET_CODE (src); | |
2694 | mode = GET_MODE (dest); | |
3496ca4e | 2695 | dbl_p = (GET_MODE_SIZE (mode).to_constant () == 8); |
2696 | width = GET_MODE_SIZE (mode).to_constant (); | |
09cae750 PD |
2697 | |
2698 | if (dbl_p && riscv_split_64bit_move_p (dest, src)) | |
2699 | return "#"; | |
2700 | ||
2701 | if (dest_code == REG && GP_REG_P (REGNO (dest))) | |
2702 | { | |
2703 | if (src_code == REG && FP_REG_P (REGNO (src))) | |
27d68a60 KC |
2704 | switch (width) |
2705 | { | |
2706 | case 2: | |
bd159a76 KC |
2707 | if (TARGET_ZFHMIN) |
2708 | return "fmv.x.h\t%0,%1"; | |
27d68a60 KC |
2709 | /* Using fmv.x.s + sign-extend to emulate fmv.x.h. */ |
2710 | return "fmv.x.s\t%0,%1;slli\t%0,%0,16;srai\t%0,%0,16"; | |
2711 | case 4: | |
2712 | return "fmv.x.s\t%0,%1"; | |
2713 | case 8: | |
2714 | return "fmv.x.d\t%0,%1"; | |
2715 | } | |
09cae750 PD |
2716 | |
2717 | if (src_code == MEM) | |
27d68a60 | 2718 | switch (width) |
09cae750 PD |
2719 | { |
2720 | case 1: return "lbu\t%0,%1"; | |
2721 | case 2: return "lhu\t%0,%1"; | |
2722 | case 4: return "lw\t%0,%1"; | |
2723 | case 8: return "ld\t%0,%1"; | |
2724 | } | |
2725 | ||
2726 | if (src_code == CONST_INT) | |
4e1e0d79 JW |
2727 | { |
2728 | if (SMALL_OPERAND (INTVAL (src)) || LUI_OPERAND (INTVAL (src))) | |
2729 | return "li\t%0,%1"; | |
2730 | ||
2731 | if (TARGET_ZBS | |
2732 | && SINGLE_BIT_MASK_OPERAND (INTVAL (src))) | |
2733 | return "bseti\t%0,zero,%S1"; | |
2734 | ||
2735 | /* Should never reach here. */ | |
2736 | abort (); | |
2737 | } | |
09cae750 PD |
2738 | |
2739 | if (src_code == HIGH) | |
2740 | return "lui\t%0,%h1"; | |
2741 | ||
2742 | if (symbolic_operand (src, VOIDmode)) | |
2743 | switch (riscv_classify_symbolic_expression (src)) | |
2744 | { | |
2745 | case SYMBOL_GOT_DISP: return "la\t%0,%1"; | |
2746 | case SYMBOL_ABSOLUTE: return "lla\t%0,%1"; | |
2747 | case SYMBOL_PCREL: return "lla\t%0,%1"; | |
2748 | default: gcc_unreachable (); | |
2749 | } | |
2750 | } | |
2751 | if ((src_code == REG && GP_REG_P (REGNO (src))) | |
2752 | || (src == CONST0_RTX (mode))) | |
2753 | { | |
2754 | if (dest_code == REG) | |
2755 | { | |
2756 | if (GP_REG_P (REGNO (dest))) | |
2757 | return "mv\t%0,%z1"; | |
2758 | ||
2759 | if (FP_REG_P (REGNO (dest))) | |
27d68a60 KC |
2760 | switch (width) |
2761 | { | |
2762 | case 2: | |
bd159a76 KC |
2763 | if (TARGET_ZFHMIN) |
2764 | return "fmv.h.x\t%0,%z1"; | |
27d68a60 KC |
2765 | /* High 16 bits should be all-1, otherwise HW will treated |
2766 | as a n-bit canonical NaN, but isn't matter for softfloat. */ | |
2767 | return "fmv.s.x\t%0,%1"; | |
2768 | case 4: | |
2769 | return "fmv.s.x\t%0,%z1"; | |
2770 | case 8: | |
2771 | if (TARGET_64BIT) | |
2772 | return "fmv.d.x\t%0,%z1"; | |
2773 | /* in RV32, we can emulate fmv.d.x %0, x0 using fcvt.d.w */ | |
2774 | gcc_assert (src == CONST0_RTX (mode)); | |
2775 | return "fcvt.d.w\t%0,x0"; | |
2776 | } | |
09cae750 PD |
2777 | } |
2778 | if (dest_code == MEM) | |
27d68a60 | 2779 | switch (width) |
09cae750 PD |
2780 | { |
2781 | case 1: return "sb\t%z1,%0"; | |
2782 | case 2: return "sh\t%z1,%0"; | |
2783 | case 4: return "sw\t%z1,%0"; | |
2784 | case 8: return "sd\t%z1,%0"; | |
2785 | } | |
2786 | } | |
2787 | if (src_code == REG && FP_REG_P (REGNO (src))) | |
2788 | { | |
2789 | if (dest_code == REG && FP_REG_P (REGNO (dest))) | |
27d68a60 KC |
2790 | switch (width) |
2791 | { | |
2792 | case 2: | |
bd159a76 KC |
2793 | if (TARGET_ZFH) |
2794 | return "fmv.h\t%0,%1"; | |
27d68a60 KC |
2795 | return "fmv.s\t%0,%1"; |
2796 | case 4: | |
2797 | return "fmv.s\t%0,%1"; | |
2798 | case 8: | |
2799 | return "fmv.d\t%0,%1"; | |
2800 | } | |
09cae750 PD |
2801 | |
2802 | if (dest_code == MEM) | |
bd159a76 KC |
2803 | switch (width) |
2804 | { | |
2805 | case 2: | |
2806 | return "fsh\t%1,%0"; | |
2807 | case 4: | |
2808 | return "fsw\t%1,%0"; | |
2809 | case 8: | |
2810 | return "fsd\t%1,%0"; | |
2811 | } | |
09cae750 PD |
2812 | } |
2813 | if (dest_code == REG && FP_REG_P (REGNO (dest))) | |
2814 | { | |
2815 | if (src_code == MEM) | |
bd159a76 KC |
2816 | switch (width) |
2817 | { | |
2818 | case 2: | |
2819 | return "flh\t%0,%1"; | |
2820 | case 4: | |
2821 | return "flw\t%0,%1"; | |
2822 | case 8: | |
2823 | return "fld\t%0,%1"; | |
2824 | } | |
09cae750 | 2825 | } |
8fe75147 | 2826 | if (dest_code == REG && GP_REG_P (REGNO (dest)) && src_code == CONST_POLY_INT) |
2827 | { | |
2828 | /* We only want a single full vector register VLEN read after reload. */ | |
2829 | gcc_assert (known_eq (rtx_to_poly_int64 (src), BYTES_PER_RISCV_VECTOR)); | |
2830 | return "csrr\t%0,vlenb"; | |
2831 | } | |
09cae750 PD |
2832 | gcc_unreachable (); |
2833 | } | |
8cad5b14 KC |
2834 | |
2835 | const char * | |
2836 | riscv_output_return () | |
2837 | { | |
2838 | if (cfun->machine->naked_p) | |
2839 | return ""; | |
2840 | ||
2841 | return "ret"; | |
2842 | } | |
2843 | ||
09cae750 PD |
2844 | \f |
2845 | /* Return true if CMP1 is a suitable second operand for integer ordering | |
2846 | test CODE. See also the *sCC patterns in riscv.md. */ | |
2847 | ||
2848 | static bool | |
2849 | riscv_int_order_operand_ok_p (enum rtx_code code, rtx cmp1) | |
2850 | { | |
2851 | switch (code) | |
2852 | { | |
2853 | case GT: | |
2854 | case GTU: | |
2855 | return reg_or_0_operand (cmp1, VOIDmode); | |
2856 | ||
2857 | case GE: | |
2858 | case GEU: | |
2859 | return cmp1 == const1_rtx; | |
2860 | ||
2861 | case LT: | |
2862 | case LTU: | |
2863 | return arith_operand (cmp1, VOIDmode); | |
2864 | ||
2865 | case LE: | |
2866 | return sle_operand (cmp1, VOIDmode); | |
2867 | ||
2868 | case LEU: | |
2869 | return sleu_operand (cmp1, VOIDmode); | |
2870 | ||
2871 | default: | |
2872 | gcc_unreachable (); | |
2873 | } | |
2874 | } | |
2875 | ||
2876 | /* Return true if *CMP1 (of mode MODE) is a valid second operand for | |
2877 | integer ordering test *CODE, or if an equivalent combination can | |
2878 | be formed by adjusting *CODE and *CMP1. When returning true, update | |
2879 | *CODE and *CMP1 with the chosen code and operand, otherwise leave | |
2880 | them alone. */ | |
2881 | ||
2882 | static bool | |
2883 | riscv_canonicalize_int_order_test (enum rtx_code *code, rtx *cmp1, | |
b8506a8a | 2884 | machine_mode mode) |
09cae750 PD |
2885 | { |
2886 | HOST_WIDE_INT plus_one; | |
2887 | ||
2888 | if (riscv_int_order_operand_ok_p (*code, *cmp1)) | |
2889 | return true; | |
2890 | ||
2891 | if (CONST_INT_P (*cmp1)) | |
2892 | switch (*code) | |
2893 | { | |
2894 | case LE: | |
2895 | plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode); | |
2896 | if (INTVAL (*cmp1) < plus_one) | |
2897 | { | |
2898 | *code = LT; | |
2899 | *cmp1 = force_reg (mode, GEN_INT (plus_one)); | |
2900 | return true; | |
2901 | } | |
2902 | break; | |
2903 | ||
2904 | case LEU: | |
2905 | plus_one = trunc_int_for_mode (UINTVAL (*cmp1) + 1, mode); | |
2906 | if (plus_one != 0) | |
2907 | { | |
2908 | *code = LTU; | |
2909 | *cmp1 = force_reg (mode, GEN_INT (plus_one)); | |
2910 | return true; | |
2911 | } | |
2912 | break; | |
2913 | ||
2914 | default: | |
2915 | break; | |
2916 | } | |
2917 | return false; | |
2918 | } | |
2919 | ||
2920 | /* Compare CMP0 and CMP1 using ordering test CODE and store the result | |
2921 | in TARGET. CMP0 and TARGET are register_operands. If INVERT_PTR | |
2922 | is nonnull, it's OK to set TARGET to the inverse of the result and | |
2923 | flip *INVERT_PTR instead. */ | |
2924 | ||
2925 | static void | |
2926 | riscv_emit_int_order_test (enum rtx_code code, bool *invert_ptr, | |
2927 | rtx target, rtx cmp0, rtx cmp1) | |
2928 | { | |
b8506a8a | 2929 | machine_mode mode; |
09cae750 PD |
2930 | |
2931 | /* First see if there is a RISCV instruction that can do this operation. | |
2932 | If not, try doing the same for the inverse operation. If that also | |
2933 | fails, force CMP1 into a register and try again. */ | |
2934 | mode = GET_MODE (cmp0); | |
2935 | if (riscv_canonicalize_int_order_test (&code, &cmp1, mode)) | |
2936 | riscv_emit_binary (code, target, cmp0, cmp1); | |
2937 | else | |
2938 | { | |
2939 | enum rtx_code inv_code = reverse_condition (code); | |
2940 | if (!riscv_canonicalize_int_order_test (&inv_code, &cmp1, mode)) | |
2941 | { | |
2942 | cmp1 = force_reg (mode, cmp1); | |
2943 | riscv_emit_int_order_test (code, invert_ptr, target, cmp0, cmp1); | |
2944 | } | |
2945 | else if (invert_ptr == 0) | |
2946 | { | |
2947 | rtx inv_target = riscv_force_binary (GET_MODE (target), | |
2948 | inv_code, cmp0, cmp1); | |
2949 | riscv_emit_binary (XOR, target, inv_target, const1_rtx); | |
2950 | } | |
2951 | else | |
2952 | { | |
2953 | *invert_ptr = !*invert_ptr; | |
2954 | riscv_emit_binary (inv_code, target, cmp0, cmp1); | |
2955 | } | |
2956 | } | |
2957 | } | |
2958 | ||
2959 | /* Return a register that is zero iff CMP0 and CMP1 are equal. | |
2960 | The register will have the same mode as CMP0. */ | |
2961 | ||
2962 | static rtx | |
2963 | riscv_zero_if_equal (rtx cmp0, rtx cmp1) | |
2964 | { | |
2965 | if (cmp1 == const0_rtx) | |
2966 | return cmp0; | |
2967 | ||
2968 | return expand_binop (GET_MODE (cmp0), sub_optab, | |
2969 | cmp0, cmp1, 0, 0, OPTAB_DIRECT); | |
2970 | } | |
2971 | ||
2972 | /* Sign- or zero-extend OP0 and OP1 for integer comparisons. */ | |
2973 | ||
2974 | static void | |
2975 | riscv_extend_comparands (rtx_code code, rtx *op0, rtx *op1) | |
2976 | { | |
2977 | /* Comparisons consider all XLEN bits, so extend sub-XLEN values. */ | |
3496ca4e | 2978 | if (GET_MODE_SIZE (word_mode) > GET_MODE_SIZE (GET_MODE (*op0)).to_constant ()) |
09cae750 | 2979 | { |
7bbce9b5 JW |
2980 | /* It is more profitable to zero-extend QImode values. But not if the |
2981 | first operand has already been sign-extended, and the second one is | |
2982 | is a constant or has already been sign-extended also. */ | |
2983 | if (unsigned_condition (code) == code | |
2984 | && (GET_MODE (*op0) == QImode | |
2985 | && ! (GET_CODE (*op0) == SUBREG | |
2986 | && SUBREG_PROMOTED_VAR_P (*op0) | |
2987 | && SUBREG_PROMOTED_SIGNED_P (*op0) | |
2988 | && (CONST_INT_P (*op1) | |
2989 | || (GET_CODE (*op1) == SUBREG | |
2990 | && SUBREG_PROMOTED_VAR_P (*op1) | |
2991 | && SUBREG_PROMOTED_SIGNED_P (*op1)))))) | |
09cae750 PD |
2992 | { |
2993 | *op0 = gen_rtx_ZERO_EXTEND (word_mode, *op0); | |
2994 | if (CONST_INT_P (*op1)) | |
2995 | *op1 = GEN_INT ((uint8_t) INTVAL (*op1)); | |
2996 | else | |
2997 | *op1 = gen_rtx_ZERO_EXTEND (word_mode, *op1); | |
2998 | } | |
2999 | else | |
3000 | { | |
3001 | *op0 = gen_rtx_SIGN_EXTEND (word_mode, *op0); | |
3002 | if (*op1 != const0_rtx) | |
3003 | *op1 = gen_rtx_SIGN_EXTEND (word_mode, *op1); | |
3004 | } | |
3005 | } | |
3006 | } | |
3007 | ||
3008 | /* Convert a comparison into something that can be used in a branch. On | |
3009 | entry, *OP0 and *OP1 are the values being compared and *CODE is the code | |
3010 | used to compare them. Update them to describe the final comparison. */ | |
3011 | ||
3012 | static void | |
3013 | riscv_emit_int_compare (enum rtx_code *code, rtx *op0, rtx *op1) | |
3014 | { | |
3015 | if (splittable_const_int_operand (*op1, VOIDmode)) | |
3016 | { | |
3017 | HOST_WIDE_INT rhs = INTVAL (*op1); | |
3018 | ||
3019 | if (*code == EQ || *code == NE) | |
3020 | { | |
3021 | /* Convert e.g. OP0 == 2048 into OP0 - 2048 == 0. */ | |
3022 | if (SMALL_OPERAND (-rhs)) | |
3023 | { | |
3024 | *op0 = riscv_force_binary (GET_MODE (*op0), PLUS, *op0, | |
3025 | GEN_INT (-rhs)); | |
3026 | *op1 = const0_rtx; | |
3027 | } | |
3028 | } | |
3029 | else | |
3030 | { | |
3031 | static const enum rtx_code mag_comparisons[][2] = { | |
3032 | {LEU, LTU}, {GTU, GEU}, {LE, LT}, {GT, GE} | |
3033 | }; | |
3034 | ||
3035 | /* Convert e.g. (OP0 <= 0xFFF) into (OP0 < 0x1000). */ | |
3036 | for (size_t i = 0; i < ARRAY_SIZE (mag_comparisons); i++) | |
3037 | { | |
3038 | HOST_WIDE_INT new_rhs; | |
3039 | bool increment = *code == mag_comparisons[i][0]; | |
3040 | bool decrement = *code == mag_comparisons[i][1]; | |
3041 | if (!increment && !decrement) | |
3042 | continue; | |
3043 | ||
3044 | new_rhs = rhs + (increment ? 1 : -1); | |
2c721ea9 | 3045 | new_rhs = trunc_int_for_mode (new_rhs, GET_MODE (*op0)); |
09cae750 PD |
3046 | if (riscv_integer_cost (new_rhs) < riscv_integer_cost (rhs) |
3047 | && (rhs < 0) == (new_rhs < 0)) | |
3048 | { | |
3049 | *op1 = GEN_INT (new_rhs); | |
3050 | *code = mag_comparisons[i][increment]; | |
3051 | } | |
3052 | break; | |
3053 | } | |
3054 | } | |
3055 | } | |
3056 | ||
3057 | riscv_extend_comparands (*code, op0, op1); | |
3058 | ||
3059 | *op0 = force_reg (word_mode, *op0); | |
3060 | if (*op1 != const0_rtx) | |
3061 | *op1 = force_reg (word_mode, *op1); | |
3062 | } | |
3063 | ||
3064 | /* Like riscv_emit_int_compare, but for floating-point comparisons. */ | |
3065 | ||
3066 | static void | |
3067 | riscv_emit_float_compare (enum rtx_code *code, rtx *op0, rtx *op1) | |
3068 | { | |
3069 | rtx tmp0, tmp1, cmp_op0 = *op0, cmp_op1 = *op1; | |
3070 | enum rtx_code fp_code = *code; | |
3071 | *code = NE; | |
3072 | ||
3073 | switch (fp_code) | |
3074 | { | |
3075 | case UNORDERED: | |
3076 | *code = EQ; | |
3077 | /* Fall through. */ | |
3078 | ||
3079 | case ORDERED: | |
3080 | /* a == a && b == b */ | |
3081 | tmp0 = riscv_force_binary (word_mode, EQ, cmp_op0, cmp_op0); | |
3082 | tmp1 = riscv_force_binary (word_mode, EQ, cmp_op1, cmp_op1); | |
3083 | *op0 = riscv_force_binary (word_mode, AND, tmp0, tmp1); | |
3084 | *op1 = const0_rtx; | |
3085 | break; | |
3086 | ||
3087 | case UNEQ: | |
09cae750 | 3088 | /* ordered(a, b) > (a == b) */ |
9069e948 | 3089 | *code = EQ; |
09cae750 PD |
3090 | tmp0 = riscv_force_binary (word_mode, EQ, cmp_op0, cmp_op0); |
3091 | tmp1 = riscv_force_binary (word_mode, EQ, cmp_op1, cmp_op1); | |
3092 | *op0 = riscv_force_binary (word_mode, AND, tmp0, tmp1); | |
3093 | *op1 = riscv_force_binary (word_mode, EQ, cmp_op0, cmp_op1); | |
3094 | break; | |
3095 | ||
3096 | #define UNORDERED_COMPARISON(CODE, CMP) \ | |
3097 | case CODE: \ | |
3098 | *code = EQ; \ | |
3099 | *op0 = gen_reg_rtx (word_mode); \ | |
3100 | if (GET_MODE (cmp_op0) == SFmode && TARGET_64BIT) \ | |
3101 | emit_insn (gen_f##CMP##_quietsfdi4 (*op0, cmp_op0, cmp_op1)); \ | |
3102 | else if (GET_MODE (cmp_op0) == SFmode) \ | |
3103 | emit_insn (gen_f##CMP##_quietsfsi4 (*op0, cmp_op0, cmp_op1)); \ | |
3104 | else if (GET_MODE (cmp_op0) == DFmode && TARGET_64BIT) \ | |
3105 | emit_insn (gen_f##CMP##_quietdfdi4 (*op0, cmp_op0, cmp_op1)); \ | |
3106 | else if (GET_MODE (cmp_op0) == DFmode) \ | |
3107 | emit_insn (gen_f##CMP##_quietdfsi4 (*op0, cmp_op0, cmp_op1)); \ | |
bd159a76 KC |
3108 | else if (GET_MODE (cmp_op0) == HFmode && TARGET_64BIT) \ |
3109 | emit_insn (gen_f##CMP##_quiethfdi4 (*op0, cmp_op0, cmp_op1)); \ | |
3110 | else if (GET_MODE (cmp_op0) == HFmode) \ | |
3111 | emit_insn (gen_f##CMP##_quiethfsi4 (*op0, cmp_op0, cmp_op1)); \ | |
09cae750 PD |
3112 | else \ |
3113 | gcc_unreachable (); \ | |
3114 | *op1 = const0_rtx; \ | |
3115 | break; | |
3116 | ||
3117 | case UNLT: | |
3118 | std::swap (cmp_op0, cmp_op1); | |
cccfcff4 | 3119 | gcc_fallthrough (); |
09cae750 PD |
3120 | |
3121 | UNORDERED_COMPARISON(UNGT, le) | |
3122 | ||
3123 | case UNLE: | |
3124 | std::swap (cmp_op0, cmp_op1); | |
cccfcff4 | 3125 | gcc_fallthrough (); |
09cae750 PD |
3126 | |
3127 | UNORDERED_COMPARISON(UNGE, lt) | |
3128 | #undef UNORDERED_COMPARISON | |
3129 | ||
3130 | case NE: | |
3131 | fp_code = EQ; | |
3132 | *code = EQ; | |
3133 | /* Fall through. */ | |
3134 | ||
3135 | case EQ: | |
3136 | case LE: | |
3137 | case LT: | |
3138 | case GE: | |
3139 | case GT: | |
3140 | /* We have instructions for these cases. */ | |
3141 | *op0 = riscv_force_binary (word_mode, fp_code, cmp_op0, cmp_op1); | |
3142 | *op1 = const0_rtx; | |
3143 | break; | |
3144 | ||
9069e948 KC |
3145 | case LTGT: |
3146 | /* (a < b) | (a > b) */ | |
8cc59ac5 KC |
3147 | tmp0 = riscv_force_binary (word_mode, LT, cmp_op0, cmp_op1); |
3148 | tmp1 = riscv_force_binary (word_mode, GT, cmp_op0, cmp_op1); | |
3149 | *op0 = riscv_force_binary (word_mode, IOR, tmp0, tmp1); | |
3150 | *op1 = const0_rtx; | |
9069e948 KC |
3151 | break; |
3152 | ||
09cae750 PD |
3153 | default: |
3154 | gcc_unreachable (); | |
3155 | } | |
3156 | } | |
3157 | ||
3158 | /* CODE-compare OP0 and OP1. Store the result in TARGET. */ | |
3159 | ||
3160 | void | |
3161 | riscv_expand_int_scc (rtx target, enum rtx_code code, rtx op0, rtx op1) | |
3162 | { | |
3163 | riscv_extend_comparands (code, &op0, &op1); | |
3164 | op0 = force_reg (word_mode, op0); | |
3165 | ||
3166 | if (code == EQ || code == NE) | |
3167 | { | |
3168 | rtx zie = riscv_zero_if_equal (op0, op1); | |
3169 | riscv_emit_binary (code, target, zie, const0_rtx); | |
3170 | } | |
3171 | else | |
3172 | riscv_emit_int_order_test (code, 0, target, op0, op1); | |
3173 | } | |
3174 | ||
3175 | /* Like riscv_expand_int_scc, but for floating-point comparisons. */ | |
3176 | ||
3177 | void | |
3178 | riscv_expand_float_scc (rtx target, enum rtx_code code, rtx op0, rtx op1) | |
3179 | { | |
3180 | riscv_emit_float_compare (&code, &op0, &op1); | |
3181 | ||
3182 | rtx cmp = riscv_force_binary (word_mode, code, op0, op1); | |
3183 | riscv_emit_set (target, lowpart_subreg (SImode, cmp, word_mode)); | |
3184 | } | |
3185 | ||
3186 | /* Jump to LABEL if (CODE OP0 OP1) holds. */ | |
3187 | ||
3188 | void | |
3189 | riscv_expand_conditional_branch (rtx label, rtx_code code, rtx op0, rtx op1) | |
3190 | { | |
3191 | if (FLOAT_MODE_P (GET_MODE (op1))) | |
3192 | riscv_emit_float_compare (&code, &op0, &op1); | |
3193 | else | |
3194 | riscv_emit_int_compare (&code, &op0, &op1); | |
3195 | ||
3196 | rtx condition = gen_rtx_fmt_ee (code, VOIDmode, op0, op1); | |
3197 | emit_jump_insn (gen_condjump (condition, label)); | |
3198 | } | |
3199 | ||
4f475391 AW |
3200 | /* If (CODE OP0 OP1) holds, move CONS to DEST; else move ALT to DEST. */ |
3201 | ||
3202 | void | |
3203 | riscv_expand_conditional_move (rtx dest, rtx cons, rtx alt, rtx_code code, | |
3204 | rtx op0, rtx op1) | |
3205 | { | |
3206 | riscv_emit_int_compare (&code, &op0, &op1); | |
3207 | rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); | |
3208 | emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond, | |
3209 | cons, alt))); | |
3210 | } | |
3211 | ||
09cae750 PD |
3212 | /* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at |
3213 | least PARM_BOUNDARY bits of alignment, but will be given anything up | |
c0d3d1b6 | 3214 | to PREFERRED_STACK_BOUNDARY bits if the type requires it. */ |
09cae750 PD |
3215 | |
3216 | static unsigned int | |
b8506a8a | 3217 | riscv_function_arg_boundary (machine_mode mode, const_tree type) |
09cae750 PD |
3218 | { |
3219 | unsigned int alignment; | |
3220 | ||
3221 | /* Use natural alignment if the type is not aggregate data. */ | |
3222 | if (type && !AGGREGATE_TYPE_P (type)) | |
3223 | alignment = TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); | |
3224 | else | |
3225 | alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); | |
3226 | ||
c0d3d1b6 | 3227 | return MIN (PREFERRED_STACK_BOUNDARY, MAX (PARM_BOUNDARY, alignment)); |
09cae750 PD |
3228 | } |
3229 | ||
3230 | /* If MODE represents an argument that can be passed or returned in | |
3231 | floating-point registers, return the number of registers, else 0. */ | |
3232 | ||
3233 | static unsigned | |
b8506a8a | 3234 | riscv_pass_mode_in_fpr_p (machine_mode mode) |
09cae750 PD |
3235 | { |
3236 | if (GET_MODE_UNIT_SIZE (mode) <= UNITS_PER_FP_ARG) | |
3237 | { | |
3238 | if (GET_MODE_CLASS (mode) == MODE_FLOAT) | |
3239 | return 1; | |
3240 | ||
3241 | if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) | |
3242 | return 2; | |
3243 | } | |
3244 | ||
3245 | return 0; | |
3246 | } | |
3247 | ||
3248 | typedef struct { | |
3249 | const_tree type; | |
3250 | HOST_WIDE_INT offset; | |
3251 | } riscv_aggregate_field; | |
3252 | ||
3253 | /* Identify subfields of aggregates that are candidates for passing in | |
3254 | floating-point registers. */ | |
3255 | ||
3256 | static int | |
3257 | riscv_flatten_aggregate_field (const_tree type, | |
3258 | riscv_aggregate_field fields[2], | |
e98c3ee9 JW |
3259 | int n, HOST_WIDE_INT offset, |
3260 | bool ignore_zero_width_bit_field_p) | |
09cae750 PD |
3261 | { |
3262 | switch (TREE_CODE (type)) | |
3263 | { | |
3264 | case RECORD_TYPE: | |
3265 | /* Can't handle incomplete types nor sizes that are not fixed. */ | |
3266 | if (!COMPLETE_TYPE_P (type) | |
3267 | || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST | |
3268 | || !tree_fits_uhwi_p (TYPE_SIZE (type))) | |
3269 | return -1; | |
3270 | ||
3271 | for (tree f = TYPE_FIELDS (type); f; f = DECL_CHAIN (f)) | |
3272 | if (TREE_CODE (f) == FIELD_DECL) | |
3273 | { | |
3274 | if (!TYPE_P (TREE_TYPE (f))) | |
3275 | return -1; | |
3276 | ||
e98c3ee9 JW |
3277 | /* The C++ front end strips zero-length bit-fields from structs. |
3278 | So we need to ignore them in the C front end to make C code | |
3279 | compatible with C++ code. */ | |
3280 | if (ignore_zero_width_bit_field_p | |
3281 | && DECL_BIT_FIELD (f) | |
3282 | && (DECL_SIZE (f) == NULL_TREE | |
3283 | || integer_zerop (DECL_SIZE (f)))) | |
3284 | ; | |
3285 | else | |
3286 | { | |
3287 | HOST_WIDE_INT pos = offset + int_byte_position (f); | |
3288 | n = riscv_flatten_aggregate_field (TREE_TYPE (f), | |
3289 | fields, n, pos, | |
3290 | ignore_zero_width_bit_field_p); | |
3291 | } | |
09cae750 PD |
3292 | if (n < 0) |
3293 | return -1; | |
3294 | } | |
3295 | return n; | |
3296 | ||
3297 | case ARRAY_TYPE: | |
3298 | { | |
3299 | HOST_WIDE_INT n_elts; | |
3300 | riscv_aggregate_field subfields[2]; | |
3301 | tree index = TYPE_DOMAIN (type); | |
3302 | tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type)); | |
3303 | int n_subfields = riscv_flatten_aggregate_field (TREE_TYPE (type), | |
e98c3ee9 JW |
3304 | subfields, 0, offset, |
3305 | ignore_zero_width_bit_field_p); | |
09cae750 PD |
3306 | |
3307 | /* Can't handle incomplete types nor sizes that are not fixed. */ | |
3308 | if (n_subfields <= 0 | |
3309 | || !COMPLETE_TYPE_P (type) | |
3310 | || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST | |
3311 | || !index | |
3312 | || !TYPE_MAX_VALUE (index) | |
3313 | || !tree_fits_uhwi_p (TYPE_MAX_VALUE (index)) | |
3314 | || !TYPE_MIN_VALUE (index) | |
3315 | || !tree_fits_uhwi_p (TYPE_MIN_VALUE (index)) | |
3316 | || !tree_fits_uhwi_p (elt_size)) | |
3317 | return -1; | |
3318 | ||
3319 | n_elts = 1 + tree_to_uhwi (TYPE_MAX_VALUE (index)) | |
3320 | - tree_to_uhwi (TYPE_MIN_VALUE (index)); | |
3321 | gcc_assert (n_elts >= 0); | |
3322 | ||
3323 | for (HOST_WIDE_INT i = 0; i < n_elts; i++) | |
3324 | for (int j = 0; j < n_subfields; j++) | |
3325 | { | |
3326 | if (n >= 2) | |
3327 | return -1; | |
3328 | ||
3329 | fields[n] = subfields[j]; | |
3330 | fields[n++].offset += i * tree_to_uhwi (elt_size); | |
3331 | } | |
3332 | ||
3333 | return n; | |
3334 | } | |
3335 | ||
3336 | case COMPLEX_TYPE: | |
3337 | { | |
3338 | /* Complex type need consume 2 field, so n must be 0. */ | |
3339 | if (n != 0) | |
3340 | return -1; | |
3341 | ||
3496ca4e | 3342 | HOST_WIDE_INT elt_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type))).to_constant (); |
09cae750 PD |
3343 | |
3344 | if (elt_size <= UNITS_PER_FP_ARG) | |
3345 | { | |
3346 | fields[0].type = TREE_TYPE (type); | |
3347 | fields[0].offset = offset; | |
3348 | fields[1].type = TREE_TYPE (type); | |
3349 | fields[1].offset = offset + elt_size; | |
3350 | ||
3351 | return 2; | |
3352 | } | |
3353 | ||
3354 | return -1; | |
3355 | } | |
3356 | ||
3357 | default: | |
3358 | if (n < 2 | |
3359 | && ((SCALAR_FLOAT_TYPE_P (type) | |
3496ca4e | 3360 | && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_FP_ARG) |
09cae750 | 3361 | || (INTEGRAL_TYPE_P (type) |
3496ca4e | 3362 | && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_WORD))) |
09cae750 PD |
3363 | { |
3364 | fields[n].type = type; | |
3365 | fields[n].offset = offset; | |
3366 | return n + 1; | |
3367 | } | |
3368 | else | |
3369 | return -1; | |
3370 | } | |
3371 | } | |
3372 | ||
3373 | /* Identify candidate aggregates for passing in floating-point registers. | |
3374 | Candidates have at most two fields after flattening. */ | |
3375 | ||
3376 | static int | |
3377 | riscv_flatten_aggregate_argument (const_tree type, | |
e98c3ee9 JW |
3378 | riscv_aggregate_field fields[2], |
3379 | bool ignore_zero_width_bit_field_p) | |
09cae750 PD |
3380 | { |
3381 | if (!type || TREE_CODE (type) != RECORD_TYPE) | |
3382 | return -1; | |
3383 | ||
e98c3ee9 JW |
3384 | return riscv_flatten_aggregate_field (type, fields, 0, 0, |
3385 | ignore_zero_width_bit_field_p); | |
09cae750 PD |
3386 | } |
3387 | ||
3388 | /* See whether TYPE is a record whose fields should be returned in one or | |
3389 | two floating-point registers. If so, populate FIELDS accordingly. */ | |
3390 | ||
3391 | static unsigned | |
3392 | riscv_pass_aggregate_in_fpr_pair_p (const_tree type, | |
3393 | riscv_aggregate_field fields[2]) | |
3394 | { | |
e98c3ee9 | 3395 | static int warned = 0; |
09cae750 | 3396 | |
e98c3ee9 JW |
3397 | /* This is the old ABI, which differs for C++ and C. */ |
3398 | int n_old = riscv_flatten_aggregate_argument (type, fields, false); | |
3399 | for (int i = 0; i < n_old; i++) | |
09cae750 | 3400 | if (!SCALAR_FLOAT_TYPE_P (fields[i].type)) |
e98c3ee9 JW |
3401 | { |
3402 | n_old = -1; | |
3403 | break; | |
3404 | } | |
3405 | ||
3406 | /* This is the new ABI, which is the same for C++ and C. */ | |
3407 | int n_new = riscv_flatten_aggregate_argument (type, fields, true); | |
3408 | for (int i = 0; i < n_new; i++) | |
3409 | if (!SCALAR_FLOAT_TYPE_P (fields[i].type)) | |
3410 | { | |
3411 | n_new = -1; | |
3412 | break; | |
3413 | } | |
09cae750 | 3414 | |
e98c3ee9 JW |
3415 | if ((n_old != n_new) && (warned == 0)) |
3416 | { | |
98afdc3e JJ |
3417 | warning (OPT_Wpsabi, "ABI for flattened struct with zero-length " |
3418 | "bit-fields changed in GCC 10"); | |
e98c3ee9 JW |
3419 | warned = 1; |
3420 | } | |
3421 | ||
3422 | return n_new > 0 ? n_new : 0; | |
09cae750 PD |
3423 | } |
3424 | ||
3425 | /* See whether TYPE is a record whose fields should be returned in one or | |
3426 | floating-point register and one integer register. If so, populate | |
3427 | FIELDS accordingly. */ | |
3428 | ||
3429 | static bool | |
3430 | riscv_pass_aggregate_in_fpr_and_gpr_p (const_tree type, | |
3431 | riscv_aggregate_field fields[2]) | |
3432 | { | |
e98c3ee9 JW |
3433 | static int warned = 0; |
3434 | ||
3435 | /* This is the old ABI, which differs for C++ and C. */ | |
3436 | unsigned num_int_old = 0, num_float_old = 0; | |
3437 | int n_old = riscv_flatten_aggregate_argument (type, fields, false); | |
3438 | for (int i = 0; i < n_old; i++) | |
3439 | { | |
3440 | num_float_old += SCALAR_FLOAT_TYPE_P (fields[i].type); | |
3441 | num_int_old += INTEGRAL_TYPE_P (fields[i].type); | |
3442 | } | |
3443 | ||
3444 | /* This is the new ABI, which is the same for C++ and C. */ | |
3445 | unsigned num_int_new = 0, num_float_new = 0; | |
3446 | int n_new = riscv_flatten_aggregate_argument (type, fields, true); | |
3447 | for (int i = 0; i < n_new; i++) | |
3448 | { | |
3449 | num_float_new += SCALAR_FLOAT_TYPE_P (fields[i].type); | |
3450 | num_int_new += INTEGRAL_TYPE_P (fields[i].type); | |
3451 | } | |
09cae750 | 3452 | |
e98c3ee9 JW |
3453 | if (((num_int_old == 1 && num_float_old == 1 |
3454 | && (num_int_old != num_int_new || num_float_old != num_float_new)) | |
3455 | || (num_int_new == 1 && num_float_new == 1 | |
3456 | && (num_int_old != num_int_new || num_float_old != num_float_new))) | |
3457 | && (warned == 0)) | |
09cae750 | 3458 | { |
98afdc3e JJ |
3459 | warning (OPT_Wpsabi, "ABI for flattened struct with zero-length " |
3460 | "bit-fields changed in GCC 10"); | |
e98c3ee9 | 3461 | warned = 1; |
09cae750 PD |
3462 | } |
3463 | ||
e98c3ee9 | 3464 | return num_int_new == 1 && num_float_new == 1; |
09cae750 PD |
3465 | } |
3466 | ||
3467 | /* Return the representation of an argument passed or returned in an FPR | |
3468 | when the value has mode VALUE_MODE and the type has TYPE_MODE. The | |
3469 | two modes may be different for structures like: | |
3470 | ||
3471 | struct __attribute__((packed)) foo { float f; } | |
3472 | ||
3473 | where the SFmode value "f" is passed in REGNO but the struct itself | |
3474 | has mode BLKmode. */ | |
3475 | ||
3476 | static rtx | |
b8506a8a | 3477 | riscv_pass_fpr_single (machine_mode type_mode, unsigned regno, |
4d7dfada AB |
3478 | machine_mode value_mode, |
3479 | HOST_WIDE_INT offset) | |
09cae750 PD |
3480 | { |
3481 | rtx x = gen_rtx_REG (value_mode, regno); | |
3482 | ||
3483 | if (type_mode != value_mode) | |
3484 | { | |
4d7dfada | 3485 | x = gen_rtx_EXPR_LIST (VOIDmode, x, GEN_INT (offset)); |
09cae750 PD |
3486 | x = gen_rtx_PARALLEL (type_mode, gen_rtvec (1, x)); |
3487 | } | |
3488 | return x; | |
3489 | } | |
3490 | ||
3491 | /* Pass or return a composite value in the FPR pair REGNO and REGNO + 1. | |
3492 | MODE is the mode of the composite. MODE1 and OFFSET1 are the mode and | |
3493 | byte offset for the first value, likewise MODE2 and OFFSET2 for the | |
3494 | second value. */ | |
3495 | ||
3496 | static rtx | |
b8506a8a RS |
3497 | riscv_pass_fpr_pair (machine_mode mode, unsigned regno1, |
3498 | machine_mode mode1, HOST_WIDE_INT offset1, | |
3499 | unsigned regno2, machine_mode mode2, | |
09cae750 PD |
3500 | HOST_WIDE_INT offset2) |
3501 | { | |
3502 | return gen_rtx_PARALLEL | |
3503 | (mode, | |
3504 | gen_rtvec (2, | |
3505 | gen_rtx_EXPR_LIST (VOIDmode, | |
3506 | gen_rtx_REG (mode1, regno1), | |
3507 | GEN_INT (offset1)), | |
3508 | gen_rtx_EXPR_LIST (VOIDmode, | |
3509 | gen_rtx_REG (mode2, regno2), | |
3510 | GEN_INT (offset2)))); | |
3511 | } | |
3512 | ||
3513 | /* Fill INFO with information about a single argument, and return an | |
3514 | RTL pattern to pass or return the argument. CUM is the cumulative | |
3515 | state for earlier arguments. MODE is the mode of this argument and | |
3516 | TYPE is its type (if known). NAMED is true if this is a named | |
3517 | (fixed) argument rather than a variable one. RETURN_P is true if | |
3518 | returning the argument, or false if passing the argument. */ | |
3519 | ||
3520 | static rtx | |
3521 | riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, | |
b8506a8a | 3522 | machine_mode mode, const_tree type, bool named, |
09cae750 PD |
3523 | bool return_p) |
3524 | { | |
3525 | unsigned num_bytes, num_words; | |
3526 | unsigned fpr_base = return_p ? FP_RETURN : FP_ARG_FIRST; | |
3527 | unsigned gpr_base = return_p ? GP_RETURN : GP_ARG_FIRST; | |
3528 | unsigned alignment = riscv_function_arg_boundary (mode, type); | |
3529 | ||
3530 | memset (info, 0, sizeof (*info)); | |
3531 | info->gpr_offset = cum->num_gprs; | |
3532 | info->fpr_offset = cum->num_fprs; | |
3533 | ||
3534 | if (named) | |
3535 | { | |
3536 | riscv_aggregate_field fields[2]; | |
3537 | unsigned fregno = fpr_base + info->fpr_offset; | |
3538 | unsigned gregno = gpr_base + info->gpr_offset; | |
3539 | ||
3540 | /* Pass one- or two-element floating-point aggregates in FPRs. */ | |
3541 | if ((info->num_fprs = riscv_pass_aggregate_in_fpr_pair_p (type, fields)) | |
3542 | && info->fpr_offset + info->num_fprs <= MAX_ARGS_IN_REGISTERS) | |
3543 | switch (info->num_fprs) | |
3544 | { | |
3545 | case 1: | |
3546 | return riscv_pass_fpr_single (mode, fregno, | |
4d7dfada AB |
3547 | TYPE_MODE (fields[0].type), |
3548 | fields[0].offset); | |
09cae750 PD |
3549 | |
3550 | case 2: | |
3551 | return riscv_pass_fpr_pair (mode, fregno, | |
3552 | TYPE_MODE (fields[0].type), | |
3553 | fields[0].offset, | |
3554 | fregno + 1, | |
3555 | TYPE_MODE (fields[1].type), | |
3556 | fields[1].offset); | |
3557 | ||
3558 | default: | |
3559 | gcc_unreachable (); | |
3560 | } | |
3561 | ||
3562 | /* Pass real and complex floating-point numbers in FPRs. */ | |
3563 | if ((info->num_fprs = riscv_pass_mode_in_fpr_p (mode)) | |
3564 | && info->fpr_offset + info->num_fprs <= MAX_ARGS_IN_REGISTERS) | |
3565 | switch (GET_MODE_CLASS (mode)) | |
3566 | { | |
3567 | case MODE_FLOAT: | |
3568 | return gen_rtx_REG (mode, fregno); | |
3569 | ||
3570 | case MODE_COMPLEX_FLOAT: | |
3571 | return riscv_pass_fpr_pair (mode, fregno, GET_MODE_INNER (mode), 0, | |
3572 | fregno + 1, GET_MODE_INNER (mode), | |
3573 | GET_MODE_UNIT_SIZE (mode)); | |
3574 | ||
3575 | default: | |
3576 | gcc_unreachable (); | |
3577 | } | |
3578 | ||
3579 | /* Pass structs with one float and one integer in an FPR and a GPR. */ | |
3580 | if (riscv_pass_aggregate_in_fpr_and_gpr_p (type, fields) | |
3581 | && info->gpr_offset < MAX_ARGS_IN_REGISTERS | |
3582 | && info->fpr_offset < MAX_ARGS_IN_REGISTERS) | |
3583 | { | |
3584 | info->num_gprs = 1; | |
3585 | info->num_fprs = 1; | |
3586 | ||
3587 | if (!SCALAR_FLOAT_TYPE_P (fields[0].type)) | |
3588 | std::swap (fregno, gregno); | |
3589 | ||
3590 | return riscv_pass_fpr_pair (mode, fregno, TYPE_MODE (fields[0].type), | |
3591 | fields[0].offset, | |
3592 | gregno, TYPE_MODE (fields[1].type), | |
3593 | fields[1].offset); | |
3594 | } | |
3595 | } | |
3596 | ||
3597 | /* Work out the size of the argument. */ | |
3496ca4e | 3598 | num_bytes = type ? int_size_in_bytes (type) : GET_MODE_SIZE (mode).to_constant (); |
09cae750 PD |
3599 | num_words = (num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
3600 | ||
3601 | /* Doubleword-aligned varargs start on an even register boundary. */ | |
3602 | if (!named && num_bytes != 0 && alignment > BITS_PER_WORD) | |
3603 | info->gpr_offset += info->gpr_offset & 1; | |
3604 | ||
3605 | /* Partition the argument between registers and stack. */ | |
3606 | info->num_fprs = 0; | |
3607 | info->num_gprs = MIN (num_words, MAX_ARGS_IN_REGISTERS - info->gpr_offset); | |
3608 | info->stack_p = (num_words - info->num_gprs) != 0; | |
3609 | ||
3610 | if (info->num_gprs || return_p) | |
3611 | return gen_rtx_REG (mode, gpr_base + info->gpr_offset); | |
3612 | ||
3613 | return NULL_RTX; | |
3614 | } | |
3615 | ||
3616 | /* Implement TARGET_FUNCTION_ARG. */ | |
3617 | ||
3618 | static rtx | |
6783fdb7 | 3619 | riscv_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) |
09cae750 PD |
3620 | { |
3621 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
3622 | struct riscv_arg_info info; | |
3623 | ||
6783fdb7 | 3624 | if (arg.end_marker_p ()) |
09cae750 PD |
3625 | return NULL; |
3626 | ||
6783fdb7 | 3627 | return riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); |
09cae750 PD |
3628 | } |
3629 | ||
3630 | /* Implement TARGET_FUNCTION_ARG_ADVANCE. */ | |
3631 | ||
3632 | static void | |
6930c98c RS |
3633 | riscv_function_arg_advance (cumulative_args_t cum_v, |
3634 | const function_arg_info &arg) | |
09cae750 PD |
3635 | { |
3636 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
3637 | struct riscv_arg_info info; | |
3638 | ||
6930c98c | 3639 | riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); |
09cae750 PD |
3640 | |
3641 | /* Advance the register count. This has the effect of setting | |
3642 | num_gprs to MAX_ARGS_IN_REGISTERS if a doubleword-aligned | |
3643 | argument required us to skip the final GPR and pass the whole | |
3644 | argument on the stack. */ | |
3645 | cum->num_fprs = info.fpr_offset + info.num_fprs; | |
3646 | cum->num_gprs = info.gpr_offset + info.num_gprs; | |
3647 | } | |
3648 | ||
3649 | /* Implement TARGET_ARG_PARTIAL_BYTES. */ | |
3650 | ||
3651 | static int | |
3652 | riscv_arg_partial_bytes (cumulative_args_t cum, | |
a7c81bc1 | 3653 | const function_arg_info &generic_arg) |
09cae750 PD |
3654 | { |
3655 | struct riscv_arg_info arg; | |
3656 | ||
a7c81bc1 RS |
3657 | riscv_get_arg_info (&arg, get_cumulative_args (cum), generic_arg.mode, |
3658 | generic_arg.type, generic_arg.named, false); | |
09cae750 PD |
3659 | return arg.stack_p ? arg.num_gprs * UNITS_PER_WORD : 0; |
3660 | } | |
3661 | ||
3662 | /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, | |
3663 | VALTYPE is the return type and MODE is VOIDmode. For libcalls, | |
3664 | VALTYPE is null and MODE is the mode of the return value. */ | |
3665 | ||
3666 | rtx | |
b8506a8a | 3667 | riscv_function_value (const_tree type, const_tree func, machine_mode mode) |
09cae750 PD |
3668 | { |
3669 | struct riscv_arg_info info; | |
3670 | CUMULATIVE_ARGS args; | |
3671 | ||
3672 | if (type) | |
3673 | { | |
3674 | int unsigned_p = TYPE_UNSIGNED (type); | |
3675 | ||
3676 | mode = TYPE_MODE (type); | |
3677 | ||
3678 | /* Since TARGET_PROMOTE_FUNCTION_MODE unconditionally promotes, | |
3679 | return values, promote the mode here too. */ | |
3680 | mode = promote_function_mode (type, mode, &unsigned_p, func, 1); | |
3681 | } | |
3682 | ||
3683 | memset (&args, 0, sizeof args); | |
3684 | return riscv_get_arg_info (&info, &args, mode, type, true, true); | |
3685 | } | |
3686 | ||
3687 | /* Implement TARGET_PASS_BY_REFERENCE. */ | |
3688 | ||
3689 | static bool | |
52090e4d | 3690 | riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) |
09cae750 | 3691 | { |
3496ca4e | 3692 | HOST_WIDE_INT size = arg.type_size_in_bytes ().to_constant ();; |
09cae750 PD |
3693 | struct riscv_arg_info info; |
3694 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
3695 | ||
3696 | /* ??? std_gimplify_va_arg_expr passes NULL for cum. Fortunately, we | |
3697 | never pass variadic arguments in floating-point registers, so we can | |
3698 | avoid the call to riscv_get_arg_info in this case. */ | |
3699 | if (cum != NULL) | |
3700 | { | |
3701 | /* Don't pass by reference if we can use a floating-point register. */ | |
52090e4d | 3702 | riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); |
09cae750 PD |
3703 | if (info.num_fprs) |
3704 | return false; | |
3705 | } | |
3706 | ||
3707 | /* Pass by reference if the data do not fit in two integer registers. */ | |
3708 | return !IN_RANGE (size, 0, 2 * UNITS_PER_WORD); | |
3709 | } | |
3710 | ||
3711 | /* Implement TARGET_RETURN_IN_MEMORY. */ | |
3712 | ||
3713 | static bool | |
3714 | riscv_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) | |
3715 | { | |
3716 | CUMULATIVE_ARGS args; | |
3717 | cumulative_args_t cum = pack_cumulative_args (&args); | |
3718 | ||
3719 | /* The rules for returning in memory are the same as for passing the | |
3720 | first named argument by reference. */ | |
3721 | memset (&args, 0, sizeof args); | |
52090e4d RS |
3722 | function_arg_info arg (const_cast<tree> (type), /*named=*/true); |
3723 | return riscv_pass_by_reference (cum, arg); | |
09cae750 PD |
3724 | } |
3725 | ||
3726 | /* Implement TARGET_SETUP_INCOMING_VARARGS. */ | |
3727 | ||
3728 | static void | |
e7056ca4 RS |
3729 | riscv_setup_incoming_varargs (cumulative_args_t cum, |
3730 | const function_arg_info &arg, | |
3731 | int *pretend_size ATTRIBUTE_UNUSED, int no_rtl) | |
09cae750 PD |
3732 | { |
3733 | CUMULATIVE_ARGS local_cum; | |
3734 | int gp_saved; | |
3735 | ||
3736 | /* The caller has advanced CUM up to, but not beyond, the last named | |
3737 | argument. Advance a local copy of CUM past the last "real" named | |
3738 | argument, to find out how many registers are left over. */ | |
3739 | local_cum = *get_cumulative_args (cum); | |
6930c98c | 3740 | riscv_function_arg_advance (pack_cumulative_args (&local_cum), arg); |
09cae750 PD |
3741 | |
3742 | /* Found out how many registers we need to save. */ | |
3743 | gp_saved = MAX_ARGS_IN_REGISTERS - local_cum.num_gprs; | |
3744 | ||
3745 | if (!no_rtl && gp_saved > 0) | |
3746 | { | |
3747 | rtx ptr = plus_constant (Pmode, virtual_incoming_args_rtx, | |
3748 | REG_PARM_STACK_SPACE (cfun->decl) | |
3749 | - gp_saved * UNITS_PER_WORD); | |
3750 | rtx mem = gen_frame_mem (BLKmode, ptr); | |
3751 | set_mem_alias_set (mem, get_varargs_alias_set ()); | |
3752 | ||
3753 | move_block_from_reg (local_cum.num_gprs + GP_ARG_FIRST, | |
3754 | mem, gp_saved); | |
3755 | } | |
3756 | if (REG_PARM_STACK_SPACE (cfun->decl) == 0) | |
3757 | cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD; | |
3758 | } | |
3759 | ||
8cad5b14 KC |
3760 | /* Handle an attribute requiring a FUNCTION_DECL; |
3761 | arguments as in struct attribute_spec.handler. */ | |
3762 | static tree | |
3763 | riscv_handle_fndecl_attribute (tree *node, tree name, | |
3764 | tree args ATTRIBUTE_UNUSED, | |
3765 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) | |
3766 | { | |
3767 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
3768 | { | |
3769 | warning (OPT_Wattributes, "%qE attribute only applies to functions", | |
3770 | name); | |
3771 | *no_add_attrs = true; | |
3772 | } | |
3773 | ||
3774 | return NULL_TREE; | |
3775 | } | |
3776 | ||
ec74725c JW |
3777 | /* Verify type based attributes. NODE is the what the attribute is being |
3778 | applied to. NAME is the attribute name. ARGS are the attribute args. | |
3779 | FLAGS gives info about the context. NO_ADD_ATTRS should be set to true if | |
3780 | the attribute should be ignored. */ | |
3781 | ||
3782 | static tree | |
3783 | riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args, | |
3784 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) | |
3785 | { | |
3786 | /* Check for an argument. */ | |
3787 | if (is_attribute_p ("interrupt", name)) | |
3788 | { | |
3789 | if (args) | |
3790 | { | |
3791 | tree cst = TREE_VALUE (args); | |
3792 | const char *string; | |
3793 | ||
3794 | if (TREE_CODE (cst) != STRING_CST) | |
3795 | { | |
3796 | warning (OPT_Wattributes, | |
3797 | "%qE attribute requires a string argument", | |
3798 | name); | |
3799 | *no_add_attrs = true; | |
3800 | return NULL_TREE; | |
3801 | } | |
3802 | ||
3803 | string = TREE_STRING_POINTER (cst); | |
3804 | if (strcmp (string, "user") && strcmp (string, "supervisor") | |
3805 | && strcmp (string, "machine")) | |
3806 | { | |
3807 | warning (OPT_Wattributes, | |
fdf31ae2 ML |
3808 | "argument to %qE attribute is not %<\"user\"%>, %<\"supervisor\"%>, " |
3809 | "or %<\"machine\"%>", name); | |
ec74725c JW |
3810 | *no_add_attrs = true; |
3811 | } | |
3812 | } | |
3813 | } | |
3814 | ||
3815 | return NULL_TREE; | |
3816 | } | |
3817 | ||
5af3ff21 | 3818 | /* Return true if function TYPE is an interrupt function. */ |
d0ebdd9f JW |
3819 | static bool |
3820 | riscv_interrupt_type_p (tree type) | |
3821 | { | |
3822 | return lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type)) != NULL; | |
3823 | } | |
3824 | ||
3825 | /* Return true if FUNC is a naked function. */ | |
8cad5b14 KC |
3826 | static bool |
3827 | riscv_naked_function_p (tree func) | |
3828 | { | |
3829 | tree func_decl = func; | |
3830 | if (func == NULL_TREE) | |
3831 | func_decl = current_function_decl; | |
3832 | return NULL_TREE != lookup_attribute ("naked", DECL_ATTRIBUTES (func_decl)); | |
3833 | } | |
3834 | ||
3835 | /* Implement TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS. */ | |
3836 | static bool | |
3837 | riscv_allocate_stack_slots_for_args () | |
3838 | { | |
3839 | /* Naked functions should not allocate stack slots for arguments. */ | |
3840 | return !riscv_naked_function_p (current_function_decl); | |
3841 | } | |
3842 | ||
3843 | /* Implement TARGET_WARN_FUNC_RETURN. */ | |
3844 | static bool | |
3845 | riscv_warn_func_return (tree decl) | |
3846 | { | |
3847 | /* Naked functions are implemented entirely in assembly, including the | |
3848 | return sequence, so suppress warnings about this. */ | |
3849 | return !riscv_naked_function_p (decl); | |
3850 | } | |
3851 | ||
09cae750 PD |
3852 | /* Implement TARGET_EXPAND_BUILTIN_VA_START. */ |
3853 | ||
3854 | static void | |
3855 | riscv_va_start (tree valist, rtx nextarg) | |
3856 | { | |
3857 | nextarg = plus_constant (Pmode, nextarg, -cfun->machine->varargs_size); | |
3858 | std_expand_builtin_va_start (valist, nextarg); | |
3859 | } | |
3860 | ||
3861 | /* Make ADDR suitable for use as a call or sibcall target. */ | |
3862 | ||
3863 | rtx | |
3864 | riscv_legitimize_call_address (rtx addr) | |
3865 | { | |
3866 | if (!call_insn_operand (addr, VOIDmode)) | |
3867 | { | |
207de839 | 3868 | rtx reg = RISCV_CALL_ADDRESS_TEMP (Pmode); |
09cae750 PD |
3869 | riscv_emit_move (reg, addr); |
3870 | return reg; | |
3871 | } | |
3872 | return addr; | |
3873 | } | |
3874 | ||
6ed01e6b AW |
3875 | /* Emit straight-line code to move LENGTH bytes from SRC to DEST. |
3876 | Assume that the areas do not overlap. */ | |
3877 | ||
3878 | static void | |
d9f0ade0 | 3879 | riscv_block_move_straight (rtx dest, rtx src, unsigned HOST_WIDE_INT length) |
6ed01e6b | 3880 | { |
d9f0ade0 | 3881 | unsigned HOST_WIDE_INT offset, delta; |
6ed01e6b AW |
3882 | unsigned HOST_WIDE_INT bits; |
3883 | int i; | |
3884 | enum machine_mode mode; | |
3885 | rtx *regs; | |
3886 | ||
3887 | bits = MAX (BITS_PER_UNIT, | |
3888 | MIN (BITS_PER_WORD, MIN (MEM_ALIGN (src), MEM_ALIGN (dest)))); | |
3889 | ||
fb5621b1 | 3890 | mode = mode_for_size (bits, MODE_INT, 0).require (); |
6ed01e6b AW |
3891 | delta = bits / BITS_PER_UNIT; |
3892 | ||
3893 | /* Allocate a buffer for the temporary registers. */ | |
3894 | regs = XALLOCAVEC (rtx, length / delta); | |
3895 | ||
3896 | /* Load as many BITS-sized chunks as possible. Use a normal load if | |
3897 | the source has enough alignment, otherwise use left/right pairs. */ | |
3898 | for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) | |
3899 | { | |
3900 | regs[i] = gen_reg_rtx (mode); | |
3901 | riscv_emit_move (regs[i], adjust_address (src, mode, offset)); | |
3902 | } | |
3903 | ||
3904 | /* Copy the chunks to the destination. */ | |
3905 | for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) | |
3906 | riscv_emit_move (adjust_address (dest, mode, offset), regs[i]); | |
3907 | ||
3908 | /* Mop up any left-over bytes. */ | |
3909 | if (offset < length) | |
3910 | { | |
3911 | src = adjust_address (src, BLKmode, offset); | |
3912 | dest = adjust_address (dest, BLKmode, offset); | |
3913 | move_by_pieces (dest, src, length - offset, | |
cece89d0 | 3914 | MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), RETURN_BEGIN); |
6ed01e6b AW |
3915 | } |
3916 | } | |
3917 | ||
3918 | /* Helper function for doing a loop-based block operation on memory | |
3919 | reference MEM. Each iteration of the loop will operate on LENGTH | |
3920 | bytes of MEM. | |
3921 | ||
3922 | Create a new base register for use within the loop and point it to | |
3923 | the start of MEM. Create a new memory reference that uses this | |
3924 | register. Store them in *LOOP_REG and *LOOP_MEM respectively. */ | |
3925 | ||
3926 | static void | |
d9f0ade0 SL |
3927 | riscv_adjust_block_mem (rtx mem, unsigned HOST_WIDE_INT length, |
3928 | rtx *loop_reg, rtx *loop_mem) | |
6ed01e6b AW |
3929 | { |
3930 | *loop_reg = copy_addr_to_reg (XEXP (mem, 0)); | |
3931 | ||
3932 | /* Although the new mem does not refer to a known location, | |
3933 | it does keep up to LENGTH bytes of alignment. */ | |
3934 | *loop_mem = change_address (mem, BLKmode, *loop_reg); | |
3935 | set_mem_align (*loop_mem, MIN (MEM_ALIGN (mem), length * BITS_PER_UNIT)); | |
3936 | } | |
3937 | ||
3938 | /* Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER | |
3939 | bytes at a time. LENGTH must be at least BYTES_PER_ITER. Assume that | |
3940 | the memory regions do not overlap. */ | |
3941 | ||
3942 | static void | |
d9f0ade0 SL |
3943 | riscv_block_move_loop (rtx dest, rtx src, unsigned HOST_WIDE_INT length, |
3944 | unsigned HOST_WIDE_INT bytes_per_iter) | |
6ed01e6b AW |
3945 | { |
3946 | rtx label, src_reg, dest_reg, final_src, test; | |
d9f0ade0 | 3947 | unsigned HOST_WIDE_INT leftover; |
6ed01e6b AW |
3948 | |
3949 | leftover = length % bytes_per_iter; | |
3950 | length -= leftover; | |
3951 | ||
3952 | /* Create registers and memory references for use within the loop. */ | |
3953 | riscv_adjust_block_mem (src, bytes_per_iter, &src_reg, &src); | |
3954 | riscv_adjust_block_mem (dest, bytes_per_iter, &dest_reg, &dest); | |
3955 | ||
3956 | /* Calculate the value that SRC_REG should have after the last iteration | |
3957 | of the loop. */ | |
3958 | final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length), | |
3959 | 0, 0, OPTAB_WIDEN); | |
3960 | ||
3961 | /* Emit the start of the loop. */ | |
3962 | label = gen_label_rtx (); | |
3963 | emit_label (label); | |
3964 | ||
3965 | /* Emit the loop body. */ | |
3966 | riscv_block_move_straight (dest, src, bytes_per_iter); | |
3967 | ||
3968 | /* Move on to the next block. */ | |
3969 | riscv_emit_move (src_reg, plus_constant (Pmode, src_reg, bytes_per_iter)); | |
3970 | riscv_emit_move (dest_reg, plus_constant (Pmode, dest_reg, bytes_per_iter)); | |
3971 | ||
3972 | /* Emit the loop condition. */ | |
3973 | test = gen_rtx_NE (VOIDmode, src_reg, final_src); | |
e1fcf14f | 3974 | emit_jump_insn (gen_cbranch4 (Pmode, test, src_reg, final_src, label)); |
6ed01e6b AW |
3975 | |
3976 | /* Mop up any left-over bytes. */ | |
3977 | if (leftover) | |
3978 | riscv_block_move_straight (dest, src, leftover); | |
3979 | else | |
3980 | emit_insn(gen_nop ()); | |
3981 | } | |
3982 | ||
76715c32 | 3983 | /* Expand a cpymemsi instruction, which copies LENGTH bytes from |
6ed01e6b AW |
3984 | memory reference SRC to memory reference DEST. */ |
3985 | ||
3986 | bool | |
3987 | riscv_expand_block_move (rtx dest, rtx src, rtx length) | |
3988 | { | |
3989 | if (CONST_INT_P (length)) | |
3990 | { | |
540dace2 | 3991 | unsigned HOST_WIDE_INT hwi_length = UINTVAL (length); |
d9f0ade0 | 3992 | unsigned HOST_WIDE_INT factor, align; |
6ed01e6b AW |
3993 | |
3994 | align = MIN (MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), BITS_PER_WORD); | |
3995 | factor = BITS_PER_WORD / align; | |
3996 | ||
3997 | if (optimize_function_for_size_p (cfun) | |
d9f0ade0 | 3998 | && hwi_length * factor * UNITS_PER_WORD > MOVE_RATIO (false)) |
6ed01e6b AW |
3999 | return false; |
4000 | ||
d9f0ade0 | 4001 | if (hwi_length <= (RISCV_MAX_MOVE_BYTES_STRAIGHT / factor)) |
6ed01e6b AW |
4002 | { |
4003 | riscv_block_move_straight (dest, src, INTVAL (length)); | |
4004 | return true; | |
4005 | } | |
4006 | else if (optimize && align >= BITS_PER_WORD) | |
4007 | { | |
4008 | unsigned min_iter_words | |
4009 | = RISCV_MAX_MOVE_BYTES_PER_LOOP_ITER / UNITS_PER_WORD; | |
4010 | unsigned iter_words = min_iter_words; | |
d9f0ade0 SL |
4011 | unsigned HOST_WIDE_INT bytes = hwi_length; |
4012 | unsigned HOST_WIDE_INT words = bytes / UNITS_PER_WORD; | |
6ed01e6b AW |
4013 | |
4014 | /* Lengthen the loop body if it shortens the tail. */ | |
4015 | for (unsigned i = min_iter_words; i < min_iter_words * 2 - 1; i++) | |
4016 | { | |
4017 | unsigned cur_cost = iter_words + words % iter_words; | |
4018 | unsigned new_cost = i + words % i; | |
4019 | if (new_cost <= cur_cost) | |
4020 | iter_words = i; | |
4021 | } | |
4022 | ||
4023 | riscv_block_move_loop (dest, src, bytes, iter_words * UNITS_PER_WORD); | |
4024 | return true; | |
4025 | } | |
4026 | } | |
4027 | return false; | |
4028 | } | |
4029 | ||
09cae750 PD |
4030 | /* Print symbolic operand OP, which is part of a HIGH or LO_SUM |
4031 | in context CONTEXT. HI_RELOC indicates a high-part reloc. */ | |
4032 | ||
4033 | static void | |
4034 | riscv_print_operand_reloc (FILE *file, rtx op, bool hi_reloc) | |
4035 | { | |
4036 | const char *reloc; | |
4037 | ||
4038 | switch (riscv_classify_symbolic_expression (op)) | |
4039 | { | |
4040 | case SYMBOL_ABSOLUTE: | |
4041 | reloc = hi_reloc ? "%hi" : "%lo"; | |
4042 | break; | |
4043 | ||
4044 | case SYMBOL_PCREL: | |
4045 | reloc = hi_reloc ? "%pcrel_hi" : "%pcrel_lo"; | |
4046 | break; | |
4047 | ||
4048 | case SYMBOL_TLS_LE: | |
4049 | reloc = hi_reloc ? "%tprel_hi" : "%tprel_lo"; | |
4050 | break; | |
4051 | ||
4052 | default: | |
a0ab54de JJ |
4053 | output_operand_lossage ("invalid use of '%%%c'", hi_reloc ? 'h' : 'R'); |
4054 | return; | |
09cae750 PD |
4055 | } |
4056 | ||
4057 | fprintf (file, "%s(", reloc); | |
4058 | output_addr_const (file, riscv_strip_unspec_address (op)); | |
4059 | fputc (')', file); | |
4060 | } | |
4061 | ||
4062 | /* Return true if the .AQ suffix should be added to an AMO to implement the | |
4063 | acquire portion of memory model MODEL. */ | |
4064 | ||
4065 | static bool | |
4066 | riscv_memmodel_needs_amo_acquire (enum memmodel model) | |
4067 | { | |
4068 | switch (model) | |
4069 | { | |
4070 | case MEMMODEL_ACQ_REL: | |
4071 | case MEMMODEL_SEQ_CST: | |
4072 | case MEMMODEL_SYNC_SEQ_CST: | |
4073 | case MEMMODEL_ACQUIRE: | |
4074 | case MEMMODEL_CONSUME: | |
4075 | case MEMMODEL_SYNC_ACQUIRE: | |
4076 | return true; | |
4077 | ||
4078 | case MEMMODEL_RELEASE: | |
4079 | case MEMMODEL_SYNC_RELEASE: | |
4080 | case MEMMODEL_RELAXED: | |
4081 | return false; | |
4082 | ||
4083 | default: | |
4084 | gcc_unreachable (); | |
4085 | } | |
4086 | } | |
4087 | ||
4088 | /* Return true if a FENCE should be emitted to before a memory access to | |
4089 | implement the release portion of memory model MODEL. */ | |
4090 | ||
4091 | static bool | |
4092 | riscv_memmodel_needs_release_fence (enum memmodel model) | |
4093 | { | |
4094 | switch (model) | |
4095 | { | |
4096 | case MEMMODEL_ACQ_REL: | |
4097 | case MEMMODEL_SEQ_CST: | |
4098 | case MEMMODEL_SYNC_SEQ_CST: | |
4099 | case MEMMODEL_RELEASE: | |
4100 | case MEMMODEL_SYNC_RELEASE: | |
4101 | return true; | |
4102 | ||
4103 | case MEMMODEL_ACQUIRE: | |
4104 | case MEMMODEL_CONSUME: | |
4105 | case MEMMODEL_SYNC_ACQUIRE: | |
4106 | case MEMMODEL_RELAXED: | |
4107 | return false; | |
4108 | ||
4109 | default: | |
4110 | gcc_unreachable (); | |
4111 | } | |
4112 | } | |
4113 | ||
4114 | /* Implement TARGET_PRINT_OPERAND. The RISCV-specific operand codes are: | |
4115 | ||
4116 | 'h' Print the high-part relocation associated with OP, after stripping | |
4117 | any outermost HIGH. | |
4118 | 'R' Print the low-part relocation associated with OP. | |
4119 | 'C' Print the integer branch condition for comparison OP. | |
4120 | 'A' Print the atomic operation suffix for memory model OP. | |
4121 | 'F' Print a FENCE if the memory model requires a release. | |
0791ac18 | 4122 | 'z' Print x0 if OP is zero, otherwise print OP normally. |
4e1e0d79 JW |
4123 | 'i' Print i if the operand is not a register. |
4124 | 'S' Print shift-index of single-bit mask OP. | |
380b8fd9 | 4125 | 'T' Print shift-index of inverted single-bit mask OP. |
473d7aad | 4126 | '~' Print w if TARGET_64BIT is true; otherwise not print anything. |
380b8fd9 AP |
4127 | |
4128 | Note please keep this list and the list in riscv.md in sync. */ | |
09cae750 PD |
4129 | |
4130 | static void | |
4131 | riscv_print_operand (FILE *file, rtx op, int letter) | |
4132 | { | |
473d7aad AP |
4133 | /* `~` does not take an operand so op will be null |
4134 | Check for before accessing op. | |
4135 | */ | |
4136 | if (letter == '~') | |
4137 | { | |
4138 | if (TARGET_64BIT) | |
4139 | fputc('w', file); | |
4140 | return; | |
4141 | } | |
b8506a8a | 4142 | machine_mode mode = GET_MODE (op); |
09cae750 PD |
4143 | enum rtx_code code = GET_CODE (op); |
4144 | ||
4145 | switch (letter) | |
4146 | { | |
f56d48b2 | 4147 | case 'm': { |
f556cd8b | 4148 | if (riscv_v_ext_vector_mode_p (mode)) |
f56d48b2 | 4149 | { |
f556cd8b JZZ |
4150 | /* Calculate lmul according to mode and print the value. */ |
4151 | poly_int64 size = GET_MODE_SIZE (mode); | |
4152 | unsigned int lmul; | |
4153 | if (known_lt (size, BYTES_PER_RISCV_VECTOR)) | |
4154 | lmul = 1; | |
4155 | else | |
4156 | lmul = exact_div (size, BYTES_PER_RISCV_VECTOR).to_constant (); | |
4157 | asm_fprintf (file, "%d", lmul); | |
4158 | } | |
4159 | else if (code == CONST_INT) | |
4160 | { | |
4161 | /* The value in the operand is the unsigned int value | |
4162 | converted from (enum machine_mode). | |
4163 | This RTX is generated as follows: | |
4164 | ||
4165 | machine_mode mode = XXXmode; | |
4166 | operand = gen_int_mode ((unsigned int)mode, Pmode); | |
4167 | ||
4168 | So we convert it back into machine_mode and then calculate | |
4169 | the LMUL according to GET_MODE_SIZE. */ | |
4170 | ||
4171 | machine_mode rvv_mode = (machine_mode) UINTVAL (op); | |
4172 | /* For rvv mask modes, we can not calculate LMUL simpily according | |
4173 | to BYTES_PER_RISCV_VECTOR. When rvv_mode = VNx4BImode. | |
4174 | Set SEW = 8, LMUL = 1 by default if TARGET_MIN_VLEN == 32. | |
4175 | Set SEW = 8, LMUL = 1 / 2 by default if TARGET_MIN_VLEN > 32. */ | |
4176 | bool bool_p = GET_MODE_CLASS (rvv_mode) == MODE_VECTOR_BOOL; | |
4177 | poly_int64 m1_size = BYTES_PER_RISCV_VECTOR; | |
4178 | poly_int64 rvv_size | |
4179 | = bool_p ? GET_MODE_NUNITS (rvv_mode) : GET_MODE_SIZE (rvv_mode); | |
4180 | bool fractional_p = known_lt (rvv_size, BYTES_PER_RISCV_VECTOR); | |
4181 | unsigned int factor | |
4182 | = fractional_p ? exact_div (m1_size, rvv_size).to_constant () | |
4183 | : exact_div (rvv_size, m1_size).to_constant (); | |
f56d48b2 JZZ |
4184 | asm_fprintf (file, "%s%d", fractional_p ? "mf" : "m", factor); |
4185 | } | |
4186 | else | |
4187 | output_operand_lossage ("invalid vector constant"); | |
4188 | break; | |
4189 | } | |
4190 | case 'p': { | |
f556cd8b JZZ |
4191 | if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) |
4192 | { | |
4193 | /* Print for RVV mask operand. | |
4194 | If op is reg, print ",v0.t". | |
4195 | Otherwise, don't print anything. */ | |
4196 | if (code == REG) | |
4197 | fprintf (file, ",%s.t", reg_names[REGNO (op)]); | |
4198 | } | |
4199 | else if (code == CONST_INT) | |
f56d48b2 JZZ |
4200 | { |
4201 | /* Tail && Mask policy. */ | |
4202 | bool agnostic_p = UINTVAL (op) & 0x1; | |
4203 | asm_fprintf (file, "%s", agnostic_p ? "a" : "u"); | |
4204 | } | |
4205 | else | |
4206 | output_operand_lossage ("invalid vector constant"); | |
4207 | break; | |
4208 | } | |
09cae750 PD |
4209 | case 'h': |
4210 | if (code == HIGH) | |
4211 | op = XEXP (op, 0); | |
4212 | riscv_print_operand_reloc (file, op, true); | |
4213 | break; | |
4214 | ||
4215 | case 'R': | |
4216 | riscv_print_operand_reloc (file, op, false); | |
4217 | break; | |
4218 | ||
4219 | case 'C': | |
4220 | /* The RTL names match the instruction names. */ | |
4221 | fputs (GET_RTX_NAME (code), file); | |
4222 | break; | |
4223 | ||
4224 | case 'A': | |
4225 | if (riscv_memmodel_needs_amo_acquire ((enum memmodel) INTVAL (op))) | |
4226 | fputs (".aq", file); | |
4227 | break; | |
4228 | ||
4229 | case 'F': | |
4230 | if (riscv_memmodel_needs_release_fence ((enum memmodel) INTVAL (op))) | |
e05a9f8e | 4231 | fputs ("fence iorw,ow; ", file); |
09cae750 PD |
4232 | break; |
4233 | ||
0791ac18 MC |
4234 | case 'i': |
4235 | if (code != REG) | |
4236 | fputs ("i", file); | |
4237 | break; | |
4238 | ||
4e1e0d79 JW |
4239 | case 'S': |
4240 | { | |
4241 | rtx newop = GEN_INT (ctz_hwi (INTVAL (op))); | |
4242 | output_addr_const (file, newop); | |
4243 | break; | |
4244 | } | |
4245 | case 'T': | |
4246 | { | |
4247 | rtx newop = GEN_INT (ctz_hwi (~INTVAL (op))); | |
4248 | output_addr_const (file, newop); | |
4249 | break; | |
4250 | } | |
09cae750 PD |
4251 | default: |
4252 | switch (code) | |
4253 | { | |
4254 | case REG: | |
4255 | if (letter && letter != 'z') | |
4256 | output_operand_lossage ("invalid use of '%%%c'", letter); | |
4257 | fprintf (file, "%s", reg_names[REGNO (op)]); | |
4258 | break; | |
4259 | ||
4260 | case MEM: | |
4261 | if (letter && letter != 'z') | |
4262 | output_operand_lossage ("invalid use of '%%%c'", letter); | |
4263 | else | |
4264 | output_address (mode, XEXP (op, 0)); | |
4265 | break; | |
4266 | ||
4267 | default: | |
4268 | if (letter == 'z' && op == CONST0_RTX (GET_MODE (op))) | |
4269 | fputs (reg_names[GP_REG_FIRST], file); | |
4270 | else if (letter && letter != 'z') | |
4271 | output_operand_lossage ("invalid use of '%%%c'", letter); | |
4272 | else | |
4273 | output_addr_const (file, riscv_strip_unspec_address (op)); | |
4274 | break; | |
4275 | } | |
4276 | } | |
4277 | } | |
4278 | ||
473d7aad AP |
4279 | /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P */ |
4280 | static bool | |
4281 | riscv_print_operand_punct_valid_p (unsigned char code) | |
4282 | { | |
4283 | return (code == '~'); | |
4284 | } | |
4285 | ||
09cae750 PD |
4286 | /* Implement TARGET_PRINT_OPERAND_ADDRESS. */ |
4287 | ||
4288 | static void | |
4289 | riscv_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED, rtx x) | |
4290 | { | |
4291 | struct riscv_address_info addr; | |
4292 | ||
4293 | if (riscv_classify_address (&addr, x, word_mode, true)) | |
4294 | switch (addr.type) | |
4295 | { | |
4296 | case ADDRESS_REG: | |
4297 | riscv_print_operand (file, addr.offset, 0); | |
4298 | fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]); | |
4299 | return; | |
4300 | ||
4301 | case ADDRESS_LO_SUM: | |
4302 | riscv_print_operand_reloc (file, addr.offset, false); | |
4303 | fprintf (file, "(%s)", reg_names[REGNO (addr.reg)]); | |
4304 | return; | |
4305 | ||
4306 | case ADDRESS_CONST_INT: | |
4307 | output_addr_const (file, x); | |
4308 | fprintf (file, "(%s)", reg_names[GP_REG_FIRST]); | |
4309 | return; | |
4310 | ||
4311 | case ADDRESS_SYMBOLIC: | |
4312 | output_addr_const (file, riscv_strip_unspec_address (x)); | |
4313 | return; | |
4314 | } | |
4315 | gcc_unreachable (); | |
4316 | } | |
4317 | ||
4318 | static bool | |
4319 | riscv_size_ok_for_small_data_p (int size) | |
4320 | { | |
4321 | return g_switch_value && IN_RANGE (size, 1, g_switch_value); | |
4322 | } | |
4323 | ||
4324 | /* Return true if EXP should be placed in the small data section. */ | |
4325 | ||
4326 | static bool | |
4327 | riscv_in_small_data_p (const_tree x) | |
4328 | { | |
4329 | if (TREE_CODE (x) == STRING_CST || TREE_CODE (x) == FUNCTION_DECL) | |
4330 | return false; | |
4331 | ||
4332 | if (TREE_CODE (x) == VAR_DECL && DECL_SECTION_NAME (x)) | |
4333 | { | |
4334 | const char *sec = DECL_SECTION_NAME (x); | |
4335 | return strcmp (sec, ".sdata") == 0 || strcmp (sec, ".sbss") == 0; | |
4336 | } | |
4337 | ||
4338 | return riscv_size_ok_for_small_data_p (int_size_in_bytes (TREE_TYPE (x))); | |
4339 | } | |
4340 | ||
6cb0725c AW |
4341 | /* Switch to the appropriate section for output of DECL. */ |
4342 | ||
4343 | static section * | |
4344 | riscv_select_section (tree decl, int reloc, | |
4345 | unsigned HOST_WIDE_INT align) | |
4346 | { | |
4347 | switch (categorize_decl_for_section (decl, reloc)) | |
4348 | { | |
4349 | case SECCAT_SRODATA: | |
4350 | return get_named_section (decl, ".srodata", reloc); | |
4351 | ||
4352 | default: | |
4353 | return default_elf_select_section (decl, reloc, align); | |
4354 | } | |
4355 | } | |
4356 | ||
adce62f5 KP |
4357 | /* Switch to the appropriate section for output of DECL. */ |
4358 | ||
4359 | static void | |
4360 | riscv_unique_section (tree decl, int reloc) | |
4361 | { | |
4362 | const char *prefix = NULL; | |
4363 | bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP; | |
4364 | ||
4365 | switch (categorize_decl_for_section (decl, reloc)) | |
4366 | { | |
4367 | case SECCAT_SRODATA: | |
4368 | prefix = one_only ? ".sr" : ".srodata"; | |
4369 | break; | |
4370 | ||
4371 | default: | |
4372 | break; | |
4373 | } | |
4374 | if (prefix) | |
4375 | { | |
4376 | const char *name, *linkonce; | |
4377 | char *string; | |
4378 | ||
4379 | name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); | |
4380 | name = targetm.strip_name_encoding (name); | |
4381 | ||
4382 | /* If we're using one_only, then there needs to be a .gnu.linkonce | |
4383 | prefix to the section name. */ | |
4384 | linkonce = one_only ? ".gnu.linkonce" : ""; | |
4385 | ||
4386 | string = ACONCAT ((linkonce, prefix, ".", name, NULL)); | |
4387 | ||
4388 | set_decl_section_name (decl, string); | |
4389 | return; | |
4390 | } | |
4391 | default_unique_section (decl, reloc); | |
4392 | } | |
4393 | ||
09cae750 PD |
4394 | /* Return a section for X, handling small data. */ |
4395 | ||
4396 | static section * | |
b8506a8a | 4397 | riscv_elf_select_rtx_section (machine_mode mode, rtx x, |
09cae750 PD |
4398 | unsigned HOST_WIDE_INT align) |
4399 | { | |
4400 | section *s = default_elf_select_rtx_section (mode, x, align); | |
4401 | ||
3496ca4e | 4402 | if (riscv_size_ok_for_small_data_p (GET_MODE_SIZE (mode).to_constant ())) |
09cae750 | 4403 | { |
c0129e2d | 4404 | if (startswith (s->named.name, ".rodata.cst")) |
09cae750 PD |
4405 | { |
4406 | /* Rename .rodata.cst* to .srodata.cst*. */ | |
4407 | char *name = (char *) alloca (strlen (s->named.name) + 2); | |
4408 | sprintf (name, ".s%s", s->named.name + 1); | |
4409 | return get_section (name, s->named.common.flags, NULL); | |
4410 | } | |
4411 | ||
4412 | if (s == data_section) | |
4413 | return sdata_section; | |
4414 | } | |
4415 | ||
4416 | return s; | |
4417 | } | |
4418 | ||
4419 | /* Make the last instruction frame-related and note that it performs | |
4420 | the operation described by FRAME_PATTERN. */ | |
4421 | ||
4422 | static void | |
4423 | riscv_set_frame_expr (rtx frame_pattern) | |
4424 | { | |
4425 | rtx insn; | |
4426 | ||
4427 | insn = get_last_insn (); | |
4428 | RTX_FRAME_RELATED_P (insn) = 1; | |
4429 | REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
4430 | frame_pattern, | |
4431 | REG_NOTES (insn)); | |
4432 | } | |
4433 | ||
4434 | /* Return a frame-related rtx that stores REG at MEM. | |
4435 | REG must be a single register. */ | |
4436 | ||
4437 | static rtx | |
4438 | riscv_frame_set (rtx mem, rtx reg) | |
4439 | { | |
4440 | rtx set = gen_rtx_SET (mem, reg); | |
4441 | RTX_FRAME_RELATED_P (set) = 1; | |
4442 | return set; | |
4443 | } | |
4444 | ||
4445 | /* Return true if the current function must save register REGNO. */ | |
4446 | ||
4447 | static bool | |
4448 | riscv_save_reg_p (unsigned int regno) | |
4449 | { | |
a365fa06 | 4450 | bool call_saved = !global_regs[regno] && !call_used_or_fixed_reg_p (regno); |
09cae750 PD |
4451 | bool might_clobber = crtl->saves_all_registers |
4452 | || df_regs_ever_live_p (regno); | |
4453 | ||
4454 | if (call_saved && might_clobber) | |
4455 | return true; | |
4456 | ||
4457 | if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) | |
4458 | return true; | |
4459 | ||
4460 | if (regno == RETURN_ADDR_REGNUM && crtl->calls_eh_return) | |
4461 | return true; | |
4462 | ||
d0ebdd9f JW |
4463 | /* If this is an interrupt handler, then must save extra registers. */ |
4464 | if (cfun->machine->interrupt_handler_p) | |
4465 | { | |
4466 | /* zero register is always zero. */ | |
4467 | if (regno == GP_REG_FIRST) | |
4468 | return false; | |
4469 | ||
4470 | /* The function will return the stack pointer to its original value. */ | |
4471 | if (regno == STACK_POINTER_REGNUM) | |
4472 | return false; | |
4473 | ||
4474 | /* By convention, we assume that gp and tp are safe. */ | |
4475 | if (regno == GP_REGNUM || regno == THREAD_POINTER_REGNUM) | |
4476 | return false; | |
4477 | ||
4478 | /* We must save every register used in this function. If this is not a | |
4479 | leaf function, then we must save all temporary registers. */ | |
4480 | if (df_regs_ever_live_p (regno) | |
a365fa06 | 4481 | || (!crtl->is_leaf && call_used_or_fixed_reg_p (regno))) |
d0ebdd9f JW |
4482 | return true; |
4483 | } | |
4484 | ||
09cae750 PD |
4485 | return false; |
4486 | } | |
4487 | ||
4488 | /* Determine whether to call GPR save/restore routines. */ | |
4489 | static bool | |
4490 | riscv_use_save_libcall (const struct riscv_frame_info *frame) | |
4491 | { | |
d0ebdd9f JW |
4492 | if (!TARGET_SAVE_RESTORE || crtl->calls_eh_return || frame_pointer_needed |
4493 | || cfun->machine->interrupt_handler_p) | |
09cae750 PD |
4494 | return false; |
4495 | ||
4496 | return frame->save_libcall_adjustment != 0; | |
4497 | } | |
4498 | ||
4499 | /* Determine which GPR save/restore routine to call. */ | |
4500 | ||
4501 | static unsigned | |
4502 | riscv_save_libcall_count (unsigned mask) | |
4503 | { | |
4504 | for (unsigned n = GP_REG_LAST; n > GP_REG_FIRST; n--) | |
4505 | if (BITSET_P (mask, n)) | |
4506 | return CALLEE_SAVED_REG_NUMBER (n) + 1; | |
4507 | abort (); | |
4508 | } | |
4509 | ||
4510 | /* Populate the current function's riscv_frame_info structure. | |
4511 | ||
4512 | RISC-V stack frames grown downward. High addresses are at the top. | |
4513 | ||
4514 | +-------------------------------+ | |
4515 | | | | |
4516 | | incoming stack arguments | | |
4517 | | | | |
4518 | +-------------------------------+ <-- incoming stack pointer | |
4519 | | | | |
4520 | | callee-allocated save area | | |
4521 | | for arguments that are | | |
4522 | | split between registers and | | |
4523 | | the stack | | |
4524 | | | | |
4525 | +-------------------------------+ <-- arg_pointer_rtx | |
4526 | | | | |
4527 | | callee-allocated save area | | |
4528 | | for register varargs | | |
4529 | | | | |
4530 | +-------------------------------+ <-- hard_frame_pointer_rtx; | |
4531 | | | stack_pointer_rtx + gp_sp_offset | |
4532 | | GPR save area | + UNITS_PER_WORD | |
4533 | | | | |
4534 | +-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset | |
4535 | | | + UNITS_PER_HWVALUE | |
4536 | | FPR save area | | |
4537 | | | | |
4538 | +-------------------------------+ <-- frame_pointer_rtx (virtual) | |
4539 | | | | |
4540 | | local variables | | |
4541 | | | | |
4542 | P +-------------------------------+ | |
4543 | | | | |
4544 | | outgoing stack arguments | | |
4545 | | | | |
4546 | +-------------------------------+ <-- stack_pointer_rtx | |
4547 | ||
4548 | Dynamic stack allocations such as alloca insert data at point P. | |
4549 | They decrease stack_pointer_rtx but leave frame_pointer_rtx and | |
4550 | hard_frame_pointer_rtx unchanged. */ | |
4551 | ||
d0ebdd9f JW |
4552 | static HOST_WIDE_INT riscv_first_stack_step (struct riscv_frame_info *frame); |
4553 | ||
3496ca4e | 4554 | /* Handle stack align for poly_int. */ |
4555 | static poly_int64 | |
4556 | riscv_stack_align (poly_int64 value) | |
4557 | { | |
4558 | return aligned_upper_bound (value, PREFERRED_STACK_BOUNDARY / 8); | |
4559 | } | |
4560 | ||
4561 | static HOST_WIDE_INT | |
4562 | riscv_stack_align (HOST_WIDE_INT value) | |
4563 | { | |
4564 | return RISCV_STACK_ALIGN (value); | |
4565 | } | |
4566 | ||
09cae750 PD |
4567 | static void |
4568 | riscv_compute_frame_info (void) | |
4569 | { | |
4570 | struct riscv_frame_info *frame; | |
3496ca4e | 4571 | poly_int64 offset; |
207de839 | 4572 | bool interrupt_save_prologue_temp = false; |
09cae750 PD |
4573 | unsigned int regno, i, num_x_saved = 0, num_f_saved = 0; |
4574 | ||
4575 | frame = &cfun->machine->frame; | |
d0ebdd9f JW |
4576 | |
4577 | /* In an interrupt function, if we have a large frame, then we need to | |
207de839 | 4578 | save/restore t0. We check for this before clearing the frame struct. */ |
d0ebdd9f JW |
4579 | if (cfun->machine->interrupt_handler_p) |
4580 | { | |
4581 | HOST_WIDE_INT step1 = riscv_first_stack_step (frame); | |
3496ca4e | 4582 | if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1))) |
207de839 | 4583 | interrupt_save_prologue_temp = true; |
d0ebdd9f JW |
4584 | } |
4585 | ||
7b9b6969 | 4586 | frame->reset(); |
09cae750 | 4587 | |
8cad5b14 KC |
4588 | if (!cfun->machine->naked_p) |
4589 | { | |
4590 | /* Find out which GPRs we need to save. */ | |
4591 | for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) | |
d0ebdd9f | 4592 | if (riscv_save_reg_p (regno) |
207de839 MC |
4593 | || (interrupt_save_prologue_temp |
4594 | && (regno == RISCV_PROLOGUE_TEMP_REGNUM))) | |
8cad5b14 KC |
4595 | frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++; |
4596 | ||
4597 | /* If this function calls eh_return, we must also save and restore the | |
4598 | EH data registers. */ | |
4599 | if (crtl->calls_eh_return) | |
4600 | for (i = 0; (regno = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++) | |
4601 | frame->mask |= 1 << (regno - GP_REG_FIRST), num_x_saved++; | |
4602 | ||
4603 | /* Find out which FPRs we need to save. This loop must iterate over | |
4604 | the same space as its companion in riscv_for_each_saved_reg. */ | |
4605 | if (TARGET_HARD_FLOAT) | |
4606 | for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) | |
4607 | if (riscv_save_reg_p (regno)) | |
4608 | frame->fmask |= 1 << (regno - FP_REG_FIRST), num_f_saved++; | |
4609 | } | |
09cae750 PD |
4610 | |
4611 | /* At the bottom of the frame are any outgoing stack arguments. */ | |
3496ca4e | 4612 | offset = riscv_stack_align (crtl->outgoing_args_size); |
09cae750 | 4613 | /* Next are local stack variables. */ |
3496ca4e | 4614 | offset += riscv_stack_align (get_frame_size ()); |
09cae750 PD |
4615 | /* The virtual frame pointer points above the local variables. */ |
4616 | frame->frame_pointer_offset = offset; | |
4617 | /* Next are the callee-saved FPRs. */ | |
4618 | if (frame->fmask) | |
3496ca4e | 4619 | offset += riscv_stack_align (num_f_saved * UNITS_PER_FP_REG); |
09cae750 PD |
4620 | frame->fp_sp_offset = offset - UNITS_PER_FP_REG; |
4621 | /* Next are the callee-saved GPRs. */ | |
4622 | if (frame->mask) | |
4623 | { | |
3496ca4e | 4624 | unsigned x_save_size = riscv_stack_align (num_x_saved * UNITS_PER_WORD); |
09cae750 PD |
4625 | unsigned num_save_restore = 1 + riscv_save_libcall_count (frame->mask); |
4626 | ||
4627 | /* Only use save/restore routines if they don't alter the stack size. */ | |
3496ca4e | 4628 | if (riscv_stack_align (num_save_restore * UNITS_PER_WORD) == x_save_size) |
09baee1a KC |
4629 | { |
4630 | /* Libcall saves/restores 3 registers at once, so we need to | |
4631 | allocate 12 bytes for callee-saved register. */ | |
4632 | if (TARGET_RVE) | |
4633 | x_save_size = 3 * UNITS_PER_WORD; | |
4634 | ||
4635 | frame->save_libcall_adjustment = x_save_size; | |
4636 | } | |
09cae750 PD |
4637 | |
4638 | offset += x_save_size; | |
4639 | } | |
4640 | frame->gp_sp_offset = offset - UNITS_PER_WORD; | |
4641 | /* The hard frame pointer points above the callee-saved GPRs. */ | |
4642 | frame->hard_frame_pointer_offset = offset; | |
4643 | /* Above the hard frame pointer is the callee-allocated varags save area. */ | |
3496ca4e | 4644 | offset += riscv_stack_align (cfun->machine->varargs_size); |
09cae750 | 4645 | /* Next is the callee-allocated area for pretend stack arguments. */ |
3496ca4e | 4646 | offset += riscv_stack_align (crtl->args.pretend_args_size); |
035fc2ad JW |
4647 | /* Arg pointer must be below pretend args, but must be above alignment |
4648 | padding. */ | |
4649 | frame->arg_pointer_offset = offset - crtl->args.pretend_args_size; | |
09cae750 PD |
4650 | frame->total_size = offset; |
4651 | /* Next points the incoming stack pointer and any incoming arguments. */ | |
4652 | ||
4653 | /* Only use save/restore routines when the GPRs are atop the frame. */ | |
3496ca4e | 4654 | if (known_ne (frame->hard_frame_pointer_offset, frame->total_size)) |
09cae750 PD |
4655 | frame->save_libcall_adjustment = 0; |
4656 | } | |
4657 | ||
4658 | /* Make sure that we're not trying to eliminate to the wrong hard frame | |
4659 | pointer. */ | |
4660 | ||
4661 | static bool | |
4662 | riscv_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) | |
4663 | { | |
4664 | return (to == HARD_FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM); | |
4665 | } | |
4666 | ||
4667 | /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame pointer | |
4668 | or argument pointer. TO is either the stack pointer or hard frame | |
4669 | pointer. */ | |
4670 | ||
3496ca4e | 4671 | poly_int64 |
09cae750 PD |
4672 | riscv_initial_elimination_offset (int from, int to) |
4673 | { | |
3496ca4e | 4674 | poly_int64 src, dest; |
09cae750 PD |
4675 | |
4676 | riscv_compute_frame_info (); | |
4677 | ||
4678 | if (to == HARD_FRAME_POINTER_REGNUM) | |
4679 | dest = cfun->machine->frame.hard_frame_pointer_offset; | |
4680 | else if (to == STACK_POINTER_REGNUM) | |
4681 | dest = 0; /* The stack pointer is the base of all offsets, hence 0. */ | |
4682 | else | |
4683 | gcc_unreachable (); | |
4684 | ||
4685 | if (from == FRAME_POINTER_REGNUM) | |
4686 | src = cfun->machine->frame.frame_pointer_offset; | |
4687 | else if (from == ARG_POINTER_REGNUM) | |
4688 | src = cfun->machine->frame.arg_pointer_offset; | |
4689 | else | |
4690 | gcc_unreachable (); | |
4691 | ||
4692 | return src - dest; | |
4693 | } | |
4694 | ||
4695 | /* Implement RETURN_ADDR_RTX. We do not support moving back to a | |
4696 | previous frame. */ | |
4697 | ||
4698 | rtx | |
4699 | riscv_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) | |
4700 | { | |
4701 | if (count != 0) | |
4702 | return const0_rtx; | |
4703 | ||
4704 | return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNUM); | |
4705 | } | |
4706 | ||
4707 | /* Emit code to change the current function's return address to | |
4708 | ADDRESS. SCRATCH is available as a scratch register, if needed. | |
4709 | ADDRESS and SCRATCH are both word-mode GPRs. */ | |
4710 | ||
4711 | void | |
4712 | riscv_set_return_address (rtx address, rtx scratch) | |
4713 | { | |
4714 | rtx slot_address; | |
4715 | ||
4716 | gcc_assert (BITSET_P (cfun->machine->frame.mask, RETURN_ADDR_REGNUM)); | |
4717 | slot_address = riscv_add_offset (scratch, stack_pointer_rtx, | |
3496ca4e | 4718 | cfun->machine->frame.gp_sp_offset.to_constant()); |
09cae750 PD |
4719 | riscv_emit_move (gen_frame_mem (GET_MODE (address), slot_address), address); |
4720 | } | |
4721 | ||
4722 | /* A function to save or store a register. The first argument is the | |
4723 | register and the second is the stack slot. */ | |
4724 | typedef void (*riscv_save_restore_fn) (rtx, rtx); | |
4725 | ||
4726 | /* Use FN to save or restore register REGNO. MODE is the register's | |
4727 | mode and OFFSET is the offset of its save slot from the current | |
4728 | stack pointer. */ | |
4729 | ||
4730 | static void | |
b8506a8a | 4731 | riscv_save_restore_reg (machine_mode mode, int regno, |
09cae750 PD |
4732 | HOST_WIDE_INT offset, riscv_save_restore_fn fn) |
4733 | { | |
4734 | rtx mem; | |
4735 | ||
4736 | mem = gen_frame_mem (mode, plus_constant (Pmode, stack_pointer_rtx, offset)); | |
4737 | fn (gen_rtx_REG (mode, regno), mem); | |
4738 | } | |
4739 | ||
4740 | /* Call FN for each register that is saved by the current function. | |
4741 | SP_OFFSET is the offset of the current stack pointer from the start | |
4742 | of the frame. */ | |
4743 | ||
4744 | static void | |
3496ca4e | 4745 | riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn, |
fd1e52dc | 4746 | bool epilogue, bool maybe_eh_return) |
09cae750 PD |
4747 | { |
4748 | HOST_WIDE_INT offset; | |
4749 | ||
4750 | /* Save the link register and s-registers. */ | |
3496ca4e | 4751 | offset = (cfun->machine->frame.gp_sp_offset - sp_offset).to_constant (); |
fd1e52dc | 4752 | for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) |
09cae750 PD |
4753 | if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST)) |
4754 | { | |
fd1e52dc JW |
4755 | bool handle_reg = TRUE; |
4756 | ||
4757 | /* If this is a normal return in a function that calls the eh_return | |
4758 | builtin, then do not restore the eh return data registers as that | |
4759 | would clobber the return value. But we do still need to save them | |
4760 | in the prologue, and restore them for an exception return, so we | |
4761 | need special handling here. */ | |
4762 | if (epilogue && !maybe_eh_return && crtl->calls_eh_return) | |
4763 | { | |
4764 | unsigned int i, regnum; | |
4765 | ||
4766 | for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; | |
4767 | i++) | |
4768 | if (regno == regnum) | |
4769 | { | |
4770 | handle_reg = FALSE; | |
4771 | break; | |
4772 | } | |
4773 | } | |
4774 | ||
4775 | if (handle_reg) | |
4776 | riscv_save_restore_reg (word_mode, regno, offset, fn); | |
09cae750 PD |
4777 | offset -= UNITS_PER_WORD; |
4778 | } | |
4779 | ||
4780 | /* This loop must iterate over the same space as its companion in | |
4781 | riscv_compute_frame_info. */ | |
3496ca4e | 4782 | offset = (cfun->machine->frame.fp_sp_offset - sp_offset).to_constant (); |
fd1e52dc | 4783 | for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) |
09cae750 PD |
4784 | if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST)) |
4785 | { | |
b8506a8a | 4786 | machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode; |
09cae750 PD |
4787 | |
4788 | riscv_save_restore_reg (mode, regno, offset, fn); | |
3496ca4e | 4789 | offset -= GET_MODE_SIZE (mode).to_constant (); |
09cae750 PD |
4790 | } |
4791 | } | |
4792 | ||
4793 | /* Save register REG to MEM. Make the instruction frame-related. */ | |
4794 | ||
4795 | static void | |
4796 | riscv_save_reg (rtx reg, rtx mem) | |
4797 | { | |
4798 | riscv_emit_move (mem, reg); | |
4799 | riscv_set_frame_expr (riscv_frame_set (mem, reg)); | |
4800 | } | |
4801 | ||
4802 | /* Restore register REG from MEM. */ | |
4803 | ||
4804 | static void | |
4805 | riscv_restore_reg (rtx reg, rtx mem) | |
4806 | { | |
4807 | rtx insn = riscv_emit_move (reg, mem); | |
4808 | rtx dwarf = NULL_RTX; | |
4809 | dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); | |
09cae750 | 4810 | |
b579523b JW |
4811 | if (epilogue_cfa_sp_offset && REGNO (reg) == HARD_FRAME_POINTER_REGNUM) |
4812 | { | |
4813 | rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, | |
4814 | GEN_INT (epilogue_cfa_sp_offset)); | |
4815 | dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); | |
4816 | } | |
4817 | ||
4818 | REG_NOTES (insn) = dwarf; | |
09cae750 PD |
4819 | RTX_FRAME_RELATED_P (insn) = 1; |
4820 | } | |
4821 | ||
09cae750 PD |
4822 | /* For stack frames that can't be allocated with a single ADDI instruction, |
4823 | compute the best value to initially allocate. It must at a minimum | |
10789329 JW |
4824 | allocate enough space to spill the callee-saved registers. If TARGET_RVC, |
4825 | try to pick a value that will allow compression of the register saves | |
4826 | without adding extra instructions. */ | |
09cae750 PD |
4827 | |
4828 | static HOST_WIDE_INT | |
4829 | riscv_first_stack_step (struct riscv_frame_info *frame) | |
4830 | { | |
3496ca4e | 4831 | if (SMALL_OPERAND (frame->total_size.to_constant())) |
4832 | return frame->total_size.to_constant(); | |
09cae750 | 4833 | |
9b922d6a | 4834 | HOST_WIDE_INT min_first_step = |
3496ca4e | 4835 | RISCV_STACK_ALIGN ((frame->total_size - frame->fp_sp_offset).to_constant()); |
c0d3d1b6 | 4836 | HOST_WIDE_INT max_first_step = IMM_REACH / 2 - PREFERRED_STACK_BOUNDARY / 8; |
3496ca4e | 4837 | HOST_WIDE_INT min_second_step = frame->total_size.to_constant() - max_first_step; |
10789329 JW |
4838 | gcc_assert (min_first_step <= max_first_step); |
4839 | ||
09cae750 PD |
4840 | /* As an optimization, use the least-significant bits of the total frame |
4841 | size, so that the second adjustment step is just LUI + ADD. */ | |
10789329 | 4842 | if (!SMALL_OPERAND (min_second_step) |
3496ca4e | 4843 | && frame->total_size.to_constant() % IMM_REACH < IMM_REACH / 2 |
4844 | && frame->total_size.to_constant() % IMM_REACH >= min_first_step) | |
4845 | return frame->total_size.to_constant() % IMM_REACH; | |
09cae750 | 4846 | |
10789329 JW |
4847 | if (TARGET_RVC) |
4848 | { | |
4849 | /* If we need two subtracts, and one is small enough to allow compressed | |
4850 | loads and stores, then put that one first. */ | |
4851 | if (IN_RANGE (min_second_step, 0, | |
4852 | (TARGET_64BIT ? SDSP_REACH : SWSP_REACH))) | |
4853 | return MAX (min_second_step, min_first_step); | |
4854 | ||
4855 | /* If we need LUI + ADDI + ADD for the second adjustment step, then start | |
4856 | with the minimum first step, so that we can get compressed loads and | |
4857 | stores. */ | |
4858 | else if (!SMALL_OPERAND (min_second_step)) | |
4859 | return min_first_step; | |
4860 | } | |
4861 | ||
09cae750 PD |
4862 | return max_first_step; |
4863 | } | |
4864 | ||
4865 | static rtx | |
4866 | riscv_adjust_libcall_cfi_prologue () | |
4867 | { | |
4868 | rtx dwarf = NULL_RTX; | |
4869 | rtx adjust_sp_rtx, reg, mem, insn; | |
4870 | int saved_size = cfun->machine->frame.save_libcall_adjustment; | |
4871 | int offset; | |
4872 | ||
f3abed16 | 4873 | for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) |
09cae750 PD |
4874 | if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST)) |
4875 | { | |
4876 | /* The save order is ra, s0, s1, s2 to s11. */ | |
4877 | if (regno == RETURN_ADDR_REGNUM) | |
4878 | offset = saved_size - UNITS_PER_WORD; | |
4879 | else if (regno == S0_REGNUM) | |
4880 | offset = saved_size - UNITS_PER_WORD * 2; | |
4881 | else if (regno == S1_REGNUM) | |
4882 | offset = saved_size - UNITS_PER_WORD * 3; | |
4883 | else | |
4884 | offset = saved_size - ((regno - S2_REGNUM + 4) * UNITS_PER_WORD); | |
4885 | ||
4886 | reg = gen_rtx_REG (SImode, regno); | |
4887 | mem = gen_frame_mem (SImode, plus_constant (Pmode, | |
4888 | stack_pointer_rtx, | |
4889 | offset)); | |
4890 | ||
4891 | insn = gen_rtx_SET (mem, reg); | |
4892 | dwarf = alloc_reg_note (REG_CFA_OFFSET, insn, dwarf); | |
4893 | } | |
4894 | ||
4895 | /* Debug info for adjust sp. */ | |
4896 | adjust_sp_rtx = gen_add3_insn (stack_pointer_rtx, | |
4897 | stack_pointer_rtx, GEN_INT (-saved_size)); | |
4898 | dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, | |
4899 | dwarf); | |
4900 | return dwarf; | |
4901 | } | |
4902 | ||
4903 | static void | |
4904 | riscv_emit_stack_tie (void) | |
4905 | { | |
4906 | if (Pmode == SImode) | |
4907 | emit_insn (gen_stack_tiesi (stack_pointer_rtx, hard_frame_pointer_rtx)); | |
4908 | else | |
4909 | emit_insn (gen_stack_tiedi (stack_pointer_rtx, hard_frame_pointer_rtx)); | |
4910 | } | |
4911 | ||
4912 | /* Expand the "prologue" pattern. */ | |
4913 | ||
4914 | void | |
4915 | riscv_expand_prologue (void) | |
4916 | { | |
4917 | struct riscv_frame_info *frame = &cfun->machine->frame; | |
3496ca4e | 4918 | HOST_WIDE_INT size = frame->total_size.to_constant (); |
09cae750 PD |
4919 | unsigned mask = frame->mask; |
4920 | rtx insn; | |
4921 | ||
4922 | if (flag_stack_usage_info) | |
4923 | current_function_static_stack_size = size; | |
4924 | ||
d0ebdd9f JW |
4925 | if (cfun->machine->naked_p) |
4926 | return; | |
4927 | ||
09cae750 PD |
4928 | /* When optimizing for size, call a subroutine to save the registers. */ |
4929 | if (riscv_use_save_libcall (frame)) | |
4930 | { | |
4931 | rtx dwarf = NULL_RTX; | |
4932 | dwarf = riscv_adjust_libcall_cfi_prologue (); | |
4933 | ||
09cae750 | 4934 | size -= frame->save_libcall_adjustment; |
d0e0c130 KC |
4935 | insn = emit_insn (riscv_gen_gpr_save_insn (frame)); |
4936 | frame->mask = 0; /* Temporarily fib that we need not save GPRs. */ | |
09cae750 PD |
4937 | |
4938 | RTX_FRAME_RELATED_P (insn) = 1; | |
4939 | REG_NOTES (insn) = dwarf; | |
4940 | } | |
4941 | ||
4942 | /* Save the registers. */ | |
4943 | if ((frame->mask | frame->fmask) != 0) | |
4944 | { | |
4945 | HOST_WIDE_INT step1 = MIN (size, riscv_first_stack_step (frame)); | |
4946 | ||
4947 | insn = gen_add3_insn (stack_pointer_rtx, | |
4948 | stack_pointer_rtx, | |
4949 | GEN_INT (-step1)); | |
4950 | RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; | |
4951 | size -= step1; | |
fd1e52dc | 4952 | riscv_for_each_saved_reg (size, riscv_save_reg, false, false); |
09cae750 PD |
4953 | } |
4954 | ||
4955 | frame->mask = mask; /* Undo the above fib. */ | |
4956 | ||
4957 | /* Set up the frame pointer, if we're using one. */ | |
4958 | if (frame_pointer_needed) | |
4959 | { | |
4960 | insn = gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx, | |
3496ca4e | 4961 | GEN_INT ((frame->hard_frame_pointer_offset - size).to_constant ())); |
09cae750 PD |
4962 | RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; |
4963 | ||
4964 | riscv_emit_stack_tie (); | |
4965 | } | |
4966 | ||
4967 | /* Allocate the rest of the frame. */ | |
4968 | if (size > 0) | |
4969 | { | |
4970 | if (SMALL_OPERAND (-size)) | |
4971 | { | |
4972 | insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, | |
4973 | GEN_INT (-size)); | |
4974 | RTX_FRAME_RELATED_P (emit_insn (insn)) = 1; | |
4975 | } | |
4976 | else | |
4977 | { | |
4978 | riscv_emit_move (RISCV_PROLOGUE_TEMP (Pmode), GEN_INT (-size)); | |
4979 | emit_insn (gen_add3_insn (stack_pointer_rtx, | |
4980 | stack_pointer_rtx, | |
4981 | RISCV_PROLOGUE_TEMP (Pmode))); | |
4982 | ||
4983 | /* Describe the effect of the previous instructions. */ | |
4984 | insn = plus_constant (Pmode, stack_pointer_rtx, -size); | |
4985 | insn = gen_rtx_SET (stack_pointer_rtx, insn); | |
4986 | riscv_set_frame_expr (insn); | |
4987 | } | |
4988 | } | |
4989 | } | |
4990 | ||
4991 | static rtx | |
4992 | riscv_adjust_libcall_cfi_epilogue () | |
4993 | { | |
4994 | rtx dwarf = NULL_RTX; | |
4995 | rtx adjust_sp_rtx, reg; | |
4996 | int saved_size = cfun->machine->frame.save_libcall_adjustment; | |
4997 | ||
4998 | /* Debug info for adjust sp. */ | |
4999 | adjust_sp_rtx = gen_add3_insn (stack_pointer_rtx, | |
5000 | stack_pointer_rtx, GEN_INT (saved_size)); | |
5001 | dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, adjust_sp_rtx, | |
5002 | dwarf); | |
5003 | ||
f3abed16 | 5004 | for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) |
09cae750 PD |
5005 | if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST)) |
5006 | { | |
5007 | reg = gen_rtx_REG (SImode, regno); | |
5008 | dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); | |
5009 | } | |
5010 | ||
5011 | return dwarf; | |
5012 | } | |
5013 | ||
fd1e52dc JW |
5014 | /* Expand an "epilogue", "sibcall_epilogue", or "eh_return_internal" pattern; |
5015 | style says which. */ | |
09cae750 PD |
5016 | |
5017 | void | |
fd1e52dc | 5018 | riscv_expand_epilogue (int style) |
09cae750 PD |
5019 | { |
5020 | /* Split the frame into two. STEP1 is the amount of stack we should | |
5021 | deallocate before restoring the registers. STEP2 is the amount we | |
5022 | should deallocate afterwards. | |
5023 | ||
5024 | Start off by assuming that no registers need to be restored. */ | |
5025 | struct riscv_frame_info *frame = &cfun->machine->frame; | |
5026 | unsigned mask = frame->mask; | |
3496ca4e | 5027 | HOST_WIDE_INT step1 = frame->total_size.to_constant (); |
09cae750 | 5028 | HOST_WIDE_INT step2 = 0; |
fd1e52dc JW |
5029 | bool use_restore_libcall = ((style == NORMAL_RETURN) |
5030 | && riscv_use_save_libcall (frame)); | |
09cae750 PD |
5031 | rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); |
5032 | rtx insn; | |
5033 | ||
5034 | /* We need to add memory barrier to prevent read from deallocated stack. */ | |
3496ca4e | 5035 | bool need_barrier_p |
5036 | = known_ne (get_frame_size (), cfun->machine->frame.arg_pointer_offset); | |
09cae750 | 5037 | |
8cad5b14 KC |
5038 | if (cfun->machine->naked_p) |
5039 | { | |
fd1e52dc | 5040 | gcc_assert (style == NORMAL_RETURN); |
8cad5b14 KC |
5041 | |
5042 | emit_jump_insn (gen_return ()); | |
5043 | ||
5044 | return; | |
5045 | } | |
5046 | ||
fd1e52dc | 5047 | if ((style == NORMAL_RETURN) && riscv_can_use_return_insn ()) |
09cae750 PD |
5048 | { |
5049 | emit_jump_insn (gen_return ()); | |
5050 | return; | |
5051 | } | |
5052 | ||
b579523b JW |
5053 | /* Reset the epilogue cfa info before starting to emit the epilogue. */ |
5054 | epilogue_cfa_sp_offset = 0; | |
5055 | ||
09cae750 PD |
5056 | /* Move past any dynamic stack allocations. */ |
5057 | if (cfun->calls_alloca) | |
5058 | { | |
5059 | /* Emit a barrier to prevent loads from a deallocated stack. */ | |
5060 | riscv_emit_stack_tie (); | |
5061 | need_barrier_p = false; | |
5062 | ||
3496ca4e | 5063 | rtx adjust = GEN_INT (-frame->hard_frame_pointer_offset.to_constant ()); |
09cae750 PD |
5064 | if (!SMALL_OPERAND (INTVAL (adjust))) |
5065 | { | |
5066 | riscv_emit_move (RISCV_PROLOGUE_TEMP (Pmode), adjust); | |
5067 | adjust = RISCV_PROLOGUE_TEMP (Pmode); | |
5068 | } | |
5069 | ||
5070 | insn = emit_insn ( | |
5071 | gen_add3_insn (stack_pointer_rtx, hard_frame_pointer_rtx, | |
5072 | adjust)); | |
5073 | ||
5074 | rtx dwarf = NULL_RTX; | |
5075 | rtx cfa_adjust_value = gen_rtx_PLUS ( | |
5076 | Pmode, hard_frame_pointer_rtx, | |
3496ca4e | 5077 | GEN_INT (-frame->hard_frame_pointer_offset.to_constant ())); |
09cae750 PD |
5078 | rtx cfa_adjust_rtx = gen_rtx_SET (stack_pointer_rtx, cfa_adjust_value); |
5079 | dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, cfa_adjust_rtx, dwarf); | |
5080 | RTX_FRAME_RELATED_P (insn) = 1; | |
5081 | ||
5082 | REG_NOTES (insn) = dwarf; | |
5083 | } | |
5084 | ||
5085 | /* If we need to restore registers, deallocate as much stack as | |
5086 | possible in the second step without going out of range. */ | |
5087 | if ((frame->mask | frame->fmask) != 0) | |
5088 | { | |
5089 | step2 = riscv_first_stack_step (frame); | |
5090 | step1 -= step2; | |
5091 | } | |
5092 | ||
5093 | /* Set TARGET to BASE + STEP1. */ | |
3496ca4e | 5094 | if (known_gt (step1, 0)) |
09cae750 PD |
5095 | { |
5096 | /* Emit a barrier to prevent loads from a deallocated stack. */ | |
5097 | riscv_emit_stack_tie (); | |
5098 | need_barrier_p = false; | |
5099 | ||
5100 | /* Get an rtx for STEP1 that we can add to BASE. */ | |
5101 | rtx adjust = GEN_INT (step1); | |
5102 | if (!SMALL_OPERAND (step1)) | |
5103 | { | |
5104 | riscv_emit_move (RISCV_PROLOGUE_TEMP (Pmode), adjust); | |
5105 | adjust = RISCV_PROLOGUE_TEMP (Pmode); | |
5106 | } | |
5107 | ||
5108 | insn = emit_insn ( | |
5109 | gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, adjust)); | |
5110 | ||
5111 | rtx dwarf = NULL_RTX; | |
5112 | rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, | |
5113 | GEN_INT (step2)); | |
5114 | ||
5115 | dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); | |
5116 | RTX_FRAME_RELATED_P (insn) = 1; | |
5117 | ||
5118 | REG_NOTES (insn) = dwarf; | |
5119 | } | |
b579523b JW |
5120 | else if (frame_pointer_needed) |
5121 | { | |
5122 | /* Tell riscv_restore_reg to emit dwarf to redefine CFA when restoring | |
5123 | old value of FP. */ | |
5124 | epilogue_cfa_sp_offset = step2; | |
5125 | } | |
09cae750 PD |
5126 | |
5127 | if (use_restore_libcall) | |
5128 | frame->mask = 0; /* Temporarily fib that we need not save GPRs. */ | |
5129 | ||
5130 | /* Restore the registers. */ | |
fd1e52dc JW |
5131 | riscv_for_each_saved_reg (frame->total_size - step2, riscv_restore_reg, |
5132 | true, style == EXCEPTION_RETURN); | |
09cae750 PD |
5133 | |
5134 | if (use_restore_libcall) | |
5135 | { | |
5136 | frame->mask = mask; /* Undo the above fib. */ | |
5137 | gcc_assert (step2 >= frame->save_libcall_adjustment); | |
5138 | step2 -= frame->save_libcall_adjustment; | |
5139 | } | |
5140 | ||
5141 | if (need_barrier_p) | |
5142 | riscv_emit_stack_tie (); | |
5143 | ||
5144 | /* Deallocate the final bit of the frame. */ | |
5145 | if (step2 > 0) | |
5146 | { | |
5147 | insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, | |
5148 | GEN_INT (step2))); | |
5149 | ||
5150 | rtx dwarf = NULL_RTX; | |
5151 | rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, | |
5152 | const0_rtx); | |
5153 | dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); | |
5154 | RTX_FRAME_RELATED_P (insn) = 1; | |
5155 | ||
5156 | REG_NOTES (insn) = dwarf; | |
5157 | } | |
5158 | ||
5159 | if (use_restore_libcall) | |
5160 | { | |
5161 | rtx dwarf = riscv_adjust_libcall_cfi_epilogue (); | |
5162 | insn = emit_insn (gen_gpr_restore (GEN_INT (riscv_save_libcall_count (mask)))); | |
5163 | RTX_FRAME_RELATED_P (insn) = 1; | |
5164 | REG_NOTES (insn) = dwarf; | |
5165 | ||
5166 | emit_jump_insn (gen_gpr_restore_return (ra)); | |
5167 | return; | |
5168 | } | |
5169 | ||
5170 | /* Add in the __builtin_eh_return stack adjustment. */ | |
fd1e52dc | 5171 | if ((style == EXCEPTION_RETURN) && crtl->calls_eh_return) |
09cae750 PD |
5172 | emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, |
5173 | EH_RETURN_STACKADJ_RTX)); | |
5174 | ||
d0ebdd9f JW |
5175 | /* Return from interrupt. */ |
5176 | if (cfun->machine->interrupt_handler_p) | |
ec74725c JW |
5177 | { |
5178 | enum riscv_privilege_levels mode = cfun->machine->interrupt_mode; | |
5179 | ||
8528f27b KC |
5180 | gcc_assert (mode != UNKNOWN_MODE); |
5181 | ||
ec74725c | 5182 | if (mode == MACHINE_MODE) |
eb153f07 | 5183 | emit_jump_insn (gen_riscv_mret ()); |
ec74725c | 5184 | else if (mode == SUPERVISOR_MODE) |
eb153f07 | 5185 | emit_jump_insn (gen_riscv_sret ()); |
ec74725c | 5186 | else |
eb153f07 | 5187 | emit_jump_insn (gen_riscv_uret ()); |
ec74725c | 5188 | } |
fd1e52dc | 5189 | else if (style != SIBCALL_RETURN) |
09cae750 PD |
5190 | emit_jump_insn (gen_simple_return_internal (ra)); |
5191 | } | |
5192 | ||
d0ebdd9f JW |
5193 | /* Implement EPILOGUE_USES. */ |
5194 | ||
5195 | bool | |
5196 | riscv_epilogue_uses (unsigned int regno) | |
5197 | { | |
5198 | if (regno == RETURN_ADDR_REGNUM) | |
5199 | return true; | |
5200 | ||
5201 | if (epilogue_completed && cfun->machine->interrupt_handler_p) | |
5202 | { | |
5203 | /* An interrupt function restores temp regs, so we must indicate that | |
5204 | they are live at function end. */ | |
5205 | if (df_regs_ever_live_p (regno) | |
a365fa06 | 5206 | || (!crtl->is_leaf && call_used_or_fixed_reg_p (regno))) |
d0ebdd9f JW |
5207 | return true; |
5208 | } | |
5209 | ||
5210 | return false; | |
5211 | } | |
5212 | ||
09cae750 PD |
5213 | /* Return nonzero if this function is known to have a null epilogue. |
5214 | This allows the optimizer to omit jumps to jumps if no stack | |
5215 | was created. */ | |
5216 | ||
5217 | bool | |
5218 | riscv_can_use_return_insn (void) | |
5219 | { | |
3496ca4e | 5220 | return (reload_completed && known_eq (cfun->machine->frame.total_size, 0) |
d0ebdd9f | 5221 | && ! cfun->machine->interrupt_handler_p); |
09cae750 PD |
5222 | } |
5223 | ||
88108b27 AW |
5224 | /* Given that there exists at least one variable that is set (produced) |
5225 | by OUT_INSN and read (consumed) by IN_INSN, return true iff | |
5226 | IN_INSN represents one or more memory store operations and none of | |
5227 | the variables set by OUT_INSN is used by IN_INSN as the address of a | |
5228 | store operation. If either IN_INSN or OUT_INSN does not represent | |
5229 | a "single" RTL SET expression (as loosely defined by the | |
5230 | implementation of the single_set function) or a PARALLEL with only | |
5231 | SETs, CLOBBERs, and USEs inside, this function returns false. | |
5232 | ||
5233 | Borrowed from rs6000, riscv_store_data_bypass_p checks for certain | |
5234 | conditions that result in assertion failures in the generic | |
5235 | store_data_bypass_p function and returns FALSE in such cases. | |
5236 | ||
5237 | This is required to make -msave-restore work with the sifive-7 | |
5238 | pipeline description. */ | |
5239 | ||
5240 | bool | |
5241 | riscv_store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) | |
5242 | { | |
5243 | rtx out_set, in_set; | |
5244 | rtx out_pat, in_pat; | |
5245 | rtx out_exp, in_exp; | |
5246 | int i, j; | |
5247 | ||
5248 | in_set = single_set (in_insn); | |
5249 | if (in_set) | |
5250 | { | |
5251 | if (MEM_P (SET_DEST (in_set))) | |
5252 | { | |
5253 | out_set = single_set (out_insn); | |
5254 | if (!out_set) | |
5255 | { | |
5256 | out_pat = PATTERN (out_insn); | |
5257 | if (GET_CODE (out_pat) == PARALLEL) | |
5258 | { | |
5259 | for (i = 0; i < XVECLEN (out_pat, 0); i++) | |
5260 | { | |
5261 | out_exp = XVECEXP (out_pat, 0, i); | |
5262 | if ((GET_CODE (out_exp) == CLOBBER) | |
5263 | || (GET_CODE (out_exp) == USE)) | |
5264 | continue; | |
5265 | else if (GET_CODE (out_exp) != SET) | |
5266 | return false; | |
5267 | } | |
5268 | } | |
5269 | } | |
5270 | } | |
5271 | } | |
5272 | else | |
5273 | { | |
5274 | in_pat = PATTERN (in_insn); | |
5275 | if (GET_CODE (in_pat) != PARALLEL) | |
5276 | return false; | |
5277 | ||
5278 | for (i = 0; i < XVECLEN (in_pat, 0); i++) | |
5279 | { | |
5280 | in_exp = XVECEXP (in_pat, 0, i); | |
5281 | if ((GET_CODE (in_exp) == CLOBBER) || (GET_CODE (in_exp) == USE)) | |
5282 | continue; | |
5283 | else if (GET_CODE (in_exp) != SET) | |
5284 | return false; | |
5285 | ||
5286 | if (MEM_P (SET_DEST (in_exp))) | |
5287 | { | |
5288 | out_set = single_set (out_insn); | |
5289 | if (!out_set) | |
5290 | { | |
5291 | out_pat = PATTERN (out_insn); | |
5292 | if (GET_CODE (out_pat) != PARALLEL) | |
5293 | return false; | |
5294 | for (j = 0; j < XVECLEN (out_pat, 0); j++) | |
5295 | { | |
5296 | out_exp = XVECEXP (out_pat, 0, j); | |
5297 | if ((GET_CODE (out_exp) == CLOBBER) | |
5298 | || (GET_CODE (out_exp) == USE)) | |
5299 | continue; | |
5300 | else if (GET_CODE (out_exp) != SET) | |
5301 | return false; | |
5302 | } | |
5303 | } | |
5304 | } | |
5305 | } | |
5306 | } | |
5307 | ||
5308 | return store_data_bypass_p (out_insn, in_insn); | |
5309 | } | |
5310 | ||
f15643d4 RS |
5311 | /* Implement TARGET_SECONDARY_MEMORY_NEEDED. |
5312 | ||
5313 | When floating-point registers are wider than integer ones, moves between | |
5314 | them must go through memory. */ | |
5315 | ||
5316 | static bool | |
5317 | riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1, | |
5318 | reg_class_t class2) | |
5319 | { | |
31380d4b | 5320 | return (!riscv_v_ext_vector_mode_p (mode) |
5321 | && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD | |
f15643d4 RS |
5322 | && (class1 == FP_REGS) != (class2 == FP_REGS)); |
5323 | } | |
5324 | ||
09cae750 PD |
5325 | /* Implement TARGET_REGISTER_MOVE_COST. */ |
5326 | ||
5327 | static int | |
b8506a8a | 5328 | riscv_register_move_cost (machine_mode mode, |
09cae750 PD |
5329 | reg_class_t from, reg_class_t to) |
5330 | { | |
b646d7d2 VG |
5331 | if ((from == FP_REGS && to == GR_REGS) || |
5332 | (from == GR_REGS && to == FP_REGS)) | |
5333 | return tune_param->fmv_cost; | |
5334 | ||
f15643d4 | 5335 | return riscv_secondary_memory_needed (mode, from, to) ? 8 : 2; |
09cae750 PD |
5336 | } |
5337 | ||
c43f4279 RS |
5338 | /* Implement TARGET_HARD_REGNO_NREGS. */ |
5339 | ||
5340 | static unsigned int | |
5341 | riscv_hard_regno_nregs (unsigned int regno, machine_mode mode) | |
5342 | { | |
31380d4b | 5343 | if (riscv_v_ext_vector_mode_p (mode)) |
5344 | { | |
5345 | /* Handle fractional LMUL, it only occupy part of vector register but | |
5346 | still need one vector register to hold. */ | |
5347 | if (maybe_lt (GET_MODE_SIZE (mode), UNITS_PER_V_REG)) | |
5348 | return 1; | |
5349 | ||
5350 | return exact_div (GET_MODE_SIZE (mode), UNITS_PER_V_REG).to_constant (); | |
5351 | } | |
5352 | ||
5353 | /* mode for VL or VTYPE are just a marker, not holding value, | |
5354 | so it always consume one register. */ | |
5355 | if (regno == VTYPE_REGNUM || regno == VL_REGNUM) | |
5356 | return 1; | |
5357 | ||
5358 | /* Assume every valid non-vector mode fits in one vector register. */ | |
5359 | if (V_REG_P (regno)) | |
5360 | return 1; | |
5361 | ||
c43f4279 | 5362 | if (FP_REG_P (regno)) |
3496ca4e | 5363 | return (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_FP_REG - 1) / UNITS_PER_FP_REG; |
c43f4279 RS |
5364 | |
5365 | /* All other registers are word-sized. */ | |
3496ca4e | 5366 | return (GET_MODE_SIZE (mode).to_constant () + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
c43f4279 RS |
5367 | } |
5368 | ||
f939c3e6 | 5369 | /* Implement TARGET_HARD_REGNO_MODE_OK. */ |
09cae750 | 5370 | |
f939c3e6 RS |
5371 | static bool |
5372 | riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode) | |
09cae750 PD |
5373 | { |
5374 | unsigned int nregs = riscv_hard_regno_nregs (regno, mode); | |
5375 | ||
5376 | if (GP_REG_P (regno)) | |
5377 | { | |
31380d4b | 5378 | if (riscv_v_ext_vector_mode_p (mode)) |
5379 | return false; | |
5380 | ||
09cae750 PD |
5381 | if (!GP_REG_P (regno + nregs - 1)) |
5382 | return false; | |
5383 | } | |
5384 | else if (FP_REG_P (regno)) | |
5385 | { | |
31380d4b | 5386 | if (riscv_v_ext_vector_mode_p (mode)) |
5387 | return false; | |
5388 | ||
09cae750 PD |
5389 | if (!FP_REG_P (regno + nregs - 1)) |
5390 | return false; | |
5391 | ||
5392 | if (GET_MODE_CLASS (mode) != MODE_FLOAT | |
5393 | && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) | |
5394 | return false; | |
5395 | ||
5396 | /* Only use callee-saved registers if a potential callee is guaranteed | |
5397 | to spill the requisite width. */ | |
5398 | if (GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_REG | |
a365fa06 | 5399 | || (!call_used_or_fixed_reg_p (regno) |
09cae750 PD |
5400 | && GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_ARG)) |
5401 | return false; | |
5402 | } | |
31380d4b | 5403 | else if (V_REG_P (regno)) |
5404 | { | |
5405 | if (!riscv_v_ext_vector_mode_p (mode)) | |
5406 | return false; | |
5407 | ||
b4feb49c | 5408 | if (!V_REG_P (regno + nregs - 1)) |
5409 | return false; | |
5410 | ||
31380d4b | 5411 | /* 3.3.2. LMUL = 2,4,8, register numbers should be multiple of 2,4,8. |
5412 | but for mask vector register, register numbers can be any number. */ | |
5413 | int lmul = 1; | |
5414 | if (known_gt (GET_MODE_SIZE (mode), UNITS_PER_V_REG)) | |
5415 | lmul = exact_div (GET_MODE_SIZE (mode), UNITS_PER_V_REG).to_constant (); | |
5416 | if (lmul != 1) | |
5417 | return ((regno % lmul) == 0); | |
5418 | } | |
b4feb49c | 5419 | else if (regno == VL_REGNUM || regno == VTYPE_REGNUM) |
5420 | return true; | |
09cae750 PD |
5421 | else |
5422 | return false; | |
5423 | ||
5424 | /* Require same callee-savedness for all registers. */ | |
5425 | for (unsigned i = 1; i < nregs; i++) | |
a365fa06 RS |
5426 | if (call_used_or_fixed_reg_p (regno) |
5427 | != call_used_or_fixed_reg_p (regno + i)) | |
09cae750 PD |
5428 | return false; |
5429 | ||
5430 | return true; | |
5431 | } | |
5432 | ||
99e1629f RS |
5433 | /* Implement TARGET_MODES_TIEABLE_P. |
5434 | ||
5435 | Don't allow floating-point modes to be tied, since type punning of | |
5436 | single-precision and double-precision is implementation defined. */ | |
5437 | ||
5438 | static bool | |
5439 | riscv_modes_tieable_p (machine_mode mode1, machine_mode mode2) | |
5440 | { | |
5441 | return (mode1 == mode2 | |
5442 | || !(GET_MODE_CLASS (mode1) == MODE_FLOAT | |
5443 | && GET_MODE_CLASS (mode2) == MODE_FLOAT)); | |
5444 | } | |
5445 | ||
09cae750 PD |
5446 | /* Implement CLASS_MAX_NREGS. */ |
5447 | ||
5448 | static unsigned char | |
b8506a8a | 5449 | riscv_class_max_nregs (reg_class_t rclass, machine_mode mode) |
09cae750 | 5450 | { |
a31056e9 | 5451 | if (reg_class_subset_p (rclass, FP_REGS)) |
09cae750 PD |
5452 | return riscv_hard_regno_nregs (FP_REG_FIRST, mode); |
5453 | ||
a31056e9 | 5454 | if (reg_class_subset_p (rclass, GR_REGS)) |
09cae750 PD |
5455 | return riscv_hard_regno_nregs (GP_REG_FIRST, mode); |
5456 | ||
31380d4b | 5457 | if (reg_class_subset_p (rclass, V_REGS)) |
5458 | return riscv_hard_regno_nregs (V_REG_FIRST, mode); | |
5459 | ||
5460 | if (reg_class_subset_p (rclass, VL_REGS)) | |
5461 | return 1; | |
5462 | ||
5463 | if (reg_class_subset_p (rclass, VTYPE_REGS)) | |
5464 | return 1; | |
5465 | ||
09cae750 PD |
5466 | return 0; |
5467 | } | |
5468 | ||
09cae750 PD |
5469 | /* Implement TARGET_MEMORY_MOVE_COST. */ |
5470 | ||
5471 | static int | |
b8506a8a | 5472 | riscv_memory_move_cost (machine_mode mode, reg_class_t rclass, bool in) |
09cae750 | 5473 | { |
72eb8335 | 5474 | return (tune_param->memory_cost |
09cae750 PD |
5475 | + memory_move_secondary_cost (mode, rclass, in)); |
5476 | } | |
5477 | ||
5478 | /* Return the number of instructions that can be issued per cycle. */ | |
5479 | ||
5480 | static int | |
5481 | riscv_issue_rate (void) | |
5482 | { | |
72eb8335 | 5483 | return tune_param->issue_rate; |
09cae750 PD |
5484 | } |
5485 | ||
8e966210 KC |
5486 | /* Auxiliary function to emit RISC-V ELF attribute. */ |
5487 | static void | |
5488 | riscv_emit_attribute () | |
5489 | { | |
5490 | fprintf (asm_out_file, "\t.attribute arch, \"%s\"\n", | |
5491 | riscv_arch_str ().c_str ()); | |
5492 | ||
5493 | fprintf (asm_out_file, "\t.attribute unaligned_access, %d\n", | |
5494 | TARGET_STRICT_ALIGN ? 0 : 1); | |
5495 | ||
5496 | fprintf (asm_out_file, "\t.attribute stack_align, %d\n", | |
5497 | riscv_stack_boundary / 8); | |
5498 | } | |
5499 | ||
09cae750 PD |
5500 | /* Implement TARGET_ASM_FILE_START. */ |
5501 | ||
5502 | static void | |
5503 | riscv_file_start (void) | |
5504 | { | |
5505 | default_file_start (); | |
5506 | ||
5507 | /* Instruct GAS to generate position-[in]dependent code. */ | |
5508 | fprintf (asm_out_file, "\t.option %spic\n", (flag_pic ? "" : "no")); | |
a7af8489 PD |
5509 | |
5510 | /* If the user specifies "-mno-relax" on the command line then disable linker | |
5511 | relaxation in the assembler. */ | |
5512 | if (! riscv_mrelax) | |
5513 | fprintf (asm_out_file, "\t.option norelax\n"); | |
8e966210 | 5514 | |
32f86f2b J |
5515 | /* If the user specifies "-mcsr-check" on the command line then enable csr |
5516 | check in the assembler. */ | |
5517 | if (riscv_mcsr_check) | |
5518 | fprintf (asm_out_file, "\t.option csr-check\n"); | |
5519 | ||
8e966210 KC |
5520 | if (riscv_emit_attribute_p) |
5521 | riscv_emit_attribute (); | |
09cae750 PD |
5522 | } |
5523 | ||
5524 | /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text | |
5525 | in order to avoid duplicating too much logic from elsewhere. */ | |
5526 | ||
5527 | static void | |
5528 | riscv_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, | |
5529 | HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
5530 | tree function) | |
5531 | { | |
f7430263 | 5532 | const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl)); |
09cae750 PD |
5533 | rtx this_rtx, temp1, temp2, fnaddr; |
5534 | rtx_insn *insn; | |
5535 | ||
5536 | /* Pretend to be a post-reload pass while generating rtl. */ | |
5537 | reload_completed = 1; | |
5538 | ||
5539 | /* Mark the end of the (empty) prologue. */ | |
5540 | emit_note (NOTE_INSN_PROLOGUE_END); | |
5541 | ||
5542 | /* Determine if we can use a sibcall to call FUNCTION directly. */ | |
5543 | fnaddr = gen_rtx_MEM (FUNCTION_MODE, XEXP (DECL_RTL (function), 0)); | |
5544 | ||
5545 | /* We need two temporary registers in some cases. */ | |
5546 | temp1 = gen_rtx_REG (Pmode, RISCV_PROLOGUE_TEMP_REGNUM); | |
5547 | temp2 = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); | |
5548 | ||
5549 | /* Find out which register contains the "this" pointer. */ | |
5550 | if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) | |
5551 | this_rtx = gen_rtx_REG (Pmode, GP_ARG_FIRST + 1); | |
5552 | else | |
5553 | this_rtx = gen_rtx_REG (Pmode, GP_ARG_FIRST); | |
5554 | ||
5555 | /* Add DELTA to THIS_RTX. */ | |
5556 | if (delta != 0) | |
5557 | { | |
5558 | rtx offset = GEN_INT (delta); | |
5559 | if (!SMALL_OPERAND (delta)) | |
5560 | { | |
5561 | riscv_emit_move (temp1, offset); | |
5562 | offset = temp1; | |
5563 | } | |
5564 | emit_insn (gen_add3_insn (this_rtx, this_rtx, offset)); | |
5565 | } | |
5566 | ||
5567 | /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ | |
5568 | if (vcall_offset != 0) | |
5569 | { | |
5570 | rtx addr; | |
5571 | ||
5572 | /* Set TEMP1 to *THIS_RTX. */ | |
5573 | riscv_emit_move (temp1, gen_rtx_MEM (Pmode, this_rtx)); | |
5574 | ||
5575 | /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */ | |
5576 | addr = riscv_add_offset (temp2, temp1, vcall_offset); | |
5577 | ||
5578 | /* Load the offset and add it to THIS_RTX. */ | |
5579 | riscv_emit_move (temp1, gen_rtx_MEM (Pmode, addr)); | |
5580 | emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1)); | |
5581 | } | |
5582 | ||
5583 | /* Jump to the target function. */ | |
5584 | insn = emit_call_insn (gen_sibcall (fnaddr, const0_rtx, NULL, const0_rtx)); | |
5585 | SIBLING_CALL_P (insn) = 1; | |
5586 | ||
5587 | /* Run just enough of rest_of_compilation. This sequence was | |
e53b6e56 | 5588 | "borrowed" from alpha.cc. */ |
09cae750 PD |
5589 | insn = get_insns (); |
5590 | split_all_insns_noflow (); | |
5591 | shorten_branches (insn); | |
f7430263 | 5592 | assemble_start_function (thunk_fndecl, fnname); |
09cae750 PD |
5593 | final_start_function (insn, file, 1); |
5594 | final (insn, file, 1); | |
5595 | final_end_function (); | |
f7430263 | 5596 | assemble_end_function (thunk_fndecl, fnname); |
09cae750 PD |
5597 | |
5598 | /* Clean up the vars set above. Note that final_end_function resets | |
5599 | the global pointer for us. */ | |
5600 | reload_completed = 0; | |
5601 | } | |
5602 | ||
5603 | /* Allocate a chunk of memory for per-function machine-dependent data. */ | |
5604 | ||
5605 | static struct machine_function * | |
5606 | riscv_init_machine_status (void) | |
5607 | { | |
5608 | return ggc_cleared_alloc<machine_function> (); | |
5609 | } | |
5610 | ||
3496ca4e | 5611 | /* Return the VLEN value associated with -march. |
5612 | TODO: So far we only support length-agnostic value. */ | |
5613 | static poly_uint16 | |
5614 | riscv_convert_vector_bits (void) | |
5615 | { | |
e9f827d7 | 5616 | if (TARGET_MIN_VLEN > 32) |
3496ca4e | 5617 | { |
e9f827d7 | 5618 | /* When targetting minimum VLEN > 32, we should use 64-bit chunk size. |
5619 | Otherwise we can not include SEW = 64bits. | |
5620 | Runtime invariant: The single indeterminate represent the | |
3496ca4e | 5621 | number of 64-bit chunks in a vector beyond minimum length of 64 bits. |
5622 | Thus the number of bytes in a vector is 8 + 8 * x1 which is | |
e9f827d7 | 5623 | riscv_vector_chunks * 8 = poly_int (8, 8). */ |
3496ca4e | 5624 | riscv_bytes_per_vector_chunk = 8; |
5625 | } | |
5626 | else | |
5627 | { | |
e9f827d7 | 5628 | /* When targetting minimum VLEN = 32, we should use 32-bit |
3496ca4e | 5629 | chunk size. Runtime invariant: The single indeterminate represent the |
5630 | number of 32-bit chunks in a vector beyond minimum length of 32 bits. | |
5631 | Thus the number of bytes in a vector is 4 + 4 * x1 which is | |
5632 | riscv_vector_chunks * 4 = poly_int (4, 4). */ | |
5633 | riscv_bytes_per_vector_chunk = 4; | |
5634 | } | |
5635 | ||
b4feb49c | 5636 | /* Set riscv_vector_chunks as poly (1, 1) run-time constant if TARGET_VECTOR |
5637 | is enabled. Set riscv_vector_chunks as 1 compile-time constant if | |
5638 | TARGET_VECTOR is disabled. riscv_vector_chunks is used in "riscv-modes.def" | |
5639 | to set RVV mode size. The RVV machine modes size are run-time constant if | |
5640 | TARGET_VECTOR is enabled. The RVV machine modes size remains default | |
5641 | compile-time constant if TARGET_VECTOR is disabled. */ | |
5642 | return TARGET_VECTOR ? poly_uint16 (1, 1) : 1; | |
3496ca4e | 5643 | } |
5644 | ||
09cae750 PD |
5645 | /* Implement TARGET_OPTION_OVERRIDE. */ |
5646 | ||
5647 | static void | |
5648 | riscv_option_override (void) | |
5649 | { | |
72eb8335 | 5650 | const struct riscv_tune_info *cpu; |
09cae750 PD |
5651 | |
5652 | #ifdef SUBTARGET_OVERRIDE_OPTIONS | |
5653 | SUBTARGET_OVERRIDE_OPTIONS; | |
5654 | #endif | |
5655 | ||
5656 | flag_pcc_struct_return = 0; | |
5657 | ||
5658 | if (flag_pic) | |
5659 | g_switch_value = 0; | |
5660 | ||
5661 | /* The presence of the M extension implies that division instructions | |
5662 | are present, so include them unless explicitly disabled. */ | |
5663 | if (TARGET_MUL && (target_flags_explicit & MASK_DIV) == 0) | |
ae97ba1e | 5664 | target_flags |= MASK_DIV; |
09cae750 | 5665 | else if (!TARGET_MUL && TARGET_DIV) |
a3f9f006 | 5666 | error ("%<-mdiv%> requires %<-march%> to subsume the %<M%> extension"); |
ae97ba1e | 5667 | |
09cae750 PD |
5668 | /* Likewise floating-point division and square root. */ |
5669 | if (TARGET_HARD_FLOAT && (target_flags_explicit & MASK_FDIV) == 0) | |
5670 | target_flags |= MASK_FDIV; | |
5671 | ||
72eb8335 | 5672 | /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune |
027e3041 | 5673 | if -mtune and -mcpu both not given. */ |
72eb8335 KC |
5674 | cpu = riscv_parse_tune (riscv_tune_string ? riscv_tune_string : |
5675 | (riscv_cpu_string ? riscv_cpu_string : | |
5676 | RISCV_TUNE_STRING_DEFAULT)); | |
88108b27 | 5677 | riscv_microarchitecture = cpu->microarchitecture; |
72eb8335 | 5678 | tune_param = optimize_size ? &optimize_size_tune_info : cpu->tune_param; |
09cae750 | 5679 | |
82285692 AW |
5680 | /* Use -mtune's setting for slow_unaligned_access, even when optimizing |
5681 | for size. For architectures that trap and emulate unaligned accesses, | |
caf1c1cd AW |
5682 | the performance cost is too great, even for -Os. Similarly, if |
5683 | -m[no-]strict-align is left unspecified, heed -mtune's advice. */ | |
72eb8335 | 5684 | riscv_slow_unaligned_access_p = (cpu->tune_param->slow_unaligned_access |
e0bd6c9f | 5685 | || TARGET_STRICT_ALIGN); |
caf1c1cd | 5686 | if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0 |
72eb8335 | 5687 | && cpu->tune_param->slow_unaligned_access) |
caf1c1cd | 5688 | target_flags |= MASK_STRICT_ALIGN; |
82285692 | 5689 | |
09cae750 PD |
5690 | /* If the user hasn't specified a branch cost, use the processor's |
5691 | default. */ | |
5692 | if (riscv_branch_cost == 0) | |
72eb8335 | 5693 | riscv_branch_cost = tune_param->branch_cost; |
09cae750 PD |
5694 | |
5695 | /* Function to allocate machine-dependent function status. */ | |
5696 | init_machine_status = &riscv_init_machine_status; | |
5697 | ||
5698 | if (flag_pic) | |
5699 | riscv_cmodel = CM_PIC; | |
5700 | ||
5701 | /* We get better code with explicit relocs for CM_MEDLOW, but | |
5702 | worse code for the others (for now). Pick the best default. */ | |
5703 | if ((target_flags_explicit & MASK_EXPLICIT_RELOCS) == 0) | |
5704 | if (riscv_cmodel == CM_MEDLOW) | |
5705 | target_flags |= MASK_EXPLICIT_RELOCS; | |
5706 | ||
5707 | /* Require that the ISA supports the requested floating-point ABI. */ | |
5708 | if (UNITS_PER_FP_ARG > (TARGET_HARD_FLOAT ? UNITS_PER_FP_REG : 0)) | |
a3f9f006 | 5709 | error ("requested ABI requires %<-march%> to subsume the %qc extension", |
09cae750 PD |
5710 | UNITS_PER_FP_ARG > 8 ? 'Q' : (UNITS_PER_FP_ARG > 4 ? 'D' : 'F')); |
5711 | ||
09baee1a KC |
5712 | if (TARGET_RVE && riscv_abi != ABI_ILP32E) |
5713 | error ("rv32e requires ilp32e ABI"); | |
5714 | ||
09cae750 PD |
5715 | /* We do not yet support ILP32 on RV64. */ |
5716 | if (BITS_PER_WORD != POINTER_SIZE) | |
a3f9f006 | 5717 | error ("ABI requires %<-march=rv%d%>", POINTER_SIZE); |
0ce42fe1 AW |
5718 | |
5719 | /* Validate -mpreferred-stack-boundary= value. */ | |
5720 | riscv_stack_boundary = ABI_STACK_BOUNDARY; | |
5721 | if (riscv_preferred_stack_boundary_arg) | |
5722 | { | |
c0d3d1b6 | 5723 | int min = ctz_hwi (STACK_BOUNDARY / 8); |
0ce42fe1 AW |
5724 | int max = 8; |
5725 | ||
5726 | if (!IN_RANGE (riscv_preferred_stack_boundary_arg, min, max)) | |
a3f9f006 | 5727 | error ("%<-mpreferred-stack-boundary=%d%> must be between %d and %d", |
0ce42fe1 AW |
5728 | riscv_preferred_stack_boundary_arg, min, max); |
5729 | ||
5730 | riscv_stack_boundary = 8 << riscv_preferred_stack_boundary_arg; | |
5731 | } | |
8e966210 KC |
5732 | |
5733 | if (riscv_emit_attribute_p < 0) | |
5734 | #ifdef HAVE_AS_RISCV_ATTRIBUTE | |
5735 | riscv_emit_attribute_p = TARGET_RISCV_ATTRIBUTE; | |
5736 | #else | |
5737 | riscv_emit_attribute_p = 0; | |
5738 | ||
5739 | if (riscv_emit_attribute_p) | |
a3f9f006 ML |
5740 | error ("%<-mriscv-attribute%> RISC-V ELF attribute requires GNU as 2.32" |
5741 | " [%<-mriscv-attribute%>]"); | |
8e966210 | 5742 | #endif |
de6320a8 | 5743 | |
c931e8d5 | 5744 | if (riscv_stack_protector_guard == SSP_GLOBAL |
00f34291 | 5745 | && OPTION_SET_P (riscv_stack_protector_guard_offset_str)) |
c931e8d5 CQ |
5746 | { |
5747 | error ("incompatible options %<-mstack-protector-guard=global%> and " | |
5748 | "%<-mstack-protector-guard-offset=%s%>", | |
5749 | riscv_stack_protector_guard_offset_str); | |
5750 | } | |
5751 | ||
5752 | if (riscv_stack_protector_guard == SSP_TLS | |
00f34291 ML |
5753 | && !(OPTION_SET_P (riscv_stack_protector_guard_offset_str) |
5754 | && OPTION_SET_P (riscv_stack_protector_guard_reg_str))) | |
c931e8d5 CQ |
5755 | { |
5756 | error ("both %<-mstack-protector-guard-offset%> and " | |
5757 | "%<-mstack-protector-guard-reg%> must be used " | |
5758 | "with %<-mstack-protector-guard=sysreg%>"); | |
5759 | } | |
5760 | ||
00f34291 | 5761 | if (OPTION_SET_P (riscv_stack_protector_guard_reg_str)) |
c931e8d5 CQ |
5762 | { |
5763 | const char *str = riscv_stack_protector_guard_reg_str; | |
5764 | int reg = decode_reg_name (str); | |
5765 | ||
5766 | if (!IN_RANGE (reg, GP_REG_FIRST + 1, GP_REG_LAST)) | |
5767 | error ("%qs is not a valid base register in %qs", str, | |
5768 | "-mstack-protector-guard-reg="); | |
5769 | ||
5770 | riscv_stack_protector_guard_reg = reg; | |
5771 | } | |
5772 | ||
00f34291 | 5773 | if (OPTION_SET_P (riscv_stack_protector_guard_offset_str)) |
c931e8d5 CQ |
5774 | { |
5775 | char *end; | |
5776 | const char *str = riscv_stack_protector_guard_offset_str; | |
5777 | errno = 0; | |
5778 | long offs = strtol (riscv_stack_protector_guard_offset_str, &end, 0); | |
5779 | ||
5780 | if (!*str || *end || errno) | |
5781 | error ("%qs is not a valid number in %qs", str, | |
5782 | "-mstack-protector-guard-offset="); | |
5783 | ||
5784 | if (!SMALL_OPERAND (offs)) | |
5785 | error ("%qs is not a valid offset in %qs", str, | |
5786 | "-mstack-protector-guard-offset="); | |
5787 | ||
5788 | riscv_stack_protector_guard_offset = offs; | |
5789 | } | |
5790 | ||
3496ca4e | 5791 | /* Convert -march to a chunks count. */ |
5792 | riscv_vector_chunks = riscv_convert_vector_bits (); | |
09cae750 PD |
5793 | } |
5794 | ||
5795 | /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */ | |
5796 | ||
5797 | static void | |
5798 | riscv_conditional_register_usage (void) | |
5799 | { | |
09baee1a KC |
5800 | /* We have only x0~x15 on RV32E. */ |
5801 | if (TARGET_RVE) | |
5802 | { | |
5803 | for (int r = 16; r <= 31; r++) | |
5804 | fixed_regs[r] = 1; | |
5805 | } | |
5806 | ||
5807 | if (riscv_abi == ABI_ILP32E) | |
5808 | { | |
5809 | for (int r = 16; r <= 31; r++) | |
5810 | call_used_regs[r] = 1; | |
5811 | } | |
5812 | ||
09cae750 PD |
5813 | if (!TARGET_HARD_FLOAT) |
5814 | { | |
5815 | for (int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) | |
5816 | fixed_regs[regno] = call_used_regs[regno] = 1; | |
5817 | } | |
e423d5bc AW |
5818 | |
5819 | /* In the soft-float ABI, there are no callee-saved FP registers. */ | |
5820 | if (UNITS_PER_FP_ARG == 0) | |
5821 | { | |
5822 | for (int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) | |
5823 | call_used_regs[regno] = 1; | |
5824 | } | |
e8c83ab9 | 5825 | |
5826 | if (!TARGET_VECTOR) | |
5827 | { | |
5828 | for (int regno = V_REG_FIRST; regno <= V_REG_LAST; regno++) | |
5829 | fixed_regs[regno] = call_used_regs[regno] = 1; | |
5830 | ||
5831 | fixed_regs[VTYPE_REGNUM] = call_used_regs[VTYPE_REGNUM] = 1; | |
5832 | fixed_regs[VL_REGNUM] = call_used_regs[VL_REGNUM] = 1; | |
5833 | } | |
09cae750 PD |
5834 | } |
5835 | ||
5836 | /* Return a register priority for hard reg REGNO. */ | |
5837 | ||
5838 | static int | |
5839 | riscv_register_priority (int regno) | |
5840 | { | |
de6320a8 CB |
5841 | /* Favor compressed registers to improve the odds of RVC instruction |
5842 | selection. */ | |
5843 | if (riscv_compressed_reg_p (regno)) | |
09cae750 PD |
5844 | return 1; |
5845 | ||
5846 | return 0; | |
5847 | } | |
5848 | ||
5849 | /* Implement TARGET_TRAMPOLINE_INIT. */ | |
5850 | ||
5851 | static void | |
5852 | riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) | |
5853 | { | |
5854 | rtx addr, end_addr, mem; | |
5855 | uint32_t trampoline[4]; | |
5856 | unsigned int i; | |
5857 | HOST_WIDE_INT static_chain_offset, target_function_offset; | |
5858 | ||
5859 | /* Work out the offsets of the pointers from the start of the | |
5860 | trampoline code. */ | |
5861 | gcc_assert (ARRAY_SIZE (trampoline) * 4 == TRAMPOLINE_CODE_SIZE); | |
5862 | ||
5863 | /* Get pointers to the beginning and end of the code block. */ | |
5864 | addr = force_reg (Pmode, XEXP (m_tramp, 0)); | |
5865 | end_addr = riscv_force_binary (Pmode, PLUS, addr, | |
5866 | GEN_INT (TRAMPOLINE_CODE_SIZE)); | |
5867 | ||
5868 | ||
5869 | if (Pmode == SImode) | |
5870 | { | |
5871 | chain_value = force_reg (Pmode, chain_value); | |
5872 | ||
5873 | rtx target_function = force_reg (Pmode, XEXP (DECL_RTL (fndecl), 0)); | |
5874 | /* lui t2, hi(chain) | |
207de839 | 5875 | lui t0, hi(func) |
09cae750 | 5876 | addi t2, t2, lo(chain) |
207de839 | 5877 | jr t0, lo(func) |
09cae750 PD |
5878 | */ |
5879 | unsigned HOST_WIDE_INT lui_hi_chain_code, lui_hi_func_code; | |
5880 | unsigned HOST_WIDE_INT lo_chain_code, lo_func_code; | |
5881 | ||
5882 | rtx uimm_mask = force_reg (SImode, gen_int_mode (-IMM_REACH, SImode)); | |
5883 | ||
5884 | /* 0xfff. */ | |
5885 | rtx imm12_mask = gen_reg_rtx (SImode); | |
5886 | emit_insn (gen_one_cmplsi2 (imm12_mask, uimm_mask)); | |
5887 | ||
5888 | rtx fixup_value = force_reg (SImode, gen_int_mode (IMM_REACH/2, SImode)); | |
5889 | ||
5890 | /* Gen lui t2, hi(chain). */ | |
5891 | rtx hi_chain = riscv_force_binary (SImode, PLUS, chain_value, | |
5892 | fixup_value); | |
5893 | hi_chain = riscv_force_binary (SImode, AND, hi_chain, | |
5894 | uimm_mask); | |
5895 | lui_hi_chain_code = OPCODE_LUI | (STATIC_CHAIN_REGNUM << SHIFT_RD); | |
5896 | rtx lui_hi_chain = riscv_force_binary (SImode, IOR, hi_chain, | |
5897 | gen_int_mode (lui_hi_chain_code, SImode)); | |
5898 | ||
5899 | mem = adjust_address (m_tramp, SImode, 0); | |
28bddf0e | 5900 | riscv_emit_move (mem, riscv_swap_instruction (lui_hi_chain)); |
09cae750 | 5901 | |
207de839 | 5902 | /* Gen lui t0, hi(func). */ |
09cae750 PD |
5903 | rtx hi_func = riscv_force_binary (SImode, PLUS, target_function, |
5904 | fixup_value); | |
5905 | hi_func = riscv_force_binary (SImode, AND, hi_func, | |
5906 | uimm_mask); | |
5907 | lui_hi_func_code = OPCODE_LUI | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RD); | |
5908 | rtx lui_hi_func = riscv_force_binary (SImode, IOR, hi_func, | |
5909 | gen_int_mode (lui_hi_func_code, SImode)); | |
5910 | ||
5911 | mem = adjust_address (m_tramp, SImode, 1 * GET_MODE_SIZE (SImode)); | |
28bddf0e | 5912 | riscv_emit_move (mem, riscv_swap_instruction (lui_hi_func)); |
09cae750 PD |
5913 | |
5914 | /* Gen addi t2, t2, lo(chain). */ | |
5915 | rtx lo_chain = riscv_force_binary (SImode, AND, chain_value, | |
5916 | imm12_mask); | |
5917 | lo_chain = riscv_force_binary (SImode, ASHIFT, lo_chain, GEN_INT (20)); | |
5918 | ||
5919 | lo_chain_code = OPCODE_ADDI | |
5920 | | (STATIC_CHAIN_REGNUM << SHIFT_RD) | |
5921 | | (STATIC_CHAIN_REGNUM << SHIFT_RS1); | |
5922 | ||
5923 | rtx addi_lo_chain = riscv_force_binary (SImode, IOR, lo_chain, | |
5924 | force_reg (SImode, GEN_INT (lo_chain_code))); | |
5925 | ||
5926 | mem = adjust_address (m_tramp, SImode, 2 * GET_MODE_SIZE (SImode)); | |
28bddf0e | 5927 | riscv_emit_move (mem, riscv_swap_instruction (addi_lo_chain)); |
09cae750 | 5928 | |
207de839 | 5929 | /* Gen jr t0, lo(func). */ |
09cae750 PD |
5930 | rtx lo_func = riscv_force_binary (SImode, AND, target_function, |
5931 | imm12_mask); | |
5932 | lo_func = riscv_force_binary (SImode, ASHIFT, lo_func, GEN_INT (20)); | |
5933 | ||
5934 | lo_func_code = OPCODE_JALR | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RS1); | |
5935 | ||
5936 | rtx jr_lo_func = riscv_force_binary (SImode, IOR, lo_func, | |
5937 | force_reg (SImode, GEN_INT (lo_func_code))); | |
5938 | ||
5939 | mem = adjust_address (m_tramp, SImode, 3 * GET_MODE_SIZE (SImode)); | |
28bddf0e | 5940 | riscv_emit_move (mem, riscv_swap_instruction (jr_lo_func)); |
09cae750 PD |
5941 | } |
5942 | else | |
5943 | { | |
5944 | static_chain_offset = TRAMPOLINE_CODE_SIZE; | |
5945 | target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode); | |
5946 | ||
5947 | /* auipc t2, 0 | |
207de839 | 5948 | l[wd] t0, target_function_offset(t2) |
09cae750 | 5949 | l[wd] t2, static_chain_offset(t2) |
207de839 | 5950 | jr t0 |
09cae750 PD |
5951 | */ |
5952 | trampoline[0] = OPCODE_AUIPC | (STATIC_CHAIN_REGNUM << SHIFT_RD); | |
5953 | trampoline[1] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) | |
5954 | | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RD) | |
5955 | | (STATIC_CHAIN_REGNUM << SHIFT_RS1) | |
5956 | | (target_function_offset << SHIFT_IMM); | |
5957 | trampoline[2] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) | |
5958 | | (STATIC_CHAIN_REGNUM << SHIFT_RD) | |
5959 | | (STATIC_CHAIN_REGNUM << SHIFT_RS1) | |
5960 | | (static_chain_offset << SHIFT_IMM); | |
5961 | trampoline[3] = OPCODE_JALR | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RS1); | |
5962 | ||
5963 | /* Copy the trampoline code. */ | |
5964 | for (i = 0; i < ARRAY_SIZE (trampoline); i++) | |
5965 | { | |
28bddf0e MC |
5966 | if (BYTES_BIG_ENDIAN) |
5967 | trampoline[i] = __builtin_bswap32(trampoline[i]); | |
09cae750 PD |
5968 | mem = adjust_address (m_tramp, SImode, i * GET_MODE_SIZE (SImode)); |
5969 | riscv_emit_move (mem, gen_int_mode (trampoline[i], SImode)); | |
5970 | } | |
5971 | ||
5972 | /* Set up the static chain pointer field. */ | |
5973 | mem = adjust_address (m_tramp, ptr_mode, static_chain_offset); | |
5974 | riscv_emit_move (mem, chain_value); | |
5975 | ||
5976 | /* Set up the target function field. */ | |
5977 | mem = adjust_address (m_tramp, ptr_mode, target_function_offset); | |
5978 | riscv_emit_move (mem, XEXP (DECL_RTL (fndecl), 0)); | |
5979 | } | |
5980 | ||
5981 | /* Flush the code part of the trampoline. */ | |
5982 | emit_insn (gen_add3_insn (end_addr, addr, GEN_INT (TRAMPOLINE_SIZE))); | |
5983 | emit_insn (gen_clear_cache (addr, end_addr)); | |
5984 | } | |
5985 | ||
09cae750 PD |
5986 | /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ |
5987 | ||
5988 | static bool | |
5989 | riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, | |
5990 | tree exp ATTRIBUTE_UNUSED) | |
5991 | { | |
c8a0c7b6 | 5992 | /* Don't use sibcalls when use save-restore routine. */ |
09cae750 | 5993 | if (TARGET_SAVE_RESTORE) |
c8a0c7b6 | 5994 | return false; |
09cae750 | 5995 | |
d0ebdd9f | 5996 | /* Don't use sibcall for naked functions. */ |
8cad5b14 KC |
5997 | if (cfun->machine->naked_p) |
5998 | return false; | |
5999 | ||
d0ebdd9f JW |
6000 | /* Don't use sibcall for interrupt functions. */ |
6001 | if (cfun->machine->interrupt_handler_p) | |
6002 | return false; | |
6003 | ||
09cae750 PD |
6004 | return true; |
6005 | } | |
6006 | ||
31215daa | 6007 | /* Get the interrupt type, return UNKNOWN_MODE if it's not |
8528f27b KC |
6008 | interrupt function. */ |
6009 | static enum riscv_privilege_levels | |
6010 | riscv_get_interrupt_type (tree decl) | |
6011 | { | |
6012 | gcc_assert (decl != NULL_TREE); | |
6013 | ||
6014 | if ((TREE_CODE(decl) != FUNCTION_DECL) | |
6015 | || (!riscv_interrupt_type_p (TREE_TYPE (decl)))) | |
6016 | return UNKNOWN_MODE; | |
6017 | ||
6018 | tree attr_args | |
6019 | = TREE_VALUE (lookup_attribute ("interrupt", | |
6020 | TYPE_ATTRIBUTES (TREE_TYPE (decl)))); | |
6021 | ||
6022 | if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE) | |
6023 | { | |
6024 | const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args)); | |
6025 | ||
6026 | if (!strcmp (string, "user")) | |
6027 | return USER_MODE; | |
6028 | else if (!strcmp (string, "supervisor")) | |
6029 | return SUPERVISOR_MODE; | |
6030 | else /* Must be "machine". */ | |
6031 | return MACHINE_MODE; | |
6032 | } | |
6033 | else | |
6034 | /* Interrupt attributes are machine mode by default. */ | |
6035 | return MACHINE_MODE; | |
6036 | } | |
6037 | ||
8cad5b14 KC |
6038 | /* Implement `TARGET_SET_CURRENT_FUNCTION'. */ |
6039 | /* Sanity cheching for above function attributes. */ | |
6040 | static void | |
6041 | riscv_set_current_function (tree decl) | |
6042 | { | |
6043 | if (decl == NULL_TREE | |
6044 | || current_function_decl == NULL_TREE | |
6045 | || current_function_decl == error_mark_node | |
d0ebdd9f JW |
6046 | || ! cfun->machine |
6047 | || cfun->machine->attributes_checked_p) | |
8cad5b14 KC |
6048 | return; |
6049 | ||
6050 | cfun->machine->naked_p = riscv_naked_function_p (decl); | |
d0ebdd9f JW |
6051 | cfun->machine->interrupt_handler_p |
6052 | = riscv_interrupt_type_p (TREE_TYPE (decl)); | |
6053 | ||
6054 | if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p) | |
6055 | error ("function attributes %qs and %qs are mutually exclusive", | |
6056 | "interrupt", "naked"); | |
6057 | ||
6058 | if (cfun->machine->interrupt_handler_p) | |
6059 | { | |
d0ebdd9f | 6060 | tree ret = TREE_TYPE (TREE_TYPE (decl)); |
ec74725c | 6061 | tree args = TYPE_ARG_TYPES (TREE_TYPE (decl)); |
d0ebdd9f JW |
6062 | |
6063 | if (TREE_CODE (ret) != VOID_TYPE) | |
6064 | error ("%qs function cannot return a value", "interrupt"); | |
6065 | ||
6066 | if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) | |
6067 | error ("%qs function cannot have arguments", "interrupt"); | |
ec74725c | 6068 | |
8528f27b KC |
6069 | cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl); |
6070 | ||
6071 | gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE); | |
d0ebdd9f JW |
6072 | } |
6073 | ||
6074 | /* Don't print the above diagnostics more than once. */ | |
6075 | cfun->machine->attributes_checked_p = 1; | |
8cad5b14 KC |
6076 | } |
6077 | ||
8528f27b KC |
6078 | /* Implement TARGET_MERGE_DECL_ATTRIBUTES. */ |
6079 | static tree | |
6080 | riscv_merge_decl_attributes (tree olddecl, tree newdecl) | |
6081 | { | |
6082 | tree combined_attrs; | |
6083 | ||
6084 | enum riscv_privilege_levels old_interrupt_type | |
6085 | = riscv_get_interrupt_type (olddecl); | |
6086 | enum riscv_privilege_levels new_interrupt_type | |
6087 | = riscv_get_interrupt_type (newdecl); | |
6088 | ||
6089 | /* Check old and new has same interrupt type. */ | |
6090 | if ((old_interrupt_type != UNKNOWN_MODE) | |
6091 | && (new_interrupt_type != UNKNOWN_MODE) | |
6092 | && (old_interrupt_type != new_interrupt_type)) | |
31215daa | 6093 | error ("%qs function cannot have different interrupt type", "interrupt"); |
8528f27b KC |
6094 | |
6095 | /* Create combined attributes. */ | |
6096 | combined_attrs = merge_attributes (DECL_ATTRIBUTES (olddecl), | |
6097 | DECL_ATTRIBUTES (newdecl)); | |
6098 | ||
6099 | return combined_attrs; | |
6100 | } | |
6101 | ||
09cae750 PD |
6102 | /* Implement TARGET_CANNOT_COPY_INSN_P. */ |
6103 | ||
6104 | static bool | |
6105 | riscv_cannot_copy_insn_p (rtx_insn *insn) | |
6106 | { | |
6107 | return recog_memoized (insn) >= 0 && get_attr_cannot_copy (insn); | |
6108 | } | |
6109 | ||
e0bd6c9f RS |
6110 | /* Implement TARGET_SLOW_UNALIGNED_ACCESS. */ |
6111 | ||
6112 | static bool | |
6113 | riscv_slow_unaligned_access (machine_mode, unsigned int) | |
6114 | { | |
6115 | return riscv_slow_unaligned_access_p; | |
6116 | } | |
6117 | ||
0d803030 RS |
6118 | /* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ |
6119 | ||
6120 | static bool | |
6121 | riscv_can_change_mode_class (machine_mode, machine_mode, reg_class_t rclass) | |
6122 | { | |
6123 | return !reg_classes_intersect_p (FP_REGS, rclass); | |
6124 | } | |
6125 | ||
58e17cf8 RS |
6126 | |
6127 | /* Implement TARGET_CONSTANT_ALIGNMENT. */ | |
6128 | ||
6129 | static HOST_WIDE_INT | |
6130 | riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align) | |
6131 | { | |
ffbb9818 ID |
6132 | if ((TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR) |
6133 | && (riscv_align_data_type == riscv_align_data_type_xlen)) | |
58e17cf8 RS |
6134 | return MAX (align, BITS_PER_WORD); |
6135 | return align; | |
6136 | } | |
6137 | ||
860edc46 KC |
6138 | /* Implement TARGET_PROMOTE_FUNCTION_MODE. */ |
6139 | ||
6140 | /* This function is equivalent to default_promote_function_mode_always_promote | |
6141 | except that it returns a promoted mode even if type is NULL_TREE. This is | |
6142 | needed by libcalls which have no type (only a mode) such as fixed conversion | |
6143 | routines that take a signed or unsigned char/short/int argument and convert | |
6144 | it to a fixed type. */ | |
6145 | ||
6146 | static machine_mode | |
6147 | riscv_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, | |
6148 | machine_mode mode, | |
6149 | int *punsignedp ATTRIBUTE_UNUSED, | |
6150 | const_tree fntype ATTRIBUTE_UNUSED, | |
6151 | int for_return ATTRIBUTE_UNUSED) | |
6152 | { | |
6153 | int unsignedp; | |
6154 | ||
6155 | if (type != NULL_TREE) | |
6156 | return promote_mode (type, mode, punsignedp); | |
6157 | ||
6158 | unsignedp = *punsignedp; | |
3496ca4e | 6159 | PROMOTE_MODE (as_a <scalar_mode> (mode), unsignedp, type); |
860edc46 KC |
6160 | *punsignedp = unsignedp; |
6161 | return mode; | |
6162 | } | |
6163 | ||
e18a6d14 AB |
6164 | /* Implement TARGET_MACHINE_DEPENDENT_REORG. */ |
6165 | ||
6166 | static void | |
6167 | riscv_reorg (void) | |
6168 | { | |
6169 | /* Do nothing unless we have -msave-restore */ | |
6170 | if (TARGET_SAVE_RESTORE) | |
6171 | riscv_remove_unneeded_save_restore_calls (); | |
6172 | } | |
6173 | ||
e0a5b313 KC |
6174 | /* Return nonzero if register FROM_REGNO can be renamed to register |
6175 | TO_REGNO. */ | |
6176 | ||
6177 | bool | |
6178 | riscv_hard_regno_rename_ok (unsigned from_regno ATTRIBUTE_UNUSED, | |
6179 | unsigned to_regno) | |
6180 | { | |
6181 | /* Interrupt functions can only use registers that have already been | |
6182 | saved by the prologue, even if they would normally be | |
6183 | call-clobbered. */ | |
6184 | return !cfun->machine->interrupt_handler_p || df_regs_ever_live_p (to_regno); | |
6185 | } | |
6186 | ||
de6320a8 CB |
6187 | /* Implement TARGET_NEW_ADDRESS_PROFITABLE_P. */ |
6188 | ||
6189 | bool | |
6190 | riscv_new_address_profitable_p (rtx memref, rtx_insn *insn, rtx new_addr) | |
6191 | { | |
6192 | /* Prefer old address if it is less expensive. */ | |
6193 | addr_space_t as = MEM_ADDR_SPACE (memref); | |
6194 | bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)); | |
6195 | int old_cost = address_cost (XEXP (memref, 0), GET_MODE (memref), as, speed); | |
6196 | int new_cost = address_cost (new_addr, GET_MODE (memref), as, speed); | |
6197 | return new_cost <= old_cost; | |
6198 | } | |
6199 | ||
d0e0c130 KC |
6200 | /* Helper function for generating gpr_save pattern. */ |
6201 | ||
6202 | rtx | |
6203 | riscv_gen_gpr_save_insn (struct riscv_frame_info *frame) | |
6204 | { | |
6205 | unsigned count = riscv_save_libcall_count (frame->mask); | |
6206 | /* 1 for unspec 2 for clobber t0/t1 and 1 for ra. */ | |
6207 | unsigned veclen = 1 + 2 + 1 + count; | |
6208 | rtvec vec = rtvec_alloc (veclen); | |
6209 | ||
6210 | gcc_assert (veclen <= ARRAY_SIZE (gpr_save_reg_order)); | |
6211 | ||
6212 | RTVEC_ELT (vec, 0) = | |
6213 | gen_rtx_UNSPEC_VOLATILE (VOIDmode, | |
dcf41a4e | 6214 | gen_rtvec (1, GEN_INT (count)), UNSPECV_GPR_SAVE); |
d0e0c130 | 6215 | |
82a3008e | 6216 | for (unsigned i = 1; i < veclen; ++i) |
d0e0c130 KC |
6217 | { |
6218 | unsigned regno = gpr_save_reg_order[i]; | |
6219 | rtx reg = gen_rtx_REG (Pmode, regno); | |
6220 | rtx elt; | |
6221 | ||
6222 | /* t0 and t1 are CLOBBERs, others are USEs. */ | |
6223 | if (i < 3) | |
6224 | elt = gen_rtx_CLOBBER (Pmode, reg); | |
6225 | else | |
6226 | elt = gen_rtx_USE (Pmode, reg); | |
6227 | ||
6228 | RTVEC_ELT (vec, i) = elt; | |
6229 | } | |
6230 | ||
6231 | /* Largest number of caller-save register must set in mask if we are | |
6232 | not using __riscv_save_0. */ | |
6233 | gcc_assert ((count == 0) || | |
6234 | BITSET_P (frame->mask, gpr_save_reg_order[veclen - 1])); | |
6235 | ||
6236 | return gen_rtx_PARALLEL (VOIDmode, vec); | |
6237 | } | |
6238 | ||
6239 | /* Return true if it's valid gpr_save pattern. */ | |
6240 | ||
6241 | bool | |
6242 | riscv_gpr_save_operation_p (rtx op) | |
6243 | { | |
82a3008e | 6244 | unsigned len = XVECLEN (op, 0); |
beaf12b4 KC |
6245 | |
6246 | if (len > ARRAY_SIZE (gpr_save_reg_order)) | |
6247 | return false; | |
6248 | ||
82a3008e | 6249 | for (unsigned i = 0; i < len; i++) |
d0e0c130 KC |
6250 | { |
6251 | rtx elt = XVECEXP (op, 0, i); | |
6252 | if (i == 0) | |
6253 | { | |
6254 | /* First element in parallel is unspec. */ | |
6255 | if (GET_CODE (elt) != UNSPEC_VOLATILE | |
6256 | || GET_CODE (XVECEXP (elt, 0, 0)) != CONST_INT | |
6257 | || XINT (elt, 1) != UNSPECV_GPR_SAVE) | |
6258 | return false; | |
6259 | } | |
6260 | else | |
6261 | { | |
6262 | /* Two CLOBBER and USEs, must check the order. */ | |
6263 | unsigned expect_code = i < 3 ? CLOBBER : USE; | |
6264 | if (GET_CODE (elt) != expect_code | |
6265 | || !REG_P (XEXP (elt, 1)) | |
6266 | || (REGNO (XEXP (elt, 1)) != gpr_save_reg_order[i])) | |
6267 | return false; | |
6268 | } | |
6269 | break; | |
6270 | } | |
6271 | return true; | |
6272 | } | |
6273 | ||
dcf0dde4 JW |
6274 | /* Implement TARGET_ASAN_SHADOW_OFFSET. */ |
6275 | ||
6276 | static unsigned HOST_WIDE_INT | |
6277 | riscv_asan_shadow_offset (void) | |
6278 | { | |
6279 | /* We only have libsanitizer support for RV64 at present. | |
6280 | ||
6281 | This number must match kRiscv*_ShadowOffset* in the file | |
6282 | libsanitizer/asan/asan_mapping.h which is currently 1<<29 for rv64, | |
6283 | even though 1<<36 makes more sense. */ | |
6284 | return TARGET_64BIT ? (HOST_WIDE_INT_1 << 29) : 0; | |
6285 | } | |
6286 | ||
27d68a60 KC |
6287 | /* Implement TARGET_MANGLE_TYPE. */ |
6288 | ||
6289 | static const char * | |
6290 | riscv_mangle_type (const_tree type) | |
6291 | { | |
6292 | /* Half-precision float, _Float16 is "DF16_". */ | |
6293 | if (TREE_CODE (type) == REAL_TYPE && TYPE_PRECISION (type) == 16) | |
6294 | return "DF16_"; | |
6295 | ||
03f33657 JZZ |
6296 | /* Mangle all vector type for vector extension. */ |
6297 | /* The mangle name follows the rule of RVV LLVM | |
6298 | that is "u" + length of (abi_name) + abi_name. */ | |
6299 | if (TYPE_NAME (type) != NULL) | |
6300 | { | |
6301 | const char *res = riscv_vector::mangle_builtin_type (type); | |
6302 | if (res) | |
6303 | return res; | |
6304 | } | |
6305 | ||
27d68a60 KC |
6306 | /* Use the default mangling. */ |
6307 | return NULL; | |
6308 | } | |
6309 | ||
6310 | /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */ | |
6311 | ||
6312 | static bool | |
6313 | riscv_scalar_mode_supported_p (scalar_mode mode) | |
6314 | { | |
6315 | if (mode == HFmode) | |
6316 | return true; | |
6317 | else | |
6318 | return default_scalar_mode_supported_p (mode); | |
6319 | } | |
6320 | ||
6321 | /* Implement TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P - return TRUE | |
6322 | if MODE is HFmode, and punt to the generic implementation otherwise. */ | |
6323 | ||
6324 | static bool | |
6325 | riscv_libgcc_floating_mode_supported_p (scalar_float_mode mode) | |
6326 | { | |
6327 | if (mode == HFmode) | |
6328 | return true; | |
6329 | else | |
6330 | return default_libgcc_floating_mode_supported_p (mode); | |
6331 | } | |
6332 | ||
6333 | /* Set the value of FLT_EVAL_METHOD. | |
6334 | ISO/IEC TS 18661-3 defines two values that we'd like to make use of: | |
6335 | ||
6336 | 0: evaluate all operations and constants, whose semantic type has at | |
6337 | most the range and precision of type float, to the range and | |
6338 | precision of float; evaluate all other operations and constants to | |
6339 | the range and precision of the semantic type; | |
6340 | ||
6341 | N, where _FloatN is a supported interchange floating type | |
6342 | evaluate all operations and constants, whose semantic type has at | |
6343 | most the range and precision of _FloatN type, to the range and | |
6344 | precision of the _FloatN type; evaluate all other operations and | |
6345 | constants to the range and precision of the semantic type; | |
6346 | ||
6347 | If we have the zfh extensions then we support _Float16 in native | |
6348 | precision, so we should set this to 16. */ | |
6349 | static enum flt_eval_method | |
6350 | riscv_excess_precision (enum excess_precision_type type) | |
6351 | { | |
6352 | switch (type) | |
6353 | { | |
6354 | case EXCESS_PRECISION_TYPE_FAST: | |
6355 | case EXCESS_PRECISION_TYPE_STANDARD: | |
bd159a76 KC |
6356 | return (TARGET_ZFH ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 |
6357 | : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT); | |
27d68a60 | 6358 | case EXCESS_PRECISION_TYPE_IMPLICIT: |
75c08994 | 6359 | case EXCESS_PRECISION_TYPE_FLOAT16: |
27d68a60 KC |
6360 | return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16; |
6361 | default: | |
6362 | gcc_unreachable (); | |
6363 | } | |
6364 | return FLT_EVAL_METHOD_UNPREDICTABLE; | |
6365 | } | |
6366 | ||
6367 | /* Implement TARGET_FLOATN_MODE. */ | |
6368 | static opt_scalar_float_mode | |
6369 | riscv_floatn_mode (int n, bool extended) | |
6370 | { | |
6371 | if (!extended && n == 16) | |
6372 | return HFmode; | |
6373 | ||
6374 | return default_floatn_mode (n, extended); | |
6375 | } | |
6376 | ||
6377 | static void | |
6378 | riscv_init_libfuncs (void) | |
6379 | { | |
6380 | /* Half-precision float operations. The compiler handles all operations | |
6381 | with NULL libfuncs by converting to SFmode. */ | |
6382 | ||
6383 | /* Arithmetic. */ | |
6384 | set_optab_libfunc (add_optab, HFmode, NULL); | |
6385 | set_optab_libfunc (sdiv_optab, HFmode, NULL); | |
6386 | set_optab_libfunc (smul_optab, HFmode, NULL); | |
6387 | set_optab_libfunc (neg_optab, HFmode, NULL); | |
6388 | set_optab_libfunc (sub_optab, HFmode, NULL); | |
6389 | ||
6390 | /* Comparisons. */ | |
6391 | set_optab_libfunc (eq_optab, HFmode, NULL); | |
6392 | set_optab_libfunc (ne_optab, HFmode, NULL); | |
6393 | set_optab_libfunc (lt_optab, HFmode, NULL); | |
6394 | set_optab_libfunc (le_optab, HFmode, NULL); | |
6395 | set_optab_libfunc (ge_optab, HFmode, NULL); | |
6396 | set_optab_libfunc (gt_optab, HFmode, NULL); | |
6397 | set_optab_libfunc (unord_optab, HFmode, NULL); | |
6398 | } | |
6399 | ||
b4feb49c | 6400 | #if CHECKING_P |
6401 | void | |
6402 | riscv_reinit (void) | |
6403 | { | |
6404 | riscv_option_override (); | |
6405 | init_adjust_machine_modes (); | |
6406 | init_derived_machine_modes (); | |
6407 | reinit_regs (); | |
6408 | init_optabs (); | |
6409 | } | |
6410 | #endif | |
6411 | ||
6412 | #if CHECKING_P | |
6413 | #undef TARGET_RUN_TARGET_SELFTESTS | |
6414 | #define TARGET_RUN_TARGET_SELFTESTS selftest::riscv_run_selftests | |
6415 | #endif /* #if CHECKING_P */ | |
6416 | ||
03f33657 JZZ |
6417 | /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */ |
6418 | ||
6419 | static bool | |
6420 | riscv_vector_mode_supported_p (machine_mode mode) | |
6421 | { | |
6422 | if (TARGET_VECTOR) | |
6423 | return riscv_v_ext_enabled_vector_mode_p (mode); | |
6424 | ||
6425 | return false; | |
6426 | } | |
6427 | ||
6428 | /* Implement TARGET_VERIFY_TYPE_CONTEXT. */ | |
6429 | ||
6430 | static bool | |
6431 | riscv_verify_type_context (location_t loc, type_context_kind context, | |
6432 | const_tree type, bool silent_p) | |
6433 | { | |
6434 | return riscv_vector::verify_type_context (loc, context, type, silent_p); | |
6435 | } | |
6436 | ||
6437 | /* Implement TARGET_VECTOR_ALIGNMENT. */ | |
6438 | ||
6439 | static HOST_WIDE_INT | |
6440 | riscv_vector_alignment (const_tree type) | |
6441 | { | |
6442 | /* ??? Checking the mode isn't ideal, but VECTOR_BOOLEAN_TYPE_P can | |
6443 | be set for non-predicate vectors of booleans. Modes are the most | |
6444 | direct way we have of identifying real RVV predicate types. */ | |
6445 | /* FIXME: RVV didn't mention the alignment of bool, we uses | |
6446 | one byte align. */ | |
6447 | if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_BOOL) | |
6448 | return 8; | |
6449 | ||
6450 | widest_int min_size | |
6451 | = constant_lower_bound (wi::to_poly_widest (TYPE_SIZE (type))); | |
6452 | return wi::umin (min_size, 128).to_uhwi (); | |
6453 | } | |
6454 | ||
f556cd8b JZZ |
6455 | /* Implement REGMODE_NATURAL_SIZE. */ |
6456 | ||
6457 | poly_uint64 | |
6458 | riscv_regmode_natural_size (machine_mode mode) | |
6459 | { | |
6460 | /* The natural size for RVV data modes is one RVV data vector, | |
6461 | and similarly for predicates. We can't independently modify | |
6462 | anything smaller than that. */ | |
6463 | /* ??? For now, only do this for variable-width RVV registers. | |
6464 | Doing it for constant-sized registers breaks lower-subreg.c. */ | |
6465 | if (!riscv_vector_chunks.is_constant () && riscv_v_ext_vector_mode_p (mode)) | |
6466 | return BYTES_PER_RISCV_VECTOR; | |
6467 | return UNITS_PER_WORD; | |
6468 | } | |
6469 | ||
09cae750 PD |
6470 | /* Initialize the GCC target structure. */ |
6471 | #undef TARGET_ASM_ALIGNED_HI_OP | |
6472 | #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" | |
6473 | #undef TARGET_ASM_ALIGNED_SI_OP | |
6474 | #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" | |
6475 | #undef TARGET_ASM_ALIGNED_DI_OP | |
6476 | #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t" | |
6477 | ||
6478 | #undef TARGET_OPTION_OVERRIDE | |
6479 | #define TARGET_OPTION_OVERRIDE riscv_option_override | |
6480 | ||
6481 | #undef TARGET_LEGITIMIZE_ADDRESS | |
6482 | #define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address | |
6483 | ||
6484 | #undef TARGET_SCHED_ISSUE_RATE | |
6485 | #define TARGET_SCHED_ISSUE_RATE riscv_issue_rate | |
6486 | ||
6487 | #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
6488 | #define TARGET_FUNCTION_OK_FOR_SIBCALL riscv_function_ok_for_sibcall | |
6489 | ||
8cad5b14 KC |
6490 | #undef TARGET_SET_CURRENT_FUNCTION |
6491 | #define TARGET_SET_CURRENT_FUNCTION riscv_set_current_function | |
6492 | ||
09cae750 PD |
6493 | #undef TARGET_REGISTER_MOVE_COST |
6494 | #define TARGET_REGISTER_MOVE_COST riscv_register_move_cost | |
6495 | #undef TARGET_MEMORY_MOVE_COST | |
6496 | #define TARGET_MEMORY_MOVE_COST riscv_memory_move_cost | |
6497 | #undef TARGET_RTX_COSTS | |
6498 | #define TARGET_RTX_COSTS riscv_rtx_costs | |
6499 | #undef TARGET_ADDRESS_COST | |
6500 | #define TARGET_ADDRESS_COST riscv_address_cost | |
6501 | ||
09cae750 PD |
6502 | #undef TARGET_ASM_FILE_START |
6503 | #define TARGET_ASM_FILE_START riscv_file_start | |
6504 | #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE | |
6505 | #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true | |
6506 | ||
6507 | #undef TARGET_EXPAND_BUILTIN_VA_START | |
6508 | #define TARGET_EXPAND_BUILTIN_VA_START riscv_va_start | |
6509 | ||
6510 | #undef TARGET_PROMOTE_FUNCTION_MODE | |
860edc46 | 6511 | #define TARGET_PROMOTE_FUNCTION_MODE riscv_promote_function_mode |
09cae750 PD |
6512 | |
6513 | #undef TARGET_RETURN_IN_MEMORY | |
6514 | #define TARGET_RETURN_IN_MEMORY riscv_return_in_memory | |
6515 | ||
6516 | #undef TARGET_ASM_OUTPUT_MI_THUNK | |
6517 | #define TARGET_ASM_OUTPUT_MI_THUNK riscv_output_mi_thunk | |
6518 | #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
6519 | #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true | |
6520 | ||
6521 | #undef TARGET_PRINT_OPERAND | |
6522 | #define TARGET_PRINT_OPERAND riscv_print_operand | |
6523 | #undef TARGET_PRINT_OPERAND_ADDRESS | |
6524 | #define TARGET_PRINT_OPERAND_ADDRESS riscv_print_operand_address | |
473d7aad AP |
6525 | #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P |
6526 | #define TARGET_PRINT_OPERAND_PUNCT_VALID_P riscv_print_operand_punct_valid_p | |
09cae750 PD |
6527 | |
6528 | #undef TARGET_SETUP_INCOMING_VARARGS | |
6529 | #define TARGET_SETUP_INCOMING_VARARGS riscv_setup_incoming_varargs | |
8cad5b14 KC |
6530 | #undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS |
6531 | #define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS riscv_allocate_stack_slots_for_args | |
09cae750 PD |
6532 | #undef TARGET_STRICT_ARGUMENT_NAMING |
6533 | #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true | |
6534 | #undef TARGET_MUST_PASS_IN_STACK | |
6535 | #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size | |
6536 | #undef TARGET_PASS_BY_REFERENCE | |
6537 | #define TARGET_PASS_BY_REFERENCE riscv_pass_by_reference | |
6538 | #undef TARGET_ARG_PARTIAL_BYTES | |
6539 | #define TARGET_ARG_PARTIAL_BYTES riscv_arg_partial_bytes | |
6540 | #undef TARGET_FUNCTION_ARG | |
6541 | #define TARGET_FUNCTION_ARG riscv_function_arg | |
6542 | #undef TARGET_FUNCTION_ARG_ADVANCE | |
6543 | #define TARGET_FUNCTION_ARG_ADVANCE riscv_function_arg_advance | |
6544 | #undef TARGET_FUNCTION_ARG_BOUNDARY | |
6545 | #define TARGET_FUNCTION_ARG_BOUNDARY riscv_function_arg_boundary | |
6546 | ||
6547 | /* The generic ELF target does not always have TLS support. */ | |
6548 | #ifdef HAVE_AS_TLS | |
6549 | #undef TARGET_HAVE_TLS | |
6550 | #define TARGET_HAVE_TLS true | |
6551 | #endif | |
6552 | ||
6553 | #undef TARGET_CANNOT_FORCE_CONST_MEM | |
6554 | #define TARGET_CANNOT_FORCE_CONST_MEM riscv_cannot_force_const_mem | |
6555 | ||
6556 | #undef TARGET_LEGITIMATE_CONSTANT_P | |
6557 | #define TARGET_LEGITIMATE_CONSTANT_P riscv_legitimate_constant_p | |
6558 | ||
6559 | #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P | |
6560 | #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true | |
6561 | ||
6562 | #undef TARGET_LEGITIMATE_ADDRESS_P | |
6563 | #define TARGET_LEGITIMATE_ADDRESS_P riscv_legitimate_address_p | |
6564 | ||
6565 | #undef TARGET_CAN_ELIMINATE | |
6566 | #define TARGET_CAN_ELIMINATE riscv_can_eliminate | |
6567 | ||
6568 | #undef TARGET_CONDITIONAL_REGISTER_USAGE | |
6569 | #define TARGET_CONDITIONAL_REGISTER_USAGE riscv_conditional_register_usage | |
6570 | ||
6571 | #undef TARGET_CLASS_MAX_NREGS | |
6572 | #define TARGET_CLASS_MAX_NREGS riscv_class_max_nregs | |
6573 | ||
6574 | #undef TARGET_TRAMPOLINE_INIT | |
6575 | #define TARGET_TRAMPOLINE_INIT riscv_trampoline_init | |
6576 | ||
6577 | #undef TARGET_IN_SMALL_DATA_P | |
6578 | #define TARGET_IN_SMALL_DATA_P riscv_in_small_data_p | |
6579 | ||
6cb0725c AW |
6580 | #undef TARGET_HAVE_SRODATA_SECTION |
6581 | #define TARGET_HAVE_SRODATA_SECTION true | |
6582 | ||
6583 | #undef TARGET_ASM_SELECT_SECTION | |
6584 | #define TARGET_ASM_SELECT_SECTION riscv_select_section | |
6585 | ||
adce62f5 KP |
6586 | #undef TARGET_ASM_UNIQUE_SECTION |
6587 | #define TARGET_ASM_UNIQUE_SECTION riscv_unique_section | |
6588 | ||
09cae750 PD |
6589 | #undef TARGET_ASM_SELECT_RTX_SECTION |
6590 | #define TARGET_ASM_SELECT_RTX_SECTION riscv_elf_select_rtx_section | |
6591 | ||
6592 | #undef TARGET_MIN_ANCHOR_OFFSET | |
6593 | #define TARGET_MIN_ANCHOR_OFFSET (-IMM_REACH/2) | |
6594 | ||
6595 | #undef TARGET_MAX_ANCHOR_OFFSET | |
6596 | #define TARGET_MAX_ANCHOR_OFFSET (IMM_REACH/2-1) | |
6597 | ||
6598 | #undef TARGET_REGISTER_PRIORITY | |
6599 | #define TARGET_REGISTER_PRIORITY riscv_register_priority | |
6600 | ||
6601 | #undef TARGET_CANNOT_COPY_INSN_P | |
6602 | #define TARGET_CANNOT_COPY_INSN_P riscv_cannot_copy_insn_p | |
6603 | ||
6604 | #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV | |
6605 | #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV riscv_atomic_assign_expand_fenv | |
6606 | ||
6607 | #undef TARGET_INIT_BUILTINS | |
6608 | #define TARGET_INIT_BUILTINS riscv_init_builtins | |
6609 | ||
6610 | #undef TARGET_BUILTIN_DECL | |
6611 | #define TARGET_BUILTIN_DECL riscv_builtin_decl | |
6612 | ||
6613 | #undef TARGET_EXPAND_BUILTIN | |
6614 | #define TARGET_EXPAND_BUILTIN riscv_expand_builtin | |
6615 | ||
c43f4279 RS |
6616 | #undef TARGET_HARD_REGNO_NREGS |
6617 | #define TARGET_HARD_REGNO_NREGS riscv_hard_regno_nregs | |
f939c3e6 RS |
6618 | #undef TARGET_HARD_REGNO_MODE_OK |
6619 | #define TARGET_HARD_REGNO_MODE_OK riscv_hard_regno_mode_ok | |
6620 | ||
99e1629f RS |
6621 | #undef TARGET_MODES_TIEABLE_P |
6622 | #define TARGET_MODES_TIEABLE_P riscv_modes_tieable_p | |
6623 | ||
e0bd6c9f RS |
6624 | #undef TARGET_SLOW_UNALIGNED_ACCESS |
6625 | #define TARGET_SLOW_UNALIGNED_ACCESS riscv_slow_unaligned_access | |
6626 | ||
f15643d4 RS |
6627 | #undef TARGET_SECONDARY_MEMORY_NEEDED |
6628 | #define TARGET_SECONDARY_MEMORY_NEEDED riscv_secondary_memory_needed | |
6629 | ||
0d803030 RS |
6630 | #undef TARGET_CAN_CHANGE_MODE_CLASS |
6631 | #define TARGET_CAN_CHANGE_MODE_CLASS riscv_can_change_mode_class | |
6632 | ||
58e17cf8 RS |
6633 | #undef TARGET_CONSTANT_ALIGNMENT |
6634 | #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment | |
6635 | ||
8528f27b KC |
6636 | #undef TARGET_MERGE_DECL_ATTRIBUTES |
6637 | #define TARGET_MERGE_DECL_ATTRIBUTES riscv_merge_decl_attributes | |
6638 | ||
8cad5b14 KC |
6639 | #undef TARGET_ATTRIBUTE_TABLE |
6640 | #define TARGET_ATTRIBUTE_TABLE riscv_attribute_table | |
6641 | ||
6642 | #undef TARGET_WARN_FUNC_RETURN | |
6643 | #define TARGET_WARN_FUNC_RETURN riscv_warn_func_return | |
6644 | ||
11fcb8f2 JW |
6645 | /* The low bit is ignored by jump instructions so is safe to use. */ |
6646 | #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS | |
6647 | #define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 | |
6648 | ||
e18a6d14 AB |
6649 | #undef TARGET_MACHINE_DEPENDENT_REORG |
6650 | #define TARGET_MACHINE_DEPENDENT_REORG riscv_reorg | |
6651 | ||
de6320a8 CB |
6652 | #undef TARGET_NEW_ADDRESS_PROFITABLE_P |
6653 | #define TARGET_NEW_ADDRESS_PROFITABLE_P riscv_new_address_profitable_p | |
6654 | ||
27d68a60 KC |
6655 | #undef TARGET_MANGLE_TYPE |
6656 | #define TARGET_MANGLE_TYPE riscv_mangle_type | |
6657 | ||
6658 | #undef TARGET_SCALAR_MODE_SUPPORTED_P | |
6659 | #define TARGET_SCALAR_MODE_SUPPORTED_P riscv_scalar_mode_supported_p | |
6660 | ||
6661 | #undef TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P | |
6662 | #define TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P \ | |
6663 | riscv_libgcc_floating_mode_supported_p | |
6664 | ||
6665 | #undef TARGET_INIT_LIBFUNCS | |
6666 | #define TARGET_INIT_LIBFUNCS riscv_init_libfuncs | |
6667 | ||
6668 | #undef TARGET_C_EXCESS_PRECISION | |
6669 | #define TARGET_C_EXCESS_PRECISION riscv_excess_precision | |
6670 | ||
6671 | #undef TARGET_FLOATN_MODE | |
6672 | #define TARGET_FLOATN_MODE riscv_floatn_mode | |
6673 | ||
dcf0dde4 JW |
6674 | #undef TARGET_ASAN_SHADOW_OFFSET |
6675 | #define TARGET_ASAN_SHADOW_OFFSET riscv_asan_shadow_offset | |
6676 | ||
cd1e2f63 MC |
6677 | #ifdef TARGET_BIG_ENDIAN_DEFAULT |
6678 | #undef TARGET_DEFAULT_TARGET_FLAGS | |
6679 | #define TARGET_DEFAULT_TARGET_FLAGS (MASK_BIG_ENDIAN) | |
6680 | #endif | |
6681 | ||
03f33657 JZZ |
6682 | #undef TARGET_VECTOR_MODE_SUPPORTED_P |
6683 | #define TARGET_VECTOR_MODE_SUPPORTED_P riscv_vector_mode_supported_p | |
6684 | ||
6685 | #undef TARGET_VERIFY_TYPE_CONTEXT | |
6686 | #define TARGET_VERIFY_TYPE_CONTEXT riscv_verify_type_context | |
6687 | ||
6688 | #undef TARGET_VECTOR_ALIGNMENT | |
6689 | #define TARGET_VECTOR_ALIGNMENT riscv_vector_alignment | |
6690 | ||
09cae750 PD |
6691 | struct gcc_target targetm = TARGET_INITIALIZER; |
6692 | ||
6693 | #include "gt-riscv.h" |