Exemple #1
0
        internal void ProcessStoreLoc(FunctionContext funcContext, BuilderStackItem stackItem, int localVariableIndex)
        {
            var localVariableType = funcContext.LocalVariableTypes[localVariableIndex];
            var localVariable     = funcContext.LocalVariables[localVariableIndex];

            //TODO: Need a better way to compare...
            if (localVariableType.IsPointer)
            {
                var resolvePtrType = Context.TypeResolver.Resolve(localVariableType);
                var store          = ProcessStore(funcContext,
                                                  LLVM.BuildIntToPtr(funcContext.Builder, stackItem.ValRef.Value, resolvePtrType, "IntPtr"),
                                                  localVariable);
                Context.CLRLogger.Debug(
                    $"[Stloc_{localVariableIndex}] -> Popped {stackItem.ValRef.Value.TypeOf()} and Stored {store}");
            }
            else
            {
                var store = ProcessStore(funcContext, stackItem.ValRef.Value, localVariable);
                Context.CLRLogger.Debug(
                    $"[Stloc_{localVariableIndex}] -> Popped {stackItem.ValRef.Value.TypeOf()} and Stored {store}");
            }
        }
Exemple #2
0
        public override BuildResult Build(Instruction instruction, FunctionContext funcContext)
        {
            if (instruction.OpCode == OpCodes.Ldloca_S)
            {
                var def       = (VariableDefinition)instruction.Operand;
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[def.Index].VariableType,
                                                     funcContext.LocalVariables[def.Index]);
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug(
                    $"[Ldloca_S {def.Index}] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldloc_S)
            {
                var def       = (VariableDefinition)instruction.Operand;
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[def.Index].VariableType,
                                                     LLVM.BuildLoad(funcContext.Builder, funcContext.LocalVariables[def.Index], ""));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug(
                    $"[Ldloc_S {def.Index}] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldloc_0)
            {
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[0].VariableType,
                                                     LLVM.BuildLoad(funcContext.Builder, funcContext.LocalVariables[0], ""));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldloc_0] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldloc_1)
            {
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[1].VariableType,
                                                     LLVM.BuildLoad(funcContext.Builder, funcContext.LocalVariables[1], ""));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldloc_1] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldloc_2)
            {
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[2].VariableType,
                                                     LLVM.BuildLoad(funcContext.Builder, funcContext.LocalVariables[2], ""));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldloc_2] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldloc_3)
            {
                var stackItem = new BuilderStackItem(funcContext.MethodDef.Body.Variables[3].VariableType,
                                                     LLVM.BuildLoad(funcContext.Builder, funcContext.LocalVariables[3], ""));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldloc_3] -> Pushed Local Variable {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stloc_0)
            {
                var val = funcContext.BuilderStack.Pop();
                ProcessStoreLoc(funcContext, val, 0);
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stloc_1)
            {
                var val = funcContext.BuilderStack.Pop();
                ProcessStoreLoc(funcContext, val, 1);
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stloc_2)
            {
                var val = funcContext.BuilderStack.Pop();
                ProcessStoreLoc(funcContext, val, 2);
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stloc_3)
            {
                var val = funcContext.BuilderStack.Pop();
                ProcessStoreLoc(funcContext, val, 3);
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stloc_S)
            {
                var index = (VariableDefinition)instruction.Operand;
                var val   = funcContext.BuilderStack.Pop();
                ProcessStoreLoc(funcContext, val, index.Index);
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stind_I1)
            {
                var val     = funcContext.BuilderStack.Pop();
                var cast    = LLVM.BuildZExt(funcContext.Builder, val.ValRef.Value, LLVM.Int8Type(), "");
                var address = funcContext.BuilderStack.Pop();
                var ptr     = address.ValRef.Value;
                if (address.ValRef.Value.TypeOf().TypeKind != LLVMTypeKind.LLVMPointerTypeKind)
                {
                    ptr = LLVM.BuildIntToPtr(funcContext.Builder, address.ValRef.Value,
                                             LLVM.PointerType(LLVM.Int8Type(), 0),
                                             "");
                }
                var store = ProcessStore(funcContext, cast, ptr);
                Context.CLRLogger.Debug(
                    $"[Stind_I1] -> Popped {val.ValRef.Value} and {address.ValRef.Value} and Stored into address: {store}");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Stfld)
            {
                var fieldDef  = (FieldDefinition)instruction.Operand;
                var value     = funcContext.BuilderStack.Pop();
                var structRef = funcContext.BuilderStack.Pop();
                if (value.ValRef.Value.IsNull())
                {
                    throw new Exception(
                              "The Value/Reference returned as null thus cannot be stored in Struct!");
                }
                if (structRef.ValRef.Value.IsNull())
                {
                    throw new Exception(
                              "The Value/Reference returned as null thus cannot be stored in Struct!");
                }

                var index = (uint)Array.IndexOf(
                    Context.FullSymbolToTypeRef[fieldDef.DeclaringType.FullName].CS_FieldDefs,
                    Context.FullSymbolToTypeRef[fieldDef.DeclaringType.FullName].CS_FieldDefs
                    .First(I => I.Name == fieldDef.Name));

                var          refToStruct = structRef.ValRef.Value;
                LLVMValueRef offset;
                if (fieldDef.DeclaringType.IsClass)
                {
                    offset = LLVM.BuildLoad(funcContext.Builder, refToStruct, "");
                }

                offset = LLVM.BuildStructGEP(funcContext.Builder, refToStruct, index, structRef.Type.Name);
                ProcessStore(funcContext, value.ValRef.Value, offset);
                Context.CLRLogger.Debug(
                    $"[Stfld {fieldDef.FullName}] -> Popped {value.ValRef.Value} and {refToStruct.TypeOf()} and Store {value.ValRef.Value} into {offset}");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldfld)
            {
                var fieldDef  = (FieldDefinition)instruction.Operand;
                var structRef = funcContext.BuilderStack.Pop();
                if (!structRef.ValRef.HasValue)
                {
                    throw new Exception(
                              "The Value/Reference returned as null thus cannot be stored in Struct!");
                }
                //var load = LLVM.BuildLoad(funcContext.Builder, structRef.ValRef.Value, $"Loaded_{structRef.Type.Name}");
                var load   = structRef.ValRef.Value;
                var offset = LLVM.BuildStructGEP(funcContext.Builder, load,
                                                 (uint)Array.IndexOf(
                                                     Context.FullSymbolToTypeRef[fieldDef.DeclaringType.FullName].CS_FieldDefs,
                                                     Context.FullSymbolToTypeRef[fieldDef.DeclaringType.FullName].CS_FieldDefs
                                                     .First(I => I.Name == fieldDef.Name)), $"Offset_{fieldDef.Name}");
                var item = new BuilderStackItem(fieldDef.FieldType, LLVM.BuildLoad(funcContext.Builder, offset, ""));
                funcContext.BuilderStack.Push(item);
                Context.CLRLogger.Debug(
                    $"[Ldfld {fieldDef.FullName}] -> Popped {structRef.ValRef.Value} off stack and pushed {item.ValRef.Value} to stack");
                return(new BuildResult(true));
            }

            return(new BuildResult(false));
        }
Exemple #3
0
        public override BuildResult Build(Instruction instruction, FunctionContext funcContext)
        {
            if (instruction.OpCode == OpCodes.Conv_I)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int32Type,
                                                         LLVM.BuildFPToUI(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U1] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int32Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U1] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                // TODO: Support Decimal Conversion To Int64
                else
                {
                    throw new Exception(
                              "INTEGER 8 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_U1)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt8Type,
                                                         LLVM.BuildFPToUI(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U1] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt8Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U1] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "UNSIGNED INTEGER 1 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_U2)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt16Type,
                                                         LLVM.BuildFPToUI(funcContext.Builder, value.ValRef.Value, LLVM.Int16Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U2] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt16Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int16Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U2] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "UNSIGNED INTEGER 2 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_U4)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt32Type,
                                                         LLVM.BuildFPToUI(funcContext.Builder, value.ValRef.Value, LLVM.Int32Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U4] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt32Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int32Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U4] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "UNSIGNED INTEGER 4 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_U8)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt64Type,
                                                         LLVM.BuildFPToUI(funcContext.Builder, value.ValRef.Value, LLVM.Int64Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U8] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.UInt64Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int64Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_U8] -> Popped {value.ValRef.Value} and Pushed As Unsigned Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "UNSIGNED INTEGER 8 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_I1)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int8Type,
                                                         LLVM.BuildFPToSI(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I1] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int8Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int8Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I1] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "INTEGER 1 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_I2)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int16Type,
                                                         LLVM.BuildFPToSI(funcContext.Builder, value.ValRef.Value, LLVM.Int16Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I2] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int16Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int16Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I2] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "INTEGER 2 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_I4)
            {
                var value = funcContext.BuilderStack.Pop();
                if (value.Type.IsPointer)
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int32Type,
                                                         LLVM.BuildPtrToInt(funcContext.Builder, value.ValRef.Value, LLVM.Int32Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I4] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int32Type,
                                                         LLVM.BuildFPToSI(funcContext.Builder, value.ValRef.Value, LLVM.Int32Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I4] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int32Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int32Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I4] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "INTEGER 4 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_I8)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int64Type,
                                                         LLVM.BuildFPToSI(funcContext.Builder, value.ValRef.Value, LLVM.Int64Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I8] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.Int64Type,
                                                         LLVM.BuildZExt(funcContext.Builder, value.ValRef.Value, LLVM.Int64Type(), ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_I8] -> Popped {value.ValRef.Value} and Pushed As Signed Integer {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "INTEGER 8 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_R4)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.FloatType,
                                                         LLVM.BuildSIToFP(funcContext.Builder, value.ValRef.Value,
                                                                          LLVM.FloatTypeInContext(Context.ContextRef),
                                                                          ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_R4] -> Popped {value.ValRef.Value} and Pushed As Float {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.FloatType,
                                                         LLVM.BuildFPCast(funcContext.Builder, value.ValRef.Value,
                                                                          LLVM.FloatTypeInContext(Context.ContextRef),
                                                                          ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_R4] -> Popped {value.ValRef.Value} and Pushed As Float {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "REAL 4 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Conv_R8)
            {
                var value = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.DoubleType,
                                                         LLVM.BuildSIToFP(funcContext.Builder, value.ValRef.Value,
                                                                          LLVM.DoubleTypeInContext(Context.ContextRef),
                                                                          ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_R8] -> Popped {value.ValRef.Value} and Pushed As Float {stackItem.ValRef.Value} to Stack");
                }
                else if (MiniBCL.IsTypeARealNumber(value.Type))
                {
                    var stackItem = new BuilderStackItem(MiniBCL.DoubleType,
                                                         LLVM.BuildFPCast(funcContext.Builder, value.ValRef.Value,
                                                                          LLVM.DoubleTypeInContext(Context.ContextRef),
                                                                          ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Conv_R8] -> Popped {value.ValRef.Value} and Pushed As Float {stackItem.ValRef.Value} to Stack");
                }
                else
                {
                    throw new Exception(
                              "REAL 8 BYTES CONVERSION IS NOT SUPPORTED");
                }

                return(new BuildResult(true));
            }

            return(new BuildResult(false));
        }
        public override BuildResult Build(Instruction instruction, FunctionContext funcContext)
        {
            if (instruction.OpCode == OpCodes.Ldind_U1)
            {
                var          val = funcContext.BuilderStack.Pop();
                LLVMValueRef cast;
                if (val.Type.IsPointer)
                {
                    cast = LLVM.BuildPtrToInt(funcContext.Builder,
                                              LLVM.BuildLoad(funcContext.Builder, val.ValRef.Value, ""),
                                              LLVM.Int32Type(), "");
                }
                else
                {
                    cast = LLVM.BuildZExt(funcContext.Builder,
                                          LLVM.BuildLoad(funcContext.Builder, val.ValRef.Value, ""),
                                          LLVM.Int32Type(), "");
                }
                funcContext.BuilderStack.Push(new BuilderStackItem
                {
                    Type    = MiniBCL.Int32Type,
                    TypeRef = LLVM.Int32Type(),
                    ValRef  = cast
                });
                Context.CLRLogger.Debug(
                    $"[Ldind_U1] -> Popped Stack Item {val.ValRef.Value}, Loaded and Casted to Int32 Type {cast}");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldind_I)
            {
                var val = funcContext.BuilderStack.Pop();
                // TODO: Support Native Integer conversion
                LLVMValueRef cast;
                if (val.Type.IsPointer)
                {
                    cast = LLVM.BuildLoad(funcContext.Builder, val.ValRef.Value, "");
                    funcContext.BuilderStack.Push(new BuilderStackItem
                    {
                        Type    = ((PointerType)val.Type).ElementType,
                        TypeRef = cast.TypeOf(),
                        ValRef  = cast
                    });
                }
                else
                {
                    cast = LLVM.BuildZExt(funcContext.Builder,
                                          LLVM.BuildLoad(funcContext.Builder, val.ValRef.Value, $"Load_{val.Type.Name}"),
                                          LLVM.Int64Type(), "");
                    funcContext.BuilderStack.Push(new BuilderStackItem
                    {
                        Type    = MiniBCL.Int64Type,
                        TypeRef = LLVM.Int64Type(),
                        ValRef  = cast
                    });
                }

                Context.CLRLogger.Debug(
                    $"[Ldind_I] -> Popped Stack Item {val.ValRef.Value} and Casted to Int64 Type {cast}");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4)
            {
                var operand   = (int)instruction.Operand;
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), (ulong)operand,
                                              true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4 {operand}] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_S)
            {
                var operand   = (sbyte)instruction.Operand;
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), (ulong)operand,
                                              true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_S {operand}] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_0)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 0, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_0] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_1)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 1, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_1] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_2)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 2, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_2] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_3)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 3, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_3] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_4)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 4, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_4] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_5)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 5, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_5] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_6)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 6, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_6] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_7)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 7, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_7] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_8)
            {
                var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), 8, true);
                funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                   stackItem));
                Context.CLRLogger.Debug($"[Ldc_I4_8] -> Pushed {stackItem} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_I4_M1)
            {
                unchecked
                {
                    var stackItem = LLVM.ConstInt(LLVM.Int32TypeInContext(Context.ContextRef), (ulong)-1,
                                                  true);
                    funcContext.BuilderStack.Push(new BuilderStackItem(MiniBCL.Int32Type,
                                                                       stackItem));
                    Context.CLRLogger.Debug($"[Ldc_I4_M1] -> Pushed {stackItem} to Stack");
                    return(new BuildResult(true));
                }
            }

            if (instruction.OpCode == OpCodes.Ldc_I8)
            {
                var stackItem = new BuilderStackItem(MiniBCL.Int64Type,
                                                     LLVM.ConstInt(LLVM.Int64TypeInContext(Context.ContextRef), (ulong)instruction.Operand,
                                                                   new LLVMBool(1)));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldc_I8] -> Pushed {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_R4)
            {
                var stackItem = new BuilderStackItem(MiniBCL.FloatType,
                                                     LLVM.ConstReal(LLVM.FloatTypeInContext(Context.ContextRef), (double)instruction.Operand));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldc_R4] -> Pushed {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldc_R8)
            {
                var stackItem = new BuilderStackItem(MiniBCL.DoubleType,
                                                     LLVM.ConstReal(LLVM.DoubleTypeInContext(Context.ContextRef),
                                                                    (double)instruction.Operand));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldc_R8] -> Pushed {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldnull)
            {
                var stackItem = new BuilderStackItem(MiniBCL.Int64Type,
                                                     LLVM.ConstNull(LLVM.PointerType(LLVM.Int8Type(), 0)));
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldnull] -> Pushed {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldftn)
            {
                var operand = (MethodDefinition)instruction.Operand;
                var symbol  = SymbolHelper.GetCSToLLVMSymbolName(operand);
                if (!Context.SymbolToCallableFunction.ContainsKey(symbol))
                {
                    Context.CLR.ProcessFunction(operand.Resolve(), false);
                }

                var stackItem =
                    new BuilderStackItem(operand.ReturnType.Resolve(),
                                         Context.SymbolToCallableFunction[symbol]);
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldftn {stackItem.Type}] -> Pushed {stackItem.ValRef.Value} to Stack");
                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Ldstr)
            {
                var val       = (string)instruction.Operand;
                var ldstr     = LLVM.BuildGlobalStringPtr(funcContext.Builder, val, "");
                var stackItem = new BuilderStackItem(MiniBCL.StringType, ldstr);
                funcContext.BuilderStack.Push(stackItem);
                Context.CLRLogger.Debug($"[Ldstr {val}] -> Pushed {ldstr.TypeOf()} to Stack");
                return(new BuildResult(true));
            }

            return(new BuildResult(false));
        }
        public override BuildResult Build(Instruction instruction, FunctionContext funcContext)
        {
            if (instruction.OpCode == OpCodes.Add)
            {
                // TODO: Support conversion between Floating Point and Integers
                var rval = funcContext.BuilderStack.Pop();
                var lval = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(lval.Type) && MiniBCL.IsTypeAnInteger(rval.Type))
                {
                    // TODO: Need to determine the size of pointer.
                    LLVMValueRef actualLVal;
                    LLVMValueRef actualRVal;
                    if (lval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualLVal = LLVM.BuildPtrToInt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(),
                                                        "lval");
                    }
                    else
                    {
                        actualLVal = LLVM.BuildZExt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(), "lval");
                    }

                    if (rval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualRVal = LLVM.BuildPtrToInt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(),
                                                        "rval");
                    }
                    else
                    {
                        actualRVal = LLVM.BuildZExt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(), "rval");
                    }

                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildAdd(funcContext.Builder, actualLVal, actualRVal, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Add] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value.TypeOf()} and Pushed {stackItem.ValRef.Value}");
                }
                else if (MiniBCL.IsTypeARealNumber(lval.Type) && MiniBCL.IsTypeARealNumber(rval.Type))
                {
                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildFAdd(funcContext.Builder, lval.ValRef.Value, rval.ValRef.Value, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Add] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else
                {
                    throw new Exception("Unknown type, thus cannot add!");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Sub)
            {
                // TODO: Support conversion between Floating Point and Integers
                var rval = funcContext.BuilderStack.Pop();
                var lval = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(lval.Type) && MiniBCL.IsTypeAnInteger(rval.Type))
                {
                    // TODO: Need to determine the size of pointer.
                    LLVMValueRef actualLVal;
                    LLVMValueRef actualRVal;
                    if (lval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualLVal = LLVM.BuildPtrToInt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(),
                                                        "lval");
                    }
                    else
                    {
                        actualLVal = LLVM.BuildZExt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(), "lval");
                    }

                    if (rval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualRVal = LLVM.BuildPtrToInt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(),
                                                        "rval");
                    }
                    else
                    {
                        actualRVal = LLVM.BuildZExt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(), "rval");
                    }

                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildSub(funcContext.Builder, actualLVal, actualRVal, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else if (MiniBCL.IsTypeARealNumber(lval.Type) && MiniBCL.IsTypeARealNumber(rval.Type))
                {
                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildFSub(funcContext.Builder, lval.ValRef.Value, rval.ValRef.Value, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else
                {
                    throw new Exception("Unknown type, thus cannot add!");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Mul)
            {
                // TODO: Support conversion between Floating Point and Integers
                var rval = funcContext.BuilderStack.Pop();
                var lval = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(lval.Type) && MiniBCL.IsTypeAnInteger(rval.Type))
                {
                    // TODO: Need to determine the size of pointer.
                    LLVMValueRef actualLVal;
                    LLVMValueRef actualRVal;
                    if (lval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualLVal = LLVM.BuildPtrToInt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(),
                                                        "lval");
                    }
                    else
                    {
                        actualLVal = LLVM.BuildZExt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(), "lval");
                    }

                    if (rval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualRVal = LLVM.BuildPtrToInt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(),
                                                        "rval");
                    }
                    else
                    {
                        actualRVal = LLVM.BuildZExt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(), "rval");
                    }

                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildMul(funcContext.Builder, actualLVal, actualRVal, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else if (MiniBCL.IsTypeARealNumber(lval.Type) && MiniBCL.IsTypeARealNumber(rval.Type))
                {
                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildFMul(funcContext.Builder, lval.ValRef.Value, rval.ValRef.Value, ""));
                    funcContext.BuilderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else
                {
                    throw new Exception("Unknown type, thus cannot add!");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Div)
            {
                // TODO: Support conversion between Floating Point and Integers
                var rval = funcContext.BuilderStack.Pop();
                var lval = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(lval.Type) && MiniBCL.IsTypeAnInteger(rval.Type))
                {
                    // TODO: Need to determine the size of pointer.
                    LLVMValueRef actualLVal;
                    LLVMValueRef actualRVal;
                    if (lval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualLVal = LLVM.BuildPtrToInt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(),
                                                        "lval");
                    }
                    else
                    {
                        actualLVal = LLVM.BuildZExt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(), "lval");
                    }

                    if (rval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualRVal = LLVM.BuildPtrToInt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(),
                                                        "rval");
                    }
                    else
                    {
                        actualRVal = LLVM.BuildZExt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(), "rval");
                    }

                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildSDiv(funcContext.Builder, actualLVal, actualRVal, ""));
                    funcContext.BuilderStack.Push(stackItem);

                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else if (MiniBCL.IsTypeARealNumber(lval.Type) && MiniBCL.IsTypeARealNumber(rval.Type))
                {
                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildFDiv(funcContext.Builder, lval.ValRef.Value, rval.ValRef.Value, ""));
                    funcContext.BuilderStack.Push(stackItem);

                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else
                {
                    throw new Exception("Unknown type, thus cannot add!");
                }

                return(new BuildResult(true));
            }

            if (instruction.OpCode == OpCodes.Rem)
            {
                // TODO: Support conversion between Floating Point and Integers
                var rval = funcContext.BuilderStack.Pop();
                var lval = funcContext.BuilderStack.Pop();
                if (MiniBCL.IsTypeAnInteger(lval.Type) && MiniBCL.IsTypeAnInteger(rval.Type))
                {
                    // TODO: Need to determine the size of pointer.
                    LLVMValueRef actualLVal;
                    LLVMValueRef actualRVal;
                    if (lval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualLVal = LLVM.BuildPtrToInt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(),
                                                        "lval");
                    }
                    else
                    {
                        actualLVal = LLVM.BuildZExt(funcContext.Builder, lval.ValRef.Value, LLVM.Int32Type(), "lval");
                    }

                    if (rval.ValRef.Value.TypeOf().TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
                    {
                        actualRVal = LLVM.BuildPtrToInt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(),
                                                        "rval");
                    }
                    else
                    {
                        actualRVal = LLVM.BuildZExt(funcContext.Builder, rval.ValRef.Value, LLVM.Int32Type(), "rval");
                    }

                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildSRem(funcContext.Builder, actualLVal, actualRVal, ""));
                    funcContext.BuilderStack.Push(stackItem);

                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else if (MiniBCL.IsTypeARealNumber(lval.Type) && MiniBCL.IsTypeARealNumber(rval.Type))
                {
                    var stackItem = new BuilderStackItem(lval.Type,
                                                         LLVM.BuildFRem(funcContext.Builder, lval.ValRef.Value, rval.ValRef.Value, ""));
                    funcContext.BuilderStack.Push(stackItem);

                    Context.CLRLogger.Debug(
                        $"[Sub] -> Popped {rval.ValRef.Value} and {lval.ValRef.Value} and Pushed {stackItem.ValRef.Value}");
                }
                else
                {
                    throw new Exception("Unknown type, thus cannot add!");
                }

                return(new BuildResult(true));
            }

            return(new BuildResult(false));
        }
Exemple #6
0
        internal void ProcessCall(Instruction instruction, LLVMBuilderRef builder,
                                  Stack <BuilderStackItem> builderStack)
        {
            var methodToCall = (MethodReference)instruction.Operand;

            Context.CLRLogger.Debug(methodToCall.ToString());
            var resolvedMethodToCall = methodToCall.Resolve();

            if (methodToCall.HasThis && resolvedMethodToCall.DeclaringType?.BaseType != null &&
                (resolvedMethodToCall.DeclaringType.BaseType.FullName == "System.Delegate" ||
                 resolvedMethodToCall.DeclaringType.BaseType.FullName == "System.MulticastDelegate"))
            {
                var refs = new LLVMValueRef[methodToCall.Parameters.Count];
                if (refs.Length > 0)
                {
                    for (var i = methodToCall.Parameters.Count - 1; i > -1; --i)
                    {
                        refs[i] = builderStack.Pop().ValRef.Value;
                    }
                }

                var reference = builderStack.Pop();
                var stackItem = new BuilderStackItem(methodToCall.ReturnType.Resolve(),
                                                     LLVM.BuildCall(builder, reference.ValRef.Value, refs, ""));
                // We know this is a delegate, now to call it!
                builderStack.Push(stackItem);
                Context.CLRLogger.Debug(
                    $"[{instruction.OpCode.Name} {methodToCall.FullName}] -> Determined as Delegate, Popped Reference {reference} and Push {stackItem.ValRef} to Stack");
            }
            else
            {
                var refs = new LLVMValueRef[methodToCall.HasThis
                    ? methodToCall.Parameters.Count + 1
                    : methodToCall.Parameters.Count];
                var symbol = SymbolHelper.GetCSToLLVMSymbolName(methodToCall);

                if (refs.Length > (methodToCall.HasThis ? 1 : 0))
                {
                    for (var i = methodToCall.HasThis
                            ? methodToCall.Parameters.Count
                            : methodToCall.Parameters.Count - 1;
                         i > (methodToCall.HasThis ? 0 : -1);
                         --i)
                    {
                        refs[i] = builderStack.Pop().ValRef.Value;
                    }
                }

                if (!Context.SymbolToCallableFunction.ContainsKey(SymbolHelper.GetCSToLLVMSymbolName(methodToCall)))
                {
                    Context.CLRLogger.Debug("Resolving Function");
                    Context.CLR.ProcessFunction(methodToCall.Resolve(), false);
                }

                if (methodToCall.HasThis)
                {
                    var reference = builderStack.Pop();
                    if (methodToCall.DeclaringType.FullName != reference.Type.FullName)
                    {
                        refs[0] = LLVM.BuildPointerCast(builder, reference.ValRef.Value,
                                                        Context.SymbolToCallableFunction[symbol].GetFirstParam().TypeOf(), "");
                    }
                    else
                    {
                        refs[0] = reference.ValRef.Value;
                    }
                }

                if (methodToCall.ReturnType.FullName != "System.Void")
                {
                    var stackItem = new BuilderStackItem(methodToCall.ReturnType.Resolve(),
                                                         LLVM.BuildCall(builder,
                                                                        Context.SymbolToCallableFunction[SymbolHelper.GetCSToLLVMSymbolName(methodToCall)],
                                                                        refs, ""));
                    builderStack.Push(stackItem);
                    Context.CLRLogger.Debug(
                        $"[{instruction.OpCode.Name} {methodToCall.FullName}] -> Push {stackItem.ValRef} to Stack");
                    return;
                }

                var call = LLVM.BuildCall(builder,
                                          Context.SymbolToCallableFunction[SymbolHelper.GetCSToLLVMSymbolName(methodToCall)],
                                          refs, "");
                Context.CLRLogger.Debug($"[{instruction.OpCode.Name} {methodToCall.FullName}] -> Called {call}");
            }
        }