Диапазон непосредственных значений в сборке ARMv8 A64

Насколько я понимаю, непосредственные параметры в сборке ARMv8 A64 могут иметь длину 12 бит. Если это так, то почему эта строка ассемблерного кода:

AND X12, X10, 0xFEF 

Произведите эту ошибку (при компиляции с помощью gcc)

Error:  immediate out of range at operand 3 -- `AND X12, X10, 0xFEF'

Интересно, что эта строка ассемблерного кода прекрасно компилируется:

ADD X12, X10, 0xFEF

Я использую aarch64-linux-gnu-gcc (Linaro GCC 2014.11) 4.9.3 (предварительная версия)


person Zack    schedule 18.06.2015    source источник


Ответы (2)


В отличие от «гибкого второго операнда» A32, в A64 нет общего непосредственного формата. Для инструкций по обработке данных с немедленным операндом (игнорируя скучные и простые инструкции, такие как сдвиги),

  • Арифметические инструкции (add{s}, sub{s}, cmp, cmn) принимают 12-битное беззнаковое непосредственное значение с необязательным 12-битным сдвигом влево.
  • Инструкции перемещения (movz, movn, movk) принимают 16-битное непосредственное значение, которое может быть сдвинуто в любую позицию в регистре, выровненную по 16-битам.
  • Вычисления адресов (adr, adrp) берут 21-битное подписанное непосредственное значение, хотя нет фактического синтаксиса для его прямого указания - для этого вам придется прибегнуть к обману ассемблерных выражений, чтобы сгенерировать соответствующую «метку».
  • Логические инструкции (and{s}, orr, eor, tst) принимают "немедленную битовую маску", которую я не уверен, что смогу даже объяснить, поэтому я просто процитирую невероятно сложное определение:

Такой непосредственный образец представляет собой 32-битный или 64-битный шаблон, рассматриваемый как вектор идентичных элементов размера e = 2, 4, 8, 16, 32 или 64 бита. Каждый элемент содержит один и тот же подшаблон: один набор ненулевых битов от 1 до e-1, повернутых на биты от 0 до e-1. Этот механизм может генерировать 5334 уникальных 64-битных шаблона (как 2667 пар шаблонов и их побитовую инверсию).

person Notlikethat    schedule 18.06.2015
comment
Это объяснение имеет немного больше смысла: логические немедленные инструкции принимают немедленную битовую маску bimm32 или bimm64. Такое непосредственное состоит ЛИБО из одной последовательной последовательности, по крайней мере, с одним ненулевым битом и по крайней мере с одним нулевым битом в пределах элемента из 2, 4, 8, 16, 32 или 64 битов; затем элемент реплицируется по всей ширине регистра или побитовой инверсии такого значения. - person Zack; 18.06.2015
comment
Немедленное поле битовой маски руки составляет 13 бит (насколько я могу судить). Кто-нибудь точно знает, как интерпретируются эти биты (т. е. алгоритм преобразования этих 13 битов в 32- или 64-битное значение)? Почему этот алгоритм не так легко найти? - person Zack; 18.06.2015
comment
Я нашел здесь код, который может быть полезен: llvm.org/docs/doxygen/html/ - person Zack; 18.06.2015
comment
@Zack Как и во всем, полное авторитетное определение можно найти в псевдокоде инструкции в ARM ARM (бесплатная загрузка, но для принятия лицензии необходимо зарегистрироваться). В данном случае это функция DecodeBitMasks() в приложении псевдокода (страница J8-5588 в выпуске A.f). - person Notlikethat; 18.06.2015
comment
Непосредственные действия для побитовых инструкций не так уж сложно по крайней мере обобщить: это повторяющийся шаблон, в котором внутри одного элемента установленные биты должны быть смежными. - person Peter Cordes; 25.02.2021

Вот фрагмент кода для вывода всех допустимых битовых масок, следуя механизму, указанному в ответе Notlikethat. Надеюсь, это поможет понять, как работает правило создания непосредственных битовых масок.

    #include <stdio.h>
    #include <stdint.h>

    // Dumps all legal bitmask immediates for ARM64
    // Total number of unique 64-bit patterns: 
    //   1*2 + 3*4 + 7*8 + 15*16 + 31*32 + 63*64 = 5334

    const char *uint64_to_binary(uint64_t x) {
      static char b[65];
      unsigned i;
      for (i = 0; i < 64; i++, x <<= 1)
        b[i] = (0x8000000000000000ULL & x)? '1' : '0';
      b[64] = '\0';
      return b;
    }

    int main() {
      uint64_t result;
      unsigned size, length, rotation, e;
      for (size = 2; size <= 64; size *= 2)
        for (length = 1; length < size; ++length) {
          result = 0xffffffffffffffffULL >> (64 - length);
          for (e = size; e < 64; e *= 2)
            result |= result << e;
          for (rotation = 0; rotation < size; ++rotation) {
            printf("0x%016llx %s (size=%u, length=%u, rotation=%u)\n",
                (unsigned long long)result, uint64_to_binary(result),
                size, length, rotation);
            result = (result >> 63) | (result << 1);
          }
        }
      return 0;
    }
person Yan    schedule 21.10.2015
comment
Вы можете запустить вывод этого через сортировку, чтобы его было легче читать. - person Olsonist; 07.04.2019