Verilatorの解析続き。
V3Const.cpp
には、いくつかの定数最適化が加わっているようだ。astgen
というPythonスクリプトによってソースコードが拡張されている。展開用のスクリプトは長くてすぐには理解できないのだが、生成されたソースコードを読んでみる。
verilator/src/obj_dbg/V3Const__gen.cpp
// Generated by astgen virtual void visit(AstAdd* nodep) override { iterateChildren(nodep); if (match_NodeBiop_0(nodep)) return; if (match_NodeBiCom_0(nodep)) return; if (match_NodeBiComAsv_0(nodep)) return; if (match_NodeBiComAsv_1(nodep)) return; if (match_NodeBiComAsv_2(nodep)) return; if (match_NodeBiComAsv_3(nodep)) return; if (match_Add_0(nodep)) return; if (match_Add_1(nodep)) return; }
AstAdd
ノードに遭遇すると、これらの最適化を行うようだ。
match_Add_0
/match_Add_1
どちらかのオペランドが0の場合は加算ノードを省略する。
bool match_Add_0(AstAdd* nodep) { // TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)") if (m_doNConst && nodep->lhsp()->isZero()) { UINFO(7,cvtToHex(nodep)<<" TREEOP ( AstAdd $lhsp.isZero, $rhsp , replaceWRhs(nodep) )\n"); replaceWRhs(nodep); return true; } return false; }
この条件はこのマクロから来ているようだ。
// Zero on one side or the other TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
AstNodeBiOp
は2項演算のノードにはすべて適用されるようだ。つまり、両方のオペランドが定数の場合はこれを置き換える。
// Generic constants on both side. Do this first to avoid other replacements TREEOPA("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)");
// Generated by astgen bool match_NodeBiop_0(AstNodeBiop* nodep) { // TREEOPA("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)") if (VN_IS(nodep->lhsp(),Const) && VN_IS(nodep->rhsp(),Const) && nodep->isPredictOptimizable()) { UINFO(7,cvtToHex(nodep)<<" TREEOPA( AstNodeBiop $lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable() , replaceConst(nodep) )\n"); replaceConst(nodep); return true; }
BiCom
というのは2項演算の可換な演算のようだ。これに対する最適化も定義されている。
if (match_NodeBiComAsv_0(nodep)) return; if (match_NodeBiComAsv_1(nodep)) return; if (match_NodeBiComAsv_2(nodep)) return; if (match_NodeBiComAsv_3(nodep)) return;