/// <summary> /// Loads the value of a field specified by the given metadata token. /// </summary> /// <param name="field">The field.</param> private void LoadField(FieldInfo field) { var value = CurrentBlock.Pop(); var name = string.Empty; if (value.ValueType.IsTreatedAsPtr()) { var address = LoadFieldAddress(field, value); CurrentBlock.Push(field.FieldType, BuildLoad(Builder, address, name)); } else { // It is a value object do { var mappedType = Unit.GetObjectType(value.ValueType); if (mappedType.TryResolveOffset(field, out int offset)) { value = new Value(field.FieldType, BuildExtractValue(Builder, value.LLVMValue, offset, name)); break; } var baseType = value.ValueType.BaseType; if (baseType == null) { throw new InvalidOperationException(); } value = new Value(baseType, BuildExtractValue(Builder, value.LLVMValue, 0, name)); }while (value.ValueType.BaseType != null); CurrentBlock.Push(value); } }
/// <summary> /// Loads the length of an array. /// </summary> private void LoadArrayLength() { var array = CurrentBlock.Pop(); Debug.Assert(array.ValueType.IsArray); CurrentBlock.Push(typeof(int), BuildExtractValue(Builder, array.LLVMValue, 1, "ldlen")); }
/// <summary> /// Realizes a new-array instruction. /// </summary> /// <param name="elementType">The element type of the array.</param> private void MakeNewArray(Type elementType) { var stackValue = CurrentBlock.Pop(); var arrayLength = stackValue.LLVMValue; if (!IsConstant(arrayLength)) { throw CompilationContext.GetNotSupportedException(ErrorMessages.NotSupportedArrayCreation); } // Allocate the element data first in a local alloca var llvmElementType = Unit.GetType(elementType); var arrayLengthValue = (int)ConstIntGetZExtValue(arrayLength); var llvmAllocaArrayType = ArrayType(llvmElementType, arrayLengthValue); var arrayData = CreateTempAlloca(llvmAllocaArrayType); BuildStore(Builder, ConstNull(llvmAllocaArrayType), arrayData); // Array<T> = (T*, int32) var arrayType = elementType.MakeArrayType(); var llvmArrayType = Unit.GetType(arrayType); var initialArrayValue = GetUndef(llvmArrayType); // Setup T*: (T*, undef) var basePtr = BuildPointerCast(Builder, arrayData, PointerType(llvmElementType), string.Empty); var arrayWithPointer = BuildInsertValue(Builder, initialArrayValue, basePtr, 0, string.Empty); // Setup length: (T*, int32) var array = BuildInsertValue(Builder, arrayWithPointer, arrayLength, 1, string.Empty); // Push the final array value CurrentBlock.Push(arrayType, array); }
/// <summary> /// Loads a value of the given type from an unsafe memory address. /// </summary> /// <param name="type">The type of the value to load.</param> private void LoadIndirect(Type type) { var address = CurrentBlock.Pop(type.MakePointerType()); var load = BuildLoad(Builder, address.LLVMValue, "ldind"); CurrentBlock.Push(type, load); }
/// <summary> /// Stores a value to an unsafe address. /// </summary> /// <param name="type">The type of the value to store.</param> private void StoreIndirect(Type type) { var value = CurrentBlock.Pop(type); var address = CurrentBlock.Pop(type.MakePointerType()); BuildStore(Builder, value.LLVMValue, address.LLVMValue); }
/// <summary> /// Realizes an indirect load instruction. /// </summary> /// <param name="type">The target type.</param> private void MakeLoadObject(Type type) { var address = CurrentBlock.Pop(); address = CreateConversion(address, type.MakePointerType()); CurrentBlock.Push(type, BuildLoad(Builder, address.LLVMValue, string.Empty)); }
/// <summary> /// Stores a value to a field. /// </summary> /// <param name="field">The field.</param> private void StoreField(FieldInfo field) { var value = CurrentBlock.Pop(field.FieldType); var fieldValue = CurrentBlock.Pop(); var fieldAddress = LoadFieldAddress(field, fieldValue); BuildStore(Builder, value.LLVMValue, fieldAddress); }
/// <summary> /// Realizes an indirect store instruction. /// </summary> /// <param name="type">The target type.</param> private void MakeStoreObject(Type type) { var value = CurrentBlock.Pop(type); var address = CurrentBlock.Pop(); address = CreateConversion(address, type.MakePointerType()); BuildStore(Builder, value.LLVMValue, address.LLVMValue); }
/// <summary> /// Stores a value to a static field. /// </summary> /// <param name="field">The field.</param> private void StoreStaticField(FieldInfo field) { VerifyStaticFieldStore(CompilationContext, Unit.Flags, field); // Consume the current value from the stack but do not emit a global store, // since we dont have any valid target address. // TODO: Stores to static fields could be automatically propagated to the .Net // runtime after kernel invocation. However, this remains as a future feature. CurrentBlock.Pop(); }
/// <summary> /// Realizes an un-boxing operation that unboxes a previously boxed value. /// </summary> /// <param name="type">The target type.</param> private void MakeUnbox(Type type) { var value = CurrentBlock.Pop(); if (!value.ValueType.IsPointer || !type.IsValueType) { throw CompilationContext.GetInvalidILCodeException(); } throw CompilationContext.GetNotSupportedException(ErrorMessages.NotSupportedUnboxing); }
/// <summary> /// Loads the address of an array element. /// </summary> private void LoadArrayElementAddress() { var idx = CurrentBlock.PopInt(); var array = CurrentBlock.Pop(); Debug.Assert(array.ValueType.IsArray); var addr = ComputeArrayAddress(array.LLVMValue, idx.LLVMValue); CurrentBlock.Push(array.ValueType.GetElementType().MakePointerType(), addr); }
/// <summary> /// Loads an array element. /// </summary> /// <param name="type">The type of element to load.</param> private void LoadArrayElement(Type type) { var idx = CurrentBlock.PopInt(); var array = CurrentBlock.Pop(); Debug.Assert(array.ValueType.IsArray); var addr = ComputeArrayAddress(array.LLVMValue, idx.LLVMValue); var value = BuildLoad(Builder, addr, string.Empty); CurrentBlock.Push(CreateConversion(new Value(array.ValueType.GetElementType(), value), type)); }
/// <summary> /// Stores an array element of the specified type. /// </summary> /// <param name="type">The target type.</param> private void StoreArrayElement(Type type) { var value = CurrentBlock.Pop(type); var idx = CurrentBlock.PopInt(); var array = CurrentBlock.Pop(); Debug.Assert(array.ValueType.IsArray); var addr = ComputeArrayAddress(array.LLVMValue, idx.LLVMValue); BuildStore(Builder, value.LLVMValue, addr); }
/// <summary> /// Realizes a return instruction. /// </summary> private void MakeReturn() { if (Method.IsVoid) { BuildRetVoid(Builder); } else { var returnValue = CurrentBlock.Pop(Method.ReturnType); BuildRet(Builder, returnValue.LLVMValue); } }
/// <summary> /// Realizes a managed-object initialization. /// </summary> /// <param name="type">The target type.</param> private void MakeInitObject(Type type) { if (type == null) { throw CompilationContext.GetInvalidILCodeException(); } var address = CurrentBlock.Pop(); var llvmType = Unit.GetType(type); BuildStore(Builder, ConstNull(llvmType), address.LLVMValue); }
/// <summary> /// Realizes a numeric-neg instruction. /// </summary> private void MakeNumericNeg() { var value = CurrentBlock.Pop(); var name = string.Empty; if (value.ValueType.IsFloat()) { CurrentBlock.Push(value.ValueType, BuildFNeg(Builder, value.LLVMValue, name)); } else { CurrentBlock.Push(value.ValueType, BuildNeg(Builder, value.LLVMValue, name)); } }
/// <summary> /// Stores a value to the argument with index idx. /// </summary> /// <param name="var">The variable reference.</param> private void StoreVariable(VariableRef var) { Debug.Assert(var.RefType == VariableRefType.Argument || var.RefType == VariableRefType.Local); var variableType = variableTypes[var]; var value = CurrentBlock.Pop(variableType); if (variables.TryGetValue(var, out Value nonSSAValue)) { BuildStore(Builder, value.LLVMValue, nonSSAValue.LLVMValue); } else { CurrentBlock.SetValue(var, value); } }
/// <summary> /// Realizes a local stackalloc instruction. /// </summary> private void MakeLocalAlloc() { var size = CurrentBlock.Pop(); var arrayLength = size.LLVMValue; if (!IsConstant(arrayLength)) { throw CompilationContext.GetNotSupportedException( ErrorMessages.NotSupportedUnsafeAllocation); } // Allocate the element data first in a local alloca var llvmElementType = LLVMContext.Int8Type; var arrayData = BuildArrayAlloca(Builder, llvmElementType, arrayLength, "localloc"); CurrentBlock.Push(typeof(byte).MakePointerType(), arrayData); }
/// <summary> /// Realizes a numeric-not instruction. /// </summary> private void MakeNumericNot() { var value = CurrentBlock.Pop(); CurrentBlock.Push(value.ValueType, BuildNot(Builder, value.LLVMValue, string.Empty)); }
/// <summary> /// Realizes a cast operation that casts a given class to another type. /// </summary> /// <param name="targetType">The target type.</param> private void MakeCastClass(Type targetType) { var value = CurrentBlock.Pop(); CurrentBlock.Push(CreateCastClass(value, targetType)); }
/// <summary> /// Realizes a convert instruction. /// </summary> /// <param name="targetType">The target type.</param> /// <param name="forceUnsigned">True, if the comparison should be forced to be unsigned.</param> private void MakeConvert(Type targetType, bool forceUnsigned = false) { var value = CurrentBlock.Pop(); CurrentBlock.Push(CreateConversion(value, targetType, forceUnsigned)); }
/// <summary> /// Loads the address of a field specified by the given metadata token. /// </summary> /// <param name="field">The field.</param> private void LoadFieldAddress(FieldInfo field) { var value = CurrentBlock.Pop(); CurrentBlock.Push(field.FieldType.MakePointerType(), LoadFieldAddress(field, value)); }