-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[clr-interp] Fix implicit promotion of I4 to I #122319
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
Merged
davidwrighton
merged 11 commits into
dotnet:main
from
davidwrighton:fix_implicit_unsigned_promotion_to_i
Dec 10, 2025
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
382b1ac
First pass at test structure
davidwrighton d52e050
Add tests and fixes for the various simple integer arithmetic opcodes
davidwrighton 8d5517a
Add testing for logical operators
davidwrighton 4981e69
Tests for the compare opcodes
davidwrighton 3fc6f62
More fixes and test cases for branch scenarios
davidwrighton 73c2c40
Test works on box 64 and 32bit platforms
davidwrighton 67e9138
Make a single Fact instead of a giant stack of theories. This should …
davidwrighton 226ddb8
Apply suggestions from code review
davidwrighton 5ea57ad
Fix issues
davidwrighton 55db698
Actually get the test to run in CI by adding attribute
davidwrighton d3b5ec8
Disable test on mono
davidwrighton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
236 changes: 236 additions & 0 deletions
236
src/tests/JIT/Methodical/int64/unsigned/implicit_promotion.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using Xunit; | ||
| using JitTest_implicit_promotion; | ||
| using implicit_promotion; | ||
|
|
||
| namespace JitTest_implicit_promotion | ||
| { | ||
| public class Test | ||
| { | ||
| // These tests attempt to verify that the implicit upcasting from I4 to I which happens on 64 bit platforms | ||
| // is done in a consistent manner across all implementations. | ||
| // Notable details of interest: | ||
| // add.ovf.un, sub.ovf.un, mul.ovf.un upcast without sign-extension. | ||
| // div.un, and rem.un upcast with sign-extension. | ||
| // clt.un, cgt.un upcast without sign-extension | ||
| // bne.un, blt.un, ble.un, bgt.un, bge.un upcast without sign-extension | ||
| [Fact] | ||
| [ActiveIssue("https://github.com/dotnet/runtime/issues/122398", TestRuntimes.Mono)] | ||
| public static void TestUpcastBehavior() | ||
davidwrighton marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| unchecked | ||
| { | ||
| ////////////////////////////////////////////////////////////////// | ||
| /// Test scenarios where the first operand is I and the second is i32 | ||
| ///////////////////////////////////////////////////////////////// | ||
|
|
||
| // add: (int)0x1 + -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.add_I_i32((nint)0x1, -2)); | ||
|
|
||
| // add.ovf.un: (int)0x1 + -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(ulong)0x00000000FFFFFFFF : (nint)(-1), Operator.add_ovf_un_I_i32((nint)0x1, -2)); | ||
|
|
||
| // add.ovf: (int)0x1 + -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.add_ovf_I_i32((nint)0x1, -2)); | ||
|
|
||
| // sub: -1 - -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.sub_I_i32((nint)(-1), -1)); | ||
|
|
||
| // sub.ovf: -1 - -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.sub_ovf_I_i32((nint)(-1), -1)); | ||
|
|
||
| // sub.ovf.un: -1 - -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? unchecked((nint)(ulong)0xFFFFFFFF00000000) : (nint)0, Operator.sub_ovf_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // mul: (int)0x2 * -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-2) : (nint)(-2), Operator.mul_I_i32((nint)0x2, -1)); | ||
|
|
||
| // mul.ovf: (int)0x2 * -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-2) : (nint)(-2), Operator.mul_ovf_I_i32((nint)0x2, -1)); | ||
|
|
||
| // mul.ovf.un: (int)0x2 * -1 | ||
| if (!Environment.Is64BitProcess) | ||
| { | ||
| Assert.Throws<OverflowException>(() => Operator.mul_ovf_un_I_i32((nint)0x2, -1)); | ||
| } | ||
| else | ||
| { | ||
| Assert.Equal((nint)(ulong)0x1FFFFFFFE, Operator.mul_ovf_un_I_i32((nint)0x2, -1)); | ||
| } | ||
|
|
||
| // div: -1 / -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.div_I_i32((nint)(-1), -1)); | ||
|
|
||
| // div.un: -1 / -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.div_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // rem: -1 % -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.rem_I_i32((nint)(-1), -1)); | ||
|
|
||
| // rem.un: -1 % -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.rem_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // and: -1 & -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.and_I_i32((nint)(-1), -1)); | ||
|
|
||
| // or: 0 | -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.or_I_i32((nint)0, -1)); | ||
|
|
||
| // xor: -1 ^ -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.xor_I_i32((nint)(-1), -1)); | ||
|
|
||
| // ceq: -1 == -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.ceq_I_i32((nint)(-1), -1)); | ||
|
|
||
| // cgt: -2 > -3 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.cgt_I_i32((nint)(-2), -3)); | ||
|
|
||
| // cgt.un: -2 > -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.cgt_un_I_i32((nint)(-2), -1)); | ||
|
|
||
| // clt: -1 < -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.clt_I_i32((nint)(-1), -2)); | ||
|
|
||
| // clt.un: -2 < -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.clt_un_I_i32((nint)(-2), -1)); | ||
|
|
||
| // beq: -1 == -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.beq_I_i32((nint)(-1), -1)); | ||
|
|
||
| // bne.un: -1 != -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)0, Operator.bne_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // blt: -1 < -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.blt_I_i32((nint)(-1), -1)); | ||
|
|
||
| // blt.un: -2 < -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)1, Operator.blt_un_I_i32((nint)(-2), -1)); | ||
|
|
||
| // ble: -1 <= -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.ble_I_i32((nint)(-1), -1)); | ||
|
|
||
| // ble.un: -1 <= -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)1, Operator.ble_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // bgt: -1 > -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.bgt_I_i32((nint)(-1), -1)); | ||
|
|
||
| // bgt.un: -1 > -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)0, Operator.bgt_un_I_i32((nint)(-1), -1)); | ||
|
|
||
| // bge: -1 >= -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.bge_I_i32((nint)(-1), -1)); | ||
|
|
||
| // bge.un: 0xFFFFFFFF >= -2 (unsigned, special case) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.bge_un_I_i32(unchecked((nint)(nuint)0xFFFFFFFF), -2)); | ||
|
|
||
| ////////////////////////////////////////////////////////////////// | ||
| /// Test scenarios where the first operand is i32 and the second is I | ||
| ///////////////////////////////////////////////////////////////// | ||
|
|
||
| // add: -2 + 1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.add_i32_I(-2, (nint)1)); | ||
|
|
||
| // add.ovf.un: -2 + 1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(ulong)0x00000000FFFFFFFF : (nint)(-1), Operator.add_ovf_un_i32_I(-2, (nint)1)); | ||
|
|
||
| // add.ovf: -2 + 1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.add_ovf_i32_I(-2, (nint)1)); | ||
|
|
||
| // sub: -1 - -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.sub_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // sub.ovf: -1 - -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.sub_ovf_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // sub.ovf.un: -1 - 1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(ulong)0xFFFFFFFE : (nint)(-2), Operator.sub_ovf_un_i32_I(-1, (nint)1)); | ||
|
|
||
| // mul: -1 * 2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-2) : (nint)(-2), Operator.mul_i32_I(-1, (nint)2)); | ||
|
|
||
| // mul.ovf: -1 * 2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-2) : (nint)(-2), Operator.mul_ovf_i32_I(-1, (nint)2)); | ||
|
|
||
| // mul.ovf.un: -1 * 2 | ||
| if (!Environment.Is64BitProcess) | ||
| { | ||
| Assert.Throws<OverflowException>(() => Operator.mul_ovf_un_i32_I(-1, (nint)2)); | ||
| } | ||
| else | ||
| { | ||
| Assert.Equal((nint)(ulong)0x1FFFFFFFE, Operator.mul_ovf_un_i32_I(-1, (nint)2)); | ||
| } | ||
|
|
||
| // div: -1 / -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.div_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // div.un: -1 / -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.div_un_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // rem: -1 % -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.rem_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // rem.un: -1 % -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.rem_un_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // and: -1 & -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.and_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // or: -1 | 0 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)(-1) : (nint)(-1), Operator.or_i32_I(-1, (nint)0)); | ||
|
|
||
| // xor: -1 ^ -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.xor_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // ceq: -1 == -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.ceq_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // cgt: -2 > -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.cgt_i32_I(-2, (nint)(-1))); | ||
|
|
||
| // cgt.un: -1 > -2 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.cgt_un_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // clt: -1 < -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)0, Operator.clt_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // clt.un: -2 < -1 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.clt_un_i32_I(-2, (nint)(-1))); | ||
|
|
||
| // beq: -1 == -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.beq_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // bne.un: -1 != -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)0, Operator.bne_un_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // blt: -2 < -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.blt_i32_I(-2, (nint)(-1))); | ||
|
|
||
| // blt.un: -1 < -2 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)0, Operator.blt_un_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // ble: -1 <= -1 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.ble_i32_I(-1, (nint)(-1))); | ||
|
|
||
| // ble.un: -1 <= -2 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)0, Operator.ble_un_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // bgt: -1 > -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.bgt_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // bgt.un: -1 > -2 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)1, Operator.bgt_un_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // bge: -1 >= -2 | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)1 : (nint)1, Operator.bge_i32_I(-1, (nint)(-2))); | ||
|
|
||
| // bge.un: -1 >= -2 (unsigned) | ||
| Assert.Equal(Environment.Is64BitProcess ? (nint)0 : (nint)1, Operator.bge_un_i32_I(-1, (nint)(-2))); | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.