Noalias for dummies

I have not really a clue what the noalias keyword does.

When can we use it to optimize?

If you have a function that takes in two pointers there are certain optimizations you can make if you can assume that the pointers don’t point to the same memory or overlap. I think the most basic example is if you have pointers a and b and you write to a you can still assume that the value in b did not change. For example @memcpy(noalias dest, noalias source) void uses this optimization.

Edit: The official documentation has like no info on this but going off of the similar C keyword restrict I think this means that there is no other alias to this memory

1 Like

Aha, so it only makes sense with two or more parameters?

If you watched this:

You know about memory regions. Basically noalias makes it so pointers marked by it are guarantied to point in unique memory region. For example here Compiler Explorer even though functions only accepts one parameter second case with noalias is still more optimal since compiler knows pointer can’t point to global and it won’t load global twice.

I think the design of alias in Zig hasn’t been fully finalized yet, which is why the related keyword lacks documentation.

The impact of noalias is reflected in @memcpy and @memmove. The former prohibits overlapping memory copies, allowing for better performance, while the latter allows overlapping memory copies, resulting in worse performance.

Languages like C have rules such as ‘strict aliasing,’ which assume that two pointers of ‘non-compatible types’ do not point to overlapping memory. This is a very controversial feature, and at least Linus does not agree with it.

As far as I know, Zig should also not adhere to strict aliasing rules, but perhaps this means that passing any two pointers, regardless of whether they are of the same type, could potentially be optimized further by specifying noalias.

In addition, when using LLVM’s backend, it still seems to try to make some strict aliasing assumptions, which leads to unexpected results.

Now that is very strange for me…
What is a “unique memory region”?
Isn’t a ptr parameter just at one (unique) memory location when passed as argument??
I completely don’t get it… But I will watch that youtube link.

Here, both bar and baz could point to the same location in memory, since the compiler can’t prove that, this isn’t the case it can’t do anything about memory reordering, which in this case doesn’t matter but in a larger function you could loose some optimizations.

pub fn foo(bar : *i32, baz : *i32) i32 {
    bar.* = 1;
    baz.* = 2;
// here the result is actually 2 if baz points to the same location as bar
    return = bar.*; 
}
pub fn foo(noalias bar : *i32, noalias baz : *i32) i32 {
    bar.* = 1;
    baz.* = 2;
// here the result is 1 because baz can't point to the same memory location as bar, it doesn't alias.
    return = bar.*;
}

noalias for dummies

Simply never use it.

2 Likes