1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 ;; Contributed by Loongson Ltd.
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3. If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23 ;; Integer operations that are too cumbersome to describe directly.
28 ;; Floating-point moves.
35 ;; Floating point unspecs.
46 ;; Override return address for exception handling.
76 UNSPEC_ADD_TLS_LE_RELAX
83 ;; Fake div.w[u] mod.w[u]
86 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
87 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
90 (define_c_enum "unspecv" [
91 ;; Blockage and synchronisation.
96 ;; Privileged instructions
108 UNSPECV_PROBE_STACK_RANGE
110 ;; Floating-point environment.
123 [(RETURN_ADDR_REGNUM 1)
129 ;; Return path styles
134 ;; PIC long branch sequences are never longer than 100 bytes.
135 (MAX_PIC_BRANCH_LENGTH 100)
138 (include "predicates.md")
139 (include "constraints.md")
141 ;; ....................
145 ;; ....................
147 (define_attr "enabled" "no,yes" (const_string "yes"))
149 (define_attr "got" "unset,load"
150 (const_string "unset"))
152 ;; For jirl instructions, this attribute is DIRECT when the target address
153 ;; is symbolic and INDIRECT when it is a register.
154 (define_attr "jirl" "unset,direct,indirect"
155 (const_string "unset"))
158 ;; Classification of moves, extensions and truncations. Most values
159 ;; are as for "type" (see below) but there are also the following
160 ;; move-specific values:
162 ;; sll0 "slli.w DEST,SRC,0", which on 64-bit targets is guaranteed
163 ;; to produce a sign-extended DEST, even if SRC is not
164 ;; properly sign-extended
165 ;; pick_ins BSTRPICK.W, BSTRPICK.D, BSTRINS.W or BSTRINS.D instruction
166 ;; andi a single ANDI instruction
167 ;; shift_shift a shift left followed by a shift right
169 ;; This attribute is used to determine the instruction's length and
170 ;; scheduling type. For doubleword moves, the attribute always describes
171 ;; the split instructions; in some cases, it is more appropriate for the
172 ;; scheduling type to be "multi" instead.
173 (define_attr "move_type"
174 "unknown,load,fpload,store,fpstore,mgtf,mftg,imul,move,fmove,
175 const,signext,pick_ins,logical,arith,sll0,andi,shift_shift"
176 (const_string "unknown"))
178 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor,simd_add"
179 (const_string "unknown"))
181 ;; Main data type used by the insn
182 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FCC,
183 V2DI,V4SI,V8HI,V16QI,V2DF,V4SF,V4DI,V8SI,V16HI,V32QI,V4DF,V8SF"
184 (const_string "unknown"))
186 ;; True if the main data type is twice the size of a word.
187 (define_attr "dword_mode" "no,yes"
188 (cond [(and (eq_attr "mode" "DI,DF")
189 (not (match_test "TARGET_64BIT")))
192 (and (eq_attr "mode" "TI,TF")
193 (match_test "TARGET_64BIT"))
194 (const_string "yes")]
195 (const_string "no")))
197 ;; True if the main data type is four times of the size of a word.
198 (define_attr "qword_mode" "no,yes"
199 (cond [(and (eq_attr "mode" "TI,TF")
200 (not (match_test "TARGET_64BIT")))
201 (const_string "yes")]
202 (const_string "no")))
204 ;; Classification of each insn.
205 ;; branch conditional branch
206 ;; jump unconditional jump
207 ;; call unconditional call
208 ;; load load instruction(s)
209 ;; fpload floating point load
210 ;; fpidxload floating point indexed load
211 ;; store store instruction(s)
212 ;; fpstore floating point store
213 ;; fpidxstore floating point indexed store
214 ;; prefetch memory prefetch (register + offset)
215 ;; prefetchx memory indexed prefetch (register + register)
216 ;; condmove conditional moves
217 ;; mgtf move general-purpose register to floating point register
218 ;; mftg move floating point register to general-purpose register
219 ;; const load constant
220 ;; arith integer arithmetic instructions
221 ;; logical integer logical instructions
222 ;; shift integer shift instructions
223 ;; slt set less than instructions
224 ;; signext sign extend instructions
225 ;; clz the clz and clo instructions
226 ;; trap trap if instructions
227 ;; imul integer multiply
228 ;; idiv integer divide
230 ;; fmove floating point register move
231 ;; fadd floating point add/subtract
232 ;; fmul floating point multiply
233 ;; fmadd floating point multiply-add
234 ;; fdiv floating point divide
235 ;; frdiv floating point reciprocal divide
236 ;; frecipe floating point approximate reciprocal
237 ;; fabs floating point absolute value
238 ;; flogb floating point exponent extract
239 ;; fneg floating point negation
240 ;; fcmp floating point compare
241 ;; fcopysign floating point copysign
242 ;; fcvt floating point convert
243 ;; fscaleb floating point scale
244 ;; fsqrt floating point square root
245 ;; frsqrt floating point reciprocal square root
246 ;; frsqrte floating point approximate reciprocal square root
247 ;; multi multiword sequence (or user asm statements)
248 ;; atomic atomic memory update instruction
249 ;; syncloop memory atomic operation implemented as a sync loop
251 ;; ghost an instruction that produces no real code
253 "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
254 prefetch,prefetchx,condmove,mgtf,mftg,const,arith,logical,
255 shift,slt,signext,clz,trap,imul,idiv,move,
256 fmove,fadd,fmul,fmadd,fdiv,frdiv,frecipe,fabs,flogb,fneg,fcmp,fcopysign,fcvt,
257 fscaleb,fsqrt,frsqrt,frsqrte,accext,accmod,multi,atomic,syncloop,nop,ghost,
258 simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
259 simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
260 simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
261 simd_permute,simd_shf,simd_sat,simd_pcnt,simd_copy,simd_branch,simd_clsx,
262 simd_fminmax,simd_logic,simd_move,simd_load,simd_store"
263 (cond [(eq_attr "jirl" "!unset") (const_string "call")
264 (eq_attr "got" "load") (const_string "load")
266 (eq_attr "alu_type" "add,sub") (const_string "arith")
268 (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical")
270 ;; If a doubleword move uses these expensive instructions,
271 ;; it is usually better to schedule them in the same way
272 ;; as the singleword form, rather than as "multi".
273 (eq_attr "move_type" "load") (const_string "load")
274 (eq_attr "move_type" "fpload") (const_string "fpload")
275 (eq_attr "move_type" "store") (const_string "store")
276 (eq_attr "move_type" "fpstore") (const_string "fpstore")
277 (eq_attr "move_type" "mgtf") (const_string "mgtf")
278 (eq_attr "move_type" "mftg") (const_string "mftg")
280 ;; These types of move are always single insns.
281 (eq_attr "move_type" "imul") (const_string "imul")
282 (eq_attr "move_type" "fmove") (const_string "fmove")
283 (eq_attr "move_type" "signext") (const_string "signext")
284 (eq_attr "move_type" "pick_ins") (const_string "arith")
285 (eq_attr "move_type" "arith") (const_string "arith")
286 (eq_attr "move_type" "logical") (const_string "logical")
287 (eq_attr "move_type" "sll0") (const_string "shift")
288 (eq_attr "move_type" "andi") (const_string "logical")
290 ;; These types of move are always split.
291 (eq_attr "move_type" "shift_shift")
292 (const_string "multi")
294 ;; These types of move are split for quadword modes only.
295 (and (eq_attr "move_type" "move,const")
296 (eq_attr "qword_mode" "yes"))
297 (const_string "multi")
299 ;; These types of move are split for doubleword modes only.
300 (and (eq_attr "move_type" "move,const")
301 (eq_attr "dword_mode" "yes"))
302 (const_string "multi")
303 (eq_attr "move_type" "move") (const_string "move")
304 (eq_attr "move_type" "const") (const_string "const")]
305 (const_string "unknown")))
307 ;; Mode for conversion types (fcvt)
308 ;; I2S integer to float single (SI/DI to SF)
309 ;; I2D integer to float double (SI/DI to DF)
310 ;; S2I float to integer (SF to SI/DI)
311 ;; D2I float to integer (DF to SI/DI)
312 ;; D2S double to float single
313 ;; S2D float single to double
315 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
316 (const_string "unknown"))
318 ;; The number of individual instructions that a non-branch pattern generates
319 (define_attr "insn_count" ""
320 (cond [;; "Ghost" instructions occupy no space.
321 (eq_attr "type" "ghost")
324 ;; Check for doubleword moves that are decomposed into two
326 (and (eq_attr "move_type" "mgtf,mftg,move")
327 (eq_attr "dword_mode" "yes"))
330 ;; Check for quadword moves that are decomposed into four
332 (and (eq_attr "move_type" "mgtf,mftg,move")
333 (eq_attr "qword_mode" "yes"))
336 ;; Constants, loads and stores are handled by external routines.
337 (and (eq_attr "move_type" "const")
338 (eq_attr "dword_mode" "yes"))
339 (symbol_ref "loongarch_split_const_insns (operands[1])")
340 (eq_attr "move_type" "const")
341 (symbol_ref "loongarch_const_insns (operands[1])")
342 (eq_attr "move_type" "load,fpload")
343 (symbol_ref "loongarch_load_store_insns (operands[1], insn)")
344 (eq_attr "move_type" "store,fpstore")
345 (symbol_ref "loongarch_load_store_insns (operands[0], insn)")
347 (eq_attr "type" "idiv")
348 (symbol_ref "loongarch_idiv_insns (GET_MODE (PATTERN (insn)))")]
351 ;; Length of instruction in bytes.
352 (define_attr "length" ""
354 ;; Branch futher than +/- 128 KiB require two instructions.
355 (eq_attr "type" "branch")
356 (if_then_else (and (le (minus (match_dup 0) (pc)) (const_int 131064))
357 (le (minus (pc) (match_dup 0)) (const_int 131068)))
360 (symbol_ref "get_attr_insn_count (insn) * 4")))
362 ;; Describe a user's asm statement.
363 (define_asm_attributes
364 [(set_attr "type" "multi")])
366 ;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
367 ;; from the same template.
368 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
370 ;; A copy of GPR that can be used when a pattern has two independent
372 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
374 ;; This mode iterator allows 16-bit and 32-bit GPR patterns and 32-bit 64-bit
375 ;; FPR patterns to be generated from the same template.
376 (define_mode_iterator JOIN_MODE [HI
378 (SF "TARGET_HARD_FLOAT")
379 (DF "TARGET_DOUBLE_FLOAT")])
381 ;; This mode iterator allows :P to be used for patterns that operate on
382 ;; pointer-sized quantities. Exactly one of the two alternatives will match.
383 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
385 ;; Likewise, but for GRLEN-sized quantities.
386 (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
388 ;; 64-bit modes for which we provide move patterns.
389 (define_mode_iterator MOVE64 [DI DF])
391 ;; 128-bit modes for which we provide move patterns on 64-bit targets.
392 (define_mode_iterator MOVE128 [TI TF])
394 ;; Iterator for sub-32-bit integer modes.
395 (define_mode_iterator SHORT [QI HI])
397 ;; Likewise the 64-bit truncate-and-shift patterns.
398 (define_mode_iterator SUBDI [QI HI SI])
400 ;; Iterator for scalar fixed point modes.
401 (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
403 ;; Iterator for hardware-supported floating-point modes.
404 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
405 (DF "TARGET_DOUBLE_FLOAT")])
407 ;; Iterator for fixed-point modes which can be hold by a hardware
408 ;; floating-point register.
409 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
410 (DI "TARGET_DOUBLE_FLOAT")])
412 ;; A mode for which moves involving FPRs may need to be split.
413 (define_mode_iterator SPLITF
414 [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
415 (DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
416 (TF "TARGET_64BIT && TARGET_DOUBLE_FLOAT")])
418 ;; A mode for anything with 32 bits or more, and able to be loaded with
419 ;; the same addressing mode as ld.w.
420 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
422 ;; A mode for anything able to be stored with the same addressing mode as
424 (define_mode_iterator ST_ANY [QHWD ANYF])
426 ;; A mode for anything legal as a input of a div or mod instruction.
427 (define_mode_iterator DIV [(DI "TARGET_64BIT")
428 (SI "!TARGET_64BIT || TARGET_DIV32")])
430 ;; In GPR templates, a string like "mul.<d>" will expand to "mul.w" in the
431 ;; 32-bit version and "mul.d" in the 64-bit version.
432 (define_mode_attr d [(SI "w") (DI "d")])
434 ;; This attribute gives the length suffix for a load or store instruction.
435 ;; The same suffixes work for zero and sign extensions.
436 (define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")])
437 (define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")])
439 ;; This attribute gives the mode mask of a SHORT.
440 (define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
442 ;; This attribute gives the size (bits) of a SHORT.
443 (define_mode_attr 7_or_15 [(QI "7") (HI "15")])
445 ;; Instruction names for stores.
446 (define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
448 ;; This attribute gives the format suffix for floating-point operations.
449 (define_mode_attr fmt [(SF "s") (DF "d")])
450 (define_mode_attr ifmt [(SI "w") (DI "l")])
452 ;; This attribute gives the upper-case mode name for one unit of a
453 ;; floating-point mode or vector mode.
454 (define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF") (V4SF "SF")
455 (V16QI "QI") (V8HI "HI") (V4SI "SI") (V2DI "DI")
456 (V2DF "DF")(V8SF "SF")(V32QI "QI")(V16HI "HI")(V8SI "SI")(V4DI "DI")(V4DF "DF")])
458 ;; As above, but in lower case.
459 (define_mode_attr unitmode [(SF "sf") (DF "df") (V2SF "sf") (V4SF "sf")
460 (V16QI "qi") (V8QI "qi") (V8HI "hi") (V4HI "hi")
461 (V4SI "si") (V2SI "si") (V2DI "di") (V2DF "df")
462 (V8SI "si") (V4DI "di") (V32QI "qi") (V16HI "hi")
463 (V8SF "sf") (V4DF "df")])
465 ;; This attribute gives the integer mode that has half the size of
466 ;; the controlling mode.
467 (define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
468 (V2SI "SI") (V4HI "SI") (V8QI "SI")
471 ;; This attribute gives the integer mode that has the same size of a
472 ;; floating-point mode.
473 (define_mode_attr IMODE [(SF "SI") (DF "DI")])
475 ;; This code iterator allows signed and unsigned widening multiplications
476 ;; to use the same template.
477 (define_code_iterator any_extend [sign_extend zero_extend])
479 ;; This code iterator allows the two right shift instructions to be
480 ;; generated from the same template.
481 (define_code_iterator any_shiftrt [ashiftrt lshiftrt])
483 ;; This code iterator allows the three shift instructions to be generated
484 ;; from the same template.
485 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
487 ;; This code iterator allows the three bitwise instructions to be generated
488 ;; from the same template.
489 (define_code_iterator any_bitwise [and ior xor])
490 (define_code_iterator neg_bitwise [and ior])
492 ;; This code iterator allows unsigned and signed division to be generated
493 ;; from the same template.
494 (define_code_iterator any_div [div udiv mod umod])
496 ;; This code iterator allows addition and subtraction to be generated
497 ;; from the same template.
498 (define_code_iterator addsub [plus minus])
500 ;; This code iterator allows addition and multiplication to be generated
501 ;; from the same template.
502 (define_code_iterator addmul [plus mult])
504 ;; This code iterator allows addition subtraction and multiplication to be
505 ;; generated from the same template
506 (define_code_iterator addsubmul [plus minus mult])
508 ;; This code iterator allows all native floating-point comparisons to be
509 ;; generated from the same template.
510 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
511 ordered ltgt ne ge gt unge ungt])
513 ;; Equality operators.
514 (define_code_iterator equality_op [eq ne])
516 ;; These code iterators allow the signed and unsigned scc operations to use
517 ;; the same template.
518 (define_code_iterator any_gt [gt gtu])
519 (define_code_iterator any_ge [ge geu])
520 (define_code_iterator any_lt [lt ltu])
521 (define_code_iterator any_le [le leu])
523 (define_code_iterator any_return [return simple_return])
525 ;; <u> expands to an empty string when doing a signed operation and
526 ;; "u" when doing an unsigned operation.
527 (define_code_attr u [(sign_extend "") (zero_extend "u")
535 ;; <U> is like <u> except uppercase.
536 (define_code_attr U [(sign_extend "") (zero_extend "U")])
538 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
539 (define_code_attr su [(sign_extend "s") (zero_extend "u")])
541 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
543 ;; <optab> expands to the name of the optab for a particular code.
544 (define_code_attr optab [(ashift "ashl")
558 (simple_return "simple_return")])
560 ;; <insn> expands to the name of the insn that implements a particular code.
561 (define_code_attr insn [(ashift "sll")
574 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
575 (define_code_attr fcond [(unordered "cun")
590 ;; The sel mnemonic to use depending on the condition test.
591 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
592 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
594 ;; Iterator and attributes for floating-point to fixed-point conversion
596 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
597 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
598 (UNSPEC_FTINTRM "lfloor")
599 (UNSPEC_FTINTRP "lceil")])
600 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
601 (UNSPEC_FTINTRM "rm")
602 (UNSPEC_FTINTRP "rp")])
604 ;; Iterator and attributes for bytepick.d
605 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
606 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
609 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
610 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
617 (define_int_attr bytepick_imm [(8 "1")
626 ;; ....................
630 ;; ....................
634 [(trap_if (const_int 1) (const_int 0))]
639 [(set_attr "type" "trap")])
644 ;; ....................
648 ;; ....................
651 (define_insn "add<mode>3"
652 [(set (match_operand:ANYF 0 "register_operand" "=f")
653 (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
654 (match_operand:ANYF 2 "register_operand" "f")))]
656 "fadd.<fmt>\t%0,%1,%2"
657 [(set_attr "type" "fadd")
658 (set_attr "mode" "<UNITMODE>")])
660 (define_insn_and_split "add<mode>3"
661 [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r,r,r,r")
662 (plus:GPR (match_operand:GPR 1 "register_operand" "r,r,r,r,r,r,r")
663 (match_operand:GPR 2 "plus_<mode>_operand"
664 "r,I,La,Lb,Lc,Ld,Le")))]
670 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
671 return \"addu16i.d\t%0,%1,%2\";
675 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
676 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
677 [(set (match_dup 0) (plus:GPR (match_dup 1) (match_dup 3)))
678 (set (match_dup 0) (plus:GPR (match_dup 0) (match_dup 4)))]
680 loongarch_split_plus_constant (&operands[2], <MODE>mode);
682 [(set_attr "alu_type" "add")
683 (set_attr "mode" "<MODE>")
684 (set_attr "insn_count" "1,1,2,1,2,2,2")
685 (set (attr "enabled")
687 [(match_test "<MODE>mode != DImode && which_alternative == 4")
689 (match_test "<MODE>mode != DImode && which_alternative == 5")
691 (match_test "<MODE>mode != SImode && which_alternative == 6")
693 (const_string "yes")))])
695 (define_insn_and_split "*addsi3_extended"
696 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
698 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
699 (match_operand:SI 2 "plus_si_extend_operand"
707 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
708 [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
710 (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
713 loongarch_split_plus_constant (&operands[2], SImode);
715 [(set_attr "alu_type" "add")
716 (set_attr "mode" "SI")
717 (set_attr "insn_count" "1,1,2,2")])
721 ;; ....................
725 ;; ....................
728 (define_insn "sub<mode>3"
729 [(set (match_operand:ANYF 0 "register_operand" "=f")
730 (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
731 (match_operand:ANYF 2 "register_operand" "f")))]
733 "fsub.<fmt>\t%0,%1,%2"
734 [(set_attr "type" "fadd")
735 (set_attr "mode" "<UNITMODE>")])
737 (define_insn "sub<mode>3"
738 [(set (match_operand:GPR 0 "register_operand" "=r")
739 (minus:GPR (match_operand:GPR 1 "register_operand" "rJ")
740 (match_operand:GPR 2 "register_operand" "r")))]
743 [(set_attr "alu_type" "sub")
744 (set_attr "mode" "<MODE>")])
747 (define_insn "*subsi3_extended"
748 [(set (match_operand:DI 0 "register_operand" "=r")
750 (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
751 (match_operand:SI 2 "register_operand" "r"))))]
754 [(set_attr "type" "arith")
755 (set_attr "mode" "SI")])
758 ;; ....................
762 ;; ....................
765 (define_insn "mul<mode>3"
766 [(set (match_operand:ANYF 0 "register_operand" "=f")
767 (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
768 (match_operand:ANYF 2 "register_operand" "f")))]
770 "fmul.<fmt>\t%0,%1,%2"
771 [(set_attr "type" "fmul")
772 (set_attr "mode" "<MODE>")])
774 (define_insn "mul<mode>3"
775 [(set (match_operand:GPR 0 "register_operand" "=r")
776 (mult:GPR (match_operand:GPR 1 "register_operand" "r")
777 (match_operand:GPR 2 "register_operand" "r")))]
780 [(set_attr "type" "imul")
781 (set_attr "mode" "<MODE>")])
783 (define_insn "*mulsi3_extended"
784 [(set (match_operand:DI 0 "register_operand" "=r")
786 (mult:SI (match_operand:SI 1 "register_operand" "r")
787 (match_operand:SI 2 "register_operand" "r"))))]
790 [(set_attr "type" "imul")
791 (set_attr "mode" "SI")])
794 ;; ........................
796 ;; MULTIPLICATION HIGH-PART
798 ;; ........................
801 (define_expand "<u>mulditi3"
802 [(set (match_operand:TI 0 "register_operand")
803 (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
804 (any_extend:TI (match_operand:DI 2 "register_operand"))))]
807 rtx low = gen_reg_rtx (DImode);
808 emit_insn (gen_muldi3 (low, operands[1], operands[2]));
810 rtx high = gen_reg_rtx (DImode);
811 emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
813 emit_move_insn (gen_lowpart (DImode, operands[0]), low);
814 emit_move_insn (gen_highpart (DImode, operands[0]), high);
818 (define_insn "<su>muldi3_highpart"
819 [(set (match_operand:DI 0 "register_operand" "=r")
822 (mult:TI (any_extend:TI
823 (match_operand:DI 1 "register_operand" " r"))
825 (match_operand:DI 2 "register_operand" " r")))
828 "mulh.d<u>\t%0,%1,%2"
829 [(set_attr "type" "imul")
830 (set_attr "mode" "DI")])
832 (define_expand "<u>mulsidi3"
833 [(set (match_operand:DI 0 "register_operand")
834 (mult:DI (any_extend:DI
835 (match_operand:SI 1 "register_operand"))
837 (match_operand:SI 2 "register_operand"))))]
842 rtx temp = gen_reg_rtx (SImode);
843 emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
844 emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
845 operands[1], operands[2]));
846 emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
851 (define_insn "<u>mulsidi3_64bit"
852 [(set (match_operand:DI 0 "register_operand" "=r")
853 (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
854 (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
856 "mulw.d.w<u>\t%0,%1,%2"
857 [(set_attr "type" "imul")
858 (set_attr "mode" "DI")])
860 (define_insn "<su>mulsi3_highpart"
861 [(set (match_operand:SI 0 "register_operand" "=r")
864 (mult:DI (any_extend:DI
865 (match_operand:SI 1 "register_operand" " r"))
867 (match_operand:SI 2 "register_operand" " r")))
870 "mulh.w<u>\t%0,%1,%2"
871 [(set_attr "type" "imul")
872 (set_attr "mode" "SI")])
874 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
875 ;; sign extension by default, so the sign extension instruction can be
878 [(set (match_operand:SI 0 "register_operand")
881 (mult:DI (any_extend:DI
882 (match_operand:SI 1 "register_operand"))
884 (match_operand:SI 2 "register_operand")))
886 (set (match_operand:DI 3 "register_operand")
887 (sign_extend:DI (match_dup 0)))]
888 "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
889 "mulh.w<u>\t%0,%1,%2")
892 ;; ....................
894 ;; DIVISION and REMAINDER
896 ;; ....................
899 ;; Float division and modulus.
900 (define_expand "div<mode>3"
901 [(set (match_operand:ANYF 0 "register_operand")
902 (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
903 (match_operand:ANYF 2 "register_operand")))]
906 if (<MODE>mode == SFmode
908 && optimize_insn_for_speed_p ()
909 && flag_finite_math_only && !flag_trapping_math
910 && flag_unsafe_math_optimizations)
912 loongarch_emit_swdivsf (operands[0], operands[1],
913 operands[2], SFmode);
918 (define_insn "*div<mode>3"
919 [(set (match_operand:ANYF 0 "register_operand" "=f")
920 (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
921 (match_operand:ANYF 2 "register_operand" "f")))]
923 "fdiv.<fmt>\t%0,%1,%2"
924 [(set_attr "type" "fdiv")
925 (set_attr "mode" "<UNITMODE>")])
927 ;; In 3A5000, the reciprocal operation is the same as the division operation.
929 (define_insn "*recip<mode>3"
930 [(set (match_operand:ANYF 0 "register_operand" "=f")
931 (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
932 (match_operand:ANYF 2 "register_operand" "f")))]
934 "frecip.<fmt>\t%0,%2"
935 [(set_attr "type" "frdiv")
936 (set_attr "mode" "<UNITMODE>")])
938 ;; Approximate Reciprocal Instructions.
940 (define_insn "loongarch_frecipe_<fmt>"
941 [(set (match_operand:ANYF 0 "register_operand" "=f")
942 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
945 "frecipe.<fmt>\t%0,%1"
946 [(set_attr "type" "frecipe")
947 (set_attr "mode" "<UNITMODE>")
948 (set_attr "insn_count" "1")])
950 ;; Integer division and modulus.
951 (define_expand "<optab><mode>3"
952 [(set (match_operand:GPR 0 "register_operand")
953 (any_div:GPR (match_operand:GPR 1 "register_operand")
954 (match_operand:GPR 2 "register_operand")))]
957 if (GET_MODE (operands[0]) == SImode && TARGET_64BIT && !TARGET_DIV32)
959 rtx reg1 = gen_reg_rtx (DImode);
960 rtx reg2 = gen_reg_rtx (DImode);
961 rtx rd = gen_reg_rtx (DImode);
963 operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
964 operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
966 emit_insn (gen_rtx_SET (reg1, operands[1]));
967 emit_insn (gen_rtx_SET (reg2, operands[2]));
969 emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
970 emit_insn (gen_rtx_SET (operands[0],
971 simplify_gen_subreg (SImode, rd, DImode, 0)));
976 (define_insn "*<optab><mode>3"
977 [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
978 (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
979 (match_operand:DIV 2 "register_operand" "r,r,r")))]
982 return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
984 [(set_attr "type" "idiv")
985 (set_attr "mode" "<MODE>")
986 (set (attr "enabled")
988 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
990 (const_string "no")))])
992 (define_insn "<optab>si3_extended"
993 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
995 (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
996 (match_operand:SI 2 "register_operand" "r,r,r"))))]
997 "TARGET_64BIT && TARGET_DIV32"
999 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1001 [(set_attr "type" "idiv")
1002 (set_attr "mode" "SI")
1003 (set (attr "enabled")
1005 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1006 (const_string "yes")
1007 (const_string "no")))])
1009 (define_insn "<optab>di3_fake"
1010 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1014 (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1015 (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1016 UNSPEC_FAKE_ANY_DIV)))]
1017 "TARGET_64BIT && !TARGET_DIV32"
1019 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1021 [(set_attr "type" "idiv")
1022 (set_attr "mode" "SI")
1023 (set (attr "enabled")
1025 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1026 (const_string "yes")
1027 (const_string "no")))])
1029 ;; Floating point multiply accumulate instructions.
1032 (define_insn "fma<mode>4"
1033 [(set (match_operand:ANYF 0 "register_operand" "=f")
1034 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1035 (match_operand:ANYF 2 "register_operand" "f")
1036 (match_operand:ANYF 3 "register_operand" "f")))]
1038 "fmadd.<fmt>\t%0,%1,%2,%3"
1039 [(set_attr "type" "fmadd")
1040 (set_attr "mode" "<UNITMODE>")])
1043 (define_insn "fms<mode>4"
1044 [(set (match_operand:ANYF 0 "register_operand" "=f")
1045 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1046 (match_operand:ANYF 2 "register_operand" "f")
1047 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1049 "fmsub.<fmt>\t%0,%1,%2,%3"
1050 [(set_attr "type" "fmadd")
1051 (set_attr "mode" "<UNITMODE>")])
1053 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1054 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1055 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1056 ;; This transformation means we may return the wrong signed zero
1057 ;; so we check HONOR_SIGNED_ZEROS.
1060 (define_insn "fnma<mode>4"
1061 [(set (match_operand:ANYF 0 "register_operand" "=f")
1062 (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1063 (match_operand:ANYF 2 "register_operand" "f")
1064 (match_operand:ANYF 3 "register_operand" "f")))]
1065 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1066 "fnmsub.<fmt>\t%0,%1,%2,%3"
1067 [(set_attr "type" "fmadd")
1068 (set_attr "mode" "<UNITMODE>")])
1070 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1071 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1072 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1073 ;; This transformation means we may return the wrong signed zero
1074 ;; so we check HONOR_SIGNED_ZEROS.
1077 (define_insn "fnms<mode>4"
1078 [(set (match_operand:ANYF 0 "register_operand" "=f")
1080 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1081 (match_operand:ANYF 2 "register_operand" "f")
1082 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1083 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1084 "fnmadd.<fmt>\t%0,%1,%2,%3"
1085 [(set_attr "type" "fmadd")
1086 (set_attr "mode" "<UNITMODE>")])
1088 ;; -(-a * b - c), modulo signed zeros
1089 (define_insn "*fma<mode>4"
1090 [(set (match_operand:ANYF 0 "register_operand" "=f")
1093 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1094 (match_operand:ANYF 2 "register_operand" " f")
1095 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1096 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1097 "fmadd.<fmt>\t%0,%1,%2,%3"
1098 [(set_attr "type" "fmadd")
1099 (set_attr "mode" "<UNITMODE>")])
1101 ;; -(-a * b + c), modulo signed zeros
1102 (define_insn "*fms<mode>4"
1103 [(set (match_operand:ANYF 0 "register_operand" "=f")
1106 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1107 (match_operand:ANYF 2 "register_operand" " f")
1108 (match_operand:ANYF 3 "register_operand" " f"))))]
1109 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1110 "fmsub.<fmt>\t%0,%1,%2,%3"
1111 [(set_attr "type" "fmadd")
1112 (set_attr "mode" "<UNITMODE>")])
1115 (define_insn "*fnms<mode>4"
1116 [(set (match_operand:ANYF 0 "register_operand" "=f")
1119 (match_operand:ANYF 1 "register_operand" " f")
1120 (match_operand:ANYF 2 "register_operand" " f")
1121 (match_operand:ANYF 3 "register_operand" " f"))))]
1123 "fnmadd.<fmt>\t%0,%1,%2,%3"
1124 [(set_attr "type" "fmadd")
1125 (set_attr "mode" "<UNITMODE>")])
1128 (define_insn "*fnma<mode>4"
1129 [(set (match_operand:ANYF 0 "register_operand" "=f")
1132 (match_operand:ANYF 1 "register_operand" " f")
1133 (match_operand:ANYF 2 "register_operand" " f")
1134 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1136 "fnmsub.<fmt>\t%0,%1,%2,%3"
1137 [(set_attr "type" "fmadd")
1138 (set_attr "mode" "<UNITMODE>")])
1141 ;; ....................
1145 ;; ....................
1147 (define_expand "sqrt<mode>2"
1148 [(set (match_operand:ANYF 0 "register_operand")
1149 (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1152 if (<MODE>mode == SFmode
1153 && TARGET_RECIP_SQRT
1154 && flag_unsafe_math_optimizations
1155 && !optimize_insn_for_size_p ()
1156 && flag_finite_math_only && !flag_trapping_math)
1158 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1163 (define_insn "*sqrt<mode>2"
1164 [(set (match_operand:ANYF 0 "register_operand" "=f")
1165 (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1167 "fsqrt.<fmt>\t%0,%1"
1168 [(set_attr "type" "fsqrt")
1169 (set_attr "mode" "<UNITMODE>")
1170 (set_attr "insn_count" "1")])
1172 (define_expand "rsqrt<mode>2"
1173 [(set (match_operand:ANYF 0 "register_operand")
1174 (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1178 if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1180 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1185 (define_insn "*rsqrt<mode>2"
1186 [(set (match_operand:ANYF 0 "register_operand" "=f")
1187 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1190 "frsqrt.<fmt>\t%0,%1"
1191 [(set_attr "type" "frsqrt")
1192 (set_attr "mode" "<UNITMODE>")])
1194 ;; Approximate Reciprocal Square Root Instructions.
1196 (define_insn "loongarch_frsqrte_<fmt>"
1197 [(set (match_operand:ANYF 0 "register_operand" "=f")
1198 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1201 "frsqrte.<fmt>\t%0,%1"
1202 [(set_attr "type" "frsqrte")
1203 (set_attr "mode" "<UNITMODE>")])
1206 ;; ....................
1210 ;; ....................
1212 (define_insn "abs<mode>2"
1213 [(set (match_operand:ANYF 0 "register_operand" "=f")
1214 (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1217 [(set_attr "type" "fabs")
1218 (set_attr "mode" "<UNITMODE>")])
1221 ;; ....................
1223 ;; FLOATING POINT COPYSIGN
1225 ;; ....................
1227 (define_insn "copysign<mode>3"
1228 [(set (match_operand:ANYF 0 "register_operand" "=f")
1229 (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1230 (match_operand:ANYF 2 "register_operand" "f")))]
1232 "fcopysign.<fmt>\t%0,%1,%2"
1233 [(set_attr "type" "fcopysign")
1234 (set_attr "mode" "<UNITMODE>")])
1236 (define_expand "@xorsign<mode>3"
1237 [(match_operand:ANYF 0 "register_operand")
1238 (match_operand:ANYF 1 "register_operand")
1239 (match_operand:ANYF 2 "register_operand")]
1242 machine_mode lsx_mode
1243 = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1244 rtx tmp = gen_reg_rtx (lsx_mode);
1245 rtx op1 = lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1246 rtx op2 = lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1247 emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1248 emit_move_insn (operands[0],
1249 lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1254 ;; ....................
1256 ;; FLOATING POINT SCALE
1258 ;; ....................
1260 (define_insn "ldexp<mode>3"
1261 [(set (match_operand:ANYF 0 "register_operand" "=f")
1262 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")
1263 (match_operand:<IMODE> 2 "register_operand" "f")]
1266 "fscaleb.<fmt>\t%0,%1,%2"
1267 [(set_attr "type" "fscaleb")
1268 (set_attr "mode" "<UNITMODE>")])
1271 ;; ....................
1273 ;; FLOATING POINT EXPONENT EXTRACT
1275 ;; ....................
1277 (define_insn "logb_non_negative<mode>2"
1278 [(set (match_operand:ANYF 0 "register_operand" "=f")
1279 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1282 "flogb.<fmt>\t%0,%1"
1283 [(set_attr "type" "flogb")
1284 (set_attr "mode" "<UNITMODE>")])
1286 (define_expand "logb<mode>2"
1287 [(set (match_operand:ANYF 0 "register_operand")
1288 (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1292 rtx tmp = gen_reg_rtx (<MODE>mode);
1294 emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1295 emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1300 ;; ...................
1302 ;; Count leading zeroes.
1304 ;; ...................
1307 (define_insn "clz<mode>2"
1308 [(set (match_operand:GPR 0 "register_operand" "=r")
1309 (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1312 [(set_attr "type" "clz")
1313 (set_attr "mode" "<MODE>")])
1316 ;; ...................
1318 ;; Count trailing zeroes.
1320 ;; ...................
1323 (define_insn "ctz<mode>2"
1324 [(set (match_operand:GPR 0 "register_operand" "=r")
1325 (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1328 [(set_attr "type" "clz")
1329 (set_attr "mode" "<MODE>")])
1332 ;; ....................
1336 ;; ....................
1338 (define_insn "smax<mode>3"
1339 [(set (match_operand:ANYF 0 "register_operand" "=f")
1340 (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1341 (match_operand:ANYF 2 "register_operand" "f")))]
1343 "fmax.<fmt>\t%0,%1,%2"
1344 [(set_attr "type" "fmove")
1345 (set_attr "mode" "<MODE>")])
1347 (define_insn "smin<mode>3"
1348 [(set (match_operand:ANYF 0 "register_operand" "=f")
1349 (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1350 (match_operand:ANYF 2 "register_operand" "f")))]
1352 "fmin.<fmt>\t%0,%1,%2"
1353 [(set_attr "type" "fmove")
1354 (set_attr "mode" "<MODE>")])
1356 (define_insn "fmax<mode>3"
1357 [(set (match_operand:ANYF 0 "register_operand" "=f")
1358 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1359 (use (match_operand:ANYF 2 "register_operand" "f"))]
1362 "fmax.<fmt>\t%0,%1,%2"
1363 [(set_attr "type" "fmove")
1364 (set_attr "mode" "<MODE>")])
1366 (define_insn "fmin<mode>3"
1367 [(set (match_operand:ANYF 0 "register_operand" "=f")
1368 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1369 (use (match_operand:ANYF 2 "register_operand" "f"))]
1372 "fmin.<fmt>\t%0,%1,%2"
1373 [(set_attr "type" "fmove")
1374 (set_attr "mode" "<MODE>")])
1376 (define_insn "smaxa<mode>3"
1377 [(set (match_operand:ANYF 0 "register_operand" "=f")
1379 (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1380 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1384 "fmaxa.<fmt>\t%0,%1,%2"
1385 [(set_attr "type" "fmove")
1386 (set_attr "mode" "<MODE>")])
1388 (define_insn "smina<mode>3"
1389 [(set (match_operand:ANYF 0 "register_operand" "=f")
1391 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1392 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1396 "fmina.<fmt>\t%0,%1,%2"
1397 [(set_attr "type" "fmove")
1398 (set_attr "mode" "<MODE>")])
1401 ;; ....................
1403 ;; NEGATION and ONE'S COMPLEMENT
1405 ;; ....................
1407 (define_insn "neg<mode>2"
1408 [(set (match_operand:GPR 0 "register_operand" "=r")
1409 (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1412 [(set_attr "alu_type" "sub")
1413 (set_attr "mode" "<MODE>")])
1415 (define_insn "one_cmpl<mode>2"
1416 [(set (match_operand:GPR 0 "register_operand" "=r")
1417 (not:GPR (match_operand:GPR 1 "register_operand" "r")))]
1420 [(set_attr "alu_type" "not")
1421 (set_attr "mode" "<MODE>")])
1423 (define_insn "neg<mode>2"
1424 [(set (match_operand:ANYF 0 "register_operand" "=f")
1425 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1428 [(set_attr "type" "fneg")
1429 (set_attr "mode" "<UNITMODE>")])
1433 ;; ....................
1437 ;; ....................
1440 (define_insn "<optab><mode>3"
1441 [(set (match_operand:GPR 0 "register_operand" "=r,r")
1442 (any_bitwise:GPR (match_operand:GPR 1 "register_operand" "%r,r")
1443 (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
1445 "<insn>%i2\t%0,%1,%2"
1446 [(set_attr "type" "logical")
1447 (set_attr "mode" "<MODE>")])
1449 (define_insn "and<mode>3_extended"
1450 [(set (match_operand:GPR 0 "register_operand" "=r")
1451 (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "r")
1452 (match_operand:GPR 2 "low_bitmask_operand" "Yx")))]
1457 len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
1458 operands[2] = GEN_INT (len-1);
1459 return "bstrpick.<d>\t%0,%1,%2,0";
1461 [(set_attr "move_type" "pick_ins")
1462 (set_attr "mode" "<MODE>")])
1464 (define_insn_and_split "*bstrins_<mode>_for_mask"
1465 [(set (match_operand:GPR 0 "register_operand")
1466 (and:GPR (match_operand:GPR 1 "register_operand")
1467 (match_operand:GPR 2 "ins_zero_bitmask_operand")))]
1471 [(set (match_dup 0) (match_dup 1))
1472 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 3))
1475 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1476 int lo = ffs_hwi (mask) - 1;
1477 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1479 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1480 operands[2] = GEN_INT (len);
1481 operands[3] = GEN_INT (lo);
1484 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1485 [(set (match_operand:GPR 0 "register_operand")
1486 (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand")
1487 (match_operand:GPR 2 "const_int_operand"))
1488 (and:GPR (match_operand:GPR 3 "register_operand")
1489 (match_operand:GPR 4 "const_int_operand"))))]
1490 "loongarch_pre_reload_split ()
1491 && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1494 [(set (match_dup 0) (match_dup 1))
1495 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1498 if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1500 std::swap (operands[1], operands[3]);
1501 std::swap (operands[2], operands[4]);
1504 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1505 int lo = ffs_hwi (mask) - 1;
1506 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1508 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1509 operands[2] = GEN_INT (len);
1510 operands[4] = GEN_INT (lo);
1514 rtx tmp = gen_reg_rtx (<MODE>mode);
1515 emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1521 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1522 ;; if possible, but the result may be sub-optimal when one of the masks
1523 ;; is (1 << N) - 1 and one of the src register is the dest register.
1527 ;; bstrins.d a0, t0, 42, 0
1529 ;; using a shift operation would be better:
1530 ;; srai.d t0, a1, 43
1531 ;; bstrins.d a0, t0, 63, 43
1533 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1534 ;; know if the dest register is one of the src register. Fix it up in
1537 [(set (match_operand:GPR 0 "register_operand")
1538 (match_operand:GPR 1 "register_operand"))
1539 (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1540 (set (zero_extract:GPR (match_dup 1)
1541 (match_operand:SI 3 "const_int_operand")
1544 "peep2_reg_dead_p (3, operands[0])"
1547 int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1549 emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1550 emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1555 (define_insn "*iorhi3"
1556 [(set (match_operand:HI 0 "register_operand" "=r,r")
1557 (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1558 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1561 [(set_attr "type" "logical")
1562 (set_attr "mode" "HI")])
1564 (define_insn "*nor<mode>3"
1565 [(set (match_operand:GPR 0 "register_operand" "=r")
1566 (and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "%r"))
1567 (not:GPR (match_operand:GPR 2 "register_operand" "r"))))]
1570 [(set_attr "type" "logical")
1571 (set_attr "mode" "<MODE>")])
1573 (define_insn "<optab>n<mode>"
1574 [(set (match_operand:GPR 0 "register_operand" "=r")
1576 (not:GPR (match_operand:GPR 1 "register_operand" "r"))
1577 (match_operand:GPR 2 "register_operand" "r")))]
1580 [(set_attr "type" "logical")
1581 (set_attr "mode" "<MODE>")])
1585 ;; ....................
1589 ;; ....................
1591 (define_insn "truncdfsf2"
1592 [(set (match_operand:SF 0 "register_operand" "=f")
1593 (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1594 "TARGET_DOUBLE_FLOAT"
1596 [(set_attr "type" "fcvt")
1597 (set_attr "cnv_mode" "D2S")
1598 (set_attr "mode" "SF")])
1600 ;; In vector registers, popcount can be implemented directly through
1601 ;; the vector instruction [X]VPCNT. For GP registers, we can implement
1602 ;; it through the following method. Compared with loop implementation
1603 ;; of popcount, the following method has better performance.
1605 ;; This attribute used for get connection of scalar mode and corresponding
1607 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1609 (define_expand "popcount<mode>2"
1610 [(set (match_operand:GPR 0 "register_operand")
1611 (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1614 rtx in = operands[1];
1615 rtx out = operands[0];
1616 rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1617 gen_reg_rtx (V2DImode);
1618 emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1619 emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1620 emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1625 ;; ....................
1629 ;; ....................
1630 (define_expand "zero_extendsidi2"
1631 [(set (match_operand:DI 0 "register_operand")
1632 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1635 (define_insn_and_split "*zero_extendsidi2_internal"
1636 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1637 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1640 bstrpick.d\t%0,%1,31,0
1644 "&& reload_completed
1645 && MEM_P (operands[1])
1646 && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1647 && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1648 && !paradoxical_subreg_p (operands[0])"
1649 [(set (match_dup 3) (match_dup 1))
1651 (ior:DI (zero_extend:DI
1652 (subreg:SI (match_dup 0) 0))
1655 operands[1] = gen_lowpart (SImode, operands[1]);
1656 operands[3] = gen_lowpart (SImode, operands[0]);
1657 operands[2] = const0_rtx;
1659 [(set_attr "move_type" "arith,load,load,load")
1660 (set_attr "mode" "DI")])
1662 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1663 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1665 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1668 bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1669 ld.<SHORT:size>u\t%0,%1
1670 ldx.<SHORT:size>u\t%0,%1"
1671 [(set_attr "move_type" "pick_ins,load,load")
1672 (set_attr "mode" "<GPR:MODE>")])
1674 (define_insn "zero_extendqihi2"
1675 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1676 (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1682 [(set_attr "move_type" "andi,load,load")
1683 (set_attr "mode" "HI")])
1685 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1687 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1688 [(set (match_operand:GPR 0 "register_operand" "=r")
1690 (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1692 "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1693 [(set_attr "move_type" "pick_ins")
1694 (set_attr "mode" "<GPR:MODE>")])
1696 (define_insn "*zero_extendhi_truncqi"
1697 [(set (match_operand:HI 0 "register_operand" "=r")
1699 (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1702 [(set_attr "alu_type" "and")
1703 (set_attr "mode" "HI")])
1706 ;; ....................
1710 ;; ....................
1712 (define_insn "extendsidi2"
1713 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1715 (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k")))]
1722 [(set_attr "move_type" "sll0,load,load,load")
1723 (set_attr "mode" "DI")])
1725 (define_insn "extend<SHORT:mode><GPR:mode>2"
1726 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1728 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1731 ext.w.<SHORT:size>\t%0,%1
1732 ld.<SHORT:size>\t%0,%1
1733 ldx.<SHORT:size>\t%0,%1"
1734 [(set_attr "move_type" "signext,load,load")
1735 (set_attr "mode" "<GPR:MODE>")])
1737 (define_insn "extendqihi2"
1738 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1740 (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1746 [(set_attr "move_type" "signext,load,load")
1747 (set_attr "mode" "SI")])
1749 (define_insn "extendsfdf2"
1750 [(set (match_operand:DF 0 "register_operand" "=f")
1751 (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1752 "TARGET_DOUBLE_FLOAT"
1754 [(set_attr "type" "fcvt")
1755 (set_attr "cnv_mode" "S2D")
1756 (set_attr "mode" "DF")])
1759 ;; ....................
1763 ;; ....................
1765 ;; conversion of a floating-point value to a integer
1767 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1768 [(set (match_operand:GPR 0 "register_operand" "=f")
1769 (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1771 "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1772 [(set_attr "type" "fcvt")
1773 (set_attr "mode" "<ANYF:MODE>")])
1775 ;; conversion of an integeral (or boolean) value to a floating-point value
1777 (define_insn "floatsidf2"
1778 [(set (match_operand:DF 0 "register_operand" "=f")
1779 (float:DF (match_operand:SI 1 "register_operand" "f")))]
1780 "TARGET_DOUBLE_FLOAT"
1782 [(set_attr "type" "fcvt")
1783 (set_attr "mode" "DF")
1784 (set_attr "cnv_mode" "I2D")])
1786 (define_insn "floatdidf2"
1787 [(set (match_operand:DF 0 "register_operand" "=f")
1788 (float:DF (match_operand:DI 1 "register_operand" "f")))]
1789 "TARGET_DOUBLE_FLOAT"
1791 [(set_attr "type" "fcvt")
1792 (set_attr "mode" "DF")
1793 (set_attr "cnv_mode" "I2D")])
1795 (define_insn "floatsisf2"
1796 [(set (match_operand:SF 0 "register_operand" "=f")
1797 (float:SF (match_operand:SI 1 "register_operand" "f")))]
1800 [(set_attr "type" "fcvt")
1801 (set_attr "mode" "SF")
1802 (set_attr "cnv_mode" "I2S")])
1804 (define_insn "floatdisf2"
1805 [(set (match_operand:SF 0 "register_operand" "=f")
1806 (float:SF (match_operand:DI 1 "register_operand" "f")))]
1807 "TARGET_DOUBLE_FLOAT"
1809 [(set_attr "type" "fcvt")
1810 (set_attr "mode" "SF")
1811 (set_attr "cnv_mode" "I2S")])
1813 ;; Convert a floating-point value to an unsigned integer.
1815 (define_expand "fixuns_truncdfsi2"
1816 [(set (match_operand:SI 0 "register_operand")
1817 (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1818 "TARGET_DOUBLE_FLOAT"
1820 rtx reg1 = gen_reg_rtx (DFmode);
1821 rtx reg2 = gen_reg_rtx (DFmode);
1822 rtx reg3 = gen_reg_rtx (SImode);
1823 rtx_code_label *label1 = gen_label_rtx ();
1824 rtx_code_label *label2 = gen_label_rtx ();
1826 REAL_VALUE_TYPE offset;
1828 real_2expN (&offset, 31, DFmode);
1830 loongarch_emit_move (reg1,
1831 const_double_from_real_value (offset, DFmode));
1832 do_pending_stack_adjust ();
1834 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1835 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1837 emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1838 emit_jump_insn (gen_rtx_SET (pc_rtx,
1839 gen_rtx_LABEL_REF (VOIDmode, label2)));
1842 emit_label (label1);
1843 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1844 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1845 (BITMASK_HIGH, SImode)));
1847 emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1848 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1850 emit_label (label2);
1852 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1853 fields, and can't be used for REG_NOTES anyway). */
1854 emit_use (stack_pointer_rtx);
1858 (define_expand "fixuns_truncdfdi2"
1859 [(set (match_operand:DI 0 "register_operand")
1860 (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
1861 "TARGET_DOUBLE_FLOAT"
1863 rtx reg1 = gen_reg_rtx (DFmode);
1864 rtx reg2 = gen_reg_rtx (DFmode);
1865 rtx reg3 = gen_reg_rtx (DImode);
1866 rtx_code_label *label1 = gen_label_rtx ();
1867 rtx_code_label *label2 = gen_label_rtx ();
1869 REAL_VALUE_TYPE offset;
1871 real_2expN (&offset, 63, DFmode);
1873 loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
1874 do_pending_stack_adjust ();
1876 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1877 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1879 emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
1880 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1883 emit_label (label1);
1884 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1885 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
1886 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
1888 emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
1889 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
1891 emit_label (label2);
1893 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1894 fields, and can't be used for REG_NOTES anyway). */
1895 emit_use (stack_pointer_rtx);
1899 (define_expand "fixuns_truncsfsi2"
1900 [(set (match_operand:SI 0 "register_operand")
1901 (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
1904 rtx reg1 = gen_reg_rtx (SFmode);
1905 rtx reg2 = gen_reg_rtx (SFmode);
1906 rtx reg3 = gen_reg_rtx (SImode);
1907 rtx_code_label *label1 = gen_label_rtx ();
1908 rtx_code_label *label2 = gen_label_rtx ();
1910 REAL_VALUE_TYPE offset;
1912 real_2expN (&offset, 31, SFmode);
1914 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
1915 do_pending_stack_adjust ();
1917 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1918 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
1920 emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
1921 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1924 emit_label (label1);
1925 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
1926 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1927 (BITMASK_HIGH, SImode)));
1929 emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
1930 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1932 emit_label (label2);
1934 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1935 fields, and can't be used for REG_NOTES anyway). */
1936 emit_use (stack_pointer_rtx);
1940 (define_expand "fixuns_truncsfdi2"
1941 [(set (match_operand:DI 0 "register_operand")
1942 (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
1943 "TARGET_DOUBLE_FLOAT"
1945 rtx reg1 = gen_reg_rtx (SFmode);
1946 rtx reg2 = gen_reg_rtx (SFmode);
1947 rtx reg3 = gen_reg_rtx (DImode);
1948 rtx_code_label *label1 = gen_label_rtx ();
1949 rtx_code_label *label2 = gen_label_rtx ();
1951 REAL_VALUE_TYPE offset;
1953 real_2expN (&offset, 63, SFmode);
1955 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
1956 do_pending_stack_adjust ();
1958 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1959 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
1961 emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
1962 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1965 emit_label (label1);
1966 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
1967 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
1968 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
1970 emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
1971 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
1973 emit_label (label2);
1975 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1976 fields, and can't be used for REG_NOTES anyway). */
1977 emit_use (stack_pointer_rtx);
1982 ;; ....................
1984 ;; EXTRACT AND INSERT
1986 ;; ....................
1988 (define_expand "extzv<mode>"
1989 [(set (match_operand:X 0 "register_operand")
1990 (zero_extract:X (match_operand:X 1 "register_operand")
1991 (match_operand 2 "const_int_operand")
1992 (match_operand 3 "const_int_operand")))]
1995 if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
1996 INTVAL (operands[3])))
2000 (define_insn "*extzv<mode>"
2001 [(set (match_operand:X 0 "register_operand" "=r")
2002 (zero_extract:X (match_operand:X 1 "register_operand" "r")
2003 (match_operand 2 "const_int_operand" "")
2004 (match_operand 3 "const_int_operand" "")))]
2005 "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2006 INTVAL (operands[3]))"
2008 operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2009 return "bstrpick.<d>\t%0,%1,%2,%3";
2011 [(set_attr "type" "arith")
2012 (set_attr "mode" "<MODE>")])
2014 (define_expand "insv<mode>"
2015 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2016 (match_operand 1 "const_int_operand")
2017 (match_operand 2 "const_int_operand"))
2018 (match_operand:GPR 3 "reg_or_0_operand"))]
2021 if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2022 INTVAL (operands[2])))
2026 (define_insn "*insv<mode>"
2027 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2028 (match_operand:SI 1 "const_int_operand" "")
2029 (match_operand:SI 2 "const_int_operand" ""))
2030 (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2031 "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2032 INTVAL (operands[2]))"
2034 operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2035 return "bstrins.<d>\t%0,%z3,%1,%2";
2037 [(set_attr "type" "arith")
2038 (set_attr "mode" "<MODE>")])
2041 ;; ....................
2045 ;; ....................
2047 ;; 64-bit integer moves
2049 ;; Unlike most other insns, the move insns can't be split with
2050 ;; different predicates, because register spilling and other parts of
2051 ;; the compiler, have memoized the insn number already.
2053 (define_expand "movdi"
2054 [(set (match_operand:DI 0 "")
2055 (match_operand:DI 1 ""))]
2058 if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2062 (define_insn_and_split "*movdi_32bit"
2063 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2064 (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2066 && (register_operand (operands[0], DImode)
2067 || reg_or_0_operand (operands[1], DImode))"
2068 { return loongarch_output_move (operands[0], operands[1]); }
2069 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2074 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2078 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2079 (set_attr "mode" "DI")])
2081 (define_insn_and_split "*movdi_64bit"
2082 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2083 (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2085 && (register_operand (operands[0], DImode)
2086 || reg_or_0_operand (operands[1], DImode))"
2087 { return loongarch_output_move (operands[0], operands[1]); }
2088 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2093 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2097 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2098 (set_attr "mode" "DI")])
2100 ;; 32-bit Integer moves
2102 (define_expand "movsi"
2103 [(set (match_operand:SI 0 "")
2104 (match_operand:SI 1 ""))]
2107 if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2111 (define_insn_and_split "*movsi_internal"
2112 [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m,*r,*z")
2113 (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f,*z,*r"))]
2114 "(register_operand (operands[0], SImode)
2115 || reg_or_0_operand (operands[1], SImode))"
2116 { return loongarch_output_move (operands[0], operands[1]); }
2117 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2122 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2126 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore,mftg,mgtf")
2127 (set_attr "mode" "SI")])
2129 ;; 16-bit Integer moves
2131 ;; Unlike most other insns, the move insns can't be split with
2132 ;; different predicates, because register spilling and other parts of
2133 ;; the compiler, have memoized the insn number already.
2134 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2136 (define_expand "movhi"
2137 [(set (match_operand:HI 0 "")
2138 (match_operand:HI 1 ""))]
2141 if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2145 (define_insn_and_split "*movhi_internal"
2146 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2147 (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2148 "(register_operand (operands[0], HImode)
2149 || reg_or_0_operand (operands[1], HImode))"
2150 { return loongarch_output_move (operands[0], operands[1]); }
2151 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2156 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2160 [(set_attr "move_type" "move,const,const,load,store,load,store")
2161 (set_attr "mode" "HI")])
2163 ;; 8-bit Integer moves
2165 ;; Unlike most other insns, the move insns can't be split with
2166 ;; different predicates, because register spilling and other parts of
2167 ;; the compiler, have memoized the insn number already.
2168 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2170 (define_expand "movqi"
2171 [(set (match_operand:QI 0 "")
2172 (match_operand:QI 1 ""))]
2175 if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2179 (define_insn "*movqi_internal"
2180 [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2181 (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2182 "(register_operand (operands[0], QImode)
2183 || reg_or_0_operand (operands[1], QImode))"
2184 { return loongarch_output_move (operands[0], operands[1]); }
2185 [(set_attr "move_type" "move,const,load,store,load,store")
2186 (set_attr "mode" "QI")])
2188 ;; 32-bit floating point moves
2190 (define_expand "movsf"
2191 [(set (match_operand:SF 0 "")
2192 (match_operand:SF 1 ""))]
2195 if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2199 (define_insn "*movsf_hardfloat"
2200 [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2201 (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2203 && (register_operand (operands[0], SFmode)
2204 || reg_or_0_operand (operands[1], SFmode))"
2205 { return loongarch_output_move (operands[0], operands[1]); }
2206 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2207 (set_attr "mode" "SF")])
2209 (define_insn "*movsf_softfloat"
2210 [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2211 (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2213 && (register_operand (operands[0], SFmode)
2214 || reg_or_0_operand (operands[1], SFmode))"
2215 { return loongarch_output_move (operands[0], operands[1]); }
2216 [(set_attr "move_type" "move,load,store")
2217 (set_attr "mode" "SF")])
2219 ;; 64-bit floating point moves
2221 (define_expand "movdf"
2222 [(set (match_operand:DF 0 "")
2223 (match_operand:DF 1 ""))]
2226 if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2230 (define_insn "*movdf_hardfloat"
2231 [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2232 (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2233 "TARGET_DOUBLE_FLOAT
2234 && (register_operand (operands[0], DFmode)
2235 || reg_or_0_operand (operands[1], DFmode))"
2236 { return loongarch_output_move (operands[0], operands[1]); }
2237 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2238 (set_attr "mode" "DF")])
2240 (define_insn "*movdf_softfloat"
2241 [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2242 (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2243 "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2244 && (register_operand (operands[0], DFmode)
2245 || reg_or_0_operand (operands[1], DFmode))"
2246 { return loongarch_output_move (operands[0], operands[1]); }
2247 [(set_attr "move_type" "move,load,store")
2248 (set_attr "mode" "DF")])
2250 ;; Emit a doubleword move in which exactly one of the operands is
2251 ;; a floating-point register. We can't just emit two normal moves
2252 ;; because of the constraints imposed by the FPU register model;
2253 ;; see loongarch_can_change_mode_class for details. Instead, we keep
2254 ;; the FPR whole and use special patterns to refer to each word of
2255 ;; the other operand.
2257 (define_expand "move_doubleword_fpr<mode>"
2258 [(set (match_operand:SPLITF 0)
2259 (match_operand:SPLITF 1))]
2262 if (FP_REG_RTX_P (operands[0]))
2264 rtx low = loongarch_subword (operands[1], 0);
2265 rtx high = loongarch_subword (operands[1], 1);
2266 emit_insn (gen_load_low<mode> (operands[0], low));
2268 emit_insn (gen_movgr2frh<mode> (operands[0], high, operands[0]));
2270 emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
2274 rtx low = loongarch_subword (operands[0], 0);
2275 rtx high = loongarch_subword (operands[0], 1);
2276 emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
2278 emit_insn (gen_movfrh2gr<mode> (high, operands[1]));
2280 emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
2285 ;; Clear one FCC register
2287 (define_expand "movfcc"
2288 [(set (match_operand:FCC 0 "")
2289 (match_operand:FCC 1 ""))]
2292 if (memory_operand (operands[0], FCCmode)
2293 && memory_operand (operands[1], FCCmode))
2294 operands[1] = force_reg (FCCmode, operands[1]);
2297 (define_insn "movfcc_internal"
2298 [(set (match_operand:FCC 0 "nonimmediate_operand"
2299 "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2300 (match_operand:FCC 1 "reg_or_0_operand"
2301 "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2304 fcmp.caf.s\t%0,$f0,$f0
2315 [(set_attr "type" "move")
2316 (set_attr "mode" "FCC")])
2318 (define_insn "fcc_to_<X:mode>"
2319 [(set (match_operand:X 0 "register_operand" "=r")
2320 (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2326 [(set_attr "length" "0")
2327 (set_attr "type" "ghost")])
2329 (define_expand "cstore<ANYF:mode>4"
2330 [(set (match_operand:SI 0 "register_operand")
2331 (match_operator:SI 1 "loongarch_fcmp_operator"
2332 [(match_operand:ANYF 2 "register_operand")
2333 (match_operand:ANYF 3 "register_operand")]))]
2336 rtx fcc = gen_reg_rtx (FCCmode);
2337 rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2338 operands[2], operands[3]);
2340 emit_insn (gen_rtx_SET (fcc, cmp));
2343 rtx gpr = gen_reg_rtx (DImode);
2344 emit_insn (gen_fcc_to_di (gpr, fcc));
2345 emit_insn (gen_rtx_SET (operands[0],
2346 lowpart_subreg (SImode, gpr, DImode)));
2349 emit_insn (gen_fcc_to_si (operands[0], fcc));
2354 ;; Conditional move instructions.
2356 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2357 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2359 (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2361 (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2362 (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2363 "register_operand (operands[2], <GPR:MODE>mode)
2364 != register_operand (operands[3], <GPR:MODE>mode)"
2368 [(set_attr "type" "condmove")
2369 (set_attr "mode" "<GPR:MODE>")])
2371 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2372 ;; argument if the 1st is zero. This means operand 2 and 3 are
2373 ;; inverted in the instruction.
2375 (define_insn "*sel<mode>"
2376 [(set (match_operand:ANYF 0 "register_operand" "=f")
2378 (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2380 (match_operand:ANYF 2 "reg_or_0_operand" "f")
2381 (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2384 [(set_attr "type" "condmove")
2385 (set_attr "mode" "<ANYF:MODE>")])
2387 ;; These are the main define_expand's used to make conditional moves.
2389 (define_expand "mov<mode>cc"
2390 [(set (match_operand:GPR 0 "register_operand")
2391 (if_then_else:GPR (match_operator 1 "comparison_operator"
2392 [(match_operand:GPR 2 "reg_or_0_operand")
2393 (match_operand:GPR 3 "reg_or_0_operand")])))]
2394 "TARGET_COND_MOVE_INT"
2396 if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2399 loongarch_expand_conditional_move (operands);
2403 (define_expand "mov<mode>cc"
2404 [(set (match_operand:ANYF 0 "register_operand")
2405 (if_then_else:ANYF (match_operator 1 "comparison_operator"
2406 [(match_operand:ANYF 2 "reg_or_0_operand")
2407 (match_operand:ANYF 3 "reg_or_0_operand")])))]
2408 "TARGET_COND_MOVE_FLOAT"
2410 if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2413 loongarch_expand_conditional_move (operands);
2417 (define_insn "lu32i_d"
2418 [(set (match_operand:DI 0 "register_operand" "=r")
2421 (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2422 (match_operand:DI 2 "const_lu32i_operand" "u")))]
2424 "lu32i.d\t%0,%X2>>32"
2425 [(set_attr "type" "arith")
2426 (set_attr "mode" "DI")])
2428 (define_insn "lu52i_d"
2429 [(set (match_operand:DI 0 "register_operand" "=r")
2431 (and:DI (match_operand:DI 1 "register_operand" "r")
2432 (match_operand 2 "lu52i_mask_operand"))
2433 (match_operand 3 "const_lu52i_operand" "v")))]
2435 "lu52i.d\t%0,%1,%X3>>52"
2436 [(set_attr "type" "arith")
2437 (set_attr "mode" "DI")])
2439 ;; Instructions for adding the low 12 bits of an address to a register.
2440 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2441 ;; should be applied.
2443 (define_insn "*low<mode>"
2444 [(set (match_operand:P 0 "register_operand" "=r")
2445 (lo_sum:P (match_operand:P 1 "register_operand" " r")
2446 (match_operand:P 2 "symbolic_operand" "")))]
2448 "addi.<d>\t%0,%1,%L2"
2449 [(set_attr "type" "arith")
2450 (set_attr "mode" "<MODE>")])
2452 (define_insn "@tls_low<mode>"
2453 [(set (match_operand:P 0 "register_operand" "=r")
2454 (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2455 (match_operand:P 2 "symbolic_operand" "")))]
2458 "addi.<d>\t%0,%1,%L2"
2459 [(set_attr "type" "arith")
2460 (set_attr "mode" "<MODE>")])
2462 ;; Instructions for loading address from GOT entry.
2463 ;; operands[1] is pc plus the high half of the address difference with the got
2465 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2467 ;; loongarch_print_operand works out which relocation should be applied.
2469 (define_insn "@ld_from_got<mode>"
2470 [(set (match_operand:P 0 "register_operand" "=r")
2471 (unspec:P [(mem:P (lo_sum:P
2472 (match_operand:P 1 "register_operand" "r")
2473 (match_operand:P 2 "symbolic_operand")))]
2474 UNSPEC_LOAD_FROM_GOT))]
2477 [(set_attr "type" "move")]
2480 (define_insn "@lui_l_hi20<mode>"
2481 [(set (match_operand:P 0 "register_operand" "=r")
2482 (unspec:P [(match_operand:P 1 "symbolic_operand")]
2483 UNSPEC_LUI_L_HI20))]
2486 [(set_attr "type" "move")]
2489 (define_insn "@pcalau12i<mode>"
2490 [(set (match_operand:P 0 "register_operand" "=j")
2491 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2494 "pcalau12i\t%0,%%pc_hi20(%1)"
2495 [(set_attr "type" "move")])
2497 ;; @pcalau12i may be used for sibcall so it has a strict constraint. This
2498 ;; allows any general register as the operand.
2499 (define_insn "@pcalau12i_gr<mode>"
2500 [(set (match_operand:P 0 "register_operand" "=r")
2501 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2502 UNSPEC_PCALAU12I_GR))]
2504 "pcalau12i\t%0,%%pc_hi20(%1)"
2505 [(set_attr "type" "move")])
2507 (define_insn "@add_tls_le_relax<mode>"
2508 [(set (match_operand:P 0 "register_operand" "=r")
2509 (unspec:P [(match_operand:P 1 "register_operand" "r")
2510 (match_operand:P 2 "register_operand" "r")
2511 (match_operand:P 3 "symbolic_operand")]
2512 UNSPEC_ADD_TLS_LE_RELAX))]
2513 "HAVE_AS_TLS_LE_RELAXATION"
2514 "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2515 [(set_attr "type" "move")]
2518 (define_insn "@ori_l_lo12<mode>"
2519 [(set (match_operand:P 0 "register_operand" "=r")
2520 (unspec:P [(match_operand:P 1 "register_operand" "r")
2521 (match_operand:P 2 "symbolic_operand")]
2522 UNSPEC_ORI_L_LO12))]
2525 [(set_attr "type" "move")]
2528 (define_insn "lui_h_lo20"
2529 [(set (match_operand:DI 0 "register_operand" "=r")
2530 (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2531 (match_operand:DI 2 "symbolic_operand")]
2532 UNSPEC_LUI_H_LO20))]
2535 [(set_attr "type" "move")]
2538 (define_insn "lui_h_hi12"
2539 [(set (match_operand:DI 0 "register_operand" "=r")
2540 (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2541 (match_operand:DI 2 "symbolic_operand")]
2542 UNSPEC_LUI_H_HI12))]
2544 "lu52i.d\t%0,%1,%H2"
2545 [(set_attr "type" "move")]
2548 ;; Round floating-point numbers to integers
2549 (define_insn "rint<mode>2"
2550 [(set (match_operand:ANYF 0 "register_operand" "=f")
2551 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2554 "frint.<fmt>\t%0,%1"
2555 [(set_attr "type" "fcvt")
2556 (set_attr "mode" "<MODE>")])
2558 ;; Convert floating-point numbers to integers
2559 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2560 [(set (match_operand:ANYFI 0 "register_operand" "=f")
2561 (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2563 "TARGET_HARD_FLOAT &&
2564 (<LRINT> == UNSPEC_FTINT
2565 || flag_fp_int_builtin_inexact
2566 || !flag_trapping_math)"
2567 "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2568 [(set_attr "type" "fcvt")
2569 (set_attr "mode" "<ANYF:MODE>")])
2571 ;; Load the low word of operand 0 with operand 1.
2572 (define_insn "load_low<mode>"
2573 [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
2574 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "rJ,m")]
2578 operands[0] = loongarch_subword (operands[0], 0);
2579 return loongarch_output_move (operands[0], operands[1]);
2581 [(set_attr "move_type" "mgtf,fpload")
2582 (set_attr "mode" "<HALFMODE>")])
2584 ;; Load the high word of operand 0 from operand 1, preserving the value
2586 (define_insn "load_high<mode>"
2587 [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
2588 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "rJ,m")
2589 (match_operand:SPLITF 2 "register_operand" "0,0")]
2593 operands[0] = loongarch_subword (operands[0], 1);
2594 return loongarch_output_move (operands[0], operands[1]);
2596 [(set_attr "move_type" "mgtf,fpload")
2597 (set_attr "mode" "<HALFMODE>")])
2599 ;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
2600 ;; high word and 0 to store the low word.
2601 (define_insn "store_word<mode>"
2602 [(set (match_operand:<HALFMODE> 0 "nonimmediate_operand" "=r,m")
2603 (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f,f")
2604 (match_operand 2 "const_int_operand")]
2605 UNSPEC_STORE_WORD))]
2608 operands[1] = loongarch_subword (operands[1], INTVAL (operands[2]));
2609 return loongarch_output_move (operands[0], operands[1]);
2611 [(set_attr "move_type" "mftg,fpstore")
2612 (set_attr "mode" "<HALFMODE>")])
2614 ;; Thread-Local Storage
2616 (define_insn "@got_load_tls_gd<mode>"
2617 [(set (match_operand:P 0 "register_operand" "=r")
2619 [(match_operand:P 1 "symbolic_operand" "")]
2623 [(set_attr "got" "load")
2624 (set_attr "mode" "<MODE>")])
2626 (define_insn "@got_load_tls_ld<mode>"
2627 [(set (match_operand:P 0 "register_operand" "=r")
2629 [(match_operand:P 1 "symbolic_operand" "")]
2633 [(set_attr "got" "load")
2634 (set_attr "mode" "<MODE>")])
2636 (define_insn "@got_load_tls_le<mode>"
2637 [(set (match_operand:P 0 "register_operand" "=r")
2639 [(match_operand:P 1 "symbolic_operand" "")]
2643 [(set_attr "got" "load")
2644 (set_attr "mode" "<MODE>")])
2646 (define_insn "@got_load_tls_ie<mode>"
2647 [(set (match_operand:P 0 "register_operand" "=r")
2649 [(match_operand:P 1 "symbolic_operand" "")]
2653 [(set_attr "got" "load")
2654 (set_attr "mode" "<MODE>")])
2656 ;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving the
2657 ;; value in the low word.
2658 (define_insn "movgr2frh<mode>"
2659 [(set (match_operand:SPLITF 0 "register_operand" "=f")
2660 (unspec:SPLITF [(match_operand:<HALFMODE> 1 "reg_or_0_operand" "rJ")
2661 (match_operand:SPLITF 2 "register_operand" "0")]
2663 "TARGET_DOUBLE_FLOAT"
2664 "movgr2frh.w\t%z1,%0"
2665 [(set_attr "move_type" "mgtf")
2666 (set_attr "mode" "<HALFMODE>")])
2668 ;; Move high word of operand 1 to operand 0 using movfrh2gr.s.
2669 (define_insn "movfrh2gr<mode>"
2670 [(set (match_operand:<HALFMODE> 0 "register_operand" "=r")
2671 (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f")]
2673 "TARGET_DOUBLE_FLOAT"
2674 "movfrh2gr.s\t%0,%1"
2675 [(set_attr "move_type" "mftg")
2676 (set_attr "mode" "<HALFMODE>")])
2679 ;; Expand in-line code to clear the instruction cache between operand[0] and
2681 (define_expand "clear_cache"
2682 [(match_operand 0 "pmode_register_operand")
2683 (match_operand 1 "pmode_register_operand")]
2686 emit_insn (gen_loongarch_ibar (const0_rtx));
2690 (define_insn "loongarch_ibar"
2691 [(unspec_volatile:SI
2692 [(match_operand 0 "const_uimm15_operand")]
2694 (clobber (mem:BLK (scratch)))]
2698 (define_insn "loongarch_dbar"
2699 [(unspec_volatile:SI
2700 [(match_operand 0 "const_uimm15_operand")]
2702 (clobber (mem:BLK (scratch)))]
2708 ;; Privileged state instruction
2710 (define_insn "loongarch_cpucfg"
2711 [(set (match_operand:SI 0 "register_operand" "=r")
2712 (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2716 [(set_attr "type" "load")
2717 (set_attr "mode" "SI")])
2719 (define_insn "loongarch_syscall"
2720 [(unspec_volatile:SI
2721 [(match_operand 0 "const_uimm15_operand")]
2723 (clobber (mem:BLK (scratch)))]
2727 (define_insn "loongarch_break"
2728 [(unspec_volatile:SI
2729 [(match_operand 0 "const_uimm15_operand")]
2731 (clobber (mem:BLK (scratch)))]
2735 (define_insn "loongarch_asrtle_d"
2736 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2737 (match_operand:DI 1 "register_operand" "r")]
2741 [(set_attr "type" "load")
2742 (set_attr "mode" "DI")])
2744 (define_insn "loongarch_asrtgt_d"
2745 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2746 (match_operand:DI 1 "register_operand" "r")]
2750 [(set_attr "type" "load")
2751 (set_attr "mode" "DI")])
2753 (define_insn "loongarch_csrrd_<d>"
2754 [(set (match_operand:GPR 0 "register_operand" "=r")
2755 (unspec_volatile:GPR [(match_operand 1 "const_uimm14_operand")]
2757 (clobber (mem:BLK (scratch)))]
2760 [(set_attr "type" "load")
2761 (set_attr "mode" "<MODE>")])
2763 (define_insn "loongarch_csrwr_<d>"
2764 [(set (match_operand:GPR 0 "register_operand" "=r")
2765 (unspec_volatile:GPR
2766 [(match_operand:GPR 1 "register_operand" "0")
2767 (match_operand 2 "const_uimm14_operand")]
2769 (clobber (mem:BLK (scratch)))]
2772 [(set_attr "type" "store")
2773 (set_attr "mode" "<MODE>")])
2775 (define_insn "loongarch_csrxchg_<d>"
2776 [(set (match_operand:GPR 0 "register_operand" "=r")
2777 (unspec_volatile:GPR
2778 [(match_operand:GPR 1 "register_operand" "0")
2779 (match_operand:GPR 2 "register_operand" "q")
2780 (match_operand 3 "const_uimm14_operand")]
2782 (clobber (mem:BLK (scratch)))]
2785 [(set_attr "type" "load")
2786 (set_attr "mode" "<MODE>")])
2788 (define_insn "loongarch_iocsrrd_<size>"
2789 [(set (match_operand:QHWD 0 "register_operand" "=r")
2790 (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2792 (clobber (mem:BLK (scratch)))]
2794 "iocsrrd.<size>\t%0,%1"
2795 [(set_attr "type" "load")
2796 (set_attr "mode" "<MODE>")])
2798 (define_insn "loongarch_iocsrwr_<size>"
2799 [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2800 (match_operand:SI 1 "register_operand" "r")]
2802 (clobber (mem:BLK (scratch)))]
2804 "iocsrwr.<size>\t%0,%1"
2805 [(set_attr "type" "load")
2806 (set_attr "mode" "<MODE>")])
2808 (define_insn "loongarch_cacop_<d>"
2809 [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2810 (match_operand:X 1 "register_operand" "r")
2811 (match_operand 2 "const_imm12_operand")]
2813 (clobber (mem:BLK (scratch)))]
2816 [(set_attr "type" "load")
2817 (set_attr "mode" "<MODE>")])
2819 (define_insn "loongarch_lddir_<d>"
2820 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2821 (match_operand:X 1 "register_operand" "r")
2822 (match_operand 2 "const_uimm5_operand")]
2824 (clobber (mem:BLK (scratch)))]
2827 [(set_attr "type" "load")
2828 (set_attr "mode" "<MODE>")])
2830 (define_insn "loongarch_ldpte_<d>"
2831 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2832 (match_operand 1 "const_uimm5_operand")]
2834 (clobber (mem:BLK (scratch)))]
2837 [(set_attr "type" "load")
2838 (set_attr "mode" "<MODE>")])
2841 ;; Block moves, see loongarch.c for more details.
2842 ;; Argument 0 is the destination.
2843 ;; Argument 1 is the source.
2844 ;; Argument 2 is the length.
2845 ;; Argument 3 is the alignment.
2847 (define_expand "cpymemsi"
2848 [(parallel [(set (match_operand:BLK 0 "general_operand")
2849 (match_operand:BLK 1 "general_operand"))
2850 (use (match_operand:SI 2 ""))
2851 (use (match_operand:SI 3 "const_int_operand"))])]
2854 if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
2855 && loongarch_expand_block_move (operands[0], operands[1],
2856 operands[2], operands[3]))
2863 ;; ....................
2867 ;; ....................
2869 (define_insn "<optab><mode>3"
2870 [(set (match_operand:GPR 0 "register_operand" "=r")
2871 (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
2872 (match_operand:SI 2 "arith_operand" "rI")))]
2875 if (CONST_INT_P (operands[2]))
2876 operands[2] = GEN_INT (INTVAL (operands[2])
2877 & (GET_MODE_BITSIZE (<MODE>mode) - 1));
2879 return "<insn>%i2.<d>\t%0,%1,%2";
2881 [(set_attr "type" "shift")
2882 (set_attr "mode" "<MODE>")])
2884 (define_insn "*<optab>si3_extend"
2885 [(set (match_operand:DI 0 "register_operand" "=r")
2887 (any_shift:SI (match_operand:SI 1 "register_operand" "r")
2888 (match_operand:SI 2 "arith_operand" "rI"))))]
2891 if (CONST_INT_P (operands[2]))
2892 operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
2894 return "<insn>%i2.w\t%0,%1,%2";
2896 [(set_attr "type" "shift")
2897 (set_attr "mode" "SI")])
2899 (define_insn "rotr<mode>3"
2900 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2901 (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
2902 (match_operand:SI 2 "arith_operand" "r,I")))]
2904 "rotr%i2.<d>\t%0,%1,%2"
2905 [(set_attr "type" "shift,shift")
2906 (set_attr "mode" "<MODE>")])
2908 (define_insn "rotrsi3_extend"
2909 [(set (match_operand:DI 0 "register_operand" "=r,r")
2911 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
2912 (match_operand:SI 2 "arith_operand" "r,I"))))]
2914 "rotr%i2.w\t%0,%1,%2"
2915 [(set_attr "type" "shift,shift")
2916 (set_attr "mode" "SI")])
2918 ;; Expand left rotate to right rotate.
2919 (define_expand "rotl<mode>3"
2921 (neg:SI (match_operand:SI 2 "register_operand")))
2922 (set (match_operand:GPR 0 "register_operand")
2923 (rotatert:GPR (match_operand:GPR 1 "register_operand")
2927 operands[3] = gen_reg_rtx (SImode);
2930 ;; The following templates were added to generate "bstrpick.d + alsl.d"
2931 ;; instruction pairs.
2932 ;; It is required that the values of const_immalsl_operand and
2933 ;; immediate_operand must have the following correspondence:
2935 ;; (immediate_operand >> const_immalsl_operand) == 0xffffffff
2937 (define_insn "zero_extend_ashift"
2938 [(set (match_operand:DI 0 "register_operand" "=r")
2939 (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
2940 (match_operand 2 "const_immalsl_operand" ""))
2941 (match_operand 3 "immediate_operand" "")))]
2943 && ((INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff)"
2944 "bstrpick.d\t%0,%1,31,0\n\talsl.d\t%0,%0,$r0,%2"
2945 [(set_attr "type" "arith")
2946 (set_attr "mode" "DI")
2947 (set_attr "insn_count" "2")])
2949 (define_insn "bstrpick_alsl_paired"
2950 [(set (match_operand:DI 0 "register_operand" "=&r")
2951 (plus:DI (match_operand:DI 1 "register_operand" "r")
2952 (and:DI (ashift:DI (match_operand:DI 2 "register_operand" "r")
2953 (match_operand 3 "const_immalsl_operand" ""))
2954 (match_operand 4 "immediate_operand" ""))))]
2956 && ((INTVAL (operands[4]) >> INTVAL (operands[3])) == 0xffffffff)"
2957 "bstrpick.d\t%0,%2,31,0\n\talsl.d\t%0,%0,%1,%3"
2958 [(set_attr "type" "arith")
2959 (set_attr "mode" "DI")
2960 (set_attr "insn_count" "2")])
2962 (define_insn "alsl<mode>3"
2963 [(set (match_operand:GPR 0 "register_operand" "=r")
2964 (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
2965 (match_operand 2 "const_immalsl_operand" ""))
2966 (match_operand:GPR 3 "register_operand" "r")))]
2968 "alsl.<d>\t%0,%1,%3,%2"
2969 [(set_attr "type" "arith")
2970 (set_attr "mode" "<MODE>")])
2972 (define_insn "alslsi3_extend"
2973 [(set (match_operand:DI 0 "register_operand" "=r")
2976 (ashift:SI (match_operand:SI 1 "register_operand" "r")
2977 (match_operand 2 "const_immalsl_operand" ""))
2978 (match_operand:SI 3 "register_operand" "r"))))]
2980 "alsl.w\t%0,%1,%3,%2"
2981 [(set_attr "type" "arith")
2982 (set_attr "mode" "SI")])
2986 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
2988 (define_insn "bswaphi2"
2989 [(set (match_operand:HI 0 "register_operand" "=r")
2990 (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
2993 [(set_attr "type" "shift")])
2995 (define_insn_and_split "bswapsi2"
2996 [(set (match_operand:SI 0 "register_operand" "=r")
2997 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3001 [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_REVB_2H))
3002 (set (match_dup 0) (rotatert:SI (match_dup 0) (const_int 16)))]
3004 [(set_attr "insn_count" "2")])
3006 (define_insn_and_split "bswapdi2"
3007 [(set (match_operand:DI 0 "register_operand" "=r")
3008 (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3012 [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_REVB_4H))
3013 (set (match_dup 0) (unspec:DI [(match_dup 0)] UNSPEC_REVH_D))]
3015 [(set_attr "insn_count" "2")])
3017 (define_insn "revb_2h"
3018 [(set (match_operand:SI 0 "register_operand" "=r")
3019 (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_REVB_2H))]
3022 [(set_attr "type" "shift")])
3024 (define_insn "revb_4h"
3025 [(set (match_operand:DI 0 "register_operand" "=r")
3026 (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_REVB_4H))]
3029 [(set_attr "type" "shift")])
3031 (define_insn "revh_d"
3032 [(set (match_operand:DI 0 "register_operand" "=r")
3033 (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_REVH_D))]
3036 [(set_attr "type" "shift")])
3039 ;; ....................
3041 ;; CONDITIONAL BRANCHES
3043 ;; ....................
3045 ;; Conditional branches
3047 (define_insn "*branch_fp_FCCmode"
3050 (match_operator 1 "equality_operator"
3051 [(match_operand:FCC 2 "register_operand" "z")
3053 (label_ref (match_operand 0 "" ""))
3057 return loongarch_output_conditional_branch (insn, operands,
3058 LARCH_BRANCH ("b%F1", "%Z2%0"),
3059 LARCH_BRANCH ("b%W1", "%Z2%0"));
3061 [(set_attr "type" "branch")])
3063 (define_insn "*branch_fp_inverted_FCCmode"
3066 (match_operator 1 "equality_operator"
3067 [(match_operand:FCC 2 "register_operand" "z")
3070 (label_ref (match_operand 0 "" ""))))]
3073 return loongarch_output_conditional_branch (insn, operands,
3074 LARCH_BRANCH ("b%W1", "%Z2%0"),
3075 LARCH_BRANCH ("b%F1", "%Z2%0"));
3077 [(set_attr "type" "branch")])
3079 ;; Conditional branches on ordered comparisons with zero.
3081 (define_insn "*branch_order<mode>"
3084 (match_operator 1 "order_operator"
3085 [(match_operand:X 2 "register_operand" "r,r")
3086 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3087 (label_ref (match_operand 0 "" ""))
3090 { return loongarch_output_order_conditional_branch (insn, operands, false); }
3091 [(set_attr "type" "branch")])
3093 (define_insn "*branch_order<mode>_inverted"
3096 (match_operator 1 "order_operator"
3097 [(match_operand:X 2 "register_operand" "r,r")
3098 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3100 (label_ref (match_operand 0 "" ""))))]
3102 { return loongarch_output_order_conditional_branch (insn, operands, true); }
3103 [(set_attr "type" "branch")])
3105 ;; Conditional branch on equality comparison.
3107 (define_insn "branch_equality<mode>"
3110 (match_operator 1 "equality_operator"
3111 [(match_operand:X 2 "register_operand" "r")
3112 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3113 (label_ref (match_operand 0 "" ""))
3116 { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3117 [(set_attr "type" "branch")])
3120 (define_insn "*branch_equality<mode>_inverted"
3123 (match_operator 1 "equality_operator"
3124 [(match_operand:X 2 "register_operand" "r")
3125 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3127 (label_ref (match_operand 0 "" ""))))]
3129 { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3130 [(set_attr "type" "branch")])
3133 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3134 ;; QImode values so we can force zero-extension.
3135 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3137 (define_expand "cbranch<mode>4"
3139 (if_then_else (match_operator 0 "comparison_operator"
3140 [(match_operand:BR 1 "register_operand")
3141 (match_operand:BR 2 "nonmemory_operand")])
3142 (label_ref (match_operand 3 ""))
3146 loongarch_expand_conditional_branch (operands);
3150 (define_expand "cbranch<mode>4"
3152 (if_then_else (match_operator 0 "comparison_operator"
3153 [(match_operand:ANYF 1 "register_operand")
3154 (match_operand:ANYF 2 "register_operand")])
3155 (label_ref (match_operand 3 ""))
3159 loongarch_expand_conditional_branch (operands);
3163 ;; Used to implement built-in functions.
3164 (define_expand "condjump"
3166 (if_then_else (match_operand 0)
3167 (label_ref (match_operand 1))
3173 ;; ....................
3175 ;; SETTING A REGISTER FROM A COMPARISON
3177 ;; ....................
3179 ;; Destination is always set in SI mode.
3181 (define_expand "cstore<mode>4"
3182 [(set (match_operand:SI 0 "register_operand")
3183 (match_operator:SI 1 "loongarch_cstore_operator"
3184 [(match_operand:GPR 2 "register_operand")
3185 (match_operand:GPR 3 "nonmemory_operand")]))]
3188 loongarch_expand_scc (operands);
3192 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3193 [(set (match_operand:GPR 0 "register_operand" "=r")
3194 (eq:GPR (match_operand:X 1 "register_operand" "r")
3198 [(set_attr "type" "slt")
3199 (set_attr "mode" "<X:MODE>")])
3202 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3203 [(set (match_operand:GPR 0 "register_operand" "=r")
3204 (ne:GPR (match_operand:X 1 "register_operand" "r")
3208 [(set_attr "type" "slt")
3209 (set_attr "mode" "<X:MODE>")])
3211 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3212 [(set (match_operand:GPR 0 "register_operand" "=r")
3213 (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3214 (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3217 [(set_attr "type" "slt")
3218 (set_attr "mode" "<X:MODE>")])
3220 (define_insn "*sge<u>_<X:mode><GPR:mode>"
3221 [(set (match_operand:GPR 0 "register_operand" "=r")
3222 (any_ge:GPR (match_operand:X 1 "register_operand" "r")
3226 [(set_attr "type" "slt")
3227 (set_attr "mode" "<X:MODE>")])
3229 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3230 [(set (match_operand:GPR 0 "register_operand" "=r")
3231 (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3232 (match_operand:X 2 "arith_operand" "rI")))]
3234 "slt<u>%i2\t%0,%1,%2";
3235 [(set_attr "type" "slt")
3236 (set_attr "mode" "<X:MODE>")])
3238 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3239 [(set (match_operand:GPR 0 "register_operand" "=r")
3240 (any_le:GPR (match_operand:X 1 "register_operand" "r")
3241 (match_operand:X 2 "sle_operand" "")))]
3244 operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3245 return "slt<u>i\t%0,%1,%2";
3247 [(set_attr "type" "slt")
3248 (set_attr "mode" "<X:MODE>")])
3252 ;; ....................
3254 ;; FLOATING POINT COMPARISONS
3256 ;; ....................
3258 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3259 [(set (match_operand:FCC 0 "register_operand" "=z")
3260 (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3261 (match_operand:ANYF 2 "register_operand" "f")))]
3263 "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3264 [(set_attr "type" "fcmp")
3265 (set_attr "mode" "FCC")])
3269 ;; ....................
3271 ;; UNCONDITIONAL BRANCHES
3273 ;; ....................
3275 ;; Unconditional branches.
3277 (define_expand "jump"
3279 (label_ref (match_operand 0)))])
3281 (define_insn "*jump_absolute"
3283 (label_ref (match_operand 0)))]
3288 [(set_attr "type" "branch")])
3290 (define_insn "*jump_pic"
3292 (label_ref (match_operand 0)))]
3297 [(set_attr "type" "branch")])
3299 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3300 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3301 ;; return prediction and the more general indirect branch prediction.
3303 (define_expand "indirect_jump"
3304 [(set (pc) (match_operand 0 "register_operand"))]
3307 operands[0] = force_reg (Pmode, operands[0]);
3308 emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3312 (define_insn "@indirect_jump<mode>"
3313 [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3316 [(set_attr "type" "jump")
3317 (set_attr "mode" "none")])
3319 (define_expand "tablejump"
3321 (match_operand 0 "register_operand"))
3322 (use (label_ref (match_operand 1 "")))]
3326 operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3327 gen_rtx_LABEL_REF (Pmode,
3329 NULL_RTX, 0, OPTAB_DIRECT);
3330 emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3334 (define_insn "@tablejump<mode>"
3336 (match_operand:P 0 "register_operand" "e"))
3337 (use (label_ref (match_operand 1 "" "")))]
3340 [(set_attr "type" "jump")
3341 (set_attr "mode" "none")])
3346 ;; ....................
3348 ;; Function prologue/epilogue
3350 ;; ....................
3353 (define_expand "prologue"
3357 loongarch_expand_prologue ();
3361 ;; Block any insns from being moved before this point, since the
3362 ;; profiling call to mcount can use various registers that aren't
3363 ;; saved or used to pass arguments.
3365 (define_insn "blockage"
3366 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3369 [(set_attr "type" "ghost")
3370 (set_attr "mode" "none")])
3372 (define_insn "@probe_stack_range<P:mode>"
3373 [(set (match_operand:P 0 "register_operand" "=r")
3374 (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3375 (match_operand:P 2 "register_operand" "r")
3376 (match_operand:P 3 "register_operand" "r")]
3377 UNSPECV_PROBE_STACK_RANGE))]
3380 return loongarch_output_probe_stack_range (operands[0],
3384 [(set_attr "type" "unknown")
3385 (set_attr "mode" "<MODE>")])
3387 (define_expand "epilogue"
3391 loongarch_expand_epilogue (NORMAL_RETURN);
3395 (define_expand "sibcall_epilogue"
3399 loongarch_expand_epilogue (SIBCALL_RETURN);
3403 ;; Trivial return. Make it look like a normal return insn as that
3404 ;; allows jump optimizations to work better.
3406 (define_expand "return"
3408 "loongarch_can_use_return_insn ()"
3411 (define_expand "simple_return"
3416 (define_insn "*<optab>"
3420 operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3423 [(set_attr "type" "jump")
3424 (set_attr "mode" "none")])
3428 (define_insn "<optab>_internal"
3430 (use (match_operand 0 "pmode_register_operand" ""))]
3433 [(set_attr "type" "jump")
3434 (set_attr "mode" "none")])
3436 ;; Exception return.
3437 (define_insn "loongarch_ertn"
3439 (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3442 [(set_attr "type" "trap")
3443 (set_attr "mode" "none")])
3445 ;; This is used in compiling the unwind routines.
3446 (define_expand "eh_return"
3447 [(use (match_operand 0 "general_operand"))]
3450 if (GET_MODE (operands[0]) != word_mode)
3451 operands[0] = convert_to_mode (word_mode, operands[0], 0);
3453 emit_insn (gen_eh_set_ra_di (operands[0]));
3455 emit_insn (gen_eh_set_ra_si (operands[0]));
3457 emit_jump_insn (gen_eh_return_internal ());
3462 (define_insn_and_split "eh_return_internal"
3466 "epilogue_completed"
3469 loongarch_expand_epilogue (EXCEPTION_RETURN);
3473 ;; Clobber the return address on the stack. We can't expand this
3474 ;; until we know where it will be put in the stack frame.
3476 (define_insn "eh_set_ra_si"
3477 [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3478 (clobber (match_scratch:SI 1 "=&r"))]
3482 (define_insn "eh_set_ra_di"
3483 [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3484 (clobber (match_scratch:DI 1 "=&r"))]
3489 [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3490 (clobber (match_scratch 1))]
3494 loongarch_set_return_address (operands[0], operands[1]);
3501 ;; ....................
3505 ;; ....................
3507 ;; Sibling calls. All these patterns use jump instructions.
3509 (define_expand "sibcall"
3510 [(parallel [(call (match_operand 0 "")
3511 (match_operand 1 ""))
3512 (use (match_operand 2 "")) ;; next_arg_reg
3513 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3516 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3518 if (GET_CODE (target) == LO_SUM)
3519 emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3524 rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3526 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3527 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3528 gen_rtx_REG (Pmode, T0_REGNUM));
3533 (define_insn "sibcall_internal"
3534 [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3535 (match_operand 1 "" ""))]
3536 "SIBLING_CALL_P (insn)"
3538 switch (which_alternative)
3543 if (TARGET_CMODEL_MEDIUM)
3544 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3548 if (TARGET_CMODEL_MEDIUM)
3549 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3551 return "b\t%%plt(%0)";
3556 [(set_attr "jirl" "indirect,direct,direct")])
3558 (define_insn "@sibcall_internal_1<mode>"
3559 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3560 (match_operand:P 1 "symbolic_operand" "")))
3561 (match_operand 2 "" ""))]
3562 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3563 "jirl\t$r0,%0,%%pc_lo12(%1)"
3564 [(set_attr "jirl" "indirect")])
3566 (define_expand "sibcall_value"
3567 [(parallel [(set (match_operand 0 "")
3568 (call (match_operand 1 "")
3569 (match_operand 2 "")))
3570 (use (match_operand 3 ""))])] ;; next_arg_reg
3573 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3575 /* Handle return values created by loongarch_pass_fpr_pair. */
3576 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3578 rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3579 rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3581 if (GET_CODE (target) == LO_SUM)
3582 emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3590 = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3595 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3596 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3597 gen_rtx_REG (Pmode, T0_REGNUM));
3602 /* Handle return values created by loongarch_return_fpr_single. */
3603 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3604 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3606 if (GET_CODE (target) == LO_SUM)
3607 emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3613 rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3617 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3618 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3619 gen_rtx_REG (Pmode, T0_REGNUM));
3625 (define_insn "sibcall_value_internal"
3626 [(set (match_operand 0 "register_operand" "")
3627 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3628 (match_operand 2 "" "")))]
3629 "SIBLING_CALL_P (insn)"
3631 switch (which_alternative)
3636 if (TARGET_CMODEL_MEDIUM)
3637 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3641 if (TARGET_CMODEL_MEDIUM)
3642 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3644 return "b\t%%plt(%1)";
3649 [(set_attr "jirl" "indirect,direct,direct")])
3651 (define_insn "@sibcall_value_internal_1<mode>"
3652 [(set (match_operand 0 "register_operand" "")
3653 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3654 (match_operand:P 2 "symbolic_operand" "")))
3655 (match_operand 3 "" "")))]
3656 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3657 "jirl\t$r0,%1,%%pc_lo12(%2)"
3658 [(set_attr "jirl" "indirect")])
3660 (define_insn "sibcall_value_multiple_internal"
3661 [(set (match_operand 0 "register_operand" "")
3662 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3663 (match_operand 2 "" "")))
3664 (set (match_operand 3 "register_operand" "")
3665 (call (mem:SI (match_dup 1))
3667 "SIBLING_CALL_P (insn)"
3669 switch (which_alternative)
3674 if (TARGET_CMODEL_MEDIUM)
3675 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3679 if (TARGET_CMODEL_MEDIUM)
3680 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3682 return "b\t%%plt(%1)";
3687 [(set_attr "jirl" "indirect,direct,direct")])
3689 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3690 [(set (match_operand 0 "register_operand" "")
3691 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3692 (match_operand:P 2 "symbolic_operand" "")]
3693 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3694 (match_operand 3 "" "")))
3695 (set (match_operand 4 "register_operand" "")
3696 (call (mem:P (unspec:P [(match_dup 1)
3698 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3700 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3701 "jirl\t$r0,%1,%%pc_lo12(%2)"
3702 [(set_attr "jirl" "indirect")])
3704 (define_expand "call"
3705 [(parallel [(call (match_operand 0 "")
3706 (match_operand 1 ""))
3707 (use (match_operand 2 "")) ;; next_arg_reg
3708 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3711 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3713 if (GET_CODE (target) == LO_SUM)
3714 emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3715 XEXP (target, 1), operands[1]));
3717 emit_call_insn (gen_call_internal (target, operands[1]));
3721 (define_insn "call_internal"
3722 [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3723 (match_operand 1 "" ""))
3724 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3727 switch (which_alternative)
3730 return "jirl\t$r1,%0,0";
3732 if (TARGET_CMODEL_MEDIUM)
3733 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3737 if (TARGET_CMODEL_MEDIUM)
3738 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3740 return "bl\t%%plt(%0)";
3745 [(set_attr "jirl" "indirect,direct,direct")])
3747 (define_insn "@call_internal_1<mode>"
3748 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3749 (match_operand:P 1 "symbolic_operand" "")))
3750 (match_operand 2 "" ""))
3751 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3752 "TARGET_CMODEL_MEDIUM"
3753 "jirl\t$r1,%0,%%pc_lo12(%1)"
3754 [(set_attr "jirl" "indirect")])
3756 (define_expand "call_value"
3757 [(parallel [(set (match_operand 0 "")
3758 (call (match_operand 1 "")
3759 (match_operand 2 "")))
3760 (use (match_operand 3 ""))])] ;; next_arg_reg
3763 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3764 /* Handle return values created by loongarch_pass_fpr_pair. */
3765 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3767 rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
3768 rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
3770 if (GET_CODE (target) == LO_SUM)
3771 emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
3774 operands[2], arg2));
3776 emit_call_insn (gen_call_value_multiple_internal (arg1, target,
3777 operands[2], arg2));
3781 /* Handle return values created by loongarch_return_fpr_single. */
3782 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3783 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3785 if (GET_CODE (target) == LO_SUM)
3786 emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
3791 emit_call_insn (gen_call_value_internal (operands[0], target,
3797 (define_insn "call_value_internal"
3798 [(set (match_operand 0 "register_operand" "")
3799 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3800 (match_operand 2 "" "")))
3801 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3804 switch (which_alternative)
3807 return "jirl\t$r1,%1,0";
3809 if (TARGET_CMODEL_MEDIUM)
3810 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3814 if (TARGET_CMODEL_MEDIUM)
3815 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3817 return "bl\t%%plt(%1)";
3822 [(set_attr "jirl" "indirect,direct,direct")])
3824 (define_insn "@call_value_internal_1<mode>"
3825 [(set (match_operand 0 "register_operand" "")
3826 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3827 (match_operand:P 2 "symbolic_operand" "")))
3828 (match_operand 3 "" "")))
3829 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3830 "TARGET_CMODEL_MEDIUM"
3831 "jirl\t$r1,%1,%%pc_lo12(%2)"
3832 [(set_attr "jirl" "indirect")])
3834 (define_insn "call_value_multiple_internal"
3835 [(set (match_operand 0 "register_operand" "")
3836 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3837 (match_operand 2 "" "")))
3838 (set (match_operand 3 "register_operand" "")
3839 (call (mem:SI (match_dup 1))
3841 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3844 switch (which_alternative)
3847 return "jirl\t$r1,%1,0";
3849 if (TARGET_CMODEL_MEDIUM)
3850 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3854 if (TARGET_CMODEL_MEDIUM)
3855 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3857 return "bl\t%%plt(%1)";
3862 [(set_attr "jirl" "indirect,direct,direct")])
3864 (define_insn "@call_value_multiple_internal_1<mode>"
3865 [(set (match_operand 0 "register_operand" "")
3866 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3867 (match_operand:P 2 "symbolic_operand" "")]
3868 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3869 (match_operand 3 "" "")))
3870 (set (match_operand 4 "register_operand" "")
3871 (call (mem:P (unspec:P [(match_dup 1)
3873 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3875 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3876 "TARGET_CMODEL_MEDIUM"
3877 "jirl\t$r1,%1,%%pc_lo12(%2)"
3878 [(set_attr "jirl" "indirect")])
3881 ;; Call subroutine returning any type.
3882 (define_expand "untyped_call"
3883 [(parallel [(call (match_operand 0 "")
3885 (match_operand 1 "")
3886 (match_operand 2 "")])]
3891 emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
3893 for (i = 0; i < XVECLEN (operands[2], 0); i++)
3895 rtx set = XVECEXP (operands[2], 0, i);
3896 loongarch_emit_move (SET_DEST (set), SET_SRC (set));
3899 emit_insn (gen_blockage ());
3904 ;; ....................
3908 ;; ....................
3911 (define_insn "prefetch"
3912 [(prefetch (match_operand 0 "address_operand" "ZD")
3913 (match_operand 1 "const_int_operand" "n")
3914 (match_operand 2 "const_int_operand" "n"))]
3917 switch (INTVAL (operands[1]))
3919 case 0: return "preld\t0,%a0";
3920 case 1: return "preld\t8,%a0";
3921 default: gcc_unreachable ();
3929 [(set_attr "type" "nop")
3930 (set_attr "mode" "none")])
3932 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
3933 (define_insn "loongarch_movfcsr2gr"
3934 [(set (match_operand:SI 0 "register_operand" "=r")
3935 (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
3936 UNSPECV_MOVFCSR2GR))]
3938 "movfcsr2gr\t%0,$r%1")
3940 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
3941 (define_insn "loongarch_movgr2fcsr"
3942 [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
3943 (match_operand:SI 1 "register_operand" "r")]
3944 UNSPECV_MOVGR2FCSR)]
3946 "movgr2fcsr\t$r%0,%1")
3948 (define_insn "fclass_<fmt>"
3949 [(set (match_operand:ANYF 0 "register_operand" "=f")
3950 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
3953 "fclass.<fmt>\t%0,%1"
3954 [(set_attr "type" "unknown")
3955 (set_attr "mode" "<MODE>")])
3957 (define_insn "bytepick_w_<bytepick_imm>"
3958 [(set (match_operand:SI 0 "register_operand" "=r")
3959 (ior:SI (lshiftrt (match_operand:SI 1 "register_operand" "r")
3960 (const_int <bytepick_w_lshiftrt_amount>))
3961 (ashift (match_operand:SI 2 "register_operand" "r")
3962 (const_int bytepick_w_ashift_amount))))]
3964 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
3965 [(set_attr "mode" "SI")])
3967 (define_insn "bytepick_w_<bytepick_imm>_extend"
3968 [(set (match_operand:DI 0 "register_operand" "=r")
3970 (ior:SI (lshiftrt (match_operand:SI 1 "register_operand" "r")
3971 (const_int <bytepick_w_lshiftrt_amount>))
3972 (ashift (match_operand:SI 2 "register_operand" "r")
3973 (const_int bytepick_w_ashift_amount)))))]
3975 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
3976 [(set_attr "mode" "SI")])
3978 (define_insn "bytepick_d_<bytepick_imm>"
3979 [(set (match_operand:DI 0 "register_operand" "=r")
3980 (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
3981 (const_int <bytepick_d_lshiftrt_amount>))
3982 (ashift (match_operand:DI 2 "register_operand" "r")
3983 (const_int bytepick_d_ashift_amount))))]
3985 "bytepick.d\t%0,%1,%2,<bytepick_imm>"
3986 [(set_attr "mode" "DI")])
3988 (define_insn "bitrev_4b"
3989 [(set (match_operand:SI 0 "register_operand" "=r")
3990 (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
3994 [(set_attr "type" "unknown")
3995 (set_attr "mode" "SI")])
3997 (define_insn "bitrev_8b"
3998 [(set (match_operand:DI 0 "register_operand" "=r")
3999 (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4003 [(set_attr "type" "unknown")
4004 (set_attr "mode" "DI")])
4006 (define_insn "@stack_tie<mode>"
4007 [(set (mem:BLK (scratch))
4008 (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4009 (match_operand:X 1 "register_operand" "r")]
4013 [(set_attr "length" "0")
4014 (set_attr "type" "ghost")])
4016 ;; Named pattern for expanding thread pointer reference.
4017 (define_expand "get_thread_pointer<mode>"
4018 [(set (match_operand:P 0 "register_operand" "=r")
4024 [(match_operand 0 "small_data_pattern")]
4027 { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4030 ;; Match paired HI/SI/SF/DFmode load/stores.
4031 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4032 [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4034 (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4035 (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4037 (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4040 /* The load destination does not overlap the source. */
4041 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4042 output_asm_insn (loongarch_output_move (operands[0], operands[1]),
4044 output_asm_insn (loongarch_output_move (operands[2], operands[3]),
4048 [(set_attr "move_type"
4049 "load,fpload,store,fpstore,load,store")
4050 (set_attr "insn_count" "2,2,2,2,2,2")])
4052 ;; 2 HI/SI/SF/DF loads are bonded.
4054 [(set (match_operand:JOIN_MODE 0 "register_operand")
4055 (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4056 (set (match_operand:JOIN_MODE 2 "register_operand")
4057 (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4058 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4059 [(parallel [(set (match_dup 0)
4065 ;; 2 HI/SI/SF/DF stores are bonded.
4067 [(set (match_operand:JOIN_MODE 0 "memory_operand")
4068 (match_operand:JOIN_MODE 1 "register_operand"))
4069 (set (match_operand:JOIN_MODE 2 "memory_operand")
4070 (match_operand:JOIN_MODE 3 "register_operand"))]
4071 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4072 [(parallel [(set (match_dup 0)
4078 ;; Match paired HImode loads.
4079 (define_insn "*join2_loadhi"
4080 [(set (match_operand:SI 0 "register_operand" "=&r")
4081 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4082 (set (match_operand:SI 2 "register_operand" "=r")
4083 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4086 /* The load destination does not overlap the source. */
4087 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4088 output_asm_insn ("ld.h<u>\t%0,%1", operands);
4089 output_asm_insn ("ld.h<u>\t%2,%3", operands);
4093 [(set_attr "move_type" "load")
4094 (set_attr "insn_count" "2")])
4097 ;; 2 HI loads are bonded.
4099 [(set (match_operand:SI 0 "register_operand")
4100 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4101 (set (match_operand:SI 2 "register_operand")
4102 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4103 "loongarch_load_store_bonding_p (operands, HImode, true)"
4104 [(parallel [(set (match_dup 0)
4105 (any_extend:SI (match_dup 1)))
4107 (any_extend:SI (match_dup 3)))])]
4112 (define_mode_iterator QHSD [QI HI SI DI])
4114 (define_insn "loongarch_crc_w_<size>_w"
4115 [(set (match_operand:SI 0 "register_operand" "=r")
4116 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4117 (match_operand:SI 2 "register_operand" "r")]
4120 "crc.w.<size>.w\t%0,%1,%2"
4121 [(set_attr "type" "unknown")
4122 (set_attr "mode" "<MODE>")])
4124 (define_insn "loongarch_crcc_w_<size>_w"
4125 [(set (match_operand:SI 0 "register_operand" "=r")
4126 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4127 (match_operand:SI 2 "register_operand" "r")]
4130 "crcc.w.<size>.w\t%0,%1,%2"
4131 [(set_attr "type" "unknown")
4132 (set_attr "mode" "<MODE>")])
4134 ;; With normal or medium code models, if the only use of a pc-relative
4135 ;; address is for loading or storing a value, then relying on linker
4136 ;; relaxation is not better than emitting the machine instruction directly.
4137 ;; Even if the la.local pseudo op can be relaxed, we get:
4139 ;; pcaddi $t0, %pcrel_20(x)
4142 ;; There are still two instructions, same as using the machine instructions
4143 ;; and explicit relocs:
4145 ;; pcalau12i $t0, %pc_hi20(x)
4146 ;; ld.d $t0, $t0, %pc_lo12(x)
4148 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4150 (define_insn_and_rewrite "simple_load<mode>"
4151 [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4152 (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4153 "loongarch_pre_reload_split ()
4154 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4155 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4159 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4162 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4163 [(set (match_operand:GPR 0 "register_operand" "=r")
4165 (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4166 "loongarch_pre_reload_split ()
4167 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4168 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4172 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4175 (define_insn_and_rewrite "simple_store<mode>"
4176 [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4177 (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4178 "loongarch_pre_reload_split ()
4179 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4180 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4184 operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4187 ;; Synchronization instructions.
4191 (include "generic.md")
4192 (include "la464.md")
4194 ; The LoongArch SIMD Instructions.
4197 (define_c_enum "unspec" [
4198 UNSPEC_ADDRESS_FIRST