On Dec 4, 2009, at 12:40 PM, Duncan Sands wrote:
> Hi Bill,
>
>> Here's what I get with TOT compiling with -Os. The orig.ll is what
>> I get before r72619. Notice that orig.ll has only one function in
>> it. Both the one you sent and duncan.ll have more than one
>> function. It's not the fact that more than one function is showing
>> up, but these functions in particular shouldn't be there because of
>> the implicit/explicit template instantiation stuff.
>
> there are several functions in the example you sent, some linkonce
> and some
> available_externally. Which ones shouldn't be there and why? Can
> you please
> give more details about why it is a problem - it was kind of hand-
> wavy so
> far :)
>
Only "_Z11dummysymbolv" should be there. Here's Doug's
explanation of
why this should be so:
Here's what it *looks* like is happening, and where the FE is probably
getting it wrong. First of all, the constructor in question is defined
outside of the basic_string class template as a non-inline definition:
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT, _Traits, _Alloc>::
basic_string(const _CharT* __s, const _Alloc& __a)
Second, there is an explicit template instantiation declaration:
extern template class basic_string<char>;
That extern template instantiation declaration is supposed to suppress
the implicit instantiation of non-inline member functions like that
basic_string constructor. I had tripped over something similar to this
previously, where the SL llvm-gcc was suppressing instantiation of all
member functions of basic_string<char> (including inline ones, which
would be a performance problem). So, there was clearly a change in
this area.
Here's my guess: We're not properly suppressing the implicit
instantiation of non-inline member functions defined out-of-line.
Thus, we're instantiating that basic_string constructor when we
shouldn't be. That instantiation then forces the implicit
instantiation of _S_construct<const char*>. Since _S_construct is a
member template, it's instantiation is *not* suppressed (despite being
in basic_string<char>), so we emit it as a weak definition.
I don't have a debug llvm-gcc available to see why this might be
happening. The logic to suppress instantiation based on an extern
template is in instantiate_decl (gcc/cp/pt.c):
/* Check to see whether we know that this template will be
instantiated in some other file, as with "extern template"
extension. */
external_p = (DECL_INTERFACE_KNOWN (d) && DECL_REALLY_EXTERN (d));
/* In general, we do not instantiate such templates... */
if (external_p
/* ... but we instantiate inline functions so that we can inline
them and ... */
&& ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d))
/* ... we instantiate static data members whose values are
needed in integral constant expressions. */
&& ! (TREE_CODE (d) == VAR_DECL
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (d)))
goto out;
For the basic_string constructor, if we don't take that "goto",
something is wrong. If we do take that "goto", my guess is wrong. I
don't have a recent debug llvm-gcc to validate my guess.