Home | History | Annotate | Download | only in simd
      1 /*
      2  * jsimd_arm64.c
      3  *
      4  * Copyright 2009 Pierre Ossman <ossman (at) cendio.se> for Cendio AB
      5  * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander.
      6  * Copyright (C) 2015-2016, Matthieu Darbois.
      7  *
      8  * Based on the x86 SIMD extension for IJG JPEG library,
      9  * Copyright (C) 1999-2006, MIYASAKA Masaru.
     10  * For conditions of distribution and use, see copyright notice in jsimdext.inc
     11  *
     12  * This file contains the interface between the "normal" portions
     13  * of the library and the SIMD implementations when running on a
     14  * 64-bit ARM architecture.
     15  */
     16 
     17 #define JPEG_INTERNALS
     18 #include "../jinclude.h"
     19 #include "../jpeglib.h"
     20 #include "../jsimd.h"
     21 #include "../jdct.h"
     22 #include "../jsimddct.h"
     23 #include "jsimd.h"
     24 
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <ctype.h>
     28 
     29 #define JSIMD_FASTLD3 1
     30 #define JSIMD_FASTST3 2
     31 #define JSIMD_FASTTBL 4
     32 
     33 static unsigned int simd_support = ~0;
     34 static unsigned int simd_huffman = 1;
     35 static unsigned int simd_features = JSIMD_FASTLD3 | JSIMD_FASTST3 |
     36                                     JSIMD_FASTTBL;
     37 
     38 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
     39 
     40 #define SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT (1024 * 1024)
     41 
     42 LOCAL(int)
     43 check_cpuinfo (char *buffer, const char *field, char *value)
     44 {
     45   char *p;
     46   if (*value == 0)
     47     return 0;
     48   if (strncmp(buffer, field, strlen(field)) != 0)
     49     return 0;
     50   buffer += strlen(field);
     51   while (isspace(*buffer))
     52     buffer++;
     53 
     54   /* Check if 'value' is present in the buffer as a separate word */
     55   while ((p = strstr(buffer, value))) {
     56     if (p > buffer && !isspace(*(p - 1))) {
     57       buffer++;
     58       continue;
     59     }
     60     p += strlen(value);
     61     if (*p != 0 && !isspace(*p)) {
     62       buffer++;
     63       continue;
     64     }
     65     return 1;
     66   }
     67   return 0;
     68 }
     69 
     70 LOCAL(int)
     71 parse_proc_cpuinfo (int bufsize)
     72 {
     73   char *buffer = (char *)malloc(bufsize);
     74   FILE *fd;
     75 
     76   if (!buffer)
     77     return 0;
     78 
     79   fd = fopen("/proc/cpuinfo", "r");
     80   if (fd) {
     81     while (fgets(buffer, bufsize, fd)) {
     82       if (!strchr(buffer, '\n') && !feof(fd)) {
     83         /* "impossible" happened - insufficient size of the buffer! */
     84         fclose(fd);
     85         free(buffer);
     86         return 0;
     87       }
     88       if (check_cpuinfo(buffer, "CPU part", "0xd03") ||
     89           check_cpuinfo(buffer, "CPU part", "0xd07"))
     90         /* The Cortex-A53 has a slow tbl implementation.  We can gain a few
     91            percent speedup by disabling the use of that instruction.  The
     92            speedup on Cortex-A57 is more subtle but still measurable. */
     93         simd_features &= ~JSIMD_FASTTBL;
     94       else if (check_cpuinfo(buffer, "CPU part", "0x0a1"))
     95         /* The SIMD version of Huffman encoding is slower than the C version on
     96            Cavium ThunderX.  Also, ld3 and st3 are abyssmally slow on that
     97            CPU. */
     98         simd_huffman = simd_features = 0;
     99     }
    100     fclose(fd);
    101   }
    102   free(buffer);
    103   return 1;
    104 }
    105 
    106 #endif
    107 
    108 /*
    109  * Check what SIMD accelerations are supported.
    110  *
    111  * FIXME: This code is racy under a multi-threaded environment.
    112  */
    113 
    114 /*
    115  * ARMv8 architectures support NEON extensions by default.
    116  * It is no longer optional as it was with ARMv7.
    117  */
    118 
    119 
    120 LOCAL(void)
    121 init_simd (void)
    122 {
    123   char *env = NULL;
    124 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
    125   int bufsize = 1024; /* an initial guess for the line buffer size limit */
    126 #endif
    127 
    128   if (simd_support != ~0U)
    129     return;
    130 
    131   simd_support = 0;
    132 
    133   simd_support |= JSIMD_ARM_NEON;
    134 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
    135   while (!parse_proc_cpuinfo(bufsize)) {
    136     bufsize *= 2;
    137     if (bufsize > SOMEWHAT_SANE_PROC_CPUINFO_SIZE_LIMIT)
    138       break;
    139   }
    140 #endif
    141 
    142   /* Force different settings through environment variables */
    143   env = getenv("JSIMD_FORCENEON");
    144   if ((env != NULL) && (strcmp(env, "1") == 0))
    145     simd_support = JSIMD_ARM_NEON;
    146   env = getenv("JSIMD_FORCENONE");
    147   if ((env != NULL) && (strcmp(env, "1") == 0))
    148     simd_support = 0;
    149   env = getenv("JSIMD_NOHUFFENC");
    150   if ((env != NULL) && (strcmp(env, "1") == 0))
    151     simd_huffman = 0;
    152   env = getenv("JSIMD_FASTLD3");
    153   if ((env != NULL) && (strcmp(env, "1") == 0))
    154     simd_features |= JSIMD_FASTLD3;
    155   if ((env != NULL) && (strcmp(env, "0") == 0))
    156     simd_features &= ~JSIMD_FASTLD3;
    157   env = getenv("JSIMD_FASTST3");
    158   if ((env != NULL) && (strcmp(env, "1") == 0))
    159     simd_features |= JSIMD_FASTST3;
    160   if ((env != NULL) && (strcmp(env, "0") == 0))
    161     simd_features &= ~JSIMD_FASTST3;
    162 }
    163 
    164 GLOBAL(int)
    165 jsimd_can_rgb_ycc (void)
    166 {
    167   init_simd();
    168 
    169   /* The code is optimised for these values only */
    170   if (BITS_IN_JSAMPLE != 8)
    171     return 0;
    172   if (sizeof(JDIMENSION) != 4)
    173     return 0;
    174   if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
    175     return 0;
    176 
    177   if (simd_support & JSIMD_ARM_NEON)
    178     return 1;
    179 
    180   return 0;
    181 }
    182 
    183 GLOBAL(int)
    184 jsimd_can_rgb_gray (void)
    185 {
    186   init_simd();
    187 
    188   return 0;
    189 }
    190 
    191 GLOBAL(int)
    192 jsimd_can_ycc_rgb (void)
    193 {
    194   init_simd();
    195 
    196   /* The code is optimised for these values only */
    197   if (BITS_IN_JSAMPLE != 8)
    198     return 0;
    199   if (sizeof(JDIMENSION) != 4)
    200     return 0;
    201   if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
    202     return 0;
    203 
    204   if (simd_support & JSIMD_ARM_NEON)
    205     return 1;
    206 
    207   return 0;
    208 }
    209 
    210 GLOBAL(int)
    211 jsimd_can_ycc_rgb565 (void)
    212 {
    213   init_simd();
    214 
    215   /* The code is optimised for these values only */
    216   if (BITS_IN_JSAMPLE != 8)
    217     return 0;
    218   if (sizeof(JDIMENSION) != 4)
    219     return 0;
    220 
    221   if (simd_support & JSIMD_ARM_NEON)
    222     return 1;
    223 
    224   return 0;
    225 }
    226 
    227 GLOBAL(void)
    228 jsimd_rgb_ycc_convert (j_compress_ptr cinfo,
    229                        JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
    230                        JDIMENSION output_row, int num_rows)
    231 {
    232   void (*neonfct)(JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
    233 
    234   switch(cinfo->in_color_space) {
    235     case JCS_EXT_RGB:
    236       if (simd_features & JSIMD_FASTLD3)
    237         neonfct=jsimd_extrgb_ycc_convert_neon;
    238       else
    239         neonfct=jsimd_extrgb_ycc_convert_neon_slowld3;
    240       break;
    241     case JCS_EXT_RGBX:
    242     case JCS_EXT_RGBA:
    243       neonfct=jsimd_extrgbx_ycc_convert_neon;
    244       break;
    245     case JCS_EXT_BGR:
    246       if (simd_features & JSIMD_FASTLD3)
    247         neonfct=jsimd_extbgr_ycc_convert_neon;
    248       else
    249         neonfct=jsimd_extbgr_ycc_convert_neon_slowld3;
    250       break;
    251     case JCS_EXT_BGRX:
    252     case JCS_EXT_BGRA:
    253       neonfct=jsimd_extbgrx_ycc_convert_neon;
    254       break;
    255     case JCS_EXT_XBGR:
    256     case JCS_EXT_ABGR:
    257       neonfct=jsimd_extxbgr_ycc_convert_neon;
    258       break;
    259     case JCS_EXT_XRGB:
    260     case JCS_EXT_ARGB:
    261       neonfct=jsimd_extxrgb_ycc_convert_neon;
    262       break;
    263     default:
    264       if (simd_features & JSIMD_FASTLD3)
    265         neonfct=jsimd_extrgb_ycc_convert_neon;
    266       else
    267         neonfct=jsimd_extrgb_ycc_convert_neon_slowld3;
    268       break;
    269   }
    270 
    271   neonfct(cinfo->image_width, input_buf, output_buf, output_row, num_rows);
    272 }
    273 
    274 GLOBAL(void)
    275 jsimd_rgb_gray_convert (j_compress_ptr cinfo,
    276                         JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
    277                         JDIMENSION output_row, int num_rows)
    278 {
    279 }
    280 
    281 GLOBAL(void)
    282 jsimd_ycc_rgb_convert (j_decompress_ptr cinfo,
    283                        JSAMPIMAGE input_buf, JDIMENSION input_row,
    284                        JSAMPARRAY output_buf, int num_rows)
    285 {
    286   void (*neonfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
    287 
    288   switch(cinfo->out_color_space) {
    289     case JCS_EXT_RGB:
    290       if (simd_features & JSIMD_FASTST3)
    291         neonfct=jsimd_ycc_extrgb_convert_neon;
    292       else
    293         neonfct=jsimd_ycc_extrgb_convert_neon_slowst3;
    294       break;
    295     case JCS_EXT_RGBX:
    296     case JCS_EXT_RGBA:
    297       neonfct=jsimd_ycc_extrgbx_convert_neon;
    298       break;
    299     case JCS_EXT_BGR:
    300       if (simd_features & JSIMD_FASTST3)
    301         neonfct=jsimd_ycc_extbgr_convert_neon;
    302       else
    303         neonfct=jsimd_ycc_extbgr_convert_neon_slowst3;
    304       break;
    305     case JCS_EXT_BGRX:
    306     case JCS_EXT_BGRA:
    307       neonfct=jsimd_ycc_extbgrx_convert_neon;
    308       break;
    309     case JCS_EXT_XBGR:
    310     case JCS_EXT_ABGR:
    311       neonfct=jsimd_ycc_extxbgr_convert_neon;
    312       break;
    313     case JCS_EXT_XRGB:
    314     case JCS_EXT_ARGB:
    315       neonfct=jsimd_ycc_extxrgb_convert_neon;
    316       break;
    317     default:
    318       if (simd_features & JSIMD_FASTST3)
    319         neonfct=jsimd_ycc_extrgb_convert_neon;
    320       else
    321         neonfct=jsimd_ycc_extrgb_convert_neon_slowst3;
    322       break;
    323   }
    324 
    325   neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows);
    326 }
    327 
    328 GLOBAL(void)
    329 jsimd_ycc_rgb565_convert (j_decompress_ptr cinfo,
    330                           JSAMPIMAGE input_buf, JDIMENSION input_row,
    331                           JSAMPARRAY output_buf, int num_rows)
    332 {
    333   jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row,
    334                                 output_buf, num_rows);
    335 }
    336 
    337 GLOBAL(int)
    338 jsimd_can_h2v2_downsample (void)
    339 {
    340   init_simd();
    341 
    342   /* The code is optimised for these values only */
    343   if (BITS_IN_JSAMPLE != 8)
    344     return 0;
    345   if (DCTSIZE != 8)
    346     return 0;
    347   if (sizeof(JDIMENSION) != 4)
    348     return 0;
    349 
    350   if (simd_support & JSIMD_ARM_NEON)
    351     return 1;
    352 
    353   return 0;
    354 }
    355 
    356 GLOBAL(int)
    357 jsimd_can_h2v1_downsample (void)
    358 {
    359   init_simd();
    360 
    361   /* The code is optimised for these values only */
    362   if (BITS_IN_JSAMPLE != 8)
    363     return 0;
    364   if (DCTSIZE != 8)
    365     return 0;
    366   if (sizeof(JDIMENSION) != 4)
    367     return 0;
    368 
    369   if (simd_support & JSIMD_ARM_NEON)
    370     return 1;
    371 
    372   return 0;
    373 }
    374 
    375 GLOBAL(void)
    376 jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
    377                        JSAMPARRAY input_data, JSAMPARRAY output_data)
    378 {
    379   jsimd_h2v2_downsample_neon(cinfo->image_width, cinfo->max_v_samp_factor,
    380                              compptr->v_samp_factor, compptr->width_in_blocks,
    381                              input_data, output_data);
    382 }
    383 
    384 GLOBAL(void)
    385 jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
    386                        JSAMPARRAY input_data, JSAMPARRAY output_data)
    387 {
    388   jsimd_h2v1_downsample_neon(cinfo->image_width, cinfo->max_v_samp_factor,
    389                              compptr->v_samp_factor, compptr->width_in_blocks,
    390                              input_data, output_data);
    391 }
    392 
    393 GLOBAL(int)
    394 jsimd_can_h2v2_upsample (void)
    395 {
    396   init_simd();
    397 
    398   return 0;
    399 }
    400 
    401 GLOBAL(int)
    402 jsimd_can_h2v1_upsample (void)
    403 {
    404   init_simd();
    405 
    406   return 0;
    407 }
    408 
    409 GLOBAL(void)
    410 jsimd_h2v2_upsample (j_decompress_ptr cinfo,
    411                      jpeg_component_info *compptr,
    412                      JSAMPARRAY input_data,
    413                      JSAMPARRAY *output_data_ptr)
    414 {
    415 }
    416 
    417 GLOBAL(void)
    418 jsimd_h2v1_upsample (j_decompress_ptr cinfo,
    419                      jpeg_component_info *compptr,
    420                      JSAMPARRAY input_data,
    421                      JSAMPARRAY *output_data_ptr)
    422 {
    423 }
    424 
    425 GLOBAL(int)
    426 jsimd_can_h2v2_fancy_upsample (void)
    427 {
    428   init_simd();
    429 
    430   return 0;
    431 }
    432 
    433 GLOBAL(int)
    434 jsimd_can_h2v1_fancy_upsample (void)
    435 {
    436   init_simd();
    437 
    438   return 0;
    439 }
    440 
    441 GLOBAL(void)
    442 jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo,
    443                            jpeg_component_info *compptr,
    444                            JSAMPARRAY input_data,
    445                            JSAMPARRAY *output_data_ptr)
    446 {
    447 }
    448 
    449 GLOBAL(void)
    450 jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo,
    451                            jpeg_component_info *compptr,
    452                            JSAMPARRAY input_data,
    453                            JSAMPARRAY *output_data_ptr)
    454 {
    455 }
    456 
    457 GLOBAL(int)
    458 jsimd_can_h2v2_merged_upsample (void)
    459 {
    460   init_simd();
    461 
    462   return 0;
    463 }
    464 
    465 GLOBAL(int)
    466 jsimd_can_h2v1_merged_upsample (void)
    467 {
    468   init_simd();
    469 
    470   return 0;
    471 }
    472 
    473 GLOBAL(void)
    474 jsimd_h2v2_merged_upsample (j_decompress_ptr cinfo,
    475                             JSAMPIMAGE input_buf,
    476                             JDIMENSION in_row_group_ctr,
    477                             JSAMPARRAY output_buf)
    478 {
    479 }
    480 
    481 GLOBAL(void)
    482 jsimd_h2v1_merged_upsample (j_decompress_ptr cinfo,
    483                             JSAMPIMAGE input_buf,
    484                             JDIMENSION in_row_group_ctr,
    485                             JSAMPARRAY output_buf)
    486 {
    487 }
    488 
    489 GLOBAL(int)
    490 jsimd_can_convsamp (void)
    491 {
    492   init_simd();
    493 
    494   /* The code is optimised for these values only */
    495   if (DCTSIZE != 8)
    496     return 0;
    497   if (BITS_IN_JSAMPLE != 8)
    498     return 0;
    499   if (sizeof(JDIMENSION) != 4)
    500     return 0;
    501   if (sizeof(DCTELEM) != 2)
    502     return 0;
    503 
    504   if (simd_support & JSIMD_ARM_NEON)
    505     return 1;
    506 
    507   return 0;
    508 }
    509 
    510 GLOBAL(int)
    511 jsimd_can_convsamp_float (void)
    512 {
    513   init_simd();
    514 
    515   return 0;
    516 }
    517 
    518 GLOBAL(void)
    519 jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col,
    520                 DCTELEM *workspace)
    521 {
    522   jsimd_convsamp_neon(sample_data, start_col, workspace);
    523 }
    524 
    525 GLOBAL(void)
    526 jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col,
    527                       FAST_FLOAT *workspace)
    528 {
    529 }
    530 
    531 GLOBAL(int)
    532 jsimd_can_fdct_islow (void)
    533 {
    534   init_simd();
    535 
    536   /* The code is optimised for these values only */
    537   if (DCTSIZE != 8)
    538     return 0;
    539   if (sizeof(DCTELEM) != 2)
    540     return 0;
    541 
    542   if (simd_support & JSIMD_ARM_NEON)
    543     return 1;
    544 
    545   return 0;
    546 }
    547 
    548 GLOBAL(int)
    549 jsimd_can_fdct_ifast (void)
    550 {
    551   init_simd();
    552 
    553   /* The code is optimised for these values only */
    554   if (DCTSIZE != 8)
    555     return 0;
    556   if (sizeof(DCTELEM) != 2)
    557     return 0;
    558 
    559   if (simd_support & JSIMD_ARM_NEON)
    560     return 1;
    561 
    562   return 0;
    563 }
    564 
    565 GLOBAL(int)
    566 jsimd_can_fdct_float (void)
    567 {
    568   init_simd();
    569 
    570   return 0;
    571 }
    572 
    573 GLOBAL(void)
    574 jsimd_fdct_islow (DCTELEM *data)
    575 {
    576   jsimd_fdct_islow_neon(data);
    577 }
    578 
    579 GLOBAL(void)
    580 jsimd_fdct_ifast (DCTELEM *data)
    581 {
    582   jsimd_fdct_ifast_neon(data);
    583 }
    584 
    585 GLOBAL(void)
    586 jsimd_fdct_float (FAST_FLOAT *data)
    587 {
    588 }
    589 
    590 GLOBAL(int)
    591 jsimd_can_quantize (void)
    592 {
    593   init_simd();
    594 
    595   /* The code is optimised for these values only */
    596   if (DCTSIZE != 8)
    597     return 0;
    598   if (sizeof(JCOEF) != 2)
    599     return 0;
    600   if (sizeof(DCTELEM) != 2)
    601     return 0;
    602 
    603   if (simd_support & JSIMD_ARM_NEON)
    604     return 1;
    605 
    606   return 0;
    607 }
    608 
    609 GLOBAL(int)
    610 jsimd_can_quantize_float (void)
    611 {
    612   init_simd();
    613 
    614   return 0;
    615 }
    616 
    617 GLOBAL(void)
    618 jsimd_quantize (JCOEFPTR coef_block, DCTELEM *divisors,
    619                 DCTELEM *workspace)
    620 {
    621   jsimd_quantize_neon(coef_block, divisors, workspace);
    622 }
    623 
    624 GLOBAL(void)
    625 jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT *divisors,
    626                       FAST_FLOAT *workspace)
    627 {
    628 }
    629 
    630 GLOBAL(int)
    631 jsimd_can_idct_2x2 (void)
    632 {
    633   init_simd();
    634 
    635   /* The code is optimised for these values only */
    636   if (DCTSIZE != 8)
    637     return 0;
    638   if (sizeof(JCOEF) != 2)
    639     return 0;
    640   if (BITS_IN_JSAMPLE != 8)
    641     return 0;
    642   if (sizeof(JDIMENSION) != 4)
    643     return 0;
    644   if (sizeof(ISLOW_MULT_TYPE) != 2)
    645     return 0;
    646 
    647   if (simd_support & JSIMD_ARM_NEON)
    648     return 1;
    649 
    650   return 0;
    651 }
    652 
    653 GLOBAL(int)
    654 jsimd_can_idct_4x4 (void)
    655 {
    656   init_simd();
    657 
    658   /* The code is optimised for these values only */
    659   if (DCTSIZE != 8)
    660     return 0;
    661   if (sizeof(JCOEF) != 2)
    662     return 0;
    663   if (BITS_IN_JSAMPLE != 8)
    664     return 0;
    665   if (sizeof(JDIMENSION) != 4)
    666     return 0;
    667   if (sizeof(ISLOW_MULT_TYPE) != 2)
    668     return 0;
    669 
    670   if (simd_support & JSIMD_ARM_NEON)
    671     return 1;
    672 
    673   return 0;
    674 }
    675 
    676 GLOBAL(void)
    677 jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info *compptr,
    678                 JCOEFPTR coef_block, JSAMPARRAY output_buf,
    679                 JDIMENSION output_col)
    680 {
    681   jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf,
    682                       output_col);
    683 }
    684 
    685 GLOBAL(void)
    686 jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info *compptr,
    687                 JCOEFPTR coef_block, JSAMPARRAY output_buf,
    688                 JDIMENSION output_col)
    689 {
    690   jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf,
    691                       output_col);
    692 }
    693 
    694 GLOBAL(int)
    695 jsimd_can_idct_islow (void)
    696 {
    697   init_simd();
    698 
    699   /* The code is optimised for these values only */
    700   if (DCTSIZE != 8)
    701     return 0;
    702   if (sizeof(JCOEF) != 2)
    703     return 0;
    704   if (BITS_IN_JSAMPLE != 8)
    705     return 0;
    706   if (sizeof(JDIMENSION) != 4)
    707     return 0;
    708   if (sizeof(ISLOW_MULT_TYPE) != 2)
    709     return 0;
    710 
    711   if (simd_support & JSIMD_ARM_NEON)
    712     return 1;
    713 
    714   return 0;
    715 }
    716 
    717 GLOBAL(int)
    718 jsimd_can_idct_ifast (void)
    719 {
    720   init_simd();
    721 
    722   /* The code is optimised for these values only */
    723   if (DCTSIZE != 8)
    724     return 0;
    725   if (sizeof(JCOEF) != 2)
    726     return 0;
    727   if (BITS_IN_JSAMPLE != 8)
    728     return 0;
    729   if (sizeof(JDIMENSION) != 4)
    730     return 0;
    731   if (sizeof(IFAST_MULT_TYPE) != 2)
    732     return 0;
    733   if (IFAST_SCALE_BITS != 2)
    734     return 0;
    735 
    736   if (simd_support & JSIMD_ARM_NEON)
    737     return 1;
    738 
    739   return 0;
    740 }
    741 
    742 GLOBAL(int)
    743 jsimd_can_idct_float (void)
    744 {
    745   init_simd();
    746 
    747   return 0;
    748 }
    749 
    750 GLOBAL(void)
    751 jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info *compptr,
    752                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
    753                   JDIMENSION output_col)
    754 {
    755   jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf,
    756                         output_col);
    757 }
    758 
    759 GLOBAL(void)
    760 jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info *compptr,
    761                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
    762                   JDIMENSION output_col)
    763 {
    764   jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf,
    765                         output_col);
    766 }
    767 
    768 GLOBAL(void)
    769 jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info *compptr,
    770                   JCOEFPTR coef_block, JSAMPARRAY output_buf,
    771                   JDIMENSION output_col)
    772 {
    773 }
    774 
    775 GLOBAL(int)
    776 jsimd_can_huff_encode_one_block (void)
    777 {
    778   init_simd();
    779 
    780   if (DCTSIZE != 8)
    781     return 0;
    782   if (sizeof(JCOEF) != 2)
    783     return 0;
    784 
    785   if (simd_support & JSIMD_ARM_NEON && simd_huffman)
    786     return 1;
    787 
    788   return 0;
    789 }
    790 
    791 GLOBAL(JOCTET*)
    792 jsimd_huff_encode_one_block (void *state, JOCTET *buffer, JCOEFPTR block,
    793                              int last_dc_val, c_derived_tbl *dctbl,
    794                              c_derived_tbl *actbl)
    795 {
    796   if (simd_features & JSIMD_FASTTBL)
    797     return jsimd_huff_encode_one_block_neon(state, buffer, block, last_dc_val,
    798                                             dctbl, actbl);
    799   else
    800     return jsimd_huff_encode_one_block_neon_slowtbl(state, buffer, block,
    801                                                     last_dc_val, dctbl, actbl);
    802 }
    803