The goal of this project is to write a functioning proof-of-concept prototype for the function-pruning component of Automatic Function Multi-Versioning (AFMV) capability to the Gnu Compiler Collection (GCC) for AArch64 systems, building on previous work.
We're attempting to add automatic function multi-versioning (AFMV) to the GCC compiler. This builds upon other capabilities within the compiler:
1. IFUNC - The ifunc capability allows a program to provide multiple implementations of a function, and to use a “resolver function” which is run once at program initialization to determine which implementation will be used. The resolver function returns a pointer to the selected function, which is used from that point on as for the life of the process. This capability is very flexible but requires the programmer to create:
2. FMV - The GCC compiler includes a function multiversioning capability for x86_32, x86_64, powerpc, and aarch64 architectures (with slightly different implementations). FMV is similar to ifunc, and can be used in two different ways:
This requires fewer code changes than ifunc, but still requires that the programmer state the architectural variants that will be targetted. The programmer also needs to know (or guess!) which functions would benefit from multiversioning.
3. AFMV - This “automatic function multi-versioning” capability does not exist yet, and is what we're working towards building. AFMV should work like FMV function cloning, but without any source code changes; instead, a compiler option will be used to specify the architectural variants of interest, and any function that would benefit from function multi-versioning will be automatically cloned. It is proposed that AFMV operate in this fashion:
Our project this semester is to determine how to detect when two different versions of a function are “fundamentally the same”.
We're going to do this work within the GCC compiler.
Note: the Project Stage 1 requirements were changed on Oct 31 due to issues with the available server systems.
1. Become familiar with the GCC build process. Build the current development version of GCC on x86_64 and aarch64 platforms. Get to know how long a full build takes, how to change the build options, and how to install a local (non-system, personal) copy of GCC. Make sure that you are very comfortable with the build process.
Note: you do not have to produce a full bootstrap build.
1a. Become familiar with producing and reviewing dumps produced during the compilation passes (see the -fdump-tree-all
and -fdump-tree-pass
compiler options and the associated code, as well as -fdump-rtl-all
and -fdump-rtl-pass
). Important: you do not (and should not) enable these options during the compilation of the GCC compiler itself, but you should test out using them to compile other (smaller!) programs.
2. Learn how to navigate the GCC codebase. Specifically, find out what code implements these aspects of the compiler and how to add to or change the code:
a. Find the code that controls the compilation passes, and how passes can be added. Test out adding a pass (even if just a dummy pass that produces a confirmation that it's running).
b. Find out how to access the intermediate representation (IR) of the program being compiled. Ideally, experiment with using the accessor macros (see the GCC documentation) to access and perhaps iterate through the IR. You could, for example, create a pass that performs a scan for all of the function names, and identifies all of the clones of a function.
c. Find out how dumps are produced during the compilation passes (see the
-fdump-tree-all
and -fdump-tree-pass
compiler options and the associated code, as well as -fdump-rtl-all
and -fdump-rtl-pass
). Become familiar with producing and reviewing these dumps. Consider creating a dummy pass that produces a useful diagnostic dump, or add a dump to the an IR scanning pass.
Blog your results:
GCC IFUNC documenation:
Current documentation:
target_clones
syntax__HAVE_FEATURE_MULTI_VERSIONING
(or __FEATURE_FUNCTION_MULTI_VERSIONING
or __ARM_FEATURE_FUNCTION_MULTIVERSIONING
) does not appear to be defined (as of GCC 14.2.1)Implementation in GCC
__attribue__((target("nnn")))
- where nnn
may take the form of “default”, or “feature” eg., “sse4.2”, or “feature,feature” e.g., “sse4.2,avx2”, or it may take the form “arch=archlevel” e.g., “arch=x86-64-v3” or “arch=atom”__attribute__((target_clone("nnn1", "nnn2" [...])))
__attribute__((target_version("nnn")))
- where nnn
may take the form of “default”, or “feature” e.g., “sve”, or “feature+feature” e.g., “sve+sve2” (Note: in some earlier versions of GCC, a plus-sign was required at the start of the feature list, e.g., “+sve” instead of “sve”. This was changed by gcc 14). Note the use of the attribute target_version
as opposed to target
(as used on x86) which is compliant with the ACLE specification; it appears possible to use target
in some versions of the GCC compiler (apparently with the plus-sign at the start of the feature-list?). Note that the “arch=nnn” format is not supported (and probably should be).__attribute__((target_clone("nnn", "nnn" [...])))
- note that contrary to the ACLE documentation, there is no automatic “default” argument - the first argument supplied should be “default”