diff options
Diffstat (limited to 'gcc/config/riscv/riscv.cc')
| -rw-r--r-- | gcc/config/riscv/riscv.cc | 465 |
1 files changed, 413 insertions, 52 deletions
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d5de76c..63404d3 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -740,6 +740,7 @@ static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *); static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); static tree riscv_handle_rvv_vector_bits_attribute (tree *, tree, tree, int, bool *); +static tree riscv_handle_rvv_vls_cc_attribute (tree *, tree, tree, int, bool *); /* Defining target-specific uses of __attribute__. */ static const attribute_spec riscv_gnu_attributes[] = @@ -763,6 +764,8 @@ static const attribute_spec riscv_gnu_attributes[] = standard vector calling convention variant. Syntax: __attribute__((riscv_vector_cc)). */ {"riscv_vector_cc", 0, 0, false, true, true, true, NULL, NULL}, + {"riscv_vls_cc", 0, 1, false, true, true, true, + riscv_handle_rvv_vls_cc_attribute, NULL}, /* This attribute is used to declare a new type, to appoint the exactly bits size of the type. For example: @@ -790,6 +793,8 @@ static const attribute_spec riscv_attributes[] = standard vector calling convention variant. Syntax: [[riscv::vector_cc]]. */ {"vector_cc", 0, 0, false, true, true, true, NULL, NULL}, + {"vls_cc", 0, 1, false, true, true, true, riscv_handle_rvv_vls_cc_attribute, + NULL}, /* This attribute is used to declare a new type, to appoint the exactly bits size of the type. For example: @@ -3723,6 +3728,12 @@ riscv_legitimize_move (machine_mode mode, rtx dest, rtx src) riscv_vector::emit_vec_extract (result, v, gen_int_mode (index + i, Pmode)); + /* The low-part must be zero-extended when ELEN == 32 and + mode == 64. */ + if (num == 2 && i == 0) + emit_insn (gen_extend_insn (int_reg, result, mode, smode, + true)); + if (i == 1) { if (UNITS_PER_WORD < mode_size) @@ -5872,11 +5883,12 @@ typedef struct { floating-point registers. */ static int -riscv_flatten_aggregate_field (const_tree type, - riscv_aggregate_field fields[2], +riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field *fields, int n, HOST_WIDE_INT offset, - bool ignore_zero_width_bit_field_p) + bool ignore_zero_width_bit_field_p, + bool vls_p = false, unsigned abi_vlen = 0) { + int max_aggregate_field = vls_p ? 8 : 2; switch (TREE_CODE (type)) { case RECORD_TYPE: @@ -5903,9 +5915,9 @@ riscv_flatten_aggregate_field (const_tree type, else { HOST_WIDE_INT pos = offset + int_byte_position (f); - n = riscv_flatten_aggregate_field (TREE_TYPE (f), - fields, n, pos, - ignore_zero_width_bit_field_p); + n = riscv_flatten_aggregate_field ( + TREE_TYPE (f), fields, n, pos, ignore_zero_width_bit_field_p, + vls_p, abi_vlen); } if (n < 0) return -1; @@ -5915,13 +5927,14 @@ riscv_flatten_aggregate_field (const_tree type, case ARRAY_TYPE: { HOST_WIDE_INT n_elts; - riscv_aggregate_field subfields[2]; + riscv_aggregate_field subfields[8]; tree index = TYPE_DOMAIN (type); tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type)); - int n_subfields = riscv_flatten_aggregate_field (TREE_TYPE (type), - subfields, 0, offset, - ignore_zero_width_bit_field_p); - + int n_subfields + = riscv_flatten_aggregate_field (TREE_TYPE (type), subfields, 0, + offset, + ignore_zero_width_bit_field_p, vls_p, + abi_vlen); /* Can't handle incomplete types nor sizes that are not fixed. */ if (n_subfields <= 0 || !COMPLETE_TYPE_P (type) @@ -5941,7 +5954,7 @@ riscv_flatten_aggregate_field (const_tree type, for (HOST_WIDE_INT i = 0; i < n_elts; i++) for (int j = 0; j < n_subfields; j++) { - if (n >= 2) + if (n >= max_aggregate_field) return -1; fields[n] = subfields[j]; @@ -5973,18 +5986,36 @@ riscv_flatten_aggregate_field (const_tree type, } default: - if (n < 2 - && ((SCALAR_FLOAT_TYPE_P (type) - && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_FP_ARG) - || (INTEGRAL_TYPE_P (type) - && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= UNITS_PER_WORD))) + poly_uint64 mode_size = GET_MODE_SIZE (TYPE_MODE (type)); + if (vls_p) { - fields[n].type = type; - fields[n].offset = offset; - return n + 1; + gcc_assert (abi_vlen != 0); + if (n < max_aggregate_field + && (VECTOR_TYPE_P (type) && mode_size.is_constant () + && (mode_size.to_constant () <= abi_vlen * 8))) + { + fields[n].type = type; + fields[n].offset = offset; + return n + 1; + } + else + return -1; } else - return -1; + { + if (n < max_aggregate_field + && ((SCALAR_FLOAT_TYPE_P (type) + && mode_size.to_constant () <= UNITS_PER_FP_ARG) + || (INTEGRAL_TYPE_P (type) + && mode_size.to_constant () <= UNITS_PER_WORD))) + { + fields[n].type = type; + fields[n].offset = offset; + return n + 1; + } + else + return -1; + } } } @@ -5993,14 +6024,16 @@ riscv_flatten_aggregate_field (const_tree type, static int riscv_flatten_aggregate_argument (const_tree type, - riscv_aggregate_field fields[2], - bool ignore_zero_width_bit_field_p) + riscv_aggregate_field *fields, + bool ignore_zero_width_bit_field_p, + bool vls_p = false, unsigned abi_vlen = 0) { if (!type || TREE_CODE (type) != RECORD_TYPE) return -1; return riscv_flatten_aggregate_field (type, fields, 0, 0, - ignore_zero_width_bit_field_p); + ignore_zero_width_bit_field_p, vls_p, + abi_vlen); } /* See whether TYPE is a record whose fields should be returned in one or @@ -6163,18 +6196,22 @@ riscv_pass_vls_aggregate_in_gpr (struct riscv_arg_info *info, machine_mode mode, return gen_rtx_PARALLEL (mode, gen_rtvec (1, x)); } +static const predefined_function_abi & +riscv_fntype_abi_1 (const_tree fntype, bool check_only); + /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ void riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype, - rtx, tree, int) + rtx, tree, int, bool check_only) { memset (cum, 0, sizeof (*cum)); if (fntype) - cum->variant_cc = (riscv_cc) fntype_abi (fntype).id (); + cum->variant_cc = + (riscv_cc) riscv_fntype_abi_1 (fntype, check_only).id (); else cum->variant_cc = RISCV_CC_BASE; } @@ -6197,7 +6234,7 @@ riscv_hard_regno_nregs (unsigned int regno, machine_mode mode); static rtx riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, - machine_mode mode, bool return_p) + machine_mode mode, bool return_p, bool vls_p = false) { gcc_assert (riscv_v_ext_mode_p (mode)); @@ -6233,8 +6270,9 @@ riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, int arg_reg_end = V_ARG_LAST - V_REG_FIRST; int aligned_reg_start = ROUND_UP (arg_reg_start, LMUL); - /* For scalable data and scalable tuple return value. */ - if (return_p) + /* For scalable data and scalable tuple return value. + For VLS CC, we may pass struct like tuple, so need defer the handling. */ + if (return_p && !vls_p) return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST); /* Iterate through the USED_VRS array to find vector register groups that have @@ -6271,6 +6309,224 @@ riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, return NULL_RTX; } + +#define RISCV_ALL_VALID_ABI_VLEN(F) \ + F (32) \ + F (64) \ + F (128) \ + F (256) \ + F (512) \ + F (1024) \ + F (2048) \ + F (4096) \ + F (8192) \ + F (16384) + +/* Return true if CC is a variant of VLS CC. */ + +static bool +riscv_vls_cc_p (riscv_cc cc) +{ + switch (cc) + { +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \ + case RISCV_CC_VLS_V_##ABI_VLEN: + RISCV_ALL_VALID_ABI_VLEN (VLS_CC_ABI_VLEN_CASE) + +#undef VLS_CC_ABI_VLEN_CASE + return true; + default: + return false; + } +} + +/* Get ABI_VLEN from cc. */ + +static unsigned int +riscv_get_cc_abi_vlen (riscv_cc cc) +{ + switch (cc) + { +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \ + case RISCV_CC_VLS_V_##ABI_VLEN: \ + return ABI_VLEN; + RISCV_ALL_VALID_ABI_VLEN (VLS_CC_ABI_VLEN_CASE) + +#undef VLS_CC_ABI_VLEN_CASE + default: + gcc_unreachable (); + } +} + +/* Return true if ABI_VLEN is a valid for VLS_CC. */ + +static bool +riscv_valid_abi_vlen_vls_cc_p (unsigned abi_vlen) +{ + switch (abi_vlen) + { +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \ + case ABI_VLEN: + RISCV_ALL_VALID_ABI_VLEN (VLS_CC_ABI_VLEN_CASE) + +#undef VLS_CC_ABI_VLEN_CASE + return true; + default: + return false; + } +} + +static riscv_cc +riscv_get_riscv_cc_by_abi_vlen (unsigned abi_vlen) +{ + switch (abi_vlen) + { +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \ + case ABI_VLEN: \ + return RISCV_CC_VLS_V_##ABI_VLEN; + RISCV_ALL_VALID_ABI_VLEN (VLS_CC_ABI_VLEN_CASE) + +#undef VLS_CC_ABI_VLEN_CASE + default: + gcc_unreachable (); + } +} + +/* Get a VLS type has same size as MODE in ABI_VLEN, but element is always + in integer mode. */ + +static machine_mode +riscv_get_vls_container_type (machine_mode mode, unsigned abi_vlen) +{ + machine_mode element_mode = GET_MODE_INNER (mode); + unsigned int mode_size = GET_MODE_SIZE (mode).to_constant (); + unsigned int lmul = ROUND_UP (mode_size * 8, abi_vlen) / abi_vlen; + + /* Always use integer mode to pass to simplify the logic - we allow pass + unsupported vector type in vector register, e.g. float16x4_t even no vector + fp16 support. */ + switch (GET_MODE_SIZE (element_mode).to_constant ()) + { + case 1: + element_mode = QImode; + break; + case 2: + element_mode = HImode; + break; + case 4: + element_mode = SImode; + break; + case 8: + element_mode = DImode; + break; + default: + gcc_unreachable (); + } + + scalar_mode smode = as_a<scalar_mode> (element_mode); + return get_lmul_mode (smode, lmul).require (); +} + +/* Pass VLS type argument in vector argument register. */ + +static rtx +riscv_pass_vls_in_vr (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, + machine_mode mode, bool return_p) +{ + gcc_assert (riscv_v_ext_vls_mode_p (mode)); + + unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc); + unsigned int mode_size = GET_MODE_SIZE (mode).to_constant (); + unsigned int lmul = ROUND_UP (mode_size * 8, abi_vlen) / abi_vlen; + + /* Put into memory if it need more than 8 registers (> LMUL 8). */ + if (lmul > 8) + return NULL_RTX; + + machine_mode vla_mode = riscv_get_vls_container_type (mode, abi_vlen); + rtx reg = riscv_get_vector_arg (info, cum, vla_mode, + return_p, /* vls_p */ true); + + /* Can't get vector register to pass, pass by memory. */ + if (!reg) + return NULL_RTX; + + PUT_MODE (reg, mode); + + return reg; +} + +/* Pass aggregate with VLS type argument in vector argument registers. */ + +static rtx +riscv_pass_aggregate_in_vr (struct riscv_arg_info *info, + const CUMULATIVE_ARGS *cum, const_tree type, + bool return_p) +{ + riscv_aggregate_field fields[8]; + unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc); + int i; + int n = riscv_flatten_aggregate_argument (type, fields, true, + /* vls_p */ true, abi_vlen); + + if (n == -1) + return NULL_RTX; + + /* Check all field has same size. */ + unsigned int mode_size + = GET_MODE_SIZE (TYPE_MODE (fields[0].type)).to_constant (); + for (int i = 1; i < n; i++) + if (GET_MODE_SIZE (TYPE_MODE (fields[i].type)).to_constant () != mode_size) + return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg. */ + + /* Check total size is <= abi_vlen * 8, we use up to 8 vector register to + pass argument. */ + if (mode_size * 8 > abi_vlen) + return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg. */ + + /* Backup cum->used_vrs since we will defer the update until + riscv_function_arg_advance. */ + CUMULATIVE_ARGS local_cum; + memcpy (&local_cum, cum, sizeof (local_cum)); + + unsigned num_vrs = 0; + + /* Allocate vector registers for the arguments. */ + rtx expr_list[8]; + for (i = 0; i < n; i++) + { + machine_mode mode = TYPE_MODE (fields[i].type); + machine_mode vla_mode = riscv_get_vls_container_type (mode, abi_vlen); + /* Use riscv_get_vector_arg with VLA type to simplify the calling + convention implementation. */ + rtx reg + = riscv_get_vector_arg (info, &local_cum, vla_mode, + return_p, /* vls_p */true); + + /* Can't get vector register to pass, pass by memory. */ + if (!reg) + return NULL_RTX; + + PUT_MODE (reg, mode); + + expr_list[i] + = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (fields[i].offset)); + + num_vrs += info->num_vrs; + + /* Set the corresponding register in USED_VRS to used status. */ + for (unsigned int i = 0; i < info->num_vrs; i++) + { + gcc_assert (!local_cum.used_vrs[info->vr_offset + i]); + local_cum.used_vrs[info->vr_offset + i] = true; + } + } + + info->num_vrs = num_vrs; + + return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (n, expr_list)); +} + /* Fill INFO with information about a single argument, and return an RTL pattern to pass or return the argument. Return NULL_RTX if argument cannot pass or return in registers, then the argument may be passed by reference or @@ -6363,7 +6619,17 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode)) return riscv_get_vector_arg (info, cum, mode, return_p); - /* For vls mode aggregated in gpr. */ + if (riscv_vls_cc_p (cum->variant_cc)) + { + if (riscv_v_ext_vls_mode_p (mode)) + return riscv_pass_vls_in_vr (info, cum, mode, return_p); + + rtx ret = riscv_pass_aggregate_in_vr (info, cum, type, return_p); + if (ret) + return ret; + } + + /* For vls mode aggregated in gpr (for non-VLS-CC). */ if (riscv_v_ext_vls_mode_p (mode)) return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base); } @@ -6420,7 +6686,8 @@ riscv_function_arg_advance (cumulative_args_t cum_v, cum->used_vrs[info.vr_offset + i] = true; } - if ((info.num_vrs > 0 || info.num_mrs > 0) && cum->variant_cc != RISCV_CC_V) + if ((info.num_vrs > 0 || info.num_mrs > 0) && cum->variant_cc != RISCV_CC_V + && !riscv_vls_cc_p (cum->variant_cc)) { error ("RVV type %qT cannot be passed to an unprototyped function", arg.type); @@ -6463,7 +6730,8 @@ riscv_function_value (const_tree ret_type, const_tree fn_decl_or_type, { const_tree fntype = TREE_CODE (fn_decl_or_type) == FUNCTION_DECL ? TREE_TYPE (fn_decl_or_type) : fn_decl_or_type; - riscv_init_cumulative_args (&args, fntype, NULL_RTX, NULL_TREE, 0); + riscv_init_cumulative_args (&args, fntype, NULL_RTX, NULL_TREE, 0, + /* check_only */true); } else memset (&args, 0, sizeof args); @@ -6532,14 +6800,20 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) /* Implement TARGET_RETURN_IN_MEMORY. */ static bool -riscv_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) +riscv_return_in_memory (const_tree type, const_tree fntype) { CUMULATIVE_ARGS args; + + if (fntype) + riscv_init_cumulative_args (&args, fntype, NULL_RTX, NULL_TREE, 0, + /* check_only */true); + else + /* The rules for returning in memory are the same as for passing the + first named argument by reference. */ + memset (&args, 0, sizeof args); + cumulative_args_t cum = pack_cumulative_args (&args); - /* The rules for returning in memory are the same as for passing the - first named argument by reference. */ - memset (&args, 0, sizeof args); function_arg_info arg (const_cast<tree> (type), /*named=*/true); return riscv_pass_by_reference (cum, arg); } @@ -6583,9 +6857,9 @@ riscv_setup_incoming_varargs (cumulative_args_t cum, /* Return the descriptor of the Standard Vector Calling Convention Variant. */ static const predefined_function_abi & -riscv_v_abi () +riscv_v_abi (riscv_cc abi) { - predefined_function_abi &v_abi = function_abis[RISCV_CC_V]; + predefined_function_abi &v_abi = function_abis[abi]; if (!v_abi.initialized_p ()) { HARD_REG_SET full_reg_clobbers @@ -6595,7 +6869,7 @@ riscv_v_abi () CLEAR_HARD_REG_BIT (full_reg_clobbers, regno); for (int regno = V_REG_FIRST + 24; regno <= V_REG_FIRST + 31; regno += 1) CLEAR_HARD_REG_BIT (full_reg_clobbers, regno); - v_abi.initialize (RISCV_CC_V, full_reg_clobbers); + v_abi.initialize (abi, full_reg_clobbers); } return v_abi; } @@ -6756,13 +7030,14 @@ riscv_validate_vector_type (const_tree type, const char *hint) RISC-V V registers. */ static bool -riscv_return_value_is_vector_type_p (const_tree fntype) +riscv_return_value_is_vector_type_p (const_tree fntype, bool check_only) { tree return_type = TREE_TYPE (fntype); if (riscv_vector_type_p (return_type)) { - riscv_validate_vector_type (return_type, "return type"); + if (!check_only) + riscv_validate_vector_type (return_type, "return type"); return true; } else @@ -6773,7 +7048,7 @@ riscv_return_value_is_vector_type_p (const_tree fntype) RISC-V V registers. */ static bool -riscv_arguments_is_vector_type_p (const_tree fntype) +riscv_arguments_is_vector_type_p (const_tree fntype, bool check_only) { for (tree chain = TYPE_ARG_TYPES (fntype); chain && chain != void_list_node; chain = TREE_CHAIN (chain)) @@ -6781,7 +7056,8 @@ riscv_arguments_is_vector_type_p (const_tree fntype) tree arg_type = TREE_VALUE (chain); if (riscv_vector_type_p (arg_type)) { - riscv_validate_vector_type (arg_type, "argument type"); + if (!check_only) + riscv_validate_vector_type (arg_type, "argument type"); return true; } } @@ -6792,14 +7068,15 @@ riscv_arguments_is_vector_type_p (const_tree fntype) /* Return true if FUNC is a riscv_vector_cc function. For more details please reference the below link. https://github.com/riscv-non-isa/riscv-c-api-doc/pull/67 */ + static bool -riscv_vector_cc_function_p (const_tree fntype) +riscv_vector_cc_function_p (const_tree fntype, bool check_only) { tree attr = TYPE_ATTRIBUTES (fntype); bool vector_cc_p = lookup_attribute ("vector_cc", attr) != NULL_TREE || lookup_attribute ("riscv_vector_cc", attr) != NULL_TREE; - if (vector_cc_p && !TARGET_VECTOR) + if (vector_cc_p && !TARGET_VECTOR && !check_only) error_at (input_location, "function attribute %qs requires the V ISA extension", "riscv_vector_cc"); @@ -6807,26 +7084,91 @@ riscv_vector_cc_function_p (const_tree fntype) return vector_cc_p; } -/* Implement TARGET_FNTYPE_ABI. */ +/* Return the riscv_cc value according to the attribute arguments. + If the attribute arguments are invalid, return RISCV_CC_UNKNOWN + and emit an error message. */ + +static riscv_cc +riscv_get_vls_cc_attr (const_tree args, bool check_only = false) +{ + /* Default ABI_VLEN is 128. */ + int abi_vlen = 128; + + if (args && TREE_CODE (args) == TREE_LIST) + { + tree vlen_arg = TREE_VALUE (args); + if (vlen_arg && TREE_CODE (vlen_arg) == INTEGER_CST) + abi_vlen = TREE_INT_CST_LOW (vlen_arg); + } + + if (!riscv_valid_abi_vlen_vls_cc_p (abi_vlen) && !check_only) + { + error_at (input_location, + "unsupported %<ABI_VLEN%> value %d for %qs attribute;" + "%<ABI_VLEN must%> be in the range [32, 16384] and must be " + "a power of 2", + abi_vlen, "riscv_vls_cc"); + return RISCV_CC_UNKNOWN; + } + + return riscv_get_riscv_cc_by_abi_vlen (abi_vlen); +} + +/* Return true if FUNC is a riscv_vector_cc function. + For more details please reference the below link. + https://github.com/riscv-non-isa/riscv-c-api-doc/pull/67 */ +static riscv_cc +riscv_vls_cc_function_abi (const_tree fntype, bool check_only) +{ + tree attr = TYPE_ATTRIBUTES (fntype); + bool vls_cc_p = lookup_attribute ("vls_cc", attr) != NULL_TREE + || lookup_attribute ("riscv_vls_cc", attr) != NULL_TREE; + + if (!vls_cc_p) + return RISCV_CC_UNKNOWN; + + if (!TARGET_VECTOR && !check_only) + error_at (input_location, + "function attribute %qs requires the vector ISA extension", + "riscv_vls_cc"); + + tree args = TREE_VALUE (attr); + return riscv_get_vls_cc_attr (args); +} + +/* Implemention of TARGET_FNTYPE_ABI, but one extra parameter `check_only` + to suppress warning message. */ static const predefined_function_abi & -riscv_fntype_abi (const_tree fntype) +riscv_fntype_abi_1 (const_tree fntype, bool check_only) { /* Implement the vector calling convention. For more details please reference the below link. https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 */ bool validate_v_abi_p = false; - validate_v_abi_p |= riscv_return_value_is_vector_type_p (fntype); - validate_v_abi_p |= riscv_arguments_is_vector_type_p (fntype); - validate_v_abi_p |= riscv_vector_cc_function_p (fntype); + validate_v_abi_p |= riscv_return_value_is_vector_type_p (fntype, check_only); + validate_v_abi_p |= riscv_arguments_is_vector_type_p (fntype, check_only); + validate_v_abi_p |= riscv_vector_cc_function_p (fntype, check_only); if (validate_v_abi_p) - return riscv_v_abi (); + return riscv_v_abi (RISCV_CC_V); + + riscv_cc abi = riscv_vls_cc_function_abi (fntype, check_only); + if (abi != RISCV_CC_UNKNOWN) + return riscv_v_abi (abi); return default_function_abi; } +/* Implement TARGET_FNTYPE_ABI. */ + +static const predefined_function_abi & +riscv_fntype_abi (const_tree fntype) +{ + return riscv_fntype_abi_1 (fntype, /* check_only */true); +} + /* Return riscv calling convention of call_insn. */ riscv_cc get_riscv_cc (const rtx use) @@ -6916,6 +7258,25 @@ riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args, } static tree +riscv_handle_rvv_vls_cc_attribute (tree *, tree name, tree args, + ATTRIBUTE_UNUSED int flags, + bool *no_add_attrs) +{ + bool vls_cc_p = is_attribute_p ("vls_cc", name) + || is_attribute_p ("riscv_vls_cc", name); + + if (!vls_cc_p) + return NULL_TREE; + + riscv_cc cc = riscv_get_vls_cc_attr (args); + + if (cc == RISCV_CC_UNKNOWN) + *no_add_attrs = true; + + return NULL_TREE; +} + +static tree riscv_handle_rvv_vector_bits_attribute (tree *node, tree name, tree args, ATTRIBUTE_UNUSED int flags, bool *no_add_attrs) @@ -11082,7 +11443,7 @@ riscv_asm_output_variant_cc (FILE *stream, const tree decl, const char *name) if (TREE_CODE (decl) == FUNCTION_DECL) { riscv_cc cc = (riscv_cc) fndecl_abi (decl).id (); - if (cc == RISCV_CC_V) + if (cc == RISCV_CC_V || riscv_vls_cc_p (cc)) { fprintf (stream, "\t.variant_cc\t"); assemble_name (stream, name); |
