Ошибка: операнд вне диапазона (64 не между 0 и 31) - PullRequest
0 голосов
/ 01 ноября 2018

У меня страдает сборка GCC на PowerPC. Программа прекрасно компилируется с -g2 -O3, но не компилируется с -g3 -O0. Проблема в том, что мне нужно наблюдать за ним в отладчике, поэтому мне нужны символы без оптимизации.

Вот программа:

$ cat test.cxx
#include <altivec.h>
#undef vector

typedef __vector unsigned char uint8x16_p;

uint8x16_p VectorFastLoad8(const void* p)
{
  long offset = 0;
  uint8x16_p res;
  __asm(" lxvd2x  %x0, %1, %2    \n\t"
        : "=wa" (res)
        : "g" (p), "g" (offset/4), "Z" (*(const char (*)[16]) p));
  return res;
}

А вот и ошибка. (Ошибка существовала после замены PowerPC vec_xl_be с использованием встроенной сборки , но я могу игнорировать ее до сих пор).

$ g++ -g3 -O0 -mcpu=power8 test.cxx -c
/home/test/tmp/ccWvBTN4.s: Assembler messages:
/home/test/tmp/ccWvBTN4.s:31: Error: operand out of range (64 is not between 0 and 31)
/home/test/tmp/ccWvBTN4.s:31: Error: syntax error; found `(', expected `,'
/home/test/tmp/ccWvBTN4.s:31: Error: junk at end of line: `(31),32(31)'

Я считаю, что это больное место из списка * .s:

#APP
 # 12 "test.cxx" 1
         lxvd2x  0, 64(31), 32(31)

При использовании lwz сообщалось о некоторых похожих проблемах, но я не нашел ни одного, обсуждающего проблемы с lxvd2x.

В чем проблема и как ее исправить?


Вот заголовок файла *.s:

$ head -n 40 test.s
        .file   "test.cxx"
        .abiversion 2
        .section        ".toc","aw"
        .align 3
        .section        ".text"
        .machine power8
.Ltext0:
        .align 2
        .globl _Z15VectorFastLoad8PKv
        .type   _Z15VectorFastLoad8PKv, @function
_Z15VectorFastLoad8PKv:
.LFB0:
        .file 1 "test.cxx"
        .loc 1 7 0
        .cfi_startproc
        std 31,-8(1)
        stdu 1,-96(1)
        .cfi_def_cfa_offset 96
        .cfi_offset 31, -8
        mr 31,1
        .cfi_def_cfa_register 31
        std 3,64(31)
.LBB2:
        .loc 1 8 0
        li 9,0
        std 9,32(31)
        .loc 1 12 0
        ld 9,64(31)
#APP
 # 12 "test.cxx" 1
         lxvd2x  0, 64(31), 32(31)

 # 0 "" 2
#NO_APP
        xxpermdi 0,0,0,2
        li 9,48
        stxvd2x 0,31,9
        .loc 1 13 0
        li 9,48
        lxvd2x 0,31,9

Вот код, сгенерированный в -O3:

$ g++ -g3 -O3 -mcpu=power8 test.cxx -save-temps -c
$ objdump --disassemble test.o | c++filt

test.o:     file format elf64-powerpcle

Disassembly of section .text:

0000000000000000 <VectorFastLoad8(void const*)>:
   0:   99 06 43 7c     lxvd2x  vs34,r3,r0
   4:   20 00 80 4e     blr
   8:   00 00 00 00     .long 0x0
   c:   00 09 00 00     .long 0x900
  10:   00 00 00 00     .long 0x0

1 Ответ

0 голосов
/ 02 ноября 2018

Проблема в том, что сгенерированный 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", заставив компилятор использовать операнды регистров без смещения.

...