VarAction2: Replace sequences of the form: (var * flag) + (var * !flag)

pull/393/head
Jonathan G Rennison 2 years ago
parent 4553c22cee
commit 0343e9d9dd

@ -5632,6 +5632,7 @@ enum VarAction2AdjustInferenceFlags {
VA2AIF_PREV_STORE_TMP = 0x10,
VA2AIF_HAVE_CONSTANT = 0x20,
VA2AIF_SINGLE_LOAD = 0x40,
VA2AIF_MUL_BOOL = 0x80,
VA2AIF_PREV_MASK = VA2AIF_PREV_TERNARY | VA2AIF_PREV_MASK_ADJUST | VA2AIF_PREV_STORE_TMP,
};
@ -5793,6 +5794,107 @@ static const DeterministicSpriteGroupAdjust *GetVarAction2PreviousSingleLoadAdju
return nullptr;
}
/*
* Find and replace the result of: (var * flag) + (var * !flag) with var
* "+" may be ADD, OR or XOR.
*/
static void TryMergeBoolMulCombineVarAction2Adjust(std::vector<DeterministicSpriteGroupAdjust> &adjusts, const int adjust_index)
{
uint8 store_var = adjusts[adjust_index].parameter;
const DeterministicSpriteGroupAdjust *a1 = nullptr;
const DeterministicSpriteGroupAdjust *a2 = nullptr;
const DeterministicSpriteGroupAdjust *b1 = nullptr;
const DeterministicSpriteGroupAdjust *b2 = nullptr;
auto find_adjusts = [&](int start_index, const DeterministicSpriteGroupAdjust *&mul, const DeterministicSpriteGroupAdjust *&rst) {
bool have_mul = false;
for (int i = start_index; i >= 0; i--) {
const DeterministicSpriteGroupAdjust &prev = adjusts[i];
if (prev.variable == 0x7E || prev.variable == 0x7B) {
/* Procedure call or load depends on the last value, don't use or go past this */
return;
}
if (prev.operation == DSGA_OP_RST) {
if (have_mul) {
rst = &prev;
}
return;
} else if (prev.operation == DSGA_OP_STO) {
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
/* Temp store */
if (prev.and_mask == store_var) return;
} else {
/* Special register store or unpredictable store, don't use or go past this */
return;
}
} else if (prev.operation == DSGA_OP_MUL && !have_mul) {
mul = &prev;
have_mul = true;
} else {
return;
}
}
};
find_adjusts(adjust_index - 1, a1, a2);
if (a1 == nullptr || a2 == nullptr) return;
/* Find offset of referenced store */
int store_index = -1;
for (int i = adjust_index - 1; i >= 0; i--) {
const DeterministicSpriteGroupAdjust &prev = adjusts[i];
if (prev.variable == 0x7E) {
/* Procedure call, don't use or go past this */
return;
}
if (prev.operation == DSGA_OP_STO) {
if (prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A && prev.shift_num == 0 && prev.and_mask < 0x100) {
/* Temp store */
if (prev.and_mask == store_var) {
store_index = i;
break;
}
} else {
/* Special register store or unpredictable store, don't use or go past this */
return;
}
}
}
if (store_index < 0) return;
find_adjusts(store_index - 1, b1, b2);
if (b1 == nullptr || b2 == nullptr) return;
/* Sanity check to avoid being confused by bizarre inputs */
if (std::tie(a1->variable, a1->parameter) == std::tie(a2->variable, a2->parameter)) return;
if (std::tie(b1->variable, b1->parameter) == std::tie(b2->variable, b2->parameter)) return;
if (std::tie(a1->variable, a1->parameter) == std::tie(b2->variable, b2->parameter)) std::swap(a1, a2);
auto check_match = [&]() -> bool {
if (IsConstantComparisonAdjustType(a1->type) && InvertConstantComparisonAdjustType(a1->type) == b1->type &&
(std::tie(a1->variable, a1->shift_num, a1->parameter, a1->and_mask, a1->add_val, a1->divmod_val) ==
std::tie(b1->variable, b1->shift_num, b1->parameter, b1->and_mask, b1->add_val, b1->divmod_val)) &&
IsIdenticalValueLoad(a2, b2)) {
/* Success */
DeterministicSpriteGroupAdjust &adjust = adjusts[adjust_index];
adjust.operation = DSGA_OP_RST;
adjust.adjust_flags = DSGAF_NONE;
std::tie(adjust.type, adjust.variable, adjust.shift_num, adjust.parameter, adjust.and_mask, adjust.add_val, adjust.divmod_val) =
std::tie(a2->type, a2->variable, a2->shift_num, a2->parameter, a2->and_mask, a2->add_val, a2->divmod_val);
return true;
}
return false;
};
if (check_match()) return;
std::swap(a1, a2);
std::swap(b1, b2);
check_match();
}
static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSpecFeature feature, const byte varsize, DeterministicSpriteGroup *group, DeterministicSpriteGroupAdjust &adjust)
{
if (unlikely(HasGrfOptimiserFlag(NGOF_NO_OPT_VARACT2))) return;
@ -5916,7 +6018,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
}
} else {
if (adjust.type == DSGA_TYPE_NONE) {
non_const_var_inference = store.inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO);
non_const_var_inference = store.inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO | VA2AIF_MUL_BOOL);
}
if (store.inference & VA2AIF_SINGLE_LOAD) {
/* Not possible to substitute this here, but it may be possible in the DSE pass */
@ -5952,6 +6054,32 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
}
}
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.variable == 0x7D && adjust.parameter < 0x100 && adjust.type == DSGA_TYPE_NONE && adjust.shift_num == 0 && adjust.and_mask == 0xFFFFFFFF) {
TryMergeBoolMulCombineVarAction2Adjust(group->adjusts, (int)(group->adjusts.size() - 1));
}
if (group->adjusts.size() >= 2 && adjust.operation == DSGA_OP_RST && adjust.variable != 0x7B) {
/* See if any previous adjusts can be removed */
bool removed = false;
while (group->adjusts.size() >= 2) {
const DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
if (prev.variable != 0x7E && !IsEvalAdjustWithSideEffects(prev.operation)) {
/* Delete useless operation */
group->adjusts.erase(group->adjusts.end() - 2);
removed = true;
} else {
break;
}
}
if (removed) {
state.inference = prev_inference;
OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back());
return;
}
}
if (adjust.variable != 0x7E && IsEvalAdjustWithZeroLastValueAlwaysZero(adjust.operation)) {
adjust.adjust_flags |= DSGAF_SKIP_ON_ZERO;
}
@ -6026,6 +6154,9 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
if (adjust.operation == DSGA_OP_OR && (prev_inference & VA2AIF_ONE_OR_ZERO) && adjust.variable != 0x7E) {
adjust.adjust_flags |= DSGAF_SKIP_ON_LSB_SET;
}
if (adjust.operation == DSGA_OP_MUL && adjust.variable != 0x7E) {
state.inference |= VA2AIF_MUL_BOOL;
}
}
} else {
if (adjust.and_mask == 0 && IsEvalAdjustWithZeroRemovable(adjust.operation)) {
@ -6045,7 +6176,7 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
/* Convert: store, load var, commutative op on stored --> (dead) store, commutative op var */
prev.operation = adjust.operation;
group->adjusts.pop_back();
state.inference = non_const_var_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO);
state.inference = non_const_var_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO | VA2AIF_MUL_BOOL);
OptimiseVarAction2Adjust(state, feature, varsize, group, group->adjusts.back());
return;
}
@ -6292,6 +6423,9 @@ static void OptimiseVarAction2Adjust(VarAction2OptimiseState &state, const GrfSp
state.inference |= VA2AIF_SIGNED_NON_NEGATIVE;
}
}
if ((prev_inference & VA2AIF_ONE_OR_ZERO) || (non_const_var_inference & VA2AIF_ONE_OR_ZERO)) {
state.inference |= VA2AIF_MUL_BOOL;
}
break;
}
case DSGA_OP_SCMP:

Loading…
Cancel
Save