Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
JIT: Suppress emitting same-reg zero extending move (#22454)
Browse files Browse the repository at this point in the history
Add a peephole optimization to suppress emitting zero extending moves
if the previous instruction has already done a suitable zero extension.

Only implemented for x64 currently.

Closes #21923
  • Loading branch information
AndyAyersMS authored Feb 8, 2019
1 parent 76c322d commit d5f638a
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6398,6 +6398,7 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)

const regNumber srcReg = cast->gtGetOp1()->gtRegNum;
const regNumber dstReg = cast->gtRegNum;
emitter* emit = getEmitter();

assert(genIsValidIntReg(srcReg));
assert(genIsValidIntReg(dstReg));
Expand All @@ -6413,6 +6414,7 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)
{
instruction ins;
unsigned insSize;
bool canSkip = false;

switch (desc.ExtendKind())
{
Expand All @@ -6426,6 +6428,12 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)
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;
Expand All @@ -6436,12 +6444,20 @@ void CodeGen::genIntToIntCast(GenTreeCast* cast)
#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);
Expand Down
69 changes: 69 additions & 0 deletions src/jit/emitxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,75 @@ bool emitter::IsDstSrcSrcAVXInstruction(instruction ins)
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
Expand Down
2 changes: 2 additions & 0 deletions src/jit/emitxarch.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ code_t AddRexPrefix(instruction ins, code_t code);
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)
Expand Down

0 comments on commit d5f638a

Please sign in to comment.