Cuda 在asm volatile内联PTX指令中,为什么还要指定;“记忆”;副作用?

Cuda 在asm volatile内联PTX指令中,为什么还要指定;“记忆”;副作用?,cuda,language-lawyer,inline-assembly,redundancy,ptx,Cuda,Language Lawyer,Inline Assembly,Redundancy,Ptx,考虑CUDA指南(v10.2)的以下摘录: 编译器假定asm()语句没有副作用 除了更改输出操作数。以确保asm不受影响 在生成PTX期间删除或移动,应使用volatile 关键词,例如: asm volatile ("mov.u32 %0, %%clock;" : "=r"(x)); 通常,写入的任何内存都将被指定为输出 操作数,但如果对用户内存有隐藏的副作用(例如 例如,通过操作数间接访问内存位置),或者 您想停止围绕asm()语句的任何内存优化 在生成PTX期间执行,您可以添加“内存”缓

考虑CUDA指南(v10.2)的以下摘录:

编译器假定
asm()
语句没有副作用 除了更改输出操作数。以确保asm不受影响 在生成PTX期间删除或移动,应使用volatile 关键词,例如:

asm volatile ("mov.u32 %0, %%clock;" : "=r"(x));
通常,写入的任何内存都将被指定为输出 操作数,但如果对用户内存有隐藏的副作用(例如 例如,通过操作数间接访问内存位置),或者 您想停止围绕asm()语句的任何内存优化 在生成PTX期间执行,您可以添加“内存”缓冲区 第三个冒号后的规范

听起来像是
volatile
::“memory”
都是用来表示内存中的副作用。当然,现在可能会有非内存副作用(比如
trap;
)。但是-当我使用了
volatile
,同时指定
::“memory”
)不是没有用/没有意义吗


略微相关:

非易失性的内联asm语句被视为其输入的纯函数:每次使用相同的显式输入运行时都会给出相同的输出

另外,如果没有
“内存”
clobber,则不会读取或写入任何未提到的输入或输出操作数

听起来像volatile和::“memory”都是用来表示内存中的副作用

否,
volatile
仅表示输出操作数不是输入操作数的纯函数。
“内存”
clobber基本上是正交的,而不是由
volatile

您引用的示例似乎正在读取
%%时钟
周期计数器或每次都需要重新执行的某些内容,否则编译器可能会将其从循环中取出。您不希望强制编译器溢出/重新加载寄存器中的任何全局变量<代码>易失性并不意味着内存的副作用,所以它只是这个用例的标签

asm模板在编译器背后读取或写入任何其他变量(不是通过显式的
“m”
“=m”
,或
“+m”
操作数)仍然是一个错误,因为
volatile
并不意味着
内存

在GNU C内联asm中,即使是
“r”(指针变量)
也不意味着指向的数据被读取或写入。e、 g.如果您对变量所做的只是将指向该变量的指针作为输入传递给
asm
语句,而不使用
“内存”
clobber,则可以将赋值优化为死区存储

一个
“memory”
clobber将使编译器假定任何全局可访问的内存(或通过指针输入可访问的内存)可能已经被读取或写入,从而从asm语句周围的寄存器溢出/重新加载变量。(除非能够证明没有其他东西可以有指向它们的指针,即指向var的指针没有“逃逸”本地作用域。就像编译器决定可以在非内联函数调用的寄存器中保留var一样。)


如果没有
易失性
“内存”本身安全吗?否

如果没有使用asm语句的显式输出操作数,则
“内存”
clobber不会阻止asm语句进行优化。(如果没有“=…”操作数,
asm
语句是隐式可变的)

如果/当asm模板字符串执行时,必须假设带有内存阻塞器的非易失性asm语句在抽象机器中的该点修改任何可访问内存,但编译器仍然可以自由进行转换,从而导致根本不会发生这种情况,或者比源代码更不经常发生这种情况。(例如,如果在循环中更改的其他变量都是地址未逃逸函数的本地变量,则将其从循环中吊起。)


非易失性
asm语句仍然被假定为纯函数wrt。它的显式输入和输出,所以
asm(“…”:“=r”(out):“r”(in):“memory”),则可以从循环中提升code>。(只有当循环变量都是asm语句不能有指针指向的局部变量(如非内联函数调用的转义分析)时,才会发生这种情况。否则,
“memory”
clobber将阻止这种重新排序。)

或者完全优化掉,如果可以优化掉
“out”
的所有用法,而不考虑语句周围的任何内存访问。如果省略
volatile
,则判断仅基于显式操作数

没有易失性的
“内存”
clobber没有很多用例;您可以想象使用它来描述一个函数,该函数在内部使用缓存来存储结果。编译器可以根据需要频繁或不频繁地运行它,实际上我们并不关心内部缓存是否发生了变化。这是副作用,但不是有价值的副作用


我假设CUDA内联asm与GNU C内联asm具有相同的语义,由Clang/LLVM和GCC支持/实现。。从引文中可以看出确实如此。我对CUDA一无所知,所以我上面所说的一切都是基于GNU C内联asm的,因为CUDA asm似乎是相同的。Correc如果我错了,例如,如果没有输出操作数的
asm
语句不是隐式
volatile
,或者如果CUDA没有指针,请告诉我


由于GNU C内联asm语法是为C设计的,后来又为CUDA重新调整了用途,因此从C(包括指针和转义分析)的角度来考虑可能有助于您理解设计。)

我认为这是对的重复。他们正在讨论