You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[RyuJIT] Div then Mod (or viceversa) executes idiv twice instead of using the value in the register #5213
Div and mod have nothing to do with addressing, that's always done with add and mul. You're probably talking about something else.
Div and mod are pretty useful to recover row/column information from indices:
int index = row * width + col;
...
int row = index / width;
int col = index % width;
Mostly when you are treating a singular array as a 2D array (eg. through usage of Bitmap.LockBits).
That said, it's not very common, but not extremely rare either.
Reacted by Viktor Tselov, Amr, salehjafarli, Cole Tobin and Yegor
@mikedn It is if you are working with stride based binary structures as @JanielS mentioned. I would mention too, that when you are dealing with building data structures using memory maps (therefore unsafe code), it is a pretty common thing to happen.
It is if you are working with stride based binary structures as @JanielS mentioned.
What @JanielS shows is not so common and certainly not related to the notion of "addressing modes" as used in compilers. More generally, accessing matrix elements has nothing to do with division and modulo. The offset of a matrix element is simply row * stride + column. Sure, there may be special/unusual/whatever cases that requires division and modulo but it's a long way from such cases to "Everywhere you have a row and a column, you will have such an structure.".
Putting all in the context of the assembly/compiler use is why you are seeing it as special/unusual, where it is not. This pattern is usually hidden in plain sight, it is so common and used, that is very easy to overlook. Only in certain places you will see both together because that means you are trying to retrieve both values at the same time instead of accessing it using a for loop.
Any update on if we are going to see this anytime soon?
And the code that generates it.
This is actual code I cannot get away with, I will probably try to tweak it to reduce dependencies, but that's it. This is killing me, if I can get even 5% would be a huge win. :)
EDIT: All the program in context (marked in red address translations - div/mod heavy
Does BlocksPerPage change often? I would guess that it doesn't, it's fixed for a given BTree. If that's the case then you could use reciprocal division, it would likely be better than the JIT removing a redundant idiv.
@mikedn That's a great idea, I can probably pack 8 to 10 multiplications before paying for an idiv even more with 2 of them, I can do almost whatever I want and still probably win. Do you have any good resource on how to efficiently deal with a "sorta" fixed (but not constant) divisor?
Before eliminating division you should eliminate the reminder. n % d is simply n - (n / d) * d. You already have n / d so to compute % you only need a - and a * and these are very cheap compared to %. Come to think of it, the JIT could probably do this automatically if it turns out that removing the redundant idiv is problematic due to the multiple register issue.
Now, getting rid of the division completely may or may not be feasible. For a given denominator you have to store 2 numbers somewhere - a "magic" number and a shift count. Computing these 2 numbers is expensive so if you can't store them somewhere this won't work.
The exacts details can be found here, in the "Exact division by constants" section. To make your life easier you could simply pick up existing code from a compiler. RyuJIT has an implementation and I extracted it here.
It's not as fast as I hoped but it's still ~1.5x faster than division. The code generated by the compiler when the denominator is actually a constant is faster (3x) but that's expected, for example that code doesn't have to deal with positive/negative magic numbers at runtime.
Note that this implementation only works for positive numbers, supporting negative numbers makes MagicDiv more complicated and probably slower.
Before eliminating division you should eliminate the reminder. n % d is simply n - (n / d) * d. You already have n / d so to compute % you only need a - and a * and these are very cheap compared to %. Come to think of it, the JIT could probably do this automatically if it turns out that removing the redundant idiv is problematic due to the multiple register issue.
Activity
mikedn commentedon Mar 1, 2016
Related to #4155
mikedn commentedon Mar 1, 2016
Div and mod have nothing to do with addressing, that's always done with add and mul. You're probably talking about something else.
jakobbotsch commentedon Mar 1, 2016
Div and mod are pretty useful to recover row/column information from indices:
Mostly when you are treating a singular array as a 2D array (eg. through usage of
Bitmap.LockBits).That said, it's not very common, but not extremely rare either.
redknightlois commentedon Mar 1, 2016
@mikedn It is if you are working with stride based binary structures as @JanielS mentioned. I would mention too, that when you are dealing with building data structures using memory maps (therefore unsafe code), it is a pretty common thing to happen.
redknightlois commentedon Mar 1, 2016
@mikedn Actually this is a duplicate of #4155. I would have never though about calling it
DivRemthat's why I havent found it.@CarolEidt Is the limitation of using multiple registers per single instruction still relevant?
CarolEidt commentedon Mar 1, 2016
Yes, the multiple register issue is still relevant, but likely something we will soon be addressing.
mikedn commentedon Mar 1, 2016
What @JanielS shows is not so common and certainly not related to the notion of "addressing modes" as used in compilers. More generally, accessing matrix elements has nothing to do with division and modulo. The offset of a matrix element is simply
row * stride + column. Sure, there may be special/unusual/whatever cases that requires division and modulo but it's a long way from such cases to "Everywhere you have a row and a column, you will have such an structure.".redknightlois commentedon Mar 1, 2016
@mikedn They are just two sides of the same coin.
and
Putting all in the context of the assembly/compiler use is why you are seeing it as special/unusual, where it is not. This pattern is usually hidden in plain sight, it is so common and used, that is very easy to overlook. Only in certain places you will see both together because that means you are trying to retrieve both values at the same time instead of accessing it using a for loop.
redknightlois commentedon Nov 11, 2016
Any update on if we are going to see this anytime soon?
And the code that generates it.
This is actual code I cannot get away with, I will probably try to tweak it to reduce dependencies, but that's it. This is killing me, if I can get even 5% would be a huge win. :)
EDIT: All the program in context (marked in red address translations - div/mod heavy
)
cc @AndyAyersMS
mikedn commentedon Nov 11, 2016
Does
BlocksPerPagechange often? I would guess that it doesn't, it's fixed for a given BTree. If that's the case then you could use reciprocal division, it would likely be better than the JIT removing a redundantidiv.redknightlois commentedon Nov 11, 2016
@mikedn That's a great idea, I can probably pack 8 to 10 multiplications before paying for an
idiveven more with 2 of them, I can do almost whatever I want and still probably win. Do you have any good resource on how to efficiently deal with a "sorta" fixed (but not constant) divisor?mikedn commentedon Nov 12, 2016
Before eliminating division you should eliminate the reminder.
n % dis simplyn - (n / d) * d. You already haven / dso to compute%you only need a-and a*and these are very cheap compared to%. Come to think of it, the JIT could probably do this automatically if it turns out that removing the redundantidivis problematic due to the multiple register issue.Now, getting rid of the division completely may or may not be feasible. For a given denominator you have to store 2 numbers somewhere - a "magic" number and a shift count. Computing these 2 numbers is expensive so if you can't store them somewhere this won't work.
The exacts details can be found here, in the "Exact division by constants" section. To make your life easier you could simply pick up existing code from a compiler. RyuJIT has an implementation and I extracted it here.
It's not as fast as I hoped but it's still ~1.5x faster than division. The code generated by the compiler when the denominator is actually a constant is faster (3x) but that's expected, for example that code doesn't have to deal with positive/negative magic numbers at runtime.
Note that this implementation only works for positive numbers, supporting negative numbers makes
MagicDivmore complicated and probably slower.redknightlois commentedon Nov 12, 2016
@mikedn I can do that on tree creation and just store it and be done with it :).
stephentoub commentedon Nov 14, 2016
Until there's a solution for this in the JIT, should:
https://github.com/dotnet/coreclr/blob/f8b8b6ab80f1c5b30cc04676ca2e084ce200161e/src/mscorlib/src/System/Math.cs#L733
be changed from:
to:
? (And the same for the Int32 overload.)
redknightlois commentedon Nov 14, 2016
@stephentoub Yes, it should. I can confirm that the performance of using the multiplication in the second case (in my case) has been huge.
16 remaining items
svick commentedon Sep 26, 2022
@pentp Would
RuntimeHelpers.IsKnownConstanthelp with that?pentp commentedon Sep 26, 2022
Probably yes, but for long/ulong needs #67285 (or part of it).
TIHan commentedon Jan 28, 2023
Related: #4155
More optimized remainder calculation
More optimized remainder calculation (#273)
Add some TODO dotnet#5213 comments for