Skip to content

Commit

Permalink
Cleanup unrolled block op codegen (dotnet#27146)
Browse files Browse the repository at this point in the history
* Move genCodeForInitBlkUnroll to codegenarmarch

* Cleanup unrolled block op codegen

* Fix comment header

* Delete GT_INIT_VAL support from genConsumeRegs

* Add XArch TODO

* Use explicit size in instruction selection
  • Loading branch information
mikedn authored and Sergey Andreenko committed Oct 11, 2019
1 parent 99839c5 commit 711a716
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 434 deletions.
9 changes: 1 addition & 8 deletions src/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1159,19 +1159,12 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode);
void genStructPutArgUnroll(GenTreePutArgStk* putArgStkNode);
void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
#endif // FEATURE_PUT_STRUCT_ARG_STK

void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);

#ifdef _TARGET_ARM64_
void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
#endif // _TARGET_ARM64_

void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
#ifndef _TARGET_X86_
void genCodeForInitBlkHelper(GenTreeBlk* initBlkNode);
Expand Down
10 changes: 0 additions & 10 deletions src/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,16 +721,6 @@ instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
return ins;
}

// Generate code for InitBlk by performing a loop unroll
// Preconditions:
// a) Both the size and fill byte value are integer constants.
// b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
{
// TODO: Generate memory barrier instructions for GTF_BLK_VOLATILE flag
NYI_ARM("genCodeForInitBlkUnroll");
}

//------------------------------------------------------------------------
// genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
//
Expand Down
114 changes: 0 additions & 114 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2485,120 +2485,6 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree)
}
}

// Generate code for InitBlk by performing a loop unroll
// Preconditions:
// a) Both the size and fill byte value are integer constants.
// b) The size of the struct to initialize is smaller than INITBLK_UNROLL_LIMIT bytes.
void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
{
// Make sure we got the arguments of the initblk/initobj operation in the right registers
unsigned size = initBlkNode->Size();
GenTree* dstAddr = initBlkNode->Addr();
GenTree* initVal = initBlkNode->Data();
if (initVal->OperIsInitVal())
{
initVal = initVal->gtGetOp1();
}

assert(dstAddr->isUsedFromReg());
assert((initVal->isUsedFromReg() && !initVal->IsIntegralConst(0)) || initVal->IsIntegralConst(0));
assert(size != 0);
assert(size <= INITBLK_UNROLL_LIMIT);

emitter* emit = GetEmitter();

genConsumeOperands(initBlkNode);

if (initBlkNode->gtFlags & GTF_BLK_VOLATILE)
{
// issue a full memory barrier before a volatile initBlockUnroll operation
instGen_MemoryBarrier();
}

regNumber valReg = initVal->IsIntegralConst(0) ? REG_ZR : initVal->GetRegNum();

assert(!initVal->IsIntegralConst(0) || (valReg == REG_ZR));

unsigned offset = 0;

// Perform an unroll using stp.
if (size >= 2 * REGSIZE_BYTES)
{
// Determine how many 16 byte slots
size_t slots = size / (2 * REGSIZE_BYTES);

while (slots-- > 0)
{
emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, valReg, valReg, dstAddr->GetRegNum(), offset);
offset += (2 * REGSIZE_BYTES);
}
}

// Fill the remainder (15 bytes or less) if there's any.
if ((size & 0xf) != 0)
{
if ((size & 8) != 0)
{
emit->emitIns_R_R_I(INS_str, EA_8BYTE, valReg, dstAddr->GetRegNum(), offset);
offset += 8;
}
if ((size & 4) != 0)
{
emit->emitIns_R_R_I(INS_str, EA_4BYTE, valReg, dstAddr->GetRegNum(), offset);
offset += 4;
}
if ((size & 2) != 0)
{
emit->emitIns_R_R_I(INS_strh, EA_2BYTE, valReg, dstAddr->GetRegNum(), offset);
offset += 2;
}
if ((size & 1) != 0)
{
emit->emitIns_R_R_I(INS_strb, EA_1BYTE, valReg, dstAddr->GetRegNum(), offset);
}
}
}

// Generate code for a load pair from some address + offset
// base: tree node which can be either a local address or arbitrary node
// offset: distance from the base from which to load
void CodeGen::genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset)
{
emitter* emit = GetEmitter();

if (base->OperIsLocalAddr())
{
if (base->gtOper == GT_LCL_FLD_ADDR)
offset += base->gtLclFld.gtLclOffs;

emit->emitIns_R_R_S_S(INS_ldp, EA_8BYTE, EA_8BYTE, dst, dst2, base->gtLclVarCommon.GetLclNum(), offset);
}
else
{
emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, dst, dst2, base->GetRegNum(), offset);
}
}

// Generate code for a store pair to some address + offset
// base: tree node which can be either a local address or arbitrary node
// offset: distance from the base from which to load
void CodeGen::genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset)
{
emitter* emit = GetEmitter();

if (base->OperIsLocalAddr())
{
if (base->gtOper == GT_LCL_FLD_ADDR)
offset += base->gtLclFld.gtLclOffs;

emit->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, src, src2, base->gtLclVarCommon.GetLclNum(), offset);
}
else
{
emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, src, src2, base->GetRegNum(), offset);
}
}

// Generate code for CpObj nodes wich copy structs that have interleaved
// GC pointers.
// For this case we'll generate a sequence of loads/stores in the case of struct
Expand Down
Loading

0 comments on commit 711a716

Please sign in to comment.