private void ReplacePushPopPattern(List <IStatement> statements, int i) { if (i > statements.Count - 2) { return; } //First identify count consecutive push statements int count = 0; while (i + count < statements.Count - 1 && statements[i + count] is PushStatement) { count++; } while (i > 1 && statements[i - 1] is PushStatement) { i--; count++; } if (count == 0) { return; } for (int j = 0; j < count; j++) { if (((PushStatement)statements[j + i]).ValueToPush is Dup) { return; } } //If any of the push statements (other than the first one) contains pop expressions, replace them with the corresponding push values and remove the pushes. int pushcount = 1; //the number of push statements that are eligble for removal at this point. for (int j = i + 1; j < i + count; j++) { PushStatement st = (PushStatement)statements[j]; PopCounter pcc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pcc }.Traverse(st.ValueToPush); int numberOfPushesToRemove = pushcount; if (pcc.count > 0) { if (pcc.count < numberOfPushesToRemove) { numberOfPushesToRemove = pcc.count; } int firstPushToRemove = j - numberOfPushesToRemove; PopReplacer prr = new PopReplacer(this.sourceMethodBody.host, statements, firstPushToRemove, pcc.count - numberOfPushesToRemove); st.ValueToPush = prr.Visit(st.ValueToPush); statements.RemoveRange(firstPushToRemove, numberOfPushesToRemove); j = j - pcc.count; count = count - pcc.count; pushcount = pushcount - pcc.count; } pushcount++; } //If the next statement is an expression statement that pops some of the just pushed values, replace those pops with the pushed values and remove the pushes. ExpressionStatement /*?*/ expressionStatement = statements[i + count] as ExpressionStatement; if (expressionStatement == null) { return; } PopCounter pc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pc }.Traverse(expressionStatement.Expression); if (pc.count == 0) { return; } if (pc.count < count) { i += count - pc.count; //adjust i to point to the first push statement to remove because of subsequent pops. count = pc.count; } PopReplacer pr = new PopReplacer(this.sourceMethodBody.host, statements, i, pc.count - count); expressionStatement.Expression = pr.Visit(expressionStatement.Expression); expressionStatement.Locations.AddRange(statements[i].Locations); statements.RemoveRange(i, count); }
internal static bool ReplacePushPopPattern(BlockStatement b, IMetadataHost host) { Contract.Requires(b != null); Contract.Requires(host != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-1; i++) { //First identify count consecutive push statements int count = 0; while (i+count < statements.Count-1 && statements[i+count] is PushStatement) count++; if (count == 0) continue; Contract.Assert(i+count < statements.Count); Contract.Assert(count < statements.Count); for (int j = 0; j < count; j++) { Contract.Assume(statements[i+j] is PushStatement); if (((PushStatement)statements[i+j]).ValueToPush is DupValue) goto nextIteration; } Contract.Assert(i >= 0); Contract.Assert(i < statements.Count-1); //If any of the push statements (other than the first one) contains pop expressions, replace them with the corresponding push values and remove the pushes. int pushcount = 1; //the number of push statements that are eligble for removal at this point. for (int j = i + 1; j < i + count; j++) { Contract.Assume(j < statements.Count); //because i+count < statements.Count for the initial value of count and count just decreases Contract.Assume(j >= 0); //because i >= 0 and j never decreases to less than i Contract.Assume(statements[j] is PushStatement); //because i < j < i+count and i..i+count-1 are all push statements PushStatement st = (PushStatement)statements[j]; PopCounter pcc = new PopCounter(); pcc.Traverse(st.ValueToPush); int numberOfPushesToRemove = pushcount; if (pcc.count > 0) { if (pcc.count < numberOfPushesToRemove) numberOfPushesToRemove = pcc.count; int firstPushToRemove = j - numberOfPushesToRemove; PopReplacer prr = new PopReplacer(host, statements, firstPushToRemove, pcc.count-numberOfPushesToRemove); st.ValueToPush = prr.Rewrite(st.ValueToPush); statements.RemoveRange(firstPushToRemove, numberOfPushesToRemove); if (pcc.count > numberOfPushesToRemove) return true; //We've consumed all of the pushes and we're done. count -= numberOfPushesToRemove; //Fewer pushes now remain pushcount -= numberOfPushesToRemove; //Likewise fewer eligible pushes remain //Start over again at firstPushToRemove, which now indexes the first statement not yet considered. j = firstPushToRemove-1; continue; } pushcount++; } Contract.Assume(count >= 0); Contract.Assume(i+count < statements.Count); var nextStatement = statements[i + count]; Contract.Assume(nextStatement != null); if (!(nextStatement is IExpressionStatement || nextStatement is IPushStatement || nextStatement is IReturnStatement || nextStatement is IThrowStatement)) continue; PopCounter pc = new PopCounter(); pc.Traverse(nextStatement); if (pc.count == 0) continue; if (pc.count < count) { i += count-pc.count; //adjust i to point to the first push statement to remove because of subsequent pops. count = pc.count; } Contract.Assume(i < statements.Count); PopReplacer pr = new PopReplacer(host, statements, i, pc.count-count); pr.Rewrite(nextStatement); var s = nextStatement as Statement; if (s != null) s.Locations.AddRange(statements[i].Locations); Contract.Assume(count >= 0); Contract.Assert(i+count < statements.Count); statements.RemoveRange(i, count); replacedPattern = true; nextIteration: ; } return replacedPattern; }
private bool ReplacePushDupPopPattern(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-3; i++) { var push1 = statements[i] as PushStatement; if (push1 == null) continue; var binop1 = push1.ValueToPush as BinaryOperation; if (binop1 == null) continue; var bound1 = binop1.LeftOperand as BoundExpression; if (bound1 == null) continue; var exprS1 = statements[i+1] as ExpressionStatement; if (exprS1 == null) continue; var assign1 = exprS1.Expression as Assignment; if (assign1 == null) continue; if (assign1.Target.Definition != bound1.Definition) continue; if (assign1.Target.Instance != bound1.Instance) { if (!(assign1.Target.Instance is IPopValue && bound1.Instance is IDupValue)) continue; } if (!(assign1.Source is DupValue)) continue; var statement = statements[i+2] as Statement; if (statement == null) continue; var popCounter = new PopCounter(); popCounter.Traverse(statement); if (popCounter.count != 1) continue; binop1.LeftOperand = assign1.Target; var popReplacer = new SinglePopReplacer(this.host, binop1); popReplacer.Rewrite(statement); statements.RemoveRange(i, 2); replacedPattern = true; } return replacedPattern; }
private bool ReplacePushDupPushPopPattern(BlockStatement b) { Contract.Requires(b != null); bool replacedPattern = false; var statements = b.Statements; for (int i = 0; i < statements.Count-4; i++) { var push1 = statements[i] as PushStatement; if (push1 == null) continue; var exprS1 = statements[i+1] as ExpressionStatement; if (exprS1 == null) continue; var assign1 = exprS1.Expression as Assignment; if (assign1 == null) continue; if (!(assign1.Source is DupValue) || assign1.Target.Instance != null) continue; var push2 = statements[i+2] as PushStatement; if (push2 == null) continue; var popCounter = new PopCounter(); popCounter.Traverse(push2); if (popCounter.count != 1) continue; if (!this.singleUseExpressionChecker.ExpressionCanBeMovedAndDoesNotReference(push1.ValueToPush, assign1.Target.Definition)) continue; assign1.Source = push1.ValueToPush; var popReplacer = new SinglePopReplacer(this.host, assign1); popReplacer.Rewrite(push2.ValueToPush); statements.RemoveRange(i, 2); replacedPattern = true; } return replacedPattern; }
private void ReplacePushPopPattern(List<IStatement> statements, int i) { if (i > statements.Count - 2) return; //First identify count consecutive push statements int count = 0; while (i+count < statements.Count-1 && statements[i+count] is PushStatement) count++; while (i > 1 && statements[i-1] is PushStatement) { i--; count++; } if (count == 0) return; for (int j = 0; j < count; j++) { if (((PushStatement)statements[j+i]).ValueToPush is Dup) return; } //If any of the push statements (other than the first one) contains pop expressions, replace them with the corresponding push values and remove the pushes. int pushcount = 1; //the number of push statements that are eligble for removal at this point. for (int j = i + 1; j < i + count; j++) { PushStatement st = (PushStatement)statements[j]; PopCounter pcc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pcc }.Traverse(st.ValueToPush); int numberOfPushesToRemove = pushcount; if (pcc.count > 0) { if (pcc.count < numberOfPushesToRemove) numberOfPushesToRemove = pcc.count; int firstPushToRemove = j - numberOfPushesToRemove; PopReplacer prr = new PopReplacer(this.sourceMethodBody.host, statements, firstPushToRemove, pcc.count-numberOfPushesToRemove); st.ValueToPush = prr.Visit(st.ValueToPush); statements.RemoveRange(firstPushToRemove, numberOfPushesToRemove); j = j - pcc.count; count = count - pcc.count; pushcount = pushcount - pcc.count; } pushcount++; } //If the next statement is an expression statement that pops some of the just pushed values, replace those pops with the pushed values and remove the pushes. ExpressionStatement/*?*/ expressionStatement = statements[i + count] as ExpressionStatement; if (expressionStatement == null) return; PopCounter pc = new PopCounter(); new CodeTraverser() { PreorderVisitor = pc }.Traverse(expressionStatement.Expression); if (pc.count == 0) return; if (pc.count < count) { i += count-pc.count; //adjust i to point to the first push statement to remove because of subsequent pops. count = pc.count; } PopReplacer pr = new PopReplacer(this.sourceMethodBody.host, statements, i, pc.count-count); expressionStatement.Expression = pr.Visit(expressionStatement.Expression); statements.RemoveRange(i, count); }