blob: dc56eb5fb9f0e2b0e0cc6c9209f09690ca20be04 [file] [log] [blame]
Jordan R Abrahams-Whitehead917dd902024-08-15 23:12:25 +00001#!/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()