3

I need to access unaligned values using GCC vector extension

The program below crashes - in both clang and gcc

typedef int __attribute__((vector_size(16))) int4;
typedef int __attribute__((vector_size(16),aligned(4))) *int4p;

int main()
{
        int v[64] __attribute__((aligned(16))) = {};
        int4p ptr = reinterpret_cast<int4p>(&v[7]);
        int4 val = *ptr;
}

However if I change

typedef int __attribute__((vector_size(16),aligned(4))) *int4p;

to

typedef int __attribute__((vector_size(16),aligned(4))) int4u;
typedef int4u *int4up;

The generated assembly code is correct (using unaligned load) - in both clang and gcc.

What is wrong with single definition or what do I miss? Can it be the same bug in both clang and gcc?

Note: it happens in both clang and gcc

Artyom
  • 31,019
  • 21
  • 127
  • 215
  • If you do the typedef in 2 steps, one for the unaligned vector, then one for a pointer to that, it works. When you do it directly like here, the aligned attribute gets dropped somehow. Please file a bug report. – Marc Glisse Jan 30 '17 at 20:52
  • @MarcGlisse What do you mean typedef in two steps - how to define? – Artyom Jan 31 '17 at 07:21
  • @MarcGlisse I understand what you say but I found that the behaviour is similar for both clang and gcc. – Artyom Jan 31 '17 at 08:31
  • At this point I really think bugzilla is your best chance to get a clarification (and hopefully a fix). Note that if you don't have an account yet, you need to send an email to overseers (as explained on the account creation page) to get one. – Marc Glisse Jan 31 '17 at 08:58
  • @MarcGlisse Bug how is the same issue in both clang and gcc? – Artyom Jan 31 '17 at 09:15
  • Possible duplicate of [How can I apply \_\_attribute\_\_(( aligned(32))) to an int \*?](http://stackoverflow.com/questions/36211864/how-can-i-apply-attribute-aligned32-to-an-int) – ADMS Feb 04 '17 at 09:32

1 Answers1

7

TL;DR

You've altered the alignment of the pointer type itself, not the pointee type. This has nothing to do with the vector_size attribute and everything to do with the aligned attribute. It's also not a bug, and it's implemented correctly in both GCC and Clang.

Long Story

From the GCC documentation, § 6.33.1 Common Type Attributes (emphasis added):

aligned (alignment)

This attribute specifies a minimum alignment (in bytes) for variables of the specified type. [...]

The type in question is the type being declared, not the type pointed to by the type being declared. Therefore,

typedef int __attribute__((vector_size(16),aligned(4))) *int4p;

declares a new type T that points to objects of type *T, where:

  • *T is a 16-byte vector with default alignment for its size (16 bytes)
  • T is a pointer type, and the variables of this type may be exceptionally stored aligned to as low as 4-byte boundaries (even though what they point to is a type *T that is far more aligned).

Meanwhile, § 6.49 Using Vector Instructions through Built-in Functions says (emphasis added):

On some targets, the instruction set contains SIMD vector instructions which operate on multiple values contained in one large register at the same time. For example, on the x86 the MMX, 3DNow! and SSE extensions can be used this way.

The first step in using these extensions is to provide the necessary data types. This should be done using an appropriate typedef:

typedef int v4si __attribute__ ((vector_size (16)));

The int type specifies the base type, while the attribute specifies the vector size for the variable, measured in bytes. For example, the declaration above causes the compiler to set the mode for the v4si type to be 16 bytes wide and divided into int sized units. For a 32-bit int this means a vector of 4 units of 4 bytes, and the corresponding mode of foo is V4SI.

The vector_size attribute is only applicable to integral and float scalars, although arrays, pointers, and function return values are allowed in conjunction with this construct. Only sizes that are a power of two are currently allowed.

Demo

#include <stdio.h>

typedef int __attribute__((aligned(128))) * batcrazyptr;
struct batcrazystruct{
    batcrazyptr ptr;
};

int main()
{
    printf("Ptr:    %zu\n", sizeof(batcrazyptr));
    printf("Struct: %zu\n", sizeof(batcrazystruct));
}

Output:

Ptr:    8
Struct: 128

Which is consistent with batcrazyptr ptr itself having its alignment requirement changed, not its pointee, and in agreement with the documentation.

Solution

I'm afraid you'll be forced to use a chain of typedef's, as you have done with int4u. It would be unreasonable to have a separate attribute to specify the alignment of each pointer level in a typedef.

Iwillnotexist Idonotexist
  • 13,297
  • 4
  • 43
  • 66
  • It would make a lot of sense for the position of `__attribute__(...)` to determine on which (possibly inner) type it applies... – Marc Glisse Feb 01 '17 at 10:32
  • @MarcGlisse That would make sense, except can you imagine the horror of tracking all these subtypes within the compiler? It's bad enough you have to do that for `const/volatile`, now all these attributes! – Iwillnotexist Idonotexist Feb 01 '17 at 10:37
  • Uh, no horror, the compiler is tracking the inner types anyway, adding some attributes in there would not be any more complicated. – Marc Glisse Feb 01 '17 at 10:38
  • 1
    The current behavior where `typedef int*P;typedef P v __attribute__((vector_size(16)));` creates a pointer to a vector instead of a vector of pointers is really unnatural. – Marc Glisse Feb 01 '17 at 10:39
  • @MarcGlisse Don't quote me on that but IIRC `const/volatile` is dealt with by just two bit flags stuffed somewhere. I'm pretty sure many attributes would take far more space... At any rate GCC and Clang have had their `__attribute__` system out there too long, and didn't bother enforcing a particular position for that keyword within the type declaration. So there is now too much code that would break if suddenly enforcement became strict. – Iwillnotexist Idonotexist Feb 01 '17 at 10:44
  • @MarcGlisse Agreed. I was half-expecting vectorized pointers, but no: It seems `vector_size` applies to the ultimate pointee type, which must be a primitive type. – Iwillnotexist Idonotexist Feb 01 '17 at 10:46
  • 1
    attributes do indeed take more space to store than const (although many are special, in particular vector_size, and possibly aligned), but I thought we were talking about which syntax to use to realize a given type (that has some attributes on inner types), so the final type is given and occupies the space it does. I agree that syntax is unlikely to change :-( – Marc Glisse Feb 01 '17 at 10:49
  • Thank You... I expected __attribute__ behaves similarly to const. I still need to wait another 21 hours to award the bounty :-( – Artyom Feb 01 '17 at 11:46
  • @Artyom You don't need to give me the bounty immediately. You sank a considerable amount of rep into the bounty, which gave you here 1) an answer but also 2) wide exposure for 7 days. You can make back more of the rep you spent by leaving the bounty up, and collecting the extra rep from traffic. – Iwillnotexist Idonotexist Feb 01 '17 at 15:58