[UpdateTestChecks] Re-add --filter and --filter-out options

Re-add filtering options with fixes for failed tests.  We were not passing the
is_filtered argument in all check generator calls in update_cc_test_checks.py

Enhance the various update_*_test_checks.py tools to allow filtering the tool
output with regular expressions.  The --filter option will emit only tool output
lines matching the given regular expression while the --filter-out option will
emit only tools output lines not matching the given regular expression.  Filters
are applied in order of appearance on the command line (or in UTC_ARGS) and the
first matching filter terminates the search.

This allows test authors to create more focused tests by removing irrelevant
tool output and checking only the pieces of output necessary to test the desired
functionality.

Differential Revision: https://reviews.llvm.org/D117694
This commit is contained in:
David Greene 2022-01-31 07:06:08 -08:00
parent e21f90dba2
commit ecd46edd61
11 changed files with 466 additions and 24 deletions

View File

@ -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, <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0>
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, <i64 1, i64 2, i64 3, i64 4>
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, <double 1.0, double 2.0, double 3.0, double 4.0>
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, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
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, <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
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, <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
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}

View File

@ -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, <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0>
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, <i64 1, i64 2, i64 3, i64 4>
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, <double 1.0, double 2.0, double 3.0, double 4.0>
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, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
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, <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
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, <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
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}

View File

@ -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, <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0>
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, <i64 1, i64 2, i64 3, i64 4>
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, <double 1.0, double 2.0, double 3.0, double 4.0>
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, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
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, <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
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, <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
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}

View File

@ -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, <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0>
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, <i64 1, i64 2, i64 3, i64 4>
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, <double 1.0, double 2.0, double 3.0, double 4.0>
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, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
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, <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
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, <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
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}

View File

@ -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, <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0>
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, <i64 1, i64 2, i64 3, i64 4>
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, <double 1.0, double 2.0, double 3.0, double 4.0>
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, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
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, <i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8>
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, <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8>
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}

View File

@ -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

View File

@ -456,8 +456,11 @@ def get_run_handler(triple):
##### 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)

View File

@ -1,5 +1,6 @@
from __future__ import print_function
import argparse
import copy
import glob
import os
@ -13,7 +14,99 @@ import sys
_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 @@ def find_run_lines(test, lines):
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 @@ class FunctionTestBuilder:
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 @@ class FunctionTestBuilder:
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 @@ class FunctionTestBuilder:
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 @@ def generalize_check_lines(lines, is_analyze, vars_seen, global_vars_seen):
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 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
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 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
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 @@ def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
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 @@ def get_autogennote_suffix(parser, args):
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

View File

@ -344,11 +344,13 @@ def main():
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 @@ def main():
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

View File

@ -111,6 +111,7 @@ def main():
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 @@ def main():
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 @@ def main():
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:

View File

@ -160,7 +160,8 @@ def main():
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 @@ def main():
# 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)