I'm working on my HiKey. I'm trying to enable CRC extension on ARMv8 in the assembler regardless of the way GCC was built, and regardless of the user's CFLAGS and CXXFLAGS. I'm encountering an assembler error: "unknown pseudo-op: `.arch_extension'".
According to [1], I can use ".arch_extension" to enable it. According to [2], ".arch_extension" is available in GCC 4.6 and GAS 2.21. My version of Linaro provides GCC 4.9.2 and GAS 2.25.90. I can also duplicate the issue on GCC113 (compiel farm), which provides GCC 4.8 and GAS 2.24.
The test program is below. Trying to compile it results in:
$ g++ test.cxx -c /tmp/ccVZ6hiq.s: Assembler messages: /tmp/ccVZ6hiq.s:24: Error: unknown pseudo-op: `.arch_extension' /tmp/ccVZ6hiq.s:25: Error: selected processor does not support `crc32b w1,w0,w0'
Trying to compile without ".arch_extension" results in:
$ g++ test.cxx -c /tmp/cci4wu6d.s: Assembler messages: /tmp/cci4wu6d.s:24: Error: selected processor does not support `crc32b w1,w0,w0'
Its almost as if ".arch_extension" is not being properly recognized or consumed.
Any ideas what might be going wrong here?
**********
The program:
$ cat test.cxx #include <arm_neon.h>
#define GCC_INLINE_ATTRIB __attribute__((__gnu_inline__, __always_inline__, __artificial__))
#if defined(__GNUC__) && !defined(__ARM_FEATURE_CRC32) __inline unsigned int GCC_INLINE_ATTRIB CRC32B(unsigned int crc, unsigned char v) { unsigned int r; asm (" \n" ".arch_extension crc \n" "\t" "crc32b %w2, %w1, %w0 \n" : "=r"(r) : "r"(crc), "r"((unsigned int)v)); return r; } #else // just use the instrinsic # define CRC32B(a,b) __crc32b(a,b) #endif
int main(int argc, char* argv[]) { return CRC32B(argc, argc); }
**********
Versions...
$ gcc --version gcc (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04.3) 4.8.4
$ as -v GNU assembler version 2.24 (aarch64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.24
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.5 LTS Release: 14.04 Codename: trusty
[1] https://sourceware.org/binutils/docs/as/AArch64-Directives.html#AArch64-Dire... [2] https://gcc.gnu.org/ml/gcc-help/2012-07/msg00180.html
On Wed, Apr 19, 2017 at 12:38 PM, Jeffrey Walton noloader@gmail.com wrote:
According to [1], I can use ".arch_extension" to enable it. According to [2], ".arch_extension" is available in GCC 4.6 and GAS 2.21. My version of Linaro provides GCC 4.9.2 and GAS 2.25.90. I can also duplicate the issue on GCC113 (compiel farm), which provides GCC 4.8 and GAS 2.24.
ARM is a little ambiguous. It turns out that arch_extension was added to the arm (32-bit) port in 2010, but wasn't added to the aarch64 (64-bit) port until 2014. So you need binutils-2.26 in order to use arch_extension pseudo-op with the aarch64 toolchain.
Meanwhile, you might try looking at the arm_neon.h header file for your gcc version. Though it apperas in gcc-4.9.2 there is only a predefined macro __ARM_FEATURE_CRYPTO that you can use, and nothing for CRC. GCC 5.x adds a __ARM_FEATURE_CRC32 predefined macro that you could use.
With gcc 6, the arm_neon.h file uses #pragma GCC push_options #pragma GCC target ("+nothing+crypto") ... #pragma GCC pop_options to enable crypto support. You can do something similar with crc, you probably want to use "+onthing+crc" if you only want crc support enalbed, or "+simd+crc" if you want both simd and crc support enabled for instance.
The GCC aarch64 port does not use the arch64_extension support in binutils.
I think the linux kernel just puts functions that need crc support in different files, so that those files can be compiled with crc support enabled via -mcpu=generic+crc.
Jim
On Wed, Apr 19, 2017 at 9:57 PM, Jim Wilson jim.wilson@linaro.org wrote:
On Wed, Apr 19, 2017 at 12:38 PM, Jeffrey Walton noloader@gmail.com wrote:
According to [1], I can use ".arch_extension" to enable it. According to [2], ".arch_extension" is available in GCC 4.6 and GAS 2.21. My version of Linaro provides GCC 4.9.2 and GAS 2.25.90. I can also duplicate the issue on GCC113 (compiel farm), which provides GCC 4.8 and GAS 2.24.
ARM is a little ambiguous. It turns out that arch_extension was added to the arm (32-bit) port in 2010, but wasn't added to the aarch64 (64-bit) port until 2014. So you need binutils-2.26 in order to use arch_extension pseudo-op with the aarch64 toolchain.
Meanwhile, you might try looking at the arm_neon.h header file for your gcc version. Though it apperas in gcc-4.9.2 there is only a predefined macro __ARM_FEATURE_CRYPTO that you can use, and nothing for CRC. GCC 5.x adds a __ARM_FEATURE_CRC32 predefined macro that you could use.
With gcc 6, the arm_neon.h file uses #pragma GCC push_options #pragma GCC target ("+nothing+crypto") ... #pragma GCC pop_options to enable crypto support. You can do something similar with crc, you probably want to use "+onthing+crc" if you only want crc support enalbed, or "+simd+crc" if you want both simd and crc support enabled for instance.
The GCC aarch64 port does not use the arch64_extension support in binutils.
I think the linux kernel just puts functions that need crc support in different files, so that those files can be compiled with crc support enabled via -mcpu=generic+crc.
Ah, thanks Jim. That would have taken me a long time to discover.
I've had some success with something similar to the kernel method. The program below works with GCC 4.8, 4.9 and later.
The thing I am not sure about is saving and restoring the cpu. The AS manual states "Specifying .cpu clears any previously selected architecture extensions". But arch_extensions does not seem to work, so I guess its a moot point. Also, the manual only discusses '.set' in the context of MIPS. The program below does not produce a warning or error. I am not sure if its doing what's expected.
I'm trying to avoid adding an additional source file for each source file that uses NEON, CRC or CRYPTO. We are a C++ project, and it means moving functions out of headers and into source files. Additionally, we have 175 source files (plus headers), and the strategy could double the counts.
Our choices are kind of crummy at this point...
Jeff
$ cat test.cxx #include <arm_neon.h> #include <arm_acle.h>
#define GCC_INLINE_ATTRIB __attribute__((__gnu_inline__, __always_inline__, __artificial__))
#if defined(__GNUC__) && !defined(__ARM_FEATURE_CRC32) __inline unsigned int GCC_INLINE_ATTRIB CRC32B(unsigned int crc, unsigned char v) { unsigned int r; asm (".set push, .cpu \n" ".cpu generic+crc \n" "crc32w %w2, %w1, %w0 \n" ".set pop, .cpu \n" : "=r"(r) : "r"(crc), "r"((unsigned int)v)); return r; } #else // just use the intrinsic # define CRC32B(a,b) __crc32b(a,b) #endif
int main(int argc, char* argv[]) { return CRC32B(argc, argc); }
On Wed, Apr 19, 2017 at 11:35 PM, Jeffrey Walton noloader@gmail.com wrote:
On Wed, Apr 19, 2017 at 9:57 PM, Jim Wilson jim.wilson@linaro.org wrote:
On Wed, Apr 19, 2017 at 12:38 PM, Jeffrey Walton noloader@gmail.com wrote:
The thing I am not sure about is saving and restoring the cpu. The AS manual states "Specifying .cpu clears any previously selected architecture extensions". But arch_extensions does not seem to work, so I guess its a moot point. Also, the manual only discusses '.set' in the context of MIPS. The program below does not produce a warning or error. I am not sure if its doing what's expected.
For a non-mips target, .set is the same as .equ and =, it sets a symbol value to an expression. Your code using .set push and .set pop isn't doing anything useful.
I don't see any mechanism in the assembler to save/restore a cpu setting. There is one in gcc, but not until gcc 6.
I don't see any easy solution for you at the moment, you need a binutils/gcc upgrade, or you need to put crc code in separate files. Or you could force all files to be compiled with -mcpu=generic, and then you can use .cpu to add/remove crc support as necessary.
Jim
I don't see any easy solution for you at the moment, you need a binutils/gcc upgrade, or you need to put crc code in separate files. Or you could force all files to be compiled with -mcpu=generic, and then you can use .cpu to add/remove crc support as necessary.
Thanks Jim. This came from Jiong Wang on the Binutils mailing list (https://sourceware.org/ml/binutils/2017-04/msg00171.html):
__inline unsigned int GCC_INLINE_ATTRIB CRC32B(unsigned int crc, unsigned char v) { unsigned int r; asm ("\t.set raw_x0, 0\n" "\t.set raw_x1, 1\n" "\t.set raw_x2, 2\n" "\t.set raw_x3, 3\n" "\t.set raw_x4, 4\n" "\t.set raw_x5, 5\n" "\t.set raw_x6, 6\n" "\t.set raw_x7, 7\n" "\t#crc32w %w2, %w1, %w0\n" "\t.inst\t0x1ac04800 | (raw_%2) | (raw_%1 << 5) | (raw_%0 << 16)\n" : "=r"(r) : "r"(crc), "r"((unsigned int)v) ); return r; }
Thanks for the help (and thanks to the Binutil folks). I would not have gotten this far on my own.
Jeff
linaro-toolchain@lists.linaro.org