rust/tools/generate_intrinsics.py
2022-05-03 20:55:55 +02:00

130 lines
4.5 KiB
Python

import os
import re
import sys
import subprocess
from os import walk
def run_command(command, cwd=None):
p = subprocess.Popen(command, cwd=cwd)
if p.wait() != 0:
print("command `{}` failed...".format(" ".join(command)))
sys.exit(1)
def clone_repository(repo_name, path, repo_url, sub_path=None):
if os.path.exists(path):
while True:
choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(repo_name))
if choice == "" or choice.lower() == "n":
print("Skipping repository update.")
return
elif choice.lower() == "y":
print("Updating repository...")
run_command(["git", "pull", "origin"], cwd=path)
return
else:
print("Didn't understand answer...")
print("Cloning {} repository...".format(repo_name))
if sub_path is None:
run_command(["git", "clone", repo_url, "--depth", "1", path])
else:
run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
run_command(["git", "sparse-checkout", "init"], cwd=path)
run_command(["git", "sparse-checkout", "set", "add", sub_path], cwd=path)
run_command(["git", "checkout"], cwd=path)
def extract_instrinsics(intrinsics, file):
print("Extracting intrinsics from `{}`...".format(file))
with open(file, "r", encoding="utf8") as f:
content = f.read()
lines = content.splitlines()
pos = 0
current_arch = None
while pos < len(lines):
line = lines[pos].strip()
if line.startswith("let TargetPrefix ="):
current_arch = line.split('"')[1].strip()
if len(current_arch) == 0:
current_arch = None
elif current_arch is None:
pass
elif line == "}":
current_arch = None
elif line.startswith("def "):
content = ""
while not content.endswith(";") and pos < len(lines):
line = lines[pos].split(" // ")[0].strip()
content += line
pos += 1
entries = re.findall('GCCBuiltin<"(\\w+)">', content)
if len(entries) > 0:
intrinsic = content.split(":")[0].split(" ")[1].strip()
intrinsic = intrinsic.split("_")
if len(intrinsic) < 2 or intrinsic[0] != "int":
continue
intrinsic[0] = "llvm"
intrinsic = ".".join(intrinsic)
if current_arch not in intrinsics:
intrinsics[current_arch] = []
for entry in entries:
intrinsics[current_arch].append('"{}" => "{}",'.format(intrinsic, entry))
continue
pos += 1
continue
print("Done!")
def update_intrinsics(llvm_path):
files = []
intrinsics_path = os.path.join(llvm_path, "llvm/include/llvm/IR")
for (dirpath, dirnames, filenames) in walk(intrinsics_path):
files.extend([os.path.join(intrinsics_path, f) for f in filenames if f.endswith(".td")])
intrinsics = {}
for file in files:
extract_instrinsics(intrinsics, file)
archs = [arch for arch in intrinsics]
archs.sort()
output_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"../src/intrinsic/archs.rs",
)
print("Updating content of `{}`...".format(output_file))
with open(output_file, "w", encoding="utf8") as out:
out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
out.write("// DO NOT EDIT IT!\n")
out.write("match name {\n")
for arch in archs:
if len(intrinsics[arch]) == 0:
continue
intrinsics[arch].sort()
out.write(' // {}\n'.format(arch))
out.write('\n'.join([' {}'.format(x) for x in intrinsics[arch]]))
out.write('\n')
out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
out.write("}\n")
print("Done!")
def main():
llvm_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvm-project",
)
# First, we clone the LLVM repository if it's not already here.
clone_repository(
"llvm-project",
llvm_path,
"https://github.com/llvm/llvm-project",
sub_path="llvm/include/llvm/IR")
update_intrinsics(llvm_path)
if __name__ == "__main__":
sys.exit(main())