VarAction2: Allow inlining trivial procedures

This commit is contained in:
Jonathan G Rennison
2022-10-01 22:32:00 +01:00
parent 9e24414033
commit c2ede2af54
6 changed files with 125 additions and 5 deletions

View File

@@ -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;