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