簡體   English   中英

ARM匯編:重新加載“ asm”時無法在類“ GENERAL_REGS”中找到寄存器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM