1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 ;; Contributed by Loongson Ltd.
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 3, or (at your option)
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3. If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23 ;; 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 neg_bitwise [and ior])
490 ;; This code iterator allows unsigned and signed division to be generated
491 ;; from the same template.
492 (define_code_iterator any_div [div udiv mod umod])
494 ;; This code iterator allows addition and subtraction to be generated
495 ;; from the same template.
496 (define_code_iterator addsub [plus minus])
498 ;; This code iterator allows addition and multiplication to be generated
499 ;; from the same template.
500 (define_code_iterator addmul [plus mult])
502 ;; This code iterator allows addition subtraction and multiplication to be
503 ;; generated from the same template
504 (define_code_iterator addsubmul [plus minus mult])
506 ;; This code iterator allows all native floating-point comparisons to be
507 ;; generated from the same template.
508 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
509 ordered ltgt ne ge gt unge ungt])
511 ;; Equality operators.
512 (define_code_iterator equality_op [eq ne])
514 ;; These code iterators allow the signed and unsigned scc operations to use
515 ;; the same template.
516 (define_code_iterator any_gt [gt gtu])
517 (define_code_iterator any_lt [lt ltu])
518 (define_code_iterator any_le [le leu])
520 (define_code_iterator any_return [return simple_return])
522 ;; <u> expands to an empty string when doing a signed operation and
523 ;; "u" when doing an unsigned operation.
524 (define_code_attr u [(sign_extend "") (zero_extend "u")
532 ;; <U> is like <u> except uppercase.
533 (define_code_attr U [(sign_extend "") (zero_extend "U")])
535 ;; <su> is like <u>, but the signed form expands to "s" rather than "".
536 (define_code_attr su [(sign_extend "s") (zero_extend "u")])
538 (define_code_attr u_bool [(sign_extend "false") (zero_extend "true")])
540 ;; <optab> expands to the name of the optab for a particular code.
541 (define_code_attr optab [(ashift "ashl")
556 (simple_return "simple_return")])
558 ;; <insn> expands to the name of the insn that implements a particular code.
559 (define_code_attr insn [(ashift "sll")
573 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
574 (define_code_attr fcond [(unordered "cun")
589 ;; The sel mnemonic to use depending on the condition test.
590 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
591 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
593 ;; Iterator and attributes for floating-point to fixed-point conversion
595 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
596 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
597 (UNSPEC_FTINTRM "lfloor")
598 (UNSPEC_FTINTRP "lceil")])
599 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
600 (UNSPEC_FTINTRM "rm")
601 (UNSPEC_FTINTRP "rp")])
603 ;; Iterator and attributes for bytepick.d
604 (define_int_iterator bytepick_w_ashift_amount [8 16 24])
605 (define_int_attr bytepick_w_lshiftrt_amount [(8 "24")
608 (define_int_iterator bytepick_d_ashift_amount [8 16 24 32 40 48 56])
609 (define_int_attr bytepick_d_lshiftrt_amount [(8 "56")
616 (define_int_attr bytepick_imm [(8 "1")
624 ;; Expand some 32-bit operations to si3_extend operations if TARGET_64BIT
625 ;; so the redundant sign extension can be removed if the output is used as
626 ;; an input of a bitwise operation. Note plus, rotl, and div are handled
628 (define_code_iterator shift_w [any_shift rotatert])
629 (define_code_iterator arith_w [minus mult])
631 (define_expand "<optab><mode>3"
632 [(set (match_operand:GPR 0 "register_operand" "=r")
633 (shift_w:GPR (match_operand:GPR 1 "register_operand" "r")
634 (match_operand:SI 2 "arith_operand" "rI")))]
637 if (TARGET_64BIT && <MODE>mode == SImode)
639 rtx t = gen_reg_rtx (DImode);
640 emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
641 t = gen_lowpart (SImode, t);
642 SUBREG_PROMOTED_VAR_P (t) = 1;
643 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
644 emit_move_insn (operands[0], t);
649 (define_expand "<optab><mode>3"
650 [(set (match_operand:GPR 0 "register_operand" "=r")
651 (arith_w:GPR (match_operand:GPR 1 "register_operand" "r")
652 (match_operand:GPR 2 "register_operand" "r")))]
655 if (TARGET_64BIT && <MODE>mode == SImode)
657 rtx t = gen_reg_rtx (DImode);
658 emit_insn (gen_<optab>si3_extend (t, operands[1], operands[2]));
659 t = gen_lowpart (SImode, t);
660 SUBREG_PROMOTED_VAR_P (t) = 1;
661 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
662 emit_move_insn (operands[0], t);
668 ;; ....................
672 ;; ....................
676 [(trap_if (const_int 1) (const_int 0))]
681 [(set_attr "type" "trap")])
686 ;; ....................
690 ;; ....................
693 (define_insn "add<mode>3"
694 [(set (match_operand:ANYF 0 "register_operand" "=f")
695 (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
696 (match_operand:ANYF 2 "register_operand" "f")))]
698 "fadd.<fmt>\t%0,%1,%2"
699 [(set_attr "type" "fadd")
700 (set_attr "mode" "<UNITMODE>")])
702 (define_insn_and_split "*addsi3"
703 [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
704 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
705 (match_operand:SI 2 "plus_si_operand"
712 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
713 return \"addu16i.d\t%0,%1,%2\";
715 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
716 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
717 [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
718 (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
720 loongarch_split_plus_constant (&operands[2], SImode);
722 [(set_attr "alu_type" "add")
723 (set_attr "mode" "SI")
724 (set_attr "insn_count" "1,1,2,1,2")])
726 (define_expand "addsi3"
727 [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
728 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r,r")
729 (match_operand:SI 2 "plus_si_operand" "r,I,La,Le,Lb")))]
732 if (CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])
733 && ADDU16I_OPERAND (INTVAL (operands[2])))
735 rtx t1 = gen_reg_rtx (DImode);
736 rtx t2 = gen_reg_rtx (DImode);
737 rtx t3 = gen_reg_rtx (DImode);
738 emit_insn (gen_extend_insn (t1, operands[1], DImode, SImode, 0));
740 emit_insn (gen_adddi3 (t3, t1, t2));
741 t3 = gen_lowpart (SImode, t3);
742 emit_move_insn (operands[0], t3);
747 rtx t = gen_reg_rtx (DImode);
748 emit_insn (gen_addsi3_extended (t, operands[1], operands[2]));
749 t = gen_lowpart (SImode, t);
750 SUBREG_PROMOTED_VAR_P (t) = 1;
751 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
752 emit_move_insn (operands[0], t);
757 (define_insn_and_split "adddi3"
758 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
759 (plus:DI (match_operand:DI 1 "register_operand" "r,r,r,r,r,r")
760 (match_operand:DI 2 "plus_di_operand"
761 "r,I,La,Lb,Lc,Ld")))]
767 * operands[2] = GEN_INT (INTVAL (operands[2]) / 65536); \
768 return \"addu16i.d\t%0,%1,%2\";
771 "&& CONST_INT_P (operands[2]) && !IMM12_INT (operands[2]) \
772 && !ADDU16I_OPERAND (INTVAL (operands[2]))"
773 [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
774 (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
776 loongarch_split_plus_constant (&operands[2], DImode);
778 [(set_attr "alu_type" "add")
779 (set_attr "mode" "DI")
780 (set_attr "insn_count" "1,1,2,1,2,2")])
782 (define_insn_and_split "addsi3_extended"
783 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
785 (plus:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
786 (match_operand:SI 2 "plus_si_extend_operand"
794 "CONST_INT_P (operands[2]) && !IMM12_INT (operands[2])"
795 [(set (subreg:SI (match_dup 0) 0) (plus:SI (match_dup 1) (match_dup 3)))
797 (sign_extend:DI (plus:SI (subreg:SI (match_dup 0) 0)
800 loongarch_split_plus_constant (&operands[2], SImode);
802 [(set_attr "alu_type" "add")
803 (set_attr "mode" "SI")
804 (set_attr "insn_count" "1,1,2,2")])
808 ;; ....................
812 ;; ....................
815 (define_insn "sub<mode>3"
816 [(set (match_operand:ANYF 0 "register_operand" "=f")
817 (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
818 (match_operand:ANYF 2 "register_operand" "f")))]
820 "fsub.<fmt>\t%0,%1,%2"
821 [(set_attr "type" "fadd")
822 (set_attr "mode" "<UNITMODE>")])
824 (define_insn "*sub<mode>3"
825 [(set (match_operand:GPR 0 "register_operand" "=r")
826 (minus:GPR (match_operand:GPR 1 "register_operand" "r")
827 (match_operand:GPR 2 "register_operand" "r")))]
830 [(set_attr "alu_type" "sub")
831 (set_attr "mode" "<MODE>")])
834 (define_insn "subsi3_extend"
835 [(set (match_operand:DI 0 "register_operand" "=r")
837 (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
838 (match_operand:SI 2 "register_operand" "r"))))]
841 [(set_attr "type" "arith")
842 (set_attr "mode" "SI")])
845 ;; ....................
849 ;; ....................
852 (define_insn "mul<mode>3"
853 [(set (match_operand:ANYF 0 "register_operand" "=f")
854 (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
855 (match_operand:ANYF 2 "register_operand" "f")))]
857 "fmul.<fmt>\t%0,%1,%2"
858 [(set_attr "type" "fmul")
859 (set_attr "mode" "<MODE>")])
861 (define_insn "*mul<mode>3"
862 [(set (match_operand:GPR 0 "register_operand" "=r")
863 (mult:GPR (match_operand:GPR 1 "register_operand" "r")
864 (match_operand:GPR 2 "register_operand" "r")))]
867 [(set_attr "type" "imul")
868 (set_attr "mode" "<MODE>")])
870 (define_insn "mulsi3_extend"
871 [(set (match_operand:DI 0 "register_operand" "=r")
873 (mult:SI (match_operand:SI 1 "register_operand" "r")
874 (match_operand:SI 2 "register_operand" "r"))))]
877 [(set_attr "type" "imul")
878 (set_attr "mode" "SI")])
881 ;; ........................
883 ;; MULTIPLICATION HIGH-PART
885 ;; ........................
888 (define_expand "<u>mulditi3"
889 [(set (match_operand:TI 0 "register_operand")
890 (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand"))
891 (any_extend:TI (match_operand:DI 2 "register_operand"))))]
894 rtx low = gen_reg_rtx (DImode);
895 emit_insn (gen_muldi3 (low, operands[1], operands[2]));
897 rtx high = gen_reg_rtx (DImode);
898 emit_insn (gen_<su>muldi3_highpart (high, operands[1], operands[2]));
900 emit_move_insn (gen_lowpart (DImode, operands[0]), low);
901 emit_move_insn (gen_highpart (DImode, operands[0]), high);
905 (define_insn "<su>muldi3_highpart"
906 [(set (match_operand:DI 0 "register_operand" "=r")
909 (mult:TI (any_extend:TI
910 (match_operand:DI 1 "register_operand" " r"))
912 (match_operand:DI 2 "register_operand" " r")))
915 "mulh.d<u>\t%0,%1,%2"
916 [(set_attr "type" "imul")
917 (set_attr "mode" "DI")])
919 (define_expand "<u>mulsidi3"
920 [(set (match_operand:DI 0 "register_operand")
921 (mult:DI (any_extend:DI
922 (match_operand:SI 1 "register_operand"))
924 (match_operand:SI 2 "register_operand"))))]
929 rtx temp = gen_reg_rtx (SImode);
930 emit_insn (gen_mulsi3 (temp, operands[1], operands[2]));
931 emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[0], true),
932 operands[1], operands[2]));
933 emit_insn (gen_movsi (loongarch_subword (operands[0], false), temp));
938 (define_insn "<u>mulsidi3_64bit"
939 [(set (match_operand:DI 0 "register_operand" "=r")
940 (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "r"))
941 (any_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
943 "mulw.d.w<u>\t%0,%1,%2"
944 [(set_attr "type" "imul")
945 (set_attr "mode" "DI")])
947 (define_insn "<su>mulsi3_highpart"
948 [(set (match_operand:SI 0 "register_operand" "=r")
951 (mult:DI (any_extend:DI
952 (match_operand:SI 1 "register_operand" " r"))
954 (match_operand:SI 2 "register_operand" " r")))
957 "mulh.w<u>\t%0,%1,%2"
958 [(set_attr "type" "imul")
959 (set_attr "mode" "SI")])
961 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
962 ;; sign extension by default, so the sign extension instruction can be
965 [(set (match_operand:SI 0 "register_operand")
968 (mult:DI (any_extend:DI
969 (match_operand:SI 1 "register_operand"))
971 (match_operand:SI 2 "register_operand")))
973 (set (match_operand:DI 3 "register_operand")
974 (sign_extend:DI (match_dup 0)))]
975 "TARGET_64BIT && REGNO (operands[0]) == REGNO (operands[3])"
976 "mulh.w<u>\t%0,%1,%2")
979 ;; ....................
981 ;; DIVISION and REMAINDER
983 ;; ....................
986 ;; Float division and modulus.
987 (define_expand "div<mode>3"
988 [(set (match_operand:ANYF 0 "register_operand")
989 (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand")
990 (match_operand:ANYF 2 "register_operand")))]
993 if (<MODE>mode == SFmode
995 && optimize_insn_for_speed_p ()
996 && flag_finite_math_only && !flag_trapping_math
997 && flag_unsafe_math_optimizations)
999 loongarch_emit_swdivsf (operands[0], operands[1],
1000 operands[2], SFmode);
1005 (define_insn "*div<mode>3"
1006 [(set (match_operand:ANYF 0 "register_operand" "=f")
1007 (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
1008 (match_operand:ANYF 2 "register_operand" "f")))]
1010 "fdiv.<fmt>\t%0,%1,%2"
1011 [(set_attr "type" "fdiv")
1012 (set_attr "mode" "<UNITMODE>")])
1014 ;; In 3A5000, the reciprocal operation is the same as the division operation.
1016 (define_insn "*recip<mode>3"
1017 [(set (match_operand:ANYF 0 "register_operand" "=f")
1018 (div:ANYF (match_operand:ANYF 1 "const_1_operand" "")
1019 (match_operand:ANYF 2 "register_operand" "f")))]
1021 "frecip.<fmt>\t%0,%2"
1022 [(set_attr "type" "frdiv")
1023 (set_attr "mode" "<UNITMODE>")])
1025 ;; Approximate Reciprocal Instructions.
1027 (define_insn "loongarch_frecipe_<fmt>"
1028 [(set (match_operand:ANYF 0 "register_operand" "=f")
1029 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1032 "frecipe.<fmt>\t%0,%1"
1033 [(set_attr "type" "frecipe")
1034 (set_attr "mode" "<UNITMODE>")
1035 (set_attr "insn_count" "1")])
1037 ;; Integer division and modulus.
1038 (define_expand "<optab><mode>3"
1039 [(set (match_operand:GPR 0 "register_operand")
1040 (any_div:GPR (match_operand:GPR 1 "register_operand")
1041 (match_operand:GPR 2 "register_operand")))]
1044 if (GET_MODE (operands[0]) == SImode && TARGET_64BIT)
1048 rtx t = gen_reg_rtx (DImode);
1049 emit_insn (gen_<optab>si3_extended (t, operands[1], operands[2]));
1050 t = gen_lowpart (SImode, t);
1051 SUBREG_PROMOTED_VAR_P (t) = 1;
1052 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
1053 emit_move_insn (operands[0], t);
1057 rtx reg1 = gen_reg_rtx (DImode);
1058 rtx reg2 = gen_reg_rtx (DImode);
1059 rtx rd = gen_reg_rtx (DImode);
1061 operands[1] = gen_rtx_SIGN_EXTEND (word_mode, operands[1]);
1062 operands[2] = gen_rtx_SIGN_EXTEND (word_mode, operands[2]);
1064 emit_insn (gen_rtx_SET (reg1, operands[1]));
1065 emit_insn (gen_rtx_SET (reg2, operands[2]));
1067 emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
1068 emit_insn (gen_rtx_SET (operands[0],
1069 simplify_gen_subreg (SImode, rd, DImode, 0)));
1074 (define_insn "*<optab><mode>3"
1075 [(set (match_operand:DIV 0 "register_operand" "=r,&r,&r")
1076 (any_div:DIV (match_operand:DIV 1 "register_operand" "r,r,0")
1077 (match_operand:DIV 2 "register_operand" "r,r,r")))]
1080 return loongarch_output_division ("<insn>.<d><u>\t%0,%1,%2", operands);
1082 [(set_attr "type" "idiv")
1083 (set_attr "mode" "<MODE>")
1084 (set (attr "enabled")
1086 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1087 (const_string "yes")
1088 (const_string "no")))])
1090 (define_insn "<optab>si3_extended"
1091 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1093 (any_div:SI (match_operand:SI 1 "register_operand" "r,r,0")
1094 (match_operand:SI 2 "register_operand" "r,r,r"))))]
1095 "TARGET_64BIT && ISA_HAS_DIV32"
1097 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1099 [(set_attr "type" "idiv")
1100 (set_attr "mode" "SI")
1101 (set (attr "enabled")
1103 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1104 (const_string "yes")
1105 (const_string "no")))])
1107 (define_insn "<optab>di3_fake"
1108 [(set (match_operand:DI 0 "register_operand" "=r,&r,&r")
1112 (any_div:DI (match_operand:DI 1 "register_operand" "r,r,0")
1113 (match_operand:DI 2 "register_operand" "r,r,r")) 0)]
1114 UNSPEC_FAKE_ANY_DIV)))]
1115 "TARGET_64BIT && !ISA_HAS_DIV32"
1117 return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands);
1119 [(set_attr "type" "idiv")
1120 (set_attr "mode" "SI")
1121 (set (attr "enabled")
1123 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1124 (const_string "yes")
1125 (const_string "no")))])
1127 ;; Floating point multiply accumulate instructions.
1130 (define_insn "fma<mode>4"
1131 [(set (match_operand:ANYF 0 "register_operand" "=f")
1132 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1133 (match_operand:ANYF 2 "register_operand" "f")
1134 (match_operand:ANYF 3 "register_operand" "f")))]
1136 "fmadd.<fmt>\t%0,%1,%2,%3"
1137 [(set_attr "type" "fmadd")
1138 (set_attr "mode" "<UNITMODE>")])
1141 (define_insn "fms<mode>4"
1142 [(set (match_operand:ANYF 0 "register_operand" "=f")
1143 (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
1144 (match_operand:ANYF 2 "register_operand" "f")
1145 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1147 "fmsub.<fmt>\t%0,%1,%2,%3"
1148 [(set_attr "type" "fmadd")
1149 (set_attr "mode" "<UNITMODE>")])
1151 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1152 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1153 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1154 ;; This transformation means we may return the wrong signed zero
1155 ;; so we check HONOR_SIGNED_ZEROS.
1158 (define_insn "fnma<mode>4"
1159 [(set (match_operand:ANYF 0 "register_operand" "=f")
1160 (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1161 (match_operand:ANYF 2 "register_operand" "f")
1162 (match_operand:ANYF 3 "register_operand" "f")))]
1163 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1164 "fnmsub.<fmt>\t%0,%1,%2,%3"
1165 [(set_attr "type" "fmadd")
1166 (set_attr "mode" "<UNITMODE>")])
1168 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1169 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1170 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1171 ;; This transformation means we may return the wrong signed zero
1172 ;; so we check HONOR_SIGNED_ZEROS.
1175 (define_insn "fnms<mode>4"
1176 [(set (match_operand:ANYF 0 "register_operand" "=f")
1178 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1179 (match_operand:ANYF 2 "register_operand" "f")
1180 (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
1181 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1182 "fnmadd.<fmt>\t%0,%1,%2,%3"
1183 [(set_attr "type" "fmadd")
1184 (set_attr "mode" "<UNITMODE>")])
1186 ;; -(-a * b - c), modulo signed zeros
1187 (define_insn "*fma<mode>4"
1188 [(set (match_operand:ANYF 0 "register_operand" "=f")
1191 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1192 (match_operand:ANYF 2 "register_operand" " f")
1193 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1194 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1195 "fmadd.<fmt>\t%0,%1,%2,%3"
1196 [(set_attr "type" "fmadd")
1197 (set_attr "mode" "<UNITMODE>")])
1199 ;; -(-a * b + c), modulo signed zeros
1200 (define_insn "*fms<mode>4"
1201 [(set (match_operand:ANYF 0 "register_operand" "=f")
1204 (neg:ANYF (match_operand:ANYF 1 "register_operand" " f"))
1205 (match_operand:ANYF 2 "register_operand" " f")
1206 (match_operand:ANYF 3 "register_operand" " f"))))]
1207 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1208 "fmsub.<fmt>\t%0,%1,%2,%3"
1209 [(set_attr "type" "fmadd")
1210 (set_attr "mode" "<UNITMODE>")])
1213 (define_insn "*fnms<mode>4"
1214 [(set (match_operand:ANYF 0 "register_operand" "=f")
1217 (match_operand:ANYF 1 "register_operand" " f")
1218 (match_operand:ANYF 2 "register_operand" " f")
1219 (match_operand:ANYF 3 "register_operand" " f"))))]
1221 "fnmadd.<fmt>\t%0,%1,%2,%3"
1222 [(set_attr "type" "fmadd")
1223 (set_attr "mode" "<UNITMODE>")])
1226 (define_insn "*fnma<mode>4"
1227 [(set (match_operand:ANYF 0 "register_operand" "=f")
1230 (match_operand:ANYF 1 "register_operand" " f")
1231 (match_operand:ANYF 2 "register_operand" " f")
1232 (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))]
1234 "fnmsub.<fmt>\t%0,%1,%2,%3"
1235 [(set_attr "type" "fmadd")
1236 (set_attr "mode" "<UNITMODE>")])
1239 ;; ....................
1243 ;; ....................
1245 (define_expand "sqrt<mode>2"
1246 [(set (match_operand:ANYF 0 "register_operand")
1247 (sqrt:ANYF (match_operand:ANYF 1 "register_operand")))]
1250 if (<MODE>mode == SFmode
1251 && TARGET_RECIP_SQRT
1252 && flag_unsafe_math_optimizations
1253 && !optimize_insn_for_size_p ()
1254 && flag_finite_math_only && !flag_trapping_math)
1256 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 0);
1261 (define_insn "*sqrt<mode>2"
1262 [(set (match_operand:ANYF 0 "register_operand" "=f")
1263 (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1265 "fsqrt.<fmt>\t%0,%1"
1266 [(set_attr "type" "fsqrt")
1267 (set_attr "mode" "<UNITMODE>")
1268 (set_attr "insn_count" "1")])
1270 (define_expand "rsqrt<mode>2"
1271 [(set (match_operand:ANYF 0 "register_operand")
1272 (unspec:ANYF [(match_operand:ANYF 1 "register_operand")]
1276 if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1278 loongarch_emit_swrsqrtsf (operands[0], operands[1], SFmode, 1);
1283 (define_insn "*rsqrt<mode>2"
1284 [(set (match_operand:ANYF 0 "register_operand" "=f")
1285 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1288 "frsqrt.<fmt>\t%0,%1"
1289 [(set_attr "type" "frsqrt")
1290 (set_attr "mode" "<UNITMODE>")])
1292 ;; Approximate Reciprocal Square Root Instructions.
1294 (define_insn "loongarch_frsqrte_<fmt>"
1295 [(set (match_operand:ANYF 0 "register_operand" "=f")
1296 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1299 "frsqrte.<fmt>\t%0,%1"
1300 [(set_attr "type" "frsqrte")
1301 (set_attr "mode" "<UNITMODE>")])
1304 ;; ....................
1308 ;; ....................
1310 (define_insn "abs<mode>2"
1311 [(set (match_operand:ANYF 0 "register_operand" "=f")
1312 (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1315 [(set_attr "type" "fabs")
1316 (set_attr "mode" "<UNITMODE>")])
1319 ;; ....................
1321 ;; FLOATING POINT COPYSIGN
1323 ;; ....................
1325 (define_insn "copysign<mode>3"
1326 [(set (match_operand:ANYF 0 "register_operand" "=f")
1327 (copysign:ANYF (match_operand:ANYF 1 "register_operand" "f")
1328 (match_operand:ANYF 2 "register_operand" "f")))]
1330 "fcopysign.<fmt>\t%0,%1,%2"
1331 [(set_attr "type" "fcopysign")
1332 (set_attr "mode" "<UNITMODE>")])
1334 (define_expand "@xorsign<mode>3"
1335 [(match_operand:ANYF 0 "register_operand")
1336 (match_operand:ANYF 1 "register_operand")
1337 (match_operand:ANYF 2 "register_operand")]
1340 machine_mode lsx_mode
1341 = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1342 rtx tmp = gen_reg_rtx (lsx_mode);
1343 rtx op1 = lowpart_subreg (lsx_mode, operands[1], <MODE>mode);
1344 rtx op2 = lowpart_subreg (lsx_mode, operands[2], <MODE>mode);
1345 emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1346 emit_move_insn (operands[0],
1347 lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1352 ;; ....................
1354 ;; FLOATING POINT SCALE
1356 ;; ....................
1358 (define_insn "ldexp<mode>3"
1359 [(set (match_operand:ANYF 0 "register_operand" "=f")
1360 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")
1361 (match_operand:<IMODE> 2 "register_operand" "f")]
1364 "fscaleb.<fmt>\t%0,%1,%2"
1365 [(set_attr "type" "fscaleb")
1366 (set_attr "mode" "<UNITMODE>")])
1369 ;; ....................
1371 ;; FLOATING POINT EXPONENT EXTRACT
1373 ;; ....................
1375 (define_insn "logb_non_negative<mode>2"
1376 [(set (match_operand:ANYF 0 "register_operand" "=f")
1377 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
1380 "flogb.<fmt>\t%0,%1"
1381 [(set_attr "type" "flogb")
1382 (set_attr "mode" "<UNITMODE>")])
1384 (define_expand "logb<mode>2"
1385 [(set (match_operand:ANYF 0 "register_operand")
1386 (unspec:ANYF [(abs:ANYF (match_operand:ANYF 1 "register_operand"))]
1390 rtx tmp = gen_reg_rtx (<MODE>mode);
1392 emit_insn (gen_abs<mode>2 (tmp, operands[1]));
1393 emit_insn (gen_logb_non_negative<mode>2 (operands[0], tmp));
1398 ;; ...................
1400 ;; Count leading zeroes.
1402 ;; ...................
1405 (define_insn "clz<mode>2"
1406 [(set (match_operand:GPR 0 "register_operand" "=r")
1407 (clz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1410 [(set_attr "type" "clz")
1411 (set_attr "mode" "<MODE>")])
1414 ;; ...................
1416 ;; Count trailing zeroes.
1418 ;; ...................
1421 (define_insn "ctz<mode>2"
1422 [(set (match_operand:GPR 0 "register_operand" "=r")
1423 (ctz:GPR (match_operand:GPR 1 "register_operand" "r")))]
1426 [(set_attr "type" "clz")
1427 (set_attr "mode" "<MODE>")])
1430 ;; ....................
1434 ;; ....................
1436 (define_insn "smax<mode>3"
1437 [(set (match_operand:ANYF 0 "register_operand" "=f")
1438 (smax:ANYF (match_operand:ANYF 1 "register_operand" "f")
1439 (match_operand:ANYF 2 "register_operand" "f")))]
1441 "fmax.<fmt>\t%0,%1,%2"
1442 [(set_attr "type" "fmove")
1443 (set_attr "mode" "<MODE>")])
1445 (define_insn "smin<mode>3"
1446 [(set (match_operand:ANYF 0 "register_operand" "=f")
1447 (smin:ANYF (match_operand:ANYF 1 "register_operand" "f")
1448 (match_operand:ANYF 2 "register_operand" "f")))]
1450 "fmin.<fmt>\t%0,%1,%2"
1451 [(set_attr "type" "fmove")
1452 (set_attr "mode" "<MODE>")])
1454 (define_insn "fmax<mode>3"
1455 [(set (match_operand:ANYF 0 "register_operand" "=f")
1456 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1457 (use (match_operand:ANYF 2 "register_operand" "f"))]
1460 "fmax.<fmt>\t%0,%1,%2"
1461 [(set_attr "type" "fmove")
1462 (set_attr "mode" "<MODE>")])
1464 (define_insn "fmin<mode>3"
1465 [(set (match_operand:ANYF 0 "register_operand" "=f")
1466 (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" "f"))
1467 (use (match_operand:ANYF 2 "register_operand" "f"))]
1470 "fmin.<fmt>\t%0,%1,%2"
1471 [(set_attr "type" "fmove")
1472 (set_attr "mode" "<MODE>")])
1474 (define_insn "smaxa<mode>3"
1475 [(set (match_operand:ANYF 0 "register_operand" "=f")
1477 (gt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1478 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1482 "fmaxa.<fmt>\t%0,%1,%2"
1483 [(set_attr "type" "fmove")
1484 (set_attr "mode" "<MODE>")])
1486 (define_insn "smina<mode>3"
1487 [(set (match_operand:ANYF 0 "register_operand" "=f")
1489 (lt (abs:ANYF (match_operand:ANYF 1 "register_operand" "f"))
1490 (abs:ANYF (match_operand:ANYF 2 "register_operand" "f")))
1494 "fmina.<fmt>\t%0,%1,%2"
1495 [(set_attr "type" "fmove")
1496 (set_attr "mode" "<MODE>")])
1499 ;; ....................
1501 ;; NEGATION and ONE'S COMPLEMENT
1503 ;; ....................
1505 (define_insn "neg<mode>2"
1506 [(set (match_operand:GPR 0 "register_operand" "=r")
1507 (neg:GPR (match_operand:GPR 1 "register_operand" "r")))]
1510 [(set_attr "alu_type" "sub")
1511 (set_attr "mode" "<MODE>")])
1513 (define_insn "*negsi2_extended"
1514 [(set (match_operand:DI 0 "register_operand" "=r")
1515 (sign_extend:DI (neg:SI (match_operand:SI 1 "register_operand" "r"))))]
1518 [(set_attr "alu_type" "sub")
1519 (set_attr "mode" "SI")])
1521 (define_insn "neg<mode>2"
1522 [(set (match_operand:ANYF 0 "register_operand" "=f")
1523 (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
1526 [(set_attr "type" "fneg")
1527 (set_attr "mode" "<UNITMODE>")])
1531 ;; ....................
1535 ;; ....................
1538 (define_insn "<optab><mode>3"
1539 [(set (match_operand:X 0 "register_operand" "=r,r")
1540 (any_bitwise:X (match_operand:X 1 "register_operand" "%r,r")
1541 (match_operand:X 2 "uns_arith_operand" "r,K")))]
1543 "<insn>%i2\t%0,%1,%2"
1544 [(set_attr "type" "logical")
1545 (set_attr "mode" "<MODE>")])
1547 (define_insn "*<optab>si3_internal"
1548 [(set (match_operand:SI 0 "register_operand" "=r,r")
1549 (any_bitwise:SI (match_operand:SI 1 "register_operand" "%r,r")
1550 (match_operand:SI 2 "uns_arith_operand" " r,K")))]
1552 "<insn>%i2\t%0,%1,%2"
1553 [(set_attr "type" "logical")
1554 (set_attr "mode" "SI")])
1556 (define_insn "one_cmpl<mode>2"
1557 [(set (match_operand:X 0 "register_operand" "=r")
1558 (not:X (match_operand:X 1 "register_operand" "r")))]
1561 [(set_attr "alu_type" "not")
1562 (set_attr "mode" "<MODE>")])
1564 (define_insn "*one_cmplsi2_internal"
1565 [(set (match_operand:SI 0 "register_operand" "=r")
1566 (not:SI (match_operand:SI 1 "register_operand" " r")))]
1569 [(set_attr "type" "logical")
1570 (set_attr "mode" "SI")])
1572 (define_insn "and<mode>3_extended"
1573 [(set (match_operand:GPR 0 "register_operand" "=r")
1574 (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "r")
1575 (match_operand:GPR 2 "low_bitmask_operand" "Yx")))]
1580 len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
1581 operands[2] = GEN_INT (len-1);
1582 return "bstrpick.<d>\t%0,%1,%2,0";
1584 [(set_attr "move_type" "pick_ins")
1585 (set_attr "mode" "<MODE>")])
1587 (define_insn_and_split "*bstrins_<mode>_for_mask"
1588 [(set (match_operand:GPR 0 "register_operand" "=r")
1589 (and:GPR (match_operand:GPR 1 "register_operand" "r")
1590 (match_operand:GPR 2 "ins_zero_bitmask_operand" "i")))]
1594 [(set (match_dup 0) (match_dup 1))
1595 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 3))
1598 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1599 int lo = ffs_hwi (mask) - 1;
1600 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1602 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1603 operands[2] = GEN_INT (len);
1604 operands[3] = GEN_INT (lo);
1607 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1608 [(set (match_operand:GPR 0 "register_operand" "=r")
1609 (ior:GPR (and:GPR (match_operand:GPR 1 "register_operand" "r")
1610 (match_operand:GPR 2 "const_int_operand" "i"))
1611 (and:GPR (match_operand:GPR 3 "register_operand" "r")
1612 (match_operand:GPR 4 "const_int_operand" "i"))))]
1613 "loongarch_pre_reload_split ()
1614 && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1617 [(set (match_dup 0) (match_dup 1))
1618 (set (zero_extract:GPR (match_dup 0) (match_dup 2) (match_dup 4))
1621 if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) < 0)
1623 std::swap (operands[1], operands[3]);
1624 std::swap (operands[2], operands[4]);
1627 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[2]);
1628 int lo = ffs_hwi (mask) - 1;
1629 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1631 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1632 operands[2] = GEN_INT (len);
1633 operands[4] = GEN_INT (lo);
1637 rtx tmp = gen_reg_rtx (<MODE>mode);
1638 emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[3],
1644 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1645 ;; if possible, but the result may be sub-optimal when one of the masks
1646 ;; is (1 << N) - 1 and one of the src register is the dest register.
1650 ;; bstrins.d a0, t0, 42, 0
1652 ;; using a shift operation would be better:
1653 ;; srai.d t0, a1, 43
1654 ;; bstrins.d a0, t0, 63, 43
1656 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1657 ;; know if the dest register is one of the src register. Fix it up in
1660 [(set (match_operand:GPR 0 "register_operand")
1661 (match_operand:GPR 1 "register_operand"))
1662 (set (match_dup 1) (match_operand:GPR 2 "register_operand"))
1663 (set (zero_extract:GPR (match_dup 1)
1664 (match_operand:SI 3 "const_int_operand")
1667 "peep2_reg_dead_p (3, operands[0])"
1670 int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[3]);
1672 emit_insn (gen_ashr<mode>3 (operands[0], operands[2], operands[3]));
1673 emit_insn (gen_insv<mode> (operands[1], GEN_INT (len), operands[3],
1678 (define_insn "*iorhi3"
1679 [(set (match_operand:HI 0 "register_operand" "=r,r")
1680 (ior:HI (match_operand:HI 1 "register_operand" "%r,r")
1681 (match_operand:HI 2 "uns_arith_operand" "r,K")))]
1684 [(set_attr "type" "logical")
1685 (set_attr "mode" "HI")])
1687 (define_insn "nor<mode>3"
1688 [(set (match_operand:X 0 "register_operand" "=r")
1689 (and:X (not:X (match_operand:X 1 "register_operand" "%r"))
1690 (not:X (match_operand:X 2 "register_operand" "r"))))]
1693 [(set_attr "type" "logical")
1694 (set_attr "mode" "<MODE>")])
1696 (define_insn "*norsi3_internal"
1697 [(set (match_operand:SI 0 "register_operand" "=r")
1698 (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
1699 (not:SI (match_operand:SI 2 "register_operand" "r"))))]
1702 [(set_attr "type" "logical")
1703 (set_attr "mode" "SI")])
1705 (define_insn "<optab>n<mode>3"
1706 [(set (match_operand:X 0 "register_operand" "=r")
1708 (not:X (match_operand:X 2 "register_operand" "r"))
1709 (match_operand:X 1 "register_operand" "r")))]
1712 [(set_attr "type" "logical")
1713 (set_attr "mode" "<MODE>")])
1715 (define_insn "*<optab>nsi_internal"
1716 [(set (match_operand:SI 0 "register_operand" "=r")
1718 (not:SI (match_operand:SI 1 "register_operand" "r"))
1719 (match_operand:SI 2 "register_operand" "r")))]
1722 [(set_attr "type" "logical")
1723 (set_attr "mode" "SI")])
1726 ;; ....................
1730 ;; ....................
1732 (define_insn "truncdfsf2"
1733 [(set (match_operand:SF 0 "register_operand" "=f")
1734 (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
1735 "TARGET_DOUBLE_FLOAT"
1737 [(set_attr "type" "fcvt")
1738 (set_attr "cnv_mode" "D2S")
1739 (set_attr "mode" "SF")])
1741 ;; In vector registers, popcount can be implemented directly through
1742 ;; the vector instruction [X]VPCNT. For GP registers, we can implement
1743 ;; it through the following method. Compared with loop implementation
1744 ;; of popcount, the following method has better performance.
1746 ;; This attribute used for get connection of scalar mode and corresponding
1748 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1750 (define_expand "popcount<mode>2"
1751 [(set (match_operand:GPR 0 "register_operand")
1752 (popcount:GPR (match_operand:GPR 1 "register_operand")))]
1755 rtx in = operands[1];
1756 rtx out = operands[0];
1757 rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1758 gen_reg_rtx (V2DImode);
1759 emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (1)));
1760 emit_insn (gen_popcount<cntmap>2 (vreg, vreg));
1761 emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (0)));
1766 ;; ....................
1770 ;; ....................
1771 (define_expand "zero_extendsidi2"
1772 [(set (match_operand:DI 0 "register_operand")
1773 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
1776 (define_insn_and_split "*zero_extendsidi2_internal"
1777 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
1778 (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,ZC,k")))]
1781 bstrpick.d\t%0,%1,31,0
1785 "&& reload_completed
1786 && MEM_P (operands[1])
1787 && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[1], 0), SImode)
1788 && !loongarch_12bit_offset_address_p (XEXP (operands[1], 0), SImode))
1789 && !paradoxical_subreg_p (operands[0])"
1790 [(set (match_dup 3) (match_dup 1))
1792 (ior:DI (zero_extend:DI
1793 (subreg:SI (match_dup 0) 0))
1796 operands[1] = gen_lowpart (SImode, operands[1]);
1797 operands[3] = gen_lowpart (SImode, operands[0]);
1798 operands[2] = const0_rtx;
1800 [(set_attr "move_type" "arith,load,load,load")
1801 (set_attr "mode" "DI")])
1803 (define_insn "zero_extend<SHORT:mode><GPR:mode>2"
1804 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1806 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1809 bstrpick.w\t%0,%1,<SHORT:7_or_15>,0
1810 ld.<SHORT:size>u\t%0,%1
1811 ldx.<SHORT:size>u\t%0,%1"
1812 [(set_attr "move_type" "pick_ins,load,load")
1813 (set_attr "mode" "<GPR:MODE>")])
1815 (define_insn "zero_extendqihi2"
1816 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1817 (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,k,m")))]
1823 [(set_attr "move_type" "andi,load,load")
1824 (set_attr "mode" "HI")])
1826 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1828 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1829 [(set (match_operand:GPR 0 "register_operand" "=r")
1831 (truncate:SHORT (match_operand:DI 1 "register_operand" "r"))))]
1833 "bstrpick.w\t%0,%1,<SHORT:7_or_15>,0"
1834 [(set_attr "move_type" "pick_ins")
1835 (set_attr "mode" "<GPR:MODE>")])
1837 (define_insn "*zero_extendhi_truncqi"
1838 [(set (match_operand:HI 0 "register_operand" "=r")
1840 (truncate:QI (match_operand:DI 1 "register_operand" "r"))))]
1843 [(set_attr "alu_type" "and")
1844 (set_attr "mode" "HI")])
1847 ;; ....................
1851 ;; ....................
1853 (define_insn "extendsidi2"
1854 [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
1856 (match_operand:SI 1 "nonimmediate_operand" "r,ZC,m,k,f")))]
1864 [(set_attr "move_type" "sll0,load,load,load,mftg")
1865 (set_attr "mode" "DI")])
1867 (define_insn "extend<SHORT:mode><GPR:mode>2"
1868 [(set (match_operand:GPR 0 "register_operand" "=r,r,r")
1870 (match_operand:SHORT 1 "nonimmediate_operand" "r,m,k")))]
1873 ext.w.<SHORT:size>\t%0,%1
1874 ld.<SHORT:size>\t%0,%1
1875 ldx.<SHORT:size>\t%0,%1"
1876 [(set_attr "move_type" "signext,load,load")
1877 (set_attr "mode" "<GPR:MODE>")])
1879 (define_insn "extendqihi2"
1880 [(set (match_operand:HI 0 "register_operand" "=r,r,r")
1882 (match_operand:QI 1 "nonimmediate_operand" "r,m,k")))]
1888 [(set_attr "move_type" "signext,load,load")
1889 (set_attr "mode" "SI")])
1891 (define_insn "extendsfdf2"
1892 [(set (match_operand:DF 0 "register_operand" "=f")
1893 (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
1894 "TARGET_DOUBLE_FLOAT"
1896 [(set_attr "type" "fcvt")
1897 (set_attr "cnv_mode" "S2D")
1898 (set_attr "mode" "DF")])
1901 ;; ....................
1905 ;; ....................
1907 ;; conversion of a floating-point value to a integer
1909 (define_insn "fix_trunc<ANYF:mode><GPR:mode>2"
1910 [(set (match_operand:GPR 0 "register_operand" "=f")
1911 (fix:GPR (match_operand:ANYF 1 "register_operand" "f")))]
1913 "ftintrz.<GPR:ifmt>.<ANYF:fmt> %0,%1"
1914 [(set_attr "type" "fcvt")
1915 (set_attr "mode" "<ANYF:MODE>")])
1917 ;; conversion of an integeral (or boolean) value to a floating-point value
1919 (define_insn "floatsidf2"
1920 [(set (match_operand:DF 0 "register_operand" "=f")
1921 (float:DF (match_operand:SI 1 "register_operand" "f")))]
1922 "TARGET_DOUBLE_FLOAT"
1924 [(set_attr "type" "fcvt")
1925 (set_attr "mode" "DF")
1926 (set_attr "cnv_mode" "I2D")])
1928 (define_insn "floatdidf2"
1929 [(set (match_operand:DF 0 "register_operand" "=f")
1930 (float:DF (match_operand:DI 1 "register_operand" "f")))]
1931 "TARGET_DOUBLE_FLOAT"
1933 [(set_attr "type" "fcvt")
1934 (set_attr "mode" "DF")
1935 (set_attr "cnv_mode" "I2D")])
1937 (define_insn "floatsisf2"
1938 [(set (match_operand:SF 0 "register_operand" "=f")
1939 (float:SF (match_operand:SI 1 "register_operand" "f")))]
1942 [(set_attr "type" "fcvt")
1943 (set_attr "mode" "SF")
1944 (set_attr "cnv_mode" "I2S")])
1946 (define_insn "floatdisf2"
1947 [(set (match_operand:SF 0 "register_operand" "=f")
1948 (float:SF (match_operand:DI 1 "register_operand" "f")))]
1949 "TARGET_DOUBLE_FLOAT"
1951 [(set_attr "type" "fcvt")
1952 (set_attr "mode" "SF")
1953 (set_attr "cnv_mode" "I2S")])
1955 ;; Convert a floating-point value to an unsigned integer.
1957 (define_expand "fixuns_truncdfsi2"
1958 [(set (match_operand:SI 0 "register_operand")
1959 (unsigned_fix:SI (match_operand:DF 1 "register_operand")))]
1960 "TARGET_DOUBLE_FLOAT"
1962 rtx reg1 = gen_reg_rtx (DFmode);
1963 rtx reg2 = gen_reg_rtx (DFmode);
1964 rtx reg3 = gen_reg_rtx (SImode);
1965 rtx_code_label *label1 = gen_label_rtx ();
1966 rtx_code_label *label2 = gen_label_rtx ();
1968 REAL_VALUE_TYPE offset;
1970 real_2expN (&offset, 31, DFmode);
1972 loongarch_emit_move (reg1,
1973 const_double_from_real_value (offset, DFmode));
1974 do_pending_stack_adjust ();
1976 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
1977 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
1979 emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
1980 emit_jump_insn (gen_rtx_SET (pc_rtx,
1981 gen_rtx_LABEL_REF (VOIDmode, label2)));
1984 emit_label (label1);
1985 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
1986 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1987 (BITMASK_HIGH, SImode)));
1989 emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
1990 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
1992 emit_label (label2);
1994 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1995 fields, and can't be used for REG_NOTES anyway). */
1996 emit_use (stack_pointer_rtx);
2000 (define_expand "fixuns_truncdfdi2"
2001 [(set (match_operand:DI 0 "register_operand")
2002 (unsigned_fix:DI (match_operand:DF 1 "register_operand")))]
2003 "TARGET_DOUBLE_FLOAT"
2005 rtx reg1 = gen_reg_rtx (DFmode);
2006 rtx reg2 = gen_reg_rtx (DFmode);
2007 rtx reg3 = gen_reg_rtx (DImode);
2008 rtx_code_label *label1 = gen_label_rtx ();
2009 rtx_code_label *label2 = gen_label_rtx ();
2011 REAL_VALUE_TYPE offset;
2013 real_2expN (&offset, 63, DFmode);
2015 loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
2016 do_pending_stack_adjust ();
2018 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2019 emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1));
2021 emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1]));
2022 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2025 emit_label (label1);
2026 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1));
2027 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2028 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2030 emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
2031 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2033 emit_label (label2);
2035 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2036 fields, and can't be used for REG_NOTES anyway). */
2037 emit_use (stack_pointer_rtx);
2041 (define_expand "fixuns_truncsfsi2"
2042 [(set (match_operand:SI 0 "register_operand")
2043 (unsigned_fix:SI (match_operand:SF 1 "register_operand")))]
2046 rtx reg1 = gen_reg_rtx (SFmode);
2047 rtx reg2 = gen_reg_rtx (SFmode);
2048 rtx reg3 = gen_reg_rtx (SImode);
2049 rtx_code_label *label1 = gen_label_rtx ();
2050 rtx_code_label *label2 = gen_label_rtx ();
2052 REAL_VALUE_TYPE offset;
2054 real_2expN (&offset, 31, SFmode);
2056 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2057 do_pending_stack_adjust ();
2059 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2060 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2062 emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
2063 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2066 emit_label (label1);
2067 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2068 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
2069 (BITMASK_HIGH, SImode)));
2071 emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
2072 emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
2074 emit_label (label2);
2076 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2077 fields, and can't be used for REG_NOTES anyway). */
2078 emit_use (stack_pointer_rtx);
2082 (define_expand "fixuns_truncsfdi2"
2083 [(set (match_operand:DI 0 "register_operand")
2084 (unsigned_fix:DI (match_operand:SF 1 "register_operand")))]
2085 "TARGET_DOUBLE_FLOAT"
2087 rtx reg1 = gen_reg_rtx (SFmode);
2088 rtx reg2 = gen_reg_rtx (SFmode);
2089 rtx reg3 = gen_reg_rtx (DImode);
2090 rtx_code_label *label1 = gen_label_rtx ();
2091 rtx_code_label *label2 = gen_label_rtx ();
2093 REAL_VALUE_TYPE offset;
2095 real_2expN (&offset, 63, SFmode);
2097 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2098 do_pending_stack_adjust ();
2100 test = gen_rtx_GE (VOIDmode, operands[1], reg1);
2101 emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1));
2103 emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1]));
2104 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2107 emit_label (label1);
2108 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1));
2109 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2110 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32)));
2112 emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
2113 emit_insn (gen_iordi3 (operands[0], operands[0], reg3));
2115 emit_label (label2);
2117 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2118 fields, and can't be used for REG_NOTES anyway). */
2119 emit_use (stack_pointer_rtx);
2124 ;; ....................
2126 ;; EXTRACT AND INSERT
2128 ;; ....................
2130 (define_expand "extzv<mode>"
2131 [(set (match_operand:X 0 "register_operand")
2132 (zero_extract:X (match_operand:X 1 "register_operand")
2133 (match_operand 2 "const_int_operand")
2134 (match_operand 3 "const_int_operand")))]
2137 if (!loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2138 INTVAL (operands[3])))
2142 (define_insn "*extzv<mode>"
2143 [(set (match_operand:X 0 "register_operand" "=r")
2144 (zero_extract:X (match_operand:X 1 "register_operand" "r")
2145 (match_operand 2 "const_int_operand" "")
2146 (match_operand 3 "const_int_operand" "")))]
2147 "loongarch_use_ins_ext_p (operands[1], INTVAL (operands[2]),
2148 INTVAL (operands[3]))"
2150 operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
2151 return "bstrpick.<d>\t%0,%1,%2,%3";
2153 [(set_attr "type" "arith")
2154 (set_attr "mode" "<MODE>")])
2156 (define_expand "insv<mode>"
2157 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand")
2158 (match_operand 1 "const_int_operand")
2159 (match_operand 2 "const_int_operand"))
2160 (match_operand:GPR 3 "reg_or_0_operand"))]
2163 if (!loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2164 INTVAL (operands[2])))
2168 (define_insn "*insv<mode>"
2169 [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+r")
2170 (match_operand:SI 1 "const_int_operand" "")
2171 (match_operand:SI 2 "const_int_operand" ""))
2172 (match_operand:GPR 3 "reg_or_0_operand" "rJ"))]
2173 "loongarch_use_ins_ext_p (operands[0], INTVAL (operands[1]),
2174 INTVAL (operands[2]))"
2176 operands[1] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
2177 return "bstrins.<d>\t%0,%z3,%1,%2";
2179 [(set_attr "type" "arith")
2180 (set_attr "mode" "<MODE>")])
2183 ;; ....................
2187 ;; ....................
2189 ;; 64-bit integer moves
2191 ;; Unlike most other insns, the move insns can't be split with
2192 ;; different predicates, because register spilling and other parts of
2193 ;; the compiler, have memoized the insn number already.
2195 (define_expand "movdi"
2196 [(set (match_operand:DI 0 "")
2197 (match_operand:DI 1 ""))]
2200 if (loongarch_legitimize_move (DImode, operands[0], operands[1]))
2204 (define_insn_and_split "*movdi_32bit"
2205 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2206 (match_operand:DI 1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2208 && (register_operand (operands[0], DImode)
2209 || reg_or_0_operand (operands[1], DImode))"
2210 { return loongarch_output_move (operands[0], operands[1]); }
2211 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2216 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2220 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2221 (set_attr "mode" "DI")])
2223 (define_insn_and_split "*movdi_64bit"
2224 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2225 (match_operand:DI 1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2227 && (register_operand (operands[0], DImode)
2228 || reg_or_0_operand (operands[1], DImode))"
2229 { return loongarch_output_move (operands[0], operands[1]); }
2230 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2235 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2239 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2240 (set_attr "mode" "DI")])
2242 ;; Use two registers to get the global symbol address from the got table.
2243 ;; la.global rd, rt, sym
2245 (define_insn_and_split "movdi_symbolic_off64"
2246 [(set (match_operand:DI 0 "register_operand" "=r,r")
2247 (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r"))
2248 (unspec:DI [(const_int 0)]
2249 UNSPEC_LOAD_SYMBOL_OFFSET64)
2250 (clobber (match_operand:DI 2 "register_operand" "=&r,r"))]
2251 "TARGET_64BIT && TARGET_CMODEL_EXTREME"
2253 if (which_alternative == 1)
2256 enum loongarch_symbol_type symbol_type;
2257 gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2259 switch (symbol_type)
2261 case SYMBOL_PCREL64:
2262 return "la.local\t%0,%2,%1";
2263 case SYMBOL_GOT_DISP:
2264 return "la.global\t%0,%2,%1";
2266 return "la.tls.ie\t%0,%2,%1";
2268 return "la.tls.gd\t%0,%2,%1";
2270 return "la.tls.ld\t%0,%2,%1";
2276 "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0"
2277 [(set (match_dup 0) (match_dup 1))]
2279 [(set_attr "mode" "DI")
2280 (set_attr "insn_count" "5")])
2282 ;; The 64-bit PC-relative part of address loading.
2283 ;; Note that the psABI does not allow splitting it.
2284 (define_insn "la_pcrel64_two_parts"
2285 [(set (match_operand:DI 0 "register_operand" "=r")
2286 (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1))
2287 (set (match_operand:DI 1 "register_operand" "=r")
2288 (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))]
2289 "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE"
2291 return "pcalau12i\t%0,%r2\n\t"
2292 "addi.d\t%1,$r0,%L2\n\t"
2293 "lu32i.d\t%1,%R2\n\t"
2294 "lu52i.d\t%1,%1,%H2";
2296 [(set_attr "move_type" "move")
2297 (set_attr "mode" "DI")
2298 (set_attr "length" "16")])
2300 ;; 32-bit Integer moves
2302 (define_expand "movsi"
2303 [(set (match_operand:SI 0 "")
2304 (match_operand:SI 1 ""))]
2307 if (loongarch_legitimize_move (SImode, operands[0], operands[1]))
2311 (define_insn_and_split "*movsi_internal"
2312 [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m")
2313 (match_operand:SI 1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f"))]
2314 "(register_operand (operands[0], SImode)
2315 || reg_or_0_operand (operands[1], SImode))"
2316 { return loongarch_output_move (operands[0], operands[1]); }
2317 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2322 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2326 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2327 (set_attr "mode" "SI")])
2329 ;; 16-bit Integer moves
2331 ;; Unlike most other insns, the move insns can't be split with
2332 ;; different predicates, because register spilling and other parts of
2333 ;; the compiler, have memoized the insn number already.
2334 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2336 (define_expand "movhi"
2337 [(set (match_operand:HI 0 "")
2338 (match_operand:HI 1 ""))]
2341 if (loongarch_legitimize_move (HImode, operands[0], operands[1]))
2345 (define_insn_and_split "*movhi_internal"
2346 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2347 (match_operand:HI 1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2348 "(register_operand (operands[0], HImode)
2349 || reg_or_0_operand (operands[1], HImode))"
2350 { return loongarch_output_move (operands[0], operands[1]); }
2351 "CONST_INT_P (operands[1]) && REG_P (operands[0]) && GP_REG_P (REGNO
2356 loongarch_move_integer (operands[0], operands[0], INTVAL (operands[1]));
2360 [(set_attr "move_type" "move,const,const,load,store,load,store")
2361 (set_attr "mode" "HI")])
2363 ;; 8-bit Integer moves
2365 ;; Unlike most other insns, the move insns can't be split with
2366 ;; different predicates, because register spilling and other parts of
2367 ;; the compiler, have memoized the insn number already.
2368 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2370 (define_expand "movqi"
2371 [(set (match_operand:QI 0 "")
2372 (match_operand:QI 1 ""))]
2375 if (loongarch_legitimize_move (QImode, operands[0], operands[1]))
2379 (define_insn "*movqi_internal"
2380 [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m,r,k")
2381 (match_operand:QI 1 "move_operand" "r,I,m,rJ,k,rJ"))]
2382 "(register_operand (operands[0], QImode)
2383 || reg_or_0_operand (operands[1], QImode))"
2384 { return loongarch_output_move (operands[0], operands[1]); }
2385 [(set_attr "move_type" "move,const,load,store,load,store")
2386 (set_attr "mode" "QI")])
2388 ;; 32-bit floating point moves
2390 (define_expand "movsf"
2391 [(set (match_operand:SF 0 "")
2392 (match_operand:SF 1 ""))]
2395 if (loongarch_legitimize_move (SFmode, operands[0], operands[1]))
2399 (define_insn "*movsf_hardfloat"
2400 [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2401 (match_operand:SF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2403 && (register_operand (operands[0], SFmode)
2404 || reg_or_0_operand (operands[1], SFmode))"
2405 { return loongarch_output_move (operands[0], operands[1]); }
2406 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2407 (set_attr "mode" "SF")])
2409 (define_insn "*movsf_softfloat"
2410 [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
2411 (match_operand:SF 1 "move_operand" "Gr,m,r"))]
2413 && (register_operand (operands[0], SFmode)
2414 || reg_or_0_operand (operands[1], SFmode))"
2415 { return loongarch_output_move (operands[0], operands[1]); }
2416 [(set_attr "move_type" "move,load,store")
2417 (set_attr "mode" "SF")])
2419 ;; 64-bit floating point moves
2421 (define_expand "movdf"
2422 [(set (match_operand:DF 0 "")
2423 (match_operand:DF 1 ""))]
2426 if (loongarch_legitimize_move (DFmode, operands[0], operands[1]))
2430 (define_insn "*movdf_hardfloat"
2431 [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2432 (match_operand:DF 1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2433 "TARGET_DOUBLE_FLOAT
2434 && (register_operand (operands[0], DFmode)
2435 || reg_or_0_operand (operands[1], DFmode))"
2436 { return loongarch_output_move (operands[0], operands[1]); }
2437 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2438 (set_attr "mode" "DF")])
2440 (define_insn "*movdf_softfloat"
2441 [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
2442 (match_operand:DF 1 "move_operand" "rG,m,rG"))]
2443 "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2445 && (register_operand (operands[0], DFmode)
2446 || reg_or_0_operand (operands[1], DFmode))"
2447 { return loongarch_output_move (operands[0], operands[1]); }
2448 [(set_attr "move_type" "move,load,store")
2449 (set_attr "mode" "DF")])
2451 ;; Clear one FCC register
2453 (define_expand "movfcc"
2454 [(set (match_operand:FCC 0 "")
2455 (match_operand:FCC 1 ""))]
2458 if (memory_operand (operands[0], FCCmode)
2459 && memory_operand (operands[1], FCCmode))
2460 operands[1] = force_reg (FCCmode, operands[1]);
2463 (define_insn "movfcc_internal"
2464 [(set (match_operand:FCC 0 "nonimmediate_operand"
2465 "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2466 (match_operand:FCC 1 "reg_or_0_operand"
2467 "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2470 fcmp.caf.s\t%0,$f0,$f0
2481 [(set_attr "type" "move")
2482 (set_attr "mode" "FCC")])
2484 (define_insn "fcc_to_<X:mode>"
2485 [(set (match_operand:X 0 "register_operand" "=r")
2486 (if_then_else:X (ne (match_operand:FCC 1 "register_operand" "0")
2492 [(set_attr "length" "0")
2493 (set_attr "type" "ghost")])
2495 (define_expand "cstore<ANYF:mode>4"
2496 [(set (match_operand:SI 0 "register_operand")
2497 (match_operator:SI 1 "loongarch_fcmp_operator"
2498 [(match_operand:ANYF 2 "register_operand")
2499 (match_operand:ANYF 3 "register_operand")]))]
2502 rtx fcc = gen_reg_rtx (FCCmode);
2503 rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[1]), FCCmode,
2504 operands[2], operands[3]);
2506 emit_insn (gen_rtx_SET (fcc, cmp));
2509 rtx gpr = gen_reg_rtx (DImode);
2510 emit_insn (gen_fcc_to_di (gpr, fcc));
2511 emit_insn (gen_rtx_SET (operands[0],
2512 lowpart_subreg (SImode, gpr, DImode)));
2515 emit_insn (gen_fcc_to_si (operands[0], fcc));
2520 ;; Conditional move instructions.
2522 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2523 [(set (match_operand:GPR 0 "register_operand" "=r,r")
2525 (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "r,r")
2527 (match_operand:GPR 2 "reg_or_0_operand" "r,J")
2528 (match_operand:GPR 3 "reg_or_0_operand" "J,r")))]
2529 "register_operand (operands[2], <GPR:MODE>mode)
2530 != register_operand (operands[3], <GPR:MODE>mode)"
2534 [(set_attr "type" "condmove")
2535 (set_attr "mode" "<GPR:MODE>")])
2537 ;; fsel copies the 3rd argument when the 1st is non-zero and the 2nd
2538 ;; argument if the 1st is zero. This means operand 2 and 3 are
2539 ;; inverted in the instruction.
2541 (define_insn "*sel<mode>"
2542 [(set (match_operand:ANYF 0 "register_operand" "=f")
2544 (ne:FCC (match_operand:FCC 1 "register_operand" "z")
2546 (match_operand:ANYF 2 "reg_or_0_operand" "f")
2547 (match_operand:ANYF 3 "reg_or_0_operand" "f")))]
2550 [(set_attr "type" "condmove")
2551 (set_attr "mode" "<ANYF:MODE>")])
2553 ;; These are the main define_expand's used to make conditional moves.
2555 (define_expand "mov<mode>cc"
2556 [(set (match_operand:GPR 0 "register_operand")
2557 (if_then_else:GPR (match_operator 1 "comparison_operator"
2558 [(match_operand:GPR 2 "reg_or_0_operand")
2559 (match_operand:GPR 3 "reg_or_0_operand")])))]
2560 "TARGET_COND_MOVE_INT"
2562 if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2565 loongarch_expand_conditional_move (operands);
2569 (define_expand "mov<mode>cc"
2570 [(set (match_operand:ANYF 0 "register_operand")
2571 (if_then_else:ANYF (match_operator 1 "comparison_operator"
2572 [(match_operand:ANYF 2 "reg_or_0_operand")
2573 (match_operand:ANYF 3 "reg_or_0_operand")])))]
2574 "TARGET_COND_MOVE_FLOAT"
2576 if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[1], 0))))
2579 loongarch_expand_conditional_move (operands);
2583 (define_insn "lu32i_d"
2584 [(set (match_operand:DI 0 "register_operand" "=r")
2587 (subreg:SI (match_operand:DI 1 "register_operand" "0") 0))
2588 (match_operand:DI 2 "const_lu32i_operand" "u")))]
2590 "lu32i.d\t%0,%X2>>32"
2591 [(set_attr "type" "arith")
2592 (set_attr "mode" "DI")])
2594 (define_insn "lu52i_d"
2595 [(set (match_operand:DI 0 "register_operand" "=r")
2597 (and:DI (match_operand:DI 1 "register_operand" "r")
2598 (match_operand 2 "lu52i_mask_operand"))
2599 (match_operand 3 "const_lu52i_operand" "v")))]
2601 "lu52i.d\t%0,%1,%X3>>52"
2602 [(set_attr "type" "arith")
2603 (set_attr "mode" "DI")])
2605 ;; Instructions for adding the low 12 bits of an address to a register.
2606 ;; Operand 2 is the address: loongarch_print_operand works out which relocation
2607 ;; should be applied.
2609 (define_insn "*low<mode>"
2610 [(set (match_operand:P 0 "register_operand" "=r")
2611 (lo_sum:P (match_operand:P 1 "register_operand" " r")
2612 (match_operand:P 2 "symbolic_operand" "")))]
2614 "addi.<d>\t%0,%1,%L2"
2615 [(set_attr "type" "arith")
2616 (set_attr "mode" "<MODE>")])
2618 (define_insn "@tls_low<mode>"
2619 [(set (match_operand:P 0 "register_operand" "=r")
2620 (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
2621 (match_operand:P 2 "symbolic_operand" "")))]
2624 "addi.<d>\t%0,%1,%L2"
2625 [(set_attr "type" "arith")
2626 (set_attr "mode" "<MODE>")])
2628 ;; Instructions for loading address from GOT entry.
2629 ;; operands[1] is pc plus the high half of the address difference with the got
2631 ;; operands[2] is low 12 bits for low 12 bit of the address difference with the
2633 ;; loongarch_print_operand works out which relocation should be applied.
2635 (define_insn "@ld_from_got<mode>"
2636 [(set (match_operand:P 0 "register_operand" "=r")
2637 (unspec:P [(mem:P (lo_sum:P
2638 (match_operand:P 1 "register_operand" "r")
2639 (match_operand:P 2 "symbolic_operand")))]
2640 UNSPEC_LOAD_FROM_GOT))]
2642 "%Q2ld.<d>\t%0,%1,%L2"
2643 [(set_attr "type" "move")]
2646 (define_insn "@lui_l_hi20<mode>"
2647 [(set (match_operand:P 0 "register_operand" "=r")
2648 (unspec:P [(match_operand:P 1 "symbolic_operand")]
2649 UNSPEC_LUI_L_HI20))]
2652 [(set_attr "type" "move")]
2655 (define_insn "@pcalau12i<mode>"
2656 [(set (match_operand:P 0 "register_operand" "=j")
2657 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2660 "pcalau12i\t%0,%%pc_hi20(%1)"
2661 [(set_attr "type" "move")])
2663 ;; @pcalau12i may be used for sibcall so it has a strict constraint. This
2664 ;; allows any general register as the operand.
2665 (define_insn "@pcalau12i_gr<mode>"
2666 [(set (match_operand:P 0 "register_operand" "=r")
2667 (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
2668 UNSPEC_PCALAU12I_GR))]
2670 "pcalau12i\t%0,%%pc_hi20(%1)"
2671 [(set_attr "type" "move")])
2673 (define_insn "@add_tls_le_relax<mode>"
2674 [(set (match_operand:P 0 "register_operand" "=r")
2675 (unspec:P [(match_operand:P 1 "register_operand" "r")
2676 (match_operand:P 2 "register_operand" "r")
2677 (match_operand:P 3 "symbolic_operand")]
2678 UNSPEC_ADD_TLS_LE_RELAX))]
2679 "HAVE_AS_TLS_LE_RELAXATION"
2680 "add.<d>\t%0,%1,%2,%%le_add_r(%3)"
2681 [(set_attr "type" "move")]
2684 (define_insn "@ori_l_lo12<mode>"
2685 [(set (match_operand:P 0 "register_operand" "=r")
2686 (unspec:P [(match_operand:P 1 "register_operand" "r")
2687 (match_operand:P 2 "symbolic_operand")]
2688 UNSPEC_ORI_L_LO12))]
2691 [(set_attr "type" "move")]
2694 (define_insn "lui_h_lo20"
2695 [(set (match_operand:DI 0 "register_operand" "=r")
2696 (unspec:DI [(match_operand:DI 1 "register_operand" "0")
2697 (match_operand:DI 2 "symbolic_operand")]
2698 UNSPEC_LUI_H_LO20))]
2701 [(set_attr "type" "move")]
2704 (define_insn "lui_h_hi12"
2705 [(set (match_operand:DI 0 "register_operand" "=r")
2706 (unspec:DI [(match_operand:DI 1 "register_operand" "r")
2707 (match_operand:DI 2 "symbolic_operand")]
2708 UNSPEC_LUI_H_HI12))]
2710 "lu52i.d\t%0,%1,%H2"
2711 [(set_attr "type" "move")]
2714 ;; Round floating-point numbers to integers
2715 (define_insn "rint<mode>2"
2716 [(set (match_operand:ANYF 0 "register_operand" "=f")
2717 (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")]
2720 "frint.<fmt>\t%0,%1"
2721 [(set_attr "type" "fcvt")
2722 (set_attr "mode" "<MODE>")])
2724 ;; Convert floating-point numbers to integers
2725 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>2"
2726 [(set (match_operand:ANYFI 0 "register_operand" "=f")
2727 (unspec:ANYFI [(match_operand:ANYF 1 "register_operand" "f")]
2729 "TARGET_HARD_FLOAT &&
2730 (<LRINT> == UNSPEC_FTINT
2731 || flag_fp_int_builtin_inexact
2732 || !flag_trapping_math)"
2733 "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %0,%1"
2734 [(set_attr "type" "fcvt")
2735 (set_attr "mode" "<ANYF:MODE>")])
2737 ;; Thread-Local Storage
2739 (define_insn "@got_load_tls_desc<mode>"
2742 [(match_operand:P 0 "symbolic_operand" "")]
2744 (clobber (reg:SI FCC0_REGNUM))
2745 (clobber (reg:SI FCC1_REGNUM))
2746 (clobber (reg:SI FCC2_REGNUM))
2747 (clobber (reg:SI FCC3_REGNUM))
2748 (clobber (reg:SI FCC4_REGNUM))
2749 (clobber (reg:SI FCC5_REGNUM))
2750 (clobber (reg:SI FCC6_REGNUM))
2751 (clobber (reg:SI FCC7_REGNUM))
2752 (clobber (reg:SI RETURN_ADDR_REGNUM))]
2755 return TARGET_EXPLICIT_RELOCS
2756 ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2757 "addi.d\t$r4,$r4,%%desc_pc_lo12(%0)\n\t"
2758 "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2759 "jirl\t$r1,$r1,%%desc_call(%0)"
2760 : "la.tls.desc\t$r4,%0";
2762 [(set_attr "got" "load")
2763 (set_attr "mode" "<MODE>")
2764 (set_attr "length" "16")])
2766 (define_insn "got_load_tls_desc_off64"
2769 [(match_operand:DI 0 "symbolic_operand" "")]
2770 UNSPEC_TLS_DESC_OFF64))
2771 (clobber (reg:SI FCC0_REGNUM))
2772 (clobber (reg:SI FCC1_REGNUM))
2773 (clobber (reg:SI FCC2_REGNUM))
2774 (clobber (reg:SI FCC3_REGNUM))
2775 (clobber (reg:SI FCC4_REGNUM))
2776 (clobber (reg:SI FCC5_REGNUM))
2777 (clobber (reg:SI FCC6_REGNUM))
2778 (clobber (reg:SI FCC7_REGNUM))
2779 (clobber (reg:SI RETURN_ADDR_REGNUM))
2780 (clobber (match_operand:DI 1 "register_operand" "=&r"))]
2781 "TARGET_TLS_DESC && TARGET_CMODEL_EXTREME"
2783 return TARGET_EXPLICIT_RELOCS
2784 ? "pcalau12i\t$r4,%%desc_pc_hi20(%0)\n\t"
2785 "addi.d\t%1,$r0,%%desc_pc_lo12(%0)\n\t"
2786 "lu32i.d\t%1,%%desc64_pc_lo20(%0)\n\t"
2787 "lu52i.d\t%1,%1,%%desc64_pc_hi12(%0)\n\t"
2788 "add.d\t$r4,$r4,%1\n\t"
2789 "ld.d\t$r1,$r4,%%desc_ld(%0)\n\t"
2790 "jirl\t$r1,$r1,%%desc_call(%0)"
2791 : "la.tls.desc\t$r4,%1,%0";
2793 [(set_attr "got" "load")
2794 (set_attr "length" "28")])
2796 (define_insn "@load_tls<mode>"
2797 [(set (match_operand:P 0 "register_operand" "=r")
2799 [(match_operand:P 1 "symbolic_operand" "")]
2803 enum loongarch_symbol_type symbol_type;
2804 gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type));
2806 switch (symbol_type)
2809 return "la.tls.le\t%0,%1";
2811 return "la.tls.ie\t%0,%1";
2813 return "la.tls.ld\t%0,%1";
2815 return "la.tls.gd\t%0,%1";
2821 [(set_attr "mode" "<MODE>")
2822 (set (attr "insn_count")
2824 (match_test "TARGET_CMODEL_EXTREME")
2829 ;; Expand in-line code to clear the instruction cache between operand[0] and
2831 (define_expand "clear_cache"
2832 [(match_operand 0 "pmode_register_operand")
2833 (match_operand 1 "pmode_register_operand")]
2836 emit_insn (gen_loongarch_ibar (const0_rtx));
2840 (define_insn "loongarch_ibar"
2841 [(unspec_volatile:SI
2842 [(match_operand 0 "const_uimm15_operand")]
2844 (clobber (mem:BLK (scratch)))]
2848 (define_insn "loongarch_dbar"
2849 [(unspec_volatile:SI
2850 [(match_operand 0 "const_uimm15_operand")]
2852 (clobber (mem:BLK (scratch)))]
2858 ;; Privileged state instruction
2860 (define_insn "loongarch_cpucfg"
2861 [(set (match_operand:SI 0 "register_operand" "=r")
2862 (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")]
2866 [(set_attr "type" "load")
2867 (set_attr "mode" "SI")])
2869 (define_insn "loongarch_syscall"
2870 [(unspec_volatile:SI
2871 [(match_operand 0 "const_uimm15_operand")]
2873 (clobber (mem:BLK (scratch)))]
2877 (define_insn "loongarch_break"
2878 [(unspec_volatile:SI
2879 [(match_operand 0 "const_uimm15_operand")]
2881 (clobber (mem:BLK (scratch)))]
2885 (define_insn "loongarch_asrtle_d"
2886 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2887 (match_operand:DI 1 "register_operand" "r")]
2891 [(set_attr "type" "load")
2892 (set_attr "mode" "DI")])
2894 (define_insn "loongarch_asrtgt_d"
2895 [(unspec_volatile:DI [(match_operand:DI 0 "register_operand" "r")
2896 (match_operand:DI 1 "register_operand" "r")]
2900 [(set_attr "type" "load")
2901 (set_attr "mode" "DI")])
2903 (define_insn "loongarch_csrrd_<d>"
2904 [(set (match_operand:GPR 0 "register_operand" "=r")
2905 (unspec_volatile:GPR [(match_operand 1 "const_uimm14_operand")]
2907 (clobber (mem:BLK (scratch)))]
2910 [(set_attr "type" "load")
2911 (set_attr "mode" "<MODE>")])
2913 (define_insn "loongarch_csrwr_<d>"
2914 [(set (match_operand:GPR 0 "register_operand" "=r")
2915 (unspec_volatile:GPR
2916 [(match_operand:GPR 1 "register_operand" "0")
2917 (match_operand 2 "const_uimm14_operand")]
2919 (clobber (mem:BLK (scratch)))]
2922 [(set_attr "type" "store")
2923 (set_attr "mode" "<MODE>")])
2925 (define_insn "loongarch_csrxchg_<d>"
2926 [(set (match_operand:GPR 0 "register_operand" "=r")
2927 (unspec_volatile:GPR
2928 [(match_operand:GPR 1 "register_operand" "0")
2929 (match_operand:GPR 2 "register_operand" "q")
2930 (match_operand 3 "const_uimm14_operand")]
2932 (clobber (mem:BLK (scratch)))]
2935 [(set_attr "type" "load")
2936 (set_attr "mode" "<MODE>")])
2938 (define_insn "loongarch_iocsrrd_<size>"
2939 [(set (match_operand:QHWD 0 "register_operand" "=r")
2940 (unspec_volatile:QHWD [(match_operand:SI 1 "register_operand" "r")]
2942 (clobber (mem:BLK (scratch)))]
2944 "iocsrrd.<size>\t%0,%1"
2945 [(set_attr "type" "load")
2946 (set_attr "mode" "<MODE>")])
2948 (define_insn "loongarch_iocsrwr_<size>"
2949 [(unspec_volatile:QHWD [(match_operand:QHWD 0 "register_operand" "r")
2950 (match_operand:SI 1 "register_operand" "r")]
2952 (clobber (mem:BLK (scratch)))]
2954 "iocsrwr.<size>\t%0,%1"
2955 [(set_attr "type" "load")
2956 (set_attr "mode" "<MODE>")])
2958 (define_insn "loongarch_cacop_<d>"
2959 [(unspec_volatile:X [(match_operand 0 "const_uimm5_operand")
2960 (match_operand:X 1 "register_operand" "r")
2961 (match_operand 2 "const_imm12_operand")]
2963 (clobber (mem:BLK (scratch)))]
2966 [(set_attr "type" "load")
2967 (set_attr "mode" "<MODE>")])
2969 (define_insn "loongarch_lddir_<d>"
2970 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2971 (match_operand:X 1 "register_operand" "r")
2972 (match_operand 2 "const_uimm5_operand")]
2974 (clobber (mem:BLK (scratch)))]
2977 [(set_attr "type" "load")
2978 (set_attr "mode" "<MODE>")])
2980 (define_insn "loongarch_ldpte_<d>"
2981 [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")
2982 (match_operand 1 "const_uimm5_operand")]
2984 (clobber (mem:BLK (scratch)))]
2987 [(set_attr "type" "load")
2988 (set_attr "mode" "<MODE>")])
2991 ;; Block moves, see loongarch.c for more details.
2992 ;; Argument 0 is the destination.
2993 ;; Argument 1 is the source.
2994 ;; Argument 2 is the length.
2995 ;; Argument 3 is the alignment.
2997 (define_expand "cpymemsi"
2998 [(parallel [(set (match_operand:BLK 0 "general_operand")
2999 (match_operand:BLK 1 "general_operand"))
3000 (use (match_operand:SI 2 ""))
3001 (use (match_operand:SI 3 "const_int_operand"))])]
3004 if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
3005 && loongarch_expand_block_move (operands[0], operands[1],
3006 operands[2], operands[3]))
3013 ;; ....................
3017 ;; ....................
3019 (define_insn "*<optab><mode>3"
3020 [(set (match_operand:GPR 0 "register_operand" "=r")
3021 (any_shift:GPR (match_operand:GPR 1 "register_operand" "r")
3022 (match_operand:SI 2 "arith_operand" "rI")))]
3025 if (CONST_INT_P (operands[2]))
3026 operands[2] = GEN_INT (INTVAL (operands[2])
3027 & (GET_MODE_BITSIZE (<MODE>mode) - 1));
3029 return "<insn>%i2.<d>\t%0,%1,%2";
3031 [(set_attr "type" "shift")
3032 (set_attr "mode" "<MODE>")])
3034 (define_insn "<optab>si3_extend"
3035 [(set (match_operand:DI 0 "register_operand" "=r")
3037 (any_shift:SI (match_operand:SI 1 "register_operand" "r")
3038 (match_operand:SI 2 "arith_operand" "rI"))))]
3041 if (CONST_INT_P (operands[2]))
3042 operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
3044 return "<insn>%i2.w\t%0,%1,%2";
3046 [(set_attr "type" "shift")
3047 (set_attr "mode" "SI")])
3049 (define_insn "*rotr<mode>3"
3050 [(set (match_operand:GPR 0 "register_operand" "=r,r")
3051 (rotatert:GPR (match_operand:GPR 1 "register_operand" "r,r")
3052 (match_operand:SI 2 "arith_operand" "r,I")))]
3054 "rotr%i2.<d>\t%0,%1,%2"
3055 [(set_attr "type" "shift,shift")
3056 (set_attr "mode" "<MODE>")])
3058 (define_insn "rotrsi3_extend"
3059 [(set (match_operand:DI 0 "register_operand" "=r,r")
3061 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
3062 (match_operand:SI 2 "arith_operand" "r,I"))))]
3064 "rotr%i2.w\t%0,%1,%2"
3065 [(set_attr "type" "shift,shift")
3066 (set_attr "mode" "SI")])
3068 ;; Expand left rotate to right rotate.
3069 (define_expand "rotl<mode>3"
3071 (neg:SI (match_operand:SI 2 "register_operand")))
3072 (set (match_operand:GPR 0 "register_operand")
3073 (rotatert:GPR (match_operand:GPR 1 "register_operand")
3077 operands[3] = gen_reg_rtx (SImode);
3079 if (TARGET_64BIT && <MODE>mode == SImode)
3081 rtx t = gen_reg_rtx (DImode);
3083 emit_insn (gen_negsi2 (operands[3], operands[2]));
3084 emit_insn (gen_rotrsi3_extend (t, operands[1], operands[3]));
3085 t = gen_lowpart (SImode, t);
3086 SUBREG_PROMOTED_VAR_P (t) = 1;
3087 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
3088 emit_move_insn (operands[0], t);
3093 ;; The following templates were added to generate "bstrpick.d + alsl.d"
3094 ;; instruction pairs.
3095 ;; It is required that the values of const_immalsl_operand and
3096 ;; immediate_operand must have the following correspondence:
3098 ;; (immediate_operand >> const_immalsl_operand) == 0xffffffff
3100 (define_insn "zero_extend_ashift"
3101 [(set (match_operand:DI 0 "register_operand" "=r")
3102 (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
3103 (match_operand 2 "const_immalsl_operand" ""))
3104 (match_operand 3 "immediate_operand" "")))]
3106 && ((INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff)"
3107 "bstrpick.d\t%0,%1,31,0\n\talsl.d\t%0,%0,$r0,%2"
3108 [(set_attr "type" "arith")
3109 (set_attr "mode" "DI")
3110 (set_attr "insn_count" "2")])
3112 (define_insn "bstrpick_alsl_paired"
3113 [(set (match_operand:DI 0 "register_operand" "=&r")
3114 (plus:DI (match_operand:DI 1 "register_operand" "r")
3115 (and:DI (ashift:DI (match_operand:DI 2 "register_operand" "r")
3116 (match_operand 3 "const_immalsl_operand" ""))
3117 (match_operand 4 "immediate_operand" ""))))]
3119 && ((INTVAL (operands[4]) >> INTVAL (operands[3])) == 0xffffffff)"
3120 "bstrpick.d\t%0,%2,31,0\n\talsl.d\t%0,%0,%1,%3"
3121 [(set_attr "type" "arith")
3122 (set_attr "mode" "DI")
3123 (set_attr "insn_count" "2")])
3125 (define_insn "alsl<mode>3"
3126 [(set (match_operand:GPR 0 "register_operand" "=r")
3127 (plus:GPR (ashift:GPR (match_operand:GPR 1 "register_operand" "r")
3128 (match_operand 2 "const_immalsl_operand" ""))
3129 (match_operand:GPR 3 "register_operand" "r")))]
3131 "alsl.<d>\t%0,%1,%3,%2"
3132 [(set_attr "type" "arith")
3133 (set_attr "mode" "<MODE>")])
3135 (define_insn "alslsi3_extend"
3136 [(set (match_operand:DI 0 "register_operand" "=r")
3139 (ashift:SI (match_operand:SI 1 "register_operand" "r")
3140 (match_operand 2 "const_immalsl_operand" ""))
3141 (match_operand:SI 3 "register_operand" "r"))))]
3143 "alsl.w\t%0,%1,%3,%2"
3144 [(set_attr "type" "arith")
3145 (set_attr "mode" "SI")])
3149 ;; Reverse the order of bytes of operand 1 and store the result in operand 0.
3151 (define_insn "revb_2h"
3152 [(set (match_operand:SI 0 "register_operand" "=r")
3153 (rotatert:SI (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3157 [(set_attr "type" "shift")])
3159 (define_insn "revb_2h_extend"
3160 [(set (match_operand:DI 0 "register_operand" "=r")
3163 (bswap:SI (match_operand:SI 1 "register_operand" "r"))
3167 [(set_attr "type" "shift")])
3169 (define_insn "bswaphi2"
3170 [(set (match_operand:HI 0 "register_operand" "=r")
3171 (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
3174 [(set_attr "type" "shift")])
3176 (define_insn "revb_2w"
3177 [(set (match_operand:DI 0 "register_operand" "=r")
3178 (rotatert:DI (bswap:DI (match_operand:DI 1 "register_operand" "r"))
3182 [(set_attr "type" "shift")])
3184 (define_insn "*bswapsi2"
3185 [(set (match_operand:SI 0 "register_operand" "=r")
3186 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3189 [(set_attr "type" "shift")])
3191 (define_expand "bswapsi2"
3192 [(set (match_operand:SI 0 "register_operand" "=r")
3193 (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
3198 rtx t = gen_reg_rtx (SImode);
3199 emit_insn (gen_revb_2h (t, operands[1]));
3200 emit_insn (gen_rotrsi3 (operands[0], t, GEN_INT (16)));
3205 (define_insn "bswapdi2"
3206 [(set (match_operand:DI 0 "register_operand" "=r")
3207 (bswap:DI (match_operand:DI 1 "register_operand" "r")))]
3210 [(set_attr "type" "shift")])
3214 ;; ....................
3216 ;; CONDITIONAL BRANCHES
3218 ;; ....................
3220 ;; Conditional branches
3222 (define_insn "*branch_fp_FCCmode"
3225 (match_operator 1 "equality_operator"
3226 [(match_operand:FCC 2 "register_operand" "z")
3228 (label_ref (match_operand 0 "" ""))
3232 return loongarch_output_conditional_branch (insn, operands,
3233 LARCH_BRANCH ("b%F1", "%Z2%0"),
3234 LARCH_BRANCH ("b%W1", "%Z2%0"));
3236 [(set_attr "type" "branch")])
3238 (define_insn "*branch_fp_inverted_FCCmode"
3241 (match_operator 1 "equality_operator"
3242 [(match_operand:FCC 2 "register_operand" "z")
3245 (label_ref (match_operand 0 "" ""))))]
3248 return loongarch_output_conditional_branch (insn, operands,
3249 LARCH_BRANCH ("b%W1", "%Z2%0"),
3250 LARCH_BRANCH ("b%F1", "%Z2%0"));
3252 [(set_attr "type" "branch")])
3254 ;; Conditional branches on ordered comparisons with zero.
3256 (define_insn "*branch_order<mode>"
3259 (match_operator 1 "order_operator"
3260 [(match_operand:X 2 "register_operand" "r,r")
3261 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3262 (label_ref (match_operand 0 "" ""))
3265 { return loongarch_output_order_conditional_branch (insn, operands, false); }
3266 [(set_attr "type" "branch")])
3268 (define_insn "*branch_order<mode>_inverted"
3271 (match_operator 1 "order_operator"
3272 [(match_operand:X 2 "register_operand" "r,r")
3273 (match_operand:X 3 "reg_or_0_operand" "J,r")])
3275 (label_ref (match_operand 0 "" ""))))]
3277 { return loongarch_output_order_conditional_branch (insn, operands, true); }
3278 [(set_attr "type" "branch")])
3280 ;; Conditional branch on equality comparison.
3282 (define_insn "branch_equality<mode>"
3285 (match_operator 1 "equality_operator"
3286 [(match_operand:X 2 "register_operand" "r")
3287 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3288 (label_ref (match_operand 0 "" ""))
3291 { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3292 [(set_attr "type" "branch")])
3295 (define_insn "*branch_equality<mode>_inverted"
3298 (match_operator 1 "equality_operator"
3299 [(match_operand:X 2 "register_operand" "r")
3300 (match_operand:X 3 "reg_or_0_operand" "rJ")])
3302 (label_ref (match_operand 0 "" ""))))]
3304 { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3305 [(set_attr "type" "branch")])
3308 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3309 ;; QImode values so we can force zero-extension.
3310 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3312 (define_expand "cbranch<mode>4"
3314 (if_then_else (match_operator 0 "comparison_operator"
3315 [(match_operand:BR 1 "register_operand")
3316 (match_operand:BR 2 "nonmemory_operand")])
3317 (label_ref (match_operand 3 ""))
3321 loongarch_expand_conditional_branch (operands);
3325 (define_expand "cbranch<mode>4"
3327 (if_then_else (match_operator 0 "comparison_operator"
3328 [(match_operand:ANYF 1 "register_operand")
3329 (match_operand:ANYF 2 "register_operand")])
3330 (label_ref (match_operand 3 ""))
3334 loongarch_expand_conditional_branch (operands);
3338 ;; Used to implement built-in functions.
3339 (define_expand "condjump"
3341 (if_then_else (match_operand 0)
3342 (label_ref (match_operand 1))
3347 ;; ....................
3349 ;; SETTING A REGISTER FROM A COMPARISON
3351 ;; ....................
3353 ;; Destination is always set in SI mode.
3355 (define_expand "cstore<mode>4"
3356 [(set (match_operand:SI 0 "register_operand")
3357 (match_operator:SI 1 "loongarch_cstore_operator"
3358 [(match_operand:GPR 2 "register_operand")
3359 (match_operand:GPR 3 "nonmemory_operand")]))]
3362 loongarch_expand_scc (operands);
3366 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3367 [(set (match_operand:GPR 0 "register_operand" "=r")
3368 (eq:GPR (match_operand:X 1 "register_operand" "r")
3372 [(set_attr "type" "slt")
3373 (set_attr "mode" "<X:MODE>")])
3376 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3377 [(set (match_operand:GPR 0 "register_operand" "=r")
3378 (ne:GPR (match_operand:X 1 "register_operand" "r")
3382 [(set_attr "type" "slt")
3383 (set_attr "mode" "<X:MODE>")])
3385 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3386 [(set (match_operand:GPR 0 "register_operand" "=r")
3387 (any_gt:GPR (match_operand:X 1 "register_operand" "r")
3388 (match_operand:X 2 "reg_or_0_operand" "rJ")))]
3391 [(set_attr "type" "slt")
3392 (set_attr "mode" "<X:MODE>")])
3394 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3395 [(set (match_operand:GPR 0 "register_operand" "=r")
3396 (any_lt:GPR (match_operand:X 1 "register_operand" "r")
3397 (match_operand:X 2 "arith_operand" "rI")))]
3399 "slt<u>%i2\t%0,%1,%2";
3400 [(set_attr "type" "slt")
3401 (set_attr "mode" "<X:MODE>")])
3403 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3404 [(set (match_operand:GPR 0 "register_operand" "=r")
3405 (any_le:GPR (match_operand:X 1 "register_operand" "r")
3406 (match_operand:X 2 "sle_operand" "")))]
3409 operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
3410 return "slt<u>i\t%0,%1,%2";
3412 [(set_attr "type" "slt")
3413 (set_attr "mode" "<X:MODE>")])
3417 ;; ....................
3419 ;; FLOATING POINT COMPARISONS
3421 ;; ....................
3423 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3424 [(set (match_operand:FCC 0 "register_operand" "=z")
3425 (fcond:FCC (match_operand:ANYF 1 "register_operand" "f")
3426 (match_operand:ANYF 2 "register_operand" "f")))]
3428 "fcmp.<fcond>.<fmt>\t%Z0%1,%2"
3429 [(set_attr "type" "fcmp")
3430 (set_attr "mode" "FCC")])
3434 ;; ....................
3436 ;; UNCONDITIONAL BRANCHES
3438 ;; ....................
3440 ;; Unconditional branches.
3442 (define_expand "jump"
3444 (label_ref (match_operand 0)))])
3446 (define_insn "*jump_absolute"
3448 (label_ref (match_operand 0)))]
3453 [(set_attr "type" "branch")])
3455 (define_insn "*jump_pic"
3457 (label_ref (match_operand 0)))]
3462 [(set_attr "type" "branch")])
3464 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3465 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3466 ;; return prediction and the more general indirect branch prediction.
3468 (define_expand "indirect_jump"
3469 [(set (pc) (match_operand 0 "register_operand"))]
3472 operands[0] = force_reg (Pmode, operands[0]);
3473 emit_jump_insn (gen_indirect_jump (Pmode, operands[0]));
3477 (define_insn "@indirect_jump<mode>"
3478 [(set (pc) (match_operand:P 0 "register_operand" "e"))]
3481 [(set_attr "type" "jump")
3482 (set_attr "mode" "none")])
3484 (define_expand "tablejump"
3486 (match_operand 0 "register_operand"))
3487 (use (label_ref (match_operand 1 "")))]
3491 operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
3492 gen_rtx_LABEL_REF (Pmode,
3494 NULL_RTX, 0, OPTAB_DIRECT);
3495 emit_jump_insn (gen_tablejump (Pmode, operands[0], operands[1]));
3499 (define_insn "@tablejump<mode>"
3501 (match_operand:P 0 "register_operand" "e"))
3502 (use (label_ref (match_operand 1 "" "")))]
3505 [(set_attr "type" "jump")
3506 (set_attr "mode" "none")])
3511 ;; ....................
3513 ;; Function prologue/epilogue
3515 ;; ....................
3518 (define_expand "prologue"
3522 loongarch_expand_prologue ();
3526 ;; Block any insns from being moved before this point, since the
3527 ;; profiling call to mcount can use various registers that aren't
3528 ;; saved or used to pass arguments.
3530 (define_insn "blockage"
3531 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
3534 [(set_attr "type" "ghost")
3535 (set_attr "mode" "none")])
3537 (define_insn "@probe_stack_range<P:mode>"
3538 [(set (match_operand:P 0 "register_operand" "=r")
3539 (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
3540 (match_operand:P 2 "register_operand" "r")
3541 (match_operand:P 3 "register_operand" "r")]
3542 UNSPECV_PROBE_STACK_RANGE))]
3545 return loongarch_output_probe_stack_range (operands[0],
3549 [(set_attr "type" "unknown")
3550 (set_attr "mode" "<MODE>")])
3552 (define_expand "epilogue"
3556 loongarch_expand_epilogue (NORMAL_RETURN);
3560 (define_expand "sibcall_epilogue"
3564 loongarch_expand_epilogue (SIBCALL_RETURN);
3568 ;; Trivial return. Make it look like a normal return insn as that
3569 ;; allows jump optimizations to work better.
3571 (define_expand "return"
3573 "loongarch_can_use_return_insn ()"
3576 (define_expand "simple_return"
3581 (define_insn "*<optab>"
3585 operands[0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3588 [(set_attr "type" "jump")
3589 (set_attr "mode" "none")])
3593 (define_insn "<optab>_internal"
3595 (use (match_operand 0 "pmode_register_operand" ""))]
3598 [(set_attr "type" "jump")
3599 (set_attr "mode" "none")])
3601 ;; Exception return.
3602 (define_insn "loongarch_ertn"
3604 (unspec_volatile [(const_int 0)] UNSPECV_ERTN)]
3607 [(set_attr "type" "trap")
3608 (set_attr "mode" "none")])
3610 ;; This is used in compiling the unwind routines.
3611 (define_expand "eh_return"
3612 [(use (match_operand 0 "general_operand"))]
3615 if (GET_MODE (operands[0]) != word_mode)
3616 operands[0] = convert_to_mode (word_mode, operands[0], 0);
3618 emit_insn (gen_eh_set_ra_di (operands[0]));
3620 emit_insn (gen_eh_set_ra_si (operands[0]));
3622 emit_jump_insn (gen_eh_return_internal ());
3627 (define_insn_and_split "eh_return_internal"
3631 "epilogue_completed"
3634 loongarch_expand_epilogue (EXCEPTION_RETURN);
3638 ;; Clobber the return address on the stack. We can't expand this
3639 ;; until we know where it will be put in the stack frame.
3641 (define_insn "eh_set_ra_si"
3642 [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3643 (clobber (match_scratch:SI 1 "=&r"))]
3647 (define_insn "eh_set_ra_di"
3648 [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
3649 (clobber (match_scratch:DI 1 "=&r"))]
3654 [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN)
3655 (clobber (match_scratch 1))]
3659 loongarch_set_return_address (operands[0], operands[1]);
3666 ;; ....................
3670 ;; ....................
3672 ;; Sibling calls. All these patterns use jump instructions.
3674 (define_expand "sibcall"
3675 [(parallel [(call (match_operand 0 "")
3676 (match_operand 1 ""))
3677 (use (match_operand 2 "")) ;; next_arg_reg
3678 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3681 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3683 if (GET_CODE (target) == LO_SUM)
3684 emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target, 0),
3689 rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
3691 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3692 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3693 gen_rtx_REG (Pmode, T0_REGNUM));
3698 (define_insn "sibcall_internal"
3699 [(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
3700 (match_operand 1 "" ""))]
3701 "SIBLING_CALL_P (insn)"
3703 switch (which_alternative)
3708 if (TARGET_CMODEL_MEDIUM)
3709 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3713 if (TARGET_CMODEL_MEDIUM)
3714 return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
3716 return "b\t%%plt(%0)";
3721 [(set_attr "jirl" "indirect,direct,direct")])
3723 (define_insn "@sibcall_internal_1<mode>"
3724 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3725 (match_operand:P 1 "symbolic_operand" "")))
3726 (match_operand 2 "" ""))]
3727 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3728 "jirl\t$r0,%0,%%pc_lo12(%1)"
3729 [(set_attr "jirl" "indirect")])
3731 (define_expand "sibcall_value"
3732 [(parallel [(set (match_operand 0 "")
3733 (call (match_operand 1 "")
3734 (match_operand 2 "")))
3735 (use (match_operand 3 ""))])] ;; next_arg_reg
3738 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3740 /* Handle return values created by loongarch_pass_fpr_pair. */
3741 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3743 rtx arg1 = XEXP (XVECEXP (operands[0],0, 0), 0);
3744 rtx arg2 = XEXP (XVECEXP (operands[0],0, 1), 0);
3746 if (GET_CODE (target) == LO_SUM)
3747 emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3755 = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3760 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3761 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3762 gen_rtx_REG (Pmode, T0_REGNUM));
3767 /* Handle return values created by loongarch_return_fpr_single. */
3768 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3769 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3771 if (GET_CODE (target) == LO_SUM)
3772 emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[0],
3778 rtx call = emit_call_insn (gen_sibcall_value_internal (operands[0],
3782 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3783 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3784 gen_rtx_REG (Pmode, T0_REGNUM));
3790 (define_insn "sibcall_value_internal"
3791 [(set (match_operand 0 "register_operand" "")
3792 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3793 (match_operand 2 "" "")))]
3794 "SIBLING_CALL_P (insn)"
3796 switch (which_alternative)
3801 if (TARGET_CMODEL_MEDIUM)
3802 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3806 if (TARGET_CMODEL_MEDIUM)
3807 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3809 return "b\t%%plt(%1)";
3814 [(set_attr "jirl" "indirect,direct,direct")])
3816 (define_insn "@sibcall_value_internal_1<mode>"
3817 [(set (match_operand 0 "register_operand" "")
3818 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3819 (match_operand:P 2 "symbolic_operand" "")))
3820 (match_operand 3 "" "")))]
3821 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3822 "jirl\t$r0,%1,%%pc_lo12(%2)"
3823 [(set_attr "jirl" "indirect")])
3825 (define_insn "sibcall_value_multiple_internal"
3826 [(set (match_operand 0 "register_operand" "")
3827 (call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
3828 (match_operand 2 "" "")))
3829 (set (match_operand 3 "register_operand" "")
3830 (call (mem:SI (match_dup 1))
3832 "SIBLING_CALL_P (insn)"
3834 switch (which_alternative)
3839 if (TARGET_CMODEL_MEDIUM)
3840 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3844 if (TARGET_CMODEL_MEDIUM)
3845 return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
3847 return "b\t%%plt(%1)";
3852 [(set_attr "jirl" "indirect,direct,direct")])
3854 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3855 [(set (match_operand 0 "register_operand" "")
3856 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
3857 (match_operand:P 2 "symbolic_operand" "")]
3858 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3859 (match_operand 3 "" "")))
3860 (set (match_operand 4 "register_operand" "")
3861 (call (mem:P (unspec:P [(match_dup 1)
3863 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3865 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3866 "jirl\t$r0,%1,%%pc_lo12(%2)"
3867 [(set_attr "jirl" "indirect")])
3869 (define_expand "call"
3870 [(parallel [(call (match_operand 0 "")
3871 (match_operand 1 ""))
3872 (use (match_operand 2 "")) ;; next_arg_reg
3873 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
3876 rtx target = loongarch_legitimize_call_address (XEXP (operands[0], 0));
3878 if (GET_CODE (target) == LO_SUM)
3879 emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target, 0),
3880 XEXP (target, 1), operands[1]));
3882 emit_call_insn (gen_call_internal (target, operands[1]));
3886 (define_insn "call_internal"
3887 [(call (mem:SI (match_operand 0 "call_insn_operand" "e,c,b"))
3888 (match_operand 1 "" ""))
3889 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3892 switch (which_alternative)
3895 return "jirl\t$r1,%0,0";
3897 if (TARGET_CMODEL_MEDIUM)
3898 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3902 if (TARGET_CMODEL_MEDIUM)
3903 return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
3905 return "bl\t%%plt(%0)";
3910 [(set_attr "jirl" "indirect,direct,direct")])
3912 (define_insn "@call_internal_1<mode>"
3913 [(call (mem:P (lo_sum:P (match_operand:P 0 "register_operand" "j")
3914 (match_operand:P 1 "symbolic_operand" "")))
3915 (match_operand 2 "" ""))
3916 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3917 "TARGET_CMODEL_MEDIUM"
3918 "jirl\t$r1,%0,%%pc_lo12(%1)"
3919 [(set_attr "jirl" "indirect")])
3921 (define_expand "call_value"
3922 [(parallel [(set (match_operand 0 "")
3923 (call (match_operand 1 "")
3924 (match_operand 2 "")))
3925 (use (match_operand 3 ""))])] ;; next_arg_reg
3928 rtx target = loongarch_legitimize_call_address (XEXP (operands[1], 0));
3929 /* Handle return values created by loongarch_pass_fpr_pair. */
3930 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 2)
3932 rtx arg1 = XEXP (XVECEXP (operands[0], 0, 0), 0);
3933 rtx arg2 = XEXP (XVECEXP (operands[0], 0, 1), 0);
3935 if (GET_CODE (target) == LO_SUM)
3936 emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
3939 operands[2], arg2));
3941 emit_call_insn (gen_call_value_multiple_internal (arg1, target,
3942 operands[2], arg2));
3946 /* Handle return values created by loongarch_return_fpr_single. */
3947 if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) == 1)
3948 operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
3950 if (GET_CODE (target) == LO_SUM)
3951 emit_call_insn (gen_call_value_internal_1 (Pmode, operands[0],
3956 emit_call_insn (gen_call_value_internal (operands[0], target,
3962 (define_insn "call_value_internal"
3963 [(set (match_operand 0 "register_operand" "")
3964 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
3965 (match_operand 2 "" "")))
3966 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3969 switch (which_alternative)
3972 return "jirl\t$r1,%1,0";
3974 if (TARGET_CMODEL_MEDIUM)
3975 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3979 if (TARGET_CMODEL_MEDIUM)
3980 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
3982 return "bl\t%%plt(%1)";
3987 [(set_attr "jirl" "indirect,direct,direct")])
3989 (define_insn "@call_value_internal_1<mode>"
3990 [(set (match_operand 0 "register_operand" "")
3991 (call (mem:P (lo_sum:P (match_operand:P 1 "register_operand" "j")
3992 (match_operand:P 2 "symbolic_operand" "")))
3993 (match_operand 3 "" "")))
3994 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3995 "TARGET_CMODEL_MEDIUM"
3996 "jirl\t$r1,%1,%%pc_lo12(%2)"
3997 [(set_attr "jirl" "indirect")])
3999 (define_insn "call_value_multiple_internal"
4000 [(set (match_operand 0 "register_operand" "")
4001 (call (mem:SI (match_operand 1 "call_insn_operand" "e,c,b"))
4002 (match_operand 2 "" "")))
4003 (set (match_operand 3 "register_operand" "")
4004 (call (mem:SI (match_dup 1))
4006 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4009 switch (which_alternative)
4012 return "jirl\t$r1,%1,0";
4014 if (TARGET_CMODEL_MEDIUM)
4015 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4019 if (TARGET_CMODEL_MEDIUM)
4020 return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
4022 return "bl\t%%plt(%1)";
4027 [(set_attr "jirl" "indirect,direct,direct")])
4029 (define_insn "@call_value_multiple_internal_1<mode>"
4030 [(set (match_operand 0 "register_operand" "")
4031 (call (mem:P (unspec:P [(match_operand:P 1 "register_operand" "j")
4032 (match_operand:P 2 "symbolic_operand" "")]
4033 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4034 (match_operand 3 "" "")))
4035 (set (match_operand 4 "register_operand" "")
4036 (call (mem:P (unspec:P [(match_dup 1)
4038 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
4040 (clobber (reg:SI RETURN_ADDR_REGNUM))]
4041 "TARGET_CMODEL_MEDIUM"
4042 "jirl\t$r1,%1,%%pc_lo12(%2)"
4043 [(set_attr "jirl" "indirect")])
4046 ;; Call subroutine returning any type.
4047 (define_expand "untyped_call"
4048 [(parallel [(call (match_operand 0 "")
4050 (match_operand 1 "")
4051 (match_operand 2 "")])]
4056 emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
4058 for (i = 0; i < XVECLEN (operands[2], 0); i++)
4060 rtx set = XVECEXP (operands[2], 0, i);
4061 loongarch_emit_move (SET_DEST (set), SET_SRC (set));
4064 emit_insn (gen_blockage ());
4069 ;; ....................
4073 ;; ....................
4076 (define_insn "prefetch"
4077 [(prefetch (match_operand 0 "address_operand" "ZD")
4078 (match_operand 1 "const_int_operand" "n")
4079 (match_operand 2 "const_int_operand" "n"))]
4082 switch (INTVAL (operands[1]))
4084 case 0: return "preld\t0,%a0";
4085 case 1: return "preld\t8,%a0";
4086 default: gcc_unreachable ();
4094 [(set_attr "type" "nop")
4095 (set_attr "mode" "none")])
4097 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand 0.
4098 (define_insn "loongarch_movfcsr2gr"
4099 [(set (match_operand:SI 0 "register_operand" "=r")
4100 (unspec_volatile:SI [(match_operand 1 "const_uimm5_operand")]
4101 UNSPECV_MOVFCSR2GR))]
4103 "movfcsr2gr\t%0,$r%1")
4105 ;; __builtin_loongarch_movgr2fcsr: move operand 0 into the FCSR.
4106 (define_insn "loongarch_movgr2fcsr"
4107 [(unspec_volatile [(match_operand 0 "const_uimm5_operand")
4108 (match_operand:SI 1 "register_operand" "r")]
4109 UNSPECV_MOVGR2FCSR)]
4111 "movgr2fcsr\t$r%0,%1")
4113 (define_insn "fclass_<fmt>"
4114 [(set (match_operand:SI 0 "register_operand" "=f")
4115 (unspec:SI [(match_operand:ANYF 1 "register_operand" "f")]
4118 "fclass.<fmt>\t%0,%1"
4119 [(set_attr "type" "unknown")
4120 (set_attr "mode" "<MODE>")])
4122 (define_int_iterator FCLASS_MASK [68 136 952])
4123 (define_int_attr fclass_optab
4128 (define_expand "<FCLASS_MASK:fclass_optab><ANYF:mode>2"
4129 [(match_operand:SI 0 "register_operand" "=r")
4130 (match_operand:ANYF 1 "register_operand" " f")
4131 (const_int FCLASS_MASK)]
4134 rtx ft0 = gen_reg_rtx (SImode);
4135 rtx t0 = gen_reg_rtx (word_mode);
4136 rtx mask = GEN_INT (<FCLASS_MASK>);
4138 emit_insn (gen_fclass_<ANYF:fmt> (ft0, operands[1]));
4141 emit_insn (gen_extend_insn (t0, ft0, DImode, SImode, 0));
4143 emit_move_insn (t0, ft0);
4145 emit_move_insn (t0, gen_rtx_AND (word_mode, t0, mask));
4146 emit_move_insn (t0, gen_rtx_NE (word_mode, t0, const0_rtx));
4150 t0 = lowpart_subreg (SImode, t0, DImode);
4151 SUBREG_PROMOTED_VAR_P (t0) = 1;
4152 SUBREG_PROMOTED_SET (t0, SRP_SIGNED);
4155 emit_move_insn (operands[0], t0);
4160 (define_insn "bytepick_w_<bytepick_imm>"
4161 [(set (match_operand:SI 0 "register_operand" "=r")
4162 (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
4163 (const_int <bytepick_w_lshiftrt_amount>))
4164 (ashift:SI (match_operand:SI 2 "register_operand" "r")
4165 (const_int bytepick_w_ashift_amount))))]
4167 "bytepick.w\t%0,%1,%2,<bytepick_imm>"
4168 [(set_attr "mode" "SI")])
4170 (define_mode_attr bitsize [(QI "8") (HI "16")])
4171 (define_mode_attr bytepick_imm [(QI "3") (HI "2")])
4172 (define_mode_attr bytepick_w_ashift_amount [(QI "24") (HI "16")])
4174 (define_insn "bytepick_w_<bytepick_imm>_extend"
4175 [(set (match_operand:DI 0 "register_operand" "=r")
4179 (subreg:SHORT (match_operand:DI 1 "register_operand" "r") 0))
4180 (const_int <bytepick_w_ashift_amount>))
4181 (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4182 (const_int <bytepick_w_ashift_amount>)
4183 (const_int <bitsize>))))]
4185 "bytepick.w\t%0,%2,%1,<bytepick_imm>"
4186 [(set_attr "mode" "SI")])
4188 (define_insn "bytepick_w_1_extend"
4189 [(set (match_operand:DI 0 "register_operand" "=r")
4192 (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
4196 (zero_extract:DI (match_operand:DI 2 "register_operand" "r")
4200 "bytepick.w\t%0,%2,%1,1"
4201 [(set_attr "mode" "SI")])
4203 (define_insn "bytepick_d_<bytepick_imm>"
4204 [(set (match_operand:DI 0 "register_operand" "=r")
4205 (ior:DI (lshiftrt (match_operand:DI 1 "register_operand" "r")
4206 (const_int <bytepick_d_lshiftrt_amount>))
4207 (ashift (match_operand:DI 2 "register_operand" "r")
4208 (const_int bytepick_d_ashift_amount))))]
4210 "bytepick.d\t%0,%1,%2,<bytepick_imm>"
4211 [(set_attr "mode" "DI")])
4213 (define_insn "bitrev_4b"
4214 [(set (match_operand:SI 0 "register_operand" "=r")
4215 (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
4219 [(set_attr "type" "unknown")
4220 (set_attr "mode" "SI")])
4222 (define_insn "bitrev_8b"
4223 [(set (match_operand:DI 0 "register_operand" "=r")
4224 (unspec:DI [(match_operand:DI 1 "register_operand" "r")]
4228 [(set_attr "type" "unknown")
4229 (set_attr "mode" "DI")])
4231 (define_insn "@stack_tie<mode>"
4232 [(set (mem:BLK (scratch))
4233 (unspec:BLK [(match_operand:X 0 "register_operand" "r")
4234 (match_operand:X 1 "register_operand" "r")]
4238 [(set_attr "length" "0")
4239 (set_attr "type" "ghost")])
4241 ;; Named pattern for expanding thread pointer reference.
4242 (define_expand "get_thread_pointer<mode>"
4243 [(set (match_operand:P 0 "register_operand" "=r")
4249 [(match_operand 0 "small_data_pattern")]
4252 { operands[0] = loongarch_rewrite_small_data (operands[0]); })
4255 ;; Match paired HI/SI/SF/DFmode load/stores.
4256 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4257 [(set (match_operand:JOIN_MODE 0 "nonimmediate_operand"
4259 (match_operand:JOIN_MODE 1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4260 (set (match_operand:JOIN_MODE 2 "nonimmediate_operand"
4262 (match_operand:JOIN_MODE 3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4265 /* The load destination does not overlap the source. */
4266 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4267 output_asm_insn (loongarch_output_move (operands[0], operands[1]),
4269 output_asm_insn (loongarch_output_move (operands[2], operands[3]),
4273 [(set_attr "move_type"
4274 "load,fpload,store,fpstore,load,store")
4275 (set_attr "insn_count" "2,2,2,2,2,2")])
4277 ;; 2 HI/SI/SF/DF loads are bonded.
4279 [(set (match_operand:JOIN_MODE 0 "register_operand")
4280 (match_operand:JOIN_MODE 1 "non_volatile_mem_operand"))
4281 (set (match_operand:JOIN_MODE 2 "register_operand")
4282 (match_operand:JOIN_MODE 3 "non_volatile_mem_operand"))]
4283 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4284 [(parallel [(set (match_dup 0)
4290 ;; 2 HI/SI/SF/DF stores are bonded.
4292 [(set (match_operand:JOIN_MODE 0 "memory_operand")
4293 (match_operand:JOIN_MODE 1 "register_operand"))
4294 (set (match_operand:JOIN_MODE 2 "memory_operand")
4295 (match_operand:JOIN_MODE 3 "register_operand"))]
4296 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4297 [(parallel [(set (match_dup 0)
4303 ;; Match paired HImode loads.
4304 (define_insn "*join2_loadhi"
4305 [(set (match_operand:SI 0 "register_operand" "=&r")
4306 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand" "m")))
4307 (set (match_operand:SI 2 "register_operand" "=r")
4308 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand" "m")))]
4311 /* The load destination does not overlap the source. */
4312 gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
4313 output_asm_insn ("ld.h<u>\t%0,%1", operands);
4314 output_asm_insn ("ld.h<u>\t%2,%3", operands);
4318 [(set_attr "move_type" "load")
4319 (set_attr "insn_count" "2")])
4322 ;; 2 HI loads are bonded.
4324 [(set (match_operand:SI 0 "register_operand")
4325 (any_extend:SI (match_operand:HI 1 "non_volatile_mem_operand")))
4326 (set (match_operand:SI 2 "register_operand")
4327 (any_extend:SI (match_operand:HI 3 "non_volatile_mem_operand")))]
4328 "loongarch_load_store_bonding_p (operands, HImode, true)"
4329 [(parallel [(set (match_dup 0)
4330 (any_extend:SI (match_dup 1)))
4332 (any_extend:SI (match_dup 3)))])]
4337 (define_mode_iterator QHSD [QI HI SI DI])
4338 (define_int_iterator CRC [UNSPEC_CRC UNSPEC_CRCC])
4339 (define_int_attr crc [(UNSPEC_CRC "crc") (UNSPEC_CRCC "crcc")])
4341 (define_insn "loongarch_<crc>_w_<size>_w"
4342 [(set (match_operand:SI 0 "register_operand" "=r")
4343 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4344 (match_operand:SI 2 "register_operand" "r")]
4347 "<crc>.w.<size>.w\t%0,%1,%2"
4348 [(set_attr "type" "unknown")
4349 (set_attr "mode" "<MODE>")])
4351 (define_insn "loongarch_<crc>_w_<size>_w_extended"
4352 [(set (match_operand:DI 0 "register_operand" "=r")
4354 (unspec:SI [(match_operand:QHSD 1 "register_operand" "r")
4355 (match_operand:SI 2 "register_operand" "r")]
4358 "<crc>.w.<size>.w\t%0,%1,%2"
4359 [(set_attr "type" "unknown")
4360 (set_attr "mode" "<MODE>")])
4362 ;; With normal or medium code models, if the only use of a pc-relative
4363 ;; address is for loading or storing a value, then relying on linker
4364 ;; relaxation is not better than emitting the machine instruction directly.
4365 ;; Even if the la.local pseudo op can be relaxed, we get:
4367 ;; pcaddi $t0, %pcrel_20(x)
4370 ;; There are still two instructions, same as using the machine instructions
4371 ;; and explicit relocs:
4373 ;; pcalau12i $t0, %pc_hi20(x)
4374 ;; ld.d $t0, $t0, %pc_lo12(x)
4376 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4378 (define_insn_and_rewrite "simple_load<mode>"
4379 [(set (match_operand:LD_AT_LEAST_32_BIT 0 "register_operand" "=r,f")
4380 (match_operand:LD_AT_LEAST_32_BIT 1 "mem_simple_ldst_operand" ""))]
4381 "loongarch_pre_reload_split ()
4382 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4383 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4387 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4390 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4391 [(set (match_operand:GPR 0 "register_operand" "=r")
4393 (match_operand:SUBDI 1 "mem_simple_ldst_operand" "")))]
4394 "loongarch_pre_reload_split ()
4395 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4396 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4400 operands[1] = loongarch_rewrite_mem_for_simple_ldst (operands[1]);
4403 (define_insn_and_rewrite "simple_store<mode>"
4404 [(set (match_operand:ST_ANY 0 "mem_simple_ldst_operand" "")
4405 (match_operand:ST_ANY 1 "reg_or_0_operand" "r,f"))]
4406 "loongarch_pre_reload_split ()
4407 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4408 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4412 operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
4415 ;; Synchronization instructions.
4419 (include "generic.md")
4420 (include "la464.md")
4422 ; The LoongArch SIMD Instructions.
4425 (define_c_enum "unspec" [
4426 UNSPEC_ADDRESS_FIRST