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