VarAction2: Detect and replace signed relational comparisons
This commit is contained in:
@@ -5722,8 +5722,44 @@ static void NewSpriteGroup(ByteReader *buf)
|
|||||||
} else {
|
} else {
|
||||||
switch (adjust.operation) {
|
switch (adjust.operation) {
|
||||||
case DSGA_OP_SMIN:
|
case DSGA_OP_SMIN:
|
||||||
|
if (adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1) {
|
||||||
|
DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
||||||
|
if (prev.operation == DSGA_OP_SCMP) {
|
||||||
|
prev.operation = DSGA_OP_SGE;
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (group->adjusts.size() >= 3 && prev.operation == DSGA_OP_XOR && prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A &&
|
||||||
|
prev.shift_num == 0 && prev.and_mask == 2) {
|
||||||
|
DeterministicSpriteGroupAdjust &prev2 = group->adjusts[group->adjusts.size() - 3];
|
||||||
|
if (prev2.operation == DSGA_OP_SCMP) {
|
||||||
|
prev2.operation = DSGA_OP_SLE;
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (adjust.and_mask <= 1 && (prev_inference & VA2AIF_SIGNED_NON_NEGATIVE)) inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
if (adjust.and_mask <= 1 && (prev_inference & VA2AIF_SIGNED_NON_NEGATIVE)) inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
break;
|
break;
|
||||||
|
case DSGA_OP_SMAX:
|
||||||
|
if (adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 0) {
|
||||||
|
DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
||||||
|
if (group->adjusts.size() >= 3 && prev.operation == DSGA_OP_SUB && prev.type == DSGA_TYPE_NONE && prev.variable == 0x1A &&
|
||||||
|
prev.shift_num == 0 && prev.and_mask == 1) {
|
||||||
|
DeterministicSpriteGroupAdjust &prev2 = group->adjusts[group->adjusts.size() - 3];
|
||||||
|
if (prev2.operation == DSGA_OP_SCMP) {
|
||||||
|
prev2.operation = DSGA_OP_SGT;
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DSGA_OP_UMIN:
|
case DSGA_OP_UMIN:
|
||||||
if (adjust.and_mask <= 1) inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
if (adjust.and_mask <= 1) inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
break;
|
break;
|
||||||
@@ -5737,7 +5773,7 @@ static void NewSpriteGroup(ByteReader *buf)
|
|||||||
group->adjusts.pop_back();
|
group->adjusts.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((prev_inference & VA2AIF_SIGNED_NON_NEGATIVE) && adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1) {
|
if (adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1) {
|
||||||
DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
||||||
if (prev.operation == DSGA_OP_SCMP || prev.operation == DSGA_OP_UCMP) {
|
if (prev.operation == DSGA_OP_SCMP || prev.operation == DSGA_OP_UCMP) {
|
||||||
prev.operation = DSGA_OP_EQ;
|
prev.operation = DSGA_OP_EQ;
|
||||||
@@ -5753,7 +5789,18 @@ static void NewSpriteGroup(ByteReader *buf)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DSGA_OP_OR:
|
case DSGA_OP_OR:
|
||||||
|
if (adjust.and_mask <= 1) inference = prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO);
|
||||||
|
break;
|
||||||
case DSGA_OP_XOR:
|
case DSGA_OP_XOR:
|
||||||
|
if (adjust.variable == 0x1A && adjust.shift_num == 0 && adjust.and_mask == 1) {
|
||||||
|
DeterministicSpriteGroupAdjust &prev = group->adjusts[group->adjusts.size() - 2];
|
||||||
|
if (prev.operation == DSGA_OP_SLT || prev.operation == DSGA_OP_SGE || prev.operation == DSGA_OP_SLE || prev.operation == DSGA_OP_SGT) {
|
||||||
|
prev.operation = (DeterministicSpriteGroupAdjustOperation)(prev.operation ^ 1);
|
||||||
|
group->adjusts.pop_back();
|
||||||
|
inference = VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (adjust.and_mask <= 1) inference = prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO);
|
if (adjust.and_mask <= 1) inference = prev_inference & (VA2AIF_SIGNED_NON_NEGATIVE | VA2AIF_ONE_OR_ZERO);
|
||||||
break;
|
break;
|
||||||
case DSGA_OP_MUL: {
|
case DSGA_OP_MUL: {
|
||||||
@@ -5804,12 +5851,6 @@ static void NewSpriteGroup(ByteReader *buf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DSGA_OP_SCMP:
|
case DSGA_OP_SCMP:
|
||||||
inference = VA2AIF_SIGNED_NON_NEGATIVE;
|
|
||||||
/* Convert to UCMP if possible to make other analysis operations easier */
|
|
||||||
if ((prev_inference & VA2AIF_SIGNED_NON_NEGATIVE) && adjust.variable == 0x1A && adjust.shift_num == 0 && (adjust.and_mask & get_sign_bit()) == 0) {
|
|
||||||
adjust.operation = DSGA_OP_UCMP;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DSGA_OP_UCMP:
|
case DSGA_OP_UCMP:
|
||||||
inference = VA2AIF_SIGNED_NON_NEGATIVE;
|
inference = VA2AIF_SIGNED_NON_NEGATIVE;
|
||||||
break;
|
break;
|
||||||
|
@@ -184,6 +184,10 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver
|
|||||||
case DSGA_OP_SAR: return (int32)(S)last_value >> ((U)value & 0x1F);
|
case DSGA_OP_SAR: return (int32)(S)last_value >> ((U)value & 0x1F);
|
||||||
case DSGA_OP_TERNARY: return (last_value != 0) ? value : adjust.add_val;
|
case DSGA_OP_TERNARY: return (last_value != 0) ? value : adjust.add_val;
|
||||||
case DSGA_OP_EQ: return (last_value == value) ? 1 : 0;
|
case DSGA_OP_EQ: return (last_value == value) ? 1 : 0;
|
||||||
|
case DSGA_OP_SLT: return ((S)last_value < (S)value) ? 1 : 0;
|
||||||
|
case DSGA_OP_SGE: return ((S)last_value >= (S)value) ? 1 : 0;
|
||||||
|
case DSGA_OP_SLE: return ((S)last_value <= (S)value) ? 1 : 0;
|
||||||
|
case DSGA_OP_SGT: return ((S)last_value > (S)value) ? 1 : 0;
|
||||||
default: return value;
|
default: return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,6 +548,16 @@ static const char *_dsg_op_names[] {
|
|||||||
};
|
};
|
||||||
static_assert(lengthof(_dsg_op_names) == DSGA_OP_END);
|
static_assert(lengthof(_dsg_op_names) == DSGA_OP_END);
|
||||||
|
|
||||||
|
static const char *_dsg_op_special_names[] {
|
||||||
|
"TERNARY",
|
||||||
|
"EQ",
|
||||||
|
"SLT",
|
||||||
|
"SGE",
|
||||||
|
"SLE",
|
||||||
|
"SGT",
|
||||||
|
};
|
||||||
|
static_assert(lengthof(_dsg_op_special_names) == DSGA_OP_SPECIAL_END - DSGA_OP_TERNARY);
|
||||||
|
|
||||||
static const char *_sg_scope_names[] {
|
static const char *_sg_scope_names[] {
|
||||||
"SELF",
|
"SELF",
|
||||||
"PARENT",
|
"PARENT",
|
||||||
@@ -560,8 +574,7 @@ static const char *_sg_size_names[] {
|
|||||||
static const char *GetAdjustOperationName(DeterministicSpriteGroupAdjustOperation operation)
|
static const char *GetAdjustOperationName(DeterministicSpriteGroupAdjustOperation operation)
|
||||||
{
|
{
|
||||||
if (operation < DSGA_OP_END) return _dsg_op_names[operation];
|
if (operation < DSGA_OP_END) return _dsg_op_names[operation];
|
||||||
if (operation == DSGA_OP_TERNARY) return "TERNARY";
|
if (operation >= DSGA_OP_TERNARY && operation < DSGA_OP_SPECIAL_END) return _dsg_op_special_names[operation - DSGA_OP_TERNARY];
|
||||||
if (operation == DSGA_OP_EQ) return "EQ";
|
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -164,10 +164,17 @@ enum DeterministicSpriteGroupAdjustOperation {
|
|||||||
|
|
||||||
DSGA_OP_TERNARY = 0x80, ///< a == 0 ? b : c,
|
DSGA_OP_TERNARY = 0x80, ///< a == 0 ? b : c,
|
||||||
DSGA_OP_EQ, ///< a == b ? 1 : 0,
|
DSGA_OP_EQ, ///< a == b ? 1 : 0,
|
||||||
|
DSGA_OP_SLT, ///< (signed) a < b ? 1 : 0,
|
||||||
|
DSGA_OP_SGE, ///< (signed) a >= b ? 1 : 0,
|
||||||
|
DSGA_OP_SLE, ///< (signed) a <= b ? 1 : 0,
|
||||||
|
DSGA_OP_SGT, ///< (signed) a > b ? 1 : 0,
|
||||||
|
|
||||||
DSGA_OP_SPECIAL_END,
|
DSGA_OP_SPECIAL_END,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert((DSGA_OP_SLT ^ 1) == DSGA_OP_SGE);
|
||||||
|
static_assert((DSGA_OP_SLE ^ 1) == DSGA_OP_SGT);
|
||||||
|
|
||||||
inline bool IsEvalAdjustWithZeroRemovable(DeterministicSpriteGroupAdjustOperation op)
|
inline bool IsEvalAdjustWithZeroRemovable(DeterministicSpriteGroupAdjustOperation op)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
Reference in New Issue
Block a user