// We have no current allocation chunks.
for (unsigned i = 0; i < TYP_COUNT; i++)
{
- for (unsigned j = CEA_None; j <= CEA_Count + BasicBlock::MAX_LOOP_NUM; j++)
+ for (unsigned j = CEA_Const; j <= CEA_Count; j++)
{
m_curAllocChunk[i][j] = NoChunk;
}
}
// We will reserve chunk 0 to hold some special constants, like the constant NULL, the "exception" value, and the
// "zero map."
- Chunk* specialConstChunk =
- new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, TYP_REF, CEA_Const, BasicBlock::MAX_LOOP_NUM);
+ Chunk* specialConstChunk = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, TYP_REF, CEA_Const);
specialConstChunk->m_numUsed +=
SRC_NumSpecialRefConsts; // Implicitly allocate 0 ==> NULL, and 1 ==> Exception, 2 ==> ZeroMap.
ChunkNum cn = m_chunks.Push(specialConstChunk);
return GetVNFunc(vn, &funcAttr) && (s_vnfOpAttribs[funcAttr.m_func] & VNFOA_SharedStatic) != 0;
}
-ValueNumStore::Chunk::Chunk(CompAllocator alloc,
- ValueNum* pNextBaseVN,
- var_types typ,
- ChunkExtraAttribs attribs,
- BasicBlock::loopNumber loopNum)
- : m_defs(nullptr), m_numUsed(0), m_baseVN(*pNextBaseVN), m_typ(typ), m_attribs(attribs), m_loopNum(loopNum)
+ValueNumStore::Chunk::Chunk(CompAllocator alloc, ValueNum* pNextBaseVN, var_types typ, ChunkExtraAttribs attribs)
+ : m_defs(nullptr), m_numUsed(0), m_baseVN(*pNextBaseVN), m_typ(typ), m_attribs(attribs)
{
// Allocate "m_defs" here, according to the typ/attribs pair.
switch (attribs)
{
- case CEA_None:
case CEA_NotAField:
break; // Nothing to do.
case CEA_Const:
*pNextBaseVN += ChunkSize;
}
-ValueNumStore::Chunk* ValueNumStore::GetAllocChunk(var_types typ,
- ChunkExtraAttribs attribs,
- BasicBlock::loopNumber loopNum)
+ValueNumStore::Chunk* ValueNumStore::GetAllocChunk(var_types typ, ChunkExtraAttribs attribs)
{
Chunk* res;
- unsigned index;
- if (loopNum == BasicBlock::MAX_LOOP_NUM)
- {
- // Loop nest is unknown/irrelevant for this VN.
- index = attribs;
- }
- else
- {
- // Loop nest is interesting. Since we know this is only true for unique VNs, we know attribs will
- // be CEA_None and can just index based on loop number.
- noway_assert(attribs == CEA_None);
- // Map NOT_IN_LOOP -> BasicBlock::MAX_LOOP_NUM to make the index range contiguous [0..BasicBlock::MAX_LOOP_NUM]
- index = CEA_Count + (loopNum == BasicBlock::NOT_IN_LOOP ? BasicBlock::MAX_LOOP_NUM : loopNum);
- }
- ChunkNum cn = m_curAllocChunk[typ][index];
+ unsigned index = attribs;
+ ChunkNum cn = m_curAllocChunk[typ][index];
if (cn != NoChunk)
{
res = m_chunks.Get(cn);
}
}
// Otherwise, must allocate a new one.
- res = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, typ, attribs, loopNum);
+ res = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, typ, attribs);
cn = m_chunks.Push(res);
m_curAllocChunk[typ][index] = cn;
return res;
}
else
{
- Chunk* c = GetAllocChunk(TYP_I_IMPL, CEA_Handle);
- unsigned offsetWithinChunk = c->AllocVN();
- res = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNHandle*>(c->m_defs)[offsetWithinChunk] = handle;
+ Chunk* const c = GetAllocChunk(TYP_I_IMPL, CEA_Handle);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNHandle* const chunkSlots = reinterpret_cast<VNHandle*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = handle;
+ res = c->m_baseVN + offsetWithinChunk;
+
GetHandleMap()->Set(handle, res);
return res;
}
if (!GetVNFunc0Map()->Lookup(func, &resultVN))
{
// Allocate a new ValueNum for 'func'
- Chunk* c = GetAllocChunk(typ, CEA_Func0);
- unsigned offsetWithinChunk = c->AllocVN();
- resultVN = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNFunc*>(c->m_defs)[offsetWithinChunk] = func;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func0);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNFunc* const chunkSlots = reinterpret_cast<VNFunc*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = func;
+ resultVN = c->m_baseVN + offsetWithinChunk;
GetVNFunc0Map()->Set(func, resultVN);
}
return resultVN;
//
ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN)
{
+ assert(func != VNF_MemOpaque);
assert(arg0VN == VNNormalValue(arg0VN)); // Arguments don't carry exceptions.
// Try to perform constant-folding.
ValueNum resultVN;
// Have we already assigned a ValueNum for 'func'('arg0VN') ?
- //
VNDefFunc1Arg fstruct(func, arg0VN);
if (!GetVNFunc1Map()->Lookup(fstruct, &resultVN))
{
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN')
//
- Chunk* c = GetAllocChunk(typ, CEA_Func1);
- unsigned offsetWithinChunk = c->AllocVN();
- resultVN = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNDefFunc1Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func1);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc1Arg* const chunkSlots = reinterpret_cast<VNDefFunc1Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+ resultVN = c->m_baseVN + offsetWithinChunk;
+
// Record 'resultVN' in the Func1Map
GetVNFunc1Map()->Set(fstruct, resultVN);
}
{
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN','arg1VN')
//
- Chunk* c = GetAllocChunk(typ, CEA_Func2);
- unsigned offsetWithinChunk = c->AllocVN();
- resultVN = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNDefFunc2Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func2);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc2Arg* const chunkSlots = reinterpret_cast<VNDefFunc2Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+ resultVN = c->m_baseVN + offsetWithinChunk;
// Record 'resultVN' in the Func2Map
GetVNFunc2Map()->Set(fstruct, resultVN);
}
{
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN','arg1VN','arg2VN')
//
- Chunk* c = GetAllocChunk(typ, CEA_Func3);
- unsigned offsetWithinChunk = c->AllocVN();
- resultVN = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNDefFunc3Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func3);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc3Arg* const chunkSlots = reinterpret_cast<VNDefFunc3Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+ resultVN = c->m_baseVN + offsetWithinChunk;
+
// Record 'resultVN' in the Func3Map
GetVNFunc3Map()->Set(fstruct, resultVN);
}
{
// Otherwise, Allocate a new ValueNum for 'func'('arg0VN','arg1VN','arg2VN','arg3VN')
//
- Chunk* c = GetAllocChunk(typ, CEA_Func4);
- unsigned offsetWithinChunk = c->AllocVN();
- resultVN = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNDefFunc4Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func4);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc4Arg* const chunkSlots = reinterpret_cast<VNDefFunc4Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+ resultVN = c->m_baseVN + offsetWithinChunk;
+
// Record 'resultVN' in the Func4Map
GetVNFunc4Map()->Set(fstruct, resultVN);
}
if (!GetVNFunc2Map()->Lookup(fstruct, &res))
{
// Otherwise, assign a new VN for the function application.
- Chunk* c = GetAllocChunk(typ, CEA_Func2);
- unsigned offsetWithinChunk = c->AllocVN();
- res = c->m_baseVN + offsetWithinChunk;
- reinterpret_cast<VNDefFunc2Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
+ Chunk* const c = GetAllocChunk(typ, CEA_Func2);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc2Arg* const chunkSlots = reinterpret_cast<VNDefFunc2Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+ res = c->m_baseVN + offsetWithinChunk;
+
GetVNFunc2Map()->Set(fstruct, res);
}
return res;
loopNum = block->bbNatLoopNum;
}
- // We always allocate a new, unique VN in this call.
- // The 'typ' is used to partition the allocation of VNs into different chunks.
- Chunk* c = GetAllocChunk(typ, CEA_None, loopNum);
- unsigned offsetWithinChunk = c->AllocVN();
- ValueNum result = c->m_baseVN + offsetWithinChunk;
- return result;
+ // VNForFunc(typ, func, vn) but bypasses looking in the cache
+ //
+ VNDefFunc1Arg fstruct(VNF_MemOpaque, loopNum);
+ Chunk* const c = GetAllocChunk(typ, CEA_Func1);
+ unsigned const offsetWithinChunk = c->AllocVN();
+ VNDefFunc1Arg* const chunkSlots = reinterpret_cast<VNDefFunc1Arg*>(c->m_defs);
+
+ chunkSlots[offsetWithinChunk] = fstruct;
+
+ ValueNum resultVN = c->m_baseVN + offsetWithinChunk;
+ return resultVN;
}
ValueNum ValueNumStore::VNApplySelectors(ValueNumKind vnk,
}
//------------------------------------------------------------------------
-// LoopOfVN: If the given value number is an opaque one associated with a particular
-// expression in the IR, give the loop number where the expression occurs; otherwise,
-// returns BasicBlock::MAX_LOOP_NUM.
+// LoopOfVN: If the given value number is VNF_MemOpaque, return
+// the loop number where the memory update occurs, otherwise returns MAX_LOOP_NUM.
//
// Arguments:
// vn - Value number to query
//
// Return Value:
-// The correspondingblock's bbNatLoopNum, which may be BasicBlock::NOT_IN_LOOP.
-// Returns BasicBlock::MAX_LOOP_NUM if this VN is not an opaque value number associated with
-// a particular expression/location in the IR.
-
+// The memory loop number, which may be BasicBlock::NOT_IN_LOOP.
+// Returns BasicBlock::MAX_LOOP_NUM if this VN is not a memory value number.
+//
BasicBlock::loopNumber ValueNumStore::LoopOfVN(ValueNum vn)
{
- if (vn == NoVN)
+ VNFuncApp funcApp;
+ if (GetVNFunc(vn, &funcApp) && (funcApp.m_func == VNF_MemOpaque))
{
- return BasicBlock::MAX_LOOP_NUM;
+ return (BasicBlock::loopNumber)funcApp.m_args[0];
}
- Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
- return c->m_loopNum;
+ return BasicBlock::MAX_LOOP_NUM;
}
bool ValueNumStore::IsVNConstant(ValueNum vn)
case VNF_ValWithExc:
vnDumpValWithExc(comp, &funcApp);
break;
+ case VNF_MemOpaque:
+ vnDumpMemOpaque(comp, &funcApp);
+ break;
#ifdef FEATURE_SIMD
case VNF_SimdType:
vnDumpSimdType(comp, &funcApp);
printf("]");
}
+void ValueNumStore::vnDumpMemOpaque(Compiler* comp, VNFuncApp* memOpaque)
+{
+ assert(memOpaque->m_func == VNF_MemOpaque); // Precondition.
+ const unsigned loopNum = memOpaque->m_args[0];
+
+ if (loopNum == BasicBlock::NOT_IN_LOOP)
+ {
+ printf("MemOpaque:NotInLoop");
+ }
+ else if (loopNum == BasicBlock::MAX_LOOP_NUM)
+ {
+ printf("MemOpaque:Indeterminate");
+ }
+ else
+ {
+ printf("MemOpaque:L%02u", loopNum);
+ }
+}
+
#ifdef FEATURE_SIMD
void ValueNumStore::vnDumpSimdType(Compiler* comp, VNFuncApp* simdType)
{
// Prints a representation of a MapStore operation on standard out.
void vnDumpMapStore(Compiler* comp, VNFuncApp* mapStore);
+ // Requires "memOpaque" to be a mem opaque VNFuncApp
+ // Prints a representation of a MemOpaque state on standard out.
+ void vnDumpMemOpaque(Compiler* comp, VNFuncApp* memOpaque);
+
// Requires "valWithExc" to be a value with an exeception set VNFuncApp.
// Prints a representation of the exeception set on standard out.
void vnDumpValWithExc(Compiler* comp, VNFuncApp* valWithExc);
enum ChunkExtraAttribs : BYTE
{
- CEA_None, // No extra attributes.
CEA_Const, // This chunk contains constant values.
CEA_Handle, // This chunk contains handle constants.
CEA_NotAField, // This chunk contains "not a field" values.
ValueNum m_baseVN;
// The common attributes of this chunk.
- var_types m_typ;
- ChunkExtraAttribs m_attribs;
- BasicBlock::loopNumber m_loopNum;
+ var_types m_typ;
+ ChunkExtraAttribs m_attribs;
- // Initialize a chunk, starting at "*baseVN", for the given "typ", "attribs", and "loopNum" (using "alloc" for
- // allocations).
+ // 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,
- BasicBlock::loopNumber loopNum);
+ Chunk(CompAllocator alloc, ValueNum* baseVN, var_types typ, ChunkExtraAttribs attribs);
// Requires that "m_numUsed < ChunkSize." Returns the offset of the allocated VN within the chunk; the
// actual VN is this added to the "m_baseVN" of the chunk.
JitExpandArrayStack<Chunk*> m_chunks;
// These entries indicate the current allocation chunk, if any, for each valid combination of <var_types,
- // ChunkExtraAttribute, loopNumber>. Valid combinations require attribs==CEA_None or
- // loopNum==BasicBlock::MAX_LOOP_NUM.
+ // ChunkExtraAttribute>.
// If the value is NoChunk, it indicates that there is no current allocation chunk for that pair, otherwise
// it is the index in "m_chunks" of a chunk with the given attributes, in which the next allocation should
// be attempted.
- ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + BasicBlock::MAX_LOOP_NUM + 1];
+ ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + 1];
// Returns a (pointer to a) chunk in which a new value number may be allocated.
- Chunk* GetAllocChunk(var_types typ,
- ChunkExtraAttribs attribs,
- BasicBlock::loopNumber loopNum = BasicBlock::MAX_LOOP_NUM);
+ Chunk* GetAllocChunk(var_types typ, ChunkExtraAttribs attribs);
// First, we need mechanisms for mapping from constants to value numbers.
// For small integers, we'll use an array.