Daily bump.
[official-gcc.git] / gcc / config / loongarch / loongarch.md
blobf70ca85bfb386ad1a30f3241d94bcfd761e87af6
1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C) 2021-2024 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 neg_bitwise [and ior])
490 ;; This code iterator allows unsigned and signed division to be generated
491 ;; from the same template.
492 (define_code_iterator any_div [div udiv mod umod])
494 ;; This code iterator allows addition and subtraction to be generated
495 ;; from the same template.
496 (define_code_iterator addsub [plus minus])
498 ;; This code iterator allows addition and multiplication to be generated
499 ;; from the same template.
500 (define_code_iterator addmul [plus mult])
502 ;; This code iterator allows addition subtraction and multiplication to be
503 ;; generated from the same template
504 (define_code_iterator addsubmul [plus minus mult])
506 ;; This code iterator allows all native floating-point comparisons to be
507 ;; generated from the same template.
508 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
509                              ordered ltgt ne ge gt unge ungt])
511 ;; Equality operators.
512 (define_code_iterator equality_op [eq ne])
514 ;; These code iterators allow the signed and unsigned scc operations to use
515 ;; the same template.
516 (define_code_iterator any_gt [gt gtu])
517 (define_code_iterator any_lt [lt ltu])
518 (define_code_iterator any_le [le leu])
520 (define_code_iterator any_return [return simple_return])
522 ;; <u> expands to an empty string when doing a signed operation and
523 ;; "u" when doing an unsigned operation.
524 (define_code_attr u [(sign_extend "") (zero_extend "u")
525                      (div "") (udiv "u")
526                      (mod "") (umod "u")
527                      (gt "") (gtu "u")
528                      (ge "") (geu "u")
529                      (lt "") (ltu "u")
530                      (le "") (leu "u")])
532 ;; <U> is like <u> except uppercase.
533 (define_code_attr U [(sign_extend "") (zero_extend "U")])
535 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
536 (define_code_attr su [(sign_extend "s") (zero_extend "u")])
538 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
540 ;; <optab> expands to the name of the optab for a particular code.
541 (define_code_attr optab [(ashift "ashl")
542                          (ashiftrt "ashr")
543                          (lshiftrt "lshr")
544                          (rotatert "rotr")
545                          (ior "ior")
546                          (xor "xor")
547                          (and "and")
548                          (plus "add")
549                          (minus "sub")
550                          (mult "mul")
551                          (div "div")
552                          (udiv "udiv")
553                          (mod "mod")
554                          (umod "umod")
555                          (return "return")
556                          (simple_return "simple_return")])
558 ;; <insn> expands to the name of the insn that implements a particular code.
559 (define_code_attr insn [(ashift "sll")
560                         (ashiftrt "sra")
561                         (lshiftrt "srl")
562                         (rotatert "rotr")
563                         (ior "or")
564                         (xor "xor")
565                         (and "and")
566                         (plus "addu")
567                         (minus "subu")
568                         (div "div")
569                         (udiv "div")
570                         (mod "mod")
571                         (umod "mod")])
573 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
574 (define_code_attr fcond [(unordered "cun")
575                          (uneq "cueq")
576                          (unlt "cult")
577                          (unle "cule")
578                          (eq "ceq")
579                          (lt "slt")
580                          (le "sle")
581                          (ordered "cor")
582                          (ltgt "sne")
583                          (ne "cune")
584                          (ge "sge")
585                          (gt "sgt")
586                          (unge "cuge")
587                          (ungt "cugt")])
589 ;; The sel mnemonic to use depending on the condition test.
590 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
591 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
593 ;; Iterator and attributes for floating-point to fixed-point conversion
594 ;; instructions.
595 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
596 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
597                                 (UNSPEC_FTINTRM "lfloor")
598                                 (UNSPEC_FTINTRP "lceil")])
599 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
600                                     (UNSPEC_FTINTRM "rm")
601                                     (UNSPEC_FTINTRP "rp")])
603 ;; Iterator and attributes for bytepick.d
604 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
605 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
606                                              (16 "16")
607                                              (24 "8")])
608 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
609 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
610                                              (16 "48")
611                                              (24 "40")
612                                              (32 "32")
613                                              (40 "24")
614                                              (48 "16")
615                                              (56 "8")])
616 (define_int_attr bytepick_imm [(8 "1")
617                                  (16 "2")
618                                  (24 "3")
619                                  (32 "4")
620                                  (40 "5")
621                                  (48 "6")
622                                  (56 "7")])
624 ;; Expand some 32-bit operations to si3_extend operations if TARGET_64BIT
625 ;; so the redundant sign extension can be removed if the output is used as
626 ;; an input of a bitwise operation.  Note plus, rotl, and div are handled
627 ;; separately.
628 (define_code_iterator shift_w [any_shift rotatert])
629 (define_code_iterator arith_w [minus mult])
631 (define_expand "<optab><mode>3"
632   [(set (match_operand:GPR 0 "register_operand" "=r")
633         (shift_w:GPR (match_operand:GPR 1 "register_operand" "r")
634                      (match_operand:SI 2 "arith_operand" "rI")))]
635   ""
637   if (TARGET_64BIT && <MODE>mode == SImode)
638     {
639       rtx t = gen_reg_rtx (DImode);
640       emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
641       t = gen_lowpart (SImode, t);
642       SUBREG_PROMOTED_VAR_P (t) = 1;
643       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
644       emit_move_insn (operands[0], t);
645       DONE;
646     }
649 (define_expand "<optab><mode>3"
650   [(set (match_operand:GPR 0 "register_operand" "=r")
651         (arith_w:GPR (match_operand:GPR 1 "register_operand" "r")
652                      (match_operand:GPR 2 "register_operand" "r")))]
653   ""
655   if (TARGET_64BIT && <MODE>mode == SImode)
656     {
657       rtx t = gen_reg_rtx (DImode);
658       emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
659       t = gen_lowpart (SImode, t);
660       SUBREG_PROMOTED_VAR_P (t) = 1;
661       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
662       emit_move_insn (operands[0], t);
663       DONE;
664     }
668 ;;  ....................
670 ;;      CONDITIONAL TRAPS
672 ;;  ....................
675 (define_insn "trap"
676   [(trap_if (const_int 1) (const_int 0))]
677   ""
679   return "break\t0";
681   [(set_attr "type" "trap")])
686 ;;  ....................
688 ;;      ADDITION
690 ;;  ....................
693 (define_insn "add<mode>3"
694   [(set (match_operand:ANYF 0 "register_operand" "=f")
695         (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
696                    (match_operand:ANYF 2 "register_operand" "f")))]
697   ""
698   "fadd.<fmt>\t%0,%1,%2"
699   [(set_attr "type" "fadd")
700    (set_attr "mode" "<UNITMODE>")])
702 (define_insn_and_split "*addsi3"
703   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
704         (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
705                   (match_operand:SI 2 "plus_si_operand"
706                                        "r,I,La,Lb,Le")))]
707   ""
708   "@
709    add.w\t%0,%1,%2
710    addi.w\t%0,%1,%2
711    #
712    * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
713      return \"addu16i.d\t%0,%1,%2\";
714    #"
715   "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
716    && !ADDU16I_OPERAND (INTVAL (operands[2]))"
717   [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
718    (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
719   {
720     loongarch_split_plus_constant (&operands[2], SImode);
721   }
722   [(set_attr "alu_type" "add")
723    (set_attr "mode" "SI")
724    (set_attr "insn_count" "1,1,2,1,2")])
726 (define_expand "addsi3"
727   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
728         (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
729                  (match_operand:SI 2 "plus_si_operand"  "r,I,La,Le,Lb")))]
730   "TARGET_64BIT"
732   if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
733       && ADDU16I_OPERAND (INTVAL (operands[2])))
734     {
735       rtx t1 = gen_reg_rtx (DImode);
736       rtx t2 = gen_reg_rtx (DImode);
737       rtx t3 = gen_reg_rtx (DImode);
738       emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
739       t2 = operands[2];
740       emit_insn (gen_adddi3 (t3, t1, t2));
741       t3 = gen_lowpart (SImode, t3);
742       emit_move_insn (operands[0], t3);
743       DONE;
744     }
745   else
746     {
747       rtx t = gen_reg_rtx (DImode);
748       emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
749       t = gen_lowpart (SImode, t);
750       SUBREG_PROMOTED_VAR_P (t) = 1;
751       SUBREG_PROMOTED_SET (t, SRP_SIGNED);
752       emit_move_insn (operands[0], t);
753       DONE;
754     }
757 (define_insn_and_split "adddi3"
758   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
759         (plus:DI (match_operand:DI 1 "register_operand" "r,r,r,r,r,r")
760                   (match_operand:DI 2 "plus_di_operand"
761                                        "r,I,La,Lb,Lc,Ld")))]
762   "TARGET_64BIT"
763   "@
764    add.d\t%0,%1,%2
765    addi.d\t%0,%1,%2
766    #
767    * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
768      return \"addu16i.d\t%0,%1,%2\";
769    #
770    #"
771   "&& CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
772    && !ADDU16I_OPERAND (INTVAL (operands[2]))"
773   [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
774    (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
775   {
776     loongarch_split_plus_constant (&operands[2], DImode);
777   }
778   [(set_attr "alu_type" "add")
779    (set_attr "mode" "DI")
780    (set_attr "insn_count" "1,1,2,1,2,2")])
782 (define_insn_and_split "addsi3_extended"
783   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
784         (sign_extend:DI
785              (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
786                       (match_operand:SI 2 "plus_si_extend_operand"
787                                           "r,I,La,Le"))))]
788   "TARGET_64BIT"
789   "@
790    add.w\t%0,%1,%2
791    addi.w\t%0,%1,%2
792    #
793    #"
794   "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
795   [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
796    (set (match_dup 0)
797         (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
798                                  (match_dup 4))))]
799   {
800     loongarch_split_plus_constant (&operands[2], SImode);
801   }
802   [(set_attr "alu_type" "add")
803    (set_attr "mode" "SI")
804    (set_attr "insn_count" "1,1,2,2")])
808 ;;  ....................
810 ;;      SUBTRACTION
812 ;;  ....................
815 (define_insn "sub<mode>3"
816   [(set (match_operand:ANYF 0 "register_operand" "=f")
817         (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
818                     (match_operand:ANYF 2 "register_operand" "f")))]
819   ""
820   "fsub.<fmt>\t%0,%1,%2"
821   [(set_attr "type" "fadd")
822    (set_attr "mode" "<UNITMODE>")])
824 (define_insn "*sub<mode>3"
825   [(set (match_operand:GPR 0 "register_operand" "=r")
826         (minus:GPR (match_operand:GPR 1 "register_operand" "r")
827                    (match_operand:GPR 2 "register_operand" "r")))]
828   ""
829   "sub.<d>\t%0,%z1,%2"
830   [(set_attr "alu_type" "sub")
831    (set_attr "mode" "<MODE>")])
834 (define_insn "subsi3_extend"
835   [(set (match_operand:DI 0 "register_operand" "=r")
836         (sign_extend:DI
837             (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
838                       (match_operand:SI 2 "register_operand" "r"))))]
839   "TARGET_64BIT"
840   "sub.w\t%0,%z1,%2"
841   [(set_attr "type" "arith")
842    (set_attr "mode" "SI")])
845 ;;  ....................
847 ;;      MULTIPLICATION
849 ;;  ....................
852 (define_insn "mul<mode>3"
853   [(set (match_operand:ANYF 0 "register_operand" "=f")
854         (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
855                    (match_operand:ANYF 2 "register_operand" "f")))]
856   ""
857   "fmul.<fmt>\t%0,%1,%2"
858   [(set_attr "type" "fmul")
859    (set_attr "mode" "<MODE>")])
861 (define_insn "*mul<mode>3"
862   [(set (match_operand:GPR 0 "register_operand" "=r")
863         (mult:GPR (match_operand:GPR 1 "register_operand" "r")
864                   (match_operand:GPR 2 "register_operand" "r")))]
865   ""
866   "mul.<d>\t%0,%1,%2"
867   [(set_attr "type" "imul")
868    (set_attr "mode" "<MODE>")])
870 (define_insn "mulsi3_extend"
871   [(set (match_operand:DI 0 "register_operand" "=r")
872         (sign_extend:DI
873             (mult:SI (match_operand:SI 1 "register_operand" "r")
874                      (match_operand:SI 2 "register_operand" "r"))))]
875   "TARGET_64BIT"
876   "mul.w\t%0,%1,%2"
877   [(set_attr "type" "imul")
878    (set_attr "mode" "SI")])
881 ;;  ........................
883 ;;      MULTIPLICATION HIGH-PART
885 ;;  ........................
888 (define_expand "<u>mulditi3"
889   [(set (match_operand:TI 0 "register_operand")
890         (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
891                  (any_extend:TI (match_operand:DI 2 "register_operand"))))]
892   "TARGET_64BIT"
894   rtx low = gen_reg_rtx (DImode);
895   emit_insn (gen_muldi3 (low, operands[1], operands[2]));
897   rtx high = gen_reg_rtx (DImode);
898   emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
900   emit_move_insn (gen_lowpart (DImode, operands[0]), low);
901   emit_move_insn (gen_highpart (DImode, operands[0]), high);
902   DONE;
905 (define_insn "<su>muldi3_highpart"
906   [(set (match_operand:DI 0 "register_operand" "=r")
907         (truncate:DI
908           (lshiftrt:TI
909             (mult:TI (any_extend:TI
910                        (match_operand:DI 1 "register_operand" " r"))
911                      (any_extend:TI
912                        (match_operand:DI 2 "register_operand" " r")))
913             (const_int 64))))]
914   "TARGET_64BIT"
915   "mulh.d<u>\t%0,%1,%2"
916   [(set_attr "type" "imul")
917    (set_attr "mode" "DI")])
919 (define_expand "<u>mulsidi3"
920   [(set (match_operand:DI 0 "register_operand")
921         (mult:DI (any_extend:DI
922                    (match_operand:SI 1 "register_operand"))
923                  (any_extend:DI
924                    (match_operand:SI 2 "register_operand"))))]
925   ""
927   if (!TARGET_64BIT)
928   {
929     rtx temp = gen_reg_rtx (SImode);
930     emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
931     emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
932                                        operands[1], operands[2]));
933     emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
934     DONE;
935   }
938 (define_insn "<u>mulsidi3_64bit"
939   [(set (match_operand:DI 0 "register_operand" "=r")
940         (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
941                  (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
942   "TARGET_64BIT"
943   "mulw.d.w<u>\t%0,%1,%2"
944   [(set_attr "type" "imul")
945    (set_attr "mode" "DI")])
947 (define_insn "<su>mulsi3_highpart"
948   [(set (match_operand:SI 0 "register_operand" "=r")
949         (truncate:SI
950           (lshiftrt:DI
951             (mult:DI (any_extend:DI
952                        (match_operand:SI 1 "register_operand" " r"))
953                      (any_extend:DI
954                        (match_operand:SI 2 "register_operand" " r")))
955             (const_int 32))))]
956   ""
957   "mulh.w<u>\t%0,%1,%2"
958   [(set_attr "type" "imul")
959    (set_attr "mode" "SI")])
961 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
962 ;; sign extension by default, so the sign extension instruction can be
963 ;; eliminated.
964 (define_peephole
965   [(set (match_operand:SI 0 "register_operand")
966         (truncate:SI
967           (lshiftrt:DI
968             (mult:DI (any_extend:DI
969                        (match_operand:SI 1 "register_operand"))
970                      (any_extend:DI
971                        (match_operand:SI 2 "register_operand")))
972             (const_int 32))))
973    (set (match_operand:DI 3 "register_operand")
974         (sign_extend:DI (match_dup 0)))]
975    "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
976    "mulh.w<u>\t%0,%1,%2")
979 ;;  ....................
981 ;;      DIVISION and REMAINDER
983 ;;  ....................
986 ;; Float division and modulus.
987 (define_expand "div<mode>3"
988   [(set (match_operand:ANYF 0 "register_operand")
989     (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
990               (match_operand:ANYF 2 "register_operand")))]
991   ""
993   if (<MODE>mode == SFmode
994     && TARGET_RECIP_DIV
995     && optimize_insn_for_speed_p ()
996     && flag_finite_math_only && !flag_trapping_math
997     && flag_unsafe_math_optimizations)
998   {
999     loongarch_emit_swdivsf (operands[0], operands[1],
1000         operands[2], SFmode);
1001     DONE;
1002   }
1005 (define_insn "*div<mode>3"
1006   [(set (match_operand:ANYF 0 "register_operand" "=f")
1007         (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
1008                   (match_operand:ANYF 2 "register_operand" "f")))]
1009   ""
1010   "fdiv.<fmt>\t%0,%1,%2"
1011   [(set_attr "type" "fdiv")
1012    (set_attr "mode" "<UNITMODE>")])
1014 ;; In 3A5000, the reciprocal operation is the same as the division operation.
1016 (define_insn "*recip<mode>3"
1017   [(set (match_operand:ANYF 0 "register_operand" "=f")
1018         (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
1019                   (match_operand:ANYF 2 "register_operand" "f")))]
1020   ""
1021   "frecip.<fmt>\t%0,%2"
1022   [(set_attr "type" "frdiv")
1023    (set_attr "mode" "<UNITMODE>")])
1025 ;; Approximate Reciprocal Instructions.
1027 (define_insn "loongarch_frecipe_<fmt>"
1028   [(set (match_operand:ANYF 0 "register_operand" "=f")
1029     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1030              UNSPEC_RECIPE))]
1031   "ISA_HAS_FRECIPE"
1032   "frecipe.<fmt>\t%0,%1"
1033   [(set_attr "type" "frecipe")
1034    (set_attr "mode" "<UNITMODE>")
1035    (set_attr "insn_count" "1")])
1037 ;; Integer division and modulus.
1038 (define_expand "<optab><mode>3"
1039   [(set (match_operand:GPR 0 "register_operand")
1040         (any_div:GPR (match_operand:GPR 1 "register_operand")
1041                      (match_operand:GPR 2 "register_operand")))]
1042   ""
1044  if (GET_MODE (operands[0]) == SImode && TARGET_64BIT)
1045   {
1046     if (ISA_HAS_DIV32)
1047       {
1048         rtx t = gen_reg_rtx (DImode);
1049         emit_insn (gen_<optab>si3_extended (t, operands[1], operands[2]));
1050         t = gen_lowpart (SImode, t);
1051         SUBREG_PROMOTED_VAR_P (t) = 1;
1052         SUBREG_PROMOTED_SET (t, SRP_SIGNED);
1053         emit_move_insn (operands[0], t);
1054         DONE;
1055       }
1057     rtx reg1 = gen_reg_rtx (DImode);
1058     rtx reg2 = gen_reg_rtx (DImode);
1059     rtx rd = gen_reg_rtx (DImode);
1061     operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
1062     operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
1064     emit_insn (gen_rtx_SET (reg1, operands[1]));
1065     emit_insn (gen_rtx_SET (reg2, operands[2]));
1067     emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
1068     emit_insn (gen_rtx_SET (operands[0],
1069                             simplify_gen_subreg (SImode, rd, DImode, 0)));
1070     DONE;
1071   }
1074 (define_insn "*<optab><mode>3"
1075   [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
1076         (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
1077                      (match_operand:DIV 2 "register_operand" "r,r,r")))]
1078   ""
1080   return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
1082   [(set_attr "type" "idiv")
1083    (set_attr "mode" "<MODE>")
1084    (set (attr "enabled")
1085       (if_then_else
1086         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1087         (const_string "yes")
1088         (const_string "no")))])
1090 (define_insn "<optab>si3_extended"
1091   [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1092         (sign_extend:DI
1093           (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
1094                       (match_operand:SI 2 "register_operand" "r,r,r"))))]
1095   "TARGET_64BIT && ISA_HAS_DIV32"
1097   return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1099   [(set_attr "type" "idiv")
1100    (set_attr "mode" "SI")
1101    (set (attr "enabled")
1102       (if_then_else
1103         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1104         (const_string "yes")
1105         (const_string "no")))])
1107 (define_insn "<optab>di3_fake"
1108   [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1109         (sign_extend:DI
1110           (unspec:SI
1111            [(subreg:SI
1112              (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1113                          (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1114           UNSPEC_FAKE_ANY_DIV)))]
1115   "TARGET_64BIT && !ISA_HAS_DIV32"
1117   return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1119   [(set_attr "type" "idiv")
1120    (set_attr "mode" "SI")
1121    (set (attr "enabled")
1122       (if_then_else
1123         (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1124         (const_string "yes")
1125         (const_string "no")))])
1127 ;; Floating point multiply accumulate instructions.
1129 ;; a * b + c
1130 (define_insn "fma<mode>4"
1131   [(set (match_operand:ANYF 0 "register_operand" "=f")
1132         (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1133                   (match_operand:ANYF 2 "register_operand" "f")
1134                   (match_operand:ANYF 3 "register_operand" "f")))]
1135   ""
1136   "fmadd.<fmt>\t%0,%1,%2,%3"
1137   [(set_attr "type" "fmadd")
1138    (set_attr "mode" "<UNITMODE>")])
1140 ;; a * b - c
1141 (define_insn "fms<mode>4"
1142   [(set (match_operand:ANYF 0 "register_operand" "=f")
1143         (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1144                   (match_operand:ANYF 2 "register_operand" "f")
1145                   (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1146   ""
1147   "fmsub.<fmt>\t%0,%1,%2,%3"
1148   [(set_attr "type" "fmadd")
1149    (set_attr "mode" "<UNITMODE>")])
1151 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1152 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1153 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1154 ;; This transformation means we may return the wrong signed zero
1155 ;; so we check HONOR_SIGNED_ZEROS.
1157 ;; -a * b + c
1158 (define_insn "fnma<mode>4"
1159   [(set (match_operand:ANYF 0 "register_operand" "=f")
1160         (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1161                   (match_operand:ANYF 2 "register_operand" "f")
1162                   (match_operand:ANYF 3 "register_operand" "f")))]
1163   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1164   "fnmsub.<fmt>\t%0,%1,%2,%3"
1165   [(set_attr "type" "fmadd")
1166    (set_attr "mode" "<UNITMODE>")])
1168 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1169 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1170 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1171 ;; This transformation means we may return the wrong signed zero
1172 ;; so we check HONOR_SIGNED_ZEROS.
1174 ;; -a * b - c
1175 (define_insn "fnms<mode>4"
1176   [(set (match_operand:ANYF 0 "register_operand" "=f")
1177         (fma:ANYF
1178             (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1179             (match_operand:ANYF 2 "register_operand" "f")
1180             (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1181   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1182   "fnmadd.<fmt>\t%0,%1,%2,%3"
1183   [(set_attr "type" "fmadd")
1184    (set_attr "mode" "<UNITMODE>")])
1186 ;; -(-a * b - c), modulo signed zeros
1187 (define_insn "*fma<mode>4"
1188   [(set (match_operand:ANYF 0 "register_operand" "=f")
1189         (neg:ANYF
1190             (fma:ANYF
1191                 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1192                 (match_operand:ANYF 2 "register_operand" " f")
1193                 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1194   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1195   "fmadd.<fmt>\t%0,%1,%2,%3"
1196   [(set_attr "type" "fmadd")
1197    (set_attr "mode" "<UNITMODE>")])
1199 ;; -(-a * b + c), modulo signed zeros
1200 (define_insn "*fms<mode>4"
1201   [(set (match_operand:ANYF 0 "register_operand" "=f")
1202         (neg:ANYF
1203             (fma:ANYF
1204                 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1205                 (match_operand:ANYF 2 "register_operand" " f")
1206                 (match_operand:ANYF 3 "register_operand" " f"))))]
1207   "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1208   "fmsub.<fmt>\t%0,%1,%2,%3"
1209   [(set_attr "type" "fmadd")
1210    (set_attr "mode" "<UNITMODE>")])
1212 ;; -(a * b + c)
1213 (define_insn "*fnms<mode>4"
1214   [(set (match_operand:ANYF 0 "register_operand" "=f")
1215         (neg:ANYF
1216             (fma:ANYF
1217                 (match_operand:ANYF 1 "register_operand" " f")
1218                 (match_operand:ANYF 2 "register_operand" " f")
1219                 (match_operand:ANYF 3 "register_operand" " f"))))]
1220   ""
1221   "fnmadd.<fmt>\t%0,%1,%2,%3"
1222   [(set_attr "type" "fmadd")
1223    (set_attr "mode" "<UNITMODE>")])
1225 ;; -(a * b - c)
1226 (define_insn "*fnma<mode>4"
1227   [(set (match_operand:ANYF 0 "register_operand" "=f")
1228         (neg:ANYF
1229             (fma:ANYF
1230                 (match_operand:ANYF 1 "register_operand" " f")
1231                 (match_operand:ANYF 2 "register_operand" " f")
1232                 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1233   ""
1234   "fnmsub.<fmt>\t%0,%1,%2,%3"
1235   [(set_attr "type" "fmadd")
1236    (set_attr "mode" "<UNITMODE>")])
1239 ;;  ....................
1241 ;;      SQUARE ROOT
1243 ;;  ....................
1245 (define_expand "sqrt<mode>2"
1246   [(set (match_operand:ANYF 0 "register_operand")
1247     (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1248   ""
1250   if (<MODE>mode == SFmode
1251       && TARGET_RECIP_SQRT
1252       && flag_unsafe_math_optimizations
1253       && !optimize_insn_for_size_p ()
1254       && flag_finite_math_only && !flag_trapping_math)
1255     {
1256       loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1257       DONE;
1258     }
1259  })
1261 (define_insn "*sqrt<mode>2"
1262   [(set (match_operand:ANYF 0 "register_operand" "=f")
1263         (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1264   ""
1265   "fsqrt.<fmt>\t%0,%1"
1266   [(set_attr "type" "fsqrt")
1267    (set_attr "mode" "<UNITMODE>")
1268    (set_attr "insn_count" "1")])
1270 (define_expand "rsqrt<mode>2"
1271   [(set (match_operand:ANYF 0 "register_operand")
1272     (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1273            UNSPEC_RSQRT))]
1274   "TARGET_HARD_FLOAT"
1276    if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1277      {
1278        loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1279        DONE;
1280      }
1283 (define_insn "*rsqrt<mode>2"
1284   [(set (match_operand:ANYF 0 "register_operand" "=f")
1285     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1286              UNSPEC_RSQRT))]
1287   "TARGET_HARD_FLOAT"
1288   "frsqrt.<fmt>\t%0,%1"
1289   [(set_attr "type" "frsqrt")
1290    (set_attr "mode" "<UNITMODE>")])
1292 ;; Approximate Reciprocal Square Root Instructions.
1294 (define_insn "loongarch_frsqrte_<fmt>"
1295   [(set (match_operand:ANYF 0 "register_operand" "=f")
1296     (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1297                  UNSPEC_RSQRTE))]
1298   "ISA_HAS_FRECIPE"
1299   "frsqrte.<fmt>\t%0,%1"
1300   [(set_attr "type" "frsqrte")
1301    (set_attr "mode" "<UNITMODE>")])
1304 ;;  ....................
1306 ;;      ABSOLUTE VALUE
1308 ;;  ....................
1310 (define_insn "abs<mode>2"
1311   [(set (match_operand:ANYF 0 "register_operand" "=f")
1312         (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1313   ""
1314   "fabs.<fmt>\t%0,%1"
1315   [(set_attr "type" "fabs")
1316    (set_attr "mode" "<UNITMODE>")])
1319 ;;  ....................
1321 ;;      FLOATING POINT COPYSIGN
1323 ;;  ....................
1325 (define_insn "copysign<mode>3"
1326   [(set (match_operand:ANYF 0 "register_operand" "=f")
1327         (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1328                        (match_operand:ANYF 2 "register_operand" "f")))]
1329   "TARGET_HARD_FLOAT"
1330   "fcopysign.<fmt>\t%0,%1,%2"
1331   [(set_attr "type" "fcopysign")
1332    (set_attr "mode" "<UNITMODE>")])
1334 (define_expand "@xorsign<mode>3"
1335   [(match_operand:ANYF 0 "register_operand")
1336    (match_operand:ANYF 1 "register_operand")
1337    (match_operand:ANYF 2 "register_operand")]
1338   "ISA_HAS_LSX"
1340   machine_mode lsx_mode
1341     = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1342   rtx tmp = gen_reg_rtx (lsx_mode);
1343   rtx op1 = lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1344   rtx op2 = lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1345   emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1346   emit_move_insn (operands[0],
1347           lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1348   DONE;
1352 ;;  ....................
1354 ;;      FLOATING POINT SCALE
1356 ;;  ....................
1358 (define_insn "ldexp<mode>3"
1359   [(set (match_operand:ANYF 0 "register_operand" "=f")
1360         (unspec:ANYF [(match_operand:ANYF    1 "register_operand" "f")
1361                       (match_operand:<IMODE> 2 "register_operand" "f")]
1362                      UNSPEC_FSCALEB))]
1363   "TARGET_HARD_FLOAT"
1364   "fscaleb.<fmt>\t%0,%1,%2"
1365   [(set_attr "type" "fscaleb")
1366    (set_attr "mode" "<UNITMODE>")])
1369 ;;  ....................
1371 ;;      FLOATING POINT EXPONENT EXTRACT
1373 ;;  ....................
1375 (define_insn "logb_non_negative<mode>2"
1376   [(set (match_operand:ANYF 0 "register_operand" "=f")
1377         (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1378                      UNSPEC_FLOGB))]
1379   "TARGET_HARD_FLOAT"
1380   "flogb.<fmt>\t%0,%1"
1381   [(set_attr "type" "flogb")
1382    (set_attr "mode" "<UNITMODE>")])
1384 (define_expand "logb<mode>2"
1385   [(set (match_operand:ANYF 0 "register_operand")
1386         (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1387                      UNSPEC_FLOGB))]
1388   "TARGET_HARD_FLOAT"
1390   rtx tmp = gen_reg_rtx (<MODE>mode);
1392   emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1393   emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1394   DONE;
1398 ;;  ...................
1400 ;;  Count leading zeroes.
1402 ;;  ...................
1405 (define_insn "clz<mode>2"
1406   [(set (match_operand:GPR 0 "register_operand" "=r")
1407         (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1408   ""
1409   "clz.<d>\t%0,%1"
1410   [(set_attr "type" "clz")
1411    (set_attr "mode" "<MODE>")])
1414 ;;  ...................
1416 ;;  Count trailing zeroes.
1418 ;;  ...................
1421 (define_insn "ctz<mode>2"
1422   [(set (match_operand:GPR 0 "register_operand" "=r")
1423         (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1424   ""
1425   "ctz.<d>\t%0,%1"
1426   [(set_attr "type" "clz")
1427    (set_attr "mode" "<MODE>")])
1430 ;;  ....................
1432 ;;      MIN/MAX
1434 ;;  ....................
1436 (define_insn "smax<mode>3"
1437   [(set (match_operand:ANYF 0 "register_operand" "=f")
1438         (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1439                    (match_operand:ANYF 2 "register_operand" "f")))]
1440   ""
1441   "fmax.<fmt>\t%0,%1,%2"
1442   [(set_attr "type" "fmove")
1443    (set_attr "mode" "<MODE>")])
1445 (define_insn "smin<mode>3"
1446   [(set (match_operand:ANYF 0 "register_operand" "=f")
1447         (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1448                    (match_operand:ANYF 2 "register_operand" "f")))]
1449   ""
1450   "fmin.<fmt>\t%0,%1,%2"
1451   [(set_attr "type" "fmove")
1452    (set_attr "mode" "<MODE>")])
1454 (define_insn "fmax<mode>3"
1455   [(set (match_operand:ANYF 0 "register_operand" "=f")
1456         (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1457                       (use (match_operand:ANYF 2 "register_operand" "f"))]
1458                      UNSPEC_FMAX))]
1459   ""
1460   "fmax.<fmt>\t%0,%1,%2"
1461   [(set_attr "type" "fmove")
1462    (set_attr "mode" "<MODE>")])
1464 (define_insn "fmin<mode>3"
1465   [(set (match_operand:ANYF 0 "register_operand" "=f")
1466         (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1467                       (use (match_operand:ANYF 2 "register_operand" "f"))]
1468                      UNSPEC_FMIN))]
1469   ""
1470   "fmin.<fmt>\t%0,%1,%2"
1471   [(set_attr "type" "fmove")
1472    (set_attr "mode" "<MODE>")])
1474 (define_insn "smaxa<mode>3"
1475   [(set (match_operand:ANYF 0 "register_operand" "=f")
1476         (if_then_else:ANYF
1477               (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1478                   (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1479               (match_dup 1)
1480               (match_dup 2)))]
1481   ""
1482   "fmaxa.<fmt>\t%0,%1,%2"
1483   [(set_attr "type" "fmove")
1484    (set_attr "mode" "<MODE>")])
1486 (define_insn "smina<mode>3"
1487   [(set (match_operand:ANYF 0 "register_operand" "=f")
1488         (if_then_else:ANYF
1489                 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1490                     (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1491                 (match_dup 1)
1492                 (match_dup 2)))]
1493   ""
1494   "fmina.<fmt>\t%0,%1,%2"
1495   [(set_attr "type" "fmove")
1496    (set_attr "mode" "<MODE>")])
1499 ;;  ....................
1501 ;;      NEGATION and ONE'S COMPLEMENT
1503 ;;  ....................
1505 (define_insn "neg<mode>2"
1506   [(set (match_operand:GPR 0 "register_operand" "=r")
1507         (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1508   ""
1509   "sub.<d>\t%0,%.,%1"
1510   [(set_attr "alu_type" "sub")
1511    (set_attr "mode" "<MODE>")])
1513 (define_insn "*negsi2_extended"
1514   [(set (match_operand:DI 0 "register_operand" "=r")
1515         (sign_extend:DI (neg:SI (match_operand:SI 1 "register_operand" "r"))))]
1516   "TARGET_64BIT"
1517   "sub.w\t%0,%.,%1"
1518   [(set_attr "alu_type" "sub")
1519    (set_attr "mode" "SI")])
1521 (define_insn "neg<mode>2"
1522   [(set (match_operand:ANYF 0 "register_operand" "=f")
1523         (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1524   ""
1525   "fneg.<fmt>\t%0,%1"
1526   [(set_attr "type" "fneg")
1527    (set_attr "mode" "<UNITMODE>")])
1531 ;;  ....................
1533 ;;      LOGICAL
1535 ;;  ....................
1538 (define_insn "<optab><mode>3"
1539   [(set (match_operand:X 0 "register_operand" "=r,r")
1540         (any_bitwise:X (match_operand:X 1 "register_operand" "%r,r")
1541                        (match_operand:X 2 "uns_arith_operand" "r,K")))]
1542   ""
1543   "<insn>%i2\t%0,%1,%2"
1544   [(set_attr "type" "logical")
1545    (set_attr "mode" "<MODE>")])
1547 (define_insn "*<optab>si3_internal"
1548   [(set (match_operand:SI 0 "register_operand" "=r,r")
1549         (any_bitwise:SI (match_operand:SI 1 "register_operand" "%r,r")
1550                         (match_operand:SI 2 "uns_arith_operand"    " r,K")))]
1551   "TARGET_64BIT"
1552   "<insn>%i2\t%0,%1,%2"
1553   [(set_attr "type" "logical")
1554    (set_attr "mode" "SI")])
1556 (define_insn "one_cmpl<mode>2"
1557   [(set (match_operand:X 0 "register_operand" "=r")
1558         (not:X (match_operand:X 1 "register_operand" "r")))]
1559   ""
1560   "nor\t%0,%.,%1"
1561   [(set_attr "alu_type" "not")
1562    (set_attr "mode" "<MODE>")])
1564 (define_insn "*one_cmplsi2_internal"
1565   [(set (match_operand:SI 0 "register_operand" "=r")
1566         (not:SI (match_operand:SI 1 "register_operand" " r")))]
1567   "TARGET_64BIT"
1568   "nor\t%0,%.,%1"
1569   [(set_attr "type" "logical")
1570    (set_attr "mode" "SI")])
1572 (define_insn "and<mode>3_extended"
1573   [(set (match_operand:GPR 0 "register_operand" "=r")
1574         (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "r")
1575                  (match_operand:GPR 2 "low_bitmask_operand" "Yx")))]
1576   ""
1578   int len;
1580   len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
1581   operands[2] = GEN_INT (len-1);
1582   return "bstrpick.<d>\t%0,%1,%2,0";
1584   [(set_attr "move_type" "pick_ins")
1585    (set_attr "mode" "<MODE>")])
1587 (define_insn_and_split "*bstrins_<mode>_for_mask"
1588   [(set (match_operand:GPR 0 "register_operand" "=r")
1589         (and:GPR (match_operand:GPR 1 "register_operand" "r")
1590                  (match_operand:GPR 2 "ins_zero_bitmask_operand" "i")))]
1591   ""
1592   "#"
1593   ""
1594   [(set (match_dup 0) (match_dup 1))
1595    (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 3))
1596         (const_int 0))]
1597   {
1598     unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1599     int lo = ffs_hwi (mask) - 1;
1600     int len = low_bitmask_len (<MODE>mode, mask >> lo);
1602     len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1603     operands[2] = GEN_INT (len);
1604     operands[3] = GEN_INT (lo);
1605   })
1607 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1608   [(set (match_operand:GPR 0 "register_operand" "=r")
1609         (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand" "r")
1610                           (match_operand:GPR 2 "const_int_operand" "i"))
1611                  (and:GPR (match_operand:GPR 3 "register_operand" "r")
1612                           (match_operand:GPR 4 "const_int_operand" "i"))))]
1613   "loongarch_pre_reload_split ()
1614    && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1615   "#"
1616   "&& true"
1617   [(set (match_dup 0) (match_dup 1))
1618    (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1619         (match_dup 3))]
1620   {
1621     if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1622       {
1623         std::swap (operands[1], operands[3]);
1624         std::swap (operands[2], operands[4]);
1625       }
1627     unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1628     int lo = ffs_hwi (mask) - 1;
1629     int len = low_bitmask_len (<MODE>mode, mask >> lo);
1631     len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1632     operands[2] = GEN_INT (len);
1633     operands[4] = GEN_INT (lo);
1635     if (lo)
1636       {
1637         rtx tmp = gen_reg_rtx (<MODE>mode);
1638         emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1639                                               GEN_INT (lo)));
1640         operands[3] = tmp;
1641       }
1642   })
1644 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1645 ;; if possible, but the result may be sub-optimal when one of the masks
1646 ;; is (1 << N) - 1 and one of the src register is the dest register.
1647 ;; For example:
1648 ;;     move             t0, a0
1649 ;;     move             a0, a1
1650 ;;     bstrins.d        a0, t0, 42, 0
1651 ;;     ret
1652 ;; using a shift operation would be better:
1653 ;;     srai.d           t0, a1, 43
1654 ;;     bstrins.d        a0, t0, 63, 43
1655 ;;     ret
1656 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1657 ;; know if the dest register is one of the src register.  Fix it up in
1658 ;; peephole2.
1659 (define_peephole2
1660   [(set (match_operand:GPR 0 "register_operand")
1661         (match_operand:GPR 1 "register_operand"))
1662    (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1663    (set (zero_extract:GPR (match_dup 1)
1664                           (match_operand:SI 3 "const_int_operand")
1665                           (const_int 0))
1666         (match_dup 0))]
1667   "peep2_reg_dead_p (3, operands[0])"
1668   [(const_int 0)]
1669   {
1670     int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1672     emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1673     emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1674                                operands[0]));
1675     DONE;
1676   })
1678 (define_insn "*iorhi3"
1679   [(set (match_operand:HI 0 "register_operand" "=r,r")
1680         (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1681                 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1682   ""
1683   "or%i2\t%0,%1,%2"
1684   [(set_attr "type" "logical")
1685    (set_attr "mode" "HI")])
1687 (define_insn "nor<mode>3"
1688   [(set (match_operand:X 0 "register_operand" "=r")
1689         (and:X (not:X (match_operand:X 1 "register_operand" "%r"))
1690                  (not:X (match_operand:X 2 "register_operand" "r"))))]
1691   ""
1692   "nor\t%0,%1,%2"
1693   [(set_attr "type" "logical")
1694    (set_attr "mode" "<MODE>")])
1696 (define_insn "*norsi3_internal"
1697   [(set (match_operand:SI 0 "register_operand" "=r")
1698         (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
1699                  (not:SI (match_operand:SI 2 "register_operand" "r"))))]
1700   "TARGET_64BIT"
1701   "nor\t%0,%1,%2"
1702   [(set_attr "type" "logical")
1703    (set_attr "mode" "SI")])
1705 (define_insn "<optab>n<mode>3"
1706   [(set (match_operand:X 0 "register_operand" "=r")
1707         (neg_bitwise:X
1708             (not:X (match_operand:X 2 "register_operand" "r"))
1709             (match_operand:X 1 "register_operand" "r")))]
1710   ""
1711   "<insn>n\t%0,%1,%2"
1712   [(set_attr "type" "logical")
1713    (set_attr "mode" "<MODE>")])
1715 (define_insn "*<optab>nsi_internal"
1716   [(set (match_operand:SI 0 "register_operand" "=r")
1717         (neg_bitwise:SI
1718             (not:SI (match_operand:SI 1 "register_operand" "r"))
1719             (match_operand:SI 2 "register_operand" "r")))]
1720   "TARGET_64BIT"
1721   "<insn>n\t%0,%2,%1"
1722   [(set_attr "type" "logical")
1723    (set_attr "mode" "SI")])
1726 ;;  ....................
1728 ;;      TRUNCATION
1730 ;;  ....................
1732 (define_insn "truncdfsf2"
1733   [(set (match_operand:SF 0 "register_operand" "=f")
1734         (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1735   "TARGET_DOUBLE_FLOAT"
1736   "fcvt.s.d\t%0,%1"
1737   [(set_attr "type" "fcvt")
1738    (set_attr "cnv_mode" "D2S")
1739    (set_attr "mode" "SF")])
1741 ;; In vector registers, popcount can be implemented directly through
1742 ;; the vector instruction [X]VPCNT.  For GP registers, we can implement
1743 ;; it through the following method.  Compared with loop implementation
1744 ;; of popcount, the following method has better performance.
1746 ;; This attribute used for get connection of scalar mode and corresponding
1747 ;; vector mode.
1748 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1750 (define_expand "popcount<mode>2"
1751   [(set (match_operand:GPR 0 "register_operand")
1752         (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1753   "ISA_HAS_LSX"
1755   rtx in = operands[1];
1756   rtx out = operands[0];
1757   rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1758                                     gen_reg_rtx (V2DImode);
1759   emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1760   emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1761   emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1762   DONE;
1766 ;;  ....................
1768 ;;      ZERO EXTENSION
1770 ;;  ....................
1771 (define_expand "zero_extendsidi2"
1772   [(set (match_operand:DI 0 "register_operand")
1773         (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1774   "TARGET_64BIT")
1776 (define_insn_and_split "*zero_extendsidi2_internal"
1777   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1778         (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1779   "TARGET_64BIT"
1780   "@
1781    bstrpick.d\t%0,%1,31,0
1782    ld.wu\t%0,%1
1783    #
1784    ldx.wu\t%0,%1"
1785   "&& reload_completed
1786    && MEM_P (operands[1])
1787    && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1788        && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1789    && !paradoxical_subreg_p (operands[0])"
1790   [(set (match_dup 3) (match_dup 1))
1791    (set (match_dup 0)
1792         (ior:DI (zero_extend:DI
1793                   (subreg:SI (match_dup 0) 0))
1794                 (match_dup 2)))]
1795   {
1796     operands[1] = gen_lowpart (SImode, operands[1]);
1797     operands[3] = gen_lowpart (SImode, operands[0]);
1798     operands[2] = const0_rtx;
1799   }
1800   [(set_attr "move_type" "arith,load,load,load")
1801    (set_attr "mode" "DI")])
1803 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1804   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1805         (zero_extend:GPR
1806              (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1807   ""
1808   "@
1809    bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1810    ld.<SHORT:size>u\t%0,%1
1811    ldx.<SHORT:size>u\t%0,%1"
1812   [(set_attr "move_type" "pick_ins,load,load")
1813    (set_attr "mode" "<GPR:MODE>")])
1815 (define_insn "zero_extendqihi2"
1816   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1817         (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1818   ""
1819   "@
1820    andi\t%0,%1,0xff
1821    ldx.bu\t%0,%1
1822    ld.bu\t%0,%1"
1823   [(set_attr "move_type" "andi,load,load")
1824    (set_attr "mode" "HI")])
1826 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1828 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1829   [(set (match_operand:GPR 0 "register_operand" "=r")
1830         (zero_extend:GPR
1831             (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1832   "TARGET_64BIT"
1833   "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1834   [(set_attr "move_type" "pick_ins")
1835    (set_attr "mode" "<GPR:MODE>")])
1837 (define_insn "*zero_extendhi_truncqi"
1838   [(set (match_operand:HI 0 "register_operand" "=r")
1839         (zero_extend:HI
1840             (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1841   "TARGET_64BIT"
1842   "andi\t%0,%1,0xff"
1843   [(set_attr "alu_type" "and")
1844    (set_attr "mode" "HI")])
1847 ;;  ....................
1849 ;;      SIGN EXTENSION
1851 ;;  ....................
1853 (define_insn "extendsidi2"
1854   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
1855         (sign_extend:DI
1856             (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k,f")))]
1857   "TARGET_64BIT"
1858   "@
1859    slli.w\t%0,%1,0
1860    ldptr.w\t%0,%1
1861    ld.w\t%0,%1
1862    ldx.w\t%0,%1
1863    movfr2gr.s\t%0,%1"
1864   [(set_attr "move_type" "sll0,load,load,load,mftg")
1865    (set_attr "mode" "DI")])
1867 (define_insn "extend<SHORT:mode><GPR:mode>2"
1868   [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1869         (sign_extend:GPR
1870              (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1871   ""
1872   "@
1873    ext.w.<SHORT:size>\t%0,%1
1874    ld.<SHORT:size>\t%0,%1
1875    ldx.<SHORT:size>\t%0,%1"
1876   [(set_attr "move_type" "signext,load,load")
1877    (set_attr "mode" "<GPR:MODE>")])
1879 (define_insn "extendqihi2"
1880   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1881         (sign_extend:HI
1882              (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1883   ""
1884   "@
1885    ext.w.b\t%0,%1
1886    ld.b\t%0,%1
1887    ldx.b\t%0,%1"
1888   [(set_attr "move_type" "signext,load,load")
1889    (set_attr "mode" "SI")])
1891 (define_insn "extendsfdf2"
1892   [(set (match_operand:DF 0 "register_operand" "=f")
1893         (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1894   "TARGET_DOUBLE_FLOAT"
1895   "fcvt.d.s\t%0,%1"
1896   [(set_attr "type" "fcvt")
1897    (set_attr "cnv_mode" "S2D")
1898    (set_attr "mode" "DF")])
1901 ;;  ....................
1903 ;;      CONVERSIONS
1905 ;;  ....................
1907 ;; conversion of a floating-point value to a integer
1909 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1910   [(set (match_operand:GPR 0 "register_operand" "=f")
1911         (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1912   ""
1913   "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1914   [(set_attr "type" "fcvt")
1915    (set_attr "mode" "<ANYF:MODE>")])
1917 ;; conversion of an integeral (or boolean) value to a floating-point value
1919 (define_insn "floatsidf2"
1920   [(set (match_operand:DF 0 "register_operand" "=f")
1921         (float:DF (match_operand:SI 1 "register_operand" "f")))]
1922   "TARGET_DOUBLE_FLOAT"
1923   "ffint.d.w\t%0,%1"
1924   [(set_attr "type" "fcvt")
1925    (set_attr "mode" "DF")
1926    (set_attr "cnv_mode" "I2D")])
1928 (define_insn "floatdidf2"
1929   [(set (match_operand:DF 0 "register_operand" "=f")
1930         (float:DF (match_operand:DI 1 "register_operand" "f")))]
1931   "TARGET_DOUBLE_FLOAT"
1932   "ffint.d.l\t%0,%1"
1933   [(set_attr "type" "fcvt")
1934    (set_attr "mode" "DF")
1935    (set_attr "cnv_mode" "I2D")])
1937 (define_insn "floatsisf2"
1938   [(set (match_operand:SF 0 "register_operand" "=f")
1939         (float:SF (match_operand:SI 1 "register_operand" "f")))]
1940   "TARGET_HARD_FLOAT"
1941   "ffint.s.w\t%0,%1"
1942   [(set_attr "type" "fcvt")
1943    (set_attr "mode" "SF")
1944    (set_attr "cnv_mode" "I2S")])
1946 (define_insn "floatdisf2"
1947   [(set (match_operand:SF 0 "register_operand" "=f")
1948         (float:SF (match_operand:DI 1 "register_operand" "f")))]
1949   "TARGET_DOUBLE_FLOAT"
1950   "ffint.s.l\t%0,%1"
1951   [(set_attr "type" "fcvt")
1952    (set_attr "mode" "SF")
1953    (set_attr "cnv_mode" "I2S")])
1955 ;; Convert a floating-point value to an unsigned integer.
1957 (define_expand "fixuns_truncdfsi2"
1958   [(set (match_operand:SI 0 "register_operand")
1959         (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1960   "TARGET_DOUBLE_FLOAT"
1962   rtx reg1 = gen_reg_rtx (DFmode);
1963   rtx reg2 = gen_reg_rtx (DFmode);
1964   rtx reg3 = gen_reg_rtx (SImode);
1965   rtx_code_label *label1 = gen_label_rtx ();
1966   rtx_code_label *label2 = gen_label_rtx ();
1967   rtx test;
1968   REAL_VALUE_TYPE offset;
1970   real_2expN (&offset, 31, DFmode);
1972   loongarch_emit_move (reg1,
1973                        const_double_from_real_value (offset, DFmode));
1974   do_pending_stack_adjust ();
1976   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1977   emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1979   emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1980   emit_jump_insn (gen_rtx_SET (pc_rtx,
1981                                gen_rtx_LABEL_REF (VOIDmode, label2)));
1982   emit_barrier ();
1984   emit_label (label1);
1985   loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1986   loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1987                                         (BITMASK_HIGH, SImode)));
1989   emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1990   emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1992   emit_label (label2);
1994   /* Allow REG_NOTES to be set on last insn (labels don't have enough
1995      fields, and can't be used for REG_NOTES anyway).  */
1996   emit_use (stack_pointer_rtx);
1997   DONE;
2000 (define_expand "fixuns_truncdfdi2"
2001   [(set (match_operand:DI 0 "register_operand")
2002         (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
2003   "TARGET_DOUBLE_FLOAT"
2005   rtx reg1 = gen_reg_rtx (DFmode);
2006   rtx reg2 = gen_reg_rtx (DFmode);
2007   rtx reg3 = gen_reg_rtx (DImode);
2008   rtx_code_label *label1 = gen_label_rtx ();
2009   rtx_code_label *label2 = gen_label_rtx ();
2010   rtx test;
2011   REAL_VALUE_TYPE offset;
2013   real_2expN (&offset, 63, DFmode);
2015   loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
2016   do_pending_stack_adjust ();
2018   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2019   emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
2021   emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
2022   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2023   emit_barrier ();
2025   emit_label (label1);
2026   loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
2027   loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2028   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2030   emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
2031   emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2033   emit_label (label2);
2035   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2036      fields, and can't be used for REG_NOTES anyway).  */
2037   emit_use (stack_pointer_rtx);
2038   DONE;
2041 (define_expand "fixuns_truncsfsi2"
2042   [(set (match_operand:SI 0 "register_operand")
2043         (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
2044   "TARGET_HARD_FLOAT"
2046   rtx reg1 = gen_reg_rtx (SFmode);
2047   rtx reg2 = gen_reg_rtx (SFmode);
2048   rtx reg3 = gen_reg_rtx (SImode);
2049   rtx_code_label *label1 = gen_label_rtx ();
2050   rtx_code_label *label2 = gen_label_rtx ();
2051   rtx test;
2052   REAL_VALUE_TYPE offset;
2054   real_2expN (&offset, 31, SFmode);
2056   loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2057   do_pending_stack_adjust ();
2059   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2060   emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2062   emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
2063   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2064   emit_barrier ();
2066   emit_label (label1);
2067   loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2068   loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
2069                                  (BITMASK_HIGH, SImode)));
2071   emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
2072   emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
2074   emit_label (label2);
2076   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2077      fields, and can't be used for REG_NOTES anyway).  */
2078   emit_use (stack_pointer_rtx);
2079   DONE;
2082 (define_expand "fixuns_truncsfdi2"
2083   [(set (match_operand:DI 0 "register_operand")
2084         (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
2085   "TARGET_DOUBLE_FLOAT"
2087   rtx reg1 = gen_reg_rtx (SFmode);
2088   rtx reg2 = gen_reg_rtx (SFmode);
2089   rtx reg3 = gen_reg_rtx (DImode);
2090   rtx_code_label *label1 = gen_label_rtx ();
2091   rtx_code_label *label2 = gen_label_rtx ();
2092   rtx test;
2093   REAL_VALUE_TYPE offset;
2095   real_2expN (&offset, 63, SFmode);
2097   loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2098   do_pending_stack_adjust ();
2100   test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2101   emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2103   emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
2104   emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2105   emit_barrier ();
2107   emit_label (label1);
2108   loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2109   loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2110   emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2112   emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
2113   emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2115   emit_label (label2);
2117   /* Allow REG_NOTES to be set on last insn (labels don't have enough
2118      fields, and can't be used for REG_NOTES anyway).  */
2119   emit_use (stack_pointer_rtx);
2120   DONE;
2124 ;;  ....................
2126 ;;      EXTRACT AND INSERT
2128 ;;  ....................
2130 (define_expand "extzv<mode>"
2131   [(set (match_operand:X 0 "register_operand")
2132         (zero_extract:X (match_operand:X 1 "register_operand")
2133                         (match_operand 2 "const_int_operand")
2134                         (match_operand 3 "const_int_operand")))]
2135   ""
2137   if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2138                                 INTVAL (operands[3])))
2139     FAIL;
2142 (define_insn "*extzv<mode>"
2143   [(set (match_operand:X 0 "register_operand" "=r")
2144         (zero_extract:X (match_operand:X 1 "register_operand" "r")
2145                           (match_operand 2 "const_int_operand" "")
2146                           (match_operand 3 "const_int_operand" "")))]
2147   "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2148                             INTVAL (operands[3]))"
2150   operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2151   return "bstrpick.<d>\t%0,%1,%2,%3";
2153   [(set_attr "type" "arith")
2154    (set_attr "mode" "<MODE>")])
2156 (define_expand "insv<mode>"
2157   [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2158                           (match_operand 1 "const_int_operand")
2159                           (match_operand 2 "const_int_operand"))
2160         (match_operand:GPR 3 "reg_or_0_operand"))]
2161   ""
2163   if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2164                                 INTVAL (operands[2])))
2165     FAIL;
2168 (define_insn "*insv<mode>"
2169   [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2170                           (match_operand:SI 1 "const_int_operand" "")
2171                           (match_operand:SI 2 "const_int_operand" ""))
2172         (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2173   "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2174                             INTVAL (operands[2]))"
2176   operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2177   return "bstrins.<d>\t%0,%z3,%1,%2";
2179   [(set_attr "type" "arith")
2180    (set_attr "mode" "<MODE>")])
2183 ;;  ....................
2185 ;;      DATA MOVEMENT
2187 ;;  ....................
2189 ;; 64-bit integer moves
2191 ;; Unlike most other insns, the move insns can't be split with
2192 ;; different predicates, because register spilling and other parts of
2193 ;; the compiler, have memoized the insn number already.
2195 (define_expand "movdi"
2196   [(set (match_operand:DI 0 "")
2197         (match_operand:DI 1 ""))]
2198   ""
2200   if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2201     DONE;
2204 (define_insn_and_split "*movdi_32bit"
2205   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2206        (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2207   "!TARGET_64BIT
2208    && (register_operand (operands[0], DImode)
2209        || reg_or_0_operand (operands[1], DImode))"
2210   { return loongarch_output_move (operands[0], operands[1]); }
2211   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2212   (operands[0]))"
2213   [(const_int 0)]
2214   "
2216   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2217   DONE;
2219   "
2220   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2221    (set_attr "mode" "DI")])
2223 (define_insn_and_split "*movdi_64bit"
2224   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2225         (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2226   "TARGET_64BIT
2227    && (register_operand (operands[0], DImode)
2228        || reg_or_0_operand (operands[1], DImode))"
2229   { return loongarch_output_move (operands[0], operands[1]); }
2230   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2231   (operands[0]))"
2232   [(const_int 0)]
2233   "
2235   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2236   DONE;
2238   "
2239   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2240    (set_attr "mode" "DI")])
2242 ;; Use two registers to get the global symbol address from the got table.
2243 ;; la.global rd, rt, sym
2245 (define_insn_and_split "movdi_symbolic_off64"
2246  [(set (match_operand:DI 0 "register_operand" "=r,r")
2247        (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r"))
2248   (unspec:DI [(const_int 0)]
2249     UNSPEC_LOAD_SYMBOL_OFFSET64)
2250   (clobber (match_operand:DI 2 "register_operand" "=&r,r"))]
2251  "TARGET_64BIT && TARGET_CMODEL_EXTREME"
2253   if (which_alternative == 1)
2254     return "#";
2256   enum loongarch_symbol_type symbol_type;
2257   gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2259   switch (symbol_type)
2260     {
2261     case SYMBOL_PCREL64:
2262       return "la.local\t%0,%2,%1";
2263     case SYMBOL_GOT_DISP:
2264       return "la.global\t%0,%2,%1";
2265     case SYMBOL_TLS_IE:
2266       return "la.tls.ie\t%0,%2,%1";
2267     case SYMBOL_TLSGD:
2268       return "la.tls.gd\t%0,%2,%1";
2269     case SYMBOL_TLSLDM:
2270       return "la.tls.ld\t%0,%2,%1";
2272     default:
2273       gcc_unreachable ();
2274   }
2276  "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0"
2277  [(set (match_dup 0) (match_dup 1))]
2278  ""
2279  [(set_attr "mode" "DI")
2280   (set_attr "insn_count" "5")])
2282 ;; The 64-bit PC-relative part of address loading.
2283 ;; Note that the psABI does not allow splitting it.
2284 (define_insn "la_pcrel64_two_parts"
2285   [(set (match_operand:DI 0 "register_operand" "=r")
2286         (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1))
2287    (set (match_operand:DI 1 "register_operand" "=r")
2288         (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))]
2289   "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
2290   {
2291     return "pcalau12i\t%0,%r2\n\t"
2292            "addi.d\t%1,$r0,%L2\n\t"
2293            "lu32i.d\t%1,%R2\n\t"
2294            "lu52i.d\t%1,%1,%H2";
2295   }
2296   [(set_attr "move_type" "move")
2297    (set_attr "mode" "DI")
2298    (set_attr "length" "16")])
2300 ;; 32-bit Integer moves
2302 (define_expand "movsi"
2303   [(set (match_operand:SI 0 "")
2304         (match_operand:SI 1 ""))]
2305   ""
2307   if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2308     DONE;
2311 (define_insn_and_split "*movsi_internal"
2312   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m")
2313         (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f"))]
2314   "(register_operand (operands[0], SImode)
2315     || reg_or_0_operand (operands[1], SImode))"
2316   { return loongarch_output_move (operands[0], operands[1]); }
2317   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2318   (operands[0]))"
2319   [(const_int 0)]
2320   "
2322   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2323   DONE;
2325   "
2326   [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2327    (set_attr "mode" "SI")])
2329 ;; 16-bit Integer moves
2331 ;; Unlike most other insns, the move insns can't be split with
2332 ;; different predicates, because register spilling and other parts of
2333 ;; the compiler, have memoized the insn number already.
2334 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2336 (define_expand "movhi"
2337   [(set (match_operand:HI 0 "")
2338         (match_operand:HI 1 ""))]
2339   ""
2341   if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2342     DONE;
2345 (define_insn_and_split "*movhi_internal"
2346   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2347         (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2348   "(register_operand (operands[0], HImode)
2349        || reg_or_0_operand (operands[1], HImode))"
2350   { return loongarch_output_move (operands[0], operands[1]); }
2351   "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2352   (operands[0]))"
2353   [(const_int 0)]
2354   "
2356   loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2357   DONE;
2359   "
2360   [(set_attr "move_type" "move,const,const,load,store,load,store")
2361    (set_attr "mode" "HI")])
2363 ;; 8-bit Integer moves
2365 ;; Unlike most other insns, the move insns can't be split with
2366 ;; different predicates, because register spilling and other parts of
2367 ;; the compiler, have memoized the insn number already.
2368 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2370 (define_expand "movqi"
2371   [(set (match_operand:QI 0 "")
2372         (match_operand:QI 1 ""))]
2373   ""
2375   if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2376     DONE;
2379 (define_insn "*movqi_internal"
2380   [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2381         (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2382   "(register_operand (operands[0], QImode)
2383        || reg_or_0_operand (operands[1], QImode))"
2384   { return loongarch_output_move (operands[0], operands[1]); }
2385   [(set_attr "move_type" "move,const,load,store,load,store")
2386    (set_attr "mode" "QI")])
2388 ;; 32-bit floating point moves
2390 (define_expand "movsf"
2391   [(set (match_operand:SF 0 "")
2392         (match_operand:SF 1 ""))]
2393   ""
2395   if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2396     DONE;
2399 (define_insn "*movsf_hardfloat"
2400   [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2401         (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2402   "TARGET_HARD_FLOAT
2403    && (register_operand (operands[0], SFmode)
2404        || reg_or_0_operand (operands[1], SFmode))"
2405   { return loongarch_output_move (operands[0], operands[1]); }
2406   [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2407    (set_attr "mode" "SF")])
2409 (define_insn "*movsf_softfloat"
2410   [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2411         (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2412   "TARGET_SOFT_FLOAT
2413    && (register_operand (operands[0], SFmode)
2414        || reg_or_0_operand (operands[1], SFmode))"
2415   { return loongarch_output_move (operands[0], operands[1]); }
2416   [(set_attr "move_type" "move,load,store")
2417    (set_attr "mode" "SF")])
2419 ;; 64-bit floating point moves
2421 (define_expand "movdf"
2422   [(set (match_operand:DF 0 "")
2423         (match_operand:DF 1 ""))]
2424   ""
2426   if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2427     DONE;
2430 (define_insn "*movdf_hardfloat"
2431   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2432         (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2433   "TARGET_DOUBLE_FLOAT
2434    && (register_operand (operands[0], DFmode)
2435        || reg_or_0_operand (operands[1], DFmode))"
2436   { return loongarch_output_move (operands[0], operands[1]); }
2437   [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2438    (set_attr "mode" "DF")])
2440 (define_insn "*movdf_softfloat"
2441   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2442         (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2443   "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2444    && TARGET_64BIT
2445    && (register_operand (operands[0], DFmode)
2446        || reg_or_0_operand (operands[1], DFmode))"
2447   { return loongarch_output_move (operands[0], operands[1]); }
2448   [(set_attr "move_type" "move,load,store")
2449    (set_attr "mode" "DF")])
2451 ;; Clear one FCC register
2453 (define_expand "movfcc"
2454   [(set (match_operand:FCC 0 "")
2455         (match_operand:FCC 1 ""))]
2456   "TARGET_HARD_FLOAT"
2458   if (memory_operand (operands[0], FCCmode)
2459       && memory_operand (operands[1], FCCmode))
2460     operands[1] = force_reg (FCCmode, operands[1]);
2463 (define_insn "movfcc_internal"
2464   [(set (match_operand:FCC 0 "nonimmediate_operand"
2465                              "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2466         (match_operand:FCC 1 "reg_or_0_operand"
2467                              "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2468   "TARGET_HARD_FLOAT"
2469   "@
2470    fcmp.caf.s\t%0,$f0,$f0
2471    movfr2cf\t%0,%1
2472    movcf2fr\t%0,%1
2473    fmov.s\t%0,%1
2474    or\t%0,%z1,$r0
2475    ld.b\t%0,%1
2476    st.b\t%z1,%0
2477    movgr2fr.w\t%0,%1
2478    movfr2gr.s\t%0,%1
2479    movgr2cf\t%0,%1
2480    movcf2gr\t%0,%1"
2481   [(set_attr "type" "move")
2482    (set_attr "mode" "FCC")])
2484 (define_insn "fcc_to_<X:mode>"
2485   [(set (match_operand:X 0 "register_operand" "=r")
2486         (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2487                             (const_int 0))
2488                         (const_int 1)
2489                         (const_int 0)))]
2490   "TARGET_HARD_FLOAT"
2491   ""
2492   [(set_attr "length" "0")
2493    (set_attr "type" "ghost")])
2495 (define_expand "cstore<ANYF:mode>4"
2496   [(set (match_operand:SI 0 "register_operand")
2497         (match_operator:SI 1 "loongarch_fcmp_operator"
2498           [(match_operand:ANYF 2 "register_operand")
2499            (match_operand:ANYF 3 "register_operand")]))]
2500   ""
2501   {
2502     rtx fcc = gen_reg_rtx (FCCmode);
2503     rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2504                               operands[2], operands[3]);
2506     emit_insn (gen_rtx_SET (fcc, cmp));
2507     if (TARGET_64BIT)
2508       {
2509         rtx gpr = gen_reg_rtx (DImode);
2510         emit_insn (gen_fcc_to_di (gpr, fcc));
2511         emit_insn (gen_rtx_SET (operands[0],
2512                                 lowpart_subreg (SImode, gpr, DImode)));
2513       }
2514     else
2515       emit_insn (gen_fcc_to_si (operands[0], fcc));
2517     DONE;
2518   })
2520 ;; Conditional move instructions.
2522 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2523   [(set (match_operand:GPR 0 "register_operand" "=r,r")
2524         (if_then_else:GPR
2525          (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2526                            (const_int 0))
2527          (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2528          (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2529   "register_operand (operands[2], <GPR:MODE>mode)
2530    != register_operand (operands[3], <GPR:MODE>mode)"
2531   "@
2532    <sel>\t%0,%2,%1
2533    <selinv>\t%0,%3,%1"
2534   [(set_attr "type" "condmove")
2535    (set_attr "mode" "<GPR:MODE>")])
2537 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2538 ;; argument if the 1st is zero.  This means operand 2 and 3 are
2539 ;; inverted in the instruction.
2541 (define_insn "*sel<mode>"
2542   [(set (match_operand:ANYF 0 "register_operand" "=f")
2543         (if_then_else:ANYF
2544          (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2545                  (const_int 0))
2546          (match_operand:ANYF 2 "reg_or_0_operand" "f")
2547          (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2548   ""
2549   "fsel\t%0,%3,%2,%1"
2550   [(set_attr "type" "condmove")
2551    (set_attr "mode" "<ANYF:MODE>")])
2553 ;; These are the main define_expand's used to make conditional moves.
2555 (define_expand "mov<mode>cc"
2556   [(set (match_operand:GPR 0 "register_operand")
2557         (if_then_else:GPR (match_operator 1 "comparison_operator"
2558                          [(match_operand:GPR 2 "reg_or_0_operand")
2559                           (match_operand:GPR 3 "reg_or_0_operand")])))]
2560   "TARGET_COND_MOVE_INT"
2562   if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2563     FAIL;
2565   loongarch_expand_conditional_move (operands);
2566   DONE;
2569 (define_expand "mov<mode>cc"
2570   [(set (match_operand:ANYF 0 "register_operand")
2571         (if_then_else:ANYF (match_operator 1 "comparison_operator"
2572                           [(match_operand:ANYF 2 "reg_or_0_operand")
2573                            (match_operand:ANYF 3 "reg_or_0_operand")])))]
2574   "TARGET_COND_MOVE_FLOAT"
2576   if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2577     FAIL;
2579   loongarch_expand_conditional_move (operands);
2580   DONE;
2583 (define_insn "lu32i_d"
2584   [(set (match_operand:DI 0 "register_operand" "=r")
2585         (ior:DI
2586           (zero_extend:DI
2587             (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2588           (match_operand:DI 2 "const_lu32i_operand" "u")))]
2589   "TARGET_64BIT"
2590   "lu32i.d\t%0,%X2>>32"
2591   [(set_attr "type" "arith")
2592    (set_attr "mode" "DI")])
2594 (define_insn "lu52i_d"
2595   [(set (match_operand:DI 0 "register_operand" "=r")
2596         (ior:DI
2597           (and:DI (match_operand:DI 1 "register_operand" "r")
2598                   (match_operand 2 "lu52i_mask_operand"))
2599           (match_operand 3 "const_lu52i_operand" "v")))]
2600   "TARGET_64BIT"
2601   "lu52i.d\t%0,%1,%X3>>52"
2602   [(set_attr "type" "arith")
2603    (set_attr "mode" "DI")])
2605 ;; Instructions for adding the low 12 bits of an address to a register.
2606 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2607 ;; should be applied.
2609 (define_insn "*low<mode>"
2610   [(set (match_operand:P 0 "register_operand" "=r")
2611  (lo_sum:P (match_operand:P 1 "register_operand" " r")
2612      (match_operand:P 2 "symbolic_operand" "")))]
2613   ""
2614   "addi.<d>\t%0,%1,%L2"
2615   [(set_attr "type" "arith")
2616    (set_attr "mode" "<MODE>")])
2618 (define_insn "@tls_low<mode>"
2619   [(set (match_operand:P 0 "register_operand" "=r")
2620         (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2621                                     (match_operand:P 2 "symbolic_operand" "")))]
2622         UNSPEC_TLS_LOW))]
2623   ""
2624   "addi.<d>\t%0,%1,%L2"
2625   [(set_attr "type" "arith")
2626    (set_attr "mode" "<MODE>")])
2628 ;; Instructions for loading address from GOT entry.
2629 ;; operands[1] is pc plus the high half of the address difference with the got
2630 ;; entry;
2631 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2632 ;; got entry.
2633 ;; loongarch_print_operand works out which relocation should be applied.
2635 (define_insn "@ld_from_got<mode>"
2636   [(set (match_operand:P 0 "register_operand" "=r")
2637         (unspec:P [(mem:P (lo_sum:P
2638                                 (match_operand:P 1 "register_operand" "r")
2639                                 (match_operand:P 2 "symbolic_operand")))]
2640         UNSPEC_LOAD_FROM_GOT))]
2641   ""
2642   "%Q2ld.<d>\t%0,%1,%L2"
2643   [(set_attr "type" "move")]
2646 (define_insn "@lui_l_hi20<mode>"
2647   [(set (match_operand:P 0 "register_operand" "=r")
2648         (unspec:P [(match_operand:P 1 "symbolic_operand")]
2649         UNSPEC_LUI_L_HI20))]
2650   ""
2651   "lu12i.w\t%0,%r1"
2652   [(set_attr "type" "move")]
2655 (define_insn "@pcalau12i<mode>"
2656   [(set (match_operand:P 0 "register_operand" "=j")
2657         (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2658         UNSPEC_PCALAU12I))]
2659   ""
2660   "pcalau12i\t%0,%%pc_hi20(%1)"
2661   [(set_attr "type" "move")])
2663 ;; @pcalau12i may be used for sibcall so it has a strict constraint.  This
2664 ;; allows any general register as the operand.
2665 (define_insn "@pcalau12i_gr<mode>"
2666   [(set (match_operand:P 0 "register_operand" "=r")
2667        (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2668        UNSPEC_PCALAU12I_GR))]
2669   ""
2670   "pcalau12i\t%0,%%pc_hi20(%1)"
2671   [(set_attr "type" "move")])
2673 (define_insn "@add_tls_le_relax<mode>"
2674   [(set (match_operand:P 0 "register_operand" "=r")
2675         (unspec:P [(match_operand:P 1 "register_operand" "r")
2676                    (match_operand:P 2 "register_operand" "r")
2677                    (match_operand:P 3 "symbolic_operand")]
2678           UNSPEC_ADD_TLS_LE_RELAX))]
2679   "HAVE_AS_TLS_LE_RELAXATION"
2680   "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2681   [(set_attr "type" "move")]
2684 (define_insn "@ori_l_lo12<mode>"
2685   [(set (match_operand:P 0 "register_operand" "=r")
2686         (unspec:P [(match_operand:P 1 "register_operand" "r")
2687                    (match_operand:P 2 "symbolic_operand")]
2688         UNSPEC_ORI_L_LO12))]
2689   ""
2690   "ori\t%0,%1,%L2"
2691   [(set_attr "type" "move")]
2694 (define_insn "lui_h_lo20"
2695   [(set (match_operand:DI 0 "register_operand" "=r")
2696         (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2697                     (match_operand:DI 2 "symbolic_operand")]
2698         UNSPEC_LUI_H_LO20))]
2699   "TARGET_64BIT"
2700   "lu32i.d\t%0,%R2"
2701   [(set_attr "type" "move")]
2704 (define_insn "lui_h_hi12"
2705   [(set (match_operand:DI 0 "register_operand" "=r")
2706         (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2707                     (match_operand:DI 2 "symbolic_operand")]
2708         UNSPEC_LUI_H_HI12))]
2709   "TARGET_64BIT"
2710   "lu52i.d\t%0,%1,%H2"
2711   [(set_attr "type" "move")]
2714 ;; Round floating-point numbers to integers
2715 (define_insn "rint<mode>2"
2716   [(set (match_operand:ANYF 0 "register_operand" "=f")
2717         (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2718                       UNSPEC_FRINT))]
2719   ""
2720   "frint.<fmt>\t%0,%1"
2721   [(set_attr "type" "fcvt")
2722    (set_attr "mode" "<MODE>")])
2724 ;; Convert floating-point numbers to integers
2725 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2726   [(set (match_operand:ANYFI 0 "register_operand" "=f")
2727         (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2728                       LRINT))]
2729   "TARGET_HARD_FLOAT &&
2730    (<LRINT> == UNSPEC_FTINT
2731     || flag_fp_int_builtin_inexact
2732     || !flag_trapping_math)"
2733   "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2734   [(set_attr "type" "fcvt")
2735    (set_attr "mode" "<ANYF:MODE>")])
2737 ;; Thread-Local Storage
2739 (define_insn "@got_load_tls_desc<mode>"
2740   [(set (reg:P 4)
2741         (unspec:P
2742             [(match_operand:P 0 "symbolic_operand" "")]
2743             UNSPEC_TLS_DESC))
2744     (clobber (reg:SI FCC0_REGNUM))
2745     (clobber (reg:SI FCC1_REGNUM))
2746     (clobber (reg:SI FCC2_REGNUM))
2747     (clobber (reg:SI FCC3_REGNUM))
2748     (clobber (reg:SI FCC4_REGNUM))
2749     (clobber (reg:SI FCC5_REGNUM))
2750     (clobber (reg:SI FCC6_REGNUM))
2751     (clobber (reg:SI FCC7_REGNUM))
2752     (clobber (reg:SI RETURN_ADDR_REGNUM))]
2753   "TARGET_TLS_DESC"
2755   return TARGET_EXPLICIT_RELOCS
2756     ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2757       "addi.d\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
2758       "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2759       "jirl\t$r1,$r1,%%desc_call(%0)"
2760     : "la.tls.desc\t$r4,%0";
2762   [(set_attr "got" "load")
2763    (set_attr "mode" "<MODE>")
2764    (set_attr "length" "16")])
2766 (define_insn "got_load_tls_desc_off64"
2767   [(set (reg:DI 4)
2768         (unspec:DI
2769             [(match_operand:DI 0 "symbolic_operand" "")]
2770             UNSPEC_TLS_DESC_OFF64))
2771     (clobber (reg:SI FCC0_REGNUM))
2772     (clobber (reg:SI FCC1_REGNUM))
2773     (clobber (reg:SI FCC2_REGNUM))
2774     (clobber (reg:SI FCC3_REGNUM))
2775     (clobber (reg:SI FCC4_REGNUM))
2776     (clobber (reg:SI FCC5_REGNUM))
2777     (clobber (reg:SI FCC6_REGNUM))
2778     (clobber (reg:SI FCC7_REGNUM))
2779     (clobber (reg:SI RETURN_ADDR_REGNUM))
2780     (clobber (match_operand:DI 1 "register_operand" "=&r"))]
2781   "TARGET_TLS_DESC && TARGET_CMODEL_EXTREME"
2783   return TARGET_EXPLICIT_RELOCS
2784     ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2785       "addi.d\t%1,$r0,%%desc_pc_lo12(%0)\n\t"
2786       "lu32i.d\t%1,%%desc64_pc_lo20(%0)\n\t"
2787       "lu52i.d\t%1,%1,%%desc64_pc_hi12(%0)\n\t"
2788       "add.d\t$r4,$r4,%1\n\t"
2789       "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2790       "jirl\t$r1,$r1,%%desc_call(%0)"
2791     : "la.tls.desc\t$r4,%1,%0";
2793   [(set_attr "got" "load")
2794    (set_attr "length" "28")])
2796 (define_insn "@load_tls<mode>"
2797   [(set (match_operand:P 0 "register_operand" "=r")
2798         (unspec:P
2799             [(match_operand:P 1 "symbolic_operand" "")]
2800             UNSPEC_TLS))]
2801   ""
2803   enum loongarch_symbol_type symbol_type;
2804   gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2806   switch (symbol_type)
2807     {
2808     case SYMBOL_TLS_LE:
2809       return "la.tls.le\t%0,%1";
2810     case SYMBOL_TLS_IE:
2811       return "la.tls.ie\t%0,%1";
2812     case SYMBOL_TLSLDM:
2813       return "la.tls.ld\t%0,%1";
2814     case SYMBOL_TLSGD:
2815       return "la.tls.gd\t%0,%1";
2817     default:
2818       gcc_unreachable ();
2819     }
2821   [(set_attr "mode" "<MODE>")
2822    (set (attr "insn_count")
2823       (if_then_else
2824         (match_test "TARGET_CMODEL_EXTREME")
2825         (const_int 4)
2826         (const_int 2)))])
2829 ;; Expand in-line code to clear the instruction cache between operand[0] and
2830 ;; operand[1].
2831 (define_expand "clear_cache"
2832   [(match_operand 0 "pmode_register_operand")
2833    (match_operand 1 "pmode_register_operand")]
2834   ""
2836   emit_insn (gen_loongarch_ibar (const0_rtx));
2837   DONE;
2840 (define_insn "loongarch_ibar"
2841   [(unspec_volatile:SI
2842       [(match_operand 0 "const_uimm15_operand")]
2843        UNSPECV_IBAR)
2844    (clobber (mem:BLK (scratch)))]
2845   ""
2846   "ibar\t%0")
2848 (define_insn "loongarch_dbar"
2849   [(unspec_volatile:SI
2850       [(match_operand 0 "const_uimm15_operand")]
2851        UNSPECV_DBAR)
2852    (clobber (mem:BLK (scratch)))]
2853   ""
2854   "dbar\t%0")
2858 ;; Privileged state instruction
2860 (define_insn "loongarch_cpucfg"
2861   [(set (match_operand:SI 0 "register_operand" "=r")
2862         (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2863                              UNSPECV_CPUCFG))]
2864   ""
2865   "cpucfg\t%0,%1"
2866   [(set_attr "type" "load")
2867    (set_attr "mode" "SI")])
2869 (define_insn "loongarch_syscall"
2870   [(unspec_volatile:SI
2871       [(match_operand 0 "const_uimm15_operand")]
2872        UNSPECV_SYSCALL)
2873    (clobber (mem:BLK (scratch)))]
2874   ""
2875   "syscall\t%0")
2877 (define_insn "loongarch_break"
2878   [(unspec_volatile:SI
2879       [(match_operand 0 "const_uimm15_operand")]
2880        UNSPECV_BREAK)
2881    (clobber (mem:BLK (scratch)))]
2882   ""
2883   "break\t%0")
2885 (define_insn "loongarch_asrtle_d"
2886   [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2887                         (match_operand:DI 1 "register_operand" "r")]
2888                         UNSPECV_ASRTLE_D)]
2889   "TARGET_64BIT"
2890   "asrtle.d\t%0,%1"
2891   [(set_attr "type" "load")
2892    (set_attr "mode" "DI")])
2894 (define_insn "loongarch_asrtgt_d"
2895   [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2896                         (match_operand:DI 1 "register_operand" "r")]
2897                         UNSPECV_ASRTGT_D)]
2898   "TARGET_64BIT"
2899   "asrtgt.d\t%0,%1"
2900   [(set_attr "type" "load")
2901    (set_attr "mode" "DI")])
2903 (define_insn "loongarch_csrrd_<d>"
2904   [(set (match_operand:GPR 0 "register_operand" "=r")
2905         (unspec_volatile:GPR [(match_operand  1 "const_uimm14_operand")]
2906                               UNSPECV_CSRRD))
2907    (clobber (mem:BLK (scratch)))]
2908   ""
2909   "csrrd\t%0,%1"
2910   [(set_attr "type" "load")
2911    (set_attr "mode" "<MODE>")])
2913 (define_insn "loongarch_csrwr_<d>"
2914   [(set (match_operand:GPR 0 "register_operand" "=r")
2915           (unspec_volatile:GPR
2916             [(match_operand:GPR 1 "register_operand" "0")
2917              (match_operand 2 "const_uimm14_operand")]
2918              UNSPECV_CSRWR))
2919    (clobber (mem:BLK (scratch)))]
2920   ""
2921   "csrwr\t%0,%2"
2922   [(set_attr "type" "store")
2923    (set_attr "mode" "<MODE>")])
2925 (define_insn "loongarch_csrxchg_<d>"
2926   [(set (match_operand:GPR 0 "register_operand" "=r")
2927           (unspec_volatile:GPR
2928             [(match_operand:GPR 1 "register_operand" "0")
2929              (match_operand:GPR 2 "register_operand" "q")
2930              (match_operand 3 "const_uimm14_operand")]
2931              UNSPECV_CSRXCHG))
2932    (clobber (mem:BLK (scratch)))]
2933   ""
2934   "csrxchg\t%0,%2,%3"
2935   [(set_attr "type" "load")
2936    (set_attr "mode" "<MODE>")])
2938 (define_insn "loongarch_iocsrrd_<size>"
2939   [(set (match_operand:QHWD 0 "register_operand" "=r")
2940         (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2941                               UNSPECV_IOCSRRD))
2942    (clobber (mem:BLK (scratch)))]
2943   ""
2944   "iocsrrd.<size>\t%0,%1"
2945   [(set_attr "type" "load")
2946    (set_attr "mode" "<MODE>")])
2948 (define_insn "loongarch_iocsrwr_<size>"
2949   [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2950                           (match_operand:SI 1 "register_operand" "r")]
2951                           UNSPECV_IOCSRWR)
2952    (clobber (mem:BLK (scratch)))]
2953   ""
2954   "iocsrwr.<size>\t%0,%1"
2955   [(set_attr "type" "load")
2956    (set_attr "mode" "<MODE>")])
2958 (define_insn "loongarch_cacop_<d>"
2959   [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2960                        (match_operand:X 1 "register_operand" "r")
2961                        (match_operand 2 "const_imm12_operand")]
2962                        UNSPECV_CACOP)
2963    (clobber (mem:BLK (scratch)))]
2964   ""
2965   "cacop\t%0,%1,%2"
2966   [(set_attr "type" "load")
2967    (set_attr "mode" "<MODE>")])
2969 (define_insn "loongarch_lddir_<d>"
2970   [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2971                        (match_operand:X 1 "register_operand" "r")
2972                        (match_operand 2 "const_uimm5_operand")]
2973                        UNSPECV_LDDIR)
2974    (clobber (mem:BLK (scratch)))]
2975   ""
2976   "lddir\t%0,%1,%2"
2977   [(set_attr "type" "load")
2978    (set_attr "mode" "<MODE>")])
2980 (define_insn "loongarch_ldpte_<d>"
2981   [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2982                        (match_operand 1 "const_uimm5_operand")]
2983                        UNSPECV_LDPTE)
2984    (clobber (mem:BLK (scratch)))]
2985   ""
2986   "ldpte\t%0,%1"
2987   [(set_attr "type" "load")
2988    (set_attr "mode" "<MODE>")])
2991 ;; Block moves, see loongarch.c for more details.
2992 ;; Argument 0 is the destination.
2993 ;; Argument 1 is the source.
2994 ;; Argument 2 is the length.
2995 ;; Argument 3 is the alignment.
2997 (define_expand "cpymemsi"
2998   [(parallel [(set (match_operand:BLK 0 "general_operand")
2999                    (match_operand:BLK 1 "general_operand"))
3000               (use (match_operand:SI 2 ""))
3001               (use (match_operand:SI 3 "const_int_operand"))])]
3002   ""
3004   if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
3005       && loongarch_expand_block_move (operands[0], operands[1],
3006                                       operands[2], operands[3]))
3007     DONE;
3008   else
3009     FAIL;
3013 ;;  ....................
3015 ;;      SHIFTS
3017 ;;  ....................
3019 (define_insn "*<optab><mode>3"
3020   [(set (match_operand:GPR 0 "register_operand" "=r")
3021         (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
3022                        (match_operand:SI 2 "arith_operand" "rI")))]
3023   ""
3025   if (CONST_INT_P (operands[2]))
3026     operands[2] = GEN_INT (INTVAL (operands[2])
3027                            & (GET_MODE_BITSIZE (<MODE>mode) - 1));
3029   return "<insn>%i2.<d>\t%0,%1,%2";
3031   [(set_attr "type" "shift")
3032    (set_attr "mode" "<MODE>")])
3034 (define_insn "<optab>si3_extend"
3035   [(set (match_operand:DI 0 "register_operand" "=r")
3036         (sign_extend:DI
3037            (any_shift:SI (match_operand:SI 1 "register_operand" "r")
3038                          (match_operand:SI 2 "arith_operand" "rI"))))]
3039   "TARGET_64BIT"
3041   if (CONST_INT_P (operands[2]))
3042     operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
3044   return "<insn>%i2.w\t%0,%1,%2";
3046   [(set_attr "type" "shift")
3047    (set_attr "mode" "SI")])
3049 (define_insn "*rotr<mode>3"
3050   [(set (match_operand:GPR 0 "register_operand" "=r,r")
3051         (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
3052                       (match_operand:SI 2 "arith_operand" "r,I")))]
3053   ""
3054   "rotr%i2.<d>\t%0,%1,%2"
3055   [(set_attr "type" "shift,shift")
3056    (set_attr "mode" "<MODE>")])
3058 (define_insn "rotrsi3_extend"
3059   [(set (match_operand:DI 0 "register_operand" "=r,r")
3060         (sign_extend:DI
3061           (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
3062                        (match_operand:SI 2 "arith_operand" "r,I"))))]
3063   "TARGET_64BIT"
3064   "rotr%i2.w\t%0,%1,%2"
3065   [(set_attr "type" "shift,shift")
3066    (set_attr "mode" "SI")])
3068 ;; Expand left rotate to right rotate.
3069 (define_expand "rotl<mode>3"
3070   [(set (match_dup 3)
3071         (neg:SI (match_operand:SI 2 "register_operand")))
3072    (set (match_operand:GPR 0 "register_operand")
3073         (rotatert:GPR (match_operand:GPR 1 "register_operand")
3074                       (match_dup 3)))]
3075   ""
3076   {
3077     operands[3] = gen_reg_rtx (SImode);
3079     if (TARGET_64BIT && <MODE>mode == SImode)
3080       {
3081         rtx t = gen_reg_rtx (DImode);
3083         emit_insn (gen_negsi2 (operands[3], operands[2]));
3084         emit_insn (gen_rotrsi3_extend (t, operands[1], operands[3]));
3085         t = gen_lowpart (SImode, t);
3086         SUBREG_PROMOTED_VAR_P (t) = 1;
3087         SUBREG_PROMOTED_SET (t, SRP_SIGNED);
3088         emit_move_insn (operands[0], t);
3089         DONE;
3090       }
3091   });
3093 ;; The following templates were added to generate "bstrpick.d + alsl.d"
3094 ;; instruction pairs.
3095 ;; It is required that the values of const_immalsl_operand and
3096 ;; immediate_operand must have the following correspondence:
3098 ;; (immediate_operand >> const_immalsl_operand) == 0xffffffff
3100 (define_insn "zero_extend_ashift"
3101   [(set (match_operand:DI 0 "register_operand" "=r")
3102         (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
3103                            (match_operand 2 "const_immalsl_operand" ""))
3104                 (match_operand 3 "immediate_operand" "")))]
3105   "TARGET_64BIT
3106    && ((INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff)"
3107   "bstrpick.d\t%0,%1,31,0\n\talsl.d\t%0,%0,$r0,%2"
3108   [(set_attr "type" "arith")
3109    (set_attr "mode" "DI")
3110    (set_attr "insn_count" "2")])
3112 (define_insn "bstrpick_alsl_paired"
3113   [(set (match_operand:DI 0 "register_operand" "=&r")
3114         (plus:DI (match_operand:DI 1 "register_operand" "r")
3115                  (and:DI (ashift:DI (match_operand:DI 2 "register_operand" "r")
3116                                     (match_operand 3 "const_immalsl_operand" ""))
3117                          (match_operand 4 "immediate_operand" ""))))]
3118   "TARGET_64BIT
3119    && ((INTVAL (operands[4]) >> INTVAL (operands[3])) == 0xffffffff)"
3120   "bstrpick.d\t%0,%2,31,0\n\talsl.d\t%0,%0,%1,%3"
3121   [(set_attr "type" "arith")
3122    (set_attr "mode" "DI")
3123    (set_attr "insn_count" "2")])
3125 (define_insn "alsl<mode>3"
3126   [(set (match_operand:GPR 0 "register_operand" "=r")
3127         (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
3128                               (match_operand 2 "const_immalsl_operand" ""))
3129                   (match_operand:GPR 3 "register_operand" "r")))]
3130   ""
3131   "alsl.<d>\t%0,%1,%3,%2"
3132   [(set_attr "type" "arith")
3133    (set_attr "mode" "<MODE>")])
3135 (define_insn "alslsi3_extend"
3136   [(set (match_operand:DI 0 "register_operand" "=r")
3137         (sign_extend:DI
3138           (plus:SI
3139             (ashift:SI (match_operand:SI 1 "register_operand" "r")
3140                        (match_operand 2 "const_immalsl_operand" ""))
3141             (match_operand:SI 3 "register_operand" "r"))))]
3142   ""
3143   "alsl.w\t%0,%1,%3,%2"
3144   [(set_attr "type" "arith")
3145    (set_attr "mode" "SI")])
3149 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
3151 (define_insn "revb_2h"
3152   [(set (match_operand:SI 0 "register_operand" "=r")
3153         (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3154                      (const_int 16)))]
3155   ""
3156   "revb.2h\t%0,%1"
3157   [(set_attr "type" "shift")])
3159 (define_insn "revb_2h_extend"
3160   [(set (match_operand:DI 0 "register_operand" "=r")
3161         (sign_extend:DI
3162           (rotatert:SI
3163             (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3164             (const_int 16))))]
3165   "TARGET_64BIT"
3166   "revb.2h\t%0,%1"
3167   [(set_attr "type" "shift")])
3169 (define_insn "bswaphi2"
3170   [(set (match_operand:HI 0 "register_operand" "=r")
3171         (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
3172   ""
3173   "revb.2h\t%0,%1"
3174   [(set_attr "type" "shift")])
3176 (define_insn "revb_2w"
3177   [(set (match_operand:DI 0 "register_operand" "=r")
3178         (rotatert:DI (bswap:DI (match_operand:DI 1 "register_operand" "r"))
3179                      (const_int 32)))]
3180   "TARGET_64BIT"
3181   "revb.2w\t%0,%1"
3182   [(set_attr "type" "shift")])
3184 (define_insn "*bswapsi2"
3185   [(set (match_operand:SI 0 "register_operand" "=r")
3186         (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3187   "TARGET_64BIT"
3188   "revb.2w\t%0,%1"
3189   [(set_attr "type" "shift")])
3191 (define_expand "bswapsi2"
3192   [(set (match_operand:SI 0 "register_operand" "=r")
3193         (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3194   ""
3196   if (!TARGET_64BIT)
3197     {
3198       rtx t = gen_reg_rtx (SImode);
3199       emit_insn (gen_revb_2h (t, operands[1]));
3200       emit_insn (gen_rotrsi3 (operands[0], t, GEN_INT (16)));
3201       DONE;
3202     }
3205 (define_insn "bswapdi2"
3206   [(set (match_operand:DI 0 "register_operand" "=r")
3207         (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3208   "TARGET_64BIT"
3209   "revb.d\t%0,%1"
3210   [(set_attr "type" "shift")])
3214 ;;  ....................
3216 ;;      CONDITIONAL BRANCHES
3218 ;;  ....................
3220 ;; Conditional branches
3222 (define_insn "*branch_fp_FCCmode"
3223   [(set (pc)
3224         (if_then_else
3225           (match_operator 1 "equality_operator"
3226               [(match_operand:FCC 2 "register_operand" "z")
3227                 (const_int 0)])
3228           (label_ref (match_operand 0 "" ""))
3229         (pc)))]
3230   "TARGET_HARD_FLOAT"
3232   return loongarch_output_conditional_branch (insn, operands,
3233                                               LARCH_BRANCH ("b%F1", "%Z2%0"),
3234                                               LARCH_BRANCH ("b%W1", "%Z2%0"));
3236   [(set_attr "type" "branch")])
3238 (define_insn "*branch_fp_inverted_FCCmode"
3239   [(set (pc)
3240         (if_then_else
3241           (match_operator 1 "equality_operator"
3242             [(match_operand:FCC 2 "register_operand" "z")
3243             (const_int 0)])
3244           (pc)
3245           (label_ref (match_operand 0 "" ""))))]
3246   "TARGET_HARD_FLOAT"
3248   return loongarch_output_conditional_branch (insn, operands,
3249                                               LARCH_BRANCH ("b%W1", "%Z2%0"),
3250                                               LARCH_BRANCH ("b%F1", "%Z2%0"));
3252   [(set_attr "type" "branch")])
3254 ;; Conditional branches on ordered comparisons with zero.
3256 (define_insn "*branch_order<mode>"
3257   [(set (pc)
3258         (if_then_else
3259          (match_operator 1 "order_operator"
3260                          [(match_operand:X 2 "register_operand" "r,r")
3261                           (match_operand:X 3 "reg_or_0_operand" "J,r")])
3262          (label_ref (match_operand 0 "" ""))
3263          (pc)))]
3264   ""
3265   { return loongarch_output_order_conditional_branch (insn, operands, false); }
3266   [(set_attr "type" "branch")])
3268 (define_insn "*branch_order<mode>_inverted"
3269   [(set (pc)
3270         (if_then_else
3271          (match_operator 1 "order_operator"
3272                          [(match_operand:X 2 "register_operand" "r,r")
3273                           (match_operand:X 3 "reg_or_0_operand" "J,r")])
3274          (pc)
3275          (label_ref (match_operand 0 "" ""))))]
3276   ""
3277   { return loongarch_output_order_conditional_branch (insn, operands, true); }
3278   [(set_attr "type" "branch")])
3280 ;; Conditional branch on equality comparison.
3282 (define_insn "branch_equality<mode>"
3283   [(set (pc)
3284         (if_then_else
3285          (match_operator 1 "equality_operator"
3286                          [(match_operand:X 2 "register_operand" "r")
3287                           (match_operand:X 3 "reg_or_0_operand" "rJ")])
3288          (label_ref (match_operand 0 "" ""))
3289          (pc)))]
3290   ""
3291   { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3292   [(set_attr "type" "branch")])
3295 (define_insn "*branch_equality<mode>_inverted"
3296   [(set (pc)
3297         (if_then_else
3298          (match_operator 1 "equality_operator"
3299                          [(match_operand:X 2 "register_operand" "r")
3300                           (match_operand:X 3 "reg_or_0_operand" "rJ")])
3301          (pc)
3302          (label_ref (match_operand 0 "" ""))))]
3303   ""
3304   { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3305   [(set_attr "type" "branch")])
3308 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3309 ;; QImode values so we can force zero-extension.
3310 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3312 (define_expand "cbranch<mode>4"
3313   [(set (pc)
3314         (if_then_else (match_operator 0 "comparison_operator"
3315                         [(match_operand:BR 1 "register_operand")
3316                          (match_operand:BR 2 "nonmemory_operand")])
3317                       (label_ref (match_operand 3 ""))
3318                       (pc)))]
3319   ""
3321   loongarch_expand_conditional_branch (operands);
3322   DONE;
3325 (define_expand "cbranch<mode>4"
3326   [(set (pc)
3327         (if_then_else (match_operator 0 "comparison_operator"
3328                         [(match_operand:ANYF 1 "register_operand")
3329                          (match_operand:ANYF 2 "register_operand")])
3330                       (label_ref (match_operand 3 ""))
3331                       (pc)))]
3332   ""
3334   loongarch_expand_conditional_branch (operands);
3335   DONE;
3338 ;; Used to implement built-in functions.
3339 (define_expand "condjump"
3340   [(set (pc)
3341         (if_then_else (match_operand 0)
3342                       (label_ref (match_operand 1))
3343                       (pc)))])
3347 ;;  ....................
3349 ;;      SETTING A REGISTER FROM A COMPARISON
3351 ;;  ....................
3353 ;; Destination is always set in SI mode.
3355 (define_expand "cstore<mode>4"
3356   [(set (match_operand:SI 0 "register_operand")
3357         (match_operator:SI 1 "loongarch_cstore_operator"
3358          [(match_operand:GPR 2 "register_operand")
3359           (match_operand:GPR 3 "nonmemory_operand")]))]
3360   ""
3362   loongarch_expand_scc (operands);
3363   DONE;
3366 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3367   [(set (match_operand:GPR 0 "register_operand" "=r")
3368         (eq:GPR (match_operand:X 1 "register_operand" "r")
3369                  (const_int 0)))]
3370   ""
3371   "sltui\t%0,%1,1"
3372   [(set_attr "type" "slt")
3373    (set_attr "mode" "<X:MODE>")])
3376 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3377   [(set (match_operand:GPR 0 "register_operand" "=r")
3378         (ne:GPR (match_operand:X 1 "register_operand" "r")
3379                  (const_int 0)))]
3380   ""
3381   "sltu\t%0,%.,%1"
3382   [(set_attr "type" "slt")
3383    (set_attr "mode" "<X:MODE>")])
3385 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3386   [(set (match_operand:GPR 0 "register_operand" "=r")
3387         (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3388                      (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3389   ""
3390   "slt<u>\t%0,%z2,%1"
3391   [(set_attr "type" "slt")
3392    (set_attr "mode" "<X:MODE>")])
3394 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3395   [(set (match_operand:GPR 0 "register_operand" "=r")
3396         (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3397                      (match_operand:X 2 "arith_operand" "rI")))]
3398   ""
3399   "slt<u>%i2\t%0,%1,%2";
3400   [(set_attr "type" "slt")
3401    (set_attr "mode" "<X:MODE>")])
3403 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3404   [(set (match_operand:GPR 0 "register_operand" "=r")
3405         (any_le:GPR (match_operand:X 1 "register_operand" "r")
3406                     (match_operand:X 2 "sle_operand" "")))]
3407   ""
3409   operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3410   return "slt<u>i\t%0,%1,%2";
3412   [(set_attr "type" "slt")
3413    (set_attr "mode" "<X:MODE>")])
3417 ;;  ....................
3419 ;;      FLOATING POINT COMPARISONS
3421 ;;  ....................
3423 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3424   [(set (match_operand:FCC 0 "register_operand" "=z")
3425         (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3426                    (match_operand:ANYF 2 "register_operand" "f")))]
3427   ""
3428   "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3429   [(set_attr "type" "fcmp")
3430    (set_attr "mode" "FCC")])
3434 ;;  ....................
3436 ;;      UNCONDITIONAL BRANCHES
3438 ;;  ....................
3440 ;; Unconditional branches.
3442 (define_expand "jump"
3443   [(set (pc)
3444         (label_ref (match_operand 0)))])
3446 (define_insn "*jump_absolute"
3447   [(set (pc)
3448         (label_ref (match_operand 0)))]
3449   "!flag_pic"
3451   return "b\t%l0";
3453   [(set_attr "type" "branch")])
3455 (define_insn "*jump_pic"
3456   [(set (pc)
3457         (label_ref (match_operand 0)))]
3458   "flag_pic"
3460   return "b\t%0";
3462   [(set_attr "type" "branch")])
3464 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3465 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3466 ;; return prediction and the more general indirect branch prediction.
3468 (define_expand "indirect_jump"
3469   [(set (pc) (match_operand 0 "register_operand"))]
3470   ""
3472   operands[0] = force_reg (Pmode, operands[0]);
3473   emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3474   DONE;
3477 (define_insn "@indirect_jump<mode>"
3478   [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3479   ""
3480   "jr\t%0"
3481   [(set_attr "type" "jump")
3482    (set_attr "mode" "none")])
3484 (define_expand "tablejump"
3485   [(set (pc)
3486         (match_operand 0 "register_operand"))
3487    (use (label_ref (match_operand 1 "")))]
3488   ""
3490   if (flag_pic)
3491     operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3492                                        gen_rtx_LABEL_REF (Pmode,
3493                                                           operands[1]),
3494                                        NULL_RTX, 0, OPTAB_DIRECT);
3495   emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3496   DONE;
3499 (define_insn "@tablejump<mode>"
3500   [(set (pc)
3501         (match_operand:P 0 "register_operand" "e"))
3502    (use (label_ref (match_operand 1 "" "")))]
3503   ""
3504   "jr\t%0"
3505   [(set_attr "type" "jump")
3506    (set_attr "mode" "none")])
3511 ;;  ....................
3513 ;;      Function prologue/epilogue
3515 ;;  ....................
3518 (define_expand "prologue"
3519   [(const_int 1)]
3520   ""
3522   loongarch_expand_prologue ();
3523   DONE;
3526 ;; Block any insns from being moved before this point, since the
3527 ;; profiling call to mcount can use various registers that aren't
3528 ;; saved or used to pass arguments.
3530 (define_insn "blockage"
3531   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3532   ""
3533   ""
3534   [(set_attr "type" "ghost")
3535    (set_attr "mode" "none")])
3537 (define_insn "@probe_stack_range<P:mode>"
3538   [(set (match_operand:P 0 "register_operand" "=r")
3539         (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3540                             (match_operand:P 2 "register_operand" "r")
3541                             (match_operand:P 3 "register_operand" "r")]
3542                             UNSPECV_PROBE_STACK_RANGE))]
3543   ""
3545   return loongarch_output_probe_stack_range (operands[0],
3546                                              operands[2],
3547                                              operands[3]);
3549   [(set_attr "type" "unknown")
3550    (set_attr "mode" "<MODE>")])
3552 (define_expand "epilogue"
3553   [(const_int 2)]
3554   ""
3556   loongarch_expand_epilogue (NORMAL_RETURN);
3557   DONE;
3560 (define_expand "sibcall_epilogue"
3561   [(const_int 2)]
3562   ""
3564   loongarch_expand_epilogue (SIBCALL_RETURN);
3565   DONE;
3568 ;; Trivial return.  Make it look like a normal return insn as that
3569 ;; allows jump optimizations to work better.
3571 (define_expand "return"
3572   [(simple_return)]
3573   "loongarch_can_use_return_insn ()"
3574   { })
3576 (define_expand "simple_return"
3577   [(simple_return)]
3578   ""
3579   { })
3581 (define_insn "*<optab>"
3582   [(any_return)]
3583   ""
3585   operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3586   return "jr\t%0";
3588   [(set_attr "type" "jump")
3589    (set_attr "mode" "none")])
3591 ;; Normal return.
3593 (define_insn "<optab>_internal"
3594   [(any_return)
3595    (use (match_operand 0 "pmode_register_operand" ""))]
3596   ""
3597   "jr\t%0"
3598   [(set_attr "type" "jump")
3599    (set_attr "mode" "none")])
3601 ;; Exception return.
3602 (define_insn "loongarch_ertn"
3603   [(return)
3604    (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3605   ""
3606   "ertn"
3607   [(set_attr "type" "trap")
3608    (set_attr "mode" "none")])
3610 ;; This is used in compiling the unwind routines.
3611 (define_expand "eh_return"
3612   [(use (match_operand 0 "general_operand"))]
3613   ""
3615   if (GET_MODE (operands[0]) != word_mode)
3616     operands[0] = convert_to_mode (word_mode, operands[0], 0);
3617   if (TARGET_64BIT)
3618     emit_insn (gen_eh_set_ra_di (operands[0]));
3619   else
3620     emit_insn (gen_eh_set_ra_si (operands[0]));
3622   emit_jump_insn (gen_eh_return_internal ());
3623   emit_barrier ();
3624   DONE;
3627 (define_insn_and_split "eh_return_internal"
3628   [(eh_return)]
3629   ""
3630   "#"
3631   "epilogue_completed"
3632   [(const_int 0)]
3634   loongarch_expand_epilogue (EXCEPTION_RETURN);
3635   DONE;
3638 ;; Clobber the return address on the stack.  We can't expand this
3639 ;; until we know where it will be put in the stack frame.
3641 (define_insn "eh_set_ra_si"
3642   [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3643    (clobber (match_scratch:SI 1 "=&r"))]
3644   "! TARGET_64BIT"
3645   "#")
3647 (define_insn "eh_set_ra_di"
3648   [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3649    (clobber (match_scratch:DI 1 "=&r"))]
3650   "TARGET_64BIT"
3651   "#")
3653 (define_split
3654   [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3655    (clobber (match_scratch 1))]
3656   "reload_completed"
3657   [(const_int 0)]
3659   loongarch_set_return_address (operands[0], operands[1]);
3660   DONE;
3666 ;;  ....................
3668 ;;      FUNCTION CALLS
3670 ;;  ....................
3672 ;; Sibling calls.  All these patterns use jump instructions.
3674 (define_expand "sibcall"
3675   [(parallel [(call (match_operand 0 "")
3676                     (match_operand 1 ""))
3677               (use (match_operand 2 ""))        ;; next_arg_reg
3678               (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
3679   ""
3681   rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3683   if (GET_CODE (target) == LO_SUM)
3684     emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3685                                             XEXP (target, 1),
3686                                             operands[1]));
3687   else
3688     {
3689       rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3691       if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3692         clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3693                      gen_rtx_REG (Pmode, T0_REGNUM));
3694     }
3695   DONE;
3698 (define_insn "sibcall_internal"
3699   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3700          (match_operand 1 "" ""))]
3701   "SIBLING_CALL_P (insn)"
3703   switch (which_alternative)
3704     {
3705     case 0:
3706       return "jr\t%0";
3707     case 1:
3708       if (TARGET_CMODEL_MEDIUM)
3709         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3710       else
3711         return "b\t%0";
3712     case 2:
3713       if (TARGET_CMODEL_MEDIUM)
3714         return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3715       else
3716         return "b\t%%plt(%0)";
3717     default:
3718       gcc_unreachable ();
3719     }
3721   [(set_attr "jirl" "indirect,direct,direct")])
3723 (define_insn "@sibcall_internal_1<mode>"
3724   [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3725                           (match_operand:P 1 "symbolic_operand" "")))
3726          (match_operand 2 "" ""))]
3727   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3728   "jirl\t$r0,%0,%%pc_lo12(%1)"
3729   [(set_attr "jirl" "indirect")])
3731 (define_expand "sibcall_value"
3732   [(parallel [(set (match_operand 0 "")
3733                    (call (match_operand 1 "")
3734                          (match_operand 2 "")))
3735               (use (match_operand 3 ""))])]             ;; next_arg_reg
3736   ""
3738   rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3740  /*  Handle return values created by loongarch_pass_fpr_pair.  */
3741   if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3742     {
3743       rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3744       rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3746       if (GET_CODE (target) == LO_SUM)
3747         emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3748                                                            XEXP (target, 0),
3749                                                            XEXP (target, 1),
3750                                                            operands[2],
3751                                                            arg2));
3752       else
3753         {
3754           rtx call
3755             = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3756                                                                    target,
3757                                                                    operands[2],
3758                                                                    arg2));
3760           if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3761             clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3762                         gen_rtx_REG (Pmode, T0_REGNUM));
3763         }
3764     }
3765    else
3766     {
3767       /*  Handle return values created by loongarch_return_fpr_single.  */
3768       if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3769         operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3771       if (GET_CODE (target) == LO_SUM)
3772         emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3773                                                   XEXP (target, 0),
3774                                                   XEXP (target, 1),
3775                                                   operands[2]));
3776       else
3777         {
3778           rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3779                                                                  target,
3780                                                                  operands[2]));
3782           if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3783             clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3784                         gen_rtx_REG (Pmode, T0_REGNUM));
3785         }
3786     }
3787   DONE;
3790 (define_insn "sibcall_value_internal"
3791   [(set (match_operand 0 "register_operand" "")
3792         (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3793               (match_operand 2 "" "")))]
3794   "SIBLING_CALL_P (insn)"
3796   switch (which_alternative)
3797     {
3798     case 0:
3799       return "jr\t%1";
3800     case 1:
3801       if (TARGET_CMODEL_MEDIUM)
3802         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3803       else
3804         return "b\t%1";
3805     case 2:
3806       if (TARGET_CMODEL_MEDIUM)
3807         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3808       else
3809         return "b\t%%plt(%1)";
3810     default:
3811       gcc_unreachable ();
3812     }
3814   [(set_attr "jirl" "indirect,direct,direct")])
3816 (define_insn "@sibcall_value_internal_1<mode>"
3817   [(set (match_operand 0 "register_operand" "")
3818         (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3819                                (match_operand:P 2 "symbolic_operand" "")))
3820               (match_operand 3 "" "")))]
3821   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3822   "jirl\t$r0,%1,%%pc_lo12(%2)"
3823   [(set_attr "jirl" "indirect")])
3825 (define_insn "sibcall_value_multiple_internal"
3826   [(set (match_operand 0 "register_operand" "")
3827         (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3828               (match_operand 2 "" "")))
3829    (set (match_operand 3 "register_operand" "")
3830         (call (mem:SI (match_dup 1))
3831               (match_dup 2)))]
3832   "SIBLING_CALL_P (insn)"
3834   switch (which_alternative)
3835     {
3836     case 0:
3837       return "jr\t%1";
3838     case 1:
3839       if (TARGET_CMODEL_MEDIUM)
3840         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3841       else
3842         return "b\t%1";
3843     case 2:
3844       if (TARGET_CMODEL_MEDIUM)
3845         return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3846       else
3847         return "b\t%%plt(%1)";
3848     default:
3849       gcc_unreachable ();
3850     }
3852   [(set_attr "jirl" "indirect,direct,direct")])
3854 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3855   [(set (match_operand 0 "register_operand" "")
3856         (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3857                                 (match_operand:P 2 "symbolic_operand" "")]
3858                       UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3859               (match_operand 3 "" "")))
3860    (set (match_operand 4 "register_operand" "")
3861         (call (mem:P (unspec:P [(match_dup 1)
3862                                 (match_dup 2)]
3863                       UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3864               (match_dup 3)))]
3865   "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3866   "jirl\t$r0,%1,%%pc_lo12(%2)"
3867   [(set_attr "jirl" "indirect")])
3869 (define_expand "call"
3870   [(parallel [(call (match_operand 0 "")
3871                     (match_operand 1 ""))
3872               (use (match_operand 2 ""))        ;; next_arg_reg
3873               (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
3874   ""
3876   rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3878   if (GET_CODE (target) == LO_SUM)
3879     emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3880                                          XEXP (target, 1), operands[1]));
3881   else
3882     emit_call_insn (gen_call_internal (target, operands[1]));
3883   DONE;
3886 (define_insn "call_internal"
3887   [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3888          (match_operand 1 "" ""))
3889    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3890   ""
3892   switch (which_alternative)
3893     {
3894     case 0:
3895       return "jirl\t$r1,%0,0";
3896     case 1:
3897       if (TARGET_CMODEL_MEDIUM)
3898         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3899       else
3900         return "bl\t%0";
3901     case 2:
3902       if (TARGET_CMODEL_MEDIUM)
3903         return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3904       else
3905         return "bl\t%%plt(%0)";
3906     default:
3907       gcc_unreachable ();
3908     }
3910   [(set_attr "jirl" "indirect,direct,direct")])
3912 (define_insn "@call_internal_1<mode>"
3913   [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3914                           (match_operand:P 1 "symbolic_operand" "")))
3915          (match_operand 2 "" ""))
3916    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3917   "TARGET_CMODEL_MEDIUM"
3918   "jirl\t$r1,%0,%%pc_lo12(%1)"
3919   [(set_attr "jirl" "indirect")])
3921 (define_expand "call_value"
3922   [(parallel [(set (match_operand 0 "")
3923                    (call (match_operand 1 "")
3924                          (match_operand 2 "")))
3925               (use (match_operand 3 ""))])]             ;; next_arg_reg
3926   ""
3928   rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3929   /* Handle return values created by loongarch_pass_fpr_pair.  */
3930   if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3931     {
3932       rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
3933       rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
3935       if (GET_CODE (target) == LO_SUM)
3936         emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
3937                                                             XEXP (target, 0),
3938                                                             XEXP (target, 1),
3939                                                             operands[2], arg2));
3940       else
3941         emit_call_insn (gen_call_value_multiple_internal (arg1, target,
3942                                                         operands[2], arg2));
3943     }
3944    else
3945     {
3946       /* Handle return values created by loongarch_return_fpr_single.  */
3947       if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3948             operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3950       if (GET_CODE (target) == LO_SUM)
3951         emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
3952                                                    XEXP (target, 0),
3953                                                    XEXP (target, 1),
3954                                                    operands[2]));
3955       else
3956         emit_call_insn (gen_call_value_internal (operands[0], target,
3957                                                operands[2]));
3958     }
3959   DONE;
3962 (define_insn "call_value_internal"
3963   [(set (match_operand 0 "register_operand" "")
3964         (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3965               (match_operand 2 "" "")))
3966    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3967   ""
3969   switch (which_alternative)
3970     {
3971     case 0:
3972       return "jirl\t$r1,%1,0";
3973     case 1:
3974       if (TARGET_CMODEL_MEDIUM)
3975         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3976       else
3977         return "bl\t%1";
3978     case 2:
3979       if (TARGET_CMODEL_MEDIUM)
3980         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3981       else
3982         return "bl\t%%plt(%1)";
3983     default:
3984       gcc_unreachable ();
3985     }
3987   [(set_attr "jirl" "indirect,direct,direct")])
3989 (define_insn "@call_value_internal_1<mode>"
3990   [(set (match_operand 0 "register_operand" "")
3991         (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3992                                (match_operand:P 2 "symbolic_operand" "")))
3993               (match_operand 3 "" "")))
3994    (clobber (reg:SI RETURN_ADDR_REGNUM))]
3995   "TARGET_CMODEL_MEDIUM"
3996   "jirl\t$r1,%1,%%pc_lo12(%2)"
3997   [(set_attr "jirl" "indirect")])
3999 (define_insn "call_value_multiple_internal"
4000   [(set (match_operand 0 "register_operand" "")
4001         (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4002               (match_operand 2 "" "")))
4003    (set (match_operand 3 "register_operand" "")
4004         (call (mem:SI (match_dup 1))
4005               (match_dup 2)))
4006    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4007   ""
4009   switch (which_alternative)
4010     {
4011     case 0:
4012       return "jirl\t$r1,%1,0";
4013     case 1:
4014       if (TARGET_CMODEL_MEDIUM)
4015         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4016       else
4017         return "bl\t%1";
4018     case 2:
4019       if (TARGET_CMODEL_MEDIUM)
4020         return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4021       else
4022         return "bl\t%%plt(%1)";
4023     default:
4024       gcc_unreachable ();
4025     }
4027   [(set_attr "jirl" "indirect,direct,direct")])
4029 (define_insn "@call_value_multiple_internal_1<mode>"
4030   [(set (match_operand 0 "register_operand" "")
4031         (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
4032                                 (match_operand:P 2 "symbolic_operand" "")]
4033                       UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4034               (match_operand 3 "" "")))
4035    (set (match_operand 4 "register_operand" "")
4036         (call (mem:P (unspec:P [(match_dup 1)
4037                                 (match_dup 2)]
4038                       UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4039               (match_dup 3)))
4040    (clobber (reg:SI RETURN_ADDR_REGNUM))]
4041   "TARGET_CMODEL_MEDIUM"
4042   "jirl\t$r1,%1,%%pc_lo12(%2)"
4043   [(set_attr "jirl" "indirect")])
4046 ;; Call subroutine returning any type.
4047 (define_expand "untyped_call"
4048   [(parallel [(call (match_operand 0 "")
4049                     (const_int 0))
4050               (match_operand 1 "")
4051               (match_operand 2 "")])]
4052   ""
4054   int i;
4056   emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
4058   for (i = 0; i < XVECLEN (operands[2], 0); i++)
4059     {
4060       rtx set = XVECEXP (operands[2], 0, i);
4061       loongarch_emit_move (SET_DEST (set), SET_SRC (set));
4062     }
4064   emit_insn (gen_blockage ());
4065   DONE;
4069 ;;  ....................
4071 ;;      MISC.
4073 ;;  ....................
4076 (define_insn "prefetch"
4077   [(prefetch (match_operand 0 "address_operand" "ZD")
4078              (match_operand 1 "const_int_operand" "n")
4079              (match_operand 2 "const_int_operand" "n"))]
4080   ""
4082   switch (INTVAL (operands[1]))
4083   {
4084     case 0: return "preld\t0,%a0";
4085     case 1: return "preld\t8,%a0";
4086     default: gcc_unreachable ();
4087   }
4090 (define_insn "nop"
4091   [(const_int 0)]
4092   ""
4093   "nop"
4094   [(set_attr "type" "nop")
4095    (set_attr "mode" "none")])
4097 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
4098 (define_insn "loongarch_movfcsr2gr"
4099   [(set (match_operand:SI 0 "register_operand" "=r")
4100         (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
4101                              UNSPECV_MOVFCSR2GR))]
4102   "TARGET_HARD_FLOAT"
4103   "movfcsr2gr\t%0,$r%1")
4105 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
4106 (define_insn "loongarch_movgr2fcsr"
4107   [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
4108                      (match_operand:SI 1 "register_operand" "r")]
4109                      UNSPECV_MOVGR2FCSR)]
4110   "TARGET_HARD_FLOAT"
4111   "movgr2fcsr\t$r%0,%1")
4113 (define_insn "fclass_<fmt>"
4114   [(set (match_operand:SI 0 "register_operand" "=f")
4115         (unspec:SI [(match_operand:ANYF 1 "register_operand" "f")]
4116                    UNSPEC_FCLASS))]
4117   "TARGET_HARD_FLOAT"
4118   "fclass.<fmt>\t%0,%1"
4119   [(set_attr "type" "unknown")
4120    (set_attr "mode" "<MODE>")])
4122 (define_int_iterator FCLASS_MASK [68 136 952])
4123 (define_int_attr fclass_optab
4124   [(68  "isinf")
4125    (136 "isnormal")
4126    (952 "isfinite")])
4128 (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
4129   [(match_operand:SI   0 "register_operand" "=r")
4130    (match_operand:ANYF 1 "register_operand" " f")
4131    (const_int FCLASS_MASK)]
4132   "TARGET_HARD_FLOAT"
4133   {
4134     rtx ft0 = gen_reg_rtx (SImode);
4135     rtx t0 = gen_reg_rtx (word_mode);
4136     rtx mask = GEN_INT (<FCLASS_MASK>);
4138     emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
4140     if (TARGET_64BIT)
4141       emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
4142     else
4143       emit_move_insn (t0, ft0);
4145     emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
4146     emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
4148     if (TARGET_64BIT)
4149       {
4150         t0 = lowpart_subreg (SImode, t0, DImode);
4151         SUBREG_PROMOTED_VAR_P (t0) = 1;
4152         SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
4153       }
4155     emit_move_insn (operands[0], t0);
4157     DONE;
4158   })
4160 (define_insn "bytepick_w_<bytepick_imm>"
4161   [(set (match_operand:SI 0 "register_operand" "=r")
4162         (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
4163                              (const_int <bytepick_w_lshiftrt_amount>))
4164                 (ashift:SI (match_operand:SI 2 "register_operand" "r")
4165                            (const_int bytepick_w_ashift_amount))))]
4166   ""
4167   "bytepick.w\t%0,%1,%2,<bytepick_imm>"
4168   [(set_attr "mode" "SI")])
4170 (define_mode_attr bitsize [(QI "8") (HI "16")])
4171 (define_mode_attr bytepick_imm [(QI "3") (HI "2")])
4172 (define_mode_attr bytepick_w_ashift_amount [(QI "24") (HI "16")])
4174 (define_insn "bytepick_w_<bytepick_imm>_extend"
4175   [(set (match_operand:DI 0 "register_operand" "=r")
4176         (ior:DI
4177           (ashift:DI
4178             (sign_extend:DI
4179               (subreg:SHORT (match_operand:DI 1 "register_operand" "r") 0))
4180             (const_int <bytepick_w_ashift_amount>))
4181           (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4182                            (const_int <bytepick_w_ashift_amount>)
4183                            (const_int <bitsize>))))]
4184   "TARGET_64BIT"
4185   "bytepick.w\t%0,%2,%1,<bytepick_imm>"
4186   [(set_attr "mode" "SI")])
4188 (define_insn "bytepick_w_1_extend"
4189   [(set (match_operand:DI 0 "register_operand" "=r")
4190         (ior:DI
4191           (ashift:DI
4192             (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
4193                          (const_int 24)
4194                          (const_int 0))
4195         (const_int 8))
4196           (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4197                            (const_int 8)
4198                            (const_int 24))))]
4199   "TARGET_64BIT"
4200   "bytepick.w\t%0,%2,%1,1"
4201   [(set_attr "mode" "SI")])
4203 (define_insn "bytepick_d_<bytepick_imm>"
4204   [(set (match_operand:DI 0 "register_operand" "=r")
4205         (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
4206                           (const_int <bytepick_d_lshiftrt_amount>))
4207                 (ashift (match_operand:DI 2 "register_operand" "r")
4208                         (const_int bytepick_d_ashift_amount))))]
4209   "TARGET_64BIT"
4210   "bytepick.d\t%0,%1,%2,<bytepick_imm>"
4211   [(set_attr "mode" "DI")])
4213 (define_insn "bitrev_4b"
4214   [(set (match_operand:SI 0 "register_operand" "=r")
4215         (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
4216                     UNSPEC_BITREV_4B))]
4217   ""
4218   "bitrev.4b\t%0,%1"
4219   [(set_attr "type" "unknown")
4220    (set_attr "mode" "SI")])
4222 (define_insn "bitrev_8b"
4223   [(set (match_operand:DI 0 "register_operand" "=r")
4224         (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4225                     UNSPEC_BITREV_8B))]
4226   ""
4227   "bitrev.8b\t%0,%1"
4228   [(set_attr "type" "unknown")
4229    (set_attr "mode" "DI")])
4231 (define_insn "@stack_tie<mode>"
4232   [(set (mem:BLK (scratch))
4233         (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4234                      (match_operand:X 1 "register_operand" "r")]
4235                      UNSPEC_TIE))]
4236   ""
4237   ""
4238   [(set_attr "length" "0")
4239    (set_attr "type" "ghost")])
4241 ;; Named pattern for expanding thread pointer reference.
4242 (define_expand "get_thread_pointer<mode>"
4243   [(set (match_operand:P 0 "register_operand" "=r")
4244         (reg:P TP_REGNUM))]
4245   "HAVE_AS_TLS"
4246   {})
4248 (define_split
4249   [(match_operand 0 "small_data_pattern")]
4250   "reload_completed"
4251   [(match_dup 0)]
4252   { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4255 ;; Match paired HI/SI/SF/DFmode load/stores.
4256 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4257   [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4258   "=&r,f,m,m,&r,ZC")
4259         (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4260    (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4261    "=r,f,m,m,r,ZC")
4262         (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4263   "reload_completed"
4264   {
4265     /* The load destination does not overlap the source.  */
4266     gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4267     output_asm_insn (loongarch_output_move (operands[0], operands[1]),
4268                      operands);
4269     output_asm_insn (loongarch_output_move (operands[2], operands[3]),
4270                      &operands[2]);
4271     return "";
4272   }
4273   [(set_attr "move_type"
4274   "load,fpload,store,fpstore,load,store")
4275    (set_attr "insn_count" "2,2,2,2,2,2")])
4277 ;; 2 HI/SI/SF/DF loads are bonded.
4278 (define_peephole2
4279   [(set (match_operand:JOIN_MODE 0 "register_operand")
4280         (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4281    (set (match_operand:JOIN_MODE 2 "register_operand")
4282         (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4283   "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4284   [(parallel [(set (match_dup 0)
4285                    (match_dup 1))
4286               (set (match_dup 2)
4287                    (match_dup 3))])]
4288   "")
4290 ;; 2 HI/SI/SF/DF stores are bonded.
4291 (define_peephole2
4292   [(set (match_operand:JOIN_MODE 0 "memory_operand")
4293         (match_operand:JOIN_MODE 1 "register_operand"))
4294    (set (match_operand:JOIN_MODE 2 "memory_operand")
4295         (match_operand:JOIN_MODE 3 "register_operand"))]
4296   "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4297   [(parallel [(set (match_dup 0)
4298                    (match_dup 1))
4299               (set (match_dup 2)
4300                    (match_dup 3))])]
4301   "")
4303 ;; Match paired HImode loads.
4304 (define_insn "*join2_loadhi"
4305   [(set (match_operand:SI 0 "register_operand" "=&r")
4306         (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4307    (set (match_operand:SI 2 "register_operand" "=r")
4308         (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4309   "reload_completed"
4310   {
4311     /* The load destination does not overlap the source.  */
4312     gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4313     output_asm_insn ("ld.h<u>\t%0,%1", operands);
4314     output_asm_insn ("ld.h<u>\t%2,%3", operands);
4316     return "";
4317   }
4318   [(set_attr "move_type" "load")
4319    (set_attr "insn_count" "2")])
4322 ;; 2 HI loads are bonded.
4323 (define_peephole2
4324   [(set (match_operand:SI 0 "register_operand")
4325         (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4326    (set (match_operand:SI 2 "register_operand")
4327         (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4328   "loongarch_load_store_bonding_p (operands, HImode, true)"
4329   [(parallel [(set (match_dup 0)
4330                    (any_extend:SI (match_dup 1)))
4331               (set (match_dup 2)
4332                    (any_extend:SI (match_dup 3)))])]
4333   "")
4337 (define_mode_iterator QHSD [QI HI SI DI])
4338 (define_int_iterator CRC [UNSPEC_CRC UNSPEC_CRCC])
4339 (define_int_attr crc [(UNSPEC_CRC "crc") (UNSPEC_CRCC "crcc")])
4341 (define_insn "loongarch_<crc>_w_<size>_w"
4342   [(set (match_operand:SI 0 "register_operand" "=r")
4343         (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4344                    (match_operand:SI 2 "register_operand" "r")]
4345                      CRC))]
4346   ""
4347   "<crc>.w.<size>.w\t%0,%1,%2"
4348   [(set_attr "type" "unknown")
4349    (set_attr "mode" "<MODE>")])
4351 (define_insn "loongarch_<crc>_w_<size>_w_extended"
4352   [(set (match_operand:DI 0 "register_operand" "=r")
4353         (sign_extend:DI
4354           (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4355                       (match_operand:SI 2 "register_operand" "r")]
4356                      CRC)))]
4357   "TARGET_64BIT"
4358   "<crc>.w.<size>.w\t%0,%1,%2"
4359   [(set_attr "type" "unknown")
4360    (set_attr "mode" "<MODE>")])
4362 ;; With normal or medium code models, if the only use of a pc-relative
4363 ;; address is for loading or storing a value, then relying on linker
4364 ;; relaxation is not better than emitting the machine instruction directly.
4365 ;; Even if the la.local pseudo op can be relaxed, we get:
4367 ;;     pcaddi     $t0, %pcrel_20(x)
4368 ;;     ld.d       $t0, $t0, 0
4370 ;; There are still two instructions, same as using the machine instructions
4371 ;; and explicit relocs:
4373 ;;     pcalau12i  $t0, %pc_hi20(x)
4374 ;;     ld.d       $t0, $t0, %pc_lo12(x)
4376 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4377 ;; 3 instructions).
4378 (define_insn_and_rewrite "simple_load<mode>"
4379   [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4380         (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4381   "loongarch_pre_reload_split ()
4382    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4383    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4384   "#"
4385   "&& true"
4386   {
4387     operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4388   })
4390 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4391   [(set (match_operand:GPR 0 "register_operand" "=r")
4392         (any_extend:GPR
4393           (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4394   "loongarch_pre_reload_split ()
4395    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4396    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4397   "#"
4398   "&& true"
4399   {
4400     operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4401   })
4403 (define_insn_and_rewrite "simple_store<mode>"
4404   [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4405         (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4406   "loongarch_pre_reload_split ()
4407    && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4408    && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4409   "#"
4410   "&& true"
4411   {
4412     operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4413   })
4415 ;; Synchronization instructions.
4417 (include "sync.md")
4419 (include "generic.md")
4420 (include "la464.md")
4422 ; The LoongArch SIMD Instructions.
4423 (include "simd.md")
4425 (define_c_enum "unspec" [
4426   UNSPEC_ADDRESS_FIRST