]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/aarch64/aarch64.md
aarch64: Fix up casesi patterns for purecap
[gcc.git] / gcc / config / aarch64 / aarch64.md
index 1d8226d3efa4cb34b382806efebba1d2954fd13f..d885eb8de3e464bed961603435dac3f8373e71b5 100644 (file)
@@ -1,5 +1,5 @@
 ;; Machine description for AArch64 architecture.
-;; Copyright (C) 2009-2019 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2020 Free Software Foundation, Inc.
 ;; Contributed by ARM Ltd.
 ;;
 ;; This file is part of GCC.
     (R11_REGNUM                11)
     (R12_REGNUM                12)
     (R13_REGNUM                13)
-    ;; Scratch registers for prologue/epilogue use.
-    (EP0_REGNUM                12)
-    (EP1_REGNUM                13)
     (R14_REGNUM                14)
     (R15_REGNUM                15)
     (R16_REGNUM                16)
-    (IP0_REGNUM                16)
     (R17_REGNUM                17)
-    (IP1_REGNUM                17)
     (R18_REGNUM                18)
     (R19_REGNUM                19)
     (R20_REGNUM                20)
@@ -57,7 +52,6 @@
     (R28_REGNUM                28)
     (R29_REGNUM                29)
     (R30_REGNUM                30)
-    (LR_REGNUM         30)
     (SP_REGNUM         31)
     (V0_REGNUM         32)
     (V1_REGNUM         33)
@@ -91,7 +85,6 @@
     (V29_REGNUM                61)
     (V30_REGNUM                62)
     (V31_REGNUM                63)
-    (LAST_SAVED_REGNUM 63)
     (SFP_REGNUM                64)
     (AP_REGNUM         65)
     (CC_REGNUM         66)
     (P13_REGNUM                81)
     (P14_REGNUM                82)
     (P15_REGNUM                83)
+    (LAST_SAVED_REGNUM 83)
+    (FFR_REGNUM                84)
+    ;; "FFR token": a fake register used for representing the scheduling
+    ;; restrictions on FFR-related operations.
+    (FFRT_REGNUM       85)
+    ;; Scratch register used by stack clash protection to calculate
+    ;; SVE CFA offsets during probing.
+    (STACK_CLASH_SVE_CFA_REGNUM 11)
+    ;; Scratch registers for prologue/epilogue use.
+    (EP0_REGNUM         12)
+    (EP1_REGNUM         13)
     ;; A couple of call-clobbered registers that we need to reserve when
     ;; tracking speculation this is not ABI, so is subject to change.
-    (SPECULATION_TRACKER_REGNUM 15)
     (SPECULATION_SCRATCH_REGNUM 14)
+    (SPECULATION_TRACKER_REGNUM 15)
+    ;; Scratch registers used in frame layout.
+    (IP0_REGNUM         16)
+    (IP1_REGNUM         17)
+    (FP_REGNUM         29)
+    (LR_REGNUM          30)
   ]
 )
 
 (define_c_enum "unspec" [
-    UNSPEC_AUTI1716
-    UNSPEC_AUTISP
+    UNSPEC_AUTIA1716
+    UNSPEC_AUTIB1716
+    UNSPEC_AUTIASP
+    UNSPEC_AUTIBSP
+    UNSPEC_CALLEE_ABI
     UNSPEC_CASESI
     UNSPEC_CRC32B
     UNSPEC_CRC32CB
     UNSPEC_CRC32X
     UNSPEC_FCVTZS
     UNSPEC_FCVTZU
+    UNSPEC_FJCVTZS
+    UNSPEC_FRINT32Z
+    UNSPEC_FRINT32X
+    UNSPEC_FRINT64Z
+    UNSPEC_FRINT64X
     UNSPEC_URECPE
     UNSPEC_FRECPE
     UNSPEC_FRECPS
     UNSPEC_LD4_LANE
     UNSPEC_MB
     UNSPEC_NOP
-    UNSPEC_PACI1716
-    UNSPEC_PACISP
+    UNSPEC_PACIA1716
+    UNSPEC_PACIB1716
+    UNSPEC_PACIASP
+    UNSPEC_PACIBSP
     UNSPEC_PRLG_STK
     UNSPEC_REV
     UNSPEC_RBIT
     UNSPEC_UCVTF
     UNSPEC_USHL_2S
     UNSPEC_VSTRUCTDUMMY
+    UNSPEC_SSP_SYSREG
     UNSPEC_SP_SET
     UNSPEC_SP_TEST
     UNSPEC_RSQRT
     UNSPEC_XPACLRI
     UNSPEC_LD1_SVE
     UNSPEC_ST1_SVE
+    UNSPEC_LDNT1_SVE
+    UNSPEC_STNT1_SVE
     UNSPEC_LD1RQ
     UNSPEC_LD1_GATHER
+    UNSPEC_LDFF1_GATHER
+    UNSPEC_LDNT1_GATHER
     UNSPEC_ST1_SCATTER
-    UNSPEC_MERGE_PTRUE
-    UNSPEC_PTEST_PTRUE
+    UNSPEC_STNT1_SCATTER
+    UNSPEC_PRED_X
+    UNSPEC_PRED_Z
+    UNSPEC_PTEST
+    UNSPEC_PTRUE
     UNSPEC_UNPACKSHI
     UNSPEC_UNPACKUHI
     UNSPEC_UNPACKSLO
     UNSPEC_UNPACKULO
     UNSPEC_PACK
-    UNSPEC_FLOAT_CONVERT
-    UNSPEC_WHILE_LO
+    UNSPEC_WHILEGE
+    UNSPEC_WHILEGT
+    UNSPEC_WHILEHI
+    UNSPEC_WHILEHS
+    UNSPEC_WHILELE
+    UNSPEC_WHILELO
+    UNSPEC_WHILELS
+    UNSPEC_WHILELT
+    UNSPEC_WHILERW
+    UNSPEC_WHILEWR
     UNSPEC_LDN
     UNSPEC_STN
     UNSPEC_INSR
+    UNSPEC_CLASTA
     UNSPEC_CLASTB
     UNSPEC_FADDA
     UNSPEC_REV_SUBREG
+    UNSPEC_REINTERPRET
     UNSPEC_SPECULATION_TRACKER
+    UNSPEC_SPECULATION_TRACKER_REV
     UNSPEC_COPYSIGN
+    UNSPEC_TTEST               ; Represent transaction test.
+    UNSPEC_UPDATE_FFR
+    UNSPEC_UPDATE_FFRT
+    UNSPEC_RDFFR
+    UNSPEC_WRFFR
+    ;; Represents an SVE-style lane index, in which the indexing applies
+    ;; within the containing 128-bit block.
+    UNSPEC_SVE_LANE_SELECT
+    UNSPEC_SVE_CNT_PAT
+    UNSPEC_SVE_PREFETCH
+    UNSPEC_SVE_PREFETCH_GATHER
+    UNSPEC_SVE_COMPACT
+    UNSPEC_SVE_SPLICE
+    UNSPEC_GEN_TAG             ; Generate a 4-bit MTE tag.
+    UNSPEC_GEN_TAG_RND         ; Generate a random 4-bit MTE tag.
+    UNSPEC_TAG_SPACE           ; Translate address to MTE tag address space.
+    UNSPEC_LD1RO
 ])
 
 (define_c_enum "unspecv" [
     UNSPECV_BLOCKAGE           ; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE  ; Represent stack range probing.
     UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
+    UNSPECV_BTI_NOARG          ; Represent BTI.
+    UNSPECV_BTI_C              ; Represent BTI c.
+    UNSPECV_BTI_J              ; Represent BTI j.
+    UNSPECV_BTI_JC             ; Represent BTI jc.
+    UNSPECV_TSTART             ; Represent transaction start.
+    UNSPECV_TCOMMIT            ; Represent transaction commit.
+    UNSPECV_TCANCEL            ; Represent transaction cancel.
+    UNSPEC_RNDR                        ; Represent RNDR
+    UNSPEC_RNDRRS              ; Represent RNDRRS
   ]
 )
 
+;; These constants are used as a const_int in various SVE unspecs
+;; to indicate whether the governing predicate is known to be a PTRUE.
+(define_constants
+  [; Indicates that the predicate might not be a PTRUE.
+   (SVE_MAYBE_NOT_PTRUE 0)
+
+   ; Indicates that the predicate is known to be a PTRUE.
+   (SVE_KNOWN_PTRUE 1)])
+
+;; These constants are used as a const_int in predicated SVE FP arithmetic
+;; to indicate whether the operation is allowed to make additional lanes
+;; active without worrying about the effect on faulting behavior.
+(define_constants
+  [; Indicates either that all lanes are active or that the instruction may
+   ; operate on inactive inputs even if doing so could induce a fault.
+   (SVE_RELAXED_GP 0)
+
+   ; Indicates that some lanes might be inactive and that the instruction
+   ; must not operate on inactive inputs if doing so could induce a fault.
+   (SVE_STRICT_GP 1)])
+
 ;; If further include files are added the defintion of MD_INCLUDES
 ;; must be updated.
 
 ;; Attribute that specifies whether the alternative uses MOVPRFX.
 (define_attr "movprfx" "no,yes" (const_string "no"))
 
+;; Attribute to specify that an alternative has the length of a single
+;; instruction plus a speculation barrier.
+(define_attr "sls_length" "none,retbr,casesi" (const_string "none"))
+
 (define_attr "length" ""
   (cond [(eq_attr "movprfx" "yes")
            (const_int 8)
-        ] (const_int 4)))
+
+        (eq_attr "sls_length" "retbr")
+          (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 4)
+                 (match_test "TARGET_SB") (const_int 8)]
+                (const_int 12))
+
+        (eq_attr "sls_length" "casesi")
+          (cond [(match_test "!aarch64_harden_sls_retbr_p ()") (const_int 16)
+                 (match_test "TARGET_SB") (const_int 20)]
+                (const_int 24))
+       ]
+         (const_int 4)))
 
 ;; Strictly for compatibility with AArch32 in pipeline models, since AArch64 has
 ;; no predicated insns.
 (include "thunderx.md")
 (include "../arm/xgene1.md")
 (include "thunderx2t99.md")
+(include "tsv110.md")
+(include "thunderx3t110.md")
 
 ;; -------------------------------------------------------------------
 ;; Jumps and other miscellaneous insns
 ;; -------------------------------------------------------------------
 
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:DI 0 "register_operand" "r"))]
+  [(set (pc) (match_operand 0 "pmode_register_operand" "r"))]
   ""
-  "br\\t%0"
-  [(set_attr "type" "branch")]
+  {
+    output_asm_insn ("br\\t%0", operands);
+    return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+  }
+  [(set_attr "type" "branch")
+   (set_attr "sls_length" "retbr")]
 )
 
 (define_insn "jump"
 
 (define_expand "cbranch<mode>4"
   [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator"
-                           [(match_operand:GPI 1 "register_operand" "")
-                            (match_operand:GPI 2 "aarch64_plus_operand" "")])
+                           [(match_operand:GPI 1 "register_operand")
+                            (match_operand:GPI 2 "aarch64_plus_operand")])
                           (label_ref (match_operand 3 "" ""))
                           (pc)))]
   ""
 
 (define_expand "cbranch<mode>4"
   [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator"
-                           [(match_operand:GPF 1 "register_operand" "")
-                            (match_operand:GPF 2 "aarch64_fp_compare_operand" "")])
+                           [(match_operand:GPF 1 "register_operand")
+                            (match_operand:GPF 2 "aarch64_fp_compare_operand")])
                           (label_ref (match_operand 3 "" ""))
                           (pc)))]
   ""
 (define_expand "cbranchcc4"
   [(set (pc) (if_then_else
              (match_operator 0 "aarch64_comparison_operator"
-              [(match_operand 1 "cc_register" "")
+              [(match_operand 1 "cc_register")
                (match_operand 2 "const0_operand")])
              (label_ref (match_operand 3 "" ""))
              (pc)))]
   ""
   "")
 
-(define_insn "ccmp<mode>"
-  [(set (match_operand:CC 1 "cc_register" "")
-       (if_then_else:CC
+(define_insn "@ccmp<CC_ONLY:mode><GPI:mode>"
+  [(set (match_operand:CC_ONLY 1 "cc_register" "")
+       (if_then_else:CC_ONLY
          (match_operator 4 "aarch64_comparison_operator"
           [(match_operand 0 "cc_register" "")
            (const_int 0)])
-         (compare:CC
+         (compare:CC_ONLY
            (match_operand:GPI 2 "register_operand" "r,r,r")
            (match_operand:GPI 3 "aarch64_ccmp_operand" "r,Uss,Usn"))
-         (unspec:CC [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+         (unspec:CC_ONLY
+           [(match_operand 5 "immediate_operand")]
+           UNSPEC_NZCV)))]
   ""
   "@
    ccmp\\t%<w>2, %<w>3, %k5, %m4
   [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
-(define_insn "fccmp<mode>"
-  [(set (match_operand:CCFP 1 "cc_register" "")
-       (if_then_else:CCFP
+(define_insn "@ccmp<CCFP_CCFPE:mode><GPF:mode>"
+  [(set (match_operand:CCFP_CCFPE 1 "cc_register" "")
+       (if_then_else:CCFP_CCFPE
          (match_operator 4 "aarch64_comparison_operator"
           [(match_operand 0 "cc_register" "")
            (const_int 0)])
-         (compare:CCFP
+         (compare:CCFP_CCFPE
            (match_operand:GPF 2 "register_operand" "w")
            (match_operand:GPF 3 "register_operand" "w"))
-         (unspec:CCFP [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+         (unspec:CCFP_CCFPE
+           [(match_operand 5 "immediate_operand")]
+           UNSPEC_NZCV)))]
   "TARGET_FLOAT"
-  "fccmp\\t%<s>2, %<s>3, %k5, %m4"
+  "fccmp<e>\\t%<s>2, %<s>3, %k5, %m4"
   [(set_attr "type" "fccmp<s>")]
 )
 
-(define_insn "fccmpe<mode>"
-  [(set (match_operand:CCFPE 1 "cc_register" "")
-        (if_then_else:CCFPE
+(define_insn "@ccmp<CC_ONLY:mode><GPI:mode>_rev"
+  [(set (match_operand:CC_ONLY 1 "cc_register" "")
+       (if_then_else:CC_ONLY
          (match_operator 4 "aarch64_comparison_operator"
           [(match_operand 0 "cc_register" "")
-         (const_int 0)])
-          (compare:CCFPE
+           (const_int 0)])
+         (unspec:CC_ONLY
+           [(match_operand 5 "immediate_operand")]
+           UNSPEC_NZCV)
+         (compare:CC_ONLY
+           (match_operand:GPI 2 "register_operand" "r,r,r")
+           (match_operand:GPI 3 "aarch64_ccmp_operand" "r,Uss,Usn"))))]
+  ""
+  "@
+   ccmp\\t%<w>2, %<w>3, %k5, %M4
+   ccmp\\t%<w>2, %3, %k5, %M4
+   ccmn\\t%<w>2, #%n3, %k5, %M4"
+  [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
+)
+
+(define_insn "@ccmp<CCFP_CCFPE:mode><GPF:mode>_rev"
+  [(set (match_operand:CCFP_CCFPE 1 "cc_register" "")
+       (if_then_else:CCFP_CCFPE
+         (match_operator 4 "aarch64_comparison_operator"
+          [(match_operand 0 "cc_register" "")
+           (const_int 0)])
+         (unspec:CCFP_CCFPE
+           [(match_operand 5 "immediate_operand")]
+           UNSPEC_NZCV)
+         (compare:CCFP_CCFPE
            (match_operand:GPF 2 "register_operand" "w")
-           (match_operand:GPF 3 "register_operand" "w"))
-         (unspec:CCFPE [(match_operand 5 "immediate_operand")] UNSPEC_NZCV)))]
+           (match_operand:GPF 3 "register_operand" "w"))))]
   "TARGET_FLOAT"
-  "fccmpe\\t%<s>2, %<s>3, %k5, %m4"
+  "fccmp<e>\\t%<s>2, %<s>3, %k5, %M4"
   [(set_attr "type" "fccmp<s>")]
 )
 
 ;; csneg  x0, x0, x1, mi
 
 (define_expand "mod<mode>3"
-  [(match_operand:GPI 0 "register_operand" "")
-   (match_operand:GPI 1 "register_operand" "")
-   (match_operand:GPI 2 "const_int_operand" "")]
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "register_operand")
+   (match_operand:GPI 2 "const_int_operand")]
   ""
   {
     HOST_WIDE_INT val = INTVAL (operands[2]);
                           (pc)))]
   ""
   {
+    /* GCC's traditional style has been to use "beq" instead of "b.eq", etc.,
+       but the "." is required for SVE conditions.  */
+    bool use_dot_p = GET_MODE (operands[1]) == CC_NZCmode;
     if (get_attr_length (insn) == 8)
-      return aarch64_gen_far_branch (operands, 2, "Lbcond", "b%M0\\t");
+      return aarch64_gen_far_branch (operands, 2, "Lbcond",
+                                    use_dot_p ? "b.%M0\\t" : "b%M0\\t");
     else
-      return  "b%m0\\t%l2";
+      return use_dot_p ? "b.%m0\\t%l2" : "b%m0\\t%l2";
   }
   [(set_attr "type" "branch")
    (set (attr "length")
 ;;     sub     x0, x1, #(CST & 0xfff000)
 ;;     subs    x0, x0, #(CST & 0x000fff)
 ;;     b<ne,eq> .Label
-(define_insn_and_split "*compare_condjump<mode>"
+(define_insn_and_split "*compare_condjump<GPI:mode>"
   [(set (pc) (if_then_else (EQL
                              (match_operand:GPI 0 "register_operand" "r")
                              (match_operand:GPI 1 "aarch64_imm24" "n"))
                           (label_ref:P (match_operand 2 "" ""))
                           (pc)))]
-  "!aarch64_move_imm (INTVAL (operands[1]), <MODE>mode)
-   && !aarch64_plus_operand (operands[1], <MODE>mode)
+  "!aarch64_move_imm (INTVAL (operands[1]), <GPI:MODE>mode)
+   && !aarch64_plus_operand (operands[1], <GPI:MODE>mode)
    && !reload_completed"
   "#"
   "&& true"
   {
     HOST_WIDE_INT lo_imm = UINTVAL (operands[1]) & 0xfff;
     HOST_WIDE_INT hi_imm = UINTVAL (operands[1]) & 0xfff000;
-    rtx tmp = gen_reg_rtx (<MODE>mode);
-    emit_insn (gen_add<mode>3 (tmp, operands[0], GEN_INT (-hi_imm)));
-    emit_insn (gen_add<mode>3_compare0 (tmp, tmp, GEN_INT (-lo_imm)));
+    rtx tmp = gen_reg_rtx (<GPI:MODE>mode);
+    emit_insn (gen_add<GPI:mode>3 (tmp, operands[0], GEN_INT (-hi_imm)));
+    emit_insn (gen_add<GPI:mode>3_compare0 (tmp, tmp, GEN_INT (-lo_imm)));
     rtx cc_reg = gen_rtx_REG (CC_NZmode, CC_REGNUM);
-    rtx cmp_rtx = gen_rtx_fmt_ee (<EQL:CMP>, <MODE>mode, cc_reg, const0_rtx);
+    rtx cmp_rtx = gen_rtx_fmt_ee (<EQL:CMP>, <GPI:MODE>mode,
+                                 cc_reg, const0_rtx);
     emit_jump_insn (gen_condjump (cmp_rtx, cc_reg, operands[2]));
     DONE;
   }
 )
 
 (define_expand "casesi"
-  [(match_operand:SI 0 "register_operand" "")  ; Index
-   (match_operand:SI 1 "const_int_operand" "") ; Lower bound
-   (match_operand:SI 2 "const_int_operand" "") ; Total range
+  [(match_operand:SI 0 "register_operand")     ; Index
+   (match_operand:SI 1 "const_int_operand")    ; Lower bound
+   (match_operand:SI 2 "const_int_operand")    ; Total range
    (match_operand:DI 3 "" "")                  ; Table label
    (match_operand:DI 4 "" "")]                 ; Out of range label
   ""
                                                 const0_rtx),
                                    operands[0], operands[2], operands[4]));
 
-    operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[3]));
-    emit_jump_insn (gen_casesi_dispatch (operands[2], operands[0],
-                                        operands[3]));
+    operands[2] = force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, operands[3]));
+    operands[2]
+      = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, operands[2], operands[0]),
+                       UNSPEC_CASESI);
+    operands[2] = gen_rtx_MEM (Pmode, operands[2]);
+    MEM_READONLY_P (operands[2]) = 1;
+    MEM_NOTRAP_P (operands[2]) = 1;
+
+    emit_jump_insn (gen_casesi_dispatch (Pmode, operands[2], operands[3]));
     DONE;
   }
 )
 
-(define_insn "casesi_dispatch"
+(define_expand "@casesi_dispatch<mode>"
+  [(parallel
+    [(set (pc) (match_operand:ADDR 0 ""))
+     (clobber (reg:CC CC_REGNUM))
+     (clobber (match_scratch:ADDR 2))
+     (clobber (match_scratch:ADDR 3))
+     (use (label_ref:ADDR (match_operand 1 "")))])]
+  "")
+
+(define_insn "*casesi_dispatch"
   [(parallel
     [(set (pc)
-         (mem:DI (unspec [(match_operand:DI 0 "register_operand" "r")
-                          (match_operand:SI 1 "register_operand" "r")]
+         (mem:ADDR (unspec [(match_operand:ADDR 0 "register_operand" "r")
+                            (match_operand:SI 1 "register_operand" "r")]
                        UNSPEC_CASESI)))
      (clobber (reg:CC CC_REGNUM))
-     (clobber (match_scratch:DI 3 "=r"))
-     (clobber (match_scratch:DI 4 "=r"))
-     (use (label_ref (match_operand 2 "" "")))])]
+     (clobber (match_scratch:ADDR 3 "=r"))
+     (clobber (match_scratch:ADDR 4 "=r"))
+     (use (label_ref:ADDR (match_operand 2 "" "")))])]
   ""
   "*
   return aarch64_output_casesi (operands);
   "
-  [(set_attr "length" "16")
+  [(set_attr "sls_length" "casesi")
    (set_attr "type" "branch")]
 )
 
   [(return)]
   ""
   {
+    const char *ret = NULL;
     if (aarch64_return_address_signing_enabled ()
        && TARGET_ARMV8_3
        && !crtl->calls_eh_return)
-      return "retaa";
-
-    return "ret";
+      {
+       if (aarch64_ra_sign_key == AARCH64_KEY_B)
+         ret = "retab";
+       else
+         ret = "retaa";
+      }
+    else
+      ret = "ret";
+    output_asm_insn (ret, operands);
+    return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
   }
-  [(set_attr "type" "branch")]
+  [(set_attr "type" "branch")
+   (set_attr "sls_length" "retbr")]
 )
 
 (define_expand "return"
 
 (define_insn "simple_return"
   [(simple_return)]
-  "aarch64_use_simple_return_insn_p ()"
-  "ret"
-  [(set_attr "type" "branch")]
+  ""
+  {
+    output_asm_insn ("ret", operands);
+    return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+  }
+  [(set_attr "type" "branch")
+   (set_attr "sls_length" "retbr")]
 )
 
 (define_insn "*cb<optab><mode>1"
 ;; -------------------------------------------------------------------
 
 (define_expand "call"
-  [(parallel [(call (match_operand 0 "memory_operand" "")
-                   (match_operand 1 "general_operand" ""))
-             (use (match_operand 2 "" ""))
-             (clobber (reg:DI LR_REGNUM))])]
+  [(parallel
+     [(call (match_operand 0 "memory_operand")
+           (match_operand 1 "general_operand"))
+      (unspec:DI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
+      (clobber (reg:DI LR_REGNUM))])]
   ""
   "
   {
-    aarch64_expand_call (NULL_RTX, operands[0], false);
+    aarch64_expand_call (NULL_RTX, operands[0], operands[2], false);
     DONE;
   }"
 )
 
 (define_insn "*call_insn"
-  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "r, Usf"))
+  [(call (mem:DI (match_operand:ADDR 0 "aarch64_call_insn_operand" "Ucr, Usf"))
         (match_operand 1 "" ""))
-   (clobber (reg:DI LR_REGNUM))]
+   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
+   (clobber (reg:ADDR LR_REGNUM))]
   ""
   "@
-  blr\\t%0
+  * return aarch64_indirect_call_asm (operands[0]);
   bl\\t%c0"
-  [(set_attr "type" "call, call")]
-)
+  [(set_attr "type" "call, call")])
 
 (define_expand "call_value"
-  [(parallel [(set (match_operand 0 "" "")
-                  (call (match_operand 1 "memory_operand" "")
-                        (match_operand 2 "general_operand" "")))
-             (use (match_operand 3 "" ""))
-             (clobber (reg:DI LR_REGNUM))])]
+  [(parallel
+     [(set (match_operand 0 "")
+          (call (match_operand 1 "memory_operand")
+                (match_operand 2 "general_operand")))
+     (unspec:DI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_ABI)
+     (clobber (reg:DI LR_REGNUM))])]
   ""
   "
   {
-    aarch64_expand_call (operands[0], operands[1], false);
+    aarch64_expand_call (operands[0], operands[1], operands[3], false);
     DONE;
   }"
 )
 
 (define_insn "*call_value_insn"
   [(set (match_operand 0 "" "")
-       (call (mem:DI (match_operand:DI 1 "aarch64_call_insn_operand" "r, Usf"))
+       (call (mem:DI (match_operand:ADDR 1 "aarch64_call_insn_operand" "Ucr, Usf"))
                      (match_operand 2 "" "")))
-   (clobber (reg:DI LR_REGNUM))]
+   (unspec:DI [(match_operand:DI 3 "const_int_operand")] UNSPEC_CALLEE_ABI)
+   (clobber (reg:ADDR LR_REGNUM))]
   ""
   "@
-  blr\\t%1
+  * return aarch64_indirect_call_asm (operands[1]);
   bl\\t%c1"
   [(set_attr "type" "call, call")]
 )
 
 (define_expand "sibcall"
-  [(parallel [(call (match_operand 0 "memory_operand" "")
-                   (match_operand 1 "general_operand" ""))
-             (return)
-             (use (match_operand 2 "" ""))])]
+  [(parallel
+     [(call (match_operand 0 "memory_operand")
+           (match_operand 1 "general_operand"))
+      (unspec:DI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
+      (return)])]
   ""
   {
-    aarch64_expand_call (NULL_RTX, operands[0], true);
+    aarch64_expand_call (NULL_RTX, operands[0], operands[2], true);
     DONE;
   }
 )
 
 (define_expand "sibcall_value"
-  [(parallel [(set (match_operand 0 "" "")
-                  (call (match_operand 1 "memory_operand" "")
-                        (match_operand 2 "general_operand" "")))
-             (return)
-             (use (match_operand 3 "" ""))])]
+  [(parallel
+     [(set (match_operand 0 "")
+          (call (match_operand 1 "memory_operand")
+                (match_operand 2 "general_operand")))
+      (unspec:DI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_ABI)
+      (return)])]
   ""
   {
-    aarch64_expand_call (operands[0], operands[1], true);
+    aarch64_expand_call (operands[0], operands[1], operands[3], true);
     DONE;
   }
 )
 
 (define_insn "*sibcall_insn"
-  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs, Usf"))
-        (match_operand 1 "" ""))
+  [(call (mem:DI (match_operand:ADDR 0 "aarch64_call_insn_operand" "Ucs, Usf"))
+        (match_operand 1 ""))
+   (unspec:DI [(match_operand:DI 2 "const_int_operand")] UNSPEC_CALLEE_ABI)
    (return)]
   "SIBLING_CALL_P (insn)"
-  "@
-   br\\t%0
-   b\\t%c0"
-  [(set_attr "type" "branch, branch")]
+  {
+    if (which_alternative == 0)
+      {
+       output_asm_insn ("br\\t%0", operands);
+       return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+      }
+    return "b\\t%c0";
+  }
+  [(set_attr "type" "branch, branch")
+   (set_attr "sls_length" "retbr,none")]
 )
 
 (define_insn "*sibcall_value_insn"
-  [(set (match_operand 0 "" "")
+  [(set (match_operand 0 "")
        (call (mem:DI
-               (match_operand:DI 1 "aarch64_call_insn_operand" "Ucs, Usf"))
-             (match_operand 2 "" "")))
+               (match_operand:ADDR 1 "aarch64_call_insn_operand" "Ucs, Usf"))
+             (match_operand 2 "")))
+   (unspec:DI [(match_operand:DI 3 "const_int_operand")] UNSPEC_CALLEE_ABI)
    (return)]
   "SIBLING_CALL_P (insn)"
-  "@
-   br\\t%1
-   b\\t%c1"
-  [(set_attr "type" "branch, branch")]
+  {
+    if (which_alternative == 0)
+      {
+       output_asm_insn ("br\\t%1", operands);
+       return aarch64_sls_barrier (aarch64_harden_sls_retbr_p ());
+      }
+    return "b\\t%c1";
+  }
+  [(set_attr "type" "branch, branch")
+   (set_attr "sls_length" "retbr,none")]
 )
 
 ;; Call subroutine returning any type.
 {
   int i;
 
-  emit_call_insn (gen_call (operands[0], const0_rtx, NULL));
+  /* Untyped calls always use the default ABI.  It's only possible to use
+     ABI variants if we know the type of the target function.  */
+  emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx));
 
   for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
 ;; -------------------------------------------------------------------
 
 (define_expand "mov<mode>"
-  [(set (match_operand:SHORT 0 "nonimmediate_operand" "")
-       (match_operand:SHORT 1 "general_operand" ""))]
+  [(set (match_operand:SHORT 0 "nonimmediate_operand")
+       (match_operand:SHORT 1 "general_operand"))]
   ""
   "
     if (GET_CODE (operands[0]) == MEM && operands[1] != const0_rtx)
 )
 
 (define_expand "mov<mode>"
-  [(set (match_operand:GPI 0 "nonimmediate_operand" "")
-       (match_operand:GPI 1 "general_operand" ""))]
+  [(set (match_operand:GPIC 0 "nonimmediate_operand")
+       (match_operand:GPIC 1 "general_operand"))]
   ""
   "
-    if (MEM_P (operands[0]) && CONST_INT_P (operands[1])
-       && <MODE>mode == DImode
+    if (MEM_P (operands[0]) && !MEM_VOLATILE_P (operands[0])
+       && CONST_INT_P (operands[1]) && <MODE>mode == DImode
        && aarch64_split_dimode_const_store (operands[0], operands[1]))
       DONE;
 
   [(set_attr "type" "mov_imm")]
 )
 
+;; Match MOVK as a normal AND and IOR operation.
+(define_insn "aarch64_movk<mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+       (ior:GPI (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                         (match_operand:GPI 2 "const_int_operand"))
+                (match_operand:GPI 3 "const_int_operand")))]
+  "aarch64_movk_shift (rtx_mode_t (operands[2], <MODE>mode),
+                      rtx_mode_t (operands[3], <MODE>mode)) >= 0"
+  {
+    int shift = aarch64_movk_shift (rtx_mode_t (operands[2], <MODE>mode),
+                                   rtx_mode_t (operands[3], <MODE>mode));
+    operands[2] = gen_int_mode (UINTVAL (operands[3]) >> shift, SImode);
+    operands[3] = gen_int_mode (shift, SImode);
+    return "movk\\t%<w>0, #%X2, lsl %3";
+  }
+  [(set_attr "type" "mov_imm")]
+)
+
 (define_expand "movti"
-  [(set (match_operand:TI 0 "nonimmediate_operand" "")
-       (match_operand:TI 1 "general_operand" ""))]
+  [(set (match_operand:TI 0 "nonimmediate_operand")
+       (match_operand:TI 1 "general_operand"))]
   ""
   "
     if (GET_CODE (operands[0]) == MEM && operands[1] != const0_rtx)
 })
 
 (define_expand "mov<mode>"
-  [(set (match_operand:GPF_TF_F16 0 "nonimmediate_operand" "")
-       (match_operand:GPF_TF_F16 1 "general_operand" ""))]
+  [(set (match_operand:GPF_TF_F16_MOV 0 "nonimmediate_operand")
+       (match_operand:GPF_TF_F16_MOV 1 "general_operand"))]
   ""
   {
     if (!TARGET_FLOAT)
       {
        aarch64_err_no_fpadvsimd (<MODE>mode);
-       FAIL;
+       machine_mode intmode
+         = int_mode_for_size (GET_MODE_BITSIZE (<MODE>mode), 0).require ();
+       emit_move_insn (gen_lowpart (intmode, operands[0]),
+                       gen_lowpart (intmode, operands[1]));
+       DONE;
       }
 
     if (GET_CODE (operands[0]) == MEM
   }
 )
 
-(define_insn "*movhf_aarch64"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=w,w  , w,?r,w,w  ,w  ,w,m,r,m ,r")
-       (match_operand:HF 1 "general_operand"      "Y ,?rY,?r, w,w,Ufc,Uvi,m,w,m,rY,r"))]
-  "TARGET_FLOAT && (register_operand (operands[0], HFmode)
-    || aarch64_reg_or_fp_zero (operands[1], HFmode))"
+(define_insn "*mov<mode>_aarch64"
+  [(set (match_operand:HFBF 0 "nonimmediate_operand" "=w,w  , w,?r,w,w  ,w  ,w,m,r,m ,r")
+       (match_operand:HFBF 1 "general_operand"      "Y ,?rY,?r, w,w,Ufc,Uvi,m,w,m,rY,r"))]
+  "TARGET_FLOAT && (register_operand (operands[0], <MODE>mode)
+    || aarch64_reg_or_fp_zero (operands[1], <MODE>mode))"
   "@
    movi\\t%0.4h, #0
    fmov\\t%h0, %w1
 
 ;; 0 is dst
 ;; 1 is src
-;; 2 is size of move in bytes
+;; 2 is size of copy in bytes
 ;; 3 is alignment
 
-(define_expand "movmemdi"
+(define_expand "cpymemdi"
   [(match_operand:BLK 0 "memory_operand")
    (match_operand:BLK 1 "memory_operand")
    (match_operand:DI 2 "immediate_operand")
    (match_operand:DI 3 "immediate_operand")]
    "!STRICT_ALIGNMENT"
 {
-  if (aarch64_expand_movmem (operands))
+  if (aarch64_expand_cpymem (operands))
     DONE;
   FAIL;
 }
                                XEXP (operands[1], 0),
                                GET_MODE_SIZE (<SX:MODE>mode)))"
   "@
-   ldp\\t%w0, %w2, %1
-   ldp\\t%s0, %s2, %1"
+   ldp\\t%w0, %w2, %z1
+   ldp\\t%s0, %s2, %z1"
   [(set_attr "type" "load_8,neon_load1_2reg")
    (set_attr "arch" "*,fp")]
 )
                                XEXP (operands[1], 0),
                                GET_MODE_SIZE (<DX:MODE>mode)))"
   "@
-   ldp\\t%x0, %x2, %1
-   ldp\\t%d0, %d2, %1"
+   ldp\\t%x0, %x2, %z1
+   ldp\\t%d0, %d2, %z1"
   [(set_attr "type" "load_16,neon_load1_2reg")
    (set_attr "arch" "*,fp")]
 )
                    plus_constant (Pmode,
                                   XEXP (operands[1], 0),
                                   GET_MODE_SIZE (TFmode)))"
-  "ldp\\t%q0, %q2, %1"
+  "ldp\\t%q0, %q2, %z1"
   [(set_attr "type" "neon_ldp_q")
    (set_attr "fp" "yes")]
 )
                                XEXP (operands[0], 0),
                                GET_MODE_SIZE (<SX:MODE>mode)))"
   "@
-   stp\\t%w1, %w3, %0
-   stp\\t%s1, %s3, %0"
+   stp\\t%w1, %w3, %z0
+   stp\\t%s1, %s3, %z0"
   [(set_attr "type" "store_8,neon_store1_2reg")
    (set_attr "arch" "*,fp")]
 )
                                XEXP (operands[0], 0),
                                GET_MODE_SIZE (<DX:MODE>mode)))"
   "@
-   stp\\t%x1, %x3, %0
-   stp\\t%d1, %d3, %0"
+   stp\\t%x1, %x3, %z0
+   stp\\t%d1, %d3, %z0"
   [(set_attr "type" "store_16,neon_store1_2reg")
    (set_attr "arch" "*,fp")]
 )
                 plus_constant (Pmode,
                                XEXP (operands[0], 0),
                                GET_MODE_SIZE (TFmode)))"
-  "stp\\t%q1, %q3, %0"
+  "stp\\t%q1, %q3, %z0"
   [(set_attr "type" "neon_stp_q")
    (set_attr "fp" "yes")]
 )
 
 ;; Load pair with post-index writeback.  This is primarily used in function
 ;; epilogues.
-(define_insn "loadwb_pair<GPI:mode>_<P:mode>"
+;;
+;; MORELLO TODO: pure-cap.
+(define_insn "@loadwb_pair<GPI:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
+    [(set (match_operand:ADDR 0 "register_operand" "=k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+           (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
      (set (match_operand:GPI 2 "register_operand" "=r")
           (mem:GPI (match_dup 1)))
      (set (match_operand:GPI 3 "register_operand" "=r")
-          (mem:GPI (plus:P (match_dup 1)
-                   (match_operand:P 5 "const_int_operand" "n"))))])]
+          (mem:GPI (<ADDR:PLUS>:ADDR
+                    (match_dup 1)
+                    (match_operand:DI 5 "const_int_operand" "n"))))])]
   "INTVAL (operands[5]) == GET_MODE_SIZE (<GPI:MODE>mode)"
-  "ldp\\t%<w>2, %<w>3, [%1], %4"
-  [(set_attr "type" "load_<ldpstp_sz>")]
+  "ldp\\t%<GPI:w>2, %<GPI:w>3, [%1], %4"
+  [(set_attr "type" "load_<GPI:ldpstp_sz>")]
 )
 
-(define_insn "loadwb_pair<GPF:mode>_<P:mode>"
+(define_insn "@loadwb_pair<GPF:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
+    [(set (match_operand:ADDR 0 "register_operand" "=k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+            (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
      (set (match_operand:GPF 2 "register_operand" "=w")
           (mem:GPF (match_dup 1)))
      (set (match_operand:GPF 3 "register_operand" "=w")
-          (mem:GPF (plus:P (match_dup 1)
-                   (match_operand:P 5 "const_int_operand" "n"))))])]
+          (mem:GPF (<ADDR:PLUS>:ADDR
+                    (match_dup 1)
+                    (match_operand:DI 5 "const_int_operand" "n"))))])]
   "INTVAL (operands[5]) == GET_MODE_SIZE (<GPF:MODE>mode)"
-  "ldp\\t%<w>2, %<w>3, [%1], %4"
+  "ldp\\t%<GPF:w>2, %<GPF:w>3, [%1], %4"
   [(set_attr "type" "neon_load1_2reg")]
 )
 
-(define_insn "loadwb_pair<TX:mode>_<P:mode>"
+(define_insn "@loadwb_pair<TX:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
+    [(set (match_operand:ADDR 0 "register_operand" "=k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+           (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
      (set (match_operand:TX 2 "register_operand" "=w")
           (mem:TX (match_dup 1)))
      (set (match_operand:TX 3 "register_operand" "=w")
-          (mem:TX (plus:P (match_dup 1)
-                         (match_operand:P 5 "const_int_operand" "n"))))])]
+          (mem:TX (<ADDR:PLUS>:ADDR
+                   (match_dup 1)
+                   (match_operand:DI 5 "const_int_operand" "n"))))])]
   "TARGET_SIMD && INTVAL (operands[5]) == GET_MODE_SIZE (<TX:MODE>mode)"
   "ldp\\t%q2, %q3, [%1], %4"
   [(set_attr "type" "neon_ldp_q")]
 
 ;; Store pair with pre-index writeback.  This is primarily used in function
 ;; prologues.
-(define_insn "storewb_pair<GPI:mode>_<P:mode>"
+;;
+;; MORELLO TODO: pure-cap.
+(define_insn "@storewb_pair<GPI:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=&k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
-     (set (mem:GPI (plus:P (match_dup 0)
-                   (match_dup 4)))
+    [(set (match_operand:ADDR 0 "register_operand" "=&k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+           (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
+     (set (mem:GPI (<ADDR:PLUS>:ADDR (match_dup 0) (match_dup 4)))
           (match_operand:GPI 2 "register_operand" "r"))
-     (set (mem:GPI (plus:P (match_dup 0)
-                   (match_operand:P 5 "const_int_operand" "n")))
+     (set (mem:GPI (<ADDR:PLUS>:ADDR
+                    (match_dup 0)
+                    (match_operand:DI 5 "const_int_operand" "n")))
           (match_operand:GPI 3 "register_operand" "r"))])]
   "INTVAL (operands[5]) == INTVAL (operands[4]) + GET_MODE_SIZE (<GPI:MODE>mode)"
-  "stp\\t%<w>2, %<w>3, [%0, %4]!"
-  [(set_attr "type" "store_<ldpstp_sz>")]
+  "stp\\t%<GPI:w>2, %<GPI:w>3, [%0, %4]!"
+  [(set_attr "type" "store_<GPI:ldpstp_sz>")]
 )
 
-(define_insn "storewb_pair<GPF:mode>_<P:mode>"
+(define_insn "@storewb_pair<GPF:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=&k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
-     (set (mem:GPF (plus:P (match_dup 0)
-                   (match_dup 4)))
+    [(set (match_operand:ADDR 0 "register_operand" "=&k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+           (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
+     (set (mem:GPF (<ADDR:PLUS>:ADDR (match_dup 0) (match_dup 4)))
           (match_operand:GPF 2 "register_operand" "w"))
-     (set (mem:GPF (plus:P (match_dup 0)
-                   (match_operand:P 5 "const_int_operand" "n")))
+     (set (mem:GPF (<ADDR:PLUS>:ADDR
+                    (match_dup 0)
+                    (match_operand:DI 5 "const_int_operand" "n")))
           (match_operand:GPF 3 "register_operand" "w"))])]
   "INTVAL (operands[5]) == INTVAL (operands[4]) + GET_MODE_SIZE (<GPF:MODE>mode)"
-  "stp\\t%<w>2, %<w>3, [%0, %4]!"
+  "stp\\t%<GPF:w>2, %<GPF:w>3, [%0, %4]!"
   [(set_attr "type" "neon_store1_2reg<q>")]
 )
 
-(define_insn "storewb_pair<TX:mode>_<P:mode>"
+(define_insn "@storewb_pair<TX:mode>_<ADDR:mode>"
   [(parallel
-    [(set (match_operand:P 0 "register_operand" "=&k")
-          (plus:P (match_operand:P 1 "register_operand" "0")
-                  (match_operand:P 4 "aarch64_mem_pair_offset" "n")))
-     (set (mem:TX (plus:P (match_dup 0)
-                         (match_dup 4)))
+    [(set (match_operand:ADDR 0 "register_operand" "=&k")
+          (<ADDR:PLUS>:ADDR
+           (match_operand:ADDR 1 "register_operand" "0")
+            (match_operand:DI 4 "aarch64_mem_pair_offset" "n")))
+     (set (mem:TX (<ADDR:PLUS>:ADDR (match_dup 0) (match_dup 4)))
           (match_operand:TX 2 "register_operand" "w"))
-     (set (mem:TX (plus:P (match_dup 0)
-                         (match_operand:P 5 "const_int_operand" "n")))
+     (set (mem:TX (<ADDR:PLUS>:ADDR
+                   (match_dup 0)
+                   (match_operand:DI 5 "const_int_operand" "n")))
           (match_operand:TX 3 "register_operand" "w"))])]
   "TARGET_SIMD
    && INTVAL (operands[5])
                plus_constant (Pmode,
                               XEXP (operands[1], 0),
                               GET_MODE_SIZE (SImode)))"
-  "ldpsw\\t%0, %2, %1"
+  "ldpsw\\t%0, %2, %z1"
   [(set_attr "type" "load_8")]
 )
 
    ldr\t%s0, %1
    fmov\t%w0, %s1
    fmov\t%s0, %s1"
-  [(set_attr "type" "extend,load_4,f_mcr,f_loads,f_mrc,fmov")
+  [(set_attr "type" "mov_reg,load_4,f_mcr,f_loads,f_mrc,fmov")
    (set_attr "arch" "*,*,fp,fp,fp,fp")]
 )
 
                               XEXP (operands[1], 0),
                               GET_MODE_SIZE (SImode)))"
   "@
-   ldp\t%w0, %w2, %1
-   ldp\t%s0, %s2, %1"
+   ldp\t%w0, %w2, %z1
+   ldp\t%s0, %s2, %z1"
   [(set_attr "type" "load_8,neon_load1_2reg")
    (set_attr "arch" "*,fp")]
 )
 
 (define_expand "add<mode>3"
   [(set
-    (match_operand:GPI 0 "register_operand" "")
-    (plus:GPI (match_operand:GPI 1 "register_operand" "")
-             (match_operand:GPI 2 "aarch64_pluslong_or_poly_operand" "")))]
+    (match_operand:GPI 0 "register_operand")
+    (plus:GPI (match_operand:GPI 1 "register_operand")
+             (match_operand:GPI 2 "aarch64_pluslong_or_poly_operand")))]
   ""
 {
   /* If operands[1] is a subreg extract the inner RTX.  */
   /* If the constant is too large for a single instruction and isn't frame
      based, split off the immediate so it is available for CSE.  */
   if (!aarch64_plus_immediate (operands[2], <MODE>mode)
+      && !(TARGET_SVE && aarch64_sve_plus_immediate (operands[2], <MODE>mode))
       && can_create_pseudo_p ()
       && (!REG_P (op1)
         || !REGNO_PTR_FRAME_P (REGNO (op1))))
 
 (define_insn "*add<mode>3_aarch64"
   [(set
-    (match_operand:GPI 0 "register_operand" "=rk,rk,w,rk,r,rk")
+    (match_operand:GPI 0 "register_operand" "=rk,rk,w,rk,r,r,rk")
     (plus:GPI
-     (match_operand:GPI 1 "register_operand" "%rk,rk,w,rk,rk,rk")
-     (match_operand:GPI 2 "aarch64_pluslong_operand" "I,r,w,J,Uaa,Uav")))]
+     (match_operand:GPI 1 "register_operand" "%rk,rk,w,rk,rk,0,rk")
+     (match_operand:GPI 2 "aarch64_pluslong_operand" "I,r,w,J,Uaa,Uai,Uav")))]
   ""
   "@
   add\\t%<w>0, %<w>1, %2
   add\\t%<rtn>0<vas>, %<rtn>1<vas>, %<rtn>2<vas>
   sub\\t%<w>0, %<w>1, #%n2
   #
-  * return aarch64_output_sve_addvl_addpl (operands[0], operands[1], operands[2]);"
-  ;; The "alu_imm" type for ADDVL/ADDPL is just a placeholder.
-  [(set_attr "type" "alu_imm,alu_sreg,neon_add,alu_imm,multiple,alu_imm")
-   (set_attr "arch" "*,*,simd,*,*,*")]
+  * return aarch64_output_sve_scalar_inc_dec (operands[2]);
+  * return aarch64_output_sve_addvl_addpl (operands[2]);"
+  ;; The "alu_imm" types for INC/DEC and ADDVL/ADDPL are just placeholders.
+  [(set_attr "type" "alu_imm,alu_sreg,neon_add,alu_imm,multiple,alu_imm,alu_imm")
+   (set_attr "arch" "*,*,simd,*,*,sve,sve")]
 )
 
 ;; zero_extend version of above
 ;; this pattern.
 (define_insn_and_split "*add<mode>3_poly_1"
   [(set
-    (match_operand:GPI 0 "register_operand" "=r,r,r,r,r,&r")
+    (match_operand:GPI 0 "register_operand" "=r,r,r,r,r,r,&r")
     (plus:GPI
-     (match_operand:GPI 1 "register_operand" "%rk,rk,rk,rk,rk,rk")
-     (match_operand:GPI 2 "aarch64_pluslong_or_poly_operand" "I,r,J,Uaa,Uav,Uat")))]
+     (match_operand:GPI 1 "register_operand" "%rk,rk,rk,rk,rk,0,rk")
+     (match_operand:GPI 2 "aarch64_pluslong_or_poly_operand" "I,r,J,Uaa,Uav,Uai,Uat")))]
   "TARGET_SVE && operands[0] != stack_pointer_rtx"
   "@
   add\\t%<w>0, %<w>1, %2
   add\\t%<w>0, %<w>1, %<w>2
   sub\\t%<w>0, %<w>1, #%n2
   #
-  * return aarch64_output_sve_addvl_addpl (operands[0], operands[1], operands[2]);
+  * return aarch64_output_sve_scalar_inc_dec (operands[2]);
+  * return aarch64_output_sve_addvl_addpl (operands[2]);
   #"
   "&& epilogue_completed
    && !reg_overlap_mentioned_p (operands[0], operands[1])
                              operands[2], operands[0], NULL_RTX);
     DONE;
   }
-  ;; The "alu_imm" type for ADDVL/ADDPL is just a placeholder.
-  [(set_attr "type" "alu_imm,alu_sreg,alu_imm,multiple,alu_imm,multiple")]
+  ;; The "alu_imm" types for INC/DEC and ADDVL/ADDPL are just placeholders.
+  [(set_attr "type" "alu_imm,alu_sreg,alu_imm,multiple,alu_imm,alu_imm,multiple")]
 )
 
 (define_split
   ""
 {
   emit_insn (gen_add<mode>3_compareC (operands[0], operands[1], operands[2]));
-  aarch64_gen_unlikely_cbranch (NE, CC_Cmode, operands[3]);
+  aarch64_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
 
   DONE;
 })
 
 (define_expand "addti3"
-  [(set (match_operand:TI 0 "register_operand" "")
-       (plus:TI (match_operand:TI 1 "register_operand" "")
-                (match_operand:TI 2 "aarch64_reg_or_imm" "")))]
+  [(set (match_operand:TI 0 "register_operand")
+       (plus:TI (match_operand:TI 1 "register_operand")
+                (match_operand:TI 2 "aarch64_reg_or_imm")))]
   ""
 {
   rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
 })
 
 (define_expand "addvti4"
-  [(match_operand:TI 0 "register_operand" "")
-   (match_operand:TI 1 "register_operand" "")
-   (match_operand:TI 2 "aarch64_reg_or_imm" "")
+  [(match_operand:TI 0 "register_operand")
+   (match_operand:TI 1 "register_operand")
+   (match_operand:TI 2 "aarch64_reg_or_imm")
    (label_ref (match_operand 3 "" ""))]
   ""
 {
 })
 
 (define_expand "uaddvti4"
-  [(match_operand:TI 0 "register_operand" "")
-   (match_operand:TI 1 "register_operand" "")
-   (match_operand:TI 2 "aarch64_reg_or_imm" "")
+  [(match_operand:TI 0 "register_operand")
+   (match_operand:TI 1 "register_operand")
+   (match_operand:TI 2 "aarch64_reg_or_imm")
    (label_ref (match_operand 3 "" ""))]
   ""
 {
   emit_move_insn (gen_lowpart (DImode, operands[0]), low_dest);
   emit_move_insn (gen_highpart (DImode, operands[0]), high_dest);
 
-  aarch64_gen_unlikely_cbranch (NE, CC_Cmode, operands[3]);
+  aarch64_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]);
   DONE;
  })
 
 (define_insn "add<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (plus:GPI (match_operand:GPI 1 "register_operand" "%r,r,r")
+        (plus:GPI (match_operand:GPI 1 "register_operand" "%rk,rk,rk")
                   (match_operand:GPI 2 "aarch64_plus_operand" "r,I,J"))
         (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r,r,r")
 (define_insn "*addsi3_compare0_uxtw"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (plus:SI (match_operand:SI 1 "register_operand" "%r,r,r")
+        (plus:SI (match_operand:SI 1 "register_operand" "%rk,rk,rk")
                  (match_operand:SI 2 "aarch64_plus_operand" "r,I,J"))
         (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=r,r,r")
   [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
-(define_insn "*add<mode>3_compareC_cconly_imm"
-  [(set (reg:CC_C CC_REGNUM)
-       (ne:CC_C
-         (plus:<DWI>
-           (zero_extend:<DWI> (match_operand:GPI 0 "register_operand" "r,r"))
-           (match_operand:<DWI> 2 "const_scalar_int_operand" ""))
-         (zero_extend:<DWI>
-           (plus:GPI
-             (match_dup 0)
-             (match_operand:GPI 1 "aarch64_plus_immediate" "I,J")))))]
-  "aarch64_zero_extend_const_eq (<DWI>mode, operands[2],
-                                <MODE>mode, operands[1])"
-  "@
-  cmn\\t%<w>0, %1
-  cmp\\t%<w>0, #%n1"
-  [(set_attr "type" "alus_imm")]
-)
-
 (define_insn "*add<mode>3_compareC_cconly"
   [(set (reg:CC_C CC_REGNUM)
-       (ne:CC_C
-         (plus:<DWI>
-           (zero_extend:<DWI> (match_operand:GPI 0 "register_operand" "r"))
-           (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
-         (zero_extend:<DWI> (plus:GPI (match_dup 0) (match_dup 1)))))]
+       (compare:CC_C
+         (plus:GPI
+           (match_operand:GPI 0 "register_operand" "r,r,r")
+           (match_operand:GPI 1 "aarch64_plus_operand" "r,I,J"))
+         (match_dup 0)))]
   ""
-  "cmn\\t%<w>0, %<w>1"
-  [(set_attr "type" "alus_sreg")]
-)
-
-(define_insn "*add<mode>3_compareC_imm"
-  [(set (reg:CC_C CC_REGNUM)
-       (ne:CC_C
-         (plus:<DWI>
-           (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r,r"))
-           (match_operand:<DWI> 3 "const_scalar_int_operand" ""))
-         (zero_extend:<DWI>
-           (plus:GPI
-             (match_dup 1)
-             (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))))
-   (set (match_operand:GPI 0 "register_operand" "=r,r")
-       (plus:GPI (match_dup 1) (match_dup 2)))]
-  "aarch64_zero_extend_const_eq (<DWI>mode, operands[3],
-                                 <MODE>mode, operands[2])"
   "@
-  adds\\t%<w>0, %<w>1, %2
-  subs\\t%<w>0, %<w>1, #%n2"
-  [(set_attr "type" "alus_imm")]
+  cmn\\t%<w>0, %<w>1
+  cmn\\t%<w>0, %1
+  cmp\\t%<w>0, #%n1"
+  [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
 (define_insn "add<mode>3_compareC"
   [(set (reg:CC_C CC_REGNUM)
        (compare:CC_C
-         (plus:<DWI>
-           (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))
-           (zero_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
-         (zero_extend:<DWI>
-           (plus:GPI (match_dup 1) (match_dup 2)))))
-   (set (match_operand:GPI 0 "register_operand" "=r")
+         (plus:GPI
+           (match_operand:GPI 1 "register_operand" "rk,rk,rk")
+           (match_operand:GPI 2 "aarch64_plus_operand" "r,I,J"))
+         (match_dup 1)))
+   (set (match_operand:GPI 0 "register_operand" "=r,r,r")
        (plus:GPI (match_dup 1) (match_dup 2)))]
   ""
-  "adds\\t%<w>0, %<w>1, %<w>2"
-  [(set_attr "type" "alus_sreg")]
+  "@
+  adds\\t%<w>0, %<w>1, %<w>2
+  adds\\t%<w>0, %<w>1, %2
+  subs\\t%<w>0, %<w>1, #%n2"
+  [(set_attr "type" "alus_sreg,alus_imm,alus_imm")]
 )
 
 (define_insn "*add<mode>3_compareV_cconly_imm"
        (compare:CC_V
          (plus:<DWI>
            (sign_extend:<DWI>
-             (match_operand:GPI 1 "register_operand" "r,r"))
+             (match_operand:GPI 1 "register_operand" "rk,rk"))
            (match_operand:GPI 2 "aarch64_plus_immediate" "I,J"))
          (sign_extend:<DWI>
            (plus:GPI (match_dup 1) (match_dup 2)))))
   [(set (reg:CC_V CC_REGNUM)
        (compare:CC_V
          (plus:<DWI>
-           (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))
+           (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "rk"))
            (sign_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
          (sign_extend:<DWI> (plus:GPI (match_dup 1) (match_dup 2)))))
    (set (match_operand:GPI 0 "register_operand" "=r")
        (compare:CC_NZ
         (plus:GPI
          (ANY_EXTEND:GPI (match_operand:ALLX 1 "register_operand" "r"))
-         (match_operand:GPI 2 "register_operand" "r"))
+         (match_operand:GPI 2 "register_operand" "rk"))
        (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r")
        (plus:GPI (ANY_EXTEND:GPI (match_dup 1)) (match_dup 2)))]
 (define_insn "*subs_<optab><ALLX:mode>_<GPI:mode>"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (minus:GPI (match_operand:GPI 1 "register_operand" "r")
+        (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
                    (ANY_EXTEND:GPI
                     (match_operand:ALLX 2 "register_operand" "r")))
        (const_int 0)))
                    (ANY_EXTEND:GPI 
                     (match_operand:ALLX 1 "register_operand" "r"))
                    (match_operand 2 "aarch64_imm3" "Ui3"))
-                  (match_operand:GPI 3 "register_operand" "r"))
+                  (match_operand:GPI 3 "register_operand" "rk"))
         (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=rk")
        (plus:GPI (ashift:GPI (ANY_EXTEND:GPI (match_dup 1))
 (define_insn "*subs_<optab><ALLX:mode>_shift_<GPI:mode>"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (minus:GPI (match_operand:GPI 1 "register_operand" "r")
+        (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
                    (ashift:GPI 
                     (ANY_EXTEND:GPI
                      (match_operand:ALLX 2 "register_operand" "r"))
                              (match_operand 2 "aarch64_pwr_imm3" "Up3"))
                    (match_operand 3 "const_int_operand" "n")
                    (const_int 0))
-                  (match_operand:GPI 4 "register_operand" "r"))
+                  (match_operand:GPI 4 "register_operand" "rk"))
        (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r")
        (plus:GPI (ANY_EXTRACT:GPI (mult:GPI (match_dup 1) (match_dup 2))
 (define_insn "*subs_<optab><mode>_multp2"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (minus:GPI (match_operand:GPI 4 "register_operand" "r")
+        (minus:GPI (match_operand:GPI 4 "register_operand" "rk")
                    (ANY_EXTRACT:GPI
                     (mult:GPI (match_operand:GPI 1 "register_operand" "r")
                               (match_operand 2 "aarch64_pwr_imm3" "Up3"))
   [(set (match_operand:GPI 0 "register_operand")
        (plus:GPI
          (plus:GPI
-           (ne:GPI (reg:CC_C CC_REGNUM) (const_int 0))
+           (ltu:GPI (reg:CC_C CC_REGNUM) (const_int 0))
            (match_operand:GPI 1 "aarch64_reg_or_zero"))
          (match_operand:GPI 2 "aarch64_reg_or_zero")))]
    ""
 (define_expand "add<mode>3_carryinC"
   [(parallel
      [(set (match_dup 3)
-          (compare:CC_C
+          (compare:CC_ADC
             (plus:<DWI>
               (plus:<DWI>
                 (match_dup 4)
                 (zero_extend:<DWI>
-                  (match_operand:GPI 1 "register_operand" "")))
+                  (match_operand:GPI 1 "register_operand")))
               (zero_extend:<DWI>
-                (match_operand:GPI 2 "register_operand" "")))
-          (zero_extend:<DWI>
-            (plus:GPI
-              (plus:GPI (match_dup 5) (match_dup 1))
-              (match_dup 2)))))
+                (match_operand:GPI 2 "register_operand")))
+            (match_dup 6)))
       (set (match_operand:GPI 0 "register_operand")
           (plus:GPI
             (plus:GPI (match_dup 5) (match_dup 1))
             (match_dup 2)))])]
    ""
 {
-  operands[3] = gen_rtx_REG (CC_Cmode, CC_REGNUM);
-  operands[4] = gen_rtx_NE (<DWI>mode, operands[3], const0_rtx);
-  operands[5] = gen_rtx_NE (<MODE>mode, operands[3], const0_rtx);
+  operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+  rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+  operands[4] = gen_rtx_LTU (<DWI>mode, ccin, const0_rtx);
+  operands[5] = gen_rtx_LTU (<MODE>mode, ccin, const0_rtx);
+  operands[6] = immed_wide_int_const (wi::shwi (1, <DWI>mode)
+                                     << GET_MODE_BITSIZE (<MODE>mode),
+                                     TImode);
 })
 
 (define_insn "*add<mode>3_carryinC_zero"
-  [(set (reg:CC_C CC_REGNUM)
-       (compare:CC_C
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
          (plus:<DWI>
            (match_operand:<DWI> 2 "aarch64_carry_operation" "")
            (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
-         (zero_extend:<DWI>
-           (plus:GPI
-             (match_operand:GPI 3 "aarch64_carry_operation" "")
-             (match_dup 1)))))
+         (match_operand 4 "const_scalar_int_operand" "")))
    (set (match_operand:GPI 0 "register_operand" "=r")
-       (plus:GPI (match_dup 3) (match_dup 1)))]
-   ""
+       (plus:GPI (match_operand:GPI 3 "aarch64_carry_operation" "")
+                 (match_dup 1)))]
+  "rtx_mode_t (operands[4], <DWI>mode)
+   == (wi::shwi (1, <DWI>mode) << (unsigned) GET_MODE_BITSIZE (<MODE>mode))"
    "adcs\\t%<w>0, %<w>1, <w>zr"
   [(set_attr "type" "adc_reg")]
 )
 
 (define_insn "*add<mode>3_carryinC"
-  [(set (reg:CC_C CC_REGNUM)
-       (compare:CC_C
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
          (plus:<DWI>
            (plus:<DWI>
              (match_operand:<DWI> 3 "aarch64_carry_operation" "")
              (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
            (zero_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
-         (zero_extend:<DWI>
-           (plus:GPI
-             (plus:GPI
-               (match_operand:GPI 4 "aarch64_carry_operation" "")
-               (match_dup 1))
-             (match_dup 2)))))
+         (match_operand 5 "const_scalar_int_operand" "")))
    (set (match_operand:GPI 0 "register_operand" "=r")
        (plus:GPI
-         (plus:GPI (match_dup 4) (match_dup 1))
+         (plus:GPI (match_operand:GPI 4 "aarch64_carry_operation" "")
+                   (match_dup 1))
          (match_dup 2)))]
-   ""
+  "rtx_mode_t (operands[5], <DWI>mode)
+   == (wi::shwi (1, <DWI>mode) << (unsigned) GET_MODE_BITSIZE (<MODE>mode))"
    "adcs\\t%<w>0, %<w>1, %<w>2"
   [(set_attr "type" "adc_reg")]
 )
               (plus:<DWI>
                 (match_dup 3)
                 (sign_extend:<DWI>
-                  (match_operand:GPI 1 "register_operand" "")))
+                  (match_operand:GPI 1 "register_operand")))
               (sign_extend:<DWI>
-                (match_operand:GPI 2 "register_operand" "")))
+                (match_operand:GPI 2 "register_operand")))
           (sign_extend:<DWI>
             (plus:GPI
               (plus:GPI (match_dup 4) (match_dup 1))
    ""
 {
   rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
-  operands[3] = gen_rtx_NE (<DWI>mode, cc, const0_rtx);
-  operands[4] = gen_rtx_NE (<MODE>mode, cc, const0_rtx);
+  operands[3] = gen_rtx_LTU (<DWI>mode, cc, const0_rtx);
+  operands[4] = gen_rtx_LTU (<MODE>mode, cc, const0_rtx);
 })
 
 (define_insn "*add<mode>3_carryinV_zero"
 })
 
 (define_expand "subti3"
-  [(set (match_operand:TI 0 "register_operand" "")
-       (minus:TI (match_operand:TI 1 "aarch64_reg_or_zero" "")
-                 (match_operand:TI 2 "register_operand" "")))]
+  [(set (match_operand:TI 0 "register_operand")
+       (minus:TI (match_operand:TI 1 "aarch64_reg_or_zero")
+                 (match_operand:TI 2 "register_operand")))]
   ""
 {
   rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
 
 (define_insn "*sub<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
-       (compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "r")
+       (compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
                                  (match_operand:GPI 2 "register_operand" "r"))
                       (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r")
 ;; zero_extend version of above
 (define_insn "*subsi3_compare0_uxtw"
   [(set (reg:CC_NZ CC_REGNUM)
-       (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "r")
+       (compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "rk")
                                 (match_operand:SI 2 "register_operand" "r"))
                       (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=r")
 (define_insn "sub<mode>3_compare1_imm"
   [(set (reg:CC CC_REGNUM)
        (compare:CC
-         (match_operand:GPI 1 "aarch64_reg_or_zero" "rZ,rZ")
+         (match_operand:GPI 1 "aarch64_reg_or_zero" "rkZ,rkZ")
          (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))
    (set (match_operand:GPI 0 "register_operand" "=r,r")
        (plus:GPI
 (define_insn "sub<mode>3_compare1"
   [(set (reg:CC CC_REGNUM)
        (compare:CC
-         (match_operand:GPI 1 "aarch64_reg_or_zero" "rZ")
+         (match_operand:GPI 1 "aarch64_reg_or_zero" "rkZ")
          (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")))
    (set (match_operand:GPI 0 "register_operand" "=r")
        (minus:GPI (match_dup 1) (match_dup 2)))]
 )
 
 (define_peephole2
-  [(set (match_operand:GPI 0 "register_operand")
+  [(set (match_operand:GPI 0 "aarch64_general_reg")
        (minus:GPI (match_operand:GPI 1 "aarch64_reg_or_zero")
                    (match_operand:GPI 2 "aarch64_reg_or_zero")))
    (set (reg:CC CC_REGNUM)
        (compare:CC
          (match_operand:GPI 1 "aarch64_reg_or_zero")
          (match_operand:GPI 2 "aarch64_reg_or_zero")))
-   (set (match_operand:GPI 0 "register_operand")
+   (set (match_operand:GPI 0 "aarch64_general_reg")
        (minus:GPI (match_dup 1)
                   (match_dup 2)))]
   ""
 )
 
 (define_peephole2
-  [(set (match_operand:GPI 0 "register_operand")
+  [(set (match_operand:GPI 0 "aarch64_general_reg")
        (plus:GPI (match_operand:GPI 1 "register_operand")
                  (match_operand:GPI 2 "aarch64_plus_immediate")))
    (set (reg:CC CC_REGNUM)
        (compare:CC
          (match_operand:GPI 1 "register_operand")
          (match_operand:GPI 3 "const_int_operand")))
-   (set (match_operand:GPI 0 "register_operand")
+   (set (match_operand:GPI 0 "aarch64_general_reg")
        (plus:GPI (match_dup 1)
                  (match_operand:GPI 2 "aarch64_plus_immediate")))]
   "INTVAL (operands[3]) == -INTVAL (operands[2])"
      [(set (reg:CC CC_REGNUM)
           (compare:CC
             (zero_extend:<DWI>
-              (match_operand:GPI 1 "aarch64_reg_or_zero" ""))
+              (match_operand:GPI 1 "aarch64_reg_or_zero"))
             (plus:<DWI>
               (zero_extend:<DWI>
-                (match_operand:GPI 2 "register_operand" ""))
+                (match_operand:GPI 2 "register_operand"))
               (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0)))))
-      (set (match_operand:GPI 0 "register_operand" "")
+      (set (match_operand:GPI 0 "register_operand")
           (minus:GPI
             (minus:GPI (match_dup 1) (match_dup 2))
             (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])]
           (compare:CC_V
            (minus:<DWI>
             (sign_extend:<DWI>
-              (match_operand:GPI 1 "aarch64_reg_or_zero" ""))
+              (match_operand:GPI 1 "aarch64_reg_or_zero"))
             (plus:<DWI>
               (sign_extend:<DWI>
-                (match_operand:GPI 2 "register_operand" ""))
+                (match_operand:GPI 2 "register_operand"))
               (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0))))
            (sign_extend:<DWI>
             (minus:GPI (match_dup 1)
                        (plus:GPI (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))
                                  (match_dup 2))))))
-      (set (match_operand:GPI 0 "register_operand" "")
+      (set (match_operand:GPI 0 "register_operand")
           (minus:GPI
             (minus:GPI (match_dup 1) (match_dup 2))
             (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])]
 )
 
 (define_expand "abs<mode>2"
-  [(match_operand:GPI 0 "register_operand" "")
-   (match_operand:GPI 1 "register_operand" "")]
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "register_operand")]
   ""
   {
     rtx ccreg = aarch64_gen_compare_reg (LT, operands[1], const0_rtx);
 ;; -------------------------------------------------------------------
 
 (define_expand "cstore<mode>4"
-  [(set (match_operand:SI 0 "register_operand" "")
+  [(set (match_operand:SI 0 "register_operand")
        (match_operator:SI 1 "aarch64_comparison_operator"
-        [(match_operand:GPI 2 "register_operand" "")
-         (match_operand:GPI 3 "aarch64_plus_operand" "")]))]
+        [(match_operand:GPI 2 "register_operand")
+         (match_operand:GPI 3 "aarch64_plus_operand")]))]
   ""
   "
   operands[2] = aarch64_gen_compare_reg (GET_CODE (operands[1]), operands[2],
 
 
 (define_expand "cstore<mode>4"
-  [(set (match_operand:SI 0 "register_operand" "")
+  [(set (match_operand:SI 0 "register_operand")
        (match_operator:SI 1 "aarch64_comparison_operator_mode"
-        [(match_operand:GPF 2 "register_operand" "")
-         (match_operand:GPF 3 "aarch64_fp_compare_operand" "")]))]
+        [(match_operand:GPF 2 "register_operand")
+         (match_operand:GPF 3 "aarch64_fp_compare_operand")]))]
   ""
   "
   operands[2] = aarch64_gen_compare_reg (GET_CODE (operands[1]), operands[2],
 )
 
 (define_expand "cmov<mode>6"
-  [(set (match_operand:GPI 0 "register_operand" "")
+  [(set (match_operand:GPI 0 "register_operand")
        (if_then_else:GPI
         (match_operator 1 "aarch64_comparison_operator"
-         [(match_operand:GPI 2 "register_operand" "")
-          (match_operand:GPI 3 "aarch64_plus_operand" "")])
-        (match_operand:GPI 4 "register_operand" "")
-        (match_operand:GPI 5 "register_operand" "")))]
+         [(match_operand:GPI 2 "register_operand")
+          (match_operand:GPI 3 "aarch64_plus_operand")])
+        (match_operand:GPI 4 "register_operand")
+        (match_operand:GPI 5 "register_operand")))]
   ""
   "
   operands[2] = aarch64_gen_compare_reg (GET_CODE (operands[1]), operands[2],
 )
 
 (define_expand "cmov<mode>6"
-  [(set (match_operand:GPF 0 "register_operand" "")
+  [(set (match_operand:GPF 0 "register_operand")
        (if_then_else:GPF
         (match_operator 1 "aarch64_comparison_operator"
-         [(match_operand:GPF 2 "register_operand" "")
-          (match_operand:GPF 3 "aarch64_fp_compare_operand" "")])
-        (match_operand:GPF 4 "register_operand" "")
-        (match_operand:GPF 5 "register_operand" "")))]
+         [(match_operand:GPF 2 "register_operand")
+          (match_operand:GPF 3 "aarch64_fp_compare_operand")])
+        (match_operand:GPF 4 "register_operand")
+        (match_operand:GPF 5 "register_operand")))]
   ""
   "
   operands[2] = aarch64_gen_compare_reg (GET_CODE (operands[1]), operands[2],
 )
 
 (define_expand "mov<mode>cc"
-  [(set (match_operand:ALLI 0 "register_operand" "")
-       (if_then_else:ALLI (match_operand 1 "aarch64_comparison_operator" "")
-                          (match_operand:ALLI 2 "register_operand" "")
-                          (match_operand:ALLI 3 "register_operand" "")))]
+  [(set (match_operand:ALLI 0 "register_operand")
+       (if_then_else:ALLI (match_operand 1 "aarch64_comparison_operator")
+                          (match_operand:ALLI 2 "register_operand")
+                          (match_operand:ALLI 3 "register_operand")))]
   ""
   {
     rtx ccreg;
 )
 
 (define_expand "mov<GPF:mode><GPI:mode>cc"
-  [(set (match_operand:GPI 0 "register_operand" "")
-       (if_then_else:GPI (match_operand 1 "aarch64_comparison_operator" "")
-                         (match_operand:GPF 2 "register_operand" "")
-                         (match_operand:GPF 3 "register_operand" "")))]
+  [(set (match_operand:GPI 0 "register_operand")
+       (if_then_else:GPI (match_operand 1 "aarch64_comparison_operator")
+                         (match_operand:GPF 2 "register_operand")
+                         (match_operand:GPF 3 "register_operand")))]
   ""
   {
     rtx ccreg;
 )
 
 (define_expand "mov<mode>cc"
-  [(set (match_operand:GPF 0 "register_operand" "")
-       (if_then_else:GPF (match_operand 1 "aarch64_comparison_operator" "")
-                         (match_operand:GPF 2 "register_operand" "")
-                         (match_operand:GPF 3 "register_operand" "")))]
+  [(set (match_operand:GPF 0 "register_operand")
+       (if_then_else:GPF (match_operand 1 "aarch64_comparison_operator")
+                         (match_operand:GPF 2 "register_operand")
+                         (match_operand:GPF 3 "register_operand")))]
   ""
   {
     rtx ccreg;
 )
 
 (define_expand "<neg_not_op><mode>cc"
-  [(set (match_operand:GPI 0 "register_operand" "")
-       (if_then_else:GPI (match_operand 1 "aarch64_comparison_operator" "")
-                         (NEG_NOT:GPI (match_operand:GPI 2 "register_operand" ""))
-                         (match_operand:GPI 3 "register_operand" "")))]
+  [(set (match_operand:GPI 0 "register_operand")
+       (if_then_else:GPI (match_operand 1 "aarch64_comparison_operator")
+                         (NEG_NOT:GPI (match_operand:GPI 2 "register_operand"))
+                         (match_operand:GPI 3 "register_operand")))]
   ""
   {
     rtx ccreg;
   [(set_attr "type" "csel")]
 )
 
+(define_insn "*csinv3_uxtw_insn1"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (if_then_else:DI
+         (match_operand 1 "aarch64_comparison_operation" "")
+         (zero_extend:DI
+           (match_operand:SI 2 "register_operand" "r"))
+         (zero_extend:DI
+           (NEG_NOT:SI (match_operand:SI 3 "register_operand" "r")))))]
+  ""
+  "cs<neg_not_cs>\\t%w0, %w2, %w3, %m1"
+  [(set_attr "type" "csel")]
+)
+
+(define_insn "*csinv3_uxtw_insn2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (if_then_else:DI
+         (match_operand 1 "aarch64_comparison_operation" "")
+         (zero_extend:DI
+           (NEG_NOT:SI (match_operand:SI 2 "register_operand" "r")))
+         (zero_extend:DI
+           (match_operand:SI 3 "register_operand" "r"))))]
+  ""
+  "cs<neg_not_cs>\\t%w0, %w3, %w2, %M1"
+  [(set_attr "type" "csel")]
+)
+
+(define_insn "*csinv3_uxtw_insn3"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (if_then_else:DI
+         (match_operand 1 "aarch64_comparison_operation" "")
+         (zero_extend:DI
+           (NEG_NOT:SI (match_operand:SI 2 "register_operand" "r")))
+         (const_int 0)))]
+  ""
+  "cs<neg_not_cs>\\t%w0, wzr, %w2, %M1"
+  [(set_attr "type" "csel")]
+)
+
 ;; If X can be loaded by a single CNT[BHWD] instruction,
 ;;
 ;;    A = UMAX (B, X)
    (set_attr "arch" "*,simd")]
 )
 
+(define_insn "*one_cmpl_zero_extend"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (zero_extend:DI
+          (not:SI (match_operand:SI 1 "register_operand" "r"))))]
+  ""
+  "mvn\\t%w0, %w1"
+  [(set_attr "type" "logic_reg")]
+)
+
 (define_insn "*one_cmpl_<optab><mode>2"
   [(set (match_operand:GPI 0 "register_operand" "=r")
        (not:GPI (SHIFT:GPI (match_operand:GPI 1 "register_operand" "r")
 {
   rtx v = gen_reg_rtx (V8QImode);
   rtx v1 = gen_reg_rtx (V8QImode);
-  rtx r = gen_reg_rtx (QImode);
   rtx in = operands[1];
   rtx out = operands[0];
   if(<MODE>mode == SImode)
     }
   emit_move_insn (v, gen_lowpart (V8QImode, in));
   emit_insn (gen_popcountv8qi2 (v1, v));
-  emit_insn (gen_reduc_plus_scal_v8qi (r, v1));
-  emit_insn (gen_zero_extendqi<mode>2 (out, r));
+  emit_insn (gen_aarch64_zero_extend<mode>_reduc_plus_v8qi (out, v1));
   DONE;
 })
 
   [(set_attr "type" "alus_imm")]
 )
 
-(define_insn "*ands<mode>_compare0"
+(define_insn "*ands<GPI:mode>_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
         (zero_extend:GPI (match_operand:SHORT 1 "register_operand" "r"))
 ;; -------------------------------------------------------------------
 
 (define_expand "<optab>"
-  [(set (match_operand:DI 0 "register_operand" "=r")
+  [(set (match_operand:DI 0 "register_operand")
        (ANY_EXTRACT:DI (match_operand:DI 1 "register_operand")
                        (match_operand 2
                          "aarch64_simd_shift_imm_offset_di")
   [(set_attr "type" "bfm")]
 )
 
+;;  Match a bfi instruction where the shift of OP3 means that we are
+;;  actually copying the least significant bits of OP3 into OP0 by way
+;;  of the AND masks and the IOR instruction.  A similar instruction
+;;  with the two parts of the IOR swapped around was never triggered
+;;  in a bootstrap build and test of GCC so it was not included.
+
+(define_insn "*aarch64_bfi<GPI:mode>5_shift"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                          (match_operand:GPI 2 "const_int_operand" "n"))
+                 (and:GPI (ashift:GPI
+                           (match_operand:GPI 3 "register_operand" "r")
+                           (match_operand:GPI 4 "aarch64_simd_shift_imm_<mode>" "n"))
+                          (match_operand:GPI 5 "const_int_operand" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[2]),
+                                     UINTVAL (operands[4]),
+                                     UINTVAL(operands[5]))"
+  "bfi\t%<GPI:w>0, %<GPI:w>3, %4, %P5"
+  [(set_attr "type" "bfm")]
+)
+
+(define_insn "*aarch64_bfi<GPI:mode>5_shift_alt"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (ashift:GPI
+                           (match_operand:GPI 1 "register_operand" "r")
+                           (match_operand:GPI 2 "aarch64_simd_shift_imm_<mode>" "n"))
+                          (match_operand:GPI 3 "const_int_operand" "n"))
+                (and:GPI (match_operand:GPI 4 "register_operand" "0")
+                          (match_operand:GPI 5 "const_int_operand" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[5]),
+                                     UINTVAL (operands[2]),
+                                     UINTVAL(operands[3]))"
+  "bfi\t%<GPI:w>0, %<GPI:w>1, %2, %P3"
+  [(set_attr "type" "bfm")]
+)
+
+;; Like *aarch64_bfi<GPI:mode>5_shift but with no and of the ashift because
+;; the shift is large enough to remove the need for an AND instruction.
+
+(define_insn "*aarch64_bfi<GPI:mode>4_noand"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                          (match_operand:GPI 2 "const_int_operand" "n"))
+                 (ashift:GPI
+                          (match_operand:GPI 3 "register_operand" "r")
+                          (match_operand:GPI 4 "aarch64_simd_shift_imm_<mode>" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[2]),
+                                     UINTVAL (operands[4]),
+                                     HOST_WIDE_INT_M1U << UINTVAL (operands[4]) )"
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - UINTVAL (operands[4]));
+  return "bfi\t%<GPI:w>0, %<GPI:w>3, %4, %5";
+}
+  [(set_attr "type" "bfm")]
+)
+
+(define_insn "*aarch64_bfi<GPI:mode>4_noand_alt"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (ashift:GPI
+                          (match_operand:GPI 1 "register_operand" "r")
+                          (match_operand:GPI 2 "aarch64_simd_shift_imm_<mode>" "n"))
+                (and:GPI (match_operand:GPI 3 "register_operand" "0")
+                          (match_operand:GPI 4 "const_int_operand" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[4]),
+                                     UINTVAL (operands[2]),
+                                     HOST_WIDE_INT_M1U << UINTVAL (operands[2]) )"
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - UINTVAL (operands[2]));
+  return "bfi\t%<GPI:w>0, %<GPI:w>1, %2, %5";
+}
+  [(set_attr "type" "bfm")]
+)
+
+;; Like *aarch64_bfi<GPI:mode>5_shift but with no shifting, we are just
+;; copying the least significant bits of OP3 to OP0.  We need two versions
+;; of the instruction to handle different checks on the constant values.
+
+(define_insn "*aarch64_bfi<GPI:mode>4_noshift"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                          (match_operand:GPI 2 "const_int_operand" "n"))
+                 (and:GPI (match_operand:GPI 3 "register_operand" "r")
+                          (match_operand:GPI 4 "const_int_operand" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[2]), 0,
+                                     UINTVAL (operands[4]))"
+  "bfi\t%<GPI:w>0, %<GPI:w>3, 0, %P4"
+  [(set_attr "type" "bfm")]
+)
+
+(define_insn "*aarch64_bfi<GPI:mode>4_noshift_alt"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (ior:GPI (and:GPI (match_operand:GPI 3 "register_operand" "r")
+                          (match_operand:GPI 4 "const_int_operand" "n"))
+                 (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                          (match_operand:GPI 2 "const_int_operand" "n"))))]
+  "aarch64_masks_and_shift_for_bfi_p (<MODE>mode, UINTVAL (operands[2]), 0,
+                                     UINTVAL (operands[4]))"
+  "bfi\t%<GPI:w>0, %<GPI:w>3, 0, %P4"
+  [(set_attr "type" "bfm")]
+)
+
 (define_insn "*extr_insv_lower_reg<mode>"
   [(set (zero_extract:GPI (match_operand:GPI 0 "register_operand" "+r")
                          (match_operand 1 "const_int_operand" "n")
   [(set_attr "type" "bfx")]
 )
 
+(define_insn "*ashiftsi_extvdi_bfiz"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ashift:SI
+         (match_operator:SI 4 "subreg_lowpart_operator"
+           [(sign_extract:DI
+              (match_operand:DI 1 "register_operand" "r")
+              (match_operand 2 "aarch64_simd_shift_imm_offset_si")
+              (const_int 0))])
+         (match_operand 3 "aarch64_simd_shift_imm_si")))]
+  "IN_RANGE (INTVAL (operands[2]) + INTVAL (operands[3]),
+            1, GET_MODE_BITSIZE (SImode) - 1)"
+  "sbfiz\\t%w0, %w1, %3, %2"
+  [(set_attr "type" "bfx")]
+)
+
 ;; When the bit position and width of the equivalent extraction add up to 32
 ;; we can use a W-reg LSL instruction taking advantage of the implicit
 ;; zero-extension of the X-reg.
   [(set_attr "type" "f_cvtf2i")]
 )
 
+;; Equal width integer to fp and multiply combine.
+(define_insn "*aarch64_<su_optab>cvtf<fcvt_target><GPF:mode>2_mult"
+  [(set (match_operand:GPF 0 "register_operand" "=w,w")
+       (mult:GPF (FLOATUORS:GPF
+                  (match_operand:<FCVT_TARGET> 1 "register_operand" "w,?r"))
+                  (match_operand:GPF 2 "aarch64_fp_pow2_recip" "Dt,Dt")))]
+  "TARGET_FLOAT"
+  {
+    operands[2] = GEN_INT (aarch64_fpconst_pow2_recip (operands[2]));
+    switch (which_alternative)
+    {
+      case 0:
+       return "<su_optab>cvtf\t%<GPF:s>0, %<s>1, #%2";
+      case 1:
+       return "<su_optab>cvtf\t%<GPF:s>0, %<w1>1, #%2";
+      default:
+       gcc_unreachable ();
+    }
+  }
+  [(set_attr "type" "neon_int_to_fp_<Vetype>,f_cvti2f")
+   (set_attr "arch" "simd,fp")]
+)
+
+;; Unequal width integer to fp and multiply combine.
+(define_insn "*aarch64_<su_optab>cvtf<fcvt_iesize><GPF:mode>2_mult"
+  [(set (match_operand:GPF 0 "register_operand" "=w")
+       (mult:GPF (FLOATUORS:GPF
+                  (match_operand:<FCVT_IESIZE> 1 "register_operand" "r"))
+                  (match_operand:GPF 2 "aarch64_fp_pow2_recip" "Dt")))]
+  "TARGET_FLOAT"
+  {
+    operands[2] = GEN_INT (aarch64_fpconst_pow2_recip (operands[2]));
+    return "<su_optab>cvtf\t%<GPF:s>0, %<w2>1, #%2";
+  }
+  [(set_attr "type" "f_cvti2f")]
+)
+
+;; Equal width integer to fp conversion.
 (define_insn "<optab><fcvt_target><GPF:mode>2"
   [(set (match_operand:GPF 0 "register_operand" "=w,w")
         (FLOATUORS:GPF (match_operand:<FCVT_TARGET> 1 "register_operand" "w,?r")))]
    (set_attr "arch" "simd,fp")]
 )
 
+;; Unequal width integer to fp conversions.
 (define_insn "<optab><fcvt_iesize><GPF:mode>2"
   [(set (match_operand:GPF 0 "register_operand" "=w")
         (FLOATUORS:GPF (match_operand:<FCVT_IESIZE> 1 "register_operand" "r")))]
 )
 
 (define_expand "sqrt<mode>2"
-  [(set (match_operand:GPF_F16 0 "register_operand" "=w")
-       (sqrt:GPF_F16 (match_operand:GPF_F16 1 "register_operand" "w")))]
+  [(set (match_operand:GPF_F16 0 "register_operand")
+       (sqrt:GPF_F16 (match_operand:GPF_F16 1 "register_operand")))]
   "TARGET_FLOAT"
 {
   if (aarch64_emit_approx_sqrt (operands[0], operands[1], false))
   [(match_operand:GPI 0 "register_operand")
    (match_operand:GPF 1 "register_operand")]
   "TARGET_FLOAT
-   && ((GET_MODE_SIZE (<GPF:MODE>mode) <= GET_MODE_SIZE (<GPI:MODE>mode))
+   && ((GET_MODE_BITSIZE (<GPF:MODE>mode) <= LONG_TYPE_SIZE)
    || !flag_trapping_math || flag_fp_int_builtin_inexact)"
 {
   rtx cvt = gen_reg_rtx (<GPF:MODE>mode);
 ;; -------------------------------------------------------------------
 ;; Reload Scalar Floating point modes from constant pool.
 ;; The AArch64 port doesn't have __int128 constant move support.
+;; The patterns need constraints due to TARGET_SECONDARY_RELOAD hook.
 (define_expand "@aarch64_reload_movcp<GPF_TF:mode><P:mode>"
  [(set (match_operand:GPF_TF 0 "register_operand" "=w")
        (mem:GPF_TF (match_operand 1 "aarch64_constant_pool_symref" "S")))
 ;; rodata section.
 
 (define_expand "add_losym"
-  [(set (match_operand 0 "register_operand" "=r")
-       (lo_sum (match_operand 1 "register_operand" "r")
-               (match_operand 2 "aarch64_valid_symref" "S")))]
+  [(set (match_operand 0 "register_operand")
+       (lo_sum (match_operand 1 "register_operand")
+               (match_operand 2 "aarch64_valid_symref")))]
   ""
 {
   machine_mode mode = GET_MODE (operands[0]);
-
-  emit_insn ((mode == DImode
-             ? gen_add_losym_di
-             : gen_add_losym_si) (operands[0],
-                                  operands[1],
-                                  operands[2]));
+  emit_insn (gen_add_losym (mode, operands[0], operands[1], operands[2]));
   DONE;
 })
 
-(define_insn "add_losym_<mode>"
+(define_insn "@add_losym_<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (lo_sum:P (match_operand:P 1 "register_operand" "r")
                  (match_operand 2 "aarch64_valid_symref" "S")))]
   [(set_attr "type" "alu_imm")]
 )
 
-(define_insn "ldr_got_small_<mode>"
+(define_insn "@ldr_got_small_<mode>"
   [(set (match_operand:PTR 0 "register_operand" "=r")
        (unspec:PTR [(mem:PTR (lo_sum:PTR
                              (match_operand:PTR 1 "register_operand" "r")
   [(set_attr "type" "load_4")]
 )
 
-(define_insn "ldr_got_small_28k_<mode>"
+(define_insn "@ldr_got_small_28k_<mode>"
   [(set (match_operand:PTR 0 "register_operand" "=r")
        (unspec:PTR [(mem:PTR (lo_sum:PTR
                              (match_operand:PTR 1 "register_operand" "r")
   [(set_attr "type" "load_4")]
 )
 
-(define_insn "ldr_got_tiny"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "aarch64_valid_symref" "S")]
-                  UNSPEC_GOTTINYPIC))]
+(define_insn "@ldr_got_tiny_<mode>"
+  [(set (match_operand:PTR 0 "register_operand" "=r")
+       (unspec:PTR [(match_operand:PTR 1 "aarch64_valid_symref" "S")]
+                   UNSPEC_GOTTINYPIC))]
   ""
-  "ldr\\t%0, %L1"
-  [(set_attr "type" "load_8")]
+  "ldr\t%<w>0, %L1"
+  [(set_attr "type" "load_<ldst_sz>")]
 )
 
-(define_insn "aarch64_load_tp_hard"
+(define_insn "ldr_got_tiny_sidi"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(const_int 0)] UNSPEC_TLS))]
+       (zero_extend:DI
+         (unspec:SI [(match_operand:DI 1 "aarch64_valid_symref" "S")]
+                    UNSPEC_GOTTINYPIC)))]
+  "TARGET_ILP32"
+  "ldr\t%w0, %L1"
+  [(set_attr "type" "load_4")]
+)
+
+(define_insn "@aarch64_load_tp_hard_<mode>"
+  [(set (match_operand:ADDR 0 "register_operand" "=r")
+       (unspec:ADDR [(const_int 0)] UNSPEC_TLS))]
   ""
   "mrs\\t%0, tpidr_el0"
   [(set_attr "type" "mrs")]
 ;; instructions in the TLS stubs, in order to enable linker relaxation.
 ;; Therefore we treat the stubs as an atomic sequence.
 (define_expand "tlsgd_small_<mode>"
- [(parallel [(set (match_operand 0 "register_operand" "")
+ [(parallel [(set (match_operand:PTR 0 "register_operand")
                   (call (mem:DI (match_dup 2)) (const_int 1)))
-            (unspec:DI [(match_operand:PTR 1 "aarch64_valid_symref" "")] UNSPEC_GOTSMALLTLS)
+            (unspec:DI [(const_int 0)] UNSPEC_CALLEE_ABI)
+            (unspec:DI [(match_operand 1 "aarch64_valid_symref")] UNSPEC_GOTSMALLTLS)
             (clobber (reg:DI LR_REGNUM))])]
  ""
 {
 })
 
 (define_insn "*tlsgd_small_<mode>"
-  [(set (match_operand 0 "register_operand" "")
+  [(set (match_operand:PTR 0 "register_operand" "")
        (call (mem:DI (match_operand:DI 2 "" "")) (const_int 1)))
-   (unspec:DI [(match_operand:PTR 1 "aarch64_valid_symref" "S")] UNSPEC_GOTSMALLTLS)
+   (unspec:DI [(const_int 0)] UNSPEC_CALLEE_ABI)
+   (unspec:DI [(match_operand 1 "aarch64_valid_symref" "S")] UNSPEC_GOTSMALLTLS)
    (clobber (reg:DI LR_REGNUM))
   ]
   ""
   [(set_attr "type" "call")
    (set_attr "length" "16")])
 
-(define_insn "tlsie_small_<mode>"
-  [(set (match_operand:PTR 0 "register_operand" "=r")
-        (unspec:PTR [(match_operand 1 "aarch64_tls_ie_symref" "S")]
+(define_insn "@tlsie_small_<mode>"
+  [(set (match_operand:<PTR_OFF> 0 "register_operand" "=r")
+        (unspec:<PTR_OFF>
+         [(match_operand 1 "aarch64_tls_ie_symref" "S")
+          (match_operand:PTR 2 "register_operand" "r")]
                   UNSPEC_GOTSMALLTLS))]
-  ""
+  "aarch64_lowpart_regs_p (operands[0], operands[2])"
   "adrp\\t%0, %A1\;ldr\\t%<w>0, [%0, #%L1]"
   [(set_attr "type" "load_4")
    (set_attr "length" "8")]
    (set_attr "length" "8")]
 )
 
-(define_insn "tlsie_tiny_<mode>"
+(define_insn "@tlsie_tiny_<mode>"
   [(set (match_operand:PTR 0 "register_operand" "=&r")
        (unspec:PTR [(match_operand 1 "aarch64_tls_ie_symref" "S")
                     (match_operand:PTR 2 "register_operand" "r")]
    (set_attr "length" "8")]
 )
 
-(define_insn "tlsle12_<mode>"
+(define_insn "@tlsle12_<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (unspec:P [(match_operand:P 1 "register_operand" "r")
                   (match_operand 2 "aarch64_tls_le_symref" "S")]
    (set_attr "length" "4")]
 )
 
-(define_insn "tlsle24_<mode>"
+(define_insn "@tlsle24_<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (unspec:P [(match_operand:P 1 "register_operand" "r")
                   (match_operand 2 "aarch64_tls_le_symref" "S")]
    (set_attr "length" "8")]
 )
 
-(define_insn "tlsle32_<mode>"
+(define_insn "@tlsle32_<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (unspec:P [(match_operand 1 "aarch64_tls_le_symref" "S")]
                   UNSPEC_TLSLE32))]
    (set_attr "length" "8")]
 )
 
-(define_insn "tlsle48_<mode>"
+(define_insn "@tlsle48_<mode>"
   [(set (match_operand:P 0 "register_operand" "=r")
        (unspec:P [(match_operand 1 "aarch64_tls_le_symref" "S")]
                   UNSPEC_TLSLE48))]
    (set_attr "length" "12")]
 )
 
-(define_expand "tlsdesc_small_<mode>"
+(define_expand "@tlsdesc_small_<mode>"
   [(unspec:PTR [(match_operand 0 "aarch64_valid_symref")] UNSPEC_TLSDESC)]
   "TARGET_TLS_DESC"
   {
     if (TARGET_SVE)
-      emit_insn (gen_tlsdesc_small_sve_<mode> (operands[0]));
+      {
+       rtx abi = gen_int_mode (aarch64_tlsdesc_abi_id (), DImode);
+       rtx_insn *call
+         = emit_call_insn (gen_tlsdesc_small_sve_<mode> (operands[0], abi));
+       RTL_CONST_CALL_P (call) = 1;
+      }
     else
       emit_insn (gen_tlsdesc_small_advsimd_<mode> (operands[0]));
     DONE;
   [(set (reg:PTR R0_REGNUM)
         (unspec:PTR [(match_operand 0 "aarch64_valid_symref" "S")]
                    UNSPEC_TLSDESC))
-   (clobber (reg:DI LR_REGNUM))
+   (clobber (reg:<P_OF_PTR> LR_REGNUM))
    (clobber (reg:CC CC_REGNUM))
-   (clobber (match_scratch:DI 1 "=r"))]
+   (clobber (match_scratch:<P_OF_PTR> 1 "=r"))
+   (use (reg:<P_OF_PTR> FP_REGNUM))]
   "TARGET_TLS_DESC && !TARGET_SVE"
-  "adrp\\tx0, %A0\;ldr\\t%<w>1, [x0, #%L0]\;add\\t<w>0, <w>0, %L0\;.tlsdesccall\\t%0\;blr\\t%1"
+  {
+    if (<MODE>mode == CADImode)
+      return "adrp\\tx0, %A0\;ldr\\t%<w>1, [x0, #%L0]\;add\\tx0, x0, %L0\;.tlsdesccall\\t%0\;blr\\t%1";
+    else
+      return "adrp\\tx0, %A0\;ldr\\t%<w>1, [x0, #%L0]\;add\\t<w>0, <w>0, %L0\;.tlsdesccall\\t%0\;blr\\t%1";
+  }
   [(set_attr "type" "call")
    (set_attr "length" "16")])
 
-;; For SVE, model tlsdesc calls as clobbering the lower 128 bits of
-;; all vector registers, and clobber all predicate registers, on
-;; top of the usual R0 and LR.
+;; For SVE, model tlsdesc calls as normal calls, with the callee ABI
+;; describing the extra call-preserved guarantees.  This would work
+;; for non-SVE too, but avoiding a call is probably better if we can.
 (define_insn "tlsdesc_small_sve_<mode>"
   [(set (reg:PTR R0_REGNUM)
-        (unspec:PTR [(match_operand 0 "aarch64_valid_symref" "S")]
-                   UNSPEC_TLSDESC))
+       (call (mem:DI (unspec:PTR
+                       [(match_operand 0 "aarch64_valid_symref")]
+                       UNSPEC_TLSDESC))
+             (const_int 0)))
+   (unspec:DI [(match_operand:DI 1 "const_int_operand")] UNSPEC_CALLEE_ABI)
    (clobber (reg:DI LR_REGNUM))
-   (clobber (reg:CC CC_REGNUM))
-   (clobber_high (reg:TI V0_REGNUM))
-   (clobber_high (reg:TI V1_REGNUM))
-   (clobber_high (reg:TI V2_REGNUM))
-   (clobber_high (reg:TI V3_REGNUM))
-   (clobber_high (reg:TI V4_REGNUM))
-   (clobber_high (reg:TI V5_REGNUM))
-   (clobber_high (reg:TI V6_REGNUM))
-   (clobber_high (reg:TI V7_REGNUM))
-   (clobber_high (reg:TI V8_REGNUM))
-   (clobber_high (reg:TI V9_REGNUM))
-   (clobber_high (reg:TI V10_REGNUM))
-   (clobber_high (reg:TI V11_REGNUM))
-   (clobber_high (reg:TI V12_REGNUM))
-   (clobber_high (reg:TI V13_REGNUM))
-   (clobber_high (reg:TI V14_REGNUM))
-   (clobber_high (reg:TI V15_REGNUM))
-   (clobber_high (reg:TI V16_REGNUM))
-   (clobber_high (reg:TI V17_REGNUM))
-   (clobber_high (reg:TI V18_REGNUM))
-   (clobber_high (reg:TI V19_REGNUM))
-   (clobber_high (reg:TI V20_REGNUM))
-   (clobber_high (reg:TI V21_REGNUM))
-   (clobber_high (reg:TI V22_REGNUM))
-   (clobber_high (reg:TI V23_REGNUM))
-   (clobber_high (reg:TI V24_REGNUM))
-   (clobber_high (reg:TI V25_REGNUM))
-   (clobber_high (reg:TI V26_REGNUM))
-   (clobber_high (reg:TI V27_REGNUM))
-   (clobber_high (reg:TI V28_REGNUM))
-   (clobber_high (reg:TI V29_REGNUM))
-   (clobber_high (reg:TI V30_REGNUM))
-   (clobber_high (reg:TI V31_REGNUM))
-   (clobber (reg:VNx2BI P0_REGNUM))
-   (clobber (reg:VNx2BI P1_REGNUM))
-   (clobber (reg:VNx2BI P2_REGNUM))
-   (clobber (reg:VNx2BI P3_REGNUM))
-   (clobber (reg:VNx2BI P4_REGNUM))
-   (clobber (reg:VNx2BI P5_REGNUM))
-   (clobber (reg:VNx2BI P6_REGNUM))
-   (clobber (reg:VNx2BI P7_REGNUM))
-   (clobber (reg:VNx2BI P8_REGNUM))
-   (clobber (reg:VNx2BI P9_REGNUM))
-   (clobber (reg:VNx2BI P10_REGNUM))
-   (clobber (reg:VNx2BI P11_REGNUM))
-   (clobber (reg:VNx2BI P12_REGNUM))
-   (clobber (reg:VNx2BI P13_REGNUM))
-   (clobber (reg:VNx2BI P14_REGNUM))
-   (clobber (reg:VNx2BI P15_REGNUM))
-   (clobber (match_scratch:DI 1 "=r"))]
+   (clobber (match_scratch:DI 2 "=r"))]
   "TARGET_TLS_DESC && TARGET_SVE"
-  "adrp\\tx0, %A0\;ldr\\t%<w>1, [x0, #%L0]\;add\\t<w>0, <w>0, %L0\;.tlsdesccall\\t%0\;blr\\t%1"
+  "adrp\\tx0, %A0\;ldr\\t%<w>2, [x0, #%L0]\;add\\t<w>0, <w>0, %L0\;.tlsdesccall\\t%0\;blr\\t%2"
   [(set_attr "type" "call")
    (set_attr "length" "16")])
 
 (define_insn "stack_tie"
   [(set (mem:BLK (scratch))
-       (unspec:BLK [(match_operand:DI 0 "register_operand" "rk")
-                    (match_operand:DI 1 "register_operand" "rk")]
+       (unspec:BLK [(match_operand 0 "pmode_register_operand" "rk")
+                    (match_operand 1 "pmode_register_operand" "rk")]
                    UNSPEC_PRLG_STK))]
   ""
   ""
   [(set_attr "length" "0")]
 )
 
+(define_insn "aarch64_fjcvtzs"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(match_operand:DF 1 "register_operand" "w")]
+                  UNSPEC_FJCVTZS))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_JSCVT"
+  "fjcvtzs\\t%w0, %d1"
+  [(set_attr "type" "f_cvtf2i")]
+)
+
 ;; Pointer authentication patterns are always provided.  In architecture
 ;; revisions prior to ARMv8.3-A these HINT instructions operate as NOPs.
 ;; This lets the user write portable software which authenticates pointers
   [(set (reg:DI R30_REGNUM)
        (unspec:DI [(reg:DI R30_REGNUM) (reg:DI SP_REGNUM)] PAUTH_LR_SP))]
   ""
-  "hint\t<pauth_hint_num_a> // <pauth_mnem_prefix>asp";
+  "hint\t<pauth_hint_num> // <pauth_mnem_prefix>sp";
 )
 
 ;; Signing/Authenticating X17 using X16 as the salt.
   [(set (reg:DI R17_REGNUM)
        (unspec:DI [(reg:DI R17_REGNUM) (reg:DI R16_REGNUM)] PAUTH_17_16))]
   ""
-  "hint\t<pauth_hint_num_a> // <pauth_mnem_prefix>a1716";
+  "hint\t<pauth_hint_num> // <pauth_mnem_prefix>1716";
 )
 
 ;; Stripping the signature in R30.
    (set_attr "type" "block")]
 )
 
-(define_insn "probe_stack_range"
-  [(set (match_operand:DI 0 "register_operand" "=rk")
-       (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "0")
-                            (match_operand:DI 2 "register_operand" "r")]
+(define_insn "probe_stack_range_<mode>"
+  [(set (match_operand:ADDR 0 "register_operand" "=rk")
+       (unspec_volatile:ADDR [(match_operand:ADDR 1 "register_operand" "0")
+                              (match_operand:ADDR 2 "register_operand" "r")]
                              UNSPECV_PROBE_STACK_RANGE))]
   ""
 {
 ;; probing loop.  We can't change the control flow during prologue and epilogue
 ;; code generation.  So we must emit a volatile unspec and expand it later on.
 
+;; MORELLO TODO The pattern here uses Pmode for everything, but the
+;; min_probe_threshold, adjustment, and guard_size should all be in POmode.
 (define_insn "@probe_sve_stack_clash_<mode>"
   [(set (match_operand:P 0 "register_operand" "=rk")
        (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
 
 ;; Named pattern for expanding thread pointer reference.
 (define_expand "get_thread_pointerdi"
-  [(match_operand:DI 0 "register_operand" "=r")]
+  [(match_operand:DI 0 "register_operand")]
   ""
 {
   rtx tmp = aarch64_load_tp (operands[0]);
   ""
 {
   machine_mode mode = GET_MODE (operands[0]);
+  if (aarch64_stack_protector_guard != SSP_GLOBAL)
+  {
+    /* Generate access through the system register.  */
+    rtx tmp_reg = gen_reg_rtx (mode);
+    emit_insn (gen_reg_stack_protect_address (mode, tmp_reg));
+    emit_insn (gen_add3_insn (tmp_reg, tmp_reg,
+                             GEN_INT (aarch64_stack_protector_guard_offset)));
+    operands[1] = gen_rtx_MEM (mode, tmp_reg);
+  }
 
-  emit_insn ((mode == DImode
-             ? gen_stack_protect_set_di
-             : gen_stack_protect_set_si) (operands[0], operands[1]));
+  emit_insn (gen_stack_protect_set (mode, operands[0], operands[1]));
   DONE;
 })
 
-(define_insn "stack_protect_set_<mode>"
+(define_insn "@reg_stack_protect_address_<mode>"
+ [(set (match_operand:PTR 0 "register_operand" "=r")
+       (unspec:PTR [(const_int 0)]
+       UNSPEC_SSP_SYSREG))]
+ "aarch64_stack_protector_guard != SSP_GLOBAL"
+ {
+   char buf[150];
+   snprintf (buf, 150, "mrs\\t%%<w>0, %s",
+           aarch64_stack_protector_guard_reg_str);
+   output_asm_insn (buf, operands);
+   return "";
+ }
+ [(set_attr "type" "mrs")])
+
+;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
+;; canary value does not live beyond the life of this sequence.
+(define_insn "@stack_protect_set_<mode>"
   [(set (match_operand:PTR 0 "memory_operand" "=m")
        (unspec:PTR [(match_operand:PTR 1 "memory_operand" "m")]
         UNSPEC_SP_SET))
    (set (match_scratch:PTR 2 "=&r") (const_int 0))]
   ""
-  "ldr\\t%<w>2, %1\;str\\t%<w>2, %0\;mov\t%<w>2,0"
+  "ldr\\t%<w>2, %1\;str\\t%<w>2, %0\;mov\t%<w>2, 0"
   [(set_attr "length" "12")
    (set_attr "type" "multiple")])
 
    (match_operand 2)]
   ""
 {
-  rtx result;
   machine_mode mode = GET_MODE (operands[0]);
 
-  result = gen_reg_rtx(mode);
-
-  emit_insn ((mode == DImode
-             ? gen_stack_protect_test_di
-             : gen_stack_protect_test_si) (result,
-                                           operands[0],
-                                           operands[1]));
+  if (aarch64_stack_protector_guard != SSP_GLOBAL)
+  {
+    /* Generate access through the system register. The
+       sequence we want here is the access
+       of the stack offset to come with
+       mrs scratch_reg, <system_register>
+       add scratch_reg, scratch_reg, :lo12:offset. */
+    rtx tmp_reg = gen_reg_rtx (mode);
+
+    emit_insn (gen_reg_stack_protect_address (mode, tmp_reg));
+    emit_insn (gen_add3_insn (tmp_reg, tmp_reg,
+                             GEN_INT (aarch64_stack_protector_guard_offset)));
+    operands[1] = gen_rtx_MEM (mode, tmp_reg);
+  }
+  emit_insn (gen_stack_protect_test (mode, operands[0], operands[1]));
 
-  if (mode == DImode)
-    emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
-                                   result, const0_rtx, operands[2]));
-  else
-    emit_jump_insn (gen_cbranchsi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
-                                   result, const0_rtx, operands[2]));
+  rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
+  emit_jump_insn (gen_condjump (gen_rtx_EQ (VOIDmode, cc_reg, const0_rtx),
+                               cc_reg, operands[2]));
   DONE;
 })
 
-(define_insn "stack_protect_test_<mode>"
-  [(set (match_operand:PTR 0 "register_operand" "=r")
-       (unspec:PTR [(match_operand:PTR 1 "memory_operand" "m")
-                    (match_operand:PTR 2 "memory_operand" "m")]
-        UNSPEC_SP_TEST))
+;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
+;; canary value does not live beyond the end of this sequence.
+(define_insn "@stack_protect_test_<mode>"
+  [(set (reg:CC CC_REGNUM)
+       (unspec:CC [(match_operand:PTR 0 "memory_operand" "m")
+                   (match_operand:PTR 1 "memory_operand" "m")]
+                  UNSPEC_SP_TEST))
+   (clobber (match_scratch:PTR 2 "=&r"))
    (clobber (match_scratch:PTR 3 "=&r"))]
   ""
-  "ldr\t%<w>3, %1\;ldr\t%<w>0, %2\;eor\t%<w>0, %<w>3, %<w>0"
-  [(set_attr "length" "12")
+  "ldr\t%<w>2, %0\;ldr\t%<w>3, %1\;subs\t%<w>2, %<w>2, %<w>3\;mov\t%3, 0"
+  [(set_attr "length" "16")
    (set_attr "type" "multiple")])
 
-;; Write Floating-point Control Register.
-(define_insn "set_fpcr"
-  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPCR)]
-  ""
-  "msr\\tfpcr, %0"
-  [(set_attr "type" "mrs")])
-
-;; Read Floating-point Control Register.
-(define_insn "get_fpcr"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-        (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPCR))]
-  ""
-  "mrs\\t%0, fpcr"
-  [(set_attr "type" "mrs")])
-
-;; Write Floating-point Status Register.
-(define_insn "set_fpsr"
-  [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR)]
+;; Write into the Floating-point Status or Control Register.
+(define_insn "@aarch64_set_<fpscr_name><GPI:mode>"
+  [(unspec_volatile [(match_operand:GPI 0 "register_operand" "r")] SET_FPSCR)]
   ""
-  "msr\\tfpsr, %0"
+  "msr\\t<fpscr_name>, %0"
   [(set_attr "type" "mrs")])
 
-;; Read Floating-point Status Register.
-(define_insn "get_fpsr"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-        (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR))]
+;; Read into the Floating-point Status or Control Register.
+(define_insn "@aarch64_get_<fpscr_name><GPI:mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+        (unspec_volatile:GPI [(const_int 0)] GET_FPSCR))]
   ""
-  "mrs\\t%0, fpsr"
+  "mrs\\t%0, <fpscr_name>"
   [(set_attr "type" "mrs")])
 
-
 ;; Define the subtract-one-and-jump insns so loop.c
 ;; knows what to generate.
 (define_expand "doloop_end"
   [(set_attr "type" "csel")]
 )
 
-;; Helper for aarch64.c code.
-(define_expand "set_clobber_cc"
-  [(parallel [(set (match_operand 0)
-                  (match_operand 1))
-             (clobber (reg:CC CC_REGNUM))])])
+;; Like speculation_tracker, but track the inverse condition.
+(define_insn "speculation_tracker_rev"
+  [(set (reg:DI SPECULATION_TRACKER_REGNUM)
+       (unspec:DI [(reg:DI SPECULATION_TRACKER_REGNUM) (match_operand 0)]
+        UNSPEC_SPECULATION_TRACKER_REV))]
+  ""
+  {
+    operands[1] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn ("csel\\t%1, %1, xzr, %M0", operands);
+    return "";
+  }
+  [(set_attr "type" "csel")]
+)
+
+;; BTI <target> instructions
+(define_insn "bti_noarg"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_NOARG)]
+  ""
+  "hint\t32 // bti"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_c"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_C)]
+  ""
+  "hint\t34 // bti c"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_j"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_J)]
+  ""
+  "hint\t36 // bti j"
+  [(set_attr "type" "no_insn")]
+)
+
+(define_insn "bti_jc"
+  [(unspec_volatile [(const_int 0)] UNSPECV_BTI_JC)]
+  ""
+  "hint\t38 // bti jc"
+  [(set_attr "type" "no_insn")]
+)
 
 ;; Hard speculation barrier.
 (define_insn "speculation_barrier"
 ;; tracking enabled.  Use the speculation tracker to decide whether to
 ;; copy operand 1 to the target, or to copy the fail value (operand 2).
 (define_expand "@despeculate_copy<ALLI_TI:mode>"
-  [(set (match_operand:ALLI_TI 0 "register_operand" "=r")
+  [(set (match_operand:ALLI_TI 0 "register_operand")
        (unspec_volatile:ALLI_TI
-        [(match_operand:ALLI_TI 1 "register_operand" "r")
-         (match_operand:ALLI_TI 2 "aarch64_reg_or_zero" "rZ")
+        [(match_operand:ALLI_TI 1 "register_operand")
+         (match_operand:ALLI_TI 2 "aarch64_reg_or_zero")
          (use (reg:DI SPECULATION_TRACKER_REGNUM))
          (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
   ""
    (set_attr "speculation_barrier" "true")]
 )
 
+(define_insn "aarch64_<frintnzs_op><mode>"
+  [(set (match_operand:VSFDF 0 "register_operand" "=w")
+       (unspec:VSFDF [(match_operand:VSFDF 1 "register_operand" "w")]
+                     FRINTNZX))]
+  "TARGET_FRINT && TARGET_FLOAT
+   && !(VECTOR_MODE_P (<MODE>mode) && !TARGET_SIMD)"
+  "<frintnzs_op>\\t%<v>0<Vmtype>, %<v>1<Vmtype>"
+  [(set_attr "type" "f_rint<stype>")]
+)
+
+;; Transactional Memory Extension (TME) instructions.
+
+(define_insn "tstart"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(const_int 0)] UNSPECV_TSTART))
+   (clobber (mem:BLK (scratch)))]
+  "TARGET_TME"
+  "tstart\\t%0"
+  [(set_attr "type" "tme")]
+)
+
+(define_insn "ttest"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(const_int 0)] UNSPEC_TTEST))
+   (clobber (mem:BLK (scratch)))]
+  "TARGET_TME"
+  "ttest\\t%0"
+  [(set_attr "type" "tme")]
+)
+
+(define_insn "tcommit"
+  [(unspec_volatile:BLK [(const_int 0)] UNSPECV_TCOMMIT)
+   (clobber (mem:BLK (scratch)))]
+  "TARGET_TME"
+  "tcommit"
+  [(set_attr "type" "tme")]
+)
+
+(define_insn "tcancel"
+  [(unspec_volatile:BLK
+     [(match_operand 0 "const_int_operand" "n")] UNSPECV_TCANCEL)
+   (clobber (mem:BLK (scratch)))]
+  "TARGET_TME && (UINTVAL (operands[0]) <= 65535)"
+  "tcancel\\t#%0"
+  [(set_attr "type" "tme")]
+)
+
+(define_insn "aarch64_rndr"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(const_int 0)] UNSPEC_RNDR))
+   (set (reg:CC_Z CC_REGNUM)
+       (unspec_volatile:CC_Z [(const_int 0)] UNSPEC_RNDR))]
+  "TARGET_RNG"
+  "mrs\t%0, RNDR"
+  [(set_attr "type" "mrs")]
+)
+
+(define_insn "aarch64_rndrrs"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(const_int 0)] UNSPEC_RNDRRS))
+   (set (reg:CC_Z CC_REGNUM)
+       (unspec_volatile:CC_Z [(const_int 0)] UNSPEC_RNDRRS))]
+  "TARGET_RNG"
+  "mrs\t%0, RNDRRS"
+  [(set_attr "type" "mrs")]
+)
+
+;; Memory Tagging Extension (MTE) instructions.
+
+(define_insn "irg"
+  [(set (match_operand:DI 0 "register_operand" "=rk")
+       (ior:DI
+        (and:DI (match_operand:DI 1 "register_operand" "rk")
+                (const_int -1080863910568919041)) ;; 0xf0ff...
+        (ashift:DI (unspec:QI [(match_operand:DI 2 "register_operand" "r")]
+                    UNSPEC_GEN_TAG_RND)
+                   (const_int 56))))]
+  "TARGET_MEMTAG"
+  "irg\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "gmi"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ior:DI (ashift:DI
+                (const_int 1)
+                (and:QI (lshiftrt:DI
+                         (match_operand:DI 1 "register_operand" "rk")
+                         (const_int 56)) (const_int 15)))
+               (match_operand:DI 2 "register_operand" "r")))]
+  "TARGET_MEMTAG"
+  "gmi\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "addg"
+  [(set (match_operand:DI 0 "register_operand" "=rk")
+       (ior:DI
+        (and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
+                         (match_operand:DI 2 "aarch64_granule16_uimm6" "i"))
+                (const_int -1080863910568919041)) ;; 0xf0ff...
+        (ashift:DI
+         (unspec:QI
+          [(and:QI (lshiftrt:DI (match_dup 1) (const_int 56)) (const_int 15))
+           (match_operand:QI 3 "aarch64_memtag_tag_offset" "i")]
+          UNSPEC_GEN_TAG)
+         (const_int 56))))]
+  "TARGET_MEMTAG"
+  "addg\\t%0, %1, #%2, #%3"
+  [(set_attr "type" "memtag")]
+)
+
+(define_insn "subp"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (minus:DI
+         (and:DI (match_operand:DI 1 "register_operand" "rk")
+                 (const_int 72057594037927935)) ;; 0x00ff...
+         (and:DI (match_operand:DI 2 "register_operand" "rk")
+                 (const_int 72057594037927935))))] ;; 0x00ff...
+  "TARGET_MEMTAG"
+  "subp\\t%0, %1, %2"
+  [(set_attr "type" "memtag")]
+)
+
+;; LDG will use the 16-byte aligned value of the address.
+(define_insn "ldg"
+  [(set (match_operand:DI 0 "register_operand" "+r")
+       (ior:DI
+        (and:DI (match_dup 0) (const_int -1080863910568919041)) ;; 0xf0ff...
+        (ashift:DI
+         (mem:QI (unspec:DI
+          [(and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
+                            (match_operand:DI 2 "aarch64_granule16_simm9" "i"))
+                   (const_int -16))] UNSPEC_TAG_SPACE))
+         (const_int 56))))]
+  "TARGET_MEMTAG"
+  "ldg\\t%0, [%1, #%2]"
+  [(set_attr "type" "memtag")]
+)
+
+;; STG doesn't align the address but aborts with alignment fault
+;; when the address is not 16-byte aligned.
+(define_insn "stg"
+  [(set (mem:QI (unspec:DI
+        [(plus:DI (match_operand:DI 1 "register_operand" "rk")
+                  (match_operand:DI 2 "aarch64_granule16_simm9" "i"))]
+        UNSPEC_TAG_SPACE))
+       (and:QI (lshiftrt:DI (match_operand:DI 0 "register_operand" "rk")
+                            (const_int 56)) (const_int 15)))]
+  "TARGET_MEMTAG"
+  "stg\\t%0, [%1, #%2]"
+  [(set_attr "type" "memtag")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 
 
 ;; SVE.
 (include "aarch64-sve.md")
+
+;; SVE2.
+(include "aarch64-sve2.md")
+
+;; Morello
+(include "aarch64-morello.md")
This page took 0.120449 seconds and 5 git commands to generate.