From fc34424b3825a3e3113195207f8265b53fb71444 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 28 Jan 2026 15:11:24 -0800 Subject: [PATCH 1/4] Checkpoint block stores --- src/coreclr/jit/lowerwasm.cpp | 59 ++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index c7a8d34a437c24..e5c79f11afbd0e 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -171,7 +171,64 @@ GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp) // void Lowering::LowerBlockStore(GenTreeBlk* blkNode) { - NYI_WASM("LowerBlockStore"); + GenTree* dstAddr = blkNode->Addr(); + GenTree* src = blkNode->Data(); + unsigned size = blkNode->Size(); + + if (blkNode->OperIsInitBlkOp()) + { + if (src->OperIs(GT_INIT_VAL)) + { + src->SetContained(); + src = src->AsUnOp()->gtGetOp1(); + } + + if (blkNode->IsZeroingGcPointersOnHeap()) + { + blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindLoop; + // We're going to use REG_R0 for zero + src->SetContained(); + NYI_WASM("memory.fill of gc pointers"); + } + else + { + NYI_WASM("memory.fill"); + } + } + else + { + assert(src->OperIs(GT_IND, GT_LCL_VAR, GT_LCL_FLD)); + src->SetContained(); + + if (src->OperIs(GT_LCL_VAR)) + { + // TODO-1stClassStructs: for now we can't work with STORE_BLOCK source in register. + const unsigned srcLclNum = src->AsLclVar()->GetLclNum(); + comp->lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(DoNotEnregisterReason::BlockOp)); + } + + ClassLayout* layout = blkNode->GetLayout(); + bool doCpObj = layout->HasGCPtr(); + unsigned copyBlockUnrollLimit = comp->getUnrollThreshold(Compiler::UnrollKind::Memcpy); + + // CopyObj or CopyBlk + if (doCpObj) + { + // Try to use bulk copy helper + if (TryLowerBlockStoreAsGcBulkCopyCall(blkNode)) + { + return; + } + + assert(dstAddr->TypeIs(TYP_BYREF, TYP_I_IMPL)); + blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindCpObjUnroll; + } + else + { + assert(blkNode->OperIs(GT_STORE_BLK)); + NYI_WASM("memory.copy"); + } + } } //------------------------------------------------------------------------ From 34c54419343e163fe832dfd8181590d747598b9e Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 28 Jan 2026 15:34:39 -0800 Subject: [PATCH 2/4] Add insns for memory copy and fill --- src/coreclr/jit/emitfmtswasm.h | 1 + src/coreclr/jit/emitwasm.cpp | 20 ++++++++++++++++++++ src/coreclr/jit/instrswasm.h | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/src/coreclr/jit/emitfmtswasm.h b/src/coreclr/jit/emitfmtswasm.h index 55b852649192f5..f752369ae14b35 100644 --- a/src/coreclr/jit/emitfmtswasm.h +++ b/src/coreclr/jit/emitfmtswasm.h @@ -36,6 +36,7 @@ IF_DEF(F32, IS_NONE, NONE) // IF_DEF(MEMARG, IS_NONE, NONE) // ( ) IF_DEF(LOCAL_DECL, IS_NONE, NONE) // +IF_DEF(MEMCPY, IS_NONE, NONE) // #undef IF_DEF #endif // !DEFINE_ID_OPS diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index 8d08ab6a9bd826..9b3bec1e483cb7 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -319,6 +319,11 @@ unsigned emitter::instrDesc::idCodeSize() const size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this)); break; } + case IF_MEMCPY: + { + size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this)); + size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this)); + } default: unreached(); } @@ -481,6 +486,14 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutputByte(dst, valType); break; } + case IF_MEMCPY: + { + dst += emitOutputOpcode(dst, ins); + cnsval_ssize_t constant = emitGetInsSC(id); + dst += emitOutputULEB128(dst, (uint64_t)constant); + dst += emitOutputULEB128(dst, (uint64_t)constant); + break; + } default: NYI_WASM("emitOutputInstr"); break; @@ -606,6 +619,13 @@ void emitter::emitDispIns( } break; + case IF_MEMCPY: + { + cnsval_ssize_t imm = emitGetInsSC(id); + printf(" %llu %llu", (uint64_t)imm, (uint64_t)imm); + dispJumpTargetIfAny(); + } + case IF_LOCAL_DECL: { unsigned int count = emitGetLclVarDeclCount(id); diff --git a/src/coreclr/jit/instrswasm.h b/src/coreclr/jit/instrswasm.h index 7230e20a64bf7e..70e870c1c55d8f 100644 --- a/src/coreclr/jit/instrswasm.h +++ b/src/coreclr/jit/instrswasm.h @@ -218,6 +218,10 @@ INST(i64_trunc_sat_f32_u, "i64.trunc_sat_f32_u", 0, IF_OPCODE, 0x05FC) INST(i64_trunc_sat_f64_s, "i64.trunc_sat_f64_s", 0, IF_OPCODE, 0x06FC) INST(i64_trunc_sat_f64_u, "i64.trunc_sat_f64_u", 0, IF_OPCODE, 0x07FC) +INST(memory_copy, "memory.copy", 0, IF_MEMCPY, 0x10FC) +INST(memory_fill, "memory.fill", 0, IF_ULEB128, 0x11FC) + + // clang-format on #undef INST From 22b8fbe68c64280d982f571d54ae440b0fd5b6c6 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 28 Jan 2026 15:51:15 -0800 Subject: [PATCH 3/4] Remove NYIs so stuff can flow through --- src/coreclr/jit/lowerwasm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index e5c79f11afbd0e..a4c884634bf0b0 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -186,13 +186,12 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) if (blkNode->IsZeroingGcPointersOnHeap()) { blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindLoop; - // We're going to use REG_R0 for zero src->SetContained(); - NYI_WASM("memory.fill of gc pointers"); + // memory.fill } else { - NYI_WASM("memory.fill"); + // memory.fill } } else @@ -203,6 +202,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) if (src->OperIs(GT_LCL_VAR)) { // TODO-1stClassStructs: for now we can't work with STORE_BLOCK source in register. + // TODO-WASM: Is this true for wasm as well? const unsigned srcLclNum = src->AsLclVar()->GetLclNum(); comp->lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(DoNotEnregisterReason::BlockOp)); } @@ -226,7 +226,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) else { assert(blkNode->OperIs(GT_STORE_BLK)); - NYI_WASM("memory.copy"); + // memory.copy } } } From 7fcf407fff29d70b4d6fe6c2a7a49a4739812bca Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 29 Jan 2026 09:04:02 -0800 Subject: [PATCH 4/4] Cleanup --- src/coreclr/jit/lowerwasm.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index a4c884634bf0b0..7f93fa505e02c3 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -187,7 +187,6 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) { blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindLoop; src->SetContained(); - // memory.fill } else { @@ -209,7 +208,6 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) ClassLayout* layout = blkNode->GetLayout(); bool doCpObj = layout->HasGCPtr(); - unsigned copyBlockUnrollLimit = comp->getUnrollThreshold(Compiler::UnrollKind::Memcpy); // CopyObj or CopyBlk if (doCpObj)