簡體   English   中英

在 AVR 中,邏輯右移是否快了 2 的冪?

[英]Is a logical right shift by a power of 2 faster in AVR?

我想知道在以 2 的冪移動時執行邏輯右移是否更快

例如,是

myUnsigned >> 4

myUnsigned >> 3

我很欣賞每個人的第一反應是告訴我不要擔心這樣的小事,它使用正確的算法和集合來減少重要的數量級。 我完全同意你的看法,但我真的想盡我所能從嵌入式芯片(ATMega328)中擠出一切——我剛剛得到了一個值得“哇哦!”的性能轉變。 通過用位移替換除法,所以我向你保證這很重要。

讓我們看看數據表:

http://atmel.com/dyn/resources/prod_documents/8271S.pdf

就我所見,ASR(算術右移)總是移位一位,不能拿移位的位數; 執行需要一個周期。 因此,右移 n 位需要 n 個周期。 二的冪的行為與任何其他數字相同。

AVR 指令集中,算術右移和左移一次一位。 因此,對於這個特定的微控制器,移位>> n意味着編譯器實際上使 n 個單獨的asr操作,我猜>>3>>4快一個。

順便說一下,這使得 AVR 相當不尋常。

事實上,ATMega 沒有像大多數(如果不是全部)其他 8 位 MCU 那樣的桶形移位器 因此,它每次只能移動 1,而不是像更強大的 CPU 那樣任意值。 因此,理論上移動 4 比移動 3 慢

然而,ATMega確實有一個交換半字節指令,所以實際上x >> 4x >> 3

假設x是一個uint8_t那么x >>= 33 次右移實現

x >>= 1;
x >>= 1;
x >>= 1;

x >>= 4只需要一個交換和一點清除

swap(x);    // swap the top and bottom nibbles AB <-> BA
x &= 0x0f;

x &= 0xf0;
swap(x);

對於更大的交叉寄存器移位,還有多種優化方法

使用uint16_t變量y由低部分y0和高部分y1y >> 8很簡單

y0 = y1;
y1 = 0;

同樣y >> 9可以優化為

y0 = y1 >> 1;
y1 = 0;

因此甚至比在字符上移動 3 還要快


總之,換檔時間因換檔距離而異,但對於較長或非 2 的冪值,它不一定更慢 通常最多需要 3 條指令在 8 位字符內移位

以下是編譯器資源管理器中的一些演示

  • 右移 4 是通過swap和上面的and類似的

     swap r24 andi r24,lo8(15)
  • 右移 3 必須用 3 條指令完成

     lsr r24 lsr r24 lsr r24

左移也以同樣的方式優化

另請參閱哪個更快:x<<1 或 x<<10?

您必須查閱處理器的文檔以獲取此信息。 即使對於給定的指令集,根據型號的不同,成本也可能不同。 例如,在一個非常小的處理器上,移位一個值可能比其他值更快(某些 IA32 處理器上的旋轉指令就是這種情況,但這只是因為編譯器很少生成該指令)。

根據http://atmel.com/dyn/resources/prod_documents/8271S.pdf,ATMega328 的所有邏輯轉換都在一個周期內完成。 但是,當然,正如評論中指出的那樣,所有邏輯偏移都是一位。 因此,移位n的成本是n條指令中的n個周期。

這取決於處理器的構建方式。 如果處理器具有桶形旋轉,它可以在一次操作中移動任意數量的位,但這會占用芯片空間和功率預算。 最經濟的硬件只能向右旋轉一個,並提供有關環繞鑽頭的選項。 下一個是可以向左或向右旋轉一個的。 我可以想象一個具有 1-shifter、2-shifter、4-shifter 等的結構,在這種情況下,4 可能比 3 快。

先反匯編,然后對代碼計時。 不要因為有人告訴你,你在浪費時間而氣餒。 你獲得的知識將使你成為撲滅大公司火災的關鍵人物。 在這個行業中,真正了解幕后知識的人數正在以驚人的速度下降。

聽起來其他人在這里解釋了真正的答案,反匯編會顯示,單個位移指令。 因此,4 個班次將花費 3 個班次花費的時間的 133%,或者 3 個班次是 4 個班次花費的時間的 75%,這取決於您如何比較數字。 你的測量應該反映這種差異,如果他們不這樣做,我會繼續這個實驗,直到你完全理解執行時間。

如果你的目標處理器有一個位移指令(這很可能),那么它取決於該指令的硬件實現,如果移動 2 的冪或移動一些其他數字之間會有任何區別。 但是,這不太可能有所作為。

恕我直言,在開始衡量之前,您甚至不應該開始談論性能。 用除法編譯你的程序。 跑。 測量時間。 重復換檔。

用位移替換除法

這與負數不同:

char div2 (void)
{
    return (-1) / 2;
    // ldi r24,0
}

char asr1 (void)
{
    return (-1) >> 1;
    //  ldi r24,-1
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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