Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; RUN: sed 's/RETVAL/1/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKA %s
; RUN: sed 's/RETVAL/2/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKA %s
; RUN: sed 's/RETVAL/3/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKB %s
; RUN: sed 's/RETVAL/4/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKB %s

define i32 @foo() {
ret i32 RETVAL
}

define i32 @bar() {
ret i32 100
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no-generate-body-for-unused-prefixes
; RUN: sed 's/RETVAL/1/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKA %s
; RUN: sed 's/RETVAL/2/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKA %s
; RUN: sed 's/RETVAL/3/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKB %s
; RUN: sed 's/RETVAL/4/g' %s | llc -mtriple=riscv32 \
; RUN: | FileCheck -check-prefixes=CHECK,CHECKB %s

define i32 @foo() {
ret i32 RETVAL
}

define i32 @bar() {
; CHECK-LABEL: bar:
; CHECK: # %bb.0:
; CHECK-NEXT: li a0, 100
; CHECK-NEXT: ret
ret i32 100
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# REQUIRES: riscv-registered-target

# RUN: cp -f %S/Inputs/conflicting-prefixes.ll %t.ll
# RUN: %update_llc_test_checks --no-generate-body-for-unused-prefixes %t.ll 2>&1 | FileCheck %s
# RUN: diff -u %S/Inputs/conflicting-prefixes.ll.expected %t.ll

# CHECK: WARNING: For function 'foo', the following RUN lines will not generate checks due to conflicting output
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
# RUN: %update_llc_test_checks --no-generate-body-for-unused-prefixes %t.ll 2>&1 | FileCheck %s
# RUN: FileCheck --input-file=%t.ll %s --check-prefix=OUTPUT

# CHECK: WARNING: Prefix A had conflicting output
# CHECK: WARNING: For function 'fold_v2i64', the following RUN lines will not generate checks due to conflicting output
# OUTPUT-NOT: A:
64 changes: 44 additions & 20 deletions llvm/utils/UpdateTestChecks/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ def __str__(self):

class FunctionTestBuilder:
def __init__(self, run_list, flags, scrubber_args, path, ginfo):
self._run_list = run_list
self._verbose = flags.verbose
self._record_args = flags.function_signature
self._check_attributes = flags.check_attributes
Expand Down Expand Up @@ -918,14 +919,51 @@ def __init__(self, run_list, flags, scrubber_args, path, ginfo):
self._global_var_dict.update({prefix: dict()})

def finish_and_get_func_dict(self):
for prefix in self.get_failed_prefixes():
warn(
"Prefix %s had conflicting output from different RUN lines for all functions in test %s"
% (
prefix,
self._path,
all_funcs = set()
for prefix in self._func_dict:
all_funcs.update(self._func_dict[prefix].keys())

warnings_to_print = collections.defaultdict(list)
for func in sorted(list(all_funcs)):
for i, run_info in enumerate(self._run_list):
prefixes = run_info[0]
if not prefixes:
continue

# Check if this RUN line produces this function at all.
run_contains_func = True
for p in prefixes:
if func not in self._func_dict.get(p, {}):
run_contains_func = False
break
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
run_contains_func = True
for p in prefixes:
if func not in self._func_dict.get(p, {}):
run_contains_func = False
break
run_contains_func = all(func in self._func_dict.get(p, {}) for p in prefixes)

I think this should be equivalent any maybe easier to read?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I read this correctly, you are checking that all prefixes have a func_dict entry for this function?

I have never looked into this part of the update_test_checks script, so I feel this needs a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've extended the comment to hopefully clarify, and also added a test case that captures this behaviour. When I thought about potential corner cases that could produce a false positive, this is the one that came to mind. Without this logic we do seem to produce a confusing warning for the --included-generated-funcs test case I committed. Possibly there are still cases with non-matching sets of functions and prefix clashes we would want to error, but it's not clear to me what behaviour is right. Either way, I think this patch is a strict improvement even if it's possible there are corner cases like this where maybe you want even more error checking.

if not run_contains_func:
continue

# Check if this RUN line can print any checks for this
# function. It can't if all of its prefixes have conflicting
# (None) output.
can_print_for_this_run = False
for p in prefixes:
if self._func_dict[p].get(func) is not None:
can_print_for_this_run = True
break

if not can_print_for_this_run:
warnings_to_print[func].append((i, prefixes))

for func, warning_info in warnings_to_print.items():
conflict_strs = []
for run_index, prefixes in warning_info:
conflict_strs.append(
"RUN #{} (prefixes: {})".format(run_index + 1, ", ".join(prefixes))
)
warn(
"For function '{}', the following RUN lines will not generate checks due to conflicting output: {}".format(
func, ", ".join(conflict_strs)
),
test_file=self._path,
)

return self._func_dict

def func_order(self):
Expand Down Expand Up @@ -1078,20 +1116,6 @@ def processed_prefixes(self, prefixes):
"""
self._processed_prefixes.update(prefixes)

def get_failed_prefixes(self):
# This returns the list of those prefixes that failed to match any function,
# because there were conflicting bodies produced by different RUN lines, in
# all instances of the prefix.
for prefix in self._func_dict:
if self._func_dict[prefix] and (
not [
fct
for fct in self._func_dict[prefix]
if self._func_dict[prefix][fct] is not None
]
):
yield prefix


##### Generator of LLVM IR CHECK lines

Expand Down