如果指针完全相同,C++指针是否是一个别名威胁



考虑这个用于矢量化的函数:

void AddSqr(float* restrict dst, float* restrict src, int cnt)
{
    for (int i=0; i<cnt; i++) dst[i] = src[i] * src[i];
};

如果src&dst当然没有别名。但是如果src=dst呢?当然,诸如src==dst+1这样的极端情况是不允许的。但如果指针相同,就不会有问题,或者我遗漏了什么?

Edit:restrict是英特尔C++编译器关键字,MSVC有__restrict。

我对这个问题的看法是,我不认为任何形式的矢量化都会出错:由于每个dst值都依赖于完全不同(没有任何别名)或完全相同地址的单个src值,因此当dst更改时,将不再需要src值,因为它已经被写入意味着输出已经被计算出来。唯一的情况是编译器将dst本身用作临时缓冲区,我认为这是不正确的。

在C中,您的代码违反restrict定义,导致未定义行为,因为它通过dst写入一个对象,但通过src读取同一对象。

dstsrc之间是否存在偏移并不重要;条件是存在通过一个指针写入并通过另一个指针读取的CCD_ 6对象。

Restrict是一个关键字,用于允许一些只有在两个指针不相互干扰的情况下才有效的优化。

对于非常简单的情况,当两个指针相同时,不太可能有任何可用的优化会失败,所以当你测试时,不会发生任何糟糕的事情。

但在更常见的情况下,restrict关键字意味着您断言两个指针不同,并且它们所指向的数据结构不同。编译器可以自由使用这个断言来进行任何它想要的优化,特别是如果你的断言不正确,会使你的程序灾难性地失败的优化。

这种失败被称为"未定义行为",因为C标准没有定义断言错误时会发生什么。由于这是一个优化断言,完全不可预测的行为,通常被称为"鼻恶魔",是C编译器定义的合理行为。

感谢各位的回答。因此:-按照标准C++的定义,这确实是不正确的。-然而,我直接从英特尔得到回复,这是可以的。

我最初的问题实际上不是关于它是否"遵守规则",而是它是否有可能出错。src/dst数组是1:1映射的,因此数组要么完全不同,要么完全相同,因此每个项要么依赖于一些完全不相关的项,要么依赖于其本身。因此,如果项目被重写,则其最终值已被计算存储,在循环期间将不再需要。

无论如何,我做了一些额外的处理:

void AddSqr(float* restrict dst, float* restrict src, int cnt)
{
    if (dst == src)
        for (int i=0; i<cnt; i++) dst[i] = dst[i] * dst[i];
    else
        for (int i=0; i<cnt; i++) dst[i] = src[i] * src[i];
};

这应该可以解决潜在的问题,甚至提供一些额外的优化可能性,因为在指针相同的情况下,编译器可以只使用一个寄存器(或者不使用偏移寄存器)来针对数组。

最新更新