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

ein*_*ica 3 redundancy cuda inline-assembly language-lawyer ptx

考虑以下来自 CUDA 的Inline PTX Assebly指南 (v10.2) 的摘录:

编译器假定asm()语句除了更改输出操作数之外没有副作用。为确保在生成 PTX 期间不会删除或移动 asm,您应该使用 volatile 关键字,例如:

asm volatile ("mov.u32 %0, %%clock;" : "=r"(x));
Run Code Online (Sandbox Code Playgroud)

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

这听起来像是两者 volatile:: "memory"旨在表明内存中的副作用。现在,当然,可能存在非记忆副作用(例如 for trap;)。但是 - 当我使用 时volatile,也指定:: "memory")不是没用/没有意义吗?

稍微相关:当使用内联 PTX asm() 指令时,'volatile' 有什么作用?

Pet*_*des 5

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

另外,没有"memory"破坏:不读取或写入任何未作为输入或输出操作数提及的内容。

听起来 volatile 和 :: "memory" 都是为了表示内存中的副作用。

不,volatile 只是意味着输出操作数不是输入操作数的纯函数。一"memory"撞大多是正交的,没有通过暗示volatile

您引用的示例似乎正在读取%%clock循环计数器或每次都需要重新执行的内容,否则编译器可能会执行CSE并将其提升出循环。您不希望它强制编译器溢出/重新加载它在寄存器中的任何全局变量。 volatile并不意味着内存副作用,所以它只是这个用例的票。

这仍然是一个错误的ASM模板来读取或写入编译器背后的任何其他变量(不通过明确的"m""=m""+m"操作数),因为volatile并不意味着"memory"撞。

在GNU C内联汇编甚至"r"(pointer_variable)没有暗示指向的数据被读取或写入。例如,如果您对变量所做的只是将指向它的指针作为输入传递给asm没有"memory"破坏的语句,则可以将赋值优化为死存储。 如何指示可以使用内联 ASM 参数*指向*的内存?

"memory"得到的编译器假定任何全局可到达的存储器(或通过指针输入可达)可能已被读出或写入,从而溢出/重装从围绕这样asm语句寄存器瓦尔。(除非转义分析可以证明没有其他任何东西可以有指向它们的指针,即指向 var 的指针没有“转义”局部作用域。就像编译器决定他们如何将 var 保存在寄存器中的非-内联函数调用。)


那么"memory"单独安全没有volatile吗?不

"memory"撞不从,如果没有其明确的输出操作数均采用优化掉停止asm语句。(没有“=...”操作数,一个asm语句是隐式易变的)。

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

volatileasm 语句仍被假定为纯函数 wrt。它的显式输入和输出,因此asm("..." : "=r"(out) : "r"(in) : "memory");如果循环"in"每次迭代都使用相同的内容,则可以将其提升到循环之外。(只有当循环变量都是 asm 语句无法指向的局部变量时才会发生这种情况(转义分析类似于非内联函数调用)。否则"memory" clobber 会阻止重新排序。)

或者如果所有使用"out"都可以优化掉,则完全优化掉,而不管语句周围的任何内存访问。如果省略 ,则该决定基于显式操作数volatile

"memory"没有volatile;的clobber 没有很多用例;你可以想象用它来描述一个内部使用缓存来记忆结果的函数。编译器可以根据需要经常或不经常运行它,我们实际上并不关心内部缓存是否发生了变异。这是一个副作用,但不是一个有价值的副作用。


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

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