Skip to content
Closed
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
5 changes: 5 additions & 0 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5145,6 +5145,11 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
costSz = 12;
break;

case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant:
costEx = 1;
costSz = 1;
break;

case NI_System_Math_Abs:
costEx = 5;
costSz = 15;
Expand Down
25 changes: 22 additions & 3 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,11 +583,9 @@ GenTree* Lowering::LowerNode(GenTree* node)
ContainCheckLclHeap(node->AsOp());
break;

#ifdef TARGET_XARCH
case GT_INTRINSIC:
ContainCheckIntrinsic(node->AsOp());
LowerIntrinsic(node->AsIntrinsic());
break;
#endif // TARGET_XARCH

#ifdef FEATURE_HW_INTRINSICS
case GT_HWINTRINSIC:
Expand Down Expand Up @@ -7786,6 +7784,27 @@ void Lowering::TransformUnusedIndirection(GenTreeIndir* ind, Compiler* comp, Bas
}
}

//------------------------------------------------------------------------
// LowerIntrinsic: a common logic to lower INTRINSIC.
//
// Arguments:
// node - the INTRINSIC node we are lowering.
//
void Lowering::LowerIntrinsic(GenTreeIntrinsic* node)
{
if (node->gtIntrinsicName == NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant)
{
// IsKnownConstant is expected to be folded in Importer/Morph/VN+ConstantProp
// This path is just in case if VN+ConstantProp didn't fold them for some reason (or e.g. they were disabled)
Comment on lines +7797 to +7798
Copy link
Contributor

Choose a reason for hiding this comment

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

This is "not enough"...

Consider a case where VN assigns this 1 (i. e. the operand is constant). Then CSE CSEs this as a def with some other unrelated uses of the value 1. Then lowering comes along, and we get 0 instead of 1.

Essentially, each subsequent phase can only further "refine" the value of this intrinsic. The tricky part here is of course that by the time we get to lowering, VNs are no longer valid. So this needs a separate "lower IsKnownConstant" phase, that would use the still-valid VNs. Bit yucky.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree, but the current code is correct, isn't it? it justs conservatively assumes that input is not a constant so we end up in the non-constant path.

I agree that it'd be nice to have a separate phase for such transforms somewhere after assert prop with still valid VNs. Maybe I'll add one eventuallly (and move unrollings there e.g.)

Copy link
Contributor

Choose a reason for hiding this comment

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

but the current code is correct, isn't it?

No - consider the CSE example. We cannot have this assigned 1 in VN and then lower it to zero.

Copy link
Member Author

Choose a reason for hiding this comment

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

but the current code is correct, isn't it?

No - consider the CSE example. We cannot have this assigned 1 in VN and then lower it to zero.

Ah, I see what you mean. I'll implement it in a separate phase if we find a real use case for it

node->gtGetOp1()->SetUnusedValue();
node->BashToConst(0);
return;
}
#ifdef TARGET_XARCH
ContainCheckIntrinsic(node->AsOp());
#endif
}

//------------------------------------------------------------------------
// LowerBlockStoreCommon: a common logic to lower STORE_OBJ/BLK/DYN_BLK.
//
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ class Lowering final : public Phase
bool LowerUnsignedDivOrMod(GenTreeOp* divMod);
GenTree* LowerConstIntDivOrMod(GenTree* node);
GenTree* LowerSignedDivOrMod(GenTree* node);
void LowerIntrinsic(GenTreeIntrinsic* node);
void LowerBlockStore(GenTreeBlk* blkNode);
void LowerBlockStoreCommon(GenTreeBlk* blkNode);
void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent);
Expand Down
22 changes: 4 additions & 18 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10010,8 +10010,8 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
if (tree->AsIntrinsic()->gtIntrinsicName ==
NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant)
{
// Should be expanded by the time it reaches CSE phase
assert(!optValnumCSE_phase);
// Should be expanded in importer for MinOpts
assert(opts.OptimizationEnabled());

JITDUMP("\nExpanding RuntimeHelpers.IsKnownConstant to ");
if (op1->OperIsConst() || gtIsTypeof(op1))
Expand All @@ -10023,22 +10023,8 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
}
else
{
GenTree* op1SideEffects = nullptr;
gtExtractSideEffList(op1, &op1SideEffects, GTF_ALL_EFFECT);
if (op1SideEffects != nullptr)
{
DEBUG_DESTROY_NODE(tree);
// Keep side-effects of op1
tree = gtNewOperNode(GT_COMMA, TYP_INT, op1SideEffects, gtNewIconNode(0));
JITDUMP("false with side effects:\n")
DISPTREE(tree);
}
else
{
JITDUMP("false\n");
DEBUG_DESTROY_NODE(tree, op1);
tree = gtNewIconNode(0);
}
// Leave it for VN/ConstantProp (or Lowering)
return tree;
}
INDEBUG(tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
return tree;
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11047,6 +11047,12 @@ void Compiler::fgValueNumberIntrinsic(GenTree* tree)
intrinsic->gtVNPair = vnStore->VNPWithExc(newVNP, excSet);
}
}
else if (intrinsic->gtIntrinsicName == NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant)
{
ValueNum isCnsVNL = vnStore->VNForIntCon(vnStore->IsVNConstant(arg0VNP.GetLiberal()) ? 1 : 0);
ValueNum isCnsVNC = vnStore->VNForIntCon(vnStore->IsVNConstant(arg0VNP.GetConservative()) ? 1 : 0);
intrinsic->gtVNPair = vnStore->VNPWithExc(ValueNumPair(isCnsVNL, isCnsVNC), arg0VNPx);
}
else
{
assert(intrinsic->gtIntrinsicName == NI_System_Object_GetType);
Expand Down