public void Bool_non_constant_unary_expression_compiled_successfully(string expressionString, Opcode expectedOp) { var expressionSyntax = ParseExpression(expressionString); var method = new CompiledMethod("Test::Method"); var builder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); var diagnostics = new TestingDiagnosticSink(); var variableMap = new ScopedVariableMap(); variableMap.PushScope(); variableMap.TryAddVariable("a", method.AddLocal(SimpleType.Bool, LocalFlags.None)); var localIndex = ExpressionCompiler.TryCompileExpression(expressionSyntax, SimpleType.Bool, method, builder, new TestingResolver(variableMap), diagnostics); Assert.That(diagnostics.Diagnostics, Is.Empty); Assert.That(localIndex, Is.EqualTo(1)); Assert.That(method.Values[localIndex].Type, Is.EqualTo(SimpleType.Bool)); Assert.That(builder.Instructions, Has.Exactly(1).Items); var instruction = builder.Instructions[0]; Assert.That(instruction.Operation, Is.EqualTo(expectedOp)); Assert.That(instruction.Left, Is.EqualTo(0)); Assert.That(instruction.Destination, Is.EqualTo(1)); }
public void Graph_with_two_returning_branches_and_empty_block_succeeds() { var graphBuilder = new BasicBlockGraphBuilder(); var firstBuilder = graphBuilder.GetInitialBlockBuilder(); var leftBuilder = firstBuilder.CreateSuccessorBlock(); leftBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); var rightBuilder = firstBuilder.CreateBranch(7); rightBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); // This block does not return nor is referenced, therefore it should be dropped var finalBuilder = leftBuilder.CreateSuccessorBlock(); finalBuilder.AppendInstruction(Opcode.CopyValue, 1, 2, 3); var graph = graphBuilder.Build(); Assert.That(graph.BasicBlocks, Has.Exactly(3).Items); Assert.That(graph.BasicBlocks[0].Instructions, Has.Exactly(1).Items); Assert.That(graph.BasicBlocks[0].Instructions[0].Operation, Is.EqualTo(Opcode.BranchIf)); Assert.That(graph.BasicBlocks[0].Instructions[0].Left, Is.EqualTo(7)); Assert.That(graph.BasicBlocks[0].DefaultSuccessor, Is.EqualTo(1)); Assert.That(graph.BasicBlocks[0].AlternativeSuccessor, Is.EqualTo(2)); Assert.That(graph.BasicBlocks[1].Instructions, Has.Exactly(1).Items); Assert.That(graph.BasicBlocks[1].DefaultSuccessor, Is.EqualTo(-1)); CollectionAssert.AreEqual(new[] { 0 }, graph.BasicBlocks[1].Predecessors); Assert.That(graph.BasicBlocks[2].Instructions, Has.Exactly(1).Items); Assert.That(graph.BasicBlocks[2].DefaultSuccessor, Is.EqualTo(-1)); CollectionAssert.AreEqual(new[] { 0 }, graph.BasicBlocks[2].Predecessors); }
public void GetInitialBlockBuilder_cannot_be_called_twice() { var graphBuilder = new BasicBlockGraphBuilder(); Assert.That(() => graphBuilder.GetInitialBlockBuilder(), Throws.Nothing); Assert.That(() => graphBuilder.GetInitialBlockBuilder(), Throws.InvalidOperationException); }
public void Branch_cannot_be_created_if_block_already_ends_in_branch() { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); Assert.That(() => blockBuilder.CreateBranch(0), Throws.Nothing); Assert.That(() => blockBuilder.CreateBranch(0), Throws.InvalidOperationException); }
public void SetAlternativeSuccessor_cannot_be_called_twice() { var blockBuilder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); Assert.That(() => blockBuilder.SetAlternativeSuccessor(0), Throws.Nothing); Assert.That(blockBuilder.AlternativeSuccessor, Is.EqualTo(0)); Assert.That(() => blockBuilder.SetAlternativeSuccessor(0), Throws.InvalidOperationException); }
public void Branch_cannot_be_created_if_block_ends_in_return() { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); blockBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); Assert.That(() => blockBuilder.CreateBranch(0), Throws.InvalidOperationException); }
public void Graph_with_out_of_bounds_default_successor_fails(int successor) { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); blockBuilder.SetSuccessor(successor); Assert.That(() => graphBuilder.Build(), Throws.InvalidOperationException); }
public void Block_cannot_be_appended_to_after_setting_successor() { var blockBuilder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); blockBuilder.SetSuccessor(0); blockBuilder.AppendInstruction(Opcode.Nop, 0, 0, 0); Assert.That(blockBuilder.Instructions, Is.Empty); }
public void SetAlternativeSuccessor_does_nothing_if_return_exists() { var blockBuilder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); blockBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); Assert.That(() => blockBuilder.SetAlternativeSuccessor(0), Throws.Nothing); Assert.That(blockBuilder.AlternativeSuccessor, Is.EqualTo(-1)); }
public void Branch_without_default_successor_is_invalid() { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); blockBuilder.CreateBranch(0).AppendInstruction(Opcode.Return, 0, 0, 0); Assert.That(() => graphBuilder.Build(), Throws.InvalidOperationException); }
public void Appending_to_block_after_adding_return_does_nothing() { var blockBuilder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); blockBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); Assert.That(blockBuilder.Instructions, Has.Exactly(1).Items); blockBuilder.AppendInstruction(Opcode.Nop, 0, 0, 0); Assert.That(blockBuilder.Instructions, Has.Exactly(1).Items); }
public void Branch_without_alternative_successor_is_invalid() { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); blockBuilder.AppendInstruction(Opcode.BranchIf, 0, 0, 0); blockBuilder.SetSuccessor(0); Assert.That(() => graphBuilder.Build(), Throws.InvalidOperationException); }
public void Graph_with_non_returning_branch_fails() { var graphBuilder = new BasicBlockGraphBuilder(); var firstBuilder = graphBuilder.GetInitialBlockBuilder(); var leftBuilder = firstBuilder.CreateSuccessorBlock(); leftBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); firstBuilder.CreateBranch(7); // This branch has no exit behavior Assert.That(() => graphBuilder.Build(), Throws.InvalidOperationException); }
public void GetBuilderByBlockIndex_returns_existent_builders() { var graphBuilder = new BasicBlockGraphBuilder(); var first = graphBuilder.GetInitialBlockBuilder(); // Out-of-bounds indices are not tolerated Assert.That(() => graphBuilder.GetBuilderByBlockIndex(1), Throws.InstanceOf <ArgumentOutOfRangeException>()); var second = graphBuilder.GetNewBasicBlock(); Assert.That(graphBuilder.GetBuilderByBlockIndex(0), Is.SameAs(first)); Assert.That(graphBuilder.GetBuilderByBlockIndex(1), Is.SameAs(second)); }
public void Constant_comparison_compiled_successfully(string expressionString, bool expectedValue) { var expressionSyntax = ParseExpression(expressionString); var method = new CompiledMethod("Test::Method"); var builder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); var diagnostics = new TestingDiagnosticSink(); var nameResolver = new TestingResolver(new ScopedVariableMap()); var localIndex = ExpressionCompiler.TryCompileExpression(expressionSyntax, SimpleType.Bool, method, builder, nameResolver, diagnostics); Assert.That(diagnostics.Diagnostics, Is.Empty); Assert.That(localIndex, Is.EqualTo(0)); Assert.That(method.Values[localIndex].Type, Is.EqualTo(SimpleType.Bool)); AssertSingleLoad(builder, localIndex, expectedValue); }
public void Integer_literal_that_is_too_large_fails() { var position = new TextPosition(10, 3, 4); var syntax = new IntegerLiteralSyntax((ulong)int.MaxValue + 1, position); var method = new CompiledMethod("Test::Method"); var builder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); var nameResolver = new TestingResolver(new ScopedVariableMap()); var diagnostics = new TestingDiagnosticSink(); var localIndex = ExpressionCompiler.TryCompileExpression( syntax, SimpleType.Int32, method, builder, nameResolver, diagnostics); Assert.That(localIndex, Is.EqualTo(-1)); diagnostics.AssertDiagnosticAt(DiagnosticCode.TypeMismatch, position) .WithActual("uint32").WithExpected("int32"); }
public void Variable_reference_must_refer_to_existent_variable() { var position = new TextPosition(10, 3, 4); var syntax = new IdentifierSyntax("a", position); var method = new CompiledMethod("Test::Method"); var builder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); var diagnostics = new TestingDiagnosticSink(); var variableMap = new ScopedVariableMap(); variableMap.PushScope(); var localIndex = ExpressionCompiler.TryCompileExpression( syntax, SimpleType.Int32, method, builder, new TestingResolver(variableMap), diagnostics); Assert.That(localIndex, Is.EqualTo(-1)); diagnostics.AssertDiagnosticAt(DiagnosticCode.VariableNotFound, position).WithActual("a"); }
public void Graph_with_single_basic_block_succeeds() { var graphBuilder = new BasicBlockGraphBuilder(); var blockBuilder = graphBuilder.GetInitialBlockBuilder(); blockBuilder.AppendInstruction(Opcode.Return, 0, 0, 0); Assert.That(blockBuilder.Index, Is.EqualTo(0)); var graph = graphBuilder.Build(); Assert.That(graph.BasicBlocks, Has.Exactly(1).Items); Assert.That(graph.BasicBlocks[0].Instructions, Has.Exactly(1).Items); Assert.That(graph.BasicBlocks[0].Instructions[0].Operation, Is.EqualTo(Opcode.Return)); Assert.That(graph.BasicBlocks[0].DefaultSuccessor, Is.EqualTo(-1)); Assert.That(graph.BasicBlocks[0].AlternativeSuccessor, Is.EqualTo(-1)); Assert.That(graph.BasicBlocks[0].Predecessors, Is.Empty); }
public void Int32_division_by_zero_in_constant_expression_fails(BinaryOperation op) { var position = new TextPosition(10, 3, 4); var syntax = new BinaryExpressionSyntax(op, new IntegerLiteralSyntax(2ul, default), new IntegerLiteralSyntax(0, default), position); var method = new CompiledMethod("Test::Method"); var builder = new BasicBlockGraphBuilder().GetInitialBlockBuilder(); var diagnostics = new TestingDiagnosticSink(); var nameResolver = new TestingResolver(new ScopedVariableMap()); var localIndex = ExpressionCompiler.TryCompileExpression( syntax, SimpleType.Int32, method, builder, nameResolver, diagnostics); Assert.That(localIndex, Is.EqualTo(-1)); diagnostics.AssertDiagnosticAt(DiagnosticCode.DivisionByConstantZero, position); }