Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider codegen improvement for (a + b)/2 #10108

Closed
danmoseley opened this issue Apr 6, 2018 · 5 comments
Closed

Consider codegen improvement for (a + b)/2 #10108

danmoseley opened this issue Apr 6, 2018 · 5 comments
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI optimization
Milestone

Comments

@danmoseley
Copy link
Member

This diff (in a hot path binary search) seemed to give an improvement (albeit so small probably not worth loss in clarity)

-                iMid = (i + iMax) / 2;
+                iMid = (i & iMax) + ((i ^ iMax) >> 1); 

Of course ideally the JIT would take care of whatever the best codegen is. @AndyAyersMS suggested I open an issue here.

dotnet/corefx#28739 (comment)
https://sharplab.io/#v2:EYLgHgbALANALiAhgZwLYB8ACBmABJgJlwGFcBvAWAChdb88BLAOzlwHkAnBgc2cQBsAFM1YMYuERICyiMAEpy1OsvwB2XMNwBqabIUB6XAQDcSugF8ztHBJa4AcgFMA7sLtjbomfMU0V19U0AMl0fHUFNAD1QhQA+WNwARjlTP1pLKnMgA=

@mikedn
Copy link
Contributor

mikedn commented Apr 6, 2018

Just use (i + iMax) >> 1 and call it a day 😄

Note that this particular way of computing the midpoint is problematic due to integer overflow. I suppose this doesn't matter in that particular regex code...

@danmoseley
Copy link
Member Author

Would it be considered an invalid transformation if it avoided integer overflow?

@mikedn
Copy link
Contributor

mikedn commented Apr 7, 2018

Would it be considered an invalid transformation if it avoided integer overflow?

Indeed, this might work in the C/C++ wild west, where integer overflow tends to come together with undefined behavior. However, C# is different in this regard and mandates a certain behavior:

In an unchecked context, overflows are ignored and any high-order bits that do not fit in the destination type are discarded.

I'm not familiar with this fancy way of computing the midpoint but a quick test shows that it does produce a different result than (a + b) / 2:

static int BrokenMid(int a, int b) => (a + b) / 2;
static int BrokenSafeMid(int a, int b) => a + (b - a) / 2;
static int SafeMid(int a, int b) => (int)(a + (uint)(b - a) / 2);
static int FancyMid(int a, int b) => (a & b) + ((a ^ b) >> 1);
static void Main()
{
    int a = int.MinValue;
    int b = int.MaxValue;

    Console.WriteLine(BrokenMid(a, b));
    Console.WriteLine(BrokenSafeMid(a, b));
    Console.WriteLine(SafeMid(a, b));
    Console.WriteLine(FancyMid(a, b));
}

prints

0
-2147483648
-1
-1

Apparently it's equivalent to the safe version. And it has one extra integer operation.

@AntonLapounov
Copy link
Member

As @mikedn mentioned above, for int division those two expressions are not equivalent. For instance, they give different results for (-1, 0) and (1, int.MaxValue) pairs.

@erozenfeld
Copy link
Member

@danmosemsft Looks like this issue can be closed since the proposed transformation is not legal?

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI optimization
Projects
None yet
Development

No branches or pull requests

5 participants