мне было скучно, так что я написал, не проверял (но скомпилирован, как Clang и GCC сделать разумный код из этого)
void interpolateAll(int n, float* scales, float* vin, float* vout)
{
// preconditions:
// (n & 7 == 0) (not really, but vout must be padded)
// scales & 31 == 0
// vin & 31 == 0
// vout & 31 == 0
// vin format:
// float v0x[8]
// float v0y[8]
// float v1x[8]
// float v1y[8]
// float v2x[8]
// float v2y[8]
// scales format:
// float scale0[8]
// float scale1[8]
// float scale2[8]
// vout format:
// float vx[8]
// float vy[8]
for (int i = 0; i < n; i += 8) {
__m256 scale_0 = _mm256_load_ps(scales + i * 3);
__m256 scale_1 = _mm256_load_ps(scales + i * 3 + 8);
__m256 scale_2 = _mm256_load_ps(scales + i * 3 + 16);
__m256 v0x = _mm256_load_ps(vin + i * 6);
__m256 v0y = _mm256_load_ps(vin + i * 6 + 8);
__m256 v1x = _mm256_load_ps(vin + i * 6 + 16);
__m256 v1y = _mm256_load_ps(vin + i * 6 + 24);
__m256 v2x = _mm256_load_ps(vin + i * 6 + 32);
__m256 v2y = _mm256_load_ps(vin + i * 6 + 40);
__m256 x = _mm256_mul_ps(scale_0, v0x);
__m256 y = _mm256_mul_ps(scale_0, v0y);
x = _mm256_fmadd_ps(scale_1, v1x, x);
y = _mm256_fmadd_ps(scale_1, v1y, y);
x = _mm256_fmadd_ps(scale_2, v2x, x);
y = _mm256_fmadd_ps(scale_2, v2y, y);
_mm256_store_ps(vout + i * 2, x);
_mm256_store_ps(vout + i * 2 + 8, y);
}
}
использует формат Z-бозона в, если я правильно понял его. В любом случае это хороший формат, с точки зрения SIMD. Немного неудобно с точки зрения C++.
FMAs сериализуют умножения без необходимости, но это не имеет значения, поскольку оно не является частью зависимой от цикла связи.
Прогнозируемая пропускная способность этого (при достаточно малом массиве) составляет 2 итерации за 9 циклов, узких мест в нагрузках. На практике, вероятно, немного хуже, были некоторые разговоры о простых магазинах, крадущих р2 или р3 изредка, такого рода вещи, я не совсем уверен. Во всяком случае, достаточно времени для 18 «FMA», но есть только 12 (8 и 4 мульпа), поэтому может быть полезно переместить некоторые дополнительные вычисления здесь, если они есть.
Слишком много раздражающего перемещения данных было бы необходимо. Если вы передали вершины (все те, которые нуждаются в интерполяции, а не только 3) и коэффициенты масштабирования в виде массивов, вы могли бы написать разумный код. – harold
@harold. Сколько элементов за один раз стоило бы? 16 комплектов? 256 наборов? – Steven
Как насчет 'struct Vector2_block {float8 x; float8 y; }; 'и' struct Vector3_block {float8 x; float8 y; float8 z; }; 'и затем вы работаете с 8 вершинами одновременно. –