diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 70e1086da8..e13e4b94a1 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -7532,10 +7532,56 @@ static bool TryCombineTempStoreLoadWithStoreSourceAdjust(DeterministicSpriteGrou return false; } -static void OptimiseVarAction2DeterministicSpriteGroupInsertJumps(DeterministicSpriteGroup *group) +static void OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotations(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking) +{ + std::bitset<256> bits; + if (var_tracking != nullptr) bits = var_tracking->out; + + for (int i = (int)group->adjusts.size() - 1; i >= 0; i--) { + DeterministicSpriteGroupAdjust &adjust = group->adjusts[i]; + + if (adjust.operation == DSGA_OP_STO) { + if (adjust.type == DSGA_TYPE_NONE && adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask < 0x100) { + /* Predictable store */ + bits.set(adjust.and_mask, false); + } + } + if (adjust.variable == 0x7B && adjust.parameter == 0x7D) { + /* Unpredictable load */ + bits.set(); + } + if (adjust.variable == 0x7D && adjust.parameter < 0x100) { + if (!bits[adjust.parameter]) { + bits.set(adjust.parameter, true); + adjust.adjust_flags |= DSGAF_LAST_VAR_READ; + } + } + if (adjust.variable == 0x7E) { + /* procedure call */ + auto handle_group = y_combinator([&](auto handle_group, const SpriteGroup *sg) -> void { + if (sg == nullptr) return; + if (sg->type == SGT_RANDOMIZED) { + const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; + for (const auto &group : rsg->groups) { + handle_group(group); + } + } else if (sg->type == SGT_DETERMINISTIC) { + const DeterministicSpriteGroup *sub = static_cast(sg); + VarAction2GroupVariableTracking *var_tracking = _cur.GetVarAction2GroupVariableTracking(sub, false); + if (var_tracking != nullptr) bits |= var_tracking->in; + } + }); + handle_group(adjust.subroutine); + } + } +} + +static void OptimiseVarAction2DeterministicSpriteGroupInsertJumps(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking) { if (HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_INSERT_JUMPS)) return; + OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotations(group, var_tracking); + for (int i = (int)group->adjusts.size() - 1; i >= 1; i--) { DeterministicSpriteGroupAdjust &adjust = group->adjusts[i]; @@ -7930,7 +7976,6 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite } if (add) { substitution_candidates.push_back(adjust.parameter | (i << 8)); - const_cast(adjust).adjust_flags |= DSGAF_LAST_VAR_READ; } } else { bits.set(adjust.parameter, true); @@ -8004,7 +8049,7 @@ static void HandleVarAction2OptimisationPasses() OptimiseVarAction2DeterministicSpriteGroupSimplifyStores(group); OptimiseVarAction2DeterministicSpriteGroupAdjustOrdering(group); if (!(group->dsg_flags & DSGF_NO_DSE)) { - OptimiseVarAction2DeterministicSpriteGroupInsertJumps(group); + OptimiseVarAction2DeterministicSpriteGroupInsertJumps(group, var_tracking); } if (group->dsg_flags & DSGF_CHECK_EXPENSIVE_VARS) { OptimiseVarAction2DeterministicSpriteGroupExpensiveVars(group);