0

gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

How to align void * referencing entity with no declared type to a cache line size in a conforming way?

I'm interested to explain the legitimacy of the common alignment technique with Standard.

My attempt

void *ptr = //some valid pointer;
void *aligned_ptr = (void *) ((intptr_t) ptr & -64);

The (intptr_t) ptr & -64 part is conforming since any 7.20.1.4 N2310:

an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void , and the result will compare equal to the original pointer

Converting (intptr_t) ptr & -64 back to void * is not specified to have well-defined behavior. 6.3.2.3/5 provides some blurred information (emp. mine):

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

If I correctly understand the concept of the "trap representation" then it is not possible to have it in such case since there is not declared type of the object.

I'm not sure if (void *) ((intptr_t) ptr & -64) is correctly aligned from the Standard standpoint or the result is not an implementation defined.

UPD: 6.2.8 Describes

Every valid alignment value shall be a nonnegative integral power of two.

Since _Alignof (max_align_t) is 16 on my implementation then I suppose the 64 byte alignment is not obligated to be supported by gcc.

Some Name
  • 8,555
  • 5
  • 27
  • 77
  • Does this answer your question? [How to align a pointer in C](https://stackoverflow.com/questions/4840410/how-to-align-a-pointer-in-c) – 273K Apr 29 '20 at 17:29
  • @S.M. Not really. I'm mostly interested in the Standard compliance behind it which is not provided in the QA you referenced. – Some Name Apr 29 '20 at 17:31
  • 1
    As the standard says, except from conversion from pointer to integer and back the behavior is implementation-defined. Since you're using GCC: [When casting from pointer to integer and back again, the resulting pointer must reference the same object as the original pointer, otherwise the behavior is undefined](https://gcc.gnu.org/onlinedocs/gcc/Arrays-and-pointers-implementation.html). So, unless your pointer has already been aligned to a cache line, the behavior of your code is undefined. – Language Lawyer Apr 29 '20 at 18:07
  • 1
    _"except from conversion from pointer to integer and back the behavior is implementation-defined"_ Oops. Confused with the C++ standard. In C standard, even conversions to integers and back are implementation-defined, unless the pointer value is null or integer is zero. – Language Lawyer Apr 29 '20 at 18:14
  • @LanguageLawyer Looks like that was what I wanted. Especially the part _That is, one may not use integer arithmetic to avoid the undefined behavior of pointer arithmetic as proscribed in C99 and C11 6.5.6/8_ – Some Name Apr 29 '20 at 18:14
  • 2
    What you are trying to do in your snippet is unclear. What do you want to achieve by "adjusting" a pointer like that? If it does not point to a valid object, then it's pointless. This seems like an XY problem. The correct way to align something to a cache line is to just declare it padded to the needed size using `__attribute__((aligned(64))` or similar compiler directives. Needless to say, this cannot be made in a generic non compiler-specific way. There is no standard-defined way to "conformingly align" something to cache. – Marco Bonelli Apr 29 '20 at 18:32
  • @MarcoBonelli Seems you are right. One question is why you used gcc-specific `__attribute__` instead of the standardized `_Alignas`? – Some Name Apr 29 '20 at 18:39
  • 1
    Re “If I correctly understand the concept of the "trap representation" then it is not possible to have it in such case since there is not declared type of the object.” the result of the conversion to `void *` may be a trap representation of the `void *` type. – Eric Postpischil Apr 29 '20 at 18:43
  • 1
    @SomeName just because it's C11, I wouldn't opt into C11 just for such an insignificant feature. I also was assuming you were talking about C99, since it's the most common version of the standard to refer to. – Marco Bonelli Apr 29 '20 at 18:43
  • @EricPostpischil Agree. But if the source `void *` does not have a trap representation can a pointer "aligned" the way I described above have a trap representation? – Some Name Apr 29 '20 at 18:46
  • @MarcoBonelli: Re “What you are trying to do in your snippet is unclear. What do you want to achieve by "adjusting" a pointer like that?” They are seeking to locate the start of a cache line relative to a given address. This is a common technique in code working near a hardware level. For example, a high-performance matrix multiply routine might, given source and destination addresses, locate the boundaries of nearby cache lines so that partition the work efficiently based on cache geometry and memory use patterns. – Eric Postpischil Apr 29 '20 at 18:47
  • @MarcoBonelli: Re “The correct way to align something to a cache line is to just declare it padded to the needed size using __attribute__((aligned(64)) or similar compiler directives.”: That is not the point; the goal is not to define/create an object favorably positioned but to find the cache line boundaries with respect to an existing object. Things like this are a common need in high-performance libraries that must service whatever requests are made of them. – Eric Postpischil Apr 29 '20 at 18:51
  • @EricPostpischil seems a bit far-fetched really, but I guess that'd be a possible scenario... – Marco Bonelli Apr 29 '20 at 18:51
  • @MarcoBonelli: Re “This seems like an XY problem.”: It is not; this is routine work in high-performance software. – Eric Postpischil Apr 29 '20 at 18:52
  • @MarcoBonelli: Re “seems a bit far-fetched really”: It is mot; this is routine. E.g., Apple’s Accelerate framework has plenty of casts to `uintptr_t` and back, with intervening manipulations. That is largely what the type is for, to enable programs to work with raw hardware addresses. – Eric Postpischil Apr 29 '20 at 18:54
  • Re “I'm not sure if `(void *) ((intptr_t) ptr & -64)` is correctly aligned from the Standard standpoint or the result is not an implementation defined.”: The C standard is silent on the alignment of the result of that expression. That code is conforming (is accepted by some conforming C implementation) but not strictly conforming (fully defined by the C standard). It will do what you desire in C implementations that support writing kernel code or high-performance code, since such code needs these features, but support for that must be guaranteed by the C implementation, not the C standard. – Eric Postpischil Apr 29 '20 at 19:01

1 Answers1

1

If you really want a generic solution, maybe use union and optionally some preprocessor macros.

union myptr{
    void *ptr;
    (whatever-type-that-meets-your-padding-requirment) padding;
};

union myptr myalignedptr;
#define alignedptr (myalignedptr.ptr)       /* optional */
user12986714
  • 741
  • 2
  • 8
  • 19