]>
Commit | Line | Data |
---|---|---|
bc360af8 | 1 | ;; ARM Thumb-1 Machine Description |
fbd26352 | 2 | ;; Copyright (C) 2007-2019 Free Software Foundation, Inc. |
bc360af8 | 3 | ;; |
4 | ;; This file is part of GCC. | |
5 | ;; | |
6 | ;; GCC is free software; you can redistribute it and/or modify it | |
7 | ;; under the terms of the GNU General Public License as published by | |
8 | ;; the Free Software Foundation; either version 3, or (at your option) | |
9 | ;; any later version. | |
10 | ;; | |
11 | ;; GCC is distributed in the hope that it will be useful, but | |
12 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | ;; General Public License for more details. | |
15 | ;; | |
16 | ;; You should have received a copy of the GNU General Public License | |
17 | ;; along with GCC; see the file COPYING3. If not see | |
18 | ;; <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | \f | |
21 | ;;--------------------------------------------------------------------------- | |
22 | ;; Insn patterns | |
23 | ;; | |
24 | ||
6988da2f | 25 | ;; Beware of splitting Thumb1 patterns that output multiple |
26 | ;; assembly instructions, in particular instruction such as SBC and | |
27 | ;; ADC which consume flags. For example, in the pattern thumb_subdi3 | |
28 | ;; below, the output SUB implicitly sets the flags (assembled to SUBS) | |
29 | ;; and then the Carry flag is used by SBC to compute the correct | |
30 | ;; result. If we split thumb_subdi3 pattern into two separate RTL | |
31 | ;; insns (using define_insn_and_split), the scheduler might place | |
32 | ;; other RTL insns between SUB and SBC, possibly modifying the Carry | |
33 | ;; flag used by SBC. This might happen because most Thumb1 patterns | |
34 | ;; for flag-setting instructions do not have explicit RTL for setting | |
35 | ;; or clobbering the flags. Instead, they have the attribute "conds" | |
36 | ;; with value "set" or "clob". However, this attribute is not used to | |
37 | ;; identify dependencies and therefore the scheduler might reorder | |
38 | ;; these instruction. Currenly, this problem cannot happen because | |
39 | ;; there are no separate Thumb1 patterns for individual instruction | |
40 | ;; that consume flags (except conditional execution, which is treated | |
41 | ;; differently). In particular there is no Thumb1 armv6-m pattern for | |
42 | ;; sbc or adc. | |
43 | ||
44 | ||
45 | ||
bc360af8 | 46 | (define_insn "*thumb1_adddi3" |
47 | [(set (match_operand:DI 0 "register_operand" "=l") | |
48 | (plus:DI (match_operand:DI 1 "register_operand" "%0") | |
49 | (match_operand:DI 2 "register_operand" "l"))) | |
50 | (clobber (reg:CC CC_REGNUM)) | |
51 | ] | |
52 | "TARGET_THUMB1" | |
7e3c779e | 53 | "adds\\t%Q0, %Q0, %Q2\;adcs\\t%R0, %R0, %R2" |
bc360af8 | 54 | [(set_attr "length" "4") |
55 | (set_attr "type" "multiple")] | |
56 | ) | |
57 | ||
f02d0686 | 58 | ;; Changes to the constraints of this pattern must be propagated to those of |
59 | ;; atomic additions in sync.md and to the logic for bind_old_new in | |
60 | ;; arm_split_atomic_op in arm.c. These must be at least as strict as the | |
61 | ;; constraints here and aim to be as permissive. | |
bc360af8 | 62 | (define_insn_and_split "*thumb1_addsi3" |
63 | [(set (match_operand:SI 0 "register_operand" "=l,l,l,*rk,*hk,l,k,l,l,l") | |
64 | (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,k,k,0,l,k") | |
65 | (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*hk,*rk,M,O,Pa,Pb,Pc")))] | |
66 | "TARGET_THUMB1" | |
67 | "* | |
68 | static const char * const asms[] = | |
69 | { | |
7e3c779e | 70 | \"adds\\t%0, %0, %2\", |
71 | \"subs\\t%0, %0, #%n2\", | |
72 | \"adds\\t%0, %1, %2\", | |
bc360af8 | 73 | \"add\\t%0, %0, %2\", |
74 | \"add\\t%0, %0, %2\", | |
75 | \"add\\t%0, %1, %2\", | |
76 | \"add\\t%0, %1, %2\", | |
77 | \"#\", | |
78 | \"#\", | |
79 | \"#\" | |
80 | }; | |
81 | if ((which_alternative == 2 || which_alternative == 6) | |
82 | && CONST_INT_P (operands[2]) | |
83 | && INTVAL (operands[2]) < 0) | |
7e3c779e | 84 | return (which_alternative == 2) ? \"subs\\t%0, %1, #%n2\" : \"sub\\t%0, %1, #%n2\"; |
bc360af8 | 85 | return asms[which_alternative]; |
86 | " | |
87 | "&& reload_completed && CONST_INT_P (operands[2]) | |
88 | && ((operands[1] != stack_pointer_rtx | |
89 | && (INTVAL (operands[2]) > 255 || INTVAL (operands[2]) < -255)) | |
90 | || (operands[1] == stack_pointer_rtx | |
91 | && INTVAL (operands[2]) > 1020))" | |
92 | [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) | |
93 | (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] | |
94 | { | |
95 | HOST_WIDE_INT offset = INTVAL (operands[2]); | |
96 | if (operands[1] == stack_pointer_rtx) | |
97 | offset -= 1020; | |
98 | else | |
99 | { | |
100 | if (offset > 255) | |
101 | offset = 255; | |
102 | else if (offset < -255) | |
103 | offset = -255; | |
104 | } | |
105 | operands[3] = GEN_INT (offset); | |
106 | operands[2] = GEN_INT (INTVAL (operands[2]) - offset); | |
107 | } | |
108 | [(set_attr "length" "2,2,2,2,2,2,2,4,4,4") | |
112eda6f | 109 | (set_attr "type" "alus_imm,alus_imm,alus_sreg,alus_sreg,alus_sreg, |
110 | alus_sreg,alus_sreg,multiple,multiple,multiple")] | |
bc360af8 | 111 | ) |
112 | ||
113 | ;; Reloading and elimination of the frame pointer can | |
114 | ;; sometimes cause this optimization to be missed. | |
115 | (define_peephole2 | |
116 | [(set (match_operand:SI 0 "arm_general_register_operand" "") | |
117 | (match_operand:SI 1 "const_int_operand" "")) | |
118 | (set (match_dup 0) | |
119 | (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))] | |
120 | "TARGET_THUMB1 | |
8c4e8755 | 121 | && UINTVAL (operands[1]) < 1024 |
122 | && (UINTVAL (operands[1]) & 3) == 0" | |
bc360af8 | 123 | [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))] |
124 | "" | |
125 | ) | |
126 | ||
127 | (define_insn "*thumb_subdi3" | |
128 | [(set (match_operand:DI 0 "register_operand" "=l") | |
129 | (minus:DI (match_operand:DI 1 "register_operand" "0") | |
130 | (match_operand:DI 2 "register_operand" "l"))) | |
131 | (clobber (reg:CC CC_REGNUM))] | |
132 | "TARGET_THUMB1" | |
7e3c779e | 133 | "subs\\t%Q0, %Q0, %Q2\;sbcs\\t%R0, %R0, %R2" |
bc360af8 | 134 | [(set_attr "length" "4") |
135 | (set_attr "type" "multiple")] | |
136 | ) | |
137 | ||
f02d0686 | 138 | ;; Changes to the constraints of this pattern must be propagated to those of |
139 | ;; atomic subtractions in sync.md and to the logic for bind_old_new in | |
140 | ;; arm_split_atomic_op in arm.c. These must be at least as strict as the | |
141 | ;; constraints here and aim to be as permissive. | |
bc360af8 | 142 | (define_insn "thumb1_subsi3_insn" |
143 | [(set (match_operand:SI 0 "register_operand" "=l") | |
144 | (minus:SI (match_operand:SI 1 "register_operand" "l") | |
145 | (match_operand:SI 2 "reg_or_int_operand" "lPd")))] | |
146 | "TARGET_THUMB1" | |
7e3c779e | 147 | "subs\\t%0, %1, %2" |
bc360af8 | 148 | [(set_attr "length" "2") |
149 | (set_attr "conds" "set") | |
112eda6f | 150 | (set_attr "type" "alus_sreg")] |
bc360af8 | 151 | ) |
152 | ||
3f115163 | 153 | ;; Unfortunately on Thumb the '&'/'0' trick can fail when operands |
154 | ;; 1 and 2 are the same, because reload will make operand 0 match | |
155 | ;; operand 1 without realizing that this conflicts with operand 2. We fix | |
156 | ;; this by adding another alternative to match this case, and then `reload' | |
157 | ;; it ourselves. This alternative must come first. | |
bc360af8 | 158 | (define_insn "*thumb_mulsi3" |
159 | [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") | |
160 | (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") | |
161 | (match_operand:SI 2 "register_operand" "l,l,l")))] | |
162 | "TARGET_THUMB1 && !arm_arch6" | |
3582b939 | 163 | "@ |
164 | movs\\t%0, %1\;muls\\t%0, %2 | |
165 | mov\\t%0, %1\;muls\\t%0, %2 | |
166 | muls\\t%0, %2" | |
bc360af8 | 167 | [(set_attr "length" "4,4,2") |
168 | (set_attr "type" "muls")] | |
169 | ) | |
170 | ||
171 | (define_insn "*thumb_mulsi3_v6" | |
172 | [(set (match_operand:SI 0 "register_operand" "=l,l,l") | |
173 | (mult:SI (match_operand:SI 1 "register_operand" "0,l,0") | |
174 | (match_operand:SI 2 "register_operand" "l,0,0")))] | |
175 | "TARGET_THUMB1 && arm_arch6" | |
176 | "@ | |
7e3c779e | 177 | muls\\t%0, %2 |
178 | muls\\t%0, %1 | |
179 | muls\\t%0, %1" | |
bc360af8 | 180 | [(set_attr "length" "2") |
181 | (set_attr "type" "muls")] | |
182 | ) | |
183 | ||
f02d0686 | 184 | ;; Changes to the constraints of this pattern must be propagated to those of |
185 | ;; atomic bitwise ANDs and NANDs in sync.md and to the logic for bind_old_new | |
186 | ;; in arm_split_atomic_op in arm.c. These must be at least as strict as the | |
187 | ;; constraints here and aim to be as permissive. | |
bc360af8 | 188 | (define_insn "*thumb1_andsi3_insn" |
189 | [(set (match_operand:SI 0 "register_operand" "=l") | |
190 | (and:SI (match_operand:SI 1 "register_operand" "%0") | |
191 | (match_operand:SI 2 "register_operand" "l")))] | |
192 | "TARGET_THUMB1" | |
7e3c779e | 193 | "ands\\t%0, %2" |
bc360af8 | 194 | [(set_attr "length" "2") |
195 | (set_attr "type" "logic_imm") | |
196 | (set_attr "conds" "set")]) | |
197 | ||
198 | (define_split | |
199 | [(set (match_operand:SI 0 "s_register_operand" "") | |
200 | (zero_extract:SI (match_operand:SI 1 "s_register_operand" "") | |
201 | (match_operand:SI 2 "const_int_operand" "") | |
202 | (match_operand:SI 3 "const_int_operand" ""))) | |
203 | (clobber (match_operand:SI 4 "s_register_operand" ""))] | |
204 | "TARGET_THUMB1" | |
205 | [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2))) | |
206 | (set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))] | |
207 | "{ | |
208 | HOST_WIDE_INT temp = INTVAL (operands[2]); | |
209 | ||
210 | operands[2] = GEN_INT (32 - temp - INTVAL (operands[3])); | |
211 | operands[3] = GEN_INT (32 - temp); | |
212 | }" | |
213 | ) | |
214 | ||
215 | (define_split | |
216 | [(set (match_operand:SI 0 "s_register_operand" "") | |
217 | (sign_extract:SI (match_operand:SI 1 "s_register_operand" "") | |
218 | (match_operand:SI 2 "const_int_operand" "") | |
219 | (match_operand:SI 3 "const_int_operand" "")))] | |
220 | "TARGET_THUMB1" | |
221 | [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2))) | |
222 | (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))] | |
223 | "{ | |
224 | HOST_WIDE_INT temp = INTVAL (operands[2]); | |
225 | ||
226 | operands[2] = GEN_INT (32 - temp - INTVAL (operands[3])); | |
227 | operands[3] = GEN_INT (32 - temp); | |
228 | }" | |
229 | ) | |
230 | ||
231 | (define_insn "thumb1_bicsi3" | |
232 | [(set (match_operand:SI 0 "register_operand" "=l") | |
233 | (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) | |
234 | (match_operand:SI 2 "register_operand" "0")))] | |
235 | "TARGET_THUMB1" | |
7e3c779e | 236 | "bics\\t%0, %1" |
bc360af8 | 237 | [(set_attr "length" "2") |
238 | (set_attr "conds" "set") | |
239 | (set_attr "type" "logics_reg")] | |
240 | ) | |
241 | ||
f02d0686 | 242 | ;; Changes to the constraints of this pattern must be propagated to those of |
243 | ;; atomic inclusive ORs in sync.md and to the logic for bind_old_new in | |
244 | ;; arm_split_atomic_op in arm.c. These must be at least as strict as the | |
245 | ;; constraints here and aim to be as permissive. | |
bc360af8 | 246 | (define_insn "*thumb1_iorsi3_insn" |
247 | [(set (match_operand:SI 0 "register_operand" "=l") | |
248 | (ior:SI (match_operand:SI 1 "register_operand" "%0") | |
249 | (match_operand:SI 2 "register_operand" "l")))] | |
250 | "TARGET_THUMB1" | |
7e3c779e | 251 | "orrs\\t%0, %2" |
bc360af8 | 252 | [(set_attr "length" "2") |
253 | (set_attr "conds" "set") | |
254 | (set_attr "type" "logics_reg")]) | |
255 | ||
f02d0686 | 256 | ;; Changes to the constraints of this pattern must be propagated to those of |
257 | ;; atomic exclusive ORs in sync.md and to the logic for bind_old_new in | |
258 | ;; arm_split_atomic_op in arm.c. These must be at least as strict as the | |
259 | ;; constraints here and aim to be as permissive. | |
bc360af8 | 260 | (define_insn "*thumb1_xorsi3_insn" |
261 | [(set (match_operand:SI 0 "register_operand" "=l") | |
262 | (xor:SI (match_operand:SI 1 "register_operand" "%0") | |
263 | (match_operand:SI 2 "register_operand" "l")))] | |
264 | "TARGET_THUMB1" | |
7e3c779e | 265 | "eors\\t%0, %2" |
bc360af8 | 266 | [(set_attr "length" "2") |
267 | (set_attr "conds" "set") | |
268 | (set_attr "type" "logics_reg")] | |
269 | ) | |
270 | ||
271 | (define_insn "*thumb1_ashlsi3" | |
272 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
273 | (ashift:SI (match_operand:SI 1 "register_operand" "l,0") | |
274 | (match_operand:SI 2 "nonmemory_operand" "N,l")))] | |
275 | "TARGET_THUMB1" | |
7e3c779e | 276 | "lsls\\t%0, %1, %2" |
bc360af8 | 277 | [(set_attr "length" "2") |
278 | (set_attr "type" "shift_imm,shift_reg") | |
279 | (set_attr "conds" "set")]) | |
280 | ||
281 | (define_insn "*thumb1_ashrsi3" | |
282 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
283 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") | |
284 | (match_operand:SI 2 "nonmemory_operand" "N,l")))] | |
285 | "TARGET_THUMB1" | |
7e3c779e | 286 | "asrs\\t%0, %1, %2" |
bc360af8 | 287 | [(set_attr "length" "2") |
288 | (set_attr "type" "shift_imm,shift_reg") | |
289 | (set_attr "conds" "set")]) | |
290 | ||
291 | (define_insn "*thumb1_lshrsi3" | |
292 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
293 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") | |
294 | (match_operand:SI 2 "nonmemory_operand" "N,l")))] | |
295 | "TARGET_THUMB1" | |
7e3c779e | 296 | "lsrs\\t%0, %1, %2" |
bc360af8 | 297 | [(set_attr "length" "2") |
298 | (set_attr "type" "shift_imm,shift_reg") | |
299 | (set_attr "conds" "set")]) | |
300 | ||
301 | (define_insn "*thumb1_rotrsi3" | |
302 | [(set (match_operand:SI 0 "register_operand" "=l") | |
303 | (rotatert:SI (match_operand:SI 1 "register_operand" "0") | |
304 | (match_operand:SI 2 "register_operand" "l")))] | |
305 | "TARGET_THUMB1" | |
7e3c779e | 306 | "rors\\t%0, %0, %2" |
bc360af8 | 307 | [(set_attr "type" "shift_reg") |
308 | (set_attr "length" "2")] | |
309 | ) | |
310 | ||
311 | (define_insn "*thumb1_negdi2" | |
312 | [(set (match_operand:DI 0 "register_operand" "=&l") | |
313 | (neg:DI (match_operand:DI 1 "register_operand" "l"))) | |
314 | (clobber (reg:CC CC_REGNUM))] | |
315 | "TARGET_THUMB1" | |
7e3c779e | 316 | "movs\\t%R0, #0\;rsbs\\t%Q0, %Q1, #0\;sbcs\\t%R0, %R1" |
bc360af8 | 317 | [(set_attr "length" "6") |
318 | (set_attr "type" "multiple")] | |
319 | ) | |
320 | ||
321 | (define_insn "*thumb1_negsi2" | |
322 | [(set (match_operand:SI 0 "register_operand" "=l") | |
323 | (neg:SI (match_operand:SI 1 "register_operand" "l")))] | |
324 | "TARGET_THUMB1" | |
7e3c779e | 325 | "rsbs\\t%0, %1, #0" |
bc360af8 | 326 | [(set_attr "length" "2") |
327 | (set_attr "type" "alu_imm")] | |
328 | ) | |
329 | ||
330 | (define_insn_and_split "*thumb1_abssi2" | |
331 | [(set (match_operand:SI 0 "s_register_operand" "=l") | |
332 | (abs:SI (match_operand:SI 1 "s_register_operand" "l"))) | |
333 | (clobber (match_scratch:SI 2 "=&l"))] | |
334 | "TARGET_THUMB1" | |
335 | "#" | |
336 | "TARGET_THUMB1 && reload_completed" | |
337 | [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) | |
338 | (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) | |
339 | (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 2)))] | |
340 | "" | |
341 | [(set_attr "length" "6") | |
342 | (set_attr "type" "multiple")] | |
343 | ) | |
344 | ||
345 | (define_insn_and_split "*thumb1_neg_abssi2" | |
346 | [(set (match_operand:SI 0 "s_register_operand" "=l") | |
347 | (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "l")))) | |
348 | (clobber (match_scratch:SI 2 "=&l"))] | |
349 | "TARGET_THUMB1" | |
350 | "#" | |
351 | "TARGET_THUMB1 && reload_completed" | |
352 | [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) | |
353 | (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 1))) | |
354 | (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 2)))] | |
355 | "" | |
356 | [(set_attr "length" "6") | |
357 | (set_attr "type" "multiple")] | |
358 | ) | |
359 | ||
360 | (define_insn "*thumb1_one_cmplsi2" | |
361 | [(set (match_operand:SI 0 "register_operand" "=l") | |
362 | (not:SI (match_operand:SI 1 "register_operand" "l")))] | |
363 | "TARGET_THUMB1" | |
7e3c779e | 364 | "mvns\\t%0, %1" |
bc360af8 | 365 | [(set_attr "length" "2") |
366 | (set_attr "type" "mvn_reg")] | |
367 | ) | |
368 | ||
369 | (define_insn "*thumb1_zero_extendhisi2" | |
370 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
371 | (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))] | |
372 | "TARGET_THUMB1" | |
373 | { | |
374 | rtx mem; | |
375 | ||
376 | if (which_alternative == 0 && arm_arch6) | |
377 | return "uxth\t%0, %1"; | |
378 | if (which_alternative == 0) | |
379 | return "#"; | |
380 | ||
381 | mem = XEXP (operands[1], 0); | |
382 | ||
383 | if (GET_CODE (mem) == CONST) | |
384 | mem = XEXP (mem, 0); | |
385 | ||
386 | if (GET_CODE (mem) == PLUS) | |
387 | { | |
388 | rtx a = XEXP (mem, 0); | |
389 | ||
390 | /* This can happen due to bugs in reload. */ | |
391 | if (REG_P (a) && REGNO (a) == SP_REGNUM) | |
392 | { | |
393 | rtx ops[2]; | |
394 | ops[0] = operands[0]; | |
395 | ops[1] = a; | |
396 | ||
397 | output_asm_insn ("mov\t%0, %1", ops); | |
398 | ||
399 | XEXP (mem, 0) = operands[0]; | |
400 | } | |
401 | } | |
402 | ||
403 | return "ldrh\t%0, %1"; | |
404 | } | |
405 | [(set_attr_alternative "length" | |
406 | [(if_then_else (eq_attr "is_arch6" "yes") | |
407 | (const_int 2) (const_int 4)) | |
408 | (const_int 4)]) | |
409 | (set_attr "type" "extend,load_byte")] | |
410 | ) | |
411 | ||
412 | (define_insn "*thumb1_zero_extendqisi2" | |
413 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
414 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] | |
415 | "TARGET_THUMB1 && !arm_arch6" | |
416 | "@ | |
417 | # | |
418 | ldrb\\t%0, %1" | |
419 | [(set_attr "length" "4,2") | |
420 | (set_attr "type" "alu_shift_reg,load_byte") | |
421 | (set_attr "pool_range" "*,32")] | |
422 | ) | |
423 | ||
424 | (define_insn "*thumb1_zero_extendqisi2_v6" | |
425 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
426 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))] | |
427 | "TARGET_THUMB1 && arm_arch6" | |
428 | "@ | |
429 | uxtb\\t%0, %1 | |
430 | ldrb\\t%0, %1" | |
431 | [(set_attr "length" "2") | |
432 | (set_attr "type" "extend,load_byte")] | |
433 | ) | |
434 | ||
435 | ;; We used to have an early-clobber on the scratch register here. | |
436 | ;; However, there's a bug somewhere in reload which means that this | |
437 | ;; can be partially ignored during spill allocation if the memory | |
438 | ;; address also needs reloading; this causes us to die later on when | |
439 | ;; we try to verify the operands. Fortunately, we don't really need | |
440 | ;; the early-clobber: we can always use operand 0 if operand 2 | |
441 | ;; overlaps the address. | |
442 | (define_insn "thumb1_extendhisi2" | |
443 | [(set (match_operand:SI 0 "register_operand" "=l,l") | |
444 | (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m"))) | |
445 | (clobber (match_scratch:SI 2 "=X,l"))] | |
446 | "TARGET_THUMB1" | |
447 | "* | |
448 | { | |
449 | rtx ops[4]; | |
450 | rtx mem; | |
451 | ||
452 | if (which_alternative == 0 && !arm_arch6) | |
453 | return \"#\"; | |
454 | if (which_alternative == 0) | |
455 | return \"sxth\\t%0, %1\"; | |
456 | ||
457 | mem = XEXP (operands[1], 0); | |
458 | ||
459 | /* This code used to try to use 'V', and fix the address only if it was | |
460 | offsettable, but this fails for e.g. REG+48 because 48 is outside the | |
461 | range of QImode offsets, and offsettable_address_p does a QImode | |
462 | address check. */ | |
463 | ||
464 | if (GET_CODE (mem) == CONST) | |
465 | mem = XEXP (mem, 0); | |
466 | ||
467 | if (GET_CODE (mem) == LABEL_REF) | |
468 | return \"ldr\\t%0, %1\"; | |
469 | ||
470 | if (GET_CODE (mem) == PLUS) | |
471 | { | |
472 | rtx a = XEXP (mem, 0); | |
473 | rtx b = XEXP (mem, 1); | |
474 | ||
475 | if (GET_CODE (a) == LABEL_REF | |
476 | && CONST_INT_P (b)) | |
477 | return \"ldr\\t%0, %1\"; | |
478 | ||
479 | if (REG_P (b)) | |
480 | return \"ldrsh\\t%0, %1\"; | |
481 | ||
482 | ops[1] = a; | |
483 | ops[2] = b; | |
484 | } | |
485 | else | |
486 | { | |
487 | ops[1] = mem; | |
488 | ops[2] = const0_rtx; | |
489 | } | |
490 | ||
491 | gcc_assert (REG_P (ops[1])); | |
492 | ||
493 | ops[0] = operands[0]; | |
494 | if (reg_mentioned_p (operands[2], ops[1])) | |
495 | ops[3] = ops[0]; | |
496 | else | |
497 | ops[3] = operands[2]; | |
7e3c779e | 498 | output_asm_insn (\"movs\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); |
bc360af8 | 499 | return \"\"; |
500 | }" | |
501 | [(set_attr_alternative "length" | |
502 | [(if_then_else (eq_attr "is_arch6" "yes") | |
503 | (const_int 2) (const_int 4)) | |
504 | (const_int 4)]) | |
505 | (set_attr "type" "extend,load_byte") | |
506 | (set_attr "pool_range" "*,1018")] | |
507 | ) | |
508 | ||
509 | (define_split | |
510 | [(set (match_operand:SI 0 "register_operand" "") | |
511 | (sign_extend:SI (match_operand:QI 1 "memory_operand" "")))] | |
512 | "TARGET_THUMB1 && reload_completed" | |
513 | [(set (match_dup 0) (match_dup 2)) | |
514 | (set (match_dup 0) (sign_extend:SI (match_dup 3)))] | |
515 | { | |
516 | rtx addr = XEXP (operands[1], 0); | |
517 | ||
518 | if (GET_CODE (addr) == CONST) | |
519 | addr = XEXP (addr, 0); | |
520 | ||
521 | if (GET_CODE (addr) == PLUS | |
522 | && REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))) | |
523 | /* No split necessary. */ | |
524 | FAIL; | |
525 | ||
526 | if (GET_CODE (addr) == PLUS | |
527 | && !REG_P (XEXP (addr, 0)) && !REG_P (XEXP (addr, 1))) | |
528 | FAIL; | |
529 | ||
530 | if (reg_overlap_mentioned_p (operands[0], addr)) | |
531 | { | |
532 | rtx t = gen_lowpart (QImode, operands[0]); | |
533 | emit_move_insn (t, operands[1]); | |
534 | emit_insn (gen_thumb1_extendqisi2 (operands[0], t)); | |
535 | DONE; | |
536 | } | |
537 | ||
538 | if (REG_P (addr)) | |
539 | { | |
540 | addr = gen_rtx_PLUS (Pmode, addr, operands[0]); | |
541 | operands[2] = const0_rtx; | |
542 | } | |
543 | else if (GET_CODE (addr) != PLUS) | |
544 | FAIL; | |
545 | else if (REG_P (XEXP (addr, 0))) | |
546 | { | |
547 | operands[2] = XEXP (addr, 1); | |
548 | addr = gen_rtx_PLUS (Pmode, XEXP (addr, 0), operands[0]); | |
549 | } | |
550 | else | |
551 | { | |
552 | operands[2] = XEXP (addr, 0); | |
553 | addr = gen_rtx_PLUS (Pmode, XEXP (addr, 1), operands[0]); | |
554 | } | |
555 | ||
556 | operands[3] = change_address (operands[1], QImode, addr); | |
557 | }) | |
558 | ||
559 | (define_peephole2 | |
560 | [(set (match_operand:SI 0 "register_operand" "") | |
561 | (plus:SI (match_dup 0) (match_operand 1 "const_int_operand"))) | |
562 | (set (match_operand:SI 2 "register_operand" "") (const_int 0)) | |
563 | (set (match_operand:SI 3 "register_operand" "") | |
564 | (sign_extend:SI (match_operand:QI 4 "memory_operand" "")))] | |
565 | "TARGET_THUMB1 | |
566 | && GET_CODE (XEXP (operands[4], 0)) == PLUS | |
567 | && rtx_equal_p (operands[0], XEXP (XEXP (operands[4], 0), 0)) | |
568 | && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 1)) | |
569 | && (peep2_reg_dead_p (3, operands[0]) | |
570 | || rtx_equal_p (operands[0], operands[3])) | |
571 | && (peep2_reg_dead_p (3, operands[2]) | |
572 | || rtx_equal_p (operands[2], operands[3]))" | |
573 | [(set (match_dup 2) (match_dup 1)) | |
574 | (set (match_dup 3) (sign_extend:SI (match_dup 4)))] | |
575 | { | |
576 | rtx addr = gen_rtx_PLUS (Pmode, operands[0], operands[2]); | |
577 | operands[4] = change_address (operands[4], QImode, addr); | |
578 | }) | |
579 | ||
580 | (define_insn "thumb1_extendqisi2" | |
581 | [(set (match_operand:SI 0 "register_operand" "=l,l,l") | |
582 | (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))] | |
583 | "TARGET_THUMB1" | |
584 | { | |
585 | rtx addr; | |
586 | ||
587 | if (which_alternative == 0 && arm_arch6) | |
588 | return "sxtb\\t%0, %1"; | |
589 | if (which_alternative == 0) | |
590 | return "#"; | |
591 | ||
592 | addr = XEXP (operands[1], 0); | |
593 | if (GET_CODE (addr) == PLUS | |
594 | && REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1))) | |
595 | return "ldrsb\\t%0, %1"; | |
596 | ||
597 | return "#"; | |
598 | } | |
599 | [(set_attr_alternative "length" | |
600 | [(if_then_else (eq_attr "is_arch6" "yes") | |
601 | (const_int 2) (const_int 4)) | |
602 | (const_int 2) | |
603 | (if_then_else (eq_attr "is_arch6" "yes") | |
604 | (const_int 4) (const_int 6))]) | |
605 | (set_attr "type" "extend,load_byte,load_byte")] | |
606 | ) | |
607 | ||
608 | ;;; ??? This should have alternatives for constants. | |
609 | ;;; ??? This was originally identical to the movdf_insn pattern. | |
610 | ;;; ??? The 'i' constraint looks funny, but it should always be replaced by | |
611 | ;;; thumb_reorg with a memory reference. | |
612 | (define_insn "*thumb1_movdi_insn" | |
417e5cc5 | 613 | [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,r,l,>,l, m,*r") |
614 | (match_operand:DI 1 "general_operand" "l, I,J,j,>,l,mi,l,*r"))] | |
bc360af8 | 615 | "TARGET_THUMB1 |
616 | && ( register_operand (operands[0], DImode) | |
617 | || register_operand (operands[1], DImode))" | |
618 | "* | |
619 | { | |
620 | switch (which_alternative) | |
621 | { | |
622 | default: | |
623 | case 0: | |
624 | if (REGNO (operands[1]) == REGNO (operands[0]) + 1) | |
625 | return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; | |
626 | return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; | |
627 | case 1: | |
7e3c779e | 628 | return \"movs\\t%Q0, %1\;movs\\t%R0, #0\"; |
bc360af8 | 629 | case 2: |
630 | operands[1] = GEN_INT (- INTVAL (operands[1])); | |
7e3c779e | 631 | return \"movs\\t%Q0, %1\;rsbs\\t%Q0, %Q0, #0\;asrs\\t%R0, %Q0, #31\"; |
bc360af8 | 632 | case 3: |
417e5cc5 | 633 | gcc_assert (TARGET_HAVE_MOVT); |
634 | return \"movw\\t%Q0, %L1\;movs\\tR0, #0\"; | |
bc360af8 | 635 | case 4: |
417e5cc5 | 636 | return \"ldmia\\t%1, {%0, %H0}\"; |
bc360af8 | 637 | case 5: |
417e5cc5 | 638 | return \"stmia\\t%0, {%1, %H1}\"; |
bc360af8 | 639 | case 6: |
417e5cc5 | 640 | return thumb_load_double_from_address (operands); |
641 | case 7: | |
bc360af8 | 642 | operands[2] = gen_rtx_MEM (SImode, |
643 | plus_constant (Pmode, XEXP (operands[0], 0), 4)); | |
644 | output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); | |
645 | return \"\"; | |
417e5cc5 | 646 | case 8: |
bc360af8 | 647 | if (REGNO (operands[1]) == REGNO (operands[0]) + 1) |
648 | return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; | |
649 | return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; | |
650 | } | |
651 | }" | |
417e5cc5 | 652 | [(set_attr "length" "4,4,6,6,2,2,6,4,4") |
9f2c2a36 | 653 | (set_attr "type" "multiple,multiple,multiple,multiple,load_8,store_8,load_8,store_8,multiple") |
417e5cc5 | 654 | (set_attr "arch" "t1,t1,t1,v8mb,t1,t1,t1,t1,t1") |
655 | (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*")] | |
bc360af8 | 656 | ) |
657 | ||
658 | (define_insn "*thumb1_movsi_insn" | |
417e5cc5 | 659 | [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,r,l,l,l,>,l, m,*l*h*k") |
660 | (match_operand:SI 1 "general_operand" "l, I,j,J,K,>,l,mi,l,*l*h*k"))] | |
bc360af8 | 661 | "TARGET_THUMB1 |
662 | && ( register_operand (operands[0], SImode) | |
663 | || register_operand (operands[1], SImode))" | |
664 | "@ | |
7e3c779e | 665 | movs %0, %1 |
666 | movs %0, %1 | |
417e5cc5 | 667 | movw %0, %1 |
bc360af8 | 668 | # |
669 | # | |
670 | ldmia\\t%1, {%0} | |
671 | stmia\\t%0, {%1} | |
672 | ldr\\t%0, %1 | |
673 | str\\t%1, %0 | |
674 | mov\\t%0, %1" | |
417e5cc5 | 675 | [(set_attr "length" "2,2,4,4,4,2,2,2,2,2") |
9f2c2a36 | 676 | (set_attr "type" "mov_reg,mov_imm,mov_imm,multiple,multiple,load_4,store_4,load_4,store_4,mov_reg") |
417e5cc5 | 677 | (set_attr "pool_range" "*,*,*,*,*,*,*,1018,*,*") |
678 | (set_attr "arch" "t1,t1,v8mb,t1,t1,t1,t1,t1,t1,t1") | |
679 | (set_attr "conds" "set,clob,nocond,*,*,nocond,nocond,nocond,nocond,nocond")]) | |
bc360af8 | 680 | |
42dc494c | 681 | ; Split the load of 64-bit constant into two loads for high and low 32-bit parts respectively |
682 | ; to see if we can load them in fewer instructions or fewer cycles. | |
683 | ; For the small 64-bit integer constants that satisfy constraint J, the instruction pattern | |
684 | ; thumb1_movdi_insn has a better way to handle them. | |
685 | (define_split | |
686 | [(set (match_operand:ANY64 0 "arm_general_register_operand" "") | |
2b5018b0 | 687 | (match_operand:ANY64 1 "immediate_operand" ""))] |
42dc494c | 688 | "TARGET_THUMB1 && reload_completed && !satisfies_constraint_J (operands[1])" |
689 | [(set (match_dup 0) (match_dup 1)) | |
690 | (set (match_dup 2) (match_dup 3))] | |
691 | " | |
692 | operands[2] = gen_highpart (SImode, operands[0]); | |
693 | operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]), | |
694 | operands[1]); | |
695 | operands[0] = gen_lowpart (SImode, operands[0]); | |
696 | operands[1] = gen_lowpart (SImode, operands[1]); | |
697 | " | |
698 | ) | |
699 | ||
bc360af8 | 700 | (define_split |
701 | [(set (match_operand:SI 0 "register_operand" "") | |
702 | (match_operand:SI 1 "const_int_operand" ""))] | |
703 | "TARGET_THUMB1 && satisfies_constraint_J (operands[1])" | |
704 | [(set (match_dup 2) (match_dup 1)) | |
705 | (set (match_dup 0) (neg:SI (match_dup 2)))] | |
706 | " | |
707 | { | |
708 | operands[1] = GEN_INT (- INTVAL (operands[1])); | |
709 | operands[2] = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0]; | |
710 | }" | |
711 | ) | |
712 | ||
713 | (define_split | |
714 | [(set (match_operand:SI 0 "register_operand" "") | |
715 | (match_operand:SI 1 "const_int_operand" ""))] | |
417e5cc5 | 716 | "TARGET_THUMB1 && satisfies_constraint_K (operands[1]) |
717 | && !(TARGET_HAVE_MOVT && satisfies_constraint_j (operands[1]))" | |
bc360af8 | 718 | [(set (match_dup 2) (match_dup 1)) |
719 | (set (match_dup 0) (ashift:SI (match_dup 2) (match_dup 3)))] | |
720 | " | |
721 | { | |
722 | unsigned HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffffffffu; | |
723 | unsigned HOST_WIDE_INT mask = 0xff; | |
724 | int i; | |
725 | ||
726 | for (i = 0; i < 25; i++) | |
727 | if ((val & (mask << i)) == val) | |
728 | break; | |
729 | ||
730 | /* Don't split if the shift is zero. */ | |
731 | if (i == 0) | |
732 | FAIL; | |
733 | ||
734 | operands[1] = GEN_INT (val >> i); | |
735 | operands[2] = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0]; | |
736 | operands[3] = GEN_INT (i); | |
737 | }" | |
738 | ) | |
739 | ||
740 | ;; For thumb1 split imm move [256-510] into mov [1-255] and add #255 | |
741 | (define_split | |
742 | [(set (match_operand:SI 0 "register_operand" "") | |
743 | (match_operand:SI 1 "const_int_operand" ""))] | |
417e5cc5 | 744 | "TARGET_THUMB1 && satisfies_constraint_Pe (operands[1]) |
745 | && !(TARGET_HAVE_MOVT && satisfies_constraint_j (operands[1]))" | |
bc360af8 | 746 | [(set (match_dup 2) (match_dup 1)) |
747 | (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 3)))] | |
748 | " | |
749 | { | |
750 | operands[1] = GEN_INT (INTVAL (operands[1]) - 255); | |
751 | operands[2] = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0]; | |
752 | operands[3] = GEN_INT (255); | |
753 | }" | |
754 | ) | |
755 | ||
756 | (define_insn "*thumb1_movhi_insn" | |
417e5cc5 | 757 | [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,l*r,*h,l,r") |
758 | (match_operand:HI 1 "general_operand" "l,m,l,k*h,*r,I,n"))] | |
bc360af8 | 759 | "TARGET_THUMB1 |
760 | && ( register_operand (operands[0], HImode) | |
761 | || register_operand (operands[1], HImode))" | |
762 | "* | |
763 | switch (which_alternative) | |
764 | { | |
7e3c779e | 765 | case 0: return \"adds %0, %1, #0\"; |
bc360af8 | 766 | case 2: return \"strh %1, %0\"; |
767 | case 3: return \"mov %0, %1\"; | |
768 | case 4: return \"mov %0, %1\"; | |
7e3c779e | 769 | case 5: return \"movs %0, %1\"; |
417e5cc5 | 770 | case 6: gcc_assert (TARGET_HAVE_MOVT); |
771 | return \"movw %0, %L1\"; | |
bc360af8 | 772 | default: gcc_unreachable (); |
773 | case 1: | |
774 | /* The stack pointer can end up being taken as an index register. | |
775 | Catch this case here and deal with it. */ | |
776 | if (GET_CODE (XEXP (operands[1], 0)) == PLUS | |
777 | && REG_P (XEXP (XEXP (operands[1], 0), 0)) | |
778 | && REGNO (XEXP (XEXP (operands[1], 0), 0)) == SP_REGNUM) | |
779 | { | |
780 | rtx ops[2]; | |
781 | ops[0] = operands[0]; | |
782 | ops[1] = XEXP (XEXP (operands[1], 0), 0); | |
783 | ||
784 | output_asm_insn (\"mov %0, %1\", ops); | |
785 | ||
786 | XEXP (XEXP (operands[1], 0), 0) = operands[0]; | |
787 | ||
788 | } | |
789 | return \"ldrh %0, %1\"; | |
790 | }" | |
417e5cc5 | 791 | [(set_attr "length" "2,4,2,2,2,2,4") |
9f2c2a36 | 792 | (set_attr "type" "alus_imm,load_4,store_4,mov_reg,mov_reg,mov_imm,mov_imm") |
417e5cc5 | 793 | (set_attr "arch" "t1,t1,t1,t1,t1,t1,v8mb") |
794 | (set_attr "conds" "clob,nocond,nocond,nocond,nocond,clob,nocond")]) | |
bc360af8 | 795 | |
796 | (define_expand "thumb_movhi_clobber" | |
797 | [(set (match_operand:HI 0 "memory_operand" "") | |
798 | (match_operand:HI 1 "register_operand" "")) | |
799 | (clobber (match_operand:DI 2 "register_operand" ""))] | |
800 | "TARGET_THUMB1" | |
801 | " | |
802 | if (strict_memory_address_p (HImode, XEXP (operands[0], 0)) | |
803 | && REGNO (operands[1]) <= LAST_LO_REGNUM) | |
804 | { | |
805 | emit_insn (gen_movhi (operands[0], operands[1])); | |
806 | DONE; | |
807 | } | |
808 | /* XXX Fixme, need to handle other cases here as well. */ | |
809 | gcc_unreachable (); | |
810 | " | |
811 | ) | |
812 | ||
813 | (define_insn "*thumb1_movqi_insn" | |
427da503 | 814 | [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,l*r,*h,l") |
815 | (match_operand:QI 1 "general_operand" "l,m,l,k*h,*r,I"))] | |
bc360af8 | 816 | "TARGET_THUMB1 |
817 | && ( register_operand (operands[0], QImode) | |
818 | || register_operand (operands[1], QImode))" | |
819 | "@ | |
7e3c779e | 820 | adds\\t%0, %1, #0 |
bc360af8 | 821 | ldrb\\t%0, %1 |
822 | strb\\t%1, %0 | |
823 | mov\\t%0, %1 | |
824 | mov\\t%0, %1 | |
7e3c779e | 825 | movs\\t%0, %1" |
bc360af8 | 826 | [(set_attr "length" "2") |
9f2c2a36 | 827 | (set_attr "type" "alu_imm,load_4,store_4,mov_reg,mov_imm,mov_imm") |
bc360af8 | 828 | (set_attr "pool_range" "*,32,*,*,*,*") |
829 | (set_attr "conds" "clob,nocond,nocond,nocond,nocond,clob")]) | |
830 | ||
831 | (define_insn "*thumb1_movhf" | |
832 | [(set (match_operand:HF 0 "nonimmediate_operand" "=l,l,m,*r,*h") | |
833 | (match_operand:HF 1 "general_operand" "l,mF,l,*h,*r"))] | |
834 | "TARGET_THUMB1 | |
835 | && ( s_register_operand (operands[0], HFmode) | |
836 | || s_register_operand (operands[1], HFmode))" | |
837 | "* | |
838 | switch (which_alternative) | |
839 | { | |
3582b939 | 840 | case 0: |
841 | return \"movs\\t%0, %1\"; | |
bc360af8 | 842 | case 1: |
843 | { | |
844 | rtx addr; | |
845 | gcc_assert (MEM_P (operands[1])); | |
846 | addr = XEXP (operands[1], 0); | |
847 | if (GET_CODE (addr) == LABEL_REF | |
848 | || (GET_CODE (addr) == CONST | |
849 | && GET_CODE (XEXP (addr, 0)) == PLUS | |
850 | && GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF | |
851 | && CONST_INT_P (XEXP (XEXP (addr, 0), 1)))) | |
852 | { | |
853 | /* Constant pool entry. */ | |
854 | return \"ldr\\t%0, %1\"; | |
855 | } | |
856 | return \"ldrh\\t%0, %1\"; | |
857 | } | |
858 | case 2: return \"strh\\t%1, %0\"; | |
859 | default: return \"mov\\t%0, %1\"; | |
860 | } | |
861 | " | |
862 | [(set_attr "length" "2") | |
9f2c2a36 | 863 | (set_attr "type" "mov_reg,load_4,store_4,mov_reg,mov_reg") |
bc360af8 | 864 | (set_attr "pool_range" "*,1018,*,*,*") |
865 | (set_attr "conds" "clob,nocond,nocond,nocond,nocond")]) | |
866 | ;;; ??? This should have alternatives for constants. | |
867 | (define_insn "*thumb1_movsf_insn" | |
868 | [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l, m,*r,*h") | |
869 | (match_operand:SF 1 "general_operand" "l, >,l,mF,l,*h,*r"))] | |
870 | "TARGET_THUMB1 | |
871 | && ( register_operand (operands[0], SFmode) | |
872 | || register_operand (operands[1], SFmode))" | |
873 | "@ | |
7e3c779e | 874 | adds\\t%0, %1, #0 |
bc360af8 | 875 | ldmia\\t%1, {%0} |
876 | stmia\\t%0, {%1} | |
877 | ldr\\t%0, %1 | |
878 | str\\t%1, %0 | |
879 | mov\\t%0, %1 | |
880 | mov\\t%0, %1" | |
881 | [(set_attr "length" "2") | |
9f2c2a36 | 882 | (set_attr "type" "alus_imm,load_4,store_4,load_4,store_4,mov_reg,mov_reg") |
bc360af8 | 883 | (set_attr "pool_range" "*,*,*,1018,*,*,*") |
884 | (set_attr "conds" "clob,nocond,nocond,nocond,nocond,nocond,nocond")] | |
885 | ) | |
886 | ||
887 | ;;; ??? This should have alternatives for constants. | |
888 | ;;; ??? This was originally identical to the movdi_insn pattern. | |
889 | ;;; ??? The 'F' constraint looks funny, but it should always be replaced by | |
890 | ;;; thumb_reorg with a memory reference. | |
891 | (define_insn "*thumb_movdf_insn" | |
892 | [(set (match_operand:DF 0 "nonimmediate_operand" "=l,l,>,l, m,*r") | |
893 | (match_operand:DF 1 "general_operand" "l, >,l,mF,l,*r"))] | |
894 | "TARGET_THUMB1 | |
895 | && ( register_operand (operands[0], DFmode) | |
896 | || register_operand (operands[1], DFmode))" | |
897 | "* | |
898 | switch (which_alternative) | |
899 | { | |
900 | default: | |
901 | case 0: | |
902 | if (REGNO (operands[1]) == REGNO (operands[0]) + 1) | |
7e3c779e | 903 | return \"adds\\t%0, %1, #0\;adds\\t%H0, %H1, #0\"; |
904 | return \"adds\\t%H0, %H1, #0\;adds\\t%0, %1, #0\"; | |
bc360af8 | 905 | case 1: |
906 | return \"ldmia\\t%1, {%0, %H0}\"; | |
907 | case 2: | |
908 | return \"stmia\\t%0, {%1, %H1}\"; | |
909 | case 3: | |
910 | return thumb_load_double_from_address (operands); | |
911 | case 4: | |
912 | operands[2] = gen_rtx_MEM (SImode, | |
913 | plus_constant (Pmode, | |
914 | XEXP (operands[0], 0), 4)); | |
915 | output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); | |
916 | return \"\"; | |
917 | case 5: | |
918 | if (REGNO (operands[1]) == REGNO (operands[0]) + 1) | |
919 | return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; | |
920 | return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; | |
921 | } | |
922 | " | |
923 | [(set_attr "length" "4,2,2,6,4,4") | |
9f2c2a36 | 924 | (set_attr "type" "multiple,load_8,store_8,load_8,store_8,multiple") |
bc360af8 | 925 | (set_attr "pool_range" "*,*,*,1018,*,*")] |
926 | ) | |
927 | \f | |
928 | ||
929 | ;; Thumb block-move insns | |
930 | ||
931 | (define_insn "movmem12b" | |
932 | [(set (mem:SI (match_operand:SI 2 "register_operand" "0")) | |
933 | (mem:SI (match_operand:SI 3 "register_operand" "1"))) | |
934 | (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) | |
935 | (mem:SI (plus:SI (match_dup 3) (const_int 4)))) | |
936 | (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) | |
937 | (mem:SI (plus:SI (match_dup 3) (const_int 8)))) | |
938 | (set (match_operand:SI 0 "register_operand" "=l") | |
939 | (plus:SI (match_dup 2) (const_int 12))) | |
940 | (set (match_operand:SI 1 "register_operand" "=l") | |
941 | (plus:SI (match_dup 3) (const_int 12))) | |
942 | (clobber (match_scratch:SI 4 "=&l")) | |
943 | (clobber (match_scratch:SI 5 "=&l")) | |
944 | (clobber (match_scratch:SI 6 "=&l"))] | |
945 | "TARGET_THUMB1" | |
946 | "* return thumb_output_move_mem_multiple (3, operands);" | |
947 | [(set_attr "length" "4") | |
948 | ; This isn't entirely accurate... It loads as well, but in terms of | |
949 | ; scheduling the following insn it is better to consider it as a store | |
9f2c2a36 | 950 | (set_attr "type" "store_12")] |
bc360af8 | 951 | ) |
952 | ||
953 | (define_insn "movmem8b" | |
954 | [(set (mem:SI (match_operand:SI 2 "register_operand" "0")) | |
955 | (mem:SI (match_operand:SI 3 "register_operand" "1"))) | |
956 | (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) | |
957 | (mem:SI (plus:SI (match_dup 3) (const_int 4)))) | |
958 | (set (match_operand:SI 0 "register_operand" "=l") | |
959 | (plus:SI (match_dup 2) (const_int 8))) | |
960 | (set (match_operand:SI 1 "register_operand" "=l") | |
961 | (plus:SI (match_dup 3) (const_int 8))) | |
962 | (clobber (match_scratch:SI 4 "=&l")) | |
963 | (clobber (match_scratch:SI 5 "=&l"))] | |
964 | "TARGET_THUMB1" | |
965 | "* return thumb_output_move_mem_multiple (2, operands);" | |
966 | [(set_attr "length" "4") | |
967 | ; This isn't entirely accurate... It loads as well, but in terms of | |
968 | ; scheduling the following insn it is better to consider it as a store | |
9f2c2a36 | 969 | (set_attr "type" "store_8")] |
bc360af8 | 970 | ) |
971 | ||
972 | \f | |
973 | ;; A pattern to recognize a special situation and optimize for it. | |
974 | ;; On the thumb, zero-extension from memory is preferrable to sign-extension | |
975 | ;; due to the available addressing modes. Hence, convert a signed comparison | |
976 | ;; with zero into an unsigned comparison with 127 if possible. | |
977 | (define_expand "cbranchqi4" | |
978 | [(set (pc) (if_then_else | |
979 | (match_operator 0 "lt_ge_comparison_operator" | |
980 | [(match_operand:QI 1 "memory_operand" "") | |
981 | (match_operand:QI 2 "const0_operand" "")]) | |
982 | (label_ref (match_operand 3 "" "")) | |
983 | (pc)))] | |
984 | "TARGET_THUMB1" | |
985 | { | |
986 | rtx xops[4]; | |
987 | xops[1] = gen_reg_rtx (SImode); | |
988 | emit_insn (gen_zero_extendqisi2 (xops[1], operands[1])); | |
989 | xops[2] = GEN_INT (127); | |
990 | xops[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]) == GE ? LEU : GTU, | |
991 | VOIDmode, xops[1], xops[2]); | |
992 | xops[3] = operands[3]; | |
993 | emit_insn (gen_cbranchsi4 (xops[0], xops[1], xops[2], xops[3])); | |
994 | DONE; | |
995 | }) | |
996 | ||
8f5f2788 | 997 | ;; A pattern for the CB(N)Z instruction added in ARMv8-M Baseline profile, |
998 | ;; adapted from cbranchsi4_insn. Modifying cbranchsi4_insn instead leads to | |
999 | ;; code generation difference for ARMv6-M because the minimum length of the | |
1000 | ;; instruction becomes 2 even for ARMv6-M due to a limitation in genattrtab's | |
1001 | ;; handling of PC in the length condition. | |
1002 | (define_insn "thumb1_cbz" | |
1003 | [(set (pc) (if_then_else | |
1004 | (match_operator 0 "equality_operator" | |
1005 | [(match_operand:SI 1 "s_register_operand" "l") | |
1006 | (const_int 0)]) | |
1007 | (label_ref (match_operand 2 "" "")) | |
1008 | (pc)))] | |
1009 | "TARGET_THUMB1 && TARGET_HAVE_CBZ" | |
1010 | { | |
1011 | if (get_attr_length (insn) == 2) | |
1012 | { | |
1013 | if (GET_CODE (operands[0]) == EQ) | |
1014 | return "cbz\t%1, %l2"; | |
1015 | else | |
1016 | return "cbnz\t%1, %l2"; | |
1017 | } | |
1018 | else | |
1019 | { | |
1020 | rtx t = cfun->machine->thumb1_cc_insn; | |
1021 | if (t != NULL_RTX) | |
1022 | { | |
1023 | if (!rtx_equal_p (cfun->machine->thumb1_cc_op0, operands[1]) | |
1024 | || !rtx_equal_p (cfun->machine->thumb1_cc_op1, operands[2])) | |
1025 | t = NULL_RTX; | |
1026 | if (cfun->machine->thumb1_cc_mode == CC_NOOVmode) | |
1027 | { | |
1028 | if (!noov_comparison_operator (operands[0], VOIDmode)) | |
1029 | t = NULL_RTX; | |
1030 | } | |
1031 | else if (cfun->machine->thumb1_cc_mode != CCmode) | |
1032 | t = NULL_RTX; | |
1033 | } | |
1034 | if (t == NULL_RTX) | |
1035 | { | |
1036 | output_asm_insn ("cmp\t%1, #0", operands); | |
1037 | cfun->machine->thumb1_cc_insn = insn; | |
1038 | cfun->machine->thumb1_cc_op0 = operands[1]; | |
1039 | cfun->machine->thumb1_cc_op1 = operands[2]; | |
1040 | cfun->machine->thumb1_cc_mode = CCmode; | |
1041 | } | |
1042 | else | |
1043 | /* Ensure we emit the right type of condition code on the jump. */ | |
1044 | XEXP (operands[0], 0) = gen_rtx_REG (cfun->machine->thumb1_cc_mode, | |
1045 | CC_REGNUM); | |
1046 | ||
1047 | switch (get_attr_length (insn)) | |
1048 | { | |
1049 | case 4: return "b%d0\t%l2"; | |
1050 | case 6: return "b%D0\t.LCB%=;b\t%l2\t%@long jump\n.LCB%=:"; | |
1051 | case 8: return "b%D0\t.LCB%=;bl\t%l2\t%@far jump\n.LCB%=:"; | |
1052 | default: gcc_unreachable (); | |
1053 | } | |
1054 | } | |
1055 | } | |
1056 | [(set (attr "far_jump") | |
1057 | (if_then_else | |
1058 | (eq_attr "length" "8") | |
1059 | (const_string "yes") | |
1060 | (const_string "no"))) | |
1061 | (set (attr "length") | |
1062 | (if_then_else | |
1063 | (and (ge (minus (match_dup 2) (pc)) (const_int 2)) | |
1064 | (le (minus (match_dup 2) (pc)) (const_int 128))) | |
1065 | (const_int 2) | |
1066 | (if_then_else | |
1067 | (and (ge (minus (match_dup 2) (pc)) (const_int -250)) | |
1068 | (le (minus (match_dup 2) (pc)) (const_int 256))) | |
1069 | (const_int 4) | |
1070 | (if_then_else | |
1071 | (and (ge (minus (match_dup 2) (pc)) (const_int -2040)) | |
1072 | (le (minus (match_dup 2) (pc)) (const_int 2048))) | |
1073 | (const_int 6) | |
1074 | (const_int 8))))) | |
1075 | (set (attr "type") | |
1076 | (if_then_else | |
1077 | (eq_attr "length" "2") | |
1078 | (const_string "branch") | |
1079 | (const_string "multiple")))] | |
1080 | ) | |
1081 | ||
12f9739f | 1082 | ;; Changes to the constraints of this pattern must be propagated to those of |
1083 | ;; atomic compare_and_swap splitters in sync.md. These must be at least as | |
1084 | ;; strict as the constraints here and aim to be as permissive. | |
bc360af8 | 1085 | (define_insn "cbranchsi4_insn" |
1086 | [(set (pc) (if_then_else | |
1087 | (match_operator 0 "arm_comparison_operator" | |
1088 | [(match_operand:SI 1 "s_register_operand" "l,l*h") | |
1089 | (match_operand:SI 2 "thumb1_cmp_operand" "lI*h,*r")]) | |
1090 | (label_ref (match_operand 3 "" "")) | |
1091 | (pc)))] | |
1092 | "TARGET_THUMB1" | |
1093 | { | |
1094 | rtx t = cfun->machine->thumb1_cc_insn; | |
1095 | if (t != NULL_RTX) | |
1096 | { | |
1097 | if (!rtx_equal_p (cfun->machine->thumb1_cc_op0, operands[1]) | |
1098 | || !rtx_equal_p (cfun->machine->thumb1_cc_op1, operands[2])) | |
1099 | t = NULL_RTX; | |
1100 | if (cfun->machine->thumb1_cc_mode == CC_NOOVmode) | |
1101 | { | |
1102 | if (!noov_comparison_operator (operands[0], VOIDmode)) | |
1103 | t = NULL_RTX; | |
1104 | } | |
1105 | else if (cfun->machine->thumb1_cc_mode != CCmode) | |
1106 | t = NULL_RTX; | |
1107 | } | |
1108 | if (t == NULL_RTX) | |
1109 | { | |
1110 | output_asm_insn ("cmp\t%1, %2", operands); | |
1111 | cfun->machine->thumb1_cc_insn = insn; | |
1112 | cfun->machine->thumb1_cc_op0 = operands[1]; | |
1113 | cfun->machine->thumb1_cc_op1 = operands[2]; | |
1114 | cfun->machine->thumb1_cc_mode = CCmode; | |
1115 | } | |
1116 | else | |
1117 | /* Ensure we emit the right type of condition code on the jump. */ | |
1118 | XEXP (operands[0], 0) = gen_rtx_REG (cfun->machine->thumb1_cc_mode, | |
1119 | CC_REGNUM); | |
1120 | ||
1121 | switch (get_attr_length (insn)) | |
1122 | { | |
1123 | case 4: return \"b%d0\\t%l3\"; | |
1124 | case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; | |
1125 | default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; | |
1126 | } | |
1127 | } | |
1128 | [(set (attr "far_jump") | |
1129 | (if_then_else | |
1130 | (eq_attr "length" "8") | |
1131 | (const_string "yes") | |
1132 | (const_string "no"))) | |
1133 | (set (attr "length") | |
1134 | (if_then_else | |
1135 | (and (ge (minus (match_dup 3) (pc)) (const_int -250)) | |
1136 | (le (minus (match_dup 3) (pc)) (const_int 256))) | |
1137 | (const_int 4) | |
1138 | (if_then_else | |
1139 | (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) | |
1140 | (le (minus (match_dup 3) (pc)) (const_int 2048))) | |
1141 | (const_int 6) | |
1142 | (const_int 8)))) | |
1143 | (set_attr "type" "multiple")] | |
1144 | ) | |
1145 | ||
12f9739f | 1146 | ;; Changes to the constraints of this pattern must be propagated to those of |
1147 | ;; atomic compare_and_swap splitters in sync.md. These must be at least as | |
1148 | ;; strict as the constraints here and aim to be as permissive. | |
bc360af8 | 1149 | (define_insn "cbranchsi4_scratch" |
1150 | [(set (pc) (if_then_else | |
1151 | (match_operator 4 "arm_comparison_operator" | |
1152 | [(match_operand:SI 1 "s_register_operand" "l,0") | |
1153 | (match_operand:SI 2 "thumb1_cmpneg_operand" "L,J")]) | |
1154 | (label_ref (match_operand 3 "" "")) | |
1155 | (pc))) | |
1156 | (clobber (match_scratch:SI 0 "=l,l"))] | |
1157 | "TARGET_THUMB1" | |
1158 | "* | |
7e3c779e | 1159 | output_asm_insn (\"adds\\t%0, %1, #%n2\", operands); |
bc360af8 | 1160 | |
1161 | switch (get_attr_length (insn)) | |
1162 | { | |
1163 | case 4: return \"b%d4\\t%l3\"; | |
1164 | case 6: return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; | |
1165 | default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; | |
1166 | } | |
1167 | " | |
1168 | [(set (attr "far_jump") | |
1169 | (if_then_else | |
1170 | (eq_attr "length" "8") | |
1171 | (const_string "yes") | |
1172 | (const_string "no"))) | |
1173 | (set (attr "length") | |
1174 | (if_then_else | |
1175 | (and (ge (minus (match_dup 3) (pc)) (const_int -250)) | |
1176 | (le (minus (match_dup 3) (pc)) (const_int 256))) | |
1177 | (const_int 4) | |
1178 | (if_then_else | |
1179 | (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) | |
1180 | (le (minus (match_dup 3) (pc)) (const_int 2048))) | |
1181 | (const_int 6) | |
1182 | (const_int 8)))) | |
1183 | (set_attr "type" "multiple")] | |
1184 | ) | |
1185 | ||
1186 | (define_insn "*negated_cbranchsi4" | |
1187 | [(set (pc) | |
1188 | (if_then_else | |
1189 | (match_operator 0 "equality_operator" | |
1190 | [(match_operand:SI 1 "s_register_operand" "l") | |
1191 | (neg:SI (match_operand:SI 2 "s_register_operand" "l"))]) | |
1192 | (label_ref (match_operand 3 "" "")) | |
1193 | (pc)))] | |
1194 | "TARGET_THUMB1" | |
1195 | "* | |
1196 | output_asm_insn (\"cmn\\t%1, %2\", operands); | |
1197 | switch (get_attr_length (insn)) | |
1198 | { | |
1199 | case 4: return \"b%d0\\t%l3\"; | |
1200 | case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; | |
1201 | default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; | |
1202 | } | |
1203 | " | |
1204 | [(set (attr "far_jump") | |
1205 | (if_then_else | |
1206 | (eq_attr "length" "8") | |
1207 | (const_string "yes") | |
1208 | (const_string "no"))) | |
1209 | (set (attr "length") | |
1210 | (if_then_else | |
1211 | (and (ge (minus (match_dup 3) (pc)) (const_int -250)) | |
1212 | (le (minus (match_dup 3) (pc)) (const_int 256))) | |
1213 | (const_int 4) | |
1214 | (if_then_else | |
1215 | (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) | |
1216 | (le (minus (match_dup 3) (pc)) (const_int 2048))) | |
1217 | (const_int 6) | |
1218 | (const_int 8)))) | |
1219 | (set_attr "type" "multiple")] | |
1220 | ) | |
1221 | ||
1222 | (define_insn "*tbit_cbranch" | |
1223 | [(set (pc) | |
1224 | (if_then_else | |
1225 | (match_operator 0 "equality_operator" | |
1226 | [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l") | |
1227 | (const_int 1) | |
1228 | (match_operand:SI 2 "const_int_operand" "i")) | |
1229 | (const_int 0)]) | |
1230 | (label_ref (match_operand 3 "" "")) | |
1231 | (pc))) | |
1232 | (clobber (match_scratch:SI 4 "=l"))] | |
1233 | "TARGET_THUMB1" | |
1234 | "* | |
1235 | { | |
1236 | rtx op[3]; | |
1237 | op[0] = operands[4]; | |
1238 | op[1] = operands[1]; | |
1239 | op[2] = GEN_INT (32 - 1 - INTVAL (operands[2])); | |
1240 | ||
7e3c779e | 1241 | output_asm_insn (\"lsls\\t%0, %1, %2\", op); |
bc360af8 | 1242 | switch (get_attr_length (insn)) |
1243 | { | |
1244 | case 4: return \"b%d0\\t%l3\"; | |
1245 | case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; | |
1246 | default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; | |
1247 | } | |
1248 | }" | |
1249 | [(set (attr "far_jump") | |
1250 | (if_then_else | |
1251 | (eq_attr "length" "8") | |
1252 | (const_string "yes") | |
1253 | (const_string "no"))) | |
1254 | (set (attr "length") | |
1255 | (if_then_else | |
1256 | (and (ge (minus (match_dup 3) (pc)) (const_int -250)) | |
1257 | (le (minus (match_dup 3) (pc)) (const_int 256))) | |
1258 | (const_int 4) | |
1259 | (if_then_else | |
1260 | (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) | |
1261 | (le (minus (match_dup 3) (pc)) (const_int 2048))) | |
1262 | (const_int 6) | |
1263 | (const_int 8)))) | |
1264 | (set_attr "type" "multiple")] | |
1265 | ) | |
1266 | ||
1267 | (define_insn "*tlobits_cbranch" | |
1268 | [(set (pc) | |
1269 | (if_then_else | |
1270 | (match_operator 0 "equality_operator" | |
1271 | [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l") | |
1272 | (match_operand:SI 2 "const_int_operand" "i") | |
1273 | (const_int 0)) | |
1274 | (const_int 0)]) | |
1275 | (label_ref (match_operand 3 "" "")) | |
1276 | (pc))) | |
1277 | (clobber (match_scratch:SI 4 "=l"))] | |
1278 | "TARGET_THUMB1" | |
1279 | "* | |
1280 | { | |
1281 | rtx op[3]; | |
1282 | op[0] = operands[4]; | |
1283 | op[1] = operands[1]; | |
1284 | op[2] = GEN_INT (32 - INTVAL (operands[2])); | |
1285 | ||
7e3c779e | 1286 | output_asm_insn (\"lsls\\t%0, %1, %2\", op); |
bc360af8 | 1287 | switch (get_attr_length (insn)) |
1288 | { | |
1289 | case 4: return \"b%d0\\t%l3\"; | |
1290 | case 6: return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\"; | |
1291 | default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\"; | |
1292 | } | |
1293 | }" | |
1294 | [(set (attr "far_jump") | |
1295 | (if_then_else | |
1296 | (eq_attr "length" "8") | |
1297 | (const_string "yes") | |
1298 | (const_string "no"))) | |
1299 | (set (attr "length") | |
1300 | (if_then_else | |
1301 | (and (ge (minus (match_dup 3) (pc)) (const_int -250)) | |
1302 | (le (minus (match_dup 3) (pc)) (const_int 256))) | |
1303 | (const_int 4) | |
1304 | (if_then_else | |
1305 | (and (ge (minus (match_dup 3) (pc)) (const_int -2040)) | |
1306 | (le (minus (match_dup 3) (pc)) (const_int 2048))) | |
1307 | (const_int 6) | |
1308 | (const_int 8)))) | |
1309 | (set_attr "type" "multiple")] | |
1310 | ) | |
1311 | ||
1312 | (define_insn "*tstsi3_cbranch" | |
1313 | [(set (pc) | |
1314 | (if_then_else | |
1315 | (match_operator 3 "equality_operator" | |
1316 | [(and:SI (match_operand:SI 0 "s_register_operand" "%l") | |
1317 | (match_operand:SI 1 "s_register_operand" "l")) | |
1318 | (const_int 0)]) | |
1319 | (label_ref (match_operand 2 "" "")) | |
1320 | (pc)))] | |
1321 | "TARGET_THUMB1" | |
1322 | "* | |
1323 | { | |
1324 | output_asm_insn (\"tst\\t%0, %1\", operands); | |
1325 | switch (get_attr_length (insn)) | |
1326 | { | |
1327 | case 4: return \"b%d3\\t%l2\"; | |
1328 | case 6: return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\"; | |
1329 | default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\"; | |
1330 | } | |
1331 | }" | |
1332 | [(set (attr "far_jump") | |
1333 | (if_then_else | |
1334 | (eq_attr "length" "8") | |
1335 | (const_string "yes") | |
1336 | (const_string "no"))) | |
1337 | (set (attr "length") | |
1338 | (if_then_else | |
1339 | (and (ge (minus (match_dup 2) (pc)) (const_int -250)) | |
1340 | (le (minus (match_dup 2) (pc)) (const_int 256))) | |
1341 | (const_int 4) | |
1342 | (if_then_else | |
1343 | (and (ge (minus (match_dup 2) (pc)) (const_int -2040)) | |
1344 | (le (minus (match_dup 2) (pc)) (const_int 2048))) | |
1345 | (const_int 6) | |
1346 | (const_int 8)))) | |
1347 | (set_attr "type" "multiple")] | |
1348 | ) | |
1349 | ||
1350 | (define_insn "*cbranchne_decr1" | |
1351 | [(set (pc) | |
1352 | (if_then_else (match_operator 3 "equality_operator" | |
1353 | [(match_operand:SI 2 "s_register_operand" "l,l,1,l") | |
1354 | (const_int 0)]) | |
1355 | (label_ref (match_operand 4 "" "")) | |
1356 | (pc))) | |
1357 | (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m") | |
1358 | (plus:SI (match_dup 2) (const_int -1))) | |
1359 | (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] | |
1360 | "TARGET_THUMB1" | |
1361 | "* | |
1362 | { | |
1363 | rtx cond[2]; | |
1364 | cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE | |
1365 | ? GEU : LTU), | |
1366 | VOIDmode, operands[2], const1_rtx); | |
1367 | cond[1] = operands[4]; | |
1368 | ||
1369 | if (which_alternative == 0) | |
7e3c779e | 1370 | output_asm_insn (\"subs\\t%0, %2, #1\", operands); |
bc360af8 | 1371 | else if (which_alternative == 1) |
1372 | { | |
1373 | /* We must provide an alternative for a hi reg because reload | |
1374 | cannot handle output reloads on a jump instruction, but we | |
1375 | can't subtract into that. Fortunately a mov from lo to hi | |
1376 | does not clobber the condition codes. */ | |
7e3c779e | 1377 | output_asm_insn (\"subs\\t%1, %2, #1\", operands); |
bc360af8 | 1378 | output_asm_insn (\"mov\\t%0, %1\", operands); |
1379 | } | |
1380 | else | |
1381 | { | |
1382 | /* Similarly, but the target is memory. */ | |
7e3c779e | 1383 | output_asm_insn (\"subs\\t%1, %2, #1\", operands); |
bc360af8 | 1384 | output_asm_insn (\"str\\t%1, %0\", operands); |
1385 | } | |
1386 | ||
1387 | switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) | |
1388 | { | |
1389 | case 4: | |
1390 | output_asm_insn (\"b%d0\\t%l1\", cond); | |
1391 | return \"\"; | |
1392 | case 6: | |
1393 | output_asm_insn (\"b%D0\\t.LCB%=\", cond); | |
1394 | return \"b\\t%l4\\t%@long jump\\n.LCB%=:\"; | |
1395 | default: | |
1396 | output_asm_insn (\"b%D0\\t.LCB%=\", cond); | |
1397 | return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\"; | |
1398 | } | |
1399 | } | |
1400 | " | |
1401 | [(set (attr "far_jump") | |
1402 | (if_then_else | |
1403 | (ior (and (eq (symbol_ref ("which_alternative")) | |
1404 | (const_int 0)) | |
1405 | (eq_attr "length" "8")) | |
1406 | (eq_attr "length" "10")) | |
1407 | (const_string "yes") | |
1408 | (const_string "no"))) | |
1409 | (set_attr_alternative "length" | |
1410 | [ | |
1411 | ;; Alternative 0 | |
1412 | (if_then_else | |
1413 | (and (ge (minus (match_dup 4) (pc)) (const_int -250)) | |
1414 | (le (minus (match_dup 4) (pc)) (const_int 256))) | |
1415 | (const_int 4) | |
1416 | (if_then_else | |
1417 | (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) | |
1418 | (le (minus (match_dup 4) (pc)) (const_int 2048))) | |
1419 | (const_int 6) | |
1420 | (const_int 8))) | |
1421 | ;; Alternative 1 | |
1422 | (if_then_else | |
1423 | (and (ge (minus (match_dup 4) (pc)) (const_int -248)) | |
1424 | (le (minus (match_dup 4) (pc)) (const_int 256))) | |
1425 | (const_int 6) | |
1426 | (if_then_else | |
1427 | (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) | |
1428 | (le (minus (match_dup 4) (pc)) (const_int 2048))) | |
1429 | (const_int 8) | |
1430 | (const_int 10))) | |
1431 | ;; Alternative 2 | |
1432 | (if_then_else | |
1433 | (and (ge (minus (match_dup 4) (pc)) (const_int -248)) | |
1434 | (le (minus (match_dup 4) (pc)) (const_int 256))) | |
1435 | (const_int 6) | |
1436 | (if_then_else | |
1437 | (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) | |
1438 | (le (minus (match_dup 4) (pc)) (const_int 2048))) | |
1439 | (const_int 8) | |
1440 | (const_int 10))) | |
1441 | ;; Alternative 3 | |
1442 | (if_then_else | |
1443 | (and (ge (minus (match_dup 4) (pc)) (const_int -248)) | |
1444 | (le (minus (match_dup 4) (pc)) (const_int 256))) | |
1445 | (const_int 6) | |
1446 | (if_then_else | |
1447 | (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) | |
1448 | (le (minus (match_dup 4) (pc)) (const_int 2048))) | |
1449 | (const_int 8) | |
1450 | (const_int 10)))]) | |
1451 | (set_attr "type" "multiple")] | |
1452 | ) | |
1453 | ||
1454 | (define_insn "*addsi3_cbranch" | |
1455 | [(set (pc) | |
1456 | (if_then_else | |
1457 | (match_operator 4 "arm_comparison_operator" | |
1458 | [(plus:SI | |
1459 | (match_operand:SI 2 "s_register_operand" "%0,l,*l,1,1,1") | |
1460 | (match_operand:SI 3 "reg_or_int_operand" "IJ,lL,*l,lIJ,lIJ,lIJ")) | |
1461 | (const_int 0)]) | |
1462 | (label_ref (match_operand 5 "" "")) | |
1463 | (pc))) | |
1464 | (set | |
1465 | (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,*?h,*?m,*?m") | |
1466 | (plus:SI (match_dup 2) (match_dup 3))) | |
1467 | (clobber (match_scratch:SI 1 "=X,X,l,l,&l,&l"))] | |
1468 | "TARGET_THUMB1 | |
1469 | && (GET_CODE (operands[4]) == EQ | |
1470 | || GET_CODE (operands[4]) == NE | |
1471 | || GET_CODE (operands[4]) == GE | |
1472 | || GET_CODE (operands[4]) == LT)" | |
1473 | "* | |
1474 | { | |
1475 | rtx cond[3]; | |
1476 | ||
1477 | cond[0] = (which_alternative < 2) ? operands[0] : operands[1]; | |
1478 | cond[1] = operands[2]; | |
1479 | cond[2] = operands[3]; | |
1480 | ||
1481 | if (CONST_INT_P (cond[2]) && INTVAL (cond[2]) < 0) | |
7e3c779e | 1482 | output_asm_insn (\"subs\\t%0, %1, #%n2\", cond); |
bc360af8 | 1483 | else |
7e3c779e | 1484 | output_asm_insn (\"adds\\t%0, %1, %2\", cond); |
bc360af8 | 1485 | |
1486 | if (which_alternative >= 2 | |
1487 | && which_alternative < 4) | |
1488 | output_asm_insn (\"mov\\t%0, %1\", operands); | |
1489 | else if (which_alternative >= 4) | |
1490 | output_asm_insn (\"str\\t%1, %0\", operands); | |
1491 | ||
1492 | switch (get_attr_length (insn) - ((which_alternative >= 2) ? 2 : 0)) | |
1493 | { | |
1494 | case 4: | |
1495 | return \"b%d4\\t%l5\"; | |
1496 | case 6: | |
1497 | return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\"; | |
1498 | default: | |
1499 | return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\"; | |
1500 | } | |
1501 | } | |
1502 | " | |
1503 | [(set (attr "far_jump") | |
1504 | (if_then_else | |
1505 | (ior (and (lt (symbol_ref ("which_alternative")) | |
1506 | (const_int 2)) | |
1507 | (eq_attr "length" "8")) | |
1508 | (eq_attr "length" "10")) | |
1509 | (const_string "yes") | |
1510 | (const_string "no"))) | |
1511 | (set (attr "length") | |
1512 | (if_then_else | |
1513 | (lt (symbol_ref ("which_alternative")) | |
1514 | (const_int 2)) | |
1515 | (if_then_else | |
1516 | (and (ge (minus (match_dup 5) (pc)) (const_int -250)) | |
1517 | (le (minus (match_dup 5) (pc)) (const_int 256))) | |
1518 | (const_int 4) | |
1519 | (if_then_else | |
1520 | (and (ge (minus (match_dup 5) (pc)) (const_int -2040)) | |
1521 | (le (minus (match_dup 5) (pc)) (const_int 2048))) | |
1522 | (const_int 6) | |
1523 | (const_int 8))) | |
1524 | (if_then_else | |
1525 | (and (ge (minus (match_dup 5) (pc)) (const_int -248)) | |
1526 | (le (minus (match_dup 5) (pc)) (const_int 256))) | |
1527 | (const_int 6) | |
1528 | (if_then_else | |
1529 | (and (ge (minus (match_dup 5) (pc)) (const_int -2038)) | |
1530 | (le (minus (match_dup 5) (pc)) (const_int 2048))) | |
1531 | (const_int 8) | |
1532 | (const_int 10))))) | |
1533 | (set_attr "type" "multiple")] | |
1534 | ) | |
1535 | ||
1536 | (define_insn "*addsi3_cbranch_scratch" | |
1537 | [(set (pc) | |
1538 | (if_then_else | |
1539 | (match_operator 3 "arm_comparison_operator" | |
1540 | [(plus:SI | |
1541 | (match_operand:SI 1 "s_register_operand" "%l,l,l,0") | |
1542 | (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ")) | |
1543 | (const_int 0)]) | |
1544 | (label_ref (match_operand 4 "" "")) | |
1545 | (pc))) | |
1546 | (clobber (match_scratch:SI 0 "=X,X,l,l"))] | |
1547 | "TARGET_THUMB1 | |
1548 | && (GET_CODE (operands[3]) == EQ | |
1549 | || GET_CODE (operands[3]) == NE | |
1550 | || GET_CODE (operands[3]) == GE | |
1551 | || GET_CODE (operands[3]) == LT)" | |
1552 | "* | |
1553 | { | |
1554 | switch (which_alternative) | |
1555 | { | |
1556 | case 0: | |
1557 | output_asm_insn (\"cmp\t%1, #%n2\", operands); | |
1558 | break; | |
1559 | case 1: | |
1560 | output_asm_insn (\"cmn\t%1, %2\", operands); | |
1561 | break; | |
1562 | case 2: | |
1563 | if (INTVAL (operands[2]) < 0) | |
7e3c779e | 1564 | output_asm_insn (\"subs\t%0, %1, %2\", operands); |
bc360af8 | 1565 | else |
aa433824 | 1566 | output_asm_insn (\"adds\t%0, %1, %2\", operands); |
bc360af8 | 1567 | break; |
1568 | case 3: | |
1569 | if (INTVAL (operands[2]) < 0) | |
7e3c779e | 1570 | output_asm_insn (\"subs\t%0, %0, %2\", operands); |
bc360af8 | 1571 | else |
aa433824 | 1572 | output_asm_insn (\"adds\t%0, %0, %2\", operands); |
bc360af8 | 1573 | break; |
1574 | } | |
1575 | ||
1576 | switch (get_attr_length (insn)) | |
1577 | { | |
1578 | case 4: | |
1579 | return \"b%d3\\t%l4\"; | |
1580 | case 6: | |
1581 | return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\"; | |
1582 | default: | |
1583 | return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\"; | |
1584 | } | |
1585 | } | |
1586 | " | |
1587 | [(set (attr "far_jump") | |
1588 | (if_then_else | |
1589 | (eq_attr "length" "8") | |
1590 | (const_string "yes") | |
1591 | (const_string "no"))) | |
1592 | (set (attr "length") | |
1593 | (if_then_else | |
1594 | (and (ge (minus (match_dup 4) (pc)) (const_int -250)) | |
1595 | (le (minus (match_dup 4) (pc)) (const_int 256))) | |
1596 | (const_int 4) | |
1597 | (if_then_else | |
1598 | (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) | |
1599 | (le (minus (match_dup 4) (pc)) (const_int 2048))) | |
1600 | (const_int 6) | |
1601 | (const_int 8)))) | |
1602 | (set_attr "type" "multiple")] | |
1603 | ) | |
1604 | ||
1605 | (define_insn "*thumb_cmpdi_zero" | |
1606 | [(set (reg:CC_Z CC_REGNUM) | |
1607 | (compare:CC_Z (match_operand:DI 0 "s_register_operand" "l") | |
1608 | (const_int 0))) | |
1609 | (clobber (match_scratch:SI 1 "=l"))] | |
1610 | "TARGET_THUMB1" | |
7e3c779e | 1611 | "orrs\\t%1, %Q0, %R0" |
bc360af8 | 1612 | [(set_attr "conds" "set") |
1613 | (set_attr "length" "2") | |
1614 | (set_attr "type" "logics_reg")] | |
1615 | ) | |
1616 | ||
1617 | (define_expand "cstoresi_eq0_thumb1" | |
1618 | [(parallel | |
1619 | [(set (match_operand:SI 0 "s_register_operand" "") | |
1620 | (eq:SI (match_operand:SI 1 "s_register_operand" "") | |
1621 | (const_int 0))) | |
1622 | (clobber (match_dup:SI 2))])] | |
1623 | "TARGET_THUMB1" | |
1624 | "operands[2] = gen_reg_rtx (SImode);" | |
1625 | ) | |
1626 | ||
1627 | (define_expand "cstoresi_ne0_thumb1" | |
1628 | [(parallel | |
1629 | [(set (match_operand:SI 0 "s_register_operand" "") | |
1630 | (ne:SI (match_operand:SI 1 "s_register_operand" "") | |
1631 | (const_int 0))) | |
1632 | (clobber (match_dup:SI 2))])] | |
1633 | "TARGET_THUMB1" | |
1634 | "operands[2] = gen_reg_rtx (SImode);" | |
1635 | ) | |
1636 | ||
1637 | (define_insn "*cstoresi_eq0_thumb1_insn" | |
1638 | [(set (match_operand:SI 0 "s_register_operand" "=&l,l") | |
1639 | (eq:SI (match_operand:SI 1 "s_register_operand" "l,0") | |
1640 | (const_int 0))) | |
1641 | (clobber (match_operand:SI 2 "s_register_operand" "=X,l"))] | |
1642 | "TARGET_THUMB1" | |
1643 | "@ | |
7e3c779e | 1644 | rsbs\\t%0, %1, #0\;adcs\\t%0, %0, %1 |
1645 | rsbs\\t%2, %1, #0\;adcs\\t%0, %1, %2" | |
bc360af8 | 1646 | [(set_attr "length" "4") |
1647 | (set_attr "type" "multiple")] | |
1648 | ) | |
1649 | ||
1650 | (define_insn "*cstoresi_ne0_thumb1_insn" | |
1651 | [(set (match_operand:SI 0 "s_register_operand" "=l") | |
1652 | (ne:SI (match_operand:SI 1 "s_register_operand" "0") | |
1653 | (const_int 0))) | |
1654 | (clobber (match_operand:SI 2 "s_register_operand" "=l"))] | |
1655 | "TARGET_THUMB1" | |
7e3c779e | 1656 | "subs\\t%2, %1, #1\;sbcs\\t%0, %1, %2" |
bc360af8 | 1657 | [(set_attr "length" "4")] |
1658 | ) | |
1659 | ||
1660 | ;; Used as part of the expansion of thumb ltu and gtu sequences | |
1661 | (define_insn "cstoresi_nltu_thumb1" | |
1662 | [(set (match_operand:SI 0 "s_register_operand" "=l,l") | |
1663 | (neg:SI (ltu:SI (match_operand:SI 1 "s_register_operand" "l,*h") | |
1664 | (match_operand:SI 2 "thumb1_cmp_operand" "lI*h,*r"))))] | |
1665 | "TARGET_THUMB1" | |
7e3c779e | 1666 | "cmp\\t%1, %2\;sbcs\\t%0, %0, %0" |
bc360af8 | 1667 | [(set_attr "length" "4") |
1668 | (set_attr "type" "multiple")] | |
1669 | ) | |
1670 | ||
1671 | (define_insn_and_split "cstoresi_ltu_thumb1" | |
1672 | [(set (match_operand:SI 0 "s_register_operand" "=l,l") | |
1673 | (ltu:SI (match_operand:SI 1 "s_register_operand" "l,*h") | |
1674 | (match_operand:SI 2 "thumb1_cmp_operand" "lI*h,*r")))] | |
1675 | "TARGET_THUMB1" | |
1676 | "#" | |
1677 | "TARGET_THUMB1" | |
1678 | [(set (match_dup 3) | |
1679 | (neg:SI (ltu:SI (match_dup 1) (match_dup 2)))) | |
1680 | (set (match_dup 0) (neg:SI (match_dup 3)))] | |
1681 | "operands[3] = gen_reg_rtx (SImode);" | |
1682 | [(set_attr "length" "4") | |
1683 | (set_attr "type" "multiple")] | |
1684 | ) | |
1685 | ||
1686 | ;; Used as part of the expansion of thumb les sequence. | |
1687 | (define_insn "thumb1_addsi3_addgeu" | |
1688 | [(set (match_operand:SI 0 "s_register_operand" "=l") | |
1689 | (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0") | |
1690 | (match_operand:SI 2 "s_register_operand" "l")) | |
1691 | (geu:SI (match_operand:SI 3 "s_register_operand" "l") | |
1692 | (match_operand:SI 4 "thumb1_cmp_operand" "lI"))))] | |
1693 | "TARGET_THUMB1" | |
7e3c779e | 1694 | "cmp\\t%3, %4\;adcs\\t%0, %1, %2" |
bc360af8 | 1695 | [(set_attr "length" "4") |
1696 | (set_attr "type" "multiple")] | |
1697 | ) | |
1698 | ||
1699 | \f | |
1700 | (define_insn "*thumb_jump" | |
1701 | [(set (pc) | |
1702 | (label_ref (match_operand 0 "" "")))] | |
1703 | "TARGET_THUMB1" | |
1704 | "* | |
1705 | if (get_attr_length (insn) == 2) | |
1706 | return \"b\\t%l0\"; | |
1707 | return \"bl\\t%l0\\t%@ far jump\"; | |
1708 | " | |
1709 | [(set (attr "far_jump") | |
1710 | (if_then_else | |
1711 | (eq_attr "length" "4") | |
1712 | (const_string "yes") | |
1713 | (const_string "no"))) | |
1714 | (set (attr "length") | |
1715 | (if_then_else | |
1716 | (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) | |
1717 | (le (minus (match_dup 0) (pc)) (const_int 2048))) | |
1718 | (const_int 2) | |
1719 | (const_int 4))) | |
1720 | (set_attr "type" "branch")] | |
1721 | ) | |
1722 | ||
1723 | (define_insn "*call_reg_thumb1_v5" | |
1724 | [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) | |
1725 | (match_operand 1 "" "")) | |
1726 | (use (match_operand 2 "" "")) | |
1727 | (clobber (reg:SI LR_REGNUM))] | |
b232e6b5 | 1728 | "TARGET_THUMB1 && arm_arch5t && !SIBLING_CALL_P (insn)" |
bc360af8 | 1729 | "blx\\t%0" |
1730 | [(set_attr "length" "2") | |
1731 | (set_attr "type" "call")] | |
1732 | ) | |
1733 | ||
2d3a01a7 | 1734 | (define_insn "*nonsecure_call_reg_thumb1_v5" |
e27c5a70 | 1735 | [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] |
2d3a01a7 | 1736 | UNSPEC_NONSECURE_MEM) |
e27c5a70 | 1737 | (match_operand 0 "" "")) |
1738 | (use (match_operand 1 "" "")) | |
1739 | (clobber (reg:SI LR_REGNUM))] | |
2d3a01a7 | 1740 | "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)" |
1741 | "bl\\t__gnu_cmse_nonsecure_call" | |
1742 | [(set_attr "length" "4") | |
1743 | (set_attr "type" "call")] | |
1744 | ) | |
1745 | ||
bc360af8 | 1746 | (define_insn "*call_reg_thumb1" |
1747 | [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) | |
1748 | (match_operand 1 "" "")) | |
1749 | (use (match_operand 2 "" "")) | |
1750 | (clobber (reg:SI LR_REGNUM))] | |
b232e6b5 | 1751 | "TARGET_THUMB1 && !arm_arch5t && !SIBLING_CALL_P (insn)" |
bc360af8 | 1752 | "* |
1753 | { | |
1754 | if (!TARGET_CALLER_INTERWORKING) | |
1755 | return thumb_call_via_reg (operands[0]); | |
1756 | else if (operands[1] == const0_rtx) | |
1757 | return \"bl\\t%__interwork_call_via_%0\"; | |
1758 | else if (frame_pointer_needed) | |
1759 | return \"bl\\t%__interwork_r7_call_via_%0\"; | |
1760 | else | |
1761 | return \"bl\\t%__interwork_r11_call_via_%0\"; | |
1762 | }" | |
1763 | [(set_attr "type" "call")] | |
1764 | ) | |
1765 | ||
1766 | (define_insn "*call_value_reg_thumb1_v5" | |
1767 | [(set (match_operand 0 "" "") | |
1768 | (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) | |
1769 | (match_operand 2 "" ""))) | |
1770 | (use (match_operand 3 "" "")) | |
1771 | (clobber (reg:SI LR_REGNUM))] | |
b232e6b5 | 1772 | "TARGET_THUMB1 && arm_arch5t" |
bc360af8 | 1773 | "blx\\t%1" |
1774 | [(set_attr "length" "2") | |
1775 | (set_attr "type" "call")] | |
1776 | ) | |
1777 | ||
2d3a01a7 | 1778 | (define_insn "*nonsecure_call_value_reg_thumb1_v5" |
1779 | [(set (match_operand 0 "" "") | |
1780 | (call (unspec:SI | |
e27c5a70 | 1781 | [(mem:SI (reg:SI R4_REGNUM))] |
2d3a01a7 | 1782 | UNSPEC_NONSECURE_MEM) |
e27c5a70 | 1783 | (match_operand 1 "" ""))) |
1784 | (use (match_operand 2 "" "")) | |
1785 | (clobber (reg:SI LR_REGNUM))] | |
2d3a01a7 | 1786 | "TARGET_THUMB1 && use_cmse" |
1787 | "bl\\t__gnu_cmse_nonsecure_call" | |
1788 | [(set_attr "length" "4") | |
1789 | (set_attr "type" "call")] | |
1790 | ) | |
1791 | ||
bc360af8 | 1792 | (define_insn "*call_value_reg_thumb1" |
1793 | [(set (match_operand 0 "" "") | |
1794 | (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) | |
1795 | (match_operand 2 "" ""))) | |
1796 | (use (match_operand 3 "" "")) | |
1797 | (clobber (reg:SI LR_REGNUM))] | |
b232e6b5 | 1798 | "TARGET_THUMB1 && !arm_arch5t" |
bc360af8 | 1799 | "* |
1800 | { | |
1801 | if (!TARGET_CALLER_INTERWORKING) | |
1802 | return thumb_call_via_reg (operands[1]); | |
1803 | else if (operands[2] == const0_rtx) | |
1804 | return \"bl\\t%__interwork_call_via_%1\"; | |
1805 | else if (frame_pointer_needed) | |
1806 | return \"bl\\t%__interwork_r7_call_via_%1\"; | |
1807 | else | |
1808 | return \"bl\\t%__interwork_r11_call_via_%1\"; | |
1809 | }" | |
1810 | [(set_attr "type" "call")] | |
1811 | ) | |
1812 | ||
1813 | (define_insn "*call_insn" | |
1814 | [(call (mem:SI (match_operand:SI 0 "" "")) | |
1815 | (match_operand:SI 1 "" "")) | |
1816 | (use (match_operand 2 "" "")) | |
1817 | (clobber (reg:SI LR_REGNUM))] | |
1818 | "TARGET_THUMB1 | |
1819 | && GET_CODE (operands[0]) == SYMBOL_REF | |
1820 | && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))" | |
1821 | "bl\\t%a0" | |
1822 | [(set_attr "length" "4") | |
1823 | (set_attr "type" "call")] | |
1824 | ) | |
1825 | ||
1826 | (define_insn "*call_value_insn" | |
1827 | [(set (match_operand 0 "" "") | |
1828 | (call (mem:SI (match_operand 1 "" "")) | |
1829 | (match_operand 2 "" ""))) | |
1830 | (use (match_operand 3 "" "")) | |
1831 | (clobber (reg:SI LR_REGNUM))] | |
1832 | "TARGET_THUMB1 | |
1833 | && GET_CODE (operands[1]) == SYMBOL_REF | |
1834 | && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))" | |
1835 | "bl\\t%a1" | |
1836 | [(set_attr "length" "4") | |
1837 | (set_attr "type" "call")] | |
1838 | ) | |
1839 | ||
1840 | (define_expand "thumb1_casesi_internal_pic" | |
1841 | [(match_operand:SI 0 "s_register_operand" "") | |
1842 | (match_operand:SI 1 "thumb1_cmp_operand" "") | |
1843 | (match_operand 2 "" "") | |
1844 | (match_operand 3 "" "")] | |
1845 | "TARGET_THUMB1" | |
1846 | { | |
1847 | rtx reg0; | |
1848 | rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[1]); | |
1849 | emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[1], | |
1850 | operands[3])); | |
1851 | reg0 = gen_rtx_REG (SImode, 0); | |
1852 | emit_move_insn (reg0, operands[0]); | |
1853 | emit_jump_insn (gen_thumb1_casesi_dispatch (operands[2]/*, operands[3]*/)); | |
1854 | DONE; | |
1855 | } | |
1856 | ) | |
1857 | ||
1858 | (define_insn "thumb1_casesi_dispatch" | |
1859 | [(parallel [(set (pc) (unspec [(reg:SI 0) | |
1860 | (label_ref (match_operand 0 "" "")) | |
1861 | ;; (label_ref (match_operand 1 "" "")) | |
1862 | ] | |
1863 | UNSPEC_THUMB1_CASESI)) | |
1864 | (clobber (reg:SI IP_REGNUM)) | |
1865 | (clobber (reg:SI LR_REGNUM))])] | |
1866 | "TARGET_THUMB1" | |
1867 | "* return thumb1_output_casesi(operands);" | |
1868 | [(set_attr "length" "4") | |
1869 | (set_attr "type" "multiple")] | |
1870 | ) | |
1871 | ||
1872 | ;; NB Never uses BX. | |
1873 | (define_insn "*thumb1_indirect_jump" | |
1874 | [(set (pc) | |
1875 | (match_operand:SI 0 "register_operand" "l*r"))] | |
1876 | "TARGET_THUMB1" | |
1877 | "mov\\tpc, %0" | |
1878 | [(set_attr "conds" "clob") | |
1879 | (set_attr "length" "2") | |
1880 | (set_attr "type" "branch")] | |
1881 | ) | |
1882 | ||
1883 | \f | |
1884 | (define_insn "prologue_thumb1_interwork" | |
1885 | [(unspec_volatile [(const_int 0)] VUNSPEC_THUMB1_INTERWORK)] | |
1886 | "TARGET_THUMB1" | |
1887 | "* return thumb1_output_interwork ();" | |
1888 | [(set_attr "length" "8") | |
1889 | (set_attr "type" "multiple")] | |
1890 | ) | |
1891 | ||
1892 | (define_insn "*epilogue_insns" | |
1893 | [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)] | |
1894 | "TARGET_THUMB1" | |
1895 | "* | |
1896 | return thumb1_unexpanded_epilogue (); | |
1897 | " | |
4d44b674 | 1898 | ; Length is absolute worst case, when using CMSE and if this is an entry |
1899 | ; function an extra 4 (MSR) bytes will be added. | |
1900 | [(set (attr "length") | |
1901 | (if_then_else | |
1902 | (match_test "IS_CMSE_ENTRY (arm_current_func_type ())") | |
1903 | (const_int 48) | |
1904 | (const_int 44))) | |
bc360af8 | 1905 | (set_attr "type" "block") |
1906 | ;; We don't clobber the conditions, but the potential length of this | |
1907 | ;; operation is sufficient to make conditionalizing the sequence | |
1908 | ;; unlikely to be profitable. | |
1909 | (set_attr "conds" "clob")] | |
1910 | ) | |
1911 | ||
bc360af8 | 1912 | ;; Miscellaneous Thumb patterns |
1913 | (define_expand "tablejump" | |
1914 | [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "")) | |
1915 | (use (label_ref (match_operand 1 "" "")))])] | |
1916 | "TARGET_THUMB1" | |
1917 | " | |
1918 | if (flag_pic) | |
1919 | { | |
1920 | /* Hopefully, CSE will eliminate this copy. */ | |
1921 | rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1])); | |
1922 | rtx reg2 = gen_reg_rtx (SImode); | |
1923 | ||
1924 | emit_insn (gen_addsi3 (reg2, operands[0], reg1)); | |
1925 | operands[0] = reg2; | |
1926 | } | |
1927 | " | |
1928 | ) | |
1929 | ||
56640707 | 1930 | (define_insn "*thumb1_movpc_insn" |
1931 | [(set (match_operand:SI 0 "s_register_operand" "=l") | |
1932 | (reg:SI PC_REGNUM))] | |
1933 | "TARGET_THUMB1" | |
1934 | "mov\\t%0, pc" | |
1935 | [(set_attr "length" "2") | |
1936 | (set_attr "conds" "nocond") | |
1937 | (set_attr "type" "mov_reg")] | |
1938 | ) | |
1939 | ||
bc360af8 | 1940 | ;; NB never uses BX. |
1941 | (define_insn "*thumb1_tablejump" | |
1942 | [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) | |
1943 | (use (label_ref (match_operand 1 "" "")))] | |
1944 | "TARGET_THUMB1" | |
1945 | "mov\\t%|pc, %0" | |
1946 | [(set_attr "length" "2") | |
1947 | (set_attr "type" "no_insn")] | |
1948 | ) | |
1949 | ||
1950 | (define_insn_and_split "thumb_eh_return" | |
1951 | [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")] | |
1952 | VUNSPEC_EH_RETURN) | |
1953 | (clobber (match_scratch:SI 1 "=&l"))] | |
1954 | "TARGET_THUMB1" | |
1955 | "#" | |
1956 | "&& reload_completed" | |
1957 | [(const_int 0)] | |
1958 | " | |
1959 | { | |
1960 | thumb_set_return_address (operands[0], operands[1]); | |
1961 | DONE; | |
1962 | }" | |
1963 | [(set_attr "type" "mov_reg")] | |
1964 | ) | |
f98495d9 | 1965 | |
1966 | (define_insn "thumb1_stack_protect_test_insn" | |
1967 | [(set (match_operand:SI 0 "register_operand" "=&l") | |
1968 | (unspec:SI [(match_operand:SI 1 "memory_operand" "m") | |
1969 | (mem:SI (match_operand:SI 2 "register_operand" "+l"))] | |
1970 | UNSPEC_SP_TEST)) | |
1971 | (clobber (match_dup 2))] | |
1972 | "TARGET_THUMB1" | |
1973 | "ldr\t%0, [%2]\;ldr\t%2, %1\;eors\t%0, %2, %0" | |
1974 | [(set_attr "length" "8") | |
1975 | (set_attr "conds" "set") | |
1976 | (set_attr "type" "multiple")] | |
1977 | ) | |
bc360af8 | 1978 | \f |