public static bool RemoveUnusedVariables(BlockNode block) { var usedvariables = block.GetReadVariables().ToArray(); var changesmade = false; var i = 0; foreach (var node in block.GetChildren().ToList()) { if (node is VariableDeclarationNode dec) { if (!usedvariables.Contains(dec.VariableName)) { block.RemoveChild(i--); changesmade = true; } } else if (node is VariableAssignmentNode assignment) { if (!usedvariables.Contains(assignment.VariableName)) { block.RemoveChild(i--); changesmade = true; } } i++; } return(changesmade); }
public static IEnumerable <List <Node> > CreateBasicBlocks(BlockNode block) { var children = block.GetChildren(); var currentblock = new List <Node>(); foreach (var child in children) { if (currentblock.Any() && child is LabelNode) { yield return(currentblock); currentblock = new List <Node>(); } currentblock.Add(child); if (currentblock.Any() && child is GotoNode) { yield return(currentblock); currentblock = new List <Node>(); } } if (currentblock.Any()) { yield return(currentblock); } }
public static bool TransformToIncDec(BlockNode block) { var children = block.GetChildren().ToList(); var changesmade = false; for (var i = 0; i < children.Count; i++) { var node = children[i]; if (!(node is VariableAssignmentNode assignment)) { continue; } BinaryOperatorNode expression = null; if (assignment.Value is AdditionNode add) { expression = add; } if (assignment.Value is SubtractionNode sub) { expression = sub; } if (expression == null) { continue; } ExpressionNode left, right; if (expression.Left is ShortValueNode) { left = expression.Left; right = expression.Right; } else { right = expression.Left; left = expression.Right; } if (left is ShortValueNode value && value.Value == 1 && right is VariableValueNode var && var.VariableName == assignment.VariableName) { children.RemoveAt(i); block.RemoveChild(i); if (expression is AdditionNode) { block.AddChild(new IncrementNode(assignment.VariableName)); } else { block.AddChild(new DecrementNode(assignment.VariableName)); } changesmade = true; } } return(changesmade); }
public static void Optimize(BlockNode block) { while (PropagateConstants(block) || RemoveUnusedVariables(block) || TransformToIncDec(block)) { } foreach (var child in block.GetChildren()) { if (child is IfNode ifnode) { Optimize(ifnode.IfTrue); Optimize(ifnode.IfFalse); } } }
public static void Simplify(BlockNode block) { while (TransformAdditionAssignmentToExpression(block) || TransformSubtractionAssignmentToExpression(block) || FlattenExpressions(block)) { } foreach (var child in block.GetChildren()) { if (child is IfNode ifnode) { Simplify(ifnode.IfTrue); Simplify(ifnode.IfFalse); } } }
public static bool FlattenExpressions(BlockNode block) { var changesmade = false; for (var i = 0; i < block.GetChildren().Count(); i++) { var addedinstructions = FlattenExpression(block, i); if (addedinstructions <= 0) { continue; } changesmade = true; i += addedinstructions; } return(changesmade); }
public static bool TransformSubtractionAssignmentToExpression(BlockNode block) { var changesmade = false; var children = block.GetChildren().ToList(); for (var i = 0; i < children.Count; i++) { var node = children[i]; if (!(node is SubtractionAssignmentNode assignment)) { continue; } block.RemoveChild(i); block.InsertAt(new VariableAssignmentNode(assignment.VariableName, new SubtractionNode(new VariableValueNode(assignment.VariableName), assignment.Value)), i); changesmade = true; } return(changesmade); }
public static int FlattenExpression(BlockNode block, int index) { var currentblock = block.GetChildren().ToList()[index]; if (currentblock is VariableAssignmentNode assignmentnode) { if (!(assignmentnode.Value is BinaryOperatorNode value)) // Flat enough { return(0); } // Single operations per assignment is what we want. This is good, stop. if (value.Left is ConstantNode && value.Right is ConstantNode) { return(0); } block.RemoveChild(index); var count = 0; FlattenExpression(block, value, ref count, ref index, 0); count *= 2; block.InsertAt(assignmentnode, index); return(count); } if (currentblock is IfNode ifNode) { if (ifNode.Condition is VariableValueNode value) // Flat enough { return(0); } var tempvarname = ExtractVariable(block, ifNode.Condition, ref index); ifNode.Condition = new VariableValueNode(tempvarname); return(2); } return(0); }
public static IEnumerable <string> EmitAssembly(BlockNode rootnode, int startindex = 0) { char[] registernames = { 'C', 'D', 'E', 'H', 'L' }; var variablealloc = AllocateRegisters(rootnode); // Check variable count is under the register limit if (variablealloc.Count > 0) // .Max throws if collection is empty :/ { if (variablealloc.Max(pair => pair.Value) >= registernames.Length) { throw new OutOfSpaceException("Unable to allocate sufficent registers for optimized variable count"); } } char GetVariableRegister(string name) => registernames[variablealloc[name]]; string getValue(Node node) // TODO: Make this ValueNode { if (node is VariableValueNode assignment) { return(GetVariableRegister(assignment.VariableName).ToString()); } if (node is ShortValueNode shortValue) { return(shortValue.Value.ToString()); } throw new NotSupportedException("This operator is not yet supported inside the assembler. Please implement."); } var r = 1; string getRandomLabelName() => "generatedLabel" + r++; // Cases must be in order of any inheritence because of the way `is` works foreach (var node in rootnode.GetChildren()) { switch (node) { case VariableDeclarationNode _: // Do nothing break; case IncrementNode inc: yield return($"INC {GetVariableRegister(inc.VariableName)}"); break; case DecrementNode dec: yield return($"DEC {GetVariableRegister(dec.VariableName)}"); break; case LabelNode label: yield return(label.Name + ':'); break; case GotoNode gotonode: yield return("JP " + gotonode.LabelName); break; case VariableAssignmentNode var when var.Value is VariableValueNode varval: yield return($"LD {GetVariableRegister(var.VariableName)} {GetVariableRegister(varval.VariableName)}"); break; case VariableAssignmentNode var when var.Value is ShortValueNode imval: yield return($"LD {GetVariableRegister(var.VariableName)} {imval.Value}"); break; case VariableAssignmentNode var when var.Value is MemoryValueNode memval: yield return($"LD A ({memval.Address})"); yield return($"LD {GetVariableRegister(var.VariableName)} A"); break; case MemoryAssignmentNode var: if (var.Value is VariableValueNode vval) { yield return($"LD ({var.Address}) {GetVariableRegister(vval.VariableName)}"); } else if (var.Value is ShortValueNode shortval) { yield return("PUSH HL"); yield return($"LD HL {var.Address}"); yield return($"LD (HL) {shortval.Value}"); yield return("POP HL"); } break; case VariableAssignmentNode var: { if (var.Value is BinaryOperatorNode oprator) { if (var.Value is ComparisonNode comparison) { yield return($"LD A {getValue(comparison.Left)}"); yield return($"CP {getValue(comparison.Right)}"); var iffalselabelname = getRandomLabelName(); if (var.Value is LessThanComparisonNode) { yield return("JP NC " + iffalselabelname); } else if (var.Value is MoreThanComparisonNode) { yield return("JP C " + iffalselabelname); yield return("JP NZ " + iffalselabelname); } yield return($"LD {GetVariableRegister(var.VariableName)} 1"); var iftruelabelname = getRandomLabelName(); yield return("JP " + iftruelabelname); yield return(iffalselabelname + ':'); yield return($"LD {GetVariableRegister(var.VariableName)} 0"); yield return(iftruelabelname + ':'); } else // Only other operators should be addition and subtraction { yield return($"LD A {getValue(oprator.Left)}"); var rightoprand = getValue(oprator.Right); if (var.Value is AdditionNode) { yield return($"ADD A {rightoprand}"); } else if (var.Value is SubtractionNode) { yield return($"SUB A {rightoprand}"); } yield return($"LD {GetVariableRegister(var.VariableName)} A"); } } else if (var.Value is UnaryOperatorNode operatorNode) { if (var.Value is NegateNode negatenode) { yield return("LD A 1"); yield return($"XOR {getValue(negatenode.Expression)}"); yield return($"LD {GetVariableRegister(var.VariableName)} A"); } } break; } case IfNode ifNode: yield return("XOR A"); yield return($"CP {GetVariableRegister(((VariableValueNode)ifNode.Condition).VariableName)}"); // Formatter should extract condition before it gets here var iffalselabel = getRandomLabelName(); yield return($"JP NZ {iffalselabel}"); foreach (var asm in EmitAssembly(ifNode.IfTrue)) { yield return(asm); } var falsebody = ifNode.IfFalse.GetChildren(); var iftruelabel = getRandomLabelName(); if (falsebody.Any()) { yield return("JP " + iftruelabel); } yield return(iffalselabel + ':'); if (falsebody.Any()) { foreach (var asm in EmitAssembly(ifNode.IfFalse)) { yield return(asm); } yield return(iftruelabel + ':'); } break; } } }
public static bool PropagateConstants(BlockNode block) { var changesmade = false; var variablevalues = new Dictionary <string, ushort>(); var children = block.GetChildren().ToList(); for (var i = 0; i < children.Count; i++) { var node = children[i]; if (node is AssignmentNode assignment) { var newvalue = assignment.Value.Optimize(variablevalues); if (!assignment.Value.Matches(newvalue)) { changesmade = true; } assignment.Value = newvalue; } if (node is VariableAssignmentNode varassignment) { if (varassignment.Value is ConstantNode value) { if (variablevalues.ContainsKey(varassignment.VariableName)) { variablevalues[varassignment.VariableName] = value.GetValue(); } else { variablevalues.Add(varassignment.VariableName, value.GetValue()); } } } else if (node is IncrementNode inc) { if (variablevalues.ContainsKey(inc.VariableName)) { variablevalues[inc.VariableName]++; children.RemoveAt(i); block.RemoveChild(i--); changesmade = true; } } else if (node is DecrementNode dec) { if (variablevalues.ContainsKey(dec.VariableName)) { variablevalues[dec.VariableName]--; children.RemoveAt(i); block.RemoveChild(i--); changesmade = true; } } else if (node is IfNode ifnode) { if (!(ifnode.Condition is ExpressionNode condition)) { continue; } ifnode.Condition = condition.Optimize(variablevalues); if (!(ifnode.Condition is ConstantNode c)) { continue; } children.RemoveAt(i); block.RemoveChild(i); changesmade = true; if (IsTrue(c)) { children.InsertRange(i, ifnode.IfTrue.GetChildren()); var ifchildren = ifnode.IfTrue.GetChildren().ToList(); for (var j = 0; j < ifchildren.Count; j++) { block.InsertAt(ifchildren[j], i + j); } } else { children.InsertRange(i, ifnode.IfFalse.GetChildren()); var ifchildren = ifnode.IfFalse.GetChildren().ToList(); for (var j = 0; j < ifchildren.Count; j++) { block.InsertAt(ifchildren[j], i + j); } } i--; } } return(changesmade); }