]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/arm/thumb2.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / arm / thumb2.md
index 8c754d90d589e98f80ca63bdc9a2f099a444f3a8..84c9c3dfe80095ba9f956cd7947f216a9d33946a 100644 (file)
@@ -1,5 +1,5 @@
 ;; ARM Thumb-2 Machine Description
-;; Copyright (C) 2007-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2007-2024 Free Software Foundation, Inc.
 ;; Written by CodeSourcery, LLC.
 ;;
 ;; This file is part of GCC.
 ;; changes made in armv5t as "thumb2".  These are considered part
 ;; the 16-bit Thumb-1 instruction set.
 
-;; Thumb-2 only allows shift by constant on data processing instructions
-(define_insn "*thumb_andsi_not_shiftsi_si"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-       (and:SI (not:SI (match_operator:SI 4 "shift_operator"
-                        [(match_operand:SI 2 "s_register_operand" "r")
-                         (match_operand:SI 3 "const_int_operand" "M")]))
-               (match_operand:SI 1 "s_register_operand" "r")))]
-  "TARGET_THUMB2"
-  "bic%?\\t%0, %1, %2%S4"
-  [(set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "shift" "2")
-   (set_attr "type" "alu_shift_imm")]
-)
-
 ;; We use the '0' constraint for operand 1 because reload should
 ;; be smart enough to generate an appropriate move for the r/r/r case.
 (define_insn_and_split "*thumb2_smaxsi3"
@@ -57,7 +42,7 @@
                    (match_dup 2)))]
   ""
   [(set_attr "conds" "clob")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "length" "6,6,10")
    (set_attr "type" "multiple")]
 )
@@ -78,7 +63,7 @@
                    (match_dup 2)))]
   ""
   [(set_attr "conds" "clob")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "length" "6,6,10")
    (set_attr "type" "multiple")]
 )
   ""
   [(set_attr "conds" "clob")
    (set_attr "length" "6,6,10")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "type" "multiple")]
 )
 
   ""
   [(set_attr "conds" "clob")
    (set_attr "length" "6,6,10")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
-   (set_attr "type" "multiple")]
-)
-
-;; Thumb-2 does not have rsc, so use a clever trick with shifter operands.
-(define_insn_and_split "*thumb2_negdi2"
-  [(set (match_operand:DI         0 "s_register_operand" "=&r,r")
-       (neg:DI (match_operand:DI 1 "s_register_operand"  "?r,0")))
-   (clobber (reg:CC CC_REGNUM))]
-  "TARGET_THUMB2"
-  "#" ; negs\\t%Q0, %Q1\;sbc\\t%R0, %R1, %R1, lsl #1
-  "&& reload_completed"
-  [(parallel [(set (reg:CC CC_REGNUM)
-                  (compare:CC (const_int 0) (match_dup 1)))
-             (set (match_dup 0) (minus:SI (const_int 0) (match_dup 1)))])
-   (set (match_dup 2) (minus:SI (minus:SI (match_dup 3)
-                                          (ashift:SI (match_dup 3)
-                                                     (const_int 1)))
-                                (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
-  {
-    operands[2] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[3] = gen_highpart (SImode, operands[1]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-  }
-  [(set_attr "conds" "clob")
-   (set_attr "length" "8")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "type" "multiple")]
 )
 
   [(set_attr "conds" "*,clob,clob")
    (set_attr "shift" "1")
    (set_attr "predicable" "yes,no,no")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "ce_count" "2")
    (set_attr "length" "8,6,10")
    (set_attr "type" "multiple")]
   [(set_attr "conds" "*,clob,clob")
    (set_attr "shift" "1")
    (set_attr "predicable" "yes,no,no")
-   (set_attr "enabled_for_depr_it" "yes,yes,no")
-   (set_attr "predicable_short_it" "no")
+   (set_attr "enabled_for_short_it" "yes,yes,no")
    (set_attr "ce_count" "2")
    (set_attr "length" "8,6,10")
    (set_attr "type" "multiple")]
         (mem:SI (post_inc:SI (reg:SI SP_REGNUM))))]
   "TARGET_THUMB2 && (reload_in_progress || reload_completed)"
   "pop\t{%0}"
-  [(set_attr "type" "load1")
+  [(set_attr "type" "load_4")
    (set_attr "length" "2")
    (set_attr "predicable" "yes")]
 )
 ;; regs.  The high register alternatives are not taken into account when
 ;; choosing register preferences in order to reflect their expense.
 (define_insn "*thumb2_movsi_insn"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,l,r,r,l ,*hk,m,*m")
-       (match_operand:SI 1 "general_operand"      "rk,I,Py,K,j,mi,*mi,l,*hk"))]
-  "TARGET_THUMB2 && ! TARGET_IWMMXT
-   && !(TARGET_HARD_FLOAT && TARGET_VFP)
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rk,r,l,r,r,lk*r,m")
+       (match_operand:SI 1 "general_operand"      "rk,I,Py,K,j,mi,lk*r"))]
+  "TARGET_THUMB2 && !TARGET_IWMMXT && !TARGET_HARD_FLOAT
    && (   register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
-  "@
-   mov%?\\t%0, %1
-   mov%?\\t%0, %1
-   mov%?\\t%0, %1
-   mvn%?\\t%0, #%B1
-   movw%?\\t%0, %1
-   ldr%?\\t%0, %1
-   ldr%?\\t%0, %1
-   str%?\\t%1, %0
-   str%?\\t%1, %0"
-  [(set_attr "type" "mov_reg,mov_imm,mov_imm,mvn_imm,mov_imm,load1,load1,store1,store1")
-   (set_attr "length" "2,4,2,4,4,4,4,4,4")
+{
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+    case 2:
+      return \"mov%?\\t%0, %1\";
+    case 3: return \"mvn%?\\t%0, #%B1\";
+    case 4: return \"movw%?\\t%0, %1\";
+    case 5:
+      /* Cannot load it directly, split to load it via MOV / MOVT.  */
+      if (!MEM_P (operands[1]) && arm_disable_literal_pool)
+       return \"#\";
+      return \"ldr%?\\t%0, %1\";
+    case 6: return \"str%?\\t%1, %0\";
+    default: gcc_unreachable ();
+    }
+}
+  [(set_attr "type" "mov_reg,mov_imm,mov_imm,mvn_imm,mov_imm,load_4,store_4")
+   (set_attr "length" "2,4,2,4,4,4,4")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "yes,no,yes,no,no,no,no,no,no")
-   (set_attr "pool_range" "*,*,*,*,*,1018,4094,*,*")
-   (set_attr "neg_pool_range" "*,*,*,*,*,0,0,*,*")]
+   (set_attr "predicable_short_it" "yes,no,yes,no,no,no,no")
+   (set_attr "pool_range" "*,*,*,*,*,1018,*")
+   (set_attr "neg_pool_range" "*,*,*,*,*,0,*")]
 )
 
 (define_insn "tls_load_dot_plus_four"
    mov%?\\t%0, %1\\t%@ movhi
    mov%?\\t%0, %1\\t%@ movhi
    movw%?\\t%0, %L1\\t%@ movhi
-   str%(h%)\\t%1, %0\\t%@ movhi
-   ldr%(h%)\\t%0, %1\\t%@ movhi"
-  [(set_attr "type" "mov_reg,mov_imm,mov_imm,mov_imm,store1,load1")
+   strh%?\\t%1, %0\\t%@ movhi
+   ldrh%?\\t%0, %1\\t%@ movhi"
+  [(set_attr "type" "mov_reg,mov_imm,mov_imm,mov_imm,store_4,load_4")
    (set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "yes,no,yes,no,no,no")
    (set_attr "length" "2,4,2,4,4,4")
   "TARGET_THUMB2
    && INTVAL (operands[5]) == INTVAL (operands[2]) + 4"
   "strd\\t%3, %4, [%0, %2]!"
-  [(set_attr "type" "store2")]
-)
-
-(define_insn "*thumb2_cmpsi_neg_shiftsi"
-  [(set (reg:CC CC_REGNUM)
-       (compare:CC (match_operand:SI 0 "s_register_operand" "r")
-                   (neg:SI (match_operator:SI 3 "shift_operator"
-                            [(match_operand:SI 1 "s_register_operand" "r")
-                             (match_operand:SI 2 "const_int_operand" "M")]))))]
-  "TARGET_THUMB2"
-  "cmn%?\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   (set_attr "type" "alus_shift_imm")]
+  [(set_attr "type" "store_8")]
 )
 
 (define_insn_and_split "*thumb2_mov_scc"
   [(set (match_operand:SI 0 "s_register_operand" "=l,r")
-       (match_operator:SI 1 "arm_comparison_operator"
+       (match_operator:SI 1 "arm_comparison_operator_mode"
         [(match_operand 2 "cc_register" "") (const_int 0)]))]
   "TARGET_THUMB2"
   "#"   ; "ite\\t%D1\;mov%D1\\t%0, #0\;mov%d1\\t%0, #1"
                          (const_int 0)))]
   ""
   [(set_attr "conds" "use")
-   (set_attr "enabled_for_depr_it" "yes,no")
+   (set_attr "enabled_for_short_it" "yes,no")
    (set_attr "length" "8,10")
    (set_attr "type" "multiple")]
 )
 
 (define_insn_and_split "*thumb2_mov_negscc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-       (neg:SI (match_operator:SI 1 "arm_comparison_operator"
+       (neg:SI (match_operator:SI 1 "arm_comparison_operator_mode"
                 [(match_operand 2 "cc_register" "") (const_int 0)])))]
-  "TARGET_THUMB2 && !arm_restrict_it"
+  "TARGET_THUMB2
+   && !arm_restrict_it
+   && !arm_borrow_operation (operands[1], SImode)"
   "#"   ; "ite\\t%D1\;mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
-  "TARGET_THUMB2"
+  "&& true"
   [(set (match_dup 0)
         (if_then_else:SI (match_dup 1)
                          (match_dup 3)
 
 (define_insn_and_split "*thumb2_mov_negscc_strict_it"
   [(set (match_operand:SI 0 "low_register_operand" "=l")
-       (neg:SI (match_operator:SI 1 "arm_comparison_operator"
+       (neg:SI (match_operator:SI 1 "arm_comparison_operator_mode"
                 [(match_operand 2 "cc_register" "") (const_int 0)])))]
-  "TARGET_THUMB2 && arm_restrict_it"
+  "TARGET_THUMB2
+   && arm_restrict_it
+   && !arm_borrow_operation (operands[1], SImode)"
   "#"   ; ";mvn\\t%0, #0 ;it\\t%D1\;mov%D1\\t%0, #0\"
   "&& reload_completed"
   [(set (match_dup 0)
 
 (define_insn_and_split "*thumb2_mov_notscc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-       (not:SI (match_operator:SI 1 "arm_comparison_operator"
+       (not:SI (match_operator:SI 1 "arm_comparison_operator_mode"
                 [(match_operand 2 "cc_register" "") (const_int 0)])))]
   "TARGET_THUMB2 && !arm_restrict_it"
   "#"   ; "ite\\t%D1\;mvn%D1\\t%0, #0\;mvn%d1\\t%0, #1"
-  "TARGET_THUMB2"
+  "&& true"
   [(set (match_dup 0)
         (if_then_else:SI (match_dup 1)
                          (match_dup 3)
 
 (define_insn_and_split "*thumb2_mov_notscc_strict_it"
   [(set (match_operand:SI 0 "low_register_operand" "=l")
-        (not:SI (match_operator:SI 1 "arm_comparison_operator"
+       (not:SI (match_operator:SI 1 "arm_comparison_operator_mode"
                  [(match_operand 2 "cc_register" "") (const_int 0)])))]
   "TARGET_THUMB2 && arm_restrict_it"
   "#"   ; "mvn %0, #0 ; it%d1 ; lsl%d1 %0, %0, #1"
     DONE;
   }
   [(set_attr "length" "4,4,6,6,6,6,10,8,10,10,10,6")
-   (set_attr "enabled_for_depr_it" "yes,yes,no,no,no,no,no,no,no,no,no,yes")
+   (set_attr "enabled_for_short_it" "yes,yes,no,no,no,no,no,no,no,no,no,yes")
    (set_attr "conds" "use")
    (set_attr_alternative "type"
                          [(if_then_else (match_operand 2 "const_int_operand" "")
                          [(match_operand 4 "cc_register" "") (const_int 0)])
                         (match_operand:SF 1 "s_register_operand" "0,r")
                         (match_operand:SF 2 "s_register_operand" "r,0")))]
-  "TARGET_THUMB2 && TARGET_SOFT_FLOAT"
+  "TARGET_THUMB2 && TARGET_SOFT_FLOAT && !TARGET_HAVE_MVE"
   "@
    it\\t%D3\;mov%D3\\t%0, %2
    it\\t%d3\;mov%d3\\t%0, %1"
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2_fpcxt"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "l*r"))]
+                   UNSPEC_NONSECURE_MEM)
+        (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE"
+  "blxns\\t%0"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
+                   UNSPEC_NONSECURE_MEM)
+        (match_operand 0 "" ""))
+   (use (match_operand 1 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2_fpcxt"
+  [(set (match_operand 0 "" "")
+       (call
+        (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+                   UNSPEC_NONSECURE_MEM)
+        (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE"
+  "blxns\\t%1"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+       (call
+        (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] UNSPEC_NONSECURE_MEM)
+        (match_operand 1 "" "")))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "register_operand" "l*r"))]
    (set_attr "type" "multiple")]
 )
 
-(define_insn "*thumb2_ior_scc_strict_it"
-  [(set (match_operand:SI 0 "s_register_operand" "=l,l")
+(define_insn_and_split "*thumb2_ior_scc_strict_it"
+  [(set (match_operand:SI 0 "s_register_operand" "=&r")
        (ior:SI (match_operator:SI 2 "arm_comparison_operator"
                 [(match_operand 3 "cc_register" "") (const_int 0)])
-               (match_operand:SI 1 "s_register_operand" "0,?l")))]
+               (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_THUMB2 && arm_restrict_it"
-  "@
-   it\\t%d2\;mov%d2\\t%0, #1\;it\\t%d2\;orr%d2\\t%0, %1
-   mov\\t%0, #1\;orr\\t%0, %1\;it\\t%D2\;mov%D2\\t%0, %1"
+  "#" ; orr\\t%0, %1, #1\;it\\t%D2\;mov%D2\\t%0, %1
+  "&& reload_completed"
+  [(set (match_dup 0) (ior:SI (match_dup 1) (const_int 1)))
+   (cond_exec (match_dup 4)
+     (set (match_dup 0) (match_dup 1)))]
+  {
+    machine_mode mode = GET_MODE (operands[3]);
+    rtx_code rc = GET_CODE (operands[2]);
+
+    if (mode == CCFPmode || mode == CCFPEmode)
+      rc = reverse_condition_maybe_unordered (rc);
+    else
+      rc = reverse_condition (rc);
+    operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[3], const0_rtx);
+  }
   [(set_attr "conds" "use")
    (set_attr "length" "8")
    (set_attr "type" "multiple")]
       return \"%i5\\t%0, %1, %2, lsr #31\";
 
     output_asm_insn (\"cmp\\t%2, %3\", operands);
+
+    if (GET_CODE (operands[5]) == PLUS && TARGET_COND_ARITH)
+      return \"cinc\\t%0, %1, %d4\";
+
     if (GET_CODE (operands[5]) == AND)
       {
        output_asm_insn (\"ite\\t%D4\", operands);
                 [(match_operand:SI 1 "s_register_operand" "r")
                  (match_operand:SI 2 "arm_rhs_operand" "rI")])))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !TARGET_COND_ARITH"
   "#"
   "&& reload_completed"
   [(const_int 0)]
         /* Emit subs\\t%0, %1, %2\;it\\tne\;mvnne\\t%0, #0 */
         if (CONST_INT_P (operands[2]))
           emit_insn (gen_cmpsi2_addneg (operands[0], operands[1], operands[2],
-                                        GEN_INT (- INTVAL (operands[2]))));
+                                        gen_int_mode (-INTVAL (operands[2]),
+                                                     SImode)));
         else
           emit_insn (gen_subsi3_compare (operands[0], operands[1], operands[2]));
 
    (set_attr "type" "multiple")]
 )
 
+(define_insn "*thumb2_csinv"
+  [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
+        (if_then_else:SI
+         (match_operand 1 "arm_comparison_operation" "")
+         (not:SI (match_operand:SI 2 "arm_general_register_operand" "r, r"))
+         (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
+  "TARGET_COND_ARITH"
+  "@
+   csinv\\t%0, %3, %2, %D1
+   csinv\\t%0, zr, %2, %D1"
+  [(set_attr "type" "csel")
+   (set_attr "predicable" "no")]
+)
+
+(define_insn "*thumb2_csinc"
+  [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
+        (if_then_else:SI
+         (match_operand 1 "arm_comparison_operation" "")
+         (plus:SI (match_operand:SI 2 "arm_general_register_operand" "r, r")
+                  (const_int 1))
+         (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
+  "TARGET_COND_ARITH"
+  "@
+   csinc\\t%0, %3, %2, %D1
+   csinc\\t%0, zr, %2, %D1"
+  [(set_attr "type" "csel")
+   (set_attr "predicable" "no")]
+)
+
+(define_insn "*thumb2_csneg"
+  [(set (match_operand:SI 0 "arm_general_register_operand" "=r, r")
+        (if_then_else:SI
+         (match_operand 1 "arm_comparison_operation" "")
+         (neg:SI (match_operand:SI 2 "arm_general_register_operand" "r, r"))
+         (match_operand:SI 3 "reg_or_zero_operand" "r, Pz")))]
+  "TARGET_COND_ARITH"
+  "@
+   csneg\\t%0, %3, %2, %D1
+   csneg\\t%0, zr, %2, %D1"
+  [(set_attr "type" "csel")
+   (set_attr "predicable" "no")]
+)
+
 (define_insn "*thumb2_movcond"
   [(set (match_operand:SI 0 "s_register_operand" "=Ts,Ts,Ts")
        (if_then_else:SI
         (match_operand:SI 1 "arm_rhs_operand" "0,TsI,?TsI")
         (match_operand:SI 2 "arm_rhs_operand" "TsI,0,TsI")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !TARGET_COND_ARITH"
   "*
   if (GET_CODE (operands[5]) == LT
       && (operands[4] == const0_rtx))
   "TARGET_THUMB2 && arm_arch6"
   "@
    sxtb%?\\t%0, %1
-   ldr%(sb%)\\t%0, %1"
+   ldrsb%?\\t%0, %1"
   [(set_attr "type" "extend,load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
    (set_attr "pool_range" "*,4094")
    (set_attr "neg_pool_range" "*,250")]
 )
   "TARGET_THUMB2 && arm_arch6"
   "@
    uxth%?\\t%0, %1
-   ldr%(h%)\\t%0, %1"
+   ldrh%?\\t%0, %1"
   [(set_attr "type" "extend,load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
    (set_attr "pool_range" "*,4094")
    (set_attr "neg_pool_range" "*,250")]
 )
        (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
   "TARGET_THUMB2 && arm_arch6"
   "@
-   uxtb%(%)\\t%0, %1
-   ldr%(b%)\\t%0, %1\\t%@ zero_extendqisi2"
+   uxtb%?\\t%0, %1
+   ldrb%?\\t%0, %1\\t%@ zero_extendqisi2"
   [(set_attr "type" "extend,load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
    (set_attr "pool_range" "*,4094")
    (set_attr "neg_pool_range" "*,250")]
 )
 
-(define_insn "thumb2_casesi_internal"
+(define_expand "thumb2_casesi_internal"
+  [(parallel [(set (pc)
+              (if_then_else
+               (leu (match_operand:SI 0 "s_register_operand")
+                    (match_operand:SI 1 "arm_rhs_operand"))
+               (match_dup 4)
+               (label_ref:SI (match_operand 3 ""))))
+             (clobber (reg:CC CC_REGNUM))
+             (clobber (match_scratch:SI 5))
+             (use (label_ref:SI (match_operand 2 "")))])]
+  "TARGET_THUMB2 && !flag_pic"
+{
+  operands[4] = gen_rtx_MULT (SImode, operands[0], GEN_INT (4));
+  operands[4] = gen_rtx_PLUS (SImode, operands[4],
+                             gen_rtx_LABEL_REF (SImode, operands[2]));
+  operands[4] = gen_rtx_MEM (SImode, operands[4]);
+  MEM_READONLY_P (operands[4]) = 1;
+  MEM_NOTRAP_P (operands[4]) = 1;
+})
+
+(define_insn "*thumb2_casesi_internal"
   [(parallel [(set (pc)
               (if_then_else
                (leu (match_operand:SI 0 "s_register_operand" "r")
                     (match_operand:SI 1 "arm_rhs_operand" "rI"))
                (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
-                                (label_ref (match_operand 2 "" ""))))
-               (label_ref (match_operand 3 "" ""))))
+                                (label_ref:SI (match_operand 2 "" ""))))
+               (label_ref:SI (match_operand 3 "" ""))))
              (clobber (reg:CC CC_REGNUM))
              (clobber (match_scratch:SI 4 "=&r"))
-             (use (label_ref (match_dup 2)))])]
+             (use (label_ref:SI (match_dup 2)))])]
   "TARGET_THUMB2 && !flag_pic"
   "* return thumb2_output_casesi(operands);"
   [(set_attr "conds" "clob")
    (set_attr "type" "multiple")]
 )
 
-(define_insn "thumb2_casesi_internal_pic"
+(define_expand "thumb2_casesi_internal_pic"
+  [(parallel [(set (pc)
+              (if_then_else
+               (leu (match_operand:SI 0 "s_register_operand")
+                    (match_operand:SI 1 "arm_rhs_operand"))
+               (match_dup 4)
+               (label_ref:SI (match_operand 3 ""))))
+             (clobber (reg:CC CC_REGNUM))
+             (clobber (match_scratch:SI 5))
+             (clobber (match_scratch:SI 6))
+             (use (label_ref:SI (match_operand 2 "")))])]
+  "TARGET_THUMB2 && flag_pic"
+{
+  operands[4] = gen_rtx_MULT (SImode, operands[0], GEN_INT (4));
+  operands[4] = gen_rtx_PLUS (SImode, operands[4],
+                             gen_rtx_LABEL_REF (SImode, operands[2]));
+  operands[4] = gen_rtx_MEM (SImode, operands[4]);
+  MEM_READONLY_P (operands[4]) = 1;
+  MEM_NOTRAP_P (operands[4]) = 1;
+})
+
+(define_insn "*thumb2_casesi_internal_pic"
   [(parallel [(set (pc)
               (if_then_else
                (leu (match_operand:SI 0 "s_register_operand" "r")
                     (match_operand:SI 1 "arm_rhs_operand" "rI"))
                (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
-                                (label_ref (match_operand 2 "" ""))))
-               (label_ref (match_operand 3 "" ""))))
+                                (label_ref:SI (match_operand 2 "" ""))))
+               (label_ref:SI (match_operand 3 "" ""))))
              (clobber (reg:CC CC_REGNUM))
              (clobber (match_scratch:SI 4 "=&r"))
              (clobber (match_scratch:SI 5 "=r"))
-             (use (label_ref (match_dup 2)))])]
+             (use (label_ref:SI (match_dup 2)))])]
   "TARGET_THUMB2 && flag_pic"
   "* return thumb2_output_casesi(operands);"
   [(set_attr "conds" "clob")
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_cmse_entry_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 34)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
                    VUNSPEC_EH_RETURN)
    (set_attr "shift" "1")
    (set_attr "length" "2")
    (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-                     (const_string "alu_shift_imm")
+                        (if_then_else (match_operand 3 "alu_shift_operator_lsl_1_to_4")
+                          (const_string "alu_shift_imm_lsl_1to4")
+                          (const_string "alu_shift_imm_other"))
                      (const_string "alu_shift_reg")))]
 )
 
 )
 
 (define_insn "thumb2_addsi3_compare0"
-  [(set (reg:CC_NOOV CC_REGNUM)
-       (compare:CC_NOOV
+  [(set (reg:CC_NZ CC_REGNUM)
+       (compare:CC_NZ
          (plus:SI (match_operand:SI 1 "s_register_operand" "l,  0, r")
                   (match_operand:SI 2 "arm_add_operand"    "lPt,Ps,rIL"))
          (const_int 0)))
 )
 
 (define_insn "*thumb2_addsi3_compare0_scratch"
-  [(set (reg:CC_NOOV CC_REGNUM)
-       (compare:CC_NOOV
+  [(set (reg:CC_NZ CC_REGNUM)
+       (compare:CC_NZ
          (plus:SI (match_operand:SI 0 "s_register_operand" "l,  r")
                   (match_operand:SI 1 "arm_add_operand"    "lPv,rIL"))
          (const_int 0)))]
    (set_attr "type" "muls")])
 
 (define_insn "*thumb2_mulsi_short_compare0"
-  [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ
          (mult:SI (match_operand:SI 1 "register_operand" "%0")
                  (match_operand:SI 2 "register_operand" "l"))
          (const_int 0)))
    (set_attr "type" "muls")])
 
 (define_insn "*thumb2_mulsi_short_compare0_scratch"
-  [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV
+  [(set (reg:CC_NZ CC_REGNUM)
+        (compare:CC_NZ
          (mult:SI (match_operand:SI 1 "register_operand" "%0")
                  (match_operand:SI 2 "register_operand" "l"))
          (const_int 0)))
        (neg:SI (match_operand:SI 1 "low_register_operand" "l")))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_THUMB2 && reload_completed"
-  "neg%!\t%0, %1"
+  "rsb%!\t%0, %1, #0"
   [(set_attr "predicable" "yes")
    (set_attr "length" "2")
    (set_attr "type" "alu_sreg")]
 )
 
-; Constants for op 2 will never be given to these patterns.
-(define_insn_and_split "*iordi_notdi_di"
-  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
-       (ior:DI (not:DI (match_operand:DI 1 "s_register_operand" "0,r"))
-               (match_operand:DI 2 "s_register_operand" "r,0")))]
-  "TARGET_THUMB2"
-  "#"
-  "TARGET_THUMB2 && reload_completed"
-  [(set (match_dup 0) (ior:SI (not:SI (match_dup 1)) (match_dup 2)))
-   (set (match_dup 3) (ior:SI (not:SI (match_dup 4)) (match_dup 5)))]
-  "
-  {
-    operands[3] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[4] = gen_highpart (SImode, operands[1]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-    operands[5] = gen_highpart (SImode, operands[2]);
-    operands[2] = gen_lowpart (SImode, operands[2]);
-  }"
-  [(set_attr "length" "8")
-   (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "type" "multiple")]
-)
-
-(define_insn_and_split "*iordi_notzesidi_di"
-  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
-       (ior:DI (not:DI (zero_extend:DI
-                        (match_operand:SI 2 "s_register_operand" "r,r")))
-               (match_operand:DI 1 "s_register_operand" "0,?r")))]
-  "TARGET_THUMB2"
-  "#"
-  ; (not (zero_extend...)) means operand0 will always be 0xffffffff
-  "TARGET_THUMB2 && reload_completed"
-  [(set (match_dup 0) (ior:SI (not:SI (match_dup 2)) (match_dup 1)))
-   (set (match_dup 3) (const_int -1))]
-  "
-  {
-    operands[3] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-  }"
-  [(set_attr "length" "4,8")
-   (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "type" "multiple")]
-)
-
-(define_insn_and_split "*iordi_notdi_zesidi"
-  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
-       (ior:DI (not:DI (match_operand:DI 2 "s_register_operand" "0,?r"))
-               (zero_extend:DI
-                (match_operand:SI 1 "s_register_operand" "r,r"))))]
-  "TARGET_THUMB2"
-  "#"
-  "TARGET_THUMB2 && reload_completed"
-  [(set (match_dup 0) (ior:SI (not:SI (match_dup 2)) (match_dup 1)))
-   (set (match_dup 3) (not:SI (match_dup 4)))]
-  "
-  {
-    operands[3] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-    operands[4] = gen_highpart (SImode, operands[2]);
-    operands[2] = gen_lowpart (SImode, operands[2]);
-  }"
-  [(set_attr "length" "8")
-   (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "type" "multiple")]
-)
-
-(define_insn_and_split "*iordi_notsesidi_di"
-  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
-       (ior:DI (not:DI (sign_extend:DI
-                        (match_operand:SI 2 "s_register_operand" "r,r")))
-               (match_operand:DI 1 "s_register_operand" "0,r")))]
-  "TARGET_THUMB2"
-  "#"
-  "TARGET_THUMB2 && reload_completed"
-  [(set (match_dup 0) (ior:SI (not:SI (match_dup 2)) (match_dup 1)))
-   (set (match_dup 3) (ior:SI (not:SI
-                               (ashiftrt:SI (match_dup 2) (const_int 31)))
-                              (match_dup 4)))]
-  "
-  {
-    operands[3] = gen_highpart (SImode, operands[0]);
-    operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[4] = gen_highpart (SImode, operands[1]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-  }"
-  [(set_attr "length" "8")
-   (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "type" "multiple")]
-)
-
 (define_insn "*orsi_notsi_si"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (ior:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
   "TARGET_THUMB2"
   "orn%?\\t%0, %1, %2"
   [(set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
    (set_attr "type" "logic_reg")]
 )
 
   "TARGET_THUMB2"
   "orn%?\\t%0, %1, %2%S4"
   [(set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
    (set_attr "shift" "2")
-   (set_attr "type" "alu_shift_imm")]
+   (set_attr "autodetect_type" "alu_shift_operator4")]
 )
 
 (define_peephole2
-  [(set (match_operand:CC_NOOV 0 "cc_register" "")
-       (compare:CC_NOOV (zero_extract:SI
+  [(set (match_operand:CC_NZ 0 "cc_register" "")
+       (compare:CC_NZ (zero_extract:SI
                          (match_operand:SI 1 "low_register_operand" "")
                          (const_int 1)
                          (match_operand:SI 2 "const_int_operand" ""))
                         (const_int 0)))
    (match_scratch:SI 3 "l")
    (set (pc)
-       (if_then_else (match_operator:CC_NOOV 4 "equality_operator"
+       (if_then_else (match_operator:CC_NZ 4 "equality_operator"
                       [(match_dup 0) (const_int 0)])
                      (match_operand 5 "" "")
                      (match_operand 6 "" "")))]
   "TARGET_THUMB2
-   && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32)"
+   && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32)
+   && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(set (match_dup 0)
-                  (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
+                  (compare:CC_NZ (ashift:SI (match_dup 1) (match_dup 2))
                                    (const_int 0)))
              (clobber (match_dup 3))])
    (set (pc)
   ")
 
 (define_peephole2
-  [(set (match_operand:CC_NOOV 0 "cc_register" "")
-       (compare:CC_NOOV (zero_extract:SI
+  [(set (match_operand:CC_NZ 0 "cc_register" "")
+       (compare:CC_NZ (zero_extract:SI
                          (match_operand:SI 1 "low_register_operand" "")
                          (match_operand:SI 2 "const_int_operand" "")
                          (const_int 0))
                         (const_int 0)))
    (match_scratch:SI 3 "l")
    (set (pc)
-       (if_then_else (match_operator:CC_NOOV 4 "equality_operator"
+       (if_then_else (match_operator:CC_NZ 4 "equality_operator"
                       [(match_dup 0) (const_int 0)])
                      (match_operand 5 "" "")
                      (match_operand 6 "" "")))]
   "TARGET_THUMB2
-   && (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 32)"
+   && (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 32)
+   && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(set (match_dup 0)
-                  (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
-                                   (const_int 0)))
+                  (compare:CC_NZ (ashift:SI (match_dup 1) (match_dup 2))
+                                 (const_int 0)))
              (clobber (match_dup 3))])
    (set (pc)
        (if_then_else (match_op_dup 4 [(match_dup 0) (const_int 0)])
       using a certain 'count' register and (2) the loop count can be
       adjusted by modifying this register prior to the loop.
       ??? The possible introduction of a new block to initialize the
-      new IV can potentially affect branch optimizations.  */
-   if (optimize > 0 && flag_modulo_sched)
+      new IV can potentially affect branch optimizations.
+
+      Also used to implement the low over head loops feature, which is part of
+      the Armv8.1-M Mainline Low Overhead Branch (LOB) extension.  */
+   if (optimize > 0 && (flag_modulo_sched || TARGET_HAVE_LOB))
    {
      rtx s0;
      rtx bcomp;
        FAIL;
 
      s0 = operands [0];
+
+     /* Low over head loop instructions require the first operand to be LR.  */
+     if (TARGET_HAVE_LOB && arm_target_insn_ok_for_lob (operands [1]))
+       s0 = gen_rtx_REG (SImode, LR_REGNUM);
+
      if (TARGET_THUMB2)
        insn = emit_insn (gen_thumb2_addsi3_compare0 (s0, s0, GEN_INT (-1)));
      else
                                   gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
                                                         loc_ref, pc_rtx)));
      DONE;
-   }else
-      FAIL;
+   }
+ else
+   FAIL;
  }")
 
+(define_insn "*clear_apsr"
+  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)
+  (clobber (reg:CC CC_REGNUM))]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  "clrm%?\\t{APSR}"
+  [(set_attr "predicable" "yes")]
+)
+
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_multiple"
+  [(match_parallel 0 "clear_multiple_operation"
+     [(set (match_operand:SI 1 "register_operand" "")
+          (const_int 0))])]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
+  {
+    char pattern[100];
+    int i, num_saves = XVECLEN (operands[0], 0);
+
+    strcpy (pattern, \"clrm%?\\t{\");
+    for (i = 0; i < num_saves; i++)
+      {
+       if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
+         {
+           strcat (pattern, \"APSR\");
+           ++i;
+         }
+       else
+         strcat (pattern,
+                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+       if (i < num_saves - 1)
+         strcat (pattern, \", %|\");
+      }
+    strcat (pattern, \"}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")]
+)
+
+(define_insn "thumb2_asrl"
+  [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
+       (ashiftrt:DI (match_dup 0)
+                    (match_operand:SI 1 "arm_reg_or_long_shift_imm" "rPg")))]
+  "TARGET_HAVE_MVE"
+  "asrl%?\\t%Q0, %R0, %1"
+  [(set_attr "predicable" "yes")])
+
+(define_insn "thumb2_lsll"
+  [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
+       (ashift:DI (match_dup 0)
+                  (match_operand:SI 1 "arm_reg_or_long_shift_imm" "rPg")))]
+  "TARGET_HAVE_MVE"
+  "lsll%?\\t%Q0, %R0, %1"
+  [(set_attr "predicable" "yes")])
+
+(define_insn "thumb2_lsrl"
+  [(set (match_operand:DI 0 "arm_general_register_operand" "+r")
+       (lshiftrt:DI (match_dup 0)
+                    (match_operand:SI 1 "long_shift_imm" "Pg")))]
+  "TARGET_HAVE_MVE"
+  "lsrl%?\\t%Q0, %R0, %1"
+  [(set_attr "predicable" "yes")])
+
+;; Originally expanded by 'doloop_end'.
+(define_insn "*doloop_end_internal"
+  [(set (pc)
+        (if_then_else
+            (ne (reg:SI LR_REGNUM) (const_int 1))
+          (label_ref (match_operand 0 "" ""))
+          (pc)))
+   (set (reg:SI LR_REGNUM)
+        (plus:SI (reg:SI LR_REGNUM) (const_int -1)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_32BIT && TARGET_HAVE_LOB"
+  {
+    if (get_attr_length (insn) == 4)
+      return "le\t%|lr, %l0";
+    else
+      return "subs\t%|lr, #1;bne\t%l0";
+  }
+  [(set (attr "length")
+        (if_then_else
+            (ltu (minus (pc) (match_dup 0)) (const_int 1024))
+           (const_int 4)
+           (const_int 6)))
+   (set_attr "type" "branch")])
+
+(define_expand "doloop_begin"
+  [(match_operand 0 "" "")
+   (match_operand 1 "" "")]
+  "TARGET_32BIT && TARGET_HAVE_LOB"
+  {
+    if (REGNO (operands[0]) == LR_REGNUM)
+      {
+       emit_insn (gen_dls_insn (operands[0]));
+       DONE;
+      }
+    else
+      FAIL;
+  })
+
+(define_insn "dls_insn"
+  [(set (reg:SI LR_REGNUM)
+        (unspec:SI [(match_operand:SI 0 "s_register_operand" "r")] UNSPEC_DLS))]
+  "TARGET_32BIT && TARGET_HAVE_LOB"
+  "dls\t%|lr, %0")