Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

[arm64] Disable a % b = a & (b - 1); optimization. #18206

Merged
merged 3 commits into from
Jun 1, 2018

Conversation

sandreenko
Copy link

@sandreenko sandreenko commented May 30, 2018

Morph can't relay on Lower optimization that it can't guarantee.

In this test case we have such tree:

               [000041] ------------                   /--*  CAST      long <- int
               [000040] ------------                   |  \--*  CNS_INT   int    1
               [000042] ---X--------                /--*  UMOD      long  
			                                              / *** 
               [000024] ---X--------                |  \--*  MUL       long
			                                              \ ***

Moprh thinks that Lower will optimize it as a % b = a & (b - 1); , but then a tree is found to be a constant:

N034 (  1,  1) [000041] ------------                      /--*  CNS_INT   long   1 $182
N035 ( 36, 24) [000042] -A-X--------                   /--*  UMOD      long   $287
N032 (  1,  1) [000023] ------------                   |  /--*  CNS_INT   long   0 $180
N033 ( 34, 22) [000024] -A-X--------                   \--*  COMMA     long
                                                          \ *** 

and Lower rejects optimizing a % b when both operands are const.

It cases assert during Lsra: assert(!"Shouldn't see an integer typed GT_MOD node in ARM64");

The fix is similar to #17338.

Fixes #17968.

PR #15690 can help to return this optimization back.

Sergey Andreenko added 2 commits May 30, 2018 13:49
It was copied wrong previously.
Morph can't relay on Lower optimization that it can't guarantee.
@sandreenko sandreenko added bug Product bug (most likely) area-CodeGen arch-arm64 labels May 30, 2018
@sandreenko sandreenko changed the title Disable a % b = a & (b - 1); optimization on arm64 [arm64] Disable a % b = a & (b - 1); optimization. May 30, 2018
@sandreenko
Copy link
Author

sandreenko commented May 30, 2018

@dotnet-bot test Windows_NT x64_arm64_altjit Checked r2r_jitstress1
@dotnet-bot test Windows_NT x64_arm64_altjit Checked r2r_jitstressregs1
@dotnet-bot test Windows_NT x64_arm64_altjit Checked r2r_jitstress2
@dotnet-bot test Windows_NT x64_arm64_altjit Checked jitstress2
@dotnet-bot test Windows_NT x86_arm_altjit Checked jitstress2_jitstressregs0x1000

@mikedn
Copy link

mikedn commented May 30, 2018

and Lower rejects optimizing a % b when both operands are const.

The reason why Lower doesn't do anything in this case is somewhat artificial. I expected that constant folding would handle such cases so that there's no reason to reproduce that logic in lowering.

But there's nothing stopping lowering from doing it and it's IMO its responsibility to produce IR suitable for the target CPU. In the particular case of c % 0 it could simply change it to c / 0 or whatever IR is suitable for the ARM codegen.

PR #15690 can help to return this optimization back.

That seems unrelated since MOD/UMOD are AFAIK not turned into helper calls on ARM64, they're transformed into a - b * (a / b). Ideally this transform would be delayed until lowering so that the frontend doesn't have to deal with such target specific issues. However, this transform allows CSE to eliminate a redundant a / b when the code contains both a / b and a % b.

@sandreenko
Copy link
Author

That seems unrelated since MOD/UMOD are AFAIK not turned into helper calls on ARM64, they're transformed into a - b * (a / b). Ideally this transform would be delayed until lowering so that the frontend doesn't have to deal with such target specific issues.

I agree that we should decide to do an optimization and do the optimization in one place.

However, this transform allows CSE to eliminate a redundant a / b when the code contains both a / b and a % b.

We do not transform a % b to a - b * (a / b) on x86/x64, where it can have the same benefit, can we teach CSE to find such cases and transform % when it is profitable?

@sandreenko
Copy link
Author

@mmitche Looks like ci is down, do you know about this problem?

@mikedn
Copy link

mikedn commented May 30, 2018

We do not transform a % b to a - b * (a / b) on x86/x64, where it can have the same benefit

Yes, this is a funny situation.

On ARM we don't have much of a choice since there is not % instruction so one way or another we have to transform.

On x86/x64 the transform is not required and if we do it for the sake of CSE we end up with an extra - and * if CSE fails. Then lowering would need to recognize a - b * (a / b) and turn it back into MOD so a single div instruction is emitted. But recognizing a - b * (a / b) isn't easy because it's not a tree.

can we teach CSE to find such cases and transform % when it is profitable?

I suppose CSE could try to look for an available a / b when it encounters an a % b. AFAIR I looked a bit at this in the past and it's problematic because it needs to figure out various things about a / b (e.g. VN, hash, index) without seeing it first. Probably doable but fairly involved and exotic.

And there's also the x86/64 specific case that if you have both a / b and a % b then you really want to generate a single a div b instruction, that's rather difficult to fit anywhere in the JIT.

@sandreenko
Copy link
Author

@dotnet-bot test this please

@sandreenko sandreenko closed this May 31, 2018
@sandreenko sandreenko reopened this May 31, 2018
We do not expect MOD/UMOD for integer/long types in lower for arm64.
@sandreenko
Copy link
Author

@dotnet-bot test Windows_NT x64_arm64_altjit Checked r2r
@dotnet-bot test Windows_NT x64_arm64_altjit Checked r2r_jitstress2
@dotnet-bot test Windows_NT x64_arm64_altjit Checked jitstress2
@dotnet-bot test Windows_NT x86_arm_altjit Checked r2r

#ifdef _TARGET_XARCH_
if (!varTypeIsFloating(node->TypeGet()))
#endif // _TARGET_XARCH_
if (varTypeIsIntegral(node->TypeGet()))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CarolEidt could you please take a look at this check? Do you remember why it was _TARGET_XARCH_ specific before?
LowerConstIntDivOrMod has assert((type == TYP_INT) || (type == TYP_LONG));, so looks like it is not correct to skip this check for arm/arm64.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ifdef was probably intended to include the entire if, not just the condition. I don't think I enabled magic division for ARM64 when I wrote the code, it didn't have GT_MULHI back then. I see that now it's enabled for ARM64 but it's still not enabled for ARM.

Copy link
Author

@sandreenko sandreenko Jun 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not enabled for arm because we do not allow integer MOD/DIV in Lower on this platform.

So, I do not see a reason why we need this target ifdef now, it works fine for XARCH DIV/MOD and for arm64 DIV nodes (MOD are not allowed in Lower).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reason why it should be target-specific either.

@sandreenko
Copy link
Author

PTAL @dotnet/jit-contrib, @dotnet/arm64-contrib

#ifdef _TARGET_XARCH_
if (!varTypeIsFloating(node->TypeGet()))
#endif // _TARGET_XARCH_
if (varTypeIsIntegral(node->TypeGet()))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reason why it should be target-specific either.

@sandreenko
Copy link
Author

Failures are not related with this change.

@sandreenko sandreenko merged commit ad92640 into dotnet:master Jun 1, 2018
@sandreenko sandreenko deleted the Fix17968 branch June 1, 2018 23:19
@BruceForstall
Copy link
Member

@sandreenko Can you also re-enable it in issues.targets:

<!-- The following are ARM64_altjit crossgen failures. For x64_arm64_altjit buildArm==x64. -->

<ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(BuildArch)' == 'x64'">
    <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\JitBlue\DevDiv_590772\DevDiv_590772\DevDiv_590772.cmd">
        <Issue>17968</Issue>
    </ExcludeList>
...
</ItemGroup>

@sandreenko
Copy link
Author

@sandreenko Can you also re-enable it in issues.targets:

Thanks, that was missed, I will publish the PR shortly.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-arm64 area-CodeGen bug Product bug (most likely)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[arm64/RyuJit] assert(!"Shouldn't see an integer typed GT_MOD node in ARM64");
4 participants