2

我在 HLSL 中有 2 个不同的 64 位添加实现。如果我想设置 A += B,其中 al、ah、bl 和 bh 分别是 A 和 B 的低 32 位和高 32 位,那么我要么

(1):

#define pluseq64(al, ah, bl, bh) do {\
    uint tadd0 = al >> 1;\
    uint tadd1 = bl >> 1;\
    tadd0 += al & bl & 0x00000001;\
    tadd0 += tadd1;\
    tadd0 >>= 31;\
    al += bl;\
    ah += bh;\
    ah += tadd0;

或 (2):

#define pluseq64(al, ah, bl, bh) do {\
    uint t = al;\
    al += bl;\
    ah += bh;\
    if (al < t) { \
        ah += 1; \
    } } while(0)

现在,有趣的是,(1)总是产生正确的输出,而(2)则不会。鉴于(1)是一种混乱的操作(3个班次,5个加法来做一个64位+=),我更喜欢沿着(2)到(1)的路线,除了(2)不能正常工作。

作为(2)的替代方案,我尝试过:

#define pluseq64(al, ah, bl, bh) do {\
    uint t = al;\
    al += bl;\
    ah += bh;\
    ah += (al < t); } while(0)

这也不太有效(可能出于相同的原因,不管那个原因是什么,如果我有我的猜测)。

为什么(2)不能正常工作?奖励:有没有更好的方法在 HLSL 中添加 64 位?

谢谢!

4

2 回答 2

1

在我的测试中,这三个似乎在 C++ 上产生了等效的输出,所以这有点奇怪。您是否进行了 CPU 端测试并在那里为您工作?您可以尝试的一件事是跳过宏 & do/while 的东西,看看它是否适用于一个简单的 HLSL 函数:

void pluseq64(inout uint al, inout uint ah, in bl, in bh)
{
    uint t = al;
    al += bl;
    ah += bh;
    if (al < t)
    {
        ah += 1;
    }
    // or "ah += uint(al < t); 
}

无论如何,函数在 HLSL 中是内联的,所以我认为您不会从使用预处理器指令中获得任何收益。

于 2015-07-28T06:15:45.843 回答
0

也许您的代码片段显示了一个较旧的驱动程序错误?使用PIX逐步完成反汇编可能会有所帮助。我在 Nvidia/AMD/Intel 上使用了以下没有问题,这基本上等同于您的 (1)。

struct uint64_emulated
{
    uint32_t low;
    uint32_t high;
}

inline uint64_emulated Add(uint64_emulated a, uint64_emulated b)
{
    uint64_emulated c;
    c.low = a.low + b.low;
    c.high = a.high + b.high + (c.low < a.low); // Add with carry.
    return c;
}

于 2021-12-03T04:36:51.473 回答