Как получить биты регистров спецификаций c xmm? - PullRequest
0 голосов
/ 05 августа 2020

Итак, я хочу получить значение или состояние определенных регистров c xmm. Это в первую очередь для журнала cra sh или просто для просмотра состояния регистров для отладки. Я пробовал это, но похоже, что это не работает:

#include <x86intrin.h>
#include <stdio.h>

int main(void) {

     register __m128i my_val __asm__("xmm0");
     __asm__ ("" :"=r"(my_val));
     printf("%llu %llu\n", my_val & 0xFFFFFFFFFFFFFFFF, my_val << 63);
  return 0;
}

Насколько мне известно, встроенные функции, относящиеся к store, не будут рассматривать __m128i как тип данных POD, а скорее как ссылка на один из регистров xmm.

Как мне получить и получить доступ к битам, хранящимся в __m128i как 64-битные целые числа? Или мой __asm__ выше работает?

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Как мне получить и получить доступ к битам, хранящимся в __m128i как 64-битные целые числа?

Вам нужно будет преобразовать вектор __m128i в пару uint64_t переменные. Вы можете сделать это с помощью встроенных функций преобразования:

uint64_t lo = _mm_cvtsi128_si64(my_val);
uint64_t hi = _mm_cvtsi128_si64(_mm_unpackhi_epi64(my_val, my_val));

... или хотя бы память:

uint64_t buf[2];
_mm_storeu_si128((__m128i*)buf, my_val);
uint64_t lo = buf[0];
uint64_t hi = buf[1];

Последний может быть хуже с точки зрения производительности, но если вы собираетесь его использовать только для отладки, подойдет. Также легко приспособиться к элементам разного размера, если вам это нужно.

Или мой __asm__ выше работает?

Нет, не работает. Ограничение вывода "= r" не позволяет использовать векторные регистры, такие как xmm0, которые вы передаете в качестве вывода, оно допускает только регистры общего назначения. Никакие регистры общего назначения не имеют ширины 128 бит, так что оператор asm не имеет смысла.

Кроме того, я должен отметить, что my_val << 63 сдвигает значение неверным образом. Если вы хотите вывести старшую половину гипотетического 128-битного значения, вам следовало бы сместить вправо, а не влево. Кроме того, сдвиги векторов либо не реализованы, либо действуют на каждый элемент вектора , а не на вектор в целом, в зависимости от компилятора. Но эта часть является спорным, так как с кодом выше вам не нужны какие-либо изменения на выходе две половинки.

0 голосов
/ 05 августа 2020

Если вы действительно хотите знать о значениях регистров , а не __m128i C значениях переменных, я бы предложил использовать отладчик, такой как GDB. print /x $xmm0.v2_int64 при остановке в точке останова.

Захват регистра в верхней части функции - довольно ненадежная и ненадежная вещь, чтобы попытаться попытаться (пахнет так, как будто вы уже упали неправильный расчетный путь) 1 . Но вы на правильном пути с локальной переменной register-asm. Однако xmm0 не может соответствовать ограничению "=r", только "=x". См. Чтение значения регистра в переменную C для получения дополнительной информации об использовании пустого шаблона asm, чтобы сообщить компилятору, что вы хотите, чтобы переменная C была тем, что было в регистре.

Однако вам нужен оператор asm volatile("" : "=x"(var));; Локальные переменные GNU C register-asm не имеют никаких гарантий, кроме случаев, когда они используются в качестве операндов для операторов asm. (G CC часто все равно будет хранить ваш var в этом регистре, но IIR C clang не будет.)

Нет большой гарантии относительно того, где это будет заказано. другой код (asm volatile может помочь некоторым, или для более сильного заказа также используйте "memory" clobber). Также нет гарантии, что G CC сначала не будет использовать регистр для чего-то другого. (Особенно регистр с закрытым вызовом, такой как любой регистр xmm.) Но он, по крайней мере, работает в версии, которую я тестировал.

print a __m128i variable показывает, как напечатать __m128i как две 64-битные половинки, если они у вас есть, или как элементы других размеров. Компилятор часто оптимизирует _mm_store_si128 / перезагружает в случайном порядке, и это в любом случае для печати, так что не усложняйте.

Использование unsigned __int128 tmp; также было бы вариантом в GNU C на x86-64.

#include <immintrin.h>
#include <stdint.h>
#include <stdio.h>
#ifndef __cplusplus
#include <stdalign.h>
#endif

// If you need this, you're probably doing something wrong.
// There's no guarantee about what a compiler will have in XMM0 at any point
void foo() {
    register __m128i xmm0 __asm__("xmm0");
    __asm__ volatile ("" :"=x"(xmm0));

    alignas(16) uint64_t buf[2];
    _mm_store_si128((__m128i*)buf, xmm0);
    printf("%llu %llu\n", buf[1], buf[0]);   // I'd normally use hex, like %#llx
}

При этом сначала печатается старшая половина (наиболее значимая), поэтому, читая слева направо по обоим элементам, мы получаем каждый байт в порядке убывания адреса памяти в пределах buf.

Он компилируется в asm мы хотим с G CC и clang ( Godbolt ), не наступая на xmm0 перед его чтением.

# GCC10.2 -O3
foo:
        movhlps xmm1, xmm0
        movq    rdx, xmm0                 # low half -> RDX
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        movq    rsi, xmm1                 # high half -> RSI
        jmp     printf

Footnote 1 :

Если вы убедитесь, что ваша функция не встроена, вы можете воспользоваться соглашением о вызовах, чтобы получить входящие значения xmm0..7 (для x86 -64 System V) или xmm0..3, если у вас нет целочисленных аргументов (Windows x64).

__attribute__((noinline))
void foo(__m128i xmm0, __m128i xmm1, __m128i xmm2, etc.) {
  // do whatever you want with the xmm0..7 args
}

Если вы хотите предоставить другой прототип функции для использования вызывающими абонентами (который опускает __m128i аргументы), это может сработать. Это, конечно, Undefined Behavior в ISO C, но если вы действительно прекратите встраивание, эффекты будут зависеть от соглашения о вызовах. Пока вы убедитесь, что это noinline, поэтому оптимизация времени компоновки не выполняет межфайловое встраивание.

Конечно, простой факт вставки вызова функции изменит распределение регистров в вызывающий, так что это помогает только для функции, которую вы все равно собирались вызвать.

...