Beispiel #1
0
        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;
            }
        }
Beispiel #2
0
        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;
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
 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;
 }
Beispiel #5
0
        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);
        }
Beispiel #6
0
 private ValueRef SetupVTableConstant(ValueRef @object, Class @class)
 {
     return LLVM.ConstInsertValue(@object, @class.GeneratedEETypeRuntimeLLVM, new [] { (uint)ObjectFields.RuntimeTypeInfo });
 }
Beispiel #7
0
        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]);
        }
Beispiel #8
0
        /// <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;
        }
Beispiel #9
0
        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;
        }
Beispiel #11
0
        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);
                    }
                }
            }
        }
Beispiel #14
0
        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;
        }
Beispiel #17
0
        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);
        }
Beispiel #19
0
 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);
 }
Beispiel #20
0
        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);
        }
Beispiel #21
0
        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;
        }
Beispiel #22
0
        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");
        }
Beispiel #24
0
        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);
        }
Beispiel #25
0
        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;
        }
Beispiel #26
0
        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());
        }