private void BuildAstBlocks(ILCompilationUnit result, IDictionary <int, ILVariable> resultVariables) { foreach (var node in result.ControlFlowGraph.Nodes) { var ilBlock = (ILBasicBlock)node.UserData[ILBasicBlock.BasicBlockProperty]; var astBlock = new ILAstBlock(node); foreach (var instruction in ilBlock.Instructions) { // Build expression. var expression = BuildExpression(instruction, result); switch (instruction.OpCode.Code) { case ILCode.POP: { // Since we treat registers as variables, we should treat POP instructions as assignment // statements instead of a normal ILExpressionStatement. This makes it easier to apply // analysis and transformations (such as variable inlining) later, in the same way we do // that with normal variables. var registerVar = result.GetOrCreateVariable(instruction.Operand.ToString()); var value = (ILExpression)((IILArgumentsProvider)expression).Arguments[0].Remove(); var assignment = new ILAssignmentStatement(registerVar, value); astBlock.Statements.Add(assignment); break; } case ILCode.CALL: { // CALL instructions that call non-void methods store the result in R0. // TODO: Respect frame layout instead of hardcoding R0 as return value. var callAnnotation = (CallAnnotation)instruction.Annotation; var statement = callAnnotation.Function.FrameLayout.ReturnsValue ? (ILStatement) new ILAssignmentStatement( result.GetOrCreateVariable(VMRegisters.R0.ToString()), expression) : new ILExpressionStatement(expression); astBlock.Statements.Add(statement); break; } case ILCode.RET: { // TODO: Respect frame layout instead of hardcoding R0 as return value. var returnExpr = (IILArgumentsProvider)expression; foreach (var use in expression.AcceptVisitor(VariableUsageCollector.Instance)) { use.Variable = null; } returnExpr.Arguments.Clear(); if (result.FrameLayout.ReturnsValue && !instruction.ProgramState.IgnoreExitKey) { var registerVar = result.GetOrCreateVariable(VMRegisters.R0.ToString()); returnExpr.Arguments.Add(new ILVariableExpression(registerVar)); } astBlock.Statements.Add(new ILExpressionStatement(expression)); break; } default: { // Build statement around expression. var statement = resultVariables.TryGetValue(instruction.Offset, out var resultVariable) ? (ILStatement) new ILAssignmentStatement(resultVariable, expression) : new ILExpressionStatement(expression); astBlock.Statements.Add(statement); break; } } } node.UserData[ILAstBlock.AstBlockProperty] = astBlock; } }
public IEnumerable <ILVariableExpression> VisitAssignmentStatement(ILAssignmentStatement statement) { return(statement.Value.AcceptVisitor(this)); }