The motivation is to be able to optimize dynamic initialization of
things with vague linkage, as in this C++ code:
struct my_id { my_id() : v_(0) {} int v_; }; template <typename T> struct Foo { static my_id id; }; template <typename T> my_id Foo<T>::id; int main() { Foo<char>::id.v_++; }
Here, we have a class with a non-trivial, non-constexpr default
constructor, and we instantiate a static data member of a class template
of that type.
Normally, globalopt refuses to modify initializers of globals with weak
linkage because it has no way of knowing if the linker will select the
modified or unmodified global, or if there will be some duplicate
initializer that performs the same effect twice.
However, when the initializer modifies the global used as its comdat key
in llvm.global_ctors, we know that, in the Microsoft C++ ABI, if
globalopt succeeds and the modified global prevails at link time, all of
the other initializers will be discarded.
The Itanium C++ ABI does not (currently) provide a guarantee that the
.init_array entry will be in the same comdat group as the global, so it
instead requires that the compiler emit a guard variable check to
prevent double initialization as described here:
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#guards
I felt it was best to make globalopt check the triple, even though in
practice, the Itanium guard variable check blocks globalopt because the
guard variable is in its own comdat group and has weak linkage.
Fixes PR39712
If the IR doesn't have enough information to distinguish between the Microsoft and Itanium ABI cases, we should extend the IR to contain more information. Checking the triple means we're depending on semantic guarantees which are not documented in LangRef, and many not apply to non-C++ languages.