Cuda 有符号 128 位乘法错误
Cuda signed 128-bit multiplication error
我想我在 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)
并且显然不为零。
首先,我想确保我的理解是正确的,但还有,有没有办法解决这个问题?
Update 从 Debug
mod 更改为 Release
mode 修复了这个问题,仍然想知道这是否是一个cuda 中的错误?
更新 2
已将此错误报告给 NVIDIA
在 Visual Studio 2013 中使用了 Cuda 工具包 7.5。x64 Debug
、sm_52
、compute_52
。
TL;DR 这似乎是 PTX 指令 mul.hi.s64
仿真中的错误,该指令特定于 sm_5x
平台,因此提交向 NVIDIA 报告错误是推荐的做法。
通常,NVIDIA GPU 是 32 位架构,因此所有 64 位整数指令都需要仿真序列。在 64 位整数乘法的特殊情况下,对于 sm_2x
和 sm_3x
平台,这些是从机器代码指令 IMAD.U32
构造的,它是一个 32 位整数乘加指令.
对于 Maxwell 架构(即 sm_5x
),引入了高吞吐量但宽度较低的整数乘加指令 XMAD
,尽管低吞吐量遗留 32 -bit integer multipy IMUL
显然被保留了下来。检查使用 cuobjdump --dumpsass
的 CUDA 7.5 工具链为 sm_5x
生成的反汇编机器代码表明,对于 ptxas
优化级别 -O0
(用于调试构建),64-使用 IMUL
指令模拟位乘法,而对于优化级别 -O1
和更高级别,使用 XMAD
。我想不出使用两个根本不同的仿真序列的原因。
事实证明,mul.hi.s64
和 sm_5x
的基于 IMUL
的仿真被破坏,而基于 XMAD
的仿真工作正常。因此,一种可能的解决方法是通过在 nvcc
命令行上指定 -Xptxas -O1
,为 ptxas
使用至少 -O1
的优化级别。请注意,默认情况下发布版本使用 -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
我想我在 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)
并且显然不为零。
首先,我想确保我的理解是正确的,但还有,有没有办法解决这个问题?
Update 从 Debug
mod 更改为 Release
mode 修复了这个问题,仍然想知道这是否是一个cuda 中的错误?
更新 2 已将此错误报告给 NVIDIA
在 Visual Studio 2013 中使用了 Cuda 工具包 7.5。x64 Debug
、sm_52
、compute_52
。
TL;DR 这似乎是 PTX 指令 mul.hi.s64
仿真中的错误,该指令特定于 sm_5x
平台,因此提交向 NVIDIA 报告错误是推荐的做法。
通常,NVIDIA GPU 是 32 位架构,因此所有 64 位整数指令都需要仿真序列。在 64 位整数乘法的特殊情况下,对于 sm_2x
和 sm_3x
平台,这些是从机器代码指令 IMAD.U32
构造的,它是一个 32 位整数乘加指令.
对于 Maxwell 架构(即 sm_5x
),引入了高吞吐量但宽度较低的整数乘加指令 XMAD
,尽管低吞吐量遗留 32 -bit integer multipy IMUL
显然被保留了下来。检查使用 cuobjdump --dumpsass
的 CUDA 7.5 工具链为 sm_5x
生成的反汇编机器代码表明,对于 ptxas
优化级别 -O0
(用于调试构建),64-使用 IMUL
指令模拟位乘法,而对于优化级别 -O1
和更高级别,使用 XMAD
。我想不出使用两个根本不同的仿真序列的原因。
事实证明,mul.hi.s64
和 sm_5x
的基于 IMUL
的仿真被破坏,而基于 XMAD
的仿真工作正常。因此,一种可能的解决方法是通过在 nvcc
命令行上指定 -Xptxas -O1
,为 ptxas
使用至少 -O1
的优化级别。请注意,默认情况下发布版本使用 -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