我正在尋找一種優化的方法來使用另一個資料暫存器中的值的符號來更改資料暫存器中包含的值的符號。
源暫存器將包含 1 或 -1,目標始終為正,因此只需要乘法即可。這是我要做的一些偽代碼:
MOVE.B #-1,D0
MOVE.W #173,D1
MULS.W D0,D1
在那個簡單的數學運算之后,D1 將攜帶來自 D0 的符號并變為 -173 或 173。這是期望的結果,但 MULS 需要多達 70 個周期,我希望通過找到一種技巧來以某種方式只“復制”符號 。
最后一句話:技巧應該是無分支的,因為分支是我試圖通過首先復制符號來防止的。
在此先感謝您提供任何資訊或建議。
uj5u.com熱心網友回復:
您可以使用一點技巧在x和之間進行無分支選擇-x。
但是你可以做得更好:2 的補碼否定可以表示為-x == ~x 1,并且 NOT 和增量都可以表示為 XOR 和 SUB with -1。但與 a 相同的操作0是空操作,保持值不變。
(此技巧通常用于 2 的補碼絕對值,其中 0 或 -1 是從算術右移獲得的x >> 31,以將符號位復制到暫存器的所有位。即將條件符號翻轉操作應用于相同的給我們符號位的數字 。https://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs)
當然,您需要一個 WORD 大小的-1,而不僅僅是 BYTE,因為您需要涵蓋所有要否定(或不否定)的值;正如 Erik 指出的那樣,這意味著move.w #-1, d0或者ext.w如果您不能將您的位元組值提升為原始單詞。
;; d0 = word 1 or -1
asr.w #1, d0
;; d0 = word 0 or -1
eor.w d0, d1 ; ~d1
sub.w d0, d1 ; ~d1 - 1 (or unchanged for d0=0)
; d1 = d1 or -d1 according to d0
如果您想根據其他數字的符號進行否定,請直接生成0/-1而不是創建1/ -1。
(即一個整數copysign,有點像乘以signum(y)如果 ISO C 有一個signum函式,但沒有在 上歸零y=0。)
通常你會使用x >> 15算術右移,但 M68K 立即移位只允許從 1..8 開始計數。(并且在沒有桶形移位器的 CPU 上進行大量計數時速度很慢)。因此,您實際上希望通過將符號擴展到 32 位然后交換一半以將其放置到位來獲得符號位的 16 個副本:
;; manufacture a 0 / -1 word according to d0.w < 0
ext.l d0 ; high 16 bits = 0 / -1
swap d0 ; those are now the low bits
; optionally: ext.l d0 ; to make a 32-bit 0 / -1
對于 32 位源,您可以tst.l d0,d0/ smi d0(如果 MInus 設定)生成位元組大小的 0 / -1,然后對其進行符號擴展。(雖然只有 68020 可以在一條extb.l指令中做到這一點;68000 需要ext.w ext.l)
或者,如果您有 MC68020 或更高版本的 CPU,您可以使用僅符號位的符號擴展位域提取。 bfexts d0 {15:1}, d0. 這是一條 4 位元組指令,因此與 ext.l swap 的代碼大小相同,但它擴展到 32 位并且可以在 32 位源暫存器上作業而無需額外作業。即使對于 16 位整數,它也是一條指令而不是 2 條指令,因此它非常好,尤其是當它從快取中執行時。(假設它的運行速度與 ext.l 或 swap 一樣快;我沒有找到 68020 指令時序表。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/399347.html
