rust/tools/generate_intrinsics.py

120 lines
4.0 KiB
Python

import os
import re
import sys
import subprocess
from os import walk
LLVM_PATH = llvm_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"llvm-project",
)
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_llvm_repository():
if os.path.exists(LLVM_PATH):
while True:
choice = input("There is already a llvm-project folder, do you want to update it? [y/N]")
if choice == "" or choice.lower() == "n":
print("Skipping repository update.")
return
elif choice.lower() == "y":
print("Updating repository...")
run_command(["git", "pull", "origin"], cwd="llvm-project")
return
else:
print("Didn't understand answer...")
print("Cloning LLVM repository...")
run_command(["git", "clone", "https://github.com/llvm/llvm-project", "--depth", "1", LLVM_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():
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():
# First, we clone the LLVM repository if it's not already here.
clone_llvm_repository()
update_intrinsics()
if __name__ == "__main__":
sys.exit(main())