2009-10-28 3 views
2

Ok, donc je suis juste de commencer à utiliser C intrinsics dans mon code et j'ai créé une classe, qui a simplifié ressemble à ceci:utilisant C intrinsics et des difficultés d'alignement de mémoire avec les classes

class _Vector3D 
{ 
public: 
_Vector3D() 
{ 
    aVals[0] = _mm_setzero_ps(); 
    aVals[1] = _mm_setzero_ps(); 
    aVals[2] = _mm_setzero_ps(); 
} 
~_Vector3D() {} 
private: 
__m128 aVals[3]; 
}; 

Jusqu'à présent, si bien . Mais quand je crée une deuxième classe avec les membres _Vector3D, je reçois des problèmes:

class RayPacket 
{ 
public: 
RayPacket() {orig = _Vector3D(); dir = _Vector3D(); power = _mm_setzero_ps();} 
~RayPacket() {} 

RayPacket(_Vector3D origins, _Vector3D directions, float pow) 
{ 
    orig = origins; 
    dir = directions; 
    power = _mm_set_ps1(pow); 
} 

_Vector3D orig; 
_Vector3D dir; 
__m128 power; 
}; 

Je reçois l'erreur suivante:

erreur C2719: « origines »: paramètre formel avec __declspec (alignement ('16')) ne seront pas alignés

montrant la surcharge du constructeur:

RayPacket(_Vector3D origins, _Vector3D directions, float pow) 

Alors je vais sur ce dans le mauvais sens? Dois-je utiliser des structures à la place ou puis-je le faire fonctionner avec des classes?

+0

Pourquoi passez-vous soudainement à flotter de __m128? – Bill

+3

Problèmes avec vos identifiants. Les identfiers commençant par underscore suivis d'une lettre capitale et les identifiants contenant deux underscores consécutifs sont réservés par l'implémentation. Les utiliser entraînera des problèmes sur la route. –

+2

Juste pour noter - vous semblez avoir un petit malentendu sur SSE. Vous appelez '_Vector3D' ce qui devrait être une matrice ** 3x4 **. chacun des __m128 est un ensemble de 4 flotteurs. – LiraNuna

Répondre

4

Cette réponse est basée sur la documentation et les devinettes, pas la connaissance réelle. Il faut se méfier!

Le documentation for __m128 dit:

Variables of type _m128 [sic] are automatically aligned on 16-byte boundaries.

Ainsi, à l'aide d'un membre __m128 dans votre classe, cela force le compilateur d'aligner les instances de votre classe sur les limites de 16 octets. Implicitement, __declspec(align(16)) est ajouté à votre classe, mais c'est not allowed on function parameters car il est difficile (impossible?) Pour le compilateur d'appliquer l'alignement dans les cadres de la pile.

Pour contourner ce problème, essayez passer les arguments du constructeur par référence:

RayPacket(_Vector3D const &origins, _Vector3D const &directions, float pow) 
0

Essayez de passer _Vector3D par référence const, comme dans:

 
RayPacket(const _Vector3D& origins, const _Vector3D& directions, float pow); 
Ça va mettre des pointeurs au lieu des valeurs sur la pile d'appel.

+0

qui aide, merci – Nigel

4

Je pense que le problème est que le compilateur ne peut pas garantir que le pointeur de la pile sera correctement aligné quand il va créer un objet _Vector3D sur la pile pour passer au constructeur. Sur les systèmes 32 bits, les pointeurs de pile sont généralement alignés sur 4 octets (parfois 8 octets alignés) et sur les systèmes 64 bits, je pense que le pointeur de la pile est généralement aligné sur 8 octets. compilateur ne sait pas quand il va appeler le constructeur que la pile sera alignée correctement. Vous devrez peut-être passer un pointeur ou une référence.

Notez que malloc() et amis, l'alignement garanti retourné pour un bloc n'est parfois pas garanti pour être en mesure de gérer des types spéciaux comme celui-ci. Dans ce cas, une plate-forme aura une fonction d'allocation spéciale pour allouer ces objets.

Voir les éléments suivants pour plus de détails sur MSVC (http://msdn.microsoft.com/en-us/library/aa290049.aspx):

Stack Alignment

On both of the 64-bit platforms, the top of each stackframe is 16-byte aligned. Although this uses more space than is needed, it guarantees that the compiler can place all data on the stack in a way that all elements are aligned.

The x86 compiler uses a different method for aligning the stack. By default, the stack is 4-byte aligned. Although this is space efficient, you can see that there are some data types that need to be 8-byte aligned, and that, in order to get good performance, 16-byte alignment is sometimes needed. The compiler can determine, on some occasions, that dynamic 8-byte stack alignment would be beneficial—notably when there are double values on the stack.

The compiler does this in two ways. First, the compiler can use link-time code generation (LTCG), when specified by the user at compile and link time, to generate the call-tree for the complete program. With this, it can determine regions of the call-tree where 8-byte stack alignment would be beneficial, and it determines call-sites where the dynamic stack alignment gets the best payoff. The second way is used when the function has doubles on the stack, but, for whatever reason, has not yet been 8-byte aligned. The compiler applies a heuristic (which improves with each iteration of the compiler) to determine whether the function should be dynamically 8-byte aligned.

Note A downside to dynamic 8-byte stack alignment, with respect to performance, is that frame pointer omission (/Oy) effectively gets turned off. Register EBP must be used to reference the stack with dynamic 8-byte stack, and therefore it cannot be used as a general register in the function.

L'article ci-dessus lié a également des informations sur les fonctions de tas spéciales qui offrent des garanties d'alignement supérieures à celles de l'malloc() standard si vous avez besoin que.

Questions connexes