c - ARM 程序集 : can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’

标签 c gcc arm inline-assembly

我正在尝试在 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 列表,但我仍然遇到同样的错误

最佳答案

一个简单的解决方案是将其分解并且不使用“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”文件中编写汇编代码。它是利用编译器的寄存器分配逻辑AND做一些在'C'中不容易完成的事情。在您的案例中使用进位逻辑。

通过不使其成为一个巨大的“asm”子句,编译器可以在需要新寄存器时安排从内存加载。它还会将您的“UMULL”ALU 事件与加载/存储单元进行管道传输。

只有在指令隐式破坏特定寄存器时才应使用 clobber。你也可以使用类似的东西,

register int *p1 asm ("r0");

并将其用作输出。但是,除了那些可能会改变堆栈的指令之外,我不知道有任何像这样的 ARM 指令,而且您的代码当然不使用这些指令和进位。

GCC 知道如果内存被列为输入/输出,它就会发生变化,因此您不需要内存 破坏器。事实上,它是有害的,因为 内存 破坏是 compiler memory barrier这将导致在编译器可能能够为后者安排内存时写入内存。


道德是使用 gcc 内联汇编程序与编译器一起工作。如果您使用汇编程序编写代码并且有大量例程,则寄存器的使用会变得复杂和困惑。典型的汇编程序编码器在每个例程的寄存器中只保留一件事,但这并不总是寄存器的最佳用途。当代码量变大时,编译器将以一种相当聪明的方式随机排列数据,这种方式很难被击败(而且对于手工编写 IMO 代码也不是很令人满意)。

您可能想看看 the GMP library它有很多方法可以有效地解决您的代码所遇到的一些相同问题。

关于c - ARM 程序集 : can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’ ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34258904/

相关文章:

c - 中断服务例程不会跳回到 ARM Cortex M0 上的中断处理程序

macos - 每次升级 Xcode 时,我都会收到 brew installed GCC 的链接器错误

debugging - gcc sanitizer : unmap_shadow_on_exit not honored with custom SIGSEGV handler

ios - Linux ARM ELF 和 iOS ARM ELF 文件有什么区别?

debugging - 如何运行单行汇编,然后查看 [R1] 和条件标志

c - ARM Cortex M4 上的数组大小问题

c - 如何从字符串类型行中提取char类型元素并添加到c中的列表中

c - IndexOf 函数在 C 中不起作用

c - 如何从C中的线程退出程序?

c - gcc 错误为 `int y=&x`