Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LoongArch64] Fix the wrong GCInfo when testing GCStress. #72572

Merged
merged 13 commits into from
Aug 4, 2022
5 changes: 4 additions & 1 deletion src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genLeaInstruction(GenTreeAddrMode* lea);
void genSetRegToCond(regNumber dstReg, GenTree* tree);

#if defined(TARGET_ARMARCH)
#if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64)
void genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale);
#endif // TARGET_ARMARCH || TARGET_LOONGARCH64

#if defined(TARGET_ARMARCH)
void genCodeForMulLong(GenTreeOp* mul);
#endif // TARGET_ARMARCH

Expand Down
192 changes: 139 additions & 53 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2973,6 +2973,11 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
{
emitAttr attr0 = emitTypeSize(layout->GetGCPtrType(i + 0));
emitAttr attr1 = emitTypeSize(layout->GetGCPtrType(i + 1));
if (i + 2 >= slots)
{
attrSrcAddr = EA_8BYTE;
attrDstAddr = EA_8BYTE;
}

emit->emitIns_R_R_I(INS_ld_d, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, 0);
emit->emitIns_R_R_I(INS_ld_d, attr1, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE);
Expand All @@ -2989,6 +2994,11 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
if (i < slots)
{
emitAttr attr0 = emitTypeSize(layout->GetGCPtrType(i + 0));
if (i + 1 >= slots)
{
attrSrcAddr = EA_8BYTE;
attrDstAddr = EA_8BYTE;
}

emit->emitIns_R_R_I(INS_ld_d, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, 0);
emit->emitIns_R_R_I(INS_addi_d, attrSrcAddr, REG_WRITE_BARRIER_SRC_BYREF, REG_WRITE_BARRIER_SRC_BYREF,
Expand All @@ -3010,6 +3020,11 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
// Check if the next slot's type is also TYP_GC_NONE and use two ld/sd
if ((i + 1 < slots) && !layout->IsGCPtr(i + 1))
{
if (i + 2 >= slots)
{
attrSrcAddr = EA_8BYTE;
attrDstAddr = EA_8BYTE;
}
emit->emitIns_R_R_I(INS_ld_d, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, 0);
emit->emitIns_R_R_I(INS_ld_d, EA_8BYTE, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE);
emit->emitIns_R_R_I(INS_addi_d, attrSrcAddr, REG_WRITE_BARRIER_SRC_BYREF,
Expand All @@ -3022,6 +3037,11 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
}
else
{
if (i + 1 >= slots)
{
attrSrcAddr = EA_8BYTE;
attrDstAddr = EA_8BYTE;
}
emit->emitIns_R_R_I(INS_ld_d, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, 0);
emit->emitIns_R_R_I(INS_addi_d, attrSrcAddr, REG_WRITE_BARRIER_SRC_BYREF,
REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE);
Expand Down Expand Up @@ -3562,10 +3582,10 @@ void CodeGen::genCodeForReturnTrap(GenTreeOp* tree)
false /* isJump */
);

genDefineTempLabel(skipLabel);

regMaskTP killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC);
regSet.verifyRegistersUsed(killMask);

genDefineTempLabel(skipLabel);
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -4188,13 +4208,13 @@ void CodeGen::genCodeForCompare(GenTreeOp* jtree)
{
if (!IsUnsigned && emitter::isValidSimm12(imm + 1))
{
emit->emitIns_R_R_I(INS_slti, EA_PTRSIZE, REG_RA, regOp1, imm + 1);
emit->emitIns_R_R_I(INS_xori, EA_PTRSIZE, targetReg, REG_RA, 1);
emit->emitIns_R_R_I(INS_slti, EA_PTRSIZE, targetReg, regOp1, imm + 1);
emit->emitIns_R_R_I(INS_xori, EA_PTRSIZE, targetReg, targetReg, 1);
}
else if (IsUnsigned && emitter::isValidUimm11(imm + 1))
{
emit->emitIns_R_R_I(INS_sltui, EA_PTRSIZE, REG_RA, regOp1, imm + 1);
emit->emitIns_R_R_I(INS_xori, EA_PTRSIZE, targetReg, REG_RA, 1);
emit->emitIns_R_R_I(INS_sltui, EA_PTRSIZE, targetReg, regOp1, imm + 1);
emit->emitIns_R_R_I(INS_xori, EA_PTRSIZE, targetReg, targetReg, 1);
}
else
{
Expand Down Expand Up @@ -5513,11 +5533,9 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
genPutArgReg(treeNode->AsOp());
break;

#if FEATURE_ARG_SPLIT
case GT_PUTARG_SPLIT:
genPutArgSplit(treeNode->AsPutArgSplit());
break;
#endif // FEATURE_ARG_SPLIT

case GT_CALL:
genCall(treeNode->AsCall());
Expand Down Expand Up @@ -6114,7 +6132,6 @@ void CodeGen::genPutArgReg(GenTreeOp* tree)
genProduceReg(tree);
}

#if FEATURE_ARG_SPLIT
//---------------------------------------------------------------------
// genPutArgSplit - generate code for a GT_PUTARG_SPLIT node
//
Expand Down Expand Up @@ -6324,7 +6341,6 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
}
genProduceReg(treeNode);
}
#endif // FEATURE_ARG_SPLIT

//------------------------------------------------------------------------
// genRangeCheck: generate code for GT_BOUNDS_CHECK node.
Expand Down Expand Up @@ -6647,6 +6663,46 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
genProduceReg(tree);
}

//------------------------------------------------------------------------
// genScaledAdd: A helper for `dest = base + (index << scale)`
// and maybe optimize the instruction(s) for this operation.
//
void CodeGen::genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale)
{
emitter* emit = GetEmitter();
if (scale == 0)
{
instruction ins = attr == EA_4BYTE ? INS_add_w : INS_add_d;
// target = base + index
emit->emitIns_R_R_R(ins, attr, targetReg, baseReg, indexReg);
}
else if (scale <= 4)
{
instruction ins = attr == EA_4BYTE ? INS_alsl_w : INS_alsl_d;
// target = base + index << scale
emit->emitIns_R_R_R_I(ins, attr, targetReg, indexReg, baseReg, scale - 1);
}
else
{
instruction ins;
instruction ins2;
if (attr == EA_4BYTE)
{
ins = INS_slli_w;
ins2 = INS_add_w;
}
else
{
ins = INS_slli_d;
ins2 = INS_add_d;
}

// target = base + index << scale
emit->emitIns_R_R_I(ins, attr, REG_R21, indexReg, scale);
emit->emitIns_R_R_R(ins2, attr, targetReg, baseReg, REG_R21);
}
}

//------------------------------------------------------------------------
// genCodeForIndexAddr: Produce code for a GT_INDEX_ADDR node.
//
Expand Down Expand Up @@ -6692,42 +6748,55 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
emitAttr attr = emitActualTypeSize(node);
// Can we use a shift instruction for multiply ?
//
if (isPow2(node->gtElemSize) && (node->gtElemSize < 0x10000000u))
if (isPow2(node->gtElemSize))
{
regNumber tmpReg;
if (node->gtElemSize == 0)
DWORD scale;
BitScanForward(&scale, node->gtElemSize);

// dest = base + (index << scale)
if (node->gtElemSize <= 64)
{
// dest = base + index
tmpReg = index->GetRegNum();
genScaledAdd(attr, node->GetRegNum(), base->GetRegNum(), index->GetRegNum(), scale);
}
else
{
DWORD scale;
BitScanForward(&scale, node->gtElemSize);

// tmpReg = base + index << scale
// dest = base + tmpReg
GetEmitter()->emitIns_R_R_I(INS_slli_d, attr, REG_R21, index->GetRegNum(), scale);
tmpReg = REG_R21;
GetEmitter()->emitIns_I_la(EA_PTRSIZE, REG_R21, scale);
instruction ins;
instruction ins2;
if (attr == EA_4BYTE)
{
ins = INS_sll_w;
ins2 = INS_add_w;
}
else
{
ins = INS_sll_d;
ins2 = INS_add_d;
}
GetEmitter()->emitIns_R_R_R(ins, attr, REG_R21, index->GetRegNum(), REG_R21);
GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), REG_R21, base->GetRegNum());
}
GetEmitter()->emitIns_R_R_R(INS_add_d, attr, node->GetRegNum(), base->GetRegNum(), tmpReg);
}
else // we have to load the element size and use a MADD (multiply-add) instruction
{
// REG_R21 = element size
CodeGen::genSetRegToIcon(REG_R21, (ssize_t)node->gtElemSize, TYP_INT);

// dest = index * REG_R21 + base
instruction ins;
instruction ins2;
if (attr == EA_4BYTE)
{
GetEmitter()->emitIns_R_R_R(INS_mul_w, EA_4BYTE, REG_R21, index->GetRegNum(), REG_R21);
GetEmitter()->emitIns_R_R_R(INS_add_w, attr, node->GetRegNum(), REG_R21, base->GetRegNum());
ins = INS_mul_w;
ins2 = INS_add_w;
}
else
{
GetEmitter()->emitIns_R_R_R(INS_mul_d, EA_PTRSIZE, REG_R21, index->GetRegNum(), REG_R21);
GetEmitter()->emitIns_R_R_R(INS_add_d, attr, node->GetRegNum(), REG_R21, base->GetRegNum());
ins = INS_mul_d;
ins2 = INS_add_d;
}
GetEmitter()->emitIns_R_R_R(ins, EA_PTRSIZE, REG_R21, index->GetRegNum(), REG_R21);
GetEmitter()->emitIns_R_R_R(ins2, attr, node->GetRegNum(), REG_R21, base->GetRegNum());
}

// dest = dest + elemOffs
Expand Down Expand Up @@ -7068,13 +7137,25 @@ void CodeGen::genCall(GenTreeCall* call)
}
else if (abiInfo.IsSplit())
{
NYI("unimplemented on LOONGARCH64 yet");
assert(compFeatureArgSplit());
genConsumeArgSplitStruct(argNode->AsPutArgSplit());

regNumber argReg = abiInfo.GetRegNum();
regNumber allocReg = argNode->AsPutArgSplit()->GetRegNumByIdx(0);
var_types regType = argNode->AsPutArgSplit()->GetRegType(0);

// For LA64's ABI, the split is only using the A7 and stack for passing arg.
assert(emitter::isGeneralRegister(argReg));
assert(emitter::isGeneralRegister(allocReg));
assert(abiInfo.NumRegs == 1);

inst_Mov(regType, argReg, allocReg, /* canSkip */ true);
}
else
{
regNumber argReg = abiInfo.GetRegNum();
genConsumeReg(argNode);
var_types dstType = emitter::isFloatReg(argReg) ? TYP_DOUBLE : TYP_I_IMPL;
var_types dstType = emitter::isFloatReg(argReg) ? TYP_DOUBLE : argNode->TypeGet();
inst_Mov(dstType, argReg, argNode->GetRegNum(), /* canSkip */ true);
}
}
Expand Down Expand Up @@ -7981,44 +8062,45 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
GenTree* memBase = lea->Base();
GenTree* index = lea->Index();

DWORD scale;

assert(isPow2(lea->gtScale));
BitScanForward(&scale, lea->gtScale);
assert(scale <= 4);

regNumber tmpReg;
if (lea->gtScale == 0)
if (offset == 0)
{
tmpReg = index->GetRegNum();
// Then compute target reg from [base + index*scale]
genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale);
}
else
{
DWORD scale;
BitScanForward(&scale, lea->gtScale);
assert(scale <= 4);

emit->emitIns_R_R_I(INS_slli_d, EA_PTRSIZE, REG_R21, index->GetRegNum(), scale);
tmpReg = REG_R21;
}
// When generating fully interruptible code we have to use the "large offset" sequence
// when calculating a EA_BYREF as we can't report a byref that points outside of the object
bool useLargeOffsetSeq = compiler->GetInterruptible() && (size == EA_BYREF);

if (offset != 0)
{
if (emitter::isValidSimm12(offset))
if (!useLargeOffsetSeq && emitter::isValidSimm12(offset))
{
emit->emitIns_R_R_I(INS_addi_d, size, tmpReg, tmpReg, offset);
genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale);
instruction ins = size == EA_4BYTE ? INS_addi_w : INS_addi_d;
emit->emitIns_R_R_I(ins, size, lea->GetRegNum(), lea->GetRegNum(), offset);
}
else
{
regNumber tmpReg2 = lea->GetSingleTempReg();
regNumber tmpReg = lea->GetSingleTempReg();

noway_assert(tmpReg2 != index->GetRegNum());
noway_assert(tmpReg2 != memBase->GetRegNum());
noway_assert(tmpReg2 != tmpReg);
noway_assert(tmpReg != index->GetRegNum());
noway_assert(tmpReg != memBase->GetRegNum());

// compute the large offset.
emit->emitIns_I_la(EA_PTRSIZE, tmpReg2, offset);
emit->emitIns_R_R_R(INS_add_d, size, tmpReg, tmpReg, tmpReg2);
instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);

genScaledAdd(EA_PTRSIZE, tmpReg, tmpReg, index->GetRegNum(), scale);

instruction ins = size == EA_4BYTE ? INS_add_w : INS_add_d;
emit->emitIns_R_R_R(ins, size, lea->GetRegNum(), tmpReg, memBase->GetRegNum());
}
}

emit->emitIns_R_R_R(INS_add_d, size, lea->GetRegNum(), memBase->GetRegNum(), tmpReg);
}
else if (lea->Base())
{
Expand Down Expand Up @@ -8353,6 +8435,8 @@ inline void CodeGen::genJumpToThrowHlpBlk_la(
emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
}

BasicBlock* skipLabel = genCreateTempLabel();

emit->emitIns_Call(callType, compiler->eeFindHelper(compiler->acdHelper(codeKind)),
INDEBUG_LDISASM_COMMA(nullptr) addr, 0, EA_UNKNOWN, EA_UNKNOWN, gcInfo.gcVarPtrSetCur,
gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, DebugInfo(), /* IL offset */
Expand All @@ -8363,6 +8447,8 @@ inline void CodeGen::genJumpToThrowHlpBlk_la(

regMaskTP killMask = compiler->compHelperCallKillSet((CorInfoHelpFunc)(compiler->acdHelper(codeKind)));
regSet.verifyRegistersUsed(killMask);

genDefineTempLabel(skipLabel);
}
}

Expand Down Expand Up @@ -9240,13 +9326,13 @@ void CodeGen::genFnPrologCalleeRegArgs()
GetEmitter()->emitIns_I_la(EA_PTRSIZE, REG_R21, base);
// NOTE: `REG_R21` will be used within `emitIns_S_R`.
// Details see the comment for `emitIns_S_R`.
GetEmitter()->emitIns_S_R(INS_stx_d, size, REG_ARG_LAST, varNum, -8);
GetEmitter()->emitIns_S_R(INS_stx_d, size, REG_SCRATCH, varNum, -8);
}
else
{
baseOffset = -(base - tmp_offset) - 8;
GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_R21, REG_R21, 8);
GetEmitter()->emitIns_S_R(INS_stx_d, size, REG_ARG_LAST, varNum, baseOffset);
GetEmitter()->emitIns_S_R(INS_stx_d, size, REG_SCRATCH, varNum, baseOffset);
}
}
}
Expand Down
Loading