Chromium源码阅读(12):Chromium不支持MSVC的原因:Double4类型的SIMD封装

Double4 类型用于向量化的SIMD(单指令多数据)操作,这些操作在优化变换代码中常用。其源码位于\blink\render\core\ui\gfx\geometry\double4.h
Double4 类型是一个高级的数据结构,用于存储四个双精度浮点数,并允许一次性对这四个数进行并行操作。
Double4 应该仅用于局部变量,或者内联函数的参数和返回值。不应该将它用于其他情况,如类的数据成员,因为有一些约束条件(例如,内存对齐)。

当需要重新排序 Double4 变量中的数据时,建议使用类似 {v[3], v[2], v[1], v[0]} 的形式而不是使用 __builtin_shufflevector() 等其他函数。

对于逻辑操作,例如比较和逻辑与操作,注释建议使用 AllTrue 函数来检查所有分量是否满足条件,并且在做逻辑与操作时使用位与操作符 & 而不是逻辑与操作符 && 以减少分支。

最后,注释指出使用的是 GCC 扩展(也被 Clang 支持),而不是 Clang 独有的扩展,以确保代码能够在 GCC 或 Clang 编译器上编译。

Double4 类型的源码非常简单,全部如下:

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_GEOMETRY_DOUBLE4_H_
#define UI_GFX_GEOMETRY_DOUBLE4_H_

#include <type_traits>

namespace gfx {

// This header defines Double4 type for vectorized SIMD operations used in
// optimized transformation code. The type should be only used for local
// variables, or inline function parameters or return values. Don't use the
// type in other cases (e.g. for class data members) due to constraints
// (e.g. alignment).
//
// Here are some examples of usages:
//
//   double matrix[4][4] = ...;
//   // The scalar value will be applied to all components.
//   Double4 c0 = Load(matrix[0]) + 5;
//   Double4 c1 = Load(matrix[1]) * Double4{1, 2, 3, 4};
//
//   Double4 v = c0 * c1;
//   // s0/s1/s2/s3 are preferred to x/y/z/w for consistency.
//   double a = v.s0 + Sum(c1);
//   // v.s3210 is equivalent to {v.s3, v.s2, v.s1, v.s0}.
//   // Should use this form instead of __builtin_shufflevector() etc.
//   Double4 swapped = {v[3], v[2], v[1], v[0]};
//
//   // Logical operations.
//   bool b1 = AllTrue(swapped == c0);
//   // & is preferred to && to reduce branches.
//   bool b2 = AllTrue((c0 == c1) & (c0 == v) & (c0 >= swapped));
//
//   Store(swapped, matrix_[2]);
//   Store(v, matrix_[3]);
//
// We use the gcc extension (supported by clang) instead of the clang extension
// to make sure the code can compile with either gcc or clang.
//
// For more details, see
//   https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html

#if !defined(__GNUC__) && !defined(__clang__)
// #error Unsupported compiler.
#endif

typedef double __attribute__((vector_size(4 * sizeof(double)))) Double4;
typedef float __attribute__((vector_size(4 * sizeof(float)))) Float4;

ALWAYS_INLINE double Sum(Double4 v) {
  return v[0] + v[1] + v[2] + v[3];
}

ALWAYS_INLINE Double4 LoadDouble4(const double s[4]) {
  return Double4{s[0], s[1], s[2], s[3]};
}

ALWAYS_INLINE void StoreDouble4(Double4 v, double d[4]) {
  d[0] = v[0];
  d[1] = v[1];
  d[2] = v[2];
  d[3] = v[3];
}

// The parameter should be the result of Double4/Float4 operations that would
// produce bool results if they were original scalar operators, e.g.
//   auto b4 = double4_a == double4_b;
// A zero value of a component of |b4| means false, otherwise true.
// This function checks whether all 4 components in |b4| are true.
// |&| instead of |&&| is used to avoid branches, which results shorter and
// faster code in most cases. It's used like:
//   if (AllTrue(double4_a == double4_b))
//     ...
//   if (AllTrue((double4_a1 == double4_b1) & (double4_a2 == double4_b2)))
//     ...
typedef int64_t __attribute__((vector_size(4 * sizeof(int64_t))))
DoubleBoolean4;
ALWAYS_INLINE int64_t AllTrue(DoubleBoolean4 b4) {
  return b4[0] & b4[1] & b4[2] & b4[3];
}

typedef int32_t __attribute__((vector_size(4 * sizeof(int32_t)))) FloatBoolean4;
ALWAYS_INLINE int32_t AllTrue(FloatBoolean4 b4) {
  return b4[0] & b4[1] & b4[2] & b4[3];
}

}  // namespace gfx

#endif  // UI_GFX_GEOMETRY_DOUBLE4_H_

我们仔细分析。

#ifndef UI_GFX_GEOMETRY_DOUBLE4_H_
#define UI_GFX_GEOMETRY_DOUBLE4_H_

这是一个包含保护,用于防止头文件被多次包含。如果 UI_GFX_GEOMETRY_DOUBLE4_H_ 还未定义,则定义它,这样头文件的内容只会在第一次包含时被处理。

namespace gfx {

声明一个命名空间 gfx,这意味着下面定义的所有类型和函数都将在这个命名空间下,以免与其他库的名字冲突。

#if !defined(__GNUC__) && !defined(__clang__)
#error Unsupported compiler.
#endif

这是一个编译时检查,用来确定是否使用支持 GCC 或 Clang 扩展的编译器。如果两者都不支持,会有一个错误指令来阻止编译。

typedef double __attribute__((vector_size(4 * sizeof(double)))) Double4;
typedef float __attribute__((vector_size(4 * sizeof(float)))) Float4;

这里定义了两个新类型 Double4Float4,分别是由四个 double 和四个 float 组成的 SIMD 类型。__attribute__((vector_size(n))) 是 GCC 的一个扩展属性,它告诉编译器创建一个有 n 字节大小的向量类型。这就是为什么需要编译器扩展的原因:标准 C++ 没有直接支持这种数据类型。

ALWAYS_INLINE double Sum(Double4 v) {
  return v[0] + v[1] + v[2] + v[3];
}

定义了一个内联函数 Sum,它将 Double4 类型的四个分量相加并返回结果。ALWAYS_INLINE 是一个宏,通常用来告诉编译器尽可能内联此函数,以避免函数调用的开销。

ALWAYS_INLINE Double4 LoadDouble4(const double s[4]) {
  return Double4{s[0], s[1], s[2], s[3]};
}

定义了一个内联函数 LoadDouble4,它接受一个 double 类型的数组,并将其值加载到一个 Double4 类型的变量中。

ALWAYS_INLINE void StoreDouble4(Double4 v, double d[4]) {
  d[0] = v[0];
  d[1] = v[1];
  d[2] = v[2];
  d[3] = v[3];
}

定义了一个内联函数 StoreDouble4,它将 Double4 类型的变量的值存储到一个 double 类型的数组中。

typedef int64_t __attribute__((vector_size(4 * sizeof(int64_t)))) DoubleBoolean4;
ALWAYS_INLINE int64_t AllTrue(DoubleBoolean4 b4) {
  return b4[0] & b4[1] & b4[2] & b4[3];
}

定义了 DoubleBoolean4 类型,它是一个由四个 int64_t 组成的 SIMD 类型,用于存储逻辑操作的结果。AllTrue 函数检查 DoubleBoolean4 类型的所有分量是否都是真值(非零)。

typedef int32_t __attribute__((vector_size(4 * sizeof(int32_t)))) FloatBoolean4;
ALWAYS_INLINE int32_t AllTrue(FloatBoolean4 b4) {
  return b4[0] & b4[1] & b4[2] & b4[3];
}

DoubleBoolean4 类似,FloatBoolean4 是一个由四个 int32_t 组成的 SIMD 类型,AllTrue 函数同样检查是否所有分量都是真值。

总体来说,这个源文件利用了编译器提供的 SIMD 扩展来定义可以存储和操作多个数据项的类型。这些操作通常比逐一处理数据项更快,因为它们允许并行操作。由于这些扩展不是标准 C++ 的一部分,因此文件中的代码依赖于支持这些扩展的编译器,GCC 或 Clang。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值