Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ aliasing rules

Tags:

Just wondering if someone would confirm a few aliasing rules for me.

I know that aliasing (i.e load-store issues) could cause the following type of code to be suboptimal, because we can't assume that x, y, z don't overlap:

// case 1: void plus(size_t n, double *x, double *y, double *z) {     for (size_t i = 0; i != n; ++i)         z[i] = x[i] + y[i]; }  

I know that there's a C keyword __restrict that hints to the compiler that it shouldn't consider the overlapping case, and hence potentially generate better code:

// case 2: void plus(size_t n, double *__restrict x, double *__restrict y, double *__restrict z) { // as above... } 

But how does aliasing work with C++ style code, where we would be dealing with container objects passed by reference, rather than the C-like examples above with raw pointers??

For instance, I'm assuming that there would be aliasing issues if we did the following:

// case 3: void plus(std::vector<double> &x, std::vector<double> &y, std::vector<double> &z) { // similar to above... } 

And to move to a less trivial example, does it make any difference if the underlying data types in the containers are different?? At the implementation level most containers dynamically manage storage with pointers, so it's not clear to me how the compiler could ensure that the following doesn't alias:

// case 4: void foo(std::vector<mytype1> &x, std::vector<mytype2> &y) { // interwoven operations on x, y... } 

I'm not trying to micro-optimise, but I'm wondering if it's currently better to pass restricted pointers to containers around, rather than references.

EDIT: To clear up some terminology, as pointed out: restrict is the C99 keyword. There's also __restrict and __restrict__ in various compilers, but they all do the same thing.

like image 800
Darren Engwirda Avatar asked Jun 12 '11 07:06

Darren Engwirda


People also ask

Does C have strict aliasing?

From the article: "Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias each other.)"

What is pointer aliasing in C?

Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.

Can alias be given to pointers?

If a function has two pointers pa and pb , with the same value, we say the pointers alias each other. This introduces constraints on the order of instruction execution. If two write accesses that alias occur in program order, they must happen in the same order on the processor and cannot be re-ordered.

What is aliasing in programming?

An alias occurs when different variables point directly or indirectly to a single area of storage. Aliasing refers to assumptions made during optimization about which variables can point to or occupy the same storage area.


2 Answers

According to the strict-aliasing rule, you are not allowed to alias the same memory with pointers to different types (except char* and friends), so case 4 could only apply if one of the types was a char*.

Case 3 though isn't all that different from case 1, as references are implemented as pointers on all compilers I know, though the standard doesn't demand that and an implementation is free to come up with something else.

like image 117
Xeo Avatar answered Oct 04 '22 02:10

Xeo


It's not specific at all to C++. Consider this C99 bit:

struct vector {     double* data;     size_t n; };  void plus(struct vector* restrict x, struct vector* restrict y, struct vector* restrict z) {     // same deal as ever } 

Here, restrict buys us very little: x->data, y->data and z->data are all double* and are allowed to alias. This is exactly like case 1, even when using restrict.

If there were a restrict keyword in C++ (or when using an extension), the best bet would probably to do plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0]), using the same plus as in case 2. And in fact it's possible to do this right now, using a C89-style interface without restrict but that uses the keyword under the covers.

like image 22
Luc Danton Avatar answered Oct 04 '22 00:10

Luc Danton