Как правильно использовать ADDIS и ADDI для суммирования 32-битной константы непосредственно в регистр? - PullRequest
1 голос
/ 02 мая 2019

Я пытался использовать инструкции ADDIS и ADDI для базовой функции, которая суммирует константы в массив, я следовал инструкциям на стр. 48 и 49 из https://cr.yp.to/2005-590/powerpc-cwg.pdf,, но поведение не то, что я ожидал .

Я пытаюсь создать эту функцию в ассемблере, но для некоторых констант ADDIS уменьшает их на 1, и поведение не согласуется с тем, что говорится в руководстве, то есть проверяется, установлен ли бит 16. GCC и clang генерируют инструкции правильно, какое собственное правило они используют? Отсутствие приращения или реализации правила, как сказано в руководстве, просто дает неправильные суммы.

Протестировано на машине ppc970 с 64-битным ядром Linux и пользовательским пространством.

Пример вывода ассемблера компилятора из функции C:

void func(int* r){
r[0] += r[0] + 0x9f321062; //addis r3,r3,0x9f32 #has bit 16 set to 1 but is not incremented.
                           //addi  r3,r3,0x1062

r[1] += r[1] + 0x760ae53;  //addis r4,r4,0x761  #compiler correctly increments this from 0x0760 to 0x0761, but bit 16 of this number is 0!
                           //addi r4,r4,0xae53
}

Ответы [ 2 ]

2 голосов
/ 02 мая 2019

имеет бит 16, установленный в 1, но не увеличивается.

Инструкция addi PowerPC работает аналогично инструкции с тем же именем на процессорах MIPS:

Вы можете добавить число в диапазоне (-0x8000) к (+ 0x7FFF) в регистр.

Инструкция addis добавит кратное 0x10000 в регистр.

Поскольку 0x9f321062= 0x9f320000 + 0x1062, вы можете добавить 0x9f321062 в регистр, добавив в регистр 0x9f320000 и 0x1062, используя одну addis и одну addi инструкцию.

Здесь важно то, что старший бит из 16-битное число 0x1062 ясно, что означает, что 0x1062 не больше 0x7FFF и, следовательно, в диапазоне addi может иметь дело.

Теперь давайте рассмотрим другой случай:

0x760ae53 =0x7600000 + 0xae53, так что вы можете добавить 0x760ae53 в регистр, добавив 0x7600000 и 0xae53 в регистр.К сожалению, addi может работать только с диапазоном (-0x8000) до (+ 0x7FFF), поэтому добавление 0xae53 не работает.

Если задан старший бит операнда addi, addi инструкция знак-расширяет значение, что фактически означает, что инструкция добавляет (отрицательное значение) (N-0x10000) вместо (положительное значение) N. в регистр.

Таким образом, вы должны сделатьвычисление выполняется следующим образом:

0x760ae53 = 0x7600000 + (0xae53 - 0x10000) + 0x10000 = 0x7610000 + (0xae53 - 0x10000)

Другими словами: необходимо увеличить операнд addis(0x760) по одному, чтобы компенсировать эффект, из которого addi будет вычитать 0x10000.

бит 16

Обратите внимание, что в документации PowerPC используется очень запутанная битовая нумерация, которая дажеКажется, для разных процессоров процессоры различаются:

В некоторых документациях 32-разрядного (!) автомобильного PowerPC используются имена регистров от «бит 32» (старший бит) до «бит 63» (младший бит), так что битовые числаОт 0 до 31 даже не эксист ...

1 голос
/ 02 мая 2019

Это имеет смысл, если непосредственное значение знак - расширено до 32-разрядного.

Обратите внимание, что для 0xae53 установлен старший бит, поэтому знак будет расширяться до 0xffffae53. то есть это вычтет 1 из верхней половины, а также добавит 0xae53 к нижней половине (с потенциальным переносом в верхнюю половину, конечно).

Таким образом, невозможно написать add r4, r4, 0x0000ae53, потому что для этого потребуется 16-разрядный беззнаковый немедленный или более широкий, чем 16-разрядный немедленный подпись.

Но, может быть, сгенерированный компилятором asm использует нотацию 0xae53, чтобы просто показать вам битовый шаблон непосредственного без неявных старших бит?

(Извините, я не эксперт PowerPC, я не знаю, как ведут себя ассемблеры.)

...