ARM程序集:在重新加载'asm'时无法在类'GENERAL_REGS'中找到寄存器

时间:2015-12-14 02:30:14

标签: c gcc arm inline-assembly

我正在尝试在ARM Cortex-a8上实现一个将32位操作数与ARM组件中的256位操作数相乘的函数。问题是我的寄存器用完了,我不知道如何在这里减少使用的寄存器数量。这是我的功能:

test.py

EDIT-1:我根据第一条评论更新了我的clobber列表,但我仍然遇到同样的错误

1 个答案:

答案 0 :(得分:0)

一个简单的解决方案就是解决这个问题,不要使用'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被列为输入/输出,GCC知道内存会发生变化,因此您不需要内存 clobber。实际上它是有害的,因为 memory clobber是compiler memory barrier,这将导致在编译器可能为后者安排内存时写入内存。

道德是使用gcc内联汇编程序与编译器一起工作。如果您使用汇编程序进行编码并且您有大量的例程,那么寄存器的使用会变得复杂和混乱。典型的汇编程序编码器每个例程只在寄存器中保留一个东西,但这并不总是寄存器的最佳用途。当代码大小变大时,编译器将以一种相当聪明的方式对数据进行混洗,这种方式很难被击败(并且对代码IMO不太满意)。

您可能希望查看the GMP library,其中有很多方法可以有效地解决您的代码所遇到的一些相同问题。