Add cpu-target-features binary
This is a very small executable which is used to determine what CPU
target features are enabled for a given compiler toolchain. These
features are only provided through internal compiler defines, and thus
we have to do a lot of macro shenaningans to get them to display
correctly.
Bug: 354747380
Test: Built for x86_64 cuttlefish, not tested installation
Change-Id: Ic68cd365c41ddd278a856a21796e1645a82fd760
diff --git a/cpu_target_features/Android.bp b/cpu_target_features/Android.bp
new file mode 100644
index 0000000..25f37d1
--- /dev/null
+++ b/cpu_target_features/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "cpu-target-features",
+ srcs: [
+ "main.cpp",
+ ],
+ generated_headers: ["print_target_features.inc"],
+}
+
+genrule {
+ name: "print_target_features.inc",
+ out: ["print_target_features.inc"],
+ tool_files: ["generate_printer.py"],
+ cmd: "$(location generate_printer.py) $(out)",
+}
diff --git a/cpu_target_features/generate_printer.py b/cpu_target_features/generate_printer.py
new file mode 100755
index 0000000..dc56eb5
--- /dev/null
+++ b/cpu_target_features/generate_printer.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+
+"""Generate the compilation target feature printing source code.
+
+The source code for detecting target features is heavily redundant and
+copy-pasted, and is easier to maintain using a generative script.
+
+This script creates the source and the include files in its current
+directory.
+"""
+
+import argparse
+from pathlib import Path
+from typing import Dict, List, Iterable
+
+_CPP_BOILERPLATE: str = """\
+#include <stdio.h>
+
+#define TO_STRING_EXP(DEF) #DEF
+#define TO_STRING(DEF) TO_STRING_EXP(DEF)
+"""
+
+_FEATURES = {
+ "Aarch64": [
+ "__ARM_FEATURE_AES",
+ "__ARM_FEATURE_BTI",
+ "__ARM_FEATURE_CRC32",
+ "__ARM_FEATURE_CRYPTO",
+ "__ARM_FEATURE_PAC_DEFAULT",
+ "__ARM_FEATURE_SHA2",
+ "__ARM_FEATURE_SHA3",
+ "__ARM_FEATURE_SHA512",
+ ],
+ "Arm32": [
+ "__ARM_ARCH_ISA_THUMB",
+ "__ARM_FEATURE_AES",
+ "__ARM_FEATURE_BTI",
+ "__ARM_FEATURE_CRC32",
+ "__ARM_FEATURE_CRYPTO",
+ "__ARM_FEATURE_PAC_DEFAULT",
+ "__ARM_FEATURE_SHA2",
+ ],
+ "X86": [
+ "__AES__",
+ "__AVX__",
+ "__CRC32__",
+ "__POPCNT__",
+ "__SHA512__",
+ "__SHA__",
+ ],
+ "Riscv": [
+ "__riscv_vector",
+ ],
+}
+
+
+def _make_function_sig(name: str) -> str:
+ return f"void print{name}TargetFeatures()"
+
+
+def check_template(define: str) -> List[str]:
+ return [
+ f"#if defined({define})",
+ f' printf("%s=%s\\n", TO_STRING_EXP({define}), TO_STRING({define}));',
+ "#else",
+ f' printf("%s not defined\\n", TO_STRING_EXP({define}));',
+ "#endif",
+ ]
+
+
+def generate_cpp_file(define_mapping: Dict[str, List[str]]) -> List[str]:
+ out: List[str] = _CPP_BOILERPLATE.split("\n")
+ for target, defines in define_mapping.items():
+ out.append("")
+ out.extend(generate_print_function(target, defines))
+ return out
+
+
+def generate_print_function(name: str, defines: List[str]) -> List[str]:
+ """Generate a print<DEFINE>TargetFeatures function."""
+ function_body = [_make_function_sig(name) + " {"]
+ for d in defines:
+ function_body.extend(check_template(d))
+ function_body.append("}")
+ return function_body
+
+
+def parse_args() -> argparse.Namespace:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "cpp_in",
+ type=Path,
+ help="Output path to generate the cpp file.",
+ )
+ return parser.parse_args()
+
+
+def main() -> None:
+ args = parse_args()
+ printer_cpp_filepath = args.cpp_in
+ printer_cpp_filepath.write_text(
+ "\n".join(generate_cpp_file(_FEATURES)), encoding="utf-8"
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/cpu_target_features/main.cpp b/cpu_target_features/main.cpp
new file mode 100644
index 0000000..61f3d25
--- /dev/null
+++ b/cpu_target_features/main.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "print_target_features.inc"
+
+int main() {
+#if defined(__aarch64__)
+ printAarch64TargetFeatures();
+ return 0;
+#elif defined(__arm__)
+ printArm32TargetFeatures();
+ return 0;
+#elif defined(__x86_64__) || defined(__i386__)
+ printX86TargetFeatures();
+ return 0;
+#elif defined(__riscv)
+ printRiscvTargetFeatures();
+ return 0;
+#else
+#error Unsupported arch. This binary only supports aarch64, arm, x86, x86-64, and risc-v
+#endif
+}