Skip to content

Commit a2aa881

Browse files
authored
[GlobalISel] Add a update_givaluetracking_test_checks.py script (#140296)
As with the other update scripts this takes the output of -passes=print<gisel-value-tracking> and inserts the results into an existing mir file. This means that the input is a lot like update_analysis_test_checks.py, and the output needs to insert into a mir file similarly to update_mir_test_checks.py. The code used to do the inserting has been moved to common, to allow it to be reused. Otherwise it tries to reuse the existing infrastructure, and update_givaluetracking_test_checks is kept relatively short.
1 parent 213d0d2 commit a2aa881

File tree

9 files changed

+476
-239
lines changed

9 files changed

+476
-239
lines changed
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2-
# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -o - 2>&1 | FileCheck %s
1+
# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
2+
# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
33

44
---
55
name: Cst
66
tracksRegLiveness: true
77
body: |
88
bb.1:
9-
; CHECK-LABEL: name: @Cst
10-
; CHECK-NEXT: %0:_ KnownBits:00000001 SignBits:7
11-
; CHECK-NEXT: %1:_ KnownBits:00000001 SignBits:7
9+
; CHECK-LABEL: name: @Cst
10+
; CHECK-NEXT: %0:_ KnownBits:00000001 SignBits:7
11+
; CHECK-NEXT: %1:_ KnownBits:00000001 SignBits:7
1212
%0:_(s8) = G_CONSTANT i8 1
1313
%1:_(s8) = COPY %0
1414
...
1515
---
1616
name: CstWithClass
17-
# We can't analyze %0 due to the lack of an LLT. We will get a default
18-
# constructed KnownBits back. %0 will have the correct size but we will
19-
# not know any further info.
2017
tracksRegLiveness: true
2118
body: |
2219
bb.1:
23-
; CHECK-LABEL: name: @CstWithClass
24-
; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:1
20+
; We can't analyze %0 due to the lack of an LLT. We will get a default
21+
; constructed KnownBits back. %0 will have the correct size but we will
22+
; not know any further info.
23+
; CHECK-LABEL: name: @CstWithClass
24+
; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:1
2525
%0:gpr32 = MOVi32imm 1
2626
%1:_(s32) = COPY %0
2727
...

llvm/test/tools/UpdateTestChecks/lit.local.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ if os.path.isfile(llc_path):
3535
llc_arg = "--llc-binary " + shell_quote(llc_path)
3636
add_update_script_substitution("%update_llc_test_checks", extra_args=llc_arg)
3737
add_update_script_substitution("%update_mir_test_checks", extra_args=llc_arg)
38+
add_update_script_substitution("%update_givaluetracking_test_checks", extra_args=llc_arg)
3839

3940
opt_path = os.path.join(config.llvm_tools_dir, "opt")
4041
if os.path.isfile(opt_path):
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
2+
# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
3+
4+
---
5+
name: Cst
6+
body: |
7+
bb.1:
8+
%0:_(s8) = G_CONSTANT i8 1
9+
%1:_(s8) = COPY %0
10+
...
11+
---
12+
name: Test2
13+
body: |
14+
bb.1:
15+
; Note: This comment should not be removed, the check lines below should be updated
16+
; CHECK-LABEL: name: @Test2
17+
; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:1
18+
; CHECK-NEXT: %named:_ KnownBits:???????????????????????????????????????????????????????????????? SignBits:1
19+
; CHECK-NEXT: %3:_ KnownBits:???????????????????????????????? SignBits:1
20+
; CHECK-NEXT: %4:_ KnownBits:???????????????????????????????? SignBits:1
21+
%0:gpr32 = COPY $w0
22+
%1:_(s32) = COPY %0
23+
%named:_(s64) = G_ZEXT %1
24+
%3:_(s32), %4:_(s32) = G_UNMERGE_VALUES %named(s64)
25+
$w0 = COPY %3(s32)
26+
$w1 = COPY %4(s32)
27+
RET_ReallyLR
28+
...
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_givaluetracking_test_checks.py UTC_ARGS: --version 5
2+
# RUN: llc -mtriple aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
3+
4+
---
5+
name: Cst
6+
body: |
7+
bb.1:
8+
; CHECK-LABEL: name: @Cst
9+
; CHECK-NEXT: %0:_ KnownBits:00000001 SignBits:7
10+
; CHECK-NEXT: %1:_ KnownBits:00000001 SignBits:7
11+
%0:_(s8) = G_CONSTANT i8 1
12+
%1:_(s8) = COPY %0
13+
...
14+
---
15+
name: Test2
16+
body: |
17+
bb.1:
18+
; Note: This comment should not be removed, the check lines below should be updated
19+
; CHECK-LABEL: name: @Test2
20+
; CHECK-NEXT: %1:_ KnownBits:???????????????????????????????? SignBits:1
21+
; CHECK-NEXT: %named:_ KnownBits:00000000000000000000000000000000???????????????????????????????? SignBits:32
22+
; CHECK-NEXT: %3:_ KnownBits:???????????????????????????????? SignBits:1
23+
; CHECK-NEXT: %4:_ KnownBits:00000000000000000000000000000000 SignBits:32
24+
%0:gpr32 = COPY $w0
25+
%1:_(s32) = COPY %0
26+
%named:_(s64) = G_ZEXT %1
27+
%3:_(s32), %4:_(s32) = G_UNMERGE_VALUES %named(s64)
28+
$w0 = COPY %3(s32)
29+
$w1 = COPY %4(s32)
30+
RET_ReallyLR
31+
...
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# REQUIRES: aarch64-registered-target
2+
# RUN: cp -f %S/Inputs/const.mir %t.mir && %update_givaluetracking_test_checks %t.mir
3+
# RUN: diff -u %S/Inputs/const.mir.expected %t.mir
4+
# RUN: FileCheck %t.mir < %t.mir
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# These tests require llc.
2+
if "llc-binary" not in config.available_features:
3+
config.unsupported = True

llvm/utils/UpdateTestChecks/common.py

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,244 @@ def add_analyze_checks(
22712271
)
22722272

22732273

2274+
IR_FUNC_NAME_RE = re.compile(
2275+
r"^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[A-Za-z0-9_.]+)\s*\("
2276+
)
2277+
IR_PREFIX_DATA_RE = re.compile(r"^ *(;|$)")
2278+
MIR_FUNC_NAME_RE = re.compile(r" *name: *(?P<func>[A-Za-z0-9_.-]+)")
2279+
MIR_BODY_BEGIN_RE = re.compile(r" *body: *\|")
2280+
MIR_BASIC_BLOCK_RE = re.compile(r" *bb\.[0-9]+.*:$")
2281+
MIR_PREFIX_DATA_RE = re.compile(r"^ *(;|bb.[0-9].*: *$|[a-z]+:( |$)|$)")
2282+
2283+
2284+
def find_mir_functions_with_one_bb(lines, verbose=False):
2285+
result = []
2286+
cur_func = None
2287+
bbs = 0
2288+
for line in lines:
2289+
m = MIR_FUNC_NAME_RE.match(line)
2290+
if m:
2291+
if bbs == 1:
2292+
result.append(cur_func)
2293+
cur_func = m.group("func")
2294+
bbs = 0
2295+
m = MIR_BASIC_BLOCK_RE.match(line)
2296+
if m:
2297+
bbs += 1
2298+
if bbs == 1:
2299+
result.append(cur_func)
2300+
return result
2301+
2302+
2303+
def add_mir_checks_for_function(
2304+
test,
2305+
output_lines,
2306+
run_list,
2307+
func_dict,
2308+
func_name,
2309+
single_bb,
2310+
print_fixed_stack,
2311+
first_check_is_next,
2312+
at_the_function_name,
2313+
):
2314+
printed_prefixes = set()
2315+
for run in run_list:
2316+
for prefix in run[0]:
2317+
if prefix in printed_prefixes:
2318+
break
2319+
if not func_dict[prefix][func_name]:
2320+
continue
2321+
if printed_prefixes:
2322+
# Add some space between different check prefixes.
2323+
indent = len(output_lines[-1]) - len(output_lines[-1].lstrip(" "))
2324+
output_lines.append(" " * indent + ";")
2325+
printed_prefixes.add(prefix)
2326+
add_mir_check_lines(
2327+
test,
2328+
output_lines,
2329+
prefix,
2330+
("@" if at_the_function_name else "") + func_name,
2331+
single_bb,
2332+
func_dict[prefix][func_name],
2333+
print_fixed_stack,
2334+
first_check_is_next,
2335+
)
2336+
break
2337+
else:
2338+
warn(
2339+
"Found conflicting asm for function: {}".format(func_name),
2340+
test_file=test,
2341+
)
2342+
return output_lines
2343+
2344+
2345+
def add_mir_check_lines(
2346+
test,
2347+
output_lines,
2348+
prefix,
2349+
func_name,
2350+
single_bb,
2351+
func_info,
2352+
print_fixed_stack,
2353+
first_check_is_next,
2354+
):
2355+
func_body = str(func_info).splitlines()
2356+
if single_bb:
2357+
# Don't bother checking the basic block label for a single BB
2358+
func_body.pop(0)
2359+
2360+
if not func_body:
2361+
warn(
2362+
"Function has no instructions to check: {}".format(func_name),
2363+
test_file=test,
2364+
)
2365+
return
2366+
2367+
first_line = func_body[0]
2368+
indent = len(first_line) - len(first_line.lstrip(" "))
2369+
# A check comment, indented the appropriate amount
2370+
check = "{:>{}}; {}".format("", indent, prefix)
2371+
2372+
output_lines.append("{}-LABEL: name: {}".format(check, func_name))
2373+
2374+
if print_fixed_stack:
2375+
output_lines.append("{}: fixedStack:".format(check))
2376+
for stack_line in func_info.extrascrub.splitlines():
2377+
filecheck_directive = check + "-NEXT"
2378+
output_lines.append("{}: {}".format(filecheck_directive, stack_line))
2379+
2380+
first_check = not first_check_is_next
2381+
for func_line in func_body:
2382+
if not func_line.strip():
2383+
# The mir printer prints leading whitespace so we can't use CHECK-EMPTY:
2384+
output_lines.append(check + "-NEXT: {{" + func_line + "$}}")
2385+
continue
2386+
filecheck_directive = check if first_check else check + "-NEXT"
2387+
first_check = False
2388+
check_line = "{}: {}".format(filecheck_directive, func_line[indent:]).rstrip()
2389+
output_lines.append(check_line)
2390+
2391+
2392+
def should_add_mir_line_to_output(input_line, prefix_set):
2393+
# Skip any check lines that we're handling as well as comments
2394+
m = CHECK_RE.match(input_line)
2395+
if (m and m.group(1) in prefix_set) or input_line.strip() == ";":
2396+
return False
2397+
return True
2398+
2399+
2400+
def add_mir_checks(
2401+
input_lines,
2402+
prefix_set,
2403+
autogenerated_note,
2404+
test,
2405+
run_list,
2406+
func_dict,
2407+
print_fixed_stack,
2408+
first_check_is_next,
2409+
at_the_function_name,
2410+
):
2411+
simple_functions = find_mir_functions_with_one_bb(input_lines)
2412+
2413+
output_lines = []
2414+
output_lines.append(autogenerated_note)
2415+
2416+
func_name = None
2417+
state = "toplevel"
2418+
for input_line in input_lines:
2419+
if input_line == autogenerated_note:
2420+
continue
2421+
2422+
if state == "toplevel":
2423+
m = IR_FUNC_NAME_RE.match(input_line)
2424+
if m:
2425+
state = "ir function prefix"
2426+
func_name = m.group("func")
2427+
if input_line.rstrip("| \r\n") == "---":
2428+
state = "document"
2429+
output_lines.append(input_line)
2430+
elif state == "document":
2431+
m = MIR_FUNC_NAME_RE.match(input_line)
2432+
if m:
2433+
state = "mir function metadata"
2434+
func_name = m.group("func")
2435+
if input_line.strip() == "...":
2436+
state = "toplevel"
2437+
func_name = None
2438+
if should_add_mir_line_to_output(input_line, prefix_set):
2439+
output_lines.append(input_line)
2440+
elif state == "mir function metadata":
2441+
if should_add_mir_line_to_output(input_line, prefix_set):
2442+
output_lines.append(input_line)
2443+
m = MIR_BODY_BEGIN_RE.match(input_line)
2444+
if m:
2445+
if func_name in simple_functions:
2446+
# If there's only one block, put the checks inside it
2447+
state = "mir function prefix"
2448+
continue
2449+
state = "mir function body"
2450+
add_mir_checks_for_function(
2451+
test,
2452+
output_lines,
2453+
run_list,
2454+
func_dict,
2455+
func_name,
2456+
single_bb=False,
2457+
print_fixed_stack=print_fixed_stack,
2458+
first_check_is_next=first_check_is_next,
2459+
at_the_function_name=at_the_function_name,
2460+
)
2461+
elif state == "mir function prefix":
2462+
m = MIR_PREFIX_DATA_RE.match(input_line)
2463+
if not m:
2464+
state = "mir function body"
2465+
add_mir_checks_for_function(
2466+
test,
2467+
output_lines,
2468+
run_list,
2469+
func_dict,
2470+
func_name,
2471+
single_bb=True,
2472+
print_fixed_stack=print_fixed_stack,
2473+
first_check_is_next=first_check_is_next,
2474+
at_the_function_name=at_the_function_name,
2475+
)
2476+
2477+
if should_add_mir_line_to_output(input_line, prefix_set):
2478+
output_lines.append(input_line)
2479+
elif state == "mir function body":
2480+
if input_line.strip() == "...":
2481+
state = "toplevel"
2482+
func_name = None
2483+
if should_add_mir_line_to_output(input_line, prefix_set):
2484+
output_lines.append(input_line)
2485+
elif state == "ir function prefix":
2486+
m = IR_PREFIX_DATA_RE.match(input_line)
2487+
if not m:
2488+
state = "ir function body"
2489+
add_mir_checks_for_function(
2490+
test,
2491+
output_lines,
2492+
run_list,
2493+
func_dict,
2494+
func_name,
2495+
single_bb=False,
2496+
print_fixed_stack=print_fixed_stack,
2497+
first_check_is_next=first_check_is_next,
2498+
at_the_function_name=at_the_function_name,
2499+
)
2500+
2501+
if should_add_mir_line_to_output(input_line, prefix_set):
2502+
output_lines.append(input_line)
2503+
elif state == "ir function body":
2504+
if input_line.strip() == "}":
2505+
state = "toplevel"
2506+
func_name = None
2507+
if should_add_mir_line_to_output(input_line, prefix_set):
2508+
output_lines.append(input_line)
2509+
return output_lines
2510+
2511+
22742512
def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes, ginfo):
22752513
for nameless_value in ginfo.get_nameless_values():
22762514
if nameless_value.global_ir_rhs_regexp is None:

0 commit comments

Comments
 (0)