]>
Commit | Line | Data |
---|---|---|
526b7aee | 1 | ;; Machine description of the Synopsys DesignWare ARC cpu for GNU C compiler |
5624e564 | 2 | ;; Copyright (C) 1994-2015 Free Software Foundation, Inc. |
526b7aee SV |
3 | |
4 | ;; Sources derived from work done by Sankhya Technologies (www.sankhya.com) on | |
5 | ;; behalf of Synopsys Inc. | |
6 | ||
7 | ;; Position Independent Code support added,Code cleaned up, | |
8 | ;; Comments and Support For ARC700 instructions added by | |
9 | ;; Saurabh Verma (saurabh.verma@codito.com) | |
10 | ;; Ramana Radhakrishnan(ramana.radhakrishnan@codito.com) | |
11 | ;; | |
12 | ;; Profiling support and performance improvements by | |
13 | ;; Joern Rennecke (joern.rennecke@embecosm.com) | |
14 | ;; | |
15 | ;; Support for DSP multiply instructions and mul64 | |
16 | ;; instructions for ARC600; and improvements in flag setting | |
17 | ;; instructions by | |
18 | ;; Muhammad Khurram Riaz (Khurram.Riaz@arc.com) | |
19 | ||
20 | ;; This file is part of GCC. | |
21 | ||
22 | ;; GCC is free software; you can redistribute it and/or modify | |
23 | ;; it under the terms of the GNU General Public License as published by | |
24 | ;; the Free Software Foundation; either version 3, or (at your option) | |
25 | ;; any later version. | |
26 | ||
27 | ;; GCC is distributed in the hope that it will be useful, | |
28 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
29 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
30 | ;; GNU General Public License for more details. | |
31 | ||
32 | ;; You should have received a copy of the GNU General Public License | |
33 | ;; along with GCC; see the file COPYING3. If not see | |
34 | ;; <http://www.gnu.org/licenses/>. | |
35 | ||
36 | ;; See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
37 | ||
38 | ;; <op> dest, src Two operand instruction's syntax | |
39 | ;; <op> dest, src1, src2 Three operand instruction's syntax | |
40 | ||
41 | ;; ARC and ARCompact PREDICATES: | |
42 | ;; | |
43 | ;; comparison_operator LT, GT, LE, GE, LTU, GTU, LEU, GEU, EQ, NE | |
44 | ;; memory_operand memory [m] | |
45 | ;; immediate_operand immediate constant [IKLMNOP] | |
46 | ;; register_operand register [rq] | |
47 | ;; general_operand register, memory, constant [rqmIKLMNOP] | |
48 | ||
49 | ;; Note that the predicates are only used when selecting a pattern | |
50 | ;; to determine if an operand is valid. | |
51 | ||
52 | ;; The constraints then select which of the possible valid operands | |
53 | ;; is present (and guide register selection). The actual assembly | |
54 | ;; instruction is then selected on the basis of the constraints. | |
55 | ||
56 | ;; ARC and ARCompact CONSTRAINTS: | |
57 | ;; | |
58 | ;; b stack pointer r28 | |
59 | ;; f frame pointer r27 | |
60 | ;; Rgp global pointer r26 | |
61 | ;; g general reg, memory, constant | |
62 | ;; m memory | |
63 | ;; p memory address | |
64 | ;; q registers commonly used in | |
65 | ;; 16-bit insns r0-r3, r12-r15 | |
66 | ;; c core registers r0-r60, ap, pcl | |
67 | ;; r general registers r0-r28, blink, ap, pcl | |
68 | ;; | |
69 | ;; H fp 16-bit constant | |
70 | ;; I signed 12-bit immediate (for ARCompact) | |
71 | ;; K unsigned 3-bit immediate (for ARCompact) | |
72 | ;; L unsigned 6-bit immediate (for ARCompact) | |
73 | ;; M unsinged 5-bit immediate (for ARCompact) | |
74 | ;; O unsinged 7-bit immediate (for ARCompact) | |
75 | ;; P unsinged 8-bit immediate (for ARCompact) | |
76 | ;; N constant '1' (for ARCompact) | |
77 | ||
78 | ||
79 | ;; TODO: | |
80 | ;; -> prefetch instruction | |
81 | ||
82 | ;; ----------------------------------------------------------------------------- | |
83 | ||
84 | ;; Include DFA scheduluers | |
85 | (include ("arc600.md")) | |
86 | (include ("arc700.md")) | |
87 | ||
88 | ;; Predicates | |
89 | ||
90 | (include ("predicates.md")) | |
91 | (include ("constraints.md")) | |
92 | ;; ----------------------------------------------------------------------------- | |
93 | ||
94 | ;; UNSPEC Usage: | |
95 | ;; ~~~~~~~~~~~~ | |
96 | ;; ----------------------------------------------------------------------------- | |
97 | ;; Symbolic name Value Desc. | |
98 | ;; ----------------------------------------------------------------------------- | |
99 | ;; UNSPEC_PLT 3 symbol to be referenced through the PLT | |
100 | ;; UNSPEC_GOT 4 symbol to be rerenced through the GOT | |
101 | ;; UNSPEC_GOTOFF 5 Local symbol.To be referenced relative to the | |
102 | ;; GOTBASE.(Referenced as @GOTOFF) | |
103 | ;; ---------------------------------------------------------------------------- | |
104 | ||
105 | ||
106 | (define_constants | |
107 | [(UNSPEC_SWAP 13) ; swap generation through builtins. candidate for scheduling | |
108 | (UNSPEC_MUL64 14) ; mul64 generation through builtins. candidate for scheduling | |
109 | (UNSPEC_MULU64 15) ; mulu64 generation through builtins. candidate for scheduling | |
110 | (UNSPEC_DIVAW 16) ; divaw generation through builtins. candidate for scheduling | |
111 | (UNSPEC_DIRECT 17) | |
112 | (UNSPEC_PROF 18) ; profile callgraph counter | |
113 | (UNSPEC_LP 19) ; to set LP_END | |
114 | (UNSPEC_CASESI 20) | |
115 | (VUNSPEC_RTIE 17) ; blockage insn for rtie generation | |
116 | (VUNSPEC_SYNC 18) ; blockage insn for sync generation | |
117 | (VUNSPEC_BRK 19) ; blockage insn for brk generation | |
118 | (VUNSPEC_FLAG 20) ; blockage insn for flag generation | |
119 | (VUNSPEC_SLEEP 21) ; blockage insn for sleep generation | |
120 | (VUNSPEC_SWI 22) ; blockage insn for swi generation | |
121 | (VUNSPEC_CORE_READ 23) ; blockage insn for reading a core register | |
122 | (VUNSPEC_CORE_WRITE 24) ; blockage insn for writing to a core register | |
123 | (VUNSPEC_LR 25) ; blockage insn for reading an auxiliary register | |
124 | (VUNSPEC_SR 26) ; blockage insn for writing to an auxiliary register | |
125 | (VUNSPEC_TRAP_S 27) ; blockage insn for trap_s generation | |
126 | (VUNSPEC_UNIMP_S 28) ; blockage insn for unimp_s generation | |
127 | ||
128 | (R0_REG 0) | |
129 | (R1_REG 1) | |
130 | (R2_REG 2) | |
131 | (R3_REG 3) | |
132 | (R12_REG 12) | |
133 | (SP_REG 28) | |
134 | (ILINK1_REGNUM 29) | |
135 | (ILINK2_REGNUM 30) | |
136 | (RETURN_ADDR_REGNUM 31) | |
137 | (MUL64_OUT_REG 58) | |
138 | ||
139 | (VUNSPEC_DEXCL 32) ; blockage insn for reading an auxiliary register without LR support | |
140 | (VUNSPEC_DEXCL_NORES 33) ; blockage insn for reading an auxiliary register without LR support | |
141 | (VUNSPEC_LR_HIGH 34) ; blockage insn for reading an auxiliary register | |
142 | ||
143 | (LP_COUNT 60) | |
144 | (CC_REG 61) | |
145 | (LP_START 144) | |
146 | (LP_END 145) | |
147 | ] | |
148 | ) | |
149 | ||
150 | (define_attr "is_sfunc" "no,yes" (const_string "no")) | |
151 | ||
152 | ;; Insn type. Used to default other attribute values. | |
153 | ; While the attribute is_sfunc is set for any call of a special function, | |
154 | ; the instruction type sfunc is used only for the special call sequence | |
155 | ; that loads the (pc-relative) function address into r12 and then calls | |
156 | ; via r12. | |
157 | ||
158 | (define_attr "type" | |
159 | "move,load,store,cmove,unary,binary,compare,shift,uncond_branch,jump,branch, | |
160 | brcc,brcc_no_delay_slot,call,sfunc,call_no_delay_slot, | |
161 | multi,umulti, two_cycle_core,lr,sr,divaw,loop_setup,loop_end,return, | |
162 | misc,spfp,dpfp_mult,dpfp_addsub,mulmac_600,cc_arith, | |
163 | simd_vload, simd_vload128, simd_vstore, simd_vmove, simd_vmove_else_zero, | |
164 | simd_vmove_with_acc, simd_varith_1cycle, simd_varith_2cycle, | |
165 | simd_varith_with_acc, simd_vlogic, simd_vlogic_with_acc, | |
166 | simd_vcompare, simd_vpermute, simd_vpack, simd_vpack_with_acc, | |
167 | simd_valign, simd_valign_with_acc, simd_vcontrol, | |
168 | simd_vspecial_3cycle, simd_vspecial_4cycle, simd_dma" | |
169 | (cond [(eq_attr "is_sfunc" "yes") | |
170 | (cond [(match_test "!TARGET_LONG_CALLS_SET && (!TARGET_MEDIUM_CALLS || GET_CODE (PATTERN (insn)) != COND_EXEC)") (const_string "call") | |
171 | (match_test "flag_pic") (const_string "sfunc")] | |
172 | (const_string "call_no_delay_slot"))] | |
173 | (const_string "binary"))) | |
174 | ||
175 | ;; The following three attributes are mixed case so that they can be | |
176 | ;; used conveniently with the CALL_ATTR macro. | |
177 | (define_attr "is_CALL" "no,yes" | |
178 | (cond [(eq_attr "is_sfunc" "yes") (const_string "yes") | |
179 | (eq_attr "type" "call,call_no_delay_slot") (const_string "yes")] | |
180 | (const_string "no"))) | |
181 | ||
182 | (define_attr "is_SIBCALL" "no,yes" (const_string "no")) | |
183 | ||
184 | (define_attr "is_NON_SIBCALL" "no,yes" | |
185 | (cond [(eq_attr "is_SIBCALL" "yes") (const_string "no") | |
186 | (eq_attr "is_CALL" "yes") (const_string "yes")] | |
187 | (const_string "no"))) | |
188 | ||
189 | ||
190 | ;; Attribute describing the processor | |
191 | (define_attr "cpu" "none,A5,ARC600,ARC700" | |
192 | (const (symbol_ref "arc_cpu_attr"))) | |
193 | ||
194 | ;; true for compact instructions (those with _s suffix) | |
195 | ;; "maybe" means compact unless we conditionalize the insn. | |
196 | (define_attr "iscompact" "true,maybe,true_limm,maybe_limm,false" | |
197 | (cond [(eq_attr "type" "sfunc") | |
198 | (const_string "maybe")] | |
199 | (const_string "false"))) | |
200 | ||
201 | ||
202 | ; Is there an instruction that we are actually putting into the delay slot? | |
203 | (define_attr "delay_slot_filled" "no,yes" | |
204 | (cond [(match_test "NEXT_INSN (PREV_INSN (insn)) == insn") | |
205 | (const_string "no") | |
206 | (match_test "!TARGET_AT_DBR_CONDEXEC | |
207 | && JUMP_P (insn) | |
208 | && INSN_ANNULLED_BRANCH_P (insn) | |
209 | && !INSN_FROM_TARGET_P (NEXT_INSN (insn))") | |
210 | (const_string "no")] | |
211 | (const_string "yes"))) | |
212 | ||
213 | ; Is a delay slot present for purposes of shorten_branches? | |
214 | ; We have to take the length of this insn into account for forward branches | |
215 | ; even if we don't put the insn actually into a delay slot. | |
216 | (define_attr "delay_slot_present" "no,yes" | |
217 | (cond [(match_test "NEXT_INSN (PREV_INSN (insn)) == insn") | |
218 | (const_string "no")] | |
219 | (const_string "yes"))) | |
220 | ||
221 | ; We can't use get_attr_length (NEXT_INSN (insn)) because this gives the | |
222 | ; length of a different insn with the same uid. | |
223 | (define_attr "delay_slot_length" "" | |
224 | (cond [(match_test "NEXT_INSN (PREV_INSN (insn)) == insn") | |
225 | (const_int 0)] | |
226 | (symbol_ref "get_attr_length (NEXT_INSN (PREV_INSN (insn))) | |
227 | - get_attr_length (insn)"))) | |
228 | ||
229 | ||
230 | (define_attr "enabled" "no,yes" (const_string "yes")) | |
231 | ||
232 | (define_attr "predicable" "no,yes" (const_string "no")) | |
233 | ;; if 'predicable' were not so brain-dead, we would specify: | |
234 | ;; (cond [(eq_attr "cond" "!canuse") (const_string "no") | |
235 | ;; (eq_attr "iscompact" "maybe") (const_string "no")] | |
236 | ;; (const_string "yes")) | |
237 | ;; and then for everything but calls, we could just set the cond attribute. | |
238 | ||
239 | ;; Condition codes: this one is used by final_prescan_insn to speed up | |
240 | ;; conditionalizing instructions. It saves having to scan the rtl to see if | |
241 | ;; it uses or alters the condition codes. | |
242 | ||
243 | ;; USE: This insn uses the condition codes (eg: a conditional branch). | |
244 | ;; CANUSE: This insn can use the condition codes (for conditional execution). | |
245 | ;; SET: All condition codes are set by this insn. | |
246 | ;; SET_ZN: the Z and N flags are set by this insn. | |
247 | ;; SET_ZNC: the Z, N, and C flags are set by this insn. | |
248 | ;; CLOB: The condition codes are set to unknown values by this insn. | |
249 | ;; NOCOND: This insn can't use and doesn't affect the condition codes. | |
250 | ||
251 | (define_attr "cond" "use,canuse,canuse_limm,canuse_limm_add,set,set_zn,clob,nocond" | |
252 | (cond | |
253 | [(and (eq_attr "predicable" "yes") | |
254 | (eq_attr "is_sfunc" "no") | |
255 | (eq_attr "delay_slot_filled" "no")) | |
256 | (const_string "canuse") | |
257 | ||
258 | (eq_attr "type" "call") | |
259 | (cond [(eq_attr "delay_slot_filled" "yes") (const_string "nocond") | |
260 | (match_test "!flag_pic") (const_string "canuse_limm")] | |
261 | (const_string "nocond")) | |
262 | ||
263 | (eq_attr "iscompact" "maybe,false") | |
264 | (cond [ (and (eq_attr "type" "move") | |
265 | (match_operand 1 "immediate_operand" "")) | |
266 | (if_then_else | |
267 | (ior (match_operand 1 "u6_immediate_operand" "") | |
268 | (match_operand 1 "long_immediate_operand" "")) | |
269 | (const_string "canuse") | |
270 | (const_string "canuse_limm")) | |
271 | ||
272 | (eq_attr "type" "binary") | |
273 | (cond [(ne (symbol_ref "REGNO (operands[0])") | |
274 | (symbol_ref "REGNO (operands[1])")) | |
275 | (const_string "nocond") | |
276 | (match_operand 2 "register_operand" "") | |
277 | (const_string "canuse") | |
278 | (match_operand 2 "u6_immediate_operand" "") | |
279 | (const_string "canuse") | |
280 | (match_operand 2 "long_immediate_operand" "") | |
281 | (const_string "canuse") | |
282 | (match_operand 2 "const_int_operand" "") | |
283 | (const_string "canuse_limm")] | |
284 | (const_string "nocond")) | |
285 | ||
286 | (eq_attr "type" "compare") | |
287 | (const_string "set") | |
288 | ||
289 | (eq_attr "type" "cmove,branch") | |
290 | (const_string "use") | |
291 | ||
292 | (eq_attr "is_sfunc" "yes") | |
293 | (cond [(match_test "(TARGET_MEDIUM_CALLS | |
294 | && !TARGET_LONG_CALLS_SET | |
295 | && flag_pic)") | |
296 | (const_string "canuse_limm_add") | |
297 | (match_test "(TARGET_MEDIUM_CALLS | |
298 | && !TARGET_LONG_CALLS_SET)") | |
299 | (const_string "canuse_limm")] | |
300 | (const_string "canuse")) | |
301 | ||
302 | ] | |
303 | ||
304 | (const_string "nocond"))] | |
305 | ||
306 | (cond [(eq_attr "type" "compare") | |
307 | (const_string "set") | |
308 | ||
309 | (eq_attr "type" "cmove,branch") | |
310 | (const_string "use") | |
311 | ||
312 | ] | |
313 | ||
314 | (const_string "nocond")))) | |
315 | ||
316 | /* ??? Having all these patterns gives ifcvt more freedom to generate | |
317 | inefficient code. It seem to operate on the premise that | |
318 | register-register copies and registers are free. I see better code | |
319 | with -fno-if-convert now than without. */ | |
320 | (define_cond_exec | |
321 | [(match_operator 0 "proper_comparison_operator" | |
322 | [(reg CC_REG) (const_int 0)])] | |
323 | "true" | |
324 | "") | |
325 | ||
326 | ;; Length (in # of bytes, long immediate constants counted too). | |
327 | ;; ??? There's a nasty interaction between the conditional execution fsm | |
328 | ;; and insn lengths: insns with shimm values cannot be conditionally executed. | |
329 | (define_attr "length" "" | |
330 | (cond | |
331 | [(eq_attr "iscompact" "true,maybe") | |
332 | (cond | |
333 | [(eq_attr "type" "sfunc") | |
334 | (cond [(match_test "GET_CODE (PATTERN (insn)) == COND_EXEC") | |
335 | (const_int 12)] | |
336 | (const_int 10)) | |
337 | (match_test "GET_CODE (PATTERN (insn)) == COND_EXEC") (const_int 4)] | |
338 | (const_int 2)) | |
339 | ||
340 | (eq_attr "iscompact" "true_limm,maybe_limm") | |
341 | (const_int 6) | |
342 | ||
343 | (eq_attr "type" "load") | |
344 | (if_then_else | |
345 | (match_operand 1 "long_immediate_loadstore_operand" "") | |
346 | (const_int 8) (const_int 4)) | |
347 | ||
348 | (eq_attr "type" "store") | |
349 | (if_then_else | |
350 | (ior (match_operand 0 "long_immediate_loadstore_operand" "") | |
351 | (match_operand 1 "immediate_operand" "")) | |
352 | (const_int 8) (const_int 4)) | |
353 | ||
354 | (eq_attr "type" "move,unary") | |
355 | (cond | |
356 | [(match_operand 1 "u6_immediate_operand" "") (const_int 4) | |
357 | (match_operand 1 "register_operand" "") (const_int 4) | |
358 | (match_operand 1 "long_immediate_operand" "") (const_int 8) | |
359 | (match_test "GET_CODE (PATTERN (insn)) == COND_EXEC") (const_int 8)] | |
360 | (const_int 4)) | |
361 | ||
362 | (and (eq_attr "type" "shift") | |
363 | (match_operand 1 "immediate_operand")) | |
364 | (const_int 8) | |
365 | (eq_attr "type" "binary,shift") | |
366 | (if_then_else | |
367 | (ior (match_operand 2 "long_immediate_operand" "") | |
368 | (and (ne (symbol_ref "REGNO (operands[0])") | |
369 | (symbol_ref "REGNO (operands[1])")) | |
370 | (eq (match_operand 2 "u6_immediate_operand" "") | |
371 | (const_int 0)))) | |
372 | ||
373 | (const_int 8) (const_int 4)) | |
374 | ||
375 | (eq_attr "type" "cmove") | |
376 | (if_then_else (match_operand 1 "register_operand" "") | |
377 | (const_int 4) (const_int 8)) | |
378 | ||
379 | (eq_attr "type" "call_no_delay_slot") (const_int 8) | |
380 | ] | |
381 | ||
382 | (const_int 4)) | |
383 | ) | |
384 | ||
385 | ;; The length here is the length of a single asm. Unfortunately it might be | |
386 | ;; 4 or 8 so we must allow for 8. That's ok though. How often will users | |
387 | ;; lament asm's not being put in delay slots? | |
388 | ;; | |
389 | (define_asm_attributes | |
390 | [(set_attr "length" "8") | |
391 | (set_attr "type" "multi") | |
392 | (set_attr "cond" "clob") ]) | |
393 | ||
394 | ;; Delay slots. | |
395 | ;; The first two cond clauses and the default are necessary for correctness; | |
396 | ;; the remaining cond clause is mainly an optimization, as otherwise nops | |
397 | ;; would be inserted; however, if we didn't do this optimization, we would | |
398 | ;; have to be more conservative in our length calculations. | |
399 | ||
400 | (define_attr "in_delay_slot" "false,true" | |
401 | (cond [(eq_attr "type" "uncond_branch,jump,branch, | |
402 | call,sfunc,call_no_delay_slot, | |
403 | brcc, brcc_no_delay_slot,loop_setup,loop_end") | |
404 | (const_string "false") | |
405 | (match_test "arc_write_ext_corereg (insn)") | |
406 | (const_string "false") | |
407 | (gt (symbol_ref "arc_hazard (prev_active_insn (insn), | |
408 | next_active_insn (insn))") | |
409 | (symbol_ref "(arc_hazard (prev_active_insn (insn), insn) | |
410 | + arc_hazard (insn, next_active_insn (insn)))")) | |
411 | (const_string "false") | |
412 | (eq_attr "iscompact" "maybe") (const_string "true") | |
413 | ] | |
414 | ||
415 | (if_then_else (eq_attr "length" "2,4") | |
416 | (const_string "true") | |
417 | (const_string "false")))) | |
418 | ||
419 | ; must not put an insn inside that refers to blink. | |
420 | (define_attr "in_call_delay_slot" "false,true" | |
421 | (cond [(eq_attr "in_delay_slot" "false") | |
422 | (const_string "false") | |
423 | (match_test "arc_regno_use_in (RETURN_ADDR_REGNUM, PATTERN (insn))") | |
424 | (const_string "false")] | |
425 | (const_string "true"))) | |
426 | ||
427 | (define_attr "in_sfunc_delay_slot" "false,true" | |
428 | (cond [(eq_attr "in_call_delay_slot" "false") | |
429 | (const_string "false") | |
430 | (match_test "arc_regno_use_in (12, PATTERN (insn))") | |
431 | (const_string "false")] | |
432 | (const_string "true"))) | |
433 | ||
434 | ;; Instructions that we can put into a delay slot and conditionalize. | |
435 | (define_attr "cond_delay_insn" "no,yes" | |
436 | (cond [(eq_attr "cond" "!canuse") (const_string "no") | |
437 | (eq_attr "type" "call,branch,uncond_branch,jump,brcc") | |
438 | (const_string "no") | |
439 | (eq_attr "length" "2,4") (const_string "yes")] | |
440 | (const_string "no"))) | |
441 | ||
442 | (define_attr "in_ret_delay_slot" "no,yes" | |
443 | (cond [(eq_attr "in_delay_slot" "false") | |
444 | (const_string "no") | |
445 | (match_test "regno_clobbered_p | |
446 | (arc_return_address_regs | |
447 | [arc_compute_function_type (cfun)], | |
448 | insn, SImode, 1)") | |
449 | (const_string "no")] | |
450 | (const_string "yes"))) | |
451 | ||
452 | (define_attr "cond_ret_delay_insn" "no,yes" | |
453 | (cond [(eq_attr "in_ret_delay_slot" "no") (const_string "no") | |
454 | (eq_attr "cond_delay_insn" "no") (const_string "no")] | |
455 | (const_string "yes"))) | |
456 | ||
457 | (define_attr "annul_ret_delay_insn" "no,yes" | |
458 | (cond [(eq_attr "cond_ret_delay_insn" "yes") (const_string "yes") | |
459 | (match_test "TARGET_AT_DBR_CONDEXEC") (const_string "no") | |
460 | (eq_attr "type" "!call,branch,uncond_branch,jump,brcc,return,sfunc") | |
461 | (const_string "yes")] | |
462 | (const_string "no"))) | |
463 | ||
464 | ||
465 | ;; Delay slot definition for ARCompact ISA | |
466 | ;; ??? FIXME: | |
467 | ;; When outputting an annul-true insn elegible for cond-exec | |
468 | ;; in a cbranch delay slot, unless optimizing for size, we use cond-exec | |
469 | ;; for ARC600; we could also use this for ARC700 if the branch can't be | |
470 | ;; unaligned and is at least somewhat likely (add parameter for this). | |
471 | ||
472 | (define_delay (eq_attr "type" "call") | |
473 | [(eq_attr "in_call_delay_slot" "true") | |
474 | (eq_attr "in_call_delay_slot" "true") | |
475 | (nil)]) | |
476 | ||
477 | (define_delay (and (match_test "!TARGET_AT_DBR_CONDEXEC") | |
478 | (eq_attr "type" "brcc")) | |
479 | [(eq_attr "in_delay_slot" "true") | |
480 | (eq_attr "in_delay_slot" "true") | |
481 | (nil)]) | |
482 | ||
483 | (define_delay (and (match_test "TARGET_AT_DBR_CONDEXEC") | |
484 | (eq_attr "type" "brcc")) | |
485 | [(eq_attr "in_delay_slot" "true") | |
486 | (nil) | |
487 | (nil)]) | |
488 | ||
489 | (define_delay | |
490 | (eq_attr "type" "return") | |
491 | [(eq_attr "in_ret_delay_slot" "yes") | |
492 | (eq_attr "annul_ret_delay_insn" "yes") | |
493 | (eq_attr "cond_ret_delay_insn" "yes")]) | |
494 | ||
495 | ;; For ARC600, unexposing the delay sloy incurs a penalty also in the | |
496 | ;; non-taken case, so the only meaningful way to have an annull-true | |
497 | ;; filled delay slot is to conditionalize the delay slot insn. | |
498 | (define_delay (and (match_test "TARGET_AT_DBR_CONDEXEC") | |
499 | (eq_attr "type" "branch,uncond_branch,jump") | |
500 | (match_test "!optimize_size")) | |
501 | [(eq_attr "in_delay_slot" "true") | |
502 | (eq_attr "cond_delay_insn" "yes") | |
503 | (eq_attr "cond_delay_insn" "yes")]) | |
504 | ||
505 | ;; For ARC700, anything goes for annulled-true insns, since there is no | |
506 | ;; penalty for the unexposed delay slot when the branch is not taken, | |
507 | ;; however, we must avoid things that have a delay slot themselvese to | |
508 | ;; avoid confusing gcc. | |
509 | (define_delay (and (match_test "!TARGET_AT_DBR_CONDEXEC") | |
510 | (eq_attr "type" "branch,uncond_branch,jump") | |
511 | (match_test "!optimize_size")) | |
512 | [(eq_attr "in_delay_slot" "true") | |
513 | (eq_attr "type" "!call,branch,uncond_branch,jump,brcc,return,sfunc") | |
514 | (eq_attr "cond_delay_insn" "yes")]) | |
515 | ||
516 | ;; -mlongcall -fpic sfuncs use r12 to load the function address | |
517 | (define_delay (eq_attr "type" "sfunc") | |
518 | [(eq_attr "in_sfunc_delay_slot" "true") | |
519 | (eq_attr "in_sfunc_delay_slot" "true") | |
520 | (nil)]) | |
521 | ;; ??? need to use a working strategy for canuse_limm: | |
522 | ;; - either canuse_limm is not eligible for delay slots, and has no | |
523 | ;; delay slots, or arc_reorg has to treat them as nocond, or it has to | |
524 | ;; somehow modify them to become inelegible for delay slots if a decision | |
525 | ;; is made that makes conditional execution required. | |
526 | ||
527 | (define_attr "tune" "none,arc600,arc700_4_2_std,arc700_4_2_xmac" | |
528 | (const | |
529 | (cond [(symbol_ref "arc_tune == TUNE_ARC600") | |
530 | (const_string "arc600") | |
531 | (symbol_ref "arc_tune == TUNE_ARC700_4_2_STD") | |
532 | (const_string "arc700_4_2_std") | |
533 | (symbol_ref "arc_tune == TUNE_ARC700_4_2_XMAC") | |
534 | (const_string "arc700_4_2_xmac")] | |
535 | (const_string "none")))) | |
536 | ||
537 | (define_attr "tune_arc700" "false,true" | |
538 | (if_then_else (eq_attr "tune" "arc700_4_2_std, arc700_4_2_xmac") | |
539 | (const_string "true") | |
540 | (const_string "false"))) | |
541 | ||
542 | ;; Move instructions. | |
543 | (define_expand "movqi" | |
544 | [(set (match_operand:QI 0 "move_dest_operand" "") | |
545 | (match_operand:QI 1 "general_operand" ""))] | |
546 | "" | |
547 | "if (prepare_move_operands (operands, QImode)) DONE;") | |
548 | ||
549 | ; In order to allow the ccfsm machinery to do its work, the leading compact | |
550 | ; alternatives say 'canuse' - there is another alternative that will match | |
551 | ; when the condition codes are used. | |
552 | ; Rcq won't match if the condition is actually used; to avoid a spurious match | |
553 | ; via q, q is inactivated as constraint there. | |
554 | ; Likewise, the length of an alternative that might be shifted to conditional | |
555 | ; execution must reflect this, lest out-of-range branches are created. | |
556 | ; The iscompact attribute allows the epilogue expander to know for which | |
557 | ; insns it should lengthen the return insn. | |
558 | (define_insn "*movqi_insn" | |
559 | [(set (match_operand:QI 0 "move_dest_operand" "=Rcq,Rcq#q,w, w,w,???w, w,Rcq,S,!*x,r,m,???m") | |
560 | (match_operand:QI 1 "move_src_operand" "cL,cP,Rcq#q,cL,I,?Rac,?i,T,Rcq,Usd,m,c,?Rac"))] | |
561 | "register_operand (operands[0], QImode) | |
562 | || register_operand (operands[1], QImode)" | |
563 | "@ | |
564 | mov%? %0,%1%& | |
565 | mov%? %0,%1%& | |
566 | mov%? %0,%1%& | |
567 | mov%? %0,%1 | |
568 | mov%? %0,%1 | |
569 | mov%? %0,%1 | |
570 | mov%? %0,%S1 | |
571 | ldb%? %0,%1%& | |
572 | stb%? %1,%0%& | |
573 | ldb%? %0,%1%& | |
574 | ldb%U1%V1 %0,%1 | |
575 | stb%U0%V0 %1,%0 | |
576 | stb%U0%V0 %1,%0" | |
577 | [(set_attr "type" "move,move,move,move,move,move,move,load,store,load,load,store,store") | |
578 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,true,true,true,false,false,false") | |
579 | (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,no,no,no,no,no,no")]) | |
580 | ||
581 | (define_expand "movhi" | |
582 | [(set (match_operand:HI 0 "move_dest_operand" "") | |
583 | (match_operand:HI 1 "general_operand" ""))] | |
584 | "" | |
585 | "if (prepare_move_operands (operands, HImode)) DONE;") | |
586 | ||
587 | (define_insn "*movhi_insn" | |
588 | [(set (match_operand:HI 0 "move_dest_operand" "=Rcq,Rcq#q,w, w,w,???w,Rcq#q,w,Rcq,S,r,m,???m,VUsc") | |
589 | (match_operand:HI 1 "move_src_operand" "cL,cP,Rcq#q,cL,I,?Rac, ?i,?i,T,Rcq,m,c,?Rac,i"))] | |
590 | "register_operand (operands[0], HImode) | |
591 | || register_operand (operands[1], HImode) | |
592 | || (CONSTANT_P (operands[1]) | |
593 | /* Don't use a LIMM that we could load with a single insn - we loose | |
594 | delay-slot filling opportunities. */ | |
595 | && !satisfies_constraint_I (operands[1]) | |
596 | && satisfies_constraint_Usc (operands[0]))" | |
597 | "@ | |
598 | mov%? %0,%1%& | |
599 | mov%? %0,%1%& | |
600 | mov%? %0,%1%& | |
601 | mov%? %0,%1 | |
602 | mov%? %0,%1 | |
603 | mov%? %0,%1 | |
604 | mov%? %0,%S1%& | |
605 | mov%? %0,%S1 | |
606 | ldw%? %0,%1%& | |
607 | stw%? %1,%0%& | |
608 | ldw%U1%V1 %0,%1 | |
609 | stw%U0%V0 %1,%0 | |
610 | stw%U0%V0 %1,%0 | |
611 | stw%U0%V0 %S1,%0" | |
612 | [(set_attr "type" "move,move,move,move,move,move,move,move,load,store,load,store,store,store") | |
613 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false,maybe_limm,false,true,true,false,false,false,false") | |
614 | (set_attr "predicable" "yes,no,yes,yes,no,yes,yes,yes,no,no,no,no,no,no")]) | |
615 | ||
616 | (define_expand "movsi" | |
617 | [(set (match_operand:SI 0 "move_dest_operand" "") | |
618 | (match_operand:SI 1 "general_operand" ""))] | |
619 | "" | |
620 | "if (prepare_move_operands (operands, SImode)) DONE;") | |
621 | ||
622 | ; In order to allow the ccfsm machinery to do its work, the leading compact | |
623 | ; alternatives say 'canuse' - there is another alternative that will match | |
624 | ; when the condition codes are used. | |
625 | ; Rcq won't match if the condition is actually used; to avoid a spurious match | |
626 | ; via q, q is inactivated as constraint there. | |
627 | ; Likewise, the length of an alternative that might be shifted to conditional | |
628 | ; execution must reflect this, lest out-of-range branches are created. | |
629 | ; the iscompact attribute allows the epilogue expander to know for which | |
630 | ; insns it should lengthen the return insn. | |
631 | ; N.B. operand 1 of alternative 7 expands into pcl,symbol@gotpc . | |
632 | (define_insn "*movsi_insn" | |
633 | [(set (match_operand:SI 0 "move_dest_operand" "=Rcq,Rcq#q,w, w,w, w,???w, ?w, w,Rcq#q, w,Rcq, S,Us<,RcqRck,!*x,r,m,???m,VUsc") | |
634 | (match_operand:SI 1 "move_src_operand" " cL,cP,Rcq#q,cL,I,Crr,?Rac,Cpc,Clb,?Cal,?Cal,T,Rcq,RcqRck,Us>,Usd,m,c,?Rac,C32"))] | |
635 | "register_operand (operands[0], SImode) | |
636 | || register_operand (operands[1], SImode) | |
637 | || (CONSTANT_P (operands[1]) | |
638 | /* Don't use a LIMM that we could load with a single insn - we loose | |
639 | delay-slot filling opportunities. */ | |
640 | && !satisfies_constraint_I (operands[1]) | |
641 | && satisfies_constraint_Usc (operands[0]))" | |
642 | "@ | |
643 | mov%? %0,%1%& ;0 | |
644 | mov%? %0,%1%& ;1 | |
645 | mov%? %0,%1%& ;2 | |
646 | mov%? %0,%1 ;3 | |
647 | mov%? %0,%1 ;4 | |
648 | ror %0,((%1*2+1) & 0x3f) ;5 | |
649 | mov%? %0,%1 ;6 | |
650 | add %0,%S1 ;7 | |
651 | * return arc_get_unalign () ? \"add %0,pcl,%1-.+2\" : \"add %0,pcl,%1-.\"; | |
652 | mov%? %0,%S1%& ;9 | |
653 | mov%? %0,%S1 ;10 | |
654 | ld%? %0,%1%& ;11 | |
655 | st%? %1,%0%& ;12 | |
656 | * return arc_short_long (insn, \"push%? %1%&\", \"st%U0 %1,%0%&\"); | |
657 | * return arc_short_long (insn, \"pop%? %0%&\", \"ld%U1 %0,%1%&\"); | |
658 | ld%? %0,%1%& ;15 | |
659 | ld%U1%V1 %0,%1 ;16 | |
660 | st%U0%V0 %1,%0 ;17 | |
661 | st%U0%V0 %1,%0 ;18 | |
662 | st%U0%V0 %S1,%0 ;19" | |
663 | [(set_attr "type" "move,move,move,move,move,two_cycle_core,move,binary,binary,move,move,load,store,store,load,load,load,store,store,store") | |
664 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,false,false,maybe_limm,false,true,true,true,true,true,false,false,false,false") | |
665 | ; Use default length for iscompact to allow for COND_EXEC. But set length | |
666 | ; of Crr to 4. | |
667 | (set_attr "length" "*,*,*,4,4,4,4,8,8,*,8,*,*,*,*,*,*,*,*,8") | |
668 | (set_attr "predicable" "yes,no,yes,yes,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no")]) | |
669 | ||
670 | ;; Sometimes generated by the epilogue code. We don't want to | |
671 | ;; recognize these addresses in general, because the limm is costly, | |
672 | ;; and we can't use them for stores. */ | |
673 | (define_insn "*movsi_pre_mod" | |
674 | [(set (match_operand:SI 0 "register_operand" "=w") | |
675 | (mem:SI (pre_modify | |
676 | (reg:SI SP_REG) | |
677 | (plus:SI (reg:SI SP_REG) | |
678 | (match_operand 1 "immediate_operand" "Cal")))))] | |
679 | "reload_completed" | |
680 | "ld.a %0,[sp,%1]" | |
681 | [(set_attr "type" "load") | |
682 | (set_attr "length" "8")]) | |
683 | ||
684 | ;; Store a value to directly to memory. The location might also be cached. | |
685 | ;; Since the cached copy can cause a write-back at unpredictable times, | |
686 | ;; we first write cached, then we write uncached. | |
687 | (define_insn "store_direct" | |
688 | [(set (match_operand:SI 0 "move_dest_operand" "=m") | |
689 | (unspec:SI [(match_operand:SI 1 "register_operand" "c")] | |
690 | UNSPEC_DIRECT))] | |
691 | "" | |
692 | "st%U0 %1,%0\;st%U0.di %1,%0" | |
693 | [(set_attr "type" "store")]) | |
694 | ||
695 | (define_insn_and_split "*movsi_set_cc_insn" | |
696 | [(set (match_operand:CC_ZN 2 "cc_set_register" "") | |
697 | (match_operator 3 "zn_compare_operator" | |
698 | [(match_operand:SI 1 "nonmemory_operand" "cI,cL,Cal") (const_int 0)])) | |
699 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
700 | (match_dup 1))] | |
701 | "" | |
702 | "mov%?.f %0,%S1" | |
703 | ; splitting to 'tst' allows short insns and combination into brcc. | |
704 | "reload_completed && operands_match_p (operands[0], operands[1])" | |
705 | [(set (match_dup 2) (match_dup 3))] | |
706 | "" | |
707 | [(set_attr "type" "compare") | |
708 | (set_attr "predicable" "no,yes,yes") | |
709 | (set_attr "cond" "set_zn") | |
710 | (set_attr "length" "4,4,8")]) | |
711 | ||
712 | (define_insn "unary_comparison" | |
713 | [(set (match_operand:CC_ZN 0 "cc_set_register" "") | |
714 | (match_operator 3 "zn_compare_operator" | |
715 | [(match_operator:SI 2 "unary_operator" | |
716 | [(match_operand:SI 1 "register_operand" "c")]) | |
717 | (const_int 0)]))] | |
718 | "" | |
719 | "%O2.f 0,%1" | |
720 | [(set_attr "type" "compare") | |
721 | (set_attr "cond" "set_zn")]) | |
722 | ||
723 | ||
724 | ; this pattern is needed by combiner for cases like if (c=(~b)) { ... } | |
725 | (define_insn "*unary_comparison_result_used" | |
726 | [(set (match_operand 2 "cc_register" "") | |
727 | (match_operator 4 "zn_compare_operator" | |
728 | [(match_operator:SI 3 "unary_operator" | |
729 | [(match_operand:SI 1 "register_operand" "c")]) | |
730 | (const_int 0)])) | |
731 | (set (match_operand:SI 0 "register_operand" "=w") | |
732 | (match_dup 3))] | |
733 | "" | |
734 | "%O3.f %0,%1" | |
735 | [(set_attr "type" "compare") | |
736 | (set_attr "cond" "set_zn") | |
737 | (set_attr "length" "4")]) | |
738 | ||
739 | (define_insn "*tst" | |
740 | [(set | |
741 | (match_operand 0 "cc_register" "") | |
742 | (match_operator 3 "zn_compare_operator" | |
743 | [(and:SI | |
744 | (match_operand:SI 1 "register_operand" | |
745 | "%Rcq,Rcq, c, c, c, c, c, c") | |
746 | (match_operand:SI 2 "nonmemory_operand" | |
747 | " Rcq,C0p,cI,cL,C1p,Ccp,CnL,Cal")) | |
748 | (const_int 0)]))] | |
749 | "(register_operand (operands[1], SImode) | |
750 | && nonmemory_operand (operands[2], SImode)) | |
751 | || (memory_operand (operands[1], SImode) | |
752 | && satisfies_constraint_Cux (operands[2]))" | |
753 | "* | |
754 | switch (which_alternative) | |
755 | { | |
756 | case 0: case 2: case 3: case 7: | |
757 | return \"tst%? %1,%2\"; | |
758 | case 1: | |
759 | return \"btst%? %1,%z2\"; | |
760 | case 4: | |
761 | return \"bmsk%?.f 0,%1,%Z2%&\"; | |
762 | case 5: | |
763 | return \"bclr%?.f 0,%1,%M2%&\"; | |
764 | case 6: | |
765 | return \"bic%?.f 0,%1,%n2-1\"; | |
766 | default: | |
767 | gcc_unreachable (); | |
768 | } | |
769 | " | |
770 | [(set_attr "iscompact" "maybe,maybe,false,false,false,false,false,false") | |
771 | (set_attr "type" "compare") | |
772 | (set_attr "length" "*,*,4,4,4,4,4,8") | |
773 | (set_attr "predicable" "no,yes,no,yes,no,no,no,yes") | |
774 | (set_attr "cond" "set_zn")]) | |
775 | ||
776 | (define_insn "*commutative_binary_comparison" | |
777 | [(set (match_operand:CC_ZN 0 "cc_set_register" "") | |
778 | (match_operator 5 "zn_compare_operator" | |
779 | [(match_operator:SI 4 "commutative_operator" | |
780 | [(match_operand:SI 1 "register_operand" "%c,c,c") | |
781 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")]) | |
782 | (const_int 0)])) | |
783 | (clobber (match_scratch:SI 3 "=X,1,X"))] | |
784 | "" | |
785 | "%O4.f 0,%1,%2" | |
786 | [(set_attr "type" "compare") | |
787 | (set_attr "cond" "set_zn") | |
788 | (set_attr "length" "4,4,8")]) | |
789 | ||
790 | ; for flag setting 'add' instructions like if (a+b) { ...} | |
791 | ; the combiner needs this pattern | |
792 | (define_insn "*addsi_compare" | |
793 | [(set (reg:CC_ZN CC_REG) | |
794 | (compare:CC_ZN (match_operand:SI 0 "register_operand" "c") | |
795 | (neg:SI (match_operand:SI 1 "register_operand" "c"))))] | |
796 | "" | |
797 | "add.f 0,%0,%1" | |
798 | [(set_attr "cond" "set") | |
799 | (set_attr "type" "compare") | |
800 | (set_attr "length" "4")]) | |
801 | ||
802 | ; for flag setting 'add' instructions like if (a+b < a) { ...} | |
803 | ; the combiner needs this pattern | |
804 | (define_insn "addsi_compare_2" | |
805 | [(set (reg:CC_C CC_REG) | |
806 | (compare:CC_C (plus:SI (match_operand:SI 0 "register_operand" "c,c") | |
807 | (match_operand:SI 1 "nonmemory_operand" "cL,Cal")) | |
808 | (match_dup 0)))] | |
809 | "" | |
810 | "add.f 0,%0,%1" | |
811 | [(set_attr "cond" "set") | |
812 | (set_attr "type" "compare") | |
813 | (set_attr "length" "4,8")]) | |
814 | ||
815 | (define_insn "*addsi_compare_3" | |
816 | [(set (reg:CC_C CC_REG) | |
817 | (compare:CC_C (plus:SI (match_operand:SI 0 "register_operand" "c") | |
818 | (match_operand:SI 1 "register_operand" "c")) | |
819 | (match_dup 1)))] | |
820 | "" | |
821 | "add.f 0,%0,%1" | |
822 | [(set_attr "cond" "set") | |
823 | (set_attr "type" "compare") | |
824 | (set_attr "length" "4")]) | |
825 | ||
826 | ; this pattern is needed by combiner for cases like if (c=a+b) { ... } | |
827 | (define_insn "*commutative_binary_comparison_result_used" | |
828 | [(set (match_operand 3 "cc_register" "") | |
829 | (match_operator 5 "zn_compare_operator" | |
830 | ; We can accept any commutative operator except mult because | |
831 | ; our 'w' class below could try to use LP_COUNT. | |
832 | [(match_operator:SI 4 "commutative_operator_sans_mult" | |
833 | [(match_operand:SI 1 "register_operand" "c,0,c") | |
834 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")]) | |
835 | (const_int 0)])) | |
836 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
837 | (match_dup 4))] | |
838 | "" | |
839 | "%O4.f %0,%1,%2 ; non-mult commutative" | |
840 | [(set_attr "type" "compare,compare,compare") | |
841 | (set_attr "cond" "set_zn,set_zn,set_zn") | |
842 | (set_attr "length" "4,4,8")]) | |
843 | ||
844 | ; a MULT-specific version of this pattern to avoid touching the | |
845 | ; LP_COUNT register | |
846 | (define_insn "*commutative_binary_mult_comparison_result_used" | |
847 | [(set (match_operand 3 "cc_register" "") | |
848 | (match_operator 5 "zn_compare_operator" | |
849 | [(match_operator:SI 4 "mult_operator" | |
850 | [(match_operand:SI 1 "register_operand" "c,0,c") | |
851 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")]) | |
852 | (const_int 0)])) | |
853 | ; Make sure to use the W class to not touch LP_COUNT. | |
854 | (set (match_operand:SI 0 "register_operand" "=W,W,W") | |
855 | (match_dup 4))] | |
856 | "TARGET_ARC700" | |
857 | "%O4.f %0,%1,%2 ; mult commutative" | |
858 | [(set_attr "type" "compare,compare,compare") | |
859 | (set_attr "cond" "set_zn,set_zn,set_zn") | |
860 | (set_attr "length" "4,4,8")]) | |
861 | ||
862 | ; this pattern is needed by combiner for cases like if (c=a<<b) { ... } | |
863 | (define_insn "*noncommutative_binary_comparison_result_used" | |
864 | [(set (match_operand 3 "cc_register" "") | |
865 | (match_operator 5 "zn_compare_operator" | |
866 | [(match_operator:SI 4 "noncommutative_operator" | |
867 | [(match_operand:SI 1 "register_operand" "c,0,c") | |
868 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")]) | |
869 | (const_int 0)])) | |
870 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
871 | (match_dup 4 ))] | |
872 | "TARGET_BARREL_SHIFTER || GET_CODE (operands[4]) == MINUS" | |
873 | "%O4.f %0,%1,%2" | |
874 | [(set_attr "type" "compare,compare,compare") | |
875 | (set_attr "cond" "set_zn,set_zn,set_zn") | |
876 | (set_attr "length" "4,4,8")]) | |
877 | ||
878 | (define_insn "*noncommutative_binary_comparison" | |
879 | [(set (match_operand:CC_ZN 0 "cc_set_register" "") | |
880 | (match_operator 5 "zn_compare_operator" | |
881 | [(match_operator:SI 4 "noncommutative_operator" | |
882 | [(match_operand:SI 1 "register_operand" "c,c,c") | |
883 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal")]) | |
884 | (const_int 0)])) | |
885 | (clobber (match_scratch:SI 3 "=X,1,X"))] | |
886 | "TARGET_BARREL_SHIFTER || GET_CODE (operands[4]) == MINUS" | |
887 | "%O4.f 0,%1,%2" | |
888 | [(set_attr "type" "compare") | |
889 | (set_attr "cond" "set_zn") | |
890 | (set_attr "length" "4,4,8")]) | |
891 | ||
892 | (define_expand "bic_f_zn" | |
893 | [(parallel | |
894 | [(set (reg:CC_ZN CC_REG) | |
895 | (compare:CC_ZN | |
896 | (and:SI (match_operand:SI 1 "register_operand" "") | |
897 | (not:SI (match_operand:SI 2 "nonmemory_operand" ""))) | |
898 | (const_int 0))) | |
899 | (set (match_operand:SI 0 "register_operand" "") | |
900 | (and:SI (match_dup 1) (not:SI (match_dup 2))))])] | |
901 | "") | |
902 | ||
903 | (define_insn "*bic_f" | |
904 | [(set (match_operand 3 "cc_register" "=Rcc,Rcc,Rcc") | |
905 | (match_operator 4 "zn_compare_operator" | |
906 | [(and:SI (match_operand:SI 1 "register_operand" "c,0,c") | |
907 | (not:SI | |
908 | (match_operand:SI 2 "nonmemory_operand" "cL,I,?Cal"))) | |
909 | (const_int 0)])) | |
910 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
911 | (and:SI (match_dup 1) (not:SI (match_dup 2))))] | |
912 | "" | |
913 | "bic.f %0,%1,%2" | |
914 | [(set_attr "type" "compare,compare,compare") | |
915 | (set_attr "cond" "set_zn,set_zn,set_zn") | |
916 | (set_attr "length" "4,4,8")]) | |
917 | ||
918 | (define_expand "movdi" | |
919 | [(set (match_operand:DI 0 "move_dest_operand" "") | |
920 | (match_operand:DI 1 "general_operand" ""))] | |
921 | "" | |
922 | " | |
923 | { | |
924 | /* Everything except mem = const or mem = mem can be done easily. */ | |
925 | ||
926 | if (GET_CODE (operands[0]) == MEM) | |
927 | operands[1] = force_reg (DImode, operands[1]); | |
928 | }") | |
929 | ||
930 | (define_insn_and_split "*movdi_insn" | |
931 | [(set (match_operand:DI 0 "move_dest_operand" "=w,w,r,m") | |
932 | (match_operand:DI 1 "move_double_src_operand" "c,Hi,m,c"))] | |
933 | "register_operand (operands[0], DImode) | |
934 | || register_operand (operands[1], DImode)" | |
935 | "* | |
936 | { | |
937 | switch (which_alternative) | |
938 | { | |
939 | default: | |
940 | case 0 : | |
941 | /* We normally copy the low-numbered register first. However, if | |
942 | the first register operand 0 is the same as the second register of | |
943 | operand 1, we must copy in the opposite order. */ | |
944 | if (REGNO (operands[0]) == REGNO (operands[1]) + 1) | |
945 | return \"mov%? %R0,%R1\;mov%? %0,%1\"; | |
946 | else | |
947 | return \"mov%? %0,%1\;mov%? %R0,%R1\"; | |
948 | case 1 : | |
949 | return \"mov%? %L0,%L1\;mov%? %H0,%H1\"; | |
950 | case 2 : | |
951 | /* If the low-address word is used in the address, we must load it | |
952 | last. Otherwise, load it first. Note that we cannot have | |
953 | auto-increment in that case since the address register is known to be | |
954 | dead. */ | |
c9bd6bcd | 955 | if (refers_to_regno_p (REGNO (operands[0]), operands[1])) |
526b7aee SV |
956 | return \"ld%V1 %R0,%R1\;ld%V1 %0,%1\"; |
957 | else switch (GET_CODE (XEXP(operands[1], 0))) | |
958 | { | |
959 | case POST_MODIFY: case POST_INC: case POST_DEC: | |
960 | return \"ld%V1 %R0,%R1\;ld%U1%V1 %0,%1\"; | |
961 | case PRE_MODIFY: case PRE_INC: case PRE_DEC: | |
962 | return \"ld%U1%V1 %0,%1\;ld%V1 %R0,%R1\"; | |
963 | default: | |
964 | return \"ld%U1%V1 %0,%1\;ld%U1%V1 %R0,%R1\"; | |
965 | } | |
966 | case 3 : | |
967 | switch (GET_CODE (XEXP(operands[0], 0))) | |
968 | { | |
969 | case POST_MODIFY: case POST_INC: case POST_DEC: | |
970 | return \"st%V0 %R1,%R0\;st%U0%V0 %1,%0\"; | |
971 | case PRE_MODIFY: case PRE_INC: case PRE_DEC: | |
972 | return \"st%U0%V0 %1,%0\;st%V0 %R1,%R0\"; | |
973 | default: | |
974 | return \"st%U0%V0 %1,%0\;st%U0%V0 %R1,%R0\"; | |
975 | } | |
976 | } | |
977 | }" | |
978 | "&& reload_completed && optimize" | |
979 | [(set (match_dup 2) (match_dup 3)) (set (match_dup 4) (match_dup 5))] | |
980 | "arc_split_move (operands);" | |
981 | [(set_attr "type" "move,move,load,store") | |
982 | ;; ??? The ld/st values could be 4 if it's [reg,bignum]. | |
983 | (set_attr "length" "8,16,16,16")]) | |
984 | ||
985 | ||
986 | ;; Floating point move insns. | |
987 | ||
988 | (define_expand "movsf" | |
989 | [(set (match_operand:SF 0 "general_operand" "") | |
990 | (match_operand:SF 1 "general_operand" ""))] | |
991 | "" | |
992 | "if (prepare_move_operands (operands, SFmode)) DONE;") | |
993 | ||
994 | (define_insn "*movsf_insn" | |
995 | [(set (match_operand:SF 0 "move_dest_operand" "=w,w,r,m") | |
996 | (match_operand:SF 1 "move_src_operand" "c,E,m,c"))] | |
997 | "register_operand (operands[0], SFmode) | |
998 | || register_operand (operands[1], SFmode)" | |
999 | "@ | |
1000 | mov%? %0,%1 | |
1001 | mov%? %0,%1 ; %A1 | |
1002 | ld%U1%V1 %0,%1 | |
1003 | st%U0%V0 %1,%0" | |
1004 | [(set_attr "type" "move,move,load,store") | |
1005 | (set_attr "predicable" "yes,yes,no,no")]) | |
1006 | ||
1007 | (define_expand "movdf" | |
1008 | [(set (match_operand:DF 0 "nonimmediate_operand" "") | |
1009 | (match_operand:DF 1 "general_operand" ""))] | |
1010 | "" | |
1011 | "if (prepare_move_operands (operands, DFmode)) DONE;") | |
1012 | ||
1013 | (define_insn "*movdf_insn" | |
1014 | [(set (match_operand:DF 0 "move_dest_operand" "=D,r,c,c,r,m") | |
1015 | (match_operand:DF 1 "move_double_src_operand" "r,D,c,E,m,c"))] | |
1016 | "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" | |
1017 | "#" | |
1018 | [(set_attr "type" "move,move,move,move,load,store") | |
1019 | (set_attr "predicable" "no,no,yes,yes,no,no") | |
1020 | ;; ??? The ld/st values could be 16 if it's [reg,bignum]. | |
1021 | (set_attr "length" "4,16,8,16,16,16")]) | |
1022 | ||
1023 | (define_split | |
1024 | [(set (match_operand:DF 0 "move_dest_operand" "") | |
1025 | (match_operand:DF 1 "move_double_src_operand" ""))] | |
1026 | "reload_completed" | |
1027 | [(match_dup 2)] | |
1028 | "operands[2] = arc_split_move (operands);") | |
1029 | ||
1030 | (define_insn_and_split "*movdf_insn_nolrsr" | |
1031 | [(set (match_operand:DF 0 "register_operand" "=r") | |
1032 | (match_operand:DF 1 "arc_double_register_operand" "D")) | |
1033 | (use (match_operand:SI 2 "" "N")) ; aka const1_rtx | |
1034 | ] | |
1035 | "TARGET_DPFP && TARGET_DPFP_DISABLE_LRSR" | |
1036 | "#" | |
1037 | "&& 1" | |
1038 | [ | |
1039 | ; mov r0, 0 | |
1040 | (set (match_dup 0) (match_dup 3)) | |
1041 | ||
1042 | ; daddh?? r1, r0, r0 | |
1043 | (parallel [ | |
1044 | (set (match_dup 1) (plus:DF (match_dup 1) (match_dup 0))) | |
1045 | (use (const_int 1)) | |
1046 | (use (const_int 1)) | |
1047 | (use (match_dup 0)) ; used to block can_combine_p | |
1048 | (set (match_dup 0) (plus:DF (match_dup 1) (match_dup 0))) ; r1 in op 0 | |
1049 | ]) | |
1050 | ||
1051 | ; We have to do this twice, once to read the value into R0 and | |
1052 | ; second time to put back the contents which the first DEXCLx | |
1053 | ; will have overwritten | |
1054 | ; dexcl2 r0, r1, r0 | |
1055 | (set (match_dup 4) ; aka r0result | |
1056 | ; aka DF, r1, r0 | |
1057 | (unspec_volatile:SI [(match_dup 1) (match_dup 5) (match_dup 4)] VUNSPEC_DEXCL )) | |
1058 | ; Generate the second, which makes sure operand5 and operand4 values | |
1059 | ; are put back in the Dx register properly. | |
1060 | (unspec_volatile:SI [(match_dup 1) (match_dup 5) (match_dup 4)] VUNSPEC_DEXCL_NORES ) | |
1061 | ||
1062 | ; Note: we cannot use a (clobber (match_scratch)) here because | |
1063 | ; the combine pass will end up replacing uses of it with 0 | |
1064 | ] | |
1065 | "operands[3] = CONST0_RTX (DFmode); | |
1066 | operands[4] = simplify_gen_subreg (SImode, operands[0], DFmode, 0); | |
1067 | operands[5] = simplify_gen_subreg (SImode, operands[0], DFmode, 4);" | |
1068 | [(set_attr "type" "move")]) | |
1069 | ||
1070 | ;; Load/Store with update instructions. | |
1071 | ;; | |
1072 | ;; Some of these we can get by using pre-decrement or pre-increment, but the | |
1073 | ;; hardware can also do cases where the increment is not the size of the | |
1074 | ;; object. | |
1075 | ;; | |
1076 | ;; In all these cases, we use operands 0 and 1 for the register being | |
1077 | ;; incremented because those are the operands that local-alloc will | |
1078 | ;; tie and these are the pair most likely to be tieable (and the ones | |
1079 | ;; that will benefit the most). | |
1080 | ;; | |
1081 | ;; We use match_operator here because we need to know whether the memory | |
1082 | ;; object is volatile or not. | |
1083 | ||
1084 | ||
1085 | ;; Note: loadqi_update has no 16-bit variant | |
1086 | (define_insn "*loadqi_update" | |
1087 | [(set (match_operand:QI 3 "dest_reg_operand" "=r,r") | |
1088 | (match_operator:QI 4 "load_update_operand" | |
1089 | [(match_operand:SI 1 "register_operand" "0,0") | |
1090 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")])) | |
1091 | (set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
1092 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1093 | "" | |
1094 | "ldb.a%V4 %3,[%0,%S2]" | |
1095 | [(set_attr "type" "load,load") | |
1096 | (set_attr "length" "4,8")]) | |
1097 | ||
1098 | (define_insn "*load_zeroextendqisi_update" | |
1099 | [(set (match_operand:SI 3 "dest_reg_operand" "=r,r") | |
1100 | (zero_extend:SI (match_operator:QI 4 "load_update_operand" | |
1101 | [(match_operand:SI 1 "register_operand" "0,0") | |
1102 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")]))) | |
1103 | (set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
1104 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1105 | "" | |
1106 | "ldb.a%V4 %3,[%0,%S2]" | |
1107 | [(set_attr "type" "load,load") | |
1108 | (set_attr "length" "4,8")]) | |
1109 | ||
1110 | (define_insn "*load_signextendqisi_update" | |
1111 | [(set (match_operand:SI 3 "dest_reg_operand" "=r,r") | |
1112 | (sign_extend:SI (match_operator:QI 4 "load_update_operand" | |
1113 | [(match_operand:SI 1 "register_operand" "0,0") | |
1114 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")]))) | |
1115 | (set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
1116 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1117 | "" | |
1118 | "ldb.x.a%V4 %3,[%0,%S2]" | |
1119 | [(set_attr "type" "load,load") | |
1120 | (set_attr "length" "4,8")]) | |
1121 | ||
1122 | (define_insn "*storeqi_update" | |
1123 | [(set (match_operator:QI 4 "store_update_operand" | |
1124 | [(match_operand:SI 1 "register_operand" "0") | |
1125 | (match_operand:SI 2 "short_immediate_operand" "I")]) | |
1126 | (match_operand:QI 3 "register_operand" "c")) | |
1127 | (set (match_operand:SI 0 "dest_reg_operand" "=w") | |
1128 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1129 | "" | |
1130 | "stb.a%V4 %3,[%0,%2]" | |
1131 | [(set_attr "type" "store") | |
1132 | (set_attr "length" "4")]) | |
1133 | ||
1134 | ;; ??? pattern may have to be re-written | |
1135 | ;; Note: no 16-bit variant for this pattern | |
1136 | (define_insn "*loadhi_update" | |
1137 | [(set (match_operand:HI 3 "dest_reg_operand" "=r,r") | |
1138 | (match_operator:HI 4 "load_update_operand" | |
1139 | [(match_operand:SI 1 "register_operand" "0,0") | |
1140 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")])) | |
1141 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
1142 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1143 | "" | |
1144 | "ldw.a%V4 %3,[%0,%S2]" | |
1145 | [(set_attr "type" "load,load") | |
1146 | (set_attr "length" "4,8")]) | |
1147 | ||
1148 | (define_insn "*load_zeroextendhisi_update" | |
1149 | [(set (match_operand:SI 3 "dest_reg_operand" "=r,r") | |
1150 | (zero_extend:SI (match_operator:HI 4 "load_update_operand" | |
1151 | [(match_operand:SI 1 "register_operand" "0,0") | |
1152 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")]))) | |
1153 | (set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
1154 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1155 | "" | |
1156 | "ldw.a%V4 %3,[%0,%S2]" | |
1157 | [(set_attr "type" "load,load") | |
1158 | (set_attr "length" "4,8")]) | |
1159 | ||
1160 | ;; Note: no 16-bit variant for this instruction | |
1161 | (define_insn "*load_signextendhisi_update" | |
1162 | [(set (match_operand:SI 3 "dest_reg_operand" "=r,r") | |
1163 | (sign_extend:SI (match_operator:HI 4 "load_update_operand" | |
1164 | [(match_operand:SI 1 "register_operand" "0,0") | |
1165 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")]))) | |
1166 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
1167 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1168 | "" | |
1169 | "ldw.x.a%V4 %3,[%0,%S2]" | |
1170 | [(set_attr "type" "load,load") | |
1171 | (set_attr "length" "4,8")]) | |
1172 | ||
1173 | (define_insn "*storehi_update" | |
1174 | [(set (match_operator:HI 4 "store_update_operand" | |
1175 | [(match_operand:SI 1 "register_operand" "0") | |
1176 | (match_operand:SI 2 "short_immediate_operand" "I")]) | |
1177 | (match_operand:HI 3 "register_operand" "c")) | |
1178 | (set (match_operand:SI 0 "dest_reg_operand" "=w") | |
1179 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1180 | "" | |
1181 | "stw.a%V4 %3,[%0,%2]" | |
1182 | [(set_attr "type" "store") | |
1183 | (set_attr "length" "4")]) | |
1184 | ||
1185 | ;; No 16-bit variant for this instruction pattern | |
1186 | (define_insn "*loadsi_update" | |
1187 | [(set (match_operand:SI 3 "dest_reg_operand" "=r,r") | |
1188 | (match_operator:SI 4 "load_update_operand" | |
1189 | [(match_operand:SI 1 "register_operand" "0,0") | |
1190 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")])) | |
1191 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
1192 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1193 | "" | |
1194 | "ld.a%V4 %3,[%0,%S2]" | |
1195 | [(set_attr "type" "load,load") | |
1196 | (set_attr "length" "4,8")]) | |
1197 | ||
1198 | (define_insn "*storesi_update" | |
1199 | [(set (match_operator:SI 4 "store_update_operand" | |
1200 | [(match_operand:SI 1 "register_operand" "0") | |
1201 | (match_operand:SI 2 "short_immediate_operand" "I")]) | |
1202 | (match_operand:SI 3 "register_operand" "c")) | |
1203 | (set (match_operand:SI 0 "dest_reg_operand" "=w") | |
1204 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1205 | "" | |
1206 | "st.a%V4 %3,[%0,%2]" | |
1207 | [(set_attr "type" "store") | |
1208 | (set_attr "length" "4")]) | |
1209 | ||
1210 | (define_insn "*loadsf_update" | |
1211 | [(set (match_operand:SF 3 "dest_reg_operand" "=r,r") | |
1212 | (match_operator:SF 4 "load_update_operand" | |
1213 | [(match_operand:SI 1 "register_operand" "0,0") | |
1214 | (match_operand:SI 2 "nonmemory_operand" "rI,Cal")])) | |
1215 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
1216 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1217 | "" | |
1218 | "ld.a%V4 %3,[%0,%S2]" | |
1219 | [(set_attr "type" "load,load") | |
1220 | (set_attr "length" "4,8")]) | |
1221 | ||
1222 | (define_insn "*storesf_update" | |
1223 | [(set (match_operator:SF 4 "store_update_operand" | |
1224 | [(match_operand:SI 1 "register_operand" "0") | |
1225 | (match_operand:SI 2 "short_immediate_operand" "I")]) | |
1226 | (match_operand:SF 3 "register_operand" "c")) | |
1227 | (set (match_operand:SI 0 "dest_reg_operand" "=w") | |
1228 | (plus:SI (match_dup 1) (match_dup 2)))] | |
1229 | "" | |
1230 | "st.a%V4 %3,[%0,%2]" | |
1231 | [(set_attr "type" "store") | |
1232 | (set_attr "length" "4")]) | |
1233 | ||
1234 | ;; Conditional move instructions. | |
1235 | ||
1236 | (define_expand "movsicc" | |
1237 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
1238 | (if_then_else:SI (match_operand 1 "comparison_operator" "") | |
1239 | (match_operand:SI 2 "nonmemory_operand" "") | |
1240 | (match_operand:SI 3 "register_operand" "")))] | |
1241 | "" | |
1242 | "operands[1] = gen_compare_reg (operands[1], VOIDmode);") | |
1243 | ||
1244 | ||
1245 | (define_expand "movdicc" | |
1246 | [(set (match_operand:DI 0 "dest_reg_operand" "") | |
1247 | (if_then_else:DI(match_operand 1 "comparison_operator" "") | |
1248 | (match_operand:DI 2 "nonmemory_operand" "") | |
1249 | (match_operand:DI 3 "register_operand" "")))] | |
1250 | "" | |
1251 | "operands[1] = gen_compare_reg (operands[1], VOIDmode);") | |
1252 | ||
1253 | ||
1254 | (define_expand "movsfcc" | |
1255 | [(set (match_operand:SF 0 "dest_reg_operand" "") | |
1256 | (if_then_else:SF (match_operand 1 "comparison_operator" "") | |
1257 | (match_operand:SF 2 "nonmemory_operand" "") | |
1258 | (match_operand:SF 3 "register_operand" "")))] | |
1259 | "" | |
1260 | "operands[1] = gen_compare_reg (operands[1], VOIDmode);") | |
1261 | ||
1262 | (define_expand "movdfcc" | |
1263 | [(set (match_operand:DF 0 "dest_reg_operand" "") | |
1264 | (if_then_else:DF (match_operand 1 "comparison_operator" "") | |
1265 | (match_operand:DF 2 "nonmemory_operand" "") | |
1266 | (match_operand:DF 3 "register_operand" "")))] | |
1267 | "" | |
1268 | "operands[1] = gen_compare_reg (operands[1], VOIDmode);") | |
1269 | ||
1270 | (define_insn "*movsicc_insn" | |
1271 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
1272 | (if_then_else:SI (match_operator 3 "proper_comparison_operator" | |
1273 | [(match_operand 4 "cc_register" "") (const_int 0)]) | |
1274 | (match_operand:SI 1 "nonmemory_operand" "cL,Cal") | |
1275 | (match_operand:SI 2 "register_operand" "0,0")))] | |
1276 | "" | |
1277 | { | |
1278 | if (rtx_equal_p (operands[1], const0_rtx) && GET_CODE (operands[3]) == NE | |
1279 | && satisfies_constraint_Rcq (operands[0])) | |
1280 | return "sub%?.ne %0,%0,%0"; | |
1281 | /* ??? might be good for speed on ARC600 too, *if* properly scheduled. */ | |
1282 | if ((TARGET_ARC700 || optimize_size) | |
1283 | && rtx_equal_p (operands[1], constm1_rtx) | |
1284 | && GET_CODE (operands[3]) == LTU) | |
1285 | return "sbc.cs %0,%0,%0"; | |
1286 | return "mov.%d3 %0,%S1"; | |
1287 | } | |
1288 | [(set_attr "type" "cmove,cmove") | |
1289 | (set_attr "length" "4,8")]) | |
1290 | ||
1291 | ; Try to generate more short moves, and/or less limms, by substituting a | |
1292 | ; conditional move with a conditional sub. | |
1293 | (define_peephole2 | |
1294 | [(set (match_operand:SI 0 "compact_register_operand") | |
1295 | (match_operand:SI 1 "const_int_operand")) | |
1296 | (set (match_dup 0) | |
1297 | (if_then_else:SI (match_operator 3 "proper_comparison_operator" | |
1298 | [(match_operand 4 "cc_register" "") (const_int 0)]) | |
1299 | (match_operand:SI 2 "const_int_operand" "") | |
1300 | (match_dup 0)))] | |
1301 | "!satisfies_constraint_P (operands[1]) | |
1302 | && satisfies_constraint_P (operands[2]) | |
1303 | && UNSIGNED_INT6 (INTVAL (operands[2]) - INTVAL (operands[1]))" | |
1304 | [(set (match_dup 0) (match_dup 2)) | |
1305 | (cond_exec | |
1306 | (match_dup 3) | |
1307 | (set (match_dup 0) | |
1308 | (plus:SI (match_dup 0) (match_dup 1))))] | |
1309 | "operands[3] = gen_rtx_fmt_ee (REVERSE_CONDITION (GET_CODE (operands[3]), | |
1310 | GET_MODE (operands[4])), | |
1311 | VOIDmode, operands[4], const0_rtx); | |
1312 | operands[1] = GEN_INT (INTVAL (operands[1]) - INTVAL (operands[2]));") | |
1313 | ||
1314 | (define_insn "*movdicc_insn" | |
1315 | [(set (match_operand:DI 0 "dest_reg_operand" "=&w,w") | |
1316 | (if_then_else:DI (match_operator 3 "proper_comparison_operator" | |
1317 | [(match_operand 4 "cc_register" "") (const_int 0)]) | |
1318 | (match_operand:DI 1 "nonmemory_operand" "c,i") | |
1319 | (match_operand:DI 2 "register_operand" "0,0")))] | |
1320 | "" | |
1321 | "* | |
1322 | { | |
1323 | switch (which_alternative) | |
1324 | { | |
1325 | default: | |
1326 | case 0 : | |
1327 | /* We normally copy the low-numbered register first. However, if | |
1328 | the first register operand 0 is the same as the second register of | |
1329 | operand 1, we must copy in the opposite order. */ | |
1330 | if (REGNO (operands[0]) == REGNO (operands[1]) + 1) | |
1331 | return \"mov.%d3 %R0,%R1\;mov.%d3 %0,%1\"; | |
1332 | else | |
1333 | return \"mov.%d3 %0,%1\;mov.%d3 %R0,%R1\"; | |
1334 | case 1 : | |
1335 | return \"mov.%d3 %L0,%L1\;mov.%d3 %H0,%H1\"; | |
1336 | ||
1337 | ||
1338 | } | |
1339 | }" | |
1340 | [(set_attr "type" "cmove,cmove") | |
1341 | (set_attr "length" "8,16")]) | |
1342 | ||
1343 | ||
1344 | (define_insn "*movsfcc_insn" | |
1345 | [(set (match_operand:SF 0 "dest_reg_operand" "=w,w") | |
1346 | (if_then_else:SF (match_operator 3 "proper_comparison_operator" | |
1347 | [(match_operand 4 "cc_register" "") (const_int 0)]) | |
1348 | (match_operand:SF 1 "nonmemory_operand" "c,E") | |
1349 | (match_operand:SF 2 "register_operand" "0,0")))] | |
1350 | "" | |
1351 | "@ | |
1352 | mov.%d3 %0,%1 | |
1353 | mov.%d3 %0,%1 ; %A1" | |
1354 | [(set_attr "type" "cmove,cmove")]) | |
1355 | ||
1356 | (define_insn "*movdfcc_insn" | |
1357 | [(set (match_operand:DF 0 "dest_reg_operand" "=w,w") | |
1358 | (if_then_else:DF (match_operator 1 "proper_comparison_operator" | |
1359 | [(match_operand 4 "cc_register" "") (const_int 0)]) | |
1360 | (match_operand:DF 2 "nonmemory_operand" "c,E") | |
1361 | (match_operand:DF 3 "register_operand" "0,0")))] | |
1362 | "" | |
1363 | "* | |
1364 | { | |
1365 | switch (which_alternative) | |
1366 | { | |
1367 | default: | |
1368 | case 0 : | |
1369 | /* We normally copy the low-numbered register first. However, if | |
1370 | the first register operand 0 is the same as the second register of | |
1371 | operand 1, we must copy in the opposite order. */ | |
1372 | if (REGNO (operands[0]) == REGNO (operands[2]) + 1) | |
1373 | return \"mov.%d1 %R0,%R2\;mov.%d1 %0,%2\"; | |
1374 | else | |
1375 | return \"mov.%d1 %0,%2\;mov.%d1 %R0,%R2\"; | |
1376 | case 1 : | |
1377 | return \"mov.%d1 %L0,%L2\;mov.%d1 %H0,%H2; %A2 \"; | |
1378 | ||
1379 | } | |
1380 | }" | |
1381 | [(set_attr "type" "cmove,cmove") | |
1382 | (set_attr "length" "8,16")]) | |
1383 | ||
1384 | ||
1385 | (define_insn "*zero_extendqihi2_i" | |
1386 | [(set (match_operand:HI 0 "dest_reg_operand" "=Rcq,Rcq#q,Rcw,w,r") | |
1387 | (zero_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "0,Rcq#q,0,c,m")))] | |
1388 | "" | |
1389 | "@ | |
1390 | extb%? %0,%1%& | |
1391 | extb%? %0,%1%& | |
1392 | bmsk%? %0,%1,7 | |
1393 | extb %0,%1 | |
1394 | ldb%U1 %0,%1" | |
1395 | [(set_attr "type" "unary,unary,unary,unary,load") | |
1396 | (set_attr "iscompact" "maybe,true,false,false,false") | |
1397 | (set_attr "predicable" "no,no,yes,no,no")]) | |
1398 | ||
1399 | (define_expand "zero_extendqihi2" | |
1400 | [(set (match_operand:HI 0 "dest_reg_operand" "") | |
1401 | (zero_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "")))] | |
1402 | "" | |
1403 | "if (prepare_extend_operands (operands, ZERO_EXTEND, HImode)) DONE;" | |
1404 | ) | |
1405 | ||
1406 | (define_insn "*zero_extendqisi2_ac" | |
1407 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq,Rcq#q,Rcw,w,qRcq,!*x,r") | |
1408 | (zero_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "0,Rcq#q,0,c,T,Usd,m")))] | |
1409 | "" | |
1410 | "@ | |
1411 | extb%? %0,%1%& | |
1412 | extb%? %0,%1%& | |
1413 | bmsk%? %0,%1,7 | |
1414 | extb %0,%1 | |
1415 | ldb%? %0,%1%& | |
1416 | ldb%? %0,%1%& | |
1417 | ldb%U1 %0,%1" | |
1418 | [(set_attr "type" "unary,unary,unary,unary,load,load,load") | |
1419 | (set_attr "iscompact" "maybe,true,false,false,true,true,false") | |
1420 | (set_attr "predicable" "no,no,yes,no,no,no,no")]) | |
1421 | ||
1422 | (define_expand "zero_extendqisi2" | |
1423 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
1424 | (zero_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "")))] | |
1425 | "" | |
1426 | "if (prepare_extend_operands (operands, ZERO_EXTEND, SImode)) DONE;" | |
1427 | ) | |
1428 | ||
1429 | (define_insn "*zero_extendhisi2_i" | |
1430 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq,q,Rcw,w,!x,Rcqq,r") | |
1431 | (zero_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "0,q,0,c,Usd,Usd,m")))] | |
1432 | "" | |
1433 | "@ | |
1434 | extw%? %0,%1%& | |
1435 | extw%? %0,%1%& | |
1436 | bmsk%? %0,%1,15 | |
1437 | extw %0,%1 | |
1438 | ldw%? %0,%1%& | |
1439 | ldw%U1 %0,%1 | |
1440 | ldw%U1%V1 %0,%1" | |
1441 | [(set_attr "type" "unary,unary,unary,unary,load,load,load") | |
1442 | (set_attr "iscompact" "maybe,true,false,false,true,false,false") | |
1443 | (set_attr "predicable" "no,no,yes,no,no,no,no")]) | |
1444 | ||
1445 | ||
1446 | (define_expand "zero_extendhisi2" | |
1447 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
1448 | (zero_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "")))] | |
1449 | "" | |
1450 | "if (prepare_extend_operands (operands, ZERO_EXTEND, SImode)) DONE;" | |
1451 | ) | |
1452 | ||
1453 | ;; Sign extension instructions. | |
1454 | ||
1455 | (define_insn "*extendqihi2_i" | |
1456 | [(set (match_operand:HI 0 "dest_reg_operand" "=Rcqq,r,r") | |
1457 | (sign_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "Rcqq,r,m")))] | |
1458 | "" | |
1459 | "@ | |
1460 | sexb%? %0,%1%& | |
1461 | sexb %0,%1 | |
1462 | ldb.x%U1 %0,%1" | |
1463 | [(set_attr "type" "unary,unary,load") | |
1464 | (set_attr "iscompact" "true,false,false")]) | |
1465 | ||
1466 | ||
1467 | (define_expand "extendqihi2" | |
1468 | [(set (match_operand:HI 0 "dest_reg_operand" "") | |
1469 | (sign_extend:HI (match_operand:QI 1 "nonvol_nonimm_operand" "")))] | |
1470 | "" | |
1471 | "if (prepare_extend_operands (operands, SIGN_EXTEND, HImode)) DONE;" | |
1472 | ) | |
1473 | ||
1474 | (define_insn "*extendqisi2_ac" | |
1475 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,w,r") | |
1476 | (sign_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "Rcqq,c,m")))] | |
1477 | "" | |
1478 | "@ | |
1479 | sexb%? %0,%1%& | |
1480 | sexb %0,%1 | |
1481 | ldb.x%U1 %0,%1" | |
1482 | [(set_attr "type" "unary,unary,load") | |
1483 | (set_attr "iscompact" "true,false,false")]) | |
1484 | ||
1485 | (define_expand "extendqisi2" | |
1486 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
1487 | (sign_extend:SI (match_operand:QI 1 "nonvol_nonimm_operand" "")))] | |
1488 | "" | |
1489 | "if (prepare_extend_operands (operands, SIGN_EXTEND, SImode)) DONE;" | |
1490 | ) | |
1491 | ||
1492 | (define_insn "*extendhisi2_i" | |
1493 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,w,r") | |
1494 | (sign_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "Rcqq,c,m")))] | |
1495 | "" | |
1496 | "@ | |
1497 | sexw%? %0,%1%& | |
1498 | sexw %0,%1 | |
1499 | ldw.x%U1%V1 %0,%1" | |
1500 | [(set_attr "type" "unary,unary,load") | |
1501 | (set_attr "iscompact" "true,false,false")]) | |
1502 | ||
1503 | (define_expand "extendhisi2" | |
1504 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
1505 | (sign_extend:SI (match_operand:HI 1 "nonvol_nonimm_operand" "")))] | |
1506 | "" | |
1507 | "if (prepare_extend_operands (operands, SIGN_EXTEND, SImode)) DONE;" | |
1508 | ) | |
1509 | ||
1510 | ;; Unary arithmetic insns | |
1511 | ||
1512 | ;; We allow constant operands to enable late constant propagation, but it is | |
1513 | ;; not worth while to have more than one dedicated alternative to output them - | |
1514 | ;; if we are really worried about getting these the maximum benefit of all | |
1515 | ;; the available alternatives, we should add an extra pass to fold such | |
1516 | ;; operations to movsi. | |
1517 | ||
1518 | ;; Absolute instructions | |
1519 | ||
1520 | (define_insn "*abssi2_mixed" | |
1521 | [(set (match_operand:SI 0 "compact_register_operand" "=q") | |
1522 | (abs:SI (match_operand:SI 1 "compact_register_operand" "q")))] | |
1523 | "TARGET_MIXED_CODE" | |
1524 | "abs%? %0,%1%&" | |
1525 | [(set_attr "type" "two_cycle_core") | |
1526 | (set_attr "iscompact" "true")]) | |
1527 | ||
1528 | (define_insn "abssi2" | |
1529 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq#q,w,w") | |
1530 | (abs:SI (match_operand:SI 1 "nonmemory_operand" "Rcq#q,cL,Cal")))] | |
1531 | "" | |
1532 | "abs%? %0,%1%&" | |
1533 | [(set_attr "type" "two_cycle_core") | |
1534 | (set_attr "length" "*,4,8") | |
1535 | (set_attr "iscompact" "true,false,false")]) | |
1536 | ||
1537 | ;; Maximum and minimum insns | |
1538 | ||
1539 | (define_insn "smaxsi3" | |
1540 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw, w, w") | |
1541 | (smax:SI (match_operand:SI 1 "register_operand" "%0, c, c") | |
1542 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,Cal")))] | |
1543 | "" | |
1544 | "max%? %0,%1,%2" | |
1545 | [(set_attr "type" "two_cycle_core") | |
1546 | (set_attr "length" "4,4,8") | |
1547 | (set_attr "predicable" "yes,no,no")] | |
1548 | ) | |
1549 | ||
1550 | (define_insn "sminsi3" | |
1551 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw, w, w") | |
1552 | (smin:SI (match_operand:SI 1 "register_operand" "%0, c, c") | |
1553 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,Cal")))] | |
1554 | "" | |
1555 | "min%? %0,%1,%2" | |
1556 | [(set_attr "type" "two_cycle_core") | |
1557 | (set_attr "length" "4,4,8") | |
1558 | (set_attr "predicable" "yes,no,no")] | |
1559 | ) | |
1560 | ||
1561 | ;; Arithmetic instructions. | |
1562 | ||
1563 | ; We say an insn can be conditionalized if this doesn't introduce a long | |
1564 | ; immediate. We set the type such that we still have good scheduling if the | |
1565 | ; insn is conditionalized. | |
1566 | ; ??? It would make sense to allow introduction of long immediates, but | |
1567 | ; we'd need to communicate to the ccfsm machinery the extra cost. | |
1568 | ; The alternatives in the constraints still serve three purposes: | |
1569 | ; - estimate insn size assuming conditional execution | |
1570 | ; - guide reload to re-order the second and third operand to get a better fit. | |
1571 | ; - give tentative insn type to guide scheduling | |
1572 | ; N.B. "%" for commutativity doesn't help when there is another matching | |
1573 | ; (but longer) alternative. | |
1574 | ; We avoid letting this pattern use LP_COUNT as a register by specifying | |
1575 | ; register class 'W' instead of 'w'. | |
1576 | (define_insn_and_split "*addsi3_mixed" | |
1577 | ;; 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 | |
1578 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq#q,Rcq,Rcw,Rcw,Rcq,Rcb,Rcq, Rcw, Rcqq,Rcqq, W, W,W, W,Rcqq,Rcw, W") | |
1579 | (plus:SI (match_operand:SI 1 "register_operand" "%0, c, 0, c, 0, 0,Rcb, 0, Rcqq, 0, c, c,0, 0, 0, 0, c") | |
1580 | (match_operand:SI 2 "nonmemory_operand" "cL, 0, cL, 0,CL2,Csp,CM4,cCca,RcqqK, cO,cLCmL,Cca,I,C2a, Cal,Cal,Cal")))] | |
1581 | "" | |
1582 | { | |
1583 | arc_output_addsi (operands, arc_ccfsm_cond_exec_p (), true); | |
1584 | return ""; | |
1585 | } | |
1586 | "&& reload_completed && get_attr_length (insn) == 8 | |
1587 | && satisfies_constraint_I (operands[2]) | |
1588 | && GET_CODE (PATTERN (insn)) != COND_EXEC" | |
1589 | [(set (match_dup 0) (match_dup 3)) (set (match_dup 0) (match_dup 4))] | |
1590 | "split_addsi (operands);" | |
1591 | [(set_attr "type" "*,*,*,*,two_cycle_core,two_cycle_core,*,two_cycle_core,*,*,*,two_cycle_core,*,two_cycle_core,*,*,*") | |
1592 | (set (attr "iscompact") | |
1593 | (cond [(match_test "~arc_output_addsi (operands, false, false) & 2") | |
1594 | (const_string "false") | |
1595 | (match_operand 2 "long_immediate_operand" "") | |
1596 | (const_string "maybe_limm")] | |
1597 | (const_string "maybe"))) | |
1598 | (set_attr "length" "*,*,4,4,*,*,*,4,*,*,4,4,4,4,*,8,8") | |
1599 | (set_attr "predicable" "no,no,yes,yes,no,no,no,yes,no,no,no,no,no,no,no,yes,no") | |
1600 | (set_attr "cond" "canuse,canuse,canuse,canuse,canuse,canuse,nocond,canuse,nocond,nocond,nocond,nocond,canuse_limm,canuse_limm,canuse,canuse,nocond") | |
1601 | ]) | |
1602 | ||
1603 | ;; ARC700/ARC600 multiply | |
1604 | ;; SI <- SI * SI | |
1605 | ||
1606 | (define_expand "mulsi3" | |
1607 | [(set (match_operand:SI 0 "nonimmediate_operand" "") | |
1608 | (mult:SI (match_operand:SI 1 "register_operand" "") | |
1609 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
1610 | "" | |
1611 | { | |
1612 | if (TARGET_ARC700 && !TARGET_NOMPY_SET) | |
1613 | { | |
1614 | if (!register_operand (operands[0], SImode)) | |
1615 | { | |
1616 | rtx result = gen_reg_rtx (SImode); | |
1617 | ||
1618 | emit_insn (gen_mulsi3 (result, operands[1], operands[2])); | |
1619 | emit_move_insn (operands[0], result); | |
1620 | DONE; | |
1621 | } | |
1622 | } | |
1623 | else if (TARGET_MUL64_SET) | |
1624 | { | |
1625 | emit_insn (gen_mulsi_600 (operands[1], operands[2], | |
1626 | gen_mlo (), gen_mhi ())); | |
1627 | emit_move_insn (operands[0], gen_mlo ()); | |
1628 | DONE; | |
1629 | } | |
1630 | else if (TARGET_MULMAC_32BY16_SET) | |
1631 | { | |
1632 | if (immediate_operand (operands[2], SImode) | |
1633 | && INTVAL (operands[2]) >= 0 | |
1634 | && INTVAL (operands[2]) <= 65535) | |
1635 | { | |
1636 | emit_insn (gen_umul_600 (operands[1], operands[2], | |
1637 | gen_acc2 (), gen_acc1 ())); | |
1638 | emit_move_insn (operands[0], gen_acc2 ()); | |
1639 | DONE; | |
1640 | } | |
1641 | operands[2] = force_reg (SImode, operands[2]); | |
1642 | emit_insn (gen_umul_600 (operands[1], operands[2], | |
1643 | gen_acc2 (), gen_acc1 ())); | |
1644 | emit_insn (gen_mac_600 (operands[1], operands[2], | |
1645 | gen_acc2 (), gen_acc1 ())); | |
1646 | emit_move_insn (operands[0], gen_acc2 ()); | |
1647 | DONE; | |
1648 | } | |
1649 | else | |
1650 | { | |
1651 | emit_move_insn (gen_rtx_REG (SImode, R0_REG), operands[1]); | |
1652 | emit_move_insn (gen_rtx_REG (SImode, R1_REG), operands[2]); | |
1653 | emit_insn (gen_mulsi3_600_lib ()); | |
1654 | emit_move_insn (operands[0], gen_rtx_REG (SImode, R0_REG)); | |
1655 | DONE; | |
1656 | } | |
1657 | }) | |
1658 | ||
1659 | ; mululw conditional execution without a LIMM clobbers an input register; | |
1660 | ; we'd need a different pattern to describe this. | |
1661 | ; To make the conditional execution valid for the LIMM alternative, we | |
1662 | ; have to emit the LIMM before the register operand. | |
1663 | (define_insn "umul_600" | |
1664 | [(set (match_operand:SI 2 "acc2_operand" "") | |
1665 | (mult:SI (match_operand:SI 0 "register_operand" "c,c,c") | |
1666 | (zero_extract:SI (match_operand:SI 1 "nonmemory_operand" | |
1667 | "c,L,Cal") | |
1668 | (const_int 16) | |
1669 | (const_int 0)))) | |
1670 | (clobber (match_operand:SI 3 "acc1_operand" ""))] | |
1671 | "TARGET_MULMAC_32BY16_SET" | |
1672 | "@mululw 0, %0, %1 | |
1673 | mululw 0, %0, %1 | |
1674 | mululw%? 0, %1, %0" | |
1675 | [(set_attr "length" "4,4,8") | |
1676 | (set_attr "type" "mulmac_600, mulmac_600, mulmac_600") | |
1677 | (set_attr "predicable" "no, no, yes") | |
1678 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
1679 | ||
1680 | (define_insn "mac_600" | |
1681 | [(set (match_operand:SI 2 "acc2_operand" "") | |
1682 | (plus:SI | |
1683 | (mult:SI (match_operand:SI 0 "register_operand" "c,c,c") | |
1684 | (ashift:SI | |
1685 | (zero_extract:SI (match_operand:SI 1 "nonmemory_operand" "c,L,Cal") | |
1686 | (const_int 16) | |
1687 | (const_int 16)) | |
1688 | (const_int 16))) | |
1689 | (match_dup 2))) | |
1690 | (clobber (match_operand:SI 3 "acc1_operand" ""))] | |
1691 | "TARGET_MULMAC_32BY16_SET" | |
1692 | "machlw%? 0, %0, %1" | |
1693 | [(set_attr "length" "4,4,8") | |
1694 | (set_attr "type" "mulmac_600, mulmac_600, mulmac_600") | |
1695 | (set_attr "predicable" "no, no, yes") | |
1696 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
1697 | ||
1698 | (define_insn "mulsi_600" | |
1699 | [(set (match_operand:SI 2 "mlo_operand" "") | |
73f793e3 | 1700 | (mult:SI (match_operand:SI 0 "register_operand" "%Rcq#q,c,c,c") |
526b7aee SV |
1701 | (match_operand:SI 1 "nonmemory_operand" "Rcq#q,cL,I,Cal"))) |
1702 | (clobber (match_operand:SI 3 "mhi_operand" ""))] | |
1703 | "TARGET_MUL64_SET" | |
1704 | ; The assembler mis-assembles mul64 / mulu64 with "I" constraint constants, | |
1705 | ; using a machine code pattern that only allows "L" constraint constants. | |
1706 | ; "mul64%? \t0, %0, %1%&" | |
1707 | { | |
1708 | if (satisfies_constraint_I (operands[1]) | |
1709 | && !satisfies_constraint_L (operands[1])) | |
1710 | { | |
1711 | /* MUL64 <0,>b,s12 00101bbb10000100 0BBBssssssSSSSSS */ | |
1712 | int n = true_regnum (operands[0]); | |
1713 | int i = INTVAL (operands[1]); | |
1714 | asm_fprintf (asm_out_file, "\t.short %d`", 0x2884 + ((n & 7) << 8)); | |
1715 | asm_fprintf (asm_out_file, "\t.short %d`", | |
1716 | ((i & 0x3f) << 6) + ((i >> 6) & 0x3f) + ((n & 070) << 9)); | |
1717 | return "; mul64%? \t0, %0, %1%&"; | |
1718 | } | |
1719 | return "mul64%? \t0, %0, %1%&"; | |
1720 | } | |
1721 | [(set_attr "length" "*,4,4,8") | |
1722 | (set_attr "iscompact" "maybe,false,false,false") | |
1723 | (set_attr "type" "multi,multi,multi,multi") | |
1724 | (set_attr "predicable" "yes,yes,no,yes") | |
1725 | (set_attr "cond" "canuse,canuse,canuse_limm,canuse")]) | |
1726 | ||
1727 | ; If we compile without an mul option enabled, but link with libraries | |
1728 | ; for a mul option, we'll see clobbers of multiplier output registers. | |
1729 | ; There is also an implementation using norm that clobbers the loop registers. | |
1730 | (define_insn "mulsi3_600_lib" | |
1731 | [(set (reg:SI R0_REG) | |
1732 | (mult:SI (reg:SI R0_REG) (reg:SI R1_REG))) | |
1733 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
1734 | (clobber (reg:SI R1_REG)) | |
1735 | (clobber (reg:SI R2_REG)) | |
1736 | (clobber (reg:SI R3_REG)) | |
1737 | (clobber (reg:DI MUL64_OUT_REG)) | |
1738 | (clobber (reg:SI LP_COUNT)) | |
1739 | (clobber (reg:SI LP_START)) | |
1740 | (clobber (reg:SI LP_END)) | |
1741 | (clobber (reg:CC CC_REG))] | |
1742 | "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET | |
1743 | && (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
1744 | && SFUNC_CHECK_PREDICABLE" | |
1745 | "*return arc_output_libcall (\"__mulsi3\");" | |
1746 | [(set_attr "is_sfunc" "yes") | |
1747 | (set_attr "predicable" "yes")]) | |
1748 | ||
1749 | (define_insn "mulsidi_600" | |
1750 | [(set (reg:DI MUL64_OUT_REG) | |
1751 | (mult:DI (sign_extend:DI | |
73f793e3 | 1752 | (match_operand:SI 0 "register_operand" "%Rcq#q,c,c,c")) |
526b7aee SV |
1753 | (sign_extend:DI |
1754 | ; assembler issue for "I", see mulsi_600 | |
1755 | ; (match_operand:SI 1 "register_operand" "Rcq#q,cL,I,Cal"))))] | |
1756 | (match_operand:SI 1 "register_operand" "Rcq#q,cL,L,C32"))))] | |
1757 | "TARGET_MUL64_SET" | |
1758 | "mul64%? \t0, %0, %1%&" | |
1759 | [(set_attr "length" "*,4,4,8") | |
1760 | (set_attr "iscompact" "maybe,false,false,false") | |
1761 | (set_attr "type" "multi,multi,multi,multi") | |
1762 | (set_attr "predicable" "yes,yes,no,yes") | |
1763 | (set_attr "cond" "canuse,canuse,canuse_limm,canuse")]) | |
1764 | ||
1765 | (define_insn "umulsidi_600" | |
1766 | [(set (reg:DI MUL64_OUT_REG) | |
1767 | (mult:DI (zero_extend:DI | |
73f793e3 | 1768 | (match_operand:SI 0 "register_operand" "%c,c,c")) |
526b7aee SV |
1769 | (sign_extend:DI |
1770 | ; assembler issue for "I", see mulsi_600 | |
1771 | ; (match_operand:SI 1 "register_operand" "cL,I,Cal"))))] | |
1772 | (match_operand:SI 1 "register_operand" "cL,L,C32"))))] | |
1773 | "TARGET_MUL64_SET" | |
1774 | "mulu64%? \t0, %0, %1%&" | |
1775 | [(set_attr "length" "4,4,8") | |
1776 | (set_attr "iscompact" "false") | |
1777 | (set_attr "type" "umulti") | |
1778 | (set_attr "predicable" "yes,no,yes") | |
1779 | (set_attr "cond" "canuse,canuse_limm,canuse")]) | |
1780 | ||
1781 | ; ARC700 mpy* instructions: This is a multi-cycle extension, and thus 'w' | |
1782 | ; may not be used as destination constraint. | |
1783 | ||
1784 | ; The result of mpy and mpyu is the same except for flag setting (if enabled), | |
1785 | ; but mpyu is faster for the standard multiplier. | |
1786 | ; Note: we must make sure LP_COUNT is not one of the destination | |
1787 | ; registers, since it cannot be the destination of a multi-cycle insn | |
1788 | ; like MPY or MPYU. | |
1789 | (define_insn "mulsi3_700" | |
1790 | [(set (match_operand:SI 0 "mpy_dest_reg_operand" "=Rcr,r,r,Rcr,r") | |
1791 | (mult:SI (match_operand:SI 1 "register_operand" " 0,c,0,0,c") | |
1792 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,I,Cal,Cal")))] | |
1793 | "TARGET_ARC700 && !TARGET_NOMPY_SET" | |
1794 | "mpyu%? %0,%1,%2" | |
1795 | [(set_attr "length" "4,4,4,8,8") | |
1796 | (set_attr "type" "umulti") | |
1797 | (set_attr "predicable" "yes,no,no,yes,no") | |
1798 | (set_attr "cond" "canuse,nocond,canuse_limm,canuse,nocond")]) | |
1799 | ||
1800 | (define_expand "mulsidi3" | |
1801 | [(set (match_operand:DI 0 "nonimmediate_operand" "") | |
1802 | (mult:DI (sign_extend:DI(match_operand:SI 1 "register_operand" "")) | |
1803 | (sign_extend:DI(match_operand:SI 2 "nonmemory_operand" ""))))] | |
1804 | "(TARGET_ARC700 && !TARGET_NOMPY_SET) | |
1805 | || TARGET_MUL64_SET | |
1806 | || TARGET_MULMAC_32BY16_SET" | |
1807 | " | |
1808 | { | |
1809 | if (TARGET_ARC700 && !TARGET_NOMPY_SET) | |
1810 | { | |
1811 | operands[2] = force_reg (SImode, operands[2]); | |
1812 | if (!register_operand (operands[0], DImode)) | |
1813 | { | |
1814 | rtx result = gen_reg_rtx (DImode); | |
1815 | ||
1816 | operands[2] = force_reg (SImode, operands[2]); | |
1817 | emit_insn (gen_mulsidi3 (result, operands[1], operands[2])); | |
1818 | emit_move_insn (operands[0], result); | |
1819 | DONE; | |
1820 | } | |
1821 | } | |
1822 | else if (TARGET_MUL64_SET) | |
1823 | { | |
1824 | operands[2] = force_reg (SImode, operands[2]); | |
1825 | emit_insn (gen_mulsidi_600 (operands[1], operands[2])); | |
1826 | emit_move_insn (operands[0], gen_rtx_REG (DImode, MUL64_OUT_REG)); | |
1827 | DONE; | |
1828 | } | |
1829 | else if (TARGET_MULMAC_32BY16_SET) | |
1830 | { | |
1831 | rtx result_hi = gen_highpart(SImode, operands[0]); | |
1832 | rtx result_low = gen_lowpart(SImode, operands[0]); | |
1833 | ||
1834 | emit_insn (gen_mul64_600 (operands[1], operands[2])); | |
1835 | emit_insn (gen_mac64_600 (result_hi, operands[1], operands[2])); | |
1836 | emit_move_insn (result_low, gen_acc2 ()); | |
1837 | DONE; | |
1838 | } | |
1839 | }") | |
1840 | ||
1841 | (define_insn "mul64_600" | |
1842 | [(set (reg:DI 56) | |
1843 | (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" | |
1844 | "c,c,c")) | |
1845 | (zero_extract:DI (match_operand:SI 1 "nonmemory_operand" | |
1846 | "c,L,Cal") | |
1847 | (const_int 16) | |
1848 | (const_int 0)))) | |
1849 | ] | |
1850 | "TARGET_MULMAC_32BY16_SET" | |
1851 | "mullw%? 0, %0, %1" | |
1852 | [(set_attr "length" "4,4,8") | |
1853 | (set_attr "type" "mulmac_600") | |
1854 | (set_attr "predicable" "no,no,yes") | |
1855 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
1856 | ||
1857 | ||
1858 | ;; ??? check if this is canonical rtl | |
1859 | (define_insn "mac64_600" | |
1860 | [(set (reg:DI 56) | |
1861 | (plus:DI | |
1862 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "c,c,c")) | |
1863 | (ashift:DI | |
1864 | (sign_extract:DI (match_operand:SI 2 "nonmemory_operand" "c,L,Cal") | |
1865 | (const_int 16) (const_int 16)) | |
1866 | (const_int 16))) | |
1867 | (reg:DI 56))) | |
1868 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
1869 | (zero_extract:SI | |
1870 | (plus:DI | |
1871 | (mult:DI (sign_extend:DI (match_dup 1)) | |
1872 | (ashift:DI | |
1873 | (sign_extract:DI (match_dup 2) | |
1874 | (const_int 16) (const_int 16)) | |
1875 | (const_int 16))) | |
1876 | (reg:DI 56)) | |
1877 | (const_int 32) (const_int 32)))] | |
1878 | "TARGET_MULMAC_32BY16_SET" | |
1879 | "machlw%? %0, %1, %2" | |
1880 | [(set_attr "length" "4,4,8") | |
1881 | (set_attr "type" "mulmac_600") | |
1882 | (set_attr "predicable" "no,no,yes") | |
1883 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
1884 | ||
1885 | ||
1886 | ;; DI <- DI(signed SI) * DI(signed SI) | |
1887 | (define_insn_and_split "mulsidi3_700" | |
1888 | [(set (match_operand:DI 0 "register_operand" "=&r") | |
1889 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%c")) | |
167ba5b9 | 1890 | (sign_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))] |
526b7aee SV |
1891 | "TARGET_ARC700 && !TARGET_NOMPY_SET" |
1892 | "#" | |
1893 | "&& reload_completed" | |
1894 | [(const_int 0)] | |
1895 | { | |
1896 | int hi = TARGET_BIG_ENDIAN ? 0 : UNITS_PER_WORD; | |
1897 | int lo = TARGET_BIG_ENDIAN ? UNITS_PER_WORD : 0; | |
1898 | rtx l0 = simplify_gen_subreg (word_mode, operands[0], DImode, lo); | |
1899 | rtx h0 = simplify_gen_subreg (word_mode, operands[0], DImode, hi); | |
1900 | emit_insn (gen_mulsi3_highpart (h0, operands[1], operands[2])); | |
1901 | emit_insn (gen_mulsi3_700 (l0, operands[1], operands[2])); | |
1902 | DONE; | |
1903 | } | |
1904 | [(set_attr "type" "multi") | |
1905 | (set_attr "length" "8")]) | |
1906 | ||
1907 | (define_insn "mulsi3_highpart" | |
1908 | [(set (match_operand:SI 0 "register_operand" "=Rcr,r,Rcr,r") | |
1909 | (truncate:SI | |
1910 | (lshiftrt:DI | |
1911 | (mult:DI | |
1912 | (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,c, 0,c")) | |
167ba5b9 | 1913 | (sign_extend:DI (match_operand:SI 2 "extend_operand" "c,c, i,i"))) |
526b7aee SV |
1914 | (const_int 32))))] |
1915 | "TARGET_ARC700 && !TARGET_NOMPY_SET" | |
1916 | "mpyh%? %0,%1,%2" | |
1917 | [(set_attr "length" "4,4,8,8") | |
1918 | (set_attr "type" "multi") | |
1919 | (set_attr "predicable" "yes,no,yes,no") | |
1920 | (set_attr "cond" "canuse,nocond,canuse,nocond")]) | |
1921 | ||
1922 | ; Note that mpyhu has the same latency as mpy / mpyh, | |
1923 | ; thus we use the type multi. | |
1924 | (define_insn "*umulsi3_highpart_i" | |
1925 | [(set (match_operand:SI 0 "register_operand" "=Rcr,r,Rcr,r") | |
1926 | (truncate:SI | |
1927 | (lshiftrt:DI | |
1928 | (mult:DI | |
1929 | (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,c, 0,c")) | |
167ba5b9 | 1930 | (zero_extend:DI (match_operand:SI 2 "extend_operand" "c,c, i,i"))) |
526b7aee SV |
1931 | (const_int 32))))] |
1932 | "TARGET_ARC700 && !TARGET_NOMPY_SET" | |
1933 | "mpyhu%? %0,%1,%2" | |
1934 | [(set_attr "length" "4,4,8,8") | |
1935 | (set_attr "type" "multi") | |
1936 | (set_attr "predicable" "yes,no,yes,no") | |
1937 | (set_attr "cond" "canuse,nocond,canuse,nocond")]) | |
1938 | ||
1939 | ; Implementations include additional labels for umulsidi3, so we got all | |
1940 | ; the same clobbers - plus one for the result low part. */ | |
1941 | (define_insn "umulsi3_highpart_600_lib_le" | |
1942 | [(set (reg:SI R1_REG) | |
1943 | (truncate:SI | |
1944 | (lshiftrt:DI | |
1945 | (mult:DI (zero_extend:DI (reg:SI R0_REG)) | |
1946 | (zero_extend:DI (reg:SI R1_REG))) | |
1947 | (const_int 32)))) | |
1948 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
1949 | (clobber (reg:SI R0_REG)) | |
1950 | (clobber (reg:DI R2_REG)) | |
1951 | (clobber (reg:SI R12_REG)) | |
1952 | (clobber (reg:DI MUL64_OUT_REG)) | |
1953 | (clobber (reg:CC CC_REG))] | |
1954 | "!TARGET_BIG_ENDIAN | |
1955 | && !TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET | |
1956 | && (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
1957 | && SFUNC_CHECK_PREDICABLE" | |
1958 | "*return arc_output_libcall (\"__umulsi3_highpart\");" | |
1959 | [(set_attr "is_sfunc" "yes") | |
1960 | (set_attr "predicable" "yes")]) | |
1961 | ||
1962 | (define_insn "umulsi3_highpart_600_lib_be" | |
1963 | [(set (reg:SI R0_REG) | |
1964 | (truncate:SI | |
1965 | (lshiftrt:DI | |
1966 | (mult:DI (zero_extend:DI (reg:SI R0_REG)) | |
1967 | (zero_extend:DI (reg:SI R1_REG))) | |
1968 | (const_int 32)))) | |
1969 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
1970 | (clobber (reg:SI R1_REG)) | |
1971 | (clobber (reg:DI R2_REG)) | |
1972 | (clobber (reg:SI R12_REG)) | |
1973 | (clobber (reg:DI MUL64_OUT_REG)) | |
1974 | (clobber (reg:CC CC_REG))] | |
1975 | "TARGET_BIG_ENDIAN | |
1976 | && !TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET | |
1977 | && (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
1978 | && SFUNC_CHECK_PREDICABLE" | |
1979 | "*return arc_output_libcall (\"__umulsi3_highpart\");" | |
1980 | [(set_attr "is_sfunc" "yes") | |
1981 | (set_attr "predicable" "yes")]) | |
1982 | ||
1983 | ;; (zero_extend:DI (const_int)) leads to internal errors in combine, so we | |
1984 | ;; need a separate pattern for immediates | |
1985 | ;; ??? This is fine for combine, but not for reload. | |
1986 | (define_insn "umulsi3_highpart_int" | |
1987 | [(set (match_operand:SI 0 "register_operand" "=Rcr, r, r,Rcr, r") | |
1988 | (truncate:SI | |
1989 | (lshiftrt:DI | |
1990 | (mult:DI | |
1991 | (zero_extend:DI (match_operand:SI 1 "register_operand" " 0, c, 0, 0, c")) | |
1992 | (match_operand:DI 2 "immediate_usidi_operand" "L, L, I, Cal, Cal")) | |
1993 | (const_int 32))))] | |
1994 | "TARGET_ARC700 && !TARGET_NOMPY_SET" | |
1995 | "mpyhu%? %0,%1,%2" | |
1996 | [(set_attr "length" "4,4,4,8,8") | |
1997 | (set_attr "type" "multi") | |
1998 | (set_attr "predicable" "yes,no,no,yes,no") | |
1999 | (set_attr "cond" "canuse,nocond,canuse_limm,canuse,nocond")]) | |
2000 | ||
2001 | (define_expand "umulsi3_highpart" | |
2002 | [(set (match_operand:SI 0 "general_operand" "") | |
2003 | (truncate:SI | |
2004 | (lshiftrt:DI | |
2005 | (mult:DI | |
2006 | (zero_extend:DI (match_operand:SI 1 "register_operand" "")) | |
2007 | (zero_extend:DI (match_operand:SI 2 "nonmemory_operand" ""))) | |
2008 | (const_int 32))))] | |
2009 | "TARGET_ARC700 || (!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET)" | |
2010 | " | |
2011 | { | |
2012 | rtx target = operands[0]; | |
2013 | ||
2014 | if (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
2015 | { | |
2016 | emit_move_insn (gen_rtx_REG (SImode, 0), operands[1]); | |
2017 | emit_move_insn (gen_rtx_REG (SImode, 1), operands[2]); | |
2018 | if (TARGET_BIG_ENDIAN) | |
2019 | emit_insn (gen_umulsi3_highpart_600_lib_be ()); | |
2020 | else | |
2021 | emit_insn (gen_umulsi3_highpart_600_lib_le ()); | |
2022 | emit_move_insn (target, gen_rtx_REG (SImode, 0)); | |
2023 | DONE; | |
2024 | } | |
2025 | ||
2026 | if (!register_operand (target, SImode)) | |
2027 | target = gen_reg_rtx (SImode); | |
2028 | ||
2029 | if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) | |
2030 | operands[2] = simplify_const_unary_operation (ZERO_EXTEND, DImode, | |
2031 | operands[2], SImode); | |
2032 | else if (!immediate_operand (operands[2], SImode)) | |
2033 | operands[2] = gen_rtx_ZERO_EXTEND (DImode, operands[2]); | |
2034 | emit_insn (gen_umulsi3_highpart_int (target, operands[1], operands[2])); | |
2035 | if (target != operands[0]) | |
2036 | emit_move_insn (operands[0], target); | |
2037 | DONE; | |
2038 | }") | |
2039 | ||
2040 | (define_expand "umulsidi3" | |
2041 | [(set (match_operand:DI 0 "nonimmediate_operand" "") | |
2042 | (mult:DI (zero_extend:DI(match_operand:SI 1 "register_operand" "")) | |
2043 | (zero_extend:DI(match_operand:SI 2 "nonmemory_operand" ""))))] | |
2044 | "" | |
2045 | { | |
2046 | if (TARGET_ARC700 && !TARGET_NOMPY_SET) | |
2047 | { | |
2048 | operands[2] = force_reg (SImode, operands[2]); | |
2049 | if (!register_operand (operands[0], DImode)) | |
2050 | { | |
2051 | rtx result = gen_reg_rtx (DImode); | |
2052 | ||
2053 | emit_insn (gen_umulsidi3 (result, operands[1], operands[2])); | |
2054 | emit_move_insn (operands[0], result); | |
2055 | DONE; | |
2056 | } | |
2057 | } | |
2058 | else if (TARGET_MUL64_SET) | |
2059 | { | |
2060 | operands[2] = force_reg (SImode, operands[2]); | |
2061 | emit_insn (gen_umulsidi_600 (operands[1], operands[2])); | |
2062 | emit_move_insn (operands[0], gen_rtx_REG (DImode, MUL64_OUT_REG)); | |
2063 | DONE; | |
2064 | } | |
2065 | else if (TARGET_MULMAC_32BY16_SET) | |
2066 | { | |
2067 | rtx result_hi = gen_reg_rtx (SImode); | |
2068 | rtx result_low = gen_reg_rtx (SImode); | |
2069 | ||
2070 | result_hi = gen_highpart(SImode , operands[0]); | |
2071 | result_low = gen_lowpart(SImode , operands[0]); | |
2072 | ||
2073 | emit_insn (gen_umul64_600 (operands[1], operands[2])); | |
2074 | emit_insn (gen_umac64_600 (result_hi, operands[1], operands[2])); | |
2075 | emit_move_insn (result_low, gen_acc2 ()); | |
2076 | DONE; | |
2077 | } | |
2078 | else | |
2079 | { | |
2080 | emit_move_insn (gen_rtx_REG (SImode, R0_REG), operands[1]); | |
2081 | emit_move_insn (gen_rtx_REG (SImode, R1_REG), operands[2]); | |
2082 | emit_insn (gen_umulsidi3_600_lib ()); | |
2083 | emit_move_insn (operands[0], gen_rtx_REG (DImode, R0_REG)); | |
2084 | DONE; | |
2085 | } | |
2086 | }) | |
2087 | ||
2088 | (define_insn "umul64_600" | |
2089 | [(set (reg:DI 56) | |
2090 | (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" | |
2091 | "c,c,c")) | |
2092 | (zero_extract:DI (match_operand:SI 1 "nonmemory_operand" | |
2093 | "c,L,Cal") | |
2094 | (const_int 16) | |
2095 | (const_int 0)))) | |
2096 | ] | |
2097 | "TARGET_MULMAC_32BY16_SET" | |
2098 | "@mululw 0, %0, %1 | |
2099 | mululw 0, %0, %1 | |
2100 | mululw%? 0, %1, %0" | |
2101 | [(set_attr "length" "4,4,8") | |
2102 | (set_attr "type" "mulmac_600") | |
2103 | (set_attr "predicable" "no,no,yes") | |
2104 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
2105 | ||
2106 | ||
2107 | (define_insn "umac64_600" | |
2108 | [(set (reg:DI 56) | |
2109 | (plus:DI | |
2110 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "c,c,c")) | |
2111 | (ashift:DI | |
2112 | (zero_extract:DI (match_operand:SI 2 "nonmemory_operand" "c,L,Cal") | |
2113 | (const_int 16) (const_int 16)) | |
2114 | (const_int 16))) | |
2115 | (reg:DI 56))) | |
2116 | (set (match_operand:SI 0 "register_operand" "=w,w,w") | |
2117 | (zero_extract:SI | |
2118 | (plus:DI | |
2119 | (mult:DI (zero_extend:DI (match_dup 1)) | |
2120 | (ashift:DI | |
2121 | (zero_extract:DI (match_dup 2) | |
2122 | (const_int 16) (const_int 16)) | |
2123 | (const_int 16))) | |
2124 | (reg:DI 56)) | |
2125 | (const_int 32) (const_int 32)))] | |
2126 | "TARGET_MULMAC_32BY16_SET" | |
2127 | "machulw%? %0, %1, %2" | |
2128 | [(set_attr "length" "4,4,8") | |
2129 | (set_attr "type" "mulmac_600") | |
2130 | (set_attr "predicable" "no,no,yes") | |
2131 | (set_attr "cond" "nocond, canuse_limm, canuse")]) | |
2132 | ||
2133 | ||
2134 | ||
2135 | ;; DI <- DI(unsigned SI) * DI(unsigned SI) | |
2136 | (define_insn_and_split "umulsidi3_700" | |
2137 | [(set (match_operand:DI 0 "dest_reg_operand" "=&r") | |
2138 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%c")) | |
167ba5b9 | 2139 | (zero_extend:DI (match_operand:SI 2 "extend_operand" "cL"))))] |
526b7aee SV |
2140 | "TARGET_ARC700 && !TARGET_NOMPY_SET" |
2141 | "#" | |
2142 | "reload_completed" | |
2143 | [(const_int 0)] | |
2144 | { | |
2145 | int hi = !TARGET_BIG_ENDIAN; | |
2146 | int lo = !hi; | |
2147 | rtx l0 = operand_subword (operands[0], lo, 0, DImode); | |
2148 | rtx h0 = operand_subword (operands[0], hi, 0, DImode); | |
2149 | emit_insn (gen_umulsi3_highpart (h0, operands[1], operands[2])); | |
2150 | emit_insn (gen_mulsi3_700 (l0, operands[1], operands[2])); | |
2151 | DONE; | |
2152 | } | |
2153 | [(set_attr "type" "umulti") | |
2154 | (set_attr "length" "8")]) | |
2155 | ||
2156 | (define_insn "umulsidi3_600_lib" | |
2157 | [(set (reg:DI R0_REG) | |
2158 | (mult:DI (zero_extend:DI (reg:SI R0_REG)) | |
2159 | (zero_extend:DI (reg:SI R1_REG)))) | |
2160 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
2161 | (clobber (reg:DI R2_REG)) | |
2162 | (clobber (reg:SI R12_REG)) | |
2163 | (clobber (reg:DI MUL64_OUT_REG)) | |
2164 | (clobber (reg:CC CC_REG))] | |
2165 | "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET | |
2166 | && (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
2167 | && SFUNC_CHECK_PREDICABLE" | |
2168 | "*return arc_output_libcall (\"__umulsidi3\");" | |
2169 | [(set_attr "is_sfunc" "yes") | |
2170 | (set_attr "predicable" "yes")]) | |
2171 | ||
2172 | (define_peephole2 | |
2173 | [(parallel | |
2174 | [(set (reg:DI R0_REG) | |
2175 | (mult:DI (zero_extend:DI (reg:SI R0_REG)) | |
2176 | (zero_extend:DI (reg:SI R1_REG)))) | |
2177 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
2178 | (clobber (reg:DI R2_REG)) | |
2179 | (clobber (reg:SI R12_REG)) | |
2180 | (clobber (reg:DI MUL64_OUT_REG)) | |
2181 | (clobber (reg:CC CC_REG))])] | |
2182 | "!TARGET_MUL64_SET && !TARGET_MULMAC_32BY16_SET | |
2183 | && (!TARGET_ARC700 || TARGET_NOMPY_SET) | |
2184 | && peep2_regno_dead_p (1, TARGET_BIG_ENDIAN ? R1_REG : R0_REG)" | |
2185 | [(pc)] | |
2186 | { | |
2187 | if (TARGET_BIG_ENDIAN) | |
2188 | emit_insn (gen_umulsi3_highpart_600_lib_be ()); | |
2189 | else | |
2190 | emit_insn (gen_umulsi3_highpart_600_lib_le ()); | |
2191 | DONE; | |
2192 | }) | |
2193 | ||
2194 | (define_expand "addsi3" | |
2195 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2196 | (plus:SI (match_operand:SI 1 "register_operand" "") | |
2197 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2198 | "" | |
2199 | "if (flag_pic && arc_raw_symbolic_reference_mentioned_p (operands[2], false)) | |
2200 | { | |
2201 | operands[2]=force_reg(SImode, operands[2]); | |
2202 | } | |
2203 | else if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[2], Pmode)) | |
2204 | { | |
2205 | operands[2] = force_reg (SImode, arc_rewrite_small_data (operands[2])); | |
2206 | } | |
2207 | ||
2208 | ") | |
2209 | ||
2210 | (define_expand "adddi3" | |
2211 | [(parallel [(set (match_operand:DI 0 "dest_reg_operand" "") | |
2212 | (plus:DI (match_operand:DI 1 "register_operand" "") | |
2213 | (match_operand:DI 2 "nonmemory_operand" ""))) | |
2214 | (clobber (reg:CC CC_REG))])] | |
2215 | "" | |
2216 | { | |
2217 | if (TARGET_EXPAND_ADDDI) | |
2218 | { | |
2219 | rtx l0 = gen_lowpart (SImode, operands[0]); | |
2220 | rtx h0 = disi_highpart (operands[0]); | |
2221 | rtx l1 = gen_lowpart (SImode, operands[1]); | |
2222 | rtx h1 = disi_highpart (operands[1]); | |
2223 | rtx l2 = gen_lowpart (SImode, operands[2]); | |
2224 | rtx h2 = disi_highpart (operands[2]); | |
2225 | rtx cc_c = gen_rtx_REG (CC_Cmode, CC_REG); | |
2226 | ||
2227 | if (CONST_INT_P (h2) && INTVAL (h2) < 0 && SIGNED_INT12 (INTVAL (h2))) | |
2228 | { | |
2229 | emit_insn (gen_sub_f (l0, l1, gen_int_mode (-INTVAL (l2), SImode))); | |
2230 | emit_insn (gen_sbc (h0, h1, | |
2231 | gen_int_mode (-INTVAL (h2) - (l1 != 0), SImode), | |
2232 | cc_c)); | |
2233 | DONE; | |
2234 | } | |
2235 | emit_insn (gen_add_f (l0, l1, l2)); | |
2236 | emit_insn (gen_adc (h0, h1, h2)); | |
2237 | DONE; | |
2238 | } | |
2239 | }) | |
2240 | ||
2241 | ; This assumes that there can be no strictly partial overlap between | |
2242 | ; operands[1] and operands[2]. | |
2243 | (define_insn_and_split "*adddi3_i" | |
2244 | [(set (match_operand:DI 0 "dest_reg_operand" "=&w,w,w") | |
2245 | (plus:DI (match_operand:DI 1 "register_operand" "%c,0,c") | |
2246 | (match_operand:DI 2 "nonmemory_operand" "ci,ci,!i"))) | |
2247 | (clobber (reg:CC CC_REG))] | |
2248 | "" | |
2249 | "#" | |
2250 | "reload_completed" | |
2251 | [(const_int 0)] | |
2252 | { | |
2253 | int hi = !TARGET_BIG_ENDIAN; | |
2254 | int lo = !hi; | |
2255 | rtx l0 = operand_subword (operands[0], lo, 0, DImode); | |
2256 | rtx h0 = operand_subword (operands[0], hi, 0, DImode); | |
2257 | rtx l1 = operand_subword (operands[1], lo, 0, DImode); | |
2258 | rtx h1 = operand_subword (operands[1], hi, 0, DImode); | |
2259 | rtx l2 = operand_subword (operands[2], lo, 0, DImode); | |
2260 | rtx h2 = operand_subword (operands[2], hi, 0, DImode); | |
2261 | ||
2262 | ||
2263 | if (l2 == const0_rtx) | |
2264 | { | |
2265 | if (!rtx_equal_p (l0, l1) && !rtx_equal_p (l0, h1)) | |
2266 | emit_move_insn (l0, l1); | |
2267 | emit_insn (gen_addsi3 (h0, h1, h2)); | |
2268 | if (!rtx_equal_p (l0, l1) && rtx_equal_p (l0, h1)) | |
2269 | emit_move_insn (l0, l1); | |
2270 | DONE; | |
2271 | } | |
2272 | if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0 | |
2273 | && INTVAL (operands[2]) >= -0x7fffffff) | |
2274 | { | |
2275 | emit_insn (gen_subdi3_i (operands[0], operands[1], | |
2276 | GEN_INT (-INTVAL (operands[2])))); | |
2277 | DONE; | |
2278 | } | |
2279 | if (rtx_equal_p (l0, h1)) | |
2280 | { | |
2281 | if (h2 != const0_rtx) | |
2282 | emit_insn (gen_addsi3 (h0, h1, h2)); | |
2283 | else if (!rtx_equal_p (h0, h1)) | |
2284 | emit_move_insn (h0, h1); | |
2285 | emit_insn (gen_add_f (l0, l1, l2)); | |
2286 | emit_insn | |
2287 | (gen_rtx_COND_EXEC | |
2288 | (VOIDmode, | |
2289 | gen_rtx_LTU (VOIDmode, gen_rtx_REG (CC_Cmode, CC_REG), GEN_INT (0)), | |
f7df4a84 | 2290 | gen_rtx_SET (h0, plus_constant (SImode, h0, 1)))); |
526b7aee SV |
2291 | DONE; |
2292 | } | |
2293 | emit_insn (gen_add_f (l0, l1, l2)); | |
2294 | emit_insn (gen_adc (h0, h1, h2)); | |
2295 | DONE; | |
2296 | } | |
2297 | [(set_attr "cond" "clob") | |
2298 | (set_attr "type" "binary") | |
2299 | (set_attr "length" "16,16,20")]) | |
2300 | ||
2301 | (define_insn "add_f" | |
2302 | [(set (reg:CC_C CC_REG) | |
2303 | (compare:CC_C | |
2304 | (plus:SI (match_operand:SI 1 "register_operand" "c,0,c") | |
2305 | (match_operand:SI 2 "nonmemory_operand" "cL,I,cCal")) | |
2306 | (match_dup 1))) | |
2307 | (set (match_operand:SI 0 "dest_reg_operand" "=w,Rcw,w") | |
2308 | (plus:SI (match_dup 1) (match_dup 2)))] | |
2309 | "" | |
2310 | "add.f %0,%1,%2" | |
2311 | [(set_attr "cond" "set") | |
2312 | (set_attr "type" "compare") | |
2313 | (set_attr "length" "4,4,8")]) | |
2314 | ||
2315 | (define_insn "*add_f_2" | |
2316 | [(set (reg:CC_C CC_REG) | |
2317 | (compare:CC_C | |
2318 | (plus:SI (match_operand:SI 1 "register_operand" "c,0,c") | |
2319 | (match_operand:SI 2 "nonmemory_operand" "cL,I,cCal")) | |
2320 | (match_dup 2))) | |
2321 | (set (match_operand:SI 0 "dest_reg_operand" "=w,Rcw,w") | |
2322 | (plus:SI (match_dup 1) (match_dup 2)))] | |
2323 | "" | |
2324 | "add.f %0,%1,%2" | |
2325 | [(set_attr "cond" "set") | |
2326 | (set_attr "type" "compare") | |
2327 | (set_attr "length" "4,4,8")]) | |
2328 | ||
2329 | ; w/c/c comes first (rather than w/0/C_0) to prevent the middle-end | |
2330 | ; needlessly prioritizing the matching constraint. | |
2331 | ; Rcw/0/C_0 comes before w/c/L so that the lower latency conditional | |
2332 | ; execution is used where possible. | |
2333 | (define_insn_and_split "adc" | |
2334 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,Rcw,w,Rcw,w") | |
2335 | (plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REG) (const_int 0)) | |
2336 | (match_operand:SI 1 "nonmemory_operand" | |
2337 | "%c,0,c,0,cCal")) | |
2338 | (match_operand:SI 2 "nonmemory_operand" "c,C_0,L,I,cCal")))] | |
2339 | "register_operand (operands[1], SImode) | |
2340 | || register_operand (operands[2], SImode)" | |
2341 | "@ | |
2342 | adc %0,%1,%2 | |
2343 | add.cs %0,%1,1 | |
2344 | adc %0,%1,%2 | |
2345 | adc %0,%1,%2 | |
2346 | adc %0,%1,%2" | |
2347 | ; if we have a bad schedule after sched2, split. | |
2348 | "reload_completed | |
2349 | && !optimize_size && TARGET_ARC700 | |
2350 | && arc_scheduling_not_expected () | |
2351 | && arc_sets_cc_p (prev_nonnote_insn (insn)) | |
2352 | /* If next comes a return or other insn that needs a delay slot, | |
2353 | expect the adc to get into the delay slot. */ | |
2354 | && next_nonnote_insn (insn) | |
2355 | && !arc_need_delay (next_nonnote_insn (insn)) | |
2356 | /* Restore operands before emitting. */ | |
2357 | && (extract_insn_cached (insn), 1)" | |
2358 | [(set (match_dup 0) (match_dup 3)) | |
2359 | (cond_exec | |
2360 | (ltu (reg:CC_C CC_REG) (const_int 0)) | |
2361 | (set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))))] | |
2362 | "operands[3] = simplify_gen_binary (PLUS, SImode, operands[1], operands[2]);" | |
2363 | [(set_attr "cond" "use") | |
2364 | (set_attr "type" "cc_arith") | |
2365 | (set_attr "length" "4,4,4,4,8")]) | |
2366 | ||
2367 | ; combiner-splitter cmp / scc -> cmp / adc | |
2368 | (define_split | |
2369 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2370 | (gtu:SI (match_operand:SI 1 "register_operand" "") | |
2371 | (match_operand:SI 2 "register_operand" ""))) | |
2372 | (clobber (reg CC_REG))] | |
2373 | "" | |
2374 | [(set (reg:CC_C CC_REG) (compare:CC_C (match_dup 2) (match_dup 1))) | |
2375 | (set (match_dup 0) (ltu:SI (reg:CC_C CC_REG) (const_int 0)))]) | |
2376 | ||
2377 | ; combine won't work when an intermediate result is used later... | |
2378 | ; add %0,%1,%2 ` cmp %0,%[12] -> add.f %0,%1,%2 | |
2379 | (define_peephole2 | |
2380 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2381 | (plus:SI (match_operand:SI 1 "register_operand" "") | |
2382 | (match_operand:SI 2 "nonmemory_operand" ""))) | |
2383 | (set (reg:CC_C CC_REG) | |
2384 | (compare:CC_C (match_dup 0) | |
2385 | (match_operand:SI 3 "nonmemory_operand" "")))] | |
2386 | "rtx_equal_p (operands[1], operands[3]) | |
2387 | || rtx_equal_p (operands[2], operands[3])" | |
2388 | [(parallel | |
2389 | [(set (reg:CC_C CC_REG) | |
2390 | (compare:CC_C (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1))) | |
2391 | (set (match_dup 0) | |
2392 | (plus:SI (match_dup 1) (match_dup 2)))])]) | |
2393 | ||
f55d4a20 JR |
2394 | ; ??? need to delve into combine to find out why this is not useful. |
2395 | ; We'd like to be able to grok various C idioms for carry bit usage. | |
526b7aee SV |
2396 | ;(define_insn "*adc_0" |
2397 | ; [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
2398 | ; (plus:SI (ltu:SI (reg:CC_C CC_REG) (const_int 0)) | |
2399 | ; (match_operand:SI 1 "register_operand" "c")))] | |
2400 | ; "" | |
2401 | ; "adc %0,%1,0" | |
2402 | ; [(set_attr "cond" "use") | |
2403 | ; (set_attr "type" "cc_arith") | |
2404 | ; (set_attr "length" "4")]) | |
2405 | ; | |
2406 | ;(define_split | |
2407 | ; [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
2408 | ; (plus:SI (gtu:SI (match_operand:SI 1 "register_operand" "c") | |
2409 | ; (match_operand:SI 2 "register_operand" "c")) | |
2410 | ; (match_operand:SI 3 "register_operand" "c"))) | |
2411 | ; (clobber (reg CC_REG))] | |
2412 | ; "" | |
2413 | ; [(set (reg:CC_C CC_REG) (compare:CC_C (match_dup 2) (match_dup 1))) | |
2414 | ; (set (match_dup 0) | |
2415 | ; (plus:SI (ltu:SI (reg:CC_C CC_REG) (const_int 0)) | |
2416 | ; (match_dup 3)))]) | |
2417 | ||
2418 | (define_expand "subsi3" | |
2419 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2420 | (minus:SI (match_operand:SI 1 "nonmemory_operand" "") | |
2421 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2422 | "" | |
2423 | " | |
2424 | { | |
2425 | int c = 1; | |
2426 | ||
2427 | if (!register_operand (operands[2], SImode)) | |
2428 | { | |
2429 | operands[1] = force_reg (SImode, operands[1]); | |
2430 | c = 2; | |
2431 | } | |
2432 | if (flag_pic && arc_raw_symbolic_reference_mentioned_p (operands[c], false)) | |
2433 | operands[c] = force_reg (SImode, operands[c]); | |
2434 | else if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[c], Pmode)) | |
2435 | operands[c] = force_reg (SImode, arc_rewrite_small_data (operands[c])); | |
2436 | }") | |
2437 | ||
2438 | ; the casesi expander might generate a sub of zero, so we have to recognize it. | |
2439 | ; combine should make such an insn go away. | |
2440 | (define_insn_and_split "subsi3_insn" | |
2441 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcw,Rcw,w,w,w, w, w, w") | |
2442 | (minus:SI (match_operand:SI 1 "nonmemory_operand" "0, 0, cL,c,L,I,Cal,Cal, c") | |
2443 | (match_operand:SI 2 "nonmemory_operand" "Rcqq, c, 0,c,c,0, 0, c,Cal")))] | |
2444 | "register_operand (operands[1], SImode) | |
2445 | || register_operand (operands[2], SImode)" | |
2446 | "@ | |
2447 | sub%? %0,%1,%2%& | |
2448 | sub%? %0,%1,%2 | |
2449 | rsub%? %0,%2,%1 | |
2450 | sub %0,%1,%2 | |
2451 | rsub %0,%2,%1 | |
2452 | rsub %0,%2,%1 | |
2453 | rsub%? %0,%2,%1 | |
2454 | rsub %0,%2,%1 | |
2455 | sub %0,%1,%2" | |
2456 | "reload_completed && get_attr_length (insn) == 8 | |
2457 | && satisfies_constraint_I (operands[1]) | |
2458 | && GET_CODE (PATTERN (insn)) != COND_EXEC" | |
2459 | [(set (match_dup 0) (match_dup 3)) (set (match_dup 0) (match_dup 4))] | |
2460 | "split_subsi (operands);" | |
2461 | [(set_attr "iscompact" "maybe,false,false,false,false,false,false,false, false") | |
2462 | (set_attr "length" "*,4,4,4,4,4,8,8,8") | |
2463 | (set_attr "predicable" "yes,yes,yes,no,no,no,yes,no,no") | |
2464 | (set_attr "cond" "canuse,canuse,canuse,nocond,nocond,canuse_limm,canuse,nocond,nocond")]) | |
2465 | ||
2466 | (define_expand "subdi3" | |
2467 | [(parallel [(set (match_operand:DI 0 "dest_reg_operand" "") | |
2468 | (minus:DI (match_operand:DI 1 "nonmemory_operand" "") | |
2469 | (match_operand:DI 2 "nonmemory_operand" ""))) | |
2470 | (clobber (reg:CC CC_REG))])] | |
2471 | "" | |
2472 | { | |
2473 | if (!register_operand (operands[2], DImode)) | |
2474 | operands[1] = force_reg (DImode, operands[1]); | |
2475 | if (TARGET_EXPAND_ADDDI) | |
2476 | { | |
2477 | rtx l0 = gen_lowpart (SImode, operands[0]); | |
2478 | rtx h0 = disi_highpart (operands[0]); | |
2479 | rtx l1 = gen_lowpart (SImode, operands[1]); | |
2480 | rtx h1 = disi_highpart (operands[1]); | |
2481 | rtx l2 = gen_lowpart (SImode, operands[2]); | |
2482 | rtx h2 = disi_highpart (operands[2]); | |
2483 | rtx cc_c = gen_rtx_REG (CC_Cmode, CC_REG); | |
2484 | ||
2485 | emit_insn (gen_sub_f (l0, l1, l2)); | |
2486 | emit_insn (gen_sbc (h0, h1, h2, cc_c)); | |
2487 | DONE; | |
2488 | } | |
2489 | }) | |
2490 | ||
2491 | (define_insn_and_split "subdi3_i" | |
2492 | [(set (match_operand:DI 0 "dest_reg_operand" "=&w,w,w,w,w") | |
2493 | (minus:DI (match_operand:DI 1 "nonmemory_operand" "ci,0,ci,c,!i") | |
2494 | (match_operand:DI 2 "nonmemory_operand" "ci,ci,0,!i,c"))) | |
2495 | (clobber (reg:CC CC_REG))] | |
2496 | "register_operand (operands[1], DImode) | |
2497 | || register_operand (operands[2], DImode)" | |
2498 | "#" | |
2499 | "reload_completed" | |
2500 | [(const_int 0)] | |
2501 | { | |
2502 | int hi = !TARGET_BIG_ENDIAN; | |
2503 | int lo = !hi; | |
2504 | rtx l0 = operand_subword (operands[0], lo, 0, DImode); | |
2505 | rtx h0 = operand_subword (operands[0], hi, 0, DImode); | |
2506 | rtx l1 = operand_subword (operands[1], lo, 0, DImode); | |
2507 | rtx h1 = operand_subword (operands[1], hi, 0, DImode); | |
2508 | rtx l2 = operand_subword (operands[2], lo, 0, DImode); | |
2509 | rtx h2 = operand_subword (operands[2], hi, 0, DImode); | |
2510 | ||
2511 | if (rtx_equal_p (l0, h1) || rtx_equal_p (l0, h2)) | |
2512 | { | |
2513 | h1 = simplify_gen_binary (MINUS, SImode, h1, h2); | |
2514 | if (!rtx_equal_p (h0, h1)) | |
f7df4a84 | 2515 | emit_insn (gen_rtx_SET (h0, h1)); |
526b7aee SV |
2516 | emit_insn (gen_sub_f (l0, l1, l2)); |
2517 | emit_insn | |
2518 | (gen_rtx_COND_EXEC | |
2519 | (VOIDmode, | |
2520 | gen_rtx_LTU (VOIDmode, gen_rtx_REG (CC_Cmode, CC_REG), GEN_INT (0)), | |
f7df4a84 | 2521 | gen_rtx_SET (h0, plus_constant (SImode, h0, -1)))); |
526b7aee SV |
2522 | DONE; |
2523 | } | |
2524 | emit_insn (gen_sub_f (l0, l1, l2)); | |
2525 | emit_insn (gen_sbc (h0, h1, h2, gen_rtx_REG (CCmode, CC_REG))); | |
2526 | DONE; | |
2527 | } | |
2528 | [(set_attr "cond" "clob") | |
2529 | (set_attr "length" "16,16,16,20,20")]) | |
2530 | ||
2531 | (define_insn "*sbc_0" | |
2532 | [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
2533 | (minus:SI (match_operand:SI 1 "register_operand" "c") | |
2534 | (ltu:SI (match_operand:CC_C 2 "cc_use_register") | |
2535 | (const_int 0))))] | |
2536 | "" | |
2537 | "sbc %0,%1,0" | |
2538 | [(set_attr "cond" "use") | |
2539 | (set_attr "type" "cc_arith") | |
2540 | (set_attr "length" "4")]) | |
2541 | ||
2542 | ; w/c/c comes first (rather than Rcw/0/C_0) to prevent the middle-end | |
2543 | ; needlessly prioritizing the matching constraint. | |
2544 | ; Rcw/0/C_0 comes before w/c/L so that the lower latency conditional execution | |
2545 | ; is used where possible. | |
2546 | (define_insn_and_split "sbc" | |
2547 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,Rcw,w,Rcw,w") | |
2548 | (minus:SI (minus:SI (match_operand:SI 1 "nonmemory_operand" | |
2549 | "c,0,c,0,cCal") | |
2550 | (ltu:SI (match_operand:CC_C 3 "cc_use_register") | |
2551 | (const_int 0))) | |
2552 | (match_operand:SI 2 "nonmemory_operand" "c,C_0,L,I,cCal")))] | |
2553 | "register_operand (operands[1], SImode) | |
2554 | || register_operand (operands[2], SImode)" | |
2555 | "@ | |
2556 | sbc %0,%1,%2 | |
2557 | sub.cs %0,%1,1 | |
2558 | sbc %0,%1,%2 | |
2559 | sbc %0,%1,%2 | |
2560 | sbc %0,%1,%2" | |
2561 | ; if we have a bad schedule after sched2, split. | |
2562 | "reload_completed | |
2563 | && !optimize_size && TARGET_ARC700 | |
2564 | && arc_scheduling_not_expected () | |
2565 | && arc_sets_cc_p (prev_nonnote_insn (insn)) | |
2566 | /* If next comes a return or other insn that needs a delay slot, | |
2567 | expect the adc to get into the delay slot. */ | |
2568 | && next_nonnote_insn (insn) | |
2569 | && !arc_need_delay (next_nonnote_insn (insn)) | |
2570 | /* Restore operands before emitting. */ | |
2571 | && (extract_insn_cached (insn), 1)" | |
2572 | [(set (match_dup 0) (match_dup 4)) | |
2573 | (cond_exec | |
2574 | (ltu (reg:CC_C CC_REG) (const_int 0)) | |
2575 | (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))))] | |
2576 | "operands[4] = simplify_gen_binary (MINUS, SImode, operands[1], operands[2]);" | |
2577 | [(set_attr "cond" "use") | |
2578 | (set_attr "type" "cc_arith") | |
2579 | (set_attr "length" "4,4,4,4,8")]) | |
2580 | ||
2581 | (define_insn "sub_f" | |
2582 | [(set (reg:CC CC_REG) | |
2583 | (compare:CC (match_operand:SI 1 "nonmemory_operand" " c,L,0,I,c,Cal") | |
2584 | (match_operand:SI 2 "nonmemory_operand" "cL,c,I,0,Cal,c"))) | |
2585 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w,Rcw,Rcw,w,w") | |
2586 | (minus:SI (match_dup 1) (match_dup 2)))] | |
2587 | "register_operand (operands[1], SImode) | |
2588 | || register_operand (operands[2], SImode)" | |
2589 | "@ | |
2590 | sub.f %0,%1,%2 | |
2591 | rsub.f %0,%2,%1 | |
2592 | sub.f %0,%1,%2 | |
2593 | rsub.f %0,%2,%1 | |
2594 | sub.f %0,%1,%2 | |
2595 | sub.f %0,%1,%2" | |
2596 | [(set_attr "type" "compare") | |
2597 | (set_attr "length" "4,4,4,4,8,8")]) | |
2598 | ||
2599 | ; combine won't work when an intermediate result is used later... | |
2600 | ; add %0,%1,%2 ` cmp %0,%[12] -> add.f %0,%1,%2 | |
2601 | (define_peephole2 | |
2602 | [(set (reg:CC CC_REG) | |
2603 | (compare:CC (match_operand:SI 1 "register_operand" "") | |
2604 | (match_operand:SI 2 "nonmemory_operand" ""))) | |
2605 | (set (match_operand:SI 0 "dest_reg_operand" "") | |
2606 | (minus:SI (match_dup 1) (match_dup 2)))] | |
2607 | "" | |
2608 | [(parallel | |
2609 | [(set (reg:CC CC_REG) (compare:CC (match_dup 1) (match_dup 2))) | |
2610 | (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])]) | |
2611 | ||
2612 | (define_peephole2 | |
2613 | [(set (reg:CC CC_REG) | |
2614 | (compare:CC (match_operand:SI 1 "register_operand" "") | |
2615 | (match_operand:SI 2 "nonmemory_operand" ""))) | |
2616 | (set (match_operand 3 "" "") (match_operand 4 "" "")) | |
2617 | (set (match_operand:SI 0 "dest_reg_operand" "") | |
2618 | (minus:SI (match_dup 1) (match_dup 2)))] | |
2619 | "!reg_overlap_mentioned_p (operands[3], operands[1]) | |
2620 | && !reg_overlap_mentioned_p (operands[3], operands[2]) | |
2621 | && !reg_overlap_mentioned_p (operands[0], operands[4]) | |
2622 | && !reg_overlap_mentioned_p (operands[0], operands[3])" | |
2623 | [(parallel | |
2624 | [(set (reg:CC CC_REG) (compare:CC (match_dup 1) (match_dup 2))) | |
2625 | (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))]) | |
2626 | (set (match_dup 3) (match_dup 4))]) | |
2627 | ||
2628 | (define_insn "*add_n" | |
2629 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcw,W,W,w,w") | |
2630 | (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "Rcqq,c,c,c,c,c") | |
2631 | (match_operand:SI 2 "_2_4_8_operand" "")) | |
2632 | (match_operand:SI 3 "nonmemory_operand" "0,0,c,?Cal,?c,??Cal")))] | |
2633 | "" | |
2634 | "add%z2%? %0,%3,%1%&" | |
2635 | [(set_attr "type" "shift") | |
2636 | (set_attr "length" "*,4,4,8,4,8") | |
2637 | (set_attr "predicable" "yes,yes,no,no,no,no") | |
2638 | (set_attr "cond" "canuse,canuse,nocond,nocond,nocond,nocond") | |
2639 | (set_attr "iscompact" "maybe,false,false,false,false,false")]) | |
2640 | ||
2641 | ;; N.B. sub[123] has the operands of the MINUS in the opposite order from | |
2642 | ;; what synth_mult likes. | |
2643 | (define_insn "*sub_n" | |
2644 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2645 | (minus:SI (match_operand:SI 1 "nonmemory_operand" "0,c,?Cal") | |
2646 | (mult:SI (match_operand:SI 2 "register_operand" "c,c,c") | |
2647 | (match_operand:SI 3 "_2_4_8_operand" ""))))] | |
2648 | "" | |
2649 | "sub%z3%? %0,%1,%2" | |
2650 | [(set_attr "type" "shift") | |
2651 | (set_attr "length" "4,4,8") | |
2652 | (set_attr "predicable" "yes,no,no") | |
2653 | (set_attr "cond" "canuse,nocond,nocond") | |
2654 | (set_attr "iscompact" "false")]) | |
2655 | ||
2656 | ; ??? check if combine matches this. | |
2657 | (define_insn "*bset" | |
2658 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2659 | (ior:SI (ashift:SI (const_int 1) | |
2660 | (match_operand:SI 1 "nonmemory_operand" "cL,cL,c")) | |
2661 | (match_operand:SI 2 "nonmemory_operand" "0,c,Cal")))] | |
2662 | "" | |
2663 | "bset%? %0,%2,%1" | |
2664 | [(set_attr "length" "4,4,8") | |
2665 | (set_attr "predicable" "yes,no,no") | |
2666 | (set_attr "cond" "canuse,nocond,nocond")] | |
2667 | ) | |
2668 | ||
2669 | ; ??? check if combine matches this. | |
2670 | (define_insn "*bxor" | |
2671 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2672 | (xor:SI (ashift:SI (const_int 1) | |
2673 | (match_operand:SI 1 "nonmemory_operand" "cL,cL,c")) | |
2674 | (match_operand:SI 2 "nonmemory_operand" "0,c,Cal")))] | |
2675 | "" | |
2676 | "bxor%? %0,%2,%1" | |
2677 | [(set_attr "length" "4,4,8") | |
2678 | (set_attr "predicable" "yes,no,no") | |
2679 | (set_attr "cond" "canuse,nocond,nocond")] | |
2680 | ) | |
2681 | ||
2682 | ; ??? check if combine matches this. | |
2683 | (define_insn "*bclr" | |
2684 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2685 | (and:SI (not:SI (ashift:SI (const_int 1) | |
2686 | (match_operand:SI 1 "nonmemory_operand" "cL,cL,c"))) | |
2687 | (match_operand:SI 2 "nonmemory_operand" "0,c,Cal")))] | |
2688 | "" | |
2689 | "bclr%? %0,%2,%1" | |
2690 | [(set_attr "length" "4,4,8") | |
2691 | (set_attr "predicable" "yes,no,no") | |
2692 | (set_attr "cond" "canuse,nocond,nocond")] | |
2693 | ) | |
2694 | ||
2695 | ; ??? FIXME: find combine patterns for bmsk. | |
2696 | ||
2697 | ;;Following are the define_insns added for the purpose of peephole2's | |
2698 | ||
2699 | ; see also iorsi3 for use with constant bit number. | |
2700 | (define_insn "*bset_insn" | |
2701 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2702 | (ior:SI (match_operand:SI 1 "nonmemory_operand" "0,c,Cal") | |
2703 | (ashift:SI (const_int 1) | |
2704 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,c"))) ) ] | |
2705 | "" | |
2706 | "@ | |
2707 | bset%? %0,%1,%2 ;;peep2, constr 1 | |
2708 | bset %0,%1,%2 ;;peep2, constr 2 | |
2709 | bset %0,%S1,%2 ;;peep2, constr 3" | |
2710 | [(set_attr "length" "4,4,8") | |
2711 | (set_attr "predicable" "yes,no,no") | |
2712 | (set_attr "cond" "canuse,nocond,nocond")] | |
2713 | ) | |
2714 | ||
2715 | ; see also xorsi3 for use with constant bit number. | |
2716 | (define_insn "*bxor_insn" | |
2717 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2718 | (xor:SI (match_operand:SI 1 "nonmemory_operand" "0,c,Cal") | |
2719 | (ashift:SI (const_int 1) | |
2720 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,c"))) ) ] | |
2721 | "" | |
2722 | "@ | |
2723 | bxor%? %0,%1,%2 | |
2724 | bxor %0,%1,%2 | |
2725 | bxor %0,%S1,%2" | |
2726 | [(set_attr "length" "4,4,8") | |
2727 | (set_attr "predicable" "yes,no,no") | |
2728 | (set_attr "cond" "canuse,nocond,nocond")] | |
2729 | ) | |
2730 | ||
2731 | ; see also andsi3 for use with constant bit number. | |
2732 | (define_insn "*bclr_insn" | |
2733 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2734 | (and:SI (not:SI (ashift:SI (const_int 1) | |
2735 | (match_operand:SI 2 "nonmemory_operand" "cL,rL,r"))) | |
2736 | (match_operand:SI 1 "nonmemory_operand" "0,c,Cal")))] | |
2737 | "" | |
2738 | "@ | |
2739 | bclr%? %0,%1,%2 | |
2740 | bclr %0,%1,%2 | |
2741 | bclr %0,%S1,%2" | |
2742 | [(set_attr "length" "4,4,8") | |
2743 | (set_attr "predicable" "yes,no,no") | |
2744 | (set_attr "cond" "canuse,nocond,nocond")] | |
2745 | ) | |
2746 | ||
2747 | ; see also andsi3 for use with constant bit number. | |
2748 | (define_insn "*bmsk_insn" | |
2749 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw,w,w") | |
2750 | (and:SI (match_operand:SI 1 "nonmemory_operand" "0,c,Cal") | |
2751 | (plus:SI (ashift:SI (const_int 1) | |
2752 | (plus:SI (match_operand:SI 2 "nonmemory_operand" "rL,rL,r") | |
2753 | (const_int 1))) | |
2754 | (const_int -1))))] | |
2755 | "" | |
2756 | "@ | |
2757 | bmsk%? %0,%S1,%2 | |
2758 | bmsk %0,%1,%2 | |
2759 | bmsk %0,%S1,%2" | |
2760 | [(set_attr "length" "4,4,8") | |
2761 | (set_attr "predicable" "yes,no,no") | |
2762 | (set_attr "cond" "canuse,nocond,nocond")] | |
2763 | ) | |
2764 | ||
2765 | ;;Instructions added for peephole2s end | |
2766 | ||
2767 | ;; Boolean instructions. | |
2768 | ||
2769 | (define_expand "andsi3" | |
2770 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2771 | (and:SI (match_operand:SI 1 "nonimmediate_operand" "") | |
2772 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2773 | "" | |
2774 | "if (!satisfies_constraint_Cux (operands[2])) | |
2775 | operands[1] = force_reg (SImode, operands[1]); | |
2776 | else if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[1], Pmode)) | |
2777 | operands[1] = arc_rewrite_small_data (operands[1]);") | |
2778 | ||
2779 | (define_insn "andsi3_i" | |
2780 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcq,Rcqq,Rcqq,Rcqq,Rcw,Rcw,Rcw,Rcw,Rcw,Rcw, w, w, w, w,w,Rcw, w, W") | |
2781 | (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,Rcq, 0, 0,Rcqq, 0, c, 0, 0, 0, 0, c, c, c, c,0, 0, c, o") | |
2782 | (match_operand:SI 2 "nonmemory_operand" " Rcqq, 0, C1p, Ccp, Cux, cL, 0,C1p,Ccp,CnL, I, Lc,C1p,Ccp,CnL,I,Cal,Cal,Cux")))] | |
2783 | "(register_operand (operands[1], SImode) | |
2784 | && nonmemory_operand (operands[2], SImode)) | |
2785 | || (memory_operand (operands[1], SImode) | |
2786 | && satisfies_constraint_Cux (operands[2]))" | |
2787 | "* | |
2788 | { | |
2789 | switch (which_alternative) | |
2790 | { | |
2791 | case 0: case 5: case 10: case 11: case 15: case 16: case 17: | |
2792 | return \"and%? %0,%1,%2%&\"; | |
2793 | case 1: case 6: | |
2794 | return \"and%? %0,%2,%1%&\"; | |
2795 | case 2: case 7: case 12: | |
2796 | return \"bmsk%? %0,%1,%Z2%&\"; | |
2797 | case 3: case 8: case 13: | |
2798 | return \"bclr%? %0,%1,%M2%&\"; | |
2799 | case 4: | |
2800 | return (INTVAL (operands[2]) == 0xff | |
2801 | ? \"extb%? %0,%1%&\" : \"extw%? %0,%1%&\"); | |
2802 | case 9: case 14: return \"bic%? %0,%1,%n2-1\"; | |
2803 | case 18: | |
2804 | if (TARGET_BIG_ENDIAN) | |
2805 | { | |
2806 | rtx xop[2]; | |
2807 | ||
2808 | xop[0] = operands[0]; | |
2809 | xop[1] = adjust_address (operands[1], QImode, | |
2810 | INTVAL (operands[2]) == 0xff ? 3 : 2); | |
2811 | output_asm_insn (INTVAL (operands[2]) == 0xff | |
2812 | ? \"ldb %0,%1\" : \"ldw %0,%1\", | |
2813 | xop); | |
2814 | return \"\"; | |
2815 | } | |
2816 | return INTVAL (operands[2]) == 0xff ? \"ldb %0,%1\" : \"ldw %0,%1\"; | |
2817 | default: | |
2818 | gcc_unreachable (); | |
2819 | } | |
2820 | }" | |
2821 | [(set_attr "iscompact" "maybe,maybe,maybe,maybe,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false") | |
2822 | (set_attr "type" "binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,binary,load") | |
2823 | (set_attr "length" "*,*,*,*,*,4,4,4,4,4,4,4,4,4,4,4,8,8,*") | |
2824 | (set_attr "predicable" "no,no,no,no,no,yes,yes,yes,yes,yes,no,no,no,no,no,no,yes,no,no") | |
2825 | (set_attr "cond" "canuse,canuse,canuse,canuse,nocond,canuse,canuse,canuse,canuse,canuse,canuse_limm,nocond,nocond,nocond,nocond,canuse_limm,canuse,nocond,nocond")]) | |
2826 | ||
2827 | ; combiner splitter, pattern found in ldtoa.c . | |
2828 | ; and op3,op0,op1 / cmp op3,op2 -> add op3,op0,op4 / bmsk.f 0,op3,op1 | |
2829 | (define_split | |
2830 | [(set (reg:CC_Z CC_REG) | |
2831 | (compare:CC_Z (and:SI (match_operand:SI 0 "register_operand" "") | |
2832 | (match_operand 1 "const_int_operand" "")) | |
2833 | (match_operand 2 "const_int_operand" ""))) | |
2834 | (clobber (match_operand:SI 3 "register_operand" ""))] | |
2835 | "((INTVAL (operands[1]) + 1) & INTVAL (operands[1])) == 0" | |
2836 | [(set (match_dup 3) | |
2837 | (plus:SI (match_dup 0) (match_dup 4))) | |
2838 | (set (reg:CC_Z CC_REG) | |
2839 | (compare:CC_Z (and:SI (match_dup 3) (match_dup 1)) | |
2840 | (const_int 0)))] | |
2841 | "operands[4] = GEN_INT ( -(~INTVAL (operands[1]) | INTVAL (operands[2])));") | |
2842 | ||
2843 | ;;bic define_insn that allows limm to be the first operand | |
2844 | (define_insn "*bicsi3_insn" | |
2845 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcw,Rcw,Rcw,w,w,w") | |
2846 | (and:SI (not:SI (match_operand:SI 1 "nonmemory_operand" "Rcqq,Lc,I,Cal,Lc,Cal,c")) | |
2847 | (match_operand:SI 2 "nonmemory_operand" "0,0,0,0,c,c,Cal")))] | |
2848 | "" | |
2849 | "@ | |
2850 | bic%? %0, %2, %1%& ;;constraint 0 | |
2851 | bic%? %0,%2,%1 ;;constraint 1 | |
2852 | bic %0,%2,%1 ;;constraint 2, FIXME: will it ever get generated ??? | |
2853 | bic%? %0,%2,%S1 ;;constraint 3, FIXME: will it ever get generated ??? | |
2854 | bic %0,%2,%1 ;;constraint 4 | |
2855 | bic %0,%2,%S1 ;;constraint 5, FIXME: will it ever get generated ??? | |
2856 | bic %0,%S2,%1 ;;constraint 6" | |
2857 | [(set_attr "length" "*,4,4,8,4,8,8") | |
2858 | (set_attr "iscompact" "maybe, false, false, false, false, false, false") | |
2859 | (set_attr "predicable" "no,yes,no,yes,no,no,no") | |
2860 | (set_attr "cond" "canuse,canuse,canuse_limm,canuse,nocond,nocond,nocond")]) | |
2861 | ||
2862 | (define_insn "iorsi3" | |
2863 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcq,Rcqq,Rcw,Rcw,Rcw,Rcw,w, w,w,Rcw, w") | |
2864 | (ior:SI (match_operand:SI 1 "nonmemory_operand" "% 0,Rcq, 0, 0, c, 0, 0, c, c,0, 0, c") | |
2865 | (match_operand:SI 2 "nonmemory_operand" "Rcqq, 0, C0p, cL, 0,C0p, I,cL,C0p,I,Cal,Cal")))] | |
2866 | "" | |
2867 | "* | |
2868 | switch (which_alternative) | |
2869 | { | |
2870 | case 0: case 3: case 6: case 7: case 9: case 10: case 11: | |
2871 | return \"or%? %0,%1,%2%&\"; | |
2872 | case 1: case 4: | |
2873 | return \"or%? %0,%2,%1%&\"; | |
2874 | case 2: case 5: case 8: | |
2875 | return \"bset%? %0,%1,%z2%&\"; | |
2876 | default: | |
2877 | gcc_unreachable (); | |
2878 | }" | |
2879 | [(set_attr "iscompact" "maybe,maybe,maybe,false,false,false,false,false,false,false,false,false") | |
2880 | (set_attr "length" "*,*,*,4,4,4,4,4,4,4,8,8") | |
2881 | (set_attr "predicable" "no,no,no,yes,yes,yes,no,no,no,no,yes,no") | |
2882 | (set_attr "cond" "canuse,canuse,canuse,canuse,canuse,canuse,canuse_limm,nocond,nocond,canuse_limm,canuse,nocond")]) | |
2883 | ||
2884 | (define_insn "xorsi3" | |
2885 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcq,Rcw,Rcw,Rcw,Rcw, w, w,w, w, w") | |
2886 | (xor:SI (match_operand:SI 1 "register_operand" "%0, Rcq, 0, c, 0, 0, c, c,0, 0, c") | |
2887 | (match_operand:SI 2 "nonmemory_operand" " Rcqq, 0, cL, 0,C0p, I,cL,C0p,I,Cal,Cal")))] | |
2888 | "" | |
2889 | "* | |
2890 | switch (which_alternative) | |
2891 | { | |
2892 | case 0: case 2: case 5: case 6: case 8: case 9: case 10: | |
2893 | return \"xor%? %0,%1,%2%&\"; | |
2894 | case 1: case 3: | |
2895 | return \"xor%? %0,%2,%1%&\"; | |
2896 | case 4: case 7: | |
2897 | return \"bxor%? %0,%1,%z2\"; | |
2898 | default: | |
2899 | gcc_unreachable (); | |
2900 | } | |
2901 | " | |
2902 | [(set_attr "iscompact" "maybe,maybe,false,false,false,false,false,false,false,false,false") | |
2903 | (set_attr "type" "binary") | |
2904 | (set_attr "length" "*,*,4,4,4,4,4,4,4,8,8") | |
2905 | (set_attr "predicable" "no,no,yes,yes,yes,no,no,no,no,yes,no") | |
2906 | (set_attr "cond" "canuse,canuse,canuse,canuse,canuse,canuse_limm,nocond,nocond,canuse_limm,canuse,nocond")]) | |
2907 | ||
2908 | (define_insn "negsi2" | |
2909 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,Rcqq,Rcw,w") | |
2910 | (neg:SI (match_operand:SI 1 "register_operand" "0,Rcqq,0,c")))] | |
2911 | "" | |
2912 | "neg%? %0,%1%&" | |
2913 | [(set_attr "type" "unary") | |
2914 | (set_attr "iscompact" "maybe,true,false,false") | |
2915 | (set_attr "predicable" "no,no,yes,no")]) | |
2916 | ||
2917 | (define_insn "one_cmplsi2" | |
2918 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcqq,w") | |
2919 | (not:SI (match_operand:SI 1 "register_operand" "Rcqq,c")))] | |
2920 | "" | |
2921 | "not%? %0,%1%&" | |
2922 | [(set_attr "type" "unary,unary") | |
2923 | (set_attr "iscompact" "true,false")]) | |
2924 | ||
2925 | (define_insn_and_split "one_cmpldi2" | |
2926 | [(set (match_operand:DI 0 "dest_reg_operand" "=q,w") | |
2927 | (not:DI (match_operand:DI 1 "register_operand" "q,c")))] | |
2928 | "" | |
2929 | "#" | |
2930 | "&& reload_completed" | |
2931 | [(set (match_dup 2) (not:SI (match_dup 3))) | |
2932 | (set (match_dup 4) (not:SI (match_dup 5)))] | |
2933 | { | |
2934 | int swap = (true_regnum (operands[0]) == true_regnum (operands[1]) + 1); | |
2935 | ||
2936 | operands[2] = operand_subword (operands[0], 0+swap, 0, DImode); | |
2937 | operands[3] = operand_subword (operands[1], 0+swap, 0, DImode); | |
2938 | operands[4] = operand_subword (operands[0], 1-swap, 0, DImode); | |
2939 | operands[5] = operand_subword (operands[1], 1-swap, 0, DImode); | |
2940 | } | |
2941 | [(set_attr "type" "unary,unary") | |
2942 | (set_attr "cond" "nocond,nocond") | |
2943 | (set_attr "length" "4,8")]) | |
2944 | ||
2945 | ;; Shift instructions. | |
2946 | ||
2947 | (define_expand "ashlsi3" | |
2948 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2949 | (ashift:SI (match_operand:SI 1 "register_operand" "") | |
2950 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2951 | "" | |
2952 | " | |
2953 | { | |
2954 | if (!TARGET_BARREL_SHIFTER) | |
2955 | { | |
2956 | emit_shift (ASHIFT, operands[0], operands[1], operands[2]); | |
2957 | DONE; | |
2958 | } | |
2959 | }") | |
2960 | ||
2961 | (define_expand "ashrsi3" | |
2962 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2963 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "") | |
2964 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2965 | "" | |
2966 | " | |
2967 | { | |
2968 | if (!TARGET_BARREL_SHIFTER) | |
2969 | { | |
2970 | emit_shift (ASHIFTRT, operands[0], operands[1], operands[2]); | |
2971 | DONE; | |
2972 | } | |
2973 | }") | |
2974 | ||
2975 | (define_expand "lshrsi3" | |
2976 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
2977 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "") | |
2978 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
2979 | "" | |
2980 | " | |
2981 | { | |
2982 | if (!TARGET_BARREL_SHIFTER) | |
2983 | { | |
2984 | emit_shift (LSHIFTRT, operands[0], operands[1], operands[2]); | |
2985 | DONE; | |
2986 | } | |
2987 | }") | |
2988 | ||
2989 | (define_insn "shift_si3" | |
2990 | [(set (match_operand:SI 0 "dest_reg_operand" "=r") | |
2991 | (match_operator:SI 3 "shift4_operator" | |
2992 | [(match_operand:SI 1 "register_operand" "0") | |
2993 | (match_operand:SI 2 "const_int_operand" "n")])) | |
2994 | (clobber (match_scratch:SI 4 "=&r")) | |
2995 | (clobber (reg:CC CC_REG)) | |
2996 | ] | |
2997 | "!TARGET_BARREL_SHIFTER" | |
2998 | "* return output_shift (operands);" | |
2999 | [(set_attr "type" "shift") | |
3000 | (set_attr "length" "16")]) | |
3001 | ||
3002 | (define_insn "shift_si3_loop" | |
3003 | [(set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
3004 | (match_operator:SI 3 "shift_operator" | |
3005 | [(match_operand:SI 1 "register_operand" "0,0") | |
3006 | (match_operand:SI 2 "nonmemory_operand" "rn,Cal")])) | |
3007 | (clobber (match_scratch:SI 4 "=X,X")) | |
3008 | (clobber (reg:SI LP_COUNT)) | |
3009 | (clobber (reg:SI LP_START)) | |
3010 | (clobber (reg:SI LP_END)) | |
3011 | (clobber (reg:CC CC_REG)) | |
3012 | ] | |
3013 | "!TARGET_BARREL_SHIFTER" | |
3014 | "* return output_shift (operands);" | |
3015 | [(set_attr "type" "shift") | |
3016 | (set_attr "length" "16,20")]) | |
3017 | ||
3018 | ; asl, asr, lsr patterns: | |
3019 | ; There is no point in including an 'I' alternative since only the lowest 5 | |
3020 | ; bits are used for the shift. OTOH Cal can be useful if the shift amount | |
3021 | ; is defined in an external symbol, as we don't have special relocations | |
3022 | ; to truncate a symbol in a u6 immediate; but that's rather exotic, so only | |
3023 | ; provide one alternatice for this, without condexec support. | |
3024 | (define_insn "*ashlsi3_insn" | |
3025 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq,Rcqq,Rcqq,Rcw, w, w") | |
3026 | (ashift:SI (match_operand:SI 1 "nonmemory_operand" "!0,Rcqq, 0, 0, c,cCal") | |
3027 | (match_operand:SI 2 "nonmemory_operand" "K, K,RcqqM, cL,cL,cCal")))] | |
3028 | "TARGET_BARREL_SHIFTER | |
3029 | && (register_operand (operands[1], SImode) | |
3030 | || register_operand (operands[2], SImode))" | |
3031 | "asl%? %0,%1,%2%&" | |
3032 | [(set_attr "type" "shift") | |
3033 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false") | |
3034 | (set_attr "predicable" "no,no,no,yes,no,no") | |
3035 | (set_attr "cond" "canuse,nocond,canuse,canuse,nocond,nocond")]) | |
3036 | ||
3037 | (define_insn "*ashrsi3_insn" | |
3038 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq,Rcqq,Rcqq,Rcw, w, w") | |
3039 | (ashiftrt:SI (match_operand:SI 1 "nonmemory_operand" "!0,Rcqq, 0, 0, c,cCal") | |
3040 | (match_operand:SI 2 "nonmemory_operand" "K, K,RcqqM, cL,cL,cCal")))] | |
3041 | "TARGET_BARREL_SHIFTER | |
3042 | && (register_operand (operands[1], SImode) | |
3043 | || register_operand (operands[2], SImode))" | |
3044 | "asr%? %0,%1,%2%&" | |
3045 | [(set_attr "type" "shift") | |
3046 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false") | |
3047 | (set_attr "predicable" "no,no,no,yes,no,no") | |
3048 | (set_attr "cond" "canuse,nocond,canuse,canuse,nocond,nocond")]) | |
3049 | ||
3050 | (define_insn "*lshrsi3_insn" | |
3051 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq,Rcqq,Rcqq,Rcw, w, w") | |
3052 | (lshiftrt:SI (match_operand:SI 1 "nonmemory_operand" "!0,Rcqq, 0, 0, c,cCal") | |
3053 | (match_operand:SI 2 "nonmemory_operand" "N, N,RcqqM, cL,cL,cCal")))] | |
3054 | "TARGET_BARREL_SHIFTER | |
3055 | && (register_operand (operands[1], SImode) | |
3056 | || register_operand (operands[2], SImode))" | |
3057 | "*return (which_alternative <= 1 && !arc_ccfsm_cond_exec_p () | |
3058 | ? \"lsr%? %0,%1%&\" : \"lsr%? %0,%1,%2%&\");" | |
3059 | [(set_attr "type" "shift") | |
3060 | (set_attr "iscompact" "maybe,maybe,maybe,false,false,false") | |
3061 | (set_attr "predicable" "no,no,no,yes,no,no") | |
3062 | (set_attr "cond" "canuse,nocond,canuse,canuse,nocond,nocond")]) | |
3063 | ||
3064 | (define_insn "rotrsi3" | |
3065 | [(set (match_operand:SI 0 "dest_reg_operand" "=Rcw, w, w") | |
3066 | (rotatert:SI (match_operand:SI 1 "register_operand" " 0,cL,cCal") | |
3067 | (match_operand:SI 2 "nonmemory_operand" "cL,cL,cCal")))] | |
3068 | "TARGET_BARREL_SHIFTER" | |
3069 | "ror%? %0,%1,%2" | |
3070 | [(set_attr "type" "shift,shift,shift") | |
3071 | (set_attr "predicable" "yes,no,no") | |
3072 | (set_attr "length" "4,4,8")]) | |
3073 | ||
3074 | ;; Compare / branch instructions. | |
3075 | ||
3076 | (define_expand "cbranchsi4" | |
3077 | [(set (reg:CC CC_REG) | |
3078 | (compare:CC (match_operand:SI 1 "nonmemory_operand" "") | |
3079 | (match_operand:SI 2 "nonmemory_operand" ""))) | |
3080 | (set (pc) | |
3081 | (if_then_else | |
3082 | (match_operator 0 "ordered_comparison_operator" [(reg CC_REG) | |
3083 | (const_int 0)]) | |
3084 | (label_ref (match_operand 3 "" "")) | |
3085 | (pc)))] | |
3086 | "" | |
3087 | { | |
3088 | gcc_assert (XEXP (operands[0], 0) == operands[1]); | |
3089 | gcc_assert (XEXP (operands[0], 1) == operands[2]); | |
3090 | operands[0] = gen_compare_reg (operands[0], VOIDmode); | |
3091 | emit_jump_insn (gen_branch_insn (operands[3], operands[0])); | |
3092 | DONE; | |
3093 | }) | |
3094 | ||
3095 | ;; ??? Could add a peephole to generate compare with swapped operands and | |
3096 | ;; modifed cc user if second, but not first operand is a compact register. | |
3097 | (define_insn "cmpsi_cc_insn_mixed" | |
3098 | [(set (reg:CC CC_REG) | |
3099 | (compare:CC (match_operand:SI 0 "register_operand" "Rcq#q,c,c, qRcq, c") | |
3100 | (match_operand:SI 1 "nonmemory_operand" "cO,cI,cL, Cal, Cal")))] | |
3101 | "" | |
3102 | "cmp%? %0,%B1%&" | |
3103 | [(set_attr "type" "compare") | |
3104 | (set_attr "iscompact" "true,false,false,true_limm,false") | |
3105 | (set_attr "predicable" "no,no,yes,no,yes") | |
3106 | (set_attr "cond" "set") | |
3107 | (set_attr "length" "*,4,4,*,8")]) | |
3108 | ||
3109 | (define_insn "*cmpsi_cc_zn_insn" | |
3110 | [(set (reg:CC_ZN CC_REG) | |
3111 | (compare:CC_ZN (match_operand:SI 0 "register_operand" "qRcq,c") | |
3112 | (const_int 0)))] | |
3113 | "" | |
3114 | "tst%? %0,%0%&" | |
3115 | [(set_attr "type" "compare,compare") | |
3116 | (set_attr "iscompact" "true,false") | |
3117 | (set_attr "predicable" "no,yes") | |
3118 | (set_attr "cond" "set_zn") | |
3119 | (set_attr "length" "*,4")]) | |
3120 | ||
3121 | ; combiner pattern observed for unwind-dw2-fde.c:linear_search_fdes. | |
3122 | (define_insn "*btst" | |
3123 | [(set (reg:CC_ZN CC_REG) | |
3124 | (compare:CC_ZN | |
3125 | (zero_extract:SI (match_operand:SI 0 "register_operand" "Rcqq,c") | |
3126 | (const_int 1) | |
3127 | (match_operand:SI 1 "nonmemory_operand" "L,Lc")) | |
3128 | (const_int 0)))] | |
3129 | "" | |
3130 | "btst%? %0,%1" | |
3131 | [(set_attr "iscompact" "true,false") | |
3132 | (set_attr "predicable" "no,yes") | |
3133 | (set_attr "cond" "set") | |
3134 | (set_attr "type" "compare") | |
3135 | (set_attr "length" "*,4")]) | |
3136 | ||
3137 | ; combine suffers from 'simplifications' that replace a one-bit zero | |
3138 | ; extract with a shift if it can prove that the upper bits are zero. | |
3139 | ; arc_reorg sees the code after sched2, which can have caused our | |
3140 | ; inputs to be clobbered even if they were not clobbered before. | |
3141 | ; Therefore, add a third way to convert btst / b{eq,ne} to bbit{0,1} | |
3142 | ; OTOH, this is somewhat marginal, and can leat to out-of-range | |
3143 | ; bbit (i.e. bad scheduling) and missed conditional execution, | |
3144 | ; so make this an option. | |
3145 | (define_peephole2 | |
3146 | [(set (reg:CC_ZN CC_REG) | |
3147 | (compare:CC_ZN | |
3148 | (zero_extract:SI (match_operand:SI 0 "register_operand" "") | |
3149 | (const_int 1) | |
3150 | (match_operand:SI 1 "nonmemory_operand" "")) | |
3151 | (const_int 0))) | |
3152 | (set (pc) | |
3153 | (if_then_else (match_operator 3 "equality_comparison_operator" | |
3154 | [(reg:CC_ZN CC_REG) (const_int 0)]) | |
3155 | (label_ref (match_operand 2 "" "")) | |
3156 | (pc)))] | |
3157 | "TARGET_BBIT_PEEPHOLE && peep2_regno_dead_p (2, CC_REG)" | |
3158 | [(parallel [(set (pc) | |
3159 | (if_then_else | |
3160 | (match_op_dup 3 | |
3161 | [(zero_extract:SI (match_dup 0) | |
3162 | (const_int 1) (match_dup 1)) | |
3163 | (const_int 0)]) | |
3164 | (label_ref (match_dup 2)) | |
3165 | (pc))) | |
3166 | (clobber (reg:CC_ZN CC_REG))])]) | |
3167 | ||
3168 | (define_insn "*cmpsi_cc_z_insn" | |
3169 | [(set (reg:CC_Z CC_REG) | |
3170 | (compare:CC_Z (match_operand:SI 0 "register_operand" "qRcq,c") | |
3171 | (match_operand:SI 1 "p2_immediate_operand" "O,n")))] | |
3172 | "" | |
3173 | "@ | |
3174 | cmp%? %0,%1%& | |
3175 | bxor.f 0,%0,%z1" | |
3176 | [(set_attr "type" "compare,compare") | |
3177 | (set_attr "iscompact" "true,false") | |
3178 | (set_attr "cond" "set,set_zn") | |
3179 | (set_attr "length" "*,4")]) | |
3180 | ||
3181 | (define_insn "*cmpsi_cc_c_insn" | |
3182 | [(set (reg:CC_C CC_REG) | |
3183 | (compare:CC_C (match_operand:SI 0 "register_operand" "Rcqq, c,Rcqq, c") | |
3184 | (match_operand:SI 1 "nonmemory_operand" "cO, cI, Cal,Cal")))] | |
3185 | "" | |
3186 | "cmp%? %0,%S1%&" | |
3187 | [(set_attr "type" "compare") | |
3188 | (set_attr "iscompact" "true,false,true_limm,false") | |
3189 | (set_attr "cond" "set") | |
3190 | (set_attr "length" "*,4,*,8")]) | |
3191 | ||
3192 | ;; Next come the scc insns. | |
3193 | ||
3194 | (define_expand "cstoresi4" | |
3195 | [(set (reg:CC CC_REG) | |
3196 | (compare:CC (match_operand:SI 2 "nonmemory_operand" "") | |
3197 | (match_operand:SI 3 "nonmemory_operand" ""))) | |
3198 | (set (match_operand:SI 0 "dest_reg_operand" "") | |
3199 | (match_operator:SI 1 "ordered_comparison_operator" [(reg CC_REG) | |
3200 | (const_int 0)]))] | |
3201 | "" | |
3202 | { | |
3203 | gcc_assert (XEXP (operands[1], 0) == operands[2]); | |
3204 | gcc_assert (XEXP (operands[1], 1) == operands[3]); | |
3205 | operands[1] = gen_compare_reg (operands[1], SImode); | |
3206 | emit_insn (gen_scc_insn (operands[0], operands[1])); | |
3207 | DONE; | |
3208 | }) | |
3209 | ||
3210 | (define_mode_iterator SDF [SF DF]) | |
3211 | ||
3212 | (define_expand "cstore<mode>4" | |
3213 | [(set (reg:CC CC_REG) | |
3214 | (compare:CC (match_operand:SDF 2 "register_operand" "") | |
3215 | (match_operand:SDF 3 "register_operand" ""))) | |
3216 | (set (match_operand:SI 0 "dest_reg_operand" "") | |
3217 | (match_operator:SI 1 "comparison_operator" [(reg CC_REG) | |
3218 | (const_int 0)]))] | |
3219 | ||
3220 | "TARGET_OPTFPE" | |
3221 | { | |
3222 | gcc_assert (XEXP (operands[1], 0) == operands[2]); | |
3223 | gcc_assert (XEXP (operands[1], 1) == operands[3]); | |
3224 | operands[1] = gen_compare_reg (operands[1], SImode); | |
3225 | emit_insn (gen_scc_insn (operands[0], operands[1])); | |
3226 | DONE; | |
3227 | }) | |
3228 | ||
3229 | ; We need a separate expander for this lest we loose the mode of CC_REG | |
3230 | ; when match_operator substitutes the literal operand into the comparison. | |
3231 | (define_expand "scc_insn" | |
3232 | [(set (match_operand:SI 0 "dest_reg_operand" "=w") (match_operand:SI 1 ""))]) | |
3233 | ||
3234 | (define_insn_and_split "*scc_insn" | |
3235 | [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
3236 | (match_operator:SI 1 "proper_comparison_operator" [(reg CC_REG) (const_int 0)]))] | |
3237 | "" | |
3238 | "#" | |
3239 | "reload_completed" | |
3240 | [(set (match_dup 0) (const_int 1)) | |
3241 | (cond_exec | |
3242 | (match_dup 1) | |
3243 | (set (match_dup 0) (const_int 0)))] | |
3244 | { | |
3245 | operands[1] | |
3246 | = gen_rtx_fmt_ee (REVERSE_CONDITION (GET_CODE (operands[1]), | |
3247 | GET_MODE (XEXP (operands[1], 0))), | |
3248 | VOIDmode, | |
3249 | XEXP (operands[1], 0), XEXP (operands[1], 1)); | |
3250 | } | |
3251 | [(set_attr "type" "unary")]) | |
3252 | ||
3253 | ;; ??? At least for ARC600, we should use sbc b,b,s12 if we want a value | |
3254 | ;; that is one lower if the carry flag is set. | |
3255 | ||
3256 | ;; ??? Look up negscc insn. See pa.md for example. | |
3257 | (define_insn "*neg_scc_insn" | |
3258 | [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
3259 | (neg:SI (match_operator:SI 1 "proper_comparison_operator" | |
3260 | [(reg CC_REG) (const_int 0)])))] | |
3261 | "" | |
3262 | "mov %0,-1\;sub.%D1 %0,%0,%0" | |
3263 | [(set_attr "type" "unary") | |
3264 | (set_attr "length" "8")]) | |
3265 | ||
3266 | (define_insn "*not_scc_insn" | |
3267 | [(set (match_operand:SI 0 "dest_reg_operand" "=w") | |
3268 | (not:SI (match_operator:SI 1 "proper_comparison_operator" | |
3269 | [(reg CC_REG) (const_int 0)])))] | |
3270 | "" | |
3271 | "mov %0,1\;sub.%d1 %0,%0,%0" | |
3272 | [(set_attr "type" "unary") | |
3273 | (set_attr "length" "8")]) | |
3274 | ||
3275 | ; cond_exec patterns | |
3276 | (define_insn "*movsi_ne" | |
3277 | [(cond_exec | |
3278 | (ne (match_operand:CC_Z 2 "cc_use_register" "Rcc,Rcc,Rcc") (const_int 0)) | |
3279 | (set (match_operand:SI 0 "dest_reg_operand" "=Rcq#q,w,w") | |
3280 | (match_operand:SI 1 "nonmemory_operand" "C_0,Lc,?Cal")))] | |
3281 | "" | |
3282 | "@ | |
3283 | * current_insn_predicate = 0; return \"sub%?.ne %0,%0,%0%&\"; | |
3284 | mov.ne %0,%1 | |
3285 | mov.ne %0,%S1" | |
3286 | [(set_attr "type" "cmove,cmove,cmove") | |
3287 | (set_attr "iscompact" "true,false,false") | |
3288 | (set_attr "length" "2,4,8")]) | |
3289 | ||
3290 | (define_insn "*movsi_cond_exec" | |
3291 | [(cond_exec | |
3292 | (match_operator 3 "proper_comparison_operator" | |
3293 | [(match_operand 2 "cc_register" "Rcc,Rcc") (const_int 0)]) | |
3294 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
3295 | (match_operand:SI 1 "nonmemory_operand" "Lc,?Cal")))] | |
3296 | "" | |
3297 | "mov.%d3 %0,%S1" | |
3298 | [(set_attr "type" "cmove") | |
3299 | (set_attr "length" "4,8")]) | |
3300 | ||
3301 | (define_insn "*commutative_cond_exec" | |
3302 | [(cond_exec | |
3303 | (match_operator 5 "proper_comparison_operator" | |
3304 | [(match_operand 4 "cc_register" "Rcc,Rcc") (const_int 0)]) | |
3305 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
3306 | (match_operator:SI 3 "commutative_operator" | |
3307 | [(match_operand:SI 1 "register_operand" "%0,0") | |
3308 | (match_operand:SI 2 "nonmemory_operand" "cL,?Cal")])))] | |
3309 | "" | |
3310 | { | |
3311 | arc_output_commutative_cond_exec (operands, true); | |
3312 | return ""; | |
3313 | } | |
3314 | [(set_attr "cond" "use") | |
3315 | (set_attr "type" "cmove") | |
3316 | (set_attr_alternative "length" | |
3317 | [(const_int 4) | |
3318 | (cond | |
3319 | [(eq (symbol_ref "arc_output_commutative_cond_exec (operands, false)") | |
3320 | (const_int 4)) | |
3321 | (const_int 4)] | |
3322 | (const_int 8))])]) | |
3323 | ||
3324 | (define_insn "*sub_cond_exec" | |
3325 | [(cond_exec | |
3326 | (match_operator 4 "proper_comparison_operator" | |
3327 | [(match_operand 3 "cc_register" "Rcc,Rcc,Rcc") (const_int 0)]) | |
3328 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w,w") | |
3329 | (minus:SI (match_operand:SI 1 "nonmemory_operand" "0,cL,Cal") | |
3330 | (match_operand:SI 2 "nonmemory_operand" "cL,0,0"))))] | |
3331 | "" | |
3332 | "@ | |
3333 | sub.%d4 %0,%1,%2 | |
3334 | rsub.%d4 %0,%2,%1 | |
3335 | rsub.%d4 %0,%2,%1" | |
3336 | [(set_attr "cond" "use") | |
3337 | (set_attr "type" "cmove") | |
3338 | (set_attr "length" "4,4,8")]) | |
3339 | ||
3340 | (define_insn "*noncommutative_cond_exec" | |
3341 | [(cond_exec | |
3342 | (match_operator 5 "proper_comparison_operator" | |
3343 | [(match_operand 4 "cc_register" "Rcc,Rcc") (const_int 0)]) | |
3344 | (set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
3345 | (match_operator:SI 3 "noncommutative_operator" | |
3346 | [(match_operand:SI 1 "register_operand" "0,0") | |
3347 | (match_operand:SI 2 "nonmemory_operand" "cL,Cal")])))] | |
3348 | "" | |
3349 | "%O3.%d5 %0,%1,%2" | |
3350 | [(set_attr "cond" "use") | |
3351 | (set_attr "type" "cmove") | |
3352 | (set_attr "length" "4,8")]) | |
3353 | ||
3354 | ;; These control RTL generation for conditional jump insns | |
3355 | ;; Match both normal and inverted jump. | |
3356 | ||
3357 | ; We need a separate expander for this lest we loose the mode of CC_REG | |
3358 | ; when match_operator substitutes the literal operand into the comparison. | |
3359 | (define_expand "branch_insn" | |
3360 | [(set (pc) | |
3361 | (if_then_else (match_operand 1 "" "") | |
3362 | (label_ref (match_operand 0 "" "")) | |
3363 | (pc)))]) | |
3364 | ||
3365 | ; When estimating sizes during arc_reorg, when optimizing for speed, there | |
3366 | ; are three reasons why we need to consider branches to be length 6: | |
3367 | ; - annull-false delay slot insns are implemented using conditional execution, | |
3368 | ; thus preventing short insn formation where used. | |
3369 | ; - for ARC600: annull-true delay slot isnns are implemented where possile | |
3370 | ; using conditional execution, preventing short insn formation where used. | |
3371 | ; - for ARC700: likely or somewhat likely taken branches are made long and | |
3372 | ; unaligned if possible to avoid branch penalty. | |
3373 | (define_insn "*branch_insn" | |
3374 | [(set (pc) | |
3375 | (if_then_else (match_operator 1 "proper_comparison_operator" | |
3376 | [(reg CC_REG) (const_int 0)]) | |
3377 | (label_ref (match_operand 0 "" "")) | |
3378 | (pc)))] | |
3379 | "" | |
3380 | "* | |
3381 | { | |
3382 | if (arc_ccfsm_branch_deleted_p ()) | |
3383 | { | |
3384 | arc_ccfsm_record_branch_deleted (); | |
3385 | return \"; branch deleted, next insns conditionalized\"; | |
3386 | } | |
3387 | else | |
3388 | { | |
3389 | arc_ccfsm_record_condition (operands[1], false, insn, 0); | |
3390 | if (get_attr_length (insn) == 2) | |
3391 | return \"b%d1%? %^%l0%&\"; | |
3392 | else | |
3393 | return \"b%d1%# %^%l0\"; | |
3394 | } | |
3395 | }" | |
3396 | [(set_attr "type" "branch") | |
3397 | (set | |
3398 | (attr "length") | |
3399 | (cond [ | |
3400 | (eq_attr "delay_slot_filled" "yes") | |
3401 | (const_int 4) | |
3402 | ||
3403 | (ne | |
3404 | (if_then_else | |
3405 | (match_operand 1 "equality_comparison_operator" "") | |
3406 | (ior (lt (minus (match_dup 0) (pc)) (const_int -512)) | |
3407 | (gt (minus (match_dup 0) (pc)) | |
3408 | (minus (const_int 506) | |
3409 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
3410 | (ior (match_test "!arc_short_comparison_p (operands[1], -64)") | |
3411 | (lt (minus (match_dup 0) (pc)) (const_int -64)) | |
3412 | (gt (minus (match_dup 0) (pc)) | |
3413 | (minus (const_int 58) | |
3414 | (symbol_ref "get_attr_delay_slot_length (insn)"))))) | |
3415 | (const_int 0)) | |
3416 | (const_int 4)] | |
3417 | (const_int 2))) | |
3418 | ||
3419 | (set (attr "iscompact") | |
3420 | (cond [(match_test "get_attr_length (insn) == 2") (const_string "true")] | |
3421 | (const_string "false")))]) | |
3422 | ||
3423 | (define_insn "*rev_branch_insn" | |
3424 | [(set (pc) | |
3425 | (if_then_else (match_operator 1 "proper_comparison_operator" | |
3426 | [(reg CC_REG) (const_int 0)]) | |
3427 | (pc) | |
3428 | (label_ref (match_operand 0 "" ""))))] | |
3429 | "REVERSIBLE_CC_MODE (GET_MODE (XEXP (operands[1], 0)))" | |
3430 | "* | |
3431 | { | |
3432 | if (arc_ccfsm_branch_deleted_p ()) | |
3433 | { | |
3434 | arc_ccfsm_record_branch_deleted (); | |
3435 | return \"; branch deleted, next insns conditionalized\"; | |
3436 | } | |
3437 | else | |
3438 | { | |
3439 | arc_ccfsm_record_condition (operands[1], true, insn, 0); | |
3440 | if (get_attr_length (insn) == 2) | |
3441 | return \"b%D1%? %^%l0\"; | |
3442 | else | |
3443 | return \"b%D1%# %^%l0\"; | |
3444 | } | |
3445 | }" | |
3446 | [(set_attr "type" "branch") | |
3447 | (set | |
3448 | (attr "length") | |
3449 | (cond [ | |
3450 | (eq_attr "delay_slot_filled" "yes") | |
3451 | (const_int 4) | |
3452 | ||
3453 | (ne | |
3454 | (if_then_else | |
3455 | (match_operand 1 "equality_comparison_operator" "") | |
3456 | (ior (lt (minus (match_dup 0) (pc)) (const_int -512)) | |
3457 | (gt (minus (match_dup 0) (pc)) | |
3458 | (minus (const_int 506) | |
3459 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
3460 | (ior (match_test "!arc_short_comparison_p (operands[1], -64)") | |
3461 | (lt (minus (match_dup 0) (pc)) (const_int -64)) | |
3462 | (gt (minus (match_dup 0) (pc)) | |
3463 | (minus (const_int 58) | |
3464 | (symbol_ref "get_attr_delay_slot_length (insn)"))))) | |
3465 | (const_int 0)) | |
3466 | (const_int 4)] | |
3467 | (const_int 2))) | |
3468 | ||
3469 | (set (attr "iscompact") | |
3470 | (cond [(match_test "get_attr_length (insn) == 2") (const_string "true")] | |
3471 | (const_string "false")))]) | |
3472 | ||
3473 | ;; Unconditional and other jump instructions. | |
3474 | ||
3475 | (define_expand "jump" | |
3476 | [(set (pc) (label_ref (match_operand 0 "" "")))] | |
3477 | "" | |
3478 | "") | |
3479 | ||
3480 | (define_insn "jump_i" | |
3481 | [(set (pc) (label_ref (match_operand 0 "" "")))] | |
339ba33b | 3482 | "!TARGET_LONG_CALLS_SET || !CROSSING_JUMP_P (insn)" |
526b7aee SV |
3483 | "b%!%* %^%l0%&" |
3484 | [(set_attr "type" "uncond_branch") | |
3485 | (set (attr "iscompact") | |
3486 | (if_then_else (match_test "get_attr_length (insn) == 2") | |
3487 | (const_string "true") (const_string "false"))) | |
3488 | (set_attr "cond" "canuse") | |
3489 | (set (attr "length") | |
3490 | (cond [ | |
3491 | ; In arc_reorg we just guesstimate; might be more or less than 4. | |
3492 | (match_test "arc_branch_size_unknown_p ()") | |
3493 | (const_int 4) | |
3494 | ||
3495 | (eq_attr "delay_slot_filled" "yes") | |
3496 | (const_int 4) | |
3497 | ||
339ba33b | 3498 | (match_test "CROSSING_JUMP_P (insn)") |
526b7aee SV |
3499 | (const_int 4) |
3500 | ||
3501 | (ior (lt (minus (match_dup 0) (pc)) (const_int -512)) | |
3502 | (gt (minus (match_dup 0) (pc)) | |
3503 | (minus (const_int 506) | |
3504 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
3505 | (const_int 4)] | |
3506 | (const_int 2)))]) | |
3507 | ||
3508 | (define_insn "indirect_jump" | |
3509 | [(set (pc) (match_operand:SI 0 "nonmemory_operand" "L,I,Cal,Rcqq,r"))] | |
3510 | "" | |
3511 | "j%!%* [%0]%&" | |
3512 | [(set_attr "type" "jump") | |
3513 | (set_attr "iscompact" "false,false,false,maybe,false") | |
3514 | (set_attr "cond" "canuse,canuse_limm,canuse,canuse,canuse")]) | |
3515 | ||
3516 | ;; Implement a switch statement. | |
3517 | ||
3518 | (define_expand "casesi" | |
3519 | [(set (match_dup 5) | |
3520 | (minus:SI (match_operand:SI 0 "register_operand" "") | |
3521 | (match_operand:SI 1 "nonmemory_operand" ""))) | |
3522 | (set (reg:CC CC_REG) | |
3523 | (compare:CC (match_dup 5) | |
3524 | (match_operand:SI 2 "nonmemory_operand" ""))) | |
3525 | (set (pc) | |
3526 | (if_then_else (gtu (reg:CC CC_REG) | |
3527 | (const_int 0)) | |
3528 | (label_ref (match_operand 4 "" "")) | |
3529 | (pc))) | |
3530 | (set (match_dup 6) | |
3531 | (unspec:SI [(match_operand 3 "" "") | |
3532 | (match_dup 5) (match_dup 7)] UNSPEC_CASESI)) | |
3533 | (parallel [(set (pc) (match_dup 6)) (use (match_dup 7))])] | |
3534 | "" | |
3535 | " | |
3536 | { | |
3537 | rtx x; | |
3538 | ||
3539 | operands[5] = gen_reg_rtx (SImode); | |
3540 | operands[6] = gen_reg_rtx (SImode); | |
3541 | operands[7] = operands[3]; | |
3542 | emit_insn (gen_subsi3 (operands[5], operands[0], operands[1])); | |
3543 | emit_insn (gen_cmpsi_cc_insn_mixed (operands[5], operands[2])); | |
3544 | x = gen_rtx_GTU (VOIDmode, gen_rtx_REG (CCmode, CC_REG), const0_rtx); | |
3545 | x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, | |
3546 | gen_rtx_LABEL_REF (VOIDmode, operands[4]), pc_rtx); | |
f7df4a84 | 3547 | emit_jump_insn (gen_rtx_SET (pc_rtx, x)); |
526b7aee SV |
3548 | if (TARGET_COMPACT_CASESI) |
3549 | { | |
3550 | emit_jump_insn (gen_casesi_compact_jump (operands[5], operands[7])); | |
3551 | } | |
3552 | else | |
3553 | { | |
3554 | operands[3] = gen_rtx_LABEL_REF (VOIDmode, operands[3]); | |
3555 | if (flag_pic || !cse_not_expected) | |
3556 | operands[3] = force_reg (Pmode, operands[3]); | |
3557 | emit_insn (gen_casesi_load (operands[6], | |
3558 | operands[3], operands[5], operands[7])); | |
3559 | if (CASE_VECTOR_PC_RELATIVE || flag_pic) | |
3560 | emit_insn (gen_addsi3 (operands[6], operands[6], operands[3])); | |
3561 | emit_jump_insn (gen_casesi_jump (operands[6], operands[7])); | |
3562 | } | |
3563 | DONE; | |
3564 | }") | |
3565 | ||
3566 | (define_insn "casesi_load" | |
3567 | [(set (match_operand:SI 0 "register_operand" "=Rcq,r,r") | |
3568 | (unspec:SI [(match_operand:SI 1 "nonmemory_operand" "Rcq,c,Cal") | |
3569 | (match_operand:SI 2 "register_operand" "Rcq,c,c") | |
3570 | (label_ref (match_operand 3 "" ""))] UNSPEC_CASESI))] | |
3571 | "" | |
3572 | "* | |
3573 | { | |
3574 | rtx diff_vec = PATTERN (next_nonnote_insn (operands[3])); | |
3575 | ||
3576 | if (GET_CODE (diff_vec) != ADDR_DIFF_VEC) | |
3577 | { | |
3578 | gcc_assert (GET_CODE (diff_vec) == ADDR_VEC); | |
3579 | gcc_assert (GET_MODE (diff_vec) == SImode); | |
3580 | gcc_assert (!CASE_VECTOR_PC_RELATIVE && !flag_pic); | |
3581 | } | |
3582 | ||
3583 | switch (GET_MODE (diff_vec)) | |
3584 | { | |
3585 | case SImode: | |
3586 | return \"ld.as %0,[%1,%2]%&\"; | |
3587 | case HImode: | |
3588 | if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned) | |
3589 | return \"ldw.as %0,[%1,%2]\"; | |
3590 | return \"ldw.x.as %0,[%1,%2]\"; | |
3591 | case QImode: | |
3592 | if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned) | |
3593 | return \"ldb%? %0,[%1,%2]%&\"; | |
3594 | return \"ldb.x %0,[%1,%2]\"; | |
3595 | default: | |
3596 | gcc_unreachable (); | |
3597 | } | |
3598 | }" | |
3599 | [(set_attr "type" "load") | |
3600 | (set_attr_alternative "iscompact" | |
3601 | [(cond | |
3602 | [(ne (symbol_ref "GET_MODE (PATTERN (next_nonnote_insn (operands[3])))") | |
3603 | (symbol_ref "QImode")) | |
3604 | (const_string "false") | |
3605 | (match_test "!ADDR_DIFF_VEC_FLAGS (PATTERN (next_nonnote_insn (operands[3]))).offset_unsigned") | |
3606 | (const_string "false")] | |
3607 | (const_string "true")) | |
3608 | (const_string "false") | |
3609 | (const_string "false")]) | |
3610 | (set_attr_alternative "length" | |
3611 | [(cond | |
220c1a51 JR |
3612 | [(eq_attr "iscompact" "false") (const_int 4) |
3613 | ; We have to mention (match_dup 3) to convince genattrtab.c that this | |
3614 | ; is a varying length insn. | |
3615 | (eq (symbol_ref "1+1") (const_int 2)) (const_int 2) | |
3616 | (gt (minus (match_dup 3) (pc)) (const_int 42)) (const_int 4)] | |
526b7aee SV |
3617 | (const_int 2)) |
3618 | (const_int 4) | |
3619 | (const_int 8)])]) | |
3620 | ||
3621 | ; Unlike the canonical tablejump, this pattern always uses a jump address, | |
3622 | ; even for CASE_VECTOR_PC_RELATIVE. | |
3623 | (define_insn "casesi_jump" | |
3624 | [(set (pc) (match_operand:SI 0 "register_operand" "Cal,Rcqq,c")) | |
3625 | (use (label_ref (match_operand 1 "" "")))] | |
3626 | "" | |
3627 | "j%!%* [%0]%&" | |
3628 | [(set_attr "type" "jump") | |
3629 | (set_attr "iscompact" "false,maybe,false") | |
3630 | (set_attr "cond" "canuse")]) | |
3631 | ||
3632 | (define_insn "casesi_compact_jump" | |
3633 | [(set (pc) | |
3634 | (unspec:SI [(match_operand:SI 0 "register_operand" "c,q")] | |
3635 | UNSPEC_CASESI)) | |
3636 | (use (label_ref (match_operand 1 "" ""))) | |
3637 | (clobber (match_scratch:SI 2 "=q,0"))] | |
3638 | "TARGET_COMPACT_CASESI" | |
3639 | "* | |
3640 | { | |
3641 | rtx diff_vec = PATTERN (next_nonnote_insn (operands[1])); | |
3642 | int unalign = arc_get_unalign (); | |
3643 | rtx xop[3]; | |
3644 | const char *s; | |
3645 | ||
3646 | xop[0] = operands[0]; | |
3647 | xop[2] = operands[2]; | |
3648 | gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); | |
3649 | ||
3650 | switch (GET_MODE (diff_vec)) | |
3651 | { | |
3652 | case SImode: | |
3653 | /* Max length can be 12 in this case, but this is OK because | |
3654 | 2 of these are for alignment, and are anticipated in the length | |
3655 | of the ADDR_DIFF_VEC. */ | |
3656 | if (unalign && !satisfies_constraint_Rcq (xop[0])) | |
3657 | s = \"add2 %2,pcl,%0\n\tld_s%2,[%2,12]\"; | |
3658 | else if (unalign) | |
3659 | s = \"add_s %2,%0,2\n\tld.as %2,[pcl,%2]\"; | |
3660 | else | |
3661 | s = \"add %2,%0,2\n\tld.as %2,[pcl,%2]\"; | |
3662 | arc_clear_unalign (); | |
3663 | break; | |
3664 | case HImode: | |
3665 | if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned) | |
3666 | { | |
3667 | if (satisfies_constraint_Rcq (xop[0])) | |
3668 | { | |
3669 | s = \"add_s %2,%0,%1\n\tldw.as %2,[pcl,%2]\"; | |
3670 | xop[1] = GEN_INT ((10 - unalign) / 2U); | |
3671 | } | |
3672 | else | |
3673 | { | |
3674 | s = \"add1 %2,pcl,%0\n\tldw_s %2,[%2,%1]\"; | |
3675 | xop[1] = GEN_INT (10 + unalign); | |
3676 | } | |
3677 | } | |
3678 | else | |
3679 | { | |
3680 | if (satisfies_constraint_Rcq (xop[0])) | |
3681 | { | |
3682 | s = \"add_s %2,%0,%1\n\tldw.x.as %2,[pcl,%2]\"; | |
3683 | xop[1] = GEN_INT ((10 - unalign) / 2U); | |
3684 | } | |
3685 | else | |
3686 | { | |
3687 | s = \"add1 %2,pcl,%0\n\tldw_s.x %2,[%2,%1]\"; | |
3688 | xop[1] = GEN_INT (10 + unalign); | |
3689 | } | |
3690 | } | |
3691 | arc_toggle_unalign (); | |
3692 | break; | |
3693 | case QImode: | |
3694 | if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned) | |
3695 | { | |
3696 | if ((rtx_equal_p (xop[2], xop[0]) | |
3697 | || find_reg_note (insn, REG_DEAD, xop[0])) | |
3698 | && satisfies_constraint_Rcq (xop[0])) | |
3699 | { | |
3700 | s = \"add_s %0,%0,pcl\n\tldb_s %2,[%0,%1]\"; | |
3701 | xop[1] = GEN_INT (8 + unalign); | |
3702 | } | |
3703 | else | |
3704 | { | |
3705 | s = \"add %2,%0,pcl\n\tldb_s %2,[%2,%1]\"; | |
3706 | xop[1] = GEN_INT (10 + unalign); | |
3707 | arc_toggle_unalign (); | |
3708 | } | |
3709 | } | |
3710 | else if ((rtx_equal_p (xop[0], xop[2]) | |
3711 | || find_reg_note (insn, REG_DEAD, xop[0])) | |
3712 | && satisfies_constraint_Rcq (xop[0])) | |
3713 | { | |
3714 | s = \"add_s %0,%0,%1\n\tldb.x %2,[pcl,%0]\"; | |
3715 | xop[1] = GEN_INT (10 - unalign); | |
3716 | arc_toggle_unalign (); | |
3717 | } | |
3718 | else | |
3719 | { | |
3720 | /* ??? Length is 12. */ | |
3721 | s = \"add %2,%0,%1\n\tldb.x %2,[pcl,%2]\"; | |
3722 | xop[1] = GEN_INT (8 + unalign); | |
3723 | } | |
3724 | break; | |
3725 | default: | |
3726 | gcc_unreachable (); | |
3727 | } | |
3728 | output_asm_insn (s, xop); | |
3729 | return \"add_s %2,%2,pcl\n\tj_s%* [%2]\"; | |
3730 | }" | |
3731 | [(set_attr "length" "10") | |
3732 | (set_attr "type" "jump") | |
3733 | (set_attr "iscompact" "true") | |
3734 | (set_attr "cond" "nocond")]) | |
3735 | ||
3736 | (define_expand "call" | |
3737 | ;; operands[1] is stack_size_rtx | |
3738 | ;; operands[2] is next_arg_register | |
3739 | [(parallel [(call (match_operand:SI 0 "call_operand" "") | |
3740 | (match_operand 1 "" "")) | |
3741 | (clobber (reg:SI 31))])] | |
3742 | "" | |
3743 | "{ | |
3744 | rtx callee; | |
3745 | ||
3746 | gcc_assert (MEM_P (operands[0])); | |
3747 | callee = XEXP (operands[0], 0); | |
3748 | if (crtl->profile && arc_profile_call (callee)) | |
3749 | { | |
3750 | emit_call_insn (gen_call_prof (gen_rtx_SYMBOL_REF (Pmode, | |
3751 | \"_mcount_call\"), | |
3752 | operands[1])); | |
3753 | DONE; | |
3754 | } | |
3755 | /* This is to decide if we should generate indirect calls by loading the | |
3756 | 32 bit address of the callee into a register before performing the | |
3757 | branch and link - this exposes cse opportunities. | |
3758 | Also, in weird cases like compile/20010107-1.c, we may get a PLUS. */ | |
3759 | if (GET_CODE (callee) != REG | |
3760 | && (GET_CODE (callee) == PLUS || arc_is_longcall_p (callee))) | |
3761 | XEXP (operands[0], 0) = force_reg (Pmode, callee); | |
3762 | } | |
3763 | ") | |
3764 | ||
3765 | ||
3766 | ; Rcq, which is used in alternative 0, checks for conditional execution. | |
3767 | ; At instruction output time, if it doesn't match and we end up with | |
3768 | ; alternative 1 ("q"), that means that we can't use the short form. | |
3769 | (define_insn "*call_i" | |
3770 | [(call (mem:SI (match_operand:SI 0 | |
3771 | "call_address_operand" "Rcq,q,c,Cbp,Cbr,L,I,Cal")) | |
3772 | (match_operand 1 "" "")) | |
3773 | (clobber (reg:SI 31))] | |
3774 | "" | |
3775 | "@ | |
3776 | jl%!%* [%0]%& | |
3777 | jl%!%* [%0]%& | |
3778 | jl%!%* [%0] | |
3779 | bl%!%* %P0 | |
3780 | bl%!%* %P0 | |
3781 | jl%!%* %S0 | |
3782 | jl%* %S0 | |
3783 | jl%! %S0" | |
3784 | [(set_attr "type" "call,call,call,call,call,call,call,call_no_delay_slot") | |
3785 | (set_attr "iscompact" "maybe,false,*,*,*,*,*,*") | |
3786 | (set_attr "predicable" "no,no,yes,yes,no,yes,no,yes") | |
3787 | (set_attr "length" "*,*,4,4,4,4,4,8")]) | |
3788 | ||
3789 | (define_insn "call_prof" | |
3790 | [(call (mem:SI (match_operand:SI 0 "symbolic_operand" "Cbr,Cal")) | |
3791 | (match_operand 1 "" "")) | |
3792 | (clobber (reg:SI 31)) | |
3793 | (use (reg:SI 8)) | |
3794 | (use (reg:SI 9))] | |
3795 | "" | |
3796 | "@ | |
3797 | bl%!%* %P0;2 | |
3798 | jl%! %^%S0" | |
3799 | [(set_attr "type" "call,call_no_delay_slot") | |
3800 | (set_attr "predicable" "yes,yes") | |
3801 | (set_attr "length" "4,8")]) | |
3802 | ||
3803 | (define_expand "call_value" | |
3804 | ;; operand 2 is stack_size_rtx | |
3805 | ;; operand 3 is next_arg_register | |
3806 | [(parallel [(set (match_operand 0 "dest_reg_operand" "=r") | |
3807 | (call (match_operand:SI 1 "call_operand" "") | |
3808 | (match_operand 2 "" ""))) | |
3809 | (clobber (reg:SI 31))])] | |
3810 | "" | |
3811 | " | |
3812 | { | |
3813 | rtx callee; | |
3814 | ||
3815 | gcc_assert (MEM_P (operands[1])); | |
3816 | callee = XEXP (operands[1], 0); | |
3817 | if (crtl->profile && arc_profile_call (callee)) | |
3818 | { | |
3819 | emit_call_insn (gen_call_value_prof (operands[0], | |
3820 | gen_rtx_SYMBOL_REF (Pmode, | |
3821 | \"_mcount_call\"), | |
3822 | operands[2])); | |
3823 | DONE; | |
3824 | } | |
3825 | /* See the comment in define_expand \"call\". */ | |
3826 | if (GET_CODE (callee) != REG | |
3827 | && (GET_CODE (callee) == PLUS || arc_is_longcall_p (callee))) | |
3828 | XEXP (operands[1], 0) = force_reg (Pmode, callee); | |
3829 | }") | |
3830 | ||
3831 | ||
3832 | ; Rcq, which is used in alternative 0, checks for conditional execution. | |
3833 | ; At instruction output time, if it doesn't match and we end up with | |
3834 | ; alternative 1 ("q"), that means that we can't use the short form. | |
3835 | (define_insn "*call_value_i" | |
3836 | [(set (match_operand 0 "dest_reg_operand" "=Rcq,q,w, w, w,w,w, w") | |
3837 | (call (mem:SI (match_operand:SI 1 | |
3838 | "call_address_operand" "Rcq,q,c,Cbp,Cbr,L,I,Cal")) | |
3839 | (match_operand 2 "" ""))) | |
3840 | (clobber (reg:SI 31))] | |
3841 | "" | |
3842 | "@ | |
3843 | jl%!%* [%1]%& | |
3844 | jl%!%* [%1]%& | |
3845 | jl%!%* [%1] | |
3846 | bl%!%* %P1;1 | |
3847 | bl%!%* %P1;1 | |
3848 | jl%!%* %S1 | |
3849 | jl%* %S1 | |
3850 | jl%! %S1" | |
3851 | [(set_attr "type" "call,call,call,call,call,call,call,call_no_delay_slot") | |
3852 | (set_attr "iscompact" "maybe,false,*,*,*,*,*,*") | |
3853 | (set_attr "predicable" "no,no,yes,yes,no,yes,no,yes") | |
3854 | (set_attr "length" "*,*,4,4,4,4,4,8")]) | |
3855 | ||
f55d4a20 JR |
3856 | ; There is a bl_s instruction (16 bit opcode branch-and-link), but we can't |
3857 | ; use it for lack of inter-procedural branch shortening. | |
3858 | ; Link-time relaxation would help... | |
526b7aee | 3859 | |
526b7aee SV |
3860 | |
3861 | (define_insn "call_value_prof" | |
3862 | [(set (match_operand 0 "dest_reg_operand" "=r,r") | |
3863 | (call (mem:SI (match_operand:SI 1 "symbolic_operand" "Cbr,Cal")) | |
3864 | (match_operand 2 "" ""))) | |
3865 | (clobber (reg:SI 31)) | |
3866 | (use (reg:SI 8)) | |
3867 | (use (reg:SI 9))] | |
3868 | "" | |
3869 | "@ | |
3870 | bl%!%* %P1;1 | |
3871 | jl%! %^%S1" | |
3872 | [(set_attr "type" "call,call_no_delay_slot") | |
3873 | (set_attr "predicable" "yes,yes") | |
3874 | (set_attr "length" "4,8")]) | |
3875 | ||
3876 | (define_insn "nop" | |
3877 | [(const_int 0)] | |
3878 | "" | |
3879 | "nop%?" | |
3880 | [(set_attr "type" "misc") | |
3881 | (set_attr "iscompact" "true") | |
3882 | (set_attr "cond" "canuse") | |
3883 | (set_attr "length" "2")]) | |
3884 | ||
3885 | ;; Special pattern to flush the icache. | |
3886 | ;; ??? Not sure what to do here. Some ARC's are known to support this. | |
3887 | ||
3888 | (define_insn "flush_icache" | |
3889 | [(unspec_volatile [(match_operand:SI 0 "memory_operand" "m")] 0)] | |
3890 | "" | |
3891 | "* return \"\";" | |
3892 | [(set_attr "type" "misc")]) | |
3893 | ||
3894 | ;; Split up troublesome insns for better scheduling. | |
3895 | ||
3896 | ;; Peepholes go at the end. | |
3897 | ;;asl followed by add can be replaced by an add{1,2,3} | |
3898 | ;; Three define_peepholes have been added for this optimization | |
3899 | ;; ??? This used to target non-canonical rtl. Now we use add_n, which | |
3900 | ;; can be generated by combine. Check if these peepholes still provide | |
3901 | ;; any benefit. | |
3902 | ||
3903 | ;; ------------------------------------------------------------- | |
3904 | ;; Pattern 1 : r0 = r1 << {i} | |
3905 | ;; r3 = r4/INT + r0 ;;and commutative | |
3906 | ;; || | |
3907 | ;; \/ | |
3908 | ;; add{i} r3,r4/INT,r1 | |
3909 | ;; ------------------------------------------------------------- | |
3910 | ;; ??? This should be covered by combine, alas, at times combine gets | |
3911 | ;; too clever for it's own good: when the shifted input is known to be | |
3912 | ;; either 0 or 1, the operation will be made into an if-then-else, and | |
3913 | ;; thus fail to match the add_n pattern. Example: _mktm_r, line 85 in | |
3914 | ;; newlib/libc/time/mktm_r.c . | |
3915 | ||
3916 | (define_peephole2 | |
3917 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
3918 | (ashift:SI (match_operand:SI 1 "register_operand" "") | |
3919 | (match_operand:SI 2 "const_int_operand" ""))) | |
3920 | (set (match_operand:SI 3 "dest_reg_operand" "") | |
3921 | (plus:SI (match_operand:SI 4 "nonmemory_operand" "") | |
3922 | (match_operand:SI 5 "nonmemory_operand" "")))] | |
3923 | "(INTVAL (operands[2]) == 1 | |
3924 | || INTVAL (operands[2]) == 2 | |
3925 | || INTVAL (operands[2]) == 3) | |
3926 | && (true_regnum (operands[4]) == true_regnum (operands[0]) | |
3927 | || true_regnum (operands[5]) == true_regnum (operands[0])) | |
3928 | && (peep2_reg_dead_p (2, operands[0]) || (true_regnum (operands[3]) == true_regnum (operands[0])))" | |
3929 | ;; the preparation statements take care to put proper operand in operands[4] | |
3930 | ;; operands[4] will always contain the correct operand. This is added to satisfy commutativity | |
3931 | [(set (match_dup 3) | |
3932 | (plus:SI (mult:SI (match_dup 1) | |
3933 | (match_dup 2)) | |
3934 | (match_dup 4)))] | |
3935 | "if (true_regnum (operands[4]) == true_regnum (operands[0])) | |
3936 | operands[4] = operands[5]; | |
3937 | operands[2] = GEN_INT (1 << INTVAL (operands[2]));" | |
3938 | ) | |
3939 | ||
3940 | ;; ------------------------------------------------------------- | |
3941 | ;; Pattern 1 : r0 = r1 << {i} | |
3942 | ;; r3 = r4 - r0 | |
3943 | ;; || | |
3944 | ;; \/ | |
3945 | ;; sub{i} r3,r4,r1 | |
3946 | ;; ------------------------------------------------------------- | |
3947 | ;; ??? This should be covered by combine, alas, at times combine gets | |
3948 | ;; too clever for it's own good: when the shifted input is known to be | |
3949 | ;; either 0 or 1, the operation will be made into an if-then-else, and | |
3950 | ;; thus fail to match the sub_n pattern. Example: __ieee754_yn, line 239 in | |
3951 | ;; newlib/libm/math/e_jn.c . | |
3952 | ||
3953 | (define_peephole2 | |
3954 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
3955 | (ashift:SI (match_operand:SI 1 "register_operand" "") | |
3956 | (match_operand:SI 2 "const_int_operand" ""))) | |
3957 | (set (match_operand:SI 3 "dest_reg_operand" "") | |
3958 | (minus:SI (match_operand:SI 4 "nonmemory_operand" "") | |
3959 | (match_dup 0)))] | |
3960 | "(INTVAL (operands[2]) == 1 | |
3961 | || INTVAL (operands[2]) == 2 | |
3962 | || INTVAL (operands[2]) == 3) | |
3963 | && (peep2_reg_dead_p (2, operands[0]) | |
3964 | || (true_regnum (operands[3]) == true_regnum (operands[0])))" | |
3965 | [(set (match_dup 3) | |
3966 | (minus:SI (match_dup 4) | |
3967 | (mult:SI (match_dup 1) | |
3968 | (match_dup 2))))] | |
3969 | "operands[2] = GEN_INT (1 << INTVAL (operands[2]));" | |
3970 | ) | |
3971 | ||
3972 | ||
3973 | ||
3974 | ; When using the high single bit, the result of a multiply is either | |
3975 | ; the original number or zero. But MPY costs 4 cycles, which we | |
3976 | ; can replace with the 2 cycles for the pair of TST_S and ADD.NE. | |
3977 | (define_peephole2 | |
3978 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
3979 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "") | |
3980 | (const_int 31))) | |
3981 | (set (match_operand:SI 4 "register_operand" "") | |
3982 | (mult:SI (match_operand:SI 2 "register_operand") | |
3983 | (match_operand:SI 3 "nonmemory_operand" "")))] | |
3984 | "TARGET_ARC700 && !TARGET_NOMPY_SET | |
3985 | && (rtx_equal_p (operands[0], operands[2]) | |
3986 | || rtx_equal_p (operands[0], operands[3])) | |
3987 | && peep2_regno_dead_p (0, CC_REG) | |
3988 | && (rtx_equal_p (operands[0], operands[4]) | |
3989 | || (peep2_reg_dead_p (2, operands[0]) | |
3990 | && peep2_reg_dead_p (1, operands[4])))" | |
3991 | [(parallel [(set (reg:CC_Z CC_REG) | |
3992 | (compare:CC_Z (lshiftrt:SI (match_dup 1) (const_int 31)) | |
3993 | (const_int 0))) | |
3994 | (set (match_dup 4) (lshiftrt:SI (match_dup 1) (const_int 31)))]) | |
3995 | (cond_exec | |
3996 | (ne (reg:CC_Z CC_REG) (const_int 0)) | |
3997 | (set (match_dup 4) (match_dup 5)))] | |
3998 | { | |
3999 | if (!rtx_equal_p (operands[0], operands[2])) | |
4000 | operands[5] = operands[2]; | |
4001 | else if (!rtx_equal_p (operands[0], operands[3])) | |
4002 | operands[5] = operands[3]; | |
4003 | else | |
4004 | operands[5] = operands[4]; /* Actually a no-op... presumably rare. */ | |
4005 | }) | |
4006 | ||
4007 | (define_peephole2 | |
4008 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
4009 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "") | |
4010 | (const_int 31))) | |
4011 | (set (match_operand:SI 4 "register_operand" "") | |
4012 | (mult:SI (match_operand:SI 2 "register_operand") | |
4013 | (match_operand:SI 3 "nonmemory_operand" "")))] | |
4014 | "TARGET_ARC700 && !TARGET_NOMPY_SET | |
4015 | && (rtx_equal_p (operands[0], operands[2]) | |
4016 | || rtx_equal_p (operands[0], operands[3])) | |
4017 | && peep2_regno_dead_p (2, CC_REG)" | |
4018 | [(parallel [(set (reg:CC_Z CC_REG) | |
4019 | (compare:CC_Z (lshiftrt:SI (match_dup 1) (const_int 31)) | |
4020 | (const_int 0))) | |
4021 | (set (match_dup 0) (lshiftrt:SI (match_dup 1) (const_int 31)))]) | |
4022 | (set (match_dup 4) (match_dup 5)) | |
4023 | (cond_exec | |
4024 | (eq (reg:CC_Z CC_REG) (const_int 0)) | |
4025 | (set (match_dup 4) (const_int 0)))] | |
4026 | "operands[5] = operands[rtx_equal_p (operands[0], operands[2]) ? 3 : 2];") | |
4027 | ||
4028 | ;; Instructions generated through builtins | |
4029 | ||
4030 | (define_insn "clrsbsi2" | |
4031 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
4032 | (clrsb:SI (match_operand:SI 1 "general_operand" "cL,Cal")))] | |
4033 | "TARGET_NORM" | |
4034 | "@ | |
4035 | norm \t%0, %1 | |
4036 | norm \t%0, %S1" | |
4037 | [(set_attr "length" "4,8") | |
4038 | (set_attr "type" "two_cycle_core,two_cycle_core")]) | |
4039 | ||
4040 | (define_insn "norm_f" | |
4041 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
4042 | (clrsb:SI (match_operand:SI 1 "general_operand" "cL,Cal"))) | |
4043 | (set (reg:CC_ZN CC_REG) | |
4044 | (compare:CC_ZN (match_dup 1) (const_int 0)))] | |
4045 | "TARGET_NORM" | |
4046 | "@ | |
4047 | norm.f\t%0, %1 | |
4048 | norm.f\t%0, %S1" | |
4049 | [(set_attr "length" "4,8") | |
4050 | (set_attr "type" "two_cycle_core,two_cycle_core")]) | |
4051 | ||
4052 | (define_insn_and_split "clrsbhi2" | |
4053 | [(set (match_operand:HI 0 "dest_reg_operand" "=w,w") | |
4054 | (clrsb:HI (match_operand:HI 1 "general_operand" "cL,Cal")))] | |
4055 | "TARGET_NORM" | |
4056 | "#" | |
4057 | "reload_completed" | |
4058 | [(set (match_dup 0) (zero_extend:SI (clrsb:HI (match_dup 1))))] | |
4059 | "operands[0] = simplify_gen_subreg (SImode, operands[0], HImode, 0);") | |
4060 | ||
4061 | (define_insn "normw" | |
4062 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,w") | |
4063 | (zero_extend:SI | |
4064 | (clrsb:HI (match_operand:HI 1 "general_operand" "cL,Cal"))))] | |
4065 | "TARGET_NORM" | |
4066 | "@ | |
4067 | normw \t%0, %1 | |
4068 | normw \t%0, %S1" | |
4069 | [(set_attr "length" "4,8") | |
4070 | (set_attr "type" "two_cycle_core,two_cycle_core")]) | |
4071 | ||
4072 | (define_expand "clzsi2" | |
4073 | [(set (match_operand:SI 0 "dest_reg_operand" "") | |
4074 | (clz:SI (match_operand:SI 1 "register_operand" "")))] | |
4075 | "TARGET_NORM" | |
4076 | { | |
4077 | emit_insn (gen_norm_f (operands[0], operands[1])); | |
4078 | emit_insn | |
4079 | (gen_rtx_COND_EXEC | |
4080 | (VOIDmode, | |
4081 | gen_rtx_LT (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx), | |
f7df4a84 | 4082 | gen_rtx_SET (operands[0], const0_rtx))); |
526b7aee SV |
4083 | emit_insn |
4084 | (gen_rtx_COND_EXEC | |
4085 | (VOIDmode, | |
4086 | gen_rtx_GE (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx), | |
f7df4a84 | 4087 | gen_rtx_SET (operands[0], plus_constant (SImode, operands[0], 1)))); |
526b7aee SV |
4088 | DONE; |
4089 | }) | |
4090 | ||
4091 | (define_expand "ctzsi2" | |
4092 | [(set (match_operand:SI 0 "register_operand" "") | |
4093 | (ctz:SI (match_operand:SI 1 "register_operand" "")))] | |
4094 | "TARGET_NORM" | |
4095 | { | |
4096 | rtx temp = operands[0]; | |
4097 | ||
4098 | if (reg_overlap_mentioned_p (temp, operands[1]) | |
4099 | || (REGNO (temp) < FIRST_PSEUDO_REGISTER | |
4100 | && !TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], | |
4101 | REGNO (temp)))) | |
4102 | temp = gen_reg_rtx (SImode); | |
4103 | emit_insn (gen_addsi3 (temp, operands[1], constm1_rtx)); | |
4104 | emit_insn (gen_bic_f_zn (temp, temp, operands[1])); | |
4105 | emit_insn (gen_clrsbsi2 (temp, temp)); | |
4106 | emit_insn | |
4107 | (gen_rtx_COND_EXEC | |
4108 | (VOIDmode, | |
4109 | gen_rtx_LT (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx), | |
f7df4a84 | 4110 | gen_rtx_SET (operands[0], GEN_INT (32)))); |
526b7aee SV |
4111 | emit_insn |
4112 | (gen_rtx_COND_EXEC | |
4113 | (VOIDmode, | |
4114 | gen_rtx_GE (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx), | |
f7df4a84 | 4115 | gen_rtx_SET (operands[0], gen_rtx_MINUS (SImode, GEN_INT (31), temp)))); |
526b7aee SV |
4116 | DONE; |
4117 | }) | |
4118 | ||
4119 | ||
4120 | (define_insn "swap" | |
4121 | [(set (match_operand:SI 0 "dest_reg_operand" "=w,w,w") | |
4122 | (unspec:SI [(match_operand:SI 1 "general_operand" "L,Cal,c")] | |
4123 | UNSPEC_SWAP))] | |
4124 | "TARGET_SWAP" | |
4125 | "@ | |
4126 | swap \t%0, %1 | |
4127 | swap \t%0, %S1 | |
4128 | swap \t%0, %1" | |
4129 | [(set_attr "length" "4,8,4") | |
4130 | (set_attr "type" "two_cycle_core,two_cycle_core,two_cycle_core")]) | |
4131 | ||
4132 | ;; FIXME: an intrinsic for multiply is daft. Can we remove this? | |
4133 | (define_insn "mul64" | |
73f793e3 | 4134 | [(unspec [(match_operand:SI 0 "general_operand" "%q,r,r,r") |
526b7aee SV |
4135 | (match_operand:SI 1 "general_operand" "q,rL,I,Cal")] |
4136 | UNSPEC_MUL64)] | |
4137 | "TARGET_MUL64_SET" | |
4138 | "@ | |
4139 | mul64%? \t0, %0, %1%& | |
4140 | mul64%? \t0, %0, %1 | |
4141 | mul64 \t0, %0, %1 | |
4142 | mul64%? \t0, %0, %S1" | |
4143 | [(set_attr "length" "2,4,4,8") | |
4144 | (set_attr "iscompact" "true,false,false,false") | |
4145 | (set_attr "type" "binary,binary,binary,binary") | |
4146 | (set_attr "cond" "canuse,canuse, nocond, canuse")]) | |
4147 | ||
4148 | (define_insn "mulu64" | |
4149 | [(unspec [(match_operand:SI 0 "general_operand" "%r,r,r,r") | |
4150 | (match_operand:SI 1 "general_operand" "rL,I,r,Cal")] | |
4151 | UNSPEC_MULU64)] | |
4152 | "TARGET_MUL64_SET" | |
4153 | "@ | |
4154 | mulu64%? \t0, %0, %1 | |
4155 | mulu64 \t0, %0, %1 | |
4156 | mulu64 \t0, %0, %1 | |
4157 | mulu64%? \t0, %0, %S1" | |
4158 | [(set_attr "length" "4,4,4,8") | |
4159 | (set_attr "type" "binary,binary,binary,binary") | |
4160 | (set_attr "cond" "canuse,nocond,nocond,canuse")]) | |
4161 | ||
4162 | (define_insn "divaw" | |
4163 | [(set (match_operand:SI 0 "dest_reg_operand" "=&w,&w,&w") | |
4164 | (unspec:SI [(div:SI (match_operand:SI 1 "general_operand" "r,Cal,r") | |
4165 | (match_operand:SI 2 "general_operand" "r,r,Cal"))] | |
4166 | UNSPEC_DIVAW))] | |
4167 | "TARGET_ARC700 || TARGET_EA_SET" | |
4168 | "@ | |
4169 | divaw \t%0, %1, %2 | |
4170 | divaw \t%0, %S1, %2 | |
4171 | divaw \t%0, %1, %S2" | |
4172 | [(set_attr "length" "4,8,8") | |
4173 | (set_attr "type" "divaw,divaw,divaw")]) | |
4174 | ||
4175 | (define_insn "flag" | |
4176 | [(unspec_volatile [(match_operand:SI 0 "nonmemory_operand" "rL,I,Cal")] | |
4177 | VUNSPEC_FLAG)] | |
4178 | "" | |
4179 | "@ | |
4180 | flag%? %0 | |
4181 | flag %0 | |
4182 | flag%? %S0" | |
4183 | [(set_attr "length" "4,4,8") | |
4184 | (set_attr "type" "misc,misc,misc") | |
4185 | (set_attr "predicable" "yes,no,yes") | |
4186 | (set_attr "cond" "clob,clob,clob")]) | |
4187 | ||
4188 | (define_insn "brk" | |
4189 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "N")] | |
4190 | VUNSPEC_BRK)] | |
4191 | "" | |
4192 | "brk" | |
4193 | [(set_attr "length" "4") | |
4194 | (set_attr "type" "misc")]) | |
4195 | ||
4196 | (define_insn "rtie" | |
4197 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "N")] | |
4198 | VUNSPEC_RTIE)] | |
4199 | "" | |
4200 | "rtie" | |
4201 | [(set_attr "length" "4") | |
4202 | (set_attr "type" "misc") | |
4203 | (set_attr "cond" "clob")]) | |
4204 | ||
4205 | (define_insn "sync" | |
4206 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "N")] | |
4207 | VUNSPEC_SYNC)] | |
4208 | "" | |
4209 | "sync" | |
4210 | [(set_attr "length" "4") | |
4211 | (set_attr "type" "misc")]) | |
4212 | ||
4213 | (define_insn "swi" | |
4214 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "N")] | |
4215 | VUNSPEC_SWI)] | |
4216 | "" | |
4217 | "* | |
4218 | { | |
4219 | if(TARGET_ARC700) | |
4220 | return \"trap0\"; | |
4221 | else | |
4222 | return \"swi\"; | |
4223 | }" | |
4224 | [(set_attr "length" "4") | |
4225 | (set_attr "type" "misc")]) | |
4226 | ||
4227 | ||
4228 | (define_insn "sleep" | |
4229 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "L")] | |
4230 | VUNSPEC_SLEEP)] | |
4231 | "check_if_valid_sleep_operand(operands,0)" | |
4232 | "sleep %0" | |
4233 | [(set_attr "length" "4") | |
4234 | (set_attr "type" "misc")]) | |
4235 | ||
4236 | (define_insn "core_read" | |
4237 | [(set (match_operand:SI 0 "dest_reg_operand" "=r,r") | |
4238 | (unspec_volatile:SI [(match_operand:SI 1 "general_operand" "Hn,!r")] | |
4239 | VUNSPEC_CORE_READ))] | |
4240 | "" | |
4241 | "* | |
4242 | if (check_if_valid_regno_const (operands, 1)) | |
4243 | return \"mov \t%0, r%1\"; | |
4244 | return \"mov \t%0, r%1\"; | |
4245 | " | |
4246 | [(set_attr "length" "4") | |
4247 | (set_attr "type" "unary")]) | |
4248 | ||
4249 | (define_insn "core_write" | |
4250 | [(unspec_volatile [(match_operand:SI 0 "general_operand" "r,r") | |
4251 | (match_operand:SI 1 "general_operand" "Hn,!r")] | |
4252 | VUNSPEC_CORE_WRITE)] | |
4253 | "" | |
4254 | "* | |
4255 | if (check_if_valid_regno_const (operands, 1)) | |
4256 | return \"mov \tr%1, %0\"; | |
4257 | return \"mov \tr%1, %0\"; | |
4258 | " | |
4259 | [(set_attr "length" "4") | |
4260 | (set_attr "type" "unary")]) | |
4261 | ||
4262 | (define_insn "lr" | |
4263 | [(set (match_operand:SI 0 "dest_reg_operand" "=r,r,r,r") | |
4264 | (unspec_volatile:SI [(match_operand:SI 1 "general_operand" "I,HCal,r,D")] | |
4265 | VUNSPEC_LR))] | |
4266 | "" | |
4267 | "lr\t%0, [%1]" | |
4268 | [(set_attr "length" "4,8,4,8") | |
4269 | (set_attr "type" "lr,lr,lr,lr")]) | |
4270 | ||
4271 | (define_insn "sr" | |
4272 | [(unspec_volatile [(match_operand:SI 0 "general_operand" "Cal,r,r,r") | |
4273 | (match_operand:SI 1 "general_operand" "Ir,I,HCal,r")] | |
4274 | VUNSPEC_SR)] | |
4275 | "" | |
4276 | "sr\t%S0, [%1]" | |
4277 | [(set_attr "length" "8,4,8,4") | |
4278 | (set_attr "type" "sr,sr,sr,sr")]) | |
4279 | ||
4280 | (define_insn "trap_s" | |
4281 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "L,Cal")] | |
4282 | VUNSPEC_TRAP_S)] | |
4283 | "TARGET_ARC700" | |
4284 | { | |
4285 | if (which_alternative == 0) | |
4286 | { | |
4287 | arc_toggle_unalign (); | |
4288 | return \"trap_s %0\"; | |
4289 | } | |
4290 | ||
4291 | /* Keep this message in sync with the one in arc.c:arc_expand_builtin, | |
4292 | because *.md files do not get scanned by exgettext. */ | |
40fecdd6 JM |
4293 | fatal_error (input_location, |
4294 | \"operand to trap_s should be an unsigned 6-bit value\"); | |
526b7aee SV |
4295 | } |
4296 | [(set_attr "length" "2") | |
4297 | (set_attr "type" "misc")]) | |
4298 | ||
4299 | (define_insn "unimp_s" | |
4300 | [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "N")] | |
4301 | VUNSPEC_UNIMP_S)] | |
4302 | "TARGET_ARC700" | |
4303 | "unimp_s" | |
4304 | [(set_attr "length" "4") | |
4305 | (set_attr "type" "misc")]) | |
4306 | ||
4307 | ;; End of instructions generated through builtins | |
4308 | ||
4309 | ; Since the demise of REG_N_SETS as reliable data readily available to the | |
4310 | ; target, it is no longer possible to find out | |
4311 | ; in the prologue / epilogue expanders how many times blink is set. | |
4312 | ; Using df_regs_ever_live_p to decide if blink needs saving means that | |
4313 | ; any explicit use of blink will cause it to be saved; hence we cannot | |
4314 | ; represent the blink use in return / sibcall instructions themselves, and | |
4315 | ; instead have to show it in EPILOGUE_USES and must explicitly | |
4316 | ; forbid instructions that change blink in the return / sibcall delay slot. | |
4317 | (define_expand "sibcall" | |
4318 | [(parallel [(call (match_operand 0 "memory_operand" "") | |
4319 | (match_operand 1 "general_operand" "")) | |
4320 | (simple_return) | |
4321 | (use (match_operand 2 "" ""))])] | |
4322 | "" | |
4323 | " | |
4324 | { | |
4325 | rtx callee = XEXP (operands[0], 0); | |
4326 | ||
4327 | if (operands[2] == NULL_RTX) | |
4328 | operands[2] = const0_rtx; | |
4329 | if (crtl->profile && arc_profile_call (callee)) | |
4330 | { | |
4331 | emit_insn (gen_sibcall_prof | |
4332 | (gen_rtx_SYMBOL_REF (Pmode, \"_mcount_call\"), | |
4333 | operands[1], operands[2])); | |
4334 | DONE; | |
4335 | } | |
4336 | if (GET_CODE (callee) != REG | |
4337 | && (GET_CODE (callee) == PLUS || arc_is_longcall_p (callee))) | |
4338 | XEXP (operands[0], 0) = force_reg (Pmode, callee); | |
4339 | }" | |
4340 | ) | |
4341 | ||
4342 | (define_expand "sibcall_value" | |
4343 | [(parallel [(set (match_operand 0 "dest_reg_operand" "") | |
4344 | (call (match_operand 1 "memory_operand" "") | |
4345 | (match_operand 2 "general_operand" ""))) | |
4346 | (simple_return) | |
4347 | (use (match_operand 3 "" ""))])] | |
4348 | "" | |
4349 | " | |
4350 | { | |
4351 | rtx callee = XEXP (operands[1], 0); | |
4352 | ||
4353 | if (operands[3] == NULL_RTX) | |
4354 | operands[3] = const0_rtx; | |
4355 | if (crtl->profile && arc_profile_call (XEXP (operands[1], 0))) | |
4356 | { | |
4357 | emit_insn (gen_sibcall_value_prof | |
4358 | (operands[0], gen_rtx_SYMBOL_REF (Pmode, \"_mcount_call\"), | |
4359 | operands[2], operands[3])); | |
4360 | DONE; | |
4361 | } | |
4362 | if (GET_CODE (callee) != REG && arc_is_longcall_p (callee)) | |
4363 | XEXP (operands[1], 0) = force_reg (Pmode, callee); | |
4364 | }" | |
4365 | ) | |
4366 | ||
4367 | (define_insn "*sibcall_insn" | |
4368 | [(call (mem:SI (match_operand:SI 0 "call_address_operand" | |
4369 | "Cbp,Cbr,Rs5,Rsc,Cal")) | |
4370 | (match_operand 1 "" "")) | |
4371 | (simple_return) | |
4372 | (use (match_operand 2 "" ""))] | |
4373 | "" | |
4374 | "@ | |
4375 | b%!%* %P0 | |
4376 | b%!%* %P0 | |
4377 | j%!%* [%0]%& | |
4378 | j%!%* [%0] | |
4379 | j%! %P0" | |
4380 | [(set_attr "type" "call,call,call,call,call_no_delay_slot") | |
4381 | (set_attr "predicable" "yes,no,no,yes,yes") | |
4382 | (set_attr "iscompact" "false,false,maybe,false,false") | |
4383 | (set_attr "is_SIBCALL" "yes")] | |
4384 | ) | |
4385 | ||
4386 | (define_insn "*sibcall_value_insn" | |
4387 | [(set (match_operand 0 "dest_reg_operand" "") | |
4388 | (call (mem:SI (match_operand:SI 1 "call_address_operand" | |
4389 | "Cbp,Cbr,Rs5,Rsc,Cal")) | |
4390 | (match_operand 2 "" ""))) | |
4391 | (simple_return) | |
4392 | (use (match_operand 3 "" ""))] | |
4393 | "" | |
4394 | "@ | |
4395 | b%!%* %P1 | |
4396 | b%!%* %P1 | |
4397 | j%!%* [%1]%& | |
4398 | j%!%* [%1] | |
4399 | j%! %P1" | |
4400 | [(set_attr "type" "call,call,call,call,call_no_delay_slot") | |
4401 | (set_attr "predicable" "yes,no,no,yes,yes") | |
4402 | (set_attr "iscompact" "false,false,maybe,false,false") | |
4403 | (set_attr "is_SIBCALL" "yes")] | |
4404 | ) | |
4405 | ||
4406 | (define_insn "sibcall_prof" | |
4407 | [(call (mem:SI (match_operand:SI 0 "call_address_operand" "Cbr,Cal")) | |
4408 | (match_operand 1 "" "")) | |
4409 | (simple_return) | |
4410 | (use (match_operand 2 "" "")) | |
4411 | (use (reg:SI 8)) | |
4412 | (use (reg:SI 9))] | |
4413 | "" | |
4414 | "@ | |
4415 | b%!%* %P0;2 | |
4416 | j%! %^%S0;2" | |
4417 | [(set_attr "type" "call,call_no_delay_slot") | |
4418 | (set_attr "predicable" "yes") | |
4419 | (set_attr "is_SIBCALL" "yes")] | |
4420 | ) | |
4421 | ||
4422 | (define_insn "sibcall_value_prof" | |
4423 | [(set (match_operand 0 "dest_reg_operand" "") | |
4424 | (call (mem:SI (match_operand:SI 1 "call_address_operand" "Cbr,Cal")) | |
4425 | (match_operand 2 "" ""))) | |
4426 | (simple_return) | |
4427 | (use (match_operand 3 "" "")) | |
4428 | (use (reg:SI 8)) | |
4429 | (use (reg:SI 9))] | |
4430 | "" | |
4431 | "@ | |
4432 | b%!%* %P1;1 | |
4433 | j%! %^%S1;1" | |
4434 | [(set_attr "type" "call,call_no_delay_slot") | |
4435 | (set_attr "predicable" "yes") | |
4436 | (set_attr "is_SIBCALL" "yes")] | |
4437 | ) | |
4438 | ||
4439 | (define_expand "prologue" | |
4440 | [(pc)] | |
4441 | "" | |
4442 | { | |
4443 | arc_expand_prologue (); | |
4444 | DONE; | |
4445 | }) | |
4446 | ||
4447 | (define_expand "epilogue" | |
4448 | [(pc)] | |
4449 | "" | |
4450 | { | |
4451 | arc_expand_epilogue (0); | |
4452 | DONE; | |
4453 | }) | |
4454 | ||
4455 | (define_expand "sibcall_epilogue" | |
4456 | [(pc)] | |
4457 | "" | |
4458 | { | |
4459 | arc_expand_epilogue (1); | |
4460 | DONE; | |
4461 | }) | |
4462 | ||
4463 | ; Since the demise of REG_N_SETS, it is no longer possible to find out | |
4464 | ; in the prologue / epilogue expanders how many times blink is set. | |
4465 | ; Using df_regs_ever_live_p to decide if blink needs saving means that | |
4466 | ; any explicit use of blink will cause it to be saved; hence we cannot | |
4467 | ; represent the blink use in return / sibcall instructions themselves, and | |
4468 | ; instead have to show it in EPILOGUE_USES and must explicitly | |
4469 | ; forbid instructions that change blink in the return / sibcall delay slot. | |
4470 | (define_insn "simple_return" | |
4471 | [(simple_return)] | |
4472 | "reload_completed" | |
4473 | { | |
4474 | rtx reg | |
4475 | = gen_rtx_REG (Pmode, | |
4476 | arc_return_address_regs[arc_compute_function_type (cfun)]); | |
4477 | ||
4478 | if (TARGET_PAD_RETURN) | |
4479 | arc_pad_return (); | |
4480 | output_asm_insn (\"j%!%* [%0]%&\", ®); | |
4481 | return \"\"; | |
4482 | } | |
4483 | [(set_attr "type" "return") | |
4484 | ; predicable won't help here since the canonical rtl looks different | |
4485 | ; for branches. | |
4486 | (set_attr "cond" "canuse") | |
4487 | (set (attr "iscompact") | |
4488 | (cond [(eq (symbol_ref "arc_compute_function_type (cfun)") | |
4489 | (symbol_ref "ARC_FUNCTION_NORMAL")) | |
4490 | (const_string "maybe")] | |
4491 | (const_string "false"))) | |
4492 | (set (attr "length") | |
4493 | (cond [(ne (symbol_ref "arc_compute_function_type (cfun)") | |
4494 | (symbol_ref "ARC_FUNCTION_NORMAL")) | |
4495 | (const_int 4)] | |
4496 | (const_int 2)))]) | |
4497 | ||
4498 | (define_insn "p_return_i" | |
4499 | [(set (pc) | |
4500 | (if_then_else (match_operator 0 "proper_comparison_operator" | |
4501 | [(reg CC_REG) (const_int 0)]) | |
4502 | (simple_return) (pc)))] | |
4503 | "reload_completed" | |
4504 | { | |
4505 | rtx xop[2]; | |
4506 | xop[0] = operands[0]; | |
4507 | xop[1] | |
4508 | = gen_rtx_REG (Pmode, | |
4509 | arc_return_address_regs[arc_compute_function_type (cfun)]); | |
4510 | ||
4511 | if (TARGET_PAD_RETURN) | |
4512 | arc_pad_return (); | |
4513 | output_asm_insn (\"j%d0%!%# [%1]%&\", xop); | |
4514 | /* record the condition in case there is a delay insn. */ | |
4515 | arc_ccfsm_record_condition (xop[0], false, insn, 0); | |
4516 | return \"\"; | |
4517 | } | |
4518 | [(set_attr "type" "return") | |
4519 | (set_attr "cond" "use") | |
4520 | (set (attr "iscompact") | |
4521 | (cond [(eq (symbol_ref "arc_compute_function_type (cfun)") | |
4522 | (symbol_ref "ARC_FUNCTION_NORMAL")) | |
4523 | (const_string "maybe")] | |
4524 | (const_string "false"))) | |
4525 | (set (attr "length") | |
4526 | (cond [(ne (symbol_ref "arc_compute_function_type (cfun)") | |
4527 | (symbol_ref "ARC_FUNCTION_NORMAL")) | |
4528 | (const_int 4) | |
4529 | (not (match_operand 0 "equality_comparison_operator" "")) | |
4530 | (const_int 4) | |
4531 | (eq_attr "delay_slot_filled" "yes") | |
4532 | (const_int 4)] | |
4533 | (const_int 2)))]) | |
4534 | ||
4535 | (define_insn_and_split "eh_return" | |
4536 | [(eh_return) | |
4537 | (use (match_operand:SI 0 "move_src_operand" "rC32,mCalCpc")) | |
4538 | (clobber (match_scratch:SI 1 "=X,r")) | |
4539 | (clobber (match_scratch:SI 2 "=&r,r"))] | |
4540 | "" | |
4541 | "#" | |
4542 | "reload_completed" | |
4543 | [(set (match_dup 2) (match_dup 0))] | |
4544 | { | |
4545 | int offs = arc_return_slot_offset (); | |
4546 | ||
4547 | if (offs < 0) | |
4548 | operands[2] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); | |
4549 | else | |
4550 | { | |
4551 | if (!register_operand (operands[0], Pmode) | |
4552 | && !satisfies_constraint_C32 (operands[0])) | |
4553 | { | |
4554 | emit_move_insn (operands[1], operands[0]); | |
4555 | operands[0] = operands[1]; | |
4556 | } | |
4557 | rtx addr = plus_constant (Pmode, stack_pointer_rtx, offs); | |
4558 | if (!strict_memory_address_p (Pmode, addr)) | |
4559 | { | |
4560 | emit_move_insn (operands[2], addr); | |
4561 | addr = operands[2]; | |
4562 | } | |
4563 | operands[2] = gen_frame_mem (Pmode, addr); | |
4564 | } | |
4565 | } | |
4566 | [(set_attr "length" "12")]) | |
4567 | ||
4568 | ;; ??? #ifdefs in function.c require the presence of this pattern, with a | |
4569 | ;; non-constant predicate. | |
4570 | (define_expand "return" | |
4571 | [(return)] | |
4572 | "optimize < 0") | |
4573 | ||
4574 | ;; Comment in final.c (insn_current_reference_address) says | |
4575 | ;; forward branch addresses are calculated from the next insn after branch | |
4576 | ;; and for backward branches, it is calculated from the branch insn start. | |
4577 | ;; The shortening logic here is tuned to accomodate this behaviour | |
4578 | ;; ??? This should be grokked by the ccfsm machinery. | |
4579 | (define_insn "cbranchsi4_scratch" | |
4580 | [(set (pc) | |
4581 | (if_then_else (match_operator 0 "proper_comparison_operator" | |
4582 | [(match_operand:SI 1 "register_operand" "c,c, c") | |
4583 | (match_operand:SI 2 "nonmemory_operand" "L,c,?Cal")]) | |
4584 | (label_ref (match_operand 3 "" "")) | |
4585 | (pc))) | |
4586 | (clobber (match_operand 4 "cc_register" ""))] | |
4587 | "(reload_completed | |
4588 | || (TARGET_EARLY_CBRANCHSI | |
4589 | && brcc_nolimm_operator (operands[0], VOIDmode))) | |
339ba33b | 4590 | && !CROSSING_JUMP_P (insn)" |
526b7aee SV |
4591 | "* |
4592 | switch (get_attr_length (insn)) | |
4593 | { | |
4594 | case 2: return \"br%d0%? %1, %2, %^%l3%&\"; | |
4595 | case 4: return \"br%d0%* %1, %B2, %^%l3\"; | |
4596 | case 8: if (!brcc_nolimm_operator (operands[0], VOIDmode)) | |
4597 | return \"br%d0%* %1, %B2, %^%l3\"; | |
4598 | case 6: case 10: | |
4599 | case 12:return \"cmp%? %1, %B2\\n\\tb%d0%* %^%l3%&;br%d0 out of range\"; | |
4600 | default: fprintf (stderr, \"unexpected length %d\\n\", get_attr_length (insn)); fflush (stderr); gcc_unreachable (); | |
4601 | } | |
4602 | " | |
4603 | [(set_attr "cond" "clob, clob, clob") | |
4604 | (set (attr "type") | |
4605 | (if_then_else | |
4606 | (match_test "valid_brcc_with_delay_p (operands)") | |
4607 | (const_string "brcc") | |
4608 | (const_string "brcc_no_delay_slot"))) | |
4609 | ; For forward branches, we need to account not only for the distance to | |
4610 | ; the target, but also the difference between pcl and pc, the instruction | |
4611 | ; length, and any delay insn, if present. | |
4612 | (set | |
4613 | (attr "length") | |
4614 | (cond ; the outer cond does a test independent of branch shortening. | |
4615 | [(match_operand 0 "brcc_nolimm_operator" "") | |
4616 | (cond | |
4617 | [(and (match_operand:CC_Z 4 "cc_register") | |
4618 | (eq_attr "delay_slot_filled" "no") | |
4619 | (ge (minus (match_dup 3) (pc)) (const_int -128)) | |
4620 | (le (minus (match_dup 3) (pc)) | |
4621 | (minus (const_int 122) | |
4622 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
4623 | (const_int 2) | |
4624 | (and (ge (minus (match_dup 3) (pc)) (const_int -256)) | |
4625 | (le (minus (match_dup 3) (pc)) | |
4626 | (minus (const_int 244) | |
4627 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
4628 | (const_int 4) | |
4629 | (match_operand:SI 1 "compact_register_operand" "") | |
4630 | (const_int 6)] | |
4631 | (const_int 8))] | |
4632 | (cond [(and (ge (minus (match_dup 3) (pc)) (const_int -256)) | |
4633 | (le (minus (match_dup 3) (pc)) (const_int 244))) | |
4634 | (const_int 8) | |
4635 | (match_operand:SI 1 "compact_register_operand" "") | |
4636 | (const_int 10)] | |
4637 | (const_int 12)))) | |
4638 | (set (attr "iscompact") | |
4639 | (if_then_else (match_test "get_attr_length (insn) & 2") | |
4640 | (const_string "true") (const_string "false")))]) | |
4641 | ||
4642 | ; combiner pattern observed for unwind-dw2-fde.c:linear_search_fdes. | |
4643 | (define_insn "*bbit" | |
4644 | [(set (pc) | |
4645 | (if_then_else | |
4646 | (match_operator 3 "equality_comparison_operator" | |
4647 | [(zero_extract:SI (match_operand:SI 1 "register_operand" "Rcqq,c") | |
4648 | (const_int 1) | |
4649 | (match_operand:SI 2 "nonmemory_operand" "L,Lc")) | |
4650 | (const_int 0)]) | |
4651 | (label_ref (match_operand 0 "" "")) | |
4652 | (pc))) | |
4653 | (clobber (reg:CC_ZN CC_REG))] | |
339ba33b | 4654 | "!CROSSING_JUMP_P (insn)" |
526b7aee SV |
4655 | { |
4656 | switch (get_attr_length (insn)) | |
4657 | { | |
4658 | case 4: return (GET_CODE (operands[3]) == EQ | |
4659 | ? \"bbit0%* %1,%2,%0\" : \"bbit1%* %1,%2,%0\"); | |
4660 | case 6: | |
4661 | case 8: return \"btst%? %1,%2\n\tb%d3%* %0; bbit out of range\"; | |
4662 | default: gcc_unreachable (); | |
4663 | } | |
4664 | } | |
4665 | [(set_attr "type" "brcc") | |
4666 | (set_attr "cond" "clob") | |
4667 | (set (attr "length") | |
4668 | (cond [(and (ge (minus (match_dup 0) (pc)) (const_int -254)) | |
4669 | (le (minus (match_dup 0) (pc)) | |
4670 | (minus (const_int 248) | |
4671 | (symbol_ref "get_attr_delay_slot_length (insn)")))) | |
4672 | (const_int 4) | |
4673 | (eq (symbol_ref "which_alternative") (const_int 0)) | |
4674 | (const_int 6)] | |
4675 | (const_int 8))) | |
4676 | (set (attr "iscompact") | |
4677 | (if_then_else (match_test "get_attr_length (insn) == 6") | |
4678 | (const_string "true") (const_string "false")))]) | |
4679 | ||
4680 | ; ??? When testing a bit from a DImode register, combine creates a | |
4681 | ; zero_extract in DImode. This goes via an AND with a DImode constant, | |
4682 | ; so can only be observed on 64 bit hosts. | |
4683 | (define_insn_and_split "*bbit_di" | |
4684 | [(set (pc) | |
4685 | (if_then_else | |
4686 | (match_operator 3 "equality_comparison_operator" | |
4687 | [(zero_extract:DI (match_operand:SI 1 "register_operand" "Rcqq,c") | |
4688 | (const_int 1) | |
4689 | (match_operand 2 "immediate_operand" "L,L")) | |
4690 | (const_int 0)]) | |
4691 | (label_ref (match_operand 0 "" "")) | |
4692 | (pc))) | |
4693 | (clobber (reg:CC_ZN CC_REG))] | |
339ba33b | 4694 | "!CROSSING_JUMP_P (insn)" |
526b7aee SV |
4695 | "#" |
4696 | "" | |
4697 | [(parallel | |
4698 | [(set (pc) (if_then_else (match_dup 3) (label_ref (match_dup 0)) (pc))) | |
4699 | (clobber (reg:CC_ZN CC_REG))])] | |
4700 | { | |
4701 | rtx xtr; | |
4702 | ||
4703 | xtr = gen_rtx_ZERO_EXTRACT (SImode, operands[1], const1_rtx, operands[2]); | |
4704 | operands[3] = gen_rtx_fmt_ee (GET_CODE (operands[3]), GET_MODE (operands[3]), | |
4705 | xtr, const0_rtx); | |
4706 | }) | |
4707 | ||
4708 | ; operand 0 is the loop count pseudo register | |
1d0216c8 | 4709 | ; operand 1 is the loop end pattern |
526b7aee SV |
4710 | (define_expand "doloop_begin" |
4711 | [(use (match_operand 0 "register_operand" "")) | |
1d0216c8 | 4712 | (use (match_operand 1 "" ""))] |
526b7aee SV |
4713 | "" |
4714 | { | |
4715 | /* Using the INSN_UID of the loop end pattern to identify it causes | |
4716 | trouble with -fcompare-debug, so allocate a debug-independent | |
4717 | id instead. We use negative numbers so that we can use the same | |
4718 | slot in doloop_end_i where we later store a CODE_LABEL_NUMBER, and | |
4719 | still be able to tell what kind of number this is. */ | |
4720 | static HOST_WIDE_INT loop_end_id = 0; | |
4721 | ||
526b7aee | 4722 | rtx id = GEN_INT (--loop_end_id); |
1d0216c8 | 4723 | XEXP (XVECEXP (PATTERN (operands[1]), 0, 4), 0) = id; |
526b7aee SV |
4724 | emit_insn (gen_doloop_begin_i (operands[0], const0_rtx, id, |
4725 | const0_rtx, const0_rtx)); | |
4726 | DONE; | |
4727 | }) | |
4728 | ||
4729 | ; ??? can't describe the insn properly as then the optimizers try to | |
4730 | ; hoist the SETs. | |
4731 | ;(define_insn "doloop_begin_i" | |
4732 | ; [(set (reg:SI LP_START) (pc)) | |
4733 | ; (set (reg:SI LP_END) (unspec:SI [(pc)] UNSPEC_LP)) | |
4734 | ; (use (match_operand 0 "const_int_operand" "n"))] | |
4735 | ; "" | |
4736 | ; "lp .L__GCC__LP%0" | |
4737 | ;) | |
4738 | ||
4739 | ; The operands of doloop_end_i are also read / written by arc_reorg with | |
4740 | ; XVECEXP (PATTERN (lp, 0, N), so if you want to change the pattern, you | |
4741 | ; might have to adjust arc_reorg. | |
4742 | ; operands 0 / 2 are supplied by the expander, 1, 3 and 4 are filled in | |
4743 | ; by arc_reorg. arc_reorg might also alter operand 0. | |
4744 | ; | |
4745 | ; N in XVECEXP PATTERN (lp, 0 N) | |
4746 | ; V rtl purpose | |
4747 | ; 0 unspec UNSPEC_LP identify pattern | |
4748 | ; 1 clobber LP_START show LP_START is set | |
4749 | ; 2 clobber LP_END show LP_END is set | |
4750 | ; 3 use operand0 loop count pseudo register | |
4751 | ; 4 use operand1 before arc_reorg: -id | |
4752 | ; after : CODE_LABEL_NUMBER of loop top label | |
4753 | ; 5 use operand2 INSN_UID of loop end insn | |
4754 | ; 6 use operand3 loop setup not at start (1 above, 2 below) | |
4755 | ; 7 use operand4 LABEL_REF of top label, if not | |
4756 | ; immediately following | |
4757 | ; If operand1 is still zero after arc_reorg, this is an orphaned loop | |
4758 | ; instruction that was not at the start of the loop. | |
4759 | ; There is no point is reloading this insn - then lp_count would still not | |
4760 | ; be available for the loop end. | |
4761 | (define_insn "doloop_begin_i" | |
4762 | [(unspec:SI [(pc)] UNSPEC_LP) | |
4763 | (clobber (reg:SI LP_START)) | |
4764 | (clobber (reg:SI LP_END)) | |
4765 | (use (match_operand:SI 0 "register_operand" "l,l,????*X")) | |
4766 | (use (match_operand 1 "const_int_operand" "n,n,C_0")) | |
4767 | (use (match_operand 2 "const_int_operand" "n,n,X")) | |
4768 | (use (match_operand 3 "const_int_operand" "C_0,n,X")) | |
4769 | (use (match_operand 4 "const_int_operand" "C_0,X,X"))] | |
4770 | "" | |
4771 | { | |
b32d5189 | 4772 | rtx_insn *scan; |
526b7aee SV |
4773 | int len, size = 0; |
4774 | int n_insns = 0; | |
4775 | rtx loop_start = operands[4]; | |
4776 | ||
4777 | if (CONST_INT_P (loop_start)) | |
4778 | loop_start = NULL_RTX; | |
4779 | /* Size implications of the alignment will be taken care of by the | |
4780 | alignment inserted at the loop start. */ | |
4781 | if (LOOP_ALIGN (0) && INTVAL (operands[1])) | |
4782 | { | |
4783 | asm_fprintf (asm_out_file, "\t.p2align %d\\n", LOOP_ALIGN (0)); | |
4784 | arc_clear_unalign (); | |
4785 | } | |
4786 | if (!INTVAL (operands[1])) | |
4787 | return "; LITTLE LOST LOOP"; | |
4788 | if (loop_start && flag_pic) | |
4789 | { | |
4790 | /* ??? Can do better for when a scratch register | |
4791 | is known. But that would require extra testing. */ | |
6495f8e6 | 4792 | return "push_s r0\;add r0,pcl,%4-(.&-4)\;sr r0,[2]; LP_START\;add r0,pcl,.L__GCC__LP%1-(.&-4)\;sr r0,[3]; LP_END\;pop_s r0"; |
526b7aee SV |
4793 | } |
4794 | /* Check if the loop end is in range to be set by the lp instruction. */ | |
4795 | size = INTVAL (operands[3]) < 2 ? 0 : 2048; | |
4796 | for (scan = insn; scan && size < 2048; scan = NEXT_INSN (scan)) | |
4797 | { | |
4798 | if (!INSN_P (scan)) | |
4799 | continue; | |
4800 | if (recog_memoized (scan) == CODE_FOR_doloop_end_i | |
4801 | && (XEXP (XVECEXP (PATTERN (scan), 0, 4), 0) | |
4802 | == XEXP (XVECEXP (PATTERN (insn), 0, 4), 0))) | |
4803 | break; | |
4804 | len = get_attr_length (scan); | |
4805 | size += len; | |
4806 | } | |
4807 | /* Try to verify that there are at least three instruction fetches | |
4808 | between the loop setup and the first encounter of the loop end. */ | |
4809 | for (scan = NEXT_INSN (insn); scan && n_insns < 3; scan = NEXT_INSN (scan)) | |
4810 | { | |
4811 | if (!INSN_P (scan)) | |
4812 | continue; | |
b32d5189 DM |
4813 | if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (scan))) |
4814 | scan = seq->insn (0); | |
526b7aee SV |
4815 | if (JUMP_P (scan)) |
4816 | { | |
4817 | if (recog_memoized (scan) != CODE_FOR_doloop_end_i) | |
4818 | { | |
4819 | n_insns += 2; | |
4820 | if (simplejump_p (scan)) | |
4821 | { | |
b32d5189 | 4822 | scan = as_a <rtx_insn *> (XEXP (SET_SRC (PATTERN (scan)), 0)); |
526b7aee SV |
4823 | continue; |
4824 | } | |
4825 | if (JUMP_LABEL (scan) | |
4826 | /* JUMP_LABEL might be simple_return instead if an insn. */ | |
4827 | && (!INSN_P (JUMP_LABEL (scan)) | |
4828 | || (!next_active_insn (JUMP_LABEL (scan)) | |
4829 | || (recog_memoized (next_active_insn (JUMP_LABEL (scan))) | |
4830 | != CODE_FOR_doloop_begin_i))) | |
4831 | && (!next_active_insn (NEXT_INSN (PREV_INSN (scan))) | |
4832 | || (recog_memoized | |
4833 | (next_active_insn (NEXT_INSN (PREV_INSN (scan)))) | |
4834 | != CODE_FOR_doloop_begin_i))) | |
4835 | n_insns++; | |
4836 | } | |
4837 | break; | |
4838 | } | |
4839 | len = get_attr_length (scan); | |
4840 | /* Size estimation of asms assumes that each line which is nonempty | |
4841 | codes an insn, and that each has a long immediate. For minimum insn | |
4842 | count, assume merely that a nonempty asm has at least one insn. */ | |
4843 | if (GET_CODE (PATTERN (scan)) == ASM_INPUT | |
4844 | || asm_noperands (PATTERN (scan)) >= 0) | |
4845 | n_insns += (len != 0); | |
4846 | else | |
4847 | n_insns += (len > 4 ? 2 : (len ? 1 : 0)); | |
4848 | } | |
4849 | if (LOOP_ALIGN (0)) | |
4850 | { | |
4851 | asm_fprintf (asm_out_file, "\t.p2align %d\\n", LOOP_ALIGN (0)); | |
4852 | arc_clear_unalign (); | |
4853 | } | |
4854 | gcc_assert (n_insns || GET_CODE (next_nonnote_insn (insn)) == CODE_LABEL); | |
4855 | if (size >= 2048 || (TARGET_ARC600 && n_insns == 1) || loop_start) | |
4856 | { | |
4857 | if (flag_pic) | |
4858 | { | |
4859 | /* ??? Can do better for when a scratch register | |
4860 | is known. But that would require extra testing. */ | |
4861 | arc_clear_unalign (); | |
4862 | return ".p2align 2\;push_s r0\;add r0,pcl,24\;sr r0,[2]; LP_START\;add r0,pcl,.L__GCC__LP%1-.+2\;sr r0,[3]; LP_END\;pop_s r0"; | |
4863 | } | |
4864 | output_asm_insn ((size < 2048 | |
4865 | ? "lp .L__GCC__LP%1" : "sr .L__GCC__LP%1,[3]; LP_END"), | |
4866 | operands); | |
4867 | output_asm_insn (loop_start | |
4868 | ? "sr %4,[2]; LP_START" : "sr 0f,[2]; LP_START", | |
4869 | operands); | |
4870 | if (TARGET_ARC600 && n_insns < 1) | |
4871 | output_asm_insn ("nop", operands); | |
4872 | return (TARGET_ARC600 && n_insns < 3) ? "nop_s\;nop_s\;0:" : "0:"; | |
4873 | } | |
4874 | else if (TARGET_ARC600 && n_insns < 3) | |
4875 | { | |
4876 | /* At least four instructions are needed between the setting of LP_COUNT | |
4877 | and the loop end - but the lp instruction qualifies as one. */ | |
21afc57d | 4878 | rtx_insn *prev = prev_nonnote_insn (insn); |
526b7aee SV |
4879 | |
4880 | if (!INSN_P (prev) || dead_or_set_regno_p (prev, LP_COUNT)) | |
4881 | output_asm_insn ("nop", operands); | |
4882 | } | |
4883 | return "lp .L__GCC__LP%1"; | |
4884 | } | |
4885 | [(set_attr "type" "loop_setup") | |
4886 | (set_attr_alternative "length" | |
4887 | ; FIXME: length is usually 4, but we need branch shortening | |
4888 | ; to get this right. | |
4889 | ; [(if_then_else (match_test "TARGET_ARC600") (const_int 16) (const_int 4)) | |
4890 | [(if_then_else (match_test "flag_pic") (const_int 24) (const_int 16)) | |
4891 | (if_then_else (match_test "flag_pic") (const_int 28) (const_int 16)) | |
4892 | (const_int 0)])] | |
4893 | ;; ??? we should really branch shorten this insn, but then we'd | |
4894 | ;; need a proper label first. N.B. the end label can not only go out | |
4895 | ;; of range when it is far away, but also when it precedes the loop - | |
4896 | ;; which, unfortunately, it sometimes does, when the loop "optimizer" | |
4897 | ;; messes things up. | |
4898 | ) | |
4899 | ||
4900 | ; operand 0 is the loop count pseudo register | |
1d0216c8 | 4901 | ; operand 1 is the label to jump to at the top of the loop |
526b7aee SV |
4902 | ; Use this for the ARC600 and ARC700. For ARCtangent-A5, this is unsafe |
4903 | ; without further checking for nearby branches etc., and without proper | |
4904 | ; annotation of shift patterns that clobber lp_count | |
4905 | ; ??? ARC600 might want to check if the loop has few iteration and only a | |
4906 | ; single insn - loop setup is expensive then. | |
4907 | (define_expand "doloop_end" | |
4908 | [(use (match_operand 0 "register_operand" "")) | |
1d0216c8 | 4909 | (use (label_ref (match_operand 1 "" "")))] |
526b7aee SV |
4910 | "TARGET_ARC600 || TARGET_ARC700" |
4911 | { | |
526b7aee SV |
4912 | /* We could do smaller bivs with biv widening, and wider bivs by having |
4913 | a high-word counter in an outer loop - but punt on this for now. */ | |
4914 | if (GET_MODE (operands[0]) != SImode) | |
4915 | FAIL; | |
1d0216c8 | 4916 | emit_jump_insn (gen_doloop_end_i (operands[0], operands[1], const0_rtx)); |
526b7aee SV |
4917 | DONE; |
4918 | }) | |
4919 | ||
4920 | (define_insn_and_split "doloop_end_i" | |
4921 | [(set (pc) | |
4922 | (if_then_else (ne (match_operand:SI 0 "shouldbe_register_operand" "+l,*c,*m") | |
4923 | (const_int 1)) | |
4924 | (label_ref (match_operand 1 "" "")) | |
4925 | (pc))) | |
4926 | (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) | |
4927 | (use (reg:SI LP_START)) | |
4928 | (use (reg:SI LP_END)) | |
4929 | (use (match_operand 2 "const_int_operand" "n,???Cn0,???X")) | |
4930 | (clobber (match_scratch:SI 3 "=X,X,&????r"))] | |
4931 | "" | |
4932 | "* | |
4933 | { | |
21afc57d | 4934 | rtx_insn *prev = prev_nonnote_insn (insn); |
526b7aee SV |
4935 | |
4936 | /* If there is an immediately preceding label, we must output a nop, | |
4937 | lest a branch to that label will fall out of the loop. | |
4938 | ??? We could try to avoid this by claiming to have a delay slot if there | |
4939 | is a preceding label, and outputting the delay slot insn instead, if | |
4940 | present. | |
4941 | Or we could have some optimization that changes the source edge to update | |
4942 | the loop count and jump to the loop start instead. */ | |
4943 | /* For ARC600, we must also prevent jumps inside the loop and jumps where | |
4944 | the loop counter value is live at the target from being directly at the | |
4945 | loop end. Being sure that the loop counter is dead at the target is | |
4946 | too much hair - we can't rely on data flow information at this point - | |
4947 | so insert a nop for all branches. | |
4948 | The ARC600 also can't read the loop counter in the last insn of a loop. */ | |
4949 | if (LABEL_P (prev)) | |
4950 | output_asm_insn (\"nop%?\", operands); | |
4951 | return \"\\n.L__GCC__LP%2: ; loop end, start is %1\"; | |
4952 | }" | |
4953 | "&& memory_operand (operands[0], SImode)" | |
4954 | [(pc)] | |
4955 | { | |
4956 | emit_move_insn (operands[3], operands[0]); | |
4957 | emit_jump_insn (gen_doloop_fallback_m (operands[3], operands[1], operands[0])); | |
4958 | DONE; | |
4959 | } | |
4960 | [(set_attr "type" "loop_end") | |
4961 | (set (attr "length") | |
4962 | (if_then_else (match_test "LABEL_P (prev_nonnote_insn (insn))") | |
4963 | (const_int 4) (const_int 0)))] | |
4964 | ) | |
4965 | ||
4966 | ; This pattern is generated by arc_reorg when there is no recognizable | |
4967 | ; loop start. | |
4968 | (define_insn "*doloop_fallback" | |
4969 | [(set (pc) (if_then_else (ne (match_operand:SI 0 "register_operand" "+r,!w") | |
4970 | (const_int 1)) | |
4971 | (label_ref (match_operand 1 "" "")) | |
4972 | (pc))) | |
4973 | (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] | |
4974 | ; avoid fooling the loop optimizer into assuming this is a special insn. | |
4975 | "reload_completed" | |
4976 | "*return get_attr_length (insn) == 8 | |
4977 | ? \"brne.d %0,1,%1\;sub %0,%0,1\" | |
4978 | : \"breq %0,1,0f\;b.d %1\;sub %0,%0,1\\n0:\";" | |
4979 | [(set (attr "length") | |
4980 | (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -256)) | |
4981 | (le (minus (match_dup 1) (pc)) (const_int 244))) | |
4982 | (const_int 8) (const_int 12))) | |
4983 | (set_attr "type" "brcc_no_delay_slot") | |
4984 | (set_attr "cond" "nocond")] | |
4985 | ) | |
4986 | ||
4987 | ; reload can't make output reloads for jump insns, so we have to do this by hand. | |
4988 | (define_insn "doloop_fallback_m" | |
4989 | [(set (pc) (if_then_else (ne (match_operand:SI 0 "register_operand" "+&r") | |
4990 | (const_int 1)) | |
4991 | (label_ref (match_operand 1 "" "")) | |
4992 | (pc))) | |
4993 | (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) | |
4994 | (set (match_operand:SI 2 "memory_operand" "=m") | |
4995 | (plus:SI (match_dup 0) (const_int -1)))] | |
4996 | ; avoid fooling the loop optimizer into assuming this is a special insn. | |
4997 | "reload_completed" | |
4998 | "*return get_attr_length (insn) == 12 | |
4999 | ? \"sub %0,%0,1\;brne.d %0,0,%1\;st%U2%V2 %0,%2\" | |
5000 | : \"sub %0,%0,1\;breq %0,0,0f\;b.d %1\\n0:\tst%U2%V2 %0,%2\";" | |
5001 | [(set (attr "length") | |
5002 | (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -252)) | |
5003 | (le (minus (match_dup 1) (pc)) (const_int 244))) | |
5004 | (const_int 12) (const_int 16))) | |
5005 | (set_attr "type" "brcc_no_delay_slot") | |
5006 | (set_attr "cond" "nocond")] | |
5007 | ) | |
5008 | ||
5009 | (define_expand "movmemsi" | |
5010 | [(match_operand:BLK 0 "" "") | |
5011 | (match_operand:BLK 1 "" "") | |
5012 | (match_operand:SI 2 "nonmemory_operand" "") | |
5013 | (match_operand 3 "immediate_operand" "")] | |
5014 | "" | |
5015 | "if (arc_expand_movmem (operands)) DONE; else FAIL;") | |
5016 | ||
5017 | ;; Close http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35803 if this works | |
5018 | ;; to the point that we can generate cmove instructions. | |
5019 | (define_expand "cbranch<mode>4" | |
5020 | [(set (reg:CC CC_REG) | |
5021 | (compare:CC (match_operand:SDF 1 "register_operand" "") | |
5022 | (match_operand:SDF 2 "register_operand" ""))) | |
5023 | (set (pc) | |
5024 | (if_then_else | |
5025 | (match_operator 0 "comparison_operator" [(reg CC_REG) | |
5026 | (const_int 0)]) | |
5027 | (label_ref (match_operand 3 "" "")) | |
5028 | (pc)))] | |
5029 | ||
5030 | "TARGET_OPTFPE" | |
5031 | { | |
5032 | gcc_assert (XEXP (operands[0], 0) == operands[1]); | |
5033 | gcc_assert (XEXP (operands[0], 1) == operands[2]); | |
5034 | operands[0] = gen_compare_reg (operands[0], VOIDmode); | |
5035 | emit_jump_insn (gen_branch_insn (operands[3], operands[0])); | |
5036 | DONE; | |
5037 | }) | |
5038 | ||
5039 | (define_expand "cmp_float" | |
5040 | [(parallel [(set (match_operand 0 "") (match_operand 1 "")) | |
5041 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
5042 | (clobber (reg:SI R12_REG))])] | |
5043 | "" | |
5044 | "") | |
5045 | ||
5046 | (define_mode_iterator OPTFPE_CMP [CC_Z CC_FP_GT CC_FP_GE CC_FP_UNEQ CC_FP_ORD]) | |
5047 | (define_mode_attr cmp [(CC_Z "eq") (CC_FP_GT "gt") (CC_FP_GE "ge") | |
5048 | (CC_FP_UNEQ "uneq") (CC_FP_ORD "ord")]) | |
5049 | ||
5050 | (define_insn "*cmpsf_<cmp>" | |
5051 | [(set (reg:OPTFPE_CMP CC_REG) (compare:OPTFPE_CMP (reg:SF 0) (reg:SF 1))) | |
5052 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
5053 | (clobber (reg:SI R12_REG))] | |
5054 | "TARGET_OPTFPE && (!TARGET_ARGONAUT_SET || !TARGET_SPFP) | |
5055 | && SFUNC_CHECK_PREDICABLE" | |
5056 | "*return arc_output_libcall (\"__<cmp>sf2\");" | |
5057 | [(set_attr "is_sfunc" "yes") | |
5058 | (set_attr "predicable" "yes")]) | |
5059 | ||
5060 | ;; N.B. for "*cmpdf_ord": | |
5061 | ;; double precision fpx sets bit 31 for NaNs. We need bit 51 set | |
5062 | ;; for the floating point emulation to recognize the NaN. | |
5063 | (define_insn "*cmpdf_<cmp>" | |
5064 | [(set (reg:OPTFPE_CMP CC_REG) (compare:OPTFPE_CMP (reg:DF 0) (reg:DF 2))) | |
5065 | (clobber (reg:SI RETURN_ADDR_REGNUM)) | |
5066 | (clobber (reg:SI R12_REG))] | |
5067 | "TARGET_OPTFPE && (!TARGET_ARGONAUT_SET || !TARGET_DPFP) | |
5068 | && SFUNC_CHECK_PREDICABLE" | |
5069 | "*return arc_output_libcall (\"__<cmp>df2\");" | |
5070 | [(set_attr "is_sfunc" "yes") | |
5071 | (set_attr "predicable" "yes")]) | |
5072 | ||
5073 | (define_insn "abssf2" | |
5074 | [(set (match_operand:SF 0 "dest_reg_operand" "=Rcq#q,Rcw,w") | |
5075 | (abs:SF (match_operand:SF 1 "register_operand" "0, 0,c")))] | |
5076 | "" | |
5077 | "bclr%? %0,%1,31%&" | |
5078 | [(set_attr "type" "unary") | |
5079 | (set_attr "iscompact" "maybe,false,false") | |
5080 | (set_attr "length" "2,4,4") | |
5081 | (set_attr "predicable" "no,yes,no")]) | |
5082 | ||
5083 | (define_insn "negsf2" | |
5084 | [(set (match_operand:SF 0 "dest_reg_operand" "=Rcw,w") | |
5085 | (neg:SF (match_operand:SF 1 "register_operand" "0,c")))] | |
5086 | "" | |
5087 | "bxor%? %0,%1,31" | |
5088 | [(set_attr "type" "unary") | |
5089 | (set_attr "predicable" "yes,no")]) | |
5090 | ||
5091 | ;; ??? Should this use arc_output_libcall and set is_sfunc? | |
5092 | (define_insn "*millicode_thunk_st" | |
5093 | [(match_parallel 0 "millicode_store_operation" | |
5094 | [(set (mem:SI (reg:SI SP_REG)) (reg:SI 13))])] | |
5095 | "" | |
5096 | { | |
5097 | output_asm_insn ("bl%* __st_r13_to_%0", | |
5098 | &SET_SRC (XVECEXP (operands[0], 0, | |
5099 | XVECLEN (operands[0], 0) - 2))); | |
5100 | return ""; | |
5101 | } | |
5102 | [(set_attr "type" "call")]) | |
5103 | ||
5104 | (define_insn "*millicode_thunk_ld" | |
5105 | [(match_parallel 0 "millicode_load_clob_operation" | |
5106 | [(set (reg:SI 13) (mem:SI (reg:SI SP_REG)))])] | |
5107 | "" | |
5108 | { | |
5109 | output_asm_insn ("bl%* __ld_r13_to_%0", | |
5110 | &SET_DEST (XVECEXP (operands[0], 0, | |
5111 | XVECLEN (operands[0], 0) - 2))); | |
5112 | return ""; | |
5113 | } | |
5114 | [(set_attr "type" "call")]) | |
5115 | ||
5116 | ; the sibthunk restores blink, so we use the return rtx. | |
5117 | (define_insn "*millicode_sibthunk_ld" | |
5118 | [(match_parallel 0 "millicode_load_operation" | |
5119 | [(return) | |
5120 | (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (reg:SI 12))) | |
5121 | (set (reg:SI 13) (mem:SI (reg:SI SP_REG)))])] | |
5122 | "" | |
5123 | { | |
5124 | output_asm_insn ("b%* __ld_r13_to_%0_ret", | |
5125 | &SET_DEST (XVECEXP (operands[0], 0, | |
5126 | XVECLEN (operands[0], 0) - 1))); | |
5127 | return ""; | |
5128 | } | |
5129 | [(set_attr "type" "call") | |
5130 | (set_attr "is_SIBCALL" "yes")]) | |
5131 | ||
5132 | ;; If hardware floating point is available, don't define a negdf pattern; | |
5133 | ;; it would be something like: | |
5134 | ;;(define_insn "negdf2" | |
5135 | ;; [(set (match_operand:DF 0 "register_operand" "=w,w,D,?r") | |
5136 | ;; (neg:DF (match_operand:DF 1 "register_operand" "0,c,D,D"))) | |
5137 | ;; (clobber (match_scratch:DF 2 "=X,X,X,X,D1"))] | |
5138 | ;; "" | |
5139 | ;; "@ | |
5140 | ;; bxor%? %H0,%H1,31 | |
5141 | ;; bxor %H0,%H1,31 ` mov %L0,%L1 | |
5142 | ;; drsubh%F0%F1 0,0,0 | |
5143 | ;; drsubh%F2%F1 %H0,0,0 ` dexcl%F2 %L0,%H0,%L0" | |
5144 | ;; [(set_attr "type" "unary,unary,dpfp_addsub,dpfp_addsub") | |
5145 | ;; (set_attr "iscompact" "false,false,false,false") | |
5146 | ;; (set_attr "length" "4,4,8,12") | |
5147 | ;; (set_attr "cond" "canuse,nocond,nocond,nocond")]) | |
5148 | ;; and this suffers from always requiring a long immediate when using | |
5149 | ;; the floating point hardware. | |
5150 | ;; We then want the sub[sd]f patterns to be used, so that we can load the | |
5151 | ;; constant zero efficiently into a register when we want to do the | |
5152 | ;; computation using the floating point hardware. There should be a special | |
5153 | ;; subdf alternative that matches a zero operand 1, which then can allow | |
5154 | ;; to use bxor to flip the high bit of an integer register. | |
5155 | ;; ??? we actually can't use the floating point hardware for neg, because | |
5156 | ;; this would not work right for -0. OTOH optabs.c has already code | |
5157 | ;; to synthesyze negate by flipping the sign bit. | |
5158 | ||
5159 | ||
5160 | ;; include the arc-FPX instructions | |
5161 | (include "fpx.md") | |
5162 | ||
5163 | (include "simdext.md") |