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