diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 42bbec7333..759693421a 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5633,8 +5633,9 @@ enum VarAction2AdjustInferenceFlags { VA2AIF_HAVE_CONSTANT = 0x20, VA2AIF_SINGLE_LOAD = 0x40, VA2AIF_MUL_BOOL = 0x80, + VA2AIF_PREV_SCMP_DEC = 0x100, - VA2AIF_PREV_MASK = VA2AIF_PREV_TERNARY | VA2AIF_PREV_MASK_ADJUST | VA2AIF_PREV_STORE_TMP, + VA2AIF_PREV_MASK = VA2AIF_PREV_TERNARY | VA2AIF_PREV_MASK_ADJUST | VA2AIF_PREV_STORE_TMP | VA2AIF_PREV_SCMP_DEC, }; DECLARE_ENUM_AS_BIT_SET(VarAction2AdjustInferenceFlags) @@ -6322,6 +6323,12 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp } } } + if (adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1 && group->adjusts.size() >= 2) { + DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; + if (prev.operation == DSGA_OP_SCMP) { + state.inference |= VA2AIF_PREV_SCMP_DEC; + } + } try_merge_with_previous(); break; case DSGA_OP_SMIN: @@ -6543,6 +6550,23 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp state.inference = VA2AIF_PREV_TERNARY; break; } + if ((prev_inference & VA2AIF_PREV_SCMP_DEC) && group->adjusts.size() >= 4 && adjust.variable == 0x7D && adjust.shift_num == 0 && adjust.and_mask == 0xFFFFFFFF) { + const DeterministicSpriteGroupAdjust &adj1 = group->adjusts[group->adjusts.size() - 4]; + const DeterministicSpriteGroupAdjust &adj2 = group->adjusts[group->adjusts.size() - 3]; + const DeterministicSpriteGroupAdjust &adj3 = group->adjusts[group->adjusts.size() - 2]; + auto is_expected_op = [](const DeterministicSpriteGroupAdjust &adj, DeterministicSpriteGroupAdjustOperation op, uint32 value) -> bool { + return adj.operation == op && adj.type == DSGA_TYPE_NONE && adj.variable == 0x1A && adj.shift_num == 0 && adj.and_mask == value; + }; + if (is_expected_op(adj1, DSGA_OP_STO, (adjust.parameter & 0xFF)) && + is_expected_op(adj2, DSGA_OP_SCMP, 0) && + is_expected_op(adj3, DSGA_OP_SUB, 1)) { + group->adjusts.pop_back(); + group->adjusts.pop_back(); + group->adjusts.back().operation = DSGA_OP_ABS; + state.inference |= VA2AIF_SIGNED_NON_NEGATIVE; + break; + } + } uint32 sign_bit = (1 << ((varsize * 8) - 1)); if ((prev_inference & VA2AIF_PREV_MASK_ADJUST) && (prev_inference & VA2AIF_SIGNED_NON_NEGATIVE) && adjust.variable == 0x1A && adjust.shift_num == 0 && (adjust.and_mask & sign_bit) == 0) { /* Determine whether the result will be always non-negative */ diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 09ed4a4b3d..3d0f42b543 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -200,6 +200,7 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver case DSGA_OP_SGT: return ((S)last_value > (S)value) ? 1 : 0; case DSGA_OP_RSUB: return value - last_value; 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; default: return value; } } @@ -683,6 +684,7 @@ static const char *_dsg_op_special_names[] { "SGT", "RSUB", "STO_NC", + "ABS", }; static_assert(lengthof(_dsg_op_special_names) == DSGA_OP_SPECIAL_END - DSGA_OP_TERNARY); @@ -727,6 +729,11 @@ static char *DumpSpriteGroupAdjust(char *p, const char *last, const Deterministi append_flags(); return p; } + if (adjust.operation == DSGA_OP_ABS) { + p += seprintf(p, last, "%*sABS", padding, ""); + append_flags(); + return p; + } if (adjust.operation == DSGA_OP_STO && adjust.type == DSGA_TYPE_NONE && adjust.variable == 0x1A && adjust.shift_num == 0) { /* Temp storage store */ highlight_tag = (1 << 16) | (adjust.and_mask & 0xFFFF); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 8e667210eb..63728e9561 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -198,6 +198,7 @@ enum DeterministicSpriteGroupAdjustOperation : uint8 { DSGA_OP_SGT, ///< (signed) a > b ? 1 : 0, 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_SPECIAL_END, };