存储 std::assume_aligned 指针 C++ 20

Posted

技术标签:

【中文标题】存储 std::assume_aligned 指针 C++ 20【英文标题】:Storing an std::assume_aligned pointer 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;
;

【问题讨论】:

【参考方案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 版本的类型。

以上是关于存储 std::assume_aligned 指针 C++ 20的主要内容,如果未能解决你的问题,请参考以下文章

指针与指针变量

在 C++ 中使用指针和指向指针的指针读取和存储序列化对象的快速方法

如何将一个指针指向的地址存储到另一个指针?

C语言 如何给指针数组划分动态存储空间

线性表的链式存储结构

从指向函数指针数组的指针中存储返回值如何工作?