Skip to content

Commit 0df4a8f

Browse files
committed
[update_cc_test_checks.py] Use -ast-dump=json to get mangled name
Summary: Using c-index-test is fragile since it does not parse all the clang arguments that are used in the RUN: line. This can result in incorrect mangled names that do not match any of the generated IR. For example macOS triples include a leading underscore (which was handled with a hack in the current script). For the CHERI target we have added new qualifiers which affect C++ name mangling, but will be included added by update_cc_test_checks since it parses the source file with the host triple because it ignores the -triple= argument passed to clang -cc1. Using the new feature of including the mangled name in the JSON AST dump (see D69564), we can parse the output of the RUN: command with "-fsyntax-only -ast-dump=json" appended. This should make the script less fragile and also forks one process less. Reviewers: MaskRay, xbolva00 Reviewed By: MaskRay Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69565
1 parent 3c3048c commit 0df4a8f

File tree

1 file changed

+44
-51
lines changed

1 file changed

+44
-51
lines changed

llvm/utils/update_cc_test_checks.py

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
Usage:
1010
1111
% utils/update_cc_test_checks.py --llvm-bin=release/bin test/a.cc
12-
% utils/update_cc_test_checks.py --c-index-test=release/bin/c-index-test \
13-
--clang=release/bin/clang /tmp/c/a.cc
12+
% utils/update_cc_test_checks.py --clang=release/bin/clang /tmp/c/a.cc
1413
'''
1514

1615
import argparse
1716
import collections
1817
import distutils.spawn
18+
import json
1919
import os
2020
import shlex
2121
import string
@@ -38,47 +38,51 @@
3838
}
3939

4040
def get_line2spell_and_mangled(args, clang_args):
41+
def debug_mangled(*print_args, **kwargs):
42+
if args.verbose:
43+
print(*print_args, file=sys.stderr, **kwargs)
4144
ret = {}
42-
with tempfile.NamedTemporaryFile() as f:
43-
# TODO Make c-index-test print mangled names without circumventing through precompiled headers
44-
status = subprocess.run([args.c_index_test, '-write-pch', f.name, *clang_args],
45-
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
46-
if status.returncode:
47-
sys.stderr.write(status.stdout.decode())
48-
sys.exit(2)
49-
output = subprocess.check_output([args.c_index_test,
50-
'-test-print-mangle', f.name])
51-
if sys.version_info[0] > 2:
52-
output = output.decode()
53-
DeclRE = re.compile(r'^FunctionDecl=(\w+):(\d+):\d+ \(Definition\)')
54-
MangleRE = re.compile(r'.*\[mangled=([^]]+)\]')
55-
MatchedDecl = False
56-
for line in output.splitlines():
57-
# Get the function source name, line number and mangled name. Sometimes
58-
# c-index-test outputs the mangled name on a separate line (this can happen
59-
# with block comments in front of functions). Keep scanning until we see
60-
# the mangled name.
61-
decl_m = DeclRE.match(line)
62-
mangle_m = MangleRE.match(line)
63-
64-
if decl_m:
65-
MatchedDecl = True
66-
spell, lineno = decl_m.groups()
67-
if MatchedDecl and mangle_m:
68-
mangled = mangle_m.group(1)
69-
MatchedDecl = False
70-
else:
45+
# Use clang's JSON AST dump to get the mangled name
46+
json_dump_args = [args.clang, *clang_args, '-fsyntax-only', '-o', '-']
47+
if '-cc1' not in json_dump_args:
48+
# For tests that invoke %clang instead if %clang_cc1 we have to use
49+
# -Xclang -ast-dump=json instead:
50+
json_dump_args.append('-Xclang')
51+
json_dump_args.append('-ast-dump=json')
52+
debug_mangled('Running', ' '.join(json_dump_args))
53+
status = subprocess.run(json_dump_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
54+
if status.returncode != 0:
55+
sys.stderr.write('Failed to run ' + ' '.join(json_dump_args) + '\n')
56+
sys.stderr.write(status.stderr.decode())
57+
sys.stderr.write(status.stdout.decode())
58+
sys.exit(2)
59+
ast = json.loads(status.stdout.decode())
60+
if ast['kind'] != 'TranslationUnitDecl':
61+
common.error('Clang AST dump JSON format changed?')
62+
sys.exit(2)
63+
64+
# Get the inner node and iterate over all children of type FunctionDecl.
65+
# TODO: Should we add checks for global variables being emitted?
66+
for node in ast['inner']:
67+
if node['kind'] != 'FunctionDecl':
7168
continue
72-
73-
if mangled == '_' + spell:
74-
# HACK for MacOS (where the mangled name includes an _ for C but the IR won't):
75-
mangled = spell
76-
# Note -test-print-mangle does not print file names so if #include is used,
77-
# the line number may come from an included file.
78-
ret[int(lineno)-1] = (spell, mangled)
69+
if node.get('isImplicit') is True and node.get('storageClass') == 'extern':
70+
debug_mangled('Skipping builtin function:', node['name'], '@', node['loc'])
71+
continue
72+
debug_mangled('Found function:', node['kind'], node['name'], '@', node['loc'])
73+
line = node['loc'].get('line')
74+
# If there is no line it is probably a builtin function -> skip
75+
if line is None:
76+
debug_mangled('Skipping function without line number:', node['name'], '@', node['loc'])
77+
continue
78+
spell = node['name']
79+
mangled = node.get('mangledName', spell)
80+
ret[int(line)-1] = (spell, mangled)
7981
if args.verbose:
8082
for line, func_name in sorted(ret.items()):
8183
print('line {}: found function {}'.format(line+1, func_name), file=sys.stderr)
84+
if not ret:
85+
common.warn('Did not find any functions using', ' '.join(json_dump_args))
8286
return ret
8387

8488

@@ -92,8 +96,6 @@ def config():
9296
help='"clang" executable, defaults to $llvm_bin/clang')
9397
parser.add_argument('--clang-args',
9498
help='Space-separated extra args to clang, e.g. --clang-args=-v')
95-
parser.add_argument('--c-index-test',
96-
help='"c-index-test" executable, defaults to $llvm_bin/c-index-test')
9799
parser.add_argument('--opt',
98100
help='"opt" executable, defaults to $llvm_bin/opt')
99101
parser.add_argument(
@@ -140,15 +142,6 @@ def config():
140142
# defer this error message until we find that opt is actually needed.
141143
args.opt = None
142144

143-
if args.c_index_test is None:
144-
if args.llvm_bin is None:
145-
args.c_index_test = 'c-index-test'
146-
else:
147-
args.c_index_test = os.path.join(args.llvm_bin, 'c-index-test')
148-
if not distutils.spawn.find_executable(args.c_index_test):
149-
print('Please specify --llvm-bin or --c-index-test', file=sys.stderr)
150-
sys.exit(1)
151-
152145
return args
153146

154147

@@ -274,8 +267,8 @@ def main():
274267

275268
get_function_body(args, filename, clang_args, extra_commands, prefixes, triple_in_cmd, func_dict)
276269

277-
# Invoke c-index-test to get mapping from start lines to mangled names.
278-
# Forward all clang args for now.
270+
# Invoke clang -Xclang -ast-dump=json to get mapping from start lines to
271+
# mangled names. Forward all clang args for now.
279272
for k, v in get_line2spell_and_mangled(args, clang_args).items():
280273
line2spell_and_mangled_list[k].append(v)
281274

0 commit comments

Comments
 (0)