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); }
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 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); }
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); }