Also removes pfalse ldff1 tests as the calls can no longer be removed
due to virtual operation which represents the HSSR state.
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.
* 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.
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;
};
/* 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