Ejemplo n.º 1
0
        private bool TryOptimizeCompareWithZero(ILCompilationUnit unit, ILFlagsVariable fl, ILVariableExpression flUsage)
        {
            if (fl.ImplicitAssignments.Count != 1)
            {
                return(false);
            }

            var flAssignment = fl.ImplicitAssignments.First();

            MatchResult match;

            if ((match = ComparePattern.Match(flAssignment)).Success) // (cmp(a, b); equals(FL, 0)) <=> (a == b)
            {
                return(TryOptimizeToEquals(unit, fl, flUsage, flAssignment, match));
            }
            if ((match = BigRelationalPattern.Match(flAssignment)).Success)
            {
                return(TryOptimizeToLessThan(unit, fl, flUsage, flAssignment, match));
            }
            if ((match = AndRegistersPattern.Match(flAssignment)).Success)
            {
                return(TryOptimizeToGreaterThan(unit, fl, flUsage, flAssignment, match));
            }

            return(false);
        }
Ejemplo n.º 2
0
        private bool TryOptimizeToEquals(
            ILCompilationUnit unit,
            ILFlagsVariable fl,
            ILVariableExpression flUsage,
            ILExpression flAssignment,
            MatchResult match)
        {
            // Replace FL operation with the new comparison operation.
            ILOpCode opcode;

            switch (((ILInstructionExpression)flAssignment).OpCode.Code)
            {
            case ILCode.CMP:
                opcode = ILOpCodes.__EQUALS_OBJECT;
                break;

            case ILCode.CMP_R32:
                opcode = ILOpCodes.__EQUALS_R32;
                break;

            case ILCode.CMP_R64:
                opcode = ILOpCodes.__EQUALS_R64;
                break;

            case ILCode.CMP_DWORD:
                opcode = ILOpCodes.__EQUALS_DWORD;
                break;

            case ILCode.CMP_QWORD:
                opcode = ILOpCodes.__EQUALS_QWORD;
                break;

            default:
                return(false);
            }

            // Introduce new variable for storing the result of the comparison.
            var resultVar = unit.GetOrCreateVariable($"simplified_{fl.Name}");

            resultVar.VariableType = VMType.Dword;

            var assignment = new ILAssignmentStatement(resultVar,
                                                       new ILInstructionExpression(-1, opcode, null, VMType.Dword)
            {
                Arguments =
                {
                    (ILExpression)match.Captures["left"][0].Remove(),
                    (ILExpression)match.Captures["right"][0].Remove()
                }
            });

            fl.ImplicitAssignments.Remove(flAssignment);
            flAssignment.Parent.ReplaceWith(assignment);

            // Replace FL reference with new variable.
            flUsage.Variable = null;
            flUsage.Parent.Parent.ReplaceWith(new ILVariableExpression(resultVar));

            return(true);
        }
Ejemplo n.º 3
0
        private bool TryOptimizeToGreaterThan(
            ILCompilationUnit unit,
            ILFlagsVariable fl,
            ILVariableExpression flUsage,
            ILExpression flAssignment,
            MatchResult match)
        {
            var root            = flUsage.Parent?.Parent?.Parent?.Parent;
            var relationalMatch = BigRelationalPattern.Match(root);

            if (!relationalMatch.Success || !ValidateRelationalMatch(relationalMatch, out var variable))
            {
                return(false);
            }

            if (!ValidateRemainingRelationalNodes(match, variable, VMFlags.OVERFLOW | VMFlags.SIGN | VMFlags.ZERO,
                                                  out var varAssignment, out var flAssignment2, out var cmpMatch))
            {
                return(false);
            }

            // We have a match! Decide which opcode to use based on the original comparison that was made.
            ILOpCode opcode;

            switch (((ILInstructionExpression)flAssignment2).OpCode.Code)
            {
            case ILCode.CMP_R32:
                opcode = ILOpCodes.__GT_R64;
                break;

            case ILCode.CMP_R64:
                opcode = ILOpCodes.__GT_R64;
                break;

            case ILCode.CMP_DWORD:
                opcode = ILOpCodes.__GT_DWORD;
                break;

            case ILCode.CMP_QWORD:
                opcode = ILOpCodes.__GT_QWORD;
                break;

            default:
                return(false);
            }

            // Introduce new variable for storing the result of the comparison.
            var resultVar = unit.GetOrCreateVariable("simplified_" + fl.Name);

            resultVar.VariableType = VMType.Dword;

            var newAssignment = new ILAssignmentStatement(resultVar,
                                                          new ILInstructionExpression(-1, opcode, null, VMType.Dword)
            {
                Arguments =
                {
                    (ILExpression)cmpMatch.Captures["left"][0].Remove(),
                    (ILExpression)cmpMatch.Captures["right"][0].Remove()
                }
            });

            // Remove var0 assignment.
            varAssignment.Variable = null;
            varAssignment.Remove();

            // Remove comparison.
            flAssignment2.Parent.Remove();

            // Clear references to variables.
            var referencesToRemove = new List <ILVariableExpression>();

            referencesToRemove.AddRange(root.AcceptVisitor(VariableUsageCollector.Instance));
            referencesToRemove.AddRange(flAssignment.AcceptVisitor(VariableUsageCollector.Instance));
            referencesToRemove.AddRange(varAssignment.AcceptVisitor(VariableUsageCollector.Instance));
            referencesToRemove.AddRange(flAssignment2.AcceptVisitor(VariableUsageCollector.Instance));

            foreach (var reference in referencesToRemove)
            {
                reference.Variable = null;
                reference.Remove();
            }

            // Replace assignment and use of FL with new variable.
            flAssignment.FlagsVariable = null;
            flAssignment.Parent.ReplaceWith(newAssignment);
            root.ReplaceWith(new ILVariableExpression(resultVar));

            return(true);
        }
Ejemplo n.º 4
0
        private bool TryOptimizeFlagComparison(ILCompilationUnit unit, ILVariableExpression flagUsage, ILFlagsVariable fl, VMFlags flags)
        {
            // TODO: support other flag combinations.
            bool changed = false;

            switch (flags)
            {
            case VMFlags.ZERO:
                changed |= TryOptimizeCompareWithZero(unit, fl, flagUsage);
                break;
            }

            return(changed);
        }