xref: /aosp_15_r20/bionic/cpu_target_features/generate_printer.py (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1#!/usr/bin/env python3
2
3"""Generate the compilation target feature printing source code.
4
5The source code for detecting target features is heavily redundant and
6copy-pasted, and is easier to maintain using a generative script.
7
8This script creates the source and the include files in its current
9directory.
10"""
11
12import argparse
13from pathlib import Path
14from typing import Dict, List, Iterable
15
16_CPP_BOILERPLATE: str = """\
17#include <stdio.h>
18
19#define TO_STRING_EXP(DEF) #DEF
20#define TO_STRING(DEF) TO_STRING_EXP(DEF)
21"""
22
23_FEATURES = {
24    "Aarch64": [
25        "__ARM_FEATURE_AES",
26        "__ARM_FEATURE_BTI",
27        "__ARM_FEATURE_CRC32",
28        "__ARM_FEATURE_CRYPTO",
29        "__ARM_FEATURE_PAC_DEFAULT",
30        "__ARM_FEATURE_SHA2",
31        "__ARM_FEATURE_SHA3",
32        "__ARM_FEATURE_SHA512",
33    ],
34    "Arm32": [
35        "__ARM_ARCH_ISA_THUMB",
36        "__ARM_FEATURE_AES",
37        "__ARM_FEATURE_BTI",
38        "__ARM_FEATURE_CRC32",
39        "__ARM_FEATURE_CRYPTO",
40        "__ARM_FEATURE_PAC_DEFAULT",
41        "__ARM_FEATURE_SHA2",
42    ],
43    "X86": [
44        "__AES__",
45        "__AVX__",
46        "__CRC32__",
47        "__POPCNT__",
48        "__SHA512__",
49        "__SHA__",
50    ],
51    "Riscv": [
52        "__riscv_vector",
53    ],
54}
55
56
57def _make_function_sig(name: str) -> str:
58    return f"void print{name}TargetFeatures()"
59
60
61def check_template(define: str) -> List[str]:
62    return [
63        f"#if defined({define})",
64        f'  printf("%s=%s\\n", TO_STRING_EXP({define}), TO_STRING({define}));',
65        "#else",
66        f'  printf("%s not defined\\n", TO_STRING_EXP({define}));',
67        "#endif",
68    ]
69
70
71def generate_cpp_file(define_mapping: Dict[str, List[str]]) -> List[str]:
72    out: List[str] = _CPP_BOILERPLATE.split("\n")
73    for target, defines in define_mapping.items():
74        out.append("")
75        out.extend(generate_print_function(target, defines))
76    return out
77
78
79def generate_print_function(name: str, defines: List[str]) -> List[str]:
80    """Generate a print<DEFINE>TargetFeatures function."""
81    function_body = [_make_function_sig(name) + " {"]
82    for d in defines:
83        function_body.extend(check_template(d))
84    function_body.append("}")
85    return function_body
86
87
88def parse_args() -> argparse.Namespace:
89    parser = argparse.ArgumentParser(description=__doc__)
90    parser.add_argument(
91        "cpp_in",
92        type=Path,
93        help="Output path to generate the cpp file.",
94    )
95    return parser.parse_args()
96
97
98def main() -> None:
99    args = parse_args()
100    printer_cpp_filepath = args.cpp_in
101    printer_cpp_filepath.write_text(
102        "\n".join(generate_cpp_file(_FEATURES)), encoding="utf-8"
103    )
104
105
106if __name__ == "__main__":
107    main()
108