Add internal functions and optabs for:

- First-faulting loads
- Non-faulting loads
- Set ffr state
- Read ffr state

This also adds an implicit idea of "global ff state" at the gimple
level, through VDEF's and VUSE's.

Remove ldff1 and ldnf1 from pfalse-load.c test, as the FFR state change
(VDEF) can no longer be removed.

gcc/ChangeLog:

        * config/aarch64/aarch64-sve-builtins-base.cc (svld1_impl::fold):
        Use fold_continuous_load.
        (svldxf1_impl): Add LDFF/LDNF flag, and add folding to use
        IFN_MASK_FIRSTFAULT_LOAD.
        (svldxf1_extend_impl): Change fold to add else operand.
        (svrdffr_impl): Add fold to IFN_READ_FAULT_STATE and update
        expand.
        (svsetffr_impl): Add fold to IFN_SET_FAULT_STATE and update
        expand.
        * config/aarch64/aarch64-sve-builtins.cc
        (gimple_folder::fold_contiguous_load): New function.
        * config/aarch64/aarch64-sve-builtins.h:
        (gimple_folder::fold_contiguous_load): New function.
        * config/aarch64/aarch64-sve.md (aarch64_wrffr): Remove.
        (@set_first_fault_state<mode>): New instruction.
        (aarch64_rdffr<mode>): Add mode.
        (read_first_fault_state<mode>): New expand.
        (aarch64_rdffr_z<mode>): Add mode.
        (*aarch64_rdffr_z_ptest<mode>): Add mode.
        (*aarch64_rdffr_ptest<mode>): Add mode.
        (*aarch64_rdffr_z_cc<mode>): Add mode.
        (*aarch64_rdffr_cc<mode>): Add mode.
        (aarch64_ld<fn>f1<mode>): Add support for sparse
        vectors via extending loads.
        (mask_<nonfirst>fault_load<mode><vpred>): New expand.
        
(aarch64_ld<fn>f1_<ANY_EXTEND:optab><SVE_HSDI:mode><SVE_PARTIAL_I:mode>):
        Add else operand.
        * config/aarch64/iterators.md (nonfirst): New iterator.
        * internal-fn.cc (read_first_fault_state_direct): New macro.
        (set_first_fault_state_direct): New macro.
        (expand_read_first_fault_state_optab_fn): New macro.
        (expand_set_first_fault_state_optab_fn): New function.
        (direct_read_first_fault_state_optab_supported_p): New macro.
        (direct_set_first_fault_state_optab_supported_p): New macro.
        (internal_load_fn_p): Add IFN_MASK_FIRSTFAULT_LOAD and
        IFN_MASK_NONFAULT_LOAD.
        (internal_fn_else_index): Ditto.
        (internal_fn_mask_index): Ditto.
        (internal_fn_alias_ptr_index): Ditto,
        * internal-fn.def (SET_FAlLT_STATE): New internal function.
        (MASK_NONFAULT_LOAD): Ditto.
        (MASK_FIRSTFAULT_LOAD): Ditto
        (READ_FAULT_STATE): Ditto
        * optabs.def (mask_nonfault_load_optab): New optab
        (mask_firstfault_load_optab): Ditto.
        (read_first_fault_state_optab): Ditto.
        (set_first_fault_state_optab): Ditto.
        * tree-data-ref.cc (get_references_in_stmt): Add
        IFN_MASK_FIRSTFAULT_LOAD and IFN_MASK_NONFAULT_LOAD.
        * tree-ssa-alias.cc (ref_maybe_used_by_call_p_1): Ditto.
        * tree-ssa-loop-ivopts.cc (get_alias_ptr_type_for_ptr_address):
        Ditto.
        * tree-vect-slp.cc (vect_get_operand_map): Ditto.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/pfalse-load.c: Remove ldff1 and ldnf1
        tests.

Co-Authored-By: Alex Coplan <[email protected]>
---
 .../aarch64/aarch64-sve-builtins-base.cc      |  78 +++----
 gcc/config/aarch64/aarch64-sve-builtins.cc    |  24 +++
 gcc/config/aarch64/aarch64-sve-builtins.h     |   1 +
 gcc/config/aarch64/aarch64-sve.md             | 201 +++++++++++++++---
 gcc/config/aarch64/iterators.md               |   2 +
 gcc/internal-fn.cc                            |  24 +++
 gcc/internal-fn.def                           |  18 ++
 gcc/optabs.def                                |   5 +
 .../gcc.target/aarch64/sve/pfalse-load.c      |   6 +-
 gcc/tree-data-ref.cc                          |   4 +
 gcc/tree-ssa-alias.cc                         |   2 +
 gcc/tree-ssa-loop-ivopts.cc                   |   2 +
 gcc/tree-vect-slp.cc                          |   4 +
 13 files changed, 307 insertions(+), 64 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc 
b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index 1fa7473283d..9d0f8fde268 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -1682,23 +1682,7 @@ public:
   gimple *
   fold (gimple_folder &f) const override
   {
-    if (f.vectors_per_tuple () != 1)
-      return nullptr;
-
-    tree vectype = f.vector_type (0);
-
-    /* Get the predicate and base pointer.  */
-    gimple_seq stmts = NULL;
-    tree pred = f.convert_pred (stmts, vectype, 0);
-    tree base = f.fold_contiguous_base (stmts, vectype);
-    tree els = build_zero_cst (vectype);
-    gsi_insert_seq_before (f.gsi, stmts, GSI_SAME_STMT);
-
-    tree cookie = f.load_store_cookie (TREE_TYPE (vectype));
-    gcall *new_call = gimple_build_call_internal (IFN_MASK_LOAD, 4,
-                                                 base, cookie, pred, els);
-    gimple_call_set_lhs (new_call, f.lhs);
-    return new_call;
+    return f.fold_contiguous_load (IFN_MASK_LOAD);
   }
 
   rtx
@@ -2040,7 +2024,10 @@ public:
 class svldxf1_impl : public full_width_access
 {
 public:
-  CONSTEXPR svldxf1_impl (int unspec) : m_unspec (unspec) {}
+  CONSTEXPR svldxf1_impl (int unspec) : m_first (unspec == UNSPEC_LDFF1)
+  {
+    gcc_checking_assert (m_first || unspec == UNSPEC_LDNF1);
+  }
 
   unsigned int
   call_properties (const function_instance &) const override
@@ -2048,19 +2035,23 @@ public:
     return CP_READ_MEMORY | CP_READ_FFR | CP_WRITE_FFR;
   }
 
-  rtx
-  expand (function_expander &e) const override
+  gimple *fold (gimple_folder &f) const override
   {
-    /* See the block comment in aarch64-sve.md for details about the
-       FFR handling.  */
-    emit_insn (gen_aarch64_update_ffr_for_load ());
+    auto ifn_code = m_first ? IFN_MASK_FIRSTFAULT_LOAD : 
IFN_MASK_NONFAULT_LOAD;
+    return f.fold_contiguous_load (ifn_code);
+  }
 
-    machine_mode mode = e.vector_mode (0);
-    return e.use_contiguous_load_insn (code_for_aarch64_ldf1 (m_unspec, mode));
+  rtx expand (function_expander &e) const override
+  {
+    auto optab
+      = m_first ? mask_firstfault_load_optab : mask_nonfault_load_optab;
+    auto icode = convert_optab_handler (optab,
+                                       e.vector_mode (0),
+                                       e.gp_mode (0));
+    return e.use_contiguous_load_insn (icode, true);
   }
 
-  /* The unspec associated with the load.  */
-  int m_unspec;
+  bool m_first;
 };
 
 /* Implements extending contiguous forms of svldff1 and svldnf1.  */
@@ -2086,7 +2077,7 @@ public:
     insn_code icode = code_for_aarch64_ldf1 (m_unspec, extend_rtx_code (),
                                             e.vector_mode (0),
                                             e.memory_vector_mode ());
-    return e.use_contiguous_load_insn (icode);
+    return e.use_contiguous_load_insn (icode, true);
   }
 
   /* The unspec associated with the load.  */
@@ -2842,15 +2833,24 @@ public:
     return CP_READ_FFR;
   }
 
-  rtx
-  expand (function_expander &e) const override
+  gimple *fold (gimple_folder &f) const override
+  {
+    if (f.pred == PRED_z)
+      return NULL;
+
+    gcall *new_call = gimple_build_call_internal (IFN_READ_FAULT_STATE, 0);
+    gimple_call_set_lhs (new_call, f.lhs);
+    return new_call;
+  }
+
+  rtx expand (function_expander &e) const override
   {
     /* See the block comment in aarch64-sve.md for details about the
        FFR handling.  */
     emit_insn (gen_aarch64_copy_ffr_to_ffrt ());
     rtx result = e.use_exact_insn (e.pred == PRED_z
-                                  ? CODE_FOR_aarch64_rdffr_z
-                                  : CODE_FOR_aarch64_rdffr);
+                                  ? CODE_FOR_aarch64_rdffr_zvnx16bi
+                                  : CODE_FOR_aarch64_rdffrvnx16bi);
     emit_insn (gen_aarch64_update_ffrt ());
     return result;
   }
@@ -3035,11 +3035,17 @@ public:
     return CP_WRITE_FFR;
   }
 
-  rtx
-  expand (function_expander &e) const override
+  gimple *fold (gimple_folder &f ATTRIBUTE_UNUSED) const override
+  {
+    tree bool_type = acle_vector_types[0][VECTOR_TYPE_svbool_t];
+    return gimple_build_call_internal (IFN_SET_FAULT_STATE, 1,
+                                      build_all_ones_cst (bool_type));
+  }
+
+  rtx expand (function_expander &e) const override
   {
     e.args.quick_push (CONSTM1_RTX (VNx16BImode));
-    return e.use_exact_insn (CODE_FOR_aarch64_wrffr);
+    return e.use_exact_insn (code_for_set_first_fault_state (VNx16BImode));
   }
 };
 
@@ -3465,7 +3471,7 @@ public:
   rtx
   expand (function_expander &e) const override
   {
-    return e.use_exact_insn (CODE_FOR_aarch64_wrffr);
+    return e.use_exact_insn (code_for_set_first_fault_state (VNx16BImode));
   }
 };
 
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc 
b/gcc/config/aarch64/aarch64-sve-builtins.cc
index cd78713440f..6ffc2ef4273 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -3602,6 +3602,30 @@ gimple_folder::fold_contiguous_base (gimple_seq &stmts, 
tree vectype)
   return base;
 }
 
+/* Common code to fold a contiguous load intrinsic call into a gimple
+   call to IFN_CODE.  */
+gimple *
+gimple_folder::fold_contiguous_load (internal_fn ifn_code)
+{
+  if (vectors_per_tuple () != 1)
+    return nullptr;
+
+  tree vectype = vector_type (0);
+
+  /* Get the predicate and base pointer.  */
+  gimple_seq stmts = NULL;
+  tree pred = convert_pred (stmts, vectype, 0);
+  tree base = fold_contiguous_base (stmts, vectype);
+  tree els = build_zero_cst (vectype);
+  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+
+  tree cookie = load_store_cookie (TREE_TYPE (vectype));
+  gcall *new_call = gimple_build_call_internal (ifn_code, 4,
+                                               base, cookie, pred, els);
+  gimple_call_set_lhs (new_call, lhs);
+  return new_call;
+}
+
 /* Return the alignment and TBAA argument to an internal load or store
    function like IFN_MASK_LOAD or IFN_MASK_STORE, given that it accesses
    memory elements of type TYPE.  */
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.h 
b/gcc/config/aarch64/aarch64-sve-builtins.h
index f9e8c4cd729..95de95df824 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.h
+++ b/gcc/config/aarch64/aarch64-sve-builtins.h
@@ -650,6 +650,7 @@ public:
   tree force_vector (gimple_seq &, tree, tree);
   tree convert_pred (gimple_seq &, tree, unsigned int);
   tree fold_contiguous_base (gimple_seq &, tree);
+  gimple *fold_contiguous_load (internal_fn);
   tree load_store_cookie (tree);
 
   gcall *redirect_call (const function_instance &);
diff --git a/gcc/config/aarch64/aarch64-sve.md 
b/gcc/config/aarch64/aarch64-sve.md
index 4d67ad0dc87..2a1849f1ab2 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -1131,9 +1131,23 @@ (define_insn_and_split "mov<mode>"
 ;; [W1 in the block comment above about FFR handling]
 ;;
 ;; Write to the FFR and start a new FFRT scheduling region.
-(define_insn "aarch64_wrffr"
+(define_insn "@set_first_fault_state<mode>"
   [(set (reg:VNx16BI FFR_REGNUM)
-       (match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one"))
+       (match_operand:VNx16BI_ONLY 0 "aarch64_simd_reg_or_minus_one"))
+   (set (reg:VNx16BI FFRT_REGNUM)
+       (unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: 0 ]
+     [ Dm      ] setffr
+     [ Upa     ] wrffr\t%0.b
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
+
+(define_insn "@set_first_fault_state<mode>"
+  [(set (reg:VNx16BI FFR_REGNUM)
+       (subreg:VNx16BI
+         (match_operand:PRED_HSD 0 "aarch64_simd_reg_or_minus_one") 0))
    (set (reg:VNx16BI FFRT_REGNUM)
        (unspec:VNx16BI [(match_dup 0)] UNSPEC_WRFFR))]
   "TARGET_SVE && TARGET_NON_STREAMING"
@@ -1176,20 +1190,63 @@ (define_insn "aarch64_copy_ffr_to_ffrt"
 ;; [R2 in the block comment above about FFR handling]
 ;;
 ;; Read the FFR via the FFRT.
-(define_insn "aarch64_rdffr"
-  [(set (match_operand:VNx16BI 0 "register_operand" "=Upa")
+(define_insn "aarch64_rdffr<mode>"
+  [(set (match_operand:VNx16BI_ONLY 0 "register_operand" "=Upa")
        (reg:VNx16BI FFRT_REGNUM))]
   "TARGET_SVE && TARGET_NON_STREAMING"
   "rdffr\t%0.b"
   [(set_attr "sve_type" "sve_ffr")]
 )
 
+(define_insn "aarch64_rdffr<mode>"
+  [(set (match_operand:PRED_HSD 0 "register_operand" "=Upa")
+       (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  "rdffr\t%0.b"
+  [(set_attr "sve_type" "sve_ffr")]
+)
+
+;; [R2 in the block comment above about FFR handling]
+;;
+(define_expand "read_first_fault_state<mode>"
+  [(set (reg:VNx16BI FFRT_REGNUM) ; copy_ffr_to_ffrt
+       (reg:VNx16BI FFR_REGNUM))
+   (set (match_operand:VNx16BI_ONLY 0 "register_operand" "=Upa") ; rdffr
+       (reg:VNx16BI FFRT_REGNUM))
+   (set (reg:VNx16BI FFRT_REGNUM) ; update ffrt
+       (unspec:VNx16BI [(reg:VNx16BI FFRT_REGNUM)] UNSPEC_UPDATE_FFRT))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+)
+
+(define_expand "read_first_fault_state<mode>"
+  [(set (reg:VNx16BI FFRT_REGNUM) ; copy_ffr_to_ffrt
+       (reg:VNx16BI FFR_REGNUM))
+   (set (match_operand:PRED_HSD 0 "register_operand" "=Upa") ; rdffr
+       (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0))
+   (set (reg:VNx16BI FFRT_REGNUM) ; update ffrt
+       (unspec:VNx16BI [(reg:VNx16BI FFRT_REGNUM)] UNSPEC_UPDATE_FFRT))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+)
+
 ;; Likewise with zero predication.
-(define_insn "aarch64_rdffr_z"
-  [(set (match_operand:VNx16BI 0 "register_operand")
-       (and:VNx16BI
+(define_insn "aarch64_rdffr_z<mode>"
+  [(set (match_operand:VNx16BI_ONLY 0 "register_operand")
+       (and:VNx16BI_ONLY
          (reg:VNx16BI FFRT_REGNUM)
-         (match_operand:VNx16BI 1 "register_operand")))]
+         (match_operand:VNx16BI_ONLY 1 "register_operand")))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: =0, 1   ; attrs: pred_clobber ]
+     [ &Upa    , Upa ; yes                 ] rdffr\t%0.b, %1/z
+     [ ?Upa    , 0Upa; yes                 ] ^
+     [ Upa     , Upa ; no                  ] ^
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
+(define_insn "aarch64_rdffr_z<mode>"
+  [(set (match_operand:PRED_HSD 0 "register_operand")
+       (and:PRED_HSD
+         (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)
+         (match_operand:PRED_HSD 1 "register_operand")))]
   "TARGET_SVE && TARGET_NON_STREAMING"
   {@ [ cons: =0, 1   ; attrs: pred_clobber ]
      [ &Upa    , Upa ; yes                 ] rdffr\t%0.b, %1/z
@@ -1200,17 +1257,36 @@ (define_insn "aarch64_rdffr_z"
 )
 
 ;; Read the FFR to test for a fault, without using the predicate result.
-(define_insn "*aarch64_rdffr_z_ptest"
+(define_insn "*aarch64_rdffr_z_ptest<mode>"
   [(set (reg:CC_NZC CC_REGNUM)
        (unspec:CC_NZC
          [(match_operand:VNx16BI 1 "register_operand")
           (match_dup 1)
           (match_operand:SI 2 "aarch64_sve_ptrue_flag")
-          (and:VNx16BI
+          (and:VNx16BI_ONLY
             (reg:VNx16BI FFRT_REGNUM)
             (match_dup 1))]
          UNSPEC_PTEST))
-   (clobber (match_scratch:VNx16BI 0))]
+   (clobber (match_scratch:VNx16BI_ONLY 0))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: =0, 1   ; attrs: pred_clobber ]
+     [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
+     [ ?Upa    , 0Upa; yes                 ] ^
+     [ Upa     , Upa ; no                  ] ^
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
+(define_insn "*aarch64_rdffr_z_ptest<mode>"
+  [(set (reg:CC_NZC CC_REGNUM)
+       (unspec:CC_NZC
+         [(match_operand:VNx16BI 1 "register_operand")
+          (match_operand:PRED_HSD 3)
+          (match_operand:SI 2 "aarch64_sve_ptrue_flag")
+          (and:PRED_HSD
+            (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)
+            (match_dup 3))]
+         UNSPEC_PTEST))
+   (clobber (match_scratch:PRED_HSD 0))]
   "TARGET_SVE && TARGET_NON_STREAMING"
   {@ [ cons: =0, 1   ; attrs: pred_clobber ]
      [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
@@ -1221,15 +1297,32 @@ (define_insn "*aarch64_rdffr_z_ptest"
 )
 
 ;; Same for unpredicated RDFFR when tested with a known PTRUE.
-(define_insn "*aarch64_rdffr_ptest"
+(define_insn "*aarch64_rdffr_ptest<mode>"
   [(set (reg:CC_NZC CC_REGNUM)
        (unspec:CC_NZC
          [(match_operand:VNx16BI 1 "register_operand")
-          (match_dup 1)
+          (match_operand:VNx16BI_ONLY 2)
           (const_int SVE_KNOWN_PTRUE)
           (reg:VNx16BI FFRT_REGNUM)]
          UNSPEC_PTEST))
-   (clobber (match_scratch:VNx16BI 0))]
+   (clobber (match_scratch:VNx16BI_ONLY 0))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: =0, 1   ; attrs: pred_clobber ]
+     [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
+     [ ?Upa    , 0Upa; yes                 ] ^
+     [ Upa     , Upa ; no                  ] ^
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
+(define_insn "*aarch64_rdffr_ptest<mode>"
+  [(set (reg:CC_NZC CC_REGNUM)
+       (unspec:CC_NZC
+         [(match_operand:VNx16BI 1 "register_operand")
+          (match_operand:PRED_HSD 2)
+          (const_int SVE_KNOWN_PTRUE)
+          (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)]
+         UNSPEC_PTEST))
+   (clobber (match_scratch:PRED_HSD 0))]
   "TARGET_SVE && TARGET_NON_STREAMING"
   {@ [ cons: =0, 1   ; attrs: pred_clobber ]
      [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
@@ -1240,18 +1333,18 @@ (define_insn "*aarch64_rdffr_ptest"
 )
 
 ;; Read the FFR with zero predication and test the result.
-(define_insn "*aarch64_rdffr_z_cc"
+(define_insn "*aarch64_rdffr_z_cc<mode>"
   [(set (reg:CC_NZC CC_REGNUM)
        (unspec:CC_NZC
          [(match_operand:VNx16BI 1 "register_operand")
           (match_dup 1)
           (match_operand:SI 2 "aarch64_sve_ptrue_flag")
-          (and:VNx16BI
+          (and:VNx16BI_ONLY
             (reg:VNx16BI FFRT_REGNUM)
             (match_dup 1))]
          UNSPEC_PTEST))
-   (set (match_operand:VNx16BI 0 "register_operand")
-       (and:VNx16BI
+   (set (match_operand:VNx16BI_ONLY 0 "register_operand")
+       (and:VNx16BI_ONLY
          (reg:VNx16BI FFRT_REGNUM)
          (match_dup 1)))]
   "TARGET_SVE && TARGET_NON_STREAMING"
@@ -1262,9 +1355,31 @@ (define_insn "*aarch64_rdffr_z_cc"
   }
   [(set_attr "sve_type" "sve_ffr")]
 )
+(define_insn "*aarch64_rdffr_z_cc<mode>"
+  [(set (reg:CC_NZC CC_REGNUM)
+       (unspec:CC_NZC
+         [(match_operand:VNx16BI 1 "register_operand")
+          (match_operand:PRED_HSD 3)
+          (match_operand:SI 2 "aarch64_sve_ptrue_flag")
+          (and:PRED_HSD
+            (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)
+            (match_dup 3))]
+         UNSPEC_PTEST))
+   (set (match_operand:PRED_HSD 0 "register_operand")
+       (and:PRED_HSD
+         (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)
+         (match_dup 3)))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: =0, 1   ; attrs: pred_clobber ]
+     [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
+     [ ?Upa    , 0Upa; yes                 ] ^
+     [ Upa     , Upa ; no                  ] ^
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
 
 ;; Same for unpredicated RDFFR when tested with a known PTRUE.
-(define_insn "*aarch64_rdffr_cc"
+(define_insn "*aarch64_rdffr_cc<mode>"
   [(set (reg:CC_NZC CC_REGNUM)
        (unspec:CC_NZC
          [(match_operand:VNx16BI 1 "register_operand")
@@ -1272,7 +1387,7 @@ (define_insn "*aarch64_rdffr_cc"
           (const_int SVE_KNOWN_PTRUE)
           (reg:VNx16BI FFRT_REGNUM)]
          UNSPEC_PTEST))
-   (set (match_operand:VNx16BI 0 "register_operand")
+   (set (match_operand:VNx16BI_ONLY 0 "register_operand")
        (reg:VNx16BI FFRT_REGNUM))]
   "TARGET_SVE && TARGET_NON_STREAMING"
   {@ [ cons: =0, 1   ; attrs: pred_clobber ]
@@ -1282,6 +1397,24 @@ (define_insn "*aarch64_rdffr_cc"
   }
   [(set_attr "sve_type" "sve_ffr")]
 )
+(define_insn "*aarch64_rdffr_cc<mode>"
+  [(set (reg:CC_NZC CC_REGNUM)
+       (unspec:CC_NZC
+         [(match_operand:VNx16BI 1 "register_operand")
+          (match_operand:PRED_HSD 2)
+          (const_int SVE_KNOWN_PTRUE)
+          (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0)]
+         UNSPEC_PTEST))
+   (set (match_operand:PRED_HSD 0 "register_operand")
+       (subreg:PRED_HSD (reg:VNx16BI FFRT_REGNUM) 0))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {@ [ cons: =0, 1   ; attrs: pred_clobber ]
+     [ &Upa    , Upa ; yes                 ] rdffrs\t%0.b, %1/z
+     [ ?Upa    , 0Upa; yes                 ] ^
+     [ Upa     , Upa ; no                  ] ^
+  }
+  [(set_attr "sve_type" "sve_ffr")]
+)
 
 ;; [R3 in the block comment above about FFR handling]
 ;;
@@ -1448,18 +1581,37 @@ (define_insn_and_rewrite 
"*aarch64_load_<ANY_EXTEND:optab>_mov<SVE_HSDI:mode><SV
 ;; -------------------------------------------------------------------------
 
 ;; Contiguous non-extending first-faulting or non-faulting loads.
+;; Also supports sparse vectors via extendign loads
 (define_insn "@aarch64_ld<fn>f1<mode>"
-  [(set (match_operand:SVE_FULL 0 "register_operand" "=w")
-       (unspec:SVE_FULL
+  [(set (match_operand:SVE_ALL 0 "register_operand" "=w")
+       (unspec:SVE_ALL
          [(match_operand:<VPRED> 2 "register_operand" "Upl")
-          (match_operand:SVE_FULL 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>")
+          (match_operand:SVE_ALL 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>")
+          (match_operand:SVE_ALL 3 "aarch64_maskload_else_operand")
           (reg:VNx16BI FFRT_REGNUM)]
          SVE_LDFF1_LDNF1))]
   "TARGET_SVE && TARGET_NON_STREAMING"
-  "ld<fn>f1<Vesize>\t%0.<Vetype>, %2/z, %1"
+  "ld<fn>f1<Vesize>\t%0.<Vctype>, %2/z, %1"
   [(set_attr "sve_type" "sve_load_1reg")]
 )
 
+;; Expose {non,first}-faulting loads to the middle-end.
+(define_expand "mask_<nonfirst>fault_load<mode><vpred>"
+  [(set (match_operand:SVE_ALL 0 "register_operand")
+       (unspec:SVE_ALL
+         [(match_operand:<VPRED> 2 "register_operand")
+          (match_operand:SVE_ALL 1 "aarch64_sve_ld<fn>f1_operand")
+          (match_operand:SVE_ALL 3 "aarch64_maskload_else_operand")
+          (reg:VNx16BI FFRT_REGNUM)]
+         SVE_LDFF1_LDNF1))]
+  "TARGET_SVE && TARGET_NON_STREAMING"
+  {
+    /* Emit the L2 insn; L1 follows from the template above.
+       See the earlier block comment on FFR handling.  */
+    emit_insn (gen_aarch64_update_ffr_for_load ());
+  }
+)
+
 ;; -------------------------------------------------------------------------
 ;; ---- First-faulting extending contiguous loads
 ;; -------------------------------------------------------------------------
@@ -1487,6 +1639,7 @@ (define_insn_and_rewrite 
"@aarch64_ld<fn>f1_<ANY_EXTEND:optab><SVE_HSDI:mode><SV
             (unspec:SVE_PARTIAL_I
               [(match_operand:<SVE_PARTIAL_I:VPRED> 2 "register_operand" "Upl")
                (match_operand:SVE_PARTIAL_I 1 "aarch64_sve_ld<fn>f1_operand" 
"Ut<fn>")
+               (match_operand:SVE_PARTIAL_I 4 "aarch64_maskload_else_operand")
                (reg:VNx16BI FFRT_REGNUM)]
               SVE_LDFF1_LDNF1))]
          UNSPEC_PRED_X))]
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 2d1522a348a..10871f24221 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -4662,6 +4662,8 @@ (define_int_attr u [(UNSPEC_SQSHLU "u") (UNSPEC_SQSHL "") 
(UNSPEC_UQSHL "")
 
 (define_int_attr fn [(UNSPEC_LDFF1 "f") (UNSPEC_LDNF1 "n")])
 
+(define_int_attr nonfirst [(UNSPEC_LDNF1 "non") (UNSPEC_LDFF1 "first")])
+
 (define_int_attr ab [(UNSPEC_CLASTA "a") (UNSPEC_CLASTB "b")
                     (UNSPEC_LASTA "a") (UNSPEC_LASTB "b")])
 
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 0138c6f7ef0..a219d8fe59c 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -196,6 +196,8 @@ init_internal_fns ()
 #define crc_direct { 1, -1, true }
 #define reduc_sbool_direct { 0, 0, true }
 #define select_vl_direct { 2, 0, false }
+#define read_first_fault_state_direct { -1, -1, false }
+#define set_first_fault_state_direct { 0, 0, false }
 
 const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
 #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
@@ -4315,6 +4317,18 @@ expand_reduc_sbool_optab_fn (internal_fn fn, gcall 
*stmt, direct_optab optab)
 #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
   expand_convert_optab_fn (FN, STMT, OPTAB, 3)
 
+#define expand_read_first_fault_state_optab_fn(FN, STMT, OPTAB) \
+  expand_direct_optab_fn (FN, STMT, OPTAB, 0)
+
+static void
+expand_set_first_fault_state_optab_fn (internal_fn fn, gcall *stmt,
+                                     direct_optab optab)
+{
+  tree_pair types = direct_internal_fn_types (fn, stmt);
+  insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
+  expand_fn_using_insn (stmt, icode, 0, 1);
+}
+
 /* Expanders for optabs that can use expand_convert_optab_fn.  */
 
 #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
@@ -4432,6 +4446,8 @@ multi_vector_optab_supported_p (convert_optab optab, 
tree_pair types,
 #define direct_vec_extract_optab_supported_p convert_optab_supported_p
 #define direct_reduc_sbool_optab_supported_p direct_optab_supported_p
 #define direct_select_vl_optab_supported_p convert_optab_supported_p
+#define direct_read_first_fault_state_optab_supported_p 
direct_optab_supported_p
+#define direct_set_first_fault_state_optab_supported_p direct_optab_supported_p
 
 /* Return the optab used by internal function FN.  */
 
@@ -5081,6 +5097,8 @@ internal_load_fn_p (internal_fn fn)
     case IFN_MASK_LEN_GATHER_LOAD:
     case IFN_LEN_LOAD:
     case IFN_MASK_LEN_LOAD:
+    case IFN_MASK_FIRSTFAULT_LOAD:
+    case IFN_MASK_NONFAULT_LOAD:
       return true;
 
     default:
@@ -5253,6 +5271,8 @@ internal_fn_else_index (internal_fn fn)
     case IFN_MASK_LEN_LOAD:
     case IFN_MASK_LOAD_LANES:
     case IFN_MASK_LEN_LOAD_LANES:
+    case IFN_MASK_NONFAULT_LOAD:
+    case IFN_MASK_FIRSTFAULT_LOAD:
       return 3;
 
     case IFN_COND_FMA:
@@ -5293,6 +5313,8 @@ internal_fn_mask_index (internal_fn fn)
     case IFN_MASK_LEN_STORE_LANES:
     case IFN_MASK_LEN_LOAD:
     case IFN_MASK_LEN_STORE:
+    case IFN_MASK_NONFAULT_LOAD:
+    case IFN_MASK_FIRSTFAULT_LOAD:
       return 2;
 
     case IFN_MASK_LEN_STRIDED_LOAD:
@@ -5361,6 +5383,8 @@ internal_fn_alias_ptr_index (internal_fn fn)
     case IFN_SCATTER_STORE:
     case IFN_MASK_SCATTER_STORE:
     case IFN_MASK_LEN_SCATTER_STORE:
+    case IFN_MASK_NONFAULT_LOAD:
+    case IFN_MASK_FIRSTFAULT_LOAD:
       return 1;
 
     default:
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index af9f92950c7..b03a50154ea 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -649,6 +649,24 @@ DEF_INTERNAL_FN (BITINTTOFLOAT, ECF_PURE | ECF_LEAF, ". R 
. ")
 DEF_INTERNAL_OPTAB_FN (BIT_ANDN, ECF_CONST, andn, binary)
 DEF_INTERNAL_OPTAB_FN (BIT_IORN, ECF_CONST, iorn, binary)
 
+/* First faulting load internal functions.  */
+DEF_INTERNAL_OPTAB_FN (MASK_FIRSTFAULT_LOAD,
+                      0,
+                      mask_firstfault_load,
+                      mask_load)
+DEF_INTERNAL_OPTAB_FN (MASK_NONFAULT_LOAD,
+                      ECF_NOTHROW,
+                      mask_nonfault_load,
+                      mask_load)
+DEF_INTERNAL_OPTAB_FN (SET_FAULT_STATE,
+                      ECF_NOTHROW,
+                      set_first_fault_state,
+                      set_first_fault_state)
+DEF_INTERNAL_OPTAB_FN (READ_FAULT_STATE,
+                      ECF_NOTHROW,
+                      read_first_fault_state,
+                      read_first_fault_state)
+
 #undef DEF_INTERNAL_WIDENING_OPTAB_FN
 #undef DEF_INTERNAL_SIGNED_COND_FN
 #undef DEF_INTERNAL_COND_FN
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 7ccea18543f..a444aec39f3 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -109,6 +109,8 @@ OPTAB_CD(mask_len_gather_load_optab, 
"mask_len_gather_load$a$b")
 OPTAB_CD(scatter_store_optab, "scatter_store$a$b")
 OPTAB_CD(mask_scatter_store_optab, "mask_scatter_store$a$b")
 OPTAB_CD(mask_len_scatter_store_optab, "mask_len_scatter_store$a$b")
+OPTAB_CD (mask_nonfault_load_optab, "mask_nonfault_load$a$b")
+OPTAB_CD (mask_firstfault_load_optab, "mask_firstfault_load$a$b")
 OPTAB_CD(vec_extract_optab, "vec_extract$a$b")
 OPTAB_CD(vec_init_optab, "vec_init$a$b")
 OPTAB_CD (sdot_prod_optab, "sdot_prod$I$a$b")
@@ -238,6 +240,9 @@ OPTAB_D (push_optab, "push$a1")
 OPTAB_D (reload_in_optab, "reload_in$a")
 OPTAB_D (reload_out_optab, "reload_out$a")
 
+OPTAB_D (read_first_fault_state_optab, "read_first_fault_state$a")
+OPTAB_D (set_first_fault_state_optab, "set_first_fault_state$a")
+
 OPTAB_DC(cbranch_optab, "cbranch$a4", COMPARE)
 OPTAB_D (tbranch_eq_optab, "tbranch_eq$a3")
 OPTAB_D (tbranch_ne_optab, "tbranch_ne$a3")
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c 
b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c
index a32b636b278..71a068ec827 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c
@@ -24,9 +24,7 @@
   T (F##_u32, uint32_t)                                 \
   T (F##_u64, uint64_t)                                 \
 
-ALL_DATA (ldff1)
-ALL_DATA (ldnf1)
 ALL_DATA (ldnt1)
 
-/* { dg-final { scan-assembler-times 
{\t.cfi_startproc\n\tmovi?\t[vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0\n\tret\n} 36 
} } */
-/* { dg-final { scan-assembler-times {\t.cfi_startproc\n} 36 } } */
+/* { dg-final { scan-assembler-times 
{\t.cfi_startproc\n\tmovi?\t[vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0\n\tret\n} 12 
} } */
+/* { dg-final { scan-assembler-times {\t.cfi_startproc\n} 12 } } */
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index 1114903784e..ec068524423 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -5881,6 +5881,8 @@ get_references_in_stmt (gimple *stmt, vec<data_ref_loc, 
va_heap> *references)
              break;
            }
          case IFN_MASK_LOAD:
+         case IFN_MASK_FIRSTFAULT_LOAD:
+         case IFN_MASK_NONFAULT_LOAD:
          case IFN_MASK_STORE:
          break;
          case IFN_MASK_CALL:
@@ -5938,6 +5940,8 @@ get_references_in_stmt (gimple *stmt, vec<data_ref_loc, 
va_heap> *references)
        switch (gimple_call_internal_fn (stmt))
          {
          case IFN_MASK_LOAD:
+         case IFN_MASK_FIRSTFAULT_LOAD:
+         case IFN_MASK_NONFAULT_LOAD:
            if (gimple_call_lhs (stmt) == NULL_TREE)
              break;
            ref.is_read = true;
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index 9f3dd2adac0..d279908173f 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -2862,6 +2862,8 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, 
bool tbaa_p)
       case IFN_MASK_LEN_STORE_LANES:
        goto process_args;
       case IFN_MASK_LOAD:
+      case IFN_MASK_FIRSTFAULT_LOAD:
+      case IFN_MASK_NONFAULT_LOAD:
       case IFN_LEN_LOAD:
       case IFN_MASK_LEN_LOAD:
       case IFN_MASK_LOAD_LANES:
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index bbd3cfaab24..42c5238edce 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -7565,6 +7565,8 @@ get_alias_ptr_type_for_ptr_address (iv_use *use)
   switch (gimple_call_internal_fn (call))
     {
     case IFN_MASK_LOAD:
+    case IFN_MASK_FIRSTFAULT_LOAD:
+    case IFN_MASK_NONFAULT_LOAD:
     case IFN_MASK_STORE:
     case IFN_MASK_LOAD_LANES:
     case IFN_MASK_STORE_LANES:
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 2250f6f74a1..a5b79d7e608 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -581,6 +581,10 @@ vect_get_operand_map (const gimple *stmt, bool 
gather_scatter_p,
          case IFN_MASK_LOAD:
            return gather_scatter_p ? off_arg2_arg3_map : arg2_arg3_map;
 
+         case IFN_MASK_FIRSTFAULT_LOAD:
+         case IFN_MASK_NONFAULT_LOAD:
+           return arg2_arg3_map;
+
          case IFN_GATHER_LOAD:
            return arg2_map;
 
-- 
2.34.1


Reply via email to