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)
{ {
if (_optOpLastCompare != null &&
_optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
{
if (_optOpLastCompare.Emitter == InstEmit.Subs)
{
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize);
Emit(_branchOps[cond], target);
return;
}
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; OpCode ilOp;
int intCond = (int)cond; int intCond = (int)cond;
if (_optOpLastCompare != null && if (intCond < 14)
_optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
{
Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize);
ilOp = _branchOps[cond];
}
else if (intCond < 14)
{ {
int condTrue = intCond >> 1; int condTrue = intCond >> 1;