1 /* Subroutines used for LoongArch code generation.
2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
4 Based on MIPS and RISC-V target for GNU compiler.
6 This file is part of GCC.
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)
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.
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/>. */
22 #define IN_TARGET_CODE 1
26 #include "coretypes.h"
36 #include "stringpool.h"
43 #include "diagnostic.h"
44 #include "insn-attr.h"
47 #include "fold-const.h"
49 #include "stor-layout.h"
55 #include "common/common-target.h"
56 #include "langhooks.h"
59 #include "sched-int.h"
61 #include "target-globals.h"
62 #include "tree-pass.h"
67 #include "function-abi.h"
69 /* This file should be included last. */
70 #include "target-def.h"
72 /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
73 #define UNSPEC_ADDRESS_P(X) \
74 (GET_CODE (X) == UNSPEC \
75 && XINT (X, 1) >= UNSPEC_ADDRESS_FIRST \
76 && XINT (X, 1) < UNSPEC_ADDRESS_FIRST + NUM_SYMBOL_TYPES)
78 /* Extract the symbol or label from UNSPEC wrapper X. */
79 #define UNSPEC_ADDRESS(X) XVECEXP (X, 0, 0)
81 /* Extract the symbol type from UNSPEC wrapper X. */
82 #define UNSPEC_ADDRESS_TYPE(X) \
83 ((enum loongarch_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
85 /* True if INSN is a loongarch.md pattern or asm statement. */
86 /* ??? This test exists through the compiler, perhaps it should be
88 #define USEFUL_INSN_P(INSN) \
89 (NONDEBUG_INSN_P (INSN) \
90 && GET_CODE (PATTERN (INSN)) != USE \
91 && GET_CODE (PATTERN (INSN)) != CLOBBER)
93 /* True if bit BIT is set in VALUE. */
94 #define BITSET_P(VALUE, BIT) (((VALUE) & (1 << (BIT))) != 0)
96 /* Classifies an address.
99 A natural register + offset address. The register satisfies
100 loongarch_valid_base_register_p and the offset is a const_arith_operand.
103 A base register indexed by (optionally scaled) register.
106 A LO_SUM rtx. The first operand is a valid base register and the second
107 operand is a symbolic address.
110 A signed 16-bit constant address.
113 A constant symbolic address. */
114 enum loongarch_address_type
124 /* Information about an address described by loongarch_address_type. */
125 struct loongarch_address_info
127 enum loongarch_address_type type
;
130 enum loongarch_symbol_type symbol_type
;
133 /* Method of loading instant numbers:
136 Load 0-31 bit of the immediate number.
139 Load 32-51 bit of the immediate number.
142 Load 52-63 bit of the immediate number.
144 enum loongarch_load_imm_method
151 struct loongarch_integer_op
155 /* Represent the result of the immediate count of the load instruction at
157 HOST_WIDE_INT curr_value
;
158 enum loongarch_load_imm_method method
;
161 /* The largest number of operations needed to load an integer constant.
162 The worst accepted case for 64-bit constants is LU12I.W,LU32I.D,LU52I.D,ORI
163 or LU12I.W,LU32I.D,LU52I.D,ADDI.D DECL_ASSEMBLER_NAME. */
164 #define LARCH_MAX_INTEGER_OPS 4
166 /* Arrays that map GCC register numbers to debugger register numbers. */
167 int loongarch_dwarf_regno
[FIRST_PSEUDO_REGISTER
];
169 /* Index [M][R] is true if register R is allowed to hold a value of mode M. */
170 static bool loongarch_hard_regno_mode_ok_p
[MAX_MACHINE_MODE
]
171 [FIRST_PSEUDO_REGISTER
];
173 /* Index C is true if character C is a valid PRINT_OPERAND punctation
175 static bool loongarch_print_operand_punct
[256];
177 /* Cached value of can_issue_more. This is cached in loongarch_variable_issue
178 hook and returned from loongarch_sched_reorder2. */
179 static int cached_can_issue_more
;
181 /* Index R is the smallest register class that contains register R. */
182 const enum reg_class loongarch_regno_to_class
[FIRST_PSEUDO_REGISTER
] = {
183 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
184 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
185 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
186 SIBCALL_REGS
, JIRL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
,
187 SIBCALL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
,
188 SIBCALL_REGS
, GR_REGS
, GR_REGS
, JIRL_REGS
,
189 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
190 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
192 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
193 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
194 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
195 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
196 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
197 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
198 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
199 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
200 FCC_REGS
, FCC_REGS
, FCC_REGS
, FCC_REGS
,
201 FCC_REGS
, FCC_REGS
, FCC_REGS
, FCC_REGS
,
202 FRAME_REGS
, FRAME_REGS
205 /* Which cost information to use. */
206 static const struct loongarch_rtx_cost_data
*loongarch_cost
;
208 /* Information about a single argument. */
209 struct loongarch_arg_info
211 /* True if the argument is at least partially passed on the stack. */
214 /* The number of integer registers allocated to this argument. */
215 unsigned int num_gprs
;
217 /* The offset of the first register used, provided num_gprs is nonzero.
218 If passed entirely on the stack, the value is MAX_ARGS_IN_REGISTERS. */
219 unsigned int gpr_offset
;
221 /* The number of floating-point registers allocated to this argument. */
222 unsigned int num_fprs
;
224 /* The offset of the first register used, provided num_fprs is nonzero. */
225 unsigned int fpr_offset
;
228 /* Invoke MACRO (COND) for each fcmp.cond.{s/d} condition. */
229 #define LARCH_FP_CONDITIONS(MACRO) \
247 /* Enumerates the codes above as LARCH_FP_COND_<X>. */
248 #define DECLARE_LARCH_COND(X) LARCH_FP_COND_##X
249 enum loongarch_fp_condition
251 LARCH_FP_CONDITIONS (DECLARE_LARCH_COND
)
253 #undef DECLARE_LARCH_COND
255 /* Index X provides the string representation of LARCH_FP_COND_<X>. */
256 #define STRINGIFY(X) #X
258 loongarch_fp_conditions
[16]= {LARCH_FP_CONDITIONS (STRINGIFY
)};
261 /* Size of guard page. */
262 #define STACK_CLASH_PROTECTION_GUARD_SIZE \
263 (1 << param_stack_clash_protection_guard_size)
265 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at
266 least PARM_BOUNDARY bits of alignment, but will be given anything up
267 to PREFERRED_STACK_BOUNDARY bits if the type requires it. */
270 loongarch_function_arg_boundary (machine_mode mode
, const_tree type
)
272 unsigned int alignment
;
274 /* Use natural alignment if the type is not aggregate data. */
275 if (type
&& !AGGREGATE_TYPE_P (type
))
276 alignment
= TYPE_ALIGN (TYPE_MAIN_VARIANT (type
));
278 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
280 return MIN (PREFERRED_STACK_BOUNDARY
, MAX (PARM_BOUNDARY
, alignment
));
283 /* If MODE represents an argument that can be passed or returned in
284 floating-point registers, return the number of registers, else 0. */
287 loongarch_pass_mode_in_fpr_p (machine_mode mode
)
289 if (GET_MODE_UNIT_SIZE (mode
) <= UNITS_PER_FP_ARG
)
291 if (GET_MODE_CLASS (mode
) == MODE_FLOAT
)
294 if (GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
)
304 HOST_WIDE_INT offset
;
305 } loongarch_aggregate_field
;
307 /* Identify subfields of aggregates that are candidates for passing in
308 floating-point registers. */
311 loongarch_flatten_aggregate_field (const_tree type
,
312 loongarch_aggregate_field fields
[2], int n
,
313 HOST_WIDE_INT offset
)
315 switch (TREE_CODE (type
))
318 /* Can't handle incomplete types nor sizes that are not fixed. */
319 if (!COMPLETE_TYPE_P (type
)
320 || TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
321 || !tree_fits_uhwi_p (TYPE_SIZE (type
)))
324 for (tree f
= TYPE_FIELDS (type
); f
; f
= DECL_CHAIN (f
))
325 if (TREE_CODE (f
) == FIELD_DECL
)
327 if (!TYPE_P (TREE_TYPE (f
)))
330 if (DECL_SIZE (f
) && integer_zerop (DECL_SIZE (f
)))
333 HOST_WIDE_INT pos
= offset
+ int_byte_position (f
);
334 n
= loongarch_flatten_aggregate_field (TREE_TYPE (f
), fields
, n
,
343 HOST_WIDE_INT n_elts
;
344 loongarch_aggregate_field subfields
[2];
345 tree index
= TYPE_DOMAIN (type
);
346 tree elt_size
= TYPE_SIZE_UNIT (TREE_TYPE (type
));
347 int n_subfields
= loongarch_flatten_aggregate_field (TREE_TYPE (type
),
351 /* Can't handle incomplete types nor sizes that are not fixed. */
353 || !COMPLETE_TYPE_P (type
)
354 || TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
356 || !TYPE_MAX_VALUE (index
)
357 || !tree_fits_uhwi_p (TYPE_MAX_VALUE (index
))
358 || !TYPE_MIN_VALUE (index
)
359 || !tree_fits_uhwi_p (TYPE_MIN_VALUE (index
))
360 || !tree_fits_uhwi_p (elt_size
))
363 n_elts
= 1 + tree_to_uhwi (TYPE_MAX_VALUE (index
))
364 - tree_to_uhwi (TYPE_MIN_VALUE (index
));
365 gcc_assert (n_elts
>= 0);
367 for (HOST_WIDE_INT i
= 0; i
< n_elts
; i
++)
368 for (int j
= 0; j
< n_subfields
; j
++)
373 fields
[n
] = subfields
[j
];
374 fields
[n
++].offset
+= i
* tree_to_uhwi (elt_size
);
382 /* Complex type need consume 2 field, so n must be 0. */
386 HOST_WIDE_INT elt_size
= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type
)));
388 if (elt_size
<= UNITS_PER_FP_ARG
)
390 fields
[0].type
= TREE_TYPE (type
);
391 fields
[0].offset
= offset
;
392 fields
[1].type
= TREE_TYPE (type
);
393 fields
[1].offset
= offset
+ elt_size
;
403 && ((SCALAR_FLOAT_TYPE_P (type
)
404 && GET_MODE_SIZE (TYPE_MODE (type
)) <= UNITS_PER_FP_ARG
)
405 || (INTEGRAL_TYPE_P (type
)
406 && GET_MODE_SIZE (TYPE_MODE (type
)) <= UNITS_PER_WORD
)))
408 fields
[n
].type
= type
;
409 fields
[n
].offset
= offset
;
417 /* Identify candidate aggregates for passing in floating-point registers.
418 Candidates have at most two fields after flattening. */
421 loongarch_flatten_aggregate_argument (const_tree type
,
422 loongarch_aggregate_field fields
[2])
424 if (!type
|| TREE_CODE (type
) != RECORD_TYPE
)
427 return loongarch_flatten_aggregate_field (type
, fields
, 0, 0);
430 /* See whether TYPE is a record whose fields should be returned in one or
431 two floating-point registers. If so, populate FIELDS accordingly. */
434 loongarch_pass_aggregate_num_fpr (const_tree type
,
435 loongarch_aggregate_field fields
[2])
437 int n
= loongarch_flatten_aggregate_argument (type
, fields
);
439 for (int i
= 0; i
< n
; i
++)
440 if (!SCALAR_FLOAT_TYPE_P (fields
[i
].type
))
443 return n
> 0 ? n
: 0;
446 /* See whether TYPE is a record whose fields should be returned in one
447 floating-point register and one integer register. If so, populate
448 FIELDS accordingly. */
451 loongarch_pass_aggregate_in_fpr_and_gpr_p (const_tree type
,
452 loongarch_aggregate_field fields
[2])
454 unsigned num_int
= 0, num_float
= 0;
455 int n
= loongarch_flatten_aggregate_argument (type
, fields
);
457 for (int i
= 0; i
< n
; i
++)
459 num_float
+= SCALAR_FLOAT_TYPE_P (fields
[i
].type
);
460 num_int
+= INTEGRAL_TYPE_P (fields
[i
].type
);
463 return num_int
== 1 && num_float
== 1;
466 /* Return the representation of an argument passed or returned in an FPR
467 when the value has mode VALUE_MODE and the type has TYPE_MODE. The
468 two modes may be different for structures like:
470 struct __attribute__((packed)) foo { float f; }
472 where the SFmode value "f" is passed in REGNO but the struct itself
476 loongarch_pass_fpr_single (machine_mode type_mode
, unsigned regno
,
477 machine_mode value_mode
,
478 HOST_WIDE_INT offset
)
480 rtx x
= gen_rtx_REG (value_mode
, regno
);
482 if (type_mode
!= value_mode
)
484 x
= gen_rtx_EXPR_LIST (VOIDmode
, x
, GEN_INT (offset
));
485 x
= gen_rtx_PARALLEL (type_mode
, gen_rtvec (1, x
));
490 /* Pass or return a composite value in the FPR pair REGNO and REGNO + 1.
491 MODE is the mode of the composite. MODE1 and OFFSET1 are the mode and
492 byte offset for the first value, likewise MODE2 and OFFSET2 for the
496 loongarch_pass_fpr_pair (machine_mode mode
, unsigned regno1
,
497 machine_mode mode1
, HOST_WIDE_INT offset1
,
498 unsigned regno2
, machine_mode mode2
,
499 HOST_WIDE_INT offset2
)
501 return gen_rtx_PARALLEL (
503 gen_rtx_EXPR_LIST (VOIDmode
, gen_rtx_REG (mode1
, regno1
),
505 gen_rtx_EXPR_LIST (VOIDmode
, gen_rtx_REG (mode2
, regno2
),
506 GEN_INT (offset2
))));
509 /* Fill INFO with information about a single argument, and return an
510 RTL pattern to pass or return the argument. CUM is the cumulative
511 state for earlier arguments. MODE is the mode of this argument and
512 TYPE is its type (if known). NAMED is true if this is a named
513 (fixed) argument rather than a variable one. RETURN_P is true if
514 returning the argument, or false if passing the argument. */
517 loongarch_get_arg_info (struct loongarch_arg_info
*info
,
518 const CUMULATIVE_ARGS
*cum
, machine_mode mode
,
519 const_tree type
, bool named
, bool return_p
)
521 unsigned num_bytes
, num_words
;
522 unsigned fpr_base
= return_p
? FP_RETURN
: FP_ARG_FIRST
;
523 unsigned gpr_base
= return_p
? GP_RETURN
: GP_ARG_FIRST
;
524 unsigned alignment
= loongarch_function_arg_boundary (mode
, type
);
526 memset (info
, 0, sizeof (*info
));
527 info
->gpr_offset
= cum
->num_gprs
;
528 info
->fpr_offset
= cum
->num_fprs
;
532 loongarch_aggregate_field fields
[2];
533 unsigned fregno
= fpr_base
+ info
->fpr_offset
;
534 unsigned gregno
= gpr_base
+ info
->gpr_offset
;
536 /* Pass one- or two-element floating-point aggregates in FPRs. */
538 = loongarch_pass_aggregate_num_fpr (type
, fields
))
539 && info
->fpr_offset
+ info
->num_fprs
<= MAX_ARGS_IN_REGISTERS
)
540 switch (info
->num_fprs
)
543 return loongarch_pass_fpr_single (mode
, fregno
,
544 TYPE_MODE (fields
[0].type
),
548 return loongarch_pass_fpr_pair (mode
, fregno
,
549 TYPE_MODE (fields
[0].type
),
552 TYPE_MODE (fields
[1].type
),
559 /* Pass real and complex floating-point numbers in FPRs. */
560 if ((info
->num_fprs
= loongarch_pass_mode_in_fpr_p (mode
))
561 && info
->fpr_offset
+ info
->num_fprs
<= MAX_ARGS_IN_REGISTERS
)
562 switch (GET_MODE_CLASS (mode
))
565 return gen_rtx_REG (mode
, fregno
);
567 case MODE_COMPLEX_FLOAT
:
568 return loongarch_pass_fpr_pair (mode
, fregno
,
569 GET_MODE_INNER (mode
), 0,
570 fregno
+ 1, GET_MODE_INNER (mode
),
571 GET_MODE_UNIT_SIZE (mode
));
577 /* Pass structs with one float and one integer in an FPR and a GPR. */
578 if (loongarch_pass_aggregate_in_fpr_and_gpr_p (type
, fields
)
579 && info
->gpr_offset
< MAX_ARGS_IN_REGISTERS
580 && info
->fpr_offset
< MAX_ARGS_IN_REGISTERS
)
585 if (!SCALAR_FLOAT_TYPE_P (fields
[0].type
))
586 std::swap (fregno
, gregno
);
588 return loongarch_pass_fpr_pair (mode
, fregno
,
589 TYPE_MODE (fields
[0].type
),
590 fields
[0].offset
, gregno
,
591 TYPE_MODE (fields
[1].type
),
596 /* Work out the size of the argument. */
597 num_bytes
= type
? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
598 num_words
= (num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
600 /* Doubleword-aligned varargs start on an even register boundary. */
601 if (!named
&& num_bytes
!= 0 && alignment
> BITS_PER_WORD
)
602 info
->gpr_offset
+= info
->gpr_offset
& 1;
604 /* Partition the argument between registers and stack. */
606 info
->num_gprs
= MIN (num_words
, MAX_ARGS_IN_REGISTERS
- info
->gpr_offset
);
607 info
->stack_p
= (num_words
- info
->num_gprs
) != 0;
609 if (info
->num_gprs
|| return_p
)
610 return gen_rtx_REG (mode
, gpr_base
+ info
->gpr_offset
);
615 /* Implement TARGET_FUNCTION_ARG. */
618 loongarch_function_arg (cumulative_args_t cum_v
, const function_arg_info
&arg
)
620 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
621 struct loongarch_arg_info info
;
623 if (arg
.end_marker_p ())
626 return loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
,
630 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
633 loongarch_function_arg_advance (cumulative_args_t cum_v
,
634 const function_arg_info
&arg
)
636 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
637 struct loongarch_arg_info info
;
639 loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
, false);
641 /* Advance the register count. This has the effect of setting
642 num_gprs to MAX_ARGS_IN_REGISTERS if a doubleword-aligned
643 argument required us to skip the final GPR and pass the whole
644 argument on the stack. */
645 cum
->num_fprs
= info
.fpr_offset
+ info
.num_fprs
;
646 cum
->num_gprs
= info
.gpr_offset
+ info
.num_gprs
;
649 /* Implement TARGET_ARG_PARTIAL_BYTES. */
652 loongarch_arg_partial_bytes (cumulative_args_t cum
,
653 const function_arg_info
&generic_arg
)
655 struct loongarch_arg_info arg
;
657 loongarch_get_arg_info (&arg
, get_cumulative_args (cum
), generic_arg
.mode
,
658 generic_arg
.type
, generic_arg
.named
, false);
659 return arg
.stack_p
? arg
.num_gprs
* UNITS_PER_WORD
: 0;
662 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
663 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
664 VALTYPE is null and MODE is the mode of the return value. */
667 loongarch_function_value_1 (const_tree type
, const_tree func
,
670 struct loongarch_arg_info info
;
671 CUMULATIVE_ARGS args
;
675 int unsigned_p
= TYPE_UNSIGNED (type
);
677 mode
= TYPE_MODE (type
);
679 /* Since TARGET_PROMOTE_FUNCTION_MODE unconditionally promotes,
680 return values, promote the mode here too. */
681 mode
= promote_function_mode (type
, mode
, &unsigned_p
, func
, 1);
684 memset (&args
, 0, sizeof (args
));
685 return loongarch_get_arg_info (&info
, &args
, mode
, type
, true, true);
689 /* Implement TARGET_FUNCTION_VALUE. */
692 loongarch_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
693 bool outgoing ATTRIBUTE_UNUSED
)
695 return loongarch_function_value_1 (valtype
, fn_decl_or_type
, VOIDmode
);
698 /* Implement TARGET_LIBCALL_VALUE. */
701 loongarch_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
703 return loongarch_function_value_1 (NULL_TREE
, NULL_TREE
, mode
);
707 /* Implement TARGET_PASS_BY_REFERENCE. */
710 loongarch_pass_by_reference (cumulative_args_t cum_v
,
711 const function_arg_info
&arg
)
713 HOST_WIDE_INT size
= arg
.type_size_in_bytes ();
714 struct loongarch_arg_info info
;
715 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
717 /* ??? std_gimplify_va_arg_expr passes NULL for cum. Fortunately, we
718 never pass variadic arguments in floating-point registers, so we can
719 avoid the call to loongarch_get_arg_info in this case. */
722 /* Don't pass by reference if we can use a floating-point register. */
723 loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
,
729 /* Pass by reference if the data do not fit in two integer registers. */
730 return !IN_RANGE (size
, 0, 2 * UNITS_PER_WORD
);
733 /* Implement TARGET_RETURN_IN_MEMORY. */
736 loongarch_return_in_memory (const_tree type
,
737 const_tree fndecl ATTRIBUTE_UNUSED
)
739 CUMULATIVE_ARGS args
;
740 cumulative_args_t cum
= pack_cumulative_args (&args
);
742 /* The rules for returning in memory are the same as for passing the
743 first named argument by reference. */
744 memset (&args
, 0, sizeof (args
));
745 function_arg_info
arg (const_cast<tree
> (type
), /*named=*/true);
746 return loongarch_pass_by_reference (cum
, arg
);
749 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
752 loongarch_setup_incoming_varargs (cumulative_args_t cum
,
753 const function_arg_info
&arg
,
754 int *pretend_size ATTRIBUTE_UNUSED
,
757 CUMULATIVE_ARGS local_cum
;
760 /* The caller has advanced CUM up to, but not beyond, the last named
761 argument. Advance a local copy of CUM past the last "real" named
762 argument, to find out how many registers are left over. */
763 local_cum
= *get_cumulative_args (cum
);
764 if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl
)))
765 loongarch_function_arg_advance (pack_cumulative_args (&local_cum
), arg
);
767 /* Found out how many registers we need to save. */
768 gp_saved
= cfun
->va_list_gpr_size
/ UNITS_PER_WORD
;
769 if (gp_saved
> (int) (MAX_ARGS_IN_REGISTERS
- local_cum
.num_gprs
))
770 gp_saved
= MAX_ARGS_IN_REGISTERS
- local_cum
.num_gprs
;
772 if (!no_rtl
&& gp_saved
> 0)
774 rtx ptr
= plus_constant (Pmode
, virtual_incoming_args_rtx
,
775 REG_PARM_STACK_SPACE (cfun
->decl
)
776 - gp_saved
* UNITS_PER_WORD
);
777 rtx mem
= gen_frame_mem (BLKmode
, ptr
);
778 set_mem_alias_set (mem
, get_varargs_alias_set ());
780 move_block_from_reg (local_cum
.num_gprs
+ GP_ARG_FIRST
, mem
, gp_saved
);
782 if (REG_PARM_STACK_SPACE (cfun
->decl
) == 0)
783 cfun
->machine
->varargs_size
= gp_saved
* UNITS_PER_WORD
;
786 /* Make the last instruction frame-related and note that it performs
787 the operation described by FRAME_PATTERN. */
790 loongarch_set_frame_expr (rtx frame_pattern
)
794 insn
= get_last_insn ();
795 RTX_FRAME_RELATED_P (insn
) = 1;
796 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
, frame_pattern
,
800 /* Return a frame-related rtx that stores REG at MEM.
801 REG must be a single register. */
804 loongarch_frame_set (rtx mem
, rtx reg
)
806 rtx set
= gen_rtx_SET (mem
, reg
);
807 RTX_FRAME_RELATED_P (set
) = 1;
811 /* Return true if the current function must save register REGNO. */
814 loongarch_save_reg_p (unsigned int regno
)
816 bool call_saved
= !global_regs
[regno
] && !call_used_regs
[regno
];
818 = crtl
->saves_all_registers
|| df_regs_ever_live_p (regno
);
820 if (call_saved
&& might_clobber
)
823 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
826 if (regno
== RETURN_ADDR_REGNUM
&& crtl
->calls_eh_return
)
832 /* Determine which GPR save/restore routine to call. */
835 loongarch_save_libcall_count (unsigned mask
)
837 for (unsigned n
= GP_REG_LAST
; n
> GP_REG_FIRST
; n
--)
838 if (BITSET_P (mask
, n
))
839 return CALLEE_SAVED_REG_NUMBER (n
) + 1;
843 /* Populate the current function's loongarch_frame_info structure.
845 LoongArch stack frames grown downward. High addresses are at the top.
847 +-------------------------------+
849 | incoming stack arguments |
851 +-------------------------------+ <-- incoming stack pointer
853 | callee-allocated save area |
854 | for arguments that are |
855 | split between registers and |
858 +-------------------------------+ <-- arg_pointer_rtx (virtual)
860 | callee-allocated save area |
861 | for register varargs |
863 +-------------------------------+ <-- hard_frame_pointer_rtx;
864 | | stack_pointer_rtx + gp_sp_offset
865 | GPR save area | + UNITS_PER_WORD
867 +-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset
868 | | + UNITS_PER_HWVALUE
871 +-------------------------------+ <-- frame_pointer_rtx (virtual)
875 P +-------------------------------+
877 | outgoing stack arguments |
879 +-------------------------------+ <-- stack_pointer_rtx
881 Dynamic stack allocations such as alloca insert data at point P.
882 They decrease stack_pointer_rtx but leave frame_pointer_rtx and
883 hard_frame_pointer_rtx unchanged. */
886 loongarch_compute_frame_info (void)
888 struct loongarch_frame_info
*frame
;
889 HOST_WIDE_INT offset
;
890 unsigned int regno
, i
, num_x_saved
= 0, num_f_saved
= 0;
892 frame
= &cfun
->machine
->frame
;
893 memset (frame
, 0, sizeof (*frame
));
895 /* Find out which GPRs we need to save. */
896 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
897 if (loongarch_save_reg_p (regno
))
898 frame
->mask
|= 1 << (regno
- GP_REG_FIRST
), num_x_saved
++;
900 /* If this function calls eh_return, we must also save and restore the
901 EH data registers. */
902 if (crtl
->calls_eh_return
)
903 for (i
= 0; (regno
= EH_RETURN_DATA_REGNO (i
)) != INVALID_REGNUM
; i
++)
904 frame
->mask
|= 1 << (regno
- GP_REG_FIRST
), num_x_saved
++;
906 /* Find out which FPRs we need to save. This loop must iterate over
907 the same space as its companion in loongarch_for_each_saved_reg. */
908 if (TARGET_HARD_FLOAT
)
909 for (regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
910 if (loongarch_save_reg_p (regno
))
911 frame
->fmask
|= 1 << (regno
- FP_REG_FIRST
), num_f_saved
++;
913 /* At the bottom of the frame are any outgoing stack arguments. */
914 offset
= LARCH_STACK_ALIGN (crtl
->outgoing_args_size
);
915 /* Next are local stack variables. */
916 offset
+= LARCH_STACK_ALIGN (get_frame_size ());
917 /* The virtual frame pointer points above the local variables. */
918 frame
->frame_pointer_offset
= offset
;
919 /* Next are the callee-saved FPRs. */
922 offset
+= LARCH_STACK_ALIGN (num_f_saved
* UNITS_PER_FP_REG
);
923 frame
->fp_sp_offset
= offset
- UNITS_PER_FP_REG
;
926 frame
->fp_sp_offset
= offset
;
927 /* Next are the callee-saved GPRs. */
930 unsigned x_save_size
= LARCH_STACK_ALIGN (num_x_saved
* UNITS_PER_WORD
);
931 unsigned num_save_restore
932 = 1 + loongarch_save_libcall_count (frame
->mask
);
934 /* Only use save/restore routines if they don't alter the stack size. */
935 if (LARCH_STACK_ALIGN (num_save_restore
* UNITS_PER_WORD
) == x_save_size
)
936 frame
->save_libcall_adjustment
= x_save_size
;
938 offset
+= x_save_size
;
939 frame
->gp_sp_offset
= offset
- UNITS_PER_WORD
;
942 frame
->gp_sp_offset
= offset
;
943 /* The hard frame pointer points above the callee-saved GPRs. */
944 frame
->hard_frame_pointer_offset
= offset
;
945 /* Above the hard frame pointer is the callee-allocated varags save area. */
946 offset
+= LARCH_STACK_ALIGN (cfun
->machine
->varargs_size
);
947 /* Next is the callee-allocated area for pretend stack arguments. */
948 offset
+= LARCH_STACK_ALIGN (crtl
->args
.pretend_args_size
);
949 /* Arg pointer must be below pretend args, but must be above alignment
951 frame
->arg_pointer_offset
= offset
- crtl
->args
.pretend_args_size
;
952 frame
->total_size
= offset
;
953 /* Next points the incoming stack pointer and any incoming arguments. */
955 /* Only use save/restore routines when the GPRs are atop the frame. */
956 if (frame
->hard_frame_pointer_offset
!= frame
->total_size
)
957 frame
->save_libcall_adjustment
= 0;
960 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame pointer
961 or argument pointer. TO is either the stack pointer or hard frame
965 loongarch_initial_elimination_offset (int from
, int to
)
967 HOST_WIDE_INT src
, dest
;
969 loongarch_compute_frame_info ();
971 if (to
== HARD_FRAME_POINTER_REGNUM
)
972 dest
= cfun
->machine
->frame
.hard_frame_pointer_offset
;
973 else if (to
== STACK_POINTER_REGNUM
)
974 dest
= 0; /* The stack pointer is the base of all offsets, hence 0. */
978 if (from
== FRAME_POINTER_REGNUM
)
979 src
= cfun
->machine
->frame
.frame_pointer_offset
;
980 else if (from
== ARG_POINTER_REGNUM
)
981 src
= cfun
->machine
->frame
.arg_pointer_offset
;
988 /* A function to save or store a register. The first argument is the
989 register and the second is the stack slot. */
990 typedef void (*loongarch_save_restore_fn
) (rtx
, rtx
);
992 /* Use FN to save or restore register REGNO. MODE is the register's
993 mode and OFFSET is the offset of its save slot from the current
997 loongarch_save_restore_reg (machine_mode mode
, int regno
, HOST_WIDE_INT offset
,
998 loongarch_save_restore_fn fn
)
1002 mem
= gen_frame_mem (mode
, plus_constant (Pmode
, stack_pointer_rtx
, offset
));
1003 fn (gen_rtx_REG (mode
, regno
), mem
);
1006 /* Call FN for each register that is saved by the current function.
1007 SP_OFFSET is the offset of the current stack pointer from the start
1011 loongarch_for_each_saved_reg (HOST_WIDE_INT sp_offset
,
1012 loongarch_save_restore_fn fn
)
1014 HOST_WIDE_INT offset
;
1016 /* Save the link register and s-registers. */
1017 offset
= cfun
->machine
->frame
.gp_sp_offset
- sp_offset
;
1018 for (int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
1019 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
1021 if (!cfun
->machine
->reg_is_wrapped_separately
[regno
])
1022 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
1024 offset
-= UNITS_PER_WORD
;
1027 /* This loop must iterate over the same space as its companion in
1028 loongarch_compute_frame_info. */
1029 offset
= cfun
->machine
->frame
.fp_sp_offset
- sp_offset
;
1030 machine_mode mode
= TARGET_DOUBLE_FLOAT
? DFmode
: SFmode
;
1032 for (int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
1033 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
1035 if (!cfun
->machine
->reg_is_wrapped_separately
[regno
])
1036 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
1038 offset
-= GET_MODE_SIZE (mode
);
1042 /* Emit a move from SRC to DEST. Assume that the move expanders can
1043 handle all moves if !can_create_pseudo_p (). The distinction is
1044 important because, unlike emit_move_insn, the move expanders know
1045 how to force Pmode objects into the constant pool even when the
1046 constant pool address is not itself legitimate. */
1049 loongarch_emit_move (rtx dest
, rtx src
)
1051 return (can_create_pseudo_p () ? emit_move_insn (dest
, src
)
1052 : emit_move_insn_1 (dest
, src
));
1055 /* Save register REG to MEM. Make the instruction frame-related. */
1058 loongarch_save_reg (rtx reg
, rtx mem
)
1060 loongarch_emit_move (mem
, reg
);
1061 loongarch_set_frame_expr (loongarch_frame_set (mem
, reg
));
1064 /* Restore register REG from MEM. */
1067 loongarch_restore_reg (rtx reg
, rtx mem
)
1069 rtx insn
= loongarch_emit_move (reg
, mem
);
1070 rtx dwarf
= NULL_RTX
;
1071 dwarf
= alloc_reg_note (REG_CFA_RESTORE
, reg
, dwarf
);
1072 REG_NOTES (insn
) = dwarf
;
1074 RTX_FRAME_RELATED_P (insn
) = 1;
1077 /* For stack frames that can't be allocated with a single ADDI instruction,
1078 compute the best value to initially allocate. It must at a minimum
1079 allocate enough space to spill the callee-saved registers. */
1081 static HOST_WIDE_INT
1082 loongarch_first_stack_step (struct loongarch_frame_info
*frame
)
1084 HOST_WIDE_INT min_first_step
1085 = LARCH_STACK_ALIGN (frame
->total_size
- frame
->fp_sp_offset
);
1087 /* When stack checking is required, if the sum of frame->total_size
1088 and stack_check_protect is greater than stack clash protection guard
1089 size, then return min_first_step. */
1090 if (flag_stack_check
== STATIC_BUILTIN_STACK_CHECK
1091 || (flag_stack_clash_protection
1092 && frame
->total_size
> STACK_CLASH_PROTECTION_GUARD_SIZE
))
1093 return min_first_step
;
1095 if (IMM12_OPERAND (frame
->total_size
))
1096 return frame
->total_size
;
1098 HOST_WIDE_INT max_first_step
= IMM_REACH
/ 2 - PREFERRED_STACK_BOUNDARY
/ 8;
1099 HOST_WIDE_INT min_second_step
= frame
->total_size
- max_first_step
;
1100 gcc_assert (min_first_step
<= max_first_step
);
1102 /* As an optimization, use the least-significant bits of the total frame
1103 size, so that the second adjustment step is just LU12I + ADD. */
1104 if (!IMM12_OPERAND (min_second_step
)
1105 && frame
->total_size
% IMM_REACH
< IMM_REACH
/ 2
1106 && frame
->total_size
% IMM_REACH
>= min_first_step
)
1107 return frame
->total_size
% IMM_REACH
;
1109 return max_first_step
;
1113 loongarch_emit_stack_tie (void)
1115 emit_insn (gen_stack_tie (Pmode
, stack_pointer_rtx
,
1116 frame_pointer_needed
? hard_frame_pointer_rtx
1117 : stack_pointer_rtx
));
1120 #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
1122 #if PROBE_INTERVAL > 16384
1123 #error Cannot use indexed addressing mode for stack probing
1126 /* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
1127 inclusive. These are offsets from the current stack pointer. */
1130 loongarch_emit_probe_stack_range (HOST_WIDE_INT first
, HOST_WIDE_INT size
)
1132 HOST_WIDE_INT rounded_size
;
1133 HOST_WIDE_INT interval
;
1135 if (flag_stack_clash_protection
)
1136 interval
= STACK_CLASH_PROTECTION_GUARD_SIZE
;
1138 interval
= PROBE_INTERVAL
;
1140 rtx r12
= LARCH_PROLOGUE_TEMP2 (Pmode
);
1141 rtx r14
= LARCH_PROLOGUE_TEMP3 (Pmode
);
1143 size
= size
+ first
;
1145 /* Sanity check for the addressing mode we're going to use. */
1146 gcc_assert (first
<= 16384);
1148 /* Step 1: round SIZE to the previous multiple of the interval. */
1150 rounded_size
= ROUND_DOWN (size
, interval
);
1152 /* Step 2: compute initial and final value of the loop counter. */
1154 emit_move_insn (r14
, GEN_INT (interval
));
1156 /* If rounded_size is zero, it means that the space requested by
1157 the local variable is less than the interval, and there is no
1158 need to display and detect the allocated space. */
1159 if (rounded_size
!= 0)
1165 TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
1168 while (TEST_ADDR != LAST_ADDR)
1170 probes at FIRST + N * PROBE_INTERVAL for values of N from 1
1171 until it is equal to ROUNDED_SIZE. */
1173 if (rounded_size
<= STACK_CLASH_MAX_UNROLL_PAGES
* interval
)
1175 for (HOST_WIDE_INT i
= 0; i
< rounded_size
; i
+= interval
)
1177 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1178 gen_rtx_MINUS (Pmode
,
1181 emit_move_insn (gen_rtx_MEM (Pmode
,
1182 gen_rtx_PLUS (Pmode
,
1186 emit_insn (gen_blockage ());
1188 dump_stack_clash_frame_info (PROBE_INLINE
, size
!= rounded_size
);
1192 emit_move_insn (r12
, GEN_INT (rounded_size
));
1193 emit_insn (gen_rtx_SET (r12
,
1194 gen_rtx_MINUS (Pmode
,
1198 emit_insn (gen_probe_stack_range (Pmode
, stack_pointer_rtx
,
1199 stack_pointer_rtx
, r12
, r14
));
1200 emit_insn (gen_blockage ());
1201 dump_stack_clash_frame_info (PROBE_LOOP
, size
!= rounded_size
);
1205 dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME
, true);
1208 /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
1209 that SIZE is equal to ROUNDED_SIZE. */
1211 if (size
!= rounded_size
)
1213 if (size
- rounded_size
>= 2048)
1215 emit_move_insn (r14
, GEN_INT (size
- rounded_size
));
1216 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1217 gen_rtx_MINUS (Pmode
,
1222 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1223 gen_rtx_PLUS (Pmode
,
1225 GEN_INT (rounded_size
- size
))));
1230 emit_move_insn (r12
, GEN_INT (first
));
1231 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1232 gen_rtx_PLUS (Pmode
,
1233 stack_pointer_rtx
, r12
)));
1235 /* Make sure nothing is scheduled before we are done. */
1236 emit_insn (gen_blockage ());
1239 /* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
1240 absolute addresses. */
1242 loongarch_output_probe_stack_range (rtx reg1
, rtx reg2
, rtx reg3
)
1244 static int labelno
= 0;
1245 char loop_lab
[32], tmp
[64];
1248 ASM_GENERATE_INTERNAL_LABEL (loop_lab
, "LPSRL", labelno
++);
1251 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, loop_lab
);
1253 /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
1257 output_asm_insn ("sub.d\t%0,%0,%2", xops
);
1259 output_asm_insn ("sub.w\t%0,%0,%2", xops
);
1261 /* Probe at TEST_ADDR, test if TEST_ADDR == LAST_ADDR and branch. */
1263 strcpy (tmp
, "bne\t%0,%1,");
1265 output_asm_insn ("st.d\t$r0,%0,0", xops
);
1267 output_asm_insn ("st.w\t$r0,%0,0", xops
);
1268 output_asm_insn (strcat (tmp
, &loop_lab
[1]), xops
);
1273 /* Expand the "prologue" pattern. */
1276 loongarch_expand_prologue (void)
1278 struct loongarch_frame_info
*frame
= &cfun
->machine
->frame
;
1279 HOST_WIDE_INT size
= frame
->total_size
;
1282 if (flag_stack_usage_info
)
1283 current_function_static_stack_size
= size
;
1285 /* Save the registers. */
1286 if ((frame
->mask
| frame
->fmask
) != 0)
1288 HOST_WIDE_INT step1
= MIN (size
, loongarch_first_stack_step (frame
));
1290 insn
= gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1292 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1294 loongarch_for_each_saved_reg (size
, loongarch_save_reg
);
1297 /* Set up the frame pointer, if we're using one. */
1298 if (frame_pointer_needed
)
1300 insn
= gen_add3_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
,
1301 GEN_INT (frame
->hard_frame_pointer_offset
- size
));
1302 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1304 loongarch_emit_stack_tie ();
1307 if (flag_stack_check
== STATIC_BUILTIN_STACK_CHECK
1308 || flag_stack_clash_protection
)
1310 HOST_WIDE_INT first
= get_stack_check_protect ();
1312 if (frame
->total_size
== 0)
1315 dump_stack_clash_frame_info (NO_PROBE_NO_FRAME
, false);
1319 if (crtl
->is_leaf
&& !cfun
->calls_alloca
)
1321 HOST_WIDE_INT interval
;
1323 if (flag_stack_clash_protection
)
1324 interval
= STACK_CLASH_PROTECTION_GUARD_SIZE
;
1326 interval
= PROBE_INTERVAL
;
1328 if (size
> interval
&& size
> first
)
1329 loongarch_emit_probe_stack_range (first
, size
- first
);
1331 loongarch_emit_probe_stack_range (first
, size
);
1334 loongarch_emit_probe_stack_range (first
, size
);
1338 /* Describe the effect of the previous instructions. */
1339 insn
= plus_constant (Pmode
, stack_pointer_rtx
, -size
);
1340 insn
= gen_rtx_SET (stack_pointer_rtx
, insn
);
1341 loongarch_set_frame_expr (insn
);
1348 if (IMM12_OPERAND (-size
))
1350 insn
= gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1352 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1356 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
),
1358 emit_insn (gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1359 LARCH_PROLOGUE_TEMP (Pmode
)));
1361 /* Describe the effect of the previous instructions. */
1362 insn
= plus_constant (Pmode
, stack_pointer_rtx
, -size
);
1363 insn
= gen_rtx_SET (stack_pointer_rtx
, insn
);
1364 loongarch_set_frame_expr (insn
);
1369 /* Return nonzero if this function is known to have a null epilogue.
1370 This allows the optimizer to omit jumps to jumps if no stack
1374 loongarch_can_use_return_insn (void)
1376 return reload_completed
&& cfun
->machine
->frame
.total_size
== 0;
1379 /* Expand an "epilogue" or "sibcall_epilogue" pattern; SIBCALL_P
1383 loongarch_expand_epilogue (bool sibcall_p
)
1385 /* Split the frame into two. STEP1 is the amount of stack we should
1386 deallocate before restoring the registers. STEP2 is the amount we
1387 should deallocate afterwards.
1389 Start off by assuming that no registers need to be restored. */
1390 struct loongarch_frame_info
*frame
= &cfun
->machine
->frame
;
1391 HOST_WIDE_INT step1
= frame
->total_size
;
1392 HOST_WIDE_INT step2
= 0;
1393 rtx ra
= gen_rtx_REG (Pmode
, RETURN_ADDR_REGNUM
);
1396 /* We need to add memory barrier to prevent read from deallocated stack. */
1398 = (get_frame_size () + cfun
->machine
->frame
.arg_pointer_offset
) != 0;
1400 if (!sibcall_p
&& loongarch_can_use_return_insn ())
1402 emit_jump_insn (gen_return ());
1406 /* Move past any dynamic stack allocations. */
1407 if (cfun
->calls_alloca
)
1409 /* Emit a barrier to prevent loads from a deallocated stack. */
1410 loongarch_emit_stack_tie ();
1411 need_barrier_p
= false;
1413 rtx adjust
= GEN_INT (-frame
->hard_frame_pointer_offset
);
1414 if (!IMM12_OPERAND (INTVAL (adjust
)))
1416 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
), adjust
);
1417 adjust
= LARCH_PROLOGUE_TEMP (Pmode
);
1420 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1421 hard_frame_pointer_rtx
,
1424 rtx dwarf
= NULL_RTX
;
1425 rtx minus_offset
= GEN_INT (-frame
->hard_frame_pointer_offset
);
1426 rtx cfa_adjust_value
= gen_rtx_PLUS (Pmode
,
1427 hard_frame_pointer_rtx
,
1430 rtx cfa_adjust_rtx
= gen_rtx_SET (stack_pointer_rtx
, cfa_adjust_value
);
1431 dwarf
= alloc_reg_note (REG_CFA_ADJUST_CFA
, cfa_adjust_rtx
, dwarf
);
1432 RTX_FRAME_RELATED_P (insn
) = 1;
1434 REG_NOTES (insn
) = dwarf
;
1437 /* If we need to restore registers, deallocate as much stack as
1438 possible in the second step without going out of range. */
1439 if ((frame
->mask
| frame
->fmask
) != 0)
1441 step2
= loongarch_first_stack_step (frame
);
1445 /* Set TARGET to BASE + STEP1. */
1448 /* Emit a barrier to prevent loads from a deallocated stack. */
1449 loongarch_emit_stack_tie ();
1450 need_barrier_p
= false;
1452 /* Get an rtx for STEP1 that we can add to BASE. */
1453 rtx adjust
= GEN_INT (step1
);
1454 if (!IMM12_OPERAND (step1
))
1456 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
), adjust
);
1457 adjust
= LARCH_PROLOGUE_TEMP (Pmode
);
1460 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1464 rtx dwarf
= NULL_RTX
;
1465 rtx cfa_adjust_rtx
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1468 dwarf
= alloc_reg_note (REG_CFA_DEF_CFA
, cfa_adjust_rtx
, dwarf
);
1469 RTX_FRAME_RELATED_P (insn
) = 1;
1471 REG_NOTES (insn
) = dwarf
;
1474 /* Restore the registers. */
1475 loongarch_for_each_saved_reg (frame
->total_size
- step2
,
1476 loongarch_restore_reg
);
1479 loongarch_emit_stack_tie ();
1481 /* Deallocate the final bit of the frame. */
1484 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1488 rtx dwarf
= NULL_RTX
;
1489 rtx cfa_adjust_rtx
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
);
1490 dwarf
= alloc_reg_note (REG_CFA_DEF_CFA
, cfa_adjust_rtx
, dwarf
);
1491 RTX_FRAME_RELATED_P (insn
) = 1;
1493 REG_NOTES (insn
) = dwarf
;
1496 /* Add in the __builtin_eh_return stack adjustment. */
1497 if (crtl
->calls_eh_return
)
1498 emit_insn (gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1499 EH_RETURN_STACKADJ_RTX
));
1502 emit_jump_insn (gen_simple_return_internal (ra
));
1505 #define LU32I_B (0xfffffULL << 32)
1506 #define LU52I_B (0xfffULL << 52)
1508 /* Fill CODES with a sequence of rtl operations to load VALUE.
1509 Return the number of operations needed. */
1512 loongarch_build_integer (struct loongarch_integer_op
*codes
,
1513 HOST_WIDE_INT value
)
1516 unsigned int cost
= 0;
1518 /* Get the lower 32 bits of the value. */
1519 HOST_WIDE_INT low_part
= (int32_t)value
;
1521 if (IMM12_OPERAND (low_part
) || IMM12_OPERAND_UNSIGNED (low_part
))
1523 /* The value of the lower 32 bit be loaded with one instruction.
1525 codes
[cost
].code
= UNKNOWN
;
1526 codes
[cost
].method
= METHOD_NORMAL
;
1527 codes
[cost
].value
= low_part
;
1528 codes
[cost
].curr_value
= low_part
;
1533 /* lu12i.w + ior. */
1534 codes
[cost
].code
= UNKNOWN
;
1535 codes
[cost
].method
= METHOD_NORMAL
;
1536 codes
[cost
].value
= low_part
& ~(IMM_REACH
- 1);
1537 codes
[cost
].curr_value
= codes
[cost
].value
;
1539 HOST_WIDE_INT iorv
= low_part
& (IMM_REACH
- 1);
1542 codes
[cost
].code
= IOR
;
1543 codes
[cost
].method
= METHOD_NORMAL
;
1544 codes
[cost
].value
= iorv
;
1545 codes
[cost
].curr_value
= low_part
;
1552 bool lu32i
[2] = {(value
& LU32I_B
) == 0, (value
& LU32I_B
) == LU32I_B
};
1553 bool lu52i
[2] = {(value
& LU52I_B
) == 0, (value
& LU52I_B
) == LU52I_B
};
1555 int sign31
= (value
& (HOST_WIDE_INT_1U
<< 31)) >> 31;
1556 int sign51
= (value
& (HOST_WIDE_INT_1U
<< 51)) >> 51;
1557 /* Determine whether the upper 32 bits are sign-extended from the lower
1558 32 bits. If it is, the instructions to load the high order can be
1560 if (lu32i
[sign31
] && lu52i
[sign31
])
1562 /* Determine whether bits 32-51 are sign-extended from the lower 32
1563 bits. If so, directly load 52-63 bits. */
1564 else if (lu32i
[sign31
])
1566 codes
[cost
].method
= METHOD_LU52I
;
1567 codes
[cost
].value
= value
& LU52I_B
;
1568 codes
[cost
].curr_value
= value
;
1572 codes
[cost
].method
= METHOD_LU32I
;
1573 codes
[cost
].value
= (value
& LU32I_B
) | (sign51
? LU52I_B
: 0);
1574 codes
[cost
].curr_value
= (value
& 0xfffffffffffff)
1575 | (sign51
? LU52I_B
: 0);
1578 /* Determine whether the 52-61 bits are sign-extended from the low order,
1579 and if not, load the 52-61 bits. */
1580 if (!lu52i
[(value
& (HOST_WIDE_INT_1U
<< 51)) >> 51])
1582 codes
[cost
].method
= METHOD_LU52I
;
1583 codes
[cost
].value
= value
& LU52I_B
;
1584 codes
[cost
].curr_value
= value
;
1589 gcc_assert (cost
<= LARCH_MAX_INTEGER_OPS
);
1594 /* Fill CODES with a sequence of rtl operations to load VALUE.
1595 Return the number of operations needed.
1596 Split interger in loongarch_output_move. */
1599 loongarch_integer_cost (HOST_WIDE_INT value
)
1601 struct loongarch_integer_op codes
[LARCH_MAX_INTEGER_OPS
];
1602 return loongarch_build_integer (codes
, value
);
1605 /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
1608 loongarch_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1610 return loongarch_const_insns (x
) > 0;
1613 /* Return true if X is a thread-local symbol. */
1616 loongarch_tls_symbol_p (rtx x
)
1618 return SYMBOL_REF_P (x
) && SYMBOL_REF_TLS_MODEL (x
) != 0;
1621 /* Return true if SYMBOL_REF X is associated with a global symbol
1622 (in the STB_GLOBAL sense). */
1625 loongarch_global_symbol_p (const_rtx x
)
1627 if (LABEL_REF_P (x
))
1630 const_tree decl
= SYMBOL_REF_DECL (x
);
1633 return !SYMBOL_REF_LOCAL_P (x
) || SYMBOL_REF_EXTERNAL_P (x
);
1635 /* Weakref symbols are not TREE_PUBLIC, but their targets are global
1636 or weak symbols. Relocations in the object file will be against
1637 the target symbol, so it's that symbol's binding that matters here. */
1638 return DECL_P (decl
) && (TREE_PUBLIC (decl
) || DECL_WEAK (decl
));
1642 loongarch_global_symbol_noweak_p (const_rtx x
)
1644 if (LABEL_REF_P (x
))
1647 const_tree decl
= SYMBOL_REF_DECL (x
);
1650 return !SYMBOL_REF_LOCAL_P (x
) || SYMBOL_REF_EXTERNAL_P (x
);
1652 return DECL_P (decl
) && TREE_PUBLIC (decl
);
1656 loongarch_weak_symbol_p (const_rtx x
)
1659 if (LABEL_REF_P (x
) || !(decl
= SYMBOL_REF_DECL (x
)))
1661 return DECL_P (decl
) && DECL_WEAK (decl
);
1664 /* Return true if SYMBOL_REF X binds locally. */
1667 loongarch_symbol_binds_local_p (const_rtx x
)
1669 if (TARGET_DIRECT_EXTERN_ACCESS
)
1672 if (SYMBOL_REF_P (x
))
1673 return (SYMBOL_REF_DECL (x
)
1674 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
1675 : SYMBOL_REF_LOCAL_P (x
));
1680 /* Return true if OP is a constant vector with the number of units in MODE,
1681 and each unit has the same bit set. */
1684 loongarch_const_vector_bitimm_set_p (rtx op
, machine_mode mode
)
1686 if (GET_CODE (op
) == CONST_VECTOR
&& op
!= CONST0_RTX (mode
))
1688 unsigned HOST_WIDE_INT val
= UINTVAL (CONST_VECTOR_ELT (op
, 0));
1689 int vlog2
= exact_log2 (val
& GET_MODE_MASK (GET_MODE_INNER (mode
)));
1693 gcc_assert (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
);
1694 gcc_assert (vlog2
>= 0 && vlog2
<= GET_MODE_UNIT_BITSIZE (mode
) - 1);
1695 return loongarch_const_vector_same_val_p (op
, mode
);
1702 /* Return true if OP is a constant vector with the number of units in MODE,
1703 and each unit has the same bit clear. */
1706 loongarch_const_vector_bitimm_clr_p (rtx op
, machine_mode mode
)
1708 if (GET_CODE (op
) == CONST_VECTOR
&& op
!= CONSTM1_RTX (mode
))
1710 unsigned HOST_WIDE_INT val
= ~UINTVAL (CONST_VECTOR_ELT (op
, 0));
1711 int vlog2
= exact_log2 (val
& GET_MODE_MASK (GET_MODE_INNER (mode
)));
1715 gcc_assert (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
);
1716 gcc_assert (vlog2
>= 0 && vlog2
<= GET_MODE_UNIT_BITSIZE (mode
) - 1);
1717 return loongarch_const_vector_same_val_p (op
, mode
);
1724 /* Return true if OP is a constant vector with the number of units in MODE,
1725 and each unit has the same value. */
1728 loongarch_const_vector_same_val_p (rtx op
, machine_mode mode
)
1730 int i
, nunits
= GET_MODE_NUNITS (mode
);
1733 if (GET_CODE (op
) != CONST_VECTOR
|| GET_MODE (op
) != mode
)
1736 first
= CONST_VECTOR_ELT (op
, 0);
1737 for (i
= 1; i
< nunits
; i
++)
1738 if (!rtx_equal_p (first
, CONST_VECTOR_ELT (op
, i
)))
1744 /* Return true if OP is a constant vector with the number of units in MODE,
1745 and each unit has the same value as well as replicated bytes in the value.
1749 loongarch_const_vector_same_bytes_p (rtx op
, machine_mode mode
)
1752 HOST_WIDE_INT val
, first_byte
;
1755 if (!loongarch_const_vector_same_val_p (op
, mode
))
1758 first
= CONST_VECTOR_ELT (op
, 0);
1759 bytes
= GET_MODE_UNIT_SIZE (mode
);
1760 val
= INTVAL (first
);
1761 first_byte
= val
& 0xff;
1762 for (i
= 1; i
< bytes
; i
++)
1765 if ((val
& 0xff) != first_byte
)
1772 /* Return true if OP is a constant vector with the number of units in MODE,
1773 and each unit has the same integer value in the range [LOW, HIGH]. */
1776 loongarch_const_vector_same_int_p (rtx op
, machine_mode mode
, HOST_WIDE_INT low
,
1779 HOST_WIDE_INT value
;
1782 if (!loongarch_const_vector_same_val_p (op
, mode
))
1785 elem0
= CONST_VECTOR_ELT (op
, 0);
1786 if (!CONST_INT_P (elem0
))
1789 value
= INTVAL (elem0
);
1790 return (value
>= low
&& value
<= high
);
1793 /* Return true if OP is a constant vector with repeated 4-element sets
1797 loongarch_const_vector_shuffle_set_p (rtx op
, machine_mode mode
)
1799 int nunits
= GET_MODE_NUNITS (mode
);
1800 int nsets
= nunits
/ 4;
1804 /* Check if we have the same 4-element sets. */
1805 for (j
= 0; j
< nsets
; j
++, set
= 4 * j
)
1806 for (i
= 0; i
< 4; i
++)
1807 if ((INTVAL (XVECEXP (op
, 0, i
))
1808 != (INTVAL (XVECEXP (op
, 0, set
+ i
)) - set
))
1809 || !IN_RANGE (INTVAL (XVECEXP (op
, 0, set
+ i
)), 0, set
+ 3))
1814 /* Return true if rtx constants of mode MODE should be put into a small
1818 loongarch_rtx_constant_in_small_data_p (machine_mode mode
)
1820 return (GET_MODE_SIZE (mode
) <= g_switch_value
);
1823 /* Return the method that should be used to access SYMBOL_REF or
1826 static enum loongarch_symbol_type
1827 loongarch_classify_symbol (const_rtx x
)
1829 enum loongarch_symbol_type pcrel
=
1830 TARGET_CMODEL_EXTREME
? SYMBOL_PCREL64
: SYMBOL_PCREL
;
1832 if (!SYMBOL_REF_P (x
))
1835 if (SYMBOL_REF_TLS_MODEL (x
))
1838 if (!loongarch_symbol_binds_local_p (x
))
1839 return SYMBOL_GOT_DISP
;
1841 tree t
= SYMBOL_REF_DECL (x
);
1845 t
= lookup_attribute ("model", DECL_ATTRIBUTES (t
));
1849 t
= TREE_VALUE (TREE_VALUE (t
));
1851 /* loongarch_handle_model_attribute should reject other values. */
1852 gcc_assert (TREE_CODE (t
) == STRING_CST
);
1854 const char *model
= TREE_STRING_POINTER (t
);
1855 if (strcmp (model
, "normal") == 0)
1856 return SYMBOL_PCREL
;
1857 if (strcmp (model
, "extreme") == 0)
1858 return SYMBOL_PCREL64
;
1860 /* loongarch_handle_model_attribute should reject unknown model
1865 /* Classify the base of symbolic expression X, given that X appears in
1868 static enum loongarch_symbol_type
1869 loongarch_classify_symbolic_expression (rtx x
)
1873 split_const (x
, &x
, &offset
);
1874 if (UNSPEC_ADDRESS_P (x
))
1875 return UNSPEC_ADDRESS_TYPE (x
);
1877 return loongarch_classify_symbol (x
);
1880 /* Return true if X is a symbolic constant. If it is,
1881 store the type of the symbol in *SYMBOL_TYPE. */
1884 loongarch_symbolic_constant_p (rtx x
, enum loongarch_symbol_type
*symbol_type
)
1888 split_const (x
, &x
, &offset
);
1889 if (UNSPEC_ADDRESS_P (x
))
1891 *symbol_type
= UNSPEC_ADDRESS_TYPE (x
);
1892 x
= UNSPEC_ADDRESS (x
);
1894 else if (SYMBOL_REF_P (x
) || LABEL_REF_P (x
))
1896 *symbol_type
= loongarch_classify_symbol (x
);
1897 if (*symbol_type
== SYMBOL_TLS
)
1903 if (offset
== const0_rtx
)
1906 /* Check whether a nonzero offset is valid for the underlying
1908 switch (*symbol_type
)
1915 case SYMBOL_PCREL64
:
1916 /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */
1917 return sext_hwi (INTVAL (offset
), 32) == INTVAL (offset
);
1919 case SYMBOL_GOT_DISP
:
1926 /* Returns the number of instructions necessary to reference a symbol. */
1929 loongarch_symbol_insns (enum loongarch_symbol_type type
, machine_mode mode
)
1931 /* LSX LD.* and ST.* cannot support loading symbols via an immediate
1933 if (LSX_SUPPORTED_MODE_P (mode
))
1938 case SYMBOL_GOT_DISP
:
1939 /* The constant will have to be loaded from the GOT before it
1940 is used in an address. */
1941 if (!TARGET_EXPLICIT_RELOCS
&& mode
!= MAX_MACHINE_MODE
)
1955 case SYMBOL_PCREL64
:
1959 /* We don't treat a bare TLS symbol as a constant. */
1965 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
1968 loongarch_cannot_force_const_mem (machine_mode mode
, rtx x
)
1970 enum loongarch_symbol_type type
;
1973 /* As an optimization, reject constants that loongarch_legitimize_move
1976 Suppose we have a multi-instruction sequence that loads constant C
1977 into register R. If R does not get allocated a hard register, and
1978 R is used in an operand that allows both registers and memory
1979 references, reload will consider forcing C into memory and using
1980 one of the instruction's memory alternatives. Returning false
1981 here will force it to use an input reload instead. */
1982 if ((CONST_INT_P (x
) || GET_CODE (x
) == CONST_VECTOR
)
1983 && loongarch_legitimate_constant_p (mode
, x
))
1986 split_const (x
, &base
, &offset
);
1987 if (loongarch_symbolic_constant_p (base
, &type
))
1989 /* The same optimization as for CONST_INT. */
1990 if (IMM12_INT (offset
)
1991 && loongarch_symbol_insns (type
, MAX_MACHINE_MODE
) > 0)
1995 /* TLS symbols must be computed by loongarch_legitimize_move. */
1996 if (tls_referenced_p (x
))
2002 /* Return true if register REGNO is a valid base register for mode MODE.
2003 STRICT_P is true if REG_OK_STRICT is in effect. */
2006 loongarch_regno_mode_ok_for_base_p (int regno
,
2007 machine_mode mode ATTRIBUTE_UNUSED
,
2010 if (!HARD_REGISTER_NUM_P (regno
))
2014 regno
= reg_renumber
[regno
];
2017 /* These fake registers will be eliminated to either the stack or
2018 hard frame pointer, both of which are usually valid base registers.
2019 Reload deals with the cases where the eliminated form isn't valid. */
2020 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
2023 return GP_REG_P (regno
);
2026 /* Return true if X is a valid base register for mode MODE.
2027 STRICT_P is true if REG_OK_STRICT is in effect. */
2030 loongarch_valid_base_register_p (rtx x
, machine_mode mode
, bool strict_p
)
2032 if (!strict_p
&& SUBREG_P (x
))
2036 && loongarch_regno_mode_ok_for_base_p (REGNO (x
), mode
, strict_p
));
2039 /* Return true if, for every base register BASE_REG, (plus BASE_REG X)
2040 can address a value of mode MODE. */
2043 loongarch_valid_offset_p (rtx x
, machine_mode mode
)
2045 /* Check that X is a signed 12-bit number,
2046 or check that X is a signed 16-bit number
2047 and offset 4 byte aligned. */
2048 if (!(const_arith_operand (x
, Pmode
)
2049 || ((mode
== E_SImode
|| mode
== E_DImode
)
2050 && const_imm16_operand (x
, Pmode
)
2051 && (loongarch_signed_immediate_p (INTVAL (x
), 14, 2)))))
2054 /* We may need to split multiword moves, so make sure that every word
2056 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
2057 && !IMM12_OPERAND (INTVAL (x
) + GET_MODE_SIZE (mode
) - UNITS_PER_WORD
))
2060 /* LSX LD.* and ST.* supports 10-bit signed offsets. */
2061 if (LSX_SUPPORTED_MODE_P (mode
)
2062 && !loongarch_signed_immediate_p (INTVAL (x
), 10,
2063 loongarch_ldst_scaled_shift (mode
)))
2069 /* Should a symbol of type SYMBOL_TYPE should be split in two or more? */
2072 loongarch_split_symbol_type (enum loongarch_symbol_type symbol_type
)
2074 switch (symbol_type
)
2077 case SYMBOL_PCREL64
:
2078 case SYMBOL_GOT_DISP
:
2093 /* Return true if a LO_SUM can address a value of mode MODE when the
2094 LO_SUM symbol has type SYMBOL_TYPE. */
2097 loongarch_valid_lo_sum_p (enum loongarch_symbol_type symbol_type
,
2098 machine_mode mode
, rtx x
)
2102 /* Check that symbols of type SYMBOL_TYPE can be used to access values
2104 if (loongarch_symbol_insns (symbol_type
, mode
) == 0)
2107 /* Check that there is a known low-part relocation. */
2108 if (!loongarch_split_symbol_type (symbol_type
))
2111 /* We can't tell size or alignment when we have BLKmode, so try extracing a
2112 decl from the symbol if possible. */
2113 if (mode
== BLKmode
)
2117 /* Extract the symbol from the LO_SUM operand, if any. */
2118 split_const (x
, &x
, &offset
);
2120 /* Might be a CODE_LABEL. We can compute align but not size for that,
2121 so don't bother trying to handle it. */
2122 if (!SYMBOL_REF_P (x
))
2125 /* Use worst case assumptions if we don't have a SYMBOL_REF_DECL. */
2126 align
= (SYMBOL_REF_DECL (x
)
2127 ? DECL_ALIGN (SYMBOL_REF_DECL (x
))
2129 size
= (SYMBOL_REF_DECL (x
) && DECL_SIZE (SYMBOL_REF_DECL (x
))
2130 ? tree_to_uhwi (DECL_SIZE (SYMBOL_REF_DECL (x
)))
2135 align
= GET_MODE_ALIGNMENT (mode
);
2136 size
= GET_MODE_BITSIZE (mode
);
2139 /* We may need to split multiword moves, so make sure that each word
2140 can be accessed without inducing a carry. */
2141 if (size
> BITS_PER_WORD
2142 && (!TARGET_STRICT_ALIGN
|| size
> align
))
2149 loongarch_valid_index_p (struct loongarch_address_info
*info
, rtx x
,
2150 machine_mode mode
, bool strict_p
)
2154 if ((REG_P (x
) || SUBREG_P (x
))
2155 && GET_MODE (x
) == Pmode
)
2164 && contains_reg_of_mode
[GENERAL_REGS
][GET_MODE (SUBREG_REG (index
))])
2165 index
= SUBREG_REG (index
);
2167 if (loongarch_valid_base_register_p (index
, mode
, strict_p
))
2169 info
->type
= ADDRESS_REG_REG
;
2170 info
->offset
= index
;
2177 /* Return true if X is a valid address for machine mode MODE. If it is,
2178 fill in INFO appropriately. STRICT_P is true if REG_OK_STRICT is in
2182 loongarch_classify_address (struct loongarch_address_info
*info
, rtx x
,
2183 machine_mode mode
, bool strict_p
)
2185 switch (GET_CODE (x
))
2189 info
->type
= ADDRESS_REG
;
2191 info
->offset
= const0_rtx
;
2192 return loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
);
2195 if (loongarch_valid_base_register_p (XEXP (x
, 0), mode
, strict_p
)
2196 && loongarch_valid_index_p (info
, XEXP (x
, 1), mode
, strict_p
))
2198 info
->reg
= XEXP (x
, 0);
2202 if (loongarch_valid_base_register_p (XEXP (x
, 1), mode
, strict_p
)
2203 && loongarch_valid_index_p (info
, XEXP (x
, 0), mode
, strict_p
))
2205 info
->reg
= XEXP (x
, 1);
2209 info
->type
= ADDRESS_REG
;
2210 info
->reg
= XEXP (x
, 0);
2211 info
->offset
= XEXP (x
, 1);
2212 return (loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
)
2213 && loongarch_valid_offset_p (info
->offset
, mode
));
2216 info
->type
= ADDRESS_LO_SUM
;
2217 info
->reg
= XEXP (x
, 0);
2218 info
->offset
= XEXP (x
, 1);
2219 /* We have to trust the creator of the LO_SUM to do something vaguely
2220 sane. Target-independent code that creates a LO_SUM should also
2221 create and verify the matching HIGH. Target-independent code that
2222 adds an offset to a LO_SUM must prove that the offset will not
2223 induce a carry. Failure to do either of these things would be
2224 a bug, and we are not required to check for it here. The MIPS
2225 backend itself should only create LO_SUMs for valid symbolic
2226 constants, with the high part being either a HIGH or a copy
2229 = loongarch_classify_symbolic_expression (info
->offset
);
2230 return (loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
)
2231 && loongarch_valid_lo_sum_p (info
->symbol_type
, mode
,
2234 /* Small-integer addresses don't occur very often, but they
2235 are legitimate if $r0 is a valid base register. */
2236 info
->type
= ADDRESS_CONST_INT
;
2237 return IMM12_OPERAND (INTVAL (x
));
2244 /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
2247 loongarch_legitimate_address_p (machine_mode mode
, rtx x
, bool strict_p
,
2248 code_helper
= ERROR_MARK
)
2250 struct loongarch_address_info addr
;
2252 return loongarch_classify_address (&addr
, x
, mode
, strict_p
);
2255 /* Return true if ADDR matches the pattern for the indexed address
2259 loongarch_index_address_p (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
)
2261 if (GET_CODE (addr
) != PLUS
2262 || !REG_P (XEXP (addr
, 0))
2263 || !REG_P (XEXP (addr
, 1)))
2268 /* Return the number of instructions needed to load or store a value
2269 of mode MODE at address X. Return 0 if X isn't valid for MODE.
2270 Assume that multiword moves may need to be split into word moves
2271 if MIGHT_SPLIT_P, otherwise assume that a single load or store is
2275 loongarch_address_insns (rtx x
, machine_mode mode
, bool might_split_p
)
2277 struct loongarch_address_info addr
;
2279 bool lsx_p
= !might_split_p
&& LSX_SUPPORTED_MODE_P (mode
);
2281 if (!loongarch_classify_address (&addr
, x
, mode
, false))
2284 /* BLKmode is used for single unaligned loads and stores and should
2285 not count as a multiword mode. (GET_MODE_SIZE (BLKmode) is pretty
2286 meaningless, so we have to single it out as a special case one way
2288 if (mode
!= BLKmode
&& might_split_p
)
2289 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
2293 if (loongarch_classify_address (&addr
, x
, mode
, false))
2299 /* LSX LD.* and ST.* supports 10-bit signed offsets. */
2300 if (loongarch_signed_immediate_p (INTVAL (addr
.offset
), 10,
2301 loongarch_ldst_scaled_shift (mode
)))
2308 case ADDRESS_REG_REG
:
2311 case ADDRESS_CONST_INT
:
2312 return lsx_p
? 0 : factor
;
2314 case ADDRESS_LO_SUM
:
2317 case ADDRESS_SYMBOLIC
:
2319 : factor
* loongarch_symbol_insns (addr
.symbol_type
, mode
);
2324 /* Return true if X fits within an unsigned field of BITS bits that is
2325 shifted left SHIFT bits before being used. */
2328 loongarch_unsigned_immediate_p (unsigned HOST_WIDE_INT x
, int bits
,
2331 return (x
& ((1 << shift
) - 1)) == 0 && x
< ((unsigned) 1 << (shift
+ bits
));
2334 /* Return true if X fits within a signed field of BITS bits that is
2335 shifted left SHIFT bits before being used. */
2338 loongarch_signed_immediate_p (unsigned HOST_WIDE_INT x
, int bits
,
2341 x
+= 1 << (bits
+ shift
- 1);
2342 return loongarch_unsigned_immediate_p (x
, bits
, shift
);
2345 /* Return the scale shift that applied to LSX LD/ST address offset. */
2348 loongarch_ldst_scaled_shift (machine_mode mode
)
2350 int shift
= exact_log2 (GET_MODE_UNIT_SIZE (mode
));
2352 if (shift
< 0 || shift
> 8)
2358 /* Return true if X is a legitimate address with a 12-bit offset
2359 or addr.type is ADDRESS_LO_SUM.
2360 MODE is the mode of the value being accessed. */
2363 loongarch_12bit_offset_address_p (rtx x
, machine_mode mode
)
2365 struct loongarch_address_info addr
;
2367 return (loongarch_classify_address (&addr
, x
, mode
, false)
2368 && ((addr
.type
== ADDRESS_REG
2369 && CONST_INT_P (addr
.offset
)
2370 && LARCH_12BIT_OFFSET_P (INTVAL (addr
.offset
)))
2371 || addr
.type
== ADDRESS_LO_SUM
));
2374 /* Return true if X is a legitimate address with a 14-bit offset shifted 2.
2375 MODE is the mode of the value being accessed. */
2378 loongarch_14bit_shifted_offset_address_p (rtx x
, machine_mode mode
)
2380 struct loongarch_address_info addr
;
2382 return (loongarch_classify_address (&addr
, x
, mode
, false)
2383 && addr
.type
== ADDRESS_REG
2384 && CONST_INT_P (addr
.offset
)
2385 && LARCH_16BIT_OFFSET_P (INTVAL (addr
.offset
))
2386 && LARCH_SHIFT_2_OFFSET_P (INTVAL (addr
.offset
)));
2389 /* Return true if X is a legitimate address with base and index.
2390 MODE is the mode of the value being accessed. */
2393 loongarch_base_index_address_p (rtx x
, machine_mode mode
)
2395 struct loongarch_address_info addr
;
2397 return (loongarch_classify_address (&addr
, x
, mode
, false)
2398 && addr
.type
== ADDRESS_REG_REG
2399 && REG_P (addr
.offset
));
2402 /* Return the number of instructions needed to load constant X,
2403 Return 0 if X isn't a valid constant. */
2406 loongarch_const_insns (rtx x
)
2408 enum loongarch_symbol_type symbol_type
;
2411 switch (GET_CODE (x
))
2414 if (!loongarch_symbolic_constant_p (XEXP (x
, 0), &symbol_type
)
2415 || !loongarch_split_symbol_type (symbol_type
))
2418 /* This is simply a PCALAU12I. */
2422 return loongarch_integer_cost (INTVAL (x
));
2425 if (LSX_SUPPORTED_MODE_P (GET_MODE (x
))
2426 && loongarch_const_vector_same_int_p (x
, GET_MODE (x
), -512, 511))
2430 return x
== CONST0_RTX (GET_MODE (x
)) ? 1 : 0;
2433 /* See if we can refer to X directly. */
2434 if (loongarch_symbolic_constant_p (x
, &symbol_type
))
2435 return loongarch_symbol_insns (symbol_type
, MAX_MACHINE_MODE
);
2437 /* Otherwise try splitting the constant into a base and offset.
2438 If the offset is a 12-bit value, we can load the base address
2439 into a register and then use ADDI.{W/D} to add in the offset.
2440 If the offset is larger, we can load the base and offset
2441 into separate registers and add them together with ADD.{W/D}.
2442 However, the latter is only possible before reload; during
2443 and after reload, we must have the option of forcing the
2444 constant into the pool instead. */
2445 split_const (x
, &x
, &offset
);
2448 int n
= loongarch_const_insns (x
);
2451 if (IMM12_INT (offset
))
2453 else if (!targetm
.cannot_force_const_mem (GET_MODE (x
), x
))
2454 return n
+ 1 + loongarch_integer_cost (INTVAL (offset
));
2461 return loongarch_symbol_insns (
2462 loongarch_classify_symbol (x
), MAX_MACHINE_MODE
);
2469 /* X is a doubleword constant that can be handled by splitting it into
2470 two words and loading each word separately. Return the number of
2471 instructions required to do this. */
2474 loongarch_split_const_insns (rtx x
)
2476 unsigned int low
, high
;
2478 low
= loongarch_const_insns (loongarch_subword (x
, false));
2479 high
= loongarch_const_insns (loongarch_subword (x
, true));
2480 gcc_assert (low
> 0 && high
> 0);
2484 bool loongarch_split_move_insn_p (rtx dest
, rtx src
);
2485 /* Return one word of 128-bit value OP, taking into account the fixed
2486 endianness of certain registers. BYTE selects from the byte address. */
2489 loongarch_subword_at_byte (rtx op
, unsigned int byte
)
2493 mode
= GET_MODE (op
);
2494 if (mode
== VOIDmode
)
2497 gcc_assert (!FP_REG_RTX_P (op
));
2500 return loongarch_rewrite_small_data (adjust_address (op
, word_mode
, byte
));
2502 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
2505 /* Return the number of instructions needed to implement INSN,
2506 given that it loads from or stores to MEM. */
2509 loongarch_load_store_insns (rtx mem
, rtx_insn
*insn
)
2515 gcc_assert (MEM_P (mem
));
2516 mode
= GET_MODE (mem
);
2518 /* Try to prove that INSN does not need to be split. */
2519 might_split_p
= GET_MODE_SIZE (mode
) > UNITS_PER_WORD
;
2522 set
= single_set (insn
);
2524 && !loongarch_split_move_insn_p (SET_DEST (set
), SET_SRC (set
)))
2525 might_split_p
= false;
2528 return loongarch_address_insns (XEXP (mem
, 0), mode
, might_split_p
);
2531 /* Return true if we need to trap on division by zero. */
2534 loongarch_check_zero_div_p (void)
2536 /* if -m[no-]check-zero-division is given explicitly. */
2537 if (target_flags_explicit
& MASK_CHECK_ZERO_DIV
)
2538 return TARGET_CHECK_ZERO_DIV
;
2540 /* if not, don't trap for optimized code except -Og. */
2541 return !optimize
|| optimize_debug
;
2544 /* Return the number of instructions needed for an integer division. */
2547 loongarch_idiv_insns (machine_mode mode ATTRIBUTE_UNUSED
)
2552 if (loongarch_check_zero_div_p ())
2558 /* Emit an instruction of the form (set TARGET (CODE OP0 OP1)). */
2561 loongarch_emit_binary (enum rtx_code code
, rtx target
, rtx op0
, rtx op1
)
2563 emit_insn (gen_rtx_SET (target
, gen_rtx_fmt_ee (code
, GET_MODE (target
),
2567 /* Compute (CODE OP0 OP1) and store the result in a new register
2568 of mode MODE. Return that new register. */
2571 loongarch_force_binary (machine_mode mode
, enum rtx_code code
, rtx op0
,
2576 reg
= gen_reg_rtx (mode
);
2577 loongarch_emit_binary (code
, reg
, op0
, op1
);
2581 /* Copy VALUE to a register and return that register. If new pseudos
2582 are allowed, copy it into a new register, otherwise use DEST. */
2585 loongarch_force_temporary (rtx dest
, rtx value
)
2587 if (can_create_pseudo_p ())
2588 return force_reg (Pmode
, value
);
2591 loongarch_emit_move (dest
, value
);
2596 /* Wrap symbol or label BASE in an UNSPEC address of type SYMBOL_TYPE,
2597 then add CONST_INT OFFSET to the result. */
2600 loongarch_unspec_address_offset (rtx base
, rtx offset
,
2601 enum loongarch_symbol_type symbol_type
)
2603 base
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, base
),
2604 UNSPEC_ADDRESS_FIRST
+ symbol_type
);
2605 if (offset
!= const0_rtx
)
2606 base
= gen_rtx_PLUS (Pmode
, base
, offset
);
2607 return gen_rtx_CONST (Pmode
, base
);
2610 /* Return an UNSPEC address with underlying address ADDRESS and symbol
2611 type SYMBOL_TYPE. */
2614 loongarch_unspec_address (rtx address
, enum loongarch_symbol_type symbol_type
)
2618 split_const (address
, &base
, &offset
);
2619 return loongarch_unspec_address_offset (base
, offset
, symbol_type
);
2622 /* Emit an instruction of the form (set TARGET SRC). */
2625 loongarch_emit_set (rtx target
, rtx src
)
2627 emit_insn (gen_rtx_SET (target
, src
));
2631 /* If OP is an UNSPEC address, return the address to which it refers,
2632 otherwise return OP itself. */
2635 loongarch_strip_unspec_address (rtx op
)
2639 split_const (op
, &base
, &offset
);
2640 if (UNSPEC_ADDRESS_P (base
))
2641 op
= plus_constant (Pmode
, UNSPEC_ADDRESS (base
), INTVAL (offset
));
2645 /* Return a legitimate address for REG + OFFSET. TEMP is as for
2646 loongarch_force_temporary; it is only needed when OFFSET is not a
2650 loongarch_add_offset (rtx temp
, rtx reg
, HOST_WIDE_INT offset
)
2652 if (!IMM12_OPERAND (offset
))
2656 /* Leave OFFSET as a 12-bit offset and put the excess in HIGH.
2657 The addition inside the macro CONST_HIGH_PART may cause an
2658 overflow, so we need to force a sign-extension check. */
2659 high
= gen_int_mode (CONST_HIGH_PART (offset
), Pmode
);
2660 offset
= CONST_LOW_PART (offset
);
2661 high
= loongarch_force_temporary (temp
, high
);
2662 reg
= loongarch_force_temporary (temp
, gen_rtx_PLUS (Pmode
, high
, reg
));
2664 return plus_constant (Pmode
, reg
, offset
);
2667 /* The __tls_get_attr symbol. */
2668 static GTY (()) rtx loongarch_tls_symbol
;
2670 /* Load an entry from the GOT for a TLS GD access. */
2673 loongarch_got_load_tls_gd (rtx dest
, rtx sym
)
2675 return gen_got_load_tls_gd (Pmode
, dest
, sym
);
2678 /* Load an entry from the GOT for a TLS LD access. */
2681 loongarch_got_load_tls_ld (rtx dest
, rtx sym
)
2683 return gen_got_load_tls_ld (Pmode
, dest
, sym
);
2686 /* Load an entry from the GOT for a TLS IE access. */
2689 loongarch_got_load_tls_ie (rtx dest
, rtx sym
)
2691 return gen_got_load_tls_ie (Pmode
, dest
, sym
);
2694 /* Add in the thread pointer for a TLS LE access. */
2697 loongarch_got_load_tls_le (rtx dest
, rtx sym
)
2699 return gen_got_load_tls_le (Pmode
, dest
, sym
);
2702 /* Return an instruction sequence that calls __tls_get_addr. SYM is
2703 the TLS symbol we are referencing and TYPE is the symbol type to use
2704 (either global dynamic or local dynamic). V0 is an RTX for the
2705 return value location. */
2708 loongarch_call_tls_get_addr (rtx sym
, enum loongarch_symbol_type type
, rtx v0
)
2712 rtx tmp
= gen_reg_rtx (Pmode
);
2714 a0
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
);
2716 if (!loongarch_tls_symbol
)
2717 loongarch_tls_symbol
= init_one_libfunc ("__tls_get_addr");
2719 loc
= loongarch_unspec_address (sym
, type
);
2723 if (TARGET_EXPLICIT_RELOCS
)
2725 /* Split tls symbol to high and low. */
2726 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (loc
));
2727 high
= loongarch_force_temporary (tmp
, high
);
2729 if (TARGET_CMODEL_EXTREME
)
2731 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2733 rtx tmp1
= gen_reg_rtx (Pmode
);
2734 emit_insn (gen_tls_low (Pmode
, tmp1
, gen_rtx_REG (Pmode
, 0), loc
));
2735 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, loc
));
2736 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, loc
));
2737 emit_move_insn (a0
, gen_rtx_PLUS (Pmode
, high
, tmp1
));
2740 emit_insn (gen_tls_low (Pmode
, a0
, high
, loc
));
2744 if (type
== SYMBOL_TLSLDM
)
2745 emit_insn (loongarch_got_load_tls_ld (a0
, loc
));
2746 else if (type
== SYMBOL_TLSGD
)
2747 emit_insn (loongarch_got_load_tls_gd (a0
, loc
));
2754 switch (la_target
.cmodel
)
2757 insn
= emit_call_insn (gen_call_value_internal (v0
,
2758 loongarch_tls_symbol
,
2764 rtx reg
= gen_reg_rtx (Pmode
);
2765 if (TARGET_EXPLICIT_RELOCS
)
2767 emit_insn (gen_pcalau12i (Pmode
, reg
, loongarch_tls_symbol
));
2768 rtx call
= gen_call_value_internal_1 (Pmode
, v0
, reg
,
2769 loongarch_tls_symbol
,
2771 insn
= emit_call_insn (call
);
2775 emit_move_insn (reg
, loongarch_tls_symbol
);
2776 insn
= emit_call_insn (gen_call_value_internal (v0
,
2783 /* code model extreme not support plt. */
2784 case CMODEL_EXTREME
:
2787 case CMODEL_TINY_STATIC
:
2794 rtx dest
= gen_reg_rtx (Pmode
);
2796 switch (la_target
.cmodel
)
2801 if (TARGET_EXPLICIT_RELOCS
)
2803 rtx high
= gen_reg_rtx (Pmode
);
2804 loongarch_emit_move (high
,
2805 gen_rtx_HIGH (Pmode
,
2806 loongarch_tls_symbol
));
2807 emit_insn (gen_ld_from_got (Pmode
, dest
, high
,
2808 loongarch_tls_symbol
));
2811 loongarch_emit_move (dest
, loongarch_tls_symbol
);
2815 case CMODEL_EXTREME
:
2817 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2819 rtx tmp1
= gen_reg_rtx (Pmode
);
2820 rtx high
= gen_reg_rtx (Pmode
);
2822 loongarch_emit_move (high
,
2823 gen_rtx_HIGH (Pmode
, loongarch_tls_symbol
));
2824 loongarch_emit_move (tmp1
, gen_rtx_LO_SUM (Pmode
,
2825 gen_rtx_REG (Pmode
, 0),
2826 loongarch_tls_symbol
));
2827 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, loongarch_tls_symbol
));
2828 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, loongarch_tls_symbol
));
2829 loongarch_emit_move (dest
,
2831 gen_rtx_PLUS (Pmode
,
2838 case CMODEL_TINY_STATIC
:
2843 insn
= emit_call_insn (gen_call_value_internal (v0
, dest
, const0_rtx
));
2846 RTL_CONST_CALL_P (insn
) = 1;
2847 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), a0
);
2848 insn
= get_insns ();
2855 /* Generate the code to access LOC, a thread-local SYMBOL_REF, and return
2856 its address. The return value will be both a valid address and a valid
2857 SET_SRC (either a REG or a LO_SUM). */
2860 loongarch_legitimize_tls_address (rtx loc
)
2862 rtx dest
, tp
, tmp
, tmp1
, tmp2
, tmp3
;
2863 enum tls_model model
= SYMBOL_REF_TLS_MODEL (loc
);
2868 case TLS_MODEL_LOCAL_DYNAMIC
:
2869 tmp
= gen_rtx_REG (Pmode
, GP_RETURN
);
2870 dest
= gen_reg_rtx (Pmode
);
2871 insn
= loongarch_call_tls_get_addr (loc
, SYMBOL_TLSLDM
, tmp
);
2872 emit_libcall_block (insn
, dest
, tmp
, loc
);
2875 case TLS_MODEL_GLOBAL_DYNAMIC
:
2876 tmp
= gen_rtx_REG (Pmode
, GP_RETURN
);
2877 dest
= gen_reg_rtx (Pmode
);
2878 insn
= loongarch_call_tls_get_addr (loc
, SYMBOL_TLSGD
, tmp
);
2879 emit_libcall_block (insn
, dest
, tmp
, loc
);
2882 case TLS_MODEL_INITIAL_EXEC
:
2884 /* la.tls.ie; tp-relative add. */
2885 tp
= gen_rtx_REG (Pmode
, THREAD_POINTER_REGNUM
);
2886 tmp1
= gen_reg_rtx (Pmode
);
2887 dest
= gen_reg_rtx (Pmode
);
2888 if (TARGET_EXPLICIT_RELOCS
)
2890 tmp2
= loongarch_unspec_address (loc
, SYMBOL_TLS_IE
);
2891 tmp3
= gen_reg_rtx (Pmode
);
2892 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (tmp2
));
2893 high
= loongarch_force_temporary (tmp3
, high
);
2895 if (TARGET_CMODEL_EXTREME
)
2897 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2899 rtx tmp3
= gen_reg_rtx (Pmode
);
2900 emit_insn (gen_tls_low (Pmode
, tmp3
,
2901 gen_rtx_REG (Pmode
, 0), tmp2
));
2902 emit_insn (gen_lui_h_lo20 (tmp3
, tmp3
, tmp2
));
2903 emit_insn (gen_lui_h_hi12 (tmp3
, tmp3
, tmp2
));
2904 emit_move_insn (tmp1
,
2906 gen_rtx_PLUS (Pmode
,
2910 emit_insn (gen_ld_from_got (Pmode
, tmp1
, high
, tmp2
));
2913 emit_insn (loongarch_got_load_tls_ie (tmp1
, loc
));
2914 emit_insn (gen_add3_insn (dest
, tmp1
, tp
));
2918 case TLS_MODEL_LOCAL_EXEC
:
2920 /* la.tls.le; tp-relative add. */
2921 tp
= gen_rtx_REG (Pmode
, THREAD_POINTER_REGNUM
);
2922 tmp1
= gen_reg_rtx (Pmode
);
2923 dest
= gen_reg_rtx (Pmode
);
2925 if (TARGET_EXPLICIT_RELOCS
)
2927 tmp2
= loongarch_unspec_address (loc
, SYMBOL_TLS_LE
);
2928 tmp3
= gen_reg_rtx (Pmode
);
2929 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (tmp2
));
2930 high
= loongarch_force_temporary (tmp3
, high
);
2931 emit_insn (gen_ori_l_lo12 (Pmode
, tmp1
, high
, tmp2
));
2933 if (TARGET_CMODEL_EXTREME
)
2935 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2937 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, tmp2
));
2938 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, tmp2
));
2942 emit_insn (loongarch_got_load_tls_le (tmp1
, loc
));
2943 emit_insn (gen_add3_insn (dest
, tmp1
, tp
));
2954 loongarch_legitimize_call_address (rtx addr
)
2956 if (!call_insn_operand (addr
, VOIDmode
))
2958 rtx reg
= gen_reg_rtx (Pmode
);
2959 loongarch_emit_move (reg
, addr
);
2963 enum loongarch_symbol_type symbol_type
= loongarch_classify_symbol (addr
);
2965 /* Split function call insn 'bl sym' or 'bl %plt(sym)' to :
2966 pcalau12i $rd, %pc_hi20(sym)
2967 jr $rd, %pc_lo12(sym). */
2969 if (TARGET_CMODEL_MEDIUM
2970 && TARGET_EXPLICIT_RELOCS
2971 && (SYMBOL_REF_P (addr
) || LABEL_REF_P (addr
))
2972 && (symbol_type
== SYMBOL_PCREL
2973 || (symbol_type
== SYMBOL_GOT_DISP
&& flag_plt
)))
2975 rtx reg
= gen_reg_rtx (Pmode
);
2976 emit_insn (gen_pcalau12i (Pmode
, reg
, addr
));
2977 return gen_rtx_LO_SUM (Pmode
, reg
, addr
);
2983 /* If X is a PLUS of a CONST_INT, return the two terms in *BASE_PTR
2984 and *OFFSET_PTR. Return X in *BASE_PTR and 0 in *OFFSET_PTR otherwise. */
2987 loongarch_split_plus (rtx x
, rtx
*base_ptr
, HOST_WIDE_INT
*offset_ptr
)
2989 if (GET_CODE (x
) == PLUS
&& CONST_INT_P (XEXP (x
, 1)))
2991 *base_ptr
= XEXP (x
, 0);
2992 *offset_ptr
= INTVAL (XEXP (x
, 1));
3001 /* If X is not a valid address for mode MODE, force it into a register. */
3004 loongarch_force_address (rtx x
, machine_mode mode
)
3006 if (!loongarch_legitimate_address_p (mode
, x
, false))
3007 x
= force_reg (Pmode
, x
);
3012 loongarch_symbol_extreme_p (enum loongarch_symbol_type type
)
3018 case SYMBOL_PCREL64
:
3021 return TARGET_CMODEL_EXTREME
;
3025 /* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
3026 it appears in a MEM of that mode. Return true if ADDR is a legitimate
3027 constant in that context and can be split into high and low parts.
3028 If so, and if LOW_OUT is nonnull, emit the high part and store the
3029 low part in *LOW_OUT. Leave *LOW_OUT unchanged otherwise.
3031 Return false if build with '-mno-explicit-relocs'.
3033 TEMP is as for loongarch_force_temporary and is used to load the high
3034 part into a register.
3036 When MODE is MAX_MACHINE_MODE, the low part is guaranteed to be
3037 a legitimize SET_SRC for an .md pattern, otherwise the low part
3038 is guaranteed to be a legitimate address for mode MODE. */
3041 loongarch_split_symbol (rtx temp
, rtx addr
, machine_mode mode
, rtx
*low_out
)
3043 enum loongarch_symbol_type symbol_type
;
3045 /* If build with '-mno-explicit-relocs', don't split symbol. */
3046 if (!TARGET_EXPLICIT_RELOCS
)
3049 if ((GET_CODE (addr
) == HIGH
&& mode
== MAX_MACHINE_MODE
)
3050 || !loongarch_symbolic_constant_p (addr
, &symbol_type
)
3051 || loongarch_symbol_insns (symbol_type
, mode
) == 0
3052 || !loongarch_split_symbol_type (symbol_type
))
3055 rtx high
, temp1
= NULL
;
3058 temp
= gen_reg_rtx (Pmode
);
3060 /* Get the 12-31 bits of the address. */
3061 high
= gen_rtx_HIGH (Pmode
, copy_rtx (addr
));
3062 high
= loongarch_force_temporary (temp
, high
);
3064 if (loongarch_symbol_extreme_p (symbol_type
) && can_create_pseudo_p ())
3066 gcc_assert (TARGET_EXPLICIT_RELOCS
);
3068 temp1
= gen_reg_rtx (Pmode
);
3069 emit_move_insn (temp1
, gen_rtx_LO_SUM (Pmode
, gen_rtx_REG (Pmode
, 0),
3071 emit_insn (gen_lui_h_lo20 (temp1
, temp1
, addr
));
3072 emit_insn (gen_lui_h_hi12 (temp1
, temp1
, addr
));
3076 switch (symbol_type
)
3078 case SYMBOL_PCREL64
:
3079 if (can_create_pseudo_p ())
3081 *low_out
= gen_rtx_PLUS (Pmode
, high
, temp1
);
3086 *low_out
= gen_rtx_LO_SUM (Pmode
, high
, addr
);
3089 case SYMBOL_GOT_DISP
:
3090 /* SYMBOL_GOT_DISP symbols are loaded from the GOT. */
3092 if (TARGET_CMODEL_EXTREME
&& can_create_pseudo_p ())
3093 *low_out
= gen_rtx_MEM (Pmode
, gen_rtx_PLUS (Pmode
, high
, temp1
));
3096 rtx low
= gen_rtx_LO_SUM (Pmode
, high
, addr
);
3097 rtx mem
= gen_rtx_MEM (Pmode
, low
);
3098 *low_out
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, mem
),
3099 UNSPEC_LOAD_FROM_GOT
);
3112 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
3113 be legitimized in a way that the generic machinery might not expect,
3114 return a new address, otherwise return NULL. MODE is the mode of
3115 the memory being accessed. */
3118 loongarch_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
3122 HOST_WIDE_INT offset
;
3124 if (loongarch_tls_symbol_p (x
))
3125 return loongarch_legitimize_tls_address (x
);
3127 /* See if the address can split into a high part and a LO_SUM. */
3128 if (loongarch_split_symbol (NULL
, x
, mode
, &addr
))
3129 return loongarch_force_address (addr
, mode
);
3131 /* Handle BASE + OFFSET using loongarch_add_offset. */
3132 loongarch_split_plus (x
, &base
, &offset
);
3135 if (!loongarch_valid_base_register_p (base
, mode
, false))
3136 base
= copy_to_mode_reg (Pmode
, base
);
3137 addr
= loongarch_add_offset (NULL
, base
, offset
);
3138 return loongarch_force_address (addr
, mode
);
3144 /* Load VALUE into DEST. TEMP is as for loongarch_force_temporary. */
3147 loongarch_move_integer (rtx temp
, rtx dest
, unsigned HOST_WIDE_INT value
)
3149 struct loongarch_integer_op codes
[LARCH_MAX_INTEGER_OPS
];
3151 unsigned int i
, num_ops
;
3154 mode
= GET_MODE (dest
);
3155 num_ops
= loongarch_build_integer (codes
, value
);
3157 /* Apply each binary operation to X. Invariant: X is a legitimate
3158 source operand for a SET pattern. */
3159 x
= GEN_INT (codes
[0].value
);
3160 for (i
= 1; i
< num_ops
; i
++)
3162 if (!can_create_pseudo_p ())
3164 emit_insn (gen_rtx_SET (temp
, x
));
3168 x
= force_reg (mode
, x
);
3170 set_unique_reg_note (get_last_insn (), REG_EQUAL
,
3171 GEN_INT (codes
[i
-1].curr_value
));
3173 switch (codes
[i
].method
)
3176 x
= gen_rtx_fmt_ee (codes
[i
].code
, mode
, x
,
3177 GEN_INT (codes
[i
].value
));
3180 gcc_assert (mode
== DImode
);
3181 x
= gen_rtx_IOR (DImode
,
3182 gen_rtx_ZERO_EXTEND (DImode
,
3183 gen_rtx_SUBREG (SImode
, x
, 0)),
3184 GEN_INT (codes
[i
].value
));
3187 gcc_assert (mode
== DImode
);
3188 x
= gen_rtx_IOR (DImode
,
3189 gen_rtx_AND (DImode
, x
, GEN_INT (0xfffffffffffff)),
3190 GEN_INT (codes
[i
].value
));
3197 emit_insn (gen_rtx_SET (dest
, x
));
3200 /* Subroutine of loongarch_legitimize_move. Move constant SRC into register
3201 DEST given that SRC satisfies immediate_operand but doesn't satisfy
3205 loongarch_legitimize_const_move (machine_mode mode
, rtx dest
, rtx src
)
3209 /* Split moves of big integers into smaller pieces. */
3210 if (splittable_const_int_operand (src
, mode
))
3212 loongarch_move_integer (dest
, dest
, INTVAL (src
));
3216 /* Split moves of symbolic constants into high and low. */
3217 if (loongarch_split_symbol (dest
, src
, MAX_MACHINE_MODE
, &src
))
3219 loongarch_emit_set (dest
, src
);
3223 /* Generate the appropriate access sequences for TLS symbols. */
3224 if (loongarch_tls_symbol_p (src
))
3226 loongarch_emit_move (dest
, loongarch_legitimize_tls_address (src
));
3230 /* If we have (const (plus symbol offset)), and that expression cannot
3231 be forced into memory, load the symbol first and add in the offset.
3232 prefer to do this even if the constant _can_ be forced into memory,
3233 as it usually produces better code. */
3234 split_const (src
, &base
, &offset
);
3235 if (offset
!= const0_rtx
3236 && (targetm
.cannot_force_const_mem (mode
, src
)
3237 || (can_create_pseudo_p ())))
3239 base
= loongarch_force_temporary (dest
, base
);
3240 loongarch_emit_move (dest
,
3241 loongarch_add_offset (NULL
, base
, INTVAL (offset
)));
3245 src
= force_const_mem (mode
, src
);
3247 loongarch_emit_move (dest
, src
);
3250 /* If (set DEST SRC) is not a valid move instruction, emit an equivalent
3251 sequence that is valid. */
3254 loongarch_legitimize_move (machine_mode mode
, rtx dest
, rtx src
)
3256 if (!register_operand (dest
, mode
) && !reg_or_0_operand (src
, mode
))
3258 loongarch_emit_move (dest
, force_reg (mode
, src
));
3262 /* Both src and dest are non-registers; one special case is supported where
3263 the source is (const_int 0) and the store can source the zero register.
3264 LSX is never able to source the zero register directly in
3265 memory operations. */
3266 if (!register_operand (dest
, mode
) && !register_operand (src
, mode
)
3267 && (!const_0_operand (src
, mode
) || LSX_SUPPORTED_MODE_P (mode
)))
3269 loongarch_emit_move (dest
, force_reg (mode
, src
));
3273 /* We need to deal with constants that would be legitimate
3274 immediate_operands but aren't legitimate move_operands. */
3275 if (CONSTANT_P (src
) && !move_operand (src
, mode
))
3277 loongarch_legitimize_const_move (mode
, dest
, src
);
3278 set_unique_reg_note (get_last_insn (), REG_EQUAL
, copy_rtx (src
));
3285 /* Return true if OP refers to small data symbols directly. */
3288 loongarch_small_data_pattern_1 (rtx x
)
3290 subrtx_var_iterator::array_type array
;
3291 FOR_EACH_SUBRTX_VAR (iter
, array
, x
, ALL
)
3295 /* We make no particular guarantee about which symbolic constants are
3296 acceptable as asm operands versus which must be forced into a GPR. */
3297 if (GET_CODE (x
) == ASM_OPERANDS
)
3298 iter
.skip_subrtxes ();
3301 if (loongarch_small_data_pattern_1 (XEXP (x
, 0)))
3303 iter
.skip_subrtxes ();
3309 /* Return true if OP refers to small data symbols directly. */
3312 loongarch_small_data_pattern_p (rtx op
)
3314 return loongarch_small_data_pattern_1 (op
);
3317 /* Rewrite *LOC so that it refers to small data using explicit
3321 loongarch_rewrite_small_data_1 (rtx
*loc
)
3323 subrtx_ptr_iterator::array_type array
;
3324 FOR_EACH_SUBRTX_PTR (iter
, array
, loc
, ALL
)
3329 loongarch_rewrite_small_data_1 (&XEXP (*loc
, 0));
3330 iter
.skip_subrtxes ();
3335 /* Rewrite instruction pattern PATTERN so that it refers to small data
3336 using explicit relocations. */
3339 loongarch_rewrite_small_data (rtx pattern
)
3341 pattern
= copy_insn (pattern
);
3342 loongarch_rewrite_small_data_1 (&pattern
);
3346 /* The cost of loading values from the constant pool. It should be
3347 larger than the cost of any constant we want to synthesize inline. */
3348 #define CONSTANT_POOL_COST COSTS_N_INSNS (8)
3350 /* Return true if there is a instruction that implements CODE
3351 and if that instruction accepts X as an immediate operand. */
3354 loongarch_immediate_operand_p (int code
, HOST_WIDE_INT x
)
3361 /* All shift counts are truncated to a valid constant. */
3371 /* These instructions take 12-bit unsigned immediates. */
3372 return IMM12_OPERAND_UNSIGNED (x
);
3377 /* These instructions take 12-bit signed immediates. */
3378 return IMM12_OPERAND (x
);
3384 /* The "immediate" forms of these instructions are really
3385 implemented as comparisons with register 0. */
3390 /* Likewise, meaning that the only valid immediate operand is 1. */
3394 /* We add 1 to the immediate and use SLT. */
3395 return IMM12_OPERAND (x
+ 1);
3398 /* Likewise SLTU, but reject the always-true case. */
3399 return IMM12_OPERAND (x
+ 1) && x
+ 1 != 0;
3403 /* The bit position and size are immediate operands. */
3407 /* By default assume that $0 can be used for 0. */
3412 /* Return the cost of binary operation X, given that the instruction
3413 sequence for a word-sized or smaller operation has cost SINGLE_COST
3414 and that the sequence of a double-word operation has cost DOUBLE_COST.
3415 If SPEED is true, optimize for speed otherwise optimize for size. */
3418 loongarch_binary_cost (rtx x
, int single_cost
, int double_cost
, bool speed
)
3422 if (GET_MODE_SIZE (GET_MODE (x
)) == UNITS_PER_WORD
* 2)
3427 + set_src_cost (XEXP (x
, 0), GET_MODE (x
), speed
)
3428 + rtx_cost (XEXP (x
, 1), GET_MODE (x
), GET_CODE (x
), 1, speed
));
3431 /* Return the cost of floating-point multiplications of mode MODE. */
3434 loongarch_fp_mult_cost (machine_mode mode
)
3436 return mode
== DFmode
? loongarch_cost
->fp_mult_df
3437 : loongarch_cost
->fp_mult_sf
;
3440 /* Return the cost of floating-point divisions of mode MODE. */
3443 loongarch_fp_div_cost (machine_mode mode
)
3445 return mode
== DFmode
? loongarch_cost
->fp_div_df
3446 : loongarch_cost
->fp_div_sf
;
3449 /* Return the cost of sign-extending OP to mode MODE, not including the
3450 cost of OP itself. */
3453 loongarch_sign_extend_cost (rtx op
)
3456 /* Extended loads are as cheap as unextended ones. */
3459 return COSTS_N_INSNS (1);
3462 /* Return the cost of zero-extending OP to mode MODE, not including the
3463 cost of OP itself. */
3466 loongarch_zero_extend_cost (rtx op
)
3469 /* Extended loads are as cheap as unextended ones. */
3472 /* We can use ANDI. */
3473 return COSTS_N_INSNS (1);
3476 /* Return the cost of moving between two registers of mode MODE,
3477 assuming that the move will be in pieces of at most UNITS bytes. */
3480 loongarch_set_reg_reg_piece_cost (machine_mode mode
, unsigned int units
)
3482 return COSTS_N_INSNS ((GET_MODE_SIZE (mode
) + units
- 1) / units
);
3485 /* Return the cost of moving between two registers of mode MODE. */
3488 loongarch_set_reg_reg_cost (machine_mode mode
)
3490 switch (GET_MODE_CLASS (mode
))
3493 return loongarch_set_reg_reg_piece_cost (mode
, GET_MODE_SIZE (CCmode
));
3496 case MODE_COMPLEX_FLOAT
:
3497 case MODE_VECTOR_FLOAT
:
3498 if (TARGET_HARD_FLOAT
)
3499 return loongarch_set_reg_reg_piece_cost (mode
, UNITS_PER_HWFPVALUE
);
3503 return loongarch_set_reg_reg_piece_cost (mode
, UNITS_PER_WORD
);
3507 /* Implement TARGET_RTX_COSTS. */
3510 loongarch_rtx_costs (rtx x
, machine_mode mode
, int outer_code
,
3511 int opno ATTRIBUTE_UNUSED
, int *total
, bool speed
)
3513 int code
= GET_CODE (x
);
3514 bool float_mode_p
= FLOAT_MODE_P (mode
);
3518 if (outer_code
== COMPARE
)
3520 gcc_assert (CONSTANT_P (x
));
3528 if (TARGET_64BIT
&& outer_code
== AND
&& UINTVAL (x
) == 0xffffffff)
3534 /* When not optimizing for size, we care more about the cost
3535 of hot code, and hot code is often in a loop. If a constant
3536 operand needs to be forced into a register, we will often be
3537 able to hoist the constant load out of the loop, so the load
3538 should not contribute to the cost. */
3539 if (speed
|| loongarch_immediate_operand_p (outer_code
, INTVAL (x
)))
3550 cost
= loongarch_const_insns (x
);
3553 if (cost
== 1 && outer_code
== SET
3554 && !(float_mode_p
&& TARGET_HARD_FLOAT
))
3556 else if ((outer_code
== SET
|| GET_MODE (x
) == VOIDmode
))
3558 *total
= COSTS_N_INSNS (cost
);
3561 /* The value will need to be fetched from the constant pool. */
3562 *total
= CONSTANT_POOL_COST
;
3566 /* If the address is legitimate, return the number of
3567 instructions it needs. */
3569 /* Check for a scaled indexed address. */
3570 if (loongarch_index_address_p (addr
, mode
))
3572 *total
= COSTS_N_INSNS (2);
3575 cost
= loongarch_address_insns (addr
, mode
, true);
3578 *total
= COSTS_N_INSNS (cost
+ 1);
3581 /* Otherwise use the default handling. */
3585 *total
= COSTS_N_INSNS (6);
3589 *total
= COSTS_N_INSNS (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 2 : 1);
3593 /* Check for a *clear_upper32 pattern and treat it like a zero
3594 extension. See the pattern's comment for details. */
3595 if (TARGET_64BIT
&& mode
== DImode
&& CONST_INT_P (XEXP (x
, 1))
3596 && UINTVAL (XEXP (x
, 1)) == 0xffffffff)
3598 *total
= (loongarch_zero_extend_cost (XEXP (x
, 0))
3599 + set_src_cost (XEXP (x
, 0), mode
, speed
));
3602 /* (AND (NOT op0) (NOT op1) is a nor operation that can be done in
3603 a single instruction. */
3604 if (GET_CODE (XEXP (x
, 0)) == NOT
&& GET_CODE (XEXP (x
, 1)) == NOT
)
3606 cost
= GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 2 : 1;
3607 *total
= (COSTS_N_INSNS (cost
)
3608 + set_src_cost (XEXP (XEXP (x
, 0), 0), mode
, speed
)
3609 + set_src_cost (XEXP (XEXP (x
, 1), 0), mode
, speed
));
3617 /* Double-word operations use two single-word operations. */
3618 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (2),
3627 if (CONSTANT_P (XEXP (x
, 1)))
3628 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1),
3629 COSTS_N_INSNS (4), speed
);
3631 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1),
3632 COSTS_N_INSNS (12), speed
);
3637 *total
= loongarch_cost
->fp_add
;
3639 *total
= COSTS_N_INSNS (4);
3658 /* Branch comparisons have VOIDmode, so use the first operand's
3660 mode
= GET_MODE (XEXP (x
, 0));
3661 if (FLOAT_MODE_P (mode
))
3663 *total
= loongarch_cost
->fp_add
;
3666 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (4),
3674 *total
= loongarch_cost
->fp_add
;
3678 /* If it's an add + mult (which is equivalent to shift left) and
3679 it's immediate operand satisfies const_immalsl_operand predicate. */
3680 if ((mode
== SImode
|| (TARGET_64BIT
&& mode
== DImode
))
3681 && GET_CODE (XEXP (x
, 0)) == MULT
)
3683 rtx op2
= XEXP (XEXP (x
, 0), 1);
3684 if (const_immalsl_operand (op2
, mode
))
3686 *total
= (COSTS_N_INSNS (1)
3687 + set_src_cost (XEXP (XEXP (x
, 0), 0), mode
, speed
)
3688 + set_src_cost (XEXP (x
, 1), mode
, speed
));
3693 /* Double-word operations require three single-word operations and
3695 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (4),
3701 *total
= loongarch_cost
->fp_add
;
3703 *total
= COSTS_N_INSNS (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 4 : 1);
3707 *total
= loongarch_fp_mult_cost (mode
);
3712 *total
= loongarch_fp_mult_cost (mode
);
3713 else if (mode
== DImode
&& !TARGET_64BIT
)
3715 ? loongarch_cost
->int_mult_si
* 3 + 6
3716 : COSTS_N_INSNS (7));
3718 *total
= COSTS_N_INSNS (1) + 1;
3719 else if (mode
== DImode
)
3720 *total
= loongarch_cost
->int_mult_di
;
3722 *total
= loongarch_cost
->int_mult_si
;
3726 /* Check for a reciprocal. */
3728 && flag_unsafe_math_optimizations
3729 && XEXP (x
, 0) == CONST1_RTX (mode
))
3731 if (outer_code
== SQRT
|| GET_CODE (XEXP (x
, 1)) == SQRT
)
3732 /* An rsqrt<mode>a or rsqrt<mode>b pattern. Count the
3733 division as being free. */
3734 *total
= set_src_cost (XEXP (x
, 1), mode
, speed
);
3736 *total
= (loongarch_fp_div_cost (mode
)
3737 + set_src_cost (XEXP (x
, 1), mode
, speed
));
3746 *total
= loongarch_fp_div_cost (mode
);
3755 *total
= COSTS_N_INSNS (loongarch_idiv_insns (mode
));
3757 else if (mode
== DImode
)
3758 *total
= loongarch_cost
->int_div_di
;
3760 *total
= loongarch_cost
->int_div_si
;
3764 *total
= loongarch_sign_extend_cost (XEXP (x
, 0));
3768 *total
= loongarch_zero_extend_cost (XEXP (x
, 0));
3771 /* Costings for highpart multiplies. Matching patterns of the form:
3773 (lshiftrt:DI (mult:DI (sign_extend:DI (...)
3774 (sign_extend:DI (...))
3777 if ((GET_CODE (XEXP (x
, 0)) == ASHIFTRT
3778 || GET_CODE (XEXP (x
, 0)) == LSHIFTRT
)
3779 && CONST_INT_P (XEXP (XEXP (x
, 0), 1))
3780 && ((INTVAL (XEXP (XEXP (x
, 0), 1)) == 32
3781 && GET_MODE (XEXP (x
, 0)) == DImode
)
3783 && INTVAL (XEXP (XEXP (x
, 0), 1)) == 64
3784 && GET_MODE (XEXP (x
, 0)) == TImode
))
3785 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
3786 && ((GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 0)) == SIGN_EXTEND
3787 && GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 1)) == SIGN_EXTEND
)
3788 || (GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 0)) == ZERO_EXTEND
3789 && (GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 1))
3793 *total
= COSTS_N_INSNS (1) + 1;
3794 else if (mode
== DImode
)
3795 *total
= loongarch_cost
->int_mult_di
;
3797 *total
= loongarch_cost
->int_mult_si
;
3799 /* Sign extension is free, zero extension costs for DImode when
3800 on a 64bit core / when DMUL is present. */
3801 for (int i
= 0; i
< 2; ++i
)
3803 rtx op
= XEXP (XEXP (XEXP (x
, 0), 0), i
);
3805 && GET_CODE (op
) == ZERO_EXTEND
3806 && GET_MODE (op
) == DImode
)
3807 *total
+= rtx_cost (op
, DImode
, MULT
, i
, speed
);
3809 *total
+= rtx_cost (XEXP (op
, 0), VOIDmode
, GET_CODE (op
), 0,
3818 case UNSIGNED_FLOAT
:
3821 case FLOAT_TRUNCATE
:
3822 *total
= loongarch_cost
->fp_add
;
3826 if (register_operand (SET_DEST (x
), VOIDmode
)
3827 && reg_or_0_operand (SET_SRC (x
), VOIDmode
))
3829 *total
= loongarch_set_reg_reg_cost (GET_MODE (SET_DEST (x
)));
3839 /* Vectorizer cost model implementation. */
3841 /* Implement targetm.vectorize.builtin_vectorization_cost. */
3844 loongarch_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost
,
3846 int misalign ATTRIBUTE_UNUSED
)
3850 switch (type_of_cost
)
3858 case cond_branch_not_taken
:
3859 case vec_promote_demote
:
3867 case unaligned_load
:
3868 case vector_gather_load
:
3871 case unaligned_store
:
3872 case vector_scatter_store
:
3875 case cond_branch_taken
:
3879 elements
= TYPE_VECTOR_SUBPARTS (vectype
);
3880 return elements
/ 2 + 1;
3887 /* Implement TARGET_ADDRESS_COST. */
3890 loongarch_address_cost (rtx addr
, machine_mode mode
,
3891 addr_space_t as ATTRIBUTE_UNUSED
,
3892 bool speed ATTRIBUTE_UNUSED
)
3894 return loongarch_address_insns (addr
, mode
, false);
3897 /* Return one word of double-word value OP, taking into account the fixed
3898 endianness of certain registers. HIGH_P is true to select the high part,
3899 false to select the low part. */
3902 loongarch_subword (rtx op
, bool high_p
)
3907 byte
= high_p
? UNITS_PER_WORD
: 0;
3908 mode
= GET_MODE (op
);
3909 if (mode
== VOIDmode
)
3910 mode
= TARGET_64BIT
? TImode
: DImode
;
3912 if (FP_REG_RTX_P (op
))
3913 return gen_rtx_REG (word_mode
, REGNO (op
) + high_p
);
3916 return loongarch_rewrite_small_data (adjust_address (op
, word_mode
, byte
));
3918 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
3921 /* Return true if a move from SRC to DEST should be split into two.
3922 SPLIT_TYPE describes the split condition. */
3925 loongarch_split_move_p (rtx dest
, rtx src
)
3927 /* FPR-to-FPR moves can be done in a single instruction, if they're
3929 unsigned int size
= GET_MODE_SIZE (GET_MODE (dest
));
3930 if (size
== 8 && FP_REG_RTX_P (src
) && FP_REG_RTX_P (dest
))
3933 /* Check for floating-point loads and stores. */
3936 if (FP_REG_RTX_P (dest
) && MEM_P (src
))
3938 if (FP_REG_RTX_P (src
) && MEM_P (dest
))
3942 /* Check if LSX moves need splitting. */
3943 if (LSX_SUPPORTED_MODE_P (GET_MODE (dest
)))
3944 return loongarch_split_128bit_move_p (dest
, src
);
3946 /* Otherwise split all multiword moves. */
3947 return size
> UNITS_PER_WORD
;
3950 /* Split a move from SRC to DEST, given that loongarch_split_move_p holds.
3951 SPLIT_TYPE describes the split condition. */
3954 loongarch_split_move (rtx dest
, rtx src
, rtx insn_
)
3958 gcc_checking_assert (loongarch_split_move_p (dest
, src
));
3959 if (LSX_SUPPORTED_MODE_P (GET_MODE (dest
)))
3960 loongarch_split_128bit_move (dest
, src
);
3961 else if (FP_REG_RTX_P (dest
) || FP_REG_RTX_P (src
))
3963 if (!TARGET_64BIT
&& GET_MODE (dest
) == DImode
)
3964 emit_insn (gen_move_doubleword_fprdi (dest
, src
));
3965 else if (!TARGET_64BIT
&& GET_MODE (dest
) == DFmode
)
3966 emit_insn (gen_move_doubleword_fprdf (dest
, src
));
3967 else if (TARGET_64BIT
&& GET_MODE (dest
) == TFmode
)
3968 emit_insn (gen_move_doubleword_fprtf (dest
, src
));
3974 /* The operation can be split into two normal moves. Decide in
3975 which order to do them. */
3976 low_dest
= loongarch_subword (dest
, false);
3977 if (REG_P (low_dest
) && reg_overlap_mentioned_p (low_dest
, src
))
3979 loongarch_emit_move (loongarch_subword (dest
, true),
3980 loongarch_subword (src
, true));
3981 loongarch_emit_move (low_dest
, loongarch_subword (src
, false));
3985 loongarch_emit_move (low_dest
, loongarch_subword (src
, false));
3986 loongarch_emit_move (loongarch_subword (dest
, true),
3987 loongarch_subword (src
, true));
3991 /* This is a hack. See if the next insn uses DEST and if so, see if we
3992 can forward SRC for DEST. This is most useful if the next insn is a
3994 rtx_insn
*insn
= (rtx_insn
*) insn_
;
3995 struct loongarch_address_info addr
= {};
3998 rtx_insn
*next
= next_nonnote_nondebug_insn_bb (insn
);
4001 rtx set
= single_set (next
);
4002 if (set
&& SET_SRC (set
) == dest
)
4006 rtx tmp
= XEXP (src
, 0);
4007 loongarch_classify_address (&addr
, tmp
, GET_MODE (tmp
),
4009 if (addr
.reg
&& !reg_overlap_mentioned_p (dest
, addr
.reg
))
4010 validate_change (next
, &SET_SRC (set
), src
, false);
4013 validate_change (next
, &SET_SRC (set
), src
, false);
4019 /* Check if adding an integer constant value for a specific mode can be
4020 performed with an addu16i.d instruction and an addi.{w/d}
4024 loongarch_addu16i_imm12_operand_p (HOST_WIDE_INT value
, machine_mode mode
)
4026 /* Not necessary, but avoid unnecessary calculation if !TARGET_64BIT. */
4030 if ((value
& 0xffff) == 0)
4033 if (IMM12_OPERAND (value
))
4036 value
= (value
& ~HWIT_UC_0xFFF
) + ((value
& 0x800) << 1);
4037 return ADDU16I_OPERAND (trunc_int_for_mode (value
, mode
));
4040 /* Split one integer constant op[0] into two (op[1] and op[2]) for constant
4041 plus operation in a specific mode. The splitted constants can be added
4042 onto a register with a single instruction (addi.{d/w} or addu16i.d). */
4045 loongarch_split_plus_constant (rtx
*op
, machine_mode mode
)
4047 HOST_WIDE_INT v
= INTVAL (op
[0]), a
;
4049 if (DUAL_IMM12_OPERAND (v
))
4050 a
= (v
> 0 ? 2047 : -2048);
4051 else if (loongarch_addu16i_imm12_operand_p (v
, mode
))
4052 a
= (v
& ~HWIT_UC_0xFFF
) + ((v
& 0x800) << 1);
4053 else if (mode
== DImode
&& DUAL_ADDU16I_OPERAND (v
))
4054 a
= (v
> 0 ? 0x7fff : -0x8000) << 16;
4058 op
[1] = gen_int_mode (a
, mode
);
4059 v
= v
- (unsigned HOST_WIDE_INT
) a
;
4060 op
[2] = gen_int_mode (v
, mode
);
4063 /* Return true if a move from SRC to DEST in INSN should be split. */
4066 loongarch_split_move_insn_p (rtx dest
, rtx src
)
4068 return loongarch_split_move_p (dest
, src
);
4071 /* Split a move from SRC to DEST in INSN, given that
4072 loongarch_split_move_insn_p holds. */
4075 loongarch_split_move_insn (rtx dest
, rtx src
, rtx insn
)
4077 loongarch_split_move (dest
, src
, insn
);
4080 /* Implement TARGET_CONSTANT_ALIGNMENT. */
4082 static HOST_WIDE_INT
4083 loongarch_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
4085 if (TREE_CODE (exp
) == STRING_CST
|| TREE_CODE (exp
) == CONSTRUCTOR
)
4086 return MAX (align
, BITS_PER_WORD
);
4091 loongarch_output_move_index (rtx x
, machine_mode mode
, bool ldr
)
4093 int index
= exact_log2 (GET_MODE_SIZE (mode
));
4094 if (!IN_RANGE (index
, 0, 3))
4097 struct loongarch_address_info info
;
4098 if ((loongarch_classify_address (&info
, x
, mode
, false)
4099 && !(info
.type
== ADDRESS_REG_REG
))
4100 || !loongarch_legitimate_address_p (mode
, x
, false))
4103 const char *const insn
[][4] =
4119 return insn
[ldr
][index
];
4123 loongarch_output_move_index_float (rtx x
, machine_mode mode
, bool ldr
)
4125 int index
= exact_log2 (GET_MODE_SIZE (mode
));
4126 if (!IN_RANGE (index
, 2, 4))
4129 struct loongarch_address_info info
;
4130 if ((loongarch_classify_address (&info
, x
, mode
, false)
4131 && !(info
.type
== ADDRESS_REG_REG
))
4132 || !loongarch_legitimate_address_p (mode
, x
, false))
4135 const char *const insn
[][3] =
4149 return insn
[ldr
][index
-2];
4151 /* Return true if a 128-bit move from SRC to DEST should be split. */
4154 loongarch_split_128bit_move_p (rtx dest
, rtx src
)
4156 /* LSX-to-LSX moves can be done in a single instruction. */
4157 if (FP_REG_RTX_P (src
) && FP_REG_RTX_P (dest
))
4160 /* Check for LSX loads and stores. */
4161 if (FP_REG_RTX_P (dest
) && MEM_P (src
))
4163 if (FP_REG_RTX_P (src
) && MEM_P (dest
))
4166 /* Check for LSX set to an immediate const vector with valid replicated
4168 if (FP_REG_RTX_P (dest
)
4169 && loongarch_const_vector_same_int_p (src
, GET_MODE (src
), -512, 511))
4172 /* Check for LSX load zero immediate. */
4173 if (FP_REG_RTX_P (dest
) && src
== CONST0_RTX (GET_MODE (src
)))
4179 /* Split a 128-bit move from SRC to DEST. */
4182 loongarch_split_128bit_move (rtx dest
, rtx src
)
4185 rtx low_dest
, low_src
, d
, s
;
4187 if (FP_REG_RTX_P (dest
))
4189 gcc_assert (!MEM_P (src
));
4191 rtx new_dest
= dest
;
4194 if (GET_MODE (dest
) != V4SImode
)
4195 new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4199 if (GET_MODE (dest
) != V2DImode
)
4200 new_dest
= simplify_gen_subreg (V2DImode
, dest
, GET_MODE (dest
), 0);
4203 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (TImode
);
4204 byte
+= UNITS_PER_WORD
, index
++)
4206 s
= loongarch_subword_at_byte (src
, byte
);
4208 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, s
, new_dest
,
4209 GEN_INT (1 << index
)));
4211 emit_insn (gen_lsx_vinsgr2vr_d (new_dest
, s
, new_dest
,
4212 GEN_INT (1 << index
)));
4215 else if (FP_REG_RTX_P (src
))
4217 gcc_assert (!MEM_P (dest
));
4222 if (GET_MODE (src
) != V4SImode
)
4223 new_src
= simplify_gen_subreg (V4SImode
, src
, GET_MODE (src
), 0);
4227 if (GET_MODE (src
) != V2DImode
)
4228 new_src
= simplify_gen_subreg (V2DImode
, src
, GET_MODE (src
), 0);
4231 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (TImode
);
4232 byte
+= UNITS_PER_WORD
, index
++)
4234 d
= loongarch_subword_at_byte (dest
, byte
);
4236 emit_insn (gen_lsx_vpickve2gr_w (d
, new_src
, GEN_INT (index
)));
4238 emit_insn (gen_lsx_vpickve2gr_d (d
, new_src
, GEN_INT (index
)));
4243 low_dest
= loongarch_subword_at_byte (dest
, 0);
4244 low_src
= loongarch_subword_at_byte (src
, 0);
4245 gcc_assert (REG_P (low_dest
) && REG_P (low_src
));
4246 /* Make sure the source register is not written before reading. */
4247 if (REGNO (low_dest
) <= REGNO (low_src
))
4249 for (byte
= 0; byte
< GET_MODE_SIZE (TImode
);
4250 byte
+= UNITS_PER_WORD
)
4252 d
= loongarch_subword_at_byte (dest
, byte
);
4253 s
= loongarch_subword_at_byte (src
, byte
);
4254 loongarch_emit_move (d
, s
);
4259 for (byte
= GET_MODE_SIZE (TImode
) - UNITS_PER_WORD
; byte
>= 0;
4260 byte
-= UNITS_PER_WORD
)
4262 d
= loongarch_subword_at_byte (dest
, byte
);
4263 s
= loongarch_subword_at_byte (src
, byte
);
4264 loongarch_emit_move (d
, s
);
4271 /* Split a COPY_S.D with operands DEST, SRC and INDEX. GEN is a function
4272 used to generate subregs. */
4275 loongarch_split_lsx_copy_d (rtx dest
, rtx src
, rtx index
,
4276 rtx (*gen_fn
)(rtx
, rtx
, rtx
))
4278 gcc_assert ((GET_MODE (src
) == V2DImode
&& GET_MODE (dest
) == DImode
)
4279 || (GET_MODE (src
) == V2DFmode
&& GET_MODE (dest
) == DFmode
));
4281 /* Note that low is always from the lower index, and high is always
4282 from the higher index. */
4283 rtx low
= loongarch_subword (dest
, false);
4284 rtx high
= loongarch_subword (dest
, true);
4285 rtx new_src
= simplify_gen_subreg (V4SImode
, src
, GET_MODE (src
), 0);
4287 emit_insn (gen_fn (low
, new_src
, GEN_INT (INTVAL (index
) * 2)));
4288 emit_insn (gen_fn (high
, new_src
, GEN_INT (INTVAL (index
) * 2 + 1)));
4291 /* Split a INSERT.D with operand DEST, SRC1.INDEX and SRC2. */
4294 loongarch_split_lsx_insert_d (rtx dest
, rtx src1
, rtx index
, rtx src2
)
4297 gcc_assert (GET_MODE (dest
) == GET_MODE (src1
));
4298 gcc_assert ((GET_MODE (dest
) == V2DImode
4299 && (GET_MODE (src2
) == DImode
|| src2
== const0_rtx
))
4300 || (GET_MODE (dest
) == V2DFmode
&& GET_MODE (src2
) == DFmode
));
4302 /* Note that low is always from the lower index, and high is always
4303 from the higher index. */
4304 rtx low
= loongarch_subword (src2
, false);
4305 rtx high
= loongarch_subword (src2
, true);
4306 rtx new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4307 rtx new_src1
= simplify_gen_subreg (V4SImode
, src1
, GET_MODE (src1
), 0);
4308 i
= exact_log2 (INTVAL (index
));
4309 gcc_assert (i
!= -1);
4311 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, low
, new_src1
,
4312 GEN_INT (1 << (i
* 2))));
4313 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
,
4314 GEN_INT (1 << (i
* 2 + 1))));
4320 loongarch_split_lsx_fill_d (rtx dest
, rtx src
)
4322 gcc_assert ((GET_MODE (dest
) == V2DImode
4323 && (GET_MODE (src
) == DImode
|| src
== const0_rtx
))
4324 || (GET_MODE (dest
) == V2DFmode
&& GET_MODE (src
) == DFmode
));
4326 /* Note that low is always from the lower index, and high is always
4327 from the higher index. */
4329 if (src
== const0_rtx
)
4336 low
= loongarch_subword (src
, false);
4337 high
= loongarch_subword (src
, true);
4339 rtx new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4340 emit_insn (gen_lsx_vreplgr2vr_w (new_dest
, low
));
4341 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
, GEN_INT (1 << 1)));
4342 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
, GEN_INT (1 << 3)));
4346 /* Return the appropriate instructions to move SRC into DEST. Assume
4347 that SRC is operand 1 and DEST is operand 0. */
4350 loongarch_output_move (rtx dest
, rtx src
)
4352 enum rtx_code dest_code
= GET_CODE (dest
);
4353 enum rtx_code src_code
= GET_CODE (src
);
4354 machine_mode mode
= GET_MODE (dest
);
4355 bool dbl_p
= (GET_MODE_SIZE (mode
) == 8);
4356 bool lsx_p
= LSX_SUPPORTED_MODE_P (mode
);
4358 if (loongarch_split_move_p (dest
, src
))
4362 && dest_code
== REG
&& FP_REG_P (REGNO (dest
))
4363 && src_code
== CONST_VECTOR
4364 && CONST_INT_P (CONST_VECTOR_ELT (src
, 0)))
4366 gcc_assert (loongarch_const_vector_same_int_p (src
, mode
, -512, 511));
4367 switch (GET_MODE_SIZE (mode
))
4370 return "vrepli.%v0\t%w0,%E1";
4371 default: gcc_unreachable ();
4375 if ((src_code
== REG
&& GP_REG_P (REGNO (src
)))
4376 || (src
== CONST0_RTX (mode
)))
4378 if (dest_code
== REG
)
4380 if (GP_REG_P (REGNO (dest
)))
4381 return "or\t%0,%z1,$r0";
4383 if (FP_REG_P (REGNO (dest
)))
4387 gcc_assert (src
== CONST0_RTX (GET_MODE (src
)));
4388 switch (GET_MODE_SIZE (mode
))
4391 return "vrepli.b\t%w0,0";
4397 return dbl_p
? "movgr2fr.d\t%0,%z1" : "movgr2fr.w\t%0,%z1";
4400 if (dest_code
== MEM
)
4402 const char *insn
= NULL
;
4403 insn
= loongarch_output_move_index (XEXP (dest
, 0), GET_MODE (dest
),
4408 rtx offset
= XEXP (dest
, 0);
4409 if (GET_CODE (offset
) == PLUS
)
4410 offset
= XEXP (offset
, 1);
4411 switch (GET_MODE_SIZE (mode
))
4414 return "st.b\t%z1,%0";
4416 return "st.h\t%z1,%0";
4418 /* Matching address type with a 12bit offset and
4420 if (const_arith_operand (offset
, Pmode
)
4421 || GET_CODE (offset
) == LO_SUM
)
4422 return "st.w\t%z1,%0";
4424 return "stptr.w\t%z1,%0";
4426 if (const_arith_operand (offset
, Pmode
)
4427 || GET_CODE (offset
) == LO_SUM
)
4428 return "st.d\t%z1,%0";
4430 return "stptr.d\t%z1,%0";
4436 if (dest_code
== REG
&& GP_REG_P (REGNO (dest
)))
4438 if (src_code
== REG
)
4439 if (FP_REG_P (REGNO (src
)))
4441 gcc_assert (!lsx_p
);
4442 return dbl_p
? "movfr2gr.d\t%0,%1" : "movfr2gr.s\t%0,%1";
4445 if (src_code
== MEM
)
4447 const char *insn
= NULL
;
4448 insn
= loongarch_output_move_index (XEXP (src
, 0), GET_MODE (src
),
4453 rtx offset
= XEXP (src
, 0);
4454 if (GET_CODE (offset
) == PLUS
)
4455 offset
= XEXP (offset
, 1);
4456 switch (GET_MODE_SIZE (mode
))
4459 return "ld.bu\t%0,%1";
4461 return "ld.hu\t%0,%1";
4463 /* Matching address type with a 12bit offset and
4465 if (const_arith_operand (offset
, Pmode
)
4466 || GET_CODE (offset
) == LO_SUM
)
4467 return "ld.w\t%0,%1";
4469 return "ldptr.w\t%0,%1";
4471 if (const_arith_operand (offset
, Pmode
)
4472 || GET_CODE (offset
) == LO_SUM
)
4473 return "ld.d\t%0,%1";
4475 return "ldptr.d\t%0,%1";
4481 if (src_code
== HIGH
)
4484 split_const (XEXP (src
, 0), &x
, &offset
);
4485 enum loongarch_symbol_type type
= SYMBOL_PCREL
;
4487 if (UNSPEC_ADDRESS_P (x
))
4488 type
= UNSPEC_ADDRESS_TYPE (x
);
4490 if (type
== SYMBOL_TLS_LE
)
4491 return "lu12i.w\t%0,%h1";
4493 return "pcalau12i\t%0,%h1";
4496 if (src_code
== CONST_INT
)
4498 if (LU12I_INT (src
))
4499 return "lu12i.w\t%0,%1>>12\t\t\t# %X1";
4500 else if (IMM12_INT (src
))
4501 return "addi.w\t%0,$r0,%1\t\t\t# %X1";
4502 else if (IMM12_INT_UNSIGNED (src
))
4503 return "ori\t%0,$r0,%1\t\t\t# %X1";
4504 else if (LU52I_INT (src
))
4505 return "lu52i.d\t%0,$r0,%X1>>52\t\t\t# %1";
4511 if (!TARGET_EXPLICIT_RELOCS
4512 && dest_code
== REG
&& symbolic_operand (src
, VOIDmode
))
4514 if (loongarch_classify_symbol (src
) == SYMBOL_PCREL
)
4515 return "la.local\t%0,%1";
4517 return "la.global\t%0,%1";
4520 if (src_code
== REG
&& FP_REG_P (REGNO (src
)))
4522 if (dest_code
== REG
&& FP_REG_P (REGNO (dest
)))
4526 switch (GET_MODE_SIZE (mode
))
4529 return "vori.b\t%w0,%w1,0";
4535 return dbl_p
? "fmov.d\t%0,%1" : "fmov.s\t%0,%1";
4538 if (dest_code
== MEM
)
4540 const char *insn
= NULL
;
4541 insn
= loongarch_output_move_index_float (XEXP (dest
, 0),
4549 switch (GET_MODE_SIZE (mode
))
4552 return "vst\t%w1,%0";
4558 return dbl_p
? "fst.d\t%1,%0" : "fst.s\t%1,%0";
4562 if (dest_code
== REG
&& FP_REG_P (REGNO (dest
)))
4564 if (src_code
== MEM
)
4566 const char *insn
= NULL
;
4567 insn
= loongarch_output_move_index_float (XEXP (src
, 0),
4575 switch (GET_MODE_SIZE (mode
))
4578 return "vld\t%w0,%1";
4583 return dbl_p
? "fld.d\t%0,%1" : "fld.s\t%0,%1";
4590 /* Return true if CMP1 is a suitable second operand for integer ordering
4594 loongarch_int_order_operand_ok_p (enum rtx_code code
, rtx cmp1
)
4600 return reg_or_0_operand (cmp1
, VOIDmode
);
4604 return cmp1
== const1_rtx
;
4608 return arith_operand (cmp1
, VOIDmode
);
4611 return sle_operand (cmp1
, VOIDmode
);
4614 return sleu_operand (cmp1
, VOIDmode
);
4621 /* Return true if *CMP1 (of mode MODE) is a valid second operand for
4622 integer ordering test *CODE, or if an equivalent combination can
4623 be formed by adjusting *CODE and *CMP1. When returning true, update
4624 *CODE and *CMP1 with the chosen code and operand, otherwise leave
4628 loongarch_canonicalize_int_order_test (enum rtx_code
*code
, rtx
*cmp1
,
4631 HOST_WIDE_INT plus_one
;
4633 if (loongarch_int_order_operand_ok_p (*code
, *cmp1
))
4636 if (CONST_INT_P (*cmp1
))
4640 plus_one
= trunc_int_for_mode (UINTVAL (*cmp1
) + 1, mode
);
4641 if (INTVAL (*cmp1
) < plus_one
)
4644 *cmp1
= force_reg (mode
, GEN_INT (plus_one
));
4650 plus_one
= trunc_int_for_mode (UINTVAL (*cmp1
) + 1, mode
);
4654 *cmp1
= force_reg (mode
, GEN_INT (plus_one
));
4665 /* Compare CMP0 and CMP1 using ordering test CODE and store the result
4666 in TARGET. CMP0 and TARGET are register_operands. If INVERT_PTR
4667 is nonnull, it's OK to set TARGET to the inverse of the result and
4668 flip *INVERT_PTR instead. */
4671 loongarch_emit_int_order_test (enum rtx_code code
, bool *invert_ptr
,
4672 rtx target
, rtx cmp0
, rtx cmp1
)
4676 /* First see if there is a LoongArch instruction that can do this operation.
4677 If not, try doing the same for the inverse operation. If that also
4678 fails, force CMP1 into a register and try again. */
4679 mode
= GET_MODE (cmp0
);
4680 if (loongarch_canonicalize_int_order_test (&code
, &cmp1
, mode
))
4681 loongarch_emit_binary (code
, target
, cmp0
, cmp1
);
4684 enum rtx_code inv_code
= reverse_condition (code
);
4685 if (!loongarch_canonicalize_int_order_test (&inv_code
, &cmp1
, mode
))
4687 cmp1
= force_reg (mode
, cmp1
);
4688 loongarch_emit_int_order_test (code
, invert_ptr
, target
, cmp0
, cmp1
);
4690 else if (invert_ptr
== 0)
4694 inv_target
= loongarch_force_binary (GET_MODE (target
),
4695 inv_code
, cmp0
, cmp1
);
4696 loongarch_emit_binary (XOR
, target
, inv_target
, const1_rtx
);
4700 *invert_ptr
= !*invert_ptr
;
4701 loongarch_emit_binary (inv_code
, target
, cmp0
, cmp1
);
4706 /* Return a register that is zero if CMP0 and CMP1 are equal.
4707 The register will have the same mode as CMP0. */
4710 loongarch_zero_if_equal (rtx cmp0
, rtx cmp1
)
4712 if (cmp1
== const0_rtx
)
4715 if (uns_arith_operand (cmp1
, VOIDmode
))
4716 return expand_binop (GET_MODE (cmp0
), xor_optab
, cmp0
, cmp1
, 0, 0,
4719 return expand_binop (GET_MODE (cmp0
), sub_optab
, cmp0
, cmp1
, 0, 0,
4723 /* Allocate a floating-point condition-code register of mode MODE. */
4726 loongarch_allocate_fcc (machine_mode mode
)
4728 unsigned int regno
, count
;
4730 gcc_assert (TARGET_HARD_FLOAT
);
4732 if (mode
== FCCmode
)
4737 cfun
->machine
->next_fcc
+= -cfun
->machine
->next_fcc
& (count
- 1);
4738 if (cfun
->machine
->next_fcc
> FCC_REG_LAST
- FCC_REG_FIRST
)
4739 cfun
->machine
->next_fcc
= 0;
4741 regno
= FCC_REG_FIRST
+ cfun
->machine
->next_fcc
;
4742 cfun
->machine
->next_fcc
+= count
;
4743 return gen_rtx_REG (mode
, regno
);
4746 /* Sign- or zero-extend OP0 and OP1 for integer comparisons. */
4749 loongarch_extend_comparands (rtx_code code
, rtx
*op0
, rtx
*op1
)
4751 /* Comparisons consider all GRLEN bits, so extend sub-GRLEN values. */
4752 if (GET_MODE_SIZE (word_mode
) > GET_MODE_SIZE (GET_MODE (*op0
)))
4754 /* It is more profitable to zero-extend QImode values. But not if the
4755 first operand has already been sign-extended, and the second one is
4756 is a constant or has already been sign-extended also. */
4757 if (unsigned_condition (code
) == code
4758 && (GET_MODE (*op0
) == QImode
4759 && ! (GET_CODE (*op0
) == SUBREG
4760 && SUBREG_PROMOTED_VAR_P (*op0
)
4761 && SUBREG_PROMOTED_SIGNED_P (*op0
)
4762 && (CONST_INT_P (*op1
)
4763 || (GET_CODE (*op1
) == SUBREG
4764 && SUBREG_PROMOTED_VAR_P (*op1
)
4765 && SUBREG_PROMOTED_SIGNED_P (*op1
))))))
4767 *op0
= gen_rtx_ZERO_EXTEND (word_mode
, *op0
);
4768 if (CONST_INT_P (*op1
))
4769 *op1
= GEN_INT ((uint8_t) INTVAL (*op1
));
4771 *op1
= gen_rtx_ZERO_EXTEND (word_mode
, *op1
);
4775 *op0
= gen_rtx_SIGN_EXTEND (word_mode
, *op0
);
4776 if (*op1
!= const0_rtx
)
4777 *op1
= gen_rtx_SIGN_EXTEND (word_mode
, *op1
);
4783 /* Convert a comparison into something that can be used in a branch. On
4784 entry, *OP0 and *OP1 are the values being compared and *CODE is the code
4785 used to compare them. Update them to describe the final comparison. */
4788 loongarch_emit_int_compare (enum rtx_code
*code
, rtx
*op0
, rtx
*op1
)
4790 static const enum rtx_code
4791 mag_comparisons
[][2] = {{LEU
, LTU
}, {GTU
, GEU
}, {LE
, LT
}, {GT
, GE
}};
4793 if (splittable_const_int_operand (*op1
, VOIDmode
))
4795 HOST_WIDE_INT rhs
= INTVAL (*op1
);
4797 if (*code
== EQ
|| *code
== NE
)
4799 /* Convert e.g. OP0 == 2048 into OP0 - 2048 == 0. */
4800 if (IMM12_OPERAND (-rhs
))
4802 *op0
= loongarch_force_binary (GET_MODE (*op0
), PLUS
, *op0
,
4809 /* Convert e.g. (OP0 <= 0xFFF) into (OP0 < 0x1000). */
4810 for (size_t i
= 0; i
< ARRAY_SIZE (mag_comparisons
); i
++)
4812 HOST_WIDE_INT new_rhs
;
4813 bool increment
= *code
== mag_comparisons
[i
][0];
4814 bool decrement
= *code
== mag_comparisons
[i
][1];
4815 if (!increment
&& !decrement
)
4818 if ((increment
&& rhs
== HOST_WIDE_INT_MAX
)
4819 || (decrement
&& rhs
== HOST_WIDE_INT_MIN
))
4822 new_rhs
= rhs
+ (increment
? 1 : -1);
4823 if (loongarch_integer_cost (new_rhs
)
4824 < loongarch_integer_cost (rhs
))
4826 *op1
= GEN_INT (new_rhs
);
4827 *code
= mag_comparisons
[i
][increment
];
4834 loongarch_extend_comparands (*code
, op0
, op1
);
4836 *op0
= force_reg (word_mode
, *op0
);
4837 if (*op1
!= const0_rtx
)
4838 *op1
= force_reg (word_mode
, *op1
);
4841 /* Like loongarch_emit_int_compare, but for floating-point comparisons. */
4844 loongarch_emit_float_compare (enum rtx_code
*code
, rtx
*op0
, rtx
*op1
)
4849 /* Floating-point tests use a separate FCMP.cond.fmt
4850 comparison to set a register. The branch or conditional move will
4851 then compare that register against zero.
4853 Set CMP_CODE to the code of the comparison instruction and
4854 *CODE to the code that the branch or move should use. */
4855 enum rtx_code cmp_code
= *code
;
4856 /* Three FP conditions cannot be implemented by reversing the
4857 operands for FCMP.cond.fmt, instead a reversed condition code is
4858 required and a test for false. */
4860 *op0
= loongarch_allocate_fcc (FCCmode
);
4863 loongarch_emit_binary (cmp_code
, *op0
, cmp_op0
, cmp_op1
);
4866 /* Try performing the comparison in OPERANDS[1], whose arms are OPERANDS[2]
4867 and OPERAND[3]. Store the result in OPERANDS[0].
4869 On 64-bit targets, the mode of the comparison and target will always be
4870 SImode, thus possibly narrower than that of the comparison's operands. */
4873 loongarch_expand_scc (rtx operands
[])
4875 rtx target
= operands
[0];
4876 enum rtx_code code
= GET_CODE (operands
[1]);
4877 rtx op0
= operands
[2];
4878 rtx op1
= operands
[3];
4880 loongarch_extend_comparands (code
, &op0
, &op1
);
4881 op0
= force_reg (word_mode
, op0
);
4883 gcc_assert (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_INT
);
4885 if (code
== EQ
|| code
== NE
)
4887 rtx zie
= loongarch_zero_if_equal (op0
, op1
);
4888 loongarch_emit_binary (code
, target
, zie
, const0_rtx
);
4891 loongarch_emit_int_order_test (code
, 0, target
, op0
, op1
);
4894 /* Compare OPERANDS[1] with OPERANDS[2] using comparison code
4895 CODE and jump to OPERANDS[3] if the condition holds. */
4898 loongarch_expand_conditional_branch (rtx
*operands
)
4900 enum rtx_code code
= GET_CODE (operands
[0]);
4901 rtx op0
= operands
[1];
4902 rtx op1
= operands
[2];
4905 if (FLOAT_MODE_P (GET_MODE (op1
)))
4906 loongarch_emit_float_compare (&code
, &op0
, &op1
);
4908 loongarch_emit_int_compare (&code
, &op0
, &op1
);
4910 condition
= gen_rtx_fmt_ee (code
, VOIDmode
, op0
, op1
);
4911 emit_jump_insn (gen_condjump (condition
, operands
[3]));
4914 /* Perform the comparison in OPERANDS[1]. Move OPERANDS[2] into OPERANDS[0]
4915 if the condition holds, otherwise move OPERANDS[3] into OPERANDS[0]. */
4918 loongarch_expand_conditional_move (rtx
*operands
)
4920 enum rtx_code code
= GET_CODE (operands
[1]);
4921 rtx op0
= XEXP (operands
[1], 0);
4922 rtx op1
= XEXP (operands
[1], 1);
4923 rtx op0_extend
= op0
;
4924 rtx op1_extend
= op1
;
4926 /* Record whether operands[2] and operands[3] modes are promoted to word_mode. */
4927 bool promote_p
= false;
4928 machine_mode mode
= GET_MODE (operands
[0]);
4930 if (FLOAT_MODE_P (GET_MODE (op1
)))
4931 loongarch_emit_float_compare (&code
, &op0
, &op1
);
4934 if ((REGNO (op0
) == REGNO (operands
[2])
4935 || (REGNO (op1
) == REGNO (operands
[3]) && (op1
!= const0_rtx
)))
4936 && (GET_MODE_SIZE (GET_MODE (op0
)) < word_mode
))
4942 loongarch_extend_comparands (code
, &op0
, &op1
);
4944 op0
= force_reg (word_mode
, op0
);
4946 op1_extend
= force_reg (word_mode
, op1
);
4948 if (code
== EQ
|| code
== NE
)
4950 op0
= loongarch_zero_if_equal (op0
, op1
);
4955 /* The comparison needs a separate scc instruction. Store the
4956 result of the scc in *OP0 and compare it against zero. */
4957 bool invert
= false;
4958 rtx target
= gen_reg_rtx (GET_MODE (op0
));
4959 loongarch_emit_int_order_test (code
, &invert
, target
, op0
, op1
);
4960 code
= invert
? EQ
: NE
;
4966 rtx cond
= gen_rtx_fmt_ee (code
, GET_MODE (op0
), op0
, op1
);
4967 /* There is no direct support for general conditional GP move involving
4968 two registers using SEL. */
4969 if (INTEGRAL_MODE_P (GET_MODE (operands
[2]))
4970 && register_operand (operands
[2], VOIDmode
)
4971 && register_operand (operands
[3], VOIDmode
))
4973 rtx op2
= operands
[2];
4974 rtx op3
= operands
[3];
4978 if (REGNO (XEXP (operands
[1], 0)) == REGNO (operands
[2]))
4982 loongarch_extend_comparands (code
, &op2
, &const0_rtx
);
4983 op2
= force_reg (mode
, op2
);
4986 if (REGNO (XEXP (operands
[1], 1)) == REGNO (operands
[3]))
4990 loongarch_extend_comparands (code
, &op3
, &const0_rtx
);
4991 op3
= force_reg (mode
, op3
);
4995 rtx temp
= gen_reg_rtx (mode
);
4996 rtx temp2
= gen_reg_rtx (mode
);
4998 emit_insn (gen_rtx_SET (temp
,
4999 gen_rtx_IF_THEN_ELSE (mode
, cond
,
5002 /* Flip the test for the second operand. */
5003 cond
= gen_rtx_fmt_ee ((code
== EQ
) ? NE
: EQ
, GET_MODE (op0
), op0
, op1
);
5005 emit_insn (gen_rtx_SET (temp2
,
5006 gen_rtx_IF_THEN_ELSE (mode
, cond
,
5009 /* Merge the two results, at least one is guaranteed to be zero. */
5012 rtx temp3
= gen_reg_rtx (mode
);
5013 emit_insn (gen_rtx_SET (temp3
, gen_rtx_IOR (mode
, temp
, temp2
)));
5014 temp3
= gen_lowpart (GET_MODE (operands
[0]), temp3
);
5015 loongarch_emit_move (operands
[0], temp3
);
5018 emit_insn (gen_rtx_SET (operands
[0], gen_rtx_IOR (mode
, temp
, temp2
)));
5021 emit_insn (gen_rtx_SET (operands
[0],
5022 gen_rtx_IF_THEN_ELSE (GET_MODE (operands
[0]), cond
,
5023 operands
[2], operands
[3])));
5026 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
5029 loongarch_va_start (tree valist
, rtx nextarg
)
5031 nextarg
= plus_constant (Pmode
, nextarg
, -cfun
->machine
->varargs_size
);
5032 std_expand_builtin_va_start (valist
, nextarg
);
5035 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
5038 loongarch_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
5039 tree exp ATTRIBUTE_UNUSED
)
5045 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
5046 Assume that the areas do not overlap. */
5049 loongarch_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
,
5050 HOST_WIDE_INT delta
)
5052 HOST_WIDE_INT offs
, delta_cur
;
5057 /* Calculate how many registers we'll need for the block move.
5058 We'll emit length / delta move operations with delta as the size
5059 first. Then we may still have length % delta bytes not copied.
5060 We handle these remaining bytes by move operations with smaller
5061 (halfed) sizes. For example, if length = 21 and delta = 8, we'll
5062 emit two ld.d/st.d pairs, one ld.w/st.w pair, and one ld.b/st.b
5063 pair. For each load/store pair we use a dedicated register to keep
5064 the pipeline as populated as possible. */
5065 HOST_WIDE_INT num_reg
= length
/ delta
;
5066 for (delta_cur
= delta
/ 2; delta_cur
!= 0; delta_cur
/= 2)
5067 num_reg
+= !!(length
& delta_cur
);
5069 /* Allocate a buffer for the temporary registers. */
5070 regs
= XALLOCAVEC (rtx
, num_reg
);
5072 for (delta_cur
= delta
, i
= 0, offs
= 0; offs
< length
; delta_cur
/= 2)
5074 mode
= int_mode_for_size (delta_cur
* BITS_PER_UNIT
, 0).require ();
5076 for (; offs
+ delta_cur
<= length
; offs
+= delta_cur
, i
++)
5078 regs
[i
] = gen_reg_rtx (mode
);
5079 loongarch_emit_move (regs
[i
], adjust_address (src
, mode
, offs
));
5083 for (delta_cur
= delta
, i
= 0, offs
= 0; offs
< length
; delta_cur
/= 2)
5085 mode
= int_mode_for_size (delta_cur
* BITS_PER_UNIT
, 0).require ();
5087 for (; offs
+ delta_cur
<= length
; offs
+= delta_cur
, i
++)
5088 loongarch_emit_move (adjust_address (dest
, mode
, offs
), regs
[i
]);
5092 /* Helper function for doing a loop-based block operation on memory
5093 reference MEM. Each iteration of the loop will operate on LENGTH
5096 Create a new base register for use within the loop and point it to
5097 the start of MEM. Create a new memory reference that uses this
5098 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
5101 loongarch_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
, rtx
*loop_reg
,
5104 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
5106 /* Although the new mem does not refer to a known location,
5107 it does keep up to LENGTH bytes of alignment. */
5108 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
5109 set_mem_align (*loop_mem
, MIN (MEM_ALIGN (mem
), length
* BITS_PER_UNIT
));
5112 /* Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER
5113 bytes at a time. LENGTH must be at least BYTES_PER_ITER. Assume that
5114 the memory regions do not overlap. */
5117 loongarch_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
,
5118 HOST_WIDE_INT align
)
5120 rtx_code_label
*label
;
5121 rtx src_reg
, dest_reg
, final_src
, test
;
5122 HOST_WIDE_INT bytes_per_iter
= align
* LARCH_MAX_MOVE_OPS_PER_LOOP_ITER
;
5123 HOST_WIDE_INT leftover
;
5125 leftover
= length
% bytes_per_iter
;
5128 /* Create registers and memory references for use within the loop. */
5129 loongarch_adjust_block_mem (src
, bytes_per_iter
, &src_reg
, &src
);
5130 loongarch_adjust_block_mem (dest
, bytes_per_iter
, &dest_reg
, &dest
);
5132 /* Calculate the value that SRC_REG should have after the last iteration
5134 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
), 0,
5137 /* Emit the start of the loop. */
5138 label
= gen_label_rtx ();
5141 /* Emit the loop body. */
5142 loongarch_block_move_straight (dest
, src
, bytes_per_iter
, align
);
5144 /* Move on to the next block. */
5145 loongarch_emit_move (src_reg
,
5146 plus_constant (Pmode
, src_reg
, bytes_per_iter
));
5147 loongarch_emit_move (dest_reg
,
5148 plus_constant (Pmode
, dest_reg
, bytes_per_iter
));
5150 /* Emit the loop condition. */
5151 test
= gen_rtx_NE (VOIDmode
, src_reg
, final_src
);
5152 if (Pmode
== DImode
)
5153 emit_jump_insn (gen_cbranchdi4 (test
, src_reg
, final_src
, label
));
5155 emit_jump_insn (gen_cbranchsi4 (test
, src_reg
, final_src
, label
));
5157 /* Mop up any left-over bytes. */
5159 loongarch_block_move_straight (dest
, src
, leftover
, align
);
5161 /* Temporary fix for PR79150. */
5162 emit_insn (gen_nop ());
5165 /* Expand a cpymemsi instruction, which copies LENGTH bytes from
5166 memory reference SRC to memory reference DEST. */
5169 loongarch_expand_block_move (rtx dest
, rtx src
, rtx r_length
, rtx r_align
)
5171 if (!CONST_INT_P (r_length
))
5174 HOST_WIDE_INT length
= INTVAL (r_length
);
5175 if (length
> loongarch_max_inline_memcpy_size
)
5178 HOST_WIDE_INT align
= INTVAL (r_align
);
5180 if (!TARGET_STRICT_ALIGN
|| align
> UNITS_PER_WORD
)
5181 align
= UNITS_PER_WORD
;
5183 if (length
<= align
* LARCH_MAX_MOVE_OPS_STRAIGHT
)
5185 loongarch_block_move_straight (dest
, src
, length
, align
);
5191 loongarch_block_move_loop (dest
, src
, length
, align
);
5198 /* Return true if loongarch_expand_block_move is the preferred
5199 implementation of the 'cpymemsi' template. */
5202 loongarch_do_optimize_block_move_p (void)
5204 /* if -m[no-]memcpy is given explicitly. */
5205 if (target_flags_explicit
& MASK_MEMCPY
)
5206 return !TARGET_MEMCPY
;
5208 /* if not, don't optimize under -Os. */
5209 return !optimize_size
;
5212 /* Expand a QI or HI mode atomic memory operation.
5214 GENERATOR contains a pointer to the gen_* function that generates
5215 the SI mode underlying atomic operation using masks that we
5218 RESULT is the return register for the operation. Its value is NULL
5221 MEM is the location of the atomic access.
5223 OLDVAL is the first operand for the operation.
5225 NEWVAL is the optional second operand for the operation. Its value
5226 is NULL if unused. */
5229 loongarch_expand_atomic_qihi (union loongarch_gen_fn_ptrs generator
,
5230 rtx result
, rtx mem
, rtx oldval
, rtx newval
,
5233 rtx orig_addr
, memsi_addr
, memsi
, shift
, shiftsi
, unshifted_mask
;
5234 rtx unshifted_mask_reg
, mask
, inverted_mask
, si_op
;
5238 mode
= GET_MODE (mem
);
5240 /* Compute the address of the containing SImode value. */
5241 orig_addr
= force_reg (Pmode
, XEXP (mem
, 0));
5242 memsi_addr
= loongarch_force_binary (Pmode
, AND
, orig_addr
,
5243 force_reg (Pmode
, GEN_INT (-4)));
5245 /* Create a memory reference for it. */
5246 memsi
= gen_rtx_MEM (SImode
, memsi_addr
);
5247 set_mem_alias_set (memsi
, ALIAS_SET_MEMORY_BARRIER
);
5248 MEM_VOLATILE_P (memsi
) = MEM_VOLATILE_P (mem
);
5250 /* Work out the byte offset of the QImode or HImode value,
5251 counting from the least significant byte. */
5252 shift
= loongarch_force_binary (Pmode
, AND
, orig_addr
, GEN_INT (3));
5253 /* Multiply by eight to convert the shift value from bytes to bits. */
5254 loongarch_emit_binary (ASHIFT
, shift
, shift
, GEN_INT (3));
5256 /* Make the final shift an SImode value, so that it can be used in
5257 SImode operations. */
5258 shiftsi
= force_reg (SImode
, gen_lowpart (SImode
, shift
));
5260 /* Set MASK to an inclusive mask of the QImode or HImode value. */
5261 unshifted_mask
= GEN_INT (GET_MODE_MASK (mode
));
5262 unshifted_mask_reg
= force_reg (SImode
, unshifted_mask
);
5263 mask
= loongarch_force_binary (SImode
, ASHIFT
, unshifted_mask_reg
, shiftsi
);
5265 /* Compute the equivalent exclusive mask. */
5266 inverted_mask
= gen_reg_rtx (SImode
);
5267 emit_insn (gen_rtx_SET (inverted_mask
, gen_rtx_NOT (SImode
, mask
)));
5269 /* Shift the old value into place. */
5270 if (oldval
!= const0_rtx
)
5272 oldval
= convert_modes (SImode
, mode
, oldval
, true);
5273 oldval
= force_reg (SImode
, oldval
);
5274 oldval
= loongarch_force_binary (SImode
, ASHIFT
, oldval
, shiftsi
);
5277 /* Do the same for the new value. */
5278 if (newval
&& newval
!= const0_rtx
)
5280 newval
= convert_modes (SImode
, mode
, newval
, true);
5281 newval
= force_reg (SImode
, newval
);
5282 newval
= loongarch_force_binary (SImode
, ASHIFT
, newval
, shiftsi
);
5285 /* Do the SImode atomic access. */
5287 res
= gen_reg_rtx (SImode
);
5290 si_op
= generator
.fn_7 (res
, memsi
, mask
, inverted_mask
, oldval
, newval
,
5293 si_op
= generator
.fn_6 (res
, memsi
, mask
, inverted_mask
, oldval
, model
);
5295 si_op
= generator
.fn_5 (memsi
, mask
, inverted_mask
, oldval
, model
);
5301 /* Shift and convert the result. */
5302 loongarch_emit_binary (AND
, res
, res
, mask
);
5303 loongarch_emit_binary (LSHIFTRT
, res
, res
, shiftsi
);
5304 loongarch_emit_move (result
, gen_lowpart (GET_MODE (result
), res
));
5308 /* Return true if (zero_extract OP WIDTH BITPOS) can be used as the
5309 source of an "ext" instruction or the destination of an "ins"
5310 instruction. OP must be a register operand and the following
5311 conditions must hold:
5313 0 <= BITPOS < GET_MODE_BITSIZE (GET_MODE (op))
5314 0 < WIDTH <= GET_MODE_BITSIZE (GET_MODE (op))
5315 0 < BITPOS + WIDTH <= GET_MODE_BITSIZE (GET_MODE (op))
5317 Also reject lengths equal to a word as they are better handled
5318 by the move patterns. */
5321 loongarch_use_ins_ext_p (rtx op
, HOST_WIDE_INT width
, HOST_WIDE_INT bitpos
)
5323 if (!register_operand (op
, VOIDmode
)
5324 || GET_MODE_BITSIZE (GET_MODE (op
)) > BITS_PER_WORD
)
5327 if (!IN_RANGE (width
, 1, GET_MODE_BITSIZE (GET_MODE (op
)) - 1))
5330 if (bitpos
< 0 || bitpos
+ width
> GET_MODE_BITSIZE (GET_MODE (op
)))
5336 /* Print the text for PRINT_OPERAND punctation character CH to FILE.
5337 The punctuation characters are:
5339 '.' Print the name of the register with a hard-wired zero (zero or $r0).
5340 '$' Print the name of the stack pointer register (sp or $r3).
5342 See also loongarch_init_print_operand_punct. */
5345 loongarch_print_operand_punctuation (FILE *file
, int ch
)
5350 fputs (reg_names
[GP_REG_FIRST
+ 0], file
);
5354 fputs (reg_names
[STACK_POINTER_REGNUM
], file
);
5363 /* Initialize loongarch_print_operand_punct. */
5366 loongarch_init_print_operand_punct (void)
5370 for (p
= ".$"; *p
; p
++)
5371 loongarch_print_operand_punct
[(unsigned char) *p
] = true;
5374 /* PRINT_OPERAND prefix LETTER refers to the integer branch instruction
5375 associated with condition CODE. Print the condition part of the
5379 loongarch_print_int_branch_condition (FILE *file
, enum rtx_code code
,
5394 /* Conveniently, the LoongArch names for these conditions are the same
5395 as their RTL equivalents. */
5396 fputs (GET_RTX_NAME (code
), file
);
5400 output_operand_lossage ("'%%%c' is not a valid operand prefix", letter
);
5405 /* Likewise floating-point branches. */
5408 loongarch_print_float_branch_condition (FILE *file
, enum rtx_code code
,
5414 fputs ("ceqz", file
);
5418 fputs ("cnez", file
);
5422 output_operand_lossage ("'%%%c' is not a valid operand prefix", letter
);
5427 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
5430 loongarch_print_operand_punct_valid_p (unsigned char code
)
5432 return loongarch_print_operand_punct
[code
];
5435 /* Return true if a FENCE should be emitted to before a memory access to
5436 implement the release portion of memory model MODEL. */
5439 loongarch_memmodel_needs_rel_acq_fence (enum memmodel model
)
5443 case MEMMODEL_ACQ_REL
:
5444 case MEMMODEL_SEQ_CST
:
5445 case MEMMODEL_SYNC_SEQ_CST
:
5446 case MEMMODEL_RELEASE
:
5447 case MEMMODEL_SYNC_RELEASE
:
5448 case MEMMODEL_ACQUIRE
:
5449 case MEMMODEL_CONSUME
:
5450 case MEMMODEL_SYNC_ACQUIRE
:
5453 case MEMMODEL_RELAXED
:
5461 /* Return true if a FENCE should be emitted to before a memory access to
5462 implement the release portion of memory model MODEL. */
5465 loongarch_memmodel_needs_release_fence (enum memmodel model
)
5469 case MEMMODEL_ACQ_REL
:
5470 case MEMMODEL_SEQ_CST
:
5471 case MEMMODEL_SYNC_SEQ_CST
:
5472 case MEMMODEL_RELEASE
:
5473 case MEMMODEL_SYNC_RELEASE
:
5476 case MEMMODEL_ACQUIRE
:
5477 case MEMMODEL_CONSUME
:
5478 case MEMMODEL_SYNC_ACQUIRE
:
5479 case MEMMODEL_RELAXED
:
5487 /* Print symbolic operand OP, which is part of a HIGH or LO_SUM
5488 in context CONTEXT. HI_RELOC indicates a high-part reloc. */
5491 loongarch_print_operand_reloc (FILE *file
, rtx op
, bool hi64_part
,
5495 enum loongarch_symbol_type symbol_type
=
5496 loongarch_classify_symbolic_expression (op
);
5498 if (loongarch_symbol_extreme_p (symbol_type
))
5499 gcc_assert (TARGET_EXPLICIT_RELOCS
);
5501 switch (symbol_type
)
5503 case SYMBOL_PCREL64
:
5506 reloc
= hi_reloc
? "%pc64_hi12" : "%pc64_lo20";
5511 reloc
= hi_reloc
? "%pc_hi20" : "%pc_lo12";
5514 case SYMBOL_GOT_DISP
:
5517 if (TARGET_CMODEL_EXTREME
)
5518 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
5523 reloc
= hi_reloc
? "%got_pc_hi20" : "%got_pc_lo12";
5529 if (TARGET_CMODEL_EXTREME
)
5530 reloc
= hi_reloc
? "%ie64_pc_hi12" : "%ie64_pc_lo20";
5535 reloc
= hi_reloc
? "%ie_pc_hi20" : "%ie_pc_lo12";
5541 if (TARGET_CMODEL_EXTREME
)
5542 reloc
= hi_reloc
? "%le64_hi12" : "%le64_lo20";
5547 reloc
= hi_reloc
? "%le_hi20" : "%le_lo12";
5553 if (TARGET_CMODEL_EXTREME
)
5554 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
5559 reloc
= hi_reloc
? "%gd_pc_hi20" : "%got_pc_lo12";
5565 if (TARGET_CMODEL_EXTREME
)
5566 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
5571 reloc
= hi_reloc
? "%ld_pc_hi20" : "%got_pc_lo12";
5578 fprintf (file
, "%s(", reloc
);
5579 output_addr_const (file
, loongarch_strip_unspec_address (op
));
5583 /* Implement TARGET_PRINT_OPERAND. The LoongArch-specific operand codes are:
5585 'A' Print a _DB suffix if the memory model requires a release.
5586 'b' Print the address of a memory operand, without offset.
5587 'B' Print CONST_INT OP element 0 of a replicated CONST_VECTOR
5588 as an unsigned byte [0..255].
5589 'c' Print an integer.
5590 'C' Print the integer branch condition for comparison OP.
5591 'd' Print CONST_INT OP in decimal.
5592 'E' Print CONST_INT OP element 0 of a replicated CONST_VECTOR in decimal.
5593 'F' Print the FPU branch condition for comparison OP.
5594 'G' Print a DBAR insn if the memory model requires a release.
5595 'H' Print address 52-61bit relocation associated with OP.
5596 'h' Print the high-part relocation associated with OP.
5597 'i' Print i if the operand is not a register.
5598 'L' Print the low-part relocation associated with OP.
5599 'm' Print one less than CONST_INT OP in decimal.
5600 'N' Print the inverse of the integer branch condition for comparison OP.
5601 'r' Print address 12-31bit relocation associated with OP.
5602 'R' Print address 32-51bit relocation associated with OP.
5603 'T' Print 'f' for (eq:CC ...), 't' for (ne:CC ...),
5604 'z' for (eq:?I ...), 'n' for (ne:?I ...).
5605 't' Like 'T', but with the EQ/NE cases reversed
5606 'V' Print exact log2 of CONST_INT OP element 0 of a replicated
5607 CONST_VECTOR in decimal.
5608 'v' Print the insn size suffix b, h, w or d for vector modes V16QI, V8HI,
5609 V4SI, V2SI, and w, d for vector modes V4SF, V2DF respectively.
5610 'W' Print the inverse of the FPU branch condition for comparison OP.
5611 'w' Print a LSX register.
5612 'X' Print CONST_INT OP in hexadecimal format.
5613 'x' Print the low 16 bits of CONST_INT OP in hexadecimal format.
5614 'Y' Print loongarch_fp_conditions[INTVAL (OP)]
5615 'y' Print exact log2 of CONST_INT OP in decimal.
5616 'Z' Print OP and a comma for 8CC, otherwise print nothing.
5617 'z' Print $r0 if OP is zero, otherwise print OP normally. */
5620 loongarch_print_operand (FILE *file
, rtx op
, int letter
)
5624 if (loongarch_print_operand_punct_valid_p (letter
))
5626 loongarch_print_operand_punctuation (file
, letter
);
5631 code
= GET_CODE (op
);
5636 if (loongarch_memmodel_needs_rel_acq_fence ((enum memmodel
) INTVAL (op
)))
5637 fputs ("_db", file
);
5640 if (GET_CODE (op
) == CONST_VECTOR
)
5642 gcc_assert (loongarch_const_vector_same_val_p (op
, GET_MODE (op
)));
5643 op
= CONST_VECTOR_ELT (op
, 0);
5644 gcc_assert (CONST_INT_P (op
));
5645 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
5648 output_operand_lossage ("invalid use of '%%%c'", letter
);
5653 if (CONST_INT_P (op
))
5654 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
5656 output_operand_lossage ("unsupported operand for code '%c'", letter
);
5661 loongarch_print_int_branch_condition (file
, code
, letter
);
5665 if (CONST_INT_P (op
))
5666 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
5668 output_operand_lossage ("invalid use of '%%%c'", letter
);
5672 loongarch_print_float_branch_condition (file
, code
, letter
);
5676 if (loongarch_memmodel_needs_release_fence ((enum memmodel
) INTVAL (op
)))
5677 fputs ("dbar\t0", file
);
5683 loongarch_print_operand_reloc (file
, op
, false /* hi64_part */,
5684 true /* hi_reloc */);
5688 loongarch_print_operand_reloc (file
, op
, true /* hi64_part */,
5689 true /* hi_reloc */);
5698 loongarch_print_operand_reloc (file
, op
, false /* hi64_part*/,
5699 false /* lo_reloc */);
5702 if (GET_CODE (op
) == CONST_VECTOR
)
5704 gcc_assert (loongarch_const_vector_same_val_p (op
, GET_MODE (op
)));
5705 op
= CONST_VECTOR_ELT (op
, 0);
5706 gcc_assert (CONST_INT_P (op
));
5707 unsigned HOST_WIDE_INT val8
= UINTVAL (op
) & GET_MODE_MASK (QImode
);
5708 fprintf (file
, HOST_WIDE_INT_PRINT_UNSIGNED
, val8
);
5711 output_operand_lossage ("invalid use of '%%%c'", letter
);
5715 if (CONST_INT_P (op
))
5716 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
) - 1);
5718 output_operand_lossage ("invalid use of '%%%c'", letter
);
5722 loongarch_print_int_branch_condition (file
, reverse_condition (code
),
5727 loongarch_print_operand_reloc (file
, op
, false /* hi64_part */,
5728 true /* lo_reloc */);
5732 loongarch_print_operand_reloc (file
, op
, true /* hi64_part */,
5733 false /* lo_reloc */);
5739 int truth
= (code
== NE
) == (letter
== 'T');
5740 fputc ("zfnt"[truth
* 2 + FCC_REG_P (REGNO (XEXP (op
, 0)))], file
);
5745 if (CONST_VECTOR_P (op
))
5747 machine_mode mode
= GET_MODE_INNER (GET_MODE (op
));
5748 unsigned HOST_WIDE_INT val
= UINTVAL (CONST_VECTOR_ELT (op
, 0));
5749 int vlog2
= exact_log2 (val
& GET_MODE_MASK (mode
));
5751 fprintf (file
, "%d", vlog2
);
5753 output_operand_lossage ("invalid use of '%%%c'", letter
);
5756 output_operand_lossage ("invalid use of '%%%c'", letter
);
5760 switch (GET_MODE (op
))
5764 fprintf (file
, "b");
5768 fprintf (file
, "h");
5774 fprintf (file
, "w");
5780 fprintf (file
, "d");
5783 output_operand_lossage ("invalid use of '%%%c'", letter
);
5788 loongarch_print_float_branch_condition (file
, reverse_condition (code
),
5793 if (code
== REG
&& LSX_REG_P (REGNO (op
)))
5794 fprintf (file
, "$vr%s", ®_names
[REGNO (op
)][2]);
5796 output_operand_lossage ("invalid use of '%%%c'", letter
);
5800 if (CONST_INT_P (op
))
5801 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
) & 0xffff);
5803 output_operand_lossage ("invalid use of '%%%c'", letter
);
5807 if (CONST_INT_P (op
))
5808 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
5810 output_operand_lossage ("invalid use of '%%%c'", letter
);
5814 if (CONST_INT_P (op
))
5816 int val
= exact_log2 (INTVAL (op
));
5818 fprintf (file
, "%d", val
);
5820 output_operand_lossage ("invalid use of '%%%c'", letter
);
5823 output_operand_lossage ("invalid use of '%%%c'", letter
);
5827 if (code
== CONST_INT
5828 && UINTVAL (op
) < ARRAY_SIZE (loongarch_fp_conditions
))
5829 fputs (loongarch_fp_conditions
[UINTVAL (op
)], file
);
5831 output_operand_lossage ("'%%%c' is not a valid operand prefix",
5836 loongarch_print_operand (file
, op
, 0);
5845 unsigned int regno
= REGNO (op
);
5846 if (letter
&& letter
!= 'z')
5847 output_operand_lossage ("invalid use of '%%%c'", letter
);
5848 fprintf (file
, "%s", reg_names
[regno
]);
5854 output_address (GET_MODE (op
),
5855 plus_constant (Pmode
, XEXP (op
, 0), 4));
5856 else if (letter
== 'b')
5858 gcc_assert (REG_P (XEXP (op
, 0)));
5859 loongarch_print_operand (file
, XEXP (op
, 0), 0);
5861 else if (letter
&& letter
!= 'z')
5862 output_operand_lossage ("invalid use of '%%%c'", letter
);
5864 output_address (GET_MODE (op
), XEXP (op
, 0));
5868 if (letter
== 'z' && op
== CONST0_RTX (GET_MODE (op
)))
5869 fputs (reg_names
[GP_REG_FIRST
], file
);
5870 else if (letter
&& letter
!= 'z')
5871 output_operand_lossage ("invalid use of '%%%c'", letter
);
5873 output_addr_const (file
, loongarch_strip_unspec_address (op
));
5879 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5882 loongarch_print_operand_address (FILE *file
, machine_mode
/* mode */, rtx x
)
5884 struct loongarch_address_info addr
;
5886 if (loongarch_classify_address (&addr
, x
, word_mode
, true))
5890 fprintf (file
, "%s,", reg_names
[REGNO (addr
.reg
)]);
5891 loongarch_print_operand (file
, addr
.offset
, 0);
5894 case ADDRESS_REG_REG
:
5895 fprintf (file
, "%s,%s", reg_names
[REGNO (addr
.reg
)],
5896 reg_names
[REGNO (addr
.offset
)]);
5899 case ADDRESS_LO_SUM
:
5900 fprintf (file
, "%s,", reg_names
[REGNO (addr
.reg
)]);
5901 loongarch_print_operand_reloc (file
, addr
.offset
, false /* hi64_part */,
5902 false /* hi_reloc */);
5905 case ADDRESS_CONST_INT
:
5906 fprintf (file
, "%s,", reg_names
[GP_REG_FIRST
]);
5907 output_addr_const (file
, x
);
5910 case ADDRESS_SYMBOLIC
:
5911 output_addr_const (file
, loongarch_strip_unspec_address (x
));
5914 if (CONST_INT_P (x
))
5915 output_addr_const (file
, x
);
5920 /* Implement TARGET_ASM_SELECT_RTX_SECTION. */
5923 loongarch_select_rtx_section (machine_mode mode
, rtx x
,
5924 unsigned HOST_WIDE_INT align
)
5926 /* ??? Consider using mergeable small data sections. */
5927 if (loongarch_rtx_constant_in_small_data_p (mode
))
5928 return get_named_section (NULL
, ".sdata", 0);
5930 return default_elf_select_rtx_section (mode
, x
, align
);
5933 /* Implement TARGET_ASM_FUNCTION_RODATA_SECTION.
5935 The complication here is that jump tables will use absolute addresses,
5936 and should therefore not be included in the read-only part of a DSO.
5937 Handle such cases by selecting a normal data section instead of a
5938 read-only one. The logic apes that in default_function_rodata_section. */
5941 loongarch_function_rodata_section (tree decl
, bool)
5943 return default_function_rodata_section (decl
, false);
5946 /* Implement TARGET_IN_SMALL_DATA_P. */
5949 loongarch_in_small_data_p (const_tree decl
)
5953 if (TREE_CODE (decl
) == STRING_CST
|| TREE_CODE (decl
) == FUNCTION_DECL
)
5956 if (VAR_P (decl
) && DECL_SECTION_NAME (decl
) != 0)
5960 /* Reject anything that isn't in a known small-data section. */
5961 name
= DECL_SECTION_NAME (decl
);
5962 if (strcmp (name
, ".sdata") != 0 && strcmp (name
, ".sbss") != 0)
5965 /* If a symbol is defined externally, the assembler will use the
5966 usual -G rules when deciding how to implement macros. */
5967 if (!DECL_EXTERNAL (decl
))
5971 /* We have traditionally not treated zero-sized objects as small data,
5972 so this is now effectively part of the ABI. */
5973 size
= int_size_in_bytes (TREE_TYPE (decl
));
5974 return size
> 0 && size
<= g_switch_value
;
5977 /* The LoongArch debug format wants all automatic variables and arguments
5978 to be in terms of the virtual frame pointer (stack pointer before
5979 any adjustment in the function), while the LoongArch linker wants
5980 the frame pointer to be the stack pointer after the initial
5981 adjustment. So, we do the adjustment here. The arg pointer (which
5982 is eliminated) points to the virtual frame pointer, while the frame
5983 pointer (which may be eliminated) points to the stack pointer after
5984 the initial adjustments. */
5987 loongarch_debugger_offset (rtx addr
, HOST_WIDE_INT offset
)
5989 rtx offset2
= const0_rtx
;
5990 rtx reg
= eliminate_constant_term (addr
, &offset2
);
5993 offset
= INTVAL (offset2
);
5995 if (reg
== stack_pointer_rtx
5996 || reg
== frame_pointer_rtx
5997 || reg
== hard_frame_pointer_rtx
)
5999 offset
-= cfun
->machine
->frame
.total_size
;
6000 if (reg
== hard_frame_pointer_rtx
)
6001 offset
+= cfun
->machine
->frame
.hard_frame_pointer_offset
;
6007 /* Implement ASM_OUTPUT_EXTERNAL. */
6010 loongarch_output_external (FILE *file
, tree decl
, const char *name
)
6012 default_elf_asm_output_external (file
, decl
, name
);
6014 /* We output the name if and only if TREE_SYMBOL_REFERENCED is
6015 set in order to avoid putting out names that are never really
6017 if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl
)))
6019 if (loongarch_in_small_data_p (decl
))
6021 /* When using assembler macros, emit .extern directives for
6022 all small-data externs so that the assembler knows how
6025 In most cases it would be safe (though pointless) to emit
6026 .externs for other symbols too. One exception is when an
6027 object is within the -G limit but declared by the user to
6028 be in a section other than .sbss or .sdata. */
6029 fputs ("\t.extern\t", file
);
6030 assemble_name (file
, name
);
6031 fprintf (file
, ", " HOST_WIDE_INT_PRINT_DEC
"\n",
6032 int_size_in_bytes (TREE_TYPE (decl
)));
6037 /* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL. */
6039 static void ATTRIBUTE_UNUSED
6040 loongarch_output_dwarf_dtprel (FILE *file
, int size
, rtx x
)
6045 fputs ("\t.dtprelword\t", file
);
6049 fputs ("\t.dtpreldword\t", file
);
6055 output_addr_const (file
, x
);
6056 fputs ("+0x8000", file
);
6059 /* Implement ASM_OUTPUT_ASCII. */
6062 loongarch_output_ascii (FILE *stream
, const char *string
, size_t len
)
6068 fprintf (stream
, "\t.ascii\t\"");
6069 for (i
= 0; i
< len
; i
++)
6073 c
= (unsigned char) string
[i
];
6076 if (c
== '\\' || c
== '\"')
6078 putc ('\\', stream
);
6086 fprintf (stream
, "\\%03o", c
);
6090 if (cur_pos
> 72 && i
+ 1 < len
)
6093 fprintf (stream
, "\"\n\t.ascii\t\"");
6096 fprintf (stream
, "\"\n");
6099 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
6102 loongarch_frame_pointer_required (void)
6104 /* If the function contains dynamic stack allocations, we need to
6105 use the frame pointer to access the static parts of the frame. */
6106 if (cfun
->calls_alloca
)
6112 /* Implement TARGET_CAN_ELIMINATE. Make sure that we're not trying
6113 to eliminate to the wrong hard frame pointer. */
6116 loongarch_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
6118 return (to
== HARD_FRAME_POINTER_REGNUM
|| to
== STACK_POINTER_REGNUM
);
6121 /* Implement RETURN_ADDR_RTX. We do not support moving back to a
6125 loongarch_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
6130 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNUM
);
6133 /* Emit code to change the current function's return address to
6134 ADDRESS. SCRATCH is available as a scratch register, if needed.
6135 ADDRESS and SCRATCH are both word-mode GPRs. */
6138 loongarch_set_return_address (rtx address
, rtx scratch
)
6142 gcc_assert (BITSET_P (cfun
->machine
->frame
.mask
, RETURN_ADDR_REGNUM
));
6144 if (frame_pointer_needed
)
6145 slot_address
= loongarch_add_offset (scratch
, hard_frame_pointer_rtx
,
6148 slot_address
= loongarch_add_offset (scratch
, stack_pointer_rtx
,
6149 cfun
->machine
->frame
.gp_sp_offset
);
6151 loongarch_emit_move (gen_frame_mem (GET_MODE (address
), slot_address
),
6155 /* Return true if register REGNO can store a value of mode MODE.
6156 The result of this function is cached in loongarch_hard_regno_mode_ok. */
6159 loongarch_hard_regno_mode_ok_uncached (unsigned int regno
, machine_mode mode
)
6162 enum mode_class mclass
;
6164 if (mode
== FCCmode
)
6165 return FCC_REG_P (regno
);
6167 size
= GET_MODE_SIZE (mode
);
6168 mclass
= GET_MODE_CLASS (mode
);
6170 if (GP_REG_P (regno
) && !LSX_SUPPORTED_MODE_P (mode
))
6171 return ((regno
- GP_REG_FIRST
) & 1) == 0 || size
<= UNITS_PER_WORD
;
6173 /* For LSX, allow TImode and 128-bit vector modes in all FPR. */
6174 if (FP_REG_P (regno
) && LSX_SUPPORTED_MODE_P (mode
))
6177 if (FP_REG_P (regno
))
6179 if (mclass
== MODE_FLOAT
6180 || mclass
== MODE_COMPLEX_FLOAT
6181 || mclass
== MODE_VECTOR_FLOAT
)
6182 return size
<= UNITS_PER_FPVALUE
;
6184 /* Allow integer modes that fit into a single register. We need
6185 to put integers into FPRs when using instructions like CVT
6186 and TRUNC. There's no point allowing sizes smaller than a word,
6187 because the FPU has no appropriate load/store instructions. */
6188 if (mclass
== MODE_INT
)
6189 return size
>= MIN_UNITS_PER_WORD
&& size
<= UNITS_PER_FPREG
;
6195 /* Implement TARGET_HARD_REGNO_MODE_OK. */
6198 loongarch_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
6200 return loongarch_hard_regno_mode_ok_p
[mode
][regno
];
6205 loongarch_hard_regno_call_part_clobbered (unsigned int,
6206 unsigned int regno
, machine_mode mode
)
6208 if (ISA_HAS_LSX
&& FP_REG_P (regno
) && GET_MODE_SIZE (mode
) > 8)
6214 /* Implement TARGET_HARD_REGNO_NREGS. */
6217 loongarch_hard_regno_nregs (unsigned int regno
, machine_mode mode
)
6219 if (FCC_REG_P (regno
))
6220 /* The size of FP status registers is always 4, because they only hold
6221 FCCmode values, and FCCmode is always considered to be 4 bytes wide. */
6222 return (GET_MODE_SIZE (mode
) + 3) / 4;
6224 if (FP_REG_P (regno
))
6226 if (LSX_SUPPORTED_MODE_P (mode
))
6229 return (GET_MODE_SIZE (mode
) + UNITS_PER_FPREG
- 1) / UNITS_PER_FPREG
;
6232 /* All other registers are word-sized. */
6233 return (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
6236 /* Implement CLASS_MAX_NREGS, taking the maximum of the cases
6237 in loongarch_hard_regno_nregs. */
6240 loongarch_class_max_nregs (enum reg_class rclass
, machine_mode mode
)
6246 left
= reg_class_contents
[rclass
];
6247 if (hard_reg_set_intersect_p (left
, reg_class_contents
[(int) FCC_REGS
]))
6249 if (loongarch_hard_regno_mode_ok (FCC_REG_FIRST
, mode
))
6250 size
= MIN (size
, 4);
6252 left
&= ~reg_class_contents
[FCC_REGS
];
6254 if (hard_reg_set_intersect_p (left
, reg_class_contents
[(int) FP_REGS
]))
6256 if (loongarch_hard_regno_mode_ok (FP_REG_FIRST
, mode
))
6258 if (LSX_SUPPORTED_MODE_P (mode
))
6259 size
= MIN (size
, UNITS_PER_LSX_REG
);
6261 size
= MIN (size
, UNITS_PER_FPREG
);
6263 left
&= ~reg_class_contents
[FP_REGS
];
6265 if (!hard_reg_set_empty_p (left
))
6266 size
= MIN (size
, UNITS_PER_WORD
);
6267 return (GET_MODE_SIZE (mode
) + size
- 1) / size
;
6270 /* Implement TARGET_CAN_CHANGE_MODE_CLASS. */
6273 loongarch_can_change_mode_class (machine_mode from
, machine_mode to
,
6276 /* Allow conversions between different LSX vector modes. */
6277 if (LSX_SUPPORTED_MODE_P (from
) && LSX_SUPPORTED_MODE_P (to
))
6280 return !reg_classes_intersect_p (FP_REGS
, rclass
);
6283 /* Return true if moves in mode MODE can use the FPU's fmov.fmt instruction,
6287 loongarch_mode_ok_for_mov_fmt_p (machine_mode mode
)
6293 return TARGET_HARD_FLOAT
;
6296 return TARGET_HARD_FLOAT
&& TARGET_DOUBLE_FLOAT
;
6299 return LSX_SUPPORTED_MODE_P (mode
);
6303 /* Implement TARGET_MODES_TIEABLE_P. */
6306 loongarch_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
6308 /* FPRs allow no mode punning, so it's not worth tying modes if we'd
6309 prefer to put one of them in FPRs. */
6310 return (mode1
== mode2
6311 || (!loongarch_mode_ok_for_mov_fmt_p (mode1
)
6312 && !loongarch_mode_ok_for_mov_fmt_p (mode2
)));
6315 /* Implement TARGET_PREFERRED_RELOAD_CLASS. */
6318 loongarch_preferred_reload_class (rtx x
, reg_class_t rclass
)
6320 if (reg_class_subset_p (FP_REGS
, rclass
)
6321 && loongarch_mode_ok_for_mov_fmt_p (GET_MODE (x
)))
6324 if (reg_class_subset_p (GR_REGS
, rclass
))
6330 /* RCLASS is a class involved in a REGISTER_MOVE_COST calculation.
6331 Return a "canonical" class to represent it in later calculations. */
6334 loongarch_canonicalize_move_class (reg_class_t rclass
)
6336 if (reg_class_subset_p (rclass
, GENERAL_REGS
))
6337 rclass
= GENERAL_REGS
;
6342 /* Return the cost of moving a value from a register of class FROM to a GPR.
6343 Return 0 for classes that are unions of other classes handled by this
6347 loongarch_move_to_gpr_cost (reg_class_t from
)
6356 /* MOVFR2GR, etc. */
6364 /* Return the cost of moving a value from a GPR to a register of class TO.
6365 Return 0 for classes that are unions of other classes handled by this
6369 loongarch_move_from_gpr_cost (reg_class_t to
)
6378 /* MOVGR2FR, etc. */
6386 /* Implement TARGET_REGISTER_MOVE_COST. Return 0 for classes that are the
6387 maximum of the move costs for subclasses; regclass will work out
6388 the maximum for us. */
6391 loongarch_register_move_cost (machine_mode mode
, reg_class_t from
,
6397 from
= loongarch_canonicalize_move_class (from
);
6398 to
= loongarch_canonicalize_move_class (to
);
6400 /* Handle moves that can be done without using general-purpose registers. */
6401 if (from
== FP_REGS
)
6403 if (to
== FP_REGS
&& loongarch_mode_ok_for_mov_fmt_p (mode
))
6408 /* Handle cases in which only one class deviates from the ideal. */
6409 dregs
= GENERAL_REGS
;
6411 return loongarch_move_from_gpr_cost (to
);
6413 return loongarch_move_to_gpr_cost (from
);
6415 /* Handles cases that require a GPR temporary. */
6416 cost1
= loongarch_move_to_gpr_cost (from
);
6419 cost2
= loongarch_move_from_gpr_cost (to
);
6421 return cost1
+ cost2
;
6427 /* Implement TARGET_MEMORY_MOVE_COST. */
6430 loongarch_memory_move_cost (machine_mode mode
, reg_class_t rclass
, bool in
)
6432 return (loongarch_cost
->memory_latency
6433 + memory_move_secondary_cost (mode
, rclass
, in
));
6436 /* Return the register class required for a secondary register when
6437 copying between one of the registers in RCLASS and value X, which
6438 has mode MODE. X is the source of the move if IN_P, otherwise it
6439 is the destination. Return NO_REGS if no secondary register is
6443 loongarch_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x
,
6444 reg_class_t rclass
, machine_mode mode
,
6445 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
6449 regno
= true_regnum (x
);
6451 if (reg_class_subset_p (rclass
, FP_REGS
))
6455 && (GET_MODE_SIZE (mode
) == 4 || GET_MODE_SIZE (mode
) == 8)))
6456 /* In this case we can use lwc1, swc1, ldc1 or sdc1. We'll use
6457 pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported. */
6460 if (MEM_P (x
) && LSX_SUPPORTED_MODE_P (mode
))
6461 /* In this case we can use LSX LD.* and ST.*. */
6464 if (GP_REG_P (regno
) || x
== CONST0_RTX (mode
))
6465 /* In this case we can use movgr2fr.s, movfr2gr.s, movgr2fr.d or
6469 if (CONSTANT_P (x
) && !targetm
.cannot_force_const_mem (mode
, x
))
6470 /* We can force the constant to memory and use fld.s
6471 and fld.d. As above, we will use pairs of lwc1s if
6472 ldc1 is not supported. */
6475 if (FP_REG_P (regno
) && loongarch_mode_ok_for_mov_fmt_p (mode
))
6476 /* In this case we can use fmov.{s/d}. */
6479 /* Otherwise, we need to reload through an integer register. */
6482 if (FP_REG_P (regno
))
6483 return reg_class_subset_p (rclass
, GR_REGS
) ? NO_REGS
: GR_REGS
;
6488 /* Implement TARGET_VALID_POINTER_MODE. */
6491 loongarch_valid_pointer_mode (scalar_int_mode mode
)
6493 return mode
== SImode
|| (TARGET_64BIT
&& mode
== DImode
);
6496 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
6499 loongarch_vector_mode_supported_p (machine_mode mode
)
6501 return LSX_SUPPORTED_MODE_P (mode
);
6504 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
6507 loongarch_scalar_mode_supported_p (scalar_mode mode
)
6509 if (ALL_FIXED_POINT_MODE_P (mode
)
6510 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
6513 return default_scalar_mode_supported_p (mode
);
6516 /* Implement TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
6519 loongarch_preferred_simd_mode (scalar_mode mode
)
6548 loongarch_autovectorize_vector_modes (vector_modes
*modes
, bool)
6552 modes
->safe_push (V16QImode
);
6558 /* Return the assembly code for INSN, which has the operands given by
6559 OPERANDS, and which branches to OPERANDS[0] if some condition is true.
6560 BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[0]
6561 is in range of a direct branch. BRANCH_IF_FALSE is an inverted
6562 version of BRANCH_IF_TRUE. */
6565 loongarch_output_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
6566 const char *branch_if_true
,
6567 const char *branch_if_false
)
6569 unsigned int length
;
6572 gcc_assert (LABEL_P (operands
[0]));
6574 length
= get_attr_length (insn
);
6577 return branch_if_true
;
6580 /* Generate a reversed branch around a direct jump. */
6581 rtx_code_label
*not_taken
= gen_label_rtx ();
6582 taken
= operands
[0];
6584 /* Generate the reversed branch to NOT_TAKEN. */
6585 operands
[0] = not_taken
;
6586 output_asm_insn (branch_if_false
, operands
);
6588 output_asm_insn ("b\t%0", &taken
);
6590 /* Output NOT_TAKEN. */
6591 targetm
.asm_out
.internal_label (asm_out_file
, "L",
6592 CODE_LABEL_NUMBER (not_taken
));
6596 /* Return the assembly code for INSN, which branches to OPERANDS[0]
6597 if some equality condition is true. The condition is given by
6598 OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
6599 OPERANDS[1]. OPERANDS[2] is the comparison's first operand;
6600 OPERANDS[3] is the second operand and may be zero or a register. */
6603 loongarch_output_equal_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
6606 const char *branch
[2];
6607 if (operands
[3] == const0_rtx
)
6609 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1z", "%2,%0");
6610 branch
[inverted_p
] = LARCH_BRANCH ("b%N1z", "%2,%0");
6614 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,%z3,%0");
6615 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,%z3,%0");
6618 return loongarch_output_conditional_branch (insn
, operands
, branch
[1],
6622 /* Return the assembly code for INSN, which branches to OPERANDS[0]
6623 if some ordering condition is true. The condition is given by
6624 OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
6625 OPERANDS[1]. OPERANDS[2] is the comparison's first operand;
6626 OPERANDS[3] is the second operand and may be zero or a register. */
6629 loongarch_output_order_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
6632 const char *branch
[2];
6634 /* Make BRANCH[1] branch to OPERANDS[0] when the condition is true.
6635 Make BRANCH[0] branch on the inverse condition. */
6636 if (operands
[3] != const0_rtx
)
6638 /* Handle degenerate cases that should not, but do, occur. */
6639 if (REGNO (operands
[2]) == REGNO (operands
[3]))
6641 switch (GET_CODE (operands
[1]))
6647 inverted_p
= !inverted_p
;
6653 branch
[!inverted_p
] = LARCH_BRANCH ("b", "%0");
6654 branch
[inverted_p
] = "\t# branch never";
6662 switch (GET_CODE (operands
[1]))
6672 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,%3,%0");
6673 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,%3,%0");
6682 switch (GET_CODE (operands
[1]))
6684 /* These cases are equivalent to comparisons against zero. */
6693 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,$r0,%0");
6694 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,$r0,%0");
6700 return loongarch_output_conditional_branch (insn
, operands
, branch
[1],
6704 /* Return the assembly code for DIV.{W/D} instruction DIVISION, which has
6705 the operands given by OPERANDS. Add in a divide-by-zero check if needed.
6709 loongarch_output_division (const char *division
, rtx
*operands
)
6714 if (loongarch_check_zero_div_p ())
6716 output_asm_insn (s
, operands
);
6717 s
= "bne\t%2,%.,1f\n\tbreak\t7\n1:";
6722 /* Return the assembly code for LSX DIV_{S,U}.DF or MOD_{S,U}.DF instructions,
6723 which has the operands given by OPERANDS. Add in a divide-by-zero check
6727 loongarch_lsx_output_division (const char *division
, rtx
*operands
)
6732 if (TARGET_CHECK_ZERO_DIV
)
6736 output_asm_insn ("vsetallnez.%v0\t$fcc7,%w2",operands
);
6737 output_asm_insn (s
, operands
);
6738 output_asm_insn ("bcnez\t$fcc7,1f", operands
);
6745 /* Implement TARGET_SCHED_ADJUST_COST. We assume that anti and output
6746 dependencies have no cost. */
6749 loongarch_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
6752 if (dep_type
!= 0 && (dep_type
!= REG_DEP_OUTPUT
))
6757 /* Return the number of instructions that can be issued per cycle. */
6760 loongarch_issue_rate (void)
6762 if ((unsigned long) la_target
.cpu_tune
< N_TUNE_TYPES
)
6763 return loongarch_cpu_issue_rate
[la_target
.cpu_tune
];
6768 /* Implement TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD. This should
6769 be as wide as the scheduling freedom in the DFA. */
6772 loongarch_multipass_dfa_lookahead (void)
6774 if ((unsigned long) la_target
.cpu_tune
< N_ARCH_TYPES
)
6775 return loongarch_cpu_multipass_dfa_lookahead
[la_target
.cpu_tune
];
6780 /* Implement TARGET_SCHED_REORDER. */
6783 loongarch_sched_reorder (FILE *file ATTRIBUTE_UNUSED
,
6784 int verbose ATTRIBUTE_UNUSED
,
6785 rtx_insn
**ready ATTRIBUTE_UNUSED
,
6786 int *nreadyp ATTRIBUTE_UNUSED
,
6787 int cycle ATTRIBUTE_UNUSED
)
6789 return loongarch_issue_rate ();
6792 /* Implement TARGET_SCHED_REORDER2. */
6795 loongarch_sched_reorder2 (FILE *file ATTRIBUTE_UNUSED
,
6796 int verbose ATTRIBUTE_UNUSED
,
6797 rtx_insn
**ready ATTRIBUTE_UNUSED
,
6798 int *nreadyp ATTRIBUTE_UNUSED
,
6799 int cycle ATTRIBUTE_UNUSED
)
6801 return cached_can_issue_more
;
6804 /* Implement TARGET_SCHED_INIT. */
6807 loongarch_sched_init (FILE *file ATTRIBUTE_UNUSED
,
6808 int verbose ATTRIBUTE_UNUSED
,
6809 int max_ready ATTRIBUTE_UNUSED
)
6812 /* Implement TARGET_SCHED_VARIABLE_ISSUE. */
6815 loongarch_variable_issue (FILE *file ATTRIBUTE_UNUSED
,
6816 int verbose ATTRIBUTE_UNUSED
, rtx_insn
*insn
,
6819 /* Ignore USEs and CLOBBERs; don't count them against the issue rate. */
6820 if (USEFUL_INSN_P (insn
))
6822 if (get_attr_type (insn
) != TYPE_GHOST
)
6826 /* Instructions of type 'multi' should all be split before
6827 the second scheduling pass. */
6828 gcc_assert (!reload_completed
6829 || recog_memoized (insn
) < 0
6830 || get_attr_type (insn
) != TYPE_MULTI
);
6832 cached_can_issue_more
= more
;
6836 /* Given that we have an rtx of the form (prefetch ... WRITE LOCALITY),
6837 return the first operand of the associated PREF or PREFX insn. */
6840 loongarch_prefetch_cookie (rtx write
, rtx locality
)
6842 /* store_streamed / load_streamed. */
6843 if (INTVAL (locality
) <= 0)
6844 return GEN_INT (INTVAL (write
) + 4);
6847 if (INTVAL (locality
) <= 2)
6850 /* store_retained / load_retained. */
6851 return GEN_INT (INTVAL (write
) + 6);
6854 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
6855 in order to avoid duplicating too much logic from elsewhere. */
6858 loongarch_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
6859 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
6862 const char *fnname
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl
));
6863 rtx this_rtx
, temp1
, temp2
, fnaddr
;
6867 /* Pretend to be a post-reload pass while generating rtl. */
6868 reload_completed
= 1;
6870 /* Mark the end of the (empty) prologue. */
6871 emit_note (NOTE_INSN_PROLOGUE_END
);
6873 /* Determine if we can use a sibcall to call FUNCTION directly. */
6874 fnaddr
= XEXP (DECL_RTL (function
), 0);
6875 use_sibcall_p
= const_call_insn_operand (fnaddr
, Pmode
);
6877 /* We need two temporary registers in some cases. */
6878 temp1
= gen_rtx_REG (Pmode
, 12);
6879 temp2
= gen_rtx_REG (Pmode
, 13);
6881 /* Find out which register contains the "this" pointer. */
6882 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
6883 this_rtx
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
+ 1);
6885 this_rtx
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
);
6887 /* Add DELTA to THIS_RTX. */
6890 rtx offset
= GEN_INT (delta
);
6891 if (!IMM12_OPERAND (delta
))
6893 loongarch_emit_move (temp1
, offset
);
6896 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
6899 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
6900 if (vcall_offset
!= 0)
6904 /* Set TEMP1 to *THIS_RTX. */
6905 loongarch_emit_move (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
6907 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
6908 addr
= loongarch_add_offset (temp2
, temp1
, vcall_offset
);
6910 /* Load the offset and add it to THIS_RTX. */
6911 loongarch_emit_move (temp1
, gen_rtx_MEM (Pmode
, addr
));
6912 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
6915 /* Jump to the target function. Use a sibcall if direct jumps are
6916 allowed, otherwise load the address into a register first. */
6919 insn
= emit_call_insn (gen_sibcall_internal (fnaddr
, const0_rtx
));
6920 SIBLING_CALL_P (insn
) = 1;
6924 loongarch_emit_move (temp1
, fnaddr
);
6925 emit_jump_insn (gen_indirect_jump (temp1
));
6928 /* Run just enough of rest_of_compilation. This sequence was
6929 "borrowed" from alpha.c. */
6930 insn
= get_insns ();
6931 split_all_insns_noflow ();
6932 shorten_branches (insn
);
6933 assemble_start_function (thunk_fndecl
, fnname
);
6934 final_start_function (insn
, file
, 1);
6935 final (insn
, file
, 1);
6936 final_end_function ();
6937 assemble_end_function (thunk_fndecl
, fnname
);
6939 /* Stop pretending to be a post-reload pass. */
6940 reload_completed
= 0;
6943 /* Allocate a chunk of memory for per-function machine-dependent data. */
6945 static struct machine_function
*
6946 loongarch_init_machine_status (void)
6948 return ggc_cleared_alloc
<machine_function
> ();
6952 loongarch_cpu_option_override (struct loongarch_target
*target
,
6953 struct gcc_options
*opts
,
6954 struct gcc_options
*opts_set
)
6957 if (opts
->x_flag_align_functions
&& !opts
->x_str_align_functions
)
6958 opts
->x_str_align_functions
6959 = loongarch_cpu_align
[target
->cpu_tune
].function
;
6961 if (opts
->x_flag_align_labels
&& !opts
->x_str_align_labels
)
6962 opts
->x_str_align_labels
= loongarch_cpu_align
[target
->cpu_tune
].label
;
6964 /* Set up parameters to be used in prefetching algorithm. */
6965 int simultaneous_prefetches
6966 = loongarch_cpu_cache
[target
->cpu_tune
].simultaneous_prefetches
;
6968 SET_OPTION_IF_UNSET (opts
, opts_set
, param_simultaneous_prefetches
,
6969 simultaneous_prefetches
);
6971 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l1_cache_line_size
,
6972 loongarch_cpu_cache
[target
->cpu_tune
].l1d_line_size
);
6974 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l1_cache_size
,
6975 loongarch_cpu_cache
[target
->cpu_tune
].l1d_size
);
6977 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l2_cache_size
,
6978 loongarch_cpu_cache
[target
->cpu_tune
].l2d_size
);
6982 loongarch_option_override_internal (struct gcc_options
*opts
,
6983 struct gcc_options
*opts_set
)
6990 loongarch_init_target (&la_target
,
6991 la_opt_cpu_arch
, la_opt_cpu_tune
, la_opt_fpu
,
6992 la_opt_simd
, la_opt_abi_base
, la_opt_abi_ext
,
6995 /* Handle target-specific options: compute defaults/conflicts etc. */
6996 loongarch_config_target (&la_target
, NULL
, 0);
6998 loongarch_update_gcc_opt_status (&la_target
, opts
, opts_set
);
6999 loongarch_cpu_option_override (&la_target
, opts
, opts_set
);
7001 if (TARGET_ABI_LP64
)
7002 flag_pcc_struct_return
= 0;
7004 /* Decide which rtx_costs structure to use. */
7006 loongarch_cost
= &loongarch_rtx_cost_optimize_size
;
7008 loongarch_cost
= &loongarch_cpu_rtx_cost_data
[la_target
.cpu_tune
];
7010 /* If the user hasn't specified a branch cost, use the processor's
7012 if (loongarch_branch_cost
== 0)
7013 loongarch_branch_cost
= loongarch_cost
->branch_cost
;
7016 /* Enable sw prefetching at -O3 and higher. */
7017 if (opts
->x_flag_prefetch_loop_arrays
< 0
7018 && (opts
->x_optimize
>= 3 || opts
->x_flag_profile_use
)
7019 && !opts
->x_optimize_size
)
7020 opts
->x_flag_prefetch_loop_arrays
= 1;
7022 if (TARGET_DIRECT_EXTERN_ACCESS
&& flag_shlib
)
7023 error ("%qs cannot be used for compiling a shared library",
7024 "-mdirect-extern-access");
7025 if (loongarch_vector_access_cost
== 0)
7026 loongarch_vector_access_cost
= 5;
7029 switch (la_target
.cmodel
)
7031 case CMODEL_EXTREME
:
7032 if (!TARGET_EXPLICIT_RELOCS
)
7033 error ("code model %qs needs %s",
7034 "extreme", "-mexplicit-relocs");
7036 if (opts
->x_flag_plt
)
7038 if (global_options_set
.x_flag_plt
)
7039 error ("code model %qs is not compatible with %s",
7040 "extreme", "-fplt");
7041 opts
->x_flag_plt
= 0;
7045 case CMODEL_TINY_STATIC
:
7056 /* Validate the guard size. */
7057 int guard_size
= param_stack_clash_protection_guard_size
;
7059 /* Enforce that interval is the same size as size so the mid-end does the
7061 SET_OPTION_IF_UNSET (opts
, &global_options_set
,
7062 param_stack_clash_protection_probe_interval
,
7065 loongarch_init_print_operand_punct ();
7067 /* Set up array to map GCC register number to debug register number.
7068 Ignore the special purpose register numbers. */
7070 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
7072 if (GP_REG_P (i
) || FP_REG_P (i
))
7073 loongarch_dwarf_regno
[i
] = i
;
7075 loongarch_dwarf_regno
[i
] = INVALID_REGNUM
;
7078 /* Set up loongarch_hard_regno_mode_ok. */
7079 for (mode
= 0; mode
< MAX_MACHINE_MODE
; mode
++)
7080 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
7081 loongarch_hard_regno_mode_ok_p
[mode
][regno
]
7082 = loongarch_hard_regno_mode_ok_uncached (regno
, (machine_mode
) mode
);
7084 /* Function to allocate machine-dependent function status. */
7085 init_machine_status
= &loongarch_init_machine_status
;
7089 /* Implement TARGET_OPTION_OVERRIDE. */
7092 loongarch_option_override (void)
7094 loongarch_option_override_internal (&global_options
, &global_options_set
);
7097 /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
7100 loongarch_conditional_register_usage (void)
7102 if (!TARGET_HARD_FLOAT
)
7103 accessible_reg_set
&= ~(reg_class_contents
[FP_REGS
]
7104 | reg_class_contents
[FCC_REGS
]);
7107 /* Implement EH_USES. */
7110 loongarch_eh_uses (unsigned int regno ATTRIBUTE_UNUSED
)
7115 /* Implement EPILOGUE_USES. */
7118 loongarch_epilogue_uses (unsigned int regno
)
7120 /* Say that the epilogue uses the return address register. Note that
7121 in the case of sibcalls, the values "used by the epilogue" are
7122 considered live at the start of the called function. */
7123 if (regno
== RETURN_ADDR_REGNUM
)
7130 loongarch_load_store_bonding_p (rtx
*operands
, machine_mode mode
, bool load_p
)
7132 rtx reg1
, reg2
, mem1
, mem2
, base1
, base2
;
7133 enum reg_class rc1
, rc2
;
7134 HOST_WIDE_INT offset1
, offset2
;
7151 if (loongarch_address_insns (XEXP (mem1
, 0), mode
, false) == 0
7152 || loongarch_address_insns (XEXP (mem2
, 0), mode
, false) == 0)
7155 loongarch_split_plus (XEXP (mem1
, 0), &base1
, &offset1
);
7156 loongarch_split_plus (XEXP (mem2
, 0), &base2
, &offset2
);
7158 /* Base regs do not match. */
7159 if (!REG_P (base1
) || !rtx_equal_p (base1
, base2
))
7162 /* Either of the loads is clobbering base register. It is legitimate to bond
7163 loads if second load clobbers base register. However, hardware does not
7164 support such bonding. */
7166 && (REGNO (reg1
) == REGNO (base1
) || (REGNO (reg2
) == REGNO (base1
))))
7169 /* Loading in same registers. */
7170 if (load_p
&& REGNO (reg1
) == REGNO (reg2
))
7173 /* The loads/stores are not of same type. */
7174 rc1
= REGNO_REG_CLASS (REGNO (reg1
));
7175 rc2
= REGNO_REG_CLASS (REGNO (reg2
));
7176 if (rc1
!= rc2
&& !reg_class_subset_p (rc1
, rc2
)
7177 && !reg_class_subset_p (rc2
, rc1
))
7180 if (abs (offset1
- offset2
) != GET_MODE_SIZE (mode
))
7186 /* Implement TARGET_TRAMPOLINE_INIT. */
7189 loongarch_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
7191 rtx addr
, end_addr
, mem
;
7194 HOST_WIDE_INT end_addr_offset
, static_chain_offset
, target_function_offset
;
7196 /* Work out the offsets of the pointers from the start of the
7198 end_addr_offset
= TRAMPOLINE_CODE_SIZE
;
7199 static_chain_offset
= end_addr_offset
;
7200 target_function_offset
= static_chain_offset
+ GET_MODE_SIZE (ptr_mode
);
7202 /* Get pointers to the beginning and end of the code block. */
7203 addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
7205 = loongarch_force_binary (Pmode
, PLUS
, addr
, GEN_INT (end_addr_offset
));
7207 #define OP(X) gen_int_mode (X, SImode)
7209 /* Build up the code in TRAMPOLINE. */
7211 /*pcaddi $static_chain,0
7212 ld.[dw] $tmp,$static_chain,target_function_offset
7213 ld.[dw] $static_chain,$static_chain,static_chain_offset
7215 trampoline
[i
++] = OP (0x18000000 | (STATIC_CHAIN_REGNUM
- GP_REG_FIRST
));
7216 trampoline
[i
++] = OP ((ptr_mode
== DImode
? 0x28c00000 : 0x28800000)
7218 | ((STATIC_CHAIN_REGNUM
- GP_REG_FIRST
) << 5)
7219 | ((target_function_offset
& 0xfff) << 10));
7220 trampoline
[i
++] = OP ((ptr_mode
== DImode
? 0x28c00000 : 0x28800000)
7221 | (STATIC_CHAIN_REGNUM
- GP_REG_FIRST
)
7222 | ((STATIC_CHAIN_REGNUM
- GP_REG_FIRST
) << 5)
7223 | ((static_chain_offset
& 0xfff) << 10));
7224 trampoline
[i
++] = OP (0x4c000000 | (19 << 5));
7227 for (j
= 0; j
< i
; j
++)
7229 mem
= adjust_address (m_tramp
, SImode
, j
* GET_MODE_SIZE (SImode
));
7230 loongarch_emit_move (mem
, trampoline
[j
]);
7233 /* Set up the static chain pointer field. */
7234 mem
= adjust_address (m_tramp
, ptr_mode
, static_chain_offset
);
7235 loongarch_emit_move (mem
, chain_value
);
7237 /* Set up the target function field. */
7238 mem
= adjust_address (m_tramp
, ptr_mode
, target_function_offset
);
7239 loongarch_emit_move (mem
, XEXP (DECL_RTL (fndecl
), 0));
7241 /* Flush the code part of the trampoline. */
7242 emit_insn (gen_add3_insn (end_addr
, addr
, GEN_INT (TRAMPOLINE_SIZE
)));
7243 emit_insn (gen_clear_cache (addr
, end_addr
));
7246 /* Generate or test for an insn that supports a constant permutation. */
7248 #define MAX_VECT_LEN 32
7250 struct expand_vec_perm_d
7252 rtx target
, op0
, op1
;
7253 unsigned char perm
[MAX_VECT_LEN
];
7260 /* Construct (set target (vec_select op0 (parallel perm))) and
7261 return true if that's a valid instruction in the active ISA. */
7264 loongarch_expand_vselect (rtx target
, rtx op0
,
7265 const unsigned char *perm
, unsigned nelt
)
7267 rtx rperm
[MAX_VECT_LEN
], x
;
7271 for (i
= 0; i
< nelt
; ++i
)
7272 rperm
[i
] = GEN_INT (perm
[i
]);
7274 x
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec_v (nelt
, rperm
));
7275 x
= gen_rtx_VEC_SELECT (GET_MODE (target
), op0
, x
);
7276 x
= gen_rtx_SET (target
, x
);
7278 insn
= emit_insn (x
);
7279 if (recog_memoized (insn
) < 0)
7287 /* Similar, but generate a vec_concat from op0 and op1 as well. */
7290 loongarch_expand_vselect_vconcat (rtx target
, rtx op0
, rtx op1
,
7291 const unsigned char *perm
, unsigned nelt
)
7293 machine_mode v2mode
;
7296 if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0
)).exists (&v2mode
))
7298 x
= gen_rtx_VEC_CONCAT (v2mode
, op0
, op1
);
7299 return loongarch_expand_vselect (target
, x
, perm
, nelt
);
7303 loongarch_handle_model_attribute (tree
*node
, tree name
, tree arg
, int,
7309 if (DECL_THREAD_LOCAL_P (decl
))
7311 error_at (DECL_SOURCE_LOCATION (decl
),
7312 "%qE attribute cannot be specified for thread-local "
7314 *no_add_attrs
= true;
7317 if (DECL_CONTEXT (decl
)
7318 && TREE_CODE (DECL_CONTEXT (decl
)) == FUNCTION_DECL
7319 && !TREE_STATIC (decl
))
7321 error_at (DECL_SOURCE_LOCATION (decl
),
7322 "%qE attribute cannot be specified for local "
7324 *no_add_attrs
= true;
7327 if (DECL_REGISTER (decl
))
7329 error_at (DECL_SOURCE_LOCATION (decl
),
7330 "%qE attribute cannot be specified for register "
7332 *no_add_attrs
= true;
7335 if (!TARGET_EXPLICIT_RELOCS
)
7337 error_at (DECL_SOURCE_LOCATION (decl
),
7338 "%qE attribute requires %s", name
, "-mexplicit-relocs");
7339 *no_add_attrs
= true;
7343 arg
= TREE_VALUE (arg
);
7344 if (TREE_CODE (arg
) != STRING_CST
)
7346 error_at (DECL_SOURCE_LOCATION (decl
),
7347 "invalid argument of %qE attribute", name
);
7348 *no_add_attrs
= true;
7352 const char *model
= TREE_STRING_POINTER (arg
);
7353 if (strcmp (model
, "normal") != 0
7354 && strcmp (model
, "extreme") != 0)
7356 error_at (DECL_SOURCE_LOCATION (decl
),
7357 "invalid argument of %qE attribute", name
);
7358 *no_add_attrs
= true;
7362 if (lookup_attribute ("model", DECL_ATTRIBUTES (decl
)))
7364 error_at (DECL_SOURCE_LOCATION (decl
),
7365 "multiple %qE attribute", name
);
7366 *no_add_attrs
= true;
7372 warning (OPT_Wattributes
, "%qE attribute ignored", name
);
7373 *no_add_attrs
= true;
7378 static const struct attribute_spec loongarch_attribute_table
[] =
7380 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
7381 affects_type_identity, handler, exclude } */
7382 { "model", 1, 1, true, false, false, false,
7383 loongarch_handle_model_attribute
, NULL
},
7384 /* The last attribute spec is set to be NULL. */
7389 loongarch_use_anchors_for_symbol_p (const_rtx symbol
)
7391 tree decl
= SYMBOL_REF_DECL (symbol
);
7393 /* The section anchor optimization may break custom address model. */
7394 if (decl
&& lookup_attribute ("model", DECL_ATTRIBUTES (decl
)))
7397 return default_use_anchors_for_symbol_p (symbol
);
7400 /* Implement the TARGET_ASAN_SHADOW_OFFSET hook. */
7402 static unsigned HOST_WIDE_INT
7403 loongarch_asan_shadow_offset (void)
7405 /* We only have libsanitizer support for LOONGARCH64 at present.
7406 This value is taken from the file libsanitizer/asan/asan_mapping.h. */
7407 return TARGET_64BIT
? (HOST_WIDE_INT_1
<< 46) : 0;
7411 loongarch_get_separate_components (void)
7413 HOST_WIDE_INT offset
;
7414 sbitmap components
= sbitmap_alloc (FIRST_PSEUDO_REGISTER
);
7415 bitmap_clear (components
);
7416 offset
= cfun
->machine
->frame
.gp_sp_offset
;
7418 /* The stack should be aligned to 16-bytes boundary, so we can make the use
7419 of ldptr instructions. */
7420 gcc_assert (offset
% UNITS_PER_WORD
== 0);
7422 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
7423 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
7425 /* We can wrap general registers saved at [sp, sp + 32768) using the
7426 ldptr/stptr instructions. For large offsets a pseudo register
7427 might be needed which cannot be created during the shrink
7430 TODO: This may need a revise when we add LA32 as ldptr.w is not
7431 guaranteed available by the manual. */
7433 bitmap_set_bit (components
, regno
);
7435 offset
-= UNITS_PER_WORD
;
7438 offset
= cfun
->machine
->frame
.fp_sp_offset
;
7439 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
7440 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
7442 /* We can only wrap FP registers with imm12 offsets. For large
7443 offsets a pseudo register might be needed which cannot be
7444 created during the shrink wrapping pass. */
7445 if (IMM12_OPERAND (offset
))
7446 bitmap_set_bit (components
, regno
);
7448 offset
-= UNITS_PER_FPREG
;
7451 /* Don't mess with the hard frame pointer. */
7452 if (frame_pointer_needed
)
7453 bitmap_clear_bit (components
, HARD_FRAME_POINTER_REGNUM
);
7455 bitmap_clear_bit (components
, RETURN_ADDR_REGNUM
);
7461 loongarch_components_for_bb (basic_block bb
)
7463 /* Registers are used in a bb if they are in the IN, GEN, or KILL sets. */
7465 bitmap_copy (used
, DF_LIVE_IN (bb
));
7466 bitmap_ior_into (used
, &DF_LIVE_BB_INFO (bb
)->gen
);
7467 bitmap_ior_into (used
, &DF_LIVE_BB_INFO (bb
)->kill
);
7469 sbitmap components
= sbitmap_alloc (FIRST_PSEUDO_REGISTER
);
7470 bitmap_clear (components
);
7472 function_abi_aggregator callee_abis
;
7474 FOR_BB_INSNS (bb
, insn
)
7476 callee_abis
.note_callee_abi (insn_callee_abi (insn
));
7478 HARD_REG_SET extra_caller_saves
=
7479 callee_abis
.caller_save_regs (*crtl
->abi
);
7481 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
7482 if (!fixed_regs
[regno
]
7483 && !crtl
->abi
->clobbers_full_reg_p (regno
)
7484 && (TEST_HARD_REG_BIT (extra_caller_saves
, regno
) ||
7485 bitmap_bit_p (used
, regno
)))
7486 bitmap_set_bit (components
, regno
);
7488 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
7489 if (!fixed_regs
[regno
]
7490 && !crtl
->abi
->clobbers_full_reg_p (regno
)
7491 && (TEST_HARD_REG_BIT (extra_caller_saves
, regno
) ||
7492 bitmap_bit_p (used
, regno
)))
7493 bitmap_set_bit (components
, regno
);
7499 loongarch_disqualify_components (sbitmap
, edge
, sbitmap
, bool)
7505 loongarch_process_components (sbitmap components
, loongarch_save_restore_fn fn
)
7507 HOST_WIDE_INT offset
= cfun
->machine
->frame
.gp_sp_offset
;
7509 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
7510 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
7512 if (bitmap_bit_p (components
, regno
))
7513 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
7515 offset
-= UNITS_PER_WORD
;
7518 offset
= cfun
->machine
->frame
.fp_sp_offset
;
7519 machine_mode mode
= TARGET_DOUBLE_FLOAT
? DFmode
: SFmode
;
7521 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
7522 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
7524 if (bitmap_bit_p (components
, regno
))
7525 loongarch_save_restore_reg (mode
, regno
, offset
, fn
);
7527 offset
-= UNITS_PER_FPREG
;
7532 loongarch_emit_prologue_components (sbitmap components
)
7534 loongarch_process_components (components
, loongarch_save_reg
);
7538 loongarch_emit_epilogue_components (sbitmap components
)
7540 loongarch_process_components (components
, loongarch_restore_reg
);
7544 loongarch_set_handled_components (sbitmap components
)
7546 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
7547 if (bitmap_bit_p (components
, regno
))
7548 cfun
->machine
->reg_is_wrapped_separately
[regno
] = true;
7550 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
7551 if (bitmap_bit_p (components
, regno
))
7552 cfun
->machine
->reg_is_wrapped_separately
[regno
] = true;
7555 /* Initialize the GCC target structure. */
7556 #undef TARGET_ASM_ALIGNED_HI_OP
7557 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
7558 #undef TARGET_ASM_ALIGNED_SI_OP
7559 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
7560 #undef TARGET_ASM_ALIGNED_DI_OP
7561 #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
7562 /* Construct (set target (vec_select op0 (parallel selector))) and
7563 return true if that's a valid instruction in the active ISA. */
7566 loongarch_expand_lsx_shuffle (struct expand_vec_perm_d
*d
)
7568 rtx x
, elts
[MAX_VECT_LEN
];
7576 for (i
= 0; i
< d
->nelt
; i
++)
7577 elts
[i
] = GEN_INT (d
->perm
[i
]);
7579 v
= gen_rtvec_v (d
->nelt
, elts
);
7580 x
= gen_rtx_PARALLEL (VOIDmode
, v
);
7582 if (!loongarch_const_vector_shuffle_set_p (x
, d
->vmode
))
7585 x
= gen_rtx_VEC_SELECT (d
->vmode
, d
->op0
, x
);
7586 x
= gen_rtx_SET (d
->target
, x
);
7588 insn
= emit_insn (x
);
7589 if (recog_memoized (insn
) < 0)
7598 loongarch_expand_vec_perm (rtx target
, rtx op0
, rtx op1
, rtx sel
)
7600 machine_mode vmode
= GET_MODE (target
);
7605 emit_insn (gen_lsx_vshuf_b (target
, op1
, op0
, sel
));
7608 emit_insn (gen_lsx_vshuf_d_f (target
, sel
, op1
, op0
));
7611 emit_insn (gen_lsx_vshuf_d (target
, sel
, op1
, op0
));
7614 emit_insn (gen_lsx_vshuf_w_f (target
, sel
, op1
, op0
));
7617 emit_insn (gen_lsx_vshuf_w (target
, sel
, op1
, op0
));
7620 emit_insn (gen_lsx_vshuf_h (target
, sel
, op1
, op0
));
7628 loongarch_try_expand_lsx_vshuf_const (struct expand_vec_perm_d
*d
)
7631 rtx target
, op0
, op1
, sel
, tmp
;
7632 rtx rperm
[MAX_VECT_LEN
];
7634 if (d
->vmode
== E_V2DImode
|| d
->vmode
== E_V2DFmode
7635 || d
->vmode
== E_V4SImode
|| d
->vmode
== E_V4SFmode
7636 || d
->vmode
== E_V8HImode
|| d
->vmode
== E_V16QImode
)
7640 op1
= d
->one_vector_p
? d
->op0
: d
->op1
;
7642 if (GET_MODE (op0
) != GET_MODE (op1
)
7643 || GET_MODE (op0
) != GET_MODE (target
))
7649 for (i
= 0; i
< d
->nelt
; i
+= 1)
7651 rperm
[i
] = GEN_INT (d
->perm
[i
]);
7654 if (d
->vmode
== E_V2DFmode
)
7656 sel
= gen_rtx_CONST_VECTOR (E_V2DImode
, gen_rtvec_v (d
->nelt
, rperm
));
7657 tmp
= gen_rtx_SUBREG (E_V2DImode
, d
->target
, 0);
7658 emit_move_insn (tmp
, sel
);
7660 else if (d
->vmode
== E_V4SFmode
)
7662 sel
= gen_rtx_CONST_VECTOR (E_V4SImode
, gen_rtvec_v (d
->nelt
, rperm
));
7663 tmp
= gen_rtx_SUBREG (E_V4SImode
, d
->target
, 0);
7664 emit_move_insn (tmp
, sel
);
7668 sel
= gen_rtx_CONST_VECTOR (d
->vmode
, gen_rtvec_v (d
->nelt
, rperm
));
7669 emit_move_insn (d
->target
, sel
);
7675 emit_insn (gen_lsx_vshuf_d_f (target
, target
, op1
, op0
));
7678 emit_insn (gen_lsx_vshuf_d (target
, target
, op1
, op0
));
7681 emit_insn (gen_lsx_vshuf_w_f (target
, target
, op1
, op0
));
7684 emit_insn (gen_lsx_vshuf_w (target
, target
, op1
, op0
));
7687 emit_insn (gen_lsx_vshuf_h (target
, target
, op1
, op0
));
7690 emit_insn (gen_lsx_vshuf_b (target
, op1
, op0
, target
));
7702 loongarch_expand_vec_perm_const_1 (struct expand_vec_perm_d
*d
)
7704 unsigned int i
, nelt
= d
->nelt
;
7705 unsigned char perm2
[MAX_VECT_LEN
];
7707 if (d
->one_vector_p
)
7709 /* Try interleave with alternating operands. */
7710 memcpy (perm2
, d
->perm
, sizeof (perm2
));
7711 for (i
= 1; i
< nelt
; i
+= 2)
7713 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op0
, d
->op1
, perm2
,
7719 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op0
, d
->op1
,
7723 /* Try again with swapped operands. */
7724 for (i
= 0; i
< nelt
; ++i
)
7725 perm2
[i
] = (d
->perm
[i
] + nelt
) & (2 * nelt
- 1);
7726 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op1
, d
->op0
, perm2
,
7731 if (loongarch_expand_lsx_shuffle (d
))
7736 /* Implementation of constant vector permuatation. This function identifies
7737 * recognized pattern of permuation selector argument, and use one or more
7738 * instruction(s) to finish the permutation job correctly. For unsupported
7739 * patterns, it will return false. */
7742 loongarch_expand_vec_perm_const_2 (struct expand_vec_perm_d
*d
)
7744 /* Although we have the LSX vec_perm<mode> template, there's still some
7745 128bit vector permuatation operations send to vectorize_vec_perm_const.
7746 In this case, we just simpliy wrap them by single vshuf.* instruction,
7747 because LSX vshuf.* instruction just have the same behavior that GCC
7749 return loongarch_try_expand_lsx_vshuf_const (d
);
7752 /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */
7755 loongarch_vectorize_vec_perm_const (machine_mode vmode
, machine_mode op_mode
,
7756 rtx target
, rtx op0
, rtx op1
,
7757 const vec_perm_indices
&sel
)
7759 if (vmode
!= op_mode
)
7762 struct expand_vec_perm_d d
;
7764 unsigned char orig_perm
[MAX_VECT_LEN
];
7770 rtx nop0
= force_reg (vmode
, op0
);
7776 op1
= force_reg (vmode
, op1
);
7781 gcc_assert (VECTOR_MODE_P (vmode
));
7782 d
.nelt
= nelt
= GET_MODE_NUNITS (vmode
);
7783 d
.testing_p
= !target
;
7785 /* This is overly conservative, but ensures we don't get an
7786 uninitialized warning on ORIG_PERM. */
7787 memset (orig_perm
, 0, MAX_VECT_LEN
);
7788 for (i
= which
= 0; i
< nelt
; ++i
)
7790 int ei
= sel
[i
] & (2 * nelt
- 1);
7791 which
|= (ei
< nelt
? 1 : 2);
7794 memcpy (d
.perm
, orig_perm
, MAX_VECT_LEN
);
7802 d
.one_vector_p
= false;
7803 if (d
.testing_p
|| !rtx_equal_p (d
.op0
, d
.op1
))
7808 for (i
= 0; i
< nelt
; ++i
)
7809 d
.perm
[i
] &= nelt
- 1;
7811 d
.one_vector_p
= true;
7816 d
.one_vector_p
= true;
7822 d
.target
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 1);
7823 d
.op1
= d
.op0
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 2);
7824 if (!d
.one_vector_p
)
7825 d
.op1
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 3);
7827 ok
= loongarch_expand_vec_perm_const_2 (&d
);
7832 ok
= loongarch_expand_vec_perm_const_1 (&d
);
7837 ok
= loongarch_expand_vec_perm_const_2 (&d
);
7839 ok
= loongarch_expand_vec_perm_const_1 (&d
);
7841 /* If we were given a two-vector permutation which just happened to
7842 have both input vectors equal, we folded this into a one-vector
7843 permutation. There are several loongson patterns that are matched
7844 via direct vec_select+vec_concat expansion, but we do not have
7845 support in loongarch_expand_vec_perm_const_1 to guess the adjustment
7846 that should be made for a single operand. Just try again with
7847 the original permutation. */
7848 if (!ok
&& which
== 3)
7852 d
.one_vector_p
= false;
7853 memcpy (d
.perm
, orig_perm
, MAX_VECT_LEN
);
7854 ok
= loongarch_expand_vec_perm_const_1 (&d
);
7861 loongarch_cpu_sched_reassociation_width (struct loongarch_target
*target
,
7862 unsigned int opc
, machine_mode mode
)
7864 /* unreferenced argument */
7867 switch (target
->cpu_tune
)
7869 case CPU_LOONGARCH64
:
7872 if (LSX_SUPPORTED_MODE_P (mode
))
7874 /* Integer vector instructions execute in FP unit.
7875 The width of integer/float-point vector instructions is 3. */
7880 else if (INTEGRAL_MODE_P (mode
))
7882 else if (FLOAT_MODE_P (mode
))
7884 if (opc
== PLUS_EXPR
)
7899 /* Implement TARGET_SCHED_REASSOCIATION_WIDTH. */
7902 loongarch_sched_reassociation_width (unsigned int opc
, machine_mode mode
)
7904 return loongarch_cpu_sched_reassociation_width (&la_target
, opc
, mode
);
7907 /* Implement extract a scalar element from vecotr register */
7910 loongarch_expand_vector_extract (rtx target
, rtx vec
, int elt
)
7912 machine_mode mode
= GET_MODE (vec
);
7913 machine_mode inner_mode
= GET_MODE_INNER (mode
);
7926 tmp
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (1, GEN_INT (elt
)));
7927 tmp
= gen_rtx_VEC_SELECT (inner_mode
, vec
, tmp
);
7929 /* Let the rtl optimizers know about the zero extension performed. */
7930 if (inner_mode
== QImode
|| inner_mode
== HImode
)
7932 tmp
= gen_rtx_ZERO_EXTEND (SImode
, tmp
);
7933 target
= gen_lowpart (SImode
, target
);
7935 if (inner_mode
== SImode
|| inner_mode
== DImode
)
7937 tmp
= gen_rtx_SIGN_EXTEND (inner_mode
, tmp
);
7940 emit_insn (gen_rtx_SET (target
, tmp
));
7943 /* Generate code to copy vector bits i / 2 ... i - 1 from vector SRC
7944 to bits 0 ... i / 2 - 1 of vector DEST, which has the same mode.
7945 The upper bits of DEST are undefined, though they shouldn't cause
7946 exceptions (some bits from src or all zeros are ok). */
7949 emit_reduc_half (rtx dest
, rtx src
, int i
)
7952 switch (GET_MODE (src
))
7955 tem
= gen_lsx_vbsrl_w_f (dest
, src
, GEN_INT (i
== 128 ? 8 : 4));
7958 tem
= gen_lsx_vbsrl_d_f (dest
, src
, GEN_INT (8));
7964 d
= gen_reg_rtx (V2DImode
);
7965 tem
= gen_lsx_vbsrl_d (d
, gen_lowpart (V2DImode
, src
), GEN_INT (i
/16));
7972 emit_move_insn (dest
, gen_lowpart (GET_MODE (dest
), d
));
7975 /* Expand a vector reduction. FN is the binary pattern to reduce;
7976 DEST is the destination; IN is the input vector. */
7979 loongarch_expand_vector_reduc (rtx (*fn
) (rtx
, rtx
, rtx
), rtx dest
, rtx in
)
7981 rtx half
, dst
, vec
= in
;
7982 machine_mode mode
= GET_MODE (in
);
7985 for (i
= GET_MODE_BITSIZE (mode
);
7986 i
> GET_MODE_UNIT_BITSIZE (mode
);
7989 half
= gen_reg_rtx (mode
);
7990 emit_reduc_half (half
, vec
, i
);
7991 if (i
== GET_MODE_UNIT_BITSIZE (mode
) * 2)
7994 dst
= gen_reg_rtx (mode
);
7995 emit_insn (fn (dst
, half
, vec
));
8000 /* Expand an integral vector unpack operation. */
8003 loongarch_expand_vec_unpack (rtx operands
[2], bool unsigned_p
, bool high_p
)
8005 machine_mode imode
= GET_MODE (operands
[1]);
8006 rtx (*unpack
) (rtx
, rtx
, rtx
);
8007 rtx (*cmpFunc
) (rtx
, rtx
, rtx
);
8016 unpack
= gen_lsx_vilvh_w
;
8018 unpack
= gen_lsx_vilvl_w
;
8020 cmpFunc
= gen_lsx_vslt_w
;
8025 unpack
= gen_lsx_vilvh_h
;
8027 unpack
= gen_lsx_vilvl_h
;
8029 cmpFunc
= gen_lsx_vslt_h
;
8034 unpack
= gen_lsx_vilvh_b
;
8036 unpack
= gen_lsx_vilvl_b
;
8038 cmpFunc
= gen_lsx_vslt_b
;
8048 /* Extract sign extention for each element comparing each element
8049 with immediate zero. */
8050 tmp
= gen_reg_rtx (imode
);
8051 emit_insn (cmpFunc (tmp
, operands
[1], CONST0_RTX (imode
)));
8054 tmp
= force_reg (imode
, CONST0_RTX (imode
));
8056 dest
= gen_reg_rtx (imode
);
8058 emit_insn (unpack (dest
, operands
[1], tmp
));
8059 emit_move_insn (operands
[0], gen_lowpart (GET_MODE (operands
[0]), dest
));
8065 /* Construct and return PARALLEL RTX with CONST_INTs for HIGH (high_p == TRUE)
8066 or LOW (high_p == FALSE) half of a vector for mode MODE. */
8069 loongarch_lsx_vec_parallel_const_half (machine_mode mode
, bool high_p
)
8071 int nunits
= GET_MODE_NUNITS (mode
);
8072 rtvec v
= rtvec_alloc (nunits
/ 2);
8076 base
= high_p
? nunits
/ 2 : 0;
8078 for (i
= 0; i
< nunits
/ 2; i
++)
8079 RTVEC_ELT (v
, i
) = GEN_INT (base
+ i
);
8081 return gen_rtx_PARALLEL (VOIDmode
, v
);
8084 /* A subroutine of loongarch_expand_vec_init, match constant vector
8088 loongarch_constant_elt_p (rtx x
)
8090 return CONST_INT_P (x
) || GET_CODE (x
) == CONST_DOUBLE
;
8094 loongarch_gen_const_int_vector_shuffle (machine_mode mode
, int val
)
8096 int nunits
= GET_MODE_NUNITS (mode
);
8097 int nsets
= nunits
/ 4;
8098 rtx elts
[MAX_VECT_LEN
];
8102 /* Generate a const_int vector replicating the same 4-element set
8103 from an immediate. */
8104 for (j
= 0; j
< nsets
; j
++, set
= 4 * j
)
8105 for (i
= 0; i
< 4; i
++)
8106 elts
[set
+ i
] = GEN_INT (set
+ ((val
>> (2 * i
)) & 0x3));
8108 return gen_rtx_PARALLEL (VOIDmode
, gen_rtvec_v (nunits
, elts
));
8111 /* Expand a vector initialization. */
8114 loongarch_expand_vector_init (rtx target
, rtx vals
)
8116 machine_mode vmode
= GET_MODE (target
);
8117 machine_mode imode
= GET_MODE_INNER (vmode
);
8118 unsigned i
, nelt
= GET_MODE_NUNITS (vmode
);
8120 bool all_same
= true;
8123 for (i
= 0; i
< nelt
; ++i
)
8125 x
= XVECEXP (vals
, 0, i
);
8126 if (!loongarch_constant_elt_p (x
))
8128 if (i
> 0 && !rtx_equal_p (x
, XVECEXP (vals
, 0, 0)))
8136 rtx same
= XVECEXP (vals
, 0, 0);
8139 if (CONST_INT_P (same
) && nvar
== 0
8140 && loongarch_signed_immediate_p (INTVAL (same
), 10, 0))
8148 temp
= gen_rtx_CONST_VECTOR (vmode
, XVEC (vals
, 0));
8149 emit_move_insn (target
, temp
);
8156 temp
= gen_reg_rtx (imode
);
8157 if (imode
== GET_MODE (same
))
8159 else if (GET_MODE_SIZE (imode
) >= UNITS_PER_WORD
)
8161 if (GET_CODE (same
) == MEM
)
8163 rtx reg_tmp
= gen_reg_rtx (GET_MODE (same
));
8164 loongarch_emit_move (reg_tmp
, same
);
8165 temp2
= simplify_gen_subreg (imode
, reg_tmp
,
8166 GET_MODE (reg_tmp
), 0);
8169 temp2
= simplify_gen_subreg (imode
, same
, GET_MODE (same
), 0);
8173 if (GET_CODE (same
) == MEM
)
8175 rtx reg_tmp
= gen_reg_rtx (GET_MODE (same
));
8176 loongarch_emit_move (reg_tmp
, same
);
8177 temp2
= lowpart_subreg (imode
, reg_tmp
, GET_MODE (reg_tmp
));
8180 temp2
= lowpart_subreg (imode
, same
, GET_MODE (same
));
8182 emit_move_insn (temp
, temp2
);
8190 loongarch_emit_move (target
, gen_rtx_VEC_DUPLICATE (vmode
, temp
));
8194 emit_insn (gen_lsx_vreplvei_w_f_scalar (target
, temp
));
8198 emit_insn (gen_lsx_vreplvei_d_f_scalar (target
, temp
));
8207 emit_move_insn (target
, CONST0_RTX (vmode
));
8209 for (i
= 0; i
< nelt
; ++i
)
8211 rtx temp
= gen_reg_rtx (imode
);
8212 emit_move_insn (temp
, XVECEXP (vals
, 0, i
));
8217 emit_insn (gen_lsx_vreplvei_b_scalar (target
, temp
));
8219 emit_insn (gen_vec_setv16qi (target
, temp
, GEN_INT (i
)));
8224 emit_insn (gen_lsx_vreplvei_h_scalar (target
, temp
));
8226 emit_insn (gen_vec_setv8hi (target
, temp
, GEN_INT (i
)));
8231 emit_insn (gen_lsx_vreplvei_w_scalar (target
, temp
));
8233 emit_insn (gen_vec_setv4si (target
, temp
, GEN_INT (i
)));
8238 emit_insn (gen_lsx_vreplvei_d_scalar (target
, temp
));
8240 emit_insn (gen_vec_setv2di (target
, temp
, GEN_INT (i
)));
8245 emit_insn (gen_lsx_vreplvei_w_f_scalar (target
, temp
));
8247 emit_insn (gen_vec_setv4sf (target
, temp
, GEN_INT (i
)));
8252 emit_insn (gen_lsx_vreplvei_d_f_scalar (target
, temp
));
8254 emit_insn (gen_vec_setv2df (target
, temp
, GEN_INT (i
)));
8265 /* Load constants from the pool, or whatever's handy. */
8268 emit_move_insn (target
, gen_rtx_CONST_VECTOR (vmode
, XVEC (vals
, 0)));
8272 /* For two-part initialization, always use CONCAT. */
8275 rtx op0
= force_reg (imode
, XVECEXP (vals
, 0, 0));
8276 rtx op1
= force_reg (imode
, XVECEXP (vals
, 0, 1));
8277 x
= gen_rtx_VEC_CONCAT (vmode
, op0
, op1
);
8278 emit_insn (gen_rtx_SET (target
, x
));
8282 /* Loongson is the only cpu with vectors with more elements. */
8286 /* Implement HARD_REGNO_CALLER_SAVE_MODE. */
8289 loongarch_hard_regno_caller_save_mode (unsigned int regno
, unsigned int nregs
,
8292 /* For performance, avoid saving/restoring upper parts of a register
8293 by returning MODE as save mode when the mode is known. */
8294 if (mode
== VOIDmode
)
8295 return choose_hard_reg_mode (regno
, nregs
, NULL
);
8300 /* Generate RTL for comparing CMP_OP0 and CMP_OP1 using condition COND and
8301 store the result -1 or 0 in DEST. */
8304 loongarch_expand_lsx_cmp (rtx dest
, enum rtx_code cond
, rtx op0
, rtx op1
)
8306 machine_mode cmp_mode
= GET_MODE (op0
);
8308 bool negate
= false;
8323 cond
= reverse_condition (cond
);
8336 std::swap (op0
, op1
);
8337 cond
= swap_condition (cond
);
8342 loongarch_emit_binary (cond
, dest
, op0
, op1
);
8344 emit_move_insn (dest
, gen_rtx_NOT (GET_MODE (dest
), dest
));
8359 case LTGT
: cond
= NE
; break;
8360 case UNGE
: cond
= UNLE
; std::swap (op0
, op1
); break;
8361 case UNGT
: cond
= UNLT
; std::swap (op0
, op1
); break;
8362 case LE
: unspec
= UNSPEC_LSX_VFCMP_SLE
; break;
8363 case LT
: unspec
= UNSPEC_LSX_VFCMP_SLT
; break;
8364 case GE
: unspec
= UNSPEC_LSX_VFCMP_SLE
; std::swap (op0
, op1
); break;
8365 case GT
: unspec
= UNSPEC_LSX_VFCMP_SLT
; std::swap (op0
, op1
); break;
8370 loongarch_emit_binary (cond
, dest
, op0
, op1
);
8373 rtx x
= gen_rtx_UNSPEC (GET_MODE (dest
),
8374 gen_rtvec (2, op0
, op1
), unspec
);
8375 emit_insn (gen_rtx_SET (dest
, x
));
8385 /* Expand VEC_COND_EXPR, where:
8386 MODE is mode of the result
8387 VIMODE equivalent integer mode
8388 OPERANDS operands of VEC_COND_EXPR. */
8391 loongarch_expand_vec_cond_expr (machine_mode mode
, machine_mode vimode
,
8394 rtx cond
= operands
[3];
8395 rtx cmp_op0
= operands
[4];
8396 rtx cmp_op1
= operands
[5];
8397 rtx cmp_res
= gen_reg_rtx (vimode
);
8399 loongarch_expand_lsx_cmp (cmp_res
, GET_CODE (cond
), cmp_op0
, cmp_op1
);
8401 /* We handle the following cases:
8402 1) r = a CMP b ? -1 : 0
8403 2) r = a CMP b ? -1 : v
8404 3) r = a CMP b ? v : 0
8405 4) r = a CMP b ? v1 : v2 */
8407 /* Case (1) above. We only move the results. */
8408 if (operands
[1] == CONSTM1_RTX (vimode
)
8409 && operands
[2] == CONST0_RTX (vimode
))
8410 emit_move_insn (operands
[0], cmp_res
);
8413 rtx src1
= gen_reg_rtx (vimode
);
8414 rtx src2
= gen_reg_rtx (vimode
);
8415 rtx mask
= gen_reg_rtx (vimode
);
8418 /* Move the vector result to use it as a mask. */
8419 emit_move_insn (mask
, cmp_res
);
8421 if (register_operand (operands
[1], mode
))
8423 rtx xop1
= operands
[1];
8426 xop1
= gen_reg_rtx (vimode
);
8427 emit_move_insn (xop1
, gen_rtx_SUBREG (vimode
, operands
[1], 0));
8429 emit_move_insn (src1
, xop1
);
8433 gcc_assert (operands
[1] == CONSTM1_RTX (vimode
));
8434 /* Case (2) if the below doesn't move the mask to src2. */
8435 emit_move_insn (src1
, mask
);
8438 if (register_operand (operands
[2], mode
))
8440 rtx xop2
= operands
[2];
8443 xop2
= gen_reg_rtx (vimode
);
8444 emit_move_insn (xop2
, gen_rtx_SUBREG (vimode
, operands
[2], 0));
8446 emit_move_insn (src2
, xop2
);
8450 gcc_assert (operands
[2] == CONST0_RTX (mode
));
8451 /* Case (3) if the above didn't move the mask to src1. */
8452 emit_move_insn (src2
, mask
);
8455 /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
8456 In any case, we eventually do vector mask-based copy. */
8457 bsel
= gen_rtx_IOR (vimode
,
8458 gen_rtx_AND (vimode
,
8459 gen_rtx_NOT (vimode
, mask
), src2
),
8460 gen_rtx_AND (vimode
, mask
, src1
));
8461 /* The result is placed back to a register with the mask. */
8462 emit_insn (gen_rtx_SET (mask
, bsel
));
8463 emit_move_insn (operands
[0], gen_rtx_SUBREG (mode
, mask
, 0));
8468 loongarch_expand_vec_cond_mask_expr (machine_mode mode
, machine_mode vimode
,
8471 rtx cmp_res
= operands
[3];
8473 /* We handle the following cases:
8474 1) r = a CMP b ? -1 : 0
8475 2) r = a CMP b ? -1 : v
8476 3) r = a CMP b ? v : 0
8477 4) r = a CMP b ? v1 : v2 */
8479 /* Case (1) above. We only move the results. */
8480 if (operands
[1] == CONSTM1_RTX (vimode
)
8481 && operands
[2] == CONST0_RTX (vimode
))
8482 emit_move_insn (operands
[0], cmp_res
);
8485 rtx src1
= gen_reg_rtx (vimode
);
8486 rtx src2
= gen_reg_rtx (vimode
);
8487 rtx mask
= gen_reg_rtx (vimode
);
8490 /* Move the vector result to use it as a mask. */
8491 emit_move_insn (mask
, cmp_res
);
8493 if (register_operand (operands
[1], mode
))
8495 rtx xop1
= operands
[1];
8498 xop1
= gen_reg_rtx (vimode
);
8499 emit_move_insn (xop1
, gen_rtx_SUBREG (vimode
, operands
[1], 0));
8501 emit_move_insn (src1
, xop1
);
8505 gcc_assert (operands
[1] == CONSTM1_RTX (vimode
));
8506 /* Case (2) if the below doesn't move the mask to src2. */
8507 emit_move_insn (src1
, mask
);
8510 if (register_operand (operands
[2], mode
))
8512 rtx xop2
= operands
[2];
8515 xop2
= gen_reg_rtx (vimode
);
8516 emit_move_insn (xop2
, gen_rtx_SUBREG (vimode
, operands
[2], 0));
8518 emit_move_insn (src2
, xop2
);
8522 gcc_assert (operands
[2] == CONST0_RTX (mode
));
8523 /* Case (3) if the above didn't move the mask to src1. */
8524 emit_move_insn (src2
, mask
);
8527 /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
8528 In any case, we eventually do vector mask-based copy. */
8529 bsel
= gen_rtx_IOR (vimode
,
8530 gen_rtx_AND (vimode
,
8531 gen_rtx_NOT (vimode
, mask
), src2
),
8532 gen_rtx_AND (vimode
, mask
, src1
));
8533 /* The result is placed back to a register with the mask. */
8534 emit_insn (gen_rtx_SET (mask
, bsel
));
8535 emit_move_insn (operands
[0], gen_rtx_SUBREG (mode
, mask
, 0));
8539 /* Expand integer vector comparison */
8541 loongarch_expand_vec_cmp (rtx operands
[])
8544 rtx_code code
= GET_CODE (operands
[1]);
8545 loongarch_expand_lsx_cmp (operands
[0], code
, operands
[2], operands
[3]);
8549 /* Implement TARGET_CASE_VALUES_THRESHOLD. */
8552 loongarch_case_values_threshold (void)
8554 return default_case_values_threshold ();
8557 /* Implement TARGET_SPILL_CLASS. */
8560 loongarch_spill_class (reg_class_t rclass ATTRIBUTE_UNUSED
,
8561 machine_mode mode ATTRIBUTE_UNUSED
)
8566 /* Implement TARGET_PROMOTE_FUNCTION_MODE. */
8568 /* This function is equivalent to default_promote_function_mode_always_promote
8569 except that it returns a promoted mode even if type is NULL_TREE. This is
8570 needed by libcalls which have no type (only a mode) such as fixed conversion
8571 routines that take a signed or unsigned char/short argument and convert it
8575 loongarch_promote_function_mode (const_tree type ATTRIBUTE_UNUSED
,
8577 int *punsignedp ATTRIBUTE_UNUSED
,
8578 const_tree fntype ATTRIBUTE_UNUSED
,
8579 int for_return ATTRIBUTE_UNUSED
)
8583 if (type
!= NULL_TREE
)
8584 return promote_mode (type
, mode
, punsignedp
);
8586 unsignedp
= *punsignedp
;
8587 PROMOTE_MODE (mode
, unsignedp
, type
);
8588 *punsignedp
= unsignedp
;
8592 /* Implement TARGET_STARTING_FRAME_OFFSET. See loongarch_compute_frame_info
8593 for details about the frame layout. */
8595 static HOST_WIDE_INT
8596 loongarch_starting_frame_offset (void)
8598 if (FRAME_GROWS_DOWNWARD
)
8600 return crtl
->outgoing_args_size
;
8603 /* A subroutine of loongarch_build_signbit_mask. If VECT is true,
8604 then replicate the value for all elements of the vector
8608 loongarch_build_const_vector (machine_mode mode
, bool vect
, rtx value
)
8612 machine_mode scalar_mode
;
8633 n_elt
= GET_MODE_NUNITS (mode
);
8634 v
= rtvec_alloc (n_elt
);
8635 scalar_mode
= GET_MODE_INNER (mode
);
8637 RTVEC_ELT (v
, 0) = value
;
8639 for (i
= 1; i
< n_elt
; ++i
)
8640 RTVEC_ELT (v
, i
) = vect
? value
: CONST0_RTX (scalar_mode
);
8642 return gen_rtx_CONST_VECTOR (mode
, v
);
8649 /* Create a mask for the sign bit in MODE
8650 for an register. If VECT is true, then replicate the mask for
8651 all elements of the vector register. If INVERT is true, then create
8652 a mask excluding the sign bit. */
8655 loongarch_build_signbit_mask (machine_mode mode
, bool vect
, bool invert
)
8657 machine_mode vec_mode
, imode
;
8685 vec_mode
= VOIDmode
;
8693 machine_mode inner_mode
= GET_MODE_INNER (mode
);
8694 w
= wi::set_bit_in_zero (GET_MODE_BITSIZE (inner_mode
) - 1,
8695 GET_MODE_BITSIZE (inner_mode
));
8697 w
= wi::bit_not (w
);
8699 /* Force this value into the low part of a fp vector constant. */
8700 mask
= immed_wide_int_const (w
, imode
);
8701 mask
= gen_lowpart (inner_mode
, mask
);
8703 if (vec_mode
== VOIDmode
)
8704 return force_reg (inner_mode
, mask
);
8706 v
= loongarch_build_const_vector (vec_mode
, vect
, mask
);
8707 return force_reg (vec_mode
, v
);
8711 loongarch_builtin_support_vector_misalignment (machine_mode mode
,
8716 if (ISA_HAS_LSX
&& STRICT_ALIGNMENT
)
8718 if (optab_handler (movmisalign_optab
, mode
) == CODE_FOR_nothing
)
8720 if (misalignment
== -1)
8723 return default_builtin_support_vector_misalignment (mode
, type
, misalignment
,
8727 /* Initialize the GCC target structure. */
8728 #undef TARGET_ASM_ALIGNED_HI_OP
8729 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
8730 #undef TARGET_ASM_ALIGNED_SI_OP
8731 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
8732 #undef TARGET_ASM_ALIGNED_DI_OP
8733 #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
8735 #undef TARGET_OPTION_OVERRIDE
8736 #define TARGET_OPTION_OVERRIDE loongarch_option_override
8738 #undef TARGET_LEGITIMIZE_ADDRESS
8739 #define TARGET_LEGITIMIZE_ADDRESS loongarch_legitimize_address
8741 #undef TARGET_ASM_SELECT_RTX_SECTION
8742 #define TARGET_ASM_SELECT_RTX_SECTION loongarch_select_rtx_section
8743 #undef TARGET_ASM_FUNCTION_RODATA_SECTION
8744 #define TARGET_ASM_FUNCTION_RODATA_SECTION loongarch_function_rodata_section
8746 #undef TARGET_SCHED_INIT
8747 #define TARGET_SCHED_INIT loongarch_sched_init
8748 #undef TARGET_SCHED_REORDER
8749 #define TARGET_SCHED_REORDER loongarch_sched_reorder
8750 #undef TARGET_SCHED_REORDER2
8751 #define TARGET_SCHED_REORDER2 loongarch_sched_reorder2
8752 #undef TARGET_SCHED_VARIABLE_ISSUE
8753 #define TARGET_SCHED_VARIABLE_ISSUE loongarch_variable_issue
8754 #undef TARGET_SCHED_ADJUST_COST
8755 #define TARGET_SCHED_ADJUST_COST loongarch_adjust_cost
8756 #undef TARGET_SCHED_ISSUE_RATE
8757 #define TARGET_SCHED_ISSUE_RATE loongarch_issue_rate
8758 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
8759 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
8760 loongarch_multipass_dfa_lookahead
8762 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
8763 #define TARGET_FUNCTION_OK_FOR_SIBCALL loongarch_function_ok_for_sibcall
8765 #undef TARGET_VALID_POINTER_MODE
8766 #define TARGET_VALID_POINTER_MODE loongarch_valid_pointer_mode
8767 #undef TARGET_REGISTER_MOVE_COST
8768 #define TARGET_REGISTER_MOVE_COST loongarch_register_move_cost
8769 #undef TARGET_MEMORY_MOVE_COST
8770 #define TARGET_MEMORY_MOVE_COST loongarch_memory_move_cost
8771 #undef TARGET_RTX_COSTS
8772 #define TARGET_RTX_COSTS loongarch_rtx_costs
8773 #undef TARGET_ADDRESS_COST
8774 #define TARGET_ADDRESS_COST loongarch_address_cost
8775 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
8776 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \
8777 loongarch_builtin_vectorization_cost
8780 #undef TARGET_IN_SMALL_DATA_P
8781 #define TARGET_IN_SMALL_DATA_P loongarch_in_small_data_p
8783 #undef TARGET_PREFERRED_RELOAD_CLASS
8784 #define TARGET_PREFERRED_RELOAD_CLASS loongarch_preferred_reload_class
8786 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
8787 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
8789 #undef TARGET_EXPAND_BUILTIN_VA_START
8790 #define TARGET_EXPAND_BUILTIN_VA_START loongarch_va_start
8792 #undef TARGET_PROMOTE_FUNCTION_MODE
8793 #define TARGET_PROMOTE_FUNCTION_MODE loongarch_promote_function_mode
8794 #undef TARGET_RETURN_IN_MEMORY
8795 #define TARGET_RETURN_IN_MEMORY loongarch_return_in_memory
8797 #undef TARGET_FUNCTION_VALUE
8798 #define TARGET_FUNCTION_VALUE loongarch_function_value
8799 #undef TARGET_LIBCALL_VALUE
8800 #define TARGET_LIBCALL_VALUE loongarch_libcall_value
8802 #undef TARGET_ASM_OUTPUT_MI_THUNK
8803 #define TARGET_ASM_OUTPUT_MI_THUNK loongarch_output_mi_thunk
8804 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
8805 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
8806 hook_bool_const_tree_hwi_hwi_const_tree_true
8808 #undef TARGET_PRINT_OPERAND
8809 #define TARGET_PRINT_OPERAND loongarch_print_operand
8810 #undef TARGET_PRINT_OPERAND_ADDRESS
8811 #define TARGET_PRINT_OPERAND_ADDRESS loongarch_print_operand_address
8812 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
8813 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P \
8814 loongarch_print_operand_punct_valid_p
8816 #undef TARGET_SETUP_INCOMING_VARARGS
8817 #define TARGET_SETUP_INCOMING_VARARGS loongarch_setup_incoming_varargs
8818 #undef TARGET_STRICT_ARGUMENT_NAMING
8819 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
8820 #undef TARGET_MUST_PASS_IN_STACK
8821 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
8822 #undef TARGET_PASS_BY_REFERENCE
8823 #define TARGET_PASS_BY_REFERENCE loongarch_pass_by_reference
8824 #undef TARGET_ARG_PARTIAL_BYTES
8825 #define TARGET_ARG_PARTIAL_BYTES loongarch_arg_partial_bytes
8826 #undef TARGET_FUNCTION_ARG
8827 #define TARGET_FUNCTION_ARG loongarch_function_arg
8828 #undef TARGET_FUNCTION_ARG_ADVANCE
8829 #define TARGET_FUNCTION_ARG_ADVANCE loongarch_function_arg_advance
8830 #undef TARGET_FUNCTION_ARG_BOUNDARY
8831 #define TARGET_FUNCTION_ARG_BOUNDARY loongarch_function_arg_boundary
8833 #undef TARGET_VECTOR_MODE_SUPPORTED_P
8834 #define TARGET_VECTOR_MODE_SUPPORTED_P loongarch_vector_mode_supported_p
8836 #undef TARGET_SCALAR_MODE_SUPPORTED_P
8837 #define TARGET_SCALAR_MODE_SUPPORTED_P loongarch_scalar_mode_supported_p
8839 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
8840 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE loongarch_preferred_simd_mode
8842 #undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
8843 #define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
8844 loongarch_autovectorize_vector_modes
8846 #undef TARGET_INIT_BUILTINS
8847 #define TARGET_INIT_BUILTINS loongarch_init_builtins
8848 #undef TARGET_BUILTIN_DECL
8849 #define TARGET_BUILTIN_DECL loongarch_builtin_decl
8850 #undef TARGET_EXPAND_BUILTIN
8851 #define TARGET_EXPAND_BUILTIN loongarch_expand_builtin
8853 /* The generic ELF target does not always have TLS support. */
8855 #undef TARGET_HAVE_TLS
8856 #define TARGET_HAVE_TLS HAVE_AS_TLS
8859 #undef TARGET_CANNOT_FORCE_CONST_MEM
8860 #define TARGET_CANNOT_FORCE_CONST_MEM loongarch_cannot_force_const_mem
8862 #undef TARGET_LEGITIMATE_CONSTANT_P
8863 #define TARGET_LEGITIMATE_CONSTANT_P loongarch_legitimate_constant_p
8865 #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
8866 #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true
8868 #ifdef HAVE_AS_DTPRELWORD
8869 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
8870 #define TARGET_ASM_OUTPUT_DWARF_DTPREL loongarch_output_dwarf_dtprel
8873 #undef TARGET_LEGITIMATE_ADDRESS_P
8874 #define TARGET_LEGITIMATE_ADDRESS_P loongarch_legitimate_address_p
8876 #undef TARGET_FRAME_POINTER_REQUIRED
8877 #define TARGET_FRAME_POINTER_REQUIRED loongarch_frame_pointer_required
8879 #undef TARGET_CAN_ELIMINATE
8880 #define TARGET_CAN_ELIMINATE loongarch_can_eliminate
8882 #undef TARGET_CONDITIONAL_REGISTER_USAGE
8883 #define TARGET_CONDITIONAL_REGISTER_USAGE loongarch_conditional_register_usage
8885 #undef TARGET_TRAMPOLINE_INIT
8886 #define TARGET_TRAMPOLINE_INIT loongarch_trampoline_init
8888 #undef TARGET_MIN_ANCHOR_OFFSET
8889 #define TARGET_MIN_ANCHOR_OFFSET (-IMM_REACH/2)
8891 #undef TARGET_MAX_ANCHOR_OFFSET
8892 #define TARGET_MAX_ANCHOR_OFFSET (IMM_REACH/2-1)
8893 #undef TARGET_VECTORIZE_VEC_PERM_CONST
8894 #define TARGET_VECTORIZE_VEC_PERM_CONST loongarch_vectorize_vec_perm_const
8896 #undef TARGET_SCHED_REASSOCIATION_WIDTH
8897 #define TARGET_SCHED_REASSOCIATION_WIDTH loongarch_sched_reassociation_width
8899 #undef TARGET_CASE_VALUES_THRESHOLD
8900 #define TARGET_CASE_VALUES_THRESHOLD loongarch_case_values_threshold
8902 #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
8903 #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV loongarch_atomic_assign_expand_fenv
8905 #undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
8906 #define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true
8908 #undef TARGET_SPILL_CLASS
8909 #define TARGET_SPILL_CLASS loongarch_spill_class
8911 #undef TARGET_HARD_REGNO_NREGS
8912 #define TARGET_HARD_REGNO_NREGS loongarch_hard_regno_nregs
8913 #undef TARGET_HARD_REGNO_MODE_OK
8914 #define TARGET_HARD_REGNO_MODE_OK loongarch_hard_regno_mode_ok
8916 #undef TARGET_MODES_TIEABLE_P
8917 #define TARGET_MODES_TIEABLE_P loongarch_modes_tieable_p
8919 #undef TARGET_HARD_REGNO_CALL_PART_CLOBBERED
8920 #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
8921 loongarch_hard_regno_call_part_clobbered
8923 #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
8924 #define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 2
8926 #undef TARGET_CAN_CHANGE_MODE_CLASS
8927 #define TARGET_CAN_CHANGE_MODE_CLASS loongarch_can_change_mode_class
8929 #undef TARGET_CONSTANT_ALIGNMENT
8930 #define TARGET_CONSTANT_ALIGNMENT loongarch_constant_alignment
8932 #undef TARGET_STARTING_FRAME_OFFSET
8933 #define TARGET_STARTING_FRAME_OFFSET loongarch_starting_frame_offset
8935 #undef TARGET_SECONDARY_RELOAD
8936 #define TARGET_SECONDARY_RELOAD loongarch_secondary_reload
8938 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
8939 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
8941 #undef TARGET_ATTRIBUTE_TABLE
8942 #define TARGET_ATTRIBUTE_TABLE loongarch_attribute_table
8944 #undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
8945 #define TARGET_USE_ANCHORS_FOR_SYMBOL_P loongarch_use_anchors_for_symbol_p
8947 #undef TARGET_ASAN_SHADOW_OFFSET
8948 #define TARGET_ASAN_SHADOW_OFFSET loongarch_asan_shadow_offset
8950 #undef TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS
8951 #define TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS \
8952 loongarch_get_separate_components
8954 #undef TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB
8955 #define TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB loongarch_components_for_bb
8957 #undef TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS
8958 #define TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS \
8959 loongarch_disqualify_components
8961 #undef TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS
8962 #define TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS \
8963 loongarch_emit_prologue_components
8965 #undef TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS
8966 #define TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS \
8967 loongarch_emit_epilogue_components
8969 #undef TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS
8970 #define TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS \
8971 loongarch_set_handled_components
8973 #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
8974 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
8975 loongarch_builtin_support_vector_misalignment
8977 struct gcc_target targetm
= TARGET_INITIALIZER
;
8979 #include "gt-loongarch.h"