diff options
296 files changed, 23124 insertions, 181 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d0c9ac2..937a179 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,445 @@ 2019-10-29 Richard Sandiford <richard.sandiford@arm.com> + Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org> + Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> + + * config.gcc (aarch64*-*-*): Add arm_sve.h to extra_headers. + Add aarch64-sve-builtins.o, aarch64-sve-builtins-shapes.o and + aarch64-sve-builtins-base.o to extra_objs. Add + aarch64-sve-builtins.h and aarch64-sve-builtins.cc to target_gtfiles. + * config/aarch64/t-aarch64 (aarch64-sve-builtins.o): New rule. + (aarch64-sve-builtins-shapes.o): Likewise. + (aarch64-sve-builtins-base.o): New rules. + * config/aarch64/aarch64-c.c (aarch64_pragma_aarch64): New function. + (aarch64_resolve_overloaded_builtin): Likewise. + (aarch64_check_builtin_call): Likewise. + (aarch64_register_pragmas): Install aarch64_resolve_overloaded_builtin + and aarch64_check_builtin_call in targetm. Register the GCC aarch64 + pragma. + * config/aarch64/aarch64-protos.h (AARCH64_FOR_SVPRFOP): New macro. + (aarch64_svprfop): New enum. + (AARCH64_BUILTIN_SVE): New aarch64_builtin_class enum value. + (aarch64_sve_int_mode, aarch64_sve_data_mode): Declare. + (aarch64_fold_sve_cnt_pat, aarch64_output_sve_prefetch): Likewise. + (aarch64_output_sve_cnt_pat_immediate): Likewise. + (aarch64_output_sve_ptrues, aarch64_sve_ptrue_svpattern_p): Likewise. + (aarch64_sve_sqadd_sqsub_immediate_p, aarch64_sve_ldff1_operand_p) + (aarch64_sve_ldnf1_operand_p, aarch64_sve_prefetch_operand_p) + (aarch64_ptrue_all_mode, aarch64_convert_sve_data_to_pred): Likewise. + (aarch64_expand_sve_dupq, aarch64_replace_reg_mode): Likewise. + (aarch64_sve::init_builtins, aarch64_sve::handle_arm_sve_h): Likewise. + (aarch64_sve::builtin_decl, aarch64_sve::builtin_type_p): Likewise. + (aarch64_sve::mangle_builtin_type): Likewise. + (aarch64_sve::resolve_overloaded_builtin): Likewise. + (aarch64_sve::check_builtin_call, aarch64_sve::gimple_fold_builtin) + (aarch64_sve::expand_builtin): Likewise. + * config/aarch64/aarch64.c (aarch64_sve_data_mode): Make public. + (aarch64_sve_int_mode): Likewise. + (aarch64_ptrue_all_mode): New function. + (aarch64_convert_sve_data_to_pred): Make public. + (svprfop_token): New function. + (aarch64_output_sve_prefetch): Likewise. + (aarch64_fold_sve_cnt_pat): Likewise. + (aarch64_output_sve_cnt_pat_immediate): Likewise. + (aarch64_sve_move_pred_via_while): Use gen_while with UNSPEC_WHILE_LO + instead of gen_while_ult. + (aarch64_replace_reg_mode): Make public. + (aarch64_init_builtins): Call aarch64_sve::init_builtins. + (aarch64_fold_builtin): Handle AARCH64_BUILTIN_SVE. + (aarch64_gimple_fold_builtin, aarch64_expand_builtin): Likewise. + (aarch64_builtin_decl, aarch64_builtin_reciprocal): Likewise. + (aarch64_mangle_type): Call aarch64_sve::mangle_type. + (aarch64_sve_sqadd_sqsub_immediate_p): New function. + (aarch64_sve_ptrue_svpattern_p): Likewise. + (aarch64_sve_pred_valid_immediate): Check + aarch64_sve_ptrue_svpattern_p. + (aarch64_sve_ldff1_operand_p, aarch64_sve_ldnf1_operand_p) + (aarch64_sve_prefetch_operand_p, aarch64_output_sve_ptrues): New + functions. + * config/aarch64/aarch64.md (UNSPEC_LDNT1_SVE, UNSPEC_STNT1_SVE) + (UNSPEC_LDFF1_GATHER, UNSPEC_PTRUE, UNSPEC_WHILE_LE, UNSPEC_WHILE_LS) + (UNSPEC_WHILE_LT, UNSPEC_CLASTA, UNSPEC_UPDATE_FFR) + (UNSPEC_UPDATE_FFRT, UNSPEC_RDFFR, UNSPEC_WRFFR) + (UNSPEC_SVE_LANE_SELECT, UNSPEC_SVE_CNT_PAT, UNSPEC_SVE_PREFETCH) + (UNSPEC_SVE_PREFETCH_GATHER, UNSPEC_SVE_COMPACT, UNSPEC_SVE_SPLICE): + New unspecs. + * config/aarch64/iterators.md (SI_ONLY, DI_ONLY, VNx8HI_ONLY) + (VNx2DI_ONLY, SVE_PARTIAL, VNx8_NARROW, VNx8_WIDE, VNx4_NARROW) + (VNx4_WIDE, VNx2_NARROW, VNx2_WIDE, PRED_HSD): New mode iterators. + (UNSPEC_ADR, UNSPEC_BRKA, UNSPEC_BRKB, UNSPEC_BRKN, UNSPEC_BRKPA) + (UNSPEC_BRKPB, UNSPEC_PFIRST, UNSPEC_PNEXT, UNSPEC_CNTP, UNSPEC_SADDV) + (UNSPEC_UADDV, UNSPEC_FMLA, UNSPEC_FMLS, UNSPEC_FEXPA, UNSPEC_FTMAD) + (UNSPEC_FTSMUL, UNSPEC_FTSSEL, UNSPEC_COND_CMPEQ_WIDE): New unspecs. + (UNSPEC_COND_CMPGE_WIDE, UNSPEC_COND_CMPGT_WIDE): Likewise. + (UNSPEC_COND_CMPHI_WIDE, UNSPEC_COND_CMPHS_WIDE): Likewise. + (UNSPEC_COND_CMPLE_WIDE, UNSPEC_COND_CMPLO_WIDE): Likewise. + (UNSPEC_COND_CMPLS_WIDE, UNSPEC_COND_CMPLT_WIDE): Likewise. + (UNSPEC_COND_CMPNE_WIDE, UNSPEC_COND_FCADD90, UNSPEC_COND_FCADD270) + (UNSPEC_COND_FCMLA, UNSPEC_COND_FCMLA90, UNSPEC_COND_FCMLA180) + (UNSPEC_COND_FCMLA270, UNSPEC_COND_FMAX, UNSPEC_COND_FMIN): Likewise. + (UNSPEC_COND_FMULX, UNSPEC_COND_FRECPX, UNSPEC_COND_FSCALE): Likewise. + (UNSPEC_LASTA, UNSPEC_ASHIFT_WIDE, UNSPEC_ASHIFTRT_WIDE): Likewise. + (UNSPEC_LSHIFTRT_WIDE, UNSPEC_LDFF1, UNSPEC_LDNF1): Likewise. + (Vesize): Handle partial vector modes. + (self_mask, narrower_mask, sve_lane_con, sve_lane_pair_con): New + mode attributes. + (UBINQOPS, ANY_PLUS, SAT_PLUS, ANY_MINUS, SAT_MINUS): New code + iterators. + (s, paired_extend, inc_dec): New code attributes. + (SVE_INT_ADDV, CLAST, LAST): New int iterators. + (SVE_INT_UNARY): Add UNSPEC_RBIT. + (SVE_FP_UNARY, SVE_FP_UNARY_INT): New int iterators. + (SVE_FP_BINARY, SVE_FP_BINARY_INT): Likewise. + (SVE_COND_FP_UNARY): Add UNSPEC_COND_FRECPX. + (SVE_COND_FP_BINARY): Add UNSPEC_COND_FMAX, UNSPEC_COND_FMIN and + UNSPEC_COND_FMULX. + (SVE_COND_FP_BINARY_INT, SVE_COND_FP_ADD): New int iterators. + (SVE_COND_FP_SUB, SVE_COND_FP_MUL): Likewise. + (SVE_COND_FP_BINARY_I1): Add UNSPEC_COND_FMAX and UNSPEC_COND_FMIN. + (SVE_COND_FP_BINARY_REG): Add UNSPEC_COND_FMULX. + (SVE_COND_FCADD, SVE_COND_FP_MAXMIN, SVE_COND_FCMLA) + (SVE_COND_INT_CMP_WIDE, SVE_FP_TERNARY_LANE, SVE_CFP_TERNARY_LANE) + (SVE_WHILE, SVE_SHIFT_WIDE, SVE_LDFF1_LDNF1, SVE_BRK_UNARY) + (SVE_BRK_BINARY, SVE_PITER): New int iterators. + (optab): Handle UNSPEC_SADDV, UNSPEC_UADDV, UNSPEC_FRECPE, + UNSPEC_FRECPS, UNSPEC_RSQRTE, UNSPEC_RSQRTS, UNSPEC_RBIT, + UNSPEC_SMUL_HIGHPART, UNSPEC_UMUL_HIGHPART, UNSPEC_FMLA, UNSPEC_FMLS, + UNSPEC_FCMLA, UNSPEC_FCMLA90, UNSPEC_FCMLA180, UNSPEC_FCMLA270, + UNSPEC_FEXPA, UNSPEC_FTSMUL, UNSPEC_FTSSEL, UNSPEC_COND_FCADD90, + UNSPEC_COND_FCADD270, UNSPEC_COND_FCMLA, UNSPEC_COND_FCMLA90, + UNSPEC_COND_FCMLA180, UNSPEC_COND_FCMLA270, UNSPEC_COND_FMAX, + UNSPEC_COND_FMIN, UNSPEC_COND_FMULX, UNSPEC_COND_FRECPX and + UNSPEC_COND_FSCALE. + (maxmin_uns): Handle UNSPEC_COND_FMAX and UNSPEC_COND_FMIN. + (binqops_op, binqops_op_rev, last_op): New int attributes. + (su): Handle UNSPEC_SADDV and UNSPEC_UADDV. + (fn, ab): New int attributes. + (cmp_op): Handle UNSPEC_COND_CMP*_WIDE and UNSPEC_WHILE_*. + (while_optab_cmp, brk_op, sve_pred_op): New int attributes. + (sve_int_op): Handle UNSPEC_SMUL_HIGHPART, UNSPEC_UMUL_HIGHPART, + UNSPEC_ASHIFT_WIDE, UNSPEC_ASHIFTRT_WIDE, UNSPEC_LSHIFTRT_WIDE and + UNSPEC_RBIT. + (sve_fp_op): Handle UNSPEC_FRECPE, UNSPEC_FRECPS, UNSPEC_RSQRTE, + UNSPEC_RSQRTS, UNSPEC_FMLA, UNSPEC_FMLS, UNSPEC_FEXPA, UNSPEC_FTSMUL, + UNSPEC_FTSSEL, UNSPEC_COND_FMAX, UNSPEC_COND_FMIN, UNSPEC_COND_FMULX, + UNSPEC_COND_FRECPX and UNSPEC_COND_FSCALE. + (sve_fp_op_rev): Handle UNSPEC_COND_FMAX, UNSPEC_COND_FMIN and + UNSPEC_COND_FMULX. + (rot): Handle UNSPEC_COND_FCADD* and UNSPEC_COND_FCMLA*. + (brk_reg_con, brk_reg_opno): New int attributes. + (sve_pred_fp_rhs1_operand, sve_pred_fp_rhs2_operand): Handle + UNSPEC_COND_FMAX, UNSPEC_COND_FMIN and UNSPEC_COND_FMULX. + (sve_pred_fp_rhs2_immediate): Handle UNSPEC_COND_FMAX and + UNSPEC_COND_FMIN. + (max_elem_bits): New int attribute. + (min_elem_bits): Handle UNSPEC_RBIT. + * config/aarch64/predicates.md (subreg_lowpart_operator): Handle + TRUNCATE as well as SUBREG. + (ascending_int_parallel, aarch64_simd_reg_or_minus_one) + (aarch64_sve_ldff1_operand, aarch64_sve_ldnf1_operand) + (aarch64_sve_prefetch_operand, aarch64_sve_ptrue_svpattern_immediate) + (aarch64_sve_qadd_immediate, aarch64_sve_qsub_immediate) + (aarch64_sve_gather_immediate_b, aarch64_sve_gather_immediate_h) + (aarch64_sve_gather_immediate_w, aarch64_sve_gather_immediate_d) + (aarch64_sve_sqadd_operand, aarch64_sve_gather_offset_b) + (aarch64_sve_gather_offset_h, aarch64_sve_gather_offset_w) + (aarch64_sve_gather_offset_d, aarch64_gather_scale_operand_b) + (aarch64_gather_scale_operand_h): New predicates. + * config/aarch64/constraints.md (UPb, UPd, UPh, UPw, Utf, Utn, vgb) + (vgd, vgh, vgw, vsQ, vsS): New constraints. + * config/aarch64/aarch64-sve.md: Add a note on the FFR handling. + (*aarch64_sve_reinterpret<mode>): Allow any source register + instead of requiring an exact match. + (*aarch64_sve_ptruevnx16bi_cc, *aarch64_sve_ptrue<mode>_cc) + (*aarch64_sve_ptruevnx16bi_ptest, *aarch64_sve_ptrue<mode>_ptest) + (aarch64_wrffr, aarch64_update_ffr_for_load, aarch64_copy_ffr_to_ffrt) + (aarch64_rdffr, aarch64_rdffr_z, *aarch64_rdffr_z_ptest) + (*aarch64_rdffr_ptest, *aarch64_rdffr_z_cc, *aarch64_rdffr_cc) + (aarch64_update_ffrt): New patterns. + (@aarch64_load_<ANY_EXTEND:optab><VNx8_WIDE:mode><VNx8_NARROW:mode>) + (@aarch64_load_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>) + (@aarch64_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>) + (@aarch64_ld<fn>f1<mode>): New patterns. + (@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx8_WIDE:mode><VNx8_NARROW:mode>) + (@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>) + (@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>) + (@aarch64_ldnt1<mode>): New patterns. + (gather_load<mode>): Use aarch64_sve_gather_offset_<Vesize> for + the scalar part of the address. + (mask_gather_load<SVE_S:mode>): Use aarch64_sve_gather_offset_w for the + scalar part of the addresse and add an alternative for handling + nonzero offsets. + (mask_gather_load<SVE_D:mode>): Likewise aarch64_sve_gather_offset_d. + (*mask_gather_load<mode>_sxtw, *mask_gather_load<mode>_uxtw) + (@aarch64_gather_load_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>) + (@aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>) + (*aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_sxtw) + (*aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_uxtw) + (@aarch64_ldff1_gather<SVE_S:mode>, @aarch64_ldff1_gather<SVE_D:mode>) + (*aarch64_ldff1_gather<mode>_sxtw, *aarch64_ldff1_gather<mode>_uxtw) + (@aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>) + (@aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>) + (*aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_sxtw) + (*aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_uxtw) + (@aarch64_sve_prefetch<mode>): New patterns. + (@aarch64_sve_gather_prefetch<SVE_I:mode><VNx4SI_ONLY:mode>) + (@aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>) + (*aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>_sxtw) + (*aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>_uxtw) + (@aarch64_store_trunc<VNx8_NARROW:mode><VNx8_WIDE:mode>) + (@aarch64_store_trunc<VNx4_NARROW:mode><VNx4_WIDE:mode>) + (@aarch64_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>) + (@aarch64_stnt1<mode>): New patterns. + (scatter_store<mode>): Use aarch64_sve_gather_offset_<Vesize> for + the scalar part of the address. + (mask_scatter_store<SVE_S:mode>): Use aarch64_sve_gather_offset_w for + the scalar part of the addresse and add an alternative for handling + nonzero offsets. + (mask_scatter_store<SVE_D:mode>): Likewise aarch64_sve_gather_offset_d. + (*mask_scatter_store<mode>_sxtw, *mask_scatter_store<mode>_uxtw) + (@aarch64_scatter_store_trunc<VNx4_NARROW:mode><VNx4_WIDE:mode>) + (@aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>) + (*aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>_sxtw) + (*aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>_uxtw): + New patterns. + (vec_duplicate<mode>): Use QI as the mode of the input operand. + (extract_last_<mode>): Generalize to... + (@extract_<LAST:last_op>_<mode>): ...this. + (*<SVE_INT_UNARY:optab><mode>2): Rename to... + (@aarch64_pred_<SVE_INT_UNARY:optab><mode>): ...this. + (@cond_<SVE_INT_UNARY:optab><mode>): New expander. + (@aarch64_pred_sxt<SVE_HSDI:mode><SVE_PARTIAL:mode>): New pattern. + (@aarch64_cond_sxt<SVE_HSDI:mode><SVE_PARTIAL:mode>): Likewise. + (@aarch64_pred_cnot<mode>, @cond_cnot<mode>): New expanders. + (@aarch64_sve_<SVE_FP_UNARY_INT:optab><mode>): New pattern. + (@aarch64_sve_<SVE_FP_UNARY:optab><mode>): Likewise. + (*<SVE_COND_FP_UNARY:optab><mode>2): Rename to... + (@aarch64_pred_<SVE_COND_FP_UNARY:optab><mode>): ...this. + (@cond_<SVE_COND_FP_UNARY:optab><mode>): New expander. + (*<SVE_INT_BINARY_IMM:optab><mode>3): Rename to... + (@aarch64_pred_<SVE_INT_BINARY_IMM:optab><mode>): ...this. + (@aarch64_adr<mode>, *aarch64_adr_sxtw): New patterns. + (*aarch64_adr_uxtw_unspec): Likewise. + (*aarch64_adr_uxtw): Rename to... + (*aarch64_adr_uxtw_and): ...this. + (@aarch64_adr<mode>_shift): New expander. + (*aarch64_adr_shift_sxtw): New pattern. + (aarch64_<su>abd<mode>_3): Rename to... + (@aarch64_pred_<su>abd<mode>): ...this. + (<su>abd<mode>_3): Update accordingly. + (@aarch64_cond_<su>abd<mode>): New expander. + (@aarch64_<SBINQOPS:su_optab><optab><mode>): New pattern. + (@aarch64_<UBINQOPS:su_optab><optab><mode>): Likewise. + (*<su>mul<mode>3_highpart): Rename to... + (@aarch64_pred_<optab><mode>): ...this. + (@cond_<MUL_HIGHPART:optab><mode>): New expander. + (*cond_<MUL_HIGHPART:optab><mode>_2): New pattern. + (*cond_<MUL_HIGHPART:optab><mode>_z): Likewise. + (*<SVE_INT_BINARY_SD:optab><mode>3): Rename to... + (@aarch64_pred_<SVE_INT_BINARY_SD:optab><mode>): ...this. + (cond_<SVE_INT_BINARY_SD:optab><mode>): Add a "@" marker. + (@aarch64_bic<mode>, @cond_bic<mode>): New expanders. + (*v<ASHIFT:optab><mode>3): Rename to... + (@aarch64_pred_<ASHIFT:optab><mode>): ...this. + (@aarch64_sve_<SVE_SHIFT_WIDE:sve_int_op><mode>): New pattern. + (@cond_<SVE_SHIFT_WIDE:sve_int_op><mode>): New expander. + (*cond_<SVE_SHIFT_WIDE:sve_int_op><mode>_m): New pattern. + (*cond_<SVE_SHIFT_WIDE:sve_int_op><mode>_z): Likewise. + (@cond_asrd<mode>): New expander. + (*cond_asrd<mode>_2, *cond_asrd<mode>_z): New patterns. + (sdiv_pow2<mode>3): Expand to *cond_asrd<mode>_2. + (*sdiv_pow2<mode>3): Delete. + (@cond_<SVE_COND_FP_BINARY_INT:optab><mode>): New expander. + (*cond_<SVE_COND_FP_BINARY_INT:optab><mode>_2): New pattern. + (*cond_<SVE_COND_FP_BINARY_INT:optab><mode>_any): Likewise. + (@aarch64_sve_<SVE_FP_BINARY:optab><mode>): New pattern. + (@aarch64_sve_<SVE_FP_BINARY_INT:optab><mode>): Likewise. + (*<SVE_COND_FP_BINARY_REG:optab><mode>3): Rename to... + (@aarch64_pred_<SVE_COND_FP_BINARY_REG:optab><mode>): ...this. + (@aarch64_pred_<SVE_COND_FP_BINARY_INT:optab><mode>): New pattern. + (cond_<SVE_COND_FP_BINARY:optab><mode>): Add a "@" marker. + (*add<SVE_F:mode>3): Rename to... + (@aarch64_pred_add<SVE_F:mode>): ...this and add alternatives + for SVE_STRICT_GP. + (@aarch64_pred_<SVE_COND_FCADD:optab><mode>): New pattern. + (@cond_<SVE_COND_FCADD:optab><mode>): New expander. + (*cond_<SVE_COND_FCADD:optab><mode>_2): New pattern. + (*cond_<SVE_COND_FCADD:optab><mode>_any): Likewise. + (*sub<SVE_F:mode>3): Rename to... + (@aarch64_pred_sub<SVE_F:mode>): ...this and add alternatives + for SVE_STRICT_GP. + (@aarch64_pred_abd<SVE_F:mode>): New expander. + (*fabd<SVE_F:mode>3): Rename to... + (*aarch64_pred_abd<SVE_F:mode>): ...this. + (@aarch64_cond_abd<SVE_F:mode>): New expander. + (*mul<SVE_F:mode>3): Rename to... + (@aarch64_pred_<SVE_F:optab><mode>): ...this and add alternatives + for SVE_STRICT_GP. + (@aarch64_mul_lane_<SVE_F:mode>): New pattern. + (*<SVE_COND_FP_MAXMIN_PUBLIC:optab><mode>3): Rename and generalize + to... + (@aarch64_pred_<SVE_COND_FP_MAXMIN:optab><mode>): ...this. + (*<LOGICAL:optab><PRED_ALL:mode>3_ptest): New pattern. + (*<nlogical><PRED_ALL:mode>3): Rename to... + (aarch64_pred_<nlogical><PRED_ALL:mode>_z): ...this. + (*<nlogical><PRED_ALL:mode>3_cc): New pattern. + (*<nlogical><PRED_ALL:mode>3_ptest): Likewise. + (*<logical_nn><PRED_ALL:mode>3): Rename to... + (aarch64_pred_<logical_nn><mode>_z): ...this. + (*<logical_nn><PRED_ALL:mode>3_cc): New pattern. + (*<logical_nn><PRED_ALL:mode>3_ptest): Likewise. + (*fma<SVE_I:mode>4): Rename to... + (@aarch64_pred_fma<SVE_I:mode>): ...this. + (*fnma<SVE_I:mode>4): Rename to... + (@aarch64_pred_fnma<SVE_I:mode>): ...this. + (@aarch64_<sur>dot_prod_lane<vsi2qi>): New pattern. + (*<SVE_FP_TERNARY:optab><mode>4): Rename to... + (@aarch64_pred_<SVE_FP_TERNARY:optab><mode>): ...this. + (cond_<SVE_FP_TERNARY:optab><mode>): Add a "@" marker. + (@aarch64_<SVE_FP_TERNARY_LANE:optab>_lane_<mode>): New pattern. + (@aarch64_pred_<SVE_COND_FCMLA:optab><mode>): Likewise. + (@cond_<SVE_COND_FCMLA:optab><mode>): New expander. + (*cond_<SVE_COND_FCMLA:optab><mode>_4): New pattern. + (*cond_<SVE_COND_FCMLA:optab><mode>_any): Likewise. + (@aarch64_<FCMLA:optab>_lane_<mode>): Likewise. + (@aarch64_sve_tmad<mode>): Likewise. + (vcond_mask_<SVE_ALL:mode><vpred>): Add a "@" marker. + (*aarch64_sel_dup<mode>): Rename to... + (@aarch64_sel_dup<mode>): ...this. + (@aarch64_pred_cmp<cmp_op><SVE_I:mode>_wide): New pattern. + (*aarch64_pred_cmp<cmp_op><SVE_I:mode>_wide_cc): Likewise. + (*aarch64_pred_cmp<cmp_op><SVE_I:mode>_wide_ptest): Likewise. + (@while_ult<GPI:mode><PRED_ALL:mode>): Generalize to... + (@while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>): ...this. + (*while_ult<GPI:mode><PRED_ALL:mode>_cc): Generalize to. + (*while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>_cc): ...this. + (*while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>_ptest): New pattern. + (*fcm<cmp_op><mode>): Rename to... + (@aarch64_pred_fcm<cmp_op><mode>): ...this. Make operand order + match @aarch64_pred_cmp<cmp_op><SVE_I:mode>. + (*fcmuo<mode>): Rename to... + (@aarch64_pred_fcmuo<mode>): ...this. Make operand order + match @aarch64_pred_cmp<cmp_op><SVE_I:mode>. + (@aarch64_pred_fac<cmp_op><mode>): New expander. + (@vcond_mask_<PRED_ALL:mode><mode>): New pattern. + (fold_extract_last_<mode>): Generalize to... + (@fold_extract_<last_op>_<mode>): ...this. + (@aarch64_fold_extract_vector_<last_op>_<mode>): New pattern. + (*reduc_plus_scal_<SVE_I:mode>): Replace with... + (@aarch64_pred_reduc_<optab>_<mode>): ...this pattern, making the + DImode result explicit. + (reduc_plus_scal_<mode>): Update accordingly. + (*reduc_<optab>_scal_<SVE_I:mode>): Rename to... + (@aarch64_pred_reduc_<optab>_<SVE_I:mode>): ...this. + (*reduc_<optab>_scal_<SVE_F:mode>): Rename to... + (@aarch64_pred_reduc_<optab>_<SVE_F:mode>): ...this. + (*aarch64_sve_tbl<mode>): Rename to... + (@aarch64_sve_tbl<mode>): ...this. + (@aarch64_sve_compact<mode>): New pattern. + (*aarch64_sve_dup_lane<mode>): Rename to... + (@aarch64_sve_dup_lane<mode>): ...this. + (@aarch64_sve_dupq_lane<mode>): New pattern. + (@aarch64_sve_splice<mode>): Likewise. + (aarch64_sve_<perm_insn><mode>): Rename to... + (@aarch64_sve_<perm_insn><mode>): ...this. + (*aarch64_sve_ext<mode>): Rename to... + (@aarch64_sve_ext<mode>): ...this. + (aarch64_sve_<su>unpk<perm_hilo>_<SVE_BHSI:mode>): Add a "@" marker. + (*aarch64_sve_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>): Rename + to... + (@aarch64_sve_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>): ...this. + (*aarch64_sve_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>): + Rename to... + (@aarch64_sve_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>): + ...this. + (@cond_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>): New expander. + (@cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>): Likewise. + (*cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>): New pattern. + (*aarch64_sve_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>): Rename + to... + (@aarch64_sve_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>): ...this. + (aarch64_sve_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>): Add + a "@" marker. + (@cond_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>): New expander. + (@cond_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>): Likewise. + (*cond_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>): New + pattern. + (*aarch64_sve_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>): Rename to... + (@aarch64_sve_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>): ...this. + (@cond_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>): New expander. + (*cond_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>): New pattern. + (aarch64_sve_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>): Add a + "@" marker. + (@cond_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>): New expander. + (*cond_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>): New pattern. + (aarch64_sve_punpk<perm_hilo>_<mode>): Add a "@" marker. + (@aarch64_brk<SVE_BRK_UNARY:brk_op>): New pattern. + (*aarch64_brk<SVE_BRK_UNARY:brk_op>_cc): Likewise. + (*aarch64_brk<SVE_BRK_UNARY:brk_op>_ptest): Likewise. + (@aarch64_brk<SVE_BRK_BINARY:brk_op>): Likewise. + (*aarch64_brk<SVE_BRK_BINARY:brk_op>_cc): Likewise. + (*aarch64_brk<SVE_BRK_BINARY:brk_op>_ptest): Likewise. + (@aarch64_sve_<SVE_PITER:sve_pred_op><mode>): Likewise. + (*aarch64_sve_<SVE_PITER:sve_pred_op><mode>_cc): Likewise. + (*aarch64_sve_<SVE_PITER:sve_pred_op><mode>_ptest): Likewise. + (aarch64_sve_cnt_pat): Likewise. + (@aarch64_sve_<ANY_PLUS:inc_dec><DI_ONLY:mode>_pat): Likewise. + (*aarch64_sve_incsi_pat): Likewise. + (@aarch64_sve_<SAT_PLUS:inc_dec><SI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx2DI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx4SI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx8HI_ONLY:mode>_pat): New expander. + (*aarch64_sve_<ANY_PLUS:inc_dec><VNx8HI_ONLY:mode>_pat): New pattern. + (@aarch64_sve_<ANY_MINUS:inc_dec><DI_ONLY:mode>_pat): Likewise. + (*aarch64_sve_decsi_pat): Likewise. + (@aarch64_sve_<SAT_MINUS:inc_dec><SI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx2DI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx4SI_ONLY:mode>_pat): Likewise. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx8HI_ONLY:mode>_pat): New expander. + (*aarch64_sve_<ANY_MINUS:inc_dec><VNx8HI_ONLY:mode>_pat): New pattern. + (@aarch64_pred_cntp<mode>): Likewise. + (@aarch64_sve_<ANY_PLUS:inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp): + New expander. + (*aarch64_sve_<ANY_PLUS:inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp) + (*aarch64_incsi<PRED_ALL:mode>_cntp): New patterns. + (@aarch64_sve_<SAT_PLUS:inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp): + New expander. + (*aarch64_sve_<SAT_PLUS:inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp): + New pattern. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx2DI_ONLY:mode>_cntp): New expander. + (*aarch64_sve_<ANY_PLUS:inc_dec><VNx2DI_ONLY:mode>_cntp): New pattern. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx4SI_ONLY:mode>_cntp): New expander. + (*aarch64_sve_<ANY_PLUS:inc_dec><VNx4SI_ONLY:mode>_cntp): New pattern. + (@aarch64_sve_<ANY_PLUS:inc_dec><VNx8HI_ONLY:mode>_cntp): New expander. + (*aarch64_sve_<ANY_PLUS:inc_dec><VNx8HI_ONLY:mode>_cntp): New pattern. + (@aarch64_sve_<ANY_MINUS:inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp): + New expander. + (*aarch64_sve_<ANY_MINUS:inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp) + (*aarch64_incsi<PRED_ALL:mode>_cntp): New patterns. + (@aarch64_sve_<SAT_MINUS:inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp): + New expander. + (*aarch64_sve_<SAT_MINUS:inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp): + New pattern. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx2DI_ONLY:mode>_cntp): New + expander. + (*aarch64_sve_<ANY_MINUS:inc_dec><VNx2DI_ONLY:mode>_cntp): New pattern. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx4SI_ONLY:mode>_cntp): New + expander. + (*aarch64_sve_<ANY_MINUS:inc_dec><VNx4SI_ONLY:mode>_cntp): New pattern. + (@aarch64_sve_<ANY_MINUS:inc_dec><VNx8HI_ONLY:mode>_cntp): New + expander. + (*aarch64_sve_<ANY_MINUS:inc_dec><VNx8HI_ONLY:mode>_cntp): New pattern. + * config/aarch64/arm_sve.h: New file. + * config/aarch64/aarch64-sve-builtins.h: Likewise. + * config/aarch64/aarch64-sve-builtins.cc: Likewise. + * config/aarch64/aarch64-sve-builtins.def: Likewise. + * config/aarch64/aarch64-sve-builtins-base.h: Likewise. + * config/aarch64/aarch64-sve-builtins-base.cc: Likewise. + * config/aarch64/aarch64-sve-builtins-base.def: Likewise. + * config/aarch64/aarch64-sve-builtins-functions.h: Likewise. + * config/aarch64/aarch64-sve-builtins-shapes.h: Likewise. + * config/aarch64/aarch64-sve-builtins-shapes.cc: Likewise. + +2019-10-29 Richard Sandiford <richard.sandiford@arm.com> * config/aarch64/aarch64-sve.md (@aarch64_sve_rev<PRED_ALL:mode>): New pattern. diff --git a/gcc/config.gcc b/gcc/config.gcc index b444087..d74bcbb 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -315,12 +315,12 @@ m32c*-*-*) ;; aarch64*-*-*) cpu_type=aarch64 - extra_headers="arm_fp16.h arm_neon.h arm_acle.h" + extra_headers="arm_fp16.h arm_neon.h arm_acle.h arm_sve.h" c_target_objs="aarch64-c.o" cxx_target_objs="aarch64-c.o" d_target_objs="aarch64-d.o" - extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o" - target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c" + extra_objs="aarch64-builtins.o aarch-common.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64-sve-builtins-base.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o aarch64-bti-insert.o" + target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c \$(srcdir)/config/aarch64/aarch64-sve-builtins.h \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc" target_has_targetm_common=yes ;; alpha*-*-*) diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c index 85b6831..7c322ca 100644 --- a/gcc/config/aarch64/aarch64-c.c +++ b/gcc/config/aarch64/aarch64-c.c @@ -243,6 +243,73 @@ aarch64_pragma_target_parse (tree args, tree pop_target) return true; } +/* Implement "#pragma GCC aarch64". */ +static void +aarch64_pragma_aarch64 (cpp_reader *) +{ + tree x; + if (pragma_lex (&x) != CPP_STRING) + { + error ("%<#pragma GCC aarch64%> requires a string parameter"); + return; + } + + const char *name = TREE_STRING_POINTER (x); + if (strcmp (name, "arm_sve.h") == 0) + aarch64_sve::handle_arm_sve_h (); + else + error ("unknown %<#pragma GCC aarch64%> option %qs", name); +} + +/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN. */ +static tree +aarch64_resolve_overloaded_builtin (unsigned int uncast_location, + tree fndecl, void *uncast_arglist) +{ + vec<tree, va_gc> empty = {}; + location_t location = (location_t) uncast_location; + vec<tree, va_gc> *arglist = (uncast_arglist + ? (vec<tree, va_gc> *) uncast_arglist + : &empty); + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + tree new_fndecl; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return NULL_TREE; + + case AARCH64_BUILTIN_SVE: + new_fndecl = aarch64_sve::resolve_overloaded_builtin (location, subcode, + arglist); + break; + } + if (new_fndecl == NULL_TREE || new_fndecl == error_mark_node) + return new_fndecl; + return build_function_call_vec (location, vNULL, new_fndecl, arglist, + NULL, fndecl); +} + +/* Implement TARGET_CHECK_BUILTIN_CALL. */ +static bool +aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc, + tree fndecl, tree orig_fndecl, + unsigned int nargs, tree *args) +{ + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return true; + + case AARCH64_BUILTIN_SVE: + return aarch64_sve::check_builtin_call (loc, arg_loc, subcode, + orig_fndecl, nargs, args); + } + gcc_unreachable (); +} + /* Implement REGISTER_TARGET_PRAGMAS. */ void @@ -250,4 +317,9 @@ aarch64_register_pragmas (void) { /* Update pragma hook to allow parsing #pragma GCC target. */ targetm.target_option.pragma_parse = aarch64_pragma_target_parse; + + targetm.resolve_overloaded_builtin = aarch64_resolve_overloaded_builtin; + targetm.check_builtin_call = aarch64_check_builtin_call; + + c_register_pragma ("GCC", "aarch64", aarch64_pragma_aarch64); } diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index ca23508..15f288b 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -426,11 +426,31 @@ extern struct tune_params aarch64_tune_params; T (MUL3, mul3, 30) \ T (ALL, all, 31) +/* The available SVE prefetch operations, known in the ACLE as "svprfop". */ +#define AARCH64_FOR_SVPRFOP(T) \ + T (PLDL1KEEP, pldl1keep, 0) \ + T (PLDL1STRM, pldl1strm, 1) \ + T (PLDL2KEEP, pldl2keep, 2) \ + T (PLDL2STRM, pldl2strm, 3) \ + T (PLDL3KEEP, pldl3keep, 4) \ + T (PLDL3STRM, pldl3strm, 5) \ + T (PSTL1KEEP, pstl1keep, 8) \ + T (PSTL1STRM, pstl1strm, 9) \ + T (PSTL2KEEP, pstl2keep, 10) \ + T (PSTL2STRM, pstl2strm, 11) \ + T (PSTL3KEEP, pstl3keep, 12) \ + T (PSTL3STRM, pstl3strm, 13) + #define AARCH64_SVENUM(UPPER, LOWER, VALUE) AARCH64_SV_##UPPER = VALUE, enum aarch64_svpattern { AARCH64_FOR_SVPATTERN (AARCH64_SVENUM) AARCH64_NUM_SVPATTERNS }; + +enum aarch64_svprfop { + AARCH64_FOR_SVPRFOP (AARCH64_SVENUM) + AARCH64_NUM_SVPRFOPS +}; #undef AARCH64_SVENUM /* It's convenient to divide the built-in function codes into groups, @@ -438,7 +458,8 @@ enum aarch64_svpattern { those groups. */ enum aarch64_builtin_class { - AARCH64_BUILTIN_GENERAL + AARCH64_BUILTIN_GENERAL, + AARCH64_BUILTIN_SVE }; /* Built-in function codes are structured so that the low @@ -489,8 +510,11 @@ bool aarch64_masks_and_shift_for_bfi_p (scalar_int_mode, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); bool aarch64_zero_extend_const_eq (machine_mode, rtx, machine_mode, rtx); bool aarch64_move_imm (HOST_WIDE_INT, machine_mode); +machine_mode aarch64_sve_int_mode (machine_mode); opt_machine_mode aarch64_sve_pred_mode (unsigned int); +opt_machine_mode aarch64_sve_data_mode (scalar_mode, poly_uint64); bool aarch64_sve_mode_p (machine_mode); +HOST_WIDE_INT aarch64_fold_sve_cnt_pat (aarch64_svpattern, unsigned int); bool aarch64_sve_cnt_immediate_p (rtx); bool aarch64_sve_scalar_inc_dec_immediate_p (rtx); bool aarch64_sve_addvl_addpl_immediate_p (rtx); @@ -501,7 +525,9 @@ bool aarch64_mov_operand_p (rtx, machine_mode); rtx aarch64_reverse_mask (machine_mode, unsigned int); bool aarch64_offset_7bit_signed_scaled_p (machine_mode, poly_int64); bool aarch64_offset_9bit_signed_unscaled_p (machine_mode, poly_int64); +char *aarch64_output_sve_prefetch (const char *, rtx, const char *); char *aarch64_output_sve_cnt_immediate (const char *, const char *, rtx); +char *aarch64_output_sve_cnt_pat_immediate (const char *, const char *, rtx *); char *aarch64_output_sve_scalar_inc_dec (rtx); char *aarch64_output_sve_addvl_addpl (rtx); char *aarch64_output_sve_vector_inc_dec (const char *, rtx); @@ -509,6 +535,7 @@ char *aarch64_output_scalar_simd_mov_immediate (rtx, scalar_int_mode); char *aarch64_output_simd_mov_immediate (rtx, unsigned, enum simd_immediate_check w = AARCH64_CHECK_MOV); char *aarch64_output_sve_mov_immediate (rtx); +char *aarch64_output_sve_ptrues (rtx); bool aarch64_pad_reg_upward (machine_mode, const_tree, bool); bool aarch64_regno_ok_for_base_p (int, bool); bool aarch64_regno_ok_for_index_p (int, bool); @@ -517,11 +544,13 @@ bool aarch64_simd_check_vect_par_cnst_half (rtx op, machine_mode mode, bool high); bool aarch64_simd_scalar_immediate_valid_for_move (rtx, scalar_int_mode); bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool); +bool aarch64_sve_ptrue_svpattern_p (rtx, struct simd_immediate_info *); bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *, enum simd_immediate_check w = AARCH64_CHECK_MOV); rtx aarch64_check_zero_based_sve_index_immediate (rtx); bool aarch64_sve_index_immediate_p (rtx); bool aarch64_sve_arith_immediate_p (rtx, bool); +bool aarch64_sve_sqadd_sqsub_immediate_p (rtx, bool); bool aarch64_sve_bitmask_immediate_p (rtx); bool aarch64_sve_dup_immediate_p (rtx); bool aarch64_sve_cmp_immediate_p (rtx, bool); @@ -552,7 +581,10 @@ rtx aarch64_simd_gen_const_vector_dup (machine_mode, HOST_WIDE_INT); bool aarch64_simd_mem_operand_p (rtx); bool aarch64_sve_ld1r_operand_p (rtx); bool aarch64_sve_ld1rq_operand_p (rtx); +bool aarch64_sve_ldff1_operand_p (rtx); +bool aarch64_sve_ldnf1_operand_p (rtx); bool aarch64_sve_ldr_operand_p (rtx); +bool aarch64_sve_prefetch_operand_p (rtx, machine_mode); bool aarch64_sve_struct_memory_operand_p (rtx); rtx aarch64_simd_vect_par_cnst_half (machine_mode, int, bool); rtx aarch64_gen_stepped_int_parallel (unsigned int, int, int); @@ -568,6 +600,9 @@ const char * aarch64_output_probe_sve_stack_clash (rtx, rtx, rtx, rtx); void aarch64_err_no_fpadvsimd (machine_mode); void aarch64_expand_epilogue (bool); rtx aarch64_ptrue_all (unsigned int); +opt_machine_mode aarch64_ptrue_all_mode (rtx); +rtx aarch64_convert_sve_data_to_pred (rtx, machine_mode, rtx); +rtx aarch64_expand_sve_dupq (rtx, machine_mode, rtx); void aarch64_expand_mov_immediate (rtx, rtx); rtx aarch64_ptrue_reg (machine_mode); rtx aarch64_pfalse_reg (machine_mode); @@ -576,6 +611,7 @@ bool aarch64_sve_same_pred_for_ptest_p (rtx *, rtx *); void aarch64_emit_sve_pred_move (rtx, rtx, rtx); void aarch64_expand_sve_mem_move (rtx, rtx, machine_mode); bool aarch64_maybe_expand_sve_subreg_move (rtx, rtx); +rtx aarch64_replace_reg_mode (rtx, machine_mode); void aarch64_split_sve_subreg_move (rtx, rtx, rtx); void aarch64_expand_prologue (void); void aarch64_expand_vector_init (rtx, rtx); @@ -664,6 +700,20 @@ tree aarch64_general_builtin_decl (unsigned, bool); tree aarch64_general_builtin_rsqrt (unsigned int); tree aarch64_builtin_vectorized_function (unsigned int, tree, tree); +namespace aarch64_sve { + void init_builtins (); + void handle_arm_sve_h (); + tree builtin_decl (unsigned, bool); + bool builtin_type_p (const_tree); + const char *mangle_builtin_type (const_tree); + tree resolve_overloaded_builtin (location_t, unsigned int, + vec<tree, va_gc> *); + bool check_builtin_call (location_t, vec<location_t>, unsigned int, + tree, unsigned int, tree *); + gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *); + rtx expand_builtin (unsigned int, tree, rtx); +} + extern void aarch64_split_combinev16qi (rtx operands[3]); extern void aarch64_expand_vec_perm (rtx, rtx, rtx, rtx, unsigned int); extern void aarch64_expand_sve_vec_perm (rtx, rtx, rtx, rtx); diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc new file mode 100644 index 0000000..ce70f80 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc @@ -0,0 +1,2704 @@ +/* ACLE support for AArch64 SVE (__ARM_FEATURE_SVE intrinsics) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "memmodel.h" +#include "insn-codes.h" +#include "optabs.h" +#include "recog.h" +#include "expr.h" +#include "basic-block.h" +#include "function.h" +#include "fold-const.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimplify.h" +#include "explow.h" +#include "emit-rtl.h" +#include "tree-vector-builder.h" +#include "rtx-vector-builder.h" +#include "vec-perm-indices.h" +#include "aarch64-sve-builtins.h" +#include "aarch64-sve-builtins-shapes.h" +#include "aarch64-sve-builtins-base.h" +#include "aarch64-sve-builtins-functions.h" + +using namespace aarch64_sve; + +namespace { + +/* Expand a call to svmad, or svmla after reordering its operands. + Make _m forms merge with argument MERGE_ARGNO. */ +static rtx +expand_mad (function_expander &e, + unsigned int merge_argno = DEFAULT_MERGE_ARGNO) +{ + if (e.pred == PRED_x) + { + insn_code icode; + if (e.type_suffix (0).integer_p) + icode = code_for_aarch64_pred_fma (e.vector_mode (0)); + else + icode = code_for_aarch64_pred (UNSPEC_COND_FMLA, e.vector_mode (0)); + return e.use_pred_x_insn (icode); + } + + insn_code icode = e.direct_optab_handler (cond_fma_optab); + return e.use_cond_insn (icode, merge_argno); +} + +/* Expand a call to svmsb, or svmls after reordering its operands. + Make _m forms merge with argument MERGE_ARGNO. */ +static rtx +expand_msb (function_expander &e, + unsigned int merge_argno = DEFAULT_MERGE_ARGNO) +{ + if (e.pred == PRED_x) + { + insn_code icode; + if (e.type_suffix (0).integer_p) + icode = code_for_aarch64_pred_fnma (e.vector_mode (0)); + else + icode = code_for_aarch64_pred (UNSPEC_COND_FMLS, e.vector_mode (0)); + return e.use_pred_x_insn (icode); + } + + insn_code icode = e.direct_optab_handler (cond_fnma_optab); + return e.use_cond_insn (icode, merge_argno); +} + +class svabd_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* The integer operations are represented as the subtraction of the + minimum from the maximum, with the signedness of the instruction + keyed off the signedness of the maximum operation. */ + rtx_code max_code = e.type_suffix (0).unsigned_p ? UMAX : SMAX; + insn_code icode; + if (e.pred == PRED_x) + { + if (e.type_suffix (0).integer_p) + icode = code_for_aarch64_pred_abd (max_code, e.vector_mode (0)); + else + icode = code_for_aarch64_pred_abd (e.vector_mode (0)); + return e.use_pred_x_insn (icode); + } + + if (e.type_suffix (0).integer_p) + icode = code_for_aarch64_cond_abd (max_code, e.vector_mode (0)); + else + icode = code_for_aarch64_cond_abd (e.vector_mode (0)); + return e.use_cond_insn (icode); + } +}; + +/* Implements svacge, svacgt, svacle and svaclt. */ +class svac_impl : public function_base +{ +public: + CONSTEXPR svac_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + e.add_ptrue_hint (0, e.gp_mode (0)); + insn_code icode = code_for_aarch64_pred_fac (m_unspec, e.vector_mode (0)); + return e.use_exact_insn (icode); + } + + /* The unspec code for the underlying comparison. */ + int m_unspec; +}; + +class svadda_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Put the predicate last, as required by mask_fold_left_plus_optab. */ + e.rotate_inputs_left (0, 3); + machine_mode mode = e.vector_mode (0); + insn_code icode = direct_optab_handler (mask_fold_left_plus_optab, mode); + return e.use_exact_insn (icode); + } +}; + +/* Implements svadr[bhwd]. */ +class svadr_bhwd_impl : public function_base +{ +public: + CONSTEXPR svadr_bhwd_impl (unsigned int shift) : m_shift (shift) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = GET_MODE (e.args[0]); + if (m_shift == 0) + return e.use_exact_insn (code_for_aarch64_adr (mode)); + + /* Turn the access size into an extra shift argument. */ + rtx shift = gen_int_mode (m_shift, GET_MODE_INNER (mode)); + e.args.quick_push (expand_vector_broadcast (mode, shift)); + return e.use_exact_insn (code_for_aarch64_adr_shift (mode)); + } + + /* How many bits left to shift the vector displacement. */ + unsigned int m_shift; +}; + +class svasrd_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_cond_insn (code_for_cond_asrd (e.vector_mode (0))); + } +}; + +class svbic_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Convert svbic of a constant into svand of its inverse. */ + if (CONST_INT_P (e.args[2])) + { + machine_mode mode = GET_MODE_INNER (e.vector_mode (0)); + e.args[2] = simplify_unary_operation (NOT, mode, e.args[2], mode); + return e.map_to_rtx_codes (AND, AND, -1); + } + + if (e.type_suffix_ids[0] == TYPE_SUFFIX_b) + { + gcc_assert (e.pred == PRED_z); + return e.use_exact_insn (CODE_FOR_aarch64_pred_bicvnx16bi_z); + } + + if (e.pred == PRED_x) + return e.use_unpred_insn (code_for_aarch64_bic (e.vector_mode (0))); + + return e.use_cond_insn (code_for_cond_bic (e.vector_mode (0))); + } +}; + +/* Implements svbrkn, svbrkpa and svbrkpb. */ +class svbrk_binary_impl : public function_base +{ +public: + CONSTEXPR svbrk_binary_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_brk (m_unspec)); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +/* Implements svbrka and svbrkb. */ +class svbrk_unary_impl : public function_base +{ +public: + CONSTEXPR svbrk_unary_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_cond_insn (code_for_aarch64_brk (m_unspec)); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +class svcadd_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Convert the rotation amount into a specific unspec. */ + int rot = INTVAL (e.args[3]); + e.args.ordered_remove (3); + int unspec = (rot == 90 ? UNSPEC_COND_FCADD90 + : rot == 270 ? UNSPEC_COND_FCADD270 + : (gcc_unreachable (), 0)); + return e.map_to_unspecs (-1, -1, unspec); + } +}; + +/* Implements svclasta and svclastb. */ +class svclast_impl : public quiet<function_base> +{ +public: + CONSTEXPR svclast_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Match the fold_extract_optab order. */ + std::swap (e.args[0], e.args[1]); + machine_mode mode = e.vector_mode (0); + insn_code icode; + if (e.mode_suffix_id == MODE_n) + icode = code_for_fold_extract (m_unspec, mode); + else + icode = code_for_aarch64_fold_extract_vector (m_unspec, mode); + return e.use_exact_insn (icode); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +class svcmla_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Convert the rotation amount into a specific unspec. */ + int rot = INTVAL (e.args[4]); + e.args.ordered_remove (4); + int unspec = (rot == 0 ? UNSPEC_COND_FCMLA + : rot == 90 ? UNSPEC_COND_FCMLA90 + : rot == 180 ? UNSPEC_COND_FCMLA180 + : rot == 270 ? UNSPEC_COND_FCMLA270 + : (gcc_unreachable (), 0)); + + /* Make the operand order the same as the one used by the fma optabs, + with the accumulator last. */ + e.rotate_inputs_left (1, 4); + return e.map_to_unspecs (-1, -1, unspec, 3); + } +}; + +class svcmla_lane_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Convert the rotation amount into a specific unspec. */ + int rot = INTVAL (e.args[4]); + e.args.ordered_remove (4); + int unspec = (rot == 0 ? UNSPEC_FCMLA + : rot == 90 ? UNSPEC_FCMLA90 + : rot == 180 ? UNSPEC_FCMLA180 + : rot == 270 ? UNSPEC_FCMLA270 + : (gcc_unreachable (), 0)); + + /* Make the operand order the same as the one used by the fma optabs, + with the accumulator last. */ + e.rotate_inputs_left (0, 4); + insn_code icode = code_for_aarch64_lane (unspec, e.vector_mode (0)); + return e.use_exact_insn (icode); + } +}; + +/* Implements svcmp<cc> (except svcmpuo, which is handled separately). */ +class svcmp_impl : public function_base +{ +public: + CONSTEXPR svcmp_impl (tree_code code, int unspec_for_fp) + : m_code (code), m_unspec_for_fp (unspec_for_fp) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + + /* Comparisons are UNSPEC_PRED_Z operations and so need a hint + operand. */ + e.add_ptrue_hint (0, e.gp_mode (0)); + + if (e.type_suffix (0).integer_p) + { + bool unsigned_p = e.type_suffix (0).unsigned_p; + rtx_code code = get_rtx_code (m_code, unsigned_p); + return e.use_exact_insn (code_for_aarch64_pred_cmp (code, mode)); + } + + insn_code icode = code_for_aarch64_pred_fcm (m_unspec_for_fp, mode); + return e.use_exact_insn (icode); + } + + /* The tree code associated with the comparison. */ + tree_code m_code; + + /* The unspec code to use for floating-point comparisons. */ + int m_unspec_for_fp; +}; + +/* Implements svcmp<cc>_wide. */ +class svcmp_wide_impl : public function_base +{ +public: + CONSTEXPR svcmp_wide_impl (tree_code code, int unspec_for_sint, + int unspec_for_uint) + : m_code (code), m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + bool unsigned_p = e.type_suffix (0).unsigned_p; + rtx_code code = get_rtx_code (m_code, unsigned_p); + + /* Comparisons are UNSPEC_PRED_Z operations and so need a hint + operand. */ + e.add_ptrue_hint (0, e.gp_mode (0)); + + /* If the argument is a constant that the unwidened comparisons + can handle directly, use them instead. */ + insn_code icode = code_for_aarch64_pred_cmp (code, mode); + rtx op2 = unwrap_const_vec_duplicate (e.args[3]); + if (CONSTANT_P (op2) + && insn_data[icode].operand[4].predicate (op2, DImode)) + { + e.args[3] = op2; + return e.use_exact_insn (icode); + } + + int unspec = (unsigned_p ? m_unspec_for_uint : m_unspec_for_sint); + return e.use_exact_insn (code_for_aarch64_pred_cmp_wide (unspec, mode)); + } + + /* The tree code associated with the comparison. */ + tree_code m_code; + + /* The unspec codes for signed and unsigned wide comparisons + respectively. */ + int m_unspec_for_sint; + int m_unspec_for_uint; +}; + +class svcmpuo_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + e.add_ptrue_hint (0, e.gp_mode (0)); + return e.use_exact_insn (code_for_aarch64_pred_fcmuo (e.vector_mode (0))); + } +}; + +class svcnot_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + if (e.pred == PRED_x) + { + /* The pattern for CNOT includes an UNSPEC_PRED_Z, so needs + a ptrue hint. */ + e.add_ptrue_hint (0, e.gp_mode (0)); + return e.use_pred_x_insn (code_for_aarch64_pred_cnot (mode)); + } + + return e.use_cond_insn (code_for_cond_cnot (mode), 0); + } +}; + +/* Implements svcnt[bhwd], which count the number of elements + in a particular vector mode. */ +class svcnt_bhwd_impl : public function_base +{ +public: + CONSTEXPR svcnt_bhwd_impl (machine_mode ref_mode) : m_ref_mode (ref_mode) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree count = build_int_cstu (TREE_TYPE (f.lhs), + GET_MODE_NUNITS (m_ref_mode)); + return gimple_build_assign (f.lhs, count); + } + + rtx + expand (function_expander &) const OVERRIDE + { + return gen_int_mode (GET_MODE_NUNITS (m_ref_mode), DImode); + } + + /* The mode of the vector associated with the [bhwd] suffix. */ + machine_mode m_ref_mode; +}; + +/* Implements svcnt[bhwd]_pat. */ +class svcnt_bhwd_pat_impl : public svcnt_bhwd_impl +{ +public: + CONSTEXPR svcnt_bhwd_pat_impl (machine_mode ref_mode) + : svcnt_bhwd_impl (ref_mode) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree pattern_arg = gimple_call_arg (f.call, 0); + aarch64_svpattern pattern = (aarch64_svpattern) tree_to_shwi (pattern_arg); + + if (pattern == AARCH64_SV_ALL) + /* svcvnt[bwhd]_pat (SV_ALL) == svcnt[bwhd] (). */ + return svcnt_bhwd_impl::fold (f); + + /* See whether we can count the number of elements in the pattern + at compile time. */ + unsigned int elements_per_vq = 128 / GET_MODE_UNIT_BITSIZE (m_ref_mode); + HOST_WIDE_INT value = aarch64_fold_sve_cnt_pat (pattern, elements_per_vq); + if (value >= 0) + { + tree count = build_int_cstu (TREE_TYPE (f.lhs), value); + return gimple_build_assign (f.lhs, count); + } + + return NULL; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + unsigned int elements_per_vq = 128 / GET_MODE_UNIT_BITSIZE (m_ref_mode); + e.args.quick_push (gen_int_mode (elements_per_vq, DImode)); + e.args.quick_push (const1_rtx); + return e.use_exact_insn (CODE_FOR_aarch64_sve_cnt_pat); + } +}; + +class svcntp_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + e.add_ptrue_hint (0, mode); + return e.use_exact_insn (code_for_aarch64_pred_cntp (mode)); + } +}; + +class svcompact_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_compact (e.vector_mode (0))); + } +}; + +/* Implements svcreate2, svcreate3 and svcreate4. */ +class svcreate_impl : public quiet<multi_vector_function> +{ +public: + CONSTEXPR svcreate_impl (unsigned int vectors_per_tuple) + : quiet<multi_vector_function> (vectors_per_tuple) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + unsigned int nargs = gimple_call_num_args (f.call); + tree lhs_type = TREE_TYPE (f.lhs); + + /* Replace the call with a clobber of the result (to prevent it from + becoming upwards exposed) followed by stores into each individual + vector of tuple. + + The fold routines expect the replacement statement to have the + same lhs as the original call, so return the clobber statement + rather than the final vector store. */ + gassign *clobber = gimple_build_assign (f.lhs, build_clobber (lhs_type)); + + for (unsigned int i = nargs; i-- > 0; ) + { + tree rhs_vector = gimple_call_arg (f.call, i); + tree field = tuple_type_field (TREE_TYPE (f.lhs)); + tree lhs_array = build3 (COMPONENT_REF, TREE_TYPE (field), + unshare_expr (f.lhs), field, NULL_TREE); + tree lhs_vector = build4 (ARRAY_REF, TREE_TYPE (rhs_vector), + lhs_array, size_int (i), + NULL_TREE, NULL_TREE); + gassign *assign = gimple_build_assign (lhs_vector, rhs_vector); + gsi_insert_after (f.gsi, assign, GSI_SAME_STMT); + } + return clobber; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + rtx lhs_tuple = e.get_nonoverlapping_reg_target (); + + /* Record that LHS_TUPLE is dead before the first store. */ + emit_clobber (lhs_tuple); + for (unsigned int i = 0; i < e.args.length (); ++i) + { + /* Use an lvalue subreg to refer to vector I in LHS_TUPLE. */ + rtx lhs_vector = simplify_gen_subreg (GET_MODE (e.args[i]), + lhs_tuple, GET_MODE (lhs_tuple), + i * BYTES_PER_SVE_VECTOR); + emit_move_insn (lhs_vector, e.args[i]); + } + return lhs_tuple; + } +}; + +class svcvt_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode0 = e.vector_mode (0); + machine_mode mode1 = e.vector_mode (1); + insn_code icode; + /* All this complication comes from the need to select four things + simultaneously: + + (1) the kind of conversion (int<-float, float<-int, float<-float) + (2) signed vs. unsigned integers, where relevant + (3) the predication mode, which must be the wider of the predication + modes for MODE0 and MODE1 + (4) the predication type (m, x or z) + + The only supported int<->float conversions for which the integer is + narrower than the float are SI<->DF. It's therefore more convenient + to handle (3) by defining two patterns for int<->float conversions: + one in which the integer is at least as wide as the float and so + determines the predication mode, and another single SI<->DF pattern + in which the float's mode determines the predication mode (which is + always VNx2BI in that case). + + The names of the patterns follow the optab convention of giving + the source mode before the destination mode. */ + if (e.type_suffix (1).integer_p) + { + int unspec = (e.type_suffix (1).unsigned_p + ? UNSPEC_COND_UCVTF + : UNSPEC_COND_SCVTF); + if (e.type_suffix (0).element_bytes <= e.type_suffix (1).element_bytes) + icode = (e.pred == PRED_x + ? code_for_aarch64_sve_nonextend (unspec, mode1, mode0) + : code_for_cond_nonextend (unspec, mode1, mode0)); + else + icode = (e.pred == PRED_x + ? code_for_aarch64_sve_extend (unspec, mode1, mode0) + : code_for_cond_extend (unspec, mode1, mode0)); + } + else + { + int unspec = (!e.type_suffix (0).integer_p ? UNSPEC_COND_FCVT + : e.type_suffix (0).unsigned_p ? UNSPEC_COND_FCVTZU + : UNSPEC_COND_FCVTZS); + if (e.type_suffix (0).element_bytes >= e.type_suffix (1).element_bytes) + icode = (e.pred == PRED_x + ? code_for_aarch64_sve_nontrunc (unspec, mode1, mode0) + : code_for_cond_nontrunc (unspec, mode1, mode0)); + else + icode = (e.pred == PRED_x + ? code_for_aarch64_sve_trunc (unspec, mode1, mode0) + : code_for_cond_trunc (unspec, mode1, mode0)); + } + + if (e.pred == PRED_x) + return e.use_pred_x_insn (icode); + return e.use_cond_insn (icode); + } +}; + +class svdot_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* In the optab, the multiplication operands come before the accumulator + operand. The optab is keyed off the multiplication mode. */ + e.rotate_inputs_left (0, 3); + insn_code icode + = e.direct_optab_handler_for_sign (sdot_prod_optab, udot_prod_optab, + 0, GET_MODE (e.args[0])); + return e.use_unpred_insn (icode); + } +}; + +class svdot_lane_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Use the same ordering as the dot_prod_optab, with the + accumulator last. */ + e.rotate_inputs_left (0, 4); + int unspec = (e.type_suffix (0).unsigned_p ? UNSPEC_UDOT : UNSPEC_SDOT); + machine_mode mode = e.vector_mode (0); + return e.use_exact_insn (code_for_aarch64_dot_prod_lane (unspec, mode)); + } +}; + +class svdup_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree vec_type = TREE_TYPE (f.lhs); + tree rhs = gimple_call_arg (f.call, f.pred == PRED_none ? 0 : 1); + + if (f.pred == PRED_none || f.pred == PRED_x) + { + if (CONSTANT_CLASS_P (rhs)) + { + if (f.type_suffix (0).bool_p) + return (tree_to_shwi (rhs) + ? f.fold_to_ptrue () + : f.fold_to_pfalse ()); + + tree rhs_vector = build_vector_from_val (vec_type, rhs); + return gimple_build_assign (f.lhs, rhs_vector); + } + + /* Avoid folding _b to a VEC_DUPLICATE_EXPR, since to do that we + would need to introduce an extra and unwanted conversion to + the truth vector element type. */ + if (!f.type_suffix (0).bool_p) + return gimple_build_assign (f.lhs, VEC_DUPLICATE_EXPR, rhs); + } + + return NULL; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + if (e.pred == PRED_none || e.pred == PRED_x) + /* There's no benefit to using predicated instructions for _x here. */ + return e.use_unpred_insn (e.direct_optab_handler (vec_duplicate_optab)); + + /* Model predicated svdups as a SEL in which the "true" value is + the duplicate of the function argument and the "false" value + is the value of inactive lanes. */ + insn_code icode; + machine_mode mode = e.vector_mode (0); + if (valid_for_const_vector_p (GET_MODE_INNER (mode), e.args.last ())) + /* Duplicate the constant to fill a vector. The pattern optimizes + various cases involving constant operands, falling back to SEL + if necessary. */ + icode = code_for_vcond_mask (mode, mode); + else + /* Use the pattern for selecting between a duplicated scalar + variable and a vector fallback. */ + icode = code_for_aarch64_sel_dup (mode); + return e.use_vcond_mask_insn (icode); + } +}; + +class svdup_lane_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* The native DUP lane has an index range of 64 bytes. */ + machine_mode mode = e.vector_mode (0); + if (CONST_INT_P (e.args[1]) + && IN_RANGE (INTVAL (e.args[1]) * GET_MODE_UNIT_SIZE (mode), 0, 63)) + return e.use_exact_insn (code_for_aarch64_sve_dup_lane (mode)); + + /* Treat svdup_lane as if it were svtbl_n. */ + return e.use_exact_insn (code_for_aarch64_sve_tbl (e.vector_mode (0))); + } +}; + +class svdupq_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree vec_type = TREE_TYPE (f.lhs); + unsigned int nargs = gimple_call_num_args (f.call); + /* For predicates, pad out each argument so that we have one element + per bit. */ + unsigned int factor = (f.type_suffix (0).bool_p + ? f.type_suffix (0).element_bytes : 1); + tree_vector_builder builder (vec_type, nargs * factor, 1); + for (unsigned int i = 0; i < nargs; ++i) + { + tree elt = gimple_call_arg (f.call, i); + if (!CONSTANT_CLASS_P (elt)) + return NULL; + builder.quick_push (elt); + for (unsigned int j = 1; j < factor; ++j) + builder.quick_push (build_zero_cst (TREE_TYPE (vec_type))); + } + return gimple_build_assign (f.lhs, builder.build ()); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + unsigned int elements_per_vq = e.args.length (); + if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) + { + /* Construct a vector of integers so that we can compare them against + zero below. Zero vs. nonzero is the only distinction that + matters. */ + mode = aarch64_sve_int_mode (mode); + for (unsigned int i = 0; i < elements_per_vq; ++i) + e.args[i] = simplify_gen_unary (ZERO_EXTEND, GET_MODE_INNER (mode), + e.args[i], QImode); + } + + /* Get the 128-bit Advanced SIMD vector for this data size. */ + scalar_mode element_mode = GET_MODE_INNER (mode); + machine_mode vq_mode = aarch64_vq_mode (element_mode).require (); + gcc_assert (known_eq (elements_per_vq, GET_MODE_NUNITS (vq_mode))); + + /* Put the arguments into a 128-bit Advanced SIMD vector. We want + argument N to go into architectural lane N, whereas Advanced SIMD + vectors are loaded memory lsb to register lsb. We therefore need + to reverse the elements for big-endian targets. */ + rtx vq_reg = gen_reg_rtx (vq_mode); + rtvec vec = rtvec_alloc (elements_per_vq); + for (unsigned int i = 0; i < elements_per_vq; ++i) + { + unsigned int argno = BYTES_BIG_ENDIAN ? elements_per_vq - i - 1 : i; + RTVEC_ELT (vec, i) = e.args[argno]; + } + aarch64_expand_vector_init (vq_reg, gen_rtx_PARALLEL (vq_mode, vec)); + + /* If the result is a boolean, compare the data vector against zero. */ + if (mode != e.vector_mode (0)) + { + rtx data_dupq = aarch64_expand_sve_dupq (NULL, mode, vq_reg); + return aarch64_convert_sve_data_to_pred (e.possible_target, + e.vector_mode (0), data_dupq); + } + + return aarch64_expand_sve_dupq (e.possible_target, mode, vq_reg); + } +}; + +class svdupq_lane_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + rtx index = e.args[1]; + if (CONST_INT_P (index) && IN_RANGE (INTVAL (index), 0, 3)) + { + /* Use the .Q form of DUP, which is the native instruction for + this function. */ + insn_code icode = code_for_aarch64_sve_dupq_lane (mode); + unsigned int num_indices = e.elements_per_vq (0); + rtx indices = aarch64_gen_stepped_int_parallel + (num_indices, INTVAL (index) * num_indices, 1); + + e.add_output_operand (icode); + e.add_input_operand (icode, e.args[0]); + e.add_fixed_operand (indices); + return e.generate_insn (icode); + } + + /* Build a .D TBL index for the pairs of doublewords that we want to + duplicate. */ + if (CONST_INT_P (index)) + { + /* The index vector is a constant. */ + rtx_vector_builder builder (VNx2DImode, 2, 1); + builder.quick_push (gen_int_mode (INTVAL (index) * 2, DImode)); + builder.quick_push (gen_int_mode (INTVAL (index) * 2 + 1, DImode)); + index = builder.build (); + } + else + { + /* Duplicate INDEX * 2 to fill a DImode vector. The ACLE spec + explicitly allows the top of the index to be dropped. */ + index = force_reg (DImode, simplify_gen_binary (ASHIFT, DImode, + index, const1_rtx)); + index = expand_vector_broadcast (VNx2DImode, index); + + /* Get an alternating 0, 1 predicate. */ + rtx_vector_builder builder (VNx2BImode, 2, 1); + builder.quick_push (const0_rtx); + builder.quick_push (constm1_rtx); + rtx pg = force_reg (VNx2BImode, builder.build ()); + + /* Add one to the odd elements of the index. */ + rtx one = force_reg (VNx2DImode, CONST1_RTX (VNx2DImode)); + rtx target = gen_reg_rtx (VNx2DImode); + emit_insn (gen_cond_addvnx2di (target, pg, index, one, index)); + index = target; + } + + e.args[0] = gen_lowpart (VNx2DImode, e.args[0]); + e.args[1] = index; + return e.use_exact_insn (CODE_FOR_aarch64_sve_tblvnx2di); + } +}; + +class svext_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_ext (e.vector_mode (0))); + } +}; + +/* Implements svextb, svexth and svextw. */ +class svext_bhw_impl : public function_base +{ +public: + CONSTEXPR svext_bhw_impl (scalar_int_mode from_mode) + : m_from_mode (from_mode) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + if (e.type_suffix (0).unsigned_p) + { + /* Convert to an AND. The widest we go is 0xffffffff, which fits + in a CONST_INT. */ + e.args.quick_push (GEN_INT (GET_MODE_MASK (m_from_mode))); + if (e.pred == PRED_m) + /* We now have arguments "(inactive, pg, op, mask)". Convert this + to "(pg, op, mask, inactive)" so that the order matches svand_m + with an extra argument on the end. Take the inactive elements + from this extra argument. */ + e.rotate_inputs_left (0, 4); + return e.map_to_rtx_codes (AND, AND, -1, 3); + } + + machine_mode wide_mode = e.vector_mode (0); + poly_uint64 nunits = GET_MODE_NUNITS (wide_mode); + machine_mode narrow_mode + = aarch64_sve_data_mode (m_from_mode, nunits).require (); + if (e.pred == PRED_x) + { + insn_code icode = code_for_aarch64_pred_sxt (wide_mode, narrow_mode); + return e.use_pred_x_insn (icode); + } + + insn_code icode = code_for_aarch64_cond_sxt (wide_mode, narrow_mode); + return e.use_cond_insn (icode); + } + + /* The element mode that we're extending from. */ + scalar_int_mode m_from_mode; +}; + +/* Implements svget2, svget3 and svget4. */ +class svget_impl : public quiet<multi_vector_function> +{ +public: + CONSTEXPR svget_impl (unsigned int vectors_per_tuple) + : quiet<multi_vector_function> (vectors_per_tuple) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* Fold into a normal gimple component access. */ + tree rhs_tuple = gimple_call_arg (f.call, 0); + tree index = gimple_call_arg (f.call, 1); + tree field = tuple_type_field (TREE_TYPE (rhs_tuple)); + tree rhs_array = build3 (COMPONENT_REF, TREE_TYPE (field), + rhs_tuple, field, NULL_TREE); + tree rhs_vector = build4 (ARRAY_REF, TREE_TYPE (f.lhs), + rhs_array, index, NULL_TREE, NULL_TREE); + return gimple_build_assign (f.lhs, rhs_vector); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Fold the access into a subreg rvalue. */ + return simplify_gen_subreg (e.vector_mode (0), e.args[0], + GET_MODE (e.args[0]), + INTVAL (e.args[1]) * BYTES_PER_SVE_VECTOR); + } +}; + +class svindex_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (e.direct_optab_handler (vec_series_optab)); + } +}; + +class svinsr_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + gcall *new_call = gimple_build_call_internal (IFN_VEC_SHL_INSERT, 2, + gimple_call_arg (f.call, 0), + gimple_call_arg (f.call, 1)); + gimple_call_set_lhs (new_call, f.lhs); + return new_call; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = direct_optab_handler (vec_shl_insert_optab, + e.vector_mode (0)); + return e.use_exact_insn (icode); + } +}; + +/* Implements svlasta and svlastb. */ +class svlast_impl : public quiet<function_base> +{ +public: + CONSTEXPR svlast_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_extract (m_unspec, e.vector_mode (0))); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +class svld1_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + 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); + 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, 3, + base, cookie, pred); + gimple_call_set_lhs (new_call, f.lhs); + return new_call; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = convert_optab_handler (maskload_optab, + e.vector_mode (0), e.gp_mode (0)); + return e.use_contiguous_load_insn (icode); + } +}; + +/* Implements extending contiguous forms of svld1. */ +class svld1_extend_impl : public extending_load +{ +public: + CONSTEXPR svld1_extend_impl (type_suffix_index memory_type) + : extending_load (memory_type) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_load (extend_rtx_code (), + e.vector_mode (0), + e.memory_vector_mode ()); + return e.use_contiguous_load_insn (icode); + } +}; + +class svld1_gather_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_gather_address_operands (1); + /* Put the predicate last, as required by mask_gather_load_optab. */ + e.rotate_inputs_left (0, 5); + machine_mode mem_mode = e.memory_vector_mode (); + insn_code icode = direct_optab_handler (mask_gather_load_optab, mem_mode); + return e.use_exact_insn (icode); + } +}; + +/* Implements extending forms of svld1_gather. */ +class svld1_gather_extend_impl : public extending_load +{ +public: + CONSTEXPR svld1_gather_extend_impl (type_suffix_index memory_type) + : extending_load (memory_type) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_gather_address_operands (1); + /* Put the predicate last, since the extending gathers use the same + operand order as mask_gather_load_optab. */ + e.rotate_inputs_left (0, 5); + insn_code icode = code_for_aarch64_gather_load (extend_rtx_code (), + e.vector_mode (0), + e.memory_vector_mode ()); + return e.use_exact_insn (icode); + } +}; + +class svld1rq_impl : public function_base +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + tree + memory_scalar_type (const function_instance &fi) const OVERRIDE + { + return fi.scalar_type (0); + } + + machine_mode + memory_vector_mode (const function_instance &fi) const OVERRIDE + { + return aarch64_vq_mode (GET_MODE_INNER (fi.vector_mode (0))).require (); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_sve_ld1rq (e.vector_mode (0)); + return e.use_contiguous_load_insn (icode); + } +}; + +/* Implements svld2, svld3 and svld4. */ +class svld234_impl : public full_width_access +{ +public: + CONSTEXPR svld234_impl (unsigned int vectors_per_tuple) + : full_width_access (vectors_per_tuple) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree tuple_type = TREE_TYPE (f.lhs); + 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); + gsi_insert_seq_before (f.gsi, stmts, GSI_SAME_STMT); + + /* Emit two statements: a clobber of the lhs, so that it isn't + upwards exposed, and then the load itself. + + The fold routines expect the replacement statement to have the + same lhs as the original call, so return the clobber statement + rather than the load. */ + gimple *clobber = gimple_build_assign (f.lhs, build_clobber (tuple_type)); + + /* View the loaded data as an array of vectors. */ + tree field = tuple_type_field (tuple_type); + tree lhs_array = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (field), + unshare_expr (f.lhs)); + + /* Emit the load itself. */ + tree cookie = f.load_store_cookie (TREE_TYPE (vectype)); + gcall *new_call = gimple_build_call_internal (IFN_MASK_LOAD_LANES, 3, + base, cookie, pred); + gimple_call_set_lhs (new_call, lhs_array); + gsi_insert_after (f.gsi, new_call, GSI_SAME_STMT); + + return clobber; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode tuple_mode = TYPE_MODE (TREE_TYPE (e.call_expr)); + insn_code icode = convert_optab_handler (vec_mask_load_lanes_optab, + tuple_mode, e.vector_mode (0)); + return e.use_contiguous_load_insn (icode); + } +}; + +class svldff1_gather_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY | CP_READ_FFR | CP_WRITE_FFR; + } + + 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_update_ffr_for_load ()); + + e.prepare_gather_address_operands (1); + /* Put the predicate last, since ldff1_gather uses the same operand + order as mask_gather_load_optab. */ + e.rotate_inputs_left (0, 5); + machine_mode mem_mode = e.memory_vector_mode (); + return e.use_exact_insn (code_for_aarch64_ldff1_gather (mem_mode)); + } +}; + +/* Implements extending forms of svldff1_gather. */ +class svldff1_gather_extend : public extending_load +{ +public: + CONSTEXPR svldff1_gather_extend (type_suffix_index memory_type) + : extending_load (memory_type) {} + + 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_update_ffr_for_load ()); + + e.prepare_gather_address_operands (1); + /* Put the predicate last, since ldff1_gather uses the same operand + order as mask_gather_load_optab. */ + e.rotate_inputs_left (0, 5); + insn_code icode = code_for_aarch64_ldff1_gather (extend_rtx_code (), + e.vector_mode (0), + e.memory_vector_mode ()); + return e.use_exact_insn (icode); + } +}; + +class svldnt1_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_ldnt1 (e.vector_mode (0)); + return e.use_contiguous_load_insn (icode); + } +}; + +/* Implements svldff1 and svldnf1. */ +class svldxf1_impl : public full_width_access +{ +public: + CONSTEXPR svldxf1_impl (int unspec) : m_unspec (unspec) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY | CP_READ_FFR | CP_WRITE_FFR; + } + + 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_update_ffr_for_load ()); + + machine_mode mode = e.vector_mode (0); + return e.use_contiguous_load_insn (code_for_aarch64_ldf1 (m_unspec, mode)); + } + + /* The unspec associated with the load. */ + int m_unspec; +}; + +/* Implements extending contiguous forms of svldff1 and svldnf1. */ +class svldxf1_extend_impl : public extending_load +{ +public: + CONSTEXPR svldxf1_extend_impl (type_suffix_index memory_type, int unspec) + : extending_load (memory_type), m_unspec (unspec) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY | CP_READ_FFR | CP_WRITE_FFR; + } + + 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_update_ffr_for_load ()); + + 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); + } + + /* The unspec associated with the load. */ + int m_unspec; +}; + +class svlen_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* The argument only exists for its type. */ + tree rhs_type = TREE_TYPE (gimple_call_arg (f.call, 0)); + tree count = build_int_cstu (TREE_TYPE (f.lhs), + TYPE_VECTOR_SUBPARTS (rhs_type)); + return gimple_build_assign (f.lhs, count); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* The argument only exists for its type. */ + return gen_int_mode (GET_MODE_NUNITS (e.vector_mode (0)), DImode); + } +}; + +class svmad_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return expand_mad (e); + } +}; + +class svmla_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Put the accumulator at the end (argument 3), but keep it as the + merge input for _m functions. */ + e.rotate_inputs_left (1, 4); + return expand_mad (e, 3); + } +}; + +/* Base class for svmla_lane and svmls_lane. */ +class svmla_svmls_lane_impl : public function_base +{ +public: + CONSTEXPR svmla_svmls_lane_impl (int unspec) + : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Put the operands in the normal (fma ...) order, with the accumulator + last. This fits naturally since that's also the unprinted operand + in the asm output. */ + e.rotate_inputs_left (0, 4); + insn_code icode = code_for_aarch64_lane (m_unspec, e.vector_mode (0)); + return e.use_exact_insn (icode); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +class svmls_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + /* Put the accumulator at the end (argument 3), but keep it as the + merge input for _m functions. */ + e.rotate_inputs_left (1, 4); + return expand_msb (e, 3); + } +}; + +class svmov_impl : public function_base +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + return gimple_build_assign (f.lhs, BIT_AND_EXPR, + gimple_call_arg (f.call, 0), + gimple_call_arg (f.call, 1)); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* The canonical form for the assembler alias "MOV Pa.B, Pb/Z, Pc.B" + is "AND Pa.B, Pb/Z, Pc.B, Pc.B". */ + gcc_assert (e.pred == PRED_z); + e.args.quick_push (e.args[1]); + return e.use_exact_insn (CODE_FOR_aarch64_pred_andvnx16bi_z); + } +}; + +class svmsb_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return expand_msb (e); + } +}; + +class svmul_lane_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_mul_lane (e.vector_mode (0))); + } +}; + +class svnand_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + gcc_assert (e.pred == PRED_z); + return e.use_exact_insn (CODE_FOR_aarch64_pred_nandvnx16bi_z); + } +}; + +class svnor_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + gcc_assert (e.pred == PRED_z); + return e.use_exact_insn (CODE_FOR_aarch64_pred_norvnx16bi_z); + } +}; + +class svnot_impl : public rtx_code_function +{ +public: + CONSTEXPR svnot_impl () : rtx_code_function (NOT, NOT, -1) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + if (e.type_suffix_ids[0] == TYPE_SUFFIX_b) + { + /* The canonical form for the assembler alias "NOT Pa.B, Pb/Z, Pc.B" + is "EOR Pa.B, Pb/Z, Pb.B, Pc.B". */ + gcc_assert (e.pred == PRED_z); + e.args.quick_insert (1, e.args[0]); + return e.use_exact_insn (CODE_FOR_aarch64_pred_xorvnx16bi_z); + } + return rtx_code_function::expand (e); + } +}; + +class svorn_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + gcc_assert (e.pred == PRED_z); + return e.use_exact_insn (CODE_FOR_aarch64_pred_ornvnx16bi_z); + } +}; + +class svpfalse_impl : public function_base +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + return f.fold_to_pfalse (); + } + + rtx + expand (function_expander &) const OVERRIDE + { + return CONST0_RTX (VNx16BImode); + } +}; + +/* Implements svpfirst and svpnext, which share the same .md patterns. */ +class svpfirst_svpnext_impl : public function_base +{ +public: + CONSTEXPR svpfirst_svpnext_impl (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + e.add_ptrue_hint (0, mode); + return e.use_exact_insn (code_for_aarch64_sve (m_unspec, mode)); + } + + /* The unspec associated with the operation. */ + int m_unspec; +}; + +/* Implements contiguous forms of svprf[bhwd]. */ +class svprf_bhwd_impl : public function_base +{ +public: + CONSTEXPR svprf_bhwd_impl (machine_mode mode) : m_mode (mode) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_PREFETCH_MEMORY; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_prefetch_operands (); + insn_code icode = code_for_aarch64_sve_prefetch (m_mode); + return e.use_contiguous_prefetch_insn (icode); + } + + /* The mode that we'd use to hold one vector of prefetched data. */ + machine_mode m_mode; +}; + +/* Implements svprf[bhwd]_gather. */ +class svprf_bhwd_gather_impl : public function_base +{ +public: + CONSTEXPR svprf_bhwd_gather_impl (machine_mode mode) : m_mode (mode) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_PREFETCH_MEMORY; + } + + machine_mode + memory_vector_mode (const function_instance &) const OVERRIDE + { + return m_mode; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_prefetch_operands (); + e.prepare_gather_address_operands (1); + + /* Insert a zero operand to identify the mode of the memory being + accessed. This goes between the gather operands and prefetch + operands created above. */ + e.args.quick_insert (5, CONST0_RTX (m_mode)); + + machine_mode reg_mode = GET_MODE (e.args[2]); + insn_code icode = code_for_aarch64_sve_gather_prefetch (m_mode, reg_mode); + return e.use_exact_insn (icode); + } + + /* The mode that we'd use to hold one vector of prefetched data. */ + machine_mode m_mode; +}; + +/* Implements svptest_any, svptest_first and svptest_last. */ +class svptest_impl : public function_base +{ +public: + CONSTEXPR svptest_impl (rtx_code compare) : m_compare (compare) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* See whether GP is an exact ptrue for some predicate mode; + i.e. whether converting the GP to that mode will not drop + set bits and will leave all significant bits set. */ + machine_mode wide_mode; + int hint; + if (aarch64_ptrue_all_mode (e.args[0]).exists (&wide_mode)) + hint = SVE_KNOWN_PTRUE; + else + { + hint = SVE_MAYBE_NOT_PTRUE; + wide_mode = VNx16BImode; + } + + /* Generate the PTEST itself. */ + rtx pg = force_reg (VNx16BImode, e.args[0]); + rtx wide_pg = gen_lowpart (wide_mode, pg); + rtx hint_rtx = gen_int_mode (hint, DImode); + rtx op = force_reg (wide_mode, gen_lowpart (wide_mode, e.args[1])); + emit_insn (gen_aarch64_ptestvnx16bi (pg, wide_pg, hint_rtx, op)); + + /* Get the location of the boolean result. We can provide SImode and + DImode values directly; rely on generic code to convert others. */ + rtx target = e.possible_target; + if (!target + || !REG_P (target) + || (GET_MODE (target) != SImode && GET_MODE (target) != DImode)) + target = gen_reg_rtx (DImode); + + /* Generate a CSET to convert the CC result of the PTEST to a boolean. */ + rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM); + rtx compare = gen_rtx_fmt_ee (m_compare, GET_MODE (target), + cc_reg, const0_rtx); + emit_insn (gen_rtx_SET (target, compare)); + return target; + } + + /* The comparison code associated with ptest condition. */ + rtx_code m_compare; +}; + +class svptrue_impl : public function_base +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + return f.fold_to_ptrue (); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + return aarch64_ptrue_all (e.type_suffix (0).element_bytes); + } +}; + +class svptrue_pat_impl : public function_base +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree pattern_arg = gimple_call_arg (f.call, 0); + aarch64_svpattern pattern = (aarch64_svpattern) tree_to_shwi (pattern_arg); + + if (pattern == AARCH64_SV_ALL) + /* svptrue_pat_bN (SV_ALL) == svptrue_bN (). */ + return f.fold_to_ptrue (); + + /* See whether we can count the number of elements in the pattern + at compile time. If so, construct a predicate with that number + of 1s followed by all 0s. */ + int nelts_per_vq = f.elements_per_vq (0); + HOST_WIDE_INT value = aarch64_fold_sve_cnt_pat (pattern, nelts_per_vq); + if (value >= 0) + return f.fold_to_vl_pred (value); + + return NULL; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* In rtl, the predicate is represented as the constant: + + (const:V16BI (unspec:V16BI [(const_int PATTERN) + (const_vector:VnnBI [zeros])] + UNSPEC_PTRUE)) + + where nn determines the element size. */ + rtvec vec = gen_rtvec (2, e.args[0], CONST0_RTX (e.vector_mode (0))); + return gen_rtx_CONST (VNx16BImode, + gen_rtx_UNSPEC (VNx16BImode, vec, UNSPEC_PTRUE)); + } +}; + +class svqadd_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.expand_signed_unpred_op (SS_PLUS, US_PLUS); + } +}; + +/* Implements svqdec[bhwd]{,_pat} and svqinc[bhwd]{,_pat}. */ +class svqdec_svqinc_bhwd_impl : public function_base +{ +public: + CONSTEXPR svqdec_svqinc_bhwd_impl (rtx_code code_for_sint, + rtx_code code_for_uint, + scalar_int_mode elem_mode) + : m_code_for_sint (code_for_sint), + m_code_for_uint (code_for_uint), + m_elem_mode (elem_mode) + {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Treat non-_pat functions in the same way as _pat functions with + an SV_ALL argument. */ + if (e.args.length () == 2) + e.args.quick_insert (1, gen_int_mode (AARCH64_SV_ALL, DImode)); + + /* Insert the number of elements per 128-bit block as a fake argument, + between the pattern and the multiplier. Arguments 1, 2 and 3 then + correspond exactly with the 3 UNSPEC_SVE_CNT_PAT operands; see + aarch64_sve_cnt_pat for details. */ + unsigned int elements_per_vq = 128 / GET_MODE_BITSIZE (m_elem_mode); + e.args.quick_insert (2, gen_int_mode (elements_per_vq, DImode)); + + rtx_code code = (e.type_suffix (0).unsigned_p + ? m_code_for_uint + : m_code_for_sint); + + /* Choose between operating on integer scalars or integer vectors. */ + machine_mode mode = e.vector_mode (0); + if (e.mode_suffix_id == MODE_n) + mode = GET_MODE_INNER (mode); + return e.use_exact_insn (code_for_aarch64_sve_pat (code, mode)); + } + + /* The saturating addition or subtraction codes to use for signed and + unsigned values respectively. */ + rtx_code m_code_for_sint; + rtx_code m_code_for_uint; + + /* The integer mode associated with the [bhwd] suffix. */ + scalar_int_mode m_elem_mode; +}; + +/* Implements svqdec[bhwd]{,_pat}. */ +class svqdec_bhwd_impl : public svqdec_svqinc_bhwd_impl +{ +public: + CONSTEXPR svqdec_bhwd_impl (scalar_int_mode elem_mode) + : svqdec_svqinc_bhwd_impl (SS_MINUS, US_MINUS, elem_mode) {} +}; + +/* Implements svqinc[bhwd]{,_pat}. */ +class svqinc_bhwd_impl : public svqdec_svqinc_bhwd_impl +{ +public: + CONSTEXPR svqinc_bhwd_impl (scalar_int_mode elem_mode) + : svqdec_svqinc_bhwd_impl (SS_PLUS, US_PLUS, elem_mode) {} +}; + +/* Implements svqdecp and svqincp. */ +class svqdecp_svqincp_impl : public function_base +{ +public: + CONSTEXPR svqdecp_svqincp_impl (rtx_code code_for_sint, + rtx_code code_for_uint) + : m_code_for_sint (code_for_sint), + m_code_for_uint (code_for_uint) + {} + + rtx + expand (function_expander &e) const OVERRIDE + { + rtx_code code = (e.type_suffix (0).unsigned_p + ? m_code_for_uint + : m_code_for_sint); + insn_code icode; + if (e.mode_suffix_id == MODE_n) + { + /* Increment or decrement a scalar (whose mode is given by the first + type suffix) by the number of active elements in a predicate + (whose mode is given by the second type suffix). */ + machine_mode mode = GET_MODE_INNER (e.vector_mode (0)); + icode = code_for_aarch64_sve_cntp (code, mode, e.vector_mode (1)); + } + else + /* Increment a vector by the number of active elements in a predicate, + with the vector mode determining the predicate mode. */ + icode = code_for_aarch64_sve_cntp (code, e.vector_mode (0)); + return e.use_exact_insn (icode); + } + + /* The saturating addition or subtraction codes to use for signed and + unsigned values respectively. */ + rtx_code m_code_for_sint; + rtx_code m_code_for_uint; +}; + +class svqsub_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.expand_signed_unpred_op (SS_MINUS, US_MINUS); + } +}; + +class svrdffr_impl : public function_base +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_FFR; + } + + 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); + emit_insn (gen_aarch64_update_ffrt ()); + return result; + } +}; + +class svreinterpret_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* Punt to rtl if the effect of the reinterpret on registers does not + conform to GCC's endianness model. */ + if (!targetm.can_change_mode_class (f.vector_mode (0), + f.vector_mode (1), FP_REGS)) + return NULL; + + /* Otherwise svreinterpret corresponds directly to a VIEW_CONVERT_EXPR + reinterpretation. */ + tree rhs = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (f.lhs), + gimple_call_arg (f.call, 0)); + return gimple_build_assign (f.lhs, VIEW_CONVERT_EXPR, rhs); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + return e.use_exact_insn (code_for_aarch64_sve_reinterpret (mode)); + } +}; + +class svrev_impl : public permute +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* Punt for now on _b16 and wider; we'd need more complex evpc logic + to rerecognize the result. */ + if (f.type_suffix (0).bool_p && f.type_suffix (0).element_bits > 8) + return NULL; + + /* Permute as { nelts - 1, nelts - 2, nelts - 3, ... }. */ + poly_int64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs)); + vec_perm_builder builder (nelts, 1, 3); + for (int i = 0; i < 3; ++i) + builder.quick_push (nelts - i - 1); + return fold_permute (f, builder); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_rev (e.vector_mode (0))); + } +}; + +class svsel_impl : public quiet<function_base> +{ +public: + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* svsel corresponds exactly to VEC_COND_EXPR. */ + gimple_seq stmts = NULL; + tree pred = f.convert_pred (stmts, f.vector_type (0), 0); + gsi_insert_seq_before (f.gsi, stmts, GSI_SAME_STMT); + return gimple_build_assign (f.lhs, VEC_COND_EXPR, pred, + gimple_call_arg (f.call, 1), + gimple_call_arg (f.call, 2)); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* svsel (cond, truev, falsev) is vcond_mask (truev, falsev, cond). */ + e.rotate_inputs_left (0, 3); + insn_code icode = convert_optab_handler (vcond_mask_optab, + e.vector_mode (0), + e.gp_mode (0)); + return e.use_exact_insn (icode); + } +}; + +/* Implements svset2, svset3 and svset4. */ +class svset_impl : public quiet<multi_vector_function> +{ +public: + CONSTEXPR svset_impl (unsigned int vectors_per_tuple) + : quiet<multi_vector_function> (vectors_per_tuple) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + tree rhs_tuple = gimple_call_arg (f.call, 0); + tree index = gimple_call_arg (f.call, 1); + tree rhs_vector = gimple_call_arg (f.call, 2); + + /* Replace the call with two statements: a copy of the full tuple + to the call result, followed by an update of the individual vector. + + The fold routines expect the replacement statement to have the + same lhs as the original call, so return the copy statement + rather than the field update. */ + gassign *copy = gimple_build_assign (unshare_expr (f.lhs), rhs_tuple); + + /* Get a reference to the individual vector. */ + tree field = tuple_type_field (TREE_TYPE (f.lhs)); + tree lhs_array = build3 (COMPONENT_REF, TREE_TYPE (field), + f.lhs, field, NULL_TREE); + tree lhs_vector = build4 (ARRAY_REF, TREE_TYPE (rhs_vector), + lhs_array, index, NULL_TREE, NULL_TREE); + gassign *update = gimple_build_assign (lhs_vector, rhs_vector); + gsi_insert_after (f.gsi, update, GSI_SAME_STMT); + + return copy; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + rtx rhs_tuple = e.args[0]; + unsigned int index = INTVAL (e.args[1]); + rtx rhs_vector = e.args[2]; + + /* First copy the full tuple to the target register. */ + rtx lhs_tuple = e.get_nonoverlapping_reg_target (); + emit_move_insn (lhs_tuple, rhs_tuple); + + /* ...then update the individual vector. */ + rtx lhs_vector = simplify_gen_subreg (GET_MODE (rhs_vector), + lhs_tuple, GET_MODE (lhs_tuple), + index * BYTES_PER_SVE_VECTOR); + emit_move_insn (lhs_vector, rhs_vector); + return lhs_vector; + } +}; + +class svsetffr_impl : public function_base +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_FFR; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + e.args.quick_push (CONSTM1_RTX (VNx16BImode)); + return e.use_exact_insn (CODE_FOR_aarch64_wrffr); + } +}; + +class svsplice_impl : public quiet<function_base> +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_splice (e.vector_mode (0))); + } +}; + +class svst1_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_MEMORY; + } + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + 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); + gsi_insert_seq_before (f.gsi, stmts, GSI_SAME_STMT); + + tree cookie = f.load_store_cookie (TREE_TYPE (vectype)); + tree rhs = gimple_call_arg (f.call, gimple_call_num_args (f.call) - 1); + return gimple_build_call_internal (IFN_MASK_STORE, 4, + base, cookie, pred, rhs); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = convert_optab_handler (maskstore_optab, + e.vector_mode (0), e.gp_mode (0)); + return e.use_contiguous_store_insn (icode); + } +}; + +class svst1_scatter_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_MEMORY; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_gather_address_operands (1); + /* Put the predicate last, as required by mask_scatter_store_optab. */ + e.rotate_inputs_left (0, 6); + insn_code icode = direct_optab_handler (mask_scatter_store_optab, + e.memory_vector_mode ()); + return e.use_exact_insn (icode); + } +}; + +/* Implements truncating forms of svst1_scatter. */ +class svst1_scatter_truncate_impl : public truncating_store +{ +public: + CONSTEXPR svst1_scatter_truncate_impl (scalar_int_mode to_mode) + : truncating_store (to_mode) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + e.prepare_gather_address_operands (1); + /* Put the predicate last, since the truncating scatters use the same + operand order as mask_scatter_store_optab. */ + e.rotate_inputs_left (0, 6); + insn_code icode = code_for_aarch64_scatter_store_trunc + (e.memory_vector_mode (), e.vector_mode (0)); + return e.use_exact_insn (icode); + } +}; + +/* Implements truncating contiguous forms of svst1. */ +class svst1_truncate_impl : public truncating_store +{ +public: + CONSTEXPR svst1_truncate_impl (scalar_int_mode to_mode) + : truncating_store (to_mode) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_store_trunc (e.memory_vector_mode (), + e.vector_mode (0)); + return e.use_contiguous_store_insn (icode); + } +}; + +/* Implements svst2, svst3 and svst4. */ +class svst234_impl : public full_width_access +{ +public: + CONSTEXPR svst234_impl (unsigned int vectors_per_tuple) + : full_width_access (vectors_per_tuple) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_MEMORY; + } + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + 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); + gsi_insert_seq_before (f.gsi, stmts, GSI_SAME_STMT); + + /* View the stored data as an array of vectors. */ + unsigned int num_args = gimple_call_num_args (f.call); + tree rhs_tuple = gimple_call_arg (f.call, num_args - 1); + tree field = tuple_type_field (TREE_TYPE (rhs_tuple)); + tree rhs_array = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (field), rhs_tuple); + + tree cookie = f.load_store_cookie (TREE_TYPE (vectype)); + return gimple_build_call_internal (IFN_MASK_STORE_LANES, 4, + base, cookie, pred, rhs_array); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode tuple_mode = GET_MODE (e.args.last ()); + insn_code icode = convert_optab_handler (vec_mask_store_lanes_optab, + tuple_mode, e.vector_mode (0)); + return e.use_contiguous_store_insn (icode); + } +}; + +class svstnt1_impl : public full_width_access +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_MEMORY; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_stnt1 (e.vector_mode (0)); + return e.use_contiguous_store_insn (icode); + } +}; + +class svsub_impl : public rtx_code_function +{ +public: + CONSTEXPR svsub_impl () + : rtx_code_function (MINUS, MINUS, UNSPEC_COND_FSUB) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Canonicalize subtractions of constants to additions. */ + machine_mode mode = e.vector_mode (0); + if (e.try_negating_argument (2, mode)) + return e.map_to_rtx_codes (PLUS, PLUS, UNSPEC_COND_FADD); + + return rtx_code_function::expand (e); + } +}; + +class svtbl_impl : public permute +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_tbl (e.vector_mode (0))); + } +}; + +class svtmad_impl : public function_base +{ +public: + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (code_for_aarch64_sve_tmad (e.vector_mode (0))); + } +}; + +/* Implements svtrn1 and svtrn2. */ +class svtrn_impl : public binary_permute +{ +public: + CONSTEXPR svtrn_impl (int base) + : binary_permute (base ? UNSPEC_TRN2 : UNSPEC_TRN1), m_base (base) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* svtrn1: { 0, nelts, 2, nelts + 2, 4, nelts + 4, ... } + svtrn2: as for svtrn1, but with 1 added to each index. */ + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs)); + vec_perm_builder builder (nelts, 2, 3); + for (unsigned int i = 0; i < 3; ++i) + { + builder.quick_push (m_base + i * 2); + builder.quick_push (m_base + i * 2 + nelts); + } + return fold_permute (f, builder); + } + + /* 0 for svtrn1, 1 for svtrn2. */ + unsigned int m_base; +}; + +/* Base class for svundef{,2,3,4}. */ +class svundef_impl : public quiet<multi_vector_function> +{ +public: + CONSTEXPR svundef_impl (unsigned int vectors_per_tuple) + : quiet<multi_vector_function> (vectors_per_tuple) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* Don't fold svundef at the gimple level. There's no exact + correspondence for SSA_NAMEs, and we explicitly don't want + to generate a specific value (like an all-zeros vector). */ + if (vectors_per_tuple () == 1) + return NULL; + return gimple_build_assign (f.lhs, build_clobber (TREE_TYPE (f.lhs))); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + rtx target = e.get_reg_target (); + emit_clobber (copy_rtx (target)); + return target; + } +}; + +/* Implements svunpklo and svunpkhi. */ +class svunpk_impl : public quiet<function_base> +{ +public: + CONSTEXPR svunpk_impl (bool high_p) : m_high_p (high_p) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* Don't fold the predicate ops, since every bit of the svbool_t + result is significant. */ + if (f.type_suffix_ids[0] == TYPE_SUFFIX_b) + return NULL; + + /* The first half in memory is VEC_UNPACK_LO_EXPR for little-endian + and VEC_UNPACK_HI_EXPR for big-endian. */ + bool high_p = BYTES_BIG_ENDIAN ? !m_high_p : m_high_p; + tree_code code = high_p ? VEC_UNPACK_HI_EXPR : VEC_UNPACK_LO_EXPR; + return gimple_build_assign (f.lhs, code, gimple_call_arg (f.call, 0)); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = GET_MODE (e.args[0]); + unsigned int unpacku = m_high_p ? UNSPEC_UNPACKUHI : UNSPEC_UNPACKULO; + unsigned int unpacks = m_high_p ? UNSPEC_UNPACKSHI : UNSPEC_UNPACKSLO; + insn_code icode; + if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) + icode = code_for_aarch64_sve_punpk (unpacku, mode); + else + { + int unspec = e.type_suffix (0).unsigned_p ? unpacku : unpacks; + icode = code_for_aarch64_sve_unpk (unspec, unspec, mode); + } + return e.use_exact_insn (icode); + } + + /* True for svunpkhi, false for svunpklo. */ + bool m_high_p; +}; + +/* Implements svuzp1 and svuzp2. */ +class svuzp_impl : public binary_permute +{ +public: + CONSTEXPR svuzp_impl (unsigned int base) + : binary_permute (base ? UNSPEC_UZP2 : UNSPEC_UZP1), m_base (base) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* svuzp1: { 0, 2, 4, 6, ... } + svuzp2: { 1, 3, 5, 7, ... }. */ + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs)); + vec_perm_builder builder (nelts, 1, 3); + for (unsigned int i = 0; i < 3; ++i) + builder.quick_push (m_base + i * 2); + return fold_permute (f, builder); + } + + /* 0 for svuzp1, 1 for svuzp2. */ + unsigned int m_base; +}; + +/* A function_base for svwhilele and svwhilelt functions. */ +class svwhile_impl : public function_base +{ +public: + CONSTEXPR svwhile_impl (int unspec_for_sint, int unspec_for_uint, bool eq_p) + : m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint), m_eq_p (eq_p) + {} + + /* Try to fold a call by treating its arguments as constants of type T. */ + template<typename T> + gimple * + fold_type (gimple_folder &f) const + { + /* Only handle cases in which both operands are constant. */ + T arg0, arg1; + if (!poly_int_tree_p (gimple_call_arg (f.call, 0), &arg0) + || !poly_int_tree_p (gimple_call_arg (f.call, 1), &arg1)) + return NULL; + + /* Check whether the result is known to be all-false. */ + if (m_eq_p ? known_gt (arg0, arg1) : known_ge (arg0, arg1)) + return f.fold_to_pfalse (); + + /* Punt if we can't tell at compile time whether the result + is all-false. */ + if (m_eq_p ? maybe_gt (arg0, arg1) : maybe_ge (arg0, arg1)) + return NULL; + + /* At this point we know the result has at least one set element. */ + poly_uint64 diff = arg1 - arg0; + poly_uint64 nelts = GET_MODE_NUNITS (f.vector_mode (0)); + + /* Canonicalize the svwhilele form to the svwhilelt form. Subtract + from NELTS rather than adding to DIFF, to prevent overflow. */ + if (m_eq_p) + nelts -= 1; + + /* Check whether the result is known to be all-true. */ + if (known_ge (diff, nelts)) + return f.fold_to_ptrue (); + + /* Punt if DIFF might not be the actual number of set elements + in the result. Conditional equality is fine. */ + if (maybe_gt (diff, nelts)) + return NULL; + + /* At this point we know that the predicate will have DIFF set elements + for svwhilelt and DIFF + 1 set elements for svwhilele (which stops + after rather than before ARG1 is reached). See if we can create + the predicate at compile time. */ + unsigned HOST_WIDE_INT vl; + if (diff.is_constant (&vl)) + /* Overflow is no longer possible after the checks above. */ + return f.fold_to_vl_pred (m_eq_p ? vl + 1 : vl); + + return NULL; + } + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + if (f.type_suffix (1).unsigned_p) + return fold_type<poly_uint64> (f); + else + return fold_type<poly_int64> (f); + } + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Suffix 0 determines the predicate mode, suffix 1 determines the + scalar mode and signedness. */ + int unspec = (e.type_suffix (1).unsigned_p + ? m_unspec_for_uint + : m_unspec_for_sint); + machine_mode pred_mode = e.vector_mode (0); + scalar_mode reg_mode = GET_MODE_INNER (e.vector_mode (1)); + return e.use_exact_insn (code_for_while (unspec, reg_mode, pred_mode)); + } + + /* The unspec codes associated with signed and unsigned operations + respectively. */ + int m_unspec_for_sint; + int m_unspec_for_uint; + + /* True svwhilele, false for svwhilelt. */ + bool m_eq_p; +}; + +class svwrffr_impl : public function_base +{ +public: + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_FFR; + } + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.use_exact_insn (CODE_FOR_aarch64_wrffr); + } +}; + +/* Implements svzip1 and svzip2. */ +class svzip_impl : public binary_permute +{ +public: + CONSTEXPR svzip_impl (unsigned int base) + : binary_permute (base ? UNSPEC_ZIP2 : UNSPEC_ZIP1), m_base (base) {} + + gimple * + fold (gimple_folder &f) const OVERRIDE + { + /* svzip1: { 0, nelts, 1, nelts + 1, 2, nelts + 2, ... } + svzip2: as for svzip1, but with nelts / 2 added to each index. */ + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs)); + poly_uint64 base = m_base * exact_div (nelts, 2); + vec_perm_builder builder (nelts, 2, 3); + for (unsigned int i = 0; i < 3; ++i) + { + builder.quick_push (base + i); + builder.quick_push (base + i + nelts); + } + return fold_permute (f, builder); + } + + /* 0 for svzip1, 1 for svzip2. */ + unsigned int m_base; +}; + +} /* end anonymous namespace */ + +namespace aarch64_sve { + +FUNCTION (svabd, svabd_impl,) +FUNCTION (svabs, quiet<rtx_code_function>, (ABS, ABS, UNSPEC_COND_FABS)) +FUNCTION (svacge, svac_impl, (UNSPEC_COND_FCMGE)) +FUNCTION (svacgt, svac_impl, (UNSPEC_COND_FCMGT)) +FUNCTION (svacle, svac_impl, (UNSPEC_COND_FCMLE)) +FUNCTION (svaclt, svac_impl, (UNSPEC_COND_FCMLT)) +FUNCTION (svadd, rtx_code_function, (PLUS, PLUS, UNSPEC_COND_FADD)) +FUNCTION (svadda, svadda_impl,) +FUNCTION (svaddv, reduction, (UNSPEC_SADDV, UNSPEC_UADDV, UNSPEC_FADDV)) +FUNCTION (svadrb, svadr_bhwd_impl, (0)) +FUNCTION (svadrd, svadr_bhwd_impl, (3)) +FUNCTION (svadrh, svadr_bhwd_impl, (1)) +FUNCTION (svadrw, svadr_bhwd_impl, (2)) +FUNCTION (svand, rtx_code_function, (AND, AND)) +FUNCTION (svandv, reduction, (UNSPEC_ANDV)) +FUNCTION (svasr, rtx_code_function, (ASHIFTRT, ASHIFTRT)) +FUNCTION (svasr_wide, shift_wide, (ASHIFTRT, UNSPEC_ASHIFTRT_WIDE)) +FUNCTION (svasrd, svasrd_impl,) +FUNCTION (svbic, svbic_impl,) +FUNCTION (svbrka, svbrk_unary_impl, (UNSPEC_BRKA)) +FUNCTION (svbrkb, svbrk_unary_impl, (UNSPEC_BRKB)) +FUNCTION (svbrkn, svbrk_binary_impl, (UNSPEC_BRKN)) +FUNCTION (svbrkpa, svbrk_binary_impl, (UNSPEC_BRKPA)) +FUNCTION (svbrkpb, svbrk_binary_impl, (UNSPEC_BRKPB)) +FUNCTION (svcadd, svcadd_impl,) +FUNCTION (svclasta, svclast_impl, (UNSPEC_CLASTA)) +FUNCTION (svclastb, svclast_impl, (UNSPEC_CLASTB)) +FUNCTION (svcls, unary_count, (CLRSB)) +FUNCTION (svclz, unary_count, (CLZ)) +FUNCTION (svcmla, svcmla_impl,) +FUNCTION (svcmla_lane, svcmla_lane_impl,) +FUNCTION (svcmpeq, svcmp_impl, (EQ_EXPR, UNSPEC_COND_FCMEQ)) +FUNCTION (svcmpeq_wide, svcmp_wide_impl, (EQ_EXPR, UNSPEC_COND_CMPEQ_WIDE, + UNSPEC_COND_CMPEQ_WIDE)) +FUNCTION (svcmpge, svcmp_impl, (GE_EXPR, UNSPEC_COND_FCMGE)) +FUNCTION (svcmpge_wide, svcmp_wide_impl, (GE_EXPR, UNSPEC_COND_CMPGE_WIDE, + UNSPEC_COND_CMPHS_WIDE)) +FUNCTION (svcmpgt, svcmp_impl, (GT_EXPR, UNSPEC_COND_FCMGT)) +FUNCTION (svcmpgt_wide, svcmp_wide_impl, (GT_EXPR, UNSPEC_COND_CMPGT_WIDE, + UNSPEC_COND_CMPHI_WIDE)) +FUNCTION (svcmple, svcmp_impl, (LE_EXPR, UNSPEC_COND_FCMLE)) +FUNCTION (svcmple_wide, svcmp_wide_impl, (LE_EXPR, UNSPEC_COND_CMPLE_WIDE, + UNSPEC_COND_CMPLS_WIDE)) +FUNCTION (svcmplt, svcmp_impl, (LT_EXPR, UNSPEC_COND_FCMLT)) +FUNCTION (svcmplt_wide, svcmp_wide_impl, (LT_EXPR, UNSPEC_COND_CMPLT_WIDE, + UNSPEC_COND_CMPLO_WIDE)) +FUNCTION (svcmpne, svcmp_impl, (NE_EXPR, UNSPEC_COND_FCMNE)) +FUNCTION (svcmpne_wide, svcmp_wide_impl, (NE_EXPR, UNSPEC_COND_CMPNE_WIDE, + UNSPEC_COND_CMPNE_WIDE)) +FUNCTION (svcmpuo, svcmpuo_impl,) +FUNCTION (svcnot, svcnot_impl,) +FUNCTION (svcnt, unary_count, (POPCOUNT)) +FUNCTION (svcntb, svcnt_bhwd_impl, (VNx16QImode)) +FUNCTION (svcntb_pat, svcnt_bhwd_pat_impl, (VNx16QImode)) +FUNCTION (svcntd, svcnt_bhwd_impl, (VNx2DImode)) +FUNCTION (svcntd_pat, svcnt_bhwd_pat_impl, (VNx2DImode)) +FUNCTION (svcnth, svcnt_bhwd_impl, (VNx8HImode)) +FUNCTION (svcnth_pat, svcnt_bhwd_pat_impl, (VNx8HImode)) +FUNCTION (svcntp, svcntp_impl,) +FUNCTION (svcntw, svcnt_bhwd_impl, (VNx4SImode)) +FUNCTION (svcntw_pat, svcnt_bhwd_pat_impl, (VNx4SImode)) +FUNCTION (svcompact, svcompact_impl,) +FUNCTION (svcreate2, svcreate_impl, (2)) +FUNCTION (svcreate3, svcreate_impl, (3)) +FUNCTION (svcreate4, svcreate_impl, (4)) +FUNCTION (svcvt, svcvt_impl,) +FUNCTION (svdiv, rtx_code_function, (DIV, UDIV, UNSPEC_COND_FDIV)) +FUNCTION (svdivr, rtx_code_function_rotated, (DIV, UDIV, UNSPEC_COND_FDIV)) +FUNCTION (svdot, svdot_impl,) +FUNCTION (svdot_lane, svdot_lane_impl,) +FUNCTION (svdup, svdup_impl,) +FUNCTION (svdup_lane, svdup_lane_impl,) +FUNCTION (svdupq, svdupq_impl,) +FUNCTION (svdupq_lane, svdupq_lane_impl,) +FUNCTION (sveor, rtx_code_function, (XOR, XOR, -1)) +FUNCTION (sveorv, reduction, (UNSPEC_XORV)) +FUNCTION (svexpa, unspec_based_function, (-1, -1, UNSPEC_FEXPA)) +FUNCTION (svext, svext_impl,) +FUNCTION (svextb, svext_bhw_impl, (QImode)) +FUNCTION (svexth, svext_bhw_impl, (HImode)) +FUNCTION (svextw, svext_bhw_impl, (SImode)) +FUNCTION (svget2, svget_impl, (2)) +FUNCTION (svget3, svget_impl, (3)) +FUNCTION (svget4, svget_impl, (4)) +FUNCTION (svindex, svindex_impl,) +FUNCTION (svinsr, svinsr_impl,) +FUNCTION (svlasta, svlast_impl, (UNSPEC_LASTA)) +FUNCTION (svlastb, svlast_impl, (UNSPEC_LASTB)) +FUNCTION (svld1, svld1_impl,) +FUNCTION (svld1_gather, svld1_gather_impl,) +FUNCTION (svld1rq, svld1rq_impl,) +FUNCTION (svld1sb, svld1_extend_impl, (TYPE_SUFFIX_s8)) +FUNCTION (svld1sb_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_s8)) +FUNCTION (svld1sh, svld1_extend_impl, (TYPE_SUFFIX_s16)) +FUNCTION (svld1sh_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_s16)) +FUNCTION (svld1sw, svld1_extend_impl, (TYPE_SUFFIX_s32)) +FUNCTION (svld1sw_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_s32)) +FUNCTION (svld1ub, svld1_extend_impl, (TYPE_SUFFIX_u8)) +FUNCTION (svld1ub_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_u8)) +FUNCTION (svld1uh, svld1_extend_impl, (TYPE_SUFFIX_u16)) +FUNCTION (svld1uh_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_u16)) +FUNCTION (svld1uw, svld1_extend_impl, (TYPE_SUFFIX_u32)) +FUNCTION (svld1uw_gather, svld1_gather_extend_impl, (TYPE_SUFFIX_u32)) +FUNCTION (svld2, svld234_impl, (2)) +FUNCTION (svld3, svld234_impl, (3)) +FUNCTION (svld4, svld234_impl, (4)) +FUNCTION (svldff1, svldxf1_impl, (UNSPEC_LDFF1)) +FUNCTION (svldff1_gather, svldff1_gather_impl,) +FUNCTION (svldff1sb, svldxf1_extend_impl, (TYPE_SUFFIX_s8, UNSPEC_LDFF1)) +FUNCTION (svldff1sb_gather, svldff1_gather_extend, (TYPE_SUFFIX_s8)) +FUNCTION (svldff1sh, svldxf1_extend_impl, (TYPE_SUFFIX_s16, UNSPEC_LDFF1)) +FUNCTION (svldff1sh_gather, svldff1_gather_extend, (TYPE_SUFFIX_s16)) +FUNCTION (svldff1sw, svldxf1_extend_impl, (TYPE_SUFFIX_s32, UNSPEC_LDFF1)) +FUNCTION (svldff1sw_gather, svldff1_gather_extend, (TYPE_SUFFIX_s32)) +FUNCTION (svldff1ub, svldxf1_extend_impl, (TYPE_SUFFIX_u8, UNSPEC_LDFF1)) +FUNCTION (svldff1ub_gather, svldff1_gather_extend, (TYPE_SUFFIX_u8)) +FUNCTION (svldff1uh, svldxf1_extend_impl, (TYPE_SUFFIX_u16, UNSPEC_LDFF1)) +FUNCTION (svldff1uh_gather, svldff1_gather_extend, (TYPE_SUFFIX_u16)) +FUNCTION (svldff1uw, svldxf1_extend_impl, (TYPE_SUFFIX_u32, UNSPEC_LDFF1)) +FUNCTION (svldff1uw_gather, svldff1_gather_extend, (TYPE_SUFFIX_u32)) +FUNCTION (svldnf1, svldxf1_impl, (UNSPEC_LDNF1)) +FUNCTION (svldnf1sb, svldxf1_extend_impl, (TYPE_SUFFIX_s8, UNSPEC_LDNF1)) +FUNCTION (svldnf1sh, svldxf1_extend_impl, (TYPE_SUFFIX_s16, UNSPEC_LDNF1)) +FUNCTION (svldnf1sw, svldxf1_extend_impl, (TYPE_SUFFIX_s32, UNSPEC_LDNF1)) +FUNCTION (svldnf1ub, svldxf1_extend_impl, (TYPE_SUFFIX_u8, UNSPEC_LDNF1)) +FUNCTION (svldnf1uh, svldxf1_extend_impl, (TYPE_SUFFIX_u16, UNSPEC_LDNF1)) +FUNCTION (svldnf1uw, svldxf1_extend_impl, (TYPE_SUFFIX_u32, UNSPEC_LDNF1)) +FUNCTION (svldnt1, svldnt1_impl,) +FUNCTION (svlen, svlen_impl,) +FUNCTION (svlsl, rtx_code_function, (ASHIFT, ASHIFT)) +FUNCTION (svlsl_wide, shift_wide, (ASHIFT, UNSPEC_ASHIFT_WIDE)) +FUNCTION (svlsr, rtx_code_function, (LSHIFTRT, LSHIFTRT)) +FUNCTION (svlsr_wide, shift_wide, (LSHIFTRT, UNSPEC_LSHIFTRT_WIDE)) +FUNCTION (svmad, svmad_impl,) +FUNCTION (svmax, rtx_code_function, (SMAX, UMAX, UNSPEC_COND_FMAX)) +FUNCTION (svmaxnm, unspec_based_function, (-1, -1, UNSPEC_COND_FMAXNM)) +FUNCTION (svmaxnmv, reduction, (UNSPEC_FMAXNMV)) +FUNCTION (svmaxv, reduction, (UNSPEC_SMAXV, UNSPEC_UMAXV, UNSPEC_FMAXV)) +FUNCTION (svmin, rtx_code_function, (SMIN, UMIN, UNSPEC_COND_FMIN)) +FUNCTION (svminnm, unspec_based_function, (-1, -1, UNSPEC_COND_FMINNM)) +FUNCTION (svminnmv, reduction, (UNSPEC_FMINNMV)) +FUNCTION (svminv, reduction, (UNSPEC_SMINV, UNSPEC_UMINV, UNSPEC_FMINV)) +FUNCTION (svmla, svmla_impl,) +FUNCTION (svmla_lane, svmla_svmls_lane_impl, (UNSPEC_FMLA)) +FUNCTION (svmls, svmls_impl,) +FUNCTION (svmls_lane, svmla_svmls_lane_impl, (UNSPEC_FMLS)) +FUNCTION (svmov, svmov_impl,) +FUNCTION (svmsb, svmsb_impl,) +FUNCTION (svmul, rtx_code_function, (MULT, MULT, UNSPEC_COND_FMUL)) +FUNCTION (svmul_lane, svmul_lane_impl,) +FUNCTION (svmulh, unspec_based_function, (UNSPEC_SMUL_HIGHPART, + UNSPEC_UMUL_HIGHPART, -1)) +FUNCTION (svmulx, unspec_based_function, (-1, -1, UNSPEC_COND_FMULX)) +FUNCTION (svnand, svnand_impl,) +FUNCTION (svneg, quiet<rtx_code_function>, (NEG, NEG, UNSPEC_COND_FNEG)) +FUNCTION (svnmad, unspec_based_function, (-1, -1, UNSPEC_COND_FNMLA)) +FUNCTION (svnmla, unspec_based_function_rotated, (-1, -1, UNSPEC_COND_FNMLA)) +FUNCTION (svnmls, unspec_based_function_rotated, (-1, -1, UNSPEC_COND_FNMLS)) +FUNCTION (svnmsb, unspec_based_function, (-1, -1, UNSPEC_COND_FNMLS)) +FUNCTION (svnor, svnor_impl,) +FUNCTION (svnot, svnot_impl,) +FUNCTION (svorn, svorn_impl,) +FUNCTION (svorr, rtx_code_function, (IOR, IOR)) +FUNCTION (svorv, reduction, (UNSPEC_IORV)) +FUNCTION (svpfalse, svpfalse_impl,) +FUNCTION (svpfirst, svpfirst_svpnext_impl, (UNSPEC_PFIRST)) +FUNCTION (svpnext, svpfirst_svpnext_impl, (UNSPEC_PNEXT)) +FUNCTION (svprfb, svprf_bhwd_impl, (VNx16QImode)) +FUNCTION (svprfb_gather, svprf_bhwd_gather_impl, (VNx16QImode)) +FUNCTION (svprfd, svprf_bhwd_impl, (VNx2DImode)) +FUNCTION (svprfd_gather, svprf_bhwd_gather_impl, (VNx2DImode)) +FUNCTION (svprfh, svprf_bhwd_impl, (VNx8HImode)) +FUNCTION (svprfh_gather, svprf_bhwd_gather_impl, (VNx8HImode)) +FUNCTION (svprfw, svprf_bhwd_impl, (VNx4SImode)) +FUNCTION (svprfw_gather, svprf_bhwd_gather_impl, (VNx4SImode)) +FUNCTION (svptest_any, svptest_impl, (NE)) +FUNCTION (svptest_first, svptest_impl, (LT)) +FUNCTION (svptest_last, svptest_impl, (LTU)) +FUNCTION (svptrue, svptrue_impl,) +FUNCTION (svptrue_pat, svptrue_pat_impl,) +FUNCTION (svqadd, svqadd_impl,) +FUNCTION (svqdecb, svqdec_bhwd_impl, (QImode)) +FUNCTION (svqdecb_pat, svqdec_bhwd_impl, (QImode)) +FUNCTION (svqdecd, svqdec_bhwd_impl, (DImode)) +FUNCTION (svqdecd_pat, svqdec_bhwd_impl, (DImode)) +FUNCTION (svqdech, svqdec_bhwd_impl, (HImode)) +FUNCTION (svqdech_pat, svqdec_bhwd_impl, (HImode)) +FUNCTION (svqdecp, svqdecp_svqincp_impl, (SS_MINUS, US_MINUS)) +FUNCTION (svqdecw, svqdec_bhwd_impl, (SImode)) +FUNCTION (svqdecw_pat, svqdec_bhwd_impl, (SImode)) +FUNCTION (svqincb, svqinc_bhwd_impl, (QImode)) +FUNCTION (svqincb_pat, svqinc_bhwd_impl, (QImode)) +FUNCTION (svqincd, svqinc_bhwd_impl, (DImode)) +FUNCTION (svqincd_pat, svqinc_bhwd_impl, (DImode)) +FUNCTION (svqinch, svqinc_bhwd_impl, (HImode)) +FUNCTION (svqinch_pat, svqinc_bhwd_impl, (HImode)) +FUNCTION (svqincp, svqdecp_svqincp_impl, (SS_PLUS, US_PLUS)) +FUNCTION (svqincw, svqinc_bhwd_impl, (SImode)) +FUNCTION (svqincw_pat, svqinc_bhwd_impl, (SImode)) +FUNCTION (svqsub, svqsub_impl,) +FUNCTION (svrbit, unspec_based_function, (UNSPEC_RBIT, UNSPEC_RBIT, -1)) +FUNCTION (svrdffr, svrdffr_impl,) +FUNCTION (svrecpe, unspec_based_function, (-1, -1, UNSPEC_FRECPE)) +FUNCTION (svrecps, unspec_based_function, (-1, -1, UNSPEC_FRECPS)) +FUNCTION (svrecpx, unspec_based_function, (-1, -1, UNSPEC_COND_FRECPX)) +FUNCTION (svreinterpret, svreinterpret_impl,) +FUNCTION (svrev, svrev_impl,) +FUNCTION (svrevb, unspec_based_function, (UNSPEC_REVB, UNSPEC_REVB, -1)) +FUNCTION (svrevh, unspec_based_function, (UNSPEC_REVH, UNSPEC_REVH, -1)) +FUNCTION (svrevw, unspec_based_function, (UNSPEC_REVW, UNSPEC_REVW, -1)) +FUNCTION (svrinta, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTA)) +FUNCTION (svrinti, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTI)) +FUNCTION (svrintm, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTM)) +FUNCTION (svrintn, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTN)) +FUNCTION (svrintp, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTP)) +FUNCTION (svrintx, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTX)) +FUNCTION (svrintz, unspec_based_function, (-1, -1, UNSPEC_COND_FRINTZ)) +FUNCTION (svrsqrte, unspec_based_function, (-1, -1, UNSPEC_RSQRTE)) +FUNCTION (svrsqrts, unspec_based_function, (-1, -1, UNSPEC_RSQRTS)) +FUNCTION (svscale, unspec_based_function, (-1, -1, UNSPEC_COND_FSCALE)) +FUNCTION (svsel, svsel_impl,) +FUNCTION (svset2, svset_impl, (2)) +FUNCTION (svset3, svset_impl, (3)) +FUNCTION (svset4, svset_impl, (4)) +FUNCTION (svsetffr, svsetffr_impl,) +FUNCTION (svsplice, svsplice_impl,) +FUNCTION (svsqrt, rtx_code_function, (SQRT, SQRT, UNSPEC_COND_FSQRT)) +FUNCTION (svst1, svst1_impl,) +FUNCTION (svst1_scatter, svst1_scatter_impl,) +FUNCTION (svst1b, svst1_truncate_impl, (QImode)) +FUNCTION (svst1b_scatter, svst1_scatter_truncate_impl, (QImode)) +FUNCTION (svst1h, svst1_truncate_impl, (HImode)) +FUNCTION (svst1h_scatter, svst1_scatter_truncate_impl, (HImode)) +FUNCTION (svst1w, svst1_truncate_impl, (SImode)) +FUNCTION (svst1w_scatter, svst1_scatter_truncate_impl, (SImode)) +FUNCTION (svst2, svst234_impl, (2)) +FUNCTION (svst3, svst234_impl, (3)) +FUNCTION (svst4, svst234_impl, (4)) +FUNCTION (svstnt1, svstnt1_impl,) +FUNCTION (svsub, svsub_impl,) +FUNCTION (svsubr, rtx_code_function_rotated, (MINUS, MINUS, UNSPEC_COND_FSUB)) +FUNCTION (svtbl, svtbl_impl,) +FUNCTION (svtmad, svtmad_impl,) +FUNCTION (svtrn1, svtrn_impl, (0)) +FUNCTION (svtrn2, svtrn_impl, (1)) +FUNCTION (svtsmul, unspec_based_function, (-1, -1, UNSPEC_FTSMUL)) +FUNCTION (svtssel, unspec_based_function, (-1, -1, UNSPEC_FTSSEL)) +FUNCTION (svundef, svundef_impl, (1)) +FUNCTION (svundef2, svundef_impl, (2)) +FUNCTION (svundef3, svundef_impl, (3)) +FUNCTION (svundef4, svundef_impl, (4)) +FUNCTION (svunpkhi, svunpk_impl, (true)) +FUNCTION (svunpklo, svunpk_impl, (false)) +FUNCTION (svuzp1, svuzp_impl, (0)) +FUNCTION (svuzp2, svuzp_impl, (1)) +FUNCTION (svwhilele, svwhile_impl, (UNSPEC_WHILE_LE, UNSPEC_WHILE_LS, true)) +FUNCTION (svwhilelt, svwhile_impl, (UNSPEC_WHILE_LT, UNSPEC_WHILE_LO, false)) +FUNCTION (svwrffr, svwrffr_impl,) +FUNCTION (svzip1, svzip_impl, (0)) +FUNCTION (svzip2, svzip_impl, (1)) + +} /* end namespace aarch64_sve */ diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.def b/gcc/config/aarch64/aarch64-sve-builtins-base.def new file mode 100644 index 0000000..a678ee8 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.def @@ -0,0 +1,318 @@ +/* ACLE support for AArch64 SVE (__ARM_FEATURE_SVE intrinsics) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#define REQUIRED_EXTENSIONS 0 +DEF_SVE_FUNCTION (svabd, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svabs, unary, all_float_and_signed, mxz) +DEF_SVE_FUNCTION (svacge, compare_opt_n, all_float, implicit) +DEF_SVE_FUNCTION (svacgt, compare_opt_n, all_float, implicit) +DEF_SVE_FUNCTION (svacle, compare_opt_n, all_float, implicit) +DEF_SVE_FUNCTION (svaclt, compare_opt_n, all_float, implicit) +DEF_SVE_FUNCTION (svadd, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svadda, fold_left, all_float, implicit) +DEF_SVE_FUNCTION (svaddv, reduction_wide, all_data, implicit) +DEF_SVE_FUNCTION (svadrb, adr_offset, none, none) +DEF_SVE_FUNCTION (svadrd, adr_index, none, none) +DEF_SVE_FUNCTION (svadrh, adr_index, none, none) +DEF_SVE_FUNCTION (svadrw, adr_index, none, none) +DEF_SVE_FUNCTION (svand, binary_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (svand, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svandv, reduction, all_integer, implicit) +DEF_SVE_FUNCTION (svasr, binary_uint_opt_n, all_signed, mxz) +DEF_SVE_FUNCTION (svasr_wide, binary_uint64_opt_n, bhs_signed, mxz) +DEF_SVE_FUNCTION (svasrd, shift_right_imm, all_signed, mxz) +DEF_SVE_FUNCTION (svbic, binary_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (svbic, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svbrka, unary, b, mz) +DEF_SVE_FUNCTION (svbrkb, unary, b, mz) +DEF_SVE_FUNCTION (svbrkn, binary, b, z) +DEF_SVE_FUNCTION (svbrkpa, binary, b, z) +DEF_SVE_FUNCTION (svbrkpb, binary, b, z) +DEF_SVE_FUNCTION (svcadd, binary_rotate, all_float, mxz) +DEF_SVE_FUNCTION (svclasta, clast, all_data, implicit) +DEF_SVE_FUNCTION (svclastb, clast, all_data, implicit) +DEF_SVE_FUNCTION (svcls, unary_count, all_signed, mxz) +DEF_SVE_FUNCTION (svclz, unary_count, all_integer, mxz) +DEF_SVE_FUNCTION (svcmla, ternary_rotate, all_float, mxz) +DEF_SVE_FUNCTION (svcmla_lane, ternary_lane_rotate, hs_float, none) +DEF_SVE_FUNCTION (svcmpeq, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmpeq_wide, compare_wide_opt_n, bhs_signed, implicit) +DEF_SVE_FUNCTION (svcmpge, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmpge_wide, compare_wide_opt_n, bhs_integer, implicit) +DEF_SVE_FUNCTION (svcmpgt, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmpgt_wide, compare_wide_opt_n, bhs_integer, implicit) +DEF_SVE_FUNCTION (svcmple, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmple_wide, compare_wide_opt_n, bhs_integer, implicit) +DEF_SVE_FUNCTION (svcmplt, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmplt_wide, compare_wide_opt_n, bhs_integer, implicit) +DEF_SVE_FUNCTION (svcmpne, compare_opt_n, all_data, implicit) +DEF_SVE_FUNCTION (svcmpne_wide, compare_wide_opt_n, bhs_signed, implicit) +DEF_SVE_FUNCTION (svcmpuo, compare_opt_n, all_float, implicit) +DEF_SVE_FUNCTION (svcnot, unary, all_integer, mxz) +DEF_SVE_FUNCTION (svcnt, unary_count, all_data, mxz) +DEF_SVE_FUNCTION (svcntb, count_inherent, none, none) +DEF_SVE_FUNCTION (svcntb_pat, count_pat, none, none) +DEF_SVE_FUNCTION (svcntd, count_inherent, none, none) +DEF_SVE_FUNCTION (svcntd_pat, count_pat, none, none) +DEF_SVE_FUNCTION (svcnth, count_inherent, none, none) +DEF_SVE_FUNCTION (svcnth_pat, count_pat, none, none) +DEF_SVE_FUNCTION (svcntp, count_pred, all_pred, implicit) +DEF_SVE_FUNCTION (svcntw, count_inherent, none, none) +DEF_SVE_FUNCTION (svcntw_pat, count_pat, none, none) +DEF_SVE_FUNCTION (svcompact, unary, sd_data, implicit) +DEF_SVE_FUNCTION (svcreate2, create, all_data, none) +DEF_SVE_FUNCTION (svcreate3, create, all_data, none) +DEF_SVE_FUNCTION (svcreate4, create, all_data, none) +DEF_SVE_FUNCTION (svcvt, unary_convert, cvt, mxz) +DEF_SVE_FUNCTION (svdiv, binary_opt_n, all_float_and_sd_integer, mxz) +DEF_SVE_FUNCTION (svdivr, binary_opt_n, all_float_and_sd_integer, mxz) +DEF_SVE_FUNCTION (svdot, ternary_qq_opt_n, sd_integer, none) +DEF_SVE_FUNCTION (svdot_lane, ternary_qq_lane, sd_integer, none) +DEF_SVE_FUNCTION (svdup, unary_n, all_data, mxz_or_none) +DEF_SVE_FUNCTION (svdup, unary_n, all_pred, none) +DEF_SVE_FUNCTION (svdup_lane, binary_uint_n, all_data, none) +DEF_SVE_FUNCTION (svdupq, dupq, all_data, none) +DEF_SVE_FUNCTION (svdupq, dupq, all_pred, none) +DEF_SVE_FUNCTION (svdupq_lane, binary_uint64_n, all_data, none) +DEF_SVE_FUNCTION (sveor, binary_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (sveor, binary_opt_n, b, z) +DEF_SVE_FUNCTION (sveorv, reduction, all_integer, implicit) +DEF_SVE_FUNCTION (svexpa, unary_uint, all_float, none) +DEF_SVE_FUNCTION (svext, ext, all_data, none) +DEF_SVE_FUNCTION (svextb, unary, hsd_integer, mxz) +DEF_SVE_FUNCTION (svexth, unary, sd_integer, mxz) +DEF_SVE_FUNCTION (svextw, unary, d_integer, mxz) +DEF_SVE_FUNCTION (svget2, get, all_data, none) +DEF_SVE_FUNCTION (svget3, get, all_data, none) +DEF_SVE_FUNCTION (svget4, get, all_data, none) +DEF_SVE_FUNCTION (svindex, binary_scalar, all_integer, none) +DEF_SVE_FUNCTION (svinsr, binary_n, all_data, none) +DEF_SVE_FUNCTION (svlasta, reduction, all_data, implicit) +DEF_SVE_FUNCTION (svlastb, reduction, all_data, implicit) +DEF_SVE_FUNCTION (svld1, load, all_data, implicit) +DEF_SVE_FUNCTION (svld1_gather, load_gather_sv, sd_data, implicit) +DEF_SVE_FUNCTION (svld1_gather, load_gather_vs, sd_data, implicit) +DEF_SVE_FUNCTION (svld1rq, load_replicate, all_data, implicit) +DEF_SVE_FUNCTION (svld1sb, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svld1sb_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1sh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1sh_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1sh_gather, load_ext_gather_index, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1sw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svld1sw_gather, load_ext_gather_offset, d_integer, implicit) +DEF_SVE_FUNCTION (svld1sw_gather, load_ext_gather_index, d_integer, implicit) +DEF_SVE_FUNCTION (svld1ub, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svld1ub_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1uh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1uh_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1uh_gather, load_ext_gather_index, sd_integer, implicit) +DEF_SVE_FUNCTION (svld1uw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svld1uw_gather, load_ext_gather_offset, d_integer, implicit) +DEF_SVE_FUNCTION (svld1uw_gather, load_ext_gather_index, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1, load, all_data, implicit) +DEF_SVE_FUNCTION (svldff1_gather, load_gather_sv, sd_data, implicit) +DEF_SVE_FUNCTION (svldff1_gather, load_gather_vs, sd_data, implicit) +DEF_SVE_FUNCTION (svldff1sb, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svldff1sb_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1sh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1sh_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1sh_gather, load_ext_gather_index, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1sw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1sw_gather, load_ext_gather_offset, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1sw_gather, load_ext_gather_index, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1ub, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svldff1ub_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1uh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1uh_gather, load_ext_gather_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1uh_gather, load_ext_gather_index, sd_integer, implicit) +DEF_SVE_FUNCTION (svldff1uw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1uw_gather, load_ext_gather_offset, d_integer, implicit) +DEF_SVE_FUNCTION (svldff1uw_gather, load_ext_gather_index, d_integer, implicit) +DEF_SVE_FUNCTION (svldnf1, load, all_data, implicit) +DEF_SVE_FUNCTION (svldnf1sb, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svldnf1sh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svldnf1sw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svldnf1ub, load_ext, hsd_integer, implicit) +DEF_SVE_FUNCTION (svldnf1uh, load_ext, sd_integer, implicit) +DEF_SVE_FUNCTION (svldnf1uw, load_ext, d_integer, implicit) +DEF_SVE_FUNCTION (svldnt1, load, all_data, implicit) +DEF_SVE_FUNCTION (svld2, load, all_data, implicit) +DEF_SVE_FUNCTION (svld3, load, all_data, implicit) +DEF_SVE_FUNCTION (svld4, load, all_data, implicit) +DEF_SVE_FUNCTION (svlen, count_vector, all_data, none) +DEF_SVE_FUNCTION (svlsl, binary_uint_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (svlsl_wide, binary_uint64_opt_n, bhs_integer, mxz) +DEF_SVE_FUNCTION (svlsr, binary_uint_opt_n, all_unsigned, mxz) +DEF_SVE_FUNCTION (svlsr_wide, binary_uint64_opt_n, bhs_unsigned, mxz) +DEF_SVE_FUNCTION (svmad, ternary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmax, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmaxnm, binary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svmaxnmv, reduction, all_float, implicit) +DEF_SVE_FUNCTION (svmaxv, reduction, all_data, implicit) +DEF_SVE_FUNCTION (svmin, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svminnm, binary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svminnmv, reduction, all_float, implicit) +DEF_SVE_FUNCTION (svminv, reduction, all_data, implicit) +DEF_SVE_FUNCTION (svmla, ternary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmla_lane, ternary_lane, all_float, none) +DEF_SVE_FUNCTION (svmls, ternary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmls_lane, ternary_lane, all_float, none) +DEF_SVE_FUNCTION (svmov, unary, b, z) +DEF_SVE_FUNCTION (svmsb, ternary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmul, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svmul_lane, binary_lane, all_float, none) +DEF_SVE_FUNCTION (svmulh, binary_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (svmulx, binary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svnand, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svneg, unary, all_float_and_signed, mxz) +DEF_SVE_FUNCTION (svnmad, ternary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svnmla, ternary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svnmls, ternary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svnmsb, ternary_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svnor, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svnot, unary, all_integer, mxz) +DEF_SVE_FUNCTION (svnot, unary, b, z) +DEF_SVE_FUNCTION (svorn, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svorr, binary_opt_n, all_integer, mxz) +DEF_SVE_FUNCTION (svorr, binary_opt_n, b, z) +DEF_SVE_FUNCTION (svorv, reduction, all_integer, implicit) +DEF_SVE_FUNCTION (svpfalse, inherent_b, b, none) +DEF_SVE_FUNCTION (svpfirst, unary, b, implicit) +DEF_SVE_FUNCTION (svpnext, unary_pred, all_pred, implicit) +DEF_SVE_FUNCTION (svprfb, prefetch, none, implicit) +DEF_SVE_FUNCTION (svprfb_gather, prefetch_gather_offset, none, implicit) +DEF_SVE_FUNCTION (svprfd, prefetch, none, implicit) +DEF_SVE_FUNCTION (svprfd_gather, prefetch_gather_index, none, implicit) +DEF_SVE_FUNCTION (svprfh, prefetch, none, implicit) +DEF_SVE_FUNCTION (svprfh_gather, prefetch_gather_index, none, implicit) +DEF_SVE_FUNCTION (svprfw, prefetch, none, implicit) +DEF_SVE_FUNCTION (svprfw_gather, prefetch_gather_index, none, implicit) +DEF_SVE_FUNCTION (svptest_any, ptest, none, implicit) +DEF_SVE_FUNCTION (svptest_first, ptest, none, implicit) +DEF_SVE_FUNCTION (svptest_last, ptest, none, implicit) +DEF_SVE_FUNCTION (svptrue, inherent, all_pred, none) +DEF_SVE_FUNCTION (svptrue_pat, pattern_pred, all_pred, none) +DEF_SVE_FUNCTION (svqadd, binary_opt_n, all_integer, none) +DEF_SVE_FUNCTION (svqdecb, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqdecb_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqdecd, inc_dec, d_integer, none) +DEF_SVE_FUNCTION (svqdecd, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqdecd_pat, inc_dec_pat, d_integer, none) +DEF_SVE_FUNCTION (svqdecd_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqdech, inc_dec, h_integer, none) +DEF_SVE_FUNCTION (svqdech, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqdech_pat, inc_dec_pat, h_integer, none) +DEF_SVE_FUNCTION (svqdech_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqdecp, inc_dec_pred, hsd_integer, none) +DEF_SVE_FUNCTION (svqdecp, inc_dec_pred_scalar, inc_dec_n, none) +DEF_SVE_FUNCTION (svqdecw, inc_dec, s_integer, none) +DEF_SVE_FUNCTION (svqdecw, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqdecw_pat, inc_dec_pat, s_integer, none) +DEF_SVE_FUNCTION (svqdecw_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqincb, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqincb_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqincd, inc_dec, d_integer, none) +DEF_SVE_FUNCTION (svqincd, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqincd_pat, inc_dec_pat, d_integer, none) +DEF_SVE_FUNCTION (svqincd_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqinch, inc_dec, h_integer, none) +DEF_SVE_FUNCTION (svqinch, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqinch_pat, inc_dec_pat, h_integer, none) +DEF_SVE_FUNCTION (svqinch_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqincp, inc_dec_pred, hsd_integer, none) +DEF_SVE_FUNCTION (svqincp, inc_dec_pred_scalar, inc_dec_n, none) +DEF_SVE_FUNCTION (svqincw, inc_dec, s_integer, none) +DEF_SVE_FUNCTION (svqincw, inc_dec, sd_integer, none) +DEF_SVE_FUNCTION (svqincw_pat, inc_dec_pat, s_integer, none) +DEF_SVE_FUNCTION (svqincw_pat, inc_dec_pat, sd_integer, none) +DEF_SVE_FUNCTION (svqsub, binary_opt_n, all_integer, none) +DEF_SVE_FUNCTION (svrbit, unary, all_integer, mxz) +DEF_SVE_FUNCTION (svrdffr, rdffr, none, z_or_none) +DEF_SVE_FUNCTION (svrecpe, unary, all_float, none) +DEF_SVE_FUNCTION (svrecps, binary, all_float, none) +DEF_SVE_FUNCTION (svrecpx, unary, all_float, mxz) +DEF_SVE_FUNCTION (svreinterpret, unary_convert, reinterpret, none) +DEF_SVE_FUNCTION (svrev, unary, all_data, none) +DEF_SVE_FUNCTION (svrev, unary_pred, all_pred, none) +DEF_SVE_FUNCTION (svrevb, unary, hsd_integer, mxz) +DEF_SVE_FUNCTION (svrevh, unary, sd_integer, mxz) +DEF_SVE_FUNCTION (svrevw, unary, d_integer, mxz) +DEF_SVE_FUNCTION (svrinta, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrinti, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrintm, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrintn, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrintp, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrintx, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrintz, unary, all_float, mxz) +DEF_SVE_FUNCTION (svrsqrte, unary, all_float, none) +DEF_SVE_FUNCTION (svrsqrts, binary, all_float, none) +DEF_SVE_FUNCTION (svscale, binary_int_opt_n, all_float, mxz) +DEF_SVE_FUNCTION (svsel, binary, all_data, implicit) +DEF_SVE_FUNCTION (svsel, binary, b, implicit) +DEF_SVE_FUNCTION (svset2, set, all_data, none) +DEF_SVE_FUNCTION (svset3, set, all_data, none) +DEF_SVE_FUNCTION (svset4, set, all_data, none) +DEF_SVE_FUNCTION (svsetffr, setffr, none, none) +DEF_SVE_FUNCTION (svsplice, binary, all_data, implicit) +DEF_SVE_FUNCTION (svsqrt, unary, all_float, mxz) +DEF_SVE_FUNCTION (svst1, store, all_data, implicit) +DEF_SVE_FUNCTION (svst1_scatter, store_scatter_index, sd_data, implicit) +DEF_SVE_FUNCTION (svst1_scatter, store_scatter_offset, sd_data, implicit) +DEF_SVE_FUNCTION (svst1b, store, hsd_integer, implicit) +DEF_SVE_FUNCTION (svst1b_scatter, store_scatter_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svst1h, store, sd_integer, implicit) +DEF_SVE_FUNCTION (svst1h_scatter, store_scatter_index, sd_integer, implicit) +DEF_SVE_FUNCTION (svst1h_scatter, store_scatter_offset, sd_integer, implicit) +DEF_SVE_FUNCTION (svst1w, store, d_integer, implicit) +DEF_SVE_FUNCTION (svst1w_scatter, store_scatter_index, d_integer, implicit) +DEF_SVE_FUNCTION (svst1w_scatter, store_scatter_offset, d_integer, implicit) +DEF_SVE_FUNCTION (svst2, store, all_data, implicit) +DEF_SVE_FUNCTION (svst3, store, all_data, implicit) +DEF_SVE_FUNCTION (svst4, store, all_data, implicit) +DEF_SVE_FUNCTION (svstnt1, store, all_data, implicit) +DEF_SVE_FUNCTION (svsub, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svsubr, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svtbl, binary_uint, all_data, none) +DEF_SVE_FUNCTION (svtmad, tmad, all_float, none) +DEF_SVE_FUNCTION (svtrn1, binary, all_data, none) +DEF_SVE_FUNCTION (svtrn1, binary_pred, all_pred, none) +DEF_SVE_FUNCTION (svtrn2, binary, all_data, none) +DEF_SVE_FUNCTION (svtrn2, binary_pred, all_pred, none) +DEF_SVE_FUNCTION (svtsmul, binary_uint, all_float, none) +DEF_SVE_FUNCTION (svtssel, binary_uint, all_float, none) +DEF_SVE_FUNCTION (svundef, inherent, all_data, none) +DEF_SVE_FUNCTION (svundef2, inherent, all_data, none) +DEF_SVE_FUNCTION (svundef3, inherent, all_data, none) +DEF_SVE_FUNCTION (svundef4, inherent, all_data, none) +DEF_SVE_FUNCTION (svunpkhi, unary_widen, hsd_integer, none) +DEF_SVE_FUNCTION (svunpkhi, unary_widen, b, none) +DEF_SVE_FUNCTION (svunpklo, unary_widen, hsd_integer, none) +DEF_SVE_FUNCTION (svunpklo, unary_widen, b, none) +DEF_SVE_FUNCTION (svuzp1, binary, all_data, none) +DEF_SVE_FUNCTION (svuzp1, binary_pred, all_pred, none) +DEF_SVE_FUNCTION (svuzp2, binary, all_data, none) +DEF_SVE_FUNCTION (svuzp2, binary_pred, all_pred, none) +DEF_SVE_FUNCTION (svwhilele, compare_scalar, while, none) +DEF_SVE_FUNCTION (svwhilelt, compare_scalar, while, none) +DEF_SVE_FUNCTION (svwrffr, setffr, none, implicit) +DEF_SVE_FUNCTION (svzip1, binary, all_data, none) +DEF_SVE_FUNCTION (svzip1, binary_pred, all_pred, none) +DEF_SVE_FUNCTION (svzip2, binary, all_data, none) +DEF_SVE_FUNCTION (svzip2, binary_pred, all_pred, none) +#undef REQUIRED_EXTENSIONS diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.h b/gcc/config/aarch64/aarch64-sve-builtins-base.h new file mode 100644 index 0000000..41ab12f --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.h @@ -0,0 +1,283 @@ +/* ACLE support for AArch64 SVE (__ARM_FEATURE_SVE intrinsics) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_AARCH64_SVE_BUILTINS_BASE_H +#define GCC_AARCH64_SVE_BUILTINS_BASE_H + +namespace aarch64_sve +{ + namespace functions + { + extern const function_base *const svabd; + extern const function_base *const svabs; + extern const function_base *const svacge; + extern const function_base *const svacgt; + extern const function_base *const svacle; + extern const function_base *const svaclt; + extern const function_base *const svadd; + extern const function_base *const svadda; + extern const function_base *const svaddv; + extern const function_base *const svadrb; + extern const function_base *const svadrd; + extern const function_base *const svadrh; + extern const function_base *const svadrw; + extern const function_base *const svand; + extern const function_base *const svandv; + extern const function_base *const svasr; + extern const function_base *const svasr_wide; + extern const function_base *const svasrd; + extern const function_base *const svbic; + extern const function_base *const svbrka; + extern const function_base *const svbrkb; + extern const function_base *const svbrkn; + extern const function_base *const svbrkpa; + extern const function_base *const svbrkpb; + extern const function_base *const svcadd; + extern const function_base *const svclasta; + extern const function_base *const svclastb; + extern const function_base *const svcls; + extern const function_base *const svclz; + extern const function_base *const svcmla; + extern const function_base *const svcmla_lane; + extern const function_base *const svcmpeq; + extern const function_base *const svcmpeq_wide; + extern const function_base *const svcmpge; + extern const function_base *const svcmpge_wide; + extern const function_base *const svcmpgt; + extern const function_base *const svcmpgt_wide; + extern const function_base *const svcmple; + extern const function_base *const svcmple_wide; + extern const function_base *const svcmplt; + extern const function_base *const svcmplt_wide; + extern const function_base *const svcmpne; + extern const function_base *const svcmpne_wide; + extern const function_base *const svcmpuo; + extern const function_base *const svcnot; + extern const function_base *const svcnt; + extern const function_base *const svcntb; + extern const function_base *const svcntb_pat; + extern const function_base *const svcntd; + extern const function_base *const svcntd_pat; + extern const function_base *const svcnth; + extern const function_base *const svcnth_pat; + extern const function_base *const svcntp; + extern const function_base *const svcntw; + extern const function_base *const svcntw_pat; + extern const function_base *const svcompact; + extern const function_base *const svcreate2; + extern const function_base *const svcreate3; + extern const function_base *const svcreate4; + extern const function_base *const svcvt; + extern const function_base *const svdiv; + extern const function_base *const svdivr; + extern const function_base *const svdot; + extern const function_base *const svdot_lane; + extern const function_base *const svdup; + extern const function_base *const svdup_lane; + extern const function_base *const svdupq; + extern const function_base *const svdupq_lane; + extern const function_base *const sveor; + extern const function_base *const sveorv; + extern const function_base *const svexpa; + extern const function_base *const svext; + extern const function_base *const svextb; + extern const function_base *const svexth; + extern const function_base *const svextw; + extern const function_base *const svget2; + extern const function_base *const svget3; + extern const function_base *const svget4; + extern const function_base *const svindex; + extern const function_base *const svinsr; + extern const function_base *const svlasta; + extern const function_base *const svlastb; + extern const function_base *const svld1; + extern const function_base *const svld1_gather; + extern const function_base *const svld1rq; + extern const function_base *const svld1sb; + extern const function_base *const svld1sb_gather; + extern const function_base *const svld1sh; + extern const function_base *const svld1sh_gather; + extern const function_base *const svld1sw; + extern const function_base *const svld1sw_gather; + extern const function_base *const svld1ub; + extern const function_base *const svld1ub_gather; + extern const function_base *const svld1uh; + extern const function_base *const svld1uh_gather; + extern const function_base *const svld1uw; + extern const function_base *const svld1uw_gather; + extern const function_base *const svld2; + extern const function_base *const svld3; + extern const function_base *const svld4; + extern const function_base *const svldff1; + extern const function_base *const svldff1_gather; + extern const function_base *const svldff1sb; + extern const function_base *const svldff1sb_gather; + extern const function_base *const svldff1sh; + extern const function_base *const svldff1sh_gather; + extern const function_base *const svldff1sw; + extern const function_base *const svldff1sw_gather; + extern const function_base *const svldff1ub; + extern const function_base *const svldff1ub_gather; + extern const function_base *const svldff1uh; + extern const function_base *const svldff1uh_gather; + extern const function_base *const svldff1uw; + extern const function_base *const svldff1uw_gather; + extern const function_base *const svldnf1; + extern const function_base *const svldnf1sb; + extern const function_base *const svldnf1sh; + extern const function_base *const svldnf1sw; + extern const function_base *const svldnf1ub; + extern const function_base *const svldnf1uh; + extern const function_base *const svldnf1uw; + extern const function_base *const svldnt1; + extern const function_base *const svlen; + extern const function_base *const svlsl; + extern const function_base *const svlsl_wide; + extern const function_base *const svlsr; + extern const function_base *const svlsr_wide; + extern const function_base *const svmad; + extern const function_base *const svmax; + extern const function_base *const svmaxnm; + extern const function_base *const svmaxnmv; + extern const function_base *const svmaxv; + extern const function_base *const svmin; + extern const function_base *const svminnm; + extern const function_base *const svminnmv; + extern const function_base *const svminv; + extern const function_base *const svmla; + extern const function_base *const svmla_lane; + extern const function_base *const svmls; + extern const function_base *const svmls_lane; + extern const function_base *const svmov; + extern const function_base *const svmsb; + extern const function_base *const svmul; + extern const function_base *const svmul_lane; + extern const function_base *const svmulh; + extern const function_base *const svmulx; + extern const function_base *const svnand; + extern const function_base *const svneg; + extern const function_base *const svnmad; + extern const function_base *const svnmla; + extern const function_base *const svnmls; + extern const function_base *const svnmsb; + extern const function_base *const svnor; + extern const function_base *const svnot; + extern const function_base *const svorn; + extern const function_base *const svorr; + extern const function_base *const svorv; + extern const function_base *const svpfalse; + extern const function_base *const svpfirst; + extern const function_base *const svpnext; + extern const function_base *const svprfb; + extern const function_base *const svprfb_gather; + extern const function_base *const svprfd; + extern const function_base *const svprfd_gather; + extern const function_base *const svprfh; + extern const function_base *const svprfh_gather; + extern const function_base *const svprfw; + extern const function_base *const svprfw_gather; + extern const function_base *const svptest_any; + extern const function_base *const svptest_first; + extern const function_base *const svptest_last; + extern const function_base *const svptrue; + extern const function_base *const svptrue_pat; + extern const function_base *const svqadd; + extern const function_base *const svqdecb; + extern const function_base *const svqdecb_pat; + extern const function_base *const svqdecd; + extern const function_base *const svqdecd_pat; + extern const function_base *const svqdech; + extern const function_base *const svqdech_pat; + extern const function_base *const svqdecp; + extern const function_base *const svqdecw; + extern const function_base *const svqdecw_pat; + extern const function_base *const svqincb; + extern const function_base *const svqincb_pat; + extern const function_base *const svqincd; + extern const function_base *const svqincd_pat; + extern const function_base *const svqinch; + extern const function_base *const svqinch_pat; + extern const function_base *const svqincp; + extern const function_base *const svqincw; + extern const function_base *const svqincw_pat; + extern const function_base *const svqsub; + extern const function_base *const svrbit; + extern const function_base *const svrdffr; + extern const function_base *const svrecpe; + extern const function_base *const svrecps; + extern const function_base *const svrecpx; + extern const function_base *const svreinterpret; + extern const function_base *const svrev; + extern const function_base *const svrevb; + extern const function_base *const svrevh; + extern const function_base *const svrevw; + extern const function_base *const svrinta; + extern const function_base *const svrinti; + extern const function_base *const svrintm; + extern const function_base *const svrintn; + extern const function_base *const svrintp; + extern const function_base *const svrintx; + extern const function_base *const svrintz; + extern const function_base *const svrsqrte; + extern const function_base *const svrsqrts; + extern const function_base *const svscale; + extern const function_base *const svsel; + extern const function_base *const svset2; + extern const function_base *const svset3; + extern const function_base *const svset4; + extern const function_base *const svsetffr; + extern const function_base *const svsplice; + extern const function_base *const svsqrt; + extern const function_base *const svst1; + extern const function_base *const svst1_scatter; + extern const function_base *const svst1b; + extern const function_base *const svst1b_scatter; + extern const function_base *const svst1h; + extern const function_base *const svst1h_scatter; + extern const function_base *const svst1w; + extern const function_base *const svst1w_scatter; + extern const function_base *const svst2; + extern const function_base *const svst3; + extern const function_base *const svst4; + extern const function_base *const svstnt1; + extern const function_base *const svsub; + extern const function_base *const svsubr; + extern const function_base *const svtbl; + extern const function_base *const svtmad; + extern const function_base *const svtrn1; + extern const function_base *const svtrn2; + extern const function_base *const svtsmul; + extern const function_base *const svtssel; + extern const function_base *const svundef; + extern const function_base *const svundef2; + extern const function_base *const svundef3; + extern const function_base *const svundef4; + extern const function_base *const svunpkhi; + extern const function_base *const svunpklo; + extern const function_base *const svuzp1; + extern const function_base *const svuzp2; + extern const function_base *const svwhilele; + extern const function_base *const svwhilelt; + extern const function_base *const svwrffr; + extern const function_base *const svzip1; + extern const function_base *const svzip2; + } +} + +#endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins-functions.h b/gcc/config/aarch64/aarch64-sve-builtins-functions.h new file mode 100644 index 0000000..0df7306 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-functions.h @@ -0,0 +1,444 @@ +/* ACLE support for AArch64 SVE (function_base classes) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_AARCH64_SVE_BUILTINS_FUNCTIONS_H +#define GCC_AARCH64_SVE_BUILTINS_FUNCTIONS_H + +namespace aarch64_sve { + +/* Wrap T, which is derived from function_base, and indicate that the + function never has side effects. It is only necessary to use this + wrapper on functions that might have floating-point suffixes, since + otherwise we assume by default that the function has no side effects. */ +template<typename T> +class quiet : public T +{ +public: + CONSTEXPR quiet () : T () {} + + /* Unfortunately we can't use parameter packs yet. */ + template<typename T1> + CONSTEXPR quiet (const T1 &t1) : T (t1) {} + + template<typename T1, typename T2> + CONSTEXPR quiet (const T1 &t1, const T2 &t2) : T (t1, t2) {} + + template<typename T1, typename T2, typename T3> + CONSTEXPR quiet (const T1 &t1, const T2 &t2, const T3 &t3) + : T (t1, t2, t3) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return 0; + } +}; + +/* A function_base that sometimes or always operates on tuples of + vectors. */ +class multi_vector_function : public function_base +{ +public: + CONSTEXPR multi_vector_function (unsigned int vectors_per_tuple) + : m_vectors_per_tuple (vectors_per_tuple) {} + + unsigned int + vectors_per_tuple () const OVERRIDE + { + return m_vectors_per_tuple; + } + + /* The number of vectors in a tuple, or 1 if the function only operates + on single vectors. */ + unsigned int m_vectors_per_tuple; +}; + +/* A function_base that loads or stores contiguous memory elements + without extending or truncating them. */ +class full_width_access : public multi_vector_function +{ +public: + CONSTEXPR full_width_access (unsigned int vectors_per_tuple = 1) + : multi_vector_function (vectors_per_tuple) {} + + tree + memory_scalar_type (const function_instance &fi) const OVERRIDE + { + return fi.scalar_type (0); + } + + machine_mode + memory_vector_mode (const function_instance &fi) const OVERRIDE + { + machine_mode mode = fi.vector_mode (0); + if (m_vectors_per_tuple != 1) + mode = targetm.array_mode (mode, m_vectors_per_tuple).require (); + return mode; + } +}; + +/* A function_base that loads elements from memory and extends them + to a wider element. The memory element type is a fixed part of + the function base name. */ +class extending_load : public function_base +{ +public: + CONSTEXPR extending_load (type_suffix_index memory_type) + : m_memory_type (memory_type) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_READ_MEMORY; + } + + tree + memory_scalar_type (const function_instance &) const OVERRIDE + { + return scalar_types[type_suffixes[m_memory_type].vector_type]; + } + + machine_mode + memory_vector_mode (const function_instance &fi) const OVERRIDE + { + machine_mode mem_mode = type_suffixes[m_memory_type].vector_mode; + machine_mode reg_mode = fi.vector_mode (0); + return aarch64_sve_data_mode (GET_MODE_INNER (mem_mode), + GET_MODE_NUNITS (reg_mode)).require (); + } + + /* Return the rtx code associated with the kind of extension that + the load performs. */ + rtx_code + extend_rtx_code () const + { + return (type_suffixes[m_memory_type].unsigned_p + ? ZERO_EXTEND : SIGN_EXTEND); + } + + /* The type of the memory elements. This is part of the function base + name rather than a true type suffix. */ + type_suffix_index m_memory_type; +}; + +/* A function_base that truncates vector elements and stores them to memory. + The memory element width is a fixed part of the function base name. */ +class truncating_store : public function_base +{ +public: + CONSTEXPR truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {} + + unsigned int + call_properties (const function_instance &) const OVERRIDE + { + return CP_WRITE_MEMORY; + } + + tree + memory_scalar_type (const function_instance &fi) const OVERRIDE + { + /* In truncating stores, the signedness of the memory element is defined + to be the same as the signedness of the vector element. The signedness + doesn't make any difference to the behavior of the function. */ + type_class_index tclass = fi.type_suffix (0).tclass; + unsigned int element_bits = GET_MODE_BITSIZE (m_to_mode); + type_suffix_index suffix = find_type_suffix (tclass, element_bits); + return scalar_types[type_suffixes[suffix].vector_type]; + } + + machine_mode + memory_vector_mode (const function_instance &fi) const OVERRIDE + { + poly_uint64 nunits = GET_MODE_NUNITS (fi.vector_mode (0)); + return aarch64_sve_data_mode (m_to_mode, nunits).require (); + } + + /* The mode of a single memory element. */ + scalar_int_mode m_to_mode; +}; + +/* A function_base for functions that have an associated rtx code. + It supports all forms of predication except PRED_implicit. */ +class rtx_code_function : public function_base +{ +public: + CONSTEXPR rtx_code_function (rtx_code code_for_sint, rtx_code code_for_uint, + int unspec_for_fp = -1) + : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint), + m_unspec_for_fp (unspec_for_fp) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint, + m_unspec_for_fp); + } + + /* The rtx code to use for signed and unsigned integers respectively. + Can be UNKNOWN for functions that don't have integer forms. */ + rtx_code m_code_for_sint; + rtx_code m_code_for_uint; + + /* The UNSPEC_COND_* to use for floating-point operations. Can be -1 + for functions that only operate on integers. */ + int m_unspec_for_fp; +}; + +/* Like rtx_code_function, but for functions that take what is normally + the final argument first. One use of this class is to handle binary + reversed operations; another is to handle MLA-style operations that + are normally expressed in GCC as MAD-style operations. */ +class rtx_code_function_rotated : public function_base +{ +public: + CONSTEXPR rtx_code_function_rotated (rtx_code code_for_sint, + rtx_code code_for_uint, + int unspec_for_fp = -1) + : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint), + m_unspec_for_fp (unspec_for_fp) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Rotate the inputs into their normal order, but continue to make _m + functions merge with what was originally the first vector argument. */ + unsigned int nargs = e.args.length (); + e.rotate_inputs_left (e.pred != PRED_none ? 1 : 0, nargs); + return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint, + m_unspec_for_fp, nargs - 1); + } + + /* The rtx code to use for signed and unsigned integers respectively. + Can be UNKNOWN for functions that don't have integer forms. */ + rtx_code m_code_for_sint; + rtx_code m_code_for_uint; + + /* The UNSPEC_COND_* to use for floating-point operations. Can be -1 + for functions that only operate on integers. */ + int m_unspec_for_fp; +}; + +/* A function_base for functions that have an associated unspec code. + It supports all forms of predication except PRED_implicit. */ +class unspec_based_function : public function_base +{ +public: + CONSTEXPR unspec_based_function (int unspec_for_sint, int unspec_for_uint, + int unspec_for_fp) + : m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint), + m_unspec_for_fp (unspec_for_fp) + {} + + rtx + expand (function_expander &e) const OVERRIDE + { + return e.map_to_unspecs (m_unspec_for_sint, m_unspec_for_uint, + m_unspec_for_fp); + } + + /* The unspec code associated with signed-integer, unsigned-integer + and floating-point operations respectively. */ + int m_unspec_for_sint; + int m_unspec_for_uint; + int m_unspec_for_fp; +}; + +/* Like unspec_based_function, but for functions that take what is normally + the final argument first. One use of this class is to handle binary + reversed operations; another is to handle MLA-style operations that + are normally expressed in GCC as MAD-style operations. */ +class unspec_based_function_rotated : public function_base +{ +public: + CONSTEXPR unspec_based_function_rotated (int unspec_for_sint, + int unspec_for_uint, + int unspec_for_fp) + : m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint), + m_unspec_for_fp (unspec_for_fp) + {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* Rotate the inputs into their normal order, but continue to make _m + functions merge with what was originally the first vector argument. */ + unsigned int nargs = e.args.length (); + e.rotate_inputs_left (e.pred != PRED_none ? 1 : 0, nargs); + return e.map_to_unspecs (m_unspec_for_sint, m_unspec_for_uint, + m_unspec_for_fp, nargs - 1); + } + + /* The unspec code associated with signed-integer, unsigned-integer + and floating-point operations respectively. */ + int m_unspec_for_sint; + int m_unspec_for_uint; + int m_unspec_for_fp; +}; + +/* A function_base for functions that permute their arguments. */ +class permute : public quiet<function_base> +{ +public: + /* Fold a unary or binary permute with the permute vector given by + BUILDER. */ + gimple * + fold_permute (const gimple_folder &f, const vec_perm_builder &builder) const + { + /* Punt for now on _b16 and wider; we'd need more complex evpc logic + to rerecognize the result. */ + if (f.type_suffix (0).bool_p && f.type_suffix (0).element_bits > 8) + return NULL; + + unsigned int nargs = gimple_call_num_args (f.call); + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (f.lhs)); + vec_perm_indices indices (builder, nargs, nelts); + tree perm_type = build_vector_type (ssizetype, nelts); + return gimple_build_assign (f.lhs, VEC_PERM_EXPR, + gimple_call_arg (f.call, 0), + gimple_call_arg (f.call, nargs - 1), + vec_perm_indices_to_tree (perm_type, indices)); + } +}; + +/* A function_base for functions that permute two vectors using a fixed + choice of indices. */ +class binary_permute : public permute +{ +public: + CONSTEXPR binary_permute (int unspec) : m_unspec (unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + insn_code icode = code_for_aarch64_sve (m_unspec, e.vector_mode (0)); + return e.use_exact_insn (icode); + } + + /* The unspec code associated with the operation. */ + int m_unspec; +}; + +/* A function_base for functions that reduce a vector to a scalar. */ +class reduction : public function_base +{ +public: + CONSTEXPR reduction (int unspec) + : m_unspec_for_sint (unspec), + m_unspec_for_uint (unspec), + m_unspec_for_fp (unspec) + {} + + CONSTEXPR reduction (int unspec_for_sint, int unspec_for_uint, + int unspec_for_fp) + : m_unspec_for_sint (unspec_for_sint), + m_unspec_for_uint (unspec_for_uint), + m_unspec_for_fp (unspec_for_fp) + {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + int unspec = (!e.type_suffix (0).integer_p ? m_unspec_for_fp + : e.type_suffix (0).unsigned_p ? m_unspec_for_uint + : m_unspec_for_sint); + /* There's no distinction between SADDV and UADDV for 64-bit elements; + the signed versions only exist for narrower elements. */ + if (GET_MODE_UNIT_BITSIZE (mode) == 64 && unspec == UNSPEC_SADDV) + unspec = UNSPEC_UADDV; + return e.use_exact_insn (code_for_aarch64_pred_reduc (unspec, mode)); + } + + /* The unspec code associated with signed-integer, unsigned-integer + and floating-point operations respectively. */ + int m_unspec_for_sint; + int m_unspec_for_uint; + int m_unspec_for_fp; +}; + +/* A function_base for functions that shift narrower-than-64-bit values + by 64-bit amounts. */ +class shift_wide : public function_base +{ +public: + CONSTEXPR shift_wide (rtx_code code, int wide_unspec) + : m_code (code), m_wide_unspec (wide_unspec) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + machine_mode mode = e.vector_mode (0); + machine_mode elem_mode = GET_MODE_INNER (mode); + + /* If the argument is a constant that the normal shifts can handle + directly, use them instead. */ + rtx shift = unwrap_const_vec_duplicate (e.args.last ()); + if (aarch64_simd_shift_imm_p (shift, elem_mode, m_code == ASHIFT)) + { + e.args.last () = shift; + return e.map_to_rtx_codes (m_code, m_code, -1); + } + + if (e.pred == PRED_x) + return e.use_unpred_insn (code_for_aarch64_sve (m_wide_unspec, mode)); + + return e.use_cond_insn (code_for_cond (m_wide_unspec, mode)); + } + + /* The rtx code associated with a "normal" shift. */ + rtx_code m_code; + + /* The unspec code associated with the wide shift. */ + int m_wide_unspec; +}; + +/* A function_base for unary functions that count bits. */ +class unary_count : public quiet<function_base> +{ +public: + CONSTEXPR unary_count (rtx_code code) : m_code (code) {} + + rtx + expand (function_expander &e) const OVERRIDE + { + /* The md patterns treat the operand as an integer. */ + machine_mode mode = mode_for_int_vector (e.vector_mode (0)).require (); + e.args.last () = gen_lowpart (mode, e.args.last ()); + + if (e.pred == PRED_x) + return e.use_pred_x_insn (code_for_aarch64_pred (m_code, mode)); + + return e.use_cond_insn (code_for_cond (m_code, mode)); + } + + /* The rtx code associated with the operation. */ + rtx_code m_code; +}; + +} + +/* Declare the global function base NAME, creating it from an instance + of class CLASS with constructor arguments ARGS. */ +#define FUNCTION(NAME, CLASS, ARGS) \ + namespace { static CONSTEXPR const CLASS NAME##_obj ARGS; } \ + namespace functions { const function_base *const NAME = &NAME##_obj; } + +#endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc new file mode 100644 index 0000000..6ab233b --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc @@ -0,0 +1,2236 @@ +/* ACLE support for AArch64 SVE (function shapes) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "memmodel.h" +#include "insn-codes.h" +#include "optabs.h" +#include "aarch64-sve-builtins.h" +#include "aarch64-sve-builtins-shapes.h" + +/* In the comments below, _t0 represents the first type suffix and _t1 + represents the second. Square brackets enclose characters that are + present in only the full name, not the overloaded name. Governing + predicate arguments and predicate suffixes are not shown, since they + depend on the predication type, which is a separate piece of + information from the shape. + + Non-overloaded functions may have additional suffixes beyond the + ones shown, if those suffixes don't affect the types in the type + signature. E.g. the predicate form of svtrn1 has a _b<bits> suffix, + but this does not affect the prototype, which is always + "svbool_t(svbool_t, svbool_t)". */ + +namespace aarch64_sve { + +/* Return a representation of "const T *". */ +static tree +build_const_pointer (tree t) +{ + return build_pointer_type (build_qualified_type (t, TYPE_QUAL_CONST)); +} + +/* If INSTANCE has a governing predicate, add it to the list of argument + types in ARGUMENT_TYPES. RETURN_TYPE is the type returned by the + function. */ +static void +apply_predication (const function_instance &instance, tree return_type, + vec<tree> &argument_types) +{ + if (instance.pred != PRED_none) + { + argument_types.quick_insert (0, get_svbool_t ()); + /* For unary merge operations, the first argument is a vector with + the same type as the result. */ + if (argument_types.length () == 2 && instance.pred == PRED_m) + argument_types.quick_insert (0, return_type); + } +} + +/* Parse and move past an element type in FORMAT and return it as a type + suffix. The format is: + + [01] - the element type in type suffix 0 or 1 of INSTANCE + f<bits> - a floating-point type with the given number of bits + f[01] - a floating-point type with the same width as type suffix 0 or 1 + h<elt> - a half-sized version of <elt> + p - a predicate (represented as TYPE_SUFFIX_b) + q<elt> - a quarter-sized version of <elt> + s<bits> - a signed type with the given number of bits + s[01] - a signed type with the same width as type suffix 0 or 1 + u<bits> - an unsigned type with the given number of bits + u[01] - an unsigned type with the same width as type suffix 0 or 1 + w<elt> - a 64-bit version of <elt> if <elt> is integral, otherwise <elt> + + where <elt> is another element type. */ +static type_suffix_index +parse_element_type (const function_instance &instance, const char *&format) +{ + int ch = *format++; + + if (ch == 'f' || ch == 's' || ch == 'u') + { + type_class_index tclass = (ch == 'f' ? TYPE_float + : ch == 's' ? TYPE_signed + : TYPE_unsigned); + char *end; + unsigned int bits = strtol (format, &end, 10); + format = end; + if (bits == 0 || bits == 1) + bits = instance.type_suffix (bits).element_bits; + return find_type_suffix (tclass, bits); + } + + if (ch == 'w') + { + type_suffix_index suffix = parse_element_type (instance, format); + if (type_suffixes[suffix].integer_p) + return find_type_suffix (type_suffixes[suffix].tclass, 64); + return suffix; + } + + if (ch == 'p') + return TYPE_SUFFIX_b; + + if (ch == 'q') + { + type_suffix_index suffix = parse_element_type (instance, format); + return find_type_suffix (type_suffixes[suffix].tclass, + type_suffixes[suffix].element_bits / 4); + } + + if (ch == 'h') + { + type_suffix_index suffix = parse_element_type (instance, format); + /* Widening and narrowing doesn't change the type for predicates; + everything's still an svbool_t. */ + if (suffix == TYPE_SUFFIX_b) + return suffix; + return find_type_suffix (type_suffixes[suffix].tclass, + type_suffixes[suffix].element_bits / 2); + } + + if (ch == '0' || ch == '1') + return instance.type_suffix_ids[ch - '0']; + + gcc_unreachable (); +} + +/* Read and return a type from FORMAT for function INSTANCE. Advance + FORMAT beyond the type string. The format is: + + _ - void + al - array pointer for loads + ap - array pointer for prefetches + as - array pointer for stores + b - base vector type (from a _<m0>base suffix) + d - displacement vector type (from a _<m1>index or _<m1>offset suffix) + e<name> - an enum with the given name + s<elt> - a scalar type with the given element suffix + t<elt> - a vector or tuple type with given element suffix [*1] + v<elt> - a vector with the given element suffix + + where <elt> has the format described above parse_element_type + + [*1] the vectors_per_tuple function indicates whether the type should + be a tuple, and if so, how many vectors it should contain. */ +static tree +parse_type (const function_instance &instance, const char *&format) +{ + int ch = *format++; + + if (ch == '_') + return void_type_node; + + if (ch == 'a') + { + ch = *format++; + if (ch == 'l') + return build_const_pointer (instance.memory_scalar_type ()); + if (ch == 'p') + return const_ptr_type_node; + if (ch == 's') + return build_pointer_type (instance.memory_scalar_type ()); + gcc_unreachable (); + } + + if (ch == 'b') + return instance.base_vector_type (); + + if (ch == 'd') + return instance.displacement_vector_type (); + + if (ch == 'e') + { + if (strncmp (format, "pattern", 7) == 0) + { + format += 7; + return acle_svpattern; + } + if (strncmp (format, "prfop", 5) == 0) + { + format += 5; + return acle_svprfop; + } + gcc_unreachable (); + } + + if (ch == 's') + { + type_suffix_index suffix = parse_element_type (instance, format); + return scalar_types[type_suffixes[suffix].vector_type]; + } + + if (ch == 't') + { + type_suffix_index suffix = parse_element_type (instance, format); + vector_type_index vector_type = type_suffixes[suffix].vector_type; + unsigned int num_vectors = instance.vectors_per_tuple (); + return acle_vector_types[num_vectors - 1][vector_type]; + } + + if (ch == 'v') + { + type_suffix_index suffix = parse_element_type (instance, format); + return acle_vector_types[0][type_suffixes[suffix].vector_type]; + } + + gcc_unreachable (); +} + +/* Read and move past any argument count at FORMAT for the function + signature of INSTANCE. The counts are: + + *q: one argument per element in a 128-bit quadword (as for svdupq) + *t: one argument per vector in a tuple (as for svcreate) + + Otherwise the count is 1. */ +static unsigned int +parse_count (const function_instance &instance, const char *&format) +{ + if (format[0] == '*' && format[1] == 'q') + { + format += 2; + return instance.elements_per_vq (0); + } + if (format[0] == '*' && format[1] == 't') + { + format += 2; + return instance.vectors_per_tuple (); + } + return 1; +} + +/* Read a type signature for INSTANCE from FORMAT. Add the argument types + to ARGUMENT_TYPES and return the return type. + + The format is a comma-separated list of types (as for parse_type), + with the first type being the return type and the rest being the + argument types. Each argument type can be followed by an optional + count (as for parse_count). */ +static tree +parse_signature (const function_instance &instance, const char *format, + vec<tree> &argument_types) +{ + tree return_type = parse_type (instance, format); + while (format[0] == ',') + { + format += 1; + tree argument_type = parse_type (instance, format); + unsigned int count = parse_count (instance, format); + for (unsigned int i = 0; i < count; ++i) + argument_types.quick_push (argument_type); + } + gcc_assert (format[0] == 0); + return return_type; +} + +/* Add one function instance for GROUP, using mode suffix MODE_SUFFIX_ID, + the type suffixes at index TI and the predication suffix at index PI. + The other arguments are as for build_all. */ +static void +build_one (function_builder &b, const char *signature, + const function_group_info &group, mode_suffix_index mode_suffix_id, + unsigned int ti, unsigned int pi, bool force_direct_overloads) +{ + /* Byte forms of svdupq take 16 arguments. */ + auto_vec<tree, 16> argument_types; + function_instance instance (group.base_name, *group.base, *group.shape, + mode_suffix_id, group.types[ti], + group.preds[pi]); + tree return_type = parse_signature (instance, signature, argument_types); + apply_predication (instance, return_type, argument_types); + b.add_unique_function (instance, return_type, argument_types, + group.required_extensions, force_direct_overloads); +} + +/* Add a function instance for every type and predicate combination + in GROUP, which describes some sort of gather or scatter operation. + If the function has any type suffixes (as for loads and stores), + the first function type suffix specifies either a 32-bit or a 64-bit + type; use MODE32 for the former and MODE64 for the latter. If the + function has no type suffixes (as for prefetches), add one MODE32 form + and one MODE64 form for each predication type. + + The other arguments are as for build_all. */ +static void +build_32_64 (function_builder &b, const char *signature, + const function_group_info &group, mode_suffix_index mode32, + mode_suffix_index mode64, bool force_direct_overloads = false) +{ + for (unsigned int pi = 0; group.preds[pi] != NUM_PREDS; ++pi) + if (group.types[0][0] == NUM_TYPE_SUFFIXES) + { + build_one (b, signature, group, mode32, 0, pi, + force_direct_overloads); + build_one (b, signature, group, mode64, 0, pi, + force_direct_overloads); + } + else + for (unsigned int ti = 0; group.types[ti][0] != NUM_TYPE_SUFFIXES; ++ti) + { + unsigned int bits = type_suffixes[group.types[ti][0]].element_bits; + gcc_assert (bits == 32 || bits == 64); + mode_suffix_index mode = bits == 32 ? mode32 : mode64; + build_one (b, signature, group, mode, ti, pi, + force_direct_overloads); + } +} + +/* For every type and predicate combination in GROUP, add one function + that takes a scalar (pointer) base and a signed vector array index, + and another that instead takes an unsigned vector array index. + The vector array index has the same element size as the first + function type suffix. SIGNATURE is as for build_all. */ +static void +build_sv_index (function_builder &b, const char *signature, + const function_group_info &group) +{ + build_32_64 (b, signature, group, MODE_s32index, MODE_s64index); + build_32_64 (b, signature, group, MODE_u32index, MODE_u64index); +} + +/* Like build_sv_index, but taking vector byte offsets instead of vector + array indices. */ +static void +build_sv_offset (function_builder &b, const char *signature, + const function_group_info &group) +{ + build_32_64 (b, signature, group, MODE_s32offset, MODE_s64offset); + build_32_64 (b, signature, group, MODE_u32offset, MODE_u64offset); +} + +/* For every type and predicate combination in GROUP, add a function + that takes a vector base address and no displacement. The vector + base has the same element size as the first type suffix. + + The other arguments are as for build_all. */ +static void +build_v_base (function_builder &b, const char *signature, + const function_group_info &group, + bool force_direct_overloads = false) +{ + build_32_64 (b, signature, group, MODE_u32base, MODE_u64base, + force_direct_overloads); +} + +/* Like build_v_base, but for functions that also take a scalar array + index. */ +static void +build_vs_index (function_builder &b, const char *signature, + const function_group_info &group, + bool force_direct_overloads = false) +{ + build_32_64 (b, signature, group, MODE_u32base_index, MODE_u64base_index, + force_direct_overloads); +} + +/* Like build_v_base, but for functions that also take a scalar byte + offset. */ +static void +build_vs_offset (function_builder &b, const char *signature, + const function_group_info &group, + bool force_direct_overloads = false) +{ + build_32_64 (b, signature, group, MODE_u32base_offset, MODE_u64base_offset, + force_direct_overloads); +} + +/* Add a function instance for every type and predicate combination + in GROUP. Take the function base name from GROUP and the mode suffix + from MODE_SUFFIX_ID. Use SIGNATURE to construct the function signature + without a governing predicate, then use apply_predication to add in the + predicate. FORCE_DIRECT_OVERLOADS is true if there is a one-to-one + mapping between "short" and "full" names, and if standard overload + resolution therefore isn't necessary. */ +static void +build_all (function_builder &b, const char *signature, + const function_group_info &group, mode_suffix_index mode_suffix_id, + bool force_direct_overloads = false) +{ + for (unsigned int pi = 0; group.preds[pi] != NUM_PREDS; ++pi) + for (unsigned int ti = 0; + ti == 0 || group.types[ti][0] != NUM_TYPE_SUFFIXES; ++ti) + build_one (b, signature, group, mode_suffix_id, ti, pi, + force_direct_overloads); +} + +/* Declare the function shape NAME, pointing it to an instance + of class <NAME>_def. */ +#define SHAPE(NAME) \ + static CONSTEXPR const NAME##_def NAME##_obj; \ + namespace shapes { const function_shape *const NAME = &NAME##_obj; } + +/* Base class for functions that are not overloaded. */ +struct nonoverloaded_base : public function_shape +{ + bool + explicit_type_suffix_p (unsigned int) const OVERRIDE + { + return true; + } + + tree + resolve (function_resolver &) const OVERRIDE + { + gcc_unreachable (); + } +}; + +/* Base class for overloaded functions. Bit N of EXPLICIT_MASK is true + if type suffix N appears in the overloaded name. */ +template<unsigned int EXPLICIT_MASK> +struct overloaded_base : public function_shape +{ + bool + explicit_type_suffix_p (unsigned int i) const OVERRIDE + { + return (EXPLICIT_MASK >> i) & 1; + } +}; + +/* Base class for adr_index and adr_offset. */ +struct adr_base : public overloaded_base<0> +{ + /* The function takes two arguments: a vector base and a vector displacement + (either an index or an offset). Resolve based on them both. */ + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + mode_suffix_index mode; + if (!r.check_gp_argument (2, i, nargs) + || (mode = r.resolve_adr_address (0)) == MODE_none) + return error_mark_node; + + return r.resolve_to (mode); + }; +}; + +/* Base class for inc_dec and inc_dec_pat. */ +struct inc_dec_base : public overloaded_base<0> +{ + CONSTEXPR inc_dec_base (bool pat_p) : m_pat_p (pat_p) {} + + /* Resolve based on the first argument only, which must be either a + scalar or a vector. If it's a scalar, it must be a 32-bit or + 64-bit integer. */ + tree + resolve (function_resolver &r) const + { + unsigned int i, nargs; + if (!r.check_gp_argument (m_pat_p ? 3 : 2, i, nargs) + || !r.require_vector_or_scalar_type (i)) + return error_mark_node; + + mode_suffix_index mode; + type_suffix_index type; + if (r.scalar_argument_p (i)) + { + mode = MODE_n; + type = r.infer_integer_scalar_type (i); + } + else + { + mode = MODE_none; + type = r.infer_vector_type (i); + } + if (type == NUM_TYPE_SUFFIXES) + return error_mark_node; + + for (++i; i < nargs; ++i) + if (!r.require_integer_immediate (i)) + return error_mark_node; + + return r.resolve_to (mode, type); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_range (m_pat_p ? 2 : 1, 1, 16); + } + + bool m_pat_p; +}; + +/* Base class for load and load_replicate. */ +struct load_contiguous_base : public overloaded_base<0> +{ + /* Resolve a call based purely on a pointer argument. The other arguments + are a governing predicate and (for MODE_vnum) a vnum offset. */ + tree + resolve (function_resolver &r) const OVERRIDE + { + bool vnum_p = r.mode_suffix_id == MODE_vnum; + gcc_assert (r.mode_suffix_id == MODE_none || vnum_p); + + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (vnum_p ? 2 : 1, i, nargs) + || (type = r.infer_pointer_type (i)) == NUM_TYPE_SUFFIXES + || (vnum_p && !r.require_scalar_type (i + 1, "int64_t"))) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; + +/* Base class for load_ext_gather_index and load_ext_gather_offset, + which differ only in the units of the displacement. */ +struct load_ext_gather_base : public overloaded_base<1> +{ + /* Resolve a gather load that takes one of: + + - a scalar pointer base and a vector displacement + - a vector base with no displacement or + - a vector base and a scalar displacement + + The function has an explicit type suffix that determines the type + of the loaded data. */ + tree + resolve (function_resolver &r) const OVERRIDE + { + /* No resolution is needed for a vector base with no displacement; + there's a one-to-one mapping between short and long names. */ + gcc_assert (r.displacement_units () != UNITS_none); + + type_suffix_index type = r.type_suffix_ids[0]; + + unsigned int i, nargs; + mode_suffix_index mode; + if (!r.check_gp_argument (2, i, nargs) + || (mode = r.resolve_gather_address (i, type, true)) == MODE_none) + return error_mark_node; + + return r.resolve_to (mode, type); + } +}; + +/* Base class for prefetch_gather_index and prefetch_gather_offset, + which differ only in the units of the displacement. */ +struct prefetch_gather_base : public overloaded_base<0> +{ + /* Resolve a gather prefetch that takes one of: + + - a scalar pointer base (const void *) and a vector displacement + - a vector base with no displacement or + - a vector base and a scalar displacement + + The prefetch operation is the final argument. This is purely a + mode-based resolution; there are no type suffixes. */ + tree + resolve (function_resolver &r) const OVERRIDE + { + bool has_displacement_p = r.displacement_units () != UNITS_none; + + unsigned int i, nargs; + mode_suffix_index mode; + if (!r.check_gp_argument (has_displacement_p ? 3 : 2, i, nargs) + || (mode = r.resolve_gather_address (i, NUM_TYPE_SUFFIXES, + false)) == MODE_none + || !r.require_integer_immediate (nargs - 1)) + return error_mark_node; + + return r.resolve_to (mode); + } +}; + +/* Base class for store_scatter_index and store_scatter_offset, + which differ only in the units of the displacement. */ +struct store_scatter_base : public overloaded_base<0> +{ + /* Resolve a scatter store that takes one of: + + - a scalar pointer base and a vector displacement + - a vector base with no displacement or + - a vector base and a scalar displacement + + The stored data is the final argument, and it determines the + type suffix. */ + tree + resolve (function_resolver &r) const OVERRIDE + { + bool has_displacement_p = r.displacement_units () != UNITS_none; + + unsigned int i, nargs; + mode_suffix_index mode; + type_suffix_index type; + if (!r.check_gp_argument (has_displacement_p ? 3 : 2, i, nargs) + || (type = r.infer_sd_vector_type (nargs - 1)) == NUM_TYPE_SUFFIXES + || (mode = r.resolve_gather_address (i, type, false)) == MODE_none) + return error_mark_node; + + return r.resolve_to (mode, type); + } +}; + +/* sv<m0>_t svfoo[_m0base]_[m1]index(sv<m0>_t, sv<m1>_t) + + for all valid combinations of vector base type <m0> and vector + displacement type <m1>. */ +struct adr_index_def : public adr_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_index); + build_all (b, "b,b,d", group, MODE_u32base_s32index); + build_all (b, "b,b,d", group, MODE_u32base_u32index); + build_all (b, "b,b,d", group, MODE_u64base_s64index); + build_all (b, "b,b,d", group, MODE_u64base_u64index); + } +}; +SHAPE (adr_index) + +/* sv<m0>_t svfoo[_m0base]_[m1]offset(sv<m0>_t, sv<m1>_t). + + for all valid combinations of vector base type <m0> and vector + displacement type <m1>. */ +struct adr_offset_def : public adr_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_offset); + build_all (b, "b,b,d", group, MODE_u32base_s32offset); + build_all (b, "b,b,d", group, MODE_u32base_u32offset); + build_all (b, "b,b,d", group, MODE_u64base_s64offset); + build_all (b, "b,b,d", group, MODE_u64base_u64offset); + } +}; +SHAPE (adr_offset) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t) + + i.e. a binary operation with uniform types, but with no scalar form. */ +struct binary_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (2); + } +}; +SHAPE (binary) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0:int>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0:int>_t). + + i.e. a version of the standard binary shape binary_opt_n in which + the final argument is always a signed integer. */ +struct binary_int_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vs0", group, MODE_none); + build_all (b, "v0,v0,ss0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + return r.finish_opt_n_resolution (i + 1, i, type, TYPE_signed); + } +}; +SHAPE (binary_int_opt_n) + +/* sv<t0>_t svfoo_<t0>(sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument is an integer constant expression in the + range [0, 16 / sizeof (<t0>_t) - 1]. */ +struct binary_lane_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (2, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_lane_index (2); + } +}; +SHAPE (binary_lane) + +/* sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0>_t). + + i.e. a binary operation in which the final argument is always a scalar + rather than a vector. */ +struct binary_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_n); + build_all (b, "v0,v0,s0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_derived_scalar_type (i + 1, r.SAME_TYPE_CLASS)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0>_t) + + i.e. the standard shape for binary operations that operate on + uniform types. */ +struct binary_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0", group, MODE_none); + /* _b functions do not have an _n form, but are classified as + binary_opt_n so that they can be overloaded with vector + functions. */ + if (group.types[0][0] == TYPE_SUFFIX_b) + gcc_assert (group.types[0][1] == NUM_TYPE_SUFFIXES); + else + build_all (b, "v0,v0,s0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform_opt_n (2); + } +}; +SHAPE (binary_opt_n) + +/* svbool_t svfoo(svbool_t, svbool_t). */ +struct binary_pred_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "v0,v0,v0", group, MODE_none); + } +}; +SHAPE (binary_pred) + +/* sv<t0>_t svfoo[_<t0>](sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument must be 90 or 270. */ +struct binary_rotate_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (2, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_either_or (2, 90, 270); + } +}; +SHAPE (binary_rotate) + +/* sv<t0>_t svfoo_t0(<t0>_t, <t0>_t) + + i.e. a binary function that takes two scalars and returns a vector. + An explicit type suffix is required. */ +struct binary_scalar_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "v0,s0,s0", group, MODE_none); + } +}; +SHAPE (binary_scalar) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0:uint>_t) + + i.e. a version of "binary" in which the final argument is always an + unsigned integer. */ +struct binary_uint_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vu0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_derived_vector_type (i + 1, i, type, TYPE_unsigned)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_uint) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, <t0:uint>_t) + + i.e. a version of binary_n in which the final argument is always an + unsigned integer. */ +struct binary_uint_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,su0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_derived_scalar_type (i + 1, TYPE_unsigned)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_uint_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0:uint>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0:uint>_t) + + i.e. a version of the standard binary shape binary_opt_n in which + the final argument is always an unsigned integer. */ +struct binary_uint_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vu0", group, MODE_none); + build_all (b, "v0,v0,su0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + return r.finish_opt_n_resolution (i + 1, i, type, TYPE_unsigned); + } +}; +SHAPE (binary_uint_opt_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, uint64_t). + + i.e. a version of binary_n in which the final argument is always + a 64-bit unsigned integer. */ +struct binary_uint64_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_scalar_type (i + 1, "uint64_t")) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (binary_uint64_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, svuint64_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, uint64_t) + + i.e. a version of the standard binary shape binary_opt_n in which + the final argument is always a uint64_t. */ +struct binary_uint64_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vu64", group, MODE_none); + build_all (b, "v0,v0,su64", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + return r.finish_opt_n_resolution (i + 1, i, type, TYPE_unsigned, 64); + } +}; +SHAPE (binary_uint64_opt_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t) + <t0>_t svfoo[_n_t0](<t0>_t, sv<t0>_t). */ +struct clast_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0", group, MODE_none); + build_all (b, "s0,s0,v0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + if (!r.check_gp_argument (2, i, nargs) + || !r.require_vector_or_scalar_type (i)) + return error_mark_node; + + if (r.scalar_argument_p (i)) + { + type_suffix_index type; + if (!r.require_derived_scalar_type (i, r.SAME_TYPE_CLASS) + || (type = r.infer_vector_type (i + 1)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + return r.resolve_to (MODE_n, type); + } + else + { + type_suffix_index type; + if ((type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_matching_vector_type (i + 1, type)) + return error_mark_node; + return r.resolve_to (MODE_none, type); + } + } +}; +SHAPE (clast) + +/* svbool_t svfoo[_t0](sv<t0>_t, sv<t0>_t) + svbool_t svfoo[_n_t0](sv<t0>_t, <t0>_t) + + i.e. a comparison between two vectors, or between a vector and a scalar. */ +struct compare_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "vp,v0,v0", group, MODE_none); + build_all (b, "vp,v0,s0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform_opt_n (2); + } +}; +SHAPE (compare_opt_n) + +/* svbool_t svfoo_t0[_t1](<t1>_t, <t1>_t) + + where _t0 is a _b<bits> suffix that describes the predicate result. + There is no direct relationship between the element sizes of _t0 + and _t1. */ +struct compare_scalar_def : public overloaded_base<1> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "vp,s1,s1", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_integer_scalar_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_matching_integer_scalar_type (i + 1, i, type)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, r.type_suffix_ids[0], type); + } +}; +SHAPE (compare_scalar) + +/* svbool_t svfoo[_t0](sv<t0>_t, svint64_t) (for signed t0) + svbool_t svfoo[_n_t0](sv<t0>_t, int64_t) (for signed t0) + svbool_t svfoo[_t0](sv<t0>_t, svuint64_t) (for unsigned t0) + svbool_t svfoo[_n_t0](sv<t0>_t, uint64_t) (for unsigned t0) + + i.e. a comparison in which the second argument is 64 bits. */ +struct compare_wide_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "vp,v0,vw0", group, MODE_none); + build_all (b, "vp,v0,sw0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + return r.finish_opt_n_resolution (i + 1, i, type, r.SAME_TYPE_CLASS, 64); + } +}; +SHAPE (compare_wide_opt_n) + +/* uint64_t svfoo(). */ +struct count_inherent_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "su64", group, MODE_none); + } +}; +SHAPE (count_inherent) + +/* uint64_t svfoo(enum svpattern). */ +struct count_pat_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "su64,epattern", group, MODE_none); + } +}; +SHAPE (count_pat) + +/* uint64_t svfoo(svbool_t). */ +struct count_pred_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "su64,vp", group, MODE_none); + } +}; +SHAPE (count_pred) + +/* uint64_t svfoo[_t0](sv<t0>_t). */ +struct count_vector_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "su64,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (1); + } +}; +SHAPE (count_vector) + +/* sv<t0>xN_t svfoo[_t0](sv<t0>_t, ..., sv<t0>_t) + + where there are N arguments in total. */ +struct create_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "t0,v0*t", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (r.vectors_per_tuple ()); + } +}; +SHAPE (create) + +/* sv<t0>_t svfoo[_n]_t0(<t0>_t, ..., <t0>_t) + + where there are enough arguments to fill 128 bits of data (or to + control 128 bits of data in the case of predicates). */ +struct dupq_def : public overloaded_base<1> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + /* The "_n" suffix is optional; the full name has it, but the short + name doesn't. */ + build_all (b, "v0,s0*q", group, MODE_n, true); + } + + tree + resolve (function_resolver &) const OVERRIDE + { + /* The short forms just make "_n" implicit, so no resolution is needed. */ + gcc_unreachable (); + } +}; +SHAPE (dupq) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument is an integer constant expression that when + multiplied by the number of bytes in t0 is in the range [0, 255]. */ +struct ext_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (2, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + unsigned int bytes = c.type_suffix (0).element_bytes; + return c.require_immediate_range (2, 0, 256 / bytes - 1); + } +}; +SHAPE (ext) + +/* <t0>_t svfoo[_t0](<t0>_t, sv<t0>_t). */ +struct fold_left_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "s0,s0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || !r.require_derived_scalar_type (i, r.SAME_TYPE_CLASS) + || (type = r.infer_vector_type (i + 1)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (fold_left) + +/* sv<t0>_t svfoo[_t0](sv<t0>xN_t, uint64_t) + + where the final argument is an integer constant expression in + the range [0, N - 1]. */ +struct get_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,t0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_tuple_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_integer_immediate (i + 1)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } + + bool + check (function_checker &c) const OVERRIDE + { + unsigned int nvectors = c.vectors_per_tuple (); + return c.require_immediate_range (1, 0, nvectors - 1); + } +}; +SHAPE (get) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, uint64_t) + <t0>_t svfoo[_n_t0](<t0>_t, uint64_t) + + where the t0 in the vector form is a signed or unsigned integer + whose size is tied to the [bhwd] suffix of "svfoo". */ +struct inc_dec_def : public inc_dec_base +{ + CONSTEXPR inc_dec_def () : inc_dec_base (false) {} + + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + /* These functions are unusual in that the type suffixes for + the scalar and vector forms are not related. The vector + form always has exactly two potential suffixes while the + scalar form always has four. */ + if (group.types[2][0] == NUM_TYPE_SUFFIXES) + build_all (b, "v0,v0,su64", group, MODE_none); + else + build_all (b, "s0,s0,su64", group, MODE_n); + } +}; +SHAPE (inc_dec) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, enum svpattern, uint64_t) + <t0>_t svfoo[_n_t0](<t0>_t, enum svpattern, uint64_t) + + where the t0 in the vector form is a signed or unsigned integer + whose size is tied to the [bhwd] suffix of "svfoo". */ +struct inc_dec_pat_def : public inc_dec_base +{ + CONSTEXPR inc_dec_pat_def () : inc_dec_base (true) {} + + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + /* These functions are unusual in that the type suffixes for + the scalar and vector forms are not related. The vector + form always has exactly two potential suffixes while the + scalar form always has four. */ + if (group.types[2][0] == NUM_TYPE_SUFFIXES) + build_all (b, "v0,v0,epattern,su64", group, MODE_none); + else + build_all (b, "s0,s0,epattern,su64", group, MODE_n); + } +}; +SHAPE (inc_dec_pat) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, svbool_t). */ +struct inc_dec_pred_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vp", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_vector_type (i + 1, VECTOR_TYPE_svbool_t)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (inc_dec_pred) + +/* <t0>_t svfoo[_n_t0]_t1(<t0>_t, svbool_t) + + where _t1 is a _b<bits> suffix that describes the svbool_t argument. */ +struct inc_dec_pred_scalar_def : public overloaded_base<2> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_n); + build_all (b, "s0,s0,vp", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_integer_scalar_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_vector_type (i + 1, VECTOR_TYPE_svbool_t)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type, r.type_suffix_ids[1]); + } +}; +SHAPE (inc_dec_pred_scalar) + +/* sv<t0>[xN]_t svfoo_t0(). */ +struct inherent_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "t0", group, MODE_none); + } +}; +SHAPE (inherent) + +/* svbool_t svfoo[_b](). */ +struct inherent_b_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + /* The "_b" suffix is optional; the full name has it, but the short + name doesn't. */ + build_all (b, "v0", group, MODE_none, true); + } + + tree + resolve (function_resolver &) const OVERRIDE + { + /* The short forms just make "_b" implicit, so no resolution is needed. */ + gcc_unreachable (); + } +}; +SHAPE (inherent_b) + +/* sv<t0>[xN]_t svfoo[_t0](const <t0>_t *) + sv<t0>[xN]_t svfoo_vnum[_t0](const <t0>_t *, int64_t). */ +struct load_def : public load_contiguous_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + b.add_overloaded_functions (group, MODE_vnum); + build_all (b, "t0,al", group, MODE_none); + build_all (b, "t0,al,ss64", group, MODE_vnum); + } +}; +SHAPE (load) + +/* sv<t0>_t svfoo_t0(const <X>_t *) + sv<t0>_t svfoo_vnum_t0(const <X>_t *, int64_t) + + where <X> is determined by the function base name. */ +struct load_ext_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "t0,al", group, MODE_none); + build_all (b, "t0,al,ss64", group, MODE_vnum); + } +}; +SHAPE (load_ext) + +/* sv<t0>_t svfoo_[s32]index_t0(const <X>_t *, svint32_t) + sv<t0>_t svfoo_[s64]index_t0(const <X>_t *, svint64_t) + sv<t0>_t svfoo_[u32]index_t0(const <X>_t *, svuint32_t) + sv<t0>_t svfoo_[u64]index_t0(const <X>_t *, svuint64_t) + + sv<t0>_t svfoo[_u32base]_index_t0(svuint32_t, int64_t) + sv<t0>_t svfoo[_u64base]_index_t0(svuint64_t, int64_t) + + where <X> is determined by the function base name. */ +struct load_ext_gather_index_def : public load_ext_gather_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_index); + build_sv_index (b, "t0,al,d", group); + build_vs_index (b, "t0,b,ss64", group); + } +}; +SHAPE (load_ext_gather_index) + +/* sv<t0>_t svfoo_[s32]offset_t0(const <X>_t *, svint32_t) + sv<t0>_t svfoo_[s64]offset_t0(const <X>_t *, svint64_t) + sv<t0>_t svfoo_[u32]offset_t0(const <X>_t *, svuint32_t) + sv<t0>_t svfoo_[u64]offset_t0(const <X>_t *, svuint64_t) + + sv<t0>_t svfoo[_u32base]_t0(svuint32_t) + sv<t0>_t svfoo[_u64base]_t0(svuint64_t) + + sv<t0>_t svfoo[_u32base]_offset_t0(svuint32_t, int64_t) + sv<t0>_t svfoo[_u64base]_offset_t0(svuint64_t, int64_t) + + where <X> is determined by the function base name. */ +struct load_ext_gather_offset_def : public load_ext_gather_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_offset); + build_sv_offset (b, "t0,al,d", group); + build_v_base (b, "t0,b", group, true); + build_vs_offset (b, "t0,b,ss64", group); + } +}; +SHAPE (load_ext_gather_offset) + +/* sv<t0>_t svfoo_[s32]index[_t0](const <t0>_t *, svint32_t) + sv<t0>_t svfoo_[s64]index[_t0](const <t0>_t *, svint64_t) + sv<t0>_t svfoo_[u32]index[_t0](const <t0>_t *, svuint32_t) + sv<t0>_t svfoo_[u64]index[_t0](const <t0>_t *, svuint64_t) + + sv<t0>_t svfoo_[s32]offset[_t0](const <t0>_t *, svint32_t) + sv<t0>_t svfoo_[s64]offset[_t0](const <t0>_t *, svint64_t) + sv<t0>_t svfoo_[u32]offset[_t0](const <t0>_t *, svuint32_t) + sv<t0>_t svfoo_[u64]offset[_t0](const <t0>_t *, svuint64_t). */ +struct load_gather_sv_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_index); + b.add_overloaded_functions (group, MODE_offset); + build_sv_index (b, "t0,al,d", group); + build_sv_offset (b, "t0,al,d", group); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + mode_suffix_index mode; + type_suffix_index type; + if (!r.check_gp_argument (2, i, nargs) + || (type = r.infer_pointer_type (i, true)) == NUM_TYPE_SUFFIXES + || (mode = r.resolve_sv_displacement (i + 1, type, true), + mode == MODE_none)) + return error_mark_node; + + return r.resolve_to (mode, type); + } +}; +SHAPE (load_gather_sv) + +/* sv<t0>_t svfoo[_u32base]_t0(svuint32_t) + sv<t0>_t svfoo[_u64base]_t0(svuint64_t) + + sv<t0>_t svfoo[_u32base]_index_t0(svuint32_t, int64_t) + sv<t0>_t svfoo[_u64base]_index_t0(svuint64_t, int64_t) + + sv<t0>_t svfoo[_u32base]_offset_t0(svuint32_t, int64_t) + sv<t0>_t svfoo[_u64base]_offset_t0(svuint64_t, int64_t). */ +struct load_gather_vs_def : public overloaded_base<1> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + /* The base vector mode is optional; the full name has it but the + short name doesn't. There is no ambiguity with SHAPE_load_gather_sv + because the latter uses an implicit type suffix. */ + build_v_base (b, "t0,b", group, true); + build_vs_index (b, "t0,b,ss64", group, true); + build_vs_offset (b, "t0,b,ss64", group, true); + } + + tree + resolve (function_resolver &) const OVERRIDE + { + /* The short name just makes the base vector mode implicit; + no resolution is needed. */ + gcc_unreachable (); + } +}; +SHAPE (load_gather_vs) + +/* sv<t0>_t svfoo[_t0](const <t0>_t *) + + The only difference from "load" is that this shape has no vnum form. */ +struct load_replicate_def : public load_contiguous_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "t0,al", group, MODE_none); + } +}; +SHAPE (load_replicate) + +/* svbool_t svfoo(enum svpattern). */ +struct pattern_pred_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "vp,epattern", group, MODE_none); + } +}; +SHAPE (pattern_pred) + +/* void svfoo(const void *, svprfop) + void svfoo_vnum(const void *, int64_t, svprfop). */ +struct prefetch_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "_,ap,eprfop", group, MODE_none); + build_all (b, "_,ap,ss64,eprfop", group, MODE_vnum); + } +}; +SHAPE (prefetch) + +/* void svfoo_[s32]index(const void *, svint32_t, svprfop) + void svfoo_[s64]index(const void *, svint64_t, svprfop) + void svfoo_[u32]index(const void *, svuint32_t, svprfop) + void svfoo_[u64]index(const void *, svuint64_t, svprfop) + + void svfoo[_u32base](svuint32_t, svprfop) + void svfoo[_u64base](svuint64_t, svprfop) + + void svfoo[_u32base]_index(svuint32_t, int64_t, svprfop) + void svfoo[_u64base]_index(svuint64_t, int64_t, svprfop). */ +struct prefetch_gather_index_def : public prefetch_gather_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + b.add_overloaded_functions (group, MODE_index); + build_sv_index (b, "_,ap,d,eprfop", group); + build_v_base (b, "_,b,eprfop", group); + build_vs_index (b, "_,b,ss64,eprfop", group); + } +}; +SHAPE (prefetch_gather_index) + +/* void svfoo_[s32]offset(const void *, svint32_t, svprfop) + void svfoo_[s64]offset(const void *, svint64_t, svprfop) + void svfoo_[u32]offset(const void *, svuint32_t, svprfop) + void svfoo_[u64]offset(const void *, svuint64_t, svprfop) + + void svfoo[_u32base](svuint32_t, svprfop) + void svfoo[_u64base](svuint64_t, svprfop) + + void svfoo[_u32base]_offset(svuint32_t, int64_t, svprfop) + void svfoo[_u64base]_offset(svuint64_t, int64_t, svprfop). */ +struct prefetch_gather_offset_def : public prefetch_gather_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + b.add_overloaded_functions (group, MODE_offset); + build_sv_offset (b, "_,ap,d,eprfop", group); + build_v_base (b, "_,b,eprfop", group); + build_vs_offset (b, "_,b,ss64,eprfop", group); + } +}; +SHAPE (prefetch_gather_offset) + +/* bool svfoo(svbool_t). */ +struct ptest_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "sp,vp", group, MODE_none); + } +}; +SHAPE (ptest) + +/* svbool_t svfoo(). */ +struct rdffr_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "vp", group, MODE_none); + } +}; +SHAPE (rdffr) + +/* <t0>_t svfoo[_t0](sv<t0>_t). */ +struct reduction_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "s0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (1); + } +}; +SHAPE (reduction) + +/* int64_t svfoo[_t0](sv<t0>_t) (for signed t0) + uint64_t svfoo[_t0](sv<t0>_t) (for unsigned t0) + <t0>_t svfoo[_t0](sv<t0>_t) (for floating-point t0) + + i.e. a version of "reduction" in which the return type for integers + always has 64 bits. */ +struct reduction_wide_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "sw0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (1); + } +}; +SHAPE (reduction_wide) + +/* sv<t0>xN_t svfoo[_t0](sv<t0>xN_t, uint64_t, sv<t0>_t) + + where the second argument is an integer constant expression in the + range [0, N - 1]. */ +struct set_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "t0,t0,su64,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (3, i, nargs) + || (type = r.infer_tuple_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_integer_immediate (i + 1) + || !r.require_derived_vector_type (i + 2, i, type)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } + + bool + check (function_checker &c) const OVERRIDE + { + unsigned int nvectors = c.vectors_per_tuple (); + return c.require_immediate_range (1, 0, nvectors - 1); + } +}; +SHAPE (set) + +/* void svfoo(). */ +struct setffr_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "_", group, MODE_none); + } +}; +SHAPE (setffr) + +/* sv<t0>_t svfoo[_n_t0])(sv<t0>_t, uint64_t) + + where the final argument must be an integer constant expression in the + range [1, sizeof (<t0>_t) * 8]. */ +struct shift_right_imm_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_n); + build_all (b, "v0,v0,su64", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (1, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + unsigned int bits = c.type_suffix (0).element_bits; + return c.require_immediate_range (1, 1, bits); + } +}; +SHAPE (shift_right_imm) + +/* void svfoo[_t0](<X>_t *, sv<t0>[xN]_t) + void svfoo_vnum[_t0](<X>_t *, int64_t, sv<t0>[xN]_t) + + where <X> might be tied to <t0> (for non-truncating stores) or might + depend on the function base name (for truncating stores). */ +struct store_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + b.add_overloaded_functions (group, MODE_vnum); + build_all (b, "_,as,t0", group, MODE_none); + build_all (b, "_,as,ss64,t0", group, MODE_vnum); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + bool vnum_p = r.mode_suffix_id == MODE_vnum; + gcc_assert (r.mode_suffix_id == MODE_none || vnum_p); + + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (vnum_p ? 3 : 2, i, nargs) + || !r.require_pointer_type (i) + || (vnum_p && !r.require_scalar_type (i + 1, "int64_t")) + || ((type = r.infer_tuple_type (nargs - 1)) == NUM_TYPE_SUFFIXES)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } +}; +SHAPE (store) + +/* void svfoo_[s32]index[_t0](<X>_t *, svint32_t, sv<t0>_t) + void svfoo_[s64]index[_t0](<X>_t *, svint64_t, sv<t0>_t) + void svfoo_[u32]index[_t0](<X>_t *, svuint32_t, sv<t0>_t) + void svfoo_[u64]index[_t0](<X>_t *, svuint64_t, sv<t0>_t) + + void svfoo[_u32base]_index[_t0](svuint32_t, int64_t, sv<t0>_t) + void svfoo[_u64base]_index[_t0](svuint64_t, int64_t, sv<t0>_t) + + where <X> might be tied to <t0> (for non-truncating stores) or might + depend on the function base name (for truncating stores). */ +struct store_scatter_index_def : public store_scatter_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_index); + build_sv_index (b, "_,as,d,t0", group); + build_vs_index (b, "_,b,ss64,t0", group); + } +}; +SHAPE (store_scatter_index) + +/* void svfoo_[s32]offset[_t0](<X>_t *, svint32_t, sv<t0>_t) + void svfoo_[s64]offset[_t0](<X>_t *, svint64_t, sv<t0>_t) + void svfoo_[u32]offset[_t0](<X>_t *, svuint32_t, sv<t0>_t) + void svfoo_[u64]offset[_t0](<X>_t *, svuint64_t, sv<t0>_t) + + void svfoo[_u32base_t0](svuint32_t, sv<t0>_t) + void svfoo[_u64base_t0](svuint64_t, sv<t0>_t) + + void svfoo[_u32base]_offset[_t0](svuint32_t, int64_t, sv<t0>_t) + void svfoo[_u64base]_offset[_t0](svuint64_t, int64_t, sv<t0>_t) + + where <X> might be tied to <t0> (for non-truncating stores) or might + depend on the function base name (for truncating stores). */ +struct store_scatter_offset_def : public store_scatter_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + b.add_overloaded_functions (group, MODE_offset); + build_sv_offset (b, "_,as,d,t0", group); + build_v_base (b, "_,b,t0", group); + build_vs_offset (b, "_,b,ss64,t0", group); + } +}; +SHAPE (store_scatter_offset) + +/* svbool_t svfoo[_<t0>](sv<t0>_t, sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument is an integer constant expression in the + range [0, 16 / sizeof (<t0>_t) - 1]. */ +struct ternary_lane_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (3, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_lane_index (3); + } +}; +SHAPE (ternary_lane) + +/* svbool_t svfoo[_<t0>](sv<t0>_t, sv<t0>_t, sv<t0>_t, uint64_t, uint64_t) + + where the penultimate argument is an integer constant expression in + the range [0, 8 / sizeof (<t0>_t) - 1] and where the final argument + is an integer constant expression in {0, 90, 180, 270}. */ +struct ternary_lane_rotate_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,v0,su64,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (3, 2); + } + + bool + check (function_checker &c) const OVERRIDE + { + return (c.require_immediate_lane_index (3, 2) + && c.require_immediate_one_of (4, 0, 90, 180, 270)); + } +}; +SHAPE (ternary_lane_rotate) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t, sv<t0>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0>_t, <t0>_t) + + i.e. the standard shape for ternary operations that operate on + uniform types. */ +struct ternary_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,v0", group, MODE_none); + build_all (b, "v0,v0,v0,s0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform_opt_n (3); + } +}; +SHAPE (ternary_opt_n) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t, uint64_t) + + where the final argument is an integer constant expression in the range + [0, 16 / sizeof (<t0>_t) - 1]. */ +struct ternary_qq_lane_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vq0,vq0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (4, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_derived_vector_type (i + 1, i, type, r.SAME_TYPE_CLASS, + r.QUARTER_SIZE) + || !r.require_derived_vector_type (i + 2, i, type, r.SAME_TYPE_CLASS, + r.QUARTER_SIZE) + || !r.require_integer_immediate (i + 3)) + return error_mark_node; + + return r.resolve_to (r.mode_suffix_id, type); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_lane_index (3, 4); + } +}; +SHAPE (ternary_qq_lane) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0.quarter>_t, <t0.quarter>_t) + + i.e. a version of the standard ternary shape ternary_opt_n in which + the element type of the last two arguments is the quarter-sized + equivalent of <t0>. */ +struct ternary_qq_opt_n_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,vq0,vq0", group, MODE_none); + build_all (b, "v0,v0,vq0,sq0", group, MODE_n); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (3, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES + || !r.require_derived_vector_type (i + 1, i, type, r.SAME_TYPE_CLASS, + r.QUARTER_SIZE)) + return error_mark_node; + + return r.finish_opt_n_resolution (i + 2, i, type, r.SAME_TYPE_CLASS, + r.QUARTER_SIZE); + } +}; +SHAPE (ternary_qq_opt_n) + +/* svbool_t svfoo[_<t0>](sv<t0>_t, sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument is an integer constant expression in + {0, 90, 180, 270}. */ +struct ternary_rotate_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (3, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_one_of (3, 0, 90, 180, 270); + } +}; +SHAPE (ternary_rotate) + +/* svbool_t svfoo[_<t0>](sv<t0>_t, sv<t0>_t, uint64_t) + + where the final argument is an integer constant expression in the + range [0, 7]. */ +struct tmad_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0,v0,su64", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_uniform (2, 1); + } + + bool + check (function_checker &c) const OVERRIDE + { + return c.require_immediate_range (2, 0, 7); + } +}; +SHAPE (tmad) + +/* sv<t0>_t svfoo[_t0](sv<t0>_t) + + i.e. the standard shape for unary operations that operate on + uniform types. */ +struct unary_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_unary (); + } +}; +SHAPE (unary) + +/* sv<t0>_t svfoo_t0[_t1](svbool_t, sv<t1>_t) + + where the target type <t0> must be specified explicitly but the source + type <t1> can be inferred. */ +struct unary_convert_def : public overloaded_base<1> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,v1", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_unary (r.type_suffix (0).tclass, + r.type_suffix (0).element_bits); + } +}; +SHAPE (unary_convert) + +/* sv<t0:uint>_t svfoo[_t0](sv<t0>_t) + + i.e. a version of "unary" in which the returned vector contains + unsigned integers. */ +struct unary_count_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "vu0,v0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + return r.resolve_unary (TYPE_unsigned); + } +}; +SHAPE (unary_count) + +/* sv<t0>_t svfoo[_n]_t0(<t0>_t). */ +struct unary_n_def : public overloaded_base<1> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + /* The "_n" suffix is optional; the full name has it, but the short + name doesn't. */ + build_all (b, "v0,s0", group, MODE_n, true); + } + + tree + resolve (function_resolver &) const OVERRIDE + { + /* The short forms just make "_n" implicit, so no resolution is needed. */ + gcc_unreachable (); + } +}; +SHAPE (unary_n) + +/* svbool_t svfoo(svbool_t). */ +struct unary_pred_def : public nonoverloaded_base +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + build_all (b, "v0,v0", group, MODE_none); + } +}; +SHAPE (unary_pred) + +/* sv<t0>_t svfoo[_t0](sv<t0:uint>_t) + + where <t0> always belongs a certain type class, and where <t0:uint> + therefore uniquely determines <t0>. */ +struct unary_uint_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,vu0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (1, i, nargs) + || (type = r.infer_unsigned_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + /* Search for a valid suffix with the same number of bits as TYPE. */ + unsigned int element_bits = type_suffixes[type].element_bits; + if (type_suffixes[type].unsigned_p) + for (unsigned int j = 0; j < NUM_TYPE_SUFFIXES; ++j) + if (type_suffixes[j].element_bits == element_bits) + if (tree res = r.lookup_form (r.mode_suffix_id, + type_suffix_index (j))) + return res; + + return r.report_no_such_form (type); + } +}; +SHAPE (unary_uint) + +/* sv<t0>_t svfoo[_<t0>](sv<t0:half>_t) + + i.e. a version of "unary" in which the source elements are half the + size of the destination elements, but have the same type class. */ +struct unary_widen_def : public overloaded_base<0> +{ + void + build (function_builder &b, const function_group_info &group) const OVERRIDE + { + b.add_overloaded_functions (group, MODE_none); + build_all (b, "v0,vh0", group, MODE_none); + } + + tree + resolve (function_resolver &r) const OVERRIDE + { + unsigned int i, nargs; + type_suffix_index type; + if (!r.check_gp_argument (1, i, nargs) + || (type = r.infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + /* There is only a single form for predicates. */ + if (type == TYPE_SUFFIX_b) + return r.resolve_to (r.mode_suffix_id, type); + + if (type_suffixes[type].integer_p + && type_suffixes[type].element_bits < 64) + { + type_suffix_index wide_suffix + = find_type_suffix (type_suffixes[type].tclass, + type_suffixes[type].element_bits * 2); + if (tree res = r.lookup_form (r.mode_suffix_id, wide_suffix)) + return res; + } + + return r.report_no_such_form (type); + } +}; +SHAPE (unary_widen) + +} diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.h b/gcc/config/aarch64/aarch64-sve-builtins-shapes.h new file mode 100644 index 0000000..1a102e0 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.h @@ -0,0 +1,146 @@ +/* ACLE support for AArch64 SVE (function shapes) + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_AARCH64_SVE_BUILTINS_SHAPES_H +#define GCC_AARCH64_SVE_BUILTINS_SHAPES_H + +namespace aarch64_sve +{ + /* The naming convention is: + + - to use the name of the function if the rules are very specific to + a particular function (e.g. svext, for which the range of the + final immediate value is in no way generic). + + - to use names like "unary" etc. if the rules are somewhat generic, + especially if there are no ranges involved. + + When using generic names, the handling of the final vector argument + can be modified as follows: + + - an "_n" suffix changes the argument from a vector to a scalar. + + - an "_opt_n" suffix says that there are two forms of each function: + one in which the argument is the usual vector, and one in which it + is replaced by a scalar. + + - "_int" and "_uint" replace the argument's element type with a + signed or unsigned integer of the same width. The suffixes above + then indicate whether this final argument is or might be a scalar. + + - "_int64" and "_uint64" similarly replace the argument's element type + with int64_t or uint64_t. + + - "_wide" replaces the argument's element type with a 64-bit integer + of the same signedness. This only makes sense for integer elements. + + - "_lane" indicates that the argument is indexed by a constant lane + number, provided as an immediately-following argument of type uint64_t. + + Also: + + - "inherent" means that the function takes no arguments. + + - "_rotate" means that the final argument is a rotation amount + (0, 90, 180 or 270). + + - "_scalar" indicates that all data arguments are scalars rather + than vectors. + + - in gather/scatter addresses, "sv" stands for "scalar base, + vector displacement" while "vs" stands for "vector base, + scalar displacement". + + - "_pred" indicates that the function takes an svbool_t argument + that does not act as a governing predicate.. */ + namespace shapes + { + extern const function_shape *const adr_index; + extern const function_shape *const adr_offset; + extern const function_shape *const binary; + extern const function_shape *const binary_int_opt_n; + extern const function_shape *const binary_lane; + extern const function_shape *const binary_n; + extern const function_shape *const binary_opt_n; + extern const function_shape *const binary_pred; + extern const function_shape *const binary_rotate; + extern const function_shape *const binary_scalar; + extern const function_shape *const binary_uint; + extern const function_shape *const binary_uint_n; + extern const function_shape *const binary_uint_opt_n; + extern const function_shape *const binary_uint64_n; + extern const function_shape *const binary_uint64_opt_n; + extern const function_shape *const clast; + extern const function_shape *const compare_opt_n; + extern const function_shape *const compare_scalar; + extern const function_shape *const compare_wide_opt_n; + extern const function_shape *const count_inherent; + extern const function_shape *const count_pat; + extern const function_shape *const count_pred; + extern const function_shape *const count_vector; + extern const function_shape *const create; + extern const function_shape *const dupq; + extern const function_shape *const ext; + extern const function_shape *const fold_left; + extern const function_shape *const get; + extern const function_shape *const inc_dec; + extern const function_shape *const inc_dec_pat; + extern const function_shape *const inc_dec_pred; + extern const function_shape *const inc_dec_pred_scalar; + extern const function_shape *const inherent; + extern const function_shape *const inherent_b; + extern const function_shape *const load; + extern const function_shape *const load_ext; + extern const function_shape *const load_ext_gather_index; + extern const function_shape *const load_ext_gather_offset; + extern const function_shape *const load_gather_sv; + extern const function_shape *const load_gather_vs; + extern const function_shape *const load_replicate; + extern const function_shape *const pattern_pred; + extern const function_shape *const prefetch; + extern const function_shape *const prefetch_gather_index; + extern const function_shape *const prefetch_gather_offset; + extern const function_shape *const ptest; + extern const function_shape *const rdffr; + extern const function_shape *const reduction; + extern const function_shape *const reduction_wide; + extern const function_shape *const set; + extern const function_shape *const setffr; + extern const function_shape *const shift_right_imm; + extern const function_shape *const store; + extern const function_shape *const store_scatter_index; + extern const function_shape *const store_scatter_offset; + extern const function_shape *const ternary_lane; + extern const function_shape *const ternary_lane_rotate; + extern const function_shape *const ternary_opt_n; + extern const function_shape *const ternary_qq_lane; + extern const function_shape *const ternary_qq_opt_n; + extern const function_shape *const ternary_rotate; + extern const function_shape *const tmad; + extern const function_shape *const unary; + extern const function_shape *const unary_convert; + extern const function_shape *const unary_count; + extern const function_shape *const unary_n; + extern const function_shape *const unary_pred; + extern const function_shape *const unary_uint; + extern const function_shape *const unary_widen; + } +} + +#endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc new file mode 100644 index 0000000..70d7b1a --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -0,0 +1,3313 @@ +/* ACLE support for AArch64 SVE + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "memmodel.h" +#include "insn-codes.h" +#include "optabs.h" +#include "recog.h" +#include "diagnostic.h" +#include "expr.h" +#include "basic-block.h" +#include "function.h" +#include "fold-const.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimplify.h" +#include "explow.h" +#include "emit-rtl.h" +#include "tree-vector-builder.h" +#include "stor-layout.h" +#include "regs.h" +#include "alias.h" +#include "gimple-fold.h" +#include "langhooks.h" +#include "stringpool.h" +#include "aarch64-sve-builtins.h" +#include "aarch64-sve-builtins-base.h" +#include "aarch64-sve-builtins-shapes.h" + +namespace aarch64_sve { + +/* Static information about each single-predicate or single-vector + ABI and ACLE type. */ +struct vector_type_info +{ + /* The name of the type as declared by arm_sve.h. */ + const char *acle_name; + + /* The name of the type specified in AAPCS64. The type is always + available under this name, even when arm_sve.h isn't included. */ + const char *abi_name; + + /* The C++ mangling of ABI_NAME. */ + const char *mangled_name; +}; + +/* Describes a function decl. */ +class GTY(()) registered_function +{ +public: + /* The ACLE function that the decl represents. */ + function_instance instance GTY ((skip)); + + /* The decl itself. */ + tree decl; + + /* The architecture extensions that the function requires, as a set of + AARCH64_FL_* flags. */ + uint64_t required_extensions; + + /* True if the decl represents an overloaded function that needs to be + resolved by function_resolver. */ + bool overloaded_p; +}; + +/* Hash traits for registered_function. */ +struct registered_function_hasher : nofree_ptr_hash <registered_function> +{ + typedef function_instance compare_type; + + static hashval_t hash (value_type); + static bool equal (value_type, const compare_type &); +}; + +/* Information about each single-predicate or single-vector type. */ +static CONSTEXPR const vector_type_info vector_types[] = { +#define DEF_SVE_TYPE(ACLE_NAME, NCHARS, ABI_NAME, SCALAR_TYPE) \ + { #ACLE_NAME, #ABI_NAME, #NCHARS #ABI_NAME }, +#include "aarch64-sve-builtins.def" +}; + +/* The function name suffix associated with each predication type. */ +static const char *const pred_suffixes[NUM_PREDS + 1] = { + "", + "", + "_m", + "_x", + "_z", + "" +}; + +/* Static information about each mode_suffix_index. */ +CONSTEXPR const mode_suffix_info mode_suffixes[] = { +#define VECTOR_TYPE_none NUM_VECTOR_TYPES +#define DEF_SVE_MODE(NAME, BASE, DISPLACEMENT, UNITS) \ + { "_" #NAME, VECTOR_TYPE_##BASE, VECTOR_TYPE_##DISPLACEMENT, UNITS_##UNITS }, +#include "aarch64-sve-builtins.def" +#undef VECTOR_TYPE_none + { "", NUM_VECTOR_TYPES, NUM_VECTOR_TYPES, UNITS_none } +}; + +/* Static information about each type_suffix_index. */ +CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { +#define DEF_SVE_TYPE_SUFFIX(NAME, ACLE_TYPE, CLASS, BITS, MODE) \ + { "_" #NAME, \ + VECTOR_TYPE_##ACLE_TYPE, \ + TYPE_##CLASS, \ + BITS, \ + BITS / BITS_PER_UNIT, \ + TYPE_##CLASS == TYPE_signed || TYPE_##CLASS == TYPE_unsigned, \ + TYPE_##CLASS == TYPE_unsigned, \ + TYPE_##CLASS == TYPE_float, \ + TYPE_##CLASS == TYPE_bool, \ + 0, \ + MODE }, +#include "aarch64-sve-builtins.def" + { "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false, false, + 0, VOIDmode } +}; + +/* Define a TYPES_<combination> macro for each combination of type + suffixes that an ACLE function can have, where <combination> is the + name used in DEF_SVE_FUNCTION entries. + + Use S (T) for single type suffix T and D (T1, T2) for a pair of type + suffixes T1 and T2. Use commas to separate the suffixes. + + Although the order shouldn't matter, the convention is to sort the + suffixes lexicographically after dividing suffixes into a type + class ("b", "f", etc.) and a numerical bit count. */ + +/* _b8 _b16 _b32 _b64. */ +#define TYPES_all_pred(S, D) \ + S (b8), S (b16), S (b32), S (b64) + +/* _f16 _f32 _f64. */ +#define TYPES_all_float(S, D) \ + S (f16), S (f32), S (f64) + +/* _s8 _s16 _s32 _s64. */ +#define TYPES_all_signed(S, D) \ + S (s8), S (s16), S (s32), S (s64) + +/* _f16 _f32 _f64 + _s8 _s16 _s32 _s64. */ +#define TYPES_all_float_and_signed(S, D) \ + TYPES_all_float (S, D), TYPES_all_signed (S, D) + +/* _u8 _u16 _u32 _u64. */ +#define TYPES_all_unsigned(S, D) \ + S (u8), S (u16), S (u32), S (u64) + +/* _s8 _s16 _s32 _s64 + _u8 _u16 _u32 _u64. */ +#define TYPES_all_integer(S, D) \ + TYPES_all_signed (S, D), TYPES_all_unsigned (S, D) + +/* _f16 _f32 _f64 + _s8 _s16 _s32 _s64 + _u8 _u16 _u32 _u64. */ +#define TYPES_all_data(S, D) \ + TYPES_all_float (S, D), TYPES_all_integer (S, D) + +/* _b only. */ +#define TYPES_b(S, D) \ + S (b) + +/* _s8 _s16 _s32. */ +#define TYPES_bhs_signed(S, D) \ + S (s8), S (s16), S (s32) + +/* _u8 _u16 _u32. */ +#define TYPES_bhs_unsigned(S, D) \ + S (u8), S (u16), S (u32) + +/* _s8 _s16 _s32 + _u8 _u16 _u32. */ +#define TYPES_bhs_integer(S, D) \ + TYPES_bhs_signed (S, D), TYPES_bhs_unsigned (S, D) + +/* _s16 + _u16. */ +#define TYPES_h_integer(S, D) \ + S (s16), S (u16) + +/* _f16 _f32. */ +#define TYPES_hs_float(S, D) \ + S (f16), S (f32) + +/* _s16 _s32 _s64 + _u16 _u32 _u64. */ +#define TYPES_hsd_integer(S, D) \ + S (s16), S (s32), S (s64), S (u16), S (u32), S (u64) + +/* _s32 _u32. */ +#define TYPES_s_integer(S, D) \ + S (s32), S (u32) + +/* _s32 _s64 + _u32 _u64. */ +#define TYPES_sd_integer(S, D) \ + S (s32), S (s64), S (u32), S (u64) + +/* _f32 _f64 + _s32 _s64 + _u32 _u64. */ +#define TYPES_sd_data(S, D) \ + S (f32), S (f64), TYPES_sd_integer (S, D) + +/* _f16 _f32 _f64 + _s32 _s64 + _u32 _u64. */ +#define TYPES_all_float_and_sd_integer(S, D) \ + TYPES_all_float (S, D), TYPES_sd_integer (S, D) + +/* _s64 + _u64. */ +#define TYPES_d_integer(S, D) \ + S (s64), S (u64) + +/* All the type combinations allowed by svcvt. */ +#define TYPES_cvt(S, D) \ + D (f16, f32), D (f16, f64), \ + D (f16, s16), D (f16, s32), D (f16, s64), \ + D (f16, u16), D (f16, u32), D (f16, u64), \ + \ + D (f32, f16), D (f32, f64), \ + D (f32, s32), D (f32, s64), \ + D (f32, u32), D (f32, u64), \ + \ + D (f64, f16), D (f64, f32), \ + D (f64, s32), D (f64, s64), \ + D (f64, u32), D (f64, u64), \ + \ + D (s16, f16), \ + D (s32, f16), D (s32, f32), D (s32, f64), \ + D (s64, f16), D (s64, f32), D (s64, f64), \ + \ + D (u16, f16), \ + D (u32, f16), D (u32, f32), D (u32, f64), \ + D (u64, f16), D (u64, f32), D (u64, f64) + +/* { _s32 _s64 } x { _b8 _b16 _b32 _b64 } + { _u32 _u64 }. */ +#define TYPES_inc_dec_n1(D, A) \ + D (A, b8), D (A, b16), D (A, b32), D (A, b64) +#define TYPES_inc_dec_n(S, D) \ + TYPES_inc_dec_n1 (D, s32), \ + TYPES_inc_dec_n1 (D, s64), \ + TYPES_inc_dec_n1 (D, u32), \ + TYPES_inc_dec_n1 (D, u64) + +/* { _f16 _f32 _f64 } { _f16 _f32 _f64 } + { _s8 _s16 _s32 _s64 } x { _s8 _s16 _s32 _s64 } + { _u8 _u16 _u32 _u64 } { _u8 _u16 _u32 _u64 }. */ +#define TYPES_reinterpret1(D, A) \ + D (A, f16), D (A, f32), D (A, f64), \ + D (A, s8), D (A, s16), D (A, s32), D (A, s64), \ + D (A, u8), D (A, u16), D (A, u32), D (A, u64) +#define TYPES_reinterpret(S, D) \ + TYPES_reinterpret1 (D, f16), \ + TYPES_reinterpret1 (D, f32), \ + TYPES_reinterpret1 (D, f64), \ + TYPES_reinterpret1 (D, s8), \ + TYPES_reinterpret1 (D, s16), \ + TYPES_reinterpret1 (D, s32), \ + TYPES_reinterpret1 (D, s64), \ + TYPES_reinterpret1 (D, u8), \ + TYPES_reinterpret1 (D, u16), \ + TYPES_reinterpret1 (D, u32), \ + TYPES_reinterpret1 (D, u64) + +/* { _b8 _b16 _b32 _b64 } x { _s32 _s64 } + { _u32 _u64 } */ +#define TYPES_while1(D, bn) \ + D (bn, s32), D (bn, s64), D (bn, u32), D (bn, u64) +#define TYPES_while(S, D) \ + TYPES_while1 (D, b8), \ + TYPES_while1 (D, b16), \ + TYPES_while1 (D, b32), \ + TYPES_while1 (D, b64) + +/* Describe a pair of type suffixes in which only the first is used. */ +#define DEF_VECTOR_TYPE(X) { TYPE_SUFFIX_ ## X, NUM_TYPE_SUFFIXES } + +/* Describe a pair of type suffixes in which both are used. */ +#define DEF_DOUBLE_TYPE(X, Y) { TYPE_SUFFIX_ ## X, TYPE_SUFFIX_ ## Y } + +/* Create an array that can be used in aarch64-sve-builtins.def to + select the type suffixes in TYPES_<NAME>. */ +#define DEF_SVE_TYPES_ARRAY(NAME) \ + static const type_suffix_pair types_##NAME[] = { \ + TYPES_##NAME (DEF_VECTOR_TYPE, DEF_DOUBLE_TYPE), \ + { NUM_TYPE_SUFFIXES, NUM_TYPE_SUFFIXES } \ + } + +/* For functions that don't take any type suffixes. */ +static const type_suffix_pair types_none[] = { + { NUM_TYPE_SUFFIXES, NUM_TYPE_SUFFIXES }, + { NUM_TYPE_SUFFIXES, NUM_TYPE_SUFFIXES } +}; + +/* Create an array for each TYPES_<combination> macro above. */ +DEF_SVE_TYPES_ARRAY (all_pred); +DEF_SVE_TYPES_ARRAY (all_float); +DEF_SVE_TYPES_ARRAY (all_signed); +DEF_SVE_TYPES_ARRAY (all_float_and_signed); +DEF_SVE_TYPES_ARRAY (all_unsigned); +DEF_SVE_TYPES_ARRAY (all_integer); +DEF_SVE_TYPES_ARRAY (all_data); +DEF_SVE_TYPES_ARRAY (b); +DEF_SVE_TYPES_ARRAY (bhs_signed); +DEF_SVE_TYPES_ARRAY (bhs_unsigned); +DEF_SVE_TYPES_ARRAY (bhs_integer); +DEF_SVE_TYPES_ARRAY (h_integer); +DEF_SVE_TYPES_ARRAY (hs_float); +DEF_SVE_TYPES_ARRAY (hsd_integer); +DEF_SVE_TYPES_ARRAY (s_integer); +DEF_SVE_TYPES_ARRAY (sd_integer); +DEF_SVE_TYPES_ARRAY (sd_data); +DEF_SVE_TYPES_ARRAY (all_float_and_sd_integer); +DEF_SVE_TYPES_ARRAY (d_integer); +DEF_SVE_TYPES_ARRAY (cvt); +DEF_SVE_TYPES_ARRAY (inc_dec_n); +DEF_SVE_TYPES_ARRAY (reinterpret); +DEF_SVE_TYPES_ARRAY (while); + +/* Used by functions that have no governing predicate. */ +static const predication_index preds_none[] = { PRED_none, NUM_PREDS }; + +/* Used by functions that have a governing predicate but do not have an + explicit suffix. */ +static const predication_index preds_implicit[] = { PRED_implicit, NUM_PREDS }; + +/* Used by functions that allow merging, zeroing and "don't care" + predication. */ +static const predication_index preds_mxz[] = { + PRED_m, PRED_x, PRED_z, NUM_PREDS +}; + +/* Used by functions that have the mxz predicated forms above, and in addition + have an unpredicated form. */ +static const predication_index preds_mxz_or_none[] = { + PRED_m, PRED_x, PRED_z, PRED_none, NUM_PREDS +}; + +/* Used by functions that allow merging and zeroing predication but have + no "_x" form. */ +static const predication_index preds_mz[] = { PRED_m, PRED_z, NUM_PREDS }; + +/* Used by functions that have an unpredicated form and a _z predicated + form. */ +static const predication_index preds_z_or_none[] = { + PRED_z, PRED_none, NUM_PREDS +}; + +/* Used by (mostly predicate) functions that only support "_z" predication. */ +static const predication_index preds_z[] = { PRED_z, NUM_PREDS }; + +/* A list of all SVE ACLE functions. */ +static CONSTEXPR const function_group_info function_groups[] = { +#define DEF_SVE_FUNCTION(NAME, SHAPE, TYPES, PREDS) \ + { #NAME, &functions::NAME, &shapes::SHAPE, types_##TYPES, preds_##PREDS, \ + REQUIRED_EXTENSIONS | AARCH64_FL_SVE }, +#include "aarch64-sve-builtins.def" +}; + +/* The scalar type associated with each vector type. */ +GTY(()) tree scalar_types[NUM_VECTOR_TYPES]; + +/* The single-predicate and single-vector types, with their built-in + "__SV..._t" name. Allow an index of NUM_VECTOR_TYPES, which always + yields a null tree. */ +static GTY(()) tree abi_vector_types[NUM_VECTOR_TYPES + 1]; + +/* Same, but with the arm_sve.h "sv..._t" name. */ +GTY(()) tree acle_vector_types[MAX_TUPLE_SIZE][NUM_VECTOR_TYPES + 1]; + +/* The svpattern enum type. */ +GTY(()) tree acle_svpattern; + +/* The svprfop enum type. */ +GTY(()) tree acle_svprfop; + +/* The list of all registered function decls, indexed by code. */ +static GTY(()) vec<registered_function *, va_gc> *registered_functions; + +/* All registered function decls, hashed on the function_instance + that they implement. This is used for looking up implementations of + overloaded functions. */ +static hash_table<registered_function_hasher> *function_table; + +/* True if we've already complained about attempts to use functions + when the required extension is disabled. */ +static bool reported_missing_extension_p; + +/* If TYPE is an ACLE vector type, return the associated vector_type, + otherwise return NUM_VECTOR_TYPES. */ +static vector_type_index +find_vector_type (const_tree type) +{ + /* A linear search should be OK here, since the code isn't hot and + the number of types is only small. */ + type = TYPE_MAIN_VARIANT (type); + for (unsigned int i = 0; i < NUM_VECTOR_TYPES; ++i) + if (type == abi_vector_types[i]) + return vector_type_index (i); + return NUM_VECTOR_TYPES; +} + +/* If TYPE is a valid SVE element type, return the corresponding type + suffix, otherwise return NUM_TYPE_SUFFIXES. */ +static type_suffix_index +find_type_suffix_for_scalar_type (const_tree type) +{ + /* A linear search should be OK here, since the code isn't hot and + the number of types is only small. */ + type = TYPE_MAIN_VARIANT (type); + for (unsigned int suffix_i = 0; suffix_i < NUM_TYPE_SUFFIXES; ++suffix_i) + if (!type_suffixes[suffix_i].bool_p) + { + vector_type_index vector_i = type_suffixes[suffix_i].vector_type; + if (type == TYPE_MAIN_VARIANT (scalar_types[vector_i])) + return type_suffix_index (suffix_i); + } + return NUM_TYPE_SUFFIXES; +} + +/* Report an error against LOCATION that the user has tried to use + function FNDECL when extension EXTENSION is disabled. */ +static void +report_missing_extension (location_t location, tree fndecl, + const char *extension) +{ + /* Avoid reporting a slew of messages for a single oversight. */ + if (reported_missing_extension_p) + return; + + error_at (location, "ACLE function %qD requires ISA extension %qs", + fndecl, extension); + inform (location, "you can enable %qs using the command-line" + " option %<-march%>, or by using the %<target%>" + " attribute or pragma", extension); + reported_missing_extension_p = true; +} + +/* Check whether all the AARCH64_FL_* values in REQUIRED_EXTENSIONS are + enabled, given that those extensions are required for function FNDECL. + Report an error against LOCATION if not. */ +static bool +check_required_extensions (location_t location, tree fndecl, + uint64_t required_extensions) +{ + uint64_t missing_extensions = required_extensions & ~aarch64_isa_flags; + if (missing_extensions == 0) + return true; + + static const struct { uint64_t flag; const char *name; } extensions[] = { +#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \ + SYNTHETIC, FEATURE_STRING) \ + { FLAG_CANONICAL, EXT_NAME }, +#include "aarch64-option-extensions.def" + }; + + for (unsigned int i = 0; i < ARRAY_SIZE (extensions); ++i) + if (missing_extensions & extensions[i].flag) + { + report_missing_extension (location, fndecl, extensions[i].name); + return false; + } + gcc_unreachable (); +} + +/* Report that LOCATION has a call to FNDECL in which argument ARGNO + was not an integer constant expression. ARGNO counts from zero. */ +static void +report_non_ice (location_t location, tree fndecl, unsigned int argno) +{ + error_at (location, "argument %d of %qE must be an integer constant" + " expression", argno + 1, fndecl); +} + +/* Report that LOCATION has a call to FNDECL in which argument ARGNO has + the value ACTUAL, whereas the function requires a value in the range + [MIN, MAX]. ARGNO counts from zero. */ +static void +report_out_of_range (location_t location, tree fndecl, unsigned int argno, + HOST_WIDE_INT actual, HOST_WIDE_INT min, + HOST_WIDE_INT max) +{ + error_at (location, "passing %wd to argument %d of %qE, which expects" + " a value in the range [%wd, %wd]", actual, argno + 1, fndecl, + min, max); +} + +/* Report that LOCATION has a call to FNDECL in which argument ARGNO has + the value ACTUAL, whereas the function requires either VALUE0 or + VALUE1. ARGNO counts from zero. */ +static void +report_neither_nor (location_t location, tree fndecl, unsigned int argno, + HOST_WIDE_INT actual, HOST_WIDE_INT value0, + HOST_WIDE_INT value1) +{ + error_at (location, "passing %wd to argument %d of %qE, which expects" + " either %wd or %wd", actual, argno + 1, fndecl, value0, value1); +} + +/* Report that LOCATION has a call to FNDECL in which argument ARGNO has + the value ACTUAL, whereas the function requires one of VALUE0..3. + ARGNO counts from zero. */ +static void +report_not_one_of (location_t location, tree fndecl, unsigned int argno, + HOST_WIDE_INT actual, HOST_WIDE_INT value0, + HOST_WIDE_INT value1, HOST_WIDE_INT value2, + HOST_WIDE_INT value3) +{ + error_at (location, "passing %wd to argument %d of %qE, which expects" + " %wd, %wd, %wd or %wd", actual, argno + 1, fndecl, value0, value1, + value2, value3); +} + +/* Report that LOCATION has a call to FNDECL in which argument ARGNO has + the value ACTUAL, whereas the function requires a valid value of + enum type ENUMTYPE. ARGNO counts from zero. */ +static void +report_not_enum (location_t location, tree fndecl, unsigned int argno, + HOST_WIDE_INT actual, tree enumtype) +{ + error_at (location, "passing %wd to argument %d of %qE, which expects" + " a valid %qT value", actual, argno + 1, fndecl, enumtype); +} + +/* Return a hash code for a function_instance. */ +hashval_t +function_instance::hash () const +{ + inchash::hash h; + /* BASE uniquely determines BASE_NAME, so we don't need to hash both. */ + h.add_ptr (base); + h.add_ptr (shape); + h.add_int (mode_suffix_id); + h.add_int (type_suffix_ids[0]); + h.add_int (type_suffix_ids[1]); + h.add_int (pred); + return h.end (); +} + +/* Return a set of CP_* flags that describe what the function could do, + taking the command-line flags into account. */ +unsigned int +function_instance::call_properties () const +{ + unsigned int flags = base->call_properties (*this); + + /* -fno-trapping-math means that we can assume any FP exceptions + are not user-visible. */ + if (!flag_trapping_math) + flags &= ~CP_RAISE_FP_EXCEPTIONS; + + return flags; +} + +/* Return true if calls to the function could read some form of + global state. */ +bool +function_instance::reads_global_state_p () const +{ + unsigned int flags = call_properties (); + + /* Preserve any dependence on rounding mode, flush to zero mode, etc. + There is currently no way of turning this off; in particular, + -fno-rounding-math (which is the default) means that we should make + the usual assumptions about rounding mode, which for intrinsics means + acting as the instructions do. */ + if (flags & CP_READ_FPCR) + return true; + + /* Handle direct reads of global state. */ + return flags & (CP_READ_MEMORY | CP_READ_FFR); +} + +/* Return true if calls to the function could modify some form of + global state. */ +bool +function_instance::modifies_global_state_p () const +{ + unsigned int flags = call_properties (); + + /* Preserve any exception state written back to the FPCR, + unless -fno-trapping-math says this is unnecessary. */ + if (flags & CP_RAISE_FP_EXCEPTIONS) + return true; + + /* Treat prefetches as modifying global state, since that's the + only means we have of keeping them in their correct position. */ + if (flags & CP_PREFETCH_MEMORY) + return true; + + /* Handle direct modifications of global state. */ + return flags & (CP_WRITE_MEMORY | CP_WRITE_FFR); +} + +/* Return true if calls to the function could raise a signal. */ +bool +function_instance::could_trap_p () const +{ + unsigned int flags = call_properties (); + + /* Handle functions that could raise SIGFPE. */ + if (flags & CP_RAISE_FP_EXCEPTIONS) + return true; + + /* Handle functions that could raise SIGBUS or SIGSEGV. */ + if (flags & (CP_READ_MEMORY | CP_WRITE_MEMORY)) + return true; + + return false; +} + +inline hashval_t +registered_function_hasher::hash (value_type value) +{ + return value->instance.hash (); +} + +inline bool +registered_function_hasher::equal (value_type value, const compare_type &key) +{ + return value->instance == key; +} + +sve_switcher::sve_switcher () + : m_old_isa_flags (aarch64_isa_flags) +{ + /* Changing the ISA flags and have_regs_of_mode should be enough here. + We shouldn't need to pay the compile-time cost of a full target + switch. */ + aarch64_isa_flags = (AARCH64_FL_FP | AARCH64_FL_SIMD | AARCH64_FL_F16 + | AARCH64_FL_SVE); + + memcpy (m_old_have_regs_of_mode, have_regs_of_mode, + sizeof (have_regs_of_mode)); + for (int i = 0; i < NUM_MACHINE_MODES; ++i) + if (aarch64_sve_mode_p ((machine_mode) i)) + have_regs_of_mode[i] = true; +} + +sve_switcher::~sve_switcher () +{ + memcpy (have_regs_of_mode, m_old_have_regs_of_mode, + sizeof (have_regs_of_mode)); + aarch64_isa_flags = m_old_isa_flags; +} + +function_builder::function_builder () +{ + m_overload_type = build_function_type (void_type_node, void_list_node); + m_direct_overloads = lang_GNU_CXX (); + gcc_obstack_init (&m_string_obstack); +} + +function_builder::~function_builder () +{ + obstack_free (&m_string_obstack, NULL); +} + +/* Add NAME to the end of the function name being built. */ +void +function_builder::append_name (const char *name) +{ + obstack_grow (&m_string_obstack, name, strlen (name)); +} + +/* Zero-terminate and complete the function name being built. */ +char * +function_builder::finish_name () +{ + obstack_1grow (&m_string_obstack, 0); + return (char *) obstack_finish (&m_string_obstack); +} + +/* Return the overloaded or full function name for INSTANCE; OVERLOADED_P + selects which. Allocate the string on m_string_obstack; the caller + must use obstack_free to free it after use. */ +char * +function_builder::get_name (const function_instance &instance, + bool overloaded_p) +{ + append_name (instance.base_name); + if (overloaded_p) + switch (instance.displacement_units ()) + { + case UNITS_none: + break; + + case UNITS_bytes: + append_name ("_offset"); + break; + + case UNITS_elements: + append_name ("_index"); + break; + + case UNITS_vectors: + append_name ("_vnum"); + break; + } + else + append_name (instance.mode_suffix ().string); + for (unsigned int i = 0; i < 2; ++i) + if (!overloaded_p || instance.shape->explicit_type_suffix_p (i)) + append_name (instance.type_suffix (i).string); + append_name (pred_suffixes[instance.pred]); + return finish_name (); +} + +/* Add attribute NAME to ATTRS. */ +static tree +add_attribute (const char *name, tree attrs) +{ + return tree_cons (get_identifier (name), NULL_TREE, attrs); +} + +/* Return the appropriate function attributes for INSTANCE. */ +tree +function_builder::get_attributes (const function_instance &instance) +{ + tree attrs = NULL_TREE; + + if (!instance.modifies_global_state_p ()) + { + if (instance.reads_global_state_p ()) + attrs = add_attribute ("pure", attrs); + else + attrs = add_attribute ("const", attrs); + } + + if (!flag_non_call_exceptions || !instance.could_trap_p ()) + attrs = add_attribute ("nothrow", attrs); + + return add_attribute ("leaf", attrs); +} + +/* Add a function called NAME with type FNTYPE and attributes ATTRS. + INSTANCE describes what the function does and OVERLOADED_P indicates + whether it is overloaded. REQUIRED_EXTENSIONS are the set of + architecture extensions that the function requires. */ +registered_function & +function_builder::add_function (const function_instance &instance, + const char *name, tree fntype, tree attrs, + uint64_t required_extensions, + bool overloaded_p) +{ + unsigned int code = vec_safe_length (registered_functions); + code = (code << AARCH64_BUILTIN_SHIFT) | AARCH64_BUILTIN_SVE; + tree decl = simulate_builtin_function_decl (input_location, name, fntype, + code, NULL, attrs); + + registered_function &rfn = *ggc_alloc <registered_function> (); + rfn.instance = instance; + rfn.decl = decl; + rfn.required_extensions = required_extensions; + rfn.overloaded_p = overloaded_p; + vec_safe_push (registered_functions, &rfn); + + return rfn; +} + +/* Add a built-in function for INSTANCE, with the argument types given + by ARGUMENT_TYPES and the return type given by RETURN_TYPE. + REQUIRED_EXTENSIONS are the set of architecture extensions that the + function requires. FORCE_DIRECT_OVERLOADS is true if there is a + one-to-one mapping between "short" and "full" names, and if standard + overload resolution therefore isn't necessary. */ +void +function_builder::add_unique_function (const function_instance &instance, + tree return_type, + vec<tree> &argument_types, + uint64_t required_extensions, + bool force_direct_overloads) +{ + /* Add the function under its full (unique) name. */ + char *name = get_name (instance, false); + tree fntype = build_function_type_array (return_type, + argument_types.length (), + argument_types.address ()); + tree attrs = get_attributes (instance); + registered_function &rfn = add_function (instance, name, fntype, attrs, + required_extensions, false); + + /* Enter the function into the hash table. */ + hashval_t hash = instance.hash (); + registered_function **rfn_slot + = function_table->find_slot_with_hash (instance, hash, INSERT); + gcc_assert (!*rfn_slot); + *rfn_slot = &rfn; + + /* Also add the function under its overloaded alias, if we want + a separate decl for each instance of an overloaded function. */ + if (m_direct_overloads || force_direct_overloads) + { + char *overload_name = get_name (instance, true); + if (strcmp (name, overload_name) != 0) + { + /* Attribute lists shouldn't be shared. */ + tree attrs = get_attributes (instance); + add_function (instance, overload_name, fntype, attrs, + required_extensions, false); + } + } + + obstack_free (&m_string_obstack, name); +} + +/* Add one function decl for INSTANCE, to be used with manual overload + resolution. REQUIRED_EXTENSIONS are the set of architecture extensions + that the function requires. + + For simplicity, deal with duplicate attempts to add the same + function. */ +void +function_builder::add_overloaded_function (const function_instance &instance, + uint64_t required_extensions) +{ + char *name = get_name (instance, true); + if (registered_function **map_value = m_overload_names.get (name)) + gcc_assert ((*map_value)->instance == instance + && (*map_value)->required_extensions == required_extensions); + else + { + registered_function &rfn + = add_function (instance, name, m_overload_type, NULL_TREE, + required_extensions, true); + const char *permanent_name = IDENTIFIER_POINTER (DECL_NAME (rfn.decl)); + m_overload_names.put (permanent_name, &rfn); + } + obstack_free (&m_string_obstack, name); +} + +/* If we are using manual overload resolution, add one function decl + for each overloaded function in GROUP. Take the function base name + from GROUP and the mode from MODE. */ +void +function_builder::add_overloaded_functions (const function_group_info &group, + mode_suffix_index mode) +{ + if (m_direct_overloads) + return; + + unsigned int explicit_type0 = (*group.shape)->explicit_type_suffix_p (0); + unsigned int explicit_type1 = (*group.shape)->explicit_type_suffix_p (1); + for (unsigned int pi = 0; group.preds[pi] != NUM_PREDS; ++pi) + { + if (!explicit_type0 && !explicit_type1) + { + /* Deal with the common case in which there is one overloaded + function for all type combinations. */ + function_instance instance (group.base_name, *group.base, + *group.shape, mode, types_none[0], + group.preds[pi]); + add_overloaded_function (instance, group.required_extensions); + } + else + for (unsigned int ti = 0; group.types[ti][0] != NUM_TYPE_SUFFIXES; + ++ti) + { + /* Stub out the types that are determined by overload + resolution. */ + type_suffix_pair types = { + explicit_type0 ? group.types[ti][0] : NUM_TYPE_SUFFIXES, + explicit_type1 ? group.types[ti][1] : NUM_TYPE_SUFFIXES + }; + function_instance instance (group.base_name, *group.base, + *group.shape, mode, types, + group.preds[pi]); + add_overloaded_function (instance, group.required_extensions); + } + } +} + +/* Register all the functions in GROUP. */ +void +function_builder::register_function_group (const function_group_info &group) +{ + (*group.shape)->build (*this, group); +} + +function_call_info::function_call_info (location_t location_in, + const function_instance &instance_in, + tree fndecl_in) + : function_instance (instance_in), location (location_in), fndecl (fndecl_in) +{ +} + +function_resolver::function_resolver (location_t location, + const function_instance &instance, + tree fndecl, vec<tree, va_gc> &arglist) + : function_call_info (location, instance, fndecl), m_arglist (arglist) +{ +} + +/* Return the vector type associated with type suffix TYPE. */ +tree +function_resolver::get_vector_type (type_suffix_index type) +{ + return acle_vector_types[0][type_suffixes[type].vector_type]; +} + +/* Return the <stdint.h> name associated with TYPE. Using the <stdint.h> + name should be more user-friendly than the underlying canonical type, + since it makes the signedness and bitwidth explicit. */ +const char * +function_resolver::get_scalar_type_name (type_suffix_index type) +{ + return vector_types[type_suffixes[type].vector_type].acle_name + 2; +} + +/* Return the type of argument I, or error_mark_node if it isn't + well-formed. */ +tree +function_resolver::get_argument_type (unsigned int i) +{ + tree arg = m_arglist[i]; + return arg == error_mark_node ? arg : TREE_TYPE (arg); +} + +/* Return true if argument I is some form of scalar value. */ +bool +function_resolver::scalar_argument_p (unsigned int i) +{ + tree type = get_argument_type (i); + return (INTEGRAL_TYPE_P (type) + /* Allow pointer types, leaving the frontend to warn where + necessary. */ + || POINTER_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type)); +} + +/* Report that the function has no form that takes type suffix TYPE. + Return error_mark_node. */ +tree +function_resolver::report_no_such_form (type_suffix_index type) +{ + error_at (location, "%qE has no form that takes %qT arguments", + fndecl, get_vector_type (type)); + return error_mark_node; +} + +/* Silently check whether there is an instance of the function with the + mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1. + Return its function decl if so, otherwise return null. */ +tree +function_resolver::lookup_form (mode_suffix_index mode, + type_suffix_index type0, + type_suffix_index type1) +{ + type_suffix_pair types = { type0, type1 }; + function_instance instance (base_name, base, shape, mode, types, pred); + registered_function *rfn + = function_table->find_with_hash (instance, instance.hash ()); + return rfn ? rfn->decl : NULL_TREE; +} + +/* Resolve the function to one with the mode suffix given by MODE and the + type suffixes given by TYPE0 and TYPE1. Return its function decl on + success, otherwise report an error and return error_mark_node. */ +tree +function_resolver::resolve_to (mode_suffix_index mode, + type_suffix_index type0, + type_suffix_index type1) +{ + tree res = lookup_form (mode, type0, type1); + if (!res) + { + if (type1 == NUM_TYPE_SUFFIXES) + return report_no_such_form (type0); + if (type0 == type_suffix_ids[0]) + return report_no_such_form (type1); + /* To be filled in when we have other cases. */ + gcc_unreachable (); + } + return res; +} + +/* Require argument ARGNO to be a 32-bit or 64-bit scalar integer type. + Return the associated type suffix on success, otherwise report an + error and return NUM_TYPE_SUFFIXES. */ +type_suffix_index +function_resolver::infer_integer_scalar_type (unsigned int argno) +{ + tree actual = get_argument_type (argno); + if (actual == error_mark_node) + return NUM_TYPE_SUFFIXES; + + /* Allow enums and booleans to decay to integers, for compatibility + with C++ overloading rules. */ + if (INTEGRAL_TYPE_P (actual)) + { + bool uns_p = TYPE_UNSIGNED (actual); + /* Honor the usual integer promotions, so that resolution works + in the same way as for C++. */ + if (TYPE_PRECISION (actual) < 32) + return TYPE_SUFFIX_s32; + if (TYPE_PRECISION (actual) == 32) + return uns_p ? TYPE_SUFFIX_u32 : TYPE_SUFFIX_s32; + if (TYPE_PRECISION (actual) == 64) + return uns_p ? TYPE_SUFFIX_u64 : TYPE_SUFFIX_s64; + } + + error_at (location, "passing %qT to argument %d of %qE, which expects" + " a 32-bit or 64-bit integer type", actual, argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; +} + +/* Require argument ARGNO to be a pointer to a scalar type that has a + corresponding type suffix. Return that type suffix on success, + otherwise report an error and return NUM_TYPE_SUFFIXES. + GATHER_SCATTER_P is true if the function is a gather/scatter + operation, and so requires a pointer to 32-bit or 64-bit data. */ +type_suffix_index +function_resolver::infer_pointer_type (unsigned int argno, + bool gather_scatter_p) +{ + tree actual = get_argument_type (argno); + if (actual == error_mark_node) + return NUM_TYPE_SUFFIXES; + + if (TREE_CODE (actual) != POINTER_TYPE) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a pointer type", actual, argno + 1, fndecl); + if (VECTOR_TYPE_P (actual) && gather_scatter_p) + inform (location, "an explicit type suffix is needed" + " when using a vector of base addresses"); + return NUM_TYPE_SUFFIXES; + } + + tree target = TREE_TYPE (actual); + type_suffix_index type = find_type_suffix_for_scalar_type (target); + if (type == NUM_TYPE_SUFFIXES) + { + error_at (location, "passing %qT to argument %d of %qE, but %qT is not" + " a valid SVE element type", actual, argno + 1, fndecl, + target); + return NUM_TYPE_SUFFIXES; + } + unsigned int bits = type_suffixes[type].element_bits; + if (gather_scatter_p && bits != 32 && bits != 64) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a pointer to 32-bit or 64-bit elements", + actual, argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; + } + + return type; +} + +/* Require argument ARGNO to be a single vector or a tuple of NUM_VECTORS + vectors; NUM_VECTORS is 1 for the former. Return the associated type + suffix on success, using TYPE_SUFFIX_b for predicates. Report an error + and return NUM_TYPE_SUFFIXES on failure. */ +type_suffix_index +function_resolver::infer_vector_or_tuple_type (unsigned int argno, + unsigned int num_vectors) +{ + tree actual = get_argument_type (argno); + if (actual == error_mark_node) + return NUM_TYPE_SUFFIXES; + + /* A linear search should be OK here, since the code isn't hot and + the number of types is only small. */ + for (unsigned int size_i = 0; size_i < MAX_TUPLE_SIZE; ++size_i) + for (unsigned int suffix_i = 0; suffix_i < NUM_TYPE_SUFFIXES; ++suffix_i) + { + vector_type_index type_i = type_suffixes[suffix_i].vector_type; + tree type = acle_vector_types[size_i][type_i]; + if (type && TYPE_MAIN_VARIANT (actual) == TYPE_MAIN_VARIANT (type)) + { + if (size_i + 1 == num_vectors) + return type_suffix_index (suffix_i); + + if (num_vectors == 1) + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a single SVE vector rather than a tuple", + actual, argno + 1, fndecl); + else if (size_i == 0 && type_i != VECTOR_TYPE_svbool_t) + error_at (location, "passing single vector %qT to argument %d" + " of %qE, which expects a tuple of %d vectors", + actual, argno + 1, fndecl, num_vectors); + else + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a tuple of %d vectors", actual, argno + 1, + fndecl, num_vectors); + return NUM_TYPE_SUFFIXES; + } + } + + if (num_vectors == 1) + error_at (location, "passing %qT to argument %d of %qE, which" + " expects an SVE vector type", actual, argno + 1, fndecl); + else + error_at (location, "passing %qT to argument %d of %qE, which" + " expects an SVE tuple type", actual, argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; +} + +/* Require argument ARGNO to have some form of vector type. Return the + associated type suffix on success, using TYPE_SUFFIX_b for predicates. + Report an error and return NUM_TYPE_SUFFIXES on failure. */ +type_suffix_index +function_resolver::infer_vector_type (unsigned int argno) +{ + return infer_vector_or_tuple_type (argno, 1); +} + +/* Like infer_vector_type, but also require the type to be integral. */ +type_suffix_index +function_resolver::infer_integer_vector_type (unsigned int argno) +{ + type_suffix_index type = infer_vector_type (argno); + if (type == NUM_TYPE_SUFFIXES) + return type; + + if (!type_suffixes[type].integer_p) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of integers", get_argument_type (argno), + argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; + } + + return type; +} + +/* Like infer_vector_type, but also require the type to be an unsigned + integer. */ +type_suffix_index +function_resolver::infer_unsigned_vector_type (unsigned int argno) +{ + type_suffix_index type = infer_vector_type (argno); + if (type == NUM_TYPE_SUFFIXES) + return type; + + if (!type_suffixes[type].unsigned_p) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of unsigned integers", + get_argument_type (argno), argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; + } + + return type; +} + +/* Like infer_vector_type, but also require the element size to be + 32 or 64 bits. */ +type_suffix_index +function_resolver::infer_sd_vector_type (unsigned int argno) +{ + type_suffix_index type = infer_vector_type (argno); + if (type == NUM_TYPE_SUFFIXES) + return type; + + unsigned int bits = type_suffixes[type].element_bits; + if (bits != 32 && bits != 64) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of 32-bit or 64-bit elements", + get_argument_type (argno), argno + 1, fndecl); + return NUM_TYPE_SUFFIXES; + } + + return type; +} + +/* If the function operates on tuples of vectors, require argument ARGNO to be + a tuple with the appropriate number of vectors, otherwise require it to be + a single vector. Return the associated type suffix on success, using + TYPE_SUFFIX_b for predicates. Report an error and return NUM_TYPE_SUFFIXES + on failure. */ +type_suffix_index +function_resolver::infer_tuple_type (unsigned int argno) +{ + return infer_vector_or_tuple_type (argno, vectors_per_tuple ()); +} + +/* Require argument ARGNO to be a vector or scalar argument. Return true + if it is, otherwise report an appropriate error. */ +bool +function_resolver::require_vector_or_scalar_type (unsigned int argno) +{ + tree actual = get_argument_type (argno); + if (actual == error_mark_node) + return false; + + if (!scalar_argument_p (argno) && !VECTOR_TYPE_P (actual)) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector or scalar type", actual, argno + 1, fndecl); + return false; + } + + return true; +} + +/* Require argument ARGNO to have vector type TYPE, in cases where this + requirement holds for all uses of the function. Return true if the + argument has the right form, otherwise report an appropriate error. */ +bool +function_resolver::require_vector_type (unsigned int argno, + vector_type_index type) +{ + tree expected = acle_vector_types[0][type]; + tree actual = get_argument_type (argno); + if (actual != error_mark_node + && TYPE_MAIN_VARIANT (expected) != TYPE_MAIN_VARIANT (actual)) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects %qT", actual, argno + 1, fndecl, expected); + return false; + } + return true; +} + +/* Like require_vector_type, but TYPE is inferred from previous arguments + rather than being a fixed part of the function signature. This changes + the nature of the error messages. */ +bool +function_resolver::require_matching_vector_type (unsigned int argno, + type_suffix_index type) +{ + type_suffix_index new_type = infer_vector_type (argno); + if (new_type == NUM_TYPE_SUFFIXES) + return false; + + if (type != new_type) + { + error_at (location, "passing %qT to argument %d of %qE, but" + " previous arguments had type %qT", + get_vector_type (new_type), argno + 1, fndecl, + get_vector_type (type)); + return false; + } + return true; +} + +/* Require argument ARGNO to be a vector type with the following properties: + + - the type class must be the same as FIRST_TYPE's if EXPECTED_TCLASS + is SAME_TYPE_CLASS, otherwise it must be EXPECTED_TCLASS itself. + + - the element size must be: + + - the same as FIRST_TYPE's if EXPECTED_BITS == SAME_SIZE + - half of FIRST_TYPE's if EXPECTED_BITS == HALF_SIZE + - a quarter of FIRST_TYPE's if EXPECTED_BITS == QUARTER_SIZE + - EXPECTED_BITS itself otherwise + + Return true if the argument has the required type, otherwise report + an appropriate error. + + FIRST_ARGNO is the first argument that is known to have type FIRST_TYPE. + Usually it comes before ARGNO, but sometimes it is more natural to resolve + arguments out of order. + + If the required properties depend on FIRST_TYPE then both FIRST_ARGNO and + ARGNO contribute to the resolution process. If the required properties + are fixed, only FIRST_ARGNO contributes to the resolution process. + + This function is a bit of a Swiss army knife. The complication comes + from trying to give good error messages when FIRST_ARGNO and ARGNO are + inconsistent, since either of them might be wrong. */ +bool function_resolver:: +require_derived_vector_type (unsigned int argno, + unsigned int first_argno, + type_suffix_index first_type, + type_class_index expected_tclass, + unsigned int expected_bits) +{ + /* If the type needs to match FIRST_ARGNO exactly, use the preferred + error message for that case. The VECTOR_TYPE_P test excludes tuple + types, which we handle below instead. */ + bool both_vectors_p = VECTOR_TYPE_P (get_argument_type (first_argno)); + if (both_vectors_p + && expected_tclass == SAME_TYPE_CLASS + && expected_bits == SAME_SIZE) + { + /* There's no need to resolve this case out of order. */ + gcc_assert (argno > first_argno); + return require_matching_vector_type (argno, first_type); + } + + /* Use FIRST_TYPE to get the expected type class and element size. */ + type_class_index orig_expected_tclass = expected_tclass; + if (expected_tclass == NUM_TYPE_CLASSES) + expected_tclass = type_suffixes[first_type].tclass; + + unsigned int orig_expected_bits = expected_bits; + if (expected_bits == SAME_SIZE) + expected_bits = type_suffixes[first_type].element_bits; + else if (expected_bits == HALF_SIZE) + expected_bits = type_suffixes[first_type].element_bits / 2; + else if (expected_bits == QUARTER_SIZE) + expected_bits = type_suffixes[first_type].element_bits / 4; + + /* If the expected type doesn't depend on FIRST_TYPE at all, + just check for the fixed choice of vector type. */ + if (expected_tclass == orig_expected_tclass + && expected_bits == orig_expected_bits) + { + const type_suffix_info &expected_suffix + = type_suffixes[find_type_suffix (expected_tclass, expected_bits)]; + return require_vector_type (argno, expected_suffix.vector_type); + } + + /* Require the argument to be some form of SVE vector type, + without being specific about the type of vector we want. */ + type_suffix_index actual_type = infer_vector_type (argno); + if (actual_type == NUM_TYPE_SUFFIXES) + return false; + + /* Exit now if we got the right type. */ + bool tclass_ok_p = (type_suffixes[actual_type].tclass == expected_tclass); + bool size_ok_p = (type_suffixes[actual_type].element_bits == expected_bits); + if (tclass_ok_p && size_ok_p) + return true; + + /* First look for cases in which the actual type contravenes a fixed + size requirement, without having to refer to FIRST_TYPE. */ + if (!size_ok_p && expected_bits == orig_expected_bits) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of %d-bit elements", + get_vector_type (actual_type), argno + 1, fndecl, + expected_bits); + return false; + } + + /* Likewise for a fixed type class requirement. This is only ever + needed for signed and unsigned types, so don't create unnecessary + translation work for other type classes. */ + if (!tclass_ok_p && orig_expected_tclass == TYPE_signed) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of signed integers", + get_vector_type (actual_type), argno + 1, fndecl); + return false; + } + if (!tclass_ok_p && orig_expected_tclass == TYPE_unsigned) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of unsigned integers", + get_vector_type (actual_type), argno + 1, fndecl); + return false; + } + + /* Make sure that FIRST_TYPE itself is sensible before using it + as a basis for an error message. */ + if (resolve_to (mode_suffix_id, first_type) == error_mark_node) + return false; + + /* If the arguments have consistent type classes, but a link between + the sizes has been broken, try to describe the error in those terms. */ + if (both_vectors_p && tclass_ok_p && orig_expected_bits == SAME_SIZE) + { + if (argno < first_argno) + { + std::swap (argno, first_argno); + std::swap (actual_type, first_type); + } + error_at (location, "arguments %d and %d of %qE must have the" + " same element size, but the values passed here have type" + " %qT and %qT respectively", first_argno + 1, argno + 1, + fndecl, get_vector_type (first_type), + get_vector_type (actual_type)); + return false; + } + + /* Likewise in reverse: look for cases in which the sizes are consistent + but a link between the type classes has been broken. */ + if (both_vectors_p + && size_ok_p + && orig_expected_tclass == SAME_TYPE_CLASS + && type_suffixes[first_type].integer_p + && type_suffixes[actual_type].integer_p) + { + if (argno < first_argno) + { + std::swap (argno, first_argno); + std::swap (actual_type, first_type); + } + error_at (location, "arguments %d and %d of %qE must have the" + " same signedness, but the values passed here have type" + " %qT and %qT respectively", first_argno + 1, argno + 1, + fndecl, get_vector_type (first_type), + get_vector_type (actual_type)); + return false; + } + + /* The two arguments are wildly inconsistent. */ + type_suffix_index expected_type + = find_type_suffix (expected_tclass, expected_bits); + error_at (location, "passing %qT instead of the expected %qT to argument" + " %d of %qE, after passing %qT to argument %d", + get_vector_type (actual_type), get_vector_type (expected_type), + argno + 1, fndecl, get_argument_type (first_argno), + first_argno + 1); + return false; +} + +/* Require argument ARGNO to be a (possibly variable) scalar, using EXPECTED + as the name of its expected type. Return true if the argument has the + right form, otherwise report an appropriate error. */ +bool +function_resolver::require_scalar_type (unsigned int argno, + const char *expected) +{ + if (!scalar_argument_p (argno)) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects %qs", get_argument_type (argno), argno + 1, + fndecl, expected); + return false; + } + return true; +} + +/* Require argument ARGNO to be some form of pointer, without being specific + about its target type. Return true if the argument has the right form, + otherwise report an appropriate error. */ +bool +function_resolver::require_pointer_type (unsigned int argno) +{ + if (!scalar_argument_p (argno)) + { + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a scalar pointer", get_argument_type (argno), + argno + 1, fndecl); + return false; + } + return true; +} + +/* Argument FIRST_ARGNO is a scalar with type EXPECTED_TYPE, and argument + ARGNO should be consistent with it. Return true if it is, otherwise + report an appropriate error. */ +bool function_resolver:: +require_matching_integer_scalar_type (unsigned int argno, + unsigned int first_argno, + type_suffix_index expected_type) +{ + type_suffix_index actual_type = infer_integer_scalar_type (argno); + if (actual_type == NUM_TYPE_SUFFIXES) + return false; + + if (actual_type == expected_type) + return true; + + error_at (location, "call to %qE is ambiguous; argument %d has type" + " %qs but argument %d has type %qs", fndecl, + first_argno + 1, get_scalar_type_name (expected_type), + argno + 1, get_scalar_type_name (actual_type)); + return false; +} + +/* Require argument ARGNO to be a (possibly variable) scalar, expecting it + to have the following properties: + + - the type class must be the same as for type suffix 0 if EXPECTED_TCLASS + is SAME_TYPE_CLASS, otherwise it must be EXPECTED_TCLASS itself. + + - the element size must be the same as for type suffix 0 if EXPECTED_BITS + is SAME_TYPE_SIZE, otherwise it must be EXPECTED_BITS itself. + + Return true if the argument is valid, otherwise report an appropriate error. + + Note that we don't check whether the scalar type actually has the required + properties, since that's subject to implicit promotions and conversions. + Instead we just use the expected properties to tune the error message. */ +bool function_resolver:: +require_derived_scalar_type (unsigned int argno, + type_class_index expected_tclass, + unsigned int expected_bits) +{ + gcc_assert (expected_tclass == SAME_TYPE_CLASS + || expected_tclass == TYPE_signed + || expected_tclass == TYPE_unsigned); + + /* If the expected type doesn't depend on the type suffix at all, + just check for the fixed choice of scalar type. */ + if (expected_tclass != SAME_TYPE_CLASS && expected_bits != SAME_SIZE) + { + type_suffix_index expected_type + = find_type_suffix (expected_tclass, expected_bits); + return require_scalar_type (argno, get_scalar_type_name (expected_type)); + } + + if (scalar_argument_p (argno)) + return true; + + if (expected_tclass == SAME_TYPE_CLASS) + /* It doesn't really matter whether the element is expected to be + the same size as type suffix 0. */ + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a scalar element", get_argument_type (argno), + argno + 1, fndecl); + else + /* It doesn't seem useful to distinguish between signed and unsigned + scalars here. */ + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a scalar integer", get_argument_type (argno), + argno + 1, fndecl); + return false; +} + +/* Require argument ARGNO to be suitable for an integer constant expression. + Return true if it is, otherwise report an appropriate error. + + function_checker checks whether the argument is actually constant and + has a suitable range. The reason for distinguishing immediate arguments + here is because it provides more consistent error messages than + require_scalar_type would. */ +bool +function_resolver::require_integer_immediate (unsigned int argno) +{ + if (!scalar_argument_p (argno)) + { + report_non_ice (location, fndecl, argno); + return false; + } + return true; +} + +/* Require argument ARGNO to be a vector base in a gather-style address. + Return its type on success, otherwise return NUM_VECTOR_TYPES. */ +vector_type_index +function_resolver::infer_vector_base_type (unsigned int argno) +{ + type_suffix_index type = infer_vector_type (argno); + if (type == NUM_TYPE_SUFFIXES) + return NUM_VECTOR_TYPES; + + if (type == TYPE_SUFFIX_u32 || type == TYPE_SUFFIX_u64) + return type_suffixes[type].vector_type; + + error_at (location, "passing %qT to argument %d of %qE, which" + " expects %qs or %qs", get_argument_type (argno), + argno + 1, fndecl, "svuint32_t", "svuint64_t"); + return NUM_VECTOR_TYPES; +} + +/* Require argument ARGNO to be a vector displacement in a gather-style + address. Return its type on success, otherwise return NUM_VECTOR_TYPES. */ +vector_type_index +function_resolver::infer_vector_displacement_type (unsigned int argno) +{ + type_suffix_index type = infer_integer_vector_type (argno); + if (type == NUM_TYPE_SUFFIXES) + return NUM_VECTOR_TYPES; + + if (type_suffixes[type].integer_p + && (type_suffixes[type].element_bits == 32 + || type_suffixes[type].element_bits == 64)) + return type_suffixes[type].vector_type; + + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of 32-bit or 64-bit integers", + get_argument_type (argno), argno + 1, fndecl); + return NUM_VECTOR_TYPES; +} + +/* Require argument ARGNO to be a vector displacement in a gather-style + address. There are three possible uses: + + - for loading into elements of type TYPE (when LOAD_P is true) + - for storing from elements of type TYPE (when LOAD_P is false) + - for prefetching data (when TYPE is NUM_TYPE_SUFFIXES) + + The overloaded function's mode suffix determines the units of the + displacement (bytes for "_offset", elements for "_index"). + + Return the associated mode on success, otherwise report an error + and return MODE_none. */ +mode_suffix_index +function_resolver::resolve_sv_displacement (unsigned int argno, + type_suffix_index type, + bool load_p) +{ + if (type == NUM_TYPE_SUFFIXES) + { + /* For prefetches, the base is a void pointer and the displacement + can be any valid offset or index type. */ + vector_type_index displacement_vector_type + = infer_vector_displacement_type (argno); + if (displacement_vector_type == NUM_VECTOR_TYPES) + return MODE_none; + + mode_suffix_index mode = find_mode_suffix (NUM_VECTOR_TYPES, + displacement_vector_type, + displacement_units ()); + gcc_assert (mode != MODE_none); + return mode; + } + + /* Check for some form of vector type, without naming any in particular + as being expected. */ + type_suffix_index displacement_type = infer_vector_type (argno); + if (displacement_type == NUM_TYPE_SUFFIXES) + return MODE_none; + + /* If the displacement type is consistent with the data vector type, + try to find the associated mode suffix. This will fall through + for non-integral displacement types. */ + unsigned int required_bits = type_suffixes[type].element_bits; + if (type_suffixes[displacement_type].element_bits == required_bits) + { + vector_type_index displacement_vector_type + = type_suffixes[displacement_type].vector_type; + mode_suffix_index mode = find_mode_suffix (NUM_VECTOR_TYPES, + displacement_vector_type, + displacement_units ()); + if (mode != MODE_none) + return mode; + } + + if (type_suffix_ids[0] == NUM_TYPE_SUFFIXES) + { + /* TYPE has been inferred rather than specified by the user, + so mention it in the error messages. */ + if (load_p) + error_at (location, "passing %qT to argument %d of %qE, which when" + " loading %qT expects a vector of %d-bit integers", + get_argument_type (argno), argno + 1, fndecl, + get_vector_type (type), required_bits); + else + error_at (location, "passing %qT to argument %d of %qE, which when" + " storing %qT expects a vector of %d-bit integers", + get_argument_type (argno), argno + 1, fndecl, + get_vector_type (type), required_bits); + } + else + /* TYPE is part of the function name. */ + error_at (location, "passing %qT to argument %d of %qE, which" + " expects a vector of %d-bit integers", + get_argument_type (argno), argno + 1, fndecl, required_bits); + return MODE_none; +} + +/* Require the arguments starting at ARGNO to form a gather-style address. + There are three possible uses: + + - for loading into elements of type TYPE (when LOAD_P is true) + - for storing from elements of type TYPE (when LOAD_P is false) + - for prefetching data (when TYPE is NUM_TYPE_SUFFIXES) + + The three possible addresses are: + + - a vector base with no displacement + - a vector base and a scalar displacement + - a scalar (pointer) base and a vector displacement + + The overloaded function's mode suffix determines whether there is + a displacement, and if so, what units it uses: + + - MODE_none: no displacement + - MODE_offset: the displacement is measured in bytes + - MODE_index: the displacement is measured in elements + + Return the mode of the non-overloaded function on success, otherwise + report an error and return MODE_none. */ +mode_suffix_index +function_resolver::resolve_gather_address (unsigned int argno, + type_suffix_index type, + bool load_p) +{ + tree actual = get_argument_type (argno); + if (actual == error_mark_node) + return MODE_none; + + if (displacement_units () != UNITS_none) + { + /* Some form of displacement is needed. First handle a scalar + pointer base and a vector displacement. */ + if (scalar_argument_p (argno)) + /* Don't check the pointer type here, since there's only one valid + choice. Leave that to the frontend. */ + return resolve_sv_displacement (argno + 1, type, load_p); + + if (!VECTOR_TYPE_P (actual)) + { + error_at (location, "passing %qT to argument %d of %qE," + " which expects a vector or pointer base address", + actual, argno + 1, fndecl); + return MODE_none; + } + } + + /* Check for the correct choice of vector base type. */ + vector_type_index base_vector_type; + if (type == NUM_TYPE_SUFFIXES) + { + /* Since prefetches have no type suffix, there is a free choice + between 32-bit and 64-bit base addresses. */ + base_vector_type = infer_vector_base_type (argno); + if (base_vector_type == NUM_VECTOR_TYPES) + return MODE_none; + } + else + { + /* Check for some form of vector type, without saying which type + we expect. */ + type_suffix_index base_type = infer_vector_type (argno); + if (base_type == NUM_TYPE_SUFFIXES) + return MODE_none; + + /* Check whether the type is the right one. */ + unsigned int required_bits = type_suffixes[type].element_bits; + gcc_assert (required_bits == 32 || required_bits == 64); + type_suffix_index required_type = (required_bits == 32 + ? TYPE_SUFFIX_u32 + : TYPE_SUFFIX_u64); + if (required_type != base_type) + { + error_at (location, "passing %qT to argument %d of %qE," + " which expects %qT", actual, argno + 1, fndecl, + get_vector_type (required_type)); + return MODE_none; + } + base_vector_type = type_suffixes[base_type].vector_type; + } + + /* Check the scalar displacement, if any. */ + if (displacement_units () != UNITS_none + && !require_scalar_type (argno + 1, "int64_t")) + return MODE_none; + + /* Find the appropriate mode suffix. The checks above should have + weeded out all erroneous cases. */ + for (unsigned int mode_i = 0; mode_i < ARRAY_SIZE (mode_suffixes); ++mode_i) + { + const mode_suffix_info &mode = mode_suffixes[mode_i]; + if (mode.base_vector_type == base_vector_type + && mode.displacement_vector_type == NUM_VECTOR_TYPES + && mode.displacement_units == displacement_units ()) + return mode_suffix_index (mode_i); + } + + gcc_unreachable (); +} + +/* Require arguments ARGNO and ARGNO + 1 to form an ADR-style address, + i.e. one with a vector of base addresses and a vector of displacements. + The overloaded function's mode suffix determines the units of the + displacement (bytes for "_offset", elements for "_index"). + + Return the associated mode suffix on success, otherwise report + an error and return MODE_none. */ +mode_suffix_index +function_resolver::resolve_adr_address (unsigned int argno) +{ + vector_type_index base_type = infer_vector_base_type (argno); + if (base_type == NUM_VECTOR_TYPES) + return MODE_none; + + vector_type_index displacement_type + = infer_vector_displacement_type (argno + 1); + if (displacement_type == NUM_VECTOR_TYPES) + return MODE_none; + + mode_suffix_index mode = find_mode_suffix (base_type, displacement_type, + displacement_units ()); + if (mode == MODE_none) + { + if (mode_suffix_id == MODE_offset) + error_at (location, "cannot combine a base of type %qT with" + " an offset of type %qT", + get_argument_type (argno), get_argument_type (argno + 1)); + else + error_at (location, "cannot combine a base of type %qT with" + " an index of type %qT", + get_argument_type (argno), get_argument_type (argno + 1)); + } + return mode; +} + +/* Require the function to have exactly EXPECTED arguments. Return true + if it does, otherwise report an appropriate error. */ +bool +function_resolver::check_num_arguments (unsigned int expected) +{ + if (m_arglist.length () < expected) + error_at (location, "too few arguments to function %qE", fndecl); + else if (m_arglist.length () > expected) + error_at (location, "too many arguments to function %qE", fndecl); + return m_arglist.length () == expected; +} + +/* If the function is predicated, check that the first argument is a + suitable governing predicate. Also check that there are NOPS further + arguments after any governing predicate, but don't check what they are. + + Return true on success, otherwise report a suitable error. + When returning true: + + - set I to the number of the first unchecked argument. + - set NARGS to the total number of arguments. */ +bool +function_resolver::check_gp_argument (unsigned int nops, + unsigned int &i, unsigned int &nargs) +{ + i = 0; + if (pred != PRED_none) + { + /* Unary merge operations should use resolve_unary instead. */ + gcc_assert (nops != 1 || pred != PRED_m); + nargs = nops + 1; + if (!check_num_arguments (nargs) + || !require_vector_type (i, VECTOR_TYPE_svbool_t)) + return false; + i += 1; + } + else + { + nargs = nops; + if (!check_num_arguments (nargs)) + return false; + } + + return true; +} + +/* Finish resolving a function whose final argument can be a vector + or a scalar, with the function having an implicit "_n" suffix + in the latter case. This "_n" form might only exist for certain + type suffixes. + + ARGNO is the index of the final argument. The inferred type + suffix is FIRST_TYPE, which was obtained from argument FIRST_ARGNO. + EXPECTED_TCLASS and EXPECTED_BITS describe the expected properties + of the final vector or scalar argument, in the same way as for + require_derived_vector_type. + + Return the function decl of the resolved function on success, + otherwise report a suitable error and return error_mark_node. */ +tree function_resolver:: +finish_opt_n_resolution (unsigned int argno, unsigned int first_argno, + type_suffix_index first_type, + type_class_index expected_tclass, + unsigned int expected_bits) +{ + tree scalar_form = lookup_form (MODE_n, first_type); + + /* Allow the final argument to be scalar, if an _n form exists. */ + if (scalar_argument_p (argno)) + { + if (scalar_form) + return scalar_form; + + /* Check the vector form normally. If that succeeds, raise an + error about having no corresponding _n form. */ + tree res = resolve_to (mode_suffix_id, first_type); + if (res != error_mark_node) + error_at (location, "passing %qT to argument %d of %qE, but its" + " %qT form does not accept scalars", + get_argument_type (argno), argno + 1, fndecl, + get_vector_type (first_type)); + return error_mark_node; + } + + /* If an _n form does exist, provide a more accurate message than + require_derived_vector_type would for arguments that are neither + vectors nor scalars. */ + if (scalar_form && !require_vector_or_scalar_type (argno)) + return error_mark_node; + + /* Check for the correct vector type. */ + if (!require_derived_vector_type (argno, first_argno, first_type, + expected_tclass, expected_bits)) + return error_mark_node; + + return resolve_to (mode_suffix_id, first_type); +} + +/* Resolve a (possibly predicated) unary function. If the function uses + merge predication, there is an extra vector argument before the + governing predicate that specifies the values of inactive elements. + This argument has the following properties: + + - the type class must be the same as for active elements if MERGE_TCLASS + is SAME_TYPE_CLASS, otherwise it must be MERGE_TCLASS itself. + + - the element size must be the same as for active elements if MERGE_BITS + is SAME_TYPE_SIZE, otherwise it must be MERGE_BITS itself. + + Return the function decl of the resolved function on success, + otherwise report a suitable error and return error_mark_node. */ +tree +function_resolver::resolve_unary (type_class_index merge_tclass, + unsigned int merge_bits) +{ + type_suffix_index type; + if (pred == PRED_m) + { + if (!check_num_arguments (3)) + return error_mark_node; + if (merge_tclass == SAME_TYPE_CLASS && merge_bits == SAME_SIZE) + { + /* The inactive elements are the same as the active elements, + so we can use normal left-to-right resolution. */ + if ((type = infer_vector_type (0)) == NUM_TYPE_SUFFIXES + || !require_vector_type (1, VECTOR_TYPE_svbool_t) + || !require_matching_vector_type (2, type)) + return error_mark_node; + } + else + { + /* The inactive element type is a function of the active one, + so resolve the active one first. */ + if (!require_vector_type (1, VECTOR_TYPE_svbool_t) + || (type = infer_vector_type (2)) == NUM_TYPE_SUFFIXES + || !require_derived_vector_type (0, 2, type, merge_tclass, + merge_bits)) + return error_mark_node; + } + } + else + { + /* We just need to check the predicate (if any) and the single + vector argument. */ + unsigned int i, nargs; + if (!check_gp_argument (1, i, nargs) + || (type = infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + } + + /* Handle convert-like functions in which the first type suffix is + explicit. */ + if (type_suffix_ids[0] != NUM_TYPE_SUFFIXES) + return resolve_to (mode_suffix_id, type_suffix_ids[0], type); + + return resolve_to (mode_suffix_id, type); +} + +/* Resolve a (possibly predicated) function that takes NOPS like-typed + vector arguments followed by NIMM integer immediates. Return the + function decl of the resolved function on success, otherwise report + a suitable error and return error_mark_node. */ +tree +function_resolver::resolve_uniform (unsigned int nops, unsigned int nimm) +{ + unsigned int i, nargs; + type_suffix_index type; + if (!check_gp_argument (nops + nimm, i, nargs) + || (type = infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + i += 1; + for (; i < nargs - nimm; ++i) + if (!require_matching_vector_type (i, type)) + return error_mark_node; + + for (; i < nargs; ++i) + if (!require_integer_immediate (i)) + return error_mark_node; + + return resolve_to (mode_suffix_id, type); +} + +/* Resolve a (possibly predicated) function that offers a choice between + taking: + + - NOPS like-typed vector arguments or + - NOPS - 1 like-typed vector arguments followed by a scalar argument + + Return the function decl of the resolved function on success, + otherwise report a suitable error and return error_mark_node. */ +tree +function_resolver::resolve_uniform_opt_n (unsigned int nops) +{ + unsigned int i, nargs; + type_suffix_index type; + if (!check_gp_argument (nops, i, nargs) + || (type = infer_vector_type (i)) == NUM_TYPE_SUFFIXES) + return error_mark_node; + + unsigned int first_arg = i++; + for (; i < nargs - 1; ++i) + if (!require_matching_vector_type (i, type)) + return error_mark_node; + + return finish_opt_n_resolution (i, first_arg, type); +} + +/* If the call is erroneous, report an appropriate error and return + error_mark_node. Otherwise, if the function is overloaded, return + the decl of the non-overloaded function. Return NULL_TREE otherwise, + indicating that the call should be processed in the normal way. */ +tree +function_resolver::resolve () +{ + return shape->resolve (*this); +} + +function_checker::function_checker (location_t location, + const function_instance &instance, + tree fndecl, tree fntype, + unsigned int nargs, tree *args) + : function_call_info (location, instance, fndecl), + m_fntype (fntype), m_nargs (nargs), m_args (args), + /* We don't have to worry about unary _m operations here, since they + never have arguments that need checking. */ + m_base_arg (pred != PRED_none ? 1 : 0) +{ +} + +/* Return true if argument ARGNO exists. which it might not for + erroneous calls. It is safe to wave through checks if this + function returns false. */ +bool +function_checker::argument_exists_p (unsigned int argno) +{ + gcc_assert (argno < (unsigned int) type_num_arguments (m_fntype)); + return argno < m_nargs; +} + +/* Check that argument ARGNO is an integer constant expression and + store its value in VALUE_OUT if so. The caller should first + check that argument ARGNO exists. */ +bool +function_checker::require_immediate (unsigned int argno, + HOST_WIDE_INT &value_out) +{ + gcc_assert (argno < m_nargs); + tree arg = m_args[argno]; + + /* The type and range are unsigned, so read the argument as an + unsigned rather than signed HWI. */ + if (!tree_fits_uhwi_p (arg)) + { + report_non_ice (location, fndecl, argno); + return false; + } + + /* ...but treat VALUE_OUT as signed for error reporting, since printing + -1 is more user-friendly than the maximum uint64_t value. */ + value_out = tree_to_uhwi (arg); + return true; +} + +/* Check that argument REL_ARGNO is an integer constant expression that + has the value VALUE0 or VALUE1. REL_ARGNO counts from the end of the + predication arguments. */ +bool +function_checker::require_immediate_either_or (unsigned int rel_argno, + HOST_WIDE_INT value0, + HOST_WIDE_INT value1) +{ + unsigned int argno = m_base_arg + rel_argno; + if (!argument_exists_p (argno)) + return true; + + HOST_WIDE_INT actual; + if (!require_immediate (argno, actual)) + return false; + + if (actual != value0 && actual != value1) + { + report_neither_nor (location, fndecl, argno, actual, 90, 270); + return false; + } + + return true; +} + +/* Check that argument REL_ARGNO is an integer constant expression that has + a valid value for enumeration type TYPE. REL_ARGNO counts from the end + of the predication arguments. */ +bool +function_checker::require_immediate_enum (unsigned int rel_argno, tree type) +{ + unsigned int argno = m_base_arg + rel_argno; + if (!argument_exists_p (argno)) + return true; + + HOST_WIDE_INT actual; + if (!require_immediate (argno, actual)) + return false; + + for (tree entry = TYPE_VALUES (type); entry; entry = TREE_CHAIN (entry)) + { + /* The value is an INTEGER_CST for C and a CONST_DECL wrapper + around an INTEGER_CST for C++. */ + tree value = TREE_VALUE (entry); + if (TREE_CODE (value) == CONST_DECL) + value = DECL_INITIAL (value); + if (wi::to_widest (value) == actual) + return true; + } + + report_not_enum (location, fndecl, argno, actual, type); + return false; +} + +/* Check that argument REL_ARGNO is suitable for indexing argument + REL_ARGNO - 1, in groups of GROUP_SIZE elements. REL_ARGNO counts + from the end of the predication arguments. */ +bool +function_checker::require_immediate_lane_index (unsigned int rel_argno, + unsigned int group_size) +{ + unsigned int argno = m_base_arg + rel_argno; + if (!argument_exists_p (argno)) + return true; + + /* Get the type of the previous argument. tree_argument_type wants a + 1-based number, whereas ARGNO is 0-based. */ + machine_mode mode = TYPE_MODE (type_argument_type (m_fntype, argno)); + gcc_assert (VECTOR_MODE_P (mode)); + unsigned int nlanes = 128 / (group_size * GET_MODE_UNIT_BITSIZE (mode)); + return require_immediate_range (rel_argno, 0, nlanes - 1); +} + +/* Check that argument REL_ARGNO is an integer constant expression that + has one of the given values. */ +bool +function_checker::require_immediate_one_of (unsigned int rel_argno, + HOST_WIDE_INT value0, + HOST_WIDE_INT value1, + HOST_WIDE_INT value2, + HOST_WIDE_INT value3) +{ + unsigned int argno = m_base_arg + rel_argno; + if (!argument_exists_p (argno)) + return true; + + HOST_WIDE_INT actual; + if (!require_immediate (argno, actual)) + return false; + + if (actual != value0 + && actual != value1 + && actual != value2 + && actual != value3) + { + report_not_one_of (location, fndecl, argno, actual, + value0, value1, value2, value3); + return false; + } + + return true; +} + +/* Check that argument REL_ARGNO is an integer constant expression in the + range [MIN, MAX]. REL_ARGNO counts from the end of the predication + arguments. */ +bool +function_checker::require_immediate_range (unsigned int rel_argno, + HOST_WIDE_INT min, + HOST_WIDE_INT max) +{ + unsigned int argno = m_base_arg + rel_argno; + if (!argument_exists_p (argno)) + return true; + + /* Required because of the tree_to_uhwi -> HOST_WIDE_INT conversion + in require_immediate. */ + gcc_assert (min >= 0 && min <= max); + HOST_WIDE_INT actual; + if (!require_immediate (argno, actual)) + return false; + + if (!IN_RANGE (actual, min, max)) + { + report_out_of_range (location, fndecl, argno, actual, min, max); + return false; + } + + return true; +} + +/* Perform semantic checks on the call. Return true if the call is valid, + otherwise report a suitable error. */ +bool +function_checker::check () +{ + function_args_iterator iter; + tree type; + unsigned int i = 0; + FOREACH_FUNCTION_ARGS (m_fntype, type, iter) + { + if (type == void_type_node || i >= m_nargs) + break; + + if (i >= m_base_arg + && TREE_CODE (type) == ENUMERAL_TYPE + && !require_immediate_enum (i - m_base_arg, type)) + return false; + + i += 1; + } + + return shape->check (*this); +} + +gimple_folder::gimple_folder (const function_instance &instance, tree fndecl, + gimple_stmt_iterator *gsi_in, gcall *call_in) + : function_call_info (gimple_location (call_in), instance, fndecl), + gsi (gsi_in), call (call_in), lhs (gimple_call_lhs (call_in)) +{ +} + +/* Convert predicate argument ARGNO so that it has the type appropriate for + an operation on VECTYPE. Add any new statements to STMTS. */ +tree +gimple_folder::convert_pred (gimple_seq &stmts, tree vectype, + unsigned int argno) +{ + tree predtype = build_same_sized_truth_vector_type (vectype); + tree pred = gimple_call_arg (call, argno); + return gimple_build (&stmts, VIEW_CONVERT_EXPR, predtype, pred); +} + +/* Return a pointer to the address in a contiguous load or store, + given that each memory vector has type VECTYPE. Add any new + statements to STMTS. */ +tree +gimple_folder::fold_contiguous_base (gimple_seq &stmts, tree vectype) +{ + tree base = gimple_call_arg (call, 1); + if (mode_suffix_id == MODE_vnum) + { + tree offset = gimple_call_arg (call, 2); + offset = gimple_convert (&stmts, sizetype, offset); + offset = gimple_build (&stmts, MULT_EXPR, sizetype, offset, + TYPE_SIZE_UNIT (vectype)); + base = gimple_build (&stmts, POINTER_PLUS_EXPR, TREE_TYPE (base), + base, offset); + } + return base; +} + +/* 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. */ +tree +gimple_folder::load_store_cookie (tree type) +{ + return build_int_cst (build_pointer_type (type), TYPE_ALIGN_UNIT (type)); +} + +/* Fold the call to a PTRUE, taking the element size from type suffix 0. */ +gimple * +gimple_folder::fold_to_ptrue () +{ + tree svbool_type = TREE_TYPE (lhs); + tree bool_type = TREE_TYPE (svbool_type); + unsigned int element_bytes = type_suffix (0).element_bytes; + + /* The return type is svbool_t for all type suffixes, thus for b8 we + want { 1, 1, 1, 1, ... }, for b16 we want { 1, 0, 1, 0, ... }, etc. */ + tree_vector_builder builder (svbool_type, element_bytes, 1); + builder.quick_push (build_all_ones_cst (bool_type)); + for (unsigned int i = 1; i < element_bytes; ++i) + builder.quick_push (build_zero_cst (bool_type)); + return gimple_build_assign (lhs, builder.build ()); +} + +/* Fold the call to a PFALSE. */ +gimple * +gimple_folder::fold_to_pfalse () +{ + return gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs))); +} + +/* Fold an operation to a constant predicate in which the first VL + elements are set and the rest are clear. Take the element size + from type suffix 0. */ +gimple * +gimple_folder::fold_to_vl_pred (unsigned int vl) +{ + tree vectype = TREE_TYPE (lhs); + tree element_type = TREE_TYPE (vectype); + tree minus_one = build_all_ones_cst (element_type); + tree zero = build_zero_cst (element_type); + unsigned int element_bytes = type_suffix (0).element_bytes; + + /* Construct COUNT elements that contain the ptrue followed by + a repeating sequence of COUNT elements. */ + unsigned int count = constant_lower_bound (TYPE_VECTOR_SUBPARTS (vectype)); + gcc_assert (vl * element_bytes <= count); + tree_vector_builder builder (vectype, count, 2); + for (unsigned int i = 0; i < count * 2; ++i) + { + bool bit = (i & (element_bytes - 1)) == 0 && i < vl * element_bytes; + builder.quick_push (bit ? minus_one : zero); + } + return gimple_build_assign (lhs, builder.build ()); +} + +/* Try to fold the call. Return the new statement on success and null + on failure. */ +gimple * +gimple_folder::fold () +{ + /* Don't fold anything when SVE is disabled; emit an error during + expansion instead. */ + if (!TARGET_SVE) + return NULL; + + /* Punt if the function has a return type and no result location is + provided. The attributes should allow target-independent code to + remove the calls if appropriate. */ + if (!lhs && TREE_TYPE (gimple_call_fntype (call)) != void_type_node) + return NULL; + + return base->fold (*this); +} + +function_expander::function_expander (const function_instance &instance, + tree fndecl, tree call_expr_in, + rtx possible_target_in) + : function_call_info (EXPR_LOCATION (call_expr_in), instance, fndecl), + call_expr (call_expr_in), possible_target (possible_target_in) +{ +} + +/* Return the handler of direct optab OP for type suffix SUFFIX_I. */ +insn_code +function_expander::direct_optab_handler (optab op, unsigned int suffix_i) +{ + return ::direct_optab_handler (op, vector_mode (suffix_i)); +} + +/* Choose between signed and unsigned direct optabs SIGNED_OP and + UNSIGNED_OP based on the signedness of type suffix SUFFIX_I, then + pick the appropriate optab handler for the mode. Use MODE as the + mode if given, otherwise use the mode of type suffix SUFFIX_I. */ +insn_code +function_expander::direct_optab_handler_for_sign (optab signed_op, + optab unsigned_op, + unsigned int suffix_i, + machine_mode mode) +{ + if (mode == VOIDmode) + mode = vector_mode (suffix_i); + optab op = type_suffix (suffix_i).unsigned_p ? unsigned_op : signed_op; + return ::direct_optab_handler (op, mode); +} + +/* Return true if X overlaps any input. */ +bool +function_expander::overlaps_input_p (rtx x) +{ + for (unsigned int i = 0; i < args.length (); ++i) + if (reg_overlap_mentioned_p (x, args[i])) + return true; + return false; +} + +/* Return the base address for a contiguous load or store function. + MEM_MODE is the mode of the addressed memory. */ +rtx +function_expander::get_contiguous_base (machine_mode mem_mode) +{ + rtx base = args[1]; + if (mode_suffix_id == MODE_vnum) + { + /* Use the size of the memory mode for extending loads and truncating + stores. Use the size of a full vector for non-extending loads + and non-truncating stores (including svld[234] and svst[234]). */ + poly_int64 size = ordered_min (GET_MODE_SIZE (mem_mode), + BYTES_PER_SVE_VECTOR); + rtx offset = gen_int_mode (size, Pmode); + offset = simplify_gen_binary (MULT, Pmode, args[2], offset); + base = simplify_gen_binary (PLUS, Pmode, base, offset); + } + return base; +} + +/* For a function that does the equivalent of: + + OUTPUT = COND ? FN (INPUTS) : FALLBACK; + + return the value of FALLBACK. + + MODE is the mode of OUTPUT. NOPS is the number of operands in INPUTS. + MERGE_ARGNO is the argument that provides FALLBACK for _m functions, + or DEFAULT_MERGE_ARGNO if we should apply the usual rules. + + ARGNO is the caller's index into args. If the returned value is + argument 0 (as for unary _m operations), increment ARGNO past the + returned argument. */ +rtx +function_expander::get_fallback_value (machine_mode mode, unsigned int nops, + unsigned int merge_argno, + unsigned int &argno) +{ + if (pred == PRED_z) + return CONST0_RTX (mode); + + gcc_assert (pred == PRED_m || pred == PRED_x); + if (merge_argno == DEFAULT_MERGE_ARGNO) + merge_argno = nops == 1 && pred == PRED_m ? 0 : 1; + + if (merge_argno == 0) + return args[argno++]; + + return args[merge_argno]; +} + +/* Return a REG rtx that can be used for the result of the function, + using the preferred target if suitable. */ +rtx +function_expander::get_reg_target () +{ + machine_mode target_mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))); + if (!possible_target || GET_MODE (possible_target) != target_mode) + possible_target = gen_reg_rtx (target_mode); + return possible_target; +} + +/* As for get_reg_target, but make sure that the returned REG does not + overlap any inputs. */ +rtx +function_expander::get_nonoverlapping_reg_target () +{ + if (possible_target && overlaps_input_p (possible_target)) + possible_target = NULL_RTX; + return get_reg_target (); +} + +/* Add an output operand to the instruction we're building, which has + code ICODE. Bind the output to the preferred target rtx if possible. */ +void +function_expander::add_output_operand (insn_code icode) +{ + unsigned int opno = m_ops.length (); + machine_mode mode = insn_data[icode].operand[opno].mode; + m_ops.safe_grow (opno + 1); + create_output_operand (&m_ops.last (), possible_target, mode); +} + +/* Add an input operand to the instruction we're building, which has + code ICODE. Calculate the value of the operand as follows: + + - If the operand is a vector and X is not, broadcast X to fill a + vector of the appropriate mode. + + - Otherwise, if the operand is a predicate, coerce X to have the + mode that the instruction expects. In this case X is known to be + VNx16BImode (the mode of svbool_t). + + - Otherwise use X directly. The expand machinery checks that X has + the right mode for the instruction. */ +void +function_expander::add_input_operand (insn_code icode, rtx x) +{ + unsigned int opno = m_ops.length (); + const insn_operand_data &operand = insn_data[icode].operand[opno]; + machine_mode mode = operand.mode; + if (mode == VOIDmode) + { + /* The only allowable use of VOIDmode is the wildcard + aarch64_any_register_operand, which is used to avoid + combinatorial explosion in the reinterpret patterns. */ + gcc_assert (operand.predicate == aarch64_any_register_operand); + mode = GET_MODE (x); + } + else if (!VECTOR_MODE_P (GET_MODE (x)) && VECTOR_MODE_P (mode)) + x = expand_vector_broadcast (mode, x); + else if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) + { + gcc_assert (GET_MODE (x) == VNx16BImode); + x = gen_lowpart (mode, x); + } + m_ops.safe_grow (m_ops.length () + 1); + create_input_operand (&m_ops.last (), x, mode); +} + +/* Add an integer operand with value X to the instruction. */ +void +function_expander::add_integer_operand (HOST_WIDE_INT x) +{ + m_ops.safe_grow (m_ops.length () + 1); + create_integer_operand (&m_ops.last (), x); +} + +/* Add a memory operand with mode MODE and address ADDR. */ +void +function_expander::add_mem_operand (machine_mode mode, rtx addr) +{ + gcc_assert (VECTOR_MODE_P (mode)); + rtx mem = gen_rtx_MEM (mode, memory_address (mode, addr)); + /* The memory is only guaranteed to be element-aligned. */ + set_mem_align (mem, GET_MODE_ALIGNMENT (GET_MODE_INNER (mode))); + add_fixed_operand (mem); +} + +/* Add an address operand with value X. The static operand data says + what mode and form the address must have. */ +void +function_expander::add_address_operand (rtx x) +{ + m_ops.safe_grow (m_ops.length () + 1); + create_address_operand (&m_ops.last (), x); +} + +/* Add an operand that must be X. The only way of legitimizing an + invalid X is to reload the address of a MEM. */ +void +function_expander::add_fixed_operand (rtx x) +{ + m_ops.safe_grow (m_ops.length () + 1); + create_fixed_operand (&m_ops.last (), x); +} + +/* Generate instruction ICODE, given that its operands have already + been added to M_OPS. Return the value of the first operand. */ +rtx +function_expander::generate_insn (insn_code icode) +{ + expand_insn (icode, m_ops.length (), m_ops.address ()); + return function_returns_void_p () ? const0_rtx : m_ops[0].value; +} + +/* Convert the arguments to a gather/scatter function into the + associated md operands. Argument ARGNO is the scalar or vector base and + argument ARGNO + 1 is the scalar or vector displacement (if applicable). + The md pattern expects: + + - a scalar base + - a vector displacement + - a const_int that is 1 if the displacement is zero-extended from 32 bits + - a scaling multiplier (1 for bytes, 2 for .h indices, etc.). */ +void +function_expander::prepare_gather_address_operands (unsigned int argno) +{ + machine_mode mem_mode = memory_vector_mode (); + tree vector_type = base_vector_type (); + units_index units = displacement_units (); + if (units == UNITS_none) + { + /* Vector base, no displacement. Convert to an integer zero base + and a vector byte offset. */ + args.quick_insert (argno, const0_rtx); + units = UNITS_bytes; + } + else if (vector_type) + { + /* Vector base, scalar displacement. Convert to a scalar base and + a vector byte offset. */ + std::swap (args[argno], args[argno + 1]); + if (units == UNITS_elements) + { + /* Convert the original scalar array index to a byte offset. */ + rtx size = gen_int_mode (GET_MODE_UNIT_SIZE (mem_mode), DImode); + args[argno] = simplify_gen_binary (MULT, DImode, args[argno], size); + units = UNITS_bytes; + } + } + else + { + /* Scalar base, vector displacement. This is what the md pattern wants, + so we just need to make sure that the scalar base has DImode. */ + if (Pmode == SImode) + args[argno] = simplify_gen_unary (ZERO_EXTEND, DImode, + args[argno], SImode); + vector_type = displacement_vector_type (); + } + tree scalar_displacement_type = TREE_TYPE (vector_type); + + bool uxtw_p = (TYPE_PRECISION (scalar_displacement_type) < 64 + && TYPE_UNSIGNED (scalar_displacement_type)); + unsigned int scale = (units == UNITS_bytes + ? 1 : GET_MODE_UNIT_SIZE (mem_mode)); + + args.quick_insert (argno + 2, GEN_INT (uxtw_p)); + args.quick_insert (argno + 3, GEN_INT (scale)); +} + +/* The final argument is an immediate svprfop value. Add two fake arguments + to represent the rw and locality operands of a PREFETCH rtx. */ +void +function_expander::prepare_prefetch_operands () +{ + unsigned int prfop = INTVAL (args.last ()); + /* Bit 3 of the prfop selects stores over loads. */ + args.quick_push (GEN_INT ((prfop & 8) != 0)); + /* Bits 1 and 2 specify the locality; 0-based for svprfop but + 1-based for PREFETCH. */ + args.quick_push (GEN_INT (((prfop >> 1) & 3) + 1)); +} + +/* Add a dummy argument to indicate whether predicate argument ARGNO + is all-true when interpreted in mode PRED_MODE. The hint goes + immediately after ARGNO. */ +void +function_expander::add_ptrue_hint (unsigned int argno, machine_mode pred_mode) +{ + rtx pred = gen_lowpart (pred_mode, args[argno]); + int hint = (pred == CONSTM1_RTX (pred_mode) + ? SVE_KNOWN_PTRUE : SVE_MAYBE_NOT_PTRUE); + args.quick_insert (argno + 1, gen_int_mode (hint, SImode)); +} + +/* Rotate inputs args[START:END] one position to the left, so that + args[START] becomes args[END - 1]. */ +void +function_expander::rotate_inputs_left (unsigned int start, unsigned int end) +{ + rtx new_last = args[start]; + for (unsigned int i = start; i < end - 1; ++i) + args[i] = args[i + 1]; + args[end - 1] = new_last; +} + +/* Return true if the negation of argument ARGNO can be folded away, + replacing it with the negated value if so. MODE is the associated + vector mode, but the argument could be a single element. The main + case this handles is constant arguments. */ +bool +function_expander::try_negating_argument (unsigned int argno, + machine_mode mode) +{ + rtx x = args[argno]; + if (!VECTOR_MODE_P (GET_MODE (x))) + mode = GET_MODE_INNER (mode); + + x = simplify_unary_operation (NEG, mode, x, mode); + if (!x) + return false; + + args[argno] = x; + return true; +} + +/* Implement the call using instruction ICODE, with a 1:1 mapping between + arguments and input operands. */ +rtx +function_expander::use_exact_insn (insn_code icode) +{ + unsigned int nops = insn_data[icode].n_operands; + if (!function_returns_void_p ()) + { + add_output_operand (icode); + nops -= 1; + } + for (unsigned int i = 0; i < nops; ++i) + add_input_operand (icode, args[i]); + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which does not use a + governing predicate. We must therefore drop the GP from an _x call. */ +rtx +function_expander::use_unpred_insn (insn_code icode) +{ + /* We can't drop the predicate for _z and _m. */ + gcc_assert (pred == PRED_x || pred == PRED_none); + /* Discount the output operand. */ + unsigned int nops = insn_data[icode].n_operands - 1; + /* Drop the predicate argument in the case of _x predication. */ + unsigned int bias = (pred == PRED_x ? 1 : 0); + unsigned int i = 0; + + add_output_operand (icode); + for (; i < nops; ++i) + add_input_operand (icode, args[i + bias]); + + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which is a predicated + operation that returns arbitrary values for inactive lanes. */ +rtx +function_expander::use_pred_x_insn (insn_code icode) +{ + /* At present we never need to handle PRED_none, which would involve + creating a new predicate rather than using one supplied by the user. */ + gcc_assert (pred == PRED_x); + /* Discount the output operand. */ + unsigned int nops = args.length () - 1; + + bool has_float_operand_p = FLOAT_MODE_P (insn_data[icode].operand[0].mode); + + /* Add the normal operands. */ + add_output_operand (icode); + add_input_operand (icode, args[0]); + for (unsigned int i = 0; i < nops; ++i) + { + add_input_operand (icode, args[i + 1]); + if (FLOAT_MODE_P (GET_MODE (args[i + 1]))) + has_float_operand_p = true; + } + + if (has_float_operand_p) + { + /* Add a flag that indicates whether unpredicated instructions + are allowed. */ + rtx pred = m_ops[1].value; + if (flag_trapping_math && pred != CONST1_RTX (GET_MODE (pred))) + add_integer_operand (SVE_STRICT_GP); + else + add_integer_operand (SVE_RELAXED_GP); + } + + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which does the equivalent of: + + OUTPUT = COND ? FN (INPUTS) : FALLBACK; + + The instruction operands are in the order above: OUTPUT, COND, INPUTS + and FALLBACK. MERGE_ARGNO is the argument that provides FALLBACK for _m + functions, or DEFAULT_MERGE_ARGNO if we should apply the usual rules. */ +rtx +function_expander::use_cond_insn (insn_code icode, unsigned int merge_argno) +{ + /* At present we never need to handle PRED_none, which would involve + creating a new predicate rather than using one supplied by the user. */ + gcc_assert (pred != PRED_none); + /* Discount the output, predicate and fallback value. */ + unsigned int nops = insn_data[icode].n_operands - 3; + machine_mode mode = insn_data[icode].operand[0].mode; + + unsigned int opno = 0; + rtx fallback_arg = get_fallback_value (mode, nops, merge_argno, opno); + rtx pred = args[opno++]; + + add_output_operand (icode); + add_input_operand (icode, pred); + for (unsigned int i = 0; i < nops; ++i) + add_input_operand (icode, args[opno + i]); + add_input_operand (icode, fallback_arg); + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which is a select-like + operation with the following operands: + + 0: output + 1: true value + 2: false value + 3: predicate + + MERGE_ARGNO is the argument that provides the "false" value for _m + functions, or DEFAULT_MERGE_ARGNO if we should apply the usual rules. */ +rtx +function_expander::use_vcond_mask_insn (insn_code icode, + unsigned int merge_argno) +{ + machine_mode mode = vector_mode (0); + + unsigned int opno = 0; + rtx false_arg = get_fallback_value (mode, 1, merge_argno, opno); + rtx pred_arg = args[opno++]; + rtx true_arg = args[opno++]; + + add_output_operand (icode); + add_input_operand (icode, true_arg); + add_input_operand (icode, false_arg); + add_input_operand (icode, pred_arg); + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which loads memory operand 1 + into register operand 0 under the control of predicate operand 2. */ +rtx +function_expander::use_contiguous_load_insn (insn_code icode) +{ + machine_mode mem_mode = memory_vector_mode (); + + add_output_operand (icode); + add_mem_operand (mem_mode, get_contiguous_base (mem_mode)); + add_input_operand (icode, args[0]); + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which prefetches from + address operand 1 under the control of predicate operand 0. + Operands 2, 3 and 4 respectively specify the svprfop value, + the PREFETCH rw flag and the PREFETCH locality. */ +rtx +function_expander::use_contiguous_prefetch_insn (insn_code icode) +{ + add_input_operand (icode, args[0]); + add_address_operand (get_contiguous_base (VNx16QImode)); + for (unsigned int i = args.length () - 3; i < args.length (); ++i) + add_input_operand (icode, args[i]); + return generate_insn (icode); +} + +/* Implement the call using instruction ICODE, which stores register operand 1 + into memory operand 0 under the control of predicate operand 2. */ +rtx +function_expander::use_contiguous_store_insn (insn_code icode) +{ + machine_mode mem_mode = memory_vector_mode (); + + add_mem_operand (mem_mode, get_contiguous_base (mem_mode)); + add_input_operand (icode, args.last ()); + add_input_operand (icode, args[0]); + return generate_insn (icode); +} + +/* Implement the call using one of the following strategies, chosen in order: + + (1) "aarch64_pred_<optab><mode>_z" for PRED_z predicate functions + + (2) "aarch64_pred_<optab><mode>" for PRED_x functions + + (3) a normal unpredicated optab for PRED_none and PRED_x functions, + dropping the predicate in the latter case + + (4) "cond_<optab><mode>" otherwise + + where <optab> corresponds to: + + - CODE_FOR_SINT for signed integers + - CODE_FOR_UINT for unsigned integers + - UNSPEC_FOR_FP for floating-point values + + MERGE_ARGNO is the argument that provides the values of inactive lanes for + _m functions, or DEFAULT_MERGE_ARGNO if we should apply the usual rules. */ +rtx +function_expander::map_to_rtx_codes (rtx_code code_for_sint, + rtx_code code_for_uint, + int unspec_for_fp, + unsigned int merge_argno) +{ + machine_mode mode = vector_mode (0); + rtx_code code = (type_suffix (0).unsigned_p ? code_for_uint : code_for_sint); + insn_code icode; + + /* Handle predicate logic operations, which always use _z predication. */ + if (type_suffix (0).tclass == TYPE_bool) + { + gcc_assert (pred == PRED_z && code_for_uint == code_for_sint); + return use_exact_insn (code_for_aarch64_pred_z (code, mode)); + } + + /* First try using UNSPEC_PRED_X patterns for _x predication, + if available. */ + if (pred == PRED_x) + { + if (type_suffix (0).integer_p) + icode = maybe_code_for_aarch64_pred (code, mode); + else + icode = maybe_code_for_aarch64_pred (unspec_for_fp, mode); + if (icode != CODE_FOR_nothing) + return use_pred_x_insn (icode); + } + + /* Otherwise expand PRED_none and PRED_x operations without a predicate. + Floating-point operations conventionally use the signed rtx code. */ + if (pred == PRED_none || pred == PRED_x) + return use_unpred_insn (direct_optab_handler (code_to_optab (code), 0)); + + /* Don't use cond_*_optabs here, since not all codes have one yet. */ + if (type_suffix (0).integer_p) + icode = code_for_cond (code, mode); + else + icode = code_for_cond (unspec_for_fp, mode); + return use_cond_insn (icode, merge_argno); +} + +/* Implement the call using one of the following strategies, chosen in order: + + (1) "aarch64_pred_<optab><mode>" for PRED_x functions; this is a + predicated pattern + + (2) "aarch64_sve_<optab><mode>" for PRED_none and PRED_x functions; + this is an unpredicated pattern + + (3) "cond_<optab><mode>" otherwise + + where <optab> corresponds to: + + - UNSPEC_FOR_SINT for signed integers + - UNSPEC_FOR_UINT for unsigned integers + - UNSPEC_FOR_FP for floating-point values + + MERGE_ARGNO is the argument that provides the values of inactive lanes for + _m functions, or DEFAULT_MERGE_ARGNO if we should apply the usual rules. */ +rtx +function_expander::map_to_unspecs (int unspec_for_sint, int unspec_for_uint, + int unspec_for_fp, unsigned int merge_argno) +{ + machine_mode mode = vector_mode (0); + int unspec = (!type_suffix (0).integer_p ? unspec_for_fp + : type_suffix (0).unsigned_p ? unspec_for_uint + : unspec_for_sint); + + if (pred == PRED_x) + { + insn_code icode = maybe_code_for_aarch64_pred (unspec, mode); + if (icode != CODE_FOR_nothing) + return use_pred_x_insn (icode); + } + + if (pred == PRED_none || pred == PRED_x) + return use_unpred_insn (code_for_aarch64_sve (unspec, mode)); + + insn_code icode = code_for_cond (unspec, vector_mode (0)); + return use_cond_insn (icode, merge_argno); +} + +/* Implement the call using an @aarch64 instruction and the + instructions are parameterized by an rtx_code. CODE_FOR_SINT + is the rtx_code for signed integer operations, CODE_FOR_UINT + is the rtx_code for unsigned integer operations. */ +rtx +function_expander::expand_signed_unpred_op (rtx_code code_for_sint, + rtx_code code_for_uint) +{ + insn_code icode; + if (type_suffix (0).unsigned_p) + icode = code_for_aarch64 (code_for_uint, code_for_uint, vector_mode (0)); + else + icode = code_for_aarch64 (code_for_sint, code_for_sint, vector_mode (0)); + return use_unpred_insn (icode); +} + +/* Expand the call and return its lhs. */ +rtx +function_expander::expand () +{ + unsigned int nargs = call_expr_nargs (call_expr); + args.reserve (nargs); + for (unsigned int i = 0; i < nargs; ++i) + args.quick_push (expand_normal (CALL_EXPR_ARG (call_expr, i))); + + return base->expand (*this); +} + +/* Register the built-in SVE ABI types, such as __SVBool_t. */ +static void +register_builtin_types () +{ +#define DEF_SVE_TYPE(ACLE_NAME, NCHARS, ABI_NAME, SCALAR_TYPE) \ + scalar_types[VECTOR_TYPE_ ## ACLE_NAME] = SCALAR_TYPE; +#include "aarch64-sve-builtins.def" + + for (unsigned int i = 0; i < NUM_VECTOR_TYPES; ++i) + { + tree eltype = scalar_types[i]; + tree vectype; + if (eltype == boolean_type_node) + { + vectype = build_truth_vector_type (BYTES_PER_SVE_VECTOR, + BYTES_PER_SVE_VECTOR); + gcc_assert (TYPE_MODE (vectype) == VNx16BImode + && TYPE_MODE (vectype) == TYPE_MODE_RAW (vectype) + && TYPE_ALIGN (vectype) == 16 + && known_eq (wi::to_poly_offset (TYPE_SIZE (vectype)), + BYTES_PER_SVE_VECTOR)); + } + else + { + unsigned int elbytes = tree_to_uhwi (TYPE_SIZE_UNIT (eltype)); + poly_uint64 nunits = exact_div (BYTES_PER_SVE_VECTOR, elbytes); + vectype = build_vector_type (eltype, nunits); + gcc_assert (VECTOR_MODE_P (TYPE_MODE (vectype)) + && TYPE_MODE (vectype) == TYPE_MODE_RAW (vectype) + && TYPE_ALIGN (vectype) == 128 + && known_eq (wi::to_poly_offset (TYPE_SIZE (vectype)), + BITS_PER_SVE_VECTOR)); + } + vectype = build_distinct_type_copy (vectype); + SET_TYPE_STRUCTURAL_EQUALITY (vectype); + TYPE_ARTIFICIAL (vectype) = 1; + abi_vector_types[i] = vectype; + lang_hooks.types.register_builtin_type (vectype, + vector_types[i].abi_name); + } +} + +/* Initialize all compiler built-ins related to SVE that should be + defined at start-up. */ +void +init_builtins () +{ + sve_switcher sve; + register_builtin_types (); +} + +/* Register vector type TYPE under its arm_sve.h name. */ +static void +register_vector_type (vector_type_index type) +{ + tree vectype = abi_vector_types[type]; + tree id = get_identifier (vector_types[type].acle_name); + tree decl = build_decl (input_location, TYPE_DECL, id, vectype); + decl = lang_hooks.decls.pushdecl (decl); + + /* Record the new ACLE type if pushdecl succeeded without error. Use + the ABI type otherwise, so that the type we record at least has the + right form, even if it doesn't have the right name. This should give + better error recovery behavior than installing error_mark_node or + installing an incorrect type. */ + if (TREE_CODE (decl) == TYPE_DECL + && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == vectype) + vectype = TREE_TYPE (decl); + acle_vector_types[0][type] = vectype; +} + +/* Register the tuple type that contains NUM_VECTORS vectors of type TYPE. */ +static void +register_tuple_type (unsigned int num_vectors, vector_type_index type) +{ + tree tuple_type = lang_hooks.types.make_type (RECORD_TYPE); + + /* The contents of the type are opaque, so we can define them in any + way that maps to the correct ABI type. + + Here we choose to use the same layout as for arm_neon.h, but with + "__val" instead of "val": + + struct svfooxN_t { svfoo_t __val[N]; }; + + (It wouldn't be possible to write that directly in C or C++ for + sizeless types, but that's not a problem for this function.) + + Using arrays simplifies the handling of svget and svset for variable + arguments. */ + tree vector_type = acle_vector_types[0][type]; + tree array_type = build_array_type_nelts (vector_type, num_vectors); + gcc_assert (VECTOR_MODE_P (TYPE_MODE (array_type)) + && TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type) + && TYPE_ALIGN (array_type) == 128); + + tree field = build_decl (input_location, FIELD_DECL, + get_identifier ("__val"), array_type); + DECL_FIELD_CONTEXT (field) = tuple_type; + TYPE_FIELDS (tuple_type) = field; + layout_type (tuple_type); + gcc_assert (VECTOR_MODE_P (TYPE_MODE (tuple_type)) + && TYPE_MODE_RAW (tuple_type) == TYPE_MODE (tuple_type) + && TYPE_ALIGN (tuple_type) == 128); + + /* Work out the structure name. */ + char buffer[sizeof ("svfloat64x4_t")]; + const char *vector_type_name = vector_types[type].acle_name; + snprintf (buffer, sizeof (buffer), "%.*sx%d_t", + (int) strlen (vector_type_name) - 2, vector_type_name, + num_vectors); + + tree decl = build_decl (input_location, TYPE_DECL, + get_identifier (buffer), tuple_type); + TYPE_NAME (tuple_type) = decl; + TYPE_STUB_DECL (tuple_type) = decl; + lang_hooks.decls.pushdecl (decl); + /* ??? Undo the effect of set_underlying_type for C. The C frontend + doesn't recognize DECL as a built-in because (as intended) the decl has + a real location instead of BUILTINS_LOCATION. The frontend therefore + treats the decl like a normal C "typedef struct foo foo;", expecting + the type for tag "struct foo" to have a dummy unnamed TYPE_DECL instead + of the named one we attached above. It then sets DECL_ORIGINAL_TYPE + on the supposedly unnamed decl, creating a circularity that upsets + dwarf2out. + + We don't want to follow the normal C model and create "struct foo" + tags for tuple types since (a) the types are supposed to be opaque + and (b) they couldn't be defined as a real struct anyway. Treating + the TYPE_DECLs as "typedef struct foo foo;" without creating + "struct foo" would lead to confusing error messages. */ + DECL_ORIGINAL_TYPE (decl) = NULL_TREE; + + acle_vector_types[num_vectors - 1][type] = tuple_type; +} + +/* Register the svpattern enum. */ +static void +register_svpattern () +{ + auto_vec<string_int_pair, 32> values; +#define PUSH(UPPER, LOWER, VALUE) \ + values.quick_push (string_int_pair ("SV_" #UPPER, VALUE)); + AARCH64_FOR_SVPATTERN (PUSH) +#undef PUSH + + acle_svpattern = lang_hooks.types.simulate_enum_decl (input_location, + "svpattern", values); +} + +/* Register the svprfop enum. */ +static void +register_svprfop () +{ + auto_vec<string_int_pair, 16> values; +#define PUSH(UPPER, LOWER, VALUE) \ + values.quick_push (string_int_pair ("SV_" #UPPER, VALUE)); + AARCH64_FOR_SVPRFOP (PUSH) +#undef PUSH + + acle_svprfop = lang_hooks.types.simulate_enum_decl (input_location, + "svprfop", values); +} + +/* Implement #pragma GCC aarch64 "arm_sve.h". */ +void +handle_arm_sve_h () +{ + if (function_table) + { + error ("duplicate definition of %qs", "arm_sve.h"); + return; + } + + sve_switcher sve; + + /* Define the vector and tuple types. */ + for (unsigned int type_i = 0; type_i < NUM_VECTOR_TYPES; ++type_i) + { + vector_type_index type = vector_type_index (type_i); + register_vector_type (type); + if (type != VECTOR_TYPE_svbool_t) + for (unsigned int count = 2; count <= MAX_TUPLE_SIZE; ++count) + register_tuple_type (count, type); + } + + /* Define the enums. */ + register_svpattern (); + register_svprfop (); + + /* Define the functions. */ + function_table = new hash_table<registered_function_hasher> (1023); + function_builder builder; + for (unsigned int i = 0; i < ARRAY_SIZE (function_groups); ++i) + builder.register_function_group (function_groups[i]); +} + +/* Return the function decl with SVE function subcode CODE, or error_mark_node + if no such function exists. */ +tree +builtin_decl (unsigned int code, bool) +{ + if (code >= vec_safe_length (registered_functions)) + return error_mark_node; + return (*registered_functions)[code]->decl; +} + +/* If we're implementing manual overloading, check whether the SVE + function with subcode CODE is overloaded, and if so attempt to + determine the corresponding non-overloaded function. The call + occurs at location LOCATION and has the arguments given by ARGLIST. + + If the call is erroneous, report an appropriate error and return + error_mark_node. Otherwise, if the function is overloaded, return + the decl of the non-overloaded function. Return NULL_TREE otherwise, + indicating that the call should be processed in the normal way. */ +tree +resolve_overloaded_builtin (location_t location, unsigned int code, + vec<tree, va_gc> *arglist) +{ + if (code >= vec_safe_length (registered_functions)) + return NULL_TREE; + + registered_function &rfn = *(*registered_functions)[code]; + if (rfn.overloaded_p) + return function_resolver (location, rfn.instance, rfn.decl, + *arglist).resolve (); + return NULL_TREE; +} + +/* Perform any semantic checks needed for a call to the SVE function + with subcode CODE, such as testing for integer constant expressions. + The call occurs at location LOCATION and has NARGS arguments, + given by ARGS. FNDECL is the original function decl, before + overload resolution. + + Return true if the call is valid, otherwise report a suitable error. */ +bool +check_builtin_call (location_t location, vec<location_t>, unsigned int code, + tree fndecl, unsigned int nargs, tree *args) +{ + const registered_function &rfn = *(*registered_functions)[code]; + if (!check_required_extensions (location, rfn.decl, rfn.required_extensions)) + return false; + return function_checker (location, rfn.instance, fndecl, + TREE_TYPE (rfn.decl), nargs, args).check (); +} + +/* Attempt to fold STMT, given that it's a call to the SVE function + with subcode CODE. Return the new statement on success and null + on failure. Insert any other new statements at GSI. */ +gimple * +gimple_fold_builtin (unsigned int code, gimple_stmt_iterator *gsi, gcall *stmt) +{ + registered_function &rfn = *(*registered_functions)[code]; + return gimple_folder (rfn.instance, rfn.decl, gsi, stmt).fold (); +} + +/* Expand a call to the SVE function with subcode CODE. EXP is the call + expression and TARGET is the preferred location for the result. + Return the value of the lhs. */ +rtx +expand_builtin (unsigned int code, tree exp, rtx target) +{ + registered_function &rfn = *(*registered_functions)[code]; + if (!check_required_extensions (EXPR_LOCATION (exp), rfn.decl, + rfn.required_extensions)) + return target; + return function_expander (rfn.instance, rfn.decl, exp, target).expand (); +} + +/* Return true if TYPE is the ABI-defined __SVBool_t type. */ +bool +svbool_type_p (const_tree type) +{ + tree abi_type = abi_vector_types[VECTOR_TYPE_svbool_t]; + return (type != error_mark_node + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (abi_type)); +} + +/* If TYPE is a built-in type defined by the SVE ABI, return the mangled name, + otherwise return NULL. */ +const char * +mangle_builtin_type (const_tree type) +{ + if (type == error_mark_node) + return NULL; + + vector_type_index vtype = find_vector_type (type); + if (vtype != NUM_VECTOR_TYPES) + return vector_types[vtype].mangled_name; + + return NULL; +} + +/* If TYPE is one of the ABI-defined SVE vector types, or an ACLE-defined + tuple of them, return the number of vectors it contains. Return 0 + otherwise. */ +unsigned int +nvectors_if_data_type (const_tree type) +{ + if (type == error_mark_node) + return 0; + + type = TYPE_MAIN_VARIANT (type); + if (VECTOR_TYPE_P (type)) + { + vector_type_index type_id = find_vector_type (type); + if (type_id != VECTOR_TYPE_svbool_t && type_id != NUM_VECTOR_TYPES) + return 1; + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + for (unsigned int size_i = 1; size_i < MAX_TUPLE_SIZE; ++size_i) + for (unsigned int type_i = 0; type_i < NUM_VECTOR_TYPES; ++type_i) + { + tree tuple_type = acle_vector_types[size_i][type_i]; + if (tuple_type && type == TYPE_MAIN_VARIANT (tuple_type)) + return size_i + 1; + } + } + + return 0; +} + +/* Return true if TYPE is a built-in type defined by the SVE ABI. */ +bool +builtin_type_p (const_tree type) +{ + return svbool_type_p (type) || nvectors_if_data_type (type) > 0; +} + +} + +using namespace aarch64_sve; + +inline void +gt_ggc_mx (function_instance *) +{ +} + +inline void +gt_pch_nx (function_instance *) +{ +} + +inline void +gt_pch_nx (function_instance *, void (*) (void *, void *), void *) +{ +} + +#include "gt-aarch64-sve-builtins.h" diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def new file mode 100644 index 0000000..da00019 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins.def @@ -0,0 +1,98 @@ +/* Builtin lists for AArch64 SVE + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef DEF_SVE_MODE +#define DEF_SVE_MODE(A, B, C, D) +#endif + +#ifndef DEF_SVE_TYPE +#define DEF_SVE_TYPE(A, B, C, D) +#endif + +#ifndef DEF_SVE_TYPE_SUFFIX +#define DEF_SVE_TYPE_SUFFIX(A, B, C, D, E) +#endif + +#ifndef DEF_SVE_FUNCTION +#define DEF_SVE_FUNCTION(A, B, C, D) +#endif + +DEF_SVE_MODE (n, none, none, none) +DEF_SVE_MODE (index, none, none, elements) +DEF_SVE_MODE (offset, none, none, bytes) +DEF_SVE_MODE (s32index, none, svint32_t, elements) +DEF_SVE_MODE (s32offset, none, svint32_t, bytes) +DEF_SVE_MODE (s64index, none, svint64_t, elements) +DEF_SVE_MODE (s64offset, none, svint64_t, bytes) +DEF_SVE_MODE (u32base, svuint32_t, none, none) +DEF_SVE_MODE (u32base_index, svuint32_t, none, elements) +DEF_SVE_MODE (u32base_offset, svuint32_t, none, bytes) +DEF_SVE_MODE (u32base_s32index, svuint32_t, svint32_t, elements) +DEF_SVE_MODE (u32base_s32offset, svuint32_t, svint32_t, bytes) +DEF_SVE_MODE (u32base_u32index, svuint32_t, svuint32_t, elements) +DEF_SVE_MODE (u32base_u32offset, svuint32_t, svuint32_t, bytes) +DEF_SVE_MODE (u32index, none, svuint32_t, elements) +DEF_SVE_MODE (u32offset, none, svuint32_t, bytes) +DEF_SVE_MODE (u64base, svuint64_t, none, none) +DEF_SVE_MODE (u64base_index, svuint64_t, none, elements) +DEF_SVE_MODE (u64base_offset, svuint64_t, none, bytes) +DEF_SVE_MODE (u64base_s64index, svuint64_t, svint64_t, elements) +DEF_SVE_MODE (u64base_s64offset, svuint64_t, svint64_t, bytes) +DEF_SVE_MODE (u64base_u64index, svuint64_t, svuint64_t, elements) +DEF_SVE_MODE (u64base_u64offset, svuint64_t, svuint64_t, bytes) +DEF_SVE_MODE (u64index, none, svuint64_t, elements) +DEF_SVE_MODE (u64offset, none, svuint64_t, bytes) +DEF_SVE_MODE (vnum, none, none, vectors) + +DEF_SVE_TYPE (svbool_t, 10, __SVBool_t, boolean_type_node) +DEF_SVE_TYPE (svfloat16_t, 13, __SVFloat16_t, aarch64_fp16_type_node) +DEF_SVE_TYPE (svfloat32_t, 13, __SVFloat32_t, float_type_node) +DEF_SVE_TYPE (svfloat64_t, 13, __SVFloat64_t, double_type_node) +DEF_SVE_TYPE (svint8_t, 10, __SVInt8_t, intQI_type_node) +DEF_SVE_TYPE (svint16_t, 11, __SVInt16_t, intHI_type_node) +DEF_SVE_TYPE (svint32_t, 11, __SVInt32_t, intSI_type_node) +DEF_SVE_TYPE (svint64_t, 11, __SVInt64_t, intDI_type_node) +DEF_SVE_TYPE (svuint8_t, 11, __SVUint8_t, unsigned_intQI_type_node) +DEF_SVE_TYPE (svuint16_t, 12, __SVUint16_t, unsigned_intHI_type_node) +DEF_SVE_TYPE (svuint32_t, 12, __SVUint32_t, unsigned_intSI_type_node) +DEF_SVE_TYPE (svuint64_t, 12, __SVUint64_t, unsigned_intDI_type_node) + +DEF_SVE_TYPE_SUFFIX (b, svbool_t, bool, 8, VNx16BImode) +DEF_SVE_TYPE_SUFFIX (b8, svbool_t, bool, 8, VNx16BImode) +DEF_SVE_TYPE_SUFFIX (b16, svbool_t, bool, 16, VNx8BImode) +DEF_SVE_TYPE_SUFFIX (b32, svbool_t, bool, 32, VNx4BImode) +DEF_SVE_TYPE_SUFFIX (b64, svbool_t, bool, 64, VNx2BImode) +DEF_SVE_TYPE_SUFFIX (f16, svfloat16_t, float, 16, VNx8HFmode) +DEF_SVE_TYPE_SUFFIX (f32, svfloat32_t, float, 32, VNx4SFmode) +DEF_SVE_TYPE_SUFFIX (f64, svfloat64_t, float, 64, VNx2DFmode) +DEF_SVE_TYPE_SUFFIX (s8, svint8_t, signed, 8, VNx16QImode) +DEF_SVE_TYPE_SUFFIX (s16, svint16_t, signed, 16, VNx8HImode) +DEF_SVE_TYPE_SUFFIX (s32, svint32_t, signed, 32, VNx4SImode) +DEF_SVE_TYPE_SUFFIX (s64, svint64_t, signed, 64, VNx2DImode) +DEF_SVE_TYPE_SUFFIX (u8, svuint8_t, unsigned, 8, VNx16QImode) +DEF_SVE_TYPE_SUFFIX (u16, svuint16_t, unsigned, 16, VNx8HImode) +DEF_SVE_TYPE_SUFFIX (u32, svuint32_t, unsigned, 32, VNx4SImode) +DEF_SVE_TYPE_SUFFIX (u64, svuint64_t, unsigned, 64, VNx2DImode) + +#include "aarch64-sve-builtins-base.def" + +#undef DEF_SVE_FUNCTION +#undef DEF_SVE_TYPE_SUFFIX +#undef DEF_SVE_TYPE +#undef DEF_SVE_MODE diff --git a/gcc/config/aarch64/aarch64-sve-builtins.h b/gcc/config/aarch64/aarch64-sve-builtins.h new file mode 100644 index 0000000..73b07c7 --- /dev/null +++ b/gcc/config/aarch64/aarch64-sve-builtins.h @@ -0,0 +1,873 @@ +/* ACLE support for AArch64 SVE + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_AARCH64_SVE_BUILTINS_H +#define GCC_AARCH64_SVE_BUILTINS_H + +/* The full name of an SVE ACLE function is the concatenation of: + + - the base name ("svadd", etc.) + - the "mode" suffix ("_n", "_index", etc.) + - the type suffixes ("_s32", "_b8", etc.) + - the predication suffix ("_x", "_z", etc.) + + Each piece of information is individually useful, so we retain this + classification throughout: + + - function_base represents the base name + + - mode_suffix_index represents the mode suffix + + - type_suffix_index represents individual type suffixes, while + type_suffix_pair represents a pair of them + + - prediction_index extends the predication suffix with an additional + alternative: PRED_implicit for implicitly-predicated operations + + In addition to its unique full name, a function may have a shorter + overloaded alias. This alias removes pieces of the suffixes that + can be inferred from the arguments, such as by shortening the mode + suffix or dropping some of the type suffixes. The base name and the + predication suffix stay the same. + + The function_shape class describes what arguments a given function + takes and what its overloaded alias is called. In broad terms, + function_base describes how the underlying instruction behaves while + function_shape describes how that instruction has been presented at + the language level. + + The static list of functions uses function_group to describe a group + of related functions. The function_builder class is responsible for + expanding this static description into a list of individual functions + and registering the associated built-in functions. function_instance + describes one of these individual functions in terms of the properties + described above. + + The classes involved in compiling a function call are: + + - function_resolver, which resolves an overloaded function call to a + specific function_instance and its associated function decl + + - function_checker, which checks whether the values of the arguments + conform to the ACLE specification + + - gimple_folder, which tries to fold a function call at the gimple level + + - function_expander, which expands a function call into rtl instructions + + function_resolver and function_checker operate at the language level + and so are associated with the function_shape. gimple_folder and + function_expander are concerned with the behavior of the function + and so are associated with the function_base. + + Note that we've specifically chosen not to fold calls in the frontend, + since SVE intrinsics will hardly ever fold a useful language-level + constant. */ +namespace aarch64_sve +{ +/* The maximum number of vectors in an ACLE tuple type. */ +const unsigned int MAX_TUPLE_SIZE = 4; + +/* Used to represent the default merge argument index for _m functions. + The actual index depends on how many arguments the function takes. */ +const unsigned int DEFAULT_MERGE_ARGNO = ~0U; + +/* Flags that describe what a function might do, in addition to reading + its arguments and returning a result. */ +const unsigned int CP_READ_FPCR = 1U << 0; +const unsigned int CP_RAISE_FP_EXCEPTIONS = 1U << 1; +const unsigned int CP_READ_MEMORY = 1U << 2; +const unsigned int CP_PREFETCH_MEMORY = 1U << 3; +const unsigned int CP_WRITE_MEMORY = 1U << 4; +const unsigned int CP_READ_FFR = 1U << 5; +const unsigned int CP_WRITE_FFR = 1U << 6; + +/* Enumerates the SVE predicate and (data) vector types, together called + "vector types" for brevity. */ +enum vector_type_index +{ +#define DEF_SVE_TYPE(ACLE_NAME, NCHARS, ABI_NAME, SCALAR_TYPE) \ + VECTOR_TYPE_ ## ACLE_NAME, +#include "aarch64-sve-builtins.def" + NUM_VECTOR_TYPES +}; + +/* Classifies the available measurement units for an address displacement. */ +enum units_index +{ + UNITS_none, + UNITS_bytes, + UNITS_elements, + UNITS_vectors +}; + +/* Describes the various uses of a governing predicate. */ +enum predication_index +{ + /* No governing predicate is present. */ + PRED_none, + + /* A governing predicate is present but there is no predication suffix + associated with it. This is used when the result is neither a vector + nor a predicate, since the distinction between "zeroing" and "merging" + doesn't apply in that case. It is also used when a suffix would be + redundant (such as for loads and comparisons, which are inherently + zeroing operations). */ + PRED_implicit, + + /* Merging predication: copy inactive lanes from the first data argument + to the vector result. */ + PRED_m, + + /* "Don't care" predication: set inactive lanes of the vector result + to arbitrary values. */ + PRED_x, + + /* Zero predication: set inactive lanes of the vector result to zero. */ + PRED_z, + + NUM_PREDS +}; + +/* Classifies element types, based on type suffixes with the bit count + removed. */ +enum type_class_index +{ + TYPE_bool, + TYPE_float, + TYPE_signed, + TYPE_unsigned, + NUM_TYPE_CLASSES +}; + +/* Classifies an operation into "modes"; for example, to distinguish + vector-scalar operations from vector-vector operations, or to + distinguish between different addressing modes. This classification + accounts for the function suffixes that occur between the base name + and the first type suffix. */ +enum mode_suffix_index +{ +#define DEF_SVE_MODE(NAME, BASE, DISPLACEMENT, UNITS) MODE_##NAME, +#include "aarch64-sve-builtins.def" + MODE_none +}; + +/* Enumerates the possible type suffixes. Each suffix is associated with + a vector type, but for predicates provides extra information about the + element size. */ +enum type_suffix_index +{ +#define DEF_SVE_TYPE_SUFFIX(NAME, ACLE_TYPE, CLASS, BITS, MODE) \ + TYPE_SUFFIX_ ## NAME, +#include "aarch64-sve-builtins.def" + NUM_TYPE_SUFFIXES +}; + +/* Combines two type suffixes. */ +typedef enum type_suffix_index type_suffix_pair[2]; + +class function_base; +class function_shape; + +/* Static information about a mode suffix. */ +struct mode_suffix_info +{ + /* The suffix string itself. */ + const char *string; + + /* The type of the vector base address, or NUM_VECTOR_TYPES if the + mode does not include a vector base address. */ + vector_type_index base_vector_type; + + /* The type of the vector displacement, or NUM_VECTOR_TYPES if the + mode does not include a vector displacement. (Note that scalar + displacements are always int64_t.) */ + vector_type_index displacement_vector_type; + + /* The units in which the vector or scalar displacement is measured, + or UNITS_none if the mode doesn't take a displacement. */ + units_index displacement_units; +}; + +/* Static information about a type suffix. */ +struct type_suffix_info +{ + /* The suffix string itself. */ + const char *string; + + /* The associated ACLE vector or predicate type. */ + vector_type_index vector_type : 8; + + /* What kind of type the suffix represents. */ + type_class_index tclass : 8; + + /* The number of bits and bytes in an element. For predicates this + measures the associated data elements. */ + unsigned int element_bits : 8; + unsigned int element_bytes : 8; + + /* True if the suffix is for an integer type. */ + unsigned int integer_p : 1; + /* True if the suffix is for an unsigned type. */ + unsigned int unsigned_p : 1; + /* True if the suffix is for a floating-point type. */ + unsigned int float_p : 1; + /* True if the suffix is for a boolean type. */ + unsigned int bool_p : 1; + unsigned int spare : 12; + + /* The associated vector or predicate mode. */ + machine_mode vector_mode : 16; +}; + +/* Static information about a set of functions. */ +struct function_group_info +{ + /* The base name, as a string. */ + const char *base_name; + + /* Describes the behavior associated with the function base name. */ + const function_base *const *base; + + /* The shape of the functions, as described above the class definition. + It's possible to have entries with the same base name but different + shapes. */ + const function_shape *const *shape; + + /* A list of the available type suffixes, and of the available predication + types. The function supports every combination of the two. + + The list of type suffixes is terminated by two NUM_TYPE_SUFFIXES + while the list of predication types is terminated by NUM_PREDS. + The list of type suffixes is lexicographically ordered based + on the index value. */ + const type_suffix_pair *types; + const predication_index *preds; + + /* The architecture extensions that the functions require, as a set of + AARCH64_FL_* flags. */ + uint64_t required_extensions; +}; + +/* Describes a single fully-resolved function (i.e. one that has a + unique full name). */ +class GTY((user)) function_instance +{ +public: + function_instance (const char *, const function_base *, + const function_shape *, mode_suffix_index, + const type_suffix_pair &, predication_index); + + bool operator== (const function_instance &) const; + bool operator!= (const function_instance &) const; + hashval_t hash () const; + + unsigned int call_properties () const; + bool reads_global_state_p () const; + bool modifies_global_state_p () const; + bool could_trap_p () const; + + unsigned int vectors_per_tuple () const; + tree memory_scalar_type () const; + machine_mode memory_vector_mode () const; + + const mode_suffix_info &mode_suffix () const; + tree base_vector_type () const; + tree displacement_vector_type () const; + units_index displacement_units () const; + + const type_suffix_info &type_suffix (unsigned int) const; + tree scalar_type (unsigned int) const; + tree vector_type (unsigned int) const; + tree tuple_type (unsigned int) const; + unsigned int elements_per_vq (unsigned int i) const; + machine_mode vector_mode (unsigned int) const; + machine_mode gp_mode (unsigned int) const; + + /* The properties of the function. (The explicit "enum"s are required + for gengtype.) */ + const char *base_name; + const function_base *base; + const function_shape *shape; + enum mode_suffix_index mode_suffix_id; + type_suffix_pair type_suffix_ids; + enum predication_index pred; +}; + +class registered_function; + +/* A class for building and registering function decls. */ +class function_builder +{ +public: + function_builder (); + ~function_builder (); + + void add_unique_function (const function_instance &, tree, + vec<tree> &, uint64_t, bool); + void add_overloaded_function (const function_instance &, uint64_t); + void add_overloaded_functions (const function_group_info &, + mode_suffix_index); + + void register_function_group (const function_group_info &); + +private: + void append_name (const char *); + char *finish_name (); + + char *get_name (const function_instance &, bool); + + tree get_attributes (const function_instance &); + + registered_function &add_function (const function_instance &, + const char *, tree, tree, uint64_t, bool); + + /* The function type to use for functions that are resolved by + function_resolver. */ + tree m_overload_type; + + /* True if we should create a separate decl for each instance of an + overloaded function, instead of using function_resolver. */ + bool m_direct_overloads; + + /* Used for building up function names. */ + obstack m_string_obstack; + + /* Maps all overloaded function names that we've registered so far + to their associated function_instances. */ + hash_map<nofree_string_hash, registered_function *> m_overload_names; +}; + +/* A base class for handling calls to built-in functions. */ +class function_call_info : public function_instance +{ +public: + function_call_info (location_t, const function_instance &, tree); + + bool function_returns_void_p (); + + /* The location of the call. */ + location_t location; + + /* The FUNCTION_DECL that is being called. */ + tree fndecl; +}; + +/* A class for resolving an overloaded function call. */ +class function_resolver : public function_call_info +{ +public: + enum { SAME_SIZE = 256, HALF_SIZE, QUARTER_SIZE }; + static const type_class_index SAME_TYPE_CLASS = NUM_TYPE_CLASSES; + + function_resolver (location_t, const function_instance &, tree, + vec<tree, va_gc> &); + + tree get_vector_type (type_suffix_index); + const char *get_scalar_type_name (type_suffix_index); + tree get_argument_type (unsigned int); + bool scalar_argument_p (unsigned int); + + tree report_no_such_form (type_suffix_index); + tree lookup_form (mode_suffix_index, + type_suffix_index = NUM_TYPE_SUFFIXES, + type_suffix_index = NUM_TYPE_SUFFIXES); + tree resolve_to (mode_suffix_index, + type_suffix_index = NUM_TYPE_SUFFIXES, + type_suffix_index = NUM_TYPE_SUFFIXES); + + type_suffix_index infer_integer_scalar_type (unsigned int); + type_suffix_index infer_pointer_type (unsigned int, bool = false); + type_suffix_index infer_vector_or_tuple_type (unsigned int, unsigned int); + type_suffix_index infer_vector_type (unsigned int); + type_suffix_index infer_integer_vector_type (unsigned int); + type_suffix_index infer_unsigned_vector_type (unsigned int); + type_suffix_index infer_sd_vector_type (unsigned int); + type_suffix_index infer_tuple_type (unsigned int); + + bool require_vector_or_scalar_type (unsigned int); + + bool require_vector_type (unsigned int, vector_type_index); + bool require_matching_vector_type (unsigned int, type_suffix_index); + bool require_derived_vector_type (unsigned int, unsigned int, + type_suffix_index, + type_class_index = SAME_TYPE_CLASS, + unsigned int = SAME_SIZE); + + bool require_scalar_type (unsigned int, const char *); + bool require_pointer_type (unsigned int); + bool require_matching_integer_scalar_type (unsigned int, unsigned int, + type_suffix_index); + bool require_derived_scalar_type (unsigned int, type_class_index, + unsigned int = SAME_SIZE); + bool require_integer_immediate (unsigned int); + + vector_type_index infer_vector_base_type (unsigned int); + vector_type_index infer_vector_displacement_type (unsigned int); + + mode_suffix_index resolve_sv_displacement (unsigned int, + type_suffix_index, bool); + mode_suffix_index resolve_gather_address (unsigned int, + type_suffix_index, bool); + mode_suffix_index resolve_adr_address (unsigned int); + + bool check_num_arguments (unsigned int); + bool check_gp_argument (unsigned int, unsigned int &, unsigned int &); + tree resolve_unary (type_class_index = SAME_TYPE_CLASS, + unsigned int = SAME_SIZE); + tree resolve_uniform (unsigned int, unsigned int = 0); + tree resolve_uniform_opt_n (unsigned int); + tree finish_opt_n_resolution (unsigned int, unsigned int, type_suffix_index, + type_class_index = SAME_TYPE_CLASS, + unsigned int = SAME_SIZE); + + tree resolve (); + +private: + /* The arguments to the overloaded function. */ + vec<tree, va_gc> &m_arglist; +}; + +/* A class for checking that the semantic constraints on a function call are + satisfied, such as arguments being integer constant expressions with + a particular range. The parent class's FNDECL is the decl that was + called in the original source, before overload resolution. */ +class function_checker : public function_call_info +{ +public: + function_checker (location_t, const function_instance &, tree, + tree, unsigned int, tree *); + + bool require_immediate_either_or (unsigned int, HOST_WIDE_INT, + HOST_WIDE_INT); + bool require_immediate_enum (unsigned int, tree); + bool require_immediate_lane_index (unsigned int, unsigned int = 1); + bool require_immediate_one_of (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT, + HOST_WIDE_INT, HOST_WIDE_INT); + bool require_immediate_range (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT); + + bool check (); + +private: + bool argument_exists_p (unsigned int); + + bool require_immediate (unsigned int, HOST_WIDE_INT &); + + /* The type of the resolved function. */ + tree m_fntype; + + /* The arguments to the function. */ + unsigned int m_nargs; + tree *m_args; + + /* The first argument not associated with the function's predication + type. */ + unsigned int m_base_arg; +}; + +/* A class for folding a gimple function call. */ +class gimple_folder : public function_call_info +{ +public: + gimple_folder (const function_instance &, tree, + gimple_stmt_iterator *, gcall *); + + tree convert_pred (gimple_seq &, tree, unsigned int); + tree fold_contiguous_base (gimple_seq &, tree); + tree load_store_cookie (tree); + + gimple *fold_to_pfalse (); + gimple *fold_to_ptrue (); + gimple *fold_to_vl_pred (unsigned int); + + gimple *fold (); + + /* Where to insert extra statements that feed the final replacement. */ + gimple_stmt_iterator *gsi; + + /* The call we're folding. */ + gcall *call; + + /* The result of the call, or null if none. */ + tree lhs; +}; + +/* A class for expanding a function call into RTL. */ +class function_expander : public function_call_info +{ +public: + function_expander (const function_instance &, tree, tree, rtx); + rtx expand (); + + insn_code direct_optab_handler (optab, unsigned int = 0); + insn_code direct_optab_handler_for_sign (optab, optab, unsigned int = 0, + machine_mode = E_VOIDmode); + + bool overlaps_input_p (rtx); + + rtx get_contiguous_base (machine_mode); + rtx get_fallback_value (machine_mode, unsigned int, + unsigned int, unsigned int &); + rtx get_reg_target (); + rtx get_nonoverlapping_reg_target (); + + void add_output_operand (insn_code); + void add_input_operand (insn_code, rtx); + void add_integer_operand (HOST_WIDE_INT); + void add_mem_operand (machine_mode, rtx); + void add_address_operand (rtx); + void add_fixed_operand (rtx); + rtx generate_insn (insn_code); + + void prepare_gather_address_operands (unsigned int); + void prepare_prefetch_operands (); + void add_ptrue_hint (unsigned int, machine_mode); + void rotate_inputs_left (unsigned int, unsigned int); + bool try_negating_argument (unsigned int, machine_mode); + + rtx use_exact_insn (insn_code); + rtx use_unpred_insn (insn_code); + rtx use_pred_x_insn (insn_code); + rtx use_cond_insn (insn_code, unsigned int = DEFAULT_MERGE_ARGNO); + rtx use_vcond_mask_insn (insn_code, unsigned int = DEFAULT_MERGE_ARGNO); + rtx use_contiguous_load_insn (insn_code); + rtx use_contiguous_prefetch_insn (insn_code); + rtx use_contiguous_store_insn (insn_code); + + rtx map_to_rtx_codes (rtx_code, rtx_code, int, + unsigned int = DEFAULT_MERGE_ARGNO); + rtx map_to_unspecs (int, int, int, unsigned int = DEFAULT_MERGE_ARGNO); + rtx expand_signed_unpred_op (rtx_code, rtx_code); + + /* The function call expression. */ + tree call_expr; + + /* For functions that return a value, this is the preferred location + of that value. It could be null or could have a different mode + from the function return type. */ + rtx possible_target; + + /* The expanded arguments. */ + auto_vec<rtx, 16> args; + +private: + /* Used to build up the operands to an instruction. */ + auto_vec<expand_operand, 8> m_ops; +}; + +/* Provides information about a particular function base name, and handles + tasks related to the base name. */ +class function_base +{ +public: + /* Return a set of CP_* flags that describe what the function might do, + in addition to reading its arguments and returning a result. */ + virtual unsigned int call_properties (const function_instance &) const; + + /* If the function operates on tuples of vectors, return the number + of vectors in the tuples, otherwise return 1. */ + virtual unsigned int vectors_per_tuple () const { return 1; } + + /* If the function addresses memory, return the type of a single + scalar memory element. */ + virtual tree + memory_scalar_type (const function_instance &) const + { + gcc_unreachable (); + } + + /* If the function addresses memory, return a vector mode whose + GET_MODE_NUNITS is the number of elements addressed and whose + GET_MODE_INNER is the mode of a single scalar memory element. */ + virtual machine_mode + memory_vector_mode (const function_instance &) const + { + gcc_unreachable (); + } + + /* Try to fold the given gimple call. Return the new gimple statement + on success, otherwise return null. */ + virtual gimple *fold (gimple_folder &) const { return NULL; } + + /* Expand the given call into rtl. Return the result of the function, + or an arbitrary value if the function doesn't return a result. */ + virtual rtx expand (function_expander &) const = 0; +}; + +/* Classifies functions into "shapes". The idea is to take all the + type signatures for a set of functions, remove the governing predicate + (if any), and classify what's left based on: + + - the number of arguments + + - the process of determining the types in the signature from the mode + and type suffixes in the function name (including types that are not + affected by the suffixes) + + - which arguments must be integer constant expressions, and what range + those arguments have + + - the process for mapping overloaded names to "full" names. */ +class function_shape +{ +public: + virtual bool explicit_type_suffix_p (unsigned int) const = 0; + + /* Define all functions associated with the given group. */ + virtual void build (function_builder &, + const function_group_info &) const = 0; + + /* Try to resolve the overloaded call. Return the non-overloaded + function decl on success and error_mark_node on failure. */ + virtual tree resolve (function_resolver &) const = 0; + + /* Check whether the given call is semantically valid. Return true + if it is, otherwise report an error and return false. */ + virtual bool check (function_checker &) const { return true; } +}; + +/* RAII class for enabling enough SVE features to define the built-in + types and implement the arm_sve.h pragma. */ +class sve_switcher +{ +public: + sve_switcher (); + ~sve_switcher (); + +private: + unsigned long m_old_isa_flags; + bool m_old_have_regs_of_mode[MAX_MACHINE_MODE]; +}; + +extern const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1]; +extern const mode_suffix_info mode_suffixes[MODE_none + 1]; + +extern tree scalar_types[NUM_VECTOR_TYPES]; +extern tree acle_vector_types[MAX_TUPLE_SIZE][NUM_VECTOR_TYPES + 1]; +extern tree acle_svpattern; +extern tree acle_svprfop; + +/* Return the ACLE type svbool_t. */ +inline tree +get_svbool_t (void) +{ + return acle_vector_types[0][VECTOR_TYPE_svbool_t]; +} + +/* Try to find a mode with the given mode_suffix_info fields. Return the + mode on success or MODE_none on failure. */ +inline mode_suffix_index +find_mode_suffix (vector_type_index base_vector_type, + vector_type_index displacement_vector_type, + units_index displacement_units) +{ + for (unsigned int mode_i = 0; mode_i < ARRAY_SIZE (mode_suffixes); ++mode_i) + { + const mode_suffix_info &mode = mode_suffixes[mode_i]; + if (mode.base_vector_type == base_vector_type + && mode.displacement_vector_type == displacement_vector_type + && mode.displacement_units == displacement_units) + return mode_suffix_index (mode_i); + } + return MODE_none; +} + +/* Return the type suffix associated with ELEMENT_BITS-bit elements of type + class TCLASS. */ +inline type_suffix_index +find_type_suffix (type_class_index tclass, unsigned int element_bits) +{ + for (unsigned int i = 0; i < NUM_TYPE_SUFFIXES; ++i) + if (type_suffixes[i].tclass == tclass + && type_suffixes[i].element_bits == element_bits) + return type_suffix_index (i); + gcc_unreachable (); +} + +/* Return the single field in tuple type TYPE. */ +inline tree +tuple_type_field (tree type) +{ + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + return field; + gcc_unreachable (); +} + +inline function_instance:: +function_instance (const char *base_name_in, + const function_base *base_in, + const function_shape *shape_in, + mode_suffix_index mode_suffix_id_in, + const type_suffix_pair &type_suffix_ids_in, + predication_index pred_in) + : base_name (base_name_in), base (base_in), shape (shape_in), + mode_suffix_id (mode_suffix_id_in), pred (pred_in) +{ + memcpy (type_suffix_ids, type_suffix_ids_in, sizeof (type_suffix_ids)); +} + +inline bool +function_instance::operator== (const function_instance &other) const +{ + return (base == other.base + && shape == other.shape + && mode_suffix_id == other.mode_suffix_id + && pred == other.pred + && type_suffix_ids[0] == other.type_suffix_ids[0] + && type_suffix_ids[1] == other.type_suffix_ids[1]); +} + +inline bool +function_instance::operator!= (const function_instance &other) const +{ + return !operator== (other); +} + +/* If the function operates on tuples of vectors, return the number + of vectors in the tuples, otherwise return 1. */ +inline unsigned int +function_instance::vectors_per_tuple () const +{ + return base->vectors_per_tuple (); +} + +/* If the function addresses memory, return the type of a single + scalar memory element. */ +inline tree +function_instance::memory_scalar_type () const +{ + return base->memory_scalar_type (*this); +} + +/* If the function addresses memory, return a vector mode whose + GET_MODE_NUNITS is the number of elements addressed and whose + GET_MODE_INNER is the mode of a single scalar memory element. */ +inline machine_mode +function_instance::memory_vector_mode () const +{ + return base->memory_vector_mode (*this); +} + +/* Return information about the function's mode suffix. */ +inline const mode_suffix_info & +function_instance::mode_suffix () const +{ + return mode_suffixes[mode_suffix_id]; +} + +/* Return the type of the function's vector base address argument, + or null it doesn't have a vector base address. */ +inline tree +function_instance::base_vector_type () const +{ + return acle_vector_types[0][mode_suffix ().base_vector_type]; +} + +/* Return the type of the function's vector index or offset argument, + or null if doesn't have a vector index or offset argument. */ +inline tree +function_instance::displacement_vector_type () const +{ + return acle_vector_types[0][mode_suffix ().displacement_vector_type]; +} + +/* If the function takes a vector or scalar displacement, return the units + in which the displacement is measured, otherwise return UNITS_none. */ +inline units_index +function_instance::displacement_units () const +{ + return mode_suffix ().displacement_units; +} + +/* Return information about type suffix I. */ +inline const type_suffix_info & +function_instance::type_suffix (unsigned int i) const +{ + return type_suffixes[type_suffix_ids[i]]; +} + +/* Return the scalar type associated with type suffix I. */ +inline tree +function_instance::scalar_type (unsigned int i) const +{ + return scalar_types[type_suffix (i).vector_type]; +} + +/* Return the vector type associated with type suffix I. */ +inline tree +function_instance::vector_type (unsigned int i) const +{ + return acle_vector_types[0][type_suffix (i).vector_type]; +} + +/* If the function operates on tuples of vectors, return the tuple type + associated with type suffix I, otherwise return the vector type associated + with type suffix I. */ +inline tree +function_instance::tuple_type (unsigned int i) const +{ + unsigned int num_vectors = vectors_per_tuple (); + return acle_vector_types[num_vectors - 1][type_suffix (i).vector_type]; +} + +/* Return the number of elements of type suffix I that fit within a + 128-bit block. */ +inline unsigned int +function_instance::elements_per_vq (unsigned int i) const +{ + return 128 / type_suffix (i).element_bits; +} + +/* Return the vector or predicate mode associated with type suffix I. */ +inline machine_mode +function_instance::vector_mode (unsigned int i) const +{ + return type_suffix (i).vector_mode; +} + +/* Return the mode of the governing predicate to use when operating on + type suffix I. */ +inline machine_mode +function_instance::gp_mode (unsigned int i) const +{ + return aarch64_sve_pred_mode (type_suffix (i).element_bytes).require (); +} + +/* Return true if the function has no return value. */ +inline bool +function_call_info::function_returns_void_p () +{ + return TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; +} + +/* Default implementation of function::call_properties, with conservatively + correct behavior for floating-point instructions. */ +inline unsigned int +function_base::call_properties (const function_instance &instance) const +{ + unsigned int flags = 0; + if (instance.type_suffix (0).float_p || instance.type_suffix (1).float_p) + flags |= CP_READ_FPCR | CP_RAISE_FP_EXCEPTIONS; + return flags; +} + +} + +#endif diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 2d93d72..57db06a 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -27,19 +27,35 @@ ;; ---- Description of UNSPEC_PRED_Z ;; ---- Note on predicated integer arithemtic and UNSPEC_PRED_X ;; ---- Note on predicated FP arithmetic patterns and GP "strictness" +;; ---- Note on FFR handling ;; ;; == Moves ;; ---- Moves of single vectors ;; ---- Moves of multiple vectors ;; ---- Moves of predicates +;; ---- Moves relating to the FFR ;; ;; == Loads ;; ---- Normal contiguous loads +;; ---- Extending contiguous loads +;; ---- First-faulting contiguous loads +;; ---- First-faulting extending contiguous loads +;; ---- Non-temporal contiguous loads ;; ---- Normal gather loads +;; ---- Extending gather loads +;; ---- First-faulting gather loads +;; ---- First-faulting extending gather loads +;; +;; == Prefetches +;; ---- Contiguous prefetches +;; ---- Gather prefetches ;; ;; == Stores ;; ---- Normal contiguous stores +;; ---- Truncating contiguous stores +;; ---- Non-temporal contiguous stores ;; ---- Normal scatter stores +;; ---- Truncating scatter stores ;; ;; == Vector creation ;; ---- [INT,FP] Duplicate element @@ -55,8 +71,10 @@ ;; == Unary arithmetic ;; ---- [INT] General unary arithmetic corresponding to rtx codes ;; ---- [INT] General unary arithmetic corresponding to unspecs +;; ---- [INT] Sign extension ;; ---- [INT] Zero extension ;; ---- [INT] Logical inverse +;; ---- [FP<-INT] General unary arithmetic that maps to unspecs ;; ---- [FP] General unary arithmetic corresponding to unspecs ;; ---- [PRED] Inverse @@ -66,15 +84,18 @@ ;; ---- [INT] Subtraction ;; ---- [INT] Take address ;; ---- [INT] Absolute difference +;; ---- [INT] Saturating addition and subtraction ;; ---- [INT] Highpart multiplication ;; ---- [INT] Division ;; ---- [INT] Binary logical operations ;; ---- [INT] Binary logical operations (inverted second input) -;; ---- [INT] Shifts +;; ---- [INT] Shifts (rounding towards -Inf) ;; ---- [INT] Shifts (rounding towards 0) +;; ---- [FP<-INT] General binary arithmetic corresponding to unspecs ;; ---- [FP] General binary arithmetic corresponding to rtx codes ;; ---- [FP] General binary arithmetic corresponding to unspecs ;; ---- [FP] Addition +;; ---- [FP] Complex addition ;; ---- [FP] Subtraction ;; ---- [FP] Absolute difference ;; ---- [FP] Multiplication @@ -91,6 +112,8 @@ ;; ---- [INT] Dot product ;; ---- [INT] Sum of absolute differences ;; ---- [FP] General ternary arithmetic corresponding to unspecs +;; ---- [FP] Complex multiply-add +;; ---- [FP] Trigonometric multiply-add ;; ;; == Comparisons and selects ;; ---- [INT,FP] Select based on predicates @@ -99,6 +122,7 @@ ;; ---- [INT] While tests ;; ---- [FP] Direct comparisons ;; ---- [FP] Absolute comparisons +;; ---- [PRED] Select ;; ---- [PRED] Test bits ;; ;; == Reductions @@ -127,6 +151,23 @@ ;; ---- [FP<-FP] Unpacks ;; ---- [PRED<-PRED] Packs ;; ---- [PRED<-PRED] Unpacks +;; +;; == Vector partitioning +;; ---- [PRED] Unary partitioning +;; ---- [PRED] Binary partitioning +;; ---- [PRED] Scalarization +;; +;; == Counting elements +;; ---- [INT] Count elements in a pattern (scalar) +;; ---- [INT] Increment by the number of elements in a pattern (scalar) +;; ---- [INT] Increment by the number of elements in a pattern (vector) +;; ---- [INT] Decrement by the number of elements in a pattern (scalar) +;; ---- [INT] Decrement by the number of elements in a pattern (vector) +;; ---- [INT] Count elements in a predicate (scalar) +;; ---- [INT] Increment by the number of elements in a predicate (scalar) +;; ---- [INT] Increment by the number of elements in a predicate (vector) +;; ---- [INT] Decrement by the number of elements in a predicate (scalar) +;; ---- [INT] Decrement by the number of elements in a predicate (vector) ;; ========================================================================= ;; == General notes @@ -415,6 +456,73 @@ ;; - OP0 OP1 ... are the normal input operands to the operation. ;; ;; - MNEMONIC is the mnemonic of the associated SVE instruction. +;; +;; ------------------------------------------------------------------------- +;; ---- Note on FFR handling +;; ------------------------------------------------------------------------- +;; +;; Logically we want to divide FFR-related instructions into regions +;; that contain exactly one of: +;; +;; - a single write to the FFR +;; - any number of reads from the FFR (but only one read is likely) +;; - any number of LDFF1 and LDNF1 instructions +;; +;; However, LDFF1 and LDNF1 instructions should otherwise behave like +;; normal loads as far as possible. This means that they should be +;; schedulable within a region in the same way that LD1 would be, +;; and they should be deleted as dead if the result is unused. The loads +;; should therefore not write to the FFR, since that would both serialize +;; the loads with respect to each other and keep the loads live for any +;; later RDFFR. +;; +;; We get around this by using a fake "FFR token" (FFRT) to help describe +;; the dependencies. Writing to the FFRT starts a new "FFRT region", +;; while using the FFRT keeps the instruction within its region. +;; Specifically: +;; +;; - Writes start a new FFRT region as well as setting the FFR: +;; +;; W1: parallel (FFRT = <new value>, FFR = <actual FFR value>) +;; +;; - Loads use an LD1-like instruction that also uses the FFRT, so that the +;; loads stay within the same FFRT region: +;; +;; L1: load data while using the FFRT +;; +;; In addition, any FFRT region that includes a load also has at least one +;; instance of: +;; +;; L2: FFR = update(FFR, FFRT) [type == no_insn] +;; +;; to make it clear that the region both reads from and writes to the FFR. +;; +;; - Reads do the following: +;; +;; R1: FFRT = FFR [type == no_insn] +;; R2: read from the FFRT +;; R3: FFRT = update(FFRT) [type == no_insn] +;; +;; R1 and R3 both create new FFRT regions, so that previous LDFF1s and +;; LDNF1s cannot move forwards across R1 and later LDFF1s and LDNF1s +;; cannot move backwards across R3. +;; +;; This way, writes are only kept alive by later loads or reads, +;; and write/read pairs fold normally. For two consecutive reads, +;; the first R3 is made dead by the second R1, which in turn becomes +;; redundant with the first R1. We then have: +;; +;; first R1: FFRT = FFR +;; first read from the FFRT +;; second read from the FFRT +;; second R3: FFRT = update(FFRT) +;; +;; i.e. the two FFRT regions collapse into a single one with two +;; independent reads. +;; +;; The model still prevents some valid optimizations though. For example, +;; if all loads in an FFRT region are deleted as dead, nothing would remove +;; the L2 instructions. ;; ========================================================================= ;; == Moves @@ -594,15 +702,14 @@ ;; special predicate for operand 1 to reduce the number of patterns. (define_insn_and_split "*aarch64_sve_reinterpret<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w") - (unspec:SVE_ALL [(match_operand 1 "aarch64_any_register_operand" "0")] + (unspec:SVE_ALL [(match_operand 1 "aarch64_any_register_operand" "w")] UNSPEC_REINTERPRET))] "TARGET_SVE" "#" "&& reload_completed" [(set (match_dup 0) (match_dup 1))] { - emit_note (NOTE_INSN_DELETED); - DONE; + operands[1] = aarch64_replace_reg_mode (operands[1], <MODE>mode); } ) @@ -719,6 +826,7 @@ ;; - LDR ;; - PFALSE ;; - PTRUE +;; - PTRUES ;; - STR ;; ------------------------------------------------------------------------- @@ -751,6 +859,258 @@ * return aarch64_output_sve_mov_immediate (operands[1]);" ) +;; Match PTRUES Pn.B when both the predicate and flags are useful. +(define_insn_and_rewrite "*aarch64_sve_ptruevnx16bi_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 2) + (match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operator:VNx16BI 1 "aarch64_sve_ptrue_svpattern_immediate" + [(unspec:VNx16BI + [(match_operand:SI 4 "const_int_operand") + (match_operand:VNx16BI 5 "aarch64_simd_imm_zero")] + UNSPEC_PTRUE)])] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (match_dup 1))] + "TARGET_SVE" + { + return aarch64_output_sve_ptrues (operands[1]); + } + "&& (!CONSTANT_P (operands[2]) || !CONSTANT_P (operands[3]))" + { + operands[2] = operands[3] = CONSTM1_RTX (VNx16BImode); + } +) + +;; Match PTRUES Pn.[HSD] when both the predicate and flags are useful. +(define_insn_and_rewrite "*aarch64_sve_ptrue<mode>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 2) + (match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (subreg:PRED_HSD + (match_operator:VNx16BI 1 "aarch64_sve_ptrue_svpattern_immediate" + [(unspec:VNx16BI + [(match_operand:SI 4 "const_int_operand") + (match_operand:PRED_HSD 5 "aarch64_simd_imm_zero")] + UNSPEC_PTRUE)]) 0)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (match_dup 1))] + "TARGET_SVE" + { + return aarch64_output_sve_ptrues (operands[1]); + } + "&& (!CONSTANT_P (operands[2]) || !CONSTANT_P (operands[3]))" + { + operands[2] = CONSTM1_RTX (VNx16BImode); + operands[3] = CONSTM1_RTX (<MODE>mode); + } +) + +;; Match PTRUES Pn.B when only the flags result is useful (which is +;; a way of testing VL). +(define_insn_and_rewrite "*aarch64_sve_ptruevnx16bi_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 2) + (match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operator:VNx16BI 1 "aarch64_sve_ptrue_svpattern_immediate" + [(unspec:VNx16BI + [(match_operand:SI 4 "const_int_operand") + (match_operand:VNx16BI 5 "aarch64_simd_imm_zero")] + UNSPEC_PTRUE)])] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + { + return aarch64_output_sve_ptrues (operands[1]); + } + "&& (!CONSTANT_P (operands[2]) || !CONSTANT_P (operands[3]))" + { + operands[2] = operands[3] = CONSTM1_RTX (VNx16BImode); + } +) + +;; Match PTRUES Pn.[HWD] when only the flags result is useful (which is +;; a way of testing VL). +(define_insn_and_rewrite "*aarch64_sve_ptrue<mode>_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 2) + (match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (subreg:PRED_HSD + (match_operator:VNx16BI 1 "aarch64_sve_ptrue_svpattern_immediate" + [(unspec:VNx16BI + [(match_operand:SI 4 "const_int_operand") + (match_operand:PRED_HSD 5 "aarch64_simd_imm_zero")] + UNSPEC_PTRUE)]) 0)] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + { + return aarch64_output_sve_ptrues (operands[1]); + } + "&& (!CONSTANT_P (operands[2]) || !CONSTANT_P (operands[3]))" + { + operands[2] = CONSTM1_RTX (VNx16BImode); + operands[3] = CONSTM1_RTX (<MODE>mode); + } +) + +;; ------------------------------------------------------------------------- +;; ---- Moves relating to the FFR +;; ------------------------------------------------------------------------- +;; RDFFR +;; RDFFRS +;; SETFFR +;; WRFFR +;; ------------------------------------------------------------------------- + +;; [W1 in the block comment above about FFR handling] +;; +;; Write to the FFR and start a new FFRT scheduling region. +(define_insn "aarch64_wrffr" + [(set (reg:VNx16BI FFR_REGNUM) + (match_operand:VNx16BI 0 "aarch64_simd_reg_or_minus_one" "Dm, Upa")) + (set (reg:VNx16BI FFRT_REGNUM) + (match_dup 0))] + "TARGET_SVE" + "@ + setffr + wrffr\t%0.b" +) + +;; [L2 in the block comment above about FFR handling] +;; +;; Introduce a read from and write to the FFR in the current FFRT region, +;; so that the FFR value is live on entry to the region and so that the FFR +;; value visibly changes within the region. This is used (possibly multiple +;; times) in an FFRT region that includes LDFF1 or LDNF1 instructions. +(define_insn "aarch64_update_ffr_for_load" + [(set (reg:VNx16BI FFR_REGNUM) + (unspec:VNx16BI [(reg:VNx16BI FFRT_REGNUM) + (reg:VNx16BI FFR_REGNUM)] UNSPEC_UPDATE_FFR))] + "TARGET_SVE" + "" + [(set_attr "type" "no_insn")] +) + +;; [R1 in the block comment above about FFR handling] +;; +;; Notionally copy the FFR to the FFRT, so that the current FFR value +;; can be read from there by the RDFFR instructions below. This acts +;; as a scheduling barrier for earlier LDFF1 and LDNF1 instructions and +;; creates a natural dependency with earlier writes. +(define_insn "aarch64_copy_ffr_to_ffrt" + [(set (reg:VNx16BI FFRT_REGNUM) + (reg:VNx16BI FFR_REGNUM))] + "TARGET_SVE" + "" + [(set_attr "type" "no_insn")] +) + +;; [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") + (reg:VNx16BI FFRT_REGNUM))] + "TARGET_SVE" + "rdffr\t%0.b" +) + +;; Likewise with zero predication. +(define_insn "aarch64_rdffr_z" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (reg:VNx16BI FFRT_REGNUM) + (match_operand:VNx16BI 1 "register_operand" "Upa")))] + "TARGET_SVE" + "rdffr\t%0.b, %1/z" +) + +;; Read the FFR to test for a fault, without using the predicate result. +(define_insn "*aarch64_rdffr_z_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (and:VNx16BI + (reg:VNx16BI FFRT_REGNUM) + (match_dup 1))] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "rdffrs\t%0.b, %1/z" +) + +;; Same for unpredicated RDFFR when tested with a known PTRUE. +(define_insn "*aarch64_rdffr_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (const_int SVE_KNOWN_PTRUE) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "rdffrs\t%0.b, %1/z" +) + +;; Read the FFR with zero predication and test the result. +(define_insn "*aarch64_rdffr_z_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (and:VNx16BI + (reg:VNx16BI FFRT_REGNUM) + (match_dup 1))] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (reg:VNx16BI FFRT_REGNUM) + (match_dup 1)))] + "TARGET_SVE" + "rdffrs\t%0.b, %1/z" +) + +;; Same for unpredicated RDFFR when tested with a known PTRUE. +(define_insn "*aarch64_rdffr_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (const_int SVE_KNOWN_PTRUE) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (reg:VNx16BI FFRT_REGNUM))] + "TARGET_SVE" + "rdffrs\t%0.b, %1/z" +) + +;; [R3 in the block comment above about FFR handling] +;; +;; Arbitrarily update the FFRT after a read from the FFR. This acts as +;; a scheduling barrier for later LDFF1 and LDNF1 instructions. +(define_insn "aarch64_update_ffrt" + [(set (reg:VNx16BI FFRT_REGNUM) + (unspec:VNx16BI [(reg:VNx16BI FFRT_REGNUM)] UNSPEC_UPDATE_FFRT))] + "TARGET_SVE" + "" + [(set_attr "type" "no_insn")] +) + ;; ========================================================================= ;; == Loads ;; ========================================================================= @@ -813,6 +1173,161 @@ ) ;; ------------------------------------------------------------------------- +;; ---- Extending contiguous loads +;; ------------------------------------------------------------------------- +;; Includes contiguous forms of: +;; LD1B +;; LD1H +;; LD1SB +;; LD1SH +;; LD1SW +;; LD1W +;; ------------------------------------------------------------------------- + +;; Predicated load and extend, with 8 elements per 128-bit block. +(define_insn "@aarch64_load_<ANY_EXTEND:optab><VNx8_WIDE:mode><VNx8_NARROW:mode>" + [(set (match_operand:VNx8_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx8_WIDE + (unspec:VNx8_NARROW + [(match_operand:VNx8BI 2 "register_operand" "Upl") + (match_operand:VNx8_NARROW 1 "memory_operand" "m")] + UNSPEC_LD1_SVE)))] + "TARGET_SVE" + "ld1<ANY_EXTEND:s><VNx8_NARROW:Vesize>\t%0.<VNx8_WIDE:Vetype>, %2/z, %1" +) + +;; Predicated load and extend, with 4 elements per 128-bit block. +(define_insn "@aarch64_load_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>" + [(set (match_operand:VNx4_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx4_WIDE + (unspec:VNx4_NARROW + [(match_operand:VNx4BI 2 "register_operand" "Upl") + (match_operand:VNx4_NARROW 1 "memory_operand" "m")] + UNSPEC_LD1_SVE)))] + "TARGET_SVE" + "ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.<VNx4_WIDE:Vetype>, %2/z, %1" +) + +;; Predicated load and extend, with 2 elements per 128-bit block. +(define_insn "@aarch64_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 2 "register_operand" "Upl") + (match_operand:VNx2_NARROW 1 "memory_operand" "m")] + UNSPEC_LD1_SVE)))] + "TARGET_SVE" + "ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.<VNx2_WIDE:Vetype>, %2/z, %1" +) + +;; ------------------------------------------------------------------------- +;; ---- First-faulting contiguous loads +;; ------------------------------------------------------------------------- +;; Includes contiguous forms of: +;; - LDFF1B +;; - LDFF1D +;; - LDFF1H +;; - LDFF1W +;; - LDNF1B +;; - LDNF1D +;; - LDNF1H +;; - LDNF1W +;; ------------------------------------------------------------------------- + +;; Contiguous non-extending first-faulting or non-faulting loads. +(define_insn "@aarch64_ld<fn>f1<mode>" + [(set (match_operand:SVE_ALL 0 "register_operand" "=w") + (unspec:SVE_ALL + [(match_operand:<VPRED> 2 "register_operand" "Upl") + (match_operand:SVE_ALL 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>") + (reg:VNx16BI FFRT_REGNUM)] + SVE_LDFF1_LDNF1))] + "TARGET_SVE" + "ld<fn>f1<Vesize>\t%0.<Vetype>, %2/z, %1" +) + +;; ------------------------------------------------------------------------- +;; ---- First-faulting extending contiguous loads +;; ------------------------------------------------------------------------- +;; Includes contiguous forms of: +;; - LDFF1B +;; - LDFF1H +;; - LDFF1SB +;; - LDFF1SH +;; - LDFF1SW +;; - LDFF1W +;; - LDNF1B +;; - LDNF1H +;; - LDNF1SB +;; - LDNF1SH +;; - LDNF1SW +;; - LDNF1W +;; ------------------------------------------------------------------------- + +;; Predicated first-faulting or non-faulting load and extend, with 8 elements +;; per 128-bit block. +(define_insn "@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx8_WIDE:mode><VNx8_NARROW:mode>" + [(set (match_operand:VNx8_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx8_WIDE + (unspec:VNx8_NARROW + [(match_operand:VNx8BI 2 "register_operand" "Upl") + (match_operand:VNx8_NARROW 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>") + (reg:VNx16BI FFRT_REGNUM)] + SVE_LDFF1_LDNF1)))] + "TARGET_SVE" + "ld<fn>f1<ANY_EXTEND:s><VNx8_NARROW:Vesize>\t%0.<VNx8_WIDE:Vetype>, %2/z, %1" +) + +;; Predicated first-faulting or non-faulting load and extend, with 4 elements +;; per 128-bit block. +(define_insn "@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>" + [(set (match_operand:VNx4_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx4_WIDE + (unspec:VNx4_NARROW + [(match_operand:VNx4BI 2 "register_operand" "Upl") + (match_operand:VNx4_NARROW 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>") + (reg:VNx16BI FFRT_REGNUM)] + SVE_LDFF1_LDNF1)))] + "TARGET_SVE" + "ld<fn>f1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.<VNx4_WIDE:Vetype>, %2/z, %1" +) + +;; Predicated first-faulting or non-faulting load and extend, with 2 elements +;; per 128-bit block. +(define_insn "@aarch64_ld<fn>f1_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 2 "register_operand" "Upl") + (match_operand:VNx2_NARROW 1 "aarch64_sve_ld<fn>f1_operand" "Ut<fn>") + (reg:VNx16BI FFRT_REGNUM)] + SVE_LDFF1_LDNF1)))] + "TARGET_SVE" + "ld<fn>f1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.<VNx2_WIDE:Vetype>, %2/z, %1" +) + +;; ------------------------------------------------------------------------- +;; ---- Non-temporal contiguous loads +;; ------------------------------------------------------------------------- +;; Includes: +;; - LDNT1B +;; - LDNT1D +;; - LDNT1H +;; - LDNT1W +;; ------------------------------------------------------------------------- + +;; Predicated contiguous non-temporal load. +(define_insn "@aarch64_ldnt1<mode>" + [(set (match_operand:SVE_ALL 0 "register_operand" "=w") + (unspec:SVE_ALL + [(match_operand:<VPRED> 2 "register_operand" "Upl") + (match_operand:SVE_ALL 1 "memory_operand" "m")] + UNSPEC_LDNT1_SVE))] + "TARGET_SVE" + "ldnt1<Vesize>\t%0.<Vetype>, %2/z, %1" +) + +;; ------------------------------------------------------------------------- ;; ---- Normal gather loads ;; ------------------------------------------------------------------------- ;; Includes gather forms of: @@ -825,7 +1340,7 @@ [(set (match_operand:SVE_SD 0 "register_operand") (unspec:SVE_SD [(match_dup 5) - (match_operand:DI 1 "aarch64_reg_or_zero") + (match_operand:DI 1 "aarch64_sve_gather_offset_<Vesize>") (match_operand:<V_INT_EQUIV> 2 "register_operand") (match_operand:DI 3 "const_int_operand") (match_operand:DI 4 "aarch64_gather_scale_operand_<Vesize>") @@ -840,18 +1355,19 @@ ;; Predicated gather loads for 32-bit elements. Operand 3 is true for ;; unsigned extension and false for signed extension. (define_insn "mask_gather_load<mode>" - [(set (match_operand:SVE_S 0 "register_operand" "=w, w, w, w, w") + [(set (match_operand:SVE_S 0 "register_operand" "=w, w, w, w, w, w") (unspec:SVE_S - [(match_operand:<VPRED> 5 "register_operand" "Upl, Upl, Upl, Upl, Upl") - (match_operand:DI 1 "aarch64_reg_or_zero" "Z, rk, rk, rk, rk") - (match_operand:<V_INT_EQUIV> 2 "register_operand" "w, w, w, w, w") - (match_operand:DI 3 "const_int_operand" "i, Z, Ui1, Z, Ui1") - (match_operand:DI 4 "aarch64_gather_scale_operand_w" "Ui1, Ui1, Ui1, i, i") + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_w" "Z, vgw, rk, rk, rk, rk") + (match_operand:VNx4SI 2 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 3 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1") + (match_operand:DI 4 "aarch64_gather_scale_operand_w" "Ui1, Ui1, Ui1, Ui1, i, i") (mem:BLK (scratch))] UNSPEC_LD1_GATHER))] "TARGET_SVE" "@ ld1w\t%0.s, %5/z, [%2.s] + ld1w\t%0.s, %5/z, [%2.s, #%1] ld1w\t%0.s, %5/z, [%1, %2.s, sxtw] ld1w\t%0.s, %5/z, [%1, %2.s, uxtw] ld1w\t%0.s, %5/z, [%1, %2.s, sxtw %p4] @@ -861,22 +1377,539 @@ ;; Predicated gather loads for 64-bit elements. The value of operand 3 ;; doesn't matter in this case. (define_insn "mask_gather_load<mode>" - [(set (match_operand:SVE_D 0 "register_operand" "=w, w, w") + [(set (match_operand:SVE_D 0 "register_operand" "=w, w, w, w") (unspec:SVE_D - [(match_operand:<VPRED> 5 "register_operand" "Upl, Upl, Upl") - (match_operand:DI 1 "aarch64_reg_or_zero" "Z, rk, rk") - (match_operand:<V_INT_EQUIV> 2 "register_operand" "w, w, w") + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_d" "Z, vgd, rk, rk") + (match_operand:VNx2DI 2 "register_operand" "w, w, w, w") (match_operand:DI 3 "const_int_operand") - (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, Ui1, i") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, Ui1, Ui1, i") (mem:BLK (scratch))] UNSPEC_LD1_GATHER))] "TARGET_SVE" "@ ld1d\t%0.d, %5/z, [%2.d] + ld1d\t%0.d, %5/z, [%2.d, #%1] ld1d\t%0.d, %5/z, [%1, %2.d] ld1d\t%0.d, %5/z, [%1, %2.d, lsl %p4]" ) +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn "*mask_gather_load<mode>_sxtw" + [(set (match_operand:SVE_D 0 "register_operand" "=w, w") + (unspec:SVE_D + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (unspec:VNx2DI + [(match_dup 5) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER))] + "TARGET_SVE" + "@ + ld1d\t%0.d, %5/z, [%1, %2.d, sxtw] + ld1d\t%0.d, %5/z, [%1, %2.d, sxtw %p4]" +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*mask_gather_load<mode>_uxtw" + [(set (match_operand:SVE_D 0 "register_operand" "=w, w") + (unspec:SVE_D + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 2 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER))] + "TARGET_SVE" + "@ + ld1d\t%0.d, %5/z, [%1, %2.d, uxtw] + ld1d\t%0.d, %5/z, [%1, %2.d, uxtw %p4]" +) + +;; ------------------------------------------------------------------------- +;; ---- Extending gather loads +;; ------------------------------------------------------------------------- +;; Includes gather forms of: +;; - LD1B +;; - LD1H +;; - LD1SB +;; - LD1SH +;; - LD1SW +;; - LD1W +;; ------------------------------------------------------------------------- + +;; Predicated extending gather loads for 32-bit elements. Operand 3 is +;; true for unsigned extension and false for signed extension. +(define_insn "@aarch64_gather_load_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>" + [(set (match_operand:VNx4_WIDE 0 "register_operand" "=w, w, w, w, w, w") + (ANY_EXTEND:VNx4_WIDE + (unspec:VNx4_NARROW + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<VNx4_NARROW:Vesize>" "Z, vg<VNx4_NARROW:Vesize>, rk, rk, rk, rk") + (match_operand:VNx4_WIDE 2 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 3 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx4_NARROW:Vesize>" "Ui1, Ui1, Ui1, Ui1, i, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER)))] + "TARGET_SVE" + "@ + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%2.s] + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%2.s, #%1] + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, sxtw] + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, uxtw] + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, sxtw %p4] + ld1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, uxtw %p4]" +) + +;; Predicated extending gather loads for 64-bit elements. The value of +;; operand 3 doesn't matter in this case. +(define_insn "@aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w, w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<VNx2_NARROW:Vesize>" "Z, vg<VNx2_NARROW:Vesize>, rk, rk") + (match_operand:VNx2_WIDE 2 "register_operand" "w, w, w, w") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, Ui1, Ui1, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER)))] + "TARGET_SVE" + "@ + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%2.d] + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%2.d, #%1] + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d] + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, lsl %p4]" +) + +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_sxtw" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "aarch64_reg_or_zero" "rk, rk") + (unspec:VNx2DI + [(match_operand 6) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER)))] + "TARGET_SVE" + "@ + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, sxtw] + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, sxtw %p4]" + "&& !rtx_equal_p (operands[5], operands[6])" + { + operands[6] = copy_rtx (operands[5]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*aarch64_gather_load_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_uxtw" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "aarch64_reg_or_zero" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 2 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (mem:BLK (scratch))] + UNSPEC_LD1_GATHER)))] + "TARGET_SVE" + "@ + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, uxtw] + ld1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, uxtw %p4]" +) + +;; ------------------------------------------------------------------------- +;; ---- First-faulting gather loads +;; ------------------------------------------------------------------------- +;; Includes gather forms of: +;; - LDFF1D +;; - LDFF1W +;; ------------------------------------------------------------------------- + +;; Predicated first-faulting gather loads for 32-bit elements. Operand +;; 3 is true for unsigned extension and false for signed extension. +(define_insn "@aarch64_ldff1_gather<mode>" + [(set (match_operand:SVE_S 0 "register_operand" "=w, w, w, w, w, w") + (unspec:SVE_S + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_w" "Z, vgw, rk, rk, rk, rk") + (match_operand:VNx4SI 2 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 3 "const_int_operand" "i, i, Z, Ui1, Z, Ui1") + (match_operand:DI 4 "aarch64_gather_scale_operand_w" "Ui1, Ui1, Ui1, Ui1, i, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER))] + "TARGET_SVE" + "@ + ldff1w\t%0.s, %5/z, [%2.s] + ldff1w\t%0.s, %5/z, [%2.s, #%1] + ldff1w\t%0.s, %5/z, [%1, %2.s, sxtw] + ldff1w\t%0.s, %5/z, [%1, %2.s, uxtw] + ldff1w\t%0.s, %5/z, [%1, %2.s, sxtw %p4] + ldff1w\t%0.s, %5/z, [%1, %2.s, uxtw %p4]" +) + +;; Predicated first-faulting gather loads for 64-bit elements. The value +;; of operand 3 doesn't matter in this case. +(define_insn "@aarch64_ldff1_gather<mode>" + [(set (match_operand:SVE_D 0 "register_operand" "=w, w, w, w") + (unspec:SVE_D + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_d" "Z, vgd, rk, rk") + (match_operand:VNx2DI 2 "register_operand" "w, w, w, w") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, Ui1, Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER))] + "TARGET_SVE" + "@ + ldff1d\t%0.d, %5/z, [%2.d] + ldff1d\t%0.d, %5/z, [%2.d, #%1] + ldff1d\t%0.d, %5/z, [%1, %2.d] + ldff1d\t%0.d, %5/z, [%1, %2.d, lsl %p4]" +) + +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*aarch64_ldff1_gather<mode>_sxtw" + [(set (match_operand:SVE_D 0 "register_operand" "=w, w") + (unspec:SVE_D + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (unspec:VNx2DI + [(match_operand 6) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER))] + "TARGET_SVE" + "@ + ldff1d\t%0.d, %5/z, [%1, %2.d, sxtw] + ldff1d\t%0.d, %5/z, [%1, %2.d, sxtw %p4]" + "&& !rtx_equal_p (operands[5], operands[6])" + { + operands[6] = copy_rtx (operands[5]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*aarch64_ldff1_gather<mode>_uxtw" + [(set (match_operand:SVE_D 0 "register_operand" "=w, w") + (unspec:SVE_D + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 2 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_d" "Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER))] + "TARGET_SVE" + "@ + ldff1d\t%0.d, %5/z, [%1, %2.d, uxtw] + ldff1d\t%0.d, %5/z, [%1, %2.d, uxtw %p4]" +) + +;; ------------------------------------------------------------------------- +;; ---- First-faulting extending gather loads +;; ------------------------------------------------------------------------- +;; Includes gather forms of: +;; - LDFF1B +;; - LDFF1H +;; - LDFF1SB +;; - LDFF1SH +;; - LDFF1SW +;; - LDFF1W +;; ------------------------------------------------------------------------- + +;; Predicated extending first-faulting gather loads for 32-bit elements. +;; Operand 3 is true for unsigned extension and false for signed extension. +(define_insn "@aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx4_WIDE:mode><VNx4_NARROW:mode>" + [(set (match_operand:VNx4_WIDE 0 "register_operand" "=w, w, w, w, w, w") + (ANY_EXTEND:VNx4_WIDE + (unspec:VNx4_NARROW + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<VNx4_NARROW:Vesize>" "Z, vg<VNx4_NARROW:Vesize>, rk, rk, rk, rk") + (match_operand:VNx4_WIDE 2 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 3 "const_int_operand" "i, i, Z, Ui1, Z, Ui1") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx4_NARROW:Vesize>" "Ui1, Ui1, Ui1, Ui1, i, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER)))] + "TARGET_SVE" + "@ + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%2.s] + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%2.s, #%1] + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, sxtw] + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, uxtw] + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, sxtw %p4] + ldff1<ANY_EXTEND:s><VNx4_NARROW:Vesize>\t%0.s, %5/z, [%1, %2.s, uxtw %p4]" +) + +;; Predicated extending first-faulting gather loads for 64-bit elements. +;; The value of operand 3 doesn't matter in this case. +(define_insn "@aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w, w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<VNx2_NARROW:Vesize>" "Z, vg<VNx2_NARROW:Vesize>, rk, rk") + (match_operand:VNx2_WIDE 2 "register_operand" "w, w, w, w") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, Ui1, Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER)))] + "TARGET_SVE" + "@ + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%2.d] + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%2.d, #%1] + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d] + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, lsl %p4]" +) + +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_sxtw" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "aarch64_reg_or_zero" "rk, rk") + (unspec:VNx2DI + [(match_operand 6) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER)))] + "TARGET_SVE" + "@ + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, sxtw] + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, sxtw %p4]" + "&& !rtx_equal_p (operands[5], operands[6])" + { + operands[6] = copy_rtx (operands[5]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*aarch64_ldff1_gather_<ANY_EXTEND:optab><VNx2_WIDE:mode><VNx2_NARROW:mode>_uxtw" + [(set (match_operand:VNx2_WIDE 0 "register_operand" "=w, w") + (ANY_EXTEND:VNx2_WIDE + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 1 "aarch64_reg_or_zero" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 2 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (mem:BLK (scratch)) + (reg:VNx16BI FFRT_REGNUM)] + UNSPEC_LDFF1_GATHER)))] + "TARGET_SVE" + "@ + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, uxtw] + ldff1<ANY_EXTEND:s><VNx2_NARROW:Vesize>\t%0.d, %5/z, [%1, %2.d, uxtw %p4]" +) + +;; ========================================================================= +;; == Prefetches +;; ========================================================================= + +;; ------------------------------------------------------------------------- +;; ---- Contiguous prefetches +;; ------------------------------------------------------------------------- +;; Includes contiguous forms of: +;; - PRFB +;; - PRFD +;; - PRFH +;; - PRFW +;; ------------------------------------------------------------------------- + +;; Contiguous predicated prefetches. Operand 2 gives the real prefetch +;; operation (as an svprfop), with operands 3 and 4 providing distilled +;; information. +(define_insn "@aarch64_sve_prefetch<mode>" + [(prefetch (unspec:DI + [(match_operand:<VPRED> 0 "register_operand" "Upl") + (match_operand:SVE_I 1 "aarch64_sve_prefetch_operand" "UP<Vesize>") + (match_operand:DI 2 "const_int_operand")] + UNSPEC_SVE_PREFETCH) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand"))] + "TARGET_SVE" + { + operands[1] = gen_rtx_MEM (<MODE>mode, operands[1]); + return aarch64_output_sve_prefetch ("prf<Vesize>", operands[2], "%0, %1"); + } +) + +;; ------------------------------------------------------------------------- +;; ---- Gather prefetches +;; ------------------------------------------------------------------------- +;; Includes gather forms of: +;; - PRFB +;; - PRFD +;; - PRFH +;; - PRFW +;; ------------------------------------------------------------------------- + +;; Predicated gather prefetches for 32-bit bases and offsets. The operands +;; are: +;; 0: the governing predicate +;; 1: the scalar component of the address +;; 2: the vector component of the address +;; 3: 1 for zero extension, 0 for sign extension +;; 4: the scale multiplier +;; 5: a vector zero that identifies the mode of data being accessed +;; 6: the prefetch operator (an svprfop) +;; 7: the normal RTL prefetch rw flag +;; 8: the normal RTL prefetch locality value +(define_insn "@aarch64_sve_gather_prefetch<SVE_I:mode><VNx4SI_ONLY:mode>" + [(prefetch (unspec:DI + [(match_operand:VNx4BI 0 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<SVE_I:Vesize>" "Z, vg<SVE_I:Vesize>, rk, rk, rk, rk") + (match_operand:VNx4SI_ONLY 2 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 3 "const_int_operand" "i, i, Z, Ui1, Z, Ui1") + (match_operand:DI 4 "aarch64_gather_scale_operand_<SVE_I:Vesize>" "Ui1, Ui1, Ui1, Ui1, i, i") + (match_operand:SVE_I 5 "aarch64_simd_imm_zero") + (match_operand:DI 6 "const_int_operand")] + UNSPEC_SVE_PREFETCH_GATHER) + (match_operand:DI 7 "const_int_operand") + (match_operand:DI 8 "const_int_operand"))] + "TARGET_SVE" + { + static const char *const insns[][2] = { + "prf<SVE_I:Vesize>", "%0, [%2.s]", + "prf<SVE_I:Vesize>", "%0, [%2.s, #%1]", + "prfb", "%0, [%1, %2.s, sxtw]", + "prfb", "%0, [%1, %2.s, uxtw]", + "prf<SVE_I:Vesize>", "%0, [%1, %2.s, sxtw %p4]", + "prf<SVE_I:Vesize>", "%0, [%1, %2.s, uxtw %p4]" + }; + const char *const *parts = insns[which_alternative]; + return aarch64_output_sve_prefetch (parts[0], operands[6], parts[1]); + } +) + +;; Predicated gather prefetches for 64-bit elements. The value of operand 3 +;; doesn't matter in this case. +(define_insn "@aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>" + [(prefetch (unspec:DI + [(match_operand:VNx2BI 0 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 1 "aarch64_sve_gather_offset_<SVE_I:Vesize>" "Z, vg<SVE_I:Vesize>, rk, rk") + (match_operand:VNx2DI_ONLY 2 "register_operand" "w, w, w, w") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<SVE_I:Vesize>" "Ui1, Ui1, Ui1, i") + (match_operand:SVE_I 5 "aarch64_simd_imm_zero") + (match_operand:DI 6 "const_int_operand")] + UNSPEC_SVE_PREFETCH_GATHER) + (match_operand:DI 7 "const_int_operand") + (match_operand:DI 8 "const_int_operand"))] + "TARGET_SVE" + { + static const char *const insns[][2] = { + "prf<SVE_I:Vesize>", "%0, [%2.d]", + "prf<SVE_I:Vesize>", "%0, [%2.d, #%1]", + "prfb", "%0, [%1, %2.d]", + "prf<SVE_I:Vesize>", "%0, [%1, %2.d, lsl %p4]" + }; + const char *const *parts = insns[which_alternative]; + return aarch64_output_sve_prefetch (parts[0], operands[6], parts[1]); + } +) + +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>_sxtw" + [(prefetch (unspec:DI + [(match_operand:VNx2BI 0 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (unspec:VNx2DI_ONLY + [(match_operand 9) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<SVE_I:Vesize>" "Ui1, i") + (match_operand:SVE_I 5 "aarch64_simd_imm_zero") + (match_operand:DI 6 "const_int_operand")] + UNSPEC_SVE_PREFETCH_GATHER) + (match_operand:DI 7 "const_int_operand") + (match_operand:DI 8 "const_int_operand"))] + "TARGET_SVE" + { + static const char *const insns[][2] = { + "prfb", "%0, [%1, %2.d, sxtw]", + "prf<SVE_I:Vesize>", "%0, [%1, %2.d, sxtw %p4]" + }; + const char *const *parts = insns[which_alternative]; + return aarch64_output_sve_prefetch (parts[0], operands[6], parts[1]); + } + "&& !rtx_equal_p (operands[0], operands[9])" + { + operands[9] = copy_rtx (operands[0]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*aarch64_sve_gather_prefetch<SVE_I:mode><VNx2DI_ONLY:mode>_uxtw" + [(prefetch (unspec:DI + [(match_operand:VNx2BI 0 "register_operand" "Upl, Upl") + (match_operand:DI 1 "register_operand" "rk, rk") + (and:VNx2DI_ONLY + (match_operand:VNx2DI 2 "register_operand" "w, w") + (match_operand:VNx2DI 9 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "aarch64_gather_scale_operand_<SVE_I:Vesize>" "Ui1, i") + (match_operand:SVE_I 5 "aarch64_simd_imm_zero") + (match_operand:DI 6 "const_int_operand")] + UNSPEC_SVE_PREFETCH_GATHER) + (match_operand:DI 7 "const_int_operand") + (match_operand:DI 8 "const_int_operand"))] + "TARGET_SVE" + { + static const char *const insns[][2] = { + "prfb", "%0, [%1, %2.d, uxtw]", + "prf<SVE_I:Vesize>", "%0, [%1, %2.d, uxtw %p4]" + }; + const char *const *parts = insns[which_alternative]; + return aarch64_output_sve_prefetch (parts[0], operands[6], parts[1]); + } +) + ;; ========================================================================= ;; == Stores ;; ========================================================================= @@ -945,6 +1978,74 @@ ) ;; ------------------------------------------------------------------------- +;; ---- Truncating contiguous stores +;; ------------------------------------------------------------------------- +;; Includes: +;; - ST1B +;; - ST1H +;; - ST1W +;; ------------------------------------------------------------------------- + +;; Predicated truncate and store, with 8 elements per 128-bit block. +(define_insn "@aarch64_store_trunc<VNx8_NARROW:mode><VNx8_WIDE:mode>" + [(set (match_operand:VNx8_NARROW 0 "memory_operand" "+m") + (unspec:VNx8_NARROW + [(match_operand:VNx8BI 2 "register_operand" "Upl") + (truncate:VNx8_NARROW + (match_operand:VNx8_WIDE 1 "register_operand" "w")) + (match_dup 0)] + UNSPEC_ST1_SVE))] + "TARGET_SVE" + "st1<VNx8_NARROW:Vesize>\t%1.<VNx8_WIDE:Vetype>, %2, %0" +) + +;; Predicated truncate and store, with 4 elements per 128-bit block. +(define_insn "@aarch64_store_trunc<VNx4_NARROW:mode><VNx4_WIDE:mode>" + [(set (match_operand:VNx4_NARROW 0 "memory_operand" "+m") + (unspec:VNx4_NARROW + [(match_operand:VNx4BI 2 "register_operand" "Upl") + (truncate:VNx4_NARROW + (match_operand:VNx4_WIDE 1 "register_operand" "w")) + (match_dup 0)] + UNSPEC_ST1_SVE))] + "TARGET_SVE" + "st1<VNx4_NARROW:Vesize>\t%1.<VNx4_WIDE:Vetype>, %2, %0" +) + +;; Predicated truncate and store, with 2 elements per 128-bit block. +(define_insn "@aarch64_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>" + [(set (match_operand:VNx2_NARROW 0 "memory_operand" "+m") + (unspec:VNx2_NARROW + [(match_operand:VNx2BI 2 "register_operand" "Upl") + (truncate:VNx2_NARROW + (match_operand:VNx2_WIDE 1 "register_operand" "w")) + (match_dup 0)] + UNSPEC_ST1_SVE))] + "TARGET_SVE" + "st1<VNx2_NARROW:Vesize>\t%1.<VNx2_WIDE:Vetype>, %2, %0" +) + +;; ------------------------------------------------------------------------- +;; ---- Non-temporal contiguous stores +;; ------------------------------------------------------------------------- +;; Includes: +;; - STNT1B +;; - STNT1D +;; - STNT1H +;; - STNT1W +;; ------------------------------------------------------------------------- + +(define_insn "@aarch64_stnt1<mode>" + [(set (match_operand:SVE_ALL 0 "memory_operand" "+m") + (unspec:SVE_ALL [(match_operand:<VPRED> 2 "register_operand" "Upl") + (match_operand:SVE_ALL 1 "register_operand" "w") + (match_dup 0)] + UNSPEC_STNT1_SVE))] + "TARGET_SVE" + "stnt1<Vesize>\t%1.<Vetype>, %2, %0" +) + +;; ------------------------------------------------------------------------- ;; ---- Normal scatter stores ;; ------------------------------------------------------------------------- ;; Includes scatter forms of: @@ -957,7 +2058,7 @@ [(set (mem:BLK (scratch)) (unspec:BLK [(match_dup 5) - (match_operand:DI 0 "aarch64_reg_or_zero") + (match_operand:DI 0 "aarch64_sve_gather_offset_<Vesize>") (match_operand:<V_INT_EQUIV> 1 "register_operand") (match_operand:DI 2 "const_int_operand") (match_operand:DI 3 "aarch64_gather_scale_operand_<Vesize>") @@ -974,16 +2075,17 @@ (define_insn "mask_scatter_store<mode>" [(set (mem:BLK (scratch)) (unspec:BLK - [(match_operand:<VPRED> 5 "register_operand" "Upl, Upl, Upl, Upl, Upl") - (match_operand:DI 0 "aarch64_reg_or_zero" "Z, rk, rk, rk, rk") - (match_operand:<V_INT_EQUIV> 1 "register_operand" "w, w, w, w, w") - (match_operand:DI 2 "const_int_operand" "i, Z, Ui1, Z, Ui1") - (match_operand:DI 3 "aarch64_gather_scale_operand_w" "Ui1, Ui1, Ui1, i, i") - (match_operand:SVE_S 4 "register_operand" "w, w, w, w, w")] + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 0 "aarch64_sve_gather_offset_w" "Z, vgw, rk, rk, rk, rk") + (match_operand:VNx4SI 1 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 2 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1") + (match_operand:DI 3 "aarch64_gather_scale_operand_w" "Ui1, Ui1, Ui1, Ui1, i, i") + (match_operand:SVE_S 4 "register_operand" "w, w, w, w, w, w")] UNSPEC_ST1_SCATTER))] "TARGET_SVE" "@ st1w\t%4.s, %5, [%1.s] + st1w\t%4.s, %5, [%1.s, #%0] st1w\t%4.s, %5, [%0, %1.s, sxtw] st1w\t%4.s, %5, [%0, %1.s, uxtw] st1w\t%4.s, %5, [%0, %1.s, sxtw %p3] @@ -995,20 +2097,166 @@ (define_insn "mask_scatter_store<mode>" [(set (mem:BLK (scratch)) (unspec:BLK - [(match_operand:<VPRED> 5 "register_operand" "Upl, Upl, Upl") - (match_operand:DI 0 "aarch64_reg_or_zero" "Z, rk, rk") - (match_operand:<V_INT_EQUIV> 1 "register_operand" "w, w, w") + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 0 "aarch64_sve_gather_offset_d" "Z, vgd, rk, rk") + (match_operand:VNx2DI 1 "register_operand" "w, w, w, w") (match_operand:DI 2 "const_int_operand") - (match_operand:DI 3 "aarch64_gather_scale_operand_d" "Ui1, Ui1, i") - (match_operand:SVE_D 4 "register_operand" "w, w, w")] + (match_operand:DI 3 "aarch64_gather_scale_operand_d" "Ui1, Ui1, Ui1, i") + (match_operand:SVE_D 4 "register_operand" "w, w, w, w")] UNSPEC_ST1_SCATTER))] "TARGET_SVE" "@ st1d\t%4.d, %5, [%1.d] + st1d\t%4.d, %5, [%1.d, #%0] st1d\t%4.d, %5, [%0, %1.d] st1d\t%4.d, %5, [%0, %1.d, lsl %p3]" ) +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*mask_scatter_store<mode>_sxtw" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 0 "register_operand" "rk, rk") + (unspec:VNx2DI + [(match_operand 6) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 1 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "aarch64_gather_scale_operand_d" "Ui1, i") + (match_operand:SVE_D 4 "register_operand" "w, w")] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1d\t%4.d, %5, [%0, %1.d, sxtw] + st1d\t%4.d, %5, [%0, %1.d, sxtw %p3]" + "&& !rtx_equal_p (operands[5], operands[6])" + { + operands[6] = copy_rtx (operands[5]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*mask_scatter_store<mode>_uxtw" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 0 "aarch64_reg_or_zero" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 1 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "aarch64_gather_scale_operand_d" "Ui1, i") + (match_operand:SVE_D 4 "register_operand" "w, w")] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1d\t%4.d, %5, [%0, %1.d, uxtw] + st1d\t%4.d, %5, [%0, %1.d, uxtw %p3]" +) + +;; ------------------------------------------------------------------------- +;; ---- Truncating scatter stores +;; ------------------------------------------------------------------------- +;; Includes scatter forms of: +;; - ST1B +;; - ST1H +;; - ST1W +;; ------------------------------------------------------------------------- + +;; Predicated truncating scatter stores for 32-bit elements. Operand 2 is +;; true for unsigned extension and false for signed extension. +(define_insn "@aarch64_scatter_store_trunc<VNx4_NARROW:mode><VNx4_WIDE:mode>" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:DI 0 "aarch64_sve_gather_offset_<VNx4_NARROW:Vesize>" "Z, vg<VNx4_NARROW:Vesize>, rk, rk, rk, rk") + (match_operand:VNx4SI 1 "register_operand" "w, w, w, w, w, w") + (match_operand:DI 2 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1") + (match_operand:DI 3 "aarch64_gather_scale_operand_<VNx4_NARROW:Vesize>" "Ui1, Ui1, Ui1, Ui1, i, i") + (truncate:VNx4_NARROW + (match_operand:VNx4_WIDE 4 "register_operand" "w, w, w, w, w, w"))] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%1.s] + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%1.s, #%0] + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%0, %1.s, sxtw] + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%0, %1.s, uxtw] + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%0, %1.s, sxtw %p3] + st1<VNx4_NARROW:Vesize>\t%4.s, %5, [%0, %1.s, uxtw %p3]" +) + +;; Predicated truncating scatter stores for 64-bit elements. The value of +;; operand 2 doesn't matter in this case. +(define_insn "@aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl") + (match_operand:DI 0 "aarch64_sve_gather_offset_<VNx2_NARROW:Vesize>" "Z, vg<VNx2_NARROW:Vesize>, rk, rk") + (match_operand:VNx2DI 1 "register_operand" "w, w, w, w") + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, Ui1, Ui1, i") + (truncate:VNx2_NARROW + (match_operand:VNx2_WIDE 4 "register_operand" "w, w, w, w"))] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%1.d] + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%1.d, #%0] + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d] + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d, lsl %p3]" +) + +;; Likewise, but with the offset being sign-extended from 32 bits. +(define_insn_and_rewrite "*aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>_sxtw" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 0 "register_operand" "rk, rk") + (unspec:VNx2DI + [(match_operand 6) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 1 "register_operand" "w, w")))] + UNSPEC_PRED_X) + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (truncate:VNx2_NARROW + (match_operand:VNx2_WIDE 4 "register_operand" "w, w"))] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d, sxtw] + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d, sxtw %p3]" + "&& !rtx_equal_p (operands[5], operands[6])" + { + operands[6] = copy_rtx (operands[5]); + } +) + +;; Likewise, but with the offset being zero-extended from 32 bits. +(define_insn "*aarch64_scatter_store_trunc<VNx2_NARROW:mode><VNx2_WIDE:mode>_uxtw" + [(set (mem:BLK (scratch)) + (unspec:BLK + [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl") + (match_operand:DI 0 "aarch64_reg_or_zero" "rk, rk") + (and:VNx2DI + (match_operand:VNx2DI 1 "register_operand" "w, w") + (match_operand:VNx2DI 6 "aarch64_sve_uxtw_immediate")) + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "aarch64_gather_scale_operand_<VNx2_NARROW:Vesize>" "Ui1, i") + (truncate:VNx2_NARROW + (match_operand:VNx2_WIDE 4 "register_operand" "w, w"))] + UNSPEC_ST1_SCATTER))] + "TARGET_SVE" + "@ + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d, uxtw] + st1<VNx2_NARROW:Vesize>\t%4.d, %5, [%0, %1.d, uxtw %p3]" +) + ;; ========================================================================= ;; == Vector creation ;; ========================================================================= @@ -1017,6 +2265,7 @@ ;; ---- [INT,FP] Duplicate element ;; ------------------------------------------------------------------------- ;; Includes: +;; - DUP ;; - MOV ;; - LD1RB ;; - LD1RD @@ -1215,7 +2464,7 @@ ;; duplicate the input and do a compare with zero. (define_expand "vec_duplicate<mode>" [(set (match_operand:PRED_ALL 0 "register_operand") - (vec_duplicate:PRED_ALL (match_operand 1 "register_operand")))] + (vec_duplicate:PRED_ALL (match_operand:QI 1 "register_operand")))] "TARGET_SVE" { rtx tmp = gen_reg_rtx (DImode); @@ -1378,21 +2627,22 @@ ;; ---- [INT,FP] Extract active element ;; ------------------------------------------------------------------------- ;; Includes: +;; - LASTA ;; - LASTB ;; ------------------------------------------------------------------------- ;; Extract the last active element of operand 1 into operand 0. ;; If no elements are active, extract the last inactive element instead. -(define_insn "extract_last_<mode>" - [(set (match_operand:<VEL> 0 "register_operand" "=r, w") +(define_insn "@extract_<last_op>_<mode>" + [(set (match_operand:<VEL> 0 "register_operand" "=?r, w") (unspec:<VEL> [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") (match_operand:SVE_ALL 2 "register_operand" "w, w")] - UNSPEC_LASTB))] + LAST))] "TARGET_SVE" "@ - lastb\t%<vwcore>0, %1, %2.<Vetype> - lastb\t%<Vetype>0, %1, %2.<Vetype>" + last<ab>\t%<vwcore>0, %1, %2.<Vetype> + last<ab>\t%<Vetype>0, %1, %2.<Vetype>" ) ;; ------------------------------------------------------------------------- @@ -1450,7 +2700,7 @@ ) ;; Integer unary arithmetic predicated with a PTRUE. -(define_insn "*<optab><mode>2" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl") @@ -1461,6 +2711,18 @@ "<sve_int_op>\t%0.<Vetype>, %1/m, %2.<Vetype>" ) +;; Predicated integer unary arithmetic with merging. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (SVE_INT_UNARY:SVE_I + (match_operand:SVE_I 2 "register_operand")) + (match_operand:SVE_I 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + ;; Predicated integer unary arithmetic, merging with the first input. (define_insn "*cond_<optab><mode>_2" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") @@ -1504,6 +2766,7 @@ ;; ---- [INT] General unary arithmetic corresponding to unspecs ;; ------------------------------------------------------------------------- ;; Includes +;; - RBIT ;; - REVB ;; - REVH ;; - REVW @@ -1522,6 +2785,64 @@ "<sve_int_op>\t%0.<Vetype>, %1/m, %2.<Vetype>" ) +;; Predicated integer unary operations with merging. +(define_insn "@cond_<optab><mode>" + [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w, ?&w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "w, w, w")] + SVE_INT_UNARY) + (match_operand:SVE_I 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE && <elem_bits> >= <min_elem_bits>" + "@ + <sve_int_op>\t%0.<Vetype>, %1/m, %2.<Vetype> + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %2.<Vetype> + movprfx\t%0, %3\;<sve_int_op>\t%0.<Vetype>, %1/m, %2.<Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Sign extension +;; ------------------------------------------------------------------------- +;; Includes: +;; - SXTB +;; - SXTH +;; - SXTW +;; ------------------------------------------------------------------------- + +;; Predicated SXT[BHW]. +(define_insn "@aarch64_pred_sxt<SVE_HSDI:mode><SVE_PARTIAL:mode>" + [(set (match_operand:SVE_HSDI 0 "register_operand" "=w") + (unspec:SVE_HSDI + [(match_operand:<VPRED> 1 "register_operand" "Upl") + (sign_extend:SVE_HSDI + (truncate:SVE_PARTIAL + (match_operand:SVE_HSDI 2 "register_operand" "w")))] + UNSPEC_PRED_X))] + "TARGET_SVE && (~<narrower_mask> & <self_mask>) == 0" + "sxt<SVE_PARTIAL:Vesize>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_HSDI:Vetype>" +) + +;; Predicated SXT[BHW] with merging. +(define_insn "@aarch64_cond_sxt<SVE_HSDI:mode><SVE_PARTIAL:mode>" + [(set (match_operand:SVE_HSDI 0 "register_operand" "=w, ?&w, ?&w") + (unspec:SVE_HSDI + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") + (sign_extend:SVE_HSDI + (truncate:SVE_PARTIAL + (match_operand:SVE_HSDI 2 "register_operand" "w, w, w"))) + (match_operand:SVE_HSDI 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE && (~<narrower_mask> & <self_mask>) == 0" + "@ + sxt<SVE_PARTIAL:Vesize>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_HSDI:Vetype> + movprfx\t%0.<SVE_HSDI:Vetype>, %1/z, %2.<SVE_HSDI:Vetype>\;sxt<SVE_PARTIAL:Vesize>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_HSDI:Vetype> + movprfx\t%0, %3\;sxt<SVE_PARTIAL:Vesize>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_HSDI:Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [INT] Zero extension ;; ------------------------------------------------------------------------- @@ -1577,8 +2898,31 @@ ;; ------------------------------------------------------------------------- ;; ---- [INT] Logical inverse ;; ------------------------------------------------------------------------- +;; Includes: +;; - CNOT +;; ------------------------------------------------------------------------- ;; Predicated logical inverse. +(define_expand "@aarch64_pred_cnot<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (eq:<VPRED> + (match_operand:SVE_I 3 "register_operand") + (match_dup 4))] + UNSPEC_PRED_Z) + (match_dup 5) + (match_dup 4)] + UNSPEC_SEL))] + "TARGET_SVE" + { + operands[4] = CONST0_RTX (<MODE>mode); + operands[5] = CONST1_RTX (<MODE>mode); + } +) + (define_insn "*cnot<mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w") (unspec:SVE_I @@ -1596,6 +2940,32 @@ "cnot\t%0.<Vetype>, %1/m, %2.<Vetype>" ) +;; Predicated logical inverse with merging. +(define_expand "@cond_cnot<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_I + [(unspec:<VPRED> + [(match_dup 4) + (const_int SVE_KNOWN_PTRUE) + (eq:<VPRED> + (match_operand:SVE_I 2 "register_operand") + (match_dup 5))] + UNSPEC_PRED_Z) + (match_dup 6) + (match_dup 5)] + UNSPEC_SEL) + (match_operand:SVE_I 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" + { + operands[4] = CONSTM1_RTX (<VPRED>mode); + operands[5] = CONST0_RTX (<MODE>mode); + operands[6] = CONST1_RTX (<MODE>mode); + } +) + ;; Predicated logical inverse, merging with the first input. (define_insn_and_rewrite "*cond_cnot<mode>_2" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") @@ -1664,11 +3034,29 @@ ) ;; ------------------------------------------------------------------------- +;; ---- [FP<-INT] General unary arithmetic that maps to unspecs +;; ------------------------------------------------------------------------- +;; Includes: +;; - FEXPA +;; ------------------------------------------------------------------------- + +;; Unpredicated unary operations that take an integer and return a float. +(define_insn "@aarch64_sve_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w") + (unspec:SVE_F [(match_operand:<V_INT_EQUIV> 1 "register_operand" "w")] + SVE_FP_UNARY_INT))] + "TARGET_SVE" + "<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>" +) + +;; ------------------------------------------------------------------------- ;; ---- [FP] General unary arithmetic corresponding to unspecs ;; ------------------------------------------------------------------------- ;; Includes: ;; - FABS ;; - FNEG +;; - FRECPE +;; - FRECPX ;; - FRINTA ;; - FRINTI ;; - FRINTM @@ -1676,10 +3064,20 @@ ;; - FRINTP ;; - FRINTX ;; - FRINTZ +;; - FRSQRT ;; - FSQRT ;; ------------------------------------------------------------------------- ;; Unpredicated floating-point unary operations. +(define_insn "@aarch64_sve_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w") + (unspec:SVE_F [(match_operand:SVE_F 1 "register_operand" "w")] + SVE_FP_UNARY))] + "TARGET_SVE" + "<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>" +) + +;; Unpredicated floating-point unary operations. (define_expand "<optab><mode>2" [(set (match_operand:SVE_F 0 "register_operand") (unspec:SVE_F @@ -1694,7 +3092,7 @@ ) ;; Predicated floating-point unary operations. -(define_insn "*<optab><mode>2" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand" "Upl") @@ -1705,6 +3103,21 @@ "<sve_fp_op>\t%0.<Vetype>, %1/m, %2.<Vetype>" ) +;; Predicated floating-point unary arithmetic with merging. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand")] + SVE_COND_FP_UNARY) + (match_operand:SVE_F 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + ;; Predicated floating-point unary arithmetic, merging with the first input. (define_insn_and_rewrite "*cond_<optab><mode>_2" [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") @@ -1833,7 +3246,7 @@ ;; and third alternatives, but using Upa or X isn't likely to gain much ;; and would make the instruction seem less uniform to the register ;; allocator. -(define_insn_and_split "*<optab><mode>3" +(define_insn_and_split "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, w, ?&w, ?&w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") @@ -2012,8 +3425,53 @@ ;; - ADR ;; ------------------------------------------------------------------------- -;; Unshifted ADR, with the offset being zero-extended from the low 32 bits. -(define_insn "*aarch64_adr_uxtw" +;; An unshifted and unscaled ADR. This is functionally equivalent to an ADD, +;; but the svadrb intrinsics should preserve the user's choice. +(define_insn "@aarch64_adr<mode>" + [(set (match_operand:SVE_SDI 0 "register_operand" "=w") + (unspec:SVE_SDI + [(match_operand:SVE_SDI 1 "register_operand" "w") + (match_operand:SVE_SDI 2 "register_operand" "w")] + UNSPEC_ADR))] + "TARGET_SVE" + "adr\t%0.<Vetype>, [%1.<Vetype>, %2.<Vetype>]" +) + +;; Same, but with the offset being sign-extended from the low 32 bits. +(define_insn_and_rewrite "*aarch64_adr_sxtw" + [(set (match_operand:VNx2DI 0 "register_operand" "=w") + (unspec:VNx2DI + [(match_operand:VNx2DI 1 "register_operand" "w") + (unspec:VNx2DI + [(match_operand 3) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w")))] + UNSPEC_PRED_X)] + UNSPEC_ADR))] + "TARGET_SVE" + "adr\t%0.d, [%1.d, %2.d, sxtw]" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (VNx2BImode); + } +) + +;; Same, but with the offset being zero-extended from the low 32 bits. +(define_insn "*aarch64_adr_uxtw_unspec" + [(set (match_operand:VNx2DI 0 "register_operand" "=w") + (unspec:VNx2DI + [(match_operand:VNx2DI 1 "register_operand" "w") + (and:VNx2DI + (match_operand:VNx2DI 2 "register_operand" "w") + (match_operand:VNx2DI 3 "aarch64_sve_uxtw_immediate"))] + UNSPEC_ADR))] + "TARGET_SVE" + "adr\t%0.d, [%1.d, %2.d, uxtw]" +) + +;; Same, matching as a PLUS rather than unspec. +(define_insn "*aarch64_adr_uxtw_and" [(set (match_operand:VNx2DI 0 "register_operand" "=w") (plus:VNx2DI (and:VNx2DI @@ -2025,6 +3483,22 @@ ) ;; ADR with a nonzero shift. +(define_expand "@aarch64_adr<mode>_shift" + [(set (match_operand:SVE_SDI 0 "register_operand") + (plus:SVE_SDI + (unspec:SVE_SDI + [(match_dup 4) + (ashift:SVE_SDI + (match_operand:SVE_SDI 2 "register_operand") + (match_operand:SVE_SDI 3 "const_1_to_3_operand"))] + UNSPEC_PRED_X) + (match_operand:SVE_SDI 1 "register_operand")))] + "TARGET_SVE" + { + operands[4] = CONSTM1_RTX (<VPRED>mode); + } +) + (define_insn_and_rewrite "*aarch64_adr<mode>_shift" [(set (match_operand:SVE_SDI 0 "register_operand" "=w") (plus:SVE_SDI @@ -2043,6 +3517,30 @@ } ) +;; Same, but with the index being sign-extended from the low 32 bits. +(define_insn_and_rewrite "*aarch64_adr_shift_sxtw" + [(set (match_operand:VNx2DI 0 "register_operand" "=w") + (plus:VNx2DI + (unspec:VNx2DI + [(match_operand 4) + (ashift:VNx2DI + (unspec:VNx2DI + [(match_operand 5) + (sign_extend:VNx2DI + (truncate:VNx2SI + (match_operand:VNx2DI 2 "register_operand" "w")))] + UNSPEC_PRED_X) + (match_operand:VNx2DI 3 "const_1_to_3_operand"))] + UNSPEC_PRED_X) + (match_operand:VNx2DI 1 "register_operand" "w")))] + "TARGET_SVE" + "adr\t%0.d, [%1.d, %2.d, sxtw %3]" + "&& (!CONSTANT_P (operands[4]) || !CONSTANT_P (operands[5]))" + { + operands[5] = operands[4] = CONSTM1_RTX (VNx2BImode); + } +) + ;; Same, but with the index being zero-extended from the low 32 bits. (define_insn_and_rewrite "*aarch64_adr_shift_uxtw" [(set (match_operand:VNx2DI 0 "register_operand" "=w") @@ -2080,14 +3578,14 @@ "TARGET_SVE" { rtx pred = aarch64_ptrue_reg (<VPRED>mode); - emit_insn (gen_aarch64_<su>abd<mode>_3 (operands[0], pred, operands[1], - operands[2])); + emit_insn (gen_aarch64_pred_<su>abd<mode> (operands[0], pred, operands[1], + operands[2])); DONE; } ) ;; Predicated integer absolute difference. -(define_insn "aarch64_<su>abd<mode>_3" +(define_insn "@aarch64_pred_<su>abd<mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") @@ -2106,6 +3604,31 @@ [(set_attr "movprfx" "*,yes")] ) +(define_expand "@aarch64_cond_<su>abd<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (minus:SVE_I + (unspec:SVE_I + [(match_dup 1) + (USMAX:SVE_I + (match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "register_operand"))] + UNSPEC_PRED_X) + (unspec:SVE_I + [(match_dup 1) + (<max_opp>:SVE_I + (match_dup 2) + (match_dup 3))] + UNSPEC_PRED_X)) + (match_operand:SVE_I 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +{ + if (rtx_equal_p (operands[3], operands[4])) + std::swap (operands[2], operands[3]); +}) + ;; Predicated integer absolute difference, merging with the first input. (define_insn_and_rewrite "*aarch64_cond_<su>abd<mode>_2" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") @@ -2185,6 +3708,45 @@ ) ;; ------------------------------------------------------------------------- +;; ---- [INT] Saturating addition and subtraction +;; ------------------------------------------------------------------------- +;; - SQADD +;; - SQSUB +;; - UQADD +;; - UQSUB +;; ------------------------------------------------------------------------- + +;; Unpredicated saturating signed addition and subtraction. +(define_insn "@aarch64_<su_optab><optab><mode>" + [(set (match_operand:SVE_I 0 "register_operand" "=w, w, ?&w, ?&w, w") + (SBINQOPS:SVE_I + (match_operand:SVE_I 1 "register_operand" "0, 0, w, w, w") + (match_operand:SVE_I 2 "aarch64_sve_sqadd_operand" "vsQ, vsS, vsQ, vsS, w")))] + "TARGET_SVE" + "@ + <binqops_op>\t%0.<Vetype>, %0.<Vetype>, #%D2 + <binqops_op_rev>\t%0.<Vetype>, %0.<Vetype>, #%N2 + movprfx\t%0, %1\;<binqops_op>\t%0.<Vetype>, %0.<Vetype>, #%D2 + movprfx\t%0, %1\;<binqops_op_rev>\t%0.<Vetype>, %0.<Vetype>, #%N2 + <binqops_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>" + [(set_attr "movprfx" "*,*,yes,yes,*")] +) + +;; Unpredicated saturating unsigned addition and subtraction. +(define_insn "@aarch64_<su_optab><optab><mode>" + [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w, w") + (UBINQOPS:SVE_I + (match_operand:SVE_I 1 "register_operand" "0, w, w") + (match_operand:SVE_I 2 "aarch64_sve_arith_operand" "vsa, vsa, w")))] + "TARGET_SVE" + "@ + <binqops_op>\t%0.<Vetype>, %0.<Vetype>, #%D2 + movprfx\t%0, %1\;<binqops_op>\t%0.<Vetype>, %0.<Vetype>, #%D2 + <binqops_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>" + [(set_attr "movprfx" "*,yes,*")] +) + +;; ------------------------------------------------------------------------- ;; ---- [INT] Highpart multiplication ;; ------------------------------------------------------------------------- ;; Includes: @@ -2208,7 +3770,7 @@ ) ;; Predicated highpart multiplication. -(define_insn "*<su>mul<mode>3_highpart" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") @@ -2223,6 +3785,59 @@ [(set_attr "movprfx" "*,yes")] ) +;; Predicated highpart multiplications with merging. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "register_operand")] + MUL_HIGHPART) + (match_operand:SVE_I 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +{ + /* Only target code is aware of these operations, so we don't need + to handle the fully-general case. */ + gcc_assert (rtx_equal_p (operands[2], operands[4]) + || CONSTANT_P (operands[4])); +}) + +;; Predicated highpart multiplications, merging with the first input. +(define_insn "*cond_<optab><mode>_2" + [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "0, w") + (match_operand:SVE_I 3 "register_operand" "w, w")] + MUL_HIGHPART) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + <sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %2\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" + [(set_attr "movprfx" "*,yes")]) + +;; Predicated highpart multiplications, merging with zero. +(define_insn "*cond_<optab><mode>_z" + [(set (match_operand:SVE_I 0 "register_operand" "=&w, &w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "%0, w") + (match_operand:SVE_I 3 "register_operand" "w, w")] + MUL_HIGHPART) + (match_operand:SVE_I 4 "aarch64_simd_imm_zero")] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + movprfx\t%0.<Vetype>, %1/z, %0.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" + [(set_attr "movprfx" "yes")]) + ;; ------------------------------------------------------------------------- ;; ---- [INT] Division ;; ------------------------------------------------------------------------- @@ -2249,7 +3864,7 @@ ) ;; Integer division predicated with a PTRUE. -(define_insn "*<optab><mode>3" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_SDI 0 "register_operand" "=w, w, ?&w") (unspec:SVE_SDI [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") @@ -2266,7 +3881,7 @@ ) ;; Predicated integer division with merging. -(define_expand "cond_<optab><mode>" +(define_expand "@cond_<optab><mode>" [(set (match_operand:SVE_SDI 0 "register_operand") (unspec:SVE_SDI [(match_operand:<VPRED> 1 "register_operand") @@ -2374,6 +3989,22 @@ ;; - BIC ;; ------------------------------------------------------------------------- +;; Unpredicated BIC. +(define_expand "@aarch64_bic<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (and:SVE_I + (unspec:SVE_I + [(match_dup 3) + (not:SVE_I (match_operand:SVE_I 2 "register_operand"))] + UNSPEC_PRED_X) + (match_operand:SVE_I 1 "register_operand")))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +;; Predicated BIC. (define_insn_and_rewrite "*bic<mode>3" [(set (match_operand:SVE_I 0 "register_operand" "=w") (and:SVE_I @@ -2390,6 +4021,19 @@ } ) +;; Predicated BIC with merging. +(define_expand "@cond_bic<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (and:SVE_I + (not:SVE_I (match_operand:SVE_I 3 "register_operand")) + (match_operand:SVE_I 2 "register_operand")) + (match_operand:SVE_I 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + ;; Predicated integer BIC, merging with the first input. (define_insn "*cond_bic<mode>_2" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") @@ -2435,12 +4079,15 @@ ) ;; ------------------------------------------------------------------------- -;; ---- [INT] Shifts +;; ---- [INT] Shifts (rounding towards -Inf) ;; ------------------------------------------------------------------------- ;; Includes: ;; - ASR +;; - ASRR ;; - LSL +;; - LSLR ;; - LSR +;; - LSRR ;; ------------------------------------------------------------------------- ;; Unpredicated shift by a scalar, which expands into one of the vector @@ -2489,7 +4136,7 @@ ;; the predicate for the first alternative, but using Upa or X isn't ;; likely to gain much and would make the instruction seem less uniform ;; to the register allocator. -(define_insn_and_split "*v<optab><mode>3" +(define_insn_and_split "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, w, w, ?&w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") @@ -2565,6 +4212,66 @@ [(set_attr "movprfx" "yes")] ) +;; Unpredicated shifts of narrow elements by 64-bit amounts. +(define_insn "@aarch64_sve_<sve_int_op><mode>" + [(set (match_operand:SVE_BHSI 0 "register_operand" "=w") + (unspec:SVE_BHSI + [(match_operand:SVE_BHSI 1 "register_operand" "w") + (match_operand:VNx2DI 2 "register_operand" "w")] + SVE_SHIFT_WIDE))] + "TARGET_SVE" + "<sve_int_op>\t%0.<Vetype>, %1.<Vetype>, %2.d" +) + +;; Merging predicated shifts of narrow elements by 64-bit amounts. +(define_expand "@cond_<sve_int_op><mode>" + [(set (match_operand:SVE_BHSI 0 "register_operand") + (unspec:SVE_BHSI + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_BHSI + [(match_operand:SVE_BHSI 2 "register_operand") + (match_operand:VNx2DI 3 "register_operand")] + SVE_SHIFT_WIDE) + (match_operand:SVE_BHSI 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +;; Predicated shifts of narrow elements by 64-bit amounts, merging with +;; the first input. +(define_insn "*cond_<sve_int_op><mode>_m" + [(set (match_operand:SVE_BHSI 0 "register_operand" "=w, ?&w") + (unspec:SVE_BHSI + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_BHSI + [(match_operand:SVE_BHSI 2 "register_operand" "0, w") + (match_operand:VNx2DI 3 "register_operand" "w, w")] + SVE_SHIFT_WIDE) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + <sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d + movprfx\t%0, %2\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d" + [(set_attr "movprfx" "*, yes")]) + +;; Predicated shifts of narrow elements by 64-bit amounts, merging with zero. +(define_insn "*cond_<sve_int_op><mode>_z" + [(set (match_operand:SVE_BHSI 0 "register_operand" "=&w, &w") + (unspec:SVE_BHSI + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_BHSI + [(match_operand:SVE_BHSI 2 "register_operand" "0, w") + (match_operand:VNx2DI 3 "register_operand" "w, w")] + SVE_SHIFT_WIDE) + (match_operand:SVE_BHSI 4 "aarch64_simd_imm_zero")] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + movprfx\t%0.<Vetype>, %1/z, %0.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d" + [(set_attr "movprfx" "yes")]) + ;; ------------------------------------------------------------------------- ;; ---- [INT] Shifts (rounding towards 0) ;; ------------------------------------------------------------------------- @@ -2572,7 +4279,7 @@ ;; - ASRD ;; ------------------------------------------------------------------------- -;; Unpredicated arithmetic right shift for division by power-of-2. +;; Unpredicated ASRD. (define_expand "sdiv_pow2<mode>3" [(set (match_operand:SVE_I 0 "register_operand") (unspec:SVE_I @@ -2580,31 +4287,181 @@ (unspec:SVE_I [(match_operand:SVE_I 1 "register_operand") (match_operand 2 "aarch64_simd_rshift_imm")] - UNSPEC_ASRD)] - UNSPEC_PRED_X))] + UNSPEC_ASRD) + (match_dup 1)] + UNSPEC_SEL))] "TARGET_SVE" { operands[3] = aarch64_ptrue_reg (<VPRED>mode); } ) -;; Predicated ASRD with PTRUE. -(define_insn "*sdiv_pow2<mode>3" +;; Predicated ASRD with merging. +(define_expand "@cond_asrd<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_operand:SVE_I 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +;; Predicated ASRD, merging with the first input. +(define_insn "*cond_asrd<mode>_2" [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") (unspec:SVE_I [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") (unspec:SVE_I [(match_operand:SVE_I 2 "register_operand" "0, w") - (match_operand 3 "aarch64_simd_rshift_imm")] - UNSPEC_ASRD)] - UNSPEC_PRED_X))] + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 + movprfx\t%0, %2\;asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + [(set_attr "movprfx" "*,yes")]) + +;; Predicated ASRD, merging with zero. +(define_insn "*cond_asrd<mode>_z" + [(set (match_operand:SVE_I 0 "register_operand" "=w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "w") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_operand:SVE_I 4 "aarch64_simd_imm_zero")] + UNSPEC_SEL))] + "TARGET_SVE" + "movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + [(set_attr "movprfx" "yes")]) + +;; ------------------------------------------------------------------------- +;; ---- [FP<-INT] General binary arithmetic corresponding to unspecs +;; ------------------------------------------------------------------------- +;; Includes: +;; - FSCALE +;; - FTSMUL +;; - FTSSEL +;; ------------------------------------------------------------------------- + +;; Unpredicated floating-point binary operations that take an integer as +;; their second operand. +(define_insn "@aarch64_sve_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w") + (unspec:SVE_F [(match_operand:SVE_F 1 "register_operand" "w") + (match_operand:<V_INT_EQUIV> 2 "register_operand" "w")] + SVE_FP_BINARY_INT))] + "TARGET_SVE" + "<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>" +) + +;; Predicated floating-point binary operations that take an integer +;; as their second operand. +(define_insn "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "0, w") + (match_operand:<V_INT_EQUIV> 3 "register_operand" "w, w")] + SVE_COND_FP_BINARY_INT))] + "TARGET_SVE" + "@ + <sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %2\;<sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" + [(set_attr "movprfx" "*,yes")] +) + +;; Predicated floating-point binary operations with merging, taking an +;; integer as their second operand. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand") + (match_operand:<V_INT_EQUIV> 3 "register_operand")] + SVE_COND_FP_BINARY_INT) + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] "TARGET_SVE" +) + +;; Predicated floating-point binary operations that take an integer as their +;; second operand, with inactive lanes coming from the first operand. +(define_insn_and_rewrite "*cond_<optab><mode>_2" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_F + [(match_operand 4) + (match_operand:SI 5 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "0, w") + (match_operand:<V_INT_EQUIV> 3 "register_operand" "w, w")] + SVE_COND_FP_BINARY_INT) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE && aarch64_sve_pred_dominates_p (&operands[4], operands[1])" "@ - asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 - movprfx\t%0, %2\;asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + <sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %2\;<sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" + "&& !rtx_equal_p (operands[1], operands[4])" + { + operands[4] = copy_rtx (operands[1]); + } [(set_attr "movprfx" "*,yes")] ) +;; Predicated floating-point binary operations that take an integer as +;; their second operand, with the values of inactive lanes being distinct +;; from the other inputs. +(define_insn_and_rewrite "*cond_<optab><mode>_any" + [(set (match_operand:SVE_F 0 "register_operand" "=&w, &w, &w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") + (unspec:SVE_F + [(match_operand 5) + (match_operand:SI 6 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "0, w, w, w") + (match_operand:<V_INT_EQUIV> 3 "register_operand" "w, w, w, w")] + SVE_COND_FP_BINARY_INT) + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero" "Dz, Dz, 0, w")] + UNSPEC_SEL))] + "TARGET_SVE + && !rtx_equal_p (operands[2], operands[4]) + && aarch64_sve_pred_dominates_p (&operands[5], operands[1])" + "@ + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0.<Vetype>, %1/m, %2.<Vetype>\;<sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + #" + "&& 1" + { + if (reload_completed + && register_operand (operands[4], <MODE>mode) + && !rtx_equal_p (operands[0], operands[4])) + { + emit_insn (gen_vcond_mask_<mode><vpred> (operands[0], operands[2], + operands[4], operands[1])); + operands[4] = operands[2] = operands[0]; + } + else if (!rtx_equal_p (operands[1], operands[5])) + operands[5] = copy_rtx (operands[1]); + else + FAIL; + } + [(set_attr "movprfx" "yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [FP] General binary arithmetic corresponding to rtx codes ;; ------------------------------------------------------------------------- @@ -2632,14 +4489,30 @@ ;; - FADD (constant forms handled in the "Addition" section) ;; - FDIV ;; - FDIVR +;; - FMAX ;; - FMAXNM (including #0.0 and #1.0) +;; - FMIN ;; - FMINNM (including #0.0 and #1.0) ;; - FMUL (including #0.5 and #2.0) +;; - FMULX +;; - FRECPS +;; - FRSQRTS ;; - FSUB (constant forms handled in the "Addition" section) ;; - FSUBR (constant forms handled in the "Subtraction" section) ;; ------------------------------------------------------------------------- ;; Unpredicated floating-point binary operations. +(define_insn "@aarch64_sve_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w") + (unspec:SVE_F [(match_operand:SVE_F 1 "register_operand" "w") + (match_operand:SVE_F 2 "register_operand" "w")] + SVE_FP_BINARY))] + "TARGET_SVE" + "<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>" +) + +;; Unpredicated floating-point binary operations that need to be predicated +;; for SVE. (define_expand "<optab><mode>3" [(set (match_operand:SVE_F 0 "register_operand") (unspec:SVE_F @@ -2655,7 +4528,7 @@ ) ;; Predicated floating-point binary operations that have no immediate forms. -(define_insn "*<optab><mode>3" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w, w, ?&w") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") @@ -2672,7 +4545,7 @@ ) ;; Predicated floating-point operations with merging. -(define_expand "cond_<optab><mode>" +(define_expand "@cond_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand") @@ -2847,28 +4720,31 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point addition. -(define_insn_and_split "*add<mode>3" - [(set (match_operand:SVE_F 0 "register_operand" "=w, w, w, ?&w, ?&w") +(define_insn_and_split "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, w, w, w, ?&w, ?&w, ?&w") (unspec:SVE_F - [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl, Upl") - (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, i, Z, i, i") - (match_operand:SVE_F 2 "register_operand" "%0, 0, w, w, w") - (match_operand:SVE_F 3 "aarch64_sve_float_arith_with_sub_operand" "vsA, vsN, w, vsA, vsN")] - UNSPEC_COND_FADD))] + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, i, Z, Ui1, i, i, Ui1") + (match_operand:SVE_F 2 "register_operand" "%0, 0, w, 0, w, w, w") + (match_operand:SVE_F 3 "aarch64_sve_float_arith_with_sub_operand" "vsA, vsN, w, w, vsA, vsN, w")] + SVE_COND_FP_ADD))] "TARGET_SVE" "@ fadd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 fsub\t%0.<Vetype>, %1/m, %0.<Vetype>, #%N3 # + fadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> movprfx\t%0, %2\;fadd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 - movprfx\t%0, %2\;fsub\t%0.<Vetype>, %1/m, %0.<Vetype>, #%N3" + movprfx\t%0, %2\;fsub\t%0.<Vetype>, %1/m, %0.<Vetype>, #%N3 + movprfx\t%0, %2\;fadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" ; Split the unpredicated form after reload, so that we don't have ; the unnecessary PTRUE. "&& reload_completed - && register_operand (operands[3], <MODE>mode)" + && register_operand (operands[3], <MODE>mode) + && INTVAL (operands[4]) == SVE_RELAXED_GP" [(set (match_dup 0) (plus:SVE_F (match_dup 2) (match_dup 3)))] "" - [(set_attr "movprfx" "*,*,*,yes,yes")] + [(set_attr "movprfx" "*,*,*,*,yes,yes,yes")] ) ;; Predicated floating-point addition of a constant, merging with the @@ -2943,6 +4819,108 @@ ;; Register merging forms are handled through SVE_COND_FP_BINARY. ;; ------------------------------------------------------------------------- +;; ---- [FP] Complex addition +;; ------------------------------------------------------------------------- +;; Includes: +;; - FCADD +;; ------------------------------------------------------------------------- + +;; Predicated FCADD. +(define_insn "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "0, w") + (match_operand:SVE_F 3 "register_operand" "w, w")] + SVE_COND_FCADD))] + "TARGET_SVE" + "@ + fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0, %2\;fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot>" + [(set_attr "movprfx" "*,yes")] +) + +;; Predicated FCADD with merging. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand") + (match_operand:SVE_F 3 "register_operand")] + SVE_COND_FCADD) + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +;; Predicated FCADD, merging with the first input. +(define_insn_and_rewrite "*cond_<optab><mode>_2" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_F + [(match_operand 4) + (match_operand:SI 5 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "0, w") + (match_operand:SVE_F 3 "register_operand" "w, w")] + SVE_COND_FCADD) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE && aarch64_sve_pred_dominates_p (&operands[4], operands[1])" + "@ + fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0, %2\;fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot>" + "&& !rtx_equal_p (operands[1], operands[4])" + { + operands[4] = copy_rtx (operands[1]); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Predicated FCADD, merging with an independent value. +(define_insn_and_rewrite "*cond_<optab><mode>_any" + [(set (match_operand:SVE_F 0 "register_operand" "=&w, &w, &w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") + (unspec:SVE_F + [(match_operand 5) + (match_operand:SI 6 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "w, 0, w, w") + (match_operand:SVE_F 3 "register_operand" "w, w, w, w")] + SVE_COND_FCADD) + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero" "Dz, Dz, 0, w")] + UNSPEC_SEL))] + "TARGET_SVE + && !rtx_equal_p (operands[2], operands[4]) + && aarch64_sve_pred_dominates_p (&operands[5], operands[1])" + "@ + movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0.<Vetype>, %1/z, %0.<Vetype>\;fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0.<Vetype>, %1/m, %2.<Vetype>\;fcadd\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>, #<rot> + #" + "&& 1" + { + if (reload_completed + && register_operand (operands[4], <MODE>mode) + && !rtx_equal_p (operands[0], operands[4])) + { + emit_insn (gen_vcond_mask_<mode><vpred> (operands[0], operands[2], + operands[4], operands[1])); + operands[4] = operands[2] = operands[0]; + } + else if (!rtx_equal_p (operands[1], operands[5])) + operands[5] = copy_rtx (operands[1]); + else + FAIL; + } + [(set_attr "movprfx" "yes")] +) + +;; ------------------------------------------------------------------------- ;; ---- [FP] Subtraction ;; ------------------------------------------------------------------------- ;; Includes: @@ -2951,26 +4929,30 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point subtraction. -(define_insn_and_split "*sub<mode>3" - [(set (match_operand:SVE_F 0 "register_operand" "=w, w, ?&w") +(define_insn_and_split "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, w, w, w, ?&w, ?&w") (unspec:SVE_F - [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") - (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, Z, i") - (match_operand:SVE_F 2 "aarch64_sve_float_arith_operand" "vsA, w, vsA") - (match_operand:SVE_F 3 "register_operand" "0, w, 0")] - UNSPEC_COND_FSUB))] + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl, Upl, Upl") + (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, Z, Ui1, Ui1, i, Ui1") + (match_operand:SVE_F 2 "aarch64_sve_float_arith_operand" "vsA, w, 0, w, vsA, w") + (match_operand:SVE_F 3 "register_operand" "0, w, w, 0, w, w")] + SVE_COND_FP_SUB))] "TARGET_SVE" "@ fsubr\t%0.<Vetype>, %1/m, %0.<Vetype>, #%2 # - movprfx\t%0, %3\;fsubr\t%0.<Vetype>, %1/m, %0.<Vetype>, #%2" + fsub\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + fsubr\t%0.<Vetype>, %1/m, %0.<Vetype>, %2.<Vetype> + movprfx\t%0, %3\;fsubr\t%0.<Vetype>, %1/m, %0.<Vetype>, #%2 + movprfx\t%0, %2\;fsub\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" ; Split the unpredicated form after reload, so that we don't have ; the unnecessary PTRUE. "&& reload_completed - && register_operand (operands[2], <MODE>mode)" + && register_operand (operands[2], <MODE>mode) + && INTVAL (operands[4]) == SVE_RELAXED_GP" [(set (match_dup 0) (minus:SVE_F (match_dup 2) (match_dup 3)))] "" - [(set_attr "movprfx" "*,*,yes")] + [(set_attr "movprfx" "*,*,*,*,yes,yes")] ) ;; Predicated floating-point subtraction from a constant, merging with the @@ -3047,7 +5029,23 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point absolute difference. -(define_insn_and_rewrite "*fabd<mode>3" +(define_expand "@aarch64_pred_abd<mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (unspec:SVE_F + [(match_dup 1) + (match_dup 4) + (match_operand:SVE_F 2 "register_operand") + (match_operand:SVE_F 3 "register_operand")] + UNSPEC_COND_FSUB)] + UNSPEC_COND_FABS))] + "TARGET_SVE" +) + +;; Predicated floating-point absolute difference. +(define_insn_and_rewrite "*aarch64_pred_abd<mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") @@ -3070,6 +5068,28 @@ [(set_attr "movprfx" "*,yes")] ) +(define_expand "@aarch64_cond_abd<mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand") + (match_operand:SVE_F 3 "register_operand")] + UNSPEC_COND_FSUB)] + UNSPEC_COND_FABS) + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +{ + if (rtx_equal_p (operands[3], operands[4])) + std::swap (operands[2], operands[3]); +}) + ;; Predicated floating-point absolute difference, merging with the first ;; input. (define_insn_and_rewrite "*aarch64_cond_abd<mode>_2" @@ -3195,31 +5215,47 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point multiplication. -(define_insn_and_split "*mul<mode>3" - [(set (match_operand:SVE_F 0 "register_operand" "=w, w, ?&w") +(define_insn_and_split "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, w, w, ?&w, ?&w") (unspec:SVE_F - [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") - (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, Z, i") - (match_operand:SVE_F 2 "register_operand" "%0, w, 0") - (match_operand:SVE_F 3 "aarch64_sve_float_mul_operand" "vsM, w, vsM")] - UNSPEC_COND_FMUL))] + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl, Upl") + (match_operand:SI 4 "aarch64_sve_gp_strictness" "i, Z, Ui1, i, Ui1") + (match_operand:SVE_F 2 "register_operand" "%0, w, 0, w, w") + (match_operand:SVE_F 3 "aarch64_sve_float_mul_operand" "vsM, w, w, vsM, w")] + SVE_COND_FP_MUL))] "TARGET_SVE" "@ fmul\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 # - movprfx\t%0, %2\;fmul\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + fmul\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %2\;fmul\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 + movprfx\t%0, %2\;fmul\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.<Vetype>" ; Split the unpredicated form after reload, so that we don't have ; the unnecessary PTRUE. "&& reload_completed - && register_operand (operands[3], <MODE>mode)" + && register_operand (operands[3], <MODE>mode) + && INTVAL (operands[4]) == SVE_RELAXED_GP" [(set (match_dup 0) (mult:SVE_F (match_dup 2) (match_dup 3)))] "" - [(set_attr "movprfx" "*,*,yes")] + [(set_attr "movprfx" "*,*,*,yes,yes")] ) ;; Merging forms are handled through SVE_COND_FP_BINARY and ;; SVE_COND_FP_BINARY_I1. +;; Unpredicated multiplication by selected lanes. +(define_insn "@aarch64_mul_lane_<mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w") + (mult:SVE_F + (unspec:SVE_F + [(match_operand:SVE_F 2 "register_operand" "<sve_lane_con>") + (match_operand:SI 3 "const_int_operand")] + UNSPEC_SVE_LANE_SELECT) + (match_operand:SVE_F 1 "register_operand" "w")))] + "TARGET_SVE" + "fmul\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>[%3]" +) + ;; ------------------------------------------------------------------------- ;; ---- [FP] Binary logical operations ;; ------------------------------------------------------------------------- @@ -3305,7 +5341,9 @@ ;; ---- [FP] Maximum and minimum ;; ------------------------------------------------------------------------- ;; Includes: +;; - FMAX ;; - FMAXNM +;; - FMIN ;; - FMINNM ;; ------------------------------------------------------------------------- @@ -3326,14 +5364,14 @@ ) ;; Predicated floating-point maximum/minimum. -(define_insn "*<optab><mode>3" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w, w, ?&w, ?&w") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") (match_operand:SI 4 "aarch64_sve_gp_strictness") (match_operand:SVE_F 2 "register_operand" "%0, 0, w, w") (match_operand:SVE_F 3 "aarch64_sve_float_maxmin_operand" "vsB, w, vsB, w")] - SVE_COND_FP_MAXMIN_PUBLIC))] + SVE_COND_FP_MAXMIN))] "TARGET_SVE" "@ <sve_fp_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 @@ -3417,6 +5455,24 @@ "<logical>s\t%0.b, %1/z, %2.b, %3.b" ) +;; Same with just the flags result. +(define_insn "*<optab><mode>3_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (and:PRED_ALL + (LOGICAL:PRED_ALL + (match_operand:PRED_ALL 2 "register_operand" "Upa") + (match_operand:PRED_ALL 3 "register_operand" "Upa")) + (match_dup 4))] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "<logical>s\t%0.b, %1/z, %2.b, %3.b" +) + ;; ------------------------------------------------------------------------- ;; ---- [PRED] Binary logical operations (inverted second input) ;; ------------------------------------------------------------------------- @@ -3426,7 +5482,7 @@ ;; ------------------------------------------------------------------------- ;; Predicated predicate BIC and ORN. -(define_insn "*<nlogical><mode>3" +(define_insn "aarch64_pred_<nlogical><mode>_z" [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") (and:PRED_ALL (NLOGICAL:PRED_ALL @@ -3437,6 +5493,48 @@ "<nlogical>\t%0.b, %1/z, %2.b, %3.b" ) +;; Same, but set the flags as a side-effect. +(define_insn "*<nlogical><mode>3_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (and:PRED_ALL + (NLOGICAL:PRED_ALL + (not:PRED_ALL + (match_operand:PRED_ALL 3 "register_operand" "Upa")) + (match_operand:PRED_ALL 2 "register_operand" "Upa")) + (match_dup 4))] + UNSPEC_PTEST)) + (set (match_operand:PRED_ALL 0 "register_operand" "=Upa") + (and:PRED_ALL (NLOGICAL:PRED_ALL + (not:PRED_ALL (match_dup 3)) + (match_dup 2)) + (match_dup 4)))] + "TARGET_SVE" + "<nlogical>s\t%0.b, %1/z, %2.b, %3.b" +) + +;; Same with just the flags result. +(define_insn "*<nlogical><mode>3_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (and:PRED_ALL + (NLOGICAL:PRED_ALL + (not:PRED_ALL + (match_operand:PRED_ALL 3 "register_operand" "Upa")) + (match_operand:PRED_ALL 2 "register_operand" "Upa")) + (match_dup 4))] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "<nlogical>s\t%0.b, %1/z, %2.b, %3.b" +) + ;; ------------------------------------------------------------------------- ;; ---- [PRED] Binary logical operations (inverted result) ;; ------------------------------------------------------------------------- @@ -3446,7 +5544,7 @@ ;; ------------------------------------------------------------------------- ;; Predicated predicate NAND and NOR. -(define_insn "*<logical_nn><mode>3" +(define_insn "aarch64_pred_<logical_nn><mode>_z" [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") (and:PRED_ALL (NLOGICAL:PRED_ALL @@ -3457,6 +5555,50 @@ "<logical_nn>\t%0.b, %1/z, %2.b, %3.b" ) +;; Same, but set the flags as a side-effect. +(define_insn "*<logical_nn><mode>3_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (and:PRED_ALL + (NLOGICAL:PRED_ALL + (not:PRED_ALL + (match_operand:PRED_ALL 2 "register_operand" "Upa")) + (not:PRED_ALL + (match_operand:PRED_ALL 3 "register_operand" "Upa"))) + (match_dup 4))] + UNSPEC_PTEST)) + (set (match_operand:PRED_ALL 0 "register_operand" "=Upa") + (and:PRED_ALL (NLOGICAL:PRED_ALL + (not:PRED_ALL (match_dup 2)) + (not:PRED_ALL (match_dup 3))) + (match_dup 4)))] + "TARGET_SVE" + "<logical_nn>s\t%0.b, %1/z, %2.b, %3.b" +) + +;; Same with just the flags result. +(define_insn "*<logical_nn><mode>3_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (and:PRED_ALL + (NLOGICAL:PRED_ALL + (not:PRED_ALL + (match_operand:PRED_ALL 2 "register_operand" "Upa")) + (not:PRED_ALL + (match_operand:PRED_ALL 3 "register_operand" "Upa"))) + (match_dup 4))] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "<logical_nn>s\t%0.b, %1/z, %2.b, %3.b" +) + ;; ========================================================================= ;; == Ternary arithmetic ;; ========================================================================= @@ -3488,7 +5630,7 @@ ) ;; Predicated integer addition of product. -(define_insn "*fma<mode>4" +(define_insn "@aarch64_pred_fma<mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, w, ?&w") (plus:SVE_I (unspec:SVE_I @@ -3623,7 +5765,7 @@ ) ;; Predicated integer subtraction of product. -(define_insn "*fnma<mode>3" +(define_insn "@aarch64_pred_fnma<mode>" [(set (match_operand:SVE_I 0 "register_operand" "=w, w, ?&w") (minus:SVE_I (match_operand:SVE_I 4 "register_operand" "w, 0, w") @@ -3756,6 +5898,25 @@ [(set_attr "movprfx" "*,yes")] ) +;; Four-element integer dot-product by selected lanes with accumulation. +(define_insn "@aarch64_<sur>dot_prod_lane<vsi2qi>" + [(set (match_operand:SVE_SDI 0 "register_operand" "=w, ?&w") + (plus:SVE_SDI + (unspec:SVE_SDI + [(match_operand:<VSI2QI> 1 "register_operand" "w, w") + (unspec:<VSI2QI> + [(match_operand:<VSI2QI> 2 "register_operand" "<sve_lane_con>, <sve_lane_con>") + (match_operand:SI 3 "const_int_operand")] + UNSPEC_SVE_LANE_SELECT)] + DOTPROD) + (match_operand:SVE_SDI 4 "register_operand" "0, w")))] + "TARGET_SVE" + "@ + <sur>dot\\t%0.<Vetype>, %1.<Vetype_fourth>, %2.<Vetype_fourth>[%3] + movprfx\t%0, %4\;<sur>dot\\t%0.<Vetype>, %1.<Vetype_fourth>, %2.<Vetype_fourth>[%3]" + [(set_attr "movprfx" "*,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [INT] Sum of absolute differences ;; ------------------------------------------------------------------------- @@ -3817,7 +5978,7 @@ ) ;; Predicated floating-point ternary operations. -(define_insn "*<optab><mode>4" +(define_insn "@aarch64_pred_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w, w, ?&w") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl") @@ -3835,7 +5996,7 @@ ) ;; Predicated floating-point ternary operations with merging. -(define_expand "cond_<optab><mode>" +(define_expand "@cond_<optab><mode>" [(set (match_operand:SVE_F 0 "register_operand") (unspec:SVE_F [(match_operand:<VPRED> 1 "register_operand") @@ -3953,6 +6114,169 @@ [(set_attr "movprfx" "yes")] ) +;; Unpredicated FMLA and FMLS by selected lanes. It doesn't seem worth using +;; (fma ...) since target-independent code won't understand the indexing. +(define_insn "@aarch64_<optab>_lane_<mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:SVE_F 1 "register_operand" "w, w") + (unspec:SVE_F + [(match_operand:SVE_F 2 "register_operand" "<sve_lane_con>, <sve_lane_con>") + (match_operand:SI 3 "const_int_operand")] + UNSPEC_SVE_LANE_SELECT) + (match_operand:SVE_F 4 "register_operand" "0, w")] + SVE_FP_TERNARY_LANE))] + "TARGET_SVE" + "@ + <sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>[%3] + movprfx\t%0, %4\;<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>[%3]" + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [FP] Complex multiply-add +;; ------------------------------------------------------------------------- +;; Includes merging patterns for: +;; - FCMLA +;; ------------------------------------------------------------------------- + +;; Predicated FCMLA. +(define_insn "@aarch64_pred_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (match_operand:SI 5 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "w, w") + (match_operand:SVE_F 3 "register_operand" "w, w") + (match_operand:SVE_F 4 "register_operand" "0, w")] + SVE_COND_FCMLA))] + "TARGET_SVE" + "@ + fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0, %4\;fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot>" + [(set_attr "movprfx" "*,yes")] +) + +;; Predicated FCMLA with merging. +(define_expand "@cond_<optab><mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand") + (match_operand:SVE_F 3 "register_operand") + (match_operand:SVE_F 4 "register_operand")] + SVE_COND_FCMLA) + (match_operand:SVE_F 5 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +;; Predicated FCMLA, merging with the third input. +(define_insn_and_rewrite "*cond_<optab><mode>_4" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_F + [(match_operand 5) + (match_operand:SI 6 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "w, w") + (match_operand:SVE_F 3 "register_operand" "w, w") + (match_operand:SVE_F 4 "register_operand" "0, w")] + SVE_COND_FCMLA) + (match_dup 4)] + UNSPEC_SEL))] + "TARGET_SVE && aarch64_sve_pred_dominates_p (&operands[5], operands[1])" + "@ + fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0, %4\;fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot>" + "&& !rtx_equal_p (operands[1], operands[5])" + { + operands[5] = copy_rtx (operands[1]); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Predicated FCMLA, merging with an independent value. +(define_insn_and_rewrite "*cond_<optab><mode>_any" + [(set (match_operand:SVE_F 0 "register_operand" "=&w, &w, &w, ?&w") + (unspec:SVE_F + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl, Upl, Upl") + (unspec:SVE_F + [(match_operand 6) + (match_operand:SI 7 "aarch64_sve_gp_strictness") + (match_operand:SVE_F 2 "register_operand" "w, w, w, w") + (match_operand:SVE_F 3 "register_operand" "w, w, w, w") + (match_operand:SVE_F 4 "register_operand" "w, 0, w, w")] + SVE_COND_FCMLA) + (match_operand:SVE_F 5 "aarch64_simd_reg_or_zero" "Dz, Dz, 0, w")] + UNSPEC_SEL))] + "TARGET_SVE + && !rtx_equal_p (operands[4], operands[5]) + && aarch64_sve_pred_dominates_p (&operands[6], operands[1])" + "@ + movprfx\t%0.<Vetype>, %1/z, %4.<Vetype>\;fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0.<Vetype>, %1/z, %0.<Vetype>\;fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot> + movprfx\t%0.<Vetype>, %1/m, %4.<Vetype>\;fcmla\t%0.<Vetype>, %1/m, %2.<Vetype>, %3.<Vetype>, #<rot> + #" + "&& 1" + { + if (reload_completed + && register_operand (operands[5], <MODE>mode) + && !rtx_equal_p (operands[0], operands[5])) + { + emit_insn (gen_vcond_mask_<mode><vpred> (operands[0], operands[4], + operands[5], operands[1])); + operands[5] = operands[4] = operands[0]; + } + else if (!rtx_equal_p (operands[1], operands[6])) + operands[6] = copy_rtx (operands[1]); + else + FAIL; + } + [(set_attr "movprfx" "yes")] +) + +;; Unpredicated FCMLA with indexing. +(define_insn "@aarch64_<optab>_lane_<mode>" + [(set (match_operand:SVE_HSF 0 "register_operand" "=w, ?&w") + (unspec:SVE_HSF + [(match_operand:SVE_HSF 1 "register_operand" "w, w") + (unspec:SVE_HSF + [(match_operand:SVE_HSF 2 "register_operand" "<sve_lane_pair_con>, <sve_lane_pair_con>") + (match_operand:SI 3 "const_int_operand")] + UNSPEC_SVE_LANE_SELECT) + (match_operand:SVE_HSF 4 "register_operand" "0, w")] + FCMLA))] + "TARGET_SVE" + "@ + fcmla\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>[%3], #<rot> + movprfx\t%0, %4\;fcmla\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>[%3], #<rot>" + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [FP] Trigonometric multiply-add +;; ------------------------------------------------------------------------- +;; Includes: +;; - FTMAD +;; ------------------------------------------------------------------------- + +(define_insn "@aarch64_sve_tmad<mode>" + [(set (match_operand:SVE_F 0 "register_operand" "=w, ?&w") + (unspec:SVE_F [(match_operand:SVE_F 1 "register_operand" "0, w") + (match_operand:SVE_F 2 "register_operand" "w, w") + (match_operand:DI 3 "const_int_operand")] + UNSPEC_FTMAD))] + "TARGET_SVE" + "@ + ftmad\t%0.<Vetype>, %0.<Vetype>, %2.<Vetype>, #%3 + movprfx\t%0, %1\;ftmad\t%0.<Vetype>, %0.<Vetype>, %2.<Vetype>, #%3" + [(set_attr "movprfx" "*,yes")] +) + ;; ========================================================================= ;; == Comparisons and selects ;; ========================================================================= @@ -4012,7 +6336,7 @@ ;; the latter of which can be a zero constant or a variable. Treat duplicates ;; of GPRs as being more expensive than duplicates of FPRs, since they ;; involve a cross-file move. -(define_insn "*aarch64_sel_dup<mode>" +(define_insn "@aarch64_sel_dup<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=?w, w, ??w, ?&w, ??&w, ?&w") (unspec:SVE_ALL [(match_operand:<VPRED> 3 "register_operand" "Upa, Upa, Upl, Upl, Upl, Upl") @@ -4091,7 +6415,7 @@ ;; ------------------------------------------------------------------------- ;; ---- [INT] Comparisons ;; ------------------------------------------------------------------------- -;; Includes merging patterns for: +;; Includes: ;; - CMPEQ ;; - CMPGE ;; - CMPGT @@ -4253,29 +6577,102 @@ (clobber (reg:CC_NZC CC_REGNUM))])] ) +;; Predicated integer wide comparisons. +(define_insn "@aarch64_pred_cmp<cmp_op><mode>_wide" + [(set (match_operand:<VPRED> 0 "register_operand" "=Upa") + (unspec:<VPRED> + [(match_operand:VNx16BI 1 "register_operand" "Upl") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_BHSI 3 "register_operand" "w") + (match_operand:VNx2DI 4 "register_operand" "w")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z)) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" + "cmp<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.d" +) + +;; Predicated integer wide comparisons in which both the flag and +;; predicate results are interesting. +(define_insn "*aarch64_pred_cmp<cmp_op><mode>_wide_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upl") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:VNx16BI 6 "register_operand" "Upl") + (match_operand:SI 7 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_BHSI 2 "register_operand" "w") + (match_operand:VNx2DI 3 "register_operand" "w")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z)] + UNSPEC_PTEST)) + (set (match_operand:<VPRED> 0 "register_operand" "=Upa") + (unspec:<VPRED> + [(match_dup 6) + (match_dup 7) + (unspec:<VPRED> + [(match_dup 2) + (match_dup 3)] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z))] + "TARGET_SVE + && aarch64_sve_same_pred_for_ptest_p (&operands[4], &operands[6])" + "cmp<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.d" +) + +;; Predicated integer wide comparisons in which only the flags result +;; is interesting. +(define_insn "*aarch64_pred_cmp<cmp_op><mode>_wide_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upl") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:VNx16BI 6 "register_operand" "Upl") + (match_operand:SI 7 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_BHSI 2 "register_operand" "w") + (match_operand:VNx2DI 3 "register_operand" "w")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z)] + UNSPEC_PTEST)) + (clobber (match_scratch:<VPRED> 0 "=Upa"))] + "TARGET_SVE + && aarch64_sve_same_pred_for_ptest_p (&operands[4], &operands[6])" + "cmp<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.d" +) + ;; ------------------------------------------------------------------------- ;; ---- [INT] While tests ;; ------------------------------------------------------------------------- ;; Includes: +;; - WHILELE ;; - WHILELO +;; - WHILELS +;; - WHILELT ;; ------------------------------------------------------------------------- -;; Set element I of the result if operand1 + J < operand2 for all J in [0, I], -;; with the comparison being unsigned. -(define_insn "@while_ult<GPI:mode><PRED_ALL:mode>" +;; Set element I of the result if (cmp (plus operand1 J) operand2) is +;; true for all J in [0, I]. +(define_insn "@while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>" [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") (unspec:PRED_ALL [(match_operand:GPI 1 "aarch64_reg_or_zero" "rZ") (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")] - UNSPEC_WHILE_LO)) + SVE_WHILE)) (clobber (reg:CC_NZC CC_REGNUM))] "TARGET_SVE" - "whilelo\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" + "while<cmp_op>\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" ) -;; WHILELO sets the flags in the same way as a PTEST with a PTRUE GP. -;; Handle the case in which both results are useful. The GP operands -;; to the PTEST aren't needed, so we allow them to be anything. -(define_insn_and_rewrite "*while_ult<GPI:mode><PRED_ALL:mode>_cc" +;; The WHILE instructions set the flags in the same way as a PTEST with +;; a PTRUE GP. Handle the case in which both results are useful. The GP +;; operands to the PTEST aren't needed, so we allow them to be anything. +(define_insn_and_rewrite "*while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>_cc" [(set (reg:CC_NZC CC_REGNUM) (unspec:CC_NZC [(match_operand 3) @@ -4284,14 +6681,38 @@ (unspec:PRED_ALL [(match_operand:GPI 1 "aarch64_reg_or_zero" "rZ") (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")] - UNSPEC_WHILE_LO)] + SVE_WHILE)] UNSPEC_PTEST)) (set (match_operand:PRED_ALL 0 "register_operand" "=Upa") (unspec:PRED_ALL [(match_dup 1) (match_dup 2)] - UNSPEC_WHILE_LO))] + SVE_WHILE))] "TARGET_SVE" - "whilelo\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" + "while<cmp_op>\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" + ;; Force the compiler to drop the unused predicate operand, so that we + ;; don't have an unnecessary PTRUE. + "&& (!CONSTANT_P (operands[3]) || !CONSTANT_P (operands[4]))" + { + operands[3] = CONSTM1_RTX (VNx16BImode); + operands[4] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +;; Same, but handle the case in which only the flags result is useful. +(define_insn_and_rewrite "*while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 3) + (match_operand 4) + (const_int SVE_KNOWN_PTRUE) + (unspec:PRED_ALL + [(match_operand:GPI 1 "aarch64_reg_or_zero" "rZ") + (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")] + SVE_WHILE)] + UNSPEC_PTEST)) + (clobber (match_scratch:PRED_ALL 0 "=Upa"))] + "TARGET_SVE" + "while<cmp_op>\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" ;; Force the compiler to drop the unused predicate operand, so that we ;; don't have an unnecessary PTRUE. "&& (!CONSTANT_P (operands[3]) || !CONSTANT_P (operands[4]))" @@ -4331,31 +6752,31 @@ ) ;; Predicated floating-point comparisons. -(define_insn "*fcm<cmp_op><mode>" +(define_insn "@aarch64_pred_fcm<cmp_op><mode>" [(set (match_operand:<VPRED> 0 "register_operand" "=Upa, Upa") (unspec:<VPRED> [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") - (match_operand:SI 4 "aarch64_sve_ptrue_flag") - (match_operand:SVE_F 2 "register_operand" "w, w") - (match_operand:SVE_F 3 "aarch64_simd_reg_or_zero" "Dz, w")] + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand" "w, w") + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero" "Dz, w")] SVE_COND_FP_CMP_I0))] "TARGET_SVE" "@ - fcm<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, #0.0 - fcm<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype>" + fcm<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, #0.0 + fcm<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype>" ) ;; Same for unordered comparisons. -(define_insn "*fcmuo<mode>" +(define_insn "@aarch64_pred_fcmuo<mode>" [(set (match_operand:<VPRED> 0 "register_operand" "=Upa") (unspec:<VPRED> [(match_operand:<VPRED> 1 "register_operand" "Upl") - (match_operand:SI 4 "aarch64_sve_ptrue_flag") - (match_operand:SVE_F 2 "register_operand" "w") - (match_operand:SVE_F 3 "register_operand" "w")] + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand" "w") + (match_operand:SVE_F 4 "register_operand" "w")] UNSPEC_COND_FCMUO))] "TARGET_SVE" - "fcmuo\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype>" + "fcmuo\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype>" ) ;; Floating-point comparisons predicated on a PTRUE, with the results ANDed @@ -4422,6 +6843,25 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point absolute comparisons. +(define_expand "@aarch64_pred_fac<cmp_op><mode>" + [(set (match_operand:<VPRED> 0 "register_operand") + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:SVE_F + [(match_dup 1) + (match_dup 2) + (match_operand:SVE_F 3 "register_operand")] + UNSPEC_COND_FABS) + (unspec:SVE_F + [(match_dup 1) + (match_dup 2) + (match_operand:SVE_F 4 "register_operand")] + UNSPEC_COND_FABS)] + SVE_COND_FP_ABS_CMP))] + "TARGET_SVE" +) + (define_insn_and_rewrite "*aarch64_pred_fac<cmp_op><mode>" [(set (match_operand:<VPRED> 0 "register_operand" "=Upa") (unspec:<VPRED> @@ -4451,6 +6891,26 @@ ) ;; ------------------------------------------------------------------------- +;; ---- [PRED] Select +;; ------------------------------------------------------------------------- +;; Includes: +;; - SEL +;; ------------------------------------------------------------------------- + +(define_insn "@vcond_mask_<mode><mode>" + [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") + (ior:PRED_ALL + (and:PRED_ALL + (match_operand:PRED_ALL 3 "register_operand" "Upa") + (match_operand:PRED_ALL 1 "register_operand" "Upa")) + (and:PRED_ALL + (not (match_dup 3)) + (match_operand:PRED_ALL 2 "register_operand" "Upa"))))] + "TARGET_SVE" + "sel\t%0.b, %3, %1.b, %2.b" +) + +;; ------------------------------------------------------------------------- ;; ---- [PRED] Test bits ;; ------------------------------------------------------------------------- ;; Includes: @@ -4506,22 +6966,36 @@ ;; ---- [INT,FP] Conditional reductions ;; ------------------------------------------------------------------------- ;; Includes: +;; - CLASTA ;; - CLASTB ;; ------------------------------------------------------------------------- ;; Set operand 0 to the last active element in operand 3, or to tied ;; operand 1 if no elements are active. -(define_insn "fold_extract_last_<mode>" +(define_insn "@fold_extract_<last_op>_<mode>" [(set (match_operand:<VEL> 0 "register_operand" "=?r, w") (unspec:<VEL> [(match_operand:<VEL> 1 "register_operand" "0, 0") (match_operand:<VPRED> 2 "register_operand" "Upl, Upl") (match_operand:SVE_ALL 3 "register_operand" "w, w")] - UNSPEC_CLASTB))] + CLAST))] + "TARGET_SVE" + "@ + clast<ab>\t%<vwcore>0, %2, %<vwcore>0, %3.<Vetype> + clast<ab>\t%<Vetype>0, %2, %<Vetype>0, %3.<Vetype>" +) + +(define_insn "@aarch64_fold_extract_vector_<last_op>_<mode>" + [(set (match_operand:SVE_ALL 0 "register_operand" "=w, ?&w") + (unspec:SVE_ALL + [(match_operand:SVE_ALL 1 "register_operand" "0, w") + (match_operand:<VPRED> 2 "register_operand" "Upl, Upl") + (match_operand:SVE_ALL 3 "register_operand" "w, w")] + CLAST))] "TARGET_SVE" "@ - clastb\t%<vwcore>0, %2, %<vwcore>0, %3.<Vetype> - clastb\t%<Vetype>0, %2, %<Vetype>0, %3.<Vetype>" + clast<ab>\t%0.<Vetype>, %2, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %1\;clast<ab>\t%0.<Vetype>, %2, %0.<Vetype>, %3.<Vetype>" ) ;; ------------------------------------------------------------------------- @@ -4531,6 +7005,7 @@ ;; - ANDV ;; - EORV ;; - ORV +;; - SADDV ;; - SMAXV ;; - SMINV ;; - UADDV @@ -4540,24 +7015,27 @@ ;; Unpredicated integer add reduction. (define_expand "reduc_plus_scal_<mode>" - [(set (match_operand:<VEL> 0 "register_operand") - (unspec:<VEL> [(match_dup 2) - (match_operand:SVE_I 1 "register_operand")] - UNSPEC_ADDV))] + [(match_operand:<VEL> 0 "register_operand") + (match_operand:SVE_I 1 "register_operand")] "TARGET_SVE" { - operands[2] = aarch64_ptrue_reg (<VPRED>mode); + rtx pred = aarch64_ptrue_reg (<VPRED>mode); + rtx tmp = <VEL>mode == DImode ? operands[0] : gen_reg_rtx (DImode); + emit_insn (gen_aarch64_pred_reduc_uadd_<mode> (tmp, pred, operands[1])); + if (tmp != operands[0]) + emit_move_insn (operands[0], gen_lowpart (<VEL>mode, tmp)); + DONE; } ) ;; Predicated integer add reduction. The result is always 64-bits. -(define_insn "*reduc_plus_scal_<mode>" - [(set (match_operand:<VEL> 0 "register_operand" "=w") - (unspec:<VEL> [(match_operand:<VPRED> 1 "register_operand" "Upl") - (match_operand:SVE_I 2 "register_operand" "w")] - UNSPEC_ADDV))] - "TARGET_SVE" - "uaddv\t%d0, %1, %2.<Vetype>" +(define_insn "@aarch64_pred_reduc_<optab>_<mode>" + [(set (match_operand:DI 0 "register_operand" "=w") + (unspec:DI [(match_operand:<VPRED> 1 "register_operand" "Upl") + (match_operand:SVE_I 2 "register_operand" "w")] + SVE_INT_ADDV))] + "TARGET_SVE && <max_elem_bits> >= <elem_bits>" + "<su>addv\t%d0, %1, %2.<Vetype>" ) ;; Unpredicated integer reductions. @@ -4573,7 +7051,7 @@ ) ;; Predicated integer reductions. -(define_insn "*reduc_<optab>_scal_<mode>" +(define_insn "@aarch64_pred_reduc_<optab>_<mode>" [(set (match_operand:<VEL> 0 "register_operand" "=w") (unspec:<VEL> [(match_operand:<VPRED> 1 "register_operand" "Upl") (match_operand:SVE_I 2 "register_operand" "w")] @@ -4606,7 +7084,7 @@ ) ;; Predicated floating-point tree reductions. -(define_insn "*reduc_<optab>_scal_<mode>" +(define_insn "@aarch64_pred_reduc_<optab>_<mode>" [(set (match_operand:<VEL> 0 "register_operand" "=w") (unspec:<VEL> [(match_operand:<VPRED> 1 "register_operand" "Upl") (match_operand:SVE_F 2 "register_operand" "w")] @@ -4670,7 +7148,7 @@ } ) -(define_insn "*aarch64_sve_tbl<mode>" +(define_insn "@aarch64_sve_tbl<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w") (unspec:SVE_ALL [(match_operand:SVE_ALL 1 "register_operand" "w") @@ -4684,12 +7162,23 @@ ;; ---- [INT,FP] Special-purpose unary permutes ;; ------------------------------------------------------------------------- ;; Includes: +;; - COMPACT ;; - DUP ;; - REV ;; ------------------------------------------------------------------------- +;; Compact active elements and pad with zeros. +(define_insn "@aarch64_sve_compact<mode>" + [(set (match_operand:SVE_SD 0 "register_operand" "=w") + (unspec:SVE_SD [(match_operand:<VPRED> 1 "register_operand" "Upl") + (match_operand:SVE_SD 2 "register_operand" "w")] + UNSPEC_SVE_COMPACT))] + "TARGET_SVE" + "compact\t%0.<Vetype>, %1, %2.<Vetype>" +) + ;; Duplicate one element of a vector. -(define_insn "*aarch64_sve_dup_lane<mode>" +(define_insn "@aarch64_sve_dup_lane<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w") (vec_duplicate:SVE_ALL (vec_select:<VEL> @@ -4700,6 +7189,42 @@ "dup\t%0.<Vetype>, %1.<Vetype>[%2]" ) +;; Use DUP.Q to duplicate a 128-bit segment of a register. +;; +;; The vec_select:<V128> sets memory lane number N of the V128 to lane +;; number op2 + N of op1. (We don't need to distinguish between memory +;; and architectural register lane numbering for op1 or op0, since the +;; two numbering schemes are the same for SVE.) +;; +;; The vec_duplicate:SVE_ALL then copies memory lane number N of the +;; V128 (and thus lane number op2 + N of op1) to lane numbers N + I * STEP +;; of op0. We therefore get the correct result for both endiannesses. +;; +;; The wrinkle is that for big-endian V128 registers, memory lane numbering +;; is in the opposite order to architectural register lane numbering. +;; Thus if we were to do this operation via a V128 temporary register, +;; the vec_select and vec_duplicate would both involve a reverse operation +;; for big-endian targets. In this fused pattern the two reverses cancel +;; each other out. +(define_insn "@aarch64_sve_dupq_lane<mode>" + [(set (match_operand:SVE_ALL 0 "register_operand" "=w") + (vec_duplicate:SVE_ALL + (vec_select:<V128> + (match_operand:SVE_ALL 1 "register_operand" "w") + (match_operand 2 "ascending_int_parallel"))))] + "TARGET_SVE + && (INTVAL (XVECEXP (operands[2], 0, 0)) + * GET_MODE_SIZE (<VEL>mode)) % 16 == 0 + && IN_RANGE (INTVAL (XVECEXP (operands[2], 0, 0)) + * GET_MODE_SIZE (<VEL>mode), 0, 63)" + { + unsigned int byte = (INTVAL (XVECEXP (operands[2], 0, 0)) + * GET_MODE_SIZE (<VEL>mode)); + operands[2] = gen_int_mode (byte / 16, DImode); + return "dup\t%0.q, %1.q[%2]"; + } +) + ;; Reverse the order of elements within a full vector. (define_insn "@aarch64_sve_rev<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w") @@ -4712,6 +7237,7 @@ ;; ---- [INT,FP] Special-purpose binary permutes ;; ------------------------------------------------------------------------- ;; Includes: +;; - SPLICE ;; - TRN1 ;; - TRN2 ;; - UZP1 @@ -4720,9 +7246,23 @@ ;; - ZIP2 ;; ------------------------------------------------------------------------- +;; Like EXT, but start at the first active element. +(define_insn "@aarch64_sve_splice<mode>" + [(set (match_operand:SVE_ALL 0 "register_operand" "=w, ?&w") + (unspec:SVE_ALL [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (match_operand:SVE_ALL 2 "register_operand" "0, w") + (match_operand:SVE_ALL 3 "register_operand" "w, w")] + UNSPEC_SVE_SPLICE))] + "TARGET_SVE" + "@ + splice\t%0.<Vetype>, %1, %0.<Vetype>, %3.<Vetype> + movprfx\t%0, %2\;splice\t%0.<Vetype>, %1, %0.<Vetype>, %3.<Vetype>" + [(set_attr "movprfx" "*, yes")] +) + ;; Permutes that take half the elements from one vector and half the ;; elements from the other. -(define_insn "aarch64_sve_<perm_insn><mode>" +(define_insn "@aarch64_sve_<perm_insn><mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w") (unspec:SVE_ALL [(match_operand:SVE_ALL 1 "register_operand" "w") (match_operand:SVE_ALL 2 "register_operand" "w")] @@ -4733,7 +7273,7 @@ ;; Concatenate two vectors and extract a subvector. Note that the ;; immediate (third) operand is the lane index not the byte index. -(define_insn "*aarch64_sve_ext<mode>" +(define_insn "@aarch64_sve_ext<mode>" [(set (match_operand:SVE_ALL 0 "register_operand" "=w, ?&w") (unspec:SVE_ALL [(match_operand:SVE_ALL 1 "register_operand" "0, w") (match_operand:SVE_ALL 2 "register_operand" "w, w") @@ -4836,7 +7376,7 @@ } ) -(define_insn "aarch64_sve_<su>unpk<perm_hilo>_<SVE_BHSI:mode>" +(define_insn "@aarch64_sve_<su>unpk<perm_hilo>_<SVE_BHSI:mode>" [(set (match_operand:<VWIDE> 0 "register_operand" "=w") (unspec:<VWIDE> [(match_operand:SVE_BHSI 1 "register_operand" "w")] UNPACK))] @@ -4868,7 +7408,7 @@ ) ;; Predicated float-to-integer conversion, either to the same width or wider. -(define_insn "*aarch64_sve_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>" +(define_insn "@aarch64_sve_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>" [(set (match_operand:SVE_HSDI 0 "register_operand" "=w") (unspec:SVE_HSDI [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand" "Upl") @@ -4880,7 +7420,7 @@ ) ;; Predicated narrowing float-to-integer conversion. -(define_insn "*aarch64_sve_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>" +(define_insn "@aarch64_sve_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>" [(set (match_operand:VNx4SI_ONLY 0 "register_operand" "=w") (unspec:VNx4SI_ONLY [(match_operand:VNx2BI 1 "register_operand" "Upl") @@ -4893,7 +7433,20 @@ ;; Predicated float-to-integer conversion with merging, either to the same ;; width or wider. -;; +(define_expand "@cond_<optab>_nontrunc<SVE_F:mode><SVE_HSDI:mode>" + [(set (match_operand:SVE_HSDI 0 "register_operand") + (unspec:SVE_HSDI + [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand") + (unspec:SVE_HSDI + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_F 2 "register_operand")] + SVE_COND_FCVTI) + (match_operand:SVE_HSDI 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_HSDI:elem_bits> >= <SVE_F:elem_bits>" +) + ;; The first alternative doesn't need the earlyclobber, but the only case ;; it would help is the uninteresting one in which operands 2 and 3 are ;; the same register (despite having different modes). Making all the @@ -4924,6 +7477,40 @@ [(set_attr "movprfx" "*,yes,yes")] ) +;; Predicated narrowing float-to-integer conversion with merging. +(define_expand "@cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>" + [(set (match_operand:VNx4SI_ONLY 0 "register_operand") + (unspec:VNx4SI_ONLY + [(match_operand:VNx2BI 1 "register_operand") + (unspec:VNx4SI_ONLY + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:VNx2DF_ONLY 2 "register_operand")] + SVE_COND_FCVTI) + (match_operand:VNx4SI_ONLY 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +(define_insn "*cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx4SI_ONLY:mode>" + [(set (match_operand:VNx4SI_ONLY 0 "register_operand" "=&w, &w, ?&w") + (unspec:VNx4SI_ONLY + [(match_operand:VNx2BI 1 "register_operand" "Upl, Upl, Upl") + (unspec:VNx4SI_ONLY + [(match_dup 1) + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:VNx2DF_ONLY 2 "register_operand" "w, w, w")] + SVE_COND_FCVTI) + (match_operand:VNx4SI_ONLY 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + fcvtz<su>\t%0.<VNx4SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype> + movprfx\t%0.<VNx2DF_ONLY:Vetype>, %1/z, %2.<VNx2DF_ONLY:Vetype>\;fcvtz<su>\t%0.<VNx4SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype> + movprfx\t%0, %3\;fcvtz<su>\t%0.<VNx4SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [INT<-FP] Packs ;; ------------------------------------------------------------------------- @@ -4985,7 +7572,7 @@ ;; Predicated integer-to-float conversion, either to the same width or ;; narrower. -(define_insn "*aarch64_sve_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>" +(define_insn "@aarch64_sve_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>" [(set (match_operand:SVE_F 0 "register_operand" "=w") (unspec:SVE_F [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand" "Upl") @@ -4997,7 +7584,7 @@ ) ;; Predicated widening integer-to-float conversion. -(define_insn "aarch64_sve_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>" +(define_insn "@aarch64_sve_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>" [(set (match_operand:VNx2DF_ONLY 0 "register_operand" "=w") (unspec:VNx2DF_ONLY [(match_operand:VNx2BI 1 "register_operand" "Upl") @@ -5010,7 +7597,20 @@ ;; Predicated integer-to-float conversion with merging, either to the same ;; width or narrower. -;; +(define_expand "@cond_<optab>_nonextend<SVE_HSDI:mode><SVE_F:mode>" + [(set (match_operand:SVE_F 0 "register_operand") + (unspec:SVE_F + [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand") + (unspec:SVE_F + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_HSDI 2 "register_operand")] + SVE_COND_ICVTF) + (match_operand:SVE_F 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_HSDI:elem_bits> >= <SVE_F:elem_bits>" +) + ;; The first alternative doesn't need the earlyclobber, but the only case ;; it would help is the uninteresting one in which operands 2 and 3 are ;; the same register (despite having different modes). Making all the @@ -5041,6 +7641,40 @@ [(set_attr "movprfx" "*,yes,yes")] ) +;; Predicated widening integer-to-float conversion with merging. +(define_expand "@cond_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>" + [(set (match_operand:VNx2DF_ONLY 0 "register_operand") + (unspec:VNx2DF_ONLY + [(match_operand:VNx2BI 1 "register_operand") + (unspec:VNx2DF_ONLY + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:VNx4SI_ONLY 2 "register_operand")] + SVE_COND_ICVTF) + (match_operand:VNx2DF_ONLY 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +(define_insn "*cond_<optab>_extend<VNx4SI_ONLY:mode><VNx2DF_ONLY:mode>" + [(set (match_operand:VNx2DF_ONLY 0 "register_operand" "=w, ?&w, ?&w") + (unspec:VNx2DF_ONLY + [(match_operand:VNx2BI 1 "register_operand" "Upl, Upl, Upl") + (unspec:VNx2DF_ONLY + [(match_dup 1) + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:VNx4SI_ONLY 2 "register_operand" "w, w, w")] + SVE_COND_ICVTF) + (match_operand:VNx2DF_ONLY 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + <su>cvtf\t%0.<VNx2DF_ONLY:Vetype>, %1/m, %2.<VNx4SI_ONLY:Vetype> + movprfx\t%0.<VNx2DF_ONLY:Vetype>, %1/z, %2.<VNx2DF_ONLY:Vetype>\;<su>cvtf\t%0.<VNx2DF_ONLY:Vetype>, %1/m, %2.<VNx4SI_ONLY:Vetype> + movprfx\t%0, %3\;<su>cvtf\t%0.<VNx2DF_ONLY:Vetype>, %1/m, %2.<VNx4SI_ONLY:Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [FP<-INT] Packs ;; ------------------------------------------------------------------------- @@ -5113,7 +7747,7 @@ ) ;; Predicated float-to-float truncation. -(define_insn "*aarch64_sve_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>" +(define_insn "@aarch64_sve_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>" [(set (match_operand:SVE_HSF 0 "register_operand" "=w") (unspec:SVE_HSF [(match_operand:<SVE_SDF:VPRED> 1 "register_operand" "Upl") @@ -5124,6 +7758,40 @@ "fcvt\t%0.<SVE_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype>" ) +;; Predicated float-to-float truncation with merging. +(define_expand "@cond_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>" + [(set (match_operand:SVE_HSF 0 "register_operand") + (unspec:SVE_HSF + [(match_operand:<SVE_SDF:VPRED> 1 "register_operand") + (unspec:SVE_HSF + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_SDF 2 "register_operand")] + SVE_COND_FCVT) + (match_operand:SVE_HSF 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_SDF:elem_bits> > <SVE_HSF:elem_bits>" +) + +(define_insn "*cond_<optab>_trunc<SVE_SDF:mode><SVE_HSF:mode>" + [(set (match_operand:SVE_HSF 0 "register_operand" "=w, ?&w, ?&w") + (unspec:SVE_HSF + [(match_operand:<SVE_SDF:VPRED> 1 "register_operand" "Upl, Upl, Upl") + (unspec:SVE_HSF + [(match_dup 1) + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:SVE_SDF 2 "register_operand" "w, w, w")] + SVE_COND_FCVT) + (match_operand:SVE_HSF 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_SDF:elem_bits> > <SVE_HSF:elem_bits>" + "@ + fcvt\t%0.<SVE_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype> + movprfx\t%0.<SVE_SDF:Vetype>, %1/z, %2.<SVE_SDF:Vetype>\;fcvt\t%0.<SVE_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype> + movprfx\t%0, %3\;fcvt\t%0.<SVE_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [FP<-FP] Unpacks ;; ------------------------------------------------------------------------- @@ -5158,7 +7826,7 @@ ) ;; Predicated float-to-float extension. -(define_insn "aarch64_sve_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>" +(define_insn "@aarch64_sve_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>" [(set (match_operand:SVE_SDF 0 "register_operand" "=w") (unspec:SVE_SDF [(match_operand:<SVE_SDF:VPRED> 1 "register_operand" "Upl") @@ -5169,6 +7837,40 @@ "fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_HSF:Vetype>" ) +;; Predicated float-to-float extension with merging. +(define_expand "@cond_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>" + [(set (match_operand:SVE_SDF 0 "register_operand") + (unspec:SVE_SDF + [(match_operand:<SVE_SDF:VPRED> 1 "register_operand") + (unspec:SVE_SDF + [(match_dup 1) + (const_int SVE_STRICT_GP) + (match_operand:SVE_HSF 2 "register_operand")] + SVE_COND_FCVT) + (match_operand:SVE_SDF 3 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_SDF:elem_bits> > <SVE_HSF:elem_bits>" +) + +(define_insn "*cond_<optab>_nontrunc<SVE_HSF:mode><SVE_SDF:mode>" + [(set (match_operand:SVE_SDF 0 "register_operand" "=w, ?&w, ?&w") + (unspec:SVE_SDF + [(match_operand:<SVE_SDF:VPRED> 1 "register_operand" "Upl, Upl, Upl") + (unspec:SVE_SDF + [(match_dup 1) + (match_operand:SI 4 "aarch64_sve_gp_strictness") + (match_operand:SVE_HSF 2 "register_operand" "w, w, w")] + SVE_COND_FCVT) + (match_operand:SVE_SDF 3 "aarch64_simd_reg_or_zero" "0, Dz, w")] + UNSPEC_SEL))] + "TARGET_SVE && <SVE_SDF:elem_bits> > <SVE_HSF:elem_bits>" + "@ + fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_HSF:Vetype> + movprfx\t%0.<SVE_SDF:Vetype>, %1/z, %2.<SVE_SDF:Vetype>\;fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_HSF:Vetype> + movprfx\t%0, %3\;fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_HSF:Vetype>" + [(set_attr "movprfx" "*,yes,yes")] +) + ;; ------------------------------------------------------------------------- ;; ---- [PRED<-PRED] Packs ;; ------------------------------------------------------------------------- @@ -5213,10 +7915,1042 @@ } ) -(define_insn "aarch64_sve_punpk<perm_hilo>_<mode>" +(define_insn "@aarch64_sve_punpk<perm_hilo>_<mode>" [(set (match_operand:<VWIDE> 0 "register_operand" "=Upa") (unspec:<VWIDE> [(match_operand:PRED_BHS 1 "register_operand" "Upa")] UNPACK_UNSIGNED))] "TARGET_SVE" "punpk<perm_hilo>\t%0.h, %1.b" ) + +;; ========================================================================= +;; == Vector partitioning +;; ========================================================================= + +;; ------------------------------------------------------------------------- +;; ---- [PRED] Unary partitioning +;; ------------------------------------------------------------------------- +;; Includes: +;; - BRKA +;; - BRKAS +;; - BRKB +;; - BRKBS +;; ------------------------------------------------------------------------- + +;; Note that unlike most other instructions that have both merging and +;; zeroing forms, these instructions don't operate elementwise and so +;; don't fit the IFN_COND model. +(define_insn "@aarch64_brk<brk_op>" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa, Upa") + (unspec:VNx16BI + [(match_operand:VNx16BI 1 "register_operand" "Upa, Upa") + (match_operand:VNx16BI 2 "register_operand" "Upa, Upa") + (match_operand:VNx16BI 3 "aarch64_simd_reg_or_zero" "Dz, 0")] + SVE_BRK_UNARY))] + "TARGET_SVE" + "@ + brk<brk_op>\t%0.b, %1/z, %2.b + brk<brk_op>\t%0.b, %1/m, %2.b" +) + +;; Same, but also producing a flags result. +(define_insn "*aarch64_brk<brk_op>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa, Upa") + (match_dup 1) + (match_operand:SI 4 "aarch64_sve_ptrue_flag") + (unspec:VNx16BI + [(match_dup 1) + (match_operand:VNx16BI 2 "register_operand" "Upa, Upa") + (match_operand:VNx16BI 3 "aarch64_simd_reg_or_zero" "Dz, 0")] + SVE_BRK_UNARY)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa, Upa") + (unspec:VNx16BI + [(match_dup 1) + (match_dup 2) + (match_dup 3)] + SVE_BRK_UNARY))] + "TARGET_SVE" + "@ + brk<brk_op>s\t%0.b, %1/z, %2.b + brk<brk_op>s\t%0.b, %1/m, %2.b" +) + +;; Same, but with only the flags result being interesting. +(define_insn "*aarch64_brk<brk_op>_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa, Upa") + (match_dup 1) + (match_operand:SI 4 "aarch64_sve_ptrue_flag") + (unspec:VNx16BI + [(match_dup 1) + (match_operand:VNx16BI 2 "register_operand" "Upa, Upa") + (match_operand:VNx16BI 3 "aarch64_simd_reg_or_zero" "Dz, 0")] + SVE_BRK_UNARY)] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa, Upa"))] + "TARGET_SVE" + "@ + brk<brk_op>s\t%0.b, %1/z, %2.b + brk<brk_op>s\t%0.b, %1/m, %2.b" +) + +;; ------------------------------------------------------------------------- +;; ---- [PRED] Binary partitioning +;; ------------------------------------------------------------------------- +;; Includes: +;; - BRKN +;; - BRKNS +;; - BRKPA +;; - BRKPAS +;; - BRKPB +;; - BRKPBS +;; ------------------------------------------------------------------------- + +;; Binary BRKs (BRKN, BRKPA, BRKPB). +(define_insn "@aarch64_brk<brk_op>" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (unspec:VNx16BI + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand:VNx16BI 2 "register_operand" "Upa") + (match_operand:VNx16BI 3 "register_operand" "<brk_reg_con>")] + SVE_BRK_BINARY))] + "TARGET_SVE" + "brk<brk_op>\t%0.b, %1/z, %2.b, %<brk_reg_opno>.b" +) + +;; Same, but also producing a flags result. +(define_insn "*aarch64_brk<brk_op>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (match_operand:SI 4 "aarch64_sve_ptrue_flag") + (unspec:VNx16BI + [(match_dup 1) + (match_operand:VNx16BI 2 "register_operand" "Upa") + (match_operand:VNx16BI 3 "register_operand" "<brk_reg_con>")] + SVE_BRK_BINARY)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (unspec:VNx16BI + [(match_dup 1) + (match_dup 2) + (match_dup 3)] + SVE_BRK_BINARY))] + "TARGET_SVE" + "brk<brk_op>s\t%0.b, %1/z, %2.b, %<brk_reg_opno>.b" +) + +;; Same, but with only the flags result being interesting. +(define_insn "*aarch64_brk<brk_op>_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_dup 1) + (match_operand:SI 4 "aarch64_sve_ptrue_flag") + (unspec:VNx16BI + [(match_dup 1) + (match_operand:VNx16BI 2 "register_operand" "Upa") + (match_operand:VNx16BI 3 "register_operand" "<brk_reg_con>")] + SVE_BRK_BINARY)] + UNSPEC_PTEST)) + (clobber (match_scratch:VNx16BI 0 "=Upa"))] + "TARGET_SVE" + "brk<brk_op>s\t%0.b, %1/z, %2.b, %<brk_reg_opno>.b" +) + +;; ------------------------------------------------------------------------- +;; ---- [PRED] Scalarization +;; ------------------------------------------------------------------------- +;; Includes: +;; - PFIRST +;; - PNEXT +;; ------------------------------------------------------------------------- + +(define_insn "@aarch64_sve_<sve_pred_op><mode>" + [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") + (unspec:PRED_ALL + [(match_operand:PRED_ALL 1 "register_operand" "Upa") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:PRED_ALL 3 "register_operand" "0")] + SVE_PITER)) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE && <max_elem_bits> >= <elem_bits>" + "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" +) + +;; Same, but also producing a flags result. +(define_insn_and_rewrite "*aarch64_sve_<sve_pred_op><mode>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 2) + (match_operand:SI 3 "aarch64_sve_ptrue_flag") + (unspec:PRED_ALL + [(match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (match_operand:PRED_ALL 6 "register_operand" "0")] + SVE_PITER)] + UNSPEC_PTEST)) + (set (match_operand:PRED_ALL 0 "register_operand" "=Upa") + (unspec:PRED_ALL + [(match_dup 4) + (match_dup 5) + (match_dup 6)] + SVE_PITER))] + "TARGET_SVE + && <max_elem_bits> >= <elem_bits> + && aarch64_sve_same_pred_for_ptest_p (&operands[2], &operands[4])" + "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" + "&& !rtx_equal_p (operands[2], operands[4])" + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } +) + +;; Same, but with only the flags result being interesting. +(define_insn_and_rewrite "*aarch64_sve_<sve_pred_op><mode>_ptest" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 2) + (match_operand:SI 3 "aarch64_sve_ptrue_flag") + (unspec:PRED_ALL + [(match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (match_operand:PRED_ALL 6 "register_operand" "0")] + SVE_PITER)] + UNSPEC_PTEST)) + (clobber (match_scratch:PRED_ALL 0 "=Upa"))] + "TARGET_SVE + && <max_elem_bits> >= <elem_bits> + && aarch64_sve_same_pred_for_ptest_p (&operands[2], &operands[4])" + "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" + "&& !rtx_equal_p (operands[2], operands[4])" + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } +) + +;; ========================================================================= +;; == Counting elements +;; ========================================================================= + +;; ------------------------------------------------------------------------- +;; ---- [INT] Count elements in a pattern (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - CNTB +;; - CNTD +;; - CNTH +;; - CNTW +;; ------------------------------------------------------------------------- + +;; Count the number of elements in an svpattern. Operand 1 is the pattern, +;; operand 2 is the number of elements that fit in a 128-bit block, and +;; operand 3 is a multiplier in the range [1, 16]. +;; +;; Note that this pattern isn't used for SV_ALL (but would work for that too). +(define_insn "aarch64_sve_cnt_pat" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (unspec:SI [(match_operand:DI 1 "const_int_operand") + (match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)))] + "TARGET_SVE" + { + return aarch64_output_sve_cnt_pat_immediate ("cnt", "%x0", operands + 1); + } +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Increment by the number of elements in a pattern (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - INC +;; - SQINC +;; - UQINC +;; ------------------------------------------------------------------------- + +;; Increment a DImode register by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:DI 0 "register_operand" "=r") + (ANY_PLUS:DI (zero_extend:DI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)) + (match_operand:DI_ONLY 1 "register_operand" "0")))] + "TARGET_SVE" + { + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%x0", + operands + 2); + } +) + +;; Increment an SImode register by the number of elements in an svpattern +;; using modular arithmetic. See aarch64_sve_cnt_pat for the counting +;; behavior. +(define_insn "*aarch64_sve_incsi_pat" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT) + (match_operand:SI 1 "register_operand" "0")))] + "TARGET_SVE" + { + return aarch64_output_sve_cnt_pat_immediate ("inc", "%x0", operands + 2); + } +) + +;; Increment an SImode register by the number of elements in an svpattern +;; using saturating arithmetic, extending the result to 64 bits. +;; +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:DI 0 "register_operand" "=r") + (<paired_extend>:DI + (SAT_PLUS:SI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT) + (match_operand:SI_ONLY 1 "register_operand" "0"))))] + "TARGET_SVE" + { + const char *registers = (<CODE> == SS_PLUS ? "%x0, %w0" : "%w0"); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", registers, + operands + 2); + } +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Increment by the number of elements in a pattern (vector) +;; ------------------------------------------------------------------------- +;; Includes: +;; - INC +;; - SQINC +;; - UQINC +;; ------------------------------------------------------------------------- + +;; Increment a vector of DIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx2DI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx2DI + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT))) + (match_operand:VNx2DI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Increment a vector of SIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx4SI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx4SI + (vec_duplicate:VNx4SI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)) + (match_operand:VNx4SI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Increment a vector of HIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_expand "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx8HI 0 "register_operand") + (ANY_PLUS:VNx8HI + (vec_duplicate:VNx8HI + (truncate:HI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT))) + (match_operand:VNx8HI_ONLY 1 "register_operand")))] + "TARGET_SVE" +) + +(define_insn "*aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx8HI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx8HI + (vec_duplicate:VNx8HI + (match_operator:HI 5 "subreg_lowpart_operator" + [(unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)])) + (match_operand:VNx8HI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Decrement by the number of elements in a pattern (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - DEC +;; - SQDEC +;; - UQDEC +;; ------------------------------------------------------------------------- + +;; Decrement a DImode register by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:DI 0 "register_operand" "=r") + (ANY_MINUS:DI (match_operand:DI_ONLY 1 "register_operand" "0") + (zero_extend:DI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT))))] + "TARGET_SVE" + { + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%x0", + operands + 2); + } +) + +;; Decrement an SImode register by the number of elements in an svpattern +;; using modular arithmetic. See aarch64_sve_cnt_pat for the counting +;; behavior. +(define_insn "*aarch64_sve_decsi_pat" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "0") + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)))] + "TARGET_SVE" + { + return aarch64_output_sve_cnt_pat_immediate ("dec", "%x0", operands + 2); + } +) + +;; Decrement an SImode register by the number of elements in an svpattern +;; using saturating arithmetic, extending the result to 64 bits. +;; +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:DI 0 "register_operand" "=r") + (<paired_extend>:DI + (SAT_MINUS:SI + (match_operand:SI_ONLY 1 "register_operand" "0") + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT))))] + "TARGET_SVE" + { + const char *registers = (<CODE> == SS_MINUS ? "%x0, %w0" : "%w0"); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", registers, + operands + 2); + } +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Decrement by the number of elements in a pattern (vector) +;; ------------------------------------------------------------------------- +;; Includes: +;; - DEC +;; - SQDEC +;; - UQDEC +;; ------------------------------------------------------------------------- + +;; Decrement a vector of DIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx2DI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx2DI + (match_operand:VNx2DI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)))))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Decrement a vector of SIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_insn "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx4SI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx4SI + (match_operand:VNx4SI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx4SI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT))))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Decrement a vector of HIs by the number of elements in an svpattern. +;; See aarch64_sve_cnt_pat for the counting behavior. +(define_expand "@aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx8HI 0 "register_operand") + (ANY_MINUS:VNx8HI + (match_operand:VNx8HI_ONLY 1 "register_operand") + (vec_duplicate:VNx8HI + (truncate:HI + (unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)))))] + "TARGET_SVE" +) + +(define_insn "*aarch64_sve_<inc_dec><mode>_pat" + [(set (match_operand:VNx8HI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx8HI + (match_operand:VNx8HI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx8HI + (match_operator:HI 5 "subreg_lowpart_operator" + [(unspec:SI [(match_operand:DI 2 "const_int_operand") + (match_operand:DI 3 "const_int_operand") + (match_operand:DI 4 "const_int_operand")] + UNSPEC_SVE_CNT_PAT)]))))] + "TARGET_SVE" + { + if (which_alternative == 1) + output_asm_insn ("movprfx\t%0, %1", operands); + return aarch64_output_sve_cnt_pat_immediate ("<inc_dec>", "%0.<Vetype>", + operands + 2); + } + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Count elements in a predicate (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - CNTP +;; ------------------------------------------------------------------------- + +;; Count the number of set bits in a predicate. Operand 3 is true if +;; operand 1 is known to be all-true. +(define_insn "@aarch64_pred_cntp<mode>" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (unspec:SI [(match_operand:PRED_ALL 1 "register_operand" "Upl") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:PRED_ALL 3 "register_operand" "Upa")] + UNSPEC_CNTP)))] + "TARGET_SVE" + "cntp\t%x0, %1, %3.<Vetype>") + +;; ------------------------------------------------------------------------- +;; ---- [INT] Increment by the number of elements in a predicate (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - INCP +;; - SQINCP +;; - UQINCP +;; ------------------------------------------------------------------------- + +;; Increment a DImode register by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand") + (ANY_PLUS:DI + (zero_extend:DI + (unspec:SI [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand")] + UNSPEC_CNTP)) + (match_operand:DI_ONLY 1 "register_operand")))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand" "=r") + (ANY_PLUS:DI + (zero_extend:DI + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP)) + (match_operand:DI_ONLY 1 "register_operand" "0")))] + "TARGET_SVE" + "<inc_dec>p\t%x0, %2.<PRED_ALL:Vetype>" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +;; Increment an SImode register by the number of set bits in a predicate +;; using modular arithmetic. See aarch64_sve_cntp for a description of +;; the operands. +(define_insn_and_rewrite "*aarch64_incsi<mode>_cntp" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP) + (match_operand:SI 1 "register_operand" "0")))] + "TARGET_SVE" + "incp\t%x0, %2.<Vetype>" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<MODE>mode); + } +) + +;; Increment an SImode register by the number of set bits in a predicate +;; using saturating arithmetic, extending the result to 64 bits. +;; +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand") + (<paired_extend>:DI + (SAT_PLUS:SI + (unspec:SI [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand")] + UNSPEC_CNTP) + (match_operand:SI_ONLY 1 "register_operand"))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand" "=r") + (<paired_extend>:DI + (SAT_PLUS:SI + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP) + (match_operand:SI_ONLY 1 "register_operand" "0"))))] + "TARGET_SVE" + { + if (<CODE> == SS_PLUS) + return "<inc_dec>p\t%x0, %2.<PRED_ALL:Vetype>, %w0"; + else + return "<inc_dec>p\t%w0, %2.<PRED_ALL:Vetype>"; + } + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Increment by the number of elements in a predicate (vector) +;; ------------------------------------------------------------------------- +;; Includes: +;; - INCP +;; - SQINCP +;; - UQINCP +;; ------------------------------------------------------------------------- + +;; Increment a vector of DIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx2DI 0 "register_operand") + (ANY_PLUS:VNx2DI + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP))) + (match_operand:VNx2DI_ONLY 1 "register_operand")))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx2DI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx2DI + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI + [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP))) + (match_operand:VNx2DI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.d, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.d, %2" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Increment a vector of SIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx4SI 0 "register_operand") + (ANY_PLUS:VNx4SI + (vec_duplicate:VNx4SI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP)) + (match_operand:VNx4SI_ONLY 1 "register_operand")))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx4SI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx4SI + (vec_duplicate:VNx4SI + (unspec:SI + [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP)) + (match_operand:VNx4SI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.s, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.s, %2" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Increment a vector of HIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx8HI 0 "register_operand") + (ANY_PLUS:VNx8HI + (vec_duplicate:VNx8HI + (truncate:HI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP))) + (match_operand:VNx8HI_ONLY 1 "register_operand")))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx8HI 0 "register_operand" "=w, ?&w") + (ANY_PLUS:VNx8HI + (vec_duplicate:VNx8HI + (match_operator:HI 3 "subreg_lowpart_operator" + [(unspec:SI + [(match_operand 4) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP)])) + (match_operand:VNx8HI_ONLY 1 "register_operand" "0, w")))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.h, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.h, %2" + "&& !CONSTANT_P (operands[4])" + { + operands[4] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Decrement by the number of elements in a predicate (scalar) +;; ------------------------------------------------------------------------- +;; Includes: +;; - DECP +;; - SQDECP +;; - UQDECP +;; ------------------------------------------------------------------------- + +;; Decrement a DImode register by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand") + (ANY_MINUS:DI + (match_operand:DI_ONLY 1 "register_operand") + (zero_extend:DI + (unspec:SI [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand")] + UNSPEC_CNTP))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><DI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand" "=r") + (ANY_MINUS:DI + (match_operand:DI_ONLY 1 "register_operand" "0") + (zero_extend:DI + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP))))] + "TARGET_SVE" + "<inc_dec>p\t%x0, %2.<PRED_ALL:Vetype>" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +;; Decrement an SImode register by the number of set bits in a predicate +;; using modular arithmetic. See aarch64_sve_cntp for a description of the +;; operands. +(define_insn_and_rewrite "*aarch64_decsi<mode>_cntp" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI + (match_operand:SI 1 "register_operand" "0") + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP)))] + "TARGET_SVE" + "decp\t%x0, %2.<Vetype>" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<MODE>mode); + } +) + +;; Decrement an SImode register by the number of set bits in a predicate +;; using saturating arithmetic, extending the result to 64 bits. +;; +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand") + (<paired_extend>:DI + (SAT_MINUS:SI + (match_operand:SI_ONLY 1 "register_operand") + (unspec:SI [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand")] + UNSPEC_CNTP))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><SI_ONLY:mode><PRED_ALL:mode>_cntp" + [(set (match_operand:DI 0 "register_operand" "=r") + (<paired_extend>:DI + (SAT_MINUS:SI + (match_operand:SI_ONLY 1 "register_operand" "0") + (unspec:SI [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:PRED_ALL 2 "register_operand" "Upa")] + UNSPEC_CNTP))))] + "TARGET_SVE" + { + if (<CODE> == SS_MINUS) + return "<inc_dec>p\t%x0, %2.<PRED_ALL:Vetype>, %w0"; + else + return "<inc_dec>p\t%w0, %2.<PRED_ALL:Vetype>"; + } + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<PRED_ALL:MODE>mode); + } +) + +;; ------------------------------------------------------------------------- +;; ---- [INT] Decrement by the number of elements in a predicate (vector) +;; ------------------------------------------------------------------------- +;; Includes: +;; - DECP +;; - SQDECP +;; - UQDECP +;; ------------------------------------------------------------------------- + +;; Decrement a vector of DIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx2DI 0 "register_operand") + (ANY_MINUS:VNx2DI + (match_operand:VNx2DI_ONLY 1 "register_operand") + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP)))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx2DI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx2DI + (match_operand:VNx2DI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx2DI + (zero_extend:DI + (unspec:SI + [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP)))))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.d, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.d, %2" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Decrement a vector of SIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx4SI 0 "register_operand") + (ANY_MINUS:VNx4SI + (match_operand:VNx4SI_ONLY 1 "register_operand") + (vec_duplicate:VNx4SI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx4SI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx4SI + (match_operand:VNx4SI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx4SI + (unspec:SI + [(match_operand 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP))))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.s, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.s, %2" + "&& !CONSTANT_P (operands[3])" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) + +;; Decrement a vector of HIs by the number of set bits in a predicate. +;; See aarch64_sve_cntp for a description of the operands. +(define_expand "@aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx8HI 0 "register_operand") + (ANY_MINUS:VNx8HI + (match_operand:VNx8HI_ONLY 1 "register_operand") + (vec_duplicate:VNx8HI + (truncate:HI + (unspec:SI + [(match_dup 3) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand")] + UNSPEC_CNTP)))))] + "TARGET_SVE" + { + operands[3] = CONSTM1_RTX (<VPRED>mode); + } +) + +(define_insn_and_rewrite "*aarch64_sve_<inc_dec><mode>_cntp" + [(set (match_operand:VNx8HI 0 "register_operand" "=w, ?&w") + (ANY_MINUS:VNx8HI + (match_operand:VNx8HI_ONLY 1 "register_operand" "0, w") + (vec_duplicate:VNx8HI + (match_operator:HI 3 "subreg_lowpart_operator" + [(unspec:SI + [(match_operand 4) + (const_int SVE_KNOWN_PTRUE) + (match_operand:<VPRED> 2 "register_operand" "Upa, Upa")] + UNSPEC_CNTP)]))))] + "TARGET_SVE" + "@ + <inc_dec>p\t%0.h, %2 + movprfx\t%0, %1\;<inc_dec>p\t%0.h, %2" + "&& !CONSTANT_P (operands[4])" + { + operands[4] = CONSTM1_RTX (<VPRED>mode); + } + [(set_attr "movprfx" "*,yes")] +) diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 3b4290a..9cafef4 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1744,7 +1744,7 @@ aarch64_get_mask_mode (poly_uint64 nunits, poly_uint64 nbytes) /* Return the SVE vector mode that has NUNITS elements of mode INNER_MODE. */ -static opt_machine_mode +opt_machine_mode aarch64_sve_data_mode (scalar_mode inner_mode, poly_uint64 nunits) { enum mode_class mclass = (is_a <scalar_float_mode> (inner_mode) @@ -1772,7 +1772,7 @@ aarch64_sve_element_int_mode (machine_mode mode) Unlike mode_for_int_vector, this can handle the case in which MODE is a predicate (and thus has a different total size). */ -static machine_mode +machine_mode aarch64_sve_int_mode (machine_mode mode) { scalar_int_mode int_mode = aarch64_sve_element_int_mode (mode); @@ -2764,6 +2764,27 @@ aarch64_widest_sve_pred_elt_size (rtx_vector_builder &builder) return mask & -mask; } +/* If VNx16BImode rtx X is a canonical PTRUE for a predicate mode, + return that predicate mode, otherwise return opt_machine_mode (). */ + +opt_machine_mode +aarch64_ptrue_all_mode (rtx x) +{ + gcc_assert (GET_MODE (x) == VNx16BImode); + if (GET_CODE (x) != CONST_VECTOR + || !CONST_VECTOR_DUPLICATE_P (x) + || !CONST_INT_P (CONST_VECTOR_ENCODED_ELT (x, 0)) + || INTVAL (CONST_VECTOR_ENCODED_ELT (x, 0)) == 0) + return opt_machine_mode (); + + unsigned int nelts = const_vector_encoded_nelts (x); + for (unsigned int i = 1; i < nelts; ++i) + if (CONST_VECTOR_ENCODED_ELT (x, i) != const0_rtx) + return opt_machine_mode (); + + return aarch64_sve_pred_mode (nelts); +} + /* BUILDER is a predicate constant of mode VNx16BI. Consider the value that the constant would have with predicate element size ELT_SIZE (ignoring the upper bits in each element) and return: @@ -2948,7 +2969,7 @@ aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp, the corresponding SVE predicate mode. Use TARGET for the result if it's nonnull and convenient. */ -static rtx +rtx aarch64_convert_sve_data_to_pred (rtx target, machine_mode mode, rtx src) { machine_mode src_mode = GET_MODE (src); @@ -2956,6 +2977,78 @@ aarch64_convert_sve_data_to_pred (rtx target, machine_mode mode, rtx src) src, CONST0_RTX (src_mode)); } +/* Return the assembly token for svprfop value PRFOP. */ + +static const char * +svprfop_token (enum aarch64_svprfop prfop) +{ + switch (prfop) + { +#define CASE(UPPER, LOWER, VALUE) case AARCH64_SV_##UPPER: return #LOWER; + AARCH64_FOR_SVPRFOP (CASE) +#undef CASE + case AARCH64_NUM_SVPRFOPS: + break; + } + gcc_unreachable (); +} + +/* Return the assembly string for an SVE prefetch operation with + mnemonic MNEMONIC, given that PRFOP_RTX is the prefetch operation + and that SUFFIX is the format for the remaining operands. */ + +char * +aarch64_output_sve_prefetch (const char *mnemonic, rtx prfop_rtx, + const char *suffix) +{ + static char buffer[128]; + aarch64_svprfop prfop = (aarch64_svprfop) INTVAL (prfop_rtx); + unsigned int written = snprintf (buffer, sizeof (buffer), "%s\t%s, %s", + mnemonic, svprfop_token (prfop), suffix); + gcc_assert (written < sizeof (buffer)); + return buffer; +} + +/* Check whether we can calculate the number of elements in PATTERN + at compile time, given that there are NELTS_PER_VQ elements per + 128-bit block. Return the value if so, otherwise return -1. */ + +HOST_WIDE_INT +aarch64_fold_sve_cnt_pat (aarch64_svpattern pattern, unsigned int nelts_per_vq) +{ + unsigned int vl, const_vg; + if (pattern >= AARCH64_SV_VL1 && pattern <= AARCH64_SV_VL8) + vl = 1 + (pattern - AARCH64_SV_VL1); + else if (pattern >= AARCH64_SV_VL16 && pattern <= AARCH64_SV_VL256) + vl = 16 << (pattern - AARCH64_SV_VL16); + else if (aarch64_sve_vg.is_constant (&const_vg)) + { + /* There are two vector granules per quadword. */ + unsigned int nelts = (const_vg / 2) * nelts_per_vq; + switch (pattern) + { + case AARCH64_SV_POW2: return 1 << floor_log2 (nelts); + case AARCH64_SV_MUL4: return nelts & -4; + case AARCH64_SV_MUL3: return (nelts / 3) * 3; + case AARCH64_SV_ALL: return nelts; + default: gcc_unreachable (); + } + } + else + return -1; + + /* There are two vector granules per quadword. */ + poly_uint64 nelts_all = exact_div (aarch64_sve_vg, 2) * nelts_per_vq; + if (known_le (vl, nelts_all)) + return vl; + + /* Requesting more elements than are available results in a PFALSE. */ + if (known_gt (vl, nelts_all)) + return 0; + + return -1; +} + /* Return true if we can move VALUE into a register using a single CNT[BHWD] instruction. */ @@ -3038,6 +3131,24 @@ aarch64_output_sve_cnt_immediate (const char *prefix, const char *operands, value.coeffs[1], 0); } +/* Return the asm string for an instruction with a CNT-like vector size + operand (a vector pattern followed by a multiplier in the range [1, 16]). + PREFIX is the mnemonic without the size suffix and OPERANDS is the + first part of the operands template (the part that comes before the + vector size itself). CNT_PAT[0..2] are the operands of the + UNSPEC_SVE_CNT_PAT; see aarch64_sve_cnt_pat for details. */ + +char * +aarch64_output_sve_cnt_pat_immediate (const char *prefix, + const char *operands, rtx *cnt_pat) +{ + aarch64_svpattern pattern = (aarch64_svpattern) INTVAL (cnt_pat[0]); + unsigned int nelts_per_vq = INTVAL (cnt_pat[1]); + unsigned int factor = INTVAL (cnt_pat[2]) * nelts_per_vq; + return aarch64_output_sve_cnt_immediate (prefix, operands, pattern, + factor, nelts_per_vq); +} + /* Return true if we can add X using a single SVE INC or DEC instruction. */ bool @@ -3904,7 +4015,8 @@ aarch64_sve_move_pred_via_while (rtx target, machine_mode mode, { rtx limit = force_reg (DImode, gen_int_mode (vl, DImode)); target = aarch64_target_reg (target, mode); - emit_insn (gen_while_ult (DImode, mode, target, const0_rtx, limit)); + emit_insn (gen_while (UNSPEC_WHILE_LO, DImode, mode, + target, const0_rtx, limit)); return target; } @@ -4416,7 +4528,7 @@ aarch64_maybe_expand_sve_subreg_move (rtx dest, rtx src) attributes. Unlike gen_lowpart, this doesn't care whether the mode change is valid. */ -static rtx +rtx aarch64_replace_reg_mode (rtx x, machine_mode mode) { if (GET_MODE (x) == mode) @@ -11718,6 +11830,7 @@ static void aarch64_init_builtins () { aarch64_general_init_builtins (); + aarch64_sve::init_builtins (); } /* Implement TARGET_FOLD_BUILTIN. */ @@ -11731,6 +11844,9 @@ aarch64_fold_builtin (tree fndecl, int nargs, tree *args, bool) { case AARCH64_BUILTIN_GENERAL: return aarch64_general_fold_builtin (subcode, type, nargs, args); + + case AARCH64_BUILTIN_SVE: + return NULL_TREE; } gcc_unreachable (); } @@ -11749,6 +11865,10 @@ aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi) case AARCH64_BUILTIN_GENERAL: new_stmt = aarch64_general_gimple_fold_builtin (subcode, stmt); break; + + case AARCH64_BUILTIN_SVE: + new_stmt = aarch64_sve::gimple_fold_builtin (subcode, gsi, stmt); + break; } if (!new_stmt) @@ -11769,6 +11889,9 @@ aarch64_expand_builtin (tree exp, rtx target, rtx, machine_mode, int ignore) { case AARCH64_BUILTIN_GENERAL: return aarch64_general_expand_builtin (subcode, exp, target, ignore); + + case AARCH64_BUILTIN_SVE: + return aarch64_sve::expand_builtin (subcode, exp, target); } gcc_unreachable (); } @@ -11782,6 +11905,9 @@ aarch64_builtin_decl (unsigned int code, bool initialize_p) { case AARCH64_BUILTIN_GENERAL: return aarch64_general_builtin_decl (subcode, initialize_p); + + case AARCH64_BUILTIN_SVE: + return aarch64_sve::builtin_decl (subcode, initialize_p); } gcc_unreachable (); } @@ -11815,6 +11941,9 @@ aarch64_builtin_reciprocal (tree fndecl) { case AARCH64_BUILTIN_GENERAL: return aarch64_general_builtin_rsqrt (subcode); + + case AARCH64_BUILTIN_SVE: + return NULL_TREE; } gcc_unreachable (); } @@ -15259,7 +15388,12 @@ aarch64_mangle_type (const_tree type) /* Mangle AArch64-specific internal types. TYPE_NAME is non-NULL_TREE for builtin types. */ if (TYPE_NAME (type) != NULL) - return aarch64_general_mangle_builtin_type (type); + { + const char *res; + if ((res = aarch64_general_mangle_builtin_type (type)) + || (res = aarch64_sve::mangle_builtin_type (type))) + return res; + } /* Use the default mangling. */ return NULL; @@ -15417,6 +15551,27 @@ aarch64_sve_arith_immediate_p (rtx x, bool negate_p) return IN_RANGE (val, 0, 0xff00); } +/* Return true if X is a valid immediate for the SVE SQADD and SQSUB + instructions. Negate X first if NEGATE_P is true. */ + +bool +aarch64_sve_sqadd_sqsub_immediate_p (rtx x, bool negate_p) +{ + rtx elt; + + if (!const_vec_duplicate_p (x, &elt) + || !CONST_INT_P (elt)) + return false; + + if (!aarch64_sve_arith_immediate_p (x, negate_p)) + return false; + + /* After the optional negation, the immediate must be nonnegative. + E.g. a saturating add of -127 must be done via SQSUB Zn.B, Zn.B, #127 + instead of SQADD Zn.B, Zn.B, #129. */ + return negate_p == (INTVAL (elt) < 0); +} + /* Return true if X is a valid immediate operand for an SVE logical instruction such as AND. */ @@ -15649,12 +15804,45 @@ aarch64_sve_valid_immediate (unsigned HOST_WIDE_INT val64, return false; } +/* Return true if X is an UNSPEC_PTRUE constant of the form: + + (const (unspec [PATTERN ZERO] UNSPEC_PTRUE)) + + where PATTERN is the svpattern as a CONST_INT and where ZERO + is a zero constant of the required PTRUE mode (which can have + fewer elements than X's mode, if zero bits are significant). + + If so, and if INFO is nonnull, describe the immediate in INFO. */ +bool +aarch64_sve_ptrue_svpattern_p (rtx x, struct simd_immediate_info *info) +{ + if (GET_CODE (x) != CONST) + return false; + + x = XEXP (x, 0); + if (GET_CODE (x) != UNSPEC || XINT (x, 1) != UNSPEC_PTRUE) + return false; + + if (info) + { + aarch64_svpattern pattern + = (aarch64_svpattern) INTVAL (XVECEXP (x, 0, 0)); + machine_mode pred_mode = GET_MODE (XVECEXP (x, 0, 1)); + scalar_int_mode int_mode = aarch64_sve_element_int_mode (pred_mode); + *info = simd_immediate_info (int_mode, pattern); + } + return true; +} + /* Return true if X is a valid SVE predicate. If INFO is nonnull, use it to describe valid immediates. */ static bool aarch64_sve_pred_valid_immediate (rtx x, simd_immediate_info *info) { + if (aarch64_sve_ptrue_svpattern_p (x, info)) + return true; + if (x == CONST0_RTX (GET_MODE (x))) { if (info) @@ -16063,6 +16251,35 @@ aarch64_sve_ld1rq_operand_p (rtx op) return false; } +/* Return true if OP is a valid MEM operand for an SVE LDFF1 instruction. */ +bool +aarch64_sve_ldff1_operand_p (rtx op) +{ + if (!MEM_P (op)) + return false; + + struct aarch64_address_info addr; + if (!aarch64_classify_address (&addr, XEXP (op, 0), GET_MODE (op), false)) + return false; + + if (addr.type == ADDRESS_REG_IMM) + return known_eq (addr.const_offset, 0); + + return addr.type == ADDRESS_REG_REG; +} + +/* Return true if OP is a valid MEM operand for an SVE LDNF1 instruction. */ +bool +aarch64_sve_ldnf1_operand_p (rtx op) +{ + struct aarch64_address_info addr; + + return (MEM_P (op) + && aarch64_classify_address (&addr, XEXP (op, 0), + GET_MODE (op), false) + && addr.type == ADDRESS_REG_IMM); +} + /* Return true if OP is a valid MEM operand for an SVE LDR instruction. The conditions for STR are the same. */ bool @@ -16076,6 +16293,21 @@ aarch64_sve_ldr_operand_p (rtx op) && addr.type == ADDRESS_REG_IMM); } +/* Return true if OP is a valid address for an SVE PRF[BHWD] instruction, + addressing memory of mode MODE. */ +bool +aarch64_sve_prefetch_operand_p (rtx op, machine_mode mode) +{ + struct aarch64_address_info addr; + if (!aarch64_classify_address (&addr, op, mode, false)) + return false; + + if (addr.type == ADDRESS_REG_IMM) + return known_eq (addr.const_offset, 0); + + return addr.type == ADDRESS_REG_REG; +} + /* Return true if OP is a valid MEM operand for an SVE_STRUCT mode. We need to be able to access the individual pieces, so the range is different from LD[234] and ST[234]. */ @@ -17704,6 +17936,25 @@ aarch64_output_sve_mov_immediate (rtx const_vector) return templ; } +/* Return the asm template for a PTRUES. CONST_UNSPEC is the + aarch64_sve_ptrue_svpattern_immediate that describes the predicate + pattern. */ + +char * +aarch64_output_sve_ptrues (rtx const_unspec) +{ + static char templ[40]; + + struct simd_immediate_info info; + bool is_valid = aarch64_simd_valid_immediate (const_unspec, &info); + gcc_assert (is_valid && info.insn == simd_immediate_info::PTRUE); + + char element_char = sizetochar (GET_MODE_BITSIZE (info.elt_mode)); + snprintf (templ, sizeof (templ), "ptrues\t%%0.%c, %s", element_char, + svpattern_token (info.u.pattern)); + return templ; +} + /* Split operands into moves from op[1] + op[2] into op[0]. */ void diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 3778109..d1fe173 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -226,21 +226,29 @@ UNSPEC_XPACLRI UNSPEC_LD1_SVE UNSPEC_ST1_SVE + UNSPEC_LDNT1_SVE + UNSPEC_STNT1_SVE UNSPEC_LD1RQ UNSPEC_LD1_GATHER + UNSPEC_LDFF1_GATHER UNSPEC_ST1_SCATTER UNSPEC_PRED_X UNSPEC_PRED_Z UNSPEC_PTEST + UNSPEC_PTRUE UNSPEC_UNPACKSHI UNSPEC_UNPACKUHI UNSPEC_UNPACKSLO UNSPEC_UNPACKULO UNSPEC_PACK + UNSPEC_WHILE_LE UNSPEC_WHILE_LO + UNSPEC_WHILE_LS + UNSPEC_WHILE_LT UNSPEC_LDN UNSPEC_STN UNSPEC_INSR + UNSPEC_CLASTA UNSPEC_CLASTB UNSPEC_FADDA UNSPEC_REV_SUBREG @@ -248,6 +256,18 @@ UNSPEC_SPECULATION_TRACKER 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 ]) (define_c_enum "unspecv" [ diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h new file mode 100644 index 0000000..b76d321 --- /dev/null +++ b/gcc/config/aarch64/arm_sve.h @@ -0,0 +1,36 @@ +/* AArch64 SVE intrinsics include file. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _ARM_SVE_H_ +#define _ARM_SVE_H_ + +#include <stdint.h> + +typedef __fp16 float16_t; +typedef float float32_t; +typedef double float64_t; + +#pragma GCC aarch64 "arm_sve.h" + +#endif diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md index 9326bec..d0c3dd5 100644 --- a/gcc/config/aarch64/constraints.md +++ b/gcc/config/aarch64/constraints.md @@ -257,6 +257,38 @@ true, ADDR_QUERY_LDP_STP_N)"))) +(define_address_constraint "UPb" + "@internal + An address valid for SVE PRFB instructions." + (match_test "aarch64_sve_prefetch_operand_p (op, VNx16QImode)")) + +(define_address_constraint "UPd" + "@internal + An address valid for SVE PRFD instructions." + (match_test "aarch64_sve_prefetch_operand_p (op, VNx2DImode)")) + +(define_address_constraint "UPh" + "@internal + An address valid for SVE PRFH instructions." + (match_test "aarch64_sve_prefetch_operand_p (op, VNx8HImode)")) + +(define_address_constraint "UPw" + "@internal + An address valid for SVE PRFW instructions." + (match_test "aarch64_sve_prefetch_operand_p (op, VNx4SImode)")) + +(define_memory_constraint "Utf" + "@internal + An address valid for SVE LDFF1 instructions." + (and (match_code "mem") + (match_test "aarch64_sve_ldff1_operand_p (op)"))) + +(define_memory_constraint "Utn" + "@internal + An address valid for SVE LDNF1 instructions." + (and (match_code "mem") + (match_test "aarch64_sve_ldnf1_operand_p (op)"))) + (define_memory_constraint "Utr" "@internal An address valid for SVE LDR and STR instructions (as distinct from @@ -395,6 +427,30 @@ An address valid for a prefetch instruction." (match_test "aarch64_address_valid_for_prefetch_p (op, true)")) +(define_constraint "vgb" + "@internal + A constraint that matches an immediate offset valid for SVE LD1B + gather instructions." + (match_operand 0 "aarch64_sve_gather_immediate_b")) + +(define_constraint "vgd" + "@internal + A constraint that matches an immediate offset valid for SVE LD1D + gather instructions." + (match_operand 0 "aarch64_sve_gather_immediate_d")) + +(define_constraint "vgh" + "@internal + A constraint that matches an immediate offset valid for SVE LD1H + gather instructions." + (match_operand 0 "aarch64_sve_gather_immediate_h")) + +(define_constraint "vgw" + "@internal + A constraint that matches an immediate offset valid for SVE LD1W + gather instructions." + (match_operand 0 "aarch64_sve_gather_immediate_w")) + (define_constraint "vsa" "@internal A constraint that matches an immediate operand valid for SVE @@ -437,6 +493,18 @@ is valid for SVE SUB instructions." (match_operand 0 "aarch64_sve_sub_arith_immediate")) +(define_constraint "vsQ" + "@internal + Like vsa, but additionally check that the immediate is nonnegative + when interpreted as a signed value." + (match_operand 0 "aarch64_sve_qadd_immediate")) + +(define_constraint "vsS" + "@internal + Like vsn, but additionally check that the immediate is negative + when interpreted as a signed value." + (match_operand 0 "aarch64_sve_qsub_immediate")) + (define_constraint "vsl" "@internal A constraint that matches an immediate operand valid for SVE logical diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index f879fad..d0ede24 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -35,6 +35,10 @@ ;; Iterator for QI and HI modes (define_mode_iterator SHORT [QI HI]) +;; Iterators for single modes, for "@" patterns. +(define_mode_iterator SI_ONLY [SI]) +(define_mode_iterator DI_ONLY [DI]) + ;; Iterator for all integer modes (up to 64-bit) (define_mode_iterator ALLI [QI HI SI DI]) @@ -285,7 +289,9 @@ VNx8HF VNx4SF VNx2DF]) ;; Iterators for single modes, for "@" patterns. +(define_mode_iterator VNx8HI_ONLY [VNx8HI]) (define_mode_iterator VNx4SI_ONLY [VNx4SI]) +(define_mode_iterator VNx2DI_ONLY [VNx2DI]) (define_mode_iterator VNx2DF_ONLY [VNx2DF]) ;; All SVE vector structure modes. @@ -335,12 +341,33 @@ ;; All SVE floating-point vector modes. (define_mode_iterator SVE_F [VNx8HF VNx4SF VNx2DF]) +;; All partial SVE modes. +(define_mode_iterator SVE_PARTIAL [VNx2QI + VNx4QI VNx2HI + VNx8QI VNx4HI VNx2SI]) + +;; Modes involved in extending or truncating SVE data, for 8 elements per +;; 128-bit block. +(define_mode_iterator VNx8_NARROW [VNx8QI]) +(define_mode_iterator VNx8_WIDE [VNx8HI]) + +;; ...same for 4 elements per 128-bit block. +(define_mode_iterator VNx4_NARROW [VNx4QI VNx4HI]) +(define_mode_iterator VNx4_WIDE [VNx4SI]) + +;; ...same for 2 elements per 128-bit block. +(define_mode_iterator VNx2_NARROW [VNx2QI VNx2HI VNx2SI]) +(define_mode_iterator VNx2_WIDE [VNx2DI]) + ;; All SVE predicate modes. (define_mode_iterator PRED_ALL [VNx16BI VNx8BI VNx4BI VNx2BI]) ;; SVE predicate modes that control 8-bit, 16-bit or 32-bit elements. (define_mode_iterator PRED_BHS [VNx16BI VNx8BI VNx4BI]) +;; SVE predicate modes that control 16-bit, 32-bit or 64-bit elements. +(define_mode_iterator PRED_HSD [VNx8BI VNx4BI VNx2BI]) + ;; ------------------------------------------------------------------ ;; Unspec enumerations for Advance SIMD. These could well go into ;; aarch64.md but for their use in int_iterators here. @@ -483,7 +510,18 @@ UNSPEC_FMLSL ; Used in aarch64-simd.md. UNSPEC_FMLAL2 ; Used in aarch64-simd.md. UNSPEC_FMLSL2 ; Used in aarch64-simd.md. + UNSPEC_ADR ; Used in aarch64-sve.md. UNSPEC_SEL ; Used in aarch64-sve.md. + UNSPEC_BRKA ; Used in aarch64-sve.md. + UNSPEC_BRKB ; Used in aarch64-sve.md. + UNSPEC_BRKN ; Used in aarch64-sve.md. + UNSPEC_BRKPA ; Used in aarch64-sve.md. + UNSPEC_BRKPB ; Used in aarch64-sve.md. + UNSPEC_PFIRST ; Used in aarch64-sve.md. + UNSPEC_PNEXT ; Used in aarch64-sve.md. + UNSPEC_CNTP ; Used in aarch64-sve.md. + UNSPEC_SADDV ; Used in aarch64-sve.md. + UNSPEC_UADDV ; Used in aarch64-sve.md. UNSPEC_ANDV ; Used in aarch64-sve.md. UNSPEC_IORV ; Used in aarch64-sve.md. UNSPEC_XORV ; Used in aarch64-sve.md. @@ -495,11 +533,33 @@ UNSPEC_REVW ; Used in aarch64-sve.md. UNSPEC_SMUL_HIGHPART ; Used in aarch64-sve.md. UNSPEC_UMUL_HIGHPART ; Used in aarch64-sve.md. + UNSPEC_FMLA ; Used in aarch64-sve.md. + UNSPEC_FMLS ; Used in aarch64-sve.md. + UNSPEC_FEXPA ; Used in aarch64-sve.md. + UNSPEC_FTMAD ; Used in aarch64-sve.md. + UNSPEC_FTSMUL ; Used in aarch64-sve.md. + UNSPEC_FTSSEL ; Used in aarch64-sve.md. + UNSPEC_COND_CMPEQ_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPGE_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPGT_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPHI_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPHS_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPLE_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPLO_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPLS_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPLT_WIDE ; Used in aarch64-sve.md. + UNSPEC_COND_CMPNE_WIDE ; Used in aarch64-sve.md. UNSPEC_COND_FABS ; Used in aarch64-sve.md. UNSPEC_COND_FADD ; Used in aarch64-sve.md. + UNSPEC_COND_FCADD90 ; Used in aarch64-sve.md. + UNSPEC_COND_FCADD270 ; Used in aarch64-sve.md. UNSPEC_COND_FCMEQ ; Used in aarch64-sve.md. UNSPEC_COND_FCMGE ; Used in aarch64-sve.md. UNSPEC_COND_FCMGT ; Used in aarch64-sve.md. + UNSPEC_COND_FCMLA ; Used in aarch64-sve.md. + UNSPEC_COND_FCMLA90 ; Used in aarch64-sve.md. + UNSPEC_COND_FCMLA180 ; Used in aarch64-sve.md. + UNSPEC_COND_FCMLA270 ; Used in aarch64-sve.md. UNSPEC_COND_FCMLE ; Used in aarch64-sve.md. UNSPEC_COND_FCMLT ; Used in aarch64-sve.md. UNSPEC_COND_FCMNE ; Used in aarch64-sve.md. @@ -508,14 +568,18 @@ UNSPEC_COND_FCVTZS ; Used in aarch64-sve.md. UNSPEC_COND_FCVTZU ; Used in aarch64-sve.md. UNSPEC_COND_FDIV ; Used in aarch64-sve.md. + UNSPEC_COND_FMAX ; Used in aarch64-sve.md. UNSPEC_COND_FMAXNM ; Used in aarch64-sve.md. + UNSPEC_COND_FMIN ; Used in aarch64-sve.md. UNSPEC_COND_FMINNM ; Used in aarch64-sve.md. UNSPEC_COND_FMLA ; Used in aarch64-sve.md. UNSPEC_COND_FMLS ; Used in aarch64-sve.md. UNSPEC_COND_FMUL ; Used in aarch64-sve.md. + UNSPEC_COND_FMULX ; Used in aarch64-sve.md. UNSPEC_COND_FNEG ; Used in aarch64-sve.md. UNSPEC_COND_FNMLA ; Used in aarch64-sve.md. UNSPEC_COND_FNMLS ; Used in aarch64-sve.md. + UNSPEC_COND_FRECPX ; Used in aarch64-sve.md. UNSPEC_COND_FRINTA ; Used in aarch64-sve.md. UNSPEC_COND_FRINTI ; Used in aarch64-sve.md. UNSPEC_COND_FRINTM ; Used in aarch64-sve.md. @@ -523,11 +587,18 @@ UNSPEC_COND_FRINTP ; Used in aarch64-sve.md. UNSPEC_COND_FRINTX ; Used in aarch64-sve.md. UNSPEC_COND_FRINTZ ; Used in aarch64-sve.md. + UNSPEC_COND_FSCALE ; Used in aarch64-sve.md. UNSPEC_COND_FSQRT ; Used in aarch64-sve.md. UNSPEC_COND_FSUB ; Used in aarch64-sve.md. UNSPEC_COND_SCVTF ; Used in aarch64-sve.md. UNSPEC_COND_UCVTF ; Used in aarch64-sve.md. + UNSPEC_LASTA ; Used in aarch64-sve.md. UNSPEC_LASTB ; Used in aarch64-sve.md. + UNSPEC_ASHIFT_WIDE ; Used in aarch64-sve.md. + UNSPEC_ASHIFTRT_WIDE ; Used in aarch64-sve.md. + UNSPEC_LSHIFTRT_WIDE ; Used in aarch64-sve.md. + UNSPEC_LDFF1 ; Used in aarch64-sve.md. + UNSPEC_LDNF1 ; Used in aarch64-sve.md. UNSPEC_FCADD90 ; Used in aarch64-simd.md. UNSPEC_FCADD270 ; Used in aarch64-simd.md. UNSPEC_FCMLA ; Used in aarch64-simd.md. @@ -723,9 +794,11 @@ (define_mode_attr Vetype_fourth [(VNx4SI "b") (VNx2DI "h")]) ;; Equivalent of "size" for a vector element. -(define_mode_attr Vesize [(VNx16QI "b") - (VNx8HI "h") (VNx8HF "h") - (VNx4SI "w") (VNx4SF "w") +(define_mode_attr Vesize [(VNx16QI "b") (VNx8QI "b") + (VNx4QI "b") (VNx2QI "b") + (VNx8HI "h") (VNx4HI "h") + (VNx2HI "h") (VNx8HF "h") + (VNx4SI "w") (VNx2SI "w") (VNx4SF "w") (VNx2DI "d") (VNx2DF "d") (VNx32QI "b") (VNx48QI "b") (VNx64QI "b") (VNx16HI "h") (VNx24HI "h") (VNx32HI "h") @@ -1221,6 +1294,26 @@ (define_mode_attr data_bytes [(VNx16BI "1") (VNx8BI "2") (VNx4BI "4") (VNx2BI "8")]) +;; Two-nybble mask for partial vector modes: nunits, byte size. +(define_mode_attr self_mask [(VNx8QI "0x81") + (VNx4QI "0x41") + (VNx2QI "0x21") + (VNx4HI "0x42") + (VNx2HI "0x22") + (VNx2SI "0x24")]) + +;; For full vector modes, the mask of narrower modes, encoded as above. +(define_mode_attr narrower_mask [(VNx8HI "0x81") + (VNx4SI "0x43") + (VNx2DI "0x27")]) + +;; The constraint to use for an SVE [SU]DOT, FMUL, FMLA or FMLS lane index. +(define_mode_attr sve_lane_con [(VNx4SI "y") (VNx2DI "x") + (VNx8HF "y") (VNx4SF "y") (VNx2DF "x")]) + +;; The constraint to use for an SVE FCMLA lane index. +(define_mode_attr sve_lane_pair_con [(VNx8HF "y") (VNx4SF "x")]) + ;; ------------------------------------------------------------------- ;; Code Iterators ;; ------------------------------------------------------------------- @@ -1291,6 +1384,21 @@ ;; Code iterator for signed variants of vector saturating binary ops. (define_code_iterator SBINQOPS [ss_plus ss_minus]) +;; Code iterator for unsigned variants of vector saturating binary ops. +(define_code_iterator UBINQOPS [us_plus us_minus]) + +;; Modular and saturating addition. +(define_code_iterator ANY_PLUS [plus ss_plus us_plus]) + +;; Saturating addition. +(define_code_iterator SAT_PLUS [ss_plus us_plus]) + +;; Modular and saturating subtraction. +(define_code_iterator ANY_MINUS [minus ss_minus us_minus]) + +;; Saturating subtraction. +(define_code_iterator SAT_MINUS [ss_minus us_minus]) + ;; Comparison operators for <F>CM. (define_code_iterator COMPARISONS [lt le eq ge gt]) @@ -1441,6 +1549,15 @@ (smax "s") (umax "u") (smin "s") (umin "u")]) +;; "s" for signed ops, empty for unsigned ones. +(define_code_attr s [(sign_extend "s") (zero_extend "")]) + +;; Map signed/unsigned ops to the corresponding extension. +(define_code_attr paired_extend [(ss_plus "sign_extend") + (us_plus "zero_extend") + (ss_minus "sign_extend") + (us_minus "zero_extend")]) + ;; Whether a shift is left or right. (define_code_attr lr [(ashift "l") (ashiftrt "r") (lshiftrt "r")]) @@ -1574,6 +1691,9 @@ (ior "register_operand") (xor "register_operand")]) +(define_code_attr inc_dec [(minus "dec") (ss_minus "sqdec") (us_minus "uqdec") + (plus "inc") (ss_plus "sqinc") (us_plus "uqinc")]) + ;; ------------------------------------------------------------------- ;; Int Iterators. ;; ------------------------------------------------------------------- @@ -1593,6 +1713,8 @@ (define_int_iterator FMAXMINV [UNSPEC_FMAXV UNSPEC_FMINV UNSPEC_FMAXNMV UNSPEC_FMINNMV]) +(define_int_iterator SVE_INT_ADDV [UNSPEC_SADDV UNSPEC_UADDV]) + (define_int_iterator LOGICALF [UNSPEC_ANDF UNSPEC_IORF UNSPEC_XORF]) (define_int_iterator HADDSUB [UNSPEC_SHADD UNSPEC_UHADD @@ -1714,7 +1836,20 @@ (define_int_iterator MUL_HIGHPART [UNSPEC_SMUL_HIGHPART UNSPEC_UMUL_HIGHPART]) -(define_int_iterator SVE_INT_UNARY [UNSPEC_REVB UNSPEC_REVH UNSPEC_REVW]) +(define_int_iterator CLAST [UNSPEC_CLASTA UNSPEC_CLASTB]) + +(define_int_iterator LAST [UNSPEC_LASTA UNSPEC_LASTB]) + +(define_int_iterator SVE_INT_UNARY [UNSPEC_RBIT UNSPEC_REVB + UNSPEC_REVH UNSPEC_REVW]) + +(define_int_iterator SVE_FP_UNARY [UNSPEC_FRECPE UNSPEC_RSQRTE]) + +(define_int_iterator SVE_FP_UNARY_INT [UNSPEC_FEXPA]) + +(define_int_iterator SVE_FP_BINARY [UNSPEC_FRECPS UNSPEC_RSQRTS]) + +(define_int_iterator SVE_FP_BINARY_INT [UNSPEC_FTSMUL UNSPEC_FTSSEL]) (define_int_iterator SVE_INT_REDUCTION [UNSPEC_ANDV UNSPEC_IORV @@ -1732,6 +1867,7 @@ (define_int_iterator SVE_COND_FP_UNARY [UNSPEC_COND_FABS UNSPEC_COND_FNEG + UNSPEC_COND_FRECPX UNSPEC_COND_FRINTA UNSPEC_COND_FRINTI UNSPEC_COND_FRINTM @@ -1747,16 +1883,36 @@ (define_int_iterator SVE_COND_FP_BINARY [UNSPEC_COND_FADD UNSPEC_COND_FDIV + UNSPEC_COND_FMAX UNSPEC_COND_FMAXNM + UNSPEC_COND_FMIN UNSPEC_COND_FMINNM UNSPEC_COND_FMUL + UNSPEC_COND_FMULX UNSPEC_COND_FSUB]) -(define_int_iterator SVE_COND_FP_BINARY_I1 [UNSPEC_COND_FMAXNM +(define_int_iterator SVE_COND_FP_BINARY_INT [UNSPEC_COND_FSCALE]) + +(define_int_iterator SVE_COND_FP_ADD [UNSPEC_COND_FADD]) +(define_int_iterator SVE_COND_FP_SUB [UNSPEC_COND_FSUB]) +(define_int_iterator SVE_COND_FP_MUL [UNSPEC_COND_FMUL]) + +(define_int_iterator SVE_COND_FP_BINARY_I1 [UNSPEC_COND_FMAX + UNSPEC_COND_FMAXNM + UNSPEC_COND_FMIN UNSPEC_COND_FMINNM UNSPEC_COND_FMUL]) -(define_int_iterator SVE_COND_FP_BINARY_REG [UNSPEC_COND_FDIV]) +(define_int_iterator SVE_COND_FP_BINARY_REG [UNSPEC_COND_FDIV + UNSPEC_COND_FMULX]) + +(define_int_iterator SVE_COND_FCADD [UNSPEC_COND_FCADD90 + UNSPEC_COND_FCADD270]) + +(define_int_iterator SVE_COND_FP_MAXMIN [UNSPEC_COND_FMAX + UNSPEC_COND_FMAXNM + UNSPEC_COND_FMIN + UNSPEC_COND_FMINNM]) ;; Floating-point max/min operations that correspond to optabs, ;; as opposed to those that are internal to the port. @@ -1768,6 +1924,22 @@ UNSPEC_COND_FNMLA UNSPEC_COND_FNMLS]) +(define_int_iterator SVE_COND_FCMLA [UNSPEC_COND_FCMLA + UNSPEC_COND_FCMLA90 + UNSPEC_COND_FCMLA180 + UNSPEC_COND_FCMLA270]) + +(define_int_iterator SVE_COND_INT_CMP_WIDE [UNSPEC_COND_CMPEQ_WIDE + UNSPEC_COND_CMPGE_WIDE + UNSPEC_COND_CMPGT_WIDE + UNSPEC_COND_CMPHI_WIDE + UNSPEC_COND_CMPHS_WIDE + UNSPEC_COND_CMPLE_WIDE + UNSPEC_COND_CMPLO_WIDE + UNSPEC_COND_CMPLS_WIDE + UNSPEC_COND_CMPLT_WIDE + UNSPEC_COND_CMPNE_WIDE]) + ;; SVE FP comparisons that accept #0.0. (define_int_iterator SVE_COND_FP_CMP_I0 [UNSPEC_COND_FCMEQ UNSPEC_COND_FCMGE @@ -1781,6 +1953,20 @@ UNSPEC_COND_FCMLE UNSPEC_COND_FCMLT]) +(define_int_iterator SVE_FP_TERNARY_LANE [UNSPEC_FMLA UNSPEC_FMLS]) + +(define_int_iterator SVE_CFP_TERNARY_LANE [UNSPEC_FCMLA UNSPEC_FCMLA90 + UNSPEC_FCMLA180 UNSPEC_FCMLA270]) + +(define_int_iterator SVE_WHILE [UNSPEC_WHILE_LE UNSPEC_WHILE_LO + UNSPEC_WHILE_LS UNSPEC_WHILE_LT]) + +(define_int_iterator SVE_SHIFT_WIDE [UNSPEC_ASHIFT_WIDE + UNSPEC_ASHIFTRT_WIDE + UNSPEC_LSHIFTRT_WIDE]) + +(define_int_iterator SVE_LDFF1_LDNF1 [UNSPEC_LDFF1 UNSPEC_LDNF1]) + (define_int_iterator FCADD [UNSPEC_FCADD90 UNSPEC_FCADD270]) @@ -1792,6 +1978,12 @@ (define_int_iterator FRINTNZX [UNSPEC_FRINT32Z UNSPEC_FRINT32X UNSPEC_FRINT64Z UNSPEC_FRINT64X]) +(define_int_iterator SVE_BRK_UNARY [UNSPEC_BRKA UNSPEC_BRKB]) + +(define_int_iterator SVE_BRK_BINARY [UNSPEC_BRKN UNSPEC_BRKPA UNSPEC_BRKPB]) + +(define_int_iterator SVE_PITER [UNSPEC_PFIRST UNSPEC_PNEXT]) + ;; Iterators for atomic operations. (define_int_iterator ATOMIC_LDOP @@ -1816,9 +2008,16 @@ (define_int_attr optab [(UNSPEC_ANDF "and") (UNSPEC_IORF "ior") (UNSPEC_XORF "xor") + (UNSPEC_SADDV "sadd") + (UNSPEC_UADDV "uadd") (UNSPEC_ANDV "and") (UNSPEC_IORV "ior") (UNSPEC_XORV "xor") + (UNSPEC_FRECPE "frecpe") + (UNSPEC_FRECPS "frecps") + (UNSPEC_RSQRTE "frsqrte") + (UNSPEC_RSQRTS "frsqrts") + (UNSPEC_RBIT "rbit") (UNSPEC_REVB "revb") (UNSPEC_REVH "revh") (UNSPEC_REVW "revw") @@ -1831,20 +2030,41 @@ (UNSPEC_FMAXV "smax_nan") (UNSPEC_FMINNMV "smin") (UNSPEC_FMINV "smin_nan") + (UNSPEC_SMUL_HIGHPART "smulh") + (UNSPEC_UMUL_HIGHPART "umulh") + (UNSPEC_FMLA "fma") + (UNSPEC_FMLS "fnma") + (UNSPEC_FCMLA "fcmla") + (UNSPEC_FCMLA90 "fcmla90") + (UNSPEC_FCMLA180 "fcmla180") + (UNSPEC_FCMLA270 "fcmla270") + (UNSPEC_FEXPA "fexpa") + (UNSPEC_FTSMUL "ftsmul") + (UNSPEC_FTSSEL "ftssel") (UNSPEC_COND_FABS "abs") (UNSPEC_COND_FADD "add") + (UNSPEC_COND_FCADD90 "cadd90") + (UNSPEC_COND_FCADD270 "cadd270") + (UNSPEC_COND_FCMLA "fcmla") + (UNSPEC_COND_FCMLA90 "fcmla90") + (UNSPEC_COND_FCMLA180 "fcmla180") + (UNSPEC_COND_FCMLA270 "fcmla270") (UNSPEC_COND_FCVT "fcvt") (UNSPEC_COND_FCVTZS "fix_trunc") (UNSPEC_COND_FCVTZU "fixuns_trunc") (UNSPEC_COND_FDIV "div") + (UNSPEC_COND_FMAX "smax_nan") (UNSPEC_COND_FMAXNM "smax") + (UNSPEC_COND_FMIN "smin_nan") (UNSPEC_COND_FMINNM "smin") (UNSPEC_COND_FMLA "fma") (UNSPEC_COND_FMLS "fnma") (UNSPEC_COND_FMUL "mul") + (UNSPEC_COND_FMULX "mulx") (UNSPEC_COND_FNEG "neg") (UNSPEC_COND_FNMLA "fnms") (UNSPEC_COND_FNMLS "fms") + (UNSPEC_COND_FRECPX "frecpx") (UNSPEC_COND_FRINTA "round") (UNSPEC_COND_FRINTI "nearbyint") (UNSPEC_COND_FRINTM "floor") @@ -1852,6 +2072,7 @@ (UNSPEC_COND_FRINTP "ceil") (UNSPEC_COND_FRINTX "rint") (UNSPEC_COND_FRINTZ "btrunc") + (UNSPEC_COND_FSCALE "fscale") (UNSPEC_COND_FSQRT "sqrt") (UNSPEC_COND_FSUB "sub") (UNSPEC_COND_SCVTF "float") @@ -1869,7 +2090,9 @@ (UNSPEC_FMINV "smin_nan") (UNSPEC_FMAXNM "fmax") (UNSPEC_FMINNM "fmin") + (UNSPEC_COND_FMAX "fmax_nan") (UNSPEC_COND_FMAXNM "fmax") + (UNSPEC_COND_FMIN "fmin_nan") (UNSPEC_COND_FMINNM "fmin")]) (define_int_attr maxmin_uns_op [(UNSPEC_UMAXV "umax") @@ -1885,13 +2108,28 @@ (UNSPEC_FMAXNM "fmaxnm") (UNSPEC_FMINNM "fminnm")]) +(define_code_attr binqops_op [(ss_plus "sqadd") + (us_plus "uqadd") + (ss_minus "sqsub") + (us_minus "uqsub")]) + +(define_code_attr binqops_op_rev [(ss_plus "sqsub") + (ss_minus "sqadd")]) + ;; The SVE logical instruction that implements an unspec. (define_int_attr logicalf_op [(UNSPEC_ANDF "and") (UNSPEC_IORF "orr") (UNSPEC_XORF "eor")]) +(define_int_attr last_op [(UNSPEC_CLASTA "after_last") + (UNSPEC_CLASTB "last") + (UNSPEC_LASTA "after_last") + (UNSPEC_LASTB "last")]) + ;; "s" for signed operations and "u" for unsigned ones. -(define_int_attr su [(UNSPEC_UNPACKSHI "s") +(define_int_attr su [(UNSPEC_SADDV "s") + (UNSPEC_UADDV "u") + (UNSPEC_UNPACKSHI "s") (UNSPEC_UNPACKUHI "u") (UNSPEC_UNPACKSLO "s") (UNSPEC_UNPACKULO "u") @@ -1961,6 +2199,11 @@ (define_int_attr bt [(UNSPEC_SMULLB "b") (UNSPEC_UMULLB "b") (UNSPEC_SMULLT "t") (UNSPEC_UMULLT "t")]) +(define_int_attr fn [(UNSPEC_LDFF1 "f") (UNSPEC_LDNF1 "n")]) + +(define_int_attr ab [(UNSPEC_CLASTA "a") (UNSPEC_CLASTB "b") + (UNSPEC_LASTA "a") (UNSPEC_LASTB "b")]) + (define_int_attr addsub [(UNSPEC_SHADD "add") (UNSPEC_UHADD "add") (UNSPEC_SRHADD "add") @@ -2102,13 +2345,37 @@ (UNSPEC_FRINT64Z "frint64z") (UNSPEC_FRINT64X "frint64x")]) ;; The condition associated with an UNSPEC_COND_<xx>. -(define_int_attr cmp_op [(UNSPEC_COND_FCMEQ "eq") +(define_int_attr cmp_op [(UNSPEC_COND_CMPEQ_WIDE "eq") + (UNSPEC_COND_CMPGE_WIDE "ge") + (UNSPEC_COND_CMPGT_WIDE "gt") + (UNSPEC_COND_CMPHI_WIDE "hi") + (UNSPEC_COND_CMPHS_WIDE "hs") + (UNSPEC_COND_CMPLE_WIDE "le") + (UNSPEC_COND_CMPLO_WIDE "lo") + (UNSPEC_COND_CMPLS_WIDE "ls") + (UNSPEC_COND_CMPLT_WIDE "lt") + (UNSPEC_COND_CMPNE_WIDE "ne") + (UNSPEC_COND_FCMEQ "eq") (UNSPEC_COND_FCMGE "ge") (UNSPEC_COND_FCMGT "gt") (UNSPEC_COND_FCMLE "le") (UNSPEC_COND_FCMLT "lt") (UNSPEC_COND_FCMNE "ne") - (UNSPEC_COND_FCMUO "uo")]) + (UNSPEC_WHILE_LE "le") + (UNSPEC_WHILE_LO "lo") + (UNSPEC_WHILE_LS "ls") + (UNSPEC_WHILE_LT "lt")]) + +(define_int_attr while_optab_cmp [(UNSPEC_WHILE_LE "le") + (UNSPEC_WHILE_LO "ult") + (UNSPEC_WHILE_LS "ule") + (UNSPEC_WHILE_LT "lt")]) + +(define_int_attr brk_op [(UNSPEC_BRKA "a") (UNSPEC_BRKB "b") + (UNSPEC_BRKN "n") + (UNSPEC_BRKPA "pa") (UNSPEC_BRKPB "pb")]) + +(define_int_attr sve_pred_op [(UNSPEC_PFIRST "pfirst") (UNSPEC_PNEXT "pnext")]) (define_int_attr sve_int_op [(UNSPEC_ANDV "andv") (UNSPEC_IORV "orv") @@ -2117,22 +2384,41 @@ (UNSPEC_UMINV "uminv") (UNSPEC_SMAXV "smaxv") (UNSPEC_SMINV "sminv") + (UNSPEC_SMUL_HIGHPART "smulh") + (UNSPEC_UMUL_HIGHPART "umulh") + (UNSPEC_ASHIFT_WIDE "lsl") + (UNSPEC_ASHIFTRT_WIDE "asr") + (UNSPEC_LSHIFTRT_WIDE "lsr") + (UNSPEC_RBIT "rbit") (UNSPEC_REVB "revb") (UNSPEC_REVH "revh") (UNSPEC_REVW "revw")]) -(define_int_attr sve_fp_op [(UNSPEC_FADDV "faddv") +(define_int_attr sve_fp_op [(UNSPEC_FRECPE "frecpe") + (UNSPEC_FRECPS "frecps") + (UNSPEC_RSQRTE "frsqrte") + (UNSPEC_RSQRTS "frsqrts") + (UNSPEC_FADDV "faddv") (UNSPEC_FMAXNMV "fmaxnmv") (UNSPEC_FMAXV "fmaxv") (UNSPEC_FMINNMV "fminnmv") (UNSPEC_FMINV "fminv") + (UNSPEC_FMLA "fmla") + (UNSPEC_FMLS "fmls") + (UNSPEC_FEXPA "fexpa") + (UNSPEC_FTSMUL "ftsmul") + (UNSPEC_FTSSEL "ftssel") (UNSPEC_COND_FABS "fabs") (UNSPEC_COND_FADD "fadd") (UNSPEC_COND_FDIV "fdiv") + (UNSPEC_COND_FMAX "fmax") (UNSPEC_COND_FMAXNM "fmaxnm") + (UNSPEC_COND_FMIN "fmin") (UNSPEC_COND_FMINNM "fminnm") (UNSPEC_COND_FMUL "fmul") + (UNSPEC_COND_FMULX "fmulx") (UNSPEC_COND_FNEG "fneg") + (UNSPEC_COND_FRECPX "frecpx") (UNSPEC_COND_FRINTA "frinta") (UNSPEC_COND_FRINTI "frinti") (UNSPEC_COND_FRINTM "frintm") @@ -2140,14 +2426,18 @@ (UNSPEC_COND_FRINTP "frintp") (UNSPEC_COND_FRINTX "frintx") (UNSPEC_COND_FRINTZ "frintz") + (UNSPEC_COND_FSCALE "fscale") (UNSPEC_COND_FSQRT "fsqrt") (UNSPEC_COND_FSUB "fsub")]) (define_int_attr sve_fp_op_rev [(UNSPEC_COND_FADD "fadd") (UNSPEC_COND_FDIV "fdivr") + (UNSPEC_COND_FMAX "fmax") (UNSPEC_COND_FMAXNM "fmaxnm") + (UNSPEC_COND_FMIN "fmin") (UNSPEC_COND_FMINNM "fminnm") (UNSPEC_COND_FMUL "fmul") + (UNSPEC_COND_FMULX "fmulx") (UNSPEC_COND_FSUB "fsubr")]) (define_int_attr rot [(UNSPEC_FCADD90 "90") @@ -2155,7 +2445,13 @@ (UNSPEC_FCMLA "0") (UNSPEC_FCMLA90 "90") (UNSPEC_FCMLA180 "180") - (UNSPEC_FCMLA270 "270")]) + (UNSPEC_FCMLA270 "270") + (UNSPEC_COND_FCADD90 "90") + (UNSPEC_COND_FCADD270 "270") + (UNSPEC_COND_FCMLA "0") + (UNSPEC_COND_FCMLA90 "90") + (UNSPEC_COND_FCMLA180 "180") + (UNSPEC_COND_FCMLA270 "270")]) (define_int_attr sve_fmla_op [(UNSPEC_COND_FMLA "fmla") (UNSPEC_COND_FMLS "fmls") @@ -2167,14 +2463,25 @@ (UNSPEC_COND_FNMLA "fnmad") (UNSPEC_COND_FNMLS "fnmsb")]) +;; The register constraint to use for the final operand in a binary BRK. +(define_int_attr brk_reg_con [(UNSPEC_BRKN "0") + (UNSPEC_BRKPA "Upa") (UNSPEC_BRKPB "Upa")]) + +;; The register number to print for the above. +(define_int_attr brk_reg_opno [(UNSPEC_BRKN "0") + (UNSPEC_BRKPA "3") (UNSPEC_BRKPB "3")]) + ;; The predicate to use for the first input operand in a floating-point ;; <optab><mode>3 pattern. (define_int_attr sve_pred_fp_rhs1_operand [(UNSPEC_COND_FADD "register_operand") (UNSPEC_COND_FDIV "register_operand") + (UNSPEC_COND_FMAX "register_operand") (UNSPEC_COND_FMAXNM "register_operand") + (UNSPEC_COND_FMIN "register_operand") (UNSPEC_COND_FMINNM "register_operand") (UNSPEC_COND_FMUL "register_operand") + (UNSPEC_COND_FMULX "register_operand") (UNSPEC_COND_FSUB "aarch64_sve_float_arith_operand")]) ;; The predicate to use for the second input operand in a floating-point @@ -2182,18 +2489,28 @@ (define_int_attr sve_pred_fp_rhs2_operand [(UNSPEC_COND_FADD "aarch64_sve_float_arith_with_sub_operand") (UNSPEC_COND_FDIV "register_operand") + (UNSPEC_COND_FMAX "aarch64_sve_float_maxmin_operand") (UNSPEC_COND_FMAXNM "aarch64_sve_float_maxmin_operand") + (UNSPEC_COND_FMIN "aarch64_sve_float_maxmin_operand") (UNSPEC_COND_FMINNM "aarch64_sve_float_maxmin_operand") (UNSPEC_COND_FMUL "aarch64_sve_float_mul_operand") + (UNSPEC_COND_FMULX "register_operand") (UNSPEC_COND_FSUB "register_operand")]) ;; Likewise for immediates only. (define_int_attr sve_pred_fp_rhs2_immediate - [(UNSPEC_COND_FMAXNM "aarch64_sve_float_maxmin_immediate") + [(UNSPEC_COND_FMAX "aarch64_sve_float_maxmin_immediate") + (UNSPEC_COND_FMAXNM "aarch64_sve_float_maxmin_immediate") + (UNSPEC_COND_FMIN "aarch64_sve_float_maxmin_immediate") (UNSPEC_COND_FMINNM "aarch64_sve_float_maxmin_immediate") (UNSPEC_COND_FMUL "aarch64_sve_float_mul_immediate")]) +;; The maximum number of element bits that an instruction can handle. +(define_int_attr max_elem_bits [(UNSPEC_UADDV "64") (UNSPEC_SADDV "32") + (UNSPEC_PFIRST "8") (UNSPEC_PNEXT "64")]) + ;; The minimum number of element bits that an instruction can handle. -(define_int_attr min_elem_bits [(UNSPEC_REVB "16") +(define_int_attr min_elem_bits [(UNSPEC_RBIT "8") + (UNSPEC_REVB "16") (UNSPEC_REVH "32") (UNSPEC_REVW "64")]) diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index 2b9aa4a..2c5c53c 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -46,9 +46,10 @@ return CONST_INT_P (op) && IN_RANGE (INTVAL (op), 1, 3); }) -(define_special_predicate "subreg_lowpart_operator" - (and (match_code "subreg") - (match_test "subreg_lowpart_p (op)"))) +(define_predicate "subreg_lowpart_operator" + (ior (match_code "truncate") + (and (match_code "subreg") + (match_test "subreg_lowpart_p (op)")))) (define_predicate "aarch64_ccmp_immediate" (and (match_code "const_int") @@ -457,6 +458,12 @@ return aarch64_stepped_int_parallel_p (op, -1); }) +(define_predicate "ascending_int_parallel" + (match_code "parallel") +{ + return aarch64_stepped_int_parallel_p (op, 1); +}) + (define_special_predicate "aarch64_simd_lshift_imm" (match_code "const,const_vector") { @@ -491,6 +498,10 @@ (match_test "op == const0_rtx") (match_operand 0 "aarch64_simd_or_scalar_imm_zero")))) +(define_predicate "aarch64_simd_reg_or_minus_one" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_simd_imm_minus_one"))) + (define_predicate "aarch64_simd_struct_operand" (and (match_code "mem") (match_test "TARGET_SIMD && aarch64_simd_mem_operand_p (op)"))) @@ -577,12 +588,24 @@ (and (match_code "mem") (match_test "aarch64_sve_ld1rq_operand_p (op)"))) +(define_predicate "aarch64_sve_ldff1_operand" + (and (match_code "mem") + (match_test "aarch64_sve_ldff1_operand_p (op)"))) + +(define_predicate "aarch64_sve_ldnf1_operand" + (and (match_code "mem") + (match_test "aarch64_sve_ldnf1_operand_p (op)"))) + ;; Like memory_operand, but restricted to addresses that are valid for ;; SVE LDR and STR instructions. (define_predicate "aarch64_sve_ldr_operand" (and (match_code "mem") (match_test "aarch64_sve_ldr_operand_p (op)"))) +(define_special_predicate "aarch64_sve_prefetch_operand" + (and (match_code "reg, plus") + (match_test "aarch64_sve_prefetch_operand_p (op, mode)"))) + (define_predicate "aarch64_sve_nonimmediate_operand" (ior (match_operand 0 "register_operand") (match_operand 0 "aarch64_sve_ldr_operand"))) @@ -607,6 +630,10 @@ (ior (match_operand 0 "register_operand") (match_operand 0 "aarch64_sve_ld1r_operand"))) +(define_predicate "aarch64_sve_ptrue_svpattern_immediate" + (and (match_code "const") + (match_test "aarch64_sve_ptrue_svpattern_p (op, NULL)"))) + (define_predicate "aarch64_sve_arith_immediate" (and (match_code "const,const_vector") (match_test "aarch64_sve_arith_immediate_p (op, false)"))) @@ -615,10 +642,37 @@ (and (match_code "const,const_vector") (match_test "aarch64_sve_arith_immediate_p (op, true)"))) +(define_predicate "aarch64_sve_qadd_immediate" + (and (match_code "const,const_vector") + (match_test "aarch64_sve_sqadd_sqsub_immediate_p (op, false)"))) + +(define_predicate "aarch64_sve_qsub_immediate" + (and (match_code "const,const_vector") + (match_test "aarch64_sve_sqadd_sqsub_immediate_p (op, true)"))) + (define_predicate "aarch64_sve_vector_inc_dec_immediate" (and (match_code "const,const_vector") (match_test "aarch64_sve_vector_inc_dec_immediate_p (op)"))) +(define_predicate "aarch64_sve_gather_immediate_b" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 31)"))) + +(define_predicate "aarch64_sve_gather_immediate_h" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 62)") + (match_test "(INTVAL (op) & 1) == 0"))) + +(define_predicate "aarch64_sve_gather_immediate_w" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 124)") + (match_test "(INTVAL (op) & 3) == 0"))) + +(define_predicate "aarch64_sve_gather_immediate_d" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 248)") + (match_test "(INTVAL (op) & 7) == 0"))) + (define_predicate "aarch64_sve_uxtb_immediate" (and (match_code "const_vector") (match_test "GET_MODE_UNIT_BITSIZE (GET_MODE (op)) > 8") @@ -702,6 +756,11 @@ (match_operand 0 "aarch64_sve_sub_arith_immediate") (match_operand 0 "aarch64_sve_vector_inc_dec_immediate"))) +(define_predicate "aarch64_sve_sqadd_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_sve_qadd_immediate") + (match_operand 0 "aarch64_sve_qsub_immediate"))) + (define_predicate "aarch64_sve_pred_and_operand" (ior (match_operand 0 "register_operand") (match_operand 0 "aarch64_sve_uxt_immediate"))) @@ -710,6 +769,22 @@ (ior (match_operand 0 "register_operand") (match_operand 0 "aarch64_sve_logical_immediate"))) +(define_predicate "aarch64_sve_gather_offset_b" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_sve_gather_immediate_b"))) + +(define_predicate "aarch64_sve_gather_offset_h" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_sve_gather_immediate_h"))) + +(define_predicate "aarch64_sve_gather_offset_w" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_sve_gather_immediate_w"))) + +(define_predicate "aarch64_sve_gather_offset_d" + (ior (match_operand 0 "register_operand") + (match_operand 0 "aarch64_sve_gather_immediate_d"))) + (define_predicate "aarch64_sve_lshift_operand" (ior (match_operand 0 "register_operand") (match_operand 0 "aarch64_simd_lshift_imm"))) @@ -772,6 +847,14 @@ (ior (match_test "INTVAL (op) == SVE_RELAXED_GP") (match_test "INTVAL (op) == SVE_STRICT_GP")))) +(define_predicate "aarch64_gather_scale_operand_b" + (and (match_code "const_int") + (match_test "INTVAL (op) == 1"))) + +(define_predicate "aarch64_gather_scale_operand_h" + (and (match_code "const_int") + (match_test "INTVAL (op) == 1 || INTVAL (op) == 2"))) + (define_predicate "aarch64_gather_scale_operand_w" (and (match_code "const_int") (match_test "INTVAL (op) == 1 || INTVAL (op) == 4"))) diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64 index 391b4a2..28e1c7a 100644 --- a/gcc/config/aarch64/t-aarch64 +++ b/gcc/config/aarch64/t-aarch64 @@ -40,6 +40,43 @@ aarch64-builtins.o: $(srcdir)/config/aarch64/aarch64-builtins.c $(CONFIG_H) \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/aarch64/aarch64-builtins.c +aarch64-sve-builtins.o: $(srcdir)/config/aarch64/aarch64-sve-builtins.cc \ + $(srcdir)/config/aarch64/aarch64-sve-builtins.def \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + $(TM_P_H) memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) $(DIAGNOSTIC_H) \ + $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) fold-const.h $(GIMPLE_H) \ + gimple-iterator.h gimplify.h explow.h $(EMIT_RTL_H) tree-vector-builder.h \ + stor-layout.h $(REG_H) alias.h gimple-fold.h langhooks.h \ + stringpool.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-shapes.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-base.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/aarch64/aarch64-sve-builtins.cc + +aarch64-sve-builtins-shapes.o: \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-shapes.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + $(TM_P_H) memmodel.h insn-codes.h $(OPTABS_H) \ + $(srcdir)/config/aarch64/aarch64-sve-builtins.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-shapes.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-shapes.cc + +aarch64-sve-builtins-base.o: \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-base.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + $(TM_P_H) memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) \ + $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) fold-const.h $(GIMPLE_H) \ + gimple-iterator.h gimplify.h explow.h $(EMIT_RTL_H) tree-vector-builder.h \ + rtx-vector-builder.h vec-perm-indices.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-shapes.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-base.h \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-functions.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/aarch64/aarch64-sve-builtins-base.cc + aarch64-builtin-iterators.h: $(srcdir)/config/aarch64/geniterators.sh \ $(srcdir)/config/aarch64/iterators.md $(SHELL) $(srcdir)/config/aarch64/geniterators.sh \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bbb5f1b..0507477 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2019-10-29 Richard Sandiford <richard.sandiford@arm.com> + Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org> + Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> + + * g++.target/aarch64/sve/acle/aarch64-sve-acle.exp: New file. + * g++.target/aarch64/sve/acle/general-c++: New test directory. + * gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp: New file. + * gcc.target/aarch64/sve/acle/general: New test directory. + * gcc.target/aarch64/sve/acle/general-c: Likewise. + 2019-10-29 Richard Biener <rguenther@suse.de> PR tree-optimization/92241 diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp new file mode 100644 index 0000000..54c43a3 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp @@ -0,0 +1,55 @@ +# Specific regression driver for AArch64 SVE. +# Copyright (C) 2009-2019 Free Software Foundation, Inc. +# Contributed by ARM Ltd. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. */ + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an AArch64 target. +if {![istarget aarch64*-*-*] } { + return +} + +# Load support procs. +load_lib g++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CXXFLAGS +if ![info exists DEFAULT_CXXFLAGS] then { + set DEFAULT_CXXFLAGS " -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Force SVE if we're not testing it already. +if { [check_effective_target_aarch64_sve] } { + set sve_flags "" +} else { + set sve_flags "-march=armv8.2-a+sve" +} + +# Main loop. +set gcc_subdir [string replace $subdir 0 2 gcc] +set files [glob -nocomplain \ + "$srcdir/$gcc_subdir/general/*.c" \ + "$srcdir/$subdir/general-c++/*.\[cC\]"] +dg-runtest [lsort $files] "$sve_flags" $DEFAULT_CXXFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.C new file mode 100644 index 0000000..44aa10e --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +#include "add_1.h" + +svuint8_t +f1 (svbool_t pg, svuint8_t x, svint8_t y) +{ + return svadd_u8_x (pg, x, y); /* { dg-error "cannot convert 'svint8_t' to 'svuint8_t'" } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.h b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.h new file mode 100644 index 0000000..d441328 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_1.h @@ -0,0 +1,2 @@ +#pragma GCC system_header +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "initializing argument 3" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.C new file mode 100644 index 0000000..fcfb0f4 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.C @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +#include "add_2.h" + +void +f1 (svbool_t pg, svuint8_t x, svint8_t y) +{ + svadd_x (pg, x); /* { dg-error {no matching function for call to 'svadd_x\(svbool_t&, svuint8_t&\)'} } */ + svadd_x (pg, x, x, x); /* { dg-error {no matching function for call to 'svadd_x\(svbool_t&, svuint8_t&, svuint8_t&, svuint8_t&\)'} } */ + svadd_x (x, x, x); /* { dg-error {no matching function for call to 'svadd_x\(svuint8_t&, svuint8_t&, svuint8_t&\)'} } */ + svadd_x (pg, pg, pg); /* { dg-error {no matching function for call to 'svadd_x\(svbool_t&, svbool_t&, svbool_t&\)'} } */ + svadd_x (pg, 1, x); /* { dg-error {no matching function for call to 'svadd_x\(svbool_t&, int, svuint8_t&\)'} } */ + svadd_x (pg, x, y); /* { dg-error {no matching function for call to 'svadd_x\(svbool_t&, svuint8_t&, svint8_t&\)'} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.h b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.h new file mode 100644 index 0000000..2b3a520 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_2.h @@ -0,0 +1,9 @@ +#pragma GCC system_header +#pragma GCC aarch64 "arm_sve.h" +/* { dg-message {note: candidate: 'svfloat16_t svadd_x\(svbool_t, svfloat16_t, svfloat16_t\)'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *candidate expects 3 arguments, 2 provided} "" { target *-*-* } 3 } */ +/* { dg-message {note: *candidate expects 3 arguments, 4 provided} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 1 from 'svuint8_t' to 'svbool_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svbool_t' to 'svfloat16_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'int' to 'svfloat16_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svuint8_t' to 'svfloat16_t'} "" { target *-*-* } 3 } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_3.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_3.C new file mode 100644 index 0000000..1d811fc --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/add_3.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized -fnon-call-exceptions" } */ + +#include <arm_sve.h> + +svint8_t +foo (svbool_t pg, svint8_t a, svint8_t b) +{ + try + { + a = svadd_m (pg, a, b); + } + catch (...) + { + a = b; + } + return a; +} + +/* { dg-final { scan-tree-dump-not {__cxa_begin_catch} "optimized" } } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_1.C new file mode 100644 index 0000000..a73934f --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_1.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64, int x) +{ + const int one = 1; + u8 = svasrd_x (pg, u8, 1); /* { dg-error {no matching function for call to 'svasrd_x\(svbool_t&, svuint8_t&, [^)]*\)'} } */ + s8 = svasrd_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, one); + s8 = svasrd_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1.0); + s8 = svasrd_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1); + s8 = svasrd_x (pg, s8, 1 + 1); + s8 = svasrd_x (pg, s8, const_add (1, 1)); + s8 = svasrd_x (pg, s8, add (1, 1)); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, 8); + s8 = svasrd_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, (uint64_t (1) << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_x (pg, s16, 1); + s16 = svasrd_x (pg, s16, 16); + s16 = svasrd_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_x (pg, s32, 1); + s32 = svasrd_x (pg, s32, 32); + s32 = svasrd_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_x (pg, s64, 1); + s64 = svasrd_x (pg, s64, 64); + s64 = svasrd_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_2.C new file mode 100644 index 0000000..bbe7ba7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_2.C @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +void +f1 (svbool_t pg, svint8_t s8, svint16_t s16, svint32_t s32, svint64_t s64, + int x) +{ + const int one = 1; + s8 = svasrd_n_s8_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, one); + s8 = svasrd_n_s8_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1.0); + s8 = svasrd_n_s8_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1); + s8 = svasrd_n_s8_x (pg, s8, 1 + 1); + s8 = svasrd_n_s8_x (pg, s8, const_add (1, 1)); + s8 = svasrd_n_s8_x (pg, s8, add (1, 1)); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, 8); + s8 = svasrd_n_s8_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, (uint64_t (1) << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 1); + s16 = svasrd_n_s16_x (pg, s16, 16); + s16 = svasrd_n_s16_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 1); + s32 = svasrd_n_s32_x (pg, s32, 32); + s32 = svasrd_n_s32_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 1); + s64 = svasrd_n_s64_x (pg, s64, 64); + s64 = svasrd_n_s64_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_3.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_3.C new file mode 100644 index 0000000..5ebd770 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/asrd_3.C @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +template<uint64_t N, typename T> +T shift (svbool_t pg, T v) { return svasrd_x (pg, v, N); } +/* { dg-error {no matching function for call to 'svasrd_x\(svbool_t&,} "" { target *-*-* } .-1 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} "" { target *-*-* } .-2 } */ +/* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} "" { target *-*-* } .-3 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} "" { target *-*-* } .-4 } */ +/* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} "" { target *-*-* } .-5 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} "" { target *-*-* } .-6 } */ +/* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} "" { target *-*-* } .-7 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} "" { target *-*-* } .-8 } */ +/* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} "" { target *-*-* } .-9 } */ + +template<typename T> +T shift1 (svbool_t pg, T v, uint64_t n) { return svasrd_x (pg, v, n); } + +template<typename T> +T shift2 (svbool_t pg, T v, uint64_t n) { return svasrd_x (pg, v, n); } +/* { dg-error {argument 3 of 'svasrd_x' must be an integer constant expression} "" { target *-*-* } .-1 } */ + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64) +{ + u8 = shift <1> (pg, u8); + s8 = shift <0> (pg, s8); + s8 = shift <1> (pg, s8); + s8 = shift <8> (pg, s8); + s8 = shift <9> (pg, s8); + s16 = shift <0> (pg, s16); + s16 = shift <1> (pg, s16); + s16 = shift <16> (pg, s16); + s16 = shift <17> (pg, s16); + s32 = shift <0> (pg, s32); + s32 = shift <1> (pg, s32); + s32 = shift <32> (pg, s32); + s32 = shift <33> (pg, s32); + s64 = shift <0> (pg, s64); + s64 = shift <1> (pg, s64); + s64 = shift <64> (pg, s64); + s64 = shift <65> (pg, s64); + + s8 = shift2 (pg, s8, 1); +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/cntb_pat.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/cntb_pat.c new file mode 100644 index 0000000..bbc9f90 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/cntb_pat.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +test (svpattern pat, int i) +{ + svcntb_pat (pat); /* { dg-error "argument 1 of 'svcntb_pat' must be an integer constant expression" } */ + svcntb_pat (i); /* { dg-error "invalid conversion from 'int' to 'svpattern'" } */ + /* { dg-error "argument 1 of 'svcntb_pat' must be an integer constant expression" "" { target *-*-* } .-1 } */ + svcntb_pat ((svpattern) -1); /* { dg-error "passing 4294967295 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 0); + svcntb_pat ((svpattern) 1); + svcntb_pat ((svpattern) 2); + svcntb_pat ((svpattern) 3); + svcntb_pat ((svpattern) 4); + svcntb_pat ((svpattern) 5); + svcntb_pat ((svpattern) 6); + svcntb_pat ((svpattern) 7); + svcntb_pat ((svpattern) 8); + svcntb_pat ((svpattern) 9); + svcntb_pat ((svpattern) 10); + svcntb_pat ((svpattern) 11); + svcntb_pat ((svpattern) 12); + svcntb_pat ((svpattern) 13); + svcntb_pat ((svpattern) 14); /* { dg-error "passing 14 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 15); /* { dg-error "passing 15 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 16); /* { dg-error "passing 16 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 17); /* { dg-error "passing 17 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 18); /* { dg-error "passing 18 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 19); /* { dg-error "passing 19 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 20); /* { dg-error "passing 20 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 21); /* { dg-error "passing 21 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 22); /* { dg-error "passing 22 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 23); /* { dg-error "passing 23 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 24); /* { dg-error "passing 24 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 25); /* { dg-error "passing 25 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 26); /* { dg-error "passing 26 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 27); /* { dg-error "passing 27 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 28); /* { dg-error "passing 28 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ + svcntb_pat ((svpattern) 29); + svcntb_pat ((svpattern) 30); + svcntb_pat ((svpattern) 31); + svcntb_pat ((svpattern) 32); /* { dg-error "passing 32 to argument 1 of 'svcntb_pat', which expects a valid 'svpattern' value" } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/conversion_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/conversion_1.C new file mode 100644 index 0000000..1b939cd --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/conversion_1.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +template<typename T> +struct S +{ + S(T); + operator T() const; + void *base; +}; + +void f(svbool_t pg, const S<svuint8_t> &u8a, const S<svuint8_t> &u8b, + const S<svint8_t> &s8a) +{ + svadd_x(pg, u8a, u8b); + svadd_x(pg, u8a, 1); + svadd_x(pg, s8a, u8b); // { dg-error "no matching function for call" } + svadd_x(pg, s8a, 1); +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_1.C new file mode 100644 index 0000000..247fd85 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_1.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svuint8x2_t *ptr, svbool_t pg, svuint8_t u8, svfloat64_t f64, + svuint8x2_t u8x2) +{ + *ptr = svcreate2 (u8); /* { dg-error {no matching function for call to 'svcreate2\(svuint8_t\&\)'} } */ + *ptr = svcreate2 (u8, u8, u8); /* { dg-error {no matching function for call to 'svcreate2\(svuint8_t\&, svuint8_t\&, svuint8_t\&\)'} } */ + *ptr = svcreate2 (u8x2, u8x2); /* { dg-error {no matching function for call to 'svcreate2\(svuint8x2_t\&, svuint8x2_t\&\)'} } */ + *ptr = svcreate2 (u8, f64); /* { dg-error {no matching function for call to 'svcreate2\(svuint8_t\&, svfloat64_t\&\)'} } */ + *ptr = svcreate2 (u8, pg); /* { dg-error {no matching function for call to 'svcreate2\(svuint8_t\&, svbool_t\&\)'} } */ + *ptr = svcreate2 (u8, u8); + *ptr = svcreate2 (f64, f64); /* { dg-error {cannot convert 'svfloat64x2_t' to 'svuint8x2_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_2.C new file mode 100644 index 0000000..10f3231 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create2_2.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svuint8x2_t *ptr, svbool_t pg, svuint8_t u8, svfloat64_t f64, + svuint8x2_t u8x2) +{ + *ptr = svcreate2_u8 (u8); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate2_u8 (u8, u8, u8); /* { dg-error {too many arguments to function '[^']*'} } */ + *ptr = svcreate2_u8 (u8x2, u8x2); /* { dg-error {cannot convert 'svuint8x2_t' to 'svuint8_t'} } */ + *ptr = svcreate2_u8 (u8, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svuint8_t'} } */ + *ptr = svcreate2_u8 (pg, u8); /* { dg-error {cannot convert 'svbool_t' to 'svuint8_t'} } */ + *ptr = svcreate2_u8 (u8, u8); + *ptr = svcreate2_f64 (f64, f64); /* { dg-error {cannot convert 'svfloat64x2_t' to 'svuint8x2_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_1.C new file mode 100644 index 0000000..ff01363 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_1.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svfloat16x3_t *ptr, svbool_t pg, svfloat16_t f16, svfloat64_t f64, + svfloat16x3_t f16x3) +{ + *ptr = svcreate3 (f16); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16_t\&\)'} } */ + *ptr = svcreate3 (f16, f16); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16_t\&, svfloat16_t\&\)'} } */ + *ptr = svcreate3 (f16, f16, f16, f16); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16_t\&, svfloat16_t\&, svfloat16_t\&, svfloat16_t\&\)'} } */ + *ptr = svcreate3 (f16x3, f16x3, f16x3); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16x3_t\&, svfloat16x3_t\&, svfloat16x3_t\&\)'} } */ + *ptr = svcreate3 (f16, f16, f64); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16_t\&, svfloat16_t\&, svfloat64_t\&\)'} } */ + *ptr = svcreate3 (f16, pg, f16); /* { dg-error {no matching function for call to 'svcreate3\(svfloat16_t\&, svbool_t\&, svfloat16_t\&\)'} } */ + *ptr = svcreate3 (f16, f16, f16); + *ptr = svcreate3 (f64, f64, f64); /* { dg-error {cannot convert 'svfloat64x3_t' to 'svfloat16x3_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_2.C new file mode 100644 index 0000000..07a72b1 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create3_2.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svfloat16x3_t *ptr, svbool_t pg, svfloat16_t f16, svfloat64_t f64, + svfloat16x3_t f16x3) +{ + *ptr = svcreate3_f16 (f16); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate3_f16 (f16, f16); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate3_f16 (f16, f16, f16, f16); /* { dg-error {too many arguments to function '[^']*'} } */ + *ptr = svcreate3_f16 (f16x3, f16x3, f16x3); /* { dg-error {cannot convert 'svfloat16x3_t' to 'svfloat16_t'} } */ + *ptr = svcreate3_f16 (f16, f16, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svfloat16_t'} } */ + *ptr = svcreate3_f16 (f16, pg, f16); /* { dg-error {cannot convert 'svbool_t' to 'svfloat16_t'} } */ + *ptr = svcreate3_f16 (f16, f16, f16); + *ptr = svcreate3_f64 (f64, f64, f64); /* { dg-error {cannot convert 'svfloat64x3_t' to 'svfloat16x3_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_1.C new file mode 100644 index 0000000..2785d90 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_1.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svint32x4_t *ptr, svbool_t pg, svint32_t s32, svfloat64_t f64, + svint32x4_t s32x4) +{ + *ptr = svcreate4 (s32); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&\)'} } */ + *ptr = svcreate4 (s32, s32); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&, svint32_t\&\)'} } */ + *ptr = svcreate4 (s32, s32, s32); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&, svint32_t\&, svint32_t\&\)'} } */ + *ptr = svcreate4 (s32, s32, s32, s32, s32); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&, svint32_t\&, svint32_t\&, svint32_t\&, svint32_t\&\)'} } */ + *ptr = svcreate4 (s32x4, s32x4, s32x4, s32x4); /* { dg-error {no matching function for call to 'svcreate4\(svint32x4_t\&, svint32x4_t\&, svint32x4_t\&, svint32x4_t\&\)'} } */ + *ptr = svcreate4 (s32, s32, s32, f64); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&, svint32_t\&, svint32_t\&, svfloat64_t\&\)'} } */ + *ptr = svcreate4 (s32, pg, s32, s32); /* { dg-error {no matching function for call to 'svcreate4\(svint32_t\&, svbool_t\&, svint32_t\&, svint32_t\&\)'} } */ + *ptr = svcreate4 (s32, s32, s32, s32); + *ptr = svcreate4 (f64, f64, f64, f64); /* { dg-error {cannot convert 'svfloat64x4_t' to 'svint32x4_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_2.C new file mode 100644 index 0000000..68f21a1 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/create4_2.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svint32x4_t *ptr, svbool_t pg, svint32_t s32, svfloat64_t f64, + svint32x4_t s32x4) +{ + *ptr = svcreate4_s32 (s32); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate4_s32 (s32, s32); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate4_s32 (s32, s32, s32); /* { dg-error {too few arguments to function '[^']*'} } */ + *ptr = svcreate4_s32 (s32, s32, s32, s32, s32); /* { dg-error {too many arguments to function '[^']*'} } */ + *ptr = svcreate4_s32 (s32x4, s32x4, s32x4, s32x4); /* { dg-error {cannot convert 'svint32x4_t' to 'svint32_t'} } */ + *ptr = svcreate4_s32 (s32, s32, s32, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svint32_t'} } */ + *ptr = svcreate4_s32 (s32, pg, s32, s32); /* { dg-error {cannot convert 'svbool_t' to 'svint32_t'} } */ + *ptr = svcreate4_s32 (s32, s32, s32, s32); + *ptr = svcreate4_f64 (f64, f64, f64, f64); /* { dg-error {cannot convert 'svfloat64x4_t' to 'svint32x4_t' in assignment} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.C new file mode 100644 index 0000000..93397c8 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +#include "dot_1.h" + +svuint32_t +f1 (svuint32_t x, svint8_t y, svuint8_t z) +{ + return svdot_u32 (x, y, z); /* { dg-error "cannot convert 'svint8_t' to 'svuint8_t'" } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.h b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.h new file mode 100644 index 0000000..aef02f2 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_1.h @@ -0,0 +1,2 @@ +#pragma GCC system_header +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "initializing argument 2" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.C new file mode 100644 index 0000000..2084ed8 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +#include "dot_2.h" + +void +f1 (svuint32_t x, svint8_t y, svuint8_t z) +{ + svdot (x, y); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&\)'} } */ + svdot (x, x, x); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svuint32_t&, svuint32_t&\)'} } */ + svdot (1, z, z); /* { dg-error {no matching function for call to 'svdot\(int, svuint8_t&, svuint8_t&\)'} } */ + svdot (x, y, z); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&, svuint8_t&\)'} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.h b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.h new file mode 100644 index 0000000..3e4a9c7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/dot_2.h @@ -0,0 +1,7 @@ +#pragma GCC system_header +#pragma GCC aarch64 "arm_sve.h" +/* { dg-message {note: candidate: 'svuint32_t svdot\(svuint32_t, svuint8_t, svuint8_t\)'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *candidate expects 3 arguments, 2 provided} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svuint32_t' to 'svuint8_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 1 from 'int' to 'svuint32_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svint8_t' to 'svuint8_t'} "" { target *-*-* } 3 } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_1.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_1.c new file mode 100644 index 0000000..8f18810 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_1.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svadd_n_u8_x; /* { dg-message "note: previous declaration 'int svadd_n_u8_x'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svuint8_t svadd_n_u8_x\(svbool_t, svuint8_t, [^)\n]*\)' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_2.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_2.c new file mode 100644 index 0000000..a67f9f7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svadd_n_u8_x = 1; /* { dg-message "note: previous declaration 'int svadd_n_u8_x'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svuint8_t svadd_n_u8_x\(svbool_t, svuint8_t, [^)\n]*\)' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_3.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_3.c new file mode 100644 index 0000000..74b820f --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +/* Although not supported, there's nothing to stop the user overloading + the sv* functions. */ +extern __SVInt8_t svadd_u8_x (__SVBool_t, __SVInt8_t, __SVInt8_t); + +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_4.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_4.c new file mode 100644 index 0000000..9591e3d --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_4.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +/* Although somewhat suspect, this isn't actively wrong, and doesn't need + to be diagnosed. Any attempt to call the function before including + arm_sve.h will lead to a link failure. (Same for taking its address, + etc.) */ +extern __SVUint8_t svadd_u8_x (__SVBool_t, __SVUint8_t, __SVUint8_t); + +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_5.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_5.c new file mode 100644 index 0000000..f872019 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +__SVUint8_t +svadd_u8_x (__SVBool_t pg, __SVUint8_t x, __SVUint8_t y) +{ + return x; +} + +#pragma GCC aarch64 "arm_sve.h" + +svuint8_t +f (svbool_t pg, svuint8_t x, svuint8_t y) +{ + return svadd_u8_x (pg, x, y); +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_6.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_6.c new file mode 100644 index 0000000..a65e0d6 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_6.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svadd_u8_x; /* { dg-message "note: previous declaration 'typedef int svadd_u8_x'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svuint8_t svadd_u8_x\(svbool_t, svuint8_t, svuint8_t\)' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_7.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_7.c new file mode 100644 index 0000000..1f2e4bf --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/func_redef_7.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +__SVUint8_t +svadd_x (__SVBool_t pg, __SVUint8_t x, __SVUint8_t y) +{ + return x; +} + +#pragma GCC aarch64 "arm_sve.h" + +svuint8_t +f (svbool_t pg, svuint8_t x, svuint8_t y) +{ + return svadd_x (pg, x, y); +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_1.C new file mode 100644 index 0000000..8d6bb23 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_1.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8 = svget2 (u8x2); /* { dg-error {no matching function for call to 'svget2\(svuint8x2_t\&\)'} } */ + u8 = svget2 (u8x2, 1, 2); /* { dg-error {no matching function for call to 'svget2\(svuint8x2_t\&, int, int\)'} } */ + u8 = svget2 (u8, 0); /* { dg-error {no matching function for call to 'svget2\(svuint8_t\&, int\)'} } */ + u8 = svget2 (u8x3, 0); /* { dg-error {no matching function for call to 'svget2\(svuint8x3_t\&, int\)'} } */ + u8 = svget2 (pg, 0); /* { dg-error {no matching function for call to 'svget2\(svbool_t\&, int\)'} } */ + u8 = svget2 (u8x2, x); /* { dg-error "argument 2 of 'svget2' must be an integer constant expression" } */ + u8 = svget2 (u8x2, 0); + f64 = svget2 (u8x2, 0); /* { dg-error "cannot convert 'svuint8_t' to 'svfloat64_t' in assignment" } */ + u8 = svget2 (u8x2, 1); + u8 = svget2 (u8x2, 2); /* { dg-error {passing 2 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 3); /* { dg-error {passing 3 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 4); /* { dg-error {passing 4 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 5); /* { dg-error {passing 5 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, one); + u8 = svget2 (u8x2, 3 - 2); + u8 = svget2 (u8x2, 1.0); + u8 = svget2 (u8x2, const_sub (5, 4)); + u8 = svget2 (u8x2, const_sub (6, 4)); /* { dg-error {passing 2 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, const_sub (7, 4)); /* { dg-error {passing 3 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, add (0, 0)); /* { dg-error "argument 2 of 'svget2' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_2.C new file mode 100644 index 0000000..9c7674b --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get2_2.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8 = svget2_u8 (u8x2); /* { dg-error {too few arguments to function '[^']*'} } */ + u8 = svget2_u8 (u8x2, 1, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + u8 = svget2_u8 (u8, 0); /* { dg-error {cannot convert 'svuint8_t' to 'svuint8x2_t'} } */ + u8 = svget2_u8 (u8x3, 0); /* { dg-error {cannot convert 'svuint8x3_t' to 'svuint8x2_t'} } */ + u8 = svget2_u8 (pg, 0); /* { dg-error {cannot convert 'svbool_t' to 'svuint8x2_t'} } */ + u8 = svget2_u8 (u8x2, x); /* { dg-error "argument 2 of 'svget2_u8' must be an integer constant expression" } */ + u8 = svget2_u8 (u8x2, 0); + f64 = svget2_u8 (u8x2, 0); /* { dg-error "cannot convert 'svuint8_t' to 'svfloat64_t' in assignment" } */ + u8 = svget2_u8 (u8x2, 1); + u8 = svget2_u8 (u8x2, 2); /* { dg-error {passing 2 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 3); /* { dg-error {passing 3 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 4); /* { dg-error {passing 4 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 5); /* { dg-error {passing 5 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, one); + u8 = svget2_u8 (u8x2, 3 - 2); + u8 = svget2_u8 (u8x2, 1.0); + u8 = svget2_u8 (u8x2, const_sub (5, 4)); + u8 = svget2_u8 (u8x2, const_sub (6, 4)); /* { dg-error {passing 2 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, const_sub (7, 4)); /* { dg-error {passing 3 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, add (0, 0)); /* { dg-error "argument 2 of 'svget2_u8' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_1.C new file mode 100644 index 0000000..bd8808a --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_1.C @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svfloat16x4_t f16x4, + int x) +{ + const int one = 1; + svfloat64_t f64; + + f16 = svget3 (f16x3); /* { dg-error {no matching function for call to 'svget3\(svfloat16x3_t\&\)'} } */ + f16 = svget3 (f16x3, 1, 2); /* { dg-error {no matching function for call to 'svget3\(svfloat16x3_t\&, int, int\)'} } */ + f16 = svget3 (f16, 0); /* { dg-error {no matching function for call to 'svget3\(svfloat16_t\&, int\)'} } */ + f16 = svget3 (f16x4, 0); /* { dg-error {no matching function for call to 'svget3\(svfloat16x4_t\&, int\)'} } */ + f16 = svget3 (pg, 0); /* { dg-error {no matching function for call to 'svget3\(svbool_t\&, int\)'} } */ + f16 = svget3 (f16x3, x); /* { dg-error "argument 2 of 'svget3' must be an integer constant expression" } */ + f16 = svget3 (f16x3, 0); + f64 = svget3 (f16x3, 0); /* { dg-error "cannot convert 'svfloat16_t' to 'svfloat64_t' in assignment" } */ + f16 = svget3 (f16x3, 1); + f16 = svget3 (f16x3, 2); + f16 = svget3 (f16x3, 3); /* { dg-error {passing 3 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, 4); /* { dg-error {passing 4 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, 5); /* { dg-error {passing 5 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, one); + f16 = svget3 (f16x3, 3 - 2); + f16 = svget3 (f16x3, 1.0); + f16 = svget3 (f16x3, const_sub (5, 4)); + f16 = svget3 (f16x3, const_sub (6, 4)); + f16 = svget3 (f16x3, const_sub (7, 4)); /* { dg-error {passing 3 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, add (0, 0)); /* { dg-error "argument 2 of 'svget3' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_2.C new file mode 100644 index 0000000..d526947 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get3_2.C @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svfloat16x4_t f16x4, + int x) +{ + const int one = 1; + svfloat64_t f64; + + f16 = svget3_f16 (f16x3); /* { dg-error {too few arguments to function '[^']*'} } */ + f16 = svget3_f16 (f16x3, 1, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + f16 = svget3_f16 (f16, 0); /* { dg-error {cannot convert 'svfloat16_t' to 'svfloat16x3_t'} } */ + f16 = svget3_f16 (f16x4, 0); /* { dg-error {cannot convert 'svfloat16x4_t' to 'svfloat16x3_t'} } */ + f16 = svget3_f16 (pg, 0); /* { dg-error {cannot convert 'svbool_t' to 'svfloat16x3_t'} } */ + f16 = svget3_f16 (f16x3, x); /* { dg-error "argument 2 of 'svget3_f16' must be an integer constant expression" } */ + f16 = svget3_f16 (f16x3, 0); + f64 = svget3_f16 (f16x3, 0); /* { dg-error "cannot convert 'svfloat16_t' to 'svfloat64_t' in assignment" } */ + f16 = svget3_f16 (f16x3, 1); + f16 = svget3_f16 (f16x3, 2); + f16 = svget3_f16 (f16x3, 3); /* { dg-error {passing 3 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, 4); /* { dg-error {passing 4 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, 5); /* { dg-error {passing 5 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, one); + f16 = svget3_f16 (f16x3, 3 - 2); + f16 = svget3_f16 (f16x3, 1.0); + f16 = svget3_f16 (f16x3, const_sub (5, 4)); + f16 = svget3_f16 (f16x3, const_sub (6, 4)); + f16 = svget3_f16 (f16x3, const_sub (7, 4)); /* { dg-error {passing 3 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, add (0, 0)); /* { dg-error "argument 2 of 'svget3_f16' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_1.C new file mode 100644 index 0000000..19853de --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_1.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32 = svget4 (s32x4); /* { dg-error {no matching function for call to 'svget4\(svint32x4_t\&\)'} } */ + s32 = svget4 (s32x4, 1, 2); /* { dg-error {no matching function for call to 'svget4\(svint32x4_t\&, int, int\)'} } */ + s32 = svget4 (s32, 0); /* { dg-error {no matching function for call to 'svget4\(svint32_t\&, int\)'} } */ + s32 = svget4 (s32x2, 0); /* { dg-error {no matching function for call to 'svget4\(svint32x2_t\&, int\)'} } */ + s32 = svget4 (pg, 0); /* { dg-error {no matching function for call to 'svget4\(svbool_t\&, int\)'} } */ + s32 = svget4 (s32x4, x); /* { dg-error "argument 2 of 'svget4' must be an integer constant expression" } */ + s32 = svget4 (s32x4, 0); + f64 = svget4 (s32x4, 0); /* { dg-error "cannot convert 'svint32_t' to 'svfloat64_t' in assignment" } */ + s32 = svget4 (s32x4, 1); + s32 = svget4 (s32x4, 2); + s32 = svget4 (s32x4, 3); + s32 = svget4 (s32x4, 4); /* { dg-error {passing 4 to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, 5); /* { dg-error {passing 5 to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, one); + s32 = svget4 (s32x4, 3 - 2); + s32 = svget4 (s32x4, 1.0); + s32 = svget4 (s32x4, const_sub (5, 4)); + s32 = svget4 (s32x4, const_sub (6, 4)); + s32 = svget4 (s32x4, const_sub (7, 4)); + s32 = svget4 (s32x4, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, add (0, 0)); /* { dg-error "argument 2 of 'svget4' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_2.C new file mode 100644 index 0000000..7a09792 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/get4_2.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32 = svget4_s32 (s32x4); /* { dg-error {too few arguments to function '[^']*'} } */ + s32 = svget4_s32 (s32x4, 1, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + s32 = svget4_s32 (s32, 0); /* { dg-error {cannot convert 'svint32_t' to 'svint32x4_t'} } */ + s32 = svget4_s32 (s32x2, 0); /* { dg-error {cannot convert 'svint32x2_t' to 'svint32x4_t'} } */ + s32 = svget4_s32 (pg, 0); /* { dg-error {cannot convert 'svbool_t' to 'svint32x4_t'} } */ + s32 = svget4_s32 (s32x4, x); /* { dg-error "argument 2 of 'svget4_s32' must be an integer constant expression" } */ + s32 = svget4_s32 (s32x4, 0); + f64 = svget4_s32 (s32x4, 0); /* { dg-error "cannot convert 'svint32_t' to 'svfloat64_t' in assignment" } */ + s32 = svget4_s32 (s32x4, 1); + s32 = svget4_s32 (s32x4, 2); + s32 = svget4_s32 (s32x4, 3); + s32 = svget4_s32 (s32x4, 4); /* { dg-error {passing 4 to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, 5); /* { dg-error {passing 5 to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, one); + s32 = svget4_s32 (s32x4, 3 - 2); + s32 = svget4_s32 (s32x4, 1.0); + s32 = svget4_s32 (s32x4, const_sub (5, 4)); + s32 = svget4_s32 (s32x4, const_sub (6, 4)); + s32 = svget4_s32 (s32x4, const_sub (7, 4)); + s32 = svget4_s32 (s32x4, const_sub (8, 4)); /* { dg-error {passing 4 to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, add (0, 0)); /* { dg-error "argument 2 of 'svget4_s32' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_1.C new file mode 100644 index 0000000..fb31e94 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_1.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, svuint8_t x, svint8_t w, svuint64_t y) +{ + svlsl_wide_u8_x (pg, x, x); /* { dg-error "cannot convert 'svuint8_t' to 'svuint64_t'" } */ + svlsl_wide_u8_x (pg, x); /* { dg-error {too few arguments to function 'svuint8_t svlsl_wide_u8_x\(svbool_t, svuint8_t, svuint64_t\)'} } */ + svlsl_wide_u8_x (pg, x, y, x); /* { dg-error {too many arguments to function 'svuint8_t svlsl_wide_u8_x\(svbool_t, svuint8_t, svuint64_t\)'} } */ + return svlsl_wide_s8_x (pg, w, y); /* { dg-error {cannot convert 'svint8_t' to 'svuint8_t' in return} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_2.C new file mode 100644 index 0000000..95d341d --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/lsl_wide_2.C @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +void +f1 (svbool_t pg, svuint8_t x, svuint64_t y) +{ + svlsl_wide_x (pg, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&\)'} } */ + svlsl_wide_x (pg, x, x, x, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&, svuint8_t&, svuint8_t&, svuint8_t&\)'} } */ + svlsl_wide_x (x, x, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svuint8_t&, svuint8_t&, svuint64_t&\)'} } */ + svlsl_wide_x (pg, 1, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, int, svuint64_t&\)'} } */ + svlsl_wide_x (pg, x, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&, svuint8_t&\)'} } */ + svlsl_wide_x (pg, y, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint64_t&, svuint64_t&\)'} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C new file mode 100644 index 0000000..1138f2e --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_1.C @@ -0,0 +1,29 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void f1(svbool_t) {} +void f2(svint8_t) {} +void f3(svint16_t) {} +void f4(svint32_t) {} +void f5(svint64_t) {} +void f6(svuint8_t) {} +void f7(svuint16_t) {} +void f8(svuint32_t) {} +void f9(svuint64_t) {} +void f10(svfloat16_t) {} +void f11(svfloat32_t) {} +void f12(svfloat64_t) {} + +/* { dg-final { scan-assembler "_Z2f110__SVBool_t:" } } */ +/* { dg-final { scan-assembler "_Z2f210__SVInt8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f311__SVInt16_t:" } } */ +/* { dg-final { scan-assembler "_Z2f411__SVInt32_t:" } } */ +/* { dg-final { scan-assembler "_Z2f511__SVInt64_t:" } } */ +/* { dg-final { scan-assembler "_Z2f611__SVUint8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f712__SVUint16_t:" } } */ +/* { dg-final { scan-assembler "_Z2f812__SVUint32_t:" } } */ +/* { dg-final { scan-assembler "_Z2f912__SVUint64_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1013__SVFloat16_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1113__SVFloat32_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1213__SVFloat64_t:" } } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C new file mode 100644 index 0000000..575b262 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_2.C @@ -0,0 +1,27 @@ +/* { dg-do compile } */ + +void f1(__SVBool_t) {} +void f2(__SVInt8_t) {} +void f3(__SVInt16_t) {} +void f4(__SVInt32_t) {} +void f5(__SVInt64_t) {} +void f6(__SVUint8_t) {} +void f7(__SVUint16_t) {} +void f8(__SVUint32_t) {} +void f9(__SVUint64_t) {} +void f10(__SVFloat16_t) {} +void f11(__SVFloat32_t) {} +void f12(__SVFloat64_t) {} + +/* { dg-final { scan-assembler "_Z2f110__SVBool_t:" } } */ +/* { dg-final { scan-assembler "_Z2f210__SVInt8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f311__SVInt16_t:" } } */ +/* { dg-final { scan-assembler "_Z2f411__SVInt32_t:" } } */ +/* { dg-final { scan-assembler "_Z2f511__SVInt64_t:" } } */ +/* { dg-final { scan-assembler "_Z2f611__SVUint8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f712__SVUint16_t:" } } */ +/* { dg-final { scan-assembler "_Z2f812__SVUint32_t:" } } */ +/* { dg-final { scan-assembler "_Z2f912__SVUint64_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1013__SVFloat16_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1113__SVFloat32_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1213__SVFloat64_t:" } } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_3.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_3.C new file mode 100644 index 0000000..8f64f7c --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_3.C @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-msve-vector-bits=256" } */ + +#include <arm_sve.h> + +typedef __SVInt8_t t1; +typedef svint8_t t2; +/* Distinct from svint8_t, but compatible with it. */ +typedef int8_t t3 __attribute__((vector_size(32))); + +void f1(t1) {} +void f2(t2) {} +void f3(t3) {} +void f4(t1 &a, t2 &b, t3 &c) { a = b = c; } + +/* { dg-final { scan-assembler "_Z2f110__SVInt8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f210__SVInt8_t:" } } */ +/* { dg-final { scan-assembler "_Z2f3Dv32_a:" } } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_4.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_4.C new file mode 100644 index 0000000..7cdc6cb --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/mangle_4.C @@ -0,0 +1,75 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void f1(svint8x2_t) {} +void f2(svint16x2_t) {} +void f3(svint32x2_t) {} +void f4(svint64x2_t) {} +void f5(svuint8x2_t) {} +void f6(svuint16x2_t) {} +void f7(svuint32x2_t) {} +void f8(svuint64x2_t) {} +void f9(svfloat16x2_t) {} +void f10(svfloat32x2_t) {} +void f11(svfloat64x2_t) {} + +void g1(svint8x3_t) {} +void g2(svint16x3_t) {} +void g3(svint32x3_t) {} +void g4(svint64x3_t) {} +void g5(svuint8x3_t) {} +void g6(svuint16x3_t) {} +void g7(svuint32x3_t) {} +void g8(svuint64x3_t) {} +void g9(svfloat16x3_t) {} +void g10(svfloat32x3_t) {} +void g11(svfloat64x3_t) {} + +void h1(svint8x4_t) {} +void h2(svint16x4_t) {} +void h3(svint32x4_t) {} +void h4(svint64x4_t) {} +void h5(svuint8x4_t) {} +void h6(svuint16x4_t) {} +void h7(svuint32x4_t) {} +void h8(svuint64x4_t) {} +void h9(svfloat16x4_t) {} +void h10(svfloat32x4_t) {} +void h11(svfloat64x4_t) {} + +/* { dg-final { scan-assembler "_Z2f110svint8x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f211svint16x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f311svint32x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f411svint64x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f511svuint8x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f612svuint16x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f712svuint32x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f812svuint64x2_t:" } } */ +/* { dg-final { scan-assembler "_Z2f913svfloat16x2_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1013svfloat32x2_t:" } } */ +/* { dg-final { scan-assembler "_Z3f1113svfloat64x2_t:" } } */ + +/* { dg-final { scan-assembler "_Z2g110svint8x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g211svint16x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g311svint32x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g411svint64x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g511svuint8x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g612svuint16x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g712svuint32x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g812svuint64x3_t:" } } */ +/* { dg-final { scan-assembler "_Z2g913svfloat16x3_t:" } } */ +/* { dg-final { scan-assembler "_Z3g1013svfloat32x3_t:" } } */ +/* { dg-final { scan-assembler "_Z3g1113svfloat64x3_t:" } } */ + +/* { dg-final { scan-assembler "_Z2h110svint8x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h211svint16x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h311svint32x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h411svint64x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h511svuint8x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h612svuint16x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h712svuint32x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h812svuint64x4_t:" } } */ +/* { dg-final { scan-assembler "_Z2h913svfloat16x4_t:" } } */ +/* { dg-final { scan-assembler "_Z3h1013svfloat32x4_t:" } } */ +/* { dg-final { scan-assembler "_Z3h1113svfloat64x4_t:" } } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_1.C new file mode 100644 index 0000000..80c3ad7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_1.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svint8x2_t s8x2, + svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8x2 = svset2 (u8x2); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&\)'} } */ + u8x2 = svset2 (u8x2, 1); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&, int\)'} } */ + u8x2 = svset2 (u8x2, 1, u8, 2); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&, int, svuint8_t\&, int\)'} } */ + u8x2 = svset2 (u8, 0, u8); /* { dg-error {no matching function for call to 'svset2\(svuint8_t\&, int, svuint8_t\&\)'} } */ + u8x2 = svset2 (s8x2, 0, u8); /* { dg-error {no matching function for call to 'svset2\(svint8x2_t\&, int, svuint8_t\&\)'} } */ + u8x2 = svset2 (u8x3, 0, u8); /* { dg-error {no matching function for call to 'svset2\(svuint8x3_t\&, int, svuint8_t\&\)'} } */ + u8x2 = svset2 (pg, 0, u8); /* { dg-error {no matching function for call to 'svset2\(svbool_t\&, int, svuint8_t\&\)'} } */ + u8x2 = svset2 (u8x2, 0, f64); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&, int, svfloat64_t\&\)'} } */ + u8x2 = svset2 (u8x2, 0, u8x2); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&, int, svuint8x2_t\&\)'} } */ + u8x2 = svset2 (u8x2, 0, pg); /* { dg-error {no matching function for call to 'svset2\(svuint8x2_t\&, int, svbool_t\&\)'} } */ + u8x2 = svset2 (u8x2, x, u8); /* { dg-error "argument 2 of 'svset2' must be an integer constant expression" } */ + u8x2 = svset2 (u8x2, 0, u8); + s8x2 = svset2 (u8x2, 0, u8); /* { dg-error {cannot convert 'svuint8x2_t' to 'svint8x2_t' in assignment} } */ + u8x2 = svset2 (u8x2, 1, u8); + u8x2 = svset2 (u8x2, 2, u8); /* { dg-error {passing 2 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 3, u8); /* { dg-error {passing 3 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 4, u8); /* { dg-error {passing 4 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 5, u8); /* { dg-error {passing 5 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, ~0U, u8); /* { dg-error {passing [^ ]* to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, one, u8); + u8x2 = svset2 (u8x2, 3 - 2, u8); + u8x2 = svset2 (u8x2, 1.0, u8); + u8x2 = svset2 (u8x2, const_sub (5, 4), u8); + u8x2 = svset2 (u8x2, const_sub (6, 4), u8); /* { dg-error {passing 2 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, const_sub (7, 4), u8); /* { dg-error {passing 3 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, const_sub (8, 4), u8); /* { dg-error {passing 4 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, add (0, 0), u8); /* { dg-error "argument 2 of 'svset2' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_2.C new file mode 100644 index 0000000..1433b78 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set2_2.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svint8x2_t s8x2, + svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8x2 = svset2_u8 (u8x2); /* { dg-error {too few arguments to function '[^']*'} } */ + u8x2 = svset2_u8 (u8x2, 1); /* { dg-error {too few arguments to function '[^']*'} } */ + u8x2 = svset2_u8 (u8x2, 1, u8, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + u8x2 = svset2_u8 (u8, 0, u8); /* { dg-error {cannot convert 'svuint8_t' to 'svuint8x2_t'} } */ + u8x2 = svset2_u8 (s8x2, 0, u8); /* { dg-error {cannot convert 'svint8x2_t' to 'svuint8x2_t'} } */ + u8x2 = svset2_u8 (u8x3, 0, u8); /* { dg-error {cannot convert 'svuint8x3_t' to 'svuint8x2_t'} } */ + u8x2 = svset2_u8 (pg, 0, u8); /* { dg-error {cannot convert 'svbool_t' to 'svuint8x2_t'} } */ + u8x2 = svset2_u8 (u8x2, 0, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svuint8_t'} } */ + u8x2 = svset2_u8 (u8x2, 0, u8x2); /* { dg-error {cannot convert 'svuint8x2_t' to 'svuint8_t'} } */ + u8x2 = svset2_u8 (u8x2, 0, pg); /* { dg-error {cannot convert 'svbool_t' to 'svuint8_t'} } */ + u8x2 = svset2_u8 (u8x2, x, u8); /* { dg-error "argument 2 of 'svset2_u8' must be an integer constant expression" } */ + u8x2 = svset2_u8 (u8x2, 0, u8); + s8x2 = svset2_u8 (u8x2, 0, u8); /* { dg-error {cannot convert 'svuint8x2_t' to 'svint8x2_t' in assignment} } */ + u8x2 = svset2_u8 (u8x2, 1, u8); + u8x2 = svset2_u8 (u8x2, 2, u8); /* { dg-error {passing 2 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 3, u8); /* { dg-error {passing 3 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 4, u8); /* { dg-error {passing 4 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 5, u8); /* { dg-error {passing 5 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, ~0U, u8); /* { dg-error {passing [^ ]* to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, one, u8); + u8x2 = svset2_u8 (u8x2, 3 - 2, u8); + u8x2 = svset2_u8 (u8x2, 1.0, u8); + u8x2 = svset2_u8 (u8x2, const_sub (5, 4), u8); + u8x2 = svset2_u8 (u8x2, const_sub (6, 4), u8); /* { dg-error {passing 2 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, const_sub (7, 4), u8); /* { dg-error {passing 3 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, const_sub (8, 4), u8); /* { dg-error {passing 4 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, add (0, 0), u8); /* { dg-error "argument 2 of 'svset2_u8' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_1.C new file mode 100644 index 0000000..9bb4f7a --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_1.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svuint16x3_t u16x3, + svfloat16x4_t f16x4, int x) +{ + const int one = 1; + svfloat64_t f64; + + f16x3 = svset3 (f16x3); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&\)'} } */ + f16x3 = svset3 (f16x3, 1); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&, int\)'} } */ + f16x3 = svset3 (f16x3, 1, f16, 2); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&, int, svfloat16_t\&, int\)'} } */ + f16x3 = svset3 (f16, 0, f16); /* { dg-error {no matching function for call to 'svset3\(svfloat16_t\&, int, svfloat16_t\&\)'} } */ + f16x3 = svset3 (u16x3, 0, f16); /* { dg-error {no matching function for call to 'svset3\(svuint16x3_t\&, int, svfloat16_t\&\)'} } */ + f16x3 = svset3 (f16x4, 0, f16); /* { dg-error {no matching function for call to 'svset3\(svfloat16x4_t\&, int, svfloat16_t\&\)'} } */ + f16x3 = svset3 (pg, 0, f16); /* { dg-error {no matching function for call to 'svset3\(svbool_t\&, int, svfloat16_t\&\)'} } */ + f16x3 = svset3 (f16x3, 0, f64); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&, int, svfloat64_t\&\)'} } */ + f16x3 = svset3 (f16x3, 0, f16x3); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&, int, svfloat16x3_t\&\)'} } */ + f16x3 = svset3 (f16x3, 0, pg); /* { dg-error {no matching function for call to 'svset3\(svfloat16x3_t\&, int, svbool_t\&\)'} } */ + f16x3 = svset3 (f16x3, x, f16); /* { dg-error "argument 2 of 'svset3' must be an integer constant expression" } */ + f16x3 = svset3 (f16x3, 0, f16); + u16x3 = svset3 (f16x3, 0, f16); /* { dg-error {cannot convert 'svfloat16x3_t' to 'svuint16x3_t' in assignment} } */ + f16x3 = svset3 (f16x3, 1, f16); + f16x3 = svset3 (f16x3, 2, f16); + f16x3 = svset3 (f16x3, 3, f16); /* { dg-error {passing 3 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, 4, f16); /* { dg-error {passing 4 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, 5, f16); /* { dg-error {passing 5 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, ~0U, f16); /* { dg-error {passing [^ ]* to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, one, f16); + f16x3 = svset3 (f16x3, 3 - 2, f16); + f16x3 = svset3 (f16x3, 1.0, f16); + f16x3 = svset3 (f16x3, const_sub (5, 4), f16); + f16x3 = svset3 (f16x3, const_sub (6, 4), f16); + f16x3 = svset3 (f16x3, const_sub (7, 4), f16); /* { dg-error {passing 3 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, const_sub (8, 4), f16); /* { dg-error {passing 4 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, add (0, 0), f16); /* { dg-error "argument 2 of 'svset3' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_2.C new file mode 100644 index 0000000..0bb6049 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set3_2.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svuint16x3_t u16x3, + svfloat16x4_t f16x4, int x) +{ + const int one = 1; + svfloat64_t f64; + + f16x3 = svset3_f16 (f16x3); /* { dg-error {too few arguments to function '[^']*'} } */ + f16x3 = svset3_f16 (f16x3, 1); /* { dg-error {too few arguments to function '[^']*'} } */ + f16x3 = svset3_f16 (f16x3, 1, f16, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + f16x3 = svset3_f16 (f16, 0, f16); /* { dg-error {cannot convert 'svfloat16_t' to 'svfloat16x3_t'} } */ + f16x3 = svset3_f16 (u16x3, 0, f16); /* { dg-error {cannot convert 'svuint16x3_t' to 'svfloat16x3_t'} } */ + f16x3 = svset3_f16 (f16x4, 0, f16); /* { dg-error {cannot convert 'svfloat16x4_t' to 'svfloat16x3_t'} } */ + f16x3 = svset3_f16 (pg, 0, f16); /* { dg-error {cannot convert 'svbool_t' to 'svfloat16x3_t'} } */ + f16x3 = svset3_f16 (f16x3, 0, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svfloat16_t'} } */ + f16x3 = svset3_f16 (f16x3, 0, f16x3); /* { dg-error {cannot convert 'svfloat16x3_t' to 'svfloat16_t'} } */ + f16x3 = svset3_f16 (f16x3, 0, pg); /* { dg-error {cannot convert 'svbool_t' to 'svfloat16_t'} } */ + f16x3 = svset3_f16 (f16x3, x, f16); /* { dg-error "argument 2 of 'svset3_f16' must be an integer constant expression" } */ + f16x3 = svset3_f16 (f16x3, 0, f16); + u16x3 = svset3_f16 (f16x3, 0, f16); /* { dg-error {cannot convert 'svfloat16x3_t' to 'svuint16x3_t' in assignment} } */ + f16x3 = svset3_f16 (f16x3, 1, f16); + f16x3 = svset3_f16 (f16x3, 2, f16); + f16x3 = svset3_f16 (f16x3, 3, f16); /* { dg-error {passing 3 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, 4, f16); /* { dg-error {passing 4 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, 5, f16); /* { dg-error {passing 5 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, ~0U, f16); /* { dg-error {passing [^ ]* to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, one, f16); + f16x3 = svset3_f16 (f16x3, 3 - 2, f16); + f16x3 = svset3_f16 (f16x3, 1.0, f16); + f16x3 = svset3_f16 (f16x3, const_sub (5, 4), f16); + f16x3 = svset3_f16 (f16x3, const_sub (6, 4), f16); + f16x3 = svset3_f16 (f16x3, const_sub (7, 4), f16); /* { dg-error {passing 3 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, const_sub (8, 4), f16); /* { dg-error {passing 4 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, add (0, 0), f16); /* { dg-error "argument 2 of 'svset3_f16' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_1.C new file mode 100644 index 0000000..dc5dae8 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_1.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svfloat32x4_t f32x4, + svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32x4 = svset4 (s32x4); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&\)'} } */ + s32x4 = svset4 (s32x4, 1); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&, int\)'} } */ + s32x4 = svset4 (s32x4, 1, s32, 2); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&, int, svint32_t\&, int\)'} } */ + s32x4 = svset4 (s32, 0, s32); /* { dg-error {no matching function for call to 'svset4\(svint32_t\&, int, svint32_t\&\)'} } */ + s32x4 = svset4 (f32x4, 0, s32); /* { dg-error {no matching function for call to 'svset4\(svfloat32x4_t\&, int, svint32_t\&\)'} } */ + s32x4 = svset4 (s32x2, 0, s32); /* { dg-error {no matching function for call to 'svset4\(svint32x2_t\&, int, svint32_t\&\)'} } */ + s32x4 = svset4 (pg, 0, s32); /* { dg-error {no matching function for call to 'svset4\(svbool_t\&, int, svint32_t\&\)'} } */ + s32x4 = svset4 (s32x4, 0, f64); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&, int, svfloat64_t\&\)'} } */ + s32x4 = svset4 (s32x4, 0, s32x4); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&, int, svint32x4_t\&\)'} } */ + s32x4 = svset4 (s32x4, 0, pg); /* { dg-error {no matching function for call to 'svset4\(svint32x4_t\&, int, svbool_t\&\)'} } */ + s32x4 = svset4 (s32x4, x, s32); /* { dg-error "argument 2 of 'svset4' must be an integer constant expression" } */ + s32x4 = svset4 (s32x4, 0, s32); + f32x4 = svset4 (s32x4, 0, s32); /* { dg-error {cannot convert 'svint32x4_t' to 'svfloat32x4_t' in assignment} } */ + s32x4 = svset4 (s32x4, 1, s32); + s32x4 = svset4 (s32x4, 2, s32); + s32x4 = svset4 (s32x4, 3, s32); + s32x4 = svset4 (s32x4, 4, s32); /* { dg-error {passing 4 to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, 5, s32); /* { dg-error {passing 5 to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, ~0U, s32); /* { dg-error {passing [^ ]* to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, one, s32); + s32x4 = svset4 (s32x4, 3 - 2, s32); + s32x4 = svset4 (s32x4, 1.0, s32); + s32x4 = svset4 (s32x4, const_sub (5, 4), s32); + s32x4 = svset4 (s32x4, const_sub (6, 4), s32); + s32x4 = svset4 (s32x4, const_sub (7, 4), s32); + s32x4 = svset4 (s32x4, const_sub (8, 4), s32); /* { dg-error {passing 4 to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, add (0, 0), s32); /* { dg-error "argument 2 of 'svset4' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_2.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_2.C new file mode 100644 index 0000000..762a6db --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/set4_2.C @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_sub (uint64_t a, uint64_t b) { return a - b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svfloat32x4_t f32x4, + svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32x4 = svset4_s32 (s32x4); /* { dg-error {too few arguments to function '[^']*'} } */ + s32x4 = svset4_s32 (s32x4, 1); /* { dg-error {too few arguments to function '[^']*'} } */ + s32x4 = svset4_s32 (s32x4, 1, s32, 2); /* { dg-error {too many arguments to function '[^']*'} } */ + s32x4 = svset4_s32 (s32, 0, s32); /* { dg-error {cannot convert 'svint32_t' to 'svint32x4_t'} } */ + s32x4 = svset4_s32 (f32x4, 0, s32); /* { dg-error {cannot convert 'svfloat32x4_t' to 'svint32x4_t'} } */ + s32x4 = svset4_s32 (s32x2, 0, s32); /* { dg-error {cannot convert 'svint32x2_t' to 'svint32x4_t'} } */ + s32x4 = svset4_s32 (pg, 0, s32); /* { dg-error {cannot convert 'svbool_t' to 'svint32x4_t'} } */ + s32x4 = svset4_s32 (s32x4, 0, f64); /* { dg-error {cannot convert 'svfloat64_t' to 'svint32_t'} } */ + s32x4 = svset4_s32 (s32x4, 0, s32x4); /* { dg-error {cannot convert 'svint32x4_t' to 'svint32_t'} } */ + s32x4 = svset4_s32 (s32x4, 0, pg); /* { dg-error {cannot convert 'svbool_t' to 'svint32_t'} } */ + s32x4 = svset4_s32 (s32x4, x, s32); /* { dg-error "argument 2 of 'svset4_s32' must be an integer constant expression" } */ + s32x4 = svset4_s32 (s32x4, 0, s32); + f32x4 = svset4_s32 (s32x4, 0, s32); /* { dg-error {cannot convert 'svint32x4_t' to 'svfloat32x4_t' in assignment} } */ + s32x4 = svset4_s32 (s32x4, 1, s32); + s32x4 = svset4_s32 (s32x4, 2, s32); + s32x4 = svset4_s32 (s32x4, 3, s32); + s32x4 = svset4_s32 (s32x4, 4, s32); /* { dg-error {passing 4 to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, 5, s32); /* { dg-error {passing 5 to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, ~0U, s32); /* { dg-error {passing [^ ]* to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, one, s32); + s32x4 = svset4_s32 (s32x4, 3 - 2, s32); + s32x4 = svset4_s32 (s32x4, 1.0, s32); + s32x4 = svset4_s32 (s32x4, const_sub (5, 4), s32); + s32x4 = svset4_s32 (s32x4, const_sub (6, 4), s32); + s32x4 = svset4_s32 (s32x4, const_sub (7, 4), s32); + s32x4 = svset4_s32 (s32x4, const_sub (8, 4), s32); /* { dg-error {passing 4 to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, add (0, 0), s32); /* { dg-error "argument 2 of 'svset4_s32' must be an integer constant expression" } */ + + return f64; +} diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_1.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_1.c new file mode 100644 index 0000000..ff25900 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_1.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svbool_t; /* { dg-message "note: previous declaration 'int svbool_t'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'typedef [^'\n]* svbool_t' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_10.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_10.c new file mode 100644 index 0000000..86d87fa --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_10.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration 'typedef struct svint8x2_t svint8x2_t'} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_11.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_11.c new file mode 100644 index 0000000..741d10e --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_11.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +struct svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration 'typedef struct svint8x2_t svint8x2_t'} } */ + +svint8_t f (svint8x2_t x) { return x.__val[0]; } /* { dg-error {'x' has incomplete type} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_12.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_12.c new file mode 100644 index 0000000..fc6a07a --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_12.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +typedef struct svint8x2_t svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration 'typedef struct svint8x2_t svint8x2_t'} } */ + +svint8_t f (svint8x2_t x) { return x.__val[0]; } /* { dg-error {'x' has incomplete type} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_13.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_13.c new file mode 100644 index 0000000..161aacb --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_13.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +struct svint8x2_t {}; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration 'typedef struct svint8x2_t svint8x2_t'} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_14.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_14.c new file mode 100644 index 0000000..8319111 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_14.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +enum svpattern { FOO }; /* { dg-message "note: previous definition here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error "multiple definition of 'enum svpattern'" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_15.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_15.c new file mode 100644 index 0000000..71e35a4 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_15.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +enum svpattern { FOO }; /* { dg-error "multiple definition of 'enum svpattern'" } */ +enum foo { SV_ALL }; /* { dg-error "'SV_ALL' conflicts with a previous declaration" } */ +typedef int SV_POW2; /* { dg-error "'typedef int SV_POW2' redeclared as different kind of entity" } */ +int SV_VL3; /* { dg-error "'int SV_VL3' redeclared as different kind of entity" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_16.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_16.c new file mode 100644 index 0000000..277064d --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_16.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +struct svpattern { int x; }; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error "'svpattern' referred to as enum" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_17.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_17.c new file mode 100644 index 0000000..e4bcda6 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_17.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +struct svpattern { int x; }; /* { dg-error "'svpattern' referred to as 'struct'" } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_18.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_18.c new file mode 100644 index 0000000..b670615 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_18.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svpattern; /* OK in C. */ + +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_19.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_19.c new file mode 100644 index 0000000..c6379f7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_19.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +int svpattern; /* OK in C. */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_2.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_2.c new file mode 100644 index 0000000..5baf599 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svint8_t; /* { dg-message "note: previous declaration 'int svint8_t" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'typedef [^'\n]* svint8_t' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_20.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_20.c new file mode 100644 index 0000000..3ba19f5 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_20.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +enum foo { SV_VL4 }; +typedef int SV_POW2; +int SV_ALL; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error "'SV_VL4' conflicts with a previous declaration" } */ +/* { dg-error "'SV_POW2' redeclared as different kind of entity" "" { target *-*-* } .-1 } */ +/* { dg-error "'SV_ALL' redeclared as different kind of entity" "" { target *-*-* } .-2 } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_3.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_3.c new file mode 100644 index 0000000..a8d7bdc --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_3.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svuint16_t; /* { dg-message "note: previous declaration 'int svuint16_t'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'typedef [^'\n]* svuint16_t' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_4.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_4.c new file mode 100644 index 0000000..c0563d0 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_4.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svfloat32_t; /* { dg-message "note: previous declaration 'int svfloat32_t'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'typedef [^'\n]* svfloat32_t' redeclared as different kind of entity} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_5.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_5.c new file mode 100644 index 0000000..ee28e95 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_5.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svbool_t; /* { dg-message "note: previous declaration as 'typedef int svbool_t'" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration '[^'\n]* svbool_t'} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_6.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_6.c new file mode 100644 index 0000000..85c17ea --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_6.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ + +typedef __SVBool_t svbool_t; + +#pragma GCC aarch64 "arm_sve.h" + diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_7.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_7.c new file mode 100644 index 0000000..3a0dfb1 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_7.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +int svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'typedef struct svint8x2_t svint8x2_t' redeclared as different kind of entity} } */ + +void f (struct svint8x2_t) {} /* { dg-error {incomplete type} } */ +void g () { int &x = svint8x2_t; } diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_8.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_8.c new file mode 100644 index 0000000..9b0df91 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_8.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ + +struct svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting declaration 'typedef struct svint8x2_t svint8x2_t'} } */ + +void f (svint8x2_t) {} /* { dg-error {incomplete type} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_9.c b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_9.c new file mode 100644 index 0000000..43068da --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/type_redef_9.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +int svint8x2_t; /* { dg-error {'int svint8x2_t' redeclared as different kind of entity} } */ + +void f (struct svint8x2_t) {} /* { dg-error {using typedef-name 'svint8x2_t' after 'struct'} } */ +void g () { int &x = svint8x2_t; } /* { dg-error {expected primary-expression before ';' token} } */ diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/whilele_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/whilele_1.C new file mode 100644 index 0000000..9571e66 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/whilele_1.C @@ -0,0 +1,81 @@ +// { dg-do compile } + +#include <arm_sve.h> + +enum foo { A, B }; + +void +test (int8_t s8, int16_t s16, int32_t s32, int64_t s64, + uint8_t u8, uint16_t u16, uint32_t u32, uint64_t u64, + bool b, foo e, int *ptr, float f32, svbool_t pg, + svint32_t vec) +{ + svwhilele_b8 (s32); // { dg-error {no matching function for call to 'svwhilele_b8\(int32_t&\)'} } + svwhilele_b8 (s32, s32, s32); // { dg-error {no matching function for call to 'svwhilele_b8\(int32_t&, int32_t&, int32_t&\)'} } + + svwhilele_b8 (b, b); + svwhilele_b8 (e, e); + svwhilele_b8 (s8, s8); + svwhilele_b8 (u8, u8); + svwhilele_b8 (s16, s16); + svwhilele_b8 (u16, u16); + svwhilele_b8 (ptr, ptr); // { dg-error {no matching function for call to 'svwhilele_b8\(int\*&, int\*&\)'} } + // { dg-error {invalid conversion from 'int\*' to '[^']*'} "" { target *-*-* } .-1 } + svwhilele_b8 (f32, f32); // { dg-error {call of overloaded 'svwhilele_b8\(float&, float&\)' is ambiguous} } + svwhilele_b8 (pg, pg); // { dg-error {no matching function for call to 'svwhilele_b8\(svbool_t&, svbool_t&\)'} } + svwhilele_b8 (vec, vec); // { dg-error {no matching function for call to 'svwhilele_b8\(svint32_t&, svint32_t&\)'} } + + svwhilele_b8 (s32, b); + svwhilele_b8 (s32, e); + svwhilele_b8 (s32, s8); + svwhilele_b8 (s32, u8); + svwhilele_b8 (s32, s16); + svwhilele_b8 (s32, u16); + + svwhilele_b8 (u32, b); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, bool&\)' is ambiguous} } + svwhilele_b8 (u32, e); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, foo&\)' is ambiguous} } + svwhilele_b8 (u32, s8); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, int8_t&\)' is ambiguous} } + svwhilele_b8 (u32, u8); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, uint8_t&\)' is ambiguous} } + svwhilele_b8 (u32, s16); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, int16_t&\)' is ambiguous} } + svwhilele_b8 (u32, u16); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, uint16_t&\)' is ambiguous} } + + svwhilele_b8 (s32, s32); + svwhilele_b8 (s32, u32); // { dg-error {call of overloaded 'svwhilele_b8\(int32_t&, uint32_t&\)' is ambiguous} } + svwhilele_b8 (s32, s64); // { dg-error {call of overloaded 'svwhilele_b8\(int32_t&, int64_t&\)' is ambiguous} } + svwhilele_b8 (s32, u64); // { dg-error {call of overloaded 'svwhilele_b8\(int32_t&, uint64_t&\)' is ambiguous} } + + svwhilele_b8 (u32, s32); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, int32_t&\)' is ambiguous} } + svwhilele_b8 (u32, u32); + svwhilele_b8 (u32, s64); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, int64_t&\)' is ambiguous} } + svwhilele_b8 (u32, u64); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, uint64_t&\)' is ambiguous} } + + svwhilele_b8 (s64, s32); // { dg-error {call of overloaded 'svwhilele_b8\(int64_t&, int32_t&\)' is ambiguous} } + svwhilele_b8 (s64, u32); // { dg-error {call of overloaded 'svwhilele_b8\(int64_t&, uint32_t&\)' is ambiguous} } + svwhilele_b8 (s64, s64); + svwhilele_b8 (s64, u64); // { dg-error {call of overloaded 'svwhilele_b8\(int64_t&, uint64_t&\)' is ambiguous} } + + svwhilele_b8 (u64, s32); // { dg-error {call of overloaded 'svwhilele_b8\(uint64_t&, int32_t&\)' is ambiguous} } + svwhilele_b8 (u64, u32); // { dg-error {call of overloaded 'svwhilele_b8\(uint64_t&, uint32_t&\)' is ambiguous} } + svwhilele_b8 (u64, s64); // { dg-error {call of overloaded 'svwhilele_b8\(uint64_t&, int64_t&\)' is ambiguous} } + svwhilele_b8 (u64, u64); + + svwhilele_b8 (0, s32); + svwhilele_b8 (0, u32); // { dg-error {call of overloaded 'svwhilele_b8\(int, uint32_t&\)' is ambiguous} } + svwhilele_b8 (0, s64); // { dg-error {call of overloaded 'svwhilele_b8\(int, int64_t&\)' is ambiguous} } + svwhilele_b8 (0, u64); // { dg-error {call of overloaded 'svwhilele_b8\(int, uint64_t&\)' is ambiguous} } + + svwhilele_b8 (s32, 0); + svwhilele_b8 (u32, 0); // { dg-error {call of overloaded 'svwhilele_b8\(uint32_t&, int\)' is ambiguous} } + svwhilele_b8 (s64, 0); // { dg-error {call of overloaded 'svwhilele_b8\(int64_t&, int\)' is ambiguous} } + svwhilele_b8 (u64, 0); // { dg-error {call of overloaded 'svwhilele_b8\(uint64_t&, int\)' is ambiguous} } + + svwhilele_b8 (0U, s32); // { dg-error {call of overloaded 'svwhilele_b8\(unsigned int, int32_t&\)' is ambiguous} } + svwhilele_b8 (0U, u32); + svwhilele_b8 (0U, s64); // { dg-error {call of overloaded 'svwhilele_b8\(unsigned int, int64_t&\)' is ambiguous} } + svwhilele_b8 (0U, u64); // { dg-error {call of overloaded 'svwhilele_b8\(unsigned int, uint64_t&\)' is ambiguous} } + + svwhilele_b8 (s32, 0U); // { dg-error {call of overloaded 'svwhilele_b8\(int32_t&, unsigned int\)' is ambiguous} } + svwhilele_b8 (u32, 0U); + svwhilele_b8 (s64, 0U); // { dg-error {call of overloaded 'svwhilele_b8\(int64_t&, unsigned int\)' is ambiguous} } + svwhilele_b8 (u64, 0U); // { dg-error {call of overloaded 'svwhilele_b8\(uint64_t&, unsigned int\)' is ambiguous} } +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp new file mode 100644 index 0000000..34d9dfd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp @@ -0,0 +1,54 @@ +# Specific regression driver for AArch64 SVE. +# Copyright (C) 2009-2019 Free Software Foundation, Inc. +# Contributed by ARM Ltd. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. */ + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an AArch64 target. +if {![istarget aarch64*-*-*] } { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Force SVE if we're not testing it already. +if { [check_effective_target_aarch64_sve] } { + set sve_flags "" +} else { + set sve_flags "-march=armv8.2-a+sve" +} + +# Main loop. +# FIXME: This should include general/*.c too, but leave that until the +# C frontend allows initialization of SVE vectors. +set files [glob -nocomplain $srcdir/$subdir/general-c/*.c] +dg-runtest [lsort $files] "$sve_flags" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_index_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_index_1.c new file mode 100644 index 0000000..714265e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_index_1.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, uint32_t *u32_ptr, svuint8_t u8, svuint16_t u16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64) +{ + svadrh_index (u32); /* { dg-error {too few arguments to function 'svadrh_index'} } */ + svadrh_index (u32, u32, u32); /* { dg-error {too many arguments to function 'svadrh_index'} } */ + svadrh_index (u32_ptr, s32); /* { dg-error {passing '[^']*\*'[^\n]* to argument 1 of 'svadrh_index', which expects an SVE vector type} } */ + svadrh_index (0, s32); /* { dg-error {passing 'int' to argument 1 of 'svadrh_index', which expects an SVE vector type} } */ + svadrh_index (u16, u16); /* { dg-error {passing 'svuint16_t' to argument 1 of 'svadrh_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrh_index (s32, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svadrh_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrh_index (f32, s32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svadrh_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrh_index (pg, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svadrh_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + + svadrh_index (u32, 0); /* { dg-error {passing 'int' to argument 2 of 'svadrh_index', which expects an SVE vector type} } */ + svadrh_index (u32, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svadrh_index', which expects a vector of 32-bit or 64-bit integers} } */ + svadrh_index (u32, u16); /* { dg-error {passing 'svuint16_t' to argument 2 of 'svadrh_index', which expects a vector of 32-bit or 64-bit integers} } */ + svadrh_index (u32, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svadrh_index', which expects a vector of integers} } */ + + svadrh_index (u32, s32); + svadrh_index (u32, u32); + svadrh_index (u32, f32); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svadrh_index', which expects a vector of integers} } */ + svadrh_index (u32, s64); /* { dg-error {cannot combine a base of type 'svuint32_t' with an index of type 'svint64_t'} } */ + svadrh_index (u32, u64); /* { dg-error {cannot combine a base of type 'svuint32_t' with an index of type 'svuint64_t'} } */ + svadrh_index (u32, f64); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svadrh_index', which expects a vector of integers} } */ + + svadrh_index (u64, s32); /* { dg-error {cannot combine a base of type 'svuint64_t' with an index of type 'svint32_t'} } */ + svadrh_index (u64, u32); /* { dg-error {cannot combine a base of type 'svuint64_t' with an index of type 'svuint32_t'} } */ + svadrh_index (u64, f32); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svadrh_index', which expects a vector of integers} } */ + svadrh_index (u64, s64); + svadrh_index (u64, u64); + svadrh_index (u64, f64); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svadrh_index', which expects a vector of integers} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_offset_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_offset_1.c new file mode 100644 index 0000000..528d7ac --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/adr_offset_1.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, uint32_t *u32_ptr, svuint8_t u8, svuint16_t u16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64) +{ + svadrb_offset (u32); /* { dg-error {too few arguments to function 'svadrb_offset'} } */ + svadrb_offset (u32, u32, u32); /* { dg-error {too many arguments to function 'svadrb_offset'} } */ + svadrb_offset (u32_ptr, s32); /* { dg-error {passing '[^']*\*'[^\n]* to argument 1 of 'svadrb_offset', which expects an SVE vector type} } */ + svadrb_offset (0, s32); /* { dg-error {passing 'int' to argument 1 of 'svadrb_offset', which expects an SVE vector type} } */ + svadrb_offset (u16, u16); /* { dg-error {passing 'svuint16_t' to argument 1 of 'svadrb_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrb_offset (s32, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svadrb_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrb_offset (f32, s32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svadrb_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svadrb_offset (pg, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svadrb_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + + svadrb_offset (u32, 0); /* { dg-error {passing 'int' to argument 2 of 'svadrb_offset', which expects an SVE vector type} } */ + svadrb_offset (u32, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svadrb_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svadrb_offset (u32, u16); /* { dg-error {passing 'svuint16_t' to argument 2 of 'svadrb_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svadrb_offset (u32, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svadrb_offset', which expects a vector of integers} } */ + + svadrb_offset (u32, s32); + svadrb_offset (u32, u32); + svadrb_offset (u32, f32); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svadrb_offset', which expects a vector of integers} } */ + svadrb_offset (u32, s64); /* { dg-error {cannot combine a base of type 'svuint32_t' with an offset of type 'svint64_t'} } */ + svadrb_offset (u32, u64); /* { dg-error {cannot combine a base of type 'svuint32_t' with an offset of type 'svuint64_t'} } */ + svadrb_offset (u32, f64); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svadrb_offset', which expects a vector of integers} } */ + + svadrb_offset (u64, s32); /* { dg-error {cannot combine a base of type 'svuint64_t' with an offset of type 'svint32_t'} } */ + svadrb_offset (u64, u32); /* { dg-error {cannot combine a base of type 'svuint64_t' with an offset of type 'svuint32_t'} } */ + svadrb_offset (u64, f32); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svadrb_offset', which expects a vector of integers} } */ + svadrb_offset (u64, s64); + svadrb_offset (u64, u64); + svadrb_offset (u64, f64); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svadrb_offset', which expects a vector of integers} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_1.c new file mode 100644 index 0000000..8ce89fa --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, svuint8_t u8, svint16_t s16) +{ + svzip1 (pg); /* { dg-error {too few arguments to function 'svzip1'} } */ + svzip1 (pg, u8, u8); /* { dg-error {too many arguments to function 'svzip1'} } */ + svzip1 (pg, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svzip1', but previous arguments had type 'svbool_t'} } */ + svzip1 (u8, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svzip1', but previous arguments had type 'svuint8_t'} } */ + svzip1 (u8, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svzip1', but previous arguments had type 'svuint8_t'} } */ + svzip1 (u8, 0); /* { dg-error {passing 'int' to argument 2 of 'svzip1', which expects an SVE vector type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_int_opt_n.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_int_opt_n.c new file mode 100644 index 0000000..965e9a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_int_opt_n.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat16_t f16, svint16_t s16, svuint16_t u16, + svfloat32_t f32, svint32_t s32, svuint32_t u32) +{ + svscale_x (pg, f16); /* { dg-error {too few arguments to function 'svscale_x'} } */ + svscale_x (pg, f16, s16, s16); /* { dg-error {too many arguments to function 'svscale_x'} } */ + svscale_x (s32, f16, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svscale_x', which expects 'svbool_t'} } */ + svscale_x (1, f16, s32); /* { dg-error {passing 'int' to argument 1 of 'svscale_x', which expects 'svbool_t'} } */ + svscale_x (pg, pg, s16); /* { dg-error {'svscale_x' has no form that takes 'svbool_t' arguments} } */ + svscale_x (pg, 1, s16); /* { dg-error {passing 'int' to argument 2 of 'svscale_x', which expects an SVE vector type} } */ + svscale_x (pg, f16, s16); + svscale_x (pg, f16, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, f16, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, f16, s32); /* { dg-error {arguments 2 and 3 of 'svscale_x' must have the same element size, but the values passed here have type 'svfloat16_t' and 'svint32_t' respectively} } */ + svscale_x (pg, f16, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, f16, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, f16, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, f16, 0); + svscale_x (pg, s16, s16); /* { dg-error {'svscale_x' has no form that takes 'svint16_t' arguments} } */ + svscale_x (pg, s16, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, s16, s32); /* { dg-error {'svscale_x' has no form that takes 'svint16_t' arguments} } */ + svscale_x (pg, s16, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svscale_x', which expects a vector of signed integers} } */ + svscale_x (pg, u16, s16); /* { dg-error {'svscale_x' has no form that takes 'svuint16_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_lane_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_lane_1.c new file mode 100644 index 0000000..f1879ca --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_lane_1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat16_t f16, svfloat32_t f32, svfloat64_t f64, + svint32_t s32, int i) +{ + svmul_lane (f32, f32); /* { dg-error {too few arguments to function 'svmul_lane'} } */ + svmul_lane (f32, f32, 0, 0); /* { dg-error {too many arguments to function 'svmul_lane'} } */ + svmul_lane (pg, pg, 0); /* { dg-error {'svmul_lane' has no form that takes 'svbool_t' arguments} } */ + svmul_lane (s32, s32, 0); /* { dg-error {'svmul_lane' has no form that takes 'svint32_t' arguments} } */ + svmul_lane (1, f32, 0); /* { dg-error {passing 'int' to argument 1 of 'svmul_lane', which expects an SVE vector type} } */ + svmul_lane (f32, 1, 0); /* { dg-error {passing 'int' to argument 2 of 'svmul_lane', which expects an SVE vector type} } */ + svmul_lane (f32, f64, 0); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svmul_lane', but previous arguments had type 'svfloat32_t'} } */ + svmul_lane (f32, f32, s32); /* { dg-error {argument 3 of 'svmul_lane' must be an integer constant expression} } */ + svmul_lane (f32, f32, i); /* { dg-error {argument 3 of 'svmul_lane' must be an integer constant expression} } */ + + svmul_lane (f16, f16, 0); + svmul_lane (f16, f16, 7); + svmul_lane (f16, f16, 8); /* { dg-error {passing 8 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 7\]} } */ + svmul_lane (f16, f16, -1); /* { dg-error {passing -1 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 7\]} } */ + + svmul_lane (f32, f32, 0); + svmul_lane (f32, f32, 3); + svmul_lane (f32, f32, 4); /* { dg-error {passing 4 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 3\]} } */ + svmul_lane (f32, f32, -1); /* { dg-error {passing -1 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 3\]} } */ + + svmul_lane (f64, f64, 0); + svmul_lane (f64, f64, 1); + svmul_lane (f64, f64, 2); /* { dg-error {passing 2 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 1\]} } */ + svmul_lane (f64, f64, -1); /* { dg-error {passing -1 to argument 3 of 'svmul_lane', which expects a value in the range \[0, 1\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_n_1.c new file mode 100644 index 0000000..0c69e66 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_n_1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, svfloat16_t f16, int i, float f) +{ + svinsr (u8); /* { dg-error {too few arguments to function 'svinsr'} } */ + svinsr (u8, 0, 0); /* { dg-error {too many arguments to function 'svinsr'} } */ + svinsr (0, 0); /* { dg-error {passing 'int' to argument 1 of 'svinsr', which expects an SVE vector type} } */ + svinsr (u8, 0); + svinsr (u8, -1); + svinsr (u8, i); + svinsr (u8, f); + svinsr (u8, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svinsr', which expects a scalar element} } */ + svinsr (pg, 0); /* { dg-error {'svinsr' has no form that takes 'svbool_t' arguments} } */ + svinsr (f16, f); + svinsr (f16, f16); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svinsr', which expects a scalar element} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_1.c new file mode 100644 index 0000000..29615e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, svuint8_t u8, svint8_t s8) +{ + svadd_u8_x (pg, u8, s8); /* { dg-error {incompatible type for argument 3 of 'svadd_u8_x'} } */ + svadd_u8_x (pg, u8); /* { dg-error {too few arguments to function 'svadd_u8_x'} } */ + svadd_u8_x (pg, u8, u8, u8); /* { dg-error {too many arguments to function 'svadd_u8_x'} } */ + return svadd_s8_x (pg, s8, s8); /* { dg-error {incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_2.c new file mode 100644 index 0000000..9fa83ca --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16) +{ + svadd_x (pg, u8); /* { dg-error {too few arguments to function 'svadd_x'} } */ + svadd_x (pg, u8, u8, u8); /* { dg-error {too many arguments to function 'svadd_x'} } */ + svadd_x (u8, u8, u8); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svadd_x', which expects 'svbool_t'} } */ + svadd_x (pg, pg, pg); /* { dg-error {'svadd_x' has no form that takes 'svbool_t' arguments} } */ + svadd_x (pg, 1, u8); /* { dg-error {passing 'int' to argument 2 of 'svadd_x', which expects an SVE vector type} } */ + svadd_x (pg, u8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svadd_x', but previous arguments had type 'svuint8_t'} } */ + svadd_x (pg, u8, u8); + svadd_x (pg, u8, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svadd_x', but previous arguments had type 'svuint8_t'} } */ + svadd_x (pg, u8, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svadd_x', but previous arguments had type 'svuint8_t'} } */ + svadd_x (pg, u8, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svadd_x', but previous arguments had type 'svuint8_t'} } */ + svadd_x (pg, u8, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svadd_x', but previous arguments had type 'svuint8_t'} } */ + svadd_x (pg, u8, 0); + + svadd_x (pg, f16, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svadd_x', but previous arguments had type 'svfloat16_t'} } */ + svadd_x (pg, f16, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svadd_x', but previous arguments had type 'svfloat16_t'} } */ + svadd_x (pg, f16, f16); + svadd_x (pg, f16, 1); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_3.c new file mode 100644 index 0000000..4d0b253 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_opt_n_3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16) +{ + svand_z (pg, u8); /* { dg-error {too few arguments to function 'svand_z'} } */ + svand_z (pg, u8, u8, u8); /* { dg-error {too many arguments to function 'svand_z'} } */ + svand_z (u8, u8, u8); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svand_z', which expects 'svbool_t'} } */ + svand_z (pg, pg, pg); + svand_z (pg, 1, u8); /* { dg-error {passing 'int' to argument 2 of 'svand_z', which expects an SVE vector type} } */ + svand_z (pg, u8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svand_z', but previous arguments had type 'svuint8_t'} } */ + svand_z (pg, u8, u8); + svand_z (pg, u8, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svand_z', but previous arguments had type 'svuint8_t'} } */ + svand_z (pg, u8, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svand_z', but previous arguments had type 'svuint8_t'} } */ + svand_z (pg, u8, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svand_z', but previous arguments had type 'svuint8_t'} } */ + svand_z (pg, u8, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svand_z', but previous arguments had type 'svuint8_t'} } */ + svand_z (pg, u8, 0); + + svand_z (pg, pg, u8); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svand_z', but previous arguments had type 'svbool_t'} } */ + svand_z (pg, pg, 0); /* { dg-error {passing 'int' to argument 3 of 'svand_z', but its 'svbool_t' form does not accept scalars} } */ + + svand_z (pg, f16, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svand_z', but previous arguments had type 'svfloat16_t'} } */ + svand_z (pg, f16, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svand_z', but previous arguments had type 'svfloat16_t'} } */ + svand_z (pg, f16, f16); /* { dg-error {'svand_z' has no form that takes 'svfloat16_t' arguments} } */ + svand_z (pg, f16, 1); /* { dg-error {'svand_z' has no form that takes 'svfloat16_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_rotate_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_rotate_1.c new file mode 100644 index 0000000..8ffe91b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_rotate_1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat32_t f32, svfloat64_t f64, svint32_t s32, int i) +{ + svcadd_x (pg, f32, f32); /* { dg-error {too few arguments to function 'svcadd_x'} } */ + svcadd_x (pg, f32, f32, 90, 90); /* { dg-error {too many arguments to function 'svcadd_x'} } */ + svcadd_x (f32, f32, f32, 90); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svcadd_x', which expects 'svbool_t'} } */ + svcadd_x (pg, pg, pg, 90); /* { dg-error {'svcadd_x' has no form that takes 'svbool_t' arguments} } */ + svcadd_x (pg, s32, s32, 90); /* { dg-error {'svcadd_x' has no form that takes 'svint32_t' arguments} } */ + svcadd_x (pg, 1, f32, 90); /* { dg-error {passing 'int' to argument 2 of 'svcadd_x', which expects an SVE vector type} } */ + svcadd_x (pg, f32, 1, 90); /* { dg-error {passing 'int' to argument 3 of 'svcadd_x', which expects an SVE vector type} } */ + svcadd_x (pg, f32, f64, 90); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svcadd_x', but previous arguments had type 'svfloat32_t'} } */ + svcadd_x (pg, f32, f32, s32); /* { dg-error {argument 4 of 'svcadd_x' must be an integer constant expression} } */ + svcadd_x (pg, f32, f32, i); /* { dg-error {argument 4 of 'svcadd_x' must be an integer constant expression} } */ + svcadd_x (pg, f32, f32, -90); /* { dg-error {passing -90 to argument 4 of 'svcadd_x', which expects either 90 or 270} } */ + svcadd_x (pg, f32, f32, 0); /* { dg-error {passing 0 to argument 4 of 'svcadd_x', which expects either 90 or 270} } */ + svcadd_x (pg, f32, f32, 1); /* { dg-error {passing 1 to argument 4 of 'svcadd_x', which expects either 90 or 270} } */ + svcadd_x (pg, f32, f32, 90); + svcadd_x (pg, f32, f32, 180); /* { dg-error {passing 180 to argument 4 of 'svcadd_x', which expects either 90 or 270} } */ + svcadd_x (pg, f32, f32, 270); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_n_1.c new file mode 100644 index 0000000..c8ca5f7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_n_1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, int i, float f) +{ + svdupq_lane (u8); /* { dg-error {too few arguments to function 'svdupq_lane'} } */ + svdupq_lane (u8, 0, 0); /* { dg-error {too many arguments to function 'svdupq_lane'} } */ + svdupq_lane (0, 0); /* { dg-error {passing 'int' to argument 1 of 'svdupq_lane', which expects an SVE vector type} } */ + svdupq_lane (u8, 0); + svdupq_lane (u8, -1); + svdupq_lane (u8, i); + svdupq_lane (u8, f); + svdupq_lane (u8, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svdupq_lane', which expects 'uint64_t'} } */ + svdupq_lane (pg, 0); /* { dg-error {'svdupq_lane' has no form that takes 'svbool_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_1.c new file mode 100644 index 0000000..27726a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svuint64_t u64) +{ + svlsl_wide_u8_x (pg, u8, u8); /* { dg-error {incompatible type for argument 3 of 'svlsl_wide_u8_x'} } */ + svlsl_wide_u8_x (pg, u8); /* { dg-error {too few arguments to function 'svlsl_wide_u8_x'} } */ + svlsl_wide_u8_x (pg, u8, u64, u8); /* { dg-error {too many arguments to function 'svlsl_wide_u8_x'} } */ + return svlsl_wide_s8_x (pg, s8, u64); /* { dg-error {incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_2.c new file mode 100644 index 0000000..be21739 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint64_opt_n_2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, svuint64_t u64) +{ + svlsl_wide_x (pg, u8); /* { dg-error {too few arguments to function 'svlsl_wide_x'} } */ + svlsl_wide_x (pg, u8, u8, u8); /* { dg-error {too many arguments to function 'svlsl_wide_x'} } */ + svlsl_wide_x (u8, u8, u64); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svlsl_wide_x', which expects 'svbool_t'} } */ + svlsl_wide_x (pg, 1, u64); /* { dg-error {passing 'int' to argument 2 of 'svlsl_wide_x', which expects an SVE vector type} } */ + svlsl_wide_x (pg, u8, u8); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svlsl_wide_x', which expects 'svuint64_t'} } */ + svlsl_wide_x (pg, u64, u64); /* { dg-error {'svlsl_wide_x' has no form that takes 'svuint64_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_1.c new file mode 100644 index 0000000..8f86c50 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_1.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svuint16_t u16, svint16_t s16, + svfloat16_t f16) +{ + svtbl (u8); /* { dg-error {too few arguments to function 'svtbl'} } */ + svtbl (u8, u8, u8); /* { dg-error {too many arguments to function 'svtbl'} } */ + svtbl (pg, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (pg, u8); /* { dg-error {'svtbl' has no form that takes 'svbool_t' arguments} } */ + + svtbl (u8, 0); /* { dg-error {passing 'int' to argument 2 of 'svtbl', which expects an SVE vector type} } */ + svtbl (u8, u8); + svtbl (u8, s8); /* { dg-error {passing 'svint8_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (u8, u16); /* { dg-error {arguments 1 and 2 of 'svtbl' must have the same element size, but the values passed here have type 'svuint8_t' and 'svuint16_t' respectively} } */ + svtbl (u8, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (u8, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + + svtbl (s8, u8); + svtbl (s8, s8); /* { dg-error {passing 'svint8_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (s8, u16); /* { dg-error {arguments 1 and 2 of 'svtbl' must have the same element size, but the values passed here have type 'svint8_t' and 'svuint16_t' respectively} } */ + svtbl (s8, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (s8, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + + svtbl (u16, u8); /* { dg-error {arguments 1 and 2 of 'svtbl' must have the same element size, but the values passed here have type 'svuint16_t' and 'svuint8_t' respectively} } */ + svtbl (u16, s8); /* { dg-error {passing 'svint8_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (u16, u16); + svtbl (u16, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (u16, f16); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + + svtbl (s16, u8); /* { dg-error {arguments 1 and 2 of 'svtbl' must have the same element size, but the values passed here have type 'svint16_t' and 'svuint8_t' respectively} } */ + svtbl (s16, s8); /* { dg-error {passing 'svint8_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (s16, u16); + svtbl (s16, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (s16, f16); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + + svtbl (f16, u8); /* { dg-error {arguments 1 and 2 of 'svtbl' must have the same element size, but the values passed here have type 'svfloat16_t' and 'svuint8_t' respectively} } */ + svtbl (f16, s8); /* { dg-error {passing 'svint8_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (f16, u16); + svtbl (f16, s16); /* { dg-error {passing 'svint16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ + svtbl (f16, f16); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svtbl', which expects a vector of unsigned integers} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_n_1.c new file mode 100644 index 0000000..36a902e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_n_1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, int i, float f) +{ + svdup_lane (u8); /* { dg-error {too few arguments to function 'svdup_lane'} } */ + svdup_lane (u8, 0, 0); /* { dg-error {too many arguments to function 'svdup_lane'} } */ + svdup_lane (0, 0); /* { dg-error {passing 'int' to argument 1 of 'svdup_lane', which expects an SVE vector type} } */ + svdup_lane (u8, 0); + svdup_lane (u8, -1); + svdup_lane (u8, i); + svdup_lane (u8, f); + svdup_lane (u8, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svdup_lane', which expects a scalar integer} } */ + svdup_lane (pg, 0); /* { dg-error {'svdup_lane' has no form that takes 'svbool_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_opt_n_1.c new file mode 100644 index 0000000..b162ab4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/binary_uint_opt_n_1.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat16_t f16, svint16_t s16, svuint16_t u16, + svfloat32_t f32, svint32_t s32, svuint32_t u32) +{ + svlsl_x (pg, s16); /* { dg-error {too few arguments to function 'svlsl_x'} } */ + svlsl_x (pg, s16, u16, u16); /* { dg-error {too many arguments to function 'svlsl_x'} } */ + svlsl_x (s32, s32, u32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svlsl_x', which expects 'svbool_t'} } */ + svlsl_x (1, s32, u32); /* { dg-error {passing 'int' to argument 1 of 'svlsl_x', which expects 'svbool_t'} } */ + svlsl_x (pg, pg, u16); /* { dg-error {'svlsl_x' has no form that takes 'svbool_t' arguments} } */ + svlsl_x (pg, 1, s16); /* { dg-error {passing 'int' to argument 2 of 'svlsl_x', which expects an SVE vector type} } */ + svlsl_x (pg, s16, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, s16, u16); + svlsl_x (pg, s16, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, s16, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, s16, u32); /* { dg-error {arguments 2 and 3 of 'svlsl_x' must have the same element size, but the values passed here have type 'svint16_t' and 'svuint32_t' respectively} } */ + svlsl_x (pg, s16, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, s16, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, s16, 0); + svlsl_x (pg, f16, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, f16, u16); /* { dg-error {'svlsl_x' has no form that takes 'svfloat16_t' arguments} } */ + svlsl_x (pg, f16, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svlsl_x', which expects a vector of unsigned integers} } */ + svlsl_x (pg, f16, u32); /* { dg-error {'svlsl_x' has no form that takes 'svfloat16_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/clast_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/clast_1.c new file mode 100644 index 0000000..cb9ac94 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/clast_1.c @@ -0,0 +1,15 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint32_t s32, svint64_t s64, int i) +{ + svclasta (pg, 1); /* { dg-error {too few arguments to function 'svclasta'} } */ + svclasta (pg, 1, s32, 1); /* { dg-error {too many arguments to function 'svclasta'} } */ + svclasta (1, 1, s32); /* { dg-error {passing 'int' to argument 1 of 'svclasta', which expects 'svbool_t'} } */ + svclasta (pg, 1, 1); /* { dg-error {passing 'int' to argument 3 of 'svclasta', which expects an SVE vector type} } */ + svclasta (pg, 1, pg); /* { dg-error {'svclasta' has no form that takes 'svbool_t' arguments} } */ + svclasta (pg, i, s32); + svclasta (pg, s32, 1); /* { dg-error {passing 'int' to argument 3 of 'svclasta', which expects an SVE vector type} } */ + svclasta (pg, s32, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svclasta', but previous arguments had type 'svint32_t'} } */ + svclasta (pg, pg, pg); /* { dg-error {'svclasta' has no form that takes 'svbool_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_opt_n_1.c new file mode 100644 index 0000000..71c8e86 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_opt_n_1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16) +{ + svcmpeq (pg, u8); /* { dg-error {too few arguments to function 'svcmpeq'} } */ + svcmpeq (pg, u8, u8, u8); /* { dg-error {too many arguments to function 'svcmpeq'} } */ + svcmpeq (u8, u8, u8); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svcmpeq', which expects 'svbool_t'} } */ + svcmpeq (pg, pg, pg); /* { dg-error {'svcmpeq' has no form that takes 'svbool_t' arguments} } */ + svcmpeq (pg, 1, u8); /* { dg-error {passing 'int' to argument 2 of 'svcmpeq', which expects an SVE vector type} } */ + svcmpeq (pg, u8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svuint8_t'} } */ + svcmpeq (pg, u8, u8); + svcmpeq (pg, u8, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svuint8_t'} } */ + svcmpeq (pg, u8, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svuint8_t'} } */ + svcmpeq (pg, u8, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svuint8_t'} } */ + svcmpeq (pg, u8, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svuint8_t'} } */ + svcmpeq (pg, u8, 0); + + svcmpeq (pg, f16, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svfloat16_t'} } */ + svcmpeq (pg, f16, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svcmpeq', but previous arguments had type 'svfloat16_t'} } */ + svcmpeq (pg, f16, f16); + svcmpeq (pg, f16, 1); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_scalar_1.c new file mode 100644 index 0000000..d5a60f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_scalar_1.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> +#include <stdbool.h> + +enum signed_enum { SA = -1, SB }; +enum unsigned_enum { UA, UB }; + +void +test (int8_t s8, int16_t s16, int32_t s32, int64_t s64, + uint8_t u8, uint16_t u16, uint32_t u32, uint64_t u64, + bool b, enum signed_enum se, enum unsigned_enum ue, + int *ptr, float f32, svbool_t pg, svint32_t vec) +{ + svwhilele_b8 (s32); /* { dg-error {too few arguments to function 'svwhilele_b8'} } */ + svwhilele_b8 (s32, s32, s32); /* { dg-error {too many arguments to function 'svwhilele_b8'} } */ + + svwhilele_b8 (b, b); + svwhilele_b8 (se, se); + svwhilele_b8 (ue, ue); + svwhilele_b8 (s8, s8); + svwhilele_b8 (u8, u8); + svwhilele_b8 (s16, s16); + svwhilele_b8 (u16, u16); + svwhilele_b8 (ptr, ptr); /* { dg-error {passing 'int \*' to argument 1 of 'svwhilele_b8', which expects a 32-bit or 64-bit integer type} } */ + svwhilele_b8 (f32, f32); /* { dg-error {passing 'float' to argument 1 of 'svwhilele_b8', which expects a 32-bit or 64-bit integer type} } */ + svwhilele_b8 (pg, pg); /* { dg-error {passing 'svbool_t' to argument 1 of 'svwhilele_b8', which expects a 32-bit or 64-bit integer type} } */ + svwhilele_b8 (vec, vec); /* { dg-error {passing 'svint32_t' to argument 1 of 'svwhilele_b8', which expects a 32-bit or 64-bit integer type} } */ + + svwhilele_b8 (s32, b); + svwhilele_b8 (s32, se); + svwhilele_b8 (s32, ue); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (s32, s8); + svwhilele_b8 (s32, u8); + svwhilele_b8 (s32, s16); + svwhilele_b8 (s32, u16); + + svwhilele_b8 (u32, b); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, se); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, ue); + svwhilele_b8 (u32, s8); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, u8); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, s16); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, u16); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + + svwhilele_b8 (s32, s32); + svwhilele_b8 (s32, u32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (s32, s64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'int64_t'} } */ + svwhilele_b8 (s32, u64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint64_t'} } */ + + svwhilele_b8 (u32, s32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u32, u32); + svwhilele_b8 (u32, s64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int64_t'} } */ + svwhilele_b8 (u32, u64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'uint64_t'} } */ + + svwhilele_b8 (s64, s32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int64_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (s64, u32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int64_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (s64, s64); + svwhilele_b8 (s64, u64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int64_t' but argument 2 has type 'uint64_t'} } */ + + svwhilele_b8 (u64, s32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint64_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u64, u32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint64_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (u64, s64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint64_t' but argument 2 has type 'int64_t'} } */ + svwhilele_b8 (u64, u64); + + svwhilele_b8 (0, s32); + svwhilele_b8 (0, u32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (0, s64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'int64_t'} } */ + svwhilele_b8 (0, u64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint64_t'} } */ + + svwhilele_b8 (s32, 0); + svwhilele_b8 (u32, 0); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (s64, 0); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int64_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (u64, 0); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint64_t' but argument 2 has type 'int32_t'} } */ + + svwhilele_b8 (0U, s32); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int32_t'} } */ + svwhilele_b8 (0U, u32); + svwhilele_b8 (0U, s64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'int64_t'} } */ + svwhilele_b8 (0U, u64); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint32_t' but argument 2 has type 'uint64_t'} } */ + + svwhilele_b8 (s32, 0U); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int32_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (u32, 0U); + svwhilele_b8 (s64, 0U); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'int64_t' but argument 2 has type 'uint32_t'} } */ + svwhilele_b8 (u64, 0U); /* { dg-error {call to 'svwhilele_b8' is ambiguous; argument 1 has type 'uint64_t' but argument 2 has type 'uint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_wide_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_wide_opt_n_1.c new file mode 100644 index 0000000..fc5e456 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/compare_wide_opt_n_1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint64_t s64, svuint64_t u64, + svfloat32_t f32, svfloat64_t f64, unsigned int x) +{ + svcmpeq_wide (pg, s8); /* { dg-error {too few arguments to function 'svcmpeq_wide'} } */ + svcmpeq_wide (pg, s8, s64, s8); /* { dg-error {too many arguments to function 'svcmpeq_wide'} } */ + svcmpeq_wide (s8, s8, s64); /* { dg-error {passing 'svint8_t' to argument 1 of 'svcmpeq_wide', which expects 'svbool_t'} } */ + svcmpeq_wide (pg, 0, s64); /* { dg-error {passing 'int' to argument 2 of 'svcmpeq_wide', which expects an SVE vector type} } */ + svcmpeq_wide (pg, s8, 0); + svcmpeq_wide (pg, s8, x); + svcmpeq_wide (pg, s8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svcmpeq_wide', which expects a vector of 64-bit elements} } */ + svcmpeq_wide (pg, s8, u8); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svcmpeq_wide', which expects a vector of 64-bit elements} } */ + svcmpeq_wide (pg, s8, s64); + svcmpeq_wide (pg, s8, u64); /* { dg-error {arguments 2 and 3 of 'svcmpeq_wide' must have the same signedness, but the values passed here have type 'svint8_t' and 'svuint64_t' respectively} } */ + svcmpeq_wide (pg, u8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svcmpeq_wide', which expects a vector of 64-bit elements} } */ + svcmpeq_wide (pg, u8, u64); /* { dg-error {'svcmpeq_wide' has no form that takes 'svuint8_t' arguments} } */ + svcmpeq_wide (pg, s64, s64); /* { dg-error {'svcmpeq_wide' has no form that takes 'svint64_t' arguments} } */ + svcmpeq_wide (pg, f32, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svcmpeq_wide', which expects a vector of 64-bit elements} } */ + svcmpeq_wide (pg, f32, f64); /* { dg-error {'svcmpeq_wide' has no form that takes 'svfloat32_t' arguments} } */ + svcmpeq_wide (pg, f64, f64); /* { dg-error {'svcmpeq_wide' has no form that takes 'svfloat64_t' arguments} } */ + svcmpeq_wide (pg, pg, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svcmpeq_wide', which expects a vector of 64-bit elements} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_pat_1.c new file mode 100644 index 0000000..8dd76a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_pat_1.c @@ -0,0 +1,42 @@ +#include <arm_sve.h> + +void +test (enum svpattern pat, int i) +{ + svcntb_pat (pat); /* { dg-error {argument 1 of 'svcntb_pat' must be an integer constant expression} } */ + svcntb_pat (i); /* { dg-error {argument 1 of 'svcntb_pat' must be an integer constant expression} } */ + svcntb_pat ((enum svpattern) -1); /* { dg-error {passing 4294967295 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 0); + svcntb_pat ((enum svpattern) 1); + svcntb_pat ((enum svpattern) 2); + svcntb_pat ((enum svpattern) 3); + svcntb_pat ((enum svpattern) 4); + svcntb_pat ((enum svpattern) 5); + svcntb_pat ((enum svpattern) 6); + svcntb_pat ((enum svpattern) 7); + svcntb_pat ((enum svpattern) 8); + svcntb_pat ((enum svpattern) 9); + svcntb_pat ((enum svpattern) 10); + svcntb_pat ((enum svpattern) 11); + svcntb_pat ((enum svpattern) 12); + svcntb_pat ((enum svpattern) 13); + svcntb_pat ((enum svpattern) 14); /* { dg-error {passing 14 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 15); /* { dg-error {passing 15 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 16); /* { dg-error {passing 16 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 17); /* { dg-error {passing 17 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 18); /* { dg-error {passing 18 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 19); /* { dg-error {passing 19 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 20); /* { dg-error {passing 20 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 21); /* { dg-error {passing 21 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 22); /* { dg-error {passing 22 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 23); /* { dg-error {passing 23 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 24); /* { dg-error {passing 24 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 25); /* { dg-error {passing 25 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 26); /* { dg-error {passing 26 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 27); /* { dg-error {passing 27 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 28); /* { dg-error {passing 28 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ + svcntb_pat ((enum svpattern) 29); + svcntb_pat ((enum svpattern) 30); + svcntb_pat ((enum svpattern) 31); + svcntb_pat ((enum svpattern) 32); /* { dg-error {passing 32 to argument 1 of 'svcntb_pat', which expects a valid 'enum svpattern' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_vector_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_vector_1.c new file mode 100644 index 0000000..daf9e0d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/count_vector_1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint32_t u32, svuint32x2_t u32x2) +{ + svlen (); /* { dg-error {too few arguments to function 'svlen'} } */ + svlen (u32, u32); /* { dg-error {too many arguments to function 'svlen'} } */ + svlen (0); /* { dg-error {passing 'int' to argument 1 of 'svlen', which expects an SVE vector type} } */ + svlen (pg); /* { dg-error {'svlen' has no form that takes 'svbool_t' arguments} } */ + svlen (u32x2); /* { dg-error {passing 'svuint32x2_t' to argument 1 of 'svlen', which expects a single SVE vector rather than a tuple} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_1.c new file mode 100644 index 0000000..31321a0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svuint8x2_t *ptr, svbool_t pg, svuint8_t u8, svfloat64_t f64, + svuint8x2_t u8x2, int x) +{ + *ptr = svcreate2 (u8); /* { dg-error {too few arguments to function 'svcreate2'} } */ + *ptr = svcreate2 (u8, u8, u8); /* { dg-error {too many arguments to function 'svcreate2'} } */ + *ptr = svcreate2 (u8x2, u8x2); /* { dg-error {passing 'svuint8x2_t' to argument 1 of 'svcreate2', which expects a single SVE vector rather than a tuple} } */ + *ptr = svcreate2 (u8, f64); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svcreate2', but previous arguments had type 'svuint8_t'} } */ + *ptr = svcreate2 (u8, pg); /* { dg-error {passing 'svbool_t' to argument 2 of 'svcreate2', but previous arguments had type 'svuint8_t'} } */ + *ptr = svcreate2 (u8, x); /* { dg-error {passing 'int' to argument 2 of 'svcreate2', which expects an SVE vector type} } */ + *ptr = svcreate2 (x, u8); /* { dg-error {passing 'int' to argument 1 of 'svcreate2', which expects an SVE vector type} } */ + *ptr = svcreate2 (pg, u8); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svcreate2', but previous arguments had type 'svbool_t'} } */ + *ptr = svcreate2 (pg, pg); /* { dg-error {'svcreate2' has no form that takes 'svbool_t' arguments} } */ + *ptr = svcreate2 (u8, u8); + *ptr = svcreate2 (f64, f64); /* { dg-error {incompatible types when assigning to type 'svuint8x2_t' from type 'svfloat64x2_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_2.c new file mode 100644 index 0000000..28ad16c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svuint8x2_t *ptr, svbool_t pg, svuint8_t u8, svfloat64_t f64, + svuint8x2_t u8x2, int x) +{ + *ptr = svcreate2_u8 (u8); /* { dg-error {too few arguments to function 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (u8, u8, u8); /* { dg-error {too many arguments to function 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (u8x2, u8x2); /* { dg-error {incompatible type for argument 1 of 'svcreate2_u8'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate2_u8'} "" { target *-*-* } .-1 } */ + *ptr = svcreate2_u8 (u8, f64); /* { dg-error {incompatible type for argument 2 of 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (u8, pg); /* { dg-error {incompatible type for argument 2 of 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (u8, x); /* { dg-error {incompatible type for argument 2 of 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (x, u8); /* { dg-error {incompatible type for argument 1 of 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (pg, u8); /* { dg-error {incompatible type for argument 1 of 'svcreate2_u8'} } */ + *ptr = svcreate2_u8 (pg, pg); /* { dg-error {incompatible type for argument 1 of 'svcreate2_u8'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate2_u8'} "" { target *-*-* } .-1 } */ + *ptr = svcreate2_u8 (u8, u8); + *ptr = svcreate2_f64 (f64, f64); /* { dg-error {incompatible types when assigning to type 'svuint8x2_t' from type 'svfloat64x2_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_3.c new file mode 100644 index 0000000..a88e56b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_3.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svfloat16x3_t *ptr, svbool_t pg, svfloat16_t f16, svfloat64_t f64, + svfloat16x3_t f16x3, int x) +{ + *ptr = svcreate3 (f16); /* { dg-error {too few arguments to function 'svcreate3'} } */ + *ptr = svcreate3 (f16, f16); /* { dg-error {too few arguments to function 'svcreate3'} } */ + *ptr = svcreate3 (f16, f16, f16, f16); /* { dg-error {too many arguments to function 'svcreate3'} } */ + *ptr = svcreate3 (f16x3, f16x3, f16x3); /* { dg-error {passing 'svfloat16x3_t' to argument 1 of 'svcreate3', which expects a single SVE vector rather than a tuple} } */ + *ptr = svcreate3 (f16, f16, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svcreate3', but previous arguments had type 'svfloat16_t'} } */ + *ptr = svcreate3 (f16, pg, f16); /* { dg-error {passing 'svbool_t' to argument 2 of 'svcreate3', but previous arguments had type 'svfloat16_t'} } */ + *ptr = svcreate3 (f16, x, f16); /* { dg-error {passing 'int' to argument 2 of 'svcreate3', which expects an SVE vector type} } */ + *ptr = svcreate3 (x, f16, f16); /* { dg-error {passing 'int' to argument 1 of 'svcreate3', which expects an SVE vector type} } */ + *ptr = svcreate3 (pg, f16, f16); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svcreate3', but previous arguments had type 'svbool_t'} } */ + *ptr = svcreate3 (pg, pg, pg); /* { dg-error {'svcreate3' has no form that takes 'svbool_t' arguments} } */ + *ptr = svcreate3 (f16, f16, f16); + *ptr = svcreate3 (f64, f64, f64); /* { dg-error {incompatible types when assigning to type 'svfloat16x3_t' from type 'svfloat64x3_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_4.c new file mode 100644 index 0000000..c111e9f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_4.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svfloat16x3_t *ptr, svbool_t pg, svfloat16_t f16, svfloat64_t f64, + svfloat16x3_t f16x3, int x) +{ + *ptr = svcreate3_f16 (f16); /* { dg-error {too few arguments to function 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (f16, f16); /* { dg-error {too few arguments to function 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (f16, f16, f16, f16); /* { dg-error {too many arguments to function 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (f16x3, f16x3, f16x3); /* { dg-error {incompatible type for argument 1 of 'svcreate3_f16'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate3_f16'} "" { target *-*-* } .-1 } */ + /* { dg-error {incompatible type for argument 3 of 'svcreate3_f16'} "" { target *-*-* } .-2 } */ + *ptr = svcreate3_f16 (f16, f16, f64); /* { dg-error {incompatible type for argument 3 of 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (f16, pg, f16); /* { dg-error {incompatible type for argument 2 of 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (f16, x, f16); /* { dg-error {incompatible type for argument 2 of 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (x, f16, f16); /* { dg-error {incompatible type for argument 1 of 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (pg, f16, f16); /* { dg-error {incompatible type for argument 1 of 'svcreate3_f16'} } */ + *ptr = svcreate3_f16 (pg, pg, pg); /* { dg-error {incompatible type for argument 1 of 'svcreate3_f16'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate3_f16'} "" { target *-*-* } .-1 } */ + /* { dg-error {incompatible type for argument 3 of 'svcreate3_f16'} "" { target *-*-* } .-2 } */ + *ptr = svcreate3_f16 (f16, f16, f16); + *ptr = svcreate3_f64 (f64, f64, f64); /* { dg-error {incompatible types when assigning to type 'svfloat16x3_t' from type 'svfloat64x3_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_5.c new file mode 100644 index 0000000..fed1245 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_5.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svint32x4_t *ptr, svbool_t pg, svint32_t s32, svfloat64_t f64, + svint32x4_t s32x4, int x) +{ + *ptr = svcreate4 (s32); /* { dg-error {too few arguments to function 'svcreate4'} } */ + *ptr = svcreate4 (s32, s32); /* { dg-error {too few arguments to function 'svcreate4'} } */ + *ptr = svcreate4 (s32, s32, s32); /* { dg-error {too few arguments to function 'svcreate4'} } */ + *ptr = svcreate4 (s32, s32, s32, s32, s32); /* { dg-error {too many arguments to function 'svcreate4'} } */ + *ptr = svcreate4 (s32x4, s32x4, s32x4, s32x4); /* { dg-error {passing 'svint32x4_t' to argument 1 of 'svcreate4', which expects a single SVE vector rather than a tuple} } */ + *ptr = svcreate4 (s32, s32, s32, f64); /* { dg-error {passing 'svfloat64_t' to argument 4 of 'svcreate4', but previous arguments had type 'svint32_t'} } */ + *ptr = svcreate4 (s32, s32, pg, s32); /* { dg-error {passing 'svbool_t' to argument 3 of 'svcreate4', but previous arguments had type 'svint32_t'} } */ + *ptr = svcreate4 (s32, x, s32, s32); /* { dg-error {passing 'int' to argument 2 of 'svcreate4', which expects an SVE vector type} } */ + *ptr = svcreate4 (x, s32, s32, s32); /* { dg-error {passing 'int' to argument 1 of 'svcreate4', which expects an SVE vector type} } */ + *ptr = svcreate4 (pg, s32, s32, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svcreate4', but previous arguments had type 'svbool_t'} } */ + *ptr = svcreate4 (pg, pg, pg, pg); /* { dg-error {'svcreate4' has no form that takes 'svbool_t' arguments} } */ + *ptr = svcreate4 (s32, s32, s32, s32); + *ptr = svcreate4 (f64, f64, f64, f64); /* { dg-error {incompatible types when assigning to type 'svint32x4_t' from type 'svfloat64x4_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_6.c new file mode 100644 index 0000000..b9e298a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/create_6.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svint32x4_t *ptr, svbool_t pg, svint32_t s32, svfloat64_t f64, + svint32x4_t s32x4, int x) +{ + *ptr = svcreate4_s32 (s32); /* { dg-error {too few arguments to function 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32, s32); /* { dg-error {too few arguments to function 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32, s32, s32); /* { dg-error {too few arguments to function 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32, s32, s32, s32, s32); /* { dg-error {too many arguments to function 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32x4, s32x4, s32x4, s32x4); /* { dg-error {incompatible type for argument 1 of 'svcreate4_s32'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate4_s32'} "" { target *-*-* } .-1 } */ + /* { dg-error {incompatible type for argument 3 of 'svcreate4_s32'} "" { target *-*-* } .-2 } */ + /* { dg-error {incompatible type for argument 4 of 'svcreate4_s32'} "" { target *-*-* } .-3 } */ + *ptr = svcreate4_s32 (s32, s32, s32, f64); /* { dg-error {incompatible type for argument 4 of 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32, s32, pg, s32); /* { dg-error {incompatible type for argument 3 of 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (s32, x, s32, s32); /* { dg-error {incompatible type for argument 2 of 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (x, s32, s32, s32); /* { dg-error {incompatible type for argument 1 of 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (pg, s32, s32, s32); /* { dg-error {incompatible type for argument 1 of 'svcreate4_s32'} } */ + *ptr = svcreate4_s32 (pg, pg, pg, pg); /* { dg-error {incompatible type for argument 1 of 'svcreate4_s32'} } */ + /* { dg-error {incompatible type for argument 2 of 'svcreate4_s32'} "" { target *-*-* } .-1 } */ + /* { dg-error {incompatible type for argument 3 of 'svcreate4_s32'} "" { target *-*-* } .-2 } */ + /* { dg-error {incompatible type for argument 4 of 'svcreate4_s32'} "" { target *-*-* } .-3 } */ + *ptr = svcreate4_s32 (s32, s32, s32, s32); + *ptr = svcreate4_f64 (f64, f64, f64, f64); /* { dg-error {incompatible types when assigning to type 'svint32x4_t' from type 'svfloat64x4_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ext_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ext_1.c new file mode 100644 index 0000000..bdce392 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ext_1.c @@ -0,0 +1,67 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, + svfloat16_t f16, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, int i) +{ + svext (pg, pg, 0); /* { dg-error {'svext' has no form that takes 'svbool_t' arguments} } */ + svext (s8, s8, i); /* { dg-error {argument 3 of 'svext' must be an integer constant expression} } */ + + svext (s8, s8, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 255\]} } */ + svext (s8, s8, 0); + svext (s8, s8, 255); + svext (s8, s8, 256); /* { dg-error {passing 256 to argument 3 of 'svext', which expects a value in the range \[0, 255\]} } */ + + svext (u8, u8, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 255\]} } */ + svext (u8, u8, 0); + svext (u8, u8, 255); + svext (u8, u8, 256); /* { dg-error {passing 256 to argument 3 of 'svext', which expects a value in the range \[0, 255\]} } */ + + svext (s16, s16, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + svext (s16, s16, 0); + svext (s16, s16, 127); + svext (s16, s16, 128); /* { dg-error {passing 128 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + + svext (u16, u16, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + svext (u16, u16, 0); + svext (u16, u16, 127); + svext (u16, u16, 128); /* { dg-error {passing 128 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + + svext (f16, f16, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + svext (f16, f16, 0); + svext (f16, f16, 127); + svext (f16, f16, 128); /* { dg-error {passing 128 to argument 3 of 'svext', which expects a value in the range \[0, 127\]} } */ + + svext (s32, s32, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + svext (s32, s32, 0); + svext (s32, s32, 63); + svext (s32, s32, 64); /* { dg-error {passing 64 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + + svext (u32, u32, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + svext (u32, u32, 0); + svext (u32, u32, 63); + svext (u32, u32, 64); /* { dg-error {passing 64 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + + svext (f32, f32, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + svext (f32, f32, 0); + svext (f32, f32, 63); + svext (f32, f32, 64); /* { dg-error {passing 64 to argument 3 of 'svext', which expects a value in the range \[0, 63\]} } */ + + svext (s64, s64, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ + svext (s64, s64, 0); + svext (s64, s64, 31); + svext (s64, s64, 32); /* { dg-error {passing 32 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ + + svext (u64, u64, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ + svext (u64, u64, 0); + svext (u64, u64, 31); + svext (u64, u64, 32); /* { dg-error {passing 32 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ + + svext (f64, f64, -1); /* { dg-error {passing -1 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ + svext (f64, f64, 0); + svext (f64, f64, 31); + svext (f64, f64, 32); /* { dg-error {passing 32 to argument 3 of 'svext', which expects a value in the range \[0, 31\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/fold_left_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/fold_left_1.c new file mode 100644 index 0000000..1d29278 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/fold_left_1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svuint8_t +f1 (svbool_t pg, int i, float f, double d, void *ptr, svfloat32_t f32, + svint32_t i32) +{ + svadda (pg, f); /* { dg-error {too few arguments to function 'svadda'} } */ + svadda (pg, f, f32, f32); /* { dg-error {too many arguments to function 'svadda'} } */ + svadda (f32, f, f32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svadda', which expects 'svbool_t'} } */ + svadda (pg, i, f32); + svadda (pg, f, f32); + svadda (pg, d, f32); + svadda (pg, ptr, f32); /* { dg-error {incompatible type for argument 2 of 'svadda_f32'} } */ + svadda (pg, pg, f32); /* { dg-error {passing 'svbool_t' to argument 2 of 'svadda', which expects a scalar element} } */ + svadda (pg, f32, f32); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svadda', which expects a scalar element} } */ + svadda (pg, f, f); /* { dg-error {passing 'float' to argument 3 of 'svadda', which expects an SVE vector type} } */ + svadda (pg, i, i32); /* { dg-error {'svadda' has no form that takes 'svint32_t' arguments} } */ + svadda (pg, i, i); /* { dg-error {passing 'int' to argument 3 of 'svadda', which expects an SVE vector type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_1.c new file mode 100644 index 0000000..e1b99fa --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_1.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svadd_n_u8_x; /* { dg-message "note: previous declaration of 'svadd_n_u8_x' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svadd_n_u8_x' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_2.c new file mode 100644 index 0000000..7f653f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svadd_n_u8_x = 1; /* { dg-message "note: previous definition of 'svadd_n_u8_x' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svadd_n_u8_x' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_3.c new file mode 100644 index 0000000..d9ff15a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_3.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +extern __SVInt8_t svadd_u8_x (__SVBool_t, __SVInt8_t, __SVInt8_t); /* { dg-message "note: previous declaration of 'svadd_u8_x' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting types for 'svadd_u8_x'} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_4.c new file mode 100644 index 0000000..9591e3d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_4.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +/* Although somewhat suspect, this isn't actively wrong, and doesn't need + to be diagnosed. Any attempt to call the function before including + arm_sve.h will lead to a link failure. (Same for taking its address, + etc.) */ +extern __SVUint8_t svadd_u8_x (__SVBool_t, __SVUint8_t, __SVUint8_t); + +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_5.c new file mode 100644 index 0000000..8592361 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_5.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +/* There's no requirement to diagnose this. In particular, arm_sve.h + is allowed to use macros to implement the functions, and defining + a macro that matches an existing symbol would not be diagnosed. + + At the moment this works like other built-ins in the sense that the + explicit definition "wins". This isn't supported behavior though. */ +__SVUint8_t +svadd_u8_x (__SVBool_t pg, __SVUint8_t x, __SVUint8_t y) +{ + return x; +} + +#pragma GCC aarch64 "arm_sve.h" + +svuint8_t +f (svbool_t pg, svuint8_t x, svuint8_t y) +{ + return svadd_u8_x (pg, x, y); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_6.c new file mode 100644 index 0000000..1f04e46 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/func_redef_6.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svadd_u8_x; /* { dg-message "note: previous declaration of 'svadd_u8_x' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svadd_u8_x' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_1.c new file mode 100644 index 0000000..a3ac08f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_1.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8 = svget2 (u8x2); /* { dg-error {too few arguments to function 'svget2'} } */ + u8 = svget2 (u8x2, 1, 2); /* { dg-error {too many arguments to function 'svget2'} } */ + u8 = svget2 (u8, 0); /* { dg-error {passing single vector 'svuint8_t' to argument 1 of 'svget2', which expects a tuple of 2 vectors} } */ + u8 = svget2 (u8x3, 0); /* { dg-error {passing 'svuint8x3_t' to argument 1 of 'svget2', which expects a tuple of 2 vectors} } */ + u8 = svget2 (pg, 0); /* { dg-error {passing 'svbool_t' to argument 1 of 'svget2', which expects a tuple of 2 vectors} } */ + u8 = svget2 (u8x2, x); /* { dg-error {argument 2 of 'svget2' must be an integer constant expression} } */ + u8 = svget2 (u8x2, 0); + f64 = svget2 (u8x2, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svuint8_t'} } */ + u8 = svget2 (u8x2, 1); + u8 = svget2 (u8x2, 2); /* { dg-error {passing 2 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 3); /* { dg-error {passing 3 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 4); /* { dg-error {passing 4 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, 5); /* { dg-error {passing 5 to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget2', which expects a value in the range \[0, 1\]} } */ + u8 = svget2 (u8x2, one); /* { dg-error {argument 2 of 'svget2' must be an integer constant expression} } */ + u8 = svget2 (u8x2, 3 - 2); + u8 = svget2 (u8x2, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_2.c new file mode 100644 index 0000000..4eee243 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svint8x2_t s8x2, + svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8 = svget2_u8 (u8x2); /* { dg-error {too few arguments to function 'svget2_u8'} } */ + u8 = svget2_u8 (u8x2, 1, 2); /* { dg-error {too many arguments to function 'svget2_u8'} } */ + u8 = svget2_u8 (u8, 0); /* { dg-error {incompatible type for argument 1 of 'svget2_u8'} } */ + u8 = svget2_u8 (s8x2, 0); /* { dg-error {incompatible type for argument 1 of 'svget2_u8'} } */ + u8 = svget2_u8 (u8x3, 0); /* { dg-error {incompatible type for argument 1 of 'svget2_u8'} } */ + u8 = svget2_u8 (pg, 0); /* { dg-error {incompatible type for argument 1 of 'svget2_u8'} } */ + u8 = svget2_u8 (u8x2, x); /* { dg-error {argument 2 of 'svget2_u8' must be an integer constant expression} } */ + u8 = svget2_u8 (u8x2, 0); + f64 = svget2_u8 (u8x2, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svuint8_t'} } */ + u8 = svget2_u8 (u8x2, 1); + u8 = svget2_u8 (u8x2, 2); /* { dg-error {passing 2 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 3); /* { dg-error {passing 3 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 4); /* { dg-error {passing 4 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, 5); /* { dg-error {passing 5 to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget2_u8', which expects a value in the range \[0, 1\]} } */ + u8 = svget2_u8 (u8x2, one); /* { dg-error {argument 2 of 'svget2_u8' must be an integer constant expression} } */ + u8 = svget2_u8 (u8x2, 3 - 2); + u8 = svget2_u8 (u8x2, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_3.c new file mode 100644 index 0000000..0e7b2e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_3.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svfloat16x4_t f16x4, + int x) +{ + const int one = 1; + svfloat64_t f64; + + f16 = svget3 (f16x3); /* { dg-error {too few arguments to function 'svget3'} } */ + f16 = svget3 (f16x3, 1, 2); /* { dg-error {too many arguments to function 'svget3'} } */ + f16 = svget3 (f16, 0); /* { dg-error {passing single vector 'svfloat16_t' to argument 1 of 'svget3', which expects a tuple of 3 vectors} } */ + f16 = svget3 (f16x4, 0); /* { dg-error {passing 'svfloat16x4_t' to argument 1 of 'svget3', which expects a tuple of 3 vectors} } */ + f16 = svget3 (pg, 0); /* { dg-error {passing 'svbool_t' to argument 1 of 'svget3', which expects a tuple of 3 vectors} } */ + f16 = svget3 (f16x3, x); /* { dg-error {argument 2 of 'svget3' must be an integer constant expression} } */ + f16 = svget3 (f16x3, 0); + f64 = svget3 (f16x3, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svfloat16_t'} } */ + f16 = svget3 (f16x3, 1); + f16 = svget3 (f16x3, 2); + f16 = svget3 (f16x3, 3); /* { dg-error {passing 3 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, 4); /* { dg-error {passing 4 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, 5); /* { dg-error {passing 5 to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget3', which expects a value in the range \[0, 2\]} } */ + f16 = svget3 (f16x3, one); /* { dg-error {argument 2 of 'svget3' must be an integer constant expression} } */ + f16 = svget3 (f16x3, 3 - 2); + f16 = svget3 (f16x3, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_4.c new file mode 100644 index 0000000..72b4f82 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_4.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svfloat32x3_t f32x3, + svfloat16x4_t f16x4, int x) +{ + const int one = 1; + svfloat64_t f64; + + f16 = svget3_f16 (f16x3); /* { dg-error {too few arguments to function 'svget3_f16'} } */ + f16 = svget3_f16 (f16x3, 1, 2); /* { dg-error {too many arguments to function 'svget3_f16'} } */ + f16 = svget3_f16 (f16, 0); /* { dg-error {incompatible type for argument 1 of 'svget3_f16'} } */ + f16 = svget3_f16 (f32x3, 0); /* { dg-error {incompatible type for argument 1 of 'svget3_f16'} } */ + f16 = svget3_f16 (f16x4, 0); /* { dg-error {incompatible type for argument 1 of 'svget3_f16'} } */ + f16 = svget3_f16 (pg, 0); /* { dg-error {incompatible type for argument 1 of 'svget3_f16'} } */ + f16 = svget3_f16 (f16x3, x); /* { dg-error {argument 2 of 'svget3_f16' must be an integer constant expression} } */ + f16 = svget3_f16 (f16x3, 0); + f64 = svget3_f16 (f16x3, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svfloat16_t'} } */ + f16 = svget3_f16 (f16x3, 1); + f16 = svget3_f16 (f16x3, 2); + f16 = svget3_f16 (f16x3, 3); /* { dg-error {passing 3 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, 4); /* { dg-error {passing 4 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, 5); /* { dg-error {passing 5 to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget3_f16', which expects a value in the range \[0, 2\]} } */ + f16 = svget3_f16 (f16x3, one); /* { dg-error {argument 2 of 'svget3_f16' must be an integer constant expression} } */ + f16 = svget3_f16 (f16x3, 3 - 2); + f16 = svget3_f16 (f16x3, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_5.c new file mode 100644 index 0000000..b0b69b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_5.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32 = svget4 (s32x4); /* { dg-error {too few arguments to function 'svget4'} } */ + s32 = svget4 (s32x4, 1, 2); /* { dg-error {too many arguments to function 'svget4'} } */ + s32 = svget4 (s32, 0); /* { dg-error {passing single vector 'svint32_t' to argument 1 of 'svget4', which expects a tuple of 4 vectors} } */ + s32 = svget4 (s32x2, 0); /* { dg-error {passing 'svint32x2_t' to argument 1 of 'svget4', which expects a tuple of 4 vectors} } */ + s32 = svget4 (pg, 0); /* { dg-error {passing 'svbool_t' to argument 1 of 'svget4', which expects a tuple of 4 vectors} } */ + s32 = svget4 (s32x4, x); /* { dg-error {argument 2 of 'svget4' must be an integer constant expression} } */ + s32 = svget4 (s32x4, 0); + f64 = svget4 (s32x4, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svint32_t'} } */ + s32 = svget4 (s32x4, 1); + s32 = svget4 (s32x4, 2); + s32 = svget4 (s32x4, 3); + s32 = svget4 (s32x4, 4); /* { dg-error {passing 4 to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, 5); /* { dg-error {passing 5 to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget4', which expects a value in the range \[0, 3\]} } */ + s32 = svget4 (s32x4, one); /* { dg-error {argument 2 of 'svget4' must be an integer constant expression} } */ + s32 = svget4 (s32x4, 3 - 2); + s32 = svget4 (s32x4, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_6.c new file mode 100644 index 0000000..3801c0c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/get_6.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svfloat32x4_t f32x4, + svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32 = svget4_s32 (s32x4); /* { dg-error {too few arguments to function 'svget4_s32'} } */ + s32 = svget4_s32 (s32x4, 1, 2); /* { dg-error {too many arguments to function 'svget4_s32'} } */ + s32 = svget4_s32 (s32, 0); /* { dg-error {incompatible type for argument 1 of 'svget4_s32'} } */ + s32 = svget4_s32 (f32x4, 0); /* { dg-error {incompatible type for argument 1 of 'svget4_s32'} } */ + s32 = svget4_s32 (s32x2, 0); /* { dg-error {incompatible type for argument 1 of 'svget4_s32'} } */ + s32 = svget4_s32 (pg, 0); /* { dg-error {incompatible type for argument 1 of 'svget4_s32'} } */ + s32 = svget4_s32 (s32x4, x); /* { dg-error {argument 2 of 'svget4_s32' must be an integer constant expression} } */ + s32 = svget4_s32 (s32x4, 0); + f64 = svget4_s32 (s32x4, 0); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svint32_t'} } */ + s32 = svget4_s32 (s32x4, 1); + s32 = svget4_s32 (s32x4, 2); + s32 = svget4_s32 (s32x4, 3); + s32 = svget4_s32 (s32x4, 4); /* { dg-error {passing 4 to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, 5); /* { dg-error {passing 5 to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, ~0U); /* { dg-error {passing [^ ]* to argument 2 of 'svget4_s32', which expects a value in the range \[0, 3\]} } */ + s32 = svget4_s32 (s32x4, one); /* { dg-error {argument 2 of 'svget4_s32' must be an integer constant expression} } */ + s32 = svget4_s32 (s32x4, 3 - 2); + s32 = svget4_s32 (s32x4, 1.0); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_1.c new file mode 100644 index 0000000..dcd291d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_1.c @@ -0,0 +1,37 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f, int i) +{ + svqincb (sw); /* { dg-error {too few arguments to function 'svqincb'} } */ + svqincb (sw, 1, 1); /* { dg-error {too many arguments to function 'svqincb'} } */ + + svqincb (pg, 1); /* { dg-error {'svqincb' has no form that takes 'svbool_t' arguments} } */ + svqincb (s8, 1); /* { dg-error {'svqincb' has no form that takes 'svint8_t' arguments} } */ + svqincb (u8, 1); /* { dg-error {'svqincb' has no form that takes 'svuint8_t' arguments} } */ + svqincb (s16, 1); /* { dg-error {'svqincb' has no form that takes 'svint16_t' arguments} } */ + svqincb (u16, 1); /* { dg-error {'svqincb' has no form that takes 'svuint16_t' arguments} } */ + svqincb (s32, 1); /* { dg-error {'svqincb' has no form that takes 'svint32_t' arguments} } */ + svqincb (u32, 1); /* { dg-error {'svqincb' has no form that takes 'svuint32_t' arguments} } */ + svqincb (s64, 1); /* { dg-error {'svqincb' has no form that takes 'svint64_t' arguments} } */ + svqincb (u64, 1); /* { dg-error {'svqincb' has no form that takes 'svuint64_t' arguments} } */ + svqincb (sh, 1); + svqincb (sw, 1); + svqincb (sd, 1); + svqincb (uh, 1); + svqincb (uw, 1); + svqincb (ud, 1); + svqincb (f, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincb', which expects a 32-bit or 64-bit integer type} } */ + svqincb (ud, i); /* { dg-error {argument 2 of 'svqincb' must be an integer constant expression} } */ + + svqincb (sw, -1); /* { dg-error {passing -1 to argument 2 of 'svqincb', which expects a value in the range \[1, 16\]} } */ + svqincb (sw, 0); /* { dg-error {passing 0 to argument 2 of 'svqincb', which expects a value in the range \[1, 16\]} } */ + svqincb (sw, 1); + svqincb (sw, 2); + svqincb (sw, 16); + svqincb (sw, 17); /* { dg-error {passing 17 to argument 2 of 'svqincb', which expects a value in the range \[1, 16\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_2.c new file mode 100644 index 0000000..e5acad1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_2.c @@ -0,0 +1,13 @@ +#include <arm_sve.h> + +void +test (int32_t sw, int i) +{ + svqincb_n_s32 (sw, -1); /* { dg-error {passing -1 to argument 2 of 'svqincb_n_s32', which expects a value in the range \[1, 16\]} } */ + svqincb_n_s32 (sw, 0); /* { dg-error {passing 0 to argument 2 of 'svqincb_n_s32', which expects a value in the range \[1, 16\]} } */ + svqincb_n_s32 (sw, 1); + svqincb_n_s32 (sw, 2); + svqincb_n_s32 (sw, 16); + svqincb_n_s32 (sw, 17); /* { dg-error {passing 17 to argument 2 of 'svqincb_n_s32', which expects a value in the range \[1, 16\]} } */ + svqincb_n_s32 (sw, i); /* { dg-error {argument 2 of 'svqincb_n_s32' must be an integer constant expression} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_3.c new file mode 100644 index 0000000..351e775 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_3.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqinch (pg, 1); /* { dg-error {'svqinch' has no form that takes 'svbool_t' arguments} } */ + svqinch (s8, 1); /* { dg-error {'svqinch' has no form that takes 'svint8_t' arguments} } */ + svqinch (u8, 1); /* { dg-error {'svqinch' has no form that takes 'svuint8_t' arguments} } */ + svqinch (s16, 1); + svqinch (u16, 1); + svqinch (s32, 1); /* { dg-error {'svqinch' has no form that takes 'svint32_t' arguments} } */ + svqinch (u32, 1); /* { dg-error {'svqinch' has no form that takes 'svuint32_t' arguments} } */ + svqinch (s64, 1); /* { dg-error {'svqinch' has no form that takes 'svint64_t' arguments} } */ + svqinch (u64, 1); /* { dg-error {'svqinch' has no form that takes 'svuint64_t' arguments} } */ + svqinch (sh, 1); + svqinch (sw, 1); + svqinch (sd, 1); + svqinch (uh, 1); + svqinch (uw, 1); + svqinch (ud, 1); + svqinch (f, 1); /* { dg-error {passing 'float' to argument 1 of 'svqinch', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_4.c new file mode 100644 index 0000000..e071c02 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_4.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqincw (pg, 1); /* { dg-error {'svqincw' has no form that takes 'svbool_t' arguments} } */ + svqincw (s8, 1); /* { dg-error {'svqincw' has no form that takes 'svint8_t' arguments} } */ + svqincw (u8, 1); /* { dg-error {'svqincw' has no form that takes 'svuint8_t' arguments} } */ + svqincw (s16, 1); /* { dg-error {'svqincw' has no form that takes 'svint16_t' arguments} } */ + svqincw (u16, 1); /* { dg-error {'svqincw' has no form that takes 'svuint16_t' arguments} } */ + svqincw (s32, 1); + svqincw (u32, 1); + svqincw (s64, 1); /* { dg-error {'svqincw' has no form that takes 'svint64_t' arguments} } */ + svqincw (u64, 1); /* { dg-error {'svqincw' has no form that takes 'svuint64_t' arguments} } */ + svqincw (sh, 1); + svqincw (sw, 1); + svqincw (sd, 1); + svqincw (uh, 1); + svqincw (uw, 1); + svqincw (ud, 1); + svqincw (f, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincw', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_5.c new file mode 100644 index 0000000..be9c769 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_5.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqincd (pg, 1); /* { dg-error {'svqincd' has no form that takes 'svbool_t' arguments} } */ + svqincd (s8, 1); /* { dg-error {'svqincd' has no form that takes 'svint8_t' arguments} } */ + svqincd (u8, 1); /* { dg-error {'svqincd' has no form that takes 'svuint8_t' arguments} } */ + svqincd (s16, 1); /* { dg-error {'svqincd' has no form that takes 'svint16_t' arguments} } */ + svqincd (u16, 1); /* { dg-error {'svqincd' has no form that takes 'svuint16_t' arguments} } */ + svqincd (s32, 1); /* { dg-error {'svqincd' has no form that takes 'svint32_t' arguments} } */ + svqincd (u32, 1); /* { dg-error {'svqincd' has no form that takes 'svuint32_t' arguments} } */ + svqincd (s64, 1); + svqincd (u64, 1); + svqincd (sh, 1); + svqincd (sw, 1); + svqincd (sd, 1); + svqincd (uh, 1); + svqincd (uw, 1); + svqincd (ud, 1); + svqincd (f, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincd', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_1.c new file mode 100644 index 0000000..f2e5841 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_1.c @@ -0,0 +1,47 @@ +#include <arm_sve.h> + +void +test (enum svpattern pat, svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f, int i) +{ + svqincb_pat (sw, pat); /* { dg-error {too few arguments to function 'svqincb_pat'} } */ + svqincb_pat (sw, pat, 1, 1); /* { dg-error {too many arguments to function 'svqincb_pat'} } */ + + svqincb_pat (pg, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svbool_t' arguments} } */ + svqincb_pat (s8, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svint8_t' arguments} } */ + svqincb_pat (u8, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svuint8_t' arguments} } */ + svqincb_pat (s16, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svint16_t' arguments} } */ + svqincb_pat (u16, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svuint16_t' arguments} } */ + svqincb_pat (s32, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svint32_t' arguments} } */ + svqincb_pat (u32, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svuint32_t' arguments} } */ + svqincb_pat (s64, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svint64_t' arguments} } */ + svqincb_pat (u64, SV_ALL, 1); /* { dg-error {'svqincb_pat' has no form that takes 'svuint64_t' arguments} } */ + svqincb_pat (sh, SV_ALL, 1); + svqincb_pat (sw, SV_ALL, 1); + svqincb_pat (sd, SV_ALL, 1); + svqincb_pat (uh, SV_ALL, 1); + svqincb_pat (uw, SV_ALL, 1); + svqincb_pat (ud, SV_ALL, 1); + svqincb_pat (f, SV_ALL, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincb_pat', which expects a 32-bit or 64-bit integer type} } */ + + svqincb_pat (sw, pat, 1); /* { dg-error {argument 2 of 'svqincb_pat' must be an integer constant expression} } */ + svqincb_pat (sw, i, 1); /* { dg-error {argument 2 of 'svqincb_pat' must be an integer constant expression} } */ + svqincb_pat (sw, (enum svpattern) -1, 1); /* { dg-error {passing 4294967295 to argument 2 of 'svqincb_pat', which expects a valid 'enum svpattern' value} } */ + svqincb_pat (sw, (enum svpattern) 0, 1); + svqincb_pat (sw, (enum svpattern) 13, 1); + svqincb_pat (sw, (enum svpattern) 14, 1); /* { dg-error {passing 14 to argument 2 of 'svqincb_pat', which expects a valid 'enum svpattern' value} } */ + svqincb_pat (sw, (enum svpattern) 28, 1); /* { dg-error {passing 28 to argument 2 of 'svqincb_pat', which expects a valid 'enum svpattern' value} } */ + svqincb_pat (sw, (enum svpattern) 29, 1); + svqincb_pat (sw, (enum svpattern) 31, 1); + svqincb_pat (sw, (enum svpattern) 32, 1); /* { dg-error {passing 32 to argument 2 of 'svqincb_pat', which expects a valid 'enum svpattern' value} } */ + + svqincb_pat (sw, SV_POW2, -1); /* { dg-error {passing -1 to argument 3 of 'svqincb_pat', which expects a value in the range \[1, 16\]} } */ + svqincb_pat (sw, SV_POW2, 0); /* { dg-error {passing 0 to argument 3 of 'svqincb_pat', which expects a value in the range \[1, 16\]} } */ + svqincb_pat (sw, SV_POW2, 1); + svqincb_pat (sw, SV_POW2, 2); + svqincb_pat (sw, SV_POW2, 16); + svqincb_pat (sw, SV_POW2, 17); /* { dg-error {passing 17 to argument 3 of 'svqincb_pat', which expects a value in the range \[1, 16\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_2.c new file mode 100644 index 0000000..c1c1ab9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_2.c @@ -0,0 +1,23 @@ +#include <arm_sve.h> + +void +test (int32_t sw, enum svpattern pat, int i) +{ + svqincb_pat_n_s32 (sw, pat, 1); /* { dg-error {argument 2 of 'svqincb_pat_n_s32' must be an integer constant expression} } */ + svqincb_pat_n_s32 (sw, i, 1); /* { dg-error {argument 2 of 'svqincb_pat_n_s32' must be an integer constant expression} } */ + svqincb_pat_n_s32 (sw, (enum svpattern) -1, 1); /* { dg-error {passing 4294967295 to argument 2 of 'svqincb_pat_n_s32', which expects a valid 'enum svpattern' value} } */ + svqincb_pat_n_s32 (sw, (enum svpattern) 0, 1); + svqincb_pat_n_s32 (sw, (enum svpattern) 13, 1); + svqincb_pat_n_s32 (sw, (enum svpattern) 14, 1); /* { dg-error {passing 14 to argument 2 of 'svqincb_pat_n_s32', which expects a valid 'enum svpattern' value} } */ + svqincb_pat_n_s32 (sw, (enum svpattern) 28, 1); /* { dg-error {passing 28 to argument 2 of 'svqincb_pat_n_s32', which expects a valid 'enum svpattern' value} } */ + svqincb_pat_n_s32 (sw, (enum svpattern) 29, 1); + svqincb_pat_n_s32 (sw, (enum svpattern) 31, 1); + svqincb_pat_n_s32 (sw, (enum svpattern) 32, 1); /* { dg-error {passing 32 to argument 2 of 'svqincb_pat_n_s32', which expects a valid 'enum svpattern' value} } */ + + svqincb_pat_n_s32 (sw, SV_POW2, -1); /* { dg-error {passing -1 to argument 3 of 'svqincb_pat_n_s32', which expects a value in the range \[1, 16\]} } */ + svqincb_pat_n_s32 (sw, SV_POW2, 0); /* { dg-error {passing 0 to argument 3 of 'svqincb_pat_n_s32', which expects a value in the range \[1, 16\]} } */ + svqincb_pat_n_s32 (sw, SV_POW2, 1); + svqincb_pat_n_s32 (sw, SV_POW2, 2); + svqincb_pat_n_s32 (sw, SV_POW2, 16); + svqincb_pat_n_s32 (sw, SV_POW2, 17); /* { dg-error {passing 17 to argument 3 of 'svqincb_pat_n_s32', which expects a value in the range \[1, 16\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_3.c new file mode 100644 index 0000000..4126b24 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_3.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqinch_pat (pg, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svbool_t' arguments} } */ + svqinch_pat (s8, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svint8_t' arguments} } */ + svqinch_pat (u8, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svuint8_t' arguments} } */ + svqinch_pat (s16, SV_ALL, 1); + svqinch_pat (u16, SV_ALL, 1); + svqinch_pat (s32, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svint32_t' arguments} } */ + svqinch_pat (u32, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svuint32_t' arguments} } */ + svqinch_pat (s64, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svint64_t' arguments} } */ + svqinch_pat (u64, SV_ALL, 1); /* { dg-error {'svqinch_pat' has no form that takes 'svuint64_t' arguments} } */ + svqinch_pat (sh, SV_ALL, 1); + svqinch_pat (sw, SV_ALL, 1); + svqinch_pat (sd, SV_ALL, 1); + svqinch_pat (uh, SV_ALL, 1); + svqinch_pat (uw, SV_ALL, 1); + svqinch_pat (ud, SV_ALL, 1); + svqinch_pat (f, SV_ALL, 1); /* { dg-error {passing 'float' to argument 1 of 'svqinch_pat', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_4.c new file mode 100644 index 0000000..9aabbd7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_4.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqincw_pat (pg, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svbool_t' arguments} } */ + svqincw_pat (s8, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svint8_t' arguments} } */ + svqincw_pat (u8, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svuint8_t' arguments} } */ + svqincw_pat (s16, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svint16_t' arguments} } */ + svqincw_pat (u16, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svuint16_t' arguments} } */ + svqincw_pat (s32, SV_ALL, 1); + svqincw_pat (u32, SV_ALL, 1); + svqincw_pat (s64, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svint64_t' arguments} } */ + svqincw_pat (u64, SV_ALL, 1); /* { dg-error {'svqincw_pat' has no form that takes 'svuint64_t' arguments} } */ + svqincw_pat (sh, SV_ALL, 1); + svqincw_pat (sw, SV_ALL, 1); + svqincw_pat (sd, SV_ALL, 1); + svqincw_pat (uh, SV_ALL, 1); + svqincw_pat (uw, SV_ALL, 1); + svqincw_pat (ud, SV_ALL, 1); + svqincw_pat (f, SV_ALL, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincw_pat', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_5.c new file mode 100644 index 0000000..5df88c6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pat_5.c @@ -0,0 +1,26 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud, + float f) +{ + svqincd_pat (pg, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svbool_t' arguments} } */ + svqincd_pat (s8, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svint8_t' arguments} } */ + svqincd_pat (u8, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svuint8_t' arguments} } */ + svqincd_pat (s16, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svint16_t' arguments} } */ + svqincd_pat (u16, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svuint16_t' arguments} } */ + svqincd_pat (s32, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svint32_t' arguments} } */ + svqincd_pat (u32, SV_ALL, 1); /* { dg-error {'svqincd_pat' has no form that takes 'svuint32_t' arguments} } */ + svqincd_pat (s64, SV_ALL, 1); + svqincd_pat (u64, SV_ALL, 1); + svqincd_pat (sh, SV_ALL, 1); + svqincd_pat (sw, SV_ALL, 1); + svqincd_pat (sd, SV_ALL, 1); + svqincd_pat (uh, SV_ALL, 1); + svqincd_pat (uw, SV_ALL, 1); + svqincd_pat (ud, SV_ALL, 1); + svqincd_pat (f, SV_ALL, 1); /* { dg-error {passing 'float' to argument 1 of 'svqincd_pat', which expects a 32-bit or 64-bit integer type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_1.c new file mode 100644 index 0000000..a61afcd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_1.c @@ -0,0 +1,22 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, int i) +{ + svqincp (s32); /* { dg-error {too few arguments to function 'svqincp'} } */ + svqincp (s32, pg, pg); /* { dg-error {too many arguments to function 'svqincp'} } */ + svqincp (i, pg); /* { dg-error {passing 'int' to argument 1 of 'svqincp', which expects an SVE vector type} } */ + svqincp (pg, pg); /* { dg-error {'svqincp' has no form that takes 'svbool_t' arguments} } */ + svqincp (s8, pg); /* { dg-error {'svqincp' has no form that takes 'svint8_t' arguments} } */ + svqincp (u8, pg); /* { dg-error {'svqincp' has no form that takes 'svuint8_t' arguments} } */ + svqincp (s16, pg); + svqincp (u16, pg); + svqincp (s32, pg); + svqincp (u32, pg); + svqincp (s64, pg); + svqincp (u64, pg); + svqincp (u64, 0); /* { dg-error {passing 'int' to argument 2 of 'svqincp', which expects 'svbool_t'} } */ + svqincp (u64, u64); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svqincp', which expects 'svbool_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_scalar_1.c new file mode 100644 index 0000000..94ebe7e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/inc_dec_pred_scalar_1.c @@ -0,0 +1,19 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint32_t s32, svuint64_t u64, int16_t sh, uint16_t uh, + int32_t sw, uint32_t uw, int64_t sd, uint64_t ud) +{ + svqincp_b8 (s32); /* { dg-error {too few arguments to function 'svqincp_b8'} } */ + svqincp_b8 (s32, pg, pg); /* { dg-error {too many arguments to function 'svqincp_b8'} } */ + svqincp_b8 (pg, pg); /* { dg-error {passing 'svbool_t' to argument 1 of 'svqincp_b8', which expects a 32-bit or 64-bit integer type} } */ + svqincp_b8 (s32, pg); /* { dg-error {passing 'svint32_t' to argument 1 of 'svqincp_b8', which expects a 32-bit or 64-bit integer type} } */ + svqincp_b8 (sh, pg); + svqincp_b8 (uh, pg); + svqincp_b8 (sw, pg); + svqincp_b8 (uw, pg); + svqincp_b8 (sd, pg); + svqincp_b8 (ud, pg); + svqincp_b8 (ud, 0); /* { dg-error {passing 'int' to argument 2 of 'svqincp_b8', which expects 'svbool_t'} } */ + svqincp_b8 (ud, u64); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svqincp_b8', which expects 'svbool_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ld1sh_gather_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ld1sh_gather_1.c new file mode 100644 index 0000000..91f37f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ld1sh_gather_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -Wpointer-sign" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, short *s16_ptr, unsigned short *u16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sh_gather_index (pg, s16_ptr, s32); /* { dg-warning {implicit declaration of function 'svld1sh_gather_index'; did you mean 'svld1_gather_index'} } */ + svld1sh_gather_index_u32 (pg, s16_ptr); /* { dg-error {too few arguments to function 'svld1sh_gather_index_u32'} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1sh_gather_index_u32'} } */ + svld1sh_gather_index_u32 (pg, u16_ptr, s32); /* { dg-warning {pointer targets in passing argument 2 of 'svld1sh_gather_s32index_u32' differ in signedness} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s32); + svld1sh_gather_index_u32 (pg, s16_ptr, u32); + svld1sh_gather_index_u32 (pg, s16_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + + svld1sh_gather_index_u32 (pg, 0, s32); + svld1sh_gather_index_u32 (pg, s, s32); /* { dg-error {'struct s' to argument 2 of 'svld1sh_gather_index_u32', which expects a vector or pointer base address} } */ + + svld1sh_gather_index_u32 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ + svld1sh_gather_index_u32 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ + svld1sh_gather_index_u32 (pg, u32, 0); + svld1sh_gather_index_u32 (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c new file mode 100644 index 0000000..34f989b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr, + float *f32_ptr, _Complex float *cf32_ptr, int **ptr_ptr) +{ + svld1 (pg); /* { dg-error {too few arguments to function 'svld1'} } */ + svld1 (pg, s8_ptr, 0); /* { dg-error {too many arguments to function 'svld1'} } */ + svld1 (0, s8_ptr); /* { dg-error {passing 'int' to argument 1 of 'svld1', which expects 'svbool_t'} } */ + svld1 (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svld1', which expects a pointer type} } */ + svld1 (pg, (int *) 0); + svld1 (pg, void_ptr); /* { dg-error {passing 'void \*' to argument 2 of 'svld1', but 'void' is not a valid SVE element type} } */ + svld1 (pg, s_ptr); /* { dg-error {passing 'struct s \*' to argument 2 of 'svld1', but 'struct s' is not a valid SVE element type} } */ + svld1 (pg, f32_ptr); + svld1 (pg, cf32_ptr); /* { dg-error {passing '_Complex float \*' to argument 2 of 'svld1', but 'complex float' is not a valid SVE element type} } */ + svld1 (pg, ptr_ptr); /* { dg-error {passing 'int \*\*' to argument 2 of 'svld1', but 'int \*' is not a valid SVE element type} } */ + return svld1 (pg, s8_ptr); /* { dg-error {incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_2.c new file mode 100644 index 0000000..beb07f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr, + float *f32_ptr, _Complex float *cf32_ptr) +{ + svld1_s8 (pg); /* { dg-error {too few arguments to function 'svld1_s8'} } */ + svld1_s8 (pg, s8_ptr, 0); /* { dg-error {too many arguments to function 'svld1_s8'} } */ + svld1_s8 (0, 0); /* { dg-error {incompatible type for argument 1 of 'svld1_s8'} } */ + svld1_s8 (pg, 0); + svld1_s32 (pg, (int *) 0); + svld1_s8 (pg, void_ptr); + svld1_s8 (pg, s_ptr); /* { dg-warning {passing argument 2 of 'svld1_s8' from incompatible pointer type} } */ + svld1_f32 (pg, f32_ptr); + svld1_f32 (pg, cf32_ptr); /* { dg-warning {passing argument 2 of 'svld1_f32' from incompatible pointer type} } */ + return svld1_s8 (pg, s8_ptr); /* { dg-error {incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_3.c new file mode 100644 index 0000000..770203f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_3.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, svint8_t s8) +{ + svld1_vnum (pg); /* { dg-error {too few arguments to function 'svld1_vnum'} } */ + svld1_vnum (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1_vnum'} } */ + svld1_vnum (pg, s8_ptr, 0, 0); /* { dg-error {too many arguments to function 'svld1_vnum'} } */ + svld1_vnum (0, s8_ptr, 0); /* { dg-error {passing 'int' to argument 1 of 'svld1_vnum', which expects 'svbool_t'} } */ + svld1_vnum (pg, 0, 0); /* { dg-error {passing 'int' to argument 2 of 'svld1_vnum', which expects a pointer type} } */ + svld1_vnum (pg, s8_ptr, s8_ptr); /* { dg-warning "passing argument 3 of 'svld1_vnum_s8' makes integer from pointer without a cast" } */ + svld1_vnum (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1_vnum', which expects 'int64_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_index_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_index_1.c new file mode 100644 index 0000000..91f37f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_index_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -Wpointer-sign" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, short *s16_ptr, unsigned short *u16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sh_gather_index (pg, s16_ptr, s32); /* { dg-warning {implicit declaration of function 'svld1sh_gather_index'; did you mean 'svld1_gather_index'} } */ + svld1sh_gather_index_u32 (pg, s16_ptr); /* { dg-error {too few arguments to function 'svld1sh_gather_index_u32'} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1sh_gather_index_u32'} } */ + svld1sh_gather_index_u32 (pg, u16_ptr, s32); /* { dg-warning {pointer targets in passing argument 2 of 'svld1sh_gather_s32index_u32' differ in signedness} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s32); + svld1sh_gather_index_u32 (pg, s16_ptr, u32); + svld1sh_gather_index_u32 (pg, s16_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + svld1sh_gather_index_u32 (pg, s16_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sh_gather_index_u32', which expects a vector of 32-bit integers} } */ + + svld1sh_gather_index_u32 (pg, 0, s32); + svld1sh_gather_index_u32 (pg, s, s32); /* { dg-error {'struct s' to argument 2 of 'svld1sh_gather_index_u32', which expects a vector or pointer base address} } */ + + svld1sh_gather_index_u32 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ + svld1sh_gather_index_u32 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ + svld1sh_gather_index_u32 (pg, u32, 0); + svld1sh_gather_index_u32 (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1sh_gather_index_u32', which expects 'svuint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_1.c new file mode 100644 index 0000000..dae4d0c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sb_gather_offset (pg, s8_ptr, s32); /* { dg-warning {implicit declaration of function 'svld1sb_gather_offset'; did you mean 'svld1_gather_offset'} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1sb_gather_offset_s32'} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1sb_gather_offset_s32'} } */ + svld1sb_gather_offset_s32 (pg, s16_ptr, s32); /* { dg-warning {passing argument 2 of 'svld1sb_gather_s32offset_s32' from incompatible pointer type} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, s32); + svld1sb_gather_offset_s32 (pg, s8_ptr, u32); + svld1sb_gather_offset_s32 (pg, s8_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_s32 (pg, s8_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sb_gather_offset_s32', which expects a vector of 32-bit integers} } */ + + svld1sb_gather_offset_s32 (pg, 0, s32); + svld1sb_gather_offset_s32 (pg, s, s32); /* { dg-error {'struct s' to argument 2 of 'svld1sb_gather_offset_s32', which expects a vector or pointer base address} } */ + + svld1sb_gather_offset_s32 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sb_gather_offset_s32', which expects 'svuint32_t'} } */ + svld1sb_gather_offset_s32 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sb_gather_offset_s32', which expects 'svuint32_t'} } */ + svld1sb_gather_offset_s32 (pg, u32, 0); + svld1sb_gather_offset_s32 (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1sb_gather_offset_s32', which expects 'svuint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_2.c new file mode 100644 index 0000000..1bc6697 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_2.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sb_gather_offset (pg, s8_ptr, s32); /* { dg-warning {implicit declaration of function 'svld1sb_gather_offset'; did you mean 'svld1_gather_offset'} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1sb_gather_offset_u32'} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1sb_gather_offset_u32'} } */ + svld1sb_gather_offset_u32 (pg, s16_ptr, s32); /* { dg-warning {passing argument 2 of 'svld1sb_gather_s32offset_u32' from incompatible pointer type} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, s32); + svld1sb_gather_offset_u32 (pg, s8_ptr, u32); + svld1sb_gather_offset_u32 (pg, s8_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + svld1sb_gather_offset_u32 (pg, s8_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sb_gather_offset_u32', which expects a vector of 32-bit integers} } */ + + svld1sb_gather_offset_u32 (pg, 0, s32); + svld1sb_gather_offset_u32 (pg, s, s32); /* { dg-error {'struct s' to argument 2 of 'svld1sb_gather_offset_u32', which expects a vector or pointer base address} } */ + + svld1sb_gather_offset_u32 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sb_gather_offset_u32', which expects 'svuint32_t'} } */ + svld1sb_gather_offset_u32 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sb_gather_offset_u32', which expects 'svuint32_t'} } */ + svld1sb_gather_offset_u32 (pg, u32, 0); + svld1sb_gather_offset_u32 (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1sb_gather_offset_u32', which expects 'svuint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_3.c new file mode 100644 index 0000000..6522889 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_3.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sb_gather_offset (pg, s8_ptr, s64); /* { dg-warning {implicit declaration of function 'svld1sb_gather_offset'; did you mean 'svld1_gather_offset'} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1sb_gather_offset_s64'} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, s64, 0); /* { dg-error {too many arguments to function 'svld1sb_gather_offset_s64'} } */ + svld1sb_gather_offset_s64 (pg, s16_ptr, s64); /* { dg-warning {passing argument 2 of 'svld1sb_gather_s64offset_s64' from incompatible pointer type} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_s64 (pg, s8_ptr, s64); + svld1sb_gather_offset_s64 (pg, s8_ptr, u64); + svld1sb_gather_offset_s64 (pg, s8_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sb_gather_offset_s64', which expects a vector of 64-bit integers} } */ + + svld1sb_gather_offset_s64 (pg, 0, s64); + svld1sb_gather_offset_s64 (pg, s, s64); /* { dg-error {'struct s' to argument 2 of 'svld1sb_gather_offset_s64', which expects a vector or pointer base address} } */ + + svld1sb_gather_offset_s64 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sb_gather_offset_s64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_s64 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sb_gather_offset_s64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_s64 (pg, u32, 0); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svld1sb_gather_offset_s64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_s64 (pg, u64, 0); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_4.c new file mode 100644 index 0000000..0256219 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_4.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1sb_gather_offset (pg, s8_ptr, s64); /* { dg-warning {implicit declaration of function 'svld1sb_gather_offset'; did you mean 'svld1_gather_offset'} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1sb_gather_offset_u64'} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, s64, 0); /* { dg-error {too many arguments to function 'svld1sb_gather_offset_u64'} } */ + svld1sb_gather_offset_u64 (pg, s16_ptr, s64); /* { dg-warning {passing argument 2 of 'svld1sb_gather_s64offset_u64' from incompatible pointer type} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + svld1sb_gather_offset_u64 (pg, s8_ptr, s64); + svld1sb_gather_offset_u64 (pg, s8_ptr, u64); + svld1sb_gather_offset_u64 (pg, s8_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1sb_gather_offset_u64', which expects a vector of 64-bit integers} } */ + + svld1sb_gather_offset_u64 (pg, 0, s64); + svld1sb_gather_offset_u64 (pg, s, s64); /* { dg-error {'struct s' to argument 2 of 'svld1sb_gather_offset_u64', which expects a vector or pointer base address} } */ + + svld1sb_gather_offset_u64 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1sb_gather_offset_u64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_u64 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1sb_gather_offset_u64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_u64 (pg, u32, 0); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svld1sb_gather_offset_u64', which expects 'svuint64_t'} } */ + svld1sb_gather_offset_u64 (pg, u64, 0); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_5.c new file mode 100644 index 0000000..8d57aa0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_ext_gather_offset_5.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, unsigned char *s8_ptr, unsigned short *s16_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svld1ub_gather_offset (pg, s8_ptr, s32); /* { dg-warning {implicit declaration of function 'svld1ub_gather_offset'; did you mean 'svld1_gather_offset'} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svld1ub_gather_offset_s32'} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1ub_gather_offset_s32'} } */ + svld1ub_gather_offset_s32 (pg, s16_ptr, s32); /* { dg-warning {passing argument 2 of 'svld1ub_gather_s32offset_s32' from incompatible pointer type} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, s32); + svld1ub_gather_offset_s32 (pg, s8_ptr, u32); + svld1ub_gather_offset_s32 (pg, s8_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + svld1ub_gather_offset_s32 (pg, s8_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1ub_gather_offset_s32', which expects a vector of 32-bit integers} } */ + + svld1ub_gather_offset_s32 (pg, 0, s32); + svld1ub_gather_offset_s32 (pg, s, s32); /* { dg-error {'struct s' to argument 2 of 'svld1ub_gather_offset_s32', which expects a vector or pointer base address} } */ + + svld1ub_gather_offset_s32 (pg, pg, 0); /* { dg-error {passing 'svbool_t' to argument 2 of 'svld1ub_gather_offset_s32', which expects 'svuint32_t'} } */ + svld1ub_gather_offset_s32 (pg, s32, 0); /* { dg-error {passing 'svint32_t' to argument 2 of 'svld1ub_gather_offset_s32', which expects 'svuint32_t'} } */ + svld1ub_gather_offset_s32 (pg, u32, 0); + svld1ub_gather_offset_s32 (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1ub_gather_offset_s32', which expects 'svuint32_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_1.c new file mode 100644 index 0000000..21566a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_1.c @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint32_t +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + int32_t *s32_ptr, uint32_t *u32_ptr, float *f32_ptr, + int64_t *s64_ptr, uint64_t *u64_ptr, double *f64_ptr, + void *void_ptr, struct s *s_ptr, _Complex float *cf32_ptr, int **ptr_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64) +{ + svld1_gather_offset (pg, s32_ptr); /* { dg-error {too few arguments to function 'svld1_gather_offset'} } */ + svld1_gather_offset (pg, s32_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1_gather_offset'} } */ + svld1_gather_offset (0, s32_ptr, s32); /* { dg-error {passing 'int' to argument 1 of 'svld1_gather_offset', which expects 'svbool_t'} } */ + svld1_gather_offset (pg, 0, s32); /* { dg-error {passing 'int' to argument 2 of 'svld1_gather_offset', which expects a pointer type} } */ + svld1_gather_offset (pg, (int *) 0, s32); + svld1_gather_offset (pg, void_ptr, s32); /* { dg-error {passing 'void \*' to argument 2 of 'svld1_gather_offset', but 'void' is not a valid SVE element type} } */ + svld1_gather_offset (pg, s_ptr, s32); /* { dg-error {passing 'struct s \*' to argument 2 of 'svld1_gather_offset', but 'struct s' is not a valid SVE element type} } */ + svld1_gather_offset (pg, f32_ptr, s32); + svld1_gather_offset (pg, cf32_ptr, s32); /* { dg-error {passing '_Complex float \*' to argument 2 of 'svld1_gather_offset', but 'complex float' is not a valid SVE element type} } */ + svld1_gather_offset (pg, ptr_ptr, u64); /* { dg-error {passing 'int \*\*' to argument 2 of 'svld1_gather_offset', but 'int \*' is not a valid SVE element type} } */ + svld1_gather_offset (pg, u32, 0); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svld1_gather_offset', which expects a pointer type} } */ + /* { dg-message {an explicit type suffix is needed when using a vector of base addresses} "" { target *-*-* } .-1 } */ + svld1_gather_offset (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1_gather_offset', which expects a pointer type} } */ + /* { dg-message {an explicit type suffix is needed when using a vector of base addresses} "" { target *-*-* } .-1 } */ + + svld1_gather_offset (pg, s8_ptr, s8); /* { dg-error {passing 'signed char \*' to argument 2 of 'svld1_gather_offset', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_offset (pg, s8_ptr, s32); /* { dg-error {passing 'signed char \*' to argument 2 of 'svld1_gather_offset', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_offset (pg, s16_ptr, s16); /* { dg-error {passing 'short( int)? \*' to argument 2 of 'svld1_gather_offset', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_offset (pg, s16_ptr, s32); /* { dg-error {passing 'short( int)? \*' to argument 2 of 'svld1_gather_offset', which expects a pointer to 32-bit or 64-bit elements} } */ + + svld1_gather_offset (pg, s32_ptr, s32); + svld1_gather_offset (pg, s32_ptr, u32); + svld1_gather_offset (pg, s32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, s32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, s32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, s32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_offset (pg, u32_ptr, s32); + svld1_gather_offset (pg, u32_ptr, u32); + svld1_gather_offset (pg, u32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, u32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, u32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, u32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_offset (pg, f32_ptr, s32); + svld1_gather_offset (pg, f32_ptr, u32); + svld1_gather_offset (pg, f32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, f32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, f32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_offset (pg, f32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_offset (pg, s64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, s64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, s64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, s64_ptr, s64); + svld1_gather_offset (pg, s64_ptr, u64); + svld1_gather_offset (pg, s64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + + svld1_gather_offset (pg, u64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, u64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, u64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, u64_ptr, s64); + svld1_gather_offset (pg, u64_ptr, u64); + svld1_gather_offset (pg, u64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + + svld1_gather_offset (pg, f64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, f64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, f64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_offset (pg, f64_ptr, s64); + svld1_gather_offset (pg, f64_ptr, u64); + svld1_gather_offset (pg, f64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_offset', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + + return svld1_gather_offset (pg, s32_ptr, s32); /* { dg-error {incompatible types when returning type 'svint32_t' but 'svuint32_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_2.c new file mode 100644 index 0000000..4c15fc4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_gather_sv_2.c @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint32_t +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + int32_t *s32_ptr, uint32_t *u32_ptr, float *f32_ptr, + int64_t *s64_ptr, uint64_t *u64_ptr, double *f64_ptr, + void *void_ptr, struct s *s_ptr, _Complex float *cf32_ptr, int **ptr_ptr, + svint8_t s8, svint16_t s16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64) +{ + svld1_gather_index (pg, s32_ptr); /* { dg-error {too few arguments to function 'svld1_gather_index'} } */ + svld1_gather_index (pg, s32_ptr, s32, 0); /* { dg-error {too many arguments to function 'svld1_gather_index'} } */ + svld1_gather_index (0, s32_ptr, s32); /* { dg-error {passing 'int' to argument 1 of 'svld1_gather_index', which expects 'svbool_t'} } */ + svld1_gather_index (pg, 0, s32); /* { dg-error {passing 'int' to argument 2 of 'svld1_gather_index', which expects a pointer type} } */ + svld1_gather_index (pg, (int *) 0, s32); + svld1_gather_index (pg, void_ptr, s32); /* { dg-error {passing 'void \*' to argument 2 of 'svld1_gather_index', but 'void' is not a valid SVE element type} } */ + svld1_gather_index (pg, s_ptr, s32); /* { dg-error {passing 'struct s \*' to argument 2 of 'svld1_gather_index', but 'struct s' is not a valid SVE element type} } */ + svld1_gather_index (pg, f32_ptr, s32); + svld1_gather_index (pg, cf32_ptr, s32); /* { dg-error {passing '_Complex float \*' to argument 2 of 'svld1_gather_index', but 'complex float' is not a valid SVE element type} } */ + svld1_gather_index (pg, ptr_ptr, u64); /* { dg-error {passing 'int \*\*' to argument 2 of 'svld1_gather_index', but 'int \*' is not a valid SVE element type} } */ + svld1_gather_index (pg, u32, 0); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svld1_gather_index', which expects a pointer type} } */ + /* { dg-message {an explicit type suffix is needed when using a vector of base addresses} "" { target *-*-* } .-1 } */ + svld1_gather_index (pg, u64, 0); /* { dg-error {passing 'svuint64_t' to argument 2 of 'svld1_gather_index', which expects a pointer type} } */ + /* { dg-message {an explicit type suffix is needed when using a vector of base addresses} "" { target *-*-* } .-1 } */ + + svld1_gather_index (pg, s8_ptr, s8); /* { dg-error {passing 'signed char \*' to argument 2 of 'svld1_gather_index', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_index (pg, s8_ptr, s32); /* { dg-error {passing 'signed char \*' to argument 2 of 'svld1_gather_index', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_index (pg, s16_ptr, s16); /* { dg-error {passing 'short( int)? \*' to argument 2 of 'svld1_gather_index', which expects a pointer to 32-bit or 64-bit elements} } */ + svld1_gather_index (pg, s16_ptr, s32); /* { dg-error {passing 'short( int)? \*' to argument 2 of 'svld1_gather_index', which expects a pointer to 32-bit or 64-bit elements} } */ + + svld1_gather_index (pg, s32_ptr, s32); + svld1_gather_index (pg, s32_ptr, u32); + svld1_gather_index (pg, s32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, s32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, s32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, s32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svint32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_index (pg, u32_ptr, s32); + svld1_gather_index (pg, u32_ptr, u32); + svld1_gather_index (pg, u32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, u32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, u32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, u32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_index (pg, f32_ptr, s32); + svld1_gather_index (pg, f32_ptr, u32); + svld1_gather_index (pg, f32_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, f32_ptr, s64); /* { dg-error {passing 'svint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, f32_ptr, u64); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + svld1_gather_index (pg, f32_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat32_t' expects a vector of 32-bit integers} } */ + + svld1_gather_index (pg, s64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, s64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, s64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, s64_ptr, s64); + svld1_gather_index (pg, s64_ptr, u64); + svld1_gather_index (pg, s64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svint64_t' expects a vector of 64-bit integers} } */ + + svld1_gather_index (pg, u64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, u64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, u64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, u64_ptr, s64); + svld1_gather_index (pg, u64_ptr, u64); + svld1_gather_index (pg, u64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svuint64_t' expects a vector of 64-bit integers} } */ + + svld1_gather_index (pg, f64_ptr, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, f64_ptr, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, f64_ptr, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + svld1_gather_index (pg, f64_ptr, s64); + svld1_gather_index (pg, f64_ptr, u64); + svld1_gather_index (pg, f64_ptr, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svld1_gather_index', which when loading 'svfloat64_t' expects a vector of 64-bit integers} } */ + + return svld1_gather_index (pg, s32_ptr, s32); /* { dg-error {incompatible types when returning type 'svint32_t' but 'svuint32_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_replicate_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_replicate_1.c new file mode 100644 index 0000000..d4ff76e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/load_replicate_1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr, + float *f32_ptr, _Complex float *cf32_ptr, int **ptr_ptr) +{ + svld1rq (pg); /* { dg-error {too few arguments to function 'svld1rq'} } */ + svld1rq (pg, s8_ptr, 0); /* { dg-error {too many arguments to function 'svld1rq'} } */ + svld1rq (0, s8_ptr); /* { dg-error {passing 'int' to argument 1 of 'svld1rq', which expects 'svbool_t'} } */ + svld1rq (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svld1rq', which expects a pointer type} } */ + svld1rq (pg, (int *) 0); + svld1rq (pg, void_ptr); /* { dg-error {passing 'void \*' to argument 2 of 'svld1rq', but 'void' is not a valid SVE element type} } */ + svld1rq (pg, s_ptr); /* { dg-error {passing 'struct s \*' to argument 2 of 'svld1rq', but 'struct s' is not a valid SVE element type} } */ + svld1rq (pg, f32_ptr); + svld1rq (pg, cf32_ptr); /* { dg-error {passing '_Complex float \*' to argument 2 of 'svld1rq', but 'complex float' is not a valid SVE element type} } */ + svld1rq (pg, ptr_ptr); /* { dg-error {passing 'int \*\*' to argument 2 of 'svld1rq', but 'int \*' is not a valid SVE element type} } */ + return svld1rq (pg, s8_ptr); /* { dg-error {incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/pattern_pred_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/pattern_pred_1.c new file mode 100644 index 0000000..99b61bd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/pattern_pred_1.c @@ -0,0 +1,14 @@ +#include <arm_sve.h> + +void +test () +{ + svptrue_pat_b16 ((enum svpattern) -1); /* { dg-error {passing 4294967295 to argument 1 of 'svptrue_pat_b16', which expects a valid 'enum svpattern' value} } */ + svptrue_pat_b16 ((enum svpattern) 0); + svptrue_pat_b16 ((enum svpattern) 13); + svptrue_pat_b16 ((enum svpattern) 14); /* { dg-error {passing 14 to argument 1 of 'svptrue_pat_b16', which expects a valid 'enum svpattern' value} } */ + svptrue_pat_b16 ((enum svpattern) 28); /* { dg-error {passing 28 to argument 1 of 'svptrue_pat_b16', which expects a valid 'enum svpattern' value} } */ + svptrue_pat_b16 ((enum svpattern) 29); + svptrue_pat_b16 ((enum svpattern) 31); + svptrue_pat_b16 ((enum svpattern) 32); /* { dg-error {passing 32 to argument 1 of 'svptrue_pat_b16', which expects a valid 'enum svpattern' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_1.c new file mode 100644 index 0000000..316f77f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, int32_t *s32_ptr, enum svprfop op) +{ + svprfb (pg, s32_ptr, op); /* { dg-error {argument 3 of 'svprfb' must be an integer constant expression} } */ + svprfb (pg, s32_ptr, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 3 of 'svprfb', which expects a valid 'enum svprfop' value} } */ + svprfb (pg, s32_ptr, (enum svprfop) 0); + svprfb (pg, s32_ptr, (enum svprfop) 5); + svprfb (pg, s32_ptr, (enum svprfop) 6); /* { dg-error {passing 6 to argument 3 of 'svprfb', which expects a valid 'enum svprfop' value} } */ + svprfb (pg, s32_ptr, (enum svprfop) 7); /* { dg-error {passing 7 to argument 3 of 'svprfb', which expects a valid 'enum svprfop' value} } */ + svprfb (pg, s32_ptr, (enum svprfop) 8); + svprfb (pg, s32_ptr, (enum svprfop) 14); /* { dg-error {passing 14 to argument 3 of 'svprfb', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_1.c new file mode 100644 index 0000000..c33c954 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, int32_t *s32_ptr, void *void_ptr, void **ptr_ptr, + svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, enum svprfop op, + struct s s) +{ + svprfh_gather_index (pg, s32_ptr, s32); /* { dg-error {too few arguments to function 'svprfh_gather_index'} } */ + svprfh_gather_index (pg, s32_ptr, s32, SV_PLDL1KEEP, 0); /* { dg-error {too many arguments to function 'svprfh_gather_index'} } */ + svprfh_gather_index (0, s32_ptr, s32, SV_PLDL1KEEP); /* { dg-error {passing 'int' to argument 1 of 'svprfh_gather_index', which expects 'svbool_t'} } */ + svprfh_gather_index (pg, 0, s32, SV_PLDL1KEEP); + svprfh_gather_index (pg, (int *) 0, s32, SV_PLDL1KEEP); + svprfh_gather_index (pg, void_ptr, s32, SV_PLDL1KEEP); + svprfh_gather_index (pg, ptr_ptr, s32, SV_PLDL1KEEP); + svprfh_gather_index (pg, s, s32, SV_PLDL1KEEP); /* { dg-error {passing 'struct s' to argument 2 of 'svprfh_gather_index', which expects a vector or pointer base address} } */ + + svprfh_gather_index (pg, s32_ptr, s8, SV_PLDL1KEEP); /* { dg-error {passing 'svint8_t' to argument 3 of 'svprfh_gather_index', which expects a vector of 32-bit or 64-bit integers} } */ + svprfh_gather_index (pg, s32_ptr, u8, SV_PLDL1KEEP); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svprfh_gather_index', which expects a vector of 32-bit or 64-bit integers} } */ + svprfh_gather_index (pg, s32_ptr, s16, SV_PLDL1KEEP); /* { dg-error {passing 'svint16_t' to argument 3 of 'svprfh_gather_index', which expects a vector of 32-bit or 64-bit integers} } */ + svprfh_gather_index (pg, s32_ptr, u16, SV_PLDL1KEEP); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svprfh_gather_index', which expects a vector of 32-bit or 64-bit integers} } */ + svprfh_gather_index (pg, s32_ptr, f16, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svprfh_gather_index', which expects a vector of integers} } */ + svprfh_gather_index (pg, s32_ptr, s32, SV_PLDL1KEEP); + svprfh_gather_index (pg, s32_ptr, u32, SV_PLDL1KEEP); + svprfh_gather_index (pg, s32_ptr, f32, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svprfh_gather_index', which expects a vector of integers} } */ + svprfh_gather_index (pg, s32_ptr, s64, SV_PLDL1KEEP); + svprfh_gather_index (pg, s32_ptr, u64, SV_PLDL1KEEP); + svprfh_gather_index (pg, s32_ptr, f64, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svprfh_gather_index', which expects a vector of integers} } */ + + svprfh_gather_index (pg, u8, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfh_gather_index (pg, u16, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svuint16_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfh_gather_index (pg, s32, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svint32_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfh_gather_index (pg, u32, 0, SV_PLDL1KEEP); + svprfh_gather_index (pg, f32, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfh_gather_index (pg, s64, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svint64_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfh_gather_index (pg, u64, 0, SV_PLDL1KEEP); + svprfh_gather_index (pg, f64, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svprfh_gather_index', which expects 'svuint32_t' or 'svuint64_t'} } */ + + svprfh_gather_index (pg, s32_ptr, s32, op); /* { dg-error {argument 4 of 'svprfh_gather_index' must be an integer constant expression} } */ + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 4 of 'svprfh_gather_index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 0); + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 5); + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 4 of 'svprfh_gather_index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 4 of 'svprfh_gather_index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 8); + svprfh_gather_index (pg, s32_ptr, s32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 4 of 'svprfh_gather_index', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_2.c new file mode 100644 index 0000000..3d77973 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_index_2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, int32_t *s32_ptr, svint32_t s32, enum svprfop op) +{ + svprfh_gather_s32index (pg, s32_ptr, s32, op); /* { dg-error {argument 4 of 'svprfh_gather_s32index' must be an integer constant expression} } */ + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 4 of 'svprfh_gather_s32index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 0); + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 5); + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 4 of 'svprfh_gather_s32index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 4 of 'svprfh_gather_s32index', which expects a valid 'enum svprfop' value} } */ + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 8); + svprfh_gather_s32index (pg, s32_ptr, s32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 4 of 'svprfh_gather_s32index', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_1.c new file mode 100644 index 0000000..cc61901 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { int i; }; + +void +f1 (svbool_t pg, int32_t *s32_ptr, void *void_ptr, void **ptr_ptr, + svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, enum svprfop op, + struct s s) +{ + svprfb_gather_offset (pg, s32_ptr, s32); /* { dg-error {too few arguments to function 'svprfb_gather_offset'} } */ + svprfb_gather_offset (pg, s32_ptr, s32, SV_PLDL1KEEP, 0); /* { dg-error {too many arguments to function 'svprfb_gather_offset'} } */ + svprfb_gather_offset (0, s32_ptr, s32, SV_PLDL1KEEP); /* { dg-error {passing 'int' to argument 1 of 'svprfb_gather_offset', which expects 'svbool_t'} } */ + svprfb_gather_offset (pg, 0, s32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, (int *) 0, s32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, void_ptr, s32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, ptr_ptr, s32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, s, s32, SV_PLDL1KEEP); /* { dg-error {passing 'struct s' to argument 2 of 'svprfb_gather_offset', which expects a vector or pointer base address} } */ + + svprfb_gather_offset (pg, s32_ptr, s8, SV_PLDL1KEEP); /* { dg-error {passing 'svint8_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svprfb_gather_offset (pg, s32_ptr, u8, SV_PLDL1KEEP); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svprfb_gather_offset (pg, s32_ptr, s16, SV_PLDL1KEEP); /* { dg-error {passing 'svint16_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svprfb_gather_offset (pg, s32_ptr, u16, SV_PLDL1KEEP); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of 32-bit or 64-bit integers} } */ + svprfb_gather_offset (pg, s32_ptr, f16, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of integers} } */ + svprfb_gather_offset (pg, s32_ptr, s32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, s32_ptr, u32, SV_PLDL1KEEP); + svprfb_gather_offset (pg, s32_ptr, f32, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of integers} } */ + svprfb_gather_offset (pg, s32_ptr, s64, SV_PLDL1KEEP); + svprfb_gather_offset (pg, s32_ptr, u64, SV_PLDL1KEEP); + svprfb_gather_offset (pg, s32_ptr, f64, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svprfb_gather_offset', which expects a vector of integers} } */ + + svprfb_gather_offset (pg, u8, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather_offset (pg, u16, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svuint16_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather_offset (pg, s32, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svint32_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather_offset (pg, u32, 0, SV_PLDL1KEEP); + svprfb_gather_offset (pg, f32, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather_offset (pg, s64, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svint64_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather_offset (pg, u64, 0, SV_PLDL1KEEP); + svprfb_gather_offset (pg, f64, 0, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svprfb_gather_offset', which expects 'svuint32_t' or 'svuint64_t'} } */ + + svprfb_gather_offset (pg, s32_ptr, s32, op); /* { dg-error {argument 4 of 'svprfb_gather_offset' must be an integer constant expression} } */ + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 4 of 'svprfb_gather_offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 0); + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 5); + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 4 of 'svprfb_gather_offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 4 of 'svprfb_gather_offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 8); + svprfb_gather_offset (pg, s32_ptr, s32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 4 of 'svprfb_gather_offset', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_2.c new file mode 100644 index 0000000..b74721f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_2.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, enum svprfop op) +{ + svprfb_gather (pg, u32); /* { dg-error {too few arguments to function 'svprfb_gather'} } */ + svprfb_gather (pg, u32, SV_PLDL1KEEP, 0); /* { dg-error {too many arguments to function 'svprfb_gather'} } */ + svprfb_gather (0, u32, SV_PLDL1KEEP); /* { dg-error {passing 'int' to argument 1 of 'svprfb_gather', which expects 'svbool_t'} } */ + svprfb_gather (pg, 0, SV_PLDL1KEEP); /* { dg-error {passing 'int' to argument 2 of 'svprfb_gather', which expects an SVE vector type} } */ + + svprfb_gather (pg, s8, SV_PLDL1KEEP); /* { dg-error {passing 'svint8_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, u8, SV_PLDL1KEEP); /* { dg-error {passing 'svuint8_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, s16, SV_PLDL1KEEP); /* { dg-error {passing 'svint16_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, u16, SV_PLDL1KEEP); /* { dg-error {passing 'svuint16_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, f16, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat16_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, s32, SV_PLDL1KEEP); /* { dg-error {passing 'svint32_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, u32, SV_PLDL1KEEP); + svprfb_gather (pg, f32, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat32_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, s64, SV_PLDL1KEEP); /* { dg-error {passing 'svint64_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + svprfb_gather (pg, u64, SV_PLDL1KEEP); + svprfb_gather (pg, f64, SV_PLDL1KEEP); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svprfb_gather', which expects 'svuint32_t' or 'svuint64_t'} } */ + + svprfb_gather (pg, u32, op); /* { dg-error {argument 3 of 'svprfb_gather' must be an integer constant expression} } */ + svprfb_gather (pg, u32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 3 of 'svprfb_gather', which expects a valid 'enum svprfop' value} } */ + svprfb_gather (pg, u32, (enum svprfop) 0); + svprfb_gather (pg, u32, (enum svprfop) 5); + svprfb_gather (pg, u32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 3 of 'svprfb_gather', which expects a valid 'enum svprfop' value} } */ + svprfb_gather (pg, u32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 3 of 'svprfb_gather', which expects a valid 'enum svprfop' value} } */ + svprfb_gather (pg, u32, (enum svprfop) 8); + svprfb_gather (pg, u32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 3 of 'svprfb_gather', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_3.c new file mode 100644 index 0000000..24b4aa1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, int32_t *s32_ptr, svint32_t s32, enum svprfop op) +{ + svprfb_gather_s32offset (pg, s32_ptr, s32, op); /* { dg-error {argument 4 of 'svprfb_gather_s32offset' must be an integer constant expression} } */ + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 4 of 'svprfb_gather_s32offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 0); + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 5); + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 4 of 'svprfb_gather_s32offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 4 of 'svprfb_gather_s32offset', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 8); + svprfb_gather_s32offset (pg, s32_ptr, s32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 4 of 'svprfb_gather_s32offset', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_4.c new file mode 100644 index 0000000..63ccdc5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/prefetch_gather_offset_4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint32_t u32, enum svprfop op) +{ + svprfb_gather_u32base (pg, u32, op); /* { dg-error {argument 3 of 'svprfb_gather_u32base' must be an integer constant expression} } */ + svprfb_gather_u32base (pg, u32, (enum svprfop) -1); /* { dg-error {passing 4294967295 to argument 3 of 'svprfb_gather_u32base', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_u32base (pg, u32, (enum svprfop) 0); + svprfb_gather_u32base (pg, u32, (enum svprfop) 5); + svprfb_gather_u32base (pg, u32, (enum svprfop) 6); /* { dg-error {passing 6 to argument 3 of 'svprfb_gather_u32base', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_u32base (pg, u32, (enum svprfop) 7); /* { dg-error {passing 7 to argument 3 of 'svprfb_gather_u32base', which expects a valid 'enum svprfop' value} } */ + svprfb_gather_u32base (pg, u32, (enum svprfop) 8); + svprfb_gather_u32base (pg, u32, (enum svprfop) 14); /* { dg-error {passing 14 to argument 3 of 'svprfb_gather_u32base', which expects a valid 'enum svprfop' value} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_1.c new file mode 100644 index 0000000..ab0ef30 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svuint32x2_t u32x2) +{ + svorv (pg); /* { dg-error {too few arguments to function 'svorv'} } */ + svorv (pg, u32, u32); /* { dg-error {too many arguments to function 'svorv'} } */ + svorv (0, u32); /* { dg-error {passing 'int' to argument 1 of 'svorv', which expects 'svbool_t'} } */ + svorv (u32, u32); /* { dg-error {passing 'svuint32_t' to argument 1 of 'svorv', which expects 'svbool_t'} } */ + svorv (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svorv', which expects an SVE vector type} } */ + svorv (pg, pg); /* { dg-error {'svorv' has no form that takes 'svbool_t' arguments} } */ + svorv (pg, s32); + svorv (pg, u32); + svorv (pg, f32); /* { dg-error {'svorv' has no form that takes 'svfloat32_t' arguments} } */ + svorv (pg, u32x2); /* { dg-error {passing 'svuint32x2_t' to argument 2 of 'svorv', which expects a single SVE vector rather than a tuple} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_wide_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_wide_1.c new file mode 100644 index 0000000..f99a288 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/reduction_wide_1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svuint32x2_t u32x2) +{ + svaddv (pg); /* { dg-error {too few arguments to function 'svaddv'} } */ + svaddv (pg, u32, u32); /* { dg-error {too many arguments to function 'svaddv'} } */ + svaddv (0, u32); /* { dg-error {passing 'int' to argument 1 of 'svaddv', which expects 'svbool_t'} } */ + svaddv (u32, u32); /* { dg-error {passing 'svuint32_t' to argument 1 of 'svaddv', which expects 'svbool_t'} } */ + svaddv (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svaddv', which expects an SVE vector type} } */ + svaddv (pg, pg); /* { dg-error {'svaddv' has no form that takes 'svbool_t' arguments} } */ + svaddv (pg, s32); + svaddv (pg, u32); + svaddv (pg, f32); + svaddv (pg, u32x2); /* { dg-error {passing 'svuint32x2_t' to argument 2 of 'svaddv', which expects a single SVE vector rather than a tuple} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_1.c new file mode 100644 index 0000000..f07c761 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8x2 = svset2 (u8x2); /* { dg-error {too few arguments to function 'svset2'} } */ + u8x2 = svset2 (u8x2, 1); /* { dg-error {too few arguments to function 'svset2'} } */ + u8x2 = svset2 (u8x2, 1, u8, 3); /* { dg-error {too many arguments to function 'svset2'} } */ + u8x2 = svset2 (u8, 0, u8); /* { dg-error {passing single vector 'svuint8_t' to argument 1 of 'svset2', which expects a tuple of 2 vectors} } */ + u8x2 = svset2 (u8x3, 0, u8); /* { dg-error {passing 'svuint8x3_t' to argument 1 of 'svset2', which expects a tuple of 2 vectors} } */ + u8x2 = svset2 (pg, 0, u8); /* { dg-error {passing 'svbool_t' to argument 1 of 'svset2', which expects a tuple of 2 vectors} } */ + u8x2 = svset2 (u8x2, 0, u8x2); /* { dg-error {passing 'svuint8x2_t' to argument 3 of 'svset2', which expects a single SVE vector rather than a tuple} } */ + u8x2 = svset2 (u8x2, 0, f64); /* { dg-error {passing 'svfloat64_t' instead of the expected 'svuint8_t' to argument 3 of 'svset2', after passing 'svuint8x2_t' to argument 1} } */ + u8x2 = svset2 (u8x2, 0, pg); /* { dg-error {passing 'svbool_t' instead of the expected 'svuint8_t' to argument 3 of 'svset2', after passing 'svuint8x2_t' to argument 1} } */ + u8x2 = svset2 (u8x2, x, u8); /* { dg-error {argument 2 of 'svset2' must be an integer constant expression} } */ + u8x2 = svset2 (u8x2, 0, u8); + f64 = svset2 (u8x2, 0, u8); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svuint8x2_t'} } */ + u8x2 = svset2 (u8x2, 1, u8); + u8x2 = svset2 (u8x2, 2, u8); /* { dg-error {passing 2 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 3, u8); /* { dg-error {passing 3 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 4, u8); /* { dg-error {passing 4 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, 5, u8); /* { dg-error {passing 5 to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, ~0U, u8); /* { dg-error {passing [^ ]* to argument 2 of 'svset2', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2 (u8x2, one, u8); /* { dg-error {argument 2 of 'svset2' must be an integer constant expression} } */ + u8x2 = svset2 (u8x2, 3 - 2, u8); + u8x2 = svset2 (u8x2, 1.0, u8); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_2.c new file mode 100644 index 0000000..ae277ea --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_2.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svuint8_t u8, svuint8x2_t u8x2, svint8x2_t s8x2, + svuint8x3_t u8x3, int x) +{ + const int one = 1; + svfloat64_t f64; + + u8x2 = svset2_u8 (u8x2); /* { dg-error {too few arguments to function 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, 1); /* { dg-error {too few arguments to function 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, 1, u8, 3); /* { dg-error {too many arguments to function 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8, 0, u8); /* { dg-error {incompatible type for argument 1 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (s8x2, 0, u8); /* { dg-error {incompatible type for argument 1 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x3, 0, u8); /* { dg-error {incompatible type for argument 1 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (pg, 0, u8); /* { dg-error {incompatible type for argument 1 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, 0, u8x2); /* { dg-error {incompatible type for argument 3 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, 0, f64); /* { dg-error {incompatible type for argument 3 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, 0, pg); /* { dg-error {incompatible type for argument 3 of 'svset2_u8'} } */ + u8x2 = svset2_u8 (u8x2, x, u8); /* { dg-error {argument 2 of 'svset2_u8' must be an integer constant expression} } */ + u8x2 = svset2_u8 (u8x2, 0, u8); + f64 = svset2_u8 (u8x2, 0, u8); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svuint8x2_t'} } */ + u8x2 = svset2_u8 (u8x2, 1, u8); + u8x2 = svset2_u8 (u8x2, 2, u8); /* { dg-error {passing 2 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 3, u8); /* { dg-error {passing 3 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 4, u8); /* { dg-error {passing 4 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, 5, u8); /* { dg-error {passing 5 to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, ~0U, u8); /* { dg-error {passing [^ ]* to argument 2 of 'svset2_u8', which expects a value in the range \[0, 1\]} } */ + u8x2 = svset2_u8 (u8x2, one, u8); /* { dg-error {argument 2 of 'svset2_u8' must be an integer constant expression} } */ + u8x2 = svset2_u8 (u8x2, 3 - 2, u8); + u8x2 = svset2_u8 (u8x2, 1.0, u8); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_3.c new file mode 100644 index 0000000..543a1be --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_3.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svfloat16x4_t f16x4, + int x) +{ + const int one = 1; + svfloat64_t f64; + + f16x3 = svset3 (f16x3); /* { dg-error {too few arguments to function 'svset3'} } */ + f16x3 = svset3 (f16x3, 1); /* { dg-error {too few arguments to function 'svset3'} } */ + f16x3 = svset3 (f16x3, 1, f16, 3); /* { dg-error {too many arguments to function 'svset3'} } */ + f16x3 = svset3 (f16, 0, f16); /* { dg-error {passing single vector 'svfloat16_t' to argument 1 of 'svset3', which expects a tuple of 3 vectors} } */ + f16x3 = svset3 (f16x4, 0, f16); /* { dg-error {passing 'svfloat16x4_t' to argument 1 of 'svset3', which expects a tuple of 3 vectors} } */ + f16x3 = svset3 (pg, 0, f16); /* { dg-error {passing 'svbool_t' to argument 1 of 'svset3', which expects a tuple of 3 vectors} } */ + f16x3 = svset3 (f16x3, 0, f16x3); /* { dg-error {passing 'svfloat16x3_t' to argument 3 of 'svset3', which expects a single SVE vector rather than a tuple} } */ + f16x3 = svset3 (f16x3, 0, f64); /* { dg-error {passing 'svfloat64_t' instead of the expected 'svfloat16_t' to argument 3 of 'svset3', after passing 'svfloat16x3_t' to argument 1} } */ + f16x3 = svset3 (f16x3, 0, pg); /* { dg-error {passing 'svbool_t' instead of the expected 'svfloat16_t' to argument 3 of 'svset3', after passing 'svfloat16x3_t' to argument 1} } */ + f16x3 = svset3 (f16x3, x, f16); /* { dg-error {argument 2 of 'svset3' must be an integer constant expression} } */ + f16x3 = svset3 (f16x3, 0, f16); + f64 = svset3 (f16x3, 0, f16); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svfloat16x3_t'} } */ + f16x3 = svset3 (f16x3, 1, f16); + f16x3 = svset3 (f16x3, 2, f16); + f16x3 = svset3 (f16x3, 3, f16); /* { dg-error {passing 3 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, 4, f16); /* { dg-error {passing 4 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, 5, f16); /* { dg-error {passing 5 to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, ~0U, f16); /* { dg-error {passing [^ ]* to argument 2 of 'svset3', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3 (f16x3, one, f16); /* { dg-error {argument 2 of 'svset3' must be an integer constant expression} } */ + f16x3 = svset3 (f16x3, 3 - 2, f16); + f16x3 = svset3 (f16x3, 1.0, f16); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_4.c new file mode 100644 index 0000000..198b034 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_4.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svfloat16_t f16, svfloat16x3_t f16x3, svuint16x3_t u16x3, + svfloat16x4_t f16x4, int x) +{ + const int one = 1; + svfloat64_t f64; + + f16x3 = svset3_f16 (f16x3); /* { dg-error {too few arguments to function 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, 1); /* { dg-error {too few arguments to function 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, 1, f16, 3); /* { dg-error {too many arguments to function 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16, 0, f16); /* { dg-error {incompatible type for argument 1 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (u16x3, 0, f16); /* { dg-error {incompatible type for argument 1 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x4, 0, f16); /* { dg-error {incompatible type for argument 1 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (pg, 0, f16); /* { dg-error {incompatible type for argument 1 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, 0, f16x3); /* { dg-error {incompatible type for argument 3 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, 0, f64); /* { dg-error {incompatible type for argument 3 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, 0, pg); /* { dg-error {incompatible type for argument 3 of 'svset3_f16'} } */ + f16x3 = svset3_f16 (f16x3, x, f16); /* { dg-error {argument 2 of 'svset3_f16' must be an integer constant expression} } */ + f16x3 = svset3_f16 (f16x3, 0, f16); + f64 = svset3_f16 (f16x3, 0, f16); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svfloat16x3_t'} } */ + f16x3 = svset3_f16 (f16x3, 1, f16); + f16x3 = svset3_f16 (f16x3, 2, f16); + f16x3 = svset3_f16 (f16x3, 3, f16); /* { dg-error {passing 3 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, 4, f16); /* { dg-error {passing 4 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, 5, f16); /* { dg-error {passing 5 to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, ~0U, f16); /* { dg-error {passing [^ ]* to argument 2 of 'svset3_f16', which expects a value in the range \[0, 2\]} } */ + f16x3 = svset3_f16 (f16x3, one, f16); /* { dg-error {argument 2 of 'svset3_f16' must be an integer constant expression} } */ + f16x3 = svset3_f16 (f16x3, 3 - 2, f16); + f16x3 = svset3_f16 (f16x3, 1.0, f16); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_5.c new file mode 100644 index 0000000..be911a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_5.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32x4 = svset4 (s32x4); /* { dg-error {too few arguments to function 'svset4'} } */ + s32x4 = svset4 (s32x4, 1); /* { dg-error {too few arguments to function 'svset4'} } */ + s32x4 = svset4 (s32x4, 1, s32, 3); /* { dg-error {too many arguments to function 'svset4'} } */ + s32x4 = svset4 (s32, 0, s32); /* { dg-error {passing single vector 'svint32_t' to argument 1 of 'svset4', which expects a tuple of 4 vectors} } */ + s32x4 = svset4 (s32x2, 0, s32); /* { dg-error {passing 'svint32x2_t' to argument 1 of 'svset4', which expects a tuple of 4 vectors} } */ + s32x4 = svset4 (pg, 0, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svset4', which expects a tuple of 4 vectors} } */ + s32x4 = svset4 (s32x4, 0, s32x4); /* { dg-error {passing 'svint32x4_t' to argument 3 of 'svset4', which expects a single SVE vector rather than a tuple} } */ + s32x4 = svset4 (s32x4, 0, f64); /* { dg-error {passing 'svfloat64_t' instead of the expected 'svint32_t' to argument 3 of 'svset4', after passing 'svint32x4_t' to argument 1} } */ + s32x4 = svset4 (s32x4, 0, pg); /* { dg-error {passing 'svbool_t' instead of the expected 'svint32_t' to argument 3 of 'svset4', after passing 'svint32x4_t' to argument 1} } */ + s32x4 = svset4 (s32x4, x, s32); /* { dg-error {argument 2 of 'svset4' must be an integer constant expression} } */ + s32x4 = svset4 (s32x4, 0, s32); + f64 = svset4 (s32x4, 0, s32); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svint32x4_t'} } */ + s32x4 = svset4 (s32x4, 1, s32); + s32x4 = svset4 (s32x4, 2, s32); + s32x4 = svset4 (s32x4, 3, s32); + s32x4 = svset4 (s32x4, 4, s32); /* { dg-error {passing 4 to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, 5, s32); /* { dg-error {passing 5 to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, ~0U, s32); /* { dg-error {passing [^ ]* to argument 2 of 'svset4', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4 (s32x4, one, s32); /* { dg-error {argument 2 of 'svset4' must be an integer constant expression} } */ + s32x4 = svset4 (s32x4, 3 - 2, s32); + s32x4 = svset4 (s32x4, 1.0, s32); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_6.c new file mode 100644 index 0000000..cec4354 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/set_6.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +svfloat64_t +f1 (svbool_t pg, svint32_t s32, svint32x4_t s32x4, svfloat32x4_t f32x4, + svint32x2_t s32x2, int x) +{ + const int one = 1; + svfloat64_t f64; + + s32x4 = svset4_s32 (s32x4); /* { dg-error {too few arguments to function 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, 1); /* { dg-error {too few arguments to function 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, 1, s32, 3); /* { dg-error {too many arguments to function 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32, 0, s32); /* { dg-error {incompatible type for argument 1 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (f32x4, 0, s32); /* { dg-error {incompatible type for argument 1 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x2, 0, s32); /* { dg-error {incompatible type for argument 1 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (pg, 0, s32); /* { dg-error {incompatible type for argument 1 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, 0, s32x4); /* { dg-error {incompatible type for argument 3 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, 0, f64); /* { dg-error {incompatible type for argument 3 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, 0, pg); /* { dg-error {incompatible type for argument 3 of 'svset4_s32'} } */ + s32x4 = svset4_s32 (s32x4, x, s32); /* { dg-error {argument 2 of 'svset4_s32' must be an integer constant expression} } */ + s32x4 = svset4_s32 (s32x4, 0, s32); + f64 = svset4_s32 (s32x4, 0, s32); /* { dg-error {incompatible types when assigning to type 'svfloat64_t' from type 'svint32x4_t'} } */ + s32x4 = svset4_s32 (s32x4, 1, s32); + s32x4 = svset4_s32 (s32x4, 2, s32); + s32x4 = svset4_s32 (s32x4, 3, s32); + s32x4 = svset4_s32 (s32x4, 4, s32); /* { dg-error {passing 4 to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, 5, s32); /* { dg-error {passing 5 to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, ~0U, s32); /* { dg-error {passing [^ ]* to argument 2 of 'svset4_s32', which expects a value in the range \[0, 3\]} } */ + s32x4 = svset4_s32 (s32x4, one, s32); /* { dg-error {argument 2 of 'svset4_s32' must be an integer constant expression} } */ + s32x4 = svset4_s32 (s32x4, 3 - 2, s32); + s32x4 = svset4_s32 (s32x4, 1.0, s32); + + return f64; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_1.c new file mode 100644 index 0000000..4dd9a9c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64, int x) +{ + const int one = 1; + u8 = svasrd_x (pg, u8, 1); /* { dg-error {'svasrd_x' has no form that takes 'svuint8_t' arguments} } */ + s8 = svasrd_x (pg, s8, x); /* { dg-error {argument 3 of 'svasrd_x' must be an integer constant expression} } */ + s8 = svasrd_x (pg, s8, one); /* { dg-error {argument 3 of 'svasrd_x' must be an integer constant expression} } */ + s8 = svasrd_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1.0); + s8 = svasrd_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1); + s8 = svasrd_x (pg, s8, 1 + 1); + s8 = svasrd_x (pg, s8, 8); + s8 = svasrd_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, (1ULL << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_x (pg, s16, 1); + s16 = svasrd_x (pg, s16, 16); + s16 = svasrd_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_x (pg, s32, 1); + s32 = svasrd_x (pg, s32, 32); + s32 = svasrd_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_x (pg, s64, 1); + s64 = svasrd_x (pg, s64, 64); + s64 = svasrd_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_2.c new file mode 100644 index 0000000..4970689 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/shift_right_imm_2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svint16_t s16, svint32_t s32, svint64_t s64, + int x) +{ + const int one = 1; + s8 = svasrd_n_s8_x (pg, s8, x); /* { dg-error {argument 3 of 'svasrd_n_s8_x' must be an integer constant expression} } */ + s8 = svasrd_n_s8_x (pg, s8, one); /* { dg-error {argument 3 of 'svasrd_n_s8_x' must be an integer constant expression} } */ + s8 = svasrd_n_s8_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1.0); + s8 = svasrd_n_s8_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1); + s8 = svasrd_n_s8_x (pg, s8, 1 + 1); + s8 = svasrd_n_s8_x (pg, s8, 8); + s8 = svasrd_n_s8_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, (1ULL << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 1); + s16 = svasrd_n_s16_x (pg, s16, 16); + s16 = svasrd_n_s16_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 1); + s32 = svasrd_n_s32_x (pg, s32, 32); + s32 = svasrd_n_s32_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 1); + s64 = svasrd_n_s64_x (pg, s64, 64); + s64 = svasrd_n_s64_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_1.c new file mode 100644 index 0000000..267db83 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr, + float *f32_ptr, _Complex float *cf32_ptr, svint8_t s8, svfloat32_t f32, + struct s s) +{ + svst1 (pg, s8_ptr); /* { dg-error {too few arguments to function 'svst1'} } */ + svst1 (pg, s8_ptr, s8, 0); /* { dg-error {too many arguments to function 'svst1'} } */ + svst1 (0, s8_ptr, s8); /* { dg-error {passing 'int' to argument 1 of 'svst1', which expects 'svbool_t'} } */ + svst1 (pg, void_ptr, 0); /* { dg-error {passing 'int' to argument 3 of 'svst1', which expects an SVE vector type} } */ + svst1 (pg, void_ptr, pg); /* { dg-error {'svst1' has no form that takes 'svbool_t' arguments} } */ + svst1 (pg, 0, s8); + svst1 (pg, (int *) 0, s8); /* { dg-warning "passing argument 2 of 'svst1_s8' from incompatible pointer type" } */ + svst1 (pg, void_ptr, s8); + svst1 (pg, s_ptr, s8); /* { dg-warning "passing argument 2 of 'svst1_s8' from incompatible pointer type" } */ + svst1 (pg, f32_ptr, s8); /* { dg-warning "passing argument 2 of 'svst1_s8' from incompatible pointer type" } */ + svst1 (pg, f32_ptr, f32); + svst1 (pg, cf32_ptr, f32); /* { dg-warning "passing argument 2 of 'svst1_f32' from incompatible pointer type" } */ + svst1 (pg, s, s8); /* { dg-error {passing 'struct s' to argument 2 of 'svst1', which expects a scalar pointer} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_2.c new file mode 100644 index 0000000..4e4fb3c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint8_t +f1 (svbool_t pg, signed char *s8_ptr, void *void_ptr, struct s *s_ptr, + float *f32_ptr, _Complex float *cf32_ptr, svint8_t s8, svfloat32_t f32) +{ + svst1_vnum (pg, s8_ptr, 0); /* { dg-error {too few arguments to function 'svst1_vnum'} } */ + svst1_vnum (pg, s8_ptr, 0, s8, 0); /* { dg-error {too many arguments to function 'svst1_vnum'} } */ + svst1_vnum (0, s8_ptr, 0, s8); /* { dg-error {passing 'int' to argument 1 of 'svst1_vnum', which expects 'svbool_t'} } */ + svst1_vnum (pg, s8_ptr, pg, s8); /* { dg-error {passing 'svbool_t' to argument 3 of 'svst1_vnum', which expects 'int64_t'} } */ + svst1_vnum (pg, s8_ptr, s8, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svst1_vnum', which expects 'int64_t'} } */ + svst1_vnum (pg, s8_ptr, void_ptr, s8); /* { dg-warning "passing argument 3 of 'svst1_vnum_s8' makes integer from pointer without a cast" } */ + svst1_vnum (pg, void_ptr, 0, 0); /* { dg-error {passing 'int' to argument 4 of 'svst1_vnum', which expects an SVE vector type} } */ + svst1_vnum (pg, void_ptr, 0, pg); /* { dg-error {'svst1_vnum' has no form that takes 'svbool_t' arguments} } */ + svst1_vnum (pg, 0, 0, s8); + svst1_vnum (pg, (int *) 0, 0, s8); /* { dg-warning "passing argument 2 of 'svst1_vnum_s8' from incompatible pointer type" } */ + svst1_vnum (pg, void_ptr, 0, s8); + svst1_vnum (pg, s_ptr, 0, s8); /* { dg-warning "passing argument 2 of 'svst1_vnum_s8' from incompatible pointer type" } */ + svst1_vnum (pg, f32_ptr, 0, s8); /* { dg-warning "passing argument 2 of 'svst1_vnum_s8' from incompatible pointer type" } */ + svst1_vnum (pg, f32_ptr, 0, f32); + svst1_vnum (pg, cf32_ptr, 0, f32); /* { dg-warning "passing argument 2 of 'svst1_vnum_f32' from incompatible pointer type" } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_index_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_index_1.c new file mode 100644 index 0000000..3209149 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_index_1.c @@ -0,0 +1,101 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint32_t +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + int32_t *s32_ptr, uint32_t *u32_ptr, float *f32_ptr, + int64_t *s64_ptr, uint64_t *u64_ptr, double *f64_ptr, + void *void_ptr, struct s *s_ptr, _Complex float *cf32_ptr, + svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svst1_scatter_index (pg, s32_ptr, s32); /* { dg-error {too few arguments to function 'svst1_scatter_index'} } */ + svst1_scatter_index (pg, s32_ptr, s32, s32, 0); /* { dg-error {too many arguments to function 'svst1_scatter_index'} } */ + svst1_scatter_index (0, s32_ptr, s32, s32); /* { dg-error {passing 'int' to argument 1 of 'svst1_scatter_index', which expects 'svbool_t'} } */ + svst1_scatter_index (pg, 0, s32, s32); + svst1_scatter_index (pg, (int *) 0, s32, s32); + svst1_scatter_index (pg, void_ptr, s32, s32); + svst1_scatter_index (pg, s_ptr, s32, s32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32index_s32' from incompatible pointer type" } */ + svst1_scatter_index (pg, f32_ptr, s32, s32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32index_s32' from incompatible pointer type" } */ + svst1_scatter_index (pg, f32_ptr, s32, f32); + svst1_scatter_index (pg, cf32_ptr, s32, f32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32index_f32' from incompatible pointer type" } */ + svst1_scatter_index (pg, s, s32, s32); /* { dg-error {passing 'struct s' to argument 2 of 'svst1_scatter_index', which expects a vector or pointer base address} } */ + + svst1_scatter_index (pg, u32, void_ptr, s32); /* { dg-warning "passing argument 3 of 'svst1_scatter_u32base_index_s32' makes integer from pointer without a cast" } */ + svst1_scatter_index (pg, u32, pg, s32); /* { dg-error {passing 'svbool_t' to argument 3 of 'svst1_scatter_index', which expects 'int64_t'} } */ + svst1_scatter_index (pg, u32, s32, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_index', which expects 'int64_t'} } */ + + svst1_scatter_index (pg, void_ptr, u32, pg); /* { dg-error {passing 'svbool_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_index (pg, s8_ptr, u32, s8); /* { dg-error {passing 'svint8_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_index (pg, s8_ptr, u32, u8); /* { dg-error {passing 'svuint8_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_index (pg, s16_ptr, u32, s16); /* { dg-error {passing 'svint16_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_index (pg, s16_ptr, u32, u16); /* { dg-error {passing 'svuint16_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_index (pg, s16_ptr, u32, f16); /* { dg-error {passing 'svfloat16_t' to argument 4 of 'svst1_scatter_index', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_index (pg, u32, 0, s32); + svst1_scatter_index (pg, s32, 0, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint32_t'} } */ + + svst1_scatter_index (pg, u32, 0, u32); + svst1_scatter_index (pg, s32, 0, u32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint32_t'} } */ + + svst1_scatter_index (pg, u32, 0, f32); + svst1_scatter_index (pg, s32, 0, f32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint32_t'} } */ + + svst1_scatter_index (pg, u64, 0, s64); + svst1_scatter_index (pg, s64, 0, s64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint64_t'} } */ + + svst1_scatter_index (pg, u64, 0, u64); + svst1_scatter_index (pg, s64, 0, u64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint64_t'} } */ + + svst1_scatter_index (pg, u64, 0, f64); + svst1_scatter_index (pg, s64, 0, f64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_index', which expects 'svuint64_t'} } */ + + svst1_scatter_index (pg, s32_ptr, s32, s32); + svst1_scatter_index (pg, s32_ptr, u32, s32); + svst1_scatter_index (pg, s32_ptr, f32, s32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, s32_ptr, s64, s32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, s32_ptr, u64, s32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, s32_ptr, f64, s32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_index (pg, u32_ptr, s32, u32); + svst1_scatter_index (pg, u32_ptr, u32, u32); + svst1_scatter_index (pg, u32_ptr, f32, u32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, u32_ptr, s64, u32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, u32_ptr, u64, u32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, u32_ptr, f64, u32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_index (pg, f32_ptr, s32, f32); + svst1_scatter_index (pg, f32_ptr, u32, f32); + svst1_scatter_index (pg, f32_ptr, f32, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, f32_ptr, s64, f32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, f32_ptr, u64, f32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_index (pg, f32_ptr, f64, f32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_index (pg, s64_ptr, s32, s64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, s64_ptr, u32, s64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, s64_ptr, f32, s64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, s64_ptr, s64, s64); + svst1_scatter_index (pg, s64_ptr, u64, s64); + svst1_scatter_index (pg, s64_ptr, f64, s64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + + svst1_scatter_index (pg, u64_ptr, s32, u64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, u64_ptr, u32, u64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, u64_ptr, f32, u64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, u64_ptr, s64, u64); + svst1_scatter_index (pg, u64_ptr, u64, u64); + svst1_scatter_index (pg, u64_ptr, f64, u64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + + svst1_scatter_index (pg, f64_ptr, s32, f64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, f64_ptr, u32, f64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, f64_ptr, f32, f64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_index (pg, f64_ptr, s64, f64); + svst1_scatter_index (pg, f64_ptr, u64, f64); + svst1_scatter_index (pg, f64_ptr, f64, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_index', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_1.c new file mode 100644 index 0000000..10abf75 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_1.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint32_t +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, + svfloat16_t f16, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64) +{ + svst1_scatter (pg, u32); /* { dg-error {too few arguments to function 'svst1_scatter'} } */ + svst1_scatter (pg, u32, u32, 0); /* { dg-error {too many arguments to function 'svst1_scatter'} } */ + svst1_scatter (0, u32, u32); /* { dg-error {passing 'int' to argument 1 of 'svst1_scatter', which expects 'svbool_t'} } */ + svst1_scatter (pg, 0, u32); /* { dg-error {passing 'int' to argument 2 of 'svst1_scatter', which expects an SVE vector type} } */ + svst1_scatter (pg, u32, 0); /* { dg-error {passing 'int' to argument 3 of 'svst1_scatter', which expects an SVE vector type} } */ + + svst1_scatter (pg, u32, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter (pg, u32, s8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter (pg, u32, u8); /* { dg-error {passing 'svuint8_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter (pg, u32, s16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter (pg, u32, u16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter (pg, u32, f16); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svst1_scatter', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter (pg, u32, s32); + svst1_scatter (pg, s32, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter', which expects 'svuint32_t'} } */ + + svst1_scatter (pg, u32, u32); + svst1_scatter (pg, s32, u32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter', which expects 'svuint32_t'} } */ + + svst1_scatter (pg, u32, f32); + svst1_scatter (pg, s32, f32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter', which expects 'svuint32_t'} } */ + + svst1_scatter (pg, u64, s64); + svst1_scatter (pg, s64, s64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter', which expects 'svuint64_t'} } */ + + svst1_scatter (pg, u64, u64); + svst1_scatter (pg, s64, u64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter', which expects 'svuint64_t'} } */ + + svst1_scatter (pg, u64, f64); + svst1_scatter (pg, s64, f64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter', which expects 'svuint64_t'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_2.c new file mode 100644 index 0000000..8ee8129 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/store_scatter_offset_2.c @@ -0,0 +1,101 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +#include <arm_sve.h> + +struct s { signed char x; }; + +svuint32_t +f1 (svbool_t pg, signed char *s8_ptr, short *s16_ptr, + int32_t *s32_ptr, uint32_t *u32_ptr, float *f32_ptr, + int64_t *s64_ptr, uint64_t *u64_ptr, double *f64_ptr, + void *void_ptr, struct s *s_ptr, _Complex float *cf32_ptr, + svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, struct s s) +{ + svst1_scatter_offset (pg, s32_ptr, s32); /* { dg-error {too few arguments to function 'svst1_scatter_offset'} } */ + svst1_scatter_offset (pg, s32_ptr, s32, s32, 0); /* { dg-error {too many arguments to function 'svst1_scatter_offset'} } */ + svst1_scatter_offset (0, s32_ptr, s32, s32); /* { dg-error {passing 'int' to argument 1 of 'svst1_scatter_offset', which expects 'svbool_t'} } */ + svst1_scatter_offset (pg, 0, s32, s32); + svst1_scatter_offset (pg, (int *) 0, s32, s32); + svst1_scatter_offset (pg, void_ptr, s32, s32); + svst1_scatter_offset (pg, s_ptr, s32, s32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32offset_s32' from incompatible pointer type" } */ + svst1_scatter_offset (pg, f32_ptr, s32, s32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32offset_s32' from incompatible pointer type" } */ + svst1_scatter_offset (pg, f32_ptr, s32, f32); + svst1_scatter_offset (pg, cf32_ptr, s32, f32); /* { dg-warning "passing argument 2 of 'svst1_scatter_s32offset_f32' from incompatible pointer type" } */ + svst1_scatter_offset (pg, s, s32, s32); /* { dg-error {passing 'struct s' to argument 2 of 'svst1_scatter_offset', which expects a vector or pointer base address} } */ + + svst1_scatter_offset (pg, u32, void_ptr, s32); /* { dg-warning "passing argument 3 of 'svst1_scatter_u32base_offset_s32' makes integer from pointer without a cast" } */ + svst1_scatter_offset (pg, u32, pg, s32); /* { dg-error {passing 'svbool_t' to argument 3 of 'svst1_scatter_offset', which expects 'int64_t'} } */ + svst1_scatter_offset (pg, u32, s32, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_offset', which expects 'int64_t'} } */ + + svst1_scatter_offset (pg, void_ptr, u32, pg); /* { dg-error {passing 'svbool_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_offset (pg, s8_ptr, u32, s8); /* { dg-error {passing 'svint8_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_offset (pg, s8_ptr, u32, u8); /* { dg-error {passing 'svuint8_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_offset (pg, s16_ptr, u32, s16); /* { dg-error {passing 'svint16_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_offset (pg, s16_ptr, u32, u16); /* { dg-error {passing 'svuint16_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + svst1_scatter_offset (pg, s16_ptr, u32, f16); /* { dg-error {passing 'svfloat16_t' to argument 4 of 'svst1_scatter_offset', which expects a vector of 32-bit or 64-bit elements} } */ + + svst1_scatter_offset (pg, u32, 0, s32); + svst1_scatter_offset (pg, s32, 0, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint32_t'} } */ + + svst1_scatter_offset (pg, u32, 0, u32); + svst1_scatter_offset (pg, s32, 0, u32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint32_t'} } */ + + svst1_scatter_offset (pg, u32, 0, f32); + svst1_scatter_offset (pg, s32, 0, f32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint32_t'} } */ + + svst1_scatter_offset (pg, u64, 0, s64); + svst1_scatter_offset (pg, s64, 0, s64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint64_t'} } */ + + svst1_scatter_offset (pg, u64, 0, u64); + svst1_scatter_offset (pg, s64, 0, u64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint64_t'} } */ + + svst1_scatter_offset (pg, u64, 0, f64); + svst1_scatter_offset (pg, s64, 0, f64); /* { dg-error {passing 'svint64_t' to argument 2 of 'svst1_scatter_offset', which expects 'svuint64_t'} } */ + + svst1_scatter_offset (pg, s32_ptr, s32, s32); + svst1_scatter_offset (pg, s32_ptr, u32, s32); + svst1_scatter_offset (pg, s32_ptr, f32, s32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, s32_ptr, s64, s32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, s32_ptr, u64, s32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, s32_ptr, f64, s32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_offset (pg, u32_ptr, s32, u32); + svst1_scatter_offset (pg, u32_ptr, u32, u32); + svst1_scatter_offset (pg, u32_ptr, f32, u32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, u32_ptr, s64, u32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, u32_ptr, u64, u32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, u32_ptr, f64, u32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_offset (pg, f32_ptr, s32, f32); + svst1_scatter_offset (pg, f32_ptr, u32, f32); + svst1_scatter_offset (pg, f32_ptr, f32, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, f32_ptr, s64, f32); /* { dg-error {passing 'svint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, f32_ptr, u64, f32); /* { dg-error {passing 'svuint64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + svst1_scatter_offset (pg, f32_ptr, f64, f32); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat32_t' expects a vector of 32-bit integers} } */ + + svst1_scatter_offset (pg, s64_ptr, s32, s64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, s64_ptr, u32, s64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, s64_ptr, f32, s64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, s64_ptr, s64, s64); + svst1_scatter_offset (pg, s64_ptr, u64, s64); + svst1_scatter_offset (pg, s64_ptr, f64, s64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svint64_t' expects a vector of 64-bit integers} } */ + + svst1_scatter_offset (pg, u64_ptr, s32, u64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, u64_ptr, u32, u64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, u64_ptr, f32, u64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, u64_ptr, s64, u64); + svst1_scatter_offset (pg, u64_ptr, u64, u64); + svst1_scatter_offset (pg, u64_ptr, f64, u64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svuint64_t' expects a vector of 64-bit integers} } */ + + svst1_scatter_offset (pg, f64_ptr, s32, f64); /* { dg-error {passing 'svint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, f64_ptr, u32, f64); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, f64_ptr, f32, f64); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ + svst1_scatter_offset (pg, f64_ptr, s64, f64); + svst1_scatter_offset (pg, f64_ptr, u64, f64); + svst1_scatter_offset (pg, f64_ptr, f64, f64); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svst1_scatter_offset', which when storing 'svfloat64_t' expects a vector of 64-bit integers} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_1.c new file mode 100644 index 0000000..bbd1f91 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_1.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat16_t f16, svfloat32_t f32, svfloat64_t f64, + svint32_t s32, int i) +{ + svmla_lane (f32, f32, f32); /* { dg-error {too few arguments to function 'svmla_lane'} } */ + svmla_lane (f32, f32, f32, 0, 0); /* { dg-error {too many arguments to function 'svmla_lane'} } */ + svmla_lane (pg, pg, pg, 0); /* { dg-error {'svmla_lane' has no form that takes 'svbool_t' arguments} } */ + svmla_lane (s32, s32, s32, 0); /* { dg-error {'svmla_lane' has no form that takes 'svint32_t' arguments} } */ + svmla_lane (1, f32, f32, 0); /* { dg-error {passing 'int' to argument 1 of 'svmla_lane', which expects an SVE vector type} } */ + svmla_lane (f32, 1, f32, 0); /* { dg-error {passing 'int' to argument 2 of 'svmla_lane', which expects an SVE vector type} } */ + svmla_lane (f32, f32, 1, 0); /* { dg-error {passing 'int' to argument 3 of 'svmla_lane', which expects an SVE vector type} } */ + svmla_lane (f32, f64, f32, 0); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svmla_lane', but previous arguments had type 'svfloat32_t'} } */ + svmla_lane (f32, f32, f64, 0); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svmla_lane', but previous arguments had type 'svfloat32_t'} } */ + svmla_lane (f32, f32, f32, s32); /* { dg-error {argument 4 of 'svmla_lane' must be an integer constant expression} } */ + svmla_lane (f32, f32, f32, i); /* { dg-error {argument 4 of 'svmla_lane' must be an integer constant expression} } */ + + svmla_lane (f16, f16, f16, 0); + svmla_lane (f16, f16, f16, 7); + svmla_lane (f16, f16, f16, 8); /* { dg-error {passing 8 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 7\]} } */ + svmla_lane (f16, f16, f16, -1); /* { dg-error {passing -1 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 7\]} } */ + + svmla_lane (f32, f32, f32, 0); + svmla_lane (f32, f32, f32, 3); + svmla_lane (f32, f32, f32, 4); /* { dg-error {passing 4 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 3\]} } */ + svmla_lane (f32, f32, f32, -1); /* { dg-error {passing -1 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 3\]} } */ + + svmla_lane (f64, f64, f64, 0); + svmla_lane (f64, f64, f64, 1); + svmla_lane (f64, f64, f64, 2); /* { dg-error {passing 2 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 1\]} } */ + svmla_lane (f64, f64, f64, -1); /* { dg-error {passing -1 to argument 4 of 'svmla_lane', which expects a value in the range \[0, 1\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_rotate_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_rotate_1.c new file mode 100644 index 0000000..bccc6c7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_lane_rotate_1.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat16_t f16, svfloat32_t f32, svfloat64_t f64, + svint32_t s32, int i) +{ + svcmla_lane (f32, f32, f32, 0); /* { dg-error {too few arguments to function 'svcmla_lane'} } */ + svcmla_lane (f32, f32, f32, 0, 90, 90); /* { dg-error {too many arguments to function 'svcmla_lane'} } */ + svcmla_lane (pg, pg, pg, 0, 90); /* { dg-error {'svcmla_lane' has no form that takes 'svbool_t' arguments} } */ + svcmla_lane (s32, s32, s32, 0, 90); /* { dg-error {'svcmla_lane' has no form that takes 'svint32_t' arguments} } */ + svcmla_lane (f64, f64, f64, 0, 90); /* { dg-error {'svcmla_lane' has no form that takes 'svfloat64_t' arguments} } */ + svcmla_lane (1, f32, f32, 0, 90); /* { dg-error {passing 'int' to argument 1 of 'svcmla_lane', which expects an SVE vector type} } */ + svcmla_lane (f32, 1, f32, 0, 90); /* { dg-error {passing 'int' to argument 2 of 'svcmla_lane', which expects an SVE vector type} } */ + svcmla_lane (f32, f32, 1, 0, 90); /* { dg-error {passing 'int' to argument 3 of 'svcmla_lane', which expects an SVE vector type} } */ + svcmla_lane (f32, f64, f32, 0, 90); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svcmla_lane', but previous arguments had type 'svfloat32_t'} } */ + svcmla_lane (f32, f32, f64, 0, 90); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svcmla_lane', but previous arguments had type 'svfloat32_t'} } */ + svcmla_lane (f32, f32, f32, s32, 0); /* { dg-error {argument 4 of 'svcmla_lane' must be an integer constant expression} } */ + svcmla_lane (f32, f32, f32, i, 0); /* { dg-error {argument 4 of 'svcmla_lane' must be an integer constant expression} } */ + + svcmla_lane (f16, f16, f16, 0, 0); + svcmla_lane (f16, f16, f16, 3, 0); + svcmla_lane (f16, f16, f16, 4, 0); /* { dg-error {passing 4 to argument 4 of 'svcmla_lane', which expects a value in the range \[0, 3\]} } */ + svcmla_lane (f16, f16, f16, -1, 0); /* { dg-error {passing -1 to argument 4 of 'svcmla_lane', which expects a value in the range \[0, 3\]} } */ + + svcmla_lane (f32, f32, f32, 0, 0); + svcmla_lane (f32, f32, f32, 1, 0); + svcmla_lane (f32, f32, f32, 2, 0); /* { dg-error {passing 2 to argument 4 of 'svcmla_lane', which expects a value in the range \[0, 1\]} } */ + svcmla_lane (f32, f32, f32, -1, 0); /* { dg-error {passing -1 to argument 4 of 'svcmla_lane', which expects a value in the range \[0, 1\]} } */ + + svcmla_lane (f32, f32, f32, 0, -90); /* { dg-error {passing -90 to argument 5 of 'svcmla_lane', which expects 0, 90, 180 or 270} } */ + svcmla_lane (f32, f32, f32, 0, 0); + svcmla_lane (f32, f32, f32, 0, 1); /* { dg-error {passing 1 to argument 5 of 'svcmla_lane', which expects 0, 90, 180 or 270} } */ + svcmla_lane (f32, f32, f32, 0, 90); + svcmla_lane (f32, f32, f32, 0, 180); + svcmla_lane (f32, f32, f32, 0, 270); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_opt_n_1.c new file mode 100644 index 0000000..c4a80e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_opt_n_1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16) +{ + svmla_x (pg, u8, u8); /* { dg-error {too few arguments to function 'svmla_x'} } */ + svmla_x (pg, u8, u8, u8, u8); /* { dg-error {too many arguments to function 'svmla_x'} } */ + svmla_x (u8, u8, u8, u8); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svmla_x', which expects 'svbool_t'} } */ + svmla_x (pg, pg, pg, pg); /* { dg-error {'svmla_x' has no form that takes 'svbool_t' arguments} } */ + svmla_x (pg, 1, u8, u8); /* { dg-error {passing 'int' to argument 2 of 'svmla_x', which expects an SVE vector type} } */ + svmla_x (pg, u8, s8, u8); /* { dg-error {passing 'svint8_t' to argument 3 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, u8); + svmla_x (pg, u8, s16, u8); /* { dg-error {passing 'svint16_t' to argument 3 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u16, u8); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, f16, u8); /* { dg-error {passing 'svfloat16_t' to argument 3 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, pg, u8); /* { dg-error {passing 'svbool_t' to argument 3 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, 0, u8); /* { dg-error {passing 'int' to argument 3 of 'svmla_x', which expects an SVE vector type} } */ + svmla_x (pg, u8, u8, s8); /* { dg-error {passing 'svint8_t' to argument 4 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, s16); /* { dg-error {passing 'svint16_t' to argument 4 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, u16); /* { dg-error {passing 'svuint16_t' to argument 4 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, f16); /* { dg-error {passing 'svfloat16_t' to argument 4 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, pg); /* { dg-error {passing 'svbool_t' to argument 4 of 'svmla_x', but previous arguments had type 'svuint8_t'} } */ + svmla_x (pg, u8, u8, 0); + + svmla_x (pg, f16, s16, f16); /* { dg-error {passing 'svint16_t' to argument 3 of 'svmla_x', but previous arguments had type 'svfloat16_t'} } */ + svmla_x (pg, f16, u16, f16); /* { dg-error {passing 'svuint16_t' to argument 3 of 'svmla_x', but previous arguments had type 'svfloat16_t'} } */ + svmla_x (pg, f16, f16, s16); /* { dg-error {passing 'svint16_t' to argument 4 of 'svmla_x', but previous arguments had type 'svfloat16_t'} } */ + svmla_x (pg, f16, f16, u16); /* { dg-error {passing 'svuint16_t' to argument 4 of 'svmla_x', but previous arguments had type 'svfloat16_t'} } */ + svmla_x (pg, f16, f16, f16); + svmla_x (pg, f16, f16, 1); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_lane_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_lane_1.c new file mode 100644 index 0000000..e81552b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_lane_1.c @@ -0,0 +1,63 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, svint16_t s16, svuint16_t u16, + svint32_t s32, svuint32_t u32, svint64_t s64, svuint64_t u64, + svfloat32_t f32, int i) +{ + svdot_lane (u32, u8, u8); /* { dg-error {too few arguments to function 'svdot_lane'} } */ + svdot_lane (u32, u8, u8, 0, 0); /* { dg-error {too many arguments to function 'svdot_lane'} } */ + svdot_lane (0, u8, u8, 0); /* { dg-error {passing 'int' to argument 1 of 'svdot_lane', which expects an SVE vector type} } */ + svdot_lane (pg, u8, u8, 0); /* { dg-error {'svdot_lane' has no form that takes 'svbool_t' arguments} } */ + svdot_lane (u8, u8, u8, 0); /* { dg-error {'svdot_lane' has no form that takes 'svuint8_t' arguments} } */ + svdot_lane (f32, u8, u8, 0); /* { dg-error {'svdot_lane' has no form that takes 'svfloat32_t' arguments} } */ + svdot_lane (u32, u8, u8, 0); + svdot_lane (u32, 0, u8, 0); /* { dg-error {passing 'int' to argument 2 of 'svdot_lane', which expects an SVE vector type} } */ + svdot_lane (u32, u8, 0, 0); /* { dg-error {passing 'int' to argument 3 of 'svdot_lane', which expects an SVE vector type} } */ + + svdot_lane (s32, s8, s8, 0); + svdot_lane (s32, u8, s8, 0); /* { dg-error {arguments 1 and 2 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svint32_t' and 'svuint8_t' respectively} } */ + svdot_lane (s32, s8, u8, 0); /* { dg-error {arguments 1 and 3 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svint32_t' and 'svuint8_t' respectively} } */ + svdot_lane (s32, s32, s32, 0); /* { dg-error {passing 'svint32_t' instead of the expected 'svint8_t' to argument 2 of 'svdot_lane', after passing 'svint32_t' to argument 1} } */ + + svdot_lane (u32, u8, u8, 0); + svdot_lane (u32, s8, u8, 0); /* { dg-error {arguments 1 and 2 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svuint32_t' and 'svint8_t' respectively} } */ + svdot_lane (u32, u8, s8, 0); /* { dg-error {arguments 1 and 3 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svuint32_t' and 'svint8_t' respectively} } */ + svdot_lane (u32, u32, u32, 0); /* { dg-error {passing 'svuint32_t' instead of the expected 'svuint8_t' to argument 2 of 'svdot_lane', after passing 'svuint32_t' to argument 1} } */ + + svdot_lane (s64, s16, s16, 0); + svdot_lane (s64, u16, s16, 0); /* { dg-error {arguments 1 and 2 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svint64_t' and 'svuint16_t' respectively} } */ + svdot_lane (s64, s16, u16, 0); /* { dg-error {arguments 1 and 3 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svint64_t' and 'svuint16_t' respectively} } */ + svdot_lane (s64, s64, s64, 0); /* { dg-error {passing 'svint64_t' instead of the expected 'svint16_t' to argument 2 of 'svdot_lane', after passing 'svint64_t' to argument 1} } */ + + svdot_lane (u64, u16, u16, 0); + svdot_lane (u64, s16, u16, 0); /* { dg-error {arguments 1 and 2 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svuint64_t' and 'svint16_t' respectively} } */ + svdot_lane (u64, u16, s16, 0); /* { dg-error {arguments 1 and 3 of 'svdot_lane' must have the same signedness, but the values passed here have type 'svuint64_t' and 'svint16_t' respectively} } */ + svdot_lane (u64, u64, u64, 0); /* { dg-error {passing 'svuint64_t' instead of the expected 'svuint16_t' to argument 2 of 'svdot_lane', after passing 'svuint64_t' to argument 1} } */ + + svdot_lane (s32, s8, s8, i); /* { dg-error {argument 4 of 'svdot_lane' must be an integer constant expression} } */ + svdot_lane (s32, s8, s8, 0); + svdot_lane (s32, s8, s8, 3); + svdot_lane (s32, s8, s8, 4); /* { dg-error {passing 4 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 3\]} } */ + svdot_lane (s32, s8, s8, -1); /* { dg-error {passing -1 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 3\]} } */ + + svdot_lane (u32, u8, u8, i); /* { dg-error {argument 4 of 'svdot_lane' must be an integer constant expression} } */ + svdot_lane (u32, u8, u8, 0); + svdot_lane (u32, u8, u8, 3); + svdot_lane (u32, u8, u8, 4); /* { dg-error {passing 4 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 3\]} } */ + svdot_lane (u32, u8, u8, -1); /* { dg-error {passing -1 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 3\]} } */ + + svdot_lane (s64, s16, s16, i); /* { dg-error {argument 4 of 'svdot_lane' must be an integer constant expression} } */ + svdot_lane (s64, s16, s16, 0); + svdot_lane (s64, s16, s16, 1); + svdot_lane (s64, s16, s16, 2); /* { dg-error {passing 2 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 1\]} } */ + svdot_lane (s64, s16, s16, -1); /* { dg-error {passing -1 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 1\]} } */ + + svdot_lane (u64, u16, u16, i); /* { dg-error {argument 4 of 'svdot_lane' must be an integer constant expression} } */ + svdot_lane (u64, u16, u16, 0); + svdot_lane (u64, u16, u16, 1); + svdot_lane (u64, u16, u16, 2); /* { dg-error {passing 2 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 1\]} } */ + svdot_lane (u64, u16, u16, -1); /* { dg-error {passing -1 to argument 4 of 'svdot_lane', which expects a value in the range \[0, 1\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_1.c new file mode 100644 index 0000000..b41e6fc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +svint32_t +f1 (svuint32_t u32, svuint8_t u8, svint8_t s8) +{ + svdot_u32 (u32); /* { dg-error {too few arguments to function 'svdot_u32'} } */ + svdot_u32 (u32, u8, u8, u32); /* { dg-error {too many arguments to function 'svdot_u32'} } */ + svdot_u32 (u32, u32, u8); /* { dg-error {incompatible type for argument 2 of 'svdot_u32'} } */ + svdot_u32 (u32, s8, u8); /* { dg-error {incompatible type for argument 2 of 'svdot_u32'} } */ + svdot_u32 (u32, u8, u32); /* { dg-error {incompatible type for argument 3 of 'svdot_u32'} } */ + svdot_u32 (u32, u8, s8); /* { dg-error {incompatible type for argument 3 of 'svdot_u32'} } */ + return svdot_u32 (u32, u8, u8); /* { dg-error {incompatible types when returning type 'svuint32_t' but 'svint32_t' was expected} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_2.c new file mode 100644 index 0000000..fee4096 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_qq_opt_n_2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, svuint32_t u32, + svfloat32_t f32) +{ + svdot (u32, u8); /* { dg-error {too few arguments to function 'svdot'} } */ + svdot (u32, u8, u8, u8); /* { dg-error {too many arguments to function 'svdot'} } */ + svdot (0, u8, u8); /* { dg-error {passing 'int' to argument 1 of 'svdot', which expects an SVE vector type} } */ + svdot (pg, u8, u8); /* { dg-error {'svdot' has no form that takes 'svbool_t' arguments} } */ + svdot (u8, u8, u8); /* { dg-error {'svdot' has no form that takes 'svuint8_t' arguments} } */ + svdot (f32, u8, u8); /* { dg-error {'svdot' has no form that takes 'svfloat32_t' arguments} } */ + svdot (u32, u8, u8); + svdot (u32, 0, u8); /* { dg-error {passing 'int' to argument 2 of 'svdot', which expects an SVE vector type} } */ + svdot (u32, s8, u8); /* { dg-error {arguments 1 and 2 of 'svdot' must have the same signedness, but the values passed here have type 'svuint32_t' and 'svint8_t' respectively} } */ + svdot (u32, u8, 0); + svdot (u32, u8, s8); /* { dg-error {arguments 1 and 3 of 'svdot' must have the same signedness, but the values passed here have type 'svuint32_t' and 'svint8_t' respectively} } */ + svdot (u32, u32, u32); /* { dg-error {passing 'svuint32_t' instead of the expected 'svuint8_t' to argument 2 of 'svdot', after passing 'svuint32_t' to argument 1} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_rotate_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_rotate_1.c new file mode 100644 index 0000000..f340e3d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/ternary_rotate_1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat32_t f32, svfloat64_t f64, svint32_t s32, int i) +{ + svcmla_x (pg, f32, f32, f32); /* { dg-error {too few arguments to function 'svcmla_x'} } */ + svcmla_x (pg, f32, f32, f32, 90, 90); /* { dg-error {too many arguments to function 'svcmla_x'} } */ + svcmla_x (f32, f32, f32, f32, 90); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svcmla_x', which expects 'svbool_t'} } */ + svcmla_x (pg, pg, pg, pg, 90); /* { dg-error {'svcmla_x' has no form that takes 'svbool_t' arguments} } */ + svcmla_x (pg, s32, s32, s32, 90); /* { dg-error {'svcmla_x' has no form that takes 'svint32_t' arguments} } */ + svcmla_x (pg, 1, f32, f32, 90); /* { dg-error {passing 'int' to argument 2 of 'svcmla_x', which expects an SVE vector type} } */ + svcmla_x (pg, f32, 1, f32, 90); /* { dg-error {passing 'int' to argument 3 of 'svcmla_x', which expects an SVE vector type} } */ + svcmla_x (pg, f32, f32, 1, 90); /* { dg-error {passing 'int' to argument 4 of 'svcmla_x', which expects an SVE vector type} } */ + svcmla_x (pg, f32, f64, f32, 90); /* { dg-error {passing 'svfloat64_t' to argument 3 of 'svcmla_x', but previous arguments had type 'svfloat32_t'} } */ + svcmla_x (pg, f32, f32, f64, 90); /* { dg-error {passing 'svfloat64_t' to argument 4 of 'svcmla_x', but previous arguments had type 'svfloat32_t'} } */ + svcmla_x (pg, f32, f32, f32, s32); /* { dg-error {argument 5 of 'svcmla_x' must be an integer constant expression} } */ + svcmla_x (pg, f32, f32, f32, i); /* { dg-error {argument 5 of 'svcmla_x' must be an integer constant expression} } */ + svcmla_x (pg, f32, f32, f32, -90); /* { dg-error {passing -90 to argument 5 of 'svcmla_x', which expects 0, 90, 180 or 270} } */ + svcmla_x (pg, f32, f32, f32, 0); + svcmla_x (pg, f32, f32, f32, 1); /* { dg-error {passing 1 to argument 5 of 'svcmla_x', which expects 0, 90, 180 or 270} } */ + svcmla_x (pg, f32, f32, f32, 90); + svcmla_x (pg, f32, f32, f32, 180); + svcmla_x (pg, f32, f32, f32, 270); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/tmad_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/tmad_1.c new file mode 100644 index 0000000..8b98fc2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/tmad_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svfloat32_t f32, svfloat64_t f64, svint32_t s32, int i) +{ + svtmad (f32, f32); /* { dg-error {too few arguments to function 'svtmad'} } */ + svtmad (f32, f32, 0, 0); /* { dg-error {too many arguments to function 'svtmad'} } */ + svtmad (pg, pg, 0); /* { dg-error {'svtmad' has no form that takes 'svbool_t' arguments} } */ + svtmad (s32, s32, 0); /* { dg-error {'svtmad' has no form that takes 'svint32_t' arguments} } */ + svtmad (1, f32, 0); /* { dg-error {passing 'int' to argument 1 of 'svtmad', which expects an SVE vector type} } */ + svtmad (f32, 1, 0); /* { dg-error {passing 'int' to argument 2 of 'svtmad', which expects an SVE vector type} } */ + svtmad (f32, f64, 0); /* { dg-error {passing 'svfloat64_t' to argument 2 of 'svtmad', but previous arguments had type 'svfloat32_t'} } */ + svtmad (f32, f32, s32); /* { dg-error {argument 3 of 'svtmad' must be an integer constant expression} } */ + svtmad (f32, f32, i); /* { dg-error {argument 3 of 'svtmad' must be an integer constant expression} } */ + svtmad (f32, f32, -1); /* { dg-error {passing -1 to argument 3 of 'svtmad', which expects a value in the range \[0, 7\]} } */ + svtmad (f32, f32, 0); + svtmad (f32, f32, 1); + svtmad (f32, f32, 7); + svtmad (f32, f32, 8); /* { dg-error {passing 8 to argument 3 of 'svtmad', which expects a value in the range \[0, 7\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_1.c new file mode 100644 index 0000000..70b2d9d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_1.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svbool_t; /* { dg-message "note: previous declaration of 'svbool_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svbool_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_10.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_10.c new file mode 100644 index 0000000..8278c1c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_10.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef struct svint8x2_t svint8x2_t; /* { dg-message "note: previous declaration of 'svint8x2_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting types for 'svint8x2_t'} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_11.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_11.c new file mode 100644 index 0000000..2147df7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +/* This isn't explicitly allowed or disallowed, but mustn't ICE. */ +struct svint8x2_t; + +#pragma GCC aarch64 "arm_sve.h" + +void +f (svint8x2_t *a, struct svint8x2_t *b) +{ + *a = *b; /* { dg-error {dereferencing pointer to incomplete type} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_12.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_12.c new file mode 100644 index 0000000..1a6ccbd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_12.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +/* This isn't explicitly allowed or disallowed, but mustn't ICE. */ +struct svint8x2_t { int x; }; + +#pragma GCC aarch64 "arm_sve.h" + +void +f (svint8x2_t *a, struct svint8x2_t *b) +{ + *a = *b; /* { dg-error {incompatible types} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_13.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_13.c new file mode 100644 index 0000000..62bab1f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_13.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "note: previous declaration of 'svint8x2_t' was here" } */ + +int svint8x2_t; /* { dg-error {'svint8x2_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_14.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_14.c new file mode 100644 index 0000000..0f00db1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_14.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +enum svpattern { FOO }; /* { dg-message "note: originally defined here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {redeclaration of 'enum svpattern'} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_15.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_15.c new file mode 100644 index 0000000..ea97217 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_15.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "note: originally defined here" } */ + +enum svpattern { FOO }; /* { dg-error {redeclaration of 'enum svpattern'} } */ +enum foo { SV_ALL }; /* { dg-error {redeclaration of enumerator 'SV_ALL'} } */ +typedef int SV_POW2; /* { dg-error {'SV_POW2' redeclared as different kind of symbol} } */ +int SV_VL3; /* { dg-error {'SV_VL3' redeclared as different kind of symbol} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_16.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_16.c new file mode 100644 index 0000000..a59dabc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_16.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +struct svpattern { int x; }; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svpattern' defined as wrong kind of tag} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_17.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_17.c new file mode 100644 index 0000000..027fdb2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_17.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +struct svpattern { int x; }; /* { dg-error {'svpattern' defined as wrong kind of tag} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_18.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_18.c new file mode 100644 index 0000000..b670615 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_18.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svpattern; /* OK in C. */ + +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_19.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_19.c new file mode 100644 index 0000000..c6379f7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_19.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +int svpattern; /* OK in C. */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_2.c new file mode 100644 index 0000000..ffd86ae --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_2.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svint8_t; /* { dg-message "note: previous declaration of 'svint8_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svint8_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_20.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_20.c new file mode 100644 index 0000000..3d770a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_20.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +enum foo { SV_VL4 }; +typedef int SV_POW2; +int SV_ALL; + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {redeclaration of enumerator 'SV_VL4'} } */ +/* { dg-error {'SV_POW2' redeclared as different kind of symbol} "" { target *-*-* } .-1 } */ +/* { dg-error {'SV_ALL' redeclared as different kind of symbol} "" { target *-*-* } .-2 } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_3.c new file mode 100644 index 0000000..f42dd96 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_3.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svuint16_t; /* { dg-message "note: previous declaration of 'svuint16_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svuint16_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_4.c new file mode 100644 index 0000000..91c95a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_4.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svfloat32_t; /* { dg-message "note: previous declaration of 'svfloat32_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svfloat32_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_5.c new file mode 100644 index 0000000..3cb6b8a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_5.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svbool_t; /* { dg-message "note: previous declaration of 'svbool_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting types for 'svbool_t'} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_6.c new file mode 100644 index 0000000..c051897 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_6.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ + +typedef __SVBool_t svbool_t; /* { dg-message "note: previous declaration of 'svbool_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {redefinition of typedef 'svbool_t'} } */ + diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_7.c new file mode 100644 index 0000000..fd40631 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_7.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu90" } */ + +typedef __SVBool_t svbool_t; + +/* Without -pedantic-errors this should compile. */ +#pragma GCC aarch64 "arm_sve.h" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_8.c new file mode 100644 index 0000000..41614a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_8.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +int svint8x2_t; /* { dg-message "note: previous declaration of 'svint8x2_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {'svint8x2_t' redeclared} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_9.c new file mode 100644 index 0000000..83b6855 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/type_redef_9.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ + +typedef int svint8x2_t; /* { dg-message "note: previous declaration of 'svint8x2_t' was here" } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-error {conflicting types for 'svint8x2_t'} } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_1.c new file mode 100644 index 0000000..eef85a0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint32_t s32, svuint32_t u32, svfloat32_t f32) +{ + svabs_m (s32, pg); /* { dg-error {too few arguments to function 'svabs_m'} } */ + svabs_m (s32, pg, s32, s32); /* { dg-error {too many arguments to function 'svabs_m'} } */ + svabs_m (0, pg, s32); /* { dg-error {passing 'int' to argument 1 of 'svabs_m', which expects an SVE vector type} } */ + svabs_m (s32, s32, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svabs_m', which expects 'svbool_t'} } */ + svabs_m (s32, 0, s32); /* { dg-error {passing 'int' to argument 2 of 'svabs_m', which expects 'svbool_t'} } */ + svabs_m (s32, pg, s32); + svabs_m (u32, pg, u32); /* { dg-error {'svabs_m' has no form that takes 'svuint32_t' arguments} } */ + svabs_m (f32, pg, f32); + svabs_m (s32, pg, u32); /* { dg-error {passing 'svuint32_t' to argument 3 of 'svabs_m', but previous arguments had type 'svint32_t'} } */ + svabs_m (s32, pg, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svabs_m', but previous arguments had type 'svint32_t'} } */ + svabs_m (s32, pg, pg); /* { dg-error {passing 'svbool_t' to argument 3 of 'svabs_m', but previous arguments had type 'svint32_t'} } */ + svabs_m (pg, pg, s32); /* { dg-error {passing 'svint32_t' to argument 3 of 'svabs_m', but previous arguments had type 'svbool_t'} } */ + svabs_m (pg, pg, pg); /* { dg-error {'svabs_m' has no form that takes 'svbool_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_2.c new file mode 100644 index 0000000..e94673a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8) +{ + svabs_x (pg); /* { dg-error {too few arguments to function 'svabs_x'} } */ + svabs_x (pg, s8, s8); /* { dg-error {too many arguments to function 'svabs_x'} } */ + svabs_x (s8, s8); /* { dg-error {passing 'svint8_t' to argument 1 of 'svabs_x', which expects 'svbool_t'} } */ + svabs_x (pg, pg); /* { dg-error {'svabs_x' has no form that takes 'svbool_t' arguments} } */ + svabs_x (pg, 1); /* { dg-error {passing 'int' to argument 2 of 'svabs_x', which expects an SVE vector type} } */ + svabs_x (pg, s8); + svabs_x (pg, u8); /* { dg-error {'svabs_x' has no form that takes 'svuint8_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c new file mode 100644 index 0000000..caa4e62 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_1.c @@ -0,0 +1,73 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, svfloat16_t f16, svfloat32_t f32, + svfloat64_t f64) +{ + svcvt_f64_x (pg); /* { dg-error {too few arguments to function 'svcvt_f64_x'} } */ + svcvt_f64_x (pg, s32, 0); /* { dg-error {too many arguments to function 'svcvt_f64_x'} } */ + svcvt_f64_x (s32, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svcvt_f64_x', which expects 'svbool_t'} } */ + svcvt_f64_x (pg, 0); /* { dg-error {passing 'int' to argument 2 of 'svcvt_f64_x', which expects an SVE vector type} } */ + + svcvt_f64_x (pg, s8); /* { dg-error {'svcvt_f64_x' has no form that takes 'svint8_t' arguments} } */ + svcvt_f64_x (pg, s16); /* { dg-error {'svcvt_f64_x' has no form that takes 'svint16_t' arguments} } */ + svcvt_f64_x (pg, s32); + svcvt_f64_x (pg, s64); + svcvt_f64_x (pg, u8); /* { dg-error {'svcvt_f64_x' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f64_x (pg, u16); /* { dg-error {'svcvt_f64_x' has no form that takes 'svuint16_t' arguments} } */ + svcvt_f64_x (pg, u32); + svcvt_f64_x (pg, u64); + svcvt_f64_x (pg, f16); + svcvt_f64_x (pg, f32); + svcvt_f64_x (pg, f64); /* { dg-error {'svcvt_f64_x' has no form that takes 'svfloat64_t' arguments} } */ + + svcvt_f32_x (pg, s8); /* { dg-error {'svcvt_f32_x' has no form that takes 'svint8_t' arguments} } */ + svcvt_f32_x (pg, s16); /* { dg-error {'svcvt_f32_x' has no form that takes 'svint16_t' arguments} } */ + svcvt_f32_x (pg, s32); + svcvt_f32_x (pg, s64); + svcvt_f32_x (pg, u8); /* { dg-error {'svcvt_f32_x' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f32_x (pg, u16); /* { dg-error {'svcvt_f32_x' has no form that takes 'svuint16_t' arguments} } */ + svcvt_f32_x (pg, u32); + svcvt_f32_x (pg, u64); + svcvt_f32_x (pg, f16); + svcvt_f32_x (pg, f32); /* { dg-error {'svcvt_f32_x' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_f32_x (pg, f64); + + svcvt_f16_x (pg, s8); /* { dg-error {'svcvt_f16_x' has no form that takes 'svint8_t' arguments} } */ + svcvt_f16_x (pg, s16); + svcvt_f16_x (pg, s32); + svcvt_f16_x (pg, s64); + svcvt_f16_x (pg, u8); /* { dg-error {'svcvt_f16_x' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f16_x (pg, u16); + svcvt_f16_x (pg, u32); + svcvt_f16_x (pg, u64); + svcvt_f16_x (pg, f16); /* { dg-error {'svcvt_f16_x' has no form that takes 'svfloat16_t' arguments} } */ + svcvt_f16_x (pg, f32); + svcvt_f16_x (pg, f64); + + svcvt_s64_x (pg, f16); + svcvt_s64_x (pg, f32); + svcvt_s64_x (pg, f64); + + svcvt_s32_x (pg, f16); + svcvt_s32_x (pg, f32); + svcvt_s32_x (pg, f64); + + svcvt_s16_x (pg, f16); + svcvt_s16_x (pg, f32); /* { dg-error {'svcvt_s16_x' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_s16_x (pg, f64); /* { dg-error {'svcvt_s16_x' has no form that takes 'svfloat64_t' arguments} } */ + + svcvt_u64_x (pg, f16); + svcvt_u64_x (pg, f32); + svcvt_u64_x (pg, f64); + + svcvt_u32_x (pg, f16); + svcvt_u32_x (pg, f32); + svcvt_u32_x (pg, f64); + + svcvt_u16_x (pg, f16); + svcvt_u16_x (pg, f32); /* { dg-error {'svcvt_u16_x' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_u16_x (pg, f64); /* { dg-error {'svcvt_u16_x' has no form that takes 'svfloat64_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_2.c new file mode 100644 index 0000000..ddbd93b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_convert_2.c @@ -0,0 +1,76 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svint32_t s32, svuint32_t u32, + svint64_t s64, svuint64_t u64, svfloat16_t f16, svfloat32_t f32, + svfloat64_t f64) +{ + svcvt_f64_m (f64, pg); /* { dg-error {too few arguments to function 'svcvt_f64_m'} } */ + svcvt_f64_m (f64, pg, s32, 0); /* { dg-error {too many arguments to function 'svcvt_f64_m'} } */ + svcvt_f64_m (f32, pg, s32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svcvt_f64_m', which expects 'svfloat64_t'} } */ + svcvt_f64_m (0, pg, s32); /* { dg-error {passing 'int' to argument 1 of 'svcvt_f64_m', which expects 'svfloat64_t'} } */ + svcvt_f64_m (pg, pg, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svcvt_f64_m', which expects 'svfloat64_t'} } */ + svcvt_f64_m (f64, s32, s32); /* { dg-error {passing 'svint32_t' to argument 2 of 'svcvt_f64_m', which expects 'svbool_t'} } */ + svcvt_f64_m (f64, pg, 0); /* { dg-error {passing 'int' to argument 3 of 'svcvt_f64_m', which expects an SVE vector type} } */ + + svcvt_f64_m (f64, pg, s8); /* { dg-error {'svcvt_f64_m' has no form that takes 'svint8_t' arguments} } */ + svcvt_f64_m (f64, pg, s16); /* { dg-error {'svcvt_f64_m' has no form that takes 'svint16_t' arguments} } */ + svcvt_f64_m (f64, pg, s32); + svcvt_f64_m (f64, pg, s64); + svcvt_f64_m (f64, pg, u8); /* { dg-error {'svcvt_f64_m' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f64_m (f64, pg, u16); /* { dg-error {'svcvt_f64_m' has no form that takes 'svuint16_t' arguments} } */ + svcvt_f64_m (f64, pg, u32); + svcvt_f64_m (f64, pg, u64); + svcvt_f64_m (f64, pg, f16); + svcvt_f64_m (f64, pg, f32); + svcvt_f64_m (f64, pg, f64); /* { dg-error {'svcvt_f64_m' has no form that takes 'svfloat64_t' arguments} } */ + + svcvt_f32_m (f32, pg, s8); /* { dg-error {'svcvt_f32_m' has no form that takes 'svint8_t' arguments} } */ + svcvt_f32_m (f32, pg, s16); /* { dg-error {'svcvt_f32_m' has no form that takes 'svint16_t' arguments} } */ + svcvt_f32_m (f32, pg, s32); + svcvt_f32_m (f32, pg, s64); + svcvt_f32_m (f32, pg, u8); /* { dg-error {'svcvt_f32_m' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f32_m (f32, pg, u16); /* { dg-error {'svcvt_f32_m' has no form that takes 'svuint16_t' arguments} } */ + svcvt_f32_m (f32, pg, u32); + svcvt_f32_m (f32, pg, u64); + svcvt_f32_m (f32, pg, f16); + svcvt_f32_m (f32, pg, f32); /* { dg-error {'svcvt_f32_m' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_f32_m (f32, pg, f64); + + svcvt_f16_m (f16, pg, s8); /* { dg-error {'svcvt_f16_m' has no form that takes 'svint8_t' arguments} } */ + svcvt_f16_m (f16, pg, s16); + svcvt_f16_m (f16, pg, s32); + svcvt_f16_m (f16, pg, s64); + svcvt_f16_m (f16, pg, u8); /* { dg-error {'svcvt_f16_m' has no form that takes 'svuint8_t' arguments} } */ + svcvt_f16_m (f16, pg, u16); + svcvt_f16_m (f16, pg, u32); + svcvt_f16_m (f16, pg, u64); + svcvt_f16_m (f16, pg, f16); /* { dg-error {'svcvt_f16_m' has no form that takes 'svfloat16_t' arguments} } */ + svcvt_f16_m (f16, pg, f32); + svcvt_f16_m (f16, pg, f64); + + svcvt_s64_m (s64, pg, f16); + svcvt_s64_m (s64, pg, f32); + svcvt_s64_m (s64, pg, f64); + + svcvt_s32_m (s32, pg, f16); + svcvt_s32_m (s32, pg, f32); + svcvt_s32_m (s32, pg, f64); + + svcvt_s16_m (s16, pg, f16); + svcvt_s16_m (s16, pg, f32); /* { dg-error {'svcvt_s16_m' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_s16_m (s16, pg, f64); /* { dg-error {'svcvt_s16_m' has no form that takes 'svfloat64_t' arguments} } */ + + svcvt_u64_m (u64, pg, f16); + svcvt_u64_m (u64, pg, f32); + svcvt_u64_m (u64, pg, f64); + + svcvt_u32_m (u32, pg, f16); + svcvt_u32_m (u32, pg, f32); + svcvt_u32_m (u32, pg, f64); + + svcvt_u16_m (u16, pg, f16); + svcvt_u16_m (u16, pg, f32); /* { dg-error {'svcvt_u16_m' has no form that takes 'svfloat32_t' arguments} } */ + svcvt_u16_m (u16, pg, f64); /* { dg-error {'svcvt_u16_m' has no form that takes 'svfloat64_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_1.c new file mode 100644 index 0000000..888b525 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64) +{ + svclz_m (u32, pg); /* { dg-error {too few arguments to function 'svclz_m'} } */ + svclz_m (u32, pg, s32, s32); /* { dg-error {too many arguments to function 'svclz_m'} } */ + svclz_m (0, pg, f32); /* { dg-error {passing 'int' to argument 1 of 'svclz_m', which expects an SVE vector type} } */ + svclz_m (u32, u32, f32); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svclz_m', which expects 'svbool_t'} } */ + svclz_m (u32, 0, f32); /* { dg-error {passing 'int' to argument 2 of 'svclz_m', which expects 'svbool_t'} } */ + svclz_m (u32, pg, s32); + svclz_m (u32, pg, u32); + svclz_m (u32, pg, f32); /* { dg-error {'svclz_m' has no form that takes 'svfloat32_t' arguments} } */ + svclz_m (u32, pg, pg); /* { dg-error {'svclz_m' has no form that takes 'svbool_t' arguments} } */ + + svclz_m (pg, pg, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (s32, pg, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (f32, pg, s32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (s64, pg, s32); /* { dg-error {passing 'svint64_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (u64, pg, s32); /* { dg-error {arguments 1 and 3 of 'svclz_m' must have the same element size, but the values passed here have type 'svuint64_t' and 'svint32_t' respectively} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_2.c new file mode 100644 index 0000000..233e847 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_2.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-flax-vector-conversions" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64) +{ + svclz_m (u32, pg); /* { dg-error {too few arguments to function 'svclz_m'} } */ + svclz_m (u32, pg, s32, s32); /* { dg-error {too many arguments to function 'svclz_m'} } */ + svclz_m (0, pg, f32); /* { dg-error {passing 'int' to argument 1 of 'svclz_m', which expects an SVE vector type} } */ + svclz_m (u32, u32, f32); /* { dg-error {passing 'svuint32_t' to argument 2 of 'svclz_m', which expects 'svbool_t'} } */ + svclz_m (u32, 0, f32); /* { dg-error {passing 'int' to argument 2 of 'svclz_m', which expects 'svbool_t'} } */ + svclz_m (u32, pg, s32); + svclz_m (u32, pg, u32); + svclz_m (u32, pg, f32); /* { dg-error {'svclz_m' has no form that takes 'svfloat32_t' arguments} } */ + svclz_m (u32, pg, pg); /* { dg-error {'svclz_m' has no form that takes 'svbool_t' arguments} } */ + + svclz_m (pg, pg, s32); /* { dg-error {passing 'svbool_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (s32, pg, s32); /* { dg-error {passing 'svint32_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (f32, pg, s32); /* { dg-error {passing 'svfloat32_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (s64, pg, s32); /* { dg-error {passing 'svint64_t' to argument 1 of 'svclz_m', which expects a vector of unsigned integers} } */ + svclz_m (u64, pg, s32); /* { dg-error {arguments 1 and 3 of 'svclz_m' must have the same element size, but the values passed here have type 'svuint64_t' and 'svint32_t' respectively} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_3.c new file mode 100644 index 0000000..da57b07 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_count_3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8) +{ + svcnt_x (pg); /* { dg-error {too few arguments to function 'svcnt_x'} } */ + svcnt_x (pg, u8, u8); /* { dg-error {too many arguments to function 'svcnt_x'} } */ + svcnt_x (u8, u8); /* { dg-error {passing 'svuint8_t' to argument 1 of 'svcnt_x', which expects 'svbool_t'} } */ + svcnt_x (pg, pg); /* { dg-error {'svcnt_x' has no form that takes 'svbool_t' arguments} } */ + svcnt_x (pg, 1); /* { dg-error {passing 'int' to argument 2 of 'svcnt_x', which expects an SVE vector type} } */ + svcnt_x (pg, u8); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_uint_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_uint_1.c new file mode 100644 index 0000000..9c8acdf --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_uint_1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16) +{ + svexpa (); /* { dg-error {too few arguments to function 'svexpa'} } */ + svexpa (u16, u16); /* { dg-error {too many arguments to function 'svexpa'} } */ + svexpa (1); /* { dg-error {passing 'int' to argument 1 of 'svexpa', which expects an SVE vector type} } */ + svexpa (pg); /* { dg-error {passing 'svbool_t' to argument 1 of 'svexpa', which expects a vector of unsigned integers} } */ + svexpa (s8); /* { dg-error {passing 'svint8_t' to argument 1 of 'svexpa', which expects a vector of unsigned integers} } */ + svexpa (s16); /* { dg-error {passing 'svint16_t' to argument 1 of 'svexpa', which expects a vector of unsigned integers} } */ + svexpa (f16); /* { dg-error {passing 'svfloat16_t' to argument 1 of 'svexpa', which expects a vector of unsigned integers} } */ + + svexpa (u8); /* { dg-error {'svexpa' has no form that takes 'svuint8_t' arguments} } */ + svexpa (u16); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_widen_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_widen_1.c new file mode 100644 index 0000000..95a97a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/unary_widen_1.c @@ -0,0 +1,25 @@ +#include <arm_sve.h> + +void +test (svbool_t pg, svint8_t s8, svuint8_t u8, + svint16_t s16, svuint16_t u16, svfloat16_t f16, + svint32_t s32, svuint32_t u32, svfloat32_t f32, + svint64_t s64, svuint64_t u64, svfloat64_t f64, float f, int i) +{ + svunpklo (); /* { dg-error {too few arguments to function 'svunpklo'} } */ + svunpklo (pg, s8); /* { dg-error {too many arguments to function 'svunpklo'} } */ + svunpklo (i); /* { dg-error {passing 'int' to argument 1 of 'svunpklo', which expects an SVE vector type} } */ + svunpklo (f); /* { dg-error {passing 'float' to argument 1 of 'svunpklo', which expects an SVE vector type} } */ + svunpklo (pg); + svunpklo (s8); + svunpklo (s16); + svunpklo (s32); + svunpklo (s64); /* { dg-error {'svunpklo' has no form that takes 'svint64_t' arguments} } */ + svunpklo (u8); + svunpklo (u16); + svunpklo (u32); + svunpklo (u64); /* { dg-error {'svunpklo' has no form that takes 'svuint64_t' arguments} } */ + svunpklo (f16); /* { dg-error {'svunpklo' has no form that takes 'svfloat16_t' arguments} } */ + svunpklo (f32); /* { dg-error {'svunpklo' has no form that takes 'svfloat32_t' arguments} } */ + svunpklo (f64); /* { dg-error {'svunpklo' has no form that takes 'svfloat64_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_1.c new file mode 100644 index 0000000..37524c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_1.c @@ -0,0 +1,17 @@ +#include <arm_sve.h> + +void +f (svint8_t s8, svuint16_t u16, svfloat32_t f32, + svint16x2_t s16x2, svuint32x3_t u32x3, svfloat64x4_t f64x4, + svbool_t pg) +{ + s8 = no_ret_s8 (); /* { dg-error {incompatible types when assigning to type 'svint8_t' from type 'int'} } */ + u16 = no_ret_u16 (); /* { dg-error {incompatible types when assigning to type 'svuint16_t' from type 'int'} } */ + f32 = no_ret_f32 (); /* { dg-error {incompatible types when assigning to type 'svfloat32_t' from type 'int'} } */ + s16x2 = no_ret_s16x2 (); /* { dg-error {incompatible types when assigning to type 'svint16x2_t' from type 'int'} } */ + u32x3 = no_ret_u32x3 (); /* { dg-error {incompatible types when assigning to type 'svuint32x3_t' from type 'int'} } */ + f64x4 = no_ret_f64x4 (); /* { dg-error {incompatible types when assigning to type 'svfloat64x4_t' from type 'int'} } */ + pg = no_ret_pg (); /* { dg-error {incompatible types when assigning to type 'svbool_t' from type 'int'} } */ + + no_pass_args (pg, u16, f32, s16x2, u32x3, f64x4, pg); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_2.c new file mode 100644 index 0000000..7e869bd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/undeclared_2.c @@ -0,0 +1,15 @@ +#include <arm_sve.h> + +void +f (svint8_t s8, svuint16_t u16, svfloat32_t f32, + svint16x2_t s16x2, svuint32x3_t u32x3, svfloat64x4_t f64x4, + svbool_t pg) +{ + s8 = svlsr_x (pg, s8, 1); /* { dg-error {'svlsr_x' has no form that takes 'svint8_t' arguments} } */ + u16 = svneg_x (pg, u16); /* { dg-error {'svneg_x' has no form that takes 'svuint16_t' arguments} } */ + f32 = svclz_x (pg, f32); /* { dg-error {'svclz_x' has no form that takes 'svfloat32_t' arguments} } */ + s16x2 = svcreate2 (s8); /* { dg-error {too few arguments to function 'svcreate2'} } */ + u32x3 = svcreate3 (u16, u16, f32); /* { dg-error {passing 'svfloat32_t' to argument 3 of 'svcreate3', but previous arguments had type 'svuint16_t'} } */ + f64x4 = svcreate4 (f32, f32, f32, f32, f32); /* { dg-error {too many arguments to function 'svcreate4'} } */ + pg = svadd_x (pg, pg, pg); /* { dg-error {'svadd_x' has no form that takes 'svbool_t' arguments} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/add_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/add_1.c new file mode 100644 index 0000000..f5c6285 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/add_1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +#include <arm_sve.h> + +void +foo (svint8_t *res1, svint8_t *res2, svbool_t pg, svint8_t a, svint8_t b) +{ + *res1 = svadd_m (pg, a, b); + *res2 = svadd_m (pg, a, b); +} + +/* { dg-final { scan-tree-dump-times {svadd_s8_m|svadd_m} 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/and_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/and_1.c new file mode 100644 index 0000000..59348ce --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/and_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svand_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svand_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tands\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/bic_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/bic_1.c new file mode 100644 index 0000000..e1c4849 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/bic_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbic_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbic_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbics\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tbic\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_1.c new file mode 100644 index 0000000..24aa8f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbrka_m (x, pg, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbrka_m (x, pg, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkas\tp[0-9]+\.b, p[0-9]+/m,} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrka\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_2.c new file mode 100644 index 0000000..8aa3388 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brka_2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svbrka_z (pg, x); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, int *any) +{ + svbool_t res = svbrka_z (pg, x); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkas\tp[0-9]+\.b, p[0-9]+/z,} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrka\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_1.c new file mode 100644 index 0000000..07e3622 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbrkb_m (x, pg, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbrkb_m (x, pg, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkbs\tp[0-9]+\.b, p[0-9]+/m,} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrkb\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_2.c new file mode 100644 index 0000000..ee677ce --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkb_2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svbrkb_z (pg, x); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, int *any) +{ + svbool_t res = svbrkb_z (pg, x); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkbs\tp[0-9]+\.b, p[0-9]+/z,} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrkb\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkn_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkn_1.c new file mode 100644 index 0000000..7fd9318 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkn_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbrkn_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbrkn_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkns\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrkn\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpa_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpa_1.c new file mode 100644 index 0000000..18cca37 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpa_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbrkpa_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbrkpa_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkpas\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrkpa\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpb_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpb_1.c new file mode 100644 index 0000000..73eb709 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/brkpb_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svbrkpb_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svbrkpb_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tbrkpbs\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tbrkpb\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c new file mode 100644 index 0000000..dd8f6c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpeq_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmpeq_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpeq\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c new file mode 100644 index 0000000..028d375 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpeq (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmpeq (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpeq (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmpeq (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpeq\t} 4 } } */ +/* { dg-final { scan-assembler-times {\tcmpeq\t[^\n]*, #10} 2 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_3.c new file mode 100644 index 0000000..115b26c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_3.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svfloat32_t x, svfloat32_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpeq (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y, int *any) +{ + svbool_t res = svcmpeq (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svfloat32_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpeq (pg, x, 0.0); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svfloat32_t x, int *any) +{ + svbool_t res = svcmpeq (pg, x, 0.0); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tfcmeq\t} 4 } } */ +/* { dg-final { scan-assembler-times {\tfcmeq\t[^\n]*, #0\.0} 2 } } */ +/* { dg-final { scan-assembler-times {\tptest\t} 4 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntb_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntb_pat_1.c new file mode 100644 index 0000000..d57a75c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntb_pat_1.c @@ -0,0 +1,132 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** cntb_pow2: +** mov x0, #?32 +** ret +*/ +uint64_t cntb_pow2 () { return svcntb_pat (SV_POW2); } + +/* +** cntb_vl1: +** mov x0, #?1 +** ret +*/ +uint64_t cntb_vl1 () { return svcntb_pat (SV_VL1); } + +/* +** cntb_vl2: +** mov x0, #?2 +** ret +*/ +uint64_t cntb_vl2 () { return svcntb_pat (SV_VL2); } + +/* +** cntb_vl3: +** mov x0, #?3 +** ret +*/ +uint64_t cntb_vl3 () { return svcntb_pat (SV_VL3); } + +/* +** cntb_vl4: +** mov x0, #?4 +** ret +*/ +uint64_t cntb_vl4 () { return svcntb_pat (SV_VL4); } + +/* +** cntb_vl5: +** mov x0, #?5 +** ret +*/ +uint64_t cntb_vl5 () { return svcntb_pat (SV_VL5); } + +/* +** cntb_vl6: +** mov x0, #?6 +** ret +*/ +uint64_t cntb_vl6 () { return svcntb_pat (SV_VL6); } + +/* +** cntb_vl7: +** mov x0, #?7 +** ret +*/ +uint64_t cntb_vl7 () { return svcntb_pat (SV_VL7); } + +/* +** cntb_vl8: +** mov x0, #?8 +** ret +*/ +uint64_t cntb_vl8 () { return svcntb_pat (SV_VL8); } + +/* +** cntb_vl16: +** mov x0, #?16 +** ret +*/ +uint64_t cntb_vl16 () { return svcntb_pat (SV_VL16); } + +/* +** cntb_vl32: +** mov x0, #?32 +** ret +*/ +uint64_t cntb_vl32 () { return svcntb_pat (SV_VL32); } + +/* +** cntb_vl64: +** mov x0, #?0 +** ret +*/ +uint64_t cntb_vl64 () { return svcntb_pat (SV_VL64); } + +/* +** cntb_vl128: +** mov x0, #?0 +** ret +*/ +uint64_t cntb_vl128 () { return svcntb_pat (SV_VL128); } + +/* +** cntb_vl256: +** mov x0, #?0 +** ret +*/ +uint64_t cntb_vl256 () { return svcntb_pat (SV_VL256); } + +/* +** cntb_mul3: +** mov x0, #?30 +** ret +*/ +uint64_t cntb_mul3 () { return svcntb_pat (SV_MUL3); } + +/* +** cntb_mul4: +** mov x0, #?32 +** ret +*/ +uint64_t cntb_mul4 () { return svcntb_pat (SV_MUL4); } + +/* +** cntb_all: +** mov x0, #?32 +** ret +*/ +uint64_t cntb_all () { return svcntb_pat (SV_ALL); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntd_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntd_pat_1.c new file mode 100644 index 0000000..d93a320 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntd_pat_1.c @@ -0,0 +1,132 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** cntd_pow2: +** mov x0, #?4 +** ret +*/ +uint64_t cntd_pow2 () { return svcntd_pat (SV_POW2); } + +/* +** cntd_vl1: +** mov x0, #?1 +** ret +*/ +uint64_t cntd_vl1 () { return svcntd_pat (SV_VL1); } + +/* +** cntd_vl2: +** mov x0, #?2 +** ret +*/ +uint64_t cntd_vl2 () { return svcntd_pat (SV_VL2); } + +/* +** cntd_vl3: +** mov x0, #?3 +** ret +*/ +uint64_t cntd_vl3 () { return svcntd_pat (SV_VL3); } + +/* +** cntd_vl4: +** mov x0, #?4 +** ret +*/ +uint64_t cntd_vl4 () { return svcntd_pat (SV_VL4); } + +/* +** cntd_vl5: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl5 () { return svcntd_pat (SV_VL5); } + +/* +** cntd_vl6: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl6 () { return svcntd_pat (SV_VL6); } + +/* +** cntd_vl7: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl7 () { return svcntd_pat (SV_VL7); } + +/* +** cntd_vl8: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl8 () { return svcntd_pat (SV_VL8); } + +/* +** cntd_vl16: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl16 () { return svcntd_pat (SV_VL16); } + +/* +** cntd_vl32: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl32 () { return svcntd_pat (SV_VL32); } + +/* +** cntd_vl64: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl64 () { return svcntd_pat (SV_VL64); } + +/* +** cntd_vl128: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl128 () { return svcntd_pat (SV_VL128); } + +/* +** cntd_vl256: +** mov x0, #?0 +** ret +*/ +uint64_t cntd_vl256 () { return svcntd_pat (SV_VL256); } + +/* +** cntd_mul3: +** mov x0, #?3 +** ret +*/ +uint64_t cntd_mul3 () { return svcntd_pat (SV_MUL3); } + +/* +** cntd_mul4: +** mov x0, #?4 +** ret +*/ +uint64_t cntd_mul4 () { return svcntd_pat (SV_MUL4); } + +/* +** cntd_all: +** mov x0, #?4 +** ret +*/ +uint64_t cntd_all () { return svcntd_pat (SV_ALL); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cnth_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cnth_pat_1.c new file mode 100644 index 0000000..bd988f5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cnth_pat_1.c @@ -0,0 +1,132 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** cnth_pow2: +** mov x0, #?16 +** ret +*/ +uint64_t cnth_pow2 () { return svcnth_pat (SV_POW2); } + +/* +** cnth_vl1: +** mov x0, #?1 +** ret +*/ +uint64_t cnth_vl1 () { return svcnth_pat (SV_VL1); } + +/* +** cnth_vl2: +** mov x0, #?2 +** ret +*/ +uint64_t cnth_vl2 () { return svcnth_pat (SV_VL2); } + +/* +** cnth_vl3: +** mov x0, #?3 +** ret +*/ +uint64_t cnth_vl3 () { return svcnth_pat (SV_VL3); } + +/* +** cnth_vl4: +** mov x0, #?4 +** ret +*/ +uint64_t cnth_vl4 () { return svcnth_pat (SV_VL4); } + +/* +** cnth_vl5: +** mov x0, #?5 +** ret +*/ +uint64_t cnth_vl5 () { return svcnth_pat (SV_VL5); } + +/* +** cnth_vl6: +** mov x0, #?6 +** ret +*/ +uint64_t cnth_vl6 () { return svcnth_pat (SV_VL6); } + +/* +** cnth_vl7: +** mov x0, #?7 +** ret +*/ +uint64_t cnth_vl7 () { return svcnth_pat (SV_VL7); } + +/* +** cnth_vl8: +** mov x0, #?8 +** ret +*/ +uint64_t cnth_vl8 () { return svcnth_pat (SV_VL8); } + +/* +** cnth_vl16: +** mov x0, #?16 +** ret +*/ +uint64_t cnth_vl16 () { return svcnth_pat (SV_VL16); } + +/* +** cnth_vl32: +** mov x0, #?0 +** ret +*/ +uint64_t cnth_vl32 () { return svcnth_pat (SV_VL32); } + +/* +** cnth_vl64: +** mov x0, #?0 +** ret +*/ +uint64_t cnth_vl64 () { return svcnth_pat (SV_VL64); } + +/* +** cnth_vl128: +** mov x0, #?0 +** ret +*/ +uint64_t cnth_vl128 () { return svcnth_pat (SV_VL128); } + +/* +** cnth_vl256: +** mov x0, #?0 +** ret +*/ +uint64_t cnth_vl256 () { return svcnth_pat (SV_VL256); } + +/* +** cnth_mul3: +** mov x0, #?15 +** ret +*/ +uint64_t cnth_mul3 () { return svcnth_pat (SV_MUL3); } + +/* +** cnth_mul4: +** mov x0, #?16 +** ret +*/ +uint64_t cnth_mul4 () { return svcnth_pat (SV_MUL4); } + +/* +** cnth_all: +** mov x0, #?16 +** ret +*/ +uint64_t cnth_all () { return svcnth_pat (SV_ALL); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntw_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntw_pat_1.c new file mode 100644 index 0000000..53c8435 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cntw_pat_1.c @@ -0,0 +1,132 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** cntw_pow2: +** mov x0, #?8 +** ret +*/ +uint64_t cntw_pow2 () { return svcntw_pat (SV_POW2); } + +/* +** cntw_vl1: +** mov x0, #?1 +** ret +*/ +uint64_t cntw_vl1 () { return svcntw_pat (SV_VL1); } + +/* +** cntw_vl2: +** mov x0, #?2 +** ret +*/ +uint64_t cntw_vl2 () { return svcntw_pat (SV_VL2); } + +/* +** cntw_vl3: +** mov x0, #?3 +** ret +*/ +uint64_t cntw_vl3 () { return svcntw_pat (SV_VL3); } + +/* +** cntw_vl4: +** mov x0, #?4 +** ret +*/ +uint64_t cntw_vl4 () { return svcntw_pat (SV_VL4); } + +/* +** cntw_vl5: +** mov x0, #?5 +** ret +*/ +uint64_t cntw_vl5 () { return svcntw_pat (SV_VL5); } + +/* +** cntw_vl6: +** mov x0, #?6 +** ret +*/ +uint64_t cntw_vl6 () { return svcntw_pat (SV_VL6); } + +/* +** cntw_vl7: +** mov x0, #?7 +** ret +*/ +uint64_t cntw_vl7 () { return svcntw_pat (SV_VL7); } + +/* +** cntw_vl8: +** mov x0, #?8 +** ret +*/ +uint64_t cntw_vl8 () { return svcntw_pat (SV_VL8); } + +/* +** cntw_vl16: +** mov x0, #?0 +** ret +*/ +uint64_t cntw_vl16 () { return svcntw_pat (SV_VL16); } + +/* +** cntw_vl32: +** mov x0, #?0 +** ret +*/ +uint64_t cntw_vl32 () { return svcntw_pat (SV_VL32); } + +/* +** cntw_vl64: +** mov x0, #?0 +** ret +*/ +uint64_t cntw_vl64 () { return svcntw_pat (SV_VL64); } + +/* +** cntw_vl128: +** mov x0, #?0 +** ret +*/ +uint64_t cntw_vl128 () { return svcntw_pat (SV_VL128); } + +/* +** cntw_vl256: +** mov x0, #?0 +** ret +*/ +uint64_t cntw_vl256 () { return svcntw_pat (SV_VL256); } + +/* +** cntw_mul3: +** mov x0, #?6 +** ret +*/ +uint64_t cntw_mul3 () { return svcntw_pat (SV_MUL3); } + +/* +** cntw_mul4: +** mov x0, #?8 +** ret +*/ +uint64_t cntw_mul4 () { return svcntw_pat (SV_MUL4); } + +/* +** cntw_all: +** mov x0, #?8 +** ret +*/ +uint64_t cntw_all () { return svcntw_pat (SV_ALL); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_1.c new file mode 100644 index 0000000..0442efe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_1.c @@ -0,0 +1,16 @@ +/* { dg-options "-g" } */ + +#include <arm_sve.h> + +svbool_t f_b (svbool_t x) { return x; } +svint8_t f_s8 (svint8_t x) { return x; } +svuint8_t f_u8 (svuint8_t x) { return x; } +svint16_t f_s16 (svint16_t x) { return x; } +svuint16_t f_u16 (svuint16_t x) { return x; } +svfloat16_t f_f16 (svfloat16_t x) { return x; } +svint32_t f_s32 (svint32_t x) { return x; } +svuint32_t f_u32 (svuint32_t x) { return x; } +svfloat32_t f_f32 (svfloat32_t x) { return x; } +svint64_t f_s64 (svint64_t x) { return x; } +svuint64_t f_u64 (svuint64_t x) { return x; } +svfloat64_t f_f64 (svfloat64_t x) { return x; } diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_2.c new file mode 100644 index 0000000..63a26d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_2.c @@ -0,0 +1,16 @@ +/* { dg-options "-g" } */ + +#include <arm_sve.h> + +svbool_t f_b (svbool_t x) { return svptrue_b32 (); } +svint8_t f_s8 (svint8_t x) { return svdup_s8 (0); } +svuint8_t f_u8 (svuint8_t x) { return svdup_u8 (1); } +svint16_t f_s16 (svint16_t x) { return svdup_s16 (2); } +svuint16_t f_u16 (svuint16_t x) { return svdup_u16 (3); } +svfloat16_t f_f16 (svfloat16_t x) { return svdup_f16 (4); } +svint32_t f_s32 (svint32_t x) { return svdup_s32 (5); } +svuint32_t f_u32 (svuint32_t x) { return svdup_u32 (6); } +svfloat32_t f_f32 (svfloat32_t x) { return svdup_f32 (7); } +svint64_t f_s64 (svint64_t x) { return svdup_s64 (8); } +svuint64_t f_u64 (svuint64_t x) { return svdup_u64 (9); } +svfloat64_t f_f64 (svfloat64_t x) { return svdup_f64 (10); } diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_3.c new file mode 100644 index 0000000..ac151e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/debug_3.c @@ -0,0 +1,39 @@ +/* { dg-options "-g" } */ + +#include <arm_sve.h> + +svint8x2_t f2_s8 (svint8x2_t x) { return x; } +svuint8x2_t f2_u8 (svuint8x2_t x) { return x; } +svint16x2_t f2_s16 (svint16x2_t x) { return x; } +svuint16x2_t f2_u16 (svuint16x2_t x) { return x; } +svfloat16x2_t f2_f16 (svfloat16x2_t x) { return x; } +svint32x2_t f2_s32 (svint32x2_t x) { return x; } +svuint32x2_t f2_u32 (svuint32x2_t x) { return x; } +svfloat32x2_t f2_f32 (svfloat32x2_t x) { return x; } +svint64x2_t f2_s64 (svint64x2_t x) { return x; } +svuint64x2_t f2_u64 (svuint64x2_t x) { return x; } +svfloat64x2_t f2_f64 (svfloat64x2_t x) { return x; } + +svint8x3_t f3_s8 (svint8x3_t x) { return x; } +svuint8x3_t f3_u8 (svuint8x3_t x) { return x; } +svint16x3_t f3_s16 (svint16x3_t x) { return x; } +svuint16x3_t f3_u16 (svuint16x3_t x) { return x; } +svfloat16x3_t f3_f16 (svfloat16x3_t x) { return x; } +svint32x3_t f3_s32 (svint32x3_t x) { return x; } +svuint32x3_t f3_u32 (svuint32x3_t x) { return x; } +svfloat32x3_t f3_f32 (svfloat32x3_t x) { return x; } +svint64x3_t f3_s64 (svint64x3_t x) { return x; } +svuint64x3_t f3_u64 (svuint64x3_t x) { return x; } +svfloat64x3_t f3_f64 (svfloat64x3_t x) { return x; } + +svint8x4_t f4_s8 (svint8x4_t x) { return x; } +svuint8x4_t f4_u8 (svuint8x4_t x) { return x; } +svint16x4_t f4_s16 (svint16x4_t x) { return x; } +svuint16x4_t f4_u16 (svuint16x4_t x) { return x; } +svfloat16x4_t f4_f16 (svfloat16x4_t x) { return x; } +svint32x4_t f4_s32 (svint32x4_t x) { return x; } +svuint32x4_t f4_u32 (svuint32x4_t x) { return x; } +svfloat32x4_t f4_f42 (svfloat32x4_t x) { return x; } +svint64x4_t f4_s64 (svint64x4_t x) { return x; } +svuint64x4_t f4_u64 (svuint64x4_t x) { return x; } +svfloat64x4_t f4_f64 (svfloat64x4_t x) { return x; } diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/double_pragma_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/double_pragma_1.c new file mode 100644 index 0000000..9b3c369 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/double_pragma_1.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +/* It doesn't really matter if this produces errors about redefinitions, + but it mustn't trigger an ICE. */ +#pragma GCC aarch64 "arm_sve.h" +#pragma GCC aarch64 "arm_sve.h" /* { dg-error "duplicate definition of 'arm_sve.h'" } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_1.c new file mode 100644 index 0000000..d71507b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlittle-endian" } */ + +#include <arm_sve.h> + +svint32_t +dupq (int x) +{ + return svdupq_s32 (x, 1, 2, 3); +} + +/* { dg-final { scan-assembler {\tldr\tq[0-9]+,} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[0\], w0\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ +/* { dg-final { scan-assembler {\t\.word\t1\n\t\.word\t2\n\t\.word\t3\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_10.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_10.c new file mode 100644 index 0000000..f8f797c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_10.c @@ -0,0 +1,66 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t __attribute__ ((noipa)) +make_b8 (int8_t x0, int8_t x1, int8_t x2, int8_t x3, + int8_t x4, int8_t x5, int8_t x6, int8_t x7, + int8_t x8, int8_t x9, int8_t xa, int8_t xb, + int8_t xc, int8_t xd, int8_t xe, int8_t xf) +{ + return svdupq_b8 (x0, x1, x2, x3, x4, x5, x6, x7, + x8, x9, xa, xb, xc, xd, xe, xf); +} + +svbool_t __attribute__ ((noipa)) +make_b16 (int16_t x0, int16_t x1, int16_t x2, int16_t x3, + int16_t x4, int16_t x5, int16_t x6, int16_t x7) +{ + return svdupq_b16 (x0, x1, x2, x3, x4, x5, x6, x7); +} + +svbool_t __attribute__ ((noipa)) +make_b32 (int32_t x0, int32_t x1, int32_t x2, int32_t x3) +{ + return svdupq_b32 (x0, x1, x2, x3); +} + +svbool_t __attribute__ ((noipa)) +make_b64 (int64_t x0, int64_t x1) +{ + return svdupq_b64 (x0, x1); +} + +int8_t a[16] = { 1, 0, 0, -3, 0, 9, 11, 0, 0, 1, 0, -4, 9, 9, 0, 0 }; + +int +main () +{ + svbool_t pg = svptrue_pat_b8 (SV_VL16); + svbool_t b8 = make_b8 (a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15]); + if (svptest_any (svptrue_b8 (), + sveor_z (pg, b8, svcmpne (pg, svld1 (pg, a), 0)))) + __builtin_abort (); + + svbool_t b16 = make_b16 (a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7]); + if (svptest_any (svptrue_b16 (), + sveor_z (pg, b16, svcmpne (pg, svld1sb_u16 (pg, a), 0)))) + __builtin_abort (); + + svbool_t b32 = make_b32 (a[0], a[1], a[2], a[3]); + if (svptest_any (svptrue_b32 (), + sveor_z (pg, b32, svcmpne (pg, svld1sb_u32 (pg, a), 0)))) + __builtin_abort (); + + svbool_t b64 = make_b64 (a[0], a[1]); + if (svptest_any (svptrue_b64 (), + sveor_z (pg, b64, svcmpne (pg, svld1sb_u64 (pg, a), 0)))) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_2.c new file mode 100644 index 0000000..d494943 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbig-endian" } */ + +/* To avoid needing big-endian header files. */ +#pragma GCC aarch64 "arm_sve.h" + +svint32_t +dupq (int x) +{ + return svdupq_s32 (x, 1, 2, 3); +} + +/* { dg-final { scan-assembler {\tldr\tq[0-9]+,} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[0\], w0\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ +/* { dg-final { scan-assembler {\t\.word\t3\n\t\.word\t2\n\t\.word\t1\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_3.c new file mode 100644 index 0000000..4bc8259 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_3.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlittle-endian" } */ + +/* To avoid needing big-endian header files. */ +#pragma GCC aarch64 "arm_sve.h" + +svint32_t +dupq (int x) +{ + return svdupq_s32 (0, 1, x, 3); +} + +/* { dg-final { scan-assembler {\tldr\tq[0-9]+,} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[2\], w0\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ +/* { dg-final { scan-assembler {\t\.word\t0\n\t\.word\t1\n\t\.word\t[^\n]*\n\t\.word\t3\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_4.c new file mode 100644 index 0000000..6f9f9f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_4.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbig-endian" } */ + +/* To avoid needing big-endian header files. */ +#pragma GCC aarch64 "arm_sve.h" + +svint32_t +dupq (int x) +{ + return svdupq_s32 (0, 1, x, 3); +} + +/* { dg-final { scan-assembler {\tldr\tq[0-9]+,} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[2\], w0\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ +/* { dg-final { scan-assembler {\t\.word\t3\n\t\.word\t[^\n]*\n\t\.word\t1\n\t\.word\t0\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_5.c new file mode 100644 index 0000000..53426c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_5.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlittle-endian" } */ + +#include <arm_sve.h> + +svint32_t +dupq (int x1, int x2, int x3, int x4) +{ + return svdupq_s32 (x1, x2, x3, x4); +} + +/* { dg-final { scan-assembler-not {\tldr\t} } } */ +/* { dg-final { scan-assembler {, [wx]0\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[1\], w1\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[2\], w2\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[3\], w3\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_6.c new file mode 100644 index 0000000..dfce5e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_6.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbig-endian" } */ + +/* To avoid needing big-endian header files. */ +#pragma GCC aarch64 "arm_sve.h" + +svint32_t +dupq (int x1, int x2, int x3, int x4) +{ + return svdupq_s32 (x1, x2, x3, x4); +} + +/* { dg-final { scan-assembler-not {\tldr\t} } } */ +/* { dg-final { scan-assembler {, [wx]0\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[1\], w1\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[2\], w2\n} } } */ +/* { dg-final { scan-assembler {\tins\tv[0-9]+\.s\[3\], w3\n} } } */ +/* { dg-final { scan-assembler {\tdup\tz[0-9]+\.q, z[0-9]+\.q\[0\]\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_7.c new file mode 100644 index 0000000..08decb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_7.c @@ -0,0 +1,66 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svint8_t __attribute__ ((noipa)) +make_s8 (int8_t x0, int8_t x1, int8_t x2, int8_t x3, + int8_t x4, int8_t x5, int8_t x6, int8_t x7, + int8_t x8, int8_t x9, int8_t xa, int8_t xb, + int8_t xc, int8_t xd, int8_t xe, int8_t xf) +{ + return svdupq_s8 (x0, x1, x2, x3, x4, x5, x6, x7, + x8, x9, xa, xb, xc, xd, xe, xf); +} + +svint16_t __attribute__ ((noipa)) +make_s16 (int16_t x0, int16_t x1, int16_t x2, int16_t x3, + int16_t x4, int16_t x5, int16_t x6, int16_t x7) +{ + return svdupq_s16 (x0, x1, x2, x3, x4, x5, x6, x7); +} + +svint32_t __attribute__ ((noipa)) +make_s32 (int32_t x0, int32_t x1, int32_t x2, int32_t x3) +{ + return svdupq_s32 (x0, x1, x2, x3); +} + +svint64_t __attribute__ ((noipa)) +make_s64 (int64_t x0, int64_t x1) +{ + return svdupq_s64 (x0, x1); +} + +int8_t a[16] = { 1, -44, 91, -24, 101, -55, 77, 83, + -30, 69, 121, -128, -1, 13, 127, 26 }; +int16_t b[8] = { -716, -10288, 30604, -19258, -9418, -10435, -16001, 7300 }; +int32_t c[4] = { 1268374995, -1023602831, -891830021, -1793452959 }; +int64_t d[2] = { 0x123456789abcdefLL, -0x123456789abcdefLL }; + +int +main () +{ + svbool_t pg = svptrue_pat_b8 (SV_VL16); + svint8_t s8 = make_s8 (a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, s8, svld1 (pg, a)))) + __builtin_abort (); + + svint16_t s16 = make_s16 (b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, s16, svld1 (pg, b)))) + __builtin_abort (); + + svint32_t s32 = make_s32 (c[0], c[1], c[2], c[3]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, s32, svld1 (pg, c)))) + __builtin_abort (); + + svint64_t s64 = make_s64 (d[0], d[1]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, s64, svld1 (pg, d)))) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_8.c new file mode 100644 index 0000000..c20fb73 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_8.c @@ -0,0 +1,66 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svuint8_t __attribute__ ((noipa)) +make_u8 (uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, + uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7, + uint8_t x8, uint8_t x9, uint8_t xa, uint8_t xb, + uint8_t xc, uint8_t xd, uint8_t xe, uint8_t xf) +{ + return svdupq_u8 (x0, x1, x2, x3, x4, x5, x6, x7, + x8, x9, xa, xb, xc, xd, xe, xf); +} + +svuint16_t __attribute__ ((noipa)) +make_u16 (uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, + uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) +{ + return svdupq_u16 (x0, x1, x2, x3, x4, x5, x6, x7); +} + +svuint32_t __attribute__ ((noipa)) +make_u32 (uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) +{ + return svdupq_u32 (x0, x1, x2, x3); +} + +svuint64_t __attribute__ ((noipa)) +make_u64 (uint64_t x0, uint64_t x1) +{ + return svdupq_u64 (x0, x1); +} + +uint8_t a[16] = { 1, 212, 91, 232, 101, 201, 77, 83, + 226, 69, 121, 128, 255, 13, 127, 26 }; +uint16_t b[8] = { 64820, 55248, 30604, 46278, 56118, 55101, 49535, 7300 }; +uint32_t c[4] = { 1268374995, 3271364465, 3403137275, 2501514337 }; +uint64_t d[2] = { 0x123456789abcdefULL, 0xfedcba9876543210ULL }; + +int +main () +{ + svbool_t pg = svptrue_pat_b8 (SV_VL16); + svuint8_t u8 = make_u8 (a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, u8, svld1 (pg, a)))) + __builtin_abort (); + + svuint16_t u16 = make_u16 (b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, u16, svld1 (pg, b)))) + __builtin_abort (); + + svuint32_t u32 = make_u32 (c[0], c[1], c[2], c[3]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, u32, svld1 (pg, c)))) + __builtin_abort (); + + svuint64_t u64 = make_u64 (d[0], d[1]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, u64, svld1 (pg, d)))) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_9.c new file mode 100644 index 0000000..b29aa94 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_9.c @@ -0,0 +1,47 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svfloat16_t __attribute__ ((noipa)) +make_f16 (float16_t x0, float16_t x1, float16_t x2, float16_t x3, + float16_t x4, float16_t x5, float16_t x6, float16_t x7) +{ + return svdupq_f16 (x0, x1, x2, x3, x4, x5, x6, x7); +} + +svfloat32_t __attribute__ ((noipa)) +make_f32 (float32_t x0, float32_t x1, float32_t x2, float32_t x3) +{ + return svdupq_f32 (x0, x1, x2, x3); +} + +svfloat64_t __attribute__ ((noipa)) +make_f64 (float64_t x0, float64_t x1) +{ + return svdupq_f64 (x0, x1); +} + +float16_t a[8] = { 1.0, -4.25, 9.75, 6.5, -2.125, 5.5, -3.75, 7.625 }; +float32_t b[4] = { 1.0, -90.25, -11.75, 141.5 }; +float64_t c[2] = { 9221.5, -4491.25 }; + +int +main () +{ + svbool_t pg = svptrue_pat_b8 (SV_VL16); + svfloat16_t f16 = make_f16 (a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, f16, svld1 (pg, a)))) + __builtin_abort (); + + svfloat32_t f32 = make_f32 (b[0], b[1], b[2], b[3]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, f32, svld1 (pg, b)))) + __builtin_abort (); + + svfloat64_t f64 = make_f64 (c[0], c[1]); + if (svptest_any (svptrue_b8 (), svcmpne (pg, f64, svld1 (pg, c)))) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_1.c new file mode 100644 index 0000000..32ccb08 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_1.c @@ -0,0 +1,87 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +#ifndef TYPE +#define TYPE svint8_t +#define DUPQ svdupq_lane_s8 +#define INDEX svindex_s8 +#define COUNT 16 +#endif + +#define BASE 42 + +TYPE __attribute__ ((noipa)) +dupq_var (TYPE x, uint64_t y) +{ + return DUPQ (x, y); +} + +TYPE __attribute__ ((noipa)) +dupq_0 (TYPE x) +{ + return DUPQ (x, 0); +} + +TYPE __attribute__ ((noipa)) +dupq_1 (TYPE x) +{ + return DUPQ (x, 1); +} + +TYPE __attribute__ ((noipa)) +dupq_2 (TYPE x) +{ + return DUPQ (x, 2); +} + +TYPE __attribute__ ((noipa)) +dupq_3 (TYPE x) +{ + return DUPQ (x, 3); +} + +TYPE __attribute__ ((noipa)) +dupq_4 (TYPE x) +{ + return DUPQ (x, 4); +} + +void __attribute__ ((noipa)) +check (TYPE x, uint64_t y) +{ + svbool_t pg = svptrue_b8 (); + if (y * 2 >= svcntd ()) + { + if (svptest_any (pg, svcmpne (pg, x, 0))) + __builtin_abort (); + } + else + { + TYPE repeat = svand_x (pg, INDEX (0, 1), COUNT - 1); + TYPE expected = svadd_x (pg, repeat, BASE + y * COUNT); + if (svptest_any (pg, svcmpne (pg, x, expected))) + __builtin_abort (); + } +} + +int +main () +{ + TYPE x = INDEX (BASE, 1); + + check (dupq_0 (x), 0); + check (dupq_1 (x), 1); + check (dupq_2 (x), 2); + check (dupq_3 (x), 3); + check (dupq_4 (x), 4); + + for (int i = 0; i < 63; ++i) + { + check (dupq_var (x, i), i); + check (dupq_var (x, (uint64_t) 1 << i), (uint64_t) 1 << i); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_2.c new file mode 100644 index 0000000..40de1c7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_2.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svuint8_t +#define DUPQ svdupq_lane_u8 +#define INDEX svindex_u8 +#define COUNT 16 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_3.c new file mode 100644 index 0000000..4ebe895 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_3.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svint16_t +#define DUPQ svdupq_lane_s16 +#define INDEX svindex_s16 +#define COUNT 8 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_4.c new file mode 100644 index 0000000..1be20c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_4.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svuint16_t +#define DUPQ svdupq_lane_u16 +#define INDEX svindex_u16 +#define COUNT 8 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_5.c new file mode 100644 index 0000000..67554d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_5.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svint32_t +#define DUPQ svdupq_lane_s32 +#define INDEX svindex_s32 +#define COUNT 4 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_6.c new file mode 100644 index 0000000..1914d23 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_6.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svuint32_t +#define DUPQ svdupq_lane_u32 +#define INDEX svindex_u32 +#define COUNT 4 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_7.c new file mode 100644 index 0000000..d7a8e52 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_7.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svint64_t +#define DUPQ svdupq_lane_s64 +#define INDEX svindex_s64 +#define COUNT 2 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_8.c new file mode 100644 index 0000000..68655fe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_8.c @@ -0,0 +1,9 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2" } */ + +#define TYPE svuint64_t +#define DUPQ svdupq_lane_u64 +#define INDEX svindex_u64 +#define COUNT 2 + +#include "dupq_lane_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/eor_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/eor_1.c new file mode 100644 index 0000000..357b0bf --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/eor_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = sveor_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = sveor_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\teors\t} 2 } } */ +/* { dg-final { scan-assembler-not {\teor\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ld1_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ld1_1.c new file mode 100644 index 0000000..c68a9ed --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ld1_1.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** nop1: +** ret +*/ +void nop1 (int8_t *s) { svld1 (svptrue_b8 (), s); } + +/* +** nop2: +** ret +*/ +void nop2 (svbool_t pg, int16_t *s) { svld1 (pg, s); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_1.c new file mode 100644 index 0000000..79f8bee --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that SETFFR comes first, however high the priority of the + LDFF1 is. */ +svint8_t +foo (svbool_t pg, int8_t *ptr) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + x = svadd_x (pg, x, x); + x = svmul_x (pg, x, x); + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_2.c new file mode 100644 index 0000000..7c3c8d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that RDFFR comes after the LDFF1 and that the RDFFRs can + be CSEd. */ +svint8_t +foo (svbool_t pg, int8_t *__restrict ptr, + svbool_t *__restrict *__restrict preds) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + *preds[0] = svrdffr (); + *preds[1] = svrdffr (); + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t.*\trdffr\t} } } */ +/* { dg-final { scan-assembler-times {\trdffr\t} 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_3.c new file mode 100644 index 0000000..41ad0bc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_3.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that LDFF1s can be reordered. The load of x should come due + to its longer dependence chain. */ +svint8_t +foo (int8_t *ptr1, int8_t *ptr2) +{ + svsetffr (); + svbool_t pg = svptrue_b8 (); + svint8_t y = svldff1 (pg, ptr2); + svint8_t x = svldff1 (pg, ptr1); + x = svadd_x (pg, x, x); + x = svmul_x (pg, x, x); + x = svadd_x (pg, x, y); + return x; +} + +/* { dg-final { scan-assembler {\tldff1b\tz[0-9]+\.b, p[0-7]/z, \[x0\]\n.*\tldff1b\tz[0-9]+\.b, p[0-7]/z, \[x1\]\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_4.c new file mode 100644 index 0000000..c273021 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that we can use RDFFRS to test for a fault. */ +svint8_t +foo (svbool_t pg, int8_t *ptr, int *fault) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + *fault = svptest_any (pg, svrdffr_z (pg)); + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t.*\trdffrs\t} } } */ +/* { dg-final { scan-assembler-not {\trdffr\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_5.c new file mode 100644 index 0000000..76e7ab8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_5.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that we can use RDFFRS to read the FFR while testing for a + fault. */ +svint8_t +foo (svbool_t pg, int8_t *ptr, svbool_t *pred, int *fault) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + svbool_t ffr = svrdffr_z (pg); + *fault = svptest_any (pg, ffr); + *pred = ffr; + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t.*\trdffrs\t} } } */ +/* { dg-final { scan-assembler-not {\trdffr\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_6.c new file mode 100644 index 0000000..7110e5f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_6.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that we can use RDFFRS to test for a fault. */ +svint8_t +foo (svbool_t pg, int8_t *ptr, int *fault) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + *fault = svptest_any (svptrue_b8 (), svrdffr ()); + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t.*\trdffrs\t} } } */ +/* { dg-final { scan-assembler-not {\trdffr\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_7.c new file mode 100644 index 0000000..355fe91 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ldff1_7.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* Make sure that we can use RDFFRS to read the FFR while testing for a + fault. */ +svint8_t +foo (svbool_t pg, int8_t *ptr, svbool_t *pred, int *fault) +{ + svsetffr (); + svint8_t x = svldff1 (pg, ptr); + svbool_t ffr = svrdffr (); + *fault = svptest_any (svptrue_b8 (), ffr); + *pred = ffr; + return x; +} + +/* { dg-final { scan-assembler {\tsetffr\n.*\tldff1b\t.*\trdffrs\t} } } */ +/* { dg-final { scan-assembler-not {\trdffr\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nand_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nand_1.c new file mode 100644 index 0000000..0bc54c0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nand_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svnand_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svnand_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tnands\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tnand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nor_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nor_1.c new file mode 100644 index 0000000..7973294 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nor_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svnor_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svnor_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tnors\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tnor\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_1.c new file mode 100644 index 0000000..09dfacd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_1.c @@ -0,0 +1,17 @@ +/* { dg-options "-march=armv8-a" } */ + +#pragma GCC aarch64 "arm_sve.h" + +void +f (svbool_t *x, svint8_t *y) +{ + *x = svptrue_b8 (); /* { dg-error {ACLE function '(svbool_t svptrue_b8\(\)|svptrue_b8)' requires ISA extension 'sve'} } */ + /* { dg-message {note: you can enable 'sve' using the command-line option '-march', or by using the 'target' attribute or pragma} "" { target *-*-* } .-1 } */ + *x = svptrue_b8 (); + *x = svptrue_b8 (); + *x = svptrue_b8 (); + *x = svptrue_b8 (); + *x = svptrue_b8 (); + *x = svptrue_b8 (); + *y = svadd_m (*x, *y, 1); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_2.c new file mode 100644 index 0000000..594be1c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_2.c @@ -0,0 +1,14 @@ +/* { dg-options "-march=armv8-a" } */ + +#pragma GCC aarch64 "arm_sve.h" + +#pragma GCC target "+sve" + +void +f (svbool_t *x, svint8_t *y) +{ + *x = svptrue_b8 (); + *y = svadd_m (*x, *y, 1); +} + +/* { dg-final { scan-assembler {\tadd\tz[0-9]+\.b, p[0-7]/m, z[0-9]+\.b, z[0-9]+\.b\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_3.c new file mode 100644 index 0000000..85f4eb3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/nosve_3.c @@ -0,0 +1,12 @@ +/* { dg-options "-march=armv8-a" } */ + +#pragma GCC aarch64 "arm_sve.h" + +void __attribute__ ((target("+sve"))) +f (svbool_t *x, svint8_t *y) +{ + *x = svptrue_b8 (); + *y = svadd_m (*x, *y, 1); +} + +/* { dg-final { scan-assembler {\tadd\tz[0-9]+\.b, p[0-7]/m, z[0-9]+\.b, z[0-9]+\.b\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orn_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orn_1.c new file mode 100644 index 0000000..c3ed1eb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orn_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svorn_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svorn_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\torns\t} 2 } } */ +/* { dg-final { scan-assembler-not {\torn\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orr_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orr_1.c new file mode 100644 index 0000000..4456fa6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/orr_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t x, svbool_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svorr_z (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t x, svbool_t y, int *any) +{ + svbool_t res = svorr_z (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\torrs\t} 2 } } */ +/* { dg-final { scan-assembler-not {\torr\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_1.c new file mode 100644 index 0000000..de1ff69 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pfirst_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, int *last, svbool_t *ptr) +{ + svbool_t res = svpfirst (pg, svpfalse ()); + *last = svptest_last (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg) +{ + svbool_t res = svpfirst (pg, svpfalse ()); + return svptest_last (pg, res); +} + +/* { dg-final { scan-assembler-times {\tpfirst\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_1.c new file mode 100644 index 0000000..bf59cb9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t prev, int *last, svbool_t *ptr) +{ + svbool_t res = svpnext_b8 (pg, prev); + *last = svptest_last (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t prev) +{ + svbool_t res = svpnext_b8 (pg, prev); + return svptest_last (pg, res); +} + +/* { dg-final { scan-assembler-times {\tpnext\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_2.c new file mode 100644 index 0000000..9926a2b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_2.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svbool_t prev, int *last, svbool_t *ptr) +{ + svbool_t res = svpnext_b16 (pg, prev); + *last = svptest_last (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svbool_t prev) +{ + svbool_t res = svpnext_b16 (pg, prev); + return svptest_last (pg, res); +} + +void +test3 (svbool_t pg, svbool_t prev, int *last, svbool_t *ptr) +{ + svbool_t res = svpnext_b32 (pg, prev); + *last = svptest_last (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svbool_t prev) +{ + svbool_t res = svpnext_b32 (pg, prev); + return svptest_last (pg, res); +} + +void +test5 (svbool_t pg, svbool_t prev, int *last, svbool_t *ptr) +{ + svbool_t res = svpnext_b64 (pg, prev); + *last = svptest_last (pg, res); + *ptr = res; +} + +int +test6 (svbool_t pg, svbool_t prev) +{ + svbool_t res = svpnext_b64 (pg, prev); + return svptest_last (pg, res); +} + +/* { dg-final { scan-assembler-times {\tpnext\t} 6 } } */ +/* { dg-final { scan-assembler-times {\tptest\t} 6 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_1.c new file mode 100644 index 0000000..69bbb1e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int *last, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b8 (SV_VL32); + *last = svptest_last (svptrue_b8 (), res); + *ptr = res; +} + +int +test2 () +{ + svbool_t res = svptrue_pat_b8 (SV_VL32); + return svptest_last (svptrue_b8 (), res); +} + +/* { dg-final { scan-assembler-times {\tptrues\tp[0-9]+\.b, vl32\n} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_2.c new file mode 100644 index 0000000..ede8340 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int *last, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b16 (SV_VL16); + *last = svptest_last (svptrue_b16 (), res); + *ptr = res; +} + +int +test2 () +{ + svbool_t res = svptrue_pat_b16 (SV_VL16); + return svptest_last (svptrue_b16 (), res); +} + +/* { dg-final { scan-assembler-times {\tptrues\tp[0-9]+\.h, vl16\n} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_3.c new file mode 100644 index 0000000..d2eb3fc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_3.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int *last, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b32 (SV_VL16); + *last = svptest_last (svptrue_b32 (), res); + *ptr = res; +} + +int +test2 () +{ + svbool_t res = svptrue_pat_b32 (SV_VL16); + return svptest_last (svptrue_b32 (), res); +} + +/* { dg-final { scan-assembler-times {\tptrues\tp[0-9]+\.s, vl16\n} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_4.c new file mode 100644 index 0000000..59a21da --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_4.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b64 (SV_VL7); + *any = svptest_any (svptrue_b64 (), res); + *ptr = res; +} + +int +test2 () +{ + svbool_t res = svptrue_pat_b64 (SV_VL7); + return svptest_any (svptrue_b64 (), res); +} + +/* { dg-final { scan-assembler-times {\tptrues\tp[0-9]+\.d, vl7\n} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} { xfail *-*-* } } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_5.c new file mode 100644 index 0000000..c8f6d8a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/ptrue_pat_5.c @@ -0,0 +1,188 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +b8_b16_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b8 (SV_VL64); + *any = svptest_any (svptrue_b16 (), res); + *ptr = res; +} + +int +b8_b16_2 () +{ + svbool_t res = svptrue_pat_b8 (SV_VL64); + return svptest_any (svptrue_b16 (), res); +} + +void +b8_b32_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b8 (SV_VL32); + *any = svptest_any (svptrue_b32 (), res); + *ptr = res; +} + +int +b8_b32_2 () +{ + svbool_t res = svptrue_pat_b8 (SV_VL32); + return svptest_any (svptrue_b32 (), res); +} + +void +b8_b64_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b8 (SV_VL128); + *any = svptest_any (svptrue_b64 (), res); + *ptr = res; +} + +int +b8_b64_2 () +{ + svbool_t res = svptrue_pat_b8 (SV_VL128); + return svptest_any (svptrue_b64 (), res); +} + +void +b16_b8_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b16 (SV_VL32); + *any = svptest_any (svptrue_b8 (), res); + *ptr = res; +} + +int +b16_b8_2 () +{ + svbool_t res = svptrue_pat_b16 (SV_VL32); + return svptest_any (svptrue_b8 (), res); +} + +void +b16_b32_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b16 (SV_VL16); + *any = svptest_any (svptrue_b32 (), res); + *ptr = res; +} + +int +b16_b32_2 () +{ + svbool_t res = svptrue_pat_b16 (SV_VL16); + return svptest_any (svptrue_b32 (), res); +} + +void +b16_b64_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b16 (SV_VL64); + *any = svptest_any (svptrue_b64 (), res); + *ptr = res; +} + +int +b16_b64_2 () +{ + svbool_t res = svptrue_pat_b16 (SV_VL64); + return svptest_any (svptrue_b64 (), res); +} + +void +b32_b8_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b32 (SV_VL16); + *any = svptest_any (svptrue_b8 (), res); + *ptr = res; +} + +int +b32_b8_2 () +{ + svbool_t res = svptrue_pat_b32 (SV_VL16); + return svptest_any (svptrue_b8 (), res); +} + +void +b32_b16_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b32 (SV_VL6); + *any = svptest_any (svptrue_b16 (), res); + *ptr = res; +} + +int +b32_b16_2 () +{ + svbool_t res = svptrue_pat_b32 (SV_VL6); + return svptest_any (svptrue_b16 (), res); +} + +void +b32_b64_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b32 (SV_VL32); + *any = svptest_any (svptrue_b64 (), res); + *ptr = res; +} + +int +b32_b64_2 () +{ + svbool_t res = svptrue_pat_b32 (SV_VL32); + return svptest_any (svptrue_b64 (), res); +} + +void +b64_b8_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b64 (SV_VL7); + *any = svptest_any (svptrue_b8 (), res); + *ptr = res; +} + +int +b64_b8_2 () +{ + svbool_t res = svptrue_pat_b64 (SV_VL7); + return svptest_any (svptrue_b8 (), res); +} + +void +b64_b16_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b64 (SV_VL16); + *any = svptest_any (svptrue_b16 (), res); + *ptr = res; +} + +int +b64_b16_2 () +{ + svbool_t res = svptrue_pat_b64 (SV_VL16); + return svptest_any (svptrue_b16 (), res); +} + +void +b64_b32_1 (int *any, svbool_t *ptr) +{ + svbool_t res = svptrue_pat_b64 (SV_VL32); + *any = svptest_any (svptrue_b32 (), res); + *ptr = res; +} + +int +b64_b32_2 () +{ + svbool_t res = svptrue_pat_b64 (SV_VL32); + return svptest_any (svptrue_b32 (), res); +} + +/* { dg-final { scan-assembler-not {\tptrues\n} } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 48 } } */ +/* { dg-final { scan-assembler-times {\tptest\t} 24 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/qincb_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/qincb_1.c new file mode 100644 index 0000000..ba512f4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/qincb_1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** qincb_s32_s: +** sqincb x0, w0, all, mul #15 +** ret +*/ +uint64_t qincb_s32_s (int32_t x) { return svqincb (x, 15); } + +/* +** qincb_s32_z: +** sqincb x([0-9]+), w0, all, mul #15 +** uxtw x0, w\1 +** ret +*/ +uint64_t qincb_s32_z (int32_t x) { return (uint32_t) svqincb (x, 15); } + +/* +** qincb_u32_s: +** uqincb (w[0-9]+), all, mul #15 +** sxtw x0, \1 +** ret +*/ +uint64_t qincb_u32_s (uint32_t x) { return (int32_t) svqincb (x, 15); } + +/* +** qincb_u32_z: +** uqincb w0, all, mul #15 +** ret +*/ +uint64_t qincb_u32_z (uint32_t x) { return svqincb (x, 15); } + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/struct_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/struct_1.c new file mode 100644 index 0000000..50892c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/struct_1.c @@ -0,0 +1,16 @@ +#include <arm_sve.h> + +void +f (svint8x2_t *a, svint8x2_t *b) +{ + svint8_t *ptr; + svint8x2_t x = *a; + *a = *b; + a = &x; + (void) (a == b); + (void) (a != b); + (void) (a < b); + (void) (a > b); + (void) (a <= b); + (void) (a >= b); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_1.c new file mode 100644 index 0000000..1d5523e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int32_t x, int32_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svwhilele_b8 (x, y); + *any = svptest_last (svptrue_b8 (), res); + *ptr = res; +} + +int +test2 (int32_t x, int32_t y) +{ + svbool_t res = svwhilele_b8 (x, y); + return svptest_last (svptrue_b8 (), res); +} + +/* { dg-final { scan-assembler-times {\twhilele\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_10.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_10.c new file mode 100644 index 0000000..ca339c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_10.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilele_b32_u32 (-1, 0); +} + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_u64 (0x80000000, 0); +} + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_u64 (0x8000000000000001ULL, 0x7ffffffffffffffeULL); +} + +/* { dg-final { scan-assembler-times {\tpfalse\tp[0-7]\.b\n} 3 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_2.c new file mode 100644 index 0000000..0208460 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int32_t x, int32_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svwhilele_b16 (x, y); + *any = svptest_last (svptrue_b16 (), res); + *ptr = res; +} + +int +test2 (int32_t x, int32_t y) +{ + svbool_t res = svwhilele_b16 (x, y); + return svptest_last (svptrue_b16 (), res); +} + +/* { dg-final { scan-assembler-times {\twhilele\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_3.c new file mode 100644 index 0000000..4a1045c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_3.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int32_t x, int32_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svwhilele_b32 (x, y); + *any = svptest_last (svptrue_b32 (), res); + *ptr = res; +} + +int +test2 (int32_t x, int32_t y) +{ + svbool_t res = svwhilele_b32 (x, y); + return svptest_last (svptrue_b32 (), res); +} + +/* { dg-final { scan-assembler-times {\twhilele\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_4.c new file mode 100644 index 0000000..f6fb0d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_4.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (int32_t x, int32_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svwhilele_b64 (x, y); + *any = svptest_last (svptrue_b64 (), res); + *ptr = res; +} + +int +test2 (int32_t x, int32_t y) +{ + svbool_t res = svwhilele_b64 (x, y); + return svptest_last (svptrue_b64 (), res); +} + +/* { dg-final { scan-assembler-times {\twhilele\t} 2 } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_5.c new file mode 100644 index 0000000..ada958b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_5.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilele_b32_s32 (-8, -8); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.[bhsd], vl1\n} } } */ + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_s64 (-1, 1); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, vl3\n} } } */ + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_s32 (0x7ffffffb, 0x7fffffff); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, vl5\n} } } */ + +void +test4 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_s64 (svcntb (), svcntb () + 6); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.b, vl7\n} } } */ + +void +test5 (svbool_t *ptr) +{ + *ptr = svwhilele_b64_s64 (0, 1); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.d, vl2\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_6.c new file mode 100644 index 0000000..00d92ba --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_6.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilele_b32_s32 (-8, -9); +} + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_s64 (50, -1); +} + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_s32 (0x7ffffffb, 0x80000000); +} + +void +test4 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_s64 (svcntb (), 15); +} + +void +test5 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_s64 (svcntb (), svcntw ()); +} + +/* { dg-final { scan-assembler-times {\tpfalse\tp[0-7]\.b\n} 5 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_7.c new file mode 100644 index 0000000..92488f5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_7.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilel[et]\t} } } */ +/* { dg-final { scan-assembler-not {\tpfalse\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_s32 (-svcnth (), svcnth () - 1); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.b, all\n} } } */ + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_s64 (1, svcntw () * 2); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, all\n} } } */ + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilele_b32_s32 (svcntd (), svcntw () + svcntd () - 1); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.s, all\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_9.c new file mode 100644 index 0000000..e7f81a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_9.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilele_b32_u32 (1, 3); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.s, vl3\n} } } */ + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilele_b16_u64 (svcntd (), svcntd () + 5); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, vl6\n} } } */ + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilele_b8_u32 (0x7ffffffb, 0x80000002); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.b, vl8\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_1.c new file mode 100644 index 0000000..5c8f97e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_1.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilelt_b32_s32 (-8, -7); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.[bhsd], vl1\n} } } */ + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilelt_b16_s64 (-1, 2); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, vl3\n} } } */ + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilelt_b16_s32 (0x7ffffffa, 0x7fffffff); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, vl5\n} } } */ + +void +test4 (svbool_t *ptr) +{ + *ptr = svwhilelt_b8_s64 (svcntb (), svcntb () + 7); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.b, vl7\n} } } */ + +void +test5 (svbool_t *ptr) +{ + *ptr = svwhilelt_b64_s64 (0, 2); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.d, vl2\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_2.c new file mode 100644 index 0000000..2be3a5b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_2.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilele\t} } } */ +/* { dg-final { scan-assembler-not {\twhilelt\t} } } */ +/* { dg-final { scan-assembler-not {\tptrue\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilelt_b32_s32 (0, 0); +} + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilelt_b16_s64 (50, -1); +} + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilelt_b16_s32 (0x7ffffffb, 0x80000000); +} + +void +test4 (svbool_t *ptr) +{ + *ptr = svwhilelt_b8_s64 (svcntb (), svcntb ()); +} + +void +test5 (svbool_t *ptr) +{ + *ptr = svwhilelt_b8_s64 (svcntb (), svcntw ()); +} + +/* { dg-final { scan-assembler-times {\tpfalse\tp[0-7]\.b\n} 5 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_3.c new file mode 100644 index 0000000..650b265 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_3.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +/* { dg-final { scan-assembler-not {\twhilel[et]\t} } } */ +/* { dg-final { scan-assembler-not {\tpfalse\t} } } */ + +void +test1 (svbool_t *ptr) +{ + *ptr = svwhilelt_b8_s32 (-svcnth (), svcnth ()); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.b, all\n} } } */ + +void +test2 (svbool_t *ptr) +{ + *ptr = svwhilelt_b16_s64 (0, svcntw () * 2); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h, all\n} } } */ + +void +test3 (svbool_t *ptr) +{ + *ptr = svwhilelt_b32_s32 (svcntd (), svcntw () + svcntd ()); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.s, all\n} } } */ |