mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
compiler: improve target features support
This commit is contained in:
@@ -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`
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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("};")
|
||||
Reference in New Issue
Block a user