From 5062b35b7dcbcf9b10df3628f9a914f6f0a6cbbb Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 17 Dec 2023 14:47:02 +0000 Subject: [PATCH] VarAction2: Handle deterministic/CB groups under real sprite groups in optimiser See: #618 --- src/newgrf_optimiser.cpp | 114 ++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 32 deletions(-) diff --git a/src/newgrf_optimiser.cpp b/src/newgrf_optimiser.cpp index 708776f6db..b27684689b 100644 --- a/src/newgrf_optimiser.cpp +++ b/src/newgrf_optimiser.cpp @@ -717,6 +717,65 @@ static uint TryMergeVarAction2AdjustConstantOperations(DeterministicSpriteGroupA return 1; } +static inline bool IsSimpleContainerSpriteGroup(const SpriteGroup *group) { + return group != nullptr && (group->type == SGT_RANDOMIZED || group->type == SGT_REAL); +} + +struct SimpleContainerSpriteGroupIterator { + typedef const SpriteGroup * value_type; + typedef const SpriteGroup * *pointer; + typedef const SpriteGroup * &reference; + typedef size_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit SimpleContainerSpriteGroupIterator(const SpriteGroup * const * current, const SpriteGroup * const * end, const SpriteGroup * const * next) + : current(current), end(end), next(next) + { + this->ValidateIndex(); + }; + + bool operator==(const SimpleContainerSpriteGroupIterator &other) const { return this->current == other.current; } + bool operator!=(const SimpleContainerSpriteGroupIterator &other) const { return !(*this == other); } + const SpriteGroup *operator*() const { return *this->current; } + SimpleContainerSpriteGroupIterator &operator++() { ++this->current; this->ValidateIndex(); return *this; } + +private: + const SpriteGroup * const * current; + const SpriteGroup * const * end; + const SpriteGroup * const * next; + + void ValidateIndex() + { + if (this->current == this->end) this->current = this->next; + } +}; + +/* Wrapper to iterate the sprite groups within SGT_RANDOMIZED or SGT_REAL groups */ +struct IterateSimpleContainerSpriteGroup { + std::array begin_ptr{}; + std::array end_ptr{}; + + IterateSimpleContainerSpriteGroup(const SpriteGroup *sg) + { + if (sg == nullptr) return; + if (sg->type == SGT_RANDOMIZED) { + const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; + this->begin_ptr[0] = rsg->groups.data(); + this->end_ptr[0] = rsg->groups.data() + rsg->groups.size(); + } + if (sg->type == SGT_REAL) { + const RealSpriteGroup *rsg = (const RealSpriteGroup*)sg; + this->begin_ptr[0] = rsg->loaded.data(); + this->end_ptr[0] = rsg->loaded.data() + rsg->loaded.size(); + this->begin_ptr[1] = rsg->loading.data(); + this->end_ptr[1] = rsg->loading.data() + rsg->loading.size(); + } + } + + SimpleContainerSpriteGroupIterator begin() { return SimpleContainerSpriteGroupIterator(this->begin_ptr[0], this->end_ptr[0], this->begin_ptr[1]); } + SimpleContainerSpriteGroupIterator end() { return SimpleContainerSpriteGroupIterator(this->end_ptr[1], this->end_ptr[1], this->end_ptr[1]); } +}; + void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const VarAction2AdjustInfo info, DeterministicSpriteGroup *group, DeterministicSpriteGroupAdjust &adjust) { if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return; @@ -1057,9 +1116,8 @@ void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const VarAction2Ad bool seen_perm_store = false; auto handle_proc_stores = y_combinator([&](auto handle_proc_stores, 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) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_proc_stores(group); } } else if (sg->type == SGT_DETERMINISTIC) { @@ -1099,9 +1157,8 @@ void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const VarAction2Ad 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) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group); } } else if (sg->type == SGT_DETERMINISTIC) { @@ -1729,14 +1786,14 @@ struct CheckDeterministicSpriteGroupOutputVarBitsProcedureHandler { bool ProcessGroup(const SpriteGroup *sg, std::bitset<256> *input_bits, bool top_level) { if (sg == nullptr) return true; - if (sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - if (rsg->groups.empty()) return true; + if (IsSimpleContainerSpriteGroup(sg)) { bool non_handled = false; - for (const auto &group : rsg->groups) { + uint count = 0; + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { + count++; non_handled |= this->ProcessGroup(group, input_bits, top_level); } - return non_handled; + return non_handled || count == 0; } else if (sg->type == SGT_DETERMINISTIC) { const DeterministicSpriteGroup *sub = static_cast(sg); @@ -1923,9 +1980,8 @@ static bool OptimiseVarAction2DeterministicSpriteGroupExpensiveVarsInner(Determi VarAction2GroupVariableTracking *var_tracking = _cur.GetVarAction2GroupVariableTracking(sg, false); if (var_tracking != nullptr) usable_vars &= ~var_tracking->in; } - if (sg != nullptr && sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - for (const auto &group : rsg->groups) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group); } } @@ -2123,9 +2179,8 @@ static VarAction2ProcedureAnnotation *OptimiseVarAction2GetFilledProcedureAnnota if (is_new) { auto handle_group_contents = y_combinator([&](auto handle_group_contents, const SpriteGroup *sg) -> void { if (sg == nullptr || anno->unskippable) return; - if (sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - for (const auto &group : rsg->groups) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group_contents(group); } @@ -2282,9 +2337,8 @@ static void OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotat 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) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group); } @@ -2622,9 +2676,8 @@ void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &state, state.have_cb_handler = true; } } - if (sg != nullptr && sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - for (const auto &group : rsg->groups) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group, state); } } @@ -3024,9 +3077,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite 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) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group); } } else if (sg->type == SGT_DETERMINISTIC) { @@ -3110,9 +3162,8 @@ void HandleVarAction2OptimisationPasses() var_tracking->out |= targ_var_tracking->in; } } - if (sg != nullptr && sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - for (const auto &group : rsg->groups) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { handle_group(group); } } @@ -3172,9 +3223,8 @@ const SpriteGroup *PruneTargetSpriteGroup(const SpriteGroup *result) auto need_var1C = y_combinator([&](auto need_var1C, const SpriteGroup *sg) -> bool { if (sg == nullptr) return false; - if (sg->type == SGT_RANDOMIZED) { - const RandomizedSpriteGroup *rsg = (const RandomizedSpriteGroup*)sg; - for (const auto &group : rsg->groups) { + if (IsSimpleContainerSpriteGroup(sg)) { + for (const auto &group : IterateSimpleContainerSpriteGroup(sg)) { if (need_var1C(group)) return true; } } else if (sg->type == SGT_DETERMINISTIC) {