@@ -2609,14 +2609,55 @@ void CodeGen::genJumpTable(GenTree* treeNode)
26092609}
26102610
26112611// ------------------------------------------------------------------------
2612- // genLockedInstructions: Generate code for a GT_XADD or GT_XCHG node.
2612+ // genLockedInstructions: Generate code for a GT_XADD, GT_XAND, GT_XORR or GT_XCHG node.
26132613//
26142614// Arguments:
2615- // treeNode - the GT_XADD/XCHG node
2615+ // treeNode - the GT_XADD/XAND/XORR/ XCHG node
26162616//
26172617void CodeGen::genLockedInstructions (GenTreeOp* treeNode)
26182618{
2619- NYI_RISCV64 (" genLockedInstructions-----unimplemented/unused on RISCV64 yet----" );
2619+ GenTree* data = treeNode->AsOp ()->gtOp2 ;
2620+ GenTree* addr = treeNode->AsOp ()->gtOp1 ;
2621+ regNumber dataReg = data->GetRegNum ();
2622+ regNumber addrReg = addr->GetRegNum ();
2623+ regNumber targetReg = treeNode->GetRegNum ();
2624+ if (targetReg == REG_NA)
2625+ {
2626+ targetReg = REG_R0;
2627+ }
2628+
2629+ genConsumeAddress (addr);
2630+ genConsumeRegs (data);
2631+
2632+ emitAttr dataSize = emitActualTypeSize (data);
2633+ bool is4 = (dataSize == EA_4BYTE);
2634+
2635+ assert (!data->isContainedIntOrIImmed ());
2636+
2637+ instruction ins = INS_none;
2638+ switch (treeNode->gtOper )
2639+ {
2640+ case GT_XORR:
2641+ ins = is4 ? INS_amoor_w : INS_amoor_d;
2642+ break ;
2643+ case GT_XAND:
2644+ ins = is4 ? INS_amoand_w : INS_amoand_d;
2645+ break ;
2646+ case GT_XCHG:
2647+ ins = is4 ? INS_amoswap_w : INS_amoswap_d;
2648+ break ;
2649+ case GT_XADD:
2650+ ins = is4 ? INS_amoadd_w : INS_amoadd_d;
2651+ break ;
2652+ default :
2653+ noway_assert (!" Unexpected treeNode->gtOper" );
2654+ }
2655+ GetEmitter ()->emitIns_R_R_R (ins, dataSize, targetReg, addrReg, dataReg);
2656+
2657+ if (targetReg != REG_R0)
2658+ {
2659+ genProduceReg (treeNode);
2660+ }
26202661}
26212662
26222663// ------------------------------------------------------------------------
@@ -2627,7 +2668,62 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
26272668//
26282669void CodeGen::genCodeForCmpXchg (GenTreeCmpXchg* treeNode)
26292670{
2630- NYI_RISCV64 (" genCodeForCmpXchg-----unimplemented/unused on RISCV64 yet----" );
2671+ assert (treeNode->OperIs (GT_CMPXCHG));
2672+
2673+ GenTree* locOp = treeNode->gtOpLocation ;
2674+ GenTree* valOp = treeNode->gtOpValue ;
2675+ GenTree* comparandOp = treeNode->gtOpComparand ;
2676+
2677+ regNumber target = treeNode->GetRegNum ();
2678+ regNumber loc = locOp->GetRegNum ();
2679+ regNumber val = valOp->GetRegNum ();
2680+ regNumber comparand = comparandOp->GetRegNum ();
2681+ regNumber storeErr = treeNode->ExtractTempReg (RBM_ALLINT);
2682+
2683+ // Register allocator should have extended the lifetimes of all input and internal registers
2684+ // They should all be different
2685+ noway_assert (target != loc);
2686+ noway_assert (target != val);
2687+ noway_assert (target != comparand);
2688+ noway_assert (target != storeErr);
2689+ noway_assert (loc != val);
2690+ noway_assert (loc != comparand);
2691+ noway_assert (loc != storeErr);
2692+ noway_assert (val != comparand);
2693+ noway_assert (val != storeErr);
2694+ noway_assert (comparand != storeErr);
2695+ noway_assert (target != REG_NA);
2696+ noway_assert (storeErr != REG_NA);
2697+
2698+ assert (locOp->isUsedFromReg ());
2699+ assert (valOp->isUsedFromReg ());
2700+ assert (!comparandOp->isUsedFromMemory ());
2701+
2702+ genConsumeAddress (locOp);
2703+ genConsumeRegs (valOp);
2704+ genConsumeRegs (comparandOp);
2705+
2706+ // NOTE: `genConsumeAddress` marks consumed register as not a GC pointer, assuming the input
2707+ // registers die at the first generated instruction. However, here the input registers are reused,
2708+ // so mark the location register as a GC pointer until code generation for this node is finished.
2709+ gcInfo.gcMarkRegPtrVal (loc, locOp->TypeGet ());
2710+
2711+ BasicBlock* retry = genCreateTempLabel ();
2712+ BasicBlock* fail = genCreateTempLabel ();
2713+
2714+ emitter* e = GetEmitter ();
2715+ emitAttr size = emitActualTypeSize (valOp);
2716+ bool is4 = (size == EA_4BYTE);
2717+
2718+ genDefineTempLabel (retry);
2719+ e->emitIns_R_R_R (is4 ? INS_lr_w : INS_lr_d, size, target, loc, REG_R0); // load original value
2720+ e->emitIns_J_cond_la (INS_bne, fail, target, comparand); // fail if doesn’t match
2721+ e->emitIns_R_R_R (is4 ? INS_sc_w : INS_sc_d, size, storeErr, loc, val); // try to update
2722+ e->emitIns_J (INS_bnez, retry, storeErr); // retry if update failed
2723+ genDefineTempLabel (fail);
2724+
2725+ gcInfo.gcMarkRegSetNpt (locOp->gtGetRegMask ());
2726+ genProduceReg (treeNode);
26312727}
26322728
26332729static inline bool isImmed (GenTree* treeNode)
@@ -4643,6 +4739,8 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
46434739
46444740 case GT_XCHG:
46454741 case GT_XADD:
4742+ case GT_XORR:
4743+ case GT_XAND:
46464744 genLockedInstructions (treeNode->AsOp ());
46474745 break ;
46484746
0 commit comments