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); }
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()); }
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); }
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); }
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); }
public string VisitAssignmentStatement(ILAssignmentStatement statement) => statement.Variable + " = ";
public virtual bool VisitAssignmentStatement(ILAssignmentStatement statement) { return(statement.Value.AcceptVisitor(this)); }
public void VisitAssignmentStatement(ILAssignmentStatement statement) { statement.Value.AcceptVisitor(this); }