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