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