On Tue, Oct 4, 2011 at 1:55 PM, Michael Matz <m...@suse.de> wrote:
> Hi,
>
> On Mon, 3 Oct 2011, Jakub Jelinek wrote:
>
>> std::vector acts roughly as something having a restrict pointer field,
>> i.e. two different std::vector objects will have the pointers pointing to
>> a different array, unfortunately unlike e.g. std::valarray we have 3
>> different pointers pointing into the array instead of 1, and we can't change
>> it without breaking the ABI.  This patch adds an extension, where several
>> pointer fields in the same structure can be marked as being a group for
>> restrict purposes (so the ISO C99 restrict wording would for them not
>> mandate that all accesses are made through pointers based on say _M_start,
>> but through pointers based on any of the fields in the group (_M_start,
>> _M_finish or _M_end_of_storage in the std::vector case).
>
> Ugh, that's stretching our fragile to unsafe restrict support quite much.
> IMO beyond what we can reasonably be confident to not cause
> miscompilations.  Essentially what you're implicitely assuming is that the
> sources of restrict tags can ultimately be memory, and that this is
> somehow reliable.  It unfortunately isn't.
>
> Keep in mind that the whole current restrict-tag support was designed to
> support fortrans specific needs where we can rely on the compiler
> generating code we most probably (!) won't miscompile later.  Further we
> interpret some of the part where ISO-C says nothing in our favor.
> Together this means that e.g. (intentionally _not_ ISO-C, but sort of
> middle-end speak):
>
> foo (struct s)
> { restrict int *p1 = s.p;
>  restrict int *p2 = s.p;
>  *p1 = 0; *p2 = 1; return *p1;
> }
>
> depends on optimization.  We either generate two restrict tags for p1 and
> p2 (this currently happens when there's no CSE of s.p), or we generate
> only one for p1 and p2 (that's what currently happens with CSE).
>
> Note that both interpretations make sense.  One tag makes sense to make
> the above function work as the user expected (returning 1, not 0).  Two
> tags make sense that this case could be optimized:
>
> foo (struct s)
> { restrict int *p1 = s.p;
>  restrict int *p2 = s.p;
>  ... accesses of p1[2*i] and p2[2*i+1] intermixed ...
>  ... we expect to be able to disambiguate both sets purely because of
>      restrict tags ...
> }
>
> We will generate new tags when the source of the load is _not_ restrict
> qualified (conversion that introduce restrict generate new tags).  We will
> generate only one tag when the load _is_ restrict qualified _and_ memory
> CSE has eliminated one of the loads.
>
> In any case, right now the middle end sees memory-loads of restrict
> qualified pointers as source of new restrict tags (and depends on
> optimizations if that isn't what is wanted).  This all works more or less
> for fortran because the array->data pointer usually is loaded only once
> for one array, or at least later memory optimizations come and optimize
> away superflous loads.  For fortran at least we currently _rely_ on such
> memory optimizations to take place in case there are multiple accesses to
> one array (as each of them should better have the same restrict tag).
> Luckily if we disable such optimizations we still can't write
> miscompiled testcases because we would as well disable the transformations
> that make use of the invalid restrict info.  But we certainly should be
> able to create fortran testcases where the restrict tags clearly are
> wrong with disabled memory optimizations.
>
> So, loads generate new tags, and we rely on optimizations that this
> doesn't cause miscompilations via invalid disambiguations, which works
> fine for the restricted set of cases coming from the fortran frontend.
>
> You introduce even more freedom to this mud.  Effectively:
>
> foo (struct s)
> { restrict int *p1 = s.p;
>  restrict int *p2 = s.q; // same restrict tag as s.p
> }
>
> You're giving the user rope to specify the comment part.  For
> this to not cause miscompilations you absolutely rely on that request to
> not be merely a hint.  The problem is that there's no guarantee that it
> isn't lost:
>
> foo_abstract (restrict *p1, restrict *p2)
> { ... p1 and p2 have different tags ... }
> foo { foo_abstract (s.p, s.q); }
>
> or
>
> user does pointer to member games:
>
> foo (struct s)
> { restrict **pp1 = &s.p;
>  restrict **pp2 = &s.q;
>  ... mem clobber ...
>  restrict *p1 = *pp1;
>  restrict *p2 = *pp2;  // generate new tag for p2
> }
>
> Or our own lowering for MEM_EXPR:
>
> foo (struct s)
> { restrict *p1 = MEM[s, 0];
>  restrict *p2 = MEM[s, 4]; // new tag for p2
> }
>
> Granted, you're trying to look at the type of s to reconstruct the
> field_decl, but that might be misleading when enough obfuscations are
> present.  For fortran it's impossible to generate any of the breaking
> situations above.
>
> All in all the restrict tag support is extremely fragile when it comes to
> tag source from loads, and deep down even unsafe for generic cases, hence
> I don't think to increase its exposal into that generic direction is a
> good idea.

Even more so, annotating libstdc++ with that but being chicken enough
to not have a malloc attribute annotated ::new is - interesting ;)

Richard.

Reply via email to