From d4da3ca117d888a6281c50db3fe9a4e287d809dd Mon Sep 17 00:00:00 2001 From: MoFtZ Date: Tue, 9 Apr 2024 15:40:59 +1000 Subject: [PATCH] Moved OpenCL IntrinsicMath implementations. (#1185) --- .../CL/CLContext.Generated.tt | 28 +- Src/ILGPU.Algorithms/CL/CLContext.cs | 46 +- Src/ILGPU.Algorithms/CL/CLMath.cs | 413 ------------------ Src/ILGPU/Backends/OpenCL/CLIntrinsics.cs | 111 ++++- Src/ILGPU/IntrinsicMath.BinaryLog.cs | 104 +++++ 5 files changed, 216 insertions(+), 486 deletions(-) delete mode 100644 Src/ILGPU.Algorithms/CL/CLMath.cs create mode 100644 Src/ILGPU/IntrinsicMath.BinaryLog.cs diff --git a/Src/ILGPU.Algorithms/CL/CLContext.Generated.tt b/Src/ILGPU.Algorithms/CL/CLContext.Generated.tt index 1e93feb21..5ffb011c8 100644 --- a/Src/ILGPU.Algorithms/CL/CLContext.Generated.tt +++ b/Src/ILGPU.Algorithms/CL/CLContext.Generated.tt @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU Algorithms -// Copyright (c) 2019-2021 ILGPU Project +// Copyright (c) 2019-2024 ILGPU Project // www.ilgpu.net // // File: CLContext.Generated.tt/CLContext.Generated.cs @@ -17,16 +17,6 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <# -var unaryMathFunctions = new ValueTuple[] - { - UnaryMathFunctions[18], // Rcp - UnaryMathFunctions[19], // Rcp - }; -var binaryMathFunctions = new ValueTuple[] - { - BinaryMathFunctions[6], // Log - BinaryMathFunctions[7], // Log - }; var xmathUnaryCodeGenerators = new ValueTuple[] { ( "RoundAwayFromZero", "round" ), @@ -49,22 +39,6 @@ namespace ILGPU.Algorithms.CL public static void EnableCLAlgorithms(IntrinsicImplementationManager manager) { // Register math intrinsics -<# foreach (var (name, type, kind, basicType) in binaryMathFunctions) { #> - manager.RegisterBinaryArithmetic( - BinaryArithmeticKind.<#= kind #>, - BasicValueType.<#= basicType #>, - GetMathIntrinsic( - "<#= name #>", - typeof(<#= type #>), typeof(<#= type #>))); -<# } #> - -<# foreach (var (name, type, kind, basicType) in unaryMathFunctions) { #> - manager.RegisterUnaryArithmetic( - UnaryArithmeticKind.<#= kind #>, - BasicValueType.<#= basicType #>, - MathCodeGeneratorIntrinsic); -<# } #> - <# foreach (var (name, functionName) in xmathUnaryCodeGenerators) { #> RegisterXMathCodeGenerator( manager, diff --git a/Src/ILGPU.Algorithms/CL/CLContext.cs b/Src/ILGPU.Algorithms/CL/CLContext.cs index 5f9c7222a..5e9c3f42f 100644 --- a/Src/ILGPU.Algorithms/CL/CLContext.cs +++ b/Src/ILGPU.Algorithms/CL/CLContext.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU Algorithms -// Copyright (c) 2019-2023 ILGPU Project +// Copyright (c) 2019-2024 ILGPU Project // www.ilgpu.net // // File: CLContext.cs @@ -27,32 +27,6 @@ namespace ILGPU.Algorithms.CL /// static partial class CLContext { - /// - /// The type. - /// - private static readonly Type CLMathType = typeof(CLMath); - - /// - /// Represents the - /// methods. - /// - private static readonly MethodInfo MathCodeGenerator = - CLMathType.GetMethod( - nameof(CLMath.GenerateMathIntrinsic), - AlgorithmContext.IntrinsicBindingFlags) - .ThrowIfNull(); - - /// - /// Represents the intrinsic representation of the - /// . - /// - private static readonly CLIntrinsic MathCodeGeneratorIntrinsic = - new CLIntrinsic( - MathCodeGenerator, - IntrinsicImplementationMode.GenerateCode) - .ThrowIfNull(); - /// /// The type. /// @@ -63,24 +37,6 @@ static partial class CLContext /// internal static readonly Type CLWarpExtensionsType = typeof(CLWarpExtensions); - /// - /// Resolves a CL intrinsic for the given math-function configuration. - /// - /// The intrinsic name. - /// The parameter types. - /// The resolved intrinsic representation. - private static CLIntrinsic GetMathIntrinsic(string name, params Type[] types) - { - var targetMethod = CLMathType.GetMethod( - name, - AlgorithmContext.IntrinsicBindingFlags, - null, - types, - null) - .ThrowIfNull(); - return new CLIntrinsic(targetMethod, IntrinsicImplementationMode.Redirect); - } - /// /// Registers an intrinsic mapping. /// diff --git a/Src/ILGPU.Algorithms/CL/CLMath.cs b/Src/ILGPU.Algorithms/CL/CLMath.cs deleted file mode 100644 index de2acbe53..000000000 --- a/Src/ILGPU.Algorithms/CL/CLMath.cs +++ /dev/null @@ -1,413 +0,0 @@ -// --------------------------------------------------------------------------------------- -// ILGPU Algorithms -// Copyright (c) 2020-2023 ILGPU Project -// www.ilgpu.net -// -// File: CLMath.cs -// -// This file is part of ILGPU and is distributed under the University of Illinois Open -// Source License. See LICENSE.txt for details. -// --------------------------------------------------------------------------------------- - -using ILGPU.Backends.OpenCL; -using ILGPU.IR; -using ILGPU.IR.Values; -using ILGPU.Util; -using System; -using System.Runtime.CompilerServices; - -namespace ILGPU.Algorithms.CL -{ - static class CLMath - { - #region Code Generator - - /// - /// Generates intrinsic math instructions for the following kinds: - /// Rcp - /// - /// The current backend. - /// The code generator. - /// The value to generate code for. - public static void GenerateMathIntrinsic( - CLBackend backend, - CLCodeGenerator codeGenerator, - Value value) - { - // Manually generate code for "1.0 / argument" - var arithmeticValue = value.AsNotNullCast(); - var argument = codeGenerator.Load(arithmeticValue.Value); - var target = codeGenerator.Allocate(arithmeticValue); - var operation = CLInstructions.GetArithmeticOperation( - BinaryArithmeticKind.Div, - arithmeticValue.BasicValueType.IsFloat(), - out var isFunction); - using var statement = codeGenerator.BeginStatement(target); - statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); - if (isFunction) - { - statement.AppendCommand(operation); - statement.BeginArguments(); - } - else - statement.OpenParen(); - - statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); - if (arithmeticValue.BasicValueType == BasicValueType.Float32) - statement.AppendConstant(1.0f); - else - statement.AppendConstant(1.0); - - if (!isFunction) - statement.AppendCommand(operation); - - statement.AppendArgument(); - statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); - statement.Append(argument); - - if (isFunction) - statement.EndArguments(); - else - statement.CloseParen(); - } - - #endregion - - #region IsNaN & IsInfinity - - /// - public static bool IsNaN(double value) => - throw new NotImplementedException(); - - /// - public static bool IsNaN(float value) => - throw new NotImplementedException(); - - /// - public static bool IsInfinity(double value) => - throw new NotImplementedException(); - - /// - public static bool IsInfinity(float value) => - throw new NotImplementedException(); - - #endregion - - #region Rcp - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Rcp(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Rcp(float value) => - throw new NotImplementedException(); - - #endregion - - #region Rem - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Rem(double x, double y) => - throw new NotImplementedException(); - - /// - public static float Rem(float x, float y) => - throw new NotImplementedException(); - - #endregion - - #region Sqrt - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Sqrt(double value) => - throw new NotImplementedException(); - - /// - public static float Sqrt(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Rsqrt(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Rsqrt(float value) => - throw new NotImplementedException(); - - #endregion - - #region Floor & Ceiling - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Floor(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Floor(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Ceiling(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Ceiling(float value) => - throw new NotImplementedException(); - - #endregion - - #region Trig - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Sin(double value) => - throw new NotImplementedException(); - - /// - public static float Sin(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Sinh(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Sinh(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Asin(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Asin(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Cos(double value) => - throw new NotImplementedException(); - - /// - public static float Cos(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Cosh(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Cosh(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Acos(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Acos(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Tan(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Tan(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Tanh(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Tanh(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Atan(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Atan(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Atan2(double y, double x) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Atan2(float y, float x) => - throw new NotImplementedException(); - - #endregion - - #region Pow - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Pow(double @base, double exp) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Pow(float @base, float exp) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Exp(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Exp(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Exp2(double value) => - throw new NotImplementedException(); - - /// - public static float Exp2(float value) => - throw new NotImplementedException(); - - #endregion - - #region Log - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Log(double value, double newBase) - { - if (value < 0.0 || - newBase < 0.0 || - (value != 1.0 && newBase == 0.0) || - (value != 1.0 && newBase == double.PositiveInfinity) || - XMath.IsNaN(value) || - XMath.IsNaN(newBase) || - newBase == 1.0) - { - return double.NaN; - } - - if (value == 0.0) - { - if (0.0 < newBase && newBase < 1.0) - return double.PositiveInfinity; - else if (newBase > 1.0) - return double.NegativeInfinity; - } - - if (value == double.PositiveInfinity) - { - if (0.0 < newBase && newBase < 1.0) - return double.NegativeInfinity; - else if (newBase > 1.0) - return double.PositiveInfinity; - } - - if (value == 1.0 && (newBase == 0.0 || newBase == double.PositiveInfinity)) - return 0.0; - - return XMath.Log(value) * XMath.Rcp(XMath.Log(newBase)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Log(float value, float newBase) - { - if (value < 0.0f || - newBase < 0.0f || - (value != 1.0f && newBase == 0.0f) || - (value != 1.0f && newBase == float.PositiveInfinity) || - XMath.IsNaN(value) || - XMath.IsNaN(newBase) || - newBase == 1.0f) - { - return float.NaN; - } - - if (value == 0.0f) - { - if (0.0f < newBase && newBase < 1.0f) - return float.PositiveInfinity; - else if (newBase > 1.0f) - return float.NegativeInfinity; - } - - if (value == float.PositiveInfinity) - { - if (0.0f < newBase && newBase < 1.0f) - return float.NegativeInfinity; - else if (newBase > 1.0f) - return float.PositiveInfinity; - } - - if (value == 1.0f && (newBase == 0.0f || newBase == float.PositiveInfinity)) - return 0.0f; - - return XMath.Log(value) * XMath.Rcp(XMath.Log(newBase)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Log(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Log(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Log10(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Log10(float value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Log2(double value) => - throw new NotImplementedException(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Log2(float value) => - throw new NotImplementedException(); - - #endregion - } -} diff --git a/Src/ILGPU/Backends/OpenCL/CLIntrinsics.cs b/Src/ILGPU/Backends/OpenCL/CLIntrinsics.cs index ad312ffe9..1dc5ebd8c 100644 --- a/Src/ILGPU/Backends/OpenCL/CLIntrinsics.cs +++ b/Src/ILGPU/Backends/OpenCL/CLIntrinsics.cs @@ -1,6 +1,6 @@ // --------------------------------------------------------------------------------------- // ILGPU -// Copyright (c) 2020-2021 ILGPU Project +// Copyright (c) 2020-2024 ILGPU Project // www.ilgpu.net // // File: CLIntrinsics.cs @@ -10,9 +10,12 @@ // --------------------------------------------------------------------------------------- using ILGPU.AtomicOperations; +using ILGPU.IR; using ILGPU.IR.Intrinsics; using ILGPU.IR.Values; +using ILGPU.Util; using System; +using System.Reflection; using System.Runtime.CompilerServices; namespace ILGPU.Backends.OpenCL @@ -69,6 +72,21 @@ public static void Register(IntrinsicImplementationManager manager) CreateIntrinsic( nameof(BarrierPopCount), IntrinsicImplementationMode.Redirect)); + + // IntrinsicMath + RegisterBinaryLogMathIntrinsic( + manager, + BasicValueType.Float32, + typeof(float), + typeof(float)); + RegisterBinaryLogMathIntrinsic( + manager, + BasicValueType.Float64, + typeof(double), + typeof(double)); + + RegisterRcpMathIntrinsic(manager, BasicValueType.Float32); + RegisterRcpMathIntrinsic(manager, BasicValueType.Float64); } #endregion @@ -138,5 +156,96 @@ private static int BarrierPopCount(bool predicate) } #endregion + + #region IntrinsicMath + + /// + /// Registers intrinsic for Log with two parameters. + /// + private static void RegisterBinaryLogMathIntrinsic( + IntrinsicImplementationManager manager, + BasicValueType basicValueType, + params Type[] types) + { + var targetMethod = typeof(IntrinsicMath.BinaryLog).GetMethod( + nameof(IntrinsicMath.BinaryLog.Log), + BindingFlags.Public | BindingFlags.Static, + null, + types, + null) + .ThrowIfNull(); + manager.RegisterBinaryArithmetic( + BinaryArithmeticKind.BinaryLogF, + basicValueType, + new CLIntrinsic(targetMethod, IntrinsicImplementationMode.Redirect)); + } + + /// + /// Registers the Rcp intrinsic for the basic value type. + /// + private static void RegisterRcpMathIntrinsic( + IntrinsicImplementationManager manager, + BasicValueType basicValueType) => + manager.RegisterUnaryArithmetic( + UnaryArithmeticKind.RcpF, + basicValueType, + new CLIntrinsic( + typeof(CLIntrinsics).GetMethod( + nameof(GenerateRcpMathIntrinsic), + BindingFlags.NonPublic | BindingFlags.Static).AsNotNull(), + IntrinsicImplementationMode.GenerateCode)); + + /// + /// Generates intrinsic math instructions for the following kinds: + /// Rcp + /// + /// The current backend. + /// The code generator. + /// The value to generate code for. + private static void GenerateRcpMathIntrinsic( + CLBackend backend, + CLCodeGenerator codeGenerator, + Value value) + { + // Manually generate code for "1.0 / argument" + var arithmeticValue = value.AsNotNullCast(); + var argument = codeGenerator.Load(arithmeticValue.Value); + var target = codeGenerator.Allocate(arithmeticValue); + var operation = CLInstructions.GetArithmeticOperation( + BinaryArithmeticKind.Div, + arithmeticValue.BasicValueType.IsFloat(), + out var isFunction); + using var statement = codeGenerator.BeginStatement(target); + statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); + if (isFunction) + { + statement.AppendCommand(operation); + statement.BeginArguments(); + } + else + { + statement.OpenParen(); + } + + statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); + if (arithmeticValue.BasicValueType == BasicValueType.Float32) + statement.AppendConstant(1.0f); + else + statement.AppendConstant(1.0); + + if (!isFunction) + statement.AppendCommand(operation); + + statement.AppendArgument(); + statement.AppendCast(arithmeticValue.ArithmeticBasicValueType); + statement.Append(argument); + + if (isFunction) + statement.EndArguments(); + else + statement.CloseParen(); + } + + #endregion } } diff --git a/Src/ILGPU/IntrinsicMath.BinaryLog.cs b/Src/ILGPU/IntrinsicMath.BinaryLog.cs new file mode 100644 index 000000000..edfc0b5ce --- /dev/null +++ b/Src/ILGPU/IntrinsicMath.BinaryLog.cs @@ -0,0 +1,104 @@ +// --------------------------------------------------------------------------------------- +// ILGPU +// Copyright (c) 2024 ILGPU Project +// www.ilgpu.net +// +// File: IntrinsicMath.BinaryLog.cs +// +// This file is part of ILGPU and is distributed under the University of Illinois Open +// Source License. See LICENSE.txt for details. +// --------------------------------------------------------------------------------------- + +namespace ILGPU +{ + partial class IntrinsicMath + { + /// + /// Contains software implementation for Log with two parameters. + /// + internal static class BinaryLog + { + /// + /// Implements Log with two parameters. + /// + public static double Log(double value, double newBase) + { + if (value < 0.0 || + newBase < 0.0 || + value != 1.0 && newBase == 0.0 || + value != 1.0 && newBase == double.PositiveInfinity || + CPUOnly.IsNaN(value) || + CPUOnly.IsNaN(newBase) || + newBase == 1.0) + { + return double.NaN; + } + + if (value == 0.0) + { + if (0.0 < newBase && newBase < 1.0) + return double.PositiveInfinity; + else if (newBase > 1.0) + return double.NegativeInfinity; + } + + if (value == double.PositiveInfinity) + { + if (0.0 < newBase && newBase < 1.0) + return double.NegativeInfinity; + else if (newBase > 1.0) + return double.PositiveInfinity; + } + + if (value == 1.0 && + (newBase == 0.0 || newBase == double.PositiveInfinity)) + { + return 0.0; + } + + return CPUOnly.Log(value) * CPUOnly.Rcp(CPUOnly.Log(newBase)); + } + + /// + /// Implements Log with two parameters. + /// + public static float Log(float value, float newBase) + { + if (value < 0.0f || + newBase < 0.0f || + value != 1.0f && newBase == 0.0f || + value != 1.0f && newBase == float.PositiveInfinity || + CPUOnly.IsNaN(value) || + CPUOnly.IsNaN(newBase) || + newBase == 1.0f) + { + return float.NaN; + } + + if (value == 0.0f) + { + if (0.0f < newBase && newBase < 1.0f) + return float.PositiveInfinity; + else if (newBase > 1.0f) + return float.NegativeInfinity; + } + + if (value == float.PositiveInfinity) + { + if (0.0f < newBase && newBase < 1.0f) + return float.NegativeInfinity; + else if (newBase > 1.0f) + return float.PositiveInfinity; + } + + if (value == 1.0f && + (newBase == 0.0f || newBase == float.PositiveInfinity)) + { + return 0.0f; + } + + return CPUOnly.Log(value) * CPUOnly.Rcp(CPUOnly.Log(newBase)); + } + } + } +}