const regNumber srcReg = cast->gtGetOp1()->gtRegNum;
const regNumber dstReg = cast->gtRegNum;
+ emitter* emit = getEmitter();
assert(genIsValidIntReg(srcReg));
assert(genIsValidIntReg(dstReg));
{
instruction ins;
unsigned insSize;
+ bool canSkip = false;
switch (desc.ExtendKind())
{
break;
#ifdef _TARGET_64BIT_
case GenIntCastDesc::ZERO_EXTEND_INT:
+ // We can skip emitting this zero extending move if the previous instruction zero extended implicitly
+ if ((srcReg == dstReg) && compiler->opts.OptimizationEnabled())
+ {
+ canSkip = emit->AreUpper32BitsZero(srcReg);
+ }
+
ins = INS_mov;
insSize = 4;
break;
#endif
default:
assert(desc.ExtendKind() == GenIntCastDesc::COPY);
+ assert(srcReg != dstReg);
ins = INS_mov;
insSize = desc.ExtendSrcSize();
break;
}
- getEmitter()->emitIns_R_R(ins, EA_ATTR(insSize), dstReg, srcReg);
+ if (canSkip)
+ {
+ JITDUMP("\n -- suppressing emission as previous instruction already properly extends.\n");
+ }
+ else
+ {
+ emit->emitIns_R_R(ins, EA_ATTR(insSize), dstReg, srcReg);
+ }
}
genProduceReg(cast);
return ((CodeGenInterface::instInfo[ins] & INS_Flags_IsDstSrcSrcAVXInstruction) != 0) && IsAVXInstruction(ins);
}
+//------------------------------------------------------------------------
+// AreUpper32BitsZero: check if some previously emitted
+// instruction set the upper 32 bits of reg to zero.
+//
+// Arguments:
+// reg - register of interest
+//
+// Return Value:
+// true if previous instruction zeroed reg's upper 32 bits.
+// false if it did not, or if we can't safely determine.
+//
+// Notes:
+// Currently only looks back one instruction.
+//
+// movsx eax, ... might seem viable but we always encode this
+// instruction with a 64 bit destination. See TakesRexWPrefix.
+
+bool emitter::AreUpper32BitsZero(regNumber reg)
+{
+ // Don't look back across IG boundaries (possible control flow)
+ if (emitCurIGinsCnt == 0)
+ {
+ return false;
+ }
+
+ instrDesc* id = emitLastIns;
+ insFormat fmt = id->idInsFmt();
+
+ // This isn't meant to be a comprehensive check. Just look for what
+ // seems to be common.
+ switch (fmt)
+ {
+ case IF_RWR_CNS:
+ case IF_RRW_CNS:
+ case IF_RRW_SHF:
+ case IF_RWR_RRD:
+ case IF_RRW_RRD:
+ case IF_RWR_MRD:
+ case IF_RWR_SRD:
+ case IF_RWR_ARD:
+
+ // Bail if not writing to the right register
+ if (id->idReg1() != reg)
+ {
+ return false;
+ }
+
+ // Bail if movsx, we always have movsx sign extend to 8 bytes
+ if (id->idIns() == INS_movsx)
+ {
+ return false;
+ }
+
+ // movzx always zeroes the upper 32 bits.
+ if (id->idIns() == INS_movzx)
+ {
+ return true;
+ }
+
+ // Else rely on operation size.
+ return (id->idOpSize() == EA_4BYTE);
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
#ifdef FEATURE_HW_INTRINSICS
//------------------------------------------------------------------------
// IsDstSrcImmAvxInstruction: Checks if the instruction has a "reg, reg/mem, imm" or
bool EncodedBySSE38orSSE3A(instruction ins);
bool Is4ByteSSEInstruction(instruction ins);
+bool AreUpper32BitsZero(regNumber reg);
+
// Adjust code size for CRC32 that has 4-byte opcode
// but does not use SSE38 or EES3A encoding.
UNATIVE_OFFSET emitAdjustSizeCrc32(instruction ins, emitAttr attr)