diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 58298c9c83..4d60cbfa7d 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5852,6 +5852,10 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } } + if (adjust.variable != 0x7E && IsEvalAdjustWithZeroLastValueAlwaysZero(adjust.operation)) { + adjust.adjust_flags |= DSGAF_SKIP_ON_ZERO; + } + if ((prev_inference & VA2AIF_PREV_TERNARY) && adjust.variable == 0x1A && IsEvalAdjustUsableForConstantPropagation(adjust.operation)) { /* Propagate constant operation back into previous ternary */ DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; @@ -5862,7 +5866,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } else if ((prev_inference & VA2AIF_HAVE_CONSTANT) && adjust.variable == 0x1A && IsEvalAdjustUsableForConstantPropagation(adjust.operation)) { /* Reduce constant operation on previous constant */ replace_with_constant_load(EvaluateDeterministicSpriteGroupAdjust(group->size, adjust, nullptr, state.current_constant, UINT_MAX)); - } else if ((prev_inference & VA2AIF_HAVE_CONSTANT) && state.current_constant == 0 && adjust.variable != 0x7E && IsEvalAdjustWithZeroLastValueAlwaysZero(adjust.operation)) { + } else if ((prev_inference & VA2AIF_HAVE_CONSTANT) && state.current_constant == 0 && (adjust.adjust_flags & DSGAF_SKIP_ON_ZERO)) { /* Remove operation which does nothing when applied to 0 */ group->adjusts.pop_back(); state.inference = prev_inference; @@ -5880,6 +5884,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } } current.operation = DSGA_OP_RST; + current.adjust_flags = DSGAF_NONE; group->adjusts.push_back(current); OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back()); return; @@ -5917,6 +5922,9 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } else if (adjust.operation == DSGA_OP_OR || adjust.operation == DSGA_OP_XOR || adjust.operation == DSGA_OP_AND) { state.inference |= (prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO)); } + if (adjust.operation == DSGA_OP_OR && (prev_inference & VA2AIF_ONE_OR_ZERO) && adjust.variable != 0x7E) { + adjust.adjust_flags |= DSGAF_SKIP_ON_LSB_SET; + } } } else { if (adjust.and_mask == 0 && IsEvalAdjustWithZeroRemovable(adjust.operation)) { @@ -5936,6 +5944,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp /* Convert: store, load var, commutative op on stored --> (dead) store, commutative op var */ prev.operation = adjust.operation; group->adjusts.pop_back(); + state.inference = non_const_var_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO); OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back()); return; } @@ -5952,6 +5961,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp /* Convert: store, load var, subtract stored --> (dead) store, reverse subtract var */ prev.operation = DSGA_OP_RSUB; group->adjusts.pop_back(); + state.inference = non_const_var_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO); OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back()); return; } @@ -6068,6 +6078,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } if (adjust.and_mask <= 1) state.inference = prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO); state.inference |= prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO) & non_const_var_inference; + if ((non_const_var_inference & VA2AIF_ONE_OR_ZERO) || (adjust.and_mask <= 1)) adjust.adjust_flags |= DSGAF_SKIP_ON_LSB_SET; break; case DSGA_OP_XOR: if (adjust.variable == 0x1A && adjust.shift_num == 0 && group->adjusts.size() >= 2) { @@ -6081,6 +6092,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } if (prev.operation == DSGA_OP_UMIN && prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask == 1) { prev.operation = DSGA_OP_TERNARY; + prev.adjust_flags = DSGAF_NONE; prev.and_mask = 0; prev.add_val = 1; group->adjusts.pop_back(); @@ -6097,6 +6109,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp if (prev.operation == DSGA_OP_OR && prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask == adjust.and_mask) { prev.operation = DSGA_OP_AND; prev.and_mask = ~prev.and_mask; + prev.adjust_flags = DSGAF_NONE; group->adjusts.pop_back(); break; } @@ -6108,6 +6121,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp if ((prev_inference & VA2AIF_ONE_OR_ZERO) && adjust.variable == 0x1A && adjust.shift_num == 0 && group->adjusts.size() >= 2) { /* Found a ternary operator */ adjust.operation = DSGA_OP_TERNARY; + adjust.adjust_flags = DSGAF_NONE; while (group->adjusts.size() > 1) { /* Merge with previous if applicable */ const DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; @@ -6537,6 +6551,7 @@ static void OptimiseVarAction2DeterministicSpriteGroupSimplifyStores(Determinist if (ok) { const DeterministicSpriteGroupAdjust &src = group->adjusts[src_adjust]; adjust.operation = DSGA_OP_STO_NC; + adjust.adjust_flags = DSGAF_NONE; adjust.add_val = adjust.and_mask; adjust.variable = src.variable; adjust.parameter = src.parameter; diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 1fa56273c0..5757a62154 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -223,6 +223,9 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con ScopeResolver *scope = object.GetScope(this->var_scope); for (const auto &adjust : this->adjusts) { + 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; + /* Try to get the variable. We shall assume it is available, unless told otherwise. */ GetVariableExtra extra(adjust.and_mask << adjust.shift_num); if (adjust.variable == 0x7E) { @@ -772,8 +775,19 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint /* Temp storage load */ highlight_tag = (1 << 16) | (adjust.parameter & 0xFFFF); } + + auto append_flags = [&]() { + if (adjust.adjust_flags & DSGAF_SKIP_ON_ZERO) { + p += seprintf(p, lastof(this->buffer), ", skip on zero"); + } + if (adjust.adjust_flags & DSGAF_SKIP_ON_LSB_SET) { + p += seprintf(p, lastof(this->buffer), ", skip on LSB set"); + } + }; + if (adjust.operation == DSGA_OP_TERNARY) { p += seprintf(p, lastof(this->buffer), "%*sTERNARY: true: %X, false: %X", padding, "", adjust.and_mask, adjust.add_val); + append_flags(); print(); continue; } @@ -808,6 +822,7 @@ void SpriteGroupDumper::DumpSpriteGroup(const SpriteGroup *sg, int padding, uint } p += seprintf(p, lastof(this->buffer), ", op: "); p = GetAdjustOperationName(p, lastof(this->buffer), adjust.operation); + append_flags(); print(); if (adjust.variable == 0x7E && adjust.subroutine != nullptr) { this->DumpSpriteGroup(adjust.subroutine, padding + 5, 0); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 218432f16c..9d56e0e182 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -202,6 +202,13 @@ enum DeterministicSpriteGroupAdjustOperation : uint8 { static_assert((DSGA_OP_SLT ^ 1) == DSGA_OP_SGE); static_assert((DSGA_OP_SLE ^ 1) == DSGA_OP_SGT); +enum DeterministicSpriteGroupAdjustFlags : uint8 { + DSGAF_NONE = 0, + DSGAF_SKIP_ON_ZERO = 1 << 0, + DSGAF_SKIP_ON_LSB_SET = 1 << 1, +}; +DECLARE_ENUM_AS_BIT_SET(DeterministicSpriteGroupAdjustFlags); + inline bool IsEvalAdjustWithZeroRemovable(DeterministicSpriteGroupAdjustOperation op) { switch (op) { @@ -333,6 +340,7 @@ struct DeterministicSpriteGroupAdjust { DeterministicSpriteGroupAdjustType type; uint16 variable; byte shift_num; + DeterministicSpriteGroupAdjustFlags adjust_flags = DSGAF_NONE; uint32 parameter; ///< Used for variables between 0x60 and 0x7F inclusive. uint32 and_mask; uint32 add_val; @@ -340,7 +348,6 @@ struct DeterministicSpriteGroupAdjust { const SpriteGroup *subroutine; }; - struct DeterministicSpriteGroupRange { const SpriteGroup *group; uint32 low;