private ValueRef CreateDebugType(FunctionCompilerContext functionContext, Type type) { var size = LLVM.ABISizeOfType(targetData, type.DefaultType) * 8; var align = LLVM.ABIAlignmentOfType(targetData, type.DefaultType) * 8; switch (type.TypeReference.MetadataType) { case MetadataType.Boolean: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "bool", size, align, (uint)DW_ATE.Boolean)); case MetadataType.SByte: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "sbyte", size, align, (uint)DW_ATE.Signed)); case MetadataType.Byte: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "byte", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int16: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "short", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt16: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "ushort", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int32: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "int", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt32: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "uint", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int64: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "long", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt64: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "ulong", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Single: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "float", size, align, (uint)DW_ATE.Float)); case MetadataType.Double: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "double", size, align, (uint)DW_ATE.Float)); case MetadataType.Char: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "char", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.IntPtr: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "IntPtr", size, align, (uint)DW_ATE.Signed)); case MetadataType.UIntPtr: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "UIntPtr", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Pointer: var elementType = GetType(((PointerType)type.TypeReference).ElementType); return(LLVM.DIBuilderCreatePointerType(debugBuilder, CreateDebugType(functionContext, elementType), size, align, type.TypeReference.Name)); default: // For now, let's have a fallback since lot of types are not supported yet. return(CreateDebugType(functionContext, intPtr)); } }
public DefaultABI(ContextRef context, TargetDataRef targetData) { this.context = context; this.targetData = targetData; var intPtrLLVM = LLVM.PointerType(LLVM.Int8TypeInContext(context), 0); intPtrSize = (int)LLVM.ABISizeOfType(targetData, intPtrLLVM); }
private void ProcessMissingDebugTypes() { // Process missing debug types. // Deferred here to avoid circular issues (when processing fields). while (debugClassesToProcess.Count > 0) { var debugClassToProcess = debugClassesToProcess.Dequeue(); var @class = debugClassToProcess.Key; var debugClass = debugClassToProcess.Value; var type = @class.Type; // Complete members if (type.Fields == null) { continue; } var memberTypes = new List <ValueRef>(type.Fields.Count); foreach (var field in type.Fields) { var fieldType = CreateDebugType(field.Value.Type); var fieldSize = LLVM.ABISizeOfType(targetData, field.Value.Type.DefaultTypeLLVM) * 8; var fieldAlign = LLVM.ABIAlignmentOfType(targetData, field.Value.Type.DefaultTypeLLVM) * 8; var fieldOffset = IsCustomLayout(type.TypeDefinitionCecil) ? (ulong)field.Value.StructIndex * 8 : LLVM.OffsetOfElement(targetData, type.ValueTypeLLVM, (uint)field.Value.StructIndex) * 8; // Add object header (VTable ptr, etc...) if (type.StackType == StackValueType.Object) { fieldOffset += LLVM.OffsetOfElement(targetData, type.ObjectTypeLLVM, (int)ObjectFields.Data) * 8; } memberTypes.Add(LLVM.DIBuilderCreateMemberType(debugBuilder, debugClass, field.Key.Name, ValueRef.Empty, 0, fieldSize, fieldAlign, fieldOffset, 0, fieldType)); } // Update members (mutation) // TODO: LLVM.DICompositeTypeSetTypeArray should take a ref, not out. var oldDebugClass = debugClass; LLVM.DICompositeTypeSetTypeArray(out debugClass, LLVM.DIBuilderGetOrCreateArray(debugBuilder, memberTypes.ToArray())); // debugClass being changed, set it again (old value is not valid anymore) debugClasses[@class] = debugClass; // Same in debugTypeCache (if value type) if (debugTypeCache.ContainsKey(@class.Type) && debugTypeCache[@class.Type] == oldDebugClass) { debugTypeCache[@class.Type] = debugClass; } } }
int GetSize(TypeReference type) { TypeRef dataType; // Try to avoid recursive GetType if possible if (type is PointerType || type is ByReferenceType) { dataType = intPtrLLVM; } else { dataType = GetType(type, TypeState.StackComplete).DefaultTypeLLVM; } return((int)LLVM.ABISizeOfType(targetData, dataType)); }
private ValueRef GetOrCreateDebugClass(Class @class) { ValueRef debugClass; if (debugClasses.TryGetValue(@class, out debugClass)) { return(debugClass); } var type = @class.Type; // Find namespace scope var debugNamespace = GetOrCreateDebugNamespace(type.TypeReferenceCecil.Namespace); // Create debug version of the class var structType = type.StackType == StackValueType.Object ? type.ObjectTypeLLVM : type.ValueTypeLLVM; var size = LLVM.ABISizeOfType(targetData, structType) * 8; var align = LLVM.ABIAlignmentOfType(targetData, structType) * 8; var emptyArray = LLVM.DIBuilderGetOrCreateArray(debugBuilder, new ValueRef[0]); bool isLocal = type.IsLocal; if (isLocal) { var parentClass = @class.BaseType; var parentDebugClass = parentClass != null?GetOrCreateDebugClass(parentClass) : ValueRef.Empty; debugClass = LLVM.DIBuilderCreateClassType(debugBuilder, debugNamespace, type.TypeReferenceCecil.Name, ValueRef.Empty, 0, size, align, 0, 0, parentDebugClass, emptyArray, ValueRef.Empty, ValueRef.Empty, type.TypeReferenceCecil.FullName); } else { debugClass = LLVM.DIBuilderCreateForwardDecl(debugBuilder, (int)DW_TAG.class_type, type.TypeReferenceCecil.Name, debugNamespace, ValueRef.Empty, 0, 0, size, align, type.TypeReferenceCecil.FullName); } debugClasses.Add(@class, debugClass); if (isLocal) { debugClassesToProcess.Enqueue(new KeyValuePair <Class, ValueRef>(@class, debugClass)); } return(debugClass); }
/// <summary> /// Initializes common types. /// </summary> /// <param name="targetData">Target data.</param> /// <param name="compiler">The compiler.</param> public static void Init(TargetDataRef targetData, Compiler compiler) { Int64 = LLVM.Int64Type(); Int32 = LLVM.Int32Type(); Int16 = LLVM.Int16Type(); Int8 = LLVM.Int8Type(); Boolean = LLVM.Int1Type(); String = LLVM.PointerType(LLVM.Int8Type(), 0); Void = LLVM.VoidType(); Float = LLVM.FloatType(); Double = LLVM.DoubleType(); VoidPtr = LLVM.PointerType(LLVM.VoidType(), 0); IntPtrSize = (uint)LLVM.ABISizeOfType(targetData, VoidPtr); NativeIntType = LLVM.IntType(IntPtrSize * 8); mCompiler = compiler; mLookup = compiler.Lookup; }
public ABIParameterInfo GetParameterInfo(Type type) { if (type.StackType == StackValueType.Value) { // Types smaller than register size will be coerced to integer register type var structSize = LLVM.ABISizeOfType(targetData, type.DefaultTypeLLVM); if (structSize <= (ulong)intPtrSize) { return(new ABIParameterInfo(ABIParameterInfoKind.Coerced, LLVM.IntTypeInContext(context, (uint)structSize * 8))); } // Otherwise, fallback to passing by pointer + byval (x86) or direct (x64) if (intPtrSize == 8) { return(new ABIParameterInfo(ABIParameterInfoKind.Direct)); } return(new ABIParameterInfo(ABIParameterInfoKind.Indirect)); } // Other types are passed by value (pointers, int32, int64, float, etc...) return(new ABIParameterInfo(ABIParameterInfoKind.Direct)); }
private ValueRef CreateDebugType(Type type) { ValueRef result; if (debugTypeCache.TryGetValue(type, out result)) { return(result); } ulong size = 0; ulong align = 0; switch (type.TypeReferenceCecil.MetadataType) { case MetadataType.Boolean: case MetadataType.SByte: case MetadataType.Byte: case MetadataType.Int16: case MetadataType.UInt16: case MetadataType.Int32: case MetadataType.UInt32: case MetadataType.Int64: case MetadataType.UInt64: case MetadataType.Single: case MetadataType.Double: case MetadataType.Char: case MetadataType.IntPtr: case MetadataType.UIntPtr: case MetadataType.Pointer: case MetadataType.ByReference: size = LLVM.ABISizeOfType(targetData, type.DefaultTypeLLVM) * 8; align = LLVM.ABIAlignmentOfType(targetData, type.DefaultTypeLLVM) * 8; break; default: break; } switch (type.TypeReferenceCecil.MetadataType) { case MetadataType.Boolean: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "bool", size, align, (uint)DW_ATE.Boolean)); case MetadataType.SByte: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "sbyte", size, align, (uint)DW_ATE.Signed)); case MetadataType.Byte: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "byte", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int16: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "short", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt16: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "ushort", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int32: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "int", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt32: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "uint", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Int64: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "long", size, align, (uint)DW_ATE.Signed)); case MetadataType.UInt64: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "ulong", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.Single: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "float", size, align, (uint)DW_ATE.Float)); case MetadataType.Double: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "double", size, align, (uint)DW_ATE.Float)); case MetadataType.Char: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "char", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.IntPtr: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "IntPtr", size, align, (uint)DW_ATE.Signed)); case MetadataType.UIntPtr: return(LLVM.DIBuilderCreateBasicType(debugBuilder, "UIntPtr", size, align, (uint)DW_ATE.Unsigned)); case MetadataType.ByReference: { var elementType = GetType(((ByReferenceType)type.TypeReferenceCecil).ElementType, TypeState.TypeComplete); return(LLVM.DIBuilderCreatePointerType(debugBuilder, CreateDebugType(elementType), size, align, type.TypeReferenceCecil.Name)); } case MetadataType.Pointer: { var elementType = GetType(((PointerType)type.TypeReferenceCecil).ElementType, TypeState.TypeComplete); return(LLVM.DIBuilderCreatePointerType(debugBuilder, CreateDebugType(elementType), size, align, type.TypeReferenceCecil.Name)); } case MetadataType.Array: case MetadataType.String: case MetadataType.TypedByReference: case MetadataType.GenericInstance: case MetadataType.ValueType: case MetadataType.Class: case MetadataType.Object: { var typeDefinition = GetMethodTypeDefinition(type.TypeReferenceCecil); if (typeDefinition.IsEnum) { var enumDebugType = CreateDebugType(GetType(typeDefinition.GetEnumUnderlyingType(), TypeState.StackComplete)); debugTypeCache.Add(type, enumDebugType); return(enumDebugType); } var debugClass = GetOrCreateDebugClass(GetClass(type)); // Try again from cache, it might have been done through recursion already if (debugTypeCache.TryGetValue(type, out result)) { return(result); } if (!typeDefinition.IsValueType) { size = LLVM.ABISizeOfType(targetData, type.DefaultTypeLLVM) * 8; align = LLVM.ABIAlignmentOfType(targetData, type.DefaultTypeLLVM) * 8; debugClass = LLVM.DIBuilderCreatePointerType(debugBuilder, debugClass, size, align, string.Empty); } debugTypeCache.Add(type, debugClass); return(debugClass); } default: // For now, let's have a fallback since lot of types are not supported yet. return(CreateDebugType(intPtr)); } }
public void InitializeCommonTypes() { // Load runtime runtimeModule = LoadModule(context, @"SharpLang.Runtime.bc"); // Load data layout from runtime var dataLayout = LLVM.GetDataLayout(runtimeModule); targetData = LLVM.CreateTargetData(dataLayout); // Initialize LLVM types intPtrLLVM = LLVM.PointerType(LLVM.Int8TypeInContext(context), 0); int32LLVM = LLVM.Int32TypeInContext(context); int64LLVM = LLVM.Int64TypeInContext(context); intPtrSize = (int)LLVM.ABISizeOfType(targetData, intPtrLLVM); nativeIntLLVM = LLVM.IntTypeInContext(context, (uint)intPtrSize * 8); // Or int64LLVM? // Prepare system types, for easier access intPtr = GetType(corlib.MainModule.GetType(typeof(IntPtr).FullName), TypeState.StackComplete); int8 = GetType(corlib.MainModule.GetType(typeof(sbyte).FullName), TypeState.StackComplete); int16 = GetType(corlib.MainModule.GetType(typeof(short).FullName), TypeState.StackComplete); int32 = GetType(corlib.MainModule.GetType(typeof(int).FullName), TypeState.StackComplete); int64 = GetType(corlib.MainModule.GetType(typeof(long).FullName), TypeState.StackComplete); uint8 = GetType(corlib.MainModule.GetType(typeof(byte).FullName), TypeState.StackComplete); uint16 = GetType(corlib.MainModule.GetType(typeof(ushort).FullName), TypeState.StackComplete); uint32 = GetType(corlib.MainModule.GetType(typeof(uint).FullName), TypeState.StackComplete); uint64 = GetType(corlib.MainModule.GetType(typeof(ulong).FullName), TypeState.StackComplete); @bool = GetType(corlib.MainModule.GetType(typeof(bool).FullName), TypeState.StackComplete); @float = GetType(corlib.MainModule.GetType(typeof(float).FullName), TypeState.StackComplete); @double = GetType(corlib.MainModule.GetType(typeof(double).FullName), TypeState.StackComplete); @char = GetType(corlib.MainModule.GetType(typeof(char).FullName), TypeState.StackComplete); @object = GetType(corlib.MainModule.GetType(typeof(object).FullName), TypeState.StackComplete); @void = GetType(corlib.MainModule.GetType(typeof(void).FullName), TypeState.StackComplete); // struct IMTEntry { i8* interfaceFunctionPtr, i8* functionPtr } imtEntryLLVM = LLVM.StructCreateNamed(context, "IMTEntry"); LLVM.StructSetBody(imtEntryLLVM, new[] { intPtrLLVM, intPtrLLVM }, false); // struct CaughtResultType { i8*, i32 } caughtResultLLVM = LLVM.StructCreateNamed(context, "CaughtResultType"); LLVM.StructSetBody(caughtResultLLVM, new[] { intPtrLLVM, int32LLVM }, false); // Prepare types used to emit metadata and reflection if (!TestMode) { sharpLangTypeType = GetType(corlib.MainModule.GetType("System.SharpLangType"), TypeState.StackComplete); sharpLangModuleType = GetType(corlib.MainModule.GetType("System.SharpLangModule"), TypeState.StackComplete); } else { sharpLangTypeType = intPtr; sharpLangModuleType = intPtr; } // struct TypeDef { SharpLangModule*, i32 } typeDefLLVM = LLVM.StructCreateNamed(context, "TypeDef"); LLVM.StructSetBody(typeDefLLVM, new[] { sharpLangModuleType.DefaultTypeLLVM, int32LLVM }, false); // Import runtime methods allocObjectFunctionLLVM = ImportRuntimeFunction(module, "allocObject"); resolveInterfaceCallFunctionLLVM = ImportRuntimeFunction(module, "resolveInterfaceCall"); isInstInterfaceFunctionLLVM = ImportRuntimeFunction(module, "isInstInterface"); throwExceptionFunctionLLVM = ImportRuntimeFunction(module, "throwException"); sharpPersonalityFunctionLLVM = ImportRuntimeFunction(module, "sharpPersonality"); pinvokeLoadLibraryFunctionLLVM = ImportRuntimeFunction(module, "PInvokeOpenLibrary"); pinvokeGetProcAddressFunctionLLVM = ImportRuntimeFunction(module, "PInvokeGetProcAddress"); }
public ulong ABISizeOfType(Type ty) => LLVM.ABISizeOfType(this.Unwrap(), ty.Unwrap());
private void CompleteType(Type type) { var typeReference = type.TypeReferenceCecil; switch (typeReference.MetadataType) { case MetadataType.Pointer: case MetadataType.ByReference: case MetadataType.RequiredModifier: return; } var valueType = type.ValueTypeLLVM; var typeDefinition = GetMethodTypeDefinition(typeReference); var stackType = type.StackType; // Sometime, GetType might already define DataType (for standard CLR types such as int, enum, string, array, etc...). // In that case, do not process fields. if (type.Fields == null && (LLVM.GetTypeKind(valueType) == TypeKind.StructTypeKind || LLVM.GetTypeKind(valueType) == TypeKind.ArrayTypeKind)) { var fields = new Dictionary <FieldDefinition, Field>(MemberEqualityComparer.Default); // Avoid recursion (need a better way?) type.Fields = fields; var baseType = GetBaseTypeDefinition(typeReference); var parentType = baseType != null?GetType(ResolveGenericsVisitor.Process(typeReference, baseType), TypeState.TypeComplete) : null; // Build actual type data (fields) // Add fields and vtable slots from parent class var fieldTypes = new List <TypeRef>(typeDefinition.Fields.Count + 1); if (parentType != null && stackType == StackValueType.Object) { fieldTypes.Add(parentType.DataTypeLLVM); } // Special cases: Array if (typeReference.MetadataType == MetadataType.Array) { // String: length (native int) + first element pointer var arrayType = (ArrayType)typeReference; var elementType = GetType(arrayType.ElementType, TypeState.StackComplete); fieldTypes.Add(intPtrLLVM); fieldTypes.Add(LLVM.PointerType(elementType.DefaultTypeLLVM, 0)); } else { bool isCustomLayout = IsCustomLayout(typeDefinition); // Do we use a struct or array? int classSize = 0; // Used for sequential layout foreach (var field in typeDefinition.Fields) { if (field.IsStatic) { continue; } var fieldType = GetType(ResolveGenericsVisitor.Process(typeReference, field.FieldType), TypeState.StackComplete); // Compute struct index (that we can use to access the field). Either struct index or array offset. int structIndex; if (!isCustomLayout) { // Default case, if no custom layout (index so that we can use it in GEP) structIndex = fieldTypes.Count; } else if (typeDefinition.IsExplicitLayout) { structIndex = field.Offset; } else if (typeDefinition.IsSequentialLayout) { // Align for next field, according to packing size classSize = (classSize + typeDefinition.PackingSize - 1) & ~(typeDefinition.PackingSize - 1); structIndex = classSize; classSize += (int)LLVM.ABISizeOfType(targetData, fieldType.DefaultTypeLLVM); } else { throw new InvalidOperationException("Invalid class layouting when computing field offsets."); } fields.Add(field, new Field(field, type, fieldType, structIndex)); fieldTypes.Add(fieldType.DefaultTypeLLVM); } } // Set struct (if not custom layout with array type) if (LLVM.GetTypeKind(valueType) == TypeKind.StructTypeKind) { LLVM.StructSetBody(valueType, fieldTypes.ToArray(), false); } } }