modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
98 stars 42 forks source link

Impossible to pass valid function pointer to LAPACK function dgees #2183

Open modelica-trac-importer opened 5 years ago

modelica-trac-importer commented 5 years ago

Reported by henrikt on 24 Apr 2017 08:51 UTC The current hack (mentioned in #960) for calling the external FORTRAN dgees from Modelica.Math.Matrices.LAPACK.dgees results in code that is not legal C++ since the pointer types don't match. I don't see why tools should be forced to generate C code in order to "just" get a warning for the hack instead of an error when compiling the code.

Since generating FORTRAN functions that can be passed via function pointers to in external FORTRAN calls would require considerable design work as well as work on the part of the tool vendors, it would be more reasonable to just provide a way to pass a null pointer to external functions.

The null pointer would not need to be a Modelica value, not be stored, not have a type, etc. All that we would need is a way to indicate where a null pointer is to be passed in the argument list of an external function call.

To start the discussion, I propose the following syntax:

  external "FORTRAN 77" dgees("V", "N", external 0, n, T, lda, …

Using external 0 instead of, for instance, NULL avoids the need to introduce a new keyword.


Migrated-From: https://trac.modelica.org/Modelica/ticket/2183

modelica-trac-importer commented 5 years ago

Comment by sjoelund.se on 24 Apr 2017 10:09 UTC Passing external 0 would require a change in the grammar. Passing NULL or NULL() would not (you can pass any expression you like according to the grammar).

I don't see why tools should be forced to generate C code in order to "just" get a warning for the hack instead of an error when compiling the code.

Well, it's using "FORTRAN 77" and not even C, so I suppose we should be happy that we can call it from C without weird Fortran wrappers, marshalling, etc...

Note: If solving the issue by creating wrapper functions and linking lapack directly in MSL to avoid passing NULL or function pointers, I think I would prefer using lapacke over clapack (since it is maintained and not an f2c hack; it does have the disadvantage of perhaps not providing lapack symbols for older MSL although these could be added).

modelica-trac-importer commented 5 years ago

Modified by beutlich on 24 Apr 2017 11:07 UTC

modelica-trac-importer commented 5 years ago

Comment by beutlich on 25 Apr 2017 08:27 UTC What is the aim of this ticket?

  1. Add external null pointer, such that dgees with "N" works in a clean way?
  2. Add external function pointer arguments, such that also dgees with "S" and sort function works correctly?
modelica-trac-importer commented 5 years ago

Comment by henrikt on 25 Apr 2017 13:17 UTC The aim is 1; make it possible to call dgees with "N" in a clean way that will work also for tools that generate C++ code. The description explicitly excludes alternative 2.

modelica-trac-importer commented 5 years ago

Comment by choeger on 25 Apr 2017 15:38 UTC I do not think that this is a very good idea. We would introduce a literal that can only be used in some calls to external functions. I think that precisely this sort of special cases makes the language hard to implement.

IMO, a better way is to use the existing external function interface and create an external object that is the NULL pointer. Is there any reason against this?

modelica-trac-importer commented 5 years ago

Comment by anonymous on 25 Apr 2017 15:51 UTC Passing a variable which is void* in C++ is an error for function pointer expected. Passing NULL is allowed.

modelica-trac-importer commented 5 years ago

Comment by dag on 26 Apr 2017 07:31 UTC Well, NULL often has some problems in C++. I would in that case suggest the literal 0 which can always be converted to a null pointer, or in modern versions of C++ the new keyword nullptr.

However, going back to the original proposal -- why do you need external 0? Wouldn't the perfectly legitimate (integer) literal 0 do the job? Assuming that the tool passes it through as a literal.

modelica-trac-importer commented 5 years ago

Comment by sjoelund.se on 26 Apr 2017 07:53 UTC Replying to [comment:7 dag]:

Well, NULL often has some problems in C++. I would in that case suggest the literal 0 which can always be converted to a null pointer, or in modern versions of C++ the new keyword nullptr.

However, going back to the original proposal -- why do you need external 0? Wouldn't the perfectly legitimate (integer) literal 0 do the job? Assuming that the tool passes it through as a literal.

For C++, you need a function prototype in order to call a function. This is automatically generated by a Modelica tool in some cases. Passing the literal 0 would mean generating int in the interface, which is not the same length as a function pointer (on e.g. x86 64-bit platforms).

This could be solved by using external "C" instead of Fortran 77, and knowing which LAPACK interface to compile against...

modelica-trac-importer commented 5 years ago

Comment by choeger on 26 Apr 2017 08:39 UTC Let me reiterate the discussion:

  1. The problem is that there are Fortran functions that do not comply to the Modelica FFI
  2. The proposed solution is the creation of a special "Fortran call" syntax where there is a special literal for null pointers

I think that 2. is way too specific for a change to the grammar. IMO, the only way that could be worth the effort would be to introduce generic Fortran/C/C++ literals:

This is a slightly more general change with basically the same effort w.r.t. the specification. It requires a MCP.

As a side note: What prevents users from wrapping the function into one that automatically adds the NULL argument?

modelica-trac-importer commented 5 years ago

Comment by henrikt on 26 Apr 2017 08:41 UTC Replying to [comment:8 Martin Sjölund]:

Replying to [comment:7 dag]:

Well, NULL often has some problems in C++. I would in that case suggest the literal 0 which can always be converted to a null pointer, or in modern versions of C++ the new keyword nullptr.

However, going back to the original proposal -- why do you need external 0? Wouldn't the perfectly legitimate (integer) literal 0 do the job? Assuming that the tool passes it through as a literal.

For C++, you need a function prototype in order to call a function. This is automatically generated by a Modelica tool in some cases. Passing the literal 0 would mean generating int in the interface, which is not the same length as a function pointer (on e.g. x86 64-bit platforms).

I don't think there is a need to specify whether a tool should generate 0, NULL, or nullptr; what we need is a way to specify that the external function should be called with a null pointer.

modelica-trac-importer commented 5 years ago

Comment by henrikt on 26 Apr 2017 08:51 UTC Replying to [comment:5 choeger]:

IMO, a better way is to use the existing external function interface and create an external object that is the NULL pointer. Is there any reason against this?

See comment:17 and comment:9. We don't have a way to pass external object pointers to to external FORTRAN 77 functions, and even if we did, the pointer would be of mismatching type void* (error in C++).

modelica-trac-importer commented 5 years ago

Comment by dag on 26 Apr 2017 08:53 UTC Replying to [comment:9 choeger]:

As a side note: What prevents users from wrapping the function into one that adds the NULL argument?

Excellent point. Doesn't that solve the problem in the relatively few cases we are concerned with?

modelica-trac-importer commented 5 years ago

Comment by henrikt on 26 Apr 2017 08:55 UTC Replying to [comment:9 choeger]:

As a side note: What prevents users from wrapping the function into one that automatically adds the NULL argument?

See: https://github.com/modelica/Modelica/issues/2241

modelica-trac-importer commented 5 years ago

Comment by choeger on 26 Apr 2017 09:07 UTC Replying to [comment:13 Henrik Tidefelt]:

Replying to [comment:9 choeger]:

As a side note: What prevents users from wrapping the function into one that automatically adds the NULL argument?

See: https://github.com/modelica/Modelica/issues/2241

If I understand the discussion correctly, the issue with a C wrapper stems from different Fortran implementations. Now I am even more convinced that adding special syntax for this case is a bad idea. Either we do it right and extend Modelica's FFI in a more general way or we should leave the grammar untouched.

The correct solution for now seems to be to provide a ModelicaExternalFortran library that contains the required wrapper.

modelica-trac-importer commented 5 years ago

Comment by hansolsson on 11 May 2017 13:28 UTC For the specification this is clearly an enhancement.

modelica-trac-importer commented 5 years ago

Modified by beutlich on 6 Oct 2017 06:11 UTC

modelica-trac-importer commented 5 years ago

Comment by hansolsson on 19 Oct 2017 08:34 UTC Martin: One possibility is to just use C-version of Lapack Hans: Another possibility is to provide a few C-macros so that one can write the C-wrapper calling Fortran as an include-annotation in Modelica (name mangling and more?); see f2c.h

Martin S: Explained by NULL() in external call does not influence grammar, but need separate semantics.

Poll for possibilities:

  1. Nothing: 1
  2. "external 0": 1
  3. NULL() - possibly NULLFunction(): 5
  4. Standarize C-version of Lapack: 4
  5. C-macros for calling Fortran: 1 Might consider a slightly different name (to avoid confusion with C-macro).
modelica-trac-importer commented 5 years ago

Comment by hansolsson on 19 Oct 2017 09:01 UTC Hans: NullFunction() for generating Null-pointer to function (all capital smells like C-macro). According to Martin S all function pointers are the same size. Otto: There are embedded systems where function pointers are different in size from normal pointers - but perhaps without Fortran-library.

Henrik: A bit dangerous to derive prototypes from the call. Hans: It's possible to avoid deriving prototypes - but then C-macros for calling Fortran seems required.

modelica-trac-importer commented 5 years ago

Modified by beutlich on 10 Jan 2018 08:23 UTC