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; } }
private ValueRef LoadValue(StackValueType stackType, ValueRef value, InstructionFlags instructionFlags) { // Load value from local (indirect values are kept as pointer) if (stackType == StackValueType.Value) { // Option1: Make a copy // TODO: Optimize stack allocation (reuse alloca slots, with help of FunctionStack) var result = LLVM.BuildAlloca(builderAlloca, LLVM.GetElementType(LLVM.TypeOf(value)), string.Empty); var valueCopy = LLVM.BuildLoad(builder, value, string.Empty); LLVM.BuildStore(builder, valueCopy, result); SetInstructionFlags(valueCopy, instructionFlags); return result; // Option2: Return pointer as is //return value; } else { var result = LLVM.BuildLoad(builder, value, string.Empty); SetInstructionFlags(result, instructionFlags); return result; } }
private void StoreValue(StackValueType stackType, ValueRef value, ValueRef dest, InstructionFlags instructionFlags) { if (stackType == StackValueType.Value) value = LLVM.BuildLoad(builder, value, string.Empty); var store = LLVM.BuildStore(builder, value, dest); SetInstructionFlags(store, instructionFlags); }
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(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); }
private ValueRef SetupVTableConstant(ValueRef @object, Class @class) { return LLVM.ConstInsertValue(@object, @class.GeneratedEETypeRuntimeLLVM, new [] { (uint)ObjectFields.RuntimeTypeInfo }); }
private void GenerateLeave(List<ExceptionHandlerInfo> activeTryHandlers, Instruction targetInstruction, ValueRef endfinallyJumpTarget, BasicBlockRef[] basicBlocks) { // Check if we need to go through a finally handler for (int index = activeTryHandlers.Count - 1; index >= 0; index--) { var exceptionHandler = activeTryHandlers[index]; // Jumping inside that exception clause? if (targetInstruction.Offset >= exceptionHandler.Source.TryStart.Offset && targetInstruction.Offset < exceptionHandler.Source.TryEnd.Offset) break; // Leaving through a finally clause if (exceptionHandler.Source.HandlerType == ExceptionHandlerType.Finally) { // Find or insert index of this instruction var leaveTargetIndex = exceptionHandler.LeaveTargets.IndexOf(targetInstruction); if (leaveTargetIndex == -1) { leaveTargetIndex = exceptionHandler.LeaveTargets.Count; exceptionHandler.LeaveTargets.Add(targetInstruction); } // Update desired jump target LLVM.BuildStore(builder, LLVM.ConstInt(int32Type, (ulong)leaveTargetIndex, false), endfinallyJumpTarget); // Actual jump will be to finally clause targetInstruction = exceptionHandler.Source.HandlerStart; break; } } EmitBr(basicBlocks[targetInstruction.Offset]); }
/// <summary> /// Generates invoke if inside a try block, otherwise a call. /// </summary> /// <param name="functionContext">The function context.</param> /// <param name="function">The function.</param> /// <param name="args">The arguments.</param> /// <returns></returns> private ValueRef GenerateInvoke(FunctionCompilerContext functionContext, ValueRef function, ValueRef[] args) { ValueRef callResult; if (functionContext.LandingPadBlock.Value != IntPtr.Zero) { var nextBlock = LLVM.AppendBasicBlockInContext(context, functionContext.FunctionGlobal, string.Empty); LLVM.MoveBasicBlockAfter(nextBlock, LLVM.GetInsertBlock(builder)); callResult = LLVM.BuildInvoke(builder, function, args, nextBlock, functionContext.LandingPadBlock, string.Empty); LLVM.PositionBuilderAtEnd(builder, nextBlock); functionContext.BasicBlock = nextBlock; } else { callResult = LLVM.BuildCall(builder, function, args, string.Empty); } return callResult; }
private ValueRef ComputeFieldAddress(BuilderRef builder, Field field, StackValueType objectStackType, ValueRef objectValue, ref InstructionFlags instructionFlags) { objectValue = ConvertReferenceToExpectedType(builder, objectStackType, objectValue, field.DeclaringType); Type type = field.DeclaringType; // Build indices for GEP var indices = new List<ValueRef>(3); if (objectStackType == StackValueType.Reference || objectStackType == StackValueType.Object || objectStackType == StackValueType.Value || objectStackType == StackValueType.NativeInt) { // First pointer indirection indices.Add(LLVM.ConstInt(int32LLVM, 0, false)); } bool isCustomLayout = IsCustomLayout(type.TypeDefinitionCecil); if (objectStackType == StackValueType.Object) { // Access data indices.Add(LLVM.ConstInt(int32LLVM, (int)ObjectFields.Data, false)); if (!isCustomLayout) { // For now, go through hierarchy and check that type match // Other options: // - cast // - store class depth (and just do a substraction) int depth = 0; var @class = GetClass(type); while (@class != null) { if (@class.Type == field.DeclaringType) break; @class = @class.BaseType; depth++; } if (@class == null) throw new InvalidOperationException(string.Format("Could not find field {0} in hierarchy of {1}", field.FieldDefinition, type.TypeReferenceCecil)); // Apply GEP indices to find right object (parent is always stored in first element) for (int i = 0; i < depth; ++i) indices.Add(LLVM.ConstInt(int32LLVM, 0, false)); } } // Access the appropriate field indices.Add(LLVM.ConstInt(int32LLVM, (uint)field.StructIndex, false)); // Find field address using GEP var fieldAddress = LLVM.BuildInBoundsGEP(builder, objectValue, indices.ToArray(), string.Empty); // Cast to real field type (if stored in a custom layout array) if (isCustomLayout) { fieldAddress = LLVM.BuildPointerCast(builder, fieldAddress, LLVM.PointerType(field.Type.DefaultTypeLLVM, 0), string.Empty); // Check if non aligned if (field.StructIndex % 4 != 0) instructionFlags = InstructionFlags.Unaligned; } return fieldAddress; }
private ValueRef GenerateMulticastInvokeThunk(Class declaringClass) { // Reuse same signature as Invoke var delegateType = corlib.MainModule.GetType(typeof(Delegate).FullName); var invokeMethod = declaringClass.Functions.Single(x => x.MethodReference.Name == "Invoke"); var invokeMethodHelper = LLVM.AddFunction(module, LLVM.GetValueName(invokeMethod.GeneratedValue) + "_MulticastHelper", invokeMethod.FunctionType); ApplyFunctionAttributes(invokeMethod.Signature, invokeMethodHelper); LLVM.SetLinkage(invokeMethodHelper, declaringClass.Type.Linkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty)); var invokeFunctionType = LLVM.GetElementType(LLVM.TypeOf(invokeMethodHelper)); bool hasRetValue = LLVM.GetReturnType(invokeFunctionType) != LLVM.VoidTypeInContext(context); var delegateArrayType = GetType(new ArrayType(delegateType), TypeState.TypeComplete); // Prepare basic blocks var forCodeBlock = LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty); var exitBlock = LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty); var stack = new FunctionStack(); // Load first argument and cast as Delegate[] var @this = LLVM.GetParam(invokeMethodHelper, 0); @this = LLVM.BuildPointerCast(builder, @this, delegateArrayType.DefaultTypeLLVM, string.Empty); // Create index (i = 0) var locals = new List<StackValue>(); locals.Add(new StackValue(StackValueType.Int32, int32, LLVM.BuildAlloca(builder, int32.DefaultTypeLLVM, "i"))); EmitI4(stack, 0); EmitStloc(stack, locals, 0); // length = invocationList.Length var delegateArray = new StackValue(StackValueType.Object, delegateArrayType, @this); stack.Add(delegateArray); EmitLdlen(stack); EmitConv(stack, Code.Conv_I4); var invocationCount = stack.Pop(); // Iterate over each element in array LLVM.BuildBr(builder, forCodeBlock); LLVM.PositionBuilderAtEnd(builder, forCodeBlock); // Get delegateArray[i] stack.Add(delegateArray); EmitLdloc(stack, locals, 0); EmitLdelem(stack); // Call var helperArgs = new ValueRef[LLVM.CountParams(invokeMethodHelper)]; var thisIndex = invokeMethod.Signature.GetParameterIndexForThis(); helperArgs[thisIndex] = LLVM.BuildPointerCast(builder, stack.Pop().Value, declaringClass.Type.DefaultTypeLLVM, string.Empty); for (int i = 0; i < helperArgs.Length; ++i) { if (i == thisIndex) continue; helperArgs[i] = LLVM.GetParam(invokeMethodHelper, (uint)i); } var retValue = LLVM.BuildCall(builder, invokeMethod.GeneratedValue, helperArgs, string.Empty); ApplyCallAttributes(invokeMethod.Signature, retValue); // i++ EmitLdloc(stack, locals, 0); var lastStack = stack[stack.Count - 1]; var incrementedValue = LLVM.BuildAdd(builder, lastStack.Value, LLVM.ConstInt(int32LLVM, 1, false), string.Empty); lastStack = new StackValue(StackValueType.Int32, int32, incrementedValue); stack[stack.Count - 1] = lastStack; EmitStloc(stack, locals, 0); // if (i < length) // goto forCodeBlock // else // return lastReturnValue; EmitLdloc(stack, locals, 0); stack.Add(invocationCount); EmitConditionalBranch(stack, forCodeBlock, exitBlock, Code.Blt_S); LLVM.PositionBuilderAtEnd(builder, exitBlock); // Return value if (hasRetValue) LLVM.BuildRet(builder, retValue); else LLVM.BuildRetVoid(builder); return invokeMethodHelper; }
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)); } }
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 ValueRef GenerateStaticInvokeThunk(Class declaringClass, TypeDefinition delegateType, FieldDefinition methodPtrAuxField) { // Reuse same signature as Invoke var invokeMethod = declaringClass.Functions.Single(x => x.MethodReference.Name == "Invoke"); // Create method var invokeMethodHelper = LLVM.AddFunction(module, LLVM.GetValueName(invokeMethod.GeneratedValue) + "_Helper", invokeMethod.FunctionType); LLVM.PositionBuilderAtEnd(builder2, LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty)); // Ignore first arguments var helperArgs = new ValueRef[LLVM.CountParams(invokeMethodHelper) - 1]; var helperArgTypes = new TypeRef[helperArgs.Length]; for (int i = 0; i < helperArgs.Length; ++i) { helperArgs[i] = LLVM.GetParam(invokeMethodHelper, (uint) i + 1); helperArgTypes[i] = LLVM.TypeOf(helperArgs[i]); } var helperFunctionType = LLVM.FunctionType(LLVM.GetReturnType(invokeMethod.FunctionType), helperArgTypes, false); // 1. Load static function pointers (arg0->_methodPtrAux) var @this = LLVM.GetParam(invokeMethodHelper, 0); var indices = BuildFieldIndices(GetClass(delegateType).Fields[methodPtrAuxField], StackValueType.Object, GetType(declaringClass.Type.TypeReference)); // Find field address using GEP var fieldAddress = LLVM.BuildInBoundsGEP(builder2, @this, indices, string.Empty); // Load value from field var methodPtrAux = LLVM.BuildLoad(builder2, fieldAddress, string.Empty); methodPtrAux = LLVM.BuildPointerCast(builder2, methodPtrAux, LLVM.PointerType(helperFunctionType, 0), string.Empty); // 2. Call method var methodPtrAuxCall = LLVM.BuildCall(builder2, methodPtrAux, helperArgs, string.Empty); // Return value if (LLVM.GetReturnType(invokeMethod.FunctionType) != LLVM.VoidTypeInContext(context)) LLVM.BuildRet(builder2, methodPtrAuxCall); else LLVM.BuildRetVoid(builder2); return invokeMethodHelper; }
/// <summary> /// Helper function to convert variables from local to stack. /// </summary> /// <param name="local">The local variable.</param> /// <param name="stack">The stack variable.</param> /// <returns></returns> /// <exception cref="System.InvalidOperationException"></exception> /// <exception cref="System.NotImplementedException"></exception> private ValueRef ConvertFromLocalToStack(Type localType, ValueRef stack) { switch (localType.StackType) { case StackValueType.Int32: case StackValueType.Int64: var expectedIntType = localType.StackType == StackValueType.Int32 ? int32LLVM : int64LLVM; if (localType.DefaultTypeLLVM != expectedIntType) { if (LLVM.GetTypeKind(localType.DefaultTypeLLVM) != TypeKind.IntegerTypeKind) throw new InvalidOperationException(); if (LLVM.GetIntTypeWidth(localType.DefaultTypeLLVM) < LLVM.GetIntTypeWidth(expectedIntType)) { if (IsSigned(localType)) return LLVM.BuildIntCast(builder, stack, expectedIntType, string.Empty); return LLVM.BuildUnsignedIntCast(builder, stack, expectedIntType, string.Empty); } } break; case StackValueType.NativeInt: // NativeInt type, no conversion should be needed break; case StackValueType.Value: // Value type, no conversion should be needed break; case StackValueType.Reference: case StackValueType.Object: // TODO: Check type conversions (upcasts, etc...) break; case StackValueType.Float: // Float type, no conversion should be needed break; default: throw new NotImplementedException(); } return stack; }
/// <summary> /// Helper function to convert variables from local to stack. /// </summary> /// <param name="local">The local variable.</param> /// <param name="stack">The stack variable.</param> /// <returns></returns> /// <exception cref="System.InvalidOperationException"></exception> /// <exception cref="System.NotImplementedException"></exception> private ValueRef ConvertFromLocalToStack(Type localType, ValueRef stack) { switch (localType.StackType) { case StackValueType.Int32: case StackValueType.Int64: var expectedIntType = localType.StackType == StackValueType.Int32 ? int32Type : int64Type; if (localType.DefaultType != expectedIntType) { if (LLVM.GetTypeKind(localType.DefaultType) != TypeKind.IntegerTypeKind) throw new InvalidOperationException(); if (LLVM.GetIntTypeWidth(localType.DefaultType) < LLVM.GetIntTypeWidth(expectedIntType)) { // Extend sign if needed // TODO: Need a way to handle unsigned int. Unfortunately it seems that // LLVMBuildIntCast doesn't have CastInst::CreateIntegerCast isSigned parameter. // Probably need to directly create ZExt/SExt. return LLVM.BuildIntCast(builder, stack, expectedIntType, string.Empty); } } break; case StackValueType.NativeInt: // NativeInt type, no conversion should be needed break; case StackValueType.Value: // Value type, no conversion should be needed break; case StackValueType.Reference: case StackValueType.Object: // TODO: Check type conversions (upcasts, etc...) break; case StackValueType.Float: // Float type, no conversion should be needed break; default: throw new NotImplementedException(); } return stack; }
private ValueRef ConvertReferenceToExpectedType(BuilderRef builder, StackValueType stackValueType, ValueRef value, Type type) { var expectedType = stackValueType == StackValueType.Object ? LLVM.PointerType(type.ObjectTypeLLVM, 0) : LLVM.PointerType(type.ValueTypeLLVM, 0); if (LLVM.TypeOf(value) == expectedType) return value; return LLVM.BuildPointerCast(builder, value, expectedType, string.Empty); }
private void EmitStaticInvokeCall(ValueRef invokeMethodHelper) { // Get Delegate type and _methodPtrAux field var delegateType = corlib.MainModule.GetType(typeof(Delegate).FullName); var methodPtrAuxField = delegateType.Fields.First(x => x.Name == "_methodPtrAux"); var invokeFunctionType = LLVM.GetElementType(LLVM.TypeOf(invokeMethodHelper)); // Ignore first arguments var helperArgs = new ValueRef[LLVM.CountParams(invokeMethodHelper) - 1]; var helperArgTypes = new TypeRef[helperArgs.Length]; for (int i = 0; i < helperArgs.Length; ++i) { helperArgs[i] = LLVM.GetParam(invokeMethodHelper, (uint)i + 1); helperArgTypes[i] = LLVM.TypeOf(helperArgs[i]); } var helperFunctionType = LLVM.FunctionType(LLVM.GetReturnType(invokeFunctionType), helperArgTypes, false); // 1. Load static function pointers (arg0->_methodPtrAux) var @this = LLVM.GetParam(invokeMethodHelper, 0); // Compute field address var instructionFlags = InstructionFlags.None; var fieldAddress = ComputeFieldAddress(builder2, GetType(delegateType, TypeState.TypeComplete).Fields[methodPtrAuxField], StackValueType.Object, @this, ref instructionFlags); // Load value from field var methodPtrAux = LLVM.BuildLoad(builder2, fieldAddress, string.Empty); methodPtrAux = LLVM.BuildPointerCast(builder2, methodPtrAux, LLVM.PointerType(helperFunctionType, 0), string.Empty); // 2. Call method var methodPtrAuxCall = LLVM.BuildCall(builder2, methodPtrAux, helperArgs, string.Empty); LLVM.SetTailCall(methodPtrAuxCall, true); // Return value if (LLVM.GetReturnType(invokeFunctionType) != LLVM.VoidTypeInContext(context)) LLVM.BuildRet(builder2, methodPtrAuxCall); else LLVM.BuildRetVoid(builder2); }
private static void SetInstructionFlags(ValueRef instruction, InstructionFlags instructionFlags) { // Set instruction flags (if necessary) if ((instructionFlags & InstructionFlags.Volatile) != 0) LLVM.SetVolatile(instruction, true); if ((instructionFlags & InstructionFlags.Unaligned) != 0) LLVM.SetAlignment(instruction, 1); }
private void EmitDebugVariable(FunctionCompilerContext functionContext, Instruction start, ValueRef generatedScope, StackValue variable, DW_TAG dwarfType, string variableName, int argIndex = 0) { var sequencePoint = start.SequencePoint; var debugType = CreateDebugType(functionContext, variable.Type); // TODO: Detect where variable is actually declared (first use of local?) var debugLocalVariable = LLVM.DIBuilderCreateLocalVariable(debugBuilder, (uint)dwarfType, generatedScope, variableName, functionContext.DebugFile, sequencePoint != null ? (uint)sequencePoint.StartLine : 0, debugType, true, 0, (uint)argIndex); var debugVariableDeclare = LLVM.DIBuilderInsertDeclareAtEnd(debugBuilder, variable.Value, debugLocalVariable, LLVM.GetInsertBlock(builder)); LLVM.SetInstDebugLocation(builder, debugVariableDeclare); }
private ValueRef ConvertToInt(ValueRef value, TypeRef intTypeLLVM) { var valueType = LLVM.TypeOf(value); // NatveInt: cast to integer if (LLVM.GetTypeKind(valueType) == TypeKind.PointerTypeKind) return LLVM.BuildPtrToInt(builder, value, intTypeLLVM, string.Empty); // Integer of different size: cast if (valueType != intTypeLLVM) return LLVM.BuildIntCast(builder, value, intTypeLLVM, string.Empty); // Otherwise, return as is return value; }
private void GenerateComparableOperands(StackValue operand1, StackValue operand2, out ValueRef value1, out ValueRef value2) { value1 = operand1.Value; value2 = operand2.Value; // Downcast objects to typeof(object) so that they are comparables if (operand1.StackType == StackValueType.Object) value1 = ConvertFromStackToLocal(@object, operand1); if (operand2.StackType == StackValueType.Object) value2 = ConvertFromStackToLocal(@object, operand2); if ((operand1.StackType == StackValueType.NativeInt && operand2.StackType != StackValueType.NativeInt) || (operand1.StackType != StackValueType.NativeInt && operand2.StackType == StackValueType.NativeInt)) throw new NotImplementedException("Comparison between native int and int types."); if (operand1.StackType == StackValueType.NativeInt && LLVM.TypeOf(value1) != LLVM.TypeOf(value2)) { // NativeInt types should have same types to be comparable value2 = LLVM.BuildPointerCast(builder, value2, LLVM.TypeOf(value1), string.Empty); } // Different object types: cast everything to object if (operand1.StackType == StackValueType.Object && operand2.StackType == StackValueType.Object && operand1.Type != operand2.Type) { value1 = LLVM.BuildPointerCast(builder, value1, @object.DefaultTypeLLVM, string.Empty); value2 = LLVM.BuildPointerCast(builder, value2, @object.DefaultTypeLLVM, string.Empty); } if (operand1.StackType != operand2.StackType || LLVM.TypeOf(value1) != LLVM.TypeOf(value2)) throw new InvalidOperationException(string.Format("Comparison between operands of different types, {0} and {1}.", operand1.Type, operand2.Type)); }
public void InitializeCommonTypes() { // Load runtime runtimeModule = LoadModule(context, LocateRuntimeModule(triple)); // 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); // 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"); }
private void SetupVTable(ValueRef @object, Class @class) { // Store vtable global into first field of the object var indices = new[] { LLVM.ConstInt(int32LLVM, 0, false), // Pointer indirection LLVM.ConstInt(int32LLVM, (int)ObjectFields.RuntimeTypeInfo, false), // Access RTTI }; var vtablePointer = LLVM.BuildInBoundsGEP(builder, @object, indices, string.Empty); LLVM.BuildStore(builder, @class.GeneratedEETypeRuntimeLLVM, vtablePointer); }
private ValueRef GetDataPointer(ValueRef obj) { // Get data pointer var indices = new[] { LLVM.ConstInt(int32Type, 0, false), // Pointer indirection LLVM.ConstInt(int32Type, (int)ObjectFields.Data, false), // Data }; var dataPointer = LLVM.BuildInBoundsGEP(builder, obj, indices, string.Empty); return dataPointer; }
private void PInvokeEmitGlobals() { // Add ThunkPointers global, which contains the addresses of our thunk functions var thunkPointers = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, 4096), "ThunkPointers"); if (TestMode) { LLVM.SetInitializer(thunkPointers, LLVM.ConstNull(LLVM.GetElementType(LLVM.TypeOf(thunkPointers)))); return; } ValueRef[] thunkPointersData = new ValueRef[PInvokeThunkCount]; for (int i = 0; i < PInvokeThunkCount; ++i) { thunkPointersData[i] = LLVM.AddGlobal(module, LLVM.GetElementType(intPtrLLVM), string.Format("thunk{0}", i)); } LLVM.SetInitializer(thunkPointers, LLVM.ConstArray(intPtrLLVM, thunkPointersData)); // Add TLS variable for storing current thunk ID var thunkCurrentId = LLVM.AddGlobal(module, int32LLVM, "ThunkCurrentId"); LLVM.SetThreadLocal(thunkCurrentId, true); var pinvokeThunks = PInvokeEmitThunks(); LLVM.SetModuleInlineAsm(module, pinvokeThunks.ToString()); }