diff --git a/src/newgrf.cpp b/src/newgrf.cpp index fd9de57db2..42bbec7333 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5796,6 +5796,34 @@ static const DeterministicSpriteGroupAdjust *GetVarAction2PreviousSingleLoadAdju return nullptr; } +static const DeterministicSpriteGroupAdjust *GetVarAction2PreviousSingleStoreAdjust(const std::vector &adjusts, int start_index, bool *is_inverted) +{ + if (is_inverted != nullptr) *is_inverted = false; + for (int i = start_index; i >= 0; i--) { + const DeterministicSpriteGroupAdjust &prev = adjusts[i]; + if (prev.variable == 0x7E) { + /* Procedure call, don't use or go past this */ + break; + } + if (prev.operation == DSGA_OP_STO) { + if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) { + /* Temp store */ + return &prev; + } else { + /* Special register store or unpredictable store, don't try to optimise following load */ + break; + } + } else if (prev.operation == DSGA_OP_XOR && prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask == 1 && is_inverted != nullptr) { + /* XOR invert */ + *is_inverted = !(*is_inverted); + continue; + } else { + break; + } + } + return nullptr; +} + /* * Find and replace the result of: (var * flag) + (var * !flag) with var * "+" may be ADD, OR or XOR. @@ -6132,6 +6160,10 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp return GetVarAction2PreviousSingleLoadAdjust(group->adjusts, (int)group->adjusts.size() - 2, invert); }; + auto get_prev_single_store = [&](bool *invert) -> const DeterministicSpriteGroupAdjust* { + return GetVarAction2PreviousSingleStoreAdjust(group->adjusts, (int)group->adjusts.size() - 2, invert); + }; + if ((prev_inference & VA2AIF_SINGLE_LOAD) && adjust.operation == DSGA_OP_RST && adjust.variable != 0x1A && adjust.variable != 0x7D && adjust.variable != 0x7E) { /* See if this is a repeated load of a variable (not constant, temp store load or procedure call) */ const DeterministicSpriteGroupAdjust *prev_load = get_prev_single_load(nullptr); @@ -6564,8 +6596,23 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp store.var_source.and_mask = prev_load->and_mask; store.var_source.add_val = prev_load->add_val; store.var_source.divmod_val = prev_load->divmod_val; + break; } } + bool invert_store = false; + const DeterministicSpriteGroupAdjust *prev_store = get_prev_single_store((prev_inference & VA2AIF_ONE_OR_ZERO) ? &invert_store : nullptr); + if (prev_store != nullptr) { + /* This store is a clone of the previous store, or inverted clone of the previous store (bool) */ + store.inference |= VA2AIF_SINGLE_LOAD; + store.var_source.type = (invert_store ? DSGA_TYPE_EQ : DSGA_TYPE_NONE); + store.var_source.variable = 0x7D; + store.var_source.shift_num = 0; + store.var_source.parameter = prev_store->and_mask | (state.temp_stores[prev_store->and_mask].version << 8); + store.var_source.and_mask = 0xFFFFFFFF; + store.var_source.add_val = 0; + store.var_source.divmod_val = 0; + break; + } } else { /* Store to special register, this can change the result of future variable loads for some variables. * Assume all variables except temp storage for now.