Exemplo n.º 1
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);
        }
Exemplo n.º 2
0
        private static void InlineVariable(ILVariableExpression usage, ILAssignmentStatement assignmentStatement)
        {
            var replacement = assignmentStatement.Value;

            // Simple inlining can cause massive PUSH chains. For example, the following:
            //
            //     R0 = PUSHR_DWORD(expr)
            //     R1 = PUSHR_DWORD(R0)
            //
            // would be optimised to
            //
            //     R1 = PUSHR_DWORD(PUSHR_DWORD(expr))
            //
            // But this can be simply:
            //
            //     R1 = PUSHR_DWORD(expr)
            //
            // Try to optimise for this:
            var match1 = PushPattern.Match(usage.Parent);
            var match2 = PushPattern.Match(assignmentStatement.Value);

            if (match1.Success && match2.Success)
            {
                var pushVariable = (ILInstructionExpression)usage.Parent;
                var value        = (ILInstructionExpression)assignmentStatement.Value;

                if (pushVariable.OpCode.Code == value.OpCode.Code)
                {
                    replacement = value.Arguments[0];
                }
            }

            usage.Variable = null;
            usage.ReplaceWith(replacement.Remove());
        }
Exemplo n.º 3
0
        private bool ValidateRemainingRelationalNodes(MatchResult match, ILVariableExpression variable, VMFlags flags,
                                                      out ILAssignmentStatement varAssignment, out ILExpression flAssignment2, out MatchResult cmpMatch)
        {
            varAssignment = null;
            flAssignment2 = null;
            cmpMatch      = null;

            // Check if __AND_DWORD(var, var)
            var(left, right) = GetOperands(match);
            if (left.Variable != right.Variable ||
                left.Variable != variable.Variable ||
                left.Variable.AssignedBy.Count != 1)
            {
                return(false);
            }

            // Check if __AND_DWORD(fl2, overflow | sign | zero)
            varAssignment = left.Variable.AssignedBy[0];
            var flMatch = FLAndConstantPattern.Match(varAssignment.Value);

            if (!flMatch.Success)
            {
                return(false);
            }

            var constant3 = (ILInstructionExpression)flMatch.Captures["constant"][0];

            if ((byte)(uint)constant3.Operand != _constants.GetFlagMask(flags))
            {
                return(false);
            }

            // Check if CMP_xxxx(op0, op1)
            var flUsage2 = (ILFlagsVariable)((ILVariableExpression)flMatch.Captures["fl"][0]).Variable;

            if (flUsage2.ImplicitAssignments.Count != 1)
            {
                return(false);
            }

            flAssignment2 = flUsage2.ImplicitAssignments.First();
            cmpMatch      = ComparePattern.Match(flAssignment2);
            if (!cmpMatch.Success)
            {
                return(false);
            }

            return(true);
        }
Exemplo n.º 4
0
        private static Dictionary <Node, ICollection <ILAssignmentStatement> > InsertPhiNodes(ILCompilationUnit unit)
        {
            var result = unit.ControlFlowGraph.Nodes.ToDictionary(
                x => x,
                x => (ICollection <ILAssignmentStatement>) new List <ILAssignmentStatement>());

            // We try to find all variables that have more than one assignment, and therefore have multiple
            // versions of it during execution of the program. This is only a problem when they have different
            // values at join nodes, as depicted below. We therefore need to get to the dominance frontier of
            // those nodes and insert phi nodes there.
            //
            //  [ x1 <- value1 ]         [ x2 <- value2 ]
            //        |                        |
            //        '------------+-----------'
            //                     |
            //          [ x3 <- phi(x1, x2) ]
            //

            // Collect all nodes that contain a variable assignment (i.e. a new definition).
            var variableBlocks = unit.Variables.ToDictionary(
                x => x,
                x => new HashSet <Node>(x.AssignedBy.Select(a => a.GetParentNode())));

            foreach (var variable in unit.Variables.Where(x =>
                                                          x.AssignedBy.Count > 1 || // If the variable has more than one definition
                                                          GetNodesReferencingVariable(x).Count() > 1) // Or is used in multiple nodes.
                     )
            {
                var agenda = new Queue <Node>(variableBlocks[variable]);
                while (agenda.Count > 0)
                {
                    var current = agenda.Dequeue();
                    foreach (var frontierNode in unit.DominatorInfo.GetDominanceFrontier(current))
                    {
                        // If the frontier node does not define a phi node already for this variable, we need to add it.
                        if (result[frontierNode].All(x => x.Variable != variable))
                        {
                            // Check if the variable is defined in the frontier node.
                            bool defined = variableBlocks[variable].Contains(frontierNode);

                            // Build phi node.
                            // The number of different versions of the variable is equal to the amount of predecessors.
                            var phiExpression = new ILPhiExpression(Enumerable
                                                                    .Repeat(variable, frontierNode.InDegree)
                                                                    .Select(v => new ILVariableExpression(v)));

                            var phiNode = new ILAssignmentStatement(variable, phiExpression);

                            // Insert at top of the current block.
                            var block = (ILAstBlock)frontierNode.UserData[ILAstBlock.AstBlockProperty];
                            block.Statements.Insert(0, phiNode);

                            // Register phi node.
                            result[frontierNode].Add(phiNode);

                            // We might have to check this node again if we introduce a new version of this variable
                            // at this node.
                            if (!defined)
                            {
                                agenda.Enqueue(frontierNode);
                            }
                        }
                    }
                }
            }

            return(result);
        }
Exemplo n.º 5
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);
        }
Exemplo n.º 6
0
 public string VisitAssignmentStatement(ILAssignmentStatement statement) => statement.Variable + " = ";
Exemplo n.º 7
0
 public virtual bool VisitAssignmentStatement(ILAssignmentStatement statement)
 {
     return(statement.Value.AcceptVisitor(this));
 }
Exemplo n.º 8
0
 public void VisitAssignmentStatement(ILAssignmentStatement statement)
 {
     statement.Value.AcceptVisitor(this);
 }