2 # -*- coding: UTF-8 -*-
4 # Polly/LLVM update_check.py
5 # Update lit FileCheck files by replacing the 'CHECK:' lines by the actual output of the 'RUN:' command.
14 polly_src_dir
= """@POLLY_SOURCE_DIR@"""
15 polly_lib_dir
= """@POLLY_LIB_DIR@"""
16 shlibext
= """@LLVM_SHLIBEXT@"""
17 llvm_tools_dir
= """@LLVM_TOOLS_DIR@"""
18 llvm_polly_link_into_tools
= not """@LLVM_POLLY_LINK_INTO_TOOLS@""".lower() in {
26 "llvm_polly_link_into_tools-notfound",
29 runre
= re
.compile(r
"\s*\;\s*RUN\s*\:(?P<tool>.*)")
30 filecheckre
= re
.compile(r
"\s*(?P<tool>.*)\|\s*(?P<filecheck>FileCheck\s[^|]*)")
31 emptyline
= re
.compile(r
"\s*(\;\s*)?")
32 commentline
= re
.compile(r
"\s*(\;.*)?")
35 def ltrim_emptylines(lines
, meta
=None):
36 while len(lines
) and emptyline
.fullmatch(lines
[0]):
42 def rtrim_emptylines(lines
):
43 while len(lines
) and emptyline
.fullmatch(lines
[-1]):
47 def trim_emptylines(lines
):
48 ltrim_emptylines(lines
)
49 rtrim_emptylines(lines
)
52 def complete_exename(path
, filename
):
53 complpath
= os
.path
.join(path
, filename
)
54 if os
.path
.isfile(complpath
):
56 elif os
.path
.isfile(complpath
+ ".exe"):
57 return complpath
+ ".exe"
62 for i
, c
in enumerate(line
):
63 if c
!= " " and c
!= "\t":
68 def common_indent(lines
):
69 indentions
= (indention(line
) for line
in lines
)
70 indentions
= (indent
for indent
in indentions
if indent
is not None)
71 return min(indentions
, default
=0)
74 funcre
= re
.compile(r
"^ Function: \S*$")
75 regionre
= re
.compile(r
"^ Region: \S*$")
76 depthre
= re
.compile(r
"^ Max Loop Depth: .*")
77 paramre
= re
.compile(r
" [0-9a-z-A-Z_]+\: .*")
80 def classyfier1(lines
):
85 "Printing analysis 'Polly - Calculate dependences' for region: "
87 yield {"PrintingDependenceInfo"}
88 elif line
.startswith("remark: "):
90 elif funcre
.fullmatch(line
):
92 elif regionre
.fullmatch(line
):
94 elif depthre
.fullmatch(line
):
95 yield {"MaxLoopDepth"}
96 elif line
== " Invariant Accesses: {":
98 yield {"InvariantAccesses"}
102 elif line
== " Context:":
106 elif line
== " Assumed Context:":
107 yield {"AssumedContext"}
109 yield {"AssumedContext"}
110 elif line
== " Invalid Context:":
111 yield {"InvalidContext"}
113 yield {"InvalidContext"}
114 elif line
== " Boundary Context:":
115 yield {"BoundaryContext"}
117 yield {"BoundaryContext"}
119 while paramre
.fullmatch(line
):
123 elif line
== " Arrays {":
129 elif line
== " Arrays (Bounds as pw_affs) {":
131 yield {"PwAffArrays"}
135 elif line
.startswith(" Alias Groups ("):
137 yield {"AliasGroups"}
139 if not line
.startswith(" "):
142 elif line
== " Statements {":
148 elif line
== " RAW dependences:":
149 yield {"RAWDep", "BasicDep", "Dep", "DepInfo"}
151 while line
.startswith(" "):
152 yield {"RAWDep", "BasicDep", "Dep", "DepInfo"}
155 elif line
== " WAR dependences:":
156 yield {"WARDep", "BasicDep", "Dep", "DepInfo"}
158 while line
.startswith(" "):
159 yield {"WARDep", "BasicDep", "Dep", "DepInfo"}
162 elif line
== " WAW dependences:":
163 yield {"WAWDep", "BasicDep", "Dep", "DepInfo"}
165 while line
.startswith(" "):
166 yield {"WAWDep", "BasicDep", "Dep", "DepInfo"}
169 elif line
== " Reduction dependences:":
170 yield {"RedDep", "Dep", "DepInfo"}
172 while line
.startswith(" "):
173 yield {"RedDep", "Dep", "DepInfo"}
176 elif line
== " Transitive closure of reduction dependences:":
177 yield {"TransitiveClosureDep", "DepInfo"}
179 while line
.startswith(" "):
180 yield {"TransitiveClosureDep", "DepInfo"}
183 elif line
.startswith("New access function '"):
184 yield {"NewAccessFunction"}
185 elif line
== "Schedule before flattening {":
187 yield {"ScheduleBeforeFlattening"}
191 elif line
== "Schedule after flattening {":
193 yield {"ScheduleAfterFlattening"}
202 def classyfier2(lines
):
206 if funcre
.fullmatch(line
):
207 while line
.startswith(" "):
208 yield {"FunctionDetail"}
211 elif line
.startswith(
212 "Printing analysis 'Polly - Generate an AST from the SCoP (isl)' for region: "
214 yield {"PrintingIslAst"}
216 while not line
.startswith("Printing analysis"):
231 replre
= re
.compile("|".join(re
.escape(k
) for k
in replrepl
.keys()))
235 parser
= argparse
.ArgumentParser(description
="Update CHECK lines")
237 "testfile", help="File to update (absolute or relative to --testdir)"
241 choices
=["CHECK", "CHECK-NEXT"],
242 default
="CHECK-NEXT",
243 help="What kind of checks lines to generate",
247 choices
=["end", "before-content", "autodetect"],
248 default
="autodetect",
249 help="Where to add the CHECK lines into the file; 'autodetect' searches for the first 'CHECK' line ind inserts it there",
255 help="What parts of the output lines to check; use syntax 'CHECK=include' to apply to one CHECK-prefix only (by default, everything)",
258 "--check-label-include",
261 help="Use CHECK-LABEL for these includes",
264 "--check-part-newline",
266 help="Add empty line between different check parts",
272 help="Update only these prefixes (default: all)",
274 parser
.add_argument("--bindir", help="Location of the opt program")
275 parser
.add_argument("--testdir", help="Root dir for unit tests")
277 "--inplace", "-i", action
="store_true", help="Replace input file"
279 parser
.add_argument("--output", "-o", help="Write changed input to this file")
280 known
= parser
.parse_args()
282 if not known
.inplace
and known
.output
is None:
283 print("Must specify what to do with output (--output or --inplace)")
285 if known
.inplace
and known
.output
is not None:
286 print("--inplace and --output are mutually exclusive")
289 outfile
= known
.output
291 filecheckparser
= argparse
.ArgumentParser(add_help
=False)
292 filecheckparser
.add_argument("-check-prefix", "--check-prefix", default
="CHECK")
294 filename
= known
.testfile
295 for dir in [".", known
.testdir
, os
.path
.join(polly_src_dir
, "test"), polly_src_dir
]:
298 testfilename
= os
.path
.join(dir, filename
)
299 if os
.path
.isfile(testfilename
):
300 filename
= testfilename
309 with
open(filename
, "r") as file:
310 oldlines
= [line
.rstrip("\r\n") for line
in file.readlines()]
313 for line
in oldlines
:
314 m
= runre
.match(line
)
316 runlines
.append(m
.group("tool"))
320 for line
in runlines
:
321 if line
.endswith("\\"):
322 continuation
+= line
[:-2] + " "
324 newrunlines
.append(continuation
+ line
)
327 newrunlines
.append(continuation
)
329 for line
in newrunlines
:
330 m
= filecheckre
.match(line
)
334 tool
, filecheck
= m
.group("tool", "filecheck")
335 filecheck
= shlex
.split(filecheck
)
336 tool
= shlex
.split(tool
)
337 if known
.bindir
is not None:
338 tool
[0] = complete_exename(known
.bindir
, tool
[0])
339 if os
.path
.isdir(llvm_tools_dir
):
340 tool
[0] = complete_exename(llvm_tools_dir
, tool
[0])
341 check_prefix
= filecheckparser
.parse_known_args(filecheck
)[0].check_prefix
342 if known
.prefix_only
is not None and not check_prefix
in known
.prefix_only
:
344 if check_prefix
in checkprefixes
:
346 checkprefixes
.append(check_prefix
)
351 toolarg
= toolarg
.replace("%s", filename
)
352 toolarg
= toolarg
.replace("%S", os
.path
.dirname(filename
))
353 if toolarg
== "%loadPolly":
354 if not llvm_polly_link_into_tools
:
357 os
.path
.join(polly_lib_dir
, "LLVMPolly" + shlibext
),
359 newtool
.append("-polly-process-unprofitable")
360 newtool
.append("-polly-remarks-minimal")
361 elif toolarg
== "2>&1":
362 optstderr
= subprocess
.STDOUT
364 newtool
.append(toolarg
)
371 inpfile
= tool
[i
+ 1]
376 with
open(inpfile
) as inp
:
377 retlines
= subprocess
.check_output(
378 tool
, universal_newlines
=True, stdin
=inp
, stderr
=optstderr
381 retlines
= subprocess
.check_output(
382 tool
, universal_newlines
=True, stderr
=optstderr
384 retlines
= [line
.replace("\t", " ") for line
in retlines
.splitlines()]
386 for checkme
in known
.check_include
+ known
.check_label_include
:
387 parts
= checkme
.split("=")
389 if parts
[0] == check_prefix
:
390 check_include
.append(parts
[1])
392 check_include
.append(checkme
)
395 filtered_retlines
= []
396 classified_retlines
= []
399 (line
, class1
.union(class2
))
400 for line
, class1
, class2
in zip(
401 retlines
, classyfier1(retlines
), classyfier2(retlines
)
404 match
= kind
.intersection(check_include
)
406 if lastmatch
!= match
:
407 filtered_retlines
.append("")
408 classified_retlines
.append({"Separator"})
409 filtered_retlines
.append(line
)
410 classified_retlines
.append(kind
)
413 retlines
= filtered_retlines
415 classified_retlines
= (set() for line
in retlines
)
417 rtrim_emptylines(retlines
)
418 ltrim_emptylines(retlines
, classified_retlines
)
420 replre
.sub(lambda m
: replrepl
[m
.group(0)], line
) for line
in retlines
422 indent
= common_indent(retlines
)
423 retlines
= [line
[indent
:] for line
in retlines
]
425 previous_was_empty
= True
426 for line
, kind
in zip(retlines
, classified_retlines
):
428 if known
.check_style
== "CHECK" and known
.check_label_include
:
429 if not kind
.isdisjoint(known
.check_label_include
):
430 checklines
.append("; " + check_prefix
+ "-LABEL: " + line
)
432 checklines
.append("; " + check_prefix
+ ": " + line
)
433 elif known
.check_style
== "CHECK":
434 checklines
.append("; " + check_prefix
+ ": " + line
)
435 elif known
.check_label_include
and known
.check_label_include
:
436 if not kind
.isdisjoint(known
.check_label_include
):
437 checklines
.append("; " + check_prefix
+ "-LABEL: " + line
)
438 elif previous_was_empty
:
439 checklines
.append("; " + check_prefix
+ ": " + line
)
441 checklines
.append("; " + check_prefix
+ "-NEXT: " + line
)
443 if previous_was_empty
:
444 checklines
.append("; " + check_prefix
+ ": " + line
)
446 checklines
.append("; " + check_prefix
+ "-NEXT: " + line
)
447 previous_was_empty
= False
449 if not "Separator" in kind
or known
.check_part_newline
:
450 checklines
.append(";")
451 previous_was_empty
= True
452 allchecklines
.append(checklines
)
454 if not checkprefixes
:
457 checkre
= re
.compile(
459 + "|".join([re
.escape(s
) for s
in checkprefixes
])
460 + r
")(\-NEXT|\-DAG|\-NOT|\-LABEL|\-SAME)?\s*\:"
462 firstcheckline
= None
463 firstnoncommentline
= None
469 for line
in oldlines
:
470 if checkre
.match(line
):
471 if firstcheckline
is None:
472 firstcheckline
= len(newlines
) + len(emptylines
)
474 uptonowlines
+= emptylines
477 elif emptyline
.fullmatch(line
):
478 emptylines
.append(line
)
480 newlines
+= uptonowlines
481 newlines
+= emptylines
482 newlines
.append(line
)
487 for i
, line
in enumerate(newlines
):
488 if not commentline
.fullmatch(line
):
489 firstnoncommentline
= i
492 with
open(outfile
, "w", newline
="") as file:
494 def writelines(lines
):
499 if firstcheckline
is not None and known
.check_position
== "autodetect":
500 writelines(newlines
[:firstcheckline
])
501 writelines(uptonowlines
)
502 for i
, checklines
in enumerate(allchecklines
):
505 writelines(checklines
)
506 writelines(newlines
[firstcheckline
:])
507 writelines(emptylines
)
509 firstnoncommentline
is not None and known
.check_position
== "before-content"
511 headerlines
= newlines
[:firstnoncommentline
]
512 rtrim_emptylines(headerlines
)
513 contentlines
= newlines
[firstnoncommentline
:]
514 ltrim_emptylines(contentlines
)
516 writelines(headerlines
)
517 for checklines
in allchecklines
:
519 writelines(checklines
)
521 writelines(contentlines
)
522 writelines(uptonowlines
)
523 writelines(emptylines
)
526 rtrim_emptylines(newlines
)
527 for checklines
in allchecklines
:
529 writelines(checklines
)
532 if __name__
== "__main__":