0

我想我在使用有符号整数在 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)

首先,我想确保我的理解是正确的,但是,有没有办法解决这个问题?

更新Debugmod 更改为Releasemode 修复了这个问题,仍然想知道这是否是 cuda 中的错误?

更新 2 将此错误报告给 NVIDIA

将 Cuda 工具包 7.5 与 Visual Studio 2013 一起使用。x64 Debug, sm_52, compute_52.

4

1 回答 1

3

TL;DR这似乎mul.hi.s64是特定于sm_5x平台的 PTX 指令仿真中的错误,因此建议向 NVIDIA 提交错误报告。

通常,NVIDIA GPU 是 32 位架构,因此所有 64 位整数指令都需要仿真序列。在 64 位整数乘法的特定情况下,forsm_2xsm_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.s64for仿真sm_5x被破坏,而XMAD基于 - 的仿真工作正常。因此,一种可能的解决方法是通过在命令行上指定来利用至少-O1为 for的优化级别。请注意,默认情况下使用发布构建,因此发布构建不需要更正操作。ptxas-Xptxas -O1nvcc-Xptxas -O3

从代码分析来看,for 的仿真mul.hi.s64被实现为 仿真的包装器mul.hi.u64,而后一种仿真似乎在所有平台上都可以正常工作,包括sm_5x. 因此,另一种可能的解决方法是使用我们自己的mul.hi.u64. 在这种情况下,不需要使用内联 PTX 进行编码,因为mul.hi.s64mul.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
于 2016-02-14T20:51:57.160 回答