@@ -1036,29 +1036,30 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10361036 AVS_UNUSED (bits_per_pixel);
10371037
10381038 const int filter_size = program->filter_size ;
1039- const float * AVS_RESTRICT current_coeff = program->pixel_coefficient_float ;
1039+ const float * AVS_RESTRICT current_coeff = ( const float * AVS_RESTRICT ) program->pixel_coefficient_float ;
10401040
10411041 const float * src = (const float *)src8;
10421042 float * AVS_RESTRICT dst = (float *)dst8;
1043- dst_pitch = dst_pitch / sizeof (float );
1044- src_pitch = src_pitch / sizeof (float );
10451043
1046- const int kernel_size = program->filter_size_real ; // not the aligned
1047- const int kernel_size_mod2 = (kernel_size / 2 ) * 2 ; // Process pairs of rows for better efficiency
1044+ const int dst_stride_float = dst_pitch / sizeof (float );
1045+ const int src_stride_float = src_pitch / sizeof (float );
1046+
1047+ const int kernel_size = program->filter_size_real ;
1048+ // Pre-calculate Mod2 size for the remainder loop
1049+ const int kernel_size_mod2 = (kernel_size / 2 ) * 2 ;
10481050 const bool notMod2 = kernel_size_mod2 < kernel_size;
10491051
10501052 for (int y = 0 ; y < target_height; y++) {
10511053 int offset = program->pixel_offset [y];
1052- const float * src_ptr = src + offset * src_pitch ;
1054+ const float * src_row_start = src + offset * src_stride_float ;
10531055
10541056 int x = 0 ;
10551057
1056- // 128-64-32 pixels prelude
1057- // we spare some coeff reload per unrolled loop
1058- // Perhaps for an i7-11700 which has only 1x512 as 2x256 fma unit, not ideal.
1059-
1060- // Process by 8x 512 (8 x 16 floats) to make memory read/write linear streams longer
1061- // 32x512 bit registers should be enough
1058+ // -----------------------------------------------------------------------
1059+ // 128 pixels (512 bytes) per iteration
1060+ // Uses ~17 ZMM registers. Safe for x64 (32 regs available).
1061+ // Provides 8 independent dependency chains to hide FMA latency.
1062+ // -----------------------------------------------------------------------
10621063 const int width_mod128 = (width / 128 ) * 128 ;
10631064 for (; x < width_mod128; x += 128 ) {
10641065 __m512 result_1 = _mm512_setzero_ps ();
@@ -1070,19 +1071,21 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10701071 __m512 result_7 = _mm512_setzero_ps ();
10711072 __m512 result_8 = _mm512_setzero_ps ();
10721073
1073- const float * AVS_RESTRICT src2_ptr = src_ptr + x;
1074- int i = 0 ;
1075- for (; i < kernel_size; i++) {
1074+ const float * AVS_RESTRICT src2_ptr = src_row_start + x;
1075+
1076+ for (int i = 0 ; i < kernel_size; i++) {
10761077 __m512 coeff = _mm512_set1_ps (current_coeff[i]);
10771078
1078- __m512 src_1 = _mm512_load_ps (src2_ptr);
1079- __m512 src_2 = _mm512_load_ps (src2_ptr + 16 );
1079+ // Loading 512 bytes contiguous memory (8 cache lines)
1080+ __m512 src_1 = _mm512_load_ps (src2_ptr); // 0..15
1081+ __m512 src_2 = _mm512_load_ps (src2_ptr + 16 ); // 16..31 (offset in floats)
10801082 __m512 src_3 = _mm512_load_ps (src2_ptr + 32 );
10811083 __m512 src_4 = _mm512_load_ps (src2_ptr + 48 );
10821084 __m512 src_5 = _mm512_load_ps (src2_ptr + 64 );
10831085 __m512 src_6 = _mm512_load_ps (src2_ptr + 80 );
10841086 __m512 src_7 = _mm512_load_ps (src2_ptr + 96 );
10851087 __m512 src_8 = _mm512_load_ps (src2_ptr + 112 );
1088+
10861089 result_1 = _mm512_fmadd_ps (src_1, coeff, result_1);
10871090 result_2 = _mm512_fmadd_ps (src_2, coeff, result_2);
10881091 result_3 = _mm512_fmadd_ps (src_3, coeff, result_3);
@@ -1092,31 +1095,32 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
10921095 result_7 = _mm512_fmadd_ps (src_7, coeff, result_7);
10931096 result_8 = _mm512_fmadd_ps (src_8, coeff, result_8);
10941097
1095- src2_ptr += src_pitch ;
1098+ src2_ptr += src_stride_float ;
10961099 }
10971100
1098- _mm512_store_ps (dst + x, result_1);
1099- _mm512_store_ps (dst + x + 16 , result_2);
1100- _mm512_store_ps (dst + x + 32 , result_3);
1101- _mm512_store_ps (dst + x + 48 , result_4);
1102- _mm512_store_ps (dst + x + 64 , result_5);
1103- _mm512_store_ps (dst + x + 80 , result_6);
1104- _mm512_store_ps (dst + x + 96 , result_7);
1105- _mm512_store_ps (dst + x + 112 , result_8);
1101+ _mm512_stream_ps (dst + x, result_1);
1102+ _mm512_stream_ps (dst + x + 16 , result_2);
1103+ _mm512_stream_ps (dst + x + 32 , result_3);
1104+ _mm512_stream_ps (dst + x + 48 , result_4);
1105+ _mm512_stream_ps (dst + x + 64 , result_5);
1106+ _mm512_stream_ps (dst + x + 80 , result_6);
1107+ _mm512_stream_ps (dst + x + 96 , result_7);
1108+ _mm512_stream_ps (dst + x + 112 , result_8);
11061109 }
11071110
1108- // Process by 4x512 (4 x 16 floats) to make memory read/write linear streams longer
1111+ // -----------------------------------------------------------------------
1112+ // 64 pixels per iteration
1113+ // -----------------------------------------------------------------------
11091114 const int width_mod64 = (width / 64 ) * 64 ;
11101115 for (; x < width_mod64; x += 64 ) {
11111116 __m512 result_1 = _mm512_setzero_ps ();
11121117 __m512 result_2 = _mm512_setzero_ps ();
11131118 __m512 result_3 = _mm512_setzero_ps ();
11141119 __m512 result_4 = _mm512_setzero_ps ();
11151120
1116- const float * AVS_RESTRICT src2_ptr = src_ptr + x;
1121+ const float * AVS_RESTRICT src2_ptr = src_row_start + x;
11171122
1118- int i = 0 ;
1119- for (; i < kernel_size; i++) {
1123+ for (int i = 0 ; i < kernel_size; i++) {
11201124 __m512 coeff = _mm512_set1_ps (current_coeff[i]);
11211125
11221126 __m512 src_1 = _mm512_load_ps (src2_ptr);
@@ -1129,25 +1133,26 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11291133 result_3 = _mm512_fmadd_ps (src_3, coeff, result_3);
11301134 result_4 = _mm512_fmadd_ps (src_4, coeff, result_4);
11311135
1132- src2_ptr += src_pitch ;
1136+ src2_ptr += src_stride_float ;
11331137 }
11341138
1135- _mm512_store_ps (dst + x, result_1);
1136- _mm512_store_ps (dst + x + 16 , result_2);
1137- _mm512_store_ps (dst + x + 32 , result_3);
1138- _mm512_store_ps (dst + x + 48 , result_4);
1139+ _mm512_stream_ps (dst + x, result_1);
1140+ _mm512_stream_ps (dst + x + 16 , result_2);
1141+ _mm512_stream_ps (dst + x + 32 , result_3);
1142+ _mm512_stream_ps (dst + x + 48 , result_4);
11391143 }
11401144
1141- // Process by 2x512 (2 x 16 floats) to make memory read/write linear streams longer,
1145+ // -----------------------------------------------------------------------
1146+ // 32 pixels per iteration
1147+ // -----------------------------------------------------------------------
11421148 const int width_mod32 = (width / 32 ) * 32 ;
11431149 for (; x < width_mod32; x += 32 ) {
11441150 __m512 result_1 = _mm512_setzero_ps ();
11451151 __m512 result_2 = _mm512_setzero_ps ();
11461152
1147- const float * AVS_RESTRICT src2_ptr = src_ptr + x;
1153+ const float * AVS_RESTRICT src2_ptr = src_row_start + x;
11481154
1149- int i = 0 ;
1150- for (; i < kernel_size; i++) {
1155+ for (int i = 0 ; i < kernel_size; i++) {
11511156 __m512 coeff = _mm512_set1_ps (current_coeff[i]);
11521157
11531158 __m512 src_1 = _mm512_load_ps (src2_ptr);
@@ -1156,36 +1161,39 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11561161 result_1 = _mm512_fmadd_ps (src_1, coeff, result_1);
11571162 result_2 = _mm512_fmadd_ps (src_2, coeff, result_2);
11581163
1159- src2_ptr += src_pitch ;
1164+ src2_ptr += src_stride_float ;
11601165 }
11611166
1162- _mm512_store_ps (dst + x, result_1);
1163- _mm512_store_ps (dst + x + 16 , result_2);
1167+ _mm512_stream_ps (dst + x, result_1);
1168+ _mm512_stream_ps (dst + x + 16 , result_2);
11641169 }
11651170
1166- // Process 1x512 dual
1167- // 64 byte 16 floats (AVX512 register holds 16 floats)
1168- // row alignment is 64 bytes - so it is safe to load mod16 of float32.
1171+ // -----------------------------------------------------------------------
1172+ // Remainder loop (16 pixels)
1173+ // Uses vertical loop unrolling (pairs of taps) to hide FMA latency
1174+ // because we don't have enough horizontal data to do it spatially.
1175+ // -----------------------------------------------------------------------
1176+ const int src_stride_2 = src_stride_float * 2 ;
1177+
11691178 for (; x < width; x += 16 ) {
11701179 __m512 result_single = _mm512_setzero_ps ();
11711180 __m512 result_single_2 = _mm512_setzero_ps ();
11721181
1173- const float * AVS_RESTRICT src2_ptr = src_ptr + x;
1174-
1175- // Process pairs of rows for better efficiency (2 coeffs/cycle)
1176- // two result variables for potential parallel operation
1182+ const float * AVS_RESTRICT src2_ptr = src_row_start + x;
11771183 int i = 0 ;
1184+
1185+ // Process pairs of rows
11781186 for (; i < kernel_size_mod2; i += 2 ) {
11791187 __m512 coeff_even = _mm512_set1_ps (current_coeff[i]);
11801188 __m512 coeff_odd = _mm512_set1_ps (current_coeff[i + 1 ]);
11811189
11821190 __m512 src_even = _mm512_load_ps (src2_ptr);
1183- __m512 src_odd = _mm512_load_ps (src2_ptr + src_pitch );
1191+ __m512 src_odd = _mm512_load_ps (src2_ptr + src_stride_float );
11841192
11851193 result_single = _mm512_fmadd_ps (src_even, coeff_even, result_single);
11861194 result_single_2 = _mm512_fmadd_ps (src_odd, coeff_odd, result_single_2);
11871195
1188- src2_ptr += 2 * src_pitch ;
1196+ src2_ptr += src_stride_2 ;
11891197 }
11901198
11911199 result_single = _mm512_add_ps (result_single, result_single_2);
@@ -1197,11 +1205,10 @@ void resize_v_avx512_planar_float_w_sr(BYTE* dst8, const BYTE* src8, int dst_pit
11971205 result_single = _mm512_fmadd_ps (src_val, coeff, result_single);
11981206 }
11991207
1200- _mm512_store_ps (dst + x, result_single);
1208+ _mm512_stream_ps (dst + x, result_single);
12011209 }
12021210
1203-
1204- dst += dst_pitch;
1211+ dst += dst_stride_float;
12051212 current_coeff += filter_size;
12061213 }
12071214}
0 commit comments