Проблема в том, что сгенерированный asm имеет операнды регистр + смещение для RA и RB, но инструкция lxvd2x
принимает только прямые адреса регистров (т. Е. Без смещений).
Похоже, что вы неправильно поняли ограничения. Глядя на встроенный ассм:
__asm(" lxvd2x %x0, %1, %2 \n\t"
: "=wa" (res)
: "g" (p), "g" (offset/4), "Z" (*(const char (*)[16]) p));
Во-первых, у вас есть один выходной операнд и три входных операнда (всего четыре), но только три операнда используются в вашем шаблоне.
Я предполагаю, что ваша функция читает непосредственно из *p
, и она ничего не сжимает, поэтому похоже, что это неиспользуемый операнд для указания потенциального доступа к памяти (подробнее об этом ниже). Сейчас мы будем простыми; сбросив это дает нам:
__asm(" lxvd2x %x0, %1, %2 \n\t"
: "=wa" (res)
: "g" (p), "g" (offset/4));
При компиляции я все еще получаю смещение, используемое для RA и / или RB:
lxvd2x 0, 40(31), 9
Глядя на документы для ограничения "g"
, мы видим:
'г':
Допускается любой регистр, память или непосредственный целочисленный операнд,
за исключением регистров, которые не являются общими регистрами.
Однако мы не можем предоставить здесь операнд памяти; разрешен только регистр (без смещения). Если мы изменим ограничение на "r"
:
__asm(" lxvd2x %x0, %1, %2 \n\t"
: "=wa" (res)
: "r" (p), "r" (offset/4));
Для меня это компилируется в действительный lxvd2x
вызов:
lxvd2x 0, 9, 10
- что радостно принимает ассемблер.
Теперь, как прокомментировал @PeterCordes, этот пример больше не указывает, что он может обращаться к памяти, поэтому мы должны восстановить эту зависимость ввода памяти, давая:
__asm(" lxvd2x %x0, %1, %2 \n\t"
: "=wa" (res)
: "r" (p), "r" (offset/4), "m" (*(const char (*)[16]) p));
Фактически, все, что мы сделали, изменили ограничения с "g"
на "r"
, заставив компилятор использовать операнды регистров без смещения.