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.