Как мне переместить константу с плавающей запятой в регистр FP?

Итак, я программирую на сборке ARM, используя набор инструкций A64. Я использую инструкцию fmov d1, # ​​31.0 для перемещения значений в регистр dx. Однако, когда я использую 0,0 или любое значение выше 31,0, отображается ошибка:

"Error: invalid floating-point constant at operand 2 -- `fmov d1,#32.0'"

Итак, как мне определить константу с плавающей запятой в A64? Почему я не могу использовать значение выше 31 или использовать 0? Как я могу представить значения в шестнадцатеричном формате?

Другой вопрос: согласно веб-сайту руки, он поддерживает использование регистров с плавающей запятой, таких как Bx, Hx, Sx, Dx и Qx (8,16,34,64 и 128 бит соответственно), но я просто не могу использовать Bx, Hx и Qx показывает:

"Ошибка: несоответствие операнда -`fmov b1,#1.0'"

"Ошибка: выбранный процессор не поддерживает`fmov h1,#2.0 "

"Ошибка: несоответствие операнда - `fmov q1,#2.0'"

Как правильно установить второй операнд?

2 ответа

Только очень небольшой набор констант с плавающей запятой можно использовать с fmovпотому что константа кодируется как 8 бит непосредственно в инструкции. В частности, он должен быть представлен как ±n/ 16 × 2r, где n - целое число в диапазоне 16 ≤ n ≤ 31, а r - целое число в диапазоне -3 ≤ n ≤ 4.

Точный список поддерживаемых номеров приведен в Справочном руководстве по архитектуре ARMv8. Дополнительно, fmovдоступен только для размеров данных 16, 32 и 64 бит, поскольку для ARMv8 не указаны 8-битные или 128-битные форматы с плавающей запятой. Для ядер ARMv8, не поддерживающих FEAT_FP16, 16-битный размер данных также не поддерживается. ARMv8 не хватает ортогональности во многих подобных местах; не все инструкции доступны для всех размеров операндов.

Для простого альтернативного решения используйте ldrвместо этого с константой в литеральном пуле (которую вам нужно вручную перевести в целое число). Например, чтобы загрузить 32.0, переведите 32.0 в его представление IEEE 754, давая вам 0x4040000000000000. Затем вы можете загрузить эту константу следующим образом:

ldr d1, =0x4040000000000000

В ldrинструкция с регистром SIMD и FP и значение в литеральном пуле доступны с размерами операндов 32, 64 и 128 бит. Меньшие размеры операндов недоступны для режимов адресации буквального пула. Если вы хотите загрузить 8- или 16-битный регистр, вместо этого загрузите соответствующий 32-битный регистр.

Немного более быстрое решение - сначала загрузить желаемое число в регистр общего назначения (который поддерживает более гибкую генерацию немедленных значений), а затем переместить его в регистры SIMD и FP:

mov x0, #0x4040000000000000
fmov d1, x0

Загрузить 0.0 или маски, используйте moviинструкция. Набор допустимых немедленных действий для этой инструкции зависит от размера операнда. Но для вашего случая это было бы просто

movi d1, #0

Это очищает d1 регистр (и, следовательно, b1, h1, s1, и q1 регистры тоже).

Я опоздал на вечеринку, но я (любитель) понял, как загружать числа с плавающей запятой в регистры, используя .data. Вот мой пример кода для печати PI. Я надеюсь, что это поможет кому-то еще, поскольку я потратил около двух часов, пытаясь понять это сам. -- JDS

      .global main
.align 4


main:
    ADRP    X1, pi@PAGE         // Load the address for our "pi" data
    ADD X1, X1, pi@PAGEOFF
    LDR D1, [X1]                // Store the contents of X1 to D1

    STR D1, [SP, #-16]!         // Store the float (D1) onto the stack for printing
    ADRP    X0, format@PAGE     // Load the address of our printf format string
    ADD X0, X0, format@PAGEOFF

    
end:
    BL  _printf                 // print -- reads string from X0 and data from stack
    mov X16, #1
    svc 0



.data
    pi: .double 3.141519
    format: .asciz  "Pi is %f \n"
Другие вопросы по тегам