internal static void BuildOptionDropFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef optionDropFunction)
        {
            NIType innerType;

            signature.GetGenericParameters().First().TryDestructureOptionType(out innerType);

            LLVMBasicBlockRef entryBlock  = optionDropFunction.AppendBasicBlock("entry"),
                              isSomeBlock = optionDropFunction.AppendBasicBlock("isSome"),
                              endBlock    = optionDropFunction.AppendBasicBlock("end");
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef optionPtr = optionDropFunction.GetParam(0u),
                         isSomePtr = builder.CreateStructGEP(optionPtr, 0u, "isSomePtr"),
                         isSome    = builder.CreateLoad(isSomePtr, "isSome");

            builder.CreateCondBr(isSome, isSomeBlock, endBlock);

            builder.PositionBuilderAtEnd(isSomeBlock);
            moduleContext.CreateDropCallIfDropFunctionExists(builder, innerType, b => b.CreateStructGEP(optionPtr, 1u, "innerValuePtr"));
            builder.CreateBr(endBlock);

            builder.PositionBuilderAtEnd(endBlock);
            builder.CreateRetVoid();
        }
        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();
        }
Example #3
0
        private static LLVMValueRef BuildDecrementRefCountFunction(FunctionModuleContext moduleContext, string functionName, NIType valueType)
        {
            LLVMTypeRef functionType = LLVMTypeRef.FunctionType(
                moduleContext.LLVMContext.VoidType,
                new LLVMTypeRef[]
            {
                LLVMTypeRef.PointerType(moduleContext.LLVMContext.CreateLLVMRefCountType(moduleContext.LLVMContext.AsLLVMType(valueType)), 0u)
            },
                false);
            LLVMValueRef      decrementRefCountFunction = moduleContext.Module.AddFunction(functionName, functionType);
            LLVMBasicBlockRef entryBlock           = decrementRefCountFunction.AppendBasicBlock("entry"),
                              noRefsRemainingBlock = decrementRefCountFunction.AppendBasicBlock("noRefsRemaining"),
                              endBlock             = decrementRefCountFunction.AppendBasicBlock("end");
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef refCountObjectPtr = decrementRefCountFunction.GetParam(0u),
                         referenceCountPtr = builder.CreateStructGEP(refCountObjectPtr, 0u, "referenceCountPtr"),
                         one = moduleContext.LLVMContext.AsLLVMValue(1),
                         previousReferenceCount = builder.CreateAtomicRMW(
                LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpSub,
                referenceCountPtr,
                one,
                // Since the decrement to the reference count does not have any effect until after we branch,
                // we only need monotonic ordering here.
                // See the documentation about atomic orderings here: https://llvm.org/docs/LangRef.html#atomic-memory-ordering-constraints
                LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic,
                false),
                         noRefsRemaining = builder.CreateICmp(LLVMIntPredicate.LLVMIntEQ, previousReferenceCount, one, "noRefsRemaining");

            builder.CreateCondBr(noRefsRemaining, noRefsRemainingBlock, endBlock);

            builder.PositionBuilderAtEnd(noRefsRemainingBlock);
            moduleContext.CreateDropCallIfDropFunctionExists(builder, valueType, b => b.CreateStructGEP(refCountObjectPtr, 1u, "valuePtr"));
            builder.CreateFree(refCountObjectPtr);
            builder.CreateBr(endBlock);

            builder.PositionBuilderAtEnd(endBlock);
            builder.CreateRetVoid();
            return(decrementRefCountFunction);
        }
Example #4
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();
        }
        internal static void BuildNotifierReaderDropFunction(FunctionModuleContext moduleContext, NIType signature, LLVMValueRef notifierReaderDropFunction)
        {
            NIType notifierReaderType = signature.GetGenericParameters().ElementAt(0),
                   valueType          = notifierReaderType.GetGenericParameters().ElementAt(0);

            LLVMBasicBlockRef entryBlock = notifierReaderDropFunction.AppendBasicBlock("entry"),
                              writerWasDroppedWithValueBlock = notifierReaderDropFunction.AppendBasicBlock("writerWasDroppedWithValue"),
                              endBlock = notifierReaderDropFunction.AppendBasicBlock("end");
            var builder = moduleContext.LLVMContext.CreateIRBuilder();

            builder.PositionBuilderAtEnd(entryBlock);
            LLVMValueRef notifierReaderPtr = notifierReaderDropFunction.GetParam(0u),
                         notifierReader    = builder.CreateLoad(notifierReaderPtr, "notifierReaderPromise"),
                         refCountPtr       = builder.CreateExtractValue(notifierReader, 0u, "refCountPtr"),
                         sharedDataPtr     = builder.CreateStructGEP(refCountPtr, 1u, "sharedDataPtr"),
                         statePtr          = builder.CreateStructGEP(sharedDataPtr, SharedDataStateFieldIndex, "statePtr");
            // This is Acquire because it may need to observe the writer's value store.
            LLVMValueRef oldState = builder.CreateAtomicRMW(
                LLVMAtomicRMWBinOp.LLVMAtomicRMWBinOpOr,
                statePtr,
                moduleContext.LLVMContext.AsLLVMValue(ReaderDropped),
                LLVMAtomicOrdering.LLVMAtomicOrderingAcquire,
                false),
                         oldWriterState            = builder.CreateAnd(oldState, moduleContext.LLVMContext.AsLLVMValue(WriterStateMask), "oldWriterState"),
                         writerWasDroppedWithValue = builder.CreateICmp(LLVMIntPredicate.LLVMIntEQ, oldWriterState, moduleContext.LLVMContext.AsLLVMValue(WriterDroppedWithValue), "writerWasDroppedWithValue");

            builder.CreateCondBr(writerWasDroppedWithValue, writerWasDroppedWithValueBlock, endBlock);

            builder.PositionBuilderAtEnd(writerWasDroppedWithValueBlock);
            moduleContext.CreateDropCallIfDropFunctionExists(builder, valueType, b => b.CreateStructGEP(sharedDataPtr, SharedDataValueFieldIndex, "valuePtr"));
            builder.CreateBr(endBlock);

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

            builder.CreateCall(decrementRefCountFunction, new LLVMValueRef[] { refCountPtr }, string.Empty);
            builder.CreateRetVoid();
        }