gpt4 book ai didi

C++ 加载和存储优化和堆对象

转载 作者:太空狗 更新时间:2023-10-29 21:31:53 24 4
gpt4 key购买 nike

我正在尝试围绕对已加载或未加载到寄存器的内部类型的内存访问进行思考。

假设一些 SIMD 函数接受对 float 组的引用。例如,

void do_something(std::array<float, 4>& arr);
void do_something_else(std::array<float, 4>& arr);

每个函数首先将数据加载到寄存器中,执行其操作,然后将结果存储回数组中。假设以下片段:

std::array<float, 4> my_arr{0.f, 0.f, 0.f, 0.f};
do_something(my_arr);
do_something_else(my_arr);
do_something(my_arr);

C++ 编译器是否优化了函数调用之间不必要的加载和存储?这有关系吗?

我见过将 __m128 类型包装在结构中并在构造函数中调用加载的库。当您将这些存储在堆上并尝试调用它们的内在函数时会发生什么?例如,

struct vec4 {
vec4(std::array<float, 4>&) {
// do load
}

__m128 data;
};

std::vector<vec4> my_vecs;
// do SIMD work

每次访问都必须加载/存储数据吗?或者这些类是否应该声明一个私有(private)的 operator new,这样它们就不会存储在堆上?

最佳答案

如果编译器将函数与调用分开编译,它就无法优化存储和加载。当函数在一个 .cpp 文件中,调用在另一个 .cpp 文件中,并且未启用链接时间优化时,情况确实如此。

但是,如果编译器

  1. 同时(或在链接时间优化期间)查看函数定义及其调用,

  2. 决定内联函数调用并

  3. 决定融合循环,

然后它可能会删除不必要的存储和负载。

但是请注意,这三点都不是微不足道的。程序员只控制第一点,其他两点由编译器自行决定 100%。因此,您通常必须假设此类优化不会发生。如果您的函数实际上是模板(这也保证满足第 1 点),则内联的可能性会增加一点,但是编译器是否真的融合循环是您无法控制的。


关于包含 SIMD 类型的结构:SIMD 类型驻留在堆上是完全合法的。和在栈上分配完全没有区别。

但是,您不能只为 std::array<float, 4> 添加别名用__m128 ,那将违反严格的别名规则。重新诠释std::array<float, 4>__m128只能通过拷贝安全地发生(重新解释为 char* ,复制,重新解释为 __m128 ),否则允许您的编译器混淆对数组和 SIMD 类型的访问。

关于C++ 加载和存储优化和堆对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56727626/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com