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));
        }
Beispiel #2
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}");
            }
        }