Example #1
0
        /// <summary>
        /// Emits a stfld instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            StackElement   value = context.CurrentStack.Pop();
            StackElement   obj   = context.CurrentStack.Pop();
            FieldReference field = (FieldReference)instruction.Operand;

            uint index = context.Compiler.Lookup.GetFieldIndex(field);

            ValueRef ptr = LLVM.BuildInBoundsGEP(builder, obj.Value, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false), LLVM.ConstInt(TypeHelper.Int32, index, false) }, "field");

            // Possible cast needed.
            TypeRef destType = TypeHelper.GetTypeRefFromType(field.FieldType);

            if (value.Type != destType)
            {
                CastHelper.HelpIntAndPtrCast(builder, ref value.Value, ref value.Type, destType, "stfldcast");
            }

            ValueRef store = LLVM.BuildStore(builder, value.Value, ptr);

            if (instruction.HasPrefix(Code.Volatile))
            {
                LLVM.SetVolatile(store, true);
            }
        }
Example #2
0
        /// <summary>
        /// Emits a Ldind instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            Code         code    = instruction.OpCode.Code;
            StackElement pointer = context.CurrentStack.Pop();

            ValueRef ptr     = pointer.Value;
            TypeRef  ptrType = LLVM.PointerType(TypeHelper.GetTypeRefFromStOrLdind(code), 0);

            if (pointer.Type != ptrType)
            {
                CastHelper.HelpIntAndPtrCast(builder, ref ptr, ref pointer.Type, ptrType, "ldindcast");
            }

            ValueRef res = LLVM.BuildLoad(builder, ptr, "elem");

            // Some need to be pushed as an int32 on the stack.
            if (code == Code.Ldind_I1 || code == Code.Ldind_I2 || code == Code.Ldind_I4 ||
                code == Code.Ldind_U1 || code == Code.Ldind_U2 || code == Code.Ldind_U4)
            {
                res = LLVM.BuildIntCast(builder, res, TypeHelper.Int32, "tmp");
            }

            TypeRef type = LLVM.TypeOf(res);

            context.CurrentStack.Push(new StackElement(res, TypeHelper.GetBasicTypeFromTypeRef(type), type));
        }
Example #3
0
        /// <summary>
        /// Emits a stloc instruction
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            Code code = instruction.OpCode.Code;

            int index;

            if (code >= Code.Stloc_0 && code <= Code.Stloc_3)
            {
                index = instruction.OpCode.Code - Code.Stloc_0;
            }
            else
            {
                VariableDefinition def = (VariableDefinition)instruction.Operand;
                index = def.Index;
            }

            StackElement element  = context.CurrentStack.Pop();
            ValueRef     data     = element.Value;
            TypeRef      destType = context.LocalTypes[index];

            // Possible cast needed.
            if (element.Type != destType)
            {
                CastHelper.HelpIntAndPtrCast(builder, ref data, ref element.Type, destType, "stloccast");
            }

            LLVM.BuildStore(builder, data, context.LocalValues[index]);
        }
Example #4
0
        /// <summary>
        /// Emits an initobj instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            StackElement  valueTypeAddress = context.CurrentStack.Pop();
            TypeReference type             = (TypeReference)instruction.Operand;
            TypeRef       typeRef          = context.Compiler.Lookup.GetTypeRef(type);

            // We clear this using memset.
            CastHelper.HelpIntAndPtrCast(builder, ref valueTypeAddress.Value, ref valueTypeAddress.Type, TypeHelper.VoidPtr, "initobjcast");
            LLVM.BuildCall(builder, RuntimeHelper.Memset, new ValueRef[] { valueTypeAddress.Value, LLVM.ConstNull(TypeHelper.Int32), LLVM.SizeOf(typeRef) }, string.Empty);
        }
Example #5
0
        /// <summary>
        /// Emits a newobj instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            MethodReference ctor    = (MethodReference)instruction.Operand;
            TypeDefinition  objType = ctor.DeclaringType.Resolve();
            TypeRef         type    = TypeHelper.GetTypeRefFromType(ctor.DeclaringType);

            ValueRef objPtr;
            bool     ptr = (objType.IsClass && !objType.IsValueType);

            if (ptr)
            {
                // This type is a class, therefor we have a specialised "newobj" method.
                objPtr = LLVM.BuildCall(builder, context.Compiler.Lookup.GetNewobjMethod(ctor.DeclaringType.Resolve()), new ValueRef[0], "newobj");
            }
            else
            {
                // Not a class, allocate on stack.
                objPtr = LLVM.BuildAlloca(builder, type, "newobj");
            }

            // Constructor.
            ValueRef?ctorFunc = context.Compiler.Lookup.GetFunction(NameHelper.CreateMethodName(ctor));

            if (!ctorFunc.HasValue)
            {
                throw new Exception("Constructor not found: " + ctor);
            }

            // Get .ctor parameters.
            int paramCount = 1 + ctor.Parameters.Count;

            ValueRef[] values = new ValueRef[paramCount];
            values[0] = objPtr;
            for (int i = paramCount - 1; i >= 1; i--)
            {
                StackElement element = context.CurrentStack.Pop();
                values[i] = element.Value;

                // Cast needed?
                TypeRef paramType = TypeHelper.GetTypeRefFromType(ctor.Parameters[i - 1].ParameterType);
                if (element.Type != paramType)
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref values[i], ref element.Type, paramType, "ctorcallcast");
                }
            }

            // Call .ctor.
            LLVM.BuildCall(builder, ctorFunc.Value, values, string.Empty);

            // Load and push object on stack.
            ValueRef obj = (ptr) ? objPtr : LLVM.BuildLoad(builder, objPtr, "obj");

            context.CurrentStack.Push(new StackElement(obj, ctor.DeclaringType, type));
        }
Example #6
0
        /// <summary>
        /// Emits a starg instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            StackElement value = context.CurrentStack.Pop();

            ParameterDefinition def = (ParameterDefinition)instruction.Operand;
            int index = def.Index;

            ValueRef arg = context.ArgumentValues[index];

            CastHelper.HelpIntAndPtrCast(builder, ref value.Value, ref value.Type, TypeHelper.GetTypeRefFromType(context.ArgumentILTypes[index]), "stargcast");
            LLVM.BuildStore(builder, value.Value, arg);
        }
Example #7
0
        /// <summary>
        /// Emits a stsfld instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            bool isCctor = (context.Method.Name == ".cctor");

            StackElement data = context.CurrentStack.Pop();

            FieldReference field      = (FieldReference)instruction.Operand;
            TypeReference  fieldType  = field.FieldType;
            ValueRef       fieldValue = context.Compiler.Lookup.GetStaticField(field);

            // Possible cast needed.
            TypeRef destType = TypeHelper.GetTypeRefFromType(field.FieldType);

            if (data.Type != destType)
            {
                CastHelper.HelpIntAndPtrCast(builder, ref data.Value, ref data.Type, destType, "stsfldcast");
            }

            string[] useInitializer =
            {
                "System.Byte",
                "System.SByte",
                "System.Int16",
                "System.Int32",
                "System.Int64",
                "System.UInt16",
                "System.UInt32",
                "System.UInt64",
                "System.Single",
                "System.Double",
                "System.Boolean",
                "System.String"
            };

            // If we're in a cctor and it is a number or string, we can just set the initializer.
            if (isCctor && useInitializer.Contains(fieldType.FullName))
            {
                LLVM.SetInitializer(fieldValue, data.Value);
            }
            else
            {
                ValueRef store = LLVM.BuildStore(builder, data.Value, fieldValue);
                if (instruction.HasPrefix(Code.Volatile))
                {
                    LLVM.SetVolatile(store, true);
                }
            }
        }
Example #8
0
        /// <summary>
        /// Emits a ret instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            TypeReference returnType = context.Method.ReturnType;

            if (returnType.MetadataType == MetadataType.Void)
            {
                LLVM.BuildRetVoid(builder);
            }
            else
            {
                StackElement element       = context.CurrentStack.Pop();
                TypeRef      returnTypeRef = TypeHelper.GetTypeRefFromType(returnType);

                if (element.Type != returnTypeRef)
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref element.Value, ref element.Type, returnTypeRef, "retcast");
                }

                LLVM.BuildRet(builder, element.Value);
            }
        }
Example #9
0
        /// <summary>
        /// Emits a stelem instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            StackElement value = context.CurrentStack.Pop();
            StackElement index = context.CurrentStack.Pop();
            StackElement array = context.CurrentStack.Pop();

            // Convert to "pointer to value type" type.
            if (array.Type == TypeHelper.VoidPtr)
            {
                TypeRef destType = TypeHelper.GetTypeRefFromStelem(instruction.OpCode.Code);
                TypeRef ptrType  = LLVM.PointerType(destType, 0);
                array.Value = LLVM.BuildPointerCast(builder, array.Value, ptrType, "tmp");
                array.Type  = ptrType;
            }

            TypeRef elementType = TypeHelper.GetTypeRefFromType(array.ILType.GetElementType());

            ValueRef ptr = LLVM.BuildGEP(builder, array.Value, new ValueRef[] { index.Value }, "arrayptr");

            CastHelper.HelpIntAndPtrCast(builder, ref value.Value, ref value.Type, elementType, "stelemcast");
            LLVM.BuildStore(builder, value.Value, ptr);
        }
Example #10
0
        /// <summary>
        /// Emits a callvirt instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            MethodReference methodRef        = (MethodReference)instruction.Operand;
            TypeRef         returnType       = TypeHelper.GetTypeRefFromType(methodRef.ReturnType);
            Lookup          lookup           = context.Compiler.Lookup;
            bool            needsVirtualCall = lookup.NeedsVirtualCall(methodRef.DeclaringType);

            // Build parameter value and types arrays.
            int paramCount = 1 + methodRef.Parameters.Count;

            // Get the method, if it is null, create a new empty one, otherwise reference it.
            string   methodName = NameHelper.CreateMethodName(methodRef);
            ValueRef?func       = lookup.GetFunction(methodName);

            // Process arguments.
            // Note: backwards for loop because stack is backwards!
            ValueRef[] argVals    = new ValueRef[paramCount];
            TypeRef[]  paramTypes = new TypeRef[paramCount];
            for (int i = paramCount - 1; i >= 0; i--)
            {
                TypeReference type;
                StackElement  element = context.CurrentStack.Pop();
                argVals[i] = element.Value;

                // Get type of parameter.
                if (i == 0)
                {
                    type = methodRef.DeclaringType;
                }
                else
                {
                    type = methodRef.Parameters[i - 1].ParameterType;
                }

                paramTypes[i] = TypeHelper.GetTypeRefFromType(type);
                if (type.IsValueType && i == 0)
                {
                    paramTypes[i] = LLVM.PointerType(paramTypes[i], 0);
                }

                // Cast needed?
                if (element.Type != paramTypes[i])
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref argVals[i], ref element.Type, paramTypes[i], "callvirtcast");
                }
            }

            // Function does not exist, create a declaration for the function.
            TypeRef functionType = LLVM.FunctionType(returnType, paramTypes, false);

            if (!func.HasValue)
            {
                func = LLVM.AddFunction(context.Compiler.Module, methodName, functionType);
                context.Compiler.Lookup.AddFunction(methodName, func.Value);
            }

            // Call.
            ValueRef method;

            if (needsVirtualCall && !lookup.IsMethodUnique(methodRef))
            {
                // We need a virtual call.
                TypeDefinition methodParent = methodRef.DeclaringType.Resolve();
                TypeRef        funcPtrType  = LLVM.PointerType(functionType, 0);
                VTable         vTable       = lookup.GetVTable(methodParent);
                ValueRef       methodGep;

                // Two cases:
                // 1) The parent of the method is an interface.
                //    In this case, we need to first get the VTable from the indirection table.
                // 2) The parent of the method is a class.
                //    In this case, we can directly now the offset to the VTable from the object pointer.

                if (!methodParent.IsInterface)
                {
                    uint     index          = lookup.GetClassVTableIndex(methodParent);
                    ValueRef vTableGep      = LLVM.BuildInBoundsGEP(builder, argVals[0], new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false), LLVM.ConstInt(TypeHelper.Int32, index, false) }, "vtablegep");
                    ValueRef vTableInstance = LLVM.BuildLoad(builder, vTableGep, "vtable");
                    methodGep = LLVM.BuildInBoundsGEP(builder, vTableInstance, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false), LLVM.ConstInt(TypeHelper.Int32, (uint)vTable.GetMethodIndex(methodParent, methodRef), false) }, "methodgep");
                }
                else
                {
                    uint index = lookup.GetInterfaceID(methodParent);

                    ValueRef indirectionGep = LLVM.BuildInBoundsGEP(builder, argVals[0], new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false) }, "indirectiongep");
                    indirectionGep = LLVM.BuildPointerCast(builder, indirectionGep, LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(TypeHelper.VoidPtr, 0), 0), 0), string.Empty);
                    ValueRef indirectionTable = LLVM.BuildLoad(builder, indirectionGep, "indirectiontable");
                    ValueRef vTableGep        = LLVM.BuildInBoundsGEP(builder, indirectionTable, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, index, false) }, "vtablegep");
                    ValueRef vTableInstance   = LLVM.BuildLoad(builder, vTableGep, "vtable");
                    methodGep = LLVM.BuildInBoundsGEP(builder, vTableInstance, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, (uint)vTable.GetMethodIndex(methodParent, methodRef), false) }, "methodgep");
                }

                // Indirect call.
                ValueRef methodPtr = LLVM.BuildLoad(builder, methodGep, "methodptr");
                method = LLVM.BuildPointerCast(builder, methodPtr, funcPtrType, "method");
            }
            else
            {
                // We can call it directly without VTable lookup.
                method = func.Value;
            }

            ValueRef retVal = LLVM.BuildCall(builder, method, argVals, string.Empty);

            if (instruction.HasPrefix(Code.Tail))
            {
                LLVM.SetTailCall(retVal, true);
            }

            // Push return value on stack if it has one.
            if (methodRef.ReturnType.MetadataType != MetadataType.Void)
            {
                context.CurrentStack.Push(new StackElement(retVal, methodRef.ReturnType));
            }
        }
Example #11
0
        /// <summary>
        /// Update stack with phi nodes.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="srcStack">The source stack.</param>
        /// <param name="oldBlock">The old block.</param>
        /// <param name="newBlock">The new block.</param>
        /// <param name="refers">The amount of references to the new block.</param>
        public void Update(BuilderRef builder, ILStack srcStack, BasicBlockRef oldBlock, BasicBlockRef newBlock, int refers)
        {
            // If there's only one reference to this branch, there's only one way to get here.
            // That means the stack elements only depend on one other branch, therefor we don't need to build phi nodes.
            if (refers == 1)
            {
                for (int i = 0; i < srcStack.Count; i++)
                {
                    Push(new StackElement(srcStack[i]));
                }
            }
            // Multiple references.
            else
            {
                // We got three possible cases here:
                // 1. #deststack = #srcstack => build phi nodes for every element.
                // 2. #deststack > #srcstack => build phi nodes for the top elements of the srcstack.
                // 3. #deststack < #srcstack => build phi nodes for the top elements and put the rest on the stack as independent values.

                int dstOffset  = Count - 1;
                int difference = 0;

                // Case 3.
                if (Count < srcStack.Count)
                {
                    difference = srcStack.Count - Count;

                    // Push independent values on the stack start.
                    for (int i = difference - 1; i >= 0; i--)
                    {
                        InsertAtStart(srcStack[i]);
                        oldBlocks.Insert(0, oldBlock);
                    }
                }

                difference += srcStack.GetDependentCount();

                for (int i = srcStack.Count - 1; i >= difference; i--)
                {
                    // Not a phi node yet. Transform to a phi node.
                    if (mPhi[dstOffset] == 0)
                    {
                        StackElement element  = mStack[dstOffset];
                        ValueRef     oldValue = element.Value;

                        LLVM.PositionBuilderAtEnd(builder, newBlock);
                        element.Value = LLVM.BuildPhi(builder, element.Type, "phi");
                        LLVM.PositionBuilderAtEnd(builder, oldBlock);
                        LLVM.AddIncoming(element.Value, new ValueRef[] { oldValue }, new BasicBlockRef[] { oldBlocks[i] });
                    }

                    ValueRef phi = mStack[dstOffset].Value;

                    // We might need to cast the incoming value to the phi type.
                    // This is because it is possible that an integer type of a smaller type is pushed on the stack.
                    // by IL, for example in "branch on condition".
                    TypeRef  phiType       = LLVM.TypeOf(phi);
                    ValueRef incomingValue = srcStack[i].Value;

                    // Cast if not the same type.
                    if (srcStack[i].Type != phiType)
                    {
                        CastHelper.HelpIntAndPtrCast(builder, ref incomingValue, ref srcStack[i].Type, phiType, "phicast");
                    }

                    // Add new incoming from source stack.
                    LLVM.AddIncoming(phi, new ValueRef[] { incomingValue }, new BasicBlockRef[] { oldBlock });

                    mPhi[dstOffset]++;
                    dstOffset--;
                }
            }
        }
Example #12
0
        /// <summary>
        /// Emits a call instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            MethodReference methodRef  = (MethodReference)instruction.Operand;
            TypeRef         returnType = TypeHelper.GetTypeRefFromType(methodRef.ReturnType);

            // Check for special cases.
            if (instruction.Previous != null && instruction.Previous.OpCode.Code == Code.Ldtoken)
            {
                emitFromLdtoken(instruction, context, builder);
                return;
            }
            // Call System.Object::.ctor() ?
            else if (methodRef.FullName == "System.Void System.Object::.ctor()")
            {
                // Delete object reference from stack and ignore this.
                context.CurrentStack.Pop();
                return;
            }

            // Build parameter value and types arrays.
            int paramCount = methodRef.Parameters.Count;

            if (methodRef.HasThis)
            {
                paramCount++;
            }

            // Get the method, if it is null, create a new empty one, otherwise reference it.
            string   methodName = NameHelper.CreateMethodName(methodRef);
            ValueRef?func       = context.Compiler.Lookup.GetFunction(methodName);

            // Process arguments.
            // Note: backwards for loop because stack is backwards!
            ValueRef[] argVals    = new ValueRef[paramCount];
            TypeRef[]  paramTypes = new TypeRef[paramCount];
            for (int i = paramCount - 1; i >= 0; i--)
            {
                TypeReference type;
                StackElement  element = context.CurrentStack.Pop();
                argVals[i] = element.Value;

                // Note: the instance pointer is not included in the parameters explicitely.
                if (methodRef.HasThis)
                {
                    if (i == 0)
                    {
                        type = methodRef.DeclaringType;
                    }
                    else
                    {
                        type = methodRef.Parameters[i - 1].ParameterType;
                    }
                }
                else
                {
                    type = methodRef.Parameters[i].ParameterType;
                }

                paramTypes[i] = TypeHelper.GetTypeRefFromType(type);
                if (type.IsValueType && methodRef.HasThis && i == 0)
                {
                    paramTypes[i] = LLVM.PointerType(paramTypes[i], 0);
                }

                // Cast needed?
                if (element.Type != paramTypes[i])
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref argVals[i], ref element.Type, paramTypes[i], "callcast");
                }
            }

            // Function does not exist, create a declaration for the function.
            if (!func.HasValue)
            {
                TypeRef functionType = LLVM.FunctionType(returnType, paramTypes, false);
                func = LLVM.AddFunction(context.Compiler.Module, methodName, functionType);
                context.Compiler.Lookup.AddFunction(methodName, func.Value);
            }

            // Call.
            ValueRef retVal = LLVM.BuildCall(builder, func.Value, argVals, string.Empty);

            if (instruction.HasPrefix(Code.Tail))
            {
                LLVM.SetTailCall(retVal, true);
            }

            // Push return value on stack if it has one.
            if (methodRef.ReturnType.MetadataType != MetadataType.Void)
            {
                context.CurrentStack.Push(new StackElement(retVal, methodRef.ReturnType));
            }
        }