Hi Rimvydas,

> Gesendet: Mittwoch, 15. Februar 2023 um 21:58 Uhr
> Von: "Rimvydas Jasinskas" <rimvydas...@gmail.com>
>
> On Tue, Feb 14, 2023 at 9:55 PM Harald Anlauf <anl...@gmx.de> wrote:
> > >>> There is one thing I cannot test, which is the handling of weak symbols
> > >>> on other platforms.  A quick glance at the C testcases suggests that
> > >>> someone with access to either an NVPTX or MingGW target might tell
> > >>> whether that particular target should be excluded.
> While working on part 2 patch for weak variables I noticed that MingGW
> has quite different handling of weak symbols as weak externals between
> 32/64.  I think adding "! { dg-skip-if "" { x86-64-*-mingw*} }" is
> needed to weak-1.f90 testcase, but I decided to wait for testsuite
> failure reports.

there are some MinGW users that will hopefully report back here soon.

> > > And, orthogonally: is '!GCC$ ATTRIBUTES weak' meant to be used only for
> > > subroutines (like in 'gfortran.dg/weak-1.f90') and also functions (I
> > > suppose; test case?), or also for weak "data" in some way (which, for
> > > example, in the C world then evaluates to a zero-address unless actually
> > > defined)?
> Weak zero-addressed "data" is more complicated between targets,  I do
> not see a need for it.
> Functions are handled the same as subroutines, I had testcase for it,
> but decided to deal with fallout from weak-1.f90 first:
> $ cat gcc/testsuite/gfortran.dg/weak-2.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> ! { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?impl" } }
> integer function impl()
> implicit none
> !GCC$ ATTRIBUTES weak :: impl
> end function

Yes, this works.  I tried that before pushing.

> > Syntax and use of the WEAK directive.
> > !DIR$ WEAK procedure_name[, procedure_name] ...
> > !DIR$ WEAK procedure_name= stub_name[, procedure_name1= stub_name1] ...
> > stub_name
> >      A stub procedure that exists in the code. The stub_name will be
> > called if a strong reference does not exist for procedure_name. The
> > stub_name procedure must have the same name and dummy argument list as
> > procedure_name.
> I think the same for procedure_name=stub_name can be achieved with
> bind(c,'sym') already without caring about symbol name mangling:
> $ cat gcc/testsuite/gfortran.dg/weak-6.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> ! { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?bar__" } }
> integer function impl() bind(c,name='bar__')
> implicit none
> !GCC$ ATTRIBUTES weak :: impl
> end function

This does work indeed.  It would be good to add these examples to
the documentation for reference in a subsequent patch.

> > I'm not sure whether we need to support weak symbols other than
> > procedures in gfortran.  Maybe Rimvydas can comment on this.
> In 2nd part patch I was thinking to add support for weak global
> variables (like in modules):
> --- a/gcc/fortran/trans-decl.cc
> +++ b/gcc/fortran/trans-decl.cc
> @@ -814,6 +814,10 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym)
>        && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
>      set_decl_tls_model (decl, decl_default_tls_model (decl));
>
> +  /* Mark weak variables.  */
> +  if (sym->attr.ext_attr & (1 << EXT_ATTR_WEAK))
> +    declare_weak (decl);
> +
>    gfc_finish_decl_attrs (decl, &sym->attr);
>  }
>
> $ cat gcc/testsuite/gfortran.dg/weak-3.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> ! { dg-skip-if "" { x86_64-*-mingw* } }
> ! { dg-skip-if "" { nvptx-*-* } }
> ! { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?__foo_MOD_abc" } }
> module foo
> implicit none
> !GCC$ ATTRIBUTES weak :: abc
> real :: abc(7)
> end module
>
> The catch is again scan-assembler issues with various symbol name
> manglings.  Maybe just to add testcase without scan-assembler to check
> if testcase is not rejected?

Either that, or restricting those testcases by adding:

! { dg-skip-if "" { nvptx-*-* } }
! { dg-skip-if "" { x86_64-*-mingw* } }

> Currently already rejected are:
> $ cat gcc/testsuite/gfortran.dg/weak-4.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> program foo  ! { dg-error "weak declaration of 'foo' must be public" "" }
> implicit none
> !GCC$ ATTRIBUTES weak :: foo
> end program

Yes.

> $ cat gcc/testsuite/gfortran.dg/weak-9.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> subroutine foo
> implicit none
> real :: abc     ! { dg-error "weak declaration of 'abc' must be public" "" }
> !GCC$ ATTRIBUTES weak :: abc
> print *, abc
> contains
>  subroutine bar ! { dg-error "weak declaration of 'bar' must be public" "" }
> !GCC$ ATTRIBUTES weak :: bar
>  end subroutine
> end subroutine
>
> However error is not given if 'abc' is made a dummy argument or is not
> used, any ideas why?

At least for a dummy argument one can generate an error in
gfc_get_symbol_decl():

@@ -1549,6 +1552,14 @@ gfc_get_symbol_decl (gfc_symbol * sym)
              || (sym->module && sym->attr.if_source != IFSRC_DECL
                  && sym->backend_decl));

+  if (sym->attr.dummy && (sym->attr.ext_attr & (1 << EXT_ATTR_WEAK)))
+    {
+      if (!sym->error)
+       gfc_error ("Symbol %qs at %L has the WEAK attribute but is a dummy "
+                  "argument", sym->name, &sym->declared_at);
+      sym->error = 1;
+    }
+
   if (sym->attr.dummy && sym->ns->proc_name->attr.is_bind_c
       && is_CFI_desc (sym, NULL))
     {

(The setting of sym->error is done to suppress multiple errors
for the same line.  Not sure if this is the best solution, but
it works.)

> $ cat gcc/testsuite/gfortran.dg/weak-8.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> module foo
> implicit none
> real :: a,b
> common /c/ a,b
> !GCC$ ATTRIBUTES weak :: c
> ! { dg-error "has no IMPLICIT type" "common" {target *-*-*} .-1 }
> end module

Well, here 'c' is an undeclared variable.
(The syntax would be different anyway, see e.g. SAVE).

> I suspect declaring common blocks weak should be explicitly rejected
> somewhere in resolve.cc, since .comm + .weak (should?) be illegal:
> $ cat cweak.s
> .comm c_,8,16
> .weak c_
> $ as cweak.s
> cweak.s: Assembler messages:
> cweak.s: Error: symbol `c_' can not be both weak and common
> However in weak-8.f90 error depends if "implicit none" is given.

Commenting out the "implicit none", I see in the assembler:

        .comm   c_,8,16
        .weak   __foo_MOD_c

which confirms that variable "c" and common /c/ are different beasts.

> Also what to do with declarations like:
> $ cat gcc/testsuite/gfortran.dg/weak-7.f90
> ! { dg-do compile }
> ! { dg-require-weak "" }
> module foo
> implicit none
> !GCC$ ATTRIBUTES weak :: foo
> integer :: ijk
> end module
>
> Currently it is silently accepted and has no effect.  I would see it
> useful if such a declaration would make all publicly visible variables
> and procedures to be marked as weak (as a shorthand, instead of
> declaring each variable/procedure as weak).  But I have not looked up
> how to do this yet.

Yes, it makes sense to either diagnose it or apply it
to publicly visible variables and procedures.  This
appears to be more work.

> Similar issue is with other attributes too:
> module aaa
> !GCC$ ATTRIBUTES fastcall :: aaa
> !GCC$ ATTRIBUTES deprecated :: aaa
> !GCC$ ATTRIBUTES noinline :: aaa
> integer :: ijk
> end module
>
> If such declarations to be explicitly rejected/diagnosed (say under
> -Wattributes) some kind of table like in
> gcc/c-family/c-attribs.cc:c_common_attribute_table[] would be needed,
> where false/true indicate if attribute could be applied for a given
> use case.
> On a side note, could someone check if cdecl/stdcall/fastcall actually
> affect code generation on windows targets?

Could you please open a PR for handling and tracking this?
This mail has already gotten quite long.

> In the end, the most problematic issue is useability of GCC directives
> in user codes.  As more and more attributes or other directives get
> supported it tends to create chaos in how users (try to) make use of
> these attributes.  The NO_ARGS_CHECK is/was a good example.  The mpi
> libraries generate bindings on the fly after checking if this
> attribute is supported.  Other projects use cpp preprocessor "#if
> __GNUC__ > 8", sometimes even in wrong ways like "#if __GFORTRAN__ >
> 10" or explicit rules like "cc -E -P -traditional -xc foo.F90 >
> foo.f90 && $(FC) -c foo.f90" while not suspecting that system cc(1)
> and say gfortran-10 could be of different versions on given host
> environment (or even not gfortran), specially on systems where cc(1)
> is 4.8.5.  The __GFORTRAN__ macro defined to '1' seems like a lost
> opportunity to use it as a compiler version major or maybe even
> currently active Fortran standard level.
> Issue is that unlike C frontends, gfortran hard rejects compilation
> units containing unknown attributes or slightly expanded new syntax:
> $ cat cold.f90
> subroutine foo
> !GCC$ ATTRIBUTES cold :: foo
> end subroutine
> $ gfortran -c cold.f90
> Error: Unknown attribute in !GCC$ ATTRIBUTES statement at (1)

Same here: please open a PR on this.

> I have a patch that adds -fallow-ignored-directive to demote such
> errors to warnings, but it looks too ugly and does not solve the
> useability issues by itself.
> What about adding support for conditional directives based on the
> compiler version?  Simple "!GCC$ if(13+) ATTRIBUTES weak :: foo" would
> in theory allow to keep the same sourcecode with different compiler
> versions and not require cpp preprocessor tricks once this feature
> "age" enough.

This does look a bit strange to me, and I do not see the real
point.  It is possible to use the accompanying preprocessor to
generate gcc/gfortran version dependent stuff (works for me):

#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 1300
#define GCC_ATTRIBUTES_WEAK GCC$ ATTRIBUTES weak
#endif
!GCC_ATTRIBUTES_WEAK :: foo

(The system gcc/cpp version is lower).

Cheers,
Harald

> Any thoughts?
>
> Regards,
> Rimvydas
>

Reply via email to