/// <summary> /// Resolves an unary arithmetic operation. /// </summary> /// <param name="kind">The arithmetic kind.</param> /// <param name="isFloat">True, if this is a floating-point operation.</param> /// <param name="isFunction">True, if the resolved operation is a function call.</param> /// <returns>The resolved arithmetic operation.</returns> public static string GetArithmeticOperation( UnaryArithmeticKind kind, bool isFloat, out bool isFunction) { string operation; (operation, isFunction) = UnaryArithmeticOperations[(kind, isFloat)];
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="location">The current location.</param> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Location location, Value node, UnaryArithmeticKind kind) => CreateArithmetic( location, node, kind, ArithmeticFlags.None);
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <param name="flags">Operation flags.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Value node, UnaryArithmeticKind kind, ArithmeticFlags flags) { Debug.Assert(node != null, "Invalid node"); if (UseConstantPropagation) { // Check for constants if (node is PrimitiveValue value) { return(UnaryArithmeticFoldConstants(value, kind)); } var isUnsigned = (flags & ArithmeticFlags.Unsigned) == ArithmeticFlags.Unsigned; switch (kind) { case UnaryArithmeticKind.Not: if (node is UnaryArithmeticValue otherValue && otherValue.Kind == UnaryArithmeticKind.Not) { return(otherValue.Value); } if (node is CompareValue compareValue) { return(CreateCompare( compareValue.Left, compareValue.Right, CompareValue.Invert(compareValue.Kind), compareValue.Flags)); } break; case UnaryArithmeticKind.Neg: if (node.BasicValueType == BasicValueType.Int1) { return(CreateArithmetic(node, UnaryArithmeticKind.Not)); } break; case UnaryArithmeticKind.Abs: if (isUnsigned) { return(node); } break; } } return(Append(new UnaryArithmeticValue( Context, BasicBlock, node, kind, flags))); }
/// <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> private static void MakeArithmetic( Block block, IRBuilder builder, UnaryArithmeticKind kind) { var value = block.PopCompareOrArithmeticValue(ConvertFlags.None); var arithmetic = builder.CreateArithmetic(value, kind); block.Push(arithmetic); }
/// <summary> /// Resolves an unary arithmetic operation. /// </summary> /// <param name="kind">The arithmetic kind.</param> /// <param name="isFloat">True, if this is a floating-point operation.</param> /// <param name="isFunction">True, if the resolved operation is a function call.</param> /// <returns>The resolved arithmetic operation.</returns> public static string GetArithmeticOperation( UnaryArithmeticKind kind, bool isFloat, out bool isFunction) { if (!UnaryArithmeticOperations.TryGetValue((kind, isFloat), out var operation)) { throw new NotSupportedIntrinsicException(kind.ToString()); } isFunction = operation.Item2; return(operation.Item1); }
/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="kind">The kind of the arithmetic operation.</param> private void MakeArithmetic(UnaryArithmeticKind kind) { var value = Block.PopCompareOrArithmeticValue( Location, ConvertFlags.None); var arithmetic = Builder.CreateArithmetic( Location, value, kind); Block.Push(arithmetic); }
/// <summary> /// Resolves an unary arithmetic operation. /// </summary> /// <param name="kind">The arithmetic kind.</param> /// <param name="basicValueType">The arithmetic basic value type.</param> /// <param name="isFunction"> /// True, if the resolved operation is a function call. /// </param> /// <returns>The resolved arithmetic operation.</returns> public static string GetArithmeticOperation( UnaryArithmeticKind kind, ArithmeticBasicValueType basicValueType, out bool isFunction) { if (!UnaryCategoryLookup.TryGetValue(basicValueType, out var category) || !UnaryArithmeticOperations.TryGetValue((kind, category), out var operation)) { throw new NotSupportedIntrinsicException(kind.ToString()); } isFunction = operation.Item2; return(operation.Item1); }
public static string GetArithmeticOperation( UnaryArithmeticKind kind, ArithmeticBasicValueType type, bool fastMath) { var key = (kind, type); if (fastMath && UnaryArithmeticOperationsFastMath.TryGetValue(key, out string operation)) { return(operation); } return(UnaryArithmeticOperations[key]); }
/// <summary> /// Constructs a new unary arithmetic operation. /// </summary> /// <param name="context">The parent IR context.</param> /// <param name="basicBlock">The parent basic block.</param> /// <param name="value">The operand.</param> /// <param name="kind">The operation kind.</param> /// <param name="flags">The operation flags.</param> internal UnaryArithmeticValue( IRContext context, BasicBlock basicBlock, ValueReference value, UnaryArithmeticKind kind, ArithmeticFlags flags) : base( basicBlock, ImmutableArray.Create(value), flags, ComputeType(context, value, kind)) { Kind = kind; }
/// <summary> /// Resolves an unary arithmetic operation. /// </summary> /// <param name="kind">The arithmetic kind.</param> /// <param name="type">The operation type.</param> /// <param name="fastMath">True, to use a fast-math operation.</param> /// <returns>The resolved arithmetic operation.</returns> public static string GetArithmeticOperation( UnaryArithmeticKind kind, ArithmeticBasicValueType type, bool fastMath) { var key = (kind, type); if (fastMath && UnaryArithmeticOperationsFastMath.TryGetValue(key, out string operation) || UnaryArithmeticOperations.TryGetValue(key, out operation)) { return(operation); } throw new NotSupportedIntrinsicException(kind.ToString()); }
private static TypeNode ComputeType( IRContext context, ValueReference operand, UnaryArithmeticKind kind) { var type = operand.Type; switch (kind) { case UnaryArithmeticKind.IsInfF: case UnaryArithmeticKind.IsNaNF: type = context.GetPrimitiveType(BasicValueType.Int1); break; } return(type); }
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="location">The current location.</param> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <param name="flags">Operation flags.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Location location, Value node, UnaryArithmeticKind kind, ArithmeticFlags flags) { // Check for constants if (node is PrimitiveValue value) { return(UnaryArithmeticFoldConstants(location, value, kind)); } return (UnaryArithmeticSimplify( location, node, kind, flags) ?? Append(new UnaryArithmeticValue( GetInitializer(location), node, kind, flags))); }
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Value node, UnaryArithmeticKind kind) => CreateArithmetic(node, kind, ArithmeticFlags.None);
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="location">The current location.</param> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <param name="flags">Operation flags.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Location location, Value node, UnaryArithmeticKind kind, ArithmeticFlags flags) { if (UseConstantPropagation) { // Check for constants if (node is PrimitiveValue value) { return(UnaryArithmeticFoldConstants(location, value, kind)); } var isUnsigned = (flags & ArithmeticFlags.Unsigned) == ArithmeticFlags.Unsigned; switch (kind) { case UnaryArithmeticKind.Not: if (node is UnaryArithmeticValue otherValue && otherValue.Kind == UnaryArithmeticKind.Not) { return(otherValue.Value); } if (node is CompareValue compareValue) { // When the comparison is inverted, and we are comparing floats, // toggle between ordered/unordered float comparison. var compareFlags = compareValue.Flags; if (compareValue.Left.BasicValueType.IsFloat() && compareValue.Right.BasicValueType.IsFloat()) { compareFlags ^= CompareFlags.UnsignedOrUnordered; } return(CreateCompare( location, compareValue.Left, compareValue.Right, CompareValue.Invert(compareValue.Kind), compareFlags)); } break; case UnaryArithmeticKind.Neg: if (node.BasicValueType == BasicValueType.Int1) { return(CreateArithmetic( location, node, UnaryArithmeticKind.Not)); } break; case UnaryArithmeticKind.Abs: if (isUnsigned) { return(node); } break; } } return(Append(new UnaryArithmeticValue( GetInitializer(location), node, kind, flags))); }
/// <summary> /// Creates a unary arithmetic operation. /// </summary> /// <param name="location">The current location.</param> /// <param name="node">The operand.</param> /// <param name="kind">The operation kind.</param> /// <param name="flags">Operation flags.</param> /// <returns>A node that represents the arithmetic operation.</returns> public ValueReference CreateArithmetic( Location location, Value node, UnaryArithmeticKind kind, ArithmeticFlags flags) { if (UseConstantPropagation) { // Check for constants if (node is PrimitiveValue value) { return(UnaryArithmeticFoldConstants(location, value, kind)); } var isUnsigned = (flags & ArithmeticFlags.Unsigned) == ArithmeticFlags.Unsigned; switch (kind) { case UnaryArithmeticKind.Not: switch (node) { // Check nested not operations case UnaryArithmeticValue otherValue when otherValue.Kind == UnaryArithmeticKind.Not: return(otherValue.Value); // Check whether we can invert compare values case CompareValue compareValue: // When the comparison is inverted, and we are comparing // floats, toggle between ordered/unordered float // comparison var compareFlags = compareValue.Flags; if (compareValue.Left.BasicValueType.IsFloat() && compareValue.Right.BasicValueType.IsFloat()) { compareFlags ^= CompareFlags.UnsignedOrUnordered; } return(CreateCompare( location, compareValue.Left, compareValue.Right, CompareValue.Invert(compareValue.Kind), compareFlags)); // Propagate the not operator through binary operations case BinaryArithmeticValue otherBinary when BinaryArithmeticValue.TryInvertLogical( otherBinary.Kind, out var invertedBinary): return(CreateArithmetic( otherBinary.Location, CreateArithmetic( location, otherBinary.Left, UnaryArithmeticKind.Not), CreateArithmetic( location, otherBinary.Right, UnaryArithmeticKind.Not), invertedBinary, otherBinary.Flags)); } break; case UnaryArithmeticKind.Neg: if (node.BasicValueType == BasicValueType.Int1) { return(CreateArithmetic( location, node, UnaryArithmeticKind.Not)); } break; case UnaryArithmeticKind.Abs: if (isUnsigned) { return(node); } break; } } return(Append(new UnaryArithmeticValue( GetInitializer(location), node, kind, flags))); }