1#!/bin/sh
2
3type=float
4abi=0
5name=
6srcdir="$(cd "${0%/*}" && pwd)/tests"
7sim="$GCC_TEST_SIMULATOR"
8quiet=false
9verbose=false
10timeout=180
11run_expensive=false
12if [ -n "$GCC_TEST_RUN_EXPENSIVE" ]; then
13  run_expensive=true
14fi
15keep_failed=false
16only=
17
18usage() {
19  cat <<EOF
20Usage: $0 [Options] <g++ invocation>
21
22Options:
23  -h, --help          Print this message and exit.
24  -q, --quiet         Only print failures.
25  -v, --verbose       Print compiler and test output on failure.
26  -t <type>, --type <type>
27                      The value_type to test (default: $type).
28  -a [0-9], --abi [0-9]
29                      The ABI tag subset to test (default: $abi).
30  -n <name>, --name <name>
31                      The name of the test (required).
32  -k, --keep-failed   Keep executables of failed tests.
33  --srcdir <path>     The source directory of the tests (default: $srcdir).
34  --sim <executable>  Path to an executable that is prepended to the test
35                      execution binary (default: the value of
36                      GCC_TEST_SIMULATOR).
37  --timeout-factor <x>
38                      Multiply the default timeout with x.
39  --run-expensive     Compile and run tests marked as expensive (default:
40                      true if GCC_TEST_RUN_EXPENSIVE is set, false otherwise).
41  --only <pattern>    Compile and run only tests matching the given pattern.
42EOF
43}
44
45while [ $# -gt 0 ]; do
46  case "$1" in
47  -h|--help)
48    usage
49    exit
50    ;;
51  -q|--quiet)
52    quiet=true
53    ;;
54  -v|--verbose)
55    verbose=true
56    ;;
57  --run-expensive)
58    run_expensive=true
59    ;;
60  -k|--keep-failed)
61    keep_failed=true
62    ;;
63  --only)
64    only="$2"
65    shift
66    ;;
67  --only=*)
68    only="${1#--only=}"
69    ;;
70  -t|--type)
71    type="$2"
72    shift
73    ;;
74  --type=*)
75    type="${1#--type=}"
76    ;;
77  -a|--abi)
78    abi="$2"
79    shift
80    ;;
81  --abi=*)
82    abi="${1#--abi=}"
83    ;;
84  -n|--name)
85    name="$2"
86    shift
87    ;;
88  --name=*)
89    name="${1#--name=}"
90    ;;
91  --srcdir)
92    srcdir="$2"
93    shift
94    ;;
95  --srcdir=*)
96    srcdir="${1#--srcdir=}"
97    ;;
98  --sim)
99    sim="$2"
100    shift
101    ;;
102  --sim=*)
103    sim="${1#--sim=}"
104    ;;
105  --timeout-factor)
106    timeout=$(awk "BEGIN { print int($timeout * $2) }")
107    shift
108    ;;
109  --timeout-factor=*)
110    x=${1#--timeout-factor=}
111    timeout=$(awk "BEGIN { print int($timeout * $x) }")
112    ;;
113  --)
114    shift
115    break
116    ;;
117  *)
118    break
119    ;;
120  esac
121  shift
122done
123
124CXX="$1"
125shift
126CXXFLAGS="$@"
127src="${srcdir}/${name}.cc"
128shorttype=$(echo $type|sed -e 's/long /l/' -e 's/unsigned /u/' -e 's/signed /s/')
129testname="${name}-${shorttype}-${abi}"
130exe="${testname}.exe"
131log="${testname}.log"
132sum="${testname}.sum"
133if [ -n "$only" ]; then
134  if echo "$testname"|awk "{ exit /$only/ }"; then
135    touch "$log" "$sum"
136    exit 0
137  fi
138fi
139
140if [ $abi -eq 0 ]; then
141  abiflag=""
142elif [ $abi -gt 0 -a $abi -lt 10 ]; then
143  abiflag="-DEXTENDEDTESTS=$((abi-1))"
144else
145  echo "Error: The -a argument must be a value between 0 and 9 (inclusive)." >&2
146  exit 1
147fi
148
149fail() {
150  echo "FAIL: $src $type $abiflag ($*)" | tee -a "$sum" "$log"
151}
152
153xpass() {
154  echo "XPASS: $src $type $abiflag ($*)" | tee -a "$sum" "$log"
155}
156
157xfail() {
158  $quiet || echo "XFAIL: $src $type $abiflag ($*)"
159  echo "XFAIL: $src $type $abiflag ($*)" >> "$sum"
160  echo "XFAIL: $src $type $abiflag ($*)" >> "$log"
161}
162
163pass() {
164  $quiet || echo "PASS: $src $type $abiflag ($*)"
165  echo "PASS: $src $type $abiflag ($*)" >> "$sum"
166  echo "PASS: $src $type $abiflag ($*)" >> "$log"
167}
168
169unsupported() {
170  $quiet || echo "UNSUPPORTED: $src $type $abiflag ($*)"
171  echo "UNSUPPORTED: $src $type $abiflag ($*)" >> "$sum"
172  echo "UNSUPPORTED: $src $type $abiflag ($*)" >> "$log"
173}
174
175write_log_and_verbose() {
176  echo "$*" >> "$log"
177  if $verbose; then
178    if [ -z "$COLUMNS" ] || ! type fmt>/dev/null; then
179      echo "$*"
180    else
181      echo "$*" | fmt -w $COLUMNS -s - || cat
182    fi
183  fi
184}
185
186matches() {
187  eval "case '$1' in
188    $2) return 0;; esac"
189  return 1
190}
191
192test_selector() {
193  string="$1"
194  pat_type="${string%% *}"
195  if matches "$shorttype" "$pat_type"; then
196    string="${string#* }"
197    pat_abi="${string%% *}"
198    if matches "$abi" "$pat_abi"; then
199      string="${string#* }"
200      pat_triplet="${string%% *}"
201      [ -z "$target_triplet" ] && target_triplet=$($CXX -dumpmachine)
202      if matches "$target_triplet" "$pat_triplet"; then
203        pat_flags="${string#* }"
204        if matches "$CXXFLAGS" "*$pat_flags*"; then
205          return 0
206        fi
207      fi
208    fi
209  fi
210  return 1
211}
212
213trap "rm -f '$log' '$sum' $exe; exit" INT
214rm -f "$log" "$sum"
215touch "$log" "$sum"
216
217read_src_option() {
218  local key tmp var
219  key="$1"
220  var="$2"
221  [ -z "$var" ] && var="$1"
222  local tmp="$(head -n25 "$src" | grep "^//\\s*${key}: ")"
223  if [ -n "$tmp" ]; then
224    tmp="$(echo "${tmp#//*${key}: }" | sed -e 's/ \+/ /g' -e 's/^ //' -e 's/$//')"
225    eval "$var=\"$tmp\""
226  else
227    return 1
228  fi
229}
230
231if read_src_option skip; then
232  if test_selector "$skip"; then
233    # silently skip this test
234    exit 0
235  fi
236fi
237if read_src_option only; then
238  if ! test_selector "$only"; then
239    # silently skip this test
240    exit 0
241  fi
242fi
243
244if ! $run_expensive; then
245  if read_src_option expensive; then
246    if test_selector "$expensive"; then
247      unsupported "skip expensive tests"
248      exit 0
249    fi
250  fi
251fi
252
253if read_src_option xfail; then
254  if test_selector "${xfail#* }"; then
255    xfail="${xfail%% *}"
256  else
257    unset xfail
258  fi
259fi
260
261read_src_option timeout
262
263if read_src_option timeout-factor factor; then
264  timeout=$(awk "BEGIN { print int($timeout * $factor) }")
265fi
266
267log_output() {
268  if $verbose; then
269    maxcol=${1:-1024}
270    awk "
271BEGIN { count = 0 }
272/^###exitstatus### [0-9]+$/ { exit \$2 }
273{
274  print >> \"$log\"
275  if (count >= 1000) {
276    print \"Aborting: too much output\" >> \"$log\"
277    print \"Aborting: too much output\"
278    exit 125
279  }
280  ++count
281  if (length(\$0) > $maxcol) {
282    i = 1
283    while (i + $maxcol <= length(\$0)) {
284      len = $maxcol
285      line = substr(\$0, i, len)
286      len = match(line, / [^ ]*$/)
287      if (len <= 0) {
288        len = match(substr(\$0, i), / [^ ]/)
289        if (len <= 0) len = $maxcol
290      }
291      print substr(\$0, i, len)
292      i += len
293    }
294    print substr(\$0, i)
295  } else {
296    print
297  }
298}
299END { close(\"$log\") }
300"
301  else
302    awk "
303BEGIN { count = 0 }
304/^###exitstatus### [0-9]+$/ { exit \$2 }
305{
306  print >> \"$log\"
307  if (count >= 1000) {
308    print \"Aborting: too much output\" >> \"$log\"
309    print \"Aborting: too much output\"
310    exit 125
311  }
312  ++count
313}
314END { close(\"$log\") }
315"
316  fi
317}
318
319verify_compilation() {
320  log_output $COLUMNS
321  exitstatus=$?
322  if [ $exitstatus -eq 0 ]; then
323    warnings=$(grep -ic 'warning:' "$log")
324    if [ $warnings -gt 0 ]; then
325      fail "excess warnings:" $warnings
326      if ! $verbose && ! $quiet; then
327        grep -i 'warning:' "$log" | head -n5
328      fi
329    elif [ "$xfail" = "compile" ]; then
330      xpass "test for excess errors"
331    else
332      pass "test for excess errors"
333    fi
334    return 0
335  else
336    if [ $exitstatus -eq 124 ]; then
337      fail "timeout: test for excess errors"
338    else
339      errors=$(grep -ic 'error:' "$log")
340      if [ "$xfail" = "compile" ]; then
341        xfail "excess errors:" $errors
342        exit 0
343      else
344        fail "excess errors:" $errors
345      fi
346    fi
347    if ! $verbose && ! $quiet; then
348      grep -i 'error:' "$log" | head -n5
349    fi
350    return 1
351  fi
352}
353
354verify_test() {
355  log_output $COLUMNS
356  exitstatus=$?
357  if [ $exitstatus -eq 0 ]; then
358    if [ "$xfail" = "run" ]; then
359      $keep_failed || rm "$exe"
360      xpass "execution test"
361    else
362      rm "$exe"
363      pass "execution test"
364    fi
365    return 0
366  else
367    $keep_failed || rm "$exe"
368    if ! $verbose && ! $quiet; then
369      grep -i fail "$log" | head -n5
370    fi
371    if [ $exitstatus -eq 124 ]; then
372      fail "timeout: execution test"
373    elif [ "$xfail" = "run" ]; then
374      xfail "execution test"
375    else
376      fail "execution test"
377    fi
378    return 1
379  fi
380}
381
382write_log_and_verbose "$CXX $src $@ -D_GLIBCXX_SIMD_TESTTYPE=$type $abiflag -o $exe"
383{
384  timeout --foreground $timeout "$CXX" "$src" "$@" "-D_GLIBCXX_SIMD_TESTTYPE=$type" $abiflag -o "$exe" 2>&1 <&-
385  printf "###exitstatus### %d\n" $?
386} | verify_compilation || exit 0
387if [ -n "$sim" ]; then
388  write_log_and_verbose "$sim ./$exe"
389else
390  write_log_and_verbose "./$exe"
391  timeout=$(awk "BEGIN { print int($timeout / 2) }")
392fi
393{
394  timeout --foreground $timeout $sim "./$exe" 2>&1 <&-
395  printf "###exitstatus### %d\n" $?
396} | verify_test || exit 0
397
398# vim: sw=2 et cc=81 si
399