Remember #7439? I ran into that again but this time it's a real bug.
The importer does this: https://github.com/dotnet/coreclr/blob/a6045809b3720833459c9247aeb4aafe281d7841/src/jit/importer.cpp#L9374-L9396
Note that it selects the "castType" based on the signedness of the operation but it does not set the GTF_UNSIGNED flag on the cast.
So if it doesn't set the flag how come we zero extend int32 in the case of add.ovf.un? That's because CodeGen::genIntToIntCast does something weird: https://github.com/dotnet/coreclr/blob/a6045809b3720833459c9247aeb4aafe281d7841/src/jit/codegenxarch.cpp#L6490-L6497
It selects INS_movsxd if the source is signed. And if the destination is signed! That doesn't make sense, the sign of the destination is relevant only for overflow checks, it should have no impact on the kind of widening performed.
I was curious what the ARM64 codegen does and of course, it doesn't consider the destination sign and emits sxtw:
B9802C09 ldrsw x9, [x0,#44]
93407D29 sxtw x9, x9
F9400C2A ldr x10, [x1,#24]
AB0A0129 adds x9, x9, x10
54000062 bhs G_M55886_IG04
For the same code the x64 codegen produces mov, not movsxd.
So, if we want to keep the existing x64 behavior (zero extend add.ovf.un operands) we need to:
- make the importer set
GTF_UNSIGNED when needed (this will make ARM64 codegen generate the required code)
- change x64 codegen to ignore the destination type when selecting
INS_movsxd
Though after seeing this I'm more inclined to consider the current behavior to be a JIT bug and that sign extension should be performed. So:
- change x64 codegen to ignore the destination type when selecting
INS_movsxd
And either way we probably need to add tests for this. I only noticed this while looking at diffs in dotnet/coreclr#12676. All tests pass but the code isn't right.
Remember #7439? I ran into that again but this time it's a real bug.
The importer does this: https://github.com/dotnet/coreclr/blob/a6045809b3720833459c9247aeb4aafe281d7841/src/jit/importer.cpp#L9374-L9396
Note that it selects the "castType" based on the signedness of the operation but it does not set the
GTF_UNSIGNEDflag on the cast.So if it doesn't set the flag how come we zero extend
int32in the case ofadd.ovf.un? That's becauseCodeGen::genIntToIntCastdoes something weird: https://github.com/dotnet/coreclr/blob/a6045809b3720833459c9247aeb4aafe281d7841/src/jit/codegenxarch.cpp#L6490-L6497It selects
INS_movsxdif the source is signed. And if the destination is signed! That doesn't make sense, the sign of the destination is relevant only for overflow checks, it should have no impact on the kind of widening performed.I was curious what the ARM64 codegen does and of course, it doesn't consider the destination sign and emits
sxtw:For the same code the x64 codegen produces
mov, notmovsxd.So, if we want to keep the existing x64 behavior (zero extend
add.ovf.unoperands) we need to:GTF_UNSIGNEDwhen needed (this will make ARM64 codegen generate the required code)INS_movsxdThough after seeing this I'm more inclined to consider the current behavior to be a JIT bug and that sign extension should be performed. So:
INS_movsxdAnd either way we probably need to add tests for this. I only noticed this while looking at diffs in dotnet/coreclr#12676. All tests pass but the code isn't right.