about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2022-05-03 18:59:04 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2022-05-03 18:59:04 +0200
commitaf9149a1c6b9f69137951fd385d912a8ddbb7c84 (patch)
tree835f9e2d422eb43befd4cc5e732b17073704eee6
parent035ac03521cd65bd9b5daf1128a0a3f67b939478 (diff)
downloadrust-af9149a1c6b9f69137951fd385d912a8ddbb7c84.tar.gz
rust-af9149a1c6b9f69137951fd385d912a8ddbb7c84.zip
Add tool to generate intrinsics conversion automatically
-rw-r--r--.gitignore1
-rw-r--r--tools/generate_intrinsics.py119
2 files changed, 120 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 0b611d05b5c..ba11981a5e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@ res
 test-backend
 gcc_path
 benchmarks
+tools/llvm-project
diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py
new file mode 100644
index 00000000000..587db3679ef
--- /dev/null
+++ b/tools/generate_intrinsics.py
@@ -0,0 +1,119 @@
+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())