}
//------------------------------------------------------------------------
+// IsSafeToContainMem: Checks for conflicts between childNode and parentNode.
+//
+// Arguments:
+// parentNode - a non-leaf binary node
+// childNode - a memory op that is a child op of 'parentNode'
+//
+// Return value:
+// returns true if it is safe to make childNode a contained memory op
+//
+// Notes:
+// Checks for memory conflicts in the instructions between childNode and parentNode,
+// and returns true iff childNode can be contained.
+
+bool Lowering::IsSafeToContainMem(GenTree* parentNode, GenTree* childNode)
+{
+ assert(parentNode->OperIsBinary());
+ assert(childNode->isMemoryOp());
+
+ // Check conflicts against nodes between 'childNode' and 'parentNode'
+ GenTree* node;
+ unsigned int childFlags = (childNode->gtFlags & GTF_ALL_EFFECT);
+ for (node = childNode->gtNext;
+ (node != parentNode) && (node != nullptr);
+ node = node->gtNext)
+ {
+ if ((childFlags != 0) && node->IsCall())
+ {
+ bool isPureHelper = (node->gtCall.gtCallType == CT_HELPER) && comp->s_helperCallProperties.IsPure(comp->eeGetHelperNum(node->gtCall.gtCallMethHnd));
+ if (!isPureHelper && ((node->gtFlags & childFlags & GTF_ALL_EFFECT) != 0))
+ {
+ return false;
+ }
+ }
+ else if (node->OperIsStore() && comp->fgNodesMayInterfere(node, childNode))
+ {
+ return false;
+ }
+ }
+ if (node != parentNode)
+ {
+ assert(!"Ran off end of stmt\n");
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
Compiler::fgWalkResult Lowering::DecompNodeHelper(GenTreePtr* pTree, Compiler::fgWalkData* data)
{
}
assert(otherOp != nullptr);
- if (otherOp->isMemoryOp() || otherOp->IsCnsNonZeroFltOrDbl())
+ if (otherOp->IsCnsNonZeroFltOrDbl())
{
MakeSrcContained(tree, otherOp);
}
+ else if (otherOp->isMemoryOp())
+ {
+ if ((otherOp == op2) || IsSafeToContainMem(tree, otherOp))
+ {
+ MakeSrcContained(tree, otherOp);
+ }
+ }
return;
}
}
}
}
- else if (op1->isMemoryOp())
+ else if (op2->isMemoryOp())
{
- if(op1Type == op2Type)
+ if (op1Type == op2Type)
{
- MakeSrcContained(tree, op1);
+ MakeSrcContained(tree, op2);
// Mark the tree as doing unsigned comparison if
// both the operands are small and unsigned types.
}
}
}
- else if (op2->isMemoryOp())
+ else if (op1->isMemoryOp())
{
- if(op1Type == op2Type)
+ if ((op1Type == op2Type) && IsSafeToContainMem(tree, op1))
{
- MakeSrcContained(tree, op2);
+ MakeSrcContained(tree, op1);
// Mark the tree as doing unsigned comparison if
// both the operands are small and unsigned types.
GenTreePtr indirOpSource = nullptr;
if (rhsLeft->OperGet() == GT_IND &&
- rhsLeft->gtGetOp1()->OperGet() == indirDst->OperGet())
+ rhsLeft->gtGetOp1()->OperGet() == indirDst->OperGet() &&
+ IsSafeToContainMem(indirSrc, rhsLeft))
{
indirCandidate = rhsLeft;
indirOpSource = rhsRight;
// To generate an LEA we need to force memOp into a register
// so don't allow memOp to be 'contained'
//
- if ((memOp != nullptr) && !useLeaEncoding && (memOp->TypeGet() == tree->TypeGet()))
+ if ((memOp != nullptr) &&
+ !useLeaEncoding &&
+ (memOp->TypeGet() == tree->TypeGet()) &&
+ IsSafeToContainMem(tree, memOp))
{
MakeSrcContained(tree, memOp);
}
// tree - a binary tree node
//
// Return Value:
-// returns true if we can use the read-modify-write memory instruction form
+// Returns true if we can use the read-modify-write instruction form
+//
+// Notes:
+// This is used to determine whether to preference the source to the destination register.
//
bool Lowering::isRMWRegOper(GenTreePtr tree)
{