Я новичок в ассемблере ARM и хочу реализовать одну из своих функций C во встроенном ассемблере. Мои функции - это умножение с множественной точностью, которое умножает 32-битное целое число без знака на 256-битное целое число без знака и помещает результат в 288-битный целочисленный тип данных без знака. Я определил свой тип данных как:
typedef struct UN_256fe{
uint32_t uint32[8];
}UN_256fe;
typedef struct UN_288bite{
uint32_t uint32[9];
}UN_288bite;
и вот моя функция:
void multiply32x256(uint32_t A, UN_256fe* B, UN_288bite* res){
uint32_t temp;
asm ( "umull %0, %1, %9, %10;\n\t"
"umull %18, %2, %9, %11;\n\t"
"adds %1, %18, %1; \n\t"
"umull %18, %3, %9, %12;\n\t"
"adcs %2, %18, %2; \n\t"
"umull %18, %4, %9, %13;\n\t"
"adcs %3, %18, %3; \n\t"
"umull %18, %5, %9, %14;\n\t"
"adcs %4, %18, %4; \n\t"
"umull %18, %6, %9, %15;\n\t"
"adcs %5, %18, %5; \n\t"
"umull %18, %7, %9, %16;\n\t"
"adcs %6, %18, %6; \n\t"
"umull %18, %8, %9, %17;\n\t"
"adcs %7, %18, %7; \n\t"
"adc %8, %8, 0 ; \n\t"
: "=r"(res->uint32[8]), "=r"(res->uint32[7]), "=r"(res->uint32[6]), "=r"(res->uint32[5]), "=r"(res->uint32[4]),
"=r"(res->uint32[3]), "=r"(res->uint32[2]), "=r"(res->uint32[1]), "=r"(res->uint32[0])
: "r"(A), "r"(B->uint32[7]), "r"(B->uint32[6]), "r"(B->uint32[5]),
"r"(B->uint32[4]), "r"(B->uint32[3]), "r"(B->uint32[2]), "r"(B->uint32[1]), "r"(B->uint32[0]), "r"(temp));
}
Мне кажется, это нормально. Но когда я отлаживаю свой код, например, в первой строке после выполнения "umull %0, %1, %9, %10;\n\t"
у меня есть:
(gdb) p/x A //-->%9
$8 = 0x1
(gdb) p/x B->uint32[7] //-->%10
$9 = 0xffffff1
(gdb) p/x res->uint32[8] //-->%0
$10 = 0x1
(gdb) p/x res->uint32[7] //-->%1
$11 = 0x0
Кажется, я допустил некоторые ошибки в инструкции по сборке. Может ли кто-нибудь объяснить это мне?
uint32
не изменится после выполнения первой инструкции в операторе asm. Поскольку он делает все в регистрах, только через некоторое время после выполнения всех инструкций в операторе значения в регистрах будут сохранены в массиве. Когда именно, зависит от кода, который компилятор выдает после инструкции сборки для этих хранилищ. - person Ross Ridge   schedule 13.12.2015=&r
, чтобы компилятор знал, что нельзя использовать регистры, назначенные этим операндам, в качестве входных операндов. Операндtemp
должен быть ранним выходным операндом затирания, чтобы компилятор знал, что инструкция asm изменяет регистр. - person Ross Ridge   schedule 13.12.2015%0
и%1
используютr
, что ограничивает операнд регистром. Если вместо этого вы использовалиm
, то компилятор использовал бы вместо этого операнд памяти, но ассемблер тогда отклонил бы оператор, потому что инструкция UMULL не принимает операнды памяти. Вам не нужно добавлять операторы, чтобы делать магазины самостоятельно. Как я уже сказал, компилятор автоматически выдаст необходимый код (инструкции по ассемблеру) для этих хранилищ после вашего оператора asm. - person Ross Ridge   schedule 14.12.2015=r
на=&r
, компилятор выдает эту ошибку:can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’
. Я думаю, что это связано с количеством общих регистров в моем процессоре ARM, и кажется, что я использовал много регистров в своем коде. Не могли бы вы привести пример встроенного ассемблерного кода, который получает два операндаuint32_t
из памяти и перемножает их, а затем сохраняет 64-битный результат в памяти? - person A23149577   schedule 14.12.2015uint64_t n = (uint64_t) A * B->uint32[7]
. - person Ross Ridge   schedule 14.12.2015asm
блоками. И с этим кодом это вполне может произойти с инструкциями по вычислению адресов для настройки входов/выходов. (И погода была не так уж и плоха. Хотя на обратном пути из PEI ехали довольно плохо.) - person Peter Cordes   schedule 15.12.2015