about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2022-05-03 21:24:14 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2022-05-03 21:24:14 +0200
commit19d8617330a481dc2a0cea149f5d75c7ed3d3203 (patch)
treee8fe8da02023a6cc27e691086830f763372ef2ff
parented0ba311c5da68edfd132c2e4f40d25f0ec24768 (diff)
downloadrust-19d8617330a481dc2a0cea149f5d75c7ed3d3203.tar.gz
rust-19d8617330a481dc2a0cea149f5d75c7ed3d3203.zip
Generate intrinsics translations from llvmint as well
-rw-r--r--.gitignore1
-rw-r--r--tools/generate_intrinsics.py97
2 files changed, 91 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index ba11981a5e3..ffd36ddb7db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ test-backend
 gcc_path
 benchmarks
 tools/llvm-project
+tools/llvmint
diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py
index 069611e60eb..88b8b54b6ba 100644
--- a/tools/generate_intrinsics.py
+++ b/tools/generate_intrinsics.py
@@ -1,3 +1,4 @@
+import json
 import os
 import re
 import sys
@@ -35,6 +36,10 @@ def clone_repository(repo_name, path, repo_url, sub_path=None):
         run_command(["git", "checkout"], cwd=path)
 
 
+def append_intrinsic(array, intrinsic_name, translation):
+    array.append((intrinsic_name, translation))
+
+
 def extract_instrinsics(intrinsics, file):
     print("Extracting intrinsics from `{}`...".format(file))
     with open(file, "r", encoding="utf8") as f:
@@ -70,25 +75,85 @@ def extract_instrinsics(intrinsics, file):
                 if current_arch not in intrinsics:
                     intrinsics[current_arch] = []
                 for entry in entries:
-                    intrinsics[current_arch].append('"{}" => "{}",'.format(intrinsic, entry))
+                    append_intrinsic(intrinsics[current_arch], intrinsic, entry)
             continue
         pos += 1
         continue
     print("Done!")
 
 
-def update_intrinsics(llvm_path):
+def extract_instrinsics_from_llvm(llvm_path, 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)
 
+
+def append_translation(json_data, p, array):
+    it = json_data["index"][p]
+    content = it["docs"].split('`')
+    if len(content) != 5:
+        return
+    append_intrinsic(array, content[1], content[3])
+
+
+def extract_instrinsics_from_llvmint(llvmint, intrinsics):
+    archs = [
+        "AMDGPU",
+        "aarch64",
+        "arm",
+        "cuda",
+        "hexagon",
+        "mips",
+        "nvvm",
+        "ppc",
+        "ptx",
+        "x86",
+        "xcore",
+    ]
+
+    json_file = os.path.join(llvmint, "target/doc/llvmint.json")
+    if not os.path.exists(json_file):
+        # We need to regenerate the documentation!
+        run_command(
+            ["cargo", "rustdoc", "--", "-Zunstable-options", "--output-format", "json"],
+            cwd=llvmint,
+        )
+    with open(json_file, "r", encoding="utf8") as f:
+        json_data = json.loads(f.read())
+    for p in json_data["paths"]:
+        it = json_data["paths"][p]
+        if it["crate_id"] != 0:
+            # This is from an external crate.
+            continue
+        if it["kind"] != "function":
+            # We're only looking for functions.
+            continue
+        # if len(it["path"]) == 2:
+        #   # This is a "general" intrinsic, not bound to a specific arch.
+        #   append_translation(json_data, p, general)
+        #   continue
+        if len(it["path"]) != 3 or it["path"][1] not in archs:
+            continue
+        arch = it["path"][1]
+        if arch not in intrinsics:
+            intrinsics[arch] = []
+        append_translation(json_data, p, intrinsics[arch])
+
+
+def update_intrinsics(llvm_path, llvmint):
+    intrinsics = {}
+    all_intrinsics = {}
+
+    extract_instrinsics_from_llvm(llvm_path, intrinsics)
+    extract_instrinsics_from_llvmint(llvmint, intrinsics)
+
     archs = [arch for arch in intrinsics]
     archs.sort()
+
     output_file = os.path.join(
         os.path.dirname(os.path.abspath(__file__)),
         "../src/intrinsic/archs.rs",
@@ -103,8 +168,16 @@ def update_intrinsics(llvm_path):
                 continue
             intrinsics[arch].sort()
             out.write('    // {}\n'.format(arch))
-            out.write('\n'.join(['    {}'.format(x) for x in intrinsics[arch]]))
-            out.write('\n')
+            for entry in intrinsics[arch]:
+                if entry[0] in all_intrinsics:
+                    if all_intrinsics[entry[0]] == entry[1]:
+                        # This is a "full" duplicate, both the LLVM instruction and the GCC
+                        # translation are the same.
+                        continue
+                    out.write('    // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
+                else:
+                    out.write('    "{}" => "{}",\n'.format(entry[0], entry[1]))
+                    all_intrinsics[entry[0]] = entry[1]
         out.write('    _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
         out.write("}\n")
     print("Done!")
@@ -115,14 +188,24 @@ def main():
         os.path.dirname(os.path.abspath(__file__)),
         "llvm-project",
     )
+    llvmint_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "llvmint",
+    )
 
     # 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)
+        sub_path="llvm/include/llvm/IR",
+    )
+    clone_repository(
+        "llvmint",
+        llvmint_path,
+        "https://github.com/GuillaumeGomez/llvmint",
+    )
+    update_intrinsics(llvm_path, llvmint_path)
 
 
 if __name__ == "__main__":