> -----Original Message-----
> From: Alfie Richards <[email protected]>
> Sent: 08 August 2026 00:11
> To: [email protected]
> Cc: Alex Coplan <[email protected]>; Alice Carlotti
> <[email protected]>; [email protected];
> [email protected]; Tamar Christina <[email protected]>;
> [email protected]; [email protected]; [email protected]; Alfie
> Richards <[email protected]>
> Subject: [PATCH v2 04/13] ifn: optab: aarch64: Add optabs and internal
> functions for hssr operations.
> 
> Also removes pfalse ldff1 tests as the calls can no longer be removed
> due to virtual operation which represents the HSSR state.

Ah, that's why the refactoring.

Please split off the AArch64 implementation bit from the middle-end machinery.

> 
> gcc/ChangeLog:
> 
>       * config/aarch64/aarch64-sve-builtins-base.cc:
>       (svldxf1_impl::fold): Update to use new optabs.
>       (svldxf1_impl::expand): Update to use new optabs.
>       (aarch64_wrffr::fold): Update to use new IFN's.
>       (aarch64_wrffr::expand): Update to use new optabs.
>       (svsetffr_impl::fold): Update to use new IFN's.
>       (svsetffr_impl::expand): Update to use new optabs.
>       (svwrffr_impl::fold): Update to use new optabs.
>       (svwrffr_impl::expand): Update to use new IFN's.
>       * config/aarch64/aarch64-sve.md
>       (@set_hssr_state<mode>): Rename aarch64_wrffr and add new
> modes.
>       (aarch64_rdffr<mode>): Update for new modes.
>       (aarch64_ld<fn>f1<mode>): Add support for extending loads.
>       (mask_ff_hssr_load<mode><vpred>): New define expand.
>       * internal-fn.cc (read_hssr_state_direct): New macro.
>       (set_hssr_state_direct): New macro.
>       (detect_hssr_fault_direct): New macro.
>       (expand_read_hssr_state_optab_fn): New macro.
>       (expand_detect_hssr_fault_optab_fn): New macro.
>       (expand_set_hssr_state_optab_fn): New function.
>       (direct_read_hssr_state_optab_supported_p): New macro.
>       (direct_set_hssr_state_optab_supported_p): New macro.
>       (direct_detect_hssr_fault_optab_supported_p): New macro.
>       (internal_load_fn_p): Add support for IFN_MASK_FF_HSSR_LOAD.
>       (internal_fn_else_index): Add support for IFN_MASK_FF_HSSR_LOAD.
>       (internal_fn_mask_index): Add support for
> IFN_MASK_FF_HSSR_LOAD.
>       (internal_fn_alias_ptr_index): Add support for
> IFN_MASK_FF_HSSR_LOAD.
>       * internal-fn.def (MASK_FF_HSSR_LOAD): New IFN.
>       (SET_HSSR_STATE): New IFN.
>       (READ_HSSR_STATE): New IFN.
>       (DETECT_HSSR_FAULT): New IFN.
>       * optabs.def (mask_ff_hssr_load_optab): New optab.
>       (read_hssr_state_optab): New optab.
>       (set_hssr_state_optab): New optab.
>       (detect_hssr_fault_optab): New optab.

These are missing documentation, it's a bit hard to review this atm since I'm 
not
sure what the arguments and constraints for these are.

IFNs need documenting in ifn.texi and the optabs in md.texi

>       * tree-data-ref.cc (get_references_in_stmt):
>       Add support for IFN_MASK_FF_HSSR_LOAD.
>       * tree-ssa-alias.cc (ref_maybe_used_by_call_p_1):
>       Add support for IFN_MASK_FF_HSSR_LOAD.
>       * tree-ssa-loop-ivopts.cc (get_mem_type_for_internal_fn):
>       Add support for IFN_MASK_FF_HSSR_LOAD.
>       (get_alias_ptr_type_for_ptr_address):
>       Add support for IFN_MASK_FF_HSSR_LOAD.
>       * tree-vect-slp.cc (vect_get_operand_map):
>       Add support for IFN_MASK_FF_HSSR_LOAD.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.target/aarch64/sve/pfalse-load.c: Remove ldff1 tests.

Why is this? It should still be valid to fold to zero, at least in terms of
ACLE that's a regression.

Why doesn't using something like

gimple *
fold (gimple_folder &f) const override
{
  if (!m_first)
    return nullptr;

  if (is_pfalse (gimple_call_arg (f.call, 0)))
    return f.fold_call_to (build_zero_cst (TREE_TYPE (f.lhs)));

  return f.fold_contiguous_load (IFN_MASK_FF_HSSR_LOAD);
}

work?

> 
> Co-Authored-By: Alex Coplan <[email protected]>
> 
> ---
>  .../aarch64/aarch64-sve-builtins-base.cc      |  74 ++++--
>  gcc/config/aarch64/aarch64-sve.md             | 221 ++++++++++++++++--
>  gcc/internal-fn.cc                            |  25 ++
>  gcc/internal-fn.def                           |  18 ++
>  gcc/optabs.def                                |   8 +
>  .../gcc.target/aarch64/sve/pfalse-load.c      |   7 +-
>  gcc/tree-data-ref.cc                          |   2 +
>  gcc/tree-ssa-alias.cc                         |   1 +
>  gcc/tree-ssa-loop-ivopts.cc                   |   2 +
>  gcc/tree-vect-slp.cc                          |   3 +
>  10 files changed, 315 insertions(+), 46 deletions(-)
> 
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> index 800541a9262..febcfe163c6 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
> @@ -2046,7 +2046,10 @@ public:
>  class svldxf1_impl : public full_width_access
>  {
>  public:
> -  constexpr svldxf1_impl (unspec unspec) : m_unspec (unspec) {}
> +  constexpr svldxf1_impl (unspec unspec) : m_first (unspec ==
> UNSPEC_LDFF1)
> +  {
> +    gcc_checking_assert (m_first || unspec == UNSPEC_LDNF1);
> +  }
> 
>    unsigned int
>    call_properties (const function_instance &) const override
> @@ -2054,19 +2057,33 @@ 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 ());
> +    if (m_first)
> +      return f.fold_contiguous_load (IFN_MASK_FF_HSSR_LOAD);
> +    else
> +      return nullptr;
> +  }
> 
> -    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
> +  {
> +    if (m_first)
> +      {
> +     auto icode = convert_optab_handler (mask_ff_hssr_load_optab,
> +                                         e.vector_mode (0), e.gp_mode (0));
> +     return e.use_contiguous_load_insn (icode, true);
> +      }
> +    else
> +      {
> +     emit_insn (gen_aarch64_update_ffr_for_load ());
> +     machine_mode mode = e.vector_mode (0);
> +     return e.use_contiguous_load_insn (code_for_aarch64_ldf1
> (UNSPEC_LDNF1,
> +                                                               mode),
> +                                        true);
> +      }
>    }
> 
> -  /* The unspec associated with the load.  */
> -  unspec m_unspec;
> +  bool m_first;

Can we call this something more descriptive.

Otherwise looks good but I'd like to see some docs before continuing to review 
the RTL changes.

Thanks,
Tamar

>  };
> 
>  /* Implements extending contiguous forms of svldff1 and svldnf1.  */
> @@ -2848,15 +2865,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 nullptr;
> +
> +    gcall *new_call = gimple_build_call_internal (IFN_READ_HSSR_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;
>    }
> @@ -3041,11 +3067,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_HSSR_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_hssr_state (VNx16BImode));
>    }
>  };
> 
> @@ -3468,10 +3500,16 @@ public:
>      return CP_WRITE_FFR;
>    }
> 
> +  gimple *fold (gimple_folder &f) const override
> +  {
> +    return gimple_build_call_internal (IFN_SET_HSSR_STATE, 1,
> +                                    gimple_call_arg (f.call, 0));
> +  }
> +
>    rtx
>    expand (function_expander &e) const override
>    {
> -    return e.use_exact_insn (CODE_FOR_aarch64_wrffr);
> +    return e.use_exact_insn (code_for_set_hssr_state (VNx16BImode));
>    }
>  };
> 
> diff --git a/gcc/config/aarch64/aarch64-sve.md
> b/gcc/config/aarch64/aarch64-sve.md
> index 878dadf6f61..eb56bc850b4 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_hssr_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_hssr_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_hssr_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_hssr_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]
>  ;;
> @@ -1295,6 +1428,27 @@ (define_insn "aarch64_update_ffrt"
>    [(set_attr "type" "no_insn")]
>  )
> 
> +/* Test if the last element of the predicate is not true.  */
> +(define_expand "detect_hssr_fault<mode>"
> +  [(match_operand:QI       0 "register_operand")
> +   (match_operand:PRED_ALL 1 "register_operand")]
> +  "TARGET_SVE && TARGET_NON_STREAMING"
> +  {
> +    rtx ptrue = force_reg (VNx16BImode, aarch64_ptrue_all (<data_bytes>));
> +    rtx cast_ptrue = gen_lowpart (<MODE>mode, ptrue);
> +    rtx ptrue_flag = gen_int_mode (SVE_KNOWN_PTRUE, SImode);
> +    emit_insn (gen_aarch64_ptestvnx16bi (ptrue, cast_ptrue, ptrue_flag,
> +                                      operands[1]));
> +
> +    rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM);
> +    rtx cmp = gen_rtx_fmt_ee (GEU, QImode, cc_reg, const0_rtx);
> +
> +    emit_insn (gen_aarch64_cstoreqi (operands[0], cmp, cc_reg));
> +
> +    DONE;
> +  }
> +)
> +
>  ;;
> ===================================================================
> ======
>  ;; == Loads
>  ;;
> ===================================================================
> ======
> @@ -1448,18 +1602,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 extending 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_ff_hssr_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_ldff1_operand")
> +        (match_operand:SVE_ALL 3 "aarch64_maskload_else_operand")
> +        (reg:VNx16BI FFRT_REGNUM)]
> +       UNSPEC_LDFF1))]
> +  "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
>  ;; -------------------------------------------------------------------------
> diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
> index 0138c6f7ef0..5f5040cb0b9 100644
> --- a/gcc/internal-fn.cc
> +++ b/gcc/internal-fn.cc
> @@ -196,6 +196,9 @@ 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_hssr_state_direct { -1, -1, false }
> +#define set_hssr_state_direct { 0, 0, false }
> +#define detect_hssr_fault_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 +4318,21 @@ 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_hssr_state_optab_fn(FN, STMT, OPTAB) \
> +  expand_direct_optab_fn (FN, STMT, OPTAB, 0)
> +
> +#define expand_detect_hssr_fault_optab_fn(FN, STMT, OPTAB) \
> +  expand_direct_optab_fn (FN, STMT, OPTAB, 1)
> +
> +static void
> +expand_set_hssr_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 +4450,9 @@ 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_hssr_state_optab_supported_p
> direct_optab_supported_p
> +#define direct_set_hssr_state_optab_supported_p
> direct_optab_supported_p
> +#define direct_detect_hssr_fault_optab_supported_p
> direct_optab_supported_p
> 
>  /* Return the optab used by internal function FN.  */
> 
> @@ -5081,6 +5102,7 @@ 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_FF_HSSR_LOAD:
>        return true;
> 
>      default:
> @@ -5253,6 +5275,7 @@ 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_FF_HSSR_LOAD:
>        return 3;
> 
>      case IFN_COND_FMA:
> @@ -5293,6 +5316,7 @@ 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_FF_HSSR_LOAD:
>        return 2;
> 
>      case IFN_MASK_LEN_STRIDED_LOAD:
> @@ -5361,6 +5385,7 @@ 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_FF_HSSR_LOAD:
>        return 1;
> 
>      default:
> diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
> index 28ad5b7809d..68397c7bced 100644
> --- a/gcc/internal-fn.def
> +++ b/gcc/internal-fn.def
> @@ -651,6 +651,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)
> 
> +/* Hardware Safe Speculative Reads internal functions.  */
> +DEF_INTERNAL_OPTAB_FN (MASK_FF_HSSR_LOAD,
> +                    0,
> +                    mask_ff_hssr_load,
> +                    mask_load)
> +DEF_INTERNAL_OPTAB_FN (SET_HSSR_STATE,
> +                    ECF_NOTHROW,
> +                    set_hssr_state,
> +                    set_hssr_state)
> +DEF_INTERNAL_OPTAB_FN (READ_HSSR_STATE,
> +                    ECF_NOTHROW,
> +                    read_hssr_state,
> +                    read_hssr_state)
> +DEF_INTERNAL_OPTAB_FN (DETECT_HSSR_FAULT,
> +                    ECF_CONST,
> +                    detect_hssr_fault,
> +                    detect_hssr_fault)
> +
>  #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 da58147a513..9b5ca3434be 100644
> --- a/gcc/optabs.def
> +++ b/gcc/optabs.def
> @@ -118,6 +118,9 @@ OPTAB_CD (usdot_prod_optab,
> "usdot_prod$I$a$b")
>  OPTAB_CD (while_ult_optab, "while_ult$a$b")
>  OPTAB_CD (select_vl_optab, "select_vl$a$b")
> 
> +/* Hardware Safe Speculative Reads optabs.  */
> +OPTAB_CD (mask_ff_hssr_load_optab, "mask_ff_hssr_load$a$b")
> +
>  OPTAB_NL(add_optab, "add$P$a3", PLUS, "add", '3',
> gen_int_fp_fixed_libfunc)
>  OPTAB_NX(add_optab, "add$F$a3")
>  OPTAB_NX(add_optab, "add$Q$a3")
> @@ -238,6 +241,11 @@ OPTAB_D (push_optab, "push$a1")
>  OPTAB_D (reload_in_optab, "reload_in$a")
>  OPTAB_D (reload_out_optab, "reload_out$a")
> 
> +/* Hardware Safe Speculative Reads optabs.  */
> +OPTAB_D (read_hssr_state_optab, "read_hssr_state$a")
> +OPTAB_D (set_hssr_state_optab, "set_hssr_state$a")
> +OPTAB_D (detect_hssr_fault_optab, "detect_hssr_fault$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..faf433dfb61 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-load.c
> @@ -24,9 +24,8 @@
>    T (F##_u32, uint32_t)                                 \
>    T (F##_u64, uint64_t)                                 \
> 
> -ALL_DATA (ldff1)
> -ALL_DATA (ldnf1)
>  ALL_DATA (ldnt1)
> +ALL_DATA (ldnf1)
> 
> -/* { 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} 24 } } */
> +/* { dg-final { scan-assembler-times {\t.cfi_startproc\n} 24 } } */
> diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
> index 8e9d7871348..e4f04a44e0c 100644
> --- a/gcc/tree-data-ref.cc
> +++ b/gcc/tree-data-ref.cc
> @@ -5893,6 +5893,7 @@ get_references_in_stmt (gimple *stmt,
> vec<data_ref_loc, va_heap> *references)
>             break;
>           }
>         case IFN_MASK_LOAD:
> +       case IFN_MASK_FF_HSSR_LOAD:
>         case IFN_MASK_STORE:
>         break;
>         case IFN_MASK_CALL:
> @@ -5950,6 +5951,7 @@ 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_FF_HSSR_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 1d10f6dbd97..be47194ef3b 100644
> --- a/gcc/tree-ssa-alias.cc
> +++ b/gcc/tree-ssa-alias.cc
> @@ -2888,6 +2888,7 @@ 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_FF_HSSR_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 3c0ce1794c2..881055212d7 100644
> --- a/gcc/tree-ssa-loop-ivopts.cc
> +++ b/gcc/tree-ssa-loop-ivopts.cc
> @@ -2370,6 +2370,7 @@ get_mem_type_for_internal_fn (gcall *call, tree
> *op_p)
>    switch (gimple_call_internal_fn (call))
>      {
>      case IFN_MASK_LOAD:
> +    case IFN_MASK_FF_HSSR_LOAD:
>      case IFN_MASK_LOAD_LANES:
>      case IFN_MASK_LEN_LOAD_LANES:
>      case IFN_LEN_LOAD:
> @@ -7567,6 +7568,7 @@ get_alias_ptr_type_for_ptr_address (iv_use *use)
>    switch (gimple_call_internal_fn (call))
>      {
>      case IFN_MASK_LOAD:
> +    case IFN_MASK_FF_HSSR_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 b4eb9c204cb..3d767a5822f 100644
> --- a/gcc/tree-vect-slp.cc
> +++ b/gcc/tree-vect-slp.cc
> @@ -581,6 +581,9 @@ 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_FF_HSSR_LOAD:
> +         return arg2_arg3_map;
> +
>         case IFN_GATHER_LOAD:
>           return arg2_map;
> 
> --
> 2.43.0

Reply via email to