Просмотр исходного кода

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

gdkchan 7 лет назад
Родитель
Сommit
948a758270
2 измененных файлов с 48 добавлено и 8 удалено
  1. 2 0
      ChocolArm64/Instructions/InstEmitAlu.cs
  2. 46 8
      ChocolArm64/Translation/ILEmitterCtx.cs

+ 2 - 0
ChocolArm64/Instructions/InstEmitAlu.cs

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

+ 46 - 8
ChocolArm64/Translation/ILEmitterCtx.cs

@@ -312,19 +312,57 @@ namespace ChocolArm64.Translation
 
         public void EmitCondBranch(ILLabel target, Condition cond)
         {
-            OpCode ilOp;
-
-            int intCond = (int)cond;
-
             if (_optOpLastCompare != null &&
                 _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
             {
-                Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize);
-                Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize);
+                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);
+                        }
 
-                ilOp = _branchOps[cond];
+                        Emit(_branchOps[cond], target);
+
+                        return;
+                    }
+                }
             }
-            else if (intCond < 14)
+
+            OpCode ilOp;
+
+            int intCond = (int)cond;
+
+            if (intCond < 14)
             {
                 int condTrue = intCond >> 1;