]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/loongarch/loongarch.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / loongarch / loongarch.md
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.
5
6 ;; This file is part of GCC.
7
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
11 ;; any later version.
12
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3. If not see
20 ;; <http://www.gnu.org/licenses/>.
21
22 (define_c_enum "unspec" [
23 ;; Integer operations that are too cumbersome to describe directly.
24 UNSPEC_REVB_2H
25 UNSPEC_REVB_4H
26 UNSPEC_REVH_D
27
28 ;; Floating-point moves.
29 UNSPEC_LOAD_LOW
30 UNSPEC_LOAD_HIGH
31 UNSPEC_STORE_WORD
32 UNSPEC_MOVGR2FRH
33 UNSPEC_MOVFRH2GR
34
35 ;; Floating point unspecs.
36 UNSPEC_FRINT
37 UNSPEC_FCLASS
38 UNSPEC_FMAX
39 UNSPEC_FMIN
40 UNSPEC_FTINT
41 UNSPEC_FTINTRM
42 UNSPEC_FTINTRP
43 UNSPEC_FSCALEB
44 UNSPEC_FLOGB
45
46 ;; Override return address for exception handling.
47 UNSPEC_EH_RETURN
48
49 ;; Bit operation
50 UNSPEC_BITREV_4B
51 UNSPEC_BITREV_8B
52
53 ;; TLS
54 UNSPEC_TLS_GD
55 UNSPEC_TLS_LD
56 UNSPEC_TLS_LE
57 UNSPEC_TLS_IE
58
59 ;; Stack tie
60 UNSPEC_TIE
61
62 ;; RSQRT
63 UNSPEC_RSQRT
64 UNSPEC_RSQRTE
65
66 ;; RECIP
67 UNSPEC_RECIPE
68
69 ;; CRC
70 UNSPEC_CRC
71 UNSPEC_CRCC
72
73 UNSPEC_LOAD_FROM_GOT
74 UNSPEC_PCALAU12I
75 UNSPEC_PCALAU12I_GR
76 UNSPEC_ADD_TLS_LE_RELAX
77 UNSPEC_ORI_L_LO12
78 UNSPEC_LUI_L_HI20
79 UNSPEC_LUI_H_LO20
80 UNSPEC_LUI_H_HI12
81 UNSPEC_TLS_LOW
82
83 ;; Fake div.w[u] mod.w[u]
84 UNSPEC_FAKE_ANY_DIV
85
86 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
87 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
88 ])
89
90 (define_c_enum "unspecv" [
91 ;; Blockage and synchronisation.
92 UNSPECV_BLOCKAGE
93 UNSPECV_DBAR
94 UNSPECV_IBAR
95
96 ;; Privileged instructions
97 UNSPECV_CSRRD
98 UNSPECV_CSRWR
99 UNSPECV_CSRXCHG
100 UNSPECV_IOCSRRD
101 UNSPECV_IOCSRWR
102 UNSPECV_CACOP
103 UNSPECV_LDDIR
104 UNSPECV_LDPTE
105 UNSPECV_ERTN
106
107 ;; Stack checking.
108 UNSPECV_PROBE_STACK_RANGE
109
110 ;; Floating-point environment.
111 UNSPECV_MOVFCSR2GR
112 UNSPECV_MOVGR2FCSR
113
114 ;; Others
115 UNSPECV_CPUCFG
116 UNSPECV_ASRTLE_D
117 UNSPECV_ASRTGT_D
118 UNSPECV_SYSCALL
119 UNSPECV_BREAK
120 ])
121
122 (define_constants
123 [(RETURN_ADDR_REGNUM 1)
124 (TP_REGNUM 2)
125 (T0_REGNUM 12)
126 (T1_REGNUM 13)
127 (S0_REGNUM 23)
128
129 ;; Return path styles
130 (NORMAL_RETURN 0)
131 (SIBCALL_RETURN 1)
132 (EXCEPTION_RETURN 2)
133
134 ;; PIC long branch sequences are never longer than 100 bytes.
135 (MAX_PIC_BRANCH_LENGTH 100)
136 ])
137
138 (include "predicates.md")
139 (include "constraints.md")
140 \f
141 ;; ....................
142 ;;
143 ;; Attributes
144 ;;
145 ;; ....................
146
147 (define_attr "enabled" "no,yes" (const_string "yes"))
148
149 (define_attr "got" "unset,load"
150 (const_string "unset"))
151
152 ;; For jirl instructions, this attribute is DIRECT when the target address
153 ;; is symbolic and INDIRECT when it is a register.
154 (define_attr "jirl" "unset,direct,indirect"
155 (const_string "unset"))
156
157
158 ;; Classification of moves, extensions and truncations. Most values
159 ;; are as for "type" (see below) but there are also the following
160 ;; move-specific values:
161 ;;
162 ;; sll0 "slli.w DEST,SRC,0", which on 64-bit targets is guaranteed
163 ;; to produce a sign-extended DEST, even if SRC is not
164 ;; properly sign-extended
165 ;; pick_ins BSTRPICK.W, BSTRPICK.D, BSTRINS.W or BSTRINS.D instruction
166 ;; andi a single ANDI instruction
167 ;; shift_shift a shift left followed by a shift right
168 ;;
169 ;; This attribute is used to determine the instruction's length and
170 ;; scheduling type. For doubleword moves, the attribute always describes
171 ;; the split instructions; in some cases, it is more appropriate for the
172 ;; scheduling type to be "multi" instead.
173 (define_attr "move_type"
174 "unknown,load,fpload,store,fpstore,mgtf,mftg,imul,move,fmove,
175 const,signext,pick_ins,logical,arith,sll0,andi,shift_shift"
176 (const_string "unknown"))
177
178 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor,simd_add"
179 (const_string "unknown"))
180
181 ;; Main data type used by the insn
182 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FCC,
183 V2DI,V4SI,V8HI,V16QI,V2DF,V4SF,V4DI,V8SI,V16HI,V32QI,V4DF,V8SF"
184 (const_string "unknown"))
185
186 ;; True if the main data type is twice the size of a word.
187 (define_attr "dword_mode" "no,yes"
188 (cond [(and (eq_attr "mode" "DI,DF")
189 (not (match_test "TARGET_64BIT")))
190 (const_string "yes")
191
192 (and (eq_attr "mode" "TI,TF")
193 (match_test "TARGET_64BIT"))
194 (const_string "yes")]
195 (const_string "no")))
196
197 ;; True if the main data type is four times of the size of a word.
198 (define_attr "qword_mode" "no,yes"
199 (cond [(and (eq_attr "mode" "TI,TF")
200 (not (match_test "TARGET_64BIT")))
201 (const_string "yes")]
202 (const_string "no")))
203
204 ;; Classification of each insn.
205 ;; branch conditional branch
206 ;; jump unconditional jump
207 ;; call unconditional call
208 ;; load load instruction(s)
209 ;; fpload floating point load
210 ;; fpidxload floating point indexed load
211 ;; store store instruction(s)
212 ;; fpstore floating point store
213 ;; fpidxstore floating point indexed store
214 ;; prefetch memory prefetch (register + offset)
215 ;; prefetchx memory indexed prefetch (register + register)
216 ;; condmove conditional moves
217 ;; mgtf move general-purpose register to floating point register
218 ;; mftg move floating point register to general-purpose register
219 ;; const load constant
220 ;; arith integer arithmetic instructions
221 ;; logical integer logical instructions
222 ;; shift integer shift instructions
223 ;; slt set less than instructions
224 ;; signext sign extend instructions
225 ;; clz the clz and clo instructions
226 ;; trap trap if instructions
227 ;; imul integer multiply
228 ;; idiv integer divide
229 ;; move integer move
230 ;; fmove floating point register move
231 ;; fadd floating point add/subtract
232 ;; fmul floating point multiply
233 ;; fmadd floating point multiply-add
234 ;; fdiv floating point divide
235 ;; frdiv floating point reciprocal divide
236 ;; frecipe floating point approximate reciprocal
237 ;; fabs floating point absolute value
238 ;; flogb floating point exponent extract
239 ;; fneg floating point negation
240 ;; fcmp floating point compare
241 ;; fcopysign floating point copysign
242 ;; fcvt floating point convert
243 ;; fscaleb floating point scale
244 ;; fsqrt floating point square root
245 ;; frsqrt floating point reciprocal square root
246 ;; frsqrte floating point approximate reciprocal square root
247 ;; multi multiword sequence (or user asm statements)
248 ;; atomic atomic memory update instruction
249 ;; syncloop memory atomic operation implemented as a sync loop
250 ;; nop no operation
251 ;; ghost an instruction that produces no real code
252 (define_attr "type"
253 "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
254 prefetch,prefetchx,condmove,mgtf,mftg,const,arith,logical,
255 shift,slt,signext,clz,trap,imul,idiv,move,
256 fmove,fadd,fmul,fmadd,fdiv,frdiv,frecipe,fabs,flogb,fneg,fcmp,fcopysign,fcvt,
257 fscaleb,fsqrt,frsqrt,frsqrte,accext,accmod,multi,atomic,syncloop,nop,ghost,
258 simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
259 simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
260 simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
261 simd_permute,simd_shf,simd_sat,simd_pcnt,simd_copy,simd_branch,simd_clsx,
262 simd_fminmax,simd_logic,simd_move,simd_load,simd_store"
263 (cond [(eq_attr "jirl" "!unset") (const_string "call")
264 (eq_attr "got" "load") (const_string "load")
265
266 (eq_attr "alu_type" "add,sub") (const_string "arith")
267
268 (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical")
269
270 ;; If a doubleword move uses these expensive instructions,
271 ;; it is usually better to schedule them in the same way
272 ;; as the singleword form, rather than as "multi".
273 (eq_attr "move_type" "load") (const_string "load")
274 (eq_attr "move_type" "fpload") (const_string "fpload")
275 (eq_attr "move_type" "store") (const_string "store")
276 (eq_attr "move_type" "fpstore") (const_string "fpstore")
277 (eq_attr "move_type" "mgtf") (const_string "mgtf")
278 (eq_attr "move_type" "mftg") (const_string "mftg")
279
280 ;; These types of move are always single insns.
281 (eq_attr "move_type" "imul") (const_string "imul")
282 (eq_attr "move_type" "fmove") (const_string "fmove")
283 (eq_attr "move_type" "signext") (const_string "signext")
284 (eq_attr "move_type" "pick_ins") (const_string "arith")
285 (eq_attr "move_type" "arith") (const_string "arith")
286 (eq_attr "move_type" "logical") (const_string "logical")
287 (eq_attr "move_type" "sll0") (const_string "shift")
288 (eq_attr "move_type" "andi") (const_string "logical")
289
290 ;; These types of move are always split.
291 (eq_attr "move_type" "shift_shift")
292 (const_string "multi")
293
294 ;; These types of move are split for quadword modes only.
295 (and (eq_attr "move_type" "move,const")
296 (eq_attr "qword_mode" "yes"))
297 (const_string "multi")
298
299 ;; These types of move are split for doubleword modes only.
300 (and (eq_attr "move_type" "move,const")
301 (eq_attr "dword_mode" "yes"))
302 (const_string "multi")
303 (eq_attr "move_type" "move") (const_string "move")
304 (eq_attr "move_type" "const") (const_string "const")]
305 (const_string "unknown")))
306
307 ;; Mode for conversion types (fcvt)
308 ;; I2S integer to float single (SI/DI to SF)
309 ;; I2D integer to float double (SI/DI to DF)
310 ;; S2I float to integer (SF to SI/DI)
311 ;; D2I float to integer (DF to SI/DI)
312 ;; D2S double to float single
313 ;; S2D float single to double
314
315 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
316 (const_string "unknown"))
317
318 ;; The number of individual instructions that a non-branch pattern generates
319 (define_attr "insn_count" ""
320 (cond [;; "Ghost" instructions occupy no space.
321 (eq_attr "type" "ghost")
322 (const_int 0)
323
324 ;; Check for doubleword moves that are decomposed into two
325 ;; instructions.
326 (and (eq_attr "move_type" "mgtf,mftg,move")
327 (eq_attr "dword_mode" "yes"))
328 (const_int 2)
329
330 ;; Check for quadword moves that are decomposed into four
331 ;; instructions.
332 (and (eq_attr "move_type" "mgtf,mftg,move")
333 (eq_attr "qword_mode" "yes"))
334 (const_int 4)
335
336 ;; Constants, loads and stores are handled by external routines.
337 (and (eq_attr "move_type" "const")
338 (eq_attr "dword_mode" "yes"))
339 (symbol_ref "loongarch_split_const_insns (operands[1])")
340 (eq_attr "move_type" "const")
341 (symbol_ref "loongarch_const_insns (operands[1])")
342 (eq_attr "move_type" "load,fpload")
343 (symbol_ref "loongarch_load_store_insns (operands[1], insn)")
344 (eq_attr "move_type" "store,fpstore")
345 (symbol_ref "loongarch_load_store_insns (operands[0], insn)")
346
347 (eq_attr "type" "idiv")
348 (symbol_ref "loongarch_idiv_insns (GET_MODE (PATTERN (insn)))")]
349 (const_int 1)))
350
351 ;; Length of instruction in bytes.
352 (define_attr "length" ""
353 (cond [
354 ;; Branch futher than +/- 128 KiB require two instructions.
355 (eq_attr "type" "branch")
356 (if_then_else (and (le (minus (match_dup 0) (pc)) (const_int 131064))
357 (le (minus (pc) (match_dup 0)) (const_int 131068)))
358 (const_int 4)
359 (const_int 8))]
360 (symbol_ref "get_attr_insn_count (insn) * 4")))
361
362 ;; Describe a user's asm statement.
363 (define_asm_attributes
364 [(set_attr "type" "multi")])
365 \f
366 ;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
367 ;; from the same template.
368 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
369
370 ;; A copy of GPR that can be used when a pattern has two independent
371 ;; modes.
372 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
373
374 ;; This mode iterator allows 16-bit and 32-bit GPR patterns and 32-bit 64-bit
375 ;; FPR patterns to be generated from the same template.
376 (define_mode_iterator JOIN_MODE [HI
377 SI
378 (SF "TARGET_HARD_FLOAT")
379 (DF "TARGET_DOUBLE_FLOAT")])
380
381 ;; This mode iterator allows :P to be used for patterns that operate on
382 ;; pointer-sized quantities. Exactly one of the two alternatives will match.
383 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
384
385 ;; Likewise, but for GRLEN-sized quantities.
386 (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
387
388 ;; 64-bit modes for which we provide move patterns.
389 (define_mode_iterator MOVE64 [DI DF])
390
391 ;; 128-bit modes for which we provide move patterns on 64-bit targets.
392 (define_mode_iterator MOVE128 [TI TF])
393
394 ;; Iterator for sub-32-bit integer modes.
395 (define_mode_iterator SHORT [QI HI])
396
397 ;; Likewise the 64-bit truncate-and-shift patterns.
398 (define_mode_iterator SUBDI [QI HI SI])
399
400 ;; Iterator for scalar fixed point modes.
401 (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
402
403 ;; Iterator for hardware-supported floating-point modes.
404 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
405 (DF "TARGET_DOUBLE_FLOAT")])
406
407 ;; Iterator for fixed-point modes which can be hold by a hardware
408 ;; floating-point register.
409 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
410 (DI "TARGET_DOUBLE_FLOAT")])
411
412 ;; A mode for which moves involving FPRs may need to be split.
413 (define_mode_iterator SPLITF
414 [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
415 (DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
416 (TF "TARGET_64BIT && TARGET_DOUBLE_FLOAT")])
417
418 ;; A mode for anything with 32 bits or more, and able to be loaded with
419 ;; the same addressing mode as ld.w.
420 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
421
422 ;; A mode for anything able to be stored with the same addressing mode as
423 ;; st.w.
424 (define_mode_iterator ST_ANY [QHWD ANYF])
425
426 ;; A mode for anything legal as a input of a div or mod instruction.
427 (define_mode_iterator DIV [(DI "TARGET_64BIT")
428 (SI "!TARGET_64BIT || TARGET_DIV32")])
429
430 ;; In GPR templates, a string like "mul.<d>" will expand to "mul.w" in the
431 ;; 32-bit version and "mul.d" in the 64-bit version.
432 (define_mode_attr d [(SI "w") (DI "d")])
433
434 ;; This attribute gives the length suffix for a load or store instruction.
435 ;; The same suffixes work for zero and sign extensions.
436 (define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")])
437 (define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")])
438
439 ;; This attribute gives the mode mask of a SHORT.
440 (define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
441
442 ;; This attribute gives the size (bits) of a SHORT.
443 (define_mode_attr 7_or_15 [(QI "7") (HI "15")])
444
445 ;; Instruction names for stores.
446 (define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
447
448 ;; This attribute gives the format suffix for floating-point operations.
449 (define_mode_attr fmt [(SF "s") (DF "d")])
450 (define_mode_attr ifmt [(SI "w") (DI "l")])
451
452 ;; This attribute gives the upper-case mode name for one unit of a
453 ;; floating-point mode or vector mode.
454 (define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF") (V4SF "SF")
455 (V16QI "QI") (V8HI "HI") (V4SI "SI") (V2DI "DI")
456 (V2DF "DF")(V8SF "SF")(V32QI "QI")(V16HI "HI")(V8SI "SI")(V4DI "DI")(V4DF "DF")])
457
458 ;; As above, but in lower case.
459 (define_mode_attr unitmode [(SF "sf") (DF "df") (V2SF "sf") (V4SF "sf")
460 (V16QI "qi") (V8QI "qi") (V8HI "hi") (V4HI "hi")
461 (V4SI "si") (V2SI "si") (V2DI "di") (V2DF "df")
462 (V8SI "si") (V4DI "di") (V32QI "qi") (V16HI "hi")
463 (V8SF "sf") (V4DF "df")])
464
465 ;; This attribute gives the integer mode that has half the size of
466 ;; the controlling mode.
467 (define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
468 (V2SI "SI") (V4HI "SI") (V8QI "SI")
469 (TF "DI")])
470
471 ;; This attribute gives the integer mode that has the same size of a
472 ;; floating-point mode.
473 (define_mode_attr IMODE [(SF "SI") (DF "DI")])
474
475 ;; This code iterator allows signed and unsigned widening multiplications
476 ;; to use the same template.
477 (define_code_iterator any_extend [sign_extend zero_extend])
478
479 ;; This code iterator allows the two right shift instructions to be
480 ;; generated from the same template.
481 (define_code_iterator any_shiftrt [ashiftrt lshiftrt])
482
483 ;; This code iterator allows the three shift instructions to be generated
484 ;; from the same template.
485 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
486
487 ;; This code iterator allows the three bitwise instructions to be generated
488 ;; from the same template.
489 (define_code_iterator any_bitwise [and ior xor])
490 (define_code_iterator neg_bitwise [and ior])
491
492 ;; This code iterator allows unsigned and signed division to be generated
493 ;; from the same template.
494 (define_code_iterator any_div [div udiv mod umod])
495
496 ;; This code iterator allows addition and subtraction to be generated
497 ;; from the same template.
498 (define_code_iterator addsub [plus minus])
499
500 ;; This code iterator allows addition and multiplication to be generated
501 ;; from the same template.
502 (define_code_iterator addmul [plus mult])
503
504 ;; This code iterator allows addition subtraction and multiplication to be
505 ;; generated from the same template
506 (define_code_iterator addsubmul [plus minus mult])
507
508 ;; This code iterator allows all native floating-point comparisons to be
509 ;; generated from the same template.
510 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
511 ordered ltgt ne ge gt unge ungt])
512
513 ;; Equality operators.
514 (define_code_iterator equality_op [eq ne])
515
516 ;; These code iterators allow the signed and unsigned scc operations to use
517 ;; the same template.
518 (define_code_iterator any_gt [gt gtu])
519 (define_code_iterator any_ge [ge geu])
520 (define_code_iterator any_lt [lt ltu])
521 (define_code_iterator any_le [le leu])
522
523 (define_code_iterator any_return [return simple_return])
524
525 ;; <u> expands to an empty string when doing a signed operation and
526 ;; "u" when doing an unsigned operation.
527 (define_code_attr u [(sign_extend "") (zero_extend "u")
528 (div "") (udiv "u")
529 (mod "") (umod "u")
530 (gt "") (gtu "u")
531 (ge "") (geu "u")
532 (lt "") (ltu "u")
533 (le "") (leu "u")])
534
535 ;; <U> is like <u> except uppercase.
536 (define_code_attr U [(sign_extend "") (zero_extend "U")])
537
538 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
539 (define_code_attr su [(sign_extend "s") (zero_extend "u")])
540
541 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
542
543 ;; <optab> expands to the name of the optab for a particular code.
544 (define_code_attr optab [(ashift "ashl")
545 (ashiftrt "ashr")
546 (lshiftrt "lshr")
547 (ior "ior")
548 (xor "xor")
549 (and "and")
550 (plus "add")
551 (minus "sub")
552 (mult "mul")
553 (div "div")
554 (udiv "udiv")
555 (mod "mod")
556 (umod "umod")
557 (return "return")
558 (simple_return "simple_return")])
559
560 ;; <insn> expands to the name of the insn that implements a particular code.
561 (define_code_attr insn [(ashift "sll")
562 (ashiftrt "sra")
563 (lshiftrt "srl")
564 (ior "or")
565 (xor "xor")
566 (and "and")
567 (plus "addu")
568 (minus "subu")
569 (div "div")
570 (udiv "div")
571 (mod "mod")
572 (umod "mod")])
573
574 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
575 (define_code_attr fcond [(unordered "cun")
576 (uneq "cueq")
577 (unlt "cult")
578 (unle "cule")
579 (eq "ceq")
580 (lt "slt")
581 (le "sle")
582 (ordered "cor")
583 (ltgt "sne")
584 (ne "cune")
585 (ge "sge")
586 (gt "sgt")
587 (unge "cuge")
588 (ungt "cugt")])
589
590 ;; The sel mnemonic to use depending on the condition test.
591 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
592 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
593
594 ;; Iterator and attributes for floating-point to fixed-point conversion
595 ;; instructions.
596 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
597 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
598 (UNSPEC_FTINTRM "lfloor")
599 (UNSPEC_FTINTRP "lceil")])
600 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
601 (UNSPEC_FTINTRM "rm")
602 (UNSPEC_FTINTRP "rp")])
603
604 ;; Iterator and attributes for bytepick.d
605 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
606 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
607 (16 "16")
608 (24 "8")])
609 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
610 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
611 (16 "48")
612 (24 "40")
613 (32 "32")
614 (40 "24")
615 (48 "16")
616 (56 "8")])
617 (define_int_attr bytepick_imm [(8 "1")
618 (16 "2")
619 (24 "3")
620 (32 "4")
621 (40 "5")
622 (48 "6")
623 (56 "7")])
624
625 ;;
626 ;; ....................
627 ;;
628 ;; CONDITIONAL TRAPS
629 ;;
630 ;; ....................
631 ;;
632
633 (define_insn "trap"
634 [(trap_if (const_int 1) (const_int 0))]
635 ""
636 {
637 return "break\t0";
638 }
639 [(set_attr "type" "trap")])
640
641
642 \f
643 ;;
644 ;; ....................
645 ;;
646 ;; ADDITION
647 ;;
648 ;; ....................
649 ;;
650
651 (define_insn "add<mode>3"
652 [(set (match_operand:ANYF 0 "register_operand" "=f")
653 (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
654 (match_operand:ANYF 2 "register_operand" "f")))]
655 ""
656 "fadd.<fmt>\t%0,%1,%2"
657 [(set_attr "type" "fadd")
658 (set_attr "mode" "<UNITMODE>")])
659
660 (define_insn_and_split "add<mode>3"
661 [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r,r,r,r")
662 (plus:GPR (match_operand:GPR 1 "register_operand" "r,r,r,r,r,r,r")
663 (match_operand:GPR 2 "plus_<mode>_operand"
664 "r,I,La,Lb,Lc,Ld,Le")))]
665 ""
666 "@
667 add.<d>\t%0,%1,%2
668 addi.<d>\t%0,%1,%2
669 #
670 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
671 return \"addu16i.d\t%0,%1,%2\";
672 #
673 #
674 #"
675 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
676 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
677 [(set (match_dup 0) (plus:GPR (match_dup 1) (match_dup 3)))
678 (set (match_dup 0) (plus:GPR (match_dup 0) (match_dup 4)))]
679 {
680 loongarch_split_plus_constant (&operands[2], <MODE>mode);
681 }
682 [(set_attr "alu_type" "add")
683 (set_attr "mode" "<MODE>")
684 (set_attr "insn_count" "1,1,2,1,2,2,2")
685 (set (attr "enabled")
686 (cond
687 [(match_test "<MODE>mode != DImode && which_alternative == 4")
688 (const_string "no")
689 (match_test "<MODE>mode != DImode && which_alternative == 5")
690 (const_string "no")
691 (match_test "<MODE>mode != SImode && which_alternative == 6")
692 (const_string "no")]
693 (const_string "yes")))])
694
695 (define_insn_and_split "*addsi3_extended"
696 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
697 (sign_extend:DI
698 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
699 (match_operand:SI 2 "plus_si_extend_operand"
700 "r,I,La,Le"))))]
701 "TARGET_64BIT"
702 "@
703 add.w\t%0,%1,%2
704 addi.w\t%0,%1,%2
705 #
706 #"
707 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
708 [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
709 (set (match_dup 0)
710 (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
711 (match_dup 4))))]
712 {
713 loongarch_split_plus_constant (&operands[2], SImode);
714 }
715 [(set_attr "alu_type" "add")
716 (set_attr "mode" "SI")
717 (set_attr "insn_count" "1,1,2,2")])
718
719 \f
720 ;;
721 ;; ....................
722 ;;
723 ;; SUBTRACTION
724 ;;
725 ;; ....................
726 ;;
727
728 (define_insn "sub<mode>3"
729 [(set (match_operand:ANYF 0 "register_operand" "=f")
730 (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
731 (match_operand:ANYF 2 "register_operand" "f")))]
732 ""
733 "fsub.<fmt>\t%0,%1,%2"
734 [(set_attr "type" "fadd")
735 (set_attr "mode" "<UNITMODE>")])
736
737 (define_insn "sub<mode>3"
738 [(set (match_operand:GPR 0 "register_operand" "=r")
739 (minus:GPR (match_operand:GPR 1 "register_operand" "rJ")
740 (match_operand:GPR 2 "register_operand" "r")))]
741 ""
742 "sub.<d>\t%0,%z1,%2"
743 [(set_attr "alu_type" "sub")
744 (set_attr "mode" "<MODE>")])
745
746
747 (define_insn "*subsi3_extended"
748 [(set (match_operand:DI 0 "register_operand" "=r")
749 (sign_extend:DI
750 (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
751 (match_operand:SI 2 "register_operand" "r"))))]
752 "TARGET_64BIT"
753 "sub.w\t%0,%z1,%2"
754 [(set_attr "type" "arith")
755 (set_attr "mode" "SI")])
756
757 ;;
758 ;; ....................
759 ;;
760 ;; MULTIPLICATION
761 ;;
762 ;; ....................
763 ;;
764
765 (define_insn "mul<mode>3"
766 [(set (match_operand:ANYF 0 "register_operand" "=f")
767 (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
768 (match_operand:ANYF 2 "register_operand" "f")))]
769 ""
770 "fmul.<fmt>\t%0,%1,%2"
771 [(set_attr "type" "fmul")
772 (set_attr "mode" "<MODE>")])
773
774 (define_insn "mul<mode>3"
775 [(set (match_operand:GPR 0 "register_operand" "=r")
776 (mult:GPR (match_operand:GPR 1 "register_operand" "r")
777 (match_operand:GPR 2 "register_operand" "r")))]
778 ""
779 "mul.<d>\t%0,%1,%2"
780 [(set_attr "type" "imul")
781 (set_attr "mode" "<MODE>")])
782
783 (define_insn "*mulsi3_extended"
784 [(set (match_operand:DI 0 "register_operand" "=r")
785 (sign_extend:DI
786 (mult:SI (match_operand:SI 1 "register_operand" "r")
787 (match_operand:SI 2 "register_operand" "r"))))]
788 "TARGET_64BIT"
789 "mul.w\t%0,%1,%2"
790 [(set_attr "type" "imul")
791 (set_attr "mode" "SI")])
792
793 ;;
794 ;; ........................
795 ;;
796 ;; MULTIPLICATION HIGH-PART
797 ;;
798 ;; ........................
799 ;;
800
801 (define_expand "<u>mulditi3"
802 [(set (match_operand:TI 0 "register_operand")
803 (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
804 (any_extend:TI (match_operand:DI 2 "register_operand"))))]
805 "TARGET_64BIT"
806 {
807 rtx low = gen_reg_rtx (DImode);
808 emit_insn (gen_muldi3 (low, operands[1], operands[2]));
809
810 rtx high = gen_reg_rtx (DImode);
811 emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
812
813 emit_move_insn (gen_lowpart (DImode, operands[0]), low);
814 emit_move_insn (gen_highpart (DImode, operands[0]), high);
815 DONE;
816 })
817
818 (define_insn "<su>muldi3_highpart"
819 [(set (match_operand:DI 0 "register_operand" "=r")
820 (truncate:DI
821 (lshiftrt:TI
822 (mult:TI (any_extend:TI
823 (match_operand:DI 1 "register_operand" " r"))
824 (any_extend:TI
825 (match_operand:DI 2 "register_operand" " r")))
826 (const_int 64))))]
827 "TARGET_64BIT"
828 "mulh.d<u>\t%0,%1,%2"
829 [(set_attr "type" "imul")
830 (set_attr "mode" "DI")])
831
832 (define_expand "<u>mulsidi3"
833 [(set (match_operand:DI 0 "register_operand")
834 (mult:DI (any_extend:DI
835 (match_operand:SI 1 "register_operand"))
836 (any_extend:DI
837 (match_operand:SI 2 "register_operand"))))]
838 ""
839 {
840 if (!TARGET_64BIT)
841 {
842 rtx temp = gen_reg_rtx (SImode);
843 emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
844 emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
845 operands[1], operands[2]));
846 emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
847 DONE;
848 }
849 })
850
851 (define_insn "<u>mulsidi3_64bit"
852 [(set (match_operand:DI 0 "register_operand" "=r")
853 (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
854 (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
855 "TARGET_64BIT"
856 "mulw.d.w<u>\t%0,%1,%2"
857 [(set_attr "type" "imul")
858 (set_attr "mode" "DI")])
859
860 (define_insn "<su>mulsi3_highpart"
861 [(set (match_operand:SI 0 "register_operand" "=r")
862 (truncate:SI
863 (lshiftrt:DI
864 (mult:DI (any_extend:DI
865 (match_operand:SI 1 "register_operand" " r"))
866 (any_extend:DI
867 (match_operand:SI 2 "register_operand" " r")))
868 (const_int 32))))]
869 ""
870 "mulh.w<u>\t%0,%1,%2"
871 [(set_attr "type" "imul")
872 (set_attr "mode" "SI")])
873
874 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
875 ;; sign extension by default, so the sign extension instruction can be
876 ;; eliminated.
877 (define_peephole
878 [(set (match_operand:SI 0 "register_operand")
879 (truncate:SI
880 (lshiftrt:DI
881 (mult:DI (any_extend:DI
882 (match_operand:SI 1 "register_operand"))
883 (any_extend:DI
884 (match_operand:SI 2 "register_operand")))
885 (const_int 32))))
886 (set (match_operand:DI 3 "register_operand")
887 (sign_extend:DI (match_dup 0)))]
888 "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
889 "mulh.w<u>\t%0,%1,%2")
890
891 ;;
892 ;; ....................
893 ;;
894 ;; DIVISION and REMAINDER
895 ;;
896 ;; ....................
897 ;;
898
899 ;; Float division and modulus.
900 (define_expand "div<mode>3"
901 [(set (match_operand:ANYF 0 "register_operand")
902 (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
903 (match_operand:ANYF 2 "register_operand")))]
904 ""
905 {
906 if (<MODE>mode == SFmode
907 && TARGET_RECIP_DIV
908 && optimize_insn_for_speed_p ()
909 && flag_finite_math_only && !flag_trapping_math
910 && flag_unsafe_math_optimizations)
911 {
912 loongarch_emit_swdivsf (operands[0], operands[1],
913 operands[2], SFmode);
914 DONE;
915 }
916 })
917
918 (define_insn "*div<mode>3"
919 [(set (match_operand:ANYF 0 "register_operand" "=f")
920 (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
921 (match_operand:ANYF 2 "register_operand" "f")))]
922 ""
923 "fdiv.<fmt>\t%0,%1,%2"
924 [(set_attr "type" "fdiv")
925 (set_attr "mode" "<UNITMODE>")])
926
927 ;; In 3A5000, the reciprocal operation is the same as the division operation.
928
929 (define_insn "*recip<mode>3"
930 [(set (match_operand:ANYF 0 "register_operand" "=f")
931 (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
932 (match_operand:ANYF 2 "register_operand" "f")))]
933 ""
934 "frecip.<fmt>\t%0,%2"
935 [(set_attr "type" "frdiv")
936 (set_attr "mode" "<UNITMODE>")])
937
938 ;; Approximate Reciprocal Instructions.
939
940 (define_insn "loongarch_frecipe_<fmt>"
941 [(set (match_operand:ANYF 0 "register_operand" "=f")
942 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
943 UNSPEC_RECIPE))]
944 "TARGET_FRECIPE"
945 "frecipe.<fmt>\t%0,%1"
946 [(set_attr "type" "frecipe")
947 (set_attr "mode" "<UNITMODE>")
948 (set_attr "insn_count" "1")])
949
950 ;; Integer division and modulus.
951 (define_expand "<optab><mode>3"
952 [(set (match_operand:GPR 0 "register_operand")
953 (any_div:GPR (match_operand:GPR 1 "register_operand")
954 (match_operand:GPR 2 "register_operand")))]
955 ""
956 {
957 if (GET_MODE (operands[0]) == SImode && TARGET_64BIT && !TARGET_DIV32)
958 {
959 rtx reg1 = gen_reg_rtx (DImode);
960 rtx reg2 = gen_reg_rtx (DImode);
961 rtx rd = gen_reg_rtx (DImode);
962
963 operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
964 operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
965
966 emit_insn (gen_rtx_SET (reg1, operands[1]));
967 emit_insn (gen_rtx_SET (reg2, operands[2]));
968
969 emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
970 emit_insn (gen_rtx_SET (operands[0],
971 simplify_gen_subreg (SImode, rd, DImode, 0)));
972 DONE;
973 }
974 })
975
976 (define_insn "*<optab><mode>3"
977 [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
978 (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
979 (match_operand:DIV 2 "register_operand" "r,r,r")))]
980 ""
981 {
982 return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
983 }
984 [(set_attr "type" "idiv")
985 (set_attr "mode" "<MODE>")
986 (set (attr "enabled")
987 (if_then_else
988 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
989 (const_string "yes")
990 (const_string "no")))])
991
992 (define_insn "<optab>si3_extended"
993 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
994 (sign_extend
995 (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
996 (match_operand:SI 2 "register_operand" "r,r,r"))))]
997 "TARGET_64BIT && TARGET_DIV32"
998 {
999 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1000 }
1001 [(set_attr "type" "idiv")
1002 (set_attr "mode" "SI")
1003 (set (attr "enabled")
1004 (if_then_else
1005 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1006 (const_string "yes")
1007 (const_string "no")))])
1008
1009 (define_insn "<optab>di3_fake"
1010 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1011 (sign_extend:DI
1012 (unspec:SI
1013 [(subreg:SI
1014 (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1015 (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1016 UNSPEC_FAKE_ANY_DIV)))]
1017 "TARGET_64BIT && !TARGET_DIV32"
1018 {
1019 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1020 }
1021 [(set_attr "type" "idiv")
1022 (set_attr "mode" "SI")
1023 (set (attr "enabled")
1024 (if_then_else
1025 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1026 (const_string "yes")
1027 (const_string "no")))])
1028
1029 ;; Floating point multiply accumulate instructions.
1030
1031 ;; a * b + c
1032 (define_insn "fma<mode>4"
1033 [(set (match_operand:ANYF 0 "register_operand" "=f")
1034 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1035 (match_operand:ANYF 2 "register_operand" "f")
1036 (match_operand:ANYF 3 "register_operand" "f")))]
1037 ""
1038 "fmadd.<fmt>\t%0,%1,%2,%3"
1039 [(set_attr "type" "fmadd")
1040 (set_attr "mode" "<UNITMODE>")])
1041
1042 ;; a * b - c
1043 (define_insn "fms<mode>4"
1044 [(set (match_operand:ANYF 0 "register_operand" "=f")
1045 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1046 (match_operand:ANYF 2 "register_operand" "f")
1047 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1048 ""
1049 "fmsub.<fmt>\t%0,%1,%2,%3"
1050 [(set_attr "type" "fmadd")
1051 (set_attr "mode" "<UNITMODE>")])
1052
1053 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1054 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1055 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1056 ;; This transformation means we may return the wrong signed zero
1057 ;; so we check HONOR_SIGNED_ZEROS.
1058
1059 ;; -a * b + c
1060 (define_insn "fnma<mode>4"
1061 [(set (match_operand:ANYF 0 "register_operand" "=f")
1062 (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1063 (match_operand:ANYF 2 "register_operand" "f")
1064 (match_operand:ANYF 3 "register_operand" "f")))]
1065 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1066 "fnmsub.<fmt>\t%0,%1,%2,%3"
1067 [(set_attr "type" "fmadd")
1068 (set_attr "mode" "<UNITMODE>")])
1069
1070 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1071 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1072 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1073 ;; This transformation means we may return the wrong signed zero
1074 ;; so we check HONOR_SIGNED_ZEROS.
1075
1076 ;; -a * b - c
1077 (define_insn "fnms<mode>4"
1078 [(set (match_operand:ANYF 0 "register_operand" "=f")
1079 (fma:ANYF
1080 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1081 (match_operand:ANYF 2 "register_operand" "f")
1082 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1083 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1084 "fnmadd.<fmt>\t%0,%1,%2,%3"
1085 [(set_attr "type" "fmadd")
1086 (set_attr "mode" "<UNITMODE>")])
1087
1088 ;; -(-a * b - c), modulo signed zeros
1089 (define_insn "*fma<mode>4"
1090 [(set (match_operand:ANYF 0 "register_operand" "=f")
1091 (neg:ANYF
1092 (fma:ANYF
1093 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1094 (match_operand:ANYF 2 "register_operand" " f")
1095 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1096 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1097 "fmadd.<fmt>\t%0,%1,%2,%3"
1098 [(set_attr "type" "fmadd")
1099 (set_attr "mode" "<UNITMODE>")])
1100
1101 ;; -(-a * b + c), modulo signed zeros
1102 (define_insn "*fms<mode>4"
1103 [(set (match_operand:ANYF 0 "register_operand" "=f")
1104 (neg:ANYF
1105 (fma:ANYF
1106 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1107 (match_operand:ANYF 2 "register_operand" " f")
1108 (match_operand:ANYF 3 "register_operand" " f"))))]
1109 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1110 "fmsub.<fmt>\t%0,%1,%2,%3"
1111 [(set_attr "type" "fmadd")
1112 (set_attr "mode" "<UNITMODE>")])
1113
1114 ;; -(a * b + c)
1115 (define_insn "*fnms<mode>4"
1116 [(set (match_operand:ANYF 0 "register_operand" "=f")
1117 (neg:ANYF
1118 (fma:ANYF
1119 (match_operand:ANYF 1 "register_operand" " f")
1120 (match_operand:ANYF 2 "register_operand" " f")
1121 (match_operand:ANYF 3 "register_operand" " f"))))]
1122 ""
1123 "fnmadd.<fmt>\t%0,%1,%2,%3"
1124 [(set_attr "type" "fmadd")
1125 (set_attr "mode" "<UNITMODE>")])
1126
1127 ;; -(a * b - c)
1128 (define_insn "*fnma<mode>4"
1129 [(set (match_operand:ANYF 0 "register_operand" "=f")
1130 (neg:ANYF
1131 (fma:ANYF
1132 (match_operand:ANYF 1 "register_operand" " f")
1133 (match_operand:ANYF 2 "register_operand" " f")
1134 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1135 ""
1136 "fnmsub.<fmt>\t%0,%1,%2,%3"
1137 [(set_attr "type" "fmadd")
1138 (set_attr "mode" "<UNITMODE>")])
1139 \f
1140 ;;
1141 ;; ....................
1142 ;;
1143 ;; SQUARE ROOT
1144 ;;
1145 ;; ....................
1146
1147 (define_expand "sqrt<mode>2"
1148 [(set (match_operand:ANYF 0 "register_operand")
1149 (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1150 ""
1151 {
1152 if (<MODE>mode == SFmode
1153 && TARGET_RECIP_SQRT
1154 && flag_unsafe_math_optimizations
1155 && !optimize_insn_for_size_p ()
1156 && flag_finite_math_only && !flag_trapping_math)
1157 {
1158 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1159 DONE;
1160 }
1161 })
1162
1163 (define_insn "*sqrt<mode>2"
1164 [(set (match_operand:ANYF 0 "register_operand" "=f")
1165 (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1166 ""
1167 "fsqrt.<fmt>\t%0,%1"
1168 [(set_attr "type" "fsqrt")
1169 (set_attr "mode" "<UNITMODE>")
1170 (set_attr "insn_count" "1")])
1171
1172 (define_expand "rsqrt<mode>2"
1173 [(set (match_operand:ANYF 0 "register_operand")
1174 (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1175 UNSPEC_RSQRT))]
1176 "TARGET_HARD_FLOAT"
1177 {
1178 if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1179 {
1180 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1181 DONE;
1182 }
1183 })
1184
1185 (define_insn "*rsqrt<mode>2"
1186 [(set (match_operand:ANYF 0 "register_operand" "=f")
1187 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1188 UNSPEC_RSQRT))]
1189 "TARGET_HARD_FLOAT"
1190 "frsqrt.<fmt>\t%0,%1"
1191 [(set_attr "type" "frsqrt")
1192 (set_attr "mode" "<UNITMODE>")])
1193
1194 ;; Approximate Reciprocal Square Root Instructions.
1195
1196 (define_insn "loongarch_frsqrte_<fmt>"
1197 [(set (match_operand:ANYF 0 "register_operand" "=f")
1198 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1199 UNSPEC_RSQRTE))]
1200 "TARGET_FRECIPE"
1201 "frsqrte.<fmt>\t%0,%1"
1202 [(set_attr "type" "frsqrte")
1203 (set_attr "mode" "<UNITMODE>")])
1204 \f
1205 ;;
1206 ;; ....................
1207 ;;
1208 ;; ABSOLUTE VALUE
1209 ;;
1210 ;; ....................
1211
1212 (define_insn "abs<mode>2"
1213 [(set (match_operand:ANYF 0 "register_operand" "=f")
1214 (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1215 ""
1216 "fabs.<fmt>\t%0,%1"
1217 [(set_attr "type" "fabs")
1218 (set_attr "mode" "<UNITMODE>")])
1219 \f
1220 ;;
1221 ;; ....................
1222 ;;
1223 ;; FLOATING POINT COPYSIGN
1224 ;;
1225 ;; ....................
1226
1227 (define_insn "copysign<mode>3"
1228 [(set (match_operand:ANYF 0 "register_operand" "=f")
1229 (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1230 (match_operand:ANYF 2 "register_operand" "f")))]
1231 "TARGET_HARD_FLOAT"
1232 "fcopysign.<fmt>\t%0,%1,%2"
1233 [(set_attr "type" "fcopysign")
1234 (set_attr "mode" "<UNITMODE>")])
1235
1236 (define_expand "@xorsign<mode>3"
1237 [(match_operand:ANYF 0 "register_operand")
1238 (match_operand:ANYF 1 "register_operand")
1239 (match_operand:ANYF 2 "register_operand")]
1240 "ISA_HAS_LSX"
1241 {
1242 machine_mode lsx_mode
1243 = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1244 rtx tmp = gen_reg_rtx (lsx_mode);
1245 rtx op1 = lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1246 rtx op2 = lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1247 emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1248 emit_move_insn (operands[0],
1249 lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1250 DONE;
1251 })
1252 \f
1253 ;;
1254 ;; ....................
1255 ;;
1256 ;; FLOATING POINT SCALE
1257 ;;
1258 ;; ....................
1259
1260 (define_insn "ldexp<mode>3"
1261 [(set (match_operand:ANYF 0 "register_operand" "=f")
1262 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")
1263 (match_operand:<IMODE> 2 "register_operand" "f")]
1264 UNSPEC_FSCALEB))]
1265 "TARGET_HARD_FLOAT"
1266 "fscaleb.<fmt>\t%0,%1,%2"
1267 [(set_attr "type" "fscaleb")
1268 (set_attr "mode" "<UNITMODE>")])
1269 \f
1270 ;;
1271 ;; ....................
1272 ;;
1273 ;; FLOATING POINT EXPONENT EXTRACT
1274 ;;
1275 ;; ....................
1276
1277 (define_insn "logb_non_negative<mode>2"
1278 [(set (match_operand:ANYF 0 "register_operand" "=f")
1279 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1280 UNSPEC_FLOGB))]
1281 "TARGET_HARD_FLOAT"
1282 "flogb.<fmt>\t%0,%1"
1283 [(set_attr "type" "flogb")
1284 (set_attr "mode" "<UNITMODE>")])
1285
1286 (define_expand "logb<mode>2"
1287 [(set (match_operand:ANYF 0 "register_operand")
1288 (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1289 UNSPEC_FLOGB))]
1290 "TARGET_HARD_FLOAT"
1291 {
1292 rtx tmp = gen_reg_rtx (<MODE>mode);
1293
1294 emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1295 emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1296 DONE;
1297 })
1298 \f
1299 ;;
1300 ;; ...................
1301 ;;
1302 ;; Count leading zeroes.
1303 ;;
1304 ;; ...................
1305 ;;
1306
1307 (define_insn "clz<mode>2"
1308 [(set (match_operand:GPR 0 "register_operand" "=r")
1309 (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1310 ""
1311 "clz.<d>\t%0,%1"
1312 [(set_attr "type" "clz")
1313 (set_attr "mode" "<MODE>")])
1314
1315 ;;
1316 ;; ...................
1317 ;;
1318 ;; Count trailing zeroes.
1319 ;;
1320 ;; ...................
1321 ;;
1322
1323 (define_insn "ctz<mode>2"
1324 [(set (match_operand:GPR 0 "register_operand" "=r")
1325 (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1326 ""
1327 "ctz.<d>\t%0,%1"
1328 [(set_attr "type" "clz")
1329 (set_attr "mode" "<MODE>")])
1330
1331 ;;
1332 ;; ....................
1333 ;;
1334 ;; MIN/MAX
1335 ;;
1336 ;; ....................
1337
1338 (define_insn "smax<mode>3"
1339 [(set (match_operand:ANYF 0 "register_operand" "=f")
1340 (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1341 (match_operand:ANYF 2 "register_operand" "f")))]
1342 ""
1343 "fmax.<fmt>\t%0,%1,%2"
1344 [(set_attr "type" "fmove")
1345 (set_attr "mode" "<MODE>")])
1346
1347 (define_insn "smin<mode>3"
1348 [(set (match_operand:ANYF 0 "register_operand" "=f")
1349 (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1350 (match_operand:ANYF 2 "register_operand" "f")))]
1351 ""
1352 "fmin.<fmt>\t%0,%1,%2"
1353 [(set_attr "type" "fmove")
1354 (set_attr "mode" "<MODE>")])
1355
1356 (define_insn "fmax<mode>3"
1357 [(set (match_operand:ANYF 0 "register_operand" "=f")
1358 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1359 (use (match_operand:ANYF 2 "register_operand" "f"))]
1360 UNSPEC_FMAX))]
1361 ""
1362 "fmax.<fmt>\t%0,%1,%2"
1363 [(set_attr "type" "fmove")
1364 (set_attr "mode" "<MODE>")])
1365
1366 (define_insn "fmin<mode>3"
1367 [(set (match_operand:ANYF 0 "register_operand" "=f")
1368 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1369 (use (match_operand:ANYF 2 "register_operand" "f"))]
1370 UNSPEC_FMIN))]
1371 ""
1372 "fmin.<fmt>\t%0,%1,%2"
1373 [(set_attr "type" "fmove")
1374 (set_attr "mode" "<MODE>")])
1375
1376 (define_insn "smaxa<mode>3"
1377 [(set (match_operand:ANYF 0 "register_operand" "=f")
1378 (if_then_else:ANYF
1379 (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1380 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1381 (match_dup 1)
1382 (match_dup 2)))]
1383 ""
1384 "fmaxa.<fmt>\t%0,%1,%2"
1385 [(set_attr "type" "fmove")
1386 (set_attr "mode" "<MODE>")])
1387
1388 (define_insn "smina<mode>3"
1389 [(set (match_operand:ANYF 0 "register_operand" "=f")
1390 (if_then_else:ANYF
1391 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1392 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1393 (match_dup 1)
1394 (match_dup 2)))]
1395 ""
1396 "fmina.<fmt>\t%0,%1,%2"
1397 [(set_attr "type" "fmove")
1398 (set_attr "mode" "<MODE>")])
1399
1400 ;;
1401 ;; ....................
1402 ;;
1403 ;; NEGATION and ONE'S COMPLEMENT
1404 ;;
1405 ;; ....................
1406
1407 (define_insn "neg<mode>2"
1408 [(set (match_operand:GPR 0 "register_operand" "=r")
1409 (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1410 ""
1411 "sub.<d>\t%0,%.,%1"
1412 [(set_attr "alu_type" "sub")
1413 (set_attr "mode" "<MODE>")])
1414
1415 (define_insn "one_cmpl<mode>2"
1416 [(set (match_operand:GPR 0 "register_operand" "=r")
1417 (not:GPR (match_operand:GPR 1 "register_operand" "r")))]
1418 ""
1419 "nor\t%0,%.,%1"
1420 [(set_attr "alu_type" "not")
1421 (set_attr "mode" "<MODE>")])
1422
1423 (define_insn "neg<mode>2"
1424 [(set (match_operand:ANYF 0 "register_operand" "=f")
1425 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1426 ""
1427 "fneg.<fmt>\t%0,%1"
1428 [(set_attr "type" "fneg")
1429 (set_attr "mode" "<UNITMODE>")])
1430 \f
1431
1432 ;;
1433 ;; ....................
1434 ;;
1435 ;; LOGICAL
1436 ;;
1437 ;; ....................
1438 ;;
1439
1440 (define_insn "<optab><mode>3"
1441 [(set (match_operand:GPR 0 "register_operand" "=r,r")
1442 (any_bitwise:GPR (match_operand:GPR 1 "register_operand" "%r,r")
1443 (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
1444 ""
1445 "<insn>%i2\t%0,%1,%2"
1446 [(set_attr "type" "logical")
1447 (set_attr "mode" "<MODE>")])
1448
1449 (define_insn "and<mode>3_extended"
1450 [(set (match_operand:GPR 0 "register_operand" "=r")
1451 (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "r")
1452 (match_operand:GPR 2 "low_bitmask_operand" "Yx")))]
1453 ""
1454 {
1455 int len;
1456
1457 len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
1458 operands[2] = GEN_INT (len-1);
1459 return "bstrpick.<d>\t%0,%1,%2,0";
1460 }
1461 [(set_attr "move_type" "pick_ins")
1462 (set_attr "mode" "<MODE>")])
1463
1464 (define_insn_and_split "*bstrins_<mode>_for_mask"
1465 [(set (match_operand:GPR 0 "register_operand")
1466 (and:GPR (match_operand:GPR 1 "register_operand")
1467 (match_operand:GPR 2 "ins_zero_bitmask_operand")))]
1468 ""
1469 "#"
1470 ""
1471 [(set (match_dup 0) (match_dup 1))
1472 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 3))
1473 (const_int 0))]
1474 {
1475 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1476 int lo = ffs_hwi (mask) - 1;
1477 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1478
1479 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1480 operands[2] = GEN_INT (len);
1481 operands[3] = GEN_INT (lo);
1482 })
1483
1484 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1485 [(set (match_operand:GPR 0 "register_operand")
1486 (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand")
1487 (match_operand:GPR 2 "const_int_operand"))
1488 (and:GPR (match_operand:GPR 3 "register_operand")
1489 (match_operand:GPR 4 "const_int_operand"))))]
1490 "loongarch_pre_reload_split ()
1491 && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1492 "#"
1493 "&& true"
1494 [(set (match_dup 0) (match_dup 1))
1495 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1496 (match_dup 3))]
1497 {
1498 if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1499 {
1500 std::swap (operands[1], operands[3]);
1501 std::swap (operands[2], operands[4]);
1502 }
1503
1504 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1505 int lo = ffs_hwi (mask) - 1;
1506 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1507
1508 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1509 operands[2] = GEN_INT (len);
1510 operands[4] = GEN_INT (lo);
1511
1512 if (lo)
1513 {
1514 rtx tmp = gen_reg_rtx (<MODE>mode);
1515 emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1516 GEN_INT (lo)));
1517 operands[3] = tmp;
1518 }
1519 })
1520
1521 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1522 ;; if possible, but the result may be sub-optimal when one of the masks
1523 ;; is (1 << N) - 1 and one of the src register is the dest register.
1524 ;; For example:
1525 ;; move t0, a0
1526 ;; move a0, a1
1527 ;; bstrins.d a0, t0, 42, 0
1528 ;; ret
1529 ;; using a shift operation would be better:
1530 ;; srai.d t0, a1, 43
1531 ;; bstrins.d a0, t0, 63, 43
1532 ;; ret
1533 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1534 ;; know if the dest register is one of the src register. Fix it up in
1535 ;; peephole2.
1536 (define_peephole2
1537 [(set (match_operand:GPR 0 "register_operand")
1538 (match_operand:GPR 1 "register_operand"))
1539 (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1540 (set (zero_extract:GPR (match_dup 1)
1541 (match_operand:SI 3 "const_int_operand")
1542 (const_int 0))
1543 (match_dup 0))]
1544 "peep2_reg_dead_p (3, operands[0])"
1545 [(const_int 0)]
1546 {
1547 int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1548
1549 emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1550 emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1551 operands[0]));
1552 DONE;
1553 })
1554
1555 (define_insn "*iorhi3"
1556 [(set (match_operand:HI 0 "register_operand" "=r,r")
1557 (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1558 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1559 ""
1560 "or%i2\t%0,%1,%2"
1561 [(set_attr "type" "logical")
1562 (set_attr "mode" "HI")])
1563
1564 (define_insn "*nor<mode>3"
1565 [(set (match_operand:GPR 0 "register_operand" "=r")
1566 (and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "%r"))
1567 (not:GPR (match_operand:GPR 2 "register_operand" "r"))))]
1568 ""
1569 "nor\t%0,%1,%2"
1570 [(set_attr "type" "logical")
1571 (set_attr "mode" "<MODE>")])
1572
1573 (define_insn "<optab>n<mode>"
1574 [(set (match_operand:GPR 0 "register_operand" "=r")
1575 (neg_bitwise:GPR
1576 (not:GPR (match_operand:GPR 1 "register_operand" "r"))
1577 (match_operand:GPR 2 "register_operand" "r")))]
1578 ""
1579 "<insn>n\t%0,%2,%1"
1580 [(set_attr "type" "logical")
1581 (set_attr "mode" "<MODE>")])
1582
1583 \f
1584 ;;
1585 ;; ....................
1586 ;;
1587 ;; TRUNCATION
1588 ;;
1589 ;; ....................
1590
1591 (define_insn "truncdfsf2"
1592 [(set (match_operand:SF 0 "register_operand" "=f")
1593 (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1594 "TARGET_DOUBLE_FLOAT"
1595 "fcvt.s.d\t%0,%1"
1596 [(set_attr "type" "fcvt")
1597 (set_attr "cnv_mode" "D2S")
1598 (set_attr "mode" "SF")])
1599
1600 ;; In vector registers, popcount can be implemented directly through
1601 ;; the vector instruction [X]VPCNT. For GP registers, we can implement
1602 ;; it through the following method. Compared with loop implementation
1603 ;; of popcount, the following method has better performance.
1604
1605 ;; This attribute used for get connection of scalar mode and corresponding
1606 ;; vector mode.
1607 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1608
1609 (define_expand "popcount<mode>2"
1610 [(set (match_operand:GPR 0 "register_operand")
1611 (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1612 "ISA_HAS_LSX"
1613 {
1614 rtx in = operands[1];
1615 rtx out = operands[0];
1616 rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1617 gen_reg_rtx (V2DImode);
1618 emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1619 emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1620 emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1621 DONE;
1622 })
1623
1624 ;;
1625 ;; ....................
1626 ;;
1627 ;; ZERO EXTENSION
1628 ;;
1629 ;; ....................
1630 (define_expand "zero_extendsidi2"
1631 [(set (match_operand:DI 0 "register_operand")
1632 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1633 "TARGET_64BIT")
1634
1635 (define_insn_and_split "*zero_extendsidi2_internal"
1636 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1637 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1638 "TARGET_64BIT"
1639 "@
1640 bstrpick.d\t%0,%1,31,0
1641 ld.wu\t%0,%1
1642 #
1643 ldx.wu\t%0,%1"
1644 "&& reload_completed
1645 && MEM_P (operands[1])
1646 && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1647 && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1648 && !paradoxical_subreg_p (operands[0])"
1649 [(set (match_dup 3) (match_dup 1))
1650 (set (match_dup 0)
1651 (ior:DI (zero_extend:DI
1652 (subreg:SI (match_dup 0) 0))
1653 (match_dup 2)))]
1654 {
1655 operands[1] = gen_lowpart (SImode, operands[1]);
1656 operands[3] = gen_lowpart (SImode, operands[0]);
1657 operands[2] = const0_rtx;
1658 }
1659 [(set_attr "move_type" "arith,load,load,load")
1660 (set_attr "mode" "DI")])
1661
1662 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1663 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1664 (zero_extend:GPR
1665 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1666 ""
1667 "@
1668 bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1669 ld.<SHORT:size>u\t%0,%1
1670 ldx.<SHORT:size>u\t%0,%1"
1671 [(set_attr "move_type" "pick_ins,load,load")
1672 (set_attr "mode" "<GPR:MODE>")])
1673
1674 (define_insn "zero_extendqihi2"
1675 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1676 (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1677 ""
1678 "@
1679 andi\t%0,%1,0xff
1680 ldx.bu\t%0,%1
1681 ld.bu\t%0,%1"
1682 [(set_attr "move_type" "andi,load,load")
1683 (set_attr "mode" "HI")])
1684
1685 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1686
1687 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1688 [(set (match_operand:GPR 0 "register_operand" "=r")
1689 (zero_extend:GPR
1690 (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1691 "TARGET_64BIT"
1692 "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1693 [(set_attr "move_type" "pick_ins")
1694 (set_attr "mode" "<GPR:MODE>")])
1695
1696 (define_insn "*zero_extendhi_truncqi"
1697 [(set (match_operand:HI 0 "register_operand" "=r")
1698 (zero_extend:HI
1699 (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1700 "TARGET_64BIT"
1701 "andi\t%0,%1,0xff"
1702 [(set_attr "alu_type" "and")
1703 (set_attr "mode" "HI")])
1704 \f
1705 ;;
1706 ;; ....................
1707 ;;
1708 ;; SIGN EXTENSION
1709 ;;
1710 ;; ....................
1711
1712 (define_insn "extendsidi2"
1713 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1714 (sign_extend:DI
1715 (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k")))]
1716 "TARGET_64BIT"
1717 "@
1718 slli.w\t%0,%1,0
1719 ldptr.w\t%0,%1
1720 ld.w\t%0,%1
1721 ldx.w\t%0,%1"
1722 [(set_attr "move_type" "sll0,load,load,load")
1723 (set_attr "mode" "DI")])
1724
1725 (define_insn "extend<SHORT:mode><GPR:mode>2"
1726 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1727 (sign_extend:GPR
1728 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1729 ""
1730 "@
1731 ext.w.<SHORT:size>\t%0,%1
1732 ld.<SHORT:size>\t%0,%1
1733 ldx.<SHORT:size>\t%0,%1"
1734 [(set_attr "move_type" "signext,load,load")
1735 (set_attr "mode" "<GPR:MODE>")])
1736
1737 (define_insn "extendqihi2"
1738 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1739 (sign_extend:HI
1740 (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1741 ""
1742 "@
1743 ext.w.b\t%0,%1
1744 ld.b\t%0,%1
1745 ldx.b\t%0,%1"
1746 [(set_attr "move_type" "signext,load,load")
1747 (set_attr "mode" "SI")])
1748
1749 (define_insn "extendsfdf2"
1750 [(set (match_operand:DF 0 "register_operand" "=f")
1751 (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1752 "TARGET_DOUBLE_FLOAT"
1753 "fcvt.d.s\t%0,%1"
1754 [(set_attr "type" "fcvt")
1755 (set_attr "cnv_mode" "S2D")
1756 (set_attr "mode" "DF")])
1757 \f
1758 ;;
1759 ;; ....................
1760 ;;
1761 ;; CONVERSIONS
1762 ;;
1763 ;; ....................
1764
1765 ;; conversion of a floating-point value to a integer
1766
1767 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1768 [(set (match_operand:GPR 0 "register_operand" "=f")
1769 (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1770 ""
1771 "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1772 [(set_attr "type" "fcvt")
1773 (set_attr "mode" "<ANYF:MODE>")])
1774
1775 ;; conversion of an integeral (or boolean) value to a floating-point value
1776
1777 (define_insn "floatsidf2"
1778 [(set (match_operand:DF 0 "register_operand" "=f")
1779 (float:DF (match_operand:SI 1 "register_operand" "f")))]
1780 "TARGET_DOUBLE_FLOAT"
1781 "ffint.d.w\t%0,%1"
1782 [(set_attr "type" "fcvt")
1783 (set_attr "mode" "DF")
1784 (set_attr "cnv_mode" "I2D")])
1785
1786 (define_insn "floatdidf2"
1787 [(set (match_operand:DF 0 "register_operand" "=f")
1788 (float:DF (match_operand:DI 1 "register_operand" "f")))]
1789 "TARGET_DOUBLE_FLOAT"
1790 "ffint.d.l\t%0,%1"
1791 [(set_attr "type" "fcvt")
1792 (set_attr "mode" "DF")
1793 (set_attr "cnv_mode" "I2D")])
1794
1795 (define_insn "floatsisf2"
1796 [(set (match_operand:SF 0 "register_operand" "=f")
1797 (float:SF (match_operand:SI 1 "register_operand" "f")))]
1798 "TARGET_HARD_FLOAT"
1799 "ffint.s.w\t%0,%1"
1800 [(set_attr "type" "fcvt")
1801 (set_attr "mode" "SF")
1802 (set_attr "cnv_mode" "I2S")])
1803
1804 (define_insn "floatdisf2"
1805 [(set (match_operand:SF 0 "register_operand" "=f")
1806 (float:SF (match_operand:DI 1 "register_operand" "f")))]
1807 "TARGET_DOUBLE_FLOAT"
1808 "ffint.s.l\t%0,%1"
1809 [(set_attr "type" "fcvt")
1810 (set_attr "mode" "SF")
1811 (set_attr "cnv_mode" "I2S")])
1812
1813 ;; Convert a floating-point value to an unsigned integer.
1814
1815 (define_expand "fixuns_truncdfsi2"
1816 [(set (match_operand:SI 0 "register_operand")
1817 (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1818 "TARGET_DOUBLE_FLOAT"
1819 {
1820 rtx reg1 = gen_reg_rtx (DFmode);
1821 rtx reg2 = gen_reg_rtx (DFmode);
1822 rtx reg3 = gen_reg_rtx (SImode);
1823 rtx_code_label *label1 = gen_label_rtx ();
1824 rtx_code_label *label2 = gen_label_rtx ();
1825 rtx test;
1826 REAL_VALUE_TYPE offset;
1827
1828 real_2expN (&offset, 31, DFmode);
1829
1830 loongarch_emit_move (reg1,
1831 const_double_from_real_value (offset, DFmode));
1832 do_pending_stack_adjust ();
1833
1834 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1835 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1836
1837 emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1838 emit_jump_insn (gen_rtx_SET (pc_rtx,
1839 gen_rtx_LABEL_REF (VOIDmode, label2)));
1840 emit_barrier ();
1841
1842 emit_label (label1);
1843 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1844 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1845 (BITMASK_HIGH, SImode)));
1846
1847 emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1848 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1849
1850 emit_label (label2);
1851
1852 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1853 fields, and can't be used for REG_NOTES anyway). */
1854 emit_use (stack_pointer_rtx);
1855 DONE;
1856 })
1857
1858 (define_expand "fixuns_truncdfdi2"
1859 [(set (match_operand:DI 0 "register_operand")
1860 (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
1861 "TARGET_DOUBLE_FLOAT"
1862 {
1863 rtx reg1 = gen_reg_rtx (DFmode);
1864 rtx reg2 = gen_reg_rtx (DFmode);
1865 rtx reg3 = gen_reg_rtx (DImode);
1866 rtx_code_label *label1 = gen_label_rtx ();
1867 rtx_code_label *label2 = gen_label_rtx ();
1868 rtx test;
1869 REAL_VALUE_TYPE offset;
1870
1871 real_2expN (&offset, 63, DFmode);
1872
1873 loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
1874 do_pending_stack_adjust ();
1875
1876 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1877 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1878
1879 emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
1880 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1881 emit_barrier ();
1882
1883 emit_label (label1);
1884 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1885 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
1886 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
1887
1888 emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
1889 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
1890
1891 emit_label (label2);
1892
1893 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1894 fields, and can't be used for REG_NOTES anyway). */
1895 emit_use (stack_pointer_rtx);
1896 DONE;
1897 })
1898
1899 (define_expand "fixuns_truncsfsi2"
1900 [(set (match_operand:SI 0 "register_operand")
1901 (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
1902 "TARGET_HARD_FLOAT"
1903 {
1904 rtx reg1 = gen_reg_rtx (SFmode);
1905 rtx reg2 = gen_reg_rtx (SFmode);
1906 rtx reg3 = gen_reg_rtx (SImode);
1907 rtx_code_label *label1 = gen_label_rtx ();
1908 rtx_code_label *label2 = gen_label_rtx ();
1909 rtx test;
1910 REAL_VALUE_TYPE offset;
1911
1912 real_2expN (&offset, 31, SFmode);
1913
1914 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
1915 do_pending_stack_adjust ();
1916
1917 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1918 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
1919
1920 emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
1921 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1922 emit_barrier ();
1923
1924 emit_label (label1);
1925 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
1926 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1927 (BITMASK_HIGH, SImode)));
1928
1929 emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
1930 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1931
1932 emit_label (label2);
1933
1934 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1935 fields, and can't be used for REG_NOTES anyway). */
1936 emit_use (stack_pointer_rtx);
1937 DONE;
1938 })
1939
1940 (define_expand "fixuns_truncsfdi2"
1941 [(set (match_operand:DI 0 "register_operand")
1942 (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
1943 "TARGET_DOUBLE_FLOAT"
1944 {
1945 rtx reg1 = gen_reg_rtx (SFmode);
1946 rtx reg2 = gen_reg_rtx (SFmode);
1947 rtx reg3 = gen_reg_rtx (DImode);
1948 rtx_code_label *label1 = gen_label_rtx ();
1949 rtx_code_label *label2 = gen_label_rtx ();
1950 rtx test;
1951 REAL_VALUE_TYPE offset;
1952
1953 real_2expN (&offset, 63, SFmode);
1954
1955 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
1956 do_pending_stack_adjust ();
1957
1958 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1959 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
1960
1961 emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
1962 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1963 emit_barrier ();
1964
1965 emit_label (label1);
1966 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
1967 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
1968 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
1969
1970 emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
1971 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
1972
1973 emit_label (label2);
1974
1975 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1976 fields, and can't be used for REG_NOTES anyway). */
1977 emit_use (stack_pointer_rtx);
1978 DONE;
1979 })
1980 \f
1981 ;;
1982 ;; ....................
1983 ;;
1984 ;; EXTRACT AND INSERT
1985 ;;
1986 ;; ....................
1987
1988 (define_expand "extzv<mode>"
1989 [(set (match_operand:X 0 "register_operand")
1990 (zero_extract:X (match_operand:X 1 "register_operand")
1991 (match_operand 2 "const_int_operand")
1992 (match_operand 3 "const_int_operand")))]
1993 ""
1994 {
1995 if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
1996 INTVAL (operands[3])))
1997 FAIL;
1998 })
1999
2000 (define_insn "*extzv<mode>"
2001 [(set (match_operand:X 0 "register_operand" "=r")
2002 (zero_extract:X (match_operand:X 1 "register_operand" "r")
2003 (match_operand 2 "const_int_operand" "")
2004 (match_operand 3 "const_int_operand" "")))]
2005 "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2006 INTVAL (operands[3]))"
2007 {
2008 operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2009 return "bstrpick.<d>\t%0,%1,%2,%3";
2010 }
2011 [(set_attr "type" "arith")
2012 (set_attr "mode" "<MODE>")])
2013
2014 (define_expand "insv<mode>"
2015 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2016 (match_operand 1 "const_int_operand")
2017 (match_operand 2 "const_int_operand"))
2018 (match_operand:GPR 3 "reg_or_0_operand"))]
2019 ""
2020 {
2021 if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2022 INTVAL (operands[2])))
2023 FAIL;
2024 })
2025
2026 (define_insn "*insv<mode>"
2027 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2028 (match_operand:SI 1 "const_int_operand" "")
2029 (match_operand:SI 2 "const_int_operand" ""))
2030 (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2031 "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2032 INTVAL (operands[2]))"
2033 {
2034 operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2035 return "bstrins.<d>\t%0,%z3,%1,%2";
2036 }
2037 [(set_attr "type" "arith")
2038 (set_attr "mode" "<MODE>")])
2039 \f
2040 ;;
2041 ;; ....................
2042 ;;
2043 ;; DATA MOVEMENT
2044 ;;
2045 ;; ....................
2046
2047 ;; 64-bit integer moves
2048
2049 ;; Unlike most other insns, the move insns can't be split with
2050 ;; different predicates, because register spilling and other parts of
2051 ;; the compiler, have memoized the insn number already.
2052
2053 (define_expand "movdi"
2054 [(set (match_operand:DI 0 "")
2055 (match_operand:DI 1 ""))]
2056 ""
2057 {
2058 if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2059 DONE;
2060 })
2061
2062 (define_insn_and_split "*movdi_32bit"
2063 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2064 (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2065 "!TARGET_64BIT
2066 && (register_operand (operands[0], DImode)
2067 || reg_or_0_operand (operands[1], DImode))"
2068 { return loongarch_output_move (operands[0], operands[1]); }
2069 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2070 (operands[0]))"
2071 [(const_int 0)]
2072 "
2073 {
2074 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2075 DONE;
2076 }
2077 "
2078 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2079 (set_attr "mode" "DI")])
2080
2081 (define_insn_and_split "*movdi_64bit"
2082 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2083 (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2084 "TARGET_64BIT
2085 && (register_operand (operands[0], DImode)
2086 || reg_or_0_operand (operands[1], DImode))"
2087 { return loongarch_output_move (operands[0], operands[1]); }
2088 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2089 (operands[0]))"
2090 [(const_int 0)]
2091 "
2092 {
2093 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2094 DONE;
2095 }
2096 "
2097 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2098 (set_attr "mode" "DI")])
2099
2100 ;; 32-bit Integer moves
2101
2102 (define_expand "movsi"
2103 [(set (match_operand:SI 0 "")
2104 (match_operand:SI 1 ""))]
2105 ""
2106 {
2107 if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2108 DONE;
2109 })
2110
2111 (define_insn_and_split "*movsi_internal"
2112 [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m,*r,*z")
2113 (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f,*z,*r"))]
2114 "(register_operand (operands[0], SImode)
2115 || reg_or_0_operand (operands[1], SImode))"
2116 { return loongarch_output_move (operands[0], operands[1]); }
2117 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2118 (operands[0]))"
2119 [(const_int 0)]
2120 "
2121 {
2122 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2123 DONE;
2124 }
2125 "
2126 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore,mftg,mgtf")
2127 (set_attr "mode" "SI")])
2128
2129 ;; 16-bit Integer moves
2130
2131 ;; Unlike most other insns, the move insns can't be split with
2132 ;; different predicates, because register spilling and other parts of
2133 ;; the compiler, have memoized the insn number already.
2134 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2135
2136 (define_expand "movhi"
2137 [(set (match_operand:HI 0 "")
2138 (match_operand:HI 1 ""))]
2139 ""
2140 {
2141 if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2142 DONE;
2143 })
2144
2145 (define_insn_and_split "*movhi_internal"
2146 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2147 (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2148 "(register_operand (operands[0], HImode)
2149 || reg_or_0_operand (operands[1], HImode))"
2150 { return loongarch_output_move (operands[0], operands[1]); }
2151 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2152 (operands[0]))"
2153 [(const_int 0)]
2154 "
2155 {
2156 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2157 DONE;
2158 }
2159 "
2160 [(set_attr "move_type" "move,const,const,load,store,load,store")
2161 (set_attr "mode" "HI")])
2162
2163 ;; 8-bit Integer moves
2164
2165 ;; Unlike most other insns, the move insns can't be split with
2166 ;; different predicates, because register spilling and other parts of
2167 ;; the compiler, have memoized the insn number already.
2168 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2169
2170 (define_expand "movqi"
2171 [(set (match_operand:QI 0 "")
2172 (match_operand:QI 1 ""))]
2173 ""
2174 {
2175 if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2176 DONE;
2177 })
2178
2179 (define_insn "*movqi_internal"
2180 [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2181 (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2182 "(register_operand (operands[0], QImode)
2183 || reg_or_0_operand (operands[1], QImode))"
2184 { return loongarch_output_move (operands[0], operands[1]); }
2185 [(set_attr "move_type" "move,const,load,store,load,store")
2186 (set_attr "mode" "QI")])
2187
2188 ;; 32-bit floating point moves
2189
2190 (define_expand "movsf"
2191 [(set (match_operand:SF 0 "")
2192 (match_operand:SF 1 ""))]
2193 ""
2194 {
2195 if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2196 DONE;
2197 })
2198
2199 (define_insn "*movsf_hardfloat"
2200 [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2201 (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2202 "TARGET_HARD_FLOAT
2203 && (register_operand (operands[0], SFmode)
2204 || reg_or_0_operand (operands[1], SFmode))"
2205 { return loongarch_output_move (operands[0], operands[1]); }
2206 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2207 (set_attr "mode" "SF")])
2208
2209 (define_insn "*movsf_softfloat"
2210 [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2211 (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2212 "TARGET_SOFT_FLOAT
2213 && (register_operand (operands[0], SFmode)
2214 || reg_or_0_operand (operands[1], SFmode))"
2215 { return loongarch_output_move (operands[0], operands[1]); }
2216 [(set_attr "move_type" "move,load,store")
2217 (set_attr "mode" "SF")])
2218
2219 ;; 64-bit floating point moves
2220
2221 (define_expand "movdf"
2222 [(set (match_operand:DF 0 "")
2223 (match_operand:DF 1 ""))]
2224 ""
2225 {
2226 if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2227 DONE;
2228 })
2229
2230 (define_insn "*movdf_hardfloat"
2231 [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2232 (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2233 "TARGET_DOUBLE_FLOAT
2234 && (register_operand (operands[0], DFmode)
2235 || reg_or_0_operand (operands[1], DFmode))"
2236 { return loongarch_output_move (operands[0], operands[1]); }
2237 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2238 (set_attr "mode" "DF")])
2239
2240 (define_insn "*movdf_softfloat"
2241 [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2242 (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2243 "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2244 && (register_operand (operands[0], DFmode)
2245 || reg_or_0_operand (operands[1], DFmode))"
2246 { return loongarch_output_move (operands[0], operands[1]); }
2247 [(set_attr "move_type" "move,load,store")
2248 (set_attr "mode" "DF")])
2249
2250 ;; Emit a doubleword move in which exactly one of the operands is
2251 ;; a floating-point register. We can't just emit two normal moves
2252 ;; because of the constraints imposed by the FPU register model;
2253 ;; see loongarch_can_change_mode_class for details. Instead, we keep
2254 ;; the FPR whole and use special patterns to refer to each word of
2255 ;; the other operand.
2256
2257 (define_expand "move_doubleword_fpr<mode>"
2258 [(set (match_operand:SPLITF 0)
2259 (match_operand:SPLITF 1))]
2260 ""
2261 {
2262 if (FP_REG_RTX_P (operands[0]))
2263 {
2264 rtx low = loongarch_subword (operands[1], 0);
2265 rtx high = loongarch_subword (operands[1], 1);
2266 emit_insn (gen_load_low<mode> (operands[0], low));
2267 if (!TARGET_64BIT)
2268 emit_insn (gen_movgr2frh<mode> (operands[0], high, operands[0]));
2269 else
2270 emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
2271 }
2272 else
2273 {
2274 rtx low = loongarch_subword (operands[0], 0);
2275 rtx high = loongarch_subword (operands[0], 1);
2276 emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
2277 if (!TARGET_64BIT)
2278 emit_insn (gen_movfrh2gr<mode> (high, operands[1]));
2279 else
2280 emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
2281 }
2282 DONE;
2283 })
2284
2285 ;; Clear one FCC register
2286
2287 (define_expand "movfcc"
2288 [(set (match_operand:FCC 0 "")
2289 (match_operand:FCC 1 ""))]
2290 "TARGET_HARD_FLOAT"
2291 {
2292 if (memory_operand (operands[0], FCCmode)
2293 && memory_operand (operands[1], FCCmode))
2294 operands[1] = force_reg (FCCmode, operands[1]);
2295 })
2296
2297 (define_insn "movfcc_internal"
2298 [(set (match_operand:FCC 0 "nonimmediate_operand"
2299 "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2300 (match_operand:FCC 1 "reg_or_0_operand"
2301 "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2302 "TARGET_HARD_FLOAT"
2303 "@
2304 fcmp.caf.s\t%0,$f0,$f0
2305 movfr2cf\t%0,%1
2306 movcf2fr\t%0,%1
2307 fmov.s\t%0,%1
2308 or\t%0,%z1,$r0
2309 ld.b\t%0,%1
2310 st.b\t%z1,%0
2311 movgr2fr.w\t%0,%1
2312 movfr2gr.s\t%0,%1
2313 movgr2cf\t%0,%1
2314 movcf2gr\t%0,%1"
2315 [(set_attr "type" "move")
2316 (set_attr "mode" "FCC")])
2317
2318 (define_insn "fcc_to_<X:mode>"
2319 [(set (match_operand:X 0 "register_operand" "=r")
2320 (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2321 (const_int 0))
2322 (const_int 1)
2323 (const_int 0)))]
2324 "TARGET_HARD_FLOAT"
2325 ""
2326 [(set_attr "length" "0")
2327 (set_attr "type" "ghost")])
2328
2329 (define_expand "cstore<ANYF:mode>4"
2330 [(set (match_operand:SI 0 "register_operand")
2331 (match_operator:SI 1 "loongarch_fcmp_operator"
2332 [(match_operand:ANYF 2 "register_operand")
2333 (match_operand:ANYF 3 "register_operand")]))]
2334 ""
2335 {
2336 rtx fcc = gen_reg_rtx (FCCmode);
2337 rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2338 operands[2], operands[3]);
2339
2340 emit_insn (gen_rtx_SET (fcc, cmp));
2341 if (TARGET_64BIT)
2342 {
2343 rtx gpr = gen_reg_rtx (DImode);
2344 emit_insn (gen_fcc_to_di (gpr, fcc));
2345 emit_insn (gen_rtx_SET (operands[0],
2346 lowpart_subreg (SImode, gpr, DImode)));
2347 }
2348 else
2349 emit_insn (gen_fcc_to_si (operands[0], fcc));
2350
2351 DONE;
2352 })
2353
2354 ;; Conditional move instructions.
2355
2356 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2357 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2358 (if_then_else:GPR
2359 (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2360 (const_int 0))
2361 (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2362 (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2363 "register_operand (operands[2], <GPR:MODE>mode)
2364 != register_operand (operands[3], <GPR:MODE>mode)"
2365 "@
2366 <sel>\t%0,%2,%1
2367 <selinv>\t%0,%3,%1"
2368 [(set_attr "type" "condmove")
2369 (set_attr "mode" "<GPR:MODE>")])
2370
2371 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2372 ;; argument if the 1st is zero. This means operand 2 and 3 are
2373 ;; inverted in the instruction.
2374
2375 (define_insn "*sel<mode>"
2376 [(set (match_operand:ANYF 0 "register_operand" "=f")
2377 (if_then_else:ANYF
2378 (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2379 (const_int 0))
2380 (match_operand:ANYF 2 "reg_or_0_operand" "f")
2381 (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2382 ""
2383 "fsel\t%0,%3,%2,%1"
2384 [(set_attr "type" "condmove")
2385 (set_attr "mode" "<ANYF:MODE>")])
2386
2387 ;; These are the main define_expand's used to make conditional moves.
2388
2389 (define_expand "mov<mode>cc"
2390 [(set (match_operand:GPR 0 "register_operand")
2391 (if_then_else:GPR (match_operator 1 "comparison_operator"
2392 [(match_operand:GPR 2 "reg_or_0_operand")
2393 (match_operand:GPR 3 "reg_or_0_operand")])))]
2394 "TARGET_COND_MOVE_INT"
2395 {
2396 if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2397 FAIL;
2398
2399 loongarch_expand_conditional_move (operands);
2400 DONE;
2401 })
2402
2403 (define_expand "mov<mode>cc"
2404 [(set (match_operand:ANYF 0 "register_operand")
2405 (if_then_else:ANYF (match_operator 1 "comparison_operator"
2406 [(match_operand:ANYF 2 "reg_or_0_operand")
2407 (match_operand:ANYF 3 "reg_or_0_operand")])))]
2408 "TARGET_COND_MOVE_FLOAT"
2409 {
2410 if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2411 FAIL;
2412
2413 loongarch_expand_conditional_move (operands);
2414 DONE;
2415 })
2416
2417 (define_insn "lu32i_d"
2418 [(set (match_operand:DI 0 "register_operand" "=r")
2419 (ior:DI
2420 (zero_extend:DI
2421 (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2422 (match_operand:DI 2 "const_lu32i_operand" "u")))]
2423 "TARGET_64BIT"
2424 "lu32i.d\t%0,%X2>>32"
2425 [(set_attr "type" "arith")
2426 (set_attr "mode" "DI")])
2427
2428 (define_insn "lu52i_d"
2429 [(set (match_operand:DI 0 "register_operand" "=r")
2430 (ior:DI
2431 (and:DI (match_operand:DI 1 "register_operand" "r")
2432 (match_operand 2 "lu52i_mask_operand"))
2433 (match_operand 3 "const_lu52i_operand" "v")))]
2434 "TARGET_64BIT"
2435 "lu52i.d\t%0,%1,%X3>>52"
2436 [(set_attr "type" "arith")
2437 (set_attr "mode" "DI")])
2438
2439 ;; Instructions for adding the low 12 bits of an address to a register.
2440 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2441 ;; should be applied.
2442
2443 (define_insn "*low<mode>"
2444 [(set (match_operand:P 0 "register_operand" "=r")
2445 (lo_sum:P (match_operand:P 1 "register_operand" " r")
2446 (match_operand:P 2 "symbolic_operand" "")))]
2447 ""
2448 "addi.<d>\t%0,%1,%L2"
2449 [(set_attr "type" "arith")
2450 (set_attr "mode" "<MODE>")])
2451
2452 (define_insn "@tls_low<mode>"
2453 [(set (match_operand:P 0 "register_operand" "=r")
2454 (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2455 (match_operand:P 2 "symbolic_operand" "")))]
2456 UNSPEC_TLS_LOW))]
2457 ""
2458 "addi.<d>\t%0,%1,%L2"
2459 [(set_attr "type" "arith")
2460 (set_attr "mode" "<MODE>")])
2461
2462 ;; Instructions for loading address from GOT entry.
2463 ;; operands[1] is pc plus the high half of the address difference with the got
2464 ;; entry;
2465 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2466 ;; got entry.
2467 ;; loongarch_print_operand works out which relocation should be applied.
2468
2469 (define_insn "@ld_from_got<mode>"
2470 [(set (match_operand:P 0 "register_operand" "=r")
2471 (unspec:P [(mem:P (lo_sum:P
2472 (match_operand:P 1 "register_operand" "r")
2473 (match_operand:P 2 "symbolic_operand")))]
2474 UNSPEC_LOAD_FROM_GOT))]
2475 ""
2476 "ld.<d>\t%0,%1,%L2"
2477 [(set_attr "type" "move")]
2478 )
2479
2480 (define_insn "@lui_l_hi20<mode>"
2481 [(set (match_operand:P 0 "register_operand" "=r")
2482 (unspec:P [(match_operand:P 1 "symbolic_operand")]
2483 UNSPEC_LUI_L_HI20))]
2484 ""
2485 "lu12i.w\t%0,%r1"
2486 [(set_attr "type" "move")]
2487 )
2488
2489 (define_insn "@pcalau12i<mode>"
2490 [(set (match_operand:P 0 "register_operand" "=j")
2491 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2492 UNSPEC_PCALAU12I))]
2493 ""
2494 "pcalau12i\t%0,%%pc_hi20(%1)"
2495 [(set_attr "type" "move")])
2496
2497 ;; @pcalau12i may be used for sibcall so it has a strict constraint. This
2498 ;; allows any general register as the operand.
2499 (define_insn "@pcalau12i_gr<mode>"
2500 [(set (match_operand:P 0 "register_operand" "=r")
2501 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2502 UNSPEC_PCALAU12I_GR))]
2503 ""
2504 "pcalau12i\t%0,%%pc_hi20(%1)"
2505 [(set_attr "type" "move")])
2506
2507 (define_insn "@add_tls_le_relax<mode>"
2508 [(set (match_operand:P 0 "register_operand" "=r")
2509 (unspec:P [(match_operand:P 1 "register_operand" "r")
2510 (match_operand:P 2 "register_operand" "r")
2511 (match_operand:P 3 "symbolic_operand")]
2512 UNSPEC_ADD_TLS_LE_RELAX))]
2513 "HAVE_AS_TLS_LE_RELAXATION"
2514 "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2515 [(set_attr "type" "move")]
2516 )
2517
2518 (define_insn "@ori_l_lo12<mode>"
2519 [(set (match_operand:P 0 "register_operand" "=r")
2520 (unspec:P [(match_operand:P 1 "register_operand" "r")
2521 (match_operand:P 2 "symbolic_operand")]
2522 UNSPEC_ORI_L_LO12))]
2523 ""
2524 "ori\t%0,%1,%L2"
2525 [(set_attr "type" "move")]
2526 )
2527
2528 (define_insn "lui_h_lo20"
2529 [(set (match_operand:DI 0 "register_operand" "=r")
2530 (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2531 (match_operand:DI 2 "symbolic_operand")]
2532 UNSPEC_LUI_H_LO20))]
2533 "TARGET_64BIT"
2534 "lu32i.d\t%0,%R2"
2535 [(set_attr "type" "move")]
2536 )
2537
2538 (define_insn "lui_h_hi12"
2539 [(set (match_operand:DI 0 "register_operand" "=r")
2540 (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2541 (match_operand:DI 2 "symbolic_operand")]
2542 UNSPEC_LUI_H_HI12))]
2543 "TARGET_64BIT"
2544 "lu52i.d\t%0,%1,%H2"
2545 [(set_attr "type" "move")]
2546 )
2547
2548 ;; Round floating-point numbers to integers
2549 (define_insn "rint<mode>2"
2550 [(set (match_operand:ANYF 0 "register_operand" "=f")
2551 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2552 UNSPEC_FRINT))]
2553 ""
2554 "frint.<fmt>\t%0,%1"
2555 [(set_attr "type" "fcvt")
2556 (set_attr "mode" "<MODE>")])
2557
2558 ;; Convert floating-point numbers to integers
2559 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2560 [(set (match_operand:ANYFI 0 "register_operand" "=f")
2561 (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2562 LRINT))]
2563 "TARGET_HARD_FLOAT &&
2564 (<LRINT> == UNSPEC_FTINT
2565 || flag_fp_int_builtin_inexact
2566 || !flag_trapping_math)"
2567 "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2568 [(set_attr "type" "fcvt")
2569 (set_attr "mode" "<ANYF:MODE>")])
2570
2571 ;; Load the low word of operand 0 with operand 1.
2572 (define_insn "load_low<mode>"
2573 [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
2574 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "rJ,m")]
2575 UNSPEC_LOAD_LOW))]
2576 "TARGET_HARD_FLOAT"
2577 {
2578 operands[0] = loongarch_subword (operands[0], 0);
2579 return loongarch_output_move (operands[0], operands[1]);
2580 }
2581 [(set_attr "move_type" "mgtf,fpload")
2582 (set_attr "mode" "<HALFMODE>")])
2583
2584 ;; Load the high word of operand 0 from operand 1, preserving the value
2585 ;; in the low word.
2586 (define_insn "load_high<mode>"
2587 [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
2588 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "rJ,m")
2589 (match_operand:SPLITF 2 "register_operand" "0,0")]
2590 UNSPEC_LOAD_HIGH))]
2591 "TARGET_HARD_FLOAT"
2592 {
2593 operands[0] = loongarch_subword (operands[0], 1);
2594 return loongarch_output_move (operands[0], operands[1]);
2595 }
2596 [(set_attr "move_type" "mgtf,fpload")
2597 (set_attr "mode" "<HALFMODE>")])
2598
2599 ;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
2600 ;; high word and 0 to store the low word.
2601 (define_insn "store_word<mode>"
2602 [(set (match_operand:<HALFMODE> 0 "nonimmediate_operand" "=r,m")
2603 (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f,f")
2604 (match_operand 2 "const_int_operand")]
2605 UNSPEC_STORE_WORD))]
2606 "TARGET_HARD_FLOAT"
2607 {
2608 operands[1] = loongarch_subword (operands[1], INTVAL (operands[2]));
2609 return loongarch_output_move (operands[0], operands[1]);
2610 }
2611 [(set_attr "move_type" "mftg,fpstore")
2612 (set_attr "mode" "<HALFMODE>")])
2613
2614 ;; Thread-Local Storage
2615
2616 (define_insn "@got_load_tls_gd<mode>"
2617 [(set (match_operand:P 0 "register_operand" "=r")
2618 (unspec:P
2619 [(match_operand:P 1 "symbolic_operand" "")]
2620 UNSPEC_TLS_GD))]
2621 ""
2622 "la.tls.gd\t%0,%1"
2623 [(set_attr "got" "load")
2624 (set_attr "mode" "<MODE>")])
2625
2626 (define_insn "@got_load_tls_ld<mode>"
2627 [(set (match_operand:P 0 "register_operand" "=r")
2628 (unspec:P
2629 [(match_operand:P 1 "symbolic_operand" "")]
2630 UNSPEC_TLS_LD))]
2631 ""
2632 "la.tls.ld\t%0,%1"
2633 [(set_attr "got" "load")
2634 (set_attr "mode" "<MODE>")])
2635
2636 (define_insn "@got_load_tls_le<mode>"
2637 [(set (match_operand:P 0 "register_operand" "=r")
2638 (unspec:P
2639 [(match_operand:P 1 "symbolic_operand" "")]
2640 UNSPEC_TLS_LE))]
2641 ""
2642 "la.tls.le\t%0,%1"
2643 [(set_attr "got" "load")
2644 (set_attr "mode" "<MODE>")])
2645
2646 (define_insn "@got_load_tls_ie<mode>"
2647 [(set (match_operand:P 0 "register_operand" "=r")
2648 (unspec:P
2649 [(match_operand:P 1 "symbolic_operand" "")]
2650 UNSPEC_TLS_IE))]
2651 ""
2652 "la.tls.ie\t%0,%1"
2653 [(set_attr "got" "load")
2654 (set_attr "mode" "<MODE>")])
2655
2656 ;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving the
2657 ;; value in the low word.
2658 (define_insn "movgr2frh<mode>"
2659 [(set (match_operand:SPLITF 0 "register_operand" "=f")
2660 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "reg_or_0_operand" "rJ")
2661 (match_operand:SPLITF 2 "register_operand" "0")]
2662 UNSPEC_MOVGR2FRH))]
2663 "TARGET_DOUBLE_FLOAT"
2664 "movgr2frh.w\t%z1,%0"
2665 [(set_attr "move_type" "mgtf")
2666 (set_attr "mode" "<HALFMODE>")])
2667
2668 ;; Move high word of operand 1 to operand 0 using movfrh2gr.s.
2669 (define_insn "movfrh2gr<mode>"
2670 [(set (match_operand:<HALFMODE> 0 "register_operand" "=r")
2671 (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f")]
2672 UNSPEC_MOVFRH2GR))]
2673 "TARGET_DOUBLE_FLOAT"
2674 "movfrh2gr.s\t%0,%1"
2675 [(set_attr "move_type" "mftg")
2676 (set_attr "mode" "<HALFMODE>")])
2677
2678 \f
2679 ;; Expand in-line code to clear the instruction cache between operand[0] and
2680 ;; operand[1].
2681 (define_expand "clear_cache"
2682 [(match_operand 0 "pmode_register_operand")
2683 (match_operand 1 "pmode_register_operand")]
2684 ""
2685 {
2686 emit_insn (gen_loongarch_ibar (const0_rtx));
2687 DONE;
2688 })
2689
2690 (define_insn "loongarch_ibar"
2691 [(unspec_volatile:SI
2692 [(match_operand 0 "const_uimm15_operand")]
2693 UNSPECV_IBAR)
2694 (clobber (mem:BLK (scratch)))]
2695 ""
2696 "ibar\t%0")
2697
2698 (define_insn "loongarch_dbar"
2699 [(unspec_volatile:SI
2700 [(match_operand 0 "const_uimm15_operand")]
2701 UNSPECV_DBAR)
2702 (clobber (mem:BLK (scratch)))]
2703 ""
2704 "dbar\t%0")
2705
2706 \f
2707
2708 ;; Privileged state instruction
2709
2710 (define_insn "loongarch_cpucfg"
2711 [(set (match_operand:SI 0 "register_operand" "=r")
2712 (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2713 UNSPECV_CPUCFG))]
2714 ""
2715 "cpucfg\t%0,%1"
2716 [(set_attr "type" "load")
2717 (set_attr "mode" "SI")])
2718
2719 (define_insn "loongarch_syscall"
2720 [(unspec_volatile:SI
2721 [(match_operand 0 "const_uimm15_operand")]
2722 UNSPECV_SYSCALL)
2723 (clobber (mem:BLK (scratch)))]
2724 ""
2725 "syscall\t%0")
2726
2727 (define_insn "loongarch_break"
2728 [(unspec_volatile:SI
2729 [(match_operand 0 "const_uimm15_operand")]
2730 UNSPECV_BREAK)
2731 (clobber (mem:BLK (scratch)))]
2732 ""
2733 "break\t%0")
2734
2735 (define_insn "loongarch_asrtle_d"
2736 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2737 (match_operand:DI 1 "register_operand" "r")]
2738 UNSPECV_ASRTLE_D)]
2739 "TARGET_64BIT"
2740 "asrtle.d\t%0,%1"
2741 [(set_attr "type" "load")
2742 (set_attr "mode" "DI")])
2743
2744 (define_insn "loongarch_asrtgt_d"
2745 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2746 (match_operand:DI 1 "register_operand" "r")]
2747 UNSPECV_ASRTGT_D)]
2748 "TARGET_64BIT"
2749 "asrtgt.d\t%0,%1"
2750 [(set_attr "type" "load")
2751 (set_attr "mode" "DI")])
2752
2753 (define_insn "loongarch_csrrd_<d>"
2754 [(set (match_operand:GPR 0 "register_operand" "=r")
2755 (unspec_volatile:GPR [(match_operand 1 "const_uimm14_operand")]
2756 UNSPECV_CSRRD))
2757 (clobber (mem:BLK (scratch)))]
2758 ""
2759 "csrrd\t%0,%1"
2760 [(set_attr "type" "load")
2761 (set_attr "mode" "<MODE>")])
2762
2763 (define_insn "loongarch_csrwr_<d>"
2764 [(set (match_operand:GPR 0 "register_operand" "=r")
2765 (unspec_volatile:GPR
2766 [(match_operand:GPR 1 "register_operand" "0")
2767 (match_operand 2 "const_uimm14_operand")]
2768 UNSPECV_CSRWR))
2769 (clobber (mem:BLK (scratch)))]
2770 ""
2771 "csrwr\t%0,%2"
2772 [(set_attr "type" "store")
2773 (set_attr "mode" "<MODE>")])
2774
2775 (define_insn "loongarch_csrxchg_<d>"
2776 [(set (match_operand:GPR 0 "register_operand" "=r")
2777 (unspec_volatile:GPR
2778 [(match_operand:GPR 1 "register_operand" "0")
2779 (match_operand:GPR 2 "register_operand" "q")
2780 (match_operand 3 "const_uimm14_operand")]
2781 UNSPECV_CSRXCHG))
2782 (clobber (mem:BLK (scratch)))]
2783 ""
2784 "csrxchg\t%0,%2,%3"
2785 [(set_attr "type" "load")
2786 (set_attr "mode" "<MODE>")])
2787
2788 (define_insn "loongarch_iocsrrd_<size>"
2789 [(set (match_operand:QHWD 0 "register_operand" "=r")
2790 (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2791 UNSPECV_IOCSRRD))
2792 (clobber (mem:BLK (scratch)))]
2793 ""
2794 "iocsrrd.<size>\t%0,%1"
2795 [(set_attr "type" "load")
2796 (set_attr "mode" "<MODE>")])
2797
2798 (define_insn "loongarch_iocsrwr_<size>"
2799 [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2800 (match_operand:SI 1 "register_operand" "r")]
2801 UNSPECV_IOCSRWR)
2802 (clobber (mem:BLK (scratch)))]
2803 ""
2804 "iocsrwr.<size>\t%0,%1"
2805 [(set_attr "type" "load")
2806 (set_attr "mode" "<MODE>")])
2807
2808 (define_insn "loongarch_cacop_<d>"
2809 [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2810 (match_operand:X 1 "register_operand" "r")
2811 (match_operand 2 "const_imm12_operand")]
2812 UNSPECV_CACOP)
2813 (clobber (mem:BLK (scratch)))]
2814 ""
2815 "cacop\t%0,%1,%2"
2816 [(set_attr "type" "load")
2817 (set_attr "mode" "<MODE>")])
2818
2819 (define_insn "loongarch_lddir_<d>"
2820 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2821 (match_operand:X 1 "register_operand" "r")
2822 (match_operand 2 "const_uimm5_operand")]
2823 UNSPECV_LDDIR)
2824 (clobber (mem:BLK (scratch)))]
2825 ""
2826 "lddir\t%0,%1,%2"
2827 [(set_attr "type" "load")
2828 (set_attr "mode" "<MODE>")])
2829
2830 (define_insn "loongarch_ldpte_<d>"
2831 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2832 (match_operand 1 "const_uimm5_operand")]
2833 UNSPECV_LDPTE)
2834 (clobber (mem:BLK (scratch)))]
2835 ""
2836 "ldpte\t%0,%1"
2837 [(set_attr "type" "load")
2838 (set_attr "mode" "<MODE>")])
2839
2840 \f
2841 ;; Block moves, see loongarch.c for more details.
2842 ;; Argument 0 is the destination.
2843 ;; Argument 1 is the source.
2844 ;; Argument 2 is the length.
2845 ;; Argument 3 is the alignment.
2846
2847 (define_expand "cpymemsi"
2848 [(parallel [(set (match_operand:BLK 0 "general_operand")
2849 (match_operand:BLK 1 "general_operand"))
2850 (use (match_operand:SI 2 ""))
2851 (use (match_operand:SI 3 "const_int_operand"))])]
2852 ""
2853 {
2854 if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
2855 && loongarch_expand_block_move (operands[0], operands[1],
2856 operands[2], operands[3]))
2857 DONE;
2858 else
2859 FAIL;
2860 })
2861 \f
2862 ;;
2863 ;; ....................
2864 ;;
2865 ;; SHIFTS
2866 ;;
2867 ;; ....................
2868
2869 (define_insn "<optab><mode>3"
2870 [(set (match_operand:GPR 0 "register_operand" "=r")
2871 (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
2872 (match_operand:SI 2 "arith_operand" "rI")))]
2873 ""
2874 {
2875 if (CONST_INT_P (operands[2]))
2876 operands[2] = GEN_INT (INTVAL (operands[2])
2877 & (GET_MODE_BITSIZE (<MODE>mode) - 1));
2878
2879 return "<insn>%i2.<d>\t%0,%1,%2";
2880 }
2881 [(set_attr "type" "shift")
2882 (set_attr "mode" "<MODE>")])
2883
2884 (define_insn "*<optab>si3_extend"
2885 [(set (match_operand:DI 0 "register_operand" "=r")
2886 (sign_extend:DI
2887 (any_shift:SI (match_operand:SI 1 "register_operand" "r")
2888 (match_operand:SI 2 "arith_operand" "rI"))))]
2889 "TARGET_64BIT"
2890 {
2891 if (CONST_INT_P (operands[2]))
2892 operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
2893
2894 return "<insn>%i2.w\t%0,%1,%2";
2895 }
2896 [(set_attr "type" "shift")
2897 (set_attr "mode" "SI")])
2898
2899 (define_insn "rotr<mode>3"
2900 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2901 (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
2902 (match_operand:SI 2 "arith_operand" "r,I")))]
2903 ""
2904 "rotr%i2.<d>\t%0,%1,%2"
2905 [(set_attr "type" "shift,shift")
2906 (set_attr "mode" "<MODE>")])
2907
2908 (define_insn "rotrsi3_extend"
2909 [(set (match_operand:DI 0 "register_operand" "=r,r")
2910 (sign_extend:DI
2911 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
2912 (match_operand:SI 2 "arith_operand" "r,I"))))]
2913 "TARGET_64BIT"
2914 "rotr%i2.w\t%0,%1,%2"
2915 [(set_attr "type" "shift,shift")
2916 (set_attr "mode" "SI")])
2917
2918 ;; Expand left rotate to right rotate.
2919 (define_expand "rotl<mode>3"
2920 [(set (match_dup 3)
2921 (neg:SI (match_operand:SI 2 "register_operand")))
2922 (set (match_operand:GPR 0 "register_operand")
2923 (rotatert:GPR (match_operand:GPR 1 "register_operand")
2924 (match_dup 3)))]
2925 ""
2926 {
2927 operands[3] = gen_reg_rtx (SImode);
2928 });
2929
2930 ;; The following templates were added to generate "bstrpick.d + alsl.d"
2931 ;; instruction pairs.
2932 ;; It is required that the values of const_immalsl_operand and
2933 ;; immediate_operand must have the following correspondence:
2934 ;;
2935 ;; (immediate_operand >> const_immalsl_operand) == 0xffffffff
2936
2937 (define_insn "zero_extend_ashift"
2938 [(set (match_operand:DI 0 "register_operand" "=r")
2939 (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
2940 (match_operand 2 "const_immalsl_operand" ""))
2941 (match_operand 3 "immediate_operand" "")))]
2942 "TARGET_64BIT
2943 && ((INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff)"
2944 "bstrpick.d\t%0,%1,31,0\n\talsl.d\t%0,%0,$r0,%2"
2945 [(set_attr "type" "arith")
2946 (set_attr "mode" "DI")
2947 (set_attr "insn_count" "2")])
2948
2949 (define_insn "bstrpick_alsl_paired"
2950 [(set (match_operand:DI 0 "register_operand" "=&r")
2951 (plus:DI (match_operand:DI 1 "register_operand" "r")
2952 (and:DI (ashift:DI (match_operand:DI 2 "register_operand" "r")
2953 (match_operand 3 "const_immalsl_operand" ""))
2954 (match_operand 4 "immediate_operand" ""))))]
2955 "TARGET_64BIT
2956 && ((INTVAL (operands[4]) >> INTVAL (operands[3])) == 0xffffffff)"
2957 "bstrpick.d\t%0,%2,31,0\n\talsl.d\t%0,%0,%1,%3"
2958 [(set_attr "type" "arith")
2959 (set_attr "mode" "DI")
2960 (set_attr "insn_count" "2")])
2961
2962 (define_insn "alsl<mode>3"
2963 [(set (match_operand:GPR 0 "register_operand" "=r")
2964 (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
2965 (match_operand 2 "const_immalsl_operand" ""))
2966 (match_operand:GPR 3 "register_operand" "r")))]
2967 ""
2968 "alsl.<d>\t%0,%1,%3,%2"
2969 [(set_attr "type" "arith")
2970 (set_attr "mode" "<MODE>")])
2971
2972 (define_insn "alslsi3_extend"
2973 [(set (match_operand:DI 0 "register_operand" "=r")
2974 (sign_extend:DI
2975 (plus:SI
2976 (ashift:SI (match_operand:SI 1 "register_operand" "r")
2977 (match_operand 2 "const_immalsl_operand" ""))
2978 (match_operand:SI 3 "register_operand" "r"))))]
2979 ""
2980 "alsl.w\t%0,%1,%3,%2"
2981 [(set_attr "type" "arith")
2982 (set_attr "mode" "SI")])
2983
2984 \f
2985
2986 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
2987
2988 (define_insn "bswaphi2"
2989 [(set (match_operand:HI 0 "register_operand" "=r")
2990 (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
2991 ""
2992 "revb.2h\t%0,%1"
2993 [(set_attr "type" "shift")])
2994
2995 (define_insn_and_split "bswapsi2"
2996 [(set (match_operand:SI 0 "register_operand" "=r")
2997 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
2998 ""
2999 "#"
3000 ""
3001 [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_REVB_2H))
3002 (set (match_dup 0) (rotatert:SI (match_dup 0) (const_int 16)))]
3003 ""
3004 [(set_attr "insn_count" "2")])
3005
3006 (define_insn_and_split "bswapdi2"
3007 [(set (match_operand:DI 0 "register_operand" "=r")
3008 (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3009 "TARGET_64BIT"
3010 "#"
3011 ""
3012 [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_REVB_4H))
3013 (set (match_dup 0) (unspec:DI [(match_dup 0)] UNSPEC_REVH_D))]
3014 ""
3015 [(set_attr "insn_count" "2")])
3016
3017 (define_insn "revb_2h"
3018 [(set (match_operand:SI 0 "register_operand" "=r")
3019 (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_REVB_2H))]
3020 ""
3021 "revb.2h\t%0,%1"
3022 [(set_attr "type" "shift")])
3023
3024 (define_insn "revb_4h"
3025 [(set (match_operand:DI 0 "register_operand" "=r")
3026 (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_REVB_4H))]
3027 "TARGET_64BIT"
3028 "revb.4h\t%0,%1"
3029 [(set_attr "type" "shift")])
3030
3031 (define_insn "revh_d"
3032 [(set (match_operand:DI 0 "register_operand" "=r")
3033 (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_REVH_D))]
3034 "TARGET_64BIT"
3035 "revh.d\t%0,%1"
3036 [(set_attr "type" "shift")])
3037 \f
3038 ;;
3039 ;; ....................
3040 ;;
3041 ;; CONDITIONAL BRANCHES
3042 ;;
3043 ;; ....................
3044
3045 ;; Conditional branches
3046
3047 (define_insn "*branch_fp_FCCmode"
3048 [(set (pc)
3049 (if_then_else
3050 (match_operator 1 "equality_operator"
3051 [(match_operand:FCC 2 "register_operand" "z")
3052 (const_int 0)])
3053 (label_ref (match_operand 0 "" ""))
3054 (pc)))]
3055 "TARGET_HARD_FLOAT"
3056 {
3057 return loongarch_output_conditional_branch (insn, operands,
3058 LARCH_BRANCH ("b%F1", "%Z2%0"),
3059 LARCH_BRANCH ("b%W1", "%Z2%0"));
3060 }
3061 [(set_attr "type" "branch")])
3062
3063 (define_insn "*branch_fp_inverted_FCCmode"
3064 [(set (pc)
3065 (if_then_else
3066 (match_operator 1 "equality_operator"
3067 [(match_operand:FCC 2 "register_operand" "z")
3068 (const_int 0)])
3069 (pc)
3070 (label_ref (match_operand 0 "" ""))))]
3071 "TARGET_HARD_FLOAT"
3072 {
3073 return loongarch_output_conditional_branch (insn, operands,
3074 LARCH_BRANCH ("b%W1", "%Z2%0"),
3075 LARCH_BRANCH ("b%F1", "%Z2%0"));
3076 }
3077 [(set_attr "type" "branch")])
3078
3079 ;; Conditional branches on ordered comparisons with zero.
3080
3081 (define_insn "*branch_order<mode>"
3082 [(set (pc)
3083 (if_then_else
3084 (match_operator 1 "order_operator"
3085 [(match_operand:X 2 "register_operand" "r,r")
3086 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3087 (label_ref (match_operand 0 "" ""))
3088 (pc)))]
3089 ""
3090 { return loongarch_output_order_conditional_branch (insn, operands, false); }
3091 [(set_attr "type" "branch")])
3092
3093 (define_insn "*branch_order<mode>_inverted"
3094 [(set (pc)
3095 (if_then_else
3096 (match_operator 1 "order_operator"
3097 [(match_operand:X 2 "register_operand" "r,r")
3098 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3099 (pc)
3100 (label_ref (match_operand 0 "" ""))))]
3101 ""
3102 { return loongarch_output_order_conditional_branch (insn, operands, true); }
3103 [(set_attr "type" "branch")])
3104
3105 ;; Conditional branch on equality comparison.
3106
3107 (define_insn "branch_equality<mode>"
3108 [(set (pc)
3109 (if_then_else
3110 (match_operator 1 "equality_operator"
3111 [(match_operand:X 2 "register_operand" "r")
3112 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3113 (label_ref (match_operand 0 "" ""))
3114 (pc)))]
3115 ""
3116 { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3117 [(set_attr "type" "branch")])
3118
3119
3120 (define_insn "*branch_equality<mode>_inverted"
3121 [(set (pc)
3122 (if_then_else
3123 (match_operator 1 "equality_operator"
3124 [(match_operand:X 2 "register_operand" "r")
3125 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3126 (pc)
3127 (label_ref (match_operand 0 "" ""))))]
3128 ""
3129 { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3130 [(set_attr "type" "branch")])
3131
3132
3133 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3134 ;; QImode values so we can force zero-extension.
3135 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3136
3137 (define_expand "cbranch<mode>4"
3138 [(set (pc)
3139 (if_then_else (match_operator 0 "comparison_operator"
3140 [(match_operand:BR 1 "register_operand")
3141 (match_operand:BR 2 "nonmemory_operand")])
3142 (label_ref (match_operand 3 ""))
3143 (pc)))]
3144 ""
3145 {
3146 loongarch_expand_conditional_branch (operands);
3147 DONE;
3148 })
3149
3150 (define_expand "cbranch<mode>4"
3151 [(set (pc)
3152 (if_then_else (match_operator 0 "comparison_operator"
3153 [(match_operand:ANYF 1 "register_operand")
3154 (match_operand:ANYF 2 "register_operand")])
3155 (label_ref (match_operand 3 ""))
3156 (pc)))]
3157 ""
3158 {
3159 loongarch_expand_conditional_branch (operands);
3160 DONE;
3161 })
3162
3163 ;; Used to implement built-in functions.
3164 (define_expand "condjump"
3165 [(set (pc)
3166 (if_then_else (match_operand 0)
3167 (label_ref (match_operand 1))
3168 (pc)))])
3169
3170
3171 \f
3172 ;;
3173 ;; ....................
3174 ;;
3175 ;; SETTING A REGISTER FROM A COMPARISON
3176 ;;
3177 ;; ....................
3178
3179 ;; Destination is always set in SI mode.
3180
3181 (define_expand "cstore<mode>4"
3182 [(set (match_operand:SI 0 "register_operand")
3183 (match_operator:SI 1 "loongarch_cstore_operator"
3184 [(match_operand:GPR 2 "register_operand")
3185 (match_operand:GPR 3 "nonmemory_operand")]))]
3186 ""
3187 {
3188 loongarch_expand_scc (operands);
3189 DONE;
3190 })
3191
3192 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3193 [(set (match_operand:GPR 0 "register_operand" "=r")
3194 (eq:GPR (match_operand:X 1 "register_operand" "r")
3195 (const_int 0)))]
3196 ""
3197 "sltui\t%0,%1,1"
3198 [(set_attr "type" "slt")
3199 (set_attr "mode" "<X:MODE>")])
3200
3201
3202 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3203 [(set (match_operand:GPR 0 "register_operand" "=r")
3204 (ne:GPR (match_operand:X 1 "register_operand" "r")
3205 (const_int 0)))]
3206 ""
3207 "sltu\t%0,%.,%1"
3208 [(set_attr "type" "slt")
3209 (set_attr "mode" "<X:MODE>")])
3210
3211 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3212 [(set (match_operand:GPR 0 "register_operand" "=r")
3213 (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3214 (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3215 ""
3216 "slt<u>\t%0,%z2,%1"
3217 [(set_attr "type" "slt")
3218 (set_attr "mode" "<X:MODE>")])
3219
3220 (define_insn "*sge<u>_<X:mode><GPR:mode>"
3221 [(set (match_operand:GPR 0 "register_operand" "=r")
3222 (any_ge:GPR (match_operand:X 1 "register_operand" "r")
3223 (const_int 1)))]
3224 ""
3225 "slt<u>i\t%0,%.,%1"
3226 [(set_attr "type" "slt")
3227 (set_attr "mode" "<X:MODE>")])
3228
3229 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3230 [(set (match_operand:GPR 0 "register_operand" "=r")
3231 (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3232 (match_operand:X 2 "arith_operand" "rI")))]
3233 ""
3234 "slt<u>%i2\t%0,%1,%2";
3235 [(set_attr "type" "slt")
3236 (set_attr "mode" "<X:MODE>")])
3237
3238 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3239 [(set (match_operand:GPR 0 "register_operand" "=r")
3240 (any_le:GPR (match_operand:X 1 "register_operand" "r")
3241 (match_operand:X 2 "sle_operand" "")))]
3242 ""
3243 {
3244 operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3245 return "slt<u>i\t%0,%1,%2";
3246 }
3247 [(set_attr "type" "slt")
3248 (set_attr "mode" "<X:MODE>")])
3249
3250 \f
3251 ;;
3252 ;; ....................
3253 ;;
3254 ;; FLOATING POINT COMPARISONS
3255 ;;
3256 ;; ....................
3257
3258 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3259 [(set (match_operand:FCC 0 "register_operand" "=z")
3260 (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3261 (match_operand:ANYF 2 "register_operand" "f")))]
3262 ""
3263 "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3264 [(set_attr "type" "fcmp")
3265 (set_attr "mode" "FCC")])
3266
3267 \f
3268 ;;
3269 ;; ....................
3270 ;;
3271 ;; UNCONDITIONAL BRANCHES
3272 ;;
3273 ;; ....................
3274
3275 ;; Unconditional branches.
3276
3277 (define_expand "jump"
3278 [(set (pc)
3279 (label_ref (match_operand 0)))])
3280
3281 (define_insn "*jump_absolute"
3282 [(set (pc)
3283 (label_ref (match_operand 0)))]
3284 "!flag_pic"
3285 {
3286 return "b\t%l0";
3287 }
3288 [(set_attr "type" "branch")])
3289
3290 (define_insn "*jump_pic"
3291 [(set (pc)
3292 (label_ref (match_operand 0)))]
3293 "flag_pic"
3294 {
3295 return "b\t%0";
3296 }
3297 [(set_attr "type" "branch")])
3298
3299 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3300 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3301 ;; return prediction and the more general indirect branch prediction.
3302
3303 (define_expand "indirect_jump"
3304 [(set (pc) (match_operand 0 "register_operand"))]
3305 ""
3306 {
3307 operands[0] = force_reg (Pmode, operands[0]);
3308 emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3309 DONE;
3310 })
3311
3312 (define_insn "@indirect_jump<mode>"
3313 [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3314 ""
3315 "jr\t%0"
3316 [(set_attr "type" "jump")
3317 (set_attr "mode" "none")])
3318
3319 (define_expand "tablejump"
3320 [(set (pc)
3321 (match_operand 0 "register_operand"))
3322 (use (label_ref (match_operand 1 "")))]
3323 ""
3324 {
3325 if (flag_pic)
3326 operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3327 gen_rtx_LABEL_REF (Pmode,
3328 operands[1]),
3329 NULL_RTX, 0, OPTAB_DIRECT);
3330 emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3331 DONE;
3332 })
3333
3334 (define_insn "@tablejump<mode>"
3335 [(set (pc)
3336 (match_operand:P 0 "register_operand" "e"))
3337 (use (label_ref (match_operand 1 "" "")))]
3338 ""
3339 "jr\t%0"
3340 [(set_attr "type" "jump")
3341 (set_attr "mode" "none")])
3342
3343
3344 \f
3345 ;;
3346 ;; ....................
3347 ;;
3348 ;; Function prologue/epilogue
3349 ;;
3350 ;; ....................
3351 ;;
3352
3353 (define_expand "prologue"
3354 [(const_int 1)]
3355 ""
3356 {
3357 loongarch_expand_prologue ();
3358 DONE;
3359 })
3360
3361 ;; Block any insns from being moved before this point, since the
3362 ;; profiling call to mcount can use various registers that aren't
3363 ;; saved or used to pass arguments.
3364
3365 (define_insn "blockage"
3366 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3367 ""
3368 ""
3369 [(set_attr "type" "ghost")
3370 (set_attr "mode" "none")])
3371
3372 (define_insn "@probe_stack_range<P:mode>"
3373 [(set (match_operand:P 0 "register_operand" "=r")
3374 (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3375 (match_operand:P 2 "register_operand" "r")
3376 (match_operand:P 3 "register_operand" "r")]
3377 UNSPECV_PROBE_STACK_RANGE))]
3378 ""
3379 {
3380 return loongarch_output_probe_stack_range (operands[0],
3381 operands[2],
3382 operands[3]);
3383 }
3384 [(set_attr "type" "unknown")
3385 (set_attr "mode" "<MODE>")])
3386
3387 (define_expand "epilogue"
3388 [(const_int 2)]
3389 ""
3390 {
3391 loongarch_expand_epilogue (NORMAL_RETURN);
3392 DONE;
3393 })
3394
3395 (define_expand "sibcall_epilogue"
3396 [(const_int 2)]
3397 ""
3398 {
3399 loongarch_expand_epilogue (SIBCALL_RETURN);
3400 DONE;
3401 })
3402
3403 ;; Trivial return. Make it look like a normal return insn as that
3404 ;; allows jump optimizations to work better.
3405
3406 (define_expand "return"
3407 [(simple_return)]
3408 "loongarch_can_use_return_insn ()"
3409 { })
3410
3411 (define_expand "simple_return"
3412 [(simple_return)]
3413 ""
3414 { })
3415
3416 (define_insn "*<optab>"
3417 [(any_return)]
3418 ""
3419 {
3420 operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3421 return "jr\t%0";
3422 }
3423 [(set_attr "type" "jump")
3424 (set_attr "mode" "none")])
3425
3426 ;; Normal return.
3427
3428 (define_insn "<optab>_internal"
3429 [(any_return)
3430 (use (match_operand 0 "pmode_register_operand" ""))]
3431 ""
3432 "jr\t%0"
3433 [(set_attr "type" "jump")
3434 (set_attr "mode" "none")])
3435
3436 ;; Exception return.
3437 (define_insn "loongarch_ertn"
3438 [(return)
3439 (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3440 ""
3441 "ertn"
3442 [(set_attr "type" "trap")
3443 (set_attr "mode" "none")])
3444
3445 ;; This is used in compiling the unwind routines.
3446 (define_expand "eh_return"
3447 [(use (match_operand 0 "general_operand"))]
3448 ""
3449 {
3450 if (GET_MODE (operands[0]) != word_mode)
3451 operands[0] = convert_to_mode (word_mode, operands[0], 0);
3452 if (TARGET_64BIT)
3453 emit_insn (gen_eh_set_ra_di (operands[0]));
3454 else
3455 emit_insn (gen_eh_set_ra_si (operands[0]));
3456
3457 emit_jump_insn (gen_eh_return_internal ());
3458 emit_barrier ();
3459 DONE;
3460 })
3461
3462 (define_insn_and_split "eh_return_internal"
3463 [(eh_return)]
3464 ""
3465 "#"
3466 "epilogue_completed"
3467 [(const_int 0)]
3468 {
3469 loongarch_expand_epilogue (EXCEPTION_RETURN);
3470 DONE;
3471 })
3472
3473 ;; Clobber the return address on the stack. We can't expand this
3474 ;; until we know where it will be put in the stack frame.
3475
3476 (define_insn "eh_set_ra_si"
3477 [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3478 (clobber (match_scratch:SI 1 "=&r"))]
3479 "! TARGET_64BIT"
3480 "#")
3481
3482 (define_insn "eh_set_ra_di"
3483 [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3484 (clobber (match_scratch:DI 1 "=&r"))]
3485 "TARGET_64BIT"
3486 "#")
3487
3488 (define_split
3489 [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3490 (clobber (match_scratch 1))]
3491 "reload_completed"
3492 [(const_int 0)]
3493 {
3494 loongarch_set_return_address (operands[0], operands[1]);
3495 DONE;
3496 })
3497
3498
3499 \f
3500 ;;
3501 ;; ....................
3502 ;;
3503 ;; FUNCTION CALLS
3504 ;;
3505 ;; ....................
3506
3507 ;; Sibling calls. All these patterns use jump instructions.
3508
3509 (define_expand "sibcall"
3510 [(parallel [(call (match_operand 0 "")
3511 (match_operand 1 ""))
3512 (use (match_operand 2 "")) ;; next_arg_reg
3513 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3514 ""
3515 {
3516 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3517
3518 if (GET_CODE (target) == LO_SUM)
3519 emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3520 XEXP (target, 1),
3521 operands[1]));
3522 else
3523 {
3524 rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3525
3526 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3527 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3528 gen_rtx_REG (Pmode, T0_REGNUM));
3529 }
3530 DONE;
3531 })
3532
3533 (define_insn "sibcall_internal"
3534 [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3535 (match_operand 1 "" ""))]
3536 "SIBLING_CALL_P (insn)"
3537 {
3538 switch (which_alternative)
3539 {
3540 case 0:
3541 return "jr\t%0";
3542 case 1:
3543 if (TARGET_CMODEL_MEDIUM)
3544 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3545 else
3546 return "b\t%0";
3547 case 2:
3548 if (TARGET_CMODEL_MEDIUM)
3549 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3550 else
3551 return "b\t%%plt(%0)";
3552 default:
3553 gcc_unreachable ();
3554 }
3555 }
3556 [(set_attr "jirl" "indirect,direct,direct")])
3557
3558 (define_insn "@sibcall_internal_1<mode>"
3559 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3560 (match_operand:P 1 "symbolic_operand" "")))
3561 (match_operand 2 "" ""))]
3562 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3563 "jirl\t$r0,%0,%%pc_lo12(%1)"
3564 [(set_attr "jirl" "indirect")])
3565
3566 (define_expand "sibcall_value"
3567 [(parallel [(set (match_operand 0 "")
3568 (call (match_operand 1 "")
3569 (match_operand 2 "")))
3570 (use (match_operand 3 ""))])] ;; next_arg_reg
3571 ""
3572 {
3573 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3574
3575 /* Handle return values created by loongarch_pass_fpr_pair. */
3576 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3577 {
3578 rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3579 rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3580
3581 if (GET_CODE (target) == LO_SUM)
3582 emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3583 XEXP (target, 0),
3584 XEXP (target, 1),
3585 operands[2],
3586 arg2));
3587 else
3588 {
3589 rtx call
3590 = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3591 target,
3592 operands[2],
3593 arg2));
3594
3595 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3596 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3597 gen_rtx_REG (Pmode, T0_REGNUM));
3598 }
3599 }
3600 else
3601 {
3602 /* Handle return values created by loongarch_return_fpr_single. */
3603 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3604 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3605
3606 if (GET_CODE (target) == LO_SUM)
3607 emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3608 XEXP (target, 0),
3609 XEXP (target, 1),
3610 operands[2]));
3611 else
3612 {
3613 rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3614 target,
3615 operands[2]));
3616
3617 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3618 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3619 gen_rtx_REG (Pmode, T0_REGNUM));
3620 }
3621 }
3622 DONE;
3623 })
3624
3625 (define_insn "sibcall_value_internal"
3626 [(set (match_operand 0 "register_operand" "")
3627 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3628 (match_operand 2 "" "")))]
3629 "SIBLING_CALL_P (insn)"
3630 {
3631 switch (which_alternative)
3632 {
3633 case 0:
3634 return "jr\t%1";
3635 case 1:
3636 if (TARGET_CMODEL_MEDIUM)
3637 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3638 else
3639 return "b\t%1";
3640 case 2:
3641 if (TARGET_CMODEL_MEDIUM)
3642 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3643 else
3644 return "b\t%%plt(%1)";
3645 default:
3646 gcc_unreachable ();
3647 }
3648 }
3649 [(set_attr "jirl" "indirect,direct,direct")])
3650
3651 (define_insn "@sibcall_value_internal_1<mode>"
3652 [(set (match_operand 0 "register_operand" "")
3653 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3654 (match_operand:P 2 "symbolic_operand" "")))
3655 (match_operand 3 "" "")))]
3656 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3657 "jirl\t$r0,%1,%%pc_lo12(%2)"
3658 [(set_attr "jirl" "indirect")])
3659
3660 (define_insn "sibcall_value_multiple_internal"
3661 [(set (match_operand 0 "register_operand" "")
3662 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3663 (match_operand 2 "" "")))
3664 (set (match_operand 3 "register_operand" "")
3665 (call (mem:SI (match_dup 1))
3666 (match_dup 2)))]
3667 "SIBLING_CALL_P (insn)"
3668 {
3669 switch (which_alternative)
3670 {
3671 case 0:
3672 return "jr\t%1";
3673 case 1:
3674 if (TARGET_CMODEL_MEDIUM)
3675 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3676 else
3677 return "b\t%1";
3678 case 2:
3679 if (TARGET_CMODEL_MEDIUM)
3680 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3681 else
3682 return "b\t%%plt(%1)";
3683 default:
3684 gcc_unreachable ();
3685 }
3686 }
3687 [(set_attr "jirl" "indirect,direct,direct")])
3688
3689 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3690 [(set (match_operand 0 "register_operand" "")
3691 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3692 (match_operand:P 2 "symbolic_operand" "")]
3693 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3694 (match_operand 3 "" "")))
3695 (set (match_operand 4 "register_operand" "")
3696 (call (mem:P (unspec:P [(match_dup 1)
3697 (match_dup 2)]
3698 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3699 (match_dup 3)))]
3700 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3701 "jirl\t$r0,%1,%%pc_lo12(%2)"
3702 [(set_attr "jirl" "indirect")])
3703
3704 (define_expand "call"
3705 [(parallel [(call (match_operand 0 "")
3706 (match_operand 1 ""))
3707 (use (match_operand 2 "")) ;; next_arg_reg
3708 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3709 ""
3710 {
3711 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3712
3713 if (GET_CODE (target) == LO_SUM)
3714 emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3715 XEXP (target, 1), operands[1]));
3716 else
3717 emit_call_insn (gen_call_internal (target, operands[1]));
3718 DONE;
3719 })
3720
3721 (define_insn "call_internal"
3722 [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3723 (match_operand 1 "" ""))
3724 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3725 ""
3726 {
3727 switch (which_alternative)
3728 {
3729 case 0:
3730 return "jirl\t$r1,%0,0";
3731 case 1:
3732 if (TARGET_CMODEL_MEDIUM)
3733 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3734 else
3735 return "bl\t%0";
3736 case 2:
3737 if (TARGET_CMODEL_MEDIUM)
3738 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3739 else
3740 return "bl\t%%plt(%0)";
3741 default:
3742 gcc_unreachable ();
3743 }
3744 }
3745 [(set_attr "jirl" "indirect,direct,direct")])
3746
3747 (define_insn "@call_internal_1<mode>"
3748 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3749 (match_operand:P 1 "symbolic_operand" "")))
3750 (match_operand 2 "" ""))
3751 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3752 "TARGET_CMODEL_MEDIUM"
3753 "jirl\t$r1,%0,%%pc_lo12(%1)"
3754 [(set_attr "jirl" "indirect")])
3755
3756 (define_expand "call_value"
3757 [(parallel [(set (match_operand 0 "")
3758 (call (match_operand 1 "")
3759 (match_operand 2 "")))
3760 (use (match_operand 3 ""))])] ;; next_arg_reg
3761 ""
3762 {
3763 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3764 /* Handle return values created by loongarch_pass_fpr_pair. */
3765 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3766 {
3767 rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
3768 rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
3769
3770 if (GET_CODE (target) == LO_SUM)
3771 emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
3772 XEXP (target, 0),
3773 XEXP (target, 1),
3774 operands[2], arg2));
3775 else
3776 emit_call_insn (gen_call_value_multiple_internal (arg1, target,
3777 operands[2], arg2));
3778 }
3779 else
3780 {
3781 /* Handle return values created by loongarch_return_fpr_single. */
3782 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3783 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3784
3785 if (GET_CODE (target) == LO_SUM)
3786 emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
3787 XEXP (target, 0),
3788 XEXP (target, 1),
3789 operands[2]));
3790 else
3791 emit_call_insn (gen_call_value_internal (operands[0], target,
3792 operands[2]));
3793 }
3794 DONE;
3795 })
3796
3797 (define_insn "call_value_internal"
3798 [(set (match_operand 0 "register_operand" "")
3799 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3800 (match_operand 2 "" "")))
3801 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3802 ""
3803 {
3804 switch (which_alternative)
3805 {
3806 case 0:
3807 return "jirl\t$r1,%1,0";
3808 case 1:
3809 if (TARGET_CMODEL_MEDIUM)
3810 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3811 else
3812 return "bl\t%1";
3813 case 2:
3814 if (TARGET_CMODEL_MEDIUM)
3815 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3816 else
3817 return "bl\t%%plt(%1)";
3818 default:
3819 gcc_unreachable ();
3820 }
3821 }
3822 [(set_attr "jirl" "indirect,direct,direct")])
3823
3824 (define_insn "@call_value_internal_1<mode>"
3825 [(set (match_operand 0 "register_operand" "")
3826 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3827 (match_operand:P 2 "symbolic_operand" "")))
3828 (match_operand 3 "" "")))
3829 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3830 "TARGET_CMODEL_MEDIUM"
3831 "jirl\t$r1,%1,%%pc_lo12(%2)"
3832 [(set_attr "jirl" "indirect")])
3833
3834 (define_insn "call_value_multiple_internal"
3835 [(set (match_operand 0 "register_operand" "")
3836 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3837 (match_operand 2 "" "")))
3838 (set (match_operand 3 "register_operand" "")
3839 (call (mem:SI (match_dup 1))
3840 (match_dup 2)))
3841 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3842 ""
3843 {
3844 switch (which_alternative)
3845 {
3846 case 0:
3847 return "jirl\t$r1,%1,0";
3848 case 1:
3849 if (TARGET_CMODEL_MEDIUM)
3850 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3851 else
3852 return "bl\t%1";
3853 case 2:
3854 if (TARGET_CMODEL_MEDIUM)
3855 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3856 else
3857 return "bl\t%%plt(%1)";
3858 default:
3859 gcc_unreachable ();
3860 }
3861 }
3862 [(set_attr "jirl" "indirect,direct,direct")])
3863
3864 (define_insn "@call_value_multiple_internal_1<mode>"
3865 [(set (match_operand 0 "register_operand" "")
3866 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3867 (match_operand:P 2 "symbolic_operand" "")]
3868 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3869 (match_operand 3 "" "")))
3870 (set (match_operand 4 "register_operand" "")
3871 (call (mem:P (unspec:P [(match_dup 1)
3872 (match_dup 2)]
3873 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3874 (match_dup 3)))
3875 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3876 "TARGET_CMODEL_MEDIUM"
3877 "jirl\t$r1,%1,%%pc_lo12(%2)"
3878 [(set_attr "jirl" "indirect")])
3879
3880
3881 ;; Call subroutine returning any type.
3882 (define_expand "untyped_call"
3883 [(parallel [(call (match_operand 0 "")
3884 (const_int 0))
3885 (match_operand 1 "")
3886 (match_operand 2 "")])]
3887 ""
3888 {
3889 int i;
3890
3891 emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
3892
3893 for (i = 0; i < XVECLEN (operands[2], 0); i++)
3894 {
3895 rtx set = XVECEXP (operands[2], 0, i);
3896 loongarch_emit_move (SET_DEST (set), SET_SRC (set));
3897 }
3898
3899 emit_insn (gen_blockage ());
3900 DONE;
3901 })
3902 \f
3903 ;;
3904 ;; ....................
3905 ;;
3906 ;; MISC.
3907 ;;
3908 ;; ....................
3909 ;;
3910
3911 (define_insn "prefetch"
3912 [(prefetch (match_operand 0 "address_operand" "ZD")
3913 (match_operand 1 "const_int_operand" "n")
3914 (match_operand 2 "const_int_operand" "n"))]
3915 ""
3916 {
3917 switch (INTVAL (operands[1]))
3918 {
3919 case 0: return "preld\t0,%a0";
3920 case 1: return "preld\t8,%a0";
3921 default: gcc_unreachable ();
3922 }
3923 })
3924
3925 (define_insn "nop"
3926 [(const_int 0)]
3927 ""
3928 "nop"
3929 [(set_attr "type" "nop")
3930 (set_attr "mode" "none")])
3931
3932 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
3933 (define_insn "loongarch_movfcsr2gr"
3934 [(set (match_operand:SI 0 "register_operand" "=r")
3935 (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
3936 UNSPECV_MOVFCSR2GR))]
3937 "TARGET_HARD_FLOAT"
3938 "movfcsr2gr\t%0,$r%1")
3939
3940 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
3941 (define_insn "loongarch_movgr2fcsr"
3942 [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
3943 (match_operand:SI 1 "register_operand" "r")]
3944 UNSPECV_MOVGR2FCSR)]
3945 "TARGET_HARD_FLOAT"
3946 "movgr2fcsr\t$r%0,%1")
3947
3948 (define_insn "fclass_<fmt>"
3949 [(set (match_operand:ANYF 0 "register_operand" "=f")
3950 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
3951 UNSPEC_FCLASS))]
3952 "TARGET_HARD_FLOAT"
3953 "fclass.<fmt>\t%0,%1"
3954 [(set_attr "type" "unknown")
3955 (set_attr "mode" "<MODE>")])
3956
3957 (define_insn "bytepick_w_<bytepick_imm>"
3958 [(set (match_operand:SI 0 "register_operand" "=r")
3959 (ior:SI (lshiftrt (match_operand:SI 1 "register_operand" "r")
3960 (const_int <bytepick_w_lshiftrt_amount>))
3961 (ashift (match_operand:SI 2 "register_operand" "r")
3962 (const_int bytepick_w_ashift_amount))))]
3963 ""
3964 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
3965 [(set_attr "mode" "SI")])
3966
3967 (define_insn "bytepick_w_<bytepick_imm>_extend"
3968 [(set (match_operand:DI 0 "register_operand" "=r")
3969 (sign_extend:DI
3970 (ior:SI (lshiftrt (match_operand:SI 1 "register_operand" "r")
3971 (const_int <bytepick_w_lshiftrt_amount>))
3972 (ashift (match_operand:SI 2 "register_operand" "r")
3973 (const_int bytepick_w_ashift_amount)))))]
3974 "TARGET_64BIT"
3975 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
3976 [(set_attr "mode" "SI")])
3977
3978 (define_insn "bytepick_d_<bytepick_imm>"
3979 [(set (match_operand:DI 0 "register_operand" "=r")
3980 (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
3981 (const_int <bytepick_d_lshiftrt_amount>))
3982 (ashift (match_operand:DI 2 "register_operand" "r")
3983 (const_int bytepick_d_ashift_amount))))]
3984 "TARGET_64BIT"
3985 "bytepick.d\t%0,%1,%2,<bytepick_imm>"
3986 [(set_attr "mode" "DI")])
3987
3988 (define_insn "bitrev_4b"
3989 [(set (match_operand:SI 0 "register_operand" "=r")
3990 (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
3991 UNSPEC_BITREV_4B))]
3992 ""
3993 "bitrev.4b\t%0,%1"
3994 [(set_attr "type" "unknown")
3995 (set_attr "mode" "SI")])
3996
3997 (define_insn "bitrev_8b"
3998 [(set (match_operand:DI 0 "register_operand" "=r")
3999 (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4000 UNSPEC_BITREV_8B))]
4001 ""
4002 "bitrev.8b\t%0,%1"
4003 [(set_attr "type" "unknown")
4004 (set_attr "mode" "DI")])
4005
4006 (define_insn "@stack_tie<mode>"
4007 [(set (mem:BLK (scratch))
4008 (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4009 (match_operand:X 1 "register_operand" "r")]
4010 UNSPEC_TIE))]
4011 ""
4012 ""
4013 [(set_attr "length" "0")
4014 (set_attr "type" "ghost")])
4015
4016 ;; Named pattern for expanding thread pointer reference.
4017 (define_expand "get_thread_pointer<mode>"
4018 [(set (match_operand:P 0 "register_operand" "=r")
4019 (reg:P TP_REGNUM))]
4020 "HAVE_AS_TLS"
4021 {})
4022 \f
4023 (define_split
4024 [(match_operand 0 "small_data_pattern")]
4025 "reload_completed"
4026 [(match_dup 0)]
4027 { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4028
4029
4030 ;; Match paired HI/SI/SF/DFmode load/stores.
4031 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4032 [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4033 "=&r,f,m,m,&r,ZC")
4034 (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4035 (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4036 "=r,f,m,m,r,ZC")
4037 (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4038 "reload_completed"
4039 {
4040 /* The load destination does not overlap the source. */
4041 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4042 output_asm_insn (loongarch_output_move (operands[0], operands[1]),
4043 operands);
4044 output_asm_insn (loongarch_output_move (operands[2], operands[3]),
4045 &operands[2]);
4046 return "";
4047 }
4048 [(set_attr "move_type"
4049 "load,fpload,store,fpstore,load,store")
4050 (set_attr "insn_count" "2,2,2,2,2,2")])
4051
4052 ;; 2 HI/SI/SF/DF loads are bonded.
4053 (define_peephole2
4054 [(set (match_operand:JOIN_MODE 0 "register_operand")
4055 (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4056 (set (match_operand:JOIN_MODE 2 "register_operand")
4057 (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4058 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4059 [(parallel [(set (match_dup 0)
4060 (match_dup 1))
4061 (set (match_dup 2)
4062 (match_dup 3))])]
4063 "")
4064
4065 ;; 2 HI/SI/SF/DF stores are bonded.
4066 (define_peephole2
4067 [(set (match_operand:JOIN_MODE 0 "memory_operand")
4068 (match_operand:JOIN_MODE 1 "register_operand"))
4069 (set (match_operand:JOIN_MODE 2 "memory_operand")
4070 (match_operand:JOIN_MODE 3 "register_operand"))]
4071 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4072 [(parallel [(set (match_dup 0)
4073 (match_dup 1))
4074 (set (match_dup 2)
4075 (match_dup 3))])]
4076 "")
4077
4078 ;; Match paired HImode loads.
4079 (define_insn "*join2_loadhi"
4080 [(set (match_operand:SI 0 "register_operand" "=&r")
4081 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4082 (set (match_operand:SI 2 "register_operand" "=r")
4083 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4084 "reload_completed"
4085 {
4086 /* The load destination does not overlap the source. */
4087 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4088 output_asm_insn ("ld.h<u>\t%0,%1", operands);
4089 output_asm_insn ("ld.h<u>\t%2,%3", operands);
4090
4091 return "";
4092 }
4093 [(set_attr "move_type" "load")
4094 (set_attr "insn_count" "2")])
4095
4096
4097 ;; 2 HI loads are bonded.
4098 (define_peephole2
4099 [(set (match_operand:SI 0 "register_operand")
4100 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4101 (set (match_operand:SI 2 "register_operand")
4102 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4103 "loongarch_load_store_bonding_p (operands, HImode, true)"
4104 [(parallel [(set (match_dup 0)
4105 (any_extend:SI (match_dup 1)))
4106 (set (match_dup 2)
4107 (any_extend:SI (match_dup 3)))])]
4108 "")
4109
4110
4111
4112 (define_mode_iterator QHSD [QI HI SI DI])
4113
4114 (define_insn "loongarch_crc_w_<size>_w"
4115 [(set (match_operand:SI 0 "register_operand" "=r")
4116 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4117 (match_operand:SI 2 "register_operand" "r")]
4118 UNSPEC_CRC))]
4119 ""
4120 "crc.w.<size>.w\t%0,%1,%2"
4121 [(set_attr "type" "unknown")
4122 (set_attr "mode" "<MODE>")])
4123
4124 (define_insn "loongarch_crcc_w_<size>_w"
4125 [(set (match_operand:SI 0 "register_operand" "=r")
4126 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4127 (match_operand:SI 2 "register_operand" "r")]
4128 UNSPEC_CRCC))]
4129 ""
4130 "crcc.w.<size>.w\t%0,%1,%2"
4131 [(set_attr "type" "unknown")
4132 (set_attr "mode" "<MODE>")])
4133
4134 ;; With normal or medium code models, if the only use of a pc-relative
4135 ;; address is for loading or storing a value, then relying on linker
4136 ;; relaxation is not better than emitting the machine instruction directly.
4137 ;; Even if the la.local pseudo op can be relaxed, we get:
4138 ;;
4139 ;; pcaddi $t0, %pcrel_20(x)
4140 ;; ld.d $t0, $t0, 0
4141 ;;
4142 ;; There are still two instructions, same as using the machine instructions
4143 ;; and explicit relocs:
4144 ;;
4145 ;; pcalau12i $t0, %pc_hi20(x)
4146 ;; ld.d $t0, $t0, %pc_lo12(x)
4147 ;;
4148 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4149 ;; 3 instructions).
4150 (define_insn_and_rewrite "simple_load<mode>"
4151 [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4152 (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4153 "loongarch_pre_reload_split ()
4154 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4155 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4156 "#"
4157 "&& true"
4158 {
4159 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4160 })
4161
4162 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4163 [(set (match_operand:GPR 0 "register_operand" "=r")
4164 (any_extend:GPR
4165 (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4166 "loongarch_pre_reload_split ()
4167 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4168 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4169 "#"
4170 "&& true"
4171 {
4172 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4173 })
4174
4175 (define_insn_and_rewrite "simple_store<mode>"
4176 [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4177 (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4178 "loongarch_pre_reload_split ()
4179 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4180 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4181 "#"
4182 "&& true"
4183 {
4184 operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4185 })
4186
4187 ;; Synchronization instructions.
4188
4189 (include "sync.md")
4190
4191 (include "generic.md")
4192 (include "la464.md")
4193
4194 ; The LoongArch SIMD Instructions.
4195 (include "simd.md")
4196
4197 (define_c_enum "unspec" [
4198 UNSPEC_ADDRESS_FIRST
4199 ])