Hi,
Jason, this is about C++ frontend producing two copies of same type with
different TYPE_CANONICAL but same get_alias_set. Since the types are
structurally different, this does not go well with LTO which no longer
sees they are same. They are created in
if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t))
{
/* T needs a different layout as a base (eliding virtual bases
or whatever). Create that version. */
tree base_t = make_node (TREE_CODE (t));
and later cxx_get_alias_set arranges they have same set by testing
IS_FAKE_BASE_TYPE.
I am not able to come with a testcase that triggers wrong code with LTO
However compiling this testcase:
struct E {
~E();
virtual void f() const;
};
struct B : E {};
struct G : virtual B {};
struct A {
virtual ~A();
};
struct J : E {
int val;
~J() {if (val) __builtin_abort ();}
void f() const {
E *p = 0;
p->f();
}
};
J h;
struct I : A, G, virtual B {};
Front-end produce two versions of J that do not pass
gimple_canonical_types_compatible_p thus at compile time they have same
alias set and at LTO time they are considered non-conflicting.
Both types are mixed in one function:
J::~J (struct J * const this)
{
int _1;
struct E * _2;
<bb 2> [local count: 1073741824]:
this_4(D)->D.2376._vptr.E = &MEM <int (*__vtbl_ptr_type) ()[3]> [(void
*)&_ZTV1J + 16B];
_1 = this_4(D)->val;
if (_1 != 0)
goto <bb 3>; [0.00%]
else
goto <bb 4>; [100.00%]
<bb 3> [count: 0]:
abort ();
<bb 4> [local count: 1073741824]:
_2 = &this_4(D)->D.2376;
E::~E (_2);
MEM[(struct &)this_4(D)] ={v} {CLOBBER};
return;
}
Here "(struct &)" cast is turning struct J into the other, incompatible,
variant. I can't make FE to use the type anywhere else and this is why
I do not get wrong code since we sort of ignore the clobber then
(consider that the memory it guards is not used/initialized).
Jason, is there a way to actually read/write into the copied structure?
Putting same alias set but keeping canonical types different comfuses
same_type_for_tbaa, is there a reason why we do not make canonical types
same?
It seems to me that we want
1) use same TYPE_CANONICAL for both variants of the type
2) teach LTO canonical type merging about fake bases (i.e. add a
middle-end flag to do so).
Or can we avoid these types from getting into instruction stream?
(I suppose not - I guess point of using them in clobber is to get the
size right)
Honza