internal static void BuildSetNotifierValueFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef setNotifierValueFunction)
        {
            NIType      valueType     = signature.GetGenericParameters().First();
            LLVMTypeRef valueLLVMType = moduleContext.LLVMContext.AsLLVMType(valueType);

            LLVMBasicBlockRef entryBlock            = setNotifierValueFunction.AppendBasicBlock("entry"),
                              readerWasWaitingBlock = setNotifierValueFunction.AppendBasicBlock("readerWasWaiting"),
                              readerWasDroppedBlock = setNotifierValueFunction.AppendBasicBlock("readerWasDropped"),
                              exitBlock             = setNotifierValueFunction.AppendBasicBlock("exit");
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef notifierWriter = setNotifierValueFunction.GetParam(0u),
                         value          = setNotifierValueFunction.GetParam(1u),
                         refCountPtr    = builder.CreateExtractValue(notifierWriter, 0u, "refCountPtr"),
                         sharedDataPtr  = builder.CreateStructGEP(refCountPtr, 1u, "sharedDataPtr"),
                         valuePtr       = builder.CreateStructGEP(sharedDataPtr, SharedDataValueFieldIndex, "valuePtr"),
                         statePtr       = builder.CreateStructGEP(sharedDataPtr, SharedDataStateFieldIndex, "statePtr");

            builder.CreateStore(value, valuePtr);
            // This is Release because it needs the reader thread to observe the value store above,
            // and Acquire because it may need to observe the reader thread's waker store below.
            LLVMValueRef oldState = builder.CreateAtomicRMW(
                LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpOr,
                statePtr,
                moduleContext.LLVMContext.AsLLVMValue(WriterDroppedWithValue),
                LLVMAtomicOrdering.LLVMAtomicOrderingAcquireRelease,
                false);
            LLVMValueRef oldReaderState    = builder.CreateAnd(oldState, moduleContext.LLVMContext.AsLLVMValue(ReaderStateMask), "oldReaderState"),
                         readerStateSwitch = builder.CreateSwitch(oldReaderState, exitBlock, 2u);

            readerStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(ReaderWaitingForValue), readerWasWaitingBlock);
            readerStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(ReaderDropped), readerWasDroppedBlock);

            builder.PositionBuilderAtEnd(readerWasWaitingBlock);
            LLVMValueRef wakerPtr = builder.CreateStructGEP(sharedDataPtr, SharedDataWakerFieldIndex, "wakerPtr"),
                         waker    = builder.CreateLoad(wakerPtr, "waker");

            builder.CreateCall(moduleContext.FunctionImporter.GetImportedCommonFunction(CommonModules.InvokeName), new LLVMValueRef[] { waker }, string.Empty);
            builder.CreateBr(exitBlock);

            builder.PositionBuilderAtEnd(readerWasDroppedBlock);
            moduleContext.CreateDropCallIfDropFunctionExists(builder, valueType, _ => valuePtr);
            builder.CreateBr(exitBlock);

            builder.PositionBuilderAtEnd(exitBlock);
            LLVMValueRef decrementRefCountFunction = GetDecrementRefCountFunction(moduleContext, valueType.CreateNotifierSharedDataType());

            builder.CreateCall(decrementRefCountFunction, new LLVMValueRef[] { refCountPtr }, string.Empty);
            builder.CreateRetVoid();
        }
Beispiel #2
0
        internal static void BuildVariantDropFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef variantDropFunction)
        {
            NIType variantType = signature.GetGenericParameters().First();

            Tuple <NIType, int>[] droppableFields = variantType.GetFields()
                                                    .Select((field, i) => new Tuple <NIType, int>(field, i))
                                                    .Where(field => field.Item1.GetDataType().TypeHasDropTrait()).ToArray();
            LLVMBasicBlockRef entryBlock = variantDropFunction.AppendBasicBlock("entry");

            Tuple <LLVMBasicBlockRef, int>[] dropBlocks = droppableFields.Select(field => new Tuple <LLVMBasicBlockRef, int>(variantDropFunction.AppendBasicBlock($"drop{field.Item1.GetName()}"), field.Item2)).ToArray();
            LLVMBasicBlockRef exitBlock = variantDropFunction.AppendBasicBlock("exit");

            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef variantPtr     = variantDropFunction.GetParam(0u),
                         variantTagPtr  = builder.CreateStructGEP(variantPtr, 0u, "variantTagPtr"),
                         variantDataPtr = builder.CreateStructGEP(variantPtr, 1u, "variantDataPtr"),
                         variantTag     = builder.CreateLoad(variantTagPtr, "variantTag"),
                         tagSwitch      = builder.CreateSwitch(variantTag, exitBlock, (uint)dropBlocks.Length);

            foreach (var pair in dropBlocks)
            {
                tagSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue((byte)pair.Item2), pair.Item1);
            }

            for (int i = 0; i < droppableFields.Length; ++i)
            {
                builder.PositionBuilderAtEnd(dropBlocks[i].Item1);
                NIType       fieldType       = droppableFields[i].Item1.GetDataType();
                LLVMTypeRef  fieldLLVMType   = moduleContext.LLVMContext.AsLLVMType(fieldType);
                LLVMValueRef bitCastFieldPtr = builder.CreateBitCast(variantDataPtr, LLVMTypeRef.PointerType(fieldLLVMType, 0u), "bitCastFieldPtr");
                moduleContext.CreateDropCallIfDropFunctionExists(builder, fieldType, _ => bitCastFieldPtr);
                builder.CreateBr(exitBlock);
            }

            builder.PositionBuilderAtEnd(exitBlock);
            builder.CreateRetVoid();
        }
Beispiel #3
0
        internal static void BuildMethodCallPromisePollFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef methodCallPromisePollFunction)
        {
            NIType optionPromiseResultType = signature.GetParameters().ElementAt(2).GetDataType();
            NIType promiseResultType;

            optionPromiseResultType.TryDestructureOptionType(out promiseResultType);
            NIType resultType;
            bool   mayPanic = promiseResultType.TryDestructurePanicResultType(out resultType);

            LLVMBasicBlockRef entryBlock          = methodCallPromisePollFunction.AppendBasicBlock("entry"),
                              targetDoneBlock     = methodCallPromisePollFunction.AppendBasicBlock("targetDone"),
                              targetNotDoneBlock  = methodCallPromisePollFunction.AppendBasicBlock("targetNotDone");
            LLVMBasicBlockRef targetPanickedBlock = mayPanic
                ? methodCallPromisePollFunction.AppendBasicBlock("targetPanicked")
                : default(LLVMBasicBlockRef);
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMTypeRef stateType = moduleContext.LLVMContext.StructType(new[]
            {
                FunctionAllocationSet.FunctionCompletionStatusType(moduleContext.LLVMContext),
                moduleContext.LLVMContext.WakerType(),
            });

            LLVMValueRef promisePtr              = methodCallPromisePollFunction.GetParam(0u),
                         promise                 = builder.CreateLoad(promisePtr, "promise"),
                         stateVoidPtr            = builder.CreateExtractValue(promise, MethodCallPromiseStatePtrFieldIndex, "stateVoidPtr"),
                         result                  = builder.CreateExtractValue(promise, MethodCallPromiseOutputFieldIndex, "result"),
                         statePtr                = builder.CreateBitCast(stateVoidPtr, LLVMTypeRef.PointerType(stateType, 0u), "statePtr"),
                         state                   = builder.CreateLoad(statePtr, "state"),
                         functionCompletionState = builder.CreateExtractValue(state, 0u, "functionCompletionState"),
                         optionResultOutputPtr   = methodCallPromisePollFunction.GetParam(2u);
            LLVMTypeRef optionResultOutputType   = optionResultOutputPtr.TypeOf().GetElementType();

            uint         switchCases           = mayPanic ? 2u : 1u;
            LLVMValueRef completionStateSwitch = builder.CreateSwitch(functionCompletionState, targetNotDoneBlock, switchCases);

            completionStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(RuntimeConstants.FunctionCompletedNormallyStatus), targetDoneBlock);
            if (mayPanic)
            {
                completionStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(RuntimeConstants.FunctionPanickedStatus), targetPanickedBlock);
            }

            builder.PositionBuilderAtEnd(targetDoneBlock);
            builder.CreateFree(stateVoidPtr);
            LLVMValueRef finalResult = mayPanic ? builder.CreateInsertValue(result, moduleContext.LLVMContext.AsLLVMValue(true), 0u, "okResult") : result;
            LLVMValueRef someResult  = moduleContext.LLVMContext.BuildOptionValue(builder, optionResultOutputType, finalResult);

            builder.CreateStore(someResult, optionResultOutputPtr);
            builder.CreateRetVoid();

            builder.PositionBuilderAtEnd(targetNotDoneBlock);
            LLVMValueRef waker            = methodCallPromisePollFunction.GetParam(1u),
                         wakerFunctionPtr = builder.CreateExtractValue(waker, 0u, "wakerFunctionPtr"),
                         wakerStatePtr    = builder.CreateExtractValue(waker, 1u, "wakerStatePtr"),
                         pollFunctionPtr  = builder.CreateExtractValue(promise, MethodCallPromisePollFunctionPtrFieldIndex, "pollFunctionPtr");

            builder.CreateCall(pollFunctionPtr, new LLVMValueRef[] { stateVoidPtr, wakerFunctionPtr, wakerStatePtr }, string.Empty);
            LLVMValueRef noneResult = moduleContext.LLVMContext.BuildOptionValue(builder, optionResultOutputType, null);

            builder.CreateStore(noneResult, optionResultOutputPtr);
            builder.CreateRetVoid();

            if (mayPanic)
            {
                builder.PositionBuilderAtEnd(targetPanickedBlock);
                LLVMValueRef panicResult     = builder.CreateInsertValue(result, moduleContext.LLVMContext.AsLLVMValue(false), 0u, "panicResult"),
                             somePanicResult = moduleContext.LLVMContext.BuildOptionValue(builder, optionResultOutputType, panicResult);
                builder.CreateStore(somePanicResult, optionResultOutputPtr);
                builder.CreateRetVoid();
            }
        }
        internal static void BuildNotifierReaderPromisePollFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef notifierReaderPromisePollFunction)
        {
            NIType notifierReaderPromiseType = signature.GetGenericParameters().ElementAt(0),
                   valueType = notifierReaderPromiseType.GetGenericParameters().ElementAt(0);
            LLVMTypeRef optionValueLLVMType       = moduleContext.LLVMContext.AsLLVMType(valueType.CreateOption()),
                        optionOptionValueLLVMType = moduleContext.LLVMContext.AsLLVMType(valueType.CreateOption().CreateOption());

            LLVMBasicBlockRef entryBlock       = notifierReaderPromisePollFunction.AppendBasicBlock("entry"),
                              writerReadyBlock = notifierReaderPromisePollFunction.AppendBasicBlock("writerReady"),
                              writerDroppedWithoutValueBlock = notifierReaderPromisePollFunction.AppendBasicBlock("writerDroppedWithoutValue"),
                              writerDroppedWithValueBlock    = notifierReaderPromisePollFunction.AppendBasicBlock("writerDroppedWithValue"),
                              endBlock = notifierReaderPromisePollFunction.AppendBasicBlock("end");
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef notifierReaderPromisePtr = notifierReaderPromisePollFunction.GetParam(0u),
                         waker                 = notifierReaderPromisePollFunction.GetParam(1u),
                         pollResultPtr         = notifierReaderPromisePollFunction.GetParam(2u),
                         notifierReaderPromise = builder.CreateLoad(notifierReaderPromisePtr, "notifierReaderPromise"),
                         refCountPtr           = builder.CreateExtractValue(notifierReaderPromise, 0u, "refCountPtr"),
                         sharedDataPtr         = builder.CreateStructGEP(refCountPtr, 1u, "sharedDataPtr"),
                         wakerPtr              = builder.CreateStructGEP(sharedDataPtr, SharedDataWakerFieldIndex, "wakerPtr"),
                         statePtr              = builder.CreateStructGEP(sharedDataPtr, SharedDataStateFieldIndex, "statePtr");

            builder.CreateStore(waker, wakerPtr);
            // This is Release because it needs the writer thread to observe the waker store,
            // and Acquire because it may need to observe the writer thread's value store.
            LLVMValueRef oldState = builder.CreateAtomicRMW(
                LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpOr,
                statePtr,
                moduleContext.LLVMContext.AsLLVMValue(ReaderWaitingForValue),
                LLVMAtomicOrdering.LLVMAtomicOrderingAcquireRelease,
                false),
                         oldWriterState    = builder.CreateAnd(oldState, moduleContext.LLVMContext.AsLLVMValue(WriterStateMask), "oldWriterState");
            LLVMValueRef writerStateSwitch = builder.CreateSwitch(oldWriterState, writerReadyBlock, 2u);

            writerStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(WriterDroppedWithoutValue), writerDroppedWithoutValueBlock);
            writerStateSwitch.AddCase(moduleContext.LLVMContext.AsLLVMValue(WriterDroppedWithValue), writerDroppedWithValueBlock);

            builder.PositionBuilderAtEnd(writerReadyBlock);
            // output None
            builder.CreateStore(LLVMTypeRef.ConstNull(optionOptionValueLLVMType), pollResultPtr);
            builder.CreateRetVoid();

            builder.PositionBuilderAtEnd(writerDroppedWithoutValueBlock);
            // output Some(None)
            builder.CreateStore(moduleContext.LLVMContext.BuildOptionValue(builder, optionOptionValueLLVMType, LLVMTypeRef.ConstNull(optionValueLLVMType)), pollResultPtr);
            builder.CreateBr(endBlock);

            builder.PositionBuilderAtEnd(writerDroppedWithValueBlock);
            // output Some(Some(value))
            LLVMValueRef valuePtr = builder.CreateStructGEP(sharedDataPtr, SharedDataValueFieldIndex, "valuePtr"),
                         value    = builder.CreateLoad(valuePtr, "value");

            builder.CreateStore(moduleContext.LLVMContext.BuildOptionValue(builder, optionOptionValueLLVMType, moduleContext.LLVMContext.BuildOptionValue(builder, optionValueLLVMType, value)), pollResultPtr);
            builder.CreateBr(endBlock);

            builder.PositionBuilderAtEnd(endBlock);
            LLVMValueRef decrementRefCountFunction = GetDecrementRefCountFunction(moduleContext, valueType.CreateNotifierSharedDataType());

            builder.CreateCall(decrementRefCountFunction, new LLVMValueRef[] { refCountPtr }, string.Empty);
            builder.CreateRetVoid();
        }
        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;
        }