VarAction2: Avoid group variable tracking coupling through shared procs
Output dependencies on a procedure shouldn't propagate into input dependencies on unrelated call sites in different groups
This commit is contained in:
@@ -101,6 +101,7 @@ static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400);
|
|||||||
struct VarAction2GroupVariableTracking {
|
struct VarAction2GroupVariableTracking {
|
||||||
std::bitset<256> in;
|
std::bitset<256> in;
|
||||||
std::bitset<256> out;
|
std::bitset<256> out;
|
||||||
|
std::bitset<256> proc_call_out;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VarAction2ProcedureAnnotation {
|
struct VarAction2ProcedureAnnotation {
|
||||||
@@ -7377,10 +7378,14 @@ static bool CheckDeterministicSpriteGroupOutputVarBits(const DeterministicSprite
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (procedure_dse_ok()) {
|
if (procedure_dse_ok()) {
|
||||||
std::bitset<256> new_out = bits | var_tracking->out;
|
std::bitset<256> new_proc_call_out = bits | var_tracking->proc_call_out;
|
||||||
if (new_out != var_tracking->out) {
|
if (new_proc_call_out != var_tracking->proc_call_out) {
|
||||||
var_tracking->out = new_out;
|
var_tracking->proc_call_out = new_proc_call_out;
|
||||||
CheckDeterministicSpriteGroupOutputVarBits(sub, new_out, false);
|
std::bitset<256> old_total = var_tracking->out | var_tracking->proc_call_out;
|
||||||
|
std::bitset<256> new_total = var_tracking->out | new_proc_call_out;
|
||||||
|
if (old_total != new_total) {
|
||||||
|
CheckDeterministicSpriteGroupOutputVarBits(sub, new_total, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RecursiveDisallowDSEForProcedure(sub);
|
RecursiveDisallowDSEForProcedure(sub);
|
||||||
@@ -7399,7 +7404,7 @@ static bool OptimiseVarAction2DeterministicSpriteGroupExpensiveVarsInner(Determi
|
|||||||
btree::btree_map<uint64, uint32> seen_expensive_variables;
|
btree::btree_map<uint64, uint32> seen_expensive_variables;
|
||||||
std::bitset<256> usable_vars;
|
std::bitset<256> usable_vars;
|
||||||
if (var_tracking != nullptr) {
|
if (var_tracking != nullptr) {
|
||||||
usable_vars = ~var_tracking->out;
|
usable_vars = ~(var_tracking->out | var_tracking->proc_call_out);
|
||||||
} else {
|
} else {
|
||||||
usable_vars.set();
|
usable_vars.set();
|
||||||
}
|
}
|
||||||
@@ -7798,7 +7803,7 @@ static std::vector<VarAction2ProcedureCallVarReadAnnotation> _varaction2_proc_ca
|
|||||||
static void OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotations(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking)
|
static void OptimiseVarAction2DeterministicSpriteGroupPopulateLastVarReadAnnotations(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking)
|
||||||
{
|
{
|
||||||
std::bitset<256> bits;
|
std::bitset<256> bits;
|
||||||
if (var_tracking != nullptr) bits = var_tracking->out;
|
if (var_tracking != nullptr) bits = (var_tracking->out | var_tracking->proc_call_out);
|
||||||
bool need_var1C = false;
|
bool need_var1C = false;
|
||||||
|
|
||||||
for (int i = (int)group->adjusts.size() - 1; i >= 0; i--) {
|
for (int i = (int)group->adjusts.size() - 1; i >= 0; i--) {
|
||||||
@@ -8187,14 +8192,19 @@ static void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &
|
|||||||
|
|
||||||
static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking, bool no_changes)
|
static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSpriteGroup *group, VarAction2GroupVariableTracking *var_tracking, bool no_changes)
|
||||||
{
|
{
|
||||||
std::bitset<256> bits;
|
std::bitset<256> all_bits;
|
||||||
|
std::bitset<256> propagate_bits;
|
||||||
std::vector<uint> substitution_candidates;
|
std::vector<uint> substitution_candidates;
|
||||||
if (var_tracking != nullptr) bits = var_tracking->out;
|
if (var_tracking != nullptr) {
|
||||||
|
propagate_bits = var_tracking->out;
|
||||||
|
all_bits = propagate_bits | var_tracking->proc_call_out;
|
||||||
|
}
|
||||||
bool need_var1C = false;
|
bool need_var1C = false;
|
||||||
|
|
||||||
auto abandon_substitution_candidates = [&]() {
|
auto abandon_substitution_candidates = [&]() {
|
||||||
for (uint value : substitution_candidates) {
|
for (uint value : substitution_candidates) {
|
||||||
bits.set(value & 0xFF, true);
|
all_bits.set(value & 0xFF, true);
|
||||||
|
propagate_bits.set(value & 0xFF, true);
|
||||||
}
|
}
|
||||||
substitution_candidates.clear();
|
substitution_candidates.clear();
|
||||||
};
|
};
|
||||||
@@ -8234,9 +8244,11 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
pending_restart = false;
|
pending_restart = false;
|
||||||
i = (int)group->adjusts.size() - 1;
|
i = (int)group->adjusts.size() - 1;
|
||||||
if (var_tracking != nullptr) {
|
if (var_tracking != nullptr) {
|
||||||
bits = var_tracking->out;
|
propagate_bits = var_tracking->out;
|
||||||
|
all_bits = propagate_bits | var_tracking->proc_call_out;
|
||||||
} else {
|
} else {
|
||||||
bits.reset();
|
all_bits.reset();
|
||||||
|
propagate_bits.reset();
|
||||||
}
|
}
|
||||||
substitution_candidates.clear();
|
substitution_candidates.clear();
|
||||||
need_var1C = false;
|
need_var1C = false;
|
||||||
@@ -8255,7 +8267,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
bool substituted = try_variable_substitution(target, i - 1, idx);
|
bool substituted = try_variable_substitution(target, i - 1, idx);
|
||||||
if (!substituted) {
|
if (!substituted) {
|
||||||
/* Not usable, mark as required so it's not eliminated */
|
/* Not usable, mark as required so it's not eliminated */
|
||||||
bits.set(idx, true);
|
all_bits.set(idx, true);
|
||||||
|
propagate_bits.set(idx, true);
|
||||||
}
|
}
|
||||||
substitution_candidates[j] = substitution_candidates.back();
|
substitution_candidates[j] = substitution_candidates.back();
|
||||||
substitution_candidates.pop_back();
|
substitution_candidates.pop_back();
|
||||||
@@ -8263,7 +8276,7 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bits[idx] && !no_changes) {
|
if (!all_bits[idx] && !no_changes) {
|
||||||
/* Redundant store */
|
/* Redundant store */
|
||||||
erase_adjust(i);
|
erase_adjust(i);
|
||||||
i--;
|
i--;
|
||||||
@@ -8360,7 +8373,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
/* Non-redundant store */
|
/* Non-redundant store */
|
||||||
bits.set(idx, false);
|
all_bits.set(idx, false);
|
||||||
|
propagate_bits.set(idx, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Unpredictable store */
|
/* Unpredictable store */
|
||||||
@@ -8369,11 +8383,12 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
}
|
}
|
||||||
if (adjust.variable == 0x7B && adjust.parameter == 0x7D) {
|
if (adjust.variable == 0x7B && adjust.parameter == 0x7D) {
|
||||||
/* Unpredictable load */
|
/* Unpredictable load */
|
||||||
bits.set();
|
all_bits.set();
|
||||||
|
propagate_bits.set();
|
||||||
abandon_substitution_candidates();
|
abandon_substitution_candidates();
|
||||||
}
|
}
|
||||||
if (adjust.variable == 0x7D && adjust.parameter < 0x100) {
|
if (adjust.variable == 0x7D && adjust.parameter < 0x100) {
|
||||||
if (i > 0 && !bits[adjust.parameter] && !no_changes) {
|
if (i > 0 && !all_bits[adjust.parameter] && !no_changes) {
|
||||||
/* See if this can be made a substitution candidate */
|
/* See if this can be made a substitution candidate */
|
||||||
bool add = true;
|
bool add = true;
|
||||||
for (size_t j = 0; j < substitution_candidates.size(); j++) {
|
for (size_t j = 0; j < substitution_candidates.size(); j++) {
|
||||||
@@ -8381,7 +8396,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
/* There already is a candidate */
|
/* There already is a candidate */
|
||||||
substitution_candidates[j] = substitution_candidates.back();
|
substitution_candidates[j] = substitution_candidates.back();
|
||||||
substitution_candidates.pop_back();
|
substitution_candidates.pop_back();
|
||||||
bits.set(adjust.parameter, true);
|
all_bits.set(adjust.parameter, true);
|
||||||
|
propagate_bits.set(adjust.parameter, true);
|
||||||
add = false;
|
add = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -8390,7 +8406,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
substitution_candidates.push_back(adjust.parameter | (i << 8));
|
substitution_candidates.push_back(adjust.parameter | (i << 8));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bits.set(adjust.parameter, true);
|
all_bits.set(adjust.parameter, true);
|
||||||
|
propagate_bits.set(adjust.parameter, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (adjust.variable == 0x1C) {
|
if (adjust.variable == 0x1C) {
|
||||||
@@ -8403,7 +8420,7 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
|
|
||||||
bool may_remove = !need_var1C;
|
bool may_remove = !need_var1C;
|
||||||
if (may_remove && anno->unskippable) may_remove = false;
|
if (may_remove && anno->unskippable) may_remove = false;
|
||||||
if (may_remove && (anno->stores & bits).any()) may_remove = false;
|
if (may_remove && (anno->stores & all_bits).any()) may_remove = false;
|
||||||
|
|
||||||
if (may_remove) {
|
if (may_remove) {
|
||||||
if ((i + 1 < (int)group->adjusts.size() && group->adjusts[i + 1].operation == DSGA_OP_RST && group->adjusts[i + 1].variable != 0x7B) ||
|
if ((i + 1 < (int)group->adjusts.size() && group->adjusts[i + 1].operation == DSGA_OP_RST && group->adjusts[i + 1].variable != 0x7B) ||
|
||||||
@@ -8432,7 +8449,10 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
} else if (sg->type == SGT_DETERMINISTIC) {
|
} else if (sg->type == SGT_DETERMINISTIC) {
|
||||||
const DeterministicSpriteGroup *sub = static_cast<const DeterministicSpriteGroup *>(sg);
|
const DeterministicSpriteGroup *sub = static_cast<const DeterministicSpriteGroup *>(sg);
|
||||||
VarAction2GroupVariableTracking *var_tracking = _cur.GetVarAction2GroupVariableTracking(sub, false);
|
VarAction2GroupVariableTracking *var_tracking = _cur.GetVarAction2GroupVariableTracking(sub, false);
|
||||||
if (var_tracking != nullptr) bits |= var_tracking->in;
|
if (var_tracking != nullptr) {
|
||||||
|
all_bits |= var_tracking->in;
|
||||||
|
propagate_bits |= var_tracking->in;
|
||||||
|
}
|
||||||
if (sub->dsg_flags & DSGF_REQUIRES_VAR1C) need_var1C = true;
|
if (sub->dsg_flags & DSGF_REQUIRES_VAR1C) need_var1C = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -8444,7 +8464,8 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
for (size_t j = 0; j < substitution_candidates.size();) {
|
for (size_t j = 0; j < substitution_candidates.size();) {
|
||||||
uint8 idx = substitution_candidates[j] & 0xFF;
|
uint8 idx = substitution_candidates[j] & 0xFF;
|
||||||
if (anno->stores[idx]) {
|
if (anno->stores[idx]) {
|
||||||
bits.set(idx, true);
|
all_bits.set(idx, true);
|
||||||
|
propagate_bits.set(idx, true);
|
||||||
substitution_candidates[j] = substitution_candidates.back();
|
substitution_candidates[j] = substitution_candidates.back();
|
||||||
substitution_candidates.pop_back();
|
substitution_candidates.pop_back();
|
||||||
} else {
|
} else {
|
||||||
@@ -8456,7 +8477,7 @@ static std::bitset<256> HandleVarAction2DeadStoreElimination(DeterministicSprite
|
|||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
abandon_substitution_candidates();
|
abandon_substitution_candidates();
|
||||||
return bits;
|
return propagate_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleVarAction2OptimisationPasses()
|
static void HandleVarAction2OptimisationPasses()
|
||||||
|
Reference in New Issue
Block a user