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