Bootstrapped and regtested on x86_64-pc-linux-gnu
(--enable-languages=c,c++,fortran): all three stages built and the
stage 2/3 comparison succeeded, and the gfortran testsuite shows no
regressions (75375 expected passes, 335 expected failures, 0
unexpected
failures), with the two new tests passing.
gcc/fortran/ChangeLog:
* gfortran.h (enum ext_attr_id_t): Add
EXT_ATTR_FORCEINLINE.
* decl.cc (ext_attr_list): Add "forceinline".
(gfc_match_gcc_attributes): Warn about and drop
FORCEINLINE when
it is combined with NOINLINE on the same symbol.
* trans-decl.cc (build_function_decl): Handle
EXT_ATTR_FORCEINLINE
by setting DECL_DECLARED_INLINE_P and
DECL_DISREGARD_INLINE_LIMITS.
* gfortran.texi (ATTRIBUTES directive): Document
FORCEINLINE.
gcc/testsuite/ChangeLog:
* gfortran.dg/forceinline_1.f90: New test.
* gfortran.dg/forceinline_2.f90: New test.
Signed-off-by: Henri Menke <[email protected]>
---
gcc/fortran/decl.cc | 13 +++++++++++
gcc/fortran/gfortran.h | 1 +
gcc/fortran/gfortran.texi | 5 ++++
gcc/fortran/trans-decl.cc | 9 +++++++
gcc/testsuite/gfortran.dg/forceinline_1.f90 | 26
+++++++++++++++++++++
gcc/testsuite/gfortran.dg/forceinline_2.f90 | 14 +++++++++++
6 files changed, 68 insertions(+)
create mode 100644 gcc/testsuite/gfortran.dg/forceinline_1.f90
create mode 100644 gcc/testsuite/gfortran.dg/forceinline_2.f90
diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 166b10d4cd4..aa5b291ac41 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -12847,6 +12847,7 @@ const ext_attr_t ext_attr_list[] = {
{ "no_arg_check", EXT_ATTR_NO_ARG_CHECK, NULL },
{ "deprecated", EXT_ATTR_DEPRECATED, NULL },
{ "noinline", EXT_ATTR_NOINLINE, NULL },
+ { "forceinline", EXT_ATTR_FORCEINLINE, NULL },
{ "noreturn", EXT_ATTR_NORETURN, NULL },
{ "weak", EXT_ATTR_WEAK, NULL },
{ NULL, EXT_ATTR_LAST, NULL }
@@ -12925,6 +12926,18 @@ gfc_match_gcc_attributes (void)
sym->attr.ext_attr |= attr.ext_attr;
+ /* FORCEINLINE and NOINLINE are mutually exclusive. In the
middle-end
+ DECL_UNINLINABLE (set by NOINLINE) always wins, so
FORCEINLINE would
+ be silently ignored. Warn and drop it instead. */
+ if ((sym->attr.ext_attr & (1 << EXT_ATTR_FORCEINLINE))
+ && (sym->attr.ext_attr & (1 << EXT_ATTR_NOINLINE)))
+ {
+ gfc_warning (0, "Attribute %<FORCEINLINE%> at %C is
incompatible "
+ "with %<NOINLINE%> for %qs and will be
ignored",
+ sym->name);
+ sym->attr.ext_attr &= ~(1 << EXT_ATTR_FORCEINLINE);
+ }
+
if (gfc_match_eos () == MATCH_YES)
break;
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 37a8582e36d..440ad050bcb 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -886,6 +886,7 @@ typedef enum
EXT_ATTR_NO_ARG_CHECK,
EXT_ATTR_DEPRECATED,
EXT_ATTR_NOINLINE,
+ EXT_ATTR_FORCEINLINE,
EXT_ATTR_NORETURN,
EXT_ATTR_WEAK,
EXT_ATTR_LAST, EXT_ATTR_NUM = EXT_ATTR_LAST
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index a930cc1dc9c..255a9235f60 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -3397,6 +3397,11 @@ requires an explicit interface.
deprecated procedure, variable or parameter; the warning can be
suppressed
with @option{-Wno-deprecated-declarations}.
@item @code{NOINLINE} -- prevent inlining given function.
+@item @code{FORCEINLINE} -- force inlining of a given function,
ignoring the
+inlining size limits. This is the counterpart of @code{NOINLINE}
and
+corresponds to the C @code{always_inline} attribute.
@code{FORCEINLINE} and
+@code{NOINLINE} are mutually exclusive; specifying both for the
same procedure
+makes @code{FORCEINLINE} ignored with a warning.
@item @code{NORETURN} -- add a hint that a given function cannot
return.
@item @code{WEAK} -- emit the declaration of an external symbol
as a weak
symbol rather than a global. This is primarily useful in
defining library
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 1bcbfdfd2c9..da291c976ba 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -2652,6 +2652,15 @@ build_function_decl (gfc_symbol * sym, bool
global)
if (attr.ext_attr & (1 << EXT_ATTR_NOINLINE))
DECL_UNINLINABLE (fndecl) = 1;
+ /* Mark forceinline functions. Fortran has no 'inline' keyword,
so set
+ DECL_DECLARED_INLINE_P as well; otherwise the middle-end
warns that the
+ always-inline function "might not be inlinable". */
+ if (attr.ext_attr & (1 << EXT_ATTR_FORCEINLINE))
+ {
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+ DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
+ }
+
/* Mark noreturn functions. */
if (attr.ext_attr & (1 << EXT_ATTR_NORETURN))
TREE_THIS_VOLATILE (fndecl) = 1;
diff --git a/gcc/testsuite/gfortran.dg/forceinline_1.f90
b/gcc/testsuite/gfortran.dg/forceinline_1.f90
new file mode 100644
index 00000000000..2058c088662
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/forceinline_1.f90
@@ -0,0 +1,26 @@
+! { dg-do compile }
+! { dg-options "-O -fdump-tree-optimized" }
+!
+! Verify that !GCC$ ATTRIBUTES forceinline forces inlining: the
helper
+! procedure is inlined into its caller and no standalone call
remains.
+
+subroutine caller(a, n)
+ implicit none
+ integer, intent(in) :: n
+ real, intent(inout) :: a(n)
+ call helper(a, n)
+ call helper(a, n)
+contains
+ subroutine helper(x, m)
+ implicit none
+ integer, intent(in) :: m
+ real, intent(inout) :: x(m)
+!GCC$ ATTRIBUTES forceinline :: helper
+ integer :: i
+ do i = 1, m
+ x(i) = x(i) + 1.0
+ end do
+ end subroutine helper
+end subroutine caller
+
+! { dg-final { scan-tree-dump-not "helper" "optimized" } }
diff --git a/gcc/testsuite/gfortran.dg/forceinline_2.f90
b/gcc/testsuite/gfortran.dg/forceinline_2.f90
new file mode 100644
index 00000000000..44e4c107034
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/forceinline_2.f90
@@ -0,0 +1,14 @@
+! { dg-do compile }
+!
+! FORCEINLINE and NOINLINE are mutually exclusive. Specifying
both for the
+! same procedure must warn and drop FORCEINLINE, whether they
appear in one
+! directive or in separate directives.
+
+subroutine foo()
+!GCC$ ATTRIBUTES forceinline, noinline :: foo ! { dg-warning
"FORCEINLINE. at .1. is incompatible with .NOINLINE." }
+end subroutine foo
+
+subroutine bar()
+!GCC$ ATTRIBUTES forceinline :: bar
+!GCC$ ATTRIBUTES noinline :: bar ! { dg-warning "FORCEINLINE. at
.1. is incompatible with .NOINLINE." }
+end subroutine bar