【问题标题】:Storing an std::assume_aligned pointer C++ 20存储 std::assume_aligned 指针 C++ 20
【发布时间】:2020-11-22 22:23:17
【问题描述】:

在 C++ 20 中,我们假设对齐,这对于音频代码非常有用,其中指向对齐的浮点块的指针一直在传递。假设我们有以下跨度类型:

template<typename T>
struct Signal
{
    const T* data
    size_t size;
};

如何表明这个结构中的数据指针是由某个 constexpr 整数对齐的?在 C++ 20 中是否已经可以实现这样的功能?

constexpr int SIMDAlignment = 16;

template<typename T>
struct Signal
{
    aligned<SIMDAlignment> const T* data
    size_t size;
};

【问题讨论】:

    标签: c++ traits simd c++20 memory-alignment


    【解决方案1】:

    似乎 assume-aligned 提示是特定指针对象的属性,不能成为指针类型的属性。但是,您可能会尝试通过(内联)getter 函数包装该指针,并使用std::assume_aligned 作为其返回值。例如,在我的实验中,当我使用这样一个函数返回的指针时,它被GCC正确地视为“对齐”(指向对齐的数据):

    double* f()
    {
      static double* data =
        (double*)std::aligned_alloc(64, 1024 * sizeof(double));
      return std::assume_aligned<64>(data);
    }
    
    void g()
    {
      double* a = f();
      for (int i = 0; i < 1024; i++)
        a[i] = 123.45;
    }
    

    在这种情况下,数组由vmovapd 填充,这需要对齐的内存访问。

    相反,当我改变时:

    return std::assume_aligned<64>(data);
    

    到:

    return data;
    

    生成的程序集包含vmovupd,它适用于未对齐的数据。

    现场演示:https://godbolt.org/z/d5aPPj — 检查两种情况下的 .L19 循环。

    【讨论】:

    • 这是有道理的,从名称来看,它只是 GNU C void *__builtin_assume_aligned(void*, size_t)std 版本也就不足为奇了。 gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html(在 C 中与 foo = __builtin_assume_aligned(foo, 64); 类似,允许与 void* 进行隐式转换。)
    • @PeterCordes 是的;甚至相应的提案也提到了__builtin_assume_aligned 为 GCC 和 Clang 提供的可能实现:open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1007r3.pdf
    • 在 GNU C 中,您有时可以执行 typedef int aligned_int __attribute__((aligned(16))) 之类的操作并拥有指向该类型的指针,但这是分开的。 (并且不那么容易工作,因为 sizeof(aligned_int) 也是 16,有填充)。 typedef 技巧更适合声明 under-aligned 和 may_alias 版本的类型。
    猜你喜欢
    • 2017-12-03
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多