common.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from __future__ import print_function
  2. import re
  3. import string
  4. import subprocess
  5. import sys
  6. import copy
  7. if sys.version_info[0] > 2:
  8. class string:
  9. expandtabs = str.expandtabs
  10. else:
  11. import string
  12. ##### Common utilities for update_*test_checks.py
  13. def should_add_line_to_output(input_line, prefix_set):
  14. # Skip any blank comment lines in the IR.
  15. if input_line.strip() == ';':
  16. return False
  17. # Skip any blank lines in the IR.
  18. #if input_line.strip() == '':
  19. # return False
  20. # And skip any CHECK lines. We're building our own.
  21. m = CHECK_RE.match(input_line)
  22. if m and m.group(1) in prefix_set:
  23. return False
  24. return True
  25. # Invoke the tool that is being tested.
  26. def invoke_tool(exe, cmd_args, ir):
  27. with open(ir) as ir_file:
  28. # TODO Remove the str form which is used by update_test_checks.py and
  29. # update_llc_test_checks.py
  30. # The safer list form is used by update_cc_test_checks.py
  31. if isinstance(cmd_args, list):
  32. stdout = subprocess.check_output([exe] + cmd_args, stdin=ir_file)
  33. else:
  34. stdout = subprocess.check_output(exe + ' ' + cmd_args,
  35. shell=True, stdin=ir_file)
  36. if sys.version_info[0] > 2:
  37. stdout = stdout.decode()
  38. # Fix line endings to unix CR style.
  39. return stdout.replace('\r\n', '\n')
  40. ##### LLVM IR parser
  41. RUN_LINE_RE = re.compile('^\s*[;#]\s*RUN:\s*(.*)$')
  42. CHECK_PREFIX_RE = re.compile('--?check-prefix(?:es)?[= ](\S+)')
  43. CHECK_RE = re.compile(r'^\s*[;#]\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
  44. OPT_FUNCTION_RE = re.compile(
  45. r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w-]+?)\s*\('
  46. r'(\s+)?[^)]*[^{]*\{\n(?P<body>.*?)^\}$',
  47. flags=(re.M | re.S))
  48. ANALYZE_FUNCTION_RE = re.compile(
  49. r'^\s*\'(?P<analysis>[\w\s-]+?)\'\s+for\s+function\s+\'(?P<func>[\w-]+?)\':'
  50. r'\s*\n(?P<body>.*)$',
  51. flags=(re.X | re.S))
  52. IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(')
  53. TRIPLE_IR_RE = re.compile(r'^\s*target\s+triple\s*=\s*"([^"]+)"$')
  54. TRIPLE_ARG_RE = re.compile(r'-mtriple[= ]([^ ]+)')
  55. MARCH_ARG_RE = re.compile(r'-march[= ]([^ ]+)')
  56. SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
  57. SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
  58. SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
  59. SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
  60. SCRUB_LOOP_COMMENT_RE = re.compile(
  61. r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
  62. def scrub_body(body):
  63. # Scrub runs of whitespace out of the assembly, but leave the leading
  64. # whitespace in place.
  65. body = SCRUB_WHITESPACE_RE.sub(r' ', body)
  66. # Expand the tabs used for indentation.
  67. body = string.expandtabs(body, 2)
  68. # Strip trailing whitespace.
  69. body = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body)
  70. return body
  71. def do_scrub(body, scrubber, scrubber_args, extra):
  72. if scrubber_args:
  73. local_args = copy.deepcopy(scrubber_args)
  74. local_args[0].extra_scrub = extra
  75. return scrubber(body, *local_args)
  76. return scrubber(body, *scrubber_args)
  77. # Build up a dictionary of all the function bodies.
  78. class function_body(object):
  79. def __init__(self, string, extra):
  80. self.scrub = string
  81. self.extrascrub = extra
  82. def __str__(self):
  83. return self.scrub
  84. def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose):
  85. for m in function_re.finditer(raw_tool_output):
  86. if not m:
  87. continue
  88. func = m.group('func')
  89. body = m.group('body')
  90. scrubbed_body = do_scrub(body, scrubber, scrubber_args, extra = False)
  91. scrubbed_extra = do_scrub(body, scrubber, scrubber_args, extra = True)
  92. if m.groupdict().has_key('analysis'):
  93. analysis = m.group('analysis')
  94. if analysis.lower() != 'cost model analysis':
  95. print('WARNING: Unsupported analysis mode: %r!' % (analysis,), file=sys.stderr)
  96. if func.startswith('stress'):
  97. # We only use the last line of the function body for stress tests.
  98. scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
  99. if verbose:
  100. print('Processing function: ' + func, file=sys.stderr)
  101. for l in scrubbed_body.splitlines():
  102. print(' ' + l, file=sys.stderr)
  103. for prefix in prefixes:
  104. if func in func_dict[prefix] and str(func_dict[prefix][func]) != scrubbed_body:
  105. if func_dict[prefix][func] and func_dict[prefix][func].extrascrub == scrubbed_extra:
  106. func_dict[prefix][func].scrub = scrubbed_extra
  107. continue
  108. else:
  109. if prefix == prefixes[-1]:
  110. print('WARNING: Found conflicting asm under the '
  111. 'same prefix: %r!' % (prefix,), file=sys.stderr)
  112. else:
  113. func_dict[prefix][func] = None
  114. continue
  115. func_dict[prefix][func] = function_body(scrubbed_body, scrubbed_extra)
  116. ##### Generator of LLVM IR CHECK lines
  117. SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*')
  118. # Match things that look at identifiers, but only if they are followed by
  119. # spaces, commas, paren, or end of the string
  120. IR_VALUE_RE = re.compile(r'(\s+)%([\w\.\-]+?)([,\s\(\)]|\Z)')
  121. # Create a FileCheck variable name based on an IR name.
  122. def get_value_name(var):
  123. if var.isdigit():
  124. var = 'TMP' + var
  125. var = var.replace('.', '_')
  126. var = var.replace('-', '_')
  127. return var.upper()
  128. # Create a FileCheck variable from regex.
  129. def get_value_definition(var):
  130. return '[[' + get_value_name(var) + ':%.*]]'
  131. # Use a FileCheck variable.
  132. def get_value_use(var):
  133. return '[[' + get_value_name(var) + ']]'
  134. # Replace IR value defs and uses with FileCheck variables.
  135. def genericize_check_lines(lines, is_analyze):
  136. # This gets called for each match that occurs in
  137. # a line. We transform variables we haven't seen
  138. # into defs, and variables we have seen into uses.
  139. def transform_line_vars(match):
  140. var = match.group(2)
  141. if var in vars_seen:
  142. rv = get_value_use(var)
  143. else:
  144. vars_seen.add(var)
  145. rv = get_value_definition(var)
  146. # re.sub replaces the entire regex match
  147. # with whatever you return, so we have
  148. # to make sure to hand it back everything
  149. # including the commas and spaces.
  150. return match.group(1) + rv + match.group(3)
  151. vars_seen = set()
  152. lines_with_def = []
  153. for i, line in enumerate(lines):
  154. # An IR variable named '%.' matches the FileCheck regex string.
  155. line = line.replace('%.', '%dot')
  156. # Ignore any comments, since the check lines will too.
  157. scrubbed_line = SCRUB_IR_COMMENT_RE.sub(r'', line)
  158. if is_analyze == False:
  159. lines[i] = IR_VALUE_RE.sub(transform_line_vars, scrubbed_line)
  160. else:
  161. lines[i] = scrubbed_line
  162. return lines
  163. def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_asm, is_analyze):
  164. printed_prefixes = []
  165. for p in prefix_list:
  166. checkprefixes = p[0]
  167. for checkprefix in checkprefixes:
  168. if checkprefix in printed_prefixes:
  169. break
  170. # TODO func_dict[checkprefix] may be None, '' or not exist.
  171. # Fix the call sites.
  172. if func_name not in func_dict[checkprefix] or not func_dict[checkprefix][func_name]:
  173. continue
  174. # Add some space between different check prefixes, but not after the last
  175. # check line (before the test code).
  176. if is_asm == True:
  177. if len(printed_prefixes) != 0:
  178. output_lines.append(comment_marker)
  179. printed_prefixes.append(checkprefix)
  180. output_lines.append(check_label_format % (checkprefix, func_name))
  181. func_body = str(func_dict[checkprefix][func_name]).splitlines()
  182. # For ASM output, just emit the check lines.
  183. if is_asm == True:
  184. output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0]))
  185. for func_line in func_body[1:]:
  186. output_lines.append('%s %s-NEXT: %s' % (comment_marker, checkprefix, func_line))
  187. break
  188. # For IR output, change all defs to FileCheck variables, so we're immune
  189. # to variable naming fashions.
  190. func_body = genericize_check_lines(func_body, is_analyze)
  191. # This could be selectively enabled with an optional invocation argument.
  192. # Disabled for now: better to check everything. Be safe rather than sorry.
  193. # Handle the first line of the function body as a special case because
  194. # it's often just noise (a useless asm comment or entry label).
  195. #if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
  196. # is_blank_line = True
  197. #else:
  198. # output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0]))
  199. # is_blank_line = False
  200. is_blank_line = False
  201. for func_line in func_body:
  202. if func_line.strip() == '':
  203. is_blank_line = True
  204. continue
  205. # Do not waste time checking IR comments.
  206. func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line)
  207. # Skip blank lines instead of checking them.
  208. if is_blank_line == True:
  209. output_lines.append('{} {}: {}'.format(
  210. comment_marker, checkprefix, func_line))
  211. else:
  212. output_lines.append('{} {}-NEXT: {}'.format(
  213. comment_marker, checkprefix, func_line))
  214. is_blank_line = False
  215. # Add space between different check prefixes and also before the first
  216. # line of code in the test function.
  217. output_lines.append(comment_marker)
  218. break
  219. def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict, func_name):
  220. # Label format is based on IR string.
  221. check_label_format = '{} %s-LABEL: @%s('.format(comment_marker)
  222. add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, False, False)
  223. def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name):
  224. check_label_format = '{} %s-LABEL: \'%s\''.format(comment_marker)
  225. add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, False, True)