Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 9d2ff10

Browse files
author
Zachary Turner
committed
Resubmit "[lit] Refactor out some more common lit configuration code."
There were two issues, one Python 3 specific related to Unicode, and another which is that the tool substitution for lld no longer rejected matches where a / preceded the tool name. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313928 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 5b21104 commit 9d2ff10

File tree

4 files changed

+173
-111
lines changed

4 files changed

+173
-111
lines changed

test/lit.cfg.py

Lines changed: 30 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import lit.util
1212
import lit.formats
1313
from lit.llvm import llvm_config
14+
from lit.llvm import ToolFilter
1415

1516
# name: The name of this test suite.
1617
config.name = 'LLVM'
@@ -134,108 +135,39 @@ def get_asan_rtlib():
134135
# The regex is a pre-assertion to avoid matching a preceding
135136
# dot, hyphen, carat, or slash (.foo, -foo, etc.). Some patterns
136137
# also have a post-assertion to not match a trailing hyphen (foo-).
137-
NOJUNK = r"(?<!\.|-|\^|/|<)"
138-
139-
140-
def find_tool_substitution(pattern):
141-
# Extract the tool name from the pattern. This relies on the tool
142-
# name being surrounded by \b word match operators. If the
143-
# pattern starts with "| ", include it in the string to be
144-
# substituted.
145-
tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_]+)\\b\W*$",
146-
pattern)
147-
tool_pipe = tool_match.group(2)
148-
tool_name = tool_match.group(4)
149-
# Did the user specify the tool path + arguments? This allows things like
150-
# llvm-lit "-Dllc=llc -enable-misched -verify-machineinstrs"
151-
tool_path = lit_config.params.get(tool_name)
152-
if tool_path is None:
153-
tool_path = lit.util.which(tool_name, config.llvm_tools_dir)
154-
if tool_path is None:
155-
return tool_name, tool_path, tool_pipe
156-
if (tool_name == "llc" and
157-
'LLVM_ENABLE_MACHINE_VERIFIER' in os.environ and
158-
os.environ['LLVM_ENABLE_MACHINE_VERIFIER'] == "1"):
159-
tool_path += " -verify-machineinstrs"
160-
if (tool_name == "llvm-go"):
161-
tool_path += " go=" + config.go_executable
162-
return tool_name, tool_path, tool_pipe
163-
164-
165-
for pattern in [r"\bbugpoint\b(?!-)",
166-
NOJUNK + r"\bllc\b",
167-
r"\blli\b",
168-
r"\bllvm-ar\b",
169-
r"\bllvm-as\b",
170-
r"\bllvm-bcanalyzer\b",
171-
r"\bllvm-config\b",
172-
r"\bllvm-cov\b",
173-
r"\bllvm-cxxdump\b",
174-
r"\bllvm-cvtres\b",
175-
r"\bllvm-diff\b",
176-
r"\bllvm-dis\b",
177-
r"\bllvm-dsymutil\b",
178-
r"\bllvm-dwarfdump\b",
179-
r"\bllvm-extract\b",
180-
r"\bllvm-isel-fuzzer\b",
181-
r"\bllvm-lib\b",
182-
r"\bllvm-link\b",
183-
r"\bllvm-lto\b",
184-
r"\bllvm-lto2\b",
185-
r"\bllvm-mc\b",
186-
r"\bllvm-mcmarkup\b",
187-
r"\bllvm-modextract\b",
188-
r"\bllvm-nm\b",
189-
r"\bllvm-objcopy\b",
190-
r"\bllvm-objdump\b",
191-
r"\bllvm-pdbutil\b",
192-
r"\bllvm-profdata\b",
193-
r"\bllvm-ranlib\b",
194-
r"\bllvm-readobj\b",
195-
r"\bllvm-rtdyld\b",
196-
r"\bllvm-size\b",
197-
r"\bllvm-split\b",
198-
r"\bllvm-strings\b",
199-
r"\bllvm-tblgen\b",
200-
r"\bllvm-c-test\b",
201-
r"\bllvm-cxxfilt\b",
202-
r"\bllvm-xray\b",
203-
NOJUNK + r"\bllvm-symbolizer\b",
204-
NOJUNK + r"\bopt\b",
205-
r"\bFileCheck\b",
206-
r"\bobj2yaml\b",
207-
NOJUNK + r"\bsancov\b",
208-
NOJUNK + r"\bsanstats\b",
209-
r"\byaml2obj\b",
210-
r"\byaml-bench\b",
211-
r"\bverify-uselistorder\b",
212-
# Handle these specially as they are strings searched
213-
# for during testing.
214-
r"\| \bcount\b",
215-
r"\| \bnot\b"]:
216-
tool_name, tool_path, tool_pipe = find_tool_substitution(pattern)
217-
if not tool_path:
218-
# Warn, but still provide a substitution.
219-
lit_config.note('Did not find ' + tool_name + ' in ' + config.llvm_tools_dir)
220-
tool_path = config.llvm_tools_dir + '/' + tool_name
221-
config.substitutions.append((pattern, tool_pipe + tool_path))
138+
JUNKCHARS = r".-^/<"
139+
140+
required_tools = [
141+
'lli', 'llvm-ar', 'llvm-as', 'llvm-bcanalyzer', 'llvm-config', 'llvm-cov',
142+
'llvm-cxxdump', 'llvm-cvtres', 'llvm-diff', 'llvm-dis', 'llvm-dsymutil',
143+
'llvm-dwarfdump', 'llvm-extract', 'llvm-isel-fuzzer', 'llvm-lib',
144+
'llvm-link', 'llvm-lto', 'llvm-lto2', 'llvm-mc', 'llvm-mcmarkup',
145+
'llvm-modextract', 'llvm-nm', 'llvm-objcopy', 'llvm-objdump',
146+
'llvm-pdbutil', 'llvm-profdata', 'llvm-ranlib', 'llvm-readobj',
147+
'llvm-rtdyld', 'llvm-size', 'llvm-split', 'llvm-strings', 'llvm-tblgen',
148+
'llvm-c-test', 'llvm-cxxfilt', 'llvm-xray', 'yaml2obj', 'obj2yaml',
149+
'FileCheck', 'yaml-bench', 'verify-uselistorder',
150+
ToolFilter('bugpoint', post='-'),
151+
ToolFilter('llc', pre=JUNKCHARS),
152+
ToolFilter('llvm-symbolizer', pre=JUNKCHARS),
153+
ToolFilter('opt', JUNKCHARS),
154+
ToolFilter('sancov', pre=JUNKCHARS),
155+
ToolFilter('sanstats', pre=JUNKCHARS),
156+
# Handle these specially as they are strings searched for during testing.
157+
ToolFilter(r'\| \bcount\b', verbatim=True),
158+
ToolFilter(r'\| \bnot\b', verbatim=True)]
159+
160+
llvm_config.add_tool_substitutions(required_tools, config.llvm_tools_dir)
222161

223162
# For tools that are optional depending on the config, we won't warn
224163
# if they're missing.
225-
for pattern in [r"\bllvm-go\b",
226-
r"\bllvm-mt\b",
227-
r"\bKaleidoscope-Ch3\b",
228-
r"\bKaleidoscope-Ch4\b",
229-
r"\bKaleidoscope-Ch5\b",
230-
r"\bKaleidoscope-Ch6\b",
231-
r"\bKaleidoscope-Ch7\b",
232-
r"\bKaleidoscope-Ch8\b"]:
233-
tool_name, tool_path, tool_pipe = find_tool_substitution(pattern)
234-
if not tool_path:
235-
# Provide a substitution anyway, for the sake of consistent errors.
236-
tool_path = config.llvm_tools_dir + '/' + tool_name
237-
config.substitutions.append((pattern, tool_pipe + tool_path))
238164

165+
optional_tools = [
166+
'llvm-go', 'llvm-mt', 'Kaleidoscope-Ch3', 'Kaleidoscope-Ch4',
167+
'Kaleidoscope-Ch5', 'Kaleidoscope-Ch6', 'Kaleidoscope-Ch7',
168+
'Kaleidoscope-Ch8']
169+
llvm_config.add_tool_substitutions(optional_tools, config.llvm_tools_dir,
170+
warn_missing=False)
239171

240172
### Targets
241173

utils/lit/lit/llvm/__init__.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,51 @@
1-
21
from lit.llvm import config
2+
import lit.util
3+
import re
34

45
llvm_config = None
56

7+
class ToolFilter(object):
8+
"""
9+
String-like class used to build regex substitution patterns for
10+
llvm tools. Handles things like adding word-boundary patterns,
11+
and filtering characters from the beginning an end of a tool name
12+
"""
13+
14+
def __init__(self, name, pre=None, post=None, verbatim=False):
15+
"""
16+
Construct a ToolFilter.
17+
18+
name: the literal name of the substitution to look for.
19+
20+
pre: If specified, the substitution will not find matches where
21+
the character immediately preceding the word-boundary that begins
22+
`name` is any of the characters in the string `pre`.
23+
24+
post: If specified, the substitution will not find matches where
25+
the character immediately after the word-boundary that ends `name`
26+
is any of the characters specified in the string `post`.
27+
28+
verbatim: If True, `name` is an exact regex that is passed to the
29+
underlying substitution
30+
"""
31+
if verbatim:
32+
self.regex = name
33+
return
34+
35+
def not_in(chars, where=''):
36+
if not chars:
37+
return ''
38+
pattern_str = '|'.join(re.escape(x) for x in chars)
39+
return r'(?{}!({}))'.format(where, pattern_str)
40+
41+
self.regex = not_in(pre, '<') + r'\b' + name + r'\b' + not_in(post)
42+
43+
def __str__(self):
44+
return self.regex
45+
46+
647
def initialize(lit_config, test_config):
748
global llvm_config
49+
850
llvm_config = config.LLVMConfig(lit_config, test_config)
951

utils/lit/lit/llvm/config.py

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,22 +136,26 @@ def clear_environment(self, variables):
136136
if name in self.config.environment:
137137
del self.config.environment[name]
138138

139-
def feature_config(self, features, encoding = 'ascii'):
140-
# Ask llvm-config about the specified feature.
141-
arguments = [x for (x, _) in features]
139+
def get_process_output(self, command):
142140
try:
143-
config_path = os.path.join(self.config.llvm_tools_dir, 'llvm-config')
144-
145-
llvm_config_cmd = subprocess.Popen(
146-
[config_path] + arguments,
147-
stdout = subprocess.PIPE,
148-
env=self.config.environment)
141+
cmd = subprocess.Popen(
142+
command, stdout=subprocess.PIPE,
143+
stderr=subprocess.PIPE, env=self.config.environment)
144+
stdout, stderr = cmd.communicate()
145+
stdout = lit.util.to_string(stdout)
146+
stderr = lit.util.to_string(stderr)
147+
return (stdout, stderr)
149148
except OSError:
150-
self.lit_config.fatal("Could not find llvm-config in " + self.config.llvm_tools_dir)
149+
self.lit_config.fatal("Could not run process %s" % command)
150+
151+
def feature_config(self, features):
152+
# Ask llvm-config about the specified feature.
153+
arguments = [x for (x, _) in features]
154+
config_path = os.path.join(self.config.llvm_tools_dir, 'llvm-config')
151155

152-
output, _ = llvm_config_cmd.communicate()
153-
output = output.decode(encoding)
156+
output, _ = self.get_process_output([config_path] + arguments)
154157
lines = output.split('\n')
158+
155159
for (feature_line, (_, patterns)) in zip(lines, features):
156160
# We should have either a callable or a dictionary. If it's a
157161
# dictionary, grep each key against the output and use the value if
@@ -163,3 +167,85 @@ def feature_config(self, features, encoding = 'ascii'):
163167
for (re_pattern, feature) in patterns.items():
164168
if re.search(re_pattern, feature_line):
165169
self.config.available_features.add(feature)
170+
171+
172+
# Note that when substituting %clang_cc1 also fill in the include directory of
173+
# the builtin headers. Those are part of even a freestanding environment, but
174+
# Clang relies on the driver to locate them.
175+
def get_clang_builtin_include_dir(self, clang):
176+
# FIXME: Rather than just getting the version, we should have clang print
177+
# out its resource dir here in an easy to scrape form.
178+
clang_dir, _ = self.get_process_output([clang, '-print-file-name=include'])
179+
180+
if not clang_dir:
181+
self.lit_config.fatal("Couldn't find the include dir for Clang ('%s')" % clang)
182+
183+
clang_dir = clang_dir.strip()
184+
if sys.platform in ['win32'] and not self.use_lit_shell:
185+
# Don't pass dosish path separator to msys bash.exe.
186+
clang_dir = clang_dir.replace('\\', '/')
187+
# Ensure the result is an ascii string, across Python2.5+ - Python3.
188+
return clang_dir
189+
190+
def make_itanium_abi_triple(self, triple):
191+
m = re.match(r'(\w+)-(\w+)-(\w+)', triple)
192+
if not m:
193+
self.lit_config.fatal("Could not turn '%s' into Itanium ABI triple" % triple)
194+
if m.group(3).lower() != 'win32':
195+
# All non-win32 triples use the Itanium ABI.
196+
return triple
197+
return m.group(1) + '-' + m.group(2) + '-mingw32'
198+
199+
def make_msabi_triple(self, triple):
200+
m = re.match(r'(\w+)-(\w+)-(\w+)', triple)
201+
if not m:
202+
self.lit_config.fatal("Could not turn '%s' into MS ABI triple" % triple)
203+
isa = m.group(1).lower()
204+
vendor = m.group(2).lower()
205+
os = m.group(3).lower()
206+
if os == 'win32':
207+
# If the OS is win32, we're done.
208+
return triple
209+
if isa.startswith('x86') or isa == 'amd64' or re.match(r'i\d86', isa):
210+
# For x86 ISAs, adjust the OS.
211+
return isa + '-' + vendor + '-win32'
212+
# -win32 is not supported for non-x86 targets; use a default.
213+
return 'i686-pc-win32'
214+
215+
def add_tool_substitutions(self, tools, search_dirs, warn_missing = True):
216+
if lit.util.is_string(search_dirs):
217+
search_dirs = [search_dirs]
218+
219+
search_dirs = os.pathsep.join(search_dirs)
220+
for tool in tools:
221+
# Extract the tool name from the pattern. This relies on the tool
222+
# name being surrounded by \b word match operators. If the
223+
# pattern starts with "| ", include it in the string to be
224+
# substituted.
225+
if lit.util.is_string(tool):
226+
tool = lit.util.make_word_regex(tool)
227+
else:
228+
tool = str(tool)
229+
230+
tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_\.]+)\\b\W*$",
231+
tool)
232+
if not tool_match:
233+
continue
234+
235+
tool_pipe = tool_match.group(2)
236+
tool_name = tool_match.group(4)
237+
tool_path = lit.util.which(tool_name, search_dirs)
238+
if not tool_path:
239+
if warn_missing:
240+
# Warn, but still provide a substitution.
241+
self.lit_config.note('Did not find ' + tool_name + ' in %s' % search_dirs)
242+
tool_path = self.config.llvm_tools_dir + '/' + tool_name
243+
244+
if tool_name == 'llc' and os.environ.get('LLVM_ENABLE_MACHINE_VERIFIER') == '1':
245+
tool_path += ' -verify-machineinstrs'
246+
if tool_name == 'llvm-go':
247+
exe = getattr(self.config, 'go_executable', None)
248+
if exe:
249+
tool_path += " go=" + exe
250+
251+
self.config.substitutions.append((tool, tool_pipe + tool_path))

utils/lit/lit/util.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ def pythonize_bool(value):
3636
return False
3737
raise ValueError('"{}" is not a valid boolean'.format(value))
3838

39+
def make_word_regex(word):
40+
return r'\b' + word + r'\b'
3941

4042
def to_bytes(s):
4143
"""Return the parameter as type 'bytes', possibly encoding it.

0 commit comments

Comments
 (0)