Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 82 additions & 84 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1141,12 +1141,12 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
if (curAssertion->op1.kind == O1K_EXACT_TYPE)
{
printf("Exact Type MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
assert(curAssertion->op2.u1.iconFlags != GTF_EMPTY);
assert(curAssertion->op2.HasIconFlag());
}
else if (curAssertion->op1.kind == O1K_SUBTYPE)
{
printf("MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
assert(curAssertion->op2.u1.iconFlags != GTF_EMPTY);
assert(curAssertion->op2.HasIconFlag());
}
else if ((curAssertion->op1.kind == O1K_BOUND_OPER_BND) ||
(curAssertion->op1.kind == O1K_BOUND_LOOP_BND) ||
Expand Down Expand Up @@ -1183,7 +1183,7 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
}
else
{
if ((curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) != 0)
if (curAssertion->op2.HasIconFlag())
{
printf("[%08p]", dspPtr(curAssertion->op2.u1.iconVal));
}
Expand Down Expand Up @@ -1495,12 +1495,12 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
vn = optConservativeNormalVN(op1);
}

assertion.op1.vn = vn;
assertion.assertionKind = assertionKind;
assertion.op2.kind = O2K_CONST_INT;
assertion.op2.vn = ValueNumStore::VNForNull();
assertion.op2.u1.iconVal = 0;
assertion.op2.u1.iconFlags = GTF_EMPTY;
assertion.op1.vn = vn;
assertion.assertionKind = assertionKind;
assertion.op2.kind = O2K_CONST_INT;
assertion.op2.vn = ValueNumStore::VNForNull();
assertion.op2.u1.iconVal = 0;
assertion.op2.SetIconFlag(GTF_EMPTY);
}
//
// Are we making an assertion about a local variable?
Expand Down Expand Up @@ -1548,13 +1548,13 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
// where a class can be sealed, but they don't behave as exact types because casts to
// non-base types sometimes still succeed.
//
assertion.op1.kind = O1K_SUBTYPE;
assertion.op1.lcl.lclNum = lclNum;
assertion.op1.vn = optConservativeNormalVN(op1);
assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
assertion.op2.u1.iconVal = op2->AsIntCon()->gtIconVal;
assertion.op2.vn = optConservativeNormalVN(op2);
assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
assertion.op1.kind = O1K_SUBTYPE;
assertion.op1.lcl.lclNum = lclNum;
assertion.op1.vn = optConservativeNormalVN(op1);
assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
assertion.op2.u1.iconVal = op2->AsIntCon()->gtIconVal;
assertion.op2.vn = optConservativeNormalVN(op2);
assertion.op2.SetIconFlag(op2->GetIconHandleFlag());

//
// Ok everything has been set and the assertion looks good
Expand Down Expand Up @@ -1642,8 +1642,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
}
#endif // TARGET_ARM

assertion.op2.u1.iconVal = iconVal;
assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
assertion.op2.u1.iconVal = iconVal;
assertion.op2.SetIconFlag(op2->GetIconHandleFlag(), op2->AsIntCon()->gtFieldSeq);
}
else if (op2->gtOper == GT_CNS_LNG)
{
Expand Down Expand Up @@ -1792,7 +1792,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,

/* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
assertion.op2.u1.iconFlags = iconFlags;
assertion.op2.SetIconFlag(iconFlags);
}
// JIT case
else if (optIsTreeKnownIntValue(!optLocalAssertionProp, op2, &cnsValue, &iconFlags))
Expand All @@ -1804,7 +1804,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,

/* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
assertion.op2.u1.iconFlags = iconFlags;
assertion.op2.SetIconFlag(iconFlags);
}
else
{
Expand Down Expand Up @@ -2105,13 +2105,11 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
case O2K_CONST_INT:
{
// The only flags that can be set are those in the GTF_ICON_HDL_MASK.
assert((assertion->op2.u1.iconFlags & ~GTF_ICON_HDL_MASK) == 0);

switch (assertion->op1.kind)
{
case O1K_EXACT_TYPE:
case O1K_SUBTYPE:
assert(assertion->op2.u1.iconFlags != GTF_EMPTY);
assert(assertion->op2.HasIconFlag());
break;
case O1K_LCLVAR:
assert((lvaGetDesc(assertion->op1.lcl.lclNum)->lvType != TYP_REF) ||
Expand All @@ -2130,7 +2128,7 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
{
// All handles should be represented by O2K_CONST_INT,
// so no handle bits should be set here.
assert((assertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) == 0);
assert(!assertion->op2.HasIconFlag());
}
break;

Expand Down Expand Up @@ -2336,13 +2334,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBoundArith(op1VN))
{
AssertionDsc dsc;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_OPER_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_OPER_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand All @@ -2353,13 +2351,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNCompareCheckedBoundArith(relopVN))
{
AssertionDsc dsc;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_OPER_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_OPER_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand All @@ -2370,13 +2368,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBound(op1VN))
{
AssertionDsc dsc;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_LOOP_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_LOOP_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand All @@ -2387,13 +2385,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNCompareCheckedBound(relopVN))
{
AssertionDsc dsc;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_LOOP_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_BOUND_LOOP_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand Down Expand Up @@ -2430,13 +2428,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (hasTestAgainstZero && vnStore->IsVNConstantBound(op1VN))
{
AssertionDsc dsc;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
dsc.op1.vn = op1VN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand All @@ -2447,27 +2445,27 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNConstantBound(relopVN))
{
AssertionDsc dsc;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
}
else if (vnStore->IsVNConstantBoundUnsigned(relopVN))
{
AssertionDsc dsc;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND_UN;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.assertionKind = OAK_NOT_EQUAL;
dsc.op1.kind = O1K_CONSTANT_LOOP_BND_UN;
dsc.op1.vn = relopVN;
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
Expand Down Expand Up @@ -2557,13 +2555,13 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
dsc.op1.bnd.vnIdx = vnStore->VNForIntCon(con - 1);
}

dsc.op1.vn = op1VN;
dsc.op1.kind = O1K_ARR_BND;
dsc.op1.bnd.vnLen = op1VN;
dsc.op2.vn = vnStore->VNConservativeNormalValue(op2->gtVNPair);
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.u1.iconFlags = GTF_EMPTY;
dsc.op2.u1.iconVal = 0;
dsc.op1.vn = op1VN;
dsc.op1.kind = O1K_ARR_BND;
dsc.op1.bnd.vnLen = op1VN;
dsc.op2.vn = vnStore->VNConservativeNormalValue(op2->gtVNPair);
dsc.op2.kind = O2K_CONST_INT;
dsc.op2.u1.iconVal = 0;
dsc.op2.SetIconFlag(GTF_EMPTY);

// when con is not zero, create an assertion on the arr.Length == con edge
// when con is zero, create an assertion on the arr.Length != 0 edge
Expand Down Expand Up @@ -3366,7 +3364,7 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
case O2K_CONST_INT:

// Don't propagate handles if we need to report relocs.
if (opts.compReloc && ((curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) != 0))
if (opts.compReloc && curAssertion->op2.HasIconFlag())
{
return nullptr;
}
Expand All @@ -3381,11 +3379,11 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
assert(!varTypeIsSmall(tree) || (curAssertion->op2.u1.iconVal ==
optCastConstantSmall(curAssertion->op2.u1.iconVal, tree->TypeGet())));

if (curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK)
if (curAssertion->op2.HasIconFlag())
{
// Here we have to allocate a new 'large' node to replace the old one
newTree = gtNewIconHandleNode(curAssertion->op2.u1.iconVal,
curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK);
newTree = gtNewIconHandleNode(curAssertion->op2.u1.iconVal, curAssertion->op2.GetIconFlag(),
curAssertion->op2.u1.fieldSeq);

// Make sure we don't retype const gc handles to TYP_I_IMPL
// Although, it's possible for e.g. GTF_ICON_STATIC_HDL
Expand Down
34 changes: 30 additions & 4 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7058,7 +7058,7 @@ class Compiler
O1K_COUNT
};

enum optOp2Kind
enum optOp2Kind : uint16_t
{
O2K_INVALID,
O2K_LCLVAR_COPY,
Expand Down Expand Up @@ -7096,14 +7096,17 @@ class Compiler
struct AssertionDscOp2
{
optOp2Kind kind; // a const or copy assignment
ValueNum vn;
private:
uint16_t m_encodedIconFlags; // encoded icon gtFlags, don't use directly
public:
ValueNum vn;
struct IntVal
{
ssize_t iconVal; // integer
#if !defined(HOST_64BIT)
unsigned padding; // unused; ensures iconFlags does not overlap lconVal
#endif
GenTreeFlags iconFlags; // gtFlags
FieldSeq* fieldSeq;
};
union {
SsaVar lcl;
Expand All @@ -7112,6 +7115,29 @@ class Compiler
double dconVal;
IntegralRange u2;
};

bool HasIconFlag()
{
assert(m_encodedIconFlags <= 0xFF);
return m_encodedIconFlags != 0;
}
GenTreeFlags GetIconFlag()
{
// number of trailing zeros in GTF_ICON_HDL_MASK
const uint16_t iconMaskTzc = 24;
static_assert_no_msg((0xFF000000 == GTF_ICON_HDL_MASK) && (GTF_ICON_HDL_MASK >> iconMaskTzc) == 0xFF);

GenTreeFlags flags = (GenTreeFlags)(m_encodedIconFlags << iconMaskTzc);
assert((flags & ~GTF_ICON_HDL_MASK) == 0);
return flags;
}
void SetIconFlag(GenTreeFlags flags, FieldSeq* fieldSeq = nullptr)
{
const uint16_t iconMaskTzc = 24;
assert((flags & ~GTF_ICON_HDL_MASK) == 0);
m_encodedIconFlags = flags >> iconMaskTzc;
u1.fieldSeq = fieldSeq;
}
} op2;

bool IsCheckedBoundArithBound()
Expand Down Expand Up @@ -7220,7 +7246,7 @@ class Compiler
{
case O2K_IND_CNS_INT:
case O2K_CONST_INT:
return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.GetIconFlag() == that->op2.GetIconFlag()));

case O2K_CONST_LONG:
return (op2.lconVal == that->op2.lconVal);
Expand Down
Loading