public AsyncStateGroupData( AsyncStateGroup asyncStateGroup, ContextWrapper context, LLVMValueRef function, LLVMBasicBlockRef initialBasicBlock, LLVMBasicBlockRef continueBasicBlock, LLVMBasicBlockRef exitBasicBlock, StateFieldValueSource fireCountStateField) { AsyncStateGroup = asyncStateGroup; Context = context; Function = function; InitialBasicBlock = initialBasicBlock; ContinueBasicBlock = continueBasicBlock; ExitBasicBlock = exitBasicBlock; FireCountStateField = fireCountStateField; }
public void UnconditionalFrameWithNoInteriorAwaits_GroupAsyncStates_AllFrameAsyncStateGroupsInSameFunction() { DfirRoot function = DfirRoot.Create(); Frame frame = Frame.Create(function.BlockDiagram); Tunnel inputTunnel = CreateInputTunnel(frame); ConnectConstantToInputTerminal(inputTunnel.InputTerminals[0], NITypes.Int32, false); var output = new FunctionalNode(frame.Diagram, Signatures.OutputType); Wire.Create(frame.Diagram, inputTunnel.OutputTerminals[0], output.InputTerminals[0]); IEnumerable <AsyncStateGroup> asyncStateGroups = GroupAsyncStates(function); AsyncStateGroup firstGroup = asyncStateGroups.First(); var groupFunctionId = firstGroup.FunctionId; Assert.IsTrue(asyncStateGroups.All(g => g.FunctionId == groupFunctionId)); }
public void LoopFollowedByLoop_GroupAsyncStates_SubsequentLoopStartsInPredecessorLoopTerminalGroup() { DfirRoot function = DfirRoot.Create(); Loop firstLoop = new Loop(function.BlockDiagram); BorrowTunnel firstLoopBorrow = CreateBorrowTunnel(firstLoop, BorrowMode.Immutable); ConnectConstantToInputTerminal(firstLoopBorrow.InputTerminals[0], NITypes.Int32, false); TerminateLifetimeTunnel firstLoopTerminate = firstLoopBorrow.TerminateLifetimeTunnel; Loop secondLoop = new Loop(function.BlockDiagram); Tunnel loopTunnel = CreateInputTunnel(secondLoop); Wire.Create(function.BlockDiagram, firstLoopTerminate.OutputTerminals[0], loopTunnel.InputTerminals[0]); IEnumerable <AsyncStateGroup> asyncStateGroups = GroupAsyncStates(function); string terminalGroupName = $"loop{firstLoop.UniqueId}_terminalGroup"; AsyncStateGroup firstLoopTerminalGroup = asyncStateGroups.First(g => g.Label == terminalGroupName); AsyncStateGroup secondLoopInitialGroup = asyncStateGroups.First(g => g.GroupContainsStructureTraversalPoint(secondLoop, secondLoop.Diagram, StructureTraversalPoint.BeforeLeftBorderNodes)); Assert.AreEqual(firstLoopTerminalGroup, secondLoopInitialGroup); }
public void FrameWithUnwrapOptionTunnelAndNoInteriorAwaits_GroupAsyncStates_AllFrameAsyncStateGroupsInSameFunction() { DfirRoot function = DfirRoot.Create(); Frame frame = Frame.Create(function.BlockDiagram); UnwrapOptionTunnel unwrapTunnel = CreateUnwrapOptionTunnel(frame); FunctionalNode someConstructor = ConnectSomeConstructorToInputTerminal(unwrapTunnel.InputTerminals[0]); ConnectConstantToInputTerminal(someConstructor.InputTerminals[0], NITypes.Int32, false); var output = new FunctionalNode(frame.Diagram, Signatures.OutputType); Wire.Create(frame.Diagram, unwrapTunnel.OutputTerminals[0], output.InputTerminals[0]); IEnumerable <AsyncStateGroup> asyncStateGroups = GroupAsyncStates(function); AsyncStateGroup frameInitialGroup = asyncStateGroups.First(g => g.GroupContainsStructureTraversalPoint(frame, frame.Diagram, StructureTraversalPoint.BeforeLeftBorderNodes)), frameDiagramInitialGroup = asyncStateGroups.First(g => g.GroupContainsNode(output)), frameTerminalGroup = asyncStateGroups.First(g => g.GroupContainsStructureTraversalPoint(frame, frame.Diagram, StructureTraversalPoint.AfterRightBorderNodes)); Assert.AreEqual(frameInitialGroup.FunctionId, frameDiagramInitialGroup.FunctionId); Assert.AreEqual(frameInitialGroup.FunctionId, frameTerminalGroup.FunctionId); }
protected void CompileAsyncStateGroup(AsyncStateGroup asyncStateGroup, FunctionCompilerState compilerState) { FunctionCompilerState previousState = CurrentState; CurrentGroup = asyncStateGroup; CurrentState = compilerState; AsyncStateGroupData groupData = AsyncStateGroups[asyncStateGroup]; LLVMValueRef groupFunction = groupData.Function; Builder.PositionBuilderAtEnd(groupData.InitialBasicBlock); // Here we are assuming that the group whose label matches the function name is also the entry group. if (asyncStateGroup.FunctionId == asyncStateGroup.Label && this is AsynchronousFunctionModuleBuilder) { AllocationSet.InitializeFunctionLocalAllocations(asyncStateGroup.FunctionId, Builder); } var conditionalContinuation = asyncStateGroup.Continuation as ConditionallyScheduleGroupsContinuation; if (conditionalContinuation != null) { var continuationConditionValueSource = (IInitializableValueSource)SharedData.VariableStorage.GetValueSourceForVariable(asyncStateGroup.ContinuationCondition); LLVMValueRef initialConditionValue = LLVMSharp.LLVM.ConstNull(SharedData.Context.AsLLVMType(asyncStateGroup.ContinuationCondition.Type)); continuationConditionValueSource.InitializeValue(Builder, initialConditionValue); } if (asyncStateGroup.IsSkippable) { if (asyncStateGroup.FunctionId == asyncStateGroup.Label && this is SynchronousFunctionModuleBuilder) { _localDoneAllocationPtr = Builder.CreateAlloca(FunctionAllocationSet.FunctionCompletionStatusType(SharedData.Context), "donePtr"); Builder.CreateBr(groupData.ContinueBasicBlock); } else { LLVMValueRef shouldContinue = GenerateContinueStateCheck(); Builder.CreateCondBr(shouldContinue, groupData.ContinueBasicBlock, groupData.ExitBasicBlock); } Builder.PositionBuilderAtEnd(groupData.ContinueBasicBlock); } groupData.CreateFireCountReset(Builder); foreach (Visitation visitation in asyncStateGroup.Visitations) { visitation.Visit <bool>(SharedData.VisitationHandler); } var unconditionalContinuation = asyncStateGroup.Continuation as UnconditionallySchduleGroupsContinuation; if (unconditionalContinuation != null && !unconditionalContinuation.UnconditionalSuccessors.Any() && this is AsynchronousFunctionModuleBuilder) { GenerateStoreCompletionState(RuntimeConstants.FunctionCompletedNormallyStatus); } if (asyncStateGroup.IsSkippable) { Builder.CreateBr(groupData.ExitBasicBlock); Builder.PositionBuilderAtEnd(groupData.ExitBasicBlock); } bool returnAfterGroup = true; if (unconditionalContinuation != null) { if (unconditionalContinuation.UnconditionalSuccessors.Any()) { AsyncStateGroup singleSuccessor; if (unconditionalContinuation.UnconditionalSuccessors.TryGetSingleElement(out singleSuccessor) && singleSuccessor.FunctionId == asyncStateGroup.FunctionId) { Builder.CreateBr(AsyncStateGroups[singleSuccessor].InitialBasicBlock); returnAfterGroup = false; } else { CreateInvokeOrScheduleOfSuccessors(unconditionalContinuation.UnconditionalSuccessors); } } else if (this is AsynchronousFunctionModuleBuilder) { GenerateFunctionTerminator(); } } if (conditionalContinuation != null) { LLVMValueRef condition = SharedData.VariableStorage.GetValueSourceForVariable(asyncStateGroup.ContinuationCondition).GetValue(Builder); bool isBooleanCondition = conditionalContinuation.SuccessorConditionGroups.Count == 2; bool allSynchronousContinuations = conditionalContinuation.SuccessorConditionGroups.All(group => { AsyncStateGroup singleSuccessor; return(group.TryGetSingleElement(out singleSuccessor) && singleSuccessor.FunctionId == asyncStateGroup.FunctionId); }); if (allSynchronousContinuations) { LLVMBasicBlockRef[] initialBlocks = conditionalContinuation.SuccessorConditionGroups .Select(g => AsyncStateGroups[g.First()].InitialBasicBlock) .ToArray(); if (isBooleanCondition) { Builder.CreateCondBr(condition, initialBlocks[1], initialBlocks[0]); } else { LLVMValueRef conditionSwitch = Builder.CreateSwitch(condition, initialBlocks[0], (uint)(initialBlocks.Length - 1)); for (int i = 1; i < initialBlocks.Length; ++i) { conditionSwitch.AddCase(SharedData.Context.AsLLVMValue((byte)i), initialBlocks[i]); } } returnAfterGroup = false; } else { LLVMBasicBlockRef[] continuationConditionBlocks = Enumerable.Range(0, conditionalContinuation.SuccessorConditionGroups.Count) .Select(i => groupFunction.AppendBasicBlock($"continuationCondition{i}")) .ToArray(); LLVMBasicBlockRef exitBlock = groupFunction.AppendBasicBlock("exit"); if (isBooleanCondition) { Builder.CreateCondBr(condition, continuationConditionBlocks[1], continuationConditionBlocks[0]); } else { LLVMValueRef conditionSwitch = Builder.CreateSwitch(condition, continuationConditionBlocks[0], (uint)(conditionalContinuation.SuccessorConditionGroups.Count - 1)); for (int i = 1; i < continuationConditionBlocks.Length; ++i) { conditionSwitch.AddCase(SharedData.Context.AsLLVMValue((byte)i), continuationConditionBlocks[i]); } } for (int i = 0; i < continuationConditionBlocks.Length; ++i) { Builder.PositionBuilderAtEnd(continuationConditionBlocks[i]); CreateInvokeOrScheduleOfSuccessors(conditionalContinuation.SuccessorConditionGroups[i]); Builder.CreateBr(exitBlock); } Builder.PositionBuilderAtEnd(exitBlock); } } if (returnAfterGroup) { Builder.CreateRetVoid(); } CurrentGroup = null; CurrentState = previousState; }