private void EmitDebugVariable(FunctionCompilerContext functionContext, SequencePoint sequencePoint, DIDescriptor generatedScope, StackValue variable, DW_TAG dwarfType, string variableName, int argIndex = 0) { var debugType = CreateDebugType(variable.Type); // Process fields and other dependent debug types ProcessMissingDebugTypes(); // Read it again in case it was mutated debugType = CreateDebugType(variable.Type); // TODO: Detect where variable is actually declared (first use of local?) var debugLocalVariable = LLVM.DIBuilderCreateLocalVariable(debugBuilder, (uint)dwarfType, generatedScope, variableName, functionContext.DebugFile, sequencePoint != null ? (uint)sequencePoint.StartLine : 0, debugType, true, 0, (uint)argIndex); var debugVariableDeclare = LLVM.DIBuilderInsertDeclareAtEnd(debugBuilder, variable.Value, debugLocalVariable, debugEmptyExpression, LLVM.GetInsertBlock(builder)); LLVM.SetInstDebugLocation(builder, debugVariableDeclare); }
/// <summary> /// Helper function to convert variables from stack to local /// </summary> /// <param name="local">The local variable.</param> /// <param name="stack">The stack variable.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> private ValueRef ConvertFromStackToLocal(Type localType, StackValue stack) { var stackValue = stack.Value; // Same type, return as is if ((stack.StackType == StackValueType.Value || stack.StackType == StackValueType.NativeInt) && localType.DefaultTypeLLVM == LLVM.TypeOf(stack.Value)) { return(stackValue); } // NativeInt to NativeInt // Need pointer conversion if (stack.StackType == StackValueType.NativeInt && localType.StackType == StackValueType.NativeInt) { return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } // Int32 to NativeInt if (stack.StackType == StackValueType.Int32 && localType.StackType == StackValueType.NativeInt) { if (intPtrSize == 8) { // TODO: SExt (IntPTr) or ZExt (everything else) throw new NotImplementedException(); } return(LLVM.BuildIntToPtr(builder, stackValue, localType.DataTypeLLVM, string.Empty)); } // NativeInt to Reference // Used for example when casting+boxing primitive type pointers // TODO: Start GC tracking? if (stack.StackType == StackValueType.NativeInt && localType.StackType == StackValueType.Reference) { // Fallback: allow everything for now... return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } // Object: allow upcast as well if (stack.StackType == StackValueType.Reference || stack.StackType == StackValueType.Object) { if (localType.DefaultTypeLLVM == stack.Type.DefaultTypeLLVM) { return(stackValue); } if (localType.TypeReferenceCecil.Resolve().IsInterface) { // Interface upcast var stackClass = GetClass(stack.Type); foreach (var @interface in stackClass.Interfaces) { if (MemberEqualityComparer.Default.Equals(@interface.Type.TypeReferenceCecil, localType.TypeReferenceCecil)) { return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } } } else { // Class upcast // Check upcast in hierarchy // TODO: we could optimize by storing Depth var stackType = stack.Type.TypeReferenceCecil; while (stackType != null) { if (MemberEqualityComparer.Default.Equals(stackType, localType.TypeReferenceCecil)) { // It's an upcast, do LLVM pointer cast return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } stackType = stackType.Resolve().BaseType; } } // Fallback: allow everything for now... return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } if (stack.StackType == StackValueType.Float && stack.Type == localType) { return(stackValue); } // Spec: Storing into locals that hold an integer value smaller than 4 bytes long truncates the value as it moves from the stack to the local variable. if ((stack.StackType == StackValueType.Int32 || stack.StackType == StackValueType.Int64) && LLVM.GetTypeKind(localType.DefaultTypeLLVM) == TypeKind.IntegerTypeKind) { return(LLVM.BuildIntCast(builder, stackValue, localType.DefaultTypeLLVM, string.Empty)); } // TODO: Other cases throw new NotImplementedException(string.Format("Error converting from {0} to {1}", stack.Type, localType)); }
private ValueRef GenerateMulticastInvokeThunk(Class declaringClass) { // Reuse same signature as Invoke var delegateType = corlib.MainModule.GetType(typeof(Delegate).FullName); var invokeMethod = declaringClass.Functions.Single(x => x.MethodReference.Name == "Invoke"); var invokeMethodHelper = LLVM.AddFunction(module, LLVM.GetValueName(invokeMethod.GeneratedValue) + "_MulticastHelper", invokeMethod.FunctionType); LLVM.SetLinkage(invokeMethodHelper, declaringClass.Type.Linkage); LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty)); var invokeFunctionType = LLVM.GetElementType(LLVM.TypeOf(invokeMethodHelper)); bool hasRetValue = LLVM.GetReturnType(invokeFunctionType) != LLVM.VoidTypeInContext(context); var delegateArrayType = GetType(new ArrayType(delegateType), TypeState.TypeComplete); // Prepare basic blocks var forCodeBlock = LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty); var exitBlock = LLVM.AppendBasicBlockInContext(context, invokeMethodHelper, string.Empty); var stack = new List <StackValue>(); // Load first argument and cast as Delegate[] var @this = LLVM.GetParam(invokeMethodHelper, 0); @this = LLVM.BuildPointerCast(builder, @this, delegateArrayType.DefaultTypeLLVM, string.Empty); // Create index (i = 0) var locals = new List <StackValue>(); locals.Add(new StackValue(StackValueType.Int32, int32, LLVM.BuildAlloca(builder, int32.DefaultTypeLLVM, "i"))); EmitI4(stack, 0); EmitStloc(stack, locals, 0); // length = invocationList.Length var delegateArray = new StackValue(StackValueType.Object, delegateArrayType, @this); stack.Add(delegateArray); EmitLdlen(stack); EmitConv(stack, Code.Conv_I4); var invocationCount = stack.Pop(); // Iterate over each element in array LLVM.BuildBr(builder, forCodeBlock); LLVM.PositionBuilderAtEnd(builder, forCodeBlock); // Get delegateArray[i] stack.Add(delegateArray); EmitLdloc(stack, locals, 0); EmitLdelem(stack); // Call var helperArgs = new ValueRef[LLVM.CountParams(invokeMethodHelper)]; helperArgs[0] = LLVM.BuildPointerCast(builder, stack.Pop().Value, declaringClass.Type.DefaultTypeLLVM, string.Empty); for (int i = 1; i < helperArgs.Length; ++i) { helperArgs[i] = LLVM.GetParam(invokeMethodHelper, (uint)i); } var retValue = LLVM.BuildCall(builder, invokeMethod.GeneratedValue, helperArgs, string.Empty); // i++ EmitLdloc(stack, locals, 0); var lastStack = stack[stack.Count - 1]; var incrementedValue = LLVM.BuildAdd(builder, lastStack.Value, LLVM.ConstInt(int32LLVM, 1, false), string.Empty); lastStack = new StackValue(StackValueType.Int32, int32, incrementedValue); stack[stack.Count - 1] = lastStack; EmitStloc(stack, locals, 0); // if (i < length) // goto forCodeBlock // else // return lastReturnValue; EmitLdloc(stack, locals, 0); stack.Add(invocationCount); EmitConditionalBranch(stack, forCodeBlock, exitBlock, Code.Blt_S); LLVM.PositionBuilderAtEnd(builder, exitBlock); // Return value if (hasRetValue) { LLVM.BuildRet(builder, retValue); } else { LLVM.BuildRetVoid(builder); } if (LLVM.VerifyFunction(invokeMethodHelper, VerifierFailureAction.PrintMessageAction)) { throw new InvalidOperationException(string.Format("Verification failed for function {0}", invokeMethodHelper)); } return(invokeMethodHelper); }
/// <summary> /// Helper function to convert variables from stack to local /// </summary> /// <param name="local">The local variable.</param> /// <param name="stack">The stack variable.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> private ValueRef ConvertFromStackToLocal(Type localType, StackValue stack) { var stackValue = stack.Value; // Same type, return as is if ((stack.StackType == StackValueType.Value || stack.StackType == StackValueType.NativeInt) && localType.DefaultType == stack.Type.DefaultType) { return(stackValue); } // Object: allow upcast as well if (stack.StackType == StackValueType.Object) { if (localType.DefaultType == stack.Type.DefaultType) { return(stackValue); } if (localType.TypeReference.Resolve().IsInterface) { // Interface upcast var stackClass = GetClass(stack.Type.TypeReference); foreach (var @interface in stackClass.Interfaces) { if (MemberEqualityComparer.Default.Equals(@interface.TypeReference, localType.TypeReference)) { return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultType, string.Empty)); } } } else { // Class upcast // Check upcast in hierarchy // TODO: we could optimize by storing Depth var stackType = stack.Type.TypeReference; while (stackType != null) { if (MemberEqualityComparer.Default.Equals(stackType, localType.TypeReference)) { // It's an upcast, do LLVM pointer cast return(LLVM.BuildPointerCast(builder, stackValue, localType.DefaultType, string.Empty)); } stackType = stackType.Resolve().BaseType; } } } // Spec: Storing into locals that hold an integer value smaller than 4 bytes long truncates the value as it moves from the stack to the local variable. if ((stack.StackType == StackValueType.Int32 || stack.StackType == StackValueType.Int64) && LLVM.GetTypeKind(localType.DefaultType) == TypeKind.IntegerTypeKind) { return(LLVM.BuildIntCast(builder, stackValue, localType.DefaultType, string.Empty)); } // TODO: Other cases throw new NotImplementedException(); }