Skip to content

Commit

Permalink
RISC-V: Handle multi-lib path correclty for linux
Browse files Browse the repository at this point in the history
RISC-V Linux encodes the ABI into the path, so in theory, we can only use that
to select multi-lib paths, and no way to use different multi-lib paths between
`rv32i/ilp32` and `rv32ima/ilp32`, we'll mapping both to `/lib/ilp32`.

It's hard to do that with GCC's builtin multi-lib selection mechanism; builtin
mechanism did the option string compare and then enumerate all possible reuse
rules during the build time. However, it's impossible to RISC-V; we have a huge
number of combinations of `-march`, so implementing a customized multi-lib
selection becomes the only solution.

Multi-lib configuration is only used for determines which ISA should be used
when compiling the corresponding ABI variant after this patch.

During the multi-lib selection stage, only consider -mabi as the only key to
select the multi-lib path.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc (riscv_select_multilib_by_abi): New.
	(riscv_select_multilib): New.
	(riscv_compute_multilib): Extract logic to riscv_select_multilib and
	also handle select_by_abi.
	* config/riscv/elf.h (RISCV_USE_CUSTOMISED_MULTI_LIB): Change it
	to select_by_abi_arch_cmodel from 1.
	* config/riscv/linux.h (RISCV_USE_CUSTOMISED_MULTI_LIB): Define.
	* config/riscv/riscv-opts.h (enum riscv_multilib_select_kind): New.
  • Loading branch information
kito-cheng committed May 8, 2023
1 parent 31c70a7 commit 17d683d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 41 deletions.
128 changes: 88 additions & 40 deletions gcc/common/config/riscv/riscv-common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1441,9 +1441,6 @@ riscv_multi_lib_check (int argc ATTRIBUTE_UNUSED,
return "";
}

/* We only override this in bare-metal toolchain. */
#ifdef RISCV_USE_CUSTOMISED_MULTI_LIB

/* Find last switch with the prefix, options are take last one in general,
return NULL if not found, and return the option value if found, it could
return empty string if the option has no value. */
Expand Down Expand Up @@ -1597,6 +1594,68 @@ riscv_check_conds (
return match_score + ok_count * 100;
}

static const char *
riscv_select_multilib_by_abi (
const std::string &riscv_current_arch_str,
const std::string &riscv_current_abi_str,
const riscv_subset_list *subset_list, const struct switchstr *switches,
int n_switches, const std::vector<riscv_multi_lib_info_t> &multilib_infos)
{
for (size_t i = 0; i < multilib_infos.size (); ++i)
if (riscv_current_abi_str == multilib_infos[i].abi_str)
return xstrdup (multilib_infos[i].path.c_str ());

return NULL;
}

static const char *
riscv_select_multilib (
const std::string &riscv_current_arch_str,
const std::string &riscv_current_abi_str,
const riscv_subset_list *subset_list, const struct switchstr *switches,
int n_switches, const std::vector<riscv_multi_lib_info_t> &multilib_infos)
{
int match_score = 0;
int max_match_score = 0;
int best_match_multi_lib = -1;
/* Try to decision which set we should used. */
/* We have 3 level decision tree here, ABI, check input arch/ABI must
be superset of multi-lib arch, and other rest option checking. */
for (size_t i = 0; i < multilib_infos.size (); ++i)
{
/* Check ABI is same first. */
if (riscv_current_abi_str != multilib_infos[i].abi_str)
continue;

/* Found a potential compatible multi-lib setting!
Calculate the match score. */
match_score = subset_list->match_score (multilib_infos[i].subset_list);

/* Checking other cond in the multi-lib setting. */
match_score = riscv_check_conds (switches, n_switches, match_score,
multilib_infos[i].conds);

/* Record highest match score multi-lib setting. */
if (match_score > max_match_score)
{
best_match_multi_lib = i;
max_match_score = match_score;
}
}

if (best_match_multi_lib == -1)
{
riscv_no_matched_multi_lib = true;
return NULL;
}
else
return xstrdup (multilib_infos[best_match_multi_lib].path.c_str ());
}

#ifndef RISCV_USE_CUSTOMISED_MULTI_LIB
#define RISCV_USE_CUSTOMISED_MULTI_LIB select_by_builtin
#endif

/* Implement TARGET_COMPUTE_MULTILIB. */
static const char *
riscv_compute_multilib (
Expand All @@ -1609,6 +1668,11 @@ riscv_compute_multilib (
const char *multilib_exclusions ATTRIBUTE_UNUSED,
const char *multilib_reuse ATTRIBUTE_UNUSED)
{
enum riscv_multilib_select_kind select_kind = RISCV_USE_CUSTOMISED_MULTI_LIB;

if (select_kind == select_by_builtin)
return multilib_dir;

const char *p;
const char *this_path;
size_t this_path_len;
Expand Down Expand Up @@ -1672,7 +1736,13 @@ riscv_compute_multilib (
}

this_path_len = p - this_path;
multilib_info.path = std::string (this_path, this_path_len);
const char *multi_os_dir_pos
= (const char *) memchr (this_path, ':', this_path_len);
if (multi_os_dir_pos)
multilib_info.path
= std::string (this_path, multi_os_dir_pos - this_path);
else
multilib_info.path = std::string (this_path, this_path_len);

option_conds.clear ();
/* Pasrse option check list into vector<string>.
Expand Down Expand Up @@ -1707,48 +1777,26 @@ riscv_compute_multilib (
p++;
}

int match_score = 0;
int max_match_score = 0;
int best_match_multi_lib = -1;
/* Try to decision which set we should used. */
/* We have 3 level decision tree here, ABI, check input arch/ABI must
be superset of multi-lib arch, and other rest option checking. */
for (size_t i = 0; i < multilib_infos.size (); ++i)
switch (select_kind)
{
/* Check ABI is same first. */
if (riscv_current_abi_str != multilib_infos[i].abi_str)
continue;

/* Found a potential compatible multi-lib setting!
Calculate the match score. */
match_score = subset_list->match_score (multilib_infos[i].subset_list);

/* Checking other cond in the multi-lib setting. */
match_score = riscv_check_conds (switches,
n_switches,
match_score,
multilib_infos[i].conds);

/* Record highest match score multi-lib setting. */
if (match_score > max_match_score)
{
best_match_multi_lib = i;
max_match_score = match_score;
}
}

if (best_match_multi_lib == -1)
{
riscv_no_matched_multi_lib = true;
return multilib_dir;
case select_by_abi:
return riscv_select_multilib (riscv_current_arch_str,
riscv_current_abi_str, subset_list,
switches, n_switches, multilib_infos);
case select_by_abi_arch_cmodel:
return riscv_select_multilib_by_abi (riscv_current_arch_str,
riscv_current_abi_str, subset_list,
switches, n_switches,
multilib_infos);
case select_by_builtin:
gcc_unreachable ();
default:
gcc_unreachable ();
}
else
return xstrdup (multilib_infos[best_match_multi_lib].path.c_str ());
}

#undef TARGET_COMPUTE_MULTILIB
#define TARGET_COMPUTE_MULTILIB riscv_compute_multilib
#endif

vec<const char *>
riscv_get_valid_option_values (int option_code,
Expand Down
2 changes: 1 addition & 1 deletion gcc/config/riscv/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ along with GCC; see the file COPYING3. If not see
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtend%O%s"

#define RISCV_USE_CUSTOMISED_MULTI_LIB 1
#define RISCV_USE_CUSTOMISED_MULTI_LIB select_by_abi_arch_cmodel
2 changes: 2 additions & 0 deletions gcc/config/riscv/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@ along with GCC; see the file COPYING3. If not see
"/usr/lib" XLEN_SPEC "/" ABI_SPEC "/ " \
"/lib/ " \
"/usr/lib/ "

#define RISCV_USE_CUSTOMISED_MULTI_LIB select_by_abi
9 changes: 9 additions & 0 deletions gcc/config/riscv/riscv-opts.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ enum riscv_autovec_lmul_enum {
RVV_M8 = 8
};

enum riscv_multilib_select_kind {
/* Select multilib by builtin way. */
select_by_builtin,
/* Select multilib by ABI, arch and code model. */
select_by_abi_arch_cmodel,
/* Select multilib by ABI only. */
select_by_abi,
};

#define MASK_ZICSR (1 << 0)
#define MASK_ZIFENCEI (1 << 1)

Expand Down

0 comments on commit 17d683d

Please sign in to comment.