我认为在使用有符号整数在cuda PTX中进行128位有符号乘法时发现了一个问题。 这是我的示例代码:
long long result_lo, result_hi;
asm(" mul.lo.s64 %0, 0, -1; \n\t" // 0 * -1 = 0
" mul.hi.s64 %1, 0, -1; \n\t"
: "=l"(result_lo), "=l"(result_hi));
这应该产生结果result_lo = 0x0, result_hi = 0x0
。然而,这会产生结果:result_lo = 0x0, result_hi = 0xFFFFFFFFFFFFFFFF
如果我没有弄错并且显然不是零,那么它实际上是值2^127 - (2^126 - 1)
。
首先,我想确保我的理解是正确的,但更多的是,还有办法解决这个问题吗?
更新从Debug
mod更改为Release
模式修复此问题,仍然想知道这是否是cuda中的错误?
更新2 向NVIDIA报告了这个错误
在Visual Studio 2013中使用过Cuda toolkit 7.5。x64 Debug
,sm_52
,compute_52
。
答案 0 :(得分:3)
TL; DR 这似乎是模拟mul.hi.s64
平台专用的PTX指令sm_5x
的错误,因此向NVIDIA提交错误报告是推荐的行动方案。
通常,NVIDIA GPU是32位架构,因此所有64位整数指令都需要仿真序列。在64位整数乘法的特定情况下,对于sm_2x
和sm_3x
平台,这些是从机器代码指令IMAD.U32
构造的,这是一个32位整数乘加指令。
对于Maxwell架构(即sm_5x
),引入了高吞吐量但宽度较低的整数乘加指令XMAD
,尽管是低吞吐量的传统32位显然保留了整数乘法IMUL
。通过带有sm_5x
的CUDA 7.5工具链检查为cuobjdump --dumpsass
生成的反汇编机器代码,显示ptxas
优化级-O0
(用于调试版本),64-使用IMUL
指令模拟位乘法,而使用更高级-O1
和更高XMAD
。我想不出为什么采用两种根本不同的仿真序列的原因。
事实证明,基于IMUL
的基于mul.hi.s64
的{{1}}基于sm_5x
的模拟已经被打破,而基于XMAD
的模拟工作正常。因此,一种可能的解决方法是通过在-O1
命令行上指定ptxas
,为-Xptxas -O1
使用至少nvcc
的优化级别。请注意,发布版本默认使用-Xptxas -O3
,因此发布版本不需要采取纠正措施。
通过代码分析,mul.hi.s64
的仿真实现为mul.hi.u64
仿真的包装,后一种仿真似乎在包括sm_5x
在内的所有平台上都能正常工作。因此,另一种可能的解决方法是在mul.hi.u64
周围使用我们自己的包装器。在这种情况下,不需要使用内联PTX进行编码,因为mul.hi.s64
和mul.hi.u64
可通过设备内在函数__mul64hi()
和__umul64hi()
访问。从下面的代码中可以看出,将结果从无符号转换为有符号乘法的调整相当简单。
long long int m1, m2, result;
#if 0 // broken on sm_5x at optimization level -O0
asm(" mul.hi.s64 %0, %1, %2; \n\t"
: "=l"(result)
: "l"(m1), "l"(m2));
#else
result = __umul64hi (m1, m2);
if (m1 < 0LL) result -= m2;
if (m2 < 0LL) result -= m1;
#endif