9 def run_command(command, cwd=None):
10 p = subprocess.Popen(command, cwd=cwd)
12 print("command `{}` failed...".format(" ".join(command)))
16 def clone_repository(repo_name, path, repo_url, sub_path=None):
17 if os.path.exists(path):
19 choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
20 if choice == "" or choice.lower() == "n":
21 print("Skipping repository update.")
23 elif choice.lower() == "y":
24 print("Updating repository...")
25 run_command(["git", "pull", "origin"], cwd=path)
28 print("Didn't understand answer...")
29 print("Cloning {} repository...".format(repo_name))
31 run_command(["git", "clone", repo_url, "--depth", "1", path])
33 run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
34 run_command(["git", "sparse-checkout", "init"], cwd=path)
35 run_command(["git", "sparse-checkout", "set", "add", sub_path], cwd=path)
36 run_command(["git", "checkout"], cwd=path)
39 def append_intrinsic(array, intrinsic_name, translation):
40 array.append((intrinsic_name, translation))
43 def extract_instrinsics(intrinsics, file):
44 print("Extracting intrinsics from `{}`...".format(file))
45 with open(file, "r", encoding="utf8") as f:
48 lines = content.splitlines()
51 while pos < len(lines):
52 line = lines[pos].strip()
53 if line.startswith("let TargetPrefix ="):
54 current_arch = line.split('"')[1].strip()
55 if len(current_arch) == 0:
57 elif current_arch is None:
61 elif line.startswith("def "):
63 while not content.endswith(";") and not content.endswith("}") and pos < len(lines):
64 line = lines[pos].split(" // ")[0].strip()
67 entries = re.findall('GCCBuiltin<"(\\w+)">', content)
69 intrinsic = content.split("def ")[1].strip().split(":")[0].strip()
70 intrinsic = intrinsic.split("_")
71 if len(intrinsic) < 2 or intrinsic[0] != "int":
74 intrinsic = ".".join(intrinsic)
75 if current_arch not in intrinsics:
76 intrinsics[current_arch] = []
78 append_intrinsic(intrinsics[current_arch], intrinsic, entry)
85 def extract_instrinsics_from_llvm(llvm_path, intrinsics):
87 intrinsics_path = os.path.join(llvm_path, "llvm/include/llvm/IR")
88 for (dirpath, dirnames, filenames) in walk(intrinsics_path):
89 files.extend([os.path.join(intrinsics_path, f) for f in filenames if f.endswith(".td")])
92 extract_instrinsics(intrinsics, file)
95 def append_translation(json_data, p, array):
96 it = json_data["index"][p]
97 content = it["docs"].split('`')
100 append_intrinsic(array, content[1], content[3])
103 def extract_instrinsics_from_llvmint(llvmint, intrinsics):
118 json_file = os.path.join(llvmint, "target/doc/llvmint.json")
119 # We need to regenerate the documentation!
121 ["cargo", "rustdoc", "--", "-Zunstable-options", "--output-format", "json"],
124 with open(json_file, "r", encoding="utf8") as f:
125 json_data = json.loads(f.read())
126 for p in json_data["paths"]:
127 it = json_data["paths"][p]
128 if it["crate_id"] != 0:
129 # This is from an external crate.
131 if it["kind"] != "function":
132 # We're only looking for functions.
134 # if len(it["path"]) == 2:
135 # # This is a "general" intrinsic, not bound to a specific arch.
136 # append_translation(json_data, p, general)
138 if len(it["path"]) != 3 or it["path"][1] not in archs:
141 if arch not in intrinsics:
142 intrinsics[arch] = []
143 append_translation(json_data, p, intrinsics[arch])
146 def fill_intrinsics(intrinsics, from_intrinsics, all_intrinsics):
147 for arch in from_intrinsics:
148 if arch not in intrinsics:
149 intrinsics[arch] = []
150 for entry in from_intrinsics[arch]:
151 if entry[0] in all_intrinsics:
152 if all_intrinsics[entry[0]] == entry[1]:
153 # This is a "full" duplicate, both the LLVM instruction and the GCC
154 # translation are the same.
156 intrinsics[arch].append((entry[0], entry[1], True))
158 intrinsics[arch].append((entry[0], entry[1], False))
159 all_intrinsics[entry[0]] = entry[1]
162 def update_intrinsics(llvm_path, llvmint, llvmint2):
164 intrinsics_llvmint = {}
167 extract_instrinsics_from_llvm(llvm_path, intrinsics_llvm)
168 extract_instrinsics_from_llvmint(llvmint, intrinsics_llvmint)
169 extract_instrinsics_from_llvmint(llvmint2, intrinsics_llvmint)
172 # We give priority to translations from LLVM over the ones from llvmint.
173 fill_intrinsics(intrinsics, intrinsics_llvm, all_intrinsics)
174 fill_intrinsics(intrinsics, intrinsics_llvmint, all_intrinsics)
176 archs = [arch for arch in intrinsics]
179 output_file = os.path.join(
180 os.path.dirname(os.path.abspath(__file__)),
181 "../src/intrinsic/archs.rs",
183 print("Updating content of `{}`...".format(output_file))
184 with open(output_file, "w", encoding="utf8") as out:
185 out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
186 out.write("// DO NOT EDIT IT!\n")
187 out.write("match name {\n")
189 if len(intrinsics[arch]) == 0:
191 intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
192 out.write(' // {}\n'.format(arch))
193 for entry in intrinsics[arch]:
194 if entry[2] == True: # if it is a duplicate
195 out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
197 out.write(' "{}" => "{}",\n'.format(entry[0], entry[1]))
198 out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
204 llvm_path = os.path.join(
205 os.path.dirname(os.path.abspath(__file__)),
208 llvmint_path = os.path.join(
209 os.path.dirname(os.path.abspath(__file__)),
212 llvmint2_path = os.path.join(
213 os.path.dirname(os.path.abspath(__file__)),
217 # First, we clone the LLVM repository if it's not already here.
221 "https://github.com/llvm/llvm-project",
222 sub_path="llvm/include/llvm/IR",
227 "https://github.com/GuillaumeGomez/llvmint",
232 "https://github.com/antoyo/llvmint",
234 update_intrinsics(llvm_path, llvmint_path, llvmint2_path)
237 if __name__ == "__main__":