mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-01 01:31:26 +00:00
f98ee40f4b
This is an ongoing series of commits that are reformatting our Python code. This catches the last of the python files to reformat. Since they where so few I bunched them together. Reformatting is done with `black`. If you end up having problems merging this commit because you have made changes to a python file, the best way to handle that is to run git checkout --ours <yourfile> and then reformat it with black. If you run into any problems, post to discourse about it and we will try to help. RFC Thread below: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Reviewed By: jhenderson, #libc, Mordante, sivachandra Differential Revision: https://reviews.llvm.org/D150784
529 lines
18 KiB
Python
529 lines
18 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
# Polly/LLVM update_check.py
|
|
# Update lit FileCheck files by replacing the 'CHECK:' lines by the actual output of the 'RUN:' command.
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import shlex
|
|
import re
|
|
|
|
|
|
polly_src_dir = """@POLLY_SOURCE_DIR@"""
|
|
polly_lib_dir = """@POLLY_LIB_DIR@"""
|
|
shlibext = """@LLVM_SHLIBEXT@"""
|
|
llvm_tools_dir = """@LLVM_TOOLS_DIR@"""
|
|
llvm_polly_link_into_tools = not """@LLVM_POLLY_LINK_INTO_TOOLS@""".lower() in {
|
|
"",
|
|
"0",
|
|
"n",
|
|
"no",
|
|
"off",
|
|
"false",
|
|
"notfound",
|
|
"llvm_polly_link_into_tools-notfound",
|
|
}
|
|
|
|
runre = re.compile(r"\s*\;\s*RUN\s*\:(?P<tool>.*)")
|
|
filecheckre = re.compile(r"\s*(?P<tool>.*)\|\s*(?P<filecheck>FileCheck\s[^|]*)")
|
|
emptyline = re.compile(r"\s*(\;\s*)?")
|
|
commentline = re.compile(r"\s*(\;.*)?")
|
|
|
|
|
|
def ltrim_emptylines(lines, meta=None):
|
|
while len(lines) and emptyline.fullmatch(lines[0]):
|
|
del lines[0]
|
|
if meta is not None:
|
|
del meta[0]
|
|
|
|
|
|
def rtrim_emptylines(lines):
|
|
while len(lines) and emptyline.fullmatch(lines[-1]):
|
|
del lines[-1]
|
|
|
|
|
|
def trim_emptylines(lines):
|
|
ltrim_emptylines(lines)
|
|
rtrim_emptylines(lines)
|
|
|
|
|
|
def complete_exename(path, filename):
|
|
complpath = os.path.join(path, filename)
|
|
if os.path.isfile(complpath):
|
|
return complpath
|
|
elif os.path.isfile(complpath + ".exe"):
|
|
return complpath + ".exe"
|
|
return filename
|
|
|
|
|
|
def indention(line):
|
|
for i, c in enumerate(line):
|
|
if c != " " and c != "\t":
|
|
return i
|
|
return None
|
|
|
|
|
|
def common_indent(lines):
|
|
indentions = (indention(line) for line in lines)
|
|
indentions = (indent for indent in indentions if indent is not None)
|
|
return min(indentions, default=0)
|
|
|
|
|
|
funcre = re.compile(r"^ Function: \S*$")
|
|
regionre = re.compile(r"^ Region: \S*$")
|
|
depthre = re.compile(r"^ Max Loop Depth: .*")
|
|
paramre = re.compile(r" [0-9a-z-A-Z_]+\: .*")
|
|
|
|
|
|
def classyfier1(lines):
|
|
i = iter(lines)
|
|
line = i.__next__()
|
|
while True:
|
|
if line.startswith(
|
|
"Printing analysis 'Polly - Calculate dependences' for region: "
|
|
):
|
|
yield {"PrintingDependenceInfo"}
|
|
elif line.startswith("remark: "):
|
|
yield {"Remark"}
|
|
elif funcre.fullmatch(line):
|
|
yield {"Function"}
|
|
elif regionre.fullmatch(line):
|
|
yield {"Region"}
|
|
elif depthre.fullmatch(line):
|
|
yield {"MaxLoopDepth"}
|
|
elif line == " Invariant Accesses: {":
|
|
while True:
|
|
yield {"InvariantAccesses"}
|
|
if line == " }":
|
|
break
|
|
line = i.__next__()
|
|
elif line == " Context:":
|
|
yield {"Context"}
|
|
line = i.__next__()
|
|
yield {"Context"}
|
|
elif line == " Assumed Context:":
|
|
yield {"AssumedContext"}
|
|
line = i.__next__()
|
|
yield {"AssumedContext"}
|
|
elif line == " Invalid Context:":
|
|
yield {"InvalidContext"}
|
|
line = i.__next__()
|
|
yield {"InvalidContext"}
|
|
elif line == " Boundary Context:":
|
|
yield {"BoundaryContext"}
|
|
line = i.__next__()
|
|
yield {"BoundaryContext"}
|
|
line = i.__next__()
|
|
while paramre.fullmatch(line):
|
|
yield {"Param"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line == " Arrays {":
|
|
while True:
|
|
yield {"Arrays"}
|
|
if line == " }":
|
|
break
|
|
line = i.__next__()
|
|
elif line == " Arrays (Bounds as pw_affs) {":
|
|
while True:
|
|
yield {"PwAffArrays"}
|
|
if line == " }":
|
|
break
|
|
line = i.__next__()
|
|
elif line.startswith(" Alias Groups ("):
|
|
while True:
|
|
yield {"AliasGroups"}
|
|
line = i.__next__()
|
|
if not line.startswith(" "):
|
|
break
|
|
continue
|
|
elif line == " Statements {":
|
|
while True:
|
|
yield {"Statements"}
|
|
if line == " }":
|
|
break
|
|
line = i.__next__()
|
|
elif line == " RAW dependences:":
|
|
yield {"RAWDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
while line.startswith(" "):
|
|
yield {"RAWDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line == " WAR dependences:":
|
|
yield {"WARDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
while line.startswith(" "):
|
|
yield {"WARDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line == " WAW dependences:":
|
|
yield {"WAWDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
while line.startswith(" "):
|
|
yield {"WAWDep", "BasicDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line == " Reduction dependences:":
|
|
yield {"RedDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
while line.startswith(" "):
|
|
yield {"RedDep", "Dep", "DepInfo"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line == " Transitive closure of reduction dependences:":
|
|
yield {"TransitiveClosureDep", "DepInfo"}
|
|
line = i.__next__()
|
|
while line.startswith(" "):
|
|
yield {"TransitiveClosureDep", "DepInfo"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line.startswith("New access function '"):
|
|
yield {"NewAccessFunction"}
|
|
elif line == "Schedule before flattening {":
|
|
while True:
|
|
yield {"ScheduleBeforeFlattening"}
|
|
if line == "}":
|
|
break
|
|
line = i.__next__()
|
|
elif line == "Schedule after flattening {":
|
|
while True:
|
|
yield {"ScheduleAfterFlattening"}
|
|
if line == "}":
|
|
break
|
|
line = i.__next__()
|
|
else:
|
|
yield set()
|
|
line = i.__next__()
|
|
|
|
|
|
def classyfier2(lines):
|
|
i = iter(lines)
|
|
line = i.__next__()
|
|
while True:
|
|
if funcre.fullmatch(line):
|
|
while line.startswith(" "):
|
|
yield {"FunctionDetail"}
|
|
line = i.__next__()
|
|
continue
|
|
elif line.startswith(
|
|
"Printing analysis 'Polly - Generate an AST from the SCoP (isl)' for region: "
|
|
):
|
|
yield {"PrintingIslAst"}
|
|
line = i.__next__()
|
|
while not line.startswith("Printing analysis"):
|
|
yield {"AstDetail"}
|
|
line = i.__next__()
|
|
continue
|
|
else:
|
|
yield set()
|
|
line = i.__next__()
|
|
|
|
|
|
replrepl = {"{{": "{{[{][{]}}", "}}": "{{[}][}]}}", "[[": "{{\[\[}}", "]]": "{{\]\]}}"}
|
|
replre = re.compile("|".join(re.escape(k) for k in replrepl.keys()))
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Update CHECK lines")
|
|
parser.add_argument(
|
|
"testfile", help="File to update (absolute or relative to --testdir)"
|
|
)
|
|
parser.add_argument(
|
|
"--check-style",
|
|
choices=["CHECK", "CHECK-NEXT"],
|
|
default="CHECK-NEXT",
|
|
help="What kind of checks lines to generate",
|
|
)
|
|
parser.add_argument(
|
|
"--check-position",
|
|
choices=["end", "before-content", "autodetect"],
|
|
default="autodetect",
|
|
help="Where to add the CHECK lines into the file; 'autodetect' searches for the first 'CHECK' line ind inserts it there",
|
|
)
|
|
parser.add_argument(
|
|
"--check-include",
|
|
action="append",
|
|
default=[],
|
|
help="What parts of the output lines to check; use syntax 'CHECK=include' to apply to one CHECK-prefix only (by default, everything)",
|
|
)
|
|
parser.add_argument(
|
|
"--check-label-include",
|
|
action="append",
|
|
default=[],
|
|
help="Use CHECK-LABEL for these includes",
|
|
)
|
|
parser.add_argument(
|
|
"--check-part-newline",
|
|
action="store_true",
|
|
help="Add empty line between different check parts",
|
|
)
|
|
parser.add_argument(
|
|
"--prefix-only",
|
|
action="append",
|
|
default=None,
|
|
help="Update only these prefixes (default: all)",
|
|
)
|
|
parser.add_argument("--bindir", help="Location of the opt program")
|
|
parser.add_argument("--testdir", help="Root dir for unit tests")
|
|
parser.add_argument(
|
|
"--inplace", "-i", action="store_true", help="Replace input file"
|
|
)
|
|
parser.add_argument("--output", "-o", help="Write changed input to this file")
|
|
known = parser.parse_args()
|
|
|
|
if not known.inplace and known.output is None:
|
|
print("Must specify what to do with output (--output or --inplace)")
|
|
exit(1)
|
|
if known.inplace and known.output is not None:
|
|
print("--inplace and --output are mutually exclusive")
|
|
exit(1)
|
|
|
|
outfile = known.output
|
|
|
|
filecheckparser = argparse.ArgumentParser(add_help=False)
|
|
filecheckparser.add_argument("-check-prefix", "--check-prefix", default="CHECK")
|
|
|
|
filename = known.testfile
|
|
for dir in [".", known.testdir, os.path.join(polly_src_dir, "test"), polly_src_dir]:
|
|
if not dir:
|
|
continue
|
|
testfilename = os.path.join(dir, filename)
|
|
if os.path.isfile(testfilename):
|
|
filename = testfilename
|
|
break
|
|
|
|
if known.inplace:
|
|
outfile = filename
|
|
|
|
allchecklines = []
|
|
checkprefixes = []
|
|
|
|
with open(filename, "r") as file:
|
|
oldlines = [line.rstrip("\r\n") for line in file.readlines()]
|
|
|
|
runlines = []
|
|
for line in oldlines:
|
|
m = runre.match(line)
|
|
if m:
|
|
runlines.append(m.group("tool"))
|
|
|
|
continuation = ""
|
|
newrunlines = []
|
|
for line in runlines:
|
|
if line.endswith("\\"):
|
|
continuation += line[:-2] + " "
|
|
else:
|
|
newrunlines.append(continuation + line)
|
|
continuation = ""
|
|
if continuation:
|
|
newrunlines.append(continuation)
|
|
|
|
for line in newrunlines:
|
|
m = filecheckre.match(line)
|
|
if not m:
|
|
continue
|
|
|
|
tool, filecheck = m.group("tool", "filecheck")
|
|
filecheck = shlex.split(filecheck)
|
|
tool = shlex.split(tool)
|
|
if known.bindir is not None:
|
|
tool[0] = complete_exename(known.bindir, tool[0])
|
|
if os.path.isdir(llvm_tools_dir):
|
|
tool[0] = complete_exename(llvm_tools_dir, tool[0])
|
|
check_prefix = filecheckparser.parse_known_args(filecheck)[0].check_prefix
|
|
if known.prefix_only is not None and not check_prefix in known.prefix_only:
|
|
continue
|
|
if check_prefix in checkprefixes:
|
|
continue
|
|
checkprefixes.append(check_prefix)
|
|
|
|
newtool = []
|
|
optstderr = None
|
|
for toolarg in tool:
|
|
toolarg = toolarg.replace("%s", filename)
|
|
toolarg = toolarg.replace("%S", os.path.dirname(filename))
|
|
if toolarg == "%loadPolly":
|
|
if not llvm_polly_link_into_tools:
|
|
newtool += [
|
|
"-load",
|
|
os.path.join(polly_lib_dir, "LLVMPolly" + shlibext),
|
|
]
|
|
newtool.append("-polly-process-unprofitable")
|
|
newtool.append("-polly-remarks-minimal")
|
|
elif toolarg == "2>&1":
|
|
optstderr = subprocess.STDOUT
|
|
else:
|
|
newtool.append(toolarg)
|
|
tool = newtool
|
|
|
|
inpfile = None
|
|
i = 1
|
|
while i < len(tool):
|
|
if tool[i] == "<":
|
|
inpfile = tool[i + 1]
|
|
del tool[i : i + 2]
|
|
continue
|
|
i += 1
|
|
if inpfile:
|
|
with open(inpfile) as inp:
|
|
retlines = subprocess.check_output(
|
|
tool, universal_newlines=True, stdin=inp, stderr=optstderr
|
|
)
|
|
else:
|
|
retlines = subprocess.check_output(
|
|
tool, universal_newlines=True, stderr=optstderr
|
|
)
|
|
retlines = [line.replace("\t", " ") for line in retlines.splitlines()]
|
|
check_include = []
|
|
for checkme in known.check_include + known.check_label_include:
|
|
parts = checkme.split("=")
|
|
if len(parts) == 2:
|
|
if parts[0] == check_prefix:
|
|
check_include.append(parts[1])
|
|
else:
|
|
check_include.append(checkme)
|
|
|
|
if check_include:
|
|
filtered_retlines = []
|
|
classified_retlines = []
|
|
lastmatch = None
|
|
for line, kind in (
|
|
(line, class1.union(class2))
|
|
for line, class1, class2 in zip(
|
|
retlines, classyfier1(retlines), classyfier2(retlines)
|
|
)
|
|
):
|
|
match = kind.intersection(check_include)
|
|
if match:
|
|
if lastmatch != match:
|
|
filtered_retlines.append("")
|
|
classified_retlines.append({"Separator"})
|
|
filtered_retlines.append(line)
|
|
classified_retlines.append(kind)
|
|
lastmatch = match
|
|
|
|
retlines = filtered_retlines
|
|
else:
|
|
classified_retlines = (set() for line in retlines)
|
|
|
|
rtrim_emptylines(retlines)
|
|
ltrim_emptylines(retlines, classified_retlines)
|
|
retlines = [
|
|
replre.sub(lambda m: replrepl[m.group(0)], line) for line in retlines
|
|
]
|
|
indent = common_indent(retlines)
|
|
retlines = [line[indent:] for line in retlines]
|
|
checklines = []
|
|
previous_was_empty = True
|
|
for line, kind in zip(retlines, classified_retlines):
|
|
if line:
|
|
if known.check_style == "CHECK" and known.check_label_include:
|
|
if not kind.isdisjoint(known.check_label_include):
|
|
checklines.append("; " + check_prefix + "-LABEL: " + line)
|
|
else:
|
|
checklines.append("; " + check_prefix + ": " + line)
|
|
elif known.check_style == "CHECK":
|
|
checklines.append("; " + check_prefix + ": " + line)
|
|
elif known.check_label_include and known.check_label_include:
|
|
if not kind.isdisjoint(known.check_label_include):
|
|
checklines.append("; " + check_prefix + "-LABEL: " + line)
|
|
elif previous_was_empty:
|
|
checklines.append("; " + check_prefix + ": " + line)
|
|
else:
|
|
checklines.append("; " + check_prefix + "-NEXT: " + line)
|
|
else:
|
|
if previous_was_empty:
|
|
checklines.append("; " + check_prefix + ": " + line)
|
|
else:
|
|
checklines.append("; " + check_prefix + "-NEXT: " + line)
|
|
previous_was_empty = False
|
|
else:
|
|
if not "Separator" in kind or known.check_part_newline:
|
|
checklines.append(";")
|
|
previous_was_empty = True
|
|
allchecklines.append(checklines)
|
|
|
|
if not checkprefixes:
|
|
return
|
|
|
|
checkre = re.compile(
|
|
r"^\s*\;\s*("
|
|
+ "|".join([re.escape(s) for s in checkprefixes])
|
|
+ ")(\-NEXT|\-DAG|\-NOT|\-LABEL|\-SAME)?\s*\:"
|
|
)
|
|
firstcheckline = None
|
|
firstnoncommentline = None
|
|
headerlines = []
|
|
newlines = []
|
|
uptonowlines = []
|
|
emptylines = []
|
|
lastwascheck = False
|
|
for line in oldlines:
|
|
if checkre.match(line):
|
|
if firstcheckline is None:
|
|
firstcheckline = len(newlines) + len(emptylines)
|
|
if not lastwascheck:
|
|
uptonowlines += emptylines
|
|
emptylines = []
|
|
lastwascheck = True
|
|
elif emptyline.fullmatch(line):
|
|
emptylines.append(line)
|
|
else:
|
|
newlines += uptonowlines
|
|
newlines += emptylines
|
|
newlines.append(line)
|
|
emptylines = []
|
|
uptonowlines = []
|
|
lastwascheck = False
|
|
|
|
for i, line in enumerate(newlines):
|
|
if not commentline.fullmatch(line):
|
|
firstnoncommentline = i
|
|
break
|
|
|
|
with open(outfile, "w", newline="") as file:
|
|
|
|
def writelines(lines):
|
|
for line in lines:
|
|
file.write(line)
|
|
file.write("\n")
|
|
|
|
if firstcheckline is not None and known.check_position == "autodetect":
|
|
writelines(newlines[:firstcheckline])
|
|
writelines(uptonowlines)
|
|
for i, checklines in enumerate(allchecklines):
|
|
if i != 0:
|
|
file.write("\n")
|
|
writelines(checklines)
|
|
writelines(newlines[firstcheckline:])
|
|
writelines(emptylines)
|
|
elif (
|
|
firstnoncommentline is not None and known.check_position == "before-content"
|
|
):
|
|
headerlines = newlines[:firstnoncommentline]
|
|
rtrim_emptylines(headerlines)
|
|
contentlines = newlines[firstnoncommentline:]
|
|
ltrim_emptylines(contentlines)
|
|
|
|
writelines(headerlines)
|
|
for checklines in allchecklines:
|
|
file.write("\n")
|
|
writelines(checklines)
|
|
file.write("\n")
|
|
writelines(contentlines)
|
|
writelines(uptonowlines)
|
|
writelines(emptylines)
|
|
else:
|
|
writelines(newlines)
|
|
rtrim_emptylines(newlines)
|
|
for checklines in allchecklines:
|
|
file.write("\n\n")
|
|
writelines(checklines)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|