simd/x86_64/jsimd.c


Log

Author Commit Date CI Message
DRC e69dd40c 2024-01-23T13:26:41 Reorganize source to make things easier to find - Move all libjpeg documentation, except for README.ijg, into the doc/ subdirectory. - Move the TurboJPEG C API documentation from doc/html/ into doc/turbojpeg/. - Move all C source code and headers into a src/ subdirectory. - Move turbojpeg-jni.c into the java/ subdirectory. Referring to #226, there is no ideal solution to this problem. A semantically ideal solution would have involved placing all source code, including the SIMD and Java source code, under src/ (or perhaps placing C library source code under lib/ and C test program source code under test/), all header files under include/, and all documentation under doc/. However: - To me it makes more sense to have separate top-level directories for each language, since the SIMD extensions and the Java API are technically optional features. src/ now contains only the code that is relevant to the core C API libraries and associated programs. - I didn't want to bury the java/ and simd/ directories or add a level of depth to them, since both directories already contain source code that is 3-4 levels deep. - I would prefer not to separate the header files from the C source code, because: 1. It would be disruptive. libjpeg and libjpeg-turbo have historically placed C source code and headers in the same directory, and people who are familiar with both projects (self included) are used to looking for the headers in the same directory as the C source code. 2. In terms of how the headers are used internally in libjpeg-turbo, the distinction between public and private headers is a bit fuzzy. - It didn't make sense to separate the test source code from the library source code, since there is not a clear distinction in some cases. (For instance, the IJG image I/O functions are used by cjpeg and djpeg as well as by the TurboJPEG API.) This solution is minimally disruptive, since it keeps all C source code and headers together and keeps java/ and simd/ as top-level directories. It is a bit awkward, because java/ and simd/ technically contain source code, even though they are not under src/. However, other solutions would have been more awkward for different reasons. Closes #226
DRC 4e028ecd 2023-02-02T08:55:37 SIMD/x86: Initialize simd_support before every use As long as a libjpeg instance is only used by one thread at a time, a program is technically within its rights to call jpeg_start_*compress() in one thread and jpeg_(read|write)_*(), with the same libjpeg instance, in a second thread. However, because the various jsimd_can*() functions are called within the body of jpeg_start_*compress() and simd_support is now thread-local (due to f579cc11b33e5bfeb9931e37cc74b4a33c95d2e6), that led to a situation in which simd_support was initialized in the first thread but not the second. The uninitialized value of simd_support is 0xFFFFFFFF, which the second thread interpreted to mean that it could use any instruction set, and when it attempted to use AVX2 instructions on a CPU that didn't support them, an illegal instruction error occurred. This issue was known to affect libvips. This commit modifies the i386 and x86-64 SIMD dispatchers so that the various jsimd_*() functions always call init_simd(), if simd_support is uninitialized, prior to dispatching based on the value of simd_support. Note that the other SIMD dispatchers don't need this, because only the x86 SIMD extensions currently support multiple instruction sets. This patch has been verified to be performance-neutral to within +/- 0.4% with 32-bit and 64-bit code running on a 2.8 GHz Intel Xeon W3530 and a 3.6 GHz Intel Xeon W2123. Fixes #649
DRC 78a36f6d 2022-11-15T17:01:17 Fix buffer overrun in 12-bit prog Huffman encoder Regression introduced by 16bd984557fa2c490be0b9665e2ea0d4274528a8 and 5b177b3cab5cfb661256c1e74df160158ec6c34e The pre-computed absolute values used in encode_mcu_AC_first() and encode_mcu_AC_refine() were stored in a JCOEF (signed short) array. When attempting to losslessly transform a specially-crafted malformed 12-bit JPEG image with a coefficient value of -32768 into a progressive 12-bit JPEG image, the progressive Huffman encoder attempted to store the absolute value of -32768 in the JCOEF array, thus overflowing the 16-bit signed data type. Therefore, at this point in the code: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/8c5e78ce292c1642057102eac42f12ab57964293/jcphuff.c#L889 the absolute value was read as -32768, which caused the test at https://github.com/libjpeg-turbo/libjpeg-turbo/blob/8c5e78ce292c1642057102eac42f12ab57964293/jcphuff.c#L896 to fail, falling through to https://github.com/libjpeg-turbo/libjpeg-turbo/blob/8c5e78ce292c1642057102eac42f12ab57964293/jcphuff.c#L908 with an overly large value of r (46) that, when shifted left four places, incremented, and passed to emit_symbol(), exceeded the maximum index (255) for the derived code tables. Fortunately, the buffer overrun was fully contained within phuff_entropy_encoder, so the issue did not generate a segfault or other user-visible errant behavior, but it did cause a UBSan failure that was detected by OSS-Fuzz. This commit introduces an unsigned JCOEF (UJCOEF) data type and uses it to store the absolute values of DCT coefficients computed by the AC_first_prepare() and AC_refine_prepare() methods. Note that the changes to the Arm Neon progressive Huffman encoder extensions cause signed 16-bit instructions to be replaced with equivalent unsigned 16-bit instructions, so the changes should be performance-neutral. Based on: https://github.com/mayeut/libjpeg-turbo/commit/bbf61c0382c4f8bd1f1cfc666467581496c2fb7c Closes #628
DRC eb0a024a 2022-10-04T12:51:38 Remove redundant jconfigint.h #includes Because of 607b668ff96e40fdc749de9b1bb98e7f40c86d93, jconfigint.h is included by jinclude.h.
DRC f579cc11 2022-10-03T19:46:09 Make SIMD capability variables thread-local ... ... on platforms that support TLS, which should include all currently-supported platforms (https://libjpeg-turbo.org/Documentation/OfficialBinaries) Addresses a concern raised in #87 Although it is still my opinion that the data race in init_simd() was innocuous, we can now fix it for free thanks to ae87a958613b69628b92088b313ded0d4f59a716, so why not?
DRC 607b668f 2022-02-10T11:33:49 MSVC: Eliminate C4996 warnings in API libs The primary purpose of this is to encourage adoption of libjpeg-turbo in downstream Windows projects that forbid the use of "deprecated" functions. libjpeg-turbo's usage of those functions was not actually unsafe, because: - libjpeg-turbo always checks the return value of fopen() and ensures that a NULL filename can never be passed to it. - libjpeg-turbo always checks the return value of getenv() and never passes a NULL argument to it. - The sprintf() calls in format_message() (jerror.c) could never overflow the destination string buffer or leave it unterminated as long as the buffer was at least JMSG_LENGTH_MAX bytes in length, as instructed. (Regardless, this commit replaces those calls with snprintf() calls.) - libjpeg-turbo never uses sscanf() to read strings or multi-byte character arrays. - Because of b7d6e84d6a9283dc2bc50ef9fcaadc0cdeb25c9f, wrjpgcom explicitly checks the bounds of the source and destination strings before calling strcat() and strcpy(). - libjpeg-turbo always ensures that the destination string is terminated when using strncpy(). (548490fe5e2aa31cb00f6602d5a478b068b99682 made this explicit.) Regarding thread safety: Technically speaking, getenv() is not thread-safe, because the returned pointer may be invalidated if another thread sets the same environment variable between the time that the first thread calls getenv() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if: (1) A multithreaded calling application used the deprecated and undocumented TJFLAG_FORCEMMX/TJFLAG_FORCESSE/TJFLAG_FORCESSE2 flags in the TurboJPEG API or set one of the corresponding environment variables (which are only intended for testing purposes.) Since the TurboJPEG API library only ever passed string constants to putenv(), the only inherent risk (i.e. the only risk introduced by the library and not the calling application) was that the SIMD extensions may have read an incorrect value from one of the aforementioned environment variables. or (2) A multithreaded calling application modified the value of the JPEGMEM environment variable in one thread while another thread was reading the value of that environment variable (in the body of jpeg_create_compress() or jpeg_create_decompress().) Given that the libjpeg API provides a thread-safe way for applications to modify the default memory limit without using the JPEGMEM environment variable, direct modification of that environment variable by calling applications is not supported. Microsoft's implementation of getenv_s() does not claim to be thread-safe either, so this commit uses getenv_s() solely to mollify Visual Studio. New inline functions and macros (GETENV_S() and PUTENV_S) wrap getenv_s()/_putenv_s() when building for Visual Studio and getenv()/setenv() otherwise, but GETENV_S()/PUTENV_S() provide no advantages over getenv()/setenv() other than parameter validation. They are implemented solely for convenience. Technically speaking, strerror() is not thread-safe, because the returned pointer may be invalidated if another thread changes the locale and/or calls strerror() between the time that the first thread calls strerror() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if a multithreaded calling application encountered a file I/O error in tjLoadImage() or tjSaveImage(). Since both of those functions immediately copy the string returned from strerror() into a thread-local buffer, the risk is minimal, and the worst case would involve an incorrect error string being reported to the calling application. Regardless, this commit uses strerror_s() in the TurboJPEG API library when building for Visual Studio. Note that strerror_r() could have been used on Un*x systems, but it would have been necessary to handle both the POSIX and GNU implementations of that function and perform widespread compatibility testing. Such is left as an exercise for another day. Fixes #568
DRC 713c451f 2019-11-08T14:53:55 Enable SSE2 progressive Huffman encoder for x32 Referring to #289, I'm not sure where I arrived at the conclusion that the SSE2 progressive Huffman encoder doesn't provide any speedup for x32. Upon re-testing, I discovered it to be about 50% faster than the C encoder. This commit also re-purposes one of the CI tests (specifically, the jpeg-7 API/ABI test) so that it tests x32 as well.
mayeut 269e84c9 2018-04-10T00:02:57 jsimd_can_encode_mcu_AC_*(): Remove useless checks These were necessary for the first iteration of the feature (see #46), which provided a different C front end for the SIMD version of the function. The final version of the feature uses a common C front end for both SIMD and non-SIMD implementations, so these checks are no longer necessary. Closes #231
DRC 58cb10ee 2018-03-31T13:51:31 Eliminate compiler warnings w/ Solaris Studio
mayeut 5b177b3c 2018-03-22T11:36:43 C/SSE2 optimization of encode_mcu_AC_first() This commit adds C and SSE2 optimizations for the encode_mcu_AC_first() function used in progressive Huffman encoding. The image used for testing can be retrieved from this page: https://blog.cloudflare.com/doubling-the-speed-of-jpegtran All timings done on `Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz` clang version is `Apple LLVM version 9.0.0 (clang-900.0.39.2)` gcc-5 version is `gcc-5 (Homebrew GCC 5.5.0) 5.5.0` gcc-7 version is `gcc-7 (Homebrew GCC 7.2.0) 7.2.0` Here are the results in comparison to libjpeg-turbo@293263c using `time ./jpegtran -outfile /dev/null -progressive -optimise -copy none print_poster_0025.jpg` C clang x86_64: +19% gcc-5 x86_64: +80% gcc-7 x86_64: +57% clang i386: +5% gcc-5 i386: +59% gcc-7 i386: +51% SSE2 clang x86_64: +79% gcc-5 x86_64: +158% gcc-7 x86_64: +122% clang i386: +71% gcc-5 i386: +134% gcc-7 i386: +135% Discussion in libjpeg-turbo/libjpeg-turbo#46
mayeut 16bd9845 2018-03-02T22:33:19 C/SSE2 optimization of encode_mcu_AC_refine() This commit adds C and SSE2 optimizations for the encode_mcu_AC_refine() function used in progressive Huffman encoding. The image used for testing can be retrieved from this page: https://blog.cloudflare.com/doubling-the-speed-of-jpegtran All timings done on `Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz` clang version is `Apple LLVM version 9.0.0 (clang-900.0.39.2)` gcc-5 version is `gcc-5 (Homebrew GCC 5.5.0) 5.5.0` gcc-7 version is `gcc-7 (Homebrew GCC 7.2.0) 7.2.0` Here are the results in comparison to libjpeg-turbo@3c54642 using `time ./jpegtran -outfile /dev/null -progressive -optimise -copy none print_poster_0025.jpg` C clang x86_64: +7% gcc-5 x86_64: +30% gcc-7 x86_64: +33% clang i386: +0% gcc-5 i386: +24% gcc-7 i386: +23% SSE2 clang x86_64: +42% gcc-5 x86_64: +53% gcc-7 x86_64: +64% clang i386: +35% gcc-5 i386: +46% gcc-7 i386: +49% Discussion in libjpeg-turbo/libjpeg-turbo#46
DRC 293263c3 2018-03-17T15:14:35 Format preprocessor macros more consistently Within the libjpeg API code, it seems to be more the convention than not to separate the macro name and value by two or more spaces, which improves general readability. Making this consistent across all of libjpeg-turbo is less about my individual preferences and more about making it easy to automatically detect variations from our chosen formatting convention. I intend to release the script I'm using to validate this stuff, once it matures and stabilizes a bit.
DRC 84fbd4f1 2018-03-17T00:27:49 Merge branch 'master' into dev
DRC 19c791cd 2018-03-08T10:55:20 Improve code formatting consistency With rare exceptions ... - Always separate line continuation characters by one space from preceding code. - Always use two-space indentation. Never use tabs. - Always use K&R-style conditional blocks. - Always surround operators with spaces, except in raw assembly code. - Always put a space after, but not before, a comma. - Never put a space between type casts and variables/function calls. - Never put a space between the function name and the argument list in function declarations and prototypes. - Always surround braces ('{' and '}') with spaces. - Always surround statements (if, for, else, catch, while, do, switch) with spaces. - Always attach pointer symbols ('*' and '**') to the variable or function name. - Always precede pointer symbols ('*' and '**') by a space in type casts. - Use the MIN() macro from jpegint.h within the libjpeg and TurboJPEG API libraries (using min() from tjutil.h is still necessary for TJBench.) - Where it makes sense (particularly in the TurboJPEG code), put a blank line after variable declaration blocks. - Always separate statements in one-liners by two spaces. The purpose of this was to ease maintenance on my part and also to make it easier for contributors to figure out how to format patch submissions. This was admittedly confusing (even to me sometimes) when we had 3 or 4 different style conventions in the same source tree. The new convention is more consistent with the formatting of other OSS code bases. This commit corrects deviations from the chosen formatting style in the libjpeg API code and reformats the TurboJPEG API code such that it conforms to the same standard. NOTES: - Although it is no longer necessary for the function name in function declarations to begin in Column 1 (this was historically necessary because of the ansi2knr utility, which allowed libjpeg to be built with non-ANSI compilers), we retain that formatting for the libjpeg code because it improves readability when using libjpeg's function attribute macros (GLOBAL(), etc.) - This reformatting project was accomplished with the help of AStyle and Uncrustify, although neither was completely up to the task, and thus a great deal of manual tweaking was required. Note to developers of code formatting utilities: the libjpeg-turbo code base is an excellent test bed, because AFAICT, it breaks every single one of the utilities that are currently available. - The legacy (MMX, SSE, 3DNow!) assembly code for i386 has been formatted to match the SSE2 code (refer to ff5685d5344273df321eb63a005eaae19d2496e3.) I hadn't intended to bother with this, but the Loongson MMI implementation demonstrated that there is still academic value to the MMX implementation, as an algorithmic model for other 64-bit vector implementations. Thus, it is desirable to improve its readability in the same manner as that of the SSE2 implementation.
DRC de9e9db6 2018-02-23T11:50:11 64-bit AVX2 implementation of slow int inverse DCT
DRC 39e9e65c 2018-02-17T19:39:53 64-bit AVX2 implementation of int sample conv.
DRC 264dd42a 2018-02-17T17:32:25 64-bit AVX2 implementation of slow int forward DCT
DRC 6abd3916 2016-11-15T08:47:43 Unified CMake-based build system See #56 for discussion. Fixes #21, Fixes #29, Fixes #37, Closes #56, Fixes #58, Closes #73 Obviates #82 See also: https://sourceforge.net/p/libjpeg-turbo/feature-requests/5/ https://sourceforge.net/p/libjpeg-turbo/patches/5/