对具有不匹配宽度的输出缓冲区进行矢量化

时间:2017-04-28 15:06:11

标签: c++ halide

我的生成器在其计划中使用.vectorize(x, 8)。我面临的问题是,如果我的输出缓冲区宽度不是8的幂,我将获得缓冲区外的访问权限!我当然可以将输入x, y限制为图像的大小,但我想知道是否有任何方法可以使用我的生成器中的Output<Func>。也许我没有以正确的方式看问题?

class BasicGenerator : public Generator<BasicGenerator>
{
public:
    Var x, y;

    Input<Func> input { "input", UInt(8), 2 }
    Output<Func> output { "output", UInt(8), 2 }

    void generate()
    {
        output(x, y) = input(x, y);
    }

    void schedule()
    {
        output.vectorize(x, 8).parallel(y);
    }
};

1 个答案:

答案 0 :(得分:2)

vectorize指令采用TailStrategy参数。这可以控制如何处理矢量化范围的结束。您描述的行为似乎是RoundUp,这是减少的默认行为。非减少的默认值为ShiftInwardsRoundUp强制约束宽度是矢量化宽度的倍数。 (注意,“8的倍数”与上面所写的“8的幂”不同。)ShiftInwards强加宽度至少是矢量化大小的约束。 ShiftInwards在循环结束时导致少量冗余计算,因此不能用于减少,因为它们不是幂等的。 (即重复部分计算可以改变结果。)

还有GuardWithIf尾巴策略。这在所有情况下都是安全的,但往往导致代码被标记,从而失去性能。我们计划使用向量预测来使这项工作更好,但目前尚不清楚这将在所有架构上实现。

还有另外两种机制需要了解。第一个是BoundaryConditions。这就是你在提到夹具时所想到的。 (在它的核心,BoundaryConditions函数基于clamp,但它们还做了一些其他的事情来帮助编译器,并且应该使代码更清晰。)将BoundaryConditions视为正确性问题,而非性能问题。当给定输出的输入不足时,您希望算法做什么?一旦你决定了正确的事情,它可以通过BoundaryConditions实现,或者在某些情况下被忽略,因为它不允许发生。

BoundaryConditions通常会在性能上付出一些代价。希望它在常用中相当小,但事实证明很难在很多硬件上使它们自由。

第二种机制是在时间表中使用specialize。这样可以快速处理大小合适的大小写,同时回退到较慢而正确的代码。通常你会写一些类似的东西:

f.specialize(input.width() % 8 == 0).vectorize(x, 8);