+++ /dev/null
-#! /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()