From: Yunze Zhu <yunze...@linux.alibaba.com>

Currently when choosing multilib set for target like 
march=rv32imaf_zca/mabi=ilp32,
gnu toolchain reports "Cannot find suitable multilib set".
This is because in current dependent extension zca implies c when has 
combinations of extensions: Zca, F_Zca_Zcf or FD_Zca_Zcf_Zcd,
and f_zca is not one of these combinations and therefore extension c can not be 
implied,
and multilib set march=rv32imac/mabi=ilp32 cannot be selected.
The most accurate method to fix this problem is changing multilib in 
MULTILIB_REQUIRED: march=rv32imac/mabi=ilp32
to an equivalent one: march=rv32ima_zca/mabi=ilp32.
However, this method may cause compatibility issues with multilib path in 
previos toolchain.
There is an alternative method that add an extra check in multilib selection 
functions,
which checks whether c extension in multilibs is subset of zc* extensions in 
arch string.
By this method not only totally matched multilib sets but equivalent multilib 
subsets could be selected.

gcc/ChangeLog:

        * common/config/riscv/riscv-common.cc 
(riscv_subset_list::match_score_inc_p): New Function.
        * config/riscv/riscv-subset.h: New Function.
---
 gcc/common/config/riscv/riscv-common.cc | 27 +++++++++++++++++++++++++
 gcc/config/riscv/riscv-subset.h         |  2 ++
 2 files changed, 29 insertions(+)

diff --git a/gcc/common/config/riscv/riscv-common.cc 
b/gcc/common/config/riscv/riscv-common.cc
index a6d8763f032..f43899bb413 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -412,12 +412,39 @@ riscv_subset_list::match_score (riscv_subset_list *list) 
const
   for (s = list->m_head; s != NULL; s = s->next)
     if (this->lookup (s->name.c_str ()) != NULL)
       score++;
+    else if (this->match_score_inc_p (s->name.c_str (), list))
+      score++;
     else
       return 0;
 
   return score;
 }
 
+/* Check if given extension is equivalent to one or group of extensions
+in given subset list.  */
+bool
+riscv_subset_list::match_score_inc_p (std::string name,
+                                    riscv_subset_list *multilib) const
+{
+  if (name.compare ("c") != 0 || this->lookup ("zca") == NULL)
+    return false;
+
+  /* Check equivalent requirment when having d extension in multilib.  */
+  if (multilib->lookup ("d") != NULL)
+    {
+      if (multilib->xlen () == 32)
+       return this->lookup ("zcf") != NULL && this->lookup ("zcd") != NULL;
+      else
+       return this->lookup ("zcd") != NULL;
+    }
+
+  /* Check equivalent requirment when having f extension in multilib.  */
+  if (multilib->lookup ("f") != NULL && multilib->xlen () == 32)
+    return this->lookup ("zcf") != NULL;
+
+  return true;
+}
+
 /* Get the rank for single-letter subsets, lower value meaning higher
    priority.  */
 
diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h
index c5d9fab4de9..f80210cd755 100644
--- a/gcc/config/riscv/riscv-subset.h
+++ b/gcc/config/riscv/riscv-subset.h
@@ -114,6 +114,8 @@ public:
 
   int match_score (riscv_subset_list *) const;
 
+  bool match_score_inc_p (std::string, riscv_subset_list *) const;
+
   void set_loc (location_t);
 
   void set_allow_adding_dup (bool v) { m_allow_adding_dup = v; }
-- 
2.47.1

Reply via email to