From 4d3a299aaf9fe37ee75d8fee9c1aed470ed08416 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 15 Apr 2026 01:22:45 +0200 Subject: [PATCH 1/2] JIT: Precompute func-app element stride in VN chunks Precompute and cache the element size for func-app chunks (sizeof(VNFunc) + sizeof(ValueNum) * arity) in Chunk::m_funcAppElemSize, initialized once in the constructor. PointerToFuncApp now uses a single multiply by the cached stride instead of recomputing the expression on every call. This reduces work on a hot path (GetVNFunc and all VN creation sites that call PointerToFuncApp). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/valuenum.cpp | 15 +++++++++++---- src/coreclr/jit/valuenum.h | 8 ++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 5c2884cb29659e..64f639fc16b73b 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1659,6 +1659,7 @@ ValueNumStore::Chunk::Chunk(CompAllocator alloc, ValueNum* pNextBaseVN, var_type , m_baseVN(*pNextBaseVN) , m_typ(typ) , m_attribs(attribs) + , m_funcAppElemSize(0) { // Allocate "m_defs" here, according to the typ/attribs pair. switch (attribs) @@ -1748,19 +1749,24 @@ ValueNumStore::Chunk::Chunk(CompAllocator alloc, ValueNum* pNextBaseVN, var_type case CEA_Func0: m_defs = new (alloc) VNFunc[ChunkSize]; + m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 0; break; case CEA_Func1: - m_defs = alloc.allocate((sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 1) * ChunkSize); + m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 1; + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func2: - m_defs = alloc.allocate((sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 2) * ChunkSize); + m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 2; + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func3: - m_defs = alloc.allocate((sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 3) * ChunkSize); + m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 3; + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func4: - m_defs = alloc.allocate((sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 4) * ChunkSize); + m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 4; + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; default: unreached(); @@ -9991,6 +9997,7 @@ bool ValueNumStore::GetVNFunc(ValueNum vn, VNFuncApp* funcApp) return false; } + //---------------------------------------------------------------------------------- // IsVNBinFunc: A specialized version of GetVNFunc that checks if the given ValueNum // is the given VNFunc with arity 2. If so, it returns the two operands. diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 8c75e17935a485..0d67e154bfcdc8 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -1540,6 +1540,10 @@ class ValueNumStore var_types m_typ; ChunkExtraAttribs m_attribs; + // Precomputed element size for func-app chunks (sizeof(VNFunc) + sizeof(ValueNum) * arity). + // Zero for non-func chunks. + unsigned m_funcAppElemSize; + // Initialize a chunk, starting at "*baseVN", for the given "typ", and "attribs", using "alloc" for allocations. // (Increments "*baseVN" by ChunkSize.) Chunk(CompAllocator alloc, ValueNum* baseVN, var_types typ, ChunkExtraAttribs attribs); @@ -1556,9 +1560,9 @@ class ValueNumStore { assert((m_attribs >= CEA_Func0) && (m_attribs <= CEA_Func4)); assert(numArgs == (unsigned)(m_attribs - CEA_Func0)); - static_assert(sizeof(VNDefFuncAppFlexible) == sizeof(VNFunc)); + assert(m_funcAppElemSize == sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * numArgs); return reinterpret_cast( - (char*)m_defs + offsetWithinChunk * (sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * numArgs)); + (char*)m_defs + offsetWithinChunk * m_funcAppElemSize); } template From 37d96a8c665f063672140ca49e8f1ee8fd5475fb Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 15 Apr 2026 01:27:08 +0200 Subject: [PATCH 2/2] formatting --- src/coreclr/jit/valuenum.cpp | 11 +++++------ src/coreclr/jit/valuenum.h | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 64f639fc16b73b..d001c984a13f01 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -1748,25 +1748,25 @@ ValueNumStore::Chunk::Chunk(CompAllocator alloc, ValueNum* pNextBaseVN, var_type break; case CEA_Func0: - m_defs = new (alloc) VNFunc[ChunkSize]; + m_defs = new (alloc) VNFunc[ChunkSize]; m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 0; break; case CEA_Func1: m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 1; - m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func2: m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 2; - m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func3: m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 3; - m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; case CEA_Func4: m_funcAppElemSize = sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * 4; - m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); + m_defs = alloc.allocate(m_funcAppElemSize * ChunkSize); break; default: unreached(); @@ -9997,7 +9997,6 @@ bool ValueNumStore::GetVNFunc(ValueNum vn, VNFuncApp* funcApp) return false; } - //---------------------------------------------------------------------------------- // IsVNBinFunc: A specialized version of GetVNFunc that checks if the given ValueNum // is the given VNFunc with arity 2. If so, it returns the two operands. diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 0d67e154bfcdc8..f6f0acd6ccdaf5 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -1561,8 +1561,7 @@ class ValueNumStore assert((m_attribs >= CEA_Func0) && (m_attribs <= CEA_Func4)); assert(numArgs == (unsigned)(m_attribs - CEA_Func0)); assert(m_funcAppElemSize == sizeof(VNDefFuncAppFlexible) + sizeof(ValueNum) * numArgs); - return reinterpret_cast( - (char*)m_defs + offsetWithinChunk * m_funcAppElemSize); + return reinterpret_cast((char*)m_defs + offsetWithinChunk * m_funcAppElemSize); } template