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())