C++ 中文周刊 第89期

周刊项目地址

公众号

欢迎投稿,推荐或自荐文章/软件/资源等

可以贴在下一期草稿里 草稿链接

2022 1118 今天有事,提前发了


资讯

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2022-11-16 第176期

文章

使用target_clones能帮助生成平台兼容的SIMD代码,具体呢就是生成N份汇编。比如这种。https://godbolt.org/z/of5d6v

但问题在于,某些平台某些libc某些编译器可能不支持/支持程度不够,导致你用了这玩意但是实际上没生效,使用的时候需要注意

一个perf查性能的思路。当然循环里的if是比较不合时宜的,不利于编译器展开

循环访问大有学问,涉及到 循环的优化,上面也说了,循环里的条件判断非常不合理

constexpr auto tuple = [][[nodiscard]](auto... args) {
    return [=][[nodiscard]](auto fn)  { return fn(args...); };
};

constexpr auto apply(auto fn, auto t) { return t(fn); };

static_assert(0 == apply([](auto... args) { return sizeof...(args); }, tuple()));
static_assert(1 == apply([](auto... args) { return sizeof...(args); }, tuple(1)));
static_assert(2 == apply([](auto... args) { return sizeof...(args); }, tuple(1, 2)));

namespace detail {
template <std::size_t N, typename T> struct elem_by_index { T &ref; };
template <typename T> struct elem_by_type { T &ref; };
} // namespace detail

template <auto N> [[nodiscard]] constexpr auto get(auto t) {
    return t([]<typename... Ts>(Ts... elems) {
        return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
            struct all_elems : detail::elem_by_index<Is, Ts>... {};
            return []<typename U>(const detail::elem_by_index<N, U> &elem) {
                return elem.ref;
            }(all_elems{elems...});
        }(std::index_sequence_for<Ts...>{});
    });
}

template <class T> [[nodiscard]] constexpr auto get(auto t) {
    return t([]<typename... Ts>(Ts... elems) {
        struct all_elems : detail::elem_by_type<Ts>... {};
        return [](const detail::elem_by_type<T> &elem) {
            return elem.ref;
        }(all_elems{elems...});
    });
};

看不懂

改写这个

int f() {
    int* data = new int[2];
    data[0] = 1;
    data[1] = 2;
    int x = data[0];
    int y = data[1];
    int z = data[2];
    delete[] data;
    return x + y;
} 

用avx512 第一版

float dot512fma(float *x1, float *x2, size_t length) {
  // create a vector of 16 32-bit floats (zeroed)
  __m512 sum = _mm512_setzero_ps();
  for (size_t i = 0; i < length; i += 16) {
    // load 16 32-bit floats
    __m512 v1 = _mm512_loadu_ps(x1 + i);
    // load 16 32-bit floats

    __m512 v2 = _mm512_loadu_ps(x2 + i);
    // do sum[0] += v1[i]*v2[i] (fused multiply-add)
    sum = _mm512_fmadd_ps(v1, v2, sum);
  }
  // reduce: sums all elements
  return _mm512_reduce_add_ps(sum);
}

问题在于 i<length越界,如何解决 ?这就用标题讲的 mask load/store

float dot512fma(float *x1, float *x2, size_t length) {
  // create a vector of 16 32-bit floats (zeroed)
  __m512 sum = _mm512_setzero_ps();
  size_t i = 0;
  for (; i + 16 <= length; i+=16) {
    // load 16 32-bit floats
    __m512 v1 = _mm512_loadu_ps(x1 + i);
    // load 16 32-bit floats
    __m512 v2 = _mm512_loadu_ps(x2 + i);
    // do sum[0] += v1[i]*v2[i] (fused multiply-add)
    sum = _mm512_fmadd_ps(v1, v2, sum);
  }
  if  (i  < length) {
    // load 16 32-bit floats, load only the first length-i floats
    // other floats are automatically set to zero
    __m512 v1 = _mm512_maskz_loadu_ps((1<<(length-i))-1, x1 + i);
    // load 16 32-bit floats, load only the first length-i floats
    __m512 v2 = _mm512_maskz_loadu_ps((1<<(length-i))-1, x2 + i);
    // do sum[0] += v1[i]*v2[i] (fused multiply-add)
    sum = _mm512_fmadd_ps(v1, v2, sum);
  }
  // reduce: sums all elements
  return _mm512_reduce_add_ps(sum);
}

arm平台怎么做?

float dotsve(float *x1, float *x2, int64_t length) {
  int64_t i = 0;
  svfloat32_t sum = svdup_n_f32(0);
  while(i + svcntw() <= length) {
    svfloat32_t in1 = svld1_f32(svptrue_b32(), x1 + i);
    svfloat32_t in2 = svld1_f32(svptrue_b32(), x2 + i);
    sum = svmad_f32_m(svptrue_b32(), in1, in2, sum);
    i += svcntw();
  }
  svbool_t while_mask = svwhilelt_b32(i, length);
  do {
    svfloat32_t in1 = svld1_f32(while_mask, x1 + i);
    svfloat32_t in2 = svld1_f32(while_mask, x2 + i);
    sum = svmad_f32_m(svptrue_b32(), in1, in2, sum);
    i += svcntw();
    while_mask = svwhilelt_b32(i, length);
  } while (svptest_any(svptrue_b32(), while_mask));

  return svaddv_f32(svptrue_b32(),sum);
}

代码在这里,可以简单玩一下 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2022/11/08

鼓励多用final。这个是常识了

代码重构。没啥说的

介绍 ODR相关的检测,很长

编译期的字符串,怎么编译期查长度?strlen不是constexpr,不行

#include <string>

constexpr std::size_t constexpr_strlen(const char* s)
{
    return std::char_traits<char>::length(s);
    // return std::string::traits_type::length(s);
}

constexpr std::size_t constexpr_wcslen(const wchar_t* s)
{
    return std::char_traits<wchar_t>::length(s);
    //  return std::wstring::traits_type::length(s);
}

void f() { E1 x = static_cast(2); // undefined behavior, 2 is outside the range of values }

``` 这种是UB,UBSan能抓到,也可以用 -fstrict-enums来抓

介绍了一些语言相关的优化/论文/点子,比如GC/JIT之类的,jdk/python相关的进展,感兴趣的可以看看

视频

这周没看。有啥推荐的也可以发一下。CPPCON 2022新出了俩协程教程,没看

开源项目需要人手

新项目介绍/版本更新


本文永久链接

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账