By using .arch_extension (if supported) to enable the relevant
extensions, we can also disable them afterwards, so we can e.g.
cleanly enable one extension only for one subsection of a file.
This also makes it easier to enable various combinations of
supported architecture extensions.
This hasn't been needed for SVE/SVE2, as all toolchains have
supported just enabling it via ".arch armv8.2-a+sve". For other
arch extensions, like dotprod/i8mm, there's more combinations of
toolchain bugs in slightly older toolchains; try to detect what is
supported.
Additionally, when involving more than one architecture extension,
we may want to enable/disable individual extensions one at a time,
without needing to specify the full list in one single .arch
statement.
This is a preparatory commit for adding support for the dotprod/i8mm
extensions.
We intentionally don't add AS_ARCH_LEVEL to the CONFIG_HAVE list,
as this define isn't prefixed with "HAVE_", and we don't use the
define except in the case where we actually do set it. (It's not
a regular 0/1 define like the others.)
This requires adding the "-c" flag to ASFLAGS before doing the
check.
This also makes sure to validate the gas-preprocessor is functional
for MSVC configurations, by testing whether the "cmeq" instruction
can be assembled at this point.
This is more correct than using cc_check; we're going to assemble
standalone external assembly - thus check for whether we can
build it in that form, not using inline assembly.
This allows sharing checks with the MSVC codepath (where inline
assembly isn't supported, and where assembly is built using
a tool different from the regular compiler).
This updates the dependecy information on each successive recompile.
When building with MSVC, dependency information is generated with
a separate command just like before, but done together with
compiling each object file. (This is quite similar to how ffmpeg does
the same.)
This avoids the serial dependency generation step. In slow
environments (in particular if using MSVC) it could take a notable
amount of time; this can now all be done in parallel.
In one example, this reduces the time for a full build from clean
with MSVC (wrapped in wine) from 23 seconds down to 9 seconds,
thanks to parallelism. (For non-parallel builds, it doesn't make
much of a difference.)
Make use of _SC_NPROCESSORS_ONLN if it exists and fallback to
_SC_NPROCESSORS_CONF for really old operating systems. This adds
support for retrieving the number of CPUs on a few OS's such as
NetBSD, DragonFly and a few others.
PLT/GOT indirections are required in some cases. Most commonly when
calling functions from other shared libraries, but also in some
scenarios when calling functions with default symbol visibility
even within the same component on certain elf64 platforms.
On elf64 we can simply use PLT relocations for all calls to external
functions. Since the linker is able to eliminate unnecessary PLT
indirections with the final output binary being identical to non-PLT
relocations there isn't really any downside to doing so. This mimics
what regular compilers normally do for calls to external functions.
On elf32 with PIC we can use a function pointer from the GOT when
calling external functions, similar to what regular compilers do when
using -fno-plt. Since this both introduces overhead and clobbers one
register, which could potentially have been used for custom calling
conventions when calling other asm functions within the same library,
it's only performed for functions declared using 'cextern_naked'.
Prior to this change dealing with the scenario where the number of
XMM registers spilled depends on if a branch is taken or not was
complicated to handle well. There was essentially three options:
1) Always spill the largest number of XMM register. Results in
unnecessary spills.
2) Do the spilling after the branch. Results in code duplication
for the shared subset of spills.
3) Do the spilling manually. Optimal, but overly complex and vexing.
This adds an additional optional argument to the WIN64_SPILL_XMM
and WIN64_PUSH_XMM macros to make it possible to allocate space
for a certain number of registers but initially only push a subset
of those, with the option of pushing additional register later.
This makes the code much simpler (especially for adding support
for other instruction set extensions), avoids needing inline
assembly for this feature, and generally is more of the canonical
way to do this.
The CPU feature detection was added in
9c3c716882, using HWCAP_CPUID.
The argument for using that, was that HWCAP_CPUID was added much
earlier in the kernel (in Linux v4.11), while the HWCAP flags for
individual features always come later. This allows detecting support
for new CPU extensions before the kernel exposes information about
them via hwcap flags.
However in practice, there's probably quite little advantage in this.
E.g. HWCAP_SVE was added in Linux v4.15, and HWCAP2_SVE2 was added in
v5.10 - later than HWCAP_CPUID, but there's probably very little
practical cases where one would run a kernel older than that on a CPU
that supports those instructions.
Additionally, we provide our own definitions of the flag values to
check (as they are fixed constants anyway), with names not conflicting
with the ones from system headers. This reduces the number of ifdefs
needed, and allows detecting those features even if building with
userland headers that are lacking the definitions of those flags.
Also, slightly older versions of QEMU, e.g. 6.2 in Ubuntu 22.04,
do expose support for these features via HWCAP flags, but the
emulated cpuid registers are missing the bits for exposing e.g. SVE2
(This issue is fixed in later versions of QEMU though.)
Also drop the ifdef check for whether AT_HWCAP is defined; it was
added to glibc in 1997. AT_HWCAP2 was added in 2013, in glibc 2.18,
which also precedes when aarch64 was commonly used anyway, so
don't guard the use of that with an ifdef.
Automatically flag x86-64 asm object files as SHSTK-compatible.
Shadow Stack (SHSTK) is a part of Control-flow Enforcement Technology
(CET) which is a feature aimed at defending against ROP attacks by
verifying that 'call' and 'ret' instructions are correctly matched.
For well-written code this works transparently without any code changes,
as return addresses popped from the shadow stack should match return
addresses popped from the normal stack for performance reasons anyway.
Broadcasting a memory operand is a binary flag, you either broadcast
or you don't, and there's only a single possible element size for
any given instruction.
The instruction syntax however requires the broadcast semanticts
to be explicitly defined, which is an issue when using macros to
template code for multiple register widths.
Add some helper defines to alleviate the issue.
Imporve the performance of NEON functions of aarch64/deblock-a.S
by using the SVE/SVE2 instruction set. Below, the specific functions
are listed together with the improved performance results.
Command executed: ./checkasm8 --bench=deblock
Testbed: Alibaba g8y instance based on Yitian 710 CPU
Results:
deblock_chroma[1]_c: 735
deblock_chroma[1]_neon: 427
deblock_chroma[1]_sve: 353
Command executed: ./checkasm8 --bench=deblock
Testbed: AWS Graviton3
Results:
deblock_chroma[1]_c: 719
deblock_chroma[1]_neon: 442
deblock_chroma[1]_sve: 345
The sve-default-vector-length property sets the maximum vector
length in bytes; the default is 64, i.e. handling up to 512
bit vectors. In order to be able to test 1024 and 2048 bit vectors,
this has to be raised separately from setting the sve<n>=on
property.