4

One of the major uses of restrict keyword that was added to C99 is to allow compilers to load something into a register and assume that the register will mirror the state of the variable thus loaded. Given

void foo1(int * restrict a, int * restrict b) {
  (*a)++; (*b)++; (*b)+=(*a);
}

a compiler is entitled to assume that the write to (*b) will not have affected (*a), thus avoiding any need to reload (*a) after it. Does restrict have any other effects on aliasing? For example, given:

extern void foo2a(int * restrict q);
extern void foo2b(void);
int x;
int foo2(restrict int *q) {
  int z=x;
  x++; *q++; x++;
  foo2a(&z);
  x++; *q++; z++;
  foo2b();
  x++; *q++; z++;
  return x+(*q)+z;
}

would a compiler be required to anticipate that the increment of *q, and the calls to foo2a() and foo2b() might all have disturbed x, and that the calls might be "interested" in the value of x and *q? Would a compiler be required to assume that a call to foo2a() might have persisted its parameter--even though it was marked restrict, such that foo2b() could modify z?

If compilers would be required to operate under worst-case assumptions, despite the restrict keyword, is there any way to grant permission for a compiler to ignore any normal obligation to store any changes to certain variables prior to a function call and reload it the next time it's needed?

Ven
  • 19,015
  • 2
  • 41
  • 61
supercat
  • 77,689
  • 9
  • 166
  • 211
  • The `t1 == t2` problem can't be optimized away, because both could be null-pointers, which must compare equal. – EOF Apr 28 '15 at 19:22
  • @EOF: Given the edit, could the compiler omit the `t1==t2` check? – supercat Apr 28 '15 at 19:33
  • I believe it could, but a while ago I tried this, and couldn't get either gcc or clang to remove the check, *even for incompatible types*. The only way gcc omitted the check was an explicit `if (a == b) __builtin_unreachable()`. Whether it's a good idea to *rely* on that is a different question. – EOF Apr 28 '15 at 19:38
  • no it shouldn't. `restrict` qualified pointers are required to access distinct objects, but if `t1` or `t2` is not dereferenced, of if they are dereferenced using a disjoint set of offsets, they could be equal without violating the requirements implied by the `restrict` keyword. For instance, `memcpy(p,p,0);` is perfectly fine. – chqrlie Apr 28 '15 at 19:38
  • @chqrlie: Okay, thanks for that bit. I wonder if I should take out the last bit of the question to help direct focus toward the first bit? – supercat Apr 28 '15 at 19:51
  • Your syntax is wrong. The way you use `restrict` applies it to `int` (which is pointless) and not to `int*`. Use `int* restrict`. – Jens Gustedt Apr 28 '15 at 20:13
  • Also, please just ask one single question in one go. Yours is much to long and complicated. – Jens Gustedt Apr 28 '15 at 20:15
  • @JensGustedt: Syntax adjusted; question simplfied. Better? – supercat Apr 28 '15 at 20:19

1 Answers1

6

To answer just your question in the title: yes. A restrict qualified pointer means that you guarantee that the whole object in question can only be accessed through that pointer alone. That also means that it can't alias with file scope objects of the same type, e.g.

For the rest of the question, you are mixing things. restrict is by no means a guarantee of the caller. The caller doesn't even "see" the restrict keyword, the type qualification is not part of the interface. So whether or not a file scope variable may have changed when returning from a call has nothing to do with restrict.

restrict is only a guarantee that the caller gives to the callee who may then use the information internally for optimization.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • So referring to the example, `*q` cannot alias `x`, but `foo2a` and `foo2b` may both freely modify `*q`, `x`, and `z` [the first because a copy of the pointer could legitimately exist in a global variable; the second because it is a global variable, and the third because `foo2a` could legitimately have stashed a copy of `&z`?] – supercat Apr 28 '15 at 21:18
  • Yes, I think so, as soon as you leak information about the address of a variable in an opaque function call, you never can't be sure what any other function does with that variable. – Jens Gustedt Apr 28 '15 at 21:21
  • I wonder if C will ever standardize any means of distinguishing retained versus non-retained pointers, or pure versus impure functions? I would think a compiler armed with some knowledge could make some substantial optimizations not presently justified by the Standard. – supercat Apr 29 '15 at 15:13
  • Thinking about it, I'm not quite so sure that persisting a copy of a `restrict` pointer would be kosher except under very narrow circumstances (e.g. neither is ever written to, and nothing that will be accessed via the `restrict` pointer is written while the `restrict` pointer is in scope). If the function of `restrict` is to say that code which holds such a pointer may eagerly read from it anything which will either eventually be read or may be read without side-effects (e.g. seg-faults), and writes may be deferred until something else would be allowed to read the same locations... – supercat Apr 29 '15 at 15:59
  • ...I'm not quite clear how that would be affected if the lifetime of the restricted pointer was extended by copying it outside its original scope. – supercat Apr 29 '15 at 16:05