首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CMPXCHG16B正确吗?

CMPXCHG16B正确吗?
EN

Stack Overflow用户
提问于 2011-01-28 14:12:04
回答 4查看 7.2K关注 0票数 9

这看起来并不完全正确,尽管我不确定为什么。建议是很棒的,因为CMPXCHG16B的文档非常简单(我没有任何英特尔手册...)

代码语言:javascript
复制
template<>
inline bool cas(volatile types::uint128_t *src, types::uint128_t cmp, types::uint128_t with)
{
    /*
    Description:
     The CMPXCHG16B instruction compares the 128-bit value in the RDX:RAX and RCX:RBX registers 
     with a 128-bit memory location. If the values are equal, the zero flag (ZF) is set, 
     and the RCX:RBX value is copied to the memory location. 
     Otherwise, the ZF flag is cleared, and the memory value is copied to RDX:RAX.
     */
    uint64_t * cmpP = (uint64_t*)&cmp;
    uint64_t * withP = (uint64_t*)&with;
    unsigned char result = 0;
    __asm__ __volatile__ (
    "LOCK; CMPXCHG16B %1\n\t"
    "SETZ %b0\n\t"
    : "=q"(result)  /* output */ 
    : "m"(*src), /* input */
      //what to compare against
      "rax"( ((uint64_t) (cmpP[1])) ), //lower bits
      "rdx"( ((uint64_t) (cmpP[0])) ),//upper bits
      //what to replace it with if it was equal
      "rbx"( ((uint64_t) (withP[1])) ), //lower bits
      "rcx"( ((uint64_t) (withP[0]) ) )//upper bits
    : "memory", "cc", "rax", "rdx", "rbx","rcx" /* clobbered items */
    );
    return result;
}

当运行一个例子时,我得到了0,而它应该是1。有什么想法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-01-29 00:12:21

注意到一些问题,

(1)主要的问题是约束,"rax“并不像它看起来那样,而是第一个字符"r”让gcc使用任何寄存器。

(2)不确定您是如何存储types::uint128_t的,但假设x86平台的标准小端,那么高和低双字也被交换。

(3)获取某个对象的地址并将其转换为其他对象可能会违反别名规则。这取决于你的types::uint128_t是如何定义的,这是否是一个问题(如果它是一个由两个uint64_t组成的结构,也没问题)。-O2的GCC将在不违反锯齿规则的情况下进行优化。

(4) *src实际上应该标记为输出,而不是指定内存占位器。但这实际上更多的是性能问题,而不是正确性问题。类似地,rbx和rcx不需要指定为clobbered。

这是一个可以工作的版本,

代码语言:javascript
复制
#include <stdint.h>

namespace types
{
    // alternative: union with  unsigned __int128
    struct uint128_t
    {
        uint64_t lo;
        uint64_t hi;
    }
    __attribute__ (( __aligned__( 16 ) ));
}

template< class T > inline bool cas( volatile T * src, T cmp, T with );

template<> inline bool cas( volatile types::uint128_t * src, types::uint128_t cmp, types::uint128_t with )
{
    // cmp can be by reference so the caller's value is updated on failure.

    // suggestion: use __sync_bool_compare_and_swap and compile with -mcx16 instead of inline asm
    bool result;
    __asm__ __volatile__
    (
        "lock cmpxchg16b %1\n\t"
        "setz %0"       // on gcc6 and later, use a flag output constraint instead
        : "=q" ( result )
        , "+m" ( *src )
        , "+d" ( cmp.hi )
        , "+a" ( cmp.lo )
        : "c" ( with.hi )
        , "b" ( with.lo )
        : "cc", "memory" // compile-time memory barrier.  Omit if you want memory_order_relaxed compile-time ordering.
    );
    return result;
}

int main()
{
    using namespace types;
    uint128_t test = { 0xdecafbad, 0xfeedbeef };
    uint128_t cmp = test;
    uint128_t with = { 0x55555555, 0xaaaaaaaa };
    return ! cas( & test, cmp, with );
}
票数 13
EN

Stack Overflow用户

发布于 2011-01-28 15:54:07

所有英特尔文档均免费提供:Intel® 64 and IA-32 Architectures Software Developer's Manuals

票数 6
EN

Stack Overflow用户

发布于 2014-08-10 12:54:02

值得注意的是,如果你使用的是GCC,你不需要使用内联asm来获得这条指令。您可以使用__sync函数之一,如下所示:

代码语言:javascript
复制
template<>
inline bool cas(volatile types::uint128_t *src,
                types::uint128_t cmp,
                types::uint128_t with)
{
    return __sync_bool_compare_and_swap(src, cmp, with);
}

微软对VC++也有类似的功能:

代码语言:javascript
复制
__int64 exchhi = __int64(with >> 64);
__int64 exchlo = (__int64)(with);

return _InterlockedCompareExchange128(a, exchhi, exchlo, &cmp) != 0;
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4825400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档