行內組合陳述式範例
volatile
關鍵字的用法。#include <stdio.h>
inline bool acquireLock(int *lock){
bool returnvalue = false;
int lockval;
asm volatile(
/*--------a fence here-----*/
" 0: lwarx %0,0,%2 \n" // Loads the word and reserves
// a memory location for the subsequent
// stwcx. instruction.
" cmpwi %0,0 \n" // Compares the lock value to 0.
" bne- 1f \n" // If it is 0, you can acquire the
// lock. Otherwise, you did not get the
// lock and must try again later.
" ori %0,%0,1 \n" // Sets the lock to 1.
" stwcx. %0,0,%2 \n" // Tries to conditionally store 1
// into the lock word to acquire
// the lock.
" bne- 0b \n" // Reservation was lost. Try again.
" isync \n" // Lock acquired. The isync instruction
// implements an import barrier to
// ensure that the instructions that
// access the shared region guarded by
// this lock are executed only after
// they acquire the lock.
" ori %1,%1,1 \n" // Sets the return value for the
// function acquireLock to true.
" 1: \n" // Did not get the lock.
// Will return false.
/*------a fence here------*/
: "+r" (lockval),
"+r" (returnvalue)
: "r" (lock) // "lock" is the address of the lock in
// memory.
: "cr0" // cr0 is clobbered by cmpwi and stwcx.
);
return returnvalue;
}
int main()
{
int myLock;
if(acquireLock(&myLock)){
printf("got it!\n");
}else{
printf("someone else got it\n");
}
return 0;
}
在此範例中, %0
參照第一個運算元 "+r"(lockval)
, %1
參照第二個運算元 "+r"(returnvalue)
,而 %2
參照第三個運算元 "r"(lock)
。
組合陳述式使用鎖定來控制對共用儲存體的存取; 在取得鎖定之前,沒有任何指令可以存取共用儲存體。
volatile
關鍵字暗示組合指示群組周圍有柵欄,因此無法將組合指示移出組合區塊或在組合區塊周圍移動。
如果沒有 volatile
關鍵字,編譯器可以移動指示以進行最佳化。 這可能會導致部分指示存取共用儲存體而不獲得鎖定。
在此組件陳述式中不需要使用 memory
clobber ,因為指示不會以非預期的方式修改記憶體。 如果您使用 memory
clobber ,則程式在功能上仍然正確。 不過, memory
clobber 會導致許多不必要的重新載入,導致效能降低。
int a ;
int b = 1, c = 2, d = 3 ;
__asm(" addc %[result], %[first], %[second]"
: [result] "=r" (a)
: [first] "r" (b),
[second] "r" (d)
);
在此範例中, %[result]
是指輸出運算元變數 a
, %[first]
是指輸入運算元變數 b
,而 %[second]
是指輸入運算元變數 d
。
asm (" add. %0,%1,%2 \n"
: "=r" (c)
: "r" (a),
"r" (b)
: "cr0"
);
在此範例中,除了組件陳述式 輸入 及 輸出 中列出的暫存器之外, add.
指令也會影響條件暫存器欄位 0。 因此,您必須將 cr0
新增至 clobbers,以通知編譯器這一點。memory
clobber 的用法。 asm volatile (" dcbz 0, %0 \n"
: "=r"(b)
:
: "memory"
);
在此範例中,指示 dcbz
會清除快取區塊,且可能已變更記憶體位置中的變數。 編譯器無法知道哪些變數已變更。 因此,編譯器會假設所有資料都可能與該指令所變更的記憶體建立別名。因此,在完成組合陳述式之後,必須從記憶體重新載入所需的所有項目。 memory
clobber 可確保程式正確性,但犧牲程式效能,因為編譯器可能會重新載入與組合陳述式無關的資料。
+
修飾元及 K
限制的用法。 asm (" addi %0,%0,%2"
: "+r" (a)
: "r" (a),
"K" (15)
);
此組合陳述式會新增運算元 %0
及運算元 %2
,並將結果寫入運算元 %0
。 輸出運算元使用 +
修飾元來指示可由指令讀取及寫入運算元 %0
。 K
限制指出載入至運算元 %2
的值必須是 不帶正負號 16 位元 常數值。
%
修飾元及 f
限制的用法。asm(" fadd %0, %1, %2"
: "=f" (c)
: "%f" (a),
"f" (b)
);
此組合陳述式會新增運算元 a
及 b
,並將結果寫入運算元 c
。 %
修飾元指出如果編譯器可以在這樣做時產生更好的程式碼,則可以切換運算元 a
和 b
。 每一個運算元都有 f
限制,指出需要浮點暫存器。b
限制的用法。char res[8]={'a','b','c','d','e','f','g','h'};
char a='y';
int index=7;
asm (" stbx %0,%1,%2 \n" \
: \
: "r" (a),
"b" (index),
"r" (res)
);
在此範例中, b
限制項指示編譯器為輸入運算元 %1
選擇 r0
以外的一般暫存器。 此程式的結果字串為 abcdefgy
。m
限制的用法。 asm (" stb %1,%0 \n" \
: "=m" (res) \
: "r" (a)
);
在此範例中,指令 stb
的語法為 stb
RS,D(RA)
,其中 D
是位移, R
是暫存器。 D+RA
會形成有效位址,從 D(RA)
計算。 透過使用限制 m,您不需要透過個別指定暫存器及位移來手動建構有效位址。
您可以使用單一限制 m
或 o
來參照指令中的兩個運算元,不論正確的偏移應該是什麼,以及它是堆疊偏移還是 TOC (目錄) 偏移。 這可讓編譯器選擇正確的暫存器 (例如r1
代表自動變數) ,並自動套用正確的位移。