|
|
|
@ -742,6 +742,59 @@ void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSpecFeatu
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto try_inline_procedure = [&]() -> bool {
|
|
|
|
|
if (adjust.operation != DSGA_OP_RST || adjust.type != DSGA_TYPE_NONE || state.var_1C_present) return false;
|
|
|
|
|
|
|
|
|
|
const SpriteGroup *subroutine = adjust.subroutine;
|
|
|
|
|
|
|
|
|
|
if (subroutine == nullptr || subroutine->type != SGT_DETERMINISTIC || subroutine->feature != group->feature) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DeterministicSpriteGroup *dsg = (const DeterministicSpriteGroup*)subroutine;
|
|
|
|
|
if (!(dsg->dsg_flags & DSGF_INLINE_CANDIDATE) || dsg->var_scope != group->var_scope || dsg->size != group->size) return false;
|
|
|
|
|
|
|
|
|
|
std::vector<DeterministicSpriteGroupAdjust> *proc = _cur.GetInlinableGroupAdjusts(dsg, false);
|
|
|
|
|
if (proc == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
byte shift_num = adjust.shift_num;
|
|
|
|
|
uint32 and_mask = adjust.and_mask;
|
|
|
|
|
|
|
|
|
|
// Initial value state is 0
|
|
|
|
|
replace_with_constant_load(0);
|
|
|
|
|
|
|
|
|
|
for (const DeterministicSpriteGroupAdjust &proc_adjust : *proc) {
|
|
|
|
|
group->adjusts.push_back(proc_adjust);
|
|
|
|
|
OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back());
|
|
|
|
|
}
|
|
|
|
|
if (shift_num != 0) {
|
|
|
|
|
DeterministicSpriteGroupAdjust &adj = group->adjusts.emplace_back();
|
|
|
|
|
adj.operation = DSGA_OP_SHR;
|
|
|
|
|
adj.variable = 0x1A;
|
|
|
|
|
adj.shift_num = 0;
|
|
|
|
|
adj.type = DSGA_TYPE_NONE;
|
|
|
|
|
adj.and_mask = shift_num;
|
|
|
|
|
adj.add_val = 0;
|
|
|
|
|
adj.divmod_val = 0;
|
|
|
|
|
OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back());
|
|
|
|
|
}
|
|
|
|
|
if (and_mask != 0xFFFFFFFF) {
|
|
|
|
|
DeterministicSpriteGroupAdjust &adj = group->adjusts.emplace_back();
|
|
|
|
|
adj.operation = DSGA_OP_AND;
|
|
|
|
|
adj.variable = 0x1A;
|
|
|
|
|
adj.shift_num = 0;
|
|
|
|
|
adj.type = DSGA_TYPE_NONE;
|
|
|
|
|
adj.and_mask = and_mask;
|
|
|
|
|
adj.add_val = 0;
|
|
|
|
|
adj.divmod_val = 0;
|
|
|
|
|
OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group->sg_flags |= SGF_INLINING;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Special handling of variable 7B, this uses the parameter as the variable number, and the last value as the variable's parameter.
|
|
|
|
|
* If the last value is a known constant, it can be substituted immediately. */
|
|
|
|
|
if (adjust.variable == 0x7B) {
|
|
|
|
@ -772,6 +825,7 @@ void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSpecFeatu
|
|
|
|
|
const VarAction2TempStoreInference &store = iter->second;
|
|
|
|
|
if (store.inference & VA2AIF_HAVE_CONSTANT) {
|
|
|
|
|
adjust.variable = 0x1A;
|
|
|
|
|
adjust.parameter = 0;
|
|
|
|
|
adjust.and_mask &= (store.store_constant >> adjust.shift_num);
|
|
|
|
|
} else if ((store.inference & VA2AIF_SINGLE_LOAD) && (store.var_source.variable == 0x7D || IsVariableVeryCheap(store.var_source.variable, feature))) {
|
|
|
|
|
if (adjust.type == DSGA_TYPE_NONE && adjust.shift_num == 0 && (adjust.and_mask == 0xFFFFFFFF || ((store.inference & VA2AIF_ONE_OR_ZERO) && (adjust.and_mask & 1)))) {
|
|
|
|
@ -904,6 +958,8 @@ void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSpecFeatu
|
|
|
|
|
/* Procedure call or complex adjustment */
|
|
|
|
|
if (adjust.operation == DSGA_OP_STO) handle_unpredictable_temp_store();
|
|
|
|
|
if (adjust.variable == 0x7E) {
|
|
|
|
|
if (try_inline_procedure()) return;
|
|
|
|
|
|
|
|
|
|
std::bitset<256> seen_stores;
|
|
|
|
|
bool seen_unpredictable_store = false;
|
|
|
|
|
bool seen_special_store = false;
|
|
|
|
@ -2311,7 +2367,30 @@ static void OptimiseVarAction2DeterministicSpriteResolveJumps(DeterministicSprit
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &state, const GrfSpecFeature feature, const byte varsize, DeterministicSpriteGroup *group)
|
|
|
|
|
static const size_t MAX_PROC_INLINE_ADJUST_COUNT = 5;
|
|
|
|
|
|
|
|
|
|
static void OptimiseVarAction2CheckInliningCandidate(DeterministicSpriteGroup *group, std::vector<DeterministicSpriteGroupAdjust> &saved_adjusts)
|
|
|
|
|
{
|
|
|
|
|
if (HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_PROC_INLINE)) return;
|
|
|
|
|
if (group->adjusts.size() > MAX_PROC_INLINE_ADJUST_COUNT || !group->calculated_result || group->var_scope != VSG_SCOPE_SELF) return;
|
|
|
|
|
|
|
|
|
|
for (const DeterministicSpriteGroupAdjust &adjust : group->adjusts) {
|
|
|
|
|
uint variable = adjust.variable;
|
|
|
|
|
if (variable == 0x7B) variable = adjust.parameter;
|
|
|
|
|
if (variable == 0xC || variable == 0x10 || variable == 0x18 || variable == 0x1A || (variable >= 0x7D && variable <= 0x7F)) {
|
|
|
|
|
// OK
|
|
|
|
|
} else if (variable == 0x7C) {
|
|
|
|
|
if (group->feature != GSF_AIRPORTS && group->feature != GSF_INDUSTRIES) return;
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group->dsg_flags |= DSGF_INLINE_CANDIDATE;
|
|
|
|
|
*(_cur.GetInlinableGroupAdjusts(group, true)) = std::move(saved_adjusts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &state, const GrfSpecFeature feature, const byte varsize, DeterministicSpriteGroup *group, std::vector<DeterministicSpriteGroupAdjust> &saved_adjusts)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return;
|
|
|
|
|
|
|
|
|
@ -2506,6 +2585,8 @@ void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &state,
|
|
|
|
|
OptimiseVarAction2DeterministicSpriteGroupAdjustOrdering(group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OptimiseVarAction2CheckInliningCandidate(group, saved_adjusts);
|
|
|
|
|
|
|
|
|
|
if (state.check_expensive_vars && !HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_EXPENSIVE_VARS)) {
|
|
|
|
|
if (dse_candidate) {
|
|
|
|
|
group->dsg_flags |= DSGF_CHECK_EXPENSIVE_VARS;
|
|
|
|
|