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. Ciao, Michael.