[polly] r261899 - Add update_test.py script.
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 25 09:12:12 PST 2016
Author: meinersbur
Date: Thu Feb 25 11:12:12 2016
New Revision: 261899
URL: http://llvm.org/viewvc/llvm-project?rev=261899&view=rev
Log:
Add update_test.py script.
The script updates a lit test case that uses FileCheck using the actual
output of the 'RUN:'-lines program. Useful when updating test cases due
expected output changes and diff'ing expected and actual output.
Added:
polly/trunk/test/update_check.py
Modified:
polly/trunk/test/CMakeLists.txt
Modified: polly/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/CMakeLists.txt?rev=261899&r1=261898&r2=261899&view=diff
==============================================================================
--- polly/trunk/test/CMakeLists.txt (original)
+++ polly/trunk/test/CMakeLists.txt Thu Feb 25 11:12:12 2016
@@ -95,6 +95,14 @@ configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/update_check.py
+ ${CMAKE_CURRENT_BINARY_DIR}/update_check.py)
+file(COPY ${CMAKE_CURRENT_BINARY_DIR}/update_check.py
+ DESTINATION ${LLVM_TOOLS_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
+ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+
# Add a legacy target spelling: polly-test
add_custom_target(polly-test)
set_target_properties(polly-test PROPERTIES FOLDER "Polly")
Added: polly/trunk/test/update_check.py
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/update_check.py?rev=261899&view=auto
==============================================================================
--- polly/trunk/test/update_check.py (added)
+++ polly/trunk/test/update_check.py Thu Feb 25 11:12:12 2016
@@ -0,0 +1,440 @@
+#! /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@'''
+link_polly_into_tools = not '''@LINK_POLLY_INTO_TOOLS@'''.lower() in {'','0','n','no','off','false','notfound','link_polly_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 == ' 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
+ 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 link_polly_into_tools:
+ newtool += ['-load',os.path.join(polly_lib_dir,'LLVMPolly' + shlibext)]
+ newtool.append('-polly-process-unprofitable')
+ 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()
More information about the llvm-commits
mailing list