2015-10-17 80 views
2

我試圖產生 AXI總線突發訪問與ARM編譯器armcc 5編譯.c文件使用內聯組件STM/LDM指令。如何防止ARM Compiler 5 armcc內嵌彙編程序中的LDM/STM指令擴展?

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1) 
{ 
    __asm { 
     STMIA addr!, { w0, w1 } 
    } 
} 

但ARM編譯器armcc用戶指南,第7.18段是說: 「所有的LDM和STM指令被擴展爲等效的LDR和STR指令序列然而,編譯器可能因此重組的單獨的指令在優化過程中轉換爲LDM或STM。「

這就是真正發生的事情在實踐中,LDM/STM被擴展成一組的LDR/STR在某些情況下,這些instuctions的順序是任意的。 這會影響性能,因爲我們使用HW優化了突發處理。此外,這破壞了函數的正確性,因爲我們使用的HW考慮了字的序列並忽略了偏移量(但編譯器認爲改變指令的順序是安全的)。

要解決這一點,是可以使用的,而不是內聯彙編嵌入式彙編程序,但是這會導致額外的函數調用,返回什麼影響性能。

所以我想知道如果有一種方法來生成LDM/STM正確不失的表現?我們能夠在GCC中做到這一點,但沒有找到任何解決方案。

目標CPU:Cortex M0 +(ARMv6-M)。

編輯: 從屬設備都是片上設備,其中大多數是非存儲設備。對於支持地址空間突發訪問區域的每個非存儲器從站寄存器(例如[0x10000..0x10100]),我不完全確定爲什麼,也許CPU或總線不支持固定(非增量)地址。 HW忽略該區域內的偏移量。例如,完整請求可以是16個字節,並且完整請求的第一個字是第一個寫入的字(即使偏移量不爲零)。

+1

如果你很在乎性能,然後寫更多的,你在一個單獨的彙編程序文件所需要的。考慮到編譯器處理代碼的其餘部分有多糟糕,內聯C函數中的單個指令不會讓你感到太多。我的運營主體總是 - 如果您關心時間關鍵的例程的性能,請自己寫(使用匯編程序)。 – BitBank

+0

@ imiron13:我懷疑你是搞砸了。基爾內聯彙編讓優化器無所不能,對「優化」功能缺乏細粒度的控制。如果您使用正常的易失性指針來確保寫入器與64位類型的順序以嘗試組合寫入,那麼代碼生成有多糟糕? – doynax

+0

@BitBank:我的假設是,性能命中並不是孤立於單個重要的內部環路,這可以很容易地手動調整,但寫入內聯生成代碼庫的重要部分。 – doynax

回答

1

所以我想知道是否有一種方法可以正常生成LDM/STM而不會丟失性能?我們能夠在GCC中做到這一點,但沒有找到任何解決方案。

約編譯器優化一點點。 Register allocation是最難的工作之一。任何編譯器代碼生成的核心可能都在於它分配物理CPU寄存器的時間。大多數編譯器使用Single static assignment or SSA將'C'變量重命名爲一堆僞變量(或時序變量)。

爲了讓您的STMIA和LDMIA工作,你需要在加載和存儲是一致的。也就是說,如果它是stmia [rx], {r3,r7}並且像ldmia [rx], {r4,r8}這樣的恢復具有'r3'映射到新的'r4'並且存儲的'r7'映射到恢復的'r8'。對於任何編譯器來說,這並不簡單,因爲'C'變量將根據需要進行分配。相同變量的不同版本可能在不同的寄存器中。要使stm/ldm工作,必須分配這些變量,以便按正確的順序進行寄存器增量。也就是說,如果編譯器希望存儲的r7位於r0(可能是返回值?),上面的ldmia,則無法創建好的ldm指令而不生成其他代碼。

你可能已經得到了gcc來生成這個,但它可能是運氣。如果你只使用gcc,你可能會發現它不能正常工作。

參見:ldm/stm and gcc與GCC STM/LDM問題。

以你的榜樣,

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1) 
{ 
    __asm { 
     STMIA addr!, { w0, w1 } 
    } 
} 

inline值是整個函數體可以放在右邊的代碼。調用者可能在寄存器R8和R4中有w0w1。如果函數不是inline,那麼編譯時必須將它們放在R1和R2中,但可能會產生額外的移動。任何編譯器一般難以滿足ldm/stm的要求。

這會影響,因爲HW我們使用的突發處理優化的性能。此外,這破壞了函數的正確性,因爲我們使用的HW考慮了字的序列並忽略了偏移量(但編譯器認爲改變指令的順序是安全的)。

如果硬件在總線上一個特定的非存儲器從屬外圍,則可以包裹的功能寫入到該從機在外部包裹件和強制寄存器分配(見AAPCS),使得ldm/stm將工作。這會導致性能下降,這可以通過設備驅動程序中的某個自定義彙編程序來緩解。

然而,這聽起來像設備可能是內存嗎?在這種情況下,你有一個問題。通常情況下,像這樣的內存設備只會使用緩存?如果您的CPU有一個MPU(內存保護單元)並且可以啓用數據和代碼緩存,則可以解決此問題。緩存行將始終是突發訪問。只需在代碼中設置MPU和數據高速緩存即可。 的OP的Cortex-M0 +不具有高速緩存和裝置是非存儲器所以這將是不可能的(也不需要)。

如果你的設備是內存,你有沒有數據緩存那麼您的問題可能是無法解決的(沒有付出巨大的努力),你需要不同的硬件。或者你可以像外圍設備一樣包裝它,並採取性能打擊;失去了存儲設備隨機存取的好處。

+0

(這與您在帖子中鏈接的問題更相關,但我無法在此發表評論)。 'gcc問題'意味着可以可靠地生成突發,但是由於顯式的寄存器分配,它可能不是最優的? – imiron13

+0

雖然,您的里程可能會有所不同,具體取決於GCC版本和選項標誌。我發現唯一可靠的方法是使用函數調用並依賴寄存器參數或者指定gcc寄存器'asm'變量。如果你不這樣做,你可能會得到神祕的關於寄存器的stm/ldm亂序的消息。也就是說,有人更改代碼或編譯器選項以及GCC選項寄存器不起作用。 –

+0

如果這一切都是'芯片上的'並且你的公司沒有設計它,但是一些大公司和芯片組被廣泛使用,我懷疑有某種總線配置需要。很難相信商業SOC會在編輯中遇到問題。任何使用該芯片的人都會遇到同樣的問題。如果芯片是未來產品的樣本,那麼這可能是一個勘誤,我期望在芯片進入大規模生產之前能夠修復。 –