2010-02-20 33 views
5

如果我有以下C++代碼比較兩個128位無符號整數,直列AMD-64 ASM:在GCC風格的擴展內聯asm中,是否可以輸出「虛擬化」布爾值,例如進位標誌?

struct uint128_t { 
    uint64_t lo, hi; 
}; 
inline bool operator< (const uint128_t &a, const uint128_t &b) 
{ 
    uint64_t temp; 
    bool result; 
    __asm__(
     "cmpq %3, %2;" 
     "sbbq %4, %1;" 
     "setc %0;" 
     : // outputs: 
     /*0*/"=r,1,2"(result), 
     /*1*/"=r,r,r"(temp) 
     : // inputs: 
     /*2*/"r,r,r"(a.lo), 
     /*3*/"emr,emr,emr"(b.lo), 
     /*4*/"emr,emr,emr"(b.hi), 
     "1"(a.hi)); 
    return result; 
} 

然後,它會被非常有效地內聯,但是有一個缺陷。返回值是通過通用寄存器的「接口」完成的,值爲0或1.這將增加兩到三個不必要的額外指令,並減少比較操作的數量,否則會進行完全優化。生成的代碼將是這個樣子:

mov r10, [r14] 
    mov r11, [r14+8] 
    cmp r10, [r15] 
    sbb r11, [r15+8] 
    setc al 
    movzx eax, al 
    test eax, eax 
    jnz is_lessthan 

如果我使用「SBB%0%0」與「INT」返回值,而不是「國家經貿委%0」與「布爾」返回值,有仍然是兩個額外的指令:

mov r10, [r14] 
    mov r11, [r14+8] 
    cmp r10, [r15] 
    sbb r11, [r15+8] 
    sbb eax, eax 
    test eax, eax 
    jnz is_lessthan 

我想是這樣的:

mov r10, [r14] 
    mov r11, [r14+8] 
    cmp r10, [r15] 
    sbb r11, [r15+8] 
    jc  is_lessthan 

GCC擴展內聯彙編是美妙的,否則。但我希望它能像內在功能一樣好,無論如何。我希望能夠以CPU標誌或標誌狀態的形式直接返回布爾值,而不必將其「渲染」爲通用寄存器。

這是可能的,還是GCC(和英特爾C++編譯器,它也允許使用這種形式的內聯asm)必須被修改或甚至重構使之成爲可能?

另外,雖然我在這 - 有沒有其他方法可以改進我的比較運算符的表達式?

+0

截至2013年,似乎仍無法直接進行。但是這裏有一個2011年的bug報告,討論這種功能的可取性:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49611。它鏈接到一個2001 Linux內核線程也希望這樣的事情:http://lkml.indiana。埃杜/ hypermail/LINUX /內核/ 0111.2/0256.html。 – 2013-10-24 09:25:28

回答

3

在這裏,我們是近7年後的今天,是的,GCC終於增加了「輸出標誌」(支持在2016年4月發佈的6.1.0中添加)。詳細的文檔是here,但在短,它看起來像這樣:

/* Test if bit 0 is set in 'value' */ 
char a; 

asm("bt $0, %1" 
    : "[email protected]" (a) 
    : "r" (value)); 

if (a) 
    blah; 

爲了理解[email protected]:輸出約束(要求=)是@cc類型接着條件碼使用的(在這種情況下c以引用進位標誌)。 (這是因爲gcc現在支持直接比較128位數據類型),但是(目前)有1,326人已經看過這個問題。顯然這個功能有一些興趣。

現在我個人比較喜歡don't use inline asm at all。但如果你必須,是的,你可以(現在)'輸出'標誌。

FWIW。

4

我不知道如何做到這一點。您可能會或可能不會認爲這是一個進步:

inline bool operator< (const uint128_t &a, const uint128_t &b) 
{ 
    register uint64_t temp = a.hi; 
    __asm__(
     "cmpq %2, %1;" 
     "sbbq $0, %0;" 
     : // outputs: 
     /*0*/"=r"(temp) 
     : // inputs: 
     /*1*/"r"(a.lo), 
     /*2*/"mr"(b.lo), 
     "0"(temp)); 

    return temp < b.hi; 
} 

它產生這樣的:

mov rdx, [r14] 
mov rax, [r14+8] 
cmp rdx, [r15] 
sbb rax, 0 
cmp rax, [r15+8] 
jc is_lessthan 
+0

+1極好的改進。這比我在問題中發佈的基準更好(用於執行數千兆字節的排序操作)。 我仍然抱着希望,可能有辦法直接返回進位標誌,所以我不會將此標記爲「已接受的答案」,但是,很好地完成了。 – Deadcode 2010-02-22 17:24:15

相關問題