|
|
@ -5652,6 +5652,7 @@ struct VarAction2TempStoreInference {
|
|
|
|
VarAction2AdjustInferenceFlags inference = VA2AIF_NONE;
|
|
|
|
VarAction2AdjustInferenceFlags inference = VA2AIF_NONE;
|
|
|
|
uint32 store_constant = 0;
|
|
|
|
uint32 store_constant = 0;
|
|
|
|
VarAction2TempStoreInferenceVarSource var_source;
|
|
|
|
VarAction2TempStoreInferenceVarSource var_source;
|
|
|
|
|
|
|
|
uint version = 0;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct VarAction2InferenceBackup {
|
|
|
|
struct VarAction2InferenceBackup {
|
|
|
@ -5669,6 +5670,7 @@ struct VarAction2OptimiseState {
|
|
|
|
bool seen_procedure_call = false;
|
|
|
|
bool seen_procedure_call = false;
|
|
|
|
bool check_expensive_vars = false;
|
|
|
|
bool check_expensive_vars = false;
|
|
|
|
bool enable_dse = false;
|
|
|
|
bool enable_dse = false;
|
|
|
|
|
|
|
|
uint default_variable_version = 0;
|
|
|
|
|
|
|
|
|
|
|
|
inline VarAction2GroupVariableTracking *GetVarTracking(DeterministicSpriteGroup *group)
|
|
|
|
inline VarAction2GroupVariableTracking *GetVarTracking(DeterministicSpriteGroup *group)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -5765,7 +5767,7 @@ static const DeterministicSpriteGroupAdjust *GetVarAction2PreviousSingleLoadAdju
|
|
|
|
/* If we passed a store perm then a load from permanent storage is not a valid previous load as we may have clobbered it */
|
|
|
|
/* If we passed a store perm then a load from permanent storage is not a valid previous load as we may have clobbered it */
|
|
|
|
return nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (prev.variable == 0x7D && prev.parameter < 0x100 && seen_stores[prev.parameter]) {
|
|
|
|
if (prev.variable == 0x7D && seen_stores[prev.parameter & 0xFF]) {
|
|
|
|
/* If we passed a store then a load from that same store is not valid */
|
|
|
|
/* If we passed a store then a load from that same store is not valid */
|
|
|
|
return nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -5800,7 +5802,7 @@ static const DeterministicSpriteGroupAdjust *GetVarAction2PreviousSingleLoadAdju
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void TryMergeBoolMulCombineVarAction2Adjust(std::vector<DeterministicSpriteGroupAdjust> &adjusts, const int adjust_index)
|
|
|
|
static void TryMergeBoolMulCombineVarAction2Adjust(std::vector<DeterministicSpriteGroupAdjust> &adjusts, const int adjust_index)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
uint8 store_var = adjusts[adjust_index].parameter;
|
|
|
|
uint store_var = adjusts[adjust_index].parameter;
|
|
|
|
|
|
|
|
|
|
|
|
const DeterministicSpriteGroupAdjust *a1 = nullptr;
|
|
|
|
const DeterministicSpriteGroupAdjust *a1 = nullptr;
|
|
|
|
const DeterministicSpriteGroupAdjust *a2 = nullptr;
|
|
|
|
const DeterministicSpriteGroupAdjust *a2 = nullptr;
|
|
|
@ -5823,7 +5825,7 @@ static void TryMergeBoolMulCombineVarAction2Adjust(std::vector<DeterministicSpri
|
|
|
|
} else if (prev.operation == DSGA_OP_STO) {
|
|
|
|
} else if (prev.operation == DSGA_OP_STO) {
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
|
|
|
|
/* Temp store */
|
|
|
|
/* Temp store */
|
|
|
|
if (prev.and_mask == store_var) return;
|
|
|
|
if (prev.and_mask == (store_var & 0xFF)) return;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
/* Special register store or unpredictable store, don't use or go past this */
|
|
|
|
/* Special register store or unpredictable store, don't use or go past this */
|
|
|
|
return;
|
|
|
|
return;
|
|
|
@ -5851,7 +5853,7 @@ static void TryMergeBoolMulCombineVarAction2Adjust(std::vector<DeterministicSpri
|
|
|
|
if (prev.operation == DSGA_OP_STO) {
|
|
|
|
if (prev.operation == DSGA_OP_STO) {
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
|
|
|
|
/* Temp store */
|
|
|
|
/* Temp store */
|
|
|
|
if (prev.and_mask == store_var) {
|
|
|
|
if (prev.and_mask == (store_var & 0xFF)) {
|
|
|
|
store_index = i;
|
|
|
|
store_index = i;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -6031,7 +6033,9 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
auto reset_store_values = [&]() {
|
|
|
|
auto reset_store_values = [&]() {
|
|
|
|
for (auto &it : state.temp_stores) {
|
|
|
|
for (auto &it : state.temp_stores) {
|
|
|
|
it.second.inference = VA2AIF_NONE;
|
|
|
|
it.second.inference = VA2AIF_NONE;
|
|
|
|
|
|
|
|
it.second.version++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state.default_variable_version++;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
auto handle_unpredictable_temp_store = [&]() {
|
|
|
|
auto handle_unpredictable_temp_store = [&]() {
|
|
|
|
reset_store_values();
|
|
|
|
reset_store_values();
|
|
|
@ -6069,12 +6073,13 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VarAction2AdjustInferenceFlags non_const_var_inference = VA2AIF_NONE;
|
|
|
|
VarAction2AdjustInferenceFlags non_const_var_inference = VA2AIF_NONE;
|
|
|
|
while (adjust.variable == 0x7D && adjust.parameter < 0x100) {
|
|
|
|
while (adjust.variable == 0x7D) {
|
|
|
|
non_const_var_inference = VA2AIF_NONE;
|
|
|
|
non_const_var_inference = VA2AIF_NONE;
|
|
|
|
auto iter = state.temp_stores.find(adjust.parameter);
|
|
|
|
auto iter = state.temp_stores.find(adjust.parameter & 0xFF);
|
|
|
|
if (iter == state.temp_stores.end()) {
|
|
|
|
if (iter == state.temp_stores.end()) {
|
|
|
|
/* Read without any previous store */
|
|
|
|
/* Read without any previous store */
|
|
|
|
state.GetVarTracking(group)->in.set(adjust.parameter, true);
|
|
|
|
state.GetVarTracking(group)->in.set(adjust.parameter & 0xFF, true);
|
|
|
|
|
|
|
|
adjust.parameter |= (state.default_variable_version << 8);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
const VarAction2TempStoreInference &store = iter->second;
|
|
|
|
const VarAction2TempStoreInference &store = iter->second;
|
|
|
|
if (store.inference & VA2AIF_HAVE_CONSTANT) {
|
|
|
|
if (store.inference & VA2AIF_HAVE_CONSTANT) {
|
|
|
@ -6097,6 +6102,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
adjust.shift_num += store.var_source.shift_num;
|
|
|
|
adjust.shift_num += store.var_source.shift_num;
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
adjust.parameter |= (store.version << 8);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if (adjust.type == DSGA_TYPE_NONE) {
|
|
|
|
if (adjust.type == DSGA_TYPE_NONE) {
|
|
|
|
non_const_var_inference = store.inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO | VA2AIF_MUL_BOOL);
|
|
|
|
non_const_var_inference = store.inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO | VA2AIF_MUL_BOOL);
|
|
|
@ -6105,6 +6111,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
/* Not possible to substitute this here, but it may be possible in the DSE pass */
|
|
|
|
/* Not possible to substitute this here, but it may be possible in the DSE pass */
|
|
|
|
state.enable_dse = true;
|
|
|
|
state.enable_dse = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
adjust.parameter |= (store.version << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
@ -6137,7 +6144,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
|
|
|
|
|
|
|
|
if ((prev_inference & VA2AIF_MUL_BOOL) && (non_const_var_inference & VA2AIF_MUL_BOOL) &&
|
|
|
|
if ((prev_inference & VA2AIF_MUL_BOOL) && (non_const_var_inference & VA2AIF_MUL_BOOL) &&
|
|
|
|
(adjust.operation == DSGA_OP_ADD || adjust.operation == DSGA_OP_OR || adjust.operation == DSGA_OP_XOR) &&
|
|
|
|
(adjust.operation == DSGA_OP_ADD || adjust.operation == DSGA_OP_OR || adjust.operation == DSGA_OP_XOR) &&
|
|
|
|
adjust.variable == 0x7D && adjust.parameter < 0x100 && adjust.type == DSGA_TYPE_NONE && adjust.shift_num == 0 && adjust.and_mask == 0xFFFFFFFF) {
|
|
|
|
adjust.variable == 0x7D && adjust.type == DSGA_TYPE_NONE && adjust.shift_num == 0 && adjust.and_mask == 0xFFFFFFFF) {
|
|
|
|
TryMergeBoolMulCombineVarAction2Adjust(group->adjusts, (int)(group->adjusts.size() - 1));
|
|
|
|
TryMergeBoolMulCombineVarAction2Adjust(group->adjusts, (int)(group->adjusts.size() - 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -6530,11 +6537,18 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
if (adjust.and_mask < 0x100) {
|
|
|
|
if (adjust.and_mask < 0x100) {
|
|
|
|
for (auto &it : state.temp_stores) {
|
|
|
|
for (auto &it : state.temp_stores) {
|
|
|
|
/* Check if some other variable is marked as a copy of the one we are overwriting */
|
|
|
|
/* Check if some other variable is marked as a copy of the one we are overwriting */
|
|
|
|
if ((it.second.inference & VA2AIF_SINGLE_LOAD) && it.second.var_source.variable == 0x7D && it.second.var_source.parameter == adjust.and_mask) {
|
|
|
|
if ((it.second.inference & VA2AIF_SINGLE_LOAD) && it.second.var_source.variable == 0x7D && (it.second.var_source.parameter & 0xFF) == adjust.and_mask) {
|
|
|
|
it.second.inference &= ~VA2AIF_SINGLE_LOAD;
|
|
|
|
it.second.inference &= ~VA2AIF_SINGLE_LOAD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VarAction2TempStoreInference &store = state.temp_stores[adjust.and_mask];
|
|
|
|
VarAction2TempStoreInference &store = state.temp_stores[adjust.and_mask];
|
|
|
|
|
|
|
|
if (store.version == 0) {
|
|
|
|
|
|
|
|
/* New store */
|
|
|
|
|
|
|
|
store.version = state.default_variable_version + 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Updating previous store */
|
|
|
|
|
|
|
|
store.version++;
|
|
|
|
|
|
|
|
}
|
|
|
|
store.inference = prev_inference & (~VA2AIF_PREV_MASK);
|
|
|
|
store.inference = prev_inference & (~VA2AIF_PREV_MASK);
|
|
|
|
store.store_constant = state.current_constant;
|
|
|
|
store.store_constant = state.current_constant;
|
|
|
|
if (prev_inference & VA2AIF_SINGLE_LOAD) {
|
|
|
|
if (prev_inference & VA2AIF_SINGLE_LOAD) {
|
|
|
@ -6569,7 +6583,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
|
|
|
|
case DSGA_OP_RST:
|
|
|
|
case DSGA_OP_RST:
|
|
|
|
if ((prev_inference & VA2AIF_PREV_STORE_TMP) && adjust.variable == 0x7D && adjust.shift_num == 0 && adjust.and_mask == get_full_mask() && group->adjusts.size() >= 2) {
|
|
|
|
if ((prev_inference & VA2AIF_PREV_STORE_TMP) && adjust.variable == 0x7D && adjust.shift_num == 0 && adjust.and_mask == get_full_mask() && group->adjusts.size() >= 2) {
|
|
|
|
const DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
|
|
|
const DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.operation == DSGA_OP_STO && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask == adjust.parameter) {
|
|
|
|
if (prev.type == DSGA_TYPE_NONE && prev.operation == DSGA_OP_STO && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask == (adjust.parameter & 0xFF)) {
|
|
|
|
/* Redundant load from temp store after store to temp store */
|
|
|
|
/* Redundant load from temp store after store to temp store */
|
|
|
|
group->adjusts.pop_back();
|
|
|
|
group->adjusts.pop_back();
|
|
|
|
state.inference = prev_inference;
|
|
|
|
state.inference = prev_inference;
|
|
|
@ -6686,8 +6700,8 @@ static bool CheckDeterministicSpriteGroupOutputVarBits(const DeterministicSprite
|
|
|
|
/* Unpredictable load */
|
|
|
|
/* Unpredictable load */
|
|
|
|
bits.set();
|
|
|
|
bits.set();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (adjust.variable == 0x7D && adjust.parameter < 0x100) {
|
|
|
|
if (adjust.variable == 0x7D && adjust.parameter) {
|
|
|
|
bits.set(adjust.parameter, true);
|
|
|
|
bits.set(adjust.parameter & 0xFF, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (adjust.variable == 0x7E) {
|
|
|
|
if (adjust.variable == 0x7E) {
|
|
|
|
/* procedure call */
|
|
|
|
/* procedure call */
|
|
|
@ -6961,6 +6975,10 @@ static void OptimiseVarAction2DeterministicSpriteGroup(VarAction2OptimiseState &
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return;
|
|
|
|
if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (DeterministicSpriteGroupAdjust &adjust : group->adjusts) {
|
|
|
|
|
|
|
|
if (adjust.variable == 0x7D) adjust.parameter &= 0xFF; // Clear temporary version tags
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_GROUP_PRUNE) && (state.inference & VA2AIF_HAVE_CONSTANT) && !group->calculated_result) {
|
|
|
|
if (!HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2_GROUP_PRUNE) && (state.inference & VA2AIF_HAVE_CONSTANT) && !group->calculated_result) {
|
|
|
|
/* Result of this sprite group is always the same, discard the unused branches */
|
|
|
|
/* Result of this sprite group is always the same, discard the unused branches */
|
|
|
|
const SpriteGroup *target = group->default_group;
|
|
|
|
const SpriteGroup *target = group->default_group;
|
|
|
|