![](/img/trans.png)
[英]how to solve error in inline assembly in C: 'can't find a register in class 'GENERAL_REGS' while reloading 'asm''
[英]ARM assembly: can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’
我试图在ARM Cortex-a8上的ARM汇编中实现将32位操作数与256位操作数相乘的函数。 问题是我的寄存器用完了,我不知道如何减少这里使用的寄存器数量。 这是我的功能:
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){
asm (
"umull r3, r4, %9, %10;\n\t"
"mov %0, r3; \n\t"/*res->uint32[0] = r3*/
"umull r3, r5, %9, %11;\n\t"
"adds r6, r3, r4; \n\t"/*res->uint32[1] = r3 + r4*/
"mov %1, r6; \n\t"
"umull r3, r4, %9, %12;\n\t"
"adcs r6, r5, r3; \n\t"
"mov %2, r6; \n\t"/*res->uint32[2] = r6*/
"umull r3, r5, %9, %13;\n\t"
"adcs r6, r3, r4; \n\t"
"mov %3, r6; \n\t"/*res->uint32[3] = r6*/
"umull r3, r4, %9, %14;\n\t"
"adcs r6, r3, r5; \n\t"
"mov %4, r6; \n\t"/*res->uint32[4] = r6*/
"umull r3, r5, %9, %15;\n\t"
"adcs r6, r3, r4; \n\t"
"mov %5, r6; \n\t"/*res->uint32[5] = r6*/
"umull r3, r4, %9, %16;\n\t"
"adcs r6, r3, r5; \n\t"
"mov %6, r6; \n\t"/*res->uint32[6] = r6*/
"umull r3, r5, %9, %17;\n\t"
"adcs r6, r3, r4; \n\t"
"mov %7, r6; \n\t"/*res->uint32[7] = r6*/
"adc r6, r5, #0 ; \n\t"
"mov %8, r6; \n\t"/*res->uint32[8] = r6*/
: "=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)
: "r3", "r4", "r5", "r6", "cc", "memory");
}
EDIT-1:我根据第一条评论更新了我的内容清单,但仍然收到相同的错误
一个简单的解决方案是将其分解,而不使用“ Clobber”。 将变量声明为“ tmp1”,等等。请尽量不要使用任何mov
语句; 如果需要,让编译器执行此操作。 编译器将使用一种算法来找出最佳的信息“流”。 如果您使用'clobber',则它无法重用寄存器。 按照现在的方式,您可以在汇编程序执行之前先加载所有内存。 这很不好,因为您希望将内存/ CPU ALU流水线化。
void multiply32x256(uint32_t A, UN_256fe* B, UN_288bite* res)
{
uint32_t mulhi1, mullo1;
uint32_t mulhi2, mullo2;
uint32_t tmp;
asm("umull %0, %1, %2, %3;\n\t"
: "=r" (mullo1), "=r" (mulhi1)
: "r"(A), "r"(B->uint32[7])
);
res->uint32[8] = mullo1; /* was 'mov %0, r3; */
volatile asm("umull %0, %1, %3, %4;\n\t"
"adds %2, %5, %6; \n\t"/*res->uint32[1] = r3 + r4*/
: "=r" (mullo2), "=r" (mulhi2), "=r" (tmp)
: "r"(A), "r"(B->uint32[6]), "r" (mullo1), "r"(mulhi1)
: "cc"
);
res->uint32[7] = tmp; /* was 'mov %1, r6; */
/* ... etc */
}
“ gcc内联汇编程序”的全部目的不是直接在“ C”文件中编码汇编程序。 它是使用编译器的寄存器分配逻辑,做一些不能在“C”可以轻松完成。 在您的情况下使用进位逻辑。
通过使其不成为一个巨大的“ asm”子句,编译器可以在需要新寄存器时从内存中调度加载。 它还会将您的“ UMULL” ALU活动与加载/存储单元进行管道传输。
仅当指令隐式破坏特定寄存器时,才应使用Clobber。 您也可以使用类似的方法,
register int *p1 asm ("r0");
并将其用作输出。 但是,除了那些可能改变堆栈的指令之外,我不知道像这样的任何ARM指令,并且您的代码当然不会使用这些指令和进位指令。
GCC知道如果内存被列为输入/输出,它就会发生变化,因此您不需要内存破坏者。 实际上,这是有害的,因为内存破坏者是编译器的内存屏障 ,当编译器可能为后者安排内存时 ,这将导致写入内存。
道德是使用gcc内联汇编器与编译器一起工作。 如果您在汇编器中编码并且拥有大量例程,则寄存器的使用可能会变得复杂而混乱。 典型的汇编编码器每个例程在寄存器中仅保留一件事,但这并不总是寄存器的最佳用途。 编译器将以相当智能的方式对数据进行混洗,当代码变大时,这种方式很难克服(并且对于手动编写IMO不太满意)。
您可能想看一下GMP库 ,它具有许多方法来有效解决代码中看起来相同的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.