[polly] r262227 - Reapply "Add update_test.py script."

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 29 06:58:13 PST 2016


Author: meinersbur
Date: Mon Feb 29 08:58:13 2016
New Revision: 262227

URL: http://llvm.org/viewvc/llvm-project?rev=262227&view=rev
Log:
Reapply "Add update_test.py script."

Originally committed in r261899 and reverted in r262202 due to failing
in out-of-LLVM tree builds.

Replace the use of LLVM_TOOLS_BINARY_DIR by LLVM_TOOLS_DIR which exists
in both, in-tree and out-of-tree builds.

Original commit message:
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
to 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=262227&r1=262226&r2=262227&view=diff
==============================================================================
--- polly/trunk/test/CMakeLists.txt (original)
+++ polly/trunk/test/CMakeLists.txt Mon Feb 29 08:58:13 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_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=262227&view=auto
==============================================================================
--- polly/trunk/test/update_check.py (added)
+++ polly/trunk/test/update_check.py Mon Feb 29 08:58:13 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