I am attempting to build CLN (and later, GiNaC) on my Windows XP machine with Mingw. I am using g++ 3.2.3 and the latest binary utilities. I have a build of GMP 4.2.1 for use as a backend for CLN (installed under c:\msys\1.0\local\). CLN was configured with CPPFLAGS=-I/usr/local/include LIBS=/usr/local/lib/libgmp-3.dll CXXFLAGS="-O2 -finline-functions -fomit-frame-pointer -march=i686 -finline-limit=1000" ./configure --with-gmp. The build progressed and after a couple hours the link failed for the shared library. It looks a lot like what was described on ginac-devel when a fellow had problems on Alpha (thread begins here: http://www.ginac.de/lists/ginac-devel/msg00091.html), except that I am using a relatively modern toolchain. The linker errors are of the form: cl_t_c2.lo(.text+0x4e):cl_t_c2.cc: undefined reference to `_GLOBAL__I_cl_module__cl_prin_globals__firstglobalfun' Any thoughts? -Jonathan Brandmeyer P.S. I am using msys to drive the build, but I do not want to use Cygwin.
Hi! On Fri, 31 Oct 2003, Jonathan Brandmeyer wrote:
I am attempting to build CLN (and later, GiNaC) on my Windows XP machine with Mingw. I am using g++ 3.2.3 and the latest binary utilities.
I have a build of GMP 4.2.1 for use as a backend for CLN (installed under c:\msys\1.0\local\).
CLN was configured with CPPFLAGS=-I/usr/local/include LIBS=/usr/local/lib/libgmp-3.dll CXXFLAGS="-O2 -finline-functions -fomit-frame-pointer -march=i686 -finline-limit=1000" ./configure --with-gmp.
The build progressed and after a couple hours the link failed for the shared library. It looks a lot like what was described on ginac-devel when a fellow had problems on Alpha (thread begins here: http://www.ginac.de/lists/ginac-devel/msg00091.html), except that I am using a relatively modern toolchain.
The linker errors are of the form: cl_t_c2.lo(.text+0x4e):cl_t_c2.cc: undefined reference to `_GLOBAL__I_cl_module__cl_prin_globals__firstglobalfun'
Any thoughts? -Jonathan Brandmeyer
P.S. I am using msys to drive the build, but I do not want to use Cygwin.
Sorry, no clue. I don't know of anyone using your toolchain. But I am sure that it should work at least on Cygwin since we've received some smallish patches (which've all made it into our tree). Wait! -finline-functions is something which is switched on with -O3 normally. Now, I do know that there used to be such unresolved symbols with -O3. Since not much else is switched on with -O3 (only register renaming), maybe that would be the culprit? Could you please try without -finline-functions and see how it goes?! BTW, as of GCC-3.4 (current CVS snapshot) CLN should now compile fine with full -O3 optimizations (which *does* make a difference, but only due to the new -funit-at-a-time option, not due to the passes already present in GCC-3.3). Luck -richy. -- Richard B. Kreckel <Richard.Kreckel@GiNaC.DE> <http://www.ginac.de/~kreckel/>
On Sat, 2003-11-01 at 08:51, Richard B. Kreckel wrote:
Hi!
Wait! -finline-functions is something which is switched on with -O3 normally. Now, I do know that there used to be such unresolved symbols with -O3. Since not much else is switched on with -O3 (only register renaming), maybe that would be the culprit? Could you please try without -finline-functions and see how it goes?!
Sorry it took so long to get back to you on this. The first time I did this I recieved several multiple definition errors. After a lot of digging I worked around the problem my not using MAYBE_INLINE in all of the places I recieved errors. In each case the code being declared MAYBE_INLINE was fairly large, certainly larger than I would consider for an inline function. I finally got a libcln-2.dll and both 'exam' and 'test' passed. I have a couple of additional questions. 1) Why does CLN use MAYBE_INLINE at all? Defining a function inline in one compilation unit and not inline in another sounds like a bad idea to me. 2) What does CLN do that interferes with GCC's function inlining logic such that all of those undefined references pop up? Thanks, Jonathan Brandmeyer
Hi! On Sat, 1 Nov 2003, Jonathan Brandmeyer wrote:
Wait! -finline-functions is something which is switched on with -O3 normally. Now, I do know that there used to be such unresolved symbols with -O3. Since not much else is switched on with -O3 (only register renaming), maybe that would be the culprit? Could you please try without -finline-functions and see how it goes?!
Sorry it took so long to get back to you on this. The first time I did this I recieved several multiple definition errors.
Sorry, I do not understand. The first time you did *what*? Switch *off* -finline-functions??
After a lot of digging I worked around the problem my not using MAYBE_INLINE in all of the places I recieved errors. In each case the code being declared MAYBE_INLINE was fairly large, certainly larger than I would consider for an inline function.
Well, this is why it is only *selectably* inlined, I guess. :-) Seriously, pointing a disassembler at the generated .o files I see that the stuff declared MAYBE_INLINE is generally quite small. There are a few exceptions, however. These exceptions are the functions defined in cl_RA_sqrt.cc, cl_I_from_NDS.cc and in all the cl_*_idecode.cc. I slightly wonder why they got marked MAYBE_INLINE, but frankly, I don't care too much.
I finally got a libcln-2.dll and both 'exam' and 'test' passed.
I have a couple of additional questions. 1) Why does CLN use MAYBE_INLINE at all? Defining a function inline in one compilation unit and not inline in another sounds like a bad idea to me.
Why? If it ends up not being inlined in not more than one compilation unit everything is fine! This technique makes inlining manually selectable, something which is otherwise not possible with plain C++ where you either declare your functions inline or you don't. Isn't it smoewhat strange that Standard C++ puts this decision *only* into the hands of the programmer of the callee? It does not furnish the programmer of the caller with any authority on the matter of inlining! There does seem to be some degree of consensus among the maintainers of GCC that the matter is indeed not entirely asymmetric, as it appears on first sight. This became clear during the course of the recent (heated) discussion about the meaning of the keyword "inline". There, it was asserted by some that the builtin case-by-case heuristics is usually better than the programmer's intuition. [Gaby: please don't shoot me now! The question boils down to whether the heuristics are better than a good C++ programmer's reasoning or a bad programmer's "intuition". Anyway, this is going too far.] But in the end, I haven't done the analysis which led to the decisions what to MAYBE_INLINE in CLN and what not. Bruno Haible did it back in the days of GCC 2.7, I guess. And I suppose that he did this as he usually does: by carefully reading the assembler output and basing these decisions on deeper insights than by looking at the sources. Bruno?
2) What does CLN do that interferes with GCC's function inlining logic such that all of those undefined references pop up?
Nothing. I think now you're confused. You were complaining about undefined references to functions like _GLOBAL__I_cl_module__foo_bar and similar in your first email, and these are entirely unrelated to the functions declared MAYBE_INLINE. I believe these issues are a compiler bug triggered by the PROVIDE/REQUIRE scheme in include/cln/modules.h when -finline-functions is turned on. Current GCC mainline does seem to be doing a better job, so I don't think anything should be "fixed" in CLN. Regards -richy. -- Richard B. Kreckel <Richard.Kreckel@GiNaC.DE> <http://www.ginac.de/~kreckel/>
Richard,
But in the end, I haven't done the analysis which led to the decisions what to MAYBE_INLINE in CLN and what not. Bruno Haible did it back in the days of GCC 2.7, I guess. And I suppose that he did this as he usually does: by carefully reading the assembler output and basing these decisions on deeper insights than by looking at the sources.
The need to inline a function in some places and not in others came from three situations: 1) Some functions, like cl_SF_zerop or cl_FF_zerop, are just a single machine instruction when inlined, but I don't want to put the inline definition into the .h file because that would expose too many internals of the library in the .h file (leading to 1. violation of abstraction, 2. increased compilation times). Still I want to use the inline version of these functions in the library itself. 2) Some functions, like cl_{SF,FF,DF,LF}_idecode, are usually only invoked through a dispatcher cl_F_idecode that does nothing but dispatch the call to the right function. Here inlining is used, regardless of the size of the inlined functions, because it removes one function call from the chain of function calls. A compiler cannot know that this caller is the main caller for the 4 inlined functions. 3) Similarly, cl_I_from_NDS would be a bottleneck if not inlined: every creation of a new cl_I goes through this function. A compiler cannot know a priori the bottlenecks. In each case, I read the assembler output in order to verify that g++ had really inlined the functions as I wished. Bruno
On Mon, 2003-11-03 at 15:10, Bruno Haible wrote:
Richard,
But in the end, I haven't done the analysis which led to the decisions what to MAYBE_INLINE in CLN and what not. Bruno Haible did it back in the days of GCC 2.7, I guess. And I suppose that he did this as he usually does: by carefully reading the assembler output and basing these decisions on deeper insights than by looking at the sources.
The need to inline a function in some places and not in others came from three situations:
1) Some functions, like cl_SF_zerop or cl_FF_zerop, are just a single machine instruction when inlined, but I don't want to put the inline definition into the .h file because that would expose too many internals of the library in the .h file (leading to 1. violation of abstraction, 2. increased compilation times). Still I want to use the inline version of these functions in the library itself.
2) Some functions, like cl_{SF,FF,DF,LF}_idecode, are usually only invoked through a dispatcher cl_F_idecode that does nothing but dispatch the call to the right function. Here inlining is used, regardless of the size of the inlined functions, because it removes one function call from the chain of function calls. A compiler cannot know that this caller is the main caller for the 4 inlined functions.
3) Similarly, cl_I_from_NDS would be a bottleneck if not inlined: every creation of a new cl_I goes through this function. A compiler cannot know a priori the bottlenecks.
In each case, I read the assembler output in order to verify that g++ had really inlined the functions as I wished.
Bruno
Thanks for the analysis. It turns out that not all of these functions are being inlined now, although I trust you when you say that they were in the past. Instead, several cases are being emitted as weak symbols out-of-line and then being linked against the global copy. Since weak symbols are not supported on MinGW (probably a PE/COFF limitation), they are instead causing multiple definition errors. There is a way to prevent this from happening. If the functions in question are defined like this: // Declaration qualifiers ret-type foo( args) FORCE_INLINE; MAYBE_INLINE ret-type foo( args) { ... } The calling functions can #define FORCE_INLINE to be __attribute__((always_inline)) to force inlining. This define must be provided before #including the header for the function being inlined. I cannot read assembly code. However, I have used the output from nm to verify the behavior I have described. Would you accept a patch that implemented this change? Thanks, Jonathan Brandmeyer
On Mon, 3 Nov 2003, Jonathan Brandmeyer wrote: [...]
Thanks for the analysis. It turns out that not all of these functions are being inlined now, although I trust you when you say that they were in the past. Instead, several cases are being emitted as weak symbols out-of-line and then being linked against the global copy. Since weak symbols are not supported on MinGW (probably a PE/COFF limitation), they are instead causing multiple definition errors.
Perhaps a naive question: If there is no support for weak symbols or something like this, then the compiler is forced to always inline whenever somebody says "inline", right? How then, does the compiler handle extreme cases where inlining cannot be done because of recursions, mutually inlined functions, and other such things??? I can't believe this is the ultimate answer.
There is a way to prevent this from happening. If the functions in question are defined like this:
// Declaration qualifiers ret-type foo( args) FORCE_INLINE;
MAYBE_INLINE ret-type foo( args) { ... }
The calling functions can #define FORCE_INLINE to be __attribute__((always_inline)) to force inlining. This define must be provided before #including the header for the function being inlined.
I cannot read assembly code. However, I have used the output from nm to verify the behavior I have described. Would you accept a patch that implemented this change?
Only grudginly so. But if this turns out to work and there *really* is no other way on that platform, then possibly. Cheers -richy. -- Richard B. Kreckel <Richard.Kreckel@GiNaC.DE> <http://www.ginac.de/~kreckel/>
On Tue, 2003-11-04 at 17:12, Richard B. Kreckel wrote:
Perhaps a naive question: If there is no support for weak symbols or something like this, then the compiler is forced to always inline whenever somebody says "inline", right? How then, does the compiler handle extreme cases where inlining cannot be done because of recursions, mutually inlined functions, and other such things???
After browsing the assembly code, it looks like "or something like this". If a function is marked inline and emitted out of line, it is placed into a section named ".text$[mangled name of the function]". The next line is ".linkonce discard" Normal functions are simply placed in the ".text" section. I am guessing that the linker can resolve all of the specially named sections to a single one, but cannot resolve that down to an identically named function in the ".text" section.
Only grudginly so. But if this turns out to work and there *really* is no other way on that platform, then possibly.
I'll ask on the binutils list to see if there is a workaround. Besides, if Mr. Haible needed those functions inline for performance, than isn't the fact that they are not being inlined, even on Linux, a bug in its own right? -Jonathan Brandmeyer
Hi! On Tue, 4 Nov 2003, Jonathan Brandmeyer wrote: [...]
Only grudginly so. But if this turns out to work and there *really* is no other way on that platform, then possibly.
I'll ask on the binutils list to see if there is a workaround.
That effort would be highly appreciated.
Besides, if Mr. Haible needed those functions inline for performance, than isn't the fact that they are not being inlined, even on Linux, a bug in its own right?
Errr, yes, but... Wait, that's a good piece of sophistic dialectics! *If* he needed those functions inline for performance, *then* it would be a bug. But since you never actually *need* something for performance but rather just *long* for it. I would say that it would be a (less severe) optimization issue. \end{nitpick} What are those functions that aren't being inlined, even on Linux? I just checked the most obvious candidates by browsing the generated assembler and they all appear inlined on my compilation using GCC-3.3.2 with "-O2 -fno-exceptions". Let me also point out that the fact whether any function ends up being inlined or not highly depends on how CXXFLAGS are set. Namely the flags -finline-limit=<n> --param max-inline-insns-single=<m1> --param max-inline-insns-auto=<m2> --param max-inline-insns-rtl=<m3> do have a significant effect, independent of the platform. So, on your platform, the success of the whole compilation depends on such tunable compiler parameters? If that would be true it would be quite unfortunate. Cheers -richy. -- Richard B. Kreckel <Richard.Kreckel@GiNaC.DE> <http://www.ginac.de/~kreckel/>
participants (3)
-
Bruno Haible
-
Jonathan Brandmeyer
-
Richard B. Kreckel