On Fri, Sep 19, 2025 at 08:52:47AM +0200, Richard Biener wrote:
> > Some new ifn which is say:
> > *this = .POISON (this);
> > or
> > *this = .POISON (*this);
> > would be an option (which would expand to nothing if the pointers are the
> > same), dunno what would be easier to implement though.
> > I'll try artificial attribute on the this PARM_DECL.
> >
> > Richi, what is your preference from the middle-end POV?
> > Just a way to force -Wuninitialized/-Wmaybe-uninitialized warnings on
> > reads but similarly to .DEFERRED_INIT which sets to specific bytes
> > use whatever was in memory before.
I think the first question needs to be, do we throw those away during
inlining or not?
My preference would be that we do throw those away.
Consider say
struct A { A () {} int a; };
struct B : A { B () {} int b; };
struct C : B { C () {} int c; };
struct D : C { D () {} A a; B b; C c; };
void bar (D &);
void
foo ()
{
D d;
bar (d);
}
right now we get after einline
d ={v} {CLOBBER(bob)};
MEM[(struct C *)&d] ={v} {CLOBBER(bob)};
MEM[(struct B *)&d] ={v} {CLOBBER(bob)};
MEM[(struct A *)&d] ={v} {CLOBBER(bob)};
MEM[(struct A *)&d + 12B] ={v} {CLOBBER(bob)};
MEM[(struct B *)&d + 16B] ={v} {CLOBBER(bob)};
MEM[(struct A *)&d + 16B] ={v} {CLOBBER(bob)};
MEM[(struct C *)&d + 24B] ={v} {CLOBBER(bob)};
MEM[(struct B *)&d + 24B] ={v} {CLOBBER(bob)};
MEM[(struct A *)&d + 24B] ={v} {CLOBBER(bob)};
clobbers at the start, but all but the first one are useless. And
even if we don't inline everything, the clobber at the start of
a ctor not being inlined covers everything that needs to be clobbered
and later clobbers on it are just IL waste. When ctor is inlined
into the ultimate caller of the ctor, either there will be a normal
CLOBBER(bob) added by the patch for the whole variable or temporary
or with Jason's changes for new expression too.
> So a CLOBBER doesn't do because it might cause earlier writes to be
> DSEd (even if it itself doesn't alter storage)?
If it is dropped during inlining, that wouldn't be a problem.
But a problem would be say SRA or other optimizations optimizing
reads from the
[MEM[this] ={v} {CLOBBER(newkind)};
destination, we don't want optimize those to just _3(D) or some
smaller temporary initialized with a clobber. Except for -W*uninitialized
we need to treat it as what the memory contains is unknown.
Unless we tweak SRA (does e.g. SCCVN do that too?) for that new kind.
> I wonder if we can re-use .DEFERRED_INIT with a special mode here?
> Again I'm noticing we do not document internal-functions anywhere,
> in particular their expected signature or semantics ... :/
> >From internal-fn.cc it seems we have an INIT_TYPE parameter, can
> we add AUTO_INIT_KEEP_OLD or is AUTO_INIT_UNINITIALIZED already
> doing what we want here?
If we drop it during inlining, maybe, but same problem with SRA and maybe
SCCVN. We don't want for this case to see what PR121894 mentions,
that
MEM[(struct C *)this] = .DEFERRED_INIT (16, 6, &""[0]);
would be SRA optimized into
this$a_1 = .DEFERRED_INIT (4, 6, &""[0]);
this$b_2 = .DEFERRED_INIT (4, 6, &""[0]);
this$c_3 = .DEFERRED_INIT (4, 6, &""[0]);
this$d_4 = .DEFERRED_INIT (4, 6, &""[0]);
because for this kind we'd want to expand it into nothing at all, not having
to track which byte or whatever to read from which offset (which
.DEFERRED_INIT doesn't express, it is meant to set all bytes to the same
value).
Jakub