扩展装配中cmpxchg16b的不可能约束
我试图用我的C代码编写内联程序集来执行比较和交换操作。我的代码是:扩展装配中cmpxchg16b的不可能约束,c,gcc,x86-64,inline-assembly,lock-free,C,Gcc,X86 64,Inline Assembly,Lock Free,我试图用我的C代码编写内联程序集来执行比较和交换操作。我的代码是: typedef struct node { int data; struct node * next; struct node * backlink; int flag; int mark; } node_lf; typedef struct searchfrom { node_lf * current; node_lf * next; } return_sf; typ
typedef struct node {
int data;
struct node * next;
struct node * backlink;
int flag;
int mark;
} node_lf;
typedef struct searchfrom {
node_lf * current;
node_lf * next;
} return_sf;
typedef struct csArg {
node_lf * node;
int mark;
int flag;
} cs_arg;
typedef struct return_tryFlag {
node_lf * node;
int result;
} return_tf;
static inline node_lf cs(node_lf * address, cs_arg *old_val, cs_arg *new_val)
{
node_lf value = *address;
__asm__ __volatile__("lock; cmpxchg16b %0; setz %1;"
:"=m"(*(volatile node_lf *)address),
"=q"(value)
:"m"(*(volatile node_lf *)address),
"a"(old_val->mark), "d"(old_val->flag),
"b"(new_val->mark), "c"(new_val->flag)
:"memory");
return value;
}
在编译代码时,GCC会给出此错误:
函数“cs”中的linkedlist.c:linkedlist.c:45:3:错误:“asm”中不可能存在约束(*(volatile node)
我的代码出了什么问题?如何修复
我正在尝试实现此代码的等效项:
node_lf cs (node_lf * address, cs_arg *old_val, cs_arg *new_val ) {
node_lf value = *address;
if (value.next == old_val->node && value.mark == old_val->mark &&
value.flag == old_val->flag) {
address->next = new_val->node;
address->mark = new_val->mark;
address->flag = new_val->flag;
}
return value;
}
P:那么,让我们来讨论一下这个问题。 在我们开始之前,有几点:
next
、flag
和mark
进行操作,它们必须在结构中相邻searchfrom
或return\u tryFlag
,因为我不确定它们的用途
考虑到这些,我想到了以下几点:
#include <stdio.h>
#include <memory.h>
typedef struct node {
struct node * next;
int mark;
int flag;
struct node * backlink;
int data;
} node_lf;
typedef struct csArg {
node_lf * node;
int mark;
int flag;
} cs_arg;
bool cs3(node_lf * address, cs_arg *old_val, cs_arg *new_val) {
return __sync_bool_compare_and_swap((unsigned __int128 *)address,
*(unsigned __int128 *)old_val,
*(unsigned __int128 *)new_val);
}
void ShowIt(void *v)
{
unsigned long long *ull = (unsigned long long *)v;
printf("%p:%p", *ull, *(ull + 1));
}
int main()
{
cs_arg oldval, newval;
node n;
memset(&oldval, 0, sizeof(oldval));
memset(&newval, 0, sizeof(newval));
memset(&n, 0, sizeof(node));
n.mark = 3;
newval.mark = 4;
bool b;
do {
printf("If "); ShowIt(&n); printf(" is "); ShowIt(&oldval); printf(" change to "); ShowIt(&newval);
b = cs3(&n, &oldval, &newval);
printf(". Result %d\n", b);
if (b)
break;
memcpy(&oldval, &n, sizeof(cs_arg));
} while (1);
}
请注意,cas(正确!)在第一次尝试时失败,因为“旧”值与“当前”值不匹配
虽然使用汇编程序可以为您节省一两条指令,但在可读性、可维护性、可移植性等方面的胜利几乎肯定是值得的
如果出于某种原因,您必须使用内联asm,那么您仍然需要对结构重新排序,关于对齐的问题仍然存在。您也可以查看。它只使用8个字节,但概念是相同的。代码和错误消息应该在问题本身中。具体问题是x86上的“q”约束必须是a/b/c/dx,但您已经在为其他参数使用所有这些参数。也就是说,我希望推动不要使用内联asm。使用uuu sync\u bool\u compare\u和swap如何?或者甚至可能是std::atomic?我认为真正可能发生的是,
节点lf值
将值定义为数据结构(而不是指向数据结构的指针)而且不能放入64位寄存器。你真的想用那种方式传递值吗?@PeterCordes:是的,它是OCR'ed,比手工做更好;-)。我不得不修复许多问题,并且在错误消息中遗漏了一个小写的L
。但是我相信代码本身是相当准确的。我确实在一条评论中指出了value
的问题,询问OP是否真的打算做他们正在做的事情(显然他们不应该这样做)@MichaelPetch-是的,你是对的:问题是他正在按值返回结构。好吧,这与他试图用setz
设置结构的值相结合?value
将包含一个bool,指示cmpxchg16b是否成功。
If 0000000000000000:0000000000000003 is 0000000000000000:0000000000000000 change to 0000000000000000:0000000000000000. Result 0
If 0000000000000000:0000000000000003 is 0000000000000000:0000000000000003 change to 0000000000000000:0000000000000000. Result 1