]>
Commit | Line | Data |
---|---|---|
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 | ]) |