From 9e71e7fe09ba8a60a019f72a054bcc9cbd8cecd5 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 21 Dec 2018 14:07:35 +0100 Subject: [PATCH] Fix #517: Try to reverse constant folding for double and float expressions containing Math.PI and Math.E as factors. --- .../TestCases/Pretty/WellKnownConstants.cs | 70 +++++ .../TestCases/Pretty/WellKnownConstants.il | 64 ++++ .../Pretty/WellKnownConstants.opt.il | 64 ++++ .../Pretty/WellKnownConstants.opt.roslyn.il | 64 ++++ .../Pretty/WellKnownConstants.roslyn.il | 64 ++++ .../CSharp/CSharpDecompiler.cs | 3 +- .../CSharp/Syntax/TypeSystemAstBuilder.cs | 273 +++++++++++++++++- 7 files changed, 599 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs index fe839a7f6..d01cbfa7c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; + namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public class WellKnownConstants @@ -64,5 +66,73 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty public const decimal DecimalMaxValue = decimal.MaxValue; public const decimal DecimalMinValue = decimal.MinValue; + + public const float Float_PI = (float)Math.PI; + public const float Float_HalfOfPI = (float)Math.PI / 2f; + public const float Float_QuarterOfPI = (float)Math.PI / 4f; + public const float Float_PITimes2 = (float)Math.PI * 2f; + public const float Float_3QuartersOfPI = (float)Math.PI * 3f / 4f; + public const float Float_PIDiv360 = (float)Math.PI / 360f; + public const float Float_PIDiv16 = (float)Math.PI / 16f; + public const float Float_PIDiv32 = (float)Math.PI / 32f; + public const float Float_PIInverseFraction = 1f / (float)Math.PI; + public const float Float_PIInverseFraction2 = 2f / (float)Math.PI; + public const float Float_PIInverseFraction5 = 5f / (float)Math.PI; + public const float Float_PITimes90 = (float)Math.PI * 90f; + public const float Float_PITimes180 = (float)Math.PI * 180f; + public const float Float_LooksLikePI = 3.1415925f; + public const float Float_LooksLikePI2 = 3.14159f; + public const float Float_LooksLikePI3 = 3.141f; + public const float Float_Negated_PI = -(float)Math.PI; + public const float Float_Negated_HalfOfPI = -(float)Math.PI / 2f; + public const float Float_Negated_QuarterOfPI = -(float)Math.PI / 4f; + public const float Float_Negated_PITimes2 = (float)Math.PI * -2f; + public const float Float_Negated_3QuartersOfPI = (float)Math.PI * -3f / 4f; + public const float Float_Negated_PIDiv360 = -(float)Math.PI / 360f; + public const float Float_Negated_PIDiv16 = -(float)Math.PI / 16f; + public const float Float_Negated_PIDiv32 = -(float)Math.PI / 32f; + public const float Float_Negated_PIInverseFraction = -1f / (float)Math.PI; + public const float Float_Negated_PIInverseFraction2 = -2f / (float)Math.PI; + public const float Float_Negated_PIInverseFraction5 = -5f / (float)Math.PI; + public const float Float_Negated_PITimes90 = (float)Math.PI * -90f; + public const float Float_Negated_PITimes180 = (float)Math.PI * -180f; + public const float Float_Negated_LooksLikePI = -3.141f; + + public const float Float_E = (float)Math.E; + public const float Float_Negated_E = -(float)Math.E; + + public const double Double_PI = Math.PI; + public const double Double_HalfOfPI = Math.PI / 2.0; + public const double Double_QuarterOfPI = Math.PI / 4.0; + public const double Double_PITimes2 = Math.PI * 2.0; + public const double Double_3QuartersOfPI = Math.PI * 3.0 / 4.0; + public const double Double_PIDiv360 = Math.PI / 360.0; + public const double Double_PIDiv16 = Math.PI / 16.0; + public const double Double_PIDiv32 = Math.PI / 32.0; + public const double Double_PIInverseFraction = 1.0 / Math.PI; + public const double Double_PIInverseFraction2 = 2.0 / Math.PI; + public const double Double_PIInverseFraction5 = 5.0 / Math.PI; + public const double Double_PITimes90 = Math.PI * 90.0; + public const double Double_PITimes180 = Math.PI * 180.0; + public const double Double_LooksLikePI = 3.1415926; + public const double Double_LooksLikePI2 = 3.14159; + public const double Double_LooksLikePI3 = 3.141; + public const double Double_Negated_PI = -Math.PI; + public const double Double_Negated_HalfOfPI = -Math.PI / 2.0; + public const double Double_Negated_QuarterOfPI = -Math.PI / 4.0; + public const double Double_Negated_PITimes2 = Math.PI * -2.0; + public const double Double_Negated_3QuartersOfPI = Math.PI * -3.0 / 4.0; + public const double Double_Negated_PIDiv360 = -Math.PI / 360.0; + public const double Double_Negated_PIDiv16 = -Math.PI / 16.0; + public const double Double_Negated_PIDiv32 = -Math.PI / 32.0; + public const double Double_Negated_PIInverseFraction = -1.0 / Math.PI; + public const double Double_Negated_PIInverseFraction2 = -2.0 / Math.PI; + public const double Double_Negated_PIInverseFraction5 = -5.0 / Math.PI; + public const double Double_Negated_PITimes90 = Math.PI * -90.0; + public const double Double_Negated_PITimes180 = Math.PI * -180.0; + public const double Double_Negated_LooksLikePI = -3.141; + + public const double Double_E = Math.E; + public const double Double_Negated_E = -Math.E; } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.il index fb0d45121..37b6ed0e8 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.il @@ -78,6 +78,70 @@ uint32, uint32) = ( 01 00 00 80 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 ) + .field public static literal float32 Float_PI = float32(3.1415927) + .field public static literal float32 Float_HalfOfPI = float32(1.5707964) + .field public static literal float32 Float_QuarterOfPI = float32(0.78539819) + .field public static literal float32 Float_PITimes2 = float32(6.2831855) + .field public static literal float32 Float_3QuartersOfPI = float32(2.3561945) + .field public static literal float32 Float_PIDiv360 = float32(8.7266462e-003) + .field public static literal float32 Float_PIDiv16 = float32(0.19634955) + .field public static literal float32 Float_PIDiv32 = float32(9.8174773e-002) + .field public static literal float32 Float_PIInverseFraction = float32(0.31830987) + .field public static literal float32 Float_PIInverseFraction2 = float32(0.63661975) + .field public static literal float32 Float_PIInverseFraction5 = float32(1.5915494) + .field public static literal float32 Float_PITimes90 = float32(282.74335) + .field public static literal float32 Float_PITimes180 = float32(565.48669) + .field public static literal float32 Float_LooksLikePI = float32(3.1415925) + .field public static literal float32 Float_LooksLikePI2 = float32(3.1415901) + .field public static literal float32 Float_LooksLikePI3 = float32(3.141) + .field public static literal float32 Float_Negated_PI = float32(-3.1415927) + .field public static literal float32 Float_Negated_HalfOfPI = float32(-1.5707964) + .field public static literal float32 Float_Negated_QuarterOfPI = float32(-0.78539819) + .field public static literal float32 Float_Negated_PITimes2 = float32(-6.2831855) + .field public static literal float32 Float_Negated_3QuartersOfPI = float32(-2.3561945) + .field public static literal float32 Float_Negated_PIDiv360 = float32(-8.7266462e-003) + .field public static literal float32 Float_Negated_PIDiv16 = float32(-0.19634955) + .field public static literal float32 Float_Negated_PIDiv32 = float32(-9.8174773e-002) + .field public static literal float32 Float_Negated_PIInverseFraction = float32(-0.31830987) + .field public static literal float32 Float_Negated_PIInverseFraction2 = float32(-0.63661975) + .field public static literal float32 Float_Negated_PIInverseFraction5 = float32(-1.5915494) + .field public static literal float32 Float_Negated_PITimes90 = float32(-282.74335) + .field public static literal float32 Float_Negated_PITimes180 = float32(-565.48669) + .field public static literal float32 Float_Negated_LooksLikePI = float32(-3.141) + .field public static literal float32 Float_E = float32(2.7182817) + .field public static literal float32 Float_Negated_E = float32(-2.7182817) + .field public static literal float64 Double_PI = float64(3.1415926535897931) + .field public static literal float64 Double_HalfOfPI = float64(1.5707963267948966) + .field public static literal float64 Double_QuarterOfPI = float64(0.78539816339744828) + .field public static literal float64 Double_PITimes2 = float64(6.2831853071795862) + .field public static literal float64 Double_3QuartersOfPI = float64(2.3561944901923448) + .field public static literal float64 Double_PIDiv360 = float64(8.7266462599716477e-003) + .field public static literal float64 Double_PIDiv16 = float64(0.19634954084936207) + .field public static literal float64 Double_PIDiv32 = float64(9.8174770424681035e-002) + .field public static literal float64 Double_PIInverseFraction = float64(0.31830988618379069) + .field public static literal float64 Double_PIInverseFraction2 = float64(0.63661977236758138) + .field public static literal float64 Double_PIInverseFraction5 = float64(1.5915494309189535) + .field public static literal float64 Double_PITimes90 = float64(282.74333882308139) + .field public static literal float64 Double_PITimes180 = float64(565.48667764616278) + .field public static literal float64 Double_LooksLikePI = float64(3.1415926000000001) + .field public static literal float64 Double_LooksLikePI2 = float64(3.1415899999999999) + .field public static literal float64 Double_LooksLikePI3 = float64(3.141) + .field public static literal float64 Double_Negated_PI = float64(-3.1415926535897931) + .field public static literal float64 Double_Negated_HalfOfPI = float64(-1.5707963267948966) + .field public static literal float64 Double_Negated_QuarterOfPI = float64(-0.78539816339744828) + .field public static literal float64 Double_Negated_PITimes2 = float64(-6.2831853071795862) + .field public static literal float64 Double_Negated_3QuartersOfPI = float64(-2.3561944901923448) + .field public static literal float64 Double_Negated_PIDiv360 = float64(-8.7266462599716477e-003) + .field public static literal float64 Double_Negated_PIDiv16 = float64(-0.19634954084936207) + .field public static literal float64 Double_Negated_PIDiv32 = float64(-9.8174770424681035e-002) + .field public static literal float64 Double_Negated_PIInverseFraction = float64(-0.31830988618379069) + .field public static literal float64 Double_Negated_PIInverseFraction2 = float64(-0.63661977236758138) + .field public static literal float64 Double_Negated_PIInverseFraction5 = float64(-1.5915494309189535) + .field public static literal float64 Double_Negated_PITimes90 = float64(-282.74333882308139) + .field public static literal float64 Double_Negated_PITimes180 = float64(-565.48667764616278) + .field public static literal float64 Double_Negated_LooksLikePI = float64(-3.141) + .field public static literal float64 Double_E = float64(2.7182818284590451) + .field public static literal float64 Double_Negated_E = float64(-2.7182818284590451) .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.il index eda9ed8c1..b4623d634 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.il @@ -78,6 +78,70 @@ uint32, uint32) = ( 01 00 00 80 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 ) + .field public static literal float32 Float_PI = float32(3.1415927) + .field public static literal float32 Float_HalfOfPI = float32(1.5707964) + .field public static literal float32 Float_QuarterOfPI = float32(0.78539819) + .field public static literal float32 Float_PITimes2 = float32(6.2831855) + .field public static literal float32 Float_3QuartersOfPI = float32(2.3561945) + .field public static literal float32 Float_PIDiv360 = float32(8.7266462e-003) + .field public static literal float32 Float_PIDiv16 = float32(0.19634955) + .field public static literal float32 Float_PIDiv32 = float32(9.8174773e-002) + .field public static literal float32 Float_PIInverseFraction = float32(0.31830987) + .field public static literal float32 Float_PIInverseFraction2 = float32(0.63661975) + .field public static literal float32 Float_PIInverseFraction5 = float32(1.5915494) + .field public static literal float32 Float_PITimes90 = float32(282.74335) + .field public static literal float32 Float_PITimes180 = float32(565.48669) + .field public static literal float32 Float_LooksLikePI = float32(3.1415925) + .field public static literal float32 Float_LooksLikePI2 = float32(3.1415901) + .field public static literal float32 Float_LooksLikePI3 = float32(3.141) + .field public static literal float32 Float_Negated_PI = float32(-3.1415927) + .field public static literal float32 Float_Negated_HalfOfPI = float32(-1.5707964) + .field public static literal float32 Float_Negated_QuarterOfPI = float32(-0.78539819) + .field public static literal float32 Float_Negated_PITimes2 = float32(-6.2831855) + .field public static literal float32 Float_Negated_3QuartersOfPI = float32(-2.3561945) + .field public static literal float32 Float_Negated_PIDiv360 = float32(-8.7266462e-003) + .field public static literal float32 Float_Negated_PIDiv16 = float32(-0.19634955) + .field public static literal float32 Float_Negated_PIDiv32 = float32(-9.8174773e-002) + .field public static literal float32 Float_Negated_PIInverseFraction = float32(-0.31830987) + .field public static literal float32 Float_Negated_PIInverseFraction2 = float32(-0.63661975) + .field public static literal float32 Float_Negated_PIInverseFraction5 = float32(-1.5915494) + .field public static literal float32 Float_Negated_PITimes90 = float32(-282.74335) + .field public static literal float32 Float_Negated_PITimes180 = float32(-565.48669) + .field public static literal float32 Float_Negated_LooksLikePI = float32(-3.141) + .field public static literal float32 Float_E = float32(2.7182817) + .field public static literal float32 Float_Negated_E = float32(-2.7182817) + .field public static literal float64 Double_PI = float64(3.1415926535897931) + .field public static literal float64 Double_HalfOfPI = float64(1.5707963267948966) + .field public static literal float64 Double_QuarterOfPI = float64(0.78539816339744828) + .field public static literal float64 Double_PITimes2 = float64(6.2831853071795862) + .field public static literal float64 Double_3QuartersOfPI = float64(2.3561944901923448) + .field public static literal float64 Double_PIDiv360 = float64(8.7266462599716477e-003) + .field public static literal float64 Double_PIDiv16 = float64(0.19634954084936207) + .field public static literal float64 Double_PIDiv32 = float64(9.8174770424681035e-002) + .field public static literal float64 Double_PIInverseFraction = float64(0.31830988618379069) + .field public static literal float64 Double_PIInverseFraction2 = float64(0.63661977236758138) + .field public static literal float64 Double_PIInverseFraction5 = float64(1.5915494309189535) + .field public static literal float64 Double_PITimes90 = float64(282.74333882308139) + .field public static literal float64 Double_PITimes180 = float64(565.48667764616278) + .field public static literal float64 Double_LooksLikePI = float64(3.1415926000000001) + .field public static literal float64 Double_LooksLikePI2 = float64(3.1415899999999999) + .field public static literal float64 Double_LooksLikePI3 = float64(3.141) + .field public static literal float64 Double_Negated_PI = float64(-3.1415926535897931) + .field public static literal float64 Double_Negated_HalfOfPI = float64(-1.5707963267948966) + .field public static literal float64 Double_Negated_QuarterOfPI = float64(-0.78539816339744828) + .field public static literal float64 Double_Negated_PITimes2 = float64(-6.2831853071795862) + .field public static literal float64 Double_Negated_3QuartersOfPI = float64(-2.3561944901923448) + .field public static literal float64 Double_Negated_PIDiv360 = float64(-8.7266462599716477e-003) + .field public static literal float64 Double_Negated_PIDiv16 = float64(-0.19634954084936207) + .field public static literal float64 Double_Negated_PIDiv32 = float64(-9.8174770424681035e-002) + .field public static literal float64 Double_Negated_PIInverseFraction = float64(-0.31830988618379069) + .field public static literal float64 Double_Negated_PIInverseFraction2 = float64(-0.63661977236758138) + .field public static literal float64 Double_Negated_PIInverseFraction5 = float64(-1.5915494309189535) + .field public static literal float64 Double_Negated_PITimes90 = float64(-282.74333882308139) + .field public static literal float64 Double_Negated_PITimes180 = float64(-565.48667764616278) + .field public static literal float64 Double_Negated_LooksLikePI = float64(-3.141) + .field public static literal float64 Double_E = float64(2.7182818284590451) + .field public static literal float64 Double_Negated_E = float64(-2.7182818284590451) .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.roslyn.il index ed7f96787..534c4085a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.opt.roslyn.il @@ -82,6 +82,70 @@ uint32, uint32) = ( 01 00 00 80 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 ) + .field public static literal float32 Float_PI = float32(3.1415927) + .field public static literal float32 Float_HalfOfPI = float32(1.5707964) + .field public static literal float32 Float_QuarterOfPI = float32(0.78539819) + .field public static literal float32 Float_PITimes2 = float32(6.2831855) + .field public static literal float32 Float_3QuartersOfPI = float32(2.3561945) + .field public static literal float32 Float_PIDiv360 = float32(8.7266462e-003) + .field public static literal float32 Float_PIDiv16 = float32(0.19634955) + .field public static literal float32 Float_PIDiv32 = float32(9.8174773e-002) + .field public static literal float32 Float_PIInverseFraction = float32(0.31830987) + .field public static literal float32 Float_PIInverseFraction2 = float32(0.63661975) + .field public static literal float32 Float_PIInverseFraction5 = float32(1.5915494) + .field public static literal float32 Float_PITimes90 = float32(282.74335) + .field public static literal float32 Float_PITimes180 = float32(565.48669) + .field public static literal float32 Float_LooksLikePI = float32(3.1415925) + .field public static literal float32 Float_LooksLikePI2 = float32(3.1415901) + .field public static literal float32 Float_LooksLikePI3 = float32(3.141) + .field public static literal float32 Float_Negated_PI = float32(-3.1415927) + .field public static literal float32 Float_Negated_HalfOfPI = float32(-1.5707964) + .field public static literal float32 Float_Negated_QuarterOfPI = float32(-0.78539819) + .field public static literal float32 Float_Negated_PITimes2 = float32(-6.2831855) + .field public static literal float32 Float_Negated_3QuartersOfPI = float32(-2.3561945) + .field public static literal float32 Float_Negated_PIDiv360 = float32(-8.7266462e-003) + .field public static literal float32 Float_Negated_PIDiv16 = float32(-0.19634955) + .field public static literal float32 Float_Negated_PIDiv32 = float32(-9.8174773e-002) + .field public static literal float32 Float_Negated_PIInverseFraction = float32(-0.31830987) + .field public static literal float32 Float_Negated_PIInverseFraction2 = float32(-0.63661975) + .field public static literal float32 Float_Negated_PIInverseFraction5 = float32(-1.5915494) + .field public static literal float32 Float_Negated_PITimes90 = float32(-282.74335) + .field public static literal float32 Float_Negated_PITimes180 = float32(-565.48669) + .field public static literal float32 Float_Negated_LooksLikePI = float32(-3.141) + .field public static literal float32 Float_E = float32(2.7182817) + .field public static literal float32 Float_Negated_E = float32(-2.7182817) + .field public static literal float64 Double_PI = float64(3.1415926535897931) + .field public static literal float64 Double_HalfOfPI = float64(1.5707963267948966) + .field public static literal float64 Double_QuarterOfPI = float64(0.78539816339744828) + .field public static literal float64 Double_PITimes2 = float64(6.2831853071795862) + .field public static literal float64 Double_3QuartersOfPI = float64(2.3561944901923448) + .field public static literal float64 Double_PIDiv360 = float64(8.7266462599716477e-003) + .field public static literal float64 Double_PIDiv16 = float64(0.19634954084936207) + .field public static literal float64 Double_PIDiv32 = float64(9.8174770424681035e-002) + .field public static literal float64 Double_PIInverseFraction = float64(0.31830988618379069) + .field public static literal float64 Double_PIInverseFraction2 = float64(0.63661977236758138) + .field public static literal float64 Double_PIInverseFraction5 = float64(1.5915494309189535) + .field public static literal float64 Double_PITimes90 = float64(282.74333882308139) + .field public static literal float64 Double_PITimes180 = float64(565.48667764616278) + .field public static literal float64 Double_LooksLikePI = float64(3.1415926000000001) + .field public static literal float64 Double_LooksLikePI2 = float64(3.1415899999999999) + .field public static literal float64 Double_LooksLikePI3 = float64(3.141) + .field public static literal float64 Double_Negated_PI = float64(-3.1415926535897931) + .field public static literal float64 Double_Negated_HalfOfPI = float64(-1.5707963267948966) + .field public static literal float64 Double_Negated_QuarterOfPI = float64(-0.78539816339744828) + .field public static literal float64 Double_Negated_PITimes2 = float64(-6.2831853071795862) + .field public static literal float64 Double_Negated_3QuartersOfPI = float64(-2.3561944901923448) + .field public static literal float64 Double_Negated_PIDiv360 = float64(-8.7266462599716477e-003) + .field public static literal float64 Double_Negated_PIDiv16 = float64(-0.19634954084936207) + .field public static literal float64 Double_Negated_PIDiv32 = float64(-9.8174770424681035e-002) + .field public static literal float64 Double_Negated_PIInverseFraction = float64(-0.31830988618379069) + .field public static literal float64 Double_Negated_PIInverseFraction2 = float64(-0.63661977236758138) + .field public static literal float64 Double_Negated_PIInverseFraction5 = float64(-1.5915494309189535) + .field public static literal float64 Double_Negated_PITimes90 = float64(-282.74333882308139) + .field public static literal float64 Double_Negated_PITimes180 = float64(-565.48667764616278) + .field public static literal float64 Double_Negated_LooksLikePI = float64(-3.141) + .field public static literal float64 Double_E = float64(2.7182818284590451) + .field public static literal float64 Double_Negated_E = float64(-2.7182818284590451) .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.roslyn.il index 445c5dd16..f4f77372a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.roslyn.il @@ -82,6 +82,70 @@ uint32, uint32) = ( 01 00 00 80 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 ) + .field public static literal float32 Float_PI = float32(3.1415927) + .field public static literal float32 Float_HalfOfPI = float32(1.5707964) + .field public static literal float32 Float_QuarterOfPI = float32(0.78539819) + .field public static literal float32 Float_PITimes2 = float32(6.2831855) + .field public static literal float32 Float_3QuartersOfPI = float32(2.3561945) + .field public static literal float32 Float_PIDiv360 = float32(8.7266462e-003) + .field public static literal float32 Float_PIDiv16 = float32(0.19634955) + .field public static literal float32 Float_PIDiv32 = float32(9.8174773e-002) + .field public static literal float32 Float_PIInverseFraction = float32(0.31830987) + .field public static literal float32 Float_PIInverseFraction2 = float32(0.63661975) + .field public static literal float32 Float_PIInverseFraction5 = float32(1.5915494) + .field public static literal float32 Float_PITimes90 = float32(282.74335) + .field public static literal float32 Float_PITimes180 = float32(565.48669) + .field public static literal float32 Float_LooksLikePI = float32(3.1415925) + .field public static literal float32 Float_LooksLikePI2 = float32(3.1415901) + .field public static literal float32 Float_LooksLikePI3 = float32(3.141) + .field public static literal float32 Float_Negated_PI = float32(-3.1415927) + .field public static literal float32 Float_Negated_HalfOfPI = float32(-1.5707964) + .field public static literal float32 Float_Negated_QuarterOfPI = float32(-0.78539819) + .field public static literal float32 Float_Negated_PITimes2 = float32(-6.2831855) + .field public static literal float32 Float_Negated_3QuartersOfPI = float32(-2.3561945) + .field public static literal float32 Float_Negated_PIDiv360 = float32(-8.7266462e-003) + .field public static literal float32 Float_Negated_PIDiv16 = float32(-0.19634955) + .field public static literal float32 Float_Negated_PIDiv32 = float32(-9.8174773e-002) + .field public static literal float32 Float_Negated_PIInverseFraction = float32(-0.31830987) + .field public static literal float32 Float_Negated_PIInverseFraction2 = float32(-0.63661975) + .field public static literal float32 Float_Negated_PIInverseFraction5 = float32(-1.5915494) + .field public static literal float32 Float_Negated_PITimes90 = float32(-282.74335) + .field public static literal float32 Float_Negated_PITimes180 = float32(-565.48669) + .field public static literal float32 Float_Negated_LooksLikePI = float32(-3.141) + .field public static literal float32 Float_E = float32(2.7182817) + .field public static literal float32 Float_Negated_E = float32(-2.7182817) + .field public static literal float64 Double_PI = float64(3.1415926535897931) + .field public static literal float64 Double_HalfOfPI = float64(1.5707963267948966) + .field public static literal float64 Double_QuarterOfPI = float64(0.78539816339744828) + .field public static literal float64 Double_PITimes2 = float64(6.2831853071795862) + .field public static literal float64 Double_3QuartersOfPI = float64(2.3561944901923448) + .field public static literal float64 Double_PIDiv360 = float64(8.7266462599716477e-003) + .field public static literal float64 Double_PIDiv16 = float64(0.19634954084936207) + .field public static literal float64 Double_PIDiv32 = float64(9.8174770424681035e-002) + .field public static literal float64 Double_PIInverseFraction = float64(0.31830988618379069) + .field public static literal float64 Double_PIInverseFraction2 = float64(0.63661977236758138) + .field public static literal float64 Double_PIInverseFraction5 = float64(1.5915494309189535) + .field public static literal float64 Double_PITimes90 = float64(282.74333882308139) + .field public static literal float64 Double_PITimes180 = float64(565.48667764616278) + .field public static literal float64 Double_LooksLikePI = float64(3.1415926000000001) + .field public static literal float64 Double_LooksLikePI2 = float64(3.1415899999999999) + .field public static literal float64 Double_LooksLikePI3 = float64(3.141) + .field public static literal float64 Double_Negated_PI = float64(-3.1415926535897931) + .field public static literal float64 Double_Negated_HalfOfPI = float64(-1.5707963267948966) + .field public static literal float64 Double_Negated_QuarterOfPI = float64(-0.78539816339744828) + .field public static literal float64 Double_Negated_PITimes2 = float64(-6.2831853071795862) + .field public static literal float64 Double_Negated_3QuartersOfPI = float64(-2.3561944901923448) + .field public static literal float64 Double_Negated_PIDiv360 = float64(-8.7266462599716477e-003) + .field public static literal float64 Double_Negated_PIDiv16 = float64(-0.19634954084936207) + .field public static literal float64 Double_Negated_PIDiv32 = float64(-9.8174770424681035e-002) + .field public static literal float64 Double_Negated_PIInverseFraction = float64(-0.31830988618379069) + .field public static literal float64 Double_Negated_PIInverseFraction2 = float64(-0.63661977236758138) + .field public static literal float64 Double_Negated_PIInverseFraction5 = float64(-1.5915494309189535) + .field public static literal float64 Double_Negated_PITimes90 = float64(-282.74333882308139) + .field public static literal float64 Double_Negated_PITimes180 = float64(-565.48667764616278) + .field public static literal float64 Double_Negated_LooksLikePI = float64(-3.141) + .field public static literal float64 Double_E = float64(2.7182818284590451) + .field public static literal float64 Double_Negated_E = float64(-2.7182818284590451) .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 8f905b06c..730d30560 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1271,7 +1271,8 @@ namespace ICSharpCode.Decompiler.CSharp enumDec.AddAnnotation(new MemberResolveResult(null, field)); return enumDec; } - typeSystemAstBuilder.UseSpecialConstants = !field.DeclaringType.Equals(field.ReturnType); + bool isMathPIOrE = ((field.Name == "PI" || field.Name == "E") && (field.DeclaringType.FullName == "System.Math" || field.DeclaringType.FullName == "System.MathF")); + typeSystemAstBuilder.UseSpecialConstants = !(field.DeclaringType.Equals(field.ReturnType) || isMathPIOrE); var fieldDecl = typeSystemAstBuilder.ConvertEntity(field); SetNewModifier(fieldDecl); if (settings.FixedBuffers && IsFixedField(field, out var elementType, out var elementCount)) { diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 575306478..5cc27e19e 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -713,6 +713,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax } else { if (IsSpecialConstant(type, constantValue, out var expr)) return expr; + if (type.IsKnownType(KnownTypeCode.Double) || type.IsKnownType(KnownTypeCode.Single)) + return ConvertFloatingPointLiteral(type, constantValue); IType literalType = type; bool smallInteger = type.IsCSharpSmallIntegerType(); if (smallInteger) { @@ -915,9 +917,276 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax } return new CastExpression(ConvertType(type), new PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false))); } - + + static bool IsValidFraction(long num, long den) + { + if (!(den > 0 && num != 0)) + return false; + + if (den == 1 || Math.Abs(num) == 1) + return true; + return Math.Abs(num) < den && new int[] { 2, 3, 5 }.Any(x => den % x == 0); + } + + const int MAX_DENOMINATOR = 1000; + + const double DOUBLE_THRESHOLD = 1e-10; + const float FLOAT_THRESHOLD = 1e-10f; + + Expression ConvertFloatingPointLiteral(IType type, object constantValue) + { + bool isDouble = type.IsKnownType(KnownTypeCode.Double); + ICompilation compilation = type.GetDefinition().Compilation; + Expression expr = null; + + if (isDouble) { + if ((double)constantValue >= int.MaxValue || (double)constantValue <= int.MinValue) { + expr = new PrimitiveExpression(constantValue); + } + } else { + if ((float)constantValue >= int.MaxValue || (float)constantValue <= int.MinValue) { + expr = new PrimitiveExpression(constantValue); + } + } + + if (expr == null && UseSpecialConstants) { + IType mathType; + if (isDouble) + mathType = compilation.FindType(typeof(Math)); + else + mathType = compilation.FindType(new TopLevelTypeName("System", "MathF")).GetDefinition() + ?? compilation.FindType(typeof(Math)); + + expr = TryExtractExpression(mathType, type, constantValue, "PI", isDouble) + ?? TryExtractExpression(mathType, type, constantValue, "E", isDouble); + } + + if (expr == null) { + (long num, long den) = isDouble + ? DoubleFractionApprox((double)constantValue, MAX_DENOMINATOR) + : FloatFractionApprox((float)constantValue, MAX_DENOMINATOR); + + if (IsValidFraction(num, den) && Math.Abs(num) != 1 && Math.Abs(den) != 1) { + var left = MakeConstant(type, num); + var right = MakeConstant(type, den); + return new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction() + .WithRR(new ConstantResolveResult(type, constantValue)); + } + } + + if (expr == null) + expr = new PrimitiveExpression(constantValue); + + if (AddResolveResultAnnotations) + expr.AddAnnotation(new ConstantResolveResult(type, constantValue)); + + return expr; + } + + Expression MakeConstant(IType type, long c) + { + return new PrimitiveExpression(CSharpPrimitiveCast.Cast(type.GetTypeCode(), c, checkForOverflow: true)); + } + + const float MathF_PI = 3.14159274f; + const float MathF_E = 2.71828175f; + + Expression TryExtractExpression(IType mathType, IType type, object literalValue, string memberName, bool isDouble) + { + Expression MakeFieldReference() + { + AstType mathAstType = ConvertType(mathType); + var fieldRef = new MemberReferenceExpression(new TypeReferenceExpression(mathAstType), memberName); + if (AddResolveResultAnnotations) + fieldRef.WithRR(new MemberResolveResult(mathAstType.GetResolveResult(), mathType.GetFields(f => f.Name == memberName).Single())); + if (type.IsKnownType(KnownTypeCode.Double)) + return fieldRef; + if (mathType.Name == "MathF") + return fieldRef; + return new CastExpression(ConvertType(type), fieldRef); + } + + Expression ExtractExpression(long n, long d) + { + Expression fieldReference = MakeFieldReference(); + + Expression expr = fieldReference; + + if (n != 1) { + if (n == -1) { + expr = new UnaryOperatorExpression(UnaryOperatorType.Minus, expr); + } else { + expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Multiply, MakeConstant(type, n)); + } + } + + if (d != 1) { + expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, MakeConstant(type, d)); + } + + if (isDouble) { + if (Math.Abs((double)literalValue - (memberName == "PI" ? Math.PI : Math.E) * n / d) < DOUBLE_THRESHOLD) + return expr; + } else { + float approxValue = (memberName == "PI" ? MathF_PI : MathF_E) * n / d; + float diff = (float)literalValue - approxValue; + if ((float)Math.Abs(diff) < FLOAT_THRESHOLD) + return expr; + } + + expr = fieldReference.Detach(); + expr = new BinaryOperatorExpression(MakeConstant(type, n), BinaryOperatorType.Divide, expr); + + if (d != 1) { + expr = new BinaryOperatorExpression(MakeConstant(type, d), BinaryOperatorType.Multiply, expr); + } + + if (isDouble) { + if (Math.Abs((double)literalValue - (n / (d * (memberName == "PI" ? Math.PI : Math.E)))) < DOUBLE_THRESHOLD) + return expr; + } else { + float approxValue = n / (d * (memberName == "PI" ? MathF_PI : MathF_E)); + float diff = (float)literalValue - approxValue; + if ((float)Math.Abs(diff) < FLOAT_THRESHOLD) + return expr; + } + + return null; + } + + (long num, long den) = isDouble + ? DoubleFractionApprox((double)literalValue / (memberName == "PI" ? Math.PI : Math.E), MAX_DENOMINATOR) + : FloatFractionApprox((float)literalValue / (memberName == "PI" ? MathF_PI : MathF_E), MAX_DENOMINATOR); + + if (IsValidFraction(num, den)) { + return ExtractExpression(num, den); + } + + (num, den) = isDouble + ? DoubleFractionApprox((double)literalValue * (memberName == "PI" ? Math.PI : Math.E), MAX_DENOMINATOR) + : FloatFractionApprox((float)literalValue * (memberName == "PI" ? MathF_PI : MathF_E), MAX_DENOMINATOR); + + if (IsValidFraction(num, den)) { + return ExtractExpression(num, den); + } + + return null; + } + + #region FractionApprox + // based on https://www.ics.uci.edu/~eppstein/numth/frap.c + // find rational approximation to given real number + // David Eppstein / UC Irvine / 8 Aug 1993 + // + // With corrections from Arno Formella, May 2008 + // + // usage: a.out r d + // r is real number to approx + // d is the maximum denominator allowed + // + // based on the theory of continued fractions + // if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...))) + // then best approximation is found by truncating this series + // (with some adjustments in the last term). + // + // Note the fraction can be recovered as the first column of the matrix + // ( a1 1 ) ( a2 1 ) ( a3 1 ) ... + // ( 1 0 ) ( 1 0 ) ( 1 0 ) + // Instead of keeping the sequence of continued fraction terms, + // we just keep the last partial product of these matrices. + static (long Num, long Den) DoubleFractionApprox(double value, int maxDenominator) + { + if (value > 0x7FFFFFFF) + return (0, 0); + + double startValue = value; + if (value < 0) + value = -value; + bool IsValid(long num, long den) => den > 0 && (double)Math.Abs(value - num / (double)den) < DOUBLE_THRESHOLD; + + long ai; + long[,] m = new long[2, 2]; + + m[0, 0] = m[1, 1] = 1; + m[0, 1] = m[1, 0] = 0; + + double v = value; + + while (m[1, 0] * (ai = (long)v) + m[1, 1] <= maxDenominator) { + long t = m[0, 0] * ai + m[0, 1]; + m[0, 1] = m[0, 0]; + m[0, 0] = t; + t = m[1, 0] * ai + m[1, 1]; + m[1, 1] = m[1, 0]; + m[1, 0] = t; + if (v - ai == 0) break; + v = 1 / (v - ai); + if (Math.Abs(v) > long.MaxValue) break; // value cannot be stored in fraction without overflow + } + + if (m[1, 0] == 0) + return (0, 0); + + if (!IsValid(num: m[0, 0], den: m[1, 0])) { + ai = (maxDenominator - m[1, 1]) / m[1, 0]; + m[0, 0] = m[0, 0] * ai + m[0, 1]; + m[1, 0] = m[1, 0] * ai + m[1, 1]; + } + + if (!IsValid(num: m[0, 0], den: m[1, 0])) + return (0, 0); + + return ((startValue < 0 ? -m[0, 0] : m[0, 0]), m[1, 0]); + } + + static (long Num, long Den) FloatFractionApprox(float value, int maxDenominator) + { + if (value > 0x7FFFFFFF) + return (0, 0); + + float startValue = value; + if (value < 0) + value = -value; + + bool IsValid(long num, long den) => den > 0 && (float)Math.Abs(value - num / (float)den) < 1e-9f; + + long ai; + long[,] m = new long[2, 2]; + + m[0, 0] = m[1, 1] = 1; + m[0, 1] = m[1, 0] = 0; + + float v = value; + + while (m[1, 0] * (ai = (long)v) + m[1, 1] <= maxDenominator) { + long t = m[0, 0] * ai + m[0, 1]; + m[0, 1] = m[0, 0]; + m[0, 0] = t; + t = m[1, 0] * ai + m[1, 1]; + m[1, 1] = m[1, 0]; + m[1, 0] = t; + if (v - ai == 0) break; + v = 1 / (v - ai); + if (Math.Abs(v) > long.MaxValue) break; // value cannot be stored in fraction without overflow + } + + if (m[1, 0] == 0) + return (0, 0); + + if (!IsValid(num: m[0, 0], den: m[1, 0])) { + ai = (maxDenominator - m[1, 1]) / m[1, 0]; + m[0, 0] = m[0, 0] * ai + m[0, 1]; + m[1, 0] = m[1, 0] * ai + m[1, 1]; + } + + if (!IsValid(num: m[0, 0], den: m[1, 0])) + return (0, 0); + + return (startValue < 0 ? -m[0, 0] : m[0, 0], m[1, 0]); + } #endregion - + #endregion + #region Convert Parameter public ParameterDeclaration ConvertParameter(IParameter parameter) {