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

Commit 55f162d

Browse files
authored
Merge pull request #15301 from mikedn/cast-un
Fix inconsistent handling of zero extending casts
2 parents c7229d6 + 0880a64 commit 55f162d

File tree

16 files changed

+252
-137
lines changed

16 files changed

+252
-137
lines changed

src/jit/codegenxarch.cpp

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6354,7 +6354,7 @@ void CodeGen::genIntToIntCast(GenTree* treeNode)
63546354
bool isUnsignedSrc = varTypeIsUnsigned(srcType);
63556355

63566356
// if necessary, force the srcType to unsigned when the GT_UNSIGNED flag is set
6357-
if (!isUnsignedSrc && (treeNode->gtFlags & GTF_UNSIGNED) != 0)
6357+
if (!isUnsignedSrc && treeNode->IsUnsigned())
63586358
{
63596359
srcType = genUnsignedType(srcType);
63606360
isUnsignedSrc = true;
@@ -6371,37 +6371,29 @@ void CodeGen::genIntToIntCast(GenTree* treeNode)
63716371

63726372
if (srcSize < dstSize)
63736373
{
6374-
// Widening cast
6375-
// Is this an Overflow checking cast?
6376-
// We only need to handle one case, as the other casts can never overflow.
6377-
// cast from TYP_INT to TYP_ULONG
6378-
//
6379-
if (treeNode->gtOverflow() && (srcType == TYP_INT) && (dstType == TYP_ULONG))
6374+
#ifdef _TARGET_X86_
6375+
// dstType cannot be a long type on x86, such casts should have been decomposed.
6376+
// srcType cannot be a small type since it's the "actual type" of the cast operand.
6377+
// This means that widening casts do not actually occur on x86.
6378+
unreached();
6379+
#else
6380+
// This is a widening cast from TYP_(U)INT to TYP_(U)LONG.
6381+
assert(dstSize == EA_8BYTE);
6382+
assert(srcSize == EA_4BYTE);
6383+
6384+
// When widening, overflows can only happen if the source type is signed and the
6385+
// destination type is unsigned. Since the overflow check ensures that the value
6386+
// is positive a cheaper mov instruction can be used instead of movsxd.
6387+
if (treeNode->gtOverflow() && !isUnsignedSrc && isUnsignedDst)
63806388
{
63816389
requiresOverflowCheck = true;
63826390
ins = INS_mov;
63836391
}
63846392
else
63856393
{
6386-
noway_assert(srcSize < EA_PTRSIZE);
6387-
6388-
ins = ins_Move_Extend(srcType, false);
6389-
6390-
/*
6391-
Special case: ins_Move_Extend assumes the destination type is no bigger
6392-
than TYP_INT. movsx and movzx can already extend all the way to
6393-
64-bit, and a regular 32-bit mov clears the high 32 bits (like the non-existant movzxd),
6394-
but for a sign extension from TYP_INT to TYP_LONG, we need to use movsxd opcode.
6395-
*/
6396-
if (!isUnsignedSrc && !isUnsignedDst)
6397-
{
6398-
#ifdef _TARGET_X86_
6399-
NYI_X86("Cast to 64 bit for x86/RyuJIT");
6400-
#else // !_TARGET_X86_
6401-
ins = INS_movsxd;
6402-
#endif // !_TARGET_X86_
6403-
}
6394+
ins = isUnsignedSrc ? INS_mov : INS_movsxd;
64046395
}
6396+
#endif
64056397
}
64066398
else
64076399
{

src/jit/compiler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,9 +2128,9 @@ class Compiler
21282128

21292129
GenTree* gtUnusedValNode(GenTree* expr);
21302130

2131-
GenTree* gtNewCastNode(var_types typ, GenTree* op1, var_types castType);
2131+
GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
21322132

2133-
GenTree* gtNewCastNodeL(var_types typ, GenTree* op1, var_types castType);
2133+
GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
21342134

21352135
GenTree* gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
21362136

src/jit/compiler.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,13 +1476,13 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
14761476
}
14771477
}
14781478

1479-
inline GenTree* Compiler::gtNewCastNode(var_types typ, GenTree* op1, var_types castType)
1479+
inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
14801480
{
1481-
GenTree* res = new (this, GT_CAST) GenTreeCast(typ, op1, castType);
1481+
GenTreeCast* res = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
14821482
return res;
14831483
}
14841484

1485-
inline GenTree* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, var_types castType)
1485+
inline GenTreeCast* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
14861486
{
14871487
/* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
14881488

@@ -1491,7 +1491,8 @@ inline GenTree* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, var_types
14911491

14921492
/* Make a big node first and then change it to be GT_CAST */
14931493

1494-
GenTree* res = new (this, LargeOpOpcode()) GenTreeCast(typ, op1, castType DEBUGARG(/*largeNode*/ true));
1494+
GenTreeCast* res =
1495+
new (this, LargeOpOpcode()) GenTreeCast(typ, op1, fromUnsigned, castType DEBUGARG(/*largeNode*/ true));
14951496
return res;
14961497
}
14971498

src/jit/decomposelongs.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,12 +1924,7 @@ GenTree* DecomposeLongs::EnsureIntSized(GenTree* node, bool signExtend)
19241924
return node;
19251925
}
19261926

1927-
GenTree* const cast = m_compiler->gtNewCastNode(TYP_INT, node, node->TypeGet());
1928-
if (!signExtend)
1929-
{
1930-
cast->gtFlags |= GTF_UNSIGNED;
1931-
}
1932-
1927+
GenTree* const cast = m_compiler->gtNewCastNode(TYP_INT, node, !signExtend, node->TypeGet());
19331928
Range().InsertAfter(node, cast);
19341929
return cast;
19351930
}

src/jit/flowgraph.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7468,7 +7468,7 @@ GenTree* Compiler::fgDoNormalizeOnStore(GenTree* tree)
74687468

74697469
if (fgCastNeeded(op2, varDsc->TypeGet()))
74707470
{
7471-
op2 = gtNewCastNode(TYP_INT, op2, varDsc->TypeGet());
7471+
op2 = gtNewCastNode(TYP_INT, op2, false, varDsc->TypeGet());
74727472
tree->gtOp.gtOp2 = op2;
74737473

74747474
// Propagate GTF_COLON_COND
@@ -20692,12 +20692,12 @@ Compiler::fgWalkResult Compiler::fgStress64RsltMulCB(GenTree** pTree, fgWalkData
2069220692
#endif // DEBUG
2069320693

2069420694
// To ensure optNarrowTree() doesn't fold back to the original tree.
20695-
tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, TYP_LONG);
20695+
tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, false, TYP_LONG);
2069620696
tree->gtOp.gtOp1 = pComp->gtNewOperNode(GT_NOP, TYP_LONG, tree->gtOp.gtOp1);
20697-
tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, TYP_LONG);
20698-
tree->gtOp.gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp2, TYP_LONG);
20697+
tree->gtOp.gtOp1 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp1, false, TYP_LONG);
20698+
tree->gtOp.gtOp2 = pComp->gtNewCastNode(TYP_LONG, tree->gtOp.gtOp2, false, TYP_LONG);
2069920699
tree->gtType = TYP_LONG;
20700-
*pTree = pComp->gtNewCastNode(TYP_INT, tree, TYP_INT);
20700+
*pTree = pComp->gtNewCastNode(TYP_INT, tree, false, TYP_INT);
2070120701

2070220702
#ifdef DEBUG
2070320703
if (pComp->verbose)

src/jit/gentree.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7820,8 +7820,9 @@ GenTree* Compiler::gtCloneExpr(
78207820
break;
78217821

78227822
case GT_CAST:
7823-
copy = new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(),
7824-
tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
7823+
copy =
7824+
new (this, LargeOpOpcode()) GenTreeCast(tree->TypeGet(), tree->gtCast.CastOp(), tree->IsUnsigned(),
7825+
tree->gtCast.gtCastType DEBUGARG(/*largeNode*/ TRUE));
78257826
break;
78267827

78277828
// The nodes below this are not bashed, so they can be allocated at their individual sizes.
@@ -7993,10 +7994,6 @@ GenTree* Compiler::gtCloneExpr(
79937994
{
79947995
copy->gtFlags |= GTF_OVERFLOW;
79957996
}
7996-
if (copy->OperGet() == GT_CAST)
7997-
{
7998-
copy->gtFlags |= (tree->gtFlags & GTF_UNSIGNED);
7999-
}
80007997

80017998
if (tree->gtOp.gtOp1)
80027999
{
@@ -14000,15 +13997,22 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1400013997
goto CNS_INT;
1400113998

1400213999
case TYP_ULONG:
14003-
if (!(tree->gtFlags & GTF_UNSIGNED) && tree->gtOverflow() && i1 < 0)
14000+
if (tree->IsUnsigned())
1400414001
{
14005-
goto LNG_OVF;
14002+
lval1 = UINT64(UINT32(i1));
14003+
}
14004+
else
14005+
{
14006+
if (tree->gtOverflow() && (i1 < 0))
14007+
{
14008+
goto LNG_OVF;
14009+
}
14010+
lval1 = UINT64(INT32(i1));
1400614011
}
14007-
lval1 = UINT64(UINT32(i1));
1400814012
goto CNS_LONG;
1400914013

1401014014
case TYP_LONG:
14011-
if (tree->gtFlags & GTF_UNSIGNED)
14015+
if (tree->IsUnsigned())
1401214016
{
1401314017
lval1 = INT64(UINT32(i1));
1401414018
}
@@ -15431,11 +15435,11 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
1543115435
}
1543215436
else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
1543315437
{
15434-
assg = gtNewCastNode(TYP_DOUBLE, assg, TYP_DOUBLE);
15438+
assg = gtNewCastNode(TYP_DOUBLE, assg, false, TYP_DOUBLE);
1543515439
}
1543615440
else if (lclTyp == TYP_FLOAT && assg->TypeGet() == TYP_DOUBLE)
1543715441
{
15438-
assg = gtNewCastNode(TYP_FLOAT, assg, TYP_FLOAT);
15442+
assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
1543915443
}
1544015444

1544115445
args = gtNewArgList(assg);
@@ -15495,7 +15499,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
1549515499
else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
1549615500
{
1549715501
// The helper does not extend the small return types.
15498-
tree = gtNewCastNode(genActualType(lclTyp), tree, lclTyp);
15502+
tree = gtNewCastNode(genActualType(lclTyp), tree, false, lclTyp);
1549915503
}
1550015504
}
1550115505
}

src/jit/gentree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3031,9 +3031,10 @@ struct GenTreeCast : public GenTreeOp
30313031
}
30323032
var_types gtCastType;
30333033

3034-
GenTreeCast(var_types type, GenTree* op, var_types castType DEBUGARG(bool largeNode = false))
3034+
GenTreeCast(var_types type, GenTree* op, bool fromUnsigned, var_types castType DEBUGARG(bool largeNode = false))
30353035
: GenTreeOp(GT_CAST, type, op, nullptr DEBUGARG(largeNode)), gtCastType(castType)
30363036
{
3037+
gtFlags |= fromUnsigned ? GTF_UNSIGNED : 0;
30373038
}
30383039
#if DEBUGGABLE_GENTREE
30393040
GenTreeCast() : GenTreeOp()

0 commit comments

Comments
 (0)