画像: UCB-BAR: RISC-V Instruction Set Architecture より。
久しぶりにISSのメンテナンスをしていたのだが、結構落ちているパタンがある。これをメンテしていると、いろいろ考えなければならないところがあって実装をちょっとずつ変更していった。
整数の除算オーバフローに気を付ける
恥ずかしい話だがこれに気を付けたことがなかった。整数除算の際に発生する。非序数が最小値(INT64_MIN)で序数が-1だと発生する。これも条件付けしてやらないと浮動小数点例外が発生して落ちた。
- res = rs1_val / rs2_val; + DWord_t rs1_val = m_env->GRegRead<DWord_t> (rs1_addr); + DWord_t rs2_val = m_env->GRegRead<DWord_t> (rs2_addr); + + DWord_t res; + if (rs2_val == 0) { + res = -1; + } else if ((rs1_val == INT64_MIN) && (rs2_val == -1)) { + res = INT64_MIN; + } else { + res = rs1_val / rs2_val; + } + m_env->GRegWrite (rd_addr, res); } - m_env->GRegWrite (rd_addr, res);
浮動小数点異常値の取り扱い
これはアーキテクチャによっても異なる部分だと思う。また、RISC-Vにおいてはそのあたりが明確に定義されていないため、テストパタンの結果を見ながら確認していく必要がある。
基本的にはオペランドの中に非正規化数が存在すれば、結果も非正規化数にする必要がある。また、演算結果が異状な場合でも、最終的にどのような値にするかを確認しながら実装しなければならない。
たとえば、Super-Hの命令セット一覧にはちゃんと以下のような表が定義されている。以下は浮動小数点数から整数への変換を行うFTRC命令の発生しうる例外と、異常値が生成されたときの動作。
http://documentation.renesas.com/doc/products/mpumcu/rjj09b0090_sh4a.pdf より抜粋。
RISC-Vはここまできちんとマニュアルが書かれていないから大変なんだよなあ。。。 とりあえず演算前と演算後に条件をいろいろ追加している。以下は倍精度浮動小数点数から64bit符号なし整数への変換処理だが、
- 入力値が非正規化数であれば、例外フラグを立ててAll-1を返す
- 入力値が正の無限大であれば、例外フラグを立てて正の最大整数値を返す
- 入力値が負の無限大であれば、例外フラグを立てて0(正の最小整数値)を返す
- 変換結果が異常(非正規化数、これは例えば64bit符号なし整数に入りきらない値であったなど)であれば、フラグを立てて0を返す。
など、いろいろ条件を追加しないとテストパタンを通過させることができない。
@@ -778,9 +796,27 @@ UDWord_t InstOps::Convert_DtoLU (DWord_t op1, uint8_t round_mode, UWord_t *fflag float64_t f_op1; f_op1.v = op1; + if (isDoubleNaN (op1)) { + softfloat_exceptionFlags = softfloat_flag_invalid; + return UINT64_MAX; + } + if (isDoublePlusInf (op1)) { + softfloat_exceptionFlags = softfloat_flag_infinite; + return UINT64_MAX; + } + if (isDoubleMinusInf (op1)) { + softfloat_exceptionFlags = softfloat_flag_infinite; + return 0; + } + softfloat_exceptionFlags = 0; UDWord_t res = f64_to_ui64 (f_op1, round_mode, true); *fflags = softfloat_exceptionFlags; + + if ((softfloat_exceptionFlags & softfloat_flag_invalid) != 0) { + res = 0; + } +
現在はいろいろ修正して、やっとFailパタンが25本まで落ち着いてきた(約450本中)。
94% tests passed, 25 tests failed out of 445 Total Test time (real) = 80.75 sec The following tests FAILED: 8 - rv32mi-p-timer (Failed) 9 - rv32si-p-csr (Failed) 47 - rv32ui-pm-lrsc (Failed) 126 - rv64mi-p-dirty (Failed) 130 - rv64mi-p-mcsr (Failed) 134 - rv64mi-p-timer (Failed) 136 - rv64si-p-csr (Failed) 154 - rv64uf-p-recoding (Failed) 167 - rv64uf-pt-recoding (Failed) 180 - rv64uf-v-recoding (Failed) 191 - rv64ui-p-amomaxu_d (Failed) 200 - rv64ui-p-amoswap_d (Failed) 230 - rv64ui-pm-lrsc (Failed) 231 - rv64ui-p-mul (Failed) 233 - rv64ui-p-mulhsu (Failed) 274 - rv64ui-pt-amomaxu_d (Failed) 283 - rv64ui-pt-amoswap_d (Failed) 313 - rv64ui-pt-mul (Failed) 315 - rv64ui-pt-mulhsu (Failed) 360 - rv64ui-v-amomaxu_d (Failed) 369 - rv64ui-v-amoswap_d (Failed) 399 - rv64ui-v-mul (Failed) 401 - rv64ui-v-mulhsu (Failed) 436 - median (Failed) 443 - spmv (Failed)