Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 102 additions & 4 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2609,14 +2609,55 @@ void CodeGen::genJumpTable(GenTree* treeNode)
}

//------------------------------------------------------------------------
// genLockedInstructions: Generate code for a GT_XADD or GT_XCHG node.
// genLockedInstructions: Generate code for a GT_XADD, GT_XAND, GT_XORR or GT_XCHG node.
//
// Arguments:
// treeNode - the GT_XADD/XCHG node
// treeNode - the GT_XADD/XAND/XORR/XCHG node
//
void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
{
NYI_RISCV64("genLockedInstructions-----unimplemented/unused on RISCV64 yet----");
GenTree* data = treeNode->AsOp()->gtOp2;
GenTree* addr = treeNode->AsOp()->gtOp1;
regNumber dataReg = data->GetRegNum();
regNumber addrReg = addr->GetRegNum();
regNumber targetReg = treeNode->GetRegNum();
if (targetReg == REG_NA)
{
targetReg = REG_R0;
}

genConsumeAddress(addr);
genConsumeRegs(data);

emitAttr dataSize = emitActualTypeSize(data);
bool is4 = (dataSize == EA_4BYTE);

assert(!data->isContainedIntOrIImmed());

instruction ins = INS_none;
switch (treeNode->gtOper)
{
case GT_XORR:
ins = is4 ? INS_amoor_w : INS_amoor_d;
break;
case GT_XAND:
ins = is4 ? INS_amoand_w : INS_amoand_d;
break;
case GT_XCHG:
ins = is4 ? INS_amoswap_w : INS_amoswap_d;
break;
case GT_XADD:
ins = is4 ? INS_amoadd_w : INS_amoadd_d;
break;
default:
noway_assert(!"Unexpected treeNode->gtOper");
}
GetEmitter()->emitIns_R_R_R(ins, dataSize, targetReg, addrReg, dataReg);

if (targetReg != REG_R0)
{
genProduceReg(treeNode);
}
}

//------------------------------------------------------------------------
Expand All @@ -2627,7 +2668,62 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
//
void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode)
{
NYI_RISCV64("genCodeForCmpXchg-----unimplemented/unused on RISCV64 yet----");
assert(treeNode->OperIs(GT_CMPXCHG));

GenTree* locOp = treeNode->gtOpLocation;
GenTree* valOp = treeNode->gtOpValue;
GenTree* comparandOp = treeNode->gtOpComparand;

regNumber target = treeNode->GetRegNum();
regNumber loc = locOp->GetRegNum();
regNumber val = valOp->GetRegNum();
regNumber comparand = comparandOp->GetRegNum();
regNumber storeErr = treeNode->ExtractTempReg(RBM_ALLINT);

// Register allocator should have extended the lifetimes of all input and internal registers
// They should all be different
noway_assert(target != loc);
noway_assert(target != val);
noway_assert(target != comparand);
noway_assert(target != storeErr);
noway_assert(loc != val);
noway_assert(loc != comparand);
noway_assert(loc != storeErr);
noway_assert(val != comparand);
noway_assert(val != storeErr);
noway_assert(comparand != storeErr);
noway_assert(target != REG_NA);
noway_assert(storeErr != REG_NA);

assert(locOp->isUsedFromReg());
assert(valOp->isUsedFromReg());
assert(!comparandOp->isUsedFromMemory());

genConsumeAddress(locOp);
genConsumeRegs(valOp);
genConsumeRegs(comparandOp);

// NOTE: `genConsumeAddress` marks consumed register as not a GC pointer, assuming the input
// registers die at the first generated instruction. However, here the input registers are reused,
// so mark the location register as a GC pointer until code generation for this node is finished.
gcInfo.gcMarkRegPtrVal(loc, locOp->TypeGet());

BasicBlock* retry = genCreateTempLabel();
BasicBlock* fail = genCreateTempLabel();

emitter* e = GetEmitter();
emitAttr size = emitActualTypeSize(valOp);
bool is4 = (size == EA_4BYTE);

genDefineTempLabel(retry);
e->emitIns_R_R_R(is4 ? INS_lr_w : INS_lr_d, size, target, loc, REG_R0); // load original value
e->emitIns_J_cond_la(INS_bne, fail, target, comparand); // fail if doesn’t match
e->emitIns_R_R_R(is4 ? INS_sc_w : INS_sc_d, size, storeErr, loc, val); // try to update
e->emitIns_J(INS_bnez, retry, storeErr); // retry if update failed
genDefineTempLabel(fail);

gcInfo.gcMarkRegSetNpt(locOp->gtGetRegMask());
genProduceReg(treeNode);
}

static inline bool isImmed(GenTree* treeNode)
Expand Down Expand Up @@ -4643,6 +4739,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)

case GT_XCHG:
case GT_XADD:
case GT_XORR:
case GT_XAND:
genLockedInstructions(treeNode->AsOp());
break;

Expand Down
Loading