3 """This script verifies expression folding.
4 It compiles a source file with '-fdebug-dump-symbols'
5 and looks for parameter declarations to check
6 they have been folded as expected.
7 To check folding of an expression EXPR,
8 the fortran program passed to this script
9 must contain the following:
11 logical, parameter :: test_x = <compare EXPR to expected value>
13 This script will test that all parameter
14 with a name starting with "test_"
15 have been folded to .true.
16 For instance, acos folding can be tested with:
18 real(4), parameter :: res_acos = acos(0.5_4)
19 real(4), parameter :: exp_acos = 1.047
20 logical, parameter :: test_acos = abs(res_acos - exp_acos).LE.(0.001_4)
22 There are two kinds of failure:
23 - test_x is folded to .false..
24 This means the expression was folded
25 but the value is not as expected.
26 - test_x is not folded (it is neither .true. nor .false.).
27 This means the compiler could not fold the expression.
30 sys.argv[1]: a source file with contains the input and expected output
31 sys.argv[2]: the Flang frontend driver
32 sys.argv[3:]: Optional arguments to the Flang frontend driver"""
40 from difflib
import unified_diff
41 from pathlib
import Path
44 """Verifies that the number is arguments passed is correct."""
46 print(f
"Usage: {args[0]} <fortran-source> <flang-command>")
49 def set_source(source
):
50 """Sets the path to the source files."""
51 if not Path(source
).is_file():
52 print(f
"File not found: {src}")
56 def set_executable(exe
):
57 """Sets the path to the Flang frontend driver."""
58 if not Path(exe
).is_file():
59 print(f
"Flang was not found: {exe}")
65 srcdir
= set_source(sys
.argv
[1]).resolve()
66 with
open(srcdir
, 'r', encoding
="utf-8") as f
:
74 expected_warnings
= ""
77 flang_fc1
= set_executable(sys
.argv
[2])
78 flang_fc1_args
= sys
.argv
[3:]
79 flang_fc1_options
= ""
80 LIBPGMATH
= os
.getenv('LIBPGMATH')
82 flang_fc1_options
= ["-fdebug-dump-symbols", "-DTEST_LIBPGMATH"]
83 print("Assuming libpgmath support")
85 flang_fc1_options
= ["-fdebug-dump-symbols"]
86 print("Not assuming libpgmath support")
88 cmd
= [flang_fc1
, *flang_fc1_args
, *flang_fc1_options
, str(srcdir
)]
89 with tempfile
.TemporaryDirectory() as tmpdir
:
90 proc
= subprocess
.run(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
,
91 check
=True, universal_newlines
=True, cwd
=tmpdir
)
93 messages
= proc
.stderr
95 for line
in src1
.split("\n"):
96 m
= re
.search(r
"(\w*)(?=, PARAMETER).*init:(.*)", line
)
98 src2
+= f
"{m.group(1)} {m.group(2)}\n"
100 for line
in src2
.split("\n"):
101 m
= re
.match(r
"test_*", line
)
103 src3
+= f
"{m.string}\n"
105 for passed_results
, line
in enumerate(src3
.split("\n")):
106 m
= re
.search(r
"\.false\._.$", line
)
110 for line
in messages
.split("\n"):
111 m
= re
.search(r
"[^:]*:(\d*):\d*: (.*)", line
)
113 actual_warnings
+= f
"{m.group(1)}: {m.group(2)}\n"
117 for i
, line
in enumerate(src
, 1):
118 m
= re
.search(r
"(?:!WARN:)(.*)", line
)
120 warnings
.append(m
.group(1))
125 expected_warnings
+= f
"{i}:{x}\n"
128 for line
in unified_diff(actual_warnings
.split("\n"),
129 expected_warnings
.split("\n"), n
=0):
130 line
= re
.sub(r
"(^\-)(\d+:)", r
"\nactual at \g<2>", line
)
131 line
= re
.sub(r
"(^\+)(\d+:)", r
"\nexpect at \g<2>", line
)
132 warning_diffs
+= line
134 if src4
or warning_diffs
:
135 print("Folding test failed:")
136 # Prints failed tests, including parameters with the same
137 # suffix so that more information can be obtained by declaring
138 # expected_x and result_x
140 for line
in src4
.split("\n"):
141 m
= re
.match(r
"test_(\w+)", line
)
143 for line
in src2
.split("\n"):
144 if m
.group(1) in line
:
153 print(f
"All {passed_results+passed_warnings} tests passed")