{
case GT_LSH:
{
+ // Reduce count modulo 64 to match behavior found in
+ // the LLSH helper and in gtFoldExpr.
+ count &= 0x3F;
+
+ // Retest for zero shift
+ if (count == 0)
+ {
+ GenTree* next = shift->gtNext;
+ // Remove shift and don't do anything else.
+ if (shift->IsUnusedValue())
+ {
+ gtLong->SetUnusedValue();
+ }
+ Range().Remove(shift);
+ use.ReplaceWith(m_compiler, gtLong);
+ return next;
+ }
+
if (count < 32)
{
// For shifts of < 32 bits, we transform the code to:
}
else
{
- assert(count >= 32);
+ assert(count >= 32 && count < 64);
// Since we're left shifting at least 32 bits, we can remove the hi part of the shifted value iff
// it has no side effects.
hiOp1->SetUnusedValue();
}
- if (count < 64)
+ if (count == 32)
{
- if (count == 32)
- {
- // Move loOp1 into hiResult (shift of 32 bits is just a mov of lo to hi)
- // We need to make sure that we save lo to a temp variable so that we don't overwrite lo
- // before saving it to hi in the case that we are doing an inplace shift. I.e.:
- // x = x << 32
+ // Move loOp1 into hiResult (shift of 32 bits is just a mov of lo to hi)
+ // We need to make sure that we save lo to a temp variable so that we don't overwrite lo
+ // before saving it to hi in the case that we are doing an inplace shift. I.e.:
+ // x = x << 32
- LIR::Use loOp1Use(Range(), >Long->gtOp.gtOp1, gtLong);
- loOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight);
-
- hiResult = loOp1Use.Def();
- Range().Remove(gtLong);
- }
- else
- {
- Range().Remove(gtLong);
- assert(count > 32 && count < 64);
+ LIR::Use loOp1Use(Range(), >Long->gtOp.gtOp1, gtLong);
+ loOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight);
- // Move loOp1 into hiResult, do a GT_LSH with count - 32.
- // We will compute hiResult before loResult in this case, so we don't need to store lo to a
- // temp
- GenTree* shiftBy = m_compiler->gtNewIconNode(count - 32, TYP_INT);
- hiResult = m_compiler->gtNewOperNode(oper, TYP_INT, loOp1, shiftBy);
- Range().InsertBefore(shift, shiftBy, hiResult);
- }
+ hiResult = loOp1Use.Def();
+ Range().Remove(gtLong);
}
else
{
- assert(count >= 64);
-
Range().Remove(gtLong);
-
- // Since we're left shifting at least 64 bits, we can remove the lo part of the shifted value
- // iff it has no side effects.
- //
- // TODO-CQ: we could go perform this removal transitively (i.e. iteratively remove everything
- // that feeds the lo operand while there are no side effects)
- if ((loOp1->gtFlags & (GTF_ALL_EFFECT | GTF_SET_FLAGS)) == 0)
- {
- Range().Remove(loOp1, true);
- }
- else
- {
- loOp1->SetUnusedValue();
- }
-
- // Zero out hi (shift of >= 64 bits moves all the bits out of the two registers)
- hiResult = m_compiler->gtNewZeroConNode(TYP_INT);
- Range().InsertBefore(shift, hiResult);
+ assert(count > 32 && count < 64);
+
+ // Move loOp1 into hiResult, do a GT_LSH with count - 32.
+ // We will compute hiResult before loResult in this case, so we don't need to store lo to a
+ // temp
+ GenTree* shiftBy = m_compiler->gtNewIconNode(count - 32, TYP_INT);
+ hiResult = m_compiler->gtNewOperNode(oper, TYP_INT, loOp1, shiftBy);
+ Range().InsertBefore(shift, shiftBy, hiResult);
}
// Zero out loResult (shift of >= 32 bits shifts all lo bits to hiResult)