Is it enough to only restrict the “out”-(pointer-)parameters of a function?

Suppose I have a function which takes some pointer parameters – some non-const, through which it may write, and some const through which it only reads. Example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void f(int * a, int const *b);
</code>
<code>void f(int * a, int const *b); </code>
void f(int * a, int const *b);

Suppose also that the function does not otherwise write to memory (i.e. doesn’t use global variables, fixed addresses, recasting the const pointers as non-const and such tricks).

Now, is it sufficient (as per the C language standard), for achieving the benefits of restrict for all reads within f(), to only restrict the output parameters? i.e. in the example, restrict a but not b?

A simple test (GodBolt) suggests such restriction should be sufficient. This source:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>int f(int * restrict a, int const * b) {
a[0] += b[0];
return a[0] + b[0];
}
int all_restricted(int * restrict a, int const * restrict b) {
a[0] += b[0];
return a[0] + b[0];
}
int unrestricted(int * a, int const * b) {
a[0] += b[0];
return a[0] + b[0];
}
</code>
<code>int f(int * restrict a, int const * b) { a[0] += b[0]; return a[0] + b[0]; } int all_restricted(int * restrict a, int const * restrict b) { a[0] += b[0]; return a[0] + b[0]; } int unrestricted(int * a, int const * b) { a[0] += b[0]; return a[0] + b[0]; } </code>
int f(int * restrict a, int const * b) {
    a[0] += b[0];
    return a[0] + b[0];
}

int all_restricted(int * restrict a, int const * restrict b) {
    a[0] += b[0];
    return a[0] + b[0];
}

int unrestricted(int * a, int const * b) {
    a[0] += b[0];
    return a[0] + b[0];
}

Produces the same object code for x86_64:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>f:
mov eax, DWORD PTR [rsi]
mov edx, DWORD PTR [rdi]
add edx, eax
mov DWORD PTR [rdi], edx
add eax, edx
ret
all_restricted:
mov eax, DWORD PTR [rsi]
mov edx, DWORD PTR [rdi]
add edx, eax
mov DWORD PTR [rdi], edx
add eax, edx
ret
unrestricted:
mov eax, DWORD PTR [rsi]
add eax, DWORD PTR [rdi]
mov DWORD PTR [rdi], eax
add eax, DWORD PTR [rsi]
ret
</code>
<code>f: mov eax, DWORD PTR [rsi] mov edx, DWORD PTR [rdi] add edx, eax mov DWORD PTR [rdi], edx add eax, edx ret all_restricted: mov eax, DWORD PTR [rsi] mov edx, DWORD PTR [rdi] add edx, eax mov DWORD PTR [rdi], edx add eax, edx ret unrestricted: mov eax, DWORD PTR [rsi] add eax, DWORD PTR [rdi] mov DWORD PTR [rdi], eax add eax, DWORD PTR [rsi] ret </code>
f:
        mov     eax, DWORD PTR [rsi]
        mov     edx, DWORD PTR [rdi]
        add     edx, eax
        mov     DWORD PTR [rdi], edx
        add     eax, edx
        ret
all_restricted:
        mov     eax, DWORD PTR [rsi]
        mov     edx, DWORD PTR [rdi]
        add     edx, eax
        mov     DWORD PTR [rdi], edx
        add     eax, edx
        ret
unrestricted:
        mov     eax, DWORD PTR [rsi]
        add     eax, DWORD PTR [rdi]
        mov     DWORD PTR [rdi], eax
        add     eax, DWORD PTR [rsi]
        ret

but that’s not a general guarantee.

7

No, it is not enough.

Suppose also that the function does not otherwise write to memory (i.e. doesn’t use global variables, fixed addresses, recasting the const pointers as non-const and such tricks).

This supposition is insufficient. It would also be necessary that the compiler see the function does not otherwise write to memory that the pointer points to (including any memory that could be accessed via the pointer, such as b[18]). For example, if the function f calls bar(b);, and the compiler cannot see bar, then it cannot know whether memory that b points to is modified during execution of f, even if it is not.

Give this additional premise, that the compiler can see there are no modifications to any memory pointed to via b, then it does not matter for optimization whether b is declared with const and/or restrict: The compiler knows everything about the memory, and telling it anything more does not add information.

However, it is often not the case that code satisfies this premise. (And even when it does, it may be a nuisance for a programmer to be sure of it.) So let’s consider a case when we do not have the additional premise:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void f(int * restrict a, int const *b)
{
printf("%dn", *b);
bar();
printf("%dn", *b);
}
</code>
<code>void f(int * restrict a, int const *b) { printf("%dn", *b); bar(); printf("%dn", *b); } </code>
void f(int * restrict a, int const *b)
{
    printf("%dn", *b);
    bar();
    printf("%dn", *b);
}

When bar is called, the compiler does not know whether *b is modified. Even though this function does not pass b to bar, bar might access some external object that is *b or has a pointer to where *b is, and so bar can change the object that is *b. Therefore, the compiler must reload *b from memory for the second printf.

If instead we declare the function void f(int * restrict a, int const * restrict b), then restrict asserts that, if *b is modified during execution of f (including indirectly, inside bar), then every access to it will be via b (directly, as in *b, or indirectly, as through a pointer visibly copied or calculated from b). Since the compiler can see bar does not receive b, it knows bar does not contain any accesses to *b that are based on b, and therefore it may assume bar does not change *b.

Therefore, adding restrict to a parameter that is a pointer to a const-qualified type may enable some optimizations, even if all other parameters are also declared restrict.

1

Suppose I have a function which takes some pointer parameters – some
non-const, through which it may write, and some const through which it
only reads. Example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void f(int * a, int const *b);
</code>
<code>void f(int * a, int const *b); </code>
void f(int * a, int const *b);

Suppose also that the function does not otherwise write to memory
(i.e. doesn’t use global variables, fixed addresses, recasting the
const pointers as non-const and such tricks).

Now, is it sufficient (as per the C language standard), for achieving
the benefits of restrict for all reads within f(), to only restrict
the output parameters? i.e. in the example, restrict a but not b?

restrict is one-sided. It licenses the compiler to make assumptions about object accesses via lvalues “based on” the restrict-qualified pointer that do not depend on whether any other pointer is also restrict-qualified.

In particular, if you restrict parameter a then regardless of whether you also restrict parameter b, you license the compiler to assume that during any given execution of f(),

  • if L is any lvalue whose address is “based on” a, and
  • L is used to access the object it designates (read or write), and
  • that object is modified by any means during the function’s execution, then
  • every access to that object (read or write) during the execution of that function will be performed via an lvalue whose address is “based on” a, though not necessarily via L in particular.
  • (For example, that object will not be accessed via an lvalue “based on” b but not on a.)

That is laid out in more detail in C17 section 6.7.3.1, though that text is both complex and a bit fraught.

Thus, in the case you describe, restricting only a entitles the compiler to assume that reads via pointers derived from b will never observe writes via pointers derived from a. Whether it actually will generate different code is an entirely different question, of course.

2

The const keyword as shown will cause a warning or error if you attempt to modify the value pointed by the pointer, but it will not necessarily prevent you from modifying that value, and it certainly will not prevent someone else from modifying that value. Thus, the compiler may have to assume that such modifications may take place.

For example, if you invoke some function defined in a different source file, the compiler will have no knowledge of what that function does, so it will have to assume that the function may somehow have access to the value pointed by that pointer and it may modify it.

Furthermore, even as you modify the value pointed by the non-const pointer, that non-const pointer may be pointing to the same value as the const pointer. (As in, f( &x, &x );) Without restrict on the const pointer, the compiler has to assume that this is also a possibility.

Therefore, even the const parameter could benefit from the restrict keyword, because it promises that the memory pointed by that pointer will not be modified by anyone. Essentially, you would be promising that you are never going to do something like f( &x, &x );.

9

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật