0

编译器产生“警告 X3557:循环仅执行 0 次迭代,强制循环展开”,我不明白为什么。

这是源代码。它是一个重新访问的 itoa() 函数,用于 HLSL 在 uint 数组中生成结果 ascii 代码。

#define ITOA_BUFFER_SIZE 16
// Convert uint to ascii and return number of characters
uint UIntToAscii(
    in  uint Num,                   // Number to convert
    out uint Buf[ITOA_BUFFER_SIZE], // Where to put resulting ascii codes
    in  uint Base)                  // Numeration base for convertion
{
    uint I, J, K;

    I = 0;
    while (I < (ITOA_BUFFER_SIZE - 1)) {   // <==== Warning X3557
        uint Digit = Num % Base;
        if (Digit < 10)
            Buf[I++] = '0' + Digit;
        else
            Buf[I++] = 'A' + Digit - 10;
        if ((Num /= Base) == 0)
            break;
    }

    // Reverse buffer
    for (K = 0, J = I - 1; K < J; K++, J--) {     // <==== Warning X3557
        uint T = Buf[K];
        Buf[K] = Buf[J];
        Buf[J] = T;
    }

    // Fill remaining of buffer with zeros to make compiler happy
    K = I;
    while (K < ITOA_BUFFER_SIZE)
        Buf[K++] = 0;

    return I;
}

我试图重写while循环,但这并没有改变任何东西。还尝试使用属性 [fastopt] 没有成功。据我所见,该函数产生了正确的结果。

任何帮助表示赞赏。

4

1 回答 1

1

你得到的警告是

WAR_TOO_SIMPLE_LOOP 3557 循环只执行有限的迭代次数,或者似乎没有做任何事情,所以考虑删除它或强制它展开。

如果您认为循环在 GPGPU 中被认为效率低下,则该警告几乎是不言自明的,因此编译器会在可能的情况下尝试展开它们。编译器告诉您的是,您创建了一些循环,如果展开这些循环可以更有效地运行,或者可以删除,因为它们从不运行。如果循环不可滚动,则意味着您可以在编译时预测它将运行的次数。你的第一眼循环不应该满足这个标准。

    I = 0;
    while (I < (ITOA_BUFFER_SIZE - 1)) {   // <==== Warning X3557
        uint Digit = Num % Base;
        if (Digit < 10)
            Buf[I++] = '0' + Digit;
        else
            Buf[I++] = 'A' + Digit - 10;
        if ((Num /= Base) == 0)
            break;
    }

此 while 循环最多运行 15 次I < (ITOA_BUFFER_SIZE - 1),具体取决于(Num /= Base) == 0. 的最终值I介于 1 到 15 之间,具体取决于if ((Num /= Base) == 0)每个周期的评估方式。尽管如此,它仍然是不可滚动的,因为编译器仍可能在迭代中插入条件跳转。

// Reverse buffer
for (K = 0, J = I - 1; K < J; K++, J--) {     // <==== Warning X3557
    uint T = Buf[K];
    Buf[K] = Buf[J];
    Buf[J] = T;
}

相反,第二个循环不应该是不可滚动的,因为I编译器不应该知道。您报告的警告

警告 X3557:循环仅执行 0 次迭代,强制循环展开

if ((Num /= Base) == 0)如果总是在第一次迭代时计算为,则可能引用第true一个循环。在这种情况下,I将等于 1,并且J在第二个循环中将等于 0。第二个循环不会运行,因为K < Jfalse在第一次迭代时评估为。如果你让它最终得到的[unroll]可能是循环上的一次迭代while和后续循环的完全删除for。我高度怀疑这不是您的预期行为,虽然它可能会抑制警告,但您可能需要检查代码并查看是否有某些东西没有按应有的方式运行。

于 2019-09-04T19:06:00.893 回答