diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll @@ -0,0 +1,38 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 | FileCheck %s + +define i32 @f(<8 x float> %A, i8* %B, <4 x double> %C, <4 x i64> %E, <8 x i32> %F, <16 x i16> %G, <32 x i8> %H, i32* %loadptr) nounwind { + %v0 = load i32, i32* %loadptr, align 1 + %cast = bitcast i8* %B to <8 x float>* + %A2 = fadd <8 x float> %A, + store <8 x float> %A2, <8 x float>* %cast, align 32, !nontemporal !0 + %v1 = load i32, i32* %loadptr, align 1 + %cast1 = bitcast i8* %B to <4 x i64>* + %E2 = add <4 x i64> %E, + store <4 x i64> %E2, <4 x i64>* %cast1, align 32, !nontemporal !0 + %v2 = load i32, i32* %loadptr, align 1 + %cast2 = bitcast i8* %B to <4 x double>* + %C2 = fadd <4 x double> %C, + store <4 x double> %C2, <4 x double>* %cast2, align 32, !nontemporal !0 + %v3 = load i32, i32* %loadptr, align 1 + %cast3 = bitcast i8* %B to <8 x i32>* + %F2 = add <8 x i32> %F, + store <8 x i32> %F2, <8 x i32>* %cast3, align 32, !nontemporal !0 + %v4 = load i32, i32* %loadptr, align 1 + %cast4 = bitcast i8* %B to <16 x i16>* + %G2 = add <16 x i16> %G, + store <16 x i16> %G2, <16 x i16>* %cast4, align 32, !nontemporal !0 + %v5 = load i32, i32* %loadptr, align 1 + %cast5 = bitcast i8* %B to <32 x i8>* + %H2 = add <32 x i8> %H, + store <32 x i8> %H2, <32 x i8>* %cast5, align 32, !nontemporal !0 + %v6 = load i32, i32* %loadptr, align 1 + %sum1 = add i32 %v0, %v1 + %sum2 = add i32 %sum1, %v2 + %sum3 = add i32 %sum2, %v3 + %sum4 = add i32 %sum3, %v4 + %sum5 = add i32 %sum4, %v5 + %sum6 = add i32 %sum5, %v6 + ret i32 %sum5 +} + +!0 = !{i32 1} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter-out.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter-out.expected new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter-out.expected @@ -0,0 +1,54 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter-out "movnt" +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 | FileCheck %s + +define i32 @f(<8 x float> %A, i8* %B, <4 x double> %C, <4 x i64> %E, <8 x i32> %F, <16 x i16> %G, <32 x i8> %H, i32* %loadptr) nounwind { +; CHECK-LABEL: f: +; CHECK: movl (%rsi), %eax +; CHECK: vaddps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm0 +; CHECK: vpaddq {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm2, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vaddpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm1, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vpaddd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm3, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vpaddw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm4, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vpaddb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm5, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vzeroupper +; CHECK: retq + %v0 = load i32, i32* %loadptr, align 1 + %cast = bitcast i8* %B to <8 x float>* + %A2 = fadd <8 x float> %A, + store <8 x float> %A2, <8 x float>* %cast, align 32, !nontemporal !0 + %v1 = load i32, i32* %loadptr, align 1 + %cast1 = bitcast i8* %B to <4 x i64>* + %E2 = add <4 x i64> %E, + store <4 x i64> %E2, <4 x i64>* %cast1, align 32, !nontemporal !0 + %v2 = load i32, i32* %loadptr, align 1 + %cast2 = bitcast i8* %B to <4 x double>* + %C2 = fadd <4 x double> %C, + store <4 x double> %C2, <4 x double>* %cast2, align 32, !nontemporal !0 + %v3 = load i32, i32* %loadptr, align 1 + %cast3 = bitcast i8* %B to <8 x i32>* + %F2 = add <8 x i32> %F, + store <8 x i32> %F2, <8 x i32>* %cast3, align 32, !nontemporal !0 + %v4 = load i32, i32* %loadptr, align 1 + %cast4 = bitcast i8* %B to <16 x i16>* + %G2 = add <16 x i16> %G, + store <16 x i16> %G2, <16 x i16>* %cast4, align 32, !nontemporal !0 + %v5 = load i32, i32* %loadptr, align 1 + %cast5 = bitcast i8* %B to <32 x i8>* + %H2 = add <32 x i8> %H, + store <32 x i8> %H2, <32 x i8>* %cast5, align 32, !nontemporal !0 + %v6 = load i32, i32* %loadptr, align 1 + %sum1 = add i32 %v0, %v1 + %sum2 = add i32 %sum1, %v2 + %sum3 = add i32 %sum2, %v3 + %sum4 = add i32 %sum3, %v4 + %sum5 = add i32 %sum4, %v5 + %sum6 = add i32 %sum5, %v6 + ret i32 %sum5 +} + +!0 = !{i32 1} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter.expected new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.filter.expected @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "movnt" +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 | FileCheck %s + +define i32 @f(<8 x float> %A, i8* %B, <4 x double> %C, <4 x i64> %E, <8 x i32> %F, <16 x i16> %G, <32 x i8> %H, i32* %loadptr) nounwind { +; CHECK-LABEL: f: +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vmovntpd %ymm0, (%rdi) +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vmovntdq %ymm0, (%rdi) + %v0 = load i32, i32* %loadptr, align 1 + %cast = bitcast i8* %B to <8 x float>* + %A2 = fadd <8 x float> %A, + store <8 x float> %A2, <8 x float>* %cast, align 32, !nontemporal !0 + %v1 = load i32, i32* %loadptr, align 1 + %cast1 = bitcast i8* %B to <4 x i64>* + %E2 = add <4 x i64> %E, + store <4 x i64> %E2, <4 x i64>* %cast1, align 32, !nontemporal !0 + %v2 = load i32, i32* %loadptr, align 1 + %cast2 = bitcast i8* %B to <4 x double>* + %C2 = fadd <4 x double> %C, + store <4 x double> %C2, <4 x double>* %cast2, align 32, !nontemporal !0 + %v3 = load i32, i32* %loadptr, align 1 + %cast3 = bitcast i8* %B to <8 x i32>* + %F2 = add <8 x i32> %F, + store <8 x i32> %F2, <8 x i32>* %cast3, align 32, !nontemporal !0 + %v4 = load i32, i32* %loadptr, align 1 + %cast4 = bitcast i8* %B to <16 x i16>* + %G2 = add <16 x i16> %G, + store <16 x i16> %G2, <16 x i16>* %cast4, align 32, !nontemporal !0 + %v5 = load i32, i32* %loadptr, align 1 + %cast5 = bitcast i8* %B to <32 x i8>* + %H2 = add <32 x i8> %H, + store <32 x i8> %H2, <32 x i8>* %cast5, align 32, !nontemporal !0 + %v6 = load i32, i32* %loadptr, align 1 + %sum1 = add i32 %v0, %v1 + %sum2 = add i32 %sum1, %v2 + %sum3 = add i32 %sum2, %v3 + %sum4 = add i32 %sum3, %v4 + %sum5 = add i32 %sum4, %v5 + %sum6 = add i32 %sum5, %v6 + ret i32 %sum5 +} + +!0 = !{i32 1} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.multifilter.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.multifilter.expected new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.multifilter.expected @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "LCPI[0-9]+_[0-9]+" --filter "movnt" --filter "(%esp|%rsi)" +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 | FileCheck %s + +define i32 @f(<8 x float> %A, i8* %B, <4 x double> %C, <4 x i64> %E, <8 x i32> %F, <16 x i16> %G, <32 x i8> %H, i32* %loadptr) nounwind { +; CHECK-LABEL: f: +; CHECK: vaddps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm0 +; CHECK: vmovntps %ymm0, (%rdi) +; CHECK: vpaddq {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm2, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vaddpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm1, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vmovntpd %ymm0, (%rdi) +; CHECK: vpaddd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm3, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vpaddw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm4, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vmovntdq %ymm0, (%rdi) +; CHECK: vpaddb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm5, %ymm0 +; CHECK: addl (%rsi), %eax +; CHECK: vmovntdq %ymm0, (%rdi) + %v0 = load i32, i32* %loadptr, align 1 + %cast = bitcast i8* %B to <8 x float>* + %A2 = fadd <8 x float> %A, + store <8 x float> %A2, <8 x float>* %cast, align 32, !nontemporal !0 + %v1 = load i32, i32* %loadptr, align 1 + %cast1 = bitcast i8* %B to <4 x i64>* + %E2 = add <4 x i64> %E, + store <4 x i64> %E2, <4 x i64>* %cast1, align 32, !nontemporal !0 + %v2 = load i32, i32* %loadptr, align 1 + %cast2 = bitcast i8* %B to <4 x double>* + %C2 = fadd <4 x double> %C, + store <4 x double> %C2, <4 x double>* %cast2, align 32, !nontemporal !0 + %v3 = load i32, i32* %loadptr, align 1 + %cast3 = bitcast i8* %B to <8 x i32>* + %F2 = add <8 x i32> %F, + store <8 x i32> %F2, <8 x i32>* %cast3, align 32, !nontemporal !0 + %v4 = load i32, i32* %loadptr, align 1 + %cast4 = bitcast i8* %B to <16 x i16>* + %G2 = add <16 x i16> %G, + store <16 x i16> %G2, <16 x i16>* %cast4, align 32, !nontemporal !0 + %v5 = load i32, i32* %loadptr, align 1 + %cast5 = bitcast i8* %B to <32 x i8>* + %H2 = add <32 x i8> %H, + store <32 x i8> %H2, <32 x i8>* %cast5, align 32, !nontemporal !0 + %v6 = load i32, i32* %loadptr, align 1 + %sum1 = add i32 %v0, %v1 + %sum2 = add i32 %sum1, %v2 + %sum3 = add i32 %sum2, %v3 + %sum4 = add i32 %sum3, %v4 + %sum5 = add i32 %sum4, %v5 + %sum6 = add i32 %sum5, %v6 + ret i32 %sum5 +} + +!0 = !{i32 1} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.nofilter.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.nofilter.expected new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/x86-non-temporal.ll.nofilter.expected @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=+avx2 | FileCheck %s + +define i32 @f(<8 x float> %A, i8* %B, <4 x double> %C, <4 x i64> %E, <8 x i32> %F, <16 x i16> %G, <32 x i8> %H, i32* %loadptr) nounwind { +; CHECK-LABEL: f: +; CHECK: # %bb.0: +; CHECK-NEXT: movl (%rsi), %eax +; CHECK-NEXT: vaddps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm0 +; CHECK-NEXT: vmovntps %ymm0, (%rdi) +; CHECK-NEXT: vpaddq {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm2, %ymm0 +; CHECK-NEXT: addl (%rsi), %eax +; CHECK-NEXT: vmovntdq %ymm0, (%rdi) +; CHECK-NEXT: vaddpd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm1, %ymm0 +; CHECK-NEXT: addl (%rsi), %eax +; CHECK-NEXT: vmovntpd %ymm0, (%rdi) +; CHECK-NEXT: vpaddd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm3, %ymm0 +; CHECK-NEXT: addl (%rsi), %eax +; CHECK-NEXT: vmovntdq %ymm0, (%rdi) +; CHECK-NEXT: vpaddw {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm4, %ymm0 +; CHECK-NEXT: addl (%rsi), %eax +; CHECK-NEXT: vmovntdq %ymm0, (%rdi) +; CHECK-NEXT: vpaddb {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm5, %ymm0 +; CHECK-NEXT: addl (%rsi), %eax +; CHECK-NEXT: vmovntdq %ymm0, (%rdi) +; CHECK-NEXT: vzeroupper +; CHECK-NEXT: retq + %v0 = load i32, i32* %loadptr, align 1 + %cast = bitcast i8* %B to <8 x float>* + %A2 = fadd <8 x float> %A, + store <8 x float> %A2, <8 x float>* %cast, align 32, !nontemporal !0 + %v1 = load i32, i32* %loadptr, align 1 + %cast1 = bitcast i8* %B to <4 x i64>* + %E2 = add <4 x i64> %E, + store <4 x i64> %E2, <4 x i64>* %cast1, align 32, !nontemporal !0 + %v2 = load i32, i32* %loadptr, align 1 + %cast2 = bitcast i8* %B to <4 x double>* + %C2 = fadd <4 x double> %C, + store <4 x double> %C2, <4 x double>* %cast2, align 32, !nontemporal !0 + %v3 = load i32, i32* %loadptr, align 1 + %cast3 = bitcast i8* %B to <8 x i32>* + %F2 = add <8 x i32> %F, + store <8 x i32> %F2, <8 x i32>* %cast3, align 32, !nontemporal !0 + %v4 = load i32, i32* %loadptr, align 1 + %cast4 = bitcast i8* %B to <16 x i16>* + %G2 = add <16 x i16> %G, + store <16 x i16> %G2, <16 x i16>* %cast4, align 32, !nontemporal !0 + %v5 = load i32, i32* %loadptr, align 1 + %cast5 = bitcast i8* %B to <32 x i8>* + %H2 = add <32 x i8> %H, + store <32 x i8> %H2, <32 x i8>* %cast5, align 32, !nontemporal !0 + %v6 = load i32, i32* %loadptr, align 1 + %sum1 = add i32 %v0, %v1 + %sum2 = add i32 %sum1, %v2 + %sum3 = add i32 %sum2, %v3 + %sum4 = add i32 %sum3, %v4 + %sum5 = add i32 %sum4, %v5 + %sum6 = add i32 %sum5, %v6 + ret i32 %sum5 +} + +!0 = !{i32 1} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-filter.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-filter.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/x86-filter.test @@ -0,0 +1,33 @@ +# REQUIRES: x86-registered-target + +## Check that --filter works properly. +# RUN: cp -f %S/Inputs/x86-non-temporal.ll %t.ll && %update_llc_test_checks --filter="movnt" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.filter.expected + +## Check that running the script again does not change the result: +# RUN: %update_llc_test_checks --filter="movnt" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.filter.expected + +## Check that --filter-out works properly. +# RUN: cp -f %S/Inputs/x86-non-temporal.ll %t.ll && %update_llc_test_checks --filter-out="movnt" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.filter-out.expected + +## Check that running the script again does not change the result: +# RUN: %update_llc_test_checks --filter-out="movnt" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.filter-out.expected + +## Check that multiple filters work properly. +# RUN: cp -f %S/Inputs/x86-non-temporal.ll %t.ll && %update_llc_test_checks --filter="LCPI[0-9]+_[0-9]+" --filter="movnt" --filter="(%esp|%rsi)" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.multifilter.expected + +## Check that running the script again does not change the result: +# RUN: %update_llc_test_checks --filter="LCPI[0-9]+_[0-9]+" --filter="movnt" --filter="(%esp|%rsi)" %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.multifilter.expected + +## Check that no filtering is done. +# RUN: cp -f %S/Inputs/x86-non-temporal.ll %t.ll && %update_llc_test_checks %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.nofilter.expected + +## Check that running the script again does not change the result: +# RUN: %update_llc_test_checks %t.ll +# RUN: diff -u %t.ll %S/Inputs/x86-non-temporal.ll.nofilter.expected diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py --- a/llvm/utils/UpdateTestChecks/asm.py +++ b/llvm/utils/UpdateTestChecks/asm.py @@ -456,8 +456,11 @@ ##### Generator of assembly CHECK lines -def add_asm_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): +def add_asm_checks(output_lines, comment_marker, prefix_list, func_dict, + func_name, is_filtered): # Label format is based on ASM string. check_label_format = '{} %s-LABEL: %s%s:'.format(comment_marker) global_vars_seen_dict = {} - common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False, global_vars_seen_dict) + common.add_checks(output_lines, comment_marker, prefix_list, func_dict, + func_name, check_label_format, True, False, + global_vars_seen_dict, is_filtered = is_filtered) diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -1,5 +1,6 @@ from __future__ import print_function +import argparse import copy import glob import os @@ -13,7 +14,99 @@ _verbose = False _prefix_filecheck_ir_name = '' +class Regex(object): + """Wrap a compiled regular expression object to allow deep copy of a regexp. + This is required for the deep copy done in do_scrub. + + """ + def __init__(self, regex): + self.regex = regex + + def __deepcopy__(self, memo): + result = copy.copy(self) + result.regex = self.regex + return result + + def search(self, line): + return self.regex.search(line) + + def sub(self, repl, line): + return self.regex.sub(repl, line) + + def pattern(self): + return self.regex.pattern + + def flags(self): + return self.regex.flags + +class Filter(Regex): + """Augment a Regex object with a flag indicating whether a match should be + added (!is_filter_out) or removed (is_filter_out) from the generated checks. + + """ + def __init__(self, regex, is_filter_out): + super(Filter, self).__init__(regex) + self.is_filter_out = is_filter_out + + def __deepcopy__(self, memo): + result = copy.deepcopy(super(Filter, self), memo) + result.is_filter_out = copy.deepcopy(self.is_filter_out, memo) + return result + def parse_commandline_args(parser): + class RegexAction(argparse.Action): + """Add a regular expression option value to a list of regular expressions. + This compiles the expression, wraps it in a Regex and adds it to the option + value list.""" + def __init__(self, option_strings, dest, nargs=None, **kwargs): + if nargs is not None: + raise ValueError('nargs not allowed') + super(RegexAction, self).__init__(option_strings, dest, **kwargs) + + def do_call(self, namespace, values, flags): + value_list = getattr(namespace, self.dest) + if value_list is None: + value_list = [] + + try: + value_list.append(Regex(re.compile(values, flags))) + except re.error as error: + raise ValueError('{}: Invalid regular expression \'{}\' ({})'.format( + option_string, error.pattern, error.msg)) + + setattr(namespace, self.dest, value_list) + + def __call__(self, parser, namespace, values, option_string=None): + self.do_call(namespace, values, 0) + + class FilterAction(RegexAction): + """Add a filter to a list of filter option values.""" + def __init__(self, option_strings, dest, nargs=None, **kwargs): + super(FilterAction, self).__init__(option_strings, dest, nargs, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + super(FilterAction, self).__call__(parser, namespace, values, option_string) + + value_list = getattr(namespace, self.dest) + + is_filter_out = ( option_string == '--filter-out' ) + + value_list[-1] = Filter(value_list[-1].regex, is_filter_out) + + setattr(namespace, self.dest, value_list) + + filter_group = parser.add_argument_group( + 'filtering', + """Filters are applied to each output line according to the order given. The + first matching filter terminates filter processing for that current line.""") + + filter_group.add_argument('--filter', action=FilterAction, dest='filters', + metavar='REGEX', + help='Only include lines matching REGEX (may be specified multiple times)') + filter_group.add_argument('--filter-out', action=FilterAction, dest='filters', + metavar='REGEX', + help='Exclude lines matching REGEX') + parser.add_argument('--include-generated-funcs', action='store_true', help='Output checks for functions not in source') parser.add_argument('-v', '--verbose', action='store_true', @@ -258,6 +351,21 @@ debug(' RUN: {}'.format(l)) return run_lines +def apply_filters(line, filters): + has_filter = False + for f in filters: + if not f.is_filter_out: + has_filter = True + if f.search(line): + return False if f.is_filter_out else True + # If we only used filter-out, keep the line, otherwise discard it since no + # filter matched. + return False if has_filter else True + +def do_filter(body, filters): + return body if not filters else '\n'.join(filter( + lambda line: apply_filters(line, filters), body.splitlines())) + def scrub_body(body): # Scrub runs of whitespace out of the assembly, but leave the leading # whitespace in place. @@ -320,6 +428,11 @@ self._verbose = flags.verbose self._record_args = flags.function_signature self._check_attributes = flags.check_attributes + # Strip double-quotes if input was read by UTC_ARGS + self._filters = list(map(lambda f: Filter(re.compile(f.pattern().strip('"'), + f.flags()), + f.is_filter_out), + flags.filters)) if flags.filters else [] self._scrubber_args = scrubber_args self._path = path # Strip double-quotes if input was read by UTC_ARGS @@ -344,6 +457,9 @@ def global_var_dict(self): return self._global_var_dict + def is_filtered(self): + return bool(self._filters) + def process_run_line(self, function_re, scrubber, raw_tool_output, prefixes, is_asm): build_global_values_dictionary(self._global_var_dict, raw_tool_output, prefixes) for m in function_re.finditer(raw_tool_output): @@ -360,9 +476,10 @@ args_and_sig = '(' else: args_and_sig = '' - scrubbed_body = do_scrub(body, scrubber, self._scrubber_args, + filtered_body = do_filter(body, self._filters) + scrubbed_body = do_scrub(filtered_body, scrubber, self._scrubber_args, extra=False) - scrubbed_extra = do_scrub(body, scrubber, self._scrubber_args, + scrubbed_extra = do_scrub(filtered_body, scrubber, self._scrubber_args, extra=True) if 'analysis' in m.groupdict(): analysis = m.group('analysis') @@ -649,7 +766,7 @@ return lines -def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_asm, is_analyze, global_vars_seen_dict): +def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_asm, is_analyze, global_vars_seen_dict, is_filtered): # prefix_exclusions are prefixes we cannot use to print the function because it doesn't exist in run lines that use these prefixes as well. prefix_exclusions = set() printed_prefixes = [] @@ -707,15 +824,26 @@ else: output_lines.append(check_label_format % (checkprefix, func_name, args_and_sig)) func_body = str(func_dict[checkprefix][func_name]).splitlines() + if not func_body: + # We have filtered everything. + continue # For ASM output, just emit the check lines. if is_asm: - output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0])) + body_start = 1 + if is_filtered: + # For filtered output we don't add "-NEXT" so don't add extra spaces + # before the first line. + body_start = 0 + else: + output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0])) for func_line in func_body[1:]: if func_line.strip() == '': output_lines.append('%s %s-EMPTY:' % (comment_marker, checkprefix)) else: - output_lines.append('%s %s-NEXT: %s' % (comment_marker, checkprefix, func_line)) + check_suffix = '-NEXT' if not is_filtered else '' + output_lines.append('%s %s%s: %s' % (comment_marker, checkprefix, + check_suffix, func_line)) break # For IR output, change all defs to FileCheck variables, so we're immune @@ -747,8 +875,9 @@ output_lines.append('{} {}: {}'.format( comment_marker, checkprefix, func_line)) else: - output_lines.append('{} {}-NEXT: {}'.format( - comment_marker, checkprefix, func_line)) + check_suffix = '-NEXT' if not is_filtered else '' + output_lines.append('{} {}{}: {}'.format( + comment_marker, checkprefix, check_suffix, func_line)) is_blank_line = False # Add space between different check prefixes and also before the first @@ -762,18 +891,21 @@ break def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict, - func_name, preserve_names, function_sig, global_vars_seen_dict): + func_name, preserve_names, function_sig, + global_vars_seen_dict, is_filtered): # Label format is based on IR string. function_def_regex = 'define {{[^@]+}}' if function_sig else '' check_label_format = '{} %s-LABEL: {}@%s%s'.format(comment_marker, function_def_regex) add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, preserve_names, global_vars_seen_dict) + check_label_format, False, preserve_names, global_vars_seen_dict, + is_filtered) def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): check_label_format = '{} %s-LABEL: \'%s%s\''.format(comment_marker) global_vars_seen_dict = {} add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, - check_label_format, False, True, global_vars_seen_dict) + check_label_format, False, True, global_vars_seen_dict, + is_filtered = False) def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes): for nameless_value in nameless_values: @@ -901,11 +1033,21 @@ continue if parser.get_default(action.dest) == value: continue # Don't add default values - autogenerated_note_args += action.option_strings[0] + ' ' - if action.const is None: # action takes a parameter - if action.nargs == '+': - value = ' '.join(map(lambda v: '"' + v.strip('"') + '"', value)) - autogenerated_note_args += '%s ' % value + if action.dest == 'filters': + # Create a separate option for each filter element. The value is a list + # of Filter objects. + for elem in value: + opt_name = 'filter-out' if elem.is_filter_out else 'filter' + opt_value = elem.pattern() + new_arg = '--%s "%s" ' % (opt_name, opt_value.strip('"')) + if new_arg not in autogenerated_note_args: + autogenerated_note_args += new_arg + else: + autogenerated_note_args += action.option_strings[0] + ' ' + if action.const is None: # action takes a parameter + if action.nargs == '+': + value = ' '.join(map(lambda v: '"' + v.strip('"') + '"', value)) + autogenerated_note_args += '%s ' % value if autogenerated_note_args: autogenerated_note_args = ' %s %s' % (UTC_ARGS_KEY, autogenerated_note_args[:-1]) return autogenerated_note_args diff --git a/llvm/utils/update_cc_test_checks.py b/llvm/utils/update_cc_test_checks.py --- a/llvm/utils/update_cc_test_checks.py +++ b/llvm/utils/update_cc_test_checks.py @@ -344,11 +344,13 @@ prefixes, func_dict, func, False, ti.args.function_signature, - global_vars_seen_dict) + global_vars_seen_dict, + is_filtered=builder.is_filtered()) else: asm.add_asm_checks(my_output_lines, '//', prefixes, - func_dict, func) + func_dict, func, + is_filtered=builder.is_filtered()) if ti.args.check_globals: common.add_global_checks(builder.global_var_dict(), '//', run_list, @@ -398,7 +400,8 @@ output_lines.append('//') added.add(mangled) common.add_ir_checks(output_lines, '//', filecheck_run_list, func_dict, mangled, - False, args.function_signature, global_vars_seen_dict) + False, args.function_signature, global_vars_seen_dict, + is_filtered=builder.is_filtered()) if line.rstrip('\n') == '//': include_line = False diff --git a/llvm/utils/update_llc_test_checks.py b/llvm/utils/update_llc_test_checks.py --- a/llvm/utils/update_llc_test_checks.py +++ b/llvm/utils/update_llc_test_checks.py @@ -111,6 +111,7 @@ run_list=run_list, flags=type('', (object,), { 'verbose': ti.args.verbose, + 'filters': ti.args.filters, 'function_signature': False, 'check_attributes': False, 'replace_value_regex': []}), @@ -161,7 +162,8 @@ lambda my_output_lines, prefixes, func: asm.add_asm_checks(my_output_lines, check_indent + ';', - prefixes, func_dict, func)) + prefixes, func_dict, func, + is_filtered=builder.is_filtered())) else: for input_info in ti.iterlines(output_lines): input_line = input_info.line @@ -176,7 +178,9 @@ continue # Print out the various check lines here. - asm.add_asm_checks(output_lines, check_indent + ';', run_list, func_dict, func_name) + asm.add_asm_checks(output_lines, check_indent + ';', run_list, + func_dict, func_name, + is_filtered=builder.is_filtered()) is_in_function_start = False if is_in_function: diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py --- a/llvm/utils/update_test_checks.py +++ b/llvm/utils/update_test_checks.py @@ -160,7 +160,8 @@ prefixes, func_dict, func, False, args.function_signature, - global_vars_seen_dict)) + global_vars_seen_dict, + is_filtered=builder.is_filtered())) else: # "Normal" mode. for input_line_info in ti.iterlines(output_lines): @@ -178,7 +179,8 @@ # Print out the various check lines here. common.add_ir_checks(output_lines, ';', prefix_list, func_dict, func_name, args.preserve_names, args.function_signature, - global_vars_seen_dict) + global_vars_seen_dict, + is_filtered=builder.is_filtered()) is_in_function_start = False m = common.IR_FUNCTION_RE.match(input_line)