|
| 1 | +#!/bin/bash |
| 2 | +# SPDX-License-Identifier: LGPL-2.1-or-later |
| 3 | +# See Notices.txt for copyright information |
| 4 | +set -e |
| 5 | + |
| 6 | +if [[ -z "$SOFTFLOAT_VERIFY" ]] && ! SOFTFLOAT_VERIFY="`which softfloat-verify`"; then |
| 7 | + echo "can't find softfloat-verify in PATH" >&2 |
| 8 | + echo "get it from https://salsa.debian.org/Kazan-team/softfloat-verify" >&2 |
| 9 | + echo "then put built executable in PATH or set" >&2 |
| 10 | + echo "SOFTFLOAT_VERIFY to path of executable" >&2 |
| 11 | + exit 1 |
| 12 | +fi |
| 13 | + |
| 14 | +function fail() { |
| 15 | + echo "$*">&2 |
| 16 | + exit 1 |
| 17 | +} |
| 18 | + |
| 19 | +function write_test_case() { |
| 20 | + local value="$1" |
| 21 | + local op="$2" |
| 22 | + local exact="$3" |
| 23 | + local rounding_mode="$4" |
| 24 | + local src_width |
| 25 | + local dest_width |
| 26 | + local sf_op |
| 27 | + local dest_sign_mask=0 |
| 28 | + case "$op" in |
| 29 | + f16_to_u32) |
| 30 | + src_width=16 |
| 31 | + dest_width=32 |
| 32 | + sf_op=f16_to_ui32 |
| 33 | + ;; |
| 34 | + f16_to_i32) |
| 35 | + src_width=16 |
| 36 | + dest_width=32 |
| 37 | + sf_op=f16_to_i32 |
| 38 | + dest_sign_mask=0x80000000 |
| 39 | + ;; |
| 40 | + f16_to_u64) |
| 41 | + src_width=16 |
| 42 | + dest_width=64 |
| 43 | + sf_op=f16_to_ui64 |
| 44 | + ;; |
| 45 | + f16_to_i64) |
| 46 | + src_width=16 |
| 47 | + dest_width=64 |
| 48 | + sf_op=f16_to_i64 |
| 49 | + dest_sign_mask=0x8000000000000000 |
| 50 | + ;; |
| 51 | + f32_to_u32) |
| 52 | + src_width=32 |
| 53 | + dest_width=32 |
| 54 | + sf_op=f32_to_ui32 |
| 55 | + ;; |
| 56 | + f32_to_i32) |
| 57 | + src_width=32 |
| 58 | + dest_width=32 |
| 59 | + sf_op=f32_to_i32 |
| 60 | + dest_sign_mask=0x80000000 |
| 61 | + ;; |
| 62 | + f32_to_u64) |
| 63 | + src_width=32 |
| 64 | + dest_width=64 |
| 65 | + sf_op=f32_to_ui64 |
| 66 | + ;; |
| 67 | + f32_to_i64) |
| 68 | + src_width=32 |
| 69 | + dest_width=64 |
| 70 | + sf_op=f32_to_i64 |
| 71 | + dest_sign_mask=0x8000000000000000 |
| 72 | + ;; |
| 73 | + *) |
| 74 | + fail "op not implemented: $op" |
| 75 | + ;; |
| 76 | + esac |
| 77 | + printf -v value "0x%0*X" $((src_width / 4)) $((value)) |
| 78 | + local sf_rounding_mode |
| 79 | + case "$rounding_mode" in |
| 80 | + TiesToEven) |
| 81 | + sf_rounding_mode=near_even |
| 82 | + ;; |
| 83 | + TowardZero) |
| 84 | + sf_rounding_mode=minMag |
| 85 | + ;; |
| 86 | + TowardNegative) |
| 87 | + sf_rounding_mode=min |
| 88 | + ;; |
| 89 | + TowardPositive) |
| 90 | + sf_rounding_mode=max |
| 91 | + ;; |
| 92 | + TiesToAway) |
| 93 | + sf_rounding_mode=near_maxMag |
| 94 | + ;; |
| 95 | + *) |
| 96 | + fail "invalid rounding mode: $rounding_mode" |
| 97 | + ;; |
| 98 | + esac |
| 99 | + local sf_exact |
| 100 | + case "$exact" in |
| 101 | + false) |
| 102 | + sf_exact=0 |
| 103 | + ;; |
| 104 | + true) |
| 105 | + sf_exact=1 |
| 106 | + ;; |
| 107 | + *) |
| 108 | + fail "invalid exact flag: $exact" |
| 109 | + ;; |
| 110 | + esac |
| 111 | + local input="softfloat_round_$sf_rounding_mode softfloat_roundingMode_write_helper" |
| 112 | + input+=" 0 softfloat_exceptionFlags_write_helper" |
| 113 | + input+=" $value softfloat_round_$sf_rounding_mode $sf_exact $sf_op" |
| 114 | + input+=" softfloat_exceptionFlags_read_helper" |
| 115 | + input+=" softfloat_flag_inexact" |
| 116 | + input+=" softfloat_flag_underflow" |
| 117 | + input+=" softfloat_flag_overflow" |
| 118 | + input+=" softfloat_flag_infinite" |
| 119 | + input+=" softfloat_flag_invalid" |
| 120 | + local output |
| 121 | + output=(`echo "$input" | "$SOFTFLOAT_VERIFY"`) || fail $'softfloat-verify failed. input:\n'"$input" |
| 122 | + ((${#output[@]} == 7)) || fail $'softfloat-verify returned invalid number of outputs. input:\n'"$input" |
| 123 | + local result="${output[0]}" |
| 124 | + local flags="${output[1]}" |
| 125 | + local flag_inexact="${output[2]}" |
| 126 | + local flag_underflow="${output[3]}" |
| 127 | + local flag_overflow="${output[4]}" |
| 128 | + local flag_infinite="${output[5]}" |
| 129 | + local flag_invalid="${output[6]}" |
| 130 | + local decoded_flags=() |
| 131 | + ((flags & flag_inexact)) && decoded_flags+=("INEXACT") |
| 132 | + ((flags & flag_underflow)) && decoded_flags+=("UNDERFLOW") |
| 133 | + ((flags & flag_overflow)) && decoded_flags+=("OVERFLOW") |
| 134 | + ((flags & flag_infinite)) && decoded_flags+=("DIVISION_BY_ZERO") |
| 135 | + ((flags & flag_invalid)) && decoded_flags+=("INVALID_OPERATION") |
| 136 | + if ((flags & flag_invalid)); then |
| 137 | + result="None" |
| 138 | + elif ((result & dest_sign_mask)); then |
| 139 | + printf -v result "%s0x%X" '-' $((-result)) |
| 140 | + else |
| 141 | + printf -v result "0x%X" $((result)) |
| 142 | + fi |
| 143 | + if (( ${#decoded_flags[@]} )); then |
| 144 | + printf -v flags "%s|" "${decoded_flags[@]}" |
| 145 | + flags="${flags%%|}" |
| 146 | + else |
| 147 | + flags="(empty)" |
| 148 | + fi |
| 149 | + echo "$value $exact $rounding_mode $result $flags" |
| 150 | +} |
| 151 | + |
| 152 | +f16_test_case_list=(0x0000 0x0001 0x03FF 0x0400 0x3C00 0x3C01 0x7BFF 0x7C00 0x7C01 0x7DFF 0x7E00 0x7FFF) |
| 153 | +f16_test_case_list+=(0x8000 0x8001 0x83FF 0x8400 0xBC00 0xBC01 0xFBFF 0xFC00 0xFC01 0xFDFF 0xFE00 0xFFFF) |
| 154 | +f16_test_case_list+=(0x3400 0x3800 0x3A00 0x3C00 0x3D00 0x3E00 0x3F00 0x4000 0x4080 0x4100 0x4180 0x4200) |
| 155 | +f16_test_case_list+=(0xB400 0xB800 0xBA00 0xBC00 0xBD00 0xBE00 0xBF00 0xC000 0xC080 0xC100 0xC180 0xC200) |
| 156 | +f32_test_case_list=(0x00000000 0x00000001 0x007FFFFF 0x00800000 0x3F800000 0x3F800001 0x7F7FFFFF 0x7F800000 0x7F800001 0x7FBFFFFF 0x7FC00000 0x7FFFFFFF) |
| 157 | +f32_test_case_list+=(0x80000000 0x80000001 0x807FFFFF 0x80800000 0xBF800000 0xBF800001 0xFF7FFFFF 0xFF800000 0xFF800001 0xFFBFFFFF 0xFFC00000 0xFFFFFFFF) |
| 158 | +f32_test_case_list+=(0x3E800000 0x3F000000 0x3F400000 0x3F800000 0x3FA00000 0x3FC00000 0x3FE00000 0x40000000 0x40100000 0x40200000 0x40300000 0x40400000) |
| 159 | +f32_test_case_list+=(0xBE800000 0xBF000000 0xBF400000 0xBF800000 0xBFA00000 0xBFC00000 0xBFE00000 0xC0000000 0xC0100000 0xC0200000 0xC0300000 0xC0400000) |
| 160 | +f32_test_case_list+=(0x33800000 0x387FC000 0x38800000 0x3F800000 0x3F802000 0x477FE000 0x47800000) |
| 161 | +f32_test_case_list+=(0xB3800000 0xB87FC000 0xB8800000 0xBF800000 0xBF802000 0xC77FE000 0xC7800000) |
| 162 | +f32_test_case_list+=(0x4EFFFFFF 0x4F000000 0x4F000001 0x4F7FFFFF 0x4F800000 0x4F800001 0x5EFFFFFF 0x5F000000 0x5F000001 0x5F7FFFFF 0x5F800000 0x5F800001) |
| 163 | +f32_test_case_list+=(0xCEFFFFFF 0xCF000000 0xCF000001 0xCF7FFFFF 0xCF800000 0xCF800001 0xDEFFFFFF 0xDF000000 0xDF000001 0xDF7FFFFF 0xDF800000 0xDF800001) |
| 164 | +ops=(f16_to_u32 f16_to_i32 f16_to_u64 f16_to_i64) |
| 165 | +ops+=(f32_to_u32 f32_to_i32 f32_to_u64 f32_to_i64) |
| 166 | +rounding_modes=(TiesToEven TowardZero TowardNegative TowardPositive TiesToAway) |
| 167 | + |
| 168 | +for op in "${ops[@]}"; do |
| 169 | + exec > "test_data/$op.txt" |
| 170 | + first=1 |
| 171 | + for rounding_mode in "${rounding_modes[@]}"; do |
| 172 | + for exact in false true; do |
| 173 | + if ((first)); then |
| 174 | + first=0 |
| 175 | + else |
| 176 | + echo |
| 177 | + fi |
| 178 | + echo "# testing $op with exact=$exact $rounding_mode" |
| 179 | + case "$op" in |
| 180 | + f16_to_*) |
| 181 | + test_case_list=("${f16_test_case_list[@]}") |
| 182 | + ;; |
| 183 | + f32_to_*) |
| 184 | + test_case_list=("${f32_test_case_list[@]}") |
| 185 | + ;; |
| 186 | + *) |
| 187 | + fail "op not implemented: $op" |
| 188 | + ;; |
| 189 | + esac |
| 190 | + for value in "${test_case_list[@]}"; do |
| 191 | + write_test_case $value $op $exact $rounding_mode |
| 192 | + done |
| 193 | + printf "." >&2 |
| 194 | + done |
| 195 | + done & |
| 196 | +done |
| 197 | +wait |
| 198 | +echo >&2 |
0 commit comments