aboutsummaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorAndreas T Jonsson <mail@andreasjonsson.se>2024-05-10 09:04:52 +0200
committerAndreas T Jonsson <mail@andreasjonsson.se>2024-05-10 09:04:52 +0200
commitb72c2edabbc9087b07a30b781de1925d6570dd62 (patch)
tree0e96f43038901ec8c6f6b015071c1803a2166d41 /misc
parent273e4c6b4ce6f1060870782c8e780fe2b371ede4 (diff)
parent41bd8cf7143902db59c02c56fc5318a7e749d7a5 (diff)
Merge branch 'master' into netbsd
Diffstat (limited to 'misc')
-rw-r--r--misc/featuregen/README.md28
-rw-r--r--misc/featuregen/featuregen.cpp37
-rw-r--r--misc/featuregen/featuregen.py116
3 files changed, 181 insertions, 0 deletions
diff --git a/misc/featuregen/README.md b/misc/featuregen/README.md
new file mode 100644
index 000000000..22a798cca
--- /dev/null
+++ b/misc/featuregen/README.md
@@ -0,0 +1,28 @@
+# Featuregen
+
+This directory contains a python and CPP script that generates the needed information
+for features regarding microarchitecture and target features of the compiler.
+
+It is not pretty! But LLVM has no way to query this information with their C API.
+
+It generates these globals (intended for `src/build_settings.cpp`:
+
+- `target_microarch_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of microarchitectures available on that architecture
+- `target_features_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of target features available on that architecture
+- `target_microarch_counts`: an array of ints indexed by the architecture, each int represents the amount of microarchitectures available on that target, intended for easier iteration of the next global
+- `microarch_features_list`: an array of a tuple like struct where the first string is a microarchitecture and the second is a comma-seperated list of all features that are enabled by default for it
+
+In order to get the default features for a microarchitecture there is a small CPP program that takes
+a target triple and microarchitecture and spits out the default features, this is then parsed by the python script.
+
+This should be ran each time we update LLVM to stay in sync.
+
+If there are minor differences (like the Odin user using LLVM 14 and this table being generated on LLVM 17) it
+does not impact much at all, the only thing it will do is make LLVM print a message that the feature is ignored (if it was added between 14 and 17 in this case).
+
+## Usage
+
+1. Make sure the table of architectures at the top of the python script is up-to-date (the triple can be any valid triple for the architecture)
+1. `./build.sh`
+1. `python3 featuregen.py`
+1. Copy the output into `src/build_settings.cpp`
diff --git a/misc/featuregen/featuregen.cpp b/misc/featuregen/featuregen.cpp
new file mode 100644
index 000000000..a1d00ab31
--- /dev/null
+++ b/misc/featuregen/featuregen.cpp
@@ -0,0 +1,37 @@
+#include <llvm/MC/MCSubtargetInfo.h>
+#include <llvm/MC/TargetRegistry.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/ADT/ArrayRef.h>
+#include <llvm/Support/InitLLVM.h>
+#include <llvm/Support/TargetSelect.h>
+
+// Dumps the default set of supported features for the given microarch.
+int main(int argc, char **argv) {
+ if (argc < 3) {
+ llvm::errs() << "Error: first arg should be triple, second should be microarch\n";
+ return 1;
+ }
+
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+
+ std::string error;
+ const llvm::Target* target = llvm::TargetRegistry::lookupTarget(argv[1], error);
+
+ if (!target) {
+ llvm::errs() << "Error: " << error << "\n";
+ return 1;
+ }
+
+ auto STI = target->createMCSubtargetInfo(argv[1], argv[2], "");
+
+ std::string plus = "+";
+ llvm::ArrayRef<llvm::SubtargetFeatureKV> features = STI->getAllProcessorFeatures();
+ for (const auto& feature : features) {
+ if (STI->checkFeatures(plus + feature.Key)) {
+ llvm::outs() << feature.Key << "\n";
+ }
+ }
+
+ return 0;
+}
diff --git a/misc/featuregen/featuregen.py b/misc/featuregen/featuregen.py
new file mode 100644
index 000000000..da4cc68f5
--- /dev/null
+++ b/misc/featuregen/featuregen.py
@@ -0,0 +1,116 @@
+import subprocess
+import tempfile
+import os
+import sys
+
+archs = [
+ ("amd64", "linux_amd64", "x86_64-pc-linux-gnu", [], []),
+ ("i386", "linux_i386", "i386-pc-linux-gnu", [], []),
+ ("arm32", "linux_arm32", "arm-linux-gnu", [], []),
+ ("arm64", "linux_arm64", "aarch64-linux-elf", [], []),
+ ("wasm32", "js_wasm32", "wasm32-js-js", [], []),
+ ("wasm64p32", "js_wasm64p32","wasm32-js-js", [], []),
+];
+
+SEEKING_CPUS = 0
+PARSING_CPUS = 1
+PARSING_FEATURES = 2
+
+with tempfile.NamedTemporaryFile(suffix=".odin", delete=True) as temp_file:
+ temp_file.write(b"package main\n")
+
+ for arch, target, triple, cpus, features in archs:
+ cmd = ["odin", "build", temp_file.name, "-file", "-build-mode:llvm", "-out:temp", "-target-features:\"help\"", f"-target:\"{target}\""]
+ process = subprocess.Popen(cmd, stderr=subprocess.PIPE, text=True)
+
+ state = SEEKING_CPUS
+ for line in process.stderr:
+
+ if state == SEEKING_CPUS:
+ if line == "Available CPUs for this target:\n":
+ state = PARSING_CPUS
+
+ elif state == PARSING_CPUS:
+ if line == "Available features for this target:\n":
+ state = PARSING_FEATURES
+ continue
+
+ parts = line.split(" -", maxsplit=1)
+ if len(parts) < 2:
+ continue
+
+ cpu = parts[0].strip()
+ cpus.append(cpu)
+
+ elif state == PARSING_FEATURES:
+ if line == "\n" and len(features) > 0:
+ break
+
+ parts = line.split(" -", maxsplit=1)
+ if len(parts) < 2:
+ continue
+
+ feature = parts[0].strip()
+ features.append(feature)
+
+ process.wait()
+ if process.returncode != 0:
+ print(f"odin build returned with non-zero exit code {process.returncode}")
+ sys.exit(1)
+
+ os.remove("temp.ll")
+
+def print_default_features(triple, microarch):
+ cmd = ["./featuregen", triple, microarch]
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
+ first = True
+ for line in process.stdout:
+ print("" if first else ",", line.strip(), sep="", end="")
+ first = False
+ process.wait()
+ if process.returncode != 0:
+ print(f"featuregen returned with non-zero exit code {process.returncode}")
+ sys.exit(1)
+
+print("// Generated with the featuregen script in `misc/featuregen`")
+print("gb_global String target_microarch_list[TargetArch_COUNT] = {")
+print("\t// TargetArch_Invalid:")
+print('\tstr_lit(""),')
+for arch, target, triple, cpus, features in archs:
+ print(f"\t// TargetArch_{arch}:")
+ print(f'\tstr_lit("{','.join(cpus)}"),')
+print("};")
+
+print("")
+
+print("// Generated with the featuregen script in `misc/featuregen`")
+print("gb_global String target_features_list[TargetArch_COUNT] = {")
+print("\t// TargetArch_Invalid:")
+print('\tstr_lit(""),')
+for arch, target, triple, cpus, features in archs:
+ print(f"\t// TargetArch_{arch}:")
+ print(f'\tstr_lit("{','.join(features)}"),')
+print("};")
+
+print("")
+
+print("// Generated with the featuregen script in `misc/featuregen`")
+print("gb_global int target_microarch_counts[TargetArch_COUNT] = {")
+print("\t// TargetArch_Invalid:")
+print("\t0,")
+for arch, target, triple, cpus, feature in archs:
+ print(f"\t// TargetArch_{arch}:")
+ print(f"\t{len(cpus)},")
+print("};")
+
+print("")
+
+print("// Generated with the featuregen script in `misc/featuregen`")
+print("gb_global MicroarchFeatureList microarch_features_list[] = {")
+for arch, target, triple, cpus, features in archs:
+ print(f"\t// TargetArch_{arch}:")
+ for cpu in cpus:
+ print(f'\t{{ str_lit("{cpu}"), str_lit("', end="")
+ print_default_features(triple, cpu)
+ print('") },')
+print("};")