public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature) { Signature = signature; DeclaringType = declaringType; MethodReference = methodReference; FunctionType = functionType; GeneratedValue = generatedValue; VirtualSlot = -1; MethodDefinition = methodReference.Resolve(); ParameterTypes = signature.ParameterTypes.Select(x => x.Type).ToArray(); // Generate function type when being called from vtable/IMT (if it applies) // If declaring type is a value type, needs to unbox "this" for virtual method if (DeclaringType.TypeDefinitionCecil.IsValueType && (MethodDefinition.Attributes & MethodAttributes.Virtual) != 0) { bool hasStructValueReturn = signature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect; // Create function type with boxed "this" var argumentCount = LLVM.CountParamTypes(FunctionType); var argumentTypes = new TypeRef[argumentCount]; LLVM.GetParamTypes(FunctionType, argumentTypes); // Change first type to boxed "this" var thisIndex = hasStructValueReturn ? 1 : 0; argumentTypes[thisIndex] = LLVM.PointerType(DeclaringType.ObjectTypeLLVM, 0); VirtualFunctionType = LLVM.FunctionType(LLVM.GetReturnType(FunctionType), argumentTypes, LLVM.IsFunctionVarArg(FunctionType)); } else { VirtualFunctionType = FunctionType; } }
public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, Type returnType, Type[] parameterTypes) { Signature = new FunctionSignature(returnType, parameterTypes); DeclaringType = declaringType; MethodReference = methodReference; FunctionType = functionType; GeneratedValue = generatedValue; VirtualSlot = -1; }
private void EmitCall(List <StackValue> stack, FunctionSignature targetMethod, ValueRef overrideMethod) { // Build argument list var targetNumParams = targetMethod.ParameterTypes.Length; var args = new ValueRef[targetNumParams]; for (int index = 0; index < targetNumParams; index++) { // TODO: Casting/implicit conversion? var stackItem = stack[stack.Count - targetNumParams + index]; args[index] = ConvertFromStackToLocal(targetMethod.ParameterTypes[index], stackItem); } // Remove arguments from stack stack.RemoveRange(stack.Count - targetNumParams, targetNumParams); // Invoke method var actualMethod = overrideMethod; var call = LLVM.BuildCall(builder, actualMethod, args, string.Empty); // Mark method as needed (if non-virtual call) if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero) { LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage); } // Push return result on stack if (targetMethod.ReturnType.TypeReference.MetadataType != MetadataType.Void) { // Convert return value from local to stack value var returnValue = ConvertFromLocalToStack(targetMethod.ReturnType, call); // Add value to stack stack.Add(new StackValue(targetMethod.ReturnType.StackType, targetMethod.ReturnType, returnValue)); } }
private void EmitCall(FunctionCompilerContext functionContext, FunctionSignature targetMethod, ValueRef overrideMethod) { var stack = functionContext.Stack; bool hasStructValueReturn = targetMethod.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect; // Build argument list var targetNumParams = targetMethod.ParameterTypes.Length; var args = new ValueRef[targetNumParams + (hasStructValueReturn ? 1 : 0)]; for (int index = 0; index < targetNumParams; index++) { var llvmIndex = index + (hasStructValueReturn ? 1 : 0); var parameterType = targetMethod.ParameterTypes[index]; // TODO: Casting/implicit conversion? var stackItem = stack[stack.Count - targetNumParams + index]; args[llvmIndex] = ConvertFromStackToLocal(parameterType.Type, stackItem); if (stackItem.StackType == StackValueType.Value) { switch (parameterType.ABIParameterInfo.Kind) { case ABIParameterInfoKind.Direct: args[llvmIndex] = LLVM.BuildLoad(builder, args[llvmIndex], string.Empty); break; case ABIParameterInfoKind.Indirect: // Make a copy of indirect aggregate values args[llvmIndex] = LoadValue(stackItem.Type.StackType, args[llvmIndex], InstructionFlags.None); break; case ABIParameterInfoKind.Coerced: // Coerce to integer type args[llvmIndex] = LLVM.BuildPointerCast(builder, args[llvmIndex], LLVM.PointerType(parameterType.ABIParameterInfo.CoerceType, 0), string.Empty); args[llvmIndex] = LLVM.BuildLoad(builder, args[llvmIndex], string.Empty); break; default: throw new ArgumentOutOfRangeException(); } } } // Remove arguments from stack stack.RemoveRange(stack.Count - targetNumParams, targetNumParams); // Prepare return value storage (in case of struct) if (hasStructValueReturn) { // Allocate storage args[0] = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty); } // Invoke method ValueRef callResult; var actualMethod = overrideMethod; callResult = GenerateInvoke(functionContext, actualMethod, args); switch (targetMethod.CallingConvention) { case MethodCallingConvention.StdCall: LLVM.SetInstructionCallConv(callResult, (uint)CallConv.X86StdcallCallConv); break; case MethodCallingConvention.FastCall: LLVM.SetInstructionCallConv(callResult, (uint)CallConv.X86FastcallCallConv); break; } // Mark method as needed (if non-virtual call) if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero) { LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage); } // Push return result on stack if (targetMethod.ReturnType.Type.TypeReferenceCecil.MetadataType != MetadataType.Void) { ValueRef returnValue; if (targetMethod.ReturnType.Type.StackType == StackValueType.Value) { switch (targetMethod.ReturnType.ABIParameterInfo.Kind) { case ABIParameterInfoKind.Direct: returnValue = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty); LLVM.BuildStore(builder, callResult, returnValue); break; case ABIParameterInfoKind.Indirect: returnValue = args[0]; break; case ABIParameterInfoKind.Coerced: returnValue = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty); var returnValueCasted = LLVM.BuildPointerCast(builder, returnValue, LLVM.PointerType(targetMethod.ReturnType.ABIParameterInfo.CoerceType, 0), string.Empty); LLVM.BuildStore(builder, callResult, returnValueCasted); break; default: throw new ArgumentOutOfRangeException(); } } else { returnValue = callResult; } // Convert return value from local to stack value returnValue = ConvertFromLocalToStack(targetMethod.ReturnType.Type, returnValue); // Add value to stack stack.Add(new StackValue(targetMethod.ReturnType.Type.StackType, targetMethod.ReturnType.Type, returnValue)); } // Apply attributes to the call instruction ApplyCallAttributes(targetMethod, callResult); }
public ModuleRef GenerateModule() { LLVM.DIBuilderCreateCompileUnit(debugBuilder, 0x4, // DW_LANG_C_plus_plus "file", "directory", "SharpLang", false, string.Empty, 1, string.Empty); LLVM.AddModuleFlag(module, "Dwarf Version", 4); LLVM.AddModuleFlag(module, "Debug Info Version", LLVM.DIGetDebugMetadataVersion()); // Process methods while (classesToGenerate.Count > 0) { var classToGenerate = classesToGenerate.Dequeue(); if (classToGenerate.IsLocal) { PrepareClassMethods(classToGenerate); } } // Generate code while (methodsToCompile.Count > 0) { var methodToCompile = methodsToCompile.Dequeue(); //Console.WriteLine("Compiling {0}", methodToCompile.Key.FullName); CompileFunction(methodToCompile.Key, methodToCompile.Value); } // Prepare global module constructor var globalCtorSignature = new FunctionSignature(abi, @void, new Type[0], MethodCallingConvention.Default, null); var globalCtorFunctionType = CreateFunctionTypeLLVM(globalCtorSignature); var globalCtor = LLVM.AddFunction(module, "initializeSharpLangModule", globalCtorFunctionType); LLVM.SetLinkage(globalCtor, Linkage.PrivateLinkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, globalCtor, string.Empty)); Function entryPoint = null; if (assembly.EntryPoint != null) functions.TryGetValue(assembly.EntryPoint, out entryPoint); if (!TestMode) { // Emit metadata var metadataBytes = ReadMetadata(assembly.MainModule.FullyQualifiedName); var metadataData = CreateDataConstant(metadataBytes); var metadataGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(metadataData), "metadata"); LLVM.SetInitializer(metadataGlobal, metadataData); LLVM.SetLinkage(metadataGlobal, Linkage.PrivateLinkage); // Use metadata to initialize a SharpLangModule, that will be created at module load time using a global ctor sharpLangModuleType = GetType(corlib.MainModule.GetType("System.SharpLangModule"), TypeState.VTableEmitted); sharpLangTypeType = GetType(corlib.MainModule.GetType("System.SharpLangTypeDefinition"), TypeState.VTableEmitted); // Was only StackComplete until now // Get ctor for SharpLangModule and SharpLangType var moduleCtor = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Resolve().IsConstructor); var registerTypeMethod = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "RegisterType"); var sortTypesMethod = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "SortTypes"); // Initialize SharpLangModule instance: // new SharpLangModule(moduleName, metadataStart, metadataLength) var sharpLangModuleGlobal = metadataPerModule[assembly.MainModule]; var functionContext = new FunctionCompilerContext(globalCtor, globalCtorSignature); functionContext.Stack = new FunctionStack(); functionContext.Stack.Add(new StackValue(StackValueType.Object, sharpLangModuleType, sharpLangModuleGlobal)); functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, metadataGlobal)); functionContext.Stack.Add(new StackValue(StackValueType.Int32, int32, LLVM.ConstInt(int32LLVM, (ulong)metadataBytes.Length, false))); // Setup initial value (note: VTable should be valid) LLVM.SetLinkage(sharpLangModuleGlobal, Linkage.ExternalLinkage); LLVM.SetInitializer(sharpLangModuleGlobal, SetupVTableConstant(LLVM.ConstNull(sharpLangModuleType.ObjectTypeLLVM), sharpLangModuleType.Class)); metadataPerModule[assembly.MainModule] = sharpLangModuleGlobal; EmitCall(functionContext, moduleCtor.Signature, moduleCtor.GeneratedValue); // Register types foreach (var type in types) { var @class = type.Value.Class; // Skip incomplete types if (@class == null || [email protected]) continue; // Skip if no RTTI initializer if (LLVM.GetInitializer(@class.GeneratedEETypeRuntimeLLVM) == ValueRef.Empty) continue; // Skip if interface (fake RTTI pointer) if (type.Value.TypeDefinitionCecil.IsInterface) continue; functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(@class.GeneratedEETypeRuntimeLLVM, intPtrLLVM))); EmitCall(functionContext, registerTypeMethod.Signature, registerTypeMethod.GeneratedValue); } // Register unmanaged delegate callbacks var delegateWrappers = assembly.MainModule.GetType("DelegateWrappers"); if (delegateWrappers != null) { var marshalHelper = GetType(corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper"), TypeState.VTableEmitted); var marshalHelperRegisterDelegateWrapper = marshalHelper.Class.Functions.First(x => x.DeclaringType == marshalHelper && x.MethodReference.Name == "RegisterDelegateWrapper"); foreach (var delegateWrapper in delegateWrappers.Methods) { var method = GetFunction(delegateWrapper); // Determine delegate type from MarshalFunctionAttribute var marshalFunctionAttribute = method.MethodDefinition.CustomAttributes.First(x => x.AttributeType.FullName == "SharpLang.Marshalling.MarshalFunctionAttribute"); var delegateType = GetType((TypeReference)marshalFunctionAttribute.ConstructorArguments[0].Value, TypeState.VTableEmitted); // TODO: Rename those method, and set their linking to linkonce so that it can be merged? // Of course, we would also need to make sure it works when called from external assemblies functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(delegateType.Class.GeneratedEETypeRuntimeLLVM, intPtrLLVM))); EmitLdftn(functionContext.Stack, method); EmitCall(functionContext, marshalHelperRegisterDelegateWrapper.Signature, marshalHelperRegisterDelegateWrapper.GeneratedValue); } } // Sort and remove duplicates after adding all our types // TODO: Somehow sort everything before insertion at compile time? EmitCall(functionContext, sortTypesMethod.Signature, sortTypesMethod.GeneratedValue); LLVM.BuildRetVoid(builder); } else { LLVM.BuildRetVoid(builder); } // Prepare global ctors { var globalCtorType = LLVM.StructTypeInContext(context, new[] { int32LLVM, LLVM.PointerType(globalCtorFunctionType, 0) }, true); var globalCtorsGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(globalCtorType, 1), "llvm.global_ctors"); LLVM.SetLinkage(globalCtorsGlobal, Linkage.AppendingLinkage); LLVM.SetInitializer(globalCtorsGlobal, LLVM.ConstArray(globalCtorType, new [] { LLVM.ConstNamedStruct(globalCtorType, new[] { LLVM.ConstInt(int32LLVM, (ulong)65536, false), globalCtor, })})); } // Emit "main" which will call the assembly entry point (if any) if (entryPoint != null) { var mainFunctionType = LLVM.FunctionType(int32LLVM, new TypeRef[0], false); var mainFunction = LLVM.AddFunction(module, "main", mainFunctionType); LLVM.SetLinkage(mainFunction, Linkage.ExternalLinkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, mainFunction, string.Empty)); var parameters = (entryPoint.ParameterTypes.Length > 0) ? new[] { LLVM.ConstPointerNull(entryPoint.ParameterTypes[0].DefaultTypeLLVM) } : new ValueRef[0]; LLVM.BuildCall(builder, entryPoint.GeneratedValue, parameters, string.Empty); LLVM.BuildRet(builder, LLVM.ConstInt(int32LLVM, 0, false)); // Emit PInvoke Thunks and Globals needed in entry point module PInvokeEmitGlobals(); } LLVM.DIBuilderFinalize(debugBuilder); LLVM.DIBuilderDispose(debugBuilder); LLVM.DisposeBuilder(builder); return module; }
private void EmitCall(FunctionCompilerContext functionContext, FunctionSignature targetMethod, ValueRef overrideMethod) { var stack = functionContext.Stack; // Build argument list var targetNumParams = targetMethod.ParameterTypes.Length; var args = new ValueRef[targetNumParams]; for (int index = 0; index < targetNumParams; index++) { // TODO: Casting/implicit conversion? var stackItem = stack[stack.Count - targetNumParams + index]; args[index] = ConvertFromStackToLocal(targetMethod.ParameterTypes[index], stackItem); } // Remove arguments from stack stack.RemoveRange(stack.Count - targetNumParams, targetNumParams); // Invoke method ValueRef callResult; var actualMethod = overrideMethod; callResult = GenerateInvoke(functionContext, actualMethod, args); // Mark method as needed (if non-virtual call) if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero) { LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage); } // Push return result on stack if (targetMethod.ReturnType.TypeReference.MetadataType != MetadataType.Void) { // Convert return value from local to stack value var returnValue = ConvertFromLocalToStack(targetMethod.ReturnType, callResult); // Add value to stack stack.Add(new StackValue(targetMethod.ReturnType.StackType, targetMethod.ReturnType, returnValue)); } }
public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature) { Signature = signature; DeclaringType = declaringType; MethodReference = methodReference; FunctionType = functionType; GeneratedValue = generatedValue; VirtualSlot = -1; MethodDefinition = methodReference.Resolve(); ParameterTypes = signature.ParameterTypes.Select(x => x.Type).ToArray(); // Generate function type when being called from vtable/IMT (if it applies) // If declaring type is a value type, needs to unbox "this" for virtual method if (DeclaringType.TypeDefinitionCecil.IsValueType && (MethodDefinition.Attributes & MethodAttributes.Virtual) != 0) { bool hasStructValueReturn = signature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect; // Create function type with boxed "this" var argumentCount = LLVM.CountParamTypes(FunctionType); var argumentTypes = new TypeRef[argumentCount]; LLVM.GetParamTypes(FunctionType, argumentTypes); // Change first type to boxed "this" var thisIndex = hasStructValueReturn ? 1 : 0; argumentTypes[thisIndex] = LLVM.PointerType(DeclaringType.ObjectTypeLLVM, 0); VirtualFunctionType = LLVM.FunctionType(LLVM.GetReturnType(FunctionType), argumentTypes, LLVM.IsFunctionVarArg(FunctionType)); } else { VirtualFunctionType = FunctionType; } }
/// <summary> /// Creates the function. /// </summary> /// <param name="method">The method.</param> /// <returns></returns> Function CreateFunction(MethodReference method) { Function function; if (functions.TryGetValue(method, out function)) return function; var resolvedMethod = method.Resolve(); var declaringType = GetType(ResolveGenericsVisitor.Process(method, method.DeclaringType), TypeState.Opaque); // Check if method is only defined in a parent class (can happen in some rare case, i.e. PCL TypeInfo.get_Assembly()). bool hasMatch = MetadataResolver.GetMethod(declaringType.TypeDefinitionCecil.Methods, method.GetElementMethod()) != null; if (resolvedMethod != null && !hasMatch) { var parentType = declaringType.TypeDefinitionCecil.BaseType != null ? ResolveGenericsVisitor.Process(declaringType.TypeReferenceCecil, declaringType.TypeDefinitionCecil.BaseType) : null; if (parentType == null) throw new InvalidOperationException(string.Format("Could not find a matching method in any of the type or its parent for {0}", method)); // Create function with parent type // TODO: Maybe we need to replace generic context with parent type? var parentMethod = method.ChangeDeclaringType(parentType); function = CreateFunction(parentMethod); // Register it so that it can be cached functions.Add(method, function); return function; } var returnType = GetType(ResolveGenericsVisitor.Process(method, method.ReturnType), TypeState.StackComplete); var parameterTypesBuilder = new List<Type>(); if (method.HasThis) { var parameterType = declaringType.TypeReferenceCecil; // Value type uses ByReference type for this if (declaringType.TypeDefinitionCecil.IsValueType) parameterType = parameterType.MakeByReferenceType(); parameterTypesBuilder.Add(GetType(parameterType, TypeState.StackComplete)); } foreach (var parameter in method.Parameters) { parameterTypesBuilder.Add(GetType(ResolveGenericsVisitor.Process(method, parameter.ParameterType), TypeState.StackComplete)); } var parameterTypes = parameterTypesBuilder.ToArray(); // Find calling convention var callingConvention = method.CallingConvention; PInvokeInfo pinvokeInfo = null; if (resolvedMethod != null && resolvedMethod.HasPInvokeInfo) { pinvokeInfo = resolvedMethod.PInvokeInfo; if (resolvedMethod.PInvokeInfo.IsCallConvStdCall || resolvedMethod.PInvokeInfo.IsCallConvWinapi) callingConvention = MethodCallingConvention.StdCall; else if (resolvedMethod.PInvokeInfo.IsCallConvFastcall) callingConvention = MethodCallingConvention.FastCall; } var functionSignature = new FunctionSignature(abi, returnType, parameterTypes, callingConvention, pinvokeInfo); var functionType = CreateFunctionTypeLLVM(functionSignature); // If we have an external with generic parameters, let's try to do some generic sharing (we can write only one in C++) bool isInternal = resolvedMethod != null && ((resolvedMethod.ImplAttributes & MethodImplAttributes.InternalCall) != 0); if (isInternal && resolvedMethod.HasGenericParameters && resolvedMethod.GenericParameters.All(x => x.HasReferenceTypeConstraint)) { // Check if this isn't the shareable method (in which case we should do normal processing) if (!((GenericInstanceMethod)method).GenericArguments.All(x => MemberEqualityComparer.Default.Equals(x, @object.TypeReferenceCecil))) { // Let's share it with default method var sharedGenericInstance = new GenericInstanceMethod(resolvedMethod); foreach (var genericParameter in resolvedMethod.GenericParameters) { sharedGenericInstance.GenericArguments.Add(@object.TypeReferenceCecil); } var sharedMethod = GetFunction(sharedGenericInstance); // Cast shared function to appropriate pointer type var sharedFunctionGlobal = LLVM.ConstPointerCast(sharedMethod.GeneratedValue, LLVM.PointerType(functionType, 0)); function = new Function(declaringType, method, functionType, sharedFunctionGlobal, functionSignature); functions.Add(method, function); return function; } } // Determine if type and function is local, and linkage type bool isLocal; var linkageType = GetLinkageType(method.DeclaringType, out isLocal); if (isInternal) { // Should be switched to non-weak when we have complete implementation of every internal calls linkageType = Linkage.ExternalWeakLinkage; } else if (resolvedMethod != null && resolvedMethod.HasGenericParameters) { isLocal = true; linkageType = Linkage.LinkOnceAnyLinkage; } bool isRuntime = resolvedMethod != null && ((resolvedMethod.ImplAttributes & MethodImplAttributes.Runtime) != 0); bool isInterfaceMethod = declaringType.TypeDefinitionCecil.IsInterface; var hasDefinition = resolvedMethod != null && (resolvedMethod.HasBody || isInternal || isRuntime); var methodMangledName = Regex.Replace(method.MangledName(), @"(\W)", "_"); var functionGlobal = hasDefinition ? LLVM.AddFunction(module, methodMangledName, functionType) : LLVM.ConstPointerNull(LLVM.PointerType(functionType, 0)); // Interface method uses a global so that we can have a unique pointer to use as IMT key if (isInterfaceMethod) { // For test code only: Use linkonce instead of linkageType so that we know if type was forced if (TestMode) { isLocal = true; linkageType = Linkage.LinkOnceAnyLinkage; } functionGlobal = LLVM.AddGlobal(module, LLVM.Int8TypeInContext(context), methodMangledName); if (isLocal) LLVM.SetInitializer(functionGlobal, LLVM.ConstNull(LLVM.Int8TypeInContext(context))); LLVM.SetLinkage(functionGlobal, linkageType); } if (hasDefinition) { ApplyFunctionAttributes(functionSignature, functionGlobal); } function = new Function(declaringType, method, functionType, functionGlobal, functionSignature); functions.Add(method, function); if (hasDefinition) { switch (callingConvention) { case MethodCallingConvention.StdCall: LLVM.SetFunctionCallConv(functionGlobal, (uint)CallConv.X86StdcallCallConv); break; case MethodCallingConvention.FastCall: LLVM.SetFunctionCallConv(functionGlobal, (uint)CallConv.X86FastcallCallConv); break; } if (isLocal && !isInternal) { // Need to compile EmitFunction(function); } // Apply linkage LLVM.SetLinkage(functionGlobal, linkageType); } return function; }
private void ApplyCallAttributes(FunctionSignature functionSignature, ValueRef functionGlobal) { // Internally, ApplyFunctionAttributes can also handle call/invoke (this might be split later) ApplyFunctionAttributes(functionSignature, functionGlobal); }
private void ApplyFunctionAttributes(FunctionSignature functionSignature, ValueRef functionGlobal) { // Apply parameter attributes var hasStructValueReturn = functionSignature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect; // Detect whether it's a function global or a call instruction var isCallInst = LLVM.IsACallInst(functionGlobal) != ValueRef.Empty || LLVM.IsAInvokeInst(functionGlobal) != ValueRef.Empty; // Apply sret attribute on struct return value if (hasStructValueReturn) { if (isCallInst) { LLVM.AddInstrAttribute(functionGlobal, 1, Attribute.StructRetAttribute); } else { var arg = LLVM.GetParam(functionGlobal, 0); LLVM.AddAttribute(arg, Attribute.StructRetAttribute); } } // Apply byval attribute on struct value parameters for (int index = 0; index < functionSignature.ParameterTypes.Length; index++) { var llvmIndex = index + (hasStructValueReturn ? 1 : 0); var parameterType = functionSignature.ParameterTypes[index]; if (parameterType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect) { if (isCallInst) { LLVM.AddInstrAttribute(functionGlobal, (uint)(llvmIndex + 1), Attribute.ByValAttribute); } else { var arg = LLVM.GetParam(functionGlobal, (uint)llvmIndex); LLVM.AddAttribute(arg, Attribute.ByValAttribute); } } } }
private TypeRef CreateFunctionTypeLLVM(FunctionSignature functionSignature) { // Some extra arguments might be preprended: // - Return value pointer if struct returned by value // - "this" if a class bool hasStructValueReturn = functionSignature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect; var numParams = functionSignature.ParameterTypes.Length; var firstArgumentIndex = 0; if (hasStructValueReturn) firstArgumentIndex++; var parameterTypesLLVM = new TypeRef[numParams + (hasStructValueReturn ? 1 : 0)]; for (int index = 0; index < parameterTypesLLVM.Length; index++) { FunctionParameterType parameterType; if (hasStructValueReturn && index == 0) { parameterType = functionSignature.ReturnType; } else { parameterType = functionSignature.ParameterTypes[index - firstArgumentIndex]; } if (parameterType.Type.DefaultTypeLLVM.Value == IntPtr.Zero) throw new InvalidOperationException(); parameterTypesLLVM[index] = GetFunctionInputParameterTypeLLVM(parameterType); } return LLVM.FunctionType(hasStructValueReturn ? LLVM.VoidTypeInContext(context) : GetFunctionInputParameterTypeLLVM(functionSignature.ReturnType), parameterTypesLLVM, false); }
public ModuleRef GenerateModule() { LLVM.DIBuilderCreateCompileUnit(debugBuilder, 0x4, // DW_LANG_C_plus_plus "file", "directory", "SharpLang", false, string.Empty, 1, string.Empty); LLVM.AddModuleFlag(module, "Dwarf Version", 4); LLVM.AddModuleFlag(module, "Debug Info Version", LLVM.DIGetDebugMetadataVersion()); // Process methods while (classesToGenerate.Count > 0) { var classToGenerate = classesToGenerate.Dequeue(); if (classToGenerate.IsLocal) { PrepareClassMethods(classToGenerate); } } // Generate code while (methodsToCompile.Count > 0) { var methodToCompile = methodsToCompile.Dequeue(); //Console.WriteLine("Compiling {0}", methodToCompile.Key.FullName); CompileFunction(methodToCompile.Key, methodToCompile.Value); } // Prepare global module constructor var globalCtorSignature = new FunctionSignature(abi, @void, new Type[0], MethodCallingConvention.Default, null); var globalCtorFunctionType = CreateFunctionTypeLLVM(globalCtorSignature); var globalCtor = LLVM.AddFunction(module, "initializeSharpLangModule", globalCtorFunctionType); LLVM.SetLinkage(globalCtor, Linkage.PrivateLinkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, globalCtor, string.Empty)); Function entryPoint = null; if (assembly.EntryPoint != null) { functions.TryGetValue(assembly.EntryPoint, out entryPoint); } if (!TestMode) { // Emit metadata var metadataBytes = ReadMetadata(assembly.MainModule.FullyQualifiedName); var metadataData = CreateDataConstant(metadataBytes); var metadataGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(metadataData), "metadata"); LLVM.SetInitializer(metadataGlobal, metadataData); LLVM.SetLinkage(metadataGlobal, Linkage.PrivateLinkage); // Use metadata to initialize a SharpLangModule, that will be created at module load time using a global ctor sharpLangModuleType = GetType(corlib.MainModule.GetType("System.SharpLangModule"), TypeState.VTableEmitted); sharpLangTypeType = GetType(corlib.MainModule.GetType("System.SharpLangTypeDefinition"), TypeState.VTableEmitted); // Was only StackComplete until now // Get ctor for SharpLangModule and SharpLangType var moduleCtor = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Resolve().IsConstructor); var registerTypeMethod = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "RegisterType"); var sortTypesMethod = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "SortTypes"); // Initialize SharpLangModule instance: // new SharpLangModule(moduleName, metadataStart, metadataLength) var sharpLangModuleGlobal = metadataPerModule[assembly.MainModule]; var functionContext = new FunctionCompilerContext(globalCtor, globalCtorSignature); functionContext.Stack = new FunctionStack(); functionContext.Stack.Add(new StackValue(StackValueType.Object, sharpLangModuleType, sharpLangModuleGlobal)); functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, metadataGlobal)); functionContext.Stack.Add(new StackValue(StackValueType.Int32, int32, LLVM.ConstInt(int32LLVM, (ulong)metadataBytes.Length, false))); // Setup initial value (note: VTable should be valid) LLVM.SetLinkage(sharpLangModuleGlobal, Linkage.ExternalLinkage); LLVM.SetInitializer(sharpLangModuleGlobal, SetupVTableConstant(LLVM.ConstNull(sharpLangModuleType.ObjectTypeLLVM), sharpLangModuleType.Class)); metadataPerModule[assembly.MainModule] = sharpLangModuleGlobal; EmitCall(functionContext, moduleCtor.Signature, moduleCtor.GeneratedValue); // Register types foreach (var type in types) { var @class = type.Value.Class; // Skip incomplete types if (@class == null || [email protected]) { continue; } // Skip if no RTTI initializer if (LLVM.GetInitializer(@class.GeneratedEETypeRuntimeLLVM) == ValueRef.Empty) { continue; } // Skip if interface (fake RTTI pointer) if (type.Value.TypeDefinitionCecil.IsInterface) { continue; } functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(@class.GeneratedEETypeRuntimeLLVM, intPtrLLVM))); EmitCall(functionContext, registerTypeMethod.Signature, registerTypeMethod.GeneratedValue); } // Register unmanaged delegate callbacks var delegateWrappers = assembly.MainModule.GetType("DelegateWrappers"); if (delegateWrappers != null) { var marshalHelper = GetType(corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper"), TypeState.VTableEmitted); var marshalHelperRegisterDelegateWrapper = marshalHelper.Class.Functions.First(x => x.DeclaringType == marshalHelper && x.MethodReference.Name == "RegisterDelegateWrapper"); foreach (var delegateWrapper in delegateWrappers.Methods) { var method = GetFunction(delegateWrapper); // Determine delegate type from MarshalFunctionAttribute var marshalFunctionAttribute = method.MethodDefinition.CustomAttributes.First(x => x.AttributeType.FullName == "SharpLang.Marshalling.MarshalFunctionAttribute"); var delegateType = GetType((TypeReference)marshalFunctionAttribute.ConstructorArguments[0].Value, TypeState.VTableEmitted); // TODO: Rename those method, and set their linking to linkonce so that it can be merged? // Of course, we would also need to make sure it works when called from external assemblies functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(delegateType.Class.GeneratedEETypeRuntimeLLVM, intPtrLLVM))); EmitLdftn(functionContext.Stack, method); EmitCall(functionContext, marshalHelperRegisterDelegateWrapper.Signature, marshalHelperRegisterDelegateWrapper.GeneratedValue); } } // Sort and remove duplicates after adding all our types // TODO: Somehow sort everything before insertion at compile time? EmitCall(functionContext, sortTypesMethod.Signature, sortTypesMethod.GeneratedValue); LLVM.BuildRetVoid(builder); } else { LLVM.BuildRetVoid(builder); } // Prepare global ctors { var globalCtorType = LLVM.StructTypeInContext(context, new[] { int32LLVM, LLVM.PointerType(globalCtorFunctionType, 0) }, true); var globalCtorsGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(globalCtorType, 1), "llvm.global_ctors"); LLVM.SetLinkage(globalCtorsGlobal, Linkage.AppendingLinkage); LLVM.SetInitializer(globalCtorsGlobal, LLVM.ConstArray(globalCtorType, new [] { LLVM.ConstNamedStruct(globalCtorType, new[] { LLVM.ConstInt(int32LLVM, (ulong)65536, false), globalCtor, }) })); } // Emit "main" which will call the assembly entry point (if any) if (entryPoint != null) { var mainFunctionType = LLVM.FunctionType(int32LLVM, new TypeRef[0], false); var mainFunction = LLVM.AddFunction(module, "main", mainFunctionType); LLVM.SetLinkage(mainFunction, Linkage.ExternalLinkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, mainFunction, string.Empty)); var parameters = (entryPoint.ParameterTypes.Length > 0) ? new[] { LLVM.ConstPointerNull(entryPoint.ParameterTypes[0].DefaultTypeLLVM) } : new ValueRef[0]; LLVM.BuildCall(builder, entryPoint.GeneratedValue, parameters, string.Empty); LLVM.BuildRet(builder, LLVM.ConstInt(int32LLVM, 0, false)); // Emit PInvoke Thunks and Globals needed in entry point module PInvokeEmitGlobals(); } LLVM.DIBuilderFinalize(debugBuilder); LLVM.DIBuilderDispose(debugBuilder); LLVM.DisposeBuilder(builder); return(module); }
public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature) { Signature = signature; DeclaringType = declaringType; MethodReference = methodReference; FunctionType = functionType; GeneratedValue = generatedValue; VirtualSlot = -1; }
public FunctionCompilerContext(ValueRef functionGlobal, FunctionSignature signature) { FunctionGlobal = functionGlobal; FlowingNextInstructionMode = FlowingNextInstructionMode.Implicit; Signature = signature; }