1 ;; ARM Thumb-2 Machine Description
2 ;; Copyright (C) 2007-2025 Free Software Foundation, Inc.
3 ;; Written by CodeSourcery, LLC.
5 ;; This file is part of GCC.
7 ;; GCC is free software; you can redistribute it and/or modify it
8 ;; under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; GCC is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3. If not see
19 ;; <http://www.gnu.org/licenses/>. */
21 ;; Note: Thumb-2 is the variant of the Thumb architecture that adds
22 ;; 32-bit encodings of [almost all of] the Arm instruction set.
23 ;; Some old documents refer to the relatively minor interworking
24 ;; changes made in armv5t as "thumb2". These are considered part
25 ;; the 16-bit Thumb-1 instruction set.
27 ;; We use the '0' constraint for operand 1 because reload should
28 ;; be smart enough to generate an appropriate move for the r/r/r case.
29 (define_insn_and_split "*thumb2_smaxsi3"
30 [(set (match_operand:SI 0 "s_register_operand" "=r,l,r")
31 (smax:SI (match_operand:SI 1 "s_register_operand" "%0,0,0")
32 (match_operand:SI 2 "arm_rhs_operand" "r,Py,I")))
33 (clobber (reg:CC CC_REGNUM))]
36 ; cmp\\t%1, %2\;it\\tlt\;movlt\\t%0, %2
37 "TARGET_THUMB2 && reload_completed"
38 [(set (reg:CC CC_REGNUM)
39 (compare:CC (match_dup 1) (match_dup 2)))
40 (cond_exec (lt:SI (reg:CC CC_REGNUM) (const_int 0))
44 [(set_attr "conds" "clob")
45 (set_attr "enabled_for_short_it" "yes,yes,no")
46 (set_attr "length" "6,6,10")
47 (set_attr "type" "multiple")]
50 (define_insn_and_split "*thumb2_sminsi3"
51 [(set (match_operand:SI 0 "s_register_operand" "=r,l,r")
52 (smin:SI (match_operand:SI 1 "s_register_operand" "%0,0,0")
53 (match_operand:SI 2 "arm_rhs_operand" "r,Py,I")))
54 (clobber (reg:CC CC_REGNUM))]
57 ; cmp\\t%1, %2\;it\\tge\;movge\\t%0, %2
58 "TARGET_THUMB2 && reload_completed"
59 [(set (reg:CC CC_REGNUM)
60 (compare:CC (match_dup 1) (match_dup 2)))
61 (cond_exec (ge:SI (reg:CC CC_REGNUM) (const_int 0))
65 [(set_attr "conds" "clob")
66 (set_attr "enabled_for_short_it" "yes,yes,no")
67 (set_attr "length" "6,6,10")
68 (set_attr "type" "multiple")]
71 (define_insn_and_split "*thumb32_umaxsi3"
72 [(set (match_operand:SI 0 "s_register_operand" "=r,l,r")
73 (umax:SI (match_operand:SI 1 "s_register_operand" "%0,0,0")
74 (match_operand:SI 2 "arm_rhs_operand" "r,Py,I")))
75 (clobber (reg:CC CC_REGNUM))]
78 ; cmp\\t%1, %2\;it\\tcc\;movcc\\t%0, %2
79 "TARGET_THUMB2 && reload_completed"
80 [(set (reg:CC CC_REGNUM)
81 (compare:CC (match_dup 1) (match_dup 2)))
82 (cond_exec (ltu:SI (reg:CC CC_REGNUM) (const_int 0))
86 [(set_attr "conds" "clob")
87 (set_attr "length" "6,6,10")
88 (set_attr "enabled_for_short_it" "yes,yes,no")
89 (set_attr "type" "multiple")]
92 (define_insn_and_split "*thumb2_uminsi3"
93 [(set (match_operand:SI 0 "s_register_operand" "=r,l,r")
94 (umin:SI (match_operand:SI 1 "s_register_operand" "%0,0,0")
95 (match_operand:SI 2 "arm_rhs_operand" "r,Py,I")))
96 (clobber (reg:CC CC_REGNUM))]
99 ; cmp\\t%1, %2\;it\\tcs\;movcs\\t%0, %2
100 "TARGET_THUMB2 && reload_completed"
101 [(set (reg:CC CC_REGNUM)
102 (compare:CC (match_dup 1) (match_dup 2)))
103 (cond_exec (geu:SI (reg:CC CC_REGNUM) (const_int 0))
107 [(set_attr "conds" "clob")
108 (set_attr "length" "6,6,10")
109 (set_attr "enabled_for_short_it" "yes,yes,no")
110 (set_attr "type" "multiple")]
113 (define_insn_and_split "*thumb2_abssi2"
114 [(set (match_operand:SI 0 "s_register_operand" "=&r,l,r")
115 (abs:SI (match_operand:SI 1 "s_register_operand" "r,0,0")))
116 (clobber (reg:CC CC_REGNUM))]
119 ; eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31
120 ; cmp\\t%0, #0\;it\tlt\;rsblt\\t%0, %0, #0
121 ; cmp\\t%0, #0\;it\tlt\;rsblt\\t%0, %0, #0
122 "&& reload_completed"
125 if (REGNO(operands[0]) == REGNO(operands[1]))
127 rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
129 emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (CCmode, operands[0],
131 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
135 (gen_rtx_SET (operands[0],
136 (gen_rtx_MINUS (SImode,
142 emit_insn (gen_rtx_SET (operands[0],
144 gen_rtx_ASHIFTRT (SImode,
148 emit_insn (gen_rtx_SET (operands[0],
149 gen_rtx_MINUS (SImode,
151 gen_rtx_ASHIFTRT (SImode,
157 [(set_attr "conds" "*,clob,clob")
158 (set_attr "shift" "1")
159 (set_attr "predicable" "yes,no,no")
160 (set_attr "enabled_for_short_it" "yes,yes,no")
161 (set_attr "ce_count" "2")
162 (set_attr "length" "8,6,10")
163 (set_attr "type" "multiple")]
166 (define_insn_and_split "*thumb2_neg_abssi2"
167 [(set (match_operand:SI 0 "s_register_operand" "=&r,l,r")
168 (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "r,0,0"))))
169 (clobber (reg:CC CC_REGNUM))]
172 ; eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31
173 ; cmp\\t%0, #0\;it\\tgt\;rsbgt\\t%0, %0, #0
174 ; cmp\\t%0, #0\;it\\tgt\;rsbgt\\t%0, %0, #0
175 "&& reload_completed"
178 if (REGNO(operands[0]) == REGNO(operands[1]))
180 rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
182 emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (CCmode, operands[0],
184 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
188 (gen_rtx_SET (operands[0],
189 (gen_rtx_MINUS (SImode,
195 emit_insn (gen_rtx_SET (operands[0],
197 gen_rtx_ASHIFTRT (SImode,
201 emit_insn (gen_rtx_SET (operands[0],
202 gen_rtx_MINUS (SImode,
203 gen_rtx_ASHIFTRT (SImode,
210 [(set_attr "conds" "*,clob,clob")
211 (set_attr "shift" "1")
212 (set_attr "predicable" "yes,no,no")
213 (set_attr "enabled_for_short_it" "yes,yes,no")
214 (set_attr "ce_count" "2")
215 (set_attr "length" "8,6,10")
216 (set_attr "type" "multiple")]
219 ;; Pop a single register as its size is preferred over a post-incremental load
220 (define_insn "*thumb2_pop_single"
221 [(set (match_operand:SI 0 "low_register_operand" "=r")
222 (mem:SI (post_inc:SI (reg:SI SP_REGNUM))))]
223 "TARGET_THUMB2 && (reload_in_progress || reload_completed)"
225 [(set_attr "type" "load_4")
226 (set_attr "length" "2")
227 (set_attr "predicable" "yes")]
230 ;; We have two alternatives here for memory loads (and similarly for stores)
231 ;; to reflect the fact that the permissible constant pool ranges differ
232 ;; between ldr instructions taking low regs and ldr instructions taking high
233 ;; regs. The high register alternatives are not taken into account when
234 ;; choosing register preferences in order to reflect their expense.
235 (define_insn "*thumb2_movsi_insn"
236 [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,l,r,r,lk*r,m")
237 (match_operand:SI 1 "general_operand" "rk,I,Py,K,j,mi,lk*r"))]
238 "TARGET_THUMB2 && !TARGET_IWMMXT && !TARGET_HARD_FLOAT
239 && ( register_operand (operands[0], SImode)
240 || register_operand (operands[1], SImode))"
242 switch (which_alternative)
247 return \"mov%?\\t%0, %1\";
248 case 3: return \"mvn%?\\t%0, #%B1\";
249 case 4: return \"movw%?\\t%0, %1\";
251 /* Cannot load it directly, split to load it via MOV / MOVT. */
252 if (!MEM_P (operands[1]) && arm_disable_literal_pool)
254 return \"ldr%?\\t%0, %1\";
255 case 6: return \"str%?\\t%1, %0\";
256 default: gcc_unreachable ();
259 [(set_attr "type" "mov_reg,mov_imm,mov_imm,mvn_imm,mov_imm,load_4,store_4")
260 (set_attr "length" "2,4,2,4,4,4,4")
261 (set_attr "predicable" "yes")
262 (set_attr "predicable_short_it" "yes,no,yes,no,no,no,no")
263 (set_attr "pool_range" "*,*,*,*,*,1018,*")
264 (set_attr "neg_pool_range" "*,*,*,*,*,0,*")]
267 (define_insn "tls_load_dot_plus_four"
268 [(set (match_operand:SI 0 "register_operand" "=l,l,r,r")
269 (mem:SI (unspec:SI [(match_operand:SI 2 "register_operand" "0,1,0,1")
271 (match_operand 3 "" "")]
273 (clobber (match_scratch:SI 1 "=X,l,X,r"))]
276 (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
277 INTVAL (operands[3]));
278 return \"add\\t%2, %|pc\;ldr%?\\t%0, [%2]\";
280 [(set_attr "length" "4,4,6,6")
281 (set_attr "type" "multiple")]
284 ;; Thumb-2 always has load/store halfword instructions, so we can avoid a lot
285 ;; of the messiness associated with the ARM patterns.
286 (define_insn "*thumb2_movhi_insn"
287 [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,l,r,m,r")
288 (match_operand:HI 1 "general_operand" "rk,I,Py,n,r,m"))]
290 && (register_operand (operands[0], HImode)
291 || register_operand (operands[1], HImode))"
293 mov%?\\t%0, %1\\t%@ movhi
294 mov%?\\t%0, %1\\t%@ movhi
295 mov%?\\t%0, %1\\t%@ movhi
296 movw%?\\t%0, %L1\\t%@ movhi
297 strh%?\\t%1, %0\\t%@ movhi
298 ldrh%?\\t%0, %1\\t%@ movhi"
299 [(set_attr "type" "mov_reg,mov_imm,mov_imm,mov_imm,store_4,load_4")
300 (set_attr "predicable" "yes")
301 (set_attr "predicable_short_it" "yes,no,yes,no,no,no")
302 (set_attr "length" "2,4,2,4,4,4")
303 (set_attr "pool_range" "*,*,*,*,*,4094")
304 (set_attr "neg_pool_range" "*,*,*,*,*,250")]
307 (define_insn "*thumb2_storewb_pairsi"
308 [(set (match_operand:SI 0 "register_operand" "=&kr")
309 (plus:SI (match_operand:SI 1 "register_operand" "0")
310 (match_operand:SI 2 "const_int_operand" "n")))
311 (set (mem:SI (plus:SI (match_dup 0) (match_dup 2)))
312 (match_operand:SI 3 "register_operand" "r"))
313 (set (mem:SI (plus:SI (match_dup 0)
314 (match_operand:SI 5 "const_int_operand" "n")))
315 (match_operand:SI 4 "register_operand" "r"))]
317 && INTVAL (operands[5]) == INTVAL (operands[2]) + 4"
318 "strd\\t%3, %4, [%0, %2]!"
319 [(set_attr "type" "store_8")]
322 (define_insn_and_split "*thumb2_mov_scc"
323 [(set (match_operand:SI 0 "s_register_operand" "=l,r")
324 (match_operator:SI 1 "arm_comparison_operator_mode"
325 [(match_operand 2 "cc_register" "") (const_int 0)]))]
327 "#" ; "ite\\t%D1\;mov%D1\\t%0, #0\;mov%d1\\t%0, #1"
330 (if_then_else:SI (match_dup 1)
334 [(set_attr "conds" "use")
335 (set_attr "enabled_for_short_it" "yes,no")
336 (set_attr "length" "8,10")
337 (set_attr "type" "multiple")]
340 (define_insn_and_split "*thumb2_mov_negscc"
341 [(set (match_operand:SI 0 "s_register_operand" "=r")
342 (neg:SI (match_operator:SI 1 "arm_comparison_operator_mode"
343 [(match_operand 2 "cc_register" "") (const_int 0)])))]
346 && !arm_borrow_operation (operands[1], SImode)"
347 "#" ; "ite\\t%D1\;mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
350 (if_then_else:SI (match_dup 1)
354 operands[3] = GEN_INT (~0);
356 [(set_attr "conds" "use")
357 (set_attr "length" "10")
358 (set_attr "type" "multiple")]
361 (define_insn_and_split "*thumb2_mov_negscc_strict_it"
362 [(set (match_operand:SI 0 "low_register_operand" "=l")
363 (neg:SI (match_operator:SI 1 "arm_comparison_operator_mode"
364 [(match_operand 2 "cc_register" "") (const_int 0)])))]
367 && !arm_borrow_operation (operands[1], SImode)"
368 "#" ; ";mvn\\t%0, #0 ;it\\t%D1\;mov%D1\\t%0, #0\"
369 "&& reload_completed"
372 (cond_exec (match_dup 4)
376 operands[3] = GEN_INT (~0);
377 machine_mode mode = GET_MODE (operands[2]);
378 enum rtx_code rc = GET_CODE (operands[1]);
380 if (mode == CCFPmode || mode == CCFPEmode)
381 rc = reverse_condition_maybe_unordered (rc);
383 rc = reverse_condition (rc);
384 operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[2], const0_rtx);
387 [(set_attr "conds" "use")
388 (set_attr "length" "8")
389 (set_attr "type" "multiple")]
392 (define_insn_and_split "*thumb2_mov_notscc"
393 [(set (match_operand:SI 0 "s_register_operand" "=r")
394 (not:SI (match_operator:SI 1 "arm_comparison_operator_mode"
395 [(match_operand 2 "cc_register" "") (const_int 0)])))]
396 "TARGET_THUMB2 && !arm_restrict_it"
397 "#" ; "ite\\t%D1\;mvn%D1\\t%0, #0\;mvn%d1\\t%0, #1"
400 (if_then_else:SI (match_dup 1)
404 operands[3] = GEN_INT (~1);
405 operands[4] = GEN_INT (~0);
407 [(set_attr "conds" "use")
408 (set_attr "length" "10")
409 (set_attr "type" "multiple")]
412 (define_insn_and_split "*thumb2_mov_notscc_strict_it"
413 [(set (match_operand:SI 0 "low_register_operand" "=l")
414 (not:SI (match_operator:SI 1 "arm_comparison_operator_mode"
415 [(match_operand 2 "cc_register" "") (const_int 0)])))]
416 "TARGET_THUMB2 && arm_restrict_it"
417 "#" ; "mvn %0, #0 ; it%d1 ; lsl%d1 %0, %0, #1"
418 "&& reload_completed"
421 (cond_exec (match_dup 4)
423 (ashift:SI (match_dup 0)
426 operands[3] = GEN_INT (~0);
427 operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
428 VOIDmode, operands[2], const0_rtx);
430 [(set_attr "conds" "use")
431 (set_attr "length" "8")
432 (set_attr "type" "multiple")]
435 (define_insn_and_split "*thumb2_movsicc_insn"
436 [(set (match_operand:SI 0 "s_register_operand" "=l,l,r,r,r,r,r,r,r,r,r,r")
438 (match_operator 3 "arm_comparison_operator"
439 [(match_operand 4 "cc_register" "") (const_int 0)])
440 (match_operand:SI 1 "arm_not_operand" "0 ,lPy,0 ,0,rI,K,I ,r,rI,K ,K,r")
441 (match_operand:SI 2 "arm_not_operand" "lPy,0 ,rI,K,0 ,0,rI,I,K ,rI,K,r")))]
444 it\\t%D3\;mov%D3\\t%0, %2
445 it\\t%d3\;mov%d3\\t%0, %1
446 it\\t%D3\;mov%D3\\t%0, %2
447 it\\t%D3\;mvn%D3\\t%0, #%B2
448 it\\t%d3\;mov%d3\\t%0, %1
449 it\\t%d3\;mvn%d3\\t%0, #%B1
456 ; alt 6: ite\\t%d3\;mov%d3\\t%0, %1\;mov%D3\\t%0, %2
457 ; alt 7: ite\\t%d3\;mov%d3\\t%0, %1\;mov%D3\\t%0, %2
458 ; alt 8: ite\\t%d3\;mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2
459 ; alt 9: ite\\t%d3\;mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2
460 ; alt 10: ite\\t%d3\;mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2
461 ; alt 11: ite\\t%d3\;mov%d3\\t%0, %1\;mov%D3\\t%0, %2
462 "&& reload_completed"
465 enum rtx_code rev_code;
469 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
471 gen_rtx_SET (operands[0], operands[1])));
472 rev_code = GET_CODE (operands[3]);
473 mode = GET_MODE (operands[4]);
474 if (mode == CCFPmode || mode == CCFPEmode)
475 rev_code = reverse_condition_maybe_unordered (rev_code);
477 rev_code = reverse_condition (rev_code);
479 rev_cond = gen_rtx_fmt_ee (rev_code,
481 gen_rtx_REG (mode, CC_REGNUM),
483 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
485 gen_rtx_SET (operands[0], operands[2])));
488 [(set_attr "length" "4,4,6,6,6,6,10,8,10,10,10,6")
489 (set_attr "enabled_for_short_it" "yes,yes,no,no,no,no,no,no,no,no,no,yes")
490 (set_attr "conds" "use")
491 (set_attr_alternative "type"
492 [(if_then_else (match_operand 2 "const_int_operand" "")
493 (const_string "mov_imm")
494 (const_string "mov_reg"))
495 (if_then_else (match_operand 1 "const_int_operand" "")
496 (const_string "mov_imm")
497 (const_string "mov_reg"))
498 (if_then_else (match_operand 2 "const_int_operand" "")
499 (const_string "mov_imm")
500 (const_string "mov_reg"))
501 (const_string "mvn_imm")
502 (if_then_else (match_operand 1 "const_int_operand" "")
503 (const_string "mov_imm")
504 (const_string "mov_reg"))
505 (const_string "mvn_imm")
506 (const_string "multiple")
507 (const_string "multiple")
508 (const_string "multiple")
509 (const_string "multiple")
510 (const_string "multiple")
511 (const_string "multiple")])]
514 (define_insn "*thumb2_movsfcc_soft_insn"
515 [(set (match_operand:SF 0 "s_register_operand" "=r,r")
516 (if_then_else:SF (match_operator 3 "arm_comparison_operator"
517 [(match_operand 4 "cc_register" "") (const_int 0)])
518 (match_operand:SF 1 "s_register_operand" "0,r")
519 (match_operand:SF 2 "s_register_operand" "r,0")))]
520 "TARGET_THUMB2 && TARGET_SOFT_FLOAT && !TARGET_HAVE_MVE"
522 it\\t%D3\;mov%D3\\t%0, %2
523 it\\t%d3\;mov%d3\\t%0, %1"
524 [(set_attr "length" "6,6")
525 (set_attr "conds" "use")
526 (set_attr "type" "multiple")]
529 (define_insn "*call_reg_thumb2"
530 [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
531 (match_operand 1 "" ""))
532 (use (match_operand 2 "" ""))
533 (clobber (reg:SI LR_REGNUM))]
536 [(set_attr "type" "call")]
539 (define_insn "*nonsecure_call_reg_thumb2_fpcxt"
540 [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "l*r"))]
541 UNSPEC_NONSECURE_MEM)
542 (match_operand 1 "" ""))
543 (use (match_operand 2 "" ""))
544 (clobber (reg:SI LR_REGNUM))]
545 "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE"
547 [(set_attr "length" "4")
548 (set_attr "type" "call")]
551 (define_insn "*nonsecure_call_reg_thumb2"
552 [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
553 UNSPEC_NONSECURE_MEM)
554 (match_operand 0 "" ""))
555 (use (match_operand 1 "" ""))
556 (clobber (reg:SI LR_REGNUM))]
557 "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE"
558 "bl\\t__gnu_cmse_nonsecure_call"
559 [(set_attr "length" "4")
560 (set_attr "type" "call")]
563 (define_insn "*call_value_reg_thumb2"
564 [(set (match_operand 0 "" "")
565 (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
566 (match_operand 2 "" "")))
567 (use (match_operand 3 "" ""))
568 (clobber (reg:SI LR_REGNUM))]
571 [(set_attr "type" "call")]
574 (define_insn "*nonsecure_call_value_reg_thumb2_fpcxt"
575 [(set (match_operand 0 "" "")
577 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
578 UNSPEC_NONSECURE_MEM)
579 (match_operand 2 "" "")))
580 (use (match_operand 3 "" ""))
581 (clobber (reg:SI LR_REGNUM))]
582 "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE"
584 [(set_attr "length" "4")
585 (set_attr "type" "call")]
588 (define_insn "*nonsecure_call_value_reg_thumb2"
589 [(set (match_operand 0 "" "")
591 (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] UNSPEC_NONSECURE_MEM)
592 (match_operand 1 "" "")))
593 (use (match_operand 2 "" ""))
594 (clobber (reg:SI LR_REGNUM))]
595 "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE"
596 "bl\\t__gnu_cmse_nonsecure_call"
597 [(set_attr "length" "4")
598 (set_attr "type" "call")]
601 (define_insn "*thumb2_indirect_jump"
603 (match_operand:SI 0 "register_operand" "l*r"))]
606 [(set_attr "conds" "clob")
607 (set_attr "type" "branch")]
609 ;; Don't define thumb2_load_indirect_jump because we can't guarantee label
610 ;; addresses will have the thumb bit set correctly.
613 (define_insn_and_split "*thumb2_and_scc"
614 [(set (match_operand:SI 0 "s_register_operand" "=Ts")
615 (and:SI (match_operator:SI 1 "arm_comparison_operator"
616 [(match_operand 2 "cc_register" "") (const_int 0)])
617 (match_operand:SI 3 "s_register_operand" "r")))]
619 "#" ; "and\\t%0, %3, #1\;it\\t%D1\;mov%D1\\t%0, #0"
620 "&& reload_completed"
622 (and:SI (match_dup 3) (const_int 1)))
623 (cond_exec (match_dup 4) (set (match_dup 0) (const_int 0)))]
625 machine_mode mode = GET_MODE (operands[2]);
626 enum rtx_code rc = GET_CODE (operands[1]);
628 if (mode == CCFPmode || mode == CCFPEmode)
629 rc = reverse_condition_maybe_unordered (rc);
631 rc = reverse_condition (rc);
632 operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[2], const0_rtx);
634 [(set_attr "conds" "use")
635 (set_attr "type" "multiple")
636 (set (attr "length") (if_then_else (match_test "arm_restrict_it")
641 (define_insn_and_split "*thumb2_ior_scc"
642 [(set (match_operand:SI 0 "s_register_operand" "=r,r")
643 (ior:SI (match_operator:SI 1 "arm_comparison_operator"
644 [(match_operand 2 "cc_register" "") (const_int 0)])
645 (match_operand:SI 3 "s_register_operand" "0,?r")))]
646 "TARGET_THUMB2 && !arm_restrict_it"
648 it\\t%d1\;orr%d1\\t%0, %3, #1
650 ; alt 1: ite\\t%D1\;mov%D1\\t%0, %3\;orr%d1\\t%0, %3, #1
652 && REGNO (operands [0]) != REGNO (operands[3])"
653 [(cond_exec (match_dup 5) (set (match_dup 0) (match_dup 3)))
654 (cond_exec (match_dup 4) (set (match_dup 0)
655 (ior:SI (match_dup 3) (const_int 1))))]
657 machine_mode mode = GET_MODE (operands[2]);
658 enum rtx_code rc = GET_CODE (operands[1]);
660 operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[2], const0_rtx);
661 if (mode == CCFPmode || mode == CCFPEmode)
662 rc = reverse_condition_maybe_unordered (rc);
664 rc = reverse_condition (rc);
665 operands[5] = gen_rtx_fmt_ee (rc, VOIDmode, operands[2], const0_rtx);
667 [(set_attr "conds" "use")
668 (set_attr "length" "6,10")
669 (set_attr "type" "multiple")]
672 (define_insn_and_split "*thumb2_ior_scc_strict_it"
673 [(set (match_operand:SI 0 "s_register_operand" "=&r")
674 (ior:SI (match_operator:SI 2 "arm_comparison_operator"
675 [(match_operand 3 "cc_register" "") (const_int 0)])
676 (match_operand:SI 1 "s_register_operand" "r")))]
677 "TARGET_THUMB2 && arm_restrict_it"
678 "#" ; orr\\t%0, %1, #1\;it\\t%D2\;mov%D2\\t%0, %1
679 "&& reload_completed"
680 [(set (match_dup 0) (ior:SI (match_dup 1) (const_int 1)))
681 (cond_exec (match_dup 4)
682 (set (match_dup 0) (match_dup 1)))]
684 machine_mode mode = GET_MODE (operands[3]);
685 rtx_code rc = GET_CODE (operands[2]);
687 if (mode == CCFPmode || mode == CCFPEmode)
688 rc = reverse_condition_maybe_unordered (rc);
690 rc = reverse_condition (rc);
691 operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[3], const0_rtx);
693 [(set_attr "conds" "use")
694 (set_attr "length" "8")
695 (set_attr "type" "multiple")]
698 (define_insn "*thumb2_cond_move"
699 [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
700 (if_then_else:SI (match_operator 3 "equality_operator"
701 [(match_operator 4 "arm_comparison_operator"
702 [(match_operand 5 "cc_register" "") (const_int 0)])
704 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
705 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))]
708 if (GET_CODE (operands[3]) == NE)
710 if (which_alternative != 1)
711 output_asm_insn (\"it\\t%D4\;mov%D4\\t%0, %2\", operands);
712 if (which_alternative != 0)
713 output_asm_insn (\"it\\t%d4\;mov%d4\\t%0, %1\", operands);
716 switch (which_alternative)
719 output_asm_insn (\"it\\t%d4\", operands);
722 output_asm_insn (\"it\\t%D4\", operands);
726 output_asm_insn (\"it\\t%D4\", operands);
728 output_asm_insn (\"ite\\t%D4\", operands);
733 if (which_alternative != 0)
735 output_asm_insn (\"mov%D4\\t%0, %1\", operands);
736 if (arm_restrict_it && which_alternative == 2)
737 output_asm_insn (\"it\\t%d4\", operands);
739 if (which_alternative != 1)
740 output_asm_insn (\"mov%d4\\t%0, %2\", operands);
743 [(set_attr "conds" "use")
744 (set_attr "length" "6,6,10")
745 (set_attr "type" "multiple")]
748 (define_insn "*thumb2_cond_arith"
749 [(set (match_operand:SI 0 "s_register_operand" "=r,r")
750 (match_operator:SI 5 "shiftable_operator"
751 [(match_operator:SI 4 "arm_comparison_operator"
752 [(match_operand:SI 2 "s_register_operand" "r,r")
753 (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
754 (match_operand:SI 1 "s_register_operand" "0,?r")]))
755 (clobber (reg:CC CC_REGNUM))]
756 "TARGET_THUMB2 && !arm_restrict_it"
758 if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx)
759 return \"%i5\\t%0, %1, %2, lsr #31\";
761 output_asm_insn (\"cmp\\t%2, %3\", operands);
763 if (GET_CODE (operands[5]) == PLUS && TARGET_COND_ARITH)
764 return \"cinc\\t%0, %1, %d4\";
766 if (GET_CODE (operands[5]) == AND)
768 output_asm_insn (\"ite\\t%D4\", operands);
769 output_asm_insn (\"mov%D4\\t%0, #0\", operands);
771 else if (GET_CODE (operands[5]) == MINUS)
773 output_asm_insn (\"ite\\t%D4\", operands);
774 output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands);
776 else if (which_alternative != 0)
778 output_asm_insn (\"ite\\t%D4\", operands);
779 output_asm_insn (\"mov%D4\\t%0, %1\", operands);
782 output_asm_insn (\"it\\t%d4\", operands);
783 return \"%i5%d4\\t%0, %1, #1\";
785 [(set_attr "conds" "clob")
786 (set_attr "length" "14")
787 (set_attr "type" "multiple")]
790 (define_insn_and_split "*thumb2_cond_arith_strict_it"
791 [(set (match_operand:SI 0 "s_register_operand" "=l")
792 (match_operator:SI 5 "shiftable_operator_strict_it"
793 [(match_operator:SI 4 "arm_comparison_operator"
794 [(match_operand:SI 2 "s_register_operand" "r")
795 (match_operand:SI 3 "arm_rhs_operand" "rI")])
796 (match_operand:SI 1 "s_register_operand" "0")]))
797 (clobber (reg:CC CC_REGNUM))]
798 "TARGET_THUMB2 && arm_restrict_it"
800 "&& reload_completed"
803 if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx)
805 /* %i5 %0, %1, %2, lsr #31 */
806 rtx shifted_op = gen_rtx_LSHIFTRT (SImode, operands[2], GEN_INT (31));
809 switch (GET_CODE (operands[5]))
812 op = gen_rtx_AND (SImode, shifted_op, operands[1]);
815 op = gen_rtx_PLUS (SImode, shifted_op, operands[1]);
817 default: gcc_unreachable ();
819 emit_insn (gen_rtx_SET (operands[0], op));
824 emit_insn (gen_rtx_SET (gen_rtx_REG (CCmode, CC_REGNUM),
825 gen_rtx_COMPARE (CCmode, operands[2],
828 if (GET_CODE (operands[5]) == AND)
833 enum rtx_code rc = reverse_condition (GET_CODE (operands[4]));
834 emit_insn (gen_rtx_SET (operands[0], gen_rtx_AND (SImode, operands[1],
836 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
837 gen_rtx_fmt_ee (rc, VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx),
838 gen_rtx_SET (operands[0], const0_rtx)));
844 %i5%d4\\t%0, %1, #1 */
845 emit_insn (gen_rtx_COND_EXEC (VOIDmode, gen_rtx_fmt_ee (GET_CODE (operands[4]),
847 gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx),
848 gen_rtx_SET (operands[0],
849 gen_rtx_PLUS (SImode,
856 [(set_attr "conds" "clob")
857 (set_attr "length" "12")
858 (set_attr "type" "multiple")]
861 (define_insn "*thumb2_cond_sub"
862 [(set (match_operand:SI 0 "s_register_operand" "=Ts,Ts")
863 (minus:SI (match_operand:SI 1 "s_register_operand" "0,?Ts")
864 (match_operator:SI 4 "arm_comparison_operator"
865 [(match_operand:SI 2 "s_register_operand" "r,r")
866 (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
867 (clobber (reg:CC CC_REGNUM))]
870 output_asm_insn (\"cmp\\t%2, %3\", operands);
871 if (which_alternative != 0)
875 output_asm_insn (\"mov\\t%0, %1\", operands);
876 output_asm_insn (\"it\\t%d4\", operands);
880 output_asm_insn (\"ite\\t%D4\", operands);
881 output_asm_insn (\"mov%D4\\t%0, %1\", operands);
885 output_asm_insn (\"it\\t%d4\", operands);
886 return \"sub%d4\\t%0, %1, #1\";
888 [(set_attr "conds" "clob")
889 (set_attr "length" "10,14")
890 (set_attr "type" "multiple")]
893 (define_insn_and_split "*thumb2_negscc"
894 [(set (match_operand:SI 0 "s_register_operand" "=Ts")
895 (neg:SI (match_operator 3 "arm_comparison_operator"
896 [(match_operand:SI 1 "s_register_operand" "r")
897 (match_operand:SI 2 "arm_rhs_operand" "rI")])))
898 (clobber (reg:CC CC_REGNUM))]
899 "TARGET_THUMB2 && !TARGET_COND_ARITH"
901 "&& reload_completed"
904 rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
906 if (GET_CODE (operands[3]) == LT && operands[2] == const0_rtx)
908 /* Emit asr\\t%0, %1, #31 */
909 emit_insn (gen_rtx_SET (operands[0],
910 gen_rtx_ASHIFTRT (SImode,
915 else if (GET_CODE (operands[3]) == NE && !arm_restrict_it)
917 /* Emit subs\\t%0, %1, %2\;it\\tne\;mvnne\\t%0, #0 */
918 if (CONST_INT_P (operands[2]))
919 emit_insn (gen_cmpsi2_addneg (operands[0], operands[1], operands[2],
920 gen_int_mode (-INTVAL (operands[2]),
923 emit_insn (gen_subsi3_compare (operands[0], operands[1], operands[2]));
925 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
929 gen_rtx_SET (operands[0],
935 /* Emit: cmp\\t%1, %2\;mvn\\t%0, #0\;it\\t%D3\;mov%D3\\t%0, #0\;*/
936 enum rtx_code rc = reverse_condition (GET_CODE (operands[3]));
937 machine_mode mode = SELECT_CC_MODE (rc, operands[1], operands[2]);
938 rtx tmp1 = gen_rtx_REG (mode, CC_REGNUM);
940 emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (CCmode, operands[1],
943 emit_insn (gen_rtx_SET (operands[0], GEN_INT (~0)));
945 emit_insn (gen_rtx_COND_EXEC (VOIDmode,
950 gen_rtx_SET (operands[0], const0_rtx)));
955 [(set_attr "conds" "clob")
956 (set_attr "length" "14")
957 (set_attr "type" "multiple")]
960 (define_insn "*thumb2_csinv"
961 [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
963 (match_operand 1 "arm_comparison_operation" "")
964 (not:SI (match_operand:SI 2 "arm_general_register_operand" "r, r"))
965 (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
968 csinv\\t%0, %3, %2, %D1
969 csinv\\t%0, zr, %2, %D1"
970 [(set_attr "type" "csel")
971 (set_attr "predicable" "no")]
974 (define_insn "*thumb2_csinc"
975 [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
977 (match_operand 1 "arm_comparison_operation" "")
978 (plus:SI (match_operand:SI 2 "arm_general_register_operand" "r, r")
980 (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
983 csinc\\t%0, %3, %2, %D1
984 csinc\\t%0, zr, %2, %D1"
985 [(set_attr "type" "csel")
986 (set_attr "predicable" "no")]
989 (define_insn "*thumb2_csneg"
990 [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
992 (match_operand 1 "arm_comparison_operation" "")
993 (neg:SI (match_operand:SI 2 "arm_general_register_operand" "r, r"))
994 (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
997 csneg\\t%0, %3, %2, %D1
998 csneg\\t%0, zr, %2, %D1"
999 [(set_attr "type" "csel")
1000 (set_attr "predicable" "no")]
1003 (define_insn "*thumb2_movcond"
1004 [(set (match_operand:SI 0 "s_register_operand" "=Ts,Ts,Ts")
1006 (match_operator 5 "arm_comparison_operator"
1007 [(match_operand:SI 3 "s_register_operand" "r,r,r")
1008 (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")])
1009 (match_operand:SI 1 "arm_rhs_operand" "0,TsI,?TsI")
1010 (match_operand:SI 2 "arm_rhs_operand" "TsI,0,TsI")))
1011 (clobber (reg:CC CC_REGNUM))]
1012 "TARGET_THUMB2 && !TARGET_COND_ARITH"
1014 if (GET_CODE (operands[5]) == LT
1015 && (operands[4] == const0_rtx))
1017 if (which_alternative != 1 && REG_P (operands[1]))
1019 if (operands[2] == const0_rtx)
1020 return \"and\\t%0, %1, %3, asr #31\";
1021 return \"ands\\t%0, %1, %3, asr #32\;it\\tcc\;movcc\\t%0, %2\";
1023 else if (which_alternative != 0 && REG_P (operands[2]))
1025 if (operands[1] == const0_rtx)
1026 return \"bic\\t%0, %2, %3, asr #31\";
1027 return \"bics\\t%0, %2, %3, asr #32\;it\\tcs\;movcs\\t%0, %1\";
1029 /* The only case that falls through to here is when both ops 1 & 2
1033 if (GET_CODE (operands[5]) == GE
1034 && (operands[4] == const0_rtx))
1036 if (which_alternative != 1 && REG_P (operands[1]))
1038 if (operands[2] == const0_rtx)
1039 return \"bic\\t%0, %1, %3, asr #31\";
1040 return \"bics\\t%0, %1, %3, asr #32\;it\\tcs\;movcs\\t%0, %2\";
1042 else if (which_alternative != 0 && REG_P (operands[2]))
1044 if (operands[1] == const0_rtx)
1045 return \"and\\t%0, %2, %3, asr #31\";
1046 return \"ands\\t%0, %2, %3, asr #32\;it\tcc\;movcc\\t%0, %1\";
1048 /* The only case that falls through to here is when both ops 1 & 2
1051 if (CONST_INT_P (operands[4])
1052 && !const_ok_for_arm (INTVAL (operands[4])))
1053 output_asm_insn (\"cmn\\t%3, #%n4\", operands);
1055 output_asm_insn (\"cmp\\t%3, %4\", operands);
1056 switch (which_alternative)
1059 output_asm_insn (\"it\\t%D5\", operands);
1062 output_asm_insn (\"it\\t%d5\", operands);
1065 if (arm_restrict_it)
1067 output_asm_insn (\"mov\\t%0, %1\", operands);
1068 output_asm_insn (\"it\\t%D5\", operands);
1071 output_asm_insn (\"ite\\t%d5\", operands);
1076 if (which_alternative != 0 && !(arm_restrict_it && which_alternative == 2))
1077 output_asm_insn (\"mov%d5\\t%0, %1\", operands);
1078 if (which_alternative != 1)
1079 output_asm_insn (\"mov%D5\\t%0, %2\", operands);
1082 [(set_attr "conds" "clob")
1083 (set_attr "length" "10,10,14")
1084 (set_attr "type" "multiple")]
1087 ;; Zero and sign extension instructions.
1089 ;; All supported Thumb2 implementations are armv6, so only that case is
1091 (define_insn "*thumb2_extendqisi_v6"
1092 [(set (match_operand:SI 0 "s_register_operand" "=r,r")
1093 (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
1094 "TARGET_THUMB2 && arm_arch6"
1098 [(set_attr "type" "extend,load_byte")
1099 (set_attr "predicable" "yes")
1100 (set_attr "pool_range" "*,4094")
1101 (set_attr "neg_pool_range" "*,250")]
1104 (define_insn "*thumb2_zero_extendhisi2_v6"
1105 [(set (match_operand:SI 0 "s_register_operand" "=r,r")
1106 (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
1107 "TARGET_THUMB2 && arm_arch6"
1111 [(set_attr "type" "extend,load_byte")
1112 (set_attr "predicable" "yes")
1113 (set_attr "pool_range" "*,4094")
1114 (set_attr "neg_pool_range" "*,250")]
1117 (define_insn "thumb2_zero_extendqisi2_v6"
1118 [(set (match_operand:SI 0 "s_register_operand" "=r,r")
1119 (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
1120 "TARGET_THUMB2 && arm_arch6"
1123 ldrb%?\\t%0, %1\\t%@ zero_extendqisi2"
1124 [(set_attr "type" "extend,load_byte")
1125 (set_attr "predicable" "yes")
1126 (set_attr "pool_range" "*,4094")
1127 (set_attr "neg_pool_range" "*,250")]
1130 (define_expand "thumb2_casesi_internal"
1131 [(parallel [(set (pc)
1133 (leu (match_operand:SI 0 "s_register_operand")
1134 (match_operand:SI 1 "arm_rhs_operand"))
1136 (label_ref:SI (match_operand 3 ""))))
1137 (clobber (reg:CC CC_REGNUM))
1138 (clobber (match_scratch:SI 5))
1139 (use (label_ref:SI (match_operand 2 "")))])]
1140 "TARGET_THUMB2 && !flag_pic"
1142 operands[4] = gen_rtx_MULT (SImode, operands[0], GEN_INT (4));
1143 operands[4] = gen_rtx_PLUS (SImode, operands[4],
1144 gen_rtx_LABEL_REF (SImode, operands[2]));
1145 operands[4] = gen_rtx_MEM (SImode, operands[4]);
1146 MEM_READONLY_P (operands[4]) = 1;
1147 MEM_NOTRAP_P (operands[4]) = 1;
1150 (define_insn "*thumb2_casesi_internal"
1151 [(parallel [(set (pc)
1153 (leu (match_operand:SI 0 "s_register_operand" "r")
1154 (match_operand:SI 1 "arm_rhs_operand" "rI"))
1155 (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
1156 (label_ref:SI (match_operand 2 "" ""))))
1157 (label_ref:SI (match_operand 3 "" ""))))
1158 (clobber (reg:CC CC_REGNUM))
1159 (clobber (match_scratch:SI 4 "=&r"))
1160 (use (label_ref:SI (match_dup 2)))])]
1161 "TARGET_THUMB2 && !flag_pic"
1162 "* return thumb2_output_casesi(operands);"
1163 [(set_attr "conds" "clob")
1164 (set_attr "length" "16")
1165 (set_attr "type" "multiple")]
1168 (define_expand "thumb2_casesi_internal_pic"
1169 [(parallel [(set (pc)
1171 (leu (match_operand:SI 0 "s_register_operand")
1172 (match_operand:SI 1 "arm_rhs_operand"))
1174 (label_ref:SI (match_operand 3 ""))))
1175 (clobber (reg:CC CC_REGNUM))
1176 (clobber (match_scratch:SI 5))
1177 (clobber (match_scratch:SI 6))
1178 (use (label_ref:SI (match_operand 2 "")))])]
1179 "TARGET_THUMB2 && flag_pic"
1181 operands[4] = gen_rtx_MULT (SImode, operands[0], GEN_INT (4));
1182 operands[4] = gen_rtx_PLUS (SImode, operands[4],
1183 gen_rtx_LABEL_REF (SImode, operands[2]));
1184 operands[4] = gen_rtx_MEM (SImode, operands[4]);
1185 MEM_READONLY_P (operands[4]) = 1;
1186 MEM_NOTRAP_P (operands[4]) = 1;
1189 (define_insn "*thumb2_casesi_internal_pic"
1190 [(parallel [(set (pc)
1192 (leu (match_operand:SI 0 "s_register_operand" "r")
1193 (match_operand:SI 1 "arm_rhs_operand" "rI"))
1194 (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
1195 (label_ref:SI (match_operand 2 "" ""))))
1196 (label_ref:SI (match_operand 3 "" ""))))
1197 (clobber (reg:CC CC_REGNUM))
1198 (clobber (match_scratch:SI 4 "=&r"))
1199 (clobber (match_scratch:SI 5 "=r"))
1200 (use (label_ref:SI (match_dup 2)))])]
1201 "TARGET_THUMB2 && flag_pic"
1202 "* return thumb2_output_casesi(operands);"
1203 [(set_attr "conds" "clob")
1204 (set_attr "length" "20")
1205 (set_attr "type" "multiple")]
1208 (define_insn "*thumb2_return"
1210 "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
1211 "* return output_return_instruction (const_true_rtx, true, false, true);"
1212 [(set_attr "type" "branch")
1213 (set_attr "length" "4")]
1216 (define_insn "*thumb2_cmse_entry_return"
1218 "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
1219 "* return output_return_instruction (const_true_rtx, true, false, true);"
1220 [(set_attr "type" "branch")
1221 ; This is a return from a cmse_nonsecure_entry function so code will be
1222 ; added to clear the APSR and potentially the FPSCR if VFP is available, so
1223 ; we adapt the length accordingly.
1224 (set (attr "length")
1225 (if_then_else (match_test "TARGET_HARD_FLOAT")
1228 ; We do not support predicate execution of returns from cmse_nonsecure_entry
1229 ; functions because we need to clear the APSR. Since predicable has to be
1230 ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
1232 (set_attr "predicable" "no")]
1235 (define_insn_and_split "thumb2_eh_return"
1236 [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
1238 (clobber (match_scratch:SI 1 "=&r"))]
1241 "&& reload_completed"
1245 thumb_set_return_address (operands[0], operands[1]);
1250 (define_insn "*thumb2_alusi3_short"
1251 [(set (match_operand:SI 0 "s_register_operand" "=l")
1252 (match_operator:SI 3 "thumb_16bit_operator"
1253 [(match_operand:SI 1 "s_register_operand" "0")
1254 (match_operand:SI 2 "s_register_operand" "l")]))
1255 (clobber (reg:CC CC_REGNUM))]
1256 "TARGET_THUMB2 && reload_completed
1257 && GET_CODE(operands[3]) != PLUS
1258 && GET_CODE(operands[3]) != MINUS"
1259 "%I3%!\\t%0, %1, %2"
1260 [(set_attr "predicable" "yes")
1261 (set_attr "length" "2")
1262 (set_attr "type" "alu_sreg")]
1265 (define_insn "*thumb2_shiftsi3_short"
1266 [(set (match_operand:SI 0 "low_register_operand" "=l,l")
1267 (match_operator:SI 3 "shift_operator"
1268 [(match_operand:SI 1 "low_register_operand" "0,l")
1269 (match_operand:SI 2 "low_reg_or_int_operand" "l,M")]))
1270 (clobber (reg:CC CC_REGNUM))]
1271 "TARGET_THUMB2 && reload_completed
1272 && ((GET_CODE(operands[3]) != ROTATE && GET_CODE(operands[3]) != ROTATERT)
1273 || REG_P (operands[2]))"
1274 "* return arm_output_shift(operands, 2);"
1275 [(set_attr "predicable" "yes")
1276 (set_attr "shift" "1")
1277 (set_attr "length" "2")
1278 (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
1279 (if_then_else (match_operand 3 "alu_shift_operator_lsl_1_to_4")
1280 (const_string "alu_shift_imm_lsl_1to4")
1281 (const_string "alu_shift_imm_other"))
1282 (const_string "alu_shift_reg")))]
1285 (define_insn "*thumb2_mov<mode>_shortim"
1286 [(set (match_operand:QHSI 0 "low_register_operand" "=l")
1287 (match_operand:QHSI 1 "const_int_operand" "I"))
1288 (clobber (reg:CC CC_REGNUM))]
1289 "TARGET_THUMB2 && reload_completed"
1291 [(set_attr "predicable" "yes")
1292 (set_attr "length" "2")
1293 (set_attr "type" "mov_imm")]
1296 (define_insn "*thumb2_addsi_short"
1297 [(set (match_operand:SI 0 "low_register_operand" "=l,l")
1298 (plus:SI (match_operand:SI 1 "low_register_operand" "l,0")
1299 (match_operand:SI 2 "low_reg_or_int_operand" "lPt,Ps")))
1300 (clobber (reg:CC CC_REGNUM))]
1301 "TARGET_THUMB2 && reload_completed"
1305 if (CONST_INT_P (operands[2]))
1306 val = INTVAL(operands[2]);
1310 /* We prefer eg. subs rn, rn, #1 over adds rn, rn, #0xffffffff. */
1311 if (val < 0 && const_ok_for_arm(ARM_SIGN_EXTEND (-val)))
1312 return \"sub%!\\t%0, %1, #%n2\";
1314 return \"add%!\\t%0, %1, %2\";
1316 [(set_attr "predicable" "yes")
1317 (set_attr "length" "2")
1318 (set_attr_alternative "type"
1319 [(if_then_else (match_operand 2 "const_int_operand" "")
1320 (const_string "alu_imm")
1321 (const_string "alu_sreg"))
1322 (const_string "alu_imm")])]
1325 (define_insn "*thumb2_subsi_short"
1326 [(set (match_operand:SI 0 "low_register_operand" "=l")
1327 (minus:SI (match_operand:SI 1 "low_register_operand" "l")
1328 (match_operand:SI 2 "low_register_operand" "l")))
1329 (clobber (reg:CC CC_REGNUM))]
1330 "TARGET_THUMB2 && reload_completed"
1331 "sub%!\\t%0, %1, %2"
1332 [(set_attr "predicable" "yes")
1333 (set_attr "length" "2")
1334 (set_attr "type" "alu_sreg")]
1338 [(set (match_operand:CC 0 "cc_register" "")
1339 (compare:CC (match_operand:SI 1 "low_register_operand" "")
1340 (match_operand:SI 2 "const_int_operand" "")))]
1342 && peep2_reg_dead_p (1, operands[1])
1343 && satisfies_constraint_Pw (operands[2])"
1345 [(set (match_dup 0) (compare:CC (match_dup 1) (match_dup 2)))
1346 (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 3)))])]
1347 "operands[3] = GEN_INT (- INTVAL (operands[2]));"
1351 [(match_scratch:SI 3 "l")
1352 (set (match_operand:CC 0 "cc_register" "")
1353 (compare:CC (match_operand:SI 1 "low_register_operand" "")
1354 (match_operand:SI 2 "const_int_operand" "")))]
1356 && satisfies_constraint_Px (operands[2])"
1358 [(set (match_dup 0) (compare:CC (match_dup 1) (match_dup 2)))
1359 (set (match_dup 3) (plus:SI (match_dup 1) (match_dup 4)))])]
1360 "operands[4] = GEN_INT (- INTVAL (operands[2]));"
1363 (define_insn "thumb2_addsi3_compare0"
1364 [(set (reg:CC_NZ CC_REGNUM)
1366 (plus:SI (match_operand:SI 1 "s_register_operand" "l, 0, r")
1367 (match_operand:SI 2 "arm_add_operand" "lPt,Ps,rIL"))
1369 (set (match_operand:SI 0 "s_register_operand" "=l,l,r")
1370 (plus:SI (match_dup 1) (match_dup 2)))]
1375 if (CONST_INT_P (operands[2]))
1376 val = INTVAL (operands[2]);
1380 if (val < 0 && const_ok_for_arm (ARM_SIGN_EXTEND (-val)))
1381 return \"subs\\t%0, %1, #%n2\";
1383 return \"adds\\t%0, %1, %2\";
1385 [(set_attr "conds" "set")
1386 (set_attr "length" "2,2,4")
1387 (set_attr_alternative "type"
1388 [(if_then_else (match_operand 2 "const_int_operand" "")
1389 (const_string "alus_imm")
1390 (const_string "alus_sreg"))
1391 (const_string "alus_imm")
1392 (if_then_else (match_operand 2 "const_int_operand" "")
1393 (const_string "alus_imm")
1394 (const_string "alus_sreg"))])]
1397 (define_insn "*thumb2_addsi3_compare0_scratch"
1398 [(set (reg:CC_NZ CC_REGNUM)
1400 (plus:SI (match_operand:SI 0 "s_register_operand" "l, r")
1401 (match_operand:SI 1 "arm_add_operand" "lPv,rIL"))
1407 if (CONST_INT_P (operands[1]))
1408 val = INTVAL (operands[1]);
1412 if (val < 0 && const_ok_for_arm (ARM_SIGN_EXTEND (-val)))
1413 return \"cmp\\t%0, #%n1\";
1415 return \"cmn\\t%0, %1\";
1417 [(set_attr "conds" "set")
1418 (set_attr "length" "2,4")
1419 (set (attr "type") (if_then_else (match_operand 1 "const_int_operand" "")
1420 (const_string "alus_imm")
1421 (const_string "alus_sreg")))]
1424 (define_insn "*thumb2_mulsi_short"
1425 [(set (match_operand:SI 0 "low_register_operand" "=l")
1426 (mult:SI (match_operand:SI 1 "low_register_operand" "%0")
1427 (match_operand:SI 2 "low_register_operand" "l")))
1428 (clobber (reg:CC CC_REGNUM))]
1429 "TARGET_THUMB2 && optimize_size && reload_completed"
1430 "mul%!\\t%0, %2, %0"
1431 [(set_attr "predicable" "yes")
1432 (set_attr "length" "2")
1433 (set_attr "type" "muls")])
1435 (define_insn "*thumb2_mulsi_short_compare0"
1436 [(set (reg:CC_NZ CC_REGNUM)
1438 (mult:SI (match_operand:SI 1 "register_operand" "%0")
1439 (match_operand:SI 2 "register_operand" "l"))
1441 (set (match_operand:SI 0 "register_operand" "=l")
1442 (mult:SI (match_dup 1) (match_dup 2)))]
1443 "TARGET_THUMB2 && optimize_size"
1445 [(set_attr "length" "2")
1446 (set_attr "type" "muls")])
1448 (define_insn "*thumb2_mulsi_short_compare0_scratch"
1449 [(set (reg:CC_NZ CC_REGNUM)
1451 (mult:SI (match_operand:SI 1 "register_operand" "%0")
1452 (match_operand:SI 2 "register_operand" "l"))
1454 (clobber (match_scratch:SI 0 "=l"))]
1455 "TARGET_THUMB2 && optimize_size"
1457 [(set_attr "length" "2")
1458 (set_attr "type" "muls")])
1460 (define_insn "*thumb2_cbz"
1461 [(set (pc) (if_then_else
1462 (eq (match_operand:SI 0 "s_register_operand" "l,?r")
1464 (label_ref (match_operand 1 "" ""))
1466 (clobber (reg:CC CC_REGNUM))]
1469 if (get_attr_length (insn) == 2)
1470 return \"cbz\\t%0, %l1\";
1472 return \"cmp\\t%0, #0\;beq\\t%l1\";
1474 [(set (attr "length")
1476 (and (ge (minus (match_dup 1) (pc)) (const_int 2))
1477 (le (minus (match_dup 1) (pc)) (const_int 128))
1478 (not (match_test "which_alternative")))
1481 (set_attr "type" "branch,multiple")]
1484 (define_insn "*thumb2_cbnz"
1485 [(set (pc) (if_then_else
1486 (ne (match_operand:SI 0 "s_register_operand" "l,?r")
1488 (label_ref (match_operand 1 "" ""))
1490 (clobber (reg:CC CC_REGNUM))]
1493 if (get_attr_length (insn) == 2)
1494 return \"cbnz\\t%0, %l1\";
1496 return \"cmp\\t%0, #0\;bne\\t%l1\";
1498 [(set (attr "length")
1500 (and (ge (minus (match_dup 1) (pc)) (const_int 2))
1501 (le (minus (match_dup 1) (pc)) (const_int 128))
1502 (not (match_test "which_alternative")))
1505 (set_attr "type" "branch,multiple")]
1508 (define_insn "*thumb2_one_cmplsi2_short"
1509 [(set (match_operand:SI 0 "low_register_operand" "=l")
1510 (not:SI (match_operand:SI 1 "low_register_operand" "l")))
1511 (clobber (reg:CC CC_REGNUM))]
1512 "TARGET_THUMB2 && reload_completed"
1514 [(set_attr "predicable" "yes")
1515 (set_attr "length" "2")
1516 (set_attr "type" "mvn_reg")]
1519 (define_insn "*thumb2_negsi2_short"
1520 [(set (match_operand:SI 0 "low_register_operand" "=l")
1521 (neg:SI (match_operand:SI 1 "low_register_operand" "l")))
1522 (clobber (reg:CC CC_REGNUM))]
1523 "TARGET_THUMB2 && reload_completed"
1525 [(set_attr "predicable" "yes")
1526 (set_attr "length" "2")
1527 (set_attr "type" "alu_sreg")]
1530 (define_insn "*orsi_notsi_si"
1531 [(set (match_operand:SI 0 "s_register_operand" "=r")
1532 (ior:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
1533 (match_operand:SI 1 "s_register_operand" "r")))]
1535 "orn%?\\t%0, %1, %2"
1536 [(set_attr "predicable" "yes")
1537 (set_attr "type" "logic_reg")]
1540 (define_insn "*orsi_not_shiftsi_si"
1541 [(set (match_operand:SI 0 "s_register_operand" "=r")
1542 (ior:SI (not:SI (match_operator:SI 4 "shift_operator"
1543 [(match_operand:SI 2 "s_register_operand" "r")
1544 (match_operand:SI 3 "const_int_operand" "M")]))
1545 (match_operand:SI 1 "s_register_operand" "r")))]
1547 "orn%?\\t%0, %1, %2%S4"
1548 [(set_attr "predicable" "yes")
1549 (set_attr "shift" "2")
1550 (set_attr "autodetect_type" "alu_shift_operator4")]
1554 [(set (match_operand:CC_NZ 0 "cc_register" "")
1555 (compare:CC_NZ (zero_extract:SI
1556 (match_operand:SI 1 "low_register_operand" "")
1558 (match_operand:SI 2 "const_int_operand" ""))
1560 (match_scratch:SI 3 "l")
1562 (if_then_else (match_operator:CC_NZ 4 "equality_operator"
1563 [(match_dup 0) (const_int 0)])
1564 (match_operand 5 "" "")
1565 (match_operand 6 "" "")))]
1567 && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32)
1568 && peep2_reg_dead_p (2, operands[0])"
1569 [(parallel [(set (match_dup 0)
1570 (compare:CC_NZ (ashift:SI (match_dup 1) (match_dup 2))
1572 (clobber (match_dup 3))])
1574 (if_then_else (match_op_dup 4 [(match_dup 0) (const_int 0)])
1575 (match_dup 5) (match_dup 6)))]
1577 operands[2] = GEN_INT (31 - INTVAL (operands[2]));
1578 operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]) == NE ? LT : GE,
1579 VOIDmode, operands[0], const0_rtx);
1583 [(set (match_operand:CC_NZ 0 "cc_register" "")
1584 (compare:CC_NZ (zero_extract:SI
1585 (match_operand:SI 1 "low_register_operand" "")
1586 (match_operand:SI 2 "const_int_operand" "")
1589 (match_scratch:SI 3 "l")
1591 (if_then_else (match_operator:CC_NZ 4 "equality_operator"
1592 [(match_dup 0) (const_int 0)])
1593 (match_operand 5 "" "")
1594 (match_operand 6 "" "")))]
1596 && (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 32)
1597 && peep2_reg_dead_p (2, operands[0])"
1598 [(parallel [(set (match_dup 0)
1599 (compare:CC_NZ (ashift:SI (match_dup 1) (match_dup 2))
1601 (clobber (match_dup 3))])
1603 (if_then_else (match_op_dup 4 [(match_dup 0) (const_int 0)])
1604 (match_dup 5) (match_dup 6)))]
1606 operands[2] = GEN_INT (32 - INTVAL (operands[2]));
1609 ;; Define the subtract-one-and-jump insns so loop.c
1610 ;; knows what to generate.
1611 (define_expand "doloop_end"
1612 [(use (match_operand 0 "" "")) ; loop pseudo
1613 (use (match_operand 1 "" ""))] ; label
1617 /* Currently SMS relies on the do-loop pattern to recognize loops
1618 where (1) the control part consists of all insns defining and/or
1619 using a certain 'count' register and (2) the loop count can be
1620 adjusted by modifying this register prior to the loop.
1621 ??? The possible introduction of a new block to initialize the
1622 new IV can potentially affect branch optimizations.
1624 Also used to implement the low over head loops feature, which is part of
1625 the Armv8.1-M Mainline Low Overhead Branch (LOB) extension. */
1626 if (optimize > 0 && (flag_modulo_sched || TARGET_HAVE_LOB))
1636 if (GET_MODE (operands[0]) != SImode)
1642 && arm_target_bb_ok_for_lob (BLOCK_FOR_INSN (operands[1])))
1644 /* If we have a compatible MVE target, try and analyse the loop
1645 contents to determine if we can use predicated dlstp/letp
1646 looping. These patterns implicitly use LR as the loop counter. */
1648 && ((decrement_num = arm_attempt_dlstp_transform (operands[1]))
1651 loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[1]);
1652 switch (decrement_num)
1655 insn = gen_predicated_doloop_end_internal2 (loc_ref);
1658 insn = gen_predicated_doloop_end_internal4 (loc_ref);
1661 insn = gen_predicated_doloop_end_internal8 (loc_ref);
1664 insn = gen_predicated_doloop_end_internal16 (loc_ref);
1669 emit_jump_insn (insn);
1672 /* Remaining LOB cases need to explicitly use LR. */
1673 s0 = gen_rtx_REG (SImode, LR_REGNUM);
1676 /* Otherwise, try standard decrement-by-one dls/le looping. */
1678 insn = emit_insn (gen_thumb2_addsi3_compare0 (s0, s0,
1681 insn = emit_insn (gen_addsi3_compare0 (s0, s0, GEN_INT (-1)));
1683 cmp = XVECEXP (PATTERN (insn), 0, 0);
1684 cc_reg = SET_DEST (cmp);
1685 bcomp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx);
1686 loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[1]);
1687 emit_jump_insn (gen_rtx_SET (pc_rtx,
1688 gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
1696 (define_insn "*clear_apsr"
1697 [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)
1698 (clobber (reg:CC CC_REGNUM))]
1699 "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
1701 [(set_attr "predicable" "yes")]
1704 ;; The operands are validated through the clear_multiple_operation
1705 ;; match_parallel predicate rather than through constraints so enable it only
1707 (define_insn "*clear_multiple"
1708 [(match_parallel 0 "clear_multiple_operation"
1709 [(set (match_operand:SI 1 "register_operand" "")
1711 "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
1714 int i, num_saves = XVECLEN (operands[0], 0);
1716 strcpy (pattern, \"clrm%?\\t{\");
1717 for (i = 0; i < num_saves; i++)
1719 if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
1721 strcat (pattern, \"APSR\");
1726 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
1727 if (i < num_saves - 1)
1728 strcat (pattern, \", %|\");
1730 strcat (pattern, \"}\");
1731 output_asm_insn (pattern, operands);
1734 [(set_attr "predicable" "yes")]
1737 (define_insn "thumb2_asrl"
1738 [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
1739 (ashiftrt:DI (match_dup 0)
1740 (match_operand:SI 1 "arm_reg_or_long_shift_imm" "rPg")))]
1742 "asrl%?\\t%Q0, %R0, %1"
1743 [(set_attr "predicable" "yes")])
1745 (define_insn "thumb2_lsll"
1746 [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
1747 (ashift:DI (match_dup 0)
1748 (match_operand:SI 1 "arm_reg_or_long_shift_imm" "rPg")))]
1750 "lsll%?\\t%Q0, %R0, %1"
1751 [(set_attr "predicable" "yes")])
1753 (define_insn "thumb2_lsrl"
1754 [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
1755 (lshiftrt:DI (match_dup 0)
1756 (match_operand:SI 1 "long_shift_imm" "Pg")))]
1758 "lsrl%?\\t%Q0, %R0, %1"
1759 [(set_attr "predicable" "yes")])
1761 ;; Originally expanded by 'doloop_end'.
1762 (define_insn "*doloop_end_internal"
1765 (ne (reg:SI LR_REGNUM) (const_int 1))
1766 (label_ref (match_operand 0 "" ""))
1768 (set (reg:SI LR_REGNUM)
1769 (plus:SI (reg:SI LR_REGNUM) (const_int -1)))
1770 (clobber (reg:CC CC_REGNUM))]
1771 "TARGET_32BIT && TARGET_HAVE_LOB"
1773 if (get_attr_length (insn) == 4)
1774 return "le\t%|lr, %l0";
1776 return "subs\t%|lr, #1;bne\t%l0";
1778 [(set (attr "length")
1780 (ltu (minus (pc) (match_dup 0)) (const_int 1024))
1783 (set_attr "type" "branch")])
1785 (define_expand "doloop_begin"
1786 [(match_operand 0 "" "")
1787 (match_operand 1 "" "")]
1788 "TARGET_32BIT && TARGET_HAVE_LOB"
1790 if (REGNO (operands[0]) == LR_REGNUM)
1792 /* Pick out the number by which we are decrementing the loop counter
1793 in every iteration. If it's > 1, then use dlstp. */
1794 int const_int_dec_num
1795 = abs (INTVAL (XEXP (XEXP (XVECEXP (PATTERN (operands[1]), 0, 1),
1798 switch (const_int_dec_num)
1801 emit_insn (gen_dlstp8_insn (operands[0]));
1805 emit_insn (gen_dlstp16_insn (operands[0]));
1809 emit_insn (gen_dlstp32_insn (operands[0]));
1813 emit_insn (gen_dlstp64_insn (operands[0]));
1817 emit_insn (gen_dls_insn (operands[0]));
1829 (define_insn "dls_insn"
1830 [(set (reg:SI LR_REGNUM)
1831 (unspec:SI [(match_operand:SI 0 "s_register_operand" "r")] UNSPEC_DLS))]
1832 "TARGET_32BIT && TARGET_HAVE_LOB"