From d07fbef6d000b6775b87ea5220383ff4ce806903 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 8 Jan 2026 16:53:17 -0800 Subject: [PATCH 1/6] Add 8 and 16 bit loads --- src/coreclr/jit/instr.cpp | 8 ++++++++ src/coreclr/jit/instrswasm.h | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index ce915da97cc2ef..e7f3f5efa44abf 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2104,6 +2104,14 @@ instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false* case TYP_REF: case TYP_BYREF: return ins_Load(TYP_I_IMPL, aligned); + case TYP_BYTE: + return INS_i32_load8_s; + case TYP_UBYTE: + return INS_i32_load8_u; + case TYP_SHORT: + return INS_i32_load16_s; + case TYP_USHORT: + return INS_i32_load16_u; case TYP_INT: return INS_i32_load; case TYP_LONG: diff --git a/src/coreclr/jit/instrswasm.h b/src/coreclr/jit/instrswasm.h index f8562c071c30cb..f0a236f3c5437b 100644 --- a/src/coreclr/jit/instrswasm.h +++ b/src/coreclr/jit/instrswasm.h @@ -47,6 +47,12 @@ INST(i32_load, "i32.load", 0, IF_MEMARG, 0x28) INST(i64_load, "i64.load", 0, IF_MEMARG, 0x29) INST(f32_load, "f32.load", 0, IF_MEMARG, 0x2A) INST(f64_load, "f64.load", 0, IF_MEMARG, 0x2B) +INST(i32_load8_s, "i32.load8_s", 0, IF_MEMARG, 0x2C) +INST(i32_load8_u, "i32.load8_u", 0, IF_MEMARG, 0x2D) +INST(i32_load16_s,"i32.load16_s",0, IF_MEMARG, 0x2E) +INST(i32_load16_u,"i32.load16_u",0, IF_MEMARG, 0x2F) + + INST(i32_store, "i32.store", 0, IF_MEMARG, 0x36) INST(i64_store, "i64.store", 0, IF_MEMARG, 0x37) INST(f32_store, "f32.store", 0, IF_MEMARG, 0x38) From 4356874b2071501d8404d56830811cc68c2d9feb Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 8 Jan 2026 16:55:53 -0800 Subject: [PATCH 2/6] Basic implementation of indirect loads --- src/coreclr/jit/codegenwasm.cpp | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 0fa2e31a889144..261922442b5fa7 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -353,6 +353,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genCodeForNegNot(treeNode->AsOp()); break; + case GT_IND: + genCodeForIndir(treeNode->AsIndir()); + break; + default: #ifdef DEBUG NYIRAW(GenTree::OpName(treeNode->OperGet())); @@ -871,6 +875,36 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) genUpdateLifeStore(tree, targetReg, varDsc); } +//------------------------------------------------------------------------ +// genCodeForIndir: Produce code for a GT_IND node. +// +// Arguments: +// tree - the GT_IND node +// +void CodeGen::genCodeForIndir(GenTreeIndir* tree) +{ + assert(tree->OperIs(GT_IND)); + + var_types type = tree->TypeGet(); + instruction ins = ins_Load(type); + regNumber targetReg = tree->GetRegNum(); + emitAttr attr = emitActualTypeSize(type); + + genConsumeAddress(tree->Addr()); + + // TODO-WASM: Memory barriers + /* + if ((tree->gtFlags & GTF_IND_VOLATILE) != 0) + { + instGen_MemoryBarrier(BARRIER_FULL); + } + */ + + GetEmitter()->emitIns_I(ins, emitActualTypeSize(type), 0); + + genProduceReg(tree); +} + //------------------------------------------------------------------------ // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node. // From f2c3b3a2afda25f039cb4e81b96e80e5613408b3 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Fri, 9 Jan 2026 11:44:23 -0800 Subject: [PATCH 3/6] Implement GT_STOREIND Address PR feedback --- src/coreclr/jit/codegenwasm.cpp | 48 +++++++++++++++++++++++++++------ src/coreclr/jit/instr.cpp | 6 +++++ src/coreclr/jit/instrswasm.h | 3 ++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 261922442b5fa7..be487561747fbc 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -357,6 +357,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genCodeForIndir(treeNode->AsIndir()); break; + case GT_STOREIND: + genCodeForStoreInd(treeNode->AsStoreInd()); + break; + default: #ifdef DEBUG NYIRAW(GenTree::OpName(treeNode->OperGet())); @@ -887,24 +891,52 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) var_types type = tree->TypeGet(); instruction ins = ins_Load(type); - regNumber targetReg = tree->GetRegNum(); - emitAttr attr = emitActualTypeSize(type); genConsumeAddress(tree->Addr()); // TODO-WASM: Memory barriers - /* - if ((tree->gtFlags & GTF_IND_VOLATILE) != 0) - { - instGen_MemoryBarrier(BARRIER_FULL); - } - */ GetEmitter()->emitIns_I(ins, emitActualTypeSize(type), 0); genProduceReg(tree); } +//------------------------------------------------------------------------ +// genCodeForStoreInd: Produce code for a GT_STOREIND node. +// +// Arguments: +// tree - the GT_STOREIND node +// +void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree) +{ + GenTree* data = tree->Data(); + GenTree* addr = tree->Addr(); + + GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree); + if (writeBarrierForm != GCInfo::WBF_NoBarrier) + { + NYI_WASM("write barriers in StoreInd"); + } + else // A normal store, not a WriteBarrier store + { + // We must consume the operands in the proper execution order, + // so that liveness is updated appropriately. + genConsumeAddress(addr); + + if (!data->isContained()) + { + genConsumeRegs(data); + } + + var_types type = tree->TypeGet(); + instruction ins = ins_Store(type); + + // TODO-WASM: Memory barriers + + GetEmitter()->emitIns_I(ins, emitActualTypeSize(type), 0); + } +} + //------------------------------------------------------------------------ // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node. // diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index e7f3f5efa44abf..52768505b122b1 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2515,6 +2515,12 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false case TYP_REF: case TYP_BYREF: return ins_Store(TYP_I_IMPL, aligned); + case TYP_BYTE: + case TYP_UBYTE: + return INS_i32_store8; + case TYP_SHORT: + case TYP_USHORT: + return INS_i32_store16; case TYP_INT: return INS_i32_store; case TYP_LONG: diff --git a/src/coreclr/jit/instrswasm.h b/src/coreclr/jit/instrswasm.h index f0a236f3c5437b..1caa96339139bf 100644 --- a/src/coreclr/jit/instrswasm.h +++ b/src/coreclr/jit/instrswasm.h @@ -52,11 +52,12 @@ INST(i32_load8_u, "i32.load8_u", 0, IF_MEMARG, 0x2D) INST(i32_load16_s,"i32.load16_s",0, IF_MEMARG, 0x2E) INST(i32_load16_u,"i32.load16_u",0, IF_MEMARG, 0x2F) - INST(i32_store, "i32.store", 0, IF_MEMARG, 0x36) INST(i64_store, "i64.store", 0, IF_MEMARG, 0x37) INST(f32_store, "f32.store", 0, IF_MEMARG, 0x38) INST(f64_store, "f64.store", 0, IF_MEMARG, 0x39) +INST(i32_store8, "i32.store8", 0, IF_MEMARG, 0x3A) +INST(i32_store16, "i32.store16", 0, IF_MEMARG, 0x3B) // 5.4.7 Numeric Instructions // Constants From ecfdd8d3a9df81fb1ba03b5d50cf98c273166130 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Fri, 9 Jan 2026 11:53:30 -0800 Subject: [PATCH 4/6] Set max unchecked offset for null object to 0 on wasm --- src/coreclr/vm/jitinterface.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 89fa3099cb653b..0c17a2dd3842dd 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -11,11 +11,13 @@ #include "corjit.h" -#ifndef TARGET_UNIX +#ifdef TARGET_WASM +#define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT 0 +#elif !defined(TARGET_UNIX) #define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((32*1024)-1) // when generating JIT code -#else // !TARGET_UNIX +#else // TARGET_WASM or !TARGET_UNIX #define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((GetOsPageSize() / 2) - 1) -#endif // !TARGET_UNIX +#endif // TARGET_UNIX #include "pgo.h" class ILCodeStream; @@ -970,7 +972,7 @@ class CInterpreterJitInfo final : public CEECodeGenInfo void SetDebugInfo(PTR_BYTE pDebugInfo) override; LPVOID GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) override; - + virtual CORINFO_METHOD_HANDLE getAsyncResumptionStub(void** entryPoint) override final; }; #endif // FEATURE_INTERPRETER From 98245e72f1d0a35a1d5e68485faba9ceb9a96956 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Fri, 9 Jan 2026 11:54:32 -0800 Subject: [PATCH 5/6] Apply jit format patch --- src/coreclr/jit/codegenwasm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index be487561747fbc..3d72286a2274b6 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -889,8 +889,8 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) { assert(tree->OperIs(GT_IND)); - var_types type = tree->TypeGet(); - instruction ins = ins_Load(type); + var_types type = tree->TypeGet(); + instruction ins = ins_Load(type); genConsumeAddress(tree->Addr()); From 8391d183dd3aafc076c1e24173d4807adfd00274 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 14 Jan 2026 15:45:59 -0800 Subject: [PATCH 6/6] Address PR feedback --- src/coreclr/jit/codegenwasm.cpp | 8 +++----- src/coreclr/vm/jitinterface.h | 10 ++++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 3d72286a2274b6..5d40d0b5a5dcd3 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -922,11 +922,7 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree) // We must consume the operands in the proper execution order, // so that liveness is updated appropriately. genConsumeAddress(addr); - - if (!data->isContained()) - { - genConsumeRegs(data); - } + genConsumeRegs(data); var_types type = tree->TypeGet(); instruction ins = ins_Store(type); @@ -935,6 +931,8 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree) GetEmitter()->emitIns_I(ins, emitActualTypeSize(type), 0); } + + genUpdateLife(tree); } //------------------------------------------------------------------------ diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 0c17a2dd3842dd..89fa3099cb653b 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -11,13 +11,11 @@ #include "corjit.h" -#ifdef TARGET_WASM -#define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT 0 -#elif !defined(TARGET_UNIX) +#ifndef TARGET_UNIX #define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((32*1024)-1) // when generating JIT code -#else // TARGET_WASM or !TARGET_UNIX +#else // !TARGET_UNIX #define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((GetOsPageSize() / 2) - 1) -#endif // TARGET_UNIX +#endif // !TARGET_UNIX #include "pgo.h" class ILCodeStream; @@ -972,7 +970,7 @@ class CInterpreterJitInfo final : public CEECodeGenInfo void SetDebugInfo(PTR_BYTE pDebugInfo) override; LPVOID GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) override; - + virtual CORINFO_METHOD_HANDLE getAsyncResumptionStub(void** entryPoint) override final; }; #endif // FEATURE_INTERPRETER