Beispiel #1
0
        private void EmitDebugVariable(FunctionCompilerContext functionContext, SequencePoint sequencePoint, DIDescriptor generatedScope, StackValue variable, DW_TAG dwarfType, string variableName, int argIndex = 0)
        {
            var debugType = CreateDebugType(variable.Type);

            // Process fields and other dependent debug types
            ProcessMissingDebugTypes();

            // Read it again in case it was mutated
            debugType = CreateDebugType(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, debugEmptyExpression,
                                                                        LLVM.GetInsertBlock(builder));

            LLVM.SetInstDebugLocation(builder, debugVariableDeclare);
        }
Beispiel #2
0
        /// <summary>
        /// Helper function to convert variables from stack to local
        /// </summary>
        /// <param name="local">The local variable.</param>
        /// <param name="stack">The stack variable.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        private ValueRef ConvertFromStackToLocal(Type localType, StackValue stack)
        {
            var stackValue = stack.Value;

            // Same type, return as is
            if ((stack.StackType == StackValueType.Value ||
                 stack.StackType == StackValueType.NativeInt) &&
                localType.DefaultTypeLLVM == LLVM.TypeOf(stack.Value))
            {
                return(stackValue);
            }

            // NativeInt to NativeInt
            // Need pointer conversion
            if (stack.StackType == StackValueType.NativeInt && localType.StackType == StackValueType.NativeInt)
            {
                return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
            }

            // Int32 to NativeInt
            if (stack.StackType == StackValueType.Int32 && localType.StackType == StackValueType.NativeInt)
            {
                if (intPtrSize == 8)
                {
                    // TODO: SExt (IntPTr) or ZExt (everything else)
                    throw new NotImplementedException();
                }

                return(LLVM.BuildIntToPtr(builder, stackValue, localType.DataTypeLLVM, string.Empty));
            }

            // NativeInt to Reference
            // Used for example when casting+boxing primitive type pointers
            // TODO: Start GC tracking?
            if (stack.StackType == StackValueType.NativeInt && localType.StackType == StackValueType.Reference)
            {
                // Fallback: allow everything for now...
                return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
            }

            // Object: allow upcast as well
            if (stack.StackType == StackValueType.Reference ||
                stack.StackType == StackValueType.Object)
            {
                if (localType.DefaultTypeLLVM == stack.Type.DefaultTypeLLVM)
                {
                    return(stackValue);
                }

                if (localType.TypeReferenceCecil.Resolve().IsInterface)
                {
                    // Interface upcast
                    var stackClass = GetClass(stack.Type);
                    foreach (var @interface in stackClass.Interfaces)
                    {
                        if (MemberEqualityComparer.Default.Equals(@interface.Type.TypeReferenceCecil, localType.TypeReferenceCecil))
                        {
                            return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
                        }
                    }
                }
                else
                {
                    // Class upcast
                    // Check upcast in hierarchy
                    // TODO: we could optimize by storing Depth
                    var stackType = stack.Type.TypeReferenceCecil;
                    while (stackType != null)
                    {
                        if (MemberEqualityComparer.Default.Equals(stackType, localType.TypeReferenceCecil))
                        {
                            // It's an upcast, do LLVM pointer cast
                            return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
                        }

                        stackType = stackType.Resolve().BaseType;
                    }
                }

                // Fallback: allow everything for now...
                return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
            }

            if (stack.StackType == StackValueType.Float && stack.Type == localType)
            {
                return(stackValue);
            }

            // Spec: Storing into locals that hold an integer value smaller than 4 bytes long truncates the value as it moves from the stack to the local variable.
            if ((stack.StackType == StackValueType.Int32 || stack.StackType == StackValueType.Int64) &&
                LLVM.GetTypeKind(localType.DefaultTypeLLVM) == TypeKind.IntegerTypeKind)
            {
                return(LLVM.BuildIntCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty));
            }

            // TODO: Other cases
            throw new NotImplementedException(string.Format("Error converting from {0} to {1}", stack.Type, localType));
        }
Beispiel #3
0
        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);

            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 List <StackValue>();

            // 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)];

            helperArgs[0] = LLVM.BuildPointerCast(builder, stack.Pop().Value, declaringClass.Type.DefaultTypeLLVM, string.Empty);
            for (int i = 1; i < helperArgs.Length; ++i)
            {
                helperArgs[i] = LLVM.GetParam(invokeMethodHelper, (uint)i);
            }
            var retValue = LLVM.BuildCall(builder, invokeMethod.GeneratedValue, helperArgs, string.Empty);

            // 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);
            }

            if (LLVM.VerifyFunction(invokeMethodHelper, VerifierFailureAction.PrintMessageAction))
            {
                throw new InvalidOperationException(string.Format("Verification failed for function {0}", invokeMethodHelper));
            }

            return(invokeMethodHelper);
        }
Beispiel #4
0
        /// <summary>
        /// Helper function to convert variables from stack to local
        /// </summary>
        /// <param name="local">The local variable.</param>
        /// <param name="stack">The stack variable.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        private ValueRef ConvertFromStackToLocal(Type localType, StackValue stack)
        {
            var stackValue = stack.Value;

            // Same type, return as is
            if ((stack.StackType == StackValueType.Value ||
                 stack.StackType == StackValueType.NativeInt) &&
                localType.DefaultType == stack.Type.DefaultType)
            {
                return(stackValue);
            }

            // Object: allow upcast as well
            if (stack.StackType == StackValueType.Object)
            {
                if (localType.DefaultType == stack.Type.DefaultType)
                {
                    return(stackValue);
                }

                if (localType.TypeReference.Resolve().IsInterface)
                {
                    // Interface upcast
                    var stackClass = GetClass(stack.Type.TypeReference);
                    foreach (var @interface in stackClass.Interfaces)
                    {
                        if (MemberEqualityComparer.Default.Equals(@interface.TypeReference, localType.TypeReference))
                        {
                            return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultType, string.Empty));
                        }
                    }
                }
                else
                {
                    // Class upcast
                    // Check upcast in hierarchy
                    // TODO: we could optimize by storing Depth
                    var stackType = stack.Type.TypeReference;
                    while (stackType != null)
                    {
                        if (MemberEqualityComparer.Default.Equals(stackType, localType.TypeReference))
                        {
                            // It's an upcast, do LLVM pointer cast
                            return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultType, string.Empty));
                        }

                        stackType = stackType.Resolve().BaseType;
                    }
                }
            }

            // Spec: Storing into locals that hold an integer value smaller than 4 bytes long truncates the value as it moves from the stack to the local variable.
            if ((stack.StackType == StackValueType.Int32 || stack.StackType == StackValueType.Int64) &&
                LLVM.GetTypeKind(localType.DefaultType) == TypeKind.IntegerTypeKind)
            {
                return(LLVM.BuildIntCast(builder, stackValue, localType.DefaultType, string.Empty));
            }

            // TODO: Other cases
            throw new NotImplementedException();
        }