Because LoongArch does not implement TARGET_CAN_INLINE_P,
functions with the target attribute set and those without
it cannot be inlined. At the same time, setting the
always_inline attribute will cause compilation failure.
To solve this problem, I implemented this hook. During the
implementation process, it checks the status of the target
special options of the caller and callee, such as the ISA
extension.
PR target/121875
gcc/ChangeLog:
* config/loongarch/loongarch.cc
(loongarch_can_inline_p): New function.
(TARGET_CAN_INLINE_P): Define.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/can_inline_1.c: New test.
* gcc.target/loongarch/can_inline_2.c: New test.
* gcc.target/loongarch/can_inline_3.c: New test.
* gcc.target/loongarch/can_inline_4.c: New test.
* gcc.target/loongarch/can_inline_5.c: New test.
* gcc.target/loongarch/can_inline_6.c: New test.
* gcc.target/loongarch/pr121875.c: New test.
---
gcc/config/loongarch/loongarch.cc | 66 +++++++++++++++++++
.../gcc.target/loongarch/can_inline_1.c | 18 +++++
.../gcc.target/loongarch/can_inline_2.c | 19 ++++++
.../gcc.target/loongarch/can_inline_3.c | 19 ++++++
.../gcc.target/loongarch/can_inline_4.c | 18 +++++
.../gcc.target/loongarch/can_inline_5.c | 18 +++++
.../gcc.target/loongarch/can_inline_6.c | 18 +++++
gcc/testsuite/gcc.target/loongarch/pr121875.c | 5 ++
8 files changed, 181 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_1.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_2.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_3.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_4.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_5.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/can_inline_6.c
create mode 100644 gcc/testsuite/gcc.target/loongarch/pr121875.c
diff --git a/gcc/config/loongarch/loongarch.cc
b/gcc/config/loongarch/loongarch.cc
index ef5d5f4e060..4d82fc8b6ec 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -11202,6 +11202,69 @@ loongarch_compute_pressure_classes (reg_class *classes)
return i;
}
+/* Implement TARGET_CAN_INLINE_P. Determine whether inlining the function
+ CALLER into the function CALLEE is safe. Inlining should be rejected if
+ there is no always_inline attribute and the target options differ except
+ for differences in ISA extensions or performance tuning options like the
+ code model, TLS dialect, etc. */
+
+static bool
+loongarch_can_inline_p (tree caller, tree callee)
+{
+ tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+ tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+
+ if (!callee_tree)
+ callee_tree = target_option_default_node;
+
+ if (!caller_tree)
+ caller_tree = target_option_default_node;
+
+ /* If both caller and callee have attributes, assume that if the
+ pointer is different, the two functions have different target
+ options since build_target_option_node uses a hash table for the
+ options. */
+ if (callee_tree == caller_tree)
+ return true;
+
+ struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+ struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+
+ /* Callee and caller should have the same target options. */
+ int callee_target_flags = callee_opts->x_target_flags;
+ int caller_target_flags = caller_opts->x_target_flags;
+
+ if (callee_target_flags != caller_target_flags)
+ return false;
+
+ /* If callee enables the isa extension that the caller does not enable,
+ inlining is disabled. */
+ if (~caller_opts->x_la_isa_evolution
+ & callee_opts->x_la_isa_evolution)
+ return false;
+
+ /* If simd extensions are enabled for the callee but not for the caller,
+ inlining is disabled. */
+ if ((caller_opts->x_la_opt_simd == ISA_EXT_NONE
+ && callee_opts->x_la_opt_simd != ISA_EXT_NONE)
+ || (caller_opts->x_la_opt_simd == ISA_EXT_SIMD_LSX
+ && callee_opts->x_la_opt_simd == ISA_EXT_SIMD_LASX))
+ return false;
+
+ bool always_inline
+ = lookup_attribute ("always_inline", DECL_ATTRIBUTES (callee));
+
+ /* If the architectural features match up and the callee is always_inline
+ then the other attributes don't matter. */
+ if (always_inline)
+ return true;
+
+ if (caller_opts->x_la_opt_cmodel != callee_opts->x_la_opt_cmodel)
+ return false;
+
+ return true;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -11482,6 +11545,9 @@ loongarch_compute_pressure_classes (reg_class *classes)
#undef TARGET_COMPUTE_PRESSURE_CLASSES
#define TARGET_COMPUTE_PRESSURE_CLASSES loongarch_compute_pressure_classes
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P loongarch_can_inline_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-loongarch.h"
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_1.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_1.c
new file mode 100644
index 00000000000..bdae4dbebe7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {missed: not inlinable: bar/\d+ -> foo/\d+,
target specific option mismatch} "einline" } } */
+/* { dg-final { scan-tree-dump-not {\(inlined\)} "einline" } } */
+
+void
+__attribute__ ((target ("lsx")))
+foo (void)
+{}
+
+void
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_2.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_2.c
new file mode 100644
index 00000000000..e4bf1e0ba96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {missed: not inlinable: bar/\d+ -> foo/\d+,
target specific option mismatch} "einline" } } */
+/* { dg-final { scan-tree-dump-not {\(inlined\)} "einline" } } */
+
+void
+__attribute__ ((target ("lasx")))
+foo (void)
+{}
+
+void
+__attribute__ ((target ("lsx")))
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_3.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_3.c
new file mode 100644
index 00000000000..42fb5229e78
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {missed: not inlinable: bar/\d+ -> foo/\d+,
target specific option mismatch} "einline" } } */
+/* { dg-final { scan-tree-dump-not {\(inlined\)} "einline" } } */
+
+void
+__attribute__ ((target ("arch=la64v1.1")))
+foo (void)
+{}
+
+void
+__attribute__ ((target ("arch=la64v1.0")))
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_4.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_4.c
new file mode 100644
index 00000000000..bc1913b7c07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_4.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {missed: not inlinable: bar/\d+ -> foo/\d+,
target specific option mismatch} "einline" } } */
+/* { dg-final { scan-tree-dump-not {\(inlined\)} "einline" } } */
+
+void
+foo (void)
+{}
+
+void
+__attribute__ ((target ("cmodel=extreme")))
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_5.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_5.c
new file mode 100644
index 00000000000..3d4e193f94c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_5.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {\(inlined\)} "einline" } } */
+
+void
+__attribute__ ((always_inline))
+foo (void)
+{}
+
+void
+__attribute__ ((target ("cmodel=extreme")))
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/can_inline_6.c
b/gcc/testsuite/gcc.target/loongarch/can_inline_6.c
new file mode 100644
index 00000000000..23ab505ee75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/can_inline_6.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -fdump-tree-einline-details
-O2" } */
+/* { dg-final { scan-tree-dump {missed: not inlinable: bar/\d+ -> foo/\d+,
target specific option mismatch} "einline" } } */
+/* { dg-final { scan-tree-dump-not {\(inlined\)} "einline" } } */
+
+void
+__attribute__ ((target ("strict-align")))
+foo (void)
+{}
+
+void
+bar (void)
+{
+ foo ();
+}
+
+
+
diff --git a/gcc/testsuite/gcc.target/loongarch/pr121875.c
b/gcc/testsuite/gcc.target/loongarch/pr121875.c
new file mode 100644
index 00000000000..f0a42ba020a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/pr121875.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-march=loongarch64 -mabi=lp64d -O2" } */
+
+[[gnu::always_inline]] inline void f() {}
+[[gnu::target("lasx")]] int main() {f();}
--
2.34.1