Daily bump.
[official-gcc.git] / gcc / config / loongarch / loongarch.md
blob701f31fbb17c3320dd81548df51874af0c179edf
1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C) 2021-2025 Free Software Foundation, Inc.
3 ;; Contributed by Loongson Ltd.
4 ;; Based on MIPS 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)
11 ;; any later version.
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_c_enum "unspec" [
23   ;; Floating-point moves.
24   UNSPEC_LOAD_LOW
25   UNSPEC_LOAD_HIGH
26   UNSPEC_STORE_WORD
27   UNSPEC_MOVGR2FRH
28   UNSPEC_MOVFRH2GR
30   ;; Floating point unspecs.
31   UNSPEC_FRINT
32   UNSPEC_FCLASS
33   UNSPEC_FMAX
34   UNSPEC_FMIN
35   UNSPEC_FTINT
36   UNSPEC_FTINTRM
37   UNSPEC_FTINTRP
38   UNSPEC_FSCALEB
39   UNSPEC_FLOGB
41   ;; Override return address for exception handling.
42   UNSPEC_EH_RETURN
44   ;; Bit operation
45   UNSPEC_BITREV_4B
46   UNSPEC_BITREV_8B
48   ;; TLS
49   UNSPEC_TLS
50   UNSPEC_TLS_DESC
51   UNSPEC_TLS_DESC_OFF64
53   ;; Stack tie
54   UNSPEC_TIE
56   ;; RSQRT
57   UNSPEC_RSQRT
58   UNSPEC_RSQRTE
60   ;; RECIP
61   UNSPEC_RECIPE
63   ;; CRC
64   UNSPEC_CRC
65   UNSPEC_CRCC
67   UNSPEC_LOAD_FROM_GOT
68   UNSPEC_PCALAU12I
69   UNSPEC_PCALAU12I_GR
70   UNSPEC_ADD_TLS_LE_RELAX
71   UNSPEC_ORI_L_LO12
72   UNSPEC_LUI_L_HI20
73   UNSPEC_LUI_H_LO20
74   UNSPEC_LUI_H_HI12
75   UNSPEC_TLS_LOW
77   ;; Fake div.w[u] mod.w[u]
78   UNSPEC_FAKE_ANY_DIV
80   UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
81   UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
83   UNSPEC_LOAD_SYMBOL_OFFSET64
84   UNSPEC_LA_PCREL_64_PART1
85   UNSPEC_LA_PCREL_64_PART2
88 (define_c_enum "unspecv" [
89   ;; Blockage and synchronisation.
90   UNSPECV_BLOCKAGE
91   UNSPECV_DBAR
92   UNSPECV_IBAR
94   ;; Privileged instructions
95   UNSPECV_CSRRD
96   UNSPECV_CSRWR
97   UNSPECV_CSRXCHG
98   UNSPECV_IOCSRRD
99   UNSPECV_IOCSRWR
100   UNSPECV_CACOP
101   UNSPECV_LDDIR
102   UNSPECV_LDPTE
103   UNSPECV_ERTN
105   ;; Stack checking.
106   UNSPECV_PROBE_STACK_RANGE
108   ;; Floating-point environment.
109   UNSPECV_MOVFCSR2GR
110   UNSPECV_MOVGR2FCSR
112   ;; Others
113   UNSPECV_CPUCFG
114   UNSPECV_ASRTLE_D
115   UNSPECV_ASRTGT_D
116   UNSPECV_SYSCALL
117   UNSPECV_BREAK
120 (define_constants
121   [(RETURN_ADDR_REGNUM          1)
122    (TP_REGNUM                   2)
123    (T0_REGNUM                   12)
124    (T1_REGNUM                   13)
125    (S0_REGNUM                   23)
127    (FCC0_REGNUM                 64)
128    (FCC1_REGNUM                 65)
129    (FCC2_REGNUM                 66)
130    (FCC3_REGNUM                 67)
131    (FCC4_REGNUM                 68)
132    (FCC5_REGNUM                 69)
133    (FCC6_REGNUM                 70)
134    (FCC7_REGNUM                 71)
136    ;; Return path styles
137    (NORMAL_RETURN               0)
138    (SIBCALL_RETURN              1)
139    (EXCEPTION_RETURN            2)
141    ;; PIC long branch sequences are never longer than 100 bytes.
142    (MAX_PIC_BRANCH_LENGTH       100)
145 (include "predicates.md")
146 (include "constraints.md")
148 ;; ....................
150 ;;      Attributes
152 ;; ....................
154 (define_attr "enabled" "no,yes" (const_string "yes"))
156 (define_attr "got" "unset,load"
157   (const_string "unset"))
159 ;; For jirl instructions, this attribute is DIRECT when the target address
160 ;; is symbolic and INDIRECT when it is a register.
161 (define_attr "jirl" "unset,direct,indirect"
162   (const_string "unset"))
165 ;; Classification of moves, extensions and truncations.  Most values
166 ;; are as for "type" (see below) but there are also the following
167 ;; move-specific values:
169 ;; sll0         "slli.w DEST,SRC,0", which on 64-bit targets is guaranteed
170 ;;              to produce a sign-extended DEST, even if SRC is not
171 ;;              properly sign-extended
172 ;; pick_ins     BSTRPICK.W, BSTRPICK.D, BSTRINS.W or BSTRINS.D instruction
173 ;; andi         a single ANDI instruction
174 ;; shift_shift  a shift left followed by a shift right
176 ;; This attribute is used to determine the instruction's length and
177 ;; scheduling type.  For doubleword moves, the attribute always describes
178 ;; the split instructions; in some cases, it is more appropriate for the
179 ;; scheduling type to be "multi" instead.
180 (define_attr "move_type"
181   "unknown,load,fpload,store,fpstore,mgtf,mftg,imul,move,fmove,
182    const,signext,pick_ins,logical,arith,sll0,andi,shift_shift"
183   (const_string "unknown"))
185 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor,simd_add"
186   (const_string "unknown"))
188 ;; Main data type used by the insn
189 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FCC,
190   V2DI,V4SI,V8HI,V16QI,V2DF,V4SF,V4DI,V8SI,V16HI,V32QI,V4DF,V8SF"
191   (const_string "unknown"))
193 ;; True if the main data type is twice the size of a word.
194 (define_attr "dword_mode" "no,yes"
195   (cond [(and (eq_attr "mode" "DI,DF")
196               (not (match_test "TARGET_64BIT")))
197          (const_string "yes")
199          (and (eq_attr "mode" "TI,TF")
200               (match_test "TARGET_64BIT"))
201          (const_string "yes")]
202         (const_string "no")))
204 ;; True if the main data type is four times of the size of a word.
205 (define_attr "qword_mode" "no,yes"
206   (cond [(and (eq_attr "mode" "TI,TF")
207               (not (match_test "TARGET_64BIT")))
208          (const_string "yes")]
209         (const_string "no")))
211 ;; Classification of each insn.
212 ;; branch       conditional branch
213 ;; jump         unconditional jump
214 ;; call         unconditional call
215 ;; load         load instruction(s)
216 ;; fpload       floating point load
217 ;; fpidxload    floating point indexed load
218 ;; store        store instruction(s)
219 ;; fpstore      floating point store
220 ;; fpidxstore   floating point indexed store
221 ;; prefetch     memory prefetch (register + offset)
222 ;; prefetchx    memory indexed prefetch (register + register)
223 ;; condmove     conditional moves
224 ;; mgtf         move general-purpose register to floating point register
225 ;; mftg         move floating point register to general-purpose register
226 ;; const        load constant
227 ;; arith        integer arithmetic instructions
228 ;; logical      integer logical instructions
229 ;; shift        integer shift instructions
230 ;; slt          set less than instructions
231 ;; signext      sign extend instructions
232 ;; clz          the clz and clo instructions
233 ;; trap         trap if instructions
234 ;; imul         integer multiply
235 ;; idiv         integer divide
236 ;; move         integer move
237 ;; fmove        floating point register move
238 ;; fadd         floating point add/subtract
239 ;; fmul         floating point multiply
240 ;; fmadd        floating point multiply-add
241 ;; fdiv         floating point divide
242 ;; frdiv        floating point reciprocal divide
243 ;; frecipe      floating point approximate reciprocal
244 ;; fabs         floating point absolute value
245 ;; flogb        floating point exponent extract
246 ;; fneg         floating point negation
247 ;; fcmp         floating point compare
248 ;; fcopysign    floating point copysign
249 ;; fcvt         floating point convert
250 ;; fscaleb      floating point scale
251 ;; fsqrt        floating point square root
252 ;; frsqrt       floating point reciprocal square root
253 ;; frsqrte      floating point approximate reciprocal square root
254 ;; multi        multiword sequence (or user asm statements)
255 ;; atomic       atomic memory update instruction
256 ;; syncloop     memory atomic operation implemented as a sync loop
257 ;; nop          no operation
258 ;; ghost        an instruction that produces no real code
259 (define_attr "type"
260   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
261    prefetch,prefetchx,condmove,mgtf,mftg,const,arith,logical,
262    shift,slt,signext,clz,trap,imul,idiv,move,
263    fmove,fadd,fmul,fmadd,fdiv,frdiv,frecipe,fabs,flogb,fneg,fcmp,fcopysign,fcvt,
264    fscaleb,fsqrt,frsqrt,frsqrte,accext,accmod,multi,atomic,syncloop,nop,ghost,
265    simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
266    simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
267    simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
268    simd_permute,simd_shf,simd_sat,simd_pcnt,simd_copy,simd_branch,simd_clsx,
269    simd_fminmax,simd_logic,simd_move,simd_load,simd_store"
270   (cond [(eq_attr "jirl" "!unset") (const_string "call")
271          (eq_attr "got" "load") (const_string "load")
273          (eq_attr "alu_type" "add,sub") (const_string "arith")
275          (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical")
277          ;; If a doubleword move uses these expensive instructions,
278          ;; it is usually better to schedule them in the same way
279          ;; as the singleword form, rather than as "multi".
280          (eq_attr "move_type" "load") (const_string "load")
281          (eq_attr "move_type" "fpload") (const_string "fpload")
282          (eq_attr "move_type" "store") (const_string "store")
283          (eq_attr "move_type" "fpstore") (const_string "fpstore")
284          (eq_attr "move_type" "mgtf") (const_string "mgtf")
285          (eq_attr "move_type" "mftg") (const_string "mftg")
287          ;; These types of move are always single insns.
288          (eq_attr "move_type" "imul") (const_string "imul")
289          (eq_attr "move_type" "fmove") (const_string "fmove")
290          (eq_attr "move_type" "signext") (const_string "signext")
291          (eq_attr "move_type" "pick_ins") (const_string "arith")
292          (eq_attr "move_type" "arith") (const_string "arith")
293          (eq_attr "move_type" "logical") (const_string "logical")
294          (eq_attr "move_type" "sll0") (const_string "shift")
295          (eq_attr "move_type" "andi") (const_string "logical")
297          ;; These types of move are always split.
298          (eq_attr "move_type" "shift_shift")
299            (const_string "multi")
301          ;; These types of move are split for quadword modes only.
302          (and (eq_attr "move_type" "move,const")
303               (eq_attr "qword_mode" "yes"))
304            (const_string "multi")
306          ;; These types of move are split for doubleword modes only.
307          (and (eq_attr "move_type" "move,const")
308               (eq_attr "dword_mode" "yes"))
309            (const_string "multi")
310          (eq_attr "move_type" "move") (const_string "move")
311          (eq_attr "move_type" "const") (const_string "const")]
312         (const_string "unknown")))
314 ;; Mode for conversion types (fcvt)
315 ;; I2S  integer to float single (SI/DI to SF)
316 ;; I2D  integer to float double (SI/DI to DF)
317 ;; S2I  float to integer (SF to SI/DI)
318 ;; D2I  float to integer (DF to SI/DI)
319 ;; D2S  double to float single
320 ;; S2D  float single to double
322 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
323   (const_string "unknown"))
325 ;; The number of individual instructions that a non-branch pattern generates
326 (define_attr "insn_count" ""
327   (cond [;; "Ghost" instructions occupy no space.
328          (eq_attr "type" "ghost")
329          (const_int 0)
331          ;; Check for doubleword moves that are decomposed into two
332          ;; instructions.
333          (and (eq_attr "move_type" "mgtf,mftg,move")
334               (eq_attr "dword_mode" "yes"))
335          (const_int 2)
337          ;; Check for quadword moves that are decomposed into four
338          ;; instructions.
339          (and (eq_attr "move_type" "mgtf,mftg,move")
340               (eq_attr "qword_mode" "yes"))
341          (const_int 4)
343          ;; Constants, loads and stores are handled by external routines.
344          (and (eq_attr "move_type" "const")
345               (eq_attr "dword_mode" "yes"))
346          (symbol_ref "loongarch_split_const_insns (operands[1])")
347          (eq_attr "move_type" "const")
348          (symbol_ref "loongarch_const_insns (operands[1])")
349          (eq_attr "move_type" "load,fpload")
350          (symbol_ref "loongarch_load_store_insns (operands[1], insn)")
351          (eq_attr "move_type" "store,fpstore")
352          (symbol_ref "loongarch_load_store_insns (operands[0], insn)")
354          (eq_attr "type" "idiv")
355          (symbol_ref "loongarch_idiv_insns (GET_MODE (PATTERN (insn)))")]
356 (const_int 1)))
358 ;; Length of instruction in bytes.
359 (define_attr "length" ""
360    (cond [
361           ;; Branch futher than +/- 128 KiB require two instructions.
362           (eq_attr "type" "branch")
363           (if_then_else (and (le (minus (match_dup 0) (pc)) (const_int 131064))
364                              (le (minus (pc) (match_dup 0)) (const_int 131068)))
365           (const_int 4)
366           (const_int 8))]
367     (symbol_ref "get_attr_insn_count (insn) * 4")))
369 ;; Describe a user's asm statement.
370 (define_asm_attributes
371   [(set_attr "type" "multi")])
373 ;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
374 ;; from the same template.
375 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
377 ;; A copy of GPR that can be used when a pattern has two independent
378 ;; modes.
379 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
381 ;; This mode iterator allows 16-bit and 32-bit GPR patterns and 32-bit 64-bit
382 ;; FPR patterns to be generated from the same template.
383 (define_mode_iterator JOIN_MODE [HI
384                                  SI
385                                  (SF "TARGET_HARD_FLOAT")
386                                  (DF "TARGET_DOUBLE_FLOAT")])
388 ;; This mode iterator allows :P to be used for patterns that operate on
389 ;; pointer-sized quantities.  Exactly one of the two alternatives will match.
390 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
392 ;; Likewise, but for GRLEN-sized quantities.
393 (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
395 ;; 64-bit modes for which we provide move patterns.
396 (define_mode_iterator MOVE64 [DI DF])
398 ;; Iterator for sub-32-bit integer modes.
399 (define_mode_iterator SHORT [QI HI])
401 ;; Likewise the 64-bit truncate-and-shift patterns.
402 (define_mode_iterator SUBDI [QI HI SI])
404 ;; Iterator for scalar fixed point modes.
405 (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
407 ;; Iterator for hardware-supported floating-point modes.
408 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
409                             (DF "TARGET_DOUBLE_FLOAT")])
411 ;; Iterator for fixed-point modes which can be hold by a hardware
412 ;; floating-point register.
413 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
414                              (DI "TARGET_DOUBLE_FLOAT")])
416 ;; A mode for anything with 32 bits or more, and able to be loaded with
417 ;; the same addressing mode as ld.w.
418 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
420 ;; A mode for anything able to be stored with the same addressing mode as
421 ;; st.w.
422 (define_mode_iterator ST_ANY [QHWD ANYF])
424 ;; A mode for anything legal as a input of a div or mod instruction.
425 (define_mode_iterator DIV [(DI "TARGET_64BIT")
426                            (SI "!TARGET_64BIT || ISA_HAS_DIV32")])
428 ;; In GPR templates, a string like "mul.<d>" will expand to "mul.w" in the
429 ;; 32-bit version and "mul.d" in the 64-bit version.
430 (define_mode_attr d [(SI "w") (DI "d")])
432 ;; This attribute gives the length suffix for a load or store instruction.
433 ;; The same suffixes work for zero and sign extensions.
434 (define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")])
435 (define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")])
437 ;; This attribute gives the mode mask of a SHORT.
438 (define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
440 ;; This attribute gives the size (bits) of a SHORT.
441 (define_mode_attr 7_or_15 [(QI "7") (HI "15")])
443 ;; Instruction names for stores.
444 (define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
446 ;; This attribute gives the format suffix for floating-point operations.
447 (define_mode_attr fmt [(SF "s") (DF "d")])
448 (define_mode_attr ifmt [(SI "w") (DI "l")])
450 ;; This attribute gives the upper-case mode name for one unit of a
451 ;; floating-point mode or vector mode.
452 (define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF") (V4SF "SF")
453                             (V16QI "QI") (V8HI "HI") (V4SI "SI") (V2DI "DI")
454                             (V2DF "DF")(V8SF "SF")(V32QI "QI")(V16HI "HI")(V8SI "SI")(V4DI "DI")(V4DF "DF")])
456 ;; As above, but in lower case.
457 (define_mode_attr unitmode [(SF "sf") (DF "df") (V2SF "sf") (V4SF "sf")
458                             (V16QI "qi") (V8QI "qi") (V8HI "hi") (V4HI "hi")
459                             (V4SI "si") (V2SI "si") (V2DI "di") (V2DF "df")
460                             (V8SI "si") (V4DI "di") (V32QI "qi") (V16HI "hi")
461                             (V8SF "sf") (V4DF "df")])
463 ;; This attribute gives the integer mode that has half the size of
464 ;; the controlling mode.
465 (define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
466                             (V2SI "SI") (V4HI "SI") (V8QI "SI")
467                             (TF "DI")])
469 ;; This attribute gives the integer mode that has the same size of a
470 ;; floating-point mode.
471 (define_mode_attr IMODE [(SF "SI") (DF "DI")])
473 ;; This code iterator allows signed and unsigned widening multiplications
474 ;; to use the same template.
475 (define_code_iterator any_extend [sign_extend zero_extend])
477 ;; This code iterator allows the two right shift instructions to be
478 ;; generated from the same template.
479 (define_code_iterator any_shiftrt [ashiftrt lshiftrt])
481 ;; This code iterator allows the three shift instructions to be generated
482 ;; from the same template.
483 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
485 ;; This code iterator allows the three bitwise instructions to be generated
486 ;; from the same template.
487 (define_code_iterator any_bitwise [and ior xor])
488 (define_code_iterator any_or [ior xor])
489 (define_code_iterator neg_bitwise [and ior])
490 (define_code_attr bitwise_operand [(and "and_operand")
491                                    (ior "uns_arith_operand")
492                                    (xor "uns_arith_operand")])
493 (define_code_attr is_and [(and "true") (ior "false") (xor "false")])
495 ;; This code iterator allows unsigned and signed division to be generated
496 ;; from the same template.
497 (define_code_iterator any_div [div udiv mod umod])
499 ;; This code iterator allows addition and subtraction to be generated
500 ;; from the same template.
501 (define_code_iterator addsub [plus minus])
503 ;; This code iterator allows addition and multiplication to be generated
504 ;; from the same template.
505 (define_code_iterator addmul [plus mult])
507 ;; This code iterator allows addition subtraction and multiplication to be
508 ;; generated from the same template
509 (define_code_iterator addsubmul [plus minus mult])
511 ;; This code iterator allows all native floating-point comparisons to be
512 ;; generated from the same template.
513 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
514                              ordered ltgt ne ge gt unge ungt])
516 ;; Equality operators.
517 (define_code_iterator equality_op [eq ne])
519 ;; These code iterators allow the signed and unsigned scc operations to use
520 ;; the same template.
521 (define_code_iterator any_gt [gt gtu])
522 (define_code_iterator any_lt [lt ltu])
523 (define_code_iterator any_le [le leu])
525 (define_code_iterator any_return [return simple_return])
527 ;; <u> expands to an empty string when doing a signed operation and
528 ;; "u" when doing an unsigned operation.
529 (define_code_attr u [(sign_extend "") (zero_extend "u")
530                      (div "") (udiv "u")
531                      (mod "") (umod "u")
532                      (gt "") (gtu "u")
533                      (ge "") (geu "u")
534                      (lt "") (ltu "u")
535                      (le "") (leu "u")
536                      (smax "") (umax "u")])
538 ;; <U> is like <u> except uppercase.
539 (define_code_attr U [(sign_extend "") (zero_extend "U")])
541 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
542 (define_code_attr su [(sign_extend "s") (zero_extend "u")
543                       (smax "s") (umax "u")])
545 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
547 ;; <optab> expands to the name of the optab for a particular code.
548 (define_code_attr optab [(ashift "ashl")
549                          (ashiftrt "ashr")
550                          (lshiftrt "lshr")
551                          (rotatert "rotr")
552                          (ior "ior")
553                          (xor "xor")
554                          (and "and")
555                          (plus "add")
556                          (minus "sub")
557                          (mult "mul")
558                          (div "div")
559                          (udiv "udiv")
560                          (mod "mod")
561                          (umod "umod")
562                          (return "return")
563                          (simple_return "simple_return")])
565 ;; <insn> expands to the name of the insn that implements a particular code.
566 (define_code_attr insn [(ashift "sll")
567                         (ashiftrt "sra")
568                         (lshiftrt "srl")
569                         (rotatert "rotr")
570                         (ior "or")
571                         (xor "xor")
572                         (and "and")
573                         (plus "addu")
574                         (minus "subu")
575                         (div "div")
576                         (udiv "div")
577                         (mod "mod")
578                         (umod "mod")])
580 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
581 (define_code_attr fcond [(unordered "cun")
582                          (uneq "cueq")
583                          (unlt "cult")
584                          (unle "cule")
585                          (eq "ceq")
586                          (lt "slt")
587                          (le "sle")
588                          (ordered "cor")
589                          (ltgt "sne")
590                          (ne "cune")
591                          (ge "sge")
592                          (gt "sgt")
593                          (unge "cuge")
594                          (ungt "cugt")])
596 ;; The sel mnemonic to use depending on the condition test.
597 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
598 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
600 ;; Iterator and attributes for floating-point to fixed-point conversion
601 ;; instructions.
602 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
603 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
604                                 (UNSPEC_FTINTRM "lfloor")
605                                 (UNSPEC_FTINTRP "lceil")])
606 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
607                                     (UNSPEC_FTINTRM "rm")
608                                     (UNSPEC_FTINTRP "rp")])
610 ;; Iterator and attributes for bytepick.d
611 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
612 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
613                                              (16 "16")
614                                              (24 "8")])
615 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
616 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
617                                              (16 "48")
618                                              (24 "40")
619                                              (32 "32")
620                                              (40 "24")
621                                              (48 "16")
622                                              (56 "8")])
623 (define_int_attr bytepick_imm [(8 "1")
624                                  (16 "2")
625                                  (24 "3")
626                                  (32 "4")
627                                  (40 "5")
628                                  (48 "6")
629                                  (56 "7")])
631 ;; Expand some 32-bit operations to si3_extend operations if TARGET_64BIT
632 ;; so the redundant sign extension can be removed if the output is used as
633 ;; an input of a bitwise operation.  Note plus, rotl, and div are handled
634 ;; separately.
635 (define_code_iterator shift_w [any_shift rotatert])
636 (define_code_iterator arith_w [minus mult])
638 (define_expand "<optab><mode>3"
639   [(set (match_operand:GPR 0 "register_operand" "=r")
640         (shift_w:GPR (match_operand:GPR 1 "register_operand" "r")
641                      (match_operand:SI 2 "arith_operand" "rI")))]
642   ""
644   if (TARGET_64BIT && <MODE>mode == SImode)
645     {
646       rtx t = gen_reg_rtx (DImode);
647       emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
648       t = gen_lowpart (SImode, t);
649       SUBREG_PROMOTED_VAR_P (t) = 1;
650       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
651       emit_move_insn (operands[0], t);
652       DONE;
653     }
656 (define_expand "<optab><mode>3"
657   [(set (match_operand:GPR 0 "register_operand" "=r")
658         (arith_w:GPR (match_operand:GPR 1 "register_operand" "r")
659                      (match_operand:GPR 2 "register_operand" "r")))]
660   ""
662   if (TARGET_64BIT && <MODE>mode == SImode)
663     {
664       rtx t = gen_reg_rtx (DImode);
665       emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
666       t = gen_lowpart (SImode, t);
667       SUBREG_PROMOTED_VAR_P (t) = 1;
668       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
669       emit_move_insn (operands[0], t);
670       DONE;
671     }
675 ;;  ....................
677 ;;      CONDITIONAL TRAPS
679 ;;  ....................
682 (define_insn "trap"
683   [(trap_if (const_int 1) (const_int 0))]
684   ""
686   return "break\t0";
688   [(set_attr "type" "trap")])
693 ;;  ....................
695 ;;      ADDITION
697 ;;  ....................
700 (define_insn "add<mode>3"
701   [(set (match_operand:ANYF 0 "register_operand" "=f")
702         (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
703                    (match_operand:ANYF 2 "register_operand" "f")))]
704   ""
705   "fadd.<fmt>\t%0,%1,%2"
706   [(set_attr "type" "fadd")
707    (set_attr "mode" "<UNITMODE>")])
709 (define_insn_and_split "*addsi3"
710   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
711         (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
712                   (match_operand:SI 2 "plus_si_operand"
713                                        "r,I,La,Lb,Le")))]
714   ""
715   "@
716    add.w\t%0,%1,%2
717    addi.w\t%0,%1,%2
718    #
719    * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
720      return \"addu16i.d\t%0,%1,%2\";
721    #"
722   "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
723    && !ADDU16I_OPERAND (INTVAL (operands[2]))"
724   [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
725    (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
726   {
727     loongarch_split_plus_constant (&operands[2], SImode);
728   }
729   [(set_attr "alu_type" "add")
730    (set_attr "mode" "SI")
731    (set_attr "insn_count" "1,1,2,1,2")])
733 (define_expand "addsi3"
734   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
735         (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
736                  (match_operand:SI 2 "plus_si_operand"  "r,I,La,Le,Lb")))]
737   "TARGET_64BIT"
739   if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
740       && ADDU16I_OPERAND (INTVAL (operands[2])))
741     {
742       rtx t1 = gen_reg_rtx (DImode);
743       rtx t2 = gen_reg_rtx (DImode);
744       rtx t3 = gen_reg_rtx (DImode);
745       emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
746       t2 = operands[2];
747       emit_insn (gen_adddi3 (t3, t1, t2));
748       t3 = gen_lowpart (SImode, t3);
749       emit_move_insn (operands[0], t3);
750       DONE;
751     }
752   else
753     {
754       rtx t = gen_reg_rtx (DImode);
755       emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
756       t = gen_lowpart (SImode, t);
757       SUBREG_PROMOTED_VAR_P (t) = 1;
758       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
759       emit_move_insn (operands[0], t);
760       DONE;
761     }
764 (define_insn_and_split "adddi3"
765   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
766         (plus:DI (match_operand:DI 1 "register_operand" "r,r,r,r,r,r")
767                   (match_operand:DI 2 "plus_di_operand"
768                                        "r,I,La,Lb,Lc,Ld")))]
769   "TARGET_64BIT"
770   "@
771    add.d\t%0,%1,%2
772    addi.d\t%0,%1,%2
773    #
774    * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
775      return \"addu16i.d\t%0,%1,%2\";
776    #
777    #"
778   "&& CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
779    && !ADDU16I_OPERAND (INTVAL (operands[2]))"
780   [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
781    (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
782   {
783     loongarch_split_plus_constant (&operands[2], DImode);
784   }
785   [(set_attr "alu_type" "add")
786    (set_attr "mode" "DI")
787    (set_attr "insn_count" "1,1,2,1,2,2")])
789 (define_insn_and_split "addsi3_extended"
790   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
791         (sign_extend:DI
792              (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
793                       (match_operand:SI 2 "plus_si_extend_operand"
794                                           "r,I,La,Le"))))]
795   "TARGET_64BIT"
796   "@
797    add.w\t%0,%1,%2
798    addi.w\t%0,%1,%2
799    #
800    #"
801   "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
802   [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
803    (set (match_dup 0)
804         (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
805                                  (match_dup 4))))]
806   {
807     loongarch_split_plus_constant (&operands[2], SImode);
808   }
809   [(set_attr "alu_type" "add")
810    (set_attr "mode" "SI")
811    (set_attr "insn_count" "1,1,2,2")])
815 ;;  ....................
817 ;;      SUBTRACTION
819 ;;  ....................
822 (define_insn "sub<mode>3"
823   [(set (match_operand:ANYF 0 "register_operand" "=f")
824         (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
825                     (match_operand:ANYF 2 "register_operand" "f")))]
826   ""
827   "fsub.<fmt>\t%0,%1,%2"
828   [(set_attr "type" "fadd")
829    (set_attr "mode" "<UNITMODE>")])
831 (define_insn "*sub<mode>3"
832   [(set (match_operand:GPR 0 "register_operand" "=r")
833         (minus:GPR (match_operand:GPR 1 "register_operand" "r")
834                    (match_operand:GPR 2 "register_operand" "r")))]
835   ""
836   "sub.<d>\t%0,%z1,%2"
837   [(set_attr "alu_type" "sub")
838    (set_attr "mode" "<MODE>")])
841 (define_insn "subsi3_extend"
842   [(set (match_operand:DI 0 "register_operand" "=r")
843         (sign_extend:DI
844             (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
845                       (match_operand:SI 2 "register_operand" "r"))))]
846   "TARGET_64BIT"
847   "sub.w\t%0,%z1,%2"
848   [(set_attr "type" "arith")
849    (set_attr "mode" "SI")])
852 ;;  ....................
854 ;;      MULTIPLICATION
856 ;;  ....................
859 (define_insn "mul<mode>3"
860   [(set (match_operand:ANYF 0 "register_operand" "=f")
861         (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
862                    (match_operand:ANYF 2 "register_operand" "f")))]
863   ""
864   "fmul.<fmt>\t%0,%1,%2"
865   [(set_attr "type" "fmul")
866    (set_attr "mode" "<MODE>")])
868 (define_insn "*mul<mode>3"
869   [(set (match_operand:GPR 0 "register_operand" "=r")
870         (mult:GPR (match_operand:GPR 1 "register_operand" "r")
871                   (match_operand:GPR 2 "register_operand" "r")))]
872   ""
873   "mul.<d>\t%0,%1,%2"
874   [(set_attr "type" "imul")
875    (set_attr "mode" "<MODE>")])
877 (define_insn "mulsi3_extend"
878   [(set (match_operand:DI 0 "register_operand" "=r")
879         (sign_extend:DI
880             (mult:SI (match_operand:SI 1 "register_operand" "r")
881                      (match_operand:SI 2 "register_operand" "r"))))]
882   "TARGET_64BIT"
883   "mul.w\t%0,%1,%2"
884   [(set_attr "type" "imul")
885    (set_attr "mode" "SI")])
888 ;;  ........................
890 ;;      MULTIPLICATION HIGH-PART
892 ;;  ........................
895 (define_expand "<u>mulditi3"
896   [(set (match_operand:TI 0 "register_operand")
897         (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
898                  (any_extend:TI (match_operand:DI 2 "register_operand"))))]
899   "TARGET_64BIT"
901   rtx low = gen_reg_rtx (DImode);
902   emit_insn (gen_muldi3 (low, operands[1], operands[2]));
904   rtx high = gen_reg_rtx (DImode);
905   emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
907   emit_move_insn (gen_lowpart (DImode, operands[0]), low);
908   emit_move_insn (gen_highpart (DImode, operands[0]), high);
909   DONE;
912 (define_insn "<su>muldi3_highpart"
913   [(set (match_operand:DI 0 "register_operand" "=r")
914         (truncate:DI
915           (lshiftrt:TI
916             (mult:TI (any_extend:TI
917                        (match_operand:DI 1 "register_operand" " r"))
918                      (any_extend:TI
919                        (match_operand:DI 2 "register_operand" " r")))
920             (const_int 64))))]
921   "TARGET_64BIT"
922   "mulh.d<u>\t%0,%1,%2"
923   [(set_attr "type" "imul")
924    (set_attr "mode" "DI")])
926 (define_expand "<u>mulsidi3"
927   [(set (match_operand:DI 0 "register_operand")
928         (mult:DI (any_extend:DI
929                    (match_operand:SI 1 "register_operand"))
930                  (any_extend:DI
931                    (match_operand:SI 2 "register_operand"))))]
932   ""
934   if (!TARGET_64BIT)
935   {
936     rtx temp = gen_reg_rtx (SImode);
937     emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
938     emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
939                                        operands[1], operands[2]));
940     emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
941     DONE;
942   }
945 (define_insn "<u>mulsidi3_64bit"
946   [(set (match_operand:DI 0 "register_operand" "=r")
947         (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
948                  (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
949   "TARGET_64BIT"
950   "mulw.d.w<u>\t%0,%1,%2"
951   [(set_attr "type" "imul")
952    (set_attr "mode" "DI")])
954 (define_insn "<su>mulsi3_highpart"
955   [(set (match_operand:SI 0 "register_operand" "=r")
956         (truncate:SI
957           (lshiftrt:DI
958             (mult:DI (any_extend:DI
959                        (match_operand:SI 1 "register_operand" " r"))
960                      (any_extend:DI
961                        (match_operand:SI 2 "register_operand" " r")))
962             (const_int 32))))]
963   ""
964   "mulh.w<u>\t%0,%1,%2"
965   [(set_attr "type" "imul")
966    (set_attr "mode" "SI")])
968 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
969 ;; sign extension by default, so the sign extension instruction can be
970 ;; eliminated.
971 (define_peephole
972   [(set (match_operand:SI 0 "register_operand")
973         (truncate:SI
974           (lshiftrt:DI
975             (mult:DI (any_extend:DI
976                        (match_operand:SI 1 "register_operand"))
977                      (any_extend:DI
978                        (match_operand:SI 2 "register_operand")))
979             (const_int 32))))
980    (set (match_operand:DI 3 "register_operand")
981         (sign_extend:DI (match_dup 0)))]
982    "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
983    "mulh.w<u>\t%0,%1,%2")
986 ;;  ....................
988 ;;      DIVISION and REMAINDER
990 ;;  ....................
993 ;; Float division and modulus.
994 (define_expand "div<mode>3"
995   [(set (match_operand:ANYF 0 "register_operand")
996     (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
997               (match_operand:ANYF 2 "register_operand")))]
998   ""
1000   if (<MODE>mode == SFmode
1001     && TARGET_RECIP_DIV
1002     && optimize_insn_for_speed_p ()
1003     && flag_finite_math_only && !flag_trapping_math
1004     && flag_unsafe_math_optimizations)
1005   {
1006     loongarch_emit_swdivsf (operands[0], operands[1],
1007         operands[2], SFmode);
1008     DONE;
1009   }
1012 (define_insn "*div<mode>3"
1013   [(set (match_operand:ANYF 0 "register_operand" "=f")
1014         (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
1015                   (match_operand:ANYF 2 "register_operand" "f")))]
1016   ""
1017   "fdiv.<fmt>\t%0,%1,%2"
1018   [(set_attr "type" "fdiv")
1019    (set_attr "mode" "<UNITMODE>")])
1021 ;; In 3A5000, the reciprocal operation is the same as the division operation.
1023 (define_insn "*recip<mode>3"
1024   [(set (match_operand:ANYF 0 "register_operand" "=f")
1025         (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
1026                   (match_operand:ANYF 2 "register_operand" "f")))]
1027   ""
1028   "frecip.<fmt>\t%0,%2"
1029   [(set_attr "type" "frdiv")
1030    (set_attr "mode" "<UNITMODE>")])
1032 ;; Approximate Reciprocal Instructions.
1034 (define_insn "loongarch_frecipe_<fmt>"
1035   [(set (match_operand:ANYF 0 "register_operand" "=f")
1036     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1037              UNSPEC_RECIPE))]
1038   "ISA_HAS_FRECIPE"
1039   "frecipe.<fmt>\t%0,%1"
1040   [(set_attr "type" "frecipe")
1041    (set_attr "mode" "<UNITMODE>")
1042    (set_attr "insn_count" "1")])
1044 ;; Integer division and modulus.
1045 (define_expand "<optab><mode>3"
1046   [(set (match_operand:GPR 0 "register_operand")
1047         (any_div:GPR (match_operand:GPR 1 "register_operand")
1048                      (match_operand:GPR 2 "register_operand")))]
1049   ""
1051  if (GET_MODE (operands[0]) == SImode && TARGET_64BIT)
1052   {
1053     if (ISA_HAS_DIV32)
1054       {
1055         rtx t = gen_reg_rtx (DImode);
1056         emit_insn (gen_<optab>si3_extended (t, operands[1], operands[2]));
1057         t = gen_lowpart (SImode, t);
1058         SUBREG_PROMOTED_VAR_P (t) = 1;
1059         SUBREG_PROMOTED_SET (t, SRP_SIGNED);
1060         emit_move_insn (operands[0], t);
1061         DONE;
1062       }
1064     rtx reg1 = gen_reg_rtx (DImode);
1065     rtx reg2 = gen_reg_rtx (DImode);
1066     rtx rd = gen_reg_rtx (DImode);
1068     operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
1069     operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
1071     emit_insn (gen_rtx_SET (reg1, operands[1]));
1072     emit_insn (gen_rtx_SET (reg2, operands[2]));
1074     emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
1075     emit_insn (gen_rtx_SET (operands[0],
1076                             simplify_gen_subreg (SImode, rd, DImode, 0)));
1077     DONE;
1078   }
1081 (define_insn "*<optab><mode>3"
1082   [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
1083         (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
1084                      (match_operand:DIV 2 "register_operand" "r,r,r")))]
1085   ""
1087   return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
1089   [(set_attr "type" "idiv")
1090    (set_attr "mode" "<MODE>")
1091    (set (attr "enabled")
1092       (if_then_else
1093         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1094         (const_string "yes")
1095         (const_string "no")))])
1097 (define_insn "<optab>si3_extended"
1098   [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1099         (sign_extend:DI
1100           (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
1101                       (match_operand:SI 2 "register_operand" "r,r,r"))))]
1102   "TARGET_64BIT && ISA_HAS_DIV32"
1104   return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1106   [(set_attr "type" "idiv")
1107    (set_attr "mode" "SI")
1108    (set (attr "enabled")
1109       (if_then_else
1110         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1111         (const_string "yes")
1112         (const_string "no")))])
1114 (define_insn "<optab>di3_fake"
1115   [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1116         (sign_extend:DI
1117           (unspec:SI
1118            [(subreg:SI
1119              (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1120                          (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1121           UNSPEC_FAKE_ANY_DIV)))]
1122   "TARGET_64BIT && !ISA_HAS_DIV32"
1124   return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1126   [(set_attr "type" "idiv")
1127    (set_attr "mode" "SI")
1128    (set (attr "enabled")
1129       (if_then_else
1130         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1131         (const_string "yes")
1132         (const_string "no")))])
1134 ;; Floating point multiply accumulate instructions.
1136 ;; a * b + c
1137 (define_insn "fma<mode>4"
1138   [(set (match_operand:ANYF 0 "register_operand" "=f")
1139         (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1140                   (match_operand:ANYF 2 "register_operand" "f")
1141                   (match_operand:ANYF 3 "register_operand" "f")))]
1142   ""
1143   "fmadd.<fmt>\t%0,%1,%2,%3"
1144   [(set_attr "type" "fmadd")
1145    (set_attr "mode" "<UNITMODE>")])
1147 ;; a * b - c
1148 (define_insn "fms<mode>4"
1149   [(set (match_operand:ANYF 0 "register_operand" "=f")
1150         (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1151                   (match_operand:ANYF 2 "register_operand" "f")
1152                   (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1153   ""
1154   "fmsub.<fmt>\t%0,%1,%2,%3"
1155   [(set_attr "type" "fmadd")
1156    (set_attr "mode" "<UNITMODE>")])
1158 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1159 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1160 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1161 ;; This transformation means we may return the wrong signed zero
1162 ;; so we check HONOR_SIGNED_ZEROS.
1164 ;; -a * b + c
1165 (define_insn "fnma<mode>4"
1166   [(set (match_operand:ANYF 0 "register_operand" "=f")
1167         (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1168                   (match_operand:ANYF 2 "register_operand" "f")
1169                   (match_operand:ANYF 3 "register_operand" "f")))]
1170   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1171   "fnmsub.<fmt>\t%0,%1,%2,%3"
1172   [(set_attr "type" "fmadd")
1173    (set_attr "mode" "<UNITMODE>")])
1175 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1176 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1177 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1178 ;; This transformation means we may return the wrong signed zero
1179 ;; so we check HONOR_SIGNED_ZEROS.
1181 ;; -a * b - c
1182 (define_insn "fnms<mode>4"
1183   [(set (match_operand:ANYF 0 "register_operand" "=f")
1184         (fma:ANYF
1185             (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1186             (match_operand:ANYF 2 "register_operand" "f")
1187             (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1188   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1189   "fnmadd.<fmt>\t%0,%1,%2,%3"
1190   [(set_attr "type" "fmadd")
1191    (set_attr "mode" "<UNITMODE>")])
1193 ;; -(-a * b - c), modulo signed zeros
1194 (define_insn "*fma<mode>4"
1195   [(set (match_operand:ANYF 0 "register_operand" "=f")
1196         (neg:ANYF
1197             (fma:ANYF
1198                 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1199                 (match_operand:ANYF 2 "register_operand" " f")
1200                 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1201   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1202   "fmadd.<fmt>\t%0,%1,%2,%3"
1203   [(set_attr "type" "fmadd")
1204    (set_attr "mode" "<UNITMODE>")])
1206 ;; -(-a * b + c), modulo signed zeros
1207 (define_insn "*fms<mode>4"
1208   [(set (match_operand:ANYF 0 "register_operand" "=f")
1209         (neg:ANYF
1210             (fma:ANYF
1211                 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1212                 (match_operand:ANYF 2 "register_operand" " f")
1213                 (match_operand:ANYF 3 "register_operand" " f"))))]
1214   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1215   "fmsub.<fmt>\t%0,%1,%2,%3"
1216   [(set_attr "type" "fmadd")
1217    (set_attr "mode" "<UNITMODE>")])
1219 ;; -(a * b + c)
1220 (define_insn "*fnms<mode>4"
1221   [(set (match_operand:ANYF 0 "register_operand" "=f")
1222         (neg:ANYF
1223             (fma:ANYF
1224                 (match_operand:ANYF 1 "register_operand" " f")
1225                 (match_operand:ANYF 2 "register_operand" " f")
1226                 (match_operand:ANYF 3 "register_operand" " f"))))]
1227   ""
1228   "fnmadd.<fmt>\t%0,%1,%2,%3"
1229   [(set_attr "type" "fmadd")
1230    (set_attr "mode" "<UNITMODE>")])
1232 ;; -(a * b - c)
1233 (define_insn "*fnma<mode>4"
1234   [(set (match_operand:ANYF 0 "register_operand" "=f")
1235         (neg:ANYF
1236             (fma:ANYF
1237                 (match_operand:ANYF 1 "register_operand" " f")
1238                 (match_operand:ANYF 2 "register_operand" " f")
1239                 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1240   ""
1241   "fnmsub.<fmt>\t%0,%1,%2,%3"
1242   [(set_attr "type" "fmadd")
1243    (set_attr "mode" "<UNITMODE>")])
1246 ;;  ....................
1248 ;;      SQUARE ROOT
1250 ;;  ....................
1252 (define_expand "sqrt<mode>2"
1253   [(set (match_operand:ANYF 0 "register_operand")
1254     (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1255   ""
1257   if (<MODE>mode == SFmode
1258       && TARGET_RECIP_SQRT
1259       && flag_unsafe_math_optimizations
1260       && !optimize_insn_for_size_p ()
1261       && flag_finite_math_only && !flag_trapping_math)
1262     {
1263       loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1264       DONE;
1265     }
1266  })
1268 (define_insn "*sqrt<mode>2"
1269   [(set (match_operand:ANYF 0 "register_operand" "=f")
1270         (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1271   ""
1272   "fsqrt.<fmt>\t%0,%1"
1273   [(set_attr "type" "fsqrt")
1274    (set_attr "mode" "<UNITMODE>")
1275    (set_attr "insn_count" "1")])
1277 (define_expand "rsqrt<mode>2"
1278   [(set (match_operand:ANYF 0 "register_operand")
1279     (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1280            UNSPEC_RSQRT))]
1281   "TARGET_HARD_FLOAT"
1283    if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1284      {
1285        loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1286        DONE;
1287      }
1290 (define_insn "*rsqrt<mode>2"
1291   [(set (match_operand:ANYF 0 "register_operand" "=f")
1292     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1293              UNSPEC_RSQRT))]
1294   "TARGET_HARD_FLOAT"
1295   "frsqrt.<fmt>\t%0,%1"
1296   [(set_attr "type" "frsqrt")
1297    (set_attr "mode" "<UNITMODE>")])
1299 ;; Approximate Reciprocal Square Root Instructions.
1301 (define_insn "loongarch_frsqrte_<fmt>"
1302   [(set (match_operand:ANYF 0 "register_operand" "=f")
1303     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1304                  UNSPEC_RSQRTE))]
1305   "ISA_HAS_FRECIPE"
1306   "frsqrte.<fmt>\t%0,%1"
1307   [(set_attr "type" "frsqrte")
1308    (set_attr "mode" "<UNITMODE>")])
1311 ;;  ....................
1313 ;;      ABSOLUTE VALUE
1315 ;;  ....................
1317 (define_insn "abs<mode>2"
1318   [(set (match_operand:ANYF 0 "register_operand" "=f")
1319         (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1320   ""
1321   "fabs.<fmt>\t%0,%1"
1322   [(set_attr "type" "fabs")
1323    (set_attr "mode" "<UNITMODE>")])
1326 ;;  ....................
1328 ;;      FLOATING POINT COPYSIGN
1330 ;;  ....................
1332 (define_insn "copysign<mode>3"
1333   [(set (match_operand:ANYF 0 "register_operand" "=f")
1334         (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1335                        (match_operand:ANYF 2 "register_operand" "f")))]
1336   "TARGET_HARD_FLOAT"
1337   "fcopysign.<fmt>\t%0,%1,%2"
1338   [(set_attr "type" "fcopysign")
1339    (set_attr "mode" "<UNITMODE>")])
1341 (define_expand "@xorsign<mode>3"
1342   [(match_operand:ANYF 0 "register_operand")
1343    (match_operand:ANYF 1 "register_operand")
1344    (match_operand:ANYF 2 "register_operand")]
1345   "ISA_HAS_LSX"
1347   machine_mode lsx_mode
1348     = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1349   rtx tmp = gen_reg_rtx (lsx_mode);
1350   rtx op1 = force_lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1351   rtx op2 = force_lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1352   emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1353   emit_move_insn (operands[0],
1354           lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1355   DONE;
1359 ;;  ....................
1361 ;;      FLOATING POINT SCALE
1363 ;;  ....................
1365 (define_insn "ldexp<mode>3"
1366   [(set (match_operand:ANYF 0 "register_operand" "=f")
1367         (unspec:ANYF [(match_operand:ANYF    1 "register_operand" "f")
1368                       (match_operand:<IMODE> 2 "register_operand" "f")]
1369                      UNSPEC_FSCALEB))]
1370   "TARGET_HARD_FLOAT"
1371   "fscaleb.<fmt>\t%0,%1,%2"
1372   [(set_attr "type" "fscaleb")
1373    (set_attr "mode" "<UNITMODE>")])
1376 ;;  ....................
1378 ;;      FLOATING POINT EXPONENT EXTRACT
1380 ;;  ....................
1382 (define_insn "logb_non_negative<mode>2"
1383   [(set (match_operand:ANYF 0 "register_operand" "=f")
1384         (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1385                      UNSPEC_FLOGB))]
1386   "TARGET_HARD_FLOAT"
1387   "flogb.<fmt>\t%0,%1"
1388   [(set_attr "type" "flogb")
1389    (set_attr "mode" "<UNITMODE>")])
1391 (define_expand "logb<mode>2"
1392   [(set (match_operand:ANYF 0 "register_operand")
1393         (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1394                      UNSPEC_FLOGB))]
1395   "TARGET_HARD_FLOAT"
1397   rtx tmp = gen_reg_rtx (<MODE>mode);
1399   emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1400   emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1401   DONE;
1405 ;;  ...................
1407 ;;  Count leading zeroes.
1409 ;;  ...................
1412 (define_insn "clz<mode>2"
1413   [(set (match_operand:GPR 0 "register_operand" "=r")
1414         (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1415   ""
1416   "clz.<d>\t%0,%1"
1417   [(set_attr "type" "clz")
1418    (set_attr "mode" "<MODE>")])
1421 ;;  ...................
1423 ;;  Count trailing zeroes.
1425 ;;  ...................
1428 (define_insn "ctz<mode>2"
1429   [(set (match_operand:GPR 0 "register_operand" "=r")
1430         (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1431   ""
1432   "ctz.<d>\t%0,%1"
1433   [(set_attr "type" "clz")
1434    (set_attr "mode" "<MODE>")])
1437 ;;  ....................
1439 ;;      MIN/MAX
1441 ;;  ....................
1443 (define_insn "smax<mode>3"
1444   [(set (match_operand:ANYF 0 "register_operand" "=f")
1445         (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1446                    (match_operand:ANYF 2 "register_operand" "f")))]
1447   ""
1448   "fmax.<fmt>\t%0,%1,%2"
1449   [(set_attr "type" "fmove")
1450    (set_attr "mode" "<MODE>")])
1452 (define_insn "smin<mode>3"
1453   [(set (match_operand:ANYF 0 "register_operand" "=f")
1454         (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1455                    (match_operand:ANYF 2 "register_operand" "f")))]
1456   ""
1457   "fmin.<fmt>\t%0,%1,%2"
1458   [(set_attr "type" "fmove")
1459    (set_attr "mode" "<MODE>")])
1461 (define_insn "fmax<mode>3"
1462   [(set (match_operand:ANYF 0 "register_operand" "=f")
1463         (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1464                       (use (match_operand:ANYF 2 "register_operand" "f"))]
1465                      UNSPEC_FMAX))]
1466   ""
1467   "fmax.<fmt>\t%0,%1,%2"
1468   [(set_attr "type" "fmove")
1469    (set_attr "mode" "<MODE>")])
1471 (define_insn "fmin<mode>3"
1472   [(set (match_operand:ANYF 0 "register_operand" "=f")
1473         (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1474                       (use (match_operand:ANYF 2 "register_operand" "f"))]
1475                      UNSPEC_FMIN))]
1476   ""
1477   "fmin.<fmt>\t%0,%1,%2"
1478   [(set_attr "type" "fmove")
1479    (set_attr "mode" "<MODE>")])
1481 (define_insn "smaxa<mode>3"
1482   [(set (match_operand:ANYF 0 "register_operand" "=f")
1483         (if_then_else:ANYF
1484               (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1485                   (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1486               (match_dup 1)
1487               (match_dup 2)))]
1488   ""
1489   "fmaxa.<fmt>\t%0,%1,%2"
1490   [(set_attr "type" "fmove")
1491    (set_attr "mode" "<MODE>")])
1493 (define_insn "smina<mode>3"
1494   [(set (match_operand:ANYF 0 "register_operand" "=f")
1495         (if_then_else:ANYF
1496                 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1497                     (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1498                 (match_dup 1)
1499                 (match_dup 2)))]
1500   ""
1501   "fmina.<fmt>\t%0,%1,%2"
1502   [(set_attr "type" "fmove")
1503    (set_attr "mode" "<MODE>")])
1506 ;;  ....................
1508 ;;      NEGATION and ONE'S COMPLEMENT
1510 ;;  ....................
1512 (define_insn "neg<mode>2"
1513   [(set (match_operand:GPR 0 "register_operand" "=r")
1514         (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1515   ""
1516   "sub.<d>\t%0,%.,%1"
1517   [(set_attr "alu_type" "sub")
1518    (set_attr "mode" "<MODE>")])
1520 (define_insn "*negsi2_extended"
1521   [(set (match_operand:DI 0 "register_operand" "=r")
1522         (sign_extend:DI (neg:SI (match_operand:SI 1 "register_operand" "r"))))]
1523   "TARGET_64BIT"
1524   "sub.w\t%0,%.,%1"
1525   [(set_attr "alu_type" "sub")
1526    (set_attr "mode" "SI")])
1528 (define_insn "neg<mode>2"
1529   [(set (match_operand:ANYF 0 "register_operand" "=f")
1530         (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1531   ""
1532   "fneg.<fmt>\t%0,%1"
1533   [(set_attr "type" "fneg")
1534    (set_attr "mode" "<UNITMODE>")])
1538 ;;  ....................
1540 ;;      LOGICAL
1542 ;;  ....................
1545 (define_insn "*<optab><mode>3"
1546   [(set (match_operand:GPR 0 "register_operand" "=r,r")
1547         (any_or:GPR (match_operand:GPR 1 "register_operand" "%r,r")
1548                     (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
1549   ""
1550   "<insn>%i2\t%0,%1,%2"
1551   [(set_attr "type" "logical")
1552    (set_attr "mode" "<MODE>")])
1554 (define_insn "*and<mode>3"
1555   [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r")
1556         (and:GPR (match_operand:GPR 1 "register_operand" "%r,r,r,0")
1557                  (match_operand:GPR 2 "and_operand" "r,K,Yx,Yy")))]
1558   ""
1559   "@
1560    and\t%0,%1,%2
1561    andi\t%0,%1,%2
1562    * operands[2] = GEN_INT (INTVAL (operands[2]) \
1563                             & GET_MODE_MASK (<MODE>mode)); \
1564      return \"bstrpick.<d>\t%0,%1,%M2\";
1565    * operands[2] = GEN_INT (~INTVAL (operands[2]) \
1566                             & GET_MODE_MASK (<MODE>mode)); \
1567      return \"bstrins.<d>\t%0,%.,%M2\";"
1568   [(set_attr "move_type" "logical,logical,pick_ins,pick_ins")
1569    (set_attr "mode" "<MODE>")])
1571 (define_expand "<optab><mode>3"
1572   [(set (match_operand:X 0 "register_operand")
1573         (any_bitwise:X (match_operand:X 1 "register_operand")
1574                        (match_operand:X 2 "<bitwise_operand>")))]
1575   "")
1577 (define_insn "one_cmpl<mode>2"
1578   [(set (match_operand:X 0 "register_operand" "=r")
1579         (not:X (match_operand:X 1 "register_operand" "r")))]
1580   ""
1581   "nor\t%0,%.,%1"
1582   [(set_attr "alu_type" "not")
1583    (set_attr "mode" "<MODE>")])
1585 (define_insn "*one_cmplsi2_internal"
1586   [(set (match_operand:SI 0 "register_operand" "=r")
1587         (not:SI (match_operand:SI 1 "register_operand" " r")))]
1588   "TARGET_64BIT"
1589   "nor\t%0,%.,%1"
1590   [(set_attr "type" "logical")
1591    (set_attr "mode" "SI")])
1593 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1594   [(set (match_operand:GPR 0 "register_operand" "=r")
1595         (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand" "r")
1596                           (match_operand:GPR 2 "const_int_operand" "i"))
1597                  (and:GPR (match_operand:GPR 3 "register_operand" "r")
1598                           (match_operand:GPR 4 "const_int_operand" "i"))))]
1599   "loongarch_pre_reload_split ()
1600    && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1601   "#"
1602   "&& true"
1603   [(set (match_dup 0) (match_dup 1))
1604    (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1605         (match_dup 3))]
1606   {
1607     if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1608       {
1609         std::swap (operands[1], operands[3]);
1610         std::swap (operands[2], operands[4]);
1611       }
1613     unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1614     int lo = ffs_hwi (mask) - 1;
1615     int len = low_bitmask_len (<MODE>mode, mask >> lo);
1617     len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1618     operands[2] = GEN_INT (len);
1619     operands[4] = GEN_INT (lo);
1621     if (lo)
1622       {
1623         rtx tmp = gen_reg_rtx (<MODE>mode);
1624         emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1625                                               GEN_INT (lo)));
1626         operands[3] = tmp;
1627       }
1628   })
1630 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1631 ;; if possible, but the result may be sub-optimal when one of the masks
1632 ;; is (1 << N) - 1 and one of the src register is the dest register.
1633 ;; For example:
1634 ;;     move             t0, a0
1635 ;;     move             a0, a1
1636 ;;     bstrins.d        a0, t0, 42, 0
1637 ;;     ret
1638 ;; using a shift operation would be better:
1639 ;;     srai.d           t0, a1, 43
1640 ;;     bstrins.d        a0, t0, 63, 43
1641 ;;     ret
1642 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1643 ;; know if the dest register is one of the src register.  Fix it up in
1644 ;; peephole2.
1645 (define_peephole2
1646   [(set (match_operand:GPR 0 "register_operand")
1647         (match_operand:GPR 1 "register_operand"))
1648    (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1649    (set (zero_extract:GPR (match_dup 1)
1650                           (match_operand:SI 3 "const_int_operand")
1651                           (const_int 0))
1652         (match_dup 0))]
1653   "peep2_reg_dead_p (3, operands[0])"
1654   [(const_int 0)]
1655   {
1656     int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1658     emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1659     emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1660                                operands[0]));
1661     DONE;
1662   })
1664 (define_insn "*iorhi3"
1665   [(set (match_operand:HI 0 "register_operand" "=r,r")
1666         (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1667                 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1668   ""
1669   "or%i2\t%0,%1,%2"
1670   [(set_attr "type" "logical")
1671    (set_attr "mode" "HI")])
1673 (define_insn "nor<mode>3"
1674   [(set (match_operand:X 0 "register_operand" "=r")
1675         (and:X (not:X (match_operand:X 1 "register_operand" "%r"))
1676                  (not:X (match_operand:X 2 "register_operand" "r"))))]
1677   ""
1678   "nor\t%0,%1,%2"
1679   [(set_attr "type" "logical")
1680    (set_attr "mode" "<MODE>")])
1682 (define_insn "*norsi3_internal"
1683   [(set (match_operand:SI 0 "register_operand" "=r")
1684         (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
1685                  (not:SI (match_operand:SI 2 "register_operand" "r"))))]
1686   "TARGET_64BIT"
1687   "nor\t%0,%1,%2"
1688   [(set_attr "type" "logical")
1689    (set_attr "mode" "SI")])
1691 (define_insn "<optab>n<mode>3"
1692   [(set (match_operand:X 0 "register_operand" "=r")
1693         (neg_bitwise:X
1694             (not:X (match_operand:X 2 "register_operand" "r"))
1695             (match_operand:X 1 "register_operand" "r")))]
1696   ""
1697   "<insn>n\t%0,%1,%2"
1698   [(set_attr "type" "logical")
1699    (set_attr "mode" "<MODE>")])
1701 (define_insn "*<optab>nsi_internal"
1702   [(set (match_operand:SI 0 "register_operand" "=r")
1703         (neg_bitwise:SI
1704             (not:SI (match_operand:SI 1 "register_operand" "r"))
1705             (match_operand:SI 2 "register_operand" "r")))]
1706   "TARGET_64BIT"
1707   "<insn>n\t%0,%2,%1"
1708   [(set_attr "type" "logical")
1709    (set_attr "mode" "SI")])
1712 ;;  ....................
1714 ;;      TRUNCATION
1716 ;;  ....................
1718 (define_insn "truncdfsf2"
1719   [(set (match_operand:SF 0 "register_operand" "=f")
1720         (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1721   "TARGET_DOUBLE_FLOAT"
1722   "fcvt.s.d\t%0,%1"
1723   [(set_attr "type" "fcvt")
1724    (set_attr "cnv_mode" "D2S")
1725    (set_attr "mode" "SF")])
1727 ;; In vector registers, popcount can be implemented directly through
1728 ;; the vector instruction [X]VPCNT.  For GP registers, we can implement
1729 ;; it through the following method.  Compared with loop implementation
1730 ;; of popcount, the following method has better performance.
1732 ;; This attribute used for get connection of scalar mode and corresponding
1733 ;; vector mode.
1734 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1736 (define_expand "popcount<mode>2"
1737   [(set (match_operand:GPR 0 "register_operand")
1738         (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1739   "ISA_HAS_LSX"
1741   rtx in = operands[1];
1742   rtx out = operands[0];
1743   rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1744                                     gen_reg_rtx (V2DImode);
1745   emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1746   emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1747   emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1748   DONE;
1752 ;;  ....................
1754 ;;      ZERO EXTENSION
1756 ;;  ....................
1757 (define_expand "zero_extendsidi2"
1758   [(set (match_operand:DI 0 "register_operand")
1759         (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1760   "TARGET_64BIT")
1762 (define_insn_and_split "*zero_extendsidi2_internal"
1763   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1764         (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1765   "TARGET_64BIT"
1766   "@
1767    bstrpick.d\t%0,%1,31,0
1768    ld.wu\t%0,%1
1769    #
1770    ldx.wu\t%0,%1"
1771   "&& reload_completed
1772    && MEM_P (operands[1])
1773    && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1774        && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1775    && !paradoxical_subreg_p (operands[0])"
1776   [(set (match_dup 3) (match_dup 1))
1777    (set (match_dup 0)
1778         (ior:DI (zero_extend:DI
1779                   (subreg:SI (match_dup 0) 0))
1780                 (match_dup 2)))]
1781   {
1782     operands[1] = gen_lowpart (SImode, operands[1]);
1783     operands[3] = gen_lowpart (SImode, operands[0]);
1784     operands[2] = const0_rtx;
1785   }
1786   [(set_attr "move_type" "arith,load,load,load")
1787    (set_attr "mode" "DI")])
1789 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1790   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1791         (zero_extend:GPR
1792              (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1793   ""
1794   "@
1795    bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1796    ld.<SHORT:size>u\t%0,%1
1797    ldx.<SHORT:size>u\t%0,%1"
1798   [(set_attr "move_type" "pick_ins,load,load")
1799    (set_attr "mode" "<GPR:MODE>")])
1801 (define_insn "zero_extendqihi2"
1802   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1803         (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1804   ""
1805   "@
1806    andi\t%0,%1,0xff
1807    ldx.bu\t%0,%1
1808    ld.bu\t%0,%1"
1809   [(set_attr "move_type" "andi,load,load")
1810    (set_attr "mode" "HI")])
1812 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1814 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1815   [(set (match_operand:GPR 0 "register_operand" "=r")
1816         (zero_extend:GPR
1817             (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1818   "TARGET_64BIT"
1819   "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1820   [(set_attr "move_type" "pick_ins")
1821    (set_attr "mode" "<GPR:MODE>")])
1823 (define_insn "*zero_extendhi_truncqi"
1824   [(set (match_operand:HI 0 "register_operand" "=r")
1825         (zero_extend:HI
1826             (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1827   "TARGET_64BIT"
1828   "andi\t%0,%1,0xff"
1829   [(set_attr "alu_type" "and")
1830    (set_attr "mode" "HI")])
1833 ;;  ....................
1835 ;;      SIGN EXTENSION
1837 ;;  ....................
1839 (define_insn "extendsidi2"
1840   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
1841         (sign_extend:DI
1842             (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k,f")))]
1843   "TARGET_64BIT"
1844   "@
1845    slli.w\t%0,%1,0
1846    ldptr.w\t%0,%1
1847    ld.w\t%0,%1
1848    ldx.w\t%0,%1
1849    movfr2gr.s\t%0,%1"
1850   [(set_attr "move_type" "sll0,load,load,load,mftg")
1851    (set_attr "mode" "DI")])
1853 (define_insn "extend<SHORT:mode><GPR:mode>2"
1854   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1855         (sign_extend:GPR
1856              (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1857   ""
1858   "@
1859    ext.w.<SHORT:size>\t%0,%1
1860    ld.<SHORT:size>\t%0,%1
1861    ldx.<SHORT:size>\t%0,%1"
1862   [(set_attr "move_type" "signext,load,load")
1863    (set_attr "mode" "<GPR:MODE>")])
1865 (define_insn "extendqihi2"
1866   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1867         (sign_extend:HI
1868              (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1869   ""
1870   "@
1871    ext.w.b\t%0,%1
1872    ld.b\t%0,%1
1873    ldx.b\t%0,%1"
1874   [(set_attr "move_type" "signext,load,load")
1875    (set_attr "mode" "SI")])
1877 (define_insn "extendsfdf2"
1878   [(set (match_operand:DF 0 "register_operand" "=f")
1879         (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1880   "TARGET_DOUBLE_FLOAT"
1881   "fcvt.d.s\t%0,%1"
1882   [(set_attr "type" "fcvt")
1883    (set_attr "cnv_mode" "S2D")
1884    (set_attr "mode" "DF")])
1887 ;;  ....................
1889 ;;      CONVERSIONS
1891 ;;  ....................
1893 ;; conversion of a floating-point value to a integer
1895 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1896   [(set (match_operand:GPR 0 "register_operand" "=f")
1897         (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1898   ""
1899   "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1900   [(set_attr "type" "fcvt")
1901    (set_attr "mode" "<ANYF:MODE>")])
1903 ;; conversion of an integeral (or boolean) value to a floating-point value
1905 (define_insn "floatsidf2"
1906   [(set (match_operand:DF 0 "register_operand" "=f")
1907         (float:DF (match_operand:SI 1 "register_operand" "f")))]
1908   "TARGET_DOUBLE_FLOAT"
1909   "ffint.d.w\t%0,%1"
1910   [(set_attr "type" "fcvt")
1911    (set_attr "mode" "DF")
1912    (set_attr "cnv_mode" "I2D")])
1914 (define_insn "floatdidf2"
1915   [(set (match_operand:DF 0 "register_operand" "=f")
1916         (float:DF (match_operand:DI 1 "register_operand" "f")))]
1917   "TARGET_DOUBLE_FLOAT"
1918   "ffint.d.l\t%0,%1"
1919   [(set_attr "type" "fcvt")
1920    (set_attr "mode" "DF")
1921    (set_attr "cnv_mode" "I2D")])
1923 (define_insn "floatsisf2"
1924   [(set (match_operand:SF 0 "register_operand" "=f")
1925         (float:SF (match_operand:SI 1 "register_operand" "f")))]
1926   "TARGET_HARD_FLOAT"
1927   "ffint.s.w\t%0,%1"
1928   [(set_attr "type" "fcvt")
1929    (set_attr "mode" "SF")
1930    (set_attr "cnv_mode" "I2S")])
1932 (define_insn "floatdisf2"
1933   [(set (match_operand:SF 0 "register_operand" "=f")
1934         (float:SF (match_operand:DI 1 "register_operand" "f")))]
1935   "TARGET_DOUBLE_FLOAT"
1936   "ffint.s.l\t%0,%1"
1937   [(set_attr "type" "fcvt")
1938    (set_attr "mode" "SF")
1939    (set_attr "cnv_mode" "I2S")])
1941 ;; Convert a floating-point value to an unsigned integer.
1943 (define_expand "fixuns_truncdfsi2"
1944   [(set (match_operand:SI 0 "register_operand")
1945         (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1946   "TARGET_DOUBLE_FLOAT"
1948   rtx reg1 = gen_reg_rtx (DFmode);
1949   rtx reg2 = gen_reg_rtx (DFmode);
1950   rtx reg3 = gen_reg_rtx (SImode);
1951   rtx_code_label *label1 = gen_label_rtx ();
1952   rtx_code_label *label2 = gen_label_rtx ();
1953   rtx test;
1954   REAL_VALUE_TYPE offset;
1956   real_2expN (&offset, 31, DFmode);
1958   loongarch_emit_move (reg1,
1959                        const_double_from_real_value (offset, DFmode));
1960   do_pending_stack_adjust ();
1962   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1963   emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1965   emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1966   emit_jump_insn (gen_rtx_SET (pc_rtx,
1967                                gen_rtx_LABEL_REF (VOIDmode, label2)));
1968   emit_barrier ();
1970   emit_label (label1);
1971   loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1972   loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1973                                         (BITMASK_HIGH, SImode)));
1975   emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1976   emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1978   emit_label (label2);
1980   /* Allow REG_NOTES to be set on last insn (labels don't have enough
1981      fields, and can't be used for REG_NOTES anyway).  */
1982   emit_use (stack_pointer_rtx);
1983   DONE;
1986 (define_expand "fixuns_truncdfdi2"
1987   [(set (match_operand:DI 0 "register_operand")
1988         (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
1989   "TARGET_DOUBLE_FLOAT"
1991   rtx reg1 = gen_reg_rtx (DFmode);
1992   rtx reg2 = gen_reg_rtx (DFmode);
1993   rtx reg3 = gen_reg_rtx (DImode);
1994   rtx_code_label *label1 = gen_label_rtx ();
1995   rtx_code_label *label2 = gen_label_rtx ();
1996   rtx test;
1997   REAL_VALUE_TYPE offset;
1999   real_2expN (&offset, 63, DFmode);
2001   loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
2002   do_pending_stack_adjust ();
2004   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2005   emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
2007   emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
2008   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2009   emit_barrier ();
2011   emit_label (label1);
2012   loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
2013   loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2014   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2016   emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
2017   emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2019   emit_label (label2);
2021   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2022      fields, and can't be used for REG_NOTES anyway).  */
2023   emit_use (stack_pointer_rtx);
2024   DONE;
2027 (define_expand "fixuns_truncsfsi2"
2028   [(set (match_operand:SI 0 "register_operand")
2029         (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
2030   "TARGET_HARD_FLOAT"
2032   rtx reg1 = gen_reg_rtx (SFmode);
2033   rtx reg2 = gen_reg_rtx (SFmode);
2034   rtx reg3 = gen_reg_rtx (SImode);
2035   rtx_code_label *label1 = gen_label_rtx ();
2036   rtx_code_label *label2 = gen_label_rtx ();
2037   rtx test;
2038   REAL_VALUE_TYPE offset;
2040   real_2expN (&offset, 31, SFmode);
2042   loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2043   do_pending_stack_adjust ();
2045   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2046   emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2048   emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
2049   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2050   emit_barrier ();
2052   emit_label (label1);
2053   loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2054   loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
2055                                  (BITMASK_HIGH, SImode)));
2057   emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
2058   emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
2060   emit_label (label2);
2062   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2063      fields, and can't be used for REG_NOTES anyway).  */
2064   emit_use (stack_pointer_rtx);
2065   DONE;
2068 (define_expand "fixuns_truncsfdi2"
2069   [(set (match_operand:DI 0 "register_operand")
2070         (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
2071   "TARGET_DOUBLE_FLOAT"
2073   rtx reg1 = gen_reg_rtx (SFmode);
2074   rtx reg2 = gen_reg_rtx (SFmode);
2075   rtx reg3 = gen_reg_rtx (DImode);
2076   rtx_code_label *label1 = gen_label_rtx ();
2077   rtx_code_label *label2 = gen_label_rtx ();
2078   rtx test;
2079   REAL_VALUE_TYPE offset;
2081   real_2expN (&offset, 63, SFmode);
2083   loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2084   do_pending_stack_adjust ();
2086   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2087   emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2089   emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
2090   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2091   emit_barrier ();
2093   emit_label (label1);
2094   loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2095   loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2096   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2098   emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
2099   emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2101   emit_label (label2);
2103   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2104      fields, and can't be used for REG_NOTES anyway).  */
2105   emit_use (stack_pointer_rtx);
2106   DONE;
2110 ;;  ....................
2112 ;;      EXTRACT AND INSERT
2114 ;;  ....................
2116 (define_expand "extzv<mode>"
2117   [(set (match_operand:X 0 "register_operand")
2118         (zero_extract:X (match_operand:X 1 "register_operand")
2119                         (match_operand 2 "const_int_operand")
2120                         (match_operand 3 "const_int_operand")))]
2121   ""
2123   if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2124                                 INTVAL (operands[3])))
2125     FAIL;
2128 (define_insn "*extzv<mode>"
2129   [(set (match_operand:X 0 "register_operand" "=r")
2130         (zero_extract:X (match_operand:X 1 "register_operand" "r")
2131                           (match_operand 2 "const_int_operand" "")
2132                           (match_operand 3 "const_int_operand" "")))]
2133   "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2134                             INTVAL (operands[3]))"
2136   operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2137   return "bstrpick.<d>\t%0,%1,%2,%3";
2139   [(set_attr "type" "arith")
2140    (set_attr "mode" "<MODE>")])
2142 (define_expand "insv<mode>"
2143   [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2144                           (match_operand 1 "const_int_operand")
2145                           (match_operand 2 "const_int_operand"))
2146         (match_operand:GPR 3 "reg_or_0_operand"))]
2147   ""
2149   if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2150                                 INTVAL (operands[2])))
2151     FAIL;
2154 (define_insn "*insv<mode>"
2155   [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2156                           (match_operand:SI 1 "const_int_operand" "")
2157                           (match_operand:SI 2 "const_int_operand" ""))
2158         (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2159   "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2160                             INTVAL (operands[2]))"
2162   operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2163   return "bstrins.<d>\t%0,%z3,%1,%2";
2165   [(set_attr "type" "arith")
2166    (set_attr "mode" "<MODE>")])
2169 ;;  ....................
2171 ;;      DATA MOVEMENT
2173 ;;  ....................
2175 ;; 64-bit integer moves
2177 ;; Unlike most other insns, the move insns can't be split with
2178 ;; different predicates, because register spilling and other parts of
2179 ;; the compiler, have memoized the insn number already.
2181 (define_expand "movdi"
2182   [(set (match_operand:DI 0 "")
2183         (match_operand:DI 1 ""))]
2184   ""
2186   if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2187     DONE;
2190 (define_insn_and_split "*movdi_32bit"
2191   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2192        (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2193   "!TARGET_64BIT
2194    && (register_operand (operands[0], DImode)
2195        || reg_or_0_operand (operands[1], DImode))"
2196   { return loongarch_output_move (operands); }
2197   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2198   (operands[0]))"
2199   [(const_int 0)]
2200   "
2202   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2203   DONE;
2205   "
2206   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2207    (set_attr "mode" "DI")])
2209 (define_insn_and_split "*movdi_64bit"
2210   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2211         (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2212   "TARGET_64BIT
2213    && (register_operand (operands[0], DImode)
2214        || reg_or_0_operand (operands[1], DImode))"
2215   {
2216     return loongarch_output_move (operands);
2217   }
2218   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2219   (operands[0]))"
2220   [(const_int 0)]
2221   "
2223   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2224   DONE;
2226   "
2227   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2228    (set_attr "mode" "DI")])
2230 ;; Use two registers to get the global symbol address from the got table.
2231 ;; la.global rd, rt, sym
2233 (define_insn_and_split "movdi_symbolic_off64"
2234  [(set (match_operand:DI 0 "register_operand" "=r,r")
2235        (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r"))
2236   (unspec:DI [(const_int 0)]
2237     UNSPEC_LOAD_SYMBOL_OFFSET64)
2238   (clobber (match_operand:DI 2 "register_operand" "=&r,r"))]
2239  "TARGET_64BIT && TARGET_CMODEL_EXTREME"
2241   if (which_alternative == 1)
2242     return "#";
2244   enum loongarch_symbol_type symbol_type;
2245   gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2247   switch (symbol_type)
2248     {
2249     case SYMBOL_PCREL64:
2250       return "la.local\t%0,%2,%1";
2251     case SYMBOL_GOT_DISP:
2252       return "la.global\t%0,%2,%1";
2253     case SYMBOL_TLS_IE:
2254       return "la.tls.ie\t%0,%2,%1";
2255     case SYMBOL_TLSGD:
2256       return "la.tls.gd\t%0,%2,%1";
2257     case SYMBOL_TLSLDM:
2258       return "la.tls.ld\t%0,%2,%1";
2260     default:
2261       gcc_unreachable ();
2262   }
2264  "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0"
2265  [(set (match_dup 0) (match_dup 1))]
2266  ""
2267  [(set_attr "mode" "DI")
2268   (set_attr "insn_count" "5")])
2270 ;; The 64-bit PC-relative part of address loading.
2271 ;; Note that the psABI does not allow splitting it.
2272 (define_insn "la_pcrel64_two_parts"
2273   [(set (match_operand:DI 0 "register_operand" "=r")
2274         (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1))
2275    (set (match_operand:DI 1 "register_operand" "=r")
2276         (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))]
2277   "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
2278   {
2279     return "pcalau12i\t%0,%r2\n\t"
2280            "addi.d\t%1,$r0,%L2\n\t"
2281            "lu32i.d\t%1,%R2\n\t"
2282            "lu52i.d\t%1,%1,%H2";
2283   }
2284   [(set_attr "move_type" "move")
2285    (set_attr "mode" "DI")
2286    (set_attr "length" "16")])
2288 ;; 32-bit Integer moves
2290 (define_expand "movsi"
2291   [(set (match_operand:SI 0 "")
2292         (match_operand:SI 1 ""))]
2293   ""
2295   if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2296     DONE;
2299 (define_insn_and_split "*movsi_internal"
2300   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m")
2301         (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f"))]
2302   "(register_operand (operands[0], SImode)
2303     || reg_or_0_operand (operands[1], SImode))"
2304   { return loongarch_output_move (operands); }
2305   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2306   (operands[0]))"
2307   [(const_int 0)]
2308   "
2310   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2311   DONE;
2313   "
2314   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2315    (set_attr "mode" "SI")])
2317 ;; 16-bit Integer moves
2319 ;; Unlike most other insns, the move insns can't be split with
2320 ;; different predicates, because register spilling and other parts of
2321 ;; the compiler, have memoized the insn number already.
2322 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2324 (define_expand "movhi"
2325   [(set (match_operand:HI 0 "")
2326         (match_operand:HI 1 ""))]
2327   ""
2329   if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2330     DONE;
2333 (define_insn_and_split "*movhi_internal"
2334   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2335         (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2336   "(register_operand (operands[0], HImode)
2337        || reg_or_0_operand (operands[1], HImode))"
2338   { return loongarch_output_move (operands); }
2339   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2340   (operands[0]))"
2341   [(const_int 0)]
2342   "
2344   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2345   DONE;
2347   "
2348   [(set_attr "move_type" "move,const,const,load,store,load,store")
2349    (set_attr "mode" "HI")])
2351 ;; 8-bit Integer moves
2353 ;; Unlike most other insns, the move insns can't be split with
2354 ;; different predicates, because register spilling and other parts of
2355 ;; the compiler, have memoized the insn number already.
2356 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2358 (define_expand "movqi"
2359   [(set (match_operand:QI 0 "")
2360         (match_operand:QI 1 ""))]
2361   ""
2363   if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2364     DONE;
2367 (define_insn "*movqi_internal"
2368   [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2369         (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2370   "(register_operand (operands[0], QImode)
2371        || reg_or_0_operand (operands[1], QImode))"
2372   { return loongarch_output_move (operands); }
2373   [(set_attr "move_type" "move,const,load,store,load,store")
2374    (set_attr "mode" "QI")])
2376 ;; 32-bit floating point moves
2378 (define_expand "movsf"
2379   [(set (match_operand:SF 0 "")
2380         (match_operand:SF 1 ""))]
2381   ""
2383   if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2384     DONE;
2387 (define_insn "*movsf_hardfloat"
2388   [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2389         (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2390   "TARGET_HARD_FLOAT
2391    && (register_operand (operands[0], SFmode)
2392        || reg_or_0_operand (operands[1], SFmode))"
2393   { return loongarch_output_move (operands); }
2394   [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2395    (set_attr "mode" "SF")])
2397 (define_insn "*movsf_softfloat"
2398   [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2399         (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2400   "TARGET_SOFT_FLOAT
2401    && (register_operand (operands[0], SFmode)
2402        || reg_or_0_operand (operands[1], SFmode))"
2403   { return loongarch_output_move (operands); }
2404   [(set_attr "move_type" "move,load,store")
2405    (set_attr "mode" "SF")])
2407 ;; 64-bit floating point moves
2409 (define_expand "movdf"
2410   [(set (match_operand:DF 0 "")
2411         (match_operand:DF 1 ""))]
2412   ""
2414   if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2415     DONE;
2418 (define_insn "*movdf_hardfloat"
2419   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2420         (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2421   "TARGET_DOUBLE_FLOAT
2422    && (register_operand (operands[0], DFmode)
2423        || reg_or_0_operand (operands[1], DFmode))"
2424   { return loongarch_output_move (operands); }
2425   [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2426    (set_attr "mode" "DF")])
2428 (define_insn "*movdf_softfloat"
2429   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2430         (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2431   "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2432    && TARGET_64BIT
2433    && (register_operand (operands[0], DFmode)
2434        || reg_or_0_operand (operands[1], DFmode))"
2435   { return loongarch_output_move (operands); }
2436   [(set_attr "move_type" "move,load,store")
2437    (set_attr "mode" "DF")])
2439 ;; Clear one FCC register
2441 (define_expand "movfcc"
2442   [(set (match_operand:FCC 0 "")
2443         (match_operand:FCC 1 ""))]
2444   "TARGET_HARD_FLOAT"
2446   if (memory_operand (operands[0], FCCmode)
2447       && memory_operand (operands[1], FCCmode))
2448     operands[1] = force_reg (FCCmode, operands[1]);
2451 (define_insn "movfcc_internal"
2452   [(set (match_operand:FCC 0 "nonimmediate_operand"
2453                              "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2454         (match_operand:FCC 1 "reg_or_0_operand"
2455                              "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2456   "TARGET_HARD_FLOAT"
2457   "@
2458    fcmp.caf.s\t%0,$f0,$f0
2459    movfr2cf\t%0,%1
2460    movcf2fr\t%0,%1
2461    fmov.s\t%0,%1
2462    or\t%0,%z1,$r0
2463    ld.b\t%0,%1
2464    st.b\t%z1,%0
2465    movgr2fr.w\t%0,%1
2466    movfr2gr.s\t%0,%1
2467    movgr2cf\t%0,%1
2468    movcf2gr\t%0,%1"
2469   [(set_attr "type" "move")
2470    (set_attr "mode" "FCC")])
2472 (define_insn "fcc_to_<X:mode>"
2473   [(set (match_operand:X 0 "register_operand" "=r")
2474         (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2475                             (const_int 0))
2476                         (const_int 1)
2477                         (const_int 0)))]
2478   "TARGET_HARD_FLOAT"
2479   ""
2480   [(set_attr "length" "0")
2481    (set_attr "type" "ghost")])
2483 (define_expand "cstore<ANYF:mode>4"
2484   [(set (match_operand:SI 0 "register_operand")
2485         (match_operator:SI 1 "loongarch_fcmp_operator"
2486           [(match_operand:ANYF 2 "register_operand")
2487            (match_operand:ANYF 3 "register_operand")]))]
2488   ""
2489   {
2490     rtx fcc = gen_reg_rtx (FCCmode);
2491     rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2492                               operands[2], operands[3]);
2494     emit_insn (gen_rtx_SET (fcc, cmp));
2495     if (TARGET_64BIT)
2496       {
2497         rtx gpr = gen_reg_rtx (DImode);
2498         emit_insn (gen_fcc_to_di (gpr, fcc));
2499         emit_insn (gen_rtx_SET (operands[0],
2500                                 lowpart_subreg (SImode, gpr, DImode)));
2501       }
2502     else
2503       emit_insn (gen_fcc_to_si (operands[0], fcc));
2505     DONE;
2506   })
2508 ;; Conditional move instructions.
2510 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2511   [(set (match_operand:GPR 0 "register_operand" "=r,r")
2512         (if_then_else:GPR
2513          (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2514                            (const_int 0))
2515          (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2516          (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2517   "register_operand (operands[2], <GPR:MODE>mode)
2518    != register_operand (operands[3], <GPR:MODE>mode)"
2519   "@
2520    <sel>\t%0,%2,%1
2521    <selinv>\t%0,%3,%1"
2522   [(set_attr "type" "condmove")
2523    (set_attr "mode" "<GPR:MODE>")])
2525 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2526 ;; argument if the 1st is zero.  This means operand 2 and 3 are
2527 ;; inverted in the instruction.
2529 (define_insn "*sel<mode>"
2530   [(set (match_operand:ANYF 0 "register_operand" "=f")
2531         (if_then_else:ANYF
2532          (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2533                  (const_int 0))
2534          (match_operand:ANYF 2 "reg_or_0_operand" "f")
2535          (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2536   ""
2537   "fsel\t%0,%3,%2,%1"
2538   [(set_attr "type" "condmove")
2539    (set_attr "mode" "<ANYF:MODE>")])
2541 ;; These are the main define_expand's used to make conditional moves.
2543 (define_expand "mov<mode>cc"
2544   [(set (match_operand:GPR 0 "register_operand")
2545         (if_then_else:GPR (match_operator 1 "comparison_operator"
2546                          [(match_operand:GPR 2 "reg_or_0_operand")
2547                           (match_operand:GPR 3 "reg_or_0_operand")])))]
2548   "TARGET_COND_MOVE_INT"
2550   if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2551     FAIL;
2553   loongarch_expand_conditional_move (operands);
2554   DONE;
2557 (define_expand "mov<mode>cc"
2558   [(set (match_operand:ANYF 0 "register_operand")
2559         (if_then_else:ANYF (match_operator 1 "comparison_operator"
2560                           [(match_operand:ANYF 2 "reg_or_0_operand")
2561                            (match_operand:ANYF 3 "reg_or_0_operand")])))]
2562   "TARGET_COND_MOVE_FLOAT"
2564   if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2565     FAIL;
2567   loongarch_expand_conditional_move (operands);
2568   DONE;
2571 (define_insn "lu32i_d"
2572   [(set (match_operand:DI 0 "register_operand" "=r")
2573         (ior:DI
2574           (zero_extend:DI
2575             (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2576           (match_operand:DI 2 "const_lu32i_operand" "u")))]
2577   "TARGET_64BIT"
2578   {
2579     operands[2] = GEN_INT (INTVAL (operands[2]) >> 32);
2580     return "lu32i.d\t%0,%X2";
2581   }
2582   [(set_attr "type" "arith")
2583    (set_attr "mode" "DI")])
2585 (define_insn "lu52i_d"
2586   [(set (match_operand:DI 0 "register_operand" "=r")
2587         (ior:DI
2588           (and:DI (match_operand:DI 1 "register_operand" "r")
2589                   (match_operand 2 "lu52i_mask_operand"))
2590           (match_operand 3 "const_lu52i_operand" "v")))]
2591   "TARGET_64BIT"
2592   {
2593     operands[3] = GEN_INT (INTVAL (operands[3]) >> 52);
2594     return "lu52i.d\t%0,%1,%X3";
2595   }
2596   [(set_attr "type" "arith")
2597    (set_attr "mode" "DI")])
2599 ;; Instructions for adding the low 12 bits of an address to a register.
2600 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2601 ;; should be applied.
2603 (define_insn "*low<mode>"
2604   [(set (match_operand:P 0 "register_operand" "=r")
2605  (lo_sum:P (match_operand:P 1 "register_operand" " r")
2606      (match_operand:P 2 "symbolic_operand" "")))]
2607   ""
2608   "addi.<d>\t%0,%1,%L2"
2609   [(set_attr "type" "arith")
2610    (set_attr "mode" "<MODE>")])
2612 (define_insn "@tls_low<mode>"
2613   [(set (match_operand:P 0 "register_operand" "=r")
2614         (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2615                                     (match_operand:P 2 "symbolic_operand" "")))]
2616         UNSPEC_TLS_LOW))]
2617   ""
2618   "addi.<d>\t%0,%1,%L2"
2619   [(set_attr "type" "arith")
2620    (set_attr "mode" "<MODE>")])
2622 ;; Instructions for loading address from GOT entry.
2623 ;; operands[1] is pc plus the high half of the address difference with the got
2624 ;; entry;
2625 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2626 ;; got entry.
2627 ;; loongarch_print_operand works out which relocation should be applied.
2629 (define_insn "@ld_from_got<mode>"
2630   [(set (match_operand:P 0 "register_operand" "=r")
2631         (unspec:P [(mem:P (lo_sum:P
2632                                 (match_operand:P 1 "register_operand" "r")
2633                                 (match_operand:P 2 "symbolic_operand")))]
2634         UNSPEC_LOAD_FROM_GOT))]
2635   ""
2636   "%Q2ld.<d>\t%0,%1,%L2"
2637   [(set_attr "type" "move")]
2640 (define_insn "@lui_l_hi20<mode>"
2641   [(set (match_operand:P 0 "register_operand" "=r")
2642         (unspec:P [(match_operand:P 1 "symbolic_operand")]
2643         UNSPEC_LUI_L_HI20))]
2644   ""
2645   "lu12i.w\t%0,%r1"
2646   [(set_attr "type" "move")]
2649 (define_insn "@pcalau12i<mode>"
2650   [(set (match_operand:P 0 "register_operand" "=j")
2651         (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2652         UNSPEC_PCALAU12I))]
2653   ""
2654   "pcalau12i\t%0,%%pc_hi20(%1)"
2655   [(set_attr "type" "move")])
2657 ;; @pcalau12i may be used for sibcall so it has a strict constraint.  This
2658 ;; allows any general register as the operand.
2659 (define_insn "@pcalau12i_gr<mode>"
2660   [(set (match_operand:P 0 "register_operand" "=r")
2661        (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2662        UNSPEC_PCALAU12I_GR))]
2663   ""
2664   "pcalau12i\t%0,%%pc_hi20(%1)"
2665   [(set_attr "type" "move")])
2667 (define_insn "@add_tls_le_relax<mode>"
2668   [(set (match_operand:P 0 "register_operand" "=r")
2669         (unspec:P [(match_operand:P 1 "register_operand" "r")
2670                    (match_operand:P 2 "register_operand" "r")
2671                    (match_operand:P 3 "symbolic_operand")]
2672           UNSPEC_ADD_TLS_LE_RELAX))]
2673   "HAVE_AS_TLS_LE_RELAXATION"
2674   "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2675   [(set_attr "type" "move")]
2678 (define_insn "@ori_l_lo12<mode>"
2679   [(set (match_operand:P 0 "register_operand" "=r")
2680         (unspec:P [(match_operand:P 1 "register_operand" "r")
2681                    (match_operand:P 2 "symbolic_operand")]
2682         UNSPEC_ORI_L_LO12))]
2683   ""
2684   "ori\t%0,%1,%L2"
2685   [(set_attr "type" "move")]
2688 (define_insn "lui_h_lo20"
2689   [(set (match_operand:DI 0 "register_operand" "=r")
2690         (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2691                     (match_operand:DI 2 "symbolic_operand")]
2692         UNSPEC_LUI_H_LO20))]
2693   "TARGET_64BIT"
2694   "lu32i.d\t%0,%R2"
2695   [(set_attr "type" "move")]
2698 (define_insn "lui_h_hi12"
2699   [(set (match_operand:DI 0 "register_operand" "=r")
2700         (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2701                     (match_operand:DI 2 "symbolic_operand")]
2702         UNSPEC_LUI_H_HI12))]
2703   "TARGET_64BIT"
2704   "lu52i.d\t%0,%1,%H2"
2705   [(set_attr "type" "move")]
2708 ;; Round floating-point numbers to integers
2709 (define_insn "rint<mode>2"
2710   [(set (match_operand:ANYF 0 "register_operand" "=f")
2711         (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2712                       UNSPEC_FRINT))]
2713   ""
2714   "frint.<fmt>\t%0,%1"
2715   [(set_attr "type" "fcvt")
2716    (set_attr "mode" "<MODE>")])
2718 ;; Convert floating-point numbers to integers
2719 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2720   [(set (match_operand:ANYFI 0 "register_operand" "=f")
2721         (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2722                       LRINT))]
2723   "TARGET_HARD_FLOAT &&
2724    (<LRINT> == UNSPEC_FTINT
2725     || flag_fp_int_builtin_inexact
2726     || !flag_trapping_math)"
2727   "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2728   [(set_attr "type" "fcvt")
2729    (set_attr "mode" "<ANYF:MODE>")])
2731 ;; Thread-Local Storage
2733 (define_insn "@got_load_tls_desc<mode>"
2734   [(set (reg:P 4)
2735         (unspec:P
2736             [(match_operand:P 0 "symbolic_operand" "")]
2737             UNSPEC_TLS_DESC))
2738     (clobber (reg:SI FCC0_REGNUM))
2739     (clobber (reg:SI FCC1_REGNUM))
2740     (clobber (reg:SI FCC2_REGNUM))
2741     (clobber (reg:SI FCC3_REGNUM))
2742     (clobber (reg:SI FCC4_REGNUM))
2743     (clobber (reg:SI FCC5_REGNUM))
2744     (clobber (reg:SI FCC6_REGNUM))
2745     (clobber (reg:SI FCC7_REGNUM))
2746     (clobber (reg:SI RETURN_ADDR_REGNUM))]
2747   "TARGET_TLS_DESC"
2749   return TARGET_EXPLICIT_RELOCS
2750     ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2751       "addi.d\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
2752       "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2753       "jirl\t$r1,$r1,%%desc_call(%0)"
2754     : "la.tls.desc\t$r4,%0";
2756   [(set_attr "got" "load")
2757    (set_attr "mode" "<MODE>")
2758    (set_attr "length" "16")])
2760 (define_insn "got_load_tls_desc_off64"
2761   [(set (reg:DI 4)
2762         (unspec:DI
2763             [(match_operand:DI 0 "symbolic_operand" "")]
2764             UNSPEC_TLS_DESC_OFF64))
2765     (clobber (reg:SI FCC0_REGNUM))
2766     (clobber (reg:SI FCC1_REGNUM))
2767     (clobber (reg:SI FCC2_REGNUM))
2768     (clobber (reg:SI FCC3_REGNUM))
2769     (clobber (reg:SI FCC4_REGNUM))
2770     (clobber (reg:SI FCC5_REGNUM))
2771     (clobber (reg:SI FCC6_REGNUM))
2772     (clobber (reg:SI FCC7_REGNUM))
2773     (clobber (reg:SI RETURN_ADDR_REGNUM))
2774     (clobber (match_operand:DI 1 "register_operand" "=&r"))]
2775   "TARGET_TLS_DESC && TARGET_CMODEL_EXTREME"
2777   return TARGET_EXPLICIT_RELOCS
2778     ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2779       "addi.d\t%1,$r0,%%desc_pc_lo12(%0)\n\t"
2780       "lu32i.d\t%1,%%desc64_pc_lo20(%0)\n\t"
2781       "lu52i.d\t%1,%1,%%desc64_pc_hi12(%0)\n\t"
2782       "add.d\t$r4,$r4,%1\n\t"
2783       "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2784       "jirl\t$r1,$r1,%%desc_call(%0)"
2785     : "la.tls.desc\t$r4,%1,%0";
2787   [(set_attr "got" "load")
2788    (set_attr "length" "28")])
2790 (define_insn "@load_tls<mode>"
2791   [(set (match_operand:P 0 "register_operand" "=r")
2792         (unspec:P
2793             [(match_operand:P 1 "symbolic_operand" "")]
2794             UNSPEC_TLS))]
2795   ""
2797   enum loongarch_symbol_type symbol_type;
2798   gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2800   switch (symbol_type)
2801     {
2802     case SYMBOL_TLS_LE:
2803       return "la.tls.le\t%0,%1";
2804     case SYMBOL_TLS_IE:
2805       return "la.tls.ie\t%0,%1";
2806     case SYMBOL_TLSLDM:
2807       return "la.tls.ld\t%0,%1";
2808     case SYMBOL_TLSGD:
2809       return "la.tls.gd\t%0,%1";
2811     default:
2812       gcc_unreachable ();
2813     }
2815   [(set_attr "mode" "<MODE>")
2816    (set (attr "insn_count")
2817       (if_then_else
2818         (match_test "TARGET_CMODEL_EXTREME")
2819         (const_int 4)
2820         (const_int 2)))])
2823 ;; Expand in-line code to clear the instruction cache between operand[0] and
2824 ;; operand[1].
2825 (define_expand "clear_cache"
2826   [(match_operand 0 "pmode_register_operand")
2827    (match_operand 1 "pmode_register_operand")]
2828   ""
2830   emit_insn (gen_loongarch_ibar (const0_rtx));
2831   DONE;
2834 (define_insn "loongarch_ibar"
2835   [(unspec_volatile:SI
2836       [(match_operand 0 "const_uimm15_operand")]
2837        UNSPECV_IBAR)
2838    (clobber (mem:BLK (scratch)))]
2839   ""
2840   "ibar\t%0")
2842 (define_insn "loongarch_dbar"
2843   [(unspec_volatile:SI
2844       [(match_operand 0 "const_uimm15_operand")]
2845        UNSPECV_DBAR)
2846    (clobber (mem:BLK (scratch)))]
2847   ""
2848   "dbar\t%0")
2852 ;; Privileged state instruction
2854 (define_insn "loongarch_cpucfg"
2855   [(set (match_operand:SI 0 "register_operand" "=r")
2856         (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2857                              UNSPECV_CPUCFG))]
2858   ""
2859   "cpucfg\t%0,%1"
2860   [(set_attr "type" "load")
2861    (set_attr "mode" "SI")])
2863 (define_insn "loongarch_syscall"
2864   [(unspec_volatile:SI
2865       [(match_operand 0 "const_uimm15_operand")]
2866        UNSPECV_SYSCALL)
2867    (clobber (mem:BLK (scratch)))]
2868   ""
2869   "syscall\t%0")
2871 (define_insn "loongarch_break"
2872   [(unspec_volatile:SI
2873       [(match_operand 0 "const_uimm15_operand")]
2874        UNSPECV_BREAK)
2875    (clobber (mem:BLK (scratch)))]
2876   ""
2877   "break\t%0")
2879 (define_insn "loongarch_asrtle_d"
2880   [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2881                         (match_operand:DI 1 "register_operand" "r")]
2882                         UNSPECV_ASRTLE_D)]
2883   "TARGET_64BIT"
2884   "asrtle.d\t%0,%1"
2885   [(set_attr "type" "load")
2886    (set_attr "mode" "DI")])
2888 (define_insn "loongarch_asrtgt_d"
2889   [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2890                         (match_operand:DI 1 "register_operand" "r")]
2891                         UNSPECV_ASRTGT_D)]
2892   "TARGET_64BIT"
2893   "asrtgt.d\t%0,%1"
2894   [(set_attr "type" "load")
2895    (set_attr "mode" "DI")])
2897 (define_insn "loongarch_csrrd_<d>"
2898   [(set (match_operand:GPR 0 "register_operand" "=r")
2899         (unspec_volatile:GPR [(match_operand  1 "const_uimm14_operand")]
2900                               UNSPECV_CSRRD))
2901    (clobber (mem:BLK (scratch)))]
2902   ""
2903   "csrrd\t%0,%1"
2904   [(set_attr "type" "load")
2905    (set_attr "mode" "<MODE>")])
2907 (define_insn "loongarch_csrwr_<d>"
2908   [(set (match_operand:GPR 0 "register_operand" "=r")
2909           (unspec_volatile:GPR
2910             [(match_operand:GPR 1 "register_operand" "0")
2911              (match_operand 2 "const_uimm14_operand")]
2912              UNSPECV_CSRWR))
2913    (clobber (mem:BLK (scratch)))]
2914   ""
2915   "csrwr\t%0,%2"
2916   [(set_attr "type" "store")
2917    (set_attr "mode" "<MODE>")])
2919 (define_insn "loongarch_csrxchg_<d>"
2920   [(set (match_operand:GPR 0 "register_operand" "=r")
2921           (unspec_volatile:GPR
2922             [(match_operand:GPR 1 "register_operand" "0")
2923              (match_operand:GPR 2 "register_operand" "q")
2924              (match_operand 3 "const_uimm14_operand")]
2925              UNSPECV_CSRXCHG))
2926    (clobber (mem:BLK (scratch)))]
2927   ""
2928   "csrxchg\t%0,%2,%3"
2929   [(set_attr "type" "load")
2930    (set_attr "mode" "<MODE>")])
2932 (define_insn "loongarch_iocsrrd_<size>"
2933   [(set (match_operand:QHWD 0 "register_operand" "=r")
2934         (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2935                               UNSPECV_IOCSRRD))
2936    (clobber (mem:BLK (scratch)))]
2937   ""
2938   "iocsrrd.<size>\t%0,%1"
2939   [(set_attr "type" "load")
2940    (set_attr "mode" "<MODE>")])
2942 (define_insn "loongarch_iocsrwr_<size>"
2943   [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2944                           (match_operand:SI 1 "register_operand" "r")]
2945                           UNSPECV_IOCSRWR)
2946    (clobber (mem:BLK (scratch)))]
2947   ""
2948   "iocsrwr.<size>\t%0,%1"
2949   [(set_attr "type" "load")
2950    (set_attr "mode" "<MODE>")])
2952 (define_insn "loongarch_cacop_<d>"
2953   [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2954                        (match_operand:X 1 "register_operand" "r")
2955                        (match_operand 2 "const_imm12_operand")]
2956                        UNSPECV_CACOP)
2957    (clobber (mem:BLK (scratch)))]
2958   ""
2959   "cacop\t%0,%1,%2"
2960   [(set_attr "type" "load")
2961    (set_attr "mode" "<MODE>")])
2963 (define_insn "loongarch_lddir_<d>"
2964   [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2965                        (match_operand:X 1 "register_operand" "r")
2966                        (match_operand 2 "const_uimm5_operand")]
2967                        UNSPECV_LDDIR)
2968    (clobber (mem:BLK (scratch)))]
2969   ""
2970   "lddir\t%0,%1,%2"
2971   [(set_attr "type" "load")
2972    (set_attr "mode" "<MODE>")])
2974 (define_insn "loongarch_ldpte_<d>"
2975   [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2976                        (match_operand 1 "const_uimm5_operand")]
2977                        UNSPECV_LDPTE)
2978    (clobber (mem:BLK (scratch)))]
2979   ""
2980   "ldpte\t%0,%1"
2981   [(set_attr "type" "load")
2982    (set_attr "mode" "<MODE>")])
2985 ;; Block moves, see loongarch.c for more details.
2986 ;; Argument 0 is the destination.
2987 ;; Argument 1 is the source.
2988 ;; Argument 2 is the length.
2989 ;; Argument 3 is the alignment.
2991 (define_expand "cpymemsi"
2992   [(parallel [(set (match_operand:BLK 0 "general_operand")
2993                    (match_operand:BLK 1 "general_operand"))
2994               (use (match_operand:SI 2 ""))
2995               (use (match_operand:SI 3 "const_int_operand"))])]
2996   ""
2998   if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
2999       && loongarch_expand_block_move (operands[0], operands[1],
3000                                       operands[2], operands[3]))
3001     DONE;
3002   else
3003     FAIL;
3007 ;;  ....................
3009 ;;      SHIFTS
3011 ;;  ....................
3013 (define_insn "*<optab><mode>3"
3014   [(set (match_operand:GPR 0 "register_operand" "=r")
3015         (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
3016                        (match_operand:SI 2 "arith_operand" "rI")))]
3017   ""
3019   if (CONST_INT_P (operands[2]))
3020     operands[2] = GEN_INT (INTVAL (operands[2])
3021                            & (GET_MODE_BITSIZE (<MODE>mode) - 1));
3023   return "<insn>%i2.<d>\t%0,%1,%2";
3025   [(set_attr "type" "shift")
3026    (set_attr "mode" "<MODE>")])
3028 (define_insn "<optab>si3_extend"
3029   [(set (match_operand:DI 0 "register_operand" "=r")
3030         (sign_extend:DI
3031            (any_shift:SI (match_operand:SI 1 "register_operand" "r")
3032                          (match_operand:SI 2 "arith_operand" "rI"))))]
3033   "TARGET_64BIT"
3035   if (CONST_INT_P (operands[2]))
3036     operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
3038   return "<insn>%i2.w\t%0,%1,%2";
3040   [(set_attr "type" "shift")
3041    (set_attr "mode" "SI")])
3043 (define_insn "*rotr<mode>3"
3044   [(set (match_operand:GPR 0 "register_operand" "=r,r")
3045         (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
3046                       (match_operand:SI 2 "arith_operand" "r,I")))]
3047   ""
3048   "rotr%i2.<d>\t%0,%1,%2"
3049   [(set_attr "type" "shift,shift")
3050    (set_attr "mode" "<MODE>")])
3052 (define_insn "rotrsi3_extend"
3053   [(set (match_operand:DI 0 "register_operand" "=r,r")
3054         (sign_extend:DI
3055           (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
3056                        (match_operand:SI 2 "arith_operand" "r,I"))))]
3057   "TARGET_64BIT"
3058   "rotr%i2.w\t%0,%1,%2"
3059   [(set_attr "type" "shift,shift")
3060    (set_attr "mode" "SI")])
3062 ;; Expand left rotate to right rotate.
3063 (define_expand "rotl<mode>3"
3064   [(set (match_dup 3)
3065         (neg:SI (match_operand:SI 2 "register_operand")))
3066    (set (match_operand:GPR 0 "register_operand")
3067         (rotatert:GPR (match_operand:GPR 1 "register_operand")
3068                       (match_dup 3)))]
3069   ""
3070   {
3071     operands[3] = gen_reg_rtx (SImode);
3073     if (TARGET_64BIT && <MODE>mode == SImode)
3074       {
3075         rtx t = gen_reg_rtx (DImode);
3077         emit_insn (gen_negsi2 (operands[3], operands[2]));
3078         emit_insn (gen_rotrsi3_extend (t, operands[1], operands[3]));
3079         t = gen_lowpart (SImode, t);
3080         SUBREG_PROMOTED_VAR_P (t) = 1;
3081         SUBREG_PROMOTED_SET (t, SRP_SIGNED);
3082         emit_move_insn (operands[0], t);
3083         DONE;
3084       }
3085   });
3087 (define_insn "alsl<mode>3"
3088   [(set (match_operand:GPR 0 "register_operand" "=r")
3089         (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
3090                               (match_operand 2 "const_immalsl_operand" ""))
3091                   (match_operand:GPR 3 "register_operand" "r")))]
3092   ""
3093   "alsl.<d>\t%0,%1,%3,%2"
3094   [(set_attr "type" "arith")
3095    (set_attr "mode" "<MODE>")])
3097 (define_insn "*alslsi3_extend"
3098   [(set (match_operand:DI 0 "register_operand" "=r")
3099         (any_extend:DI
3100           (plus:SI
3101             (ashift:SI (match_operand:SI 1 "register_operand" "r")
3102                        (match_operand 2 "const_immalsl_operand" ""))
3103             (match_operand:SI 3 "register_operand" "r"))))]
3104   "TARGET_64BIT"
3105   "alsl.w<u>\t%0,%1,%3,%2"
3106   [(set_attr "type" "arith")
3107    (set_attr "mode" "SI")])
3109 (define_insn "*alslsi3_extend_subreg"
3110   [(set (match_operand:DI 0 "register_operand" "=r")
3111         (any_extend:DI
3112           (plus:SI
3113             (subreg:SI
3114               (ashift:DI (match_operand:DI 1 "register_operand" "r")
3115                          (match_operand 2 "const_immalsl_operand" ""))
3116               0)
3117             (subreg:SI (match_operand:DI 3 "register_operand" "r") 0))))]
3118   "TARGET_64BIT"
3119   "alsl.w<u>\t%0,%1,%3,%2"
3120   [(set_attr "type" "arith")
3121    (set_attr "mode" "SI")])
3123 ;; The generic code prefers "(reg << shamt) [&|^] (mask << shamt)"
3124 ;; instead of "(reg [&|^] mask) << shamt" but we want the latter if
3125 ;; we don't need to load mask into an register, and either:
3126 ;; - (mask << shamt) needs to be loaded into an register, or
3127 ;; - shamt is a const_immalsl_operand, so the outer shift may be further
3128 ;;   combined with an add.
3129 (define_insn_and_split "<optab>_shift_reverse<X:mode>"
3130   [(set (match_operand:X 0 "register_operand" "=r")
3131         (any_bitwise:X
3132           (ashift:X (match_operand:X  1 "register_operand"  "r")
3133                     (match_operand:SI 2 "const_int_operand" "i"))
3134           (match_operand:X 3 "const_int_operand" "i")))]
3135   "(const_immalsl_operand (operands[2], SImode)
3136     || !<bitwise_operand> (operands[3], <MODE>mode))
3137    && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
3138                                        <MODE>mode)"
3139   "#"
3140   "&& true"
3141   [(set (match_dup 0) (any_bitwise:X (match_dup 1) (match_dup 3)))
3142    (set (match_dup 0) (ashift:X (match_dup 0) (match_dup 2)))]
3143   {
3144     operands[3] = loongarch_reassoc_shift_bitwise (<is_and>,
3145                                                    operands[2],
3146                                                    operands[3],
3147                                                    <MODE>mode);
3149     if (ins_zero_bitmask_operand (operands[3], <MODE>mode))
3150       {
3151         gcc_checking_assert (<is_and>);
3152         emit_move_insn (operands[0], operands[1]);
3153         operands[1] = operands[0];
3154       }
3155   })
3157 ;; The late_combine2 pass can handle slli.d + add.d => alsl.d, so we
3158 ;; already have slli.d + any_bitwise + add.d => any_bitwise + slli.d +
3159 ;; add.d => any_bitwise + alsl.d.  But late_combine2 cannot handle slli.d +
3160 ;; add.w => alsl.w, so implement slli.d + and + add.w => and + alsl.w on
3161 ;; our own.
3162 (define_insn_and_split "<optab>_alsl_reversesi_extended"
3163   [(set (match_operand:DI 0 "register_operand" "=&r")
3164         (sign_extend:DI
3165           (plus:SI
3166             (subreg:SI
3167               (any_bitwise:DI
3168                 (ashift:DI
3169                   (match_operand:DI 1 "register_operand" "r0")
3170                   (match_operand:SI 2 "const_immalsl_operand" ""))
3171                 (match_operand:DI 3 "const_int_operand" "i"))
3172               0)
3173             (match_operand:SI 4 "register_operand" "r"))))]
3174   "TARGET_64BIT
3175    && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
3176                                        SImode)"
3177   "#"
3178   "&& reload_completed"
3179   [; r0 = r1 [&|^] r3 is emitted in PREPARATION-STATEMENTS because we
3180    ; need to handle a special case, see below.
3181    (set (match_dup 0)
3182         (sign_extend:DI
3183           (plus:SI (ashift:SI (subreg:SI (match_dup 0) 0) (match_dup 2))
3184                    (match_dup 4))))]
3185   {
3186     operands[3] = loongarch_reassoc_shift_bitwise (<is_and>,
3187                                                    operands[2],
3188                                                    operands[3],
3189                                                    SImode);
3191     if (ins_zero_bitmask_operand (operands[3], SImode))
3192       {
3193         gcc_checking_assert (<is_and>);
3194         emit_move_insn (operands[0], operands[1]);
3195         operands[1] = operands[0];
3196       }
3198     if (operands[3] != CONSTM1_RTX (SImode))
3199       emit_insn (gen_<optab>di3 (operands[0], operands[1], operands[3]));
3200     else
3201       {
3202         /* Hmm would we really reach here?  If we reach here we'd have
3203            a miss-optimization in the generic code (as it should have
3204            optimized this to alslsi3_extend_subreg).  But let's be safe
3205            than sorry.  */
3206         gcc_checking_assert (<is_and>);
3207         emit_move_insn (operands[0], operands[1]);
3208       }
3209   })
3213 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
3215 (define_insn "revb_2h"
3216   [(set (match_operand:SI 0 "register_operand" "=r")
3217         (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3218                      (const_int 16)))]
3219   ""
3220   "revb.2h\t%0,%1"
3221   [(set_attr "type" "shift")])
3223 (define_insn "revb_2h_extend"
3224   [(set (match_operand:DI 0 "register_operand" "=r")
3225         (sign_extend:DI
3226           (rotatert:SI
3227             (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3228             (const_int 16))))]
3229   "TARGET_64BIT"
3230   "revb.2h\t%0,%1"
3231   [(set_attr "type" "shift")])
3233 (define_insn "bswaphi2"
3234   [(set (match_operand:HI 0 "register_operand" "=r")
3235         (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
3236   ""
3237   "revb.2h\t%0,%1"
3238   [(set_attr "type" "shift")])
3240 (define_insn "revb_2w"
3241   [(set (match_operand:DI 0 "register_operand" "=r")
3242         (rotatert:DI (bswap:DI (match_operand:DI 1 "register_operand" "r"))
3243                      (const_int 32)))]
3244   "TARGET_64BIT"
3245   "revb.2w\t%0,%1"
3246   [(set_attr "type" "shift")])
3248 (define_insn "*bswapsi2"
3249   [(set (match_operand:SI 0 "register_operand" "=r")
3250         (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3251   "TARGET_64BIT"
3252   "revb.2w\t%0,%1"
3253   [(set_attr "type" "shift")])
3255 (define_expand "bswapsi2"
3256   [(set (match_operand:SI 0 "register_operand" "=r")
3257         (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3258   ""
3260   if (!TARGET_64BIT)
3261     {
3262       rtx t = gen_reg_rtx (SImode);
3263       emit_insn (gen_revb_2h (t, operands[1]));
3264       emit_insn (gen_rotrsi3 (operands[0], t, GEN_INT (16)));
3265       DONE;
3266     }
3269 (define_insn "bswapdi2"
3270   [(set (match_operand:DI 0 "register_operand" "=r")
3271         (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3272   "TARGET_64BIT"
3273   "revb.d\t%0,%1"
3274   [(set_attr "type" "shift")])
3278 ;;  ....................
3280 ;;      CONDITIONAL BRANCHES
3282 ;;  ....................
3284 ;; Conditional branches
3286 (define_insn "*branch_fp_FCCmode"
3287   [(set (pc)
3288         (if_then_else
3289           (match_operator 1 "equality_operator"
3290               [(match_operand:FCC 2 "register_operand" "z")
3291                 (const_int 0)])
3292           (label_ref (match_operand 0 "" ""))
3293         (pc)))]
3294   "TARGET_HARD_FLOAT"
3296   return loongarch_output_conditional_branch (insn, operands,
3297                                               LARCH_BRANCH ("b%F1", "%Z2%0"),
3298                                               LARCH_BRANCH ("b%W1", "%Z2%0"));
3300   [(set_attr "type" "branch")])
3302 (define_insn "*branch_fp_inverted_FCCmode"
3303   [(set (pc)
3304         (if_then_else
3305           (match_operator 1 "equality_operator"
3306             [(match_operand:FCC 2 "register_operand" "z")
3307             (const_int 0)])
3308           (pc)
3309           (label_ref (match_operand 0 "" ""))))]
3310   "TARGET_HARD_FLOAT"
3312   return loongarch_output_conditional_branch (insn, operands,
3313                                               LARCH_BRANCH ("b%W1", "%Z2%0"),
3314                                               LARCH_BRANCH ("b%F1", "%Z2%0"));
3316   [(set_attr "type" "branch")])
3318 ;; Conditional branches on ordered comparisons with zero.
3320 (define_insn "*branch_order<mode>"
3321   [(set (pc)
3322         (if_then_else
3323          (match_operator 1 "order_operator"
3324                          [(match_operand:X 2 "register_operand" "r,r")
3325                           (match_operand:X 3 "reg_or_0_operand" "J,r")])
3326          (label_ref (match_operand 0 "" ""))
3327          (pc)))]
3328   ""
3329   { return loongarch_output_order_conditional_branch (insn, operands, false); }
3330   [(set_attr "type" "branch")])
3332 (define_insn "*branch_order<mode>_inverted"
3333   [(set (pc)
3334         (if_then_else
3335          (match_operator 1 "order_operator"
3336                          [(match_operand:X 2 "register_operand" "r,r")
3337                           (match_operand:X 3 "reg_or_0_operand" "J,r")])
3338          (pc)
3339          (label_ref (match_operand 0 "" ""))))]
3340   ""
3341   { return loongarch_output_order_conditional_branch (insn, operands, true); }
3342   [(set_attr "type" "branch")])
3344 ;; Conditional branch on equality comparison.
3346 (define_insn "branch_equality<mode>"
3347   [(set (pc)
3348         (if_then_else
3349          (match_operator 1 "equality_operator"
3350                          [(match_operand:X 2 "register_operand" "r")
3351                           (match_operand:X 3 "reg_or_0_operand" "rJ")])
3352          (label_ref (match_operand 0 "" ""))
3353          (pc)))]
3354   ""
3355   { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3356   [(set_attr "type" "branch")])
3359 (define_insn "*branch_equality<mode>_inverted"
3360   [(set (pc)
3361         (if_then_else
3362          (match_operator 1 "equality_operator"
3363                          [(match_operand:X 2 "register_operand" "r")
3364                           (match_operand:X 3 "reg_or_0_operand" "rJ")])
3365          (pc)
3366          (label_ref (match_operand 0 "" ""))))]
3367   ""
3368   { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3369   [(set_attr "type" "branch")])
3372 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3373 ;; QImode values so we can force zero-extension.
3374 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3376 (define_expand "cbranch<mode>4"
3377   [(set (pc)
3378         (if_then_else (match_operator 0 "comparison_operator"
3379                         [(match_operand:BR 1 "register_operand")
3380                          (match_operand:BR 2 "nonmemory_operand")])
3381                       (label_ref (match_operand 3 ""))
3382                       (pc)))]
3383   ""
3385   loongarch_expand_conditional_branch (operands);
3386   DONE;
3389 (define_expand "cbranch<mode>4"
3390   [(set (pc)
3391         (if_then_else (match_operator 0 "comparison_operator"
3392                         [(match_operand:ANYF 1 "register_operand")
3393                          (match_operand:ANYF 2 "register_operand")])
3394                       (label_ref (match_operand 3 ""))
3395                       (pc)))]
3396   ""
3398   loongarch_expand_conditional_branch (operands);
3399   DONE;
3402 ;; Used to implement built-in functions.
3403 (define_expand "condjump"
3404   [(set (pc)
3405         (if_then_else (match_operand 0)
3406                       (label_ref (match_operand 1))
3407                       (pc)))])
3411 ;;  ....................
3413 ;;      SETTING A REGISTER FROM A COMPARISON
3415 ;;  ....................
3417 ;; Destination is always set in SI mode.
3419 (define_expand "cstore<mode>4"
3420   [(set (match_operand:SI 0 "register_operand")
3421         (match_operator:SI 1 "loongarch_cstore_operator"
3422          [(match_operand:GPR 2 "register_operand")
3423           (match_operand:GPR 3 "nonmemory_operand")]))]
3424   ""
3426   loongarch_expand_scc (operands);
3427   DONE;
3430 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3431   [(set (match_operand:GPR 0 "register_operand" "=r")
3432         (eq:GPR (match_operand:X 1 "register_operand" "r")
3433                  (const_int 0)))]
3434   ""
3435   "sltui\t%0,%1,1"
3436   [(set_attr "type" "slt")
3437    (set_attr "mode" "<X:MODE>")])
3440 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3441   [(set (match_operand:GPR 0 "register_operand" "=r")
3442         (ne:GPR (match_operand:X 1 "register_operand" "r")
3443                  (const_int 0)))]
3444   ""
3445   "sltu\t%0,%.,%1"
3446   [(set_attr "type" "slt")
3447    (set_attr "mode" "<X:MODE>")])
3449 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3450   [(set (match_operand:GPR 0 "register_operand" "=r")
3451         (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3452                      (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3453   ""
3454   "slt<u>\t%0,%z2,%1"
3455   [(set_attr "type" "slt")
3456    (set_attr "mode" "<X:MODE>")])
3458 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3459   [(set (match_operand:GPR 0 "register_operand" "=r")
3460         (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3461                      (match_operand:X 2 "arith_operand" "rI")))]
3462   ""
3463   "slt<u>%i2\t%0,%1,%2";
3464   [(set_attr "type" "slt")
3465    (set_attr "mode" "<X:MODE>")])
3467 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3468   [(set (match_operand:GPR 0 "register_operand" "=r")
3469         (any_le:GPR (match_operand:X 1 "register_operand" "r")
3470                     (match_operand:X 2 "sle_operand" "")))]
3471   ""
3473   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3474   return "slt<u>i\t%0,%1,%2";
3476   [(set_attr "type" "slt")
3477    (set_attr "mode" "<X:MODE>")])
3481 ;;  ....................
3483 ;;      FLOATING POINT COMPARISONS
3485 ;;  ....................
3487 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3488   [(set (match_operand:FCC 0 "register_operand" "=z")
3489         (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3490                    (match_operand:ANYF 2 "register_operand" "f")))]
3491   ""
3492   "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3493   [(set_attr "type" "fcmp")
3494    (set_attr "mode" "FCC")])
3498 ;;  ....................
3500 ;;      UNCONDITIONAL BRANCHES
3502 ;;  ....................
3504 ;; Unconditional branches.
3506 (define_expand "jump"
3507   [(set (pc)
3508         (label_ref (match_operand 0)))])
3510 (define_insn "*jump_absolute"
3511   [(set (pc)
3512         (label_ref (match_operand 0)))]
3513   "!flag_pic"
3515   return "b\t%l0";
3517   [(set_attr "type" "branch")])
3519 (define_insn "*jump_pic"
3520   [(set (pc)
3521         (label_ref (match_operand 0)))]
3522   "flag_pic"
3524   return "b\t%0";
3526   [(set_attr "type" "branch")])
3528 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3529 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3530 ;; return prediction and the more general indirect branch prediction.
3532 (define_expand "indirect_jump"
3533   [(set (pc) (match_operand 0 "register_operand"))]
3534   ""
3536   operands[0] = force_reg (Pmode, operands[0]);
3537   emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3538   DONE;
3541 (define_insn "@indirect_jump<mode>"
3542   [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3543   ""
3544   "jr\t%0"
3545   [(set_attr "type" "jump")
3546    (set_attr "mode" "none")])
3548 (define_expand "tablejump"
3549   [(set (pc)
3550         (match_operand 0 "register_operand"))
3551    (use (label_ref (match_operand 1 "")))]
3552   ""
3554   if (flag_pic)
3555     operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3556                                        gen_rtx_LABEL_REF (Pmode,
3557                                                           operands[1]),
3558                                        NULL_RTX, 0, OPTAB_DIRECT);
3559   emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3560   DONE;
3563 (define_mode_attr mode_size [(DI "8") (SI "4")])
3565 (define_insn "@tablejump<mode>"
3566   [(set (pc)
3567         (match_operand:P 0 "register_operand" "e"))
3568    (use (label_ref (match_operand 1 "" "")))]
3569   ""
3570   {
3571     return TARGET_ANNOTATE_TABLEJUMP
3572       ? "1:jr\t%0\n\t"
3573         ".pushsection\t.discard.tablejump_annotate\n\t"
3574         "\t.<mode_size>byte\t1b\n\t"
3575         "\t.<mode_size>byte\t%1\n\t"
3576         ".popsection"
3577       : "jr\t%0";
3578   }
3579   [(set_attr "type" "jump")
3580    (set_attr "mode" "none")])
3585 ;;  ....................
3587 ;;      Function prologue/epilogue
3589 ;;  ....................
3592 (define_expand "prologue"
3593   [(const_int 1)]
3594   ""
3596   loongarch_expand_prologue ();
3597   DONE;
3600 ;; Block any insns from being moved before this point, since the
3601 ;; profiling call to mcount can use various registers that aren't
3602 ;; saved or used to pass arguments.
3604 (define_insn "blockage"
3605   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3606   ""
3607   ""
3608   [(set_attr "type" "ghost")
3609    (set_attr "mode" "none")])
3611 (define_insn "@probe_stack_range<P:mode>"
3612   [(set (match_operand:P 0 "register_operand" "=r")
3613         (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3614                             (match_operand:P 2 "register_operand" "r")
3615                             (match_operand:P 3 "register_operand" "r")]
3616                             UNSPECV_PROBE_STACK_RANGE))]
3617   ""
3619   return loongarch_output_probe_stack_range (operands[0],
3620                                              operands[2],
3621                                              operands[3]);
3623   [(set_attr "type" "unknown")
3624    (set_attr "mode" "<MODE>")])
3626 (define_expand "epilogue"
3627   [(const_int 2)]
3628   ""
3630   loongarch_expand_epilogue (NORMAL_RETURN);
3631   DONE;
3634 (define_expand "sibcall_epilogue"
3635   [(const_int 2)]
3636   ""
3638   loongarch_expand_epilogue (SIBCALL_RETURN);
3639   DONE;
3642 ;; Trivial return.  Make it look like a normal return insn as that
3643 ;; allows jump optimizations to work better.
3645 (define_expand "return"
3646   [(simple_return)]
3647   "loongarch_can_use_return_insn ()"
3648   { })
3650 (define_expand "simple_return"
3651   [(simple_return)]
3652   ""
3653   { })
3655 (define_insn "*<optab>"
3656   [(any_return)]
3657   ""
3659   operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3660   return "jr\t%0";
3662   [(set_attr "type" "jump")
3663    (set_attr "mode" "none")])
3665 ;; Normal return.
3667 (define_insn "<optab>_internal"
3668   [(any_return)
3669    (use (match_operand 0 "pmode_register_operand" ""))]
3670   ""
3671   "jr\t%0"
3672   [(set_attr "type" "jump")
3673    (set_attr "mode" "none")])
3675 ;; Exception return.
3676 (define_insn "loongarch_ertn"
3677   [(return)
3678    (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3679   ""
3680   "ertn"
3681   [(set_attr "type" "trap")
3682    (set_attr "mode" "none")])
3684 ;; This is used in compiling the unwind routines.
3685 (define_expand "eh_return"
3686   [(use (match_operand 0 "general_operand"))]
3687   ""
3689   if (GET_MODE (operands[0]) != word_mode)
3690     operands[0] = convert_to_mode (word_mode, operands[0], 0);
3691   if (TARGET_64BIT)
3692     emit_insn (gen_eh_set_ra_di (operands[0]));
3693   else
3694     emit_insn (gen_eh_set_ra_si (operands[0]));
3696   emit_jump_insn (gen_eh_return_internal ());
3697   emit_barrier ();
3698   DONE;
3701 (define_insn_and_split "eh_return_internal"
3702   [(eh_return)]
3703   ""
3704   "#"
3705   "epilogue_completed"
3706   [(const_int 0)]
3708   loongarch_expand_epilogue (EXCEPTION_RETURN);
3709   DONE;
3712 ;; Clobber the return address on the stack.  We can't expand this
3713 ;; until we know where it will be put in the stack frame.
3715 (define_insn "eh_set_ra_si"
3716   [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3717    (clobber (match_scratch:SI 1 "=&r"))]
3718   "! TARGET_64BIT"
3719   "#")
3721 (define_insn "eh_set_ra_di"
3722   [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3723    (clobber (match_scratch:DI 1 "=&r"))]
3724   "TARGET_64BIT"
3725   "#")
3727 (define_split
3728   [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3729    (clobber (match_scratch 1))]
3730   "reload_completed"
3731   [(const_int 0)]
3733   loongarch_set_return_address (operands[0], operands[1]);
3734   DONE;
3740 ;;  ....................
3742 ;;      FUNCTION CALLS
3744 ;;  ....................
3746 ;; Sibling calls.  All these patterns use jump instructions.
3748 (define_expand "sibcall"
3749   [(parallel [(call (match_operand 0 "")
3750                     (match_operand 1 ""))
3751               (use (match_operand 2 ""))        ;; next_arg_reg
3752               (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
3753   ""
3755   rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3757   if (GET_CODE (target) == LO_SUM)
3758     emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3759                                             XEXP (target, 1),
3760                                             operands[1]));
3761   else
3762     {
3763       rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3765       if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3766         clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3767                      gen_rtx_REG (Pmode, T0_REGNUM));
3768     }
3769   DONE;
3772 (define_insn "sibcall_internal"
3773   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3774          (match_operand 1 "" ""))]
3775   "SIBLING_CALL_P (insn)"
3777   switch (which_alternative)
3778     {
3779     case 0:
3780       return "jr\t%0";
3781     case 1:
3782       if (TARGET_CMODEL_MEDIUM)
3783         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3784       else
3785         return "b\t%0";
3786     case 2:
3787       if (TARGET_CMODEL_MEDIUM)
3788         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3789       else
3790         return "b\t%%plt(%0)";
3791     default:
3792       gcc_unreachable ();
3793     }
3795   [(set_attr "jirl" "indirect,direct,direct")])
3797 (define_insn "@sibcall_internal_1<mode>"
3798   [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3799                           (match_operand:P 1 "symbolic_operand" "")))
3800          (match_operand 2 "" ""))]
3801   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3802   "jirl\t$r0,%0,%%pc_lo12(%1)"
3803   [(set_attr "jirl" "indirect")])
3805 (define_expand "sibcall_value"
3806   [(parallel [(set (match_operand 0 "")
3807                    (call (match_operand 1 "")
3808                          (match_operand 2 "")))
3809               (use (match_operand 3 ""))])]             ;; next_arg_reg
3810   ""
3812   rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3814  /*  Handle return values created by loongarch_pass_fpr_pair.  */
3815   if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3816     {
3817       rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3818       rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3820       if (GET_CODE (target) == LO_SUM)
3821         emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3822                                                            XEXP (target, 0),
3823                                                            XEXP (target, 1),
3824                                                            operands[2],
3825                                                            arg2));
3826       else
3827         {
3828           rtx call
3829             = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3830                                                                    target,
3831                                                                    operands[2],
3832                                                                    arg2));
3834           if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3835             clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3836                         gen_rtx_REG (Pmode, T0_REGNUM));
3837         }
3838     }
3839    else
3840     {
3841       /*  Handle return values created by loongarch_return_fpr_single.  */
3842       if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3843         operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3845       if (GET_CODE (target) == LO_SUM)
3846         emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3847                                                   XEXP (target, 0),
3848                                                   XEXP (target, 1),
3849                                                   operands[2]));
3850       else
3851         {
3852           rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3853                                                                  target,
3854                                                                  operands[2]));
3856           if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3857             clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3858                         gen_rtx_REG (Pmode, T0_REGNUM));
3859         }
3860     }
3861   DONE;
3864 (define_insn "sibcall_value_internal"
3865   [(set (match_operand 0 "register_operand" "")
3866         (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3867               (match_operand 2 "" "")))]
3868   "SIBLING_CALL_P (insn)"
3870   switch (which_alternative)
3871     {
3872     case 0:
3873       return "jr\t%1";
3874     case 1:
3875       if (TARGET_CMODEL_MEDIUM)
3876         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3877       else
3878         return "b\t%1";
3879     case 2:
3880       if (TARGET_CMODEL_MEDIUM)
3881         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3882       else
3883         return "b\t%%plt(%1)";
3884     default:
3885       gcc_unreachable ();
3886     }
3888   [(set_attr "jirl" "indirect,direct,direct")])
3890 (define_insn "@sibcall_value_internal_1<mode>"
3891   [(set (match_operand 0 "register_operand" "")
3892         (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3893                                (match_operand:P 2 "symbolic_operand" "")))
3894               (match_operand 3 "" "")))]
3895   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3896   "jirl\t$r0,%1,%%pc_lo12(%2)"
3897   [(set_attr "jirl" "indirect")])
3899 (define_insn "sibcall_value_multiple_internal"
3900   [(set (match_operand 0 "register_operand" "")
3901         (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3902               (match_operand 2 "" "")))
3903    (set (match_operand 3 "register_operand" "")
3904         (call (mem:SI (match_dup 1))
3905               (match_dup 2)))]
3906   "SIBLING_CALL_P (insn)"
3908   switch (which_alternative)
3909     {
3910     case 0:
3911       return "jr\t%1";
3912     case 1:
3913       if (TARGET_CMODEL_MEDIUM)
3914         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3915       else
3916         return "b\t%1";
3917     case 2:
3918       if (TARGET_CMODEL_MEDIUM)
3919         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3920       else
3921         return "b\t%%plt(%1)";
3922     default:
3923       gcc_unreachable ();
3924     }
3926   [(set_attr "jirl" "indirect,direct,direct")])
3928 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3929   [(set (match_operand 0 "register_operand" "")
3930         (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3931                                 (match_operand:P 2 "symbolic_operand" "")]
3932                       UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3933               (match_operand 3 "" "")))
3934    (set (match_operand 4 "register_operand" "")
3935         (call (mem:P (unspec:P [(match_dup 1)
3936                                 (match_dup 2)]
3937                       UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3938               (match_dup 3)))]
3939   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3940   "jirl\t$r0,%1,%%pc_lo12(%2)"
3941   [(set_attr "jirl" "indirect")])
3943 (define_expand "call"
3944   [(parallel [(call (match_operand 0 "")
3945                     (match_operand 1 ""))
3946               (use (match_operand 2 ""))        ;; next_arg_reg
3947               (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
3948   ""
3950   rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3952   if (GET_CODE (target) == LO_SUM)
3953     emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3954                                          XEXP (target, 1), operands[1]));
3955   else
3956     emit_call_insn (gen_call_internal (target, operands[1]));
3957   DONE;
3960 (define_insn "call_internal"
3961   [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3962          (match_operand 1 "" ""))
3963    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3964   ""
3966   switch (which_alternative)
3967     {
3968     case 0:
3969       return "jirl\t$r1,%0,0";
3970     case 1:
3971       if (TARGET_CMODEL_MEDIUM)
3972         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3973       else
3974         return "bl\t%0";
3975     case 2:
3976       if (TARGET_CMODEL_MEDIUM)
3977         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3978       else
3979         return "bl\t%%plt(%0)";
3980     default:
3981       gcc_unreachable ();
3982     }
3984   [(set_attr "jirl" "indirect,direct,direct")])
3986 (define_insn "@call_internal_1<mode>"
3987   [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3988                           (match_operand:P 1 "symbolic_operand" "")))
3989          (match_operand 2 "" ""))
3990    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3991   "TARGET_CMODEL_MEDIUM"
3992   "jirl\t$r1,%0,%%pc_lo12(%1)"
3993   [(set_attr "jirl" "indirect")])
3995 (define_expand "call_value"
3996   [(parallel [(set (match_operand 0 "")
3997                    (call (match_operand 1 "")
3998                          (match_operand 2 "")))
3999               (use (match_operand 3 ""))])]             ;; next_arg_reg
4000   ""
4002   rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
4003   /* Handle return values created by loongarch_pass_fpr_pair.  */
4004   if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
4005     {
4006       rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
4007       rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
4009       if (GET_CODE (target) == LO_SUM)
4010         emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
4011                                                             XEXP (target, 0),
4012                                                             XEXP (target, 1),
4013                                                             operands[2], arg2));
4014       else
4015         emit_call_insn (gen_call_value_multiple_internal (arg1, target,
4016                                                         operands[2], arg2));
4017     }
4018    else
4019     {
4020       /* Handle return values created by loongarch_return_fpr_single.  */
4021       if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
4022             operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
4024       if (GET_CODE (target) == LO_SUM)
4025         emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
4026                                                    XEXP (target, 0),
4027                                                    XEXP (target, 1),
4028                                                    operands[2]));
4029       else
4030         emit_call_insn (gen_call_value_internal (operands[0], target,
4031                                                operands[2]));
4032     }
4033   DONE;
4036 (define_insn "call_value_internal"
4037   [(set (match_operand 0 "register_operand" "")
4038         (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4039               (match_operand 2 "" "")))
4040    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4041   ""
4043   switch (which_alternative)
4044     {
4045     case 0:
4046       return "jirl\t$r1,%1,0";
4047     case 1:
4048       if (TARGET_CMODEL_MEDIUM)
4049         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4050       else
4051         return "bl\t%1";
4052     case 2:
4053       if (TARGET_CMODEL_MEDIUM)
4054         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4055       else
4056         return "bl\t%%plt(%1)";
4057     default:
4058       gcc_unreachable ();
4059     }
4061   [(set_attr "jirl" "indirect,direct,direct")])
4063 (define_insn "@call_value_internal_1<mode>"
4064   [(set (match_operand 0 "register_operand" "")
4065         (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
4066                                (match_operand:P 2 "symbolic_operand" "")))
4067               (match_operand 3 "" "")))
4068    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4069   "TARGET_CMODEL_MEDIUM"
4070   "jirl\t$r1,%1,%%pc_lo12(%2)"
4071   [(set_attr "jirl" "indirect")])
4073 (define_insn "call_value_multiple_internal"
4074   [(set (match_operand 0 "register_operand" "")
4075         (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4076               (match_operand 2 "" "")))
4077    (set (match_operand 3 "register_operand" "")
4078         (call (mem:SI (match_dup 1))
4079               (match_dup 2)))
4080    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4081   ""
4083   switch (which_alternative)
4084     {
4085     case 0:
4086       return "jirl\t$r1,%1,0";
4087     case 1:
4088       if (TARGET_CMODEL_MEDIUM)
4089         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4090       else
4091         return "bl\t%1";
4092     case 2:
4093       if (TARGET_CMODEL_MEDIUM)
4094         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4095       else
4096         return "bl\t%%plt(%1)";
4097     default:
4098       gcc_unreachable ();
4099     }
4101   [(set_attr "jirl" "indirect,direct,direct")])
4103 (define_insn "@call_value_multiple_internal_1<mode>"
4104   [(set (match_operand 0 "register_operand" "")
4105         (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
4106                                 (match_operand:P 2 "symbolic_operand" "")]
4107                       UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4108               (match_operand 3 "" "")))
4109    (set (match_operand 4 "register_operand" "")
4110         (call (mem:P (unspec:P [(match_dup 1)
4111                                 (match_dup 2)]
4112                       UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4113               (match_dup 3)))
4114    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4115   "TARGET_CMODEL_MEDIUM"
4116   "jirl\t$r1,%1,%%pc_lo12(%2)"
4117   [(set_attr "jirl" "indirect")])
4120 ;; Call subroutine returning any type.
4121 (define_expand "untyped_call"
4122   [(parallel [(call (match_operand 0 "")
4123                     (const_int 0))
4124               (match_operand 1 "")
4125               (match_operand 2 "")])]
4126   ""
4128   int i;
4130   emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
4132   for (i = 0; i < XVECLEN (operands[2], 0); i++)
4133     {
4134       rtx set = XVECEXP (operands[2], 0, i);
4135       loongarch_emit_move (SET_DEST (set), SET_SRC (set));
4136     }
4138   emit_insn (gen_blockage ());
4139   DONE;
4143 ;;  ....................
4145 ;;      MISC.
4147 ;;  ....................
4150 (define_insn "prefetch"
4151   [(prefetch (match_operand 0 "address_operand" "ZD")
4152              (match_operand 1 "const_int_operand" "n")
4153              (match_operand 2 "const_int_operand" "n"))]
4154   ""
4156   switch (INTVAL (operands[1]))
4157   {
4158     case 0:
4159     case 2: return "preld\t0,%a0";
4160     case 1: return "preld\t8,%a0";
4161     default: gcc_unreachable ();
4162   }
4165 (define_insn "nop"
4166   [(const_int 0)]
4167   ""
4168   "nop"
4169   [(set_attr "type" "nop")
4170    (set_attr "mode" "none")])
4172 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
4173 (define_insn "loongarch_movfcsr2gr"
4174   [(set (match_operand:SI 0 "register_operand" "=r")
4175         (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
4176                              UNSPECV_MOVFCSR2GR))]
4177   "TARGET_HARD_FLOAT"
4178   "movfcsr2gr\t%0,$r%1")
4180 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
4181 (define_insn "loongarch_movgr2fcsr"
4182   [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
4183                      (match_operand:SI 1 "register_operand" "r")]
4184                      UNSPECV_MOVGR2FCSR)]
4185   "TARGET_HARD_FLOAT"
4186   "movgr2fcsr\t$r%0,%1")
4188 (define_insn "fclass_<fmt>"
4189   [(set (match_operand:SI 0 "register_operand" "=f")
4190         (unspec:SI [(match_operand:ANYF 1 "register_operand" "f")]
4191                    UNSPEC_FCLASS))]
4192   "TARGET_HARD_FLOAT"
4193   "fclass.<fmt>\t%0,%1"
4194   [(set_attr "type" "unknown")
4195    (set_attr "mode" "<MODE>")])
4197 (define_int_iterator FCLASS_MASK [68 136 952])
4198 (define_int_attr fclass_optab
4199   [(68  "isinf")
4200    (136 "isnormal")
4201    (952 "isfinite")])
4203 (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
4204   [(match_operand:SI   0 "register_operand" "=r")
4205    (match_operand:ANYF 1 "register_operand" " f")
4206    (const_int FCLASS_MASK)]
4207   "TARGET_HARD_FLOAT"
4208   {
4209     rtx ft0 = gen_reg_rtx (SImode);
4210     rtx t0 = gen_reg_rtx (word_mode);
4211     rtx mask = GEN_INT (<FCLASS_MASK>);
4213     emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
4215     if (TARGET_64BIT)
4216       emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
4217     else
4218       emit_move_insn (t0, ft0);
4220     emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
4221     emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
4223     if (TARGET_64BIT)
4224       {
4225         t0 = lowpart_subreg (SImode, t0, DImode);
4226         SUBREG_PROMOTED_VAR_P (t0) = 1;
4227         SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
4228       }
4230     emit_move_insn (operands[0], t0);
4232     DONE;
4233   })
4235 (define_insn "bytepick_w_<bytepick_imm>"
4236   [(set (match_operand:SI 0 "register_operand" "=r")
4237         (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
4238                              (const_int <bytepick_w_lshiftrt_amount>))
4239                 (ashift:SI (match_operand:SI 2 "register_operand" "r")
4240                            (const_int bytepick_w_ashift_amount))))]
4241   ""
4242   "bytepick.w\t%0,%1,%2,<bytepick_imm>"
4243   [(set_attr "mode" "SI")])
4245 (define_mode_attr bitsize [(QI "8") (HI "16")])
4246 (define_mode_attr bytepick_imm [(QI "3") (HI "2")])
4247 (define_mode_attr bytepick_w_ashift_amount [(QI "24") (HI "16")])
4249 (define_insn "bytepick_w_<bytepick_imm>_extend"
4250   [(set (match_operand:DI 0 "register_operand" "=r")
4251         (ior:DI
4252           (ashift:DI
4253             (sign_extend:DI
4254               (subreg:SHORT (match_operand:DI 1 "register_operand" "r") 0))
4255             (const_int <bytepick_w_ashift_amount>))
4256           (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4257                            (const_int <bytepick_w_ashift_amount>)
4258                            (const_int <bitsize>))))]
4259   "TARGET_64BIT"
4260   "bytepick.w\t%0,%2,%1,<bytepick_imm>"
4261   [(set_attr "mode" "SI")])
4263 (define_insn "bytepick_w_1_extend"
4264   [(set (match_operand:DI 0 "register_operand" "=r")
4265         (ior:DI
4266           (ashift:DI
4267             (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
4268                          (const_int 24)
4269                          (const_int 0))
4270         (const_int 8))
4271           (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4272                            (const_int 8)
4273                            (const_int 24))))]
4274   "TARGET_64BIT"
4275   "bytepick.w\t%0,%2,%1,1"
4276   [(set_attr "mode" "SI")])
4278 (define_insn "bytepick_d_<bytepick_imm>"
4279   [(set (match_operand:DI 0 "register_operand" "=r")
4280         (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
4281                           (const_int <bytepick_d_lshiftrt_amount>))
4282                 (ashift (match_operand:DI 2 "register_operand" "r")
4283                         (const_int bytepick_d_ashift_amount))))]
4284   "TARGET_64BIT"
4285   "bytepick.d\t%0,%1,%2,<bytepick_imm>"
4286   [(set_attr "mode" "DI")])
4288 (define_insn "bytepick_d_<bytepick_imm>_rev"
4289   [(set (match_operand:DI 0 "register_operand" "=r")
4290         (ior:DI (ashift (match_operand:DI 1 "register_operand" "r")
4291                         (const_int bytepick_d_ashift_amount))
4292                 (lshiftrt (match_operand:DI 2 "register_operand" "r")
4293                           (const_int <bytepick_d_lshiftrt_amount>))))]
4294   "TARGET_64BIT"
4295   "bytepick.d\t%0,%2,%1,<bytepick_imm>"
4296   [(set_attr "mode" "DI")])
4298 (define_insn "bitrev_4b"
4299   [(set (match_operand:SI 0 "register_operand" "=r")
4300         (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
4301                     UNSPEC_BITREV_4B))]
4302   ""
4303   "bitrev.4b\t%0,%1"
4304   [(set_attr "type" "unknown")
4305    (set_attr "mode" "SI")])
4307 (define_insn "bitrev_8b"
4308   [(set (match_operand:DI 0 "register_operand" "=r")
4309         (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4310                     UNSPEC_BITREV_8B))]
4311   ""
4312   "bitrev.8b\t%0,%1"
4313   [(set_attr "type" "unknown")
4314    (set_attr "mode" "DI")])
4316 (define_insn "@rbit<mode>"
4317   [(set (match_operand:GPR 0 "register_operand" "=r")
4318         (bitreverse:GPR (match_operand:GPR 1 "register_operand" "r")))]
4319   ""
4320   "bitrev.<size>\t%0,%1"
4321   [(set_attr "type" "unknown")
4322    (set_attr "mode" "<MODE>")])
4324 (define_insn "rbitsi_extended"
4325   [(set (match_operand:DI 0 "register_operand" "=r")
4326         (sign_extend:DI
4327           (bitreverse:SI (match_operand:SI 1 "register_operand" "r"))))]
4328   "TARGET_64BIT"
4329   "bitrev.w\t%0,%1"
4330   [(set_attr "type" "unknown")
4331    (set_attr "mode" "SI")])
4333 ;; If we don't care high bits, bitrev.4b can reverse bits of values in
4334 ;; QImode.
4335 (define_insn "rbitqi"
4336   [(set (match_operand:QI 0 "register_operand" "=r")
4337         (bitreverse:QI (match_operand:QI 1 "register_operand" "r")))]
4338   ""
4339   "bitrev.4b\t%0,%1"
4340   [(set_attr "type" "unknown")
4341    (set_attr "mode" "SI")])
4343 ;; For HImode it's a little complicated...
4344 (define_expand "rbithi"
4345   [(match_operand:HI 0 "register_operand")
4346    (match_operand:HI 1 "register_operand")]
4347   ""
4348   {
4349     rtx t = gen_reg_rtx (word_mode);
4351     /* Oh, using paradoxical subreg.  I learnt the trick from RISC-V,
4352        hoping we won't be blown up altogether one day.  */
4353     emit_insn (gen_rbit(word_mode, t,
4354                         gen_lowpart (word_mode, operands[1])));
4355     t = expand_simple_binop (word_mode, LSHIFTRT, t,
4356                              GEN_INT (GET_MODE_BITSIZE (word_mode) - 16),
4357                              NULL_RTX, false, OPTAB_DIRECT);
4359     t = gen_lowpart (HImode, t);
4360     SUBREG_PROMOTED_VAR_P (t) = 1;
4361     SUBREG_PROMOTED_SET (t, SRP_UNSIGNED);
4362     emit_move_insn (operands[0], t);
4364     DONE;
4365   })
4367 (define_insn "@stack_tie<mode>"
4368   [(set (mem:BLK (scratch))
4369         (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4370                      (match_operand:X 1 "register_operand" "r")]
4371                      UNSPEC_TIE))]
4372   ""
4373   ""
4374   [(set_attr "length" "0")
4375    (set_attr "type" "ghost")])
4377 ;; Named pattern for expanding thread pointer reference.
4378 (define_expand "get_thread_pointer<mode>"
4379   [(set (match_operand:P 0 "register_operand" "=r")
4380         (reg:P TP_REGNUM))]
4381   "HAVE_AS_TLS"
4382   {})
4384 (define_split
4385   [(match_operand 0 "small_data_pattern")]
4386   "reload_completed"
4387   [(match_dup 0)]
4388   { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4391 ;; Match paired HI/SI/SF/DFmode load/stores.
4392 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4393   [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4394   "=&r,f,m,m,&r,ZC")
4395         (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4396    (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4397    "=r,f,m,m,r,ZC")
4398         (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4399   "reload_completed"
4400   {
4401     /* The load destination does not overlap the source.  */
4402     gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4403     output_asm_insn (loongarch_output_move (operands),
4404                      operands);
4405     output_asm_insn (loongarch_output_move (&operands[2]),
4406                      &operands[2]);
4407     return "";
4408   }
4409   [(set_attr "move_type"
4410   "load,fpload,store,fpstore,load,store")
4411    (set_attr "insn_count" "2,2,2,2,2,2")])
4413 ;; 2 HI/SI/SF/DF loads are bonded.
4414 (define_peephole2
4415   [(set (match_operand:JOIN_MODE 0 "register_operand")
4416         (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4417    (set (match_operand:JOIN_MODE 2 "register_operand")
4418         (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4419   "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4420   [(parallel [(set (match_dup 0)
4421                    (match_dup 1))
4422               (set (match_dup 2)
4423                    (match_dup 3))])]
4424   "")
4426 ;; 2 HI/SI/SF/DF stores are bonded.
4427 (define_peephole2
4428   [(set (match_operand:JOIN_MODE 0 "memory_operand")
4429         (match_operand:JOIN_MODE 1 "register_operand"))
4430    (set (match_operand:JOIN_MODE 2 "memory_operand")
4431         (match_operand:JOIN_MODE 3 "register_operand"))]
4432   "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4433   [(parallel [(set (match_dup 0)
4434                    (match_dup 1))
4435               (set (match_dup 2)
4436                    (match_dup 3))])]
4437   "")
4439 ;; Match paired HImode loads.
4440 (define_insn "*join2_loadhi"
4441   [(set (match_operand:SI 0 "register_operand" "=&r")
4442         (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4443    (set (match_operand:SI 2 "register_operand" "=r")
4444         (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4445   "reload_completed"
4446   {
4447     /* The load destination does not overlap the source.  */
4448     gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4449     output_asm_insn ("ld.h<u>\t%0,%1", operands);
4450     output_asm_insn ("ld.h<u>\t%2,%3", operands);
4452     return "";
4453   }
4454   [(set_attr "move_type" "load")
4455    (set_attr "insn_count" "2")])
4458 ;; 2 HI loads are bonded.
4459 (define_peephole2
4460   [(set (match_operand:SI 0 "register_operand")
4461         (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4462    (set (match_operand:SI 2 "register_operand")
4463         (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4464   "loongarch_load_store_bonding_p (operands, HImode, true)"
4465   [(parallel [(set (match_dup 0)
4466                    (any_extend:SI (match_dup 1)))
4467               (set (match_dup 2)
4468                    (any_extend:SI (match_dup 3)))])]
4469   "")
4473 (define_int_iterator CRC [UNSPEC_CRC UNSPEC_CRCC])
4474 (define_int_attr crc [(UNSPEC_CRC "crc") (UNSPEC_CRCC "crcc")])
4476 (define_insn "loongarch_<crc>_w_<size>_w"
4477   [(set (match_operand:SI 0 "register_operand" "=r")
4478         (unspec:SI [(match_operand:QHWD 1 "register_operand" "r")
4479                    (match_operand:SI 2 "register_operand" "r")]
4480                      CRC))]
4481   ""
4482   "<crc>.w.<size>.w\t%0,%1,%2"
4483   [(set_attr "type" "unknown")
4484    (set_attr "mode" "<MODE>")])
4486 (define_insn "loongarch_<crc>_w_<size>_w_extended"
4487   [(set (match_operand:DI 0 "register_operand" "=r")
4488         (sign_extend:DI
4489           (unspec:SI [(match_operand:QHWD 1 "register_operand" "r")
4490                       (match_operand:SI 2 "register_operand" "r")]
4491                      CRC)))]
4492   "TARGET_64BIT"
4493   "<crc>.w.<size>.w\t%0,%1,%2"
4494   [(set_attr "type" "unknown")
4495    (set_attr "mode" "<MODE>")])
4497 (define_expand "crc_rev<mode>si4"
4498   [(match_operand:SI    0 "register_operand")   ; new_chksum
4499    (match_operand:SI    1 "register_operand")   ; old_chksum
4500    (match_operand:SUBDI 2 "reg_or_0_operand")   ; msg
4501    (match_operand       3 "const_int_operand")] ; poly
4502   ""
4503   {
4504     unsigned HOST_WIDE_INT poly = UINTVAL (operands[3]);
4505     rtx msg = operands[2];
4506     rtx (*crc_insn)(rtx, rtx, rtx) = nullptr;
4508     /* TODO: Review this when adding LA32 support.  If we're going to
4509        support CRC instructions on LA32 we'll need a "-mcrc" switch as
4510        they are optional on LA32.  */
4512     if (TARGET_64BIT)
4513       {
4514         if (poly == reflect_hwi (0xedb88320u, 32))
4515           crc_insn = gen_loongarch_crc_w_<size>_w;
4516         else if (poly == reflect_hwi (0x82f63b78u, 32))
4517           crc_insn = gen_loongarch_crcc_w_<size>_w;
4518       }
4520     if (crc_insn)
4521       {
4522         /* We cannot make crc_insn to accept const0_rtx easily:
4523            it's not possible to figure out the mode of const0_rtx so we'd
4524            have to separate both UNSPEC_CRC and UNSPEC_CRCC to 4 different
4525            UNSPECs.  Instead just hack it around here.  */
4526         if (msg == const0_rtx)
4527           msg = gen_rtx_REG (<MODE>mode, 0);
4529         emit_insn (crc_insn (operands[0], msg, operands[1]));
4530       }
4531     else
4532       {
4533         /* No CRC instruction is suitable, use the generic table-based
4534            implementation but optimize bit reversion.  */
4535         auto rbit = [](rtx *r)
4536           {
4537             /* Well, this is ugly.  The problem is
4538                expand_reversed_crc_table_based only accepts one helper
4539                for reversing data elements and CRC states.  */
4540             auto mode = GET_MODE (*r);
4541             auto rbit = (mode == <MODE>mode ? gen_rbit<mode> : gen_rbitsi);
4542             rtx out = gen_reg_rtx (mode);
4544             emit_insn (rbit (out, *r));
4545             *r = out;
4546           };
4547         expand_reversed_crc_table_based (operands[0], operands[1],
4548                                          msg, operands[3], <MODE>mode,
4549                                          rbit);
4550       }
4551     DONE;
4552   })
4554 (define_insn_and_split "*crc_combine"
4555   [(set (match_operand:SI 0 "register_operand" "=r,r")
4556         (unspec:SI
4557           [(reg:SUBDI 0)
4558            (subreg:SI
4559              (xor:DI
4560                (match_operand:DI 1 "register_operand" "r,r")
4561                ; Our LOAD_EXTEND_OP makes this same as sign_extend
4562                ; if SUBDI is SI, or zero_extend if SUBDI is QI or HI.
4563                ; For the former the high bits in rk are ignored by
4564                ; crc.w.w.w anyway, for the latter the zero extension is
4565                ; necessary for the correctness of this transformation.
4566                (subreg:DI
4567                  (match_operand:SUBDI 2 "memory_operand" "m,k") 0)) 0)]
4568           CRC))]
4569   "TARGET_64BIT && loongarch_pre_reload_split ()"
4570   "#"
4571   "&& true"
4572   [(set (match_dup 3) (match_dup 2))
4573    (set (match_dup 0)
4574         (unspec:SI [(match_dup 3) (subreg:SI (match_dup 1) 0)] CRC))]
4575   {
4576     operands[3] = gen_reg_rtx (<MODE>mode);
4577   })
4579 ;; With normal or medium code models, if the only use of a pc-relative
4580 ;; address is for loading or storing a value, then relying on linker
4581 ;; relaxation is not better than emitting the machine instruction directly.
4582 ;; Even if the la.local pseudo op can be relaxed, we get:
4584 ;;     pcaddi     $t0, %pcrel_20(x)
4585 ;;     ld.d       $t0, $t0, 0
4587 ;; There are still two instructions, same as using the machine instructions
4588 ;; and explicit relocs:
4590 ;;     pcalau12i  $t0, %pc_hi20(x)
4591 ;;     ld.d       $t0, $t0, %pc_lo12(x)
4593 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4594 ;; 3 instructions).
4595 (define_insn_and_rewrite "simple_load<mode>"
4596   [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4597         (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4598   "loongarch_pre_reload_split ()
4599    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4600    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4601   "#"
4602   "&& true"
4603   {
4604     operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4605   })
4607 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4608   [(set (match_operand:GPR 0 "register_operand" "=r")
4609         (any_extend:GPR
4610           (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4611   "loongarch_pre_reload_split ()
4612    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4613    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4614   "#"
4615   "&& true"
4616   {
4617     operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4618   })
4620 (define_insn_and_rewrite "simple_store<mode>"
4621   [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4622         (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4623   "loongarch_pre_reload_split ()
4624    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4625    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4626   "#"
4627   "&& true"
4628   {
4629     operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4630   })
4632 ;; Synchronization instructions.
4634 (include "sync.md")
4636 (include "generic.md")
4637 (include "la464.md")
4639 ; The LoongArch SIMD Instructions.
4640 (include "simd.md")
4642 (define_c_enum "unspec" [
4643   UNSPEC_ADDRESS_FIRST