Currently, we lack support for TARGET_CAN_INLINE_P on the RISC-V
ISA. As a result, certain functions cannot be optimized with inlining
when specific options, such as __attribute__((target("arch=+v"))) .
This can lead to potential performance issues when building
retargetable binaries for RISC-V.

To address this, I have implemented the riscv_can_inline_p function.
This addition enables inlining when the callee either has no special
options or when the some options match, and also ensuring that the
callee's ISA is a subset of the caller's. I also check some other
options when there is no always_inline set.

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_can_inline_p): New function.
        (TARGET_CAN_INLINE_P): Implement TARGET_CAN_INLINE_P.

Signed-off-by: Yangyu Chen <chenyan...@isrc.iscas.ac.cn>
---
 gcc/config/riscv/riscv.cc | 135 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 6efe14ff199..d36c135650e 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7656,6 +7656,138 @@ riscv_compute_frame_info (void)
   /* Next points the incoming stack pointer and any incoming arguments. */
 }
 
+/* Implement TARGET_CAN_INLINE_P.  */
+
+static bool
+riscv_can_inline_p (tree caller, tree callee)
+{
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+
+  /* It's safe to inline if callee has no opts.  */
+  if (! callee_tree)
+    return true;
+
+  if (! caller_tree)
+    caller_tree = target_option_default_node;
+
+  struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+  struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+
+  int isa_flag_mask = MASK_MUL | MASK_ATOMIC | MASK_HARD_FLOAT
+                     | MASK_DOUBLE_FLOAT | MASK_RVC | MASK_VECTOR
+                     | MASK_FULL_V;
+
+  /* Callee and caller should have the same target options except for ISA.  */
+  int callee_target_flags = callee_opts->x_target_flags & ~isa_flag_mask;
+  int caller_target_flags = caller_opts->x_target_flags & ~isa_flag_mask;
+
+  if (callee_target_flags != caller_target_flags)
+    return false;
+
+  /* Callee's ISA should be a subset of the caller's ISA.  */
+  int callee_isa_flags = callee_opts->x_target_flags & isa_flag_mask;
+  int caller_isa_flags = caller_opts->x_target_flags & isa_flag_mask;
+
+  if (callee_isa_flags & ~caller_isa_flags)
+    return false;
+
+  if (callee_opts->x_riscv_zi_subext & ~caller_opts->x_riscv_zi_subext)
+    return false;
+
+  if (callee_opts->x_riscv_za_subext & ~caller_opts->x_riscv_za_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zb_subext & ~caller_opts->x_riscv_zb_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zinx_subext & ~caller_opts->x_riscv_zinx_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zk_subext & ~caller_opts->x_riscv_zk_subext)
+    return false;
+
+  if (callee_opts->x_riscv_vector_elen_flags
+      & ~caller_opts->x_riscv_vector_elen_flags)
+    return false;
+
+  if (callee_opts->x_riscv_zvl_flags & ~caller_opts->x_riscv_zvl_flags)
+    return false;
+
+  if (callee_opts->x_riscv_zvb_subext & ~caller_opts->x_riscv_zvb_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zvk_subext & ~caller_opts->x_riscv_zvk_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zicmo_subext & ~caller_opts->x_riscv_zicmo_subext)
+    return false;
+
+  if (callee_opts->x_riscv_mop_subext & ~caller_opts->x_riscv_mop_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zf_subext & ~caller_opts->x_riscv_zf_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zfa_subext & ~caller_opts->x_riscv_zfa_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zm_subext & ~caller_opts->x_riscv_zm_subext)
+    return false;
+
+  if (callee_opts->x_riscv_zc_subext & ~caller_opts->x_riscv_zc_subext)
+    return false;
+
+  if (callee_opts->x_riscv_sv_subext & ~caller_opts->x_riscv_sv_subext)
+    return false;
+
+  if (callee_opts->x_riscv_ztso_subext & ~caller_opts->x_riscv_ztso_subext)
+    return false;
+
+  if (callee_opts->x_riscv_xcv_subext & ~caller_opts->x_riscv_xcv_subext)
+    return false;
+
+  if (callee_opts->x_riscv_xthead_subext & ~caller_opts->x_riscv_xthead_subext)
+    return false;
+
+  if (callee_opts->x_riscv_xventana_subext
+      & ~caller_opts->x_riscv_xventana_subext)
+    return false;
+
+  if (callee_opts->x_riscv_sifive_subext & ~caller_opts->x_riscv_sifive_subext)
+    return false;
+
+  /* If the callee has always_inline set, we can ignore the rest attributes.  
*/
+  if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (callee)))
+    return true;
+
+  if (caller_opts->x_riscv_cmodel != callee_opts->x_riscv_cmodel)
+    return false;
+
+  if (caller_opts->x_riscv_tls_dialect != callee_opts->x_riscv_tls_dialect)
+    return false;
+
+  if (caller_opts->x_riscv_stack_protector_guard_reg
+      != callee_opts->x_riscv_stack_protector_guard_reg)
+    return false;
+
+  if (caller_opts->x_riscv_stack_protector_guard_offset
+      != callee_opts->x_riscv_stack_protector_guard_offset)
+    return false;
+
+  if (caller_opts->x_rvv_vector_strict_align
+      != callee_opts->x_rvv_vector_strict_align)
+    return false;
+
+  if (caller_opts->x_riscv_tune_string
+      && callee_opts->x_riscv_tune_string
+      && strcmp (caller_opts->x_riscv_tune_string,
+                callee_opts->x_riscv_tune_string) != 0)
+    return false;
+
+  return true;
+}
+
 /* Make sure that we're not trying to eliminate to the wrong hard frame
    pointer.  */
 
@@ -12540,6 +12672,9 @@ riscv_stack_clash_protection_alloca_probe_range (void)
 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P    riscv_legitimate_address_p
 
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P riscv_can_inline_p
+
 #undef TARGET_CAN_ELIMINATE
 #define TARGET_CAN_ELIMINATE riscv_can_eliminate
 
-- 
2.45.2

Reply via email to