The register allocator uses `OperIsShiftOrRotate` as the assertion for the method that gets the kills for the class of instructions that use RCX as the shift amount register. Expand it to include `RSH_LO` and `LSH_HI`.
Fix #19081
GenTree* data = storeInd->Data();
GenTree* addr = storeInd->Addr();
- assert(data->OperIsShiftOrRotate());
+ assert(data->OperIsShift() || data->OperIsRotate());
// This function only handles the RMW case.
assert(data->gtOp.gtOp1->isUsedFromMemory());
return OperIsShift(OperGet());
}
+ static bool OperIsShiftLong(genTreeOps gtOper)
+ {
+#ifdef _TARGET_64BIT_
+ return false;
+#else
+ return (gtOper == GT_LSH_HI) || (gtOper == GT_RSH_LO);
+#endif
+ }
+
+ bool OperIsShiftLong() const
+ {
+ return OperIsShiftLong(OperGet());
+ }
+
static bool OperIsRotate(genTreeOps gtOper)
{
return (gtOper == GT_ROL) || (gtOper == GT_ROR);
static bool OperIsShiftOrRotate(genTreeOps gtOper)
{
- return OperIsShift(gtOper) || OperIsRotate(gtOper);
+ return OperIsShift(gtOper) || OperIsRotate(gtOper) || OperIsShiftLong(gtOper);
}
bool OperIsShiftOrRotate() const
void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
{
GenTree* shiftBy = node->gtOp2;
+ assert(node->OperIsShiftOrRotate());
#ifdef _TARGET_ARM_
GenTree* source = node->gtOp1;
assert(source->OperGet() == GT_LONG);
MakeSrcContained(node, source);
}
-#else // !_TARGET_ARM_
- assert(node->OperIsShiftOrRotate());
-#endif // !_TARGET_ARM_
+#endif // _TARGET_ARM_
if (shiftBy->IsCnsIntOrI())
{
//
void Lowering::ContainCheckShiftRotate(GenTreeOp* node)
{
+ assert(node->OperIsShiftOrRotate());
#ifdef _TARGET_X86_
GenTree* source = node->gtOp1;
- if (node->OperIs(GT_LSH_HI, GT_RSH_LO))
+ if (node->OperIsShiftLong())
{
assert(source->OperGet() == GT_LONG);
MakeSrcContained(node, source);
}
- else
#endif // !_TARGET_X86_
- {
- assert(node->OperIsShiftOrRotate());
- }
GenTree* shiftBy = node->gtOp2;
if (IsContainableImmed(node, shiftBy) && (shiftBy->gtIntConCommon.IconValue() <= 255) &&