4

I'm reading through the source code of a library (QNNPack) and noticed this line (https://github.com/pytorch/QNNPACK/blob/24d57f21503ba8ab0f8bb5d24148754a91266b9c/src/q8gemm/6x4-neon.c#L23):

void funcName(..., 
    const union some_union_type some_union_arg[restrict static 1]) {
// ...
}

I understand the keyword restrict and static in general, but I'm afraid I do not know the reason behind this. I didn't find anything on Google, perhaps I searched wrong.

I'm guessing here it's a way of telling the compiler that this pointer points to a single object. But I lack the optimization knowledge to explain further.

Thanks!

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
TerryTsao
  • 565
  • 7
  • 16
  • 2
    It's not valid C++. So please don't add that tag. – StoryTeller - Unslander Monica Dec 20 '18 at 06:00
  • 1
    It doesn't appear to be valid C either [C11 Standard - 6.7.3 Type qualifiers(p2)](http://port70.net/~nsz/c/c11/n1570.html#6.7.3p2), `1` is not a *pointer type whose referenced type is an object type*. It would appear to be for a non-conforming implementation defined compiler. – David C. Rankin Dec 20 '18 at 06:10
  • 1
    @DavidC.Rankin - Eh, what? `int a [4]` and such are valid delcarators since 89. Later revisions just allow you to shove more stuff in there with them. – StoryTeller - Unslander Monica Dec 20 '18 at 06:14
  • Where I was looking is at the qualification of a numeric literal. I'm not finding support for that in the standard. I see (p7), but how are we restringing a numeric constant -- or is it just looked on as the guarantee of one element? – David C. Rankin Dec 20 '18 at 06:16
  • 2
    @DavidC.Rankin - 6.7.6.2p3. `D[ type-qualifier-list assignment-expression ]` - An integer constant is a valid assignment expression if we follow the grammar production. – StoryTeller - Unslander Monica Dec 20 '18 at 06:18
  • Hmm.. I'll have to keep working on it. 6.7.6.3(p7) speaks to the `static` qualifier appearing between `[..]`, but not the `restrict`, 6.7.3.2 would seem to prohibit it, but 6.7.6.2 does not foreclose it (while none provide an example of `restrict` used with a numeric constant, including [6.7.3.1 Formal definition of restrict](http://port70.net/~nsz/c/c11/n1570.html#6.7.3.1)) A lot to unpack here. I hate only having a cppreference.com explanation for it "It qualifies the pointer type to which the array type is transformed", but that seems to be as much as we are going to get. – David C. Rankin Dec 20 '18 at 06:36
  • @StoryTeller Sorry, wasn't aware of that. – TerryTsao Dec 20 '18 at 07:09

2 Answers2

2

static in this context carries the following meaning according to the C standard:

6.7.6.3 Function declarators (including prototypes)

7 ... If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

This is a semantic requirement on the program. If the caller to the function doesn't uphold it, the behavior is undefined and they have a bug they must fix. Since the size specified is 1, this means the function expects a valid pointer to a single union some_union_type object, and to pass it say NULL is undefined behavior in and of itself.

It's a way to specify in the prototype that the pointer passed must be valid. Compilers can leverage this info in theory and warn when null is passed. In practice this documents the requirement on that argument explicitly, and the function may even choose not to check the pointer is valid before accessing it (because the contract it specified in its prototype demands a valid pointer).

The restrict qualifier on the pointer means that the function assumes that pointer is the only way it will access this data, either directly or indirectly. So for instance, if you were to pass it the address of a global object that it accesses in its implementation, the behavior would be undefined. This assumption fosters optimizations by the compiler at certain places.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

Regarding the usage of static in your example, we have this:

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

Regarding the usage of restrict in your example, we have this:

In a function declaration, the keyword restrict may appear inside the square brackets that are used to declare an array type of a function parameter. It qualifies the pointer type to which the array type is transformed:

void f(int m, int n, float a[restrict m][n], float b[restrict m][n]);
void g12(int n, float (*p)[n]) {
   f(10, n, p, p+10); // OK
   f(20, n, p, p+10); // possibly undefined behavior (depending on what f does)
}

Taking the above together the example:

void funcName(..., 
    const union some_union_type some_union_arg[restrict static 1]) {
// ...
}

means that whenever funcName is called, the argument (some_union_arg) passed will have at least 1 element which the function will be able to access and this access is restricted through some_union_arg which has been transformed into a pointer.

P.W
  • 26,289
  • 6
  • 39
  • 76