[PATCH] Modula-2: merge proposal/review: 1/9 01.patch-set-01

Richard Biener richard.guenther@gmail.com
Fri May 27 07:40:54 GMT 2022


On Wed, May 25, 2022 at 9:50 PM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>
> Richard Biener <richard.guenther@gmail.com> writes:
>
> > So is there a reason to have the 'scaffold' separate from the object
> > of hello.mod?
>
> Perhaps the major advantage is flexibility?  But no we can by default
> produce the scaffold within the object of hello.mod (and give users the
> ability to disable scaffold generation should they wish to implement
> their own).
>
> > Is there more than a 1:1 relation between a .mod and the 'scaffold'?
>
> yes there is a 1:1 relation between a .mod and the scaffold.  Although
> the caveat is that the compiler would need to parse every .def and .mod
> imports from the application universe.  Not a major change as gm2 has
> the ability to do whole program (application) compiling, so a minor set
> of changes to ensure that upon compiling the program module that it also
> parses every .def/.mod.
>
> > Why are multiple tools involved here - can the m2 frontend not parse
> > imports, reorder runtime modules and generate the 'scaffold' as
> > GENERIC IL as part of the translation unit of the .mod file?
> > Indirection through emitting C++ source code makes the process a bit
> > awkward IMHO.
>
> indeed the m2 front end can parse imports, reorder and generate the
> scaffold.
>
> > Unfortunately I have no m2 installation around to look at how complex
> > the 'scaffold' is.
>
> the scaffold is really simple for example here it is for hello.mod:
>
>   $ gm2 -c -g -fmakelist hello.mod
>   $ cat hello.lst
> Storage
> SYSTEM
> M2RTS
> RTExceptions
> # libc   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/libc.def FOR 'C'
> # SYSTEM   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SYSTEM.mod
> # StrIO   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrIO.mod
> # StrLib   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrLib.mod
> # ASCII   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/ASCII.mod
> # NumberIO   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/NumberIO.mod
> # Indexing   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Indexing.mod
> # errno    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/errno.def
> # termios    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/termios.def
> # FIO    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/FIO.mod
> # IO    8 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/IO.mod
> # StdIO    7 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StdIO.mod
> # Debug    6 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Debug.mod
> # SysStorage    5 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysStorage.mod
> # SysExceptions    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysExceptions.def
> # M2EXCEPTION    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2EXCEPTION.mod
> # Storage    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Storage.mod
> # RTExceptions    3 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/RTExceptions.mod
> # M2RTS    2 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2RTS.mod
> # hello    1 hello.mod
> #
> # Initialization order
> #
> StrIO
> StrLib
> ASCII
> NumberIO
> Indexing
> errno
> termios
> FIO
> IO
> StdIO
> Debug
> SysStorage
> SysExceptions
> M2EXCEPTION
> hello
>
>    and now to generate the scaffold for a static application:
>
>    $ ~/opt/bin/gm2 -fmakeinit -c -g hello.mod
>    $ cat hello_m2.cpp
> extern "C" void exit(int);
>
> extern "C" void RTExceptions_DefaultErrorCatch(void);
> extern "C" void _M2_Storage_init (int argc, char *argv[]);
> extern "C" void _M2_Storage_finish (void);
> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
> extern "C" void _M2_SYSTEM_finish (void);
> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
> extern "C" void _M2_M2RTS_finish (void);
> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_RTExceptions_finish (void);
> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
> extern "C" void _M2_StrIO_finish (void);
> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
> extern "C" void _M2_StrLib_finish (void);
> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
> extern "C" void _M2_ASCII_finish (void);
> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
> extern "C" void _M2_NumberIO_finish (void);
> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
> extern "C" void _M2_Indexing_finish (void);
> extern "C" void _M2_errno_init (int argc, char *argv[]);
> extern "C" void _M2_errno_finish (void);
> extern "C" void _M2_termios_init (int argc, char *argv[]);
> extern "C" void _M2_termios_finish (void);
> extern "C" void _M2_FIO_init (int argc, char *argv[]);
> extern "C" void _M2_FIO_finish (void);
> extern "C" void _M2_IO_init (int argc, char *argv[]);
> extern "C" void _M2_IO_finish (void);
> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
> extern "C" void _M2_StdIO_finish (void);
> extern "C" void _M2_Debug_init (int argc, char *argv[]);
> extern "C" void _M2_Debug_finish (void);
> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
> extern "C" void _M2_SysStorage_finish (void);
> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_SysExceptions_finish (void);
> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
> extern "C" void _M2_M2EXCEPTION_finish (void);
> extern "C" void _M2_hello_init (int argc, char *argv[]);
> extern "C" void _M2_hello_finish (void);
>
> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>
> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>
> static void init (int argc, char *argv[])
> {
>    try {
>        _M2_Storage_init (argc, argv);
>        _M2_SYSTEM_init (argc, argv);
>        _M2_M2RTS_init (argc, argv);
>        _M2_RTExceptions_init (argc, argv);
>        _M2_StrIO_init (argc, argv);
>        _M2_StrLib_init (argc, argv);
>        _M2_ASCII_init (argc, argv);
>        _M2_NumberIO_init (argc, argv);
>        _M2_Indexing_init (argc, argv);
>        _M2_errno_init (argc, argv);
>        _M2_termios_init (argc, argv);
>        _M2_FIO_init (argc, argv);
>        _M2_IO_init (argc, argv);
>        _M2_StdIO_init (argc, argv);
>        _M2_Debug_init (argc, argv);
>        _M2_SysStorage_init (argc, argv);
>        _M2_SysExceptions_init (argc, argv);
>        _M2_M2EXCEPTION_init (argc, argv);
>       M2RTS_ExecuteInitialProcedures ();
>        _M2_hello_init (argc, argv);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> static void finish (void)
> {
>    try {
>       M2RTS_ExecuteTerminationProcedures ();
>       _M2_hello_finish ();
>       _M2_M2EXCEPTION_finish ();
>       _M2_SysExceptions_finish ();
>       _M2_SysStorage_finish ();
>       _M2_Debug_finish ();
>       _M2_StdIO_finish ();
>       _M2_IO_finish ();
>       _M2_FIO_finish ();
>       _M2_termios_finish ();
>       _M2_errno_finish ();
>       _M2_Indexing_finish ();
>       _M2_NumberIO_finish ();
>       _M2_ASCII_finish ();
>       _M2_StrLib_finish ();
>       _M2_StrIO_finish ();
>       _M2_RTExceptions_finish ();
>       _M2_M2RTS_finish ();
>       _M2_SYSTEM_finish ();
>       _M2_Storage_finish ();
>       exit (0);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> int main (int argc, char *argv[])
> {
>    init (argc, argv);
>    finish ();
>    return (0);
> }
>
>
> or similarly for a shared library:
>
>    $ ~/opt/bin/gm2 -fshared -fmakeinit -c -g hello.mod
>    $ cat hello_m2.cpp
> extern "C" void exit(int);
>
> extern "C" void RTExceptions_DefaultErrorCatch(void);
> extern "C" void _M2_Storage_init (int argc, char *argv[]);
> extern "C" void _M2_Storage_finish (void);
> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
> extern "C" void _M2_SYSTEM_finish (void);
> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
> extern "C" void _M2_M2RTS_finish (void);
> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_RTExceptions_finish (void);
> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
> extern "C" void _M2_StrIO_finish (void);
> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
> extern "C" void _M2_StrLib_finish (void);
> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
> extern "C" void _M2_ASCII_finish (void);
> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
> extern "C" void _M2_NumberIO_finish (void);
> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
> extern "C" void _M2_Indexing_finish (void);
> extern "C" void _M2_errno_init (int argc, char *argv[]);
> extern "C" void _M2_errno_finish (void);
> extern "C" void _M2_termios_init (int argc, char *argv[]);
> extern "C" void _M2_termios_finish (void);
> extern "C" void _M2_FIO_init (int argc, char *argv[]);
> extern "C" void _M2_FIO_finish (void);
> extern "C" void _M2_IO_init (int argc, char *argv[]);
> extern "C" void _M2_IO_finish (void);
> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
> extern "C" void _M2_StdIO_finish (void);
> extern "C" void _M2_Debug_init (int argc, char *argv[]);
> extern "C" void _M2_Debug_finish (void);
> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
> extern "C" void _M2_SysStorage_finish (void);
> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_SysExceptions_finish (void);
> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
> extern "C" void _M2_M2EXCEPTION_finish (void);
> extern "C" void _M2_hello_init (int argc, char *argv[]);
> extern "C" void _M2_hello_finish (void);
>
> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>
> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>
> static void init (int argc, char *argv[])
> {
>    try {
>        _M2_Storage_init (argc, argv);
>        _M2_SYSTEM_init (argc, argv);
>        _M2_M2RTS_init (argc, argv);
>        _M2_RTExceptions_init (argc, argv);
>        _M2_StrIO_init (argc, argv);
>        _M2_StrLib_init (argc, argv);
>        _M2_ASCII_init (argc, argv);
>        _M2_NumberIO_init (argc, argv);
>        _M2_Indexing_init (argc, argv);
>        _M2_errno_init (argc, argv);
>        _M2_termios_init (argc, argv);
>        _M2_FIO_init (argc, argv);
>        _M2_IO_init (argc, argv);
>        _M2_StdIO_init (argc, argv);
>        _M2_Debug_init (argc, argv);
>        _M2_SysStorage_init (argc, argv);
>        _M2_SysExceptions_init (argc, argv);
>        _M2_M2EXCEPTION_init (argc, argv);
>       M2RTS_ExecuteInitialProcedures ();
>        _M2_hello_init (argc, argv);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> static void finish (void)
> {
>    try {
>       M2RTS_ExecuteTerminationProcedures ();
>       _M2_hello_finish ();
>       _M2_M2EXCEPTION_finish ();
>       _M2_SysExceptions_finish ();
>       _M2_SysStorage_finish ();
>       _M2_Debug_finish ();
>       _M2_StdIO_finish ();
>       _M2_IO_finish ();
>       _M2_FIO_finish ();
>       _M2_termios_finish ();
>       _M2_errno_finish ();
>       _M2_Indexing_finish ();
>       _M2_NumberIO_finish ();
>       _M2_ASCII_finish ();
>       _M2_StrLib_finish ();
>       _M2_StrIO_finish ();
>       _M2_RTExceptions_finish ();
>       _M2_M2RTS_finish ();
>       _M2_SYSTEM_finish ();
>       _M2_Storage_finish ();
>       exit (0);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> int main (int argc, char *argv[])
> {
>    init (argc, argv);
>    finish ();
>    return (0);
> }

So seeing the above the scaffold is only generated for the main program
translation unit - I suppose an application can consist of more than one
translation unit.  And the main TU compilation (recursively) will import
all other TUs (but they are compiled separately?).  Is there a well-defined
order the module initialization has to happen across a program?

I'm thinking of each m2 TU adding to a global initialization / finalization
vector thus adding

static initvec[] __attribute__((section("m2init"))) = { _M2_..._init,
_M2_..._init, ... };
static finivec[] __attribute__((section("m2fini"))) = {
_M2_..._finish, __M2_..._finish, ...};

and the main program just calling into the m2 runtime with the address
of the sections
which the would apply runtime sorting to weed out duplicates (or have
the individual
_init/_finish protect against multiple invocations).  That's of course
harder if the
initialization/finalization order is well-defined across the import
graph (or tree).

Of course the module objects could also emit meta-data so the runtime can
replicate the import graph.  Not sure if optimizing the compile or the runtime
is more important here.

> yes indeed all these programs could be placed into the front end,
> producing an IR GENERIC scaffold by default

It does look quite managable to create the above indeed.  You might want
to look into the C++ frontend creating global variable
initialization/finalization functions
for a TU like

struct X { X(); ~X(); } x;

Richard.

>
> regards,
> Gaius


More information about the Gcc-patches mailing list