internal static LLVM.FunctionCompileResult CompileFunctionForLLVM( DfirRoot dfirRoot, CompileCancellationToken cancellationToken, Dictionary <CompilableDefinitionName, bool> calleesIsYielding, Dictionary <CompilableDefinitionName, bool> calleesMayPanic, string compiledFunctionName = "") { // TODO: running this here because it needs to know which callee Functions are yielding/panicking. new AsyncNodeDecompositionTransform(calleesIsYielding, calleesMayPanic, new NodeInsertionTypeUnificationResultFactory()) .Execute(dfirRoot, cancellationToken); ExecutionOrderSortingVisitor.SortDiagrams(dfirRoot); var asyncStateGrouper = new AsyncStateGrouper(); asyncStateGrouper.Execute(dfirRoot, cancellationToken); IEnumerable <AsyncStateGroup> asyncStateGroups = asyncStateGrouper.GetAsyncStateGroups(); using (var contextWrapper = new LLVM.ContextWrapper()) { var module = contextWrapper.CreateModule("module"); var functionImporter = new LLVM.FunctionImporter(contextWrapper, module); var codeGenExpander = new CodeGenExpander( dfirRoot, new LLVM.FunctionModuleContext(contextWrapper, module, functionImporter), calleesMayPanic); asyncStateGroups.ForEach(codeGenExpander.ExpandAsyncStateGroup); #if DEBUG string prettyPrintAsyncStateGroups = asyncStateGroups.PrettyPrintAsyncStateGroups(); #endif bool isYielding = asyncStateGroups.Select(g => g.FunctionId).Distinct().HasMoreThan(1); bool mayPanic = asyncStateGroups.Any(group => group.StartsWithPanicOrContinue); var variableStorage = new LLVM.FunctionVariableStorage(); var allocator = new Allocator(contextWrapper, variableStorage, asyncStateGroups); allocator.Execute(dfirRoot, cancellationToken); compiledFunctionName = string.IsNullOrEmpty(compiledFunctionName) ? FunctionLLVMName(dfirRoot.CompileSpecification.Name) : compiledFunctionName; var parameterInfos = dfirRoot.DataItems.OrderBy(d => d.ConnectorPaneIndex).Select(ToParameterInfo).ToArray(); var sharedData = new LLVM.FunctionCompilerSharedData( contextWrapper, module, parameterInfos, allocator.AllocationSet, variableStorage, functionImporter); var moduleBuilder = isYielding ? new LLVM.AsynchronousFunctionModuleBuilder(sharedData, compiledFunctionName, asyncStateGroups) : (LLVM.FunctionModuleBuilder) new LLVM.SynchronousFunctionModuleBuilder(sharedData, compiledFunctionName, asyncStateGroups); sharedData.VisitationHandler = new LLVM.FunctionCompiler(moduleBuilder, sharedData, codeGenExpander.ReservedIndexCount); moduleBuilder.CompileFunction(); module.VerifyAndThrowIfInvalid(); return(new LLVM.FunctionCompileResult(new LLVM.ContextFreeModule(module), isYielding, mayPanic)); } }
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 ExecutionContext(IRebarTargetRuntimeServices runtimeServices) { _contextWrapper = new ContextWrapper(); _runtimeServices = runtimeServices; _globalModule = _contextWrapper.CreateModule("global"); foreach (ContextFreeModule module in new[] { CommonModules.FakeDropModule, CommonModules.SchedulerModule, CommonModules.StringModule, CommonModules.OutputModule, CommonModules.RangeModule, CommonModules.FileModule }) { _globalModule.LinkInModule(_contextWrapper.LoadContextFreeModule(module)); } _engine = _globalModule.CreateMCJITCompilerForModule(); _targetData = LLVMSharp.LLVM.GetExecutionEngineTargetData(_engine); }
internal static LLVMTypeRef TranslateParameterType(this ContextWrapper context, NIType parameterType) { // TODO: this should probably share code with how we compute the top function LLVM type above bool isInput = parameterType.GetInputParameterPassingRule() != NIParameterPassingRule.NotAllowed, isOutput = parameterType.GetOutputParameterPassingRule() != NIParameterPassingRule.NotAllowed; LLVMTypeRef parameterLLVMType = context.AsLLVMType(parameterType.GetDataType()); if (isInput) // includes inout parameters { if (isOutput && !parameterType.GetDataType().IsRebarReferenceType()) { throw new InvalidOperationException("Inout parameter with non-reference type"); } return(parameterLLVMType); } if (isOutput) { return(LLVMTypeRef.PointerType(parameterLLVMType, 0u)); } throw new NotImplementedException("Parameter direction is wrong"); }
internal static LLVMTypeRef CreateLLVMSliceIteratorType(this ContextWrapper context, LLVMTypeRef elementType) { return(LLVMTypeRef.StructType(new LLVMTypeRef[] { context.CreateLLVMSliceReferenceType(elementType), context.Int32Type }, false)); }
internal static LLVMTypeRef CreateLLVMYieldPromiseType(this ContextWrapper context, LLVMTypeRef innerType) => context.StructType(new LLVMTypeRef[] { innerType });
public FunctionAllocationSet(ContextWrapper context) { Context = context; }
public static LLVMTypeRef ScheduledTaskFunctionType(this ContextWrapper context) => LLVMTypeRef.FunctionType(context.VoidType, new[] { context.VoidPointerType() }, false);
public static LLVMValueRef NullVoidPointer(this ContextWrapper context) => LLVMSharp.LLVM.ConstPointerNull(context.VoidPointerType());
public static LLVMTypeRef FakeDropType(this ContextWrapper context) => context.StructType( new LLVMTypeRef[] { context.Int32Type });
public static LLVMTypeRef FileHandleType(this ContextWrapper context) => context.StructType( new LLVMTypeRef[] { context.VoidPointerType() });
public static LLVMTypeRef RangeIteratorType(this ContextWrapper context) => context.StructType( new LLVMTypeRef[] { context.Int32Type, context.Int32Type });
public static LLVMTypeRef StringSplitIteratorType(this ContextWrapper context) => context.StructType( new LLVMTypeRef[] { context.StringSliceReferenceType(), context.BytePointerType() });
public static LLVMTypeRef StringType(this ContextWrapper context) => context.StructType( new LLVMTypeRef[] { context.BytePointerType(), context.Int32Type });
public CommonModules(ContextWrapper contextWrapper) { _contextModules = new FunctionMemo <ContextFreeModule, Module>(contextWrapper.LoadContextFreeModule); }
internal static LLVMTypeRef TranslateFunctionType(this ContextWrapper context, NIType functionType) { LLVMTypeRef[] parameterTypes = functionType.GetParameters().Select(context.TranslateParameterType).ToArray(); return(LLVMSharp.LLVM.FunctionType(context.VoidType, parameterTypes, false)); }
// TechDebt: for some of the types below, it would be nicer to return named types, which we can do now that we're // passing around an LLVM context. public static LLVMTypeRef AsLLVMType(this ContextWrapper context, NIType niType) { switch (niType.GetKind()) { case NITypeKind.UInt8: case NITypeKind.Int8: return(context.Int8Type); case NITypeKind.UInt16: case NITypeKind.Int16: return(context.Int16Type); case NITypeKind.UInt32: case NITypeKind.Int32: return(context.Int32Type); case NITypeKind.UInt64: case NITypeKind.Int64: return(context.Int64Type); case NITypeKind.Boolean: return(context.Int1Type); case NITypeKind.String: return(context.StringType()); default: { if (niType.IsRebarReferenceType()) { NIType referentType = niType.GetReferentType(); if (referentType == DataTypes.StringSliceType) { return(context.StringSliceReferenceType()); } NIType sliceElementType; if (referentType.TryDestructureSliceType(out sliceElementType)) { return(context.CreateLLVMSliceReferenceType(context.AsLLVMType(sliceElementType))); } return(LLVMTypeRef.PointerType(context.AsLLVMType(referentType), 0u)); } if (niType.IsCluster()) { LLVMTypeRef[] fieldTypes = niType.GetFields().Select(field => context.AsLLVMType(field.GetDataType())).ToArray(); return(context.StructType(fieldTypes)); } if (niType == DataTypes.FileHandleType) { return(context.FileHandleType()); } if (niType == DataTypes.FakeDropType) { return(context.FakeDropType()); } if (niType == DataTypes.RangeIteratorType) { return(context.RangeIteratorType()); } if (niType == DataTypes.WakerType) { return(context.WakerType()); } NIType innerType; if (niType.TryDestructureOptionType(out innerType)) { return(context.CreateLLVMOptionType(context.AsLLVMType(innerType))); } if (niType.IsStringSplitIteratorType()) { return(context.StringSplitIteratorType()); } if (niType.TryDestructureVectorType(out innerType)) { return(context.CreateLLVMVectorType(context.AsLLVMType(innerType))); } if (niType.TryDestructureSliceIteratorType(out innerType) || niType.TryDestructureSliceMutableIteratorType(out innerType)) { return(context.CreateLLVMSliceIteratorType(context.AsLLVMType(innerType))); } if (niType.TryDestructureSharedType(out innerType)) { return(context.CreateLLVMSharedType(context.AsLLVMType(innerType))); } if (niType.TryDestructureYieldPromiseType(out innerType)) { return(context.CreateLLVMYieldPromiseType(context.AsLLVMType(innerType))); } if (niType.TryDestructureMethodCallPromiseType(out innerType)) { return(context.CreateLLVMMethodCallPromiseType(context.AsLLVMType(innerType))); } if (niType.TryDestructureNotifierReaderType(out innerType)) { return(context.CreateLLVMNotifierReaderType(context.AsLLVMType(innerType))); } if (niType.TryDestructureNotifierReaderPromiseType(out innerType)) { return(context.CreateLLVMNotifierReaderPromiseType(context.AsLLVMType(innerType))); } if (niType.TryDestructureNotifierWriterType(out innerType)) { return(context.CreateLLVMNotifierWriterType(context.AsLLVMType(innerType))); } if (niType.TryDestructurePanicResultType(out innerType)) { return(context.CreateLLVMPanicResultType(context.AsLLVMType(innerType))); } // TODO: when using typedef classes and unions in FunctionCompiler, the LLVM type should // come from a TypeDiagramBuiltPackage. if (niType.IsValueClass() && niType.GetFields().Any()) { LLVMTypeRef[] fieldTypes = niType.GetFields().Select(f => context.AsLLVMType(f.GetDataType())).ToArray(); return(context.StructType(fieldTypes)); } if (niType.IsUnion()) { int maxSize = 4; foreach (NIType field in niType.GetFields()) { // TODO: where possible, use a non-array type that matches the max size LLVMTypeRef llvmFieldType = context.AsLLVMType(field.GetDataType()); int fieldSize = (int)LLVMSharp.LLVM.StoreSizeOfType(LocalTargetInfo.TargetData, llvmFieldType); maxSize = Math.Max(maxSize, fieldSize); } LLVMTypeRef[] structFieldTypes = new LLVMTypeRef[] { context.Int8Type, // TODO: this is incorrect because it does not consider alignment LLVMTypeRef.ArrayType(context.Int8Type, (uint)maxSize) }; return(context.StructType(structFieldTypes)); } throw new NotSupportedException("Unsupported type: " + niType); } } }
internal static LLVMTypeRef CreateLLVMPanicResultType(this ContextWrapper context, LLVMTypeRef innerType) { return(context.StructType(new LLVMTypeRef[] { context.Int1Type, innerType })); }
public static LLVMTypeRef BytePointerType(this ContextWrapper context) => LLVMTypeRef.PointerType(context.Int8Type, 0u);
internal static LLVMTypeRef CreateLLVMSliceReferenceType(this ContextWrapper context, LLVMTypeRef innerType) { return(context.StructType(new LLVMTypeRef[] { LLVMTypeRef.PointerType(innerType, 0u), context.Int32Type })); }
public static LLVMValueRef BuildStringSliceReferenceValue(this ContextWrapper context, IRBuilder builder, LLVMValueRef stringPtr, LLVMValueRef length) { return(builder.BuildSliceReferenceValue(context.StringSliceReferenceType(), stringPtr, length)); }
internal static LLVMTypeRef CreateLLVMSharedType(this ContextWrapper context, LLVMTypeRef innerType) { return(LLVMTypeRef.PointerType(context.CreateLLVMRefCountType(innerType), 0u)); }
public static LLVMTypeRef FunctionCompletionStatusType(ContextWrapper context) => context.Int8Type;
internal static LLVMTypeRef CreateLLVMRefCountType(this ContextWrapper context, LLVMTypeRef innerType) { return(context.StructType(new LLVMTypeRef[] { context.Int32Type, innerType })); }
public FunctionModuleContext(ContextWrapper llvmContext, Module module, FunctionImporter functionImporter) { LLVMContext = llvmContext; Module = module; FunctionImporter = functionImporter; }
public FunctionImporter(ContextWrapper context, Module module) { _commonModules = new CommonModules(context); _module = module; }