1

I use intrinsics so I need to use memory alignment. By this reason I always code like:

float* data = (float*) _mm_malloc(sizeof(float)*3, 64);

But in some cases I have arrays with mixed content. So some parts are aligned and some not.

I tried to use simple test data%64 == 0 but compiler throws error: expression must have integral type. Operation modulo is not supported for pointers.

Is it possible to implement function which works like this:

// prototype
int testAlignment(void *pointer, int alignment);

float* data = (float*) _mm_malloc(sizeof(float)*3, 64);
testAlignment(data, 64); // true
testAlignment(data + 1, 64); // false
NtsDK
  • 951
  • 1
  • 9
  • 19
  • 4
    `((uintptr_t)(void*)data)%64u == 0` works. Check it yourself. – user2736738 Feb 25 '18 at 18:23
  • I know the compiler will probably optimize this anyway, but `(((uintptr_t)(void*)data)&63u) == 0` might be a better way to describe alignment. *Sidenote*: `malloc` will return maximum alignment by default (on my 64bit machine, that would be 128bits due to the maximum integer type width the CPU handles). – Myst Feb 25 '18 at 18:29
  • @Myst: Do you realize your sidenote is irrelevant, when we are talking about intrinsics? `malloc()` alignment is not sufficient for vector types. – Nominal Animal Feb 25 '18 at 18:35
  • @NominalAnimal 64 bit alignment might not be sufficient for some vector types, but it **is** the alignment in the example... ;) – Myst Feb 25 '18 at 18:43
  • @Myst I work with AVX512 and in my example alignment is in bytes. – NtsDK Feb 25 '18 at 19:52
  • Oh, right, my bad... got confused for a moment :-p – Myst Feb 25 '18 at 20:16

2 Answers2

3

The % operator needs integer operands. So how to convert a pointer to an integer?

Any pointer type may be converted to an integer type. ..., the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. C11 §6.3.2.3 5

Consider the below, the conversion of a float * to an unsigned likely will work, yet it risks undefined behavior (UB).

float* data = foo();
if ((unsigned)data % 64 == 0) puts("aligned 64"); 

Can we do better?

A pointer to void may be converted to or from a pointer to any object type. §6.3.2.3 1

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type ... uintptr_t ... These types are optional §7.20.1.4 1

Yes, by converting to void* and then to uintptr_t, code avoids UB @coderredoc. Still uintptr_t is an optional type. Yet rarely is it unavailable since C99.

#include <stdint.h>
if ((uintptr_t)(void*)data % 64 == 0) puts("aligned 64"); 
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-2

Reminder operation is not defined for pointers, but you can cast the pointer to integer.

((unsigned)data % 64) == 0

will do the trick.

freim
  • 596
  • 2
  • 10
  • Look at coderredoc's comment to see why it was up-voted and this was down-voted. Then steal his answer to update yours - he should have posted an answer rather then a comment in any case. – Clifford Feb 25 '18 at 19:59
  • @Clifford - Exactly what do you want me to steal? That unnecessary cast to void*? I don't think it will improve the answer. Replacing % with & may be a better idea, bit it is pure aesthetic anyway - the compiler always optimizes division to power of two. – freim Feb 26 '18 at 12:37
  • 1
    The cast to `void*` is not strictly unnecessary, it is the only pointer type for which `uintptr_t` is defined, and `uintptr_t` is necessary because `unsigned` may not be large enough to hold a pointer - typically so on 64 bit and 16 bit systems. Possibly that does not matter since only the last 6 bits are of interest. It is academic now, @chux has posted that answer. You had the right idea, but got downvoted through lack of rigour. I was hoping to save you from that. – Clifford Feb 26 '18 at 13:33
  • You might perhaps add information to justify why this will work on any platform, but the UB police will downvote it regardless, and avoiding it is straightforward. – Clifford Feb 26 '18 at 13:40
  • Personally I like the `&` idea in preference to `%`. In other cases you might have a variable alignment test, which might not be trivially optimised. – Clifford Feb 26 '18 at 13:44
  • @Clifford - I did consider casting to ULONG_PTR (yes, I know, but uintptr_t is not portable either), but decided that truncating to 32 bits will result to more efficient and portable code. And no, I don't want to edit a perfectly correct answer just because some people downvote anything that does not fit their scholastic view of programming style. Anyway, thanks for understanding. – freim Feb 26 '18 at 15:21
  • §6.3.2.3 5 is not applicable here as it says something different. It refers to a hypothetical case of pointers that cannot be represented by integers. And in that hypothetical case of UB no cast will work properly - be it (uintptr_t)(void*) or just (unsigned). – freim Feb 26 '18 at 15:40