1 /* Subroutines used for LoongArch code generation.
2 Copyright (C) 2021-2024 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 #include "tree-vectorizer.h"
71 /* This file should be included last. */
72 #include "target-def.h"
74 /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
75 #define UNSPEC_ADDRESS_P(X) \
76 (GET_CODE (X) == UNSPEC \
77 && XINT (X, 1) >= UNSPEC_ADDRESS_FIRST \
78 && XINT (X, 1) < UNSPEC_ADDRESS_FIRST + NUM_SYMBOL_TYPES)
80 /* Extract the symbol or label from UNSPEC wrapper X. */
81 #define UNSPEC_ADDRESS(X) XVECEXP (X, 0, 0)
83 /* Extract the symbol type from UNSPEC wrapper X. */
84 #define UNSPEC_ADDRESS_TYPE(X) \
85 ((enum loongarch_symbol_type) (XINT (X, 1) - UNSPEC_ADDRESS_FIRST))
87 /* True if INSN is a loongarch.md pattern or asm statement. */
88 /* ??? This test exists through the compiler, perhaps it should be
90 #define USEFUL_INSN_P(INSN) \
91 (NONDEBUG_INSN_P (INSN) \
92 && GET_CODE (PATTERN (INSN)) != USE \
93 && GET_CODE (PATTERN (INSN)) != CLOBBER)
95 /* True if bit BIT is set in VALUE. */
96 #define BITSET_P(VALUE, BIT) (((VALUE) & (1 << (BIT))) != 0)
98 /* Classifies an address.
101 A natural register + offset address. The register satisfies
102 loongarch_valid_base_register_p and the offset is a const_arith_operand.
105 A base register indexed by (optionally scaled) register.
108 A LO_SUM rtx. The first operand is a valid base register and the second
109 operand is a symbolic address.
112 A signed 16-bit constant address.
115 A constant symbolic address. */
116 enum loongarch_address_type
126 /* Information about an address described by loongarch_address_type. */
127 struct loongarch_address_info
129 enum loongarch_address_type type
;
132 enum loongarch_symbol_type symbol_type
;
135 /* Method of loading instant numbers:
138 Load 0-31 bit of the immediate number.
141 Load 32-51 bit of the immediate number.
144 Load 52-63 bit of the immediate number.
147 Copy 0-31 bit of the immediate number to 32-63bit.
149 enum loongarch_load_imm_method
157 struct loongarch_integer_op
161 /* Represent the result of the immediate count of the load instruction at
163 HOST_WIDE_INT curr_value
;
164 enum loongarch_load_imm_method method
;
167 /* The largest number of operations needed to load an integer constant.
168 The worst accepted case for 64-bit constants is LU12I.W,LU32I.D,LU52I.D,ORI
169 or LU12I.W,LU32I.D,LU52I.D,ADDI.D DECL_ASSEMBLER_NAME. */
170 #define LARCH_MAX_INTEGER_OPS 4
172 /* Arrays that map GCC register numbers to debugger register numbers. */
173 int loongarch_dwarf_regno
[FIRST_PSEUDO_REGISTER
];
175 /* Index [M][R] is true if register R is allowed to hold a value of mode M. */
176 static bool loongarch_hard_regno_mode_ok_p
[MAX_MACHINE_MODE
]
177 [FIRST_PSEUDO_REGISTER
];
179 /* Index C is true if character C is a valid PRINT_OPERAND punctation
181 static bool loongarch_print_operand_punct
[256];
183 /* Cached value of can_issue_more. This is cached in loongarch_variable_issue
184 hook and returned from loongarch_sched_reorder2. */
185 static int cached_can_issue_more
;
187 /* Index R is the smallest register class that contains register R. */
188 const enum reg_class loongarch_regno_to_class
[FIRST_PSEUDO_REGISTER
] = {
189 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
190 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
191 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
192 SIBCALL_REGS
, JIRL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
,
193 SIBCALL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
, SIBCALL_REGS
,
194 SIBCALL_REGS
, GR_REGS
, GR_REGS
, JIRL_REGS
,
195 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
196 JIRL_REGS
, JIRL_REGS
, JIRL_REGS
, JIRL_REGS
,
198 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
199 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
200 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
201 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
202 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
203 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
204 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
205 FP_REGS
, FP_REGS
, FP_REGS
, FP_REGS
,
206 FCC_REGS
, FCC_REGS
, FCC_REGS
, FCC_REGS
,
207 FCC_REGS
, FCC_REGS
, FCC_REGS
, FCC_REGS
,
208 FRAME_REGS
, FRAME_REGS
211 /* Which cost information to use. */
212 static const struct loongarch_rtx_cost_data
*loongarch_cost
;
214 /* Information about a single argument. */
215 struct loongarch_arg_info
217 /* True if the argument is at least partially passed on the stack. */
220 /* The number of integer registers allocated to this argument. */
221 unsigned int num_gprs
;
223 /* The offset of the first register used, provided num_gprs is nonzero.
224 If passed entirely on the stack, the value is MAX_ARGS_IN_REGISTERS. */
225 unsigned int gpr_offset
;
227 /* The number of floating-point registers allocated to this argument. */
228 unsigned int num_fprs
;
230 /* The offset of the first register used, provided num_fprs is nonzero. */
231 unsigned int fpr_offset
;
234 /* Invoke MACRO (COND) for each fcmp.cond.{s/d} condition. */
235 #define LARCH_FP_CONDITIONS(MACRO) \
253 /* Enumerates the codes above as LARCH_FP_COND_<X>. */
254 #define DECLARE_LARCH_COND(X) LARCH_FP_COND_##X
255 enum loongarch_fp_condition
257 LARCH_FP_CONDITIONS (DECLARE_LARCH_COND
)
259 #undef DECLARE_LARCH_COND
261 /* Index X provides the string representation of LARCH_FP_COND_<X>. */
262 #define STRINGIFY(X) #X
264 loongarch_fp_conditions
[16]= {LARCH_FP_CONDITIONS (STRINGIFY
)};
267 /* Size of guard page. */
268 #define STACK_CLASH_PROTECTION_GUARD_SIZE \
269 (1 << param_stack_clash_protection_guard_size)
271 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. Every parameter gets at
272 least PARM_BOUNDARY bits of alignment, but will be given anything up
273 to PREFERRED_STACK_BOUNDARY bits if the type requires it. */
276 loongarch_function_arg_boundary (machine_mode mode
, const_tree type
)
278 unsigned int alignment
;
280 /* Use natural alignment if the type is not aggregate data. */
281 if (type
&& !AGGREGATE_TYPE_P (type
))
282 alignment
= TYPE_ALIGN (TYPE_MAIN_VARIANT (type
));
284 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
286 return MIN (PREFERRED_STACK_BOUNDARY
, MAX (PARM_BOUNDARY
, alignment
));
289 /* If MODE represents an argument that can be passed or returned in
290 floating-point registers, return the number of registers, else 0. */
293 loongarch_pass_mode_in_fpr_p (machine_mode mode
)
295 if (GET_MODE_UNIT_SIZE (mode
) <= UNITS_PER_FP_ARG
)
297 if (GET_MODE_CLASS (mode
) == MODE_FLOAT
)
300 if (GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
)
310 HOST_WIDE_INT offset
;
311 } loongarch_aggregate_field
;
313 /* Identify subfields of aggregates that are candidates for passing in
314 floating-point registers. */
317 loongarch_flatten_aggregate_field (const_tree type
,
318 loongarch_aggregate_field fields
[2], int n
,
319 HOST_WIDE_INT offset
)
321 switch (TREE_CODE (type
))
324 /* Can't handle incomplete types nor sizes that are not fixed. */
325 if (!COMPLETE_TYPE_P (type
)
326 || TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
327 || !tree_fits_uhwi_p (TYPE_SIZE (type
)))
330 for (tree f
= TYPE_FIELDS (type
); f
; f
= DECL_CHAIN (f
))
331 if (TREE_CODE (f
) == FIELD_DECL
)
333 if (!TYPE_P (TREE_TYPE (f
)))
336 if (DECL_SIZE (f
) && integer_zerop (DECL_SIZE (f
)))
339 HOST_WIDE_INT pos
= offset
+ int_byte_position (f
);
340 n
= loongarch_flatten_aggregate_field (TREE_TYPE (f
), fields
, n
,
349 HOST_WIDE_INT n_elts
;
350 loongarch_aggregate_field subfields
[2];
351 tree index
= TYPE_DOMAIN (type
);
352 tree elt_size
= TYPE_SIZE_UNIT (TREE_TYPE (type
));
353 int n_subfields
= loongarch_flatten_aggregate_field (TREE_TYPE (type
),
357 /* Can't handle incomplete types nor sizes that are not fixed. */
359 || !COMPLETE_TYPE_P (type
)
360 || TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
362 || !TYPE_MAX_VALUE (index
)
363 || !tree_fits_uhwi_p (TYPE_MAX_VALUE (index
))
364 || !TYPE_MIN_VALUE (index
)
365 || !tree_fits_uhwi_p (TYPE_MIN_VALUE (index
))
366 || !tree_fits_uhwi_p (elt_size
))
369 n_elts
= 1 + tree_to_uhwi (TYPE_MAX_VALUE (index
))
370 - tree_to_uhwi (TYPE_MIN_VALUE (index
));
371 gcc_assert (n_elts
>= 0);
373 for (HOST_WIDE_INT i
= 0; i
< n_elts
; i
++)
374 for (int j
= 0; j
< n_subfields
; j
++)
379 fields
[n
] = subfields
[j
];
380 fields
[n
++].offset
+= i
* tree_to_uhwi (elt_size
);
388 /* Complex type need consume 2 field, so n must be 0. */
392 HOST_WIDE_INT elt_size
= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type
)));
394 if (elt_size
<= UNITS_PER_FP_ARG
)
396 fields
[0].type
= TREE_TYPE (type
);
397 fields
[0].offset
= offset
;
398 fields
[1].type
= TREE_TYPE (type
);
399 fields
[1].offset
= offset
+ elt_size
;
409 && ((SCALAR_FLOAT_TYPE_P (type
)
410 && GET_MODE_SIZE (TYPE_MODE (type
)) <= UNITS_PER_FP_ARG
)
411 || (INTEGRAL_TYPE_P (type
)
412 && GET_MODE_SIZE (TYPE_MODE (type
)) <= UNITS_PER_WORD
)))
414 fields
[n
].type
= type
;
415 fields
[n
].offset
= offset
;
423 /* Identify candidate aggregates for passing in floating-point registers.
424 Candidates have at most two fields after flattening. */
427 loongarch_flatten_aggregate_argument (const_tree type
,
428 loongarch_aggregate_field fields
[2])
430 if (!type
|| TREE_CODE (type
) != RECORD_TYPE
)
433 return loongarch_flatten_aggregate_field (type
, fields
, 0, 0);
436 /* See whether TYPE is a record whose fields should be returned in one or
437 two floating-point registers. If so, populate FIELDS accordingly. */
440 loongarch_pass_aggregate_num_fpr (const_tree type
,
441 loongarch_aggregate_field fields
[2])
443 int n
= loongarch_flatten_aggregate_argument (type
, fields
);
445 for (int i
= 0; i
< n
; i
++)
446 if (!SCALAR_FLOAT_TYPE_P (fields
[i
].type
))
449 return n
> 0 ? n
: 0;
452 /* See whether TYPE is a record whose fields should be returned in one
453 floating-point register and one integer register. If so, populate
454 FIELDS accordingly. */
457 loongarch_pass_aggregate_in_fpr_and_gpr_p (const_tree type
,
458 loongarch_aggregate_field fields
[2])
460 unsigned num_int
= 0, num_float
= 0;
461 int n
= loongarch_flatten_aggregate_argument (type
, fields
);
463 for (int i
= 0; i
< n
; i
++)
465 num_float
+= SCALAR_FLOAT_TYPE_P (fields
[i
].type
);
466 num_int
+= INTEGRAL_TYPE_P (fields
[i
].type
);
469 return num_int
== 1 && num_float
== 1;
472 /* Return the representation of an argument passed or returned in an FPR
473 when the value has mode VALUE_MODE and the type has TYPE_MODE. The
474 two modes may be different for structures like:
476 struct __attribute__((packed)) foo { float f; }
478 where the SFmode value "f" is passed in REGNO but the struct itself
482 loongarch_pass_fpr_single (machine_mode type_mode
, unsigned regno
,
483 machine_mode value_mode
,
484 HOST_WIDE_INT offset
)
486 rtx x
= gen_rtx_REG (value_mode
, regno
);
488 if (type_mode
!= value_mode
)
490 x
= gen_rtx_EXPR_LIST (VOIDmode
, x
, GEN_INT (offset
));
491 x
= gen_rtx_PARALLEL (type_mode
, gen_rtvec (1, x
));
496 /* Pass or return a composite value in the FPR pair REGNO and REGNO + 1.
497 MODE is the mode of the composite. MODE1 and OFFSET1 are the mode and
498 byte offset for the first value, likewise MODE2 and OFFSET2 for the
502 loongarch_pass_fpr_pair (machine_mode mode
, unsigned regno1
,
503 machine_mode mode1
, HOST_WIDE_INT offset1
,
504 unsigned regno2
, machine_mode mode2
,
505 HOST_WIDE_INT offset2
)
507 return gen_rtx_PARALLEL (
509 gen_rtx_EXPR_LIST (VOIDmode
, gen_rtx_REG (mode1
, regno1
),
511 gen_rtx_EXPR_LIST (VOIDmode
, gen_rtx_REG (mode2
, regno2
),
512 GEN_INT (offset2
))));
515 /* Fill INFO with information about a single argument, and return an
516 RTL pattern to pass or return the argument. CUM is the cumulative
517 state for earlier arguments. MODE is the mode of this argument and
518 TYPE is its type (if known). NAMED is true if this is a named
519 (fixed) argument rather than a variable one. RETURN_P is true if
520 returning the argument, or false if passing the argument. */
523 loongarch_get_arg_info (struct loongarch_arg_info
*info
,
524 const CUMULATIVE_ARGS
*cum
, machine_mode mode
,
525 const_tree type
, bool named
, bool return_p
)
527 unsigned num_bytes
, num_words
;
528 unsigned fpr_base
= return_p
? FP_RETURN
: FP_ARG_FIRST
;
529 unsigned gpr_base
= return_p
? GP_RETURN
: GP_ARG_FIRST
;
530 unsigned alignment
= loongarch_function_arg_boundary (mode
, type
);
532 memset (info
, 0, sizeof (*info
));
533 info
->gpr_offset
= cum
->num_gprs
;
534 info
->fpr_offset
= cum
->num_fprs
;
538 loongarch_aggregate_field fields
[2];
539 unsigned fregno
= fpr_base
+ info
->fpr_offset
;
540 unsigned gregno
= gpr_base
+ info
->gpr_offset
;
542 /* Pass one- or two-element floating-point aggregates in FPRs. */
544 = loongarch_pass_aggregate_num_fpr (type
, fields
))
545 && info
->fpr_offset
+ info
->num_fprs
<= MAX_ARGS_IN_REGISTERS
)
546 switch (info
->num_fprs
)
549 return loongarch_pass_fpr_single (mode
, fregno
,
550 TYPE_MODE (fields
[0].type
),
554 return loongarch_pass_fpr_pair (mode
, fregno
,
555 TYPE_MODE (fields
[0].type
),
558 TYPE_MODE (fields
[1].type
),
565 /* Pass real and complex floating-point numbers in FPRs. */
566 if ((info
->num_fprs
= loongarch_pass_mode_in_fpr_p (mode
))
567 && info
->fpr_offset
+ info
->num_fprs
<= MAX_ARGS_IN_REGISTERS
)
568 switch (GET_MODE_CLASS (mode
))
571 return gen_rtx_REG (mode
, fregno
);
573 case MODE_COMPLEX_FLOAT
:
574 return loongarch_pass_fpr_pair (mode
, fregno
,
575 GET_MODE_INNER (mode
), 0,
576 fregno
+ 1, GET_MODE_INNER (mode
),
577 GET_MODE_UNIT_SIZE (mode
));
583 /* Pass structs with one float and one integer in an FPR and a GPR. */
584 if (loongarch_pass_aggregate_in_fpr_and_gpr_p (type
, fields
)
585 && info
->gpr_offset
< MAX_ARGS_IN_REGISTERS
586 && info
->fpr_offset
< MAX_ARGS_IN_REGISTERS
)
591 if (!SCALAR_FLOAT_TYPE_P (fields
[0].type
))
592 std::swap (fregno
, gregno
);
594 return loongarch_pass_fpr_pair (mode
, fregno
,
595 TYPE_MODE (fields
[0].type
),
596 fields
[0].offset
, gregno
,
597 TYPE_MODE (fields
[1].type
),
602 /* Work out the size of the argument. */
603 num_bytes
= type
? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
604 num_words
= (num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
606 /* Doubleword-aligned varargs start on an even register boundary. */
607 if (!named
&& num_bytes
!= 0 && alignment
> BITS_PER_WORD
)
608 info
->gpr_offset
+= info
->gpr_offset
& 1;
610 /* Partition the argument between registers and stack. */
612 info
->num_gprs
= MIN (num_words
, MAX_ARGS_IN_REGISTERS
- info
->gpr_offset
);
613 info
->stack_p
= (num_words
- info
->num_gprs
) != 0;
615 if (info
->num_gprs
|| return_p
)
616 return gen_rtx_REG (mode
, gpr_base
+ info
->gpr_offset
);
621 /* Implement TARGET_FUNCTION_ARG. */
624 loongarch_function_arg (cumulative_args_t cum_v
, const function_arg_info
&arg
)
626 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
627 struct loongarch_arg_info info
;
629 if (arg
.end_marker_p ())
632 return loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
,
636 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
639 loongarch_function_arg_advance (cumulative_args_t cum_v
,
640 const function_arg_info
&arg
)
642 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
643 struct loongarch_arg_info info
;
645 loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
, false);
647 /* Advance the register count. This has the effect of setting
648 num_gprs to MAX_ARGS_IN_REGISTERS if a doubleword-aligned
649 argument required us to skip the final GPR and pass the whole
650 argument on the stack. */
651 cum
->num_fprs
= info
.fpr_offset
+ info
.num_fprs
;
652 cum
->num_gprs
= info
.gpr_offset
+ info
.num_gprs
;
655 /* Implement TARGET_ARG_PARTIAL_BYTES. */
658 loongarch_arg_partial_bytes (cumulative_args_t cum
,
659 const function_arg_info
&generic_arg
)
661 struct loongarch_arg_info arg
;
663 loongarch_get_arg_info (&arg
, get_cumulative_args (cum
), generic_arg
.mode
,
664 generic_arg
.type
, generic_arg
.named
, false);
665 return arg
.stack_p
? arg
.num_gprs
* UNITS_PER_WORD
: 0;
668 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
669 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
670 VALTYPE is null and MODE is the mode of the return value. */
673 loongarch_function_value_1 (const_tree type
, const_tree func
,
676 struct loongarch_arg_info info
;
677 CUMULATIVE_ARGS args
;
681 int unsigned_p
= TYPE_UNSIGNED (type
);
683 mode
= TYPE_MODE (type
);
685 /* Since TARGET_PROMOTE_FUNCTION_MODE unconditionally promotes,
686 return values, promote the mode here too. */
687 mode
= promote_function_mode (type
, mode
, &unsigned_p
, func
, 1);
690 memset (&args
, 0, sizeof (args
));
691 return loongarch_get_arg_info (&info
, &args
, mode
, type
, true, true);
695 /* Implement TARGET_FUNCTION_VALUE. */
698 loongarch_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
699 bool outgoing ATTRIBUTE_UNUSED
)
701 return loongarch_function_value_1 (valtype
, fn_decl_or_type
, VOIDmode
);
704 /* Implement TARGET_LIBCALL_VALUE. */
707 loongarch_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
709 return loongarch_function_value_1 (NULL_TREE
, NULL_TREE
, mode
);
713 /* Implement TARGET_PASS_BY_REFERENCE. */
716 loongarch_pass_by_reference (cumulative_args_t cum_v
,
717 const function_arg_info
&arg
)
719 HOST_WIDE_INT size
= arg
.type_size_in_bytes ();
720 struct loongarch_arg_info info
;
721 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
723 /* ??? std_gimplify_va_arg_expr passes NULL for cum. Fortunately, we
724 never pass variadic arguments in floating-point registers, so we can
725 avoid the call to loongarch_get_arg_info in this case. */
728 /* Don't pass by reference if we can use a floating-point register. */
729 loongarch_get_arg_info (&info
, cum
, arg
.mode
, arg
.type
, arg
.named
,
735 /* Pass by reference if the data do not fit in two integer registers. */
736 return !IN_RANGE (size
, 0, 2 * UNITS_PER_WORD
);
739 /* Implement TARGET_RETURN_IN_MEMORY. */
742 loongarch_return_in_memory (const_tree type
,
743 const_tree fndecl ATTRIBUTE_UNUSED
)
745 CUMULATIVE_ARGS args
;
746 cumulative_args_t cum
= pack_cumulative_args (&args
);
748 /* The rules for returning in memory are the same as for passing the
749 first named argument by reference. */
750 memset (&args
, 0, sizeof (args
));
751 function_arg_info
arg (const_cast<tree
> (type
), /*named=*/true);
752 return loongarch_pass_by_reference (cum
, arg
);
755 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
758 loongarch_setup_incoming_varargs (cumulative_args_t cum
,
759 const function_arg_info
&arg
,
760 int *pretend_size ATTRIBUTE_UNUSED
,
763 CUMULATIVE_ARGS local_cum
;
766 /* The caller has advanced CUM up to, but not beyond, the last named
767 argument. Advance a local copy of CUM past the last "real" named
768 argument, to find out how many registers are left over. */
769 local_cum
= *get_cumulative_args (cum
);
770 if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl
)))
771 loongarch_function_arg_advance (pack_cumulative_args (&local_cum
), arg
);
773 /* Found out how many registers we need to save. */
774 gp_saved
= cfun
->va_list_gpr_size
/ UNITS_PER_WORD
;
775 if (gp_saved
> (int) (MAX_ARGS_IN_REGISTERS
- local_cum
.num_gprs
))
776 gp_saved
= MAX_ARGS_IN_REGISTERS
- local_cum
.num_gprs
;
778 if (!no_rtl
&& gp_saved
> 0)
780 rtx ptr
= plus_constant (Pmode
, virtual_incoming_args_rtx
,
781 REG_PARM_STACK_SPACE (cfun
->decl
)
782 - gp_saved
* UNITS_PER_WORD
);
783 rtx mem
= gen_frame_mem (BLKmode
, ptr
);
784 set_mem_alias_set (mem
, get_varargs_alias_set ());
786 move_block_from_reg (local_cum
.num_gprs
+ GP_ARG_FIRST
, mem
, gp_saved
);
788 if (REG_PARM_STACK_SPACE (cfun
->decl
) == 0)
789 cfun
->machine
->varargs_size
= gp_saved
* UNITS_PER_WORD
;
792 /* Make the last instruction frame-related and note that it performs
793 the operation described by FRAME_PATTERN. */
796 loongarch_set_frame_expr (rtx frame_pattern
)
800 insn
= get_last_insn ();
801 RTX_FRAME_RELATED_P (insn
) = 1;
802 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
, frame_pattern
,
806 /* Return a frame-related rtx that stores REG at MEM.
807 REG must be a single register. */
810 loongarch_frame_set (rtx mem
, rtx reg
)
812 rtx set
= gen_rtx_SET (mem
, reg
);
813 RTX_FRAME_RELATED_P (set
) = 1;
817 /* Return true if the current function must save register REGNO. */
820 loongarch_save_reg_p (unsigned int regno
)
822 bool call_saved
= !global_regs
[regno
] && !call_used_regs
[regno
];
824 = crtl
->saves_all_registers
|| df_regs_ever_live_p (regno
);
826 if (call_saved
&& might_clobber
)
829 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
832 if (regno
== RETURN_ADDR_REGNUM
&& crtl
->calls_eh_return
)
838 /* Determine which GPR save/restore routine to call. */
841 loongarch_save_libcall_count (unsigned mask
)
843 for (unsigned n
= GP_REG_LAST
; n
> GP_REG_FIRST
; n
--)
844 if (BITSET_P (mask
, n
))
845 return CALLEE_SAVED_REG_NUMBER (n
) + 1;
849 /* Populate the current function's loongarch_frame_info structure.
851 LoongArch stack frames grown downward. High addresses are at the top.
853 +-------------------------------+
855 | incoming stack arguments |
857 +-------------------------------+ <-- incoming stack pointer
859 | callee-allocated save area |
860 | for arguments that are |
861 | split between registers and |
864 +-------------------------------+ <-- arg_pointer_rtx (virtual)
866 | callee-allocated save area |
867 | for register varargs |
869 +-------------------------------+ <-- hard_frame_pointer_rtx;
870 | | stack_pointer_rtx + gp_sp_offset
871 | GPR save area | + UNITS_PER_WORD
873 +-------------------------------+ <-- stack_pointer_rtx + fp_sp_offset
874 | | + UNITS_PER_HWVALUE
877 +-------------------------------+ <-- frame_pointer_rtx (virtual)
881 P +-------------------------------+
883 | outgoing stack arguments |
885 +-------------------------------+ <-- stack_pointer_rtx
887 Dynamic stack allocations such as alloca insert data at point P.
888 They decrease stack_pointer_rtx but leave frame_pointer_rtx and
889 hard_frame_pointer_rtx unchanged. */
892 loongarch_compute_frame_info (void)
894 struct loongarch_frame_info
*frame
;
895 HOST_WIDE_INT offset
;
896 unsigned int regno
, i
, num_x_saved
= 0, num_f_saved
= 0;
898 frame
= &cfun
->machine
->frame
;
899 memset (frame
, 0, sizeof (*frame
));
901 /* Find out which GPRs we need to save. */
902 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
903 if (loongarch_save_reg_p (regno
))
904 frame
->mask
|= 1 << (regno
- GP_REG_FIRST
), num_x_saved
++;
906 /* If this function calls eh_return, we must also save and restore the
907 EH data registers. */
908 if (crtl
->calls_eh_return
)
909 for (i
= 0; (regno
= EH_RETURN_DATA_REGNO (i
)) != INVALID_REGNUM
; i
++)
910 frame
->mask
|= 1 << (regno
- GP_REG_FIRST
), num_x_saved
++;
912 /* Find out which FPRs we need to save. This loop must iterate over
913 the same space as its companion in loongarch_for_each_saved_reg. */
914 if (TARGET_HARD_FLOAT
)
915 for (regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
916 if (loongarch_save_reg_p (regno
))
917 frame
->fmask
|= 1 << (regno
- FP_REG_FIRST
), num_f_saved
++;
919 /* At the bottom of the frame are any outgoing stack arguments. */
920 offset
= LARCH_STACK_ALIGN (crtl
->outgoing_args_size
);
921 /* Next are local stack variables. */
922 offset
+= LARCH_STACK_ALIGN (get_frame_size ());
923 /* The virtual frame pointer points above the local variables. */
924 frame
->frame_pointer_offset
= offset
;
925 /* Next are the callee-saved FPRs. */
928 offset
+= LARCH_STACK_ALIGN (num_f_saved
* UNITS_PER_FP_REG
);
929 frame
->fp_sp_offset
= offset
- UNITS_PER_FP_REG
;
932 frame
->fp_sp_offset
= offset
;
933 /* Next are the callee-saved GPRs. */
936 unsigned x_save_size
= LARCH_STACK_ALIGN (num_x_saved
* UNITS_PER_WORD
);
937 unsigned num_save_restore
938 = 1 + loongarch_save_libcall_count (frame
->mask
);
940 /* Only use save/restore routines if they don't alter the stack size. */
941 if (LARCH_STACK_ALIGN (num_save_restore
* UNITS_PER_WORD
) == x_save_size
)
942 frame
->save_libcall_adjustment
= x_save_size
;
944 offset
+= x_save_size
;
945 frame
->gp_sp_offset
= offset
- UNITS_PER_WORD
;
948 frame
->gp_sp_offset
= offset
;
949 /* The hard frame pointer points above the callee-saved GPRs. */
950 frame
->hard_frame_pointer_offset
= offset
;
951 /* Above the hard frame pointer is the callee-allocated varags save area. */
952 offset
+= LARCH_STACK_ALIGN (cfun
->machine
->varargs_size
);
953 /* Next is the callee-allocated area for pretend stack arguments. */
954 offset
+= LARCH_STACK_ALIGN (crtl
->args
.pretend_args_size
);
955 /* Arg pointer must be below pretend args, but must be above alignment
957 frame
->arg_pointer_offset
= offset
- crtl
->args
.pretend_args_size
;
958 frame
->total_size
= offset
;
959 /* Next points the incoming stack pointer and any incoming arguments. */
961 /* Only use save/restore routines when the GPRs are atop the frame. */
962 if (frame
->hard_frame_pointer_offset
!= frame
->total_size
)
963 frame
->save_libcall_adjustment
= 0;
966 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame pointer
967 or argument pointer. TO is either the stack pointer or hard frame
971 loongarch_initial_elimination_offset (int from
, int to
)
973 HOST_WIDE_INT src
, dest
;
975 loongarch_compute_frame_info ();
977 if (to
== HARD_FRAME_POINTER_REGNUM
)
978 dest
= cfun
->machine
->frame
.hard_frame_pointer_offset
;
979 else if (to
== STACK_POINTER_REGNUM
)
980 dest
= 0; /* The stack pointer is the base of all offsets, hence 0. */
984 if (from
== FRAME_POINTER_REGNUM
)
985 src
= cfun
->machine
->frame
.frame_pointer_offset
;
986 else if (from
== ARG_POINTER_REGNUM
)
987 src
= cfun
->machine
->frame
.arg_pointer_offset
;
994 /* A function to save or store a register. The first argument is the
995 register and the second is the stack slot. */
996 typedef void (*loongarch_save_restore_fn
) (rtx
, rtx
);
998 /* Use FN to save or restore register REGNO. MODE is the register's
999 mode and OFFSET is the offset of its save slot from the current
1003 loongarch_save_restore_reg (machine_mode mode
, int regno
, HOST_WIDE_INT offset
,
1004 loongarch_save_restore_fn fn
)
1008 mem
= gen_frame_mem (mode
, plus_constant (Pmode
, stack_pointer_rtx
, offset
));
1009 fn (gen_rtx_REG (mode
, regno
), mem
);
1012 /* Call FN for each register that is saved by the current function.
1013 SP_OFFSET is the offset of the current stack pointer from the start
1017 loongarch_for_each_saved_reg (HOST_WIDE_INT sp_offset
,
1018 loongarch_save_restore_fn fn
,
1019 bool skip_eh_data_regs_p
)
1021 HOST_WIDE_INT offset
;
1023 /* Save the link register and s-registers. */
1024 offset
= cfun
->machine
->frame
.gp_sp_offset
- sp_offset
;
1025 for (int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
1026 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
1028 /* Special care needs to be taken for $r4-$r7 (EH_RETURN_DATA_REGNO)
1029 when returning normally from a function that calls
1030 __builtin_eh_return. In this case, these registers are saved but
1031 should not be restored, or the return value may be clobbered. */
1033 if (!(cfun
->machine
->reg_is_wrapped_separately
[regno
]
1034 || (skip_eh_data_regs_p
1035 && GP_ARG_FIRST
<= regno
&& regno
< GP_ARG_FIRST
+ 4)))
1036 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
1038 offset
-= UNITS_PER_WORD
;
1041 /* This loop must iterate over the same space as its companion in
1042 loongarch_compute_frame_info. */
1043 offset
= cfun
->machine
->frame
.fp_sp_offset
- sp_offset
;
1044 machine_mode mode
= TARGET_DOUBLE_FLOAT
? DFmode
: SFmode
;
1046 for (int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
1047 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
1049 if (!cfun
->machine
->reg_is_wrapped_separately
[regno
])
1050 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
1052 offset
-= GET_MODE_SIZE (mode
);
1056 /* Emit a move from SRC to DEST. Assume that the move expanders can
1057 handle all moves if !can_create_pseudo_p (). The distinction is
1058 important because, unlike emit_move_insn, the move expanders know
1059 how to force Pmode objects into the constant pool even when the
1060 constant pool address is not itself legitimate. */
1063 loongarch_emit_move (rtx dest
, rtx src
)
1065 return (can_create_pseudo_p () ? emit_move_insn (dest
, src
)
1066 : emit_move_insn_1 (dest
, src
));
1069 /* Save register REG to MEM. Make the instruction frame-related. */
1072 loongarch_save_reg (rtx reg
, rtx mem
)
1074 loongarch_emit_move (mem
, reg
);
1075 loongarch_set_frame_expr (loongarch_frame_set (mem
, reg
));
1078 /* Restore register REG from MEM. */
1081 loongarch_restore_reg (rtx reg
, rtx mem
)
1083 rtx insn
= loongarch_emit_move (reg
, mem
);
1084 rtx dwarf
= NULL_RTX
;
1085 dwarf
= alloc_reg_note (REG_CFA_RESTORE
, reg
, dwarf
);
1086 REG_NOTES (insn
) = dwarf
;
1088 RTX_FRAME_RELATED_P (insn
) = 1;
1091 /* For stack frames that can't be allocated with a single ADDI instruction,
1092 compute the best value to initially allocate. It must at a minimum
1093 allocate enough space to spill the callee-saved registers. */
1095 static HOST_WIDE_INT
1096 loongarch_first_stack_step (struct loongarch_frame_info
*frame
)
1098 HOST_WIDE_INT min_first_step
1099 = LARCH_STACK_ALIGN (frame
->total_size
- frame
->fp_sp_offset
);
1101 /* When stack checking is required, if the sum of frame->total_size
1102 and stack_check_protect is greater than stack clash protection guard
1103 size, then return min_first_step. */
1104 if (flag_stack_check
== STATIC_BUILTIN_STACK_CHECK
1105 || (flag_stack_clash_protection
1106 && frame
->total_size
> STACK_CLASH_PROTECTION_GUARD_SIZE
))
1107 return min_first_step
;
1109 if (IMM12_OPERAND (frame
->total_size
))
1110 return frame
->total_size
;
1112 HOST_WIDE_INT max_first_step
= IMM_REACH
/ 2 - PREFERRED_STACK_BOUNDARY
/ 8;
1113 HOST_WIDE_INT min_second_step
= frame
->total_size
- max_first_step
;
1114 gcc_assert (min_first_step
<= max_first_step
);
1116 /* As an optimization, use the least-significant bits of the total frame
1117 size, so that the second adjustment step is just LU12I + ADD. */
1118 if (!IMM12_OPERAND (min_second_step
)
1119 && frame
->total_size
% IMM_REACH
< IMM_REACH
/ 2
1120 && frame
->total_size
% IMM_REACH
>= min_first_step
)
1121 return frame
->total_size
% IMM_REACH
;
1123 return max_first_step
;
1127 loongarch_emit_stack_tie (void)
1129 emit_insn (gen_stack_tie (Pmode
, stack_pointer_rtx
,
1130 frame_pointer_needed
? hard_frame_pointer_rtx
1131 : stack_pointer_rtx
));
1134 #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
1136 #if PROBE_INTERVAL > 16384
1137 #error Cannot use indexed addressing mode for stack probing
1140 /* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
1141 inclusive. These are offsets from the current stack pointer. */
1144 loongarch_emit_probe_stack_range (HOST_WIDE_INT first
, HOST_WIDE_INT size
)
1146 HOST_WIDE_INT rounded_size
;
1147 HOST_WIDE_INT interval
;
1149 if (flag_stack_clash_protection
)
1150 interval
= STACK_CLASH_PROTECTION_GUARD_SIZE
;
1152 interval
= PROBE_INTERVAL
;
1154 rtx r12
= LARCH_PROLOGUE_TEMP2 (Pmode
);
1155 rtx r14
= LARCH_PROLOGUE_TEMP3 (Pmode
);
1157 size
= size
+ first
;
1159 /* Sanity check for the addressing mode we're going to use. */
1160 gcc_assert (first
<= 16384);
1162 /* Step 1: round SIZE to the previous multiple of the interval. */
1164 rounded_size
= ROUND_DOWN (size
, interval
);
1166 /* Step 2: compute initial and final value of the loop counter. */
1168 emit_move_insn (r14
, GEN_INT (interval
));
1170 /* If rounded_size is zero, it means that the space requested by
1171 the local variable is less than the interval, and there is no
1172 need to display and detect the allocated space. */
1173 if (rounded_size
!= 0)
1179 TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
1182 while (TEST_ADDR != LAST_ADDR)
1184 probes at FIRST + N * PROBE_INTERVAL for values of N from 1
1185 until it is equal to ROUNDED_SIZE. */
1187 if (rounded_size
<= STACK_CLASH_MAX_UNROLL_PAGES
* interval
)
1189 for (HOST_WIDE_INT i
= 0; i
< rounded_size
; i
+= interval
)
1191 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1192 gen_rtx_MINUS (Pmode
,
1195 emit_move_insn (gen_rtx_MEM (Pmode
,
1196 gen_rtx_PLUS (Pmode
,
1200 emit_insn (gen_blockage ());
1202 dump_stack_clash_frame_info (PROBE_INLINE
, size
!= rounded_size
);
1206 emit_move_insn (r12
, GEN_INT (rounded_size
));
1207 emit_insn (gen_rtx_SET (r12
,
1208 gen_rtx_MINUS (Pmode
,
1212 emit_insn (gen_probe_stack_range (Pmode
, stack_pointer_rtx
,
1213 stack_pointer_rtx
, r12
, r14
));
1214 emit_insn (gen_blockage ());
1215 dump_stack_clash_frame_info (PROBE_LOOP
, size
!= rounded_size
);
1219 dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME
, true);
1222 /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
1223 that SIZE is equal to ROUNDED_SIZE. */
1225 if (size
!= rounded_size
)
1227 if (size
- rounded_size
>= 2048)
1229 emit_move_insn (r14
, GEN_INT (size
- rounded_size
));
1230 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1231 gen_rtx_MINUS (Pmode
,
1236 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1237 gen_rtx_PLUS (Pmode
,
1239 GEN_INT (rounded_size
- size
))));
1244 emit_move_insn (r12
, GEN_INT (first
));
1245 emit_insn (gen_rtx_SET (stack_pointer_rtx
,
1246 gen_rtx_PLUS (Pmode
,
1247 stack_pointer_rtx
, r12
)));
1249 /* Make sure nothing is scheduled before we are done. */
1250 emit_insn (gen_blockage ());
1253 /* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
1254 absolute addresses. */
1256 loongarch_output_probe_stack_range (rtx reg1
, rtx reg2
, rtx reg3
)
1258 static int labelno
= 0;
1259 char loop_lab
[32], tmp
[64];
1262 ASM_GENERATE_INTERNAL_LABEL (loop_lab
, "LPSRL", labelno
++);
1265 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, loop_lab
);
1267 /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
1271 output_asm_insn ("sub.d\t%0,%0,%2", xops
);
1273 output_asm_insn ("sub.w\t%0,%0,%2", xops
);
1275 /* Probe at TEST_ADDR, test if TEST_ADDR == LAST_ADDR and branch. */
1277 strcpy (tmp
, "bne\t%0,%1,");
1279 output_asm_insn ("st.d\t$r0,%0,0", xops
);
1281 output_asm_insn ("st.w\t$r0,%0,0", xops
);
1282 output_asm_insn (strcat (tmp
, &loop_lab
[1]), xops
);
1287 /* Expand the "prologue" pattern. */
1290 loongarch_expand_prologue (void)
1292 struct loongarch_frame_info
*frame
= &cfun
->machine
->frame
;
1293 HOST_WIDE_INT size
= frame
->total_size
;
1296 if (flag_stack_usage_info
)
1297 current_function_static_stack_size
= size
;
1299 /* Save the registers. */
1300 if ((frame
->mask
| frame
->fmask
) != 0)
1302 HOST_WIDE_INT step1
= MIN (size
, loongarch_first_stack_step (frame
));
1304 insn
= gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1306 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1308 loongarch_for_each_saved_reg (size
, loongarch_save_reg
, false);
1311 /* Set up the frame pointer, if we're using one. */
1312 if (frame_pointer_needed
)
1314 insn
= gen_add3_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
,
1315 GEN_INT (frame
->hard_frame_pointer_offset
- size
));
1316 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1318 loongarch_emit_stack_tie ();
1321 if (flag_stack_check
== STATIC_BUILTIN_STACK_CHECK
1322 || flag_stack_clash_protection
)
1324 HOST_WIDE_INT first
= get_stack_check_protect ();
1326 if (frame
->total_size
== 0)
1329 dump_stack_clash_frame_info (NO_PROBE_NO_FRAME
, false);
1333 if (crtl
->is_leaf
&& !cfun
->calls_alloca
)
1335 HOST_WIDE_INT interval
;
1337 if (flag_stack_clash_protection
)
1338 interval
= STACK_CLASH_PROTECTION_GUARD_SIZE
;
1340 interval
= PROBE_INTERVAL
;
1342 if (size
> interval
&& size
> first
)
1343 loongarch_emit_probe_stack_range (first
, size
- first
);
1345 loongarch_emit_probe_stack_range (first
, size
);
1348 loongarch_emit_probe_stack_range (first
, size
);
1352 /* Describe the effect of the previous instructions. */
1353 insn
= plus_constant (Pmode
, stack_pointer_rtx
, -size
);
1354 insn
= gen_rtx_SET (stack_pointer_rtx
, insn
);
1355 loongarch_set_frame_expr (insn
);
1362 if (IMM12_OPERAND (-size
))
1364 insn
= gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1366 RTX_FRAME_RELATED_P (emit_insn (insn
)) = 1;
1370 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
),
1372 emit_insn (gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1373 LARCH_PROLOGUE_TEMP (Pmode
)));
1375 /* Describe the effect of the previous instructions. */
1376 insn
= plus_constant (Pmode
, stack_pointer_rtx
, -size
);
1377 insn
= gen_rtx_SET (stack_pointer_rtx
, insn
);
1378 loongarch_set_frame_expr (insn
);
1383 /* Return nonzero if this function is known to have a null epilogue.
1384 This allows the optimizer to omit jumps to jumps if no stack
1388 loongarch_can_use_return_insn (void)
1390 return reload_completed
&& cfun
->machine
->frame
.total_size
== 0;
1393 /* Expand function epilogue using the following insn patterns:
1394 "epilogue" (style == NORMAL_RETURN)
1395 "sibcall_epilogue" (style == SIBCALL_RETURN)
1396 "eh_return" (style == EXCEPTION_RETURN) */
1399 loongarch_expand_epilogue (int style
)
1401 /* Split the frame into two. STEP1 is the amount of stack we should
1402 deallocate before restoring the registers. STEP2 is the amount we
1403 should deallocate afterwards.
1405 Start off by assuming that no registers need to be restored. */
1406 struct loongarch_frame_info
*frame
= &cfun
->machine
->frame
;
1407 HOST_WIDE_INT step1
= frame
->total_size
;
1408 HOST_WIDE_INT step2
= 0;
1409 rtx ra
= gen_rtx_REG (Pmode
, RETURN_ADDR_REGNUM
);
1412 /* We need to add memory barrier to prevent read from deallocated stack. */
1414 = (get_frame_size () + cfun
->machine
->frame
.arg_pointer_offset
) != 0;
1416 /* Handle simple returns. */
1417 if (style
== NORMAL_RETURN
&& loongarch_can_use_return_insn ())
1419 emit_jump_insn (gen_return ());
1423 /* Move past any dynamic stack allocations. */
1424 if (cfun
->calls_alloca
)
1426 /* Emit a barrier to prevent loads from a deallocated stack. */
1427 loongarch_emit_stack_tie ();
1428 need_barrier_p
= false;
1430 rtx adjust
= GEN_INT (-frame
->hard_frame_pointer_offset
);
1431 if (!IMM12_OPERAND (INTVAL (adjust
)))
1433 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
), adjust
);
1434 adjust
= LARCH_PROLOGUE_TEMP (Pmode
);
1437 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1438 hard_frame_pointer_rtx
,
1441 rtx dwarf
= NULL_RTX
;
1442 rtx minus_offset
= GEN_INT (-frame
->hard_frame_pointer_offset
);
1443 rtx cfa_adjust_value
= gen_rtx_PLUS (Pmode
,
1444 hard_frame_pointer_rtx
,
1447 rtx cfa_adjust_rtx
= gen_rtx_SET (stack_pointer_rtx
, cfa_adjust_value
);
1448 dwarf
= alloc_reg_note (REG_CFA_ADJUST_CFA
, cfa_adjust_rtx
, dwarf
);
1449 RTX_FRAME_RELATED_P (insn
) = 1;
1451 REG_NOTES (insn
) = dwarf
;
1454 /* If we need to restore registers, deallocate as much stack as
1455 possible in the second step without going out of range. */
1456 if ((frame
->mask
| frame
->fmask
) != 0)
1458 step2
= loongarch_first_stack_step (frame
);
1462 /* Set TARGET to BASE + STEP1. */
1465 /* Emit a barrier to prevent loads from a deallocated stack. */
1466 loongarch_emit_stack_tie ();
1467 need_barrier_p
= false;
1469 /* Get an rtx for STEP1 that we can add to BASE. */
1470 rtx adjust
= GEN_INT (step1
);
1471 if (!IMM12_OPERAND (step1
))
1473 loongarch_emit_move (LARCH_PROLOGUE_TEMP (Pmode
), adjust
);
1474 adjust
= LARCH_PROLOGUE_TEMP (Pmode
);
1477 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1481 rtx dwarf
= NULL_RTX
;
1482 rtx cfa_adjust_rtx
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1485 dwarf
= alloc_reg_note (REG_CFA_DEF_CFA
, cfa_adjust_rtx
, dwarf
);
1486 RTX_FRAME_RELATED_P (insn
) = 1;
1488 REG_NOTES (insn
) = dwarf
;
1491 /* Restore the registers. */
1492 loongarch_for_each_saved_reg (frame
->total_size
- step2
,
1493 loongarch_restore_reg
,
1494 crtl
->calls_eh_return
1495 && style
!= EXCEPTION_RETURN
);
1498 loongarch_emit_stack_tie ();
1500 /* Deallocate the final bit of the frame. */
1503 insn
= emit_insn (gen_add3_insn (stack_pointer_rtx
,
1507 rtx dwarf
= NULL_RTX
;
1508 rtx cfa_adjust_rtx
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
);
1509 dwarf
= alloc_reg_note (REG_CFA_DEF_CFA
, cfa_adjust_rtx
, dwarf
);
1510 RTX_FRAME_RELATED_P (insn
) = 1;
1512 REG_NOTES (insn
) = dwarf
;
1515 /* Add in the __builtin_eh_return stack adjustment. */
1516 if (crtl
->calls_eh_return
&& style
== EXCEPTION_RETURN
)
1517 emit_insn (gen_add3_insn (stack_pointer_rtx
, stack_pointer_rtx
,
1518 EH_RETURN_STACKADJ_RTX
));
1520 /* Emit return unless doing sibcall. */
1521 if (style
!= SIBCALL_RETURN
)
1522 emit_jump_insn (gen_simple_return_internal (ra
));
1525 #define LU32I_B (0xfffffULL << 32)
1526 #define LU52I_B (0xfffULL << 52)
1528 /* Fill CODES with a sequence of rtl operations to load VALUE.
1529 Return the number of operations needed. */
1532 loongarch_build_integer (struct loongarch_integer_op
*codes
,
1533 HOST_WIDE_INT value
)
1536 unsigned int cost
= 0;
1538 /* Get the lower 32 bits of the value. */
1539 HOST_WIDE_INT low_part
= (int32_t)value
;
1541 if (IMM12_OPERAND (low_part
) || IMM12_OPERAND_UNSIGNED (low_part
))
1543 /* The value of the lower 32 bit be loaded with one instruction.
1545 codes
[cost
].code
= UNKNOWN
;
1546 codes
[cost
].method
= METHOD_NORMAL
;
1547 codes
[cost
].value
= low_part
;
1548 codes
[cost
].curr_value
= low_part
;
1553 /* lu12i.w + ior. */
1554 codes
[cost
].code
= UNKNOWN
;
1555 codes
[cost
].method
= METHOD_NORMAL
;
1556 codes
[cost
].value
= low_part
& ~(IMM_REACH
- 1);
1557 codes
[cost
].curr_value
= codes
[cost
].value
;
1559 HOST_WIDE_INT iorv
= low_part
& (IMM_REACH
- 1);
1562 codes
[cost
].code
= IOR
;
1563 codes
[cost
].method
= METHOD_NORMAL
;
1564 codes
[cost
].value
= iorv
;
1565 codes
[cost
].curr_value
= low_part
;
1572 bool lu32i
[2] = {(value
& LU32I_B
) == 0, (value
& LU32I_B
) == LU32I_B
};
1573 bool lu52i
[2] = {(value
& LU52I_B
) == 0, (value
& LU52I_B
) == LU52I_B
};
1575 int sign31
= (value
& (HOST_WIDE_INT_1U
<< 31)) >> 31;
1576 int sign51
= (value
& (HOST_WIDE_INT_1U
<< 51)) >> 51;
1578 uint32_t hival
= (uint32_t) (value
>> 32);
1579 uint32_t loval
= (uint32_t) value
;
1581 /* Determine whether the upper 32 bits are sign-extended from the lower
1582 32 bits. If it is, the instructions to load the high order can be
1584 if (lu32i
[sign31
] && lu52i
[sign31
])
1586 /* If the lower 32 bits are the same as the upper 32 bits, just copy
1587 the lower 32 bits to the upper 32 bits. */
1588 else if (loval
== hival
)
1590 codes
[cost
].method
= METHOD_MIRROR
;
1591 codes
[cost
].curr_value
= value
;
1594 /* Determine whether bits 32-51 are sign-extended from the lower 32
1595 bits. If so, directly load 52-63 bits. */
1596 else if (lu32i
[sign31
])
1598 codes
[cost
].method
= METHOD_LU52I
;
1599 codes
[cost
].value
= value
& LU52I_B
;
1600 codes
[cost
].curr_value
= value
;
1604 codes
[cost
].method
= METHOD_LU32I
;
1605 codes
[cost
].value
= (value
& LU32I_B
) | (sign51
? LU52I_B
: 0);
1606 codes
[cost
].curr_value
= (value
& 0xfffffffffffff)
1607 | (sign51
? LU52I_B
: 0);
1610 /* Determine whether the 52-61 bits are sign-extended from the low order,
1611 and if not, load the 52-61 bits. */
1612 if (!lu52i
[(value
& (HOST_WIDE_INT_1U
<< 51)) >> 51])
1614 codes
[cost
].method
= METHOD_LU52I
;
1615 codes
[cost
].value
= value
& LU52I_B
;
1616 codes
[cost
].curr_value
= value
;
1621 gcc_assert (cost
<= LARCH_MAX_INTEGER_OPS
);
1626 /* Fill CODES with a sequence of rtl operations to load VALUE.
1627 Return the number of operations needed.
1628 Split interger in loongarch_output_move. */
1631 loongarch_integer_cost (HOST_WIDE_INT value
)
1633 struct loongarch_integer_op codes
[LARCH_MAX_INTEGER_OPS
];
1634 return loongarch_build_integer (codes
, value
);
1637 /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
1640 loongarch_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1642 return loongarch_const_insns (x
) > 0;
1645 /* Return true if X is a thread-local symbol. */
1648 loongarch_tls_symbol_p (rtx x
)
1650 return SYMBOL_REF_P (x
) && SYMBOL_REF_TLS_MODEL (x
) != 0;
1653 /* Return true if SYMBOL_REF X is associated with a global symbol
1654 (in the STB_GLOBAL sense). */
1657 loongarch_global_symbol_p (const_rtx x
)
1659 if (LABEL_REF_P (x
))
1662 const_tree decl
= SYMBOL_REF_DECL (x
);
1665 return !SYMBOL_REF_LOCAL_P (x
) || SYMBOL_REF_EXTERNAL_P (x
);
1667 /* Weakref symbols are not TREE_PUBLIC, but their targets are global
1668 or weak symbols. Relocations in the object file will be against
1669 the target symbol, so it's that symbol's binding that matters here. */
1670 return DECL_P (decl
) && (TREE_PUBLIC (decl
) || DECL_WEAK (decl
));
1674 loongarch_global_symbol_noweak_p (const_rtx x
)
1676 if (LABEL_REF_P (x
))
1679 const_tree decl
= SYMBOL_REF_DECL (x
);
1682 return !SYMBOL_REF_LOCAL_P (x
) || SYMBOL_REF_EXTERNAL_P (x
);
1684 return DECL_P (decl
) && TREE_PUBLIC (decl
);
1688 loongarch_weak_symbol_p (const_rtx x
)
1691 if (LABEL_REF_P (x
) || !(decl
= SYMBOL_REF_DECL (x
)))
1693 return DECL_P (decl
) && DECL_WEAK (decl
);
1696 /* Return true if SYMBOL_REF X binds locally. */
1699 loongarch_symbol_binds_local_p (const_rtx x
)
1701 if (TARGET_DIRECT_EXTERN_ACCESS
)
1704 if (SYMBOL_REF_P (x
))
1705 return (SYMBOL_REF_DECL (x
)
1706 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
1707 : SYMBOL_REF_LOCAL_P (x
));
1712 /* Return true if OP is a constant vector with the number of units in MODE,
1713 and each unit has the same bit set. */
1716 loongarch_const_vector_bitimm_set_p (rtx op
, machine_mode mode
)
1718 if (GET_CODE (op
) == CONST_VECTOR
&& op
!= CONST0_RTX (mode
))
1720 unsigned HOST_WIDE_INT val
= UINTVAL (CONST_VECTOR_ELT (op
, 0));
1721 int vlog2
= exact_log2 (val
& GET_MODE_MASK (GET_MODE_INNER (mode
)));
1725 gcc_assert (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
);
1726 gcc_assert (vlog2
>= 0 && vlog2
<= GET_MODE_UNIT_BITSIZE (mode
) - 1);
1727 return loongarch_const_vector_same_val_p (op
, mode
);
1734 /* Return true if OP is a constant vector with the number of units in MODE,
1735 and each unit has the same bit clear. */
1738 loongarch_const_vector_bitimm_clr_p (rtx op
, machine_mode mode
)
1740 if (GET_CODE (op
) == CONST_VECTOR
&& op
!= CONSTM1_RTX (mode
))
1742 unsigned HOST_WIDE_INT val
= ~UINTVAL (CONST_VECTOR_ELT (op
, 0));
1743 int vlog2
= exact_log2 (val
& GET_MODE_MASK (GET_MODE_INNER (mode
)));
1747 gcc_assert (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
);
1748 gcc_assert (vlog2
>= 0 && vlog2
<= GET_MODE_UNIT_BITSIZE (mode
) - 1);
1749 return loongarch_const_vector_same_val_p (op
, mode
);
1756 /* Return true if OP is a constant vector with the number of units in MODE,
1757 and each unit has the same value. */
1760 loongarch_const_vector_same_val_p (rtx op
, machine_mode mode
)
1762 int i
, nunits
= GET_MODE_NUNITS (mode
);
1765 if (GET_CODE (op
) != CONST_VECTOR
|| GET_MODE (op
) != mode
)
1768 first
= CONST_VECTOR_ELT (op
, 0);
1769 for (i
= 1; i
< nunits
; i
++)
1770 if (!rtx_equal_p (first
, CONST_VECTOR_ELT (op
, i
)))
1776 /* Return true if OP is a constant vector with the number of units in MODE,
1777 and each unit has the same value as well as replicated bytes in the value.
1781 loongarch_const_vector_same_bytes_p (rtx op
, machine_mode mode
)
1784 HOST_WIDE_INT val
, first_byte
;
1787 if (!loongarch_const_vector_same_val_p (op
, mode
))
1790 first
= CONST_VECTOR_ELT (op
, 0);
1791 bytes
= GET_MODE_UNIT_SIZE (mode
);
1792 val
= INTVAL (first
);
1793 first_byte
= val
& 0xff;
1794 for (i
= 1; i
< bytes
; i
++)
1797 if ((val
& 0xff) != first_byte
)
1804 /* Return true if OP is a constant vector with the number of units in MODE,
1805 and each unit has the same integer value in the range [LOW, HIGH]. */
1808 loongarch_const_vector_same_int_p (rtx op
, machine_mode mode
, HOST_WIDE_INT low
,
1811 HOST_WIDE_INT value
;
1814 if (!loongarch_const_vector_same_val_p (op
, mode
))
1817 elem0
= CONST_VECTOR_ELT (op
, 0);
1818 if (!CONST_INT_P (elem0
))
1821 value
= INTVAL (elem0
);
1822 return (value
>= low
&& value
<= high
);
1825 /* Return true if OP is a constant vector with repeated 4-element sets
1829 loongarch_const_vector_shuffle_set_p (rtx op
, machine_mode mode
)
1831 int nunits
= GET_MODE_NUNITS (mode
);
1832 int nsets
= nunits
/ 4;
1836 /* Check if we have the same 4-element sets. */
1837 for (j
= 0; j
< nsets
; j
++, set
= 4 * j
)
1838 for (i
= 0; i
< 4; i
++)
1839 if ((INTVAL (XVECEXP (op
, 0, i
))
1840 != (INTVAL (XVECEXP (op
, 0, set
+ i
)) - set
))
1841 || !IN_RANGE (INTVAL (XVECEXP (op
, 0, set
+ i
)), 0, set
+ 3))
1846 /* Return true if rtx constants of mode MODE should be put into a small
1850 loongarch_rtx_constant_in_small_data_p (machine_mode mode
)
1852 return (GET_MODE_SIZE (mode
) <= g_switch_value
);
1855 /* Return the method that should be used to access SYMBOL_REF or
1858 static enum loongarch_symbol_type
1859 loongarch_classify_symbol (const_rtx x
)
1861 enum loongarch_symbol_type pcrel
=
1862 TARGET_CMODEL_EXTREME
? SYMBOL_PCREL64
: SYMBOL_PCREL
;
1864 if (!SYMBOL_REF_P (x
))
1867 if (SYMBOL_REF_TLS_MODEL (x
))
1870 if (!loongarch_symbol_binds_local_p (x
))
1871 return SYMBOL_GOT_DISP
;
1873 tree t
= SYMBOL_REF_DECL (x
);
1877 t
= lookup_attribute ("model", DECL_ATTRIBUTES (t
));
1881 t
= TREE_VALUE (TREE_VALUE (t
));
1883 /* loongarch_handle_model_attribute should reject other values. */
1884 gcc_assert (TREE_CODE (t
) == STRING_CST
);
1886 const char *model
= TREE_STRING_POINTER (t
);
1887 if (strcmp (model
, "normal") == 0)
1888 return SYMBOL_PCREL
;
1889 if (strcmp (model
, "extreme") == 0)
1890 return SYMBOL_PCREL64
;
1892 /* loongarch_handle_model_attribute should reject unknown model
1897 /* Classify the base of symbolic expression X, given that X appears in
1900 static enum loongarch_symbol_type
1901 loongarch_classify_symbolic_expression (rtx x
)
1905 split_const (x
, &x
, &offset
);
1906 if (UNSPEC_ADDRESS_P (x
))
1907 return UNSPEC_ADDRESS_TYPE (x
);
1909 return loongarch_classify_symbol (x
);
1912 /* Return true if X is a symbolic constant. If it is,
1913 store the type of the symbol in *SYMBOL_TYPE. */
1916 loongarch_symbolic_constant_p (rtx x
, enum loongarch_symbol_type
*symbol_type
)
1920 split_const (x
, &x
, &offset
);
1921 if (UNSPEC_ADDRESS_P (x
))
1923 *symbol_type
= UNSPEC_ADDRESS_TYPE (x
);
1924 x
= UNSPEC_ADDRESS (x
);
1926 else if (SYMBOL_REF_P (x
) || LABEL_REF_P (x
))
1927 *symbol_type
= loongarch_classify_symbol (x
);
1931 if (offset
== const0_rtx
)
1934 /* Check whether a nonzero offset is valid for the underlying
1936 switch (*symbol_type
)
1939 case SYMBOL_PCREL64
:
1940 /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */
1941 return sext_hwi (INTVAL (offset
), 32) == INTVAL (offset
);
1943 /* The following symbol types do not allow non-zero offsets. */
1944 case SYMBOL_GOT_DISP
:
1949 /* From an implementation perspective, tls_le symbols are allowed to
1950 have non-zero offsets, but currently binutils has not added support,
1951 so the generation of non-zero offsets is prohibited here. */
1958 /* If -mexplicit-relocs=auto, we use machine operations with reloc hints
1959 for cases where the linker is unable to relax so we can schedule the
1960 machine operations, otherwise use an assembler pseudo-op so the
1961 assembler will generate R_LARCH_RELAX. */
1964 loongarch_explicit_relocs_p (enum loongarch_symbol_type type
)
1966 if (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_AUTO
)
1967 return la_opt_explicit_relocs
== EXPLICIT_RELOCS_ALWAYS
;
1973 case SYMBOL_PCREL64
:
1974 /* TLS IE cannot be relaxed. TLS LE relaxation is different from
1975 the normal R_LARCH_RELAX-based relaxation and it **requires**
1976 using the explicit %le_{lo12,hi20,add}_r relocs. The linker
1977 does not relax 64-bit pc-relative accesses as at now. */
1979 case SYMBOL_GOT_DISP
:
1980 /* The linker don't know how to relax GOT accesses in extreme
1982 if (TARGET_CMODEL_EXTREME
)
1985 /* If we are performing LTO for a final link, and we have the
1986 linker plugin so we know the resolution of the symbols, then
1987 all GOT references are binding to external symbols or
1988 preemptable symbols. So the linker cannot relax them. */
1990 && !flag_incremental_link
1991 && HAVE_LTO_PLUGIN
== 2
1992 && (!global_options_set
.x_flag_use_linker_plugin
1993 || global_options
.x_flag_use_linker_plugin
));
1999 /* Returns the number of instructions necessary to reference a symbol. */
2002 loongarch_symbol_insns (enum loongarch_symbol_type type
, machine_mode mode
)
2004 /* LSX LD.* and ST.* cannot support loading symbols via an immediate
2006 if (LSX_SUPPORTED_MODE_P (mode
) || LASX_SUPPORTED_MODE_P (mode
))
2011 case SYMBOL_GOT_DISP
:
2012 /* The constant will have to be loaded from the GOT before it
2013 is used in an address. */
2014 if (!loongarch_explicit_relocs_p (type
) && mode
!= MAX_MACHINE_MODE
)
2028 case SYMBOL_PCREL64
:
2032 /* We don't treat a bare TLS symbol as a constant. */
2038 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
2041 loongarch_cannot_force_const_mem (machine_mode mode
, rtx x
)
2043 enum loongarch_symbol_type type
;
2046 /* As an optimization, reject constants that loongarch_legitimize_move
2049 Suppose we have a multi-instruction sequence that loads constant C
2050 into register R. If R does not get allocated a hard register, and
2051 R is used in an operand that allows both registers and memory
2052 references, reload will consider forcing C into memory and using
2053 one of the instruction's memory alternatives. Returning false
2054 here will force it to use an input reload instead. */
2055 if ((CONST_INT_P (x
) || GET_CODE (x
) == CONST_VECTOR
)
2056 && loongarch_legitimate_constant_p (mode
, x
))
2059 split_const (x
, &base
, &offset
);
2060 if (loongarch_symbolic_constant_p (base
, &type
))
2062 /* The same optimization as for CONST_INT. */
2063 if (IMM12_INT (offset
)
2064 && loongarch_symbol_insns (type
, MAX_MACHINE_MODE
) > 0)
2068 /* TLS symbols must be computed by loongarch_legitimize_move. */
2069 if (tls_referenced_p (x
))
2075 /* Return true if register REGNO is a valid base register for mode MODE.
2076 STRICT_P is true if REG_OK_STRICT is in effect. */
2079 loongarch_regno_mode_ok_for_base_p (int regno
,
2080 machine_mode mode ATTRIBUTE_UNUSED
,
2083 if (!HARD_REGISTER_NUM_P (regno
))
2087 regno
= reg_renumber
[regno
];
2090 /* These fake registers will be eliminated to either the stack or
2091 hard frame pointer, both of which are usually valid base registers.
2092 Reload deals with the cases where the eliminated form isn't valid. */
2093 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
2096 return GP_REG_P (regno
);
2099 /* Return true if X is a valid base register for mode MODE.
2100 STRICT_P is true if REG_OK_STRICT is in effect. */
2103 loongarch_valid_base_register_p (rtx x
, machine_mode mode
, bool strict_p
)
2105 if (!strict_p
&& SUBREG_P (x
))
2109 && loongarch_regno_mode_ok_for_base_p (REGNO (x
), mode
, strict_p
));
2112 /* Return true if, for every base register BASE_REG, (plus BASE_REG X)
2113 can address a value of mode MODE. */
2116 loongarch_valid_offset_p (rtx x
, machine_mode mode
)
2118 /* Check that X is a signed 12-bit number,
2119 or check that X is a signed 16-bit number
2120 and offset 4 byte aligned. */
2121 if (!(const_arith_operand (x
, Pmode
)
2122 || ((mode
== E_SImode
|| mode
== E_DImode
)
2123 && const_imm16_operand (x
, Pmode
)
2124 && (loongarch_signed_immediate_p (INTVAL (x
), 14, 2)))))
2127 /* We may need to split multiword moves, so make sure that every word
2129 if (!(LSX_SUPPORTED_MODE_P (mode
) || LASX_SUPPORTED_MODE_P (mode
))
2130 && GET_MODE_SIZE (mode
) > UNITS_PER_WORD
2131 && !IMM12_OPERAND (INTVAL (x
) + GET_MODE_SIZE (mode
) - UNITS_PER_WORD
))
2137 /* Should a symbol of type SYMBOL_TYPE should be split in two or more? */
2140 loongarch_split_symbol_type (enum loongarch_symbol_type symbol_type
)
2142 switch (symbol_type
)
2145 case SYMBOL_PCREL64
:
2146 case SYMBOL_GOT_DISP
:
2161 /* Return true if a LO_SUM can address a value of mode MODE when the
2162 LO_SUM symbol has type SYMBOL_TYPE. */
2165 loongarch_valid_lo_sum_p (enum loongarch_symbol_type symbol_type
,
2166 machine_mode mode
, rtx x
)
2170 /* Check that symbols of type SYMBOL_TYPE can be used to access values
2172 if (loongarch_symbol_insns (symbol_type
, mode
) == 0)
2175 /* Check that there is a known low-part relocation. */
2176 if (!loongarch_split_symbol_type (symbol_type
))
2179 /* We can't tell size or alignment when we have BLKmode, so try extracing a
2180 decl from the symbol if possible. */
2181 if (mode
== BLKmode
)
2185 /* Extract the symbol from the LO_SUM operand, if any. */
2186 split_const (x
, &x
, &offset
);
2188 /* Might be a CODE_LABEL. We can compute align but not size for that,
2189 so don't bother trying to handle it. */
2190 if (!SYMBOL_REF_P (x
))
2193 /* Use worst case assumptions if we don't have a SYMBOL_REF_DECL. */
2194 align
= (SYMBOL_REF_DECL (x
)
2195 ? DECL_ALIGN (SYMBOL_REF_DECL (x
))
2197 size
= (SYMBOL_REF_DECL (x
) && DECL_SIZE (SYMBOL_REF_DECL (x
))
2198 ? tree_to_uhwi (DECL_SIZE (SYMBOL_REF_DECL (x
)))
2203 align
= GET_MODE_ALIGNMENT (mode
);
2204 size
= GET_MODE_BITSIZE (mode
);
2207 /* We may need to split multiword moves, so make sure that each word
2208 can be accessed without inducing a carry. */
2209 if (size
> BITS_PER_WORD
2210 && (!TARGET_STRICT_ALIGN
|| size
> align
))
2217 loongarch_valid_index_p (struct loongarch_address_info
*info
, rtx x
,
2218 machine_mode mode
, bool strict_p
)
2222 if ((REG_P (x
) || SUBREG_P (x
))
2223 && GET_MODE (x
) == Pmode
)
2232 && contains_reg_of_mode
[GENERAL_REGS
][GET_MODE (SUBREG_REG (index
))])
2233 index
= SUBREG_REG (index
);
2235 if (loongarch_valid_base_register_p (index
, mode
, strict_p
))
2237 info
->type
= ADDRESS_REG_REG
;
2238 info
->offset
= index
;
2245 /* Return true if X is a valid address for machine mode MODE. If it is,
2246 fill in INFO appropriately. STRICT_P is true if REG_OK_STRICT is in
2250 loongarch_classify_address (struct loongarch_address_info
*info
, rtx x
,
2251 machine_mode mode
, bool strict_p
)
2253 switch (GET_CODE (x
))
2257 info
->type
= ADDRESS_REG
;
2259 info
->offset
= const0_rtx
;
2260 return loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
);
2263 if (loongarch_valid_base_register_p (XEXP (x
, 0), mode
, strict_p
)
2264 && loongarch_valid_index_p (info
, XEXP (x
, 1), mode
, strict_p
))
2266 info
->reg
= XEXP (x
, 0);
2270 if (loongarch_valid_base_register_p (XEXP (x
, 1), mode
, strict_p
)
2271 && loongarch_valid_index_p (info
, XEXP (x
, 0), mode
, strict_p
))
2273 info
->reg
= XEXP (x
, 1);
2277 info
->type
= ADDRESS_REG
;
2278 info
->reg
= XEXP (x
, 0);
2279 info
->offset
= XEXP (x
, 1);
2280 return (loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
)
2281 && loongarch_valid_offset_p (info
->offset
, mode
));
2284 info
->type
= ADDRESS_LO_SUM
;
2285 info
->reg
= XEXP (x
, 0);
2286 info
->offset
= XEXP (x
, 1);
2287 /* We have to trust the creator of the LO_SUM to do something vaguely
2288 sane. Target-independent code that creates a LO_SUM should also
2289 create and verify the matching HIGH. Target-independent code that
2290 adds an offset to a LO_SUM must prove that the offset will not
2291 induce a carry. Failure to do either of these things would be
2292 a bug, and we are not required to check for it here. The MIPS
2293 backend itself should only create LO_SUMs for valid symbolic
2294 constants, with the high part being either a HIGH or a copy
2297 = loongarch_classify_symbolic_expression (info
->offset
);
2298 return (loongarch_valid_base_register_p (info
->reg
, mode
, strict_p
)
2299 && loongarch_valid_lo_sum_p (info
->symbol_type
, mode
,
2302 /* Small-integer addresses don't occur very often, but they
2303 are legitimate if $r0 is a valid base register. */
2304 info
->type
= ADDRESS_CONST_INT
;
2305 return IMM12_OPERAND (INTVAL (x
));
2312 /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
2315 loongarch_legitimate_address_p (machine_mode mode
, rtx x
, bool strict_p
,
2316 code_helper
= ERROR_MARK
)
2318 struct loongarch_address_info addr
;
2320 return loongarch_classify_address (&addr
, x
, mode
, strict_p
);
2323 /* Return true if ADDR matches the pattern for the indexed address
2327 loongarch_index_address_p (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
)
2329 if (GET_CODE (addr
) != PLUS
2330 || !REG_P (XEXP (addr
, 0))
2331 || !REG_P (XEXP (addr
, 1)))
2336 /* Return the number of instructions needed to load or store a value
2337 of mode MODE at address X. Return 0 if X isn't valid for MODE.
2338 Assume that multiword moves may need to be split into word moves
2339 if MIGHT_SPLIT_P, otherwise assume that a single load or store is
2343 loongarch_address_insns (rtx x
, machine_mode mode
, bool might_split_p
)
2345 struct loongarch_address_info addr
;
2347 bool lsx_p
= (!might_split_p
2348 && (LSX_SUPPORTED_MODE_P (mode
)
2349 || LASX_SUPPORTED_MODE_P (mode
)));
2351 if (!loongarch_classify_address (&addr
, x
, mode
, false))
2354 /* BLKmode is used for single unaligned loads and stores and should
2355 not count as a multiword mode. (GET_MODE_SIZE (BLKmode) is pretty
2356 meaningless, so we have to single it out as a special case one way
2358 if (mode
!= BLKmode
&& might_split_p
)
2359 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
2363 if (loongarch_classify_address (&addr
, x
, mode
, false))
2369 /* LSX LD.* and ST.* supports 12-bit signed offsets. */
2370 if (IMM12_OPERAND (INTVAL (addr
.offset
)))
2377 case ADDRESS_REG_REG
:
2380 case ADDRESS_CONST_INT
:
2381 return lsx_p
? 0 : factor
;
2383 case ADDRESS_LO_SUM
:
2386 case ADDRESS_SYMBOLIC
:
2388 : factor
* loongarch_symbol_insns (addr
.symbol_type
, mode
);
2393 /* Return true if X fits within an unsigned field of BITS bits that is
2394 shifted left SHIFT bits before being used. */
2397 loongarch_unsigned_immediate_p (unsigned HOST_WIDE_INT x
, int bits
,
2400 return (x
& ((1 << shift
) - 1)) == 0 && x
< ((unsigned) 1 << (shift
+ bits
));
2403 /* Return true if X fits within a signed field of BITS bits that is
2404 shifted left SHIFT bits before being used. */
2407 loongarch_signed_immediate_p (unsigned HOST_WIDE_INT x
, int bits
,
2410 x
+= 1 << (bits
+ shift
- 1);
2411 return loongarch_unsigned_immediate_p (x
, bits
, shift
);
2414 /* Return the scale shift that applied to LSX LD/ST address offset. */
2417 loongarch_ldst_scaled_shift (machine_mode mode
)
2419 int shift
= exact_log2 (GET_MODE_UNIT_SIZE (mode
));
2421 if (shift
< 0 || shift
> 8)
2427 /* Return true if X is a legitimate address with a 12-bit offset
2428 or addr.type is ADDRESS_LO_SUM.
2429 MODE is the mode of the value being accessed. */
2432 loongarch_12bit_offset_address_p (rtx x
, machine_mode mode
)
2434 struct loongarch_address_info addr
;
2436 return (loongarch_classify_address (&addr
, x
, mode
, false)
2437 && ((addr
.type
== ADDRESS_REG
2438 && CONST_INT_P (addr
.offset
)
2439 && LARCH_12BIT_OFFSET_P (INTVAL (addr
.offset
)))
2440 || addr
.type
== ADDRESS_LO_SUM
));
2443 /* Return true if X is a legitimate address with a 14-bit offset shifted 2.
2444 MODE is the mode of the value being accessed. */
2447 loongarch_14bit_shifted_offset_address_p (rtx x
, machine_mode mode
)
2449 struct loongarch_address_info addr
;
2451 return (loongarch_classify_address (&addr
, x
, mode
, false)
2452 && addr
.type
== ADDRESS_REG
2453 && CONST_INT_P (addr
.offset
)
2454 && LARCH_16BIT_OFFSET_P (INTVAL (addr
.offset
))
2455 && LARCH_SHIFT_2_OFFSET_P (INTVAL (addr
.offset
)));
2458 /* Return true if X is a legitimate address with base and index.
2459 MODE is the mode of the value being accessed. */
2462 loongarch_base_index_address_p (rtx x
, machine_mode mode
)
2464 struct loongarch_address_info addr
;
2466 return (loongarch_classify_address (&addr
, x
, mode
, false)
2467 && addr
.type
== ADDRESS_REG_REG
2468 && REG_P (addr
.offset
));
2471 /* Return the number of instructions needed to load constant X,
2472 Return 0 if X isn't a valid constant. */
2475 loongarch_const_insns (rtx x
)
2477 enum loongarch_symbol_type symbol_type
;
2480 switch (GET_CODE (x
))
2483 if (!loongarch_symbolic_constant_p (XEXP (x
, 0), &symbol_type
)
2484 || !loongarch_split_symbol_type (symbol_type
))
2487 /* This is simply a PCALAU12I. */
2491 return loongarch_integer_cost (INTVAL (x
));
2494 if ((LSX_SUPPORTED_MODE_P (GET_MODE (x
))
2495 || LASX_SUPPORTED_MODE_P (GET_MODE (x
)))
2496 && loongarch_const_vector_same_int_p (x
, GET_MODE (x
), -512, 511))
2500 return x
== CONST0_RTX (GET_MODE (x
)) ? 1 : 0;
2503 /* See if we can refer to X directly. */
2504 if (loongarch_symbolic_constant_p (x
, &symbol_type
))
2505 return loongarch_symbol_insns (symbol_type
, MAX_MACHINE_MODE
);
2507 /* Otherwise try splitting the constant into a base and offset.
2508 If the offset is a 12-bit value, we can load the base address
2509 into a register and then use ADDI.{W/D} to add in the offset.
2510 If the offset is larger, we can load the base and offset
2511 into separate registers and add them together with ADD.{W/D}.
2512 However, the latter is only possible before reload; during
2513 and after reload, we must have the option of forcing the
2514 constant into the pool instead. */
2515 split_const (x
, &x
, &offset
);
2518 int n
= loongarch_const_insns (x
);
2521 if (IMM12_INT (offset
))
2523 else if (!targetm
.cannot_force_const_mem (GET_MODE (x
), x
))
2524 return n
+ 1 + loongarch_integer_cost (INTVAL (offset
));
2531 return loongarch_symbol_insns (
2532 loongarch_classify_symbol (x
), MAX_MACHINE_MODE
);
2539 /* X is a doubleword constant that can be handled by splitting it into
2540 two words and loading each word separately. Return the number of
2541 instructions required to do this. */
2544 loongarch_split_const_insns (rtx x
)
2546 unsigned int low
, high
;
2548 low
= loongarch_const_insns (loongarch_subword (x
, false));
2549 high
= loongarch_const_insns (loongarch_subword (x
, true));
2550 gcc_assert (low
> 0 && high
> 0);
2554 /* Return one word of 128-bit value OP, taking into account the fixed
2555 endianness of certain registers. BYTE selects from the byte address. */
2558 loongarch_subword_at_byte (rtx op
, unsigned int byte
)
2562 mode
= GET_MODE (op
);
2563 if (mode
== VOIDmode
)
2566 gcc_assert (!FP_REG_RTX_P (op
));
2569 return loongarch_rewrite_small_data (adjust_address (op
, word_mode
, byte
));
2571 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
2574 /* Return the number of instructions needed to implement INSN,
2575 given that it loads from or stores to MEM. */
2578 loongarch_load_store_insns (rtx mem
, rtx_insn
*insn
)
2584 gcc_assert (MEM_P (mem
));
2585 mode
= GET_MODE (mem
);
2587 /* Try to prove that INSN does not need to be split. */
2588 might_split_p
= GET_MODE_SIZE (mode
) > UNITS_PER_WORD
;
2591 set
= single_set (insn
);
2593 && !loongarch_split_move_p (SET_DEST (set
), SET_SRC (set
)))
2594 might_split_p
= false;
2597 return loongarch_address_insns (XEXP (mem
, 0), mode
, might_split_p
);
2600 /* Return true if we need to trap on division by zero. */
2603 loongarch_check_zero_div_p (void)
2605 /* if -m[no-]check-zero-division is given explicitly. */
2606 if (target_flags_explicit
& MASK_CHECK_ZERO_DIV
)
2607 return TARGET_CHECK_ZERO_DIV
;
2609 /* if not, don't trap for optimized code except -Og. */
2610 return !optimize
|| optimize_debug
;
2613 /* Return the number of instructions needed for an integer division. */
2616 loongarch_idiv_insns (machine_mode mode ATTRIBUTE_UNUSED
)
2621 if (loongarch_check_zero_div_p ())
2627 /* Emit an instruction of the form (set TARGET (CODE OP0 OP1)). */
2630 loongarch_emit_binary (enum rtx_code code
, rtx target
, rtx op0
, rtx op1
)
2632 emit_insn (gen_rtx_SET (target
, gen_rtx_fmt_ee (code
, GET_MODE (target
),
2636 /* Compute (CODE OP0 OP1) and store the result in a new register
2637 of mode MODE. Return that new register. */
2640 loongarch_force_binary (machine_mode mode
, enum rtx_code code
, rtx op0
,
2645 reg
= gen_reg_rtx (mode
);
2646 loongarch_emit_binary (code
, reg
, op0
, op1
);
2650 /* Copy VALUE to a register and return that register. If new pseudos
2651 are allowed, copy it into a new register, otherwise use DEST. */
2654 loongarch_force_temporary (rtx dest
, rtx value
)
2656 if (can_create_pseudo_p ())
2657 return force_reg (Pmode
, value
);
2660 loongarch_emit_move (dest
, value
);
2665 /* Wrap symbol or label BASE in an UNSPEC address of type SYMBOL_TYPE,
2666 then add CONST_INT OFFSET to the result. */
2669 loongarch_unspec_address_offset (rtx base
, rtx offset
,
2670 enum loongarch_symbol_type symbol_type
)
2672 base
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, base
),
2673 UNSPEC_ADDRESS_FIRST
+ symbol_type
);
2674 if (offset
!= const0_rtx
)
2675 base
= gen_rtx_PLUS (Pmode
, base
, offset
);
2676 return gen_rtx_CONST (Pmode
, base
);
2679 /* Return an UNSPEC address with underlying address ADDRESS and symbol
2680 type SYMBOL_TYPE. */
2683 loongarch_unspec_address (rtx address
, enum loongarch_symbol_type symbol_type
)
2687 split_const (address
, &base
, &offset
);
2688 return loongarch_unspec_address_offset (base
, offset
, symbol_type
);
2691 /* Emit an instruction of the form (set TARGET SRC). */
2694 loongarch_emit_set (rtx target
, rtx src
)
2696 emit_insn (gen_rtx_SET (target
, src
));
2700 /* If OP is an UNSPEC address, return the address to which it refers,
2701 otherwise return OP itself. */
2704 loongarch_strip_unspec_address (rtx op
)
2708 split_const (op
, &base
, &offset
);
2709 if (UNSPEC_ADDRESS_P (base
))
2710 op
= plus_constant (Pmode
, UNSPEC_ADDRESS (base
), INTVAL (offset
));
2714 /* Return a legitimate address for REG + OFFSET. TEMP is as for
2715 loongarch_force_temporary; it is only needed when OFFSET is not a
2719 loongarch_add_offset (rtx temp
, rtx reg
, HOST_WIDE_INT offset
)
2721 if (!IMM12_OPERAND (offset
))
2725 /* Leave OFFSET as a 12-bit offset and put the excess in HIGH.
2726 The addition inside the macro CONST_HIGH_PART may cause an
2727 overflow, so we need to force a sign-extension check. */
2728 high
= gen_int_mode (CONST_HIGH_PART (offset
), Pmode
);
2729 offset
= CONST_LOW_PART (offset
);
2730 high
= loongarch_force_temporary (temp
, high
);
2731 reg
= loongarch_force_temporary (temp
, gen_rtx_PLUS (Pmode
, high
, reg
));
2733 return plus_constant (Pmode
, reg
, offset
);
2736 /* The __tls_get_attr symbol. */
2737 static GTY (()) rtx loongarch_tls_symbol
;
2739 /* Load an entry for a TLS access. */
2742 loongarch_load_tls (rtx dest
, rtx sym
)
2744 return gen_load_tls (Pmode
, dest
, sym
);
2747 /* Return an instruction sequence that calls __tls_get_addr. SYM is
2748 the TLS symbol we are referencing and TYPE is the symbol type to use
2749 (either global dynamic or local dynamic). V0 is an RTX for the
2750 return value location. */
2753 loongarch_call_tls_get_addr (rtx sym
, enum loongarch_symbol_type type
, rtx v0
)
2757 rtx tmp
= gen_reg_rtx (Pmode
);
2759 a0
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
);
2761 if (!loongarch_tls_symbol
)
2762 loongarch_tls_symbol
= init_one_libfunc ("__tls_get_addr");
2764 loc
= loongarch_unspec_address (sym
, type
);
2768 if (la_opt_explicit_relocs
== EXPLICIT_RELOCS_ALWAYS
)
2770 /* Split tls symbol to high and low. */
2771 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (loc
));
2772 high
= loongarch_force_temporary (tmp
, high
);
2774 if (TARGET_CMODEL_EXTREME
)
2776 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2778 rtx tmp1
= gen_reg_rtx (Pmode
);
2779 emit_insn (gen_tls_low (Pmode
, tmp1
, gen_rtx_REG (Pmode
, 0), loc
));
2780 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, loc
));
2781 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, loc
));
2782 emit_move_insn (a0
, gen_rtx_PLUS (Pmode
, high
, tmp1
));
2785 emit_insn (gen_tls_low (Pmode
, a0
, high
, loc
));
2788 emit_insn (loongarch_load_tls (a0
, loc
));
2792 switch (la_target
.cmodel
)
2795 insn
= emit_call_insn (gen_call_value_internal (v0
,
2796 loongarch_tls_symbol
,
2802 rtx reg
= gen_reg_rtx (Pmode
);
2803 if (TARGET_EXPLICIT_RELOCS
)
2805 emit_insn (gen_pcalau12i (Pmode
, reg
, loongarch_tls_symbol
));
2806 rtx call
= gen_call_value_internal_1 (Pmode
, v0
, reg
,
2807 loongarch_tls_symbol
,
2809 insn
= emit_call_insn (call
);
2813 emit_move_insn (reg
, loongarch_tls_symbol
);
2814 insn
= emit_call_insn (gen_call_value_internal (v0
,
2821 /* code model extreme not support plt. */
2822 case CMODEL_EXTREME
:
2825 case CMODEL_TINY_STATIC
:
2832 rtx dest
= gen_reg_rtx (Pmode
);
2834 switch (la_target
.cmodel
)
2839 if (TARGET_EXPLICIT_RELOCS
)
2841 rtx high
= gen_reg_rtx (Pmode
);
2842 loongarch_emit_move (high
,
2843 gen_rtx_HIGH (Pmode
,
2844 loongarch_tls_symbol
));
2845 emit_insn (gen_ld_from_got (Pmode
, dest
, high
,
2846 loongarch_tls_symbol
));
2849 loongarch_emit_move (dest
, loongarch_tls_symbol
);
2853 case CMODEL_EXTREME
:
2855 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2857 rtx tmp1
= gen_reg_rtx (Pmode
);
2858 rtx high
= gen_reg_rtx (Pmode
);
2860 loongarch_emit_move (high
,
2861 gen_rtx_HIGH (Pmode
, loongarch_tls_symbol
));
2862 loongarch_emit_move (tmp1
, gen_rtx_LO_SUM (Pmode
,
2863 gen_rtx_REG (Pmode
, 0),
2864 loongarch_tls_symbol
));
2865 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, loongarch_tls_symbol
));
2866 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, loongarch_tls_symbol
));
2867 loongarch_emit_move (dest
,
2869 gen_rtx_PLUS (Pmode
,
2876 case CMODEL_TINY_STATIC
:
2881 insn
= emit_call_insn (gen_call_value_internal (v0
, dest
, const0_rtx
));
2884 RTL_CONST_CALL_P (insn
) = 1;
2885 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), a0
);
2886 insn
= get_insns ();
2893 /* Generate the code to access LOC, a thread-local SYMBOL_REF, and return
2894 its address. The return value will be both a valid address and a valid
2895 SET_SRC (either a REG or a LO_SUM). */
2898 loongarch_legitimize_tls_address (rtx loc
)
2900 rtx dest
, tp
, tmp
, tmp1
, tmp2
, tmp3
;
2901 enum tls_model model
= SYMBOL_REF_TLS_MODEL (loc
);
2906 case TLS_MODEL_LOCAL_DYNAMIC
:
2907 tmp
= gen_rtx_REG (Pmode
, GP_RETURN
);
2908 dest
= gen_reg_rtx (Pmode
);
2909 insn
= loongarch_call_tls_get_addr (loc
, SYMBOL_TLSLDM
, tmp
);
2910 emit_libcall_block (insn
, dest
, tmp
, loc
);
2913 case TLS_MODEL_GLOBAL_DYNAMIC
:
2914 tmp
= gen_rtx_REG (Pmode
, GP_RETURN
);
2915 dest
= gen_reg_rtx (Pmode
);
2916 insn
= loongarch_call_tls_get_addr (loc
, SYMBOL_TLSGD
, tmp
);
2917 emit_libcall_block (insn
, dest
, tmp
, loc
);
2920 case TLS_MODEL_INITIAL_EXEC
:
2922 /* la.tls.ie; tp-relative add. */
2923 tp
= gen_rtx_REG (Pmode
, THREAD_POINTER_REGNUM
);
2924 tmp1
= gen_reg_rtx (Pmode
);
2925 tmp2
= loongarch_unspec_address (loc
, SYMBOL_TLS_IE
);
2926 dest
= gen_reg_rtx (Pmode
);
2927 if (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_NONE
)
2929 tmp3
= gen_reg_rtx (Pmode
);
2930 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (tmp2
));
2931 high
= loongarch_force_temporary (tmp3
, high
);
2933 if (TARGET_CMODEL_EXTREME
)
2935 gcc_assert (TARGET_EXPLICIT_RELOCS
);
2937 rtx tmp3
= gen_reg_rtx (Pmode
);
2938 emit_insn (gen_tls_low (Pmode
, tmp3
,
2939 gen_rtx_REG (Pmode
, 0), tmp2
));
2940 emit_insn (gen_lui_h_lo20 (tmp3
, tmp3
, tmp2
));
2941 emit_insn (gen_lui_h_hi12 (tmp3
, tmp3
, tmp2
));
2942 emit_move_insn (tmp1
,
2944 gen_rtx_PLUS (Pmode
,
2948 emit_insn (gen_ld_from_got (Pmode
, tmp1
, high
, tmp2
));
2951 emit_insn (loongarch_load_tls (tmp1
, tmp2
));
2952 emit_insn (gen_add3_insn (dest
, tmp1
, tp
));
2956 case TLS_MODEL_LOCAL_EXEC
:
2958 /* la.tls.le; tp-relative add.
2961 lu12i.w $rd, %le_hi20(sym)
2962 ori $rd, $rd, %le_lo12(sym)
2963 add.{w/d} $rd, $rd, $tp
2964 (st.{w/d}/ld.{w/d} $rs, $rd, 0)
2967 lu12i.w $rd, %le_hi20_r(sym)
2968 add.{w/d} $rd,$rd,$tp
2969 addi.{w/d} $rd,$rd,%le_lo12_r(sym)
2970 (st.{w/d}/ld.{w/d} $rs, $rd, 0)
2972 extreme (When the code model is set to extreme, the TLS le Relax
2973 instruction sequence is not generated):
2974 lu12i.w $rd, %le_hi20(sym)
2975 ori $rd, $rd, %le_lo12(sym)
2976 lu32i.d $rd, %le64_lo20(sym)
2977 lu52i.d $rd, $rd, %le64_hi12(sym)
2979 (st.{w/d}/ld.{w/d} $rs, $rd, 0) */
2981 tp
= gen_rtx_REG (Pmode
, THREAD_POINTER_REGNUM
);
2982 tmp1
= gen_reg_rtx (Pmode
);
2983 tmp2
= loongarch_unspec_address (loc
, SYMBOL_TLS_LE
);
2984 dest
= gen_reg_rtx (Pmode
);
2986 if (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_NONE
)
2988 tmp3
= gen_reg_rtx (Pmode
);
2989 rtx high
= gen_rtx_HIGH (Pmode
, copy_rtx (tmp2
));
2990 high
= loongarch_force_temporary (tmp3
, high
);
2992 /* The assembler does not implement tls le relax support when the
2993 code model is extreme, so when the code model is extreme, the
2994 old symbol address acquisition method is still used. */
2995 if (HAVE_AS_TLS_LE_RELAXATION
&& !TARGET_CMODEL_EXTREME
)
2997 emit_insn (gen_add_tls_le_relax (Pmode
, dest
, high
,
2999 loongarch_emit_move (dest
,
3000 gen_rtx_LO_SUM (Pmode
, dest
, tmp2
));
3004 emit_insn (gen_ori_l_lo12 (Pmode
, tmp1
, high
, tmp2
));
3006 if (TARGET_CMODEL_EXTREME
)
3008 gcc_assert (TARGET_EXPLICIT_RELOCS
);
3010 emit_insn (gen_lui_h_lo20 (tmp1
, tmp1
, tmp2
));
3011 emit_insn (gen_lui_h_hi12 (tmp1
, tmp1
, tmp2
));
3015 emit_insn (loongarch_load_tls (tmp1
, tmp2
));
3016 emit_insn (gen_add3_insn (dest
, tmp1
, tp
));
3027 loongarch_legitimize_call_address (rtx addr
)
3029 if (!call_insn_operand (addr
, VOIDmode
))
3031 rtx reg
= gen_reg_rtx (Pmode
);
3032 loongarch_emit_move (reg
, addr
);
3036 enum loongarch_symbol_type symbol_type
= loongarch_classify_symbol (addr
);
3038 /* If add the compilation option '-cmodel=medium', and the assembler does
3039 not support call36. The following sequence of instructions will be
3040 used for the function call:
3041 pcalau12i $rd, %pc_hi20(sym)
3042 jr $rd, %pc_lo12(sym)
3045 if (TARGET_CMODEL_MEDIUM
3046 && !HAVE_AS_SUPPORT_CALL36
3047 && (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_NONE
)
3048 && (SYMBOL_REF_P (addr
) || LABEL_REF_P (addr
))
3049 && (symbol_type
== SYMBOL_PCREL
3050 || (symbol_type
== SYMBOL_GOT_DISP
&& flag_plt
)))
3052 rtx reg
= gen_reg_rtx (Pmode
);
3053 emit_insn (gen_pcalau12i (Pmode
, reg
, addr
));
3054 return gen_rtx_LO_SUM (Pmode
, reg
, addr
);
3060 /* If X is a PLUS of a CONST_INT, return the two terms in *BASE_PTR
3061 and *OFFSET_PTR. Return X in *BASE_PTR and 0 in *OFFSET_PTR otherwise. */
3064 loongarch_split_plus (rtx x
, rtx
*base_ptr
, HOST_WIDE_INT
*offset_ptr
)
3066 if (GET_CODE (x
) == PLUS
&& CONST_INT_P (XEXP (x
, 1)))
3068 *base_ptr
= XEXP (x
, 0);
3069 *offset_ptr
= INTVAL (XEXP (x
, 1));
3078 /* If X is not a valid address for mode MODE, force it into a register. */
3081 loongarch_force_address (rtx x
, machine_mode mode
)
3083 if (!loongarch_legitimate_address_p (mode
, x
, false))
3084 x
= force_reg (Pmode
, x
);
3089 loongarch_symbol_extreme_p (enum loongarch_symbol_type type
)
3095 case SYMBOL_PCREL64
:
3098 return TARGET_CMODEL_EXTREME
;
3102 /* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
3103 it appears in a MEM of that mode. Return true if ADDR is a legitimate
3104 constant in that context and can be split into high and low parts.
3105 If so, and if LOW_OUT is nonnull, emit the high part and store the
3106 low part in *LOW_OUT. Leave *LOW_OUT unchanged otherwise.
3108 Return false if build with '-mexplicit-relocs=none'.
3110 TEMP is as for loongarch_force_temporary and is used to load the high
3111 part into a register.
3113 When MODE is MAX_MACHINE_MODE, the low part is guaranteed to be
3114 a legitimize SET_SRC for an .md pattern, otherwise the low part
3115 is guaranteed to be a legitimate address for mode MODE. */
3118 loongarch_split_symbol (rtx temp
, rtx addr
, machine_mode mode
, rtx
*low_out
)
3120 enum loongarch_symbol_type symbol_type
;
3122 if ((GET_CODE (addr
) == HIGH
&& mode
== MAX_MACHINE_MODE
)
3123 || !loongarch_symbolic_constant_p (addr
, &symbol_type
)
3124 || !loongarch_explicit_relocs_p (symbol_type
)
3125 || loongarch_symbol_insns (symbol_type
, mode
) == 0
3126 || !loongarch_split_symbol_type (symbol_type
))
3129 rtx high
, temp1
= NULL
;
3132 temp
= gen_reg_rtx (Pmode
);
3134 /* Get the 12-31 bits of the address. */
3135 high
= gen_rtx_HIGH (Pmode
, copy_rtx (addr
));
3136 high
= loongarch_force_temporary (temp
, high
);
3138 if (loongarch_symbol_extreme_p (symbol_type
) && can_create_pseudo_p ())
3140 gcc_assert (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_NONE
);
3142 temp1
= gen_reg_rtx (Pmode
);
3143 emit_move_insn (temp1
, gen_rtx_LO_SUM (Pmode
, gen_rtx_REG (Pmode
, 0),
3145 emit_insn (gen_lui_h_lo20 (temp1
, temp1
, addr
));
3146 emit_insn (gen_lui_h_hi12 (temp1
, temp1
, addr
));
3150 switch (symbol_type
)
3152 case SYMBOL_PCREL64
:
3153 if (can_create_pseudo_p ())
3155 *low_out
= gen_rtx_PLUS (Pmode
, high
, temp1
);
3160 *low_out
= gen_rtx_LO_SUM (Pmode
, high
, addr
);
3163 case SYMBOL_GOT_DISP
:
3164 /* SYMBOL_GOT_DISP symbols are loaded from the GOT. */
3166 if (TARGET_CMODEL_EXTREME
&& can_create_pseudo_p ())
3167 *low_out
= gen_rtx_MEM (Pmode
, gen_rtx_PLUS (Pmode
, high
, temp1
));
3170 rtx low
= gen_rtx_LO_SUM (Pmode
, high
, addr
);
3171 rtx mem
= gen_rtx_MEM (Pmode
, low
);
3172 *low_out
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, mem
),
3173 UNSPEC_LOAD_FROM_GOT
);
3175 /* Nonzero in a mem, if the memory is statically allocated and
3176 read-only. A common example of the later is a shared library’s
3177 global offset table. */
3178 MEM_READONLY_P (mem
) = 1;
3191 /* Helper loongarch_legitimize_address. Given X, return true if it
3192 is a left shift by 1, 2 or 3 positions or a multiply by 2, 4 or 8.
3194 This respectively represent canonical shift-add rtxs or scaled
3195 memory addresses. */
3197 mem_shadd_or_shadd_rtx_p (rtx x
)
3199 return ((GET_CODE (x
) == ASHIFT
3200 || GET_CODE (x
) == MULT
)
3201 && CONST_INT_P (XEXP (x
, 1))
3202 && ((GET_CODE (x
) == ASHIFT
&& IN_RANGE (INTVAL (XEXP (x
, 1)), 1, 3))
3203 || (GET_CODE (x
) == MULT
3204 && IN_RANGE (exact_log2 (INTVAL (XEXP (x
, 1))), 1, 3))));
3207 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
3208 be legitimized in a way that the generic machinery might not expect,
3209 return a new address, otherwise return NULL. MODE is the mode of
3210 the memory being accessed. */
3213 loongarch_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
3217 HOST_WIDE_INT offset
;
3219 if (loongarch_tls_symbol_p (x
))
3220 return loongarch_legitimize_tls_address (x
);
3222 /* See if the address can split into a high part and a LO_SUM. */
3223 if (loongarch_split_symbol (NULL
, x
, mode
, &addr
))
3224 return loongarch_force_address (addr
, mode
);
3226 /* Handle BASE + OFFSET using loongarch_add_offset. */
3227 loongarch_split_plus (x
, &base
, &offset
);
3230 /* Handle (plus (plus (mult (a) (mem_shadd_constant)) (fp)) (C)) case. */
3231 if (GET_CODE (base
) == PLUS
&& mem_shadd_or_shadd_rtx_p (XEXP (base
, 0))
3232 && IMM12_OPERAND (offset
))
3234 rtx index
= XEXP (base
, 0);
3235 rtx fp
= XEXP (base
, 1);
3237 if (REG_P (fp
) && REGNO (fp
) == VIRTUAL_STACK_VARS_REGNUM
)
3239 /* If we were given a MULT, we must fix the constant
3240 as we're going to create the ASHIFT form. */
3241 int shift_val
= INTVAL (XEXP (index
, 1));
3242 if (GET_CODE (index
) == MULT
)
3243 shift_val
= exact_log2 (shift_val
);
3245 rtx reg1
= gen_reg_rtx (Pmode
);
3246 rtx reg3
= gen_reg_rtx (Pmode
);
3247 loongarch_emit_binary (PLUS
, reg1
, fp
, GEN_INT (offset
));
3248 loongarch_emit_binary (PLUS
, reg3
,
3249 gen_rtx_ASHIFT (Pmode
, XEXP (index
, 0),
3250 GEN_INT (shift_val
)),
3257 if (!loongarch_valid_base_register_p (base
, mode
, false))
3258 base
= copy_to_mode_reg (Pmode
, base
);
3259 addr
= loongarch_add_offset (NULL
, base
, offset
);
3260 return loongarch_force_address (addr
, mode
);
3266 /* Load VALUE into DEST. TEMP is as for loongarch_force_temporary. */
3269 loongarch_move_integer (rtx temp
, rtx dest
, unsigned HOST_WIDE_INT value
)
3271 struct loongarch_integer_op codes
[LARCH_MAX_INTEGER_OPS
];
3273 unsigned int i
, num_ops
;
3276 mode
= GET_MODE (dest
);
3277 num_ops
= loongarch_build_integer (codes
, value
);
3279 /* Apply each binary operation to X. Invariant: X is a legitimate
3280 source operand for a SET pattern. */
3281 x
= GEN_INT (codes
[0].value
);
3282 for (i
= 1; i
< num_ops
; i
++)
3284 if (!can_create_pseudo_p ())
3286 emit_insn (gen_rtx_SET (temp
, x
));
3290 x
= force_reg (mode
, x
);
3292 set_unique_reg_note (get_last_insn (), REG_EQUAL
,
3293 GEN_INT (codes
[i
-1].curr_value
));
3295 switch (codes
[i
].method
)
3298 x
= gen_rtx_fmt_ee (codes
[i
].code
, mode
, x
,
3299 GEN_INT (codes
[i
].value
));
3302 gcc_assert (mode
== DImode
);
3303 x
= gen_rtx_IOR (DImode
,
3304 gen_rtx_ZERO_EXTEND (DImode
,
3305 gen_rtx_SUBREG (SImode
, x
, 0)),
3306 GEN_INT (codes
[i
].value
));
3309 gcc_assert (mode
== DImode
);
3310 x
= gen_rtx_IOR (DImode
,
3311 gen_rtx_AND (DImode
, x
, GEN_INT (0xfffffffffffff)),
3312 GEN_INT (codes
[i
].value
));
3315 gcc_assert (mode
== DImode
);
3316 emit_insn (gen_insvdi (x
, GEN_INT (32), GEN_INT (32), x
));
3323 emit_insn (gen_rtx_SET (dest
, x
));
3326 /* Subroutine of loongarch_legitimize_move. Move constant SRC into register
3327 DEST given that SRC satisfies immediate_operand but doesn't satisfy
3331 loongarch_legitimize_const_move (machine_mode mode
, rtx dest
, rtx src
)
3335 /* Split moves of big integers into smaller pieces. */
3336 if (splittable_const_int_operand (src
, mode
))
3338 loongarch_move_integer (dest
, dest
, INTVAL (src
));
3342 /* Split moves of symbolic constants into high and low. */
3343 if (loongarch_split_symbol (dest
, src
, MAX_MACHINE_MODE
, &src
))
3345 loongarch_emit_set (dest
, src
);
3349 /* Generate the appropriate access sequences for TLS symbols. */
3350 if (loongarch_tls_symbol_p (src
))
3352 loongarch_emit_move (dest
, loongarch_legitimize_tls_address (src
));
3356 /* If we have (const (plus symbol offset)), and that expression cannot
3357 be forced into memory, load the symbol first and add in the offset.
3358 prefer to do this even if the constant _can_ be forced into memory,
3359 as it usually produces better code. */
3360 split_const (src
, &base
, &offset
);
3361 if (offset
!= const0_rtx
3362 && (targetm
.cannot_force_const_mem (mode
, src
)
3363 || (can_create_pseudo_p ())))
3365 base
= loongarch_force_temporary (dest
, base
);
3366 loongarch_emit_move (dest
,
3367 loongarch_add_offset (NULL
, base
, INTVAL (offset
)));
3371 src
= force_const_mem (mode
, src
);
3373 loongarch_emit_move (dest
, src
);
3376 /* If (set DEST SRC) is not a valid move instruction, emit an equivalent
3377 sequence that is valid. */
3380 loongarch_legitimize_move (machine_mode mode
, rtx dest
, rtx src
)
3382 if (!register_operand (dest
, mode
) && !reg_or_0_operand (src
, mode
))
3384 loongarch_emit_move (dest
, force_reg (mode
, src
));
3388 /* Both src and dest are non-registers; one special case is supported where
3389 the source is (const_int 0) and the store can source the zero register.
3390 LSX and LASX are never able to source the zero register directly in
3391 memory operations. */
3392 if (!register_operand (dest
, mode
) && !register_operand (src
, mode
)
3393 && (!const_0_operand (src
, mode
)
3394 || LSX_SUPPORTED_MODE_P (mode
) || LASX_SUPPORTED_MODE_P (mode
)))
3396 loongarch_emit_move (dest
, force_reg (mode
, src
));
3400 /* We need to deal with constants that would be legitimate
3401 immediate_operands but aren't legitimate move_operands. */
3402 if (CONSTANT_P (src
) && !move_operand (src
, mode
))
3404 loongarch_legitimize_const_move (mode
, dest
, src
);
3405 set_unique_reg_note (get_last_insn (), REG_EQUAL
, copy_rtx (src
));
3412 /* Return true if OP refers to small data symbols directly. */
3415 loongarch_small_data_pattern_1 (rtx x
)
3417 subrtx_var_iterator::array_type array
;
3418 FOR_EACH_SUBRTX_VAR (iter
, array
, x
, ALL
)
3422 /* We make no particular guarantee about which symbolic constants are
3423 acceptable as asm operands versus which must be forced into a GPR. */
3424 if (GET_CODE (x
) == ASM_OPERANDS
)
3425 iter
.skip_subrtxes ();
3428 if (loongarch_small_data_pattern_1 (XEXP (x
, 0)))
3430 iter
.skip_subrtxes ();
3436 /* Return true if OP refers to small data symbols directly. */
3439 loongarch_small_data_pattern_p (rtx op
)
3441 return loongarch_small_data_pattern_1 (op
);
3444 /* Rewrite *LOC so that it refers to small data using explicit
3448 loongarch_rewrite_small_data_1 (rtx
*loc
)
3450 subrtx_ptr_iterator::array_type array
;
3451 FOR_EACH_SUBRTX_PTR (iter
, array
, loc
, ALL
)
3456 loongarch_rewrite_small_data_1 (&XEXP (*loc
, 0));
3457 iter
.skip_subrtxes ();
3462 /* Rewrite instruction pattern PATTERN so that it refers to small data
3463 using explicit relocations. */
3466 loongarch_rewrite_small_data (rtx pattern
)
3468 pattern
= copy_insn (pattern
);
3469 loongarch_rewrite_small_data_1 (&pattern
);
3473 /* The cost of loading values from the constant pool. It should be
3474 larger than the cost of any constant we want to synthesize inline. */
3475 #define CONSTANT_POOL_COST COSTS_N_INSNS (8)
3477 /* Return true if there is a instruction that implements CODE
3478 and if that instruction accepts X as an immediate operand. */
3481 loongarch_immediate_operand_p (int code
, HOST_WIDE_INT x
)
3488 /* All shift counts are truncated to a valid constant. */
3498 /* These instructions take 12-bit unsigned immediates. */
3499 return IMM12_OPERAND_UNSIGNED (x
);
3504 /* These instructions take 12-bit signed immediates. */
3505 return IMM12_OPERAND (x
);
3511 /* The "immediate" forms of these instructions are really
3512 implemented as comparisons with register 0. */
3517 /* Likewise, meaning that the only valid immediate operand is 1. */
3521 /* We add 1 to the immediate and use SLT. */
3522 return IMM12_OPERAND (x
+ 1);
3525 /* Likewise SLTU, but reject the always-true case. */
3526 return IMM12_OPERAND (x
+ 1) && x
+ 1 != 0;
3530 /* The bit position and size are immediate operands. */
3534 /* By default assume that $0 can be used for 0. */
3539 /* Return the cost of binary operation X, given that the instruction
3540 sequence for a word-sized or smaller operation has cost SINGLE_COST
3541 and that the sequence of a double-word operation has cost DOUBLE_COST.
3542 If SPEED is true, optimize for speed otherwise optimize for size. */
3545 loongarch_binary_cost (rtx x
, int single_cost
, int double_cost
, bool speed
)
3549 if (GET_MODE_SIZE (GET_MODE (x
)) == UNITS_PER_WORD
* 2)
3554 + set_src_cost (XEXP (x
, 0), GET_MODE (x
), speed
)
3555 + rtx_cost (XEXP (x
, 1), GET_MODE (x
), GET_CODE (x
), 1, speed
));
3558 /* Return the cost of floating-point multiplications of mode MODE. */
3561 loongarch_fp_mult_cost (machine_mode mode
)
3563 return mode
== DFmode
? loongarch_cost
->fp_mult_df
3564 : loongarch_cost
->fp_mult_sf
;
3567 /* Return the cost of floating-point divisions of mode MODE. */
3570 loongarch_fp_div_cost (machine_mode mode
)
3572 return mode
== DFmode
? loongarch_cost
->fp_div_df
3573 : loongarch_cost
->fp_div_sf
;
3576 /* Return the cost of sign-extending OP to mode MODE, not including the
3577 cost of OP itself. */
3580 loongarch_sign_extend_cost (rtx op
)
3583 /* Extended loads are as cheap as unextended ones. */
3586 return COSTS_N_INSNS (1);
3589 /* Return the cost of zero-extending OP to mode MODE, not including the
3590 cost of OP itself. */
3593 loongarch_zero_extend_cost (rtx op
)
3596 /* Extended loads are as cheap as unextended ones. */
3599 /* We can use ANDI. */
3600 return COSTS_N_INSNS (1);
3603 /* Return the cost of moving between two registers of mode MODE,
3604 assuming that the move will be in pieces of at most UNITS bytes. */
3607 loongarch_set_reg_reg_piece_cost (machine_mode mode
, unsigned int units
)
3609 return COSTS_N_INSNS ((GET_MODE_SIZE (mode
) + units
- 1) / units
);
3612 /* Return the cost of moving between two registers of mode MODE. */
3615 loongarch_set_reg_reg_cost (machine_mode mode
)
3617 switch (GET_MODE_CLASS (mode
))
3620 return loongarch_set_reg_reg_piece_cost (mode
, GET_MODE_SIZE (CCmode
));
3623 case MODE_COMPLEX_FLOAT
:
3624 case MODE_VECTOR_FLOAT
:
3625 if (TARGET_HARD_FLOAT
)
3626 return loongarch_set_reg_reg_piece_cost (mode
, UNITS_PER_HWFPVALUE
);
3630 return loongarch_set_reg_reg_piece_cost (mode
, UNITS_PER_WORD
);
3634 /* Implement TARGET_RTX_COSTS. */
3637 loongarch_rtx_costs (rtx x
, machine_mode mode
, int outer_code
,
3638 int opno ATTRIBUTE_UNUSED
, int *total
, bool speed
)
3640 int code
= GET_CODE (x
);
3641 bool float_mode_p
= FLOAT_MODE_P (mode
);
3645 if (outer_code
== COMPARE
)
3647 gcc_assert (CONSTANT_P (x
));
3655 if (TARGET_64BIT
&& outer_code
== AND
&& UINTVAL (x
) == 0xffffffff)
3661 /* When not optimizing for size, we care more about the cost
3662 of hot code, and hot code is often in a loop. If a constant
3663 operand needs to be forced into a register, we will often be
3664 able to hoist the constant load out of the loop, so the load
3665 should not contribute to the cost. */
3666 if (speed
|| loongarch_immediate_operand_p (outer_code
, INTVAL (x
)))
3677 cost
= loongarch_const_insns (x
);
3680 if (cost
== 1 && outer_code
== SET
3681 && !(float_mode_p
&& TARGET_HARD_FLOAT
))
3683 else if ((outer_code
== SET
|| GET_MODE (x
) == VOIDmode
))
3685 *total
= COSTS_N_INSNS (cost
);
3688 /* The value will need to be fetched from the constant pool. */
3689 *total
= CONSTANT_POOL_COST
;
3693 /* If the address is legitimate, return the number of
3694 instructions it needs. */
3696 /* Check for a scaled indexed address. */
3697 if (loongarch_index_address_p (addr
, mode
))
3699 *total
= COSTS_N_INSNS (2);
3702 cost
= loongarch_address_insns (addr
, mode
, true);
3705 *total
= COSTS_N_INSNS (cost
+ 1);
3708 /* Otherwise use the default handling. */
3712 *total
= COSTS_N_INSNS (6);
3716 *total
= COSTS_N_INSNS (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 2 : 1);
3720 /* Check for a *clear_upper32 pattern and treat it like a zero
3721 extension. See the pattern's comment for details. */
3722 if (TARGET_64BIT
&& mode
== DImode
&& CONST_INT_P (XEXP (x
, 1))
3723 && UINTVAL (XEXP (x
, 1)) == 0xffffffff)
3725 *total
= (loongarch_zero_extend_cost (XEXP (x
, 0))
3726 + set_src_cost (XEXP (x
, 0), mode
, speed
));
3729 /* (AND (NOT op0) (NOT op1) is a nor operation that can be done in
3730 a single instruction. */
3731 if (GET_CODE (XEXP (x
, 0)) == NOT
&& GET_CODE (XEXP (x
, 1)) == NOT
)
3733 cost
= GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 2 : 1;
3734 *total
= (COSTS_N_INSNS (cost
)
3735 + set_src_cost (XEXP (XEXP (x
, 0), 0), mode
, speed
)
3736 + set_src_cost (XEXP (XEXP (x
, 1), 0), mode
, speed
));
3744 /* Double-word operations use two single-word operations. */
3745 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (2),
3754 if (CONSTANT_P (XEXP (x
, 1)))
3755 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1),
3756 COSTS_N_INSNS (4), speed
);
3758 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1),
3759 COSTS_N_INSNS (12), speed
);
3764 *total
= loongarch_cost
->fp_add
;
3766 *total
= COSTS_N_INSNS (4);
3785 /* Branch comparisons have VOIDmode, so use the first operand's
3787 mode
= GET_MODE (XEXP (x
, 0));
3788 if (FLOAT_MODE_P (mode
))
3790 *total
= loongarch_cost
->fp_add
;
3793 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (4),
3801 *total
= loongarch_cost
->fp_add
;
3805 /* If it's an add + mult (which is equivalent to shift left) and
3806 it's immediate operand satisfies const_immalsl_operand predicate. */
3807 if ((mode
== SImode
|| (TARGET_64BIT
&& mode
== DImode
))
3808 && GET_CODE (XEXP (x
, 0)) == MULT
)
3810 rtx op2
= XEXP (XEXP (x
, 0), 1);
3811 if (const_immalsl_operand (op2
, mode
))
3813 *total
= (COSTS_N_INSNS (1)
3814 + set_src_cost (XEXP (XEXP (x
, 0), 0), mode
, speed
)
3815 + set_src_cost (XEXP (x
, 1), mode
, speed
));
3820 /* Double-word operations require three single-word operations and
3822 *total
= loongarch_binary_cost (x
, COSTS_N_INSNS (1), COSTS_N_INSNS (4),
3828 *total
= loongarch_cost
->fp_add
;
3830 *total
= COSTS_N_INSNS (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
? 4 : 1);
3834 *total
= loongarch_fp_mult_cost (mode
);
3839 *total
= loongarch_fp_mult_cost (mode
);
3840 else if (mode
== DImode
&& !TARGET_64BIT
)
3842 ? loongarch_cost
->int_mult_si
* 3 + 6
3843 : COSTS_N_INSNS (7));
3844 else if (mode
== DImode
)
3845 *total
= loongarch_cost
->int_mult_di
;
3847 *total
= loongarch_cost
->int_mult_si
;
3851 /* Check for a reciprocal. */
3853 && flag_unsafe_math_optimizations
3854 && XEXP (x
, 0) == CONST1_RTX (mode
))
3856 if (outer_code
== SQRT
|| GET_CODE (XEXP (x
, 1)) == SQRT
)
3857 /* An rsqrt<mode>a or rsqrt<mode>b pattern. Count the
3858 division as being free. */
3859 *total
= set_src_cost (XEXP (x
, 1), mode
, speed
);
3861 *total
= (loongarch_fp_div_cost (mode
)
3862 + set_src_cost (XEXP (x
, 1), mode
, speed
));
3871 *total
= loongarch_fp_div_cost (mode
);
3879 *total
= loongarch_cost
->int_div_di
;
3882 *total
= loongarch_cost
->int_div_si
;
3883 if (TARGET_64BIT
&& !ISA_HAS_DIV32
)
3884 *total
+= COSTS_N_INSNS (2);
3887 if (TARGET_CHECK_ZERO_DIV
)
3888 *total
+= COSTS_N_INSNS (2);
3893 *total
= loongarch_sign_extend_cost (XEXP (x
, 0));
3897 *total
= loongarch_zero_extend_cost (XEXP (x
, 0));
3900 /* Costings for highpart multiplies. Matching patterns of the form:
3902 (lshiftrt:DI (mult:DI (sign_extend:DI (...)
3903 (sign_extend:DI (...))
3906 if ((GET_CODE (XEXP (x
, 0)) == ASHIFTRT
3907 || GET_CODE (XEXP (x
, 0)) == LSHIFTRT
)
3908 && CONST_INT_P (XEXP (XEXP (x
, 0), 1))
3909 && ((INTVAL (XEXP (XEXP (x
, 0), 1)) == 32
3910 && GET_MODE (XEXP (x
, 0)) == DImode
)
3912 && INTVAL (XEXP (XEXP (x
, 0), 1)) == 64
3913 && GET_MODE (XEXP (x
, 0)) == TImode
))
3914 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == MULT
3915 && ((GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 0)) == SIGN_EXTEND
3916 && GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 1)) == SIGN_EXTEND
)
3917 || (GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 0)) == ZERO_EXTEND
3918 && (GET_CODE (XEXP (XEXP (XEXP (x
, 0), 0), 1))
3922 *total
= loongarch_cost
->int_mult_di
;
3924 *total
= loongarch_cost
->int_mult_si
;
3926 /* Sign extension is free, zero extension costs for DImode when
3927 on a 64bit core / when DMUL is present. */
3928 for (int i
= 0; i
< 2; ++i
)
3930 rtx op
= XEXP (XEXP (XEXP (x
, 0), 0), i
);
3932 && GET_CODE (op
) == ZERO_EXTEND
3933 && GET_MODE (op
) == DImode
)
3934 *total
+= rtx_cost (op
, DImode
, MULT
, i
, speed
);
3936 *total
+= rtx_cost (XEXP (op
, 0), VOIDmode
, GET_CODE (op
), 0,
3945 case UNSIGNED_FLOAT
:
3948 case FLOAT_TRUNCATE
:
3949 *total
= loongarch_cost
->fp_add
;
3953 if (register_operand (SET_DEST (x
), VOIDmode
)
3954 && reg_or_0_operand (SET_SRC (x
), VOIDmode
))
3956 *total
= loongarch_set_reg_reg_cost (GET_MODE (SET_DEST (x
)));
3966 /* Implement targetm.vectorize.builtin_vectorization_cost. */
3969 loongarch_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost
,
3971 int misalign ATTRIBUTE_UNUSED
)
3974 machine_mode mode
= vectype
!= NULL
? TYPE_MODE (vectype
) : DImode
;
3976 switch (type_of_cost
)
3986 case vec_promote_demote
:
3988 return LASX_SUPPORTED_MODE_P (mode
)
3989 && !LSX_SUPPORTED_MODE_P (mode
) ? 2 : 1;
3993 case unaligned_load
:
3994 case unaligned_store
:
3997 case cond_branch_taken
:
4000 case cond_branch_not_taken
:
4004 elements
= TYPE_VECTOR_SUBPARTS (vectype
);
4006 return elements
+ 1;
4015 class loongarch_vector_costs
: public vector_costs
4018 using vector_costs::vector_costs
;
4020 unsigned int add_stmt_cost (int count
, vect_cost_for_stmt kind
,
4021 stmt_vec_info stmt_info
, slp_tree
, tree vectype
,
4023 vect_cost_model_location where
) override
;
4024 void finish_cost (const vector_costs
*) override
;
4027 void count_operations (vect_cost_for_stmt
, stmt_vec_info
,
4028 vect_cost_model_location
, unsigned int);
4029 unsigned int determine_suggested_unroll_factor (loop_vec_info
);
4030 /* The number of vectorized stmts in loop. */
4031 unsigned m_stmts
= 0;
4032 /* The number of load and store operations in loop. */
4033 unsigned m_loads
= 0;
4034 unsigned m_stores
= 0;
4035 /* Reduction factor for suggesting unroll factor. */
4036 unsigned m_reduc_factor
= 0;
4037 /* True if the loop contains an average operation. */
4038 bool m_has_avg
= false;
4039 /* True if the loop uses approximation instruction sequence. */
4040 bool m_has_recip
= false;
4043 /* Implement TARGET_VECTORIZE_CREATE_COSTS. */
4044 static vector_costs
*
4045 loongarch_vectorize_create_costs (vec_info
*vinfo
, bool costing_for_scalar
)
4047 return new loongarch_vector_costs (vinfo
, costing_for_scalar
);
4051 loongarch_vector_costs::count_operations (vect_cost_for_stmt kind
,
4052 stmt_vec_info stmt_info
,
4053 vect_cost_model_location where
,
4056 if (!m_costing_for_scalar
4057 && is_a
<loop_vec_info
> (m_vinfo
)
4058 && where
== vect_body
)
4062 if (kind
== scalar_load
4063 || kind
== vector_load
4064 || kind
== unaligned_load
)
4066 else if (kind
== scalar_store
4067 || kind
== vector_store
4068 || kind
== unaligned_store
)
4070 else if ((kind
== scalar_stmt
4071 || kind
== vector_stmt
4072 || kind
== vec_to_scalar
)
4073 && stmt_info
&& vect_is_reduction (stmt_info
))
4075 tree lhs
= gimple_get_lhs (stmt_info
->stmt
);
4076 unsigned int base
= FLOAT_TYPE_P (TREE_TYPE (lhs
)) ? 2 : 1;
4077 m_reduc_factor
= MAX (base
* count
, m_reduc_factor
);
4083 loongarch_vector_costs::determine_suggested_unroll_factor (loop_vec_info loop_vinfo
)
4085 class loop
*loop
= LOOP_VINFO_LOOP (loop_vinfo
);
4087 if (m_has_avg
|| m_has_recip
)
4090 /* Don't unroll if it's specified explicitly not to be unrolled. */
4091 if (loop
->unroll
== 1
4092 || (OPTION_SET_P (flag_unroll_loops
) && !flag_unroll_loops
)
4093 || (OPTION_SET_P (flag_unroll_all_loops
) && !flag_unroll_all_loops
))
4096 unsigned int nstmts_nonldst
= m_stmts
- m_loads
- m_stores
;
4097 /* Don't unroll if no vector instructions excepting for memory access. */
4098 if (nstmts_nonldst
== 0)
4101 /* Use this simple hardware resource model that how many non vld/vst
4102 vector instructions can be issued per cycle. */
4103 unsigned int issue_info
= la_vect_issue_info
;
4104 unsigned int reduc_factor
= m_reduc_factor
> 1 ? m_reduc_factor
: 1;
4105 unsigned int uf
= CEIL (reduc_factor
* issue_info
, nstmts_nonldst
);
4106 uf
= MIN ((unsigned int) la_vect_unroll_limit
, uf
);
4108 return 1 << ceil_log2 (uf
);
4112 loongarch_vector_costs::add_stmt_cost (int count
, vect_cost_for_stmt kind
,
4113 stmt_vec_info stmt_info
, slp_tree
,
4114 tree vectype
, int misalign
,
4115 vect_cost_model_location where
)
4117 unsigned retval
= 0;
4119 if (flag_vect_cost_model
)
4121 int stmt_cost
= loongarch_builtin_vectorization_cost (kind
, vectype
,
4123 retval
= adjust_cost_for_freq (stmt_info
, where
, count
* stmt_cost
);
4124 m_costs
[where
] += retval
;
4126 count_operations (kind
, stmt_info
, where
, count
);
4131 /* Detect the use of an averaging operation. */
4132 gimple
*stmt
= stmt_info
->stmt
;
4133 if (is_gimple_call (stmt
)
4134 && gimple_call_internal_p (stmt
))
4136 switch (gimple_call_internal_fn (stmt
))
4148 if (kind
== vector_stmt
4152 /* Detect the use of approximate instruction sequence. */
4153 if ((TARGET_RECIP_VEC_SQRT
|| TARGET_RECIP_VEC_RSQRT
)
4154 && (cfn
= gimple_call_combined_fn (stmt_info
->stmt
)) != CFN_LAST
)
4157 case CFN_BUILT_IN_SQRTF
:
4162 else if (TARGET_RECIP_VEC_DIV
4163 && gimple_code (stmt_info
->stmt
) == GIMPLE_ASSIGN
)
4165 machine_mode mode
= TYPE_MODE (vectype
);
4166 switch (gimple_assign_rhs_code (stmt_info
->stmt
))
4169 if (GET_MODE_INNER (mode
) == SFmode
)
4181 loongarch_vector_costs::finish_cost (const vector_costs
*scalar_costs
)
4183 loop_vec_info loop_vinfo
= dyn_cast
<loop_vec_info
> (m_vinfo
);
4186 m_suggested_unroll_factor
= determine_suggested_unroll_factor (loop_vinfo
);
4189 vector_costs::finish_cost (scalar_costs
);
4192 /* Implement TARGET_ADDRESS_COST. */
4195 loongarch_address_cost (rtx addr
, machine_mode mode
,
4196 addr_space_t as ATTRIBUTE_UNUSED
,
4197 bool speed ATTRIBUTE_UNUSED
)
4199 return loongarch_address_insns (addr
, mode
, false);
4202 /* Return one word of double-word value OP, taking into account the fixed
4203 endianness of certain registers. HIGH_P is true to select the high part,
4204 false to select the low part. */
4207 loongarch_subword (rtx op
, bool high_p
)
4212 byte
= high_p
? UNITS_PER_WORD
: 0;
4213 mode
= GET_MODE (op
);
4214 if (mode
== VOIDmode
)
4215 mode
= TARGET_64BIT
? TImode
: DImode
;
4217 if (FP_REG_RTX_P (op
))
4218 return gen_rtx_REG (word_mode
, REGNO (op
) + high_p
);
4221 return loongarch_rewrite_small_data (adjust_address (op
, word_mode
, byte
));
4223 return simplify_gen_subreg (word_mode
, op
, mode
, byte
);
4226 /* Return true if a move from SRC to DEST should be split into two.
4227 SPLIT_TYPE describes the split condition. */
4230 loongarch_split_move_p (rtx dest
, rtx src
)
4232 /* FPR-to-FPR moves can be done in a single instruction, if they're
4234 unsigned int size
= GET_MODE_SIZE (GET_MODE (dest
));
4235 if (size
== 8 && FP_REG_RTX_P (src
) && FP_REG_RTX_P (dest
))
4238 /* Check for floating-point loads and stores. */
4241 if (FP_REG_RTX_P (dest
) && MEM_P (src
))
4243 if (FP_REG_RTX_P (src
) && MEM_P (dest
))
4247 /* Check if LSX moves need splitting. */
4248 if (LSX_SUPPORTED_MODE_P (GET_MODE (dest
)))
4249 return loongarch_split_128bit_move_p (dest
, src
);
4251 /* Check if LASX moves need splitting. */
4252 if (LASX_SUPPORTED_MODE_P (GET_MODE (dest
)))
4253 return loongarch_split_256bit_move_p (dest
, src
);
4255 /* Otherwise split all multiword moves. */
4256 return size
> UNITS_PER_WORD
;
4259 /* Split a move from SRC to DEST, given that loongarch_split_move_p holds.
4260 SPLIT_TYPE describes the split condition. */
4263 loongarch_split_move (rtx dest
, rtx src
)
4267 gcc_checking_assert (loongarch_split_move_p (dest
, src
));
4268 if (LSX_SUPPORTED_MODE_P (GET_MODE (dest
)))
4269 loongarch_split_128bit_move (dest
, src
);
4270 else if (LASX_SUPPORTED_MODE_P (GET_MODE (dest
)))
4271 loongarch_split_256bit_move (dest
, src
);
4272 else if (FP_REG_RTX_P (dest
) || FP_REG_RTX_P (src
))
4274 if (!TARGET_64BIT
&& GET_MODE (dest
) == DImode
)
4275 emit_insn (gen_move_doubleword_fprdi (dest
, src
));
4276 else if (!TARGET_64BIT
&& GET_MODE (dest
) == DFmode
)
4277 emit_insn (gen_move_doubleword_fprdf (dest
, src
));
4278 else if (TARGET_64BIT
&& GET_MODE (dest
) == TFmode
)
4279 emit_insn (gen_move_doubleword_fprtf (dest
, src
));
4285 /* The operation can be split into two normal moves. Decide in
4286 which order to do them. */
4287 low_dest
= loongarch_subword (dest
, false);
4288 if (REG_P (low_dest
) && reg_overlap_mentioned_p (low_dest
, src
))
4290 loongarch_emit_move (loongarch_subword (dest
, true),
4291 loongarch_subword (src
, true));
4292 loongarch_emit_move (low_dest
, loongarch_subword (src
, false));
4296 loongarch_emit_move (low_dest
, loongarch_subword (src
, false));
4297 loongarch_emit_move (loongarch_subword (dest
, true),
4298 loongarch_subword (src
, true));
4303 /* Check if adding an integer constant value for a specific mode can be
4304 performed with an addu16i.d instruction and an addi.{w/d}
4308 loongarch_addu16i_imm12_operand_p (HOST_WIDE_INT value
, machine_mode mode
)
4310 /* Not necessary, but avoid unnecessary calculation if !TARGET_64BIT. */
4314 if ((value
& 0xffff) == 0)
4317 if (IMM12_OPERAND (value
))
4320 value
= (value
& ~HWIT_UC_0xFFF
) + ((value
& 0x800) << 1);
4321 return ADDU16I_OPERAND (trunc_int_for_mode (value
, mode
));
4324 /* Split one integer constant op[0] into two (op[1] and op[2]) for constant
4325 plus operation in a specific mode. The splitted constants can be added
4326 onto a register with a single instruction (addi.{d/w} or addu16i.d). */
4329 loongarch_split_plus_constant (rtx
*op
, machine_mode mode
)
4331 HOST_WIDE_INT v
= INTVAL (op
[0]), a
;
4333 if (DUAL_IMM12_OPERAND (v
))
4334 a
= (v
> 0 ? 2047 : -2048);
4335 else if (loongarch_addu16i_imm12_operand_p (v
, mode
))
4336 a
= (v
& ~HWIT_UC_0xFFF
) + ((v
& 0x800) << 1);
4337 else if (mode
== DImode
&& DUAL_ADDU16I_OPERAND (v
))
4338 a
= (v
> 0 ? 0x7fff0000 : ~0x7fffffff);
4342 op
[1] = gen_int_mode (a
, mode
);
4343 v
= v
- (unsigned HOST_WIDE_INT
) a
;
4344 op
[2] = gen_int_mode (v
, mode
);
4347 /* Implement TARGET_CONSTANT_ALIGNMENT. */
4349 static HOST_WIDE_INT
4350 loongarch_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
4352 if (TREE_CODE (exp
) == STRING_CST
|| TREE_CODE (exp
) == CONSTRUCTOR
)
4353 return MAX (align
, BITS_PER_WORD
);
4358 loongarch_output_move_index (rtx x
, machine_mode mode
, bool ldr
)
4360 int index
= exact_log2 (GET_MODE_SIZE (mode
));
4361 if (!IN_RANGE (index
, 0, 3))
4364 struct loongarch_address_info info
;
4365 if ((loongarch_classify_address (&info
, x
, mode
, false)
4366 && !(info
.type
== ADDRESS_REG_REG
))
4367 || !loongarch_legitimate_address_p (mode
, x
, false))
4370 const char *const insn
[][4] =
4386 return insn
[ldr
][index
];
4390 loongarch_output_move_index_float (rtx x
, machine_mode mode
, bool ldr
)
4392 int index
= exact_log2 (GET_MODE_SIZE (mode
));
4393 if (!IN_RANGE (index
, 2, 5))
4396 struct loongarch_address_info info
;
4397 if ((loongarch_classify_address (&info
, x
, mode
, false)
4398 && !(info
.type
== ADDRESS_REG_REG
))
4399 || !loongarch_legitimate_address_p (mode
, x
, false))
4402 const char *const insn
[][4] =
4418 return insn
[ldr
][index
-2];
4420 /* Return true if a 128-bit move from SRC to DEST should be split. */
4423 loongarch_split_128bit_move_p (rtx dest
, rtx src
)
4425 /* LSX-to-LSX moves can be done in a single instruction. */
4426 if (FP_REG_RTX_P (src
) && FP_REG_RTX_P (dest
))
4429 /* Check for LSX loads and stores. */
4430 if (FP_REG_RTX_P (dest
) && MEM_P (src
))
4432 if (FP_REG_RTX_P (src
) && MEM_P (dest
))
4435 /* Check for LSX set to an immediate const vector with valid replicated
4437 if (FP_REG_RTX_P (dest
)
4438 && loongarch_const_vector_same_int_p (src
, GET_MODE (src
), -512, 511))
4441 /* Check for LSX load zero immediate. */
4442 if (FP_REG_RTX_P (dest
) && src
== CONST0_RTX (GET_MODE (src
)))
4448 /* Return true if a 256-bit move from SRC to DEST should be split. */
4451 loongarch_split_256bit_move_p (rtx dest
, rtx src
)
4453 /* LSX-to-LSX moves can be done in a single instruction. */
4454 if (FP_REG_RTX_P (src
) && FP_REG_RTX_P (dest
))
4457 /* Check for LSX loads and stores. */
4458 if (FP_REG_RTX_P (dest
) && MEM_P (src
))
4460 if (FP_REG_RTX_P (src
) && MEM_P (dest
))
4463 /* Check for LSX set to an immediate const vector with valid replicated
4465 if (FP_REG_RTX_P (dest
)
4466 && loongarch_const_vector_same_int_p (src
, GET_MODE (src
), -512, 511))
4469 /* Check for LSX load zero immediate. */
4470 if (FP_REG_RTX_P (dest
) && src
== CONST0_RTX (GET_MODE (src
)))
4476 /* Split a 128-bit move from SRC to DEST. */
4479 loongarch_split_128bit_move (rtx dest
, rtx src
)
4482 rtx low_dest
, low_src
, d
, s
;
4484 if (FP_REG_RTX_P (dest
))
4486 gcc_assert (!MEM_P (src
));
4488 rtx new_dest
= dest
;
4491 if (GET_MODE (dest
) != V4SImode
)
4492 new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4496 if (GET_MODE (dest
) != V2DImode
)
4497 new_dest
= simplify_gen_subreg (V2DImode
, dest
, GET_MODE (dest
), 0);
4500 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (TImode
);
4501 byte
+= UNITS_PER_WORD
, index
++)
4503 s
= loongarch_subword_at_byte (src
, byte
);
4505 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, s
, new_dest
,
4506 GEN_INT (1 << index
)));
4508 emit_insn (gen_lsx_vinsgr2vr_d (new_dest
, s
, new_dest
,
4509 GEN_INT (1 << index
)));
4512 else if (FP_REG_RTX_P (src
))
4514 gcc_assert (!MEM_P (dest
));
4519 if (GET_MODE (src
) != V4SImode
)
4520 new_src
= simplify_gen_subreg (V4SImode
, src
, GET_MODE (src
), 0);
4524 if (GET_MODE (src
) != V2DImode
)
4525 new_src
= simplify_gen_subreg (V2DImode
, src
, GET_MODE (src
), 0);
4528 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (TImode
);
4529 byte
+= UNITS_PER_WORD
, index
++)
4531 d
= loongarch_subword_at_byte (dest
, byte
);
4533 emit_insn (gen_lsx_vpickve2gr_w (d
, new_src
, GEN_INT (index
)));
4535 emit_insn (gen_lsx_vpickve2gr_d (d
, new_src
, GEN_INT (index
)));
4540 low_dest
= loongarch_subword_at_byte (dest
, 0);
4541 low_src
= loongarch_subword_at_byte (src
, 0);
4542 gcc_assert (REG_P (low_dest
) && REG_P (low_src
));
4543 /* Make sure the source register is not written before reading. */
4544 if (REGNO (low_dest
) <= REGNO (low_src
))
4546 for (byte
= 0; byte
< GET_MODE_SIZE (TImode
);
4547 byte
+= UNITS_PER_WORD
)
4549 d
= loongarch_subword_at_byte (dest
, byte
);
4550 s
= loongarch_subword_at_byte (src
, byte
);
4551 loongarch_emit_move (d
, s
);
4556 for (byte
= GET_MODE_SIZE (TImode
) - UNITS_PER_WORD
; byte
>= 0;
4557 byte
-= UNITS_PER_WORD
)
4559 d
= loongarch_subword_at_byte (dest
, byte
);
4560 s
= loongarch_subword_at_byte (src
, byte
);
4561 loongarch_emit_move (d
, s
);
4567 /* Split a 256-bit move from SRC to DEST. */
4570 loongarch_split_256bit_move (rtx dest
, rtx src
)
4573 rtx low_dest
, low_src
, d
, s
;
4575 if (FP_REG_RTX_P (dest
))
4577 gcc_assert (!MEM_P (src
));
4579 rtx new_dest
= dest
;
4582 if (GET_MODE (dest
) != V8SImode
)
4583 new_dest
= simplify_gen_subreg (V8SImode
, dest
, GET_MODE (dest
), 0);
4587 if (GET_MODE (dest
) != V4DImode
)
4588 new_dest
= simplify_gen_subreg (V4DImode
, dest
, GET_MODE (dest
), 0);
4591 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (GET_MODE (dest
));
4592 byte
+= UNITS_PER_WORD
, index
++)
4594 s
= loongarch_subword_at_byte (src
, byte
);
4596 emit_insn (gen_lasx_xvinsgr2vr_w (new_dest
, s
, new_dest
,
4597 GEN_INT (1 << index
)));
4599 emit_insn (gen_lasx_xvinsgr2vr_d (new_dest
, s
, new_dest
,
4600 GEN_INT (1 << index
)));
4603 else if (FP_REG_RTX_P (src
))
4605 gcc_assert (!MEM_P (dest
));
4610 if (GET_MODE (src
) != V8SImode
)
4611 new_src
= simplify_gen_subreg (V8SImode
, src
, GET_MODE (src
), 0);
4615 if (GET_MODE (src
) != V4DImode
)
4616 new_src
= simplify_gen_subreg (V4DImode
, src
, GET_MODE (src
), 0);
4619 for (byte
= 0, index
= 0; byte
< GET_MODE_SIZE (GET_MODE (src
));
4620 byte
+= UNITS_PER_WORD
, index
++)
4622 d
= loongarch_subword_at_byte (dest
, byte
);
4624 emit_insn (gen_lsx_vpickve2gr_w (d
, new_src
, GEN_INT (index
)));
4626 emit_insn (gen_lsx_vpickve2gr_d (d
, new_src
, GEN_INT (index
)));
4631 low_dest
= loongarch_subword_at_byte (dest
, 0);
4632 low_src
= loongarch_subword_at_byte (src
, 0);
4633 gcc_assert (REG_P (low_dest
) && REG_P (low_src
));
4634 /* Make sure the source register is not written before reading. */
4635 if (REGNO (low_dest
) <= REGNO (low_src
))
4637 for (byte
= 0; byte
< GET_MODE_SIZE (TImode
);
4638 byte
+= UNITS_PER_WORD
)
4640 d
= loongarch_subword_at_byte (dest
, byte
);
4641 s
= loongarch_subword_at_byte (src
, byte
);
4642 loongarch_emit_move (d
, s
);
4647 for (byte
= GET_MODE_SIZE (TImode
) - UNITS_PER_WORD
; byte
>= 0;
4648 byte
-= UNITS_PER_WORD
)
4650 d
= loongarch_subword_at_byte (dest
, byte
);
4651 s
= loongarch_subword_at_byte (src
, byte
);
4652 loongarch_emit_move (d
, s
);
4659 /* Split a COPY_S.D with operands DEST, SRC and INDEX. GEN is a function
4660 used to generate subregs. */
4663 loongarch_split_lsx_copy_d (rtx dest
, rtx src
, rtx index
,
4664 rtx (*gen_fn
)(rtx
, rtx
, rtx
))
4666 gcc_assert ((GET_MODE (src
) == V2DImode
&& GET_MODE (dest
) == DImode
)
4667 || (GET_MODE (src
) == V2DFmode
&& GET_MODE (dest
) == DFmode
));
4669 /* Note that low is always from the lower index, and high is always
4670 from the higher index. */
4671 rtx low
= loongarch_subword (dest
, false);
4672 rtx high
= loongarch_subword (dest
, true);
4673 rtx new_src
= simplify_gen_subreg (V4SImode
, src
, GET_MODE (src
), 0);
4675 emit_insn (gen_fn (low
, new_src
, GEN_INT (INTVAL (index
) * 2)));
4676 emit_insn (gen_fn (high
, new_src
, GEN_INT (INTVAL (index
) * 2 + 1)));
4679 /* Split a INSERT.D with operand DEST, SRC1.INDEX and SRC2. */
4682 loongarch_split_lsx_insert_d (rtx dest
, rtx src1
, rtx index
, rtx src2
)
4685 gcc_assert (GET_MODE (dest
) == GET_MODE (src1
));
4686 gcc_assert ((GET_MODE (dest
) == V2DImode
4687 && (GET_MODE (src2
) == DImode
|| src2
== const0_rtx
))
4688 || (GET_MODE (dest
) == V2DFmode
&& GET_MODE (src2
) == DFmode
));
4690 /* Note that low is always from the lower index, and high is always
4691 from the higher index. */
4692 rtx low
= loongarch_subword (src2
, false);
4693 rtx high
= loongarch_subword (src2
, true);
4694 rtx new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4695 rtx new_src1
= simplify_gen_subreg (V4SImode
, src1
, GET_MODE (src1
), 0);
4696 i
= exact_log2 (INTVAL (index
));
4697 gcc_assert (i
!= -1);
4699 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, low
, new_src1
,
4700 GEN_INT (1 << (i
* 2))));
4701 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
,
4702 GEN_INT (1 << (i
* 2 + 1))));
4708 loongarch_split_lsx_fill_d (rtx dest
, rtx src
)
4710 gcc_assert ((GET_MODE (dest
) == V2DImode
4711 && (GET_MODE (src
) == DImode
|| src
== const0_rtx
))
4712 || (GET_MODE (dest
) == V2DFmode
&& GET_MODE (src
) == DFmode
));
4714 /* Note that low is always from the lower index, and high is always
4715 from the higher index. */
4717 if (src
== const0_rtx
)
4724 low
= loongarch_subword (src
, false);
4725 high
= loongarch_subword (src
, true);
4727 rtx new_dest
= simplify_gen_subreg (V4SImode
, dest
, GET_MODE (dest
), 0);
4728 emit_insn (gen_lsx_vreplgr2vr_w (new_dest
, low
));
4729 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
, GEN_INT (1 << 1)));
4730 emit_insn (gen_lsx_vinsgr2vr_w (new_dest
, high
, new_dest
, GEN_INT (1 << 3)));
4734 /* Return the appropriate instructions to move SRC into DEST. Assume
4735 that SRC is operand 1 and DEST is operand 0. */
4738 loongarch_output_move (rtx dest
, rtx src
)
4740 enum rtx_code dest_code
= GET_CODE (dest
);
4741 enum rtx_code src_code
= GET_CODE (src
);
4742 machine_mode mode
= GET_MODE (dest
);
4743 bool dbl_p
= (GET_MODE_SIZE (mode
) == 8);
4744 bool lsx_p
= LSX_SUPPORTED_MODE_P (mode
);
4745 bool lasx_p
= LASX_SUPPORTED_MODE_P (mode
);
4747 if (loongarch_split_move_p (dest
, src
))
4750 if ((lsx_p
|| lasx_p
)
4751 && dest_code
== REG
&& FP_REG_P (REGNO (dest
))
4752 && src_code
== CONST_VECTOR
4753 && CONST_INT_P (CONST_VECTOR_ELT (src
, 0)))
4755 gcc_assert (loongarch_const_vector_same_int_p (src
, mode
, -512, 511));
4756 switch (GET_MODE_SIZE (mode
))
4759 return "vrepli.%v0\t%w0,%E1";
4761 return "xvrepli.%v0\t%u0,%E1";
4762 default: gcc_unreachable ();
4766 if ((src_code
== REG
&& GP_REG_P (REGNO (src
)))
4767 || (src
== CONST0_RTX (mode
)))
4769 if (dest_code
== REG
)
4771 if (GP_REG_P (REGNO (dest
)))
4772 return "or\t%0,%z1,$r0";
4774 if (FP_REG_P (REGNO (dest
)))
4776 if (lsx_p
|| lasx_p
)
4778 gcc_assert (src
== CONST0_RTX (GET_MODE (src
)));
4779 switch (GET_MODE_SIZE (mode
))
4782 return "vrepli.b\t%w0,0";
4784 return "xvrepli.b\t%u0,0";
4790 return dbl_p
? "movgr2fr.d\t%0,%z1" : "movgr2fr.w\t%0,%z1";
4793 if (dest_code
== MEM
)
4795 const char *insn
= NULL
;
4796 insn
= loongarch_output_move_index (XEXP (dest
, 0), GET_MODE (dest
),
4801 rtx offset
= XEXP (dest
, 0);
4802 if (GET_CODE (offset
) == PLUS
)
4803 offset
= XEXP (offset
, 1);
4804 switch (GET_MODE_SIZE (mode
))
4807 return "st.b\t%z1,%0";
4809 return "st.h\t%z1,%0";
4811 /* Matching address type with a 12bit offset and
4813 if (const_arith_operand (offset
, Pmode
)
4814 || GET_CODE (offset
) == LO_SUM
)
4815 return "st.w\t%z1,%0";
4817 return "stptr.w\t%z1,%0";
4819 if (const_arith_operand (offset
, Pmode
)
4820 || GET_CODE (offset
) == LO_SUM
)
4821 return "st.d\t%z1,%0";
4823 return "stptr.d\t%z1,%0";
4829 if (dest_code
== REG
&& GP_REG_P (REGNO (dest
)))
4831 if (src_code
== REG
)
4832 if (FP_REG_P (REGNO (src
)))
4834 gcc_assert (!lsx_p
);
4835 return dbl_p
? "movfr2gr.d\t%0,%1" : "movfr2gr.s\t%0,%1";
4838 if (src_code
== MEM
)
4840 const char *insn
= NULL
;
4841 insn
= loongarch_output_move_index (XEXP (src
, 0), GET_MODE (src
),
4846 rtx offset
= XEXP (src
, 0);
4847 if (GET_CODE (offset
) == PLUS
)
4848 offset
= XEXP (offset
, 1);
4849 switch (GET_MODE_SIZE (mode
))
4852 return "ld.bu\t%0,%1";
4854 return "ld.hu\t%0,%1";
4856 /* Matching address type with a 12bit offset and
4858 if (const_arith_operand (offset
, Pmode
)
4859 || GET_CODE (offset
) == LO_SUM
)
4860 return "ld.w\t%0,%1";
4862 return "ldptr.w\t%0,%1";
4864 if (const_arith_operand (offset
, Pmode
)
4865 || GET_CODE (offset
) == LO_SUM
)
4866 return "ld.d\t%0,%1";
4868 return "ldptr.d\t%0,%1";
4874 if (src_code
== HIGH
)
4877 split_const (XEXP (src
, 0), &x
, &offset
);
4878 enum loongarch_symbol_type type
= SYMBOL_PCREL
;
4880 if (UNSPEC_ADDRESS_P (x
))
4881 type
= UNSPEC_ADDRESS_TYPE (x
);
4883 if (type
== SYMBOL_TLS_LE
)
4884 return "lu12i.w\t%0,%h1";
4886 return "pcalau12i\t%0,%h1";
4889 if (src_code
== CONST_INT
)
4891 if (LU12I_INT (src
))
4892 return "lu12i.w\t%0,%1>>12\t\t\t# %X1";
4893 else if (IMM12_INT (src
))
4894 return "addi.w\t%0,$r0,%1\t\t\t# %X1";
4895 else if (IMM12_INT_UNSIGNED (src
))
4896 return "ori\t%0,$r0,%1\t\t\t# %X1";
4897 else if (LU52I_INT (src
))
4898 return "lu52i.d\t%0,$r0,%X1>>52\t\t\t# %1";
4904 if (!loongarch_explicit_relocs_p (loongarch_classify_symbol (src
))
4905 && dest_code
== REG
&& symbolic_operand (src
, VOIDmode
))
4907 if (loongarch_classify_symbol (src
) == SYMBOL_PCREL
)
4908 return "la.local\t%0,%1";
4910 return "la.global\t%0,%1";
4913 if (src_code
== REG
&& FP_REG_P (REGNO (src
)))
4915 if (dest_code
== REG
&& FP_REG_P (REGNO (dest
)))
4917 if (lsx_p
|| lasx_p
)
4919 switch (GET_MODE_SIZE (mode
))
4922 return "vori.b\t%w0,%w1,0";
4924 return "xvori.b\t%u0,%u1,0";
4930 return dbl_p
? "fmov.d\t%0,%1" : "fmov.s\t%0,%1";
4933 if (dest_code
== MEM
)
4935 const char *insn
= NULL
;
4936 insn
= loongarch_output_move_index_float (XEXP (dest
, 0),
4942 if (lsx_p
|| lasx_p
)
4944 switch (GET_MODE_SIZE (mode
))
4947 return "vst\t%w1,%0";
4949 return "xvst\t%u1,%0";
4955 return dbl_p
? "fst.d\t%1,%0" : "fst.s\t%1,%0";
4959 if (dest_code
== REG
&& FP_REG_P (REGNO (dest
)))
4961 if (src_code
== MEM
)
4963 const char *insn
= NULL
;
4964 insn
= loongarch_output_move_index_float (XEXP (src
, 0),
4970 if (lsx_p
|| lasx_p
)
4972 switch (GET_MODE_SIZE (mode
))
4975 return "vld\t%w0,%1";
4977 return "xvld\t%u0,%1";
4982 return dbl_p
? "fld.d\t%0,%1" : "fld.s\t%0,%1";
4989 /* Return true if CMP1 is a suitable second operand for integer ordering
4993 loongarch_int_order_operand_ok_p (enum rtx_code code
, rtx cmp1
)
4999 return reg_or_0_operand (cmp1
, VOIDmode
);
5003 return cmp1
== const1_rtx
;
5007 return arith_operand (cmp1
, VOIDmode
);
5010 return sle_operand (cmp1
, VOIDmode
);
5013 return sleu_operand (cmp1
, VOIDmode
);
5020 /* Return true if *CMP1 (of mode MODE) is a valid second operand for
5021 integer ordering test *CODE, or if an equivalent combination can
5022 be formed by adjusting *CODE and *CMP1. When returning true, update
5023 *CODE and *CMP1 with the chosen code and operand, otherwise leave
5027 loongarch_canonicalize_int_order_test (enum rtx_code
*code
, rtx
*cmp1
,
5030 HOST_WIDE_INT plus_one
;
5032 if (loongarch_int_order_operand_ok_p (*code
, *cmp1
))
5035 if (CONST_INT_P (*cmp1
))
5039 plus_one
= trunc_int_for_mode (UINTVAL (*cmp1
) + 1, mode
);
5040 if (INTVAL (*cmp1
) < plus_one
)
5043 *cmp1
= force_reg (mode
, GEN_INT (plus_one
));
5049 plus_one
= trunc_int_for_mode (UINTVAL (*cmp1
) + 1, mode
);
5053 *cmp1
= force_reg (mode
, GEN_INT (plus_one
));
5064 /* Compare CMP0 and CMP1 using ordering test CODE and store the result
5065 in TARGET. CMP0 and TARGET are register_operands. If INVERT_PTR
5066 is nonnull, it's OK to set TARGET to the inverse of the result and
5067 flip *INVERT_PTR instead. */
5070 loongarch_emit_int_order_test (enum rtx_code code
, bool *invert_ptr
,
5071 rtx target
, rtx cmp0
, rtx cmp1
)
5075 /* First see if there is a LoongArch instruction that can do this operation.
5076 If not, try doing the same for the inverse operation. If that also
5077 fails, force CMP1 into a register and try again. */
5078 mode
= GET_MODE (cmp0
);
5079 if (loongarch_canonicalize_int_order_test (&code
, &cmp1
, mode
))
5080 loongarch_emit_binary (code
, target
, cmp0
, cmp1
);
5083 enum rtx_code inv_code
= reverse_condition (code
);
5084 if (!loongarch_canonicalize_int_order_test (&inv_code
, &cmp1
, mode
))
5086 cmp1
= force_reg (mode
, cmp1
);
5087 loongarch_emit_int_order_test (code
, invert_ptr
, target
, cmp0
, cmp1
);
5089 else if (invert_ptr
== 0)
5093 inv_target
= loongarch_force_binary (GET_MODE (target
),
5094 inv_code
, cmp0
, cmp1
);
5095 loongarch_emit_binary (XOR
, target
, inv_target
, const1_rtx
);
5099 *invert_ptr
= !*invert_ptr
;
5100 loongarch_emit_binary (inv_code
, target
, cmp0
, cmp1
);
5105 /* Return a register that is zero if CMP0 and CMP1 are equal.
5106 The register will have the same mode as CMP0. */
5109 loongarch_zero_if_equal (rtx cmp0
, rtx cmp1
)
5111 if (cmp1
== const0_rtx
)
5114 if (uns_arith_operand (cmp1
, VOIDmode
))
5115 return expand_binop (GET_MODE (cmp0
), xor_optab
, cmp0
, cmp1
, 0, 0,
5118 return expand_binop (GET_MODE (cmp0
), sub_optab
, cmp0
, cmp1
, 0, 0,
5122 /* Sign- or zero-extend OP0 and OP1 for integer comparisons. */
5125 loongarch_extend_comparands (rtx_code code
, rtx
*op0
, rtx
*op1
)
5127 /* Comparisons consider all GRLEN bits, so extend sub-GRLEN values. */
5128 if (GET_MODE_SIZE (word_mode
) > GET_MODE_SIZE (GET_MODE (*op0
)))
5130 /* It is more profitable to zero-extend QImode values. But not if the
5131 first operand has already been sign-extended, and the second one is
5132 is a constant or has already been sign-extended also. */
5133 if (unsigned_condition (code
) == code
5134 && (GET_MODE (*op0
) == QImode
5135 && ! (GET_CODE (*op0
) == SUBREG
5136 && SUBREG_PROMOTED_VAR_P (*op0
)
5137 && SUBREG_PROMOTED_SIGNED_P (*op0
)
5138 && (CONST_INT_P (*op1
)
5139 || (GET_CODE (*op1
) == SUBREG
5140 && SUBREG_PROMOTED_VAR_P (*op1
)
5141 && SUBREG_PROMOTED_SIGNED_P (*op1
))))))
5143 *op0
= gen_rtx_ZERO_EXTEND (word_mode
, *op0
);
5144 if (CONST_INT_P (*op1
))
5145 *op1
= GEN_INT ((uint8_t) INTVAL (*op1
));
5147 *op1
= gen_rtx_ZERO_EXTEND (word_mode
, *op1
);
5151 *op0
= gen_rtx_SIGN_EXTEND (word_mode
, *op0
);
5152 if (*op1
!= const0_rtx
)
5153 *op1
= gen_rtx_SIGN_EXTEND (word_mode
, *op1
);
5159 /* Convert a comparison into something that can be used in a branch. On
5160 entry, *OP0 and *OP1 are the values being compared and *CODE is the code
5161 used to compare them. Update them to describe the final comparison. */
5164 loongarch_emit_int_compare (enum rtx_code
*code
, rtx
*op0
, rtx
*op1
)
5166 static const enum rtx_code
5167 mag_comparisons
[][2] = {{LEU
, LTU
}, {GTU
, GEU
}, {LE
, LT
}, {GT
, GE
}};
5169 if (splittable_const_int_operand (*op1
, VOIDmode
))
5171 HOST_WIDE_INT rhs
= INTVAL (*op1
);
5173 if (*code
== EQ
|| *code
== NE
)
5175 /* Convert e.g. OP0 == 2048 into OP0 - 2048 == 0. */
5176 if (IMM12_OPERAND (-rhs
))
5178 *op0
= loongarch_force_binary (GET_MODE (*op0
), PLUS
, *op0
,
5185 /* Convert e.g. (OP0 <= 0xFFF) into (OP0 < 0x1000). */
5186 for (size_t i
= 0; i
< ARRAY_SIZE (mag_comparisons
); i
++)
5188 HOST_WIDE_INT new_rhs
;
5189 bool increment
= *code
== mag_comparisons
[i
][0];
5190 bool decrement
= *code
== mag_comparisons
[i
][1];
5191 if (!increment
&& !decrement
)
5194 if ((increment
&& rhs
== HOST_WIDE_INT_MAX
)
5195 || (decrement
&& rhs
== HOST_WIDE_INT_MIN
))
5198 new_rhs
= rhs
+ (increment
? 1 : -1);
5199 if (loongarch_integer_cost (new_rhs
)
5200 < loongarch_integer_cost (rhs
))
5202 *op1
= GEN_INT (new_rhs
);
5203 *code
= mag_comparisons
[i
][increment
];
5210 loongarch_extend_comparands (*code
, op0
, op1
);
5212 *op0
= force_reg (word_mode
, *op0
);
5213 if (*op1
!= const0_rtx
)
5214 *op1
= force_reg (word_mode
, *op1
);
5217 /* Like loongarch_emit_int_compare, but for floating-point comparisons. */
5220 loongarch_emit_float_compare (enum rtx_code
*code
, rtx
*op0
, rtx
*op1
)
5225 /* Floating-point tests use a separate FCMP.cond.fmt
5226 comparison to set a register. The branch or conditional move will
5227 then compare that register against zero.
5229 Set CMP_CODE to the code of the comparison instruction and
5230 *CODE to the code that the branch or move should use. */
5231 enum rtx_code cmp_code
= *code
;
5232 /* Three FP conditions cannot be implemented by reversing the
5233 operands for FCMP.cond.fmt, instead a reversed condition code is
5234 required and a test for false. */
5236 *op0
= gen_reg_rtx (FCCmode
);
5239 loongarch_emit_binary (cmp_code
, *op0
, cmp_op0
, cmp_op1
);
5242 /* Try performing the comparison in OPERANDS[1], whose arms are OPERANDS[2]
5243 and OPERAND[3]. Store the result in OPERANDS[0].
5245 On 64-bit targets, the mode of the comparison and target will always be
5246 SImode, thus possibly narrower than that of the comparison's operands. */
5249 loongarch_expand_scc (rtx operands
[])
5251 rtx target
= operands
[0];
5252 enum rtx_code code
= GET_CODE (operands
[1]);
5253 rtx op0
= operands
[2];
5254 rtx op1
= operands
[3];
5256 loongarch_extend_comparands (code
, &op0
, &op1
);
5257 op0
= force_reg (word_mode
, op0
);
5259 gcc_assert (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_INT
);
5261 if (code
== EQ
|| code
== NE
)
5263 rtx zie
= loongarch_zero_if_equal (op0
, op1
);
5264 loongarch_emit_binary (code
, target
, zie
, const0_rtx
);
5267 loongarch_emit_int_order_test (code
, 0, target
, op0
, op1
);
5270 /* Compare OPERANDS[1] with OPERANDS[2] using comparison code
5271 CODE and jump to OPERANDS[3] if the condition holds. */
5274 loongarch_expand_conditional_branch (rtx
*operands
)
5276 enum rtx_code code
= GET_CODE (operands
[0]);
5277 rtx op0
= operands
[1];
5278 rtx op1
= operands
[2];
5281 if (FLOAT_MODE_P (GET_MODE (op1
)))
5282 loongarch_emit_float_compare (&code
, &op0
, &op1
);
5284 loongarch_emit_int_compare (&code
, &op0
, &op1
);
5286 condition
= gen_rtx_fmt_ee (code
, VOIDmode
, op0
, op1
);
5287 emit_jump_insn (gen_condjump (condition
, operands
[3]));
5290 /* Perform the comparison in OPERANDS[1]. Move OPERANDS[2] into OPERANDS[0]
5291 if the condition holds, otherwise move OPERANDS[3] into OPERANDS[0]. */
5294 loongarch_expand_conditional_move (rtx
*operands
)
5296 enum rtx_code code
= GET_CODE (operands
[1]);
5297 rtx op0
= XEXP (operands
[1], 0);
5298 rtx op1
= XEXP (operands
[1], 1);
5299 rtx op0_extend
= op0
;
5300 rtx op1_extend
= op1
;
5302 /* Record whether operands[2] and operands[3] modes are promoted to word_mode. */
5303 bool promote_p
= false;
5304 machine_mode mode
= GET_MODE (operands
[0]);
5306 if (FLOAT_MODE_P (GET_MODE (op1
)))
5307 loongarch_emit_float_compare (&code
, &op0
, &op1
);
5310 if ((REGNO (op0
) == REGNO (operands
[2])
5311 || (REGNO (op1
) == REGNO (operands
[3]) && (op1
!= const0_rtx
)))
5312 && (GET_MODE_SIZE (GET_MODE (op0
)) < word_mode
))
5318 loongarch_extend_comparands (code
, &op0
, &op1
);
5320 op0
= force_reg (word_mode
, op0
);
5322 op1_extend
= force_reg (word_mode
, op1
);
5324 if (code
== EQ
|| code
== NE
)
5326 op0
= loongarch_zero_if_equal (op0
, op1
);
5331 /* The comparison needs a separate scc instruction. Store the
5332 result of the scc in *OP0 and compare it against zero. */
5333 bool invert
= false;
5334 rtx target
= gen_reg_rtx (GET_MODE (op0
));
5335 loongarch_emit_int_order_test (code
, &invert
, target
, op0
, op1
);
5336 code
= invert
? EQ
: NE
;
5342 rtx cond
= gen_rtx_fmt_ee (code
, GET_MODE (op0
), op0
, op1
);
5343 /* There is no direct support for general conditional GP move involving
5344 two registers using SEL. */
5345 if (INTEGRAL_MODE_P (GET_MODE (operands
[2]))
5346 && register_operand (operands
[2], VOIDmode
)
5347 && register_operand (operands
[3], VOIDmode
))
5349 rtx op2
= operands
[2];
5350 rtx op3
= operands
[3];
5354 if (REGNO (XEXP (operands
[1], 0)) == REGNO (operands
[2]))
5358 loongarch_extend_comparands (code
, &op2
, &const0_rtx
);
5359 op2
= force_reg (mode
, op2
);
5362 if (REGNO (XEXP (operands
[1], 1)) == REGNO (operands
[3]))
5366 loongarch_extend_comparands (code
, &op3
, &const0_rtx
);
5367 op3
= force_reg (mode
, op3
);
5371 rtx temp
= gen_reg_rtx (mode
);
5372 rtx temp2
= gen_reg_rtx (mode
);
5374 emit_insn (gen_rtx_SET (temp
,
5375 gen_rtx_IF_THEN_ELSE (mode
, cond
,
5378 /* Flip the test for the second operand. */
5379 cond
= gen_rtx_fmt_ee ((code
== EQ
) ? NE
: EQ
, GET_MODE (op0
), op0
, op1
);
5381 emit_insn (gen_rtx_SET (temp2
,
5382 gen_rtx_IF_THEN_ELSE (mode
, cond
,
5385 /* Merge the two results, at least one is guaranteed to be zero. */
5388 rtx temp3
= gen_reg_rtx (mode
);
5389 emit_insn (gen_rtx_SET (temp3
, gen_rtx_IOR (mode
, temp
, temp2
)));
5390 temp3
= gen_lowpart (GET_MODE (operands
[0]), temp3
);
5391 /* Nonzero in a subreg if it was made when accessing an object that
5392 was promoted to a wider mode in accord with the PROMOTED_MODE
5393 machine description macro. */
5394 SUBREG_PROMOTED_VAR_P (temp3
) = 1;
5395 /* Sets promoted mode for SUBREG_PROMOTED_VAR_P. */
5396 SUBREG_PROMOTED_SET (temp3
, SRP_SIGNED
);
5397 loongarch_emit_move (operands
[0], temp3
);
5400 emit_insn (gen_rtx_SET (operands
[0], gen_rtx_IOR (mode
, temp
, temp2
)));
5403 emit_insn (gen_rtx_SET (operands
[0],
5404 gen_rtx_IF_THEN_ELSE (GET_MODE (operands
[0]), cond
,
5405 operands
[2], operands
[3])));
5408 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
5411 loongarch_va_start (tree valist
, rtx nextarg
)
5413 nextarg
= plus_constant (Pmode
, nextarg
, -cfun
->machine
->varargs_size
);
5414 std_expand_builtin_va_start (valist
, nextarg
);
5417 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
5420 loongarch_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
5421 tree exp ATTRIBUTE_UNUSED
)
5428 loongarch_mode_for_move_size (HOST_WIDE_INT size
)
5438 return int_mode_for_size (size
* BITS_PER_UNIT
, 0).require ();
5441 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
5442 Assume that the areas do not overlap. */
5445 loongarch_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
,
5446 HOST_WIDE_INT delta
)
5448 HOST_WIDE_INT offs
, delta_cur
;
5453 /* Calculate how many registers we'll need for the block move.
5454 We'll emit length / delta move operations with delta as the size
5455 first. Then we may still have length % delta bytes not copied.
5456 We handle these remaining bytes by move operations with smaller
5457 (halfed) sizes. For example, if length = 21 and delta = 8, we'll
5458 emit two ld.d/st.d pairs, one ld.w/st.w pair, and one ld.b/st.b
5459 pair. For each load/store pair we use a dedicated register to keep
5460 the pipeline as populated as possible. */
5461 gcc_assert (pow2p_hwi (delta
));
5462 HOST_WIDE_INT num_reg
= length
/ delta
+ popcount_hwi (length
% delta
);
5464 /* Allocate a buffer for the temporary registers. */
5465 regs
= XALLOCAVEC (rtx
, num_reg
);
5467 for (delta_cur
= delta
, i
= 0, offs
= 0; offs
< length
; delta_cur
/= 2)
5469 mode
= loongarch_mode_for_move_size (delta_cur
);
5471 for (; offs
+ delta_cur
<= length
; offs
+= delta_cur
, i
++)
5473 regs
[i
] = gen_reg_rtx (mode
);
5474 loongarch_emit_move (regs
[i
], adjust_address (src
, mode
, offs
));
5478 for (delta_cur
= delta
, i
= 0, offs
= 0; offs
< length
; delta_cur
/= 2)
5480 mode
= loongarch_mode_for_move_size (delta_cur
);
5482 for (; offs
+ delta_cur
<= length
; offs
+= delta_cur
, i
++)
5483 loongarch_emit_move (adjust_address (dest
, mode
, offs
), regs
[i
]);
5487 /* Helper function for doing a loop-based block operation on memory
5488 reference MEM. Each iteration of the loop will operate on LENGTH
5491 Create a new base register for use within the loop and point it to
5492 the start of MEM. Create a new memory reference that uses this
5493 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
5496 loongarch_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
, rtx
*loop_reg
,
5499 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
5501 /* Although the new mem does not refer to a known location,
5502 it does keep up to LENGTH bytes of alignment. */
5503 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
5504 set_mem_align (*loop_mem
, MIN (MEM_ALIGN (mem
), length
* BITS_PER_UNIT
));
5507 /* Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER
5508 bytes at a time. LENGTH must be at least BYTES_PER_ITER. Assume that
5509 the memory regions do not overlap. */
5512 loongarch_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
,
5513 HOST_WIDE_INT align
)
5515 rtx_code_label
*label
;
5516 rtx src_reg
, dest_reg
, final_src
, test
;
5517 HOST_WIDE_INT bytes_per_iter
= align
* LARCH_MAX_MOVE_OPS_PER_LOOP_ITER
;
5518 HOST_WIDE_INT leftover
;
5520 leftover
= length
% bytes_per_iter
;
5523 /* Create registers and memory references for use within the loop. */
5524 loongarch_adjust_block_mem (src
, bytes_per_iter
, &src_reg
, &src
);
5525 loongarch_adjust_block_mem (dest
, bytes_per_iter
, &dest_reg
, &dest
);
5527 /* Calculate the value that SRC_REG should have after the last iteration
5529 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
), 0,
5532 /* Emit the start of the loop. */
5533 label
= gen_label_rtx ();
5536 /* Emit the loop body. */
5537 loongarch_block_move_straight (dest
, src
, bytes_per_iter
, align
);
5539 /* Move on to the next block. */
5540 loongarch_emit_move (src_reg
,
5541 plus_constant (Pmode
, src_reg
, bytes_per_iter
));
5542 loongarch_emit_move (dest_reg
,
5543 plus_constant (Pmode
, dest_reg
, bytes_per_iter
));
5545 /* Emit the loop condition. */
5546 test
= gen_rtx_NE (VOIDmode
, src_reg
, final_src
);
5547 if (Pmode
== DImode
)
5548 emit_jump_insn (gen_cbranchdi4 (test
, src_reg
, final_src
, label
));
5550 emit_jump_insn (gen_cbranchsi4 (test
, src_reg
, final_src
, label
));
5552 /* Mop up any left-over bytes. */
5554 loongarch_block_move_straight (dest
, src
, leftover
, align
);
5556 /* Temporary fix for PR79150. */
5557 emit_insn (gen_nop ());
5560 /* Expand a cpymemsi instruction, which copies LENGTH bytes from
5561 memory reference SRC to memory reference DEST. */
5564 loongarch_expand_block_move (rtx dest
, rtx src
, rtx r_length
, rtx r_align
)
5566 if (!CONST_INT_P (r_length
))
5569 HOST_WIDE_INT length
= INTVAL (r_length
);
5570 if (length
> la_max_inline_memcpy_size
)
5573 HOST_WIDE_INT align
= INTVAL (r_align
);
5575 if (!TARGET_STRICT_ALIGN
|| align
> LARCH_MAX_MOVE_PER_INSN
)
5576 align
= LARCH_MAX_MOVE_PER_INSN
;
5578 if (length
<= align
* LARCH_MAX_MOVE_OPS_STRAIGHT
)
5580 loongarch_block_move_straight (dest
, src
, length
, align
);
5586 loongarch_block_move_loop (dest
, src
, length
, align
);
5593 /* Return true if loongarch_expand_block_move is the preferred
5594 implementation of the 'cpymemsi' template. */
5597 loongarch_do_optimize_block_move_p (void)
5599 /* if -m[no-]memcpy is given explicitly. */
5600 if (target_flags_explicit
& MASK_MEMCPY
)
5601 return !TARGET_MEMCPY
;
5603 /* if not, don't optimize under -Os. */
5604 return !optimize_size
;
5607 /* Expand a QI or HI mode atomic memory operation.
5609 GENERATOR contains a pointer to the gen_* function that generates
5610 the SI mode underlying atomic operation using masks that we
5613 RESULT is the return register for the operation. Its value is NULL
5616 MEM is the location of the atomic access.
5618 OLDVAL is the first operand for the operation.
5620 NEWVAL is the optional second operand for the operation. Its value
5621 is NULL if unused. */
5624 loongarch_expand_atomic_qihi (union loongarch_gen_fn_ptrs generator
,
5625 rtx result
, rtx mem
, rtx oldval
, rtx newval
,
5628 rtx orig_addr
, memsi_addr
, memsi
, shift
, shiftsi
, unshifted_mask
;
5629 rtx unshifted_mask_reg
, mask
, inverted_mask
, si_op
;
5633 mode
= GET_MODE (mem
);
5635 /* Compute the address of the containing SImode value. */
5636 orig_addr
= force_reg (Pmode
, XEXP (mem
, 0));
5637 memsi_addr
= loongarch_force_binary (Pmode
, AND
, orig_addr
,
5638 force_reg (Pmode
, GEN_INT (-4)));
5640 /* Create a memory reference for it. */
5641 memsi
= gen_rtx_MEM (SImode
, memsi_addr
);
5642 set_mem_alias_set (memsi
, ALIAS_SET_MEMORY_BARRIER
);
5643 MEM_VOLATILE_P (memsi
) = MEM_VOLATILE_P (mem
);
5645 /* Work out the byte offset of the QImode or HImode value,
5646 counting from the least significant byte. */
5647 shift
= loongarch_force_binary (Pmode
, AND
, orig_addr
, GEN_INT (3));
5648 /* Multiply by eight to convert the shift value from bytes to bits. */
5649 loongarch_emit_binary (ASHIFT
, shift
, shift
, GEN_INT (3));
5651 /* Make the final shift an SImode value, so that it can be used in
5652 SImode operations. */
5653 shiftsi
= force_reg (SImode
, gen_lowpart (SImode
, shift
));
5655 /* Set MASK to an inclusive mask of the QImode or HImode value. */
5656 unshifted_mask
= GEN_INT (GET_MODE_MASK (mode
));
5657 unshifted_mask_reg
= force_reg (SImode
, unshifted_mask
);
5658 mask
= loongarch_force_binary (SImode
, ASHIFT
, unshifted_mask_reg
, shiftsi
);
5660 /* Compute the equivalent exclusive mask. */
5661 inverted_mask
= gen_reg_rtx (SImode
);
5662 emit_insn (gen_rtx_SET (inverted_mask
, gen_rtx_NOT (SImode
, mask
)));
5664 /* Shift the old value into place. */
5665 if (oldval
!= const0_rtx
)
5667 oldval
= convert_modes (SImode
, mode
, oldval
, true);
5668 oldval
= force_reg (SImode
, oldval
);
5669 oldval
= loongarch_force_binary (SImode
, ASHIFT
, oldval
, shiftsi
);
5672 /* Do the same for the new value. */
5673 if (newval
&& newval
!= const0_rtx
)
5675 newval
= convert_modes (SImode
, mode
, newval
, true);
5676 newval
= force_reg (SImode
, newval
);
5677 newval
= loongarch_force_binary (SImode
, ASHIFT
, newval
, shiftsi
);
5680 /* Do the SImode atomic access. */
5682 res
= gen_reg_rtx (SImode
);
5685 si_op
= generator
.fn_7 (res
, memsi
, mask
, inverted_mask
, oldval
, newval
,
5688 si_op
= generator
.fn_6 (res
, memsi
, mask
, inverted_mask
, oldval
, model
);
5690 si_op
= generator
.fn_5 (memsi
, mask
, inverted_mask
, oldval
, model
);
5696 /* Shift and convert the result. */
5697 loongarch_emit_binary (AND
, res
, res
, mask
);
5698 loongarch_emit_binary (LSHIFTRT
, res
, res
, shiftsi
);
5699 loongarch_emit_move (result
, gen_lowpart (GET_MODE (result
), res
));
5703 /* Return true if (zero_extract OP WIDTH BITPOS) can be used as the
5704 source of an "ext" instruction or the destination of an "ins"
5705 instruction. OP must be a register operand and the following
5706 conditions must hold:
5708 0 <= BITPOS < GET_MODE_BITSIZE (GET_MODE (op))
5709 0 < WIDTH <= GET_MODE_BITSIZE (GET_MODE (op))
5710 0 < BITPOS + WIDTH <= GET_MODE_BITSIZE (GET_MODE (op))
5712 Also reject lengths equal to a word as they are better handled
5713 by the move patterns. */
5716 loongarch_use_ins_ext_p (rtx op
, HOST_WIDE_INT width
, HOST_WIDE_INT bitpos
)
5718 if (!register_operand (op
, VOIDmode
)
5719 || GET_MODE_BITSIZE (GET_MODE (op
)) > BITS_PER_WORD
)
5722 if (!IN_RANGE (width
, 1, GET_MODE_BITSIZE (GET_MODE (op
)) - 1))
5725 if (bitpos
< 0 || bitpos
+ width
> GET_MODE_BITSIZE (GET_MODE (op
)))
5731 /* Predicate for pre-reload splitters with associated instructions,
5732 which can match any time before the split1 pass (usually combine),
5733 then are unconditionally split in that pass and should not be
5734 matched again afterwards. */
5736 bool loongarch_pre_reload_split (void)
5738 return (can_create_pseudo_p ()
5739 && !(cfun
->curr_properties
& PROP_rtl_split_insns
));
5742 /* Check if we can use bstrins.<d> for
5743 op0 = (op1 & op2) | (op3 & op4)
5744 where op0, op1, op3 are regs, and op2, op4 are integer constants. */
5746 loongarch_use_bstrins_for_ior_with_mask (machine_mode mode
, rtx
*op
)
5748 unsigned HOST_WIDE_INT mask1
= UINTVAL (op
[2]);
5749 unsigned HOST_WIDE_INT mask2
= UINTVAL (op
[4]);
5751 if (mask1
!= ~mask2
|| !mask1
|| !mask2
)
5754 /* Try to avoid a right-shift. */
5755 if (low_bitmask_len (mode
, mask1
) != -1)
5758 if (low_bitmask_len (mode
, mask2
>> (ffs_hwi (mask2
) - 1)) != -1)
5761 if (low_bitmask_len (mode
, mask1
>> (ffs_hwi (mask1
) - 1)) != -1)
5767 /* Rewrite a MEM for simple load/store under -mexplicit-relocs=auto
5768 -mcmodel={normal/medium}. */
5770 loongarch_rewrite_mem_for_simple_ldst (rtx mem
)
5772 rtx addr
= XEXP (mem
, 0);
5773 rtx hi
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
),
5774 UNSPEC_PCALAU12I_GR
);
5777 addr
= gen_rtx_LO_SUM (Pmode
, force_reg (Pmode
, hi
), addr
);
5778 new_mem
= gen_rtx_MEM (GET_MODE (mem
), addr
);
5779 MEM_COPY_ATTRIBUTES (new_mem
, mem
);
5783 /* Print the text for PRINT_OPERAND punctation character CH to FILE.
5784 The punctuation characters are:
5786 '.' Print the name of the register with a hard-wired zero (zero or $r0).
5787 '$' Print the name of the stack pointer register (sp or $r3).
5789 See also loongarch_init_print_operand_punct. */
5792 loongarch_print_operand_punctuation (FILE *file
, int ch
)
5797 fputs (reg_names
[GP_REG_FIRST
+ 0], file
);
5801 fputs (reg_names
[STACK_POINTER_REGNUM
], file
);
5810 /* Initialize loongarch_print_operand_punct. */
5813 loongarch_init_print_operand_punct (void)
5817 for (p
= ".$"; *p
; p
++)
5818 loongarch_print_operand_punct
[(unsigned char) *p
] = true;
5821 /* PRINT_OPERAND prefix LETTER refers to the integer branch instruction
5822 associated with condition CODE. Print the condition part of the
5826 loongarch_print_int_branch_condition (FILE *file
, enum rtx_code code
,
5841 /* Conveniently, the LoongArch names for these conditions are the same
5842 as their RTL equivalents. */
5843 fputs (GET_RTX_NAME (code
), file
);
5847 output_operand_lossage ("'%%%c' is not a valid operand prefix", letter
);
5852 /* Likewise floating-point branches. */
5855 loongarch_print_float_branch_condition (FILE *file
, enum rtx_code code
,
5861 fputs ("ceqz", file
);
5865 fputs ("cnez", file
);
5869 output_operand_lossage ("'%%%c' is not a valid operand prefix", letter
);
5874 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
5877 loongarch_print_operand_punct_valid_p (unsigned char code
)
5879 return loongarch_print_operand_punct
[code
];
5882 /* Return true if a FENCE should be emitted to before a memory access to
5883 implement the release portion of memory model MODEL. */
5886 loongarch_memmodel_needs_rel_acq_fence (enum memmodel model
)
5888 switch (memmodel_base (model
))
5890 case MEMMODEL_ACQ_REL
:
5891 case MEMMODEL_SEQ_CST
:
5892 case MEMMODEL_RELEASE
:
5893 case MEMMODEL_ACQUIRE
:
5896 case MEMMODEL_RELAXED
:
5904 /* Return true if a FENCE should be emitted after a failed CAS to
5905 implement the acquire semantic of failure_memorder. */
5908 loongarch_cas_failure_memorder_needs_acquire (enum memmodel model
)
5910 switch (memmodel_base (model
))
5912 case MEMMODEL_ACQUIRE
:
5913 case MEMMODEL_ACQ_REL
:
5914 case MEMMODEL_SEQ_CST
:
5917 case MEMMODEL_RELAXED
:
5918 case MEMMODEL_RELEASE
:
5921 /* MEMMODEL_CONSUME is deliberately not handled because it's always
5922 replaced by MEMMODEL_ACQUIRE as at now. If you see an ICE caused by
5923 MEMMODEL_CONSUME, read the change (re)introducing it carefully and
5924 decide what to do. See PR 59448 and get_memmodel in builtins.cc. */
5930 /* Print symbolic operand OP, which is part of a HIGH or LO_SUM
5931 in context CONTEXT. HI_RELOC indicates a high-part reloc. */
5934 loongarch_print_operand_reloc (FILE *file
, rtx op
, bool hi64_part
,
5938 enum loongarch_symbol_type symbol_type
=
5939 loongarch_classify_symbolic_expression (op
);
5941 if (loongarch_symbol_extreme_p (symbol_type
))
5942 gcc_assert (la_opt_explicit_relocs
!= EXPLICIT_RELOCS_NONE
);
5944 switch (symbol_type
)
5946 case SYMBOL_PCREL64
:
5949 reloc
= hi_reloc
? "%pc64_hi12" : "%pc64_lo20";
5954 reloc
= hi_reloc
? "%pc_hi20" : "%pc_lo12";
5957 case SYMBOL_GOT_DISP
:
5960 if (TARGET_CMODEL_EXTREME
)
5961 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
5966 reloc
= hi_reloc
? "%got_pc_hi20" : "%got_pc_lo12";
5972 if (TARGET_CMODEL_EXTREME
)
5973 reloc
= hi_reloc
? "%ie64_pc_hi12" : "%ie64_pc_lo20";
5978 reloc
= hi_reloc
? "%ie_pc_hi20" : "%ie_pc_lo12";
5984 if (TARGET_CMODEL_EXTREME
)
5985 reloc
= hi_reloc
? "%le64_hi12" : "%le64_lo20";
5991 if (HAVE_AS_TLS_LE_RELAXATION
&& !TARGET_CMODEL_EXTREME
)
5992 reloc
= hi_reloc
? "%le_hi20_r" : "%le_lo12_r";
5994 reloc
= hi_reloc
? "%le_hi20" : "%le_lo12";
6001 if (TARGET_CMODEL_EXTREME
)
6002 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
6007 reloc
= hi_reloc
? "%gd_pc_hi20" : "%got_pc_lo12";
6013 if (TARGET_CMODEL_EXTREME
)
6014 reloc
= hi_reloc
? "%got64_pc_hi12" : "%got64_pc_lo20";
6019 reloc
= hi_reloc
? "%ld_pc_hi20" : "%got_pc_lo12";
6026 fprintf (file
, "%s(", reloc
);
6027 output_addr_const (file
, loongarch_strip_unspec_address (op
));
6031 /* Implement TARGET_PRINT_OPERAND. The LoongArch-specific operand codes are:
6033 'A' Print a _DB suffix if the memory model requires a release.
6034 'b' Print the address of a memory operand, without offset.
6035 'B' Print CONST_INT OP element 0 of a replicated CONST_VECTOR
6036 as an unsigned byte [0..255].
6037 'c' Print an integer.
6038 'C' Print the integer branch condition for comparison OP.
6039 'd' Print CONST_INT OP in decimal.
6040 'E' Print CONST_INT OP element 0 of a replicated CONST_VECTOR in decimal.
6041 'F' Print the FPU branch condition for comparison OP.
6042 'G' Print a DBAR insn for CAS failure (with an acquire semantic if
6043 needed, otherwise a simple load-load barrier).
6044 'H' Print address 52-61bit relocation associated with OP.
6045 'h' Print the high-part relocation associated with OP.
6046 'i' Print i if the operand is not a register.
6047 'L' Print the low-part relocation associated with OP.
6048 'm' Print one less than CONST_INT OP in decimal.
6049 'N' Print the inverse of the integer branch condition for comparison OP.
6050 'r' Print address 12-31bit relocation associated with OP.
6051 'R' Print address 32-51bit relocation associated with OP.
6052 'T' Print 'f' for (eq:CC ...), 't' for (ne:CC ...),
6053 'z' for (eq:?I ...), 'n' for (ne:?I ...).
6054 't' Like 'T', but with the EQ/NE cases reversed
6055 'F' Print the FPU branch condition for comparison OP.
6056 'W' Print the inverse of the FPU branch condition for comparison OP.
6057 'w' Print a LSX register.
6058 'u' Print a LASX register.
6059 'T' Print 'f' for (eq:CC ...), 't' for (ne:CC ...),
6060 'z' for (eq:?I ...), 'n' for (ne:?I ...).
6061 't' Like 'T', but with the EQ/NE cases reversed
6062 'Y' Print loongarch_fp_conditions[INTVAL (OP)]
6063 'Z' Print OP and a comma for 8CC, otherwise print nothing.
6064 'z' Print $0 if OP is zero, otherwise print OP normally.
6065 'v' Print the insn size suffix b, h, w or d for vector modes V16QI, V8HI,
6066 V4SI, V2SI, and w, d for vector modes V4SF, V2DF respectively.
6067 'V' Print exact log2 of CONST_INT OP element 0 of a replicated
6068 CONST_VECTOR in decimal.
6069 'W' Print the inverse of the FPU branch condition for comparison OP.
6070 'X' Print CONST_INT OP in hexadecimal format.
6071 'x' Print the low 16 bits of CONST_INT OP in hexadecimal format.
6072 'Y' Print loongarch_fp_conditions[INTVAL (OP)]
6073 'y' Print exact log2 of CONST_INT OP in decimal.
6074 'Z' Print OP and a comma for 8CC, otherwise print nothing.
6075 'z' Print $0 if OP is zero, otherwise print OP normally. */
6078 loongarch_print_operand (FILE *file
, rtx op
, int letter
)
6082 if (loongarch_print_operand_punct_valid_p (letter
))
6084 loongarch_print_operand_punctuation (file
, letter
);
6089 code
= GET_CODE (op
);
6094 if (loongarch_memmodel_needs_rel_acq_fence ((enum memmodel
) INTVAL (op
)))
6095 fputs ("_db", file
);
6098 if (GET_CODE (op
) == CONST_VECTOR
)
6100 gcc_assert (loongarch_const_vector_same_val_p (op
, GET_MODE (op
)));
6101 op
= CONST_VECTOR_ELT (op
, 0);
6102 gcc_assert (CONST_INT_P (op
));
6103 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
6106 output_operand_lossage ("invalid use of '%%%c'", letter
);
6111 if (CONST_INT_P (op
))
6112 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
6114 output_operand_lossage ("unsupported operand for code '%c'", letter
);
6119 loongarch_print_int_branch_condition (file
, code
, letter
);
6123 if (CONST_INT_P (op
))
6124 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
));
6126 output_operand_lossage ("invalid use of '%%%c'", letter
);
6130 loongarch_print_float_branch_condition (file
, code
, letter
);
6134 if (loongarch_cas_failure_memorder_needs_acquire (
6135 memmodel_from_int (INTVAL (op
))))
6136 fputs ("dbar\t0b10100", file
);
6137 else if (!ISA_HAS_LD_SEQ_SA
)
6138 fputs ("dbar\t0x700", file
);
6144 loongarch_print_operand_reloc (file
, op
, false /* hi64_part */,
6145 true /* hi_reloc */);
6149 loongarch_print_operand_reloc (file
, op
, true /* hi64_part */,
6150 true /* hi_reloc */);
6159 loongarch_print_operand_reloc (file
, op
, false /* hi64_part*/,
6160 false /* lo_reloc */);
6163 if (GET_CODE (op
) == CONST_VECTOR
)
6165 gcc_assert (loongarch_const_vector_same_val_p (op
, GET_MODE (op
)));
6166 op
= CONST_VECTOR_ELT (op
, 0);
6167 gcc_assert (CONST_INT_P (op
));
6168 unsigned HOST_WIDE_INT val8
= UINTVAL (op
) & GET_MODE_MASK (QImode
);
6169 fprintf (file
, HOST_WIDE_INT_PRINT_UNSIGNED
, val8
);
6172 output_operand_lossage ("invalid use of '%%%c'", letter
);
6176 if (CONST_INT_P (op
))
6177 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (op
) - 1);
6179 output_operand_lossage ("invalid use of '%%%c'", letter
);
6183 loongarch_print_int_branch_condition (file
, reverse_condition (code
),
6188 loongarch_print_operand_reloc (file
, op
, false /* hi64_part */,
6189 true /* lo_reloc */);
6193 loongarch_print_operand_reloc (file
, op
, true /* hi64_part */,
6194 false /* lo_reloc */);
6200 int truth
= (code
== NE
) == (letter
== 'T');
6201 fputc ("zfnt"[truth
* 2 + FCC_REG_P (REGNO (XEXP (op
, 0)))], file
);
6206 if (CONST_VECTOR_P (op
))
6208 machine_mode mode
= GET_MODE_INNER (GET_MODE (op
));
6209 unsigned HOST_WIDE_INT val
= UINTVAL (CONST_VECTOR_ELT (op
, 0));
6210 int vlog2
= exact_log2 (val
& GET_MODE_MASK (mode
));
6212 fprintf (file
, "%d", vlog2
);
6214 output_operand_lossage ("invalid use of '%%%c'", letter
);
6217 output_operand_lossage ("invalid use of '%%%c'", letter
);
6221 loongarch_print_float_branch_condition (file
, reverse_condition (code
),
6226 if (CONST_INT_P (op
))
6227 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
) & 0xffff);
6229 output_operand_lossage ("invalid use of '%%%c'", letter
);
6233 if (CONST_INT_P (op
))
6234 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
6236 output_operand_lossage ("invalid use of '%%%c'", letter
);
6240 if (CONST_INT_P (op
))
6242 int val
= exact_log2 (INTVAL (op
));
6244 fprintf (file
, "%d", val
);
6246 output_operand_lossage ("invalid use of '%%%c'", letter
);
6249 output_operand_lossage ("invalid use of '%%%c'", letter
);
6253 if (code
== CONST_INT
6254 && UINTVAL (op
) < ARRAY_SIZE (loongarch_fp_conditions
))
6255 fputs (loongarch_fp_conditions
[UINTVAL (op
)], file
);
6257 output_operand_lossage ("'%%%c' is not a valid operand prefix",
6262 loongarch_print_operand (file
, op
, 0);
6267 if (code
== REG
&& LSX_REG_P (REGNO (op
)))
6268 fprintf (file
, "$vr%s", ®_names
[REGNO (op
)][2]);
6270 output_operand_lossage ("invalid use of '%%%c'", letter
);
6274 if (code
== REG
&& LASX_REG_P (REGNO (op
)))
6275 fprintf (file
, "$xr%s", ®_names
[REGNO (op
)][2]);
6277 output_operand_lossage ("invalid use of '%%%c'", letter
);
6281 switch (GET_MODE (op
))
6285 fprintf (file
, "b");
6289 fprintf (file
, "h");
6295 fprintf (file
, "w");
6301 fprintf (file
, "d");
6304 output_operand_lossage ("invalid use of '%%%c'", letter
);
6313 unsigned int regno
= REGNO (op
);
6314 if (letter
&& letter
!= 'z')
6315 output_operand_lossage ("invalid use of '%%%c'", letter
);
6316 fprintf (file
, "%s", reg_names
[regno
]);
6322 output_address (GET_MODE (op
),
6323 plus_constant (Pmode
, XEXP (op
, 0), 4));
6324 else if (letter
== 'b')
6326 gcc_assert (REG_P (XEXP (op
, 0)));
6327 loongarch_print_operand (file
, XEXP (op
, 0), 0);
6329 else if (letter
&& letter
!= 'z')
6330 output_operand_lossage ("invalid use of '%%%c'", letter
);
6332 output_address (GET_MODE (op
), XEXP (op
, 0));
6336 if (letter
== 'z' && op
== CONST0_RTX (GET_MODE (op
)))
6337 fputs (reg_names
[GP_REG_FIRST
], file
);
6338 else if (letter
&& letter
!= 'z')
6339 output_operand_lossage ("invalid use of '%%%c'", letter
);
6341 output_addr_const (file
, loongarch_strip_unspec_address (op
));
6347 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
6350 loongarch_print_operand_address (FILE *file
, machine_mode
/* mode */, rtx x
)
6352 struct loongarch_address_info addr
;
6354 if (loongarch_classify_address (&addr
, x
, word_mode
, true))
6358 fprintf (file
, "%s,", reg_names
[REGNO (addr
.reg
)]);
6359 loongarch_print_operand (file
, addr
.offset
, 0);
6362 case ADDRESS_REG_REG
:
6363 fprintf (file
, "%s,%s", reg_names
[REGNO (addr
.reg
)],
6364 reg_names
[REGNO (addr
.offset
)]);
6367 case ADDRESS_LO_SUM
:
6368 fprintf (file
, "%s,", reg_names
[REGNO (addr
.reg
)]);
6369 loongarch_print_operand_reloc (file
, addr
.offset
, false /* hi64_part */,
6370 false /* hi_reloc */);
6373 case ADDRESS_CONST_INT
:
6374 fprintf (file
, "%s,", reg_names
[GP_REG_FIRST
]);
6375 output_addr_const (file
, x
);
6378 case ADDRESS_SYMBOLIC
:
6379 output_addr_const (file
, loongarch_strip_unspec_address (x
));
6382 if (CONST_INT_P (x
))
6383 output_addr_const (file
, x
);
6388 /* Implement TARGET_ASM_SELECT_RTX_SECTION. */
6391 loongarch_select_rtx_section (machine_mode mode
, rtx x
,
6392 unsigned HOST_WIDE_INT align
)
6394 /* ??? Consider using mergeable small data sections. */
6395 if (loongarch_rtx_constant_in_small_data_p (mode
))
6396 return get_named_section (NULL
, ".sdata", 0);
6398 return default_elf_select_rtx_section (mode
, x
, align
);
6401 /* Implement TARGET_ASM_FUNCTION_RODATA_SECTION.
6403 The complication here is that jump tables will use absolute addresses,
6404 and should therefore not be included in the read-only part of a DSO.
6405 Handle such cases by selecting a normal data section instead of a
6406 read-only one. The logic apes that in default_function_rodata_section. */
6409 loongarch_function_rodata_section (tree decl
, bool)
6411 return default_function_rodata_section (decl
, false);
6414 /* Implement TARGET_IN_SMALL_DATA_P. */
6417 loongarch_in_small_data_p (const_tree decl
)
6421 if (TREE_CODE (decl
) == STRING_CST
|| TREE_CODE (decl
) == FUNCTION_DECL
)
6424 if (VAR_P (decl
) && DECL_SECTION_NAME (decl
) != 0)
6428 /* Reject anything that isn't in a known small-data section. */
6429 name
= DECL_SECTION_NAME (decl
);
6430 if (strcmp (name
, ".sdata") != 0 && strcmp (name
, ".sbss") != 0)
6433 /* If a symbol is defined externally, the assembler will use the
6434 usual -G rules when deciding how to implement macros. */
6435 if (!DECL_EXTERNAL (decl
))
6439 /* We have traditionally not treated zero-sized objects as small data,
6440 so this is now effectively part of the ABI. */
6441 size
= int_size_in_bytes (TREE_TYPE (decl
));
6442 return size
> 0 && size
<= g_switch_value
;
6445 /* The LoongArch debug format wants all automatic variables and arguments
6446 to be in terms of the virtual frame pointer (stack pointer before
6447 any adjustment in the function), while the LoongArch linker wants
6448 the frame pointer to be the stack pointer after the initial
6449 adjustment. So, we do the adjustment here. The arg pointer (which
6450 is eliminated) points to the virtual frame pointer, while the frame
6451 pointer (which may be eliminated) points to the stack pointer after
6452 the initial adjustments. */
6455 loongarch_debugger_offset (rtx addr
, HOST_WIDE_INT offset
)
6457 rtx offset2
= const0_rtx
;
6458 rtx reg
= eliminate_constant_term (addr
, &offset2
);
6461 offset
= INTVAL (offset2
);
6463 if (reg
== stack_pointer_rtx
6464 || reg
== frame_pointer_rtx
6465 || reg
== hard_frame_pointer_rtx
)
6467 offset
-= cfun
->machine
->frame
.total_size
;
6468 if (reg
== hard_frame_pointer_rtx
)
6469 offset
+= cfun
->machine
->frame
.hard_frame_pointer_offset
;
6475 /* Implement ASM_OUTPUT_EXTERNAL. */
6478 loongarch_output_external (FILE *file
, tree decl
, const char *name
)
6480 default_elf_asm_output_external (file
, decl
, name
);
6482 /* We output the name if and only if TREE_SYMBOL_REFERENCED is
6483 set in order to avoid putting out names that are never really
6485 if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl
)))
6487 if (loongarch_in_small_data_p (decl
))
6489 /* When using assembler macros, emit .extern directives for
6490 all small-data externs so that the assembler knows how
6493 In most cases it would be safe (though pointless) to emit
6494 .externs for other symbols too. One exception is when an
6495 object is within the -G limit but declared by the user to
6496 be in a section other than .sbss or .sdata. */
6497 fputs ("\t.extern\t", file
);
6498 assemble_name (file
, name
);
6499 fprintf (file
, ", " HOST_WIDE_INT_PRINT_DEC
"\n",
6500 int_size_in_bytes (TREE_TYPE (decl
)));
6505 /* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL. */
6507 static void ATTRIBUTE_UNUSED
6508 loongarch_output_dwarf_dtprel (FILE *file
, int size
, rtx x
)
6513 fputs ("\t.dtprelword\t", file
);
6517 fputs ("\t.dtpreldword\t", file
);
6523 output_addr_const (file
, x
);
6524 fputs ("+0x8000", file
);
6527 /* Implement ASM_OUTPUT_ASCII. */
6530 loongarch_output_ascii (FILE *stream
, const char *string
, size_t len
)
6536 fprintf (stream
, "\t.ascii\t\"");
6537 for (i
= 0; i
< len
; i
++)
6541 c
= (unsigned char) string
[i
];
6544 if (c
== '\\' || c
== '\"')
6546 putc ('\\', stream
);
6554 fprintf (stream
, "\\%03o", c
);
6558 if (cur_pos
> 72 && i
+ 1 < len
)
6561 fprintf (stream
, "\"\n\t.ascii\t\"");
6564 fprintf (stream
, "\"\n");
6567 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
6570 loongarch_frame_pointer_required (void)
6572 /* If the function contains dynamic stack allocations, we need to
6573 use the frame pointer to access the static parts of the frame. */
6574 if (cfun
->calls_alloca
)
6580 /* Implement TARGET_CAN_ELIMINATE. Make sure that we're not trying
6581 to eliminate to the wrong hard frame pointer. */
6584 loongarch_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
6586 return (to
== HARD_FRAME_POINTER_REGNUM
|| to
== STACK_POINTER_REGNUM
);
6589 /* Implement RETURN_ADDR_RTX. We do not support moving back to a
6593 loongarch_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
6598 return get_hard_reg_initial_val (Pmode
, RETURN_ADDR_REGNUM
);
6601 /* Emit code to change the current function's return address to
6602 ADDRESS. SCRATCH is available as a scratch register, if needed.
6603 ADDRESS and SCRATCH are both word-mode GPRs. */
6606 loongarch_set_return_address (rtx address
, rtx scratch
)
6610 gcc_assert (BITSET_P (cfun
->machine
->frame
.mask
, RETURN_ADDR_REGNUM
));
6612 if (frame_pointer_needed
)
6613 slot_address
= loongarch_add_offset (scratch
, hard_frame_pointer_rtx
,
6616 slot_address
= loongarch_add_offset (scratch
, stack_pointer_rtx
,
6617 cfun
->machine
->frame
.gp_sp_offset
);
6619 loongarch_emit_move (gen_frame_mem (GET_MODE (address
), slot_address
),
6623 /* Return true if register REGNO can store a value of mode MODE.
6624 The result of this function is cached in loongarch_hard_regno_mode_ok. */
6627 loongarch_hard_regno_mode_ok_uncached (unsigned int regno
, machine_mode mode
)
6630 enum mode_class mclass
;
6632 if (mode
== FCCmode
)
6633 return FCC_REG_P (regno
) || GP_REG_P (regno
) || FP_REG_P (regno
);
6635 size
= GET_MODE_SIZE (mode
);
6636 mclass
= GET_MODE_CLASS (mode
);
6638 if (GP_REG_P (regno
) && !LSX_SUPPORTED_MODE_P (mode
)
6639 && !LASX_SUPPORTED_MODE_P (mode
))
6640 return ((regno
- GP_REG_FIRST
) & 1) == 0 || size
<= UNITS_PER_WORD
;
6642 /* For LSX, allow TImode and 128-bit vector modes in all FPR. */
6643 if (FP_REG_P (regno
) && LSX_SUPPORTED_MODE_P (mode
))
6646 /* FIXED ME: For LASX, allow TImode and 256-bit vector modes in all FPR. */
6647 if (FP_REG_P (regno
) && LASX_SUPPORTED_MODE_P (mode
))
6650 if (FP_REG_P (regno
))
6652 if (mclass
== MODE_FLOAT
6653 || mclass
== MODE_COMPLEX_FLOAT
6654 || mclass
== MODE_VECTOR_FLOAT
)
6655 return size
<= UNITS_PER_FPVALUE
;
6657 /* Allow integer modes that fit into a single register. We need
6658 to put integers into FPRs when using instructions like CVT
6659 and TRUNC. There's no point allowing sizes smaller than a word,
6660 because the FPU has no appropriate load/store instructions. */
6661 if (mclass
== MODE_INT
)
6662 return size
>= MIN_UNITS_PER_WORD
&& size
<= UNITS_PER_FPREG
;
6668 /* Implement TARGET_HARD_REGNO_MODE_OK. */
6671 loongarch_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
6673 return loongarch_hard_regno_mode_ok_p
[mode
][regno
];
6678 loongarch_hard_regno_call_part_clobbered (unsigned int,
6679 unsigned int regno
, machine_mode mode
)
6681 if (ISA_HAS_LSX
&& FP_REG_P (regno
) && GET_MODE_SIZE (mode
) > 8)
6687 /* Implement TARGET_HARD_REGNO_NREGS. */
6690 loongarch_hard_regno_nregs (unsigned int regno
, machine_mode mode
)
6692 if (FCC_REG_P (regno
))
6693 /* The size of FP status registers is always 4, because they only hold
6694 FCCmode values, and FCCmode is always considered to be 4 bytes wide. */
6695 return (GET_MODE_SIZE (mode
) + 3) / 4;
6697 if (FP_REG_P (regno
))
6699 if (LSX_SUPPORTED_MODE_P (mode
))
6702 if (LASX_SUPPORTED_MODE_P (mode
))
6705 return (GET_MODE_SIZE (mode
) + UNITS_PER_FPREG
- 1) / UNITS_PER_FPREG
;
6708 /* All other registers are word-sized. */
6709 return (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
6712 /* Implement CLASS_MAX_NREGS, taking the maximum of the cases
6713 in loongarch_hard_regno_nregs. */
6716 loongarch_class_max_nregs (enum reg_class rclass
, machine_mode mode
)
6722 left
= reg_class_contents
[rclass
];
6723 if (hard_reg_set_intersect_p (left
, reg_class_contents
[(int) FCC_REGS
]))
6725 if (loongarch_hard_regno_mode_ok (FCC_REG_FIRST
, mode
))
6726 size
= MIN (size
, 4);
6728 left
&= ~reg_class_contents
[FCC_REGS
];
6730 if (hard_reg_set_intersect_p (left
, reg_class_contents
[(int) FP_REGS
]))
6732 if (loongarch_hard_regno_mode_ok (FP_REG_FIRST
, mode
))
6735 if (LASX_SUPPORTED_MODE_P (mode
))
6736 size
= MIN (size
, UNITS_PER_LASX_REG
);
6737 else if (LSX_SUPPORTED_MODE_P (mode
))
6738 size
= MIN (size
, UNITS_PER_LSX_REG
);
6740 size
= MIN (size
, UNITS_PER_FPREG
);
6742 left
&= ~reg_class_contents
[FP_REGS
];
6744 if (!hard_reg_set_empty_p (left
))
6745 size
= MIN (size
, UNITS_PER_WORD
);
6746 return (GET_MODE_SIZE (mode
) + size
- 1) / size
;
6749 /* Implement TARGET_CAN_CHANGE_MODE_CLASS. */
6752 loongarch_can_change_mode_class (machine_mode from
, machine_mode to
,
6755 /* Allow conversions between different LSX/LASX vector modes. */
6756 if (LASX_SUPPORTED_MODE_P (from
) && LASX_SUPPORTED_MODE_P (to
))
6759 /* Allow conversions between different LSX vector modes. */
6760 if (LSX_SUPPORTED_MODE_P (from
) && LSX_SUPPORTED_MODE_P (to
))
6763 /* Allow conversion between LSX vector mode and scalar fp mode. */
6764 if ((LSX_SUPPORTED_MODE_P (from
) && SCALAR_FLOAT_MODE_P (to
))
6765 || ((SCALAR_FLOAT_MODE_P (from
) && LSX_SUPPORTED_MODE_P (to
))))
6768 return !reg_classes_intersect_p (FP_REGS
, rclass
);
6771 /* Return true if moves in mode MODE can use the FPU's fmov.fmt instruction,
6775 loongarch_mode_ok_for_mov_fmt_p (machine_mode mode
)
6781 return TARGET_HARD_FLOAT
;
6784 return TARGET_HARD_FLOAT
&& TARGET_DOUBLE_FLOAT
;
6787 return ISA_HAS_LASX
? LASX_SUPPORTED_MODE_P (mode
)
6788 : LSX_SUPPORTED_MODE_P (mode
);
6792 /* Implement TARGET_MODES_TIEABLE_P. */
6795 loongarch_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
6797 /* FPRs allow no mode punning, so it's not worth tying modes if we'd
6798 prefer to put one of them in FPRs. */
6799 return (mode1
== mode2
6800 || (!loongarch_mode_ok_for_mov_fmt_p (mode1
)
6801 && !loongarch_mode_ok_for_mov_fmt_p (mode2
)));
6804 /* Implement TARGET_PREFERRED_RELOAD_CLASS. */
6807 loongarch_preferred_reload_class (rtx x
, reg_class_t rclass
)
6809 if (reg_class_subset_p (FP_REGS
, rclass
)
6810 && loongarch_mode_ok_for_mov_fmt_p (GET_MODE (x
)))
6813 if (reg_class_subset_p (GR_REGS
, rclass
))
6819 /* RCLASS is a class involved in a REGISTER_MOVE_COST calculation.
6820 Return a "canonical" class to represent it in later calculations. */
6823 loongarch_canonicalize_move_class (reg_class_t rclass
)
6825 if (reg_class_subset_p (rclass
, GENERAL_REGS
))
6826 rclass
= GENERAL_REGS
;
6831 /* Return the cost of moving a value from a register of class FROM to a GPR.
6832 Return 0 for classes that are unions of other classes handled by this
6836 loongarch_move_to_gpr_cost (reg_class_t from
)
6845 /* MOVFR2GR, etc. */
6849 return loongarch_cost
->movcf2gr
;
6856 /* Return the cost of moving a value from a GPR to a register of class TO.
6857 Return 0 for classes that are unions of other classes handled by this
6861 loongarch_move_from_gpr_cost (reg_class_t to
)
6870 /* MOVGR2FR, etc. */
6874 return loongarch_cost
->movgr2cf
;
6881 /* Implement TARGET_REGISTER_MOVE_COST. Return 0 for classes that are the
6882 maximum of the move costs for subclasses; regclass will work out
6883 the maximum for us. */
6886 loongarch_register_move_cost (machine_mode mode
, reg_class_t from
,
6892 from
= loongarch_canonicalize_move_class (from
);
6893 to
= loongarch_canonicalize_move_class (to
);
6895 /* Handle moves that can be done without using general-purpose registers. */
6896 if (from
== FP_REGS
)
6898 if (to
== FP_REGS
&& loongarch_mode_ok_for_mov_fmt_p (mode
))
6903 /* Handle cases in which only one class deviates from the ideal. */
6904 dregs
= GENERAL_REGS
;
6906 return loongarch_move_from_gpr_cost (to
);
6908 return loongarch_move_to_gpr_cost (from
);
6910 /* fcc -> fcc, fcc -> fpr, or fpr -> fcc. */
6911 if (from
== FCC_REGS
|| to
== FCC_REGS
)
6912 return COSTS_N_INSNS (from
== to
? 2 : 1);
6914 /* Handles cases that require a GPR temporary. */
6915 cost1
= loongarch_move_to_gpr_cost (from
);
6918 cost2
= loongarch_move_from_gpr_cost (to
);
6920 return cost1
+ cost2
;
6926 /* Implement TARGET_MEMORY_MOVE_COST. */
6929 loongarch_memory_move_cost (machine_mode mode
, reg_class_t rclass
, bool in
)
6931 return (loongarch_cost
->memory_latency
6932 + memory_move_secondary_cost (mode
, rclass
, in
));
6935 /* Return the register class required for a secondary register when
6936 copying between one of the registers in RCLASS and value X, which
6937 has mode MODE. X is the source of the move if IN_P, otherwise it
6938 is the destination. Return NO_REGS if no secondary register is
6942 loongarch_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x
,
6943 reg_class_t rclass
, machine_mode mode
,
6944 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
6948 regno
= true_regnum (x
);
6950 if (mode
== FCCmode
)
6952 if (reg_class_subset_p (rclass
, FCC_REGS
) && !FP_REG_P (regno
))
6954 if (FCC_REG_P (regno
))
6957 auto fn
= in_p
? loongarch_move_from_gpr_cost
6958 : loongarch_move_to_gpr_cost
;
6960 if (fn (FCC_REGS
) > fn (FP_REGS
) + COSTS_N_INSNS (1))
6963 return GP_REG_P (regno
) ? NO_REGS
: GR_REGS
;
6966 if (reg_class_subset_p (rclass
, GR_REGS
) && FCC_REG_P (regno
))
6968 auto fn
= in_p
? loongarch_move_to_gpr_cost
6969 : loongarch_move_from_gpr_cost
;
6971 if (fn (FCC_REGS
) > fn (FP_REGS
) + COSTS_N_INSNS (1))
6977 if (reg_class_subset_p (rclass
, FP_REGS
)
6978 && (regno
== -1 || MEM_P (x
)))
6984 if (reg_class_subset_p (rclass
, FP_REGS
))
6988 && (GET_MODE_SIZE (mode
) == 4 || GET_MODE_SIZE (mode
) == 8)))
6989 /* In this case we can use lwc1, swc1, ldc1 or sdc1. We'll use
6990 pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported. */
6993 if (MEM_P (x
) && LSX_SUPPORTED_MODE_P (mode
))
6994 /* In this case we can use LSX LD.* and ST.*. */
6997 if (GP_REG_P (regno
) || x
== CONST0_RTX (mode
))
6998 /* In this case we can use movgr2fr.s, movfr2gr.s, movgr2fr.d or
7002 if (CONSTANT_P (x
) && !targetm
.cannot_force_const_mem (mode
, x
))
7003 /* We can force the constant to memory and use fld.s
7004 and fld.d. As above, we will use pairs of lwc1s if
7005 ldc1 is not supported. */
7008 if (FP_REG_P (regno
) && loongarch_mode_ok_for_mov_fmt_p (mode
))
7009 /* In this case we can use fmov.{s/d}. */
7012 /* Otherwise, we need to reload through an integer register. */
7015 if (FP_REG_P (regno
))
7016 return reg_class_subset_p (rclass
, GR_REGS
) ? NO_REGS
: GR_REGS
;
7021 /* Implement TARGET_VALID_POINTER_MODE. */
7024 loongarch_valid_pointer_mode (scalar_int_mode mode
)
7026 return mode
== SImode
|| (TARGET_64BIT
&& mode
== DImode
);
7029 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
7032 loongarch_vector_mode_supported_p (machine_mode mode
)
7034 return ISA_HAS_LASX
? LASX_SUPPORTED_MODE_P (mode
)
7035 : LSX_SUPPORTED_MODE_P (mode
);
7038 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
7041 loongarch_scalar_mode_supported_p (scalar_mode mode
)
7043 if (ALL_FIXED_POINT_MODE_P (mode
)
7044 && GET_MODE_PRECISION (mode
) <= 2 * BITS_PER_WORD
)
7047 return default_scalar_mode_supported_p (mode
);
7050 /* Implement TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
7053 loongarch_preferred_simd_mode (scalar_mode mode
)
7061 return ISA_HAS_LASX
? E_V32QImode
: E_V16QImode
;
7063 return ISA_HAS_LASX
? E_V16HImode
: E_V8HImode
;
7065 return ISA_HAS_LASX
? E_V8SImode
: E_V4SImode
;
7067 return ISA_HAS_LASX
? E_V4DImode
: E_V2DImode
;
7070 return ISA_HAS_LASX
? E_V8SFmode
: E_V4SFmode
;
7073 return ISA_HAS_LASX
? E_V4DFmode
: E_V2DFmode
;
7082 loongarch_autovectorize_vector_modes (vector_modes
*modes
, bool)
7086 modes
->safe_push (V32QImode
);
7087 modes
->safe_push (V16QImode
);
7089 else if (ISA_HAS_LSX
)
7091 modes
->safe_push (V16QImode
);
7097 /* Return the assembly code for INSN, which has the operands given by
7098 OPERANDS, and which branches to OPERANDS[0] if some condition is true.
7099 BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[0]
7100 is in range of a direct branch. BRANCH_IF_FALSE is an inverted
7101 version of BRANCH_IF_TRUE. */
7104 loongarch_output_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
7105 const char *branch_if_true
,
7106 const char *branch_if_false
)
7108 unsigned int length
;
7111 gcc_assert (LABEL_P (operands
[0]));
7113 length
= get_attr_length (insn
);
7116 return branch_if_true
;
7119 /* Generate a reversed branch around a direct jump. */
7120 rtx_code_label
*not_taken
= gen_label_rtx ();
7121 taken
= operands
[0];
7123 /* Generate the reversed branch to NOT_TAKEN. */
7124 operands
[0] = not_taken
;
7125 output_asm_insn (branch_if_false
, operands
);
7127 output_asm_insn ("b\t%0", &taken
);
7129 /* Output NOT_TAKEN. */
7130 targetm
.asm_out
.internal_label (asm_out_file
, "L",
7131 CODE_LABEL_NUMBER (not_taken
));
7135 /* Return the assembly code for INSN, which branches to OPERANDS[0]
7136 if some equality condition is true. The condition is given by
7137 OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
7138 OPERANDS[1]. OPERANDS[2] is the comparison's first operand;
7139 OPERANDS[3] is the second operand and may be zero or a register. */
7142 loongarch_output_equal_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
7145 const char *branch
[2];
7146 if (operands
[3] == const0_rtx
)
7148 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1z", "%2,%0");
7149 branch
[inverted_p
] = LARCH_BRANCH ("b%N1z", "%2,%0");
7153 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,%z3,%0");
7154 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,%z3,%0");
7157 return loongarch_output_conditional_branch (insn
, operands
, branch
[1],
7161 /* Return the assembly code for INSN, which branches to OPERANDS[0]
7162 if some ordering condition is true. The condition is given by
7163 OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
7164 OPERANDS[1]. OPERANDS[2] is the comparison's first operand;
7165 OPERANDS[3] is the second operand and may be zero or a register. */
7168 loongarch_output_order_conditional_branch (rtx_insn
*insn
, rtx
*operands
,
7171 const char *branch
[2];
7173 /* Make BRANCH[1] branch to OPERANDS[0] when the condition is true.
7174 Make BRANCH[0] branch on the inverse condition. */
7175 if (operands
[3] != const0_rtx
)
7177 /* Handle degenerate cases that should not, but do, occur. */
7178 if (REGNO (operands
[2]) == REGNO (operands
[3]))
7180 switch (GET_CODE (operands
[1]))
7186 inverted_p
= !inverted_p
;
7192 branch
[!inverted_p
] = LARCH_BRANCH ("b", "%0");
7193 branch
[inverted_p
] = "\t# branch never";
7201 switch (GET_CODE (operands
[1]))
7211 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,%3,%0");
7212 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,%3,%0");
7221 switch (GET_CODE (operands
[1]))
7223 /* These cases are equivalent to comparisons against zero. */
7232 branch
[!inverted_p
] = LARCH_BRANCH ("b%C1", "%2,$r0,%0");
7233 branch
[inverted_p
] = LARCH_BRANCH ("b%N1", "%2,$r0,%0");
7239 return loongarch_output_conditional_branch (insn
, operands
, branch
[1],
7243 /* Return the assembly code for DIV.{W/D} instruction DIVISION, which has
7244 the operands given by OPERANDS. Add in a divide-by-zero check if needed.
7248 loongarch_output_division (const char *division
, rtx
*operands
)
7253 if (loongarch_check_zero_div_p ())
7255 output_asm_insn (s
, operands
);
7256 s
= "bne\t%2,%.,1f\n\tbreak\t7\n1:";
7261 /* Return the assembly code for LSX DIV_{S,U}.DF or MOD_{S,U}.DF instructions,
7262 which has the operands given by OPERANDS. Add in a divide-by-zero check
7266 loongarch_lsx_output_division (const char *division
, rtx
*operands
)
7269 machine_mode mode
= GET_MODE (*operands
);
7272 if (TARGET_CHECK_ZERO_DIV
)
7274 if (ISA_HAS_LASX
&& GET_MODE_SIZE (mode
) == 32)
7276 output_asm_insn ("xvsetallnez.%v0\t$fcc7,%u2",operands
);
7277 output_asm_insn (s
, operands
);
7278 output_asm_insn ("bcnez\t$fcc7,1f", operands
);
7280 else if (ISA_HAS_LSX
)
7282 output_asm_insn ("vsetallnez.%v0\t$fcc7,%w2",operands
);
7283 output_asm_insn (s
, operands
);
7284 output_asm_insn ("bcnez\t$fcc7,1f", operands
);
7291 /* Implement TARGET_SCHED_ADJUST_COST. We assume that anti and output
7292 dependencies have no cost. */
7295 loongarch_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
7298 if (dep_type
!= 0 && (dep_type
!= REG_DEP_OUTPUT
))
7303 /* Return the number of instructions that can be issued per cycle. */
7306 loongarch_issue_rate (void)
7308 if ((unsigned long) la_target
.cpu_tune
< N_TUNE_TYPES
)
7309 return loongarch_cpu_issue_rate
[la_target
.cpu_tune
];
7314 /* Implement TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD. This should
7315 be as wide as the scheduling freedom in the DFA. */
7318 loongarch_multipass_dfa_lookahead (void)
7320 if ((unsigned long) la_target
.cpu_tune
< N_ARCH_TYPES
)
7321 return loongarch_cpu_multipass_dfa_lookahead
[la_target
.cpu_tune
];
7326 /* Implement TARGET_SCHED_REORDER. */
7329 loongarch_sched_reorder (FILE *file ATTRIBUTE_UNUSED
,
7330 int verbose ATTRIBUTE_UNUSED
,
7331 rtx_insn
**ready ATTRIBUTE_UNUSED
,
7332 int *nreadyp ATTRIBUTE_UNUSED
,
7333 int cycle ATTRIBUTE_UNUSED
)
7335 return loongarch_issue_rate ();
7338 /* Implement TARGET_SCHED_REORDER2. */
7341 loongarch_sched_reorder2 (FILE *file ATTRIBUTE_UNUSED
,
7342 int verbose ATTRIBUTE_UNUSED
,
7343 rtx_insn
**ready ATTRIBUTE_UNUSED
,
7344 int *nreadyp ATTRIBUTE_UNUSED
,
7345 int cycle ATTRIBUTE_UNUSED
)
7347 return cached_can_issue_more
;
7350 /* Implement TARGET_SCHED_INIT. */
7353 loongarch_sched_init (FILE *file ATTRIBUTE_UNUSED
,
7354 int verbose ATTRIBUTE_UNUSED
,
7355 int max_ready ATTRIBUTE_UNUSED
)
7358 /* Implement TARGET_SCHED_VARIABLE_ISSUE. */
7361 loongarch_variable_issue (FILE *file ATTRIBUTE_UNUSED
,
7362 int verbose ATTRIBUTE_UNUSED
, rtx_insn
*insn
,
7365 /* Ignore USEs and CLOBBERs; don't count them against the issue rate. */
7366 if (USEFUL_INSN_P (insn
))
7368 if (get_attr_type (insn
) != TYPE_GHOST
)
7372 /* Instructions of type 'multi' should all be split before
7373 the second scheduling pass. */
7374 gcc_assert (!reload_completed
7375 || recog_memoized (insn
) < 0
7376 || get_attr_type (insn
) != TYPE_MULTI
);
7378 cached_can_issue_more
= more
;
7382 /* Given that we have an rtx of the form (prefetch ... WRITE LOCALITY),
7383 return the first operand of the associated PREF or PREFX insn. */
7386 loongarch_prefetch_cookie (rtx write
, rtx locality
)
7388 /* store_streamed / load_streamed. */
7389 if (INTVAL (locality
) <= 0)
7390 return GEN_INT (INTVAL (write
) + 4);
7393 if (INTVAL (locality
) <= 2)
7396 /* store_retained / load_retained. */
7397 return GEN_INT (INTVAL (write
) + 6);
7400 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
7401 in order to avoid duplicating too much logic from elsewhere. */
7404 loongarch_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
7405 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
7408 const char *fnname
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl
));
7409 rtx this_rtx
, temp1
, temp2
, fnaddr
;
7413 /* Pretend to be a post-reload pass while generating rtl. */
7414 reload_completed
= 1;
7416 /* Mark the end of the (empty) prologue. */
7417 emit_note (NOTE_INSN_PROLOGUE_END
);
7419 /* Determine if we can use a sibcall to call FUNCTION directly. */
7420 fnaddr
= XEXP (DECL_RTL (function
), 0);
7421 use_sibcall_p
= const_call_insn_operand (fnaddr
, Pmode
);
7423 /* We need two temporary registers in some cases. */
7424 temp1
= gen_rtx_REG (Pmode
, 12);
7425 temp2
= gen_rtx_REG (Pmode
, 13);
7427 /* Find out which register contains the "this" pointer. */
7428 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
7429 this_rtx
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
+ 1);
7431 this_rtx
= gen_rtx_REG (Pmode
, GP_ARG_FIRST
);
7433 /* Add DELTA to THIS_RTX. */
7436 rtx offset
= GEN_INT (delta
);
7437 if (!IMM12_OPERAND (delta
))
7439 loongarch_emit_move (temp1
, offset
);
7442 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
7445 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
7446 if (vcall_offset
!= 0)
7450 /* Set TEMP1 to *THIS_RTX. */
7451 loongarch_emit_move (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
7453 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
7454 addr
= loongarch_add_offset (temp2
, temp1
, vcall_offset
);
7456 /* Load the offset and add it to THIS_RTX. */
7457 loongarch_emit_move (temp1
, gen_rtx_MEM (Pmode
, addr
));
7458 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
7461 /* Jump to the target function. Use a sibcall if direct jumps are
7462 allowed, otherwise load the address into a register first. */
7465 insn
= emit_call_insn (gen_sibcall_internal (fnaddr
, const0_rtx
));
7466 SIBLING_CALL_P (insn
) = 1;
7470 loongarch_emit_move (temp1
, fnaddr
);
7471 emit_jump_insn (gen_indirect_jump (temp1
));
7474 /* Run just enough of rest_of_compilation. This sequence was
7475 "borrowed" from alpha.c. */
7476 insn
= get_insns ();
7477 split_all_insns_noflow ();
7478 shorten_branches (insn
);
7479 assemble_start_function (thunk_fndecl
, fnname
);
7480 final_start_function (insn
, file
, 1);
7481 final (insn
, file
, 1);
7482 final_end_function ();
7483 assemble_end_function (thunk_fndecl
, fnname
);
7485 /* Stop pretending to be a post-reload pass. */
7486 reload_completed
= 0;
7489 /* Allocate a chunk of memory for per-function machine-dependent data. */
7491 static struct machine_function
*
7492 loongarch_init_machine_status (void)
7494 return ggc_cleared_alloc
<machine_function
> ();
7498 loongarch_cpu_option_override (struct loongarch_target
*target
,
7499 struct gcc_options
*opts
,
7500 struct gcc_options
*opts_set
)
7503 if (opts
->x_flag_align_functions
&& !opts
->x_str_align_functions
)
7504 opts
->x_str_align_functions
7505 = loongarch_cpu_align
[target
->cpu_tune
].function
;
7507 if (opts
->x_flag_align_labels
&& !opts
->x_str_align_labels
)
7508 opts
->x_str_align_labels
= loongarch_cpu_align
[target
->cpu_tune
].label
;
7510 /* Set up parameters to be used in prefetching algorithm. */
7511 int simultaneous_prefetches
7512 = loongarch_cpu_cache
[target
->cpu_tune
].simultaneous_prefetches
;
7514 SET_OPTION_IF_UNSET (opts
, opts_set
, param_simultaneous_prefetches
,
7515 simultaneous_prefetches
);
7517 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l1_cache_line_size
,
7518 loongarch_cpu_cache
[target
->cpu_tune
].l1d_line_size
);
7520 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l1_cache_size
,
7521 loongarch_cpu_cache
[target
->cpu_tune
].l1d_size
);
7523 SET_OPTION_IF_UNSET (opts
, opts_set
, param_l2_cache_size
,
7524 loongarch_cpu_cache
[target
->cpu_tune
].l2d_size
);
7528 loongarch_option_override_internal (struct gcc_options
*opts
,
7529 struct gcc_options
*opts_set
)
7536 loongarch_init_target (&la_target
,
7537 la_opt_cpu_arch
, la_opt_cpu_tune
, la_opt_fpu
,
7538 la_opt_simd
, la_opt_abi_base
, la_opt_abi_ext
,
7539 la_opt_cmodel
, opts
->x_la_isa_evolution
,
7540 opts_set
->x_la_isa_evolution
);
7542 /* Handle target-specific options: compute defaults/conflicts etc. */
7543 loongarch_config_target (&la_target
, NULL
, 0);
7545 loongarch_update_gcc_opt_status (&la_target
, opts
, opts_set
);
7546 loongarch_cpu_option_override (&la_target
, opts
, opts_set
);
7548 if (TARGET_ABI_LP64
)
7549 flag_pcc_struct_return
= 0;
7551 /* Decide which rtx_costs structure to use. */
7553 loongarch_cost
= &loongarch_rtx_cost_optimize_size
;
7555 loongarch_cost
= &loongarch_cpu_rtx_cost_data
[la_target
.cpu_tune
];
7557 /* If the user hasn't specified a branch cost, use the processor's
7559 if (la_branch_cost
== 0)
7560 la_branch_cost
= loongarch_cost
->branch_cost
;
7562 /* Enable sw prefetching at -O3 and higher. */
7563 if (opts
->x_flag_prefetch_loop_arrays
< 0
7564 && (opts
->x_optimize
>= 3 || opts
->x_flag_profile_use
)
7565 && !opts
->x_optimize_size
)
7566 opts
->x_flag_prefetch_loop_arrays
= 1;
7568 if (TARGET_DIRECT_EXTERN_ACCESS
&& flag_shlib
)
7569 error ("%qs cannot be used for compiling a shared library",
7570 "-mdirect-extern-access");
7572 switch (la_target
.cmodel
)
7574 case CMODEL_EXTREME
:
7575 if (la_opt_explicit_relocs
== EXPLICIT_RELOCS_NONE
)
7576 error ("code model %qs is not compatible with %s",
7577 "extreme", "-mexplicit-relocs=none");
7579 if (opts
->x_flag_plt
)
7581 if (global_options_set
.x_flag_plt
)
7582 error ("code model %qs is not compatible with %s",
7583 "extreme", "-fplt");
7584 opts
->x_flag_plt
= 0;
7588 case CMODEL_TINY_STATIC
:
7599 /* Validate the guard size. */
7600 int guard_size
= param_stack_clash_protection_guard_size
;
7602 /* Enforce that interval is the same size as size so the mid-end does the
7604 SET_OPTION_IF_UNSET (opts
, &global_options_set
,
7605 param_stack_clash_protection_probe_interval
,
7608 loongarch_init_print_operand_punct ();
7610 /* Set up array to map GCC register number to debug register number.
7611 Ignore the special purpose register numbers. */
7613 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
7615 if (GP_REG_P (i
) || FP_REG_P (i
))
7616 loongarch_dwarf_regno
[i
] = i
;
7618 loongarch_dwarf_regno
[i
] = INVALID_REGNUM
;
7621 /* Set up loongarch_hard_regno_mode_ok. */
7622 for (mode
= 0; mode
< MAX_MACHINE_MODE
; mode
++)
7623 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
7624 loongarch_hard_regno_mode_ok_p
[mode
][regno
]
7625 = loongarch_hard_regno_mode_ok_uncached (regno
, (machine_mode
) mode
);
7627 /* Function to allocate machine-dependent function status. */
7628 init_machine_status
= &loongarch_init_machine_status
;
7630 /* -mrecip options. */
7633 const char *string
; /* option name. */
7634 unsigned int mask
; /* mask bits to set. */
7636 const recip_options
[] = {
7637 { "all", RECIP_MASK_ALL
},
7638 { "none", RECIP_MASK_NONE
},
7639 { "div", RECIP_MASK_DIV
},
7640 { "sqrt", RECIP_MASK_SQRT
},
7641 { "rsqrt", RECIP_MASK_RSQRT
},
7642 { "vec-div", RECIP_MASK_VEC_DIV
},
7643 { "vec-sqrt", RECIP_MASK_VEC_SQRT
},
7644 { "vec-rsqrt", RECIP_MASK_VEC_RSQRT
},
7649 char *p
= ASTRDUP (la_recip_name
);
7651 unsigned int mask
, i
;
7654 while ((q
= strtok (p
, ",")) != NULL
)
7665 if (!strcmp (q
, "default"))
7666 mask
= RECIP_MASK_ALL
;
7669 for (i
= 0; i
< ARRAY_SIZE (recip_options
); i
++)
7670 if (!strcmp (q
, recip_options
[i
].string
))
7672 mask
= recip_options
[i
].mask
;
7676 if (i
== ARRAY_SIZE (recip_options
))
7678 error ("unknown option for %<-mrecip=%s%>", q
);
7680 mask
= RECIP_MASK_NONE
;
7685 recip_mask
&= ~mask
;
7691 recip_mask
|= RECIP_MASK_ALL
;
7692 if (!ISA_HAS_FRECIPE
)
7693 recip_mask
= RECIP_MASK_NONE
;
7695 #define INIT_TARGET_FLAG(NAME, INIT) \
7697 if (!(target_flags_explicit & MASK_##NAME)) \
7700 target_flags |= MASK_##NAME; \
7702 target_flags &= ~MASK_##NAME; \
7706 /* Enable conditional moves for int and float by default. */
7707 INIT_TARGET_FLAG (COND_MOVE_INT
, 1)
7708 INIT_TARGET_FLAG (COND_MOVE_FLOAT
, 1)
7710 /* Set mrelax default. */
7711 INIT_TARGET_FLAG (LINKER_RELAXATION
,
7712 HAVE_AS_MRELAX_OPTION
&& HAVE_AS_COND_BRANCH_RELAXATION
)
7714 #undef INIT_TARGET_FLAG
7716 if (la_opt_explicit_relocs
== M_OPT_UNSET
)
7717 la_opt_explicit_relocs
= (HAVE_AS_EXPLICIT_RELOCS
7718 ? (TARGET_LINKER_RELAXATION
7719 ? EXPLICIT_RELOCS_AUTO
7720 : EXPLICIT_RELOCS_ALWAYS
)
7721 : EXPLICIT_RELOCS_NONE
);
7725 /* Implement TARGET_OPTION_OVERRIDE. */
7728 loongarch_option_override (void)
7730 loongarch_option_override_internal (&global_options
, &global_options_set
);
7733 /* Implement TARGET_OPTION_SAVE. */
7735 loongarch_option_save (struct cl_target_option
*,
7736 struct gcc_options
*opts
,
7737 struct gcc_options
*opts_set
)
7739 loongarch_update_gcc_opt_status (&la_target
, opts
, opts_set
);
7742 /* Implement TARGET_OPTION_RESTORE. */
7744 loongarch_option_restore (struct gcc_options
*,
7745 struct gcc_options
*,
7746 struct cl_target_option
*ptr
)
7748 la_target
.cpu_arch
= ptr
->x_la_opt_cpu_arch
;
7749 la_target
.cpu_tune
= ptr
->x_la_opt_cpu_tune
;
7751 la_target
.isa
.fpu
= ptr
->x_la_opt_fpu
;
7752 la_target
.isa
.simd
= ptr
->x_la_opt_simd
;
7753 la_target
.isa
.evolution
= ptr
->x_la_isa_evolution
;
7755 la_target
.cmodel
= ptr
->x_la_opt_cmodel
;
7758 /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
7761 loongarch_conditional_register_usage (void)
7763 if (!TARGET_HARD_FLOAT
)
7764 accessible_reg_set
&= ~(reg_class_contents
[FP_REGS
]
7765 | reg_class_contents
[FCC_REGS
]);
7768 /* Implement EH_USES. */
7771 loongarch_eh_uses (unsigned int regno ATTRIBUTE_UNUSED
)
7776 /* Implement EPILOGUE_USES. */
7779 loongarch_epilogue_uses (unsigned int regno
)
7781 /* Say that the epilogue uses the return address register. Note that
7782 in the case of sibcalls, the values "used by the epilogue" are
7783 considered live at the start of the called function. */
7784 if (regno
== RETURN_ADDR_REGNUM
)
7791 loongarch_load_store_bonding_p (rtx
*operands
, machine_mode mode
, bool load_p
)
7793 rtx reg1
, reg2
, mem1
, mem2
, base1
, base2
;
7794 enum reg_class rc1
, rc2
;
7795 HOST_WIDE_INT offset1
, offset2
;
7812 if (loongarch_address_insns (XEXP (mem1
, 0), mode
, false) == 0
7813 || loongarch_address_insns (XEXP (mem2
, 0), mode
, false) == 0)
7816 loongarch_split_plus (XEXP (mem1
, 0), &base1
, &offset1
);
7817 loongarch_split_plus (XEXP (mem2
, 0), &base2
, &offset2
);
7819 /* Base regs do not match. */
7820 if (!REG_P (base1
) || !rtx_equal_p (base1
, base2
))
7823 /* Either of the loads is clobbering base register. It is legitimate to bond
7824 loads if second load clobbers base register. However, hardware does not
7825 support such bonding. */
7827 && (REGNO (reg1
) == REGNO (base1
) || (REGNO (reg2
) == REGNO (base1
))))
7830 /* Loading in same registers. */
7831 if (load_p
&& REGNO (reg1
) == REGNO (reg2
))
7834 /* The loads/stores are not of same type. */
7835 rc1
= REGNO_REG_CLASS (REGNO (reg1
));
7836 rc2
= REGNO_REG_CLASS (REGNO (reg2
));
7837 if (rc1
!= rc2
&& !reg_class_subset_p (rc1
, rc2
)
7838 && !reg_class_subset_p (rc2
, rc1
))
7841 if (abs (offset1
- offset2
) != GET_MODE_SIZE (mode
))
7847 /* Implement TARGET_TRAMPOLINE_INIT. */
7850 loongarch_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
7852 rtx addr
, end_addr
, mem
;
7855 HOST_WIDE_INT end_addr_offset
, static_chain_offset
, target_function_offset
;
7857 /* Work out the offsets of the pointers from the start of the
7859 end_addr_offset
= TRAMPOLINE_CODE_SIZE
;
7860 static_chain_offset
= end_addr_offset
;
7861 target_function_offset
= static_chain_offset
+ GET_MODE_SIZE (ptr_mode
);
7863 /* Get pointers to the beginning and end of the code block. */
7864 addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
7866 = loongarch_force_binary (Pmode
, PLUS
, addr
, GEN_INT (end_addr_offset
));
7868 #define OP(X) gen_int_mode (X, SImode)
7870 /* Build up the code in TRAMPOLINE. */
7872 /*pcaddi $static_chain,0
7873 ld.[dw] $tmp,$static_chain,target_function_offset
7874 ld.[dw] $static_chain,$static_chain,static_chain_offset
7876 trampoline
[i
++] = OP (0x18000000 | (STATIC_CHAIN_REGNUM
- GP_REG_FIRST
));
7877 trampoline
[i
++] = OP ((ptr_mode
== DImode
? 0x28c00000 : 0x28800000)
7879 | ((STATIC_CHAIN_REGNUM
- GP_REG_FIRST
) << 5)
7880 | ((target_function_offset
& 0xfff) << 10));
7881 trampoline
[i
++] = OP ((ptr_mode
== DImode
? 0x28c00000 : 0x28800000)
7882 | (STATIC_CHAIN_REGNUM
- GP_REG_FIRST
)
7883 | ((STATIC_CHAIN_REGNUM
- GP_REG_FIRST
) << 5)
7884 | ((static_chain_offset
& 0xfff) << 10));
7885 trampoline
[i
++] = OP (0x4c000000 | (19 << 5));
7888 for (j
= 0; j
< i
; j
++)
7890 mem
= adjust_address (m_tramp
, SImode
, j
* GET_MODE_SIZE (SImode
));
7891 loongarch_emit_move (mem
, trampoline
[j
]);
7894 /* Set up the static chain pointer field. */
7895 mem
= adjust_address (m_tramp
, ptr_mode
, static_chain_offset
);
7896 loongarch_emit_move (mem
, chain_value
);
7898 /* Set up the target function field. */
7899 mem
= adjust_address (m_tramp
, ptr_mode
, target_function_offset
);
7900 loongarch_emit_move (mem
, XEXP (DECL_RTL (fndecl
), 0));
7902 /* Flush the code part of the trampoline. */
7903 emit_insn (gen_add3_insn (end_addr
, addr
, GEN_INT (TRAMPOLINE_SIZE
)));
7904 emit_insn (gen_clear_cache (addr
, end_addr
));
7907 /* Generate or test for an insn that supports a constant permutation. */
7909 #define MAX_VECT_LEN 32
7911 struct expand_vec_perm_d
7913 rtx target
, op0
, op1
;
7914 unsigned char perm
[MAX_VECT_LEN
];
7921 /* Construct (set target (vec_select op0 (parallel perm))) and
7922 return true if that's a valid instruction in the active ISA. */
7925 loongarch_expand_vselect (rtx target
, rtx op0
,
7926 const unsigned char *perm
, unsigned nelt
)
7928 rtx rperm
[MAX_VECT_LEN
], x
;
7932 for (i
= 0; i
< nelt
; ++i
)
7933 rperm
[i
] = GEN_INT (perm
[i
]);
7935 x
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec_v (nelt
, rperm
));
7936 x
= gen_rtx_VEC_SELECT (GET_MODE (target
), op0
, x
);
7937 x
= gen_rtx_SET (target
, x
);
7939 insn
= emit_insn (x
);
7940 if (recog_memoized (insn
) < 0)
7948 /* Similar, but generate a vec_concat from op0 and op1 as well. */
7951 loongarch_expand_vselect_vconcat (rtx target
, rtx op0
, rtx op1
,
7952 const unsigned char *perm
, unsigned nelt
)
7954 machine_mode v2mode
;
7957 if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0
)).exists (&v2mode
))
7959 x
= gen_rtx_VEC_CONCAT (v2mode
, op0
, op1
);
7960 return loongarch_expand_vselect (target
, x
, perm
, nelt
);
7964 loongarch_handle_model_attribute (tree
*node
, tree name
, tree arg
, int,
7970 if (DECL_THREAD_LOCAL_P (decl
))
7972 error_at (DECL_SOURCE_LOCATION (decl
),
7973 "%qE attribute cannot be specified for thread-local "
7975 *no_add_attrs
= true;
7978 if (DECL_CONTEXT (decl
)
7979 && TREE_CODE (DECL_CONTEXT (decl
)) == FUNCTION_DECL
7980 && !TREE_STATIC (decl
))
7982 error_at (DECL_SOURCE_LOCATION (decl
),
7983 "%qE attribute cannot be specified for local "
7985 *no_add_attrs
= true;
7988 if (DECL_REGISTER (decl
))
7990 error_at (DECL_SOURCE_LOCATION (decl
),
7991 "%qE attribute cannot be specified for register "
7993 *no_add_attrs
= true;
7996 if (la_opt_explicit_relocs
== EXPLICIT_RELOCS_NONE
)
7998 error_at (DECL_SOURCE_LOCATION (decl
),
7999 "%qE attribute is not compatible with %s", name
,
8000 "-mexplicit-relocs=none");
8001 *no_add_attrs
= true;
8005 arg
= TREE_VALUE (arg
);
8006 if (TREE_CODE (arg
) != STRING_CST
)
8008 error_at (DECL_SOURCE_LOCATION (decl
),
8009 "invalid argument of %qE attribute", name
);
8010 *no_add_attrs
= true;
8014 const char *model
= TREE_STRING_POINTER (arg
);
8015 if (strcmp (model
, "normal") != 0
8016 && strcmp (model
, "extreme") != 0)
8018 error_at (DECL_SOURCE_LOCATION (decl
),
8019 "invalid argument of %qE attribute", name
);
8020 *no_add_attrs
= true;
8024 if (lookup_attribute ("model", DECL_ATTRIBUTES (decl
)))
8026 error_at (DECL_SOURCE_LOCATION (decl
),
8027 "multiple %qE attribute", name
);
8028 *no_add_attrs
= true;
8034 warning (OPT_Wattributes
, "%qE attribute ignored", name
);
8035 *no_add_attrs
= true;
8040 TARGET_GNU_ATTRIBUTES (loongarch_attribute_table
,
8042 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
8043 affects_type_identity, handler, exclude } */
8044 { "model", 1, 1, true, false, false, false,
8045 loongarch_handle_model_attribute
, NULL
}
8049 loongarch_use_anchors_for_symbol_p (const_rtx symbol
)
8051 tree decl
= SYMBOL_REF_DECL (symbol
);
8053 /* The section anchor optimization may break custom address model. */
8054 if (decl
&& lookup_attribute ("model", DECL_ATTRIBUTES (decl
)))
8057 return default_use_anchors_for_symbol_p (symbol
);
8060 /* Implement the TARGET_ASAN_SHADOW_OFFSET hook. */
8062 static unsigned HOST_WIDE_INT
8063 loongarch_asan_shadow_offset (void)
8065 /* We only have libsanitizer support for LOONGARCH64 at present.
8066 This value is taken from the file libsanitizer/asan/asan_mapping.h. */
8067 return TARGET_64BIT
? (HOST_WIDE_INT_1
<< 46) : 0;
8071 loongarch_get_separate_components (void)
8073 HOST_WIDE_INT offset
;
8074 sbitmap components
= sbitmap_alloc (FIRST_PSEUDO_REGISTER
);
8075 bitmap_clear (components
);
8076 offset
= cfun
->machine
->frame
.gp_sp_offset
;
8078 /* The stack should be aligned to 16-bytes boundary, so we can make the use
8079 of ldptr instructions. */
8080 gcc_assert (offset
% UNITS_PER_WORD
== 0);
8082 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
8083 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
8085 /* We can wrap general registers saved at [sp, sp + 32768) using the
8086 ldptr/stptr instructions. For large offsets a pseudo register
8087 might be needed which cannot be created during the shrink
8090 TODO: This may need a revise when we add LA32 as ldptr.w is not
8091 guaranteed available by the manual. */
8093 bitmap_set_bit (components
, regno
);
8095 offset
-= UNITS_PER_WORD
;
8098 offset
= cfun
->machine
->frame
.fp_sp_offset
;
8099 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
8100 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
8102 /* We can only wrap FP registers with imm12 offsets. For large
8103 offsets a pseudo register might be needed which cannot be
8104 created during the shrink wrapping pass. */
8105 if (IMM12_OPERAND (offset
))
8106 bitmap_set_bit (components
, regno
);
8108 offset
-= UNITS_PER_FPREG
;
8111 /* Don't mess with the hard frame pointer. */
8112 if (frame_pointer_needed
)
8113 bitmap_clear_bit (components
, HARD_FRAME_POINTER_REGNUM
);
8115 bitmap_clear_bit (components
, RETURN_ADDR_REGNUM
);
8121 loongarch_components_for_bb (basic_block bb
)
8123 /* Registers are used in a bb if they are in the IN, GEN, or KILL sets. */
8125 bitmap_copy (used
, DF_LIVE_IN (bb
));
8126 bitmap_ior_into (used
, &DF_LIVE_BB_INFO (bb
)->gen
);
8127 bitmap_ior_into (used
, &DF_LIVE_BB_INFO (bb
)->kill
);
8129 sbitmap components
= sbitmap_alloc (FIRST_PSEUDO_REGISTER
);
8130 bitmap_clear (components
);
8132 function_abi_aggregator callee_abis
;
8134 FOR_BB_INSNS (bb
, insn
)
8136 callee_abis
.note_callee_abi (insn_callee_abi (insn
));
8138 HARD_REG_SET extra_caller_saves
=
8139 callee_abis
.caller_save_regs (*crtl
->abi
);
8141 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
8142 if (!fixed_regs
[regno
]
8143 && !crtl
->abi
->clobbers_full_reg_p (regno
)
8144 && (TEST_HARD_REG_BIT (extra_caller_saves
, regno
) ||
8145 bitmap_bit_p (used
, regno
)))
8146 bitmap_set_bit (components
, regno
);
8148 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
8149 if (!fixed_regs
[regno
]
8150 && !crtl
->abi
->clobbers_full_reg_p (regno
)
8151 && (TEST_HARD_REG_BIT (extra_caller_saves
, regno
) ||
8152 bitmap_bit_p (used
, regno
)))
8153 bitmap_set_bit (components
, regno
);
8159 loongarch_disqualify_components (sbitmap
, edge
, sbitmap
, bool)
8165 loongarch_process_components (sbitmap components
, loongarch_save_restore_fn fn
)
8167 HOST_WIDE_INT offset
= cfun
->machine
->frame
.gp_sp_offset
;
8169 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
8170 if (BITSET_P (cfun
->machine
->frame
.mask
, regno
- GP_REG_FIRST
))
8172 if (bitmap_bit_p (components
, regno
))
8173 loongarch_save_restore_reg (word_mode
, regno
, offset
, fn
);
8175 offset
-= UNITS_PER_WORD
;
8178 offset
= cfun
->machine
->frame
.fp_sp_offset
;
8179 machine_mode mode
= TARGET_DOUBLE_FLOAT
? DFmode
: SFmode
;
8181 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
8182 if (BITSET_P (cfun
->machine
->frame
.fmask
, regno
- FP_REG_FIRST
))
8184 if (bitmap_bit_p (components
, regno
))
8185 loongarch_save_restore_reg (mode
, regno
, offset
, fn
);
8187 offset
-= UNITS_PER_FPREG
;
8192 loongarch_emit_prologue_components (sbitmap components
)
8194 loongarch_process_components (components
, loongarch_save_reg
);
8198 loongarch_emit_epilogue_components (sbitmap components
)
8200 loongarch_process_components (components
, loongarch_restore_reg
);
8204 loongarch_set_handled_components (sbitmap components
)
8206 for (unsigned int regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
8207 if (bitmap_bit_p (components
, regno
))
8208 cfun
->machine
->reg_is_wrapped_separately
[regno
] = true;
8210 for (unsigned int regno
= FP_REG_FIRST
; regno
<= FP_REG_LAST
; regno
++)
8211 if (bitmap_bit_p (components
, regno
))
8212 cfun
->machine
->reg_is_wrapped_separately
[regno
] = true;
8215 /* Initialize the GCC target structure. */
8216 #undef TARGET_ASM_ALIGNED_HI_OP
8217 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
8218 #undef TARGET_ASM_ALIGNED_SI_OP
8219 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
8220 #undef TARGET_ASM_ALIGNED_DI_OP
8221 #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
8222 /* Construct (set target (vec_select op0 (parallel selector))) and
8223 return true if that's a valid instruction in the active ISA. */
8226 loongarch_expand_lsx_shuffle (struct expand_vec_perm_d
*d
)
8228 rtx x
, elts
[MAX_VECT_LEN
];
8233 if (!ISA_HAS_LSX
&& !ISA_HAS_LASX
)
8236 for (i
= 0; i
< d
->nelt
; i
++)
8237 elts
[i
] = GEN_INT (d
->perm
[i
]);
8239 v
= gen_rtvec_v (d
->nelt
, elts
);
8240 x
= gen_rtx_PARALLEL (VOIDmode
, v
);
8242 if (!loongarch_const_vector_shuffle_set_p (x
, d
->vmode
))
8245 x
= gen_rtx_VEC_SELECT (d
->vmode
, d
->op0
, x
);
8246 x
= gen_rtx_SET (d
->target
, x
);
8248 insn
= emit_insn (x
);
8249 if (recog_memoized (insn
) < 0)
8257 /* Try to simplify a two vector permutation using 2 intra-lane interleave
8258 insns and cross-lane shuffle for 32-byte vectors. */
8261 loongarch_expand_vec_perm_interleave (struct expand_vec_perm_d
*d
)
8265 rtx (*gen_high
) (rtx
, rtx
, rtx
);
8266 rtx (*gen_low
) (rtx
, rtx
, rtx
);
8267 machine_mode mode
= GET_MODE (d
->target
);
8269 if (d
->one_vector_p
)
8271 if (ISA_HAS_LASX
&& GET_MODE_SIZE (d
->vmode
) == 32)
8277 if (d
->perm
[0] != 0 && d
->perm
[0] != nelt
/ 2)
8279 for (i
= 0; i
< nelt
; i
+= 2)
8280 if (d
->perm
[i
] != d
->perm
[0] + i
/ 2
8281 || d
->perm
[i
+ 1] != d
->perm
[0] + i
/ 2 + nelt
)
8290 gen_high
= gen_lasx_xvilvh_b
;
8291 gen_low
= gen_lasx_xvilvl_b
;
8294 gen_high
= gen_lasx_xvilvh_h
;
8295 gen_low
= gen_lasx_xvilvl_h
;
8298 gen_high
= gen_lasx_xvilvh_w
;
8299 gen_low
= gen_lasx_xvilvl_w
;
8302 gen_high
= gen_lasx_xvilvh_d
;
8303 gen_low
= gen_lasx_xvilvl_d
;
8306 gen_high
= gen_lasx_xvilvh_w_f
;
8307 gen_low
= gen_lasx_xvilvl_w_f
;
8310 gen_high
= gen_lasx_xvilvh_d_f
;
8311 gen_low
= gen_lasx_xvilvl_d_f
;
8317 t1
= gen_reg_rtx (mode
);
8318 t2
= gen_reg_rtx (mode
);
8319 emit_insn (gen_high (t1
, d
->op0
, d
->op1
));
8320 emit_insn (gen_low (t2
, d
->op0
, d
->op1
));
8321 if (mode
== V4DFmode
|| mode
== V8SFmode
)
8323 t3
= gen_reg_rtx (V4DFmode
);
8325 emit_insn (gen_lasx_xvpermi_q_v4df (t3
, gen_lowpart (V4DFmode
, t1
),
8326 gen_lowpart (V4DFmode
, t2
),
8329 emit_insn (gen_lasx_xvpermi_q_v4df (t3
, gen_lowpart (V4DFmode
, t1
),
8330 gen_lowpart (V4DFmode
, t2
),
8335 t3
= gen_reg_rtx (V4DImode
);
8337 emit_insn (gen_lasx_xvpermi_q_v4di (t3
, gen_lowpart (V4DImode
, t1
),
8338 gen_lowpart (V4DImode
, t2
),
8341 emit_insn (gen_lasx_xvpermi_q_v4di (t3
, gen_lowpart (V4DImode
, t1
),
8342 gen_lowpart (V4DImode
, t2
),
8345 emit_move_insn (d
->target
, gen_lowpart (mode
, t3
));
8349 /* Implement extract-even and extract-odd permutations. */
8352 loongarch_expand_vec_perm_even_odd_1 (struct expand_vec_perm_d
*d
, unsigned odd
)
8355 machine_mode mode
= GET_MODE (d
->target
);
8360 t1
= gen_reg_rtx (mode
);
8365 /* Shuffle the lanes around into { 0 4 2 6 } and { 1 5 3 7 }. */
8367 emit_insn (gen_lasx_xvilvh_d_f (t1
, d
->op0
, d
->op1
));
8369 emit_insn (gen_lasx_xvilvl_d_f (t1
, d
->op0
, d
->op1
));
8371 /* Shuffle within the 256-bit lanes to produce the result required.
8372 { 0 2 4 6 } | { 1 3 5 7 }. */
8373 emit_insn (gen_lasx_xvpermi_d_v4df (d
->target
, t1
, GEN_INT (0xd8)));
8378 emit_insn (gen_lasx_xvilvh_d (t1
, d
->op0
, d
->op1
));
8380 emit_insn (gen_lasx_xvilvl_d (t1
, d
->op0
, d
->op1
));
8382 emit_insn (gen_lasx_xvpermi_d_v4di (d
->target
, t1
, GEN_INT (0xd8)));
8386 /* Shuffle the lanes around into:
8387 { 0 2 8 a 4 6 c e } | { 1 3 9 b 5 7 d f }. */
8389 emit_insn (gen_lasx_xvpickod_w_f (t1
, d
->op0
, d
->op1
));
8391 emit_insn (gen_lasx_xvpickev_w_f (t1
, d
->op0
, d
->op1
));
8393 /* Shuffle within the 256-bit lanes to produce the result required.
8394 { 0 2 4 6 8 a c e } | { 1 3 5 7 9 b d f }. */
8395 emit_insn (gen_lasx_xvpermi_d_v8sf (d
->target
, t1
, GEN_INT (0xd8)));
8400 emit_insn (gen_lasx_xvpickod_w (t1
, d
->op0
, d
->op1
));
8402 emit_insn (gen_lasx_xvpickev_w (t1
, d
->op0
, d
->op1
));
8404 emit_insn (gen_lasx_xvpermi_d_v8si (d
->target
, t1
, GEN_INT (0xd8)));
8409 emit_insn (gen_lasx_xvpickod_h (t1
, d
->op0
, d
->op1
));
8411 emit_insn (gen_lasx_xvpickev_h (t1
, d
->op0
, d
->op1
));
8413 emit_insn (gen_lasx_xvpermi_d_v16hi (d
->target
, t1
, GEN_INT (0xd8)));
8418 emit_insn (gen_lasx_xvpickod_b (t1
, d
->op0
, d
->op1
));
8420 emit_insn (gen_lasx_xvpickev_b (t1
, d
->op0
, d
->op1
));
8422 emit_insn (gen_lasx_xvpermi_d_v32qi (d
->target
, t1
, GEN_INT (0xd8)));
8432 /* Pattern match extract-even and extract-odd permutations. */
8435 loongarch_expand_vec_perm_even_odd (struct expand_vec_perm_d
*d
)
8437 unsigned i
, odd
, nelt
= d
->nelt
;
8442 if (odd
!= 0 && odd
!= 1)
8445 for (i
= 1; i
< nelt
; ++i
)
8446 if (d
->perm
[i
] != 2 * i
+ odd
)
8449 return loongarch_expand_vec_perm_even_odd_1 (d
, odd
);
8453 loongarch_expand_vec_interleave (rtx target
, rtx op0
, rtx op1
, bool high_p
)
8455 struct expand_vec_perm_d d
;
8456 unsigned i
, nelt
, base
;
8462 d
.vmode
= GET_MODE (target
);
8463 d
.nelt
= nelt
= GET_MODE_NUNITS (d
.vmode
);
8464 d
.one_vector_p
= false;
8465 d
.testing_p
= false;
8467 base
= high_p
? nelt
/ 2 : 0;
8468 for (i
= 0; i
< nelt
/ 2; ++i
)
8470 d
.perm
[i
* 2] = i
+ base
;
8471 d
.perm
[i
* 2 + 1] = i
+ base
+ nelt
;
8474 ok
= loongarch_expand_vec_perm_interleave (&d
);
8478 /* The loongarch lasx instructions xvmulwev and xvmulwod return the even or odd
8479 parts of the double sized result elements in the corresponding elements of
8480 the target register. That's NOT what the vec_widen_umult_lo/hi patterns are
8481 expected to do. We emulate the widening lo/hi multiplies with the even/odd
8482 versions followed by a vector merge. */
8485 loongarch_expand_vec_widen_hilo (rtx dest
, rtx op1
, rtx op2
,
8486 bool uns_p
, bool high_p
, const char *optab
)
8488 machine_mode wmode
= GET_MODE (dest
);
8489 machine_mode mode
= GET_MODE (op1
);
8492 t1
= gen_reg_rtx (wmode
);
8493 t2
= gen_reg_rtx (wmode
);
8494 t3
= gen_reg_rtx (wmode
);
8498 if (!strcmp (optab
, "add"))
8502 emit_insn (gen_lasx_xvaddwev_w_h (t1
, op1
, op2
));
8503 emit_insn (gen_lasx_xvaddwod_w_h (t2
, op1
, op2
));
8507 emit_insn (gen_lasx_xvaddwev_w_hu (t1
, op1
, op2
));
8508 emit_insn (gen_lasx_xvaddwod_w_hu (t2
, op1
, op2
));
8511 else if (!strcmp (optab
, "mult"))
8515 emit_insn (gen_lasx_xvmulwev_w_h (t1
, op1
, op2
));
8516 emit_insn (gen_lasx_xvmulwod_w_h (t2
, op1
, op2
));
8520 emit_insn (gen_lasx_xvmulwev_w_hu (t1
, op1
, op2
));
8521 emit_insn (gen_lasx_xvmulwod_w_hu (t2
, op1
, op2
));
8524 else if (!strcmp (optab
, "sub"))
8528 emit_insn (gen_lasx_xvsubwev_w_h (t1
, op1
, op2
));
8529 emit_insn (gen_lasx_xvsubwod_w_h (t2
, op1
, op2
));
8533 emit_insn (gen_lasx_xvsubwev_w_hu (t1
, op1
, op2
));
8534 emit_insn (gen_lasx_xvsubwod_w_hu (t2
, op1
, op2
));
8540 if (!strcmp (optab
, "add"))
8544 emit_insn (gen_lasx_xvaddwev_h_b (t1
, op1
, op2
));
8545 emit_insn (gen_lasx_xvaddwod_h_b (t2
, op1
, op2
));
8549 emit_insn (gen_lasx_xvaddwev_h_bu (t1
, op1
, op2
));
8550 emit_insn (gen_lasx_xvaddwod_h_bu (t2
, op1
, op2
));
8553 else if (!strcmp (optab
, "mult"))
8557 emit_insn (gen_lasx_xvmulwev_h_b (t1
, op1
, op2
));
8558 emit_insn (gen_lasx_xvmulwod_h_b (t2
, op1
, op2
));
8562 emit_insn (gen_lasx_xvmulwev_h_bu (t1
, op1
, op2
));
8563 emit_insn (gen_lasx_xvmulwod_h_bu (t2
, op1
, op2
));
8566 else if (!strcmp (optab
, "sub"))
8570 emit_insn (gen_lasx_xvsubwev_h_b (t1
, op1
, op2
));
8571 emit_insn (gen_lasx_xvsubwod_h_b (t2
, op1
, op2
));
8575 emit_insn (gen_lasx_xvsubwev_h_bu (t1
, op1
, op2
));
8576 emit_insn (gen_lasx_xvsubwod_h_bu (t2
, op1
, op2
));
8585 loongarch_expand_vec_interleave (t3
, t1
, t2
, high_p
);
8586 emit_move_insn (dest
, gen_lowpart (wmode
, t3
));
8589 /* Expand a variable vector permutation for LASX. */
8592 loongarch_expand_vec_perm_1 (rtx operands
[])
8594 rtx target
= operands
[0];
8595 rtx op0
= operands
[1];
8596 rtx op1
= operands
[2];
8597 rtx mask
= operands
[3];
8599 bool one_operand_shuffle
= rtx_equal_p (op0
, op1
);
8602 rtx t3
, t4
, t5
, t6
, vt
= NULL
;
8603 rtx vec
[32] = {NULL
};
8604 machine_mode mode
= GET_MODE (op0
);
8605 machine_mode maskmode
= GET_MODE (mask
);
8608 /* Number of elements in the vector. */
8609 w
= GET_MODE_NUNITS (mode
);
8611 rtx round_data
[MAX_VECT_LEN
];
8612 rtx round_reg
, round_data_rtx
;
8614 if (mode
!= E_V32QImode
)
8616 for (int i
= 0; i
< w
; i
+= 1)
8618 round_data
[i
] = GEN_INT (0x1f);
8621 if (mode
== E_V4DFmode
)
8623 round_data_rtx
= gen_rtx_CONST_VECTOR (E_V4DImode
,
8624 gen_rtvec_v (w
, round_data
));
8625 round_reg
= gen_reg_rtx (E_V4DImode
);
8627 else if (mode
== E_V8SFmode
)
8630 round_data_rtx
= gen_rtx_CONST_VECTOR (E_V8SImode
,
8631 gen_rtvec_v (w
, round_data
));
8632 round_reg
= gen_reg_rtx (E_V8SImode
);
8636 round_data_rtx
= gen_rtx_CONST_VECTOR (mode
,
8637 gen_rtvec_v (w
, round_data
));
8638 round_reg
= gen_reg_rtx (mode
);
8641 emit_move_insn (round_reg
, round_data_rtx
);
8645 emit_insn (gen_andv32qi3 (mask
, mask
, round_reg
));
8648 emit_insn (gen_andv16hi3 (mask
, mask
, round_reg
));
8652 emit_insn (gen_andv8si3 (mask
, mask
, round_reg
));
8656 emit_insn (gen_andv4di3 (mask
, mask
, round_reg
));
8664 if (mode
== V4DImode
|| mode
== V4DFmode
)
8666 maskmode
= mode
= V8SImode
;
8668 t1
= gen_reg_rtx (maskmode
);
8670 /* Replicate the low bits of the V4DImode mask into V8SImode:
8672 t1 = { A A B B C C D D }. */
8673 for (i
= 0; i
< w
/ 2; ++i
)
8674 vec
[i
*2 + 1] = vec
[i
*2] = GEN_INT (i
* 2);
8675 vt
= gen_rtx_CONST_VECTOR (maskmode
, gen_rtvec_v (w
, vec
));
8676 vt
= force_reg (maskmode
, vt
);
8677 mask
= gen_lowpart (maskmode
, mask
);
8678 emit_insn (gen_lasx_xvperm_w (t1
, mask
, vt
));
8680 /* Multiply the shuffle indicies by two. */
8681 t1
= expand_simple_binop (maskmode
, PLUS
, t1
, t1
, t1
, 1,
8684 /* Add one to the odd shuffle indicies:
8685 t1 = { A*2, A*2+1, B*2, B*2+1, ... }. */
8686 for (i
= 0; i
< w
/ 2; ++i
)
8688 vec
[i
* 2] = const0_rtx
;
8689 vec
[i
* 2 + 1] = const1_rtx
;
8691 vt
= gen_rtx_CONST_VECTOR (maskmode
, gen_rtvec_v (w
, vec
));
8692 vt
= validize_mem (force_const_mem (maskmode
, vt
));
8693 t1
= expand_simple_binop (maskmode
, PLUS
, t1
, vt
, t1
, 1,
8696 /* Continue as if V8SImode (resp. V32QImode) was used initially. */
8697 operands
[3] = mask
= t1
;
8698 target
= gen_reg_rtx (mode
);
8699 op0
= gen_lowpart (mode
, op0
);
8700 op1
= gen_lowpart (mode
, op1
);
8706 if (one_operand_shuffle
)
8708 emit_insn (gen_lasx_xvperm_w (target
, op0
, mask
));
8709 if (target
!= operands
[0])
8710 emit_move_insn (operands
[0],
8711 gen_lowpart (GET_MODE (operands
[0]), target
));
8715 t1
= gen_reg_rtx (V8SImode
);
8716 t2
= gen_reg_rtx (V8SImode
);
8717 emit_insn (gen_lasx_xvperm_w (t1
, op0
, mask
));
8718 emit_insn (gen_lasx_xvperm_w (t2
, op1
, mask
));
8724 mask
= gen_lowpart (V8SImode
, mask
);
8725 if (one_operand_shuffle
)
8726 emit_insn (gen_lasx_xvperm_w_f (target
, op0
, mask
));
8729 t1
= gen_reg_rtx (V8SFmode
);
8730 t2
= gen_reg_rtx (V8SFmode
);
8731 emit_insn (gen_lasx_xvperm_w_f (t1
, op0
, mask
));
8732 emit_insn (gen_lasx_xvperm_w_f (t2
, op1
, mask
));
8738 if (one_operand_shuffle
)
8740 t1
= gen_reg_rtx (V16HImode
);
8741 t2
= gen_reg_rtx (V16HImode
);
8742 emit_insn (gen_lasx_xvpermi_d_v16hi (t1
, op0
, GEN_INT (0x44)));
8743 emit_insn (gen_lasx_xvpermi_d_v16hi (t2
, op0
, GEN_INT (0xee)));
8744 emit_insn (gen_lasx_xvshuf_h (target
, mask
, t2
, t1
));
8748 t1
= gen_reg_rtx (V16HImode
);
8749 t2
= gen_reg_rtx (V16HImode
);
8750 t3
= gen_reg_rtx (V16HImode
);
8751 t4
= gen_reg_rtx (V16HImode
);
8752 t5
= gen_reg_rtx (V16HImode
);
8753 t6
= gen_reg_rtx (V16HImode
);
8754 emit_insn (gen_lasx_xvpermi_d_v16hi (t3
, op0
, GEN_INT (0x44)));
8755 emit_insn (gen_lasx_xvpermi_d_v16hi (t4
, op0
, GEN_INT (0xee)));
8756 emit_insn (gen_lasx_xvshuf_h (t1
, mask
, t4
, t3
));
8757 emit_insn (gen_lasx_xvpermi_d_v16hi (t5
, op1
, GEN_INT (0x44)));
8758 emit_insn (gen_lasx_xvpermi_d_v16hi (t6
, op1
, GEN_INT (0xee)));
8759 emit_insn (gen_lasx_xvshuf_h (t2
, mask
, t6
, t5
));
8765 if (one_operand_shuffle
)
8767 t1
= gen_reg_rtx (V32QImode
);
8768 t2
= gen_reg_rtx (V32QImode
);
8769 emit_insn (gen_lasx_xvpermi_d_v32qi (t1
, op0
, GEN_INT (0x44)));
8770 emit_insn (gen_lasx_xvpermi_d_v32qi (t2
, op0
, GEN_INT (0xee)));
8771 emit_insn (gen_lasx_xvshuf_b (target
, t2
, t1
, mask
));
8775 t1
= gen_reg_rtx (V32QImode
);
8776 t2
= gen_reg_rtx (V32QImode
);
8777 t3
= gen_reg_rtx (V32QImode
);
8778 t4
= gen_reg_rtx (V32QImode
);
8779 t5
= gen_reg_rtx (V32QImode
);
8780 t6
= gen_reg_rtx (V32QImode
);
8781 emit_insn (gen_lasx_xvpermi_d_v32qi (t3
, op0
, GEN_INT (0x44)));
8782 emit_insn (gen_lasx_xvpermi_d_v32qi (t4
, op0
, GEN_INT (0xee)));
8783 emit_insn (gen_lasx_xvshuf_b (t1
, t4
, t3
, mask
));
8784 emit_insn (gen_lasx_xvpermi_d_v32qi (t5
, op1
, GEN_INT (0x44)));
8785 emit_insn (gen_lasx_xvpermi_d_v32qi (t6
, op1
, GEN_INT (0xee)));
8786 emit_insn (gen_lasx_xvshuf_b (t2
, t6
, t5
, mask
));
8792 gcc_assert (GET_MODE_SIZE (mode
) == 32);
8797 /* Then merge them together. The key is whether any given control
8798 element contained a bit set that indicates the second word. */
8802 vt
= gen_const_vec_duplicate (maskmode
, vt
);
8803 vt
= force_reg (maskmode
, vt
);
8804 mask
= expand_simple_binop (maskmode
, AND
, mask
, vt
,
8805 NULL_RTX
, 0, OPTAB_DIRECT
);
8806 if (GET_MODE (target
) != mode
)
8807 target
= gen_reg_rtx (mode
);
8809 xops
[1] = gen_lowpart (mode
, t2
);
8810 xops
[2] = gen_lowpart (mode
, t1
);
8811 xops
[3] = gen_rtx_EQ (maskmode
, mask
, vt
);
8815 loongarch_expand_vec_cond_expr (mode
, maskmode
, xops
);
8816 if (target
!= operands
[0])
8817 emit_move_insn (operands
[0],
8818 gen_lowpart (GET_MODE (operands
[0]), target
));
8822 loongarch_expand_vec_perm (rtx target
, rtx op0
, rtx op1
, rtx sel
)
8824 machine_mode vmode
= GET_MODE (target
);
8825 machine_mode vimode
= GET_MODE (sel
);
8826 auto nelt
= GET_MODE_NUNITS (vmode
);
8827 auto round_reg
= gen_reg_rtx (vimode
);
8828 rtx round_data
[MAX_VECT_LEN
];
8830 for (int i
= 0; i
< nelt
; i
+= 1)
8832 round_data
[i
] = GEN_INT (0x1f);
8835 rtx round_data_rtx
= gen_rtx_CONST_VECTOR (vimode
, gen_rtvec_v (nelt
, round_data
));
8836 emit_move_insn (round_reg
, round_data_rtx
);
8838 if (vmode
!= vimode
)
8840 target
= lowpart_subreg (vimode
, target
, vmode
);
8841 op0
= lowpart_subreg (vimode
, op0
, vmode
);
8842 op1
= lowpart_subreg (vimode
, op1
, vmode
);
8848 emit_insn (gen_andv16qi3 (sel
, sel
, round_reg
));
8849 emit_insn (gen_lsx_vshuf_b (target
, op1
, op0
, sel
));
8853 emit_insn (gen_andv2di3 (sel
, sel
, round_reg
));
8854 emit_insn (gen_lsx_vshuf_d (target
, sel
, op1
, op0
));
8858 emit_insn (gen_andv4si3 (sel
, sel
, round_reg
));
8859 emit_insn (gen_lsx_vshuf_w (target
, sel
, op1
, op0
));
8862 emit_insn (gen_andv8hi3 (sel
, sel
, round_reg
));
8863 emit_insn (gen_lsx_vshuf_h (target
, sel
, op1
, op0
));
8870 /* Following are the assist function for const vector permutation support. */
8872 loongarch_is_quad_duplicate (struct expand_vec_perm_d
*d
)
8874 if (d
->perm
[0] >= d
->nelt
/ 2)
8878 unsigned char lhs
= d
->perm
[0];
8879 unsigned char rhs
= d
->perm
[d
->nelt
/ 2];
8881 if ((rhs
- lhs
) != d
->nelt
/ 2)
8884 for (int i
= 1; i
< d
->nelt
; i
+= 1)
8886 if ((i
< d
->nelt
/ 2) && (d
->perm
[i
] != lhs
))
8891 if ((i
> d
->nelt
/ 2) && (d
->perm
[i
] != rhs
))
8902 loongarch_is_odd_extraction (struct expand_vec_perm_d
*d
)
8905 unsigned char buf
= 1;
8907 for (int i
= 0; i
< d
->nelt
; i
+= 1)
8909 if (buf
!= d
->perm
[i
])
8921 loongarch_is_even_extraction (struct expand_vec_perm_d
*d
)
8924 unsigned char buf
= 0;
8926 for (int i
= 0; i
< d
->nelt
; i
+= 1)
8928 if (buf
!= d
->perm
[i
])
8940 loongarch_is_extraction_permutation (struct expand_vec_perm_d
*d
)
8943 unsigned char buf
= d
->perm
[0];
8945 if (buf
!= 0 || buf
!= d
->nelt
)
8948 for (int i
= 0; i
< d
->nelt
; i
+= 1)
8950 if (buf
!= d
->perm
[i
])
8962 loongarch_is_lasx_lowpart_interleave (struct expand_vec_perm_d
*d
)
8965 unsigned char buf
= 0;
8967 for (int i
= 0;i
< d
->nelt
; i
+= 2)
8969 if (buf
!= d
->perm
[i
])
8980 for (int i
= 1; i
< d
->nelt
; i
+= 2)
8982 if (buf
!= d
->perm
[i
])
8995 loongarch_is_lasx_lowpart_interleave_2 (struct expand_vec_perm_d
*d
)
8997 if (d
->vmode
!= E_V32QImode
)
9000 unsigned char buf
= 0;
9002 #define COMPARE_SELECTOR(INIT, BEGIN, END) \
9004 for (int i = BEGIN; i < END && result; i += 1) \
9006 if (buf != d->perm[i]) \
9014 COMPARE_SELECTOR (0, 0, 8);
9015 COMPARE_SELECTOR (32, 8, 16);
9016 COMPARE_SELECTOR (8, 16, 24);
9017 COMPARE_SELECTOR (40, 24, 32);
9019 #undef COMPARE_SELECTOR
9024 loongarch_is_lasx_highpart_interleave (expand_vec_perm_d
*d
)
9027 unsigned char buf
= d
->nelt
/ 2;
9029 for (int i
= 0; i
< d
->nelt
; i
+= 2)
9031 if (buf
!= d
->perm
[i
])
9041 buf
= d
->nelt
+ d
->nelt
/ 2;
9042 for (int i
= 1; i
< d
->nelt
;i
+= 2)
9044 if (buf
!= d
->perm
[i
])
9057 loongarch_is_lasx_highpart_interleave_2 (struct expand_vec_perm_d
*d
)
9059 if (d
->vmode
!= E_V32QImode
)
9063 unsigned char buf
= 0;
9065 #define COMPARE_SELECTOR(INIT, BEGIN, END) \
9067 for (int i = BEGIN; i < END && result; i += 1) \
9069 if (buf != d->perm[i]) \
9077 COMPARE_SELECTOR (16, 0, 8);
9078 COMPARE_SELECTOR (48, 8, 16);
9079 COMPARE_SELECTOR (24, 16, 24);
9080 COMPARE_SELECTOR (56, 24, 32);
9082 #undef COMPARE_SELECTOR
9087 loongarch_is_elem_duplicate (struct expand_vec_perm_d
*d
)
9090 unsigned char buf
= d
->perm
[0];
9092 for (int i
= 0; i
< d
->nelt
; i
+= 1)
9094 if (buf
!= d
->perm
[i
])
9104 /* In LASX, some permutation insn does not have the behavior that gcc expects
9105 when compiler wants to emit a vector permutation.
9107 1. What GCC provides via vectorize_vec_perm_const ()'s paramater:
9108 When GCC wants to performs a vector permutation, it provides two op
9109 reigster, one target register, and a selector.
9110 In const vector permutation case, GCC provides selector as a char array
9111 that contains original value; in variable vector permuatation
9112 (performs via vec_perm<mode> insn template), it provides a vector register.
9113 We assume that nelt is the elements numbers inside single vector in current
9116 2. What GCC expects to perform:
9117 Two op registers (op0, op1) will "combine" into a 512bit temp vector storage
9118 that has 2*nelt elements inside it; the low 256bit is op0, and high 256bit
9119 is op1, then the elements are indexed as below:
9120 0 ~ nelt - 1 nelt ~ 2 * nelt - 1
9121 |-------------------------|-------------------------|
9122 Low 256bit (op0) High 256bit (op1)
9123 For example, the second element in op1 (V8SImode) will be indexed with 9.
9124 Selector is a vector that has the same mode and number of elements with
9125 op0,op1 and target, it's look like this:
9127 |-------------------------|
9129 It describes which element from 512bit temp vector storage will fit into
9130 target's every element slot.
9131 GCC expects that every element in selector can be ANY indices of 512bit
9132 vector storage (Selector can pick literally any element from op0 and op1, and
9133 then fits into any place of target register). This is also what LSX 128bit
9134 vshuf.* instruction do similarly, so we can handle 128bit vector permutation
9135 by single instruction easily.
9137 3. What LASX permutation instruction does:
9138 In short, it just execute two independent 128bit vector permuatation, and
9139 it's the reason that we need to do the jobs below. We will explain it.
9140 op0, op1, target, and selector will be separate into high 128bit and low
9141 128bit, and do permutation as the description below:
9143 a) op0's low 128bit and op1's low 128bit "combines" into a 256bit temp
9144 vector storage (TVS1), elements are indexed as below:
9145 0 ~ nelt / 2 - 1 nelt / 2 ~ nelt - 1
9146 |---------------------|---------------------| TVS1
9147 op0's low 128bit op1's low 128bit
9148 op0's high 128bit and op1's high 128bit are "combined" into TVS2 in the
9150 0 ~ nelt / 2 - 1 nelt / 2 ~ nelt - 1
9151 |---------------------|---------------------| TVS2
9152 op0's high 128bit op1's high 128bit
9153 b) Selector's low 128bit describes which elements from TVS1 will fit into
9154 target vector's low 128bit. No TVS2 elements are allowed.
9155 c) Selector's high 128bit describes which elements from TVS2 will fit into
9156 target vector's high 128bit. No TVS1 elements are allowed.
9158 As we can see, if we want to handle vector permutation correctly, we can
9159 achieve it in three ways:
9160 a) Modify selector's elements, to make sure that every elements can inform
9161 correct value that will put into target vector.
9162 b) Generate extra instruction before/after permutation instruction, for
9163 adjusting op vector or target vector, to make sure target vector's value is
9165 c) Use other instructions to process op and put correct result into target.
9168 /* Implementation of constant vector permuatation. This function identifies
9169 recognized pattern of permuation selector argument, and use one or more
9170 instruction (s) to finish the permutation job correctly. For unsupported
9171 patterns, it will return false. */
9174 loongarch_expand_vec_perm_const (struct expand_vec_perm_d
*d
)
9179 rtx target
, op0
, op1
, sel
, tmp
;
9180 rtx rperm
[MAX_VECT_LEN
];
9181 unsigned int remapped
[MAX_VECT_LEN
];
9182 unsigned char perm2
[MAX_VECT_LEN
];
9184 if (GET_MODE_SIZE (d
->vmode
) == 16)
9185 return loongarch_expand_lsx_shuffle (d
);
9188 if (d
->one_vector_p
)
9190 /* Try interleave with alternating operands. */
9191 memcpy (perm2
, d
->perm
, sizeof (perm2
));
9192 for (i
= 1; i
< d
->nelt
; i
+= 2)
9193 perm2
[i
] += d
->nelt
;
9194 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op0
, d
->op1
,
9200 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op0
, d
->op1
,
9204 /* Try again with swapped operands. */
9205 for (i
= 0; i
< d
->nelt
; ++i
)
9206 perm2
[i
] = (d
->perm
[i
] + d
->nelt
) & (2 * d
->nelt
- 1);
9207 if (loongarch_expand_vselect_vconcat (d
->target
, d
->op1
, d
->op0
,
9212 if (loongarch_expand_lsx_shuffle (d
))
9215 if (loongarch_is_odd_extraction (d
)
9216 || loongarch_is_even_extraction (d
))
9218 if (loongarch_expand_vec_perm_even_odd (d
))
9222 if (loongarch_is_lasx_lowpart_interleave (d
)
9223 || loongarch_is_lasx_lowpart_interleave_2 (d
)
9224 || loongarch_is_lasx_highpart_interleave (d
)
9225 || loongarch_is_lasx_highpart_interleave_2 (d
))
9227 if (loongarch_expand_vec_perm_interleave (d
))
9231 if (loongarch_is_quad_duplicate (d
))
9235 /* Selector example: E_V8SImode, { 0, 0, 0, 0, 4, 4, 4, 4 }. */
9236 for (i
= 0; i
< d
->nelt
; i
+= 1)
9238 rperm
[i
] = GEN_INT (d
->perm
[0]);
9240 /* Selector after: { 0, 0, 0, 0, 0, 0, 0, 0 }. */
9242 goto expand_perm_const_end
;
9245 if (loongarch_is_extraction_permutation (d
))
9249 /* Selector sample: E_V8SImode, { 0, 1, 2, 3, 4, 5, 6, 7 }. */
9250 if (d
->perm
[0] == 0)
9252 for (i
= 0; i
< d
->nelt
/ 2; i
+= 1)
9255 remapped
[i
+ d
->nelt
/ 2] = i
;
9260 /* { 8, 9, 10, 11, 12, 13, 14, 15 }. */
9261 for (i
= 0; i
< d
->nelt
/ 2; i
+= 1)
9263 idx
= i
+ d
->nelt
/ 2;
9265 remapped
[i
+ d
->nelt
/ 2] = idx
;
9268 /* Selector after: { 0, 1, 2, 3, 0, 1, 2, 3 }
9269 { 8, 9, 10, 11, 8, 9, 10, 11 } */
9271 /* Convert remapped selector array to RTL array. */
9272 for (i
= 0; i
< d
->nelt
; i
+= 1)
9274 rperm
[i
] = GEN_INT (remapped
[i
]);
9278 goto expand_perm_const_end
;
9281 if (loongarch_is_elem_duplicate (d
))
9285 /* Brocast single element (from op0 or op1) to all slot of target
9287 Selector sample:E_V8SImode, { 2, 2, 2, 2, 2, 2, 2, 2 } */
9288 rtx conv_op1
= simplify_gen_subreg (E_V4DImode
, d
->op1
, d
->vmode
, 0);
9289 rtx conv_op0
= simplify_gen_subreg (E_V4DImode
, d
->op0
, d
->vmode
, 0);
9290 rtx temp_reg
= gen_reg_rtx (d
->vmode
);
9291 rtx conv_temp
= simplify_gen_subreg (E_V4DImode
, temp_reg
,
9293 emit_move_insn (temp_reg
, d
->op0
);
9296 /* We will use xvrepl128vei.* insn to achieve the result, but we need
9297 to make the high/low 128bit has the same contents that contain the
9298 value that we need to broardcast, because xvrepl128vei does the
9299 broardcast job from every 128bit of source register to
9300 corresponded part of target register! (A deep sigh.) */
9301 if (idx
< d
->nelt
/ 2)
9303 emit_insn (gen_lasx_xvpermi_q_v4di (conv_temp
, conv_temp
,
9304 conv_op0
, GEN_INT (0x0)));
9306 else if (idx
>= d
->nelt
/ 2 && idx
< d
->nelt
)
9308 emit_insn (gen_lasx_xvpermi_q_v4di (conv_temp
, conv_temp
,
9309 conv_op0
, GEN_INT (0x11)));
9312 else if (idx
>= d
->nelt
&& idx
< (d
->nelt
+ d
->nelt
/ 2))
9314 emit_insn (gen_lasx_xvpermi_q_v4di (conv_temp
, conv_temp
,
9315 conv_op1
, GEN_INT (0x0)));
9317 else if (idx
>= (d
->nelt
+ d
->nelt
/ 2) && idx
< d
->nelt
* 2)
9319 emit_insn (gen_lasx_xvpermi_q_v4di (conv_temp
, conv_temp
,
9320 conv_op1
, GEN_INT (0x11)));
9324 /* Then we can finally generate this insn. */
9328 emit_insn (gen_lasx_xvrepl128vei_d (d
->target
, temp_reg
,
9332 emit_insn (gen_lasx_xvrepl128vei_d_f (d
->target
, temp_reg
,
9336 emit_insn (gen_lasx_xvrepl128vei_w (d
->target
, temp_reg
,
9340 emit_insn (gen_lasx_xvrepl128vei_w_f (d
->target
, temp_reg
,
9344 emit_insn (gen_lasx_xvrepl128vei_h (d
->target
, temp_reg
,
9348 emit_insn (gen_lasx_xvrepl128vei_b (d
->target
, temp_reg
,
9359 expand_perm_const_end
:
9362 /* Copy selector vector from memory to vector register for later insn
9364 If vector's element in floating point value, we cannot fit
9365 selector argument into insn gen function directly, because of the
9366 insn template definition. As a solution, generate a integral mode
9367 subreg of target, then copy selector vector (that is in integral
9368 mode) to this subreg. */
9372 sel
= gen_rtx_CONST_VECTOR (E_V4DImode
, gen_rtvec_v (d
->nelt
,
9374 tmp
= simplify_gen_subreg (E_V4DImode
, d
->target
, d
->vmode
, 0);
9375 emit_move_insn (tmp
, sel
);
9378 sel
= gen_rtx_CONST_VECTOR (E_V8SImode
, gen_rtvec_v (d
->nelt
,
9380 tmp
= simplify_gen_subreg (E_V8SImode
, d
->target
, d
->vmode
, 0);
9381 emit_move_insn (tmp
, sel
);
9384 sel
= gen_rtx_CONST_VECTOR (d
->vmode
, gen_rtvec_v (d
->nelt
,
9386 emit_move_insn (d
->target
, sel
);
9392 op1
= d
->one_vector_p
? d
->op0
: d
->op1
;
9394 /* We FINALLY can generate xvshuf.* insn. */
9398 emit_insn (gen_lasx_xvshuf_d_f (target
, target
, op1
, op0
));
9401 emit_insn (gen_lasx_xvshuf_d (target
, target
, op1
, op0
));
9404 emit_insn (gen_lasx_xvshuf_w_f (target
, target
, op1
, op0
));
9407 emit_insn (gen_lasx_xvshuf_w (target
, target
, op1
, op0
));
9410 emit_insn (gen_lasx_xvshuf_h (target
, target
, op1
, op0
));
9413 emit_insn (gen_lasx_xvshuf_b (target
, op1
, op0
, target
));
9427 /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */
9430 loongarch_vectorize_vec_perm_const (machine_mode vmode
, machine_mode op_mode
,
9431 rtx target
, rtx op0
, rtx op1
,
9432 const vec_perm_indices
&sel
)
9434 if (vmode
!= op_mode
)
9437 struct expand_vec_perm_d d
;
9439 unsigned char orig_perm
[MAX_VECT_LEN
];
9445 rtx nop0
= force_reg (vmode
, op0
);
9451 op1
= force_reg (vmode
, op1
);
9456 gcc_assert (VECTOR_MODE_P (vmode
));
9457 d
.nelt
= nelt
= GET_MODE_NUNITS (vmode
);
9458 d
.testing_p
= !target
;
9460 /* This is overly conservative, but ensures we don't get an
9461 uninitialized warning on ORIG_PERM. */
9462 memset (orig_perm
, 0, MAX_VECT_LEN
);
9463 for (i
= which
= 0; i
< nelt
; ++i
)
9465 int ei
= sel
[i
] & (2 * nelt
- 1);
9466 which
|= (ei
< nelt
? 1 : 2);
9469 memcpy (d
.perm
, orig_perm
, MAX_VECT_LEN
);
9477 d
.one_vector_p
= false;
9478 if (d
.testing_p
|| !rtx_equal_p (d
.op0
, d
.op1
))
9483 for (i
= 0; i
< nelt
; ++i
)
9484 d
.perm
[i
] &= nelt
- 1;
9486 d
.one_vector_p
= true;
9491 d
.one_vector_p
= true;
9495 // Do rounding for selector to avoid vshuf undefined behavior.
9496 for (i
= 0; i
< d
.nelt
; i
+= 1)
9498 d
.perm
[i
] %= (d
.nelt
* 2);
9503 d
.target
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 1);
9504 d
.op1
= d
.op0
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 2);
9505 if (!d
.one_vector_p
)
9506 d
.op1
= gen_raw_REG (d
.vmode
, LAST_VIRTUAL_REGISTER
+ 3);
9509 ok
= loongarch_expand_vec_perm_const (&d
);
9514 ok
= loongarch_expand_vec_perm_const (&d
);
9516 /* If we were given a two-vector permutation which just happened to
9517 have both input vectors equal, we folded this into a one-vector
9518 permutation. There are several loongson patterns that are matched
9519 via direct vec_select+vec_concat expansion, but we do not have
9520 support in loongarch_expand_vec_perm_const to guess the adjustment
9521 that should be made for a single operand. Just try again with
9522 the original permutation. */
9523 if (!ok
&& which
== 3)
9527 d
.one_vector_p
= false;
9528 memcpy (d
.perm
, orig_perm
, MAX_VECT_LEN
);
9529 ok
= loongarch_expand_vec_perm_const (&d
);
9536 loongarch_cpu_sched_reassociation_width (struct loongarch_target
*target
,
9537 unsigned int opc
, machine_mode mode
)
9539 /* unreferenced argument */
9542 switch (target
->cpu_tune
)
9544 case CPU_LOONGARCH64
:
9548 if (LSX_SUPPORTED_MODE_P (mode
) || LASX_SUPPORTED_MODE_P (mode
))
9550 /* Integer vector instructions execute in FP unit.
9551 The width of integer/float-point vector instructions is 3. */
9556 else if (INTEGRAL_MODE_P (mode
))
9558 else if (FLOAT_MODE_P (mode
))
9560 if (opc
== PLUS_EXPR
)
9575 /* Implement TARGET_SCHED_REASSOCIATION_WIDTH. */
9578 loongarch_sched_reassociation_width (unsigned int opc
, machine_mode mode
)
9580 return loongarch_cpu_sched_reassociation_width (&la_target
, opc
, mode
);
9583 /* Implement extract a scalar element from vecotr register */
9586 loongarch_expand_vector_extract (rtx target
, rtx vec
, int elt
)
9588 machine_mode mode
= GET_MODE (vec
);
9589 machine_mode inner_mode
= GET_MODE_INNER (mode
);
9603 tmp
= gen_reg_rtx (V32QImode
);
9604 emit_insn (gen_lasx_xvpermi_d_v32qi (tmp
, vec
, GEN_INT (0xe)));
9605 loongarch_expand_vector_extract (target
,
9606 gen_lowpart (V16QImode
, tmp
),
9610 loongarch_expand_vector_extract (target
,
9611 gen_lowpart (V16QImode
, vec
),
9622 tmp
= gen_reg_rtx (V16HImode
);
9623 emit_insn (gen_lasx_xvpermi_d_v16hi (tmp
, vec
, GEN_INT (0xe)));
9624 loongarch_expand_vector_extract (target
,
9625 gen_lowpart (V8HImode
, tmp
),
9629 loongarch_expand_vector_extract (target
,
9630 gen_lowpart (V8HImode
, vec
),
9640 tmp
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (1, GEN_INT (elt
)));
9641 tmp
= gen_rtx_VEC_SELECT (inner_mode
, vec
, tmp
);
9643 /* Let the rtl optimizers know about the zero extension performed. */
9644 if (inner_mode
== QImode
|| inner_mode
== HImode
)
9646 tmp
= gen_rtx_ZERO_EXTEND (SImode
, tmp
);
9647 target
= gen_lowpart (SImode
, target
);
9649 if (inner_mode
== SImode
|| inner_mode
== DImode
)
9651 tmp
= gen_rtx_SIGN_EXTEND (inner_mode
, tmp
);
9654 emit_insn (gen_rtx_SET (target
, tmp
));
9657 /* Generate code to copy vector bits i / 2 ... i - 1 from vector SRC
9658 to bits 0 ... i / 2 - 1 of vector DEST, which has the same mode.
9659 The upper bits of DEST are undefined, though they shouldn't cause
9660 exceptions (some bits from src or all zeros are ok). */
9663 emit_reduc_half (rtx dest
, rtx src
, int i
)
9666 switch (GET_MODE (src
))
9669 tem
= gen_lsx_vbsrl_w_f (dest
, src
, GEN_INT (i
== 128 ? 8 : 4));
9672 tem
= gen_lsx_vbsrl_d_f (dest
, src
, GEN_INT (8));
9676 tem
= gen_lasx_xvpermi_d_v8sf (dest
, src
, GEN_INT (0xe));
9678 tem
= gen_lasx_xvshuf4i_w_f (dest
, src
,
9679 GEN_INT (i
== 128 ? 2 + (3 << 2) : 1));
9683 tem
= gen_lasx_xvpermi_d_v4df (dest
, src
, GEN_INT (0xe));
9685 tem
= gen_lasx_xvpermi_d_v4df (dest
, src
, const1_rtx
);
9691 d
= gen_reg_rtx (V4DImode
);
9693 tem
= gen_lasx_xvpermi_d_v4di (d
, gen_lowpart (V4DImode
, src
),
9696 tem
= gen_lasx_xvbsrl_d (d
, gen_lowpart (V4DImode
, src
),
9703 d
= gen_reg_rtx (V2DImode
);
9704 tem
= gen_lsx_vbsrl_d (d
, gen_lowpart (V2DImode
, src
), GEN_INT (i
/16));
9711 emit_move_insn (dest
, gen_lowpart (GET_MODE (dest
), d
));
9714 /* Expand a vector reduction. FN is the binary pattern to reduce;
9715 DEST is the destination; IN is the input vector. */
9718 loongarch_expand_vector_reduc (rtx (*fn
) (rtx
, rtx
, rtx
), rtx dest
, rtx in
)
9720 rtx half
, dst
, vec
= in
;
9721 machine_mode mode
= GET_MODE (in
);
9724 for (i
= GET_MODE_BITSIZE (mode
);
9725 i
> GET_MODE_UNIT_BITSIZE (mode
);
9728 half
= gen_reg_rtx (mode
);
9729 emit_reduc_half (half
, vec
, i
);
9730 if (i
== GET_MODE_UNIT_BITSIZE (mode
) * 2)
9733 dst
= gen_reg_rtx (mode
);
9734 emit_insn (fn (dst
, half
, vec
));
9739 /* Expand an integral vector unpack operation. */
9742 loongarch_expand_vec_unpack (rtx operands
[2], bool unsigned_p
, bool high_p
)
9744 machine_mode imode
= GET_MODE (operands
[1]);
9745 rtx (*unpack
) (rtx
, rtx
, rtx
);
9746 rtx (*extend
) (rtx
, rtx
);
9747 rtx (*cmpFunc
) (rtx
, rtx
, rtx
);
9748 rtx (*swap_hi_lo
) (rtx
, rtx
, rtx
, rtx
);
9751 if (ISA_HAS_LASX
&& GET_MODE_SIZE (imode
) == 32)
9757 extend
= gen_lasx_vext2xv_du_wu
;
9759 extend
= gen_lasx_vext2xv_d_w
;
9760 swap_hi_lo
= gen_lasx_xvpermi_q_v8si
;
9765 extend
= gen_lasx_vext2xv_wu_hu
;
9767 extend
= gen_lasx_vext2xv_w_h
;
9768 swap_hi_lo
= gen_lasx_xvpermi_q_v16hi
;
9773 extend
= gen_lasx_vext2xv_hu_bu
;
9775 extend
= gen_lasx_vext2xv_h_b
;
9776 swap_hi_lo
= gen_lasx_xvpermi_q_v32qi
;
9786 tmp
= gen_reg_rtx (imode
);
9787 emit_insn (swap_hi_lo (tmp
, tmp
, operands
[1], const1_rtx
));
9788 emit_insn (extend (operands
[0], tmp
));
9792 emit_insn (extend (operands
[0], operands
[1]));
9796 else if (ISA_HAS_LSX
)
9802 unpack
= gen_lsx_vilvh_w
;
9804 unpack
= gen_lsx_vilvl_w
;
9806 cmpFunc
= gen_lsx_vslt_w
;
9811 unpack
= gen_lsx_vilvh_h
;
9813 unpack
= gen_lsx_vilvl_h
;
9815 cmpFunc
= gen_lsx_vslt_h
;
9820 unpack
= gen_lsx_vilvh_b
;
9822 unpack
= gen_lsx_vilvl_b
;
9824 cmpFunc
= gen_lsx_vslt_b
;
9834 /* Extract sign extention for each element comparing each element
9835 with immediate zero. */
9836 tmp
= gen_reg_rtx (imode
);
9837 emit_insn (cmpFunc (tmp
, operands
[1], CONST0_RTX (imode
)));
9840 tmp
= force_reg (imode
, CONST0_RTX (imode
));
9842 dest
= gen_reg_rtx (imode
);
9844 emit_insn (unpack (dest
, operands
[1], tmp
));
9845 emit_move_insn (operands
[0], gen_lowpart (GET_MODE (operands
[0]), dest
));
9851 /* Construct and return PARALLEL RTX with CONST_INTs for HIGH (high_p == TRUE)
9852 or LOW (high_p == FALSE) half of a vector for mode MODE. */
9855 loongarch_lsx_vec_parallel_const_half (machine_mode mode
, bool high_p
)
9857 int nunits
= GET_MODE_NUNITS (mode
);
9858 rtvec v
= rtvec_alloc (nunits
/ 2);
9862 base
= high_p
? nunits
/ 2 : 0;
9864 for (i
= 0; i
< nunits
/ 2; i
++)
9865 RTVEC_ELT (v
, i
) = GEN_INT (base
+ i
);
9867 return gen_rtx_PARALLEL (VOIDmode
, v
);
9870 /* A subroutine of loongarch_expand_vec_init, match constant vector
9874 loongarch_constant_elt_p (rtx x
)
9876 return CONST_INT_P (x
) || GET_CODE (x
) == CONST_DOUBLE
;
9880 loongarch_gen_const_int_vector_shuffle (machine_mode mode
, int val
)
9882 int nunits
= GET_MODE_NUNITS (mode
);
9883 int nsets
= nunits
/ 4;
9884 rtx elts
[MAX_VECT_LEN
];
9888 /* Generate a const_int vector replicating the same 4-element set
9889 from an immediate. */
9890 for (j
= 0; j
< nsets
; j
++, set
= 4 * j
)
9891 for (i
= 0; i
< 4; i
++)
9892 elts
[set
+ i
] = GEN_INT (set
+ ((val
>> (2 * i
)) & 0x3));
9894 return gen_rtx_PARALLEL (VOIDmode
, gen_rtvec_v (nunits
, elts
));
9898 /* Expand a vector initialization. */
9901 loongarch_expand_vector_group_init (rtx target
, rtx vals
)
9903 machine_mode vmode
= GET_MODE (target
);
9904 machine_mode half_mode
= VOIDmode
;
9905 rtx low
= XVECEXP (vals
, 0, 0);
9906 rtx high
= XVECEXP (vals
, 0, 1);
9911 half_mode
= V16QImode
;
9914 half_mode
= V8HImode
;
9917 half_mode
= V4SImode
;
9920 half_mode
= V2DImode
;
9923 half_mode
= V4SFmode
;
9926 half_mode
= V2DFmode
;
9932 if (!register_operand (low
, half_mode
))
9933 low
= force_reg (half_mode
, low
);
9934 if (!register_operand (high
, half_mode
))
9935 high
= force_reg (half_mode
, high
);
9936 emit_insn (gen_rtx_SET (target
,
9937 gen_rtx_VEC_CONCAT (vmode
, low
, high
)));
9940 /* Expand initialization of a vector which has all same elements. */
9943 loongarch_expand_vector_init_same (rtx target
, rtx vals
, unsigned nvar
)
9945 machine_mode vmode
= GET_MODE (target
);
9946 machine_mode imode
= GET_MODE_INNER (vmode
);
9947 rtx same
= XVECEXP (vals
, 0, 0);
9950 if (CONST_INT_P (same
) && nvar
== 0
9951 && loongarch_signed_immediate_p (INTVAL (same
), 10, 0))
9963 temp
= gen_rtx_CONST_VECTOR (vmode
, XVEC (vals
, 0));
9964 emit_move_insn (target
, temp
);
9971 if (imode
== GET_MODE (same
))
9973 else if (GET_MODE_SIZE (imode
) >= UNITS_PER_WORD
)
9975 if (GET_CODE (same
) == MEM
)
9977 rtx reg_tmp
= gen_reg_rtx (GET_MODE (same
));
9978 loongarch_emit_move (reg_tmp
, same
);
9979 temp
= simplify_gen_subreg (imode
, reg_tmp
, GET_MODE (reg_tmp
), 0);
9982 temp
= simplify_gen_subreg (imode
, same
, GET_MODE (same
), 0);
9986 if (GET_CODE (same
) == MEM
)
9988 rtx reg_tmp
= gen_reg_rtx (GET_MODE (same
));
9989 loongarch_emit_move (reg_tmp
, same
);
9990 temp
= lowpart_subreg (imode
, reg_tmp
, GET_MODE (reg_tmp
));
9993 temp
= lowpart_subreg (imode
, same
, GET_MODE (same
));
9996 temp
= force_reg (imode
, temp
);
10008 loongarch_emit_move (target
, gen_rtx_VEC_DUPLICATE (vmode
, temp
));
10012 emit_insn (gen_lasx_xvreplve0_w_f_scalar (target
, temp
));
10016 emit_insn (gen_lasx_xvreplve0_d_f_scalar (target
, temp
));
10020 emit_insn (gen_lsx_vreplvei_w_f_scalar (target
, temp
));
10024 emit_insn (gen_lsx_vreplvei_d_f_scalar (target
, temp
));
10028 gcc_unreachable ();
10032 /* Expand a vector initialization. */
10035 loongarch_expand_vector_init (rtx target
, rtx vals
)
10037 machine_mode vmode
= GET_MODE (target
);
10038 machine_mode imode
= GET_MODE_INNER (vmode
);
10039 unsigned i
, nelt
= GET_MODE_NUNITS (vmode
);
10040 /* VALS is divided into high and low half-part. */
10041 /* Number of non constant elements in corresponding parts of VALS. */
10042 unsigned nvar
= 0, hi_nvar
= 0, lo_nvar
= 0;
10043 /* all_same : true if all elements of VALS are the same.
10044 hi_same : true if all elements of the high half-part are the same.
10045 lo_same : true if all elements of the low half-part are the same.
10046 half_same : true if the high half-part is the same as the low one. */
10047 bool all_same
= false, hi_same
= true, lo_same
= true, half_same
= true;
10048 rtx val
[32], val_hi
[32], val_lo
[16];
10050 /* Copy one element of vals to per element of target vector. */
10051 typedef rtx (*loongarch_vec_repl1_fn
) (rtx
, rtx
);
10052 /* Copy two elements of vals to target vector. */
10053 typedef rtx (*loongarch_vec_repl2_fn
) (rtx
, rtx
, rtx
);
10054 /* Insert scalar operands into the specified position of the vector. */
10055 typedef rtx (*loongarch_vec_set_fn
) (rtx
, rtx
, rtx
);
10056 /* Copy 64bit lowpart to highpart. */
10057 typedef rtx (*loongarch_vec_mirror_fn
) (rtx
, rtx
, rtx
);
10058 /* Merge lowpart and highpart into target. */
10059 typedef rtx (*loongarch_vec_merge_fn
) (rtx
, rtx
, rtx
, rtx
);
10061 loongarch_vec_repl1_fn loongarch_vec_repl1_128
= NULL
,
10062 loongarch_vec_repl1_256
= NULL
;
10063 loongarch_vec_repl2_fn loongarch_vec_repl2_128
= NULL
,
10064 loongarch_vec_repl2_256
= NULL
;
10065 loongarch_vec_set_fn loongarch_vec_set128
= NULL
, loongarch_vec_set256
= NULL
;
10066 loongarch_vec_mirror_fn loongarch_vec_mirror
= NULL
;
10067 loongarch_vec_merge_fn loongarch_lasx_vecinit_merge
= NULL
;
10068 machine_mode half_mode
= VOIDmode
;
10070 /* Check whether elements of each part are the same. */
10071 for (i
= 0; i
< nelt
/ 2; ++i
)
10073 val_hi
[i
] = val_hi
[i
+ nelt
/ 2] = val
[i
+ nelt
/ 2]
10074 = XVECEXP (vals
, 0, i
+ nelt
/ 2);
10075 val_lo
[i
] = val
[i
] = XVECEXP (vals
, 0, i
);
10076 if (!loongarch_constant_elt_p (val_hi
[i
]))
10078 if (!loongarch_constant_elt_p (val_lo
[i
]))
10080 if (i
> 0 && !rtx_equal_p (val_hi
[i
], val_hi
[0]))
10082 if (i
> 0 && !rtx_equal_p (val_lo
[i
], val_lo
[0]))
10084 if (!rtx_equal_p (val_hi
[i
], val_lo
[i
]))
10088 /* If all elements are the same, set all_same true. */
10089 if (hi_same
&& lo_same
&& half_same
)
10092 nvar
= hi_nvar
+ lo_nvar
;
10097 half_mode
= E_V16QImode
;
10098 loongarch_vec_set256
= gen_vec_setv32qi_internal
;
10099 loongarch_vec_repl1_256
= gen_lasx_xvreplgr2vr_b
;
10100 loongarch_lasx_vecinit_merge
10101 = half_same
? gen_lasx_xvpermi_q_v32qi
: gen_lasx_vecinit_merge_v32qi
;
10104 loongarch_vec_set128
= gen_vec_setv16qi
;
10105 loongarch_vec_repl1_128
= gen_lsx_vreplgr2vr_b
;
10106 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_b
;
10110 half_mode
= E_V8HImode
;
10111 loongarch_vec_set256
= gen_vec_setv16hi_internal
;
10112 loongarch_vec_repl1_256
= gen_lasx_xvreplgr2vr_h
;
10113 loongarch_lasx_vecinit_merge
10114 = half_same
? gen_lasx_xvpermi_q_v16hi
: gen_lasx_vecinit_merge_v16hi
;
10117 loongarch_vec_set128
= gen_vec_setv8hi
;
10118 loongarch_vec_repl1_128
= gen_lsx_vreplgr2vr_h
;
10119 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_h
;
10123 half_mode
= V4SImode
;
10124 loongarch_vec_set256
= gen_vec_setv8si
;
10125 loongarch_vec_repl1_256
= gen_lasx_xvreplgr2vr_w
;
10126 loongarch_lasx_vecinit_merge
10127 = half_same
? gen_lasx_xvpermi_q_v8si
: gen_lasx_vecinit_merge_v8si
;
10130 loongarch_vec_set128
= gen_vec_setv4si
;
10131 loongarch_vec_repl1_128
= gen_lsx_vreplgr2vr_w
;
10132 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_w
;
10136 half_mode
= E_V2DImode
;
10137 loongarch_vec_set256
= gen_vec_setv4di
;
10138 loongarch_vec_repl1_256
= gen_lasx_xvreplgr2vr_d
;
10139 loongarch_lasx_vecinit_merge
10140 = half_same
? gen_lasx_xvpermi_q_v4di
: gen_lasx_vecinit_merge_v4di
;
10143 loongarch_vec_set128
= gen_vec_setv2di
;
10144 loongarch_vec_repl1_128
= gen_lsx_vreplgr2vr_d
;
10145 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_d
;
10149 half_mode
= E_V4SFmode
;
10150 loongarch_vec_set256
= gen_vec_setv8sf
;
10151 loongarch_vec_repl1_128
= gen_lsx_vreplvei_w_f_scalar
;
10152 loongarch_vec_repl2_256
= gen_lasx_xvilvl_w_f_internal
;
10153 loongarch_lasx_vecinit_merge
10154 = half_same
? gen_lasx_xvpermi_q_v8sf
: gen_lasx_vecinit_merge_v8sf
;
10157 loongarch_vec_set128
= gen_vec_setv4sf
;
10158 loongarch_vec_repl2_128
= gen_lsx_vilvl_w_f_internal
;
10159 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_w_f
;
10163 half_mode
= E_V2DFmode
;
10164 loongarch_vec_set256
= gen_vec_setv4df
;
10165 loongarch_vec_repl1_128
= gen_lsx_vreplvei_d_f_scalar
;
10166 loongarch_vec_repl2_256
= gen_lasx_xvilvl_d_f_internal
;
10167 loongarch_lasx_vecinit_merge
10168 = half_same
? gen_lasx_xvpermi_q_v4df
: gen_lasx_vecinit_merge_v4df
;
10171 loongarch_vec_set128
= gen_vec_setv2df
;
10172 loongarch_vec_repl2_128
= gen_lsx_vilvl_d_f_internal
;
10173 loongarch_vec_mirror
= gen_lsx_vreplvei_mirror_d_f
;
10177 gcc_unreachable ();
10180 if (ISA_HAS_LASX
&& GET_MODE_SIZE (vmode
) == 32)
10182 /* If all elements are the same, just do a broadcost. */
10184 loongarch_expand_vector_init_same (target
, vals
, nvar
);
10187 gcc_assert (nelt
>= 4);
10189 rtx target_hi
, target_lo
;
10190 /* Write elements of high half-part in target directly. */
10191 target_hi
= target
;
10192 target_lo
= gen_reg_rtx (half_mode
);
10194 /* If all elements of high half-part are the same,
10195 just do a broadcost. Also applicable to low half-part. */
10198 rtx vtmp
= gen_rtx_PARALLEL (vmode
, gen_rtvec_v (nelt
, val_hi
));
10199 loongarch_expand_vector_init_same (target_hi
, vtmp
, hi_nvar
);
10204 = gen_rtx_PARALLEL (half_mode
, gen_rtvec_v (nelt
/ 2, val_lo
));
10205 loongarch_expand_vector_init_same (target_lo
, vtmp
, lo_nvar
);
10208 for (i
= 0; i
< nelt
/ 2; ++i
)
10212 if (vmode
== E_V8SFmode
|| vmode
== E_V4DFmode
)
10214 /* Using xvilvl to load lowest 2 elements simultaneously
10215 to reduce the number of instructions. */
10218 op0
= force_reg (imode
, val_hi
[0]);
10219 op1
= force_reg (imode
, val_hi
[1]);
10221 loongarch_vec_repl2_256 (target_hi
, op0
, op1
));
10225 op0
= force_reg (imode
, val_hi
[i
]);
10227 loongarch_vec_set256 (target_hi
, op0
, GEN_INT (i
)));
10232 op0
= force_reg (imode
, val_hi
[i
]);
10233 /* Assign the lowest element of val_hi to all elements
10237 emit_insn (loongarch_vec_repl1_256 (target_hi
, op0
));
10239 else if (!rtx_equal_p (val_hi
[i
], val_hi
[0]))
10242 loongarch_vec_set256 (target_hi
, op0
, GEN_INT (i
)));
10246 if (!lo_same
&& !half_same
)
10248 op0
= force_reg (imode
, val_lo
[i
]);
10249 /* Assign the lowest element of val_lo to all elements
10253 emit_insn (loongarch_vec_repl1_128 (target_lo
, op0
));
10255 else if (!rtx_equal_p (val_lo
[i
], val_lo
[0]))
10258 loongarch_vec_set128 (target_lo
, op0
, GEN_INT (i
)));
10264 emit_insn (loongarch_lasx_vecinit_merge (target
, target_hi
,
10265 target_hi
, const0_rtx
));
10268 emit_insn (loongarch_lasx_vecinit_merge (target
, target_hi
, target_lo
,
10277 loongarch_expand_vector_init_same (target
, vals
, nvar
);
10280 for (i
= 0; i
< nelt
; ++i
)
10282 if (vmode
== E_V4SFmode
|| vmode
== E_V2DFmode
)
10284 /* Using vilvl to load lowest 2 elements simultaneously to
10285 reduce the number of instructions. */
10288 op0
= force_reg (imode
, val
[0]);
10289 op1
= force_reg (imode
, val
[1]);
10290 emit_insn (loongarch_vec_repl2_128 (target
, op0
, op1
));
10294 op0
= force_reg (imode
, val
[i
]);
10296 loongarch_vec_set128 (target
, op0
, GEN_INT (i
)));
10301 if (half_same
&& i
== nelt
/ 2)
10304 loongarch_vec_mirror (target
, target
, const0_rtx
));
10307 op0
= force_reg (imode
, val
[i
]);
10308 /* Assign the lowest element of val to all elements of
10312 emit_insn (loongarch_vec_repl1_128 (target
, op0
));
10314 else if (!rtx_equal_p (val
[i
], val
[0]))
10317 loongarch_vec_set128 (target
, op0
, GEN_INT (i
)));
10325 /* Load constants from the pool, or whatever's handy. */
10328 emit_move_insn (target
, gen_rtx_CONST_VECTOR (vmode
, XVEC (vals
, 0)));
10332 /* For two-part initialization, always use CONCAT. */
10335 rtx op0
= force_reg (imode
, val
[0]);
10336 rtx op1
= force_reg (imode
, val
[1]);
10337 x
= gen_rtx_VEC_CONCAT (vmode
, op0
, op1
);
10338 emit_insn (gen_rtx_SET (target
, x
));
10342 /* No LoongArch CPU supports vectors with more elements as at now. */
10343 gcc_unreachable ();
10346 /* Implement HARD_REGNO_CALLER_SAVE_MODE. */
10349 loongarch_hard_regno_caller_save_mode (unsigned int regno
, unsigned int nregs
,
10352 /* For performance, avoid saving/restoring upper parts of a register
10353 by returning MODE as save mode when the mode is known. */
10354 if (mode
== VOIDmode
)
10355 return choose_hard_reg_mode (regno
, nregs
, NULL
);
10360 /* Generate RTL for comparing CMP_OP0 and CMP_OP1 using condition COND and
10361 store the result -1 or 0 in DEST. */
10364 loongarch_expand_lsx_cmp (rtx dest
, enum rtx_code cond
, rtx op0
, rtx op1
)
10366 machine_mode cmp_mode
= GET_MODE (op0
);
10367 bool negate
= false;
10382 cond
= reverse_condition (cond
);
10395 std::swap (op0
, op1
);
10396 cond
= swap_condition (cond
);
10399 gcc_unreachable ();
10401 loongarch_emit_binary (cond
, dest
, op0
, op1
);
10403 emit_move_insn (dest
, gen_rtx_NOT (GET_MODE (dest
), dest
));
10410 loongarch_emit_binary (cond
, dest
, op0
, op1
);
10414 gcc_unreachable ();
10419 /* Expand VEC_COND_EXPR, where:
10420 MODE is mode of the result
10421 VIMODE equivalent integer mode
10422 OPERANDS operands of VEC_COND_EXPR. */
10425 loongarch_expand_vec_cond_expr (machine_mode mode
, machine_mode vimode
,
10428 rtx cond
= operands
[3];
10429 rtx cmp_op0
= operands
[4];
10430 rtx cmp_op1
= operands
[5];
10431 rtx cmp_res
= gen_reg_rtx (vimode
);
10433 loongarch_expand_lsx_cmp (cmp_res
, GET_CODE (cond
), cmp_op0
, cmp_op1
);
10435 /* We handle the following cases:
10436 1) r = a CMP b ? -1 : 0
10437 2) r = a CMP b ? -1 : v
10438 3) r = a CMP b ? v : 0
10439 4) r = a CMP b ? v1 : v2 */
10441 /* Case (1) above. We only move the results. */
10442 if (operands
[1] == CONSTM1_RTX (vimode
)
10443 && operands
[2] == CONST0_RTX (vimode
))
10444 emit_move_insn (operands
[0], cmp_res
);
10447 rtx src1
= gen_reg_rtx (vimode
);
10448 rtx src2
= gen_reg_rtx (vimode
);
10449 rtx mask
= gen_reg_rtx (vimode
);
10452 /* Move the vector result to use it as a mask. */
10453 emit_move_insn (mask
, cmp_res
);
10455 if (register_operand (operands
[1], mode
))
10457 rtx xop1
= operands
[1];
10458 if (mode
!= vimode
)
10460 xop1
= gen_reg_rtx (vimode
);
10461 emit_move_insn (xop1
,
10462 simplify_gen_subreg (vimode
, operands
[1],
10465 emit_move_insn (src1
, xop1
);
10469 gcc_assert (operands
[1] == CONSTM1_RTX (vimode
));
10470 /* Case (2) if the below doesn't move the mask to src2. */
10471 emit_move_insn (src1
, mask
);
10474 if (register_operand (operands
[2], mode
))
10476 rtx xop2
= operands
[2];
10477 if (mode
!= vimode
)
10479 xop2
= gen_reg_rtx (vimode
);
10480 emit_move_insn (xop2
,
10481 simplify_gen_subreg (vimode
, operands
[2],
10484 emit_move_insn (src2
, xop2
);
10488 gcc_assert (operands
[2] == CONST0_RTX (mode
));
10489 /* Case (3) if the above didn't move the mask to src1. */
10490 emit_move_insn (src2
, mask
);
10493 /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
10494 In any case, we eventually do vector mask-based copy. */
10495 bsel
= gen_rtx_IOR (vimode
,
10496 gen_rtx_AND (vimode
,
10497 gen_rtx_NOT (vimode
, mask
), src2
),
10498 gen_rtx_AND (vimode
, mask
, src1
));
10499 /* The result is placed back to a register with the mask. */
10500 emit_insn (gen_rtx_SET (mask
, bsel
));
10501 emit_move_insn (operands
[0],
10502 simplify_gen_subreg (mode
, mask
, vimode
, 0));
10507 loongarch_expand_vec_cond_mask_expr (machine_mode mode
, machine_mode vimode
,
10510 rtx cmp_res
= operands
[3];
10512 /* We handle the following cases:
10513 1) r = a CMP b ? -1 : 0
10514 2) r = a CMP b ? -1 : v
10515 3) r = a CMP b ? v : 0
10516 4) r = a CMP b ? v1 : v2 */
10518 /* Case (1) above. We only move the results. */
10519 if (operands
[1] == CONSTM1_RTX (vimode
)
10520 && operands
[2] == CONST0_RTX (vimode
))
10521 emit_move_insn (operands
[0], cmp_res
);
10524 rtx src1
= gen_reg_rtx (vimode
);
10525 rtx src2
= gen_reg_rtx (vimode
);
10526 rtx mask
= gen_reg_rtx (vimode
);
10529 /* Move the vector result to use it as a mask. */
10530 emit_move_insn (mask
, cmp_res
);
10532 if (register_operand (operands
[1], mode
))
10534 rtx xop1
= operands
[1];
10535 if (mode
!= vimode
)
10537 xop1
= gen_reg_rtx (vimode
);
10538 emit_move_insn (xop1
,
10539 simplify_gen_subreg (vimode
, operands
[1],
10542 emit_move_insn (src1
, xop1
);
10546 gcc_assert (operands
[1] == CONSTM1_RTX (vimode
));
10547 /* Case (2) if the below doesn't move the mask to src2. */
10548 emit_move_insn (src1
, mask
);
10551 if (register_operand (operands
[2], mode
))
10553 rtx xop2
= operands
[2];
10554 if (mode
!= vimode
)
10556 xop2
= gen_reg_rtx (vimode
);
10557 emit_move_insn (xop2
,
10558 simplify_gen_subreg (vimode
, operands
[2],
10561 emit_move_insn (src2
, xop2
);
10565 gcc_assert (operands
[2] == CONST0_RTX (mode
));
10566 /* Case (3) if the above didn't move the mask to src1. */
10567 emit_move_insn (src2
, mask
);
10570 /* We deal with case (4) if the mask wasn't moved to either src1 or src2.
10571 In any case, we eventually do vector mask-based copy. */
10572 bsel
= gen_rtx_IOR (vimode
,
10573 gen_rtx_AND (vimode
,
10574 gen_rtx_NOT (vimode
, mask
), src2
),
10575 gen_rtx_AND (vimode
, mask
, src1
));
10576 /* The result is placed back to a register with the mask. */
10577 emit_insn (gen_rtx_SET (mask
, bsel
));
10578 emit_move_insn (operands
[0], simplify_gen_subreg (mode
, mask
,
10583 /* Expand integer vector comparison */
10585 loongarch_expand_vec_cmp (rtx operands
[])
10588 rtx_code code
= GET_CODE (operands
[1]);
10589 loongarch_expand_lsx_cmp (operands
[0], code
, operands
[2], operands
[3]);
10593 /* Implement TARGET_CASE_VALUES_THRESHOLD. */
10596 loongarch_case_values_threshold (void)
10598 return default_case_values_threshold ();
10601 /* Implement TARGET_SPILL_CLASS. */
10604 loongarch_spill_class (reg_class_t rclass ATTRIBUTE_UNUSED
,
10605 machine_mode mode ATTRIBUTE_UNUSED
)
10610 /* Implement TARGET_PROMOTE_FUNCTION_MODE. */
10612 /* This function is equivalent to default_promote_function_mode_always_promote
10613 except that it returns a promoted mode even if type is NULL_TREE. This is
10614 needed by libcalls which have no type (only a mode) such as fixed conversion
10615 routines that take a signed or unsigned char/short argument and convert it
10616 to a fixed type. */
10618 static machine_mode
10619 loongarch_promote_function_mode (const_tree type ATTRIBUTE_UNUSED
,
10621 int *punsignedp ATTRIBUTE_UNUSED
,
10622 const_tree fntype ATTRIBUTE_UNUSED
,
10623 int for_return ATTRIBUTE_UNUSED
)
10627 if (type
!= NULL_TREE
)
10628 return promote_mode (type
, mode
, punsignedp
);
10630 unsignedp
= *punsignedp
;
10631 PROMOTE_MODE (mode
, unsignedp
, type
);
10632 *punsignedp
= unsignedp
;
10636 /* Implement TARGET_STARTING_FRAME_OFFSET. See loongarch_compute_frame_info
10637 for details about the frame layout. */
10639 static HOST_WIDE_INT
10640 loongarch_starting_frame_offset (void)
10642 if (FRAME_GROWS_DOWNWARD
)
10644 return crtl
->outgoing_args_size
;
10647 /* A subroutine of loongarch_build_signbit_mask. If VECT is true,
10648 then replicate the value for all elements of the vector
10652 loongarch_build_const_vector (machine_mode mode
, bool vect
, rtx value
)
10656 machine_mode scalar_mode
;
10677 n_elt
= GET_MODE_NUNITS (mode
);
10678 v
= rtvec_alloc (n_elt
);
10679 scalar_mode
= GET_MODE_INNER (mode
);
10681 RTVEC_ELT (v
, 0) = value
;
10683 for (i
= 1; i
< n_elt
; ++i
)
10684 RTVEC_ELT (v
, i
) = vect
? value
: CONST0_RTX (scalar_mode
);
10686 return gen_rtx_CONST_VECTOR (mode
, v
);
10689 gcc_unreachable ();
10693 /* Create a mask for the sign bit in MODE
10694 for an register. If VECT is true, then replicate the mask for
10695 all elements of the vector register. If INVERT is true, then create
10696 a mask excluding the sign bit. */
10699 loongarch_build_signbit_mask (machine_mode mode
, bool vect
, bool invert
)
10701 machine_mode vec_mode
, imode
;
10729 vec_mode
= VOIDmode
;
10734 gcc_unreachable ();
10737 machine_mode inner_mode
= GET_MODE_INNER (mode
);
10738 w
= wi::set_bit_in_zero (GET_MODE_BITSIZE (inner_mode
) - 1,
10739 GET_MODE_BITSIZE (inner_mode
));
10741 w
= wi::bit_not (w
);
10743 /* Force this value into the low part of a fp vector constant. */
10744 mask
= immed_wide_int_const (w
, imode
);
10745 mask
= gen_lowpart (inner_mode
, mask
);
10747 if (vec_mode
== VOIDmode
)
10748 return force_reg (inner_mode
, mask
);
10750 v
= loongarch_build_const_vector (vec_mode
, vect
, mask
);
10751 return force_reg (vec_mode
, v
);
10754 /* Use rsqrte instruction and Newton-Rhapson to compute the approximation of
10755 a single precision floating point [reciprocal] square root. */
10757 void loongarch_emit_swrsqrtsf (rtx res
, rtx a
, machine_mode mode
, bool recip
)
10759 rtx x0
, e0
, e1
, e2
, mhalf
, monehalf
;
10763 x0
= gen_reg_rtx (mode
);
10764 e0
= gen_reg_rtx (mode
);
10765 e1
= gen_reg_rtx (mode
);
10766 e2
= gen_reg_rtx (mode
);
10768 real_arithmetic (&r
, ABS_EXPR
, &dconsthalf
, NULL
);
10769 mhalf
= const_double_from_real_value (r
, SFmode
);
10771 real_arithmetic (&r
, PLUS_EXPR
, &dconsthalf
, &dconst1
);
10772 monehalf
= const_double_from_real_value (r
, SFmode
);
10773 unspec
= UNSPEC_RSQRTE
;
10775 if (VECTOR_MODE_P (mode
))
10777 mhalf
= loongarch_build_const_vector (mode
, true, mhalf
);
10778 monehalf
= loongarch_build_const_vector (mode
, true, monehalf
);
10779 unspec
= GET_MODE_SIZE (mode
) == 32 ? UNSPEC_LASX_XVFRSQRTE
10780 : UNSPEC_LSX_VFRSQRTE
;
10783 /* rsqrt(a) = rsqrte(a) * (1.5 - 0.5 * a * rsqrte(a) * rsqrte(a))
10784 sqrt(a) = a * rsqrte(a) * (1.5 - 0.5 * a * rsqrte(a) * rsqrte(a)) */
10786 a
= force_reg (mode
, a
);
10788 /* x0 = rsqrt(a) estimate. */
10789 emit_insn (gen_rtx_SET (x0
, gen_rtx_UNSPEC (mode
, gen_rtvec (1, a
),
10792 /* If (a == 0.0) Filter out infinity to prevent NaN for sqrt(0.0). */
10795 rtx zero
= force_reg (mode
, CONST0_RTX (mode
));
10797 if (VECTOR_MODE_P (mode
))
10799 machine_mode imode
= related_int_vector_mode (mode
).require ();
10800 rtx mask
= gen_reg_rtx (imode
);
10801 emit_insn (gen_rtx_SET (mask
, gen_rtx_NE (imode
, a
, zero
)));
10802 emit_insn (gen_rtx_SET (x0
, gen_rtx_AND (mode
, x0
,
10803 gen_lowpart (mode
, mask
))));
10807 rtx target
= emit_conditional_move (x0
, { GT
, a
, zero
, mode
},
10808 x0
, zero
, mode
, 0);
10810 emit_move_insn (x0
, target
);
10815 emit_insn (gen_rtx_SET (e0
, gen_rtx_MULT (mode
, x0
, a
)));
10817 emit_insn (gen_rtx_SET (e1
, gen_rtx_MULT (mode
, e0
, x0
)));
10819 /* e2 = 1.5 - e1 * 0.5 */
10820 mhalf
= force_reg (mode
, mhalf
);
10821 monehalf
= force_reg (mode
, monehalf
);
10822 emit_insn (gen_rtx_SET (e2
, gen_rtx_FMA (mode
,
10823 gen_rtx_NEG (mode
, e1
),
10824 mhalf
, monehalf
)));
10827 /* res = e2 * x0 */
10828 emit_insn (gen_rtx_SET (res
, gen_rtx_MULT (mode
, x0
, e2
)));
10830 /* res = e2 * e0 */
10831 emit_insn (gen_rtx_SET (res
, gen_rtx_MULT (mode
, e2
, e0
)));
10834 /* Use recipe instruction and Newton-Rhapson to compute the approximation of
10835 a single precision floating point divide. */
10837 void loongarch_emit_swdivsf (rtx res
, rtx a
, rtx b
, machine_mode mode
)
10841 x0
= gen_reg_rtx (mode
);
10842 e0
= gen_reg_rtx (mode
);
10843 int unspec
= UNSPEC_RECIPE
;
10845 real_arithmetic (&r
, ABS_EXPR
, &dconst2
, NULL
);
10846 mtwo
= const_double_from_real_value (r
, SFmode
);
10848 if (VECTOR_MODE_P (mode
))
10850 mtwo
= loongarch_build_const_vector (mode
, true, mtwo
);
10851 unspec
= GET_MODE_SIZE (mode
) == 32 ? UNSPEC_LASX_XVFRECIPE
10852 : UNSPEC_LSX_VFRECIPE
;
10855 mtwo
= force_reg (mode
, mtwo
);
10857 /* a / b = a * recipe(b) * (2.0 - b * recipe(b)) */
10859 /* x0 = 1./b estimate. */
10860 emit_insn (gen_rtx_SET (x0
, gen_rtx_UNSPEC (mode
, gen_rtvec (1, b
),
10862 /* e0 = 2.0 - b * x0. */
10863 emit_insn (gen_rtx_SET (e0
, gen_rtx_FMA (mode
,
10864 gen_rtx_NEG (mode
, b
), x0
, mtwo
)));
10866 if (a
!= CONST1_RTX (mode
))
10868 rtx e1
= gen_reg_rtx (mode
);
10870 emit_insn (gen_rtx_SET (e1
, gen_rtx_MULT (mode
, a
, x0
)));
10871 /* res = e0 * e1. */
10872 emit_insn (gen_rtx_SET (res
, gen_rtx_MULT (mode
, e0
, e1
)));
10876 /* res = e0 * x0. */
10877 emit_insn (gen_rtx_SET (res
, gen_rtx_MULT (mode
, e0
, x0
)));
10882 loongarch_builtin_support_vector_misalignment (machine_mode mode
,
10887 if ((ISA_HAS_LSX
|| ISA_HAS_LASX
) && STRICT_ALIGNMENT
)
10889 if (optab_handler (movmisalign_optab
, mode
) == CODE_FOR_nothing
)
10891 if (misalignment
== -1)
10894 return default_builtin_support_vector_misalignment (mode
, type
, misalignment
,
10901 return (flag_finite_math_only
10902 && !flag_trapping_math
10903 && flag_unsafe_math_optimizations
);
10906 /* Implement the TARGET_OPTAB_SUPPORTED_P hook. */
10909 loongarch_optab_supported_p (int op
, machine_mode
, machine_mode
,
10910 optimization_type opt_type
)
10915 return opt_type
== OPTIMIZE_FOR_SPEED
&& use_rsqrt_p ();
10922 /* If -fverbose-asm, dump some info for debugging. */
10924 loongarch_asm_code_end (void)
10926 #define DUMP_FEATURE(PRED) \
10927 fprintf (asm_out_file, "%s %s: %s\n", ASM_COMMENT_START, #PRED, \
10928 (PRED) ? "enabled" : "disabled")
10930 if (flag_verbose_asm
)
10932 fprintf (asm_out_file
, "\n%s CPU: %s\n", ASM_COMMENT_START
,
10933 loongarch_cpu_strings
[la_target
.cpu_arch
]);
10934 fprintf (asm_out_file
, "%s Tune: %s\n", ASM_COMMENT_START
,
10935 loongarch_cpu_strings
[la_target
.cpu_tune
]);
10936 fprintf (asm_out_file
, "%s Base ISA: %s\n", ASM_COMMENT_START
,
10937 loongarch_isa_base_strings
[la_target
.isa
.base
]);
10938 DUMP_FEATURE (ISA_HAS_FRECIPE
);
10939 DUMP_FEATURE (ISA_HAS_DIV32
);
10940 DUMP_FEATURE (ISA_HAS_LAM_BH
);
10941 DUMP_FEATURE (ISA_HAS_LAMCAS
);
10942 DUMP_FEATURE (ISA_HAS_LD_SEQ_SA
);
10945 fputs ("\n\n", asm_out_file
);
10946 #undef DUMP_FEATURE
10949 /* Initialize the GCC target structure. */
10950 #undef TARGET_ASM_ALIGNED_HI_OP
10951 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
10952 #undef TARGET_ASM_ALIGNED_SI_OP
10953 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
10954 #undef TARGET_ASM_ALIGNED_DI_OP
10955 #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
10957 #undef TARGET_OPTION_OVERRIDE
10958 #define TARGET_OPTION_OVERRIDE loongarch_option_override
10959 #undef TARGET_OPTION_SAVE
10960 #define TARGET_OPTION_SAVE loongarch_option_save
10961 #undef TARGET_OPTION_RESTORE
10962 #define TARGET_OPTION_RESTORE loongarch_option_restore
10964 #undef TARGET_LEGITIMIZE_ADDRESS
10965 #define TARGET_LEGITIMIZE_ADDRESS loongarch_legitimize_address
10967 #undef TARGET_ASM_SELECT_RTX_SECTION
10968 #define TARGET_ASM_SELECT_RTX_SECTION loongarch_select_rtx_section
10969 #undef TARGET_ASM_FUNCTION_RODATA_SECTION
10970 #define TARGET_ASM_FUNCTION_RODATA_SECTION loongarch_function_rodata_section
10972 #undef TARGET_ASM_CODE_END
10973 #define TARGET_ASM_CODE_END loongarch_asm_code_end
10975 #undef TARGET_SCHED_INIT
10976 #define TARGET_SCHED_INIT loongarch_sched_init
10977 #undef TARGET_SCHED_REORDER
10978 #define TARGET_SCHED_REORDER loongarch_sched_reorder
10979 #undef TARGET_SCHED_REORDER2
10980 #define TARGET_SCHED_REORDER2 loongarch_sched_reorder2
10981 #undef TARGET_SCHED_VARIABLE_ISSUE
10982 #define TARGET_SCHED_VARIABLE_ISSUE loongarch_variable_issue
10983 #undef TARGET_SCHED_ADJUST_COST
10984 #define TARGET_SCHED_ADJUST_COST loongarch_adjust_cost
10985 #undef TARGET_SCHED_ISSUE_RATE
10986 #define TARGET_SCHED_ISSUE_RATE loongarch_issue_rate
10987 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
10988 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
10989 loongarch_multipass_dfa_lookahead
10991 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
10992 #define TARGET_FUNCTION_OK_FOR_SIBCALL loongarch_function_ok_for_sibcall
10994 #undef TARGET_VALID_POINTER_MODE
10995 #define TARGET_VALID_POINTER_MODE loongarch_valid_pointer_mode
10996 #undef TARGET_REGISTER_MOVE_COST
10997 #define TARGET_REGISTER_MOVE_COST loongarch_register_move_cost
10998 #undef TARGET_MEMORY_MOVE_COST
10999 #define TARGET_MEMORY_MOVE_COST loongarch_memory_move_cost
11000 #undef TARGET_RTX_COSTS
11001 #define TARGET_RTX_COSTS loongarch_rtx_costs
11002 #undef TARGET_ADDRESS_COST
11003 #define TARGET_ADDRESS_COST loongarch_address_cost
11004 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
11005 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \
11006 loongarch_builtin_vectorization_cost
11007 #undef TARGET_VECTORIZE_CREATE_COSTS
11008 #define TARGET_VECTORIZE_CREATE_COSTS loongarch_vectorize_create_costs
11011 #undef TARGET_IN_SMALL_DATA_P
11012 #define TARGET_IN_SMALL_DATA_P loongarch_in_small_data_p
11014 #undef TARGET_PREFERRED_RELOAD_CLASS
11015 #define TARGET_PREFERRED_RELOAD_CLASS loongarch_preferred_reload_class
11017 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
11018 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
11020 #undef TARGET_EXPAND_BUILTIN_VA_START
11021 #define TARGET_EXPAND_BUILTIN_VA_START loongarch_va_start
11023 #undef TARGET_PROMOTE_FUNCTION_MODE
11024 #define TARGET_PROMOTE_FUNCTION_MODE loongarch_promote_function_mode
11025 #undef TARGET_RETURN_IN_MEMORY
11026 #define TARGET_RETURN_IN_MEMORY loongarch_return_in_memory
11028 #undef TARGET_FUNCTION_VALUE
11029 #define TARGET_FUNCTION_VALUE loongarch_function_value
11030 #undef TARGET_LIBCALL_VALUE
11031 #define TARGET_LIBCALL_VALUE loongarch_libcall_value
11033 #undef TARGET_ASM_OUTPUT_MI_THUNK
11034 #define TARGET_ASM_OUTPUT_MI_THUNK loongarch_output_mi_thunk
11035 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
11036 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
11037 hook_bool_const_tree_hwi_hwi_const_tree_true
11039 #undef TARGET_PRINT_OPERAND
11040 #define TARGET_PRINT_OPERAND loongarch_print_operand
11041 #undef TARGET_PRINT_OPERAND_ADDRESS
11042 #define TARGET_PRINT_OPERAND_ADDRESS loongarch_print_operand_address
11043 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
11044 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P \
11045 loongarch_print_operand_punct_valid_p
11047 #undef TARGET_SETUP_INCOMING_VARARGS
11048 #define TARGET_SETUP_INCOMING_VARARGS loongarch_setup_incoming_varargs
11049 #undef TARGET_STRICT_ARGUMENT_NAMING
11050 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
11051 #undef TARGET_MUST_PASS_IN_STACK
11052 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
11053 #undef TARGET_PASS_BY_REFERENCE
11054 #define TARGET_PASS_BY_REFERENCE loongarch_pass_by_reference
11055 #undef TARGET_ARG_PARTIAL_BYTES
11056 #define TARGET_ARG_PARTIAL_BYTES loongarch_arg_partial_bytes
11057 #undef TARGET_FUNCTION_ARG
11058 #define TARGET_FUNCTION_ARG loongarch_function_arg
11059 #undef TARGET_FUNCTION_ARG_ADVANCE
11060 #define TARGET_FUNCTION_ARG_ADVANCE loongarch_function_arg_advance
11061 #undef TARGET_FUNCTION_ARG_BOUNDARY
11062 #define TARGET_FUNCTION_ARG_BOUNDARY loongarch_function_arg_boundary
11064 #undef TARGET_OPTAB_SUPPORTED_P
11065 #define TARGET_OPTAB_SUPPORTED_P loongarch_optab_supported_p
11067 #undef TARGET_VECTOR_MODE_SUPPORTED_P
11068 #define TARGET_VECTOR_MODE_SUPPORTED_P loongarch_vector_mode_supported_p
11070 #undef TARGET_SCALAR_MODE_SUPPORTED_P
11071 #define TARGET_SCALAR_MODE_SUPPORTED_P loongarch_scalar_mode_supported_p
11073 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
11074 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE loongarch_preferred_simd_mode
11076 #undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES
11077 #define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
11078 loongarch_autovectorize_vector_modes
11080 #undef TARGET_OPTAB_SUPPORTED_P
11081 #define TARGET_OPTAB_SUPPORTED_P loongarch_optab_supported_p
11083 #undef TARGET_INIT_BUILTINS
11084 #define TARGET_INIT_BUILTINS loongarch_init_builtins
11085 #undef TARGET_BUILTIN_DECL
11086 #define TARGET_BUILTIN_DECL loongarch_builtin_decl
11087 #undef TARGET_EXPAND_BUILTIN
11088 #define TARGET_EXPAND_BUILTIN loongarch_expand_builtin
11090 /* The generic ELF target does not always have TLS support. */
11092 #undef TARGET_HAVE_TLS
11093 #define TARGET_HAVE_TLS HAVE_AS_TLS
11096 #undef TARGET_CANNOT_FORCE_CONST_MEM
11097 #define TARGET_CANNOT_FORCE_CONST_MEM loongarch_cannot_force_const_mem
11099 #undef TARGET_LEGITIMATE_CONSTANT_P
11100 #define TARGET_LEGITIMATE_CONSTANT_P loongarch_legitimate_constant_p
11102 #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
11103 #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true
11105 #ifdef HAVE_AS_DTPRELWORD
11106 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
11107 #define TARGET_ASM_OUTPUT_DWARF_DTPREL loongarch_output_dwarf_dtprel
11110 #undef TARGET_LEGITIMATE_ADDRESS_P
11111 #define TARGET_LEGITIMATE_ADDRESS_P loongarch_legitimate_address_p
11113 #undef TARGET_FRAME_POINTER_REQUIRED
11114 #define TARGET_FRAME_POINTER_REQUIRED loongarch_frame_pointer_required
11116 #undef TARGET_CAN_ELIMINATE
11117 #define TARGET_CAN_ELIMINATE loongarch_can_eliminate
11119 #undef TARGET_CONDITIONAL_REGISTER_USAGE
11120 #define TARGET_CONDITIONAL_REGISTER_USAGE loongarch_conditional_register_usage
11122 #undef TARGET_TRAMPOLINE_INIT
11123 #define TARGET_TRAMPOLINE_INIT loongarch_trampoline_init
11125 #undef TARGET_MIN_ANCHOR_OFFSET
11126 #define TARGET_MIN_ANCHOR_OFFSET (-IMM_REACH/2)
11128 #undef TARGET_MAX_ANCHOR_OFFSET
11129 #define TARGET_MAX_ANCHOR_OFFSET (IMM_REACH/2-1)
11130 #undef TARGET_VECTORIZE_VEC_PERM_CONST
11131 #define TARGET_VECTORIZE_VEC_PERM_CONST loongarch_vectorize_vec_perm_const
11133 #undef TARGET_SCHED_REASSOCIATION_WIDTH
11134 #define TARGET_SCHED_REASSOCIATION_WIDTH loongarch_sched_reassociation_width
11136 #undef TARGET_CASE_VALUES_THRESHOLD
11137 #define TARGET_CASE_VALUES_THRESHOLD loongarch_case_values_threshold
11139 #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
11140 #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV loongarch_atomic_assign_expand_fenv
11142 #undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
11143 #define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true
11145 #undef TARGET_SPILL_CLASS
11146 #define TARGET_SPILL_CLASS loongarch_spill_class
11148 #undef TARGET_HARD_REGNO_NREGS
11149 #define TARGET_HARD_REGNO_NREGS loongarch_hard_regno_nregs
11150 #undef TARGET_HARD_REGNO_MODE_OK
11151 #define TARGET_HARD_REGNO_MODE_OK loongarch_hard_regno_mode_ok
11153 #undef TARGET_MODES_TIEABLE_P
11154 #define TARGET_MODES_TIEABLE_P loongarch_modes_tieable_p
11156 #undef TARGET_HARD_REGNO_CALL_PART_CLOBBERED
11157 #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
11158 loongarch_hard_regno_call_part_clobbered
11160 #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
11161 #define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 2
11163 #undef TARGET_CAN_CHANGE_MODE_CLASS
11164 #define TARGET_CAN_CHANGE_MODE_CLASS loongarch_can_change_mode_class
11166 #undef TARGET_CONSTANT_ALIGNMENT
11167 #define TARGET_CONSTANT_ALIGNMENT loongarch_constant_alignment
11169 #undef TARGET_STARTING_FRAME_OFFSET
11170 #define TARGET_STARTING_FRAME_OFFSET loongarch_starting_frame_offset
11172 #undef TARGET_SECONDARY_RELOAD
11173 #define TARGET_SECONDARY_RELOAD loongarch_secondary_reload
11175 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
11176 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
11178 #undef TARGET_ATTRIBUTE_TABLE
11179 #define TARGET_ATTRIBUTE_TABLE loongarch_attribute_table
11181 #undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
11182 #define TARGET_USE_ANCHORS_FOR_SYMBOL_P loongarch_use_anchors_for_symbol_p
11184 #undef TARGET_ASAN_SHADOW_OFFSET
11185 #define TARGET_ASAN_SHADOW_OFFSET loongarch_asan_shadow_offset
11187 #undef TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS
11188 #define TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS \
11189 loongarch_get_separate_components
11191 #undef TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB
11192 #define TARGET_SHRINK_WRAP_COMPONENTS_FOR_BB loongarch_components_for_bb
11194 #undef TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS
11195 #define TARGET_SHRINK_WRAP_DISQUALIFY_COMPONENTS \
11196 loongarch_disqualify_components
11198 #undef TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS
11199 #define TARGET_SHRINK_WRAP_EMIT_PROLOGUE_COMPONENTS \
11200 loongarch_emit_prologue_components
11202 #undef TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS
11203 #define TARGET_SHRINK_WRAP_EMIT_EPILOGUE_COMPONENTS \
11204 loongarch_emit_epilogue_components
11206 #undef TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS
11207 #define TARGET_SHRINK_WRAP_SET_HANDLED_COMPONENTS \
11208 loongarch_set_handled_components
11210 #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
11211 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
11212 loongarch_builtin_support_vector_misalignment
11214 struct gcc_target targetm
= TARGET_INITIALIZER
;
11216 #include "gt-loongarch.h"