Skip to content

Commit

Permalink
Widen index to a temporary register
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedn committed Feb 15, 2019
1 parent 9b78e13 commit 091bc56
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 38 deletions.
35 changes: 15 additions & 20 deletions src/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4608,7 +4608,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
GenTree* const index = node->Index();

const regNumber baseReg = genConsumeReg(base);
const regNumber indexReg = genConsumeReg(index);
regNumber indexReg = genConsumeReg(index);
const regNumber dstReg = node->gtRegNum;

// NOTE: `genConsumeReg` marks the consumed register as not a GC pointer, as it assumes that the input registers
Expand All @@ -4620,6 +4620,9 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
assert(varTypeIsIntegral(index->TypeGet()));

regNumber tmpReg = REG_NA;
#ifdef _TARGET_64BIT_
tmpReg = node->GetSingleTempReg();
#endif

// Generate the bounds check if necessary.
if ((node->gtFlags & GTF_INX_RNGCHK) != 0)
Expand All @@ -4629,7 +4632,6 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
// is a native int on a 64-bit platform, we will need to widen the array length and then compare.
if (index->TypeGet() == TYP_I_IMPL)
{
tmpReg = node->GetSingleTempReg();
getEmitter()->emitIns_R_AR(INS_mov, EA_4BYTE, tmpReg, baseReg, static_cast<int>(node->gtLenOffset));
getEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, indexReg, tmpReg);
}
Expand All @@ -4646,9 +4648,8 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
if (index->TypeGet() != TYP_I_IMPL)
{
// LEA needs 64-bit operands so we need to widen the index if it's TYP_INT.
// Since it's TYP_INT the upper 32 bits aren't used so we should be able
// to widen in place, without needing a temporary register.
getEmitter()->emitIns_R_R(INS_mov, EA_4BYTE, indexReg, indexReg);
getEmitter()->emitIns_R_R(INS_mov, EA_4BYTE, tmpReg, indexReg);
indexReg = tmpReg;
}
#endif // _TARGET_64BIT_

Expand All @@ -4665,22 +4666,16 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
break;

default:
if (tmpReg == REG_NA)
{
tmpReg = node->GetSingleTempReg();
}
#ifdef _TARGET_64BIT_
if (scale > INT32_MAX)
{
genSetRegToIcon(tmpReg, static_cast<ssize_t>(scale), TYP_INT);
getEmitter()->emitIns_R_R(INS_imul, EA_PTRSIZE, tmpReg, indexReg);
}
else
#endif // _TARGET_64BIT_
{
getEmitter()->emitIns_R_I(emitter::inst3opImulForReg(tmpReg), EA_PTRSIZE, indexReg,
static_cast<ssize_t>(scale));
}
// IMUL treats its immediate operand as signed so scale can't be larger than INT32_MAX.
// The VM doesn't allow such large array elements but let's be sure.
noway_assert(scale <= INT32_MAX);
#else // !_TARGET_64BIT_
tmpReg = node->GetSingleTempReg();
#endif // !_TARGET_64BIT_

getEmitter()->emitIns_R_I(emitter::inst3opImulForReg(tmpReg), EA_PTRSIZE, indexReg,
static_cast<ssize_t>(scale));
scale = 1;
break;
}
Expand Down
39 changes: 21 additions & 18 deletions src/jit/lsraxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,25 +659,28 @@ int LinearScan::BuildNode(GenTree* tree)
{
assert(dstCount == 1);
RefPosition* internalDef = nullptr;
if (tree->AsIndexAddr()->Index()->TypeGet() == TYP_I_IMPL)
{
internalDef = buildInternalIntRegisterDefForNode(tree);
}
else
{
switch (tree->AsIndexAddr()->gtElemSize)
{
case 1:
case 2:
case 4:
case 8:
break;

default:
internalDef = buildInternalIntRegisterDefForNode(tree);
break;
}
#ifdef _TARGET_64BIT_
// On 64-bit we always need a temporary register:
// - if the index is `native int` then we need to load the array
// length into a register to widen it to `native int`
// - if the index is `int` (or smaller) then we need to widen
// it to `long` to peform the address calculation
internalDef = buildInternalIntRegisterDefForNode(tree);
#else // !_TARGET_64BIT_
assert(!varTypeIsLong(tree->AsIndexAddr()->Index()->TypeGet()));
switch (tree->AsIndexAddr()->gtElemSize)
{
case 1:
case 2:
case 4:
case 8:
break;

default:
internalDef = buildInternalIntRegisterDefForNode(tree);
break;
}
#endif // !_TARGET_64BIT_
srcCount = BuildBinaryUses(tree->AsOp());
if (internalDef != nullptr)
{
Expand Down

0 comments on commit 091bc56

Please sign in to comment.