Page 1 of 1

Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 10:41 am
by NickJohnson
I know that C99 and above allow some degree of control over which pointers the compiler believes are aliased, through strict aliasing and the restrict keyword. However, sometimes I want to declare two differently-typed pointers to be explicitly aliased (without using -fno-strict-aliasing on the whole file), for correctness reasons, and sometimes I want to declare two same-typed pointers to be explicitly not aliased (without using restrict, which implies that nothing is aliased to each pointer), for performance reasons. Basically, I'd like a pair of assume_aliased(p1, p2) and assume_not_aliased(p1, p2) functions/macros.

I was wondering if this is possible, if not in normal C99/C11, using some sort of GCC or Clang extension. From looking through the list of GCC builtins, I can't seem to find anything that does either thing outright. Can anyone thing of something more subtle (or even super-hacky) that would convey the information to the compiler? It seems like explicit aliasing data from the programmer would be a compiler-writer's dream...

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 1:08 pm
by Icee
Not exactly what you are looking for, but Clang has __builtin_assume() that hints the compiler that an arbitrary expression is true at a given point in the program. I'm not sure whether this affects the way alias analysis works, though.

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 3:18 pm
by NickJohnson
Yeah, I've been looking at stuff like that. The problem is, there's no expression (that I can think of) that is true if and only if two pointers are thought to be possibly aliased by the compiler. That's what you'd need to build this out of the existing assume/assert builtins.

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 3:22 pm
by kzinti
You would have to set the default compiler settings to assume aliasing is always possible and then use __builtin_assume( ptr1 != ptr2 ) where you know there is no aliasing.

Far from perfect... You really want it the other way :(

Do you have an example where you want two pointers of different types to be aliased? I don't believe I've run into this myself.

As for your second use case, two pointes of the same type not aliasing each other, wouldn't __builtin_assume( ptr1 != ptr2 ) work?

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 5:06 pm
by NickJohnson
kiznit wrote:Do you have an example where you want two pointers of different types to be aliased? I don't believe I've run into this myself.
That's definitely the less common case; I mostly want to be able to declare that two pointers are definitely not aliased. Still, there are cases, especially in OS development, where you want to violate the strict aliasing rule. IIRC, the Linux kernel to this day sets -fno-strict-aliasing, because there are enough key points where type punning is necessary.
kiznit wrote:As for your second use case, two pointes of the same type not aliasing each other, wouldn't __builtin_assume( ptr1 != ptr2 ) work?
No, because ptr1 != ptr2 is not a sufficient condition for non-aliasing, at least in C/C++. For example:

Code: Select all

void foo(char *ptr1) {
    char *ptr2 = &ptr1[1];
    assert(ptr1 != ptr2); // does not fail
    // but, ptr2[2] = 3 makes ptr1[1] == 3
    // so the pointers still may alias
}
So, the compiler can't safely infer just from that assert/assume that the pointers don't alias, which means it won't.

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 5:18 pm
by kzinti
I'm still really curious about an actual use case.

I've written lot of low level game console code and been dealing with aliasing forever. Yet I've never encountered a case where I needed to do what you ask for. Using restrict (and very rarely assume) has always been enough. Granted some of it ended up coded in assembly, still... If it was that useful, I would think that there would be a GCC builtin for this, but there isn't.

I can understand that Linux would turn strict aliasing off because it has a lot of existing code that would break with it. But if you are writing code with strict aliasing in mind from day 1, I believe you should be able to accomplish what you need with the existing restrict keyword.

Your char* example doesn't apply to type-punning. Type-punning can be done with a union (it's not conformant, yet it works on all known compilers, including GCC under strict aliasing rules). If you really want to be conformant, use a memcpy() for type punning.

Re: Overriding C aliasing rules precisely

Posted: Tue Jul 28, 2015 7:03 pm
by NickJohnson
It just seems strange to me that it's not possible to convey arbitrary aliasing arrangements. I haven't run into a case yet where it is absolutely necessary. I also haven't run into a case where __builtin_assume() or __builtin_unreachable() are absolutely necessary either, however; being able to help the optimizer is a good thing though.

Also, I realize that my example doesn't cover type-punning, which is probably the more common case. I just wanted to show a counterexample to the idea that ptr1 != ptr2 implies dereferencing ptr1 and per2 cannot cause aliasing, because that's the thing stopping the compiler from inferring precise aliasing information in all cases.

Re: Overriding C aliasing rules precisely

Posted: Wed Jul 29, 2015 4:03 am
by cyr1x
There's a may_alias attribute for clang and probably gcc.

Re: Overriding C aliasing rules precisely

Posted: Wed Jul 29, 2015 7:31 am
by NickJohnson
may_alias
Accesses to objects with types with this attribute are not subjected to type-based alias analysis, but are instead assumed to be able to alias any other type of objects, just like the char type. See -fstrict-aliasing for more information on aliasing issues.
That could be pretty useful, actually.

It's still much broader than what I'm talking about, because it indicates that a pointer may alias anything, not just some other specific pointer. Aliasing is inherently a pairwise relationship, so it's unlikely that any attribute on a single variable will be able to express it precisely.