/// <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> /// Realizes an arithmetic mul operation. /// </summary> /// <param name="overflow">True, if an overflow has to be checked.</param> private void MakeArithmeticMul(bool overflow) { if (overflow) { throw new NotSupportedException(); } Type type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); var name = string.Empty; var basicValueType = type.GetBasicValueType(); if (basicValueType.IsFloat()) { if (Unit.HasFlags(CompileUnitFlags.UseGPUMath)) { MakeIntrinsicMathOperation( type, basicValueType == BasicValueType.Single ? MathMulF32 : MathMulF64, left, right); } else { CurrentBlock.Push(type, BuildFMul(Builder, left, right, name)); } } else { CurrentBlock.Push(type, BuildMul(Builder, left, right, name)); } }
/// <summary> /// Realizes an arithmetic div operation. /// </summary> /// <param name="forceUnsigned">True, if the comparison should be forced to be unsigned.</param> private void MakeArithmeticDiv(bool forceUnsigned = false) { Type type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); var name = string.Empty; var basicValueType = type.GetBasicValueType(); if (basicValueType.IsFloat()) { if (Unit.HasFlags(CompileUnitFlags.UseGPUMath)) { MakeIntrinsicMathOperation( type, basicValueType == BasicValueType.Single ? MathDivF32 : MathDivF64, left, right); } else { CurrentBlock.Push(type, BuildFDiv(Builder, left, right, name)); } } else if (forceUnsigned || basicValueType.IsUnsignedInt()) { CurrentBlock.Push(type, BuildUDiv(Builder, left, right, name)); } else { CurrentBlock.Push(type, BuildSDiv(Builder, left, right, name)); } }
/// <summary> /// Creates a call instruction to the given method with the given arguments. /// </summary> /// <param name="target">The target method to invoke.</param> /// <param name="args">The call arguments</param> private void CreateCall(MethodBase target, Value[] args) { var intrinsicContext = new InvocationContext(Builder, Method, target, args, this); // Check for remapping first var remappedContext = Unit.RemapIntrinsic(intrinsicContext); if (remappedContext != null) { intrinsicContext = remappedContext.Value; } // Early rejection for runtime-dependent methods VerifyNotRuntimeMethod(CompilationContext, intrinsicContext.Method); // Handle device functions if (!Unit.HandleIntrinsic(intrinsicContext, out Value? methodInvocationResult)) { var method = Unit.GetMethod(intrinsicContext.Method); var llvmArgs = new LLVMValueRef[args.Length]; for (int i = 0, e = args.Length; i < e; ++i) { llvmArgs[i] = args[i].LLVMValue; } var call = BuildCall(Builder, method.LLVMFunction, llvmArgs); if (!method.IsVoid) { methodInvocationResult = new Value(method.ReturnType, call); } } if (methodInvocationResult.HasValue) { CurrentBlock.Push(methodInvocationResult.Value); } }
/// <summary> /// Realizes a new-object operation that creates a new instance of a specified type. /// </summary> /// <param name="method">The target method.</param> private void MakeNewObject(MethodBase method) { var constructor = method as ConstructorInfo; if (constructor == null) { throw CompilationContext.GetInvalidILCodeException(); } var type = constructor.DeclaringType; var llvmType = Unit.GetType(type); // Use a temporary alloca to realize object creation // and initialize object with zero var tempAlloca = CreateTempAlloca(llvmType); BuildStore(Builder, ConstNull(llvmType), tempAlloca); // Invoke constructor for type Value[] values = new Value[constructor.GetParameters().Length + 1]; values[0] = new Value(type.MakePointerType(), tempAlloca); CurrentBlock.PopMethodArgs(constructor, values, 1); CreateCall(constructor, values); // Push created instance on the stack if (type.IsValueType) { CurrentBlock.Push(type, BuildLoad(Builder, values[0].LLVMValue, string.Empty)); } else { CurrentBlock.Push(values[0]); } }
/// <summary> /// Loads the constant null. /// </summary> private void LoadNull() { var t = typeof(object); CurrentBlock.Push( t.MakePointerType(), ConstNull(Unit.GetType(t))); }
/// <summary> /// Loads a static field specified by the given metadata token. /// </summary> /// <param name="field">The field.</param> private void LoadStaticField(FieldInfo field) { VerifyStaticFieldLoad(CompilationContext, Unit.Flags, field); var value = field.GetValue(null); CurrentBlock.Push(field.FieldType, Unit.GetValue(field.FieldType, value)); }
/// <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> /// Loads a variable. This can be an argument or a local reference. /// </summary> /// <param name="var">The variable reference.</param> private void LoadVariable(VariableRef var) { Debug.Assert(var.RefType == VariableRefType.Argument || var.RefType == VariableRefType.Local); if (variables.TryGetValue(var, out Value nonSSAValue)) { var load = BuildLoad(Builder, nonSSAValue.LLVMValue, string.Empty); CurrentBlock.Push(nonSSAValue.ValueType, load); } else { CurrentBlock.Push(CurrentBlock.GetValue(var)); } }
/// <summary> /// Loads a double. /// </summary> private void Load(double value) { if (Unit.Force32BitFloats) { Load((float)value); } else { CurrentBlock.Push( typeof(double), ConstReal(LLVMContext.DoubleType, value)); } }
/// <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> /// Realizes a numeric-shr instruction. /// </summary> /// <param name="forceUnsigned">True if the comparison should be forced to be unsigned.</param> private void MakeNumericShr(bool forceUnsigned = false) { var type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); var name = string.Empty; if (forceUnsigned || type.IsUnsignedInt()) { CurrentBlock.Push(type, BuildLShr(Builder, left, right, name)); } else { CurrentBlock.Push(type, BuildAShr(Builder, left, right, name)); } }
/// <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> /// Constructs general math intrinsics. /// </summary> /// <param name="type">The type of the operation.</param> /// <param name="targetMethod">A reference to a specific target method.</param> /// <param name="left">The left param.</param> /// <param name="right">The right param.</param> private void MakeIntrinsicMathOperation( Type type, MethodInfo targetMethod, LLVMValueRef left, LLVMValueRef right) { if (!Unit.HandleIntrinsic(new InvocationContext( Builder, Method, targetMethod, new Value[] { new Value(type, left), new Value(type, right), }, this), out Value? result) || !result.HasValue) { throw CompilationContext.GetInvalidOperationException( ErrorMessages.InvalidMathIntrinsic, targetMethod.Name); } CurrentBlock.Push(result.Value); }
/// <summary> /// Realizes an arithmetic add operation. /// </summary> /// <param name="overflow">True, if an overflow has to be checked.</param> private void MakeArithmeticAdd(bool overflow) { if (overflow) { throw new NotSupportedException(); } Type type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); var name = string.Empty; if (type.GetBasicValueType() == BasicValueType.Ptr) { CurrentBlock.Push(type, BuildInBoundsGEP(Builder, left, right)); } else if (type.IsFloat()) { CurrentBlock.Push(type, BuildFAdd(Builder, left, right, name)); } else { Debug.Assert(type.IsInt()); CurrentBlock.Push(type, BuildAdd(Builder, left, right, name)); } }
/// <summary> /// Realizes an arithmetic sub operation. /// </summary> /// <param name="overflow">True, if an overflow has to be checked.</param> private void MakeArithmeticSub(bool overflow) { if (overflow) { throw new NotSupportedException(); } Type type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); var name = string.Empty; if (type.GetBasicValueType() == BasicValueType.Ptr) { right = BuildSub(Builder, ConstPointerNull(TypeOf(right)), right, name); CurrentBlock.Push(type, BuildInBoundsGEP(Builder, left, right)); } if (type.IsFloat()) { CurrentBlock.Push(type, BuildFSub(Builder, left, right, name)); } else { CurrentBlock.Push(type, BuildSub(Builder, left, right, name)); } }
/// <summary> /// Realizes a numeric-shl instruction. /// </summary> private void MakeNumericShl() { var type = CurrentBlock.PopArithmeticArgs(out LLVMValueRef left, out LLVMValueRef right); CurrentBlock.Push(type, BuildShl(Builder, left, right, string.Empty)); }
/// <summary> /// Loads a long. /// </summary> private void Load(long value) { CurrentBlock.Push( typeof(long), ConstInt(LLVMContext.Int64Type, value, true)); }
/// <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> /// Loads an int. /// </summary> private void Load(int value) { CurrentBlock.Push( typeof(int), ConstInt(LLVMContext.Int32Type, value, true)); }
/// <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 a float. /// </summary> private void Load(float value) { CurrentBlock.Push( typeof(float), ConstReal(LLVMContext.FloatType, value)); }
/// <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)); }
/// <summary> /// Loads a string. /// </summary> private void LoadString(string value) { CurrentBlock.Push( typeof(string), BuildGlobalStringPtr(Builder, value, string.Empty)); }
/// <summary> /// Realizes a compare instruction of the given type. /// </summary> /// <param name="compareType">The comparison type to use.</param> /// <param name="forceUnsigned">True, if the comparison should be forced to be unsigned.</param> private void MakeCompare(CompareType compareType, bool forceUnsigned = false) { CurrentBlock.Push(CreateCompare(compareType, forceUnsigned)); }