Этот кусок кода (удваивающий 4-вектор) работает:
__declspec(align(16)) struct vec4 { float a[4]; };
int main()
{
vec4 c;
c.a[0]=2;
c.a[1]=0;
c.a[2]=0;
c.a[3]=0;
__asm {
movaps xmm1, c
addps xmm1, xmm1
movaps c, xmm1
}
}
Но этот фрагмент (делает то же самое, но теперь с указателем на выровненные данные):
__declspec(align(16)) struct vec4 { float a[4]; };
int main()
{
vec4* c = new vec4;
c->a[0]=2;
c->a[1]=0;
c->a[2]=0;
c->a[3]=0;
__asm {
movaps xmm1, c
addps xmm1, xmm1
movaps c, xmm1
}
}
Зачем?
Мне нужно, чтобы он работал с указателями, потому что я не могу использовать сами выровненные данные в качестве аргумента функции.
Указатель в ASM должен обрабатываться в соответствии с определенными правилами, которые вы можете узнать в значительной степени, изучив как работает «MOV».
По правилам Ассемблера, сначала нужно скопировать указатель в регистр процессора. тогда вы можете использовать его, чтобы указать на ячейку памяти.
vec4 *d = ...;
__asm {
mov eax, d
movaps xmm1, [eax]
addps xmm1, xmm1
movaps [eax], xmm1
}
Проблема в том, что объекты, созданные распределителем кучи (например, new и malloc), не следуют указанному выравниванию. Вы получаете выравнивание только с выделенным стеком объектом (ваш первый пример).
C ++ 11 поддерживает явное выравнивание объектов, выделенных через кучу с помощью alignas, но это пока не реализовано в VC ++. Это будет работать с некоторыми компиляторами, а не с другими.
У вас есть несколько вариантов.
Самый простой: создайте выделенный объект кучи, как вы это сделали, и скопируйте его в выделенный объект стека, прежде чем использовать его:
vec4* c = new vec4;
c->a[0]=2;
c->a[1]=0;
c->a[2]=0;
c->a[3]=0;
vec4 d = *c;
// process with d
Другой вариант заключается в том, чтобы ваша структура vec4 включала достаточно дополнительной памяти, чтобы вы гарантированно имели 16 байтов при 16-байтовом выравнивании. Я считаю, что новый гарантирует как минимум 4 байта выравнивания, поэтому 28 байтов сделали бы это. Затем вам нужно будет вручную проверить указатель, чтобы увидеть, где вы хотите хранить данные, которые будут использоваться с sse.