xref: /aosp_15_r20/external/libvpx/vpx_dsp/arm/highbd_variance_neon.c (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1 /*
2  *  Copyright (c) 2022 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <arm_neon.h>
12 
13 #include "./vpx_dsp_rtcd.h"
14 #include "./vpx_config.h"
15 
16 #include "vpx/vpx_integer.h"
17 #include "vpx_dsp/arm/mem_neon.h"
18 #include "vpx_dsp/arm/sum_neon.h"
19 #include "vpx_ports/mem.h"
20 
21 // Process a block of width 4 two rows at a time.
highbd_variance_4xh_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int h,uint64_t * sse,int64_t * sum)22 static INLINE void highbd_variance_4xh_neon(const uint16_t *src_ptr,
23                                             int src_stride,
24                                             const uint16_t *ref_ptr,
25                                             int ref_stride, int h,
26                                             uint64_t *sse, int64_t *sum) {
27   int16x8_t sum_s16 = vdupq_n_s16(0);
28   int32x4_t sse_s32 = vdupq_n_s32(0);
29 
30   int i = h;
31   do {
32     const uint16x8_t s = load_unaligned_u16q(src_ptr, src_stride);
33     const uint16x8_t r = load_unaligned_u16q(ref_ptr, ref_stride);
34 
35     int16x8_t diff = vreinterpretq_s16_u16(vsubq_u16(s, r));
36     sum_s16 = vaddq_s16(sum_s16, diff);
37 
38     sse_s32 = vmlal_s16(sse_s32, vget_low_s16(diff), vget_low_s16(diff));
39     sse_s32 = vmlal_s16(sse_s32, vget_high_s16(diff), vget_high_s16(diff));
40 
41     src_ptr += 2 * src_stride;
42     ref_ptr += 2 * ref_stride;
43     i -= 2;
44   } while (i != 0);
45 
46   *sum = horizontal_add_int16x8(sum_s16);
47   *sse = horizontal_add_int32x4(sse_s32);
48 }
49 
50 // For 8-bit and 10-bit data, since we're using two int32x4 accumulators, all
51 // block sizes can be processed in 32-bit elements (1023*1023*64*16 = 1071645696
52 // for a 64x64 block).
highbd_variance_large_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int w,int h,uint64_t * sse,int64_t * sum)53 static INLINE void highbd_variance_large_neon(const uint16_t *src_ptr,
54                                               int src_stride,
55                                               const uint16_t *ref_ptr,
56                                               int ref_stride, int w, int h,
57                                               uint64_t *sse, int64_t *sum) {
58   int32x4_t sum_s32 = vdupq_n_s32(0);
59   int32x4_t sse_s32[2] = { vdupq_n_s32(0), vdupq_n_s32(0) };
60 
61   int i = h;
62   do {
63     int j = 0;
64     do {
65       const uint16x8_t s = vld1q_u16(src_ptr + j);
66       const uint16x8_t r = vld1q_u16(ref_ptr + j);
67 
68       const int16x8_t diff = vreinterpretq_s16_u16(vsubq_u16(s, r));
69       sum_s32 = vpadalq_s16(sum_s32, diff);
70 
71       sse_s32[0] =
72           vmlal_s16(sse_s32[0], vget_low_s16(diff), vget_low_s16(diff));
73       sse_s32[1] =
74           vmlal_s16(sse_s32[1], vget_high_s16(diff), vget_high_s16(diff));
75 
76       j += 8;
77     } while (j < w);
78 
79     src_ptr += src_stride;
80     ref_ptr += ref_stride;
81   } while (--i != 0);
82 
83   *sum = horizontal_add_int32x4(sum_s32);
84   *sse = horizontal_long_add_uint32x4(vaddq_u32(
85       vreinterpretq_u32_s32(sse_s32[0]), vreinterpretq_u32_s32(sse_s32[1])));
86 }
87 
highbd_variance_8xh_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)88 static INLINE void highbd_variance_8xh_neon(const uint16_t *src, int src_stride,
89                                             const uint16_t *ref, int ref_stride,
90                                             int h, uint64_t *sse,
91                                             int64_t *sum) {
92   highbd_variance_large_neon(src, src_stride, ref, ref_stride, 8, h, sse, sum);
93 }
94 
highbd_variance_16xh_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)95 static INLINE void highbd_variance_16xh_neon(const uint16_t *src,
96                                              int src_stride,
97                                              const uint16_t *ref,
98                                              int ref_stride, int h,
99                                              uint64_t *sse, int64_t *sum) {
100   highbd_variance_large_neon(src, src_stride, ref, ref_stride, 16, h, sse, sum);
101 }
102 
highbd_variance_32xh_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)103 static INLINE void highbd_variance_32xh_neon(const uint16_t *src,
104                                              int src_stride,
105                                              const uint16_t *ref,
106                                              int ref_stride, int h,
107                                              uint64_t *sse, int64_t *sum) {
108   highbd_variance_large_neon(src, src_stride, ref, ref_stride, 32, h, sse, sum);
109 }
110 
highbd_variance_64xh_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)111 static INLINE void highbd_variance_64xh_neon(const uint16_t *src,
112                                              int src_stride,
113                                              const uint16_t *ref,
114                                              int ref_stride, int h,
115                                              uint64_t *sse, int64_t *sum) {
116   highbd_variance_large_neon(src, src_stride, ref, ref_stride, 64, h, sse, sum);
117 }
118 
119 // For 12-bit data, we can only accumulate up to 128 elements in the sum of
120 // squares (4095*4095*128 = 2146435200), and because we're using two int32x4
121 // accumulators, we can only process up to 32 32-element rows (32*32/8 = 128)
122 // or 16 64-element rows before we have to accumulate into 64-bit elements.
123 // Therefore blocks of size 32x64, 64x32 and 64x64 are processed in a different
124 // helper function.
125 
126 // Process a block of any size where the width is divisible by 8, with
127 // accumulation into 64-bit elements.
highbd_variance_xlarge_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int w,int h,int h_limit,uint64_t * sse,int64_t * sum)128 static INLINE void highbd_variance_xlarge_neon(
129     const uint16_t *src_ptr, int src_stride, const uint16_t *ref_ptr,
130     int ref_stride, int w, int h, int h_limit, uint64_t *sse, int64_t *sum) {
131   int32x4_t sum_s32 = vdupq_n_s32(0);
132   int64x2_t sse_s64 = vdupq_n_s64(0);
133 
134   // 'h_limit' is the number of 'w'-width rows we can process before our 32-bit
135   // accumulator overflows. After hitting this limit we accumulate into 64-bit
136   // elements.
137   int h_tmp = h > h_limit ? h_limit : h;
138 
139   int i = 0;
140   do {
141     int32x4_t sse_s32[2] = { vdupq_n_s32(0), vdupq_n_s32(0) };
142     do {
143       int j = 0;
144       do {
145         const uint16x8_t s0 = vld1q_u16(src_ptr + j);
146         const uint16x8_t r0 = vld1q_u16(ref_ptr + j);
147 
148         const int16x8_t diff = vreinterpretq_s16_u16(vsubq_u16(s0, r0));
149         sum_s32 = vpadalq_s16(sum_s32, diff);
150 
151         sse_s32[0] =
152             vmlal_s16(sse_s32[0], vget_low_s16(diff), vget_low_s16(diff));
153         sse_s32[1] =
154             vmlal_s16(sse_s32[1], vget_high_s16(diff), vget_high_s16(diff));
155 
156         j += 8;
157       } while (j < w);
158 
159       src_ptr += src_stride;
160       ref_ptr += ref_stride;
161       i++;
162     } while (i < h_tmp);
163 
164     sse_s64 = vpadalq_s32(sse_s64, sse_s32[0]);
165     sse_s64 = vpadalq_s32(sse_s64, sse_s32[1]);
166     h_tmp += h_limit;
167   } while (i < h);
168 
169   *sum = horizontal_add_int32x4(sum_s32);
170   *sse = (uint64_t)horizontal_add_int64x2(sse_s64);
171 }
172 
highbd_variance_32xh_xlarge_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)173 static INLINE void highbd_variance_32xh_xlarge_neon(
174     const uint16_t *src, int src_stride, const uint16_t *ref, int ref_stride,
175     int h, uint64_t *sse, int64_t *sum) {
176   highbd_variance_xlarge_neon(src, src_stride, ref, ref_stride, 32, h, 32, sse,
177                               sum);
178 }
179 
highbd_variance_64xh_xlarge_neon(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int h,uint64_t * sse,int64_t * sum)180 static INLINE void highbd_variance_64xh_xlarge_neon(
181     const uint16_t *src, int src_stride, const uint16_t *ref, int ref_stride,
182     int h, uint64_t *sse, int64_t *sum) {
183   highbd_variance_xlarge_neon(src, src_stride, ref, ref_stride, 64, h, 16, sse,
184                               sum);
185 }
186 
187 #define HBD_VARIANCE_WXH_8_NEON(w, h)                                 \
188   uint32_t vpx_highbd_8_variance##w##x##h##_neon(                     \
189       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
190       int ref_stride, uint32_t *sse) {                                \
191     int sum;                                                          \
192     uint64_t sse_long = 0;                                            \
193     int64_t sum_long = 0;                                             \
194     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
195     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
196     highbd_variance_##w##xh_neon(src, src_stride, ref, ref_stride, h, \
197                                  &sse_long, &sum_long);               \
198     *sse = (uint32_t)sse_long;                                        \
199     sum = (int)sum_long;                                              \
200     return *sse - (uint32_t)(((int64_t)sum * sum) / (w * h));         \
201   }
202 
203 #define HBD_VARIANCE_WXH_10_NEON(w, h)                                \
204   uint32_t vpx_highbd_10_variance##w##x##h##_neon(                    \
205       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
206       int ref_stride, uint32_t *sse) {                                \
207     int sum;                                                          \
208     int64_t var;                                                      \
209     uint64_t sse_long = 0;                                            \
210     int64_t sum_long = 0;                                             \
211     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
212     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
213     highbd_variance_##w##xh_neon(src, src_stride, ref, ref_stride, h, \
214                                  &sse_long, &sum_long);               \
215     *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 4);                 \
216     sum = (int)ROUND_POWER_OF_TWO(sum_long, 2);                       \
217     var = (int64_t)(*sse) - (((int64_t)sum * sum) / (w * h));         \
218     return (var >= 0) ? (uint32_t)var : 0;                            \
219   }
220 
221 #define HBD_VARIANCE_WXH_12_NEON(w, h)                                \
222   uint32_t vpx_highbd_12_variance##w##x##h##_neon(                    \
223       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
224       int ref_stride, uint32_t *sse) {                                \
225     int sum;                                                          \
226     int64_t var;                                                      \
227     uint64_t sse_long = 0;                                            \
228     int64_t sum_long = 0;                                             \
229     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
230     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
231     highbd_variance_##w##xh_neon(src, src_stride, ref, ref_stride, h, \
232                                  &sse_long, &sum_long);               \
233     *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 8);                 \
234     sum = (int)ROUND_POWER_OF_TWO(sum_long, 4);                       \
235     var = (int64_t)(*sse) - (((int64_t)sum * sum) / (w * h));         \
236     return (var >= 0) ? (uint32_t)var : 0;                            \
237   }
238 
239 #define HBD_VARIANCE_WXH_12_XLARGE_NEON(w, h)                                \
240   uint32_t vpx_highbd_12_variance##w##x##h##_neon(                           \
241       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,        \
242       int ref_stride, uint32_t *sse) {                                       \
243     int sum;                                                                 \
244     int64_t var;                                                             \
245     uint64_t sse_long = 0;                                                   \
246     int64_t sum_long = 0;                                                    \
247     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                            \
248     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                            \
249     highbd_variance_##w##xh_xlarge_neon(src, src_stride, ref, ref_stride, h, \
250                                         &sse_long, &sum_long);               \
251     *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 8);                        \
252     sum = (int)ROUND_POWER_OF_TWO(sum_long, 4);                              \
253     var = (int64_t)(*sse) - (((int64_t)sum * sum) / (w * h));                \
254     return (var >= 0) ? (uint32_t)var : 0;                                   \
255   }
256 
257 // 8-bit
258 HBD_VARIANCE_WXH_8_NEON(4, 4)
259 HBD_VARIANCE_WXH_8_NEON(4, 8)
260 
261 HBD_VARIANCE_WXH_8_NEON(8, 4)
262 HBD_VARIANCE_WXH_8_NEON(8, 8)
263 HBD_VARIANCE_WXH_8_NEON(8, 16)
264 
265 HBD_VARIANCE_WXH_8_NEON(16, 8)
266 HBD_VARIANCE_WXH_8_NEON(16, 16)
267 HBD_VARIANCE_WXH_8_NEON(16, 32)
268 
269 HBD_VARIANCE_WXH_8_NEON(32, 16)
270 HBD_VARIANCE_WXH_8_NEON(32, 32)
271 HBD_VARIANCE_WXH_8_NEON(32, 64)
272 
273 HBD_VARIANCE_WXH_8_NEON(64, 32)
274 HBD_VARIANCE_WXH_8_NEON(64, 64)
275 
276 // 10-bit
277 HBD_VARIANCE_WXH_10_NEON(4, 4)
278 HBD_VARIANCE_WXH_10_NEON(4, 8)
279 
280 HBD_VARIANCE_WXH_10_NEON(8, 4)
281 HBD_VARIANCE_WXH_10_NEON(8, 8)
282 HBD_VARIANCE_WXH_10_NEON(8, 16)
283 
284 HBD_VARIANCE_WXH_10_NEON(16, 8)
285 HBD_VARIANCE_WXH_10_NEON(16, 16)
286 HBD_VARIANCE_WXH_10_NEON(16, 32)
287 
288 HBD_VARIANCE_WXH_10_NEON(32, 16)
289 HBD_VARIANCE_WXH_10_NEON(32, 32)
290 HBD_VARIANCE_WXH_10_NEON(32, 64)
291 
292 HBD_VARIANCE_WXH_10_NEON(64, 32)
293 HBD_VARIANCE_WXH_10_NEON(64, 64)
294 
295 // 12-bit
296 HBD_VARIANCE_WXH_12_NEON(4, 4)
297 HBD_VARIANCE_WXH_12_NEON(4, 8)
298 
299 HBD_VARIANCE_WXH_12_NEON(8, 4)
300 HBD_VARIANCE_WXH_12_NEON(8, 8)
301 HBD_VARIANCE_WXH_12_NEON(8, 16)
302 
303 HBD_VARIANCE_WXH_12_NEON(16, 8)
304 HBD_VARIANCE_WXH_12_NEON(16, 16)
305 HBD_VARIANCE_WXH_12_NEON(16, 32)
306 
307 HBD_VARIANCE_WXH_12_NEON(32, 16)
308 HBD_VARIANCE_WXH_12_NEON(32, 32)
309 HBD_VARIANCE_WXH_12_XLARGE_NEON(32, 64)
310 
311 HBD_VARIANCE_WXH_12_XLARGE_NEON(64, 32)
312 HBD_VARIANCE_WXH_12_XLARGE_NEON(64, 64)
313 
314 #define HIGHBD_GET_VAR(S)                                             \
315   void vpx_highbd_8_get##S##x##S##var_neon(                           \
316       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
317       int ref_stride, uint32_t *sse, int *sum) {                      \
318     uint64_t sse_long = 0;                                            \
319     int64_t sum_long = 0;                                             \
320     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
321     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
322     highbd_variance_##S##xh_neon(src, src_stride, ref, ref_stride, S, \
323                                  &sse_long, &sum_long);               \
324     *sse = (uint32_t)sse_long;                                        \
325     *sum = (int)sum_long;                                             \
326   }                                                                   \
327                                                                       \
328   void vpx_highbd_10_get##S##x##S##var_neon(                          \
329       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
330       int ref_stride, uint32_t *sse, int *sum) {                      \
331     uint64_t sse_long = 0;                                            \
332     int64_t sum_long = 0;                                             \
333     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
334     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
335     highbd_variance_##S##xh_neon(src, src_stride, ref, ref_stride, S, \
336                                  &sse_long, &sum_long);               \
337     *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 4);                 \
338     *sum = (int)ROUND_POWER_OF_TWO(sum_long, 2);                      \
339   }                                                                   \
340                                                                       \
341   void vpx_highbd_12_get##S##x##S##var_neon(                          \
342       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, \
343       int ref_stride, uint32_t *sse, int *sum) {                      \
344     uint64_t sse_long = 0;                                            \
345     int64_t sum_long = 0;                                             \
346     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                     \
347     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                     \
348     highbd_variance_##S##xh_neon(src, src_stride, ref, ref_stride, S, \
349                                  &sse_long, &sum_long);               \
350     *sse = (uint32_t)ROUND_POWER_OF_TWO(sse_long, 8);                 \
351     *sum = (int)ROUND_POWER_OF_TWO(sum_long, 4);                      \
352   }
353 
354 HIGHBD_GET_VAR(8)
355 HIGHBD_GET_VAR(16)
356 
highbd_mse_wxh_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int w,int h)357 static INLINE uint32_t highbd_mse_wxh_neon(const uint16_t *src_ptr,
358                                            int src_stride,
359                                            const uint16_t *ref_ptr,
360                                            int ref_stride, int w, int h) {
361   uint32x4_t sse_u32[2] = { vdupq_n_u32(0), vdupq_n_u32(0) };
362 
363   int i = h;
364   do {
365     int j = 0;
366     do {
367       uint16x8_t s = vld1q_u16(src_ptr + j);
368       uint16x8_t r = vld1q_u16(ref_ptr + j);
369 
370       uint16x8_t diff = vabdq_u16(s, r);
371 
372       sse_u32[0] =
373           vmlal_u16(sse_u32[0], vget_low_u16(diff), vget_low_u16(diff));
374       sse_u32[1] =
375           vmlal_u16(sse_u32[1], vget_high_u16(diff), vget_high_u16(diff));
376 
377       j += 8;
378     } while (j < w);
379 
380     src_ptr += src_stride;
381     ref_ptr += ref_stride;
382   } while (--i != 0);
383 
384   return horizontal_add_uint32x4(vaddq_u32(sse_u32[0], sse_u32[1]));
385 }
386 
highbd_mse8_8xh_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int h)387 static INLINE uint32_t highbd_mse8_8xh_neon(const uint16_t *src_ptr,
388                                             int src_stride,
389                                             const uint16_t *ref_ptr,
390                                             int ref_stride, int h) {
391   return highbd_mse_wxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 8, h);
392 }
393 
highbd_mse8_16xh_neon(const uint16_t * src_ptr,int src_stride,const uint16_t * ref_ptr,int ref_stride,int h)394 static INLINE uint32_t highbd_mse8_16xh_neon(const uint16_t *src_ptr,
395                                              int src_stride,
396                                              const uint16_t *ref_ptr,
397                                              int ref_stride, int h) {
398   return highbd_mse_wxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 16, h);
399 }
400 
401 #define HIGHBD_MSE_WXH_NEON(w, h)                                         \
402   uint32_t vpx_highbd_8_mse##w##x##h##_neon(                              \
403       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,     \
404       int ref_stride, uint32_t *sse) {                                    \
405     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                         \
406     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                         \
407     *sse = highbd_mse8_##w##xh_neon(src, src_stride, ref, ref_stride, h); \
408     return *sse;                                                          \
409   }                                                                       \
410                                                                           \
411   uint32_t vpx_highbd_10_mse##w##x##h##_neon(                             \
412       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,     \
413       int ref_stride, uint32_t *sse) {                                    \
414     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                         \
415     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                         \
416     *sse = highbd_mse_wxh_neon(src, src_stride, ref, ref_stride, w, h);   \
417     *sse = ROUND_POWER_OF_TWO(*sse, 4);                                   \
418     return *sse;                                                          \
419   }                                                                       \
420                                                                           \
421   uint32_t vpx_highbd_12_mse##w##x##h##_neon(                             \
422       const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr,     \
423       int ref_stride, uint32_t *sse) {                                    \
424     uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);                         \
425     uint16_t *ref = CONVERT_TO_SHORTPTR(ref_ptr);                         \
426     *sse = highbd_mse_wxh_neon(src, src_stride, ref, ref_stride, w, h);   \
427     *sse = ROUND_POWER_OF_TWO(*sse, 8);                                   \
428     return *sse;                                                          \
429   }
430 
431 HIGHBD_MSE_WXH_NEON(16, 16)
432 HIGHBD_MSE_WXH_NEON(16, 8)
433 HIGHBD_MSE_WXH_NEON(8, 16)
434 HIGHBD_MSE_WXH_NEON(8, 8)
435 
436 #undef HIGHBD_MSE_WXH_NEON
437