Optimize CMN/ADDS to do a single comparision like CMP/SUBS (#576)

This commit is contained in:
gdkchan 2019-02-18 01:17:34 -03:00 committed by jduncanator
parent 17ac118946
commit 948a758270
2 changed files with 49 additions and 9 deletions

View file

@ -51,6 +51,8 @@ namespace ChocolArm64.Instructions
public static void Adds(ILEmitterCtx context) public static void Adds(ILEmitterCtx context)
{ {
context.TryOptMarkCondWithoutCmp();
EmitAluLoadOpers(context); EmitAluLoadOpers(context);
context.Emit(OpCodes.Add); context.Emit(OpCodes.Add);

View file

@ -312,19 +312,57 @@ namespace ChocolArm64.Translation
public void EmitCondBranch(ILLabel target, Condition cond) public void EmitCondBranch(ILLabel target, Condition cond)
{ {
OpCode ilOp;
int intCond = (int)cond;
if (_optOpLastCompare != null && if (_optOpLastCompare != null &&
_optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond)) _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
{
if (_optOpLastCompare.Emitter == InstEmit.Subs)
{ {
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize); Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize);
ilOp = _branchOps[cond]; Emit(_branchOps[cond], target);
return;
} }
else if (intCond < 14) else if (_optOpLastCompare.Emitter == InstEmit.Adds && cond != Condition.GeUn
&& cond != Condition.LtUn
&& cond != Condition.GtUn
&& cond != Condition.LeUn)
{
//There are several limitations that needs to be taken into account for CMN comparisons:
//* The unsigned comparisons are not valid, as they depend on the
//carry flag value, and they will have different values for addition and
//subtraction. For addition, it's carry, and for subtraction, it's borrow.
//So, we need to make sure we're not doing a unsigned compare for the CMN case.
//* We can only do the optimization for the immediate variants,
//because when the second operand value is exactly INT_MIN, we can't
//negate the value as theres no positive counterpart.
//Such invalid values can't be encoded on the immediate encodings.
if (_optOpLastCompare is IOpCodeAluImm64 op)
{
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
if (_optOpLastCompare.RegisterSize == RegisterSize.Int32)
{
EmitLdc_I4((int)-op.Imm);
}
else
{
EmitLdc_I8(-op.Imm);
}
Emit(_branchOps[cond], target);
return;
}
}
}
OpCode ilOp;
int intCond = (int)cond;
if (intCond < 14)
{ {
int condTrue = intCond >> 1; int condTrue = intCond >> 1;