aboutsummaryrefslogtreecommitdiff
path: root/llvm/utils/UpdateTestChecks
diff options
context:
space:
mode:
authorTobias Hieta <tobias@hieta.se>2023-05-15 11:02:42 +0200
committerTobias Hieta <tobias@hieta.se>2023-05-17 10:48:52 +0200
commitb71edfaa4ec3c998aadb35255ce2f60bba2940b0 (patch)
treee79a8adc4e62ac9e50d889b5cf9a248ceccc65de /llvm/utils/UpdateTestChecks
parent7beb2ca8fa2aed594bb150c4c5734931d6ea4348 (diff)
downloadllvm-b71edfaa4ec3c998aadb35255ce2f60bba2940b0.zip
llvm-b71edfaa4ec3c998aadb35255ce2f60bba2940b0.tar.gz
llvm-b71edfaa4ec3c998aadb35255ce2f60bba2940b0.tar.bz2
[NFC][Py Reformat] Reformat python files in llvm
This is the first commit in a series that will reformat all the python files in the LLVM repository. Reformatting is done with `black`. See more information here: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Reviewed By: jhenderson, JDevlieghere, MatzeB Differential Revision: https://reviews.llvm.org/D150545
Diffstat (limited to 'llvm/utils/UpdateTestChecks')
-rw-r--r--llvm/utils/UpdateTestChecks/asm.py859
-rw-r--r--llvm/utils/UpdateTestChecks/common.py2689
-rw-r--r--llvm/utils/UpdateTestChecks/isel.py91
3 files changed, 2066 insertions, 1573 deletions
diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py
index 5471922..72ff67b 100644
--- a/llvm/utils/UpdateTestChecks/asm.py
+++ b/llvm/utils/UpdateTestChecks/asm.py
@@ -5,10 +5,12 @@ import sys
from . import common
if sys.version_info[0] > 2:
- class string:
- expandtabs = str.expandtabs
+
+ class string:
+ expandtabs = str.expandtabs
+
else:
- import string
+ import string
# RegEx: this is where the magic happens.
@@ -16,525 +18,580 @@ else:
ASM_FUNCTION_X86_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*(@"?(?P=func)"?| -- Begin function (?P=func))\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?'
- r'(?:\.L(?P=func)\$local:\n)?' # drop .L<func>$local:
- r'(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?' # drop .type .L<func>$local
- r'(?:[ \t]*(?:\.cfi_startproc|\.cfi_personality|\.cfi_lsda|\.seh_proc|\.seh_handler)\b[^\n]*\n)*' # drop optional cfi
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)',
- flags=(re.M | re.S))
+ r"(?:\.L(?P=func)\$local:\n)?" # drop .L<func>$local:
+ r"(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?" # drop .type .L<func>$local
+ r"(?:[ \t]*(?:\.cfi_startproc|\.cfi_personality|\.cfi_lsda|\.seh_proc|\.seh_handler)\b[^\n]*\n)*" # drop optional cfi
+ r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+ r"^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_ARM_RE = re.compile(
- r'^(?P<func>[0-9a-zA-Z_$]+):\n' # f: (name of function)
- r'(?:\.L(?P=func)\$local:\n)?' # drop .L<func>$local:
- r'(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?' # drop .type .L<func>$local
- r'\s+\.fnstart\n' # .fnstart
- r'(?P<body>.*?)' # (body of the function)
- r'^.Lfunc_end[0-9]+:', # .Lfunc_end0: or # -- End function
- flags=(re.M | re.S))
+ r"^(?P<func>[0-9a-zA-Z_$]+):\n" # f: (name of function)
+ r"(?:\.L(?P=func)\$local:\n)?" # drop .L<func>$local:
+ r"(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?" # drop .type .L<func>$local
+ r"\s+\.fnstart\n" # .fnstart
+ r"(?P<body>.*?)" # (body of the function)
+ r"^.Lfunc_end[0-9]+:", # .Lfunc_end0: or # -- End function
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_AARCH64_RE = re.compile(
- r'^_?(?P<func>[^:]+):[ \t]*\/\/[ \t]*@"?(?P=func)"?( (Function|Tail Call))?\n'
- r'(?:[ \t]+.cfi_startproc\n)?' # drop optional cfi noise
- r'(?P<body>.*?)\n'
- # This list is incomplete
- r'^\s*(\.Lfunc_end[0-9]+|// -- End function)',
- flags=(re.M | re.S))
+ r'^_?(?P<func>[^:]+):[ \t]*\/\/[ \t]*@"?(?P=func)"?( (Function|Tail Call))?\n'
+ r"(?:[ \t]+.cfi_startproc\n)?" # drop optional cfi noise
+ r"(?P<body>.*?)\n"
+ # This list is incomplete
+ r"^\s*(\.Lfunc_end[0-9]+|// -- End function)",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_AMDGPU_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@"?(?P=func)"?\n[^:]*?'
- r'(?P<body>.*?)\n' # (body of the function)
+ r"(?P<body>.*?)\n" # (body of the function)
# This list is incomplete
- r'^\s*(\.Lfunc_end[0-9]+:\n|\.section)',
- flags=(re.M | re.S))
+ r"^\s*(\.Lfunc_end[0-9]+:\n|\.section)",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_BPF_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
- r'(?:[ \t]+.cfi_startproc\n|.seh_proc[^\n]+\n)?' # drop optional cfi
- r'(?P<body>.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?:[ \t]+.cfi_startproc\n|.seh_proc[^\n]+\n)?" # drop optional cfi
+ r"(?P<body>.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_HEXAGON_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*//[ \t]*@"?(?P=func)"?\n[^:]*?'
- r'(?P<body>.*?)\n' # (body of the function)
+ r"(?P<body>.*?)\n" # (body of the function)
# This list is incomplete
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_M68K_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*;[ \t]*@"?(?P=func)"?\n'
- r'(?P<body>.*?)\s*' # (body of the function)
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?P<body>.*?)\s*" # (body of the function)
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_MIPS_RE = re.compile(
- r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n[^:]*?' # f: (name of func)
- r'(?:\s*\.?Ltmp[^:\n]*:\n)?[^:]*?' # optional .Ltmp<N> for EH
- r'(?:^[ \t]+\.(frame|f?mask|set).*?\n)+' # Mips+LLVM standard asm prologue
- r'(?P<body>.*?)\n' # (body of the function)
+ r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n[^:]*?' # f: (name of func)
+ r"(?:\s*\.?Ltmp[^:\n]*:\n)?[^:]*?" # optional .Ltmp<N> for EH
+ r"(?:^[ \t]+\.(frame|f?mask|set).*?\n)+" # Mips+LLVM standard asm prologue
+ r"(?P<body>.*?)\n" # (body of the function)
# Mips+LLVM standard asm epilogue
- r'(?:(^[ \t]+\.set[^\n]*?\n)*^[ \t]+\.end.*?\n)'
- r'(\$|\.L)func_end[0-9]+:\n', # $func_end0: (mips32 - O32) or
- # .Lfunc_end0: (mips64 - NewABI)
- flags=(re.M | re.S))
+ r"(?:(^[ \t]+\.set[^\n]*?\n)*^[ \t]+\.end.*?\n)"
+ r"(\$|\.L)func_end[0-9]+:\n", # $func_end0: (mips32 - O32) or
+ # .Lfunc_end0: (mips64 - NewABI)
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_MSP430_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@"?(?P=func)"?\n[^:]*?'
- r'(?P<body>.*?)\n'
- r'(\$|\.L)func_end[0-9]+:\n', # $func_end0:
- flags=(re.M | re.S))
+ r"(?P<body>.*?)\n"
+ r"(\$|\.L)func_end[0-9]+:\n", # $func_end0:
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_AVR_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@"?(?P=func)"?\n[^:]*?'
- r'(?P<body>.*?)\n'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?P<body>.*?)\n"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_PPC_RE = re.compile(
- r'#[ \-\t]*Begin function (?P<func>[^.:]+)\n'
- r'.*?'
+ r"#[ \-\t]*Begin function (?P<func>[^.:]+)\n"
+ r".*?"
r'^[_.]?(?P=func):(?:[ \t]*#+[ \t]*@"?(?P=func)"?)?\n'
- r'(?:^[^#]*\n)*'
- r'(?P<body>.*?)\n'
+ r"(?:^[^#]*\n)*"
+ r"(?P<body>.*?)\n"
# This list is incomplete
- r'(?:^[ \t]*(?:\.(?:long|quad|v?byte)[ \t]+[^\n]+)\n)*'
- r'(?:\.Lfunc_end|L\.\.(?P=func))[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?:^[ \t]*(?:\.(?:long|quad|v?byte)[ \t]+[^\n]+)\n)*"
+ r"(?:\.Lfunc_end|L\.\.(?P=func))[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_RISCV_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
- r'(?:\s*\.?L(?P=func)\$local:\n)?' # optional .L<func>$local: due to -fno-semantic-interposition
- r'(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?' # optional .type .L<func>$local
- r'(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?'
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?:\s*\.?L(?P=func)\$local:\n)?" # optional .L<func>$local: due to -fno-semantic-interposition
+ r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?" # optional .type .L<func>$local
+ r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
+ r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_LANAI_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@"?(?P=func)"?\n'
- r'(?:[ \t]+.cfi_startproc\n)?' # drop optional cfi noise
- r'(?P<body>.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?:[ \t]+.cfi_startproc\n)?" # drop optional cfi noise
+ r"(?P<body>.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_SPARC_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@"?(?P=func)"?\n'
- r'(?P<body>.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?P<body>.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_SYSTEMZ_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
- r'(?:[ \t]+.cfi_startproc\n)?'
- r'(?P<body>.*?)\n'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"(?:[ \t]+.cfi_startproc\n)?"
+ r"(?P<body>.*?)\n"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_AARCH64_DARWIN_RE = re.compile(
r'^_(?P<func>[^:]+):[ \t]*;[ \t]@"?(?P=func)"?\n'
- r'([ \t]*.cfi_startproc\n[\s]*)?'
- r'(?P<body>.*?)'
- r'([ \t]*.cfi_endproc\n[\s]*)?'
- r'^[ \t]*;[ \t]--[ \t]End[ \t]function',
- flags=(re.M | re.S))
+ r"([ \t]*.cfi_startproc\n[\s]*)?"
+ r"(?P<body>.*?)"
+ r"([ \t]*.cfi_endproc\n[\s]*)?"
+ r"^[ \t]*;[ \t]--[ \t]End[ \t]function",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_ARM_DARWIN_RE = re.compile(
- r'@[ \t]--[ \t]Begin[ \t]function[ \t](?P<func>[^ \t]+?)\n'
- r'^[ \t]*\.globl[ \t]*_(?P=func)[ \t]*'
- r'(?P<directives>.*?)'
- r'^_(?P=func):\n[ \t]*'
- r'(?P<body>.*?)'
- r'^[ \t]*@[ \t]--[ \t]End[ \t]function',
- flags=(re.M | re.S ))
+ r"@[ \t]--[ \t]Begin[ \t]function[ \t](?P<func>[^ \t]+?)\n"
+ r"^[ \t]*\.globl[ \t]*_(?P=func)[ \t]*"
+ r"(?P<directives>.*?)"
+ r"^_(?P=func):\n[ \t]*"
+ r"(?P<body>.*?)"
+ r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_ARM_MACHO_RE = re.compile(
- r'^_(?P<func>[^:]+):[ \t]*\n'
- r'([ \t]*.cfi_startproc\n[ \t]*)?'
- r'(?P<body>.*?)\n'
- r'[ \t]*\.cfi_endproc\n',
- flags=(re.M | re.S))
+ r"^_(?P<func>[^:]+):[ \t]*\n"
+ r"([ \t]*.cfi_startproc\n[ \t]*)?"
+ r"(?P<body>.*?)\n"
+ r"[ \t]*\.cfi_endproc\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_THUMBS_DARWIN_RE = re.compile(
- r'^_(?P<func>[^:]+):\n'
- r'(?P<body>.*?)\n'
- r'[ \t]*\.data_region\n',
- flags=(re.M | re.S))
+ r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)\n" r"[ \t]*\.data_region\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_THUMB_DARWIN_RE = re.compile(
- r'^_(?P<func>[^:]+):\n'
- r'(?P<body>.*?)\n'
- r'^[ \t]*@[ \t]--[ \t]End[ \t]function',
- flags=(re.M | re.S))
+ r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)\n" r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_ARM_IOS_RE = re.compile(
- r'^_(?P<func>[^:]+):\n'
- r'(?P<body>.*?)'
- r'^[ \t]*@[ \t]--[ \t]End[ \t]function',
- flags=(re.M | re.S))
+ r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)" r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_WASM_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
- r'(?P<body>.*?)\n'
- r'^\s*(\.Lfunc_end[0-9]+:\n|end_function)',
- flags=(re.M | re.S))
+ r"(?P<body>.*?)\n"
+ r"^\s*(\.Lfunc_end[0-9]+:\n|end_function)",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_VE_RE = re.compile(
- r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n'
- r'(?:\s*\.?L(?P=func)\$local:\n)?' # optional .L<func>$local: due to -fno-semantic-interposition
- r'(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?' # optional .type .L<func>$local
- r'(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?'
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n"
+ r"(?:\s*\.?L(?P=func)\$local:\n)?" # optional .L<func>$local: due to -fno-semantic-interposition
+ r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?" # optional .type .L<func>$local
+ r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
+ r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_CSKY_RE = re.compile(
- r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?'
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
+ r"^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
+ r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_NVPTX_RE = re.compile(
# function attributes and retval
# .visible .func (.param .align 16 .b8 func_retval0[32])
- #r'^(\.visible\s+)?\.func\s+(\([^\)]*\)\s*)?'
- r'^(\.(func|visible|weak|entry|noreturn|extern)\s+)+(\([^\)]*\)\s*)?'
-
+ # r'^(\.visible\s+)?\.func\s+(\([^\)]*\)\s*)?'
+ r"^(\.(func|visible|weak|entry|noreturn|extern)\s+)+(\([^\)]*\)\s*)?"
# function name
- r'(?P<func>[^\(\n]+)'
-
+ r"(?P<func>[^\(\n]+)"
# function name separator (opening brace)
- r'(?P<func_name_separator>\()'
-
+ r"(?P<func_name_separator>\()"
# function parameters
# (
# .param .align 16 .b8 callee_St8x4_param_0[32]
# ) // -- Begin function callee_St8x4
- r'[^\)]*\)(\s*//[^\n]*)?\n'
-
+ r"[^\)]*\)(\s*//[^\n]*)?\n"
# function body
- r'(?P<body>.*?)\n'
-
+ r"(?P<body>.*?)\n"
# function body end marker
- r'\s*// -- End function',
- flags=(re.M | re.S))
+ r"\s*// -- End function",
+ flags=(re.M | re.S),
+)
ASM_FUNCTION_LOONGARCH_RE = re.compile(
r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
- r'(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?'
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'.Lfunc_end[0-9]+:\n',
- flags=(re.M | re.S))
-
-SCRUB_X86_SHUFFLES_RE = (
- re.compile(
- r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$',
- flags=re.M))
-
-SCRUB_X86_SHUFFLES_NO_MEM_RE = (
- re.compile(
- r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = (?!.*(?:mem)).*)$',
- flags=re.M))
-
-SCRUB_X86_SPILL_RELOAD_RE = (
- re.compile(
- r'-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$',
- flags=re.M))
-SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
-SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
-SCRUB_X86_LCP_RE = re.compile(r'\.?LCPI[0-9]+_[0-9]+')
-SCRUB_X86_RET_RE = re.compile(r'ret[l|q]')
+ r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
+ r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
+ r".Lfunc_end[0-9]+:\n",
+ flags=(re.M | re.S),
+)
+
+SCRUB_X86_SHUFFLES_RE = re.compile(
+ r"^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$", flags=re.M
+)
+
+SCRUB_X86_SHUFFLES_NO_MEM_RE = re.compile(
+ r"^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = (?!.*(?:mem)).*)$",
+ flags=re.M,
+)
+
+SCRUB_X86_SPILL_RELOAD_RE = re.compile(
+ r"-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$", flags=re.M
+)
+SCRUB_X86_SP_RE = re.compile(r"\d+\(%(esp|rsp)\)")
+SCRUB_X86_RIP_RE = re.compile(r"[.\w]+\(%rip\)")
+SCRUB_X86_LCP_RE = re.compile(r"\.?LCPI[0-9]+_[0-9]+")
+SCRUB_X86_RET_RE = re.compile(r"ret[l|q]")
+
def scrub_asm_x86(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
-
- # Detect shuffle asm comments and hide the operands in favor of the comments.
- if getattr(args, 'no_x86_scrub_mem_shuffle', True):
- asm = SCRUB_X86_SHUFFLES_NO_MEM_RE.sub(r'\1 {{.*#+}} \2', asm)
- else:
- asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm)
-
- # Detect stack spills and reloads and hide their exact offset and whether
- # they used the stack pointer or frame pointer.
- asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r'{{[-0-9]+}}(%\1{{[sb]}}p)\2', asm)
- if getattr(args, 'x86_scrub_sp', True):
- # Generically match the stack offset of a memory operand.
- asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm)
- if getattr(args, 'x86_scrub_rip', False):
- # Generically match a RIP-relative memory operand.
- asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm)
- # Generically match a LCP symbol.
- asm = SCRUB_X86_LCP_RE.sub(r'{{\.?LCPI[0-9]+_[0-9]+}}', asm)
- if getattr(args, 'extra_scrub', False):
- # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'.
- asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm)
- # Strip kill operands inserted into the asm.
- asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+
+ # Detect shuffle asm comments and hide the operands in favor of the comments.
+ if getattr(args, "no_x86_scrub_mem_shuffle", True):
+ asm = SCRUB_X86_SHUFFLES_NO_MEM_RE.sub(r"\1 {{.*#+}} \2", asm)
+ else:
+ asm = SCRUB_X86_SHUFFLES_RE.sub(r"\1 {{.*#+}} \2", asm)
+
+ # Detect stack spills and reloads and hide their exact offset and whether
+ # they used the stack pointer or frame pointer.
+ asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r"{{[-0-9]+}}(%\1{{[sb]}}p)\2", asm)
+ if getattr(args, "x86_scrub_sp", True):
+ # Generically match the stack offset of a memory operand.
+ asm = SCRUB_X86_SP_RE.sub(r"{{[0-9]+}}(%\1)", asm)
+ if getattr(args, "x86_scrub_rip", False):
+ # Generically match a RIP-relative memory operand.
+ asm = SCRUB_X86_RIP_RE.sub(r"{{.*}}(%rip)", asm)
+ # Generically match a LCP symbol.
+ asm = SCRUB_X86_LCP_RE.sub(r"{{\.?LCPI[0-9]+_[0-9]+}}", asm)
+ if getattr(args, "extra_scrub", False):
+ # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'.
+ asm = SCRUB_X86_RET_RE.sub(r"ret{{[l|q]}}", asm)
+ # Strip kill operands inserted into the asm.
+ asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_amdgpu(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_arm_eabi(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip kill operands inserted into the asm.
- asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip kill operands inserted into the asm.
+ asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_bpf(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_hexagon(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_powerpc(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip unimportant comments, but leave the token '#' in place.
- asm = common.SCRUB_LOOP_COMMENT_RE.sub(r'#', asm)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- # Strip the tailing token '#', except the line only has token '#'.
- asm = common.SCRUB_TAILING_COMMENT_TOKEN_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip unimportant comments, but leave the token '#' in place.
+ asm = common.SCRUB_LOOP_COMMENT_RE.sub(r"#", asm)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ # Strip the tailing token '#', except the line only has token '#'.
+ asm = common.SCRUB_TAILING_COMMENT_TOKEN_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_m68k(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_mips(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_msp430(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_avr(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_riscv(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_lanai(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_sparc(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_systemz(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_wasm(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_ve(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_csky(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip kill operands inserted into the asm.
- asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip kill operands inserted into the asm.
+ asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_nvptx(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
def scrub_asm_loongarch(asm, args):
- # Scrub runs of whitespace out of the assembly, but leave the leading
- # whitespace in place.
- asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
- # Expand the tabs used for indentation.
- asm = string.expandtabs(asm, 2)
- # Strip trailing whitespace.
- asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
- return asm
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
+ # Expand the tabs used for indentation.
+ asm = string.expandtabs(asm, 2)
+ # Strip trailing whitespace.
+ asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
+ return asm
+
# Returns a tuple of a scrub function and a function regex. Scrub function is
# used to alter function body in some way, for example, remove trailing spaces.
# Function regex is used to match function name, body, etc. in raw llc output.
def get_run_handler(triple):
- target_handlers = {
- 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
- 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
- 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
- 'arm64_32-apple-ios': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'arm64_32-apple-watchos2.0.0': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
- 'aarch64-apple-darwin': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'aarch64-apple-ios': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'bpf': (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
- 'bpfel': (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
- 'bpfeb': (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
- 'hexagon': (scrub_asm_hexagon, ASM_FUNCTION_HEXAGON_RE),
- 'r600': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
- 'amdgcn': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
- 'arm': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
- 'arm64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
- 'arm64e': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'arm64ec': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
- 'arm64-apple-ios': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
- 'armv7-apple-ios' : (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
- 'armv7-apple-darwin': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_DARWIN_RE),
- 'thumb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
- 'thumb-macho': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
- 'thumbv5-macho': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
- 'thumbv7s-apple-darwin' : (scrub_asm_arm_eabi, ASM_FUNCTION_THUMBS_DARWIN_RE),
- 'thumbv7-apple-darwin' : (scrub_asm_arm_eabi, ASM_FUNCTION_THUMB_DARWIN_RE),
- 'thumbv7-apple-ios' : (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
- 'm68k': (scrub_asm_m68k, ASM_FUNCTION_M68K_RE),
- 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE),
- 'msp430': (scrub_asm_msp430, ASM_FUNCTION_MSP430_RE),
- 'avr': (scrub_asm_avr, ASM_FUNCTION_AVR_RE),
- 'ppc32': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
- 'ppc64': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
- 'powerpc': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
- 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
- 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
- 'lanai': (scrub_asm_lanai, ASM_FUNCTION_LANAI_RE),
- 'sparc': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE),
- 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE),
- 'wasm32': (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
- 'wasm64': (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
- 've': (scrub_asm_ve, ASM_FUNCTION_VE_RE),
- 'csky': (scrub_asm_csky, ASM_FUNCTION_CSKY_RE),
- 'nvptx': (scrub_asm_nvptx, ASM_FUNCTION_NVPTX_RE),
- 'loongarch32': (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
- 'loongarch64': (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE)
- }
- handler = None
- best_prefix = ''
- for prefix, s in target_handlers.items():
- if triple.startswith(prefix) and len(prefix) > len(best_prefix):
- handler = s
- best_prefix = prefix
-
- if handler is None:
- raise KeyError('Triple %r is not supported' % (triple))
-
- return handler
+ target_handlers = {
+ "i686": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
+ "x86": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
+ "i386": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
+ "arm64_32-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+ "arm64_32-apple-watchos2.0.0": (
+ scrub_asm_arm_eabi,
+ ASM_FUNCTION_AARCH64_DARWIN_RE,
+ ),
+ "aarch64": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
+ "aarch64-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+ "aarch64-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+ "bpf": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
+ "bpfel": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
+ "bpfeb": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
+ "hexagon": (scrub_asm_hexagon, ASM_FUNCTION_HEXAGON_RE),
+ "r600": (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
+ "amdgcn": (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
+ "arm": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
+ "arm64": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
+ "arm64e": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+ "arm64ec": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
+ "arm64-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+ "armv7-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
+ "armv7-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_DARWIN_RE),
+ "thumb": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
+ "thumb-macho": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
+ "thumbv5-macho": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
+ "thumbv7s-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_THUMBS_DARWIN_RE),
+ "thumbv7-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_THUMB_DARWIN_RE),
+ "thumbv7-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
+ "m68k": (scrub_asm_m68k, ASM_FUNCTION_M68K_RE),
+ "mips": (scrub_asm_mips, ASM_FUNCTION_MIPS_RE),
+ "msp430": (scrub_asm_msp430, ASM_FUNCTION_MSP430_RE),
+ "avr": (scrub_asm_avr, ASM_FUNCTION_AVR_RE),
+ "ppc32": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
+ "ppc64": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
+ "powerpc": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
+ "riscv32": (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
+ "riscv64": (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
+ "lanai": (scrub_asm_lanai, ASM_FUNCTION_LANAI_RE),
+ "sparc": (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE),
+ "s390x": (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE),
+ "wasm32": (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
+ "wasm64": (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
+ "ve": (scrub_asm_ve, ASM_FUNCTION_VE_RE),
+ "csky": (scrub_asm_csky, ASM_FUNCTION_CSKY_RE),
+ "nvptx": (scrub_asm_nvptx, ASM_FUNCTION_NVPTX_RE),
+ "loongarch32": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
+ "loongarch64": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
+ }
+ handler = None
+ best_prefix = ""
+ for prefix, s in target_handlers.items():
+ if triple.startswith(prefix) and len(prefix) > len(best_prefix):
+ handler = s
+ best_prefix = prefix
+
+ if handler is None:
+ raise KeyError("Triple %r is not supported" % (triple))
+
+ return handler
+
##### Generator of assembly CHECK lines
-def add_checks(output_lines, comment_marker, prefix_list, func_dict,
- func_name, global_vars_seen_dict, is_filtered):
- # Label format is based on ASM string.
- check_label_format = '{} %s-LABEL: %s%s%s%s'.format(comment_marker)
- return common.add_checks(output_lines, comment_marker, prefix_list, func_dict,
- func_name, check_label_format, True, False, 1,
- global_vars_seen_dict, is_filtered=is_filtered)
+
+def add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ global_vars_seen_dict,
+ is_filtered,
+):
+ # Label format is based on ASM string.
+ check_label_format = "{} %s-LABEL: %s%s%s%s".format(comment_marker)
+ return common.add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ check_label_format,
+ True,
+ False,
+ 1,
+ global_vars_seen_dict,
+ is_filtered=is_filtered,
+ )
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index aa0b128..b22d7e3 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -16,7 +16,7 @@ from typing import List
_verbose = False
-_prefix_filecheck_ir_name = ''
+_prefix_filecheck_ir_name = ""
"""
Version changelog:
@@ -27,792 +27,1028 @@ Version changelog:
"""
DEFAULT_VERSION = 2
+
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.
+ """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 __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 search(self, line):
- return self.regex.search(line)
+ def sub(self, repl, line):
+ return self.regex.sub(repl, line)
- def sub(self, repl, line):
- return self.regex.sub(repl, line)
+ def pattern(self):
+ return self.regex.pattern
- def pattern(self):
- return self.regex.pattern
+ def flags(self):
+ return self.regex.flags
- def flags(self):
- return self.regex.flags
class Filter(Regex):
- """Augment a Regex object with a flag indicating whether a match should be
+ """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 __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 __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',
- help='Show verbose output')
- parser.add_argument('-u', '--update-only', action='store_true',
- help='Only update test if it was already autogened')
- parser.add_argument('--force-update', action='store_true',
- help='Update test even if it was autogened by a different script')
- parser.add_argument('--enable', action='store_true', dest='enabled', default=True,
- help='Activate CHECK line generation from this point forward')
- parser.add_argument('--disable', action='store_false', dest='enabled',
- help='Deactivate CHECK line generation from this point forward')
- parser.add_argument('--replace-value-regex', nargs='+', default=[],
- help='List of regular expressions to replace matching value names')
- parser.add_argument('--prefix-filecheck-ir-name', default='',
- help='Add a prefix to FileCheck IR value names to avoid conflicts with scripted names')
- parser.add_argument('--global-value-regex', nargs='+', default=[],
- help='List of regular expressions that a global value declaration must match to generate a check (has no effect if checking globals is not enabled)')
- parser.add_argument('--global-hex-value-regex', nargs='+', default=[],
- help='List of regular expressions such that, for matching global value declarations, literal integer values should be encoded in hex in the associated FileCheck directives')
- # FIXME: in 3.9, we can use argparse.BooleanOptionalAction. At that point,
- # we need to rename the flag to just -generate-body-for-unused-prefixes.
- parser.add_argument('--no-generate-body-for-unused-prefixes',
- action='store_false',
- dest='gen_unused_prefix_body',
- default=True,
- help='Generate a function body that always matches for unused prefixes. This is useful when unused prefixes are desired, and it avoids needing to annotate each FileCheck as allowing them.')
- # This is the default when regenerating existing tests. The default when
- # generating new tests is determined by DEFAULT_VERSION.
- parser.add_argument('--version', type=int, default=1,
- help='The version of output format')
- args = parser.parse_args()
- global _verbose, _global_value_regex, _global_hex_value_regex
- _verbose = args.verbose
- _global_value_regex = args.global_value_regex
- _global_hex_value_regex = args.global_hex_value_regex
- return args
+ 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", help="Show verbose output"
+ )
+ parser.add_argument(
+ "-u",
+ "--update-only",
+ action="store_true",
+ help="Only update test if it was already autogened",
+ )
+ parser.add_argument(
+ "--force-update",
+ action="store_true",
+ help="Update test even if it was autogened by a different script",
+ )
+ parser.add_argument(
+ "--enable",
+ action="store_true",
+ dest="enabled",
+ default=True,
+ help="Activate CHECK line generation from this point forward",
+ )
+ parser.add_argument(
+ "--disable",
+ action="store_false",
+ dest="enabled",
+ help="Deactivate CHECK line generation from this point forward",
+ )
+ parser.add_argument(
+ "--replace-value-regex",
+ nargs="+",
+ default=[],
+ help="List of regular expressions to replace matching value names",
+ )
+ parser.add_argument(
+ "--prefix-filecheck-ir-name",
+ default="",
+ help="Add a prefix to FileCheck IR value names to avoid conflicts with scripted names",
+ )
+ parser.add_argument(
+ "--global-value-regex",
+ nargs="+",
+ default=[],
+ help="List of regular expressions that a global value declaration must match to generate a check (has no effect if checking globals is not enabled)",
+ )
+ parser.add_argument(
+ "--global-hex-value-regex",
+ nargs="+",
+ default=[],
+ help="List of regular expressions such that, for matching global value declarations, literal integer values should be encoded in hex in the associated FileCheck directives",
+ )
+ # FIXME: in 3.9, we can use argparse.BooleanOptionalAction. At that point,
+ # we need to rename the flag to just -generate-body-for-unused-prefixes.
+ parser.add_argument(
+ "--no-generate-body-for-unused-prefixes",
+ action="store_false",
+ dest="gen_unused_prefix_body",
+ default=True,
+ help="Generate a function body that always matches for unused prefixes. This is useful when unused prefixes are desired, and it avoids needing to annotate each FileCheck as allowing them.",
+ )
+ # This is the default when regenerating existing tests. The default when
+ # generating new tests is determined by DEFAULT_VERSION.
+ parser.add_argument(
+ "--version", type=int, default=1, help="The version of output format"
+ )
+ args = parser.parse_args()
+ global _verbose, _global_value_regex, _global_hex_value_regex
+ _verbose = args.verbose
+ _global_value_regex = args.global_value_regex
+ _global_hex_value_regex = args.global_hex_value_regex
+ return args
+
def parse_args(parser, argv):
- args = parser.parse_args(argv)
- if args.version >= 2:
- args.function_signature = True
- return args
+ args = parser.parse_args(argv)
+ if args.version >= 2:
+ args.function_signature = True
+ return args
+
class InputLineInfo(object):
- def __init__(self, line, line_number, args, argv):
- self.line = line
- self.line_number = line_number
- self.args = args
- self.argv = argv
+ def __init__(self, line, line_number, args, argv):
+ self.line = line
+ self.line_number = line_number
+ self.args = args
+ self.argv = argv
class TestInfo(object):
- def __init__(self, test, parser, script_name, input_lines, args, argv,
- comment_prefix, argparse_callback):
- self.parser = parser
- self.argparse_callback = argparse_callback
- self.path = test
- self.args = args
- if args.prefix_filecheck_ir_name:
- global _prefix_filecheck_ir_name
- _prefix_filecheck_ir_name = args.prefix_filecheck_ir_name
- self.argv = argv
- self.input_lines = input_lines
- self.run_lines = find_run_lines(test, self.input_lines)
- self.comment_prefix = comment_prefix
- if self.comment_prefix is None:
- if self.path.endswith('.mir'):
- self.comment_prefix = '#'
- else:
- self.comment_prefix = ';'
- self.autogenerated_note_prefix = self.comment_prefix + ' ' + UTC_ADVERT
- self.test_autogenerated_note = self.autogenerated_note_prefix + script_name
- self.test_autogenerated_note += get_autogennote_suffix(parser, self.args)
- self.test_unused_note = self.comment_prefix + self.comment_prefix + ' ' + UNUSED_NOTE
-
- def ro_iterlines(self):
- for line_num, input_line in enumerate(self.input_lines):
- args, argv = check_for_command(input_line, self.parser,
- self.args, self.argv, self.argparse_callback)
- yield InputLineInfo(input_line, line_num, args, argv)
-
- def iterlines(self, output_lines):
- output_lines.append(self.test_autogenerated_note)
- for line_info in self.ro_iterlines():
- input_line = line_info.line
- # Discard any previous script advertising.
- if input_line.startswith(self.autogenerated_note_prefix):
- continue
- self.args = line_info.args
- self.argv = line_info.argv
- if not self.args.enabled:
- output_lines.append(input_line)
- continue
- yield line_info
-
- def get_checks_for_unused_prefixes(self, run_list, used_prefixes: List[str]) -> List[str]:
- run_list = [element for element in run_list if element[0] is not None]
- unused_prefixes = set([
- prefix for sublist in run_list for prefix in sublist[0]
- ]).difference(set(used_prefixes))
-
- ret = []
- if not unused_prefixes:
- return ret
- ret.append(self.test_unused_note)
- for unused in sorted(unused_prefixes):
- ret.append('{comment} {prefix}: {match_everything}'.format(
- comment=self.comment_prefix,
- prefix=unused,
- match_everything=r"""{{.*}}"""
- ))
- return ret
-
-def itertests(test_patterns, parser, script_name, comment_prefix=None, argparse_callback=None):
- for pattern in test_patterns:
- # On Windows we must expand the patterns ourselves.
- tests_list = glob.glob(pattern)
- if not tests_list:
- warn("Test file pattern '%s' was not found. Ignoring it." % (pattern,))
- continue
- for test in tests_list:
- with open(test) as f:
- input_lines = [l.rstrip() for l in f]
- first_line = input_lines[0] if input_lines else ""
- is_regenerate = UTC_ADVERT in first_line
-
- # If we're generating a new test, set the default version to the latest.
- argv = sys.argv[:]
- if not is_regenerate:
- argv.insert(1, '--version=' + str(DEFAULT_VERSION))
-
- args = parse_args(parser, argv[1:])
- if argparse_callback is not None:
- argparse_callback(args)
- if is_regenerate:
- if script_name not in first_line and not args.force_update:
- warn("Skipping test which wasn't autogenerated by " + script_name, test)
- continue
- args, argv = check_for_command(first_line, parser, args, argv, argparse_callback)
- elif args.update_only:
- assert UTC_ADVERT not in first_line
- warn("Skipping test which isn't autogenerated: " + test)
- continue
- final_input_lines = []
- for l in input_lines:
- if UNUSED_NOTE in l:
- break
- final_input_lines.append(l)
- yield TestInfo(test, parser, script_name, final_input_lines, args, argv,
- comment_prefix, argparse_callback)
-
-
-def should_add_line_to_output(input_line, prefix_set, skip_global_checks = False, comment_marker = ';'):
- # Skip any blank comment lines in the IR.
- if not skip_global_checks and input_line.strip() == comment_marker:
- return False
- # Skip a special double comment line we use as a separator.
- if input_line.strip() == comment_marker + SEPARATOR:
- return False
- # Skip any blank lines in the IR.
- #if input_line.strip() == '':
- # return False
- # And skip any CHECK lines. We're building our own.
- m = CHECK_RE.match(input_line)
- if m and m.group(1) in prefix_set:
- if skip_global_checks:
- global_ir_value_re = re.compile(r'\[\[', flags=(re.M))
- return not global_ir_value_re.search(input_line)
- return False
-
- return True
+ def __init__(
+ self,
+ test,
+ parser,
+ script_name,
+ input_lines,
+ args,
+ argv,
+ comment_prefix,
+ argparse_callback,
+ ):
+ self.parser = parser
+ self.argparse_callback = argparse_callback
+ self.path = test
+ self.args = args
+ if args.prefix_filecheck_ir_name:
+ global _prefix_filecheck_ir_name
+ _prefix_filecheck_ir_name = args.prefix_filecheck_ir_name
+ self.argv = argv
+ self.input_lines = input_lines
+ self.run_lines = find_run_lines(test, self.input_lines)
+ self.comment_prefix = comment_prefix
+ if self.comment_prefix is None:
+ if self.path.endswith(".mir"):
+ self.comment_prefix = "#"
+ else:
+ self.comment_prefix = ";"
+ self.autogenerated_note_prefix = self.comment_prefix + " " + UTC_ADVERT
+ self.test_autogenerated_note = self.autogenerated_note_prefix + script_name
+ self.test_autogenerated_note += get_autogennote_suffix(parser, self.args)
+ self.test_unused_note = (
+ self.comment_prefix + self.comment_prefix + " " + UNUSED_NOTE
+ )
+
+ def ro_iterlines(self):
+ for line_num, input_line in enumerate(self.input_lines):
+ args, argv = check_for_command(
+ input_line, self.parser, self.args, self.argv, self.argparse_callback
+ )
+ yield InputLineInfo(input_line, line_num, args, argv)
+
+ def iterlines(self, output_lines):
+ output_lines.append(self.test_autogenerated_note)
+ for line_info in self.ro_iterlines():
+ input_line = line_info.line
+ # Discard any previous script advertising.
+ if input_line.startswith(self.autogenerated_note_prefix):
+ continue
+ self.args = line_info.args
+ self.argv = line_info.argv
+ if not self.args.enabled:
+ output_lines.append(input_line)
+ continue
+ yield line_info
+
+ def get_checks_for_unused_prefixes(
+ self, run_list, used_prefixes: List[str]
+ ) -> List[str]:
+ run_list = [element for element in run_list if element[0] is not None]
+ unused_prefixes = set(
+ [prefix for sublist in run_list for prefix in sublist[0]]
+ ).difference(set(used_prefixes))
+
+ ret = []
+ if not unused_prefixes:
+ return ret
+ ret.append(self.test_unused_note)
+ for unused in sorted(unused_prefixes):
+ ret.append(
+ "{comment} {prefix}: {match_everything}".format(
+ comment=self.comment_prefix,
+ prefix=unused,
+ match_everything=r"""{{.*}}""",
+ )
+ )
+ return ret
+
+
+def itertests(
+ test_patterns, parser, script_name, comment_prefix=None, argparse_callback=None
+):
+ for pattern in test_patterns:
+ # On Windows we must expand the patterns ourselves.
+ tests_list = glob.glob(pattern)
+ if not tests_list:
+ warn("Test file pattern '%s' was not found. Ignoring it." % (pattern,))
+ continue
+ for test in tests_list:
+ with open(test) as f:
+ input_lines = [l.rstrip() for l in f]
+ first_line = input_lines[0] if input_lines else ""
+ is_regenerate = UTC_ADVERT in first_line
+
+ # If we're generating a new test, set the default version to the latest.
+ argv = sys.argv[:]
+ if not is_regenerate:
+ argv.insert(1, "--version=" + str(DEFAULT_VERSION))
+
+ args = parse_args(parser, argv[1:])
+ if argparse_callback is not None:
+ argparse_callback(args)
+ if is_regenerate:
+ if script_name not in first_line and not args.force_update:
+ warn(
+ "Skipping test which wasn't autogenerated by " + script_name,
+ test,
+ )
+ continue
+ args, argv = check_for_command(
+ first_line, parser, args, argv, argparse_callback
+ )
+ elif args.update_only:
+ assert UTC_ADVERT not in first_line
+ warn("Skipping test which isn't autogenerated: " + test)
+ continue
+ final_input_lines = []
+ for l in input_lines:
+ if UNUSED_NOTE in l:
+ break
+ final_input_lines.append(l)
+ yield TestInfo(
+ test,
+ parser,
+ script_name,
+ final_input_lines,
+ args,
+ argv,
+ comment_prefix,
+ argparse_callback,
+ )
+
+
+def should_add_line_to_output(
+ input_line, prefix_set, skip_global_checks=False, comment_marker=";"
+):
+ # Skip any blank comment lines in the IR.
+ if not skip_global_checks and input_line.strip() == comment_marker:
+ return False
+ # Skip a special double comment line we use as a separator.
+ if input_line.strip() == comment_marker + SEPARATOR:
+ return False
+ # Skip any blank lines in the IR.
+ # if input_line.strip() == '':
+ # return False
+ # And skip any CHECK lines. We're building our own.
+ m = CHECK_RE.match(input_line)
+ if m and m.group(1) in prefix_set:
+ if skip_global_checks:
+ global_ir_value_re = re.compile(r"\[\[", flags=(re.M))
+ return not global_ir_value_re.search(input_line)
+ return False
+
+ return True
+
# Perform lit-like substitutions
def getSubstitutions(sourcepath):
- sourcedir = os.path.dirname(sourcepath)
- return [('%s', sourcepath),
- ('%S', sourcedir),
- ('%p', sourcedir),
- ('%{pathsep}', os.pathsep)]
+ sourcedir = os.path.dirname(sourcepath)
+ return [
+ ("%s", sourcepath),
+ ("%S", sourcedir),
+ ("%p", sourcedir),
+ ("%{pathsep}", os.pathsep),
+ ]
+
def applySubstitutions(s, substitutions):
- for a,b in substitutions:
- s = s.replace(a, b)
- return s
+ for a, b in substitutions:
+ s = s.replace(a, b)
+ return s
+
# Invoke the tool that is being tested.
def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
- with open(ir) as ir_file:
- substitutions = getSubstitutions(ir)
-
- # TODO Remove the str form which is used by update_test_checks.py and
- # update_llc_test_checks.py
- # The safer list form is used by update_cc_test_checks.py
- if preprocess_cmd:
- # Allow pre-processing the IR file (e.g. using sed):
- assert isinstance(preprocess_cmd, str) # TODO: use a list instead of using shell
- preprocess_cmd = applySubstitutions(preprocess_cmd, substitutions).strip()
- if verbose:
- print('Pre-processing input file: ', ir, " with command '",
- preprocess_cmd, "'", sep="", file=sys.stderr)
- # Python 2.7 doesn't have subprocess.DEVNULL:
- with open(os.devnull, 'w') as devnull:
- pp = subprocess.Popen(preprocess_cmd, shell=True, stdin=devnull,
- stdout=subprocess.PIPE)
- ir_file = pp.stdout
-
- if isinstance(cmd_args, list):
- args = [applySubstitutions(a, substitutions) for a in cmd_args]
- stdout = subprocess.check_output([exe] + args, stdin=ir_file)
- else:
- stdout = subprocess.check_output(exe + ' ' + applySubstitutions(cmd_args, substitutions),
- shell=True, stdin=ir_file)
- if sys.version_info[0] > 2:
- # FYI, if you crashed here with a decode error, your run line probably
- # results in bitcode or other binary format being written to the pipe.
- # For an opt test, you probably want to add -S or -disable-output.
- stdout = stdout.decode()
- # Fix line endings to unix CR style.
- return stdout.replace('\r\n', '\n')
+ with open(ir) as ir_file:
+ substitutions = getSubstitutions(ir)
+
+ # TODO Remove the str form which is used by update_test_checks.py and
+ # update_llc_test_checks.py
+ # The safer list form is used by update_cc_test_checks.py
+ if preprocess_cmd:
+ # Allow pre-processing the IR file (e.g. using sed):
+ assert isinstance(
+ preprocess_cmd, str
+ ) # TODO: use a list instead of using shell
+ preprocess_cmd = applySubstitutions(preprocess_cmd, substitutions).strip()
+ if verbose:
+ print(
+ "Pre-processing input file: ",
+ ir,
+ " with command '",
+ preprocess_cmd,
+ "'",
+ sep="",
+ file=sys.stderr,
+ )
+ # Python 2.7 doesn't have subprocess.DEVNULL:
+ with open(os.devnull, "w") as devnull:
+ pp = subprocess.Popen(
+ preprocess_cmd, shell=True, stdin=devnull, stdout=subprocess.PIPE
+ )
+ ir_file = pp.stdout
+
+ if isinstance(cmd_args, list):
+ args = [applySubstitutions(a, substitutions) for a in cmd_args]
+ stdout = subprocess.check_output([exe] + args, stdin=ir_file)
+ else:
+ stdout = subprocess.check_output(
+ exe + " " + applySubstitutions(cmd_args, substitutions),
+ shell=True,
+ stdin=ir_file,
+ )
+ if sys.version_info[0] > 2:
+ # FYI, if you crashed here with a decode error, your run line probably
+ # results in bitcode or other binary format being written to the pipe.
+ # For an opt test, you probably want to add -S or -disable-output.
+ stdout = stdout.decode()
+ # Fix line endings to unix CR style.
+ return stdout.replace("\r\n", "\n")
-##### LLVM IR parser
-RUN_LINE_RE = re.compile(r'^\s*(?://|[;#])\s*RUN:\s*(.*)$')
-CHECK_PREFIX_RE = re.compile(r'--?check-prefix(?:es)?[= ](\S+)')
-PREFIX_RE = re.compile('^[a-zA-Z0-9_-]+$')
-CHECK_RE = re.compile(r'^\s*(?://|[;#])\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAME|-EMPTY)?:')
-UTC_ARGS_KEY = 'UTC_ARGS:'
-UTC_ARGS_CMD = re.compile(r'.*' + UTC_ARGS_KEY + '\s*(?P<cmd>.*)\s*$')
-UTC_ADVERT = 'NOTE: Assertions have been autogenerated by '
-UNUSED_NOTE = 'NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:'
+##### LLVM IR parser
+RUN_LINE_RE = re.compile(r"^\s*(?://|[;#])\s*RUN:\s*(.*)$")
+CHECK_PREFIX_RE = re.compile(r"--?check-prefix(?:es)?[= ](\S+)")
+PREFIX_RE = re.compile("^[a-zA-Z0-9_-]+$")
+CHECK_RE = re.compile(
+ r"^\s*(?://|[;#])\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL|-SAME|-EMPTY)?:"
+)
+
+UTC_ARGS_KEY = "UTC_ARGS:"
+UTC_ARGS_CMD = re.compile(r".*" + UTC_ARGS_KEY + "\s*(?P<cmd>.*)\s*$")
+UTC_ADVERT = "NOTE: Assertions have been autogenerated by "
+UNUSED_NOTE = "NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:"
OPT_FUNCTION_RE = re.compile(
- r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s():,]+?))?\s*define\s+(?P<funcdef_attrs_and_ret>[^@]*)@(?P<func>[\w.$-]+?)\s*'
- r'(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P<body>.*?)^\}$',
- flags=(re.M | re.S))
+ r"^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s():,]+?))?\s*define\s+(?P<funcdef_attrs_and_ret>[^@]*)@(?P<func>[\w.$-]+?)\s*"
+ r"(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P<body>.*?)^\}$",
+ flags=(re.M | re.S),
+)
ANALYZE_FUNCTION_RE = re.compile(
- r'^\s*\'(?P<analysis>[\w\s-]+?)\'\s+for\s+function\s+\'(?P<func>[\w.$-]+?)\':'
- r'\s*\n(?P<body>.*)$',
- flags=(re.X | re.S))
+ r"^\s*\'(?P<analysis>[\w\s-]+?)\'\s+for\s+function\s+\'(?P<func>[\w.$-]+?)\':"
+ r"\s*\n(?P<body>.*)$",
+ flags=(re.X | re.S),
+)
LV_DEBUG_RE = re.compile(
- r'^\s*\'(?P<func>[\w.$-]+?)\'[^\n]*'
- r'\s*\n(?P<body>.*)$',
- flags=(re.X | re.S))
+ r"^\s*\'(?P<func>[\w.$-]+?)\'[^\n]*" r"\s*\n(?P<body>.*)$", flags=(re.X | re.S)
+)
IR_FUNCTION_RE = re.compile(r'^\s*define\s+(?:internal\s+)?[^@]*@"?([\w.$-]+)"?\s*\(')
TRIPLE_IR_RE = re.compile(r'^\s*target\s+triple\s*=\s*"([^"]+)"$')
-TRIPLE_ARG_RE = re.compile(r'-mtriple[= ]([^ ]+)')
-MARCH_ARG_RE = re.compile(r'-march[= ]([^ ]+)')
-DEBUG_ONLY_ARG_RE = re.compile(r'-debug-only[= ]([^ ]+)')
+TRIPLE_ARG_RE = re.compile(r"-mtriple[= ]([^ ]+)")
+MARCH_ARG_RE = re.compile(r"-march[= ]([^ ]+)")
+DEBUG_ONLY_ARG_RE = re.compile(r"-debug-only[= ]([^ ]+)")
-SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
-SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
-SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
+SCRUB_LEADING_WHITESPACE_RE = re.compile(r"^(\s+)")
+SCRUB_WHITESPACE_RE = re.compile(r"(?!^(| \w))[ \t]+", flags=re.M)
+SCRUB_TRAILING_WHITESPACE_RE = re.compile(r"[ \t]+$", flags=re.M)
SCRUB_TRAILING_WHITESPACE_TEST_RE = SCRUB_TRAILING_WHITESPACE_RE
-SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE = re.compile(r'([ \t]|(#[0-9]+))+$', flags=re.M)
-SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
+SCRUB_TRAILING_WHITESPACE_AND_ATTRIBUTES_RE = re.compile(
+ r"([ \t]|(#[0-9]+))+$", flags=re.M
+)
+SCRUB_KILL_COMMENT_RE = re.compile(r"^ *#+ +kill:.*\n")
SCRUB_LOOP_COMMENT_RE = re.compile(
- r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
-SCRUB_TAILING_COMMENT_TOKEN_RE = re.compile(r'(?<=\S)+[ \t]*#$', flags=re.M)
+ r"# =>This Inner Loop Header:.*|# in Loop:.*", flags=re.M
+)
+SCRUB_TAILING_COMMENT_TOKEN_RE = re.compile(r"(?<=\S)+[ \t]*#$", flags=re.M)
+
+SEPARATOR = "."
-SEPARATOR = '.'
def error(msg, test_file=None):
- if test_file:
- msg = '{}: {}'.format(msg, test_file)
- print('ERROR: {}'.format(msg), file=sys.stderr)
+ if test_file:
+ msg = "{}: {}".format(msg, test_file)
+ print("ERROR: {}".format(msg), file=sys.stderr)
+
def warn(msg, test_file=None):
- if test_file:
- msg = '{}: {}'.format(msg, test_file)
- print('WARNING: {}'.format(msg), file=sys.stderr)
+ if test_file:
+ msg = "{}: {}".format(msg, test_file)
+ print("WARNING: {}".format(msg), file=sys.stderr)
+
def debug(*args, **kwargs):
- # Python2 does not allow def debug(*args, file=sys.stderr, **kwargs):
- if 'file' not in kwargs:
- kwargs['file'] = sys.stderr
- if _verbose:
- print(*args, **kwargs)
+ # Python2 does not allow def debug(*args, file=sys.stderr, **kwargs):
+ if "file" not in kwargs:
+ kwargs["file"] = sys.stderr
+ if _verbose:
+ print(*args, **kwargs)
+
def find_run_lines(test, lines):
- debug('Scanning for RUN lines in test file:', test)
- raw_lines = [m.group(1)
- for m in [RUN_LINE_RE.match(l) for l in lines] if m]
- run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
- for l in raw_lines[1:]:
- if run_lines[-1].endswith('\\'):
- run_lines[-1] = run_lines[-1].rstrip('\\') + ' ' + l
- else:
- run_lines.append(l)
- debug('Found {} RUN lines in {}:'.format(len(run_lines), test))
- for l in run_lines:
- debug(' RUN: {}'.format(l))
- return run_lines
+ debug("Scanning for RUN lines in test file:", test)
+ raw_lines = [m.group(1) for m in [RUN_LINE_RE.match(l) for l in lines] if m]
+ run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
+ for l in raw_lines[1:]:
+ if run_lines[-1].endswith("\\"):
+ run_lines[-1] = run_lines[-1].rstrip("\\") + " " + l
+ else:
+ run_lines.append(l)
+ debug("Found {} RUN lines in {}:".format(len(run_lines), test))
+ for l in run_lines:
+ debug(" RUN: {}".format(l))
+ return run_lines
+
def get_triple_from_march(march):
- triples = {
- 'amdgcn': 'amdgcn',
- 'r600': 'r600',
- 'mips': 'mips',
- 'sparc': 'sparc',
- 'hexagon': 'hexagon',
- 've': 've',
- }
- for prefix, triple in triples.items():
- if march.startswith(prefix):
- return triple
- print("Cannot find a triple. Assume 'x86'", file=sys.stderr)
- return 'x86'
+ triples = {
+ "amdgcn": "amdgcn",
+ "r600": "r600",
+ "mips": "mips",
+ "sparc": "sparc",
+ "hexagon": "hexagon",
+ "ve": "ve",
+ }
+ for prefix, triple in triples.items():
+ if march.startswith(prefix):
+ return triple
+ print("Cannot find a triple. Assume 'x86'", file=sys.stderr)
+ return "x86"
+
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
+ 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()))
+ 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.
- body = SCRUB_WHITESPACE_RE.sub(r' ', body)
- # Expand the tabs used for indentation.
- body = str.expandtabs(body, 2)
- # Strip trailing whitespace.
- body = SCRUB_TRAILING_WHITESPACE_TEST_RE.sub(r'', body)
- return body
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ body = SCRUB_WHITESPACE_RE.sub(r" ", body)
+ # Expand the tabs used for indentation.
+ body = str.expandtabs(body, 2)
+ # Strip trailing whitespace.
+ body = SCRUB_TRAILING_WHITESPACE_TEST_RE.sub(r"", body)
+ return body
+
def do_scrub(body, scrubber, scrubber_args, extra):
- if scrubber_args:
- local_args = copy.deepcopy(scrubber_args)
- local_args[0].extra_scrub = extra
- return scrubber(body, *local_args)
- return scrubber(body, *scrubber_args)
+ if scrubber_args:
+ local_args = copy.deepcopy(scrubber_args)
+ local_args[0].extra_scrub = extra
+ return scrubber(body, *local_args)
+ return scrubber(body, *scrubber_args)
+
# Build up a dictionary of all the function bodies.
class function_body(object):
- def __init__(self, string, extra, funcdef_attrs_and_ret, args_and_sig, attrs, func_name_separator):
- self.scrub = string
- self.extrascrub = extra
- self.funcdef_attrs_and_ret = funcdef_attrs_and_ret
- self.args_and_sig = args_and_sig
- self.attrs = attrs
- self.func_name_separator = func_name_separator
- def is_same_except_arg_names(self, extrascrub, funcdef_attrs_and_ret, args_and_sig, attrs, is_backend):
- arg_names = set()
- def drop_arg_names(match):
- arg_names.add(match.group(variable_group_in_ir_value_match))
- if match.group(attribute_group_in_ir_value_match):
- attr = match.group(attribute_group_in_ir_value_match)
- else:
- attr = ''
- return match.group(1) + attr + match.group(match.lastindex)
- def repl_arg_names(match):
- if match.group(variable_group_in_ir_value_match) is not None and match.group(variable_group_in_ir_value_match) in arg_names:
- return match.group(1) + match.group(match.lastindex)
- return match.group(1) + match.group(2) + match.group(match.lastindex)
- if self.funcdef_attrs_and_ret != funcdef_attrs_and_ret:
- return False
- if self.attrs != attrs:
- return False
- ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig)
- ans1 = IR_VALUE_RE.sub(drop_arg_names, args_and_sig)
- if ans0 != ans1:
- return False
- if is_backend:
- # Check without replacements, the replacements are not applied to the
- # body for backend checks.
- return self.extrascrub == extrascrub
-
- es0 = IR_VALUE_RE.sub(repl_arg_names, self.extrascrub)
- es1 = IR_VALUE_RE.sub(repl_arg_names, extrascrub)
- es0 = SCRUB_IR_COMMENT_RE.sub(r'', es0)
- es1 = SCRUB_IR_COMMENT_RE.sub(r'', es1)
- return es0 == es1
-
- def __str__(self):
- return self.scrub
+ def __init__(
+ self,
+ string,
+ extra,
+ funcdef_attrs_and_ret,
+ args_and_sig,
+ attrs,
+ func_name_separator,
+ ):
+ self.scrub = string
+ self.extrascrub = extra
+ self.funcdef_attrs_and_ret = funcdef_attrs_and_ret
+ self.args_and_sig = args_and_sig
+ self.attrs = attrs
+ self.func_name_separator = func_name_separator
+
+ def is_same_except_arg_names(
+ self, extrascrub, funcdef_attrs_and_ret, args_and_sig, attrs, is_backend
+ ):
+ arg_names = set()
+
+ def drop_arg_names(match):
+ arg_names.add(match.group(variable_group_in_ir_value_match))
+ if match.group(attribute_group_in_ir_value_match):
+ attr = match.group(attribute_group_in_ir_value_match)
+ else:
+ attr = ""
+ return match.group(1) + attr + match.group(match.lastindex)
+
+ def repl_arg_names(match):
+ if (
+ match.group(variable_group_in_ir_value_match) is not None
+ and match.group(variable_group_in_ir_value_match) in arg_names
+ ):
+ return match.group(1) + match.group(match.lastindex)
+ return match.group(1) + match.group(2) + match.group(match.lastindex)
+
+ if self.funcdef_attrs_and_ret != funcdef_attrs_and_ret:
+ return False
+ if self.attrs != attrs:
+ return False
+ ans0 = IR_VALUE_RE.sub(drop_arg_names, self.args_and_sig)
+ ans1 = IR_VALUE_RE.sub(drop_arg_names, args_and_sig)
+ if ans0 != ans1:
+ return False
+ if is_backend:
+ # Check without replacements, the replacements are not applied to the
+ # body for backend checks.
+ return self.extrascrub == extrascrub
+
+ es0 = IR_VALUE_RE.sub(repl_arg_names, self.extrascrub)
+ es1 = IR_VALUE_RE.sub(repl_arg_names, extrascrub)
+ es0 = SCRUB_IR_COMMENT_RE.sub(r"", es0)
+ es1 = SCRUB_IR_COMMENT_RE.sub(r"", es1)
+ return es0 == es1
+
+ def __str__(self):
+ return self.scrub
+
class FunctionTestBuilder:
- def __init__(self, run_list, flags, scrubber_args, path):
- 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
- self._replace_value_regex = list(map(lambda x: x.strip('"'), flags.replace_value_regex))
- self._func_dict = {}
- self._func_order = {}
- self._global_var_dict = {}
- self._processed_prefixes = set()
- for tuple in run_list:
- for prefix in tuple[0]:
- self._func_dict.update({prefix: dict()})
- self._func_order.update({prefix: []})
- 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,))
- return self._func_dict
-
- def func_order(self):
- return self._func_order
-
- 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_backend):
- build_global_values_dictionary(self._global_var_dict, raw_tool_output, prefixes)
- for m in function_re.finditer(raw_tool_output):
- if not m:
- continue
- func = m.group('func')
- body = m.group('body')
- # func_name_separator is the string that is placed right after function name at the
- # beginning of assembly function definition. In most assemblies, that is just a
- # colon: `foo:`. But, for example, in nvptx it is a brace: `foo(`. If is_backend is
- # False, just assume that separator is an empty string.
- if is_backend:
- # Use ':' as default separator.
- func_name_separator = m.group('func_name_separator') if 'func_name_separator' in m.groupdict() else ':'
- else:
- func_name_separator = ''
- attrs = m.group('attrs') if self._check_attributes else ''
- funcdef_attrs_and_ret = m.group('funcdef_attrs_and_ret') if self._record_args else ''
- # Determine if we print arguments, the opening brace, or nothing after the
- # function name
- if self._record_args and 'args_and_sig' in m.groupdict():
- args_and_sig = scrub_body(m.group('args_and_sig').strip())
- elif 'args_and_sig' in m.groupdict():
- args_and_sig = '('
- else:
- args_and_sig = ''
- filtered_body = do_filter(body, self._filters)
- scrubbed_body = do_scrub(filtered_body, scrubber, self._scrubber_args,
- extra=False)
- scrubbed_extra = do_scrub(filtered_body, scrubber, self._scrubber_args,
- extra=True)
- if 'analysis' in m.groupdict():
- analysis = m.group('analysis')
- if analysis.lower() != 'cost model analysis':
- warn('Unsupported analysis mode: %r!' % (analysis,))
- if func.startswith('stress'):
- # We only use the last line of the function body for stress tests.
- scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
- if self._verbose:
- print('Processing function: ' + func, file=sys.stderr)
- for l in scrubbed_body.splitlines():
- print(' ' + l, file=sys.stderr)
- for prefix in prefixes:
- # Replace function names matching the regex.
- for regex in self._replace_value_regex:
- # Pattern that matches capture groups in the regex in leftmost order.
- group_regex = re.compile(r'\(.*?\)')
- # Replace function name with regex.
- match = re.match(regex, func)
- if match:
- func_repl = regex
- # Replace any capture groups with their matched strings.
- for g in match.groups():
- func_repl = group_regex.sub(re.escape(g), func_repl, count=1)
- func = re.sub(func_repl, '{{' + func_repl + '}}', func)
-
- # Replace all calls to regex matching functions.
- matches = re.finditer(regex, scrubbed_body)
- for match in matches:
- func_repl = regex
- # Replace any capture groups with their matched strings.
- for g in match.groups():
- func_repl = group_regex.sub(re.escape(g), func_repl, count=1)
- # Substitute function call names that match the regex with the same
- # capture groups set.
- scrubbed_body = re.sub(func_repl, '{{' + func_repl + '}}',
- scrubbed_body)
-
- if func in self._func_dict[prefix]:
- if (self._func_dict[prefix][func] is not None and
- (str(self._func_dict[prefix][func]) != scrubbed_body or
- self._func_dict[prefix][func].args_and_sig != args_and_sig or
- self._func_dict[prefix][func].attrs != attrs or
- self._func_dict[prefix][func].funcdef_attrs_and_ret != funcdef_attrs_and_ret)):
- if self._func_dict[prefix][func].is_same_except_arg_names(
- scrubbed_extra,
- funcdef_attrs_and_ret,
- args_and_sig,
- attrs,
- is_backend):
- self._func_dict[prefix][func].scrub = scrubbed_extra
- self._func_dict[prefix][func].args_and_sig = args_and_sig
+ def __init__(self, run_list, flags, scrubber_args, path):
+ 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
+ self._replace_value_regex = list(
+ map(lambda x: x.strip('"'), flags.replace_value_regex)
+ )
+ self._func_dict = {}
+ self._func_order = {}
+ self._global_var_dict = {}
+ self._processed_prefixes = set()
+ for tuple in run_list:
+ for prefix in tuple[0]:
+ self._func_dict.update({prefix: dict()})
+ self._func_order.update({prefix: []})
+ 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,
+ )
+ )
+ return self._func_dict
+
+ def func_order(self):
+ return self._func_order
+
+ 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_backend
+ ):
+ build_global_values_dictionary(self._global_var_dict, raw_tool_output, prefixes)
+ for m in function_re.finditer(raw_tool_output):
+ if not m:
+ continue
+ func = m.group("func")
+ body = m.group("body")
+ # func_name_separator is the string that is placed right after function name at the
+ # beginning of assembly function definition. In most assemblies, that is just a
+ # colon: `foo:`. But, for example, in nvptx it is a brace: `foo(`. If is_backend is
+ # False, just assume that separator is an empty string.
+ if is_backend:
+ # Use ':' as default separator.
+ func_name_separator = (
+ m.group("func_name_separator")
+ if "func_name_separator" in m.groupdict()
+ else ":"
+ )
else:
- # This means a previous RUN line produced a body for this function
- # that is different from the one produced by this current RUN line,
- # so the body can't be common across RUN lines. We use None to
- # indicate that.
- self._func_dict[prefix][func] = None
- else:
- if prefix not in self._processed_prefixes:
- self._func_dict[prefix][func] = function_body(
- scrubbed_body, scrubbed_extra, funcdef_attrs_and_ret,
- args_and_sig, attrs, func_name_separator)
- self._func_order[prefix].append(func)
- else:
- # An earlier RUN line used this check prefixes but didn't produce
- # a body for this function. This happens in Clang tests that use
- # preprocesser directives to exclude individual functions from some
- # RUN lines.
- self._func_dict[prefix][func] = None
-
- def processed_prefixes(self, prefixes):
- """
- Mark a set of prefixes as having had at least one applicable RUN line fully
- processed. This is used to filter out function bodies that don't have
- outputs for all RUN lines.
- """
- 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
+ func_name_separator = ""
+ attrs = m.group("attrs") if self._check_attributes else ""
+ funcdef_attrs_and_ret = (
+ m.group("funcdef_attrs_and_ret") if self._record_args else ""
+ )
+ # Determine if we print arguments, the opening brace, or nothing after the
+ # function name
+ if self._record_args and "args_and_sig" in m.groupdict():
+ args_and_sig = scrub_body(m.group("args_and_sig").strip())
+ elif "args_and_sig" in m.groupdict():
+ args_and_sig = "("
+ else:
+ args_and_sig = ""
+ filtered_body = do_filter(body, self._filters)
+ scrubbed_body = do_scrub(
+ filtered_body, scrubber, self._scrubber_args, extra=False
+ )
+ scrubbed_extra = do_scrub(
+ filtered_body, scrubber, self._scrubber_args, extra=True
+ )
+ if "analysis" in m.groupdict():
+ analysis = m.group("analysis")
+ if analysis.lower() != "cost model analysis":
+ warn("Unsupported analysis mode: %r!" % (analysis,))
+ if func.startswith("stress"):
+ # We only use the last line of the function body for stress tests.
+ scrubbed_body = "\n".join(scrubbed_body.splitlines()[-1:])
+ if self._verbose:
+ print("Processing function: " + func, file=sys.stderr)
+ for l in scrubbed_body.splitlines():
+ print(" " + l, file=sys.stderr)
+ for prefix in prefixes:
+ # Replace function names matching the regex.
+ for regex in self._replace_value_regex:
+ # Pattern that matches capture groups in the regex in leftmost order.
+ group_regex = re.compile(r"\(.*?\)")
+ # Replace function name with regex.
+ match = re.match(regex, func)
+ if match:
+ func_repl = regex
+ # Replace any capture groups with their matched strings.
+ for g in match.groups():
+ func_repl = group_regex.sub(
+ re.escape(g), func_repl, count=1
+ )
+ func = re.sub(func_repl, "{{" + func_repl + "}}", func)
+
+ # Replace all calls to regex matching functions.
+ matches = re.finditer(regex, scrubbed_body)
+ for match in matches:
+ func_repl = regex
+ # Replace any capture groups with their matched strings.
+ for g in match.groups():
+ func_repl = group_regex.sub(
+ re.escape(g), func_repl, count=1
+ )
+ # Substitute function call names that match the regex with the same
+ # capture groups set.
+ scrubbed_body = re.sub(
+ func_repl, "{{" + func_repl + "}}", scrubbed_body
+ )
+
+ if func in self._func_dict[prefix]:
+ if self._func_dict[prefix][func] is not None and (
+ str(self._func_dict[prefix][func]) != scrubbed_body
+ or self._func_dict[prefix][func].args_and_sig != args_and_sig
+ or self._func_dict[prefix][func].attrs != attrs
+ or self._func_dict[prefix][func].funcdef_attrs_and_ret
+ != funcdef_attrs_and_ret
+ ):
+ if self._func_dict[prefix][func].is_same_except_arg_names(
+ scrubbed_extra,
+ funcdef_attrs_and_ret,
+ args_and_sig,
+ attrs,
+ is_backend,
+ ):
+ self._func_dict[prefix][func].scrub = scrubbed_extra
+ self._func_dict[prefix][func].args_and_sig = args_and_sig
+ else:
+ # This means a previous RUN line produced a body for this function
+ # that is different from the one produced by this current RUN line,
+ # so the body can't be common across RUN lines. We use None to
+ # indicate that.
+ self._func_dict[prefix][func] = None
+ else:
+ if prefix not in self._processed_prefixes:
+ self._func_dict[prefix][func] = function_body(
+ scrubbed_body,
+ scrubbed_extra,
+ funcdef_attrs_and_ret,
+ args_and_sig,
+ attrs,
+ func_name_separator,
+ )
+ self._func_order[prefix].append(func)
+ else:
+ # An earlier RUN line used this check prefixes but didn't produce
+ # a body for this function. This happens in Clang tests that use
+ # preprocesser directives to exclude individual functions from some
+ # RUN lines.
+ self._func_dict[prefix][func] = None
+
+ def processed_prefixes(self, prefixes):
+ """
+ Mark a set of prefixes as having had at least one applicable RUN line fully
+ processed. This is used to filter out function bodies that don't have
+ outputs for all RUN lines.
+ """
+ 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
-SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*')
+SCRUB_IR_COMMENT_RE = re.compile(r"\s*;.*")
# TODO: We should also derive check lines for global, debug, loop declarations, etc..
+
class NamelessValue:
- def __init__(self, check_prefix, check_key, ir_prefix, ir_regexp,
- global_ir_rhs_regexp, *, is_before_functions=False, is_number=False,
- replace_number_with_counter=False):
- self.check_prefix = check_prefix
- self.check_key = check_key
- self.ir_prefix = ir_prefix
- self.ir_regexp = ir_regexp
- self.global_ir_rhs_regexp = global_ir_rhs_regexp
- self.is_before_functions = is_before_functions
- self.is_number = is_number
- # Some variable numbers (e.g. MCINST1234) will change based on unrelated
- # modifications to LLVM, replace those with an incrementing counter.
- self.replace_number_with_counter = replace_number_with_counter
- self.variable_mapping = {}
-
- # Return true if this kind of IR value is "local", basically if it matches '%{{.*}}'.
- def is_local_def_ir_value_match(self, match):
- return self.ir_prefix == '%'
-
- # Return true if this kind of IR value is "global", basically if it matches '#{{.*}}'.
- def is_global_scope_ir_value_match(self, match):
- return self.global_ir_rhs_regexp is not None
-
- # Return the IR prefix and check prefix we use for this kind or IR value,
- # e.g., (%, TMP) for locals.
- def get_ir_prefix_from_ir_value_match(self, match):
- return self.ir_prefix, self.check_prefix
-
- # Return the IR regexp we use for this kind or IR value, e.g., [\w.-]+? for locals
- def get_ir_regex_from_ir_value_re_match(self, match):
- # for backwards compatibility we check locals with '.*'
- if self.is_local_def_ir_value_match(match):
- return '.*'
- return self.ir_regexp
-
- # Create a FileCheck variable name based on an IR name.
- def get_value_name(self, var: str, check_prefix: str):
- var = var.replace('!', '')
- if self.replace_number_with_counter:
- assert var.isdigit(), var
- replacement = self.variable_mapping.get(var, None)
- if replacement is None:
- # Replace variable with an incrementing counter
- replacement = str(len(self.variable_mapping) + 1)
- self.variable_mapping[var] = replacement
- var = replacement
- # This is a nameless value, prepend check_prefix.
- if var.isdigit():
- var = check_prefix + var
- else:
- # This is a named value that clashes with the check_prefix, prepend with
- # _prefix_filecheck_ir_name, if it has been defined.
- if may_clash_with_default_check_prefix_name(check_prefix, var) and _prefix_filecheck_ir_name:
- var = _prefix_filecheck_ir_name + var
- var = var.replace('.', '_')
- var = var.replace('-', '_')
- return var.upper()
-
- # Create a FileCheck variable from regex.
- def get_value_definition(self, var, match):
- # for backwards compatibility we check locals with '.*'
- varname = self.get_value_name(var, self.check_prefix)
- prefix = self.get_ir_prefix_from_ir_value_match(match)[0]
- if self.is_number:
- regex = '' # always capture a number in the default format
- capture_start = '[[#'
- else:
- regex = self.get_ir_regex_from_ir_value_re_match(match)
- capture_start = '[['
- if self.is_local_def_ir_value_match(match):
- return capture_start + varname + ':' + prefix + regex + ']]'
- return prefix + capture_start + varname + ':' + regex + ']]'
-
- # Use a FileCheck variable.
- def get_value_use(self, var, match, var_prefix=None):
- if var_prefix is None:
- var_prefix = self.check_prefix
- capture_start = '[[#' if self.is_number else '[['
- if self.is_local_def_ir_value_match(match):
- return capture_start + self.get_value_name(var, var_prefix) + ']]'
- prefix = self.get_ir_prefix_from_ir_value_match(match)[0]
- return prefix + capture_start + self.get_value_name(var, var_prefix) + ']]'
+ def __init__(
+ self,
+ check_prefix,
+ check_key,
+ ir_prefix,
+ ir_regexp,
+ global_ir_rhs_regexp,
+ *,
+ is_before_functions=False,
+ is_number=False,
+ replace_number_with_counter=False
+ ):
+ self.check_prefix = check_prefix
+ self.check_key = check_key
+ self.ir_prefix = ir_prefix
+ self.ir_regexp = ir_regexp
+ self.global_ir_rhs_regexp = global_ir_rhs_regexp
+ self.is_before_functions = is_before_functions
+ self.is_number = is_number
+ # Some variable numbers (e.g. MCINST1234) will change based on unrelated
+ # modifications to LLVM, replace those with an incrementing counter.
+ self.replace_number_with_counter = replace_number_with_counter
+ self.variable_mapping = {}
+
+ # Return true if this kind of IR value is "local", basically if it matches '%{{.*}}'.
+ def is_local_def_ir_value_match(self, match):
+ return self.ir_prefix == "%"
+
+ # Return true if this kind of IR value is "global", basically if it matches '#{{.*}}'.
+ def is_global_scope_ir_value_match(self, match):
+ return self.global_ir_rhs_regexp is not None
+
+ # Return the IR prefix and check prefix we use for this kind or IR value,
+ # e.g., (%, TMP) for locals.
+ def get_ir_prefix_from_ir_value_match(self, match):
+ return self.ir_prefix, self.check_prefix
+
+ # Return the IR regexp we use for this kind or IR value, e.g., [\w.-]+? for locals
+ def get_ir_regex_from_ir_value_re_match(self, match):
+ # for backwards compatibility we check locals with '.*'
+ if self.is_local_def_ir_value_match(match):
+ return ".*"
+ return self.ir_regexp
+
+ # Create a FileCheck variable name based on an IR name.
+ def get_value_name(self, var: str, check_prefix: str):
+ var = var.replace("!", "")
+ if self.replace_number_with_counter:
+ assert var.isdigit(), var
+ replacement = self.variable_mapping.get(var, None)
+ if replacement is None:
+ # Replace variable with an incrementing counter
+ replacement = str(len(self.variable_mapping) + 1)
+ self.variable_mapping[var] = replacement
+ var = replacement
+ # This is a nameless value, prepend check_prefix.
+ if var.isdigit():
+ var = check_prefix + var
+ else:
+ # This is a named value that clashes with the check_prefix, prepend with
+ # _prefix_filecheck_ir_name, if it has been defined.
+ if (
+ may_clash_with_default_check_prefix_name(check_prefix, var)
+ and _prefix_filecheck_ir_name
+ ):
+ var = _prefix_filecheck_ir_name + var
+ var = var.replace(".", "_")
+ var = var.replace("-", "_")
+ return var.upper()
+
+ # Create a FileCheck variable from regex.
+ def get_value_definition(self, var, match):
+ # for backwards compatibility we check locals with '.*'
+ varname = self.get_value_name(var, self.check_prefix)
+ prefix = self.get_ir_prefix_from_ir_value_match(match)[0]
+ if self.is_number:
+ regex = "" # always capture a number in the default format
+ capture_start = "[[#"
+ else:
+ regex = self.get_ir_regex_from_ir_value_re_match(match)
+ capture_start = "[["
+ if self.is_local_def_ir_value_match(match):
+ return capture_start + varname + ":" + prefix + regex + "]]"
+ return prefix + capture_start + varname + ":" + regex + "]]"
+
+ # Use a FileCheck variable.
+ def get_value_use(self, var, match, var_prefix=None):
+ if var_prefix is None:
+ var_prefix = self.check_prefix
+ capture_start = "[[#" if self.is_number else "[["
+ if self.is_local_def_ir_value_match(match):
+ return capture_start + self.get_value_name(var, var_prefix) + "]]"
+ prefix = self.get_ir_prefix_from_ir_value_match(match)[0]
+ return prefix + capture_start + self.get_value_name(var, var_prefix) + "]]"
+
# Description of the different "unnamed" values we match in the IR, e.g.,
# (local) ssa values, (debug) metadata, etc.
ir_nameless_values = [
# check_prefix check_key ir_prefix ir_regexp global_ir_rhs_regexp
- NamelessValue(r'TMP' , '%' , r'%' , r'[\w$.-]+?' , None ) ,
- NamelessValue(r'ATTR' , '#' , r'#' , r'[0-9]+' , None ) ,
- NamelessValue(r'ATTR' , '#' , r'attributes #' , r'[0-9]+' , r'{[^}]*}' ) ,
- NamelessValue(r'GLOB' , '@' , r'@' , r'[0-9]+' , None ) ,
- NamelessValue(r'GLOB' , '@' , r'@' , r'[a-zA-Z0-9_$"\\.-]+' , r'.+' , is_before_functions=True) ,
- NamelessValue(r'DBG' , '!' , r'!dbg ' , r'![0-9]+' , None ) ,
- NamelessValue(r'DIASSIGNID' , '!' , r'!DIAssignID ' , r'![0-9]+' , None ) ,
- NamelessValue(r'PROF' , '!' , r'!prof ' , r'![0-9]+' , None ) ,
- NamelessValue(r'TBAA' , '!' , r'!tbaa ' , r'![0-9]+' , None ) ,
- NamelessValue(r'TBAA_STRUCT', '!' , r'!tbaa.struct ' , r'![0-9]+' , None ) ,
- NamelessValue(r'RNG' , '!' , r'!range ' , r'![0-9]+' , None ) ,
- NamelessValue(r'LOOP' , '!' , r'!llvm.loop ' , r'![0-9]+' , None ) ,
- NamelessValue(r'META' , '!' , r'metadata ' , r'![0-9]+' , None ) ,
- NamelessValue(r'META' , '!' , r'' , r'![0-9]+' , r'(?:distinct |)!.*' ) ,
- NamelessValue(r'ACC_GRP' , '!' , r'!llvm.access.group ' , r'![0-9]+' , None ) ,
+ NamelessValue(r"TMP", "%", r"%", r"[\w$.-]+?", None),
+ NamelessValue(r"ATTR", "#", r"#", r"[0-9]+", None),
+ NamelessValue(r"ATTR", "#", r"attributes #", r"[0-9]+", r"{[^}]*}"),
+ NamelessValue(r"GLOB", "@", r"@", r"[0-9]+", None),
+ NamelessValue(
+ r"GLOB", "@", r"@", r'[a-zA-Z0-9_$"\\.-]+', r".+", is_before_functions=True
+ ),
+ NamelessValue(r"DBG", "!", r"!dbg ", r"![0-9]+", None),
+ NamelessValue(r"DIASSIGNID", "!", r"!DIAssignID ", r"![0-9]+", None),
+ NamelessValue(r"PROF", "!", r"!prof ", r"![0-9]+", None),
+ NamelessValue(r"TBAA", "!", r"!tbaa ", r"![0-9]+", None),
+ NamelessValue(r"TBAA_STRUCT", "!", r"!tbaa.struct ", r"![0-9]+", None),
+ NamelessValue(r"RNG", "!", r"!range ", r"![0-9]+", None),
+ NamelessValue(r"LOOP", "!", r"!llvm.loop ", r"![0-9]+", None),
+ NamelessValue(r"META", "!", r"metadata ", r"![0-9]+", None),
+ NamelessValue(r"META", "!", r"", r"![0-9]+", r"(?:distinct |)!.*"),
+ NamelessValue(r"ACC_GRP", "!", r"!llvm.access.group ", r"![0-9]+", None),
]
asm_nameless_values = [
- NamelessValue(r'MCINST' , 'Inst#' , '<MCInst #' , r'\d+' , r'.+', is_number=True, replace_number_with_counter=True),
- NamelessValue(r'MCREG' , 'Reg:' , '<MCOperand Reg:' , r'\d+' , r'.+', is_number=True, replace_number_with_counter=True),
+ NamelessValue(
+ r"MCINST",
+ "Inst#",
+ "<MCInst #",
+ r"\d+",
+ r".+",
+ is_number=True,
+ replace_number_with_counter=True,
+ ),
+ NamelessValue(
+ r"MCREG",
+ "Reg:",
+ "<MCOperand Reg:",
+ r"\d+",
+ r".+",
+ is_number=True,
+ replace_number_with_counter=True,
+ ),
]
+
def createOrRegexp(old, new):
- if not old:
- return new
- if not new:
- return old
- return old + '|' + new
+ if not old:
+ return new
+ if not new:
+ return old
+ return old + "|" + new
+
def createPrefixMatch(prefix_str, prefix_re):
- return '(?:' + prefix_str + '(' + prefix_re + '))'
+ return "(?:" + prefix_str + "(" + prefix_re + "))"
+
# Build the regexp that matches an "IR value". This can be a local variable,
# argument, global, or metadata, anything that is "named". It is important that
# the PREFIX and SUFFIX below only contain a single group, if that changes
# other locations will need adjustment as well.
-IR_VALUE_REGEXP_PREFIX = r'(\s*)'
-IR_VALUE_REGEXP_STRING = r''
+IR_VALUE_REGEXP_PREFIX = r"(\s*)"
+IR_VALUE_REGEXP_STRING = r""
for nameless_value in ir_nameless_values:
- match = createPrefixMatch(nameless_value.ir_prefix, nameless_value.ir_regexp)
- if nameless_value.global_ir_rhs_regexp is not None:
- match = '^' + match
- IR_VALUE_REGEXP_STRING = createOrRegexp(IR_VALUE_REGEXP_STRING, match)
-IR_VALUE_REGEXP_SUFFIX = r'([,\s\(\)]|\Z)'
-IR_VALUE_RE = re.compile(IR_VALUE_REGEXP_PREFIX + r'(' + IR_VALUE_REGEXP_STRING + r')' + IR_VALUE_REGEXP_SUFFIX)
+ match = createPrefixMatch(nameless_value.ir_prefix, nameless_value.ir_regexp)
+ if nameless_value.global_ir_rhs_regexp is not None:
+ match = "^" + match
+ IR_VALUE_REGEXP_STRING = createOrRegexp(IR_VALUE_REGEXP_STRING, match)
+IR_VALUE_REGEXP_SUFFIX = r"([,\s\(\)]|\Z)"
+IR_VALUE_RE = re.compile(
+ IR_VALUE_REGEXP_PREFIX
+ + r"("
+ + IR_VALUE_REGEXP_STRING
+ + r")"
+ + IR_VALUE_REGEXP_SUFFIX
+)
# Build the regexp that matches an "ASM value" (currently only for --asm-show-inst comments).
-ASM_VALUE_REGEXP_STRING = ''
+ASM_VALUE_REGEXP_STRING = ""
for nameless_value in asm_nameless_values:
- match = createPrefixMatch(nameless_value.ir_prefix, nameless_value.ir_regexp)
- ASM_VALUE_REGEXP_STRING = createOrRegexp(ASM_VALUE_REGEXP_STRING, match)
-ASM_VALUE_REGEXP_SUFFIX = r'([>\s]|\Z)'
-ASM_VALUE_RE = re.compile(r'((?:#|//)\s*)' + '(' + ASM_VALUE_REGEXP_STRING + ')' + ASM_VALUE_REGEXP_SUFFIX)
+ match = createPrefixMatch(nameless_value.ir_prefix, nameless_value.ir_regexp)
+ ASM_VALUE_REGEXP_STRING = createOrRegexp(ASM_VALUE_REGEXP_STRING, match)
+ASM_VALUE_REGEXP_SUFFIX = r"([>\s]|\Z)"
+ASM_VALUE_RE = re.compile(
+ r"((?:#|//)\s*)" + "(" + ASM_VALUE_REGEXP_STRING + ")" + ASM_VALUE_REGEXP_SUFFIX
+)
# The entire match is group 0, the prefix has one group (=1), the entire
# IR_VALUE_REGEXP_STRING is one group (=2), and then the nameless values start.
@@ -825,488 +1061,665 @@ attribute_group_in_ir_value_match = 4
# Check a match for IR_VALUE_RE and inspect it to determine if it was a local
# value, %..., global @..., debug number !dbg !..., etc. See the PREFIXES above.
def get_idx_from_ir_value_match(match):
- for i in range(first_nameless_group_in_ir_value_match, match.lastindex):
- if match.group(i) is not None:
- return i - first_nameless_group_in_ir_value_match
- error("Unable to identify the kind of IR value from the match!")
- return 0
+ for i in range(first_nameless_group_in_ir_value_match, match.lastindex):
+ if match.group(i) is not None:
+ return i - first_nameless_group_in_ir_value_match
+ error("Unable to identify the kind of IR value from the match!")
+ return 0
+
# See get_idx_from_ir_value_match
def get_name_from_ir_value_match(match):
- return match.group(get_idx_from_ir_value_match(match) + first_nameless_group_in_ir_value_match)
+ return match.group(
+ get_idx_from_ir_value_match(match) + first_nameless_group_in_ir_value_match
+ )
+
def get_nameless_value_from_match(match, nameless_values) -> NamelessValue:
- return nameless_values[get_idx_from_ir_value_match(match)]
+ return nameless_values[get_idx_from_ir_value_match(match)]
+
# Return true if var clashes with the scripted FileCheck check_prefix.
def may_clash_with_default_check_prefix_name(check_prefix, var):
- return check_prefix and re.match(r'^' + check_prefix + r'[0-9]+?$', var, re.IGNORECASE)
-
-def generalize_check_lines_common(lines, is_analyze, vars_seen,
- global_vars_seen, nameless_values,
- nameless_value_regex, is_asm):
- # This gets called for each match that occurs in
- # a line. We transform variables we haven't seen
- # into defs, and variables we have seen into uses.
- def transform_line_vars(match):
- var = get_name_from_ir_value_match(match)
- nameless_value = get_nameless_value_from_match(match, nameless_values)
- if may_clash_with_default_check_prefix_name(nameless_value.check_prefix, var):
- warn("Change IR value name '%s' or use --prefix-filecheck-ir-name to prevent possible conflict"
- " with scripted FileCheck name." % (var,))
- key = (var, nameless_value.check_key)
- is_local_def = nameless_value.is_local_def_ir_value_match(match)
- if is_local_def and key in vars_seen:
- rv = nameless_value.get_value_use(var, match)
- elif not is_local_def and key in global_vars_seen:
- # We could have seen a different prefix for the global variables first,
- # ensure we use that one instead of the prefix for the current match.
- rv = nameless_value.get_value_use(var, match, global_vars_seen[key])
- else:
- if is_local_def:
- vars_seen.add(key)
- else:
- global_vars_seen[key] = nameless_value.check_prefix
- rv = nameless_value.get_value_definition(var, match)
- # re.sub replaces the entire regex match
- # with whatever you return, so we have
- # to make sure to hand it back everything
- # including the commas and spaces.
- return match.group(1) + rv + match.group(match.lastindex)
-
- lines_with_def = []
-
- for i, line in enumerate(lines):
- if not is_asm:
- # An IR variable named '%.' matches the FileCheck regex string.
- line = line.replace('%.', '%dot')
- for regex in _global_hex_value_regex:
- if re.match('^@' + regex + ' = ', line):
- line = re.sub(r'\bi([0-9]+) ([0-9]+)',
- lambda m : 'i' + m.group(1) + ' [[#' + hex(int(m.group(2))) + ']]',
- line)
- break
- # Ignore any comments, since the check lines will too.
- scrubbed_line = SCRUB_IR_COMMENT_RE.sub(r'', line)
- lines[i] = scrubbed_line
- if is_asm or not is_analyze:
- # It can happen that two matches are back-to-back and for some reason sub
- # will not replace both of them. For now we work around this by
- # substituting until there is no more match.
- changed = True
- while changed:
- (lines[i], changed) = nameless_value_regex.subn(transform_line_vars,
- lines[i], count=1)
- return lines
+ return check_prefix and re.match(
+ r"^" + check_prefix + r"[0-9]+?$", var, re.IGNORECASE
+ )
+
+
+def generalize_check_lines_common(
+ lines,
+ is_analyze,
+ vars_seen,
+ global_vars_seen,
+ nameless_values,
+ nameless_value_regex,
+ is_asm,
+):
+ # This gets called for each match that occurs in
+ # a line. We transform variables we haven't seen
+ # into defs, and variables we have seen into uses.
+ def transform_line_vars(match):
+ var = get_name_from_ir_value_match(match)
+ nameless_value = get_nameless_value_from_match(match, nameless_values)
+ if may_clash_with_default_check_prefix_name(nameless_value.check_prefix, var):
+ warn(
+ "Change IR value name '%s' or use --prefix-filecheck-ir-name to prevent possible conflict"
+ " with scripted FileCheck name." % (var,)
+ )
+ key = (var, nameless_value.check_key)
+ is_local_def = nameless_value.is_local_def_ir_value_match(match)
+ if is_local_def and key in vars_seen:
+ rv = nameless_value.get_value_use(var, match)
+ elif not is_local_def and key in global_vars_seen:
+ # We could have seen a different prefix for the global variables first,
+ # ensure we use that one instead of the prefix for the current match.
+ rv = nameless_value.get_value_use(var, match, global_vars_seen[key])
+ else:
+ if is_local_def:
+ vars_seen.add(key)
+ else:
+ global_vars_seen[key] = nameless_value.check_prefix
+ rv = nameless_value.get_value_definition(var, match)
+ # re.sub replaces the entire regex match
+ # with whatever you return, so we have
+ # to make sure to hand it back everything
+ # including the commas and spaces.
+ return match.group(1) + rv + match.group(match.lastindex)
+
+ lines_with_def = []
+
+ for i, line in enumerate(lines):
+ if not is_asm:
+ # An IR variable named '%.' matches the FileCheck regex string.
+ line = line.replace("%.", "%dot")
+ for regex in _global_hex_value_regex:
+ if re.match("^@" + regex + " = ", line):
+ line = re.sub(
+ r"\bi([0-9]+) ([0-9]+)",
+ lambda m: "i"
+ + m.group(1)
+ + " [[#"
+ + hex(int(m.group(2)))
+ + "]]",
+ line,
+ )
+ break
+ # Ignore any comments, since the check lines will too.
+ scrubbed_line = SCRUB_IR_COMMENT_RE.sub(r"", line)
+ lines[i] = scrubbed_line
+ if is_asm or not is_analyze:
+ # It can happen that two matches are back-to-back and for some reason sub
+ # will not replace both of them. For now we work around this by
+ # substituting until there is no more match.
+ changed = True
+ while changed:
+ (lines[i], changed) = nameless_value_regex.subn(
+ transform_line_vars, lines[i], count=1
+ )
+ return lines
+
# Replace IR value defs and uses with FileCheck variables.
def generalize_check_lines(lines, is_analyze, vars_seen, global_vars_seen):
- return generalize_check_lines_common(lines, is_analyze, vars_seen,
- global_vars_seen, ir_nameless_values,
- IR_VALUE_RE, False)
+ return generalize_check_lines_common(
+ lines,
+ is_analyze,
+ vars_seen,
+ global_vars_seen,
+ ir_nameless_values,
+ IR_VALUE_RE,
+ False,
+ )
-def generalize_asm_check_lines(lines, vars_seen, global_vars_seen):
- return generalize_check_lines_common(lines, False, vars_seen,
- global_vars_seen, asm_nameless_values,
- ASM_VALUE_RE, True)
-
-def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, is_backend, is_analyze, version, 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 = []
- for p in prefix_list:
- checkprefixes = p[0]
- # If not all checkprefixes of this run line produced the function we cannot check for it as it does not
- # exist for this run line. A subset of the check prefixes might know about the function but only because
- # other run lines created it.
- if any(map(lambda checkprefix: func_name not in func_dict[checkprefix], checkprefixes)):
- prefix_exclusions |= set(checkprefixes)
- continue
-
- # prefix_exclusions is constructed, we can now emit the output
- for p in prefix_list:
- global_vars_seen = {}
- checkprefixes = p[0]
- for checkprefix in checkprefixes:
- if checkprefix in global_vars_seen_dict:
- global_vars_seen.update(global_vars_seen_dict[checkprefix])
- else:
- global_vars_seen_dict[checkprefix] = {}
- if checkprefix in printed_prefixes:
- break
-
- # Check if the prefix is excluded.
- if checkprefix in prefix_exclusions:
- continue
-
- # If we do not have output for this prefix we skip it.
- if not func_dict[checkprefix][func_name]:
- continue
-
- # Add some space between different check prefixes, but not after the last
- # check line (before the test code).
- if is_backend:
- if len(printed_prefixes) != 0:
- output_lines.append(comment_marker)
-
- if checkprefix not in global_vars_seen_dict:
- global_vars_seen_dict[checkprefix] = {}
-
- global_vars_seen_before = [key for key in global_vars_seen.keys()]
-
- vars_seen = set()
- printed_prefixes.append(checkprefix)
- attrs = str(func_dict[checkprefix][func_name].attrs)
- attrs = '' if attrs == 'None' else attrs
- if version > 1:
- funcdef_attrs_and_ret = func_dict[checkprefix][func_name].funcdef_attrs_and_ret
- else:
- funcdef_attrs_and_ret = ''
-
- if attrs:
- output_lines.append('%s %s: Function Attrs: %s' % (comment_marker, checkprefix, attrs))
- args_and_sig = str(func_dict[checkprefix][func_name].args_and_sig)
- if args_and_sig:
- args_and_sig = generalize_check_lines([args_and_sig], is_analyze, vars_seen, global_vars_seen)[0]
- func_name_separator = func_dict[checkprefix][func_name].func_name_separator
- if '[[' in args_and_sig:
- output_lines.append(check_label_format % (checkprefix, funcdef_attrs_and_ret, func_name, '', func_name_separator))
- output_lines.append('%s %s-SAME: %s' % (comment_marker, checkprefix, args_and_sig))
- else:
- output_lines.append(check_label_format % (checkprefix, funcdef_attrs_and_ret, func_name, args_and_sig, func_name_separator))
- 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_backend:
- 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]))
- func_lines = generalize_asm_check_lines(func_body[body_start:],
- vars_seen, global_vars_seen)
- for func_line in func_lines:
- if func_line.strip() == '':
- output_lines.append('%s %s-EMPTY:' % (comment_marker, checkprefix))
- else:
- check_suffix = '-NEXT' if not is_filtered else ''
- output_lines.append('%s %s%s: %s' % (comment_marker, checkprefix,
- check_suffix, func_line))
- # Remember new global variables we have not seen before
- for key in global_vars_seen:
- if key not in global_vars_seen_before:
- global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
- break
-
- # For IR output, change all defs to FileCheck variables, so we're immune
- # to variable naming fashions.
- func_body = generalize_check_lines(func_body, is_analyze, vars_seen, global_vars_seen)
-
- # This could be selectively enabled with an optional invocation argument.
- # Disabled for now: better to check everything. Be safe rather than sorry.
-
- # Handle the first line of the function body as a special case because
- # it's often just noise (a useless asm comment or entry label).
- #if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
- # is_blank_line = True
- #else:
- # output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0]))
- # is_blank_line = False
-
- is_blank_line = False
-
- for func_line in func_body:
- if func_line.strip() == '':
- is_blank_line = True
- continue
- # Do not waste time checking IR comments.
- func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line)
-
- # Skip blank lines instead of checking them.
- if is_blank_line:
- output_lines.append('{} {}: {}'.format(
- comment_marker, checkprefix, func_line))
- else:
- 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
- # line of code in the test function.
- output_lines.append(comment_marker)
-
- # Remember new global variables we have not seen before
- for key in global_vars_seen:
- if key not in global_vars_seen_before:
- global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
- break
- return printed_prefixes
-
-def add_ir_checks(output_lines, comment_marker, prefix_list, func_dict,
- func_name, preserve_names, function_sig, version,
- global_vars_seen_dict, is_filtered):
- # Label format is based on IR string.
- if function_sig and version > 1:
- function_def_regex = 'define %s'
- elif function_sig:
- function_def_regex = 'define {{[^@]+}}%s'
- else:
- function_def_regex = '%s'
- check_label_format = '{} %s-LABEL: {}@%s%s%s'.format(comment_marker, function_def_regex)
- return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
- check_label_format, False, preserve_names, version,
- global_vars_seen_dict,
- is_filtered)
-
-def add_analyze_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, is_filtered):
- check_label_format = '{} %s-LABEL: \'%s%s%s%s\''.format(comment_marker)
- global_vars_seen_dict = {}
- return add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
- check_label_format, False, True, 1, global_vars_seen_dict,
- is_filtered)
-def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes):
- for nameless_value in itertools.chain(ir_nameless_values, asm_nameless_values):
- if nameless_value.global_ir_rhs_regexp is None:
- continue
-
- lhs_re_str = nameless_value.ir_prefix + nameless_value.ir_regexp
- rhs_re_str = nameless_value.global_ir_rhs_regexp
-
- global_ir_value_re_str = r'^' + lhs_re_str + r'\s=\s' + rhs_re_str + r'$'
- global_ir_value_re = re.compile(global_ir_value_re_str, flags=(re.M))
- lines = []
- for m in global_ir_value_re.finditer(raw_tool_output):
- lines.append(m.group(0))
-
- for prefix in prefixes:
- if glob_val_dict[prefix] is None:
- continue
- if nameless_value.check_prefix in glob_val_dict[prefix]:
- if lines == glob_val_dict[prefix][nameless_value.check_prefix]:
- continue
- if prefix == prefixes[-1]:
- warn('Found conflicting asm under the same prefix: %r!' % (prefix,))
- else:
- glob_val_dict[prefix][nameless_value.check_prefix] = None
- continue
- glob_val_dict[prefix][nameless_value.check_prefix] = lines
-
-def add_global_checks(glob_val_dict, comment_marker, prefix_list, output_lines, global_vars_seen_dict, is_analyze, is_before_functions):
- printed_prefixes = set()
- for nameless_value in ir_nameless_values:
- if nameless_value.global_ir_rhs_regexp is None:
- continue
- if nameless_value.is_before_functions != is_before_functions:
- continue
+def generalize_asm_check_lines(lines, vars_seen, global_vars_seen):
+ return generalize_check_lines_common(
+ lines,
+ False,
+ vars_seen,
+ global_vars_seen,
+ asm_nameless_values,
+ ASM_VALUE_RE,
+ True,
+ )
+
+
+def add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ check_label_format,
+ is_backend,
+ is_analyze,
+ version,
+ 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 = []
for p in prefix_list:
- global_vars_seen = {}
- checkprefixes = p[0]
- if checkprefixes is None:
- continue
- for checkprefix in checkprefixes:
- if checkprefix in global_vars_seen_dict:
- global_vars_seen.update(global_vars_seen_dict[checkprefix])
- else:
- global_vars_seen_dict[checkprefix] = {}
- if (checkprefix, nameless_value.check_prefix) in printed_prefixes:
- break
- if not glob_val_dict[checkprefix]:
- continue
- if nameless_value.check_prefix not in glob_val_dict[checkprefix]:
- continue
- if not glob_val_dict[checkprefix][nameless_value.check_prefix]:
- continue
-
- check_lines = []
- global_vars_seen_before = [key for key in global_vars_seen.keys()]
- for line in glob_val_dict[checkprefix][nameless_value.check_prefix]:
- if _global_value_regex:
- matched = False
- for regex in _global_value_regex:
- if re.match('^@' + regex + ' = ', line):
- matched = True
+ checkprefixes = p[0]
+ # If not all checkprefixes of this run line produced the function we cannot check for it as it does not
+ # exist for this run line. A subset of the check prefixes might know about the function but only because
+ # other run lines created it.
+ if any(
+ map(
+ lambda checkprefix: func_name not in func_dict[checkprefix],
+ checkprefixes,
+ )
+ ):
+ prefix_exclusions |= set(checkprefixes)
+ continue
+
+ # prefix_exclusions is constructed, we can now emit the output
+ for p in prefix_list:
+ global_vars_seen = {}
+ checkprefixes = p[0]
+ for checkprefix in checkprefixes:
+ if checkprefix in global_vars_seen_dict:
+ global_vars_seen.update(global_vars_seen_dict[checkprefix])
+ else:
+ global_vars_seen_dict[checkprefix] = {}
+ if checkprefix in printed_prefixes:
break
- if not matched:
- continue
- tmp = generalize_check_lines([line], is_analyze, set(), global_vars_seen)
- check_line = '%s %s: %s' % (comment_marker, checkprefix, tmp[0])
- check_lines.append(check_line)
- if not check_lines:
- continue
- output_lines.append(comment_marker + SEPARATOR)
- for check_line in check_lines:
- output_lines.append(check_line)
+ # Check if the prefix is excluded.
+ if checkprefix in prefix_exclusions:
+ continue
+
+ # If we do not have output for this prefix we skip it.
+ if not func_dict[checkprefix][func_name]:
+ continue
+
+ # Add some space between different check prefixes, but not after the last
+ # check line (before the test code).
+ if is_backend:
+ if len(printed_prefixes) != 0:
+ output_lines.append(comment_marker)
+
+ if checkprefix not in global_vars_seen_dict:
+ global_vars_seen_dict[checkprefix] = {}
+
+ global_vars_seen_before = [key for key in global_vars_seen.keys()]
+
+ vars_seen = set()
+ printed_prefixes.append(checkprefix)
+ attrs = str(func_dict[checkprefix][func_name].attrs)
+ attrs = "" if attrs == "None" else attrs
+ if version > 1:
+ funcdef_attrs_and_ret = func_dict[checkprefix][
+ func_name
+ ].funcdef_attrs_and_ret
+ else:
+ funcdef_attrs_and_ret = ""
+
+ if attrs:
+ output_lines.append(
+ "%s %s: Function Attrs: %s" % (comment_marker, checkprefix, attrs)
+ )
+ args_and_sig = str(func_dict[checkprefix][func_name].args_and_sig)
+ if args_and_sig:
+ args_and_sig = generalize_check_lines(
+ [args_and_sig], is_analyze, vars_seen, global_vars_seen
+ )[0]
+ func_name_separator = func_dict[checkprefix][func_name].func_name_separator
+ if "[[" in args_and_sig:
+ output_lines.append(
+ check_label_format
+ % (
+ checkprefix,
+ funcdef_attrs_and_ret,
+ func_name,
+ "",
+ func_name_separator,
+ )
+ )
+ output_lines.append(
+ "%s %s-SAME: %s" % (comment_marker, checkprefix, args_and_sig)
+ )
+ else:
+ output_lines.append(
+ check_label_format
+ % (
+ checkprefix,
+ funcdef_attrs_and_ret,
+ func_name,
+ args_and_sig,
+ func_name_separator,
+ )
+ )
+ 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_backend:
+ 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])
+ )
+ func_lines = generalize_asm_check_lines(
+ func_body[body_start:], vars_seen, global_vars_seen
+ )
+ for func_line in func_lines:
+ if func_line.strip() == "":
+ output_lines.append(
+ "%s %s-EMPTY:" % (comment_marker, checkprefix)
+ )
+ else:
+ check_suffix = "-NEXT" if not is_filtered else ""
+ output_lines.append(
+ "%s %s%s: %s"
+ % (comment_marker, checkprefix, check_suffix, func_line)
+ )
+ # Remember new global variables we have not seen before
+ for key in global_vars_seen:
+ if key not in global_vars_seen_before:
+ global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
+ break
- printed_prefixes.add((checkprefix, nameless_value.check_prefix))
+ # For IR output, change all defs to FileCheck variables, so we're immune
+ # to variable naming fashions.
+ func_body = generalize_check_lines(
+ func_body, is_analyze, vars_seen, global_vars_seen
+ )
+
+ # This could be selectively enabled with an optional invocation argument.
+ # Disabled for now: better to check everything. Be safe rather than sorry.
+
+ # Handle the first line of the function body as a special case because
+ # it's often just noise (a useless asm comment or entry label).
+ # if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
+ # is_blank_line = True
+ # else:
+ # output_lines.append('%s %s: %s' % (comment_marker, checkprefix, func_body[0]))
+ # is_blank_line = False
+
+ is_blank_line = False
+
+ for func_line in func_body:
+ if func_line.strip() == "":
+ is_blank_line = True
+ continue
+ # Do not waste time checking IR comments.
+ func_line = SCRUB_IR_COMMENT_RE.sub(r"", func_line)
+
+ # Skip blank lines instead of checking them.
+ if is_blank_line:
+ output_lines.append(
+ "{} {}: {}".format(comment_marker, checkprefix, func_line)
+ )
+ else:
+ 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
+ # line of code in the test function.
+ output_lines.append(comment_marker)
+
+ # Remember new global variables we have not seen before
+ for key in global_vars_seen:
+ if key not in global_vars_seen_before:
+ global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
+ break
+ return printed_prefixes
+
+
+def add_ir_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ preserve_names,
+ function_sig,
+ version,
+ global_vars_seen_dict,
+ is_filtered,
+):
+ # Label format is based on IR string.
+ if function_sig and version > 1:
+ function_def_regex = "define %s"
+ elif function_sig:
+ function_def_regex = "define {{[^@]+}}%s"
+ else:
+ function_def_regex = "%s"
+ check_label_format = "{} %s-LABEL: {}@%s%s%s".format(
+ comment_marker, function_def_regex
+ )
+ return add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ check_label_format,
+ False,
+ preserve_names,
+ version,
+ global_vars_seen_dict,
+ is_filtered,
+ )
+
+
+def add_analyze_checks(
+ output_lines, comment_marker, prefix_list, func_dict, func_name, is_filtered
+):
+ check_label_format = "{} %s-LABEL: '%s%s%s%s'".format(comment_marker)
+ global_vars_seen_dict = {}
+ return add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ check_label_format,
+ False,
+ True,
+ 1,
+ global_vars_seen_dict,
+ is_filtered,
+ )
- # Remembe new global variables we have not seen before
- for key in global_vars_seen:
- if key not in global_vars_seen_before:
- global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
- break
- if printed_prefixes:
- output_lines.append(comment_marker + SEPARATOR)
- return printed_prefixes
+def build_global_values_dictionary(glob_val_dict, raw_tool_output, prefixes):
+ for nameless_value in itertools.chain(ir_nameless_values, asm_nameless_values):
+ if nameless_value.global_ir_rhs_regexp is None:
+ continue
+
+ lhs_re_str = nameless_value.ir_prefix + nameless_value.ir_regexp
+ rhs_re_str = nameless_value.global_ir_rhs_regexp
+
+ global_ir_value_re_str = r"^" + lhs_re_str + r"\s=\s" + rhs_re_str + r"$"
+ global_ir_value_re = re.compile(global_ir_value_re_str, flags=(re.M))
+ lines = []
+ for m in global_ir_value_re.finditer(raw_tool_output):
+ lines.append(m.group(0))
+
+ for prefix in prefixes:
+ if glob_val_dict[prefix] is None:
+ continue
+ if nameless_value.check_prefix in glob_val_dict[prefix]:
+ if lines == glob_val_dict[prefix][nameless_value.check_prefix]:
+ continue
+ if prefix == prefixes[-1]:
+ warn("Found conflicting asm under the same prefix: %r!" % (prefix,))
+ else:
+ glob_val_dict[prefix][nameless_value.check_prefix] = None
+ continue
+ glob_val_dict[prefix][nameless_value.check_prefix] = lines
+
+
+def add_global_checks(
+ glob_val_dict,
+ comment_marker,
+ prefix_list,
+ output_lines,
+ global_vars_seen_dict,
+ is_analyze,
+ is_before_functions,
+):
+ printed_prefixes = set()
+ for nameless_value in ir_nameless_values:
+ if nameless_value.global_ir_rhs_regexp is None:
+ continue
+ if nameless_value.is_before_functions != is_before_functions:
+ continue
+ for p in prefix_list:
+ global_vars_seen = {}
+ checkprefixes = p[0]
+ if checkprefixes is None:
+ continue
+ for checkprefix in checkprefixes:
+ if checkprefix in global_vars_seen_dict:
+ global_vars_seen.update(global_vars_seen_dict[checkprefix])
+ else:
+ global_vars_seen_dict[checkprefix] = {}
+ if (checkprefix, nameless_value.check_prefix) in printed_prefixes:
+ break
+ if not glob_val_dict[checkprefix]:
+ continue
+ if nameless_value.check_prefix not in glob_val_dict[checkprefix]:
+ continue
+ if not glob_val_dict[checkprefix][nameless_value.check_prefix]:
+ continue
+
+ check_lines = []
+ global_vars_seen_before = [key for key in global_vars_seen.keys()]
+ for line in glob_val_dict[checkprefix][nameless_value.check_prefix]:
+ if _global_value_regex:
+ matched = False
+ for regex in _global_value_regex:
+ if re.match("^@" + regex + " = ", line):
+ matched = True
+ break
+ if not matched:
+ continue
+ tmp = generalize_check_lines(
+ [line], is_analyze, set(), global_vars_seen
+ )
+ check_line = "%s %s: %s" % (comment_marker, checkprefix, tmp[0])
+ check_lines.append(check_line)
+ if not check_lines:
+ continue
+
+ output_lines.append(comment_marker + SEPARATOR)
+ for check_line in check_lines:
+ output_lines.append(check_line)
+
+ printed_prefixes.add((checkprefix, nameless_value.check_prefix))
+
+ # Remembe new global variables we have not seen before
+ for key in global_vars_seen:
+ if key not in global_vars_seen_before:
+ global_vars_seen_dict[checkprefix][key] = global_vars_seen[key]
+ break
+
+ if printed_prefixes:
+ output_lines.append(comment_marker + SEPARATOR)
+ return printed_prefixes
def check_prefix(prefix):
- if not PREFIX_RE.match(prefix):
- hint = ""
- if ',' in prefix:
- hint = " Did you mean '--check-prefixes=" + prefix + "'?"
- warn(("Supplied prefix '%s' is invalid. Prefix must contain only alphanumeric characters, hyphens and underscores." + hint) %
- (prefix))
+ if not PREFIX_RE.match(prefix):
+ hint = ""
+ if "," in prefix:
+ hint = " Did you mean '--check-prefixes=" + prefix + "'?"
+ warn(
+ (
+ "Supplied prefix '%s' is invalid. Prefix must contain only alphanumeric characters, hyphens and underscores."
+ + hint
+ )
+ % (prefix)
+ )
+
def get_check_prefixes(filecheck_cmd):
- check_prefixes = [item for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)
- for item in m.group(1).split(',')]
- if not check_prefixes:
- check_prefixes = ['CHECK']
- return check_prefixes
+ check_prefixes = [
+ item
+ for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)
+ for item in m.group(1).split(",")
+ ]
+ if not check_prefixes:
+ check_prefixes = ["CHECK"]
+ return check_prefixes
+
def verify_filecheck_prefixes(fc_cmd):
- fc_cmd_parts = fc_cmd.split()
- for part in fc_cmd_parts:
- if "check-prefix=" in part:
- prefix = part.split('=', 1)[1]
- check_prefix(prefix)
- elif "check-prefixes=" in part:
- prefixes = part.split('=', 1)[1].split(',')
- for prefix in prefixes:
- check_prefix(prefix)
- if prefixes.count(prefix) > 1:
- warn("Supplied prefix '%s' is not unique in the prefix list." % (prefix,))
+ fc_cmd_parts = fc_cmd.split()
+ for part in fc_cmd_parts:
+ if "check-prefix=" in part:
+ prefix = part.split("=", 1)[1]
+ check_prefix(prefix)
+ elif "check-prefixes=" in part:
+ prefixes = part.split("=", 1)[1].split(",")
+ for prefix in prefixes:
+ check_prefix(prefix)
+ if prefixes.count(prefix) > 1:
+ warn(
+ "Supplied prefix '%s' is not unique in the prefix list."
+ % (prefix,)
+ )
def get_autogennote_suffix(parser, args):
- autogenerated_note_args = ''
- for action in parser._actions:
- if not hasattr(args, action.dest):
- continue # Ignore options such as --help that aren't included in args
- # Ignore parameters such as paths to the binary or the list of tests
- if action.dest in ('tests', 'update_only', 'tool_binary', 'opt_binary',
- 'llc_binary', 'clang', 'opt', 'llvm_bin', 'verbose',
- 'force_update'):
- continue
- value = getattr(args, action.dest)
- if action.const is not None: # action stores a constant (usually True/False)
- # Skip actions with different constant values (this happens with boolean
- # --foo/--no-foo options)
- if value != action.const:
- continue
- if parser.get_default(action.dest) == value:
- continue # Don't add default values
- if action.dest == 'function_signature' and args.version >= 2:
- continue # Enabled by default in version 2
- 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
+ autogenerated_note_args = ""
+ for action in parser._actions:
+ if not hasattr(args, action.dest):
+ continue # Ignore options such as --help that aren't included in args
+ # Ignore parameters such as paths to the binary or the list of tests
+ if action.dest in (
+ "tests",
+ "update_only",
+ "tool_binary",
+ "opt_binary",
+ "llc_binary",
+ "clang",
+ "opt",
+ "llvm_bin",
+ "verbose",
+ "force_update",
+ ):
+ continue
+ value = getattr(args, action.dest)
+ if action.const is not None: # action stores a constant (usually True/False)
+ # Skip actions with different constant values (this happens with boolean
+ # --foo/--no-foo options)
+ if value != action.const:
+ continue
+ if parser.get_default(action.dest) == value:
+ continue # Don't add default values
+ if action.dest == "function_signature" and args.version >= 2:
+ continue # Enabled by default in version 2
+ 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
def check_for_command(line, parser, args, argv, argparse_callback):
- cmd_m = UTC_ARGS_CMD.match(line)
- if cmd_m:
- for option in shlex.split(cmd_m.group('cmd').strip()):
- if option:
- argv.append(option)
- args = parse_args(parser, filter(lambda arg: arg not in args.tests, argv))
- if argparse_callback is not None:
- argparse_callback(args)
- return args, argv
+ cmd_m = UTC_ARGS_CMD.match(line)
+ if cmd_m:
+ for option in shlex.split(cmd_m.group("cmd").strip()):
+ if option:
+ argv.append(option)
+ args = parse_args(parser, filter(lambda arg: arg not in args.tests, argv))
+ if argparse_callback is not None:
+ argparse_callback(args)
+ return args, argv
+
def find_arg_in_test(test_info, get_arg_to_check, arg_string, is_global):
- result = get_arg_to_check(test_info.args)
- if not result and is_global:
- # See if this has been specified via UTC_ARGS. This is a "global" option
- # that affects the entire generation of test checks. If it exists anywhere
- # in the test, apply it to everything.
- saw_line = False
- for line_info in test_info.ro_iterlines():
- line = line_info.line
- if not line.startswith(';') and line.strip() != '':
- saw_line = True
- result = get_arg_to_check(line_info.args)
- if result:
- if warn and saw_line:
- # We saw the option after already reading some test input lines.
- # Warn about it.
- print('WARNING: Found {} in line following test start: '.format(arg_string)
- + line, file=sys.stderr)
- print('WARNING: Consider moving {} to top of file'.format(arg_string),
- file=sys.stderr)
- break
- return result
+ result = get_arg_to_check(test_info.args)
+ if not result and is_global:
+ # See if this has been specified via UTC_ARGS. This is a "global" option
+ # that affects the entire generation of test checks. If it exists anywhere
+ # in the test, apply it to everything.
+ saw_line = False
+ for line_info in test_info.ro_iterlines():
+ line = line_info.line
+ if not line.startswith(";") and line.strip() != "":
+ saw_line = True
+ result = get_arg_to_check(line_info.args)
+ if result:
+ if warn and saw_line:
+ # We saw the option after already reading some test input lines.
+ # Warn about it.
+ print(
+ "WARNING: Found {} in line following test start: ".format(
+ arg_string
+ )
+ + line,
+ file=sys.stderr,
+ )
+ print(
+ "WARNING: Consider moving {} to top of file".format(arg_string),
+ file=sys.stderr,
+ )
+ break
+ return result
+
def dump_input_lines(output_lines, test_info, prefix_set, comment_string):
- for input_line_info in test_info.iterlines(output_lines):
- line = input_line_info.line
- args = input_line_info.args
- if line.strip() == comment_string:
- continue
- if line.strip() == comment_string + SEPARATOR:
- continue
- if line.lstrip().startswith(comment_string):
- m = CHECK_RE.match(line)
- if m and m.group(1) in prefix_set:
- continue
- output_lines.append(line.rstrip('\n'))
-
-def add_checks_at_end(output_lines, prefix_list, func_order,
- comment_string, check_generator):
- added = set()
- generated_prefixes = set()
- for prefix in prefix_list:
- prefixes = prefix[0]
- tool_args = prefix[1]
- for prefix in prefixes:
- for func in func_order[prefix]:
- # The func order can contain the same functions multiple times.
- # If we see one again we are done.
- if (func, prefix) in added:
- continue
- if added:
- output_lines.append(comment_string)
-
- # The add_*_checks routines expect a run list whose items are
- # tuples that have a list of prefixes as their first element and
- # tool command args string as their second element. They output
- # checks for each prefix in the list of prefixes. By doing so, it
- # implicitly assumes that for each function every run line will
- # generate something for that function. That is not the case for
- # generated functions as some run lines might not generate them
- # (e.g. -fopenmp vs. no -fopenmp).
- #
- # Therefore, pass just the prefix we're interested in. This has
- # the effect of generating all of the checks for functions of a
- # single prefix before moving on to the next prefix. So checks
- # are ordered by prefix instead of by function as in "normal"
- # mode.
- for generated_prefix in check_generator(output_lines,
- [([prefix], tool_args)], func):
- added.add((func, generated_prefix))
- generated_prefixes.add(generated_prefix)
- return generated_prefixes
+ for input_line_info in test_info.iterlines(output_lines):
+ line = input_line_info.line
+ args = input_line_info.args
+ if line.strip() == comment_string:
+ continue
+ if line.strip() == comment_string + SEPARATOR:
+ continue
+ if line.lstrip().startswith(comment_string):
+ m = CHECK_RE.match(line)
+ if m and m.group(1) in prefix_set:
+ continue
+ output_lines.append(line.rstrip("\n"))
+
+
+def add_checks_at_end(
+ output_lines, prefix_list, func_order, comment_string, check_generator
+):
+ added = set()
+ generated_prefixes = set()
+ for prefix in prefix_list:
+ prefixes = prefix[0]
+ tool_args = prefix[1]
+ for prefix in prefixes:
+ for func in func_order[prefix]:
+ # The func order can contain the same functions multiple times.
+ # If we see one again we are done.
+ if (func, prefix) in added:
+ continue
+ if added:
+ output_lines.append(comment_string)
+
+ # The add_*_checks routines expect a run list whose items are
+ # tuples that have a list of prefixes as their first element and
+ # tool command args string as their second element. They output
+ # checks for each prefix in the list of prefixes. By doing so, it
+ # implicitly assumes that for each function every run line will
+ # generate something for that function. That is not the case for
+ # generated functions as some run lines might not generate them
+ # (e.g. -fopenmp vs. no -fopenmp).
+ #
+ # Therefore, pass just the prefix we're interested in. This has
+ # the effect of generating all of the checks for functions of a
+ # single prefix before moving on to the next prefix. So checks
+ # are ordered by prefix instead of by function as in "normal"
+ # mode.
+ for generated_prefix in check_generator(
+ output_lines, [([prefix], tool_args)], func
+ ):
+ added.add((func, generated_prefix))
+ generated_prefixes.add(generated_prefix)
+ return generated_prefixes
diff --git a/llvm/utils/UpdateTestChecks/isel.py b/llvm/utils/UpdateTestChecks/isel.py
index c10a555..bdb68e5 100644
--- a/llvm/utils/UpdateTestChecks/isel.py
+++ b/llvm/utils/UpdateTestChecks/isel.py
@@ -3,10 +3,12 @@ from . import common
import sys
if sys.version_info[0] > 2:
- class string:
- expandtabs = str.expandtabs
+
+ class string:
+ expandtabs = str.expandtabs
+
else:
- import string
+ import string
# Support of isel debug checks
# RegEx: this is where the magic happens.
@@ -15,43 +17,64 @@ else:
# TODO: add function prefix
ISEL_FUNCTION_DEFAULT_RE = re.compile(
- r'Selected[\s]*selection[\s]*DAG:[\s]*%bb.0[\s]*\'(?P<func>.*?):[^\']*\'*\n'
- r'(?P<body>.*?)\n'
- r'Total[\s]*amount[\s]*of[\s]*phi[\s]*nodes[\s]*to[\s]*update:[\s]*[0-9]+',
- flags=(re.M | re.S))
+ r"Selected[\s]*selection[\s]*DAG:[\s]*%bb.0[\s]*\'(?P<func>.*?):[^\']*\'*\n"
+ r"(?P<body>.*?)\n"
+ r"Total[\s]*amount[\s]*of[\s]*phi[\s]*nodes[\s]*to[\s]*update:[\s]*[0-9]+",
+ flags=(re.M | re.S),
+)
+
def scrub_isel_default(isel, args):
- # Scrub runs of whitespace out of the iSel debug output, but leave the leading
- # whitespace in place.
- isel = common.SCRUB_WHITESPACE_RE.sub(r' ', isel)
- # Expand the tabs used for indentation.
- isel = string.expandtabs(isel, 2)
- # Strip trailing whitespace.
- isel = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', isel)
- return isel
+ # Scrub runs of whitespace out of the iSel debug output, but leave the leading
+ # whitespace in place.
+ isel = common.SCRUB_WHITESPACE_RE.sub(r" ", isel)
+ # Expand the tabs used for indentation.
+ isel = string.expandtabs(isel, 2)
+ # Strip trailing whitespace.
+ isel = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", isel)
+ return isel
+
def get_run_handler(triple):
- target_handlers = {
- }
- handler = None
- best_prefix = ''
- for prefix, s in target_handlers.items():
- if triple.startswith(prefix) and len(prefix) > len(best_prefix):
- handler = s
- best_prefix = prefix
+ target_handlers = {}
+ handler = None
+ best_prefix = ""
+ for prefix, s in target_handlers.items():
+ if triple.startswith(prefix) and len(prefix) > len(best_prefix):
+ handler = s
+ best_prefix = prefix
+
+ if handler is None:
+ common.debug("Using default handler.")
+ handler = (scrub_isel_default, ISEL_FUNCTION_DEFAULT_RE)
- if handler is None:
- common.debug('Using default handler.')
- handler = (scrub_isel_default, ISEL_FUNCTION_DEFAULT_RE)
+ return handler
- return handler
##### Generator of iSel CHECK lines
-def add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name,
- global_vars_seen_dict, is_filtered):
- # Label format is based on iSel string.
- check_label_format = '{} %s-LABEL: %s%s%s%s'.format(comment_marker)
- return common.add_checks(output_lines, comment_marker, prefix_list, func_dict,
- func_name, check_label_format, True, False, 1,
- global_vars_seen_dict, is_filtered=is_filtered)
+
+def add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ global_vars_seen_dict,
+ is_filtered,
+):
+ # Label format is based on iSel string.
+ check_label_format = "{} %s-LABEL: %s%s%s%s".format(comment_marker)
+ return common.add_checks(
+ output_lines,
+ comment_marker,
+ prefix_list,
+ func_dict,
+ func_name,
+ check_label_format,
+ True,
+ False,
+ 1,
+ global_vars_seen_dict,
+ is_filtered=is_filtered,
+ )