1 ;; Machine Description for LoongArch for GNU compiler.
2 ;; Copyright (C)
2021-
2024 Free Software Foundation, Inc.
3 ;; Contributed by Loongson Ltd.
4 ;; Based on MIPS target for GNU compiler.
6 ;; This file is part of GCC.
8 ;; GCC is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version
3, or (at your option)
13 ;; GCC is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GCC; see the file COPYING3. If not see
20 ;; <http://www.gnu.org/licenses/>.
22 (define_c_enum "unspec" [
23 ;; Integer operations that are too cumbersome to describe directly.
28 ;; Floating-point moves.
35 ;; Floating point unspecs.
46 ;; Override return address for exception handling.
73 UNSPEC_ADD_TLS_LE_RELAX
80 ;; Fake div.w[u] mod.w[u]
83 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1
84 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1
87 (define_c_enum "unspecv" [
88 ;; Blockage and synchronisation.
93 ;; Privileged instructions
105 UNSPECV_PROBE_STACK_RANGE
107 ;; Floating-point environment.
120 [(RETURN_ADDR_REGNUM
1)
126 ;; Return path styles
131 ;; PIC long branch sequences are never longer than
100 bytes.
132 (MAX_PIC_BRANCH_LENGTH
100)
135 (include "predicates.md")
136 (include "constraints.md")
138 ;; ....................
142 ;; ....................
144 (define_attr "enabled" "no,yes" (const_string "yes"))
146 (define_attr "got" "unset,load"
147 (const_string "unset"))
149 ;; For jirl instructions, this attribute is DIRECT when the target address
150 ;; is symbolic and INDIRECT when it is a register.
151 (define_attr "jirl" "unset,direct,indirect"
152 (const_string "unset"))
155 ;; Classification of moves, extensions and truncations. Most values
156 ;; are as for "type" (see below) but there are also the following
157 ;; move-specific values:
159 ;; sll0 "slli.w DEST,SRC,
0", which on
64-bit targets is guaranteed
160 ;; to produce a sign-extended DEST, even if SRC is not
161 ;; properly sign-extended
162 ;; pick_ins BSTRPICK.W, BSTRPICK.D, BSTRINS.W or BSTRINS.D instruction
163 ;; andi a single ANDI instruction
164 ;; shift_shift a shift left followed by a shift right
166 ;; This attribute is used to determine the instruction's length and
167 ;; scheduling type. For doubleword moves, the attribute always describes
168 ;; the split instructions; in some cases, it is more appropriate for the
169 ;; scheduling type to be "multi" instead.
170 (define_attr "move_type"
171 "unknown,load,fpload,store,fpstore,mgtf,mftg,imul,move,fmove,
172 const,signext,pick_ins,logical,arith,sll0,andi,shift_shift"
173 (const_string "unknown"))
175 (define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor,simd_add"
176 (const_string "unknown"))
178 ;; Main data type used by the insn
179 (define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FCC,
180 V2DI,V4SI,V8HI,V16QI,V2DF,V4SF,V4DI,V8SI,V16HI,V32QI,V4DF,V8SF"
181 (const_string "unknown"))
183 ;; True if the main data type is twice the size of a word.
184 (define_attr "dword_mode" "no,yes"
185 (cond [(and (eq_attr "mode" "DI,DF")
186 (not (match_test "TARGET_64BIT")))
189 (and (eq_attr "mode" "TI,TF")
190 (match_test "TARGET_64BIT"))
191 (const_string "yes")]
192 (const_string "no")))
194 ;; True if the main data type is four times of the size of a word.
195 (define_attr "qword_mode" "no,yes"
196 (cond [(and (eq_attr "mode" "TI,TF")
197 (not (match_test "TARGET_64BIT")))
198 (const_string "yes")]
199 (const_string "no")))
201 ;; Classification of each insn.
202 ;; branch conditional branch
203 ;; jump unconditional jump
204 ;; call unconditional call
205 ;; load load instruction(s)
206 ;; fpload floating point load
207 ;; fpidxload floating point indexed load
208 ;; store store instruction(s)
209 ;; fpstore floating point store
210 ;; fpidxstore floating point indexed store
211 ;; prefetch memory prefetch (register + offset)
212 ;; prefetchx memory indexed prefetch (register + register)
213 ;; condmove conditional moves
214 ;; mgtf move general-purpose register to floating point register
215 ;; mftg move floating point register to general-purpose register
216 ;; const load constant
217 ;; arith integer arithmetic instructions
218 ;; logical integer logical instructions
219 ;; shift integer shift instructions
220 ;; slt set less than instructions
221 ;; signext sign extend instructions
222 ;; clz the clz and clo instructions
223 ;; trap trap if instructions
224 ;; imul integer multiply
225 ;; idiv integer divide
227 ;; fmove floating point register move
228 ;; fadd floating point add/subtract
229 ;; fmul floating point multiply
230 ;; fmadd floating point multiply-add
231 ;; fdiv floating point divide
232 ;; frdiv floating point reciprocal divide
233 ;; frecipe floating point approximate reciprocal
234 ;; fabs floating point absolute value
235 ;; flogb floating point exponent extract
236 ;; fneg floating point negation
237 ;; fcmp floating point compare
238 ;; fcopysign floating point copysign
239 ;; fcvt floating point convert
240 ;; fscaleb floating point scale
241 ;; fsqrt floating point square root
242 ;; frsqrt floating point reciprocal square root
243 ;; frsqrte floating point approximate reciprocal square root
244 ;; multi multiword sequence (or user asm statements)
245 ;; atomic atomic memory update instruction
246 ;; syncloop memory atomic operation implemented as a sync loop
248 ;; ghost an instruction that produces no real code
250 "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
251 prefetch,prefetchx,condmove,mgtf,mftg,const,arith,logical,
252 shift,slt,signext,clz,trap,imul,idiv,move,
253 fmove,fadd,fmul,fmadd,fdiv,frdiv,frecipe,fabs,flogb,fneg,fcmp,fcopysign,fcvt,
254 fscaleb,fsqrt,frsqrt,frsqrte,accext,accmod,multi,atomic,syncloop,nop,ghost,
255 simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
256 simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
257 simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
258 simd_permute,simd_shf,simd_sat,simd_pcnt,simd_copy,simd_branch,simd_clsx,
259 simd_fminmax,simd_logic,simd_move,simd_load,simd_store"
260 (cond [(eq_attr "jirl" "!unset") (const_string "call")
261 (eq_attr "got" "load") (const_string "load")
263 (eq_attr "alu_type" "add,sub") (const_string "arith")
265 (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical")
267 ;; If a doubleword move uses these expensive instructions,
268 ;; it is usually better to schedule them in the same way
269 ;; as the singleword form, rather than as "multi".
270 (eq_attr "move_type" "load") (const_string "load")
271 (eq_attr "move_type" "fpload") (const_string "fpload")
272 (eq_attr "move_type" "store") (const_string "store")
273 (eq_attr "move_type" "fpstore") (const_string "fpstore")
274 (eq_attr "move_type" "mgtf") (const_string "mgtf")
275 (eq_attr "move_type" "mftg") (const_string "mftg")
277 ;; These types of move are always single insns.
278 (eq_attr "move_type" "imul") (const_string "imul")
279 (eq_attr "move_type" "fmove") (const_string "fmove")
280 (eq_attr "move_type" "signext") (const_string "signext")
281 (eq_attr "move_type" "pick_ins") (const_string "arith")
282 (eq_attr "move_type" "arith") (const_string "arith")
283 (eq_attr "move_type" "logical") (const_string "logical")
284 (eq_attr "move_type" "sll0") (const_string "shift")
285 (eq_attr "move_type" "andi") (const_string "logical")
287 ;; These types of move are always split.
288 (eq_attr "move_type" "shift_shift")
289 (const_string "multi")
291 ;; These types of move are split for quadword modes only.
292 (and (eq_attr "move_type" "move,const")
293 (eq_attr "qword_mode" "yes"))
294 (const_string "multi")
296 ;; These types of move are split for doubleword modes only.
297 (and (eq_attr "move_type" "move,const")
298 (eq_attr "dword_mode" "yes"))
299 (const_string "multi")
300 (eq_attr "move_type" "move") (const_string "move")
301 (eq_attr "move_type" "const") (const_string "const")]
302 (const_string "unknown")))
304 ;; Mode for conversion types (fcvt)
305 ;; I2S integer to float single (SI/DI to SF)
306 ;; I2D integer to float double (SI/DI to DF)
307 ;; S2I float to integer (SF to SI/DI)
308 ;; D2I float to integer (DF to SI/DI)
309 ;; D2S double to float single
310 ;; S2D float single to double
312 (define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D"
313 (const_string "unknown"))
315 ;; The number of individual instructions that a non-branch pattern generates
316 (define_attr "insn_count" ""
317 (cond [;; "Ghost" instructions occupy no space.
318 (eq_attr "type" "ghost")
321 ;; Check for doubleword moves that are decomposed into two
323 (and (eq_attr "move_type" "mgtf,mftg,move")
324 (eq_attr "dword_mode" "yes"))
327 ;; Check for quadword moves that are decomposed into four
329 (and (eq_attr "move_type" "mgtf,mftg,move")
330 (eq_attr "qword_mode" "yes"))
333 ;; Constants, loads and stores are handled by external routines.
334 (and (eq_attr "move_type" "const")
335 (eq_attr "dword_mode" "yes"))
336 (symbol_ref "loongarch_split_const_insns (operands[
1])")
337 (eq_attr "move_type" "const")
338 (symbol_ref "loongarch_const_insns (operands[
1])")
339 (eq_attr "move_type" "load,fpload")
340 (symbol_ref "loongarch_load_store_insns (operands[
1], insn)")
341 (eq_attr "move_type" "store,fpstore")
342 (symbol_ref "loongarch_load_store_insns (operands[
0], insn)")
344 (eq_attr "type" "idiv")
345 (symbol_ref "loongarch_idiv_insns (GET_MODE (PATTERN (insn)))")]
348 ;; Length of instruction in bytes.
349 (define_attr "length" ""
351 ;; Branch futher than +/-
128 KiB require two instructions.
352 (eq_attr "type" "branch")
353 (if_then_else (and (le (minus (match_dup
0) (pc)) (const_int
131064))
354 (le (minus (pc) (match_dup
0)) (const_int
131068)))
357 (symbol_ref "get_attr_insn_count (insn) *
4")))
359 ;; Describe a user's asm statement.
360 (define_asm_attributes
361 [(set_attr "type" "multi")])
363 ;; This mode iterator allows
32-bit and
64-bit GPR patterns to be generated
364 ;; from the same template.
365 (define_mode_iterator GPR [SI (DI "TARGET_64BIT")])
367 ;; A copy of GPR that can be used when a pattern has two independent
369 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
371 ;; This mode iterator allows
16-bit and
32-bit GPR patterns and
32-bit
64-bit
372 ;; FPR patterns to be generated from the same template.
373 (define_mode_iterator JOIN_MODE [HI
375 (SF "TARGET_HARD_FLOAT")
376 (DF "TARGET_DOUBLE_FLOAT")])
378 ;; This mode iterator allows :P to be used for patterns that operate on
379 ;; pointer-sized quantities. Exactly one of the two alternatives will match.
380 (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
382 ;; Likewise, but for GRLEN-sized quantities.
383 (define_mode_iterator X [(SI "!TARGET_64BIT") (DI "TARGET_64BIT")])
385 ;;
64-bit modes for which we provide move patterns.
386 (define_mode_iterator MOVE64 [DI DF])
388 ;;
128-bit modes for which we provide move patterns on
64-bit targets.
389 (define_mode_iterator MOVE128 [TI TF])
391 ;; Iterator for sub-
32-bit integer modes.
392 (define_mode_iterator SHORT [QI HI])
394 ;; Likewise the
64-bit truncate-and-shift patterns.
395 (define_mode_iterator SUBDI [QI HI SI])
397 ;; Iterator for scalar fixed point modes.
398 (define_mode_iterator QHWD [QI HI SI (DI "TARGET_64BIT")])
400 ;; Iterator for hardware-supported floating-point modes.
401 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT")
402 (DF "TARGET_DOUBLE_FLOAT")])
404 ;; Iterator for fixed-point modes which can be hold by a hardware
405 ;; floating-point register.
406 (define_mode_iterator ANYFI [(SI "TARGET_HARD_FLOAT")
407 (DI "TARGET_DOUBLE_FLOAT")])
409 ;; A mode for which moves involving FPRs may need to be split.
410 (define_mode_iterator SPLITF
411 [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
412 (DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT")
413 (TF "TARGET_64BIT && TARGET_DOUBLE_FLOAT")])
415 ;; A mode for anything with
32 bits or more, and able to be loaded with
416 ;; the same addressing mode as ld.w.
417 (define_mode_iterator LD_AT_LEAST_32_BIT [GPR ANYF])
419 ;; A mode for anything able to be stored with the same addressing mode as
421 (define_mode_iterator ST_ANY [QHWD ANYF])
423 ;; A mode for anything legal as a input of a div or mod instruction.
424 (define_mode_iterator DIV [(DI "TARGET_64BIT")
425 (SI "!TARGET_64BIT || ISA_HAS_DIV32")])
427 ;; In GPR templates, a string like "mul.<d>" will expand to "mul.w" in the
428 ;;
32-bit version and "mul.d" in the
64-bit version.
429 (define_mode_attr d [(SI "w") (DI "d")])
431 ;; This attribute gives the length suffix for a load or store instruction.
432 ;; The same suffixes work for zero and sign extensions.
433 (define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")])
434 (define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")])
436 ;; This attribute gives the mode mask of a SHORT.
437 (define_mode_attr mask [(QI "
0x00ff") (HI "
0xffff")])
439 ;; This attribute gives the size (bits) of a SHORT.
440 (define_mode_attr
7_or_15 [(QI "
7") (HI "
15")])
442 ;; Instruction names for stores.
443 (define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")])
445 ;; This attribute gives the format suffix for floating-point operations.
446 (define_mode_attr fmt [(SF "s") (DF "d")])
447 (define_mode_attr ifmt [(SI "w") (DI "l")])
449 ;; This attribute gives the upper-case mode name for one unit of a
450 ;; floating-point mode or vector mode.
451 (define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF") (V4SF "SF")
452 (V16QI "QI") (V8HI "HI") (V4SI "SI") (V2DI "DI")
453 (V2DF "DF")(V8SF "SF")(V32QI "QI")(V16HI "HI")(V8SI "SI")(V4DI "DI")(V4DF "DF")])
455 ;; As above, but in lower case.
456 (define_mode_attr unitmode [(SF "sf") (DF "df") (V2SF "sf") (V4SF "sf")
457 (V16QI "qi") (V8QI "qi") (V8HI "hi") (V4HI "hi")
458 (V4SI "si") (V2SI "si") (V2DI "di") (V2DF "df")
459 (V8SI "si") (V4DI "di") (V32QI "qi") (V16HI "hi")
460 (V8SF "sf") (V4DF "df")])
462 ;; This attribute gives the integer mode that has half the size of
463 ;; the controlling mode.
464 (define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI")
465 (V2SI "SI") (V4HI "SI") (V8QI "SI")
468 ;; This attribute gives the integer mode that has the same size of a
469 ;; floating-point mode.
470 (define_mode_attr IMODE [(SF "SI") (DF "DI")])
472 ;; This code iterator allows signed and unsigned widening multiplications
473 ;; to use the same template.
474 (define_code_iterator any_extend [sign_extend zero_extend])
476 ;; This code iterator allows the two right shift instructions to be
477 ;; generated from the same template.
478 (define_code_iterator any_shiftrt [ashiftrt lshiftrt])
480 ;; This code iterator allows the three shift instructions to be generated
481 ;; from the same template.
482 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
484 ;; This code iterator allows the three bitwise instructions to be generated
485 ;; from the same template.
486 (define_code_iterator any_bitwise [and ior xor])
487 (define_code_iterator neg_bitwise [and ior])
489 ;; This code iterator allows unsigned and signed division to be generated
490 ;; from the same template.
491 (define_code_iterator any_div [div udiv mod umod])
493 ;; This code iterator allows addition and subtraction to be generated
494 ;; from the same template.
495 (define_code_iterator addsub [plus minus])
497 ;; This code iterator allows addition and multiplication to be generated
498 ;; from the same template.
499 (define_code_iterator addmul [plus mult])
501 ;; This code iterator allows addition subtraction and multiplication to be
502 ;; generated from the same template
503 (define_code_iterator addsubmul [plus minus mult])
505 ;; This code iterator allows all native floating-point comparisons to be
506 ;; generated from the same template.
507 (define_code_iterator fcond [unordered uneq unlt unle eq lt le
508 ordered ltgt ne ge gt unge ungt])
510 ;; Equality operators.
511 (define_code_iterator equality_op [eq ne])
513 ;; These code iterators allow the signed and unsigned scc operations to use
514 ;; the same template.
515 (define_code_iterator any_gt [gt gtu])
516 (define_code_iterator any_ge [ge geu])
517 (define_code_iterator any_lt [lt ltu])
518 (define_code_iterator any_le [le leu])
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")
555 (simple_return "simple_return")])
557 ;; <insn> expands to the name of the insn that implements a particular code.
558 (define_code_attr insn [(ashift "sll")
571 ;; <fcond> is the fcmp.cond.fmt condition associated with a particular code.
572 (define_code_attr fcond [(unordered "cun")
587 ;; The sel mnemonic to use depending on the condition test.
588 (define_code_attr sel [(eq "masknez") (ne "maskeqz")])
589 (define_code_attr selinv [(eq "maskeqz") (ne "masknez")])
591 ;; Iterator and attributes for floating-point to fixed-point conversion
593 (define_int_iterator LRINT [UNSPEC_FTINT UNSPEC_FTINTRM UNSPEC_FTINTRP])
594 (define_int_attr lrint_pattern [(UNSPEC_FTINT "lrint")
595 (UNSPEC_FTINTRM "lfloor")
596 (UNSPEC_FTINTRP "lceil")])
597 (define_int_attr lrint_submenmonic [(UNSPEC_FTINT "")
598 (UNSPEC_FTINTRM "rm")
599 (UNSPEC_FTINTRP "rp")])
601 ;; Iterator and attributes for bytepick.d
602 (define_int_iterator bytepick_w_ashift_amount [
8 16 24])
603 (define_int_attr bytepick_w_lshiftrt_amount [(
8 "
24")
606 (define_int_iterator bytepick_d_ashift_amount [
8 16 24 32 40 48 56])
607 (define_int_attr bytepick_d_lshiftrt_amount [(
8 "
56")
614 (define_int_attr bytepick_imm [(
8 "
1")
623 ;; ....................
627 ;; ....................
631 [(trap_if (const_int
1) (const_int
0))]
636 [(set_attr "type" "trap")])
641 ;; ....................
645 ;; ....................
648 (define_insn "add<mode>
3"
649 [(set (match_operand:ANYF
0 "register_operand" "=f")
650 (plus:ANYF (match_operand:ANYF
1 "register_operand" "f")
651 (match_operand:ANYF
2 "register_operand" "f")))]
653 "fadd.<fmt>
\t%
0,%
1,%
2"
654 [(set_attr "type" "fadd")
655 (set_attr "mode" "<UNITMODE>")])
657 (define_insn_and_split "*addsi3"
658 [(set (match_operand:SI
0 "register_operand" "=r,r,r,r,r")
659 (plus:SI (match_operand:SI
1 "register_operand" "r,r,r,r,r")
660 (match_operand:SI
2 "plus_si_operand"
667 * operands[
2] = GEN_INT (INTVAL (operands[
2]) /
65536); \
668 return
\"addu16i.d
\t%
0,%
1,%
2\";
670 "CONST_INT_P (operands[
2]) && !IMM12_INT (operands[
2]) \
671 && !ADDU16I_OPERAND (INTVAL (operands[
2]))"
672 [(set (match_dup
0) (plus:SI (match_dup
1) (match_dup
3)))
673 (set (match_dup
0) (plus:SI (match_dup
0) (match_dup
4)))]
675 loongarch_split_plus_constant (&operands[
2], SImode);
677 [(set_attr "alu_type" "add")
678 (set_attr "mode" "SI")
679 (set_attr "insn_count" "
1,
1,
2,
1,
2")])
681 (define_expand "addsi3"
682 [(set (match_operand:SI
0 "register_operand" "=r,r,r,r,r")
683 (plus:SI (match_operand:SI
1 "register_operand" "r,r,r,r,r")
684 (match_operand:SI
2 "plus_si_operand" "r,I,La,Le,Lb")))]
687 if (CONST_INT_P (operands[
2]) && !IMM12_INT (operands[
2])
688 && ADDU16I_OPERAND (INTVAL (operands[
2])))
690 rtx t1 = gen_reg_rtx (DImode);
691 rtx t2 = gen_reg_rtx (DImode);
692 rtx t3 = gen_reg_rtx (DImode);
693 emit_insn (gen_extend_insn (t1, operands[
1], DImode, SImode,
0));
695 emit_insn (gen_adddi3 (t3, t1, t2));
696 t3 = gen_lowpart (SImode, t3);
697 emit_move_insn (operands[
0], t3);
702 rtx t = gen_reg_rtx (DImode);
703 emit_insn (gen_addsi3_extended (t, operands[
1], operands[
2]));
704 t = gen_lowpart (SImode, t);
705 SUBREG_PROMOTED_VAR_P (t) =
1;
706 SUBREG_PROMOTED_SET (t, SRP_SIGNED);
707 emit_move_insn (operands[
0], t);
712 (define_insn_and_split "adddi3"
713 [(set (match_operand:DI
0 "register_operand" "=r,r,r,r,r,r")
714 (plus:DI (match_operand:DI
1 "register_operand" "r,r,r,r,r,r")
715 (match_operand:DI
2 "plus_di_operand"
716 "r,I,La,Lb,Lc,Ld")))]
722 * operands[
2] = GEN_INT (INTVAL (operands[
2]) /
65536); \
723 return
\"addu16i.d
\t%
0,%
1,%
2\";
726 "&& CONST_INT_P (operands[
2]) && !IMM12_INT (operands[
2]) \
727 && !ADDU16I_OPERAND (INTVAL (operands[
2]))"
728 [(set (match_dup
0) (plus:DI (match_dup
1) (match_dup
3)))
729 (set (match_dup
0) (plus:DI (match_dup
0) (match_dup
4)))]
731 loongarch_split_plus_constant (&operands[
2], DImode);
733 [(set_attr "alu_type" "add")
734 (set_attr "mode" "DI")
735 (set_attr "insn_count" "
1,
1,
2,
1,
2,
2")])
737 (define_insn_and_split "addsi3_extended"
738 [(set (match_operand:DI
0 "register_operand" "=r,r,r,r")
740 (plus:SI (match_operand:SI
1 "register_operand" "r,r,r,r")
741 (match_operand:SI
2 "plus_si_extend_operand"
749 "CONST_INT_P (operands[
2]) && !IMM12_INT (operands[
2])"
750 [(set (subreg:SI (match_dup
0)
0) (plus:SI (match_dup
1) (match_dup
3)))
752 (sign_extend:DI (plus:SI (subreg:SI (match_dup
0)
0)
755 loongarch_split_plus_constant (&operands[
2], SImode);
757 [(set_attr "alu_type" "add")
758 (set_attr "mode" "SI")
759 (set_attr "insn_count" "
1,
1,
2,
2")])
763 ;; ....................
767 ;; ....................
770 (define_insn "sub<mode>
3"
771 [(set (match_operand:ANYF
0 "register_operand" "=f")
772 (minus:ANYF (match_operand:ANYF
1 "register_operand" "f")
773 (match_operand:ANYF
2 "register_operand" "f")))]
775 "fsub.<fmt>
\t%
0,%
1,%
2"
776 [(set_attr "type" "fadd")
777 (set_attr "mode" "<UNITMODE>")])
779 (define_insn "sub<mode>
3"
780 [(set (match_operand:GPR
0 "register_operand" "=r")
781 (minus:GPR (match_operand:GPR
1 "register_operand" "r")
782 (match_operand:GPR
2 "register_operand" "r")))]
785 [(set_attr "alu_type" "sub")
786 (set_attr "mode" "<MODE>")])
789 (define_insn "*subsi3_extended"
790 [(set (match_operand:DI
0 "register_operand" "=r")
792 (minus:SI (match_operand:SI
1 "reg_or_0_operand" "rJ")
793 (match_operand:SI
2 "register_operand" "r"))))]
796 [(set_attr "type" "arith")
797 (set_attr "mode" "SI")])
800 ;; ....................
804 ;; ....................
807 (define_insn "mul<mode>
3"
808 [(set (match_operand:ANYF
0 "register_operand" "=f")
809 (mult:ANYF (match_operand:ANYF
1 "register_operand" "f")
810 (match_operand:ANYF
2 "register_operand" "f")))]
812 "fmul.<fmt>
\t%
0,%
1,%
2"
813 [(set_attr "type" "fmul")
814 (set_attr "mode" "<MODE>")])
816 (define_insn "mul<mode>
3"
817 [(set (match_operand:GPR
0 "register_operand" "=r")
818 (mult:GPR (match_operand:GPR
1 "register_operand" "r")
819 (match_operand:GPR
2 "register_operand" "r")))]
822 [(set_attr "type" "imul")
823 (set_attr "mode" "<MODE>")])
825 (define_insn "*mulsi3_extended"
826 [(set (match_operand:DI
0 "register_operand" "=r")
828 (mult:SI (match_operand:SI
1 "register_operand" "r")
829 (match_operand:SI
2 "register_operand" "r"))))]
832 [(set_attr "type" "imul")
833 (set_attr "mode" "SI")])
836 ;; ........................
838 ;; MULTIPLICATION HIGH-PART
840 ;; ........................
843 (define_expand "<u>mulditi3"
844 [(set (match_operand:TI
0 "register_operand")
845 (mult:TI (any_extend:TI (match_operand:DI
1 "register_operand"))
846 (any_extend:TI (match_operand:DI
2 "register_operand"))))]
849 rtx low = gen_reg_rtx (DImode);
850 emit_insn (gen_muldi3 (low, operands[
1], operands[
2]));
852 rtx high = gen_reg_rtx (DImode);
853 emit_insn (gen_<su>muldi3_highpart (high, operands[
1], operands[
2]));
855 emit_move_insn (gen_lowpart (DImode, operands[
0]), low);
856 emit_move_insn (gen_highpart (DImode, operands[
0]), high);
860 (define_insn "<su>muldi3_highpart"
861 [(set (match_operand:DI
0 "register_operand" "=r")
864 (mult:TI (any_extend:TI
865 (match_operand:DI
1 "register_operand" " r"))
867 (match_operand:DI
2 "register_operand" " r")))
870 "mulh.d<u>
\t%
0,%
1,%
2"
871 [(set_attr "type" "imul")
872 (set_attr "mode" "DI")])
874 (define_expand "<u>mulsidi3"
875 [(set (match_operand:DI
0 "register_operand")
876 (mult:DI (any_extend:DI
877 (match_operand:SI
1 "register_operand"))
879 (match_operand:SI
2 "register_operand"))))]
884 rtx temp = gen_reg_rtx (SImode);
885 emit_insn (gen_mulsi3 (temp, operands[
1], operands[
2]));
886 emit_insn (gen_<su>mulsi3_highpart (loongarch_subword (operands[
0], true),
887 operands[
1], operands[
2]));
888 emit_insn (gen_movsi (loongarch_subword (operands[
0], false), temp));
893 (define_insn "<u>mulsidi3_64bit"
894 [(set (match_operand:DI
0 "register_operand" "=r")
895 (mult:DI (any_extend:DI (match_operand:SI
1 "register_operand" "r"))
896 (any_extend:DI (match_operand:SI
2 "register_operand" "r"))))]
898 "mulw.d.w<u>
\t%
0,%
1,%
2"
899 [(set_attr "type" "imul")
900 (set_attr "mode" "DI")])
902 (define_insn "<su>mulsi3_highpart"
903 [(set (match_operand:SI
0 "register_operand" "=r")
906 (mult:DI (any_extend:DI
907 (match_operand:SI
1 "register_operand" " r"))
909 (match_operand:SI
2 "register_operand" " r")))
912 "mulh.w<u>
\t%
0,%
1,%
2"
913 [(set_attr "type" "imul")
914 (set_attr "mode" "SI")])
916 ;; Under the LoongArch architecture, the mulh.w[u] instruction performs
917 ;; sign extension by default, so the sign extension instruction can be
920 [(set (match_operand:SI
0 "register_operand")
923 (mult:DI (any_extend:DI
924 (match_operand:SI
1 "register_operand"))
926 (match_operand:SI
2 "register_operand")))
928 (set (match_operand:DI
3 "register_operand")
929 (sign_extend:DI (match_dup
0)))]
930 "TARGET_64BIT && REGNO (operands[
0]) == REGNO (operands[
3])"
931 "mulh.w<u>
\t%
0,%
1,%
2")
934 ;; ....................
936 ;; DIVISION and REMAINDER
938 ;; ....................
941 ;; Float division and modulus.
942 (define_expand "div<mode>
3"
943 [(set (match_operand:ANYF
0 "register_operand")
944 (div:ANYF (match_operand:ANYF
1 "reg_or_1_operand")
945 (match_operand:ANYF
2 "register_operand")))]
948 if (<MODE>mode == SFmode
950 && optimize_insn_for_speed_p ()
951 && flag_finite_math_only && !flag_trapping_math
952 && flag_unsafe_math_optimizations)
954 loongarch_emit_swdivsf (operands[
0], operands[
1],
955 operands[
2], SFmode);
960 (define_insn "*div<mode>
3"
961 [(set (match_operand:ANYF
0 "register_operand" "=f")
962 (div:ANYF (match_operand:ANYF
1 "register_operand" "f")
963 (match_operand:ANYF
2 "register_operand" "f")))]
965 "fdiv.<fmt>
\t%
0,%
1,%
2"
966 [(set_attr "type" "fdiv")
967 (set_attr "mode" "<UNITMODE>")])
969 ;; In
3A5000, the reciprocal operation is the same as the division operation.
971 (define_insn "*recip<mode>
3"
972 [(set (match_operand:ANYF
0 "register_operand" "=f")
973 (div:ANYF (match_operand:ANYF
1 "const_1_operand" "")
974 (match_operand:ANYF
2 "register_operand" "f")))]
976 "frecip.<fmt>
\t%
0,%
2"
977 [(set_attr "type" "frdiv")
978 (set_attr "mode" "<UNITMODE>")])
980 ;; Approximate Reciprocal Instructions.
982 (define_insn "loongarch_frecipe_<fmt>"
983 [(set (match_operand:ANYF
0 "register_operand" "=f")
984 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
987 "frecipe.<fmt>
\t%
0,%
1"
988 [(set_attr "type" "frecipe")
989 (set_attr "mode" "<UNITMODE>")
990 (set_attr "insn_count" "
1")])
992 ;; Integer division and modulus.
993 (define_expand "<optab><mode>
3"
994 [(set (match_operand:GPR
0 "register_operand")
995 (any_div:GPR (match_operand:GPR
1 "register_operand")
996 (match_operand:GPR
2 "register_operand")))]
999 if (GET_MODE (operands[
0]) == SImode && TARGET_64BIT && !ISA_HAS_DIV32)
1001 rtx reg1 = gen_reg_rtx (DImode);
1002 rtx reg2 = gen_reg_rtx (DImode);
1003 rtx rd = gen_reg_rtx (DImode);
1005 operands[
1] = gen_rtx_SIGN_EXTEND (word_mode, operands[
1]);
1006 operands[
2] = gen_rtx_SIGN_EXTEND (word_mode, operands[
2]);
1008 emit_insn (gen_rtx_SET (reg1, operands[
1]));
1009 emit_insn (gen_rtx_SET (reg2, operands[
2]));
1011 emit_insn (gen_<optab>di3_fake (rd, reg1, reg2));
1012 emit_insn (gen_rtx_SET (operands[
0],
1013 simplify_gen_subreg (SImode, rd, DImode,
0)));
1018 (define_insn "*<optab><mode>
3"
1019 [(set (match_operand:DIV
0 "register_operand" "=r,&r,&r")
1020 (any_div:DIV (match_operand:DIV
1 "register_operand" "r,r,
0")
1021 (match_operand:DIV
2 "register_operand" "r,r,r")))]
1024 return loongarch_output_division ("<insn>.<d><u>
\t%
0,%
1,%
2", operands);
1026 [(set_attr "type" "idiv")
1027 (set_attr "mode" "<MODE>")
1028 (set (attr "enabled")
1030 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1031 (const_string "yes")
1032 (const_string "no")))])
1034 (define_insn "<optab>si3_extended"
1035 [(set (match_operand:DI
0 "register_operand" "=r,&r,&r")
1037 (any_div:SI (match_operand:SI
1 "register_operand" "r,r,
0")
1038 (match_operand:SI
2 "register_operand" "r,r,r"))))]
1039 "TARGET_64BIT && ISA_HAS_DIV32"
1041 return loongarch_output_division ("<insn>.w<u>
\t%
0,%
1,%
2", operands);
1043 [(set_attr "type" "idiv")
1044 (set_attr "mode" "SI")
1045 (set (attr "enabled")
1047 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1048 (const_string "yes")
1049 (const_string "no")))])
1051 (define_insn "<optab>di3_fake"
1052 [(set (match_operand:DI
0 "register_operand" "=r,&r,&r")
1056 (any_div:DI (match_operand:DI
1 "register_operand" "r,r,
0")
1057 (match_operand:DI
2 "register_operand" "r,r,r"))
0)]
1058 UNSPEC_FAKE_ANY_DIV)))]
1059 "TARGET_64BIT && !ISA_HAS_DIV32"
1061 return loongarch_output_division ("<insn>.w<u>
\t%
0,%
1,%
2", operands);
1063 [(set_attr "type" "idiv")
1064 (set_attr "mode" "SI")
1065 (set (attr "enabled")
1067 (match_test "!!which_alternative == loongarch_check_zero_div_p()")
1068 (const_string "yes")
1069 (const_string "no")))])
1071 ;; Floating point multiply accumulate instructions.
1074 (define_insn "fma<mode>
4"
1075 [(set (match_operand:ANYF
0 "register_operand" "=f")
1076 (fma:ANYF (match_operand:ANYF
1 "register_operand" "f")
1077 (match_operand:ANYF
2 "register_operand" "f")
1078 (match_operand:ANYF
3 "register_operand" "f")))]
1080 "fmadd.<fmt>
\t%
0,%
1,%
2,%
3"
1081 [(set_attr "type" "fmadd")
1082 (set_attr "mode" "<UNITMODE>")])
1085 (define_insn "fms<mode>
4"
1086 [(set (match_operand:ANYF
0 "register_operand" "=f")
1087 (fma:ANYF (match_operand:ANYF
1 "register_operand" "f")
1088 (match_operand:ANYF
2 "register_operand" "f")
1089 (neg:ANYF (match_operand:ANYF
3 "register_operand" "f"))))]
1091 "fmsub.<fmt>
\t%
0,%
1,%
2,%
3"
1092 [(set_attr "type" "fmadd")
1093 (set_attr "mode" "<UNITMODE>")])
1095 ;; fnma is defined in GCC as (fma (neg op1) op2 op3)
1096 ;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
1097 ;; The loongarch nmsub instructions implement -((op1 * op2) - op3)
1098 ;; This transformation means we may return the wrong signed zero
1099 ;; so we check HONOR_SIGNED_ZEROS.
1102 (define_insn "fnma<mode>
4"
1103 [(set (match_operand:ANYF
0 "register_operand" "=f")
1104 (fma:ANYF (neg:ANYF (match_operand:ANYF
1 "register_operand" "f"))
1105 (match_operand:ANYF
2 "register_operand" "f")
1106 (match_operand:ANYF
3 "register_operand" "f")))]
1107 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1108 "fnmsub.<fmt>
\t%
0,%
1,%
2,%
3"
1109 [(set_attr "type" "fmadd")
1110 (set_attr "mode" "<UNITMODE>")])
1112 ;; fnms is defined as: (fma (neg op1) op2 (neg op3))
1113 ;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
1114 ;; The loongarch nmadd instructions implement -((op1 * op2) + op3)
1115 ;; This transformation means we may return the wrong signed zero
1116 ;; so we check HONOR_SIGNED_ZEROS.
1119 (define_insn "fnms<mode>
4"
1120 [(set (match_operand:ANYF
0 "register_operand" "=f")
1122 (neg:ANYF (match_operand:ANYF
1 "register_operand" "f"))
1123 (match_operand:ANYF
2 "register_operand" "f")
1124 (neg:ANYF (match_operand:ANYF
3 "register_operand" "f"))))]
1125 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1126 "fnmadd.<fmt>
\t%
0,%
1,%
2,%
3"
1127 [(set_attr "type" "fmadd")
1128 (set_attr "mode" "<UNITMODE>")])
1130 ;; -(-a * b - c), modulo signed zeros
1131 (define_insn "*fma<mode>
4"
1132 [(set (match_operand:ANYF
0 "register_operand" "=f")
1135 (neg:ANYF (match_operand:ANYF
1 "register_operand" " f"))
1136 (match_operand:ANYF
2 "register_operand" " f")
1137 (neg:ANYF (match_operand:ANYF
3 "register_operand" " f")))))]
1138 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1139 "fmadd.<fmt>
\t%
0,%
1,%
2,%
3"
1140 [(set_attr "type" "fmadd")
1141 (set_attr "mode" "<UNITMODE>")])
1143 ;; -(-a * b + c), modulo signed zeros
1144 (define_insn "*fms<mode>
4"
1145 [(set (match_operand:ANYF
0 "register_operand" "=f")
1148 (neg:ANYF (match_operand:ANYF
1 "register_operand" " f"))
1149 (match_operand:ANYF
2 "register_operand" " f")
1150 (match_operand:ANYF
3 "register_operand" " f"))))]
1151 "!HONOR_SIGNED_ZEROS (<MODE>mode)"
1152 "fmsub.<fmt>
\t%
0,%
1,%
2,%
3"
1153 [(set_attr "type" "fmadd")
1154 (set_attr "mode" "<UNITMODE>")])
1157 (define_insn "*fnms<mode>
4"
1158 [(set (match_operand:ANYF
0 "register_operand" "=f")
1161 (match_operand:ANYF
1 "register_operand" " f")
1162 (match_operand:ANYF
2 "register_operand" " f")
1163 (match_operand:ANYF
3 "register_operand" " f"))))]
1165 "fnmadd.<fmt>
\t%
0,%
1,%
2,%
3"
1166 [(set_attr "type" "fmadd")
1167 (set_attr "mode" "<UNITMODE>")])
1170 (define_insn "*fnma<mode>
4"
1171 [(set (match_operand:ANYF
0 "register_operand" "=f")
1174 (match_operand:ANYF
1 "register_operand" " f")
1175 (match_operand:ANYF
2 "register_operand" " f")
1176 (neg:ANYF (match_operand:ANYF
3 "register_operand" " f")))))]
1178 "fnmsub.<fmt>
\t%
0,%
1,%
2,%
3"
1179 [(set_attr "type" "fmadd")
1180 (set_attr "mode" "<UNITMODE>")])
1183 ;; ....................
1187 ;; ....................
1189 (define_expand "sqrt<mode>
2"
1190 [(set (match_operand:ANYF
0 "register_operand")
1191 (sqrt:ANYF (match_operand:ANYF
1 "register_operand")))]
1194 if (<MODE>mode == SFmode
1195 && TARGET_RECIP_SQRT
1196 && flag_unsafe_math_optimizations
1197 && !optimize_insn_for_size_p ()
1198 && flag_finite_math_only && !flag_trapping_math)
1200 loongarch_emit_swrsqrtsf (operands[
0], operands[
1], SFmode,
0);
1205 (define_insn "*sqrt<mode>
2"
1206 [(set (match_operand:ANYF
0 "register_operand" "=f")
1207 (sqrt:ANYF (match_operand:ANYF
1 "register_operand" "f")))]
1209 "fsqrt.<fmt>
\t%
0,%
1"
1210 [(set_attr "type" "fsqrt")
1211 (set_attr "mode" "<UNITMODE>")
1212 (set_attr "insn_count" "
1")])
1214 (define_expand "rsqrt<mode>
2"
1215 [(set (match_operand:ANYF
0 "register_operand")
1216 (unspec:ANYF [(match_operand:ANYF
1 "register_operand")]
1220 if (<MODE>mode == SFmode && TARGET_RECIP_RSQRT)
1222 loongarch_emit_swrsqrtsf (operands[
0], operands[
1], SFmode,
1);
1227 (define_insn "*rsqrt<mode>
2"
1228 [(set (match_operand:ANYF
0 "register_operand" "=f")
1229 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
1232 "frsqrt.<fmt>
\t%
0,%
1"
1233 [(set_attr "type" "frsqrt")
1234 (set_attr "mode" "<UNITMODE>")])
1236 ;; Approximate Reciprocal Square Root Instructions.
1238 (define_insn "loongarch_frsqrte_<fmt>"
1239 [(set (match_operand:ANYF
0 "register_operand" "=f")
1240 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
1243 "frsqrte.<fmt>
\t%
0,%
1"
1244 [(set_attr "type" "frsqrte")
1245 (set_attr "mode" "<UNITMODE>")])
1248 ;; ....................
1252 ;; ....................
1254 (define_insn "abs<mode>
2"
1255 [(set (match_operand:ANYF
0 "register_operand" "=f")
1256 (abs:ANYF (match_operand:ANYF
1 "register_operand" "f")))]
1259 [(set_attr "type" "fabs")
1260 (set_attr "mode" "<UNITMODE>")])
1263 ;; ....................
1265 ;; FLOATING POINT COPYSIGN
1267 ;; ....................
1269 (define_insn "copysign<mode>
3"
1270 [(set (match_operand:ANYF
0 "register_operand" "=f")
1271 (copysign:ANYF (match_operand:ANYF
1 "register_operand" "f")
1272 (match_operand:ANYF
2 "register_operand" "f")))]
1274 "fcopysign.<fmt>
\t%
0,%
1,%
2"
1275 [(set_attr "type" "fcopysign")
1276 (set_attr "mode" "<UNITMODE>")])
1278 (define_expand "@xorsign<mode>
3"
1279 [(match_operand:ANYF
0 "register_operand")
1280 (match_operand:ANYF
1 "register_operand")
1281 (match_operand:ANYF
2 "register_operand")]
1284 machine_mode lsx_mode
1285 = <MODE>mode == SFmode ? V4SFmode : V2DFmode;
1286 rtx tmp = gen_reg_rtx (lsx_mode);
1287 rtx op1 = lowpart_subreg (lsx_mode, operands[
1], <MODE>mode);
1288 rtx op2 = lowpart_subreg (lsx_mode, operands[
2], <MODE>mode);
1289 emit_insn (gen_xorsign3 (lsx_mode, tmp, op1, op2));
1290 emit_move_insn (operands[
0],
1291 lowpart_subreg (<MODE>mode, tmp, lsx_mode));
1296 ;; ....................
1298 ;; FLOATING POINT SCALE
1300 ;; ....................
1302 (define_insn "ldexp<mode>
3"
1303 [(set (match_operand:ANYF
0 "register_operand" "=f")
1304 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")
1305 (match_operand:<IMODE>
2 "register_operand" "f")]
1308 "fscaleb.<fmt>
\t%
0,%
1,%
2"
1309 [(set_attr "type" "fscaleb")
1310 (set_attr "mode" "<UNITMODE>")])
1313 ;; ....................
1315 ;; FLOATING POINT EXPONENT EXTRACT
1317 ;; ....................
1319 (define_insn "logb_non_negative<mode>
2"
1320 [(set (match_operand:ANYF
0 "register_operand" "=f")
1321 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
1324 "flogb.<fmt>
\t%
0,%
1"
1325 [(set_attr "type" "flogb")
1326 (set_attr "mode" "<UNITMODE>")])
1328 (define_expand "logb<mode>
2"
1329 [(set (match_operand:ANYF
0 "register_operand")
1330 (unspec:ANYF [(abs:ANYF (match_operand:ANYF
1 "register_operand"))]
1334 rtx tmp = gen_reg_rtx (<MODE>mode);
1336 emit_insn (gen_abs<mode>
2 (tmp, operands[
1]));
1337 emit_insn (gen_logb_non_negative<mode>
2 (operands[
0], tmp));
1342 ;; ...................
1344 ;; Count leading zeroes.
1346 ;; ...................
1349 (define_insn "clz<mode>
2"
1350 [(set (match_operand:GPR
0 "register_operand" "=r")
1351 (clz:GPR (match_operand:GPR
1 "register_operand" "r")))]
1354 [(set_attr "type" "clz")
1355 (set_attr "mode" "<MODE>")])
1358 ;; ...................
1360 ;; Count trailing zeroes.
1362 ;; ...................
1365 (define_insn "ctz<mode>
2"
1366 [(set (match_operand:GPR
0 "register_operand" "=r")
1367 (ctz:GPR (match_operand:GPR
1 "register_operand" "r")))]
1370 [(set_attr "type" "clz")
1371 (set_attr "mode" "<MODE>")])
1374 ;; ....................
1378 ;; ....................
1380 (define_insn "smax<mode>
3"
1381 [(set (match_operand:ANYF
0 "register_operand" "=f")
1382 (smax:ANYF (match_operand:ANYF
1 "register_operand" "f")
1383 (match_operand:ANYF
2 "register_operand" "f")))]
1385 "fmax.<fmt>
\t%
0,%
1,%
2"
1386 [(set_attr "type" "fmove")
1387 (set_attr "mode" "<MODE>")])
1389 (define_insn "smin<mode>
3"
1390 [(set (match_operand:ANYF
0 "register_operand" "=f")
1391 (smin:ANYF (match_operand:ANYF
1 "register_operand" "f")
1392 (match_operand:ANYF
2 "register_operand" "f")))]
1394 "fmin.<fmt>
\t%
0,%
1,%
2"
1395 [(set_attr "type" "fmove")
1396 (set_attr "mode" "<MODE>")])
1398 (define_insn "fmax<mode>
3"
1399 [(set (match_operand:ANYF
0 "register_operand" "=f")
1400 (unspec:ANYF [(use (match_operand:ANYF
1 "register_operand" "f"))
1401 (use (match_operand:ANYF
2 "register_operand" "f"))]
1404 "fmax.<fmt>
\t%
0,%
1,%
2"
1405 [(set_attr "type" "fmove")
1406 (set_attr "mode" "<MODE>")])
1408 (define_insn "fmin<mode>
3"
1409 [(set (match_operand:ANYF
0 "register_operand" "=f")
1410 (unspec:ANYF [(use (match_operand:ANYF
1 "register_operand" "f"))
1411 (use (match_operand:ANYF
2 "register_operand" "f"))]
1414 "fmin.<fmt>
\t%
0,%
1,%
2"
1415 [(set_attr "type" "fmove")
1416 (set_attr "mode" "<MODE>")])
1418 (define_insn "smaxa<mode>
3"
1419 [(set (match_operand:ANYF
0 "register_operand" "=f")
1421 (gt (abs:ANYF (match_operand:ANYF
1 "register_operand" "f"))
1422 (abs:ANYF (match_operand:ANYF
2 "register_operand" "f")))
1426 "fmaxa.<fmt>
\t%
0,%
1,%
2"
1427 [(set_attr "type" "fmove")
1428 (set_attr "mode" "<MODE>")])
1430 (define_insn "smina<mode>
3"
1431 [(set (match_operand:ANYF
0 "register_operand" "=f")
1433 (lt (abs:ANYF (match_operand:ANYF
1 "register_operand" "f"))
1434 (abs:ANYF (match_operand:ANYF
2 "register_operand" "f")))
1438 "fmina.<fmt>
\t%
0,%
1,%
2"
1439 [(set_attr "type" "fmove")
1440 (set_attr "mode" "<MODE>")])
1443 ;; ....................
1445 ;; NEGATION and ONE'S COMPLEMENT
1447 ;; ....................
1449 (define_insn "neg<mode>
2"
1450 [(set (match_operand:GPR
0 "register_operand" "=r")
1451 (neg:GPR (match_operand:GPR
1 "register_operand" "r")))]
1454 [(set_attr "alu_type" "sub")
1455 (set_attr "mode" "<MODE>")])
1457 (define_insn "*negsi2_extended"
1458 [(set (match_operand:DI
0 "register_operand" "=r")
1459 (sign_extend:DI (neg:SI (match_operand:SI
1 "register_operand" "r"))))]
1462 [(set_attr "alu_type" "sub")
1463 (set_attr "mode" "SI")])
1465 (define_insn "neg<mode>
2"
1466 [(set (match_operand:ANYF
0 "register_operand" "=f")
1467 (neg:ANYF (match_operand:ANYF
1 "register_operand" "f")))]
1470 [(set_attr "type" "fneg")
1471 (set_attr "mode" "<UNITMODE>")])
1475 ;; ....................
1479 ;; ....................
1482 (define_insn "<optab><mode>
3"
1483 [(set (match_operand:X
0 "register_operand" "=r,r")
1484 (any_bitwise:X (match_operand:X
1 "register_operand" "%r,r")
1485 (match_operand:X
2 "uns_arith_operand" "r,K")))]
1487 "<insn>%i2
\t%
0,%
1,%
2"
1488 [(set_attr "type" "logical")
1489 (set_attr "mode" "<MODE>")])
1491 (define_insn "*<optab>si3_internal"
1492 [(set (match_operand:SI
0 "register_operand" "=r,r")
1493 (any_bitwise:SI (match_operand:SI
1 "register_operand" "%r,r")
1494 (match_operand:SI
2 "uns_arith_operand" " r,K")))]
1496 "<insn>%i2
\t%
0,%
1,%
2"
1497 [(set_attr "type" "logical")
1498 (set_attr "mode" "SI")])
1500 (define_insn "one_cmpl<mode>
2"
1501 [(set (match_operand:X
0 "register_operand" "=r")
1502 (not:X (match_operand:X
1 "register_operand" "r")))]
1505 [(set_attr "alu_type" "not")
1506 (set_attr "mode" "<MODE>")])
1508 (define_insn "*one_cmplsi2_internal"
1509 [(set (match_operand:SI
0 "register_operand" "=r")
1510 (not:SI (match_operand:SI
1 "register_operand" " r")))]
1513 [(set_attr "type" "logical")
1514 (set_attr "mode" "SI")])
1516 (define_insn "and<mode>
3_extended"
1517 [(set (match_operand:GPR
0 "register_operand" "=r")
1518 (and:GPR (match_operand:GPR
1 "nonimmediate_operand" "r")
1519 (match_operand:GPR
2 "low_bitmask_operand" "Yx")))]
1524 len = low_bitmask_len (<MODE>mode, INTVAL (operands[
2]));
1525 operands[
2] = GEN_INT (len-
1);
1526 return "bstrpick.<d>
\t%
0,%
1,%
2,
0";
1528 [(set_attr "move_type" "pick_ins")
1529 (set_attr "mode" "<MODE>")])
1531 (define_insn_and_split "*bstrins_<mode>_for_mask"
1532 [(set (match_operand:GPR
0 "register_operand")
1533 (and:GPR (match_operand:GPR
1 "register_operand")
1534 (match_operand:GPR
2 "ins_zero_bitmask_operand")))]
1538 [(set (match_dup
0) (match_dup
1))
1539 (set (zero_extract:GPR (match_dup
0) (match_dup
2) (match_dup
3))
1542 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[
2]);
1543 int lo = ffs_hwi (mask) -
1;
1544 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1546 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1547 operands[
2] = GEN_INT (len);
1548 operands[
3] = GEN_INT (lo);
1551 (define_insn_and_split "*bstrins_<mode>_for_ior_mask"
1552 [(set (match_operand:GPR
0 "register_operand")
1553 (ior:GPR (and:GPR (match_operand:GPR
1 "register_operand")
1554 (match_operand:GPR
2 "const_int_operand"))
1555 (and:GPR (match_operand:GPR
3 "register_operand")
1556 (match_operand:GPR
4 "const_int_operand"))))]
1557 "loongarch_pre_reload_split ()
1558 && loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands)"
1561 [(set (match_dup
0) (match_dup
1))
1562 (set (zero_extract:GPR (match_dup
0) (match_dup
2) (match_dup
4))
1565 if (loongarch_use_bstrins_for_ior_with_mask (<MODE>mode, operands) <
0)
1567 std::swap (operands[
1], operands[
3]);
1568 std::swap (operands[
2], operands[
4]);
1571 unsigned HOST_WIDE_INT mask = ~UINTVAL (operands[
2]);
1572 int lo = ffs_hwi (mask) -
1;
1573 int len = low_bitmask_len (<MODE>mode, mask >> lo);
1575 len = MIN (len, GET_MODE_BITSIZE (<MODE>mode) - lo);
1576 operands[
2] = GEN_INT (len);
1577 operands[
4] = GEN_INT (lo);
1581 rtx tmp = gen_reg_rtx (<MODE>mode);
1582 emit_move_insn (tmp, gen_rtx_ASHIFTRT(<MODE>mode, operands[
3],
1588 ;; We always avoid the shift operation in bstrins_<mode>_for_ior_mask
1589 ;; if possible, but the result may be sub-optimal when one of the masks
1590 ;; is (
1 << N) -
1 and one of the src register is the dest register.
1594 ;; bstrins.d a0, t0,
42,
0
1596 ;; using a shift operation would be better:
1597 ;; srai.d t0, a1,
43
1598 ;; bstrins.d a0, t0,
63,
43
1600 ;; unfortunately we cannot figure it out in split1: before reload we cannot
1601 ;; know if the dest register is one of the src register. Fix it up in
1604 [(set (match_operand:GPR
0 "register_operand")
1605 (match_operand:GPR
1 "register_operand"))
1606 (set (match_dup
1) (match_operand:GPR
2 "register_operand"))
1607 (set (zero_extract:GPR (match_dup
1)
1608 (match_operand:SI
3 "const_int_operand")
1611 "peep2_reg_dead_p (
3, operands[
0])"
1614 int len = GET_MODE_BITSIZE (<MODE>mode) - INTVAL (operands[
3]);
1616 emit_insn (gen_ashr<mode>
3 (operands[
0], operands[
2], operands[
3]));
1617 emit_insn (gen_insv<mode> (operands[
1], GEN_INT (len), operands[
3],
1622 (define_insn "*iorhi3"
1623 [(set (match_operand:HI
0 "register_operand" "=r,r")
1624 (ior:HI (match_operand:HI
1 "register_operand" "%r,r")
1625 (match_operand:HI
2 "uns_arith_operand" "r,K")))]
1628 [(set_attr "type" "logical")
1629 (set_attr "mode" "HI")])
1631 (define_insn "nor<mode>
3"
1632 [(set (match_operand:X
0 "register_operand" "=r")
1633 (and:X (not:X (match_operand:X
1 "register_operand" "%r"))
1634 (not:X (match_operand:X
2 "register_operand" "r"))))]
1637 [(set_attr "type" "logical")
1638 (set_attr "mode" "<MODE>")])
1640 (define_insn "*norsi3_internal"
1641 [(set (match_operand:SI
0 "register_operand" "=r")
1642 (and:SI (not:SI (match_operand:SI
1 "register_operand" "%r"))
1643 (not:SI (match_operand:SI
2 "register_operand" "r"))))]
1646 [(set_attr "type" "logical")
1647 (set_attr "mode" "SI")])
1649 (define_insn "<optab>n<mode>"
1650 [(set (match_operand:X
0 "register_operand" "=r")
1652 (not:X (match_operand:X
1 "register_operand" "r"))
1653 (match_operand:X
2 "register_operand" "r")))]
1656 [(set_attr "type" "logical")
1657 (set_attr "mode" "<MODE>")])
1659 (define_insn "*<optab>nsi_internal"
1660 [(set (match_operand:SI
0 "register_operand" "=r")
1662 (not:SI (match_operand:SI
1 "register_operand" "r"))
1663 (match_operand:SI
2 "register_operand" "r")))]
1666 [(set_attr "type" "logical")
1667 (set_attr "mode" "SI")])
1670 ;; ....................
1674 ;; ....................
1676 (define_insn "truncdfsf2"
1677 [(set (match_operand:SF
0 "register_operand" "=f")
1678 (float_truncate:SF (match_operand:DF
1 "register_operand" "f")))]
1679 "TARGET_DOUBLE_FLOAT"
1681 [(set_attr "type" "fcvt")
1682 (set_attr "cnv_mode" "D2S")
1683 (set_attr "mode" "SF")])
1685 ;; In vector registers, popcount can be implemented directly through
1686 ;; the vector instruction [X]VPCNT. For GP registers, we can implement
1687 ;; it through the following method. Compared with loop implementation
1688 ;; of popcount, the following method has better performance.
1690 ;; This attribute used for get connection of scalar mode and corresponding
1692 (define_mode_attr cntmap [(SI "v4si") (DI "v2di")])
1694 (define_expand "popcount<mode>
2"
1695 [(set (match_operand:GPR
0 "register_operand")
1696 (popcount:GPR (match_operand:GPR
1 "register_operand")))]
1699 rtx in = operands[
1];
1700 rtx out = operands[
0];
1701 rtx vreg = <MODE>mode == SImode ? gen_reg_rtx (V4SImode) :
1702 gen_reg_rtx (V2DImode);
1703 emit_insn (gen_lsx_vinsgr2vr_<size> (vreg, in, vreg, GEN_INT (
1)));
1704 emit_insn (gen_popcount<cntmap>
2 (vreg, vreg));
1705 emit_insn (gen_lsx_vpickve2gr_<size> (out, vreg, GEN_INT (
0)));
1710 ;; ....................
1714 ;; ....................
1715 (define_expand "zero_extendsidi2"
1716 [(set (match_operand:DI
0 "register_operand")
1717 (zero_extend:DI (match_operand:SI
1 "nonimmediate_operand")))]
1720 (define_insn_and_split "*zero_extendsidi2_internal"
1721 [(set (match_operand:DI
0 "register_operand" "=r,r,r,r")
1722 (zero_extend:DI (match_operand:SI
1 "nonimmediate_operand" "r,m,ZC,k")))]
1725 bstrpick.d
\t%
0,%
1,
31,
0
1729 "&& reload_completed
1730 && MEM_P (operands[
1])
1731 && (loongarch_14bit_shifted_offset_address_p (XEXP (operands[
1],
0), SImode)
1732 && !loongarch_12bit_offset_address_p (XEXP (operands[
1],
0), SImode))
1733 && !paradoxical_subreg_p (operands[
0])"
1734 [(set (match_dup
3) (match_dup
1))
1736 (ior:DI (zero_extend:DI
1737 (subreg:SI (match_dup
0)
0))
1740 operands[
1] = gen_lowpart (SImode, operands[
1]);
1741 operands[
3] = gen_lowpart (SImode, operands[
0]);
1742 operands[
2] = const0_rtx;
1744 [(set_attr "move_type" "arith,load,load,load")
1745 (set_attr "mode" "DI")])
1747 (define_insn "zero_extend<SHORT:mode><GPR:mode>
2"
1748 [(set (match_operand:GPR
0 "register_operand" "=r,r,r")
1750 (match_operand:SHORT
1 "nonimmediate_operand" "r,m,k")))]
1753 bstrpick.w
\t%
0,%
1,<SHORT:
7_or_15>,
0
1754 ld.<SHORT:size>u
\t%
0,%
1
1755 ldx.<SHORT:size>u
\t%
0,%
1"
1756 [(set_attr "move_type" "pick_ins,load,load")
1757 (set_attr "mode" "<GPR:MODE>")])
1759 (define_insn "zero_extendqihi2"
1760 [(set (match_operand:HI
0 "register_operand" "=r,r,r")
1761 (zero_extend:HI (match_operand:QI
1 "nonimmediate_operand" "r,k,m")))]
1767 [(set_attr "move_type" "andi,load,load")
1768 (set_attr "mode" "HI")])
1770 ;; Combiner patterns to optimize truncate/zero_extend combinations.
1772 (define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>"
1773 [(set (match_operand:GPR
0 "register_operand" "=r")
1775 (truncate:SHORT (match_operand:DI
1 "register_operand" "r"))))]
1777 "bstrpick.w
\t%
0,%
1,<SHORT:
7_or_15>,
0"
1778 [(set_attr "move_type" "pick_ins")
1779 (set_attr "mode" "<GPR:MODE>")])
1781 (define_insn "*zero_extendhi_truncqi"
1782 [(set (match_operand:HI
0 "register_operand" "=r")
1784 (truncate:QI (match_operand:DI
1 "register_operand" "r"))))]
1787 [(set_attr "alu_type" "and")
1788 (set_attr "mode" "HI")])
1791 ;; ....................
1795 ;; ....................
1797 (define_insn "extendsidi2"
1798 [(set (match_operand:DI
0 "register_operand" "=r,r,r,r")
1800 (match_operand:SI
1 "nonimmediate_operand" "r,ZC,m,k")))]
1807 [(set_attr "move_type" "sll0,load,load,load")
1808 (set_attr "mode" "DI")])
1810 (define_insn "extend<SHORT:mode><GPR:mode>
2"
1811 [(set (match_operand:GPR
0 "register_operand" "=r,r,r")
1813 (match_operand:SHORT
1 "nonimmediate_operand" "r,m,k")))]
1816 ext.w.<SHORT:size>
\t%
0,%
1
1817 ld.<SHORT:size>
\t%
0,%
1
1818 ldx.<SHORT:size>
\t%
0,%
1"
1819 [(set_attr "move_type" "signext,load,load")
1820 (set_attr "mode" "<GPR:MODE>")])
1822 (define_insn "extendqihi2"
1823 [(set (match_operand:HI
0 "register_operand" "=r,r,r")
1825 (match_operand:QI
1 "nonimmediate_operand" "r,m,k")))]
1831 [(set_attr "move_type" "signext,load,load")
1832 (set_attr "mode" "SI")])
1834 (define_insn "extendsfdf2"
1835 [(set (match_operand:DF
0 "register_operand" "=f")
1836 (float_extend:DF (match_operand:SF
1 "register_operand" "f")))]
1837 "TARGET_DOUBLE_FLOAT"
1839 [(set_attr "type" "fcvt")
1840 (set_attr "cnv_mode" "S2D")
1841 (set_attr "mode" "DF")])
1844 ;; ....................
1848 ;; ....................
1850 ;; conversion of a floating-point value to a integer
1852 (define_insn "fix_trunc<ANYF:mode><GPR:mode>
2"
1853 [(set (match_operand:GPR
0 "register_operand" "=f")
1854 (fix:GPR (match_operand:ANYF
1 "register_operand" "f")))]
1856 "ftintrz.<GPR:ifmt>.<ANYF:fmt> %
0,%
1"
1857 [(set_attr "type" "fcvt")
1858 (set_attr "mode" "<ANYF:MODE>")])
1860 ;; conversion of an integeral (or boolean) value to a floating-point value
1862 (define_insn "floatsidf2"
1863 [(set (match_operand:DF
0 "register_operand" "=f")
1864 (float:DF (match_operand:SI
1 "register_operand" "f")))]
1865 "TARGET_DOUBLE_FLOAT"
1867 [(set_attr "type" "fcvt")
1868 (set_attr "mode" "DF")
1869 (set_attr "cnv_mode" "I2D")])
1871 (define_insn "floatdidf2"
1872 [(set (match_operand:DF
0 "register_operand" "=f")
1873 (float:DF (match_operand:DI
1 "register_operand" "f")))]
1874 "TARGET_DOUBLE_FLOAT"
1876 [(set_attr "type" "fcvt")
1877 (set_attr "mode" "DF")
1878 (set_attr "cnv_mode" "I2D")])
1880 (define_insn "floatsisf2"
1881 [(set (match_operand:SF
0 "register_operand" "=f")
1882 (float:SF (match_operand:SI
1 "register_operand" "f")))]
1885 [(set_attr "type" "fcvt")
1886 (set_attr "mode" "SF")
1887 (set_attr "cnv_mode" "I2S")])
1889 (define_insn "floatdisf2"
1890 [(set (match_operand:SF
0 "register_operand" "=f")
1891 (float:SF (match_operand:DI
1 "register_operand" "f")))]
1892 "TARGET_DOUBLE_FLOAT"
1894 [(set_attr "type" "fcvt")
1895 (set_attr "mode" "SF")
1896 (set_attr "cnv_mode" "I2S")])
1898 ;; Convert a floating-point value to an unsigned integer.
1900 (define_expand "fixuns_truncdfsi2"
1901 [(set (match_operand:SI
0 "register_operand")
1902 (unsigned_fix:SI (match_operand:DF
1 "register_operand")))]
1903 "TARGET_DOUBLE_FLOAT"
1905 rtx reg1 = gen_reg_rtx (DFmode);
1906 rtx reg2 = gen_reg_rtx (DFmode);
1907 rtx reg3 = gen_reg_rtx (SImode);
1908 rtx_code_label *label1 = gen_label_rtx ();
1909 rtx_code_label *label2 = gen_label_rtx ();
1911 REAL_VALUE_TYPE offset;
1913 real_2expN (&offset,
31, DFmode);
1915 loongarch_emit_move (reg1,
1916 const_double_from_real_value (offset, DFmode));
1917 do_pending_stack_adjust ();
1919 test = gen_rtx_GE (VOIDmode, operands[
1], reg1);
1920 emit_jump_insn (gen_cbranchdf4 (test, operands[
1], reg1, label1));
1922 emit_insn (gen_fix_truncdfsi2 (operands[
0], operands[
1]));
1923 emit_jump_insn (gen_rtx_SET (pc_rtx,
1924 gen_rtx_LABEL_REF (VOIDmode, label2)));
1927 emit_label (label1);
1928 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[
1], reg1));
1929 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
1930 (BITMASK_HIGH, SImode)));
1932 emit_insn (gen_fix_truncdfsi2 (operands[
0], reg2));
1933 emit_insn (gen_iorsi3 (operands[
0], operands[
0], reg3));
1935 emit_label (label2);
1937 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1938 fields, and can't be used for REG_NOTES anyway). */
1939 emit_use (stack_pointer_rtx);
1943 (define_expand "fixuns_truncdfdi2"
1944 [(set (match_operand:DI
0 "register_operand")
1945 (unsigned_fix:DI (match_operand:DF
1 "register_operand")))]
1946 "TARGET_DOUBLE_FLOAT"
1948 rtx reg1 = gen_reg_rtx (DFmode);
1949 rtx reg2 = gen_reg_rtx (DFmode);
1950 rtx reg3 = gen_reg_rtx (DImode);
1951 rtx_code_label *label1 = gen_label_rtx ();
1952 rtx_code_label *label2 = gen_label_rtx ();
1954 REAL_VALUE_TYPE offset;
1956 real_2expN (&offset,
63, DFmode);
1958 loongarch_emit_move (reg1, const_double_from_real_value (offset, DFmode));
1959 do_pending_stack_adjust ();
1961 test = gen_rtx_GE (VOIDmode, operands[
1], reg1);
1962 emit_jump_insn (gen_cbranchdf4 (test, operands[
1], reg1, label1));
1964 emit_insn (gen_fix_truncdfdi2 (operands[
0], operands[
1]));
1965 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
1968 emit_label (label1);
1969 loongarch_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[
1], reg1));
1970 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
1971 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (
32)));
1973 emit_insn (gen_fix_truncdfdi2 (operands[
0], reg2));
1974 emit_insn (gen_iordi3 (operands[
0], operands[
0], reg3));
1976 emit_label (label2);
1978 /* Allow REG_NOTES to be set on last insn (labels don't have enough
1979 fields, and can't be used for REG_NOTES anyway). */
1980 emit_use (stack_pointer_rtx);
1984 (define_expand "fixuns_truncsfsi2"
1985 [(set (match_operand:SI
0 "register_operand")
1986 (unsigned_fix:SI (match_operand:SF
1 "register_operand")))]
1989 rtx reg1 = gen_reg_rtx (SFmode);
1990 rtx reg2 = gen_reg_rtx (SFmode);
1991 rtx reg3 = gen_reg_rtx (SImode);
1992 rtx_code_label *label1 = gen_label_rtx ();
1993 rtx_code_label *label2 = gen_label_rtx ();
1995 REAL_VALUE_TYPE offset;
1997 real_2expN (&offset,
31, SFmode);
1999 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2000 do_pending_stack_adjust ();
2002 test = gen_rtx_GE (VOIDmode, operands[
1], reg1);
2003 emit_jump_insn (gen_cbranchsf4 (test, operands[
1], reg1, label1));
2005 emit_insn (gen_fix_truncsfsi2 (operands[
0], operands[
1]));
2006 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2009 emit_label (label1);
2010 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[
1], reg1));
2011 loongarch_emit_move (reg3, GEN_INT (trunc_int_for_mode
2012 (BITMASK_HIGH, SImode)));
2014 emit_insn (gen_fix_truncsfsi2 (operands[
0], reg2));
2015 emit_insn (gen_iorsi3 (operands[
0], operands[
0], reg3));
2017 emit_label (label2);
2019 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2020 fields, and can't be used for REG_NOTES anyway). */
2021 emit_use (stack_pointer_rtx);
2025 (define_expand "fixuns_truncsfdi2"
2026 [(set (match_operand:DI
0 "register_operand")
2027 (unsigned_fix:DI (match_operand:SF
1 "register_operand")))]
2028 "TARGET_DOUBLE_FLOAT"
2030 rtx reg1 = gen_reg_rtx (SFmode);
2031 rtx reg2 = gen_reg_rtx (SFmode);
2032 rtx reg3 = gen_reg_rtx (DImode);
2033 rtx_code_label *label1 = gen_label_rtx ();
2034 rtx_code_label *label2 = gen_label_rtx ();
2036 REAL_VALUE_TYPE offset;
2038 real_2expN (&offset,
63, SFmode);
2040 loongarch_emit_move (reg1, const_double_from_real_value (offset, SFmode));
2041 do_pending_stack_adjust ();
2043 test = gen_rtx_GE (VOIDmode, operands[
1], reg1);
2044 emit_jump_insn (gen_cbranchsf4 (test, operands[
1], reg1, label1));
2046 emit_insn (gen_fix_truncsfdi2 (operands[
0], operands[
1]));
2047 emit_jump_insn (gen_rtx_SET (pc_rtx, gen_rtx_LABEL_REF (VOIDmode, label2)));
2050 emit_label (label1);
2051 loongarch_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[
1], reg1));
2052 loongarch_emit_move (reg3, GEN_INT (BITMASK_HIGH));
2053 emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (
32)));
2055 emit_insn (gen_fix_truncsfdi2 (operands[
0], reg2));
2056 emit_insn (gen_iordi3 (operands[
0], operands[
0], reg3));
2058 emit_label (label2);
2060 /* Allow REG_NOTES to be set on last insn (labels don't have enough
2061 fields, and can't be used for REG_NOTES anyway). */
2062 emit_use (stack_pointer_rtx);
2067 ;; ....................
2069 ;; EXTRACT AND INSERT
2071 ;; ....................
2073 (define_expand "extzv<mode>"
2074 [(set (match_operand:X
0 "register_operand")
2075 (zero_extract:X (match_operand:X
1 "register_operand")
2076 (match_operand
2 "const_int_operand")
2077 (match_operand
3 "const_int_operand")))]
2080 if (!loongarch_use_ins_ext_p (operands[
1], INTVAL (operands[
2]),
2081 INTVAL (operands[
3])))
2085 (define_insn "*extzv<mode>"
2086 [(set (match_operand:X
0 "register_operand" "=r")
2087 (zero_extract:X (match_operand:X
1 "register_operand" "r")
2088 (match_operand
2 "const_int_operand" "")
2089 (match_operand
3 "const_int_operand" "")))]
2090 "loongarch_use_ins_ext_p (operands[
1], INTVAL (operands[
2]),
2091 INTVAL (operands[
3]))"
2093 operands[
2] = GEN_INT (INTVAL (operands[
2]) + INTVAL (operands[
3]) -
1);
2094 return "bstrpick.<d>
\t%
0,%
1,%
2,%
3";
2096 [(set_attr "type" "arith")
2097 (set_attr "mode" "<MODE>")])
2099 (define_expand "insv<mode>"
2100 [(set (zero_extract:GPR (match_operand:GPR
0 "register_operand")
2101 (match_operand
1 "const_int_operand")
2102 (match_operand
2 "const_int_operand"))
2103 (match_operand:GPR
3 "reg_or_0_operand"))]
2106 if (!loongarch_use_ins_ext_p (operands[
0], INTVAL (operands[
1]),
2107 INTVAL (operands[
2])))
2111 (define_insn "*insv<mode>"
2112 [(set (zero_extract:GPR (match_operand:GPR
0 "register_operand" "+r")
2113 (match_operand:SI
1 "const_int_operand" "")
2114 (match_operand:SI
2 "const_int_operand" ""))
2115 (match_operand:GPR
3 "reg_or_0_operand" "rJ"))]
2116 "loongarch_use_ins_ext_p (operands[
0], INTVAL (operands[
1]),
2117 INTVAL (operands[
2]))"
2119 operands[
1] = GEN_INT (INTVAL (operands[
1]) + INTVAL (operands[
2]) -
1);
2120 return "bstrins.<d>
\t%
0,%z3,%
1,%
2";
2122 [(set_attr "type" "arith")
2123 (set_attr "mode" "<MODE>")])
2126 ;; ....................
2130 ;; ....................
2132 ;;
64-bit integer moves
2134 ;; Unlike most other insns, the move insns can't be split with
2135 ;; different predicates, because register spilling and other parts of
2136 ;; the compiler, have memoized the insn number already.
2138 (define_expand "movdi"
2139 [(set (match_operand:DI
0 "")
2140 (match_operand:DI
1 ""))]
2143 if (loongarch_legitimize_move (DImode, operands[
0], operands[
1]))
2147 (define_insn_and_split "*movdi_32bit"
2148 [(set (match_operand:DI
0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2149 (match_operand:DI
1 "move_operand" "r,i,w,r,*J*r,*m,*f,*f"))]
2151 && (register_operand (operands[
0], DImode)
2152 || reg_or_0_operand (operands[
1], DImode))"
2153 { return loongarch_output_move (operands[
0], operands[
1]); }
2154 "CONST_INT_P (operands[
1]) && REG_P (operands[
0]) && GP_REG_P (REGNO
2159 loongarch_move_integer (operands[
0], operands[
0], INTVAL (operands[
1]));
2163 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2164 (set_attr "mode" "DI")])
2166 (define_insn_and_split "*movdi_64bit"
2167 [(set (match_operand:DI
0 "nonimmediate_operand" "=r,r,r,w,*f,*f,*r,*m")
2168 (match_operand:DI
1 "move_operand" "r,Yd,w,rJ,*r*J,*m,*f,*f"))]
2170 && (register_operand (operands[
0], DImode)
2171 || reg_or_0_operand (operands[
1], DImode))"
2172 { return loongarch_output_move (operands[
0], operands[
1]); }
2173 "CONST_INT_P (operands[
1]) && REG_P (operands[
0]) && GP_REG_P (REGNO
2178 loongarch_move_integer (operands[
0], operands[
0], INTVAL (operands[
1]));
2182 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2183 (set_attr "mode" "DI")])
2185 ;;
32-bit Integer moves
2187 (define_expand "movsi"
2188 [(set (match_operand:SI
0 "")
2189 (match_operand:SI
1 ""))]
2192 if (loongarch_legitimize_move (SImode, operands[
0], operands[
1]))
2196 (define_insn_and_split "*movsi_internal"
2197 [(set (match_operand:SI
0 "nonimmediate_operand" "=r,r,r,w,*f,f,*r,*m")
2198 (match_operand:SI
1 "move_operand" "r,Yd,w,rJ,*r*J,m,*f,*f"))]
2199 "(register_operand (operands[
0], SImode)
2200 || reg_or_0_operand (operands[
1], SImode))"
2201 { return loongarch_output_move (operands[
0], operands[
1]); }
2202 "CONST_INT_P (operands[
1]) && REG_P (operands[
0]) && GP_REG_P (REGNO
2207 loongarch_move_integer (operands[
0], operands[
0], INTVAL (operands[
1]));
2211 [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore")
2212 (set_attr "mode" "SI")])
2214 ;;
16-bit Integer moves
2216 ;; Unlike most other insns, the move insns can't be split with
2217 ;; different predicates, because register spilling and other parts of
2218 ;; the compiler, have memoized the insn number already.
2219 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2221 (define_expand "movhi"
2222 [(set (match_operand:HI
0 "")
2223 (match_operand:HI
1 ""))]
2226 if (loongarch_legitimize_move (HImode, operands[
0], operands[
1]))
2230 (define_insn_and_split "*movhi_internal"
2231 [(set (match_operand:HI
0 "nonimmediate_operand" "=r,r,r,r,m,r,k")
2232 (match_operand:HI
1 "move_operand" "r,Yd,I,m,rJ,k,rJ"))]
2233 "(register_operand (operands[
0], HImode)
2234 || reg_or_0_operand (operands[
1], HImode))"
2235 { return loongarch_output_move (operands[
0], operands[
1]); }
2236 "CONST_INT_P (operands[
1]) && REG_P (operands[
0]) && GP_REG_P (REGNO
2241 loongarch_move_integer (operands[
0], operands[
0], INTVAL (operands[
1]));
2245 [(set_attr "move_type" "move,const,const,load,store,load,store")
2246 (set_attr "mode" "HI")])
2248 ;;
8-bit Integer moves
2250 ;; Unlike most other insns, the move insns can't be split with
2251 ;; different predicates, because register spilling and other parts of
2252 ;; the compiler, have memoized the insn number already.
2253 ;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND.
2255 (define_expand "movqi"
2256 [(set (match_operand:QI
0 "")
2257 (match_operand:QI
1 ""))]
2260 if (loongarch_legitimize_move (QImode, operands[
0], operands[
1]))
2264 (define_insn "*movqi_internal"
2265 [(set (match_operand:QI
0 "nonimmediate_operand" "=r,r,r,m,r,k")
2266 (match_operand:QI
1 "move_operand" "r,I,m,rJ,k,rJ"))]
2267 "(register_operand (operands[
0], QImode)
2268 || reg_or_0_operand (operands[
1], QImode))"
2269 { return loongarch_output_move (operands[
0], operands[
1]); }
2270 [(set_attr "move_type" "move,const,load,store,load,store")
2271 (set_attr "mode" "QI")])
2273 ;;
32-bit floating point moves
2275 (define_expand "movsf"
2276 [(set (match_operand:SF
0 "")
2277 (match_operand:SF
1 ""))]
2280 if (loongarch_legitimize_move (SFmode, operands[
0], operands[
1]))
2284 (define_insn "*movsf_hardfloat"
2285 [(set (match_operand:SF
0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2286 (match_operand:SF
1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*G*r,*m,*r"))]
2288 && (register_operand (operands[
0], SFmode)
2289 || reg_or_0_operand (operands[
1], SFmode))"
2290 { return loongarch_output_move (operands[
0], operands[
1]); }
2291 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2292 (set_attr "mode" "SF")])
2294 (define_insn "*movsf_softfloat"
2295 [(set (match_operand:SF
0 "nonimmediate_operand" "=r,r,m")
2296 (match_operand:SF
1 "move_operand" "Gr,m,r"))]
2298 && (register_operand (operands[
0], SFmode)
2299 || reg_or_0_operand (operands[
1], SFmode))"
2300 { return loongarch_output_move (operands[
0], operands[
1]); }
2301 [(set_attr "move_type" "move,load,store")
2302 (set_attr "mode" "SF")])
2304 ;;
64-bit floating point moves
2306 (define_expand "movdf"
2307 [(set (match_operand:DF
0 "")
2308 (match_operand:DF
1 ""))]
2311 if (loongarch_legitimize_move (DFmode, operands[
0], operands[
1]))
2315 (define_insn "*movdf_hardfloat"
2316 [(set (match_operand:DF
0 "nonimmediate_operand" "=f,f,f,m,f,k,m,k,*f,*r,*r,*r,*m")
2317 (match_operand:DF
1 "move_operand" "f,G,m,f,k,f,G,G,*r,*f,*r*G,*m,*r"))]
2318 "TARGET_DOUBLE_FLOAT
2319 && (register_operand (operands[
0], DFmode)
2320 || reg_or_0_operand (operands[
1], DFmode))"
2321 { return loongarch_output_move (operands[
0], operands[
1]); }
2322 [(set_attr "move_type" "fmove,mgtf,fpload,fpstore,fpload,fpstore,store,store,mgtf,mftg,move,load,store")
2323 (set_attr "mode" "DF")])
2325 (define_insn "*movdf_softfloat"
2326 [(set (match_operand:DF
0 "nonimmediate_operand" "=r,r,m")
2327 (match_operand:DF
1 "move_operand" "rG,m,rG"))]
2328 "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
2329 && (register_operand (operands[
0], DFmode)
2330 || reg_or_0_operand (operands[
1], DFmode))"
2331 { return loongarch_output_move (operands[
0], operands[
1]); }
2332 [(set_attr "move_type" "move,load,store")
2333 (set_attr "mode" "DF")])
2335 ;; Emit a doubleword move in which exactly one of the operands is
2336 ;; a floating-point register. We can't just emit two normal moves
2337 ;; because of the constraints imposed by the FPU register model;
2338 ;; see loongarch_can_change_mode_class for details. Instead, we keep
2339 ;; the FPR whole and use special patterns to refer to each word of
2340 ;; the other operand.
2342 (define_expand "move_doubleword_fpr<mode>"
2343 [(set (match_operand:SPLITF
0)
2344 (match_operand:SPLITF
1))]
2347 if (FP_REG_RTX_P (operands[
0]))
2349 rtx low = loongarch_subword (operands[
1],
0);
2350 rtx high = loongarch_subword (operands[
1],
1);
2351 emit_insn (gen_load_low<mode> (operands[
0], low));
2353 emit_insn (gen_movgr2frh<mode> (operands[
0], high, operands[
0]));
2355 emit_insn (gen_load_high<mode> (operands[
0], high, operands[
0]));
2359 rtx low = loongarch_subword (operands[
0],
0);
2360 rtx high = loongarch_subword (operands[
0],
1);
2361 emit_insn (gen_store_word<mode> (low, operands[
1], const0_rtx));
2363 emit_insn (gen_movfrh2gr<mode> (high, operands[
1]));
2365 emit_insn (gen_store_word<mode> (high, operands[
1], const1_rtx));
2370 ;; Clear one FCC register
2372 (define_expand "movfcc"
2373 [(set (match_operand:FCC
0 "")
2374 (match_operand:FCC
1 ""))]
2377 if (memory_operand (operands[
0], FCCmode)
2378 && memory_operand (operands[
1], FCCmode))
2379 operands[
1] = force_reg (FCCmode, operands[
1]);
2382 (define_insn "movfcc_internal"
2383 [(set (match_operand:FCC
0 "nonimmediate_operand"
2384 "=z,z,*f,*f,*r,*r,*m,*f,*r,z,*r")
2385 (match_operand:FCC
1 "reg_or_0_operand"
2386 "J,*f,z,*f,J*r,*m,J*r,J*r,*f,*r,z"))]
2389 fcmp.caf.s
\t%
0,$f0,$f0
2400 [(set_attr "type" "move")
2401 (set_attr "mode" "FCC")])
2403 (define_insn "fcc_to_<X:mode>"
2404 [(set (match_operand:X
0 "register_operand" "=r")
2405 (if_then_else:X (ne (match_operand:FCC
1 "register_operand" "
0")
2411 [(set_attr "length" "
0")
2412 (set_attr "type" "ghost")])
2414 (define_expand "cstore<ANYF:mode>
4"
2415 [(set (match_operand:SI
0 "register_operand")
2416 (match_operator:SI
1 "loongarch_fcmp_operator"
2417 [(match_operand:ANYF
2 "register_operand")
2418 (match_operand:ANYF
3 "register_operand")]))]
2421 rtx fcc = gen_reg_rtx (FCCmode);
2422 rtx cmp = gen_rtx_fmt_ee (GET_CODE (operands[
1]), FCCmode,
2423 operands[
2], operands[
3]);
2425 emit_insn (gen_rtx_SET (fcc, cmp));
2428 rtx gpr = gen_reg_rtx (DImode);
2429 emit_insn (gen_fcc_to_di (gpr, fcc));
2430 emit_insn (gen_rtx_SET (operands[
0],
2431 lowpart_subreg (SImode, gpr, DImode)));
2434 emit_insn (gen_fcc_to_si (operands[
0], fcc));
2439 ;; Conditional move instructions.
2441 (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
2442 [(set (match_operand:GPR
0 "register_operand" "=r,r")
2444 (equality_op:GPR2 (match_operand:GPR2
1 "register_operand" "r,r")
2446 (match_operand:GPR
2 "reg_or_0_operand" "r,J")
2447 (match_operand:GPR
3 "reg_or_0_operand" "J,r")))]
2448 "register_operand (operands[
2], <GPR:MODE>mode)
2449 != register_operand (operands[
3], <GPR:MODE>mode)"
2453 [(set_attr "type" "condmove")
2454 (set_attr "mode" "<GPR:MODE>")])
2456 ;; fsel copies the
3rd argument when the
1st is non-zero and the
2nd
2457 ;; argument if the
1st is zero. This means operand
2 and
3 are
2458 ;; inverted in the instruction.
2460 (define_insn "*sel<mode>"
2461 [(set (match_operand:ANYF
0 "register_operand" "=f")
2463 (ne:FCC (match_operand:FCC
1 "register_operand" "z")
2465 (match_operand:ANYF
2 "reg_or_0_operand" "f")
2466 (match_operand:ANYF
3 "reg_or_0_operand" "f")))]
2469 [(set_attr "type" "condmove")
2470 (set_attr "mode" "<ANYF:MODE>")])
2472 ;; These are the main define_expand's used to make conditional moves.
2474 (define_expand "mov<mode>cc"
2475 [(set (match_operand:GPR
0 "register_operand")
2476 (if_then_else:GPR (match_operator
1 "comparison_operator"
2477 [(match_operand:GPR
2 "reg_or_0_operand")
2478 (match_operand:GPR
3 "reg_or_0_operand")])))]
2479 "TARGET_COND_MOVE_INT"
2481 if (!INTEGRAL_MODE_P (GET_MODE (XEXP (operands[
1],
0))))
2484 loongarch_expand_conditional_move (operands);
2488 (define_expand "mov<mode>cc"
2489 [(set (match_operand:ANYF
0 "register_operand")
2490 (if_then_else:ANYF (match_operator
1 "comparison_operator"
2491 [(match_operand:ANYF
2 "reg_or_0_operand")
2492 (match_operand:ANYF
3 "reg_or_0_operand")])))]
2493 "TARGET_COND_MOVE_FLOAT"
2495 if (!FLOAT_MODE_P (GET_MODE (XEXP (operands[
1],
0))))
2498 loongarch_expand_conditional_move (operands);
2502 (define_insn "lu32i_d"
2503 [(set (match_operand:DI
0 "register_operand" "=r")
2506 (subreg:SI (match_operand:DI
1 "register_operand" "
0")
0))
2507 (match_operand:DI
2 "const_lu32i_operand" "u")))]
2509 "lu32i.d
\t%
0,%X2>>
32"
2510 [(set_attr "type" "arith")
2511 (set_attr "mode" "DI")])
2513 (define_insn "lu52i_d"
2514 [(set (match_operand:DI
0 "register_operand" "=r")
2516 (and:DI (match_operand:DI
1 "register_operand" "r")
2517 (match_operand
2 "lu52i_mask_operand"))
2518 (match_operand
3 "const_lu52i_operand" "v")))]
2520 "lu52i.d
\t%
0,%
1,%X3>>
52"
2521 [(set_attr "type" "arith")
2522 (set_attr "mode" "DI")])
2524 ;; Instructions for adding the low
12 bits of an address to a register.
2525 ;; Operand
2 is the address: loongarch_print_operand works out which relocation
2526 ;; should be applied.
2528 (define_insn "*low<mode>"
2529 [(set (match_operand:P
0 "register_operand" "=r")
2530 (lo_sum:P (match_operand:P
1 "register_operand" " r")
2531 (match_operand:P
2 "symbolic_operand" "")))]
2533 "addi.<d>
\t%
0,%
1,%L2"
2534 [(set_attr "type" "arith")
2535 (set_attr "mode" "<MODE>")])
2537 (define_insn "@tls_low<mode>"
2538 [(set (match_operand:P
0 "register_operand" "=r")
2539 (unspec:P [(mem:P (lo_sum:P (match_operand:P
1 "register_operand" "r")
2540 (match_operand:P
2 "symbolic_operand" "")))]
2543 "addi.<d>
\t%
0,%
1,%L2"
2544 [(set_attr "type" "arith")
2545 (set_attr "mode" "<MODE>")])
2547 ;; Instructions for loading address from GOT entry.
2548 ;; operands[
1] is pc plus the high half of the address difference with the got
2550 ;; operands[
2] is low
12 bits for low
12 bit of the address difference with the
2552 ;; loongarch_print_operand works out which relocation should be applied.
2554 (define_insn "@ld_from_got<mode>"
2555 [(set (match_operand:P
0 "register_operand" "=r")
2556 (unspec:P [(mem:P (lo_sum:P
2557 (match_operand:P
1 "register_operand" "r")
2558 (match_operand:P
2 "symbolic_operand")))]
2559 UNSPEC_LOAD_FROM_GOT))]
2562 [(set_attr "type" "move")]
2565 (define_insn "@lui_l_hi20<mode>"
2566 [(set (match_operand:P
0 "register_operand" "=r")
2567 (unspec:P [(match_operand:P
1 "symbolic_operand")]
2568 UNSPEC_LUI_L_HI20))]
2571 [(set_attr "type" "move")]
2574 (define_insn "@pcalau12i<mode>"
2575 [(set (match_operand:P
0 "register_operand" "=j")
2576 (unspec:P [(match_operand:P
1 "symbolic_operand" "")]
2579 "pcalau12i
\t%
0,%%pc_hi20(%
1)"
2580 [(set_attr "type" "move")])
2582 ;; @pcalau12i may be used for sibcall so it has a strict constraint. This
2583 ;; allows any general register as the operand.
2584 (define_insn "@pcalau12i_gr<mode>"
2585 [(set (match_operand:P
0 "register_operand" "=r")
2586 (unspec:P [(match_operand:P
1 "symbolic_operand" "")]
2587 UNSPEC_PCALAU12I_GR))]
2589 "pcalau12i
\t%
0,%%pc_hi20(%
1)"
2590 [(set_attr "type" "move")])
2592 (define_insn "@add_tls_le_relax<mode>"
2593 [(set (match_operand:P
0 "register_operand" "=r")
2594 (unspec:P [(match_operand:P
1 "register_operand" "r")
2595 (match_operand:P
2 "register_operand" "r")
2596 (match_operand:P
3 "symbolic_operand")]
2597 UNSPEC_ADD_TLS_LE_RELAX))]
2598 "HAVE_AS_TLS_LE_RELAXATION"
2599 "add.<d>
\t%
0,%
1,%
2,%%le_add_r(%
3)"
2600 [(set_attr "type" "move")]
2603 (define_insn "@ori_l_lo12<mode>"
2604 [(set (match_operand:P
0 "register_operand" "=r")
2605 (unspec:P [(match_operand:P
1 "register_operand" "r")
2606 (match_operand:P
2 "symbolic_operand")]
2607 UNSPEC_ORI_L_LO12))]
2610 [(set_attr "type" "move")]
2613 (define_insn "lui_h_lo20"
2614 [(set (match_operand:DI
0 "register_operand" "=r")
2615 (unspec:DI [(match_operand:DI
1 "register_operand" "
0")
2616 (match_operand:DI
2 "symbolic_operand")]
2617 UNSPEC_LUI_H_LO20))]
2620 [(set_attr "type" "move")]
2623 (define_insn "lui_h_hi12"
2624 [(set (match_operand:DI
0 "register_operand" "=r")
2625 (unspec:DI [(match_operand:DI
1 "register_operand" "r")
2626 (match_operand:DI
2 "symbolic_operand")]
2627 UNSPEC_LUI_H_HI12))]
2629 "lu52i.d
\t%
0,%
1,%H2"
2630 [(set_attr "type" "move")]
2633 ;; Round floating-point numbers to integers
2634 (define_insn "rint<mode>
2"
2635 [(set (match_operand:ANYF
0 "register_operand" "=f")
2636 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
2639 "frint.<fmt>
\t%
0,%
1"
2640 [(set_attr "type" "fcvt")
2641 (set_attr "mode" "<MODE>")])
2643 ;; Convert floating-point numbers to integers
2644 (define_insn "<lrint_pattern><ANYF:mode><ANYFI:mode>
2"
2645 [(set (match_operand:ANYFI
0 "register_operand" "=f")
2646 (unspec:ANYFI [(match_operand:ANYF
1 "register_operand" "f")]
2648 "TARGET_HARD_FLOAT &&
2649 (<LRINT> == UNSPEC_FTINT
2650 || flag_fp_int_builtin_inexact
2651 || !flag_trapping_math)"
2652 "ftint<lrint_submenmonic>.<ANYFI:ifmt>.<ANYF:fmt> %
0,%
1"
2653 [(set_attr "type" "fcvt")
2654 (set_attr "mode" "<ANYF:MODE>")])
2656 ;; Load the low word of operand
0 with operand
1.
2657 (define_insn "load_low<mode>"
2658 [(set (match_operand:SPLITF
0 "register_operand" "=f,f")
2659 (unspec:SPLITF [(match_operand:<HALFMODE>
1 "general_operand" "rJ,m")]
2663 operands[
0] = loongarch_subword (operands[
0],
0);
2664 return loongarch_output_move (operands[
0], operands[
1]);
2666 [(set_attr "move_type" "mgtf,fpload")
2667 (set_attr "mode" "<HALFMODE>")])
2669 ;; Load the high word of operand
0 from operand
1, preserving the value
2671 (define_insn "load_high<mode>"
2672 [(set (match_operand:SPLITF
0 "register_operand" "=f,f")
2673 (unspec:SPLITF [(match_operand:<HALFMODE>
1 "general_operand" "rJ,m")
2674 (match_operand:SPLITF
2 "register_operand" "
0,
0")]
2678 operands[
0] = loongarch_subword (operands[
0],
1);
2679 return loongarch_output_move (operands[
0], operands[
1]);
2681 [(set_attr "move_type" "mgtf,fpload")
2682 (set_attr "mode" "<HALFMODE>")])
2684 ;; Store one word of operand
1 in operand
0. Operand
2 is
1 to store the
2685 ;; high word and
0 to store the low word.
2686 (define_insn "store_word<mode>"
2687 [(set (match_operand:<HALFMODE>
0 "nonimmediate_operand" "=r,m")
2688 (unspec:<HALFMODE> [(match_operand:SPLITF
1 "register_operand" "f,f")
2689 (match_operand
2 "const_int_operand")]
2690 UNSPEC_STORE_WORD))]
2693 operands[
1] = loongarch_subword (operands[
1], INTVAL (operands[
2]));
2694 return loongarch_output_move (operands[
0], operands[
1]);
2696 [(set_attr "move_type" "mftg,fpstore")
2697 (set_attr "mode" "<HALFMODE>")])
2699 ;; Thread-Local Storage
2701 (define_insn "@load_tls<mode>"
2702 [(set (match_operand:P
0 "register_operand" "=r")
2704 [(match_operand:P
1 "symbolic_operand" "")]
2708 enum loongarch_symbol_type symbol_type;
2709 gcc_assert (loongarch_symbolic_constant_p (operands[
1], &symbol_type));
2711 switch (symbol_type)
2714 return "la.tls.le
\t%
0,%
1";
2716 return "la.tls.ie
\t%
0,%
1";
2718 return "la.tls.ld
\t%
0,%
1";
2720 return "la.tls.gd
\t%
0,%
1";
2726 [(set_attr "mode" "<MODE>")
2727 (set_attr "insn_count" "
2")])
2729 ;; Move operand
1 to the high word of operand
0 using movgr2frh.w, preserving the
2730 ;; value in the low word.
2731 (define_insn "movgr2frh<mode>"
2732 [(set (match_operand:SPLITF
0 "register_operand" "=f")
2733 (unspec:SPLITF [(match_operand:<HALFMODE>
1 "reg_or_0_operand" "rJ")
2734 (match_operand:SPLITF
2 "register_operand" "
0")]
2736 "TARGET_DOUBLE_FLOAT"
2737 "movgr2frh.w
\t%z1,%
0"
2738 [(set_attr "move_type" "mgtf")
2739 (set_attr "mode" "<HALFMODE>")])
2741 ;; Move high word of operand
1 to operand
0 using movfrh2gr.s.
2742 (define_insn "movfrh2gr<mode>"
2743 [(set (match_operand:<HALFMODE>
0 "register_operand" "=r")
2744 (unspec:<HALFMODE> [(match_operand:SPLITF
1 "register_operand" "f")]
2746 "TARGET_DOUBLE_FLOAT"
2747 "movfrh2gr.s
\t%
0,%
1"
2748 [(set_attr "move_type" "mftg")
2749 (set_attr "mode" "<HALFMODE>")])
2752 ;; Expand in-line code to clear the instruction cache between operand[
0] and
2754 (define_expand "clear_cache"
2755 [(match_operand
0 "pmode_register_operand")
2756 (match_operand
1 "pmode_register_operand")]
2759 emit_insn (gen_loongarch_ibar (const0_rtx));
2763 (define_insn "loongarch_ibar"
2764 [(unspec_volatile:SI
2765 [(match_operand
0 "const_uimm15_operand")]
2767 (clobber (mem:BLK (scratch)))]
2771 (define_insn "loongarch_dbar"
2772 [(unspec_volatile:SI
2773 [(match_operand
0 "const_uimm15_operand")]
2775 (clobber (mem:BLK (scratch)))]
2781 ;; Privileged state instruction
2783 (define_insn "loongarch_cpucfg"
2784 [(set (match_operand:SI
0 "register_operand" "=r")
2785 (unspec_volatile:SI [(match_operand:SI
1 "register_operand" "r")]
2789 [(set_attr "type" "load")
2790 (set_attr "mode" "SI")])
2792 (define_insn "loongarch_syscall"
2793 [(unspec_volatile:SI
2794 [(match_operand
0 "const_uimm15_operand")]
2796 (clobber (mem:BLK (scratch)))]
2800 (define_insn "loongarch_break"
2801 [(unspec_volatile:SI
2802 [(match_operand
0 "const_uimm15_operand")]
2804 (clobber (mem:BLK (scratch)))]
2808 (define_insn "loongarch_asrtle_d"
2809 [(unspec_volatile:DI [(match_operand:DI
0 "register_operand" "r")
2810 (match_operand:DI
1 "register_operand" "r")]
2814 [(set_attr "type" "load")
2815 (set_attr "mode" "DI")])
2817 (define_insn "loongarch_asrtgt_d"
2818 [(unspec_volatile:DI [(match_operand:DI
0 "register_operand" "r")
2819 (match_operand:DI
1 "register_operand" "r")]
2823 [(set_attr "type" "load")
2824 (set_attr "mode" "DI")])
2826 (define_insn "loongarch_csrrd_<d>"
2827 [(set (match_operand:GPR
0 "register_operand" "=r")
2828 (unspec_volatile:GPR [(match_operand
1 "const_uimm14_operand")]
2830 (clobber (mem:BLK (scratch)))]
2833 [(set_attr "type" "load")
2834 (set_attr "mode" "<MODE>")])
2836 (define_insn "loongarch_csrwr_<d>"
2837 [(set (match_operand:GPR
0 "register_operand" "=r")
2838 (unspec_volatile:GPR
2839 [(match_operand:GPR
1 "register_operand" "
0")
2840 (match_operand
2 "const_uimm14_operand")]
2842 (clobber (mem:BLK (scratch)))]
2845 [(set_attr "type" "store")
2846 (set_attr "mode" "<MODE>")])
2848 (define_insn "loongarch_csrxchg_<d>"
2849 [(set (match_operand:GPR
0 "register_operand" "=r")
2850 (unspec_volatile:GPR
2851 [(match_operand:GPR
1 "register_operand" "
0")
2852 (match_operand:GPR
2 "register_operand" "q")
2853 (match_operand
3 "const_uimm14_operand")]
2855 (clobber (mem:BLK (scratch)))]
2858 [(set_attr "type" "load")
2859 (set_attr "mode" "<MODE>")])
2861 (define_insn "loongarch_iocsrrd_<size>"
2862 [(set (match_operand:QHWD
0 "register_operand" "=r")
2863 (unspec_volatile:QHWD [(match_operand:SI
1 "register_operand" "r")]
2865 (clobber (mem:BLK (scratch)))]
2867 "iocsrrd.<size>
\t%
0,%
1"
2868 [(set_attr "type" "load")
2869 (set_attr "mode" "<MODE>")])
2871 (define_insn "loongarch_iocsrwr_<size>"
2872 [(unspec_volatile:QHWD [(match_operand:QHWD
0 "register_operand" "r")
2873 (match_operand:SI
1 "register_operand" "r")]
2875 (clobber (mem:BLK (scratch)))]
2877 "iocsrwr.<size>
\t%
0,%
1"
2878 [(set_attr "type" "load")
2879 (set_attr "mode" "<MODE>")])
2881 (define_insn "loongarch_cacop_<d>"
2882 [(unspec_volatile:X [(match_operand
0 "const_uimm5_operand")
2883 (match_operand:X
1 "register_operand" "r")
2884 (match_operand
2 "const_imm12_operand")]
2886 (clobber (mem:BLK (scratch)))]
2889 [(set_attr "type" "load")
2890 (set_attr "mode" "<MODE>")])
2892 (define_insn "loongarch_lddir_<d>"
2893 [(unspec_volatile:X [(match_operand:X
0 "register_operand" "r")
2894 (match_operand:X
1 "register_operand" "r")
2895 (match_operand
2 "const_uimm5_operand")]
2897 (clobber (mem:BLK (scratch)))]
2900 [(set_attr "type" "load")
2901 (set_attr "mode" "<MODE>")])
2903 (define_insn "loongarch_ldpte_<d>"
2904 [(unspec_volatile:X [(match_operand:X
0 "register_operand" "r")
2905 (match_operand
1 "const_uimm5_operand")]
2907 (clobber (mem:BLK (scratch)))]
2910 [(set_attr "type" "load")
2911 (set_attr "mode" "<MODE>")])
2914 ;; Block moves, see loongarch.c for more details.
2915 ;; Argument
0 is the destination.
2916 ;; Argument
1 is the source.
2917 ;; Argument
2 is the length.
2918 ;; Argument
3 is the alignment.
2920 (define_expand "cpymemsi"
2921 [(parallel [(set (match_operand:BLK
0 "general_operand")
2922 (match_operand:BLK
1 "general_operand"))
2923 (use (match_operand:SI
2 ""))
2924 (use (match_operand:SI
3 "const_int_operand"))])]
2927 if (TARGET_DO_OPTIMIZE_BLOCK_MOVE_P
2928 && loongarch_expand_block_move (operands[
0], operands[
1],
2929 operands[
2], operands[
3]))
2936 ;; ....................
2940 ;; ....................
2942 (define_insn "<optab><mode>
3"
2943 [(set (match_operand:GPR
0 "register_operand" "=r")
2944 (any_shift:GPR (match_operand:GPR
1 "register_operand" "r")
2945 (match_operand:SI
2 "arith_operand" "rI")))]
2948 if (CONST_INT_P (operands[
2]))
2949 operands[
2] = GEN_INT (INTVAL (operands[
2])
2950 & (GET_MODE_BITSIZE (<MODE>mode) -
1));
2952 return "<insn>%i2.<d>
\t%
0,%
1,%
2";
2954 [(set_attr "type" "shift")
2955 (set_attr "mode" "<MODE>")])
2957 (define_insn "*<optab>si3_extend"
2958 [(set (match_operand:DI
0 "register_operand" "=r")
2960 (any_shift:SI (match_operand:SI
1 "register_operand" "r")
2961 (match_operand:SI
2 "arith_operand" "rI"))))]
2964 if (CONST_INT_P (operands[
2]))
2965 operands[
2] = GEN_INT (INTVAL (operands[
2]) &
0x1f);
2967 return "<insn>%i2.w
\t%
0,%
1,%
2";
2969 [(set_attr "type" "shift")
2970 (set_attr "mode" "SI")])
2972 (define_insn "rotr<mode>
3"
2973 [(set (match_operand:GPR
0 "register_operand" "=r,r")
2974 (rotatert:GPR (match_operand:GPR
1 "register_operand" "r,r")
2975 (match_operand:SI
2 "arith_operand" "r,I")))]
2977 "rotr%i2.<d>
\t%
0,%
1,%
2"
2978 [(set_attr "type" "shift,shift")
2979 (set_attr "mode" "<MODE>")])
2981 (define_insn "rotrsi3_extend"
2982 [(set (match_operand:DI
0 "register_operand" "=r,r")
2984 (rotatert:SI (match_operand:SI
1 "register_operand" "r,r")
2985 (match_operand:SI
2 "arith_operand" "r,I"))))]
2987 "rotr%i2.w
\t%
0,%
1,%
2"
2988 [(set_attr "type" "shift,shift")
2989 (set_attr "mode" "SI")])
2991 ;; Expand left rotate to right rotate.
2992 (define_expand "rotl<mode>
3"
2994 (neg:SI (match_operand:SI
2 "register_operand")))
2995 (set (match_operand:GPR
0 "register_operand")
2996 (rotatert:GPR (match_operand:GPR
1 "register_operand")
3000 operands[
3] = gen_reg_rtx (SImode);
3003 ;; The following templates were added to generate "bstrpick.d + alsl.d"
3004 ;; instruction pairs.
3005 ;; It is required that the values of const_immalsl_operand and
3006 ;; immediate_operand must have the following correspondence:
3008 ;; (immediate_operand >> const_immalsl_operand) ==
0xffffffff
3010 (define_insn "zero_extend_ashift"
3011 [(set (match_operand:DI
0 "register_operand" "=r")
3012 (and:DI (ashift:DI (match_operand:DI
1 "register_operand" "r")
3013 (match_operand
2 "const_immalsl_operand" ""))
3014 (match_operand
3 "immediate_operand" "")))]
3016 && ((INTVAL (operands[
3]) >> INTVAL (operands[
2])) ==
0xffffffff)"
3017 "bstrpick.d
\t%
0,%
1,
31,
0\n\talsl.d
\t%
0,%
0,$r0,%
2"
3018 [(set_attr "type" "arith")
3019 (set_attr "mode" "DI")
3020 (set_attr "insn_count" "
2")])
3022 (define_insn "bstrpick_alsl_paired"
3023 [(set (match_operand:DI
0 "register_operand" "=&r")
3024 (plus:DI (match_operand:DI
1 "register_operand" "r")
3025 (and:DI (ashift:DI (match_operand:DI
2 "register_operand" "r")
3026 (match_operand
3 "const_immalsl_operand" ""))
3027 (match_operand
4 "immediate_operand" ""))))]
3029 && ((INTVAL (operands[
4]) >> INTVAL (operands[
3])) ==
0xffffffff)"
3030 "bstrpick.d
\t%
0,%
2,
31,
0\n\talsl.d
\t%
0,%
0,%
1,%
3"
3031 [(set_attr "type" "arith")
3032 (set_attr "mode" "DI")
3033 (set_attr "insn_count" "
2")])
3035 (define_insn "alsl<mode>
3"
3036 [(set (match_operand:GPR
0 "register_operand" "=r")
3037 (plus:GPR (ashift:GPR (match_operand:GPR
1 "register_operand" "r")
3038 (match_operand
2 "const_immalsl_operand" ""))
3039 (match_operand:GPR
3 "register_operand" "r")))]
3041 "alsl.<d>
\t%
0,%
1,%
3,%
2"
3042 [(set_attr "type" "arith")
3043 (set_attr "mode" "<MODE>")])
3045 (define_insn "alslsi3_extend"
3046 [(set (match_operand:DI
0 "register_operand" "=r")
3049 (ashift:SI (match_operand:SI
1 "register_operand" "r")
3050 (match_operand
2 "const_immalsl_operand" ""))
3051 (match_operand:SI
3 "register_operand" "r"))))]
3053 "alsl.w
\t%
0,%
1,%
3,%
2"
3054 [(set_attr "type" "arith")
3055 (set_attr "mode" "SI")])
3059 ;; Reverse the order of bytes of operand
1 and store the result in operand
0.
3061 (define_insn "bswaphi2"
3062 [(set (match_operand:HI
0 "register_operand" "=r")
3063 (bswap:HI (match_operand:HI
1 "register_operand" "r")))]
3066 [(set_attr "type" "shift")])
3068 (define_insn_and_split "bswapsi2"
3069 [(set (match_operand:SI
0 "register_operand" "=r")
3070 (bswap:SI (match_operand:SI
1 "register_operand" "r")))]
3074 [(set (match_dup
0) (unspec:SI [(match_dup
1)] UNSPEC_REVB_2H))
3075 (set (match_dup
0) (rotatert:SI (match_dup
0) (const_int
16)))]
3077 [(set_attr "insn_count" "
2")])
3079 (define_insn_and_split "bswapdi2"
3080 [(set (match_operand:DI
0 "register_operand" "=r")
3081 (bswap:DI (match_operand:DI
1 "register_operand" "r")))]
3085 [(set (match_dup
0) (unspec:DI [(match_dup
1)] UNSPEC_REVB_4H))
3086 (set (match_dup
0) (unspec:DI [(match_dup
0)] UNSPEC_REVH_D))]
3088 [(set_attr "insn_count" "
2")])
3090 (define_insn "revb_2h"
3091 [(set (match_operand:SI
0 "register_operand" "=r")
3092 (unspec:SI [(match_operand:SI
1 "register_operand" "r")] UNSPEC_REVB_2H))]
3095 [(set_attr "type" "shift")])
3097 (define_insn "revb_4h"
3098 [(set (match_operand:DI
0 "register_operand" "=r")
3099 (unspec:DI [(match_operand:DI
1 "register_operand" "r")] UNSPEC_REVB_4H))]
3102 [(set_attr "type" "shift")])
3104 (define_insn "revh_d"
3105 [(set (match_operand:DI
0 "register_operand" "=r")
3106 (unspec:DI [(match_operand:DI
1 "register_operand" "r")] UNSPEC_REVH_D))]
3109 [(set_attr "type" "shift")])
3112 ;; ....................
3114 ;; CONDITIONAL BRANCHES
3116 ;; ....................
3118 ;; Conditional branches
3120 (define_insn "*branch_fp_FCCmode"
3123 (match_operator
1 "equality_operator"
3124 [(match_operand:FCC
2 "register_operand" "z")
3126 (label_ref (match_operand
0 "" ""))
3130 return loongarch_output_conditional_branch (insn, operands,
3131 LARCH_BRANCH ("b%F1", "%Z2%
0"),
3132 LARCH_BRANCH ("b%W1", "%Z2%
0"));
3134 [(set_attr "type" "branch")])
3136 (define_insn "*branch_fp_inverted_FCCmode"
3139 (match_operator
1 "equality_operator"
3140 [(match_operand:FCC
2 "register_operand" "z")
3143 (label_ref (match_operand
0 "" ""))))]
3146 return loongarch_output_conditional_branch (insn, operands,
3147 LARCH_BRANCH ("b%W1", "%Z2%
0"),
3148 LARCH_BRANCH ("b%F1", "%Z2%
0"));
3150 [(set_attr "type" "branch")])
3152 ;; Conditional branches on ordered comparisons with zero.
3154 (define_insn "*branch_order<mode>"
3157 (match_operator
1 "order_operator"
3158 [(match_operand:X
2 "register_operand" "r,r")
3159 (match_operand:X
3 "reg_or_0_operand" "J,r")])
3160 (label_ref (match_operand
0 "" ""))
3163 { return loongarch_output_order_conditional_branch (insn, operands, false); }
3164 [(set_attr "type" "branch")])
3166 (define_insn "*branch_order<mode>_inverted"
3169 (match_operator
1 "order_operator"
3170 [(match_operand:X
2 "register_operand" "r,r")
3171 (match_operand:X
3 "reg_or_0_operand" "J,r")])
3173 (label_ref (match_operand
0 "" ""))))]
3175 { return loongarch_output_order_conditional_branch (insn, operands, true); }
3176 [(set_attr "type" "branch")])
3178 ;; Conditional branch on equality comparison.
3180 (define_insn "branch_equality<mode>"
3183 (match_operator
1 "equality_operator"
3184 [(match_operand:X
2 "register_operand" "r")
3185 (match_operand:X
3 "reg_or_0_operand" "rJ")])
3186 (label_ref (match_operand
0 "" ""))
3189 { return loongarch_output_equal_conditional_branch (insn, operands, false); }
3190 [(set_attr "type" "branch")])
3193 (define_insn "*branch_equality<mode>_inverted"
3196 (match_operator
1 "equality_operator"
3197 [(match_operand:X
2 "register_operand" "r")
3198 (match_operand:X
3 "reg_or_0_operand" "rJ")])
3200 (label_ref (match_operand
0 "" ""))))]
3202 { return loongarch_output_equal_conditional_branch (insn, operands, true); }
3203 [(set_attr "type" "branch")])
3206 ;; Branches operate on GRLEN-sized quantities, but for LoongArch64 we accept
3207 ;; QImode values so we can force zero-extension.
3208 (define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
3210 (define_expand "cbranch<mode>
4"
3212 (if_then_else (match_operator
0 "comparison_operator"
3213 [(match_operand:BR
1 "register_operand")
3214 (match_operand:BR
2 "nonmemory_operand")])
3215 (label_ref (match_operand
3 ""))
3219 loongarch_expand_conditional_branch (operands);
3223 (define_expand "cbranch<mode>
4"
3225 (if_then_else (match_operator
0 "comparison_operator"
3226 [(match_operand:ANYF
1 "register_operand")
3227 (match_operand:ANYF
2 "register_operand")])
3228 (label_ref (match_operand
3 ""))
3232 loongarch_expand_conditional_branch (operands);
3236 ;; Used to implement built-in functions.
3237 (define_expand "condjump"
3239 (if_then_else (match_operand
0)
3240 (label_ref (match_operand
1))
3245 ;; ....................
3247 ;; SETTING A REGISTER FROM A COMPARISON
3249 ;; ....................
3251 ;; Destination is always set in SI mode.
3253 (define_expand "cstore<mode>
4"
3254 [(set (match_operand:SI
0 "register_operand")
3255 (match_operator:SI
1 "loongarch_cstore_operator"
3256 [(match_operand:GPR
2 "register_operand")
3257 (match_operand:GPR
3 "nonmemory_operand")]))]
3260 loongarch_expand_scc (operands);
3264 (define_insn "*seq_zero_<X:mode><GPR:mode>"
3265 [(set (match_operand:GPR
0 "register_operand" "=r")
3266 (eq:GPR (match_operand:X
1 "register_operand" "r")
3270 [(set_attr "type" "slt")
3271 (set_attr "mode" "<X:MODE>")])
3274 (define_insn "*sne_zero_<X:mode><GPR:mode>"
3275 [(set (match_operand:GPR
0 "register_operand" "=r")
3276 (ne:GPR (match_operand:X
1 "register_operand" "r")
3280 [(set_attr "type" "slt")
3281 (set_attr "mode" "<X:MODE>")])
3283 (define_insn "*sgt<u>_<X:mode><GPR:mode>"
3284 [(set (match_operand:GPR
0 "register_operand" "=r")
3285 (any_gt:GPR (match_operand:X
1 "register_operand" "r")
3286 (match_operand:X
2 "reg_or_0_operand" "rJ")))]
3289 [(set_attr "type" "slt")
3290 (set_attr "mode" "<X:MODE>")])
3292 (define_insn "*sge<u>_<X:mode><GPR:mode>"
3293 [(set (match_operand:GPR
0 "register_operand" "=r")
3294 (any_ge:GPR (match_operand:X
1 "register_operand" "r")
3298 [(set_attr "type" "slt")
3299 (set_attr "mode" "<X:MODE>")])
3301 (define_insn "*slt<u>_<X:mode><GPR:mode>"
3302 [(set (match_operand:GPR
0 "register_operand" "=r")
3303 (any_lt:GPR (match_operand:X
1 "register_operand" "r")
3304 (match_operand:X
2 "arith_operand" "rI")))]
3306 "slt<u>%i2
\t%
0,%
1,%
2";
3307 [(set_attr "type" "slt")
3308 (set_attr "mode" "<X:MODE>")])
3310 (define_insn "*sle<u>_<X:mode><GPR:mode>"
3311 [(set (match_operand:GPR
0 "register_operand" "=r")
3312 (any_le:GPR (match_operand:X
1 "register_operand" "r")
3313 (match_operand:X
2 "sle_operand" "")))]
3316 operands[
2] = GEN_INT (INTVAL (operands[
2]) +
1);
3317 return "slt<u>i
\t%
0,%
1,%
2";
3319 [(set_attr "type" "slt")
3320 (set_attr "mode" "<X:MODE>")])
3324 ;; ....................
3326 ;; FLOATING POINT COMPARISONS
3328 ;; ....................
3330 (define_insn "s<code>_<ANYF:mode>_using_FCCmode"
3331 [(set (match_operand:FCC
0 "register_operand" "=z")
3332 (fcond:FCC (match_operand:ANYF
1 "register_operand" "f")
3333 (match_operand:ANYF
2 "register_operand" "f")))]
3335 "fcmp.<fcond>.<fmt>
\t%Z0%
1,%
2"
3336 [(set_attr "type" "fcmp")
3337 (set_attr "mode" "FCC")])
3341 ;; ....................
3343 ;; UNCONDITIONAL BRANCHES
3345 ;; ....................
3347 ;; Unconditional branches.
3349 (define_expand "jump"
3351 (label_ref (match_operand
0)))])
3353 (define_insn "*jump_absolute"
3355 (label_ref (match_operand
0)))]
3360 [(set_attr "type" "branch")])
3362 (define_insn "*jump_pic"
3364 (label_ref (match_operand
0)))]
3369 [(set_attr "type" "branch")])
3371 ;; Micro-architecture unconditionally treats a "jr $ra" as "return from subroutine",
3372 ;; non-returning indirect jumps through $ra would interfere with both subroutine
3373 ;; return prediction and the more general indirect branch prediction.
3375 (define_expand "indirect_jump"
3376 [(set (pc) (match_operand
0 "register_operand"))]
3379 operands[
0] = force_reg (Pmode, operands[
0]);
3380 emit_jump_insn (gen_indirect_jump (Pmode, operands[
0]));
3384 (define_insn "@indirect_jump<mode>"
3385 [(set (pc) (match_operand:P
0 "register_operand" "e"))]
3388 [(set_attr "type" "jump")
3389 (set_attr "mode" "none")])
3391 (define_expand "tablejump"
3393 (match_operand
0 "register_operand"))
3394 (use (label_ref (match_operand
1 "")))]
3398 operands[
0] = expand_simple_binop (Pmode, PLUS, operands[
0],
3399 gen_rtx_LABEL_REF (Pmode,
3401 NULL_RTX,
0, OPTAB_DIRECT);
3402 emit_jump_insn (gen_tablejump (Pmode, operands[
0], operands[
1]));
3406 (define_insn "@tablejump<mode>"
3408 (match_operand:P
0 "register_operand" "e"))
3409 (use (label_ref (match_operand
1 "" "")))]
3412 [(set_attr "type" "jump")
3413 (set_attr "mode" "none")])
3418 ;; ....................
3420 ;; Function prologue/epilogue
3422 ;; ....................
3425 (define_expand "prologue"
3429 loongarch_expand_prologue ();
3433 ;; Block any insns from being moved before this point, since the
3434 ;; profiling call to mcount can use various registers that aren't
3435 ;; saved or used to pass arguments.
3437 (define_insn "blockage"
3438 [(unspec_volatile [(const_int
0)] UNSPECV_BLOCKAGE)]
3441 [(set_attr "type" "ghost")
3442 (set_attr "mode" "none")])
3444 (define_insn "@probe_stack_range<P:mode>"
3445 [(set (match_operand:P
0 "register_operand" "=r")
3446 (unspec_volatile:P [(match_operand:P
1 "register_operand" "
0")
3447 (match_operand:P
2 "register_operand" "r")
3448 (match_operand:P
3 "register_operand" "r")]
3449 UNSPECV_PROBE_STACK_RANGE))]
3452 return loongarch_output_probe_stack_range (operands[
0],
3456 [(set_attr "type" "unknown")
3457 (set_attr "mode" "<MODE>")])
3459 (define_expand "epilogue"
3463 loongarch_expand_epilogue (NORMAL_RETURN);
3467 (define_expand "sibcall_epilogue"
3471 loongarch_expand_epilogue (SIBCALL_RETURN);
3475 ;; Trivial return. Make it look like a normal return insn as that
3476 ;; allows jump optimizations to work better.
3478 (define_expand "return"
3480 "loongarch_can_use_return_insn ()"
3483 (define_expand "simple_return"
3488 (define_insn "*<optab>"
3492 operands[
0] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
3495 [(set_attr "type" "jump")
3496 (set_attr "mode" "none")])
3500 (define_insn "<optab>_internal"
3502 (use (match_operand
0 "pmode_register_operand" ""))]
3505 [(set_attr "type" "jump")
3506 (set_attr "mode" "none")])
3508 ;; Exception return.
3509 (define_insn "loongarch_ertn"
3511 (unspec_volatile [(const_int
0)] UNSPECV_ERTN)]
3514 [(set_attr "type" "trap")
3515 (set_attr "mode" "none")])
3517 ;; This is used in compiling the unwind routines.
3518 (define_expand "eh_return"
3519 [(use (match_operand
0 "general_operand"))]
3522 if (GET_MODE (operands[
0]) != word_mode)
3523 operands[
0] = convert_to_mode (word_mode, operands[
0],
0);
3525 emit_insn (gen_eh_set_ra_di (operands[
0]));
3527 emit_insn (gen_eh_set_ra_si (operands[
0]));
3529 emit_jump_insn (gen_eh_return_internal ());
3534 (define_insn_and_split "eh_return_internal"
3538 "epilogue_completed"
3541 loongarch_expand_epilogue (EXCEPTION_RETURN);
3545 ;; Clobber the return address on the stack. We can't expand this
3546 ;; until we know where it will be put in the stack frame.
3548 (define_insn "eh_set_ra_si"
3549 [(unspec [(match_operand:SI
0 "register_operand" "r")] UNSPEC_EH_RETURN)
3550 (clobber (match_scratch:SI
1 "=&r"))]
3554 (define_insn "eh_set_ra_di"
3555 [(unspec [(match_operand:DI
0 "register_operand" "r")] UNSPEC_EH_RETURN)
3556 (clobber (match_scratch:DI
1 "=&r"))]
3561 [(unspec [(match_operand
0 "register_operand")] UNSPEC_EH_RETURN)
3562 (clobber (match_scratch
1))]
3566 loongarch_set_return_address (operands[
0], operands[
1]);
3573 ;; ....................
3577 ;; ....................
3579 ;; Sibling calls. All these patterns use jump instructions.
3581 (define_expand "sibcall"
3582 [(parallel [(call (match_operand
0 "")
3583 (match_operand
1 ""))
3584 (use (match_operand
2 "")) ;; next_arg_reg
3585 (use (match_operand
3 ""))])] ;; struct_value_size_rtx
3588 rtx target = loongarch_legitimize_call_address (XEXP (operands[
0],
0));
3590 if (GET_CODE (target) == LO_SUM)
3591 emit_call_insn (gen_sibcall_internal_1 (Pmode, XEXP (target,
0),
3596 rtx call = emit_call_insn (gen_sibcall_internal (target, operands[
1]));
3598 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3599 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3600 gen_rtx_REG (Pmode, T0_REGNUM));
3605 (define_insn "sibcall_internal"
3606 [(call (mem:SI (match_operand
0 "call_insn_operand" "j,c,b"))
3607 (match_operand
1 "" ""))]
3608 "SIBLING_CALL_P (insn)"
3610 switch (which_alternative)
3615 if (TARGET_CMODEL_MEDIUM)
3616 return "pcaddu18i
\t$r12,%%call36(%
0)
\n\tjirl
\t$r0,$r12,
0";
3620 if (TARGET_CMODEL_MEDIUM)
3621 return "pcaddu18i
\t$r12,%%call36(%
0)
\n\tjirl
\t$r0,$r12,
0";
3623 return "b
\t%%plt(%
0)";
3628 [(set_attr "jirl" "indirect,direct,direct")])
3630 (define_insn "@sibcall_internal_1<mode>"
3631 [(call (mem:P (lo_sum:P (match_operand:P
0 "register_operand" "j")
3632 (match_operand:P
1 "symbolic_operand" "")))
3633 (match_operand
2 "" ""))]
3634 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3635 "jirl
\t$r0,%
0,%%pc_lo12(%
1)"
3636 [(set_attr "jirl" "indirect")])
3638 (define_expand "sibcall_value"
3639 [(parallel [(set (match_operand
0 "")
3640 (call (match_operand
1 "")
3641 (match_operand
2 "")))
3642 (use (match_operand
3 ""))])] ;; next_arg_reg
3645 rtx target = loongarch_legitimize_call_address (XEXP (operands[
1],
0));
3647 /* Handle return values created by loongarch_pass_fpr_pair. */
3648 if (GET_CODE (operands[
0]) == PARALLEL && XVECLEN (operands[
0],
0) ==
2)
3650 rtx arg1 = XEXP (XVECEXP (operands[
0],
0,
0),
0);
3651 rtx arg2 = XEXP (XVECEXP (operands[
0],
0,
1),
0);
3653 if (GET_CODE (target) == LO_SUM)
3654 emit_call_insn (gen_sibcall_value_multiple_internal_1 (Pmode, arg1,
3662 = emit_call_insn (gen_sibcall_value_multiple_internal (arg1,
3667 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3668 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3669 gen_rtx_REG (Pmode, T0_REGNUM));
3674 /* Handle return values created by loongarch_return_fpr_single. */
3675 if (GET_CODE (operands[
0]) == PARALLEL && XVECLEN (operands[
0],
0) ==
1)
3676 operands[
0] = XEXP (XVECEXP (operands[
0],
0,
0),
0);
3678 if (GET_CODE (target) == LO_SUM)
3679 emit_call_insn (gen_sibcall_value_internal_1 (Pmode, operands[
0],
3685 rtx call = emit_call_insn (gen_sibcall_value_internal (operands[
0],
3689 if (TARGET_CMODEL_MEDIUM && !REG_P (target))
3690 clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
3691 gen_rtx_REG (Pmode, T0_REGNUM));
3697 (define_insn "sibcall_value_internal"
3698 [(set (match_operand
0 "register_operand" "")
3699 (call (mem:SI (match_operand
1 "call_insn_operand" "j,c,b"))
3700 (match_operand
2 "" "")))]
3701 "SIBLING_CALL_P (insn)"
3703 switch (which_alternative)
3708 if (TARGET_CMODEL_MEDIUM)
3709 return "pcaddu18i
\t$r12,%%call36(%
1)
\n\tjirl
\t$r0,$r12,
0";
3713 if (TARGET_CMODEL_MEDIUM)
3714 return "pcaddu18i
\t$r12,%%call36(%
1)
\n\tjirl
\t$r0,$r12,
0";
3716 return "b
\t%%plt(%
1)";
3721 [(set_attr "jirl" "indirect,direct,direct")])
3723 (define_insn "@sibcall_value_internal_1<mode>"
3724 [(set (match_operand
0 "register_operand" "")
3725 (call (mem:P (lo_sum:P (match_operand:P
1 "register_operand" "j")
3726 (match_operand:P
2 "symbolic_operand" "")))
3727 (match_operand
3 "" "")))]
3728 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3729 "jirl
\t$r0,%
1,%%pc_lo12(%
2)"
3730 [(set_attr "jirl" "indirect")])
3732 (define_insn "sibcall_value_multiple_internal"
3733 [(set (match_operand
0 "register_operand" "")
3734 (call (mem:SI (match_operand
1 "call_insn_operand" "j,c,b"))
3735 (match_operand
2 "" "")))
3736 (set (match_operand
3 "register_operand" "")
3737 (call (mem:SI (match_dup
1))
3739 "SIBLING_CALL_P (insn)"
3741 switch (which_alternative)
3746 if (TARGET_CMODEL_MEDIUM)
3747 return "pcaddu18i
\t$r12,%%call36(%
1)
\n\tjirl
\t$r0,$r12,
0";
3751 if (TARGET_CMODEL_MEDIUM)
3752 return "pcaddu18i
\t$r12,%%call36(%
1)
\n\tjirl
\t$r0,$r12,
0";
3754 return "b
\t%%plt(%
1)";
3759 [(set_attr "jirl" "indirect,direct,direct")])
3761 (define_insn "@sibcall_value_multiple_internal_1<mode>"
3762 [(set (match_operand
0 "register_operand" "")
3763 (call (mem:P (unspec:P [(match_operand:P
1 "register_operand" "j")
3764 (match_operand:P
2 "symbolic_operand" "")]
3765 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3766 (match_operand
3 "" "")))
3767 (set (match_operand
4 "register_operand" "")
3768 (call (mem:P (unspec:P [(match_dup
1)
3770 UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1))
3772 "SIBLING_CALL_P (insn) && TARGET_CMODEL_MEDIUM"
3773 "jirl
\t$r0,%
1,%%pc_lo12(%
2)"
3774 [(set_attr "jirl" "indirect")])
3776 (define_expand "call"
3777 [(parallel [(call (match_operand
0 "")
3778 (match_operand
1 ""))
3779 (use (match_operand
2 "")) ;; next_arg_reg
3780 (use (match_operand
3 ""))])] ;; struct_value_size_rtx
3783 rtx target = loongarch_legitimize_call_address (XEXP (operands[
0],
0));
3785 if (GET_CODE (target) == LO_SUM)
3786 emit_call_insn (gen_call_internal_1 (Pmode, XEXP (target,
0),
3787 XEXP (target,
1), operands[
1]));
3789 emit_call_insn (gen_call_internal (target, operands[
1]));
3793 (define_insn "call_internal"
3794 [(call (mem:SI (match_operand
0 "call_insn_operand" "e,c,b"))
3795 (match_operand
1 "" ""))
3796 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3799 switch (which_alternative)
3802 return "jirl
\t$r1,%
0,
0";
3804 if (TARGET_CMODEL_MEDIUM)
3805 return "pcaddu18i
\t$r1,%%call36(%
0)
\n\tjirl
\t$r1,$r1,
0";
3809 if (TARGET_CMODEL_MEDIUM)
3810 return "pcaddu18i
\t$r1,%%call36(%
0)
\n\tjirl
\t$r1,$r1,
0";
3812 return "bl
\t%%plt(%
0)";
3817 [(set_attr "jirl" "indirect,direct,direct")])
3819 (define_insn "@call_internal_1<mode>"
3820 [(call (mem:P (lo_sum:P (match_operand:P
0 "register_operand" "j")
3821 (match_operand:P
1 "symbolic_operand" "")))
3822 (match_operand
2 "" ""))
3823 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3824 "TARGET_CMODEL_MEDIUM"
3825 "jirl
\t$r1,%
0,%%pc_lo12(%
1)"
3826 [(set_attr "jirl" "indirect")])
3828 (define_expand "call_value"
3829 [(parallel [(set (match_operand
0 "")
3830 (call (match_operand
1 "")
3831 (match_operand
2 "")))
3832 (use (match_operand
3 ""))])] ;; next_arg_reg
3835 rtx target = loongarch_legitimize_call_address (XEXP (operands[
1],
0));
3836 /* Handle return values created by loongarch_pass_fpr_pair. */
3837 if (GET_CODE (operands[
0]) == PARALLEL && XVECLEN (operands[
0],
0) ==
2)
3839 rtx arg1 = XEXP (XVECEXP (operands[
0],
0,
0),
0);
3840 rtx arg2 = XEXP (XVECEXP (operands[
0],
0,
1),
0);
3842 if (GET_CODE (target) == LO_SUM)
3843 emit_call_insn (gen_call_value_multiple_internal_1 (Pmode, arg1,
3846 operands[
2], arg2));
3848 emit_call_insn (gen_call_value_multiple_internal (arg1, target,
3849 operands[
2], arg2));
3853 /* Handle return values created by loongarch_return_fpr_single. */
3854 if (GET_CODE (operands[
0]) == PARALLEL && XVECLEN (operands[
0],
0) ==
1)
3855 operands[
0] = XEXP (XVECEXP (operands[
0],
0,
0),
0);
3857 if (GET_CODE (target) == LO_SUM)
3858 emit_call_insn (gen_call_value_internal_1 (Pmode, operands[
0],
3863 emit_call_insn (gen_call_value_internal (operands[
0], target,
3869 (define_insn "call_value_internal"
3870 [(set (match_operand
0 "register_operand" "")
3871 (call (mem:SI (match_operand
1 "call_insn_operand" "e,c,b"))
3872 (match_operand
2 "" "")))
3873 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3876 switch (which_alternative)
3879 return "jirl
\t$r1,%
1,
0";
3881 if (TARGET_CMODEL_MEDIUM)
3882 return "pcaddu18i
\t$r1,%%call36(%
1)
\n\tjirl
\t$r1,$r1,
0";
3886 if (TARGET_CMODEL_MEDIUM)
3887 return "pcaddu18i
\t$r1,%%call36(%
1)
\n\tjirl
\t$r1,$r1,
0";
3889 return "bl
\t%%plt(%
1)";
3894 [(set_attr "jirl" "indirect,direct,direct")])
3896 (define_insn "@call_value_internal_1<mode>"
3897 [(set (match_operand
0 "register_operand" "")
3898 (call (mem:P (lo_sum:P (match_operand:P
1 "register_operand" "j")
3899 (match_operand:P
2 "symbolic_operand" "")))
3900 (match_operand
3 "" "")))
3901 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3902 "TARGET_CMODEL_MEDIUM"
3903 "jirl
\t$r1,%
1,%%pc_lo12(%
2)"
3904 [(set_attr "jirl" "indirect")])
3906 (define_insn "call_value_multiple_internal"
3907 [(set (match_operand
0 "register_operand" "")
3908 (call (mem:SI (match_operand
1 "call_insn_operand" "e,c,b"))
3909 (match_operand
2 "" "")))
3910 (set (match_operand
3 "register_operand" "")
3911 (call (mem:SI (match_dup
1))
3913 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3916 switch (which_alternative)
3919 return "jirl
\t$r1,%
1,
0";
3921 if (TARGET_CMODEL_MEDIUM)
3922 return "pcaddu18i
\t$r1,%%call36(%
1)
\n\tjirl
\t$r1,$r1,
0";
3926 if (TARGET_CMODEL_MEDIUM)
3927 return "pcaddu18i
\t$r1,%%call36(%
1)
\n\tjirl
\t$r1,$r1,
0";
3929 return "bl
\t%%plt(%
1)";
3934 [(set_attr "jirl" "indirect,direct,direct")])
3936 (define_insn "@call_value_multiple_internal_1<mode>"
3937 [(set (match_operand
0 "register_operand" "")
3938 (call (mem:P (unspec:P [(match_operand:P
1 "register_operand" "j")
3939 (match_operand:P
2 "symbolic_operand" "")]
3940 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3941 (match_operand
3 "" "")))
3942 (set (match_operand
4 "register_operand" "")
3943 (call (mem:P (unspec:P [(match_dup
1)
3945 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1))
3947 (clobber (reg:SI RETURN_ADDR_REGNUM))]
3948 "TARGET_CMODEL_MEDIUM"
3949 "jirl
\t$r1,%
1,%%pc_lo12(%
2)"
3950 [(set_attr "jirl" "indirect")])
3953 ;; Call subroutine returning any type.
3954 (define_expand "untyped_call"
3955 [(parallel [(call (match_operand
0 "")
3957 (match_operand
1 "")
3958 (match_operand
2 "")])]
3963 emit_call_insn (gen_call (operands[
0], const0_rtx, NULL, const0_rtx));
3965 for (i =
0; i < XVECLEN (operands[
2],
0); i++)
3967 rtx set = XVECEXP (operands[
2],
0, i);
3968 loongarch_emit_move (SET_DEST (set), SET_SRC (set));
3971 emit_insn (gen_blockage ());
3976 ;; ....................
3980 ;; ....................
3983 (define_insn "prefetch"
3984 [(prefetch (match_operand
0 "address_operand" "ZD")
3985 (match_operand
1 "const_int_operand" "n")
3986 (match_operand
2 "const_int_operand" "n"))]
3989 switch (INTVAL (operands[
1]))
3991 case
0: return "preld
\t0,%a0";
3992 case
1: return "preld
\t8,%a0";
3993 default: gcc_unreachable ();
4001 [(set_attr "type" "nop")
4002 (set_attr "mode" "none")])
4004 ;; __builtin_loongarch_movfcsr2gr: move the FCSR into operand
0.
4005 (define_insn "loongarch_movfcsr2gr"
4006 [(set (match_operand:SI
0 "register_operand" "=r")
4007 (unspec_volatile:SI [(match_operand
1 "const_uimm5_operand")]
4008 UNSPECV_MOVFCSR2GR))]
4010 "movfcsr2gr
\t%
0,$r%
1")
4012 ;; __builtin_loongarch_movgr2fcsr: move operand
0 into the FCSR.
4013 (define_insn "loongarch_movgr2fcsr"
4014 [(unspec_volatile [(match_operand
0 "const_uimm5_operand")
4015 (match_operand:SI
1 "register_operand" "r")]
4016 UNSPECV_MOVGR2FCSR)]
4018 "movgr2fcsr
\t$r%
0,%
1")
4020 (define_insn "fclass_<fmt>"
4021 [(set (match_operand:ANYF
0 "register_operand" "=f")
4022 (unspec:ANYF [(match_operand:ANYF
1 "register_operand" "f")]
4025 "fclass.<fmt>
\t%
0,%
1"
4026 [(set_attr "type" "unknown")
4027 (set_attr "mode" "<MODE>")])
4029 (define_insn "bytepick_w_<bytepick_imm>"
4030 [(set (match_operand:SI
0 "register_operand" "=r")
4031 (ior:SI (lshiftrt (match_operand:SI
1 "register_operand" "r")
4032 (const_int <bytepick_w_lshiftrt_amount>))
4033 (ashift (match_operand:SI
2 "register_operand" "r")
4034 (const_int bytepick_w_ashift_amount))))]
4036 "bytepick.w
\t%
0,%
1,%
2,<bytepick_imm>"
4037 [(set_attr "mode" "SI")])
4039 (define_insn "bytepick_w_<bytepick_imm>_extend"
4040 [(set (match_operand:DI
0 "register_operand" "=r")
4043 (ior:DI (subreg:DI (lshiftrt
4044 (match_operand:SI
1 "register_operand" "r")
4045 (const_int <bytepick_w_lshiftrt_amount>))
0)
4047 (match_operand:SI
2 "register_operand" "r")
4048 (const_int bytepick_w_ashift_amount))
0))
0)))]
4050 "bytepick.w
\t%
0,%
1,%
2,<bytepick_imm>"
4051 [(set_attr "mode" "SI")])
4053 (define_insn "bytepick_d_<bytepick_imm>"
4054 [(set (match_operand:DI
0 "register_operand" "=r")
4055 (ior:DI (lshiftrt (match_operand:DI
1 "register_operand" "r")
4056 (const_int <bytepick_d_lshiftrt_amount>))
4057 (ashift (match_operand:DI
2 "register_operand" "r")
4058 (const_int bytepick_d_ashift_amount))))]
4060 "bytepick.d
\t%
0,%
1,%
2,<bytepick_imm>"
4061 [(set_attr "mode" "DI")])
4063 (define_insn "bitrev_4b"
4064 [(set (match_operand:SI
0 "register_operand" "=r")
4065 (unspec:SI [(match_operand:SI
1 "register_operand" "r")]
4069 [(set_attr "type" "unknown")
4070 (set_attr "mode" "SI")])
4072 (define_insn "bitrev_8b"
4073 [(set (match_operand:DI
0 "register_operand" "=r")
4074 (unspec:DI [(match_operand:DI
1 "register_operand" "r")]
4078 [(set_attr "type" "unknown")
4079 (set_attr "mode" "DI")])
4081 (define_insn "@stack_tie<mode>"
4082 [(set (mem:BLK (scratch))
4083 (unspec:BLK [(match_operand:X
0 "register_operand" "r")
4084 (match_operand:X
1 "register_operand" "r")]
4088 [(set_attr "length" "
0")
4089 (set_attr "type" "ghost")])
4091 ;; Named pattern for expanding thread pointer reference.
4092 (define_expand "get_thread_pointer<mode>"
4093 [(set (match_operand:P
0 "register_operand" "=r")
4099 [(match_operand
0 "small_data_pattern")]
4102 { operands[
0] = loongarch_rewrite_small_data (operands[
0]); })
4105 ;; Match paired HI/SI/SF/DFmode load/stores.
4106 (define_insn "*join2_load_store<JOIN_MODE:mode>"
4107 [(set (match_operand:JOIN_MODE
0 "nonimmediate_operand"
4109 (match_operand:JOIN_MODE
1 "nonimmediate_operand" "m,m,r,f,ZC,r"))
4110 (set (match_operand:JOIN_MODE
2 "nonimmediate_operand"
4112 (match_operand:JOIN_MODE
3 "nonimmediate_operand" "m,m,r,f,ZC,r"))]
4115 /* The load destination does not overlap the source. */
4116 gcc_assert (!reg_overlap_mentioned_p (operands[
0], operands[
1]));
4117 output_asm_insn (loongarch_output_move (operands[
0], operands[
1]),
4119 output_asm_insn (loongarch_output_move (operands[
2], operands[
3]),
4123 [(set_attr "move_type"
4124 "load,fpload,store,fpstore,load,store")
4125 (set_attr "insn_count" "
2,
2,
2,
2,
2,
2")])
4127 ;;
2 HI/SI/SF/DF loads are bonded.
4129 [(set (match_operand:JOIN_MODE
0 "register_operand")
4130 (match_operand:JOIN_MODE
1 "non_volatile_mem_operand"))
4131 (set (match_operand:JOIN_MODE
2 "register_operand")
4132 (match_operand:JOIN_MODE
3 "non_volatile_mem_operand"))]
4133 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, true)"
4134 [(parallel [(set (match_dup
0)
4140 ;;
2 HI/SI/SF/DF stores are bonded.
4142 [(set (match_operand:JOIN_MODE
0 "memory_operand")
4143 (match_operand:JOIN_MODE
1 "register_operand"))
4144 (set (match_operand:JOIN_MODE
2 "memory_operand")
4145 (match_operand:JOIN_MODE
3 "register_operand"))]
4146 "loongarch_load_store_bonding_p (operands, <JOIN_MODE:MODE>mode, false)"
4147 [(parallel [(set (match_dup
0)
4153 ;; Match paired HImode loads.
4154 (define_insn "*join2_loadhi"
4155 [(set (match_operand:SI
0 "register_operand" "=&r")
4156 (any_extend:SI (match_operand:HI
1 "non_volatile_mem_operand" "m")))
4157 (set (match_operand:SI
2 "register_operand" "=r")
4158 (any_extend:SI (match_operand:HI
3 "non_volatile_mem_operand" "m")))]
4161 /* The load destination does not overlap the source. */
4162 gcc_assert (!reg_overlap_mentioned_p (operands[
0], operands[
1]));
4163 output_asm_insn ("ld.h<u>
\t%
0,%
1", operands);
4164 output_asm_insn ("ld.h<u>
\t%
2,%
3", operands);
4168 [(set_attr "move_type" "load")
4169 (set_attr "insn_count" "
2")])
4172 ;;
2 HI loads are bonded.
4174 [(set (match_operand:SI
0 "register_operand")
4175 (any_extend:SI (match_operand:HI
1 "non_volatile_mem_operand")))
4176 (set (match_operand:SI
2 "register_operand")
4177 (any_extend:SI (match_operand:HI
3 "non_volatile_mem_operand")))]
4178 "loongarch_load_store_bonding_p (operands, HImode, true)"
4179 [(parallel [(set (match_dup
0)
4180 (any_extend:SI (match_dup
1)))
4182 (any_extend:SI (match_dup
3)))])]
4187 (define_mode_iterator QHSD [QI HI SI DI])
4189 (define_insn "loongarch_crc_w_<size>_w"
4190 [(set (match_operand:SI
0 "register_operand" "=r")
4191 (unspec:SI [(match_operand:QHSD
1 "register_operand" "r")
4192 (match_operand:SI
2 "register_operand" "r")]
4195 "crc.w.<size>.w
\t%
0,%
1,%
2"
4196 [(set_attr "type" "unknown")
4197 (set_attr "mode" "<MODE>")])
4199 (define_insn "loongarch_crcc_w_<size>_w"
4200 [(set (match_operand:SI
0 "register_operand" "=r")
4201 (unspec:SI [(match_operand:QHSD
1 "register_operand" "r")
4202 (match_operand:SI
2 "register_operand" "r")]
4205 "crcc.w.<size>.w
\t%
0,%
1,%
2"
4206 [(set_attr "type" "unknown")
4207 (set_attr "mode" "<MODE>")])
4209 ;; With normal or medium code models, if the only use of a pc-relative
4210 ;; address is for loading or storing a value, then relying on linker
4211 ;; relaxation is not better than emitting the machine instruction directly.
4212 ;; Even if the la.local pseudo op can be relaxed, we get:
4214 ;; pcaddi $t0, %pcrel_20(x)
4217 ;; There are still two instructions, same as using the machine instructions
4218 ;; and explicit relocs:
4220 ;; pcalau12i $t0, %pc_hi20(x)
4221 ;; ld.d $t0, $t0, %pc_lo12(x)
4223 ;; And if the pseudo op cannot be relaxed, we'll get a worse result (with
4225 (define_insn_and_rewrite "simple_load<mode>"
4226 [(set (match_operand:LD_AT_LEAST_32_BIT
0 "register_operand" "=r,f")
4227 (match_operand:LD_AT_LEAST_32_BIT
1 "mem_simple_ldst_operand" ""))]
4228 "loongarch_pre_reload_split ()
4229 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4230 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4234 operands[
1] = loongarch_rewrite_mem_for_simple_ldst (operands[
1]);
4237 (define_insn_and_rewrite "simple_load_<su>ext<SUBDI:mode><GPR:mode>"
4238 [(set (match_operand:GPR
0 "register_operand" "=r")
4240 (match_operand:SUBDI
1 "mem_simple_ldst_operand" "")))]
4241 "loongarch_pre_reload_split ()
4242 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4243 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4247 operands[
1] = loongarch_rewrite_mem_for_simple_ldst (operands[
1]);
4250 (define_insn_and_rewrite "simple_store<mode>"
4251 [(set (match_operand:ST_ANY
0 "mem_simple_ldst_operand" "")
4252 (match_operand:ST_ANY
1 "reg_or_0_operand" "r,f"))]
4253 "loongarch_pre_reload_split ()
4254 && la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO
4255 && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM)"
4259 operands[
0] = loongarch_rewrite_mem_for_simple_ldst (operands[
0]);
4262 ;; Synchronization instructions.
4266 (include "generic.md")
4267 (include "la464.md")
4269 ; The LoongArch SIMD Instructions.
4272 (define_c_enum "unspec" [
4273 UNSPEC_ADDRESS_FIRST