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(); }