diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 6466a25363..839a296964 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -7584,6 +7584,8 @@ static void OptimiseVarAction2DeterministicSpriteGroupInsertJumps(DeterministicS { if (HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_INSERT_JUMPS)) return; + group->dsg_flags &= ~DSGF_CHECK_INSERT_JUMP; + OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotations(group, var_tracking); for (int i = (int)group->adjusts.size() - 1; i >= 1; i--) { @@ -7630,12 +7632,38 @@ static void OptimiseVarAction2DeterministicSpriteGroupInsertJumps(DeterministicS } } group->adjusts.insert(group->adjusts.begin() + j + 1, current); + group->dsg_flags |= DSGF_CHECK_INSERT_JUMP; i++; } } } } +static uint OptimiseVarAction2DeterministicSpriteResolveJumpsInner(DeterministicSpriteGroup *group, const uint start) +{ + for (uint i = start + 1; i < (uint)group->adjusts.size(); i++) { + if (group->adjusts[i].operation == DSGA_OP_JZ) { + i = OptimiseVarAction2DeterministicSpriteResolveJumpsInner(group, i); + } else if (group->adjusts[i].adjust_flags & DSGAF_END_BLOCK) { + group->adjusts[start].jump = i - start; + return i; + } + } + + NOT_REACHED(); +} + +static void OptimiseVarAction2DeterministicSpriteResolveJumps(DeterministicSpriteGroup *group) +{ + if (HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_INSERT_JUMPS)) return; + + for (uint i = 0; i < (uint)group->adjusts.size(); i++) { + if (group->adjusts[i].operation == DSGA_OP_JZ) { + i = OptimiseVarAction2DeterministicSpriteResolveJumpsInner(group, i); + } + } +} + static void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &state, const GrfSpecFeature feature, const byte varsize, DeterministicSpriteGroup *group) { if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return; @@ -8058,6 +8086,9 @@ static void HandleVarAction2OptimisationPasses() if (group->dsg_flags & DSGF_CHECK_EXPENSIVE_VARS) { OptimiseVarAction2DeterministicSpriteGroupExpensiveVars(group); } + if (group->dsg_flags & DSGF_CHECK_INSERT_JUMP) { + OptimiseVarAction2DeterministicSpriteResolveJumps(group); + } } } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index b29d0fa029..6bdfa31bd8 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -153,16 +153,10 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc return &this->default_scope; } -struct ConditionalNestingState { - uint depth = 0; - uint skip_until_depth = 0; - bool skipping = false; -}; - /* Evaluate an adjustment for a variable of the given size. * U is the unsigned type and S is the signed type to use. */ template -static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver *scope, U last_value, uint32 value, ConditionalNestingState *cond_nesting_state = nullptr) +static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver *scope, U last_value, uint32 value, const DeterministicSpriteGroupAdjust **adjust_iter = nullptr) { value >>= adjust.shift_num; value &= adjust.and_mask; @@ -209,10 +203,9 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver case DSGA_OP_STO_NC: _temp_store.StoreValue(adjust.divmod_val, (S)value); return last_value; case DSGA_OP_ABS: return ((S)last_value < 0) ? -((S)last_value) : (S)last_value; case DSGA_OP_JZ: { - if (value == 0 && cond_nesting_state != nullptr) { + if (value == 0 && adjust_iter != nullptr) { /* Jump */ - cond_nesting_state->skip_until_depth = cond_nesting_state->depth - 1; - cond_nesting_state->skipping = true; + (*adjust_iter) += adjust.jump; return 0; } else { /* Don't jump */ @@ -245,19 +238,10 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con ScopeResolver *scope = object.GetScope(this->var_scope); - ConditionalNestingState conditional_nesting = {}; + const DeterministicSpriteGroupAdjust *end = this->adjusts.data() + this->adjusts.size(); + for (const DeterministicSpriteGroupAdjust *iter = this->adjusts.data(); iter != end; ++iter) { + const DeterministicSpriteGroupAdjust &adjust = *iter; - for (const auto &adjust : this->adjusts) { - if (adjust.adjust_flags & DSGAF_END_BLOCK) { - conditional_nesting.depth--; - if (conditional_nesting.skipping && conditional_nesting.skip_until_depth == conditional_nesting.depth) { - /* End of block that was skipped */ - conditional_nesting.skipping = false; - continue; - } - } - if (adjust.operation == DSGA_OP_JZ) conditional_nesting.depth++; - if (conditional_nesting.skipping) continue; if ((adjust.adjust_flags & DSGAF_SKIP_ON_ZERO) && (last_value == 0)) continue; if ((adjust.adjust_flags & DSGAF_SKIP_ON_LSB_SET) && (last_value & 1) != 0) continue; @@ -286,9 +270,9 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con } switch (this->size) { - case DSG_SIZE_BYTE: value = EvalAdjustT (adjust, scope, last_value, value, &conditional_nesting); break; - case DSG_SIZE_WORD: value = EvalAdjustT(adjust, scope, last_value, value, &conditional_nesting); break; - case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, scope, last_value, value, &conditional_nesting); break; + case DSG_SIZE_BYTE: value = EvalAdjustT (adjust, scope, last_value, value, &iter); break; + case DSG_SIZE_WORD: value = EvalAdjustT(adjust, scope, last_value, value, &iter); break; + case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, scope, last_value, value, &iter); break; default: NOT_REACHED(); } last_value = value; @@ -817,6 +801,9 @@ static char *DumpSpriteGroupAdjust(char *p, const char *last, const Deterministi } p += seprintf(p, last, ", op: "); p = GetAdjustOperationName(p, last, adjust.operation); + if (adjust.operation == DSGA_OP_JZ) { + p += seprintf(p, last, " +%u", adjust.jump); + } append_flags(); return p; } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 9c84e36911..42990806a6 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -206,7 +206,7 @@ enum DeterministicSpriteGroupAdjustOperation : uint8 { DSGA_OP_RSUB, ///< b - a DSGA_OP_STO_NC, ///< store b into temporary storage, indexed by c. return a DSGA_OP_ABS, ///< abs(a) - DSGA_OP_JZ, ///< jump to adjust after DSGAF_END_BLOCK marker (taking into account nesting) if b is zero. return 0 if jumped, return a if not jumped + DSGA_OP_JZ, ///< jump forward fixed number of adjusts (to adjust after DSGAF_END_BLOCK marker (taking into account nesting)) if b is zero. return 0 if jumped, return a if not jumped DSGA_OP_SPECIAL_END, }; @@ -430,7 +430,10 @@ struct DeterministicSpriteGroupAdjust { uint32 and_mask; uint32 add_val; ///< Also used for DSGA_TYPE_EQ/DSGA_TYPE_NEQ constants and DSGA_OP_TERNARY false value uint32 divmod_val; ///< Also used for DSGA_OP_STO_NC - const SpriteGroup *subroutine; + union { + const SpriteGroup *subroutine; + uint32 jump; + }; }; struct DeterministicSpriteGroupRange {