public void InstructionWithOneStackArgumentShouldResultInAssignmentAndExpressionStatementWithArgument() { var cfg = ConstructAst(new[] { DummyInstruction.Push(0, 1), DummyInstruction.Pop(1, 1), DummyInstruction.Ret(2) }); var variableCapture = new CaptureGroup("variable"); var pattern = new SequencePattern <Statement <DummyInstruction> >( // stack_slot = push 1() StatementPattern .Assignment <DummyInstruction>() .WithExpression(ExpressionPattern.Instruction(new DummyInstructionPattern(DummyOpCode.Push))) .CaptureVariables(variableCapture), // pop(stack_slot) StatementPattern.Expression(ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Pop)) .WithArguments(ExpressionPattern .Variable <DummyInstruction>() .CaptureVariable(variableCapture))), // ret() StatementPattern.Instruction(new DummyInstructionPattern(DummyOpCode.Ret)) ); var result = pattern.Match(cfg.Nodes[0].Contents.Instructions); Assert.True(result.IsSuccess); Assert.Single(result.Captures[variableCapture].Distinct()); }
public void TestComplexCapture() { var valueExpression = new InstructionExpression <DummyInstruction>(DummyInstruction.Push(0, 1), ArraySegment <Expression <DummyInstruction> > .Empty); var statement = new ExpressionStatement <DummyInstruction>(new InstructionExpression <DummyInstruction>(DummyInstruction.Ret(1), new List <Expression <DummyInstruction> > { valueExpression })); // Define capture group. var returnValueGroup = new CaptureGroup("returnValue"); // Create ret(?) pattern. var pattern = StatementPattern.Expression( ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Ret)) .WithArguments( ExpressionPattern.Any <DummyInstruction>().CaptureAs(returnValueGroup) ) ); // Match. var result = pattern.Match(statement); // Extract return expression node. var capturedObject = result.Captures[returnValueGroup][0]; Assert.Same(valueExpression, capturedObject); }
public void JoiningControlFlowPathsWithDifferentVariableVersionsShouldResultInPhiNode() { var variable = new DummyVariable("temp"); var cfg = ConstructAst(new[] { DummyInstruction.Push(0, 1), DummyInstruction.JmpCond(1, 5), DummyInstruction.Push(2, 1), DummyInstruction.Set(3, variable), DummyInstruction.Jmp(4, 7), DummyInstruction.Push(5, 1), DummyInstruction.Set(6, variable), DummyInstruction.Get(7, variable), DummyInstruction.Pop(8, 1), DummyInstruction.Ret(9) }); var phiSourcesCapture = new CaptureGroup("sources"); var variablesCapture = new CaptureGroup("variables"); // temp_vx = set(?) var assignPattern = StatementPattern .Assignment <DummyInstruction>() .WithExpression(ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Set)) .WithArguments(1)) .CaptureVariables(variablesCapture); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(2) .CaptureSources(phiSourcesCapture); var set1Result = assignPattern.FindFirstMatch(cfg.Nodes[2].Contents.Instructions); var set2Result = assignPattern.FindFirstMatch(cfg.Nodes[5].Contents.Instructions); var phiResult = phiPattern.Match(cfg.Nodes[7].Contents.Header); Assert.True(set1Result.IsSuccess, "Node 2 was expected to contain an assignment statement."); Assert.True(set2Result.IsSuccess, "Node 5 was expected to contain an assignment statement."); Assert.True(phiResult.IsSuccess, "Node 7 was expected to start with a phi statement."); var sources = phiResult.Captures[phiSourcesCapture] .Cast <VariableExpression <DummyInstruction> >() .Select(s => s.Variable); var allVariables = new[] { (IVariable)set1Result.Captures[variablesCapture][0], (IVariable)set2Result.Captures[variablesCapture][0] }; Assert.Equal(allVariables.ToHashSet(), sources.ToHashSet()); }
public void PushingTwoValuesOnStackWithDifferentConsumers() { var cfg = ConstructAst(new[] { DummyInstruction.Push(0, 2), DummyInstruction.Pop(1, 1), DummyInstruction.Pop(2, 1), DummyInstruction.Ret(3) }); var variableCapture = new CaptureGroup("variable"); var argumentsCapture1 = new CaptureGroup("argument1"); var argumentsCapture2 = new CaptureGroup("argument2"); var pattern = new SequencePattern <Statement <DummyInstruction> >( // stack_slot_1, stack_slot_2 = push 2() StatementPattern .Assignment <DummyInstruction>() .WithVariables(2) .CaptureVariables(variableCapture), // pop(?) StatementPattern.Expression(ExpressionPattern .Instruction <DummyInstruction>() .WithArguments(1) .CaptureArguments(argumentsCapture1)), // pop(?) StatementPattern.Expression(ExpressionPattern .Instruction <DummyInstruction>() .WithArguments(1) .CaptureArguments(argumentsCapture2)), // ret() StatementPattern.Instruction(new DummyInstructionPattern(DummyOpCode.Ret)) ); var result = pattern.Match(cfg.Nodes[0].Contents.Instructions); Assert.True(result.IsSuccess); var variables = result.Captures[variableCapture] .Cast <IVariable>() .ToArray(); var argument1 = (VariableExpression <DummyInstruction>)result.Captures[argumentsCapture1][0]; var argument2 = (VariableExpression <DummyInstruction>)result.Captures[argumentsCapture2][0]; // Note: we expect the first pop statement to use the second variable that was pushed by the push instruction. Assert.Equal(variables[1], argument1.Variable); Assert.Equal(variables[0], argument2.Variable); }
public void PushingTwoValuesOnStackShouldResultInTwoVariablesAssigned() { var cfg = ConstructAst(new[] { DummyInstruction.Push(0, 2), DummyInstruction.Pop(1, 2), DummyInstruction.Ret(2) }); var variableCapture = new CaptureGroup("variable"); var argumentsCapture = new CaptureGroup("argument"); var pattern = new SequencePattern <Statement <DummyInstruction> >( // stack_slot_1, stack_slot_2 = push 2() StatementPattern .Assignment <DummyInstruction>() .WithVariables(2) .CaptureVariables(variableCapture), // pop(?, ?) StatementPattern.Expression(ExpressionPattern .Instruction <DummyInstruction>() .WithArguments(2) .CaptureArguments(argumentsCapture)), // ret() StatementPattern.Instruction(new DummyInstructionPattern(DummyOpCode.Ret)) ); var result = pattern.Match(cfg.Nodes[0].Contents.Instructions); Assert.True(result.IsSuccess); var variables = result.Captures[variableCapture] .Cast <IVariable>() .ToArray(); var arguments = result.Captures[argumentsCapture] .Cast <VariableExpression <DummyInstruction> >() .Select(e => e.Variable) .ToArray(); Assert.Equal(variables, arguments); }
public void JoiningPathsWithMultipleAssignmentsShouldOnlyUseLatestVersion() { var variable = new DummyVariable("temp"); var cfg = ConstructAst(new[] { // if (cond) goto else: DummyInstruction.Push(0, 1), DummyInstruction.JmpCond(1, 7), // temp = some_value (not used). DummyInstruction.Push(2, 1), DummyInstruction.Set(3, variable), // temp = some_value (render previous value useless) DummyInstruction.Push(4, 1), DummyInstruction.Set(5, variable), // goto end DummyInstruction.Jmp(6, 9), // else: // temp = some_value DummyInstruction.Push(7, 1), DummyInstruction.Set(8, variable), // end: // pop(temp) DummyInstruction.Get(9, variable), DummyInstruction.Pop(10, 1), // return DummyInstruction.Ret(11) }); var phiSourcesCapture = new CaptureGroup("sources"); var variablesCapture = new CaptureGroup("variables"); // variable = phi(?, ?) var phiPattern = StatementPattern .Phi <DummyInstruction>() .WithSources(2) .CaptureSources(phiSourcesCapture); // temp_vx = set(?) var assignPattern = StatementPattern .Assignment <DummyInstruction>() .WithExpression(ExpressionPattern .Instruction(new DummyInstructionPattern(DummyOpCode.Set)) .WithArguments(1)) .CaptureVariables(variablesCapture); var assignment1Results = assignPattern .FindAllMatches(cfg.Nodes[7].Contents.Instructions) .ToArray(); var assignment2Results = assignPattern .FindAllMatches(cfg.Nodes[2].Contents.Instructions) .ToArray(); var phiResult = phiPattern.Match(cfg.Nodes[9].Contents.Header); Assert.True(assignment1Results.Length == 1, "Node 7 was expected to have one assignment to 'temp'."); Assert.True(assignment2Results.Length == 2, "Node 2 was expected to have two assignments to 'temp'."); Assert.True(phiResult.IsSuccess, "Node 9 was expected to start with a phi node with two sources."); var sources = phiResult.Captures[phiSourcesCapture] .Cast <VariableExpression <DummyInstruction> >() .Select(s => s.Variable); var allVariables = new[] { (IVariable)assignment1Results[0].Captures[variablesCapture][0], (IVariable)assignment2Results[1].Captures[variablesCapture][0] }; Assert.Equal(allVariables.ToHashSet(), sources.ToHashSet()); }