1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C) 2021-2025 Free Software Foundation, Inc.
3 ;; Contributed by Loongson Ltd.
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3. If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23 ;; Floating-point moves.
30 ;; Floating point unspecs.
41 ;; Override return address for exception handling.
70 UNSPEC_ADD_TLS_LE_RELAX
77 ;; Fake div.w[u] mod.w[u]
80 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
81 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
83 UNSPEC_LOAD_SYMBOL_OFFSET64
84 UNSPEC_LA_PCREL_64_PART1
85 UNSPEC_LA_PCREL_64_PART2
88 (define_c_enum "unspecv" [
89 ;; Blockage and synchronisation.
94 ;; Privileged instructions
106 UNSPECV_PROBE_STACK_RANGE
108 ;; Floating-point environment.
121 [(RETURN_ADDR_REGNUM 1)
136 ;; Return path styles
141 ;; PIC long branch sequences are never longer than 100 bytes.
142 (MAX_PIC_BRANCH_LENGTH 100)
145 (include "predicates.md")
146 (include "constraints.md")
148 ;; ....................
152 ;; ....................
154 (define_attr "enabled" "no,yes" (const_string "yes"))
156 (define_attr "got" "unset,load"
157 (const_string "unset"))
159 ;; For jirl instructions, this attribute is DIRECT when the target address
160 ;; is symbolic and INDIRECT when it is a register.
161 (define_attr "jirl" "unset,direct,indirect"
162 (const_string "unset"))
165 ;; Classification of moves, extensions and truncations. Most values
166 ;; are as for "type" (see below) but there are also the following
167 ;; move-specific values:
169 ;; sll0 "slli.w DEST,SRC,0", which on 64-bit targets is guaranteed
170 ;; to produce a sign-extended DEST, even if SRC is not
171 ;; properly sign-extended
172 ;; pick_ins BSTRPICK.W, BSTRPICK.D, BSTRINS.W or BSTRINS.D instruction
173 ;; andi a single ANDI instruction
174 ;; shift_shift a shift left followed by a shift right
176 ;; This attribute is used to determine the instruction's length and
177 ;; scheduling type. For doubleword moves, the attribute always describes
178 ;; the split instructions; in some cases, it is more appropriate for the
179 ;; scheduling type to be "multi" instead.
180 (define_attr "move_type"
181 "unknown,load,fpload,store,fpstore,mgtf,mftg,imul,move,fmove,
182 const,signext,pick_ins,logical,arith,sll0,andi,shift_shift"
183 (const_string "unknown"))
185 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor,simd_add"
186 (const_string "unknown"))
188 ;; Main data type used by the insn
189 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FCC,
190 V2DI,V4SI,V8HI,V16QI,V2DF,V4SF,V4DI,V8SI,V16HI,V32QI,V4DF,V8SF"
191 (const_string "unknown"))
193 ;; True if the main data type is twice the size of a word.
194 (define_attr "dword_mode" "no,yes"
195 (cond [(and (eq_attr "mode" "DI,DF")
196 (not (match_test "TARGET_64BIT")))
199 (and (eq_attr "mode" "TI,TF")
200 (match_test "TARGET_64BIT"))
201 (const_string "yes")]
202 (const_string "no")))
204 ;; True if the main data type is four times of the size of a word.
205 (define_attr "qword_mode" "no,yes"
206 (cond [(and (eq_attr "mode" "TI,TF")
207 (not (match_test "TARGET_64BIT")))
208 (const_string "yes")]
209 (const_string "no")))
211 ;; Classification of each insn.
212 ;; branch conditional branch
213 ;; jump unconditional jump
214 ;; call unconditional call
215 ;; load load instruction(s)
216 ;; fpload floating point load
217 ;; fpidxload floating point indexed load
218 ;; store store instruction(s)
219 ;; fpstore floating point store
220 ;; fpidxstore floating point indexed store
221 ;; prefetch memory prefetch (register + offset)
222 ;; prefetchx memory indexed prefetch (register + register)
223 ;; condmove conditional moves
224 ;; mgtf move general-purpose register to floating point register
225 ;; mftg move floating point register to general-purpose register
226 ;; const load constant
227 ;; arith integer arithmetic instructions
228 ;; logical integer logical instructions
229 ;; shift integer shift instructions
230 ;; slt set less than instructions
231 ;; signext sign extend instructions
232 ;; clz the clz and clo instructions
233 ;; trap trap if instructions
234 ;; imul integer multiply
235 ;; idiv integer divide
237 ;; fmove floating point register move
238 ;; fadd floating point add/subtract
239 ;; fmul floating point multiply
240 ;; fmadd floating point multiply-add
241 ;; fdiv floating point divide
242 ;; frdiv floating point reciprocal divide
243 ;; frecipe floating point approximate reciprocal
244 ;; fabs floating point absolute value
245 ;; flogb floating point exponent extract
246 ;; fneg floating point negation
247 ;; fcmp floating point compare
248 ;; fcopysign floating point copysign
249 ;; fcvt floating point convert
250 ;; fscaleb floating point scale
251 ;; fsqrt floating point square root
252 ;; frsqrt floating point reciprocal square root
253 ;; frsqrte floating point approximate reciprocal square root
254 ;; multi multiword sequence (or user asm statements)
255 ;; atomic atomic memory update instruction
256 ;; syncloop memory atomic operation implemented as a sync loop
258 ;; ghost an instruction that produces no real code
260 "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
261 prefetch,prefetchx,condmove,mgtf,mftg,const,arith,logical,
262 shift,slt,signext,clz,trap,imul,idiv,move,
263 fmove,fadd,fmul,fmadd,fdiv,frdiv,frecipe,fabs,flogb,fneg,fcmp,fcopysign,fcvt,
264 fscaleb,fsqrt,frsqrt,frsqrte,accext,accmod,multi,atomic,syncloop,nop,ghost,
265 simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
266 simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
267 simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
268 simd_permute,simd_shf,simd_sat,simd_pcnt,simd_copy,simd_branch,simd_clsx,
269 simd_fminmax,simd_logic,simd_move,simd_load,simd_store"
270 (cond [(eq_attr "jirl" "!unset") (const_string "call")
271 (eq_attr "got" "load") (const_string "load")
273 (eq_attr "alu_type" "add,sub") (const_string "arith")
275 (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical")
277 ;; If a doubleword move uses these expensive instructions,
278 ;; it is usually better to schedule them in the same way
279 ;; as the singleword form, rather than as "multi".
280 (eq_attr "move_type" "load") (const_string "load")
281 (eq_attr "move_type" "fpload") (const_string "fpload")
282 (eq_attr "move_type" "store") (const_string "store")
283 (eq_attr "move_type" "fpstore") (const_string "fpstore")
284 (eq_attr "move_type" "mgtf") (const_string "mgtf")
285 (eq_attr "move_type" "mftg") (const_string "mftg")
287 ;; These types of move are always single insns.
288 (eq_attr "move_type" "imul") (const_string "imul")
289 (eq_attr "move_type" "fmove") (const_string "fmove")
290 (eq_attr "move_type" "signext") (const_string "signext")
291 (eq_attr "move_type" "pick_ins") (const_string "arith")
292 (eq_attr "move_type" "arith") (const_string "arith")
293 (eq_attr "move_type" "logical") (const_string "logical")
294 (eq_attr "move_type" "sll0") (const_string "shift")
295 (eq_attr "move_type" "andi") (const_string "logical")
297 ;; These types of move are always split.
298 (eq_attr "move_type" "shift_shift")
299 (const_string "multi")
301 ;; These types of move are split for quadword modes only.
302 (and (eq_attr "move_type" "move,const")
303 (eq_attr "qword_mode" "yes"))
304 (const_string "multi")
306 ;; These types of move are split for doubleword modes only.
307 (and (eq_attr "move_type" "move,const")
308 (eq_attr "dword_mode" "yes"))
309 (const_string "multi")
310 (eq_attr "move_type" "move") (const_string "move")
311 (eq_attr "move_type" "const") (const_string "const")]
312 (const_string "unknown")))
314 ;; Mode for conversion types (fcvt)
315 ;; I2S integer to float single (SI/DI to SF)
316 ;; I2D integer to float double (SI/DI to DF)
317 ;; S2I float to integer (SF to SI/DI)
318 ;; D2I float to integer (DF to SI/DI)
319 ;; D2S double to float single
320 ;; S2D float single to double
322 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
323 (const_string "unknown"))
325 ;; The number of individual instructions that a non-branch pattern generates
326 (define_attr "insn_count" ""
327 (cond [;; "Ghost" instructions occupy no space.
328 (eq_attr "type" "ghost")
331 ;; Check for doubleword moves that are decomposed into two
333 (and (eq_attr "move_type" "mgtf,mftg,move")
334 (eq_attr "dword_mode" "yes"))
337 ;; Check for quadword moves that are decomposed into four
339 (and (eq_attr "move_type" "mgtf,mftg,move")
340 (eq_attr "qword_mode" "yes"))
343 ;; Constants, loads and stores are handled by external routines.
344 (and (eq_attr "move_type" "const")
345 (eq_attr "dword_mode" "yes"))
346 (symbol_ref "loongarch_split_const_insns (operands[1])")
347 (eq_attr "move_type" "const")
348 (symbol_ref "loongarch_const_insns (operands[1])")
349 (eq_attr "move_type" "load,fpload")
350 (symbol_ref "loongarch_load_store_insns (operands[1], insn)")
351 (eq_attr "move_type" "store,fpstore")
352 (symbol_ref "loongarch_load_store_insns (operands[0], insn)")
354 (eq_attr "type" "idiv")
355 (symbol_ref "loongarch_idiv_insns (GET_MODE (PATTERN (insn)))")]
358 ;; Length of instruction in bytes.
359 (define_attr "length" ""
361 ;; Branch futher than +/- 128 KiB require two instructions.
362 (eq_attr "type" "branch")
363 (if_then_else (and (le (minus (match_dup 0) (pc)) (const_int 131064))
364 (le (minus (pc) (match_dup 0)) (const_int 131068)))
367 (symbol_ref "get_attr_insn_count (insn) * 4")))
369 ;; Describe a user's asm statement.
370 (define_asm_attributes
371 [(set_attr "type" "multi")])
373 ;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated
374 ;; from the same template.
375 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
377 ;; A copy of GPR that can be used when a pattern has two independent
379 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
381 ;; This mode iterator allows 16-bit and 32-bit GPR patterns and 32-bit 64-bit
382 ;; FPR patterns to be generated from the same template.
383 (define_mode_iterator JOIN_MODE [HI
385 (SF "TARGET_HARD_FLOAT")
386 (DF "TARGET_DOUBLE_FLOAT")])
388 ;; This mode iterator allows :P to be used for patterns that operate on
389 ;; pointer-sized quantities. Exactly one of the two alternatives will match.
390 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
392 ;; Likewise, but for GRLEN-sized quantities.
393 (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
395 ;; 64-bit modes for which we provide move patterns.
396 (define_mode_iterator MOVE64 [DI DF])
398 ;; Iterator for sub-32-bit integer modes.
399 (define_mode_iterator SHORT [QI HI])
401 ;; Likewise the 64-bit truncate-and-shift patterns.
402 (define_mode_iterator SUBDI [QI HI SI])
404 ;; Iterator for scalar fixed point modes.
405 (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
407 ;; Iterator for hardware-supported floating-point modes.
408 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
409 (DF "TARGET_DOUBLE_FLOAT")])
411 ;; Iterator for fixed-point modes which can be hold by a hardware
412 ;; floating-point register.
413 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
414 (DI "TARGET_DOUBLE_FLOAT")])
416 ;; A mode for anything with 32 bits or more, and able to be loaded with
417 ;; the same addressing mode as ld.w.
418 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
420 ;; A mode for anything able to be stored with the same addressing mode as
422 (define_mode_iterator ST_ANY [QHWD ANYF])
424 ;; A mode for anything legal as a input of a div or mod instruction.
425 (define_mode_iterator DIV [(DI "TARGET_64BIT")
426 (SI "!TARGET_64BIT || ISA_HAS_DIV32")])
428 ;; In GPR templates, a string like "mul.<d>" will expand to "mul.w" in the
429 ;; 32-bit version and "mul.d" in the 64-bit version.
430 (define_mode_attr d [(SI "w") (DI "d")])
432 ;; This attribute gives the length suffix for a load or store instruction.
433 ;; The same suffixes work for zero and sign extensions.
434 (define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")])
435 (define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")])
437 ;; This attribute gives the mode mask of a SHORT.
438 (define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
440 ;; This attribute gives the size (bits) of a SHORT.
441 (define_mode_attr 7_or_15 [(QI "7") (HI "15")])
443 ;; Instruction names for stores.
444 (define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
446 ;; This attribute gives the format suffix for floating-point operations.
447 (define_mode_attr fmt [(SF "s") (DF "d")])
448 (define_mode_attr ifmt [(SI "w") (DI "l")])
450 ;; This attribute gives the upper-case mode name for one unit of a
451 ;; floating-point mode or vector mode.
452 (define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF") (V4SF "SF")
453 (V16QI "QI") (V8HI "HI") (V4SI "SI") (V2DI "DI")
454 (V2DF "DF")(V8SF "SF")(V32QI "QI")(V16HI "HI")(V8SI "SI")(V4DI "DI")(V4DF "DF")])
456 ;; As above, but in lower case.
457 (define_mode_attr unitmode [(SF "sf") (DF "df") (V2SF "sf") (V4SF "sf")
458 (V16QI "qi") (V8QI "qi") (V8HI "hi") (V4HI "hi")
459 (V4SI "si") (V2SI "si") (V2DI "di") (V2DF "df")
460 (V8SI "si") (V4DI "di") (V32QI "qi") (V16HI "hi")
461 (V8SF "sf") (V4DF "df")])
463 ;; This attribute gives the integer mode that has half the size of
464 ;; the controlling mode.
465 (define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
466 (V2SI "SI") (V4HI "SI") (V8QI "SI")
469 ;; This attribute gives the integer mode that has the same size of a
470 ;; floating-point mode.
471 (define_mode_attr IMODE [(SF "SI") (DF "DI")])
473 ;; This code iterator allows signed and unsigned widening multiplications
474 ;; to use the same template.
475 (define_code_iterator any_extend [sign_extend zero_extend])
477 ;; This code iterator allows the two right shift instructions to be
478 ;; generated from the same template.
479 (define_code_iterator any_shiftrt [ashiftrt lshiftrt])
481 ;; This code iterator allows the three shift instructions to be generated
482 ;; from the same template.
483 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
485 ;; This code iterator allows the three bitwise instructions to be generated
486 ;; from the same template.
487 (define_code_iterator any_bitwise [and ior xor])
488 (define_code_iterator any_or [ior xor])
489 (define_code_iterator neg_bitwise [and ior])
490 (define_code_attr bitwise_operand [(and "and_operand")
491 (ior "uns_arith_operand")
492 (xor "uns_arith_operand")])
493 (define_code_attr is_and [(and "true") (ior "false") (xor "false")])
495 ;; This code iterator allows unsigned and signed division to be generated
496 ;; from the same template.
497 (define_code_iterator any_div [div udiv mod umod])
499 ;; This code iterator allows addition and subtraction to be generated
500 ;; from the same template.
501 (define_code_iterator addsub [plus minus])
503 ;; This code iterator allows addition and multiplication to be generated
504 ;; from the same template.
505 (define_code_iterator addmul [plus mult])
507 ;; This code iterator allows addition subtraction and multiplication to be
508 ;; generated from the same template
509 (define_code_iterator addsubmul [plus minus mult])
511 ;; This code iterator allows all native floating-point comparisons to be
512 ;; generated from the same template.
513 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
514 ordered ltgt ne ge gt unge ungt])
516 ;; Equality operators.
517 (define_code_iterator equality_op [eq ne])
519 ;; These code iterators allow the signed and unsigned scc operations to use
520 ;; the same template.
521 (define_code_iterator any_gt [gt gtu])
522 (define_code_iterator any_lt [lt ltu])
523 (define_code_iterator any_le [le leu])
525 (define_code_iterator any_return [return simple_return])
527 ;; <u> expands to an empty string when doing a signed operation and
528 ;; "u" when doing an unsigned operation.
529 (define_code_attr u [(sign_extend "") (zero_extend "u")
536 (smax "") (umax "u")])
538 ;; <U> is like <u> except uppercase.
539 (define_code_attr U [(sign_extend "") (zero_extend "U")])
541 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
542 (define_code_attr su [(sign_extend "s") (zero_extend "u")
543 (smax "s") (umax "u")])
545 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
547 ;; <optab> expands to the name of the optab for a particular code.
548 (define_code_attr optab [(ashift "ashl")
563 (simple_return "simple_return")])
565 ;; <insn> expands to the name of the insn that implements a particular code.
566 (define_code_attr insn [(ashift "sll")
580 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
581 (define_code_attr fcond [(unordered "cun")
596 ;; The sel mnemonic to use depending on the condition test.
597 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
598 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
600 ;; Iterator and attributes for floating-point to fixed-point conversion
602 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
603 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
604 (UNSPEC_FTINTRM "lfloor")
605 (UNSPEC_FTINTRP "lceil")])
606 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
607 (UNSPEC_FTINTRM "rm")
608 (UNSPEC_FTINTRP "rp")])
610 ;; Iterator and attributes for bytepick.d
611 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
612 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
615 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
616 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
623 (define_int_attr bytepick_imm [(8 "1")
631 ;; Expand some 32-bit operations to si3_extend operations if TARGET_64BIT
632 ;; so the redundant sign extension can be removed if the output is used as
633 ;; an input of a bitwise operation. Note plus, rotl, and div are handled
635 (define_code_iterator shift_w [any_shift rotatert])
636 (define_code_iterator arith_w [minus mult])
638 (define_expand "<optab><mode>3"
639 [(set (match_operand:GPR 0 "register_operand" "=r")
640 (shift_w:GPR (match_operand:GPR 1 "register_operand" "r")
641 (match_operand:SI 2 "arith_operand" "rI")))]
644 if (TARGET_64BIT && <MODE>mode == SImode)
646 rtx t = gen_reg_rtx (DImode);
647 emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
648 t = gen_lowpart (SImode, t);
649 SUBREG_PROMOTED_VAR_P (t) = 1;
650 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
651 emit_move_insn (operands[0], t);
656 (define_expand "<optab><mode>3"
657 [(set (match_operand:GPR 0 "register_operand" "=r")
658 (arith_w:GPR (match_operand:GPR 1 "register_operand" "r")
659 (match_operand:GPR 2 "register_operand" "r")))]
662 if (TARGET_64BIT && <MODE>mode == SImode)
664 rtx t = gen_reg_rtx (DImode);
665 emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
666 t = gen_lowpart (SImode, t);
667 SUBREG_PROMOTED_VAR_P (t) = 1;
668 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
669 emit_move_insn (operands[0], t);
675 ;; ....................
679 ;; ....................
683 [(trap_if (const_int 1) (const_int 0))]
688 [(set_attr "type" "trap")])
693 ;; ....................
697 ;; ....................
700 (define_insn "add<mode>3"
701 [(set (match_operand:ANYF 0 "register_operand" "=f")
702 (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
703 (match_operand:ANYF 2 "register_operand" "f")))]
705 "fadd.<fmt>\t%0,%1,%2"
706 [(set_attr "type" "fadd")
707 (set_attr "mode" "<UNITMODE>")])
709 (define_insn_and_split "*addsi3"
710 [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
711 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
712 (match_operand:SI 2 "plus_si_operand"
719 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
720 return \"addu16i.d\t%0,%1,%2\";
722 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
723 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
724 [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
725 (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
727 loongarch_split_plus_constant (&operands[2], SImode);
729 [(set_attr "alu_type" "add")
730 (set_attr "mode" "SI")
731 (set_attr "insn_count" "1,1,2,1,2")])
733 (define_expand "addsi3"
734 [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
735 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
736 (match_operand:SI 2 "plus_si_operand" "r,I,La,Le,Lb")))]
739 if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
740 && ADDU16I_OPERAND (INTVAL (operands[2])))
742 rtx t1 = gen_reg_rtx (DImode);
743 rtx t2 = gen_reg_rtx (DImode);
744 rtx t3 = gen_reg_rtx (DImode);
745 emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
747 emit_insn (gen_adddi3 (t3, t1, t2));
748 t3 = gen_lowpart (SImode, t3);
749 emit_move_insn (operands[0], t3);
754 rtx t = gen_reg_rtx (DImode);
755 emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
756 t = gen_lowpart (SImode, t);
757 SUBREG_PROMOTED_VAR_P (t) = 1;
758 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
759 emit_move_insn (operands[0], t);
764 (define_insn_and_split "adddi3"
765 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
766 (plus:DI (match_operand:DI 1 "register_operand" "r,r,r,r,r,r")
767 (match_operand:DI 2 "plus_di_operand"
768 "r,I,La,Lb,Lc,Ld")))]
774 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
775 return \"addu16i.d\t%0,%1,%2\";
778 "&& CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
779 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
780 [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
781 (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
783 loongarch_split_plus_constant (&operands[2], DImode);
785 [(set_attr "alu_type" "add")
786 (set_attr "mode" "DI")
787 (set_attr "insn_count" "1,1,2,1,2,2")])
789 (define_insn_and_split "addsi3_extended"
790 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
792 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
793 (match_operand:SI 2 "plus_si_extend_operand"
801 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
802 [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
804 (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
807 loongarch_split_plus_constant (&operands[2], SImode);
809 [(set_attr "alu_type" "add")
810 (set_attr "mode" "SI")
811 (set_attr "insn_count" "1,1,2,2")])
815 ;; ....................
819 ;; ....................
822 (define_insn "sub<mode>3"
823 [(set (match_operand:ANYF 0 "register_operand" "=f")
824 (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
825 (match_operand:ANYF 2 "register_operand" "f")))]
827 "fsub.<fmt>\t%0,%1,%2"
828 [(set_attr "type" "fadd")
829 (set_attr "mode" "<UNITMODE>")])
831 (define_insn "*sub<mode>3"
832 [(set (match_operand:GPR 0 "register_operand" "=r")
833 (minus:GPR (match_operand:GPR 1 "register_operand" "r")
834 (match_operand:GPR 2 "register_operand" "r")))]
837 [(set_attr "alu_type" "sub")
838 (set_attr "mode" "<MODE>")])
841 (define_insn "subsi3_extend"
842 [(set (match_operand:DI 0 "register_operand" "=r")
844 (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
845 (match_operand:SI 2 "register_operand" "r"))))]
848 [(set_attr "type" "arith")
849 (set_attr "mode" "SI")])
852 ;; ....................
856 ;; ....................
859 (define_insn "mul<mode>3"
860 [(set (match_operand:ANYF 0 "register_operand" "=f")
861 (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
862 (match_operand:ANYF 2 "register_operand" "f")))]
864 "fmul.<fmt>\t%0,%1,%2"
865 [(set_attr "type" "fmul")
866 (set_attr "mode" "<MODE>")])
868 (define_insn "*mul<mode>3"
869 [(set (match_operand:GPR 0 "register_operand" "=r")
870 (mult:GPR (match_operand:GPR 1 "register_operand" "r")
871 (match_operand:GPR 2 "register_operand" "r")))]
874 [(set_attr "type" "imul")
875 (set_attr "mode" "<MODE>")])
877 (define_insn "mulsi3_extend"
878 [(set (match_operand:DI 0 "register_operand" "=r")
880 (mult:SI (match_operand:SI 1 "register_operand" "r")
881 (match_operand:SI 2 "register_operand" "r"))))]
884 [(set_attr "type" "imul")
885 (set_attr "mode" "SI")])
888 ;; ........................
890 ;; MULTIPLICATION HIGH-PART
892 ;; ........................
895 (define_expand "<u>mulditi3"
896 [(set (match_operand:TI 0 "register_operand")
897 (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
898 (any_extend:TI (match_operand:DI 2 "register_operand"))))]
901 rtx low = gen_reg_rtx (DImode);
902 emit_insn (gen_muldi3 (low, operands[1], operands[2]));
904 rtx high = gen_reg_rtx (DImode);
905 emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
907 emit_move_insn (gen_lowpart (DImode, operands[0]), low);
908 emit_move_insn (gen_highpart (DImode, operands[0]), high);
912 (define_insn "<su>muldi3_highpart"
913 [(set (match_operand:DI 0 "register_operand" "=r")
916 (mult:TI (any_extend:TI
917 (match_operand:DI 1 "register_operand" " r"))
919 (match_operand:DI 2 "register_operand" " r")))
922 "mulh.d<u>\t%0,%1,%2"
923 [(set_attr "type" "imul")
924 (set_attr "mode" "DI")])
926 (define_expand "<u>mulsidi3"
927 [(set (match_operand:DI 0 "register_operand")
928 (mult:DI (any_extend:DI
929 (match_operand:SI 1 "register_operand"))
931 (match_operand:SI 2 "register_operand"))))]
936 rtx temp = gen_reg_rtx (SImode);
937 emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
938 emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
939 operands[1], operands[2]));
940 emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
945 (define_insn "<u>mulsidi3_64bit"
946 [(set (match_operand:DI 0 "register_operand" "=r")
947 (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
948 (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
950 "mulw.d.w<u>\t%0,%1,%2"
951 [(set_attr "type" "imul")
952 (set_attr "mode" "DI")])
954 (define_insn "<su>mulsi3_highpart"
955 [(set (match_operand:SI 0 "register_operand" "=r")
958 (mult:DI (any_extend:DI
959 (match_operand:SI 1 "register_operand" " r"))
961 (match_operand:SI 2 "register_operand" " r")))
964 "mulh.w<u>\t%0,%1,%2"
965 [(set_attr "type" "imul")
966 (set_attr "mode" "SI")])
968 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
969 ;; sign extension by default, so the sign extension instruction can be
972 [(set (match_operand:SI 0 "register_operand")
975 (mult:DI (any_extend:DI
976 (match_operand:SI 1 "register_operand"))
978 (match_operand:SI 2 "register_operand")))
980 (set (match_operand:DI 3 "register_operand")
981 (sign_extend:DI (match_dup 0)))]
982 "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
983 "mulh.w<u>\t%0,%1,%2")
986 ;; ....................
988 ;; DIVISION and REMAINDER
990 ;; ....................
993 ;; Float division and modulus.
994 (define_expand "div<mode>3"
995 [(set (match_operand:ANYF 0 "register_operand")
996 (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
997 (match_operand:ANYF 2 "register_operand")))]
1000 if (<MODE>mode == SFmode
1002 && optimize_insn_for_speed_p ()
1003 && flag_finite_math_only && !flag_trapping_math
1004 && flag_unsafe_math_optimizations)
1006 loongarch_emit_swdivsf (operands[0], operands[1],
1007 operands[2], SFmode);
1012 (define_insn "*div<mode>3"
1013 [(set (match_operand:ANYF 0 "register_operand" "=f")
1014 (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
1015 (match_operand:ANYF 2 "register_operand" "f")))]
1017 "fdiv.<fmt>\t%0,%1,%2"
1018 [(set_attr "type" "fdiv")
1019 (set_attr "mode" "<UNITMODE>")])
1021 ;; In 3A5000, the reciprocal operation is the same as the division operation.
1023 (define_insn "*recip<mode>3"
1024 [(set (match_operand:ANYF 0 "register_operand" "=f")
1025 (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
1026 (match_operand:ANYF 2 "register_operand" "f")))]
1028 "frecip.<fmt>\t%0,%2"
1029 [(set_attr "type" "frdiv")
1030 (set_attr "mode" "<UNITMODE>")])
1032 ;; Approximate Reciprocal Instructions.
1034 (define_insn "loongarch_frecipe_<fmt>"
1035 [(set (match_operand:ANYF 0 "register_operand" "=f")
1036 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1039 "frecipe.<fmt>\t%0,%1"
1040 [(set_attr "type" "frecipe")
1041 (set_attr "mode" "<UNITMODE>")
1042 (set_attr "insn_count" "1")])
1044 ;; Integer division and modulus.
1045 (define_expand "<optab><mode>3"
1046 [(set (match_operand:GPR 0 "register_operand")
1047 (any_div:GPR (match_operand:GPR 1 "register_operand")
1048 (match_operand:GPR 2 "register_operand")))]
1051 if (GET_MODE (operands[0]) == SImode && TARGET_64BIT)
1055 rtx t = gen_reg_rtx (DImode);
1056 emit_insn (gen_<optab>si3_extended (t, operands[1], operands[2]));
1057 t = gen_lowpart (SImode, t);
1058 SUBREG_PROMOTED_VAR_P (t) = 1;
1059 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
1060 emit_move_insn (operands[0], t);
1064 rtx reg1 = gen_reg_rtx (DImode);
1065 rtx reg2 = gen_reg_rtx (DImode);
1066 rtx rd = gen_reg_rtx (DImode);
1068 operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
1069 operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
1071 emit_insn (gen_rtx_SET (reg1, operands[1]));
1072 emit_insn (gen_rtx_SET (reg2, operands[2]));
1074 emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
1075 emit_insn (gen_rtx_SET (operands[0],
1076 simplify_gen_subreg (SImode, rd, DImode, 0)));
1081 (define_insn "*<optab><mode>3"
1082 [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
1083 (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
1084 (match_operand:DIV 2 "register_operand" "r,r,r")))]
1087 return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
1089 [(set_attr "type" "idiv")
1090 (set_attr "mode" "<MODE>")
1091 (set (attr "enabled")
1093 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1094 (const_string "yes")
1095 (const_string "no")))])
1097 (define_insn "<optab>si3_extended"
1098 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1100 (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
1101 (match_operand:SI 2 "register_operand" "r,r,r"))))]
1102 "TARGET_64BIT && ISA_HAS_DIV32"
1104 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1106 [(set_attr "type" "idiv")
1107 (set_attr "mode" "SI")
1108 (set (attr "enabled")
1110 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1111 (const_string "yes")
1112 (const_string "no")))])
1114 (define_insn "<optab>di3_fake"
1115 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1119 (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1120 (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1121 UNSPEC_FAKE_ANY_DIV)))]
1122 "TARGET_64BIT && !ISA_HAS_DIV32"
1124 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1126 [(set_attr "type" "idiv")
1127 (set_attr "mode" "SI")
1128 (set (attr "enabled")
1130 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1131 (const_string "yes")
1132 (const_string "no")))])
1134 ;; Floating point multiply accumulate instructions.
1137 (define_insn "fma<mode>4"
1138 [(set (match_operand:ANYF 0 "register_operand" "=f")
1139 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1140 (match_operand:ANYF 2 "register_operand" "f")
1141 (match_operand:ANYF 3 "register_operand" "f")))]
1143 "fmadd.<fmt>\t%0,%1,%2,%3"
1144 [(set_attr "type" "fmadd")
1145 (set_attr "mode" "<UNITMODE>")])
1148 (define_insn "fms<mode>4"
1149 [(set (match_operand:ANYF 0 "register_operand" "=f")
1150 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1151 (match_operand:ANYF 2 "register_operand" "f")
1152 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1154 "fmsub.<fmt>\t%0,%1,%2,%3"
1155 [(set_attr "type" "fmadd")
1156 (set_attr "mode" "<UNITMODE>")])
1158 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1159 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1160 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1161 ;; This transformation means we may return the wrong signed zero
1162 ;; so we check HONOR_SIGNED_ZEROS.
1165 (define_insn "fnma<mode>4"
1166 [(set (match_operand:ANYF 0 "register_operand" "=f")
1167 (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1168 (match_operand:ANYF 2 "register_operand" "f")
1169 (match_operand:ANYF 3 "register_operand" "f")))]
1170 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1171 "fnmsub.<fmt>\t%0,%1,%2,%3"
1172 [(set_attr "type" "fmadd")
1173 (set_attr "mode" "<UNITMODE>")])
1175 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1176 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1177 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1178 ;; This transformation means we may return the wrong signed zero
1179 ;; so we check HONOR_SIGNED_ZEROS.
1182 (define_insn "fnms<mode>4"
1183 [(set (match_operand:ANYF 0 "register_operand" "=f")
1185 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1186 (match_operand:ANYF 2 "register_operand" "f")
1187 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1188 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1189 "fnmadd.<fmt>\t%0,%1,%2,%3"
1190 [(set_attr "type" "fmadd")
1191 (set_attr "mode" "<UNITMODE>")])
1193 ;; -(-a * b - c), modulo signed zeros
1194 (define_insn "*fma<mode>4"
1195 [(set (match_operand:ANYF 0 "register_operand" "=f")
1198 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1199 (match_operand:ANYF 2 "register_operand" " f")
1200 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1201 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1202 "fmadd.<fmt>\t%0,%1,%2,%3"
1203 [(set_attr "type" "fmadd")
1204 (set_attr "mode" "<UNITMODE>")])
1206 ;; -(-a * b + c), modulo signed zeros
1207 (define_insn "*fms<mode>4"
1208 [(set (match_operand:ANYF 0 "register_operand" "=f")
1211 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1212 (match_operand:ANYF 2 "register_operand" " f")
1213 (match_operand:ANYF 3 "register_operand" " f"))))]
1214 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1215 "fmsub.<fmt>\t%0,%1,%2,%3"
1216 [(set_attr "type" "fmadd")
1217 (set_attr "mode" "<UNITMODE>")])
1220 (define_insn "*fnms<mode>4"
1221 [(set (match_operand:ANYF 0 "register_operand" "=f")
1224 (match_operand:ANYF 1 "register_operand" " f")
1225 (match_operand:ANYF 2 "register_operand" " f")
1226 (match_operand:ANYF 3 "register_operand" " f"))))]
1228 "fnmadd.<fmt>\t%0,%1,%2,%3"
1229 [(set_attr "type" "fmadd")
1230 (set_attr "mode" "<UNITMODE>")])
1233 (define_insn "*fnma<mode>4"
1234 [(set (match_operand:ANYF 0 "register_operand" "=f")
1237 (match_operand:ANYF 1 "register_operand" " f")
1238 (match_operand:ANYF 2 "register_operand" " f")
1239 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1241 "fnmsub.<fmt>\t%0,%1,%2,%3"
1242 [(set_attr "type" "fmadd")
1243 (set_attr "mode" "<UNITMODE>")])
1246 ;; ....................
1250 ;; ....................
1252 (define_expand "sqrt<mode>2"
1253 [(set (match_operand:ANYF 0 "register_operand")
1254 (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1257 if (<MODE>mode == SFmode
1258 && TARGET_RECIP_SQRT
1259 && flag_unsafe_math_optimizations
1260 && !optimize_insn_for_size_p ()
1261 && flag_finite_math_only && !flag_trapping_math)
1263 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1268 (define_insn "*sqrt<mode>2"
1269 [(set (match_operand:ANYF 0 "register_operand" "=f")
1270 (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1272 "fsqrt.<fmt>\t%0,%1"
1273 [(set_attr "type" "fsqrt")
1274 (set_attr "mode" "<UNITMODE>")
1275 (set_attr "insn_count" "1")])
1277 (define_expand "rsqrt<mode>2"
1278 [(set (match_operand:ANYF 0 "register_operand")
1279 (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1283 if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1285 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1290 (define_insn "*rsqrt<mode>2"
1291 [(set (match_operand:ANYF 0 "register_operand" "=f")
1292 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1295 "frsqrt.<fmt>\t%0,%1"
1296 [(set_attr "type" "frsqrt")
1297 (set_attr "mode" "<UNITMODE>")])
1299 ;; Approximate Reciprocal Square Root Instructions.
1301 (define_insn "loongarch_frsqrte_<fmt>"
1302 [(set (match_operand:ANYF 0 "register_operand" "=f")
1303 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1306 "frsqrte.<fmt>\t%0,%1"
1307 [(set_attr "type" "frsqrte")
1308 (set_attr "mode" "<UNITMODE>")])
1311 ;; ....................
1315 ;; ....................
1317 (define_insn "abs<mode>2"
1318 [(set (match_operand:ANYF 0 "register_operand" "=f")
1319 (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1322 [(set_attr "type" "fabs")
1323 (set_attr "mode" "<UNITMODE>")])
1326 ;; ....................
1328 ;; FLOATING POINT COPYSIGN
1330 ;; ....................
1332 (define_insn "copysign<mode>3"
1333 [(set (match_operand:ANYF 0 "register_operand" "=f")
1334 (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1335 (match_operand:ANYF 2 "register_operand" "f")))]
1337 "fcopysign.<fmt>\t%0,%1,%2"
1338 [(set_attr "type" "fcopysign")
1339 (set_attr "mode" "<UNITMODE>")])
1341 (define_expand "@xorsign<mode>3"
1342 [(match_operand:ANYF 0 "register_operand")
1343 (match_operand:ANYF 1 "register_operand")
1344 (match_operand:ANYF 2 "register_operand")]
1347 machine_mode lsx_mode
1348 = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1349 rtx tmp = gen_reg_rtx (lsx_mode);
1350 rtx op1 = force_lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1351 rtx op2 = force_lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1352 emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1353 emit_move_insn (operands[0],
1354 lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1359 ;; ....................
1361 ;; FLOATING POINT SCALE
1363 ;; ....................
1365 (define_insn "ldexp<mode>3"
1366 [(set (match_operand:ANYF 0 "register_operand" "=f")
1367 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")
1368 (match_operand:<IMODE> 2 "register_operand" "f")]
1371 "fscaleb.<fmt>\t%0,%1,%2"
1372 [(set_attr "type" "fscaleb")
1373 (set_attr "mode" "<UNITMODE>")])
1376 ;; ....................
1378 ;; FLOATING POINT EXPONENT EXTRACT
1380 ;; ....................
1382 (define_insn "logb_non_negative<mode>2"
1383 [(set (match_operand:ANYF 0 "register_operand" "=f")
1384 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1387 "flogb.<fmt>\t%0,%1"
1388 [(set_attr "type" "flogb")
1389 (set_attr "mode" "<UNITMODE>")])
1391 (define_expand "logb<mode>2"
1392 [(set (match_operand:ANYF 0 "register_operand")
1393 (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1397 rtx tmp = gen_reg_rtx (<MODE>mode);
1399 emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1400 emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1405 ;; ...................
1407 ;; Count leading zeroes.
1409 ;; ...................
1412 (define_insn "clz<mode>2"
1413 [(set (match_operand:GPR 0 "register_operand" "=r")
1414 (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1417 [(set_attr "type" "clz")
1418 (set_attr "mode" "<MODE>")])
1421 ;; ...................
1423 ;; Count trailing zeroes.
1425 ;; ...................
1428 (define_insn "ctz<mode>2"
1429 [(set (match_operand:GPR 0 "register_operand" "=r")
1430 (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1433 [(set_attr "type" "clz")
1434 (set_attr "mode" "<MODE>")])
1437 ;; ....................
1441 ;; ....................
1443 (define_insn "smax<mode>3"
1444 [(set (match_operand:ANYF 0 "register_operand" "=f")
1445 (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1446 (match_operand:ANYF 2 "register_operand" "f")))]
1448 "fmax.<fmt>\t%0,%1,%2"
1449 [(set_attr "type" "fmove")
1450 (set_attr "mode" "<MODE>")])
1452 (define_insn "smin<mode>3"
1453 [(set (match_operand:ANYF 0 "register_operand" "=f")
1454 (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1455 (match_operand:ANYF 2 "register_operand" "f")))]
1457 "fmin.<fmt>\t%0,%1,%2"
1458 [(set_attr "type" "fmove")
1459 (set_attr "mode" "<MODE>")])
1461 (define_insn "fmax<mode>3"
1462 [(set (match_operand:ANYF 0 "register_operand" "=f")
1463 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1464 (use (match_operand:ANYF 2 "register_operand" "f"))]
1467 "fmax.<fmt>\t%0,%1,%2"
1468 [(set_attr "type" "fmove")
1469 (set_attr "mode" "<MODE>")])
1471 (define_insn "fmin<mode>3"
1472 [(set (match_operand:ANYF 0 "register_operand" "=f")
1473 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1474 (use (match_operand:ANYF 2 "register_operand" "f"))]
1477 "fmin.<fmt>\t%0,%1,%2"
1478 [(set_attr "type" "fmove")
1479 (set_attr "mode" "<MODE>")])
1481 (define_insn "smaxa<mode>3"
1482 [(set (match_operand:ANYF 0 "register_operand" "=f")
1484 (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1485 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1489 "fmaxa.<fmt>\t%0,%1,%2"
1490 [(set_attr "type" "fmove")
1491 (set_attr "mode" "<MODE>")])
1493 (define_insn "smina<mode>3"
1494 [(set (match_operand:ANYF 0 "register_operand" "=f")
1496 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1497 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1501 "fmina.<fmt>\t%0,%1,%2"
1502 [(set_attr "type" "fmove")
1503 (set_attr "mode" "<MODE>")])
1506 ;; ....................
1508 ;; NEGATION and ONE'S COMPLEMENT
1510 ;; ....................
1512 (define_insn "neg<mode>2"
1513 [(set (match_operand:GPR 0 "register_operand" "=r")
1514 (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1517 [(set_attr "alu_type" "sub")
1518 (set_attr "mode" "<MODE>")])
1520 (define_insn "*negsi2_extended"
1521 [(set (match_operand:DI 0 "register_operand" "=r")
1522 (sign_extend:DI (neg:SI (match_operand:SI 1 "register_operand" "r"))))]
1525 [(set_attr "alu_type" "sub")
1526 (set_attr "mode" "SI")])
1528 (define_insn "neg<mode>2"
1529 [(set (match_operand:ANYF 0 "register_operand" "=f")
1530 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1533 [(set_attr "type" "fneg")
1534 (set_attr "mode" "<UNITMODE>")])
1538 ;; ....................
1542 ;; ....................
1545 (define_insn "*<optab><mode>3"
1546 [(set (match_operand:GPR 0 "register_operand" "=r,r")
1547 (any_or:GPR (match_operand:GPR 1 "register_operand" "%r,r")
1548 (match_operand:GPR 2 "uns_arith_operand" "r,K")))]
1550 "<insn>%i2\t%0,%1,%2"
1551 [(set_attr "type" "logical")
1552 (set_attr "mode" "<MODE>")])
1554 (define_insn "*and<mode>3"
1555 [(set (match_operand:GPR 0 "register_operand" "=r,r,r,r")
1556 (and:GPR (match_operand:GPR 1 "register_operand" "%r,r,r,0")
1557 (match_operand:GPR 2 "and_operand" "r,K,Yx,Yy")))]
1562 * operands[2] = GEN_INT (INTVAL (operands[2]) \
1563 & GET_MODE_MASK (<MODE>mode)); \
1564 return \"bstrpick.<d>\t%0,%1,%M2\";
1565 * operands[2] = GEN_INT (~INTVAL (operands[2]) \
1566 & GET_MODE_MASK (<MODE>mode)); \
1567 return \"bstrins.<d>\t%0,%.,%M2\";"
1568 [(set_attr "move_type" "logical,logical,pick_ins,pick_ins")
1569 (set_attr "mode" "<MODE>")])
1571 (define_expand "<optab><mode>3"
1572 [(set (match_operand:X 0 "register_operand")
1573 (any_bitwise:X (match_operand:X 1 "register_operand")
1574 (match_operand:X 2 "<bitwise_operand>")))]
1577 (define_insn "one_cmpl<mode>2"
1578 [(set (match_operand:X 0 "register_operand" "=r")
1579 (not:X (match_operand:X 1 "register_operand" "r")))]
1582 [(set_attr "alu_type" "not")
1583 (set_attr "mode" "<MODE>")])
1585 (define_insn "*one_cmplsi2_internal"
1586 [(set (match_operand:SI 0 "register_operand" "=r")
1587 (not:SI (match_operand:SI 1 "register_operand" " r")))]
1590 [(set_attr "type" "logical")
1591 (set_attr "mode" "SI")])
1593 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1594 [(set (match_operand:GPR 0 "register_operand" "=r")
1595 (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand" "r")
1596 (match_operand:GPR 2 "const_int_operand" "i"))
1597 (and:GPR (match_operand:GPR 3 "register_operand" "r")
1598 (match_operand:GPR 4 "const_int_operand" "i"))))]
1599 "loongarch_pre_reload_split ()
1600 && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1603 [(set (match_dup 0) (match_dup 1))
1604 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1607 if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1609 std::swap (operands[1], operands[3]);
1610 std::swap (operands[2], operands[4]);
1613 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1614 int lo = ffs_hwi (mask) - 1;
1615 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1617 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1618 operands[2] = GEN_INT (len);
1619 operands[4] = GEN_INT (lo);
1623 rtx tmp = gen_reg_rtx (<MODE>mode);
1624 emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1630 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1631 ;; if possible, but the result may be sub-optimal when one of the masks
1632 ;; is (1 << N) - 1 and one of the src register is the dest register.
1636 ;; bstrins.d a0, t0, 42, 0
1638 ;; using a shift operation would be better:
1639 ;; srai.d t0, a1, 43
1640 ;; bstrins.d a0, t0, 63, 43
1642 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1643 ;; know if the dest register is one of the src register. Fix it up in
1646 [(set (match_operand:GPR 0 "register_operand")
1647 (match_operand:GPR 1 "register_operand"))
1648 (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1649 (set (zero_extract:GPR (match_dup 1)
1650 (match_operand:SI 3 "const_int_operand")
1653 "peep2_reg_dead_p (3, operands[0])"
1656 int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1658 emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1659 emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1664 (define_insn "*iorhi3"
1665 [(set (match_operand:HI 0 "register_operand" "=r,r")
1666 (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1667 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1670 [(set_attr "type" "logical")
1671 (set_attr "mode" "HI")])
1673 (define_insn "nor<mode>3"
1674 [(set (match_operand:X 0 "register_operand" "=r")
1675 (and:X (not:X (match_operand:X 1 "register_operand" "%r"))
1676 (not:X (match_operand:X 2 "register_operand" "r"))))]
1679 [(set_attr "type" "logical")
1680 (set_attr "mode" "<MODE>")])
1682 (define_insn "*norsi3_internal"
1683 [(set (match_operand:SI 0 "register_operand" "=r")
1684 (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
1685 (not:SI (match_operand:SI 2 "register_operand" "r"))))]
1688 [(set_attr "type" "logical")
1689 (set_attr "mode" "SI")])
1691 (define_insn "<optab>n<mode>3"
1692 [(set (match_operand:X 0 "register_operand" "=r")
1694 (not:X (match_operand:X 2 "register_operand" "r"))
1695 (match_operand:X 1 "register_operand" "r")))]
1698 [(set_attr "type" "logical")
1699 (set_attr "mode" "<MODE>")])
1701 (define_insn "*<optab>nsi_internal"
1702 [(set (match_operand:SI 0 "register_operand" "=r")
1704 (not:SI (match_operand:SI 1 "register_operand" "r"))
1705 (match_operand:SI 2 "register_operand" "r")))]
1708 [(set_attr "type" "logical")
1709 (set_attr "mode" "SI")])
1712 ;; ....................
1716 ;; ....................
1718 (define_insn "truncdfsf2"
1719 [(set (match_operand:SF 0 "register_operand" "=f")
1720 (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1721 "TARGET_DOUBLE_FLOAT"
1723 [(set_attr "type" "fcvt")
1724 (set_attr "cnv_mode" "D2S")
1725 (set_attr "mode" "SF")])
1727 ;; In vector registers, popcount can be implemented directly through
1728 ;; the vector instruction [X]VPCNT. For GP registers, we can implement
1729 ;; it through the following method. Compared with loop implementation
1730 ;; of popcount, the following method has better performance.
1732 ;; This attribute used for get connection of scalar mode and corresponding
1734 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1736 (define_expand "popcount<mode>2"
1737 [(set (match_operand:GPR 0 "register_operand")
1738 (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1741 rtx in = operands[1];
1742 rtx out = operands[0];
1743 rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1744 gen_reg_rtx (V2DImode);
1745 emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1746 emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1747 emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1752 ;; ....................
1756 ;; ....................
1757 (define_expand "zero_extendsidi2"
1758 [(set (match_operand:DI 0 "register_operand")
1759 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1762 (define_insn_and_split "*zero_extendsidi2_internal"
1763 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1764 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1767 bstrpick.d\t%0,%1,31,0
1771 "&& reload_completed
1772 && MEM_P (operands[1])
1773 && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1774 && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1775 && !paradoxical_subreg_p (operands[0])"
1776 [(set (match_dup 3) (match_dup 1))
1778 (ior:DI (zero_extend:DI
1779 (subreg:SI (match_dup 0) 0))
1782 operands[1] = gen_lowpart (SImode, operands[1]);
1783 operands[3] = gen_lowpart (SImode, operands[0]);
1784 operands[2] = const0_rtx;
1786 [(set_attr "move_type" "arith,load,load,load")
1787 (set_attr "mode" "DI")])
1789 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1790 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1792 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1795 bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1796 ld.<SHORT:size>u\t%0,%1
1797 ldx.<SHORT:size>u\t%0,%1"
1798 [(set_attr "move_type" "pick_ins,load,load")
1799 (set_attr "mode" "<GPR:MODE>")])
1801 (define_insn "zero_extendqihi2"
1802 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1803 (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1809 [(set_attr "move_type" "andi,load,load")
1810 (set_attr "mode" "HI")])
1812 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1814 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1815 [(set (match_operand:GPR 0 "register_operand" "=r")
1817 (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1819 "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1820 [(set_attr "move_type" "pick_ins")
1821 (set_attr "mode" "<GPR:MODE>")])
1823 (define_insn "*zero_extendhi_truncqi"
1824 [(set (match_operand:HI 0 "register_operand" "=r")
1826 (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1829 [(set_attr "alu_type" "and")
1830 (set_attr "mode" "HI")])
1833 ;; ....................
1837 ;; ....................
1839 (define_insn "extendsidi2"
1840 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
1842 (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k,f")))]
1850 [(set_attr "move_type" "sll0,load,load,load,mftg")
1851 (set_attr "mode" "DI")])
1853 (define_insn "extend<SHORT:mode><GPR:mode>2"
1854 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1856 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1859 ext.w.<SHORT:size>\t%0,%1
1860 ld.<SHORT:size>\t%0,%1
1861 ldx.<SHORT:size>\t%0,%1"
1862 [(set_attr "move_type" "signext,load,load")
1863 (set_attr "mode" "<GPR:MODE>")])
1865 (define_insn "extendqihi2"
1866 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1868 (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1874 [(set_attr "move_type" "signext,load,load")
1875 (set_attr "mode" "SI")])
1877 (define_insn "extendsfdf2"
1878 [(set (match_operand:DF 0 "register_operand" "=f")
1879 (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1880 "TARGET_DOUBLE_FLOAT"
1882 [(set_attr "type" "fcvt")
1883 (set_attr "cnv_mode" "S2D")
1884 (set_attr "mode" "DF")])
1887 ;; ....................
1891 ;; ....................
1893 ;; conversion of a floating-point value to a integer
1895 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1896 [(set (match_operand:GPR 0 "register_operand" "=f")
1897 (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1899 "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1900 [(set_attr "type" "fcvt")
1901 (set_attr "mode" "<ANYF:MODE>")])
1903 ;; conversion of an integeral (or boolean) value to a floating-point value
1905 (define_insn "floatsidf2"
1906 [(set (match_operand:DF 0 "register_operand" "=f")
1907 (float:DF (match_operand:SI 1 "register_operand" "f")))]
1908 "TARGET_DOUBLE_FLOAT"
1910 [(set_attr "type" "fcvt")
1911 (set_attr "mode" "DF")
1912 (set_attr "cnv_mode" "I2D")])
1914 (define_insn "floatdidf2"
1915 [(set (match_operand:DF 0 "register_operand" "=f")
1916 (float:DF (match_operand:DI 1 "register_operand" "f")))]
1917 "TARGET_DOUBLE_FLOAT"
1919 [(set_attr "type" "fcvt")
1920 (set_attr "mode" "DF")
1921 (set_attr "cnv_mode" "I2D")])
1923 (define_insn "floatsisf2"
1924 [(set (match_operand:SF 0 "register_operand" "=f")
1925 (float:SF (match_operand:SI 1 "register_operand" "f")))]
1928 [(set_attr "type" "fcvt")
1929 (set_attr "mode" "SF")
1930 (set_attr "cnv_mode" "I2S")])
1932 (define_insn "floatdisf2"
1933 [(set (match_operand:SF 0 "register_operand" "=f")
1934 (float:SF (match_operand:DI 1 "register_operand" "f")))]
1935 "TARGET_DOUBLE_FLOAT"
1937 [(set_attr "type" "fcvt")
1938 (set_attr "mode" "SF")
1939 (set_attr "cnv_mode" "I2S")])
1941 ;; Convert a floating-point value to an unsigned integer.
1943 (define_expand "fixuns_truncdfsi2"
1944 [(set (match_operand:SI 0 "register_operand")
1945 (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1946 "TARGET_DOUBLE_FLOAT"
1948 rtx reg1 = gen_reg_rtx (DFmode);
1949 rtx reg2 = gen_reg_rtx (DFmode);
1950 rtx reg3 = gen_reg_rtx (SImode);
1951 rtx_code_label *label1 = gen_label_rtx ();
1952 rtx_code_label *label2 = gen_label_rtx ();
1954 REAL_VALUE_TYPE offset;
1956 real_2expN (&offset, 31, DFmode);
1958 loongarch_emit_move (reg1,
1959 const_double_from_real_value (offset, DFmode));
1960 do_pending_stack_adjust ();
1962 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1963 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1965 emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1966 emit_jump_insn (gen_rtx_SET (pc_rtx,
1967 gen_rtx_LABEL_REF (VOIDmode, label2)));
1970 emit_label (label1);
1971 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1972 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1973 (BITMASK_HIGH, SImode)));
1975 emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1976 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1978 emit_label (label2);
1980 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1981 fields, and can't be used for REG_NOTES anyway). */
1982 emit_use (stack_pointer_rtx);
1986 (define_expand "fixuns_truncdfdi2"
1987 [(set (match_operand:DI 0 "register_operand")
1988 (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
1989 "TARGET_DOUBLE_FLOAT"
1991 rtx reg1 = gen_reg_rtx (DFmode);
1992 rtx reg2 = gen_reg_rtx (DFmode);
1993 rtx reg3 = gen_reg_rtx (DImode);
1994 rtx_code_label *label1 = gen_label_rtx ();
1995 rtx_code_label *label2 = gen_label_rtx ();
1997 REAL_VALUE_TYPE offset;
1999 real_2expN (&offset, 63, DFmode);
2001 loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
2002 do_pending_stack_adjust ();
2004 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2005 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
2007 emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
2008 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2011 emit_label (label1);
2012 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
2013 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2014 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2016 emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
2017 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2019 emit_label (label2);
2021 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2022 fields, and can't be used for REG_NOTES anyway). */
2023 emit_use (stack_pointer_rtx);
2027 (define_expand "fixuns_truncsfsi2"
2028 [(set (match_operand:SI 0 "register_operand")
2029 (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
2032 rtx reg1 = gen_reg_rtx (SFmode);
2033 rtx reg2 = gen_reg_rtx (SFmode);
2034 rtx reg3 = gen_reg_rtx (SImode);
2035 rtx_code_label *label1 = gen_label_rtx ();
2036 rtx_code_label *label2 = gen_label_rtx ();
2038 REAL_VALUE_TYPE offset;
2040 real_2expN (&offset, 31, SFmode);
2042 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2043 do_pending_stack_adjust ();
2045 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2046 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2048 emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
2049 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2052 emit_label (label1);
2053 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2054 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
2055 (BITMASK_HIGH, SImode)));
2057 emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
2058 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
2060 emit_label (label2);
2062 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2063 fields, and can't be used for REG_NOTES anyway). */
2064 emit_use (stack_pointer_rtx);
2068 (define_expand "fixuns_truncsfdi2"
2069 [(set (match_operand:DI 0 "register_operand")
2070 (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
2071 "TARGET_DOUBLE_FLOAT"
2073 rtx reg1 = gen_reg_rtx (SFmode);
2074 rtx reg2 = gen_reg_rtx (SFmode);
2075 rtx reg3 = gen_reg_rtx (DImode);
2076 rtx_code_label *label1 = gen_label_rtx ();
2077 rtx_code_label *label2 = gen_label_rtx ();
2079 REAL_VALUE_TYPE offset;
2081 real_2expN (&offset, 63, SFmode);
2083 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2084 do_pending_stack_adjust ();
2086 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2087 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2089 emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
2090 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2093 emit_label (label1);
2094 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2095 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2096 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2098 emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
2099 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2101 emit_label (label2);
2103 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2104 fields, and can't be used for REG_NOTES anyway). */
2105 emit_use (stack_pointer_rtx);
2110 ;; ....................
2112 ;; EXTRACT AND INSERT
2114 ;; ....................
2116 (define_expand "extzv<mode>"
2117 [(set (match_operand:X 0 "register_operand")
2118 (zero_extract:X (match_operand:X 1 "register_operand")
2119 (match_operand 2 "const_int_operand")
2120 (match_operand 3 "const_int_operand")))]
2123 if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2124 INTVAL (operands[3])))
2128 (define_insn "*extzv<mode>"
2129 [(set (match_operand:X 0 "register_operand" "=r")
2130 (zero_extract:X (match_operand:X 1 "register_operand" "r")
2131 (match_operand 2 "const_int_operand" "")
2132 (match_operand 3 "const_int_operand" "")))]
2133 "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2134 INTVAL (operands[3]))"
2136 operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2137 return "bstrpick.<d>\t%0,%1,%2,%3";
2139 [(set_attr "type" "arith")
2140 (set_attr "mode" "<MODE>")])
2142 (define_expand "insv<mode>"
2143 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2144 (match_operand 1 "const_int_operand")
2145 (match_operand 2 "const_int_operand"))
2146 (match_operand:GPR 3 "reg_or_0_operand"))]
2149 if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2150 INTVAL (operands[2])))
2154 (define_insn "*insv<mode>"
2155 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2156 (match_operand:SI 1 "const_int_operand" "")
2157 (match_operand:SI 2 "const_int_operand" ""))
2158 (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2159 "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2160 INTVAL (operands[2]))"
2162 operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2163 return "bstrins.<d>\t%0,%z3,%1,%2";
2165 [(set_attr "type" "arith")
2166 (set_attr "mode" "<MODE>")])
2169 ;; ....................
2173 ;; ....................
2175 ;; 64-bit integer moves
2177 ;; Unlike most other insns, the move insns can't be split with
2178 ;; different predicates, because register spilling and other parts of
2179 ;; the compiler, have memoized the insn number already.
2181 (define_expand "movdi"
2182 [(set (match_operand:DI 0 "")
2183 (match_operand:DI 1 ""))]
2186 if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2190 (define_insn_and_split "*movdi_32bit"
2191 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2192 (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2194 && (register_operand (operands[0], DImode)
2195 || reg_or_0_operand (operands[1], DImode))"
2196 { return loongarch_output_move (operands); }
2197 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2202 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2206 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2207 (set_attr "mode" "DI")])
2209 (define_insn_and_split "*movdi_64bit"
2210 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2211 (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2213 && (register_operand (operands[0], DImode)
2214 || reg_or_0_operand (operands[1], DImode))"
2216 return loongarch_output_move (operands);
2218 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2223 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2227 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2228 (set_attr "mode" "DI")])
2230 ;; Use two registers to get the global symbol address from the got table.
2231 ;; la.global rd, rt, sym
2233 (define_insn_and_split "movdi_symbolic_off64"
2234 [(set (match_operand:DI 0 "register_operand" "=r,r")
2235 (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r"))
2236 (unspec:DI [(const_int 0)]
2237 UNSPEC_LOAD_SYMBOL_OFFSET64)
2238 (clobber (match_operand:DI 2 "register_operand" "=&r,r"))]
2239 "TARGET_64BIT && TARGET_CMODEL_EXTREME"
2241 if (which_alternative == 1)
2244 enum loongarch_symbol_type symbol_type;
2245 gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2247 switch (symbol_type)
2249 case SYMBOL_PCREL64:
2250 return "la.local\t%0,%2,%1";
2251 case SYMBOL_GOT_DISP:
2252 return "la.global\t%0,%2,%1";
2254 return "la.tls.ie\t%0,%2,%1";
2256 return "la.tls.gd\t%0,%2,%1";
2258 return "la.tls.ld\t%0,%2,%1";
2264 "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0"
2265 [(set (match_dup 0) (match_dup 1))]
2267 [(set_attr "mode" "DI")
2268 (set_attr "insn_count" "5")])
2270 ;; The 64-bit PC-relative part of address loading.
2271 ;; Note that the psABI does not allow splitting it.
2272 (define_insn "la_pcrel64_two_parts"
2273 [(set (match_operand:DI 0 "register_operand" "=r")
2274 (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1))
2275 (set (match_operand:DI 1 "register_operand" "=r")
2276 (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))]
2277 "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
2279 return "pcalau12i\t%0,%r2\n\t"
2280 "addi.d\t%1,$r0,%L2\n\t"
2281 "lu32i.d\t%1,%R2\n\t"
2282 "lu52i.d\t%1,%1,%H2";
2284 [(set_attr "move_type" "move")
2285 (set_attr "mode" "DI")
2286 (set_attr "length" "16")])
2288 ;; 32-bit Integer moves
2290 (define_expand "movsi"
2291 [(set (match_operand:SI 0 "")
2292 (match_operand:SI 1 ""))]
2295 if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2299 (define_insn_and_split "*movsi_internal"
2300 [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m")
2301 (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f"))]
2302 "(register_operand (operands[0], SImode)
2303 || reg_or_0_operand (operands[1], SImode))"
2304 { return loongarch_output_move (operands); }
2305 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2310 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2314 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2315 (set_attr "mode" "SI")])
2317 ;; 16-bit Integer moves
2319 ;; Unlike most other insns, the move insns can't be split with
2320 ;; different predicates, because register spilling and other parts of
2321 ;; the compiler, have memoized the insn number already.
2322 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2324 (define_expand "movhi"
2325 [(set (match_operand:HI 0 "")
2326 (match_operand:HI 1 ""))]
2329 if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2333 (define_insn_and_split "*movhi_internal"
2334 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2335 (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2336 "(register_operand (operands[0], HImode)
2337 || reg_or_0_operand (operands[1], HImode))"
2338 { return loongarch_output_move (operands); }
2339 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2344 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2348 [(set_attr "move_type" "move,const,const,load,store,load,store")
2349 (set_attr "mode" "HI")])
2351 ;; 8-bit Integer moves
2353 ;; Unlike most other insns, the move insns can't be split with
2354 ;; different predicates, because register spilling and other parts of
2355 ;; the compiler, have memoized the insn number already.
2356 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2358 (define_expand "movqi"
2359 [(set (match_operand:QI 0 "")
2360 (match_operand:QI 1 ""))]
2363 if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2367 (define_insn "*movqi_internal"
2368 [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2369 (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2370 "(register_operand (operands[0], QImode)
2371 || reg_or_0_operand (operands[1], QImode))"
2372 { return loongarch_output_move (operands); }
2373 [(set_attr "move_type" "move,const,load,store,load,store")
2374 (set_attr "mode" "QI")])
2376 ;; 32-bit floating point moves
2378 (define_expand "movsf"
2379 [(set (match_operand:SF 0 "")
2380 (match_operand:SF 1 ""))]
2383 if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2387 (define_insn "*movsf_hardfloat"
2388 [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2389 (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2391 && (register_operand (operands[0], SFmode)
2392 || reg_or_0_operand (operands[1], SFmode))"
2393 { return loongarch_output_move (operands); }
2394 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2395 (set_attr "mode" "SF")])
2397 (define_insn "*movsf_softfloat"
2398 [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2399 (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2401 && (register_operand (operands[0], SFmode)
2402 || reg_or_0_operand (operands[1], SFmode))"
2403 { return loongarch_output_move (operands); }
2404 [(set_attr "move_type" "move,load,store")
2405 (set_attr "mode" "SF")])
2407 ;; 64-bit floating point moves
2409 (define_expand "movdf"
2410 [(set (match_operand:DF 0 "")
2411 (match_operand:DF 1 ""))]
2414 if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2418 (define_insn "*movdf_hardfloat"
2419 [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2420 (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2421 "TARGET_DOUBLE_FLOAT
2422 && (register_operand (operands[0], DFmode)
2423 || reg_or_0_operand (operands[1], DFmode))"
2424 { return loongarch_output_move (operands); }
2425 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2426 (set_attr "mode" "DF")])
2428 (define_insn "*movdf_softfloat"
2429 [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2430 (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2431 "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2433 && (register_operand (operands[0], DFmode)
2434 || reg_or_0_operand (operands[1], DFmode))"
2435 { return loongarch_output_move (operands); }
2436 [(set_attr "move_type" "move,load,store")
2437 (set_attr "mode" "DF")])
2439 ;; Clear one FCC register
2441 (define_expand "movfcc"
2442 [(set (match_operand:FCC 0 "")
2443 (match_operand:FCC 1 ""))]
2446 if (memory_operand (operands[0], FCCmode)
2447 && memory_operand (operands[1], FCCmode))
2448 operands[1] = force_reg (FCCmode, operands[1]);
2451 (define_insn "movfcc_internal"
2452 [(set (match_operand:FCC 0 "nonimmediate_operand"
2453 "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2454 (match_operand:FCC 1 "reg_or_0_operand"
2455 "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2458 fcmp.caf.s\t%0,$f0,$f0
2469 [(set_attr "type" "move")
2470 (set_attr "mode" "FCC")])
2472 (define_insn "fcc_to_<X:mode>"
2473 [(set (match_operand:X 0 "register_operand" "=r")
2474 (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2480 [(set_attr "length" "0")
2481 (set_attr "type" "ghost")])
2483 (define_expand "cstore<ANYF:mode>4"
2484 [(set (match_operand:SI 0 "register_operand")
2485 (match_operator:SI 1 "loongarch_fcmp_operator"
2486 [(match_operand:ANYF 2 "register_operand")
2487 (match_operand:ANYF 3 "register_operand")]))]
2490 rtx fcc = gen_reg_rtx (FCCmode);
2491 rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2492 operands[2], operands[3]);
2494 emit_insn (gen_rtx_SET (fcc, cmp));
2497 rtx gpr = gen_reg_rtx (DImode);
2498 emit_insn (gen_fcc_to_di (gpr, fcc));
2499 emit_insn (gen_rtx_SET (operands[0],
2500 lowpart_subreg (SImode, gpr, DImode)));
2503 emit_insn (gen_fcc_to_si (operands[0], fcc));
2508 ;; Conditional move instructions.
2510 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2511 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2513 (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2515 (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2516 (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2517 "register_operand (operands[2], <GPR:MODE>mode)
2518 != register_operand (operands[3], <GPR:MODE>mode)"
2522 [(set_attr "type" "condmove")
2523 (set_attr "mode" "<GPR:MODE>")])
2525 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2526 ;; argument if the 1st is zero. This means operand 2 and 3 are
2527 ;; inverted in the instruction.
2529 (define_insn "*sel<mode>"
2530 [(set (match_operand:ANYF 0 "register_operand" "=f")
2532 (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2534 (match_operand:ANYF 2 "reg_or_0_operand" "f")
2535 (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2538 [(set_attr "type" "condmove")
2539 (set_attr "mode" "<ANYF:MODE>")])
2541 ;; These are the main define_expand's used to make conditional moves.
2543 (define_expand "mov<mode>cc"
2544 [(set (match_operand:GPR 0 "register_operand")
2545 (if_then_else:GPR (match_operator 1 "comparison_operator"
2546 [(match_operand:GPR 2 "reg_or_0_operand")
2547 (match_operand:GPR 3 "reg_or_0_operand")])))]
2548 "TARGET_COND_MOVE_INT"
2550 if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2553 loongarch_expand_conditional_move (operands);
2557 (define_expand "mov<mode>cc"
2558 [(set (match_operand:ANYF 0 "register_operand")
2559 (if_then_else:ANYF (match_operator 1 "comparison_operator"
2560 [(match_operand:ANYF 2 "reg_or_0_operand")
2561 (match_operand:ANYF 3 "reg_or_0_operand")])))]
2562 "TARGET_COND_MOVE_FLOAT"
2564 if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2567 loongarch_expand_conditional_move (operands);
2571 (define_insn "lu32i_d"
2572 [(set (match_operand:DI 0 "register_operand" "=r")
2575 (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2576 (match_operand:DI 2 "const_lu32i_operand" "u")))]
2579 operands[2] = GEN_INT (INTVAL (operands[2]) >> 32);
2580 return "lu32i.d\t%0,%X2";
2582 [(set_attr "type" "arith")
2583 (set_attr "mode" "DI")])
2585 (define_insn "lu52i_d"
2586 [(set (match_operand:DI 0 "register_operand" "=r")
2588 (and:DI (match_operand:DI 1 "register_operand" "r")
2589 (match_operand 2 "lu52i_mask_operand"))
2590 (match_operand 3 "const_lu52i_operand" "v")))]
2593 operands[3] = GEN_INT (INTVAL (operands[3]) >> 52);
2594 return "lu52i.d\t%0,%1,%X3";
2596 [(set_attr "type" "arith")
2597 (set_attr "mode" "DI")])
2599 ;; Instructions for adding the low 12 bits of an address to a register.
2600 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2601 ;; should be applied.
2603 (define_insn "*low<mode>"
2604 [(set (match_operand:P 0 "register_operand" "=r")
2605 (lo_sum:P (match_operand:P 1 "register_operand" " r")
2606 (match_operand:P 2 "symbolic_operand" "")))]
2608 "addi.<d>\t%0,%1,%L2"
2609 [(set_attr "type" "arith")
2610 (set_attr "mode" "<MODE>")])
2612 (define_insn "@tls_low<mode>"
2613 [(set (match_operand:P 0 "register_operand" "=r")
2614 (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2615 (match_operand:P 2 "symbolic_operand" "")))]
2618 "addi.<d>\t%0,%1,%L2"
2619 [(set_attr "type" "arith")
2620 (set_attr "mode" "<MODE>")])
2622 ;; Instructions for loading address from GOT entry.
2623 ;; operands[1] is pc plus the high half of the address difference with the got
2625 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2627 ;; loongarch_print_operand works out which relocation should be applied.
2629 (define_insn "@ld_from_got<mode>"
2630 [(set (match_operand:P 0 "register_operand" "=r")
2631 (unspec:P [(mem:P (lo_sum:P
2632 (match_operand:P 1 "register_operand" "r")
2633 (match_operand:P 2 "symbolic_operand")))]
2634 UNSPEC_LOAD_FROM_GOT))]
2636 "%Q2ld.<d>\t%0,%1,%L2"
2637 [(set_attr "type" "move")]
2640 (define_insn "@lui_l_hi20<mode>"
2641 [(set (match_operand:P 0 "register_operand" "=r")
2642 (unspec:P [(match_operand:P 1 "symbolic_operand")]
2643 UNSPEC_LUI_L_HI20))]
2646 [(set_attr "type" "move")]
2649 (define_insn "@pcalau12i<mode>"
2650 [(set (match_operand:P 0 "register_operand" "=j")
2651 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2654 "pcalau12i\t%0,%%pc_hi20(%1)"
2655 [(set_attr "type" "move")])
2657 ;; @pcalau12i may be used for sibcall so it has a strict constraint. This
2658 ;; allows any general register as the operand.
2659 (define_insn "@pcalau12i_gr<mode>"
2660 [(set (match_operand:P 0 "register_operand" "=r")
2661 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2662 UNSPEC_PCALAU12I_GR))]
2664 "pcalau12i\t%0,%%pc_hi20(%1)"
2665 [(set_attr "type" "move")])
2667 (define_insn "@add_tls_le_relax<mode>"
2668 [(set (match_operand:P 0 "register_operand" "=r")
2669 (unspec:P [(match_operand:P 1 "register_operand" "r")
2670 (match_operand:P 2 "register_operand" "r")
2671 (match_operand:P 3 "symbolic_operand")]
2672 UNSPEC_ADD_TLS_LE_RELAX))]
2673 "HAVE_AS_TLS_LE_RELAXATION"
2674 "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2675 [(set_attr "type" "move")]
2678 (define_insn "@ori_l_lo12<mode>"
2679 [(set (match_operand:P 0 "register_operand" "=r")
2680 (unspec:P [(match_operand:P 1 "register_operand" "r")
2681 (match_operand:P 2 "symbolic_operand")]
2682 UNSPEC_ORI_L_LO12))]
2685 [(set_attr "type" "move")]
2688 (define_insn "lui_h_lo20"
2689 [(set (match_operand:DI 0 "register_operand" "=r")
2690 (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2691 (match_operand:DI 2 "symbolic_operand")]
2692 UNSPEC_LUI_H_LO20))]
2695 [(set_attr "type" "move")]
2698 (define_insn "lui_h_hi12"
2699 [(set (match_operand:DI 0 "register_operand" "=r")
2700 (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2701 (match_operand:DI 2 "symbolic_operand")]
2702 UNSPEC_LUI_H_HI12))]
2704 "lu52i.d\t%0,%1,%H2"
2705 [(set_attr "type" "move")]
2708 ;; Round floating-point numbers to integers
2709 (define_insn "rint<mode>2"
2710 [(set (match_operand:ANYF 0 "register_operand" "=f")
2711 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2714 "frint.<fmt>\t%0,%1"
2715 [(set_attr "type" "fcvt")
2716 (set_attr "mode" "<MODE>")])
2718 ;; Convert floating-point numbers to integers
2719 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2720 [(set (match_operand:ANYFI 0 "register_operand" "=f")
2721 (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2723 "TARGET_HARD_FLOAT &&
2724 (<LRINT> == UNSPEC_FTINT
2725 || flag_fp_int_builtin_inexact
2726 || !flag_trapping_math)"
2727 "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2728 [(set_attr "type" "fcvt")
2729 (set_attr "mode" "<ANYF:MODE>")])
2731 ;; Thread-Local Storage
2733 (define_insn "@got_load_tls_desc<mode>"
2736 [(match_operand:P 0 "symbolic_operand" "")]
2738 (clobber (reg:SI FCC0_REGNUM))
2739 (clobber (reg:SI FCC1_REGNUM))
2740 (clobber (reg:SI FCC2_REGNUM))
2741 (clobber (reg:SI FCC3_REGNUM))
2742 (clobber (reg:SI FCC4_REGNUM))
2743 (clobber (reg:SI FCC5_REGNUM))
2744 (clobber (reg:SI FCC6_REGNUM))
2745 (clobber (reg:SI FCC7_REGNUM))
2746 (clobber (reg:SI RETURN_ADDR_REGNUM))]
2749 return TARGET_EXPLICIT_RELOCS
2750 ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2751 "addi.d\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
2752 "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2753 "jirl\t$r1,$r1,%%desc_call(%0)"
2754 : "la.tls.desc\t$r4,%0";
2756 [(set_attr "got" "load")
2757 (set_attr "mode" "<MODE>")
2758 (set_attr "length" "16")])
2760 (define_insn "got_load_tls_desc_off64"
2763 [(match_operand:DI 0 "symbolic_operand" "")]
2764 UNSPEC_TLS_DESC_OFF64))
2765 (clobber (reg:SI FCC0_REGNUM))
2766 (clobber (reg:SI FCC1_REGNUM))
2767 (clobber (reg:SI FCC2_REGNUM))
2768 (clobber (reg:SI FCC3_REGNUM))
2769 (clobber (reg:SI FCC4_REGNUM))
2770 (clobber (reg:SI FCC5_REGNUM))
2771 (clobber (reg:SI FCC6_REGNUM))
2772 (clobber (reg:SI FCC7_REGNUM))
2773 (clobber (reg:SI RETURN_ADDR_REGNUM))
2774 (clobber (match_operand:DI 1 "register_operand" "=&r"))]
2775 "TARGET_TLS_DESC && TARGET_CMODEL_EXTREME"
2777 return TARGET_EXPLICIT_RELOCS
2778 ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2779 "addi.d\t%1,$r0,%%desc_pc_lo12(%0)\n\t"
2780 "lu32i.d\t%1,%%desc64_pc_lo20(%0)\n\t"
2781 "lu52i.d\t%1,%1,%%desc64_pc_hi12(%0)\n\t"
2782 "add.d\t$r4,$r4,%1\n\t"
2783 "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2784 "jirl\t$r1,$r1,%%desc_call(%0)"
2785 : "la.tls.desc\t$r4,%1,%0";
2787 [(set_attr "got" "load")
2788 (set_attr "length" "28")])
2790 (define_insn "@load_tls<mode>"
2791 [(set (match_operand:P 0 "register_operand" "=r")
2793 [(match_operand:P 1 "symbolic_operand" "")]
2797 enum loongarch_symbol_type symbol_type;
2798 gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2800 switch (symbol_type)
2803 return "la.tls.le\t%0,%1";
2805 return "la.tls.ie\t%0,%1";
2807 return "la.tls.ld\t%0,%1";
2809 return "la.tls.gd\t%0,%1";
2815 [(set_attr "mode" "<MODE>")
2816 (set (attr "insn_count")
2818 (match_test "TARGET_CMODEL_EXTREME")
2823 ;; Expand in-line code to clear the instruction cache between operand[0] and
2825 (define_expand "clear_cache"
2826 [(match_operand 0 "pmode_register_operand")
2827 (match_operand 1 "pmode_register_operand")]
2830 emit_insn (gen_loongarch_ibar (const0_rtx));
2834 (define_insn "loongarch_ibar"
2835 [(unspec_volatile:SI
2836 [(match_operand 0 "const_uimm15_operand")]
2838 (clobber (mem:BLK (scratch)))]
2842 (define_insn "loongarch_dbar"
2843 [(unspec_volatile:SI
2844 [(match_operand 0 "const_uimm15_operand")]
2846 (clobber (mem:BLK (scratch)))]
2852 ;; Privileged state instruction
2854 (define_insn "loongarch_cpucfg"
2855 [(set (match_operand:SI 0 "register_operand" "=r")
2856 (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2860 [(set_attr "type" "load")
2861 (set_attr "mode" "SI")])
2863 (define_insn "loongarch_syscall"
2864 [(unspec_volatile:SI
2865 [(match_operand 0 "const_uimm15_operand")]
2867 (clobber (mem:BLK (scratch)))]
2871 (define_insn "loongarch_break"
2872 [(unspec_volatile:SI
2873 [(match_operand 0 "const_uimm15_operand")]
2875 (clobber (mem:BLK (scratch)))]
2879 (define_insn "loongarch_asrtle_d"
2880 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2881 (match_operand:DI 1 "register_operand" "r")]
2885 [(set_attr "type" "load")
2886 (set_attr "mode" "DI")])
2888 (define_insn "loongarch_asrtgt_d"
2889 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2890 (match_operand:DI 1 "register_operand" "r")]
2894 [(set_attr "type" "load")
2895 (set_attr "mode" "DI")])
2897 (define_insn "loongarch_csrrd_<d>"
2898 [(set (match_operand:GPR 0 "register_operand" "=r")
2899 (unspec_volatile:GPR [(match_operand 1 "const_uimm14_operand")]
2901 (clobber (mem:BLK (scratch)))]
2904 [(set_attr "type" "load")
2905 (set_attr "mode" "<MODE>")])
2907 (define_insn "loongarch_csrwr_<d>"
2908 [(set (match_operand:GPR 0 "register_operand" "=r")
2909 (unspec_volatile:GPR
2910 [(match_operand:GPR 1 "register_operand" "0")
2911 (match_operand 2 "const_uimm14_operand")]
2913 (clobber (mem:BLK (scratch)))]
2916 [(set_attr "type" "store")
2917 (set_attr "mode" "<MODE>")])
2919 (define_insn "loongarch_csrxchg_<d>"
2920 [(set (match_operand:GPR 0 "register_operand" "=r")
2921 (unspec_volatile:GPR
2922 [(match_operand:GPR 1 "register_operand" "0")
2923 (match_operand:GPR 2 "register_operand" "q")
2924 (match_operand 3 "const_uimm14_operand")]
2926 (clobber (mem:BLK (scratch)))]
2929 [(set_attr "type" "load")
2930 (set_attr "mode" "<MODE>")])
2932 (define_insn "loongarch_iocsrrd_<size>"
2933 [(set (match_operand:QHWD 0 "register_operand" "=r")
2934 (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2936 (clobber (mem:BLK (scratch)))]
2938 "iocsrrd.<size>\t%0,%1"
2939 [(set_attr "type" "load")
2940 (set_attr "mode" "<MODE>")])
2942 (define_insn "loongarch_iocsrwr_<size>"
2943 [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2944 (match_operand:SI 1 "register_operand" "r")]
2946 (clobber (mem:BLK (scratch)))]
2948 "iocsrwr.<size>\t%0,%1"
2949 [(set_attr "type" "load")
2950 (set_attr "mode" "<MODE>")])
2952 (define_insn "loongarch_cacop_<d>"
2953 [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2954 (match_operand:X 1 "register_operand" "r")
2955 (match_operand 2 "const_imm12_operand")]
2957 (clobber (mem:BLK (scratch)))]
2960 [(set_attr "type" "load")
2961 (set_attr "mode" "<MODE>")])
2963 (define_insn "loongarch_lddir_<d>"
2964 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2965 (match_operand:X 1 "register_operand" "r")
2966 (match_operand 2 "const_uimm5_operand")]
2968 (clobber (mem:BLK (scratch)))]
2971 [(set_attr "type" "load")
2972 (set_attr "mode" "<MODE>")])
2974 (define_insn "loongarch_ldpte_<d>"
2975 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2976 (match_operand 1 "const_uimm5_operand")]
2978 (clobber (mem:BLK (scratch)))]
2981 [(set_attr "type" "load")
2982 (set_attr "mode" "<MODE>")])
2985 ;; Block moves, see loongarch.c for more details.
2986 ;; Argument 0 is the destination.
2987 ;; Argument 1 is the source.
2988 ;; Argument 2 is the length.
2989 ;; Argument 3 is the alignment.
2991 (define_expand "cpymemsi"
2992 [(parallel [(set (match_operand:BLK 0 "general_operand")
2993 (match_operand:BLK 1 "general_operand"))
2994 (use (match_operand:SI 2 ""))
2995 (use (match_operand:SI 3 "const_int_operand"))])]
2998 if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
2999 && loongarch_expand_block_move (operands[0], operands[1],
3000 operands[2], operands[3]))
3007 ;; ....................
3011 ;; ....................
3013 (define_insn "*<optab><mode>3"
3014 [(set (match_operand:GPR 0 "register_operand" "=r")
3015 (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
3016 (match_operand:SI 2 "arith_operand" "rI")))]
3019 if (CONST_INT_P (operands[2]))
3020 operands[2] = GEN_INT (INTVAL (operands[2])
3021 & (GET_MODE_BITSIZE (<MODE>mode) - 1));
3023 return "<insn>%i2.<d>\t%0,%1,%2";
3025 [(set_attr "type" "shift")
3026 (set_attr "mode" "<MODE>")])
3028 (define_insn "<optab>si3_extend"
3029 [(set (match_operand:DI 0 "register_operand" "=r")
3031 (any_shift:SI (match_operand:SI 1 "register_operand" "r")
3032 (match_operand:SI 2 "arith_operand" "rI"))))]
3035 if (CONST_INT_P (operands[2]))
3036 operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
3038 return "<insn>%i2.w\t%0,%1,%2";
3040 [(set_attr "type" "shift")
3041 (set_attr "mode" "SI")])
3043 (define_insn "*rotr<mode>3"
3044 [(set (match_operand:GPR 0 "register_operand" "=r,r")
3045 (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
3046 (match_operand:SI 2 "arith_operand" "r,I")))]
3048 "rotr%i2.<d>\t%0,%1,%2"
3049 [(set_attr "type" "shift,shift")
3050 (set_attr "mode" "<MODE>")])
3052 (define_insn "rotrsi3_extend"
3053 [(set (match_operand:DI 0 "register_operand" "=r,r")
3055 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
3056 (match_operand:SI 2 "arith_operand" "r,I"))))]
3058 "rotr%i2.w\t%0,%1,%2"
3059 [(set_attr "type" "shift,shift")
3060 (set_attr "mode" "SI")])
3062 ;; Expand left rotate to right rotate.
3063 (define_expand "rotl<mode>3"
3065 (neg:SI (match_operand:SI 2 "register_operand")))
3066 (set (match_operand:GPR 0 "register_operand")
3067 (rotatert:GPR (match_operand:GPR 1 "register_operand")
3071 operands[3] = gen_reg_rtx (SImode);
3073 if (TARGET_64BIT && <MODE>mode == SImode)
3075 rtx t = gen_reg_rtx (DImode);
3077 emit_insn (gen_negsi2 (operands[3], operands[2]));
3078 emit_insn (gen_rotrsi3_extend (t, operands[1], operands[3]));
3079 t = gen_lowpart (SImode, t);
3080 SUBREG_PROMOTED_VAR_P (t) = 1;
3081 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
3082 emit_move_insn (operands[0], t);
3087 (define_insn "alsl<mode>3"
3088 [(set (match_operand:GPR 0 "register_operand" "=r")
3089 (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
3090 (match_operand 2 "const_immalsl_operand" ""))
3091 (match_operand:GPR 3 "register_operand" "r")))]
3093 "alsl.<d>\t%0,%1,%3,%2"
3094 [(set_attr "type" "arith")
3095 (set_attr "mode" "<MODE>")])
3097 (define_insn "*alslsi3_extend"
3098 [(set (match_operand:DI 0 "register_operand" "=r")
3101 (ashift:SI (match_operand:SI 1 "register_operand" "r")
3102 (match_operand 2 "const_immalsl_operand" ""))
3103 (match_operand:SI 3 "register_operand" "r"))))]
3105 "alsl.w<u>\t%0,%1,%3,%2"
3106 [(set_attr "type" "arith")
3107 (set_attr "mode" "SI")])
3109 (define_insn "*alslsi3_extend_subreg"
3110 [(set (match_operand:DI 0 "register_operand" "=r")
3114 (ashift:DI (match_operand:DI 1 "register_operand" "r")
3115 (match_operand 2 "const_immalsl_operand" ""))
3117 (subreg:SI (match_operand:DI 3 "register_operand" "r") 0))))]
3119 "alsl.w<u>\t%0,%1,%3,%2"
3120 [(set_attr "type" "arith")
3121 (set_attr "mode" "SI")])
3123 ;; The generic code prefers "(reg << shamt) [&|^] (mask << shamt)"
3124 ;; instead of "(reg [&|^] mask) << shamt" but we want the latter if
3125 ;; we don't need to load mask into an register, and either:
3126 ;; - (mask << shamt) needs to be loaded into an register, or
3127 ;; - shamt is a const_immalsl_operand, so the outer shift may be further
3128 ;; combined with an add.
3129 (define_insn_and_split "<optab>_shift_reverse<X:mode>"
3130 [(set (match_operand:X 0 "register_operand" "=r")
3132 (ashift:X (match_operand:X 1 "register_operand" "r")
3133 (match_operand:SI 2 "const_int_operand" "i"))
3134 (match_operand:X 3 "const_int_operand" "i")))]
3135 "(const_immalsl_operand (operands[2], SImode)
3136 || !<bitwise_operand> (operands[3], <MODE>mode))
3137 && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
3141 [(set (match_dup 0) (any_bitwise:X (match_dup 1) (match_dup 3)))
3142 (set (match_dup 0) (ashift:X (match_dup 0) (match_dup 2)))]
3144 operands[3] = loongarch_reassoc_shift_bitwise (<is_and>,
3149 if (ins_zero_bitmask_operand (operands[3], <MODE>mode))
3151 gcc_checking_assert (<is_and>);
3152 emit_move_insn (operands[0], operands[1]);
3153 operands[1] = operands[0];
3157 ;; The late_combine2 pass can handle slli.d + add.d => alsl.d, so we
3158 ;; already have slli.d + any_bitwise + add.d => any_bitwise + slli.d +
3159 ;; add.d => any_bitwise + alsl.d. But late_combine2 cannot handle slli.d +
3160 ;; add.w => alsl.w, so implement slli.d + and + add.w => and + alsl.w on
3162 (define_insn_and_split "<optab>_alsl_reversesi_extended"
3163 [(set (match_operand:DI 0 "register_operand" "=&r")
3169 (match_operand:DI 1 "register_operand" "r0")
3170 (match_operand:SI 2 "const_immalsl_operand" ""))
3171 (match_operand:DI 3 "const_int_operand" "i"))
3173 (match_operand:SI 4 "register_operand" "r"))))]
3175 && loongarch_reassoc_shift_bitwise (<is_and>, operands[2], operands[3],
3178 "&& reload_completed"
3179 [; r0 = r1 [&|^] r3 is emitted in PREPARATION-STATEMENTS because we
3180 ; need to handle a special case, see below.
3183 (plus:SI (ashift:SI (subreg:SI (match_dup 0) 0) (match_dup 2))
3186 operands[3] = loongarch_reassoc_shift_bitwise (<is_and>,
3191 if (ins_zero_bitmask_operand (operands[3], SImode))
3193 gcc_checking_assert (<is_and>);
3194 emit_move_insn (operands[0], operands[1]);
3195 operands[1] = operands[0];
3198 if (operands[3] != CONSTM1_RTX (SImode))
3199 emit_insn (gen_<optab>di3 (operands[0], operands[1], operands[3]));
3202 /* Hmm would we really reach here? If we reach here we'd have
3203 a miss-optimization in the generic code (as it should have
3204 optimized this to alslsi3_extend_subreg). But let's be safe
3206 gcc_checking_assert (<is_and>);
3207 emit_move_insn (operands[0], operands[1]);
3213 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
3215 (define_insn "revb_2h"
3216 [(set (match_operand:SI 0 "register_operand" "=r")
3217 (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3221 [(set_attr "type" "shift")])
3223 (define_insn "revb_2h_extend"
3224 [(set (match_operand:DI 0 "register_operand" "=r")
3227 (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3231 [(set_attr "type" "shift")])
3233 (define_insn "bswaphi2"
3234 [(set (match_operand:HI 0 "register_operand" "=r")
3235 (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
3238 [(set_attr "type" "shift")])
3240 (define_insn "revb_2w"
3241 [(set (match_operand:DI 0 "register_operand" "=r")
3242 (rotatert:DI (bswap:DI (match_operand:DI 1 "register_operand" "r"))
3246 [(set_attr "type" "shift")])
3248 (define_insn "*bswapsi2"
3249 [(set (match_operand:SI 0 "register_operand" "=r")
3250 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3253 [(set_attr "type" "shift")])
3255 (define_expand "bswapsi2"
3256 [(set (match_operand:SI 0 "register_operand" "=r")
3257 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3262 rtx t = gen_reg_rtx (SImode);
3263 emit_insn (gen_revb_2h (t, operands[1]));
3264 emit_insn (gen_rotrsi3 (operands[0], t, GEN_INT (16)));
3269 (define_insn "bswapdi2"
3270 [(set (match_operand:DI 0 "register_operand" "=r")
3271 (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3274 [(set_attr "type" "shift")])
3278 ;; ....................
3280 ;; CONDITIONAL BRANCHES
3282 ;; ....................
3284 ;; Conditional branches
3286 (define_insn "*branch_fp_FCCmode"
3289 (match_operator 1 "equality_operator"
3290 [(match_operand:FCC 2 "register_operand" "z")
3292 (label_ref (match_operand 0 "" ""))
3296 return loongarch_output_conditional_branch (insn, operands,
3297 LARCH_BRANCH ("b%F1", "%Z2%0"),
3298 LARCH_BRANCH ("b%W1", "%Z2%0"));
3300 [(set_attr "type" "branch")])
3302 (define_insn "*branch_fp_inverted_FCCmode"
3305 (match_operator 1 "equality_operator"
3306 [(match_operand:FCC 2 "register_operand" "z")
3309 (label_ref (match_operand 0 "" ""))))]
3312 return loongarch_output_conditional_branch (insn, operands,
3313 LARCH_BRANCH ("b%W1", "%Z2%0"),
3314 LARCH_BRANCH ("b%F1", "%Z2%0"));
3316 [(set_attr "type" "branch")])
3318 ;; Conditional branches on ordered comparisons with zero.
3320 (define_insn "*branch_order<mode>"
3323 (match_operator 1 "order_operator"
3324 [(match_operand:X 2 "register_operand" "r,r")
3325 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3326 (label_ref (match_operand 0 "" ""))
3329 { return loongarch_output_order_conditional_branch (insn, operands, false); }
3330 [(set_attr "type" "branch")])
3332 (define_insn "*branch_order<mode>_inverted"
3335 (match_operator 1 "order_operator"
3336 [(match_operand:X 2 "register_operand" "r,r")
3337 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3339 (label_ref (match_operand 0 "" ""))))]
3341 { return loongarch_output_order_conditional_branch (insn, operands, true); }
3342 [(set_attr "type" "branch")])
3344 ;; Conditional branch on equality comparison.
3346 (define_insn "branch_equality<mode>"
3349 (match_operator 1 "equality_operator"
3350 [(match_operand:X 2 "register_operand" "r")
3351 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3352 (label_ref (match_operand 0 "" ""))
3355 { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3356 [(set_attr "type" "branch")])
3359 (define_insn "*branch_equality<mode>_inverted"
3362 (match_operator 1 "equality_operator"
3363 [(match_operand:X 2 "register_operand" "r")
3364 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3366 (label_ref (match_operand 0 "" ""))))]
3368 { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3369 [(set_attr "type" "branch")])
3372 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3373 ;; QImode values so we can force zero-extension.
3374 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3376 (define_expand "cbranch<mode>4"
3378 (if_then_else (match_operator 0 "comparison_operator"
3379 [(match_operand:BR 1 "register_operand")
3380 (match_operand:BR 2 "nonmemory_operand")])
3381 (label_ref (match_operand 3 ""))
3385 loongarch_expand_conditional_branch (operands);
3389 (define_expand "cbranch<mode>4"
3391 (if_then_else (match_operator 0 "comparison_operator"
3392 [(match_operand:ANYF 1 "register_operand")
3393 (match_operand:ANYF 2 "register_operand")])
3394 (label_ref (match_operand 3 ""))
3398 loongarch_expand_conditional_branch (operands);
3402 ;; Used to implement built-in functions.
3403 (define_expand "condjump"
3405 (if_then_else (match_operand 0)
3406 (label_ref (match_operand 1))
3411 ;; ....................
3413 ;; SETTING A REGISTER FROM A COMPARISON
3415 ;; ....................
3417 ;; Destination is always set in SI mode.
3419 (define_expand "cstore<mode>4"
3420 [(set (match_operand:SI 0 "register_operand")
3421 (match_operator:SI 1 "loongarch_cstore_operator"
3422 [(match_operand:GPR 2 "register_operand")
3423 (match_operand:GPR 3 "nonmemory_operand")]))]
3426 loongarch_expand_scc (operands);
3430 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3431 [(set (match_operand:GPR 0 "register_operand" "=r")
3432 (eq:GPR (match_operand:X 1 "register_operand" "r")
3436 [(set_attr "type" "slt")
3437 (set_attr "mode" "<X:MODE>")])
3440 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3441 [(set (match_operand:GPR 0 "register_operand" "=r")
3442 (ne:GPR (match_operand:X 1 "register_operand" "r")
3446 [(set_attr "type" "slt")
3447 (set_attr "mode" "<X:MODE>")])
3449 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3450 [(set (match_operand:GPR 0 "register_operand" "=r")
3451 (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3452 (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3455 [(set_attr "type" "slt")
3456 (set_attr "mode" "<X:MODE>")])
3458 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3459 [(set (match_operand:GPR 0 "register_operand" "=r")
3460 (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3461 (match_operand:X 2 "arith_operand" "rI")))]
3463 "slt<u>%i2\t%0,%1,%2";
3464 [(set_attr "type" "slt")
3465 (set_attr "mode" "<X:MODE>")])
3467 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3468 [(set (match_operand:GPR 0 "register_operand" "=r")
3469 (any_le:GPR (match_operand:X 1 "register_operand" "r")
3470 (match_operand:X 2 "sle_operand" "")))]
3473 operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3474 return "slt<u>i\t%0,%1,%2";
3476 [(set_attr "type" "slt")
3477 (set_attr "mode" "<X:MODE>")])
3481 ;; ....................
3483 ;; FLOATING POINT COMPARISONS
3485 ;; ....................
3487 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3488 [(set (match_operand:FCC 0 "register_operand" "=z")
3489 (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3490 (match_operand:ANYF 2 "register_operand" "f")))]
3492 "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3493 [(set_attr "type" "fcmp")
3494 (set_attr "mode" "FCC")])
3498 ;; ....................
3500 ;; UNCONDITIONAL BRANCHES
3502 ;; ....................
3504 ;; Unconditional branches.
3506 (define_expand "jump"
3508 (label_ref (match_operand 0)))])
3510 (define_insn "*jump_absolute"
3512 (label_ref (match_operand 0)))]
3517 [(set_attr "type" "branch")])
3519 (define_insn "*jump_pic"
3521 (label_ref (match_operand 0)))]
3526 [(set_attr "type" "branch")])
3528 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3529 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3530 ;; return prediction and the more general indirect branch prediction.
3532 (define_expand "indirect_jump"
3533 [(set (pc) (match_operand 0 "register_operand"))]
3536 operands[0] = force_reg (Pmode, operands[0]);
3537 emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3541 (define_insn "@indirect_jump<mode>"
3542 [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3545 [(set_attr "type" "jump")
3546 (set_attr "mode" "none")])
3548 (define_expand "tablejump"
3550 (match_operand 0 "register_operand"))
3551 (use (label_ref (match_operand 1 "")))]
3555 operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3556 gen_rtx_LABEL_REF (Pmode,
3558 NULL_RTX, 0, OPTAB_DIRECT);
3559 emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3563 (define_mode_attr mode_size [(DI "8") (SI "4")])
3565 (define_insn "@tablejump<mode>"
3567 (match_operand:P 0 "register_operand" "e"))
3568 (use (label_ref (match_operand 1 "" "")))]
3571 return TARGET_ANNOTATE_TABLEJUMP
3573 ".pushsection\t.discard.tablejump_annotate\n\t"
3574 "\t.<mode_size>byte\t1b\n\t"
3575 "\t.<mode_size>byte\t%1\n\t"
3579 [(set_attr "type" "jump")
3580 (set_attr "mode" "none")])
3585 ;; ....................
3587 ;; Function prologue/epilogue
3589 ;; ....................
3592 (define_expand "prologue"
3596 loongarch_expand_prologue ();
3600 ;; Block any insns from being moved before this point, since the
3601 ;; profiling call to mcount can use various registers that aren't
3602 ;; saved or used to pass arguments.
3604 (define_insn "blockage"
3605 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3608 [(set_attr "type" "ghost")
3609 (set_attr "mode" "none")])
3611 (define_insn "@probe_stack_range<P:mode>"
3612 [(set (match_operand:P 0 "register_operand" "=r")
3613 (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3614 (match_operand:P 2 "register_operand" "r")
3615 (match_operand:P 3 "register_operand" "r")]
3616 UNSPECV_PROBE_STACK_RANGE))]
3619 return loongarch_output_probe_stack_range (operands[0],
3623 [(set_attr "type" "unknown")
3624 (set_attr "mode" "<MODE>")])
3626 (define_expand "epilogue"
3630 loongarch_expand_epilogue (NORMAL_RETURN);
3634 (define_expand "sibcall_epilogue"
3638 loongarch_expand_epilogue (SIBCALL_RETURN);
3642 ;; Trivial return. Make it look like a normal return insn as that
3643 ;; allows jump optimizations to work better.
3645 (define_expand "return"
3647 "loongarch_can_use_return_insn ()"
3650 (define_expand "simple_return"
3655 (define_insn "*<optab>"
3659 operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3662 [(set_attr "type" "jump")
3663 (set_attr "mode" "none")])
3667 (define_insn "<optab>_internal"
3669 (use (match_operand 0 "pmode_register_operand" ""))]
3672 [(set_attr "type" "jump")
3673 (set_attr "mode" "none")])
3675 ;; Exception return.
3676 (define_insn "loongarch_ertn"
3678 (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3681 [(set_attr "type" "trap")
3682 (set_attr "mode" "none")])
3684 ;; This is used in compiling the unwind routines.
3685 (define_expand "eh_return"
3686 [(use (match_operand 0 "general_operand"))]
3689 if (GET_MODE (operands[0]) != word_mode)
3690 operands[0] = convert_to_mode (word_mode, operands[0], 0);
3692 emit_insn (gen_eh_set_ra_di (operands[0]));
3694 emit_insn (gen_eh_set_ra_si (operands[0]));
3696 emit_jump_insn (gen_eh_return_internal ());
3701 (define_insn_and_split "eh_return_internal"
3705 "epilogue_completed"
3708 loongarch_expand_epilogue (EXCEPTION_RETURN);
3712 ;; Clobber the return address on the stack. We can't expand this
3713 ;; until we know where it will be put in the stack frame.
3715 (define_insn "eh_set_ra_si"
3716 [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3717 (clobber (match_scratch:SI 1 "=&r"))]
3721 (define_insn "eh_set_ra_di"
3722 [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3723 (clobber (match_scratch:DI 1 "=&r"))]
3728 [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3729 (clobber (match_scratch 1))]
3733 loongarch_set_return_address (operands[0], operands[1]);
3740 ;; ....................
3744 ;; ....................
3746 ;; Sibling calls. All these patterns use jump instructions.
3748 (define_expand "sibcall"
3749 [(parallel [(call (match_operand 0 "")
3750 (match_operand 1 ""))
3751 (use (match_operand 2 "")) ;; next_arg_reg
3752 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3755 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3757 if (GET_CODE (target) == LO_SUM)
3758 emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3763 rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3765 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3766 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3767 gen_rtx_REG (Pmode, T0_REGNUM));
3772 (define_insn "sibcall_internal"
3773 [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3774 (match_operand 1 "" ""))]
3775 "SIBLING_CALL_P (insn)"
3777 switch (which_alternative)
3782 if (TARGET_CMODEL_MEDIUM)
3783 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3787 if (TARGET_CMODEL_MEDIUM)
3788 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3790 return "b\t%%plt(%0)";
3795 [(set_attr "jirl" "indirect,direct,direct")])
3797 (define_insn "@sibcall_internal_1<mode>"
3798 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3799 (match_operand:P 1 "symbolic_operand" "")))
3800 (match_operand 2 "" ""))]
3801 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3802 "jirl\t$r0,%0,%%pc_lo12(%1)"
3803 [(set_attr "jirl" "indirect")])
3805 (define_expand "sibcall_value"
3806 [(parallel [(set (match_operand 0 "")
3807 (call (match_operand 1 "")
3808 (match_operand 2 "")))
3809 (use (match_operand 3 ""))])] ;; next_arg_reg
3812 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3814 /* Handle return values created by loongarch_pass_fpr_pair. */
3815 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3817 rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3818 rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3820 if (GET_CODE (target) == LO_SUM)
3821 emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3829 = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3834 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3835 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3836 gen_rtx_REG (Pmode, T0_REGNUM));
3841 /* Handle return values created by loongarch_return_fpr_single. */
3842 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3843 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3845 if (GET_CODE (target) == LO_SUM)
3846 emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3852 rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3856 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3857 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3858 gen_rtx_REG (Pmode, T0_REGNUM));
3864 (define_insn "sibcall_value_internal"
3865 [(set (match_operand 0 "register_operand" "")
3866 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3867 (match_operand 2 "" "")))]
3868 "SIBLING_CALL_P (insn)"
3870 switch (which_alternative)
3875 if (TARGET_CMODEL_MEDIUM)
3876 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3880 if (TARGET_CMODEL_MEDIUM)
3881 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3883 return "b\t%%plt(%1)";
3888 [(set_attr "jirl" "indirect,direct,direct")])
3890 (define_insn "@sibcall_value_internal_1<mode>"
3891 [(set (match_operand 0 "register_operand" "")
3892 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3893 (match_operand:P 2 "symbolic_operand" "")))
3894 (match_operand 3 "" "")))]
3895 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3896 "jirl\t$r0,%1,%%pc_lo12(%2)"
3897 [(set_attr "jirl" "indirect")])
3899 (define_insn "sibcall_value_multiple_internal"
3900 [(set (match_operand 0 "register_operand" "")
3901 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3902 (match_operand 2 "" "")))
3903 (set (match_operand 3 "register_operand" "")
3904 (call (mem:SI (match_dup 1))
3906 "SIBLING_CALL_P (insn)"
3908 switch (which_alternative)
3913 if (TARGET_CMODEL_MEDIUM)
3914 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3918 if (TARGET_CMODEL_MEDIUM)
3919 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3921 return "b\t%%plt(%1)";
3926 [(set_attr "jirl" "indirect,direct,direct")])
3928 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3929 [(set (match_operand 0 "register_operand" "")
3930 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3931 (match_operand:P 2 "symbolic_operand" "")]
3932 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3933 (match_operand 3 "" "")))
3934 (set (match_operand 4 "register_operand" "")
3935 (call (mem:P (unspec:P [(match_dup 1)
3937 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3939 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3940 "jirl\t$r0,%1,%%pc_lo12(%2)"
3941 [(set_attr "jirl" "indirect")])
3943 (define_expand "call"
3944 [(parallel [(call (match_operand 0 "")
3945 (match_operand 1 ""))
3946 (use (match_operand 2 "")) ;; next_arg_reg
3947 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3950 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3952 if (GET_CODE (target) == LO_SUM)
3953 emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3954 XEXP (target, 1), operands[1]));
3956 emit_call_insn (gen_call_internal (target, operands[1]));
3960 (define_insn "call_internal"
3961 [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3962 (match_operand 1 "" ""))
3963 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3966 switch (which_alternative)
3969 return "jirl\t$r1,%0,0";
3971 if (TARGET_CMODEL_MEDIUM)
3972 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3976 if (TARGET_CMODEL_MEDIUM)
3977 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3979 return "bl\t%%plt(%0)";
3984 [(set_attr "jirl" "indirect,direct,direct")])
3986 (define_insn "@call_internal_1<mode>"
3987 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3988 (match_operand:P 1 "symbolic_operand" "")))
3989 (match_operand 2 "" ""))
3990 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3991 "TARGET_CMODEL_MEDIUM"
3992 "jirl\t$r1,%0,%%pc_lo12(%1)"
3993 [(set_attr "jirl" "indirect")])
3995 (define_expand "call_value"
3996 [(parallel [(set (match_operand 0 "")
3997 (call (match_operand 1 "")
3998 (match_operand 2 "")))
3999 (use (match_operand 3 ""))])] ;; next_arg_reg
4002 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
4003 /* Handle return values created by loongarch_pass_fpr_pair. */
4004 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
4006 rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
4007 rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
4009 if (GET_CODE (target) == LO_SUM)
4010 emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
4013 operands[2], arg2));
4015 emit_call_insn (gen_call_value_multiple_internal (arg1, target,
4016 operands[2], arg2));
4020 /* Handle return values created by loongarch_return_fpr_single. */
4021 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
4022 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
4024 if (GET_CODE (target) == LO_SUM)
4025 emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
4030 emit_call_insn (gen_call_value_internal (operands[0], target,
4036 (define_insn "call_value_internal"
4037 [(set (match_operand 0 "register_operand" "")
4038 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4039 (match_operand 2 "" "")))
4040 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4043 switch (which_alternative)
4046 return "jirl\t$r1,%1,0";
4048 if (TARGET_CMODEL_MEDIUM)
4049 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4053 if (TARGET_CMODEL_MEDIUM)
4054 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4056 return "bl\t%%plt(%1)";
4061 [(set_attr "jirl" "indirect,direct,direct")])
4063 (define_insn "@call_value_internal_1<mode>"
4064 [(set (match_operand 0 "register_operand" "")
4065 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
4066 (match_operand:P 2 "symbolic_operand" "")))
4067 (match_operand 3 "" "")))
4068 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4069 "TARGET_CMODEL_MEDIUM"
4070 "jirl\t$r1,%1,%%pc_lo12(%2)"
4071 [(set_attr "jirl" "indirect")])
4073 (define_insn "call_value_multiple_internal"
4074 [(set (match_operand 0 "register_operand" "")
4075 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4076 (match_operand 2 "" "")))
4077 (set (match_operand 3 "register_operand" "")
4078 (call (mem:SI (match_dup 1))
4080 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4083 switch (which_alternative)
4086 return "jirl\t$r1,%1,0";
4088 if (TARGET_CMODEL_MEDIUM)
4089 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4093 if (TARGET_CMODEL_MEDIUM)
4094 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4096 return "bl\t%%plt(%1)";
4101 [(set_attr "jirl" "indirect,direct,direct")])
4103 (define_insn "@call_value_multiple_internal_1<mode>"
4104 [(set (match_operand 0 "register_operand" "")
4105 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
4106 (match_operand:P 2 "symbolic_operand" "")]
4107 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4108 (match_operand 3 "" "")))
4109 (set (match_operand 4 "register_operand" "")
4110 (call (mem:P (unspec:P [(match_dup 1)
4112 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4114 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4115 "TARGET_CMODEL_MEDIUM"
4116 "jirl\t$r1,%1,%%pc_lo12(%2)"
4117 [(set_attr "jirl" "indirect")])
4120 ;; Call subroutine returning any type.
4121 (define_expand "untyped_call"
4122 [(parallel [(call (match_operand 0 "")
4124 (match_operand 1 "")
4125 (match_operand 2 "")])]
4130 emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
4132 for (i = 0; i < XVECLEN (operands[2], 0); i++)
4134 rtx set = XVECEXP (operands[2], 0, i);
4135 loongarch_emit_move (SET_DEST (set), SET_SRC (set));
4138 emit_insn (gen_blockage ());
4143 ;; ....................
4147 ;; ....................
4150 (define_insn "prefetch"
4151 [(prefetch (match_operand 0 "address_operand" "ZD")
4152 (match_operand 1 "const_int_operand" "n")
4153 (match_operand 2 "const_int_operand" "n"))]
4156 switch (INTVAL (operands[1]))
4159 case 2: return "preld\t0,%a0";
4160 case 1: return "preld\t8,%a0";
4161 default: gcc_unreachable ();
4169 [(set_attr "type" "nop")
4170 (set_attr "mode" "none")])
4172 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
4173 (define_insn "loongarch_movfcsr2gr"
4174 [(set (match_operand:SI 0 "register_operand" "=r")
4175 (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
4176 UNSPECV_MOVFCSR2GR))]
4178 "movfcsr2gr\t%0,$r%1")
4180 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
4181 (define_insn "loongarch_movgr2fcsr"
4182 [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
4183 (match_operand:SI 1 "register_operand" "r")]
4184 UNSPECV_MOVGR2FCSR)]
4186 "movgr2fcsr\t$r%0,%1")
4188 (define_insn "fclass_<fmt>"
4189 [(set (match_operand:SI 0 "register_operand" "=f")
4190 (unspec:SI [(match_operand:ANYF 1 "register_operand" "f")]
4193 "fclass.<fmt>\t%0,%1"
4194 [(set_attr "type" "unknown")
4195 (set_attr "mode" "<MODE>")])
4197 (define_int_iterator FCLASS_MASK [68 136 952])
4198 (define_int_attr fclass_optab
4203 (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
4204 [(match_operand:SI 0 "register_operand" "=r")
4205 (match_operand:ANYF 1 "register_operand" " f")
4206 (const_int FCLASS_MASK)]
4209 rtx ft0 = gen_reg_rtx (SImode);
4210 rtx t0 = gen_reg_rtx (word_mode);
4211 rtx mask = GEN_INT (<FCLASS_MASK>);
4213 emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
4216 emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
4218 emit_move_insn (t0, ft0);
4220 emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
4221 emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
4225 t0 = lowpart_subreg (SImode, t0, DImode);
4226 SUBREG_PROMOTED_VAR_P (t0) = 1;
4227 SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
4230 emit_move_insn (operands[0], t0);
4235 (define_insn "bytepick_w_<bytepick_imm>"
4236 [(set (match_operand:SI 0 "register_operand" "=r")
4237 (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
4238 (const_int <bytepick_w_lshiftrt_amount>))
4239 (ashift:SI (match_operand:SI 2 "register_operand" "r")
4240 (const_int bytepick_w_ashift_amount))))]
4242 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
4243 [(set_attr "mode" "SI")])
4245 (define_mode_attr bitsize [(QI "8") (HI "16")])
4246 (define_mode_attr bytepick_imm [(QI "3") (HI "2")])
4247 (define_mode_attr bytepick_w_ashift_amount [(QI "24") (HI "16")])
4249 (define_insn "bytepick_w_<bytepick_imm>_extend"
4250 [(set (match_operand:DI 0 "register_operand" "=r")
4254 (subreg:SHORT (match_operand:DI 1 "register_operand" "r") 0))
4255 (const_int <bytepick_w_ashift_amount>))
4256 (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4257 (const_int <bytepick_w_ashift_amount>)
4258 (const_int <bitsize>))))]
4260 "bytepick.w\t%0,%2,%1,<bytepick_imm>"
4261 [(set_attr "mode" "SI")])
4263 (define_insn "bytepick_w_1_extend"
4264 [(set (match_operand:DI 0 "register_operand" "=r")
4267 (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
4271 (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4275 "bytepick.w\t%0,%2,%1,1"
4276 [(set_attr "mode" "SI")])
4278 (define_insn "bytepick_d_<bytepick_imm>"
4279 [(set (match_operand:DI 0 "register_operand" "=r")
4280 (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
4281 (const_int <bytepick_d_lshiftrt_amount>))
4282 (ashift (match_operand:DI 2 "register_operand" "r")
4283 (const_int bytepick_d_ashift_amount))))]
4285 "bytepick.d\t%0,%1,%2,<bytepick_imm>"
4286 [(set_attr "mode" "DI")])
4288 (define_insn "bytepick_d_<bytepick_imm>_rev"
4289 [(set (match_operand:DI 0 "register_operand" "=r")
4290 (ior:DI (ashift (match_operand:DI 1 "register_operand" "r")
4291 (const_int bytepick_d_ashift_amount))
4292 (lshiftrt (match_operand:DI 2 "register_operand" "r")
4293 (const_int <bytepick_d_lshiftrt_amount>))))]
4295 "bytepick.d\t%0,%2,%1,<bytepick_imm>"
4296 [(set_attr "mode" "DI")])
4298 (define_insn "bitrev_4b"
4299 [(set (match_operand:SI 0 "register_operand" "=r")
4300 (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
4304 [(set_attr "type" "unknown")
4305 (set_attr "mode" "SI")])
4307 (define_insn "bitrev_8b"
4308 [(set (match_operand:DI 0 "register_operand" "=r")
4309 (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4313 [(set_attr "type" "unknown")
4314 (set_attr "mode" "DI")])
4316 (define_insn "@rbit<mode>"
4317 [(set (match_operand:GPR 0 "register_operand" "=r")
4318 (bitreverse:GPR (match_operand:GPR 1 "register_operand" "r")))]
4320 "bitrev.<size>\t%0,%1"
4321 [(set_attr "type" "unknown")
4322 (set_attr "mode" "<MODE>")])
4324 (define_insn "rbitsi_extended"
4325 [(set (match_operand:DI 0 "register_operand" "=r")
4327 (bitreverse:SI (match_operand:SI 1 "register_operand" "r"))))]
4330 [(set_attr "type" "unknown")
4331 (set_attr "mode" "SI")])
4333 ;; If we don't care high bits, bitrev.4b can reverse bits of values in
4335 (define_insn "rbitqi"
4336 [(set (match_operand:QI 0 "register_operand" "=r")
4337 (bitreverse:QI (match_operand:QI 1 "register_operand" "r")))]
4340 [(set_attr "type" "unknown")
4341 (set_attr "mode" "SI")])
4343 ;; For HImode it's a little complicated...
4344 (define_expand "rbithi"
4345 [(match_operand:HI 0 "register_operand")
4346 (match_operand:HI 1 "register_operand")]
4349 rtx t = gen_reg_rtx (word_mode);
4351 /* Oh, using paradoxical subreg. I learnt the trick from RISC-V,
4352 hoping we won't be blown up altogether one day. */
4353 emit_insn (gen_rbit(word_mode, t,
4354 gen_lowpart (word_mode, operands[1])));
4355 t = expand_simple_binop (word_mode, LSHIFTRT, t,
4356 GEN_INT (GET_MODE_BITSIZE (word_mode) - 16),
4357 NULL_RTX, false, OPTAB_DIRECT);
4359 t = gen_lowpart (HImode, t);
4360 SUBREG_PROMOTED_VAR_P (t) = 1;
4361 SUBREG_PROMOTED_SET (t, SRP_UNSIGNED);
4362 emit_move_insn (operands[0], t);
4367 (define_insn "@stack_tie<mode>"
4368 [(set (mem:BLK (scratch))
4369 (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4370 (match_operand:X 1 "register_operand" "r")]
4374 [(set_attr "length" "0")
4375 (set_attr "type" "ghost")])
4377 ;; Named pattern for expanding thread pointer reference.
4378 (define_expand "get_thread_pointer<mode>"
4379 [(set (match_operand:P 0 "register_operand" "=r")
4385 [(match_operand 0 "small_data_pattern")]
4388 { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4391 ;; Match paired HI/SI/SF/DFmode load/stores.
4392 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4393 [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4395 (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4396 (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4398 (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4401 /* The load destination does not overlap the source. */
4402 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4403 output_asm_insn (loongarch_output_move (operands),
4405 output_asm_insn (loongarch_output_move (&operands[2]),
4409 [(set_attr "move_type"
4410 "load,fpload,store,fpstore,load,store")
4411 (set_attr "insn_count" "2,2,2,2,2,2")])
4413 ;; 2 HI/SI/SF/DF loads are bonded.
4415 [(set (match_operand:JOIN_MODE 0 "register_operand")
4416 (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4417 (set (match_operand:JOIN_MODE 2 "register_operand")
4418 (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4419 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4420 [(parallel [(set (match_dup 0)
4426 ;; 2 HI/SI/SF/DF stores are bonded.
4428 [(set (match_operand:JOIN_MODE 0 "memory_operand")
4429 (match_operand:JOIN_MODE 1 "register_operand"))
4430 (set (match_operand:JOIN_MODE 2 "memory_operand")
4431 (match_operand:JOIN_MODE 3 "register_operand"))]
4432 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4433 [(parallel [(set (match_dup 0)
4439 ;; Match paired HImode loads.
4440 (define_insn "*join2_loadhi"
4441 [(set (match_operand:SI 0 "register_operand" "=&r")
4442 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4443 (set (match_operand:SI 2 "register_operand" "=r")
4444 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4447 /* The load destination does not overlap the source. */
4448 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4449 output_asm_insn ("ld.h<u>\t%0,%1", operands);
4450 output_asm_insn ("ld.h<u>\t%2,%3", operands);
4454 [(set_attr "move_type" "load")
4455 (set_attr "insn_count" "2")])
4458 ;; 2 HI loads are bonded.
4460 [(set (match_operand:SI 0 "register_operand")
4461 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4462 (set (match_operand:SI 2 "register_operand")
4463 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4464 "loongarch_load_store_bonding_p (operands, HImode, true)"
4465 [(parallel [(set (match_dup 0)
4466 (any_extend:SI (match_dup 1)))
4468 (any_extend:SI (match_dup 3)))])]
4473 (define_int_iterator CRC [UNSPEC_CRC UNSPEC_CRCC])
4474 (define_int_attr crc [(UNSPEC_CRC "crc") (UNSPEC_CRCC "crcc")])
4476 (define_insn "loongarch_<crc>_w_<size>_w"
4477 [(set (match_operand:SI 0 "register_operand" "=r")
4478 (unspec:SI [(match_operand:QHWD 1 "register_operand" "r")
4479 (match_operand:SI 2 "register_operand" "r")]
4482 "<crc>.w.<size>.w\t%0,%1,%2"
4483 [(set_attr "type" "unknown")
4484 (set_attr "mode" "<MODE>")])
4486 (define_insn "loongarch_<crc>_w_<size>_w_extended"
4487 [(set (match_operand:DI 0 "register_operand" "=r")
4489 (unspec:SI [(match_operand:QHWD 1 "register_operand" "r")
4490 (match_operand:SI 2 "register_operand" "r")]
4493 "<crc>.w.<size>.w\t%0,%1,%2"
4494 [(set_attr "type" "unknown")
4495 (set_attr "mode" "<MODE>")])
4497 (define_expand "crc_rev<mode>si4"
4498 [(match_operand:SI 0 "register_operand") ; new_chksum
4499 (match_operand:SI 1 "register_operand") ; old_chksum
4500 (match_operand:SUBDI 2 "reg_or_0_operand") ; msg
4501 (match_operand 3 "const_int_operand")] ; poly
4504 unsigned HOST_WIDE_INT poly = UINTVAL (operands[3]);
4505 rtx msg = operands[2];
4506 rtx (*crc_insn)(rtx, rtx, rtx) = nullptr;
4508 /* TODO: Review this when adding LA32 support. If we're going to
4509 support CRC instructions on LA32 we'll need a "-mcrc" switch as
4510 they are optional on LA32. */
4514 if (poly == reflect_hwi (0xedb88320u, 32))
4515 crc_insn = gen_loongarch_crc_w_<size>_w;
4516 else if (poly == reflect_hwi (0x82f63b78u, 32))
4517 crc_insn = gen_loongarch_crcc_w_<size>_w;
4522 /* We cannot make crc_insn to accept const0_rtx easily:
4523 it's not possible to figure out the mode of const0_rtx so we'd
4524 have to separate both UNSPEC_CRC and UNSPEC_CRCC to 4 different
4525 UNSPECs. Instead just hack it around here. */
4526 if (msg == const0_rtx)
4527 msg = gen_rtx_REG (<MODE>mode, 0);
4529 emit_insn (crc_insn (operands[0], msg, operands[1]));
4533 /* No CRC instruction is suitable, use the generic table-based
4534 implementation but optimize bit reversion. */
4535 auto rbit = [](rtx *r)
4537 /* Well, this is ugly. The problem is
4538 expand_reversed_crc_table_based only accepts one helper
4539 for reversing data elements and CRC states. */
4540 auto mode = GET_MODE (*r);
4541 auto rbit = (mode == <MODE>mode ? gen_rbit<mode> : gen_rbitsi);
4542 rtx out = gen_reg_rtx (mode);
4544 emit_insn (rbit (out, *r));
4547 expand_reversed_crc_table_based (operands[0], operands[1],
4548 msg, operands[3], <MODE>mode,
4554 (define_insn_and_split "*crc_combine"
4555 [(set (match_operand:SI 0 "register_operand" "=r,r")
4560 (match_operand:DI 1 "register_operand" "r,r")
4561 ; Our LOAD_EXTEND_OP makes this same as sign_extend
4562 ; if SUBDI is SI, or zero_extend if SUBDI is QI or HI.
4563 ; For the former the high bits in rk are ignored by
4564 ; crc.w.w.w anyway, for the latter the zero extension is
4565 ; necessary for the correctness of this transformation.
4567 (match_operand:SUBDI 2 "memory_operand" "m,k") 0)) 0)]
4569 "TARGET_64BIT && loongarch_pre_reload_split ()"
4572 [(set (match_dup 3) (match_dup 2))
4574 (unspec:SI [(match_dup 3) (subreg:SI (match_dup 1) 0)] CRC))]
4576 operands[3] = gen_reg_rtx (<MODE>mode);
4579 ;; With normal or medium code models, if the only use of a pc-relative
4580 ;; address is for loading or storing a value, then relying on linker
4581 ;; relaxation is not better than emitting the machine instruction directly.
4582 ;; Even if the la.local pseudo op can be relaxed, we get:
4584 ;; pcaddi $t0, %pcrel_20(x)
4587 ;; There are still two instructions, same as using the machine instructions
4588 ;; and explicit relocs:
4590 ;; pcalau12i $t0, %pc_hi20(x)
4591 ;; ld.d $t0, $t0, %pc_lo12(x)
4593 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4595 (define_insn_and_rewrite "simple_load<mode>"
4596 [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4597 (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4598 "loongarch_pre_reload_split ()
4599 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4600 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4604 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4607 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4608 [(set (match_operand:GPR 0 "register_operand" "=r")
4610 (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4611 "loongarch_pre_reload_split ()
4612 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4613 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4617 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4620 (define_insn_and_rewrite "simple_store<mode>"
4621 [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4622 (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4623 "loongarch_pre_reload_split ()
4624 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4625 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4629 operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4632 ;; Synchronization instructions.
4636 (include "generic.md")
4637 (include "la464.md")
4639 ; The LoongArch SIMD Instructions.
4642 (define_c_enum "unspec" [
4643 UNSPEC_ADDRESS_FIRST