2D数组SIMD内联汇编内存输出操作数的lvalue问题如何解决?
报错核心原因
你最初的推测是对的:"=m" 是GCC内联汇编的内存输出约束,要求绑定的对象必须是可寻址的左值,也就是编译器可以直接拿到它的内存地址、可以直接写入的对象。而matrix[i] + k是指针加法运算产生的临时右值,没有对应的固定内存位置,自然没法满足m约束的左值要求,所以编译报错。
第一种方案的原理
第一种写法把matrix[i] + k从输出约束移到了输入约束,并且用了"r"(寄存器)约束:
r约束的要求非常宽松:只要表达式的值可以被计算出来,加载到某个通用寄存器里就行,不区分左值右值,所以matrix[i] + k的地址值可以正常被加载到寄存器中。- 你在汇编代码里写的
vmovups %%ymm0, (%0),意思是把ymm0的值写到%0寄存器存储的地址对应的内存位置,不需要编译器直接操作内存对象,自然就没有左值要求。 - 这里没有声明任何输出约束,也避开了输出约束需要绑定左值的问题。
第二种方案的运行逻辑
第二种写法本质上和第一种是等价的,只是用了另一种约束规则实现了同样的效果:
- 输出约束
"=r"(matrixPointer)是让编译器分配一个通用寄存器,执行完汇编代码后,把这个寄存器的值写入matrixPointer这个左值变量,满足了输出约束需要左值的要求。 - 输入约束里的
"0"是GCC内联汇编的特殊约束,意思是「和第0个输出项使用同一个寄存器」,也就是执行汇编前,会先把matrix[i] + k的地址值加载到和输出绑定的同一个寄存器里。 - 汇编逻辑和第一种完全一样:把ymm0的值写到
%0寄存器存的地址对应的内存里,虽然这里给matrixPointer赋了值但后续没有使用,不影响功能,只是绕了一步实现了把地址放到寄存器的效果。
内容的提问来源于stack exchange,提问作者lyect
相关产品推荐
相关产品推荐

