diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 8471614d1e..54fa6d4dfa 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5531,6 +5531,7 @@ enum VarAction2AdjustInferenceFlags { VA2AIF_SIGNED_NON_NEGATIVE = 0x01, VA2AIF_ONE_OR_ZERO = 0x02, VA2AIF_PREV_TERNARY = 0x04, + VA2AIF_PREV_MASK_ADJUST = 0x08, }; DECLARE_ENUM_AS_BIT_SET(VarAction2AdjustInferenceFlags) @@ -5643,6 +5644,14 @@ static void NewSpriteGroup(ByteReader *buf) VarAction2AdjustInferenceFlags prev_inference = inference; inference = VA2AIF_NONE; + auto add_inferences_from_mask = [&](uint32 mask) { + if (mask == 1) { + inference |= VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO; + } else if ((mask & (1 << ((varsize * 8) - 1))) == 0) { + inference |= VA2AIF_SIGNED_NON_NEGATIVE; + } + }; + 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]; @@ -5666,6 +5675,15 @@ static void NewSpriteGroup(ByteReader *buf) if (adjust.and_mask <= 1) inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO; break; case DSGA_OP_AND: + if ((prev_inference & VA2AIF_PREV_MASK_ADJUST) && adjust.variable == 0x1A && adjust.shift_num == 0) { + /* Propagate and into immediately prior variable read */ + DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; + prev.and_mask &= adjust.and_mask; + add_inferences_from_mask(prev.and_mask); + inference |= VA2AIF_PREV_MASK_ADJUST; + group->adjusts.pop_back(); + break; + } if ((prev_inference & VA2AIF_SIGNED_NON_NEGATIVE) && adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1) { DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; if (prev.operation == DSGA_OP_SCMP || prev.operation == DSGA_OP_UCMP) { @@ -5733,18 +5751,32 @@ static void NewSpriteGroup(ByteReader *buf) case DSGA_OP_UCMP: inference = VA2AIF_SIGNED_NON_NEGATIVE; break; + case DSGA_OP_RST: + add_inferences_from_mask(adjust.and_mask); + inference |= VA2AIF_PREV_MASK_ADJUST; + break; + case DSGA_OP_SHR: + if ((prev_inference & VA2AIF_PREV_MASK_ADJUST) && adjust.variable == 0x1A && adjust.shift_num == 0) { + /* Propagate shift right into immediately prior variable read */ + DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2]; + if (prev.shift_num + adjust.and_mask < 32) { + prev.shift_num += adjust.and_mask; + prev.and_mask >>= adjust.and_mask; + add_inferences_from_mask(prev.and_mask); + inference |= VA2AIF_PREV_MASK_ADJUST; + group->adjusts.pop_back(); + break; + } + } default: break; } } } - } else { + } else if (adjust.type == DSGA_TYPE_NONE && group->adjusts.size() == 1) { /* First adjustment */ - if (adjust.and_mask == 1) { - inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO; - } else if ((adjust.and_mask & (1 << ((varsize * 8) - 1))) == 0) { - inference = VA2AIF_SIGNED_NON_NEGATIVE; - } + add_inferences_from_mask(adjust.and_mask); + inference |= VA2AIF_PREV_MASK_ADJUST; } /* Continue reading var adjusts while bit 5 is set. */