IIRC,第一代的Xeon Phi是基於P5核(Pentium和奔騰MMX)。直到P6(aka Pentium Pro)才引入cmov
。所以我認爲這很正常。
讓編譯器通過編寫一個正常的三元運算符來完成它的工作。
其次,cmov
是一個比setc
更差的選擇,因爲你想根據進位標誌產生一個0或1。請參閱下面的我的代碼。
另請注意,帶內存操作數的bts
超慢,因此您不希望它生成該代碼,尤其是,在將x86指令解碼爲uops的CPU上(如現代Xeon)。根據http://agner.org/optimize/,即使在P5上,bts m, r
也比bts m, i
慢得多,所以不要這樣做。
只需要編譯器的in
在寄存器中,或者更好的是,不要使用內聯asm。
由於OP顯然希望這原子的工作,最好的解決辦法是使用C++ 11的std::atomic::fetch_or
,並把它留給編譯器生成lock bts
。
std::atomic_flag有一個test_and_set
函數,但是IDK是否有辦法將它們緊緊地打包。也許作爲結構中的位域?雖然不太可能。我也沒有看到std::bitset
的原子操作。
不幸的是,gcc和鏗鏘的當前版本不會從fetch_or
產生lock bts
,即使在備受更快的即時操作數形式是可用的。我想出了下述(godbolt link):
#include <atomic>
#include <stdio.h>
// wastes instructions when the return value isn't used.
// gcc 6.0 has syntax for using flags as output operands
// IDK if lock BTS is better than lock cmpxchg.
// However, gcc doesn't use lock BTS even with -Os
int atomic_bts_asm(std::atomic<unsigned> *x, int bit) {
int retval = 0; // the compiler still provides a zeroed reg as input even if retval isn't used after the asm :/
// Letting the compiler do the xor means we can use a m constraint, in case this is inlined where we're storing to already zeroed memory
// It unfortunately doesn't help for overwriting a value that's already known to be 0 or 1.
asm(// "xor %[rv], %[rv]\n\t"
"lock bts %[bit], %[x]\n\t"
"setc %b[rv]\n\t" // hope that the compiler zeroed with xor to avoid a partial-register stall
: [x] "+m" (*x), [rv] "+rm"(retval)
: [bit] "ri" (bit));
return retval;
}
// save an insn when retval isn't used, but still doesn't avoid the setc
// leads to the less-efficient setc/ movzbl sequence when the result is needed :/
int atomic_bts_asm2(std::atomic<unsigned> *x, int bit) {
uint8_t retval;
asm("lock bts %[bit], %[x]\n\t"
"setc %b[rv]\n\t"
: [x] "+m" (*x), [rv] "=rm"(retval)
: [bit] "ri" (bit));
return retval;
}
int atomic_bts(std::atomic<unsigned> *x, unsigned int bit) {
// bit &= 31; // stops gcc from using shlx?
unsigned bitmask = 1<<bit;
//int oldval = x->fetch_or(bitmask, std::memory_order_relaxed);
int oldval = x->fetch_or(bitmask, std::memory_order_acq_rel);
// acquire and release semantics are free on x86
// Also, any atomic rmw needs a lock prefix, which is a full memory barrier (seq_cst) anyway.
if (oldval & bitmask)
return 1;
else
return 0;
}
如圖What is the best way to set a register to zero in x86 assembly: xor, mov or and?,xor
/設定標誌討論/ setc
是當需要將其結果作爲0或1的值用於所有現代CPU的最佳序列。我沒有真正考慮過P5,但setcc
在P5上很快,所以應該沒問題。
當然,如果你想分支而不是存儲它,inline asm和C之間的邊界是一個障礙。花費兩條指令來存儲0或1,僅用於測試/分支,將是非常愚蠢的。
如果是選項,gcc6的標誌操作數語法當然值得查看。 (如果你需要一個編譯器來支持英特爾MIC,則可能不需要)。
IIRC,第一代Xeon Phi基於P5內核(Pentium和Pentium MMX)。直到P6(又名Pentium Pro)才引入'cmov'。所以我認爲這很正常。讓編譯器通過編寫一個正常的三元運算符來完成它的工作。另請注意,帶有內存操作數的「bts」超慢。不要這樣做。另外,我認爲你正在測試'in'地址中的位,因爲你要求'&in'存儲在內存中。那是你想要的嗎? –
你的問題是什麼? –
我認爲Xeon phi也是基於x86的,它應該可以正常工作 – arunmoezhi