/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="block">The current basic block.</param> /// <param name="builder">The current builder.</param> /// <param name="kind">The kind of the arithmetic operation.</param> /// <param name="instruction">The current IL instruction.</param> private static void MakeArithmetic( Block block, IRBuilder builder, BinaryArithmeticKind kind, ILInstruction instruction) { var arithmeticFlags = ArithmeticFlags.None; var convertFlags = ConvertFlags.None; if (instruction.HasFlags(ILInstructionFlags.Overflow)) { arithmeticFlags |= ArithmeticFlags.Overflow; } if (instruction.HasFlags(ILInstructionFlags.Unsigned)) { convertFlags |= ConvertFlags.TargetUnsigned; arithmeticFlags |= ArithmeticFlags.Unsigned; } block.PopArithmeticArgs(convertFlags, out Value left, out Value right); switch (kind) { case BinaryArithmeticKind.Shl: case BinaryArithmeticKind.Shr: // Convert right operand to 32bits right = CreateConversion( builder, right, builder.GetPrimitiveType(BasicValueType.Int32), convertFlags); break; } var arithmetic = builder.CreateArithmetic(left, right, kind, arithmeticFlags); block.Push(arithmetic); }
/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="kind">The kind of the arithmetic operation.</param> /// <param name="instruction">The current IL instruction.</param> private void MakeArithmetic( BinaryArithmeticKind kind, ILInstruction instruction) { var arithmeticFlags = ArithmeticFlags.None; var convertFlags = ConvertFlags.None; if (instruction.HasFlags(ILInstructionFlags.Overflow)) { arithmeticFlags |= ArithmeticFlags.Overflow; } if (instruction.HasFlags(ILInstructionFlags.Unsigned)) { convertFlags |= ConvertFlags.TargetUnsigned; arithmeticFlags |= ArithmeticFlags.Unsigned; } ValueReference result; if (Block.PopArithmeticArgs( Location, convertFlags, out var left, out var right) == Block.ArithmeticOperandKind.Pointer) { // This is a pointer access bool isLeftPointer = left.Type.IsPointerType; if (!isLeftPointer) { Utilities.Swap(ref left, ref right); } if (kind != BinaryArithmeticKind.Add || right.Type.IsPointerType) { throw Location.GetNotSupportedException( ErrorMessages.NotSupportedArithmeticArgumentType, kind); } result = Builder.CreateLoadElementAddress( Location, left, right); }
/// <summary> /// Realizes a virtual-call instruction. /// </summary> /// <param name="instruction">The current IL instruction.</param> private void MakeVirtualCall(ILInstruction instruction) { var method = instruction.GetArgumentAs <MethodInfo>(); if (instruction.HasFlags(ILInstructionFlags.Constrained)) { MakeVirtualCall( method, instruction.FlagsContext.Argument as Type); } else { MakeVirtualCall(method, null); } }
/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="kind">The kind of the arithmetic operation.</param> /// <param name="instruction">The current IL instruction.</param> private void MakeArithmetic( BinaryArithmeticKind kind, ILInstruction instruction) { var arithmeticFlags = ArithmeticFlags.None; var convertFlags = ConvertFlags.None; if (instruction.HasFlags(ILInstructionFlags.Overflow)) { arithmeticFlags |= ArithmeticFlags.Overflow; } if (instruction.HasFlags(ILInstructionFlags.Unsigned)) { convertFlags |= ConvertFlags.TargetUnsigned; arithmeticFlags |= ArithmeticFlags.Unsigned; } ValueReference result = default; if (Block.PopArithmeticArgs( Location, convertFlags, out var left, out var right) == Block.ArithmeticOperandKind.Pointer) { // This is a pointer access bool isLeftPointer = left.Type.IsPointerType; if (!isLeftPointer) { Utilities.Swap(ref left, ref right); } // Check for raw combinations of two pointer values if ( !right.Type.IsPointerType && // Check whether this can be safely converted into a LEA value kind == BinaryArithmeticKind.Add) { result = Builder.CreateLoadElementAddress( Location, left, right); } // Check whether this operation on pointer values can be converted // into a LEA instruction // FIXME: remove this code once we add additional LEA nodes else if ( kind == BinaryArithmeticKind.Add && right is BinaryArithmeticValue baseAddress && TryConvertIntoLoadElementAddress(left, baseAddress, out var lea)) { result = lea; } } if (!result.IsValid) { switch (kind) { case BinaryArithmeticKind.Shl: case BinaryArithmeticKind.Shr: // Convert right operand to 32bits right = CreateConversion( right, Builder.GetPrimitiveType(BasicValueType.Int32), convertFlags); break; } result = Builder.CreateArithmetic( Location, left, right, kind, arithmeticFlags); } Block.Push(result); }
/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="kind">The kind of the arithmetic operation.</param> /// <param name="instruction">The current IL instruction.</param> private void MakeArithmetic( BinaryArithmeticKind kind, ILInstruction instruction) { var arithmeticFlags = ArithmeticFlags.None; var convertFlags = ConvertFlags.None; if (instruction.HasFlags(ILInstructionFlags.Overflow)) { arithmeticFlags |= ArithmeticFlags.Overflow; } if (instruction.HasFlags(ILInstructionFlags.Unsigned)) { convertFlags |= ConvertFlags.TargetUnsigned; arithmeticFlags |= ArithmeticFlags.Unsigned; } ValueReference result = default; if (Block.PopArithmeticArgs( Location, convertFlags, out var left, out var right) == Block.ArithmeticOperandKind.Pointer) { // This is a pointer access bool isLeftPointer = left.Type.IsPointerType; if (!isLeftPointer) { Utilities.Swap(ref left, ref right); } // Check for raw combinations of two pointer values if ( !right.Type.IsPointerType && // Check whether this can be safely converted into a LEA value kind == BinaryArithmeticKind.Add) { result = Builder.CreateLoadElementAddress( Location, left, right); } // Check whether this operation on pointer values can be converted // into a LEA instruction // FIXME: remove this code once we add additional LEA nodes else if ( kind == BinaryArithmeticKind.Add && right is BinaryArithmeticValue baseAddress && baseAddress.Kind == BinaryArithmeticKind.Mul && // Extract the element stride from the multiplication pattern // (must be the right operand since we have moved all pointer // values the left hand side by definition) TryGetBasicValueSize(baseAddress.Right, out var strideType)) { // Cast raw pointer into an appropriate target type var targetElementType = Builder.GetPrimitiveType(strideType); left = Builder.CreatePointerCast( Location, left, targetElementType); result = Builder.CreateLoadElementAddress( Location, left, baseAddress.Left); } } if (!result.IsValid) { switch (kind) { case BinaryArithmeticKind.Shl: case BinaryArithmeticKind.Shr: // Convert right operand to 32bits right = CreateConversion( right, Builder.GetPrimitiveType(BasicValueType.Int32), convertFlags); break; } result = Builder.CreateArithmetic( Location, left, right, kind, arithmeticFlags); } Block.Push(result); }