forked from OSchip/llvm-project
156 lines
4.5 KiB
Python
Executable File
156 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""This script verifies expression folding.
|
|
It compiles a source file with '-fdebug-dump-symbols'
|
|
and looks for parameter declarations to check
|
|
they have been folded as expected.
|
|
To check folding of an expression EXPR,
|
|
the fortran program passed to this script
|
|
must contain the following:
|
|
|
|
logical, parameter :: test_x = <compare EXPR to expected value>
|
|
|
|
This script will test that all parameter
|
|
with a name starting with "test_"
|
|
have been folded to .true.
|
|
For instance, acos folding can be tested with:
|
|
|
|
real(4), parameter :: res_acos = acos(0.5_4)
|
|
real(4), parameter :: exp_acos = 1.047
|
|
logical, parameter :: test_acos = abs(res_acos - exp_acos).LE.(0.001_4)
|
|
|
|
There are two kinds of failure:
|
|
- test_x is folded to .false..
|
|
This means the expression was folded
|
|
but the value is not as expected.
|
|
- test_x is not folded (it is neither .true. nor .false.).
|
|
This means the compiler could not fold the expression.
|
|
|
|
Parameters:
|
|
sys.argv[1]: a source file with contains the input and expected output
|
|
sys.argv[2]: the Flang frontend driver
|
|
sys.argv[3:]: Optional arguments to the Flang frontend driver"""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import re
|
|
import subprocess
|
|
|
|
from difflib import unified_diff
|
|
from pathlib import Path
|
|
|
|
def check_args(args):
|
|
"""Verifies that the number is arguments passed is correct."""
|
|
if len(args) < 3:
|
|
print(f"Usage: {args[0]} <fortran-source> <flang-command>")
|
|
sys.exit(1)
|
|
|
|
def set_source(source):
|
|
"""Sets the path to the source files."""
|
|
if not Path(source).is_file():
|
|
print(f"File not found: {src}")
|
|
sys.exit(1)
|
|
return Path(source)
|
|
|
|
def set_executable(exe):
|
|
"""Sets the path to the Flang frontend driver."""
|
|
if not Path(exe).is_file():
|
|
print(f"Flang was not found: {exe}")
|
|
sys.exit(1)
|
|
return str(Path(exe))
|
|
|
|
check_args(sys.argv)
|
|
cwd = os.getcwd()
|
|
srcdir = set_source(sys.argv[1]).resolve()
|
|
with open(srcdir, 'r', encoding="utf-8") as f:
|
|
src = f.readlines()
|
|
src1 = ""
|
|
src2 = ""
|
|
src3 = ""
|
|
src4 = ""
|
|
messages = ""
|
|
actual_warnings = ""
|
|
expected_warnings = ""
|
|
warning_diffs = ""
|
|
|
|
flang_fc1 = set_executable(sys.argv[2])
|
|
flang_fc1_args = sys.argv[3:]
|
|
flang_fc1_options = ""
|
|
LIBPGMATH = os.getenv('LIBPGMATH')
|
|
if LIBPGMATH:
|
|
flang_fc1_options = ["-fdebug-dump-symbols", "-DTEST_LIBPGMATH"]
|
|
print("Assuming libpgmath support")
|
|
else:
|
|
flang_fc1_options = ["-fdebug-dump-symbols"]
|
|
print("Not assuming libpgmath support")
|
|
|
|
cmd = [flang_fc1, *flang_fc1_args, *flang_fc1_options, str(srcdir)]
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
check=True, universal_newlines=True, cwd=tmpdir)
|
|
src1 = proc.stdout
|
|
messages = proc.stderr
|
|
|
|
for line in src1.split("\n"):
|
|
m = re.search(r"(\w*)(?=, PARAMETER).*init:(.*)", line)
|
|
if m:
|
|
src2 += f"{m.group(1)} {m.group(2)}\n"
|
|
|
|
for line in src2.split("\n"):
|
|
m = re.match(r"test_*", line)
|
|
if m:
|
|
src3 += f"{m.string}\n"
|
|
|
|
for passed_results, line in enumerate(src3.split("\n")):
|
|
m = re.search(r"\.false\._.$", line)
|
|
if m:
|
|
src4 += f"{line}\n"
|
|
|
|
for line in messages.split("\n"):
|
|
m = re.search(r"[^:]*:(\d*):\d*: (.*)", line)
|
|
if m:
|
|
actual_warnings += f"{m.group(1)}: {m.group(2)}\n"
|
|
|
|
passed_warnings = 0
|
|
warnings = []
|
|
for i, line in enumerate(src, 1):
|
|
m = re.search(r"(?:!WARN:)(.*)", line)
|
|
if m:
|
|
warnings.append(m.group(1))
|
|
continue
|
|
if warnings:
|
|
for x in warnings:
|
|
passed_warnings += 1
|
|
expected_warnings += f"{i}:{x}\n"
|
|
warnings = []
|
|
|
|
for line in unified_diff(actual_warnings.split("\n"),
|
|
expected_warnings.split("\n"), n=0):
|
|
line = re.sub(r"(^\-)(\d+:)", r"\nactual at \g<2>", line)
|
|
line = re.sub(r"(^\+)(\d+:)", r"\nexpect at \g<2>", line)
|
|
warning_diffs += line
|
|
|
|
if src4 or warning_diffs:
|
|
print("Folding test failed:")
|
|
# Prints failed tests, including parameters with the same
|
|
# suffix so that more information can be obtained by declaring
|
|
# expected_x and result_x
|
|
if src4:
|
|
for line in src4.split("\n"):
|
|
m = re.match(r"test_(\w+)", line)
|
|
if m:
|
|
for line in src2.split("\n"):
|
|
if m.group(1) in line:
|
|
print(line)
|
|
if warning_diffs:
|
|
print(warning_diffs)
|
|
print()
|
|
print("FAIL")
|
|
sys.exit(1)
|
|
else:
|
|
print()
|
|
print(f"All {passed_results+passed_warnings} tests passed")
|
|
print("PASS")
|
|
|