/* * Bugzilla #25249: inconsistent code for template function calls. * * Also inefficient code, because template function instances are * called using "long calls", resulting in 4 words of code per call, * instead of 1. */ extern void h(int); template class Q { public: Q(); void f (); }; template void Q::f() { h(11); // avoid inlining h(12); h(13); h(14); h(15); h(16); h(17); h(18); h(19); } class U { public: int g(); Q& rx; }; int U::g() { rx.f(); rx.f(); } #if 0 /****************************************************************************** * Code produced by unpatched GCC 4.0.2. * arm-elf-gcc -S -O2 sample.cc * * f() is implemented as a weak external, to solve the template * instantiation problem. Weak externals may be overridden in some * other object file, so the code for f() may turn out to be silently * discarded by the linker. * * Therefore the compiler cannot assume that f() resides in the * regular text segment, and therefore uses long calls (32bit address) * instead of short calls (26bit distance). * * As of 2005, the CodeSourcery ARM compiler (GCCv3) does not use weak * functions for template instantiation thus does not show this * behaviour. * * Not that it is not just a minor optimization problem, but instead * seriously inconsistent behaviour for 2 reasons * * (1) When the definition of f() is removed, f() is called directly * because it is an external function like any other and not tagged as * "weak". * * (2) With tail call optimization in effect (-O2), the second call is * nevertheless done directly. */ .weak Q::f() Q::f(): [...] U::g(): stmfd sp!, {r4, lr} ldr r3, .L5 mov r4, r0 ldr r0, [r0, #0] mov lr, pc bx r3 ldr r0, [r4, #0] ldmfd sp!, {r4, lr} b Q::f() ///////////////////////////////////////////////////////////////////////////// /* * Code produced by patched GCC 4.1.0 (4.0.2 is similar, it's just * that my WinARM is an unpatched 4.0.2, my GNUARM a patched 4.1.0): * * I simply patched ./gcc/config/arm/arm.c:arm_encode_section_info to * call weak functions the same way as regular ones. * * Whatever the reasoning behind this treatment of "weak" externals * was, it is unlikely that it was ever used in C++ code, given the * inconsistencies show above. So when applied to the C++ backend * only (cc1plus.exe), it should not break any existing code. * + #if 1 + if (first && DECL_P (decl)) + { + if (! TREE_PUBLIC (decl)) + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); + } + #else if (first && DECL_P (decl)) { if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) *************** *** 13875,13880 **** --- 13885,13891 ---- else if (! TREE_PUBLIC (decl)) arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); } + #endif * */ U::g(): stmfd sp!, {r4, lr} mov r4, r0 ldr r0, [r0, #0] bl Q::f() ldr r0, [r4, #0] ldmfd sp!, {r4, lr} b Q::f() ///////////////////////////////////////////////////////////////////////////// #endif